vbuch / node-signpdf

Simple signing of PDFs in node.
MIT License
728 stars 178 forks source link

Error when using node JS pdf-lib: Expected xref at NaN but found other content #249

Open CristiCh opened 7 months ago

CristiCh commented 7 months ago

I am using pdf-lib in a node JS project and I get the same error when trying to modify the pdf. Does anyone know why this is happening? Thanks!

exports.transformPdf = onObjectFinalized({}, async (event) => {
    const bucket = admin.storage().bucket()
    const fileBucket = event.data.bucket; // Storage bucket containing the file.
    const filePath = event.data.name; // File path in the bucket.
    const contentType = event.data.contentType; // File content type.
    console.log(filePath);
    const file = await bucket.file(filePath);
    const fileDir = path.dirname(filePath);
    const fileBasename = path.basename(filePath);
    console.log(fileDir);
    if (fileDir != 'uploads') { return; }

    getRawBody(file.createReadStream())
    .then(async (pdfBuffer) => {
        console.log(pdfBuffer.length + ' bytes submitted');
        const pdfDoc = await PDFDocument.load(pdfBuffer, { capNumbers: true });
        console.log(pdfDoc);

        const timesRomanFont = await pdfDoc.embedFont(StandardFonts.TimesRoman);
        // const page = pdfDoc.addPage();
        const pagesCount = pdfDoc.getPageCount();
        const page = pdfDoc.getPage(pagesCount-1);
        const { width, height } = page.getSize();
        const fontSize = 20;
        page.drawText('Signed By Cristi C.', {
            x: width - 10 * fontSize,
            y: height - 40 * fontSize,
            size: fontSize,
            font: timesRomanFont,
            color: rgb(0, 0.53, 0.71),
        });
        const pdfBytes = await pdfDoc.save();
        bucket.file('transformed/'+fileBasename).save(pdfBytes).then(function (res) {}); //Save file in folder signed with the original name
        console.log('Document transformed');
    });

The error is: Expected xref at NaN but found other content

Thanks!

Vanderson159 commented 1 month ago

I also came across this problem, did you find any solution?

exilonX commented 1 week ago

I'm having the same issue with PDF version 1.7 exported from sql reporting services.

Seems that the issue comes from how the trailer information is interpreted

1.4 from the contributing.pdf example :

trailer
<</Size 25
/Root 12 0 R
/Info 1 0 R>>
startxref
72203
%%EOF

1.7 example from my pdf

<< /Type /XRef 
/Index [0 50]
/W [1 4 3]
/Filter /FlateDecode /Size 50 /Length 195 /Root 47 0 R /Info 48 0 R >>
stream
X   c`
endstream
endobj
startxref
444002
%%EOF

SignPdfError: Expected xref at NaN but found other content. at getXref (C:\Users\ionel\Desktop\code\reges\reges-process\node_modules\@signpdf\placeholder-plain\dist\readRefTable.js:26:13) at getFullXref (C:\Users\ionel\Desktop\code\reges\reges-process\node_modules\@signpdf\placeholder-plain\dist\readRefTable.js:75:25) at getFullXrefTable (C:\Users\ionel\Desktop\code\reges\reges-process\node_modules\@signpdf\placeholder-plain\dist\readRefTable.js:90:10) at readRefTable (C:\Users\ionel\Desktop\code\reges\reges-process\node_modules\@signpdf\placeholder-plain\dist\readRefTable.js:106:25) at readPdf (C:\Users\ionel\Desktop\code\reges\reges-process\node_modules\@signpdf\placeholder-plain\dist\readPdf.js:56:46) at plainAddPlaceholder (C:\Users\ionel\Desktop\code\reges\reges-process\node_modules\@signpdf\placeholder-plain\dist\plainAddPlaceholder.js:70:37) at work (C:\Users\ionel\Desktop\code\reges\reges-process\scripts\test.js:32:28) {

My typescript code:

async signPdf(pdfBuffer: Buffer, pdfId: string): Promise<Buffer> {
    // Step 3: Add a signature placeholder using pdfkitAddPlaceholder
    try {
      const normalized = await this.addXrefTable(pdfBuffer);
      console.log(normalized.lastIndexOf('startxref'));
      const pdfWithPlaceholder = plainAddPlaceholder({
        pdfBuffer: normalized,
        reason: 'Document digitally signed',
        location: 'Location',
        contactInfo: 'contact@example.com',
        name: 'Signature',
        widgetRect: [100, 100, 300, 200], // Adjust coordinates as needed
        // signatureLength: 8192,
      });

      // Step 4: Generate signature hash from the external signing service
      const signatureHash = await this.generateSignature(pdfBuffer, pdfId);

      const signPdf = new SignPdf();
      const signedPdf = signPdf.sign(pdfWithPlaceholder, signatureHash);

      return signedPdf;
    } catch (error) {
      console.error('Error adding signature placeholder:', error);
      console.error(error);
    }
  }