Is there an easy way to resize a BufferedImage, and have it stay a BufferedImage in the end? getScaledInstance() gets me a casting exception. Please help!
There might be an easier way, but this seems to be a fairly common procedure (if only for other reasons):
Create new BufferedImage(scaleoldImage.getWidth(), scaleoldImage.getHeight(), oldImage.getTransparency());
The last argument may probably be left out.
Then create a Graphics2D object with (something along the lines of)
newImage.createGraphics();
Scale the Graphics2D object with graphics2D.scale(scale, scale);
Last, graphics2D.drawImage(oldImage, 0, 0, null);
That should do it, or something very close to it. Also I think it is useful for creating compatible BufferedImages from non-compatible ones such that they may be rendered more efficiently.
I get a NullPointerException in:
Graphics2D g = bi2.createGraphics();
T_T
show more code
public BufferedImage resizeImage(BufferedImage bi, int width, int height)
{
JFrame f = new JFrame();
Image bi_i = bi.getScaledInstance(width, height, bi.SCALE_SMOOTH);
BufferedImage bi2 = (BufferedImage)f.createImage(bi_i.getWidth(f),bi_i.getHeight(f));
Graphics2D g = bi2.createGraphics();
g.drawImage(bi_i, 0, 0, null);
return bi2;
}
Please don’t use getScaledInstance(). It’s an old api, and is very inefficient.
Just create a BufferedImage with the dimensions you wanted, and use Graphics.drawImage(Image img, int x, int y, int width, int height, ImageObserver observer) call to scale the image, much in the same way Ask_Hjorth_Larsen has suggested.
BufferedImage scaledBI = new BufferedImage(scaledWidth, scaledHeight, BufferedImage.TYPE_INT_RGB);
Graphics2D g = (Graphics2D)scaledBI.getGraphics();
g.setComposite(AlphaComposite.Src); // only needed if your image is non-opaque
g.drawImage(originalImage, 0, 0, scaledWidth, scaledHeight, null);
Note that if your image is non-opaque and you want to preserve the transparency, you’ll need to change the type of the scaled BufferedImage to a format with alpha (TYPE_INT_ARGB, for example).
Thanks,
Dmitri
Java2D Team
It works! Thanks a zillion ^_______^
BTW, you can control the quality of filtering used when doing scaling with
Graphics2D.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
RenderingHints.VALUE_INTERPOLATION_[NEAREST_NEIGHBOR/BILINEAR/BICUBIC]);
Set the hint before issuing the drawImage() call.
Depending on whether you’re scaling up or down, you may want to use different hints.
Thanks,
Dmitri
[quote]Please don’t use getScaledInstance(). It’s an old api, and is very inefficient.
[/quote]
So why don’t you fix it? You just provided an example of faster code.
just make me wonder too, same for pixelgrabber which is unuseable when using the OGL-Pipeline. why isn’t it simply emulated by using bufferedimages in background…
Its so slow that some 1.1 software becoms even unuseable in todays modern hardware…
image->bufferedimage->getWholeContent->emulate the Pixelgrabber…
however that’s out of scope…
lg
This is something we’d like to do. It’s already on our radar:
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6196792
Part of the reason we haven’t done this already is that getScaledInstance() uses a slightly different filtering algorithm for AreaAveragingScaleFilter than say, our typical BILINEAR or BICUBIC algorithms. And some people find that different way more visually appealing than the latter two. It’s just a matter of finding a solution that will please both sides.
Thanks,
Chris
[quote]just make me wonder too, same for pixelgrabber which is unuseable when using the OGL-Pipeline. why isn’t it simply emulated by using bufferedimages in background…
Its so slow that some 1.1 software becoms even unuseable in todays modern hardware…
image->bufferedimage->getWholeContent->emulate the Pixelgrabber…
however that’s out of scope…
lg
[/quote]
Yeah, without taking this too off topic, this issue should be fixed in Mustang due to the fact that createImage() now returns a regular managed image, not some funky variant:
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6240664
Let me know if that’s not the case.
Chris
[quote]Part of the reason we haven’t done this already is that getScaledInstance() uses a slightly different filtering algorithm for AreaAveragingScaleFilter than say, our typical BILINEAR or BICUBIC algorithms. And some people find that different way more visually appealing than the latter two. It’s just a matter of finding a solution that will please both sides.
[/quote]
Is there an issue with simply adding a new filtering hint to go alongside BILINEAR and BICUBIC that matches the algorithm used by getScaledInstance?
Then implement getScaledInstance using the code above combined with that hint.
It’s interesting that enough people are so concerned that it look exactly the same that you would choose to keep the slow code. It’s not the sort of thing that you would expect to critical to anyone - given that the API makes no statement about how it will do the scaling when you ask for DEFAULT, FAST or SMOOTH.
You also clearly state that “the image object is free to substitute a different filter that performs the same algorithm yet integrates more efficiently into the image infrastructure supplied by the toolkit.”
I guess “same algorithm” kinda ties your hands a bit more than you would like… given that the whole statement seems designed to give you this opportunity for optimization.
Totally.
I use getScaledInstance() in Easy Decal because I tried all the other options (that are standard in J2SE) and they just weren’t acceptable. Maybe something to do with the fact that I’m working with pretty small images.
[quote]Please don’t use getScaledInstance(). It’s an old api, and is very inefficient.
Just create a BufferedImage with the dimensions you wanted, and use Graphics.drawImage(Image img, int x, int y, int width, int height, ImageObserver observer) call to scale the image, much in the same way Ask_Hjorth_Larsen has suggested.
[/quote]
So I changed some (non-game) code that I had that was using getScaledInstance, since getScaledInstance was PATHOLOGICALLY slow.
The result - still pathologically slow.
By that I mean it took MINUTES to scale my image.
In the debugger I could see it was stuck in ICC_… and CMM… stuff, basically converting color spaces or something with all sorts of float arrays and such.
Calls to things like getting the number of components would take 30 seconds or so.
Exactly the same thing has happened with getScaledInstance and the drawImage method.
Something is severely wrong with the image sizing code in the JRE.
I am scaling a JPEG image from a digital camera (2048 x 1536) loaded with ImageIO to 720 x 480. That operation takes MINUTES to complete.
HELP!
btw, I’m using anti-aliasing and bicubic interpolation.
Hey Scott,
This is a known issue with the IIO JPEGImageReader:
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4705399
The bug report includes a couple possible workarounds (the one by “mrsteve” looks okay too). But obviously this isn’t ideal; we’d like to see this fixed as a number of people are running into it these days (due to digital cameras inserting non-sRGB color profiles into images).
Thanks,
Chris
Thanks Chris!
I should be able to work around the issue with the info in that bug report.