2010-03-03 49 views
6

我有一個32位NSBitmapImageRep它有一個基本上1位值的alpha通道(像素是開或關)。如何使用NSBitmapImageRep創建透明度爲8位的PNG?

我想將此位圖保存爲具有透明度的8位PNG文件。如果我使用-representationUsingType:properties:方法NSBitmapImageRep並通過NSPNGFileType,則會創建一個32位PNG,這不是我想要的。

我知道可以讀取8位PNG,它們可以在Preview中打開而不會出現問題,但是可以使用任何內置的Mac OS X API編寫這種類型的PNG文件嗎?如果需要,我很高興能夠下載到Core Image甚至QuickTime。對CGImage文檔的粗略檢查沒有發現任何明顯的問題。

編輯: 我已經開始在這個問題上的賞金,如果有人能提供工作的源代碼,需要一個32位NSBitmapImageRep和1位透明度寫入256色PNG,這是你的。

+0

8位256色?我希望圖像中不超過256種顏色。如果您的顏色可能超過256種,您可能需要使用pngnq(將其捆綁到您的應用中並使用NSTask運行):http://pngnq.sourceforge.net/ – 2010-03-03 04:31:50

+0

是,256種顏色。我正在尋找類似輸出的東西,使用'-representationUsingType:properties'和'NSGIFFileType',除了輸出一個8位的PNG。 pngnq是一個選項(謝謝),但我希望能夠在不產生任何任務的情況下處理它。 – 2010-03-03 09:43:16

回答

1

pngnq(和new pngquant實現更高質量)具有BSD樣式的許可證,因此您可以將其包含在您的r程序。不需要產生作爲單獨的任務。

+0

這確實有效,並修復了我的問題問題,謝謝。 – 2010-03-15 01:32:48

0

有一件事要嘗試創建一個8位的NSBitmapImageRep,然後將數據複製到它。

這實際上是很多工作,因爲你必須自己計算顏色索引表。

+0

正確。 Peter Hosey使用** pngnq **的建議很好地解決了這個調色板創建問題,儘管需要產生一個任務。 – 2010-03-03 23:53:49

2

pnglib怎麼樣?它非常輕巧,易於使用。

+0

這絕對是一種選擇,但是由於在涉及很多學習之前我沒有與'pnglib'一起工作,所以我真的希望有更高層次的東西。 – 2010-03-08 01:37:09

+0

@Rob,對於pnglib沒有太多的學習,就C庫而言,它確實非常簡單。你可能會被別的東西卡住,大多數更高級別的API假設更一般的情況,這通常意味着24或32 bpp圖像。 – 2010-03-08 06:47:23

0

CGImageDestination是你的低級圖像寫作的人,但我不知道它是否支持該特定能力。

+0

是的,它看起來應該是答案,但到目前爲止,我一直無法找到一種方法來指定要創建的PNG類型,我嘗試寫入的所有內容都寫入一個32位PNG。 – 2010-03-03 23:52:29

1

一種較低級別的API的工作很好的參考是Programming With Quartz

下面的一些代碼是基於這本書的例子。

注:這是未經測試的代碼的意思是隻有起點....

- (NSBitmapImageRep*)convertImageRep:(NSBitmapImageRep*)startingImage{ 

    CGImageRef anImage = [startingImage CGImage]; 

    CGContextRef bitmapContext; 
    CGRect ctxRect; 
    size_t bytesPerRow, width, height; 

    width = CGImageGetWidth(anImage); 
    height = CGImageGetHeight(anImage); 
    ctxRect = CGRectMake(0.0, 0.0, width, height); 
    bytesPerRow = (width * 4 + 63) & ~63; 
    bitmapData = calloc(bytesPerRow * height, 1); 
    bitmapContext = createRGBBitmapContext(width, height, TRUE); 
    CGContextDrawImage (bitmapContext, ctxRect, anImage); 

    //Now extract the image from the context 
    CGImageRef  bitmapImage = nil; 
    bitmapImage = CGBitmapContextCreateImage(bitmapContext); 
    if(!bitmapImage){ 
     fprintf(stderr, "Couldn't create the image!\n"); 
     return nil; 
    } 

    NSBitmapImageRep *newImage = [[NSBitmapImageRep alloc] initWithCGImage:bitmapImage]; 
    return newImage; 
} 

語境創建功能:

CGContextRef createRGBBitmapContext(size_t width, size_t height, Boolean needsTransparentBitmap) 
{ 
    CGContextRef context; 
    size_t bytesPerRow; 
    unsigned char *rasterData; 

    //minimum bytes per row is 4 bytes per sample * number of samples 
    bytesPerRow = width*4; 
    //round up to nearest multiple of 16. 
    bytesPerRow = COMPUTE_BEST_BYTES_PER_ROW(bytesPerRow); 

    int bitsPerComponent = 2; // to get 256 colors (2xRGBA) 

    //use function 'calloc' so memory is initialized to 0. 
    rasterData = calloc(1, bytesPerRow * height); 
    if(rasterData == NULL){ 
     fprintf(stderr, "Couldn't allocate the needed amount of memory!\n"); 
     return NULL; 
    } 

    // uses the generic calibrated RGB color space. 
    context = CGBitmapContextCreate(rasterData, width, height, bitsPerComponent, bytesPerRow, 
            CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB), 
            (needsTransparentBitmap ? kCGImageAlphaPremultipliedFirst : 
            kCGImageAlphaNoneSkipFirst) 
            ); 
    if(context == NULL){ 
     free(rasterData); 
     fprintf(stderr, "Couldn't create the context!\n"); 
     return NULL; 
    } 

    //Either clear the rect or paint with opaque white, 
    if(needsTransparentBitmap){ 
     CGContextClearRect(context, CGRectMake(0, 0, width, height)); 
    }else{ 
     CGContextSaveGState(context); 
     CGContextSetFillColorWithColor(context, getRGBOpaqueWhiteColor()); 
     CGContextFillRect(context, CGRectMake(0, 0, width, height)); 
     CGContextRestoreGState(context); 
    } 
    return context; 
} 

用法是:

NSBitmapImageRep *startingImage; // assumed to be previously set. 
NSBitmapImageRep *endingImageRep = [self convertImageRep:startingImage]; 
// Write out as data 
NSData *outputData = [endingImageRep representationUsingType:NSPNGFileType properties:nil]; 
// somePath is set elsewhere 
[outputData writeToFile:somePath atomically:YES]; 
+0

謝謝,這將很好地創建位圖,但它實際上並沒有解決寫入256色8位PNG文件的問題。 – 2010-03-03 23:51:21

+0

對不起,我離開了這一步。我將編輯我的答案,以包含所需的兩個電話。 – 2010-03-04 16:55:32

+0

我研究過這個,根據Quartz 2D Programming Guide中的「支持的像素格式」,不可能創建一個8位的RGB上下文,所以這段代碼無法工作。如果您嘗試運行它,則由於「無效的參數組合」而無法創建上下文。 http://developer.apple.com/mac/library/DOCUMENTATION/GraphicsImaging/Conceptual/drawingwithquartz2d/dq_context/dq_context.html#//apple_ref/doc/uid/TP30001066-CH203-BCIBHHBB – 2010-03-08 01:35:04