javascript - Any HTML to PDF renderers that offer adjustable dpi, selectable text, and CSS support?

702

I am building a specification sheet for a client with Vue and need to make viewable and printable PDFs.

I've was dabbling with Puppeteer, but from what I've came across online (correct me if I'm wrong), Puppeteer does not support selectable text nor adjusting the DPI of PDFs. I am also having an issue where Puppeteer renders the PDF in low quality - where the font is fuzzy/without anti-aliasing.

What (if any) PDF renderers are there that will

  • render an HTML page to PDF*
  • support selectable text*
  • allow for adjustable DPI*
  • CSS Support* (i.e. it will render the CSS)
  • can accept URL as parameter
  • allow for multiple pages
  • and runs in Node/Javascript (optional)

Edit: The best I've found so far was with eKoopmans html2pdf, but unfortunately, it doesn't allow for selectable text (as far as I can tell) - which is a deal breaker.

There doesn't seem to be such a package for javascript, so if there is one in PHP or C++ - it will also be considered.

611

Answer

Solution:

The best solution I've found is ebdrup/html2pdf.it. You can find a live demo here. It makes use of Phantom JS and would seem to support every feature I need, with the exception of page breaks which I haven't tested yet.

The next hurdle is to figure out how to extract the necessary functions so I can use the features in my script without having to pass GET query strings (which deserves it's own question).

Edit: An issue I didn't realize is there doesn't seem to be a way to delay the PDF generation, which is an issue since I am using Vue and the page has to build first.

Edit 2020:

Since this post, I've revisited Puppeteer and it handles everything that I need.

Adjust DPI

You can adjust the DPI by setting the page viewport.

Puppeteer equates 1in = 96px. ctrl+f forunitToPixels

Example.

const browser = puppeteer.launch();

const page = await browser.newPage();

// Multiply the desired length in inches by 96
await page.setViewport({ 
   width: 8.5 * 96,
   height: 11 * 96,
});

Wait for...

You can wait for a selector before finishing. In my case, I append a class to the body for Puppeteer to listen and capture.

const browser = puppeteer.launch();

const page = await browser.newPage();

const html = buildDOM();  // Has js that appends .finished class to <body>

await page.setContent(html);

await page.waitForSelector('.finished');

People are also looking for solutions to the problem: io - php - I/O streaming

Source

Didn't find the answer?

Our community is visited by hundreds of web development professionals every day. Ask your question and get a quick answer for free.

Ask a Question

Write quick answer

Do you know the answer to this question? Write a quick response to it. With your help, we will make our community stronger.

Similar questions

Find the answer in similar questions on our website.