【问题标题】:multipage document pdf-lib.js with node & express带有节点和快递的多页文档 pdf-lib.js
【发布时间】:2022-06-24 05:17:53
【问题描述】:

我正在尝试从我的文件系统上的模板创建一个多页文档,但我却在文档中的所有页面上出现了相同页面标题的奇怪行为。有什么想法我在这里做错了吗?

我不太明白的是我们添加页面的方式。为什么我们需要在下面的例子中引用newDoc,而我们在做await newDoc.copyPages(page, [0])?而不仅仅是newDoc.addPage(page)? 会不会是因为在复制数据流的时候两个页面的字段名相同,所以表单字段Title被覆盖了?

注意:我已经知道 StackOverflow 没有 pdf-lib.js.org 的标签,不要与其他 pdf 库混淆。

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 ]]

【问题讨论】:

  • How to Ask - 你想达到什么目的?可以分享一下模板示例吗?
  • 每个标题字段,每个页面上的不同文本
  • 看我的回答,我想这就是你要找的东西
  • @yeya 感谢您的回复。我试图为每一行加载一个新模板,我看到你所有页面只有一个模板。如果我将loadTemplate 函数移到for 循环中,它可能会起作用。您还需要将pdfSample.templateDoc 传递给addDocPage 函数吗?我已经有一段时间没有使用 JS 类了,但我会尝试一下,让你知道它是否有效。
  • 是的,您可以为每个文件调用 loadTemplate。不,您不需要填充 templateDoc,因为 loadTemplate 在每个 loadTemplate 上都保存到 this。如果它回答了您的问题,请接受答案。

标签: node.js express


【解决方案1】:

我没有你的模板文件,所以我不确定你想要实现什么。

copyPage 确实是必需的。

您应该在再次更改之前保存PDFDocument。

我试图重写你的代码,我忽略了 PDFName 和 PDFBool 行,但我相信你能明白。

const {PDFDocument} = require('pdf-lib');
const fs = require('fs');

const payload = {
    rows: [
        { id: 1, title: 'Foo', }, 
        { id: 2, title: 'Bar', },
    ], 
    formData: { hello: 'World', lorum: 'Ipsum', }
}

class PdfSample {

    async loadTemplate(templatePath) {
        const templateFile = fs.readFileSync(templatePath);
        const templateDoc = this.templateDoc = await PDFDocument.load(templateFile);
        this.templateForm = templateDoc.getForm();
    }

    async initDoc() {
        this.resultDoc = await PDFDocument.create();
    }

    fillTextField(fieldName, value) {
        const field = this.templateForm.getField(fieldName);
        field.setText(value);
    }

    get formFieldsNames() {
        return this.templateForm.getFields().map(field => field.getName());
    }

    async addDocPage() {
        const newPageBytes = await this.templateDoc.save();

        const newPage = await PDFDocument.load(newPageBytes);

        const [pageToAdd] = await this.resultDoc.copyPages(newPage, [0]);
        return this.resultDoc.addPage(pageToAdd);
    }

    async saveResult(outputPath) {

        const pdfBytes = await this.resultDoc.save();
        fs.writeFileSync(outputPath, pdfBytes);

    }
}

const pdfSample = new PdfSample();

(async () => {
    await pdfSample.initDoc();
    await pdfSample.loadTemplate('./pdfs_/OoPdfFormExample.pdf');

    console.log(pdfSample.formFieldsNames);

    for (const row of payload.rows) {
        pdfSample.fillTextField('Given Name Text Box', row.title);

        pdfSample.fillTextField('Family Name Text Box', payload.formData.hello);
        pdfSample.fillTextField('House nr Text Box', payload.formData.lorum);

        await pdfSample.addDocPage(pdfSample.templateDoc);
    }

    await pdfSample.saveResult('./pdfs_/result.pdf');
})();

样本表格来自this site

【讨论】:

  • 我没有使用这个基于类的代码,因为我无法让它工作,但答案就在这段代码中。您需要在复制到新页面之前保存页面字节const newPageBytes = await page.save(); const newPage = await PDFDocument.load(newPageBytes); const [firstPage] = await newDoc.copyPages(newPage, [0]); newDoc.addPage(firstPage)
  • 谢谢。赏金去哪儿了?
【解决方案2】:

您正在尝试创建一个包含两个名为 Title 的表单域的文档,每个页面上都有一个。这不起作用,两者都是相同的字段并显示相同的值。

而不是从模板中“复制”现有字段,您必须使用类似的东西

var newField = form.createTextField('Title' + dataRow.id);
newField.addToPage(firstPage, {x: ..., y: ...});
newField.setText(...);

【讨论】:

  • 我认为他正在尝试更改现有字段,而不是创建新字段。每行应位于不同的页面中。
猜你喜欢
  • 1970-01-01
  • 2020-05-13
  • 1970-01-01
  • 2015-04-19
  • 2022-09-27
  • 1970-01-01
  • 2016-07-23
  • 1970-01-01
  • 2018-05-11
相关资源
最近更新 更多