Which package do you use to generate PDFs in Meteor?

I needed this ability as well and resorted to the following tools to do the job.

  • create a template on the server which creates an SVG. I achieved this by using the cmather:handlebars-server plugin
  • use inkscape to convert the SVG to PDF inkscape --without-gui --file=fileName.svg --export-pdf=fileName.pdf

If you need to have a synchronous exec function you can wrap it like so var execSync = Meteor.wrapAsync(exec);

It works very nicely and fast.

Nice, how do you call that from the client ?

that code declares a route which returns a pdf, so you can call it / execute it with something like:

<a href="{{pathFor 'generatePDF'}}" class="btn btn-primary" target="_blank">Download PDF</a>

this will have a pdf open/download in a new window - works pretty well for me

@natestrauser

What version of PhantomJS were you using?

I’ve been attempting to use your snippet with little luck. It gives me ENOENT errors, when I try to generate a PDF, or says [Error: PhantomJS exited with return value 2] when I try to use the example snippet (to take a screenshot of google.com) from the webshot readme. I’ve tried building PhantomJS from source, installing it from the Ubuntu Software Center, installing it with npm, and using dfiscers’s Meteor package.

Either I’m out to lunch — I’m fairly new to Meteor and NodeJS, so it’s not impossible — or there’s some issue with the webshot/phantom combination I’m using. Right now I’m using bryanmorgan’s webshot meteor package. Any suggestions?

Thanks!

I’m using the dfischer:phantomjs package and "webshot":"0.15.4" installed via the npm package

works well for me locally and on modulus

1 Like

Thanks very much @natestrauser . That fixed the problem I was having, and I’m now able to generate PDFs. Unfortunately, I have another (perhaps trivial) problem: the client side template renders fine, but when I run webshot on the path, it only gets what’s hardcoded into the HTML, and the handlebars data goes missing. Any suggestions about getting around this? Thanks!

I’m using dfischer:phantomjs package and "webshot":"0.15.4" installed via the npm package. However, still getting [Error: PhantomJS exited with return value 2] on Ubuntu, and [Error: PhantomJS exited with return value 1] on Windows. Steps followed:

  1. Added the NPM package: meteor add meteorhacks:npm. This added the packages.json file to the project
  2. Added the Webshot package: meteor add bryanmorgan:webshot
  3. Added the PhantomJS package: meteor add dfischer:phantomjs
  4. Added NPM webshot package: "webshot":"0.15.4" to packages.json

@natestrauser @omphalosskeptic, could you pls see the above steps, and let me know what have I missed? Will be sooper helpful… thx

@omphalosskeptic probably the 5000ms render delay is not long enough - i switched my own app to take the snapshot based on a callback

var options = {
              takeShotOnCallback: true,
                "paperSize": {
                    "format": "Letter", 
                    "orientation": "portrait", 
                    "margin": "1cm"
                }
            };

then trigger the shot from the rendered callback


Template.TEMPLATE.onRendered(function() {
  if (_.isFunction(window.callPhantom))
    Meteor.setTimeout(function() {
      window.callPhantom('takeShot');
    }, 500);
});

this seems to work well for me


@pranab maybe try removing the bryanmorgan:webshot package? i don’t think you should need this as the sample code above is directly using the webshot npm. the other steps you are describing look good to me.

2 Likes

@natestrauser Thanks. Is there any chance you could put the whole thing in a Gist? Now I’m getting Uncaught TypeError: window.callPhantom is not a function on the client side. Sorry for all the questions :confused:

Are you attempting to generate a pdf from scratch or do you have a template that you fill in with data? Are you looking for a solution client or server side?

1 Like

@aadams Thanks for your reply.

  1. I have a template with data.
  2. Server or client. Any solution that works, and can be styled with css, is fine. Client-side would reduce the load on my hosting provider, but server-side would probably give more control, so it’s a toss-up.

Do you have something in mind? Using Webshot + Phantom for a glorified Print to File does seem a bit overkill…

I helped built a package to do this within a server side route https://atmospherejs.com/aadams/pdftk

I’m just trying to take a screenshot of a webpage and store it in a png or a jpg file. No template/css etc. As @omphalosskeptic mentioned, @natestrauser, it would be sooper helpful if you could put the whole thing in a step-by-step tutorial in a single post :slight_smile: Would be sooper helpful to us, and to the entire community!

@natestrauser I need to create a pdf and then save it in a zip file along with some images. I’ve got this method (using your code)

createPDF: function() {
    if (Meteor.isServer) {
        var webshot = Meteor.npmRequire('webshot');
        var fs = Npm.require('fs');
        var Future = Npm.require('fibers/future');
        var fut = new Future();

        var fileName = "google.pdf";
        var url = "google.com";

        var options = {
            renderDelay:5000,
            "paperSize": {
                "format": "Letter",
                "orientation": "portrait",
                "margin": "1cm"
            }
        };

        console.log("About to webshot");
        webshot(url, fileName, options, function(err) {
            fs.readFile(fileName, function (err,data) {
                if (err) {
                    return console.log(err);
                }

                fs.unlinkSync(fileName);
                fut.return(data);
            });
        });

       
        return fut.wait();
    }


}

I am calling the method on the client like so:

'click .download-case': function (e, tmpl) {
    e.preventDefault();

    var firm = Firms.findOne(this.firm_id);
    var zip = new JSZip();

    Meteor.call('createPDF', function (err, res) {
        if (err) {
            console.error(err);
        }
        console.log(res);
            zip.file("Hello.txt", "Hello World\n");
            var img = zip.folder("images");
            img.file("google.pdf", res, {base64: true});
            var content = zip.generate({type: "blob"});
            saveAs(content, "case.zip");
    });
}

I’m not actually wanting to save the home page of Google, but am instead trying to get the code to work before I implement taking a webshot of a client side template. However, I don’t have any idea how to send the new PDF from the server to the client… when I console.log the res object I just get a bunch of symbols in my console haha. I’m a noob when it comes to file system stuff. I’d appreciate any help you can provide.

@natestrauser
I’m getting this on my console.

/Users/sangyookim/.meteor/packages/meteor-tool/.1.1.3.1wysac9++os.osx.x86_64+web.browser+web.cordova/mt-os.osx.x86_64/dev_bundle/server-lib/node_modules/fibers/future.js:245
						throw(ex);
						      ^
TypeError: Object #<Object> has no method 'route'
    at app/modules/client_view/lib/savePDF.js:1:41
    at app/modules/client_view/lib/savePDF.js:36:3
    at /Users/sangyookim/Desktop/client-manager/.meteor/local/build/programs/server/boot.js:222:10
    at Array.forEach (native)
    at Function._.each._.forEach (/Users/sangyookim/.meteor/packages/meteor-tool/.1.1.3.1wysac9++os.osx.x86_64+web.browser+web.cordova/mt-os.osx.x86_64/dev_bundle/server-lib/node_modules/underscore/underscore.js:79:11)
    at /Users/sangyookim/Desktop/client-manager/.meteor/local/build/programs/server/boot.js:117:5
Exited with code: 8
Your application is crashing. Waiting for file change.

I did include webshot and phantomJS. I copied pasted your code into a separate savePDF.js in a lib folder.

this is the absolute link to my css
'Users/sangyookim/Desktop/client-manager/modules/client_view/style/client_view_print.css'

I do not know what is going wrong : (

I wanted to convert my markdown content to PDF and have it downloaded via the browser. This thread provided me with my start point so thanks everybody :thumbsup:

After a bit of investigation I found the npm package markdown-pdf to be an excellent choice for me and one that got me to a satisfactory working solution.

You can read a detailed description plus the Meteor ready code (coffeescript) on stack overflow: How do I generate and download a PDF from markdown using Meteor

2 Likes

I’m not sure but, after reading this post it seems like a big hazzle to export data to a pdf document?

I’ve recently picked up a project that demands an export function and am not entirely sure how to execute it.

Try this package, here’s the repo.

You should provide more details about your requirements, if it’s server side or client side.

The package that i’ve mentioned above is capable of generating pdf from data form submission, but the limitation of it is generate pdf on a table dynamically, actually, I have an open issue regarding this, issue#4.

1 Like

Cool, thanks!

Client-side should be good enough since all the client has requested is to be able to export a displayed list of items by the click of a button and send it through an email service.

The package you linked looks like it would do just the job and I’ll give it a try at the office tomorrow =) Thanks!

I am sure you have figured this out by now. Just in case for some one else who is thinking the same. The code assumes you have iron:router installed. If you don’t you can use the method @ryanswapp has mentioned.