2013-11-28 44 views
2

我正在閱讀並顯示一個PNG文件。 我沒有問題處理8位深度的圖像。 我進行如下:如何在BufferedImage中設置RGB像素以顯示16位深度的PNG?

BufferedImage result = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); 

然後我讀的各像素的3×8 = 24位,將它們保存在字節data的陣列,並把它們在圖像中與:

for (int y = 0; y < height; y++) 
    for (int x = 0; x < width; x++) 
    result.setRGB(x, y, ((data[x * 3 + 0] & 0xff) << 16) 
         + ((data[x * 3 + 1] & 0xff) << 8) 
         + ((data[x * 3 + 2] & 0xff))); 

現在的問題是16位深度圖像。當然,data現在更大,它包含48位,分爲6個字節,用於每個RGB三元組:來自調試器data具有我期望的值。 如何設置RGB像素?我是否必須更改BufferedImage聲明?也許與:

BufferedImage result = new BufferedImage(width, height, BufferedImage.TYPE_USHORT_565_RGB); 

非常感謝提前!

P.S .:按照PNG標準,圖像的顏色類型爲2(無alpha的RGB)。


也許我將不得不使用http://docs.oracle.com/javase/7/docs/api/java/awt/image/ColorModel.html

回答

0

沒有辦法來創建使用BufferedImage.TYPE_...每個採樣16個比特(或每像素48位)的圖像(沒有這樣的常數)。 TYPE_USHORT_565_RGB創建一個每像素16位的圖像,分別採樣5(紅色),6(綠色)和5(藍色)位。我認爲這些USHORT RGB值是當某些計算器實際上有16位顯示器(又名「千色」)選項時的剩餘部分。

你需要做的,實際上每個樣品16位創建的圖像是什麼,就是:

ColorModel cm; 
WritableRaster raster; 

BufferedImage result = new BufferedImage(cm, raster, cm.isAlphaPremultiplied(), null); 

DataBufferUShort類型與任3家銀行數據緩衝區中創建柵格與3 BandedSampleModel或使用單個銀行和PixelInterleavedSampleModel,其中pixelStride的3,scanLineStride的3 * width和。 PS:在數據緩衝區暴露的情況下,您可以直接訪問short樣本來操作像素。這比使用BufferedImage.getRGB(...)/setRGB(...)快得多,並且將保持每個採樣精度的原始16位。 BufferedImage.getRGB(...)會將像素值轉換爲每個採樣32位像素/ 8位,從而失去了額外的精度。

+0

感謝答覆。我將學習這些課程並讓你知道。 –

+0

我在創建ColorModel和WritableRaster時遇到了問題。 我必須使用什麼樣的ColorModel? ComponentColorModel還是可以將它設置爲null? 我該如何創建WritableRaster? 如您所說,我使用了'PixelInterleavedSampleModel(DataBuffer.TYPE_USHORT,img.getWidth(),img.getHeight(),3,3 * img.getWidth(),bandOffset)''。 也許問題出在我傳遞給createWritableRaster方法的DataBufferUShort中。 –

1

@haraldK指出了正確的方向。我提供了一些來自「icafe」Java圖像庫的「PNGReader」的工作代碼。

if(bitsPerPixel == 16) { 
    if(interlace_method==NON_INTERLACED) 
     spixels = generate16BitRGBPixels(compr_data, false); 
    else { 
     spixels = generate16BitRGBInterlacedPixels(compr_data, false); 
       } 
    int[] off = {0, 1, 2}; //band offset, we have 3 bands 
    int numOfBands = 3; 
    boolean hasAlpha = false; 
    int trans = Transparency.OPAQUE; 
    int[] nBits = {16, 16, 16}; 
    if(alpha != null) { // Deal with single color transparency 
     off = new int[] {0, 1, 2, 3}; //band offset, we have 4 bands 
     numOfBands = 4; 
     hasAlpha = true; 
     trans = Transparency.TRANSLUCENT; 
     nBits = new int[] {16, 16, 16, 16};      
    } 
    db = new DataBufferUShort(spixels, spixels.length); 
    raster = Raster.createInterleavedRaster(db, width, height, width*numOfBands, numOfBands, off, null); 
    cm = new ComponentColorModel(colorSpace, nBits, hasAlpha, false, trans, DataBuffer.TYPE_USHORT); 
} 
return new BufferedImage(cm, raster, false, null); 

這裏是generate16BitRGBPixels()方法:

private short[] generate16BitRGBPixels(byte[] compr_data, boolean fullAlpha) throws Exception { 
    // 
    int bytesPerPixel = 0; 
    byte[] pixBytes; 

    if (fullAlpha) 
     bytesPerPixel = 8; 
    else 
     bytesPerPixel = 6; 

    bytesPerScanLine = width*bytesPerPixel;   

    // Now inflate the data. 
    pixBytes = new byte[height * bytesPerScanLine]; 

    // Wrap an InflaterInputStream with a bufferedInputStream to speed up reading 
    BufferedInputStream bis = new BufferedInputStream(new InflaterInputStream(new ByteArrayInputStream(compr_data))); 

    apply_defilter(bis, pixBytes, height, bytesPerPixel, bytesPerScanLine); 

    short[] spixels = null; 

    if(alpha != null) { // Deal with single color transparency 
     spixels = new short[width*height*4]; 
     short redMask = (short)((alpha[1]&0xff)|(alpha[0]&0xff)<<8); 
     short greenMask = (short)((alpha[3]&0xff)|(alpha[2]&0xff)<<8);; 
     short blueMask = (short)((alpha[5]&0xff)|(alpha[4]&0xff)<<8); 

     for(int i = 0, index = 0; i < pixBytes.length; index += 4) { 
      short red = (short)((pixBytes[i++]&0xff)<<8|(pixBytes[i++]&0xff)); 
      short green = (short)((pixBytes[i++]&0xff)<<8|(pixBytes[i++]&0xff)); 
      short blue = (short)((pixBytes[i++]&0xff)<<8|(pixBytes[i++]&0xff)); 
      spixels[index] = red; 
      spixels[index + 1] = green; 
      spixels[index + 2] = blue; 
      if(spixels[index] == redMask && spixels[index + 1] == greenMask && spixels[index + 2] == blueMask) { 
       spixels[index + 3] = (short)0x0000;        
      } else { 
       spixels[index + 3] = (short)0xffff; 
      } 
     } 
    } else 
     spixels = ArrayUtils.toShortArray(pixBytes, true); 

    return spixels;   
} 

和ArrayUtils.toShortArray()方法:

public static short[] toShortArray(byte[] data, int offset, int len, boolean bigEndian) { 

    ByteBuffer byteBuffer = ByteBuffer.wrap(data, offset, len); 

    if (bigEndian) { 
     byteBuffer.order(ByteOrder.BIG_ENDIAN); 
    } else { 
     byteBuffer.order(ByteOrder.LITTLE_ENDIAN); 
    } 

    ShortBuffer shortBuf = byteBuffer.asShortBuffer(); 
    short[] array = new short[shortBuf.remaining()]; 
    shortBuf.get(array); 

    return array; 
}