Question

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

Was it helpful?

Solution

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.

OTHER TIPS

May be you should call:

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

and

g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

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.

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.
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top