【问题标题】:Graphics2D text - font size change causes shift on X axisGraphics2D 文本 - 字体大小更改导致 X 轴偏移
【发布时间】:2016-03-16 16:24:56
【问题描述】:

在将文本** 写入 Graphics2D 对象时,我发现当我更改字体大小时,文本的 x 位置会发生变化。随着大小的增加,x 位置增加。无论我使用什么方法编写文本都会发生这种情况:drawStringfilldrawGlyphVectordrawGlyphVector

** 文本的开头字符和字体类型都会改变这种行为:无衬线字体,其中开头字符的最左侧笔划是垂直线(P、H、L、E 等...)是受影响最大的。如果字体是 Serif 和/或起始字符的最左侧笔划不是垂直的(W、y、Y、T、X 等...),则会减少或消除这种行为。

下面是一个说明这种行为的示例程序:

import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.font.FontRenderContext;
import java.awt.font.GlyphVector;
import java.awt.image.BufferedImage;

import java.io.File;
import java.io.IOException;

import javax.imageio.ImageIO;

public class FontSizeTest {
    public FontSizeTest() {
        super();
    }

    public static void main(String[] args) throws IOException {
        int width = 700, height = 120;

        BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        Graphics2D g2d = image.createGraphics();

        g2d.setColor(Color.WHITE);
        g2d.fillRect(0, 0, width, height);

        FontRenderContext frc = g2d.getFontRenderContext();
        Font font = new Font(Font.SANS_SERIF, Font.PLAIN, 10);
        GlyphVector gv;
        Rectangle pixelBounds;

        g2d.setColor(Color.BLACK);
        g2d.translate(10, 100);

        for(float size : new float[]{40f, 80f, 120f}) {
            font = font.deriveFont(size);
            gv = font.createGlyphVector(frc, "Hello World");
            pixelBounds = gv.getPixelBounds(frc, 0, 0);
            System.out.printf("font: %s%npixel bounds: %s%n", font, pixelBounds);
            g2d.fill(gv.getOutline());
            g2d.draw(pixelBounds);
        }

        g2d.dispose();

        File pngFile = new File("FontSizeTest.png");
        ImageIO.write(image, "png", pngFile);
        System.out.printf("png file written: %s%n", pngFile.getCanonicalPath());
    }
}

这个程序的输出是控制台的信息:

font: java.awt.Font[family=SansSerif,name=SansSerif,style=plain,size=40]
pixel bounds: java.awt.Rectangle[x=4,y=-31,width=217,height=31]
font: java.awt.Font[family=SansSerif,name=SansSerif,style=plain,size=80]
pixel bounds: java.awt.Rectangle[x=7,y=-62,width=432,height=63]
font: java.awt.Font[family=SansSerif,name=SansSerif,style=plain,size=120]
pixel bounds: java.awt.Rectangle[x=11,y=-93,width=651,height=94]
png file written: FontSizeTest.png

还有图片:

注意较大的字体大小是如何从较小的字体大小偏移的。

如果这是预期行为,我可以通过获取像素边界的偏移量并使用 translate 调整 x 坐标来进行调整;我只是不确定这是预期的行为。我觉得我做错了什么 - 错过了 Graphics2D 编程方法的一部分。

【问题讨论】:

  • 你试过不同的字体吗?字符可能有一个“前导”空格
  • @MadProgrammer 我浏览了系统上的所有字体,随着尺寸的增加,它们都有一定程度的偏移。你可以看到我在这里使用的代码的 sn-p:Pastie URL。我怀疑此时偏移量是内置的,我只需要调整布局来处理它。

标签: java fonts bufferedimage graphics2d


【解决方案1】:

此效果是字体的正常行为。甚至 Microsoft Word 在不同大小的文本行中也有这种偏移。
如果您想将所有文本行对齐在同一像素行,您可以使用 translate 与您提到的计算的像素边界。
一种更优雅的方法是在 GlyphVector 中移动您的字形位置。这也会导致getPixelBounds 结果发生变化。

public static void adjust(GlyphVector gv){
    // calc the adjust Factor
    int adjust = (int)Math.round(gv.getGlyphVisualBounds(0).getBounds2D().getMinX());
    // Shift all the Glyphs in Vector
    for (int i = 0; i < gv.getNumGlyphs(); i++) {
        Point2D point = gv.getGlyphPosition(i);
        gv.setGlyphPosition( i, new Point2D.Double(
            point.getX() - adjust, 
            point.getY()));         
    }
}

在您创建字形向量后在您的代码中使用它并获得您想要的结果。

gv = font.createGlyphVector(frc, "Hello World");
adjust(gv);

【讨论】:

  • 优秀的答案,@ArcticLord。我已经得出结论,这是预期的行为,但是您从 Word 中获得的确凿证据是有帮助的,您的建议 + 调整字形位置而不是使用 translate 的示例确实符合我的审美意识。 :-)
【解决方案2】:

This page 可能不会直接回答您的问题。但它有很多关于 Graphics2D 的例子。

【讨论】:

  • 因此,应该是评论,除非您想扩展相关内容,否则如果链接失效,答案不会变得不那么无关紧要。来自help centre - “鼓励链接到外部资源,但请在链接周围添加上下文,以便您的其他用户了解它是什么以及为什么存在。始终引用重要链接中最相关的部分,以防目标站点无法访问或永久脱机。”
  • 嗯,有很多例子。谢谢@Ryan;我已经查看了很多,但没有看到对我的特殊情况有任何帮助,但我还没有全部看完(有 109 个“字体”实例)。 :-)
猜你喜欢
  • 2021-04-25
  • 1970-01-01
  • 2014-03-09
  • 1970-01-01
  • 2022-09-28
  • 2012-10-29
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多