@@ -46,89 +46,64 @@ @implementation UIImage (Compare)
4646
4747- (BOOL )fb_compareWithImage : (UIImage *)image tolerance : (CGFloat)tolerance
4848{
49+ return [self fb_isEqualToImage: image] || (tolerance > 0.0 && [self fb_differenceFromImage: image] < tolerance);
50+ }
51+
52+
53+ - (BOOL )fb_isEqualToImage : (UIImage *)image {
4954 NSAssert (CGSizeEqualToSize(self.size, image.size), @"Images must be same size.");
5055
51- CGSize referenceImageSize = CGSizeMake (CGImageGetWidth (self.CGImage ), CGImageGetHeight (self.CGImage ));
52- CGSize imageSize = CGSizeMake (CGImageGetWidth (image.CGImage ), CGImageGetHeight (image.CGImage ));
53-
54- // The images have the equal size, so we could use the smallest amount of bytes because of byte padding
55- size_t minBytesPerRow = MIN (CGImageGetBytesPerRow (self.CGImage ), CGImageGetBytesPerRow (image.CGImage ));
56- size_t referenceImageSizeBytes = referenceImageSize.height * minBytesPerRow;
57- void *referenceImagePixels = calloc (1 , referenceImageSizeBytes);
58- void *imagePixels = calloc (1 , referenceImageSizeBytes);
59-
60- if (!referenceImagePixels || !imagePixels) {
61- free (referenceImagePixels);
62- free (imagePixels);
63- return NO ;
64- }
56+ CGContextRef referenceContext = [self fb_bitmapContext ];
57+ CGContextRef imageContext = [image fb_bitmapContext ];
6558
66- CGContextRef referenceImageContext = CGBitmapContextCreate (referenceImagePixels,
67- referenceImageSize.width ,
68- referenceImageSize.height ,
69- CGImageGetBitsPerComponent (self.CGImage ),
70- minBytesPerRow,
71- CGImageGetColorSpace (self.CGImage ),
72- (CGBitmapInfo)kCGImageAlphaPremultipliedLast
73- );
74- CGContextRef imageContext = CGBitmapContextCreate (imagePixels,
75- imageSize.width ,
76- imageSize.height ,
77- CGImageGetBitsPerComponent (image.CGImage ),
78- minBytesPerRow,
79- CGImageGetColorSpace (image.CGImage ),
80- (CGBitmapInfo)kCGImageAlphaPremultipliedLast
81- );
82-
83- if (!referenceImageContext || !imageContext) {
84- CGContextRelease (referenceImageContext);
85- CGContextRelease (imageContext);
86- free (referenceImagePixels);
87- free (imagePixels);
88- return NO ;
89- }
90-
91- CGContextDrawImage (referenceImageContext, CGRectMake (0 , 0 , referenceImageSize.width , referenceImageSize.height ), self.CGImage );
92- CGContextDrawImage (imageContext, CGRectMake (0 , 0 , imageSize.width , imageSize.height ), image.CGImage );
93-
94- CGContextRelease (referenceImageContext);
59+ size_t pixelCount = CGBitmapContextGetHeight (referenceContext) * CGBitmapContextGetBytesPerRow (referenceContext);
60+ BOOL matches = (memcmp (CGBitmapContextGetData (referenceContext), CGBitmapContextGetData (imageContext), pixelCount) == 0 );
61+
62+ CGContextRelease (referenceContext);
9563 CGContextRelease (imageContext);
64+
65+ return matches;
66+ }
9667
97- BOOL imageEqual = YES ;
98-
99- // Do a fast compare if we can
100- if (tolerance == 0 ) {
101- imageEqual = (memcmp (referenceImagePixels, imagePixels, referenceImageSizeBytes) == 0 );
102- } else {
103- // Go through each pixel in turn and see if it is different
104- const NSInteger pixelCount = referenceImageSize.width * referenceImageSize.height ;
105-
106- FBComparePixel *p1 = referenceImagePixels;
107- FBComparePixel *p2 = imagePixels;
108-
109- NSInteger numDiffPixels = 0 ;
110- for (int n = 0 ; n < pixelCount; ++n) {
111- // If this pixel is different, increment the pixel diff count and see
112- // if we have hit our limit.
113- if (p1->raw != p2->raw ) {
114- numDiffPixels ++;
115-
116- CGFloat percent = (CGFloat)numDiffPixels / pixelCount;
117- if (percent > tolerance) {
118- imageEqual = NO ;
119- break ;
120- }
121- }
68+ - (CGFloat)fb_differenceFromImage : (UIImage *)image {
69+ NSAssert (CGSizeEqualToSize(self.size, image.size), @"Images must be same size.");
12270
123- p1++;
124- p2++;
71+ // Go through each pixel in turn and see if it is different
72+ CGContextRef referenceContext = [self fb_bitmapContext ];
73+ CGContextRef imageContext = [image fb_bitmapContext ];
74+
75+ FBComparePixel *p1 = CGBitmapContextGetData (referenceContext);
76+ FBComparePixel *p2 = CGBitmapContextGetData (imageContext);
77+
78+ NSInteger pixelCount = CGBitmapContextGetWidth (referenceContext) * CGBitmapContextGetHeight (referenceContext);
79+ NSInteger numDiffPixels = 0 ;
80+ for (int n = 0 ; n < pixelCount; ++n) {
81+ // If this pixel is different, increment the pixel diff count and see
82+ // if we have hit our limit.
83+ if (p1->raw != p2->raw ) {
84+ numDiffPixels++;
12585 }
86+
87+ p1++;
88+ p2++;
12689 }
90+
91+ return (CGFloat)numDiffPixels / pixelCount;
92+ }
12793
128- free (referenceImagePixels);
129- free (imagePixels);
130-
131- return imageEqual;
94+ - (CGContextRef)fb_bitmapContext {
95+ CGContextRef context = CGBitmapContextCreate (NULL ,
96+ self.size .width ,
97+ self.size .height ,
98+ CGImageGetBitsPerComponent (self.CGImage ),
99+ CGImageGetBytesPerRow (self.CGImage ),
100+ CGImageGetColorSpace (self.CGImage ),
101+ (CGBitmapInfo)kCGImageAlphaPremultipliedLast );
102+
103+ CGContextDrawImage (context, (CGRect){.size = self.size }, self.CGImage );
104+
105+ NSAssert (context != nil , @" Unable to create context for comparision." );
106+ return context;
132107}
133108
134109@end
0 commit comments