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
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:
KEY_ANTIALIASING
KEY_RENDERING
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With