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

如何在iText 7.1.17中兼顾非拉丁文字渲染与PDF文件压缩?

解决iText 7.1.17中非拉丁文字渲染异常与PDF体积过大的问题

我使用iText 7.1.17库创建PDF文档时,曾遇到非拉丁符号渲染显示异常的问题。找到修复方案后,生成的PDF文件体积从20KB增长到了37KB。现在需要在确保Acrobat Reader能正常渲染非拉丁文字的前提下,减小输出PDF的体积。


修复后代码(体积37KB)

public static void main(String[] args) {
    Rectangle FIELDRECT = new Rectangle(50, 750, 200, 18);
    String FIELDVALUE = "Hello";
    PdfWriter writer = new PdfWriter("FontEmbedded.pdf");
    InputStream resourceAsStream = Main.class.getClassLoader().getResourceAsStream("Test.pdf");
    PdfReader reader = new PdfReader(resourceAsStream);
    PdfDocument pdfDoc = new PdfDocument(reader, writer);
    Document doc = new Document(pdfDoc);
    String fontPath = Main.class.getClassLoader().getResource("fonts/arial.ttf").getPath();
    FontSet fontSet = new FontSet();
    fontSet.addFont(fontPath);
    FontProvider fontProvider = new FontProvider(fontSet);
    PdfAcroForm acroForm = PdfAcroForm.getAcroForm(pdfDoc,true);
    PdfTextFormField ff = PdfFormField.createText(pdfDoc, FIELDRECT, "test");
    PdfFont font = PdfFontFactory.createFont(fontsDir + "/arial.ttf", PdfEncodings.WINANSI, true);
    ff.setFont(font);
    ff.setFontSize(12);
    ff.setValue(FIELDVALUE);
    ff.setMultiline(true);
    ff.setScroll(true);
    ff.setVisibility(4);
    acroForm.addField(ff,pdfDoc.getFirstPage());
    PdfFormXObject xObject = new PdfFormXObject(new Rectangle(0, 0, FIELDRECT.getWidth(), FIELDRECT.getHeight()));
    Canvas canvas = new Canvas(xObject, pdfDoc);
    canvas.getPdfCanvas().beginMarkedContent(new PdfName("Tx"));
    canvas.setProperty(Property.FONT_PROVIDER, fontProvider);
    Paragraph paragraph = new Paragraph(FIELDVALUE).setFont(font)
                                               .setFontSize(12)
                                               .setFontFamily("Arial");
    canvas.add(paragraph);
    canvas.getPdfCanvas().endMarkedContent();

    ff.setAppearance(PdfName.N, null, xObject.getPdfObject());

    PdfCanvas pdfCanvas = new PdfCanvas(pdfDoc.getFirstPage());
    pdfCanvas.setLineWidth(1f).setStrokeColor(ColorConstants.BLUE).rectangle(FIELDRECT).stroke();

    doc.close();
}

原代码(体积20KB)

public static void main(String[] args) {
    Rectangle FIELDRECT = new Rectangle(50, 750, 200, 18);
    String FIELDVALUE = "Hello";
    PdfWriter writer = new PdfWriter("FontEmbedded.pdf");
    InputStream resourceAsStream = Main.class.getClassLoader().getResourceAsStream("Test.pdf");
    PdfReader reader = new PdfReader(resourceAsStream);
    PdfDocument pdfDoc = new PdfDocument(reader, writer);
    Document doc = new Document(pdfDoc);
    PdfAcroForm acroForm = PdfAcroForm.getAcroForm(pdfDoc,true);
    PdfTextFormField ff = PdfFormField.createText(pdfDoc, FIELDRECT, "test");
    PdfFont font = PdfFontFactory.createFont(fontsDir + "/arial.ttf", PdfEncodings.WINANSI, true);
    ff.setFont(font);
    ff.setFontSize(12);
    ff.setValue(FIELDVALUE);
    ff.setMultiline(true);
    ff.setScroll(true);
    ff.setVisibility(4);
    acroForm.addField(ff,pdfDoc.getFirstPage());
    
    doc.close();
}

优化方案

1. 避免重复嵌入字体

修复代码中两次加载Arial字体,可能导致字体被重复嵌入,直接增大体积。需复用同一个PdfFont实例,无需额外创建FontSet和FontProvider。

2. 改用Unicode编码支持非拉丁字符

原修复方案通过自定义外观解决渲染问题,其实只需将字体编码改为PdfEncodings.IDENTITY_H(Unicode编码),就能原生支持非拉丁字符,无需复杂的外观绘制。

3. 确保字体子集嵌入

创建字体时保持第三个参数为true,启用子集嵌入模式,只嵌入文档中实际使用的字符,而非整个字体文件,有效减小体积。

优化后的代码示例

public static void main(String[] args) {
    Rectangle FIELDRECT = new Rectangle(50, 750, 200, 18);
    String FIELDVALUE = "Hello"; // 可替换为非拉丁字符测试
    PdfWriter writer = new PdfWriter("FontEmbedded.pdf");
    InputStream resourceAsStream = Main.class.getClassLoader().getResourceAsStream("Test.pdf");
    PdfReader reader = new PdfReader(resourceAsStream);
    PdfDocument pdfDoc = new PdfDocument(reader, writer);
    Document doc = new Document(pdfDoc);
    
    // 单次加载字体,启用子集嵌入,使用Unicode编码支持非拉丁字符
    String fontPath = Main.class.getClassLoader().getResource("fonts/arial.ttf").getPath();
    PdfFont font = PdfFontFactory.createFont(fontPath, PdfEncodings.IDENTITY_H, true);
    
    PdfAcroForm acroForm = PdfAcroForm.getAcroForm(pdfDoc, true);
    PdfTextFormField ff = PdfFormField.createText(pdfDoc, FIELDRECT, "test");
    ff.setFont(font);
    ff.setFontSize(12);
    ff.setValue(FIELDVALUE);
    ff.setMultiline(true);
    ff.setScroll(true);
    ff.setVisibility(4);
    acroForm.addField(ff, pdfDoc.getFirstPage());
    
    // 保留边框绘制逻辑(按需选择)
    PdfCanvas pdfCanvas = new PdfCanvas(pdfDoc.getFirstPage());
    pdfCanvas.setLineWidth(1f).setStrokeColor(ColorConstants.BLUE).rectangle(FIELDRECT).stroke();
    
    doc.close();
}

效果说明

优化后既解决了非拉丁文字渲染异常问题,又避免了重复资源嵌入,PDF体积可回落至接近原代码的20KB水平,同时保持Acrobat Reader的正常渲染支持。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 07:47:02