Image resize quality (Java)

user7094 picture user7094 · Oct 26, 2009 · Viewed 23k times · Source

I have an open-source app which uploads photos to Facebook. To save bandwidth, the photos are automatically resized before uploading (Facebook imposes a maximum size limit). A few people have complained about the photo quality, and in fact you can see the difference (see this issue for some demo images).

So my question is, what is the "best" way of scaling down images (i.e. photos) in Java without losing quality, or at least, with minimal quality loss / artifacts?

You can see the current code I have here (resize code via this page).

Answer

Riyad Kalla picture Riyad Kalla · Jul 5, 2011

Phil, I don't know which solution you eventually went with, but scaling images in Java can look pretty good if you:

  • Avoid BufferedImage types that aren't well supported by the JDK.
  • Use incremental scaling
  • Stick to bicubic when using incremental scaling

I've done a fair share of testing with these methods and the incremental scaling along with sticking to well supported image types is the key -- I see Alexander mentioned he still didn't get good luck with it which is a bummer.

I released the imgscalr library (Apache 2) about 6 months ago to address the issue of "I want good-looking scaled copies of this image, DO IT NOW!" after reading something like 10 questions like this on SO.

Standard usage looks like:

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

The 2nd argument is the bounding width and height imgscalr will use to scale the image -- keeping its proportions correct even if you passed in invalid dimensions -- there are many more detailed methods, but that is the simplest usage.

The use-case you would want, for example if Facebook limited images to 800x600 pixels, would look like this:

BufferedImage img = ImageIO.read(...); // load image
BufferedImage scaledImg = Scalr.resize(img, Method.QUALITY, 800, 600);

That will ensure the image stays in the best supported image type and scaled with the highest quality method that Java can muster.

In my own high-resolution testing I have not noticed any gaping discrepancies with scaled images using this library/these methods EXCEPT when your image gets put into a poorly supported image type by the ImageIO loader -- for example, this happens a lot with GIFs. If you leave them like that and don't get them out of those poorly supported types, it ends up looking really dithered and terrible.

The reason for this is that the Java2D team actually has different hardware accelerated pipelines for all the different types of BufferedImages that the JDK can process - a subset of those image types that are less common all fall back to using the same software rendering pipeline under the covers in Java2D, resulting in poor and sometimes totally incorrect looking images. This was such a PIA to explain and try and figure out that I just wrote that logic directly into the library.

The two best supported types are BufferedImage.TYPE_INT_RGB and _ARGB if you are curious.