Image scaling problem
Hello,
I have been trying to scale an image to create a thumbnail. The thumbnail image size is around 200*200. The thumbnail is to be rendered on a web browser. My code is:
publicstaticbyte[] getScaledImage(InputStream imageData)throws IOException{
Image origImg = ImageIO.read(imageData);
int origImgHeight = origImg.getHeight(null);
int origImgWidth = origImg.getWidth(null);
int newImgHeight/*determined by custom logic*/;
int newImgWidth/*determined by custom logic*/;
/* code for determining newImgHeight and newImgWidth keeping the aspect ratio */
origImg = origImg.getScaledInstance(newImgWidth, newImgHeight,
Image.SCALE_AREA_AVERAGING);
BufferedImage bimage =null;
bimage =new BufferedImage(origImg.getWidth(null), origImg.getHeight(null),
BufferedImage.TYPE_INT_RGB);
Graphics g = bimage.createGraphics();
g.drawImage(origImg, 0, 0,null);
g.dispose();
ByteArrayOutputStream os =new ByteArrayOutputStream(10);
ImageIO.write(bimage,"jpg", os);
return os.toByteArray();
}
The calling method is:
FileCopyUtils.copy(ImageUtils.getScaledImage(lobHandler.getBlobAsBinaryStream(rs, 1)),
imageContent);
here imageContent is the http response's outputstream.
Now the problem is the resulting image displayed on the web page becomes distorted. I first thought that this is due to the thumbnail size. But the scaling done by gimp does not distort the image.
I have also tried this:
BufferedImage thumbImage =new BufferedImage(newImgWidth, newImgHeight, BufferedImage.TYPE_INT_RGB);
Graphics2D graphics2D = thumbImage.createGraphics();
graphics2D.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
graphics2D.drawImage(origImg, 0, 0, newImgWidth, newImgHeight,null);
instead of using getScaled instance.
What could be the problem? This is a problem I need to solve immediately. So I am at a loss. Please help me here.
# 1
Try scaling your source image like this:
import java.awt.*;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.io.*;
import javax.imageio.ImageIO;
import javax.swing.*;
public class ScalingToSize {
int W = 200;
int H = 200;
int SCALE_TO_FIT = 0;
int SCALE_TO_FILL = 1;
private JPanel getContent(BufferedImage image) {
JPanel panel = new JPanel(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.insets = new Insets(5,5,5,5);
gbc.weightx = 1.0;
panel.add(wrap(image), gbc);
panel.add(wrap(scale(image, SCALE_TO_FIT)), gbc);
panel.add(wrap(scale(image, SCALE_TO_FILL)), gbc);
return panel;
}
private BufferedImage scale(BufferedImage src, int style) {
int type = BufferedImage.TYPE_INT_RGB;
BufferedImage dest = new BufferedImage(W, H, type);
Graphics2D g2 = dest.createGraphics();
if(style == SCALE_TO_FIT) {
g2.setBackground(UIManager.getColor("Panel.background"));
g2.clearRect(0,0,W,H);
}
double scale = getScale(src, style);
double x = (W - scale*src.getWidth())/2;
double y = (H - scale*src.getHeight())/2;
AffineTransform at = AffineTransform.getTranslateInstance(x, y);
at.scale(scale, scale);
g2.drawRenderedImage(src, at);
g2.dispose();
return dest;
}
private double getScale(BufferedImage image, int style) {
double xScale = (double)W/image.getWidth();
double yScale = (double)H/image.getHeight();
return (style == SCALE_TO_FIT) ? Math.min(xScale, yScale)
: Math.max(xScale, yScale);
}
private JLabel wrap(BufferedImage image) {
ImageIcon icon = new ImageIcon(image);
return new JLabel(icon, JLabel.CENTER);
}
public static void main(String[] args) throws IOException {
String path = "images/cougar.jpg";
BufferedImage image = ImageIO.read(new File(path));
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.getContentPane().add(new ScalingToSize().getContent(image));
f.pack();
f.setVisible(true);
}
}
# 2
I have changed the code from this:
BufferedImage bimage = null;
bimage = new BufferedImage(origImg.getWidth(null), origImg.getHeight(null),
BufferedImage.TYPE_INT_RGB);
Graphics g = bimage.createGraphics();
g.drawImage(origImg, 0, 0, null);
g.dispose();
ByteArrayOutputStream os = new ByteArrayOutputStream(10);
ImageIO.write(bimage, "jpg", os);
return os.toByteArray();
to this:
BufferedImage bimage = new BufferedImage(newImgWidth, newImgHeight, BufferedImage.TYPE_INT_RGB);
Graphics2D graphics2D = bimage.createGraphics();
graphics2D.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
RenderingHints.VALUE_INTERPOLATION_BILINEAR);
graphics2D.drawImage(origImg, 0, 0, newImgWidth, newImgHeight, null);
// save thumbnail image to outstream
ByteArrayOutputStream os = new ByteArrayOutputStream(10);
JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(os);
JPEGEncodeParam param = encoder.getDefaultJPEGEncodeParam(bimage);
param.setQuality(1.0f, false);
encoder.setJPEGEncodeParam(param);
encoder.encode(bimage);
return os.toByteArray();
Surprisingly there is a slight improvement in quality. This is very strange because every body is recommending to use ImageIo.write() instead of JPEGEncoder. Besides, if the encoding can take parameters to customize the qualty then why is ImageIO.write() not accepting any parameteres for quality? Is it assuming some default value and can this be adjusted?
A point to remember the output is an http response outputstream.