如何在 Java 中从大图像中删除图像元数据而不导致内存不足

Rob*_*tos 5 java

我需要从图像中删除元数据,但当图像太大时,我会遇到 OOM。现在我正在使用 ImageIO 来实现这一点。

BufferedImage image = ImageIO.read(new File("image.jpg"));
ImageIO.write(image, "jpg", new File("image.jpg"));
Run Code Online (Sandbox Code Playgroud)

问题是ImageIO.read(...)会将整个文件读入内存,当我处理太大的图像时,这会导致 OutOfMemory 。

我可以尝试使用 CommonsImaging ( https://commons.apache.org/proper/commons-imaging/sampleusage.html),但看起来它只支持 JPEG(ExifRewriter 类)。

更改虚拟机的内存配置不是一个选项,我需要支持的不仅仅是 JPEG 文件。

有什么想法可以在不导致内存不足的情况下做到这一点吗?

uni*_*now -1

您可以通过流式传输复制图像来尝试,并在流式传输期间应用过滤器来删除元数据。

复制可以按如下方式完成:

    InputStream is = null;
    OutputStream os = null;
    try {
        // Source and Destination must be different 
        is = new FileInputStream(new File("path/to/img/src"));
        os = new FileOutputStream(new File("path/to/img/dest"));

        // Limit buffer size further is necessary!
        byte[] buffer = new byte[1024];
        int length;
        while ((length = is.read(buffer)) > 0) {
            // Apply removal of metadata here!!!
            os.write(buffer, 0, length);
        }
    } finally {
        is.close();
        os.close();
    }
Run Code Online (Sandbox Code Playgroud)

请注意,原始文件和克隆文件不能相同,因此可能需要删除原始文件并随后重命名目标文件(如果您希望它们相同)。

除了普通的,outputstream您还可以创建自己的FilteredOutputstream并使用它。

  • 这种方法的问题在于,每个图像都有自己的存储元数据的方式,并且在此应用此逻辑会使代码过于复杂。我必须知道每个支持的图像如何存储元数据,然后计算读取的字节数......太容易出错。 (3认同)