【问题标题】:The non-latin text is disappearing from the pdf text field非拉丁文本从 pdf 文本字段中消失
【发布时间】:2021-11-01 18:21:59
【问题描述】:

我使用 itext 7.1.9 库创建了一个带有文本可填写字段的 PDF 文档。 PdfTextFormField 包含多语言文本。创建 PDF 文档后,我在 Adob​​e Acrobat Reader 中打开它,非拉丁符号从文本字段中消失,我只看到拉丁符号,但如果我单击该字段,整个文本将可见,包括非拉丁符号。 [! The PDF text field after openning document]1。 [! The PDF text field after clicking to the field]2。为了创建 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();

        }
    }
}

我试图解决这个问题,我什至找到了the article on itext blog,但它对我没有帮助。我知道使用 ff.setNeedAppearence(true) 方法,但我不能使用它,因为它破坏了我应用程序的另一部分。而且我无法设置PdfEncoding.IDENTITY_H,因为它仅嵌入了以编程方式包含在该字段中的符号子集,并且用户无法填写此字段。
有人可以帮助我吗?我做错了什么?

【问题讨论】:

  • 嗨,你试过 7.1.16 吗?考虑到季度发布时间表,这几乎提前了 2 年
  • @AlexeySubach 我试过 7.1.16。我得到了同样的结果。

标签: java itext itext7


【解决方案1】:

要确保嵌入完整字体,而不仅仅是子集,请使用font.setSubset(false);

一般来说,您应该尽可能尝试使用包含您的值中所有字形的字体。否则您的 PDF 的使用者可能会遇到问题。

作为一种解决方法,您可以使用layout 模块创建自己的外观,方法是利用自动选择适当字体的FontSet 功能。在我的示例中,我只向FontSet 添加了一种字体,但您可以在那里添加多种字体。但是,强烈建议将字体数量限制为一种,如果不可能,则限制为尽可能少的数量。

所以这里我们基本上创建了一个PdfFormXObject 作为我们的外观对象:

FontSet fontSet = new FontSet();
fontSet.addFont("C:/Windows/Fonts/arial.ttf");
FontProvider fontProvider = new FontProvider(fontSet);

PdfFormXObject xObject = new PdfFormXObject(FIELDRECT);
Canvas canvas = new Canvas(xObject, pdfDoc);
canvas.setProperty(Property.FONT_PROVIDER, fontProvider);
canvas.add(new Paragraph(FIELDVALUE).setMultipliedLeading(1).setFontFamily("Arial"));

然后我们必须将其设置为字段:

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

您的createPdf 的完整代码现在如下所示:

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);

FontSet fontSet = new FontSet();
fontSet.addFont("C:/Windows/Fonts/arial.ttf");
FontProvider fontProvider = new FontProvider(fontSet);

PdfFormXObject xObject = new PdfFormXObject(FIELDRECT);
Canvas canvas = new Canvas(xObject, pdfDoc);
canvas.setProperty(Property.FONT_PROVIDER, fontProvider);
canvas.add(new Paragraph(FIELDVALUE).setMultipliedLeading(1).setFontFamily("Arial"));

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

acroForm.addField(ff,pdfDoc.getFirstPage());

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

doc.close();

打开 PDF 时的视觉结果:

UPD 上面的代码在 Adob​​e Acrobat、Foxit、Chrome PDF 查看器中运行良好,但是当您在 Adob​​e Reader 中打开它时,您会看到空白的表单字段。

要使其在 Acrobat 中工作,您必须确保 XObject bbox 从原点开始:

PdfFormXObject xObject = new PdfFormXObject(new Rectangle(0, 0, FIELDRECT.getWidth(), FIELDRECT.getHeight()));

并将外观包装到/Tx BMC/EMC块中,标记重新生成外观时需要替换的部分。

代码的固定部分在 Adob​​e Acrobat Reader 中也能产生正确的结果:

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);
canvas.add(new Paragraph(FIELDVALUE).setMultipliedLeading(1).setFontFamily("Arial"));
canvas.getPdfCanvas().endMarkedContent();

【讨论】:

  • 感谢这种方法,但如果您单击该字段,它会显示值。如果文档在 Acrobat Reader 中打开并且您没有单击该字段,则该字符串不会显示在该字段上。
  • 很遗憾,它对您没有用。它对我有用,而你的代码没有成功。我已经在这里上传了我的 PDF 结果 (easyupload.io/g10viu),你能检查一下它是否适用于你吗?
  • 我已经下载了你的文件。它不适用于 Acrobat Reader。
  • 你用的是哪个版本?
  • 非常感谢,我已经检查过了,它对我有用。
猜你喜欢
  • 2019-02-18
  • 2012-02-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-27
相关资源
最近更新 更多