UNPKG

hummus-recipe

Version:

A powerful PDF tool for NodeJS based on HummusJS

262 lines (230 loc) 7.65 kB
const muhammara = require('muhammara'); /** * Create a new page, specifying either actual width and height, or the name * of a supported page size (eg. 'letter', ) * @name createPage * @function * @memberof Recipe * @param {number|string} [pageWidth_or_pageSizeName='letter'] - The page width, or name of medium size. * Known named medium sizes: executive, folio, legal, letter, ledger, tabloid, a0-a10, b0-b10, c0-c10, ra0-ra4, sra0-ara4 * @param {number} [pageHeight_or_rotation] - The page height, or rotation (90) when when page size name given. * @param {object} [margins] - page margin definitions. * @param {number} [margins.left] - Left margin. * @param {number} [margins.right] - Right margin. * @param {number} [margins.top] - Top margin. * @param {number} [margins.bottom] - Bottom margin. */ exports.createPage = function createPage(pageWidth, pageHeight, margins) { if (!pageWidth && !pageHeight) { [pageWidth, pageHeight] = this.default.pageSize; } else if (pageWidth && !isNaN(pageWidth) && pageHeight && !isNaN(pageHeight)) { pageWidth = pageWidth || this.default.pageSize[0]; pageHeight = pageHeight || this.default.pageSize[1]; } else if (typeof pageWidth === 'string') { const rotate = pageHeight; const pageType = pageWidth.toLowerCase().replace('-size',''); const pageSize = this.default.mediumSizes[pageType]; if (pageSize) { [pageWidth, pageHeight] = pageSize; } else { [pageWidth, pageHeight] = this.default.pageSize; } if (rotate && !isNaN(rotate)) { if (rotate % 180 != 0) { // swap width and height [pageWidth, pageHeight] = [pageHeight, pageWidth]; } } } // from 0 this.metadata.pageCount += 1; const pageNumber = this.metadata.pageCount; const dimensions = [0, 0, pageWidth, pageHeight]; const layout = (pageWidth > pageHeight) ? 'landscape' : 'portrait'; this.metadata[pageNumber] = { pageNumber, mediaBox: dimensions, layout, rotate: 0, width: pageWidth, height: pageHeight }; const page = this.writer.createPage(); page.mediaBox = [0, 0, pageWidth, pageHeight]; this.page = page; this.pageNumber = pageNumber; this.pageContext = this.writer.startPageContentContext(this.page); this.editingPage = false; if (margins) { this.margins(margins); } this.moveTo(0, 0); return this; }; /** * Finish a page * @name endPage * @function * @memberof Recipe */ exports.endPage = function endPage() { if (!this.page) { return this; } if (this.page.endContext) { this.page.endContext(); this.page.writePage(); } else { this.writer.writePage(this.page); } // this.page = null; // this.pageContext = null; // this.pageNumber = 0; return this; }; /** * Start editing a page * @name editPage * @function * @memberof Recipe * @param {number} pageNumber - The page number to be edited. */ exports.editPage = function editPage(pageNumber) { const pdfWriter = this.writer; const pageIndex = pageNumber - 1; const pageModifier = new muhammara.PDFPageModifier(pdfWriter, pageIndex, true); this.page = pageModifier; this.pageNumber = pageNumber; this.pageContext = pageModifier.startContext().getContext(); this.editingPage = true; this._resumePageRotation(pageNumber); if (this.debug) { const context = this.pageContext; const { width, height, mediaBox } = this.metadata[pageNumber]; const startX = mediaBox[0]; const startY = mediaBox[1]; const textOptions = { font: this.writer.getFontForFile(this.fonts['helvetica-bold']), size: 50, colorspace: 'gray', color: 0x00 }; context.writeText(`[${startX}, ${startY}] is HERE`, startX, startY, textOptions); context.writeText(`[${startX}, width/2] is HERE`, startX, width / 2, textOptions); context.writeText(`[${startX}, height/2] is HERE`, startX, height / 2, textOptions); context.writeText(`[width/2, ${startY}] is HERE`, width / 2, startY, textOptions); context.writeText(`[height/2, ${startY}] is HERE`, height / 2, startY, textOptions); } return this; }; exports._resumePageRotation = function _resumePageRotation(pageNumber, context) { pageNumber = pageNumber || this.pageNumber; const { // layout, rotate, width, height, mediaBox } = this.metadata[pageNumber]; context = context || this.pageContext; const startX = mediaBox[0]; const startY = mediaBox[1]; this.page.mediaBox = [startX, startY, width, height]; switch (rotate) { case 90: context.cm(0, 1, -1, 0, height - startX, startY); break; case 180: context.cm(-1, 0, 0, -1, width, height); break; case 270: context.cm(0, -1, 1, 0, startX, width - startY); break; default: } return this; }; /** * Get page information * @name pageInfo * @function * @memberof Recipe * @param {number} pageNumber - The page number. */ exports.pageInfo = function pageInfo(pageNumber) { const pageInfo = this.metadata[pageNumber]; return { width: pageInfo.width, height: pageInfo.height, rotate: pageInfo.rotate, pageNumber }; }; exports.pauseContext = function pauseContext() { if (this.page && this.page.endContext) { this.page.endContext(); // this.writer.pausePageContentContext(this.pageContext); } else if (this.pageContext) { this.writer.pausePageContentContext(this.pageContext); } }; exports.resumeContext = function resumeContext() { if (!this.isNewPDF && this.page) { this.pageContext = this.page.startContext().getContext(); this._resumePageRotation(); } }; exports.getPageInfo = function getPageInfo() { const info = this.writer.getDocumentContext().getInfoDictionary(); return info; }; /** * Set/Get current page margins. * @name margins * @function * @memberof Recipe * @param {number|object} [left] - Left margin width or an object holding margin properties to be set. * Valid margin property names are: left, right, top, bottom. * @param {number} [right] - Right margin width. * @param {number} [top] - Top margin height. * @param {number} [bottom] - Bottom margin height. * @returns {object} When parameters are given, the value returned is the recipe handle. When no * parameters given, the return value is the current page margin object. */ exports.margins = function margins(left, right, top, bottom) { let marginSet = false; if (typeof left === 'object') { const margins = left; left = margins.left; right = margins.right; top = margins.top; bottom = margins.bottom; } if (left !== undefined) { this._margin.left = left; marginSet = true; } if (right !== undefined) { this._margin.right = right; marginSet = true; } if (top !== undefined) { this._margin.top = top; marginSet = true; } if (bottom !== undefined) { this._margin.bottom = bottom; marginSet = true; } // When no parameters given, send back current margins. if (!marginSet) { return this._margin; } return this; };