I create a PDF document with text fillable fields using itext 7.1.9
library. The PdfTextFormField
contains a multilanguage text. When the PDF document has created, I open it in Adobe Acrobat Reader and the non-latin symbols are disappearing from the text field and I see only latin symbols, but if I click on the field the whole text will be visible including non-latin symbols.
[! The PDF text field after openning document]1. [! The PDF text field after clicking to the field]2. For creating a PDF document I’m using the code like the following:
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(); } } }
I have tried to solve this issue and I even found the article on itext blog, but it didn’t help me. I know about using ff.setNeedAppearence(true)
method, but I can’t use it because it breaks another part of my app. And I couldn’t set PdfEncoding.IDENTITY_H
because it embeds only a subset of symbols which was included programmatically to the field and a user can’t fill out this field.
Can anyone help me? What do I do wrong?
Advertisement
Answer
To make sure the full font is embedded, and not just a subset, use font.setSubset(false);
.
Generally speaking, you should as much as possible try to use a font which contains all of the glyphs from your value. Otherwise the consumers of your PDFs may have issues.
As a workaround you can create your own appearance using layout
module by utilizing FontSet
functionality which selects appropriate fonts automatically. In my example I only add one font to the FontSet
but you may add multiple fonts there. It is strongly recommended, though, to limit the number of fonts to one, and to the smallest possible number if one is not possible.
So here we basically create a PdfFormXObject
which serves as our appearance object:
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"));
And then we have to set it to the field:
ff.setAppearance(PdfName.N, null, xObject.getPdfObject());
Full code of your createPdf
now looks as follows:
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();
Visual result on opening the PDF:
UPD The code above works fine in Adobe Acrobat, Foxit, Chrome PDF viewer but when you open it up in Adobe Reader you see empty form field.
To make it work in Acrobat, you have to make sure to have your XObject bbox start at origin:
PdfFormXObject xObject = new PdfFormXObject(new Rectangle(0, 0, FIELDRECT.getWidth(), FIELDRECT.getHeight()));
And also wrap the appearance into /Tx BMC
/ EMC
block which marks the part that need to be replaced when appearance is regenerated.
Fixed part of code produces correct result in Adobe Acrobat Reader as well:
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();