diff --git a/lib/Page.js b/lib/Page.js index bf86f61936f..e528af2a5fe 100644 --- a/lib/Page.js +++ b/lib/Page.js @@ -386,6 +386,54 @@ class Page extends EventEmitter { fs.writeFileSync(filePath, buffer); } + /** + * @param {string} filePath + * @param {!Object=} options + */ + async printToPDF(filePath, options) { + options = options || {}; + + var scale = options.scale || 1; + var displayHeaderFooter = options.displayHeaderFooter || false; + var printBackground = options.printBackground || true; + var landscape = options.landscape || false; + var pageRanges = options.pageRanges || ''; + + var paperWidth = 8.5; + var paperHeight = 11; + if (options.format) { + var format = Page.PaperFormats[options.format]; + console.assert(format, 'Unknown paper format: ' + options.format); + paperWidth = format.width; + paperHeight = format.height; + } else { + paperWidth = convertPrintParameterToInches(options.width) || paperWidth; + paperHeight = convertPrintParameterToInches(options.height) || paperHeight; + } + + var marginOptions = options.margin || {}; + var marginTop = convertPrintParameterToInches(marginOptions.top) || 0; + var marginLeft = convertPrintParameterToInches(marginOptions.left) || 0; + var marginBottom = convertPrintParameterToInches(marginOptions.bottom) || 0; + var marginRight = convertPrintParameterToInches(marginOptions.right) || 0; + + var result = await this._client.send('Page.printToPDF', { + landscape: landscape, + displayHeaderFooter: displayHeaderFooter, + printBackground: printBackground, + scale: scale, + paperWidth: paperWidth, + paperHeight: paperHeight, + marginTop: marginTop, + marginBottom: marginBottom, + marginLeft: marginLeft, + marginRight: marginRight, + pageRanges: pageRanges + }); + var buffer = new Buffer(result.data, 'base64'); + fs.writeFileSync(filePath, buffer); + } + /** * @return {!Promise} */ @@ -429,6 +477,59 @@ Page.ScreenshotTypes = { JPG: "jpeg", }; +/** @enum {string} */ +Page.PaperFormats = { + Letter: {width: 8.5, height: 11}, + Legal: {width: 8.5, height: 14}, + Tabloid: {width: 11, height: 17}, + Ledger: {width: 17, height: 11}, + A0: {width: 33.1, height: 46.8 }, + A1: {width: 23.4, height: 33.1 }, + A2: {width: 16.5, height: 23.4 }, + A3: {width: 11.7, height: 16.5 }, + A4: {width: 8.27, height: 11.7 }, + A5: {width: 5.83, height: 8.27 }, +}; + +var unitToPixels = { + 'px': 1, + 'in': 96, + 'cm': 37.8, + 'mm': 3.78 +}; + +/** + * @param {(string|number|undefined)} parameter + * @return {(number|undefined)} + */ +function convertPrintParameterToInches(parameter) { + if (typeof parameter === 'undefined') + return undefined; + var pixels; + if (typeof parameter === 'number') { + // Treat numbers as pixel values to be aligned with phantom's paperSize. + pixels = /** @type {number} */ (parameter); + } else if (typeof parameter === 'string') { + var text = parameter; + var unit = text.substring(text.length - 2).toLowerCase(); + var valueText = ''; + if (unitToPixels.hasOwnProperty(unit)) { + valueText = text.substring(0, text.length - 2); + } else { + // In case of unknown unit try to parse the whole parameter as number of pixels. + // This is consistent with phantom's paperSize behavior. + unit = 'px'; + valueText = text; + } + var value = Number(valueText); + console.assert(!isNaN(value), 'Failed to parse parameter value: ' + text); + var pixels = value * unitToPixels[unit]; + } else { + throw new Error('printToPDF Cannot handle parameter type: ' + (typeof parameter)); + } + return pixels / 96; +}; + Page.Events = { Alert: 'alert', BeforeUnload: 'beforeunload', diff --git a/phantomjs/WebPage.js b/phantomjs/WebPage.js index 4acae377377..d658b5cb2e3 100644 --- a/phantomjs/WebPage.js +++ b/phantomjs/WebPage.js @@ -276,7 +276,18 @@ class WebPage { height: this.clipRect.height }; } - var imageBuffer = await(this._page.saveScreenshot(fileName, clipRect)); + if (fileName.endsWith('pdf')) { + var options = {}; + var paperSize = this.paperSize || {}; + options.margin = paperSize.margin; + options.format = paperSize.format; + options.landscape = paperSize.orientation === 'landscape'; + options.width = paperSize.width; + options.height = paperSize.height; + await(this._page.printToPDF(fileName, options)); + } else { + await(this._page.saveScreenshot(fileName, clipRect)); + } } release() {