2017-03-24 54 views
0

我正在使用com.sun.media.imageioimpl.plugins.tiff.TIFFPackBitsCompressor嘗試編碼我使用PackBits的tiff字節數組。我對這個班不熟悉,並沒有找到很多關於如何使用它的例子。但是,在遵循javadoc時,每次嘗試對數據進行編碼時都會收到NPE。就我所知,我的值都不爲空。我試着這些測試多個值,在這一點上,但下面是我最近的迭代:TIFFPackBitsCompressor - NPE?

   TIFFPackBitsCompressor pack = new TIFFPackBitsCompressor(); 
       //bImageFromConvert is a 16-bit BufferedImage with all desired data. 
       short[] bufferHolder = ((DataBufferUShort) bImageFromConvert.getRaster().getDataBuffer()).getData(); 
       //Since bImageFromConvert is 16-bits, the short array isn't the right length. 
       //The below conversion handles tihs issue 
       byte[] byteBuffer = convertShortToByte(bufferHolder); 
       //I'm not entirely sure what this int[] in the parameters should be. 
       //For now, it is a test int[] array containing all 1s 
       int[] testint = new int[byteBuffer.length]; 
       Arrays.fill(testint, 1); 
       //0 offset. dimWidth = 1760, dimHeight = 2140. Not sure what that last param is supposed to be in layman's terms. 
       //npe thrown at this line. 
       int testOut = pack.encode(byteBuffer, 0, dimWidth, dimHeight, testint, 1); 

沒有人有任何見解,以發生了什麼?此外,如果可用,有沒有人知道一個更好的方法來編碼我的TIFF文件在Java程序中使用PackBits?

讓我知道是否有什麼可以讓我的問題更清晰。

謝謝!

+2

堆棧跟蹤在哪裏?無論如何,當你在'ImageWriteParam'中指定「PackBits」作爲壓縮類型時,我認爲你不應該自己使用壓縮器,而是使用JAI ImageIO TIFF插件('TIFFImageWriter')。你也可以在param中傳遞一個壓縮器實例,如果你先將它轉換爲'TIFFImageWriteParam',但這對插件不知道的自定義壓縮更有用。 – haraldK

回答

1

至於說在註釋中,你不應該使用TIFFPackBitsCompressor直接,而不是它的內部,當你指定「緊縮位」作爲ImageWriteParam壓縮型使用的JAI ImageIO的TIFF插件(在TIFFImageWriter)。如果先將其轉換爲TIFFImageWriteParam,您也可以在param中傳遞壓縮器實例,但這對於插件未知的自定義壓縮更有用。

另外請注意,壓縮器只會寫入PackBits壓縮的像素數據,它會而不是創建一個完整的TIFF文件。

寫緊縮位壓縮的TIFF文件的正常方式是:

BufferedImage image = ...; // Your input image 

ImageWriter writer = ImageIO.getImageWritersByFormatName("TIFF").next(); // Assuming a TIFF plugin is installed 

try (ImageOutputStream out = ImageIO.createImageOutputStream(...)) { // Your output file or stream 
    writer.setOutput(out); 

    ImageWriteParam param = writer.getDefaultWriteParam(); 
    param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT); 
    param.setCompressionType("PackBits"); 

    writer.write(null, new IIOImage(image, null, null), param); 
} 

writer.dispose(); 

上面的代碼應該可以正常同時使用JAI ImageIO的和TwelveMonkeys ImageIO的TIFF插件。


PS:PackBits是基於對run-length encoding字節數據一個非常簡單的壓縮算法。由於16位數據可能在單個採樣的高字節和低字節之間變化很大,因此PackBits通常不適合壓縮此類數據。

正如我在註釋中規定,使用我得到了以下結果完全隨機的值:

Compression  | File size 
-----------------|----------------- 
None    | 7 533 680 bytes 
PackBits   | 7 593 551 bytes 
LZW w/predictor | 10 318 091 bytes 
ZLib w/predictor | 10 318 444 bytes 

這是不是很奇怪,因爲完全隨機的數據不是一般的壓縮(沒有數據丟失)。對於一個線性梯度,其可以是更類似於「攝影」圖像數據I得到完全不同的結果:

Compression  | File size 
-----------------|----------------- 
None    | 7 533 680 bytes 
PackBits   | 7 588 779 bytes 
LZW w/predictor | 200 716 bytes 
ZLib w/predictor | 144 136 bytes 

正如所看到的,這裏的LZW和放氣/ zlib的算法(與預測步驟)執行要好得多。對於「真實」數據,可能會有更多噪音,因此您的結果可能處於這些極端之間的某個位置。

+0

當文件正在寫入並且處於tiff格式時,它大約是原始文件大小的兩倍。如果它有幫助,short []將保留16位圖像的包裝字節。圖像爲1760x2140像素,原始圖像大小爲7,532,800字節(無元數據,僅爲像素字節)。由此代碼生成的文件15,119,390字節(包括tiff元數據)。 – Sarah

+0

@Sarah你剛剛發現PackBits是一種非常低效的數據壓縮算法(對於一般的16位數據來說效率很低)。使用上面的代碼,我將黑色圖像(仍爲1760x2140 16位/像素)壓縮到120 KB。用隨機噪聲填充圖像,文件大小變成7.5 Mbytes。使用帶預測器的LZW或ZLib給出了大小約爲10 MB的大小,但對於您來說它仍可能產生更好的結果,因爲您的數據不是隨機的。 – haraldK