const hummus = require('hummus');
/**
* 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 hummus.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;
};