Reputation: 41
I have a jPanel whose width is 23500 and height 43000. I'm writing a PNG image file, but receive OutOfMemoryError: Java heap space. Is it possible to write such a large image from an equally large jPanel? I've spent about 8 hours online and simply cannot find the answer.
The error is thrown from the bufferedReader declaration. Any help would be greatly appreciated! I'll post the solution when I figure it out.
My code is below:
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();
}
Upvotes: 2
Views: 149
Reputation: 41
The large PNG image this answer produces may not be able to be opened due to it's (arbitrarily large) size. However, one can always take the PNG to a printshop (assuming you don't have a poster printer). It's a pure java method. How it works: it recycles a bufferedImage to sequentially write to disk, an ARGB PNG file using graphical translations of the (arbitrarily large) component.
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();
}
Upvotes: 1