【问题标题】:How to read kerning pairs table from TTF file in Android如何从 Android 中的 TTF 文件中读取字距调整对表
【发布时间】:2016-05-02 19:33:51
【问题描述】:

我目前正在使用从 TTF 文件加载的外部(非标准)字体在 Canvas 上绘制文本。我想为正在显示的文本启用字距调整。

我想知道的是是否有可能使用 Android API 从字体中读取字距调整对。

【问题讨论】:

  • This older question (但最近的答案是去年)表明紧缩表没有暴露在 Java 中。 “手动”解析原始文件数据是一个可行的选择吗? (注意有几种不同的表格格式,都同样糟糕......)
  • 谢谢,Jongware。我不介意解析 *.ttf 文件,提供一些关于在哪里寻找字距对的信息(我通常有点害怕糟糕的格式)。
  • 这将在OpenType specifications 中,确切地说在The Kerning Table 中。绝对不适合胆小的人;如果您真的不走运,那么您使用的字体是 Type 1 类型,因此您需要解析 GPOS 子表,这要困难得多......(这可能这就是 Canvas 的程序员 drawText 根本不打扰的原因......)
  • 谢谢。有空的时候我会试试这个。
  • 没有 Android API 可以获取字距调整表或解析 TTF 文件。但是,我已经瘦身并移植了apache fop,它应该能够完成你想要的。我找不到有字距调整的 TTF。请您使用字距调整链接到字体吗?

标签: android fonts truetype android-fonts


【解决方案1】:

我想知道的是是否有可能使用 Android API 从字体中读取字距调整对。

没有公共 API 可以从 TTF 文件中读取字距调整对。但是,我从Apache FOP 中提取了相关代码,您可以使用this library 读取字距调整对。

使用示例:

TTFFile file = TTFFile.open(getAssets().open("fonts/font.ttf"));
Map<Integer, Map<Integer, Integer>> kerning = file.getKerning();

您还可以检索其他元数据。示例:

TTFFile ttfFile = TTFFile.open(new File("/system/fonts/Roboto-Regular.ttf"));

String name = ttfFile.getFullName();             // "Roboto Regular"
String family = ttfFile.getSubFamilyName();      // "Regular"
int fontWeight = ttfFile.getWeightClass();       // 400
String copyright = ttfFile.getCopyrightNotice(); // "Font data copyright Google 2014"

我想为正在显示的文本启用字距调整。

参见:

How to adjust text kerning in Android TextView?

setLetterSpacing(float)

【讨论】:

  • 谢谢,我会试一试并回复您。至于setSpacing() 方法,它并不完全相同,因为间距设置为字符串的所有字符,而字距仅针对特定字符对进行调整。
  • 你试过图书馆了吗?如果需要/需要,我可以将其上传到 Maven。我花了几个小时在上面,希望这段时间对你的项目有用:-)
  • 那么...第一个映射的关键是对中第一个字符的代码?所以kerning.get(firstChar) 应该返回与firstChar 成对关联的所有字符的映射。因此kerning.get(firstChar).get(secondChar) 应该返回由firstCharsecondChar 组成的对的偏移量。正确的?实际值是什么意思?例如,-40。这是我应该将第二个字符移动的宽度百分比(如果是负数 - 向左移动)?请解释一下。
  • 是的,如此出色的库应该能够通过 Maven/Gradle 轻松分发(或至少作为预构建的 JAR 文件)。
  • 有点自己想通了。如果我们从字距调整表中取值乘以字体大小(或文本大小),然后除以 1000,我们得到第二个字符应该从第一个字符移开的实际距离(对于负值 - 移向第一个字符)。
【解决方案2】:

我愿意在 Windows 上使用标准 Java 使用 the parser described above。如果有人想这样做,则需要使用 Rectangle 而不是 Rect。这只是一个小的转换。我还删除了目录 jaredrummler,因为它有点太长了(不过,我将版权 cmets 保留在文件的开头)。但是这个解析器中有两个 TTFFile 类。这段代码:

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();

仅当您导入正确的类文件时才有效:

import com.fontreader.truetype.TTFFile;

最后,代码有效,但返回的字距调整对不起作用与您使用转换的路径:

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在以下代码中恢复的长度:

double interchar = fontsize * 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], tx[i], 0f);
    lens[i] = glyphs[i].getBounds2D().getWidth() + interchar;
}

为了清楚起见,我在 Graphics2D 中使用 fill 显示字形,并使用上面添加到库 Apache FOP 返回的字距偏移的长度进行翻译,但结果很糟糕. fontsize 是本讨论中建议的标准 1000,而 interchar 乘以字体大小后得到 75。这一切似乎都是正确的,但我的手动字距调整对看起来比使用 ttf 文件中的字距调整对要好得多。

有没有人受过这个库的培训,能够告诉我们应该如何使用这些字距调整对?

很抱歉稍微偏离了最初的问题,但这可能会完成信息,因为一旦阅读了字距调整对,如何在 Windows 或 Android 上正确使用它们?

【讨论】:

  • 欢迎来到 Stack Overflow。这是帮助填写此线程的有用贡献。由于 Stack Overflow 不是一个传统的讨论板,而是一个问答网站,请尝试将任何后续问题与您的答案分开。如果这是一个小问题,您可以将其作为评论添加到您的答案下。但是,如果这是您真正想深入研究的内容,我建议您提出一个新问题,然后链接回该线程以获取更多详细信息。这也有助于确保审稿人不会将您的贡献误认为(只是)一个问题。
  • 我的帖子帮助用户转换适用于 Windows 的 Apache FOP。有两个小问题要做。首先是将 Rect 转换为 Rectangle。第二点是有两个TTFFile类,比较混乱。我指出正确的一个。该帖子还显示了一个代码片段,用于使用 Windows 上的库从 TTF 文件中提取字距调整对。文章的第二部分展示了如何直接从 Java 获取字形,但信息与字距调整对不匹配。这似乎是 Java 字体管理中的一个已知问题。它将作为问题发布。
猜你喜欢
  • 1970-01-01
  • 2021-02-21
  • 1970-01-01
  • 2020-04-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-10-25
  • 1970-01-01
相关资源
最近更新 更多