From 97ebecd84a3f655c6f11f835962b53ede4fd852f Mon Sep 17 00:00:00 2001 From: hacksalot Date: Thu, 7 Jan 2016 18:24:25 -0500 Subject: [PATCH] Support CLI-based PDF generation. Support Phantom and wkhtmltopdf generation via CLI. --- src/core/default-formats.js | 2 +- src/core/error-handler.js | 2 +- src/core/status-codes.js | 2 +- src/gen/html-pdf-cli-generator.js | 113 ++++++++++++++++++++++++++++++ src/gen/html-pdf-generator.js | 2 +- 5 files changed, 117 insertions(+), 4 deletions(-) create mode 100644 src/gen/html-pdf-cli-generator.js diff --git a/src/core/default-formats.js b/src/core/default-formats.js index 18eb44a..feb9e4e 100644 --- a/src/core/default-formats.js +++ b/src/core/default-formats.js @@ -9,7 +9,7 @@ { name: 'html', ext: 'html', gen: new (require('../gen/html-generator'))() }, { name: 'txt', ext: 'txt', gen: new (require('../gen/text-generator'))() }, { name: 'doc', ext: 'doc', fmt: 'xml', gen: new (require('../gen/word-generator'))() }, - { name: 'pdf', ext: 'pdf', fmt: 'html', is: false, gen: new (require('../gen/html-pdf-generator'))() }, + { name: 'pdf', ext: 'pdf', fmt: 'html', is: false, gen: new (require('../gen/html-pdf-cli-generator'))() }, { name: 'png', ext: 'png', fmt: 'html', is: false, gen: new (require('../gen/html-png-generator'))() }, { name: 'md', ext: 'md', fmt: 'txt', gen: new (require('../gen/markdown-generator'))() }, { name: 'json', ext: 'json', gen: new (require('../gen/json-generator'))() }, diff --git a/src/core/error-handler.js b/src/core/error-handler.js index b29e4e3..36a21dd 100644 --- a/src/core/error-handler.js +++ b/src/core/error-handler.js @@ -120,7 +120,7 @@ Error-handling routines for HackMyResume. chalk.yellow(' to create.'); break; - case HACKMYSTATUS.wkhtmltopdf: + case HACKMYSTATUS.pdfGeneration: msg = chalk.red.bold('ERROR: PDF generation failed. ') + chalk.red('Make sure wkhtmltopdf is ' + 'installed and accessible from your path.'); if( ex.inner ) msg += chalk.red('\n' + ex.inner); diff --git a/src/core/status-codes.js b/src/core/status-codes.js index 2e3d72e..b8dccf5 100644 --- a/src/core/status-codes.js +++ b/src/core/status-codes.js @@ -16,7 +16,7 @@ Status codes for HackMyResume. resumeNotFoundAlt: 6, inputOutputParity: 7, createNameMissing: 8, - wkhtmltopdf: 9, + pdfgeneration: 9, missingPackageJSON: 10, invalid: 11, invalidTarget: 12 diff --git a/src/gen/html-pdf-cli-generator.js b/src/gen/html-pdf-cli-generator.js new file mode 100644 index 0000000..4ea30ab --- /dev/null +++ b/src/gen/html-pdf-cli-generator.js @@ -0,0 +1,113 @@ +/** +Definition of the HtmlPdfCLIGenerator class. +@module html-pdf-generator.js +@license MIT. See LICENSE.md for details. +*/ + + + +(function() { + + + + var TemplateGenerator = require('./template-generator') + , FS = require('fs-extra') + , HTML = require( 'html' ) + , PATH = require('path') + , SLASH = require('slash'); + + + + /** + An HTML-driven PDF resume generator for HackMyResume. Talks to Phantom, + wkhtmltopdf, and other PDF libraries over a CLI. + */ + var HtmlPdfCLIGenerator = module.exports = TemplateGenerator.extend({ + + + + init: function() { + this._super( 'pdf', 'html' ); + }, + + + + /** + Generate the binary PDF. + */ + onBeforeSave: function( info ) { + try { + engines[ info.opts.pdf || 'wkhtmltopdf' ] + .call( this, info.mk, info.outputFile ); + return null; // halt further processing + } + catch(ex) { + // { [Error: write EPIPE] code: 'EPIPE', errno: 'EPIPE', ... } + // { [Error: ENOENT] } + throw { fluenterror: this.codes.pdfGeneration, inner: ex }; + } + } + + }); + + + + var engines = { + + + + /** + Generate a PDF from HTML using wkhtmltopdf. + */ + wkhtmltopdf: function(markup, fOut) { + + // Save the markup to a temporary file + var tempFile = fOut.replace(/\.pdf$/i, '.pdf.html'); + FS.writeFileSync( tempFile, markup, 'utf8' ); + + var spawn = require('child_process').spawn; + var child = spawn('wkhtmltopdf', [ + tempFile, fOut + ]); + + // child.stdout.on('data', function(chunk) { + // // output will be here in chunks + // }); + + // or if you want to send output elsewhere + //child.stdout.pipe(dest); + }, + + + + /** + Generate a PDF from HTML using Phantom. + See: https://github.com/ariya/phantomjs/blob/master/examples/rasterize.js + */ + phantom: function( markup, fOut ) { + + // Save the markup to a temporary file + var tempFile = fOut.replace(/\.pdf$/i, '.pdf.html'); + FS.writeFileSync( tempFile, markup, 'utf8' ); + + var scriptPath = SLASH( PATH.relative( process.cwd(), + PATH.resolve( __dirname, '../utils/rasterize.js' ) ) ); + var sourcePath = SLASH( PATH.relative( process.cwd(), tempFile) ); + var destPath = SLASH( PATH.relative( process.cwd(), fOut) ); + + var spawn = require('child_process').spawn; + var child = spawn('phantomjs', [ scriptPath, sourcePath, destPath ]); + + // child.stdout.on('data', function(chunk) { + // // output will be here in chunks + // }); + // + // // or if you want to send output elsewhere + // child.stdout.pipe(dest); + } + + }; + + + +}()); diff --git a/src/gen/html-pdf-generator.js b/src/gen/html-pdf-generator.js index f46774d..42dc347 100644 --- a/src/gen/html-pdf-generator.js +++ b/src/gen/html-pdf-generator.js @@ -45,7 +45,7 @@ Definition of the HtmlPdfGenerator class. catch(ex) { // { [Error: write EPIPE] code: 'EPIPE', errno: 'EPIPE', ... } // { [Error: ENOENT] } - throw { fluenterror: this.codes.wkhtmltopdf, inner: ex }; + throw { fluenterror: this.codes.pdfGeneration, inner: ex }; } },