2011-09-04 20 views
7

我使用加載this (very small) image如何判斷和解釋CGImage的像素格式

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組件在內存中的佈局聯繫起來。任何人都可以對此有所瞭解嗎?

謝謝。

回答

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

這被標記爲接受的答案,但它並沒有真正回答這個問題。這似乎有點像用錘子錘擊釘子。當所有人真正想要做的事情是爲了整理現有數據的字節順序時,爲什麼使用所有代碼重繪整個圖像? –

+0

維克多,你有沒有想過這一點,即如何處理kCGBitmapByteOrderDefault? –

2

我敢肯定,在5年以上,你已經找到了解決辦法,但是這仍然是核芯顯卡的暗區,所以想在我的兩分錢下降。

由於各種原因,不同的設備和文件格式可能會使用不同的字節順序,主要是因爲它們可以並且因爲性能。有很多這方面的信息,包括維基百科上的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 

當斯威夫特使用,這也沒用,因爲那些#define「 s是不可用的。解決這個問題的一種方法是創建一個橋接頭和等效實現,並重新定義這些常量。現在

// Bridge.h 

extern const int CGBitmapByteOrder16Host; 
extern const int CGBitmapByteOrder32Host; 

// Bridge.m 

#import "Bridge.h" 

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

CGBitmapByteOrder16HostCGBitmapByteOrder32Host常數應該可以從斯威夫特。

相關問題