2011-09-04 16 views
7

che sto caricando this (very small) image utilizzando:Come determinare ed interpretare il formato di pixel di un CGImage

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

L'immagine è 4x1 e contiene un pixel rosso, verde, blu e bianco da sinistra a destra, in quell'ordine

Avanti, ottengo i dati dei pixel dal CGImage sottostante:

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

Ora, per qualche ragione, i dati di pixel è disposto in modo diverso a seconda del dispositivo iOS.

Quando eseguo l'applicazione nel simulatore o sul mio iPhone 4, i dati dei pixel si presenta così:

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

Quindi, i pixel sono 3 byte per pixel, con blu come il byte più significativo e rosso come il meno significativo. Quindi immagino che chiami BGR?

Quando controllo CGBitmapInfo, posso vedere che kCGBitmapByteOrderMask è kCGBitmapByteOrderDefault. Non riesco a trovare da nessuna parte che spiega cosa sia "predefinito".

D'altra parte, quando l'eseguo sulla mia prima generazione iPhone, i dati dei pixel si presenta così:

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

Quindi 4 byte per canale, alfa come il byte più significativo e blu come il meno significativo. Quindi ... si chiama ARGB?

Ho cercato CGBitmapInfo per capire come rilevare il layout. Sul primo iPhone di gen, kCGBitmapAlphaInfoMask è kCGImageAlphaNoneSkipFirst. Ciò significa che i bit più significativi vengono ignorati. Quindi ha senso. Sul primo iPhone di gen il kCGBitmapByteOrderMask è kCGBitmapByteOrder32Little. Non so cosa significhi o come relazionarlo a come i componenti R, G e B sono disposti in memoria. Qualcuno può far luce su questo?

Grazie.

risposta

6

Per garantire l'indipendenza del dispositivo, potrebbe essere preferibile utilizzare un CGBitmapContext per popolare i dati.

Qualcosa del genere dovrebbe funzionare

// 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

Questo è contrassegnato come risposta accettata, ma in realtà non risponde alla domanda. Sembra anche un po 'come martellare un chiodo con una mazza. Perché ridisegnare un'intera immagine utilizzando tutto quel codice quando tutto ciò che si vuole veramente fare è ordinare l'ordine dei byte dei dati esistenti? –

+0

Victor, l'hai capito per caso, ovvero come gestire kCGBitmapByteOrderDefault? –

2

Sono sicuro che in 5 + anni di aver trovato una soluzione, ma questo è ancora una zona ombreggiata del core grafico, così ha voluto fare un salto miei due centesimi .

Diversi dispositivi e formati di file possono utilizzare ordini di byte diversi per vari motivi, principalmente perché possono e a causa delle prestazioni. Ci sono molte informazioni su questo, incluso RGBA color space representation su Wikipedia.

core grafico usa spesso kCGBitmapByteOrderDefault, che è piuttosto inutile, ma definisce anche host endian bitmap formats, che è possibile utilizzare per il riferimento:

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

Quando viene utilizzato con Swift, questo è anche inutile, perché quelli #define ' s non sono disponibili così com'è.Un modo per ovviare a questo è creare un'intestazione di bridging e un'implementazione equivalente e ridefinire quelle costanti.

// Bridge.h 

extern const int CGBitmapByteOrder16Host; 
extern const int CGBitmapByteOrder32Host; 

// Bridge.m 

#import "Bridge.h" 

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

Ora CGBitmapByteOrder16Host e CGBitmapByteOrder32Host costanti dovrebbero essere disponibili da Swift.

Problemi correlati