How can I draw an image in java with sub pixel accuracy?
I found similar questions here:
Drawing an image using sub-pixel level accuracy using Graphics2D
Unfortunately the solutions provided within the answers does not work for me.
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g2.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
g2.translate(50.5, 50.5);
g2.fillRect(0, 0, 15, 25);
}
Using g2.translate(50.5, 50.5);
to fill a simple rectangale with sub pixel accuracy works nicely.
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g2.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
g2.translate(50.5, 50.5);
g2.drawImage(image, 0, 0, null);
}
However when I use g2.translate(double x, double y)
to draw an image with sub pixel accuracy, it doesn't work. It's exactly the same result as drawing with integer positions.
Why is this not working? I translated the graphics with double values, yet I'm not seeing any interpolation between pixels.
This might be OS or Java version dependent, but for me*, using TexturePaint
(which I consider somewhat of a hack) works:
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g2.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
g2.translate(50.5, 50.5);
// g2.drawImage(image, 0, 0, null); // Original code
g2.setPaint(new TexturePaint(image, new Rectangle(image.getWidth(), image.getHeight())));
g2.fillRect(0, 0, image.getWidth(), image.getHeight());
// Added orange rect for reference, as the difference is hard to spot...
g2.setPaint(Color.ORANGE);
g2.fillRect(0, 0, 15, 25);
}
*) on MacOS 10.15, tested with both Java 8 and 11.
You might need to zoom in to see the difference, as it is kind of subtle... But in the first image (drawImage
), you'll see the orange rect does not overlap perfectly, and the edges of the image are solid. In the second image (TexturePaint
and fillRect
) you'll see the edges of the image is translucent, and the orange rect overlaps perfectly.
Here's the same application running on my MacBooks internal "retina" screen: