这个问题是关于在Java中恢复字形字体信息的,它与问题贴在这里。有关,更多细节请查看问题和答案。
有人建议使用Apache FOP库直接从Truetype文件中恢复kerning对,因为Java没有提供这些信息。然后,我将库移植到Windows,并使用以下代码恢复了kerning对:
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();
}
}字形长度被检索到阵列透镜中。
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?
发布于 2020-11-11 07:48:58
问题解决了!
回顾一下,要打开文件并获取kerning对,您需要使用库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标记提供,如解释的这里所示。
注意,数组lens和上面注释掉的代码不能给出宽度。必须从文件中读取。使用来自int width = getCharWidthRaw(prev)的Apache FOP,其中prev是前一个字符,width是文件中所写字符的原始宽度。必须将此值添加到映射kerning中可以获得的kerning对值中。
这个映射是这样使用的:kerning.get(prev),它返回另一个包含要添加的字符和kerning值的映射。如果在此映射中找到了接下来显示的字符,则相应的值将添加到width中。如果找不到,或者如果返回null,则这对数据不存在核值。
在这里,它是一个文本,以显示克尔宁现在的工作。

发布于 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字体。如果你愿意高质量、高速度的话,摆脱这种解释似乎是个好主意。
https://stackoverflow.com/questions/64761064
复制相似问题