在Java

时间:2015-04-22 12:27:09

标签: java type-conversion png jpeg encoder

所以,假设我想用Java将一些PNG重新编码为JPEG。图像具有极高的分辨率,例如10 000 x 10 000px。使用“标准”Java映像API编写器和读取器,您需要在某些时候将整个映像解码到RAM中,这会占用极大的RAM空间(数百MB)。我一直在寻找其他工具如何做到这一点,我发现ImageMagick使用磁盘像素存储,但这似乎对我的需求来说太慢了。所以我需要的是Tru streaming streamder。通过真正的流式传输,我的意思是通过chuncks或bin来读取和处理数据,而不仅仅是将流作为输入,而是事先对其进行解码。

现在,首先是背后的理论 - 在JPEG和PNG算法的基础上,甚至可以使用流来实现这一点,或者说在数据箱中呢?所以不需要在内存(或其他存储)中编码整个图像?在JPEG压缩中,前几个阶段可以在流中完成,但我相信Huffman编码需要在量化后构建整个值概率树,因此需要分析整个图像 - 因此整个图像需要事先解码,或者以某种方式按需解码按地区划分。

如果能够实现上述目标,那么问题就在于,是否有任何Java库可以以这种方式运行?并节省大量的RAM?

3 个答案:

答案 0 :(得分:1)

如果我创建一个10,000 x 10,000 PNG文件,充满不可压缩的噪音,使用ImageMagick就是这样:

convert -size 10000x10000 xc:gray +noise random image.png

我看到ImageMagick使用675M的RAM来创建572MB的文件。

我可以将其转换为vips的JPEG,如下所示:

vips im_copy image.png output.jpg

vips在转换时使用不超过100MB的RAM,并且在4年左右的合理规格iMac上花费7秒 - 尽管有SSD。

答案 1 :(得分:0)

我已经编写了一个PNG编码器/解码器,用于PNG格式(逐步读取和写入,只需要在内存中存储一​​行):PNGJ

我不知道是否有与JPEG相似的东西

答案 2 :(得分:0)

我已经考虑了一段时间,我真的想实现这样一个库。不幸的是,它并不那么容易。不同的图像格式以不同的方式存储像素。 PNG或GIF可以交错。 JPEG可以是渐进式(多次扫描)。 TIFF通常是条纹或平铺的。 BMP通常自下而上存储。 PSD被引导。等

因此,您必须阅读以重新编码为不同格式的最小数据量,在最坏的情况下可能是整个图像(或者如果格式支持随机访问,则可能不是,并且您可以使用大量的来回seek ... ...在大多数情况下,使用相同格式对图像进行重新采样(缩放)可能会起作用(对于渐进式JPEG可能不太好),除非您可以单独重新采样每个扫描)。

如果您可以使用磁盘缓冲区,作为第二个最佳选项,我创建了一些类,允许BufferedImage由nio MappedByteBuffer支持(内存映射文件{{ 1}} s,有点像虚拟内存)。虽然性能并不像内存中的图像,但它也并非完全没用。请查看MappedImageFactoryMappedFileBuffer