似乎在 Java 8 中,子像素坐标上的描边功能被破坏了。
我有三组案例,截图显示(列代表案例,行代表不同的笔划宽度):
Java 7u51(400% 规模)
Java 8u60(400% 规模)
- 在同一坐标上填充和描边。按预期工作,描边区域大于填充区域。
- 描边被缩小(按描边宽度)并居中(按宽度的一半)以位于填充区域的边界内。这部分在 Java 8 中被破坏为 1px 笔画,其中绘画发生在子像素坐标(第一行)上; 3px stroke 没有这个问题(第三行)。看来 0.5 是针对 1px 笔划向上取整的。
- 填充矩形以与案例 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);
}
}
}
正如我测试的那样,Java 7 没有这个问题(在 7u51 上试过),Windows (8u77) 和 Mac (8u60) 也没有。在不同机器上的 Ubuntu(8u60 和 8u77)和 Linux Mint(8u60)上尝试过,错误就在这里。
有人遇到过这样的问题吗?有什么通用的解决方法吗?
在使用抚摸的地方,我不能简单地处理 1px 大小写。这是因为有很多地方,我正在使用不同的 Graphics2D
实现,而且从我使用的情况来看,这个问题似乎只在 SunGraphics2D
上重现。这意味着我需要在这些地方使用 instanceOf
以免破坏常见逻辑。
最佳答案
来自 bug report讨论:
It is an xrender bug -Dsun.java2d.xrender=false cures it.
我自己没有检查过这个解决方案,因为我没有收到来自错误报告系统的任何通知,除了它已经过审查。由于这是仅限 Linux 的问题,因此我们决定等待官方修复,因为我们的客户中没有那么多 Linux 用户。
关于在 Linux 上抚摸亚像素坐标时 Java 8 图形故障,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36627711/