UNPKG

phantom-html-to-pdf

Version:
262 lines (211 loc) 8.55 kB
/*! * Copyright(c) 2015 Jan Blaha */ /* globals phantom */ var maxLogEntrySize = require("system").env['PHANTOM_MAX_LOG_ENTRY_SIZE'] var httpsResourceProxyUrl = require("system").env['PHANTOM_HTTPS_RESOURCE_PROXY_URL']; var messages = []; function trimMessage(pars) { var message = Array.prototype.join.call(pars, ' ') // this is special case, because phantom logs base64 images content completely into the output if (message.indexOf('Request data:image') === 0 && message.length > 100) { return message.substring(0, 100) + '...'; } if (message.length > maxLogEntrySize) { return message.substring(0, maxLogEntrySize) + '...'; } return message; }; console.log = function(m) { messages.push({ timestamp: new Date().getTime(), message: trimMessage(arguments), level: 'debug'}); }; console.error = function(m) { messages.push({ timestamp: new Date().getTime(), message: trimMessage(arguments), level: 'error'}); }; console.warn = function(m) { messages.push({ timestamp: new Date().getTime(), message: trimMessage(arguments), level: 'warn'}); }; try { console.log('Converting in dedicated phantomjs ' + phantom.version.major + '.' + phantom.version.minor + '.' + phantom.version.patch); var webpage = require('webpage'); var system = require('system'); var fs = require('fs'); var page = webpage.create(); var settingsFile = system.args[system.args.length - 1]; var stream = fs.open(settingsFile, "r"); var body = JSON.parse(stream.read()); stream.close(); function respond(page, body){ system.stdout.write(JSON.stringify({ logs: messages, numberOfPages: body.numberOfPages })); // Work-around to avoid "Unsafe JavaScript attempt to access frame" warning in PhantomJS 1.9.8. // See: https://github.com/ariya/phantomjs/issues/12697 // since we rely on stdout for the dedicated-process strategy this work-around // ensures the phantom process don't log anything we don't want page.close(); setTimeout(function (){ phantom.exit(0); }, 0); } var pageJSisDone = body.waitForJS ? false : true; page.viewportSize = { width: body.viewportSize.width || 600, height: body.viewportSize.height || 600 }; page.settings.javascriptEnabled = body.settings.javascriptEnabled !== false; page.settings.resourceTimeout = body.settings.resourceTimeout || 10000; if(body.cookies.length > 0) { for(var i in body.cookies) { page.addCookie(body.cookies[i]); } } page.onResourceRequested = function (request, networkRequest) { console.log('Request ' + request.url); if (request.url.lastIndexOf(body.url, 0) === 0) { return; } //to support cdn like format //cdn.jquery... if (request.url.lastIndexOf("file://", 0) === 0 && request.url.lastIndexOf("file:///", 0) !== 0) { networkRequest.changeUrl(request.url.replace("file://", "http://")); } //potentially dangerous request if (request.url.lastIndexOf("http://", 0) !== 0 && request.url.lastIndexOf("https://", 0) && request.url.lastIndexOf("data:", 0) && !body.allowLocalFilesAccess) { networkRequest.abort(); return; } if (body.waitForJS && request.url.lastIndexOf("http://intruct-javascript-ending", 0) === 0) { pageJSisDone = true; } if (request.url.lastIndexOf("https://", 0) === 0 && httpsResourceProxyUrl) { networkRequest.changeUrl(httpsResourceProxyUrl + encodeURI(request.url)); } }; page.onConsoleMessage = function(msg, line, source) { console.log(msg, line, source); }; page.onResourceError = function(resourceError) { console.warn('Unable to load resource (#' + resourceError.id + 'URL:' + resourceError.url + ')'); console.warn('Error code: ' + resourceError.errorCode + '. Description: ' + resourceError.errorString); }; page.onError = function (msg, trace) { console.warn(msg); trace.forEach(function(item) { console.warn(' ', item.file, ':', item.line); }); }; page.onInitialized = function() { if (body.injectJs && body.injectJs.length > 0) { body.injectJs.forEach(function(script) { console.log('Injecting ' + script); page.injectJs(script); }); } // inject function to the page in order to the client can instruct the ending of its JS if (body.waitForJS) { page.evaluate(function(varName) { if (typeof Object.defineProperty === 'function') { Object.defineProperty(window, varName, { set: function(val) { if (!val) return; if (val === true) { var scriptNode = document.createElement("script"); scriptNode.src = 'http://intruct-javascript-ending'; document.body.appendChild(scriptNode); } } }); } }, body.waitForJSVarName); } }; page.open(body.url, function () { var phantomHeader = page.evaluate(function (s) { return document.querySelector(s) ? document.querySelector(s).innerHTML : null; }, '#phantomHeader'); var phantomFooter = page.evaluate(function (s) { return document.querySelector(s) ? document.querySelector(s).innerHTML : null; }, '#phantomFooter'); body.numberOfPages = 0; page.paperSize = { format: body.paperSize.format || "", orientation: body.paperSize.orientation, margin: body.paperSize.margin || "1cm", width: body.paperSize.width || undefined, height: body.paperSize.height || undefined, header: { height: body.paperSize.headerHeight || ((phantomHeader || body.headerFile) ? "1cm" : "1mm"), contents: phantom.callback(function (pageNum, numPages) { body.numberOfPages = numPages; if (!phantomHeader && !body.headerFile) return "<span></span>"; if (!phantomHeader) { var stream = fs.open(body.headerFile, "r"); phantomHeader = stream.read(); stream.close(); } return phantomHeader.replace(/{#pageNum}/g, pageNum).replace(/{#numPages}/g, numPages); }) }, footer: (body.footerFile || phantomFooter) ? { height: body.paperSize.footerHeight || "1cm", contents: phantom.callback(function (pageNum, numPages) { if (!phantomFooter) { var stream = fs.open(body.footerFile, "r"); phantomFooter = stream.read(); stream.close(); } return phantomFooter.replace(/{#pageNum}/g, pageNum).replace(/{#numPages}/g, numPages); }) } : undefined }; if (body.customHeaders) { page.customHeaders = body.customHeaders; } page.zoomFactor = 1; if(body.fitToPage) { var widths = page.evaluate(function() { return { scrollWidth : document.body.scrollWidth, offsetWidth : document.body.offsetWidth }; }); if(widths.scrollWidth > widths.offsetWidth) { page.zoomFactor =(widths.offsetWidth / widths.scrollWidth); } } setTimeout(function () { resolvePage() }, body.printDelay || 0); function resolvePage() { if (body.waitForJS && !pageJSisDone) { setTimeout(function() { console.log('PhantomJS printing done') resolvePage(); }, 100); return; } if (body.waitForJS) { phantomHeader = page.evaluate(function (s) { return document.querySelector(s) ? document.querySelector(s).innerHTML : null; }, '#phantomHeader'); phantomFooter = page.evaluate(function (s) { return document.querySelector(s) ? document.querySelector(s).innerHTML : null; }, '#phantomFooter'); } page.render(body.output, body.format); respond(page, body); } }); } catch(e) { console.error(e.message); e.message += '; log: ' + JSON.stringify(messages); system.stderr.write(JSON.stringify(e)); phantom.exit(1); }