在 iText 中访问 OpenType 字形变体
Accessing OpenType glyph variants in iText
在 iText 中使用 OpenType 字体构建 PDF 文档时,我想从字体中访问字形变体——特别是表格图形。由于 OpenType 字形变体没有 Unicode 索引,我不确定如何指定我要使用一组特定的变体(表格数字)或通过字形 ID 调用特定字形。只是寻找相关的 iText class 名称(如果存在的话)。
这在 iText 的最新标签 5.5.8, nor in the master 分支中似乎是不可能的。
如 this article and in the Microsoft's OpenType font file specification 中所述,字形变体存储在字体文件的 Glyph Substitution Table (GSUB)
中。访问字形变体需要从文件中读取这个 table,它实际上是在 class com.itextpdf.text.pdf.fonts.otf.GlyphSubstitutionTableReader
中实现的,尽管这个 class 现在被禁用了。
classcom.itextpdf.text.pdf.TrueTypeFontUnicode
中的调用readGsubTable()
被注释掉了。
void process(byte ttfAfm[], boolean preload) throws DocumentException, IOException {
super.process(ttfAfm, preload);
//readGsubTable();
}
事实证明,这条线被禁用是有原因的,因为如果您尝试激活它,代码实际上不起作用。
因此,不幸的是,无法使用字形变体,因为永远不会从字体文件中加载替换信息。
更新
最初的答案是关于使用 iText API
访问开箱即用的字形变体的可能性,目前还没有。但是,低级代码已经到位,经过一些黑客攻击后可以使用它来访问字形替换映射 table。
当调用 read()
时,GlyphSubstitutionTableReader
读取 GSUB
table 并将所有特征的替换扁平化为一个映射 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
由 TrueTypeFont
中的 cmap31
字段映射。反转地图通过 glyphId 给出 unicode。
调整
rawLigatureSubstitutionMap
无法在 GlyphSubstitutionTableReader
中访问,因为它是 private
成员并且没有 getter 访问器。最简单的破解方法是复制粘贴原始 class 并为地图添加一个 getter:
public class HackedGlyphSubstitutionTableReader extends OpenTypeFontTableReader {
// copy-pasted code ...
public Map<Integer, List<Integer>> getRawSubstitutionMap() {
return rawLigatureSubstitutionMap;
}
}
下一个问题是 GlyphSubstitutionTableReader
需要 GSUB
table 的偏移量,信息存储在 TrueTypeFont
protected HashMap<String, int[]> tables
class .放置在同一个包中的助手 class 将桥接对 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
会更好,但这不适用于 BaseFont
的工厂方法 createFont()
,后者在创建时依赖于硬编码的 class 名称一种字体。
在 iText 中使用 OpenType 字体构建 PDF 文档时,我想从字体中访问字形变体——特别是表格图形。由于 OpenType 字形变体没有 Unicode 索引,我不确定如何指定我要使用一组特定的变体(表格数字)或通过字形 ID 调用特定字形。只是寻找相关的 iText class 名称(如果存在的话)。
这在 iText 的最新标签 5.5.8, nor in the master 分支中似乎是不可能的。
如 this article and in the Microsoft's OpenType font file specification 中所述,字形变体存储在字体文件的 Glyph Substitution Table (GSUB)
中。访问字形变体需要从文件中读取这个 table,它实际上是在 class com.itextpdf.text.pdf.fonts.otf.GlyphSubstitutionTableReader
中实现的,尽管这个 class 现在被禁用了。
classcom.itextpdf.text.pdf.TrueTypeFontUnicode
中的调用readGsubTable()
被注释掉了。
void process(byte ttfAfm[], boolean preload) throws DocumentException, IOException {
super.process(ttfAfm, preload);
//readGsubTable();
}
事实证明,这条线被禁用是有原因的,因为如果您尝试激活它,代码实际上不起作用。
因此,不幸的是,无法使用字形变体,因为永远不会从字体文件中加载替换信息。
更新
最初的答案是关于使用 iText API
访问开箱即用的字形变体的可能性,目前还没有。但是,低级代码已经到位,经过一些黑客攻击后可以使用它来访问字形替换映射 table。
当调用 read()
时,GlyphSubstitutionTableReader
读取 GSUB
table 并将所有特征的替换扁平化为一个映射 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
由 TrueTypeFont
中的 cmap31
字段映射。反转地图通过 glyphId 给出 unicode。
调整
rawLigatureSubstitutionMap
无法在 GlyphSubstitutionTableReader
中访问,因为它是 private
成员并且没有 getter 访问器。最简单的破解方法是复制粘贴原始 class 并为地图添加一个 getter:
public class HackedGlyphSubstitutionTableReader extends OpenTypeFontTableReader {
// copy-pasted code ...
public Map<Integer, List<Integer>> getRawSubstitutionMap() {
return rawLigatureSubstitutionMap;
}
}
下一个问题是 GlyphSubstitutionTableReader
需要 GSUB
table 的偏移量,信息存储在 TrueTypeFont
protected HashMap<String, int[]> tables
class .放置在同一个包中的助手 class 将桥接对 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
会更好,但这不适用于 BaseFont
的工厂方法 createFont()
,后者在创建时依赖于硬编码的 class 名称一种字体。