我正在构建一个 Cocoa 应用程序来帮助我整理我的数以万计的数码图片。它旨在保留一个非常精简的信息数据库,以便我找到我想要的图像,然后我可以转到保存实际图像的存储(刻录到 DVD 或 CD)。我可以浏览图像并设置评分、标签等。然后我将这些数据存储在我的硬盘上,使用一个比几十张图片本身还小的数据库。在我的数据库中,我想存储一个缩略图(这将使它大约 10 倍大)。我玩过几种技术,使用 JPEG-2000 格式是最小的,但它似乎无法正常显示?
我创建缩略图的代码是:
// This code 'downsamples' my very large digital pictures
// Thumbnail size
int pixelsWide = 72;
int pixelsHigh = 72;
CGContextRef myBitmapContext = NULL;
CGColorSpaceRef colorSpace;
void *bitmapData;
int bitmapByteCount;
int bitmapBytesPerRow;
bitmapBytesPerRow = (pixelsWide * 4);
bitmapByteCount = (bitmapBytesPerRow * pixelsHigh);
colorSpace = CGColorSpaceCreateWithName( kCGColorSpaceGenericRGB );
bitmapData = calloc( 1, bitmapByteCount );
if( bitmapData == NULL ) {
NSLog( @"Memory not allocated!" );
} else {
myBitmapContext = CGBitmapContextCreate( bitmapData,
pixelsWide,
pixelsHigh,
8, // bits per component
bitmapBytesPerRow,
colorSpace,
kCGImageAlphaPremultipliedLast );
if( myBitmapContext == NULL ) {
free (bitmapData);
NSLog( @"myBitmapContext not created!" );
}
}
CGColorSpaceRelease( colorSpace );
// This gets any zooming or rotating that I've done to the master image
CGAffineTransform imageTransformMatrix = [self generateImageTransformMatrixForRect: NSMakeRect( 0.0, 0.0, (CGFloat) pixelsWide, (CGFloat) pixelsHigh )];
CGContextConcatCTM( myBitmapContext, imageTransformMatrix );
// imageRef is a CGImageRef to the master image to create the thumbnail of
double imgWidth = (double) CGImageGetWidth( imageRef );
double imgHeight = (double) CGImageGetHeight( imageRef );
NSRect dr = NSMakeRect( 0, 0, imgWidth, imgHeight );
CGContextDrawImage( myBitmapContext, dr, imageRef );
// This code pulls the downsampled image back in to save to the database
thumbnailImageRef = CGBitmapContextCreateImage( myBitmapContext );
bitmapData = CGBitmapContextGetData( myBitmapContext );
CGContextRelease( myBitmapContext );
if( bitmapData ) free( bitmapData );
NSDictionary *JPGopts = [NSDictionary dictionaryWithObjectsAndKeys: NSImageCompressionFactor, [NSNumber numberWithFloat: 0.0], nil];
NSBitmapImageRep *thumbnailBitmap = [[NSBitmapImageRep alloc] initWithCGImage: thumbnailImageRef];
NSData *thumbnailDataJPG = [thumbnailBitmap representationUsingType: NSJPEGFileType properties: JPGopts];
[thumbnailDataJPG writeToFile: @"/tmp/thumb.jpg" atomically: NO];
NSData *thumbnailDataPNG = [thumbnailBitmap representationUsingType: NSPNGFileType properties: nil];
[thumbnailDataPNG writeToFile: @"/tmp/thumb.png" atomically: NO];
NSData *thumbnailDataGIF = [thumbnailBitmap representationUsingType: NSGIFFileType properties: nil];
[thumbnailDataGIF writeToFile: @"/tmp/thumb.gif" atomically: NO];
NSData *thumbnailDataJPG2 = [thumbnailBitmap representationUsingType: NSJPEG2000FileType properties: nil];
[thumbnailDataJPG2 writeToFile: @"/tmp/thumb.jp2" atomically: NO];
[thumbnailBitmap release];
NSLog( @"The thumbnail sizes are %d for JPG, %d for PNG, %d for GIF, and %d for JPEG2000",
[thumbnailDataJPG length],
[thumbnailDataPNG length],
[thumbnailDataGIF length],
[thumbnailDataJPG2 length] );
// At this point I will store the selected NSData object to a BLOB in my database...
// I change the 1's to 0's and rebuild to try different formats
#if 1
CGImageSourceRef thumbSrc = CGImageSourceCreateWithData( (CFDataRef) thumbnailDataJPG2, NULL );
#elif 1
CGImageSourceRef thumbSrc = CGImageSourceCreateWithData( (CFDataRef) thumbnailDataGIF, NULL );
#elif 1
CGImageSourceRef thumbSrc = CGImageSourceCreateWithData( (CFDataRef) thumbnailDataPNG, NULL );
#else
CGImageSourceRef thumbSrc = CGImageSourceCreateWithData( (CFDataRef) thumbnailDataJPG, NULL );
#endif
thumbnailImageRef = CGImageSourceCreateImageAtIndex( thumbSrc, 0, NULL );
然后在我的drawRect
方法中我这样做:
CGContextRef myContext = [[NSGraphicsContext currentContext] graphicsPort];
if( thumbnailImageRef ) {
imgWidth = (double) CGImageGetWidth( thumbnailImageRef );
imgHeight = (double) CGImageGetHeight( thumbnailImageRef );
// Make 4-pixel red border around thumbnail
CGContextSetRGBFillColor( myContext, 1, 0, 0, 1);
CGContextFillRect( myContext, CGRectMake( 96, 96, imgWidth+8, imgHeight+8 ) );
// Draw the thumbnail image
CGContextDrawImage( myContext, NSMakeRect( 100, 100, imgWidth, imgHeight ), thumbnailImageRef );
}
当我在 Preview 中查看 thumb.* 文件时,它们看起来都很好(除了 JPG,因为它具有任何未填充区域的白色背景)。但是thumbnailImageRef
,如果我使用 JPEG-2000,则显示drawRect
的图像在图像之外有额外的黑色标记(在我放在它下面的红色矩形中)。它看起来非常适合 PNG 和 GIF,除了白色背景之外,对于 JPG 看起来还不错。但由于 JPEG-2000 是下一个最小对象大小的 1/4,我真的很想使用它。
我无法弄清楚小黑点是从哪里来的。有没有人有什么建议?
屏幕截图示例:要缩略图的图像(忽略红色方块)
上面使用 JPEG-2000 作为 thumbnailSrc 的缩略图(在红色方块中)
使用 JPEG 的顶部缩略图(在红色方块中)
使用 GIF 的顶部缩略图(在红色方块中)
我在这些之间切换的唯一更改是#if/#elif/#endif 部分中的'1' 和'0'。
出于大小原因,我想使用 JPEG-2000,但让它看起来像 GIF 图像一样。
谢谢!