2010-03-03 72 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