Name: jk109818 Date: 09/03/2003
FULL PRODUCT VERSION :
Java(TM) 2 Runtime Environment, Standard Edition (build 1.4.2-b28)
Java HotSpot(TM) Client VM (build 1.4.2-b28, mixed mode)
FULL OS VERSION :
Microsoft Windows 2000 [Versione 5.00.2195]
A DESCRIPTION OF THE PROBLEM :
I discovered that drawing an image in a Graphics2D context (both on-screen and from a bufferedimage) with a translation-only AffineTransform at non-integer coordinates does not interpolate the drawing as expected.
Note that the relevant Hints have been set in the context:
g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Create a graphics2d context;
Set best quality hints;
Set a translation-only transform at non-integer coordinates (i.e. 0.7,0.5)
Draw an image with drawImage(img,x,y,null);
Suggestion: better compile/run the sample source.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
The image should be interpolated, but it is not.
ACTUAL -
The image is not interpolated. It is plotted at is was at integer coordinates.
REPRODUCIBILITY :
This bug can be reproduced always.
---------- BEGIN SOURCE ----------
package test.bug;
import java.awt.*;
import java.awt.geom.*;
import java.awt.image.*;
public class TransImageBug extends Panel implements java.awt.event.MouseMotionListener
{
// storage
private static BufferedImage bi = new BufferedImage(60, 50, BufferedImage.TYPE_INT_ARGB);
private float px = 0, py = 0;
// create some test gfx
static
{
Graphics2D g2 = (Graphics2D) bi.getGraphics();
g2.setColor(Color.white);
g2.fillRect(0, 0, bi.getWidth() - 1, bi.getHeight() - 1);
g2.setColor(Color.black);
g2.fillRect(1, 1, bi.getWidth() - 3, bi.getHeight() - 3);
g2.setColor(Color.white);
g2.fillRect(5, 5, bi.getWidth() - 11, bi.getHeight() - 11);
g2.setColor(Color.black);
g2.drawString("CIAO!", 20, 30);
}
// paint on raster
BufferedImage raster = new BufferedImage(600, 400, BufferedImage.TYPE_INT_ARGB);
public TransImageBug()
{
super();
setBackground(Color.gray);
}
public static void main(String args[])
{
System.out.println("Starting test");
TransImageBug canvas = new TransImageBug();
Frame frame = new Frame();
frame.setSize(640, 480);
canvas.addMouseMotionListener(canvas);
frame.add("Center", canvas);
frame.requestFocus();
frame.setEnabled(true);
frame.show();
}
//
public void mouseDragged(java.awt.event.MouseEvent e)
{
}
//
public void mouseMoved(java.awt.event.MouseEvent e)
{
px = e.getX() / 10f;
py = e.getY() / 10f;
repaint();
}
//
public void paint(Graphics g)
{
// get graphics from the raster
Graphics2D g2d = (Graphics2D) raster.getGraphics();
// set hints
g2d.setColor(Color.gray);
g2d.fillRect(0, 0, raster.getWidth(), raster.getHeight());
g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
// draw
AffineTransform at = new AffineTransform();
g2d.setTransform(at);
g2d.setColor(Color.white);
g2d.drawString("drawing at (" + px + "," + py + ")", 10, 10);
// this code blits the image bi at px,py
// the image is blitted at float coords but it is not interpolated as expected !
at = AffineTransform.getTranslateInstance(px, py + 50);
g2d.setTransform(at);
g2d.drawImage(bi, 0, 0, null);
// this code blits the image bi at px,py, but with a do-nothing shear transform
// the image is blitted at float coords an now it is interpolated..
at = AffineTransform.getTranslateInstance(px + 65, py + 50);
at.shear(.0000001, .0000001); // <- workaround
g2d.setTransform(at);
g2d.drawImage(bi, 0, 0, null);
// paint raster on canvas
g.drawImage(raster, 0, 0, null);
}
// avoid flickering, please
public void update(Graphics g)
{
paint(g);
}
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
There's one, very simple:
Concatenate a do-noting shear transform to the original transform:
at.shear(.0000001, .0000001);
Now the drawImage interpolates correctly.
It should be a really simple problem in the image drawing code of Java2D. Just add a test to see if the current transform transates to non-integer coords and do the interpolation. I'm sure you do the same with shear, scale, etc. so that you can save some time by simply blitting pixels without interpolating (saving time).
I'm sure it's a 5 min. fix for you !
(Incident Review ID: 201505)
======================================================================