在iText中访问OpenType字形变体

在iText中使用OpenType字体构建PDF文档时,我想从字体中访问字形变体 – 特别是表格形状。 由于OpenType字形变体没有Unicode索引,我不知道如何指定我想使用一组特定的变体(表格图)或通过其字形ID调用特定的字形。 只查找相关的iText类名称(如果存在)。

这似乎在最新的标签5.5.8和iText的主分支中都不可能。

如本文和Microsoft的OpenType字体文件规范中所述 ,字形变体存储在字体文件的Glyph Substitution Table (GSUB)中。 访问字形变体需要从文件中读取该表,该表实际上是在com.itextpdf.text.pdf.fonts.otf.GlyphSubstitutionTableReader类中com.itextpdf.text.pdf.fonts.otf.GlyphSubstitutionTableReader ,尽管此类目前已禁用。

readGsubTable()类中的readGsubTable()调用被注释掉。

 void process(byte ttfAfm[], boolean preload) throws DocumentException, IOException { super.process(ttfAfm, preload); //readGsubTable(); } 

事实certificate,由于某些原因,该行被禁用,因为如果您尝试激活它,代码实际上不起作用。

所以,遗憾的是,没有办法使用字形变体,因为替换信息永远不会从字体文件中加载。

更新

最初的答案是关于使用iText API来开箱即用的字形变体的可能性,这还没有。 但是,低级代码已到位,并且可以在一些黑客攻击后使用以访问字形替换映射表。

当调用read()GlyphSubstitutionTableReader读取GSUB表并将所有GlyphSubstitutionTableReader的替换展平为一个映射Map> rawLigatureSubstitutionMapOpenTypeFontTableReader当前丢弃了这些function的符号名称。 rawLigatureSubstitutionMapglyphId变体映射到基本glyphId ,或者将glyphId到一系列glyphIds如下所示:

 629 -> 66 // a.feature -> a 715 -> 71, 71, 77 // ffl ligature 

可以反转此映射以获得基本glyphId所有变体。 因此,所有具有未知unicode值的扩展字形都可以通过它们与基本字形或字形序列的连接来计算出来。

接下来,为了能够将字形写入PDF,我们需要知道该字形的unicode值。 关系unicode -> glyphIdTrueTypeFontcmap31字段映射。 反转地图通过glyphId给出unicode。

扭捏

rawLigatureSubstitutionMap无法在GlyphSubstitutionTableReader中访问,因为它是private成员,并且没有getter访问器。 最简单的方法是复制粘贴原始类并为地图添加一个getter:

 public class HackedGlyphSubstitutionTableReader extends OpenTypeFontTableReader { // copy-pasted code ... public Map> getRawSubstitutionMap() { return rawLigatureSubstitutionMap; } } 

下一个问题是GlyphSubstitutionTableReader需要GSUB表的偏移量,该信息存储在TrueTypeFont类的protected HashMap tables中。 放置在同一个包中的辅助类将桥接对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> rawSubstitutionMap; public GsubHelper(TrueTypeFont font) { // get tables offsets from the font instance Map 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> getRawSubstitutionMap() { return rawSubstitutionMap; } } 

扩展TrueTypeFont会更好,但这对createFont()工厂方法createFont() BaseFont ,它在创建字体时依赖于硬编码的类名。

Interesting Posts