Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do you create a thumbnail image out of a JPEG in Java?

Tags:

java

image

jpeg

People also ask

What is a JPEG thumbnail?

For most JPEG images created by phones or digital cameras, the thumbnail image (if present) is stored in the APP1 marker (FFE1). Inside this marker segment is a TIFF file containing the EXIF information for the main image and the optional thumbnail image stored as a JPEG compressed image.

How are thumbnail images created?

Thumbnails are usually generated automatically by search engines, image editing programs, as well as image management programs. The smaller file size of thumbnails is especially useful for mobile browsing.

What is thumbnail in Java?

In this tutorial, I will show you how we can create thumbnail images using Java. Thumbnails are the reduced size of images or videos. Basically, if your website is loading a lot of images with larger pixel values i.e larger size then, the performance of the website will be poor.


Image img = ImageIO.read(new File("test.jpg")).getScaledInstance(100, 100, BufferedImage.SCALE_SMOOTH);

This will create a 100x100 pixels thumbnail as an Image object. If you want to write it back to disk simply convert the code to this:

BufferedImage img = new BufferedImage(100, 100, BufferedImage.TYPE_INT_RGB);
img.createGraphics().drawImage(ImageIO.read(new File("test.jpg")).getScaledInstance(100, 100, Image.SCALE_SMOOTH),0,0,null);
ImageIO.write(img, "jpg", new File("test_thumb.jpg"));

Also if you are concerned about speed issues (the method described above is rather slow if you want to scale many images) use these methods and the following declaration :

private BufferedImage scale(BufferedImage source,double ratio) {
  int w = (int) (source.getWidth() * ratio);
  int h = (int) (source.getHeight() * ratio);
  BufferedImage bi = getCompatibleImage(w, h);
  Graphics2D g2d = bi.createGraphics();
  double xScale = (double) w / source.getWidth();
  double yScale = (double) h / source.getHeight();
  AffineTransform at = AffineTransform.getScaleInstance(xScale,yScale);
  g2d.drawRenderedImage(source, at);
  g2d.dispose();
  return bi;
}

private BufferedImage getCompatibleImage(int w, int h) {
  GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
  GraphicsDevice gd = ge.getDefaultScreenDevice();
  GraphicsConfiguration gc = gd.getDefaultConfiguration();
  BufferedImage image = gc.createCompatibleImage(w, h);
  return image;
}

And then call :

BufferedImage scaled = scale(img,0.5);

where 0.5 is the scale ratio and img is a BufferedImage containing the normal-sized image.


As you might have found out "easy" and "good looking result" are two very different things. I have encapsulated both of these requirements into a very simple java image scaling library (Apache 2 license) that just does everything right for you.

Example code to create a thumbnail looks like this:

BufferedImage img = ImageIO.read(...); // load image
BufferedImage scaledImg = Scalr.resize(img, 150);

Your image proportions are honored, the library makes a best-guess at the method it should use based on the amount of change in the image due to scaling (FASTEST, BALANCED or QUALITY) and the best supported Java2D image types are always used to do the scaling to avoid the issue of "black" results or really terrible looking output (e.g. overly dithered GIF images).

Also, if you want to force it to output the best looking thumbnail possible in Java, the API call would look like this:

BufferedImage img = ImageIO.read(...); // load image
BufferedImage scaledImg = Scalr.resize(img, Method.QUALITY, 
                                       150, 100, Scalr.OP_ANTIALIAS);

Not only will the library use the Java2D recommended incremental scaling for you to give you the best looking result, it will also apply an optional antialiasing effect to the thumbnail (ConvolveOp with a very fine-tuned kernel) to every-so-slightly soften the transitions between pixel values so make the thumbnail look more uniform and not sharp or poppy as you might have seen when you go from very large images down to very small ones.

You can read through all the comments in the library (the code itself is doc'ed heavily) to see all the different JDK bugs that are worked around or optimizations that are made to improve the performance or memory usage. I spent a LOT of time tuning this implementation and have had a lot of good feedback from folks deploying it in web apps and other Java projects.


This is simple way of creating a 100 X 100 thumbnail without any stretch or skew in image.

private  void saveScaledImage(String filePath,String outputFile){
    try {

        BufferedImage sourceImage = ImageIO.read(new File(filePath));
        int width = sourceImage.getWidth();
        int height = sourceImage.getHeight();

        if(width>height){
            float extraSize=    height-100;
            float percentHight = (extraSize/height)*100;
            float percentWidth = width - ((width/100)*percentHight);
            BufferedImage img = new BufferedImage((int)percentWidth, 100, BufferedImage.TYPE_INT_RGB);
            Image scaledImage = sourceImage.getScaledInstance((int)percentWidth, 100, Image.SCALE_SMOOTH);
            img.createGraphics().drawImage(scaledImage, 0, 0, null);
            BufferedImage img2 = new BufferedImage(100, 100 ,BufferedImage.TYPE_INT_RGB);
            img2 = img.getSubimage((int)((percentWidth-100)/2), 0, 100, 100);

            ImageIO.write(img2, "jpg", new File(outputFile));    
        }else{
            float extraSize=    width-100;
            float percentWidth = (extraSize/width)*100;
            float  percentHight = height - ((height/100)*percentWidth);
            BufferedImage img = new BufferedImage(100, (int)percentHight, BufferedImage.TYPE_INT_RGB);
            Image scaledImage = sourceImage.getScaledInstance(100,(int)percentHight, Image.SCALE_SMOOTH);
            img.createGraphics().drawImage(scaledImage, 0, 0, null);
            BufferedImage img2 = new BufferedImage(100, 100 ,BufferedImage.TYPE_INT_RGB);
            img2 = img.getSubimage(0, (int)((percentHight-100)/2), 100, 100);

            ImageIO.write(img2, "jpg", new File(outputFile));
        }

    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

}

The JMagick library (and implementation of ImageMagick in Java) will have what you need.


the Java code above (with the scale / getCompatibleImage methods) worked great for me, but when I deployed to a server, it stopped working, because the server had no display associated with it -- anyone else with this problem can fix it by using: BufferedImage bi = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);

instead of BufferedImage bi = getCompatibleImage(w, h);

and deleting the getCompatibleImage method

(later note -- it turns out this works great for most images, but I got a bunch from my companys marketing department that are 32 bit color depth jpeg images, and the library throws an unsupported image format exception for all of those :( -- imagemagick / jmagick are starting to look more appealing)


I have writtena util class with static methods years ago using JAI. Java Advanced Imaging API is the most reliable API in Java to deal with images. It's vector interpolation is closest thing to Photoshop in Java world. Here is one of them:

public static ByteArrayOutputStream resize(InputStream inputStream , int IMG_WIDTH,
        int IMG_HEIGHT) throws Exception {
    BufferedImage originalImage = ImageIO.read(inputStream);
    int type = originalImage.getType() == 0 ? BufferedImage.TYPE_INT_ARGB
            : originalImage.getType();
    BufferedImage resizedImage = new BufferedImage(IMG_WIDTH, IMG_HEIGHT,
            type);
    {
        Graphics2D g = resizedImage.createGraphics();
        g.drawImage(originalImage, 0, 0, IMG_WIDTH, IMG_HEIGHT, null);
        g.dispose();
        g.setComposite(AlphaComposite.Src);

        g.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
                RenderingHints.VALUE_INTERPOLATION_BILINEAR);
        g.setRenderingHint(RenderingHints.KEY_RENDERING,
                RenderingHints.VALUE_RENDER_QUALITY);
        g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                RenderingHints.VALUE_ANTIALIAS_ON);
    }
    ByteArrayOutputStream bos = new ByteArrayOutputStream();
    ImageIO.write(resizedImage, "png", bos);
    return bos;

}