非拉丁文本从 pdf 文本字段中消失
The non-latin text is disappearing from the pdf text field
我使用 itext 7.1.9
库创建了一个包含文本可填写字段的 PDF 文档。 PdfTextFormField
包含多语言文本。创建 PDF 文档后,我在 Adobe 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
,因为它仅嵌入了以编程方式包含在该字段中的符号子集,而用户无法填写该字段。
谁能帮助我?我做错了什么?
要确保嵌入完整字体,而不仅仅是子集,请使用 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 上面的代码在 Adobe Acrobat、Foxit、Chrome PDF 查看器中运行良好,但是当您在 Adobe Reader 中打开它时,您会看到空的表单字段。
要使其在 Acrobat 中运行,您必须确保 XObject bbox 从原点开始:
PdfFormXObject xObject = new PdfFormXObject(new Rectangle(0, 0, FIELDRECT.getWidth(), FIELDRECT.getHeight()));
并且将外观包裹在/Tx BMC
/ EMC
块中,标记重新生成外观时需要更换的部分。
固定部分代码在 Adobe 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();
我使用 itext 7.1.9
库创建了一个包含文本可填写字段的 PDF 文档。 PdfTextFormField
包含多语言文本。创建 PDF 文档后,我在 Adobe 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
,因为它仅嵌入了以编程方式包含在该字段中的符号子集,而用户无法填写该字段。
谁能帮助我?我做错了什么?
要确保嵌入完整字体,而不仅仅是子集,请使用 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 上面的代码在 Adobe Acrobat、Foxit、Chrome PDF 查看器中运行良好,但是当您在 Adobe Reader 中打开它时,您会看到空的表单字段。
要使其在 Acrobat 中运行,您必须确保 XObject bbox 从原点开始:
PdfFormXObject xObject = new PdfFormXObject(new Rectangle(0, 0, FIELDRECT.getWidth(), FIELDRECT.getHeight()));
并且将外观包裹在/Tx BMC
/ EMC
块中,标记重新生成外观时需要更换的部分。
固定部分代码在 Adobe 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();