在iText中使用OpenType字体构建PDF文档时,我想从字体中访问字形变体 - 特别是表格图。由于OpenType字形变体没有Unicode索引,我不知道如何指定我想使用一组特定的变体(表格图)或通过其字形ID调用特定的字形。只需查找相关的iText类名称即可。
答案 0 :(得分:8)
在最新的标记5.5.8和iText的master分支中似乎都不可能。
正如this article和Microsoft OpenType font file specification中所述,字形变体存储在字体文件的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
可以反转此映射以获取基础glyphId
的所有变体。因此,所有具有未知unicode值的扩展字形都可以通过它们与基本字形或一系列字形的连接来计算出来。
接下来,为了能够将字形写入PDF,我们需要知道glyphId
的unicode值。关系unicode -> glyphId
由cmap31
中的TrueTypeFont
字段映射。反转地图可以通过glyphId获得unicode。
<强>扭捏强>
rawLigatureSubstitutionMap
无法在GlyphSubstitutionTableReader
中访问,因为它是private
成员,并且没有getter访问者。最简单的方法是复制粘贴原始类并为地图添加一个getter:
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
,它在创建字体时依赖于硬编码的类名。