Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to resize an image in a stream (using minimal RAM)?

Looking for something like djpeg which uses O(1) RAM to resize by sub sampling, but in java and able to handle jpg, png, gif, bmp, etc. Maybe some implementation already exists. How to resize an image in a stream (using minimal RAM)?

like image 570
user1133275 Avatar asked Jun 26 '13 18:06

user1133275


People also ask

How do I resize an image in Preview?

Resizing in Preview To start, select the image you want to resize by clicking Open With > Preview. Once you have your image opened, go to Tools in your menu bar and select Adjust Size.

How do I resize a photo on my Mac without losing quality?

In the Preview app on your Mac, open the file you want to change. Choose Tools > Adjust Size, then select “Resample image.” Enter a smaller value in the Resolution field. The new size is shown at the bottom.


2 Answers

The FileImageInputStream doesn't know anything about specific image formats, it's just convenience for reading ints, shorts, bytes, byte arrays, etc, from a file-backed input. File format support is handled by the various ImageReader implementations.

The short answer to your question is: You can't really resize an image without loading it.

From the description of djpeg:

djpeg decompresses the named JPEG file [...]

(Emphasis is mine)

However, you can subsample images, wich is really fast (for most formats), and will uses less memory. Have a look at the ImageReadParam.setSourceSubSampling method and the ImageReader.read(int, ImageReadParam) method. This will create a resized image, quite similar to the "nearest neighbour" or "point sampling" algorithms (ie. the results won't necessary look good).

It's possible to combine subsampling first, with better quality resizing afterwards, to save memory, and possibly get acceptable results. It all depends on what quality you expect/need.

If you really, really want to resize images without loading them into heap memory (perhaps your images are huge), I've written some classes that use memory mapped files you can look at, but they are painfully slow.

like image 157
Harald K Avatar answered Sep 28 '22 16:09

Harald K


  • The twelvemonkeys jars enable reading of non RGB jpegs
  • setSourceSubSampling and setSourceRegion permit resizing images in a stream.
  • Progressive jpegs are not supported
  • Large output files are not supported

Example:

File javaStreamSubsample(File inFile, int s, Rectangle sourceRegion) throws IOException  {
    File outFile = File.createTempFile("img", null);;
    ImageInputStream input = ImageIO.createImageInputStream(inFile);
    try {
        Iterator<ImageReader> readers = ImageIO.getImageReaders(input);
        ImageReader reader = readers.next();
        try {
            reader.setInput(input);
            ImageReadParam param = reader.getDefaultReadParam();
            param.setSourceSubsampling(s, s, 0, 0);
            if(sourceRegion!=null){
                param.setSourceRegion(sourceRegion);
            }
            BufferedImage image = reader.read(0, param);
            ImageIO.write(image, "jpg", outFile);
        }finally {
            reader.dispose();
        }
    } finally {
        input.close();
    }
    return outFile;
}
like image 36
user1133275 Avatar answered Sep 28 '22 16:09

user1133275