【问题标题】:How to use kerning pairs extracted from a TTF file to correctly show glyphs as Path2D in Java?如何使用从 TTF 文件中提取的字距调整对正确地将字形显示为 Java 中的 Path2D?
【发布时间】:2021-02-21 22:17:14
【问题描述】:

这个问题是关于在Java中恢复字形字体信息,它与question posted here.有关。更多详细信息请查看问题和答案。

建议使用Apache FOP 库直接从 Truetype 文件中恢复字距调整对,因为 Java 不提供此信息。然后我将库移植到 Windows 并使用以下代码恢复字距调整:

TTFFile file;
File ttf = new File("C:\\Windows\\Fonts\\calibri.ttf" );
try { file = TTFFile.open(ttf); }
catch (IOException e) {e.printStackTrace(); }
Map<Integer, Map<Integer, Integer>> kerning = file.getKerning();

最后,库工作,但字距调整返回不工作与使用函数在 Path2D.Float 中检索到的字形下面和之后显示的代码片段:

void vectorize(Path2D.Float path, String s) {
    PathIterator pIter;
    FontRenderContext frc = new FontRenderContext(null,true,true);
    GlyphVector gv;
    Shape glyph;
    gv = font.createGlyphVector(frc, s);
    glyph = gv.getGlyphOutline(0);
    pIter = glyph.getPathIterator(null);
    while (!pIter.isDone()) {
        switch(pIter.currentSegment(points)) {
        case PathIterator.SEG_MOVETO:
            path.moveTo(points[0], points[1]);
            break;
        case PathIterator.SEG_LINETO :
            path.lineTo(points[0], points[1]);
            break;
        case PathIterator.SEG_QUADTO :
            path.quadTo(points[0], points[1], points[2], points[3]);
            break;
        case PathIterator.SEG_CUBICTO :
            path.curveTo(points[0], points[1], points[2], points[3], points[4], points[5]);
            break;
        case PathIterator.SEG_CLOSE :
            path.closePath();
        }
        pIter.next();
    } 
}

字形长度被检索到数组lens中:

Font font = new Font("Calibri", Font.PLAIN, 1000);
double interchar = 1000. * 0.075;
int size = '}' - ' ' + 1;
Path2D.Float[] glyphs = new Path2D.Float[size];
double[] lens = new double[size];
String chars[] = new String[size];
int i; char c; 
char[] s = { '0' };
for (i = 0, c = ' '; c <= '}'; c++, i++) { s[0] = c; chars[i] = new String(s); }
for (i = 0; i < size; i++) {
    vectorize(glyphs[i] = new Path2D.Float(), chars[i]); // function shown above
    lens[i] = glyphs[i].getBounds2D().getWidth() + interchar;
}

为了清楚起见,我使用 Graphics2D 中的 fill 显示字形,并按照建议使用上面添加到 Apache FOP 库返回的字距偏移的长度进行翻译,但结果很糟糕。 font size 是标准的 1000,正如该讨论中所建议的那样,interchar 结果为 75。所有这些似乎都是正确的,但我的手动字距调整对看起来比使用字距调整好得多TTF 文件中的对。

有没有人了解这个库或 Truetype 字体能够告诉我们应该如何使用这些字距调整对?

是否有必要直接从 TTF 文件访问字形,而不是使用 Java 字体管理,如上所示?如果是,怎么做?

【问题讨论】:

    标签: java truetype glyph kerning java-font


    【解决方案1】:

    问题解决了!

    回想一下,要打开文件并获取字距调整对,需要此代码,使用库Apache FOP

    TTFFile file;
    File ttf = new File("C:\\Windows\\Fonts\\calibri.ttf" );
    try { file = TTFFile.open(ttf); }
    catch (IOException e) {e.printStackTrace(); }
    Map<Integer, Map<Integer, Integer>> kerning = file.getKerning();
    

    以下用于矢量化字形的代码现在是正确的:

    Font font = new Font("Calibri", Font.PLAIN, 2048);
    int size = '}' - ' ' + 1;
    Path2D.Float[] glyphs = new Path2D.Float[size];
    //double[] lens = new double[size];
    String chars[] = new String[size];
    int i; char c; 
    char[] s = { '0' };
    for (i = 0, c = ' '; c <= '}'; c++, i++) { s[0] = c; chars[i] = new String(s); }
    for (i = 0; i < size; i++) {
        vectorize(glyphs[i] = new Path2D.Float(), chars[i]);
        //lens[i] = glyphs[i].getBounds2D().getWidth();
    }
    

    请注意,现在字体大小为 2048,这是该特定字体的单位数。该值由字体文件中的 HEAD 标记给出,如 here 所述。

    请注意,数组lens 不能给出宽度,上面注释掉的代码。它必须从文件中读取。使用来自Apache FOPint width = getCharWidthRaw(prev),其中prev 是前一个字符,width 是写入文件中的字符的原始宽度。该值必须添加到可以在映射kerning 中获得的字距调整对值中。

    地图以这种方式使用:kerning.get(prev),它返回另一个地图,其中包含要添加的字符和字距调整值。如果在此映射中找到下一个要显示的字符,则将相应的值添加到width。如果未找到,或者如果返回 null,则该对没有字距调整值。

    这是一个显示字距调整现在有效的文本。

    【讨论】:

      【解决方案2】:

      GNU Classpath 包含一个示例,gnu.classpath.examples.awt.HintingDemo.java,它可能有助于解决这个问题。此示例允许您可视化字形。它读取字体并解释语言以获取其中给出的提示。您可以选择显示或不显示提示(提示字形适用于小字体,但不推荐用于大字体)。如果您不习惯 Truetype 提示,您将通过此演示了解它们在整数边界内对齐路径。该程序不是很花哨,但它具有读取字形和解释提示的所有必要工具,并具有可视化结果的优势。

      你不需要整个包来编译和运行这个演示。如果您使用的是 Eclipse,很容易为它创建一个项目。首先创建包 gnu.classpath.examples.awt 并在其中导入 HintingDemo.java。然后,您只需一次导入其所有依赖项,一个文件一个文件或整个包。例如,您可以导入整个包 gnu.java.awt.font 并擦除 OpenTypeFontPeer.java (演示不需要它,如果您使用它会导致错误离开它)。

      这提供了一种直接从字体文件读取和显示字形的独立方式。有趣的是,它不使用任何字距调整信息。这必须与Apache FOP 库一起添加。如果两次读取文件是一个问题,您将需要一个解决方法,或者深入 GNU Classpath 以获取相同的信息,或者尝试使 Apache FOP “与 GNU Classpath 对话”。目前我无法说这是多么困难。我只是将它用作复制信息并在其他地方使用的工具,而不是在实际程序中真正读取字体文件的一种方式。字体非常紧凑,但不是显示文本的最有效方式,尤其是在需要对字体语言进行解释的情况下,例如 Type 1 和 Truetype 字体。如果您愿意提供高质量和高速度,那么摆脱这种解释似乎是个好主意。

      【讨论】:

        猜你喜欢
        • 2021-02-25
        • 2016-05-02
        • 1970-01-01
        • 2020-04-26
        • 1970-01-01
        • 2011-01-01
        • 2014-06-04
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多