java - Graphics2D - 在所有平台上呈现相同的文本

标签 java awt graphics2d antialiasing drawstring

是否可以在所有具有相同字体的 Java 平台上使用 Graphics2D.drawString 呈现逐像素相同的结果?我尝试在不使用抗锯齿的情况下渲染文本,但结果在不同的机器上有所不同。我使用项目资源中的字体,因此字体与系统无关。

在两台不同 PC 上使用相同字体的相同代码的结果示例:

Result of same code with same font on different PCs

为了清晰起见,我使用了非常小的字体(9 px)。

import java.awt.Color;
import java.awt.Font;
import java.awt.FontFormatException;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.net.URL;

import javax.imageio.ImageIO;

public class Test {
    public static void main(String... args) throws FontFormatException, IOException {
        int x = 0;
        int y = 9;
        int width = 80;
        int height = 10;
        float fontSizeInPixels = 9f;
        String text = "PseudoText";

        BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        Graphics2D graphics = image.createGraphics();
        graphics.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
        graphics.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_OFF);

        URL fontUrl = new URL(
                "https://github.com/indvd00m/graphics2d-drawstring-test/blob/master/src/test/resources/fonts/DejaVuSansMono/DejaVuSansMono.ttf?raw=true");
        Font font = Font.createFont(Font.TRUETYPE_FONT, fontUrl.openStream());
        font = font.deriveFont(fontSizeInPixels);

        Color fontColor = Color.BLACK;
        Color backgroundColor = Color.WHITE;

        graphics.setFont(font);
        graphics.setColor(backgroundColor);
        graphics.fillRect(0, 0, width, height);
        graphics.setColor(fontColor);
        graphics.drawString(text, x, y);

        ImageIO.write(image, "png", new File("/tmp/test.png"));
    }
}

我在这里创建了用于测试的项目:

https://github.com/indvd00m/graphics2d-drawstring-test

此项目构建失败:

https://travis-ci.org/indvd00m/graphics2d-drawstring-test/builds/178672466

在linux上的openjdk6和openjdk7下测试通过,但在linux和其他操作系统和java版本的oraclejdk7和oraclejdk8下测试失败。

最佳答案

渲染文本极其复杂(不断发展的 Opentype 和 Unicode 规范、尝试在像素太少的屏幕上适应小符号、解决字体错误等)。

它非常复杂,主要依赖于系统,每个主要操作系统仅剩一个渲染引擎。这些引擎不断发展,试图解决问题、支持硬件更改和新的规范修订。它们不会根据系统和操作系统版本给出相同的结果。有时,像 Oracle JDK 这样的应用程序会通过包含自己的渲染例程来增加一层复杂性(对于旧版兼容,Open JDK 直接使用系统渲染并在现代 *nix 系统上提供更好的结果)。

您可以尝试通过以非常高的像素尺寸进行渲染来消除一些差异。这将消除所有低 dpi 网格拟合黑魔法差异,并渲染接近理想的高质量纸张打印。然而,当缩小到实际屏幕像素时,文本将很难阅读。

与此同时,对于文本像素放置在何处以及如何放置以提高阅读质量的不同解释是不争的事实。您最好不要尝试编写任何其他假设的代码。人们将赢得文本堆栈,这是一个非常 Darwin 的过程,剩下的少数文本渲染引擎是幸存者。

关于java - Graphics2D - 在所有平台上呈现相同的文本,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40745529/

相关文章:

java - 什么是本地对等体?

java - 重绘导致 mouseListener 注册未发生的点击

java - 渲染旋转图像

java - 如何使用Java生成20个唯一且有顺序的随机数?

java - 类是否扩展了另一个的注释?

java - 三角形绘制方法

java - 传递给 Paint() 调用的顶级组件是什么?

java - 如何在坐标很少的情况下使用 AffineTransform?

java - 在Java中删除字符串中的重复字符

Java - KeyListener 多个按钮按下