UNPKG

pdfmake

Version:

Client/server side PDF printing in pure JavaScript

1,549 lines (1,478 loc) 2.51 MB
/*! pdfmake v0.3.0-beta.14, @license MIT, @link http://pdfmake.org */ (function webpackUniversalModuleDefinition(root, factory) { if(typeof exports === 'object' && typeof module === 'object') module.exports = factory(); else if(typeof define === 'function' && define.amd) define([], factory); else { var a = factory(); for(var i in a) (typeof exports === 'object' ? exports : root)[i] = a[i]; } })(typeof self !== 'undefined' ? self : this, () => { return /******/ (() => { // webpackBootstrap /******/ var __webpack_modules__ = ({ /***/ 428: /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; // EXPORTS __webpack_require__.d(__webpack_exports__, { "default": () => (/* binding */ browser_extensions) }); // EXTERNAL MODULE: ./node_modules/@foliojs-fork/pdfkit/js/pdfkit.es.js var pdfkit_es = __webpack_require__(6837); ;// ./src/PDFDocument.js /* provided dependency */ var Buffer = __webpack_require__(783)["Buffer"]; const typeName = (bold, italics) => { let type = 'normal'; if (bold && italics) { type = 'bolditalics'; } else if (bold) { type = 'bold'; } else if (italics) { type = 'italics'; } return type; }; class PDFDocument extends pdfkit_es/* default */.A { constructor(fonts, images, patterns, attachments, options, virtualfs) { if (fonts === void 0) { fonts = {}; } if (images === void 0) { images = {}; } if (patterns === void 0) { patterns = {}; } if (attachments === void 0) { attachments = {}; } if (options === void 0) { options = {}; } if (virtualfs === void 0) { virtualfs = null; } super(options); this.fonts = {}; this.fontCache = {}; for (let font in fonts) { if (fonts.hasOwnProperty(font)) { let fontDef = fonts[font]; this.fonts[font] = { normal: fontDef.normal, bold: fontDef.bold, italics: fontDef.italics, bolditalics: fontDef.bolditalics }; } } this.patterns = {}; for (let pattern in patterns) { if (patterns.hasOwnProperty(pattern)) { let patternDef = patterns[pattern]; this.patterns[pattern] = this.pattern(patternDef.boundingBox, patternDef.xStep, patternDef.yStep, patternDef.pattern, patternDef.colored); } } this.images = images; this.attachments = attachments; this.virtualfs = virtualfs; } getFontType(bold, italics) { return typeName(bold, italics); } getFontFile(familyName, bold, italics) { let type = this.getFontType(bold, italics); if (!this.fonts[familyName] || !this.fonts[familyName][type]) { return null; } return this.fonts[familyName][type]; } provideFont(familyName, bold, italics) { let type = this.getFontType(bold, italics); if (this.getFontFile(familyName, bold, italics) === null) { throw new Error(`Font '${familyName}' in style '${type}' is not defined in the font section of the document definition.`); } this.fontCache[familyName] = this.fontCache[familyName] || {}; if (!this.fontCache[familyName][type]) { let def = this.fonts[familyName][type]; if (!Array.isArray(def)) { def = [def]; } if (this.virtualfs && this.virtualfs.existsSync(def[0])) { def[0] = this.virtualfs.readFileSync(def[0]); } this.fontCache[familyName][type] = this.font(...def)._font; } return this.fontCache[familyName][type]; } provideImage(src) { const realImageSrc = src => { let image = this.images[src]; if (!image) { return src; } if (this.virtualfs && this.virtualfs.existsSync(image)) { return this.virtualfs.readFileSync(image); } let index = image.indexOf('base64,'); if (index < 0) { return this.images[src]; } return Buffer.from(image.substring(index + 7), 'base64'); }; if (this._imageRegistry[src]) { return this._imageRegistry[src]; } let image; try { image = this.openImage(realImageSrc(src)); if (!image) { throw new Error('No image'); } } catch (error) { throw new Error(`Invalid image: ${error.toString()}\nImages dictionary should contain dataURL entries (or local file paths in node.js)`); } image.embed(this); this._imageRegistry[src] = image; return image; } /** * @param {Array} color pdfmake format: [<pattern name>, <color>] * @returns {Array} pdfkit format: [<pattern object>, <color>] */ providePattern(color) { if (Array.isArray(color) && color.length === 2) { return [this.patterns[color[0]], color[1]]; } return null; } provideAttachment(src) { const checkRequired = obj => { if (!obj) { throw new Error('No attachment'); } if (!obj.src) { throw new Error('The "src" key is required for attachments'); } return obj; }; if (typeof src === 'object') { return checkRequired(src); } let attachment = checkRequired(this.attachments[src]); if (this.virtualfs && this.virtualfs.existsSync(attachment.src)) { return this.virtualfs.readFileSync(attachment.src); } return attachment; } setOpenActionAsPrint() { let printActionRef = this.ref({ Type: 'Action', S: 'Named', N: 'Print' }); this._root.data.OpenAction = printActionRef; printActionRef.end(); } } /* harmony default export */ const src_PDFDocument = (PDFDocument); ;// ./src/helpers/variableType.js /** * @param {any} variable * @returns {boolean} */ function isString(variable) { return typeof variable === 'string' || variable instanceof String; } /** * @param {any} variable * @returns {boolean} */ function isNumber(variable) { return typeof variable === 'number' || variable instanceof Number; } /** * @param {any} variable * @returns {boolean} */ function isPositiveInteger(variable) { if (!isNumber(variable) || !Number.isInteger(variable) || variable <= 0) { return false; } return true; } /** * @param {any} variable * @returns {boolean} */ function isObject(variable) { return variable !== null && !Array.isArray(variable) && !isString(variable) && !isNumber(variable) && typeof variable === 'object'; } /** * @param {any} variable * @returns {boolean} */ function isEmptyObject(variable) { return isObject(variable) && Object.keys(variable).length === 0; } /** * @param {any} variable * @returns {boolean} */ function isValue(variable) { return variable !== undefined && variable !== null; } ;// ./src/helpers/node.js function fontStringify(key, val) { if (key === 'font') { return 'font'; } return val; } /** * Convert node to readable string * * @param {object} node * @returns {string} */ function stringifyNode(node) { return JSON.stringify(node, fontStringify); } /** * @param {object} node * @returns {?string} */ function getNodeId(node) { if (node.id) { return node.id; } if (Array.isArray(node.text)) { for (let n of node.text) { let nodeId = getNodeId(n); if (nodeId) { return nodeId; } } } return null; } /** * @param {object} node * @param {object} styleStack object is instance of PDFDocument * @returns {?Array} */ function getNodeMargin(node, styleStack) { function processSingleMargins(node, currentMargin) { if (node.marginLeft || node.marginTop || node.marginRight || node.marginBottom) { return [node.marginLeft || currentMargin[0] || 0, node.marginTop || currentMargin[1] || 0, node.marginRight || currentMargin[2] || 0, node.marginBottom || currentMargin[3] || 0]; } return currentMargin; } function flattenStyleArray(styleArray, styleStack) { let flattenedStyles = {}; for (let i = styleArray.length - 1; i >= 0; i--) { let styleName = styleArray[i]; let style = styleStack.styleDictionary[styleName]; for (let key in style) { if (style.hasOwnProperty(key)) { flattenedStyles[key] = style[key]; } } } return flattenedStyles; } function convertMargin(margin) { if (isNumber(margin)) { margin = [margin, margin, margin, margin]; } else if (Array.isArray(margin)) { if (margin.length === 2) { margin = [margin[0], margin[1], margin[0], margin[1]]; } } return margin; } let margin = [undefined, undefined, undefined, undefined]; if (node.style) { let styleArray = Array.isArray(node.style) ? node.style : [node.style]; let flattenedStyleArray = flattenStyleArray(styleArray, styleStack); if (flattenedStyleArray) { margin = processSingleMargins(flattenedStyleArray, margin); } if (flattenedStyleArray.margin) { margin = convertMargin(flattenedStyleArray.margin); } } margin = processSingleMargins(node, margin); if (node.margin) { margin = convertMargin(node.margin); } if (margin[0] === undefined && margin[1] === undefined && margin[2] === undefined && margin[3] === undefined) { return null; } return margin; } ;// ./src/DocPreprocessor.js /* provided dependency */ var DocPreprocessor_Buffer = __webpack_require__(783)["Buffer"]; const convertValueToString = value => { if (isString(value)) { return value.replace(/\t/g, ' '); // expand tab as spaces } else if (isNumber(value) || typeof value === 'boolean') { return value.toString(); } else if (!isValue(value) || isEmptyObject(value)) { return ''; } // TODO: throw exception ? return value; }; class DocPreprocessor { preprocessDocument(docStructure) { this.parentNode = null; this.tocs = []; this.nodeReferences = []; return this.preprocessNode(docStructure); } preprocessNode(node) { // expand shortcuts and casting values if (Array.isArray(node)) { node = { stack: node }; } else if (isString(node) || isNumber(node) || typeof node === 'boolean' || !isValue(node) || isEmptyObject(node)) { // text node defined as value node = { text: convertValueToString(node) }; } else if ('text' in node) { // cast value in text property node.text = convertValueToString(node.text); } if (node.columns) { return this.preprocessColumns(node); } else if (node.stack) { return this.preprocessVerticalContainer(node); } else if (node.ul) { return this.preprocessList(node); } else if (node.ol) { return this.preprocessList(node); } else if (node.table) { return this.preprocessTable(node); } else if (node.text !== undefined) { return this.preprocessText(node); } else if (node.toc) { return this.preprocessToc(node); } else if (node.image) { return this.preprocessImage(node); } else if (node.svg) { return this.preprocessSVG(node); } else if (node.canvas) { return this.preprocessCanvas(node); } else if (node.qr) { return this.preprocessQr(node); } else if (node.attachment) { return this.preprocessAttachment(node); } else if (node.pageReference || node.textReference) { return this.preprocessText(node); } else { throw new Error(`Unrecognized document structure: ${stringifyNode(node)}`); } } preprocessColumns(node) { let columns = node.columns; for (let i = 0, l = columns.length; i < l; i++) { columns[i] = this.preprocessNode(columns[i]); } return node; } preprocessVerticalContainer(node) { let items = node.stack; for (let i = 0, l = items.length; i < l; i++) { items[i] = this.preprocessNode(items[i]); } return node; } preprocessList(node) { let items = node.ul || node.ol; for (let i = 0, l = items.length; i < l; i++) { items[i] = this.preprocessNode(items[i]); } return node; } preprocessTable(node) { let col; let row; let cols; let rows; for (col = 0, cols = node.table.body[0].length; col < cols; col++) { for (row = 0, rows = node.table.body.length; row < rows; row++) { let rowData = node.table.body[row]; let data = rowData[col]; if (data !== undefined) { if (data === null) { // transform to object data = ''; } if (!data._span) { rowData[col] = this.preprocessNode(data); } } } } return node; } preprocessText(node) { if (node.tocItem) { if (!Array.isArray(node.tocItem)) { node.tocItem = [node.tocItem]; } for (let i = 0, l = node.tocItem.length; i < l; i++) { if (!isString(node.tocItem[i])) { node.tocItem[i] = '_default_'; } let tocItemId = node.tocItem[i]; if (!this.tocs[tocItemId]) { this.tocs[tocItemId] = { toc: { _items: [], _pseudo: true } }; } if (!node.id) { node.id = `toc-${tocItemId}-${this.tocs[tocItemId].toc._items.length}`; } let tocItemRef = { _nodeRef: this._getNodeForNodeRef(node), _textNodeRef: node }; this.tocs[tocItemId].toc._items.push(tocItemRef); } } if (node.id) { if (this.nodeReferences[node.id]) { if (!this.nodeReferences[node.id]._pseudo) { throw new Error(`Node id '${node.id}' already exists`); } this.nodeReferences[node.id]._nodeRef = this._getNodeForNodeRef(node); this.nodeReferences[node.id]._textNodeRef = node; this.nodeReferences[node.id]._pseudo = false; } else { this.nodeReferences[node.id] = { _nodeRef: this._getNodeForNodeRef(node), _textNodeRef: node }; } } if (node.pageReference) { if (!this.nodeReferences[node.pageReference]) { this.nodeReferences[node.pageReference] = { _nodeRef: {}, _textNodeRef: {}, _pseudo: true }; } node.text = '00000'; node.linkToDestination = node.pageReference; node._pageRef = this.nodeReferences[node.pageReference]; } if (node.textReference) { if (!this.nodeReferences[node.textReference]) { this.nodeReferences[node.textReference] = { _nodeRef: {}, _pseudo: true }; } node.text = ''; node.linkToDestination = node.textReference; node._textRef = this.nodeReferences[node.textReference]; } if (node.text && node.text.text) { node.text = [this.preprocessNode(node.text)]; } else if (Array.isArray(node.text)) { let isSetParentNode = false; if (this.parentNode === null) { this.parentNode = node; isSetParentNode = true; } for (let i = 0, l = node.text.length; i < l; i++) { node.text[i] = this.preprocessNode(node.text[i]); } if (isSetParentNode) { this.parentNode = null; } } return node; } preprocessToc(node) { if (!node.toc.id) { node.toc.id = '_default_'; } node.toc.title = node.toc.title ? this.preprocessNode(node.toc.title) : null; node.toc._items = []; if (this.tocs[node.toc.id]) { if (!this.tocs[node.toc.id].toc._pseudo) { throw new Error(`TOC '${node.toc.id}' already exists`); } node.toc._items = this.tocs[node.toc.id].toc._items; } this.tocs[node.toc.id] = node; return node; } preprocessImage(node) { if (node.image.type !== undefined && node.image.data !== undefined && node.image.type === 'Buffer' && Array.isArray(node.image.data)) { node.image = DocPreprocessor_Buffer.from(node.image.data); } return node; } preprocessCanvas(node) { return node; } preprocessSVG(node) { return node; } preprocessQr(node) { return node; } preprocessAttachment(node) { return node; } _getNodeForNodeRef(node) { if (this.parentNode) { return this.parentNode; } return node; } } /* harmony default export */ const src_DocPreprocessor = (DocPreprocessor); // EXTERNAL MODULE: ./node_modules/@foliojs-fork/linebreak/src/linebreaker.js var linebreaker = __webpack_require__(9534); var linebreaker_default = /*#__PURE__*/__webpack_require__.n(linebreaker); ;// ./src/StyleContextStack.js /** * Used for style inheritance and style overrides */ class StyleContextStack { /** * @param {object} styleDictionary named styles dictionary * @param {object} defaultStyle optional default style definition */ constructor(styleDictionary, defaultStyle) { if (defaultStyle === void 0) { defaultStyle = {}; } this.styleDictionary = styleDictionary; this.defaultStyle = defaultStyle; this.styleOverrides = []; } /** * Creates cloned version of current stack * * @returns {StyleContextStack} current stack snapshot */ clone() { let stack = new StyleContextStack(this.styleDictionary, this.defaultStyle); this.styleOverrides.forEach(item => { stack.styleOverrides.push(item); }); return stack; } /** * Pushes style-name or style-overrides-object onto the stack for future evaluation * * @param {string|object} styleNameOrOverride style-name (referring to styleDictionary) or * a new dictionary defining overriding properties */ push(styleNameOrOverride) { this.styleOverrides.push(styleNameOrOverride); } /** * Removes last style-name or style-overrides-object from the stack * * @param {number} howMany optional number of elements to be popped (if not specified, * one element will be removed from the stack) */ pop(howMany) { if (howMany === void 0) { howMany = 1; } while (howMany-- > 0) { this.styleOverrides.pop(); } } /** * Creates a set of named styles or/and a style-overrides-object based on the item, * pushes those elements onto the stack for future evaluation and returns the number * of elements pushed, so they can be easily poped then. * * @param {object} item - an object with optional style property and/or style overrides * @returns {number} the number of items pushed onto the stack */ autopush(item) { if (isString(item)) { return 0; } let styleNames = []; if (item.style) { if (Array.isArray(item.style)) { styleNames = item.style; } else { styleNames = [item.style]; } } for (let i = 0, l = styleNames.length; i < l; i++) { this.push(styleNames[i]); } // rather than spend significant time making a styleOverrideObject, just add item this.push(item); return styleNames.length + 1; } /** * Automatically pushes elements onto the stack, using autopush based on item, * executes callback and then pops elements back. Returns value returned by callback * * @param {object} item - an object with optional style property and/or style overrides * @param {Function} callback to be called between autopush and pop * @returns {object} value returned by callback */ auto(item, callback) { let pushedItems = this.autopush(item); let result = callback(); if (pushedItems > 0) { this.pop(pushedItems); } return result; } /** * Evaluates stack and returns value of a named property * * @param {string} property - property name * @returns {?any} property value or null if not found */ getProperty(property) { if (this.styleOverrides) { for (let i = this.styleOverrides.length - 1; i >= 0; i--) { let item = this.styleOverrides[i]; if (isString(item)) { // named-style-override let style = this.styleDictionary[item]; if (style && isValue(style[property])) { return style[property]; } } else if (isValue(item[property])) { // style-overrides-object return item[property]; } } } return this.defaultStyle && this.defaultStyle[property]; } /** * @param {object} item * @param {StyleContextStack} styleContextStack * @param {string} property * @param {any} defaultValue * @returns {any} */ static getStyleProperty(item, styleContextStack, property, defaultValue) { let value; if (isValue(item[property])) { // item defines this property return item[property]; } if (!styleContextStack) { return defaultValue; } styleContextStack.auto(item, () => { value = styleContextStack.getProperty(property); }); return isValue(value) ? value : defaultValue; } /** * @param {object} source * @param {object} destination * @returns {object} */ static copyStyle(source, destination) { if (source === void 0) { source = {}; } if (destination === void 0) { destination = {}; } // TODO: default style to source for (let key in source) { if (key != 'text' && source.hasOwnProperty(key)) { destination[key] = source[key]; } } return destination; } } /* harmony default export */ const src_StyleContextStack = (StyleContextStack); ;// ./src/TextBreaker.js /** * @param {string} text * @param {boolean} noWrap * @returns {Array} */ const splitWords = (text, noWrap) => { let words = []; if (noWrap) { words.push({ text: text }); return words; } let breaker = new (linebreaker_default())(text); let last = 0; let bk; while (bk = breaker.nextBreak()) { let word = text.slice(last, bk.position); if (bk.required || word.match(/\r?\n$|\r$/)) { // new line word = word.replace(/\r?\n$|\r$/, ''); words.push({ text: word, lineEnd: true }); } else { words.push({ text: word }); } last = bk.position; } return words; }; /** * @param {Array} words * @param {boolean} noWrap * @returns {?string} */ const getFirstWord = (words, noWrap) => { let word = words[0]; if (word === undefined) { return null; } if (noWrap) { // text was not wrapped, we need only first word let tmpWords = splitWords(word.text, false); if (tmpWords[0] === undefined) { return null; } word = tmpWords[0]; } return word.text; }; /** * @param {Array} words * @param {boolean} noWrap * @returns {?string} */ const getLastWord = (words, noWrap) => { let word = words[words.length - 1]; if (word === undefined) { return null; } if (word.lineEnd) { return null; } if (noWrap) { // text was not wrapped, we need only last word let tmpWords = splitWords(word.text, false); if (tmpWords[tmpWords.length - 1] === undefined) { return null; } word = tmpWords[tmpWords.length - 1]; } return word.text; }; class TextBreaker { /** * @param {string|Array} texts * @param {StyleContextStack} styleContextStack * @returns {Array} */ getBreaks(texts, styleContextStack) { let results = []; if (!Array.isArray(texts)) { texts = [texts]; } let lastWord = null; for (let i = 0, l = texts.length; i < l; i++) { let item = texts[i]; let style = null; let words; let noWrap = src_StyleContextStack.getStyleProperty(item || {}, styleContextStack, 'noWrap', false); if (isObject(item)) { if (item._textRef && item._textRef._textNodeRef.text) { item.text = item._textRef._textNodeRef.text; } words = splitWords(item.text, noWrap); style = src_StyleContextStack.copyStyle(item); } else { words = splitWords(item, noWrap); } if (lastWord && words.length) { let firstWord = getFirstWord(words, noWrap); let wrapWords = splitWords(lastWord + firstWord, false); if (wrapWords.length === 1) { results[results.length - 1].noNewLine = true; } } for (let i2 = 0, l2 = words.length; i2 < l2; i2++) { let result = { text: words[i2].text }; if (words[i2].lineEnd) { result.lineEnd = true; } src_StyleContextStack.copyStyle(style, result); results.push(result); } lastWord = null; if (i + 1 < l) { lastWord = getLastWord(words, noWrap); } } return results; } } /* harmony default export */ const src_TextBreaker = (TextBreaker); ;// ./src/TextInlines.js const LEADING = /^(\s)+/g; const TRAILING = /(\s)+$/g; /** * @param {Array} array * @returns {Array} */ const flattenTextArray = array => { function flatten(array) { return array.reduce((prev, cur) => { let current = Array.isArray(cur.text) ? flatten(cur.text) : cur; let more = [].concat(current).some(Array.isArray); return prev.concat(more ? flatten(current) : current); }, []); } if (!Array.isArray(array)) { array = [array]; } // TODO: Styling in nested text (issue: https://github.com/bpampuch/pdfmake/issues/1174) array = flatten(array); return array; }; /** * Text measurement utility */ class TextInlines { /** * @param {object} pdfDocument object is instance of PDFDocument */ constructor(pdfDocument) { this.pdfDocument = pdfDocument; } /** * Converts an array of strings (or inline-definition-objects) into a collection * of inlines and calculated minWidth/maxWidth and their min/max widths * * @param {Array|object} textArray an array of inline-definition-objects (or strings) * @param {StyleContextStack} styleContextStack current style stack * @returns {object} collection of inlines, minWidth, maxWidth */ buildInlines(textArray, styleContextStack) { const getTrimmedWidth = item => { return Math.max(0, item.width - item.leadingCut - item.trailingCut); }; let minWidth = 0; let maxWidth = 0; let currentLineWidth; let flattenedTextArray = flattenTextArray(textArray); const textBreaker = new src_TextBreaker(); let breakedText = textBreaker.getBreaks(flattenedTextArray, styleContextStack); let measuredText = this.measure(breakedText, styleContextStack); measuredText.forEach(inline => { minWidth = Math.max(minWidth, getTrimmedWidth(inline)); if (!currentLineWidth) { currentLineWidth = { width: 0, leadingCut: inline.leadingCut, trailingCut: 0 }; } currentLineWidth.width += inline.width; currentLineWidth.trailingCut = inline.trailingCut; maxWidth = Math.max(maxWidth, getTrimmedWidth(currentLineWidth)); if (inline.lineEnd) { currentLineWidth = null; } }); if (src_StyleContextStack.getStyleProperty({}, styleContextStack, 'noWrap', false)) { minWidth = maxWidth; } return { items: measuredText, minWidth: minWidth, maxWidth: maxWidth }; } measure(array, styleContextStack) { if (array.length) { let leadingIndent = src_StyleContextStack.getStyleProperty(array[0], styleContextStack, 'leadingIndent', 0); if (leadingIndent) { array[0].leadingCut = -leadingIndent; array[0].leadingIndent = leadingIndent; } } array.forEach(item => { let font = src_StyleContextStack.getStyleProperty(item, styleContextStack, 'font', 'Roboto'); let bold = src_StyleContextStack.getStyleProperty(item, styleContextStack, 'bold', false); let italics = src_StyleContextStack.getStyleProperty(item, styleContextStack, 'italics', false); item.font = this.pdfDocument.provideFont(font, bold, italics); item.alignment = src_StyleContextStack.getStyleProperty(item, styleContextStack, 'alignment', 'left'); item.fontSize = src_StyleContextStack.getStyleProperty(item, styleContextStack, 'fontSize', 12); item.fontFeatures = src_StyleContextStack.getStyleProperty(item, styleContextStack, 'fontFeatures', null); item.characterSpacing = src_StyleContextStack.getStyleProperty(item, styleContextStack, 'characterSpacing', 0); item.color = src_StyleContextStack.getStyleProperty(item, styleContextStack, 'color', 'black'); item.decoration = src_StyleContextStack.getStyleProperty(item, styleContextStack, 'decoration', null); item.decorationColor = src_StyleContextStack.getStyleProperty(item, styleContextStack, 'decorationColor', null); item.decorationStyle = src_StyleContextStack.getStyleProperty(item, styleContextStack, 'decorationStyle', null); item.background = src_StyleContextStack.getStyleProperty(item, styleContextStack, 'background', null); item.link = src_StyleContextStack.getStyleProperty(item, styleContextStack, 'link', null); item.linkToPage = src_StyleContextStack.getStyleProperty(item, styleContextStack, 'linkToPage', null); item.linkToDestination = src_StyleContextStack.getStyleProperty(item, styleContextStack, 'linkToDestination', null); item.noWrap = src_StyleContextStack.getStyleProperty(item, styleContextStack, 'noWrap', null); item.opacity = src_StyleContextStack.getStyleProperty(item, styleContextStack, 'opacity', 1); item.sup = src_StyleContextStack.getStyleProperty(item, styleContextStack, 'sup', false); item.sub = src_StyleContextStack.getStyleProperty(item, styleContextStack, 'sub', false); if (item.sup || item.sub) { // font size reduction taken from here: https://en.wikipedia.org/wiki/Subscript_and_superscript#Desktop_publishing item.fontSize *= 0.58; } let lineHeight = src_StyleContextStack.getStyleProperty(item, styleContextStack, 'lineHeight', 1); item.width = this.widthOfText(item.text, item); item.height = item.font.lineHeight(item.fontSize) * lineHeight; if (!item.leadingCut) { item.leadingCut = 0; } let preserveLeadingSpaces = src_StyleContextStack.getStyleProperty(item, styleContextStack, 'preserveLeadingSpaces', false); if (!preserveLeadingSpaces) { let leadingSpaces = item.text.match(LEADING); if (leadingSpaces) { item.leadingCut += this.widthOfText(leadingSpaces[0], item); } } item.trailingCut = 0; let preserveTrailingSpaces = src_StyleContextStack.getStyleProperty(item, styleContextStack, 'preserveTrailingSpaces', false); if (!preserveTrailingSpaces) { let trailingSpaces = item.text.match(TRAILING); if (trailingSpaces) { item.trailingCut = this.widthOfText(trailingSpaces[0], item); } } }, this); return array; } /** * Width of text * * @param {string} text * @param {object} inline * @returns {number} */ widthOfText(text, inline) { return inline.font.widthOfString(text, inline.fontSize, inline.fontFeatures) + (inline.characterSpacing || 0) * (text.length - 1); } /** * Returns size of the specified string (without breaking it) using the current style * * @param {string} text text to be measured * @param {object} styleContextStack current style stack * @returns {object} size of the specified string */ sizeOfText(text, styleContextStack) { //TODO: refactor - extract from measure let fontName = src_StyleContextStack.getStyleProperty({}, styleContextStack, 'font', 'Roboto'); let fontSize = src_StyleContextStack.getStyleProperty({}, styleContextStack, 'fontSize', 12); let fontFeatures = src_StyleContextStack.getStyleProperty({}, styleContextStack, 'fontFeatures', null); let bold = src_StyleContextStack.getStyleProperty({}, styleContextStack, 'bold', false); let italics = src_StyleContextStack.getStyleProperty({}, styleContextStack, 'italics', false); let lineHeight = src_StyleContextStack.getStyleProperty({}, styleContextStack, 'lineHeight', 1); let characterSpacing = src_StyleContextStack.getStyleProperty({}, styleContextStack, 'characterSpacing', 0); let font = this.pdfDocument.provideFont(fontName, bold, italics); return { width: this.widthOfText(text, { font: font, fontSize: fontSize, characterSpacing: characterSpacing, fontFeatures: fontFeatures }), height: font.lineHeight(fontSize) * lineHeight, fontSize: fontSize, lineHeight: lineHeight, ascender: font.ascender / 1000 * fontSize, descender: font.descender / 1000 * fontSize }; } /** * Returns size of the specified rotated string (without breaking it) using the current style * * @param {string} text text to be measured * @param {number} angle * @param {object} styleContextStack current style stack * @returns {object} size of the specified string */ sizeOfRotatedText(text, angle, styleContextStack) { let angleRad = angle * Math.PI / -180; let size = this.sizeOfText(text, styleContextStack); return { width: Math.abs(size.height * Math.sin(angleRad)) + Math.abs(size.width * Math.cos(angleRad)), height: Math.abs(size.width * Math.sin(angleRad)) + Math.abs(size.height * Math.cos(angleRad)) }; } } /* harmony default export */ const src_TextInlines = (TextInlines); ;// ./src/columnCalculator.js function buildColumnWidths(columns, availableWidth, offsetTotal, tableNode) { if (offsetTotal === void 0) { offsetTotal = 0; } let autoColumns = []; let autoMin = 0; let autoMax = 0; let starColumns = []; let starMaxMin = 0; let starMaxMax = 0; let fixedColumns = []; let initial_availableWidth = availableWidth; columns.forEach(column => { if (isAutoColumn(column)) { autoColumns.push(column); autoMin += column._minWidth; autoMax += column._maxWidth; } else if (isStarColumn(column)) { starColumns.push(column); starMaxMin = Math.max(starMaxMin, column._minWidth); starMaxMax = Math.max(starMaxMax, column._maxWidth); } else { fixedColumns.push(column); } }); fixedColumns.forEach((col, colIndex) => { // width specified as % if (isString(col.width) && /\d+%/.test(col.width)) { // In tables we have to take into consideration the reserved width for paddings and borders let reservedWidth = 0; if (tableNode) { const paddingLeft = tableNode._layout.paddingLeft(colIndex, tableNode); const paddingRight = tableNode._layout.paddingRight(colIndex, tableNode); const borderLeft = tableNode._layout.vLineWidth(colIndex, tableNode); const borderRight = tableNode._layout.vLineWidth(colIndex + 1, tableNode); if (colIndex === 0) { // first column assumes whole borderLeft and half of border right reservedWidth = paddingLeft + paddingRight + borderLeft + borderRight / 2; } else if (colIndex === fixedColumns.length - 1) { // last column assumes whole borderRight and half of border left reservedWidth = paddingLeft + paddingRight + borderLeft / 2 + borderRight; } else { // Columns in the middle assume half of each border reservedWidth = paddingLeft + paddingRight + borderLeft / 2 + borderRight / 2; } } const totalAvailableWidth = initial_availableWidth + offsetTotal; col.width = parseFloat(col.width) * totalAvailableWidth / 100 - reservedWidth; } if (col.width < col._minWidth && col.elasticWidth) { col._calcWidth = col._minWidth; } else { col._calcWidth = col.width; } availableWidth -= col._calcWidth; }); // http://www.freesoft.org/CIE/RFC/1942/18.htm // http://www.w3.org/TR/CSS2/tables.html#width-layout // http://dev.w3.org/csswg/css3-tables-algorithms/Overview.src.htm let minW = autoMin + starMaxMin * starColumns.length; let maxW = autoMax + starMaxMax * starColumns.length; if (minW >= availableWidth) { // case 1 - there's no way to fit all columns within available width // that's actually pretty bad situation with PDF as we have no horizontal scroll // no easy workaround (unless we decide, in the future, to split single words) // currently we simply use minWidths for all columns autoColumns.forEach(col => { col._calcWidth = col._minWidth; }); starColumns.forEach(col => { col._calcWidth = starMaxMin; // starMaxMin already contains padding }); } else { if (maxW < availableWidth) { // case 2 - we can fit rest of the table within available space autoColumns.forEach(col => { col._calcWidth = col._maxWidth; availableWidth -= col._calcWidth; }); } else { // maxW is too large, but minW fits within available width let W = availableWidth - minW; let D = maxW - minW; autoColumns.forEach(col => { let d = col._maxWidth - col._minWidth; col._calcWidth = col._minWidth + d * W / D; availableWidth -= col._calcWidth; }); } if (starColumns.length > 0) { let starSize = availableWidth / starColumns.length; starColumns.forEach(col => { col._calcWidth = starSize; }); } } } function isAutoColumn(column) { return column.width === 'auto'; } function isStarColumn(column) { return column.width === null || column.width === undefined || column.width === '*' || column.width === 'star'; } //TODO: refactor and reuse in measureTable function measureMinMax(columns) { let result = { min: 0, max: 0 }; let maxStar = { min: 0, max: 0 }; let starCount = 0; for (let i = 0, l = columns.length; i < l; i++) { let c = columns[i]; if (isStarColumn(c)) { maxStar.min = Math.max(maxStar.min, c._minWidth); maxStar.max = Math.max(maxStar.max, c._maxWidth); starCount++; } else if (isAutoColumn(c)) { result.min += c._minWidth; result.max += c._maxWidth; } else { result.min += c.width !== undefined && c.width || c._minWidth; result.max += c.width !== undefined && c.width || c._maxWidth; } } if (starCount) { result.min += starCount * maxStar.min; result.max += starCount * maxStar.max; } return result; } /** * Calculates column widths */ /* harmony default export */ const columnCalculator = ({ buildColumnWidths: buildColumnWidths, measureMinMax: measureMinMax, isAutoColumn: isAutoColumn, isStarColumn: isStarColumn }); ;// ./src/tableLayouts.js /*eslint no-unused-vars: ["error", {"args": "none"}]*/ const tableLayouts = { noBorders: { hLineWidth(i) { return 0; }, vLineWidth(i) { return 0; }, paddingLeft(i) { return i && 4 || 0; }, paddingRight(i, node) { return i < node.table.widths.length - 1 ? 4 : 0; } }, headerLineOnly: { hLineWidth(i, node) { if (i === 0 || i === node.table.body.length) { return 0; } return i === node.table.headerRows ? 2 : 0; }, vLineWidth(i) { return 0; }, paddingLeft(i) { return i === 0 ? 0 : 8; }, paddingRight(i, node) { return i === node.table.widths.length - 1 ? 0 : 8; } }, lightHorizontalLines: { hLineWidth(i, node) { if (i === 0 || i === node.table.body.length) { return 0; } return i === node.table.headerRows ? 2 : 1; }, vLineWidth(i) { return 0; }, hLineColor(i) { return i === 1 ? 'black' : '#aaa'; }, paddingLeft(i) { return i === 0 ? 0 : 8; }, paddingRight(i, node) { return i === node.table.widths.length - 1 ? 0 : 8; } } }; const defaultTableLayout = { hLineWidth(i, node) { return 1; }, vLineWidth(i, node) { return 1; }, hLineColor(i, node) { return 'black'; }, vLineColor(i, node) { return 'black'; }, hLineStyle(i, node) { return null; }, vLineStyle(i, node) { return null; }, paddingLeft(i, node) { return 4; }, paddingRight(i, node) { return 4; }, paddingTop(i, node) { return 2; }, paddingBottom(i, node) { return 2; }, fillColor(i, node) { return null; }, fillOpacity(i, node) { return 1; }, defaultBorder: true }; ;// ./src/helpers/tools.js function pack() { let result = {}; for (let i = 0, l = arguments.length; i < l; i++) { let obj = i < 0 || arguments.length <= i ? undefined : arguments[i]; if (obj) { for (let key in obj) { if (obj.hasOwnProperty(key)) { result[key] = obj[key]; } } } } return result; } function offsetVector(vector, x, y) { switch (vector.type) { case 'ellipse': case 'rect': vector.x += x; vector.y += y; break; case 'line': vector.x1 += x; vector.x2 += x; vector.y1 += y; vector.y2 += y; break; case 'polyline': for (let i = 0, l = vector.points.length; i < l; i++) { vector.points[i].x += x; vector.points[i].y += y; } break; } } function convertToDynamicContent(staticContent) { return () => // copy to new object JSON.parse(JSON.stringify(staticContent)); } ;// ./src/qrEnc.js /*eslint no-unused-vars: ["error", {"args": "none"}]*/ /*eslint no-redeclare: "off"*/ /*eslint no-throw-literal: "off"*/ /* qr.js -- QR code generator in Javascript (revision 2011-01-19) * Written by Kang Seonghoon <public+qrjs@mearie.org>. * * This source code is in the public domain; if your jurisdiction does not * recognize the public domain the terms of Creative Commons CC0 license * apply. In the other words, you can always do what you want. */ // per-version information (cf. JIS X 0510:2004 pp. 30--36, 71) // // [0]: the degree of generator polynomial by ECC levels // [1]: # of code blocks by ECC levels // [2]: left-top positions of alignment patterns // // the number in this table (in particular, [0]) does not exactly match with // the numbers in the specficiation. see augumenteccs below for the reason. var VERSIONS = [null, [[10, 7, 17, 13], [1, 1, 1, 1], []], [[16, 10, 28, 22], [1, 1, 1, 1], [4, 16]], [[26, 15, 22, 18], [1, 1, 2, 2], [4, 20]], [[18, 20, 16, 26], [2, 1, 4, 2], [4, 24]], [[24, 26, 22, 18], [2, 1, 4, 4], [4, 28]], [[16, 18, 28, 24], [4, 2, 4, 4], [4, 32]], [[18, 20, 26, 18], [4, 2, 5, 6], [4, 20, 36]], [[22, 24, 26, 22], [4, 2, 6, 6], [4, 22, 40]], [[22, 30, 24, 20], [5, 2, 8, 8], [4, 24, 44]], [[26, 18, 28, 24], [5, 4, 8, 8], [4, 26, 48]], [[30, 20, 24, 28], [5, 4, 11, 8], [4, 28, 52]], [[22, 24, 28, 26], [8, 4, 11, 10], [4, 30, 56]], [[22, 26, 22, 24], [9, 4, 16, 12], [4, 32, 60]], [[24, 30, 24, 20], [9, 4, 16, 16], [4, 24, 44, 64]], [[24, 22, 24, 30], [10, 6, 18, 12], [4, 24, 46, 68]], [[28, 24, 30, 24], [10, 6, 16, 17], [4, 24, 48, 72]], [[28, 28, 28, 28], [11, 6, 19, 16], [4, 28, 52, 76]], [[26, 30, 28, 28], [13, 6, 21, 18], [4, 28, 54, 80]], [[26, 28, 26, 26], [14, 7, 25, 21], [4, 28, 56, 84]], [[26, 28, 28, 30], [16, 8, 25, 20], [4, 32, 60, 88]], [[26, 28, 30, 28], [17, 8, 25, 23], [4, 26, 48, 70, 92]], [[28, 28, 24, 30], [17, 9, 34, 23], [4, 24, 48, 72, 96]], [[28, 30, 30, 30], [18, 9, 30, 25], [4, 28, 52, 76, 100]], [[28, 30, 30, 30], [20, 10, 32, 27], [4, 26, 52, 78, 104]], [[28, 26, 30, 30], [21, 12, 35, 29], [4, 30, 56, 82, 108]], [[28, 28, 30, 28], [23, 12, 37, 34], [4, 28, 56, 84, 112]], [[28, 30, 30, 30], [25, 12, 40, 34], [4, 32, 60, 88, 116]], [[28, 30, 30, 30], [26, 13, 42, 35], [4, 24, 48, 72, 96, 120]], [[28, 30, 30, 30], [28, 14, 45, 38], [4, 28, 52, 76, 100, 124]], [[28, 30, 30, 30], [29, 15, 48, 40], [4, 24, 50, 76, 102, 128]], [[28, 30, 30, 30], [31, 16, 51, 43], [4, 28, 54, 80, 106, 132]], [[28, 30, 30, 30], [33, 17, 54, 45], [4, 32, 58, 84, 110, 136]], [[28, 30, 30, 30], [35, 18, 57, 48], [4, 28, 56, 84, 112, 140]], [[28, 30, 30, 30], [37, 19, 60, 51], [4, 32, 60, 88, 116, 144]], [[28, 30, 30, 30], [38, 19, 63, 53], [4, 28, 52, 76, 100, 124, 148]], [[28, 30, 30, 30], [40, 20, 66, 56], [4, 22, 48, 74, 100, 126, 152]], [[28, 30, 30, 30], [43, 21, 70, 59], [4, 26, 52, 78, 104, 130, 156]], [[28, 30, 30, 30], [45, 22, 74, 62], [4, 30, 56, 82, 108, 134, 160]], [[28, 30, 30, 30], [47, 24, 77, 65], [4, 24, 52, 80, 108, 136, 164]], [[28, 30, 30, 30], [49, 25, 81, 68], [4, 28, 56, 84, 112, 140, 168]]]; // mode constants (cf. Table 2 in JIS X 0510:2004 p. 16) var MODE_TERMINATOR = 0; var MODE_NUMERIC = 1, MODE_ALPHANUMERIC = 2, MODE_OCTET = 4, MODE_KANJI = 8; // validation regexps var NUMERIC_REGEXP = /^\d*$/; var ALPHANUMERIC_REGEXP = /^[A-Za-z0-9 $%*+\-./:]*$/; var ALPHANUMERIC_OUT_REGEXP = /^[A-Z0-9 $%*+\-./:]*$/; // ECC levels (cf. Table 22 in JIS X 0510:2004 p. 45) var ECCLEVEL_L = 1, ECCLEVEL_M = 0, ECCLEVEL_Q = 3, ECCLEVEL_H = 2; // GF(2^8)-to-integer mapping with a reducing polynomial x^8+x^4+x^3+x^2+1 // invariant: GF256_MAP[GF256_INVMAP[i]] == i for all i in [1,256) var GF256_MAP = [], GF256_INVMAP = [-1]; for (var i = 0, v = 1; i < 255; ++i) { GF256_MAP.push(v); GF256_INVMAP[v] = i; v = v * 2 ^ (v >= 128 ? 0x11d : 0); } // generator polynomials up to degree 30 // (should match with polynomials in JIS X 0510:2004 Appendix A) // // generator polynomial of degree K is product of (x-\alpha^0), (x-\alpha^1), // ..., (x-\alpha^(K-1)). by convention, we omit the K-th coefficient (always 1) // from the result; also other coefficients are written in terms of the exponent // to \alpha to avoid the redundant calculation. (see also calculateecc below.) var GF256_GENPOLY = [[]]; for (var i = 0; i < 30; ++i) { var prevpoly = GF256_GENPOLY[i], poly = []; for (var j = 0; j <= i; ++j) { var a = j < i ? GF256_MAP[prevpoly[j]] : 0; var b = GF256_MAP[(i + (prevpoly[j - 1] || 0)) % 255]; poly.push(GF256_INVMAP[a ^ b]); } GF256_GENPOLY.push(poly); } // alphanumeric character mapping (cf. Table 5 in JIS X 0510:2004 p. 19) var ALPHANUMERIC_MAP = {}; for (var i = 0; i < 45; ++i) { ALPHANUMERIC_MAP['0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:'.charAt(i)] = i; } // mask functions in terms of row # and column # // (cf. Table 20 in JIS X 0510:2004 p. 42) /*jshint unused: false */ var MASKFUNCS = [function (i, j) { return (i + j) % 2 === 0; }, function (i, j) { return i % 2 === 0; }, function (i, j) { return j % 3 === 0; }, function (i, j) { return (i + j) % 3 === 0; }, function (i, j) { return ((i / 2 | 0) + (j / 3 | 0)) % 2 === 0; }, function (i, j) { return i * j % 2 + i * j % 3 === 0; }, function (i, j) { return (i * j % 2 + i * j % 3) % 2 === 0; }, function (i, j) { return ((i + j) % 2 + i * j % 3) % 2 === 0; }]; // returns true when the version information has to be embeded. var needsverinfo = function (ver) { return ver > 6; }; // returns the size of entire QR code for given version. var getsizebyver = function (ver) { return 4 * ver + 17; }; // returns the number of bits available for code words in this version. var nfullbits = function (ver) { /* * |<--------------- n --------------->| * | |<----- n-17 ---->| | * +-------+ ///+-------+ ---- * | | ///| | ^ * | 9x9 | @@@@@ ///| 9x8 | | * | | # # # @5x5@ # # # | | | * +-------+ @@@@@ +-------+ | * # ---| * ^ | * # | * @@@@@ @@@@@ @@@@@ | n * @5x5@ @5x5@ @5x5@ n-17 * @@@@@ @@@@@ @@@@@ | | * # | | * ////// v | * //////# ---| * +-------+ @@@@@ @@@@@ | * | | @5x5@ @5x5@ | * | 8x9 | @@@@@ @@@@@ | * | | v * +-------+ ---- * * when the entire code has n^2 modules and there are m^2-3 alignment * patterns, we have: * - 225 (= 9x9 + 9x8 + 8x9) modules for finder patterns and * format information; * - 2n-34 (= 2(n-17)) modules for timing patterns; * - 36 (= 3x6 + 6x3) modules for version information, if any; * - 25m^2-75 (= (m^2-3)(5x5)) modules for alignment patterns * if any, but 10m-20 (= 2(m-2)x5) of them overlaps with * timing patterns. */ var v = VERSIONS[ver]; var nbits = 16 * ver * ver + 128 * ver + 64; // finder, timing and format info. if (needsverinfo(ver)) nbits -= 36; // version information if (v[2].length) { // alignment patterns nbits -= 25 * v[2].length * v[2].length - 10 * v[2].length - 55; } return nbits; }; // returns the number of bits available for data portions (i.e. excludes ECC // bits but includes mode and length bits) in this version and ECC level. var ndatabits = function (ver, ecclevel) { var nbits = nfullbits(ver) & ~7; // no sub-octet code words var v = VERSIONS[ver]; nbits -= 8 * v[0][ecclevel] * v[1][ecclevel]; // ecc bits return nbits; }; // returns the number of bits required for the length of data. // (cf. Table 3 in JIS X 0510:2004 p. 16) var ndatalenbits = function (ver, mode) { switch (mode) { case MODE_NUMERIC: return ver < 10 ? 10 : ver < 27 ? 12 : 14; case MODE_ALPHANUMERIC: return ver < 10 ? 9 : ver < 27 ? 11 : 13; case MODE_OCTET: return ver < 10 ? 8 : 16; case MODE_KANJI: return ver < 10 ? 8 : ver < 27 ? 10 : 12; } }; // returns the maximum length of data possible in given configuration. var getmaxdatalen = function (ver, mode, ecclevel) { var nbits = ndatabits(ver, ecclevel) - 4 - ndatalenbits(ver, mode); // 4 for mode bits switch (mode) { case MODE_NUMERIC: