Why does this image look so bad after being scaled down in Java?
He开发者_JS百科re is the original image: http://rank.my/public/images/uploaded/orig-4193395691714613396.png
And here it is scaled down to 300x225:
http://rank.my/public/images/uploaded/norm-4193395691714613396.png
And here it is scaled down to 150x112:
http://rank.my/public/images/uploaded/small-4193395691714613396.png
As you can see, 300x225 looks pretty bad, and 150x112 looks awful. Here is the code I'm using to scale down the image:
private static BufferedImage createResizedCopy(final BufferedImage source, final int destWidth,
final int destHeight) {
final BufferedImage resized = new BufferedImage(destWidth, destHeight, source.getType());
final Graphics2D bg = resized.createGraphics();
bg.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
bg.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
bg.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
final float sx = (float) destWidth / source.getWidth();
final float sy = (float) destHeight / source.getHeight();
bg.scale(sx, sy);
bg.drawImage(source, 0, 0, null);
bg.dispose();
return resized;
}
What am I doing wrong here? The image scaling doesn't have to be especially fast, quality is definitely a priority over speed. Am I using the wrong technique?
There are three ways to fix the downscaling problem. First is to do it in multiple steps, with no more than a 75% reduction in each step. The second is to blur the image before resizing; the more it shrinks, the more you'll have to blur. The third way is to use a method that filters using more than the 2x2 to 4x4 pixel blocks used by a naive bilinear or bicubic interpolation method. As the shrink factor grows larger, so should the pixel block used by the filter, otherwise you get aliasing artifacts as you've seen here.
I've never used these libraries so I feel unqualified to answer, but I can't help but pass along these links I found that I think may be useful. Hopefully this will help.
http://today.java.net/pub/a/today/2007/04/03/perils-of-image-getscaledinstance.html
http://www.componenthouse.com/article-20
JAI is pretty frustrating. I still wonder why, no matter what settings you do, it never matches the speed, quality and simplicity of ImageMagick. I prefer to use ImageMagick wherever I can.
The code below is what gives me best result for image scaling. Please note that I have used RenderingHints.VALUE_RENDER_QUALITY
and SubsampleAverage
and not RenderingHints.VALUE_INTERPOLATION_BICUBIC
.
I have wrapped up JAI processing in a small block and always use it to scale down. The same code does not give good result when you scale-up -- a different setting applies for that. I have not tried with PNG, JPEG is what I worked with.
Hope this helps
//Set-up and load file
PlanarImage image = JAI.create("fileload", absPath);
RenderingHints quality = new RenderingHints(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
Properties p = new Properties(System.getProperties());
p.put("com.sun.media.jai.disableMediaLib", "true");
System.setProperties(p);
//Setup the processes
ParameterBlock pb = new ParameterBlock()
.addSource(image)
.add(scaleX) //scaleX = (double)1.0*finalX/origX
.add(scaleY); //scaleY = (double)1.0*finalY/origY
RenderedOp tempProcessingFile = JAI.create("SubsampleAverage", pb, quality);
//Save the file
FileOutputStream fout = new FileOutputStream(file);
JPEGEncodeParam encodeParam = new JPEGEncodeParam();
encodeParam.setQuality(0.92f); //My experience is anything below 0.92f gives bad result
ImageEncoder encoder = ImageCodec.createImageEncoder("JPEG", fout, encodeParam);
encoder.encode(tempProcessingFile.getAsBufferedImage());
Also, the articles that helped me are.
- https://jaistuff.dev.java.net/docs/jaitutorial.pdf
- http://today.java.net/pub/a/today/2007/04/03/perils-of-image-getscaledinstance.html
http://forums.sun.com/thread.jspa?threadID=5332078Looks like after Oracle acquisition they have washed away the forum posts. This was an extra-ordinary discussion over JAI performance and quality. I still had it bookmarked.- http://www.digitalsanctuary.com/tech-blog/java/how-to-resize-uploaded-images-using-java-better-way.html
(The links above are from my bookmark, edit them if you find they are dead)
精彩评论