2011-09-04 29 views
7

Tôi tải this (very small) image sử dụng:Làm thế nào để xác định và giải thích các định dạng pixel của một CGImage

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

Hình ảnh là 4x1 và nó chứa một pixel màu đỏ, xanh lá cây, xanh dương và trắng từ trái sang phải, trong thứ tự đó.

Tiếp theo, tôi nhận được dữ liệu pixel ra khỏi CGImage cơ bản:

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

Bây giờ, đối với một số lý do, dữ liệu pixel được đặt ra khác nhau tùy thuộc vào các thiết bị iOS.

Khi tôi chạy ứng dụng trong mô phỏng hoặc trên iPhone của tôi 4, dữ liệu pixel trông như thế này:

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

Vì vậy, pixel là 3 byte cho mỗi pixel, với màu xanh lam là byte quan trọng nhất và màu đỏ là ít quan trọng nhất. Vì vậy, tôi đoán bạn gọi đó là BGR?

Khi tôi kiểm tra CGBitmapInfo, tôi có thể thấy rằng kCGBitmapByteOrderMask là kCGBitmapByteOrderDefault. Tôi không thể tìm thấy bất cứ nơi nào mà giải thích những gì "mặc định" là.

Mặt khác, khi tôi chạy nó trên iPhone thế hệ đầu tiên của tôi, dữ liệu pixel trông như thế này:

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

Vì vậy, 4 byte cho mỗi kênh, alpha là byte quan trọng nhất và màu lam là ít quan trọng nhất. Vậy ... được gọi là ARGB?

Tôi đã xem xét CGBitmapInfo để tìm manh mối về cách phát hiện bố cục. Trên iPhone gen đầu tiên, kCGBitmapAlphaInfoMask là kCGImageAlphaNoneSkipFirst. Điều đó có nghĩa rằng các bit quan trọng nhất được bỏ qua. Điều đó có ý nghĩa. Trên iPhone gen đầu tiên, kCGBitmapByteOrderMask là kCGBitmapByteOrder32Little. Tôi không biết điều đó có nghĩa là gì hoặc làm thế nào để liên kết nó trở lại như thế nào các thành phần R, G và B được đặt ra trong bộ nhớ. Bất cứ ai có thể làm sáng tỏ về điều này?

Cảm ơn.

Trả lời

6

Để đảm bảo tính độc lập của thiết bị, tốt hơn bạn nên sử dụng số CGBitmapContext để điền dữ liệu cho bạn.

Something như thế này nên làm việc

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

Điều này được đánh dấu là câu trả lời được chấp nhận nhưng không thực sự trả lời câu hỏi. Nó cũng có vẻ hơi giống búa trong một cái đinh bằng búa tạ. Tại sao vẽ lại toàn bộ hình ảnh bằng cách sử dụng tất cả mã đó khi tất cả mọi người thực sự muốn làm là sắp xếp thứ tự byte của dữ liệu hiện có? –

+0

Victor, bạn đã tìm ra điều này bằng bất kỳ cơ hội nào, cụ thể là làm thế nào để đối phó với kCGBitmapByteOrderDefault? –

2

tôi chắc chắn rằng trong 5 năm bạn đã tìm thấy một giải pháp, nhưng đây vẫn là một khu vực râm Core Graphics, vì vậy muốn thả trong hai xu của tôi .

Thiết bị và định dạng tệp khác nhau có thể sử dụng thứ tự byte khác nhau vì nhiều lý do khác nhau, chủ yếu là vì chúng có thể và do hiệu suất. Có rất nhiều thông tin xung quanh về điều này, bao gồm RGBA color space representation trên Wikipedia.

Lõi đồ họa thường sử dụng kCGBitmapByteOrderDefault, mà là khá vô dụng, nhưng nó cũng định nghĩa host endian bitmap formats, mà bạn có thể sử dụng để tham khảo chéo:

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

Khi sử dụng với Swift, điều này cũng là vô ích, bởi vì những #define ' s không có sẵn như là.Một cách để giải quyết vấn đề này là tạo một tiêu đề bắc cầu và thực hiện tương đương và xác định lại các hằng số đó.

// Bridge.h 

extern const int CGBitmapByteOrder16Host; 
extern const int CGBitmapByteOrder32Host; 

// Bridge.m 

#import "Bridge.h" 

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

Hiện tại, CGBitmapByteOrder16HostCGBitmapByteOrder32Host hằng số sẽ có sẵn từ Swift.

Các vấn đề liên quan