2011-06-23 22 views
-1

我正在構建一個Cocoa應用程序來幫助我組織數以萬計的數字圖片。它旨在保持一個非常精簡的信息數據庫,以便我可以找到我想要的圖像,然後我可以到存儲器中保存實際圖像(刻錄到DVD或CD)。我可以瀏覽圖片並設置評分,標籤等。然後我將這些數據存儲在我的硬盤上,數據庫本身的數量小於幾十張。在我的數據庫中,我想存儲一個縮略圖圖像(這會使其大約增加10倍)。我玩過幾種技術,並且使用JPEG-2000格式最小,但它看起來不能正確顯示?創建/使用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); 
} 

當我看着拇指*文件預覽看起來都很好(除JPG以外,因爲它有任何未填充區域的白色背景)。但是,如果我使用JPEG-2000,則在drawRect中顯示的thumbnailImageRef在圖像外部(在我放在它下面的紅色矩形中)之外有額外的黑色標記。它看起來非常適合PNG和GIF,除了白色背景之外,看起來還可以用於JPG。但是由於JPEG-2000是我真正想要使用的下一個最小對象的四分之一大小。

我無法弄清楚這個小黑點是從哪裏來的。有沒有人有什麼建議?

實施例的屏幕截圖: 圖像被顯示爲縮略圖(忽略紅色正方形)從 This is the image that the thumbnail will be created from...

縮圖上述使用JPEG-2000作爲thumbnailSrc(在紅色正方形) This has the thumbnail from the above in the red square...

縮圖從頂部使用JPEG(在紅色方塊中) enter image description here

從頂部使用GIF的縮略圖(在紅色方塊中) enter image description here

我在這兩者之間切換的唯一更改是#if /#elif /#endif部分中的'1和'0。

我想使用JPEG-2000的大小的原因,但它看起來像GIF圖像呢。

謝謝!

+0

請包含截圖/示例輸出圖像。 –

+0

添加到帖子的圖像。第一個是縮略圖的視圖(忽略紅色方塊),下一個顯示縮略圖在紅色方塊中。這些都是'thumbnailJPG2'作爲'thumbSrc'。下一個是JPEG,而下一個是GIF。 – LavaSlider

回答

0

您是否嘗試過直接使用CGImageDestination代替NSBitmapImageRep來創建縮略圖數據?

+0

我不知道'CGImageDestination',但繼續嘗試它。結果是完全相同的(在完全相同的地方有很少的黑色標記),所以相同,唯一的解釋是兩種技術都使用相同的代碼。 – LavaSlider

+0

好吧,我幾乎相信我自己,它是有問題的JPEG-2000創建過程。我試圖在Photoshop中打開一個JPEG-2000文件,它看起來是空的。所有其他人看起來很正常(預覽中他們都看起來很正常)。然後我在Photoshop中創建了一個類似的文件,並將其與CGImageSourceCreateWithURL一起使用,並且在我的代碼中看起來很正常......這讓我相信這是Apple的問題,而不是我的錯誤。 – LavaSlider

+0

@LavaSlider:我有同樣的意見。我建議提交一個bug:https://bugreport.apple.com/ –