├── .gitignore ├── .npmignore ├── README.md ├── bin ├── phantomjs-linux └── phantomjs-mac ├── event.json ├── example └── example.html ├── handler.js ├── lib └── rasterize.js ├── package.json └── serverless.yml /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .serverless 3 | .DS_Store 4 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | # package directories 2 | node_modules 3 | jspm_packages 4 | 5 | # Serverless directories 6 | .serverless -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | serverless-html-pdf 2 | =================== 3 | 4 | This lambda function takes a HTML page and convert it into printable PDF using PhantomJS and the rasterize script packaged in the PhantomJS examples. 5 | 6 | ### Setup 7 | 8 | For deployment 9 | ``` 10 | sls deploy 11 | ``` 12 | -------------------------------------------------------------------------------- /bin/phantomjs-linux: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/calvintychan/serverless-html-pdf/37528562fbf29134ab7bea7d29c0bcd686c25053/bin/phantomjs-linux -------------------------------------------------------------------------------- /bin/phantomjs-mac: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/calvintychan/serverless-html-pdf/37528562fbf29134ab7bea7d29c0bcd686c25053/bin/phantomjs-mac -------------------------------------------------------------------------------- /event.json: -------------------------------------------------------------------------------- 1 | { 2 | "body": { 3 | "url": "https://www.google.com/" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /example/example.html: -------------------------------------------------------------------------------- 1 | ! 2 | 3 | 4 | Convert HTML to PDF Example 5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 |
13 |
14 |
15 | 16 | 17 |
18 |
19 | 20 |
21 |
22 |
23 |
24 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /handler.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const fs = require('fs'); 4 | const path = require('path'); 5 | const execFile = require('child_process').execFile; 6 | 7 | module.exports.print = (event, context, callback) => { 8 | console.log(event); 9 | const body = JSON.parse(event.body); 10 | const phantomjs = path.resolve('bin/phantomjs-linux'); 11 | const rasterize = path.resolve('lib/rasterize.js'); 12 | const outputPDF = '/tmp/output.pdf'; 13 | const url = body.url; 14 | 15 | if (!url) { 16 | const err = 'url parameter is undefined'; 17 | return callback(err, { 18 | statusCode: 500, 19 | body: JSON.stringify({ 'error': err }) 20 | }); 21 | } 22 | 23 | execFile(phantomjs, [rasterize, url, outputPDF, "A4", 0.68], (err, stdout, stderr) => { 24 | console.log('execute phantomjs'); 25 | if (err) { 26 | console.log(err); 27 | callback(err, { 28 | statusCode: 500, 29 | body: JSON.stringify({ 30 | 'error': err 31 | }), 32 | }); 33 | } 34 | const output = fs.readFileSync(outputPDF); 35 | callback(null, { 36 | statusCode: 200, 37 | headers: { 38 | 'Access-Control-Allow-Origin': '*', 39 | }, 40 | body: output.toString('base64') 41 | }); 42 | }); 43 | 44 | // Use this code if you don't use the http event with the LAMBDA-PROXY integration 45 | // callback(null, { message: 'Go Serverless v1.0! Your function executed successfully!', event }); 46 | }; 47 | -------------------------------------------------------------------------------- /lib/rasterize.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var page = require('webpage').create(), 3 | system = require('system'), 4 | address, output, size, pageWidth, pageHeight; 5 | 6 | if (system.args.length < 3 || system.args.length > 5) { 7 | console.log('Usage: rasterize.js URL filename [paperwidth*paperheight|paperformat] [zoom]'); 8 | console.log(' paper (pdf output) examples: "5in*7.5in", "10cm*20cm", "A4", "Letter"'); 9 | console.log(' image (png/jpg output) examples: "1920px" entire page, window width 1920px'); 10 | console.log(' "800px*600px" window, clipped to 800x600'); 11 | phantom.exit(1); 12 | } else { 13 | address = system.args[1]; 14 | output = system.args[2]; 15 | page.viewportSize = { width: 600, height: 600 }; 16 | if (system.args.length > 3 && system.args[2].substr(-4) === ".pdf") { 17 | size = system.args[3].split('*'); 18 | page.paperSize = size.length === 2 ? { width: size[0], height: size[1], margin: '0px' } 19 | : { format: system.args[3], orientation: 'portrait', margin: '1cm' }; 20 | } else if (system.args.length > 3 && system.args[3].substr(-2) === "px") { 21 | size = system.args[3].split('*'); 22 | if (size.length === 2) { 23 | var pageWidth = parseInt(size[0], 10), 24 | pageHeight = parseInt(size[1], 10); 25 | page.viewportSize = { width: pageWidth, height: pageHeight }; 26 | page.clipRect = { top: 0, left: 0, width: pageWidth, height: pageHeight }; 27 | } else { 28 | console.log("size:", system.args[3]); 29 | var pageWidth = parseInt(system.args[3], 10), 30 | pageHeight = parseInt(pageWidth * 3/4, 10); // it's as good an assumption as any 31 | console.log ("pageHeight:",pageHeight); 32 | page.viewportSize = { width: pageWidth, height: pageHeight }; 33 | } 34 | } 35 | if (system.args.length > 4) { 36 | page.zoomFactor = system.args[4]; 37 | } 38 | page.open(address, function (status) { 39 | if (status !== 'success') { 40 | console.log('Unable to load the address!'); 41 | phantom.exit(1); 42 | } else { 43 | window.setTimeout(function () { 44 | page.render(output); 45 | phantom.exit(); 46 | }, 200); 47 | } 48 | }); 49 | } 50 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "serverless-pdf", 3 | "version": "1.0.0", 4 | "description": "Convert HTML to PDF thru a lambda function using phantomjs and rasterize.", 5 | "main": "handler.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "keywords": [ 10 | "serverless", 11 | "pdf" 12 | ], 13 | "author": "Calvin Chan ", 14 | "license": "MIT", 15 | "devDependencies": { 16 | "aws-sdk": "^2.20.0" 17 | }, 18 | "dependencies": { 19 | "mocha": "^3.2.0", 20 | "serverless-webpack": "^1.0.0-rc.4", 21 | "webpack": "^1.13.3" 22 | }, 23 | "browser": { 24 | "vertx": false 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /serverless.yml: -------------------------------------------------------------------------------- 1 | # Welcome to Serverless! 2 | # 3 | # This file is the main config file for your service. 4 | # It's very minimal at this point and uses default values. 5 | # You can always add more config options for more control. 6 | # We've included some commented out config examples here. 7 | # Just uncomment any of them to get that config option. 8 | # 9 | # For full config options, check the docs: 10 | # docs.serverless.com 11 | # 12 | # Happy Coding! 13 | 14 | service: serverless-pdf 15 | 16 | provider: 17 | name: aws 18 | runtime: nodejs4.3 19 | stage: stage 20 | region: us-west-2 21 | profile: serverless 22 | 23 | functions: 24 | print: 25 | handler: handler.print 26 | events: 27 | - http: 28 | method: post 29 | path: print 30 | cors: true 31 | 32 | # plugins: 33 | # - serverless-webpack 34 | 35 | package: 36 | exclude: 37 | - node_modules/** 38 | - bin/** 39 | include: 40 | - bin/phantomjs-linux 41 | - lib/rasterize.js 42 | --------------------------------------------------------------------------------