1

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

Sub-pixel Image rendering

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.

Kcits970
  • 640
  • 1
  • 5
  • 23
  • I am not sure which version of Java you use. The signature of `drawImage` should be `drawImage(BufferedImage img, BufferedImageOp op, int x, int y)` afaik. - Correction: Both signatures seem to exist in different versions. What JDK are you using? – TreffnonX Apr 28 '20 at 13:31
  • I'm using Java 13. I tried `drawImage(BufferedImage img, BufferedImageOp op, int x, int y)` as well, but I still do not see any interpolation between pixels. – Kcits970 Apr 28 '20 at 13:38
  • One hack that might work, is set up a `TexturePaint` using your image, and use that to fill a rectangle the same size of your original image (and with the half pixel offset, as in your first code sample). – Harald K Apr 28 '20 at 13:40
  • Sorry, I still don't see any interpolation =( – Kcits970 Apr 28 '20 at 13:44
  • Well, works for me.. Java 8u181 on MacOS. Not sure what kind of interpolation you expect to see though... – Harald K Apr 28 '20 at 13:57
  • I'm running on a Win8 machine, I tried using Java 8 as well, but no luck :V I'm expecting the edges of the image to be slightly transparent, since the position is represented by a double, but it's showing a completely opaque edge. – Kcits970 Apr 28 '20 at 14:07

1 Answers1

3

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.

screenshot of running program

Here's the same application running on my MacBooks internal "retina" screen:

screenshot of running program on high res screen

Harald K
  • 26,314
  • 7
  • 65
  • 111
  • 1
    IT WORKS AAAAAAA Thank you so much, I'm still very unsure of why it didn't work when I initially tried it from your comment, but it's working on both Java 8 and Java 13 now, thanks! – Kcits970 Apr 28 '20 at 14:18