2015-08-25 45 views
0

我從設備接收16位灰度圖像,圖像以未壓縮的原始格式傳送 ,這裏是一個8字節的例子,說明2X2圖像如何使用這種格式(MSB在前):Java RenderedImage實現自定義原始數據緩衝區

21 27   33 F6   28 F3   27 F2 
-----   -----   -----   ----- 
pixel 0,0(x,y) pixel 1,0  pixel 1,0  pixel 1,1 

我需要壓縮採用JPEG2000卡卡杜庫暴露一個Java ImageWriter實現的圖像,ImageWriter.write方法期待一個RenderedImage作爲輸入,我用下面的代碼創建一個BufferedImage來自原始圖像數據:

int[] rasterData = new int[width * height]; 
int rawBufferOffset = 0; 
for(int i=0;i<rasterData.length;i++) { 
    rasterData[i] = ((int) rawBuffer[rawBufferOffset + 1] << 8) | ((int) rawBuffer[rawBufferOffset] & 0xFF); 
    rawBufferOffset += 2; 
} 
BufferedImage image = new BufferedImage(width, height,BufferedImage.TYPE_USHORT_GRAY); 
image.getRaster().setPixels(0, 0, width, height, rasterData); 

該代碼的工作原理,但它顯然不是這種轉換的最佳方法, 我想創建一個使用rawBuffer作爲圖像柵格數據源的RenderedImage實現,任何人都可以建議如何做或建議任何其他方法這個轉換?

回答

0

最直接的方法,可能是使用ByteBuffer來交換字節順序,並創建一個新的short數組來保存像素數據。

然後將(short)像素數據包裝在DataBufferUShort中。創建一個匹配的WritableRasterColorModel,最後從中創建一個BufferedImage。該圖像應與上面代碼中的圖像(BufferedImage.TYPE_USHORT_GRAY)相同,但創建速度稍快,因爲您只需複製一次像素(而不是代碼中的兩次)。

int w = 2; 
int h = 2; 
int stride = 1; 

byte[] rawBytes = {0x21, 0x27, 0x33, (byte) 0xF6, 0x28, (byte) 0xF3, (byte) 0x27, (byte) 0xF2}; 
short[] rawShorts = new short[rawBytes.length/2]; 

ByteBuffer.wrap(rawBytes) 
     .order(ByteOrder.LITTLE_ENDIAN) 
     .asShortBuffer() 
     .get(rawShorts); 

DataBuffer dataBuffer = new DataBufferUShort(rawShorts, rawShorts.length); 
WritableRaster raster = Raster.createInterleavedRaster(dataBuffer, w, h, w * stride, stride, new int[]{0}, null); 
ColorModel colorModel = new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_GRAY), false, false, Transparency.OPAQUE, DataBuffer.TYPE_USHORT); 

BufferedImage image = new BufferedImage(colorModel, raster, colorModel.isAlphaPremultiplied(), null); 

另外,稍微令人費解,但可能更快的方式(如你不要複製的支持像素陣列的話),是創建一個自定義SampleModel與MSB(小端)字節數據的作品,但將它們公開爲TYPE_USHORT。這將創建一個TYPE_CUSTOM圖像。

int w = 2, h = 2, stride = 2; 
byte[] rawBytes = {0x21, 0x27, 0x33, (byte) 0xF6, 0x28, (byte) 0xF3, (byte) 0x27, (byte) 0xF2}; 
DataBuffer dataBuffer = new DataBufferByte(rawBytes, rawBytes.length); 

SampleModel sampleModel = new ComponentSampleModel(DataBuffer.TYPE_USHORT, w, h, stride, w * stride, new int[] {0}) { 
    @Override 
    public Object getDataElements(int x, int y, Object obj, DataBuffer data) { 
     if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) { 
      throw new ArrayIndexOutOfBoundsException("Coordinate out of bounds!"); 
     } 

     // Simplified, as we only support TYPE_USHORT 
     int numDataElems = getNumDataElements(); 
     int pixelOffset = y * scanlineStride + x * pixelStride; 

     short[] sdata; 

     if (obj == null) { 
      sdata = new short[numDataElems]; 
     } 
     else { 
      sdata = (short[]) obj; 
     } 

     for (int i = 0; i < numDataElems; i++) { 
      sdata[i] = (short) (data.getElem(bankIndices[i], pixelOffset + bandOffsets[i] + 1) << 8| 
        data.getElem(bankIndices[i], pixelOffset + bandOffsets[i])); 
     } 

     return sdata; 
    } 
}; 
ColorModel colorModel = new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_GRAY), false, false, Transparency.OPAQUE, DataBuffer.TYPE_USHORT); 
WritableRaster raster = Raster.createWritableRaster(sampleModel, dataBuffer, null); 

BufferedImage image = new BufferedImage(colorModel, raster, colorModel.isAlphaPremultiplied(), null); 

我真的沒有看到創建RenderedImage子類的一個原因。

+1

這真棒,非複製代碼減少了我的JVM內存消耗幾乎沒有,謝謝! – Black0ut