From 51d55d45fdcd080746bb67ce3a870b516ddaa695 Mon Sep 17 00:00:00 2001 From: David Goldwich Date: Fri, 23 Sep 2016 17:49:47 +0200 Subject: [PATCH 1/4] Fix dHash scanline on iOS 19f22bf fixed this for macOS but not for iOS. --- CocoaImageHashing/OSCategories.m | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CocoaImageHashing/OSCategories.m b/CocoaImageHashing/OSCategories.m index 694db16..912151c 100644 --- a/CocoaImageHashing/OSCategories.m +++ b/CocoaImageHashing/OSCategories.m @@ -68,10 +68,10 @@ - (NSData *)RGBABitmapDataForResizedImageWithWidth:(NSUInteger)width return nil; } CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); - NSMutableData *data = [NSMutableData dataWithLength:height * width * 4]; NSUInteger bytesPerPixel = 4; - NSUInteger bytesPerRow = bytesPerPixel * width; + NSUInteger bytesPerRow = OS_ALIGN(width * bytesPerPixel, 64); NSUInteger bitsPerComponent = 8; + NSMutableData *data = [NSMutableData dataWithLength:height * bytesPerRow]; CGContextRef context = CGBitmapContextCreate([data mutableBytes], width, height, bitsPerComponent, bytesPerRow, colorSpace, kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big); CGColorSpaceRelease(colorSpace); From ea74924b76320b4b2db05ce691111a8a790622f8 Mon Sep 17 00:00:00 2001 From: David Goldwich Date: Thu, 3 Nov 2016 22:20:21 +0100 Subject: [PATCH 2/4] Fix scanline for aHash and pHash 19f22bf currently breaks calculations of aHash and pHash: For an image width of 8 pixels OS_ALIGN advices a 64-byte scanline, adding 32 bytes of zero-padding, but the aHash and pHash implementations in OSFastGraphics expect 32-byte scanlines without any padding. This commit introduces an inline mediator function to force a 32-byte scanline for images with an width of 8 pixels. --- CocoaImageHashing/OSCategories.h | 4 ++-- CocoaImageHashing/OSCategories.m | 24 ++++++++++++++---------- 2 files changed, 16 insertions(+), 12 deletions(-) diff --git a/CocoaImageHashing/OSCategories.h b/CocoaImageHashing/OSCategories.h index 7e6390c..5b5c04e 100644 --- a/CocoaImageHashing/OSCategories.h +++ b/CocoaImageHashing/OSCategories.h @@ -63,8 +63,8 @@ NS_ASSUME_NONNULL_END NS_ASSUME_NONNULL_BEGIN + (NSBitmapImageRep *)imageRepFrom:(NSBitmapImageRep *)sourceImageRep - scaledToWidth:(NSInteger)width - scaledToHeight:(NSInteger)height + scaledToWidth:(NSUInteger)width + scaledToHeight:(NSUInteger)height usingInterpolation:(NSImageInterpolation)imageInterpolation; NS_ASSUME_NONNULL_END diff --git a/CocoaImageHashing/OSCategories.m b/CocoaImageHashing/OSCategories.m index 912151c..9bdd706 100644 --- a/CocoaImageHashing/OSCategories.m +++ b/CocoaImageHashing/OSCategories.m @@ -52,6 +52,11 @@ - (void)arrayWithPairCombinations:(BOOL (^)(id leftHand, id rightHand))matcher #pragma mark - NSData Category +OS_INLINE OS_ALWAYS_INLINE NSUInteger OSBytesPerRowForWidth(NSUInteger width) +{ + return (width == 8) ? 32 : OS_ALIGN(4 * width, 64); +} + #if (TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR) @implementation NSData (CocoaImageHashing) @@ -68,8 +73,7 @@ - (NSData *)RGBABitmapDataForResizedImageWithWidth:(NSUInteger)width return nil; } CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); - NSUInteger bytesPerPixel = 4; - NSUInteger bytesPerRow = OS_ALIGN(width * bytesPerPixel, 64); + NSUInteger bytesPerRow = OSBytesPerRowForWidth(width); NSUInteger bitsPerComponent = 8; NSMutableData *data = [NSMutableData dataWithLength:height * bytesPerRow]; CGContextRef context = CGBitmapContextCreate([data mutableBytes], width, height, bitsPerComponent, bytesPerRow, colorSpace, @@ -95,15 +99,15 @@ - (NSData *)RGBABitmapDataForResizedImageWithWidth:(NSUInteger)width return nil; } NSBitmapImageRep *imageRep = [NSBitmapImageRep imageRepFrom:sourceImageRep - scaledToWidth:(NSInteger)width - scaledToHeight:(NSInteger)height + scaledToWidth:width + scaledToHeight:height usingInterpolation:NSImageInterpolationHigh]; if (!imageRep) { return nil; } unsigned char *pixels = [imageRep bitmapData]; NSData *result = [NSData dataWithBytes:pixels - length:OS_ALIGN(4 * width, 64) * height]; + length:OSBytesPerRowForWidth(width) * height]; return result; } @@ -118,19 +122,19 @@ - (NSData *)RGBABitmapDataForResizedImageWithWidth:(NSUInteger)width @implementation NSBitmapImageRep (CocoaImageHashing) + (NSBitmapImageRep *)imageRepFrom:(NSBitmapImageRep *)sourceImageRep - scaledToWidth:(NSInteger)width - scaledToHeight:(NSInteger)height + scaledToWidth:(NSUInteger)width + scaledToHeight:(NSUInteger)height usingInterpolation:(NSImageInterpolation)imageInterpolation { NSBitmapImageRep *imageRep = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:NULL - pixelsWide:width - pixelsHigh:height + pixelsWide:(NSInteger)width + pixelsHigh:(NSInteger)height bitsPerSample:8 samplesPerPixel:4 hasAlpha:YES isPlanar:NO colorSpaceName:NSCalibratedRGBColorSpace - bytesPerRow:OS_ALIGN(4 * width, 64) // multiple of 64 bytes to improve CG performance + bytesPerRow:(NSInteger)OSBytesPerRowForWidth(width) bitsPerPixel:0]; [NSGraphicsContext saveGraphicsState]; NSGraphicsContext *context = [NSGraphicsContext graphicsContextWithBitmapImageRep:imageRep]; From c9d823be6978f8ffe2e40eb30f9164bcbf1d84a4 Mon Sep 17 00:00:00 2001 From: David Goldwich Date: Thu, 3 Nov 2016 22:24:57 +0100 Subject: [PATCH 3/4] Fix test image dimensions --- CocoaImageHashingTests/OSFastGraphicsTests.m | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/CocoaImageHashingTests/OSFastGraphicsTests.m b/CocoaImageHashingTests/OSFastGraphicsTests.m index 3899b6b..34e2e5b 100644 --- a/CocoaImageHashingTests/OSFastGraphicsTests.m +++ b/CocoaImageHashingTests/OSFastGraphicsTests.m @@ -124,8 +124,8 @@ - (void)testRotateRGBAMatrixPerformance - (void)testDCT { NSData *imageData = [self loadImageAsData:@"blurred/architecture1.bmp"]; - NSData *pixels = [imageData RGBABitmapDataForResizedImageWithWidth:32 - andHeight:32]; + NSData *pixels = [imageData RGBABitmapDataForResizedImageWithWidth:8 + andHeight:8]; double greyscalePixels[32][32] = {{0.0}}; double fastDctPixels[32][32] = {{0.0}}; double dctPixels[32][32] = {{0.0}}; @@ -143,8 +143,8 @@ - (void)testFastDCTMultithreadedPerformance { const NSUInteger iterations = 1024 * 2; NSData *imageData = [self loadImageAsData:@"blurred/architecture1.bmp"]; - NSData *pixels = [imageData RGBABitmapDataForResizedImageWithWidth:32 - andHeight:32]; + NSData *pixels = [imageData RGBABitmapDataForResizedImageWithWidth:8 + andHeight:8]; double fastDctPixels[32][32] = {{0.0}}; double greyscalePixels[32][32] = {{0.0}}; greyscale_pixels_rgba_32_32([pixels bytes], greyscalePixels); From 487b4a072f4b630b902359034b2ffeac7456a924 Mon Sep 17 00:00:00 2001 From: David Goldwich Date: Thu, 3 Nov 2016 22:56:13 +0100 Subject: [PATCH 4/4] Add basic test for excessive padding on resized bitmap data --- CocoaImageHashingTests/OSFastGraphicsTests.m | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/CocoaImageHashingTests/OSFastGraphicsTests.m b/CocoaImageHashingTests/OSFastGraphicsTests.m index 34e2e5b..d3e2718 100644 --- a/CocoaImageHashingTests/OSFastGraphicsTests.m +++ b/CocoaImageHashingTests/OSFastGraphicsTests.m @@ -158,4 +158,22 @@ - (void)testFastDCTMultithreadedPerformance NSLog(@"DCT processing %@ MB/s", @(MBs / executionTime)); } +- (void)testResizedRGBABitmapDataScanline +{ + NSData *imageData = [self loadImageAsData:@"misc/latrobe.bmp"]; + for (NSUInteger dim = 8; dim <= 9; dim++) { + NSData *pixels = [imageData RGBABitmapDataForResizedImageWithWidth:dim + andHeight:dim]; + uint64_t *lines = (uint64_t *)[pixels bytes]; + NSUInteger length = [pixels length] / sizeof(lines); + for (NSUInteger i = 0; i < length; i += 8) { + XCTAssertNotEqual(lines[i], (uint64_t)0); + XCTAssertNotEqual(lines[i + 1], (uint64_t)0); + XCTAssertNotEqual(lines[i + 2], (uint64_t)0); + XCTAssertNotEqual(lines[i + 3], (uint64_t)0); + XCTAssertNotEqual(lines[i + 4], (uint64_t)0); + } + } +} + @end