Tuesday, February 16, 2016

Image Resizing by java, Change JPEG image quality

I have seen sample code from others to resize image and change jpeg quality by java. It was pretty good. but, just I didn't like one thing that most of them didn't close the stream of file reading or writing. So, The image files were not able to removed or rewrited. I guess probably, it will cause to create jomby process which is never die unless restart JVM. Thease kind of things must be avoided to make a stable application. It will not be visible for now. but, It will capture the application one day and make difficult to find out why application is not stable.

Add Maven Dependendy to resize image
<dependency>
 <groupId>org.imgscalr</groupId>
 <artifactId>imgscalr-lib</artifactId>
 <version>4.2</version>
</dependency>


import javax.imageio.IIOImage;
import javax.imageio.ImageIO;
import javax.imageio.ImageReader;
import javax.imageio.ImageWriteParam;
import javax.imageio.ImageWriter;
import javax.imageio.plugins.jpeg.JPEGImageWriteParam;
import javax.imageio.stream.FileImageOutputStream;

import org.imgscalr.Scalr;
import org.imgscalr.Scalr.Method;
import org.imgscalr.Scalr.Mode;
...

public class ImageUtil {

    public static void downsizeJpg(Path sourcePath, Path targetPath, int targetWidth) throws IOException {

        try (InputStream isSrc = new FileInputStream(sourcePath.toFile())) {

            // Don't Use "ImageIO.read(File file)". It will not close the stream
            // Use Stream to close the resource    
            BufferedImage sourceImage = ImageIO.read(isSrc);

            double width = sourceImage.getWidth();
            double height = sourceImage.getHeight();
            double ratio = width / height;
            int trgHeight = (int) (targetWidth / ratio);

            // If taget width is smaller than source width, start to downsize
            if (targetWidth < width) {

                BufferedImage targetImage = Scalr.resize(sourceImage, Method.QUALITY, Mode.FIT_EXACT, targetWidth,
                        trgHeight);
                saveImage(targetImage, targetPath, 0.7f);

                // prevent upsizing. just copy the source image to target image
            } else {

                saveImage(sourceImage, targetPath, 0.7f);
            }
        }
    }

    private static void saveImage(RenderedImage image, Path targetPath, float quality) throws FileNotFoundException,
            IOException {

        // set compression level 
        JPEGImageWriteParam jpegParams = new JPEGImageWriteParam(null);
        jpegParams.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
        jpegParams.setCompressionQuality(quality);

        final ImageWriter writer = ImageIO.getImageWritersByFormatName("jpg").next();

        try (FileImageOutputStream fios = new FileImageOutputStream(targetPath.toFile())) {

            // specifies where the jpg image has to be written
            writer.setOutput(fios);

            // save the image
            writer.write(null, new IIOImage(image, null, null), jpegParams);
            writer.dispose();
        }

    }
}

quality can be fromo 0f to 1f. 1 is the highst quality and file size get big. 0 is lowest quality and file size get small.