1
0
mirror of https://github.com/arsenetar/dupeguru.git synced 2024-11-05 07:49:02 +00:00
dupeguru/pe/cocoa/PictureBlocks.m
hsoft 7e45f422e1 [#64 state:fixed] fixed a bug in PictureBlocks where transparency could make two equal pictures return two different sets of blocks.
--HG--
extra : convert_revision : svn%3Ac306627e-7827-47d3-bdf0-9a457c9553a1/trunk%40150
2009-09-28 15:33:25 +00:00

146 lines
5.0 KiB
Objective-C

/*
Copyright 2009 Hardcoded Software (http://www.hardcoded.net)
This software is licensed under the "HS" License as described in the "LICENSE" file,
which should be included with this package. The terms are also available at
http://www.hardcoded.net/licenses/hs_license
*/
#import "PictureBlocks.h"
#import "Utils.h"
@implementation PictureBlocks
+ (NSString *)getBlocksFromImagePath:(NSString *)imagePath blockCount:(NSNumber *)blockCount
{
return GetBlocks(imagePath, n2i(blockCount));
}
+ (NSSize)getImageSize:(NSString *)imagePath
{
CFURLRef fileURL = CFURLCreateWithFileSystemPath(NULL, (CFStringRef)imagePath, kCFURLPOSIXPathStyle, FALSE);
CGImageSourceRef source = CGImageSourceCreateWithURL(fileURL, NULL);
if (source == NULL)
return NSMakeSize(0, 0);
CGImageRef image = CGImageSourceCreateImageAtIndex(source, 0, NULL);
if (image == NULL)
return NSMakeSize(0, 0);
size_t width = CGImageGetWidth(image);
size_t height = CGImageGetHeight(image);
CGImageRelease(image);
CFRelease(source);
CFRelease(fileURL);
return NSMakeSize(width, height);
}
@end
CGContextRef MyCreateBitmapContext (int width, int height)
{
CGContextRef context = NULL;
CGColorSpaceRef colorSpace;
void * bitmapData;
int bitmapByteCount;
int bitmapBytesPerRow;
bitmapBytesPerRow = (width * 4);
bitmapByteCount = (bitmapBytesPerRow * height);
colorSpace = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB);
// calloc() must be used to allocate bitmapData here because the buffer has to be zeroed.
// If it's not zeroes, when images with transparency are drawn in the context, this buffer
// will stay with undefined pixels, which means that two pictures with the same pixels will
// most likely have different blocks (which is not supposed to happen).
bitmapData = calloc(bitmapByteCount, 1);
if (bitmapData == NULL)
{
fprintf (stderr, "Memory not allocated!");
return NULL;
}
context = CGBitmapContextCreate (bitmapData,width,height,8,bitmapBytesPerRow,colorSpace,kCGImageAlphaNoneSkipLast);
if (context== NULL)
{
free (bitmapData);
fprintf (stderr, "Context not created!");
return NULL;
}
CGColorSpaceRelease( colorSpace );
return context;
}
// returns 0x00RRGGBB
int GetBlock(unsigned char *imageData, int imageWidth, int imageHeight, int boxX, int boxY, int boxW, int boxH)
{
int i,j;
int totalR = 0;
int totalG = 0;
int totalB = 0;
for(i = boxY; i < boxY + boxH; i++)
{
for(j = boxX; j < boxX + boxW; j++)
{
int offset = (i * imageWidth * 4) + (j * 4);
totalR += *(imageData + offset);
totalG += *(imageData + offset + 1);
totalB += *(imageData + offset + 2);
}
}
int pixelCount = boxH * boxW;
int result = 0;
result += (totalR / pixelCount) << 16;
result += (totalG / pixelCount) << 8;
result += (totalB / pixelCount);
return result;
}
NSString* GetBlocks (NSString* filePath, int blockCount)
{
CFURLRef fileURL = CFURLCreateWithFileSystemPath(NULL, (CFStringRef)filePath, kCFURLPOSIXPathStyle, FALSE);
CGImageSourceRef source = CGImageSourceCreateWithURL(fileURL, NULL);
if (source == NULL)
return NULL;
CGImageRef image = CGImageSourceCreateImageAtIndex(source, 0, NULL);
if (image == NULL)
return NULL;
size_t width = CGImageGetWidth(image);
size_t height = CGImageGetHeight(image);
CGContextRef myContext = MyCreateBitmapContext(width, height);
CGRect myBoundingBox = CGRectMake (0, 0, width, height);
CGContextDrawImage(myContext, myBoundingBox, image);
unsigned char *bitmapData = CGBitmapContextGetData(myContext);
if (bitmapData == NULL)
return NULL;
int blockHeight = height / blockCount;
if (blockHeight < 1)
blockHeight = 1;
int blockWidth = width / blockCount;
if (blockWidth < 1)
blockWidth = 1;
//blockCount might have changed
int blockXCount = (width / blockWidth);
int blockYCount = (height / blockHeight);
CFMutableArrayRef blocks = CFArrayCreateMutable(NULL, blockXCount * blockYCount, &kCFTypeArrayCallBacks);
int i,j;
for(i = 0; i < blockYCount; i++)
{
for(j = 0; j < blockXCount; j++)
{
int block = GetBlock(bitmapData, width, height, j * blockWidth, i * blockHeight, blockWidth, blockHeight);
CFStringRef strBlock = CFStringCreateWithFormat(NULL, NULL, CFSTR("%06x"), block);
CFArrayAppendValue(blocks, strBlock);
CFRelease(strBlock);
}
}
CGContextRelease (myContext);
if (bitmapData) free(bitmapData);
CGImageRelease(image);
CFRelease(source);
CFRelease(fileURL);
CFStringRef result = CFStringCreateByCombiningStrings(NULL, blocks, CFSTR(""));
CFRelease(blocks);
return (NSString *)result;
}