我用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);
Run Code Online (Sandbox Code Playgroud)
有没有办法制作和保存图像而不需要将整个图像保存在内存中?
编辑: 要绘制图像,我在循环中执行此操作:
BufferedImage tile = ImageIO.read(new File("file.png"));
g2d.drawImage(tile, x, y, w, h);
这是重复多次(通常大约25x25,但有时更多),所以如果这里甚至有一个小的内存泄漏,那可能会导致问题.
ImageIO.write(image, "png", file);
内部使用 com.sun.imageio.plugins.png.PNGImageWriter。该方法和该作者期望图像是渲染图像,但 PNG 写入是通过“带”完成的,因此您可以创建 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
Run Code Online (Sandbox Code Playgroud)
*2 我认为这是作者从图像中读取像素的唯一地方。您应该创建一个 getData(rect) 方法来计算将 3 个图像中的 3 个波段连接成一个的 rect。
*1 如您所见,它读取高度为 1 像素的条带。
如果情况如我所想,您应该一次只需要合成 3 张图像。其他 6 个就不需要在内存中了。
我知道这不是一个简单的解决方案,但如果您找不到更简单的解决方案,它可能会对您有所帮助。
归档时间: |
|
查看次数: |
1329 次 |
最近记录: |