JDK-6574349 : BILINEAR and BICUBIC interpolation broken for scales less than 1
  • Type: Bug
  • Component: client-libs
  • Sub-Component: 2d
  • Affected Version: 5.0
  • Priority: P4
  • Status: Closed
  • Resolution: Not an Issue
  • OS: windows_xp
  • CPU: x86
  • Submitted: 2007-06-27
  • Updated: 2010-04-02
  • Resolved: 2007-06-27
Related Reports
Relates :  
Description
FULL PRODUCT VERSION :
java version "1.5.0_09"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0_09-b03)
Java HotSpot(TM) Client VM (build 1.5.0_09-b03, mixed mode, sharing)


ADDITIONAL OS VERSION INFORMATION :
Microsoft Windows XP [Version 5.1.2600]

A DESCRIPTION OF THE PROBLEM :
BILINEAR and BICUBIC interpolation seems to be broken when downsampling images (for example when producing thumbnails).   Scales slightly less than one produce more-or-less acceptable results, but the results get progressively worse as the scale reduces.  At scales of around 0.333 the image is visually identical to nearest neighbour interpolation.

My interest is in downsampling at the moment.  I have not experimented to see whether there are situations when scaling up produces unacceptable results.


STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
In the attached code sample, try adjusting the value of the 'scale' variable.  Suggested values are:

0.66666
0.5
0.33333

Compare the resulting image files.  The quality of the image degrades significantly as the scale decreases.


EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
Bilinear and bicubic interpolation should work for all scales - iIncluding those less than 1.
ACTUAL -
Results degrade markedly as the scale reduces.

REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
      BufferedImage duke = ImageIO.read(new File(args[0]));
      int w = duke.getWidth(null);
      int h = duke.getHeight(null);
      double  scale = 0.6666666;
      BufferedImage nearest = new BufferedImage((int)(w*scale), (int)(h*scale), BufferedImage.TYPE_INT_RGB);
      BufferedImage bilinear = new BufferedImage((int)(w*scale), (int)(h*scale), BufferedImage.TYPE_INT_RGB);
      BufferedImage bicubic = new BufferedImage((int)(w*scale), (int)(h*scale), BufferedImage.TYPE_INT_RGB);

      Graphics2D bg = nearest.createGraphics();
      bg.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR);
      bg.scale(scale, scale);
      bg.drawImage(duke, 0, 0, null);
      bg.dispose();
      ImageIO.write(nearest, "png", new File("nearest_"+scale+".png"));

      bg = bilinear.createGraphics();
      bg.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
      bg.scale(scale, scale);
      bg.drawImage(duke, 0, 0, null);
      bg.dispose();
      ImageIO.write(bilinear, "png", new File("bilinear_"+scale+".png"));

      bg = bicubic.createGraphics();
      bg.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);
      bg.scale(scale, scale);
      bg.drawImage(duke, 0, 0, null);
      bg.dispose();
      ImageIO.write(bicubic, "png", new File("bicubic_"+scale+".png"));


---------- END SOURCE ----------

CUSTOMER SUBMITTED WORKAROUND :
No known workaround other than using alternative code for downsampling images.

Comments
EVALUATION Generally speaking, if you downscale by a factor of more than two, the quality of a BILINEAR or BICUBIC scaling operation will begin to approximate that of NEAREST_NEIGHBOR. But it is incorrect to say that BILINEAR and BICUBIC are broken for scales less than 1. For factors above 0.5, there is a visible difference between the three aforementioned algorithms. Less than 0.5, yes, quality may deteriorate, but that is the nature of those particular scaling algorithms. When downscaling by more than a factor of two with BILINEAR or BICUBIC, we recommend using a multi-step technique, which will preserve quality much more gracefully. This technique is described in more detail in the following article: http://today.java.net/pub/a/today/2007/04/03/perils-of-image-getscaledinstance.html The above article comprehensively discusses image scaling concepts and techniques in Java 2D, so I'd recommend reading that to better understand the various issues involved. Part of the problem is that the relevant APIs for image scaling aren't documented as nicely as possible, and we are intending to fix that under 6196792. Also, clearly there needs to be more convenient methods for doing high-quality (and high-performance) image scaling, and that is something we are also investigating. Closing as "not a defect".
27-06-2007