Java AWT中的字体大于100点时无法正确呈现

f5emj3cl  于 2023-05-12  发布在  Java
关注(0)|答案(1)|浏览(102)

我正在尝试使用JAVA AWT将文本渲染为图像。当我使用小于100点的字体时,一切都按预期工作。但是当我使用240个点时,文本的一些重叠部分是透明的,就像这个image。在示例图像中,我使用了这个font。我在文本编辑器中使用了这种字体,没有任何问题。
使用以下代码加载字体:

Font font = Font.createFont(Font.TRUETYPE_FONT, new File("src/main/resources/Autumn in November.ttf"));
Font derived = font.deriveFont(240f);

要渲染图像中的文本,我使用以下代码:

public static void saveTextToImage(String text, Font font) throws IOException {

        # Temp image to get the text dimensions
        BufferedImage tempImage = new BufferedImage(1, 1, BufferedImage.TYPE_INT_RGB);
        Graphics2D tempGraphics = tempImage.createGraphics();
        tempGraphics.setFont(font);
        FontMetrics fontMetrics = tempGraphics.getFontMetrics();
        FontRenderContext fontRenderContext = tempGraphics.getFontRenderContext();
        GlyphVector gv = font.createGlyphVector(fontRenderContext, text);
        Area area = new Area(gv.getOutline());
        Rectangle2D rectangle2D = area.getBounds2D();
        int width = (int) rectangle2D.getWidth();
        int height = (int) rectangle2D.getHeight();

        // Create a new image with white background
        BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        Graphics2D graphics = img.createGraphics();
        graphics.setColor(Color.WHITE);
        graphics.fillRect(0, 0, width, height);

        graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

        // Draw the text on the image
        graphics.setColor(Color.BLACK);
        graphics.setFont(font);
        graphics.drawString(text, 10, fontMetrics.getAscent() + 5);

        // Save the image
        File outputFile = new File(text + ".jpg");
        ImageIO.write(img, "jpg", outputFile);
}

我试过将字体类型更改为OTF,添加和更改RenderingHints,并将图像类型切换为PNG,但没有成功。我不知道我还能尝试什么。

toiithl6

toiithl61#

这的确是一种奇怪的行为。我不能告诉你为什么会发生这种情况,但我可以提供一个解决方法;逐个呈现字符串的字形时不会出现问题:

static final boolean USE_WORKAROUND = true;

public static void saveTextToImage(String text, Font font) throws IOException {
    // Temp image to get the GlyphVector and text dimensions
    BufferedImage tempImage = new BufferedImage(1, 1, BufferedImage.TYPE_INT_RGB);
    Graphics2D tempGraphics = tempImage.createGraphics();
    tempGraphics.setFont(font);
    tempGraphics.setRenderingHint(
        RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
    FontRenderContext fontRenderContext = tempGraphics.getFontRenderContext();
    GlyphVector gv = font.createGlyphVector(fontRenderContext, text);
    Rectangle2D rectangle2D = gv.getVisualBounds();
    int width = (int)(rectangle2D.getWidth());
    int height = (int)(rectangle2D.getHeight());

    // Create a new image with white background
    BufferedImage img
        = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
    Graphics2D graphics = img.createGraphics();
    graphics.setBackground(Color.WHITE);
    graphics.clearRect(0, 0, width, height);
    graphics.setRenderingHint(
        RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
    graphics.setColor(Color.BLACK);

    // using GlyphVector avoids repeating the work already done above
    if(!USE_WORKAROUND) {
        graphics.drawGlyphVector(gv,
            (float)-rectangle2D.getX(), (float)-rectangle2D.getY());
    } else {
        graphics.translate(-rectangle2D.getX(), -rectangle2D.getY());
        for(int gix = 0, gnum = gv.getNumGlyphs(); gix < gnum; gix++) {
            graphics.fill(gv.getGlyphOutline(gix));
        }
    }

    // Save the image
    File outputFile = new File(text + ".jpg");
    ImageIO.write(img, "jpg", outputFile);
}

作为一个侧记,我会使用PNG而不是JPG,因为它更适合这样的图像,但也许你没有这个选择。
进一步注意,通过drawGlyphVector渲染现有的GlyphVector已经被证明是“将一组字符渲染到屏幕上的最快方法”,所以如果我们无论如何都要执行这个准备工作来计算边界,为什么不使用它来渲染呢?

相关问题