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

时间:2016-11-22 15:18:37

标签: java awt graphics2d antialiasing drawstring

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

两台不同PC上具有相同字体的相同代码的结果示例:

Result of same code with same font on different PCs

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

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下失败。

2 个答案:

答案 0 :(得分:2)

渲染文本非常复杂(不断发展的Opentype和Unicode规范,尝试在像素太少的屏幕上放置小符号,解决字体错误等问题。)

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

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

与此同时,对文字像素在何处以及如何提供更好的阅读质量的不同解释是生活中的事实。你最好不要尝试编写任何其他假设的代码。人们会赢得文本堆栈,这是一个非常达尔文的过程,剩下的几个文本渲染引擎都是幸存者。

答案 1 :(得分:1)

好的..不确定这构成了一个'答案'(更多的是一个实验),但这就是我所说的缩放文字以适应空间的意思。请参阅代码中的注释。

enter image description here

$('#save-bank').click(function() {

    if ($('[name="bank"]').prop('checked') == true) {

        var id   = $('[name="bank"]').attr('id');
        var movt = $('[name="bank"]').data('movt');

        alert(id + ' - ' + movt);

    } else {

        alert('You need to select a bank');
    }
});