如何确定和解释CGImage的像素格式

时间:2011-09-04 16:33:31

标签: iphone ios quartz-graphics pixels cgimage

我正在使用

加载this (very small) image
UIImage* image = [UIImage named:@"someFile.png"];

图像为4x1,从左到右依次包含红色,绿色,蓝色和白色像素。

接下来,我从基础CGImage中获取像素数据:

NSData* data = (NSData*)CGDataProviderCopyData(CGImageGetDataProvider(image.CGImage));

现在,由于某些原因,像素数据的布局会有所不同,具体取决于iOS设备。

当我在模拟器或iPhone 4上运行应用程序时,像素数据如下所示:

(255,0,0),(0,255,0),(0,0,255),(255,255,255)

因此,像素为每像素3个字节,蓝色为最高有效字节,红色为最低有效字节。所以我猜你叫那个BGR?

当我检查CGBitmapInfo时,我可以看到kCGBitmapByteOrderMask是kCGBitmapByteOrderDefault。我无法找到解释“默认”的地方。

另一方面,当我在第一代iPhone上运行时,像素数据如下所示:

(0,0,255,255),(0,255,0,255),(255,0,0,255),(255255255255)

每个通道4个字节,alpha作为最重要的字节,蓝色作为最不重要的字节。所以...那叫做ARGB?

我一直在查看CGBitmapInfo,了解如何检测布局的线索。在第一代iPhone上,kCGBitmapAlphaInfoMask是kCGImageAlphaNoneSkipFirst。这意味着忽略了最重要的位。这是有道理的。在第一代iPhone上,kCGBitmapByteOrderMask是kCGBitmapByteOrder32Little。我不知道这意味着什么或如何将它与R,G和B组件如何在内存中布局相关联。任何人都可以对此有所了解吗?

感谢。

2 个答案:

答案 0 :(得分:6)

为确保设备独立性,最好使用CGBitmapContext为您填充数据。

这样的事情应该有效

// Get the CGImageRef
CGImageRef imageRef = [theImage CGImage];

// Find width and height
NSUInteger width = CGImageGetWidth(imageRef);
NSUInteger height = CGImageGetHeight(imageRef);

// Setup color space
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();

// Alloc data that the image data will be put into
unsigned char *rawData = malloc(height * width * 4);

// Create a CGBitmapContext to draw an image into
NSUInteger bytesPerPixel = 4;
NSUInteger bytesPerRow = bytesPerPixel * width;
NSUInteger bitsPerComponent = 8;
CGContextRef context = CGBitmapContextCreate(rawData, width, height,
                                             bitsPerComponent, bytesPerRow, colorSpace,
                                             kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big);
CGColorSpaceRelease(colorSpace);

// Draw the image which will populate rawData
CGContextDrawImage(context, CGRectMake(0, 0, width, height), imageRef);
CGContextRelease(context);


for (NSUInteger y = 0; y < height; y++) {
    for (NSUInteger x = 0; x < width; x++) {        
        int byteIndex = (bytesPerRow * y) + x * bytesPerPixel;

        CGFloat red = rawData[byteIndex];
        CGFloat green = rawData[byteIndex + 1];
        CGFloat blue = rawData[byteIndex + 2];
        CGFloat alpha = rawData[byteIndex + 3];
    }
}

free(rawData);

答案 1 :(得分:3)

我确信在5年多的时间里你找到了一个解决方案,但这仍然是Core Graphics的一个阴暗区域,所以想要降低我的两分钱。

由于各种原因,不同的设备和文件格式可能会使用不同的字节顺序,主要是因为它们可以并且由于性能原因。这方面有很多信息,包括维基百科上的RGBA color space representation

核心图形通常使用kCGBitmapByteOrderDefault,这是相当无用的,但它也定义了host endian bitmap formats,您可以将其用于交叉引用:

#ifdef __BIG_ENDIAN__
#define kCGBitmapByteOrder16Host kCGBitmapByteOrder16Big
#define kCGBitmapByteOrder32Host kCGBitmapByteOrder32Big
#else
#define kCGBitmapByteOrder16Host kCGBitmapByteOrder16Little
#define kCGBitmapByteOrder32Host kCGBitmapByteOrder32Little
#endif

当与Swift一起使用时,这也没用,因为那些#define不可用。解决此问题的一种方法是创建桥接头和等效实现,并重新定义这些常量。

// Bridge.h

extern const int CGBitmapByteOrder16Host;
extern const int CGBitmapByteOrder32Host;

// Bridge.m

#import "Bridge.h"

const int CGBitmapByteOrder16Host = kCGBitmapByteOrder16Host;
const int CGBitmapByteOrder32Host = kCGBitmapByteOrder32Host;

现在可以从Swift获得CGBitmapByteOrder16HostCGBitmapByteOrder32Host个常量。