Как определить и интерпретировать формат пикселей CGImage - PullRequest
7 голосов
/ 04 сентября 2011

Я загружаю это (очень маленькое) изображение , используя:

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,255,255), (0,255,0,255), (255,0,0,255), (255,255,255,255)

Таким образом, 4 байта на канал, альфа как наиболее значимый байт и синий как наименее значимый.Итак ... это называется ARGB?

Я искал в CGBitmapInfo подсказки о том, как определить макет.На iPhone первого поколения kCGBitmapAlphaInfoMask имеет вид kCGImageAlphaNoneSkipFirst.Это означает, что наиболее значимые биты игнорируются.Так что это имеет смысл.На iPhone первого поколения kCGBitmapByteOrderMask имеет вид kCGBitmapByteOrder32Little.Я не знаю, что это значит или как связать это с тем, как компоненты R, G и B расположены в памяти.Кто-нибудь может пролить свет на это?

Спасибо.

Ответы [ 2 ]

7 голосов
/ 04 сентября 2011

Чтобы обеспечить независимость устройства, может быть лучше использовать 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);
3 голосов
/ 04 сентября 2016

Я уверен, что за 5 с лишним лет вы нашли решение, но это все еще сомнительная область Core Graphics, поэтому я хотел бы уронить мои два цента.

Различные устройства и форматы файлов могут использовать разный порядок байтов по разным причинам, в основном потому, что они могут, и из-за производительности. Об этом много информации, в том числе представление цветового пространства RGBA в Википедии.

Базовая графика часто использует kCGBitmapByteOrderDefault, что довольно бесполезно, но она также определяет форматы растровых байтов endian , которые вы можете использовать для перекрестных ссылок:

#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;

Теперь константы CGBitmapByteOrder16Host и CGBitmapByteOrder32Host должны быть доступны в Swift.

...