Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Quality of Image after resize very low -- Java

Tags:

In the script it is going from around the 300x300 mark down to 60x60. Need to improve the overall image quality as it is coming out very poorly at the moment.

public static Boolean resizeImage(String sourceImg, String destImg, Integer Width, Integer Height, Integer whiteSpaceAmount)  {     BufferedImage origImage;      try      {         origImage = ImageIO.read(new File(sourceImg));         int type = origImage.getType() == 0? BufferedImage.TYPE_INT_ARGB : origImage.getType();         int fHeight = Height;         int fWidth = Width;         int whiteSpace = Height + whiteSpaceAmount; //Formatting all to squares so don't need two whiteSpace calcs..         double aspectRatio;          //Work out the resized dimensions         if (origImage.getHeight() > origImage.getWidth()) //If the pictures height is greater than the width then scale appropriately.         {             fHeight = Height; //Set the height to 60 as it is the biggest side.              aspectRatio = (double)origImage.getWidth() / (double)origImage.getHeight(); //Get the aspect ratio of the picture.             fWidth = (int)Math.round(Width * aspectRatio); //Sets the width as created via the aspect ratio.         }         else if (origImage.getHeight() < origImage.getWidth()) //If the pictures width is greater than the height scale appropriately.         {             fWidth = Width; //Set the height to 60 as it is the biggest side.              aspectRatio = (double)origImage.getHeight() / (double)origImage.getWidth(); //Get the aspect ratio of the picture.             fHeight = (int)Math.round(Height * aspectRatio); //Sets the height as created via the aspect ratio.         }          int extraHeight = whiteSpace - fHeight;         int extraWidth = whiteSpace - fWidth;          BufferedImage resizedImage = new BufferedImage(whiteSpace, whiteSpace, type);         Graphics2D g = resizedImage.createGraphics();         g.setColor(Color.white);         g.fillRect(0, 0, whiteSpace, whiteSpace);          g.setComposite(AlphaComposite.Src);         g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);         g.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);         g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);          g.drawImage(origImage, extraWidth/2, extraHeight/2, fWidth, fHeight, null);         g.dispose();          ImageIO.write(resizedImage, "jpg", new File(destImg));     }      catch (IOException ex)      {         return false;     }      return true; } 

Really just need to know if their is something I can plug in that will bump up the quality or if I need to look at something else entirely.

EDIT: Picture comparison.

Source, just picked a random washing machine from google. http://www.essexappliances.co.uk/images/categories/washing-machine.jpg

Washing Machine

The same picture converted in Photoshop to what I need it to be. http://imgur.com/78B1p

Good resize in Paint shop

What it looks like being converted like this. http://imgur.com/8WlXD

Bad resize

like image 528
dutchman191 Avatar asked Jan 02 '13 01:01

dutchman191


People also ask

Do images lose quality when scaled down?

The most common side effect of scaling an image larger than its original dimensions is that the image may appear to be very fuzzy or pixelated. Scaling images smaller than the original dimensions does not affect quality as much, but can have other side effects.

Why do images lose quality when resized?

Resizing images can be tricky, because when you reduce the size of an image, you are also reducing the number of pixels. The more you reduce the number of pixels, the more you reduce the quality of the image.


1 Answers

Scaling an image down over a large range is inherently dangerous (from the point of view of quality), especially using a single step.

The recommended method is to use a divide and conquer method. Basically, you scale the image down in steps of 50% until you reach your desired size.

So, I took the original image of 650x748 and scaled it down to fit within a 60x60 region (52x60).

enter image description here

Divide and conquer compared to one step...

enter image description hereenter image description here

public class TestImageResize {      public static void main(String[] args) {         new TestImageResize();     }      public TestImageResize() {         EventQueue.invokeLater(new Runnable() {             @Override             public void run() {                 try {                     UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());                 } catch (Exception ex) {                 }                  JFrame frame = new JFrame("Testing");                 frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);                 frame.setLayout(new BorderLayout());                 frame.add(new ScalePane());                 frame.pack();                 frame.setLocationRelativeTo(null);                 frame.setVisible(true);             }         });     }      public class ScalePane extends JPanel {          private BufferedImage original;         private BufferedImage scaled;          public ScalePane() {             try {                 original = ImageIO.read(new File("path/to/master.jpg"));                 scaled = getScaledInstanceToFit(original, new Dimension(60, 60));                 ImageIO.write(scaled, "jpg", new File("scaled.jpg"));                  BufferedImage image = new BufferedImage(52, 60, BufferedImage.TYPE_INT_RGB);                 Graphics2D g2d = image.createGraphics();                 g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);                 g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);                 g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);                 g2d.drawImage(original, 0, 0, 52, 60, this);                 g2d.dispose();                  ImageIO.write(image, "jpg", new File("test.jpg"));              } catch (IOException ex) {                 ex.printStackTrace();             }         }          @Override         public Dimension getPreferredSize() {              Dimension size = super.getPreferredSize();             if (original != null) {                 if (scaled != null) {                     size.width = original.getWidth() + scaled.getWidth();                     size.height = original.getHeight();                 } else {                     size.width = original.getWidth();                     size.height = original.getHeight();                 }             }              return size;         }          @Override         protected void paintComponent(Graphics g) {             super.paintComponent(g);             Graphics2D g2d = (Graphics2D) g.create();             g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);             g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);             g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);              if (original != null) {                 int x = 0;                 int y = (getHeight() - original.getHeight()) / 2;;                 if (scaled != null) {                     x = (getWidth() - (original.getWidth() + scaled.getWidth())) / 2;                 } else {                     x = (getWidth() - original.getWidth()) / 2;                 }                 g2d.drawImage(original, x, y, this);                  if (scaled != null) {                     x += original.getWidth();                     y = (getHeight() - scaled.getHeight()) / 2;                     g2d.drawImage(scaled, x, y, this);                 }             }             g2d.dispose();         }          public BufferedImage getScaledInstanceToFit(BufferedImage img, Dimension size) {             float scaleFactor = getScaleFactorToFit(img, size);             return getScaledInstance(img, scaleFactor);         }          public float getScaleFactorToFit(BufferedImage img, Dimension size) {             float scale = 1f;             if (img != null) {                 int imageWidth = img.getWidth();                 int imageHeight = img.getHeight();                 scale = getScaleFactorToFit(new Dimension(imageWidth, imageHeight), size);             }             return scale;         }          public float getScaleFactorToFit(Dimension original, Dimension toFit) {             float scale = 1f;             if (original != null && toFit != null) {                 float dScaleWidth = getScaleFactor(original.width, toFit.width);                 float dScaleHeight = getScaleFactor(original.height, toFit.height);                 scale = Math.min(dScaleHeight, dScaleWidth);             }             return scale;         }          public float getScaleFactor(int iMasterSize, int iTargetSize) {             float scale = 1;             if (iMasterSize > iTargetSize) {                 scale = (float) iTargetSize / (float) iMasterSize;             } else {                 scale = (float) iTargetSize / (float) iMasterSize;             }             return scale;         }          public BufferedImage getScaledInstance(BufferedImage img, double dScaleFactor) {             BufferedImage imgBuffer = null;             imgBuffer = getScaledInstance(img, dScaleFactor, RenderingHints.VALUE_INTERPOLATION_BILINEAR, true);             return imgBuffer;         }          protected BufferedImage getScaledInstance(BufferedImage img, double dScaleFactor, Object hint, boolean higherQuality) {              int targetWidth = (int) Math.round(img.getWidth() * dScaleFactor);             int targetHeight = (int) Math.round(img.getHeight() * dScaleFactor);              int type = (img.getTransparency() == Transparency.OPAQUE)                             ? BufferedImage.TYPE_INT_RGB : BufferedImage.TYPE_INT_ARGB;              BufferedImage ret = (BufferedImage) img;              if (targetHeight > 0 || targetWidth > 0) {                 int w, h;                 if (higherQuality) {                     w = img.getWidth();                     h = img.getHeight();                 } else {                     w = targetWidth;                     h = targetHeight;                 }                  do {                     if (higherQuality && w > targetWidth) {                         w /= 2;                         if (w < targetWidth) {                             w = targetWidth;                         }                     }                      if (higherQuality && h > targetHeight) {                         h /= 2;                         if (h < targetHeight) {                             h = targetHeight;                         }                     }                      BufferedImage tmp = new BufferedImage(Math.max(w, 1), Math.max(h, 1), type);                     Graphics2D g2 = tmp.createGraphics();                     g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, hint);                     g2.drawImage(ret, 0, 0, w, h, null);                     g2.dispose();                      ret = tmp;                 } while (w != targetWidth || h != targetHeight);             } else {                 ret = new BufferedImage(1, 1, type);             }             return ret;         }     } } 

You may, also, find The Perils of Image.getScaledInstance() of interest.

like image 160
MadProgrammer Avatar answered Sep 20 '22 14:09

MadProgrammer