Hopding / pdf-lib

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

Error: Failed to parse PDF document (line:0 col:16 offset=8): No PDF header found #247

Closed Sampadaak2613 closed 4 years ago

Sampadaak2613 commented 4 years ago

Hi there,

I am using pdf-lib module to edit header and footer of the pdf file. I am using this module in spfx webpart. When user clicks on pdf file from document library, then custom header and footer should get added in the pdf. Below is the code snippet for the same but I am getting error as Error: Failed to parse PDF document (line:0 col:16 offset=8): No PDF header found.

const existingPdfBytes = file.pdfFileName; (Note - file.pdfFileName is the name of my pdf) // Load a PDFDocument from the existing PDF bytes const pdfDoc = await PDFDocument.load(existingPdfBytes) // Embed the Helvetica font const helveticaFont = await pdfDoc.embedFont(StandardFonts.Helvetica) // Get the first page of the document const pages = pdfDoc.getPages() const firstPage = pages[0] // Get the width and height of the first page const { width, height } = firstPage.getSize() // Draw a string of text diagonally across the first page firstPage.drawText('This text was added with JavaScript!', { x: 5, y: height / 2 + 300, size: 50, font: helveticaFont, color: rgb(0.95, 0.1, 0.1), rotate: degrees(-45), }) // Serialize the PDFDocument to bytes (a Uint8Array) const pdfBytes = await pdfDoc.save() } }

Task to achieve - Create spfx webpart. Add custom header and footer on click of pdf document. Reference link - https://github.com/Hopding/pdf-lib

Quick help would be appreciated.

Sampadaak2613 commented 4 years ago

Issue is closed. Converted pdf to arraybuffer and it worked.

const url = "https://XXXX.sharepoint.com/sites/XXXX/printToPdf/pdf_customHeaderFooter.pdf"; const existingPdfBytes = await fetch(url).then(res => res.arrayBuffer()) var bytes = new Uint8Array(existingPdfBytes); const pdfDoc = await PDFDocument.load(existingPdfBytes)

rtroop commented 2 years ago

So what of the "var bytes = new Unit8Array(existingPdfBytes)" line you referenced?

ccraig09 commented 2 years ago

So what of the "var bytes = new Unit8Array(existingPdfBytes)" line you referenced?

I am also curious, were you able to resolve?

rtroop commented 2 years ago

negative, I instantiated a shell script to handle what I needed but would have liked to use pdf lib

Alex-Anev commented 2 years ago

Unfortunately I ended up with the same error. When I run your code it tells me that PDFDocument.load() expects a Uint8 or ArrayBuffer. So I did this instead.

const url = '../dump/template.pdf'
const existingPdfBytes = await fetch(url).then((res) => res.arrayBuffer)
var bytes = new Uint8Array(existingPdfBytes)
const pdfDoc = await PDFDocument.load(bytes) // <- using bytes instead of existingPdfBytes
const pages = pdfDoc.getPages()
pages[0].drawText('asdadasdasd')
const pdfBytes = await pdfDoc.save()

This unfortunately gives me the same error

shadoath commented 1 year ago

I'm still stuck on this. The compiling of nextjs breaks something with loading the PDF file and I can't get it to load a pdf from a url.

shadoath commented 1 year ago

Somehow I got a very different result when running in nextjs dev vs running after a nextjs build when using the saveBase64 method.

  const save = await currentPdf.save()
  const saveBase64 = await currentPdf.saveAsBase64()
  console.log({ save, saveBase64 })
  //  "saveBase64" has a value of "T0Y="
  // Load it back in as "save" works
  currentPdf = await PDFDocument.load(save)
King-Klauz commented 1 year ago

I had the same error, in my case the solution was just to import the .PDF file outside the async function (I'm using pdf-lib), getting this:

import pdf from '../assets/docs/plano_de_trabalho_teletrabalho_ordinario_inicial_e_renovacao.pdf' async function modifyPdf() { const url = pdf const existingPdfBytes = await fetch(url).then(res => res.arrayBuffer()) const pdfDoc = await PDFDocument.load(existingPdfBytes) const helveticaFont = await pdfDoc.embedFont(StandardFonts.Helvetica) const pages = pdfDoc.getPages() const firstPage = pages[0] const secondPage = pages[1] const { width, height } = firstPage.getSize() }

xing-lin commented 10 months ago

I have also encountered this issue before, but I managed to solve it. The key to the problem is the file path referenced in the fetch, it should not be a relative path. I moved the PDF file to the public folder, and the response returned the correct content instead of HTML. You can view the response in devtool network to check whether the requested file path is correct.

- const url = './assets/sample.pdf';
+ const url = '/sample.pdf';
const existingPdfBytes = await fetch(url).then((res) => res.arrayBuffer());
const bytes = new Uint8Array(existingPdfBytes);
const pdfDoc = await PDFDocument.load(bytes);
lucaslimafons commented 5 months ago

Issue is closed. Converted pdf to arraybuffer and it worked.

const url = "https://XXXX.sharepoint.com/sites/XXXX/printToPdf/pdf_customHeaderFooter.pdf"; const existingPdfBytes = await fetch(url).then(res => res.arrayBuffer()) var bytes = new Uint8Array(existingPdfBytes); const pdfDoc = await PDFDocument.load(existingPdfBytes)

Thanks man!!!

anisharya16 commented 4 months ago

Did you write unit test for this? I am getting file.arrayBuffer() is not a function. Anyone?

zhuzaiye commented 2 months ago

If use puppeteer convert the html to pdf file which will be stored in local OS or Docker, pdf-lib using the fs.readFileSync, and the merge local pdf-files to one-pdf which can be upload the AWS s3 successfully. Codes like the follwoing:

const mergedPdf = await PDFDocument.create();
for (let j = 0; j < examStudents.length; j++) {
    const examStudent = examStudents[j];
    const htmlUrl = `${htmlUrlDomain}?token=${task.token_code}&exam_id=${task.exam_id}&student_id=${examStudent.student_id}`;
    const pdfName = `${examStudent.username}_${examStudent.remarks}`
    const pdfPath = await htmlToPdf(htmlUrl, taskMergePdfDir, pdfName, browser);
    if (pdfPath) {
        const existingPdfBytes = fs.readFileSync(pdfPath);
        const document = await PDFDocument.load(existingPdfBytes);
        const copiedPages = await mergedPdf.copyPages(document, document.getPageIndices());
    copiedPages.forEach((page) => mergedPdf.addPage(page)); 
    }
}
const mergedPdfFile = await mergedPdf.save();
fs.writeFileSync(taskMergePdfPath, mergedPdfFile);