在Linux上调整子像素坐标时Java 8图形故障

And*_*nko 20 java graphics2d java-8

似乎在Java 8中,在子像素坐标上的划动被打破了.

我有三组案例,屏幕截图显示(列表示案例,行表示不同的笔画宽度):

Java 7u51(400%规模)
Java 7u51的截图(400%比例)
Java 8u60(400%规模)
Java 8u60的截图(400%比例)

  1. 在相同坐标上填充和描边.按预期工作,描边区域大于填充区域.
  2. 抚摸(通过笔划宽度)缩小并且居中(宽度的一半)为填充区域的内边界.这部分在Java 8中用于1px笔划,其中绘制发生在子像素坐标(第一行)上; 3px笔划没有这个问题(第三行).对于1px笔划,似乎0.5被四舍五入.
  3. 填充矩形以与案例2相同的方式收缩.我需要在支持子像素绘制的图形上使用,以便在单元格重叠时进行非重叠填充.在这里你可以看到填充操作向下舍入0.5到0,所以它只是抚摸问题.

代码如下:

import static java.awt.BasicStroke.*;

import java.awt.*;
import java.awt.geom.*;

import javax.swing.*;

public class TestCase
{
    public static void main(String[] args)
    {
        JFrame frame = new JFrame("Test case");
        frame.setSize(115, 115);
        frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);

        frame.getContentPane().add(new TestPanel());

        frame.setVisible(true);
    }

    private static class TestPanel extends JPanel
    {
        TestPanel()
        {
            setOpaque(true);
        }

        @Override
        protected void paintComponent(Graphics g)
        {
            Graphics2D g2 = (Graphics2D) g;
            g2.setColor(Color.white);
            g2.fill(getBounds());

            Rectangle2D rect = new Rectangle2D.Double();
            Color background = new Color(0, 255, 255);
            Color border = new Color(255, 0, 0, 128);
            Stroke STROKE_1PX = new BasicStroke(1, CAP_SQUARE, JOIN_MITER);
            Stroke STROKE_2PX = new BasicStroke(2, CAP_SQUARE, JOIN_MITER);
            Stroke STROKE_3PX = new BasicStroke(3, CAP_SQUARE, JOIN_MITER);
            g2.translate(10, 10);

            /**
             * Filling and stroking by original coordinates
             */
            rect.setRect(0, 0, 25, 25);
            g2.setColor(background);
            g2.fill(rect);
            g2.setColor(border);
            g2.setStroke(STROKE_1PX);
            g2.draw(rect);
            g2.translate(0, 35);
            g2.setColor(background);
            g2.fill(rect);
            g2.setColor(border);
            g2.setStroke(STROKE_2PX);
            g2.draw(rect);
            g2.translate(0, 35);
            g2.setColor(background);
            g2.fill(rect);
            g2.setColor(border);
            g2.setStroke(STROKE_3PX);
            g2.draw(rect);

            /**
             * Stroking is shrunk to be inside the filling rect
             */
            g2.translate(35, -70);
            rect.setRect(0, 0, 25, 25);
            g2.setColor(background);
            g2.fill(rect);
            rect.setRect(0.5, 0.5, 24, 24);
            g2.setColor(border);
            g2.setStroke(STROKE_1PX);
            g2.draw(rect);
            g2.translate(0, 35);
            rect.setRect(0, 0, 25, 25);
            g2.setColor(background);
            g2.fill(rect);
            rect.setRect(1, 1, 23, 23);
            g2.setColor(border);
            g2.setStroke(STROKE_2PX);
            g2.draw(rect);
            g2.translate(0, 35);
            rect.setRect(0, 0, 25, 25);
            g2.setColor(background);
            g2.fill(rect);
            rect.setRect(1.5, 1.5, 22, 22);
            g2.setColor(border);
            g2.setStroke(STROKE_3PX);
            g2.draw(rect);

            /**
             * Filling rect is additionally shrunk and centered
             */
            g2.translate(35, -70);
            rect.setRect(0.5, 0.5, 24, 24);
            g2.setColor(background);
            g2.fill(rect);
            g2.setColor(border);
            g2.setStroke(STROKE_1PX);
            g2.draw(rect);
            g2.translate(0, 35);
            rect.setRect(1, 1, 23, 23);
            g2.setColor(background);
            g2.fill(rect);
            g2.setColor(border);
            g2.setStroke(STROKE_2PX);
            g2.draw(rect);
            g2.translate(0, 35);
            rect.setRect(1.5, 1.5, 22, 22);
            g2.setColor(background);
            g2.fill(rect);
            g2.setColor(border);
            g2.setStroke(STROKE_3PX);
            g2.draw(rect);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

正如我测试的那样,Java 7也没有这个问题(试过7u51),Windows(8u77)和Mac(8u60).在不同的机器上尝试Ubuntu(8u60和8u77)和Linux Mint(8u60),这里有bug.

有人遇到过这样的问题吗?有没有一般的解决方法?

我不能简单地在使用抚摸的地方处理1px的情况.这是因为有很多地方,我正在使用不同的Graphics2D实现,似乎,从我使用的问题再现只有SunGraphics2D.这意味着我需要instanceOf在这些地方使用不破坏常见的逻辑.

And*_*nko 1

来自错误报告讨论:

这是一个 xrender bug -Dsun.java2d.xrender=false 解决它。

我自己没有检查过这个解决方案,因为除了经过审查之外,我没有收到任何来自错误报告系统的通知。由于这是 Linux 独有的问题,我们的客户中 Linux 用户并不多,因此决定等待官方修复。