Is it possible to use PhantomJS and Node to dynamically generate PDFs from templates?

10,130

Solution 1

EJS seems to run fine in PhantomJS (after installing the path module). To load a page in PhantomJS given a string of HTML, do page.content = '<html><head>...';.

npm install ejs and npm install path, then:

var ejs = require('ejs'),
    page = require('webpage').create();

var html = ejs.render('<h1><%= title %></h1>', {
    title: 'wow'
});

page.content = html;
page.render('test.pdf');
phantom.exit();

(Run this script with phantomjs, not node.)

Solution 2

I am going to post an answer for anyone trying to do something similar with node-phantom. Because node-phantom controls the local installation of PhantomJS, it must use asynchronous methods for everything even when the corresponding PhantomJS operation is synchronous. When setting the content for a page to be rendered in PhantomJS you can simply do:

page.content = '<h1>Some Markup</h1>';
page.render('page.pdf');

However, using the node-phantom module within node you must use the page.set method. This is the code I used below.

'use strict';

var phantom = require('node-phantom');

var html = '<!DOCTYPE html><html><head><title>My Webpage</title></head>' +
    '<body><h1>My Webpage</h1><p>This is my webpage. I hope you like it' +
    '!</body></html>';

phantom.create(function (error, ph) {
    ph.createPage(function (error, page) {
        page.set('content', html, function (error) {

            if (error) {
                console.log('Error setting content: %s', error);
            } else {
                page.render('page.pdf', function (error) {
                    if (error) console.log('Error rendering PDF: %s', error);
                });
            }

            ph.exit();
        });
    });
});

Solution 3

A really easy solution to this problem is the node-webshot module - you can put raw html directly in as an argument and it prints the pdf directly.

Share:
10,130
Cory Gross
Author by

Cory Gross

Senior engineer at PlayStation

Updated on June 12, 2022

Comments

  • Cory Gross
    Cory Gross almost 2 years

    Background / Need

    I am working with a group on a web application using Node.JS and Express. We need to be able to generate reports which can be printed as hard copies and also hard copy forms. Preferably we'd like to dynamically generate PDFs on the server for both reports and hand written forms. We're currently using EJS templates on the server.

    Options

    I was thinking that it would be convenient to be able to use templates to be able to build forms/reports and generate a PDF from the resulting HTML, however my options to do this appear limited as far as I can find. I have looked at two different possible solutions:

    EDIT: I found another Node.JS module which is able to generate PDFs from HTML called node-wkhtml which relies on wkhtmltopdf. I am now comparing using node-phantom and node-wkhtml. I have been able to generate PDFs on a Node server with both of these and they both appear to be capable of doing what I need.

    I have seen some examples of using PhantomJS to render PDF documents from websites, but all of the examples I have seen use a URL and do not feed it a string of HTML. I am not sure if I could make this work with templates in order to dynamically generate PDF reports.

    When a request for a report comes in I was hoping to generate HTML from an EJS template, and use that to generate a PDF. Is there anyway for me to use Phantom to dynamically create a page completely on the server without making a request?

    My other option is to use PDFkit which allows dynamic generation of PDFs, but it is a canvas-like API and doesn't really support any notion of templates as far as I can tell.

    The Question

    Does anyone know if I can use PhantomJS with Node to dynamically generate PDFs from HTML generated from a template? Or does anyone know any other solutions I can use to generate and serve printable reports/forms from my Node/Express back-end.

  • Cory Gross
    Cory Gross over 10 years
    Thanks, I had tried setting page.content like this on my Node server using (node-phantom) which controls the local PhantomJS installation. There were no errors thrown setting the content and rendering it, however the PDF was just a single blank page. In order to set the content with node-phantom you must use the async function page.set.
  • CrazyNooB
    CrazyNooB over 10 years
    I m sending a dynamic html which has external css, hence using "set" I am unable to apply my css to the pdf generated. Any suggestions please.
  • Foreever
    Foreever almost 10 years
    The document provides API's to generate only images, not PDFs.