如何在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
相关产品推荐
相关产品推荐

