views:

917

answers:

2

I want to save some java.awt.Image objects into the disk. But when I try like:

for (Image image : images) {
    image = new ImageIcon(image).getImage();
    BufferedImage temp = new BufferedImage(image.getWidth(null), image.getHeight(null), BufferedImage.TYPE_INT_RGB);
    Graphics2D g = temp.createGraphics();
    g.drawImage(image, 0, 0, null);
    g.dispose();
    File tempFile = null;
    try {
        tempFile = File.createTempFile("img", ".jpg");
        ImageIO.write(temp, "jpg", tempFile);
        } catch (IOException ex) {
            ex.printStackTrace();
        }
    files.add(tempFile);
}

I get java heap space error.

I needed to put

image = new ImageIcon(image).getImage();

to get all the pixels loaded so that image.getwidth(null) and image.getHeight(null) return valid results.

Is there any other way to do this except for increasing heap size?

A: 

You could possibly save some heap by not holding all the images in a collection which you then iterate. Instead, retrieve and write each image as you get it. The hasMoreImages() and scanner.getNextImage() parts of my suggested code are one possible implemention of this.

I'd also question the wisdom of painting the image with a Graphics context, when it might already be in a state you can write with ImageIO. ImageIO.write() requires a RenderedImage, so a quick instance check might be good enough.

while( hasMoreImages() ) {
    Image image = scanner.getNextImage();

    if ( image instanceof RenderedImage) ) {
        File tempFile = File.createTempFile( "img", ".jpg" );
        ImageIO.write( (RenderedImage)image, "jpg", tempFile );
        files.add( tempFile );
    } else {
        // Do your ImageIcon code thing here.
    }
}
banjollity
My Image is not a RenderedImage. It's an Image made by MemoryImageSource, filled outside of my Java code in a DLL. I just get a collection of Images by calling a function of that DLL. The memory allocation for Image and MemoryImageSource is done in DLL and does not affect my heap space. But when I want to save the Image from inside my java code, I needed to make BufferedImages out of Images and that made the heap full, I guess.
Mohammad Alinia
I was thinking of implementing a new java.awt.image.DataBuffer and create a custom BufferedImage. Is that gonna work?
Mohammad Alinia
A: 

Your problem is that scanner images are HUGE -- at 600 dpi, we're talking over 100 MB uncompressed per color A4 page. Good scanners can get scans at thousands of DPI -- at 2000 DPI, a single uncompressed color page will be over 1 GB. The size of good-quality scans catches most people unprepared when they first start working with them.

Unless you're running a 64-bit operating system with gigs and gigs of RAM, you're never going to fit more than a few images in memory. Scanning in black & white or greyscale and at a lower resolution will help, but the best solution is to change how you handle images.

Don't get a collection of images in memory -- get a piece of each image at a time, and write out the image until complete. Put your TWAIN driver and API to work -- let it pass you buffers with parts of an image until done. You're probably better off using a Java library to do this than rolling your own image handling


Edit: links for Java TWAIN libraries

BobMcGee
Do you know any library that can do this for me?
Mohammad Alinia
BobMcGee