Skip to content
This repository has been archived by the owner on Jan 13, 2022. It is now read-only.

Add support for non-standard content/images scales #166

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions FBSnapshotTestCase/Categories/UIImage+Compare.m
Original file line number Diff line number Diff line change
Expand Up @@ -46,11 +46,11 @@ @implementation UIImage (Compare)

- (BOOL)fb_compareWithImage:(UIImage *)image tolerance:(CGFloat)tolerance
{
NSAssert(CGSizeEqualToSize(self.size, image.size), @"Images must be same size.");

CGSize referenceImageSize = CGSizeMake(CGImageGetWidth(self.CGImage), CGImageGetHeight(self.CGImage));
CGSize imageSize = CGSizeMake(CGImageGetWidth(image.CGImage), CGImageGetHeight(image.CGImage));


NSAssert(CGSizeEqualToSize(referenceImageSize, imageSize), @"Images must be same size.");

// The images have the equal size, so we could use the smallest amount of bytes because of byte padding
size_t minBytesPerRow = MIN(CGImageGetBytesPerRow(self.CGImage), CGImageGetBytesPerRow(image.CGImage));
size_t referenceImageSizeBytes = referenceImageSize.height * minBytesPerRow;
Expand Down
2 changes: 1 addition & 1 deletion FBSnapshotTestCase/Categories/UIImage+Diff.m
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ - (UIImage *)fb_diffWithImage:(UIImage *)image
return nil;
}
CGSize imageSize = CGSizeMake(MAX(self.size.width, image.size.width), MAX(self.size.height, image.size.height));
UIGraphicsBeginImageContextWithOptions(imageSize, YES, 0);
UIGraphicsBeginImageContextWithOptions(imageSize, YES, self.scale);
CGContextRef context = UIGraphicsGetCurrentContext();
[self drawInRect:CGRectMake(0, 0, self.size.width, self.size.height)];
CGContextSetAlpha(context, 0.5);
Expand Down
6 changes: 3 additions & 3 deletions FBSnapshotTestCase/Categories/UIImage+Snapshot.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,12 @@
@interface UIImage (Snapshot)

/// Uses renderInContext: to get a snapshot of the layer.
+ (UIImage *)fb_imageForLayer:(CALayer *)layer;
+ (UIImage *)fb_imageForLayer:(CALayer *)layer scale:(CGFloat)scale;

/// Uses renderInContext: to get a snapshot of the view layer.
+ (UIImage *)fb_imageForViewLayer:(UIView *)view;
+ (UIImage *)fb_imageForViewLayer:(UIView *)view scale:(CGFloat)scale;

/// Uses drawViewHierarchyInRect: to get a snapshot of the view and adds the view into a window if needed.
+ (UIImage *)fb_imageForView:(UIView *)view;
+ (UIImage *)fb_imageForView:(UIView *)view scale:(CGFloat)scale;

@end
12 changes: 6 additions & 6 deletions FBSnapshotTestCase/Categories/UIImage+Snapshot.m
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,13 @@

@implementation UIImage (Snapshot)

+ (UIImage *)fb_imageForLayer:(CALayer *)layer
+ (UIImage *)fb_imageForLayer:(CALayer *)layer scale:(CGFloat)scale
{
CGRect bounds = layer.bounds;
NSAssert1(CGRectGetWidth(bounds), @"Zero width for layer %@", layer);
NSAssert1(CGRectGetHeight(bounds), @"Zero height for layer %@", layer);

UIGraphicsBeginImageContextWithOptions(bounds.size, NO, 0);
UIGraphicsBeginImageContextWithOptions(bounds.size, NO, scale);
CGContextRef context = UIGraphicsGetCurrentContext();
NSAssert1(context, @"Could not generate context for layer %@", layer);
CGContextSaveGState(context);
Expand All @@ -32,13 +32,13 @@ + (UIImage *)fb_imageForLayer:(CALayer *)layer
return snapshot;
}

+ (UIImage *)fb_imageForViewLayer:(UIView *)view
+ (UIImage *)fb_imageForViewLayer:(UIView *)view scale:(CGFloat)scale
{
[view layoutIfNeeded];
return [self fb_imageForLayer:view.layer];
return [self fb_imageForLayer:view.layer scale:scale];
}

+ (UIImage *)fb_imageForView:(UIView *)view
+ (UIImage *)fb_imageForView:(UIView *)view scale:(CGFloat)scale
{
CGRect bounds = view.bounds;
NSAssert1(CGRectGetWidth(bounds), @"Zero width for view %@", view);
Expand All @@ -56,7 +56,7 @@ + (UIImage *)fb_imageForView:(UIView *)view
removeFromSuperview = YES;
}

UIGraphicsBeginImageContextWithOptions(bounds.size, NO, 0);
UIGraphicsBeginImageContextWithOptions(bounds.size, NO, scale);
[view layoutIfNeeded];
[view drawViewHierarchyInRect:view.bounds afterScreenUpdates:YES];

Expand Down
5 changes: 5 additions & 0 deletions FBSnapshotTestCase/FBSnapshotTestCase.h
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,11 @@
*/
@property (readwrite, nonatomic, assign) BOOL usesDrawViewHierarchyInRect;

/**
When set to values different than 0, it uses a specific scale for generating and comparing images rather than using the main screen's default scale.
*/
@property (readwrite, nonatomic, assign) NSUInteger manualScale;

- (void)setUp NS_REQUIRES_SUPER;
- (void)tearDown NS_REQUIRES_SUPER;

Expand Down
12 changes: 11 additions & 1 deletion FBSnapshotTestCase/FBSnapshotTestCase.m
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,17 @@ - (void)setUsesDrawViewHierarchyInRect:(BOOL)usesDrawViewHierarchyInRect
_snapshotController.usesDrawViewHierarchyInRect = usesDrawViewHierarchyInRect;
}

- (void)setManualScale:(NSUInteger)manualScale
{
NSAssert1(_snapshotController, @"%s cannot be called before [super setUp]", __FUNCTION__);
_snapshotController.manualScale = manualScale;
}

- (NSUInteger)manualScale
{
return _snapshotController.manualScale;
}

#pragma mark - Public API

- (BOOL)compareSnapshotOfLayer:(CALayer *)layer
Expand Down Expand Up @@ -116,7 +127,6 @@ - (NSString *)getReferenceImageDirectoryWithDefault:(NSString *)dir
return [[NSBundle bundleForClass:self.class].resourcePath stringByAppendingPathComponent:@"ReferenceImages"];
}


#pragma mark - Private API

- (BOOL)_compareSnapshotOfViewOrLayer:(id)viewOrLayer
Expand Down
5 changes: 5 additions & 0 deletions FBSnapshotTestCase/FBSnapshotTestController.h
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,11 @@ extern NSString *const FBDiffedImageKey;
*/
@property (readwrite, nonatomic, copy) NSString *referenceImagesDirectory;

/**
When set to values different than 0, it uses a specific scale for generating and comparing images rather than using the main screen's default scale.
*/
@property (readwrite, nonatomic, assign) NSUInteger manualScale;

/**
@param testClass The subclass of FBSnapshotTestCase that is using this controller.
@returns An instance of FBSnapshotTestController.
Expand Down
26 changes: 17 additions & 9 deletions FBSnapshotTestCase/FBSnapshotTestController.m
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,8 @@ - (UIImage *)referenceImageForSelector:(SEL)selector
{
NSString *filePath = [self _referenceFilePathForSelector:selector identifier:identifier];
UIImage *image = [UIImage imageWithContentsOfFile:filePath];
if (nil == image && NULL != errorPtr) {
CGFloat scale = (self.manualScale > 0 ? self.manualScale : [[UIScreen mainScreen] scale]);
if ((nil == image && NULL != errorPtr) || (image && image.scale != scale)) {
BOOL exists = [_fileManager fileExistsAtPath:filePath];
if (!exists) {
*errorPtr = [NSError errorWithDomain:FBSnapshotTestControllerErrorDomain
Expand All @@ -129,15 +130,21 @@ - (BOOL)compareReferenceImage:(UIImage *)referenceImage
tolerance:(CGFloat)tolerance
error:(NSError **)errorPtr
{
BOOL sameImageDimensions = CGSizeEqualToSize(referenceImage.size, image.size);
CGSize referenceImagePixelSize = referenceImage.size;
referenceImagePixelSize = CGSizeMake(referenceImagePixelSize.width * referenceImage.scale,
referenceImagePixelSize.height * referenceImage.scale);
CGSize imagePixelSize = image.size;
imagePixelSize = CGSizeMake(imagePixelSize.width * image.scale,
imagePixelSize.height * image.scale);
BOOL sameImageDimensions = CGSizeEqualToSize(referenceImagePixelSize, imagePixelSize);
if (sameImageDimensions && [referenceImage fb_compareWithImage:image tolerance:tolerance]) {
return YES;
}

if (NULL != errorPtr) {
NSString *errorDescription = sameImageDimensions ? @"Images different" : @"Images different sizes";
NSString *errorReason = sameImageDimensions ? [NSString stringWithFormat:@"image pixels differed by more than %.2f%% from the reference image", tolerance * 100]
: [NSString stringWithFormat:@"referenceImage:%@, image:%@", NSStringFromCGSize(referenceImage.size), NSStringFromCGSize(image.size)];
: [NSString stringWithFormat:@"referenceImage:%@, image:%@", NSStringFromCGSize(referenceImagePixelSize), NSStringFromCGSize(imagePixelSize)];
FBSnapshotTestControllerErrorCode errorCode = sameImageDimensions ? FBSnapshotTestControllerErrorCodeImagesDifferent : FBSnapshotTestControllerErrorCodeImagesDifferentSizes;

*errorPtr = [NSError errorWithDomain:FBSnapshotTestControllerErrorDomain
Expand Down Expand Up @@ -236,9 +243,10 @@ - (NSString *)_fileNameForSelector:(SEL)selector
if (self.isDeviceAgnostic) {
fileName = FBDeviceAgnosticNormalizedFileName(fileName);
}

if ([[UIScreen mainScreen] scale] > 1) {
fileName = [fileName stringByAppendingFormat:@"@%.fx", [[UIScreen mainScreen] scale]];

CGFloat scale = (self.manualScale > 0 ? self.manualScale : [[UIScreen mainScreen] scale]);
if (1 < scale) {
fileName = [fileName stringByAppendingFormat:@"@%.fx", scale];
}
fileName = [fileName stringByAppendingPathExtension:@"png"];
return fileName;
Expand Down Expand Up @@ -343,12 +351,12 @@ - (UIImage *)_imageForViewOrLayer:(id)viewOrLayer
{
if ([viewOrLayer isKindOfClass:[UIView class]]) {
if (_usesDrawViewHierarchyInRect) {
return [UIImage fb_imageForView:viewOrLayer];
return [UIImage fb_imageForView:viewOrLayer scale:self.manualScale];
} else {
return [UIImage fb_imageForViewLayer:viewOrLayer];
return [UIImage fb_imageForViewLayer:viewOrLayer scale:self.manualScale];
}
} else if ([viewOrLayer isKindOfClass:[CALayer class]]) {
return [UIImage fb_imageForLayer:viewOrLayer];
return [UIImage fb_imageForLayer:viewOrLayer scale:self.manualScale];
} else {
[NSException raise:@"Only UIView and CALayer classes can be snapshotted" format:@"%@", viewOrLayer];
}
Expand Down