From 76c2b174c67756f78e44cb3f4e404b1ae6f07b36 Mon Sep 17 00:00:00 2001 From: Marc Bachmann Date: Wed, 27 Sep 2017 00:21:09 +0200 Subject: [PATCH 01/16] Move the example directory to examples --- .gitignore | 2 +- README.md | 6 +++--- example/businesscard.pdf | Bin 21695 -> 0 bytes .../businesscard}/businesscard.html | 0 .../businesscard}/businesscard.png | Bin {example => examples/businesscard}/image.png | Bin examples/serve-http/index.js | 19 ++++++++++++++++++ test/index.js | 4 ++-- 8 files changed, 25 insertions(+), 6 deletions(-) delete mode 100644 example/businesscard.pdf rename {example => examples/businesscard}/businesscard.html (100%) rename {example => examples/businesscard}/businesscard.png (100%) rename {example => examples/businesscard}/image.png (100%) create mode 100644 examples/serve-http/index.js diff --git a/.gitignore b/.gitignore index 0e69430..135cfd4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,3 @@ *.pdf -!example/businesscard.pdf +!examples/businesscard.pdf node_modules diff --git a/README.md b/README.md index fcaaef0..dafb8b3 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,8 @@ # node-html-pdf ## HTML to PDF converter that uses phantomjs -![image](example/businesscard.png) -[Example Business Card](example/businesscard.pdf) - -> [and its Source file](example/businesscard.html) +![image](examples/businesscard.png) +[Example Business Card](examples/businesscard.pdf) + -> [and its Source file](examples/businesscard.html) [Example Receipt](http://imgr-static.s3-eu-west-1.amazonaws.com/order.pdf) diff --git a/example/businesscard.pdf b/example/businesscard.pdf deleted file mode 100644 index a6f87527c4123da9ce19b2b8cb65bd44f81a0b2e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 21695 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 diff --git a/example/businesscard.html b/examples/businesscard/businesscard.html similarity index 100% rename from example/businesscard.html rename to examples/businesscard/businesscard.html diff --git a/example/businesscard.png b/examples/businesscard/businesscard.png similarity index 100% rename from example/businesscard.png rename to examples/businesscard/businesscard.png diff --git a/example/image.png b/examples/businesscard/image.png similarity index 100% rename from example/image.png rename to examples/businesscard/image.png diff --git a/examples/serve-http/index.js b/examples/serve-http/index.js new file mode 100644 index 0000000..2af62e6 --- /dev/null +++ b/examples/serve-http/index.js @@ -0,0 +1,19 @@ +const fs = require('fs') +const http = require('http') +const pdf = require('../../') +const tmpl = fs.readFileSync(require.resolve('../businesscard/businesscard.html'), 'utf8') + +const server = http.createServer(function (req, res) { + if (req.url === '/favicon.ico') return res.end('404') + const html = tmpl.replace('{{image}}', `file://${require.resolve('../businesscard/image.png')}`) + pdf.create(html, {width: '50mm', height: '90mm'}).toStream((err, stream) => { + if (err) return res.end(err.stack) + res.setHeader('Content-type', 'application/pdf') + stream.pipe(res) + }) +}) + +server.listen(8080, function (err) { + if (err) throw err + console.log('Listening on http://localhost:%s', server.address().port) +}) diff --git a/test/index.js b/test/index.js index bc8841f..a1e446f 100644 --- a/test/index.js +++ b/test/index.js @@ -93,11 +93,11 @@ test('pdf.create(html[, options]).toStream(callback)', function (t) { test('allows custom html and css', function (t) { t.plan(3) - var template = path.join(__dirname, '../example/businesscard.html') + var template = path.join(__dirname, '../examples/businesscard/businesscard.html') var filename = template.replace('.html', '.pdf') var templateHtml = fs.readFileSync(template, 'utf8') - var image = path.join('file://', __dirname, '../example/image.png') + var image = path.join('file://', __dirname, '../examples/businesscard/image.png') templateHtml = templateHtml.replace('{{image}}', image) var options = { From a85a9a642db411b7d65ab7f2863a1e6af4f48d89 Mon Sep 17 00:00:00 2001 From: Marc Bachmann Date: Wed, 27 Sep 2017 00:22:03 +0200 Subject: [PATCH 02/16] Improve error handling and pipe stdout to process.stdout --- lib/pdf.js | 85 ++++++++++++++++++++++++++++++------------------------ 1 file changed, 48 insertions(+), 37 deletions(-) diff --git a/lib/pdf.js b/lib/pdf.js index 7211d0f..96f93b6 100644 --- a/lib/pdf.js +++ b/lib/pdf.js @@ -84,54 +84,65 @@ PDF.prototype.toFile = function PdfToFile (filename, callback) { } PDF.prototype.exec = function PdfExec (callback) { - var callbacked = false var child = childprocess.spawn(this.options.phantomPath, [].concat(this.options.phantomArgs, [this.script])) - var stdout = [] var stderr = [] + var timeout = setTimeout(function execTimeout () { - child.stdin.end() - child.kill() - if (!stderr.length) { - stderr = [new Buffer('html-pdf: PDF generation timeout. Phantom.js script did not exit.')] - } + respond(null, new Error('html-pdf: PDF generation timeout. Phantom.js script did not exit.')) }, this.options.timeout) - child.stdout.on('data', function (buffer) { - return stdout.push(buffer) - }) - - child.stderr.on('data', function (buffer) { + function onError (buffer) { stderr.push(buffer) - child.stdin.end() - return child.kill() - }) + } + + function onData (buffer) { + var result + try { + var json = buffer.toString().trim() + if (json) result = JSON.parse(json) + } catch (err) { + // Proxy for debugging purposes + process.stdout.write(buffer) + } + + if (result) respond(null, null, result) + } - function exit (err, data) { + var callbacked = false + function respond (code, err, data) { if (callbacked) return callbacked = true clearTimeout(timeout) - if (err) return callback(err) - return callback(null, data) - } - child.on('error', exit) - - child.on('exit', function (code) { - if (code || stderr.length) { - var err = new Error(Buffer.concat(stderr).toString() || 'html-pdf: Unknown Error') - return exit(err) - } else { - try { - var buff = Buffer.concat(stdout).toString() - var data = (buff) != null ? buff.trim() : undefined - data = JSON.parse(data) - } catch (err) { - return exit(err) - } - return exit(null, data) + // If we don't have an exit code, we kill the process, ignore stderr after this point + if (code === null) kill(child, onData, onError) + + if (!data) { + if (!err && code) err = new Error("html-pdf: Received the exit code '" + code + "'") + else if (!err) err = new Error('html-pdf: Unknown Error') + + var postfix = stderr.length ? '\n' + Buffer.concat(stderr).toString() : '' + if (postfix) err.message += postfix + return callback(err, null) } - }) - var res = JSON.stringify({html: this.html, options: this.options}) - return child.stdin.write(res + '\n', 'utf8') + callback(null, data) + } + + child.stdout.on('data', onData) + child.stderr.on('data', onError) + child.on('error', function onError (err) { respond(null, err) }) + + // An exit event is most likely an error because we didn't get any data at this point + child.on('exit', respond) + + var config = JSON.stringify({html: this.html, options: this.options}) + return child.stdin.write(config + '\n', 'utf8') +} + +function kill (child, onData, onError) { + child.stdout.removeListener('data', onData) + child.stderr.removeListener('data', onError) + child.stdin.end() + child.kill() } From d6355ba572fbcd1effe988e8afb9a288dcff1da3 Mon Sep 17 00:00:00 2001 From: zmedgyes Date: Mon, 19 Jun 2017 16:56:41 +0200 Subject: [PATCH 03/16] Add cliOptions option and pass it to child process If run as windows service, use cliOptions = { detached:true} to avoid error: SetProcessDpiAwareness failed: "COM error 0x80070005 (Unknown error 0x0ffffffff80070005)" --- lib/pdf.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pdf.js b/lib/pdf.js index 96f93b6..f5477a3 100644 --- a/lib/pdf.js +++ b/lib/pdf.js @@ -84,7 +84,7 @@ PDF.prototype.toFile = function PdfToFile (filename, callback) { } PDF.prototype.exec = function PdfExec (callback) { - var child = childprocess.spawn(this.options.phantomPath, [].concat(this.options.phantomArgs, [this.script])) + var child = childprocess.spawn(this.options.phantomPath, [].concat(this.options.phantomArgs, [this.script]), this.options.cliOptions) var stderr = [] var timeout = setTimeout(function execTimeout () { From 7a9463d9c0350caa69804609c0d5ef7164c9719c Mon Sep 17 00:00:00 2001 From: zmedgyes Date: Mon, 10 Jul 2017 12:02:03 +0200 Subject: [PATCH 04/16] Update README.md --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index dafb8b3..f8ebf38 100644 --- a/README.md +++ b/README.md @@ -137,6 +137,11 @@ config = { "httpHeaders": { // e.g. "Authorization": "Bearer ACEFAD8C-4B4D-4042-AB30-6C735F5BAC8B" + }, + + // To run Node application as Windows service + "cliOptions": { + "detached": true } } From 69b78bff7a17510e5d81d7e585c407b876fd5400 Mon Sep 17 00:00:00 2001 From: Mathieu de Lorimier Date: Fri, 27 Jan 2017 08:23:45 -0500 Subject: [PATCH 05/16] Added pagination start page Added an option to the generation script to dictate on which page the page numbering should start. Option name is paginationStartPage and is 1 based (to start pagination at page 2, the value would be 2) --- lib/scripts/pdf_a4_portrait.js | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/lib/scripts/pdf_a4_portrait.js b/lib/scripts/pdf_a4_portrait.js index a9197c4..d8772e8 100755 --- a/lib/scripts/pdf_a4_portrait.js +++ b/lib/scripts/pdf_a4_portrait.js @@ -144,6 +144,7 @@ function getContent (page) { // Creates page section // -------------------- function createSection (section, content, options) { + var opts = options options = options[section] || {} var c = content[section] || {} var o = options.contents @@ -153,11 +154,19 @@ function createSection (section, content, options) { height: options.height, contents: phantom.callback(function (pageNum, numPages) { var html = o[pageNum] || c[pageNum] + + var pageNumFinal = pageNum, numPagesFinal = numPages; + if(opts.paginationStartPage && opts.paginationStartPage > 1) { + var pageOffset = opts.paginationStartPage - 1; + pageNumFinal = (pageNumFinal - pageOffset > 0 ? pageNumFinal - pageOffset : ''); + numPagesFinal -= pageOffset; + } + if (pageNum === 1 && !html) html = o.first || c.first if (pageNum === numPages && !html) html = o.last || c.last return (html || o.default || c.default || '') - .replace(/{{page}}/g, pageNum) - .replace(/{{pages}}/g, numPages) + content.styles + .replace(/{{page}}/g, pageNumFinal) + .replace(/{{pages}}/g, numPagesFinal) + content.styles }) } } From 92e2b01b13cb9e95b4441c19cd8780fe76563353 Mon Sep 17 00:00:00 2001 From: Marc Bachmann Date: Tue, 21 Mar 2017 18:50:29 -0400 Subject: [PATCH 06/16] Simplify paginationStartPage and rename to paginationOffset --- README.md | 3 ++- lib/scripts/pdf_a4_portrait.js | 16 +++++++--------- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index f8ebf38..78dff5b 100644 --- a/README.md +++ b/README.md @@ -102,6 +102,7 @@ config = { "left": "1.5in" }, + paginationOffset: 1, // Override the initial pagination number "header": { "height": "45mm", "contents": '
Author: Marc Bachmann
' @@ -138,7 +139,7 @@ config = { // e.g. "Authorization": "Bearer ACEFAD8C-4B4D-4042-AB30-6C735F5BAC8B" }, - + // To run Node application as Windows service "cliOptions": { "detached": true diff --git a/lib/scripts/pdf_a4_portrait.js b/lib/scripts/pdf_a4_portrait.js index d8772e8..b7bba87 100755 --- a/lib/scripts/pdf_a4_portrait.js +++ b/lib/scripts/pdf_a4_portrait.js @@ -144,10 +144,12 @@ function getContent (page) { // Creates page section // -------------------- function createSection (section, content, options) { - var opts = options options = options[section] || {} var c = content[section] || {} var o = options.contents + var _paginationOffset = Math.floor(options.paginationOffset) + var paginationOffset = isNaN(options.paginationOffset) ? 0 : _paginationOffset + if (typeof o !== 'object') o = {default: o} return { @@ -155,15 +157,11 @@ function createSection (section, content, options) { contents: phantom.callback(function (pageNum, numPages) { var html = o[pageNum] || c[pageNum] - var pageNumFinal = pageNum, numPagesFinal = numPages; - if(opts.paginationStartPage && opts.paginationStartPage > 1) { - var pageOffset = opts.paginationStartPage - 1; - pageNumFinal = (pageNumFinal - pageOffset > 0 ? pageNumFinal - pageOffset : ''); - numPagesFinal -= pageOffset; - } + var pageNumFinal = pageNum + paginationOffset + var numPagesFinal = numPages + paginationOffset - if (pageNum === 1 && !html) html = o.first || c.first - if (pageNum === numPages && !html) html = o.last || c.last + if (pageNumFinal === 1 && !html) html = o.first || c.first + if (numPagesFinal === numPages && !html) html = o.last || c.last return (html || o.default || c.default || '') .replace(/{{page}}/g, pageNumFinal) .replace(/{{pages}}/g, numPagesFinal) + content.styles From 9d9aa73e74eb5bf8e407b15da5f6aca53a1361ce Mon Sep 17 00:00:00 2001 From: Marc Bachmann Date: Wed, 27 Sep 2017 01:13:25 +0200 Subject: [PATCH 07/16] Add child process close event handler --- lib/pdf.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/pdf.js b/lib/pdf.js index f5477a3..c071258 100644 --- a/lib/pdf.js +++ b/lib/pdf.js @@ -63,7 +63,7 @@ PDF.prototype.toStream = function PdfToStream (callback) { } stream.on('end', function () { - fs.unlink(res.filename, function (err) { + fs.unlink(res.filename, function unlinkPdfFile (err) { if (err) console.log('html-pdf:', err) }) }) @@ -134,15 +134,15 @@ PDF.prototype.exec = function PdfExec (callback) { child.on('error', function onError (err) { respond(null, err) }) // An exit event is most likely an error because we didn't get any data at this point + child.on('close', respond) child.on('exit', respond) var config = JSON.stringify({html: this.html, options: this.options}) - return child.stdin.write(config + '\n', 'utf8') + child.stdin.write(config + '\n', 'utf8') + child.stdin.end() } function kill (child, onData, onError) { - child.stdout.removeListener('data', onData) - child.stderr.removeListener('data', onError) child.stdin.end() child.kill() } From 15f6a1501b8b615ec423646550dcef0f7930aa4e Mon Sep 17 00:00:00 2001 From: Marc Bachmann Date: Wed, 27 Sep 2017 01:13:52 +0200 Subject: [PATCH 08/16] Add callback to unlink functions to get rid of deprecation messages --- test/index.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/test/index.js b/test/index.js index a1e446f..b417dff 100644 --- a/test/index.js +++ b/test/index.js @@ -1,5 +1,7 @@ var test = require('tape') var tapSpec = require('tap-spec') +function noop (err) { if (err) throw err } + test.createStream() .pipe(tapSpec()) .pipe(process.stdout) @@ -42,7 +44,7 @@ test('pdf.create(html[, options]).toFile([filename, ]callback)', function (t) { pdf.create(html).toFile(function (err, pdf) { t.error(err) t.assert(typeof pdf.filename === 'string', `toFile(callback) returns {filename: '${pdf.filename}'} as second cb argument`) - fs.unlink(pdf.filename) + fs.unlink(pdf.filename, noop) }) var file = path.join(__dirname, 'simple.pdf') @@ -82,7 +84,7 @@ test('pdf.create(html[, options]).toStream(callback)', function (t) { stream.pipe(fs.createWriteStream(destination)) stream.on('end', function () { t.assert(fs.existsSync(destination), 'toStream returns a working readable stream') - fs.unlink(destination) + fs.unlink(destination, noop) }) }) }) From a131140cc728006d634d3812684b9ec23edd4b63 Mon Sep 17 00:00:00 2001 From: Alex Bor Date: Fri, 13 May 2016 12:00:49 +0100 Subject: [PATCH 09/16] Option for waiting for event to trigger Added an option to allow waiting for the page to say when it's finished rendering. if options.onTitleDone is set to true, the page will not take the screenshot until the title is set to "done" on the page. Signed-off-by: Alex Bor --- lib/scripts/pdf_a4_portrait.js | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/lib/scripts/pdf_a4_portrait.js b/lib/scripts/pdf_a4_portrait.js index b7bba87..7b9bd71 100755 --- a/lib/scripts/pdf_a4_portrait.js +++ b/lib/scripts/pdf_a4_portrait.js @@ -64,10 +64,26 @@ page.onLoadFinished = function (status) { } var filename = options.filename || (options.directory || '/tmp') + '/html-pdf-' + system.pid + '.' + fileOptions.type - page.render(filename, fileOptions) - system.stdout.write(JSON.stringify({filename: filename})) - exit(null) + takeShot(); + function takeShot(){ + var title = page.evaluate(function() { + return document.title; + }); + + if(title.toUpperCase() != "DONE" && options.onTitleDone){ + window.setTimeout(function () { + takeShot(); + }, 400); + } else { + page.render(filename, fileOptions) + phantom.exit(); + + system.stdout.write(JSON.stringify({filename: filename})) + + exit(null) + } + } } // Returns a hash of HTML content From 2e4f1906f74743e4411c5df46c0295d9148acb97 Mon Sep 17 00:00:00 2001 From: Marc Bachmann Date: Tue, 21 Mar 2017 18:33:00 -0400 Subject: [PATCH 10/16] Improve `renderDelay` option and add to README. --- README.md | 4 ++++ lib/scripts/pdf_a4_portrait.js | 30 +++++++++--------------------- 2 files changed, 13 insertions(+), 21 deletions(-) diff --git a/README.md b/README.md index 78dff5b..86f1a63 100644 --- a/README.md +++ b/README.md @@ -134,6 +134,10 @@ config = { "script": '/url', // Absolute path to a custom phantomjs script, use the file in lib/scripts as example "timeout": 30000, // Timeout that will cancel phantomjs, in milliseconds + // Time we should wait after window load + // accepted values are 'manual', some delay in milliseconds or undefined to wait for a render event + "renderDelay": 1000, + // HTTP Headers that are used for requests "httpHeaders": { // e.g. diff --git a/lib/scripts/pdf_a4_portrait.js b/lib/scripts/pdf_a4_portrait.js index 7b9bd71..cc480e0 100755 --- a/lib/scripts/pdf_a4_portrait.js +++ b/lib/scripts/pdf_a4_portrait.js @@ -53,11 +53,13 @@ setTimeout(function () { // Completely load page & end process // ---------------------------------- -page.onLoadFinished = function (status) { - // The paperSize object must be set at once +if (options.renderDelay === 'manual') page.onCallback = renderNow +else if (typeof options.renderDelay === 'number') setTimeout(renderNow, options.renderDelay) +else page.onLoadFinished = renderNow + +function renderNow () { page.paperSize = definePaperSize(getContent(page), options) - // Output to parent process var fileOptions = { type: options.type || 'pdf', quality: options.quality || 75 @@ -65,25 +67,11 @@ page.onLoadFinished = function (status) { var filename = options.filename || (options.directory || '/tmp') + '/html-pdf-' + system.pid + '.' + fileOptions.type - takeShot(); - function takeShot(){ - var title = page.evaluate(function() { - return document.title; - }); - - if(title.toUpperCase() != "DONE" && options.onTitleDone){ - window.setTimeout(function () { - takeShot(); - }, 400); - } else { - page.render(filename, fileOptions) - phantom.exit(); - - system.stdout.write(JSON.stringify({filename: filename})) + page.render(filename, fileOptions) - exit(null) - } - } + // Output to parent process + system.stdout.write(JSON.stringify({filename: filename})) + exit(null) } // Returns a hash of HTML content From 4eaeab0b8640fcc653bdc18fbe2ee4d6235ad77d Mon Sep 17 00:00:00 2001 From: Marc Bachmann Date: Wed, 27 Sep 2017 01:36:48 +0200 Subject: [PATCH 11/16] Add renderDelay option --- lib/scripts/pdf_a4_portrait.js | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/lib/scripts/pdf_a4_portrait.js b/lib/scripts/pdf_a4_portrait.js index cc480e0..2420910 100755 --- a/lib/scripts/pdf_a4_portrait.js +++ b/lib/scripts/pdf_a4_portrait.js @@ -53,11 +53,21 @@ setTimeout(function () { // Completely load page & end process // ---------------------------------- +var rendered = false +var renderTimeout + +// If renderDelay is manual, then listen for an event and don't automatically render if (options.renderDelay === 'manual') page.onCallback = renderNow -else if (typeof options.renderDelay === 'number') setTimeout(renderNow, options.renderDelay) -else page.onLoadFinished = renderNow + +page.onLoadFinished = function () { + if (typeof options.renderDelay === 'manual') return + renderTimeout = setTimeout(renderNow, Math.floor(options.renderDelay) || 0) +} function renderNow () { + if (rendered) return + rendered = true + clearTimeout(renderTimeout) page.paperSize = definePaperSize(getContent(page), options) var fileOptions = { @@ -151,8 +161,7 @@ function createSection (section, content, options) { options = options[section] || {} var c = content[section] || {} var o = options.contents - var _paginationOffset = Math.floor(options.paginationOffset) - var paginationOffset = isNaN(options.paginationOffset) ? 0 : _paginationOffset + var paginationOffset = Math.floor(options.paginationOffset) || 0 if (typeof o !== 'object') o = {default: o} From cbe1ed56a4d01a29acdc7f4a1911f9da21cb3e2d Mon Sep 17 00:00:00 2001 From: Chris Kinsman Date: Wed, 22 Mar 2017 07:49:11 -0700 Subject: [PATCH 12/16] Add test to ensure that renderDelay will render after a specific time --- test/index.js | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/test/index.js b/test/index.js index b417dff..444b08c 100644 --- a/test/index.js +++ b/test/index.js @@ -74,6 +74,16 @@ test('pdf.create(html, {directory: "/tmp"}).toBuffer(callback)', function (t) { }) }) +test('pdf.create(html, {renderDelay: 1000}).toBuffer(callback)', function (t) { + t.plan(2) + + pdf.create(html, {renderDelay: 1000}).toBuffer(function (err, pdf) { + t.error(err) + t.assert(Buffer.isBuffer(pdf), 'still returns after renderDelay') + }) +}) + + test('pdf.create(html[, options]).toStream(callback)', function (t) { t.plan(3) From 353cca67fc825cfe26f27830296eda79d3ea710b Mon Sep 17 00:00:00 2001 From: Marc Bachmann Date: Wed, 27 Sep 2017 02:04:49 +0200 Subject: [PATCH 13/16] Add `manual` renderDelay support using `window.callPhantom` --- lib/scripts/pdf_a4_portrait.js | 48 +++++++++++++++++++--------------- test/callback.html | 30 +++++++++++++++++++++ test/index.js | 16 ++++++++++++ 3 files changed, 73 insertions(+), 21 deletions(-) create mode 100644 test/callback.html diff --git a/lib/scripts/pdf_a4_portrait.js b/lib/scripts/pdf_a4_portrait.js index 2420910..5774e1d 100755 --- a/lib/scripts/pdf_a4_portrait.js +++ b/lib/scripts/pdf_a4_portrait.js @@ -33,34 +33,21 @@ if (!json.html || !json.html.trim()) exit('Did not receive any html') var options = json.options var page = webpage.create() -if (options.httpHeaders) page.customHeaders = options.httpHeaders -if (options.viewportSize) page.viewportSize = options.viewportSize -if (options.zoomFactor) page.zoomFactor = options.zoomFactor -if (options.base) page.setContent(json.html, options.base) -else page.setContent(json.html, null) - -page.onError = function (msg, trace) { - exit(buildStack('Evaluation - ' + msg, trace)) -} - -// Force cleanup after 2 minutes -// Add 2 seconds to make sure master process triggers kill -// before to the phantom process -var timeout = (options.timeout || 120000) + 2000 -setTimeout(function () { - exit('Force timeout') -}, timeout) - // Completely load page & end process // ---------------------------------- var rendered = false var renderTimeout // If renderDelay is manual, then listen for an event and don't automatically render -if (options.renderDelay === 'manual') page.onCallback = renderNow +if (options.renderDelay === 'manual') { + page.onCallback = function (message) { + setTimeout(renderNow, 0) + return message + } +} page.onLoadFinished = function () { - if (typeof options.renderDelay === 'manual') return + if (options.renderDelay === 'manual') return renderTimeout = setTimeout(renderNow, Math.floor(options.renderDelay) || 0) } @@ -76,7 +63,6 @@ function renderNow () { } var filename = options.filename || (options.directory || '/tmp') + '/html-pdf-' + system.pid + '.' + fileOptions.type - page.render(filename, fileOptions) // Output to parent process @@ -84,6 +70,26 @@ function renderNow () { exit(null) } +// Set Content and begin loading +// ----------------------------- +if (options.httpHeaders) page.customHeaders = options.httpHeaders +if (options.viewportSize) page.viewportSize = options.viewportSize +if (options.zoomFactor) page.zoomFactor = options.zoomFactor +if (options.base) page.setContent(json.html, options.base) +else page.setContent(json.html, null) + +page.onError = function (msg, trace) { + exit(buildStack('Evaluation - ' + msg, trace)) +} + +// Force cleanup after 2 minutes +// Add 2 seconds to make sure master process triggers kill +// before to the phantom process +var timeout = (options.timeout || 120000) + 2000 +setTimeout(function () { + exit('Force timeout') +}, timeout) + // Returns a hash of HTML content // ------------------------------ function getContent (page) { diff --git a/test/callback.html b/test/callback.html new file mode 100644 index 0000000..5684a35 --- /dev/null +++ b/test/callback.html @@ -0,0 +1,30 @@ + + + + + + + +
+ + + + + diff --git a/test/index.js b/test/index.js index 444b08c..ace1a5f 100644 --- a/test/index.js +++ b/test/index.js @@ -83,6 +83,22 @@ test('pdf.create(html, {renderDelay: 1000}).toBuffer(callback)', function (t) { }) }) +test('window.callPhantom renders page', function (t) { + t.plan(3) + + var callbackHtml = fs.readFileSync(path.join(__dirname, 'callback.html'), 'utf8') + var file = path.join(__dirname, 'callback.pdf') + var startTime = new Date().getTime() + + pdf.create(callbackHtml, {renderDelay: 'manual'}).toFile(file, function (err, pdf) { + var endTime = new Date().getTime() + t.error(err) + + var time = endTime - startTime + t.assert(time > 1000 && time < 2000, 'rendered in response to callPhantom') + t.assert(fs.existsSync(file), 'writes the file to the given destination') + }) +}) test('pdf.create(html[, options]).toStream(callback)', function (t) { t.plan(3) From a4c3d6f0a2667b389710d0a2b967c0e44209fecf Mon Sep 17 00:00:00 2001 From: seyfert Date: Thu, 2 Feb 2017 20:37:28 -0600 Subject: [PATCH 14/16] Add http cookie support --- README.md | 14 ++++++++++++++ lib/scripts/pdf_a4_portrait.js | 1 + 2 files changed, 15 insertions(+) diff --git a/README.md b/README.md index 86f1a63..275dbb1 100644 --- a/README.md +++ b/README.md @@ -149,6 +149,20 @@ config = { "detached": true } + // HTTP Cookies that are used for requests + "httpCookies": [ + // e.g. + { + "name": "Valid-Cookie-Name", // required + "value": "Valid-Cookie-Value", // required + "domain": "localhost", + "path": "/foo", // required + "httponly": true, + "secure": false, + "expires": (new Date()).getTime() + (1000 * 60 * 60) // e.g. expires in 1 hour + } + ] + } ``` diff --git a/lib/scripts/pdf_a4_portrait.js b/lib/scripts/pdf_a4_portrait.js index 5774e1d..3542baa 100755 --- a/lib/scripts/pdf_a4_portrait.js +++ b/lib/scripts/pdf_a4_portrait.js @@ -72,6 +72,7 @@ function renderNow () { // Set Content and begin loading // ----------------------------- +if (options.httpCookies) page.cookies = options.httpCookies if (options.httpHeaders) page.customHeaders = options.httpHeaders if (options.viewportSize) page.viewportSize = options.viewportSize if (options.zoomFactor) page.zoomFactor = options.zoomFactor From ee467731e47ca1c972cf775abb9d52a6022d50ec Mon Sep 17 00:00:00 2001 From: Marc Bachmann Date: Wed, 22 Mar 2017 11:11:55 -0400 Subject: [PATCH 15/16] Add test for http cookie support --- test/index.js | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/test/index.js b/test/index.js index ace1a5f..a48b42e 100644 --- a/test/index.js +++ b/test/index.js @@ -222,3 +222,36 @@ test('load external js', function (t) { t.assert(fs.existsSync(pdf.filename), 'Saves the pdf with a custom page size and footer') }) }) + +test('load with cookies js', function (t) { + t.plan(3) + + var server = require('http').createServer(function (req, res) { + res.write(req.headers.cookie) + res.end() + }) + + server.listen(0, function (err) { + t.error(err, 'http server for iframe started') + + var port = server.address().port + var filename = path.join(__dirname, 'cookies.pdf') + pdf.create(` + here is an iframe which receives the cookies + + + `, { + httpCookies: [{ + name: 'Valid-Cookie-Name', + value: 'Valid-Cookie-Value', + domain: 'localhost', + path: '/' + }] + }) + .toFile(filename, function (error, pdf) { + server.close() + t.error(error, 'There must be no render error') + t.assert(fs.existsSync(pdf.filename), 'Saves the pdf') + }) + }) +}) From 309c7c78da75fdd420019ff0845f30be3f4dd4ae Mon Sep 17 00:00:00 2001 From: Marc Bachmann Date: Wed, 27 Sep 2017 02:22:26 +0200 Subject: [PATCH 16/16] Rename cliOptions to childProcessOptions --- README.md | 2 +- lib/pdf.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 275dbb1..3f3a1d3 100644 --- a/README.md +++ b/README.md @@ -145,7 +145,7 @@ config = { }, // To run Node application as Windows service - "cliOptions": { + "childProcessOptions": { "detached": true } diff --git a/lib/pdf.js b/lib/pdf.js index c071258..4ca1afd 100644 --- a/lib/pdf.js +++ b/lib/pdf.js @@ -84,7 +84,7 @@ PDF.prototype.toFile = function PdfToFile (filename, callback) { } PDF.prototype.exec = function PdfExec (callback) { - var child = childprocess.spawn(this.options.phantomPath, [].concat(this.options.phantomArgs, [this.script]), this.options.cliOptions) + var child = childprocess.spawn(this.options.phantomPath, [].concat(this.options.phantomArgs, [this.script]), this.options.childProcessOptions) var stderr = [] var timeout = setTimeout(function execTimeout () {