java - 如何使用从 TTF 文件中提取的字距调整对在 Java 中将字形正确显示为 Path2D?

标签 java truetype glyph kerning java-font

这个问题是关于在 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 库返回的字距调整位移的长度进行翻译,但结果很糟糕。 字体大小 是标准的 1000,如该讨论中所建议的那样,interchar 的结果是 75。所有这些似乎都是正确的,但我的手动字距调整对看起来比使用字距调整要好得多来自 TTF 文件的对。

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

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

最佳答案

问题解决了!

回想起打开文件并获得字距调整需要这段代码,使用库 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,这是该特定字体的 unitsPerEm。该值由字体文件中的 HEAD 标签给出,如说明 here .

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

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

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

Text with correct kerning and correct character widths

关于java - 如何使用从 TTF 文件中提取的字距调整对在 Java 中将字形正确显示为 Path2D?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64761064/

相关文章:

java - Hibernate with H2 不存储数据

android - 我可以检查 Unicode 代码点是否可以在 Android 下显示吗?

c++ - 使用 appendBezierPathWithGlyphs 获取字形轮廓的问题

CSS 内容特殊字符 : Hex vs normal character

java - 如何将一堆线性布局转换为一个相对布局

Java swing - 可滚动 GridLayout 中的项目不可见

java - MongoDB - 分组依据 - 聚合 - java

java - 注册字体正在损坏 .TTF 文件

fonts - fontforge - 合并字体以添加字形的脚本

PHP:创建边缘光滑的圆、图像或字体?