1

我想读取一个 PNG 文件,以便我可以:

a) 访问文件的原始位图数据,无需色彩空间调整或 Alpha 预乘。

b) 基于该位图,在窗口中的图像中显示位切片(整个图像中 R、G、B 或 A 的任何单个位)。如果我有位图,我可以找到正确的位,但我可以把它们塞进什么东西让它们出现在屏幕上?

c) 对位平面进行一些修改后,编写一个新的 PNG 文件,再次不做任何调整。

这仅适用于某些特定图像。除了简单的 RGBA-32 之外,预计 PNG 不会有任何数据。

通过在这里阅读一些类似的问题,我怀疑 NSBitmapImageRep 用于文件读/写,并在 NSView 中绘制屏幕部分。这听起来对吗?

4

2 回答 2

1

1.) 您可以使用 NSBitmapImageRep 的 -bitmapData 来获取原始像素数据。不幸的是,CG(NSBitmapImageRep 的后端)不支持本机解预乘,因此您必须自己解预乘。此处使用的色彩空间与文件中的色彩空间相同。以下是如何取消预乘图像数据:

NSBitmapImageRep *imageRep = [NSBitmapImageRep imageRepWithData:data];
    NSInteger width = [imageRep pixelsWide];
    NSInteger height = [imageRep pixelsHigh];

    unsigned char *bytes = [imageRep bitmapData];
    for (NSUInteger y = 0; y < width * height * 4; y += 4) { // bgra little endian + alpha first
        uint8_t a, r, g, b;

        if (imageRep.bitmapFormat & NSAlphaFirstBitmapFormat) {
            a = bytes[y];
            r = bytes[y+1];
            g = bytes[y+2];
            b = bytes[y+3];
        } else {
            r = bytes[y+0];
            g = bytes[y+1];
            b = bytes[y+2];
            a = bytes[y+3];
        }

        // unpremultiply alpha if there is any
        if (a > 0) {
            if (!(imageRep.bitmapFormat & NSAlphaNonpremultipliedBitmapFormat)) {
                float factor = 255.0f/a;
                b *= factor;
                g *= factor;
                r *= factor;
            }
        } else {
            b = 0;
            g = 0;
            r = 0;
        }
        bytes[y]=a; // for argb
        bytes[y+1]=r;
        bytes[y+2]=g;
        bytes[y+3]=b;
    }

2.) 我想不出一个简单的方法来做到这一点。您可以制作自己的图像绘制方法,循环遍历原始图像数据并根据这些值生成新图像。请参阅上文以了解如何开始执行此操作。

3.) 这是一种从原始数据位置获取 CGImage 的方法(如果 CG 让您不舒服,您可以使用原生 CG 函数将 png 写入文件或将其转换为 NSBitmapImageRep)

static CGImageRef cgImageFrom(NSData *data, uint16_t width, uint16_t height) {
CGDataProviderRef provider = CGDataProviderCreateWithCFData((CFDataRef)data);
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGBitmapInfo bitmapInfo = kCGImageAlphaFirst;

CGImageRef cgImage = CGImageCreate(width, height, 8, 32, 4 * width, colorSpace, bitmapInfo, provider, NULL, NO, kCGRenderingIntentDefault);
CGDataProviderRelease(provider);
CGColorSpaceRelease(colorSpace);
return cgImage;
}

您可以使用+dataWithBytes:length从原始数据对象中创建 NSData 对象:

于 2011-11-04T20:56:00.913 回答
0

我从来没有在这个领域工作过,但你可以使用Image IO 来做这件事。

于 2011-11-05T02:01:20.373 回答