BINARY BufferedImage and memory consumption

My first post here so hi everyone!

I have a rather difficult question for you guys:

I have a relatively large binary (black & white) image on disk. Dimensions 8000x4000 px.
But because its binary, my math says its not that big in memory (8000x4000bits = around 3.81 MB).

When i load it into BufferedImage, memory consumption rises for expected amount.
But when i resize it, regardless of the ratio (be it 1 pixel resize), memory usage jumps for 250 MB!

So what’s going on and how can i make it stop? :slight_smile:

Here is a little example i prepared to illustrate above situation:


import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;
 
public class BufferedImageTest {
    public static void main(String[] args) {
        try {
            // initial: 7.8 MB
            
            BufferedImage image = ImageIO.read(new File("images/world_test.png"));         // image is 8000x4000 binary (black and white only)
            // 14.4 MB
            
            BufferedImage result = new BufferedImage(image.getWidth(), image.getHeight(), BufferedImage.TYPE_BYTE_BINARY);
            // 18.9 MB
            
            Graphics2D g = result.createGraphics();
            // 21.5 MB
            
            g.drawImage(image, 0, 0, 8000, 4000, null); 
            // 21.5 MB
 
            g.drawImage(image, 0, 0, 7999, 4000, null); 
            // 277.7 MB
        } catch (IOException ex) {
            Logger.getLogger(BufferedImageTest.class.getName()).log(Level.SEVERE, null, ex);
        }
 
    }
}

Does this also happen when you resize to… let’s say 2000 or 16000?

Could be because it has to calculate the new color for each pixel which might be easier if you simply double it.
Just speculating.

Ok, if that would be the case, than memory usage would rise for 8 MB, not 250 MB!

But maybe you got the point. It’s possible that drawImage method is internaly transforming image from binary to “desktop color” which is in my case 32 bit.
One image would than take 122 MB, and if it makes a copy, thats 244 MB! Then it creates final image in 1-bit color, thats additional 3.81 MB.

Now thats a “green” method ;D

Hi,

Try to replace


            g.drawImage(image, 0, 0, 7999, 4000, null); 
            // 277.7 MB

with


            BufferedImageOp op = new ColorConvertOp(image.getColorModel(),result.getColorModel(),null);
            BufferedImage img1 = op.filter(image, null);
            g.drawImage(img1, new AffineTransform(7999f/8000f,0f,0f,1f,0,0), null);

Maybe this will help.

Regards

How are you measuring the ram consumption?

However I suspect that rescaling operation is taking place in a temporary buffer/Image which will probably use a more plain pixel format (ie 24-32 bits per pixel ~128M). I had this problem with rotations. In fact I would say that using java2D you would need to be careful with what you do to avoid these kind of intermediate steps. You could try turning on java2d debug call tracing or whatever its called.

Other things to check: Antialising settings and interpolation settings. Nearest neighbour is the only thing that keeps intermediate results binary. Others result in gray scale .

Thank you for the suggestion, but it didn’t work. It ate 400 MB and was extremly slow.

Thank you for your answer!

Is seems that is what happens.
i’m still searching for a way how to avoid it.

I found that this is a java related bug and is already reported.

http://bugs.sun.com/view_bug.do?bug_id=6716560