我可以保存一个巨大的PNG,而不是整个内存吗?

时间:2011-08-21 17:14:58

标签: java png

我用Java保存了一个非常大的PNG(25 MB左右)。问题是,虽然它正在生成,但它使用3千兆字节的内存,这并不理想,因为它会严重降低内存不足的系统。

我正在使用的代码需要将一组平铺图像组合成一个图像;换句话说,我有九张图片(PNG):

A1 A2 A3
B1 B2 B3
C1 C2 C3

需要合并为单个图像。

我正在使用的代码是:

image = new BufferedImage(width, height, height, BufferedImage.TYPE_INT_ARGB_PRE);
g2d = image.createGraphics();
g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);

// draw the 9 images on here at their proper positions...

// save image
g2d.dispose();
File file = getOutputFile();
ImageIO.write(image, "png", file);

有没有办法制作和保存图像而不将整个图像留在内存中?


修改 为了绘制图像,我正在循环中这样做:

BufferedImage tile = ImageIO.read(new File("file.png"));
g2d.drawImage(tile, x, y, w, h);

这种情况经常重复多次(通常约为25x25,但有时甚至更多),所以如果这里的内存泄漏很少,那可能会导致问题。

3 个答案:

答案 0 :(得分:5)

您还可以查看此PNGJ库(免责声明:我对其编码),它允许逐行保存PNG图像。

答案 1 :(得分:4)

ImageIO.write(image, "png", file);在内部使用com.sun.imageio.plugins.png.PNGImageWriter。那个方法和那个作者希望图像是一个渲染图像,但是PNG写入是由'band'完成的,所以你可以创建一个RenderedImage的子类,当编写者向图像请求这些波段时,它会生成所组成的大图像的请求波段。

来自PNGImageWriter类:

private void encodePass(ImageOutputStream os,
                        RenderedImage image,
                        int xOffset, int yOffset,
                        int xSkip, int ySkip) throws IOException {
    // (...)
    for (int row = minY + yOffset; row < minY + height; row += ySkip) {
                Rectangle rect = new Rectangle(minX, row, width, 1); // <--- *1
                Raster ras = image.getData(rect); // <--- *2

* 2我认为这是作家从你的图像中读取像素的唯一地方。 你应该制作一个getData(rect)方法来计算将3个图像中的3个波段连接成一个矩形。

* 1如您所见,它会读取高度为1像素的条带。

如果我认为你应该只需要一次制作3张图像。其他6不需要在内存中。

我知道这不是一个简单的解决方案,但如果你没有找到更容易的东西,它可能会有所帮助。

答案 2 :(得分:1)

使用外部工具是一种选择吗?我记得使用ImageMagick是出于类似的目的,你需要先保存较小的图像。