3

I am looking for the simplest (and still non-problematic) way to resize a BufferedImage in Java.

In some answer to a question, the user coobird suggested the following solution, in his words (very slightly changed by me):

**

The Graphics object has a method to draw an Image while also performing a resize operation:

Graphics.drawImage(Image, int, int, int, int, ImageObserver) method can be used to specify the location along with the size of the image when drawing.

So, we could use a piece of code like this:

BufferedImage originalImage = // .. created somehow
BufferedImage newImage = new BufferedImage(SMALL_SIZE, SMALL_SIZE, BufferedImage.TYPE_INT_RGB);

Graphics g = newImage.createGraphics();
g.drawImage(originalImage, 0, 0, SMALL_SIZE, SMALL_SIZE, null);
g.dispose();

This will take originalImage and draw it on the newImage with the width and height of SMALL_SIZE.

**

This solution seems rather simple. I have two questions about it:

  • Will it also work (using the exact same code), if I want to resize an image to a larger size, not only a smaller one?

  • Are there any problems with this solution?

If there is a better way to do this, please suggest it.

Thanks

Aviv Cohn
  • 15,543
  • 25
  • 68
  • 131

2 Answers2

4

The major problem with single step scaling is they don't generally produce quality output, as they focus on taking the original and squeezing into a smaller space, usually by dropping out a lot of pixel information (different algorithms do different things, so I'm generalizing)

Will drawGraphics scale up and down, yes, will it do it efficiently or produce a quality output? These will come down to implementation, generally speaking, most of the scaling algorithms used by default are focused on speed. You can effect these in a little way, but generally, unless you're scaling over a small range, the quality generally suffers (from my experience).

You can take a look at The Perils of Image.getScaledInstance() for more details and discussions on the topic.

Generally, what is generally recommend is to either use a dedicated library, like imgscalr, which, from the ten minutes I've played with it, does a pretty good job or perform a stepped scale.

A stepped scale basically steps the image up or down by the power of 2 until it reaches it's desired size. Remember, scaling up is nothing more then taking a pixel and enlarging it a little, so quality will always be an issue if you scale up to a very large size.

For example...

Remember, any scaling is generally an expensive operation (based on the original and target size of the image), so it is generally best to try and do those operations out side of the paint process and in the background where possible.

There is also the question whether you want to maintain the aspect ratio of the image? Based on you example, the image would be scaled in a square manner (stretched to meet to the requirements of the target size), this is generally not desired. You can pass -1 to either the width or height parameter and the underlying algorithm will maintain the aspect ratio of the original image or you could simply take control and make more determinations over whether you want to fill or fit the image to a target area, for example...

In general, I avoid using drawImage or getScaledInstance most of the time (if your scaling only over a small range or want to do a low quality, fast scale, these can work) and rely more on things like fit/fill a target area and stepped scaling. The reason for using my own methods simply comes down to not always being allowed to use outside libraries. Nice not to have to re-invent the wheel where you can

MadProgrammer
  • 343,457
  • 22
  • 230
  • 366
1

It will enlarge the original if you set the parameters so. But: you should use some smart algorithm which preserves edges because simply enlarging an image will make it blurry and will result in worse perceived quality.

No problems. Theoretically this can even be hardware-accelerated on certain platforms.

vbence
  • 20,084
  • 9
  • 69
  • 118
  • Why should enlarging the image make it blurry? enlarging by 2,2 means making every pixel twice as large, but maintaining the same proportions, correct? If so, than why would it be a problem? Also, isn't there a built-in Java class to handle with this instead of me having to come up with some algorithm to prevent the lose of quality? – Aviv Cohn Feb 26 '14 at 22:10
  • Example: you have an 8px image, 4 black pixels followed by 4 white ones. You enlage it by 2.2: You will end up with 8 black piels, one grey one and 8 white ones. The new pixel between the existing ones will be calculated as a mean of the two existing ones, which will reduce the contrast (edge) between your two regions. - This is not a problem usual language libraries try to solve. – vbence Feb 26 '14 at 22:12
  • @Prog You can check out this question for possible out-of-the-box solutions: http://stackoverflow.com/questions/7951290/resize-image-in-java-lose-quality?rq=1 – vbence Feb 26 '14 at 22:20