views:

377

answers:

4

The title says it all. We're building an application that handles image uploads. I want users to be able to upload an image at a given size, say 128x128, and then have the server automatically generate other sizes based on that, such as 64x64, 57x57, and 25x25.

Are there libraries that can help me with this?

Edit: I should note that the resizing should take place only on upload. When the new image sizes are rendered in the browser, it should be pulling from cached copies --- not doing the resizing again. In other words, the different sizes should be generated only once, not each time the images are requested.

+2  A: 

This might be helpful. AFAIK, there are a variety of ways to do this, with varying speed/image quality.

jsn
+1 link to a code example
stacker
+2  A: 

I have used ImageIO and ImageInfo libraries for similar functionalities. They are pretty good so far.

http://java.sun.com/javase/6/docs/api/javax/imageio/ImageIO.html

http://kickjava.com/src/imageinfo/ImageInfo.java.htm

I remember having some performance problems with native java libraries while getting image sizes and hence having to use ImageInfo.

Hope this helps.

Sands
Can you speak to the image quality after resize? How many formats do these support (gif, png, jpg)? Does this do the upload and generate only once instead of generate every time an image is requested?
Josh
@Josh, We used these libraries long time ago, however AFAIR the image quality was good after resize. But that statement is true only if you are basing your "viewing" on a browser. If you want to render these images to different devices, then you may need to do a detailed investigation.These are just libraries that you can use and hence the calls for conversion will be in your code and hence it is upto you to decide.
Sands
Thanks for sharing your experience :)
Josh
A: 

From a related source in the Swing tutorial:

/**
 * Resizes an image using a Graphics2D object backed by a BufferedImage.
 * @param srcImg - source image to scale
 * @param w - desired width
 * @param h - desired height
 * @return - the new resized image
 */
private Image getScaledImage(Image srcImg, int w, int h){
    BufferedImage resizedImg = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
    Graphics2D g2 = resizedImg.createGraphics();
    g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
    g2.drawImage(srcImg, 0, 0, w, h, null);
    g2.dispose();
    return resizedImg;
}
Eli Acherkan
What about trying to keep the aspect ratio?
Ascalonian
A: 

Utility function from from one of our java portal page (coded from example from several forum, I do not claim to be the author)

Hope this help
Guillaume PATRY

/**
 * Convenience method that returns a scaled instance of the
 * provided {@code BufferedImage}.
 *
 * @param img the original image to be scaled
 * @param targetWidth the desired width of the scaled instance,
 *    in pixels
 * @param targetHeight the desired height of the scaled instance,
 *    in pixels
 * @param hint one of the rendering hints that corresponds to
 *    {@code RenderingHints.KEY_INTERPOLATION} (e.g.
 *    {@code RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR},
 *    {@code RenderingHints.VALUE_INTERPOLATION_BILINEAR},
 *    {@code RenderingHints.VALUE_INTERPOLATION_BICUBIC})
 * @param higherQuality if true, this method will use a multi-step
 *    scaling technique that provides higher quality than the usual
 *    one-step technique (only useful in downscaling cases, where
 *    {@code targetWidth} or {@code targetHeight} is
 *    smaller than the original dimensions, and generally only when
 *    the {@code BILINEAR} hint is specified)
 * @return a scaled version of the original {@code BufferedImage}
 */
 public BufferedImage getScaledInstance(
            BufferedImage img,
            int targetWidth,
            int targetHeight,
            Object hint,
            boolean higherQuality) {
BufferedImage ret = (BufferedImage) img;
int w, h;
if (higherQuality) {
    // Use multi-step technique: start with original size, then
    // scale down in multiple passes with drawImage()
    // until the target size is reached
    w = img.getWidth();
    h = img.getHeight();
} else {  
    // Use one-step technique: scale directly from original
    // size to target size with a single drawImage() call
    w = targetWidth;
    h = targetHeight;
}

do {
   if (higherQuality) {
      if (w > targetWidth) {
         w /= 2;
         if (w < targetWidth) {
            w = targetWidth;
         }
      } else {
         w = targetWidth;
      }
      if (h > targetHeight) {
         h /= 2;
         if (h < targetHeight) {
        h = targetHeight;
         }
      } else {
         h = targetHeight;
      }
   }
   BufferedImage tmp = null;
   if (img.getType() == 0) {
      tmp = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
   } else {
      tmp = new BufferedImage(w, h, img.getType());
   }
   Graphics2D g2 = tmp.createGraphics();
   g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, hint);
   g2.drawImage(ret, 0, 0, w, h, null);
   g2.dispose();
   ret = tmp;
} while (w != targetWidth || h != targetHeight);
return ret;

}

PATRY