8

I'm a reasonably experienced Java programmer but relatively new to Java2D. I'm trying to scale an image but I'm getting poor quality results. The image is a preview of a panel so contains things like text and textfields. I'll always be scaling down, never up.

Currently I'm using the following code:-

g.drawImage(panelImage, 0, 0, scaledWidth, scaledHeight, null);

Where panelImage is the full sized preview (BufferedImage) and scaledWidth and scaledHeight are the respective target dimensions. I seem to lose a lot of detail in the text and edges of things like textfields etc.

Is there a better call I should be using to scale the image?

Thanks, John

Johnathan
  • 318
  • 4
  • 8

4 Answers4

11

A suggestion I can make is to first resize the image onto a separate BufferedImage. The reason being, a Graphics2D object of the BufferedImage can be obtained in order to produce a better quality scaled image.

Graphics2D can accept "rendering hints" which instruct the way image processing should be performed by the Graphics2D object. The setRenderingHint method is one of the methods which can be used to set those rendering hints. The rendering hints from the RenderingHints class can be used.

Then, using that Graphics2D object, an image can be drawn to the BufferedImage using the rendering hints specified earlier.

A rough (untested) code would work as the following:

BufferedImage scaledImage = new BufferedImage(
    scaledWidth,
    scaledHeight,
    BufferedImage.TYPE_INT_RGB
);

Graphics2D g = scaledImage.createGraphics();
g.setRenderingHints(
    RenderingHints.Key.KEY_INTERPOLATION,
    RenderingHints.VALUE_INTERPOLATION_BICUBIC
);

g.drawImage(panelImage, 0, 0, scaledWidth, scaledHeight, null);
g.dispose();

Other rendering hints of interest may include:

The Controlling Rendering Quality section of The Java Tutorials also has more information on how to control the rendering quality of Graphics2D objects.

And for a very good source of information on dealing with graphical interfaces in general, Filthy Rich Clients by Chet Haase and Romain Guy is highly recommended. There is one section of the book that deals with the issue of scaling images, which seems quite relevant.

coobird
  • 159,216
  • 35
  • 211
  • 226
  • Thanks, I have a copy of that book and I just dove into it to read the chapter. Should have thought to look there before posting. I completely forgot about rendering hints for scaling. Thanks! John – Johnathan May 31 '09 at 17:38
  • You're welcome :) Pages 98-113 deals with Image Scaling and includes some good examples. Of particular interest to me was the idea of progressive bilinear scaling presented on page 104. – coobird May 31 '09 at 17:43
  • Yeah I saw that but don't think my application really warrants it. BICUBIC or BILINEAR are good enough for me. Time to experiment! – Johnathan May 31 '09 at 18:46
2

May be you should call:

 g.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);

and

g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
Pierre
  • 34,472
  • 31
  • 113
  • 192
1

Coobird is right that you need to incrementally down-scale (preferably using BICUBIC) to get a good-looking result for a small enough thumbnail. Image.getScaledInstance used to do this with the AREA_AVERAGED approach, but it is much slower than the incremental downscale that was original proposed by Chris Campbell in his "Perils of Image.getScaledInstance()" article.

Please excuse the self-promotion here, but I rolled a handful of "native Java best practices" when it comes to image scaling into a library called imgscalr.

It's available under an Apache 2 license and source is all on GitHub; the goal of the library was to make image-scaling in native Java dead-easy (1 class, 5 static methods) and ensure the best looking result (which is what you originally wanted), the fastest result (great when scaling among large images) or a balance between the two and let the library decide which one to use.

I just wanted a lib that could "Resize my image and get out of my way" and after reading all these posts for a few days as I addressed the pain point (my own as well) just was circling back and sharing the work for anyone else it may help.

Riyad Kalla
  • 10,604
  • 7
  • 53
  • 56
  • The original site doesn't reply right now, it seems that the official repository for the lib is here https://github.com/rkalla/imgscalr – Damien B Aug 28 '16 at 16:33
  • Yes you found the right repo - I closed down all the old 'The Buzz Media' stuff (I haven't had time for about 5 years to maintain that) and moved it all into my personal repo space. It's also in default Maven repo. – Riyad Kalla Aug 30 '16 at 12:24
0

Coobird has the correct idea. I would also try RenderingHints.VALUE_INTERPOLATION_BILINEAR interpolation and see if it's nicer looking. Bicubic works better when upscaling, though. For the best results when downscaling, one should downscale in several steps. First halve the resolution, then halve again, etc. until you get near the desired resolution (i.e. you cannot halve or the image will get too small). Final step is to scale down to the desired resolution.

For example, let's say your input image is 800x600 and you want downscale to 160x120:

  1. Downscale 50%. --> 400x300
  2. Downscale 50%. --> 200x150
  3. Downscale to 160x120.
Community
  • 1
  • 1
MH114
  • 975
  • 1
  • 9
  • 13
  • Why would downscaling in several steps be an advantage? Please elaborate :D – Thorbjørn Ravn Andersen May 31 '09 at 19:35
  • Here is something on the topic: http://www.nobel-joergensen.com/roller/java/entry/downscaling_images_in_java Other than that I don't have anything, but in my experience downscaling in steps provides a better end result. Worth trying at least. :) – MH114 May 31 '09 at 20:31
  • 1
    This is the idea behind the "progressive bilinear scaling" -- by performing a bilinear scaling in multiple steps, the information of each pixel is preserved, rather than discarded by performing a single step bilinear rescaling of the image. – coobird Jun 01 '09 at 00:29
  • @coobird: Right, thanks! Good to know the correct name for the technique. – MH114 Jun 01 '09 at 06:52