PDFNet.PDFDoc.createFromFilePath Failure on 9.1.0

Product: @pdftron/pdfnet-node

Product Version: v9.1.0

Please give a brief summary of your issue:
PDFNet.PDFDoc.createFromFilePath fails with a proper path of a png that was converted into PDF file.

Please describe your issue and provide steps to reproduce it:

  1. Create a png file with a text annotation
  2. Convert the png file to a pdf file
  3. Load the converted pdf file with PDFNet.PDFDoc.createFromFilePath

See the following error:
Assertion failed: (m_eventListeners.find(“message”) != m_eventListeners.cend()), function PostMessage, file …/…/…/Node.js/WorkerInstance.cpp, line 30.

Please provide a link to a minimal sample where the issue is reproducible:

const tempConvertedFile = tmp.fileSync({ postfix: ".pdf" });

if (await PDFNet.Convert.requiresPrinter(tempFile.name)) {
          throw new Error(`${path} should be converted using PDFNet printer`);
}
        const pdf = await PDFNet.PDFDoc.create();
        await pdf.initSecurityHandler();
        await PDFNet.Convert.toPdf(pdf, tempFile.name);
        await pdf.save(
            tempConvertedFile.name,
            PDFNet.SDFDoc.SaveOptions.e_linearized
        );

let pdfDoc;
if (tempConvertedFile) {
          //Error occurs loading file from path
          pdfDoc = await PDFNet.PDFDoc.createFromFilePath(
            tempConvertedFile.name
          );
}
1 Like

I modified our AddImageTest sample to try and reproduce the issue, but everything worked fine.

Attached is the code.
AddImageTest.js (1.4 KB)

Can you reproduce the issue using the modified AddImageTest sample?

1 Like

I can’t seem to download that file, it’s sending me to a page that reads “The change you wanted was rejected.” Maybe I’m doing somethign wrong

1 Like

Sorry about that. Below is all the code inline.

//---------------------------------------------------------------------------------------
// Copyright (c) 2001-2021 by PDFTron Systems Inc. All Rights Reserved.
// Consult legal.txt regarding legal and license information.
//---------------------------------------------------------------------------------------


const { PDFNet } = require('@pdftron/pdfnet-node');
const PDFTronLicense = require('../LicenseKey/LicenseKey');

((exports) => {

  exports.runAddImageTest = () => {

    const main = async() => {
      try {
        const inputURL = '../TestFiles/';
        const pdf = await PDFNet.PDFDoc.create();
        await pdf.initSecurityHandler();
        await PDFNet.Convert.toPdf(pdf, inputURL + 'peppers.jpg');
        await pdf.save(
            inputURL + 'Output/peppers.jpg.pdf',
            PDFNet.SDFDoc.SaveOptions.e_linearized
        );
        let pdfDoc;
        if (true) {
                  //Error occurs loading file from path
                  pdfDoc = await PDFNet.PDFDoc.createFromFilePath(inputURL + 'Output/peppers.jpg.pdf');
        }

        console.log('Done. Result saved in addimage.pdf...');
      } catch (err) {
        console.log(err);
      }
    };
    PDFNet.runWithCleanup(main, PDFTronLicense.Key).catch(function(error){console.log('Error: ' + JSON.stringify(error));}).then(function(){return PDFNet.shutdown();});
  };
  exports.runAddImageTest();
})(exports);
// eslint-disable-next-line spaced-comment
//# sourceURL=AddImageTest.js
1 Like

Thank you! Let me test it out, I’ll let you know what happens

1 Like

Sorry about the delayed response, we did the same as you gave in the example and we are seeing the same issue as above. Has the way pathing works for createFromFilePath changed in any way?

1 Like

we did the same as you gave in the example and we are seeing the same issue as above.

You mean that code failed loading a PDF created from the peppers.jpg?
If yes, please provide full exception message.

Or you made changes to the code?
If yes, please provide the changes and the input PDF or image file you used.

Assertion failed: (m_eventListeners.find(“message”) != m_eventListeners.cend()), function PostMessage, file …/…/…/Node.js/WorkerInstance.cpp, line 30.

Do you have any additional diagnostic information?
I don’t think WorkerInstance.cpp is our code.

1 Like

Hey Ryan, I went and did some additional research and found that the conversion and PDFNet.PDFDoc.createFromFilePath did not actually have any issues. It seemed to be that we had multiple calls of PDFNet.runWithCleanup and PDFNet.shutdown(); for a single file which may have caused an issue when we were working with temporary files.

Is there a general best practice how often we should use PDFNet.shutdown?

We had a function that looks like the following:

const convertToPDF = async (): Promise<FileResult> => {
        const tempConvertedFile = await tmpFile({ postfix: ".pdf" });
        const run = async () => {
          if (await PDFNet.Convert.requiresPrinter(tempFile.path)) {
            throw new Error(`${path} should be converted using PDFNet printer`);
          }
          const pdf = await PDFNet.PDFDoc.create();
          await pdf.initSecurityHandler();
          await PDFNet.Convert.toPdf(pdf, tempFile.path);
          await pdf.save(
            tempConvertedFile.path,
            PDFNet.SDFDoc.SaveOptions.e_linearized
          );
        };
        await PDFNet.runWithCleanup(run, process.env.PDF_NET_LICENSE);
        PDFNet.shutdown();
        return tempConvertedFile;
      };

And a similar function for Merging Annotations to PDF files and it resulted in calling PDFNet.runWithCleanup and shutdown 3-4 times per file. We were able to solve this issue by limiting the number of calls to those functions

1 Like

Let me know if this guide answers your question.

1 Like

This does give insight into how we should run PDFTron, for the case of multithreading PDFTron (convert and merging multiple instances of PDFTron at a time, there a preferred method of how this should be done? We are guessing this issue might stem from the fact that we are multithreading PDFTron

1 Like

By multi-threading you mean javascript promises? Or do you mean workers?

If you are sharing a since PDFDoc object/instance across threads then you need to do locking.

Otherwise, if each thread has its own PDFDoc object then there should not be any issues.

If the above does not help, then ideally you could modify one of our samples to reproduce the issue you are encountering (and update us on what the issue is).

1 Like

We are using a package called p-limit which runs multiple promise-returning & async functions with limited concurrency. I’ll take a look at locking and see if the issue still persists, thank you!

1 Like

I’ll take a look at locking and see if the issue still persists

In case it wasn’t clear before, you only need to do PDFDoc Locking if you are using single PDFDoc instance across multiple threads.

The normal use case is just processing a single PDFDoc instance on a single thread is fine.

1 Like

I think we’ve deduced what the issue was, we found that we had to initialize PDFNet for every parallel task and we didnt see the issue occuring anymore, thank you for the documentations above they helped solve the problem. We did this along the lines of

const run = async () => {
  PDFNet.initialize(process.env.PDF_NET_LICENSE);
  let pdf = await PDFNet.PDFDoc.create();
    try {
            // .. pdf operations
  } catch (error: any) {
    console.log(error);
    await logErrorInBackgroundJob(error, {
      contexts: {
        file,
      },
    });
    } finally {
      await pdf.destroy();
    }
}
await PDFNet.runWithCleanup(run, process.env.PDF_NET_LICENSE);
 PDFNet.shutdown();
1 Like

I had to use a semaphore to ensure only one usage at a time - I’m called from a React frontend and React always renders twice in development…

1 Like