Pdf-lib: How to fill form checkbox fields

Created on 14 May 2019  路  9Comments  路  Source: Hopding/pdf-lib

Can pdf-lib be used to programmatically fill out checkbox fields in a template PDF?
Analog to #48

Most helpful comment

pdf-lib now has form creation and filling APIs that should be used instead of the above example(s). See the form filling JSFiddle for a working example. Additional information is available in the README and API docs. The PDFCheckBox.check method is of particular relevance to this issue.

All 9 comments

Update (9/16/2020)

pdf-lib now has form creation and filling APIs that should be used instead of the below example(s). See the form filling JSFiddle for a working example. Additional information is available in the README and API docs. The PDFCheckBox.check method is of particular relevance to this issue.

Original

Hello @pammann-work!

I created an example script demonstrating how to do this: pdf-lib_check_box_form_fill_example.zip

You can run the script with the following commands (you may have to tweak them a bit if you're running Windows):

unzip pdf-lib_check_box_form_fill_example.zip
cd pdf-lib_check_box_form_fill_example
npm install
node index.js

Here's the input PDF: simple_form.pdf
And here's the output: filled_form.pdf

Here's a snippet from the script showing the gist of the process:

const getAcroFields = pdfDoc => {
  if (!pdfDoc.catalog.getMaybe('AcroForm')) return [];
  const acroForm = pdfDoc.index.lookup(pdfDoc.catalog.get('AcroForm'));

  if (!acroForm.getMaybe('Fields')) return [];
  const acroFields = pdfDoc.index.lookup(acroForm.get('Fields'));

  return acroFields.array.map(pdfDoc.index.lookup);
};

const findAcroFieldByName = (pdfDoc, name) => {
  const acroFields = getAcroFields(pdfDoc);
  return acroFields.find(acroField => {
    const fieldName = acroField.getMaybe('T');
    return !!fieldName && fieldName.string === name;
  });
};

const pdfDoc = PDFDocumentFactory.load(fs.readFileSync('./simple_form.pdf'));

const fooCheckBox = findAcroFieldByName(pdfDoc, 'FooCheckBox');
const barCheckBox = findAcroFieldByName(pdfDoc, 'BarCheckBox');
const quxCheckBox = findAcroFieldByName(pdfDoc, 'QuxCheckBox');
const bazCheckBox = findAcroFieldByName(pdfDoc, 'BazCheckBox');

console.log('Selecting "Foo" and "Qux" boxes...');
fooCheckBox.set('V', PDFName.from('Yes'));
quxCheckBox.set('V', PDFName.from('Yes'));

console.log('Saving modified PDF...');
const pdfBytes = PDFDocumentWriter.saveToBytes(pdfDoc);
fs.writeFileSync('./filled_form.pdf', pdfBytes);

console.log('Filled-in Form Written To ./filled_form.pdf');

I hope this helps! Please let me know if you have any additional questions.

@Hopding Thank you very much for this example, this helped a lot.

When i look at your filled_form.pdf, i do not see the checkbox checked (in Acrobat Reader + Firefox). I fiddled a bit around and found out that i need to set 'AS' as well:

this works:

fooCheckBox.set('V', PDFName.from('Yes'));
fooCheckBox.set('AS', PDFName.from('Yes'));

PS: I am using v0.6.2 of pdf-lib

I updated the example on https://github.com/Hopding/pdf-lib/issues/109#issuecomment-493761539 to v.1.1.1. to learn this library.
pdf-lib_check_box_form_fill_example2.zip
Please correct if I am missing something.
Thanks.

Hi, i can check my checkboxs with
field.set(PDFName.of('V'), PDFName.of('Yes'))
field.set(PDFName.of('AS'), PDFName.of('Yes'));
When i open the pdf locally, the checkbox are checked.
But when im sending the pdf by mail or other, i cant see the checkbox checked.

Do you have the same issue ?
Im using v1.1.1

@astanet thank you for updating the example!

@zepekenio It looks like I omitted a step in my original example. It's also necessary to set the NeedAppearances field on the AcroForm (like I did here). Here's an updated version of the example for version 1.3.0 that correctly sets the NeedAppearances field:

pdf-lib_check_box_form_fill_example3.zip

And here's the gist of the script:

const fs = require('fs');
const { PDFDocument, PDFName, PDFBool, PDFArray } = require('pdf-lib');

const getAcroForm = pdfDoc => {
  return pdfDoc.catalog.lookup(PDFName.of('AcroForm'));
};

const getAcroFields = pdfDoc => {
  const acroForm = getAcroForm(pdfDoc);
  if (!acroForm) return [];

  const fieldRefs = acroForm.lookupMaybe(PDFName.of('Fields'), PDFArray);
  if (!fieldRefs) return [];

  const fields = new Array(fieldRefs.size());
  for (let idx = 0, len = fieldRefs.size(); idx < len; idx++) {
    fields[idx] = fieldRefs.lookup(idx);
  }
  return fields;
};

const findAcroFieldByName = (pdfDoc, name) => {
  const acroFields = getAcroFields(pdfDoc);
  return acroFields.find(acroField => {
    const fieldName = acroField.get(PDFName.of('T'));
    return !!fieldName && fieldName.value === name;
  });
};

const pdfDoc = await PDFDocument.load(fs.readFileSync('./simple_form.pdf'));

const acroForm = getAcroForm(pdfDoc);
acroForm.set(PDFName.of('NeedAppearances'), PDFBool.True);

const fooCheckBox = findAcroFieldByName(pdfDoc, 'FooCheckBox');
const quxCheckBox = findAcroFieldByName(pdfDoc, 'QuxCheckBox');

console.log('Selecting "Foo" and "Qux" boxes...');
fooCheckBox.set(PDFName.of('V'), PDFName.of('Yes'));
fooCheckBox.set(PDFName.of('AS'), PDFName.of('Yes'));
quxCheckBox.set(PDFName.of('V'), PDFName.of('Yes'));
quxCheckBox.set(PDFName.of('AS'), PDFName.of('Yes'));

console.log('Saving modified PDF...');
const pdfBytes = await pdfDoc.save();
fs.writeFileSync('./filled_form.pdf', pdfBytes);

@Hopding I am following the instructions above and my code looks like this:

myCheckBox.set(PDFName.of('V'), PDFName.of('Yes'));
myCheckBox.set(PDFName.of('AS'), PDFName.of('Yes'));

I am also doing acroForm.set(PDFName.of('NeedAppearances'), PDFBool.True);

However, my saved check box is not checked:
image

Setting text field works fine, it is only setting of checkboxes which doesn't seem to work.

Are the instructions above no longer accurate?

We just ended getting the Rectangle dimensions of the field and putting a text 'x' over the selected checkbox.

pdf-lib now has form creation and filling APIs that should be used instead of the above example(s). See the form filling JSFiddle for a working example. Additional information is available in the README and API docs. The PDFCheckBox.check method is of particular relevance to this issue.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

kevinswartz picture kevinswartz  路  8Comments

jboxxx picture jboxxx  路  4Comments

ihmc3jn09hk picture ihmc3jn09hk  路  4Comments

msvargas picture msvargas  路  6Comments

zimt28 picture zimt28  路  5Comments