2011-11-04 94 views
1

我想讀一個PNG文件,這樣我可以:操作原始PNG數據

一)訪問該文件的原始位圖數據,與沒有色彩空間調整或Alpha預乘。 b)基於該位圖,在窗口的圖像中顯示位片(在整個圖像上顯示R,G,B或A的任何單個)。如果我有位圖,我可以找到合適的位,但是我可以將它們填入屏幕以便讓它們顯示出來嗎?

c)在對位平面進行了一些修改之後,再次寫入一個新的PNG文件,不做任何調整。

這僅適用於某些特定圖像。除了簡單的RGBA-32之外,PNG預計不會有任何數據。

從閱讀這裏的一些類似的問題,我懷疑NSBitmapImageRep的文件讀/寫,並在屏​​幕上的一部分NSView中繪圖。這聽起來正確嗎?

回答

1

1.)您可以使用NSBitmapImageRep的-bitmapData來獲取原始像素數據。不幸的是,CG(NSBitmapImageRep的後端)不支持本地預失真,所以你必須自己無法預測。這裏使用的顏色空間與文件中的顏色空間相同。這裏是如何預處理圖像數據:

NSBitmapImageRep *imageRep = [NSBitmapImageRep imageRepWithData:data]; 
    NSInteger width = [imageRep pixelsWide]; 
    NSInteger height = [imageRep pixelsHigh]; 

    unsigned char *bytes = [imageRep bitmapData]; 
    for (NSUInteger y = 0; y < width * height * 4; y += 4) { // bgra little endian + alpha first 
     uint8_t a, r, g, b; 

     if (imageRep.bitmapFormat & NSAlphaFirstBitmapFormat) { 
      a = bytes[y]; 
      r = bytes[y+1]; 
      g = bytes[y+2]; 
      b = bytes[y+3]; 
     } else { 
      r = bytes[y+0]; 
      g = bytes[y+1]; 
      b = bytes[y+2]; 
      a = bytes[y+3]; 
     } 

     // unpremultiply alpha if there is any 
     if (a > 0) { 
      if (!(imageRep.bitmapFormat & NSAlphaNonpremultipliedBitmapFormat)) { 
       float factor = 255.0f/a; 
       b *= factor; 
       g *= factor; 
       r *= factor; 
      } 
     } else { 
      b = 0; 
      g = 0; 
      r = 0; 
     } 
     bytes[y]=a; // for argb 
     bytes[y+1]=r; 
     bytes[y+2]=g; 
     bytes[y+3]=b; 
    } 

2.)我想不出一個簡單的方法來做到這一點。您可以製作自己的圖像繪製方法,循環顯示原始圖像數據並根據這些值生成新圖像。請參閱上文,瞭解如何開始做。

3)這裏是獲取原始數據的地方一個CGImage的方法(可以使用本機CG功能寫PNG文件或將其轉換爲NSBitmapImageRep如果CG讓你不舒服)

static CGImageRef cgImageFrom(NSData *data, uint16_t width, uint16_t height) { 
CGDataProviderRef provider = CGDataProviderCreateWithCFData((CFDataRef)data); 
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); 
CGBitmapInfo bitmapInfo = kCGImageAlphaFirst; 

CGImageRef cgImage = CGImageCreate(width, height, 8, 32, 4 * width, colorSpace, bitmapInfo, provider, NULL, NO, kCGRenderingIntentDefault); 
CGDataProviderRelease(provider); 
CGColorSpaceRelease(colorSpace); 
return cgImage; 
} 

您可以使用+dataWithBytes:length:

+1

Ouch。刪除預乘會導致嚴重的舍入誤差,特別是在alpha很小的情況下。這將毀掉訪問位圖的點。我需要同時加載和保存文件中的**精確**位圖值,這些值不是預乘。 CGImageCreateWithPNGDataProvider好像會支持這一點,因爲CGImage有一個訪問器來判斷它是否是預乘。 CGImageDestinationCreateWithURL聽起來像它會寫PNG。 –

+0

是的,如果數據已經在原始圖像中沒有預乘,那麼CGImage/NSBitmapImageRep就會這樣對待它。圖像被繪製到上下文中,然後初始化爲內存中的新圖像,因爲它不受支持,所以不會無法預知。另外,在預失真時,損失是不可避免的。 –

+0

事情是,**原始**數據在PNG文件中,不是**預乘。這是我想要加載,修改和保存的數據。但是,如果我正在閱讀引用,NSBitmapImageRep(我可以看到如何訪問位圖的唯一類)將在用文件中的數據進行初始化時預乘。如果我在Cocoa找不到簡單的方法來獲取這些數據,我認爲Python的PyPNG模塊是我的最佳選擇。 –

0

從原始數據對象中創建NSData對象我還沒有在此區域工作過,但您可能可以使用Image IO來做到這一點。

+0

圖像IO處理在文件和CGImageRef之間傳輸圖像,顯然沒有預乘,所以會覆蓋#1和#3。我可以將CGImage提供給各種過濾器,或將其發送到屏幕,但看不到訪問位圖數據的方式。 :( –