You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PDFBOX加载日文字体时embedSubset设为true报错,如何嵌入子集字符?

PDFBOX嵌入日文字体子集报错解决方案

问题概述

  • 使用PDFBOX加载日文字体(如TsukuhouMincho-Regular)时,将embedSubset参数设为true会触发IllegalArgumentException,提示"No glyph for U+65E5 (日) in font TsukuhouMincho-Regular"
  • 将embedSubset设为false时可正常运行,但输出PDF文件体积过大,需要仅嵌入所用字符子集以减小文件大小
  • 测试过PDFBOX 2.0.30、多个2.x.x及3.x.x版本,问题均未解决;iText可实现该功能,但因许可证限制无法使用

报错堆栈信息

java.lang.IllegalArgumentException: No glyph for U+65E5 (日) in font TsukuhouMincho-Regular
at org.apache.pdfbox.pdmodel.font.PDCIDFontType2.encode(PDCIDFontType2.java:389)
at org.apache.pdfbox.pdmodel.font.PDType0Font.encode(PDType0Font.java:427)
at org.apache.pdfbox.pdmodel.font.PDFont.encode(PDFont.java:337)
at org.apache.pdfbox.pdmodel.font.PDFont.getStringWidth(PDFont.java:368)
at org.apache.pdfbox.pdmodel.interactive.form.AppearanceGeneratorHelper.calculateFontSize(AppearanceGeneratorHelper.java:828)
at org.apache.pdfbox.pdmodel.interactive.form.AppearanceGeneratorHelper.insertGeneratedAppearance(AppearanceGeneratorHelper.java:488)
at org.apache.pdfbox.pdmodel.interactive.form.AppearanceGeneratorHelper.setAppearanceContent(AppearanceGeneratorHelper.java:424)
at org.apache.pdfbox.pdmodel.interactive.form.AppearanceGeneratorHelper.setAppearanceValue(AppearanceGeneratorHelper.java:248)
at org.apache.pdfbox.pdmodel.interactive.form.PDTextField.constructAppearances(PDTextField.java:264)
at org.apache.pdfbox.pdmodel.interactive.form.PDTerminalField.applyChange(PDTerminalField.java:227)
at org.apache.pdfbox.pdmodel.interactive.form.PDTextField.setValue(PDTextField.java:219)
at TEST_PDFBOX.testMSMincho(TEST_PDFBOX.java:123)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:70)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:89)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:40)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:541)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:768)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:464)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:210)

相关代码示例

PDDocument pdDoc;
//For ver3.0.1
//pdDoc = Loader.loadPDF(new File(pdffile));
//For ver2.x.x
pdDoc = PDDocument.load(new File(pdffile));

//TsukuhouMincho is free Japanese font. If I set true to embedSubset argument, it generates error.

PDFont font = PDType0Font.load(pdDoc, PDFBOXTester.class.getResourceAsStream("/font/TsukuhouMincho-Regular.ttf"), false);

PDDocumentCatalog pdCatalog = pdDoc.getDocumentCatalog();
PDAcroForm pdAcroForm = pdCatalog.getAcroForm();
PDTextField textfield = (PDTextField) pdAcroForm.getField("Text_TaxOffice_JP");

PDResources res = pdAcroForm.getDefaultResources();
String fontName = res.add(font).getName();
textfield.setDefaultAppearance("/" + fontName + " 0 Tf 0 g");
textfield.setValue(someJapanaeseStrings);

pdDoc.save(new File(args[1]));

解决方案

1. 预编码需要使用的字符

在加载字体并开启子集嵌入后,手动编码所有需要用到的日文字符,确保字体子集包含对应的字形:

// 开启子集嵌入加载字体
PDFont font = PDType0Font.load(pdDoc, PDFBOXTester.class.getResourceAsStream("/font/TsukuhouMincho-Regular.ttf"), true);
// 预编码所有需要使用的字符
for (char c : someJapanaeseStrings.toCharArray()) {
    font.encode(String.valueOf(c));
}

// 后续表单字段设置逻辑不变
PDDocumentCatalog pdCatalog = pdDoc.getDocumentCatalog();
PDAcroForm pdAcroForm = pdCatalog.getAcroForm();
PDTextField textfield = (PDTextField) pdAcroForm.getField("Text_TaxOffice_JP");

PDResources res = pdAcroForm.getDefaultResources();
String fontName = res.add(font).getName();
textfield.setDefaultAppearance("/" + fontName + " 0 Tf 0 g");
textfield.setValue(someJapanaeseStrings);

pdDoc.save(new File(args[1]));

原理:PDFBOX默认可能不会自动收集表单字段中使用的字符到子集,提前编码这些字符可以强制字体子集包含对应的字形数据。

2. 验证字体文件完整性

确认使用的TsukuhouMincho-Regular.ttf字体文件本身包含所需的日文字形(如U+65E5),部分精简版字体可能存在字形缺失,建议下载官方完整版字体文件测试。

3. 手动生成表单外观

禁用PDFBOX自动生成表单外观的逻辑,手动绘制文本外观,更精确地控制字体子集的嵌入:

// 开启子集嵌入加载字体
PDFont font = PDType0Font.load(pdDoc, PDFBOXTester.class.getResourceAsStream("/font/TsukuhouMincho-Regular.ttf"), true);
PDDocumentCatalog pdCatalog = pdDoc.getDocumentCatalog();
PDAcroForm pdAcroForm = pdCatalog.getAcroForm();
PDTextField textfield = (PDTextField) pdAcroForm.getField("Text_TaxOffice_JP");

PDResources res = pdAcroForm.getDefaultResources();
String fontName = res.add(font).getName();
textfield.setDefaultAppearance("/" + fontName + " 12 Tf 0 g"); // 设置字体大小
textfield.setValue(someJapanaeseStrings);

// 禁用自动外观生成
textfield.setNeedAppearances(false);

// 手动创建外观流
PDAppearanceDictionary appearance = new PDAppearanceDictionary();
PDAppearanceEntry appearanceEntry = new PDAppearanceEntry();
PDFormXObject form = new PDFormXObject(pdDoc);
PDRectangle rect = textfield.getWidget().getRectangle();
form.setBBox(new PDRectangle(rect.getWidth(), rect.getHeight()));

PDPageContentStream contentStream = new PDPageContentStream(pdDoc, form);
contentStream.setFont(font, 12);
contentStream.beginText();
// 设置文本起始位置(可根据需求调整)
contentStream.newLineAtOffset(5, rect.getHeight() - 15);
contentStream.showText(someJapanaeseStrings);
contentStream.endText();
contentStream.close();

appearanceEntry.setNormalAppearance(form);
appearance.setNormalAppearance(appearanceEntry);
textfield.getWidget().setAppearance(appearance);

pdDoc.save(new File(args[1]));

原理:自动生成外观时,PDFBOX可能在子集嵌入逻辑上存在冲突,手动绘制外观可以绕过该问题,同时确保只嵌入使用到的字符。


内容的提问来源于stack exchange,提问作者K M

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.01 07:27:33