pdf-lib icon indicating copy to clipboard operation
pdf-lib copied to clipboard

Duplicate field names after copying & adding pages

Open conor909 opened this issue 2 years ago • 1 comments

What were you trying to do?

Im trying to create a multi-page document from templates on my file system, but I'm getting strange behaviour of the same page title across all pages in the document instead, instead of the correct title of the current data row in the loop.

I've posted on StackOverflow, but I've been made aware that a SO tag for this library doesn't exist. Link to SO question

How did you attempt to do it?

From the example below you can see how I attempt to create the pages, but something I don't quite get, is the way we add pages. Why do we need to reference newDoc, when we do await newDoc.copyPages(page, [0])? Instead of just newDoc.addPage(page)? Would it be that the form field named Title is being overwritten because both pages have the same field name during the copying of data streams?

What actually happened?

From my example shown I get a 2 page document, but with the same titles on both pages regardless of the data rows being used to create each page. Both titles read "Foo".

[[ title: Foo, Hello: World ], [title: Foo, Lorum: Ipsum ]]

What did you expect to happen?

From my example shown I expect a 2 page document with 2 different titles printed on each page, "Foo" & "Bar".

[[ title: Foo, Hello: World ], [title: Bar, Lorum: Ipsum ]]

How can we reproduce the issue?

const payload = {
  rows: [{
    id: 1,
    title: 'Foo',

  },{
    id: 2,
    title: 'Bar'
  },
  formData: {
    hello: 'World',
    lorum: 'Ipsum'
  }
  ]
}

const makePdf = async (payload) => {
  const newDoc = await PDFDocument.create()
  newDoc.getForm().acroForm.dict.set(PDFName.of('NeedAppearances'), PDFBool.True)
  for (const row of payload.rows) {
    await addPage(row, payload.formData, newDoc)
  }
  return newDoc
}

const addPage = async (dataRow, formData, newDoc) => {
  const rowId = dataRow.id
  let templateName
  switch(true) {
    case (rowId === 1):
      templateName = 'foo'
    break
    case (rowId === 2):
      templateName = 'bar'
    break
  }
  const templatePath = path.join(__dirname, `../templates/pdfs_/${templateName}.pdf`)
  const template = await fs.readFileSync(templatePath)
  const page = await PDFDocument.load(template)
  const form = page.getForm()
  form.acroForm.dict.set(PDFName.of('NeedAppearances'), PDFBool.True)
  switch(templateName) {
    case 'foo':
      foo(form, formData)
    break
    case 'bar':
      bar(form, formData)
  }
  // dataRow.title logs correct strings ie: 'Foo' & 'Bar'
  form.getField('Title').setText(dataRow.title)
  const [firstPage] = await newDoc.copyPages(page, [0])
  return await newDoc.addPage(firstPage)
}

const bar = (form, formData) => {
  form.getField('Lorum').setText(formData.lorum)
}

const foo = (form, payload) => {
  form.getField('Hello').setText(formData.hello)
}

return makePdf(payload)

// Produces 2 page pdf with the same title
// [[ title: Foo, Hello: World ], [title: Foo, Lorum: Ipsum ]]

Version

1.17.1

What environment are you running pdf-lib in?

Node

Checklist

  • [X] My report includes a Short, Self Contained, Correct (Compilable) Example.
  • [X] I have attached all PDFs, images, and other files needed to run my SSCCE.

Additional Notes

No response

conor909 avatar May 23 '22 17:05 conor909

I ran into a similar issue, and my issue was solved by saving the page and reloading it before merging it to the new pdf. Maybe this will work for you? #1250

sPesce avatar Jun 03 '22 15:06 sPesce