Hopding / pdf-lib

Create and modify PDF documents in any JavaScript environment
https://pdf-lib.js.org
MIT License
6.69k stars 644 forks source link

PDF form text field setText does not use font #1378

Open psyanite opened 1 year ago

psyanite commented 1 year ago

Hi there, thanks for creating the best PDF library on the internet! I ran into some issues trying to fill text fields on my AcroForm

What were you trying to do?

I tried to use PDF-LIB form.getTextField('dateTaken').setText('hello this is my text') to set some text fields on my form. But the fonts I configured in Adobe Acrobat Pro is ignored.

I created a form using Adobe Acrobat Pro When creating the fields in Adobe Acrobat Pro I can edit the text field properties and set a font.

Screen Shot 2023-01-13 at 10 29 44 am

When I fill the form in Adobe Acrobat it fills correctly, the font size, color, and font is maintained:

Screen Shot 2023-01-13 at 10 25 46 am

But when I use the following code:

      form.getTextField('dateTaken').setText('hello this is my text')
      const pdfBytes = await pdfDoc.save()
      download(pdfBytes, "result.pdf", "application/pdf")

And save the pdf, the font is not maintained:

Screen Shot 2023-01-13 at 10 26 49 am

How did you attempt to do it?

  <head>
    <meta charset="utf-8" />
    <script src="https://unpkg.com/pdf-lib@1.11.0"></script>
    <script src="https://unpkg.com/downloadjs@1.4.7"></script>
  </head>

<script>
    const { PDFDocument } = PDFLib
    async function fillForm() {

      var myPdfInBytes = await document.getElementById("mypdf").files[0].arrayBuffer()
      const pdfDoc = await PDFDocument.load(myPdfInBytes)
      const form = pdfDoc.getForm()

      // Fill text fields
      form.getTextField('dateTaken').setText('hello this is my text')

      const pdfBytes = await pdfDoc.save()
      download(pdfBytes, "result.pdf", "application/pdf")
    }
  </script>

What actually happened?

The generated PDF shows the correct text, the correct font color and font size, but not the correct font.

All fonts are embedded:

Screen Shot 2023-01-13 at 10 36 02 am

What did you expect to happen?

I expected the text fields to be in the correct font, like when I filled the form out using Adobe Acrobat.

How can we reproduce the issue?

JSFIDDLE: https://jsfiddle.net/psyanite/9vdeq2nt/35/

Test PDF: test.pdf

Version

latest version

What environment are you running pdf-lib in?

Browser

Checklist

Additional Notes

No response

pietrondo commented 1 year ago

same problems... there is a solution?

coffedahl commented 1 year ago

Edit: I found the problem when i scanned trough the code i think.

When the PDFTextField.setText('string') command i called it markes the field as "dirty" that somehow tells the library that the field needs updating in styling. If you tried to add the font by yourself with PDFDocument.embedFont(font) and then try to update the apperance with PDFTextField.updateAppearances() it still marks it as dirty and changes the font.

The solution i found was that the updateAppearances(font) command marks it as clean again so as long as you call the updateAppearances() after you call the setText() the field is marked as clean and the program wont change your font

I dont think i have the coding skills neccessary to make a fix for it but this is a half solution until someone smarter can fix it :)

Example

// Imports
const { PDFDocument } = require('pdf-lib')
const { readFile } = require('fs/promises')
const fontkit = require('@pdf-lib/fontkit')
// Import pdf document
const document = await PDFDocument.load(await readFile('/path/to/file.pdf'))
// Create a custom font
document.registerFontkit(fontkit)
const custonFont = await document.embedFont(await readFile('/custom/font.ttf'))
// Get form and field
const form = document.getForm()
const titleField = form.getTextField('form identifier')
// Set the text and after update to font
titleField.setText(object.title)
titleField.updateAppearances(custonFont)
yepMad commented 1 year ago

I was doing textField.updateAppearances(font) and then textField.setAlignment(alignment). This caused the same problem. So I believe the final word is: just use updateAppearances after you did all setters

gioppoluca commented 9 months ago

I do not see the needed font even after the updateAppearances in the pdf the field is marked as using the right font, but opening the file I do not see the right font.

tacomanator commented 7 months ago

I'm having similar problem. Another issue mentioned it working only after form.flatten() is called. Unfortunately this makes the fields uneditable (additionally I am facing issue where text is garbled when using {subset: true} when embedding the font, but it's probably not related to use of flatten).

morbalint commented 6 months ago

I'm having the same issue. Thanks coffedahl for the workaround. FYI: calling form.updateFieldAppearances(pdfFont) on the entire form also solved the issue and maybe easier to achieve in some cases.

p3pp8 commented 3 months ago

Hello,

Facing same issue, i don't understand why if i have a font already embedded and used for the whole PDF and its forms fields i have to embed the same font again, this is clearly a BUG. Anyone knows how to force form text fields to use the same font and style already set for the whole PDF and its form fields without embed another one? The thing about dirty and clear is riducolous, why the lib should force using Helvetica when form fields already have their style set?