2011-09-04 8 views
7

Estoy cargando this (very small) image usando:Cómo determinar e interpretar el formato de píxel de un CGImage

UIImage* image = [UIImage named:@"someFile.png"]; 

La imagen es de 4x1 y contiene un píxel rojo, verde, azul y blanco de izquierda a derecha, en ese orden

A continuación, obtener los datos de los píxeles de la CGImage subyacente:

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

Ahora, por alguna razón, los datos de píxeles se presenta de manera diferente dependiendo del dispositivo iOS.

Cuando ejecuto la aplicación en el simulador o en mi iPhone 4, los datos de píxeles se ve así:

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

Por lo tanto, los píxeles son 3 bytes por píxel, con el azul como el byte más significativo y el rojo como el menos significativo. ¿Entonces supongo que llamas BGR?

Cuando verifico CGBitmapInfo, puedo ver que kCGBitmapByteOrderMask es kCGBitmapByteOrderDefault. No puedo encontrar ningún lugar que explique qué es "predeterminado".

Por otro lado, cuando lo ejecuto en mi primera generación de iPhone, los datos de píxeles se parece a esto:

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

Así que 4 bytes por canal, alfa como el byte más significativo y azul como el menos significativo. Entonces ... ¿eso se llama ARGB?

He estado mirando CGBitmapInfo en busca de pistas sobre cómo detectar el diseño. En el iPhone de primera generación, el kCGBitmapAlphaInfoMask es kCGImageAlphaNoneSkipFirst. Eso significa que los bits más significativos son ignorados. Entonces eso tiene sentido. En el iPhone de primera generación, el kCGBitmapByteOrderMask es kCGBitmapByteOrder32Little. No sé lo que eso significa ni cómo relacionarlo con la forma en que los componentes R, G y B se presentan en la memoria. ¿Alguien puede arrojar algo de luz sobre esto?

Gracias.

Respuesta

6

Para garantizar la independencia del dispositivo, puede ser mejor utilizar un CGBitmapContext para llenar los datos por usted.

Algo como esto debería funcionar

// 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); 
+11

Esto está marcado como la respuesta aceptada, pero en realidad no responde la pregunta. También parece un poco como martillar un clavo con un martillo. ¿Por qué volver a dibujar una imagen completa usando todo ese código cuando todo lo que uno realmente quiere hacer es ordenar el orden de bytes de los datos existentes? –

+0

Victor, ¿lo ha averiguado por casualidad, es decir, cómo lidiar con kCGBitmapByteOrderDefault? –

2

Estoy seguro que en más de 5 años que ha encontrado una solución, pero esto sigue siendo una zona de sombra del núcleo de gráficos, por lo que quería dejar en mis dos centavos .

Los diferentes dispositivos y formatos de archivo pueden usar diferentes bytes de orden por varias razones, principalmente porque pueden y debido al rendimiento. Hay mucha información al respecto, incluyendo RGBA color space representation en Wikipedia.

núcleo de gráficos a menudo utiliza kCGBitmapByteOrderDefault, que es bastante inútil, sino que también define host endian bitmap formats, que se puede utilizar como referencia cruzada:

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

Cuando se utiliza con Swift, esto también es inútil, porque los #define ' s no están disponibles como están.Una forma de evitar esto es crear un encabezado puente y una implementación equivalente y redefinir esas constantes.

// Bridge.h 

extern const int CGBitmapByteOrder16Host; 
extern const int CGBitmapByteOrder32Host; 

// Bridge.m 

#import "Bridge.h" 

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

Ahora CGBitmapByteOrder16Host y CGBitmapByteOrder32Host constantes deben estar disponibles en Swift.

Cuestiones relacionadas