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 694db16..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,10 +73,9 @@ - (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 = OSBytesPerRowForWidth(width); NSUInteger bitsPerComponent = 8; + NSMutableData *data = [NSMutableData dataWithLength:height * bytesPerRow]; CGContextRef context = CGBitmapContextCreate([data mutableBytes], width, height, bitsPerComponent, bytesPerRow, colorSpace, kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big); CGColorSpaceRelease(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]; diff --git a/CocoaImageHashingTests/OSFastGraphicsTests.m b/CocoaImageHashingTests/OSFastGraphicsTests.m index 3899b6b..d3e2718 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); @@ -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