【问题标题】:How to determine and interpret the pixel format of a CGImage如何确定和解释 CGImage 的像素格式
【发布时间】:2011-11-10 03:57:02
【问题描述】:

我正在加载 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),(255,255,255,255)

所以每个通道有 4 个字节,alpha 是最重要的字节,蓝色是最不重要的。所以……这叫 ARGB?

我一直在查看 CGBitmapInfo 以获取有关如何检测布局的线索。在第一代 iPhone 上,kCGBitmapAlphaInfoMask 是 kCGImageAlphaNoneSkipFirst。这意味着最高有效位被忽略。所以这是有道理的。在第一代 iPhone 上,kCGBitmapByteOrderMask 是 kCGBitmapByteOrder32Little。我不知道这意味着什么,也不知道如何将其与 R、G 和 B 组件在内存中的布局方式联系起来。任何人都可以对此有所了解吗?

谢谢。

【问题讨论】:

  • 我正在寻找关于内存顺序的类似答案。 kCIFormatRGBAh 是否意味着在内存顺序中首先出现红色,最后出现 alpha 通道 {red float16, green float16, blue float16, alpha float16}。如果是这样,那么kCIFormatBGRA8 只能表示相同的意思,即蓝色出现在内存的第一个字节中。那么回应“那叫ARGB?”,不就是BGRA吗?

标签: iphone ios quartz-graphics pixels cgimage


【解决方案1】:

为确保设备独立性,最好使用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);

【讨论】:

  • 这被标记为接受的答案,但它实际上并没有回答问题。这似乎也有点像用大锤敲钉子。当人们真正想做的只是整理现有数据的字节顺序时,为什么要使用所有这些代码重绘整个图像?
  • Victor,你有没有想过这个问题,即如何处理kCGBitmapByteOrderDefault?
【解决方案2】:

我敢肯定,在 5 年多的时间里,您已经找到了解决方案,但这仍然是 Core Graphics 的一个阴暗区域,所以想花我的两分钱。

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

Core Graphics 经常使用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;

现在CGBitmapByteOrder16HostCGBitmapByteOrder32Host 常量应该可以从 Swift 获得了。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-08-24
    • 1970-01-01
    相关资源
    最近更新 更多