Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java2D: scaling issues

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

like image 253
Johnathan Avatar asked May 31 '09 17:05

Johnathan


3 Answers

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.

like image 97
coobird Avatar answered Nov 20 '22 17:11

coobird


May be you should call:

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

and

g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
like image 2
Pierre Avatar answered Nov 20 '22 18:11

Pierre


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.

like image 1
Riyad Kalla Avatar answered Nov 20 '22 18:11

Riyad Kalla