在 iText 中访问 OpenType 字形变体
在 iText 中使用 OpenType 字体构建 PDF 文档时,我想从字体中访问字形变体 -- 特别是表格图形。由于OpenType字形变体没有Unicode索引,我不确定如何指定我要使用一组特定的变体(表格图形)或通过其字形ID调用特定的字形。只需查找相关的iText类名(如果存在)。
在 iText 中使用 OpenType 字体构建 PDF 文档时,我想从字体中访问字形变体 -- 特别是表格图形。由于OpenType字形变体没有Unicode索引,我不确定如何指定我要使用一组特定的变体(表格图形)或通过其字形ID调用特定的字形。只需查找相关的iText类名(如果存在)。
这似乎是不可能的,无论是在最新的标签5.5.8中,还是在iText的主分支中。
如本文和 Microsoft 的 OpenType 字体文件规范中所述,字形变体存储在字体文件中。访问字形变体需要从文件中读取此表,该文件实际上是在 类 中实现的,尽管该类目前已被禁用。Glyph Substitution Table (GSUB)
com.itextpdf.text.pdf.fonts.otf.GlyphSubstitutionTableReader
类中的调用被注释掉。readGsubTable()
com.itextpdf.text.pdf.TrueTypeFontUnicode
void process(byte ttfAfm[], boolean preload) throws DocumentException, IOException {
super.process(ttfAfm, preload);
//readGsubTable();
}
事实证明,此行被禁用是有原因的,因为如果您尝试激活它,代码实际上不起作用。
因此,不幸的是,没有办法使用字形变体,因为替换信息永远不会从字体文件中加载。
更新
最初的答案是关于用于访问开箱即用的字形变体的可能性,这还没有。但是,低级代码已经到位,可以在一些黑客攻击后使用来访问字形替换映射表。iText API
当调用 时,将读取表并将所有要素的替换平展到一个映射中。要素的符号名称当前由 丢弃。将变体映射到基数,或将连字映射到如下序列:read()
GlyphSubstitutionTableReader
GSUB
Map<Integer, List<Integer>> rawLigatureSubstitutionMap
OpenTypeFontTableReader
rawLigatureSubstitutionMap
glyphId
glyphId
glyphId
glyphIds
629 -> 66 // a.feature -> a
715 -> 71, 71, 77 // ffl ligature
可以反转此映射以获取基数的所有变体。因此,所有具有未知 unicode 值的扩展字形都可以通过它们与基本字形或字形序列的连接来计算出来。glyphId
接下来,为了能够将字形编写为PDF,我们需要知道该的unicode值。关系由 中的字段映射。反转映射会通过 glyphId 给出 unicode。glyphId
unicode -> glyphId
cmap31
TrueTypeFont
调整
rawLigatureSubstitutionMap
无法在 中访问,因为它是成员并且没有 getter 访问器。最简单的技巧是复制粘贴原始类并为地图添加一个 getter:GlyphSubstitutionTableReader
private
public class HackedGlyphSubstitutionTableReader extends OpenTypeFontTableReader {
// copy-pasted code ...
public Map<Integer, List<Integer>> getRawSubstitutionMap() {
return rawLigatureSubstitutionMap;
}
}
下一个问题是需要一个偏移量的表,即存储在类中的信息。放入同一包中的帮助程序类将桥接对 的受保护成员的访问。GlyphSubstitutionTableReader
GSUB
protected HashMap<String, int[]> tables
TrueTypeFont
TrueTypeFont
package com.itextpdf.text.pdf;
import com.itextpdf.text.pdf.fonts.otf.FontReadingException;
import java.io.IOException;
import java.util.List;
import java.util.Map;
public class GsubHelper {
private Map<Integer, List<Integer>> rawSubstitutionMap;
public GsubHelper(TrueTypeFont font) {
// get tables offsets from the font instance
Map<String, int[]> tables = font.tables;
if (tables.get("GSUB") != null) {
HackedGlyphSubstitutionTableReader gsubReader;
try {
gsubReader = new HackedGlyphSubstitutionTableReader(
font.rf, tables.get("GSUB")[0], glyphToCharacterMap, font.glyphWidthsByIndex);
gsubReader.read();
} catch (IOException | FontReadingException e) {
throw new IllegalStateException(e.getMessage());
}
rawSubstitutionMap = gsubReader.getRawSubstitutionMap();
}
}
/** Returns a glyphId substitution map
*/
public Map<Integer, List<Integer>> getRawSubstitutionMap() {
return rawSubstitutionMap;
}
}
扩展会更好,但这不适用于 的工厂方法,因为在创建字体时依赖于硬编码的类名。TrueTypeFont
createFont()
BaseFont