解析在流中连续存储的多个jpeg

时间:2017-12-05 21:18:22

标签: java image jpeg javax.imageio

我有一个可以包含一个或多个图像的流,连续存储,没有任何标记。当我使用javas ImageIO打开并解析流时,它会正确解析第一个图像,但它会关闭流,这使我无法流式传输下一个图像。

所以我试图找出文件中每个压缩图像的大小,以便我可以将该图像的确切字节数读入缓冲区,从该缓冲区中创建ByteArrayInputStream,然后创建BufferedImage使用新的较小缓冲区。我的问题是弄清楚图像有多大,宽度/高度没有帮助,因为压缩比宽度*高度小。

有没有办法读取缓冲区并找出每个图像容易结束的位置?除了溪流末端的一个eof外,没有soi,eoi,sof,eof,标签。

或者有更好的方法吗? ImageIO.read()的一种方式,它不会关闭流并让我继续使用它?

1 个答案:

答案 0 :(得分:0)

首先,tas_status是一种便捷方法,它只能读取任何格式的任何文件的单个(第一个)图像。

相反,如果您获得输入的ImageIO.read(...),则可以(通常)使用ImageReader获取输入中的图像数量,并使用{{读取(或跳过)单个图像1}}。

类似的东西:

getNumImages(boolean allowSearch)

JRE捆绑的read(int imageIndex, ImageReadParam param)理论上也应支持单个流中的多个JFIF子流。但是,我认为您会发现支持被破坏(至少我的ImageIO插件项目中有open issue to fix this)。

不幸的是,找不到没有解码的JPEG压缩图像的长度(或者将长度存储在JFIF流之外)是不可能的。

您可以尝试的一件事是(可能包裹// Create input stream try (ImageInputStream input = ImageIO.createImageInputStream(file)) { // Get the reader Iterator<ImageReader> readers = ImageIO.getImageReaders(input); if (!readers.hasNext()) { throw new IllegalArgumentException("No reader for: " + file); } ImageReader reader = readers.next(); try { reader.setInput(input); // Optionally, listen for read warnings, progress, etc. reader.addIIOReadWarningListener(...); reader.addIIOReadProgressListener(...); ImageReadParam param = reader.getDefaultReadParam(); // Note: For some formats (ie. GIF), finding the number of images // requires searching the entire stream. In this case, it may // be more convenient to just read until you get an IndexOutOfBoundsException for (int i = 0; i < reader.getNumImages(true); i++) { // Optionally, control read settings like sub sampling, source region or destination etc. param.setSourceSubsampling(...); param.setSourceRegion(...); param.setDestination(...); // ... // Finally read the image, using settings from param BufferedImage image = reader.read(i, param); // Optionally, read thumbnails, meta data, etc... int numThumbs = reader.getNumThumbnails(0); // ... } } finally { // Dispose reader in finally block to avoid memory leaks reader.dispose(); } } )以读取第一张图像,然后向前扫描以获取下一张SOI(“图像开始”,{ {1}})标记,寻找两个字节(对于SOI标记)并尝试读取下一个图像。 SOI标记不能存在于JPEG编码数据中。

您可以在维基百科上阅读有关JPEGJFIF segments的更多信息。