iText7生成PDF表单域非拉丁文字默认不显示问题求助
iText 7 生成多语言可填充PDF文本域显示异常问题解决
问题描述
我使用itext 7.1.9库创建了带可填充文本域的PDF文档,PdfTextFormField中包含多语言文本。PDF生成完成后,在Adobe Acrobat Reader中打开时文本域内的非拉丁符号消失,仅可见拉丁字符,点击该字段后,包括非拉丁符号在内的全部文本都会正常显示。
- 文档打开后的PDF文本域状态:

- 点击文本域后的显示状态:

我使用如下代码生成PDF:
public class Main { public static void main(String[] args) throws IOException, URISyntaxException { FontProviderAndFormFieldExample app = new FontProviderAndFormFieldExample(); app.createPdf("Test1.pdf"); app.fillExample("Test1.pdf", "Result.pdf", Paths.get(Main.class.getResource("/fonts").toURI()).toString()); } public static class FontProviderAndFormFieldExample { public String FIELDNAME = "test"; public Rectangle FIELDRECT = new Rectangle(50,300,300,20); public String FIELDVALUE = "ПриветHello"; public void createPdf(String dest) throws IOException { PdfWriter writer = new PdfWriter(dest); PdfDocument pdfDoc = new PdfDocument(writer); Document doc = new Document(pdfDoc); Paragraph para = new Paragraph("Test document for multi-font appearance in a text formfield"); doc.add(para); PdfAcroForm acroForm = PdfAcroForm.getAcroForm(pdfDoc,true); PdfTextFormField ff = PdfFormField.createText(pdfDoc,FIELDRECT,"test", FIELDVALUE); ff.setMultiline(true); ff.setScroll(true); acroForm.addField(ff,pdfDoc.getFirstPage()); PdfCanvas pdfCanvas = new PdfCanvas(pdfDoc.getFirstPage()); pdfCanvas.setLineWidth(1f).setStrokeColor(ColorConstants.BLUE).rectangle(FIELDRECT).stroke(); doc.close(); } public void fillExample(String src, String dest, String srcf) throws IOException, URISyntaxException { PdfReader reader = new PdfReader(src); PdfWriter writer = new PdfWriter(dest); PdfDocument pdfDoc = new PdfDocument(reader,writer); PdfAcroForm acroForm = PdfAcroForm.getAcroForm(pdfDoc,true); PdfFormField ff = acroForm.getField(FIELDNAME); String filename = Main.class.getResource("/fonts/arial unicode.ttf").toURI().toString(); final PdfFont font = PdfFontFactory.createFont(filename, PdfEncodings.UTF8, false); ff.setFont(font).setValue(FIELDVALUE); pdfDoc.close(); } } }
我已尝试多种方案均无效:
- 已知可以调用
ff.setNeedAppearence(true)方法,但该方法会破坏应用的其他功能因此无法使用 - 无法使用
PdfEncoding.IDENTITY_H配置,因为它只会嵌入代码中指定的符号子集,后续用户无法正常填充该表单域
问题原因
当前代码的问题核心在于两点:
- 创建初始表单字段时没有提前绑定支持全字符集的字体,iText默认使用的字体仅支持拉丁字符,生成的默认外观流没有包含非拉丁字符的渲染规则,Adobe Reader打开时直接用默认外观渲染就会丢失非拉丁字符
- 填充字段时没有强制iText生成完整的自定义外观流,同时没有设置表单全局的默认字体规则,后续用户手动填写时也可能出现字符不显示的问题
解决方案
无需使用setNeedAppearence,也无需用IDENTITY_H嵌入子集,按如下规则修改代码即可解决:
- 提前加载支持多语言的字体,设置为全嵌入、禁止子集化,确保所有字符都被打包到PDF中
- 创建表单字段时就绑定该全字符字体,不要等到后续填充阶段才设置
- 调用
setValue时开启强制生成外观参数,让iText直接渲染包含所有字符的默认显示效果 - 给整个AcroForm设置默认字体规则,确保后续用户手动填写时也能正常渲染所有字符
修改后的核心代码片段如下:
// 1. 提前定义全局全字符字体,embedded设为true表示嵌入PDF,subset设为false禁止子集化,确保所有字符都可用 String fontPath = Main.class.getResource("/fonts/arial unicode.ttf").toURI().toString(); PdfFont fullFont = PdfFontFactory.createFont(fontPath, PdfEncodings.UTF8, true, false); // 2. 创建表单字段时直接绑定该字体,同时指定字号 PdfTextFormField ff = PdfFormField.createText(pdfDoc,FIELDRECT,"test", FIELDVALUE, fullFont, 12f); // 3. 填充字段时调用带appearance参数的setValue方法,第二个参数设为true强制生成正确的外观流 ff.setFont(fullFont).setValue(FIELDVALUE, true); // 4. 给整个表单设置默认外观,字体名称要和嵌入字体的PostScript名称一致,可通过fullFont.getName()打印获取实际名称 acroForm.setDefaultAppearance("/ArialUnicodeMS 12 Tf 0 g");
注意事项
- 全字库嵌入会增加PDF的体积,Arial Unicode MS全嵌入大概会增加20MB左右的体积,如果对体积有要求可以换用更小的全字符开源字体,比如Noto Sans系列全字库
- 默认外观里的字体名称必须和嵌入字体的PostScript名称完全一致,否则Adobe Reader会找不到字体回退到系统字体,依然可能出现显示异常
- 当前使用的iText 7.1.9版本存在少量表单字体渲染的已知bug,如果修改后还是有问题可以升级到7.2.5以上的稳定版本,该版本已经修复了多语言表单字段默认外观生成的相关问题
内容的提问来源于stack exchange,提问作者John
相关产品推荐
相关产品推荐

