This is a very good question. ongoworks:pdf is ok, but there are problems with styling (probably because of jsPDF). I am afraid that it needs some server side rendering with phantomjs or something like that.
Here is a little snippet I recently came up with when working with a client.
this.route('generatePDF', {
path: '/api/generatePDF',
where: 'server',
action: function() {
var webshot = Meteor.npmRequire('webshot');
var fs = Npm.require('fs');
var fut = new Future();
var fileName = "generated_"+Random.id()+".pdf";
var url = Meteor.absoluteUrl(<path to a client side route with print css>);
var options = {
renderDelay:5000,
"paperSize": {
"format": "Letter",
"orientation": "portrait",
"margin": "1cm"
}
};
webshot(url, fileName, options, function(err) {
fs.readFile(fileName, function (err,data) {
if (err) {
return console.log(err);
}
fs.unlinkSync(fileName);
fut.return(data);
});
});
this.response.writeHead(200, {'Content-Type': 'application/pdf',"Content-Disposition": "attachment; filename=generated.pdf"});
this.response.end(fut.wait());
}
});
works well in practice for the use case i had (generating nicely formatted certificates) and it was pretty easy to style as desired using print css on the route we wanted to make the pdf from
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 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:
Added the NPM package: meteor add meteorhacks:npm. This added the packages.json file to the project
Added the Webshot package: meteor add bryanmorgan:webshot
Added the PhantomJS package: meteor add dfischer:phantomjs
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
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.
@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
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?
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’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 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.
/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'