保存大型BufferedImage时出现内存不足问题

7

我在保存大尺寸(比如 12,000 x 9,000 像素)的图片时遇到了问题。

我正在开发一款图形编辑软件(类似简化版 Photoshop),用户必须能够保存图片。

假设我想将图像保存为 .png 格式,那么 Java 是否总是需要使用 BufferedImage 来保存绘制的内容呢?

我知道计算图像大小的公式是:X 尺寸 × Y 尺寸 × 4(红、绿、蓝、透明度),因此在这种情况下,图像大小超过了 400MB。

我知道可以将图像分割成多个部分(瓦片)来保存,但无论如何用户都必须合并它们。

有没有其他方法可以在不使用 BufferedImage 的情况下保存如此大的图像呢?

保存图像的代码:

 public static void SavePanel() {

    BufferedImage image = null;
    image =  new BufferedImage(
            (int) (Main.scale * sizeX ),
            (int) (Main.scale * sizeY ),
            BufferedImage.TYPE_INT_RGB);

    g2 = image.createGraphics();
    panel.paint(g2);


    try {
        ImageIO.write(image, "png", new File(FactoryDialog.ProjectNameTxt.getText() + ".png"));
    } catch (IOException e) {
    }


}

感谢您的提前帮助!
2个回答

6
ImageIO.write(..)方法接受一个RenderedImage,而不仅仅是BufferedImage。我曾经成功地利用这个事实来写出非常大的图片。通常,编写器实现按顺序写出图像,并只在需要它们当前所需的部分时询问RenderedImage
从你的代码中看,我认为有可能黑客一个RenderedImage实现,它在构造函数中使用你的panel,并可以通过ImageIO传递给写入。在此过程中,ImageIO将请求从您的图像获取数据。然后,您可以使用面板即时创建所请求的部分(Raster内容)。这样,整个图像在任何时候都不必存储在内存中。这种方法的起点是:
public class PanelImage implements RenderedImage {

   private final Panel panel;

   public PanelImage(Panel panel) {
      this.panel = panel;
   }

   /* implement all the missing methods, don't be afraid, most are trivial */

}

显然,您还应该检查您的面板(panel)是否遭受与BufferedImage相同的问题。根据您的应用程序的性质,您将不得不至少在内存中保留图像一次(除非使用平铺)。但是这样,您至少可以避免重复。


听起来是个好主意,但我在实现getSampleModel和getData(rect)方法时遇到了一些困难(对这些不太熟悉)。 - Icki
您可以在这些方法中创建一个BufferedImage,将感兴趣的区域绘制到其中,然后返回其RasterSampleModel。如果这本身就是一个问题,也许最好单独发布一个关于这些问题的问题,这样我们就不必在评论中讨论它了。 - Waldheinz
好的,谢谢您的帮助。我在处理光栅方面遇到了一些问题,但我想我会提出另一个问题来解决它。 - Icki
如果您能在这里看一下 - https://dev59.com/RFnUa4cB1Zd3GeqPY0Vf 我在那里详细说明了我的问题。 - Icki

0

使用像 ImageMagick 这样的本地图像调整大小工具。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接