编写没有OutOfMemoryError的大型JPanel PNG,也不增加VM堆大小

时间:2018-04-02 03:44:13

标签: java bufferedimage javax.imageio

我有一个jPanel,其宽度为23500,高度为43000.我正在编写PNG图像文件,但收到OutOfMemoryError:Java堆空间。是否可以从同样大的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();
}

1 个答案:

答案 0 :(得分:1)

此答案产生的大PNG图片可能由于其(任意大)尺寸而无法打开。但是,您始终可以将PNG带到印刷厂(假设您没有海报打印机)。这是一个纯Java方法。工作原理:使用(任意大)组件的图形化转换,回收bufferedImage依次写入磁盘,即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();
}