如何在PdfBox中正确检查字体是否支持指定代码点
问题:PDFBox中检查NotoEmoji字体是否包含指定表情符号失败
我需要在PDF中仅当遇到表情符号时使用NotoEmoji字体,因此需要判断该字体是否包含对应表情符号。但使用hasGlyph方法检查U+1F302(关闭雨伞)时返回false,尽管已确认字体包含该符号。
复现代码
public static void main(String[] args) throws IOException { PDType0Font font = PDType0Font.load( new PDDocument(), ClassLoader.getSystemResourceAsStream("NotoEmoji-Regular.ttf"), false); String hex = "01F302"; int codepoint = Integer.parseInt(hex,16); System.out.println("codepoint: " + codepoint); System.out.println("contains hex " + hex + ": " + font.hasGlyph(codepoint)); }
环境依赖
<dependency> <groupId>org.apache.pdfbox</groupId> <artifactId>pdfbox</artifactId> <version>2.0.26</version> </dependency>
预期与实际输出
- 预期输出:
codepoint: 127746 contains hex 01F302: true
- 实际输出:
contains hex 01F302: false
解决方案与解释
通过font.codeToCID(codepoint) > 0可以正确判断字体是否支持该表情符号,而hasGlyph和codeToGID直接传Unicode码点无效的原因如下:
1. hasGlyph(int code)的误区
hasGlyph方法接收的参数是PDF编码中的字符代码,而非Unicode码点。对于Type0字体(基于TrueType的CID字体),它的编码逻辑是通过CID映射实现的,直接传入Unicode码点无法匹配到对应的字形,因此返回false。
2. codeToCID(int unicode)的可靠性
codeToCID方法是专门用于将Unicode码点转换为CID(字符标识符)的API,返回值大于0表示该Unicode码点存在对应的CID,即字体支持该字符。这个判断方式是可靠的,因为它完全遵循Type0字体的CID映射逻辑。
3. codeToGID(int code)无效的原因
codeToGID方法的参数同样是PDF编码的字符代码,不是Unicode码点。直接传入Unicode码点会返回0(无效字形ID),若要通过GID判断,需要先通过CID获取对应的GID,或先完成Unicode到PDF编码的转换。
解决方案演示代码
public static void main(String[] args) throws IOException { PDType0Font font = PDType0Font.load( new PDDocument(), ClassLoader.getSystemResourceAsStream("NotoEmoji-Regular.ttf"), false); String hex = "01F302"; int codepoint = Integer.parseInt(hex,16); System.out.println("codepoint: " + codepoint); System.out.println("hasGlyph(0): " + font.hasGlyph('0')); System.out.println("cid: " + font.codeToCID(codepoint)); System.out.println("gid: " + font.codeToGID(codepoint)); System.out.println("can Encode: " + (font.codeToCID(codepoint) > 0)); }
输出结果
codepoint: 127746 hasGlyph(0): true cid: 62210 gid: 0 can Encode: true
内容的提问来源于stack exchange,提问作者Ryan Horlacher
相关产品推荐
相关产品推荐

