7

我有一个 32 位NSBitmapImageRep,它有一个 alpha 通道,基本上是 1 位值(像素是打开还是关闭)。

我想将此位图保存为具有透明度的 8 位 PNG 文件。如果我使用 and 的-representationUsingType:properties:方法NSBitmapImageRep传入NSPNGFileType,会创建一个 32 位的 PNG,这不是我想要的。

我知道可以读取 8 位 PNG,它们在预览中打开没有问题,但是是否可以使用任何内置的 Mac OS X API 编写这种类型的 PNG 文件?如有必要,我很乐意使用 Core Image 甚至 QuickTime。对文档的粗略检查CGImage并没有发现任何明显的东西。

编辑: 我已经开始对这个问题进行赏金,如果有人可以提供工作源代码,它采用 32 位NSBitmapImageRep并编写具有 1 位透明度的 256 色 PNG,它就是你的。

4

5 回答 5

2

怎么样pnglib?它非常轻巧且易于使用。

于 2010-03-03T04:17:14.423 回答
1

pngnq(以及实现更高质量的新 pngquant)具有 BSD 风格的许可证,因此您可以将其包含在您的程序中。无需作为单独的任务生成。

于 2010-03-10T12:49:59.250 回答
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];
于 2010-03-03T15:12:35.150 回答
0

要尝试的一件事是创建一个 8 位的 NSBitmapImageRep,然后将数据复制到它。

这实际上需要做很多工作,因为您必须自己计算颜色索引表。

于 2010-03-03T04:16:36.243 回答
0

CGImageDestination是你写低级图像的人,但我不知道它是否支持那个特定的能力。

于 2010-03-03T10:18:38.107 回答