【问题标题】:Writing a large JPanel PNG without OutOfMemoryError nor increasing VM heap size编写一个没有 OutOfMemoryError 也没有增加 VM 堆大小的大型 JPanel PNG
【发布时间】:2018-04-02 03:44:13
【问题描述】:

我有一个宽度为 23500,高度为 43000 的 jPanel。我正在编写一个 PNG 图像文件,但收到 OutOfMemoryError: Java heap space。是否可以从同样大的 jPanel 写入如此大的图像?我在网上花了大约 8 个小时,根本找不到答案。

错误是从 bufferedReader 声明中引发的。任何帮助将不胜感激!等我弄明白了再贴出来。

我的代码如下:

try {
    BufferedImage bufferedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
    Graphics g = bufferedImage.createGraphics();
    uMLDiagramPanelJScrollPane.getViewport().getView().print(bufferedImage.createGraphics());
    g.dispose();
    ImageIO.write(bufferedImage, "PNG", new File(System.getProperty("user.home") + "/Desktop/" + "image.png/"));
} catch (IOException e) {
    e.printStackTrace();
}

【问题讨论】:

  • 请记住:您尝试创建的 BufferedImage 将需要 23500 * 43000 * 4 字节(或大约 3,7 GB)的连续堆...我认为您需要增加堆大小,除非您想花费大量时间实施不同的解决方案。是否可以选择将图像导出为多个较小的 PNG?其他一些替代方案是: 使用内存映射磁盘缓冲区,但它会很慢。或者也许实现您自己的 Graphics 子类,它以 BMP、TIFF 或 PPM 等未压缩格式直接写入磁盘。

标签: java bufferedimage javax.imageio


【解决方案1】:

此答案生成的大 PNG 图像可能无法打开,因为它的大小(任意大)。但是,人们总是可以将 PNG 带到印刷厂(假设您没有海报打印机)。这是一个纯java方法。它是如何工作的:它回收一个缓冲图像以顺序写入磁盘,一个使用图形转换(任意大)组件的 ARGB PNG 文件。

public void putArbitrarilyLargeComponentPNGImageOnWeeComputerDesktop(Component component) throws Exception {
    int width = component.getWidth();
    int componentHeight = component.getHeight();
    int clipHeight = 1000;
    int pixelRowsDrawn = 0;
    BufferedImage bufferedImage;
    Graphics g = null;
    ByteBuffer iHDRTypeAndDataPartsForCRCByteBuffer = ByteBuffer.allocate(17);
    FileOutputStream fos = new FileOutputStream(new File(System.getProperty("user.home") + "/Desktop/arbitrarilyLargePNG.png"), true);
    ByteArrayOutputStream compressed = new ByteArrayOutputStream(65536);
    DeflaterOutputStream dos = new DeflaterOutputStream(compressed, new Deflater(9), true);
    CRC32 crc = new CRC32();
    // Write 8-bytes PNG file signature and 4-byte IHDR data part length.
    fos.write(new byte[] { -119, 80, 78, 71, 13, 10, 26, 10, 0, 0, 0, 13 });
    iHDRTypeAndDataPartsForCRCByteBuffer.wrap(new byte[17]);
    iHDRTypeAndDataPartsForCRCByteBuffer.put("IHDR".getBytes());
    iHDRTypeAndDataPartsForCRCByteBuffer.put(ByteBuffer.allocate(4).putInt(width).array());
    iHDRTypeAndDataPartsForCRCByteBuffer.put(ByteBuffer.allocate(4).putInt(componentHeight).array());
    //See 4.1.1. at <https://www.w3.org/TR/PNG-Chunks.html> starting with "Bit depth"
    iHDRTypeAndDataPartsForCRCByteBuffer.put(new byte[] { 8, 6, 0, 0, 0 });
    fos.write(iHDRTypeAndDataPartsForCRCByteBuffer.array());
    crc.update(iHDRTypeAndDataPartsForCRCByteBuffer.array());
    fos.write(ByteBuffer.allocate(4).putInt((int) crc.getValue()).array());

    while (pixelRowsDrawn < componentHeight) {
        if (componentHeight - pixelRowsDrawn < clipHeight) clipHeight = componentHeight - pixelRowsDrawn;
        bufferedImage = new BufferedImage(width, clipHeight, BufferedImage.TYPE_INT_ARGB);
        g = bufferedImage.createGraphics();
        g.translate(0, -pixelRowsDrawn);
        component.paint(g);

        compressed.reset();
        int pixel, x = 0, y = 0;
        while (y < clipHeight) {
            x = 0;
            dos.write(0);
            while (x < width) {
                pixel = bufferedImage.getRGB(x, y);
                dos.write(new byte[] { (byte) ((pixel >> 16) & 0xff), (byte) ((pixel >> 8) & 0xff), (byte) (pixel & 0xff), (byte) ((pixel >> 24) & 0xff) });
                x++;
            }
            y++;
        }

        if ((pixelRowsDrawn = pixelRowsDrawn + clipHeight) == componentHeight) dos.finish();
        fos.write(ByteBuffer.allocate(4).putInt(compressed.size()).array());
        fos.write("IDAT".getBytes());
        crc.reset();
        crc.update("IDAT".getBytes());
        crc.update(compressed.toByteArray());
        fos.write(compressed.toByteArray());
        fos.write(ByteBuffer.allocate(4).putInt((int) crc.getValue()).array());
    }

    fos.write(new byte[] { 0, 0, 0, 0 });
    fos.write("IEND".getBytes());
    crc.reset();
    crc.update("IEND".getBytes());
    fos.write(ByteBuffer.allocate(4).putInt((int) crc.getValue()).array());

    g.dispose();
}

【讨论】:

    猜你喜欢
    • 2011-09-01
    • 2011-01-20
    • 2019-07-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-03-23
    • 2012-08-09
    • 2016-11-17
    相关资源
    最近更新 更多