2009-08-05 08:59:46 +00:00
|
|
|
/*
|
|
|
|
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
|
|
|
|
*/
|
|
|
|
|
2009-06-01 09:55:11 +00:00
|
|
|
#import "PictureBlocks.h"
|
|
|
|
#import "Utils.h"
|
|
|
|
|
|
|
|
@implementation PictureBlocks
|
2009-09-28 15:33:25 +00:00
|
|
|
+ (NSString *)getBlocksFromImagePath:(NSString *)imagePath blockCount:(NSNumber *)blockCount
|
2009-06-01 09:55:11 +00:00
|
|
|
{
|
2009-09-28 15:33:25 +00:00
|
|
|
return GetBlocks(imagePath, n2i(blockCount));
|
2009-06-01 09:55:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
+ (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);
|
|
|
|
|
2009-09-28 15:33:25 +00:00
|
|
|
// 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);
|
2009-06-01 09:55:11 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2009-09-28 15:33:25 +00:00
|
|
|
NSString* GetBlocks (NSString* filePath, int blockCount)
|
2009-06-01 09:55:11 +00:00
|
|
|
{
|
|
|
|
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;
|
|
|
|
}
|