views:

68

answers:

6

hey there,

I have a question regarding picture scaling. I have an application where users are able to upload pictures in albums but naturally the uploaded images need to be resized so there are also thumbs available and the shown pictures also fit in the page (eg. 800x600). The way I do the resize is like this:

        Image scaledImage = img.getScaledInstance((int)width, (int)height, Image.SCALE_SMOOTH);
        BufferedImage imageBuff = new BufferedImage((int)width, (int)height, BufferedImage.TYPE_INT_RGB);
        Graphics g = imageBuff.createGraphics();
        g.drawImage(scaledImage, 0, 0, new Color(0,0,0), null);
        g.dispose();

And it works okayish. My only problem is that the g.drawImage() method seems to be awfully slow, and I just cannot imagine the user to be patient enought to wait for an upload of 20 pictures 20*10 secs ~ 3 minutes. In fact, on my computer it takes almost 40 secs for making the 3 different resizes for a single picture.

That's not good enough, and I'm looking for a faster solution. I'm wondering if somebody could tell me about a better one in Java OR by calling a shell script, command, whatever hack you know, it has to be quicker, everything else does not matter this time.

Thanks for any helpful reply in advance!

Cheers, balazs

+2  A: 

You can use ImageMagick to create thumbnails.

convert -define jpeg:size=500x180  hatching_orig.jpg  -auto-orient \
        -thumbnail 250x90   -unsharp 0x.5  thumbnail.gif

To use it from Java you can try JMagick which provides a Java (JNI) interface to ImageMagick. Or you can simply invoke the ImageMagick commands directly using Runtime.exec or ProcessBuilder.

dogbane
thanks for the answer, I will go for this.
Balázs Mária Németh
A: 

You will ever have a trade off between the speed of the resizing and the quality of the resulting picture. You might try another scaling algorithm of the JDK.

The best and most flexible tool for image editing AFAIK is ImageMagick.

There are two interfaces for the Java Language:

You should prefer im4java before using the command line directly to call ImageMagick.

echox
+1  A: 

Do you really need the quality that is provided by using Image.SCALE_SMOOTH? If you don't, you can try using Image.SCALE_FAST. You might find this article helpful if you want to stick with something provided by Java.

Klarth
SCALE_FAST does not give enough quality unfortunately, but thanks for the article, that looks very useful, im gonna give it a try.
Balázs Mária Németh
A: 

If you want something fast, you're probably better with some native code, if you can give up on portability.

But if you want a pure Java solution, you can try some other solutions as well, like Graphics2D.scale and Image.getScaledInstance. I've used them in the past, but can't remember which had better performance or better looking results, sorry.

Try them out, and see which one best fits your needs.

mdrg
A: 

I'm using code similar to the following to scale images, I removed the part that deals with preserving the aspect ratio. The performance was definitely better than 10s per image, but I don't remember any exact numbers. To archive better quality when downscaling you should scale in several steps if the original image is more than twice the size of the wanted thumbnail, each step should scale the previous image to about half its size.

public static BufferedImage getScaledImage(BufferedImage image, int width, int height) throws IOException {
    int imageWidth  = image.getWidth();
    int imageHeight = image.getHeight();

    double scaleX = (double)width/imageWidth;
    double scaleY = (double)height/imageHeight;

    AffineTransformOp bilinearScaleOp = new AffineTransformOp(scaleTransform, AffineTransformOp.TYPE_BILINEAR);

    return bilinearScaleOp.filter(
        image,
        new BufferedImage(width, height, image.getType()));
}
Jörn Horstmann
A: 

Some improvement in performance (perhaps small, perhaps negligible, perhaps at the expense of quality) can be attained by tweaking the rendering hints. E.g.

    g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, 
               RenderingHints.VALUE_INTERPOLATION_BILINEAR);
leonbloy