首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何使用从TTF文件中提取的kerning对在Java中正确地将象形文字显示为Path2D?

如何使用从TTF文件中提取的kerning对在Java中正确地将象形文字显示为Path2D?
EN

Stack Overflow用户
提问于 2020-11-10 00:14:43
回答 2查看 452关注 0票数 3

这个问题是关于在Java中恢复字形字体信息的,它与问题贴在这里。有关,更多细节请查看问题和答案。

有人建议使用Apache FOP库直接从Truetype文件中恢复kerning对,因为Java没有提供这些信息。然后,我将库移植到Windows,并使用以下代码恢复了kerning对:

代码语言:javascript
复制
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中检索到的符号,使用下面的函数和后面显示的代码片段:

代码语言:javascript
复制
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();
    } 
}

字形长度被检索到阵列透镜中。

代码语言:javascript
复制
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;
}

为了清楚起见,我使用fill (从Graphics2D )显示符号,并使用上面添加到Apache库返回的kerning位移的长度进行翻译,但结果非常糟糕。正如讨论中所建议的,字体大小是标准的1000,interchar的结果是75。所有这些看起来都是正确的,但是我的手动kerning对看起来比使用TTF文件中的kerning对要好得多。

有谁在这个库或Truetype字体中有知识能够告诉我们应该如何使用这些kerning对?

是否有必要直接从TTF文件访问这些字体,而不是使用上面所示的Java字体管理?如果是,how?

EN

回答 2

Stack Overflow用户

发布于 2020-11-11 07:48:58

问题解决了!

回顾一下,要打开文件并获取kerning对,您需要使用库Apache FOP来编写以下代码

代码语言:javascript
复制
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();

下面将符号向量化的代码现在是正确的:

代码语言:javascript
复制
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,这是这个特定字体的unitsPerEm。此值由字体文件中的HEAD标记提供,如解释的这里所示。

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

这个映射是这样使用的:kerning.get(prev),它返回另一个包含要添加的字符和kerning值的映射。如果在此映射中找到了接下来显示的字符,则相应的值将添加到width中。如果找不到,或者如果返回null,则这对数据不存在核值。

在这里,它是一个文本,以显示克尔宁现在的工作。

票数 1
EN

Stack Overflow用户

发布于 2020-11-10 21:31:26

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

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

这为直接从字体文件读取和显示象形文字提供了一种独立的方法。有趣的是,它不使用任何kerning信息。这必须与Apache FOP库一起添加。如果两次读取该文件是一个问题,您需要一个解决办法,要么深入GNU获取相同的信息,要么让Apache与GNU Classpath“交谈”。现在我说不出这有多难。我只是把它作为复制信息的工具,而不是在实际程序中真正读取字体文件的方法。字体非常紧凑,但并不是显示文本的最有效方法,特别是在字体语言解释的情况下,如Type 1和Truetype字体。如果你愿意高质量、高速度的话,摆脱这种解释似乎是个好主意。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/64761064

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档