Using `drawViewHierarchyInRect` instead of `renderInContext` for snapshot tests
Summary: We found that `-[CALayer renderInContext:]` produces bad results in some cases (which is actually documented thing!), so we decided to replace it with `-[UIView drawViewHierarchyInRect:]` which is more reliable (I hope). As part of this change I completly removed support of `CALayer` from local fork of `RNTesterIntegrationTests`. See https://github.com/facebook/react-native/pull/14011#issuecomment-303844580 for more details. janicduplessis Reviewed By: javache Differential Revision: D5129492 fbshipit-source-id: 6a9227037c85bb8f862d55267f5301e177985ad9
|
@ -18,44 +18,6 @@
|
||||||
#define FB_REFERENCE_IMAGE_DIR "\"$(SOURCE_ROOT)/$(PROJECT_NAME)Tests/ReferenceImages\""
|
#define FB_REFERENCE_IMAGE_DIR "\"$(SOURCE_ROOT)/$(PROJECT_NAME)Tests/ReferenceImages\""
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
|
||||||
Similar to our much-loved XCTAssert() macros. Use this to perform your test. No need to write an explanation, though.
|
|
||||||
@param view The view to snapshot
|
|
||||||
@param identifier An optional identifier, used if there are multiple snapshot tests in a given -test method.
|
|
||||||
@param referenceImageDirectorySuffix An optional suffix, appended to the reference image directory path, such as "_iOS8"
|
|
||||||
*/
|
|
||||||
#define FBSnapshotVerifyViewWithReferenceDirectorySuffix(view__, identifier__, referenceImagesDirectorySuffix__) \
|
|
||||||
{ \
|
|
||||||
NSError *error__ = nil; \
|
|
||||||
NSString *referenceImagesDirectory__ = [NSString stringWithFormat:@"%s%@", FB_REFERENCE_IMAGE_DIR, referenceImagesDirectorySuffix__]; \
|
|
||||||
BOOL comparisonSuccess__ = [self compareSnapshotOfView:(view__) referenceImagesDirectory:referenceImagesDirectory__ identifier:(identifier__) error:&error__]; \
|
|
||||||
XCTAssertTrue(comparisonSuccess__, @"Snapshot comparison failed: %@", error__); \
|
|
||||||
}
|
|
||||||
|
|
||||||
#define FBSnapshotVerifyView(view__, identifier__) \
|
|
||||||
{ \
|
|
||||||
FBSnapshotVerifyViewWithReferenceDirectorySuffix(view__, identifier__, @""); \
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Similar to our much-loved XCTAssert() macros. Use this to perform your test. No need to write an explanation, though.
|
|
||||||
@param layer The layer to snapshot
|
|
||||||
@param identifier An optional identifier, used is there are multiple snapshot tests in a given -test method.
|
|
||||||
@param referenceImageDirectorySuffix An optional suffix, appended to the reference image directory path, such as "_iOS8"
|
|
||||||
*/
|
|
||||||
#define FBSnapshotVerifyLayerWithReferenceDirectorySuffix(layer__, identifier__, referenceImagesDirectorySuffix__) \
|
|
||||||
{ \
|
|
||||||
NSError *error__ = nil; \
|
|
||||||
NSString *referenceImagesDirectory__ = [NSString stringWithFormat:@"%s%@", FB_REFERENCE_IMAGE_DIR, referenceImagesDirectorySuffix__]; \
|
|
||||||
BOOL comparisonSuccess__ = [self compareSnapshotOfLayer:(layer__) referenceImagesDirectory:referenceImagesDirectory__ identifier:(identifier__) error:&error__]; \
|
|
||||||
XCTAssertTrue(comparisonSuccess__, @"Snapshot comparison failed: %@", error__); \
|
|
||||||
}
|
|
||||||
|
|
||||||
#define FBSnapshotVerifyLayer(layer__, identifier__) \
|
|
||||||
{ \
|
|
||||||
FBSnapshotVerifyLayerWithReferenceDirectorySuffix(layer__, identifier__, @""); \
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
The base class of view snapshotting tests. If you have small UI component, it's often easier to configure it in a test
|
The base class of view snapshotting tests. If you have small UI component, it's often easier to configure it in a test
|
||||||
and compare an image of the view to a reference image that write lots of complex layout-code tests.
|
and compare an image of the view to a reference image that write lots of complex layout-code tests.
|
||||||
|
@ -70,19 +32,6 @@ FBSnapshotVerifyLayerWithReferenceDirectorySuffix(layer__, identifier__, @""); \
|
||||||
*/
|
*/
|
||||||
@property (readwrite, nonatomic, assign) BOOL recordMode;
|
@property (readwrite, nonatomic, assign) BOOL recordMode;
|
||||||
|
|
||||||
/**
|
|
||||||
Performs the comparisons or records a snapshot of the layer if recordMode is YES.
|
|
||||||
@param layer The Layer to snapshot
|
|
||||||
@param referenceImagesDirectory The directory in which reference images are stored.
|
|
||||||
@param identifier An optional identifier, used if there are multiple snapshot tests in a given -test method.
|
|
||||||
@param error An error to log in an XCTAssert() macro if the method fails (missing reference image, images differ, etc).
|
|
||||||
@returns YES if the comparison (or saving of the reference image) succeeded.
|
|
||||||
*/
|
|
||||||
- (BOOL)compareSnapshotOfLayer:(CALayer *)layer
|
|
||||||
referenceImagesDirectory:(NSString *)referenceImagesDirectory
|
|
||||||
identifier:(NSString *)identifier
|
|
||||||
error:(NSError **)errorPtr;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Performs the comparisons or records a snapshot of the view if recordMode is YES.
|
Performs the comparisons or records a snapshot of the view if recordMode is YES.
|
||||||
@param view The view to snapshot
|
@param view The view to snapshot
|
||||||
|
|
|
@ -42,41 +42,16 @@
|
||||||
self.snapshotController.recordMode = recordMode;
|
self.snapshotController.recordMode = recordMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (BOOL)compareSnapshotOfLayer:(CALayer *)layer
|
|
||||||
referenceImagesDirectory:(NSString *)referenceImagesDirectory
|
|
||||||
identifier:(NSString *)identifier
|
|
||||||
error:(NSError **)errorPtr
|
|
||||||
{
|
|
||||||
return [self _compareSnapshotOfViewOrLayer:layer
|
|
||||||
referenceImagesDirectory:referenceImagesDirectory
|
|
||||||
identifier:identifier
|
|
||||||
error:errorPtr];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (BOOL)compareSnapshotOfView:(UIView *)view
|
- (BOOL)compareSnapshotOfView:(UIView *)view
|
||||||
referenceImagesDirectory:(NSString *)referenceImagesDirectory
|
referenceImagesDirectory:(NSString *)referenceImagesDirectory
|
||||||
identifier:(NSString *)identifier
|
identifier:(NSString *)identifier
|
||||||
error:(NSError **)errorPtr
|
error:(NSError **)errorPtr
|
||||||
{
|
|
||||||
return [self _compareSnapshotOfViewOrLayer:view
|
|
||||||
referenceImagesDirectory:referenceImagesDirectory
|
|
||||||
identifier:identifier
|
|
||||||
error:errorPtr];
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma mark -
|
|
||||||
#pragma mark Private API
|
|
||||||
|
|
||||||
- (BOOL)_compareSnapshotOfViewOrLayer:(id)viewOrLayer
|
|
||||||
referenceImagesDirectory:(NSString *)referenceImagesDirectory
|
|
||||||
identifier:(NSString *)identifier
|
|
||||||
error:(NSError **)errorPtr
|
|
||||||
{
|
{
|
||||||
_snapshotController.referenceImagesDirectory = referenceImagesDirectory;
|
_snapshotController.referenceImagesDirectory = referenceImagesDirectory;
|
||||||
return [_snapshotController compareSnapshotOfViewOrLayer:viewOrLayer
|
return [_snapshotController compareSnapshotOfView:view
|
||||||
selector:self.invocation.selector
|
selector:self.invocation.selector
|
||||||
identifier:identifier
|
identifier:identifier
|
||||||
error:errorPtr];
|
error:errorPtr];
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
|
@ -41,7 +41,7 @@ extern NSString *const FBReferenceImageFilePathKey;
|
||||||
@property(readwrite, nonatomic, assign) BOOL recordMode;
|
@property(readwrite, nonatomic, assign) BOOL recordMode;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@param testClass The subclass of FBSnapshotTestCase that is using this controller.d.
|
@param testClass The subclass of FBSnapshotTestCase that is using this controller.
|
||||||
@returns An instance of FBSnapshotTestController.
|
@returns An instance of FBSnapshotTestController.
|
||||||
*/
|
*/
|
||||||
- (id)initWithTestClass:(Class)testClass;
|
- (id)initWithTestClass:(Class)testClass;
|
||||||
|
@ -53,19 +53,6 @@ extern NSString *const FBReferenceImageFilePathKey;
|
||||||
*/
|
*/
|
||||||
- (id)initWithTestName:(NSString *)testName;
|
- (id)initWithTestName:(NSString *)testName;
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
Performs the comparison of the layer.
|
|
||||||
@param layer The Layer to snapshot.
|
|
||||||
@param identifier An optional identifier, used is there are muliptle snapshot tests in a given -test method.
|
|
||||||
@param errorPtr An error to log in an XCTAssert() macro if the method fails (missing reference image, images differ, etc).
|
|
||||||
@returns YES if the comparison (or saving of the reference image) succeeded.
|
|
||||||
*/
|
|
||||||
- (BOOL)compareSnapshotOfLayer:(CALayer *)layer
|
|
||||||
selector:(SEL)selector
|
|
||||||
identifier:(NSString *)identifier
|
|
||||||
error:(NSError **)errorPtr;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Performs the comparison of the view.
|
Performs the comparison of the view.
|
||||||
@param view The view to snapshot.
|
@param view The view to snapshot.
|
||||||
|
@ -79,20 +66,6 @@ extern NSString *const FBReferenceImageFilePathKey;
|
||||||
identifier:(NSString *)identifier
|
identifier:(NSString *)identifier
|
||||||
error:(NSError **)errorPtr;
|
error:(NSError **)errorPtr;
|
||||||
|
|
||||||
/**
|
|
||||||
Performs the comparison of a view or layer.
|
|
||||||
@param viewOrLayer The view or layer to snapshot.
|
|
||||||
@param selector selector
|
|
||||||
@param identifier An optional identifier, used is there are muliptle snapshot tests in a given -test method.
|
|
||||||
@param errorPtr An error to log in an XCTAssert() macro if the method fails (missing reference image, images differ, etc).
|
|
||||||
@returns YES if the comparison (or saving of the reference image) succeeded.
|
|
||||||
*/
|
|
||||||
- (BOOL)compareSnapshotOfViewOrLayer:(id)viewOrLayer
|
|
||||||
selector:(SEL)selector
|
|
||||||
identifier:(NSString *)identifier
|
|
||||||
error:(NSError **)errorPtr;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
The directory in which reference images are stored.
|
The directory in which reference images are stored.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -10,13 +10,13 @@
|
||||||
|
|
||||||
#import "FBSnapshotTestController.h"
|
#import "FBSnapshotTestController.h"
|
||||||
|
|
||||||
#import "UIImage+Compare.h"
|
|
||||||
#import "UIImage+Diff.h"
|
|
||||||
|
|
||||||
#import <objc/runtime.h>
|
#import <objc/runtime.h>
|
||||||
|
|
||||||
#import <UIKit/UIKit.h>
|
#import <UIKit/UIKit.h>
|
||||||
|
|
||||||
|
#import "UIImage+Compare.h"
|
||||||
|
#import "UIImage+Diff.h"
|
||||||
|
|
||||||
NSString *const FBSnapshotTestControllerErrorDomain = @"FBSnapshotTestControllerErrorDomain";
|
NSString *const FBSnapshotTestControllerErrorDomain = @"FBSnapshotTestControllerErrorDomain";
|
||||||
|
|
||||||
NSString *const FBReferenceImageFilePathKey = @"FBReferenceImageFilePathKey";
|
NSString *const FBReferenceImageFilePathKey = @"FBReferenceImageFilePathKey";
|
||||||
|
@ -39,15 +39,14 @@ typedef struct RGBAPixel {
|
||||||
NSFileManager *_fileManager;
|
NSFileManager *_fileManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma mark -
|
#pragma mark - Lifecycle
|
||||||
#pragma mark Lifecycle
|
|
||||||
|
|
||||||
- (id)initWithTestClass:(Class)testClass;
|
- (instancetype)initWithTestClass:(Class)testClass;
|
||||||
{
|
{
|
||||||
return [self initWithTestName:NSStringFromClass(testClass)];
|
return [self initWithTestName:NSStringFromClass(testClass)];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (id)initWithTestName:(NSString *)testName
|
- (instancetype)initWithTestName:(NSString *)testName
|
||||||
{
|
{
|
||||||
if ((self = [super init])) {
|
if ((self = [super init])) {
|
||||||
_testName = [testName copy];
|
_testName = [testName copy];
|
||||||
|
@ -56,16 +55,14 @@ typedef struct RGBAPixel {
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma mark -
|
#pragma mark - Properties
|
||||||
#pragma mark Properties
|
|
||||||
|
|
||||||
- (NSString *)description
|
- (NSString *)description
|
||||||
{
|
{
|
||||||
return [NSString stringWithFormat:@"%@ %@", [super description], _referenceImagesDirectory];
|
return [NSString stringWithFormat:@"%@ %@", [super description], _referenceImagesDirectory];
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma mark -
|
#pragma mark - Public API
|
||||||
#pragma mark Public API
|
|
||||||
|
|
||||||
- (UIImage *)referenceImageForSelector:(SEL)selector
|
- (UIImage *)referenceImageForSelector:(SEL)selector
|
||||||
identifier:(NSString *)identifier
|
identifier:(NSString *)identifier
|
||||||
|
@ -211,8 +208,7 @@ typedef struct RGBAPixel {
|
||||||
return NO;
|
return NO;
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma mark -
|
#pragma mark - Private API
|
||||||
#pragma mark Private API
|
|
||||||
|
|
||||||
typedef NS_ENUM(NSUInteger, FBTestSnapshotFileNameType) {
|
typedef NS_ENUM(NSUInteger, FBTestSnapshotFileNameType) {
|
||||||
FBTestSnapshotFileNameTypeReference,
|
FBTestSnapshotFileNameTypeReference,
|
||||||
|
@ -280,51 +276,28 @@ typedef NS_ENUM(NSUInteger, FBTestSnapshotFileNameType) {
|
||||||
return filePath;
|
return filePath;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (BOOL)compareSnapshotOfLayer:(CALayer *)layer
|
- (BOOL)compareSnapshotOfView:(id)view
|
||||||
selector:(SEL)selector
|
|
||||||
identifier:(NSString *)identifier
|
|
||||||
error:(NSError **)errorPtr
|
|
||||||
{
|
|
||||||
return [self compareSnapshotOfViewOrLayer:layer
|
|
||||||
selector:selector
|
|
||||||
identifier:identifier
|
|
||||||
error:errorPtr];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (BOOL)compareSnapshotOfView:(UIView *)view
|
|
||||||
selector:(SEL)selector
|
selector:(SEL)selector
|
||||||
identifier:(NSString *)identifier
|
identifier:(NSString *)identifier
|
||||||
error:(NSError **)errorPtr
|
error:(NSError **)errorPtr
|
||||||
{
|
|
||||||
return [self compareSnapshotOfViewOrLayer:view
|
|
||||||
selector:selector
|
|
||||||
identifier:identifier
|
|
||||||
error:errorPtr];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (BOOL)compareSnapshotOfViewOrLayer:(id)viewOrLayer
|
|
||||||
selector:(SEL)selector
|
|
||||||
identifier:(NSString *)identifier
|
|
||||||
error:(NSError **)errorPtr
|
|
||||||
{
|
{
|
||||||
if (self.recordMode) {
|
if (self.recordMode) {
|
||||||
return [self _recordSnapshotOfViewOrLayer:viewOrLayer selector:selector identifier:identifier error:errorPtr];
|
return [self _recordSnapshotOfView:view selector:selector identifier:identifier error:errorPtr];
|
||||||
} else {
|
} else {
|
||||||
return [self _performPixelComparisonWithViewOrLayer:viewOrLayer selector:selector identifier:identifier error:errorPtr];
|
return [self _performPixelComparisonWithView:view selector:selector identifier:identifier error:errorPtr];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma mark -
|
#pragma mark - Private API
|
||||||
#pragma mark Private API
|
|
||||||
|
|
||||||
- (BOOL)_performPixelComparisonWithViewOrLayer:(UIView *)viewOrLayer
|
- (BOOL)_performPixelComparisonWithView:(UIView *)view
|
||||||
selector:(SEL)selector
|
selector:(SEL)selector
|
||||||
identifier:(NSString *)identifier
|
identifier:(NSString *)identifier
|
||||||
error:(NSError **)errorPtr
|
error:(NSError **)errorPtr
|
||||||
{
|
{
|
||||||
UIImage *referenceImage = [self referenceImageForSelector:selector identifier:identifier error:errorPtr];
|
UIImage *referenceImage = [self referenceImageForSelector:selector identifier:identifier error:errorPtr];
|
||||||
if (nil != referenceImage) {
|
if (nil != referenceImage) {
|
||||||
UIImage *snapshot = [self _snapshotViewOrLayer:viewOrLayer];
|
UIImage *snapshot = [self _snapshotView:view];
|
||||||
BOOL imagesSame = [self compareReferenceImage:referenceImage toImage:snapshot error:errorPtr];
|
BOOL imagesSame = [self compareReferenceImage:referenceImage toImage:snapshot error:errorPtr];
|
||||||
if (!imagesSame) {
|
if (!imagesSame) {
|
||||||
[self saveFailedReferenceImage:referenceImage
|
[self saveFailedReferenceImage:referenceImage
|
||||||
|
@ -338,46 +311,33 @@ typedef NS_ENUM(NSUInteger, FBTestSnapshotFileNameType) {
|
||||||
return NO;
|
return NO;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (BOOL)_recordSnapshotOfViewOrLayer:(id)viewOrLayer
|
- (BOOL)_recordSnapshotOfView:(UIView *)view
|
||||||
selector:(SEL)selector
|
selector:(SEL)selector
|
||||||
identifier:(NSString *)identifier
|
identifier:(NSString *)identifier
|
||||||
error:(NSError **)errorPtr
|
error:(NSError **)errorPtr
|
||||||
{
|
{
|
||||||
UIImage *snapshot = [self _snapshotViewOrLayer:viewOrLayer];
|
UIImage *snapshot = [self _snapshotView:view];
|
||||||
return [self saveReferenceImage:snapshot selector:selector identifier:identifier error:errorPtr];
|
return [self saveReferenceImage:snapshot selector:selector identifier:identifier error:errorPtr];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (UIImage *)_snapshotViewOrLayer:(id)viewOrLayer
|
- (UIImage *)_snapshotView:(UIView *)view
|
||||||
{
|
{
|
||||||
CALayer *layer = nil;
|
[view layoutIfNeeded];
|
||||||
|
|
||||||
if ([viewOrLayer isKindOfClass:[UIView class]]) {
|
CGRect bounds = view.bounds;
|
||||||
return [self _renderView:viewOrLayer];
|
|
||||||
} else if ([viewOrLayer isKindOfClass:[CALayer class]]) {
|
|
||||||
layer = (CALayer *)viewOrLayer;
|
|
||||||
[layer layoutIfNeeded];
|
|
||||||
return [self _renderLayer:layer];
|
|
||||||
} else {
|
|
||||||
[NSException raise:@"Only UIView and CALayer classes can be snapshotted" format:@"%@", viewOrLayer];
|
|
||||||
}
|
|
||||||
return nil;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (UIImage *)_renderLayer:(CALayer *)layer
|
NSAssert1(CGRectGetWidth(bounds), @"Zero width for view %@", view);
|
||||||
{
|
NSAssert1(CGRectGetHeight(bounds), @"Zero height for view %@", view);
|
||||||
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, 0);
|
||||||
CGContextRef context = UIGraphicsGetCurrentContext();
|
CGContextRef context = UIGraphicsGetCurrentContext();
|
||||||
NSAssert1(context, @"Could not generate context for layer %@", layer);
|
NSAssert1(context, @"Could not generate context for view %@", view);
|
||||||
|
|
||||||
UIGraphicsPushContext(context);
|
UIGraphicsPushContext(context);
|
||||||
CGContextSaveGState(context);
|
CGContextSaveGState(context);
|
||||||
{
|
{
|
||||||
[layer renderInContext:context];
|
BOOL success = [view drawViewHierarchyInRect:bounds afterScreenUpdates:YES];
|
||||||
|
NSAssert1(success, @"Could not create snapshot for view %@", view);
|
||||||
}
|
}
|
||||||
CGContextRestoreGState(context);
|
CGContextRestoreGState(context);
|
||||||
UIGraphicsPopContext();
|
UIGraphicsPopContext();
|
||||||
|
@ -388,10 +348,4 @@ typedef NS_ENUM(NSUInteger, FBTestSnapshotFileNameType) {
|
||||||
return snapshot;
|
return snapshot;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (UIImage *)_renderView:(UIView *)view
|
|
||||||
{
|
|
||||||
[view layoutIfNeeded];
|
|
||||||
return [self _renderLayer:view.layer];
|
|
||||||
}
|
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
Before Width: | Height: | Size: 73 KiB After Width: | Height: | Size: 73 KiB |
Before Width: | Height: | Size: 59 KiB After Width: | Height: | Size: 59 KiB |
After Width: | Height: | Size: 73 KiB |
After Width: | Height: | Size: 59 KiB |
Before Width: | Height: | Size: 153 KiB After Width: | Height: | Size: 152 KiB |
Before Width: | Height: | Size: 89 KiB After Width: | Height: | Size: 89 KiB |
Before Width: | Height: | Size: 153 KiB After Width: | Height: | Size: 153 KiB |
Before Width: | Height: | Size: 88 KiB After Width: | Height: | Size: 88 KiB |
Before Width: | Height: | Size: 130 KiB After Width: | Height: | Size: 130 KiB |
Before Width: | Height: | Size: 90 KiB After Width: | Height: | Size: 90 KiB |
Before Width: | Height: | Size: 130 KiB After Width: | Height: | Size: 130 KiB |
Before Width: | Height: | Size: 89 KiB After Width: | Height: | Size: 89 KiB |
Before Width: | Height: | Size: 182 KiB After Width: | Height: | Size: 166 KiB |
Before Width: | Height: | Size: 182 KiB After Width: | Height: | Size: 166 KiB |
Before Width: | Height: | Size: 147 KiB After Width: | Height: | Size: 145 KiB |
Before Width: | Height: | Size: 147 KiB After Width: | Height: | Size: 145 KiB |
Before Width: | Height: | Size: 78 KiB After Width: | Height: | Size: 78 KiB |
Before Width: | Height: | Size: 49 KiB After Width: | Height: | Size: 203 KiB |
Before Width: | Height: | Size: 78 KiB After Width: | Height: | Size: 78 KiB |
Before Width: | Height: | Size: 49 KiB After Width: | Height: | Size: 91 KiB |
Before Width: | Height: | Size: 365 KiB After Width: | Height: | Size: 364 KiB |
Before Width: | Height: | Size: 127 KiB After Width: | Height: | Size: 127 KiB |
Before Width: | Height: | Size: 365 KiB After Width: | Height: | Size: 365 KiB |
Before Width: | Height: | Size: 124 KiB After Width: | Height: | Size: 124 KiB |
Before Width: | Height: | Size: 175 KiB After Width: | Height: | Size: 174 KiB |
Before Width: | Height: | Size: 96 KiB After Width: | Height: | Size: 96 KiB |
Before Width: | Height: | Size: 175 KiB After Width: | Height: | Size: 174 KiB |
Before Width: | Height: | Size: 95 KiB After Width: | Height: | Size: 95 KiB |