连接具有低或恒定内存占用的多个jpeg图像

时间:2012-03-20 05:28:57

标签: java jpeg javax.imageio

我有多个图像,每个图像的分辨率大约为2560x10000,我想加入所有这些图像来制作一个图像。我不能使用BufferedImage方法作为最终图像,我必须加入的图像将同时在内存中导致OutOfMemory。所以我尝试了以下方法:

public static void joinJpegFiles(File infile, File outfile, float compQuality,int i) {
    try {
        RenderedImage renderedImage = ImageIO.read(infile);
        ImageWriter Iwriter = null;

        Iterator iter = ImageIO.getImageWritersByFormatName("jpeg");
        if (iter.hasNext()) {
            Iwriter = (ImageWriter)iter.next();
        }

        ImageOutputStream IOStream = ImageIO.createImageOutputStream(outfile);
        Iwriter.setOutput(IOStream);
        IOStream.seek( IOStream.length());
        JPEGImageWriteParam JIWP=new JPEGImageWriteParam(Locale.getDefault());
        JIWP.setCompressionMode(ImageWriteParam.MODE_EXPLICIT) ;
        JIWP.setCompressionQuality(compQuality);
        Iwriter.write(null, new IIOImage(renderedImage,null,null), JIWP);               
        IOStream.flush();
        IOStream.close();
        Iwriter.dispose();
    } catch (IOException e) {
        System.out.println("write error: " + e.getMessage());
    }
}

为我想加入的每张图片调用此方法 这种方法的问题是最终图像的大小增加并且等于我加入的所有图像的大小总和,但是当我打开最终图像时只有第一个图像可见。 我仍然无法弄清楚我做错了什么,我也找不到任何示例代码来加入除了BufferedImage和ImageIO.write方法之外的jpegs。我在新闻组看到它适用于tiff格式,但我需要这个用于jpeg / png格式。

1 个答案:

答案 0 :(得分:1)

我认为你已经解决了这个问题,或者以某种方式解决了这个问题,但是..如果其他人需要解决类似的问题:

有点不清楚你想要在这里实现什么。您真的想创建一个大图像,还是创建一个包含多个图像的文件?

单个文件中的多个图片:

您的代码似乎将多个独立的JPEG文件附加到一个文件中。 JPEG(JFIF)格式不支持此功能,大多数软件可能只会将您的文件视为第一个JPEG,并在末尾添加了大量垃圾字节。 PNG不允许在一个文件AFAIK中存储多个图像。像TIFF这样的格式允许多个图像(它甚至允许你将它们存储为JPEG流),这可能是TIFF被提出的原因。

然而,JPEG标准有一个名为Abbreviated Streams的概念,这与JPEG通常存储在金字塔TIFF中的方式非常相似。 ImageIO JPEGImageWriter支持此功能:

  

“缩写流是使用ImageWriter的序列方法编写的。流元数据用于在流的开头编写仅表格图像,并使用ImageWriter.prepareWriteSequence设置表格以供使用。如果没有流元数据提供给ImageWriter.prepareWriteSequence,然后不写入只有表格的图像。如果向ImageWriter.prepareWriteSequence提供不包含表格的流元数据,则会写入包含默认视觉无损表格的仅表格图像。“

我不确定其他软件如何解释这些类型的文件,根据the libjpeg docs,它可能甚至不起作用:

  

“虽然缩写数据流   可以在封闭的环境中使用,强烈建议不要使用它们   任何可能需要与其他应用程序进行数据交换的情况。   警告设计师。“

所以..它可能适用于您的用例,也可能不适用。

将多个图像合成一个大图像:

另一方面,如果您真的想将多个图像合成一个大图像(以后再存储为单个JPEG),您可以查看我很久以前写过的some code,以便与之合作大图像,不使用堆内存。

它使用memory-mapped byte buffers,如果没有足够的内存将数据存储在RAM中,可能会非常慢。此外,生成的BufferedImage将始终为TYPE_CUSTOM,因此它将错过您通常会受益的大多数潜在硬件或本机加速,并且某些操作可能无法正常工作。但是,至少您不受堆大小和物理RAM的限制。