UNPKG

jspdf-autotable

Version:

Generate pdf tables with javascript (jsPDF plugin)

1,474 lines (1,224 loc) 880 kB
(function (factory) { typeof define === 'function' && define.amd ? define(factory) : factory(); }(function () { 'use strict'; /** @license * jsPDF - PDF Document creation from JavaScript * Version 1.5.3 Built on 2018-12-27T14:11:42.696Z * CommitID d93d28db14 * * Copyright (c) 2010-2016 James Hall <james@parall.ax>, https://github.com/MrRio/jsPDF * 2010 Aaron Spike, https://github.com/acspike * 2012 Willow Systems Corporation, willow-systems.com * 2012 Pablo Hess, https://github.com/pablohess * 2012 Florian Jenett, https://github.com/fjenett * 2013 Warren Weckesser, https://github.com/warrenweckesser * 2013 Youssef Beddad, https://github.com/lifof * 2013 Lee Driscoll, https://github.com/lsdriscoll * 2013 Stefan Slonevskiy, https://github.com/stefslon * 2013 Jeremy Morel, https://github.com/jmorel * 2013 Christoph Hartmann, https://github.com/chris-rock * 2014 Juan Pablo Gaviria, https://github.com/juanpgaviria * 2014 James Makes, https://github.com/dollaruw * 2014 Diego Casorran, https://github.com/diegocr * 2014 Steven Spungin, https://github.com/Flamenco * 2014 Kenneth Glassey, https://github.com/Gavvers * * Licensed under the MIT License * * Contributor(s): * siefkenj, ahwolf, rickygu, Midnith, saintclair, eaparango, * kim3er, mfo, alnorth, Flamenco */ function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function (obj) { return typeof obj; }; } else { _typeof = function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); } /** * JavaScript Polyfill functions for jsPDF * Collected from public resources by * https://github.com/diegocr */ (function (global) { if (_typeof(global.console) !== "object") { // Console-polyfill. MIT license. // https://github.com/paulmillr/console-polyfill // Make it safe to do console.log() always. global.console = {}; var con = global.console; var prop, method; var dummy = function dummy() {}; var properties = ['memory']; var methods = ('assert,clear,count,debug,dir,dirxml,error,exception,group,' + 'groupCollapsed,groupEnd,info,log,markTimeline,profile,profiles,profileEnd,' + 'show,table,time,timeEnd,timeline,timelineEnd,timeStamp,trace,warn').split(','); while (prop = properties.pop()) { if (!con[prop]) con[prop] = {}; } while (method = methods.pop()) { if (!con[method]) con[method] = dummy; } } var b64 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='; if (typeof global.btoa === 'undefined') { global.btoa = function (data) { // discuss at: http://phpjs.org/functions/base64_encode/ // original by: Tyler Akins (http://rumkin.com) // improved by: Bayron Guevara // improved by: Thunder.m // improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) // improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) // improved by: Rafal Kukawski (http://kukawski.pl) // bugfixed by: Pellentesque Malesuada // example 1: base64_encode('Kevin van Zonneveld'); // returns 1: 'S2V2aW4gdmFuIFpvbm5ldmVsZA==' var o1, o2, o3, h1, h2, h3, h4, bits, i = 0, ac = 0, enc = '', tmp_arr = []; if (!data) { return data; } do { // pack three octets into four hexets o1 = data.charCodeAt(i++); o2 = data.charCodeAt(i++); o3 = data.charCodeAt(i++); bits = o1 << 16 | o2 << 8 | o3; h1 = bits >> 18 & 0x3f; h2 = bits >> 12 & 0x3f; h3 = bits >> 6 & 0x3f; h4 = bits & 0x3f; // use hexets to index into b64, and append result to encoded string tmp_arr[ac++] = b64.charAt(h1) + b64.charAt(h2) + b64.charAt(h3) + b64.charAt(h4); } while (i < data.length); enc = tmp_arr.join(''); var r = data.length % 3; return (r ? enc.slice(0, r - 3) : enc) + '==='.slice(r || 3); }; } if (typeof global.atob === 'undefined') { global.atob = function (data) { // discuss at: http://phpjs.org/functions/base64_decode/ // original by: Tyler Akins (http://rumkin.com) // improved by: Thunder.m // improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) // improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) // input by: Aman Gupta // input by: Brett Zamir (http://brett-zamir.me) // bugfixed by: Onno Marsman // bugfixed by: Pellentesque Malesuada // bugfixed by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) // example 1: base64_decode('S2V2aW4gdmFuIFpvbm5ldmVsZA=='); // returns 1: 'Kevin van Zonneveld' var o1, o2, o3, h1, h2, h3, h4, bits, i = 0, ac = 0, dec = '', tmp_arr = []; if (!data) { return data; } data += ''; do { // unpack four hexets into three octets using index points in b64 h1 = b64.indexOf(data.charAt(i++)); h2 = b64.indexOf(data.charAt(i++)); h3 = b64.indexOf(data.charAt(i++)); h4 = b64.indexOf(data.charAt(i++)); bits = h1 << 18 | h2 << 12 | h3 << 6 | h4; o1 = bits >> 16 & 0xff; o2 = bits >> 8 & 0xff; o3 = bits & 0xff; if (h3 == 64) { tmp_arr[ac++] = String.fromCharCode(o1); } else if (h4 == 64) { tmp_arr[ac++] = String.fromCharCode(o1, o2); } else { tmp_arr[ac++] = String.fromCharCode(o1, o2, o3); } } while (i < data.length); dec = tmp_arr.join(''); return dec; }; } if (!Array.prototype.map) { Array.prototype.map = function (fun /*, thisArg */ ) { if (this === void 0 || this === null || typeof fun !== "function") throw new TypeError(); var t = Object(this), len = t.length >>> 0, res = new Array(len); var thisArg = arguments.length > 1 ? arguments[1] : void 0; for (var i = 0; i < len; i++) { // NOTE: Absolute correctness would demand Object.defineProperty // be used. But this method is fairly new, and failure is // possible only if Object.prototype or Array.prototype // has a property |i| (very unlikely), so use a less-correct // but more portable alternative. if (i in t) res[i] = fun.call(thisArg, t[i], i, t); } return res; }; } if (!Array.isArray) { Array.isArray = function (arg) { return Object.prototype.toString.call(arg) === '[object Array]'; }; } if (!Array.prototype.forEach) { Array.prototype.forEach = function (fun, thisArg) { if (this === void 0 || this === null || typeof fun !== "function") throw new TypeError(); var t = Object(this), len = t.length >>> 0; for (var i = 0; i < len; i++) { if (i in t) fun.call(thisArg, t[i], i, t); } }; } // https://tc39.github.io/ecma262/#sec-array.prototype.find if (!Array.prototype.find) { Object.defineProperty(Array.prototype, 'find', { value: function value(predicate) { // 1. Let O be ? ToObject(this value). if (this == null) { throw new TypeError('"this" is null or not defined'); } var o = Object(this); // 2. Let len be ? ToLength(? Get(O, "length")). var len = o.length >>> 0; // 3. If IsCallable(predicate) is false, throw a TypeError exception. if (typeof predicate !== 'function') { throw new TypeError('predicate must be a function'); } // 4. If thisArg was supplied, let T be thisArg; else let T be undefined. var thisArg = arguments[1]; // 5. Let k be 0. var k = 0; // 6. Repeat, while k < len while (k < len) { // a. Let Pk be ! ToString(k). // b. Let kValue be ? Get(O, Pk). // c. Let testResult be ToBoolean(? Call(predicate, T, « kValue, k, O »)). // d. If testResult is true, return kValue. var kValue = o[k]; if (predicate.call(thisArg, kValue, k, o)) { return kValue; } // e. Increase k by 1. k++; } // 7. Return undefined. return undefined; }, configurable: true, writable: true }); } if (!Object.keys) { Object.keys = function () { var hasOwnProperty = Object.prototype.hasOwnProperty, hasDontEnumBug = !{ toString: null }.propertyIsEnumerable('toString'), dontEnums = ['toString', 'toLocaleString', 'valueOf', 'hasOwnProperty', 'isPrototypeOf', 'propertyIsEnumerable', 'constructor'], dontEnumsLength = dontEnums.length; return function (obj) { if (_typeof(obj) !== 'object' && (typeof obj !== 'function' || obj === null)) { throw new TypeError(); } var result = [], prop, i; for (prop in obj) { if (hasOwnProperty.call(obj, prop)) { result.push(prop); } } if (hasDontEnumBug) { for (i = 0; i < dontEnumsLength; i++) { if (hasOwnProperty.call(obj, dontEnums[i])) { result.push(dontEnums[i]); } } } return result; }; }(); } if (typeof Object.assign != 'function') { Object.assign = function (target) { if (target == null) { throw new TypeError('Cannot convert undefined or null to object'); } target = Object(target); for (var index = 1; index < arguments.length; index++) { var source = arguments[index]; if (source != null) { for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } } return target; }; } if (!String.prototype.trim) { String.prototype.trim = function () { return this.replace(/^\s+|\s+$/g, ''); }; } if (!String.prototype.trimLeft) { String.prototype.trimLeft = function () { return this.replace(/^\s+/g, ""); }; } if (!String.prototype.trimRight) { String.prototype.trimRight = function () { return this.replace(/\s+$/g, ""); }; } Number.isInteger = Number.isInteger || function (value) { return typeof value === 'number' && isFinite(value) && Math.floor(value) === value; }; })(typeof self !== "undefined" && self || typeof window !== "undefined" && window || typeof global !== "undefined" && global || Function('return typeof this === "object" && this.content')() || Function('return this')()); // `self` is undefined in Firefox for Android content script context // while `this` is nsIContentFrameMessageManager // with an attribute `content` that corresponds to the window /** * Creates new jsPDF document object instance. * @name jsPDF * @class * @param orientation {string/Object} Orientation of the first page. Possible values are "portrait" or "landscape" (or shortcuts "p" (Default), "l").<br /> * Can also be an options object. * @param unit {string} Measurement unit to be used when coordinates are specified.<br /> * Possible values are "pt" (points), "mm" (Default), "cm", "in" or "px". * @param format {string/Array} The format of the first page. Can be:<ul><li>a0 - a10</li><li>b0 - b10</li><li>c0 - c10</li><li>dl</li><li>letter</li><li>government-letter</li><li>legal</li><li>junior-legal</li><li>ledger</li><li>tabloid</li><li>credit-card</li></ul><br /> * Default is "a4". If you want to use your own format just pass instead of one of the above predefined formats the size as an number-array, e.g. [595.28, 841.89] * @returns {jsPDF} jsPDF-instance * @description * If the first parameter (orientation) is an object, it will be interpreted as an object of named parameters * ``` * { * orientation: 'p', * unit: 'mm', * format: 'a4', * hotfixes: [] // an array of hotfix strings to enable * } * ``` */ var jsPDF = function (global) { /** * jsPDF's Internal PubSub Implementation. * Backward compatible rewritten on 2014 by * Diego Casorran, https://github.com/diegocr * * @class * @name PubSub * @ignore */ function PubSub(context) { if (_typeof(context) !== 'object') { throw new Error('Invalid Context passed to initialize PubSub (jsPDF-module)'); } var topics = {}; this.subscribe = function (topic, callback, once) { once = once || false; if (typeof topic !== 'string' || typeof callback !== 'function' || typeof once !== 'boolean') { throw new Error('Invalid arguments passed to PubSub.subscribe (jsPDF-module)'); } if (!topics.hasOwnProperty(topic)) { topics[topic] = {}; } var token = Math.random().toString(35); topics[topic][token] = [callback, !!once]; return token; }; this.unsubscribe = function (token) { for (var topic in topics) { if (topics[topic][token]) { delete topics[topic][token]; if (Object.keys(topics[topic]).length === 0) { delete topics[topic]; } return true; } } return false; }; this.publish = function (topic) { if (topics.hasOwnProperty(topic)) { var args = Array.prototype.slice.call(arguments, 1), tokens = []; for (var token in topics[topic]) { var sub = topics[topic][token]; try { sub[0].apply(context, args); } catch (ex) { if (global.console) { console.error('jsPDF PubSub Error', ex.message, ex); } } if (sub[1]) tokens.push(token); } if (tokens.length) tokens.forEach(this.unsubscribe); } }; this.getTopics = function () { return topics; }; } /** * @constructor * @private */ function jsPDF(orientation, unit, format, compressPdf) { var options = {}; var filters = []; var userUnit = 1.0; if (_typeof(orientation) === 'object') { options = orientation; orientation = options.orientation; unit = options.unit || unit; format = options.format || format; compressPdf = options.compress || options.compressPdf || compressPdf; filters = options.filters || (compressPdf === true ? ['FlateEncode'] : filters); userUnit = typeof options.userUnit === "number" ? Math.abs(options.userUnit) : 1.0; } unit = unit || 'mm'; orientation = ('' + (orientation || 'P')).toLowerCase(); var putOnlyUsedFonts = options.putOnlyUsedFonts || true; var usedFonts = {}; var API = { internal: {}, __private__: {} }; API.__private__.PubSub = PubSub; var pdfVersion = '1.3'; var getPdfVersion = API.__private__.getPdfVersion = function () { return pdfVersion; }; var setPdfVersion = API.__private__.setPdfVersion = function (value) { pdfVersion = value; }; // Size in pt of various paper formats var pageFormats = { 'a0': [2383.94, 3370.39], 'a1': [1683.78, 2383.94], 'a2': [1190.55, 1683.78], 'a3': [841.89, 1190.55], 'a4': [595.28, 841.89], 'a5': [419.53, 595.28], 'a6': [297.64, 419.53], 'a7': [209.76, 297.64], 'a8': [147.40, 209.76], 'a9': [104.88, 147.40], 'a10': [73.70, 104.88], 'b0': [2834.65, 4008.19], 'b1': [2004.09, 2834.65], 'b2': [1417.32, 2004.09], 'b3': [1000.63, 1417.32], 'b4': [708.66, 1000.63], 'b5': [498.90, 708.66], 'b6': [354.33, 498.90], 'b7': [249.45, 354.33], 'b8': [175.75, 249.45], 'b9': [124.72, 175.75], 'b10': [87.87, 124.72], 'c0': [2599.37, 3676.54], 'c1': [1836.85, 2599.37], 'c2': [1298.27, 1836.85], 'c3': [918.43, 1298.27], 'c4': [649.13, 918.43], 'c5': [459.21, 649.13], 'c6': [323.15, 459.21], 'c7': [229.61, 323.15], 'c8': [161.57, 229.61], 'c9': [113.39, 161.57], 'c10': [79.37, 113.39], 'dl': [311.81, 623.62], 'letter': [612, 792], 'government-letter': [576, 756], 'legal': [612, 1008], 'junior-legal': [576, 360], 'ledger': [1224, 792], 'tabloid': [792, 1224], 'credit-card': [153, 243] }; var getPageFormats = API.__private__.getPageFormats = function () { return pageFormats; }; var getPageFormat = API.__private__.getPageFormat = function (value) { return pageFormats[value]; }; if (typeof format === "string") { format = getPageFormat(format); } format = format || getPageFormat('a4'); var f2 = API.f2 = API.__private__.f2 = function (number) { if (isNaN(number)) { throw new Error('Invalid argument passed to jsPDF.f2'); } return number.toFixed(2); // Ie, %.2f }; var f3 = API.__private__.f3 = function (number) { if (isNaN(number)) { throw new Error('Invalid argument passed to jsPDF.f3'); } return number.toFixed(3); // Ie, %.3f }; var fileId = '00000000000000000000000000000000'; var getFileId = API.__private__.getFileId = function () { return fileId; }; var setFileId = API.__private__.setFileId = function (value) { value = value || "12345678901234567890123456789012".split('').map(function () { return "ABCDEF0123456789".charAt(Math.floor(Math.random() * 16)); }).join(''); fileId = value; return fileId; }; /** * @name setFileId * @memberOf jsPDF * @function * @instance * @param {string} value GUID. * @returns {jsPDF} */ API.setFileId = function (value) { setFileId(value); return this; }; /** * @name getFileId * @memberOf jsPDF * @function * @instance * * @returns {string} GUID. */ API.getFileId = function () { return getFileId(); }; var creationDate; var convertDateToPDFDate = API.__private__.convertDateToPDFDate = function (parmDate) { var result = ''; var tzoffset = parmDate.getTimezoneOffset(), tzsign = tzoffset < 0 ? '+' : '-', tzhour = Math.floor(Math.abs(tzoffset / 60)), tzmin = Math.abs(tzoffset % 60), timeZoneString = [tzsign, padd2(tzhour), "'", padd2(tzmin), "'"].join(''); result = ['D:', parmDate.getFullYear(), padd2(parmDate.getMonth() + 1), padd2(parmDate.getDate()), padd2(parmDate.getHours()), padd2(parmDate.getMinutes()), padd2(parmDate.getSeconds()), timeZoneString].join(''); return result; }; var convertPDFDateToDate = API.__private__.convertPDFDateToDate = function (parmPDFDate) { var year = parseInt(parmPDFDate.substr(2, 4), 10); var month = parseInt(parmPDFDate.substr(6, 2), 10) - 1; var date = parseInt(parmPDFDate.substr(8, 2), 10); var hour = parseInt(parmPDFDate.substr(10, 2), 10); var minutes = parseInt(parmPDFDate.substr(12, 2), 10); var seconds = parseInt(parmPDFDate.substr(14, 2), 10); var timeZoneHour = parseInt(parmPDFDate.substr(16, 2), 10); var timeZoneMinutes = parseInt(parmPDFDate.substr(20, 2), 10); var resultingDate = new Date(year, month, date, hour, minutes, seconds, 0); return resultingDate; }; var setCreationDate = API.__private__.setCreationDate = function (date) { var tmpCreationDateString; var regexPDFCreationDate = /^D:(20[0-2][0-9]|203[0-7]|19[7-9][0-9])(0[0-9]|1[0-2])([0-2][0-9]|3[0-1])(0[0-9]|1[0-9]|2[0-3])(0[0-9]|[1-5][0-9])(0[0-9]|[1-5][0-9])(\+0[0-9]|\+1[0-4]|\-0[0-9]|\-1[0-1])\'(0[0-9]|[1-5][0-9])\'?$/; if (typeof date === "undefined") { date = new Date(); } if (_typeof(date) === "object" && Object.prototype.toString.call(date) === "[object Date]") { tmpCreationDateString = convertDateToPDFDate(date); } else if (regexPDFCreationDate.test(date)) { tmpCreationDateString = date; } else { throw new Error('Invalid argument passed to jsPDF.setCreationDate'); } creationDate = tmpCreationDateString; return creationDate; }; var getCreationDate = API.__private__.getCreationDate = function (type) { var result = creationDate; if (type === "jsDate") { result = convertPDFDateToDate(creationDate); } return result; }; /** * @name setCreationDate * @memberOf jsPDF * @function * @instance * @param {Object} date * @returns {jsPDF} */ API.setCreationDate = function (date) { setCreationDate(date); return this; }; /** * @name getCreationDate * @memberOf jsPDF * @function * @instance * @param {Object} type * @returns {Object} */ API.getCreationDate = function (type) { return getCreationDate(type); }; var padd2 = API.__private__.padd2 = function (number) { return ('0' + parseInt(number)).slice(-2); }; var outToPages = !1; // switches where out() prints. outToPages true = push to pages obj. outToPages false = doc builder content var pages = []; var content = []; var currentPage; var content_length = 0; var customOutputDestination; var setOutputDestination = API.__private__.setCustomOutputDestination = function (destination) { customOutputDestination = destination; }; var resetOutputDestination = API.__private__.resetCustomOutputDestination = function (destination) { customOutputDestination = undefined; }; var out = API.__private__.out = function (string) { var writeArray; string = typeof string === "string" ? string : string.toString(); if (typeof customOutputDestination === "undefined") { writeArray = outToPages ? pages[currentPage] : content; } else { writeArray = customOutputDestination; } writeArray.push(string); if (!outToPages) { content_length += string.length + 1; } return writeArray; }; var write = API.__private__.write = function (value) { return out(arguments.length === 1 ? value.toString() : Array.prototype.join.call(arguments, ' ')); }; var getArrayBuffer = API.__private__.getArrayBuffer = function (data) { var len = data.length, ab = new ArrayBuffer(len), u8 = new Uint8Array(ab); while (len--) { u8[len] = data.charCodeAt(len); } return ab; }; var standardFonts = [['Helvetica', "helvetica", "normal", 'WinAnsiEncoding'], ['Helvetica-Bold', "helvetica", "bold", 'WinAnsiEncoding'], ['Helvetica-Oblique', "helvetica", "italic", 'WinAnsiEncoding'], ['Helvetica-BoldOblique', "helvetica", "bolditalic", 'WinAnsiEncoding'], ['Courier', "courier", "normal", 'WinAnsiEncoding'], ['Courier-Bold', "courier", "bold", 'WinAnsiEncoding'], ['Courier-Oblique', "courier", "italic", 'WinAnsiEncoding'], ['Courier-BoldOblique', "courier", "bolditalic", 'WinAnsiEncoding'], ['Times-Roman', "times", "normal", 'WinAnsiEncoding'], ['Times-Bold', "times", "bold", 'WinAnsiEncoding'], ['Times-Italic', "times", "italic", 'WinAnsiEncoding'], ['Times-BoldItalic', "times", "bolditalic", 'WinAnsiEncoding'], ['ZapfDingbats', "zapfdingbats", "normal", null], ['Symbol', "symbol", "normal", null]]; var getStandardFonts = API.__private__.getStandardFonts = function (data) { return standardFonts; }; var activeFontSize = options.fontSize || 16; /** * Sets font size for upcoming text elements. * * @param {number} size Font size in points. * @function * @instance * @returns {jsPDF} * @memberOf jsPDF * @name setFontSize */ var setFontSize = API.__private__.setFontSize = API.setFontSize = function (size) { activeFontSize = size; return this; }; /** * Gets the fontsize for upcoming text elements. * * @function * @instance * @returns {number} * @memberOf jsPDF * @name getFontSize */ var getFontSize = API.__private__.getFontSize = API.getFontSize = function () { return activeFontSize; }; var R2L = options.R2L || false; /** * Set value of R2L functionality. * * @param {boolean} value * @function * @instance * @returns {jsPDF} jsPDF-instance * @memberOf jsPDF * @name setR2L */ var setR2L = API.__private__.setR2L = API.setR2L = function (value) { R2L = value; return this; }; /** * Get value of R2L functionality. * * @function * @instance * @returns {boolean} jsPDF-instance * @memberOf jsPDF * @name getR2L */ var getR2L = API.__private__.getR2L = API.getR2L = function (value) { return R2L; }; var zoomMode; // default: 1; var setZoomMode = API.__private__.setZoomMode = function (zoom) { var validZoomModes = [undefined, null, 'fullwidth', 'fullheight', 'fullpage', 'original']; if (/^\d*\.?\d*\%$/.test(zoom)) { zoomMode = zoom; } else if (!isNaN(zoom)) { zoomMode = parseInt(zoom, 10); } else if (validZoomModes.indexOf(zoom) !== -1) { zoomMode = zoom; } else { throw new Error('zoom must be Integer (e.g. 2), a percentage Value (e.g. 300%) or fullwidth, fullheight, fullpage, original. "' + zoom + '" is not recognized.'); } }; var getZoomMode = API.__private__.getZoomMode = function () { return zoomMode; }; var pageMode; // default: 'UseOutlines'; var setPageMode = API.__private__.setPageMode = function (pmode) { var validPageModes = [undefined, null, 'UseNone', 'UseOutlines', 'UseThumbs', 'FullScreen']; if (validPageModes.indexOf(pmode) == -1) { throw new Error('Page mode must be one of UseNone, UseOutlines, UseThumbs, or FullScreen. "' + pmode + '" is not recognized.'); } pageMode = pmode; }; var getPageMode = API.__private__.getPageMode = function () { return pageMode; }; var layoutMode; // default: 'continuous'; var setLayoutMode = API.__private__.setLayoutMode = function (layout) { var validLayoutModes = [undefined, null, 'continuous', 'single', 'twoleft', 'tworight', 'two']; if (validLayoutModes.indexOf(layout) == -1) { throw new Error('Layout mode must be one of continuous, single, twoleft, tworight. "' + layout + '" is not recognized.'); } layoutMode = layout; }; var getLayoutMode = API.__private__.getLayoutMode = function () { return layoutMode; }; /** * Set the display mode options of the page like zoom and layout. * * @name setDisplayMode * @memberOf jsPDF * @function * @instance * @param {integer|String} zoom You can pass an integer or percentage as * a string. 2 will scale the document up 2x, '200%' will scale up by the * same amount. You can also set it to 'fullwidth', 'fullheight', * 'fullpage', or 'original'. * * Only certain PDF readers support this, such as Adobe Acrobat. * * @param {string} layout Layout mode can be: 'continuous' - this is the * default continuous scroll. 'single' - the single page mode only shows one * page at a time. 'twoleft' - two column left mode, first page starts on * the left, and 'tworight' - pages are laid out in two columns, with the * first page on the right. This would be used for books. * @param {string} pmode 'UseOutlines' - it shows the * outline of the document on the left. 'UseThumbs' - shows thumbnails along * the left. 'FullScreen' - prompts the user to enter fullscreen mode. * * @returns {jsPDF} */ var setDisplayMode = API.__private__.setDisplayMode = API.setDisplayMode = function (zoom, layout, pmode) { setZoomMode(zoom); setLayoutMode(layout); setPageMode(pmode); return this; }; var documentProperties = { 'title': '', 'subject': '', 'author': '', 'keywords': '', 'creator': '' }; var getDocumentProperty = API.__private__.getDocumentProperty = function (key) { if (Object.keys(documentProperties).indexOf(key) === -1) { throw new Error('Invalid argument passed to jsPDF.getDocumentProperty'); } return documentProperties[key]; }; var getDocumentProperties = API.__private__.getDocumentProperties = function (properties) { return documentProperties; }; /** * Adds a properties to the PDF document. * * @param {Object} A property_name-to-property_value object structure. * @function * @instance * @returns {jsPDF} * @memberOf jsPDF * @name setDocumentProperties */ var setDocumentProperties = API.__private__.setDocumentProperties = API.setProperties = API.setDocumentProperties = function (properties) { // copying only those properties we can render. for (var property in documentProperties) { if (documentProperties.hasOwnProperty(property) && properties[property]) { documentProperties[property] = properties[property]; } } return this; }; var setDocumentProperty = API.__private__.setDocumentProperty = function (key, value) { if (Object.keys(documentProperties).indexOf(key) === -1) { throw new Error('Invalid arguments passed to jsPDF.setDocumentProperty'); } return documentProperties[key] = value; }; var objectNumber = 0; // 'n' Current object number var offsets = []; // List of offsets. Activated and reset by buildDocument(). Pupulated by various calls buildDocument makes. var fonts = {}; // collection of font objects, where key is fontKey - a dynamically created label for a given font. var fontmap = {}; // mapping structure fontName > fontStyle > font key - performance layer. See addFont() var activeFontKey; // will be string representing the KEY of the font as combination of fontName + fontStyle var k; // Scale factor var page = 0; var pagesContext = []; var additionalObjects = []; var events = new PubSub(API); var hotfixes = options.hotfixes || []; var newObject = API.__private__.newObject = function () { var oid = newObjectDeferred(); newObjectDeferredBegin(oid, true); return oid; }; // Does not output the object. The caller must call newObjectDeferredBegin(oid) before outputing any data var newObjectDeferred = API.__private__.newObjectDeferred = function () { objectNumber++; offsets[objectNumber] = function () { return content_length; }; return objectNumber; }; var newObjectDeferredBegin = function newObjectDeferredBegin(oid, doOutput) { doOutput = typeof doOutput === 'boolean' ? doOutput : false; offsets[oid] = content_length; if (doOutput) { out(oid + ' 0 obj'); } return oid; }; // Does not output the object until after the pages have been output. // Returns an object containing the objectId and content. // All pages have been added so the object ID can be estimated to start right after. // This does not modify the current objectNumber; It must be updated after the newObjects are output. var newAdditionalObject = API.__private__.newAdditionalObject = function () { var objId = newObjectDeferred(); var obj = { objId: objId, content: '' }; additionalObjects.push(obj); return obj; }; var rootDictionaryObjId = newObjectDeferred(); var resourceDictionaryObjId = newObjectDeferred(); ///////////////////// // Private functions ///////////////////// var decodeColorString = API.__private__.decodeColorString = function (color) { var colorEncoded = color.split(' '); if (colorEncoded.length === 2 && (colorEncoded[1] === 'g' || colorEncoded[1] === 'G')) { // convert grayscale value to rgb so that it can be converted to hex for consistency var floatVal = parseFloat(colorEncoded[0]); colorEncoded = [floatVal, floatVal, floatVal, 'r']; } var colorAsRGB = '#'; for (var i = 0; i < 3; i++) { colorAsRGB += ('0' + Math.floor(parseFloat(colorEncoded[i]) * 255).toString(16)).slice(-2); } return colorAsRGB; }; var encodeColorString = API.__private__.encodeColorString = function (options) { var color; if (typeof options === "string") { options = { ch1: options }; } var ch1 = options.ch1; var ch2 = options.ch2; var ch3 = options.ch3; var ch4 = options.ch4; var precision = options.precision; var letterArray = options.pdfColorType === "draw" ? ['G', 'RG', 'K'] : ['g', 'rg', 'k']; if (typeof ch1 === "string" && ch1.charAt(0) !== '#') { var rgbColor = new RGBColor(ch1); if (rgbColor.ok) { ch1 = rgbColor.toHex(); } else if (!/^\d*\.?\d*$/.test(ch1)) { throw new Error('Invalid color "' + ch1 + '" passed to jsPDF.encodeColorString.'); } } //convert short rgb to long form if (typeof ch1 === "string" && /^#[0-9A-Fa-f]{3}$/.test(ch1)) { ch1 = '#' + ch1[1] + ch1[1] + ch1[2] + ch1[2] + ch1[3] + ch1[3]; } if (typeof ch1 === "string" && /^#[0-9A-Fa-f]{6}$/.test(ch1)) { var hex = parseInt(ch1.substr(1), 16); ch1 = hex >> 16 & 255; ch2 = hex >> 8 & 255; ch3 = hex & 255; } if (typeof ch2 === "undefined" || typeof ch4 === "undefined" && ch1 === ch2 && ch2 === ch3) { // Gray color space. if (typeof ch1 === "string") { color = ch1 + " " + letterArray[0]; } else { switch (options.precision) { case 2: color = f2(ch1 / 255) + " " + letterArray[0]; break; case 3: default: color = f3(ch1 / 255) + " " + letterArray[0]; } } } else if (typeof ch4 === "undefined" || _typeof(ch4) === "object") { // assume RGBA if (ch4 && !isNaN(ch4.a)) { //TODO Implement transparency. //WORKAROUND use white for now, if transparent, otherwise handle as rgb if (ch4.a === 0) { color = ['1.000', '1.000', '1.000', letterArray[1]].join(" "); return color; } } // assume RGB if (typeof ch1 === "string") { color = [ch1, ch2, ch3, letterArray[1]].join(" "); } else { switch (options.precision) { case 2: color = [f2(ch1 / 255), f2(ch2 / 255), f2(ch3 / 255), letterArray[1]].join(" "); break; default: case 3: color = [f3(ch1 / 255), f3(ch2 / 255), f3(ch3 / 255), letterArray[1]].join(" "); } } } else { // assume CMYK if (typeof ch1 === 'string') { color = [ch1, ch2, ch3, ch4, letterArray[2]].join(" "); } else { switch (options.precision) { case 2: color = [f2(ch1 / 255), f2(ch2 / 255), f2(ch3 / 255), f2(ch4 / 255), letterArray[2]].join(" "); break; case 3: default: color = [f3(ch1 / 255), f3(ch2 / 255), f3(ch3 / 255), f3(ch4 / 255), letterArray[2]].join(" "); } } } return color; }; var getFilters = API.__private__.getFilters = function () { return filters; }; var putStream = API.__private__.putStream = function (options) { options = options || {}; var data = options.data || ''; var filters = options.filters || getFilters(); var alreadyAppliedFilters = options.alreadyAppliedFilters || []; var addLength1 = options.addLength1 || false; var valueOfLength1 = data.length; var processedData = {}; if (filters === true) { filters = ['FlateEncode']; } var keyValues = options.additionalKeyValues || []; if (typeof jsPDF.API.processDataByFilters !== 'undefined') { processedData = jsPDF.API.processDataByFilters(data, filters); } else { processedData = { data: data, reverseChain: [] }; } var filterAsString = processedData.reverseChain + (Array.isArray(alreadyAppliedFilters) ? alreadyAppliedFilters.join(' ') : alreadyAppliedFilters.toString()); if (processedData.data.length !== 0) { keyValues.push({ key: 'Length', value: processedData.data.length }); if (addLength1 === true) { keyValues.push({ key: 'Length1', value: valueOfLength1 }); } } if (filterAsString.length != 0) { //if (filters.length === 0 && alreadyAppliedFilters.length === 1 && typeof alreadyAppliedFilters !== "undefined") { if (filterAsString.split('/').length - 1 === 1) { keyValues.push({ key: 'Filter', value: filterAsString }); } else { keyValues.push({ key: 'Filter', value: '[' + filterAsString + ']' }); } } out('<<'); for (var i = 0; i < keyValues.length; i++) { out('/' + keyValues[i].key + ' ' + keyValues[i].value); } out('>>'); if (processedData.data.length !== 0) { out('stream'); out(processedData.data); out('endstream'); } }; var putPage = API.__private__.putPage = function (page) { var mediaBox = page.mediaBox; var pageNumber = page.number; var data = page.data; var pageObjectNumber = page.objId; var pageContentsObjId = page.contentsObjId; newObjectDeferredBegin(pageObjectNumber, true); var wPt = pagesContext[currentPage].mediaBox.topRightX - pagesContext[currentPage].mediaBox.bottomLeftX; var hPt = pagesContext[currentPage].mediaBox.topRightY - pagesContext[currentPage].mediaBox.bottomLeftY; out('<</Type /Page'); out('/Parent ' + page.rootDictionaryObjId + ' 0 R'); out('/Resources ' + page.resourceDictionaryObjId + ' 0 R'); out('/MediaBox [' + parseFloat(f2(page.mediaBox.bottomLeftX)) + ' ' + parseFloat(f2(page.mediaBox.bottomLeftY)) + ' ' + f2(page.mediaBox.topRightX) + ' ' + f2(page.mediaBox.topRightY) + ']'); if (page.cropBox !== null) { out('/CropBox [' + f2(page.cropBox.bottomLeftX) + ' ' + f2(page.cropBox.bottomLeftY) + ' ' + f2(page.cropBox.topRightX) + ' ' + f2(page.cropBox.topRightY) + ']'); } if (page.bleedBox !== null) { out('/BleedBox [' + f2(page.bleedBox.bottomLeftX) + ' ' + f2(page.bleedBox.bottomLeftY) + ' ' + f2(page.bleedBox.topRightX) + ' ' + f2(page.bleedBox.topRightY) + ']'); } if (page.trimBox !== null) { out('/TrimBox [' + f2(page.trimBox.bottomLeftX) + ' ' + f2(page.trimBox.bottomLeftY) + ' ' + f2(page.trimBox.topRightX) + ' ' + f2(page.trimBox.topRightY) + ']'); } if (page.artBox !== null) { out('/ArtBox [' + f2(page.artBox.bottomLeftX) + ' ' + f2(page.artBox.bottomLeftY) + ' ' + f2(page.artBox.topRightX) + ' ' + f2(page.artBox.topRightY) + ']'); } if (typeof page.userUnit === "number" && page.userUnit !== 1.0) { out('/UserUnit ' + page.userUnit); } events.publish('putPage', { objId: pageObjectNumber, pageContext: pagesContext[pageNumber], pageNumber: pageNumber, page: data }); out('/Contents ' + pageContentsObjId + ' 0 R'); out('>>'); out('endobj'); // Page content var pageContent = data.join('\n'); newObjectDeferredBegin(pageContentsObjId, true); putStream({ data: pageContent, filters: getFilters() }); out('endobj'); return pageObjectNumber; }; var putPages = API.__private__.putPages = function () { var n, i, pageObjectNumbers = []; for (n = 1; n <= page; n++) { pagesContext[n].objId = newObjectDeferred(); pagesContext[n].contentsObjId = newObjectDeferred(); } for (n = 1; n <= page; n++) { pageObjectNumbers.push(putPage({ number: n, data: pages[n], objId: pagesContext[n].objId, contentsObjId: pagesContext[n].contentsObjId, mediaBox: pagesContext[n].mediaBox, cropBox: pagesContext[n].cropBox, bleedBox: pagesContext[n].bleedBox, trimBox: pagesContext[n].trimBox, artBox: pagesContext[n].artBox, userUnit: pagesContext[n].userUnit, rootDictionaryObjId: rootDictionaryObjId, resourceDictionaryObjId: resourceDictionaryObjId })); } newObjectDeferredBegin(rootDictionaryObjId, true); out('<</Type /Pages'); var kids = '/Kids ['; for (i = 0; i < page; i++) { kids += pageObjectNumbers[i] + ' 0 R '; } out(kids + ']'); out('/Count ' + page); out('>>'); out('endobj'); events.publish('postPutPages'); }; var putFont = function putFont(font) { events.publish('putFont', { font: font, out: out, newObject: newObject, putStream: putStream }); if (font.isAlreadyPutted !== true) { font.objectNumber = newObject(); out('<<'); out('/Type /Font'); out('/BaseFont /' + font.postScriptName); out('/Subtype /Type1'); if (typeof font.encoding === 'string') { out('/Encoding /' + font.encoding); } out('/FirstChar 32'); out('/LastChar 255'); out('>>'); out('endobj'); } }; var putFonts = function putFonts() { for (var fontKey in fonts) { if (fonts.hasOwnProperty(fontKey)) { if (putOnlyUsedFonts === false || putOnlyUsedFonts === true && usedFonts.hasOwnProperty(fontKey)) { putFont(fonts[fontKey]); } } } }; var putResourceDictionary = function putResourceDictionary() { out('/ProcSet [/PDF /Text /ImageB /ImageC /ImageI]'); out('/Font <<'); // Do this for each font, the '1' bit is the index of the font for (var fontKey in fonts) { if (fonts.hasOwnProperty(fontKey)) { if (putOnlyUsedFonts === false || putOnlyUsedFonts === true && usedFonts.hasOwnProperty(fontKey)) { out('/' + fontKey + ' ' + fonts[fontKey].objectNumber + ' 0 R'); } } } out('>>'); out('/XObject <<'); events.publish('putXobjectDict'); out('>>'); }; var putResources = function putResources() { putFonts(); events.publish('putResources'); newObjectDeferredBegin(resourceDictionaryObjId, true); out('<<'); putResourceDictionary(); out('>>'); out('endobj'); events.publish('postPutResources'); }; var putAdditionalObjects = function putAdditionalObjects() { events.publish('putAdditionalObjects'); for (var i = 0; i < additionalObjects.length; i++) { var obj = additionalObjects[i]; newObjectDeferredBegin(obj.objId, true); out(obj.content); out('endobj'); } events.publish('postPutAdditionalObjects'); }; var addToFontDictionary = function addToFontDictionary(fontKey, fontName, fontStyle) { // this is mapping structure for quick font key lookup. // returns the KEY of the font (ex: "F1") for a given // pair of font name and type (ex: "Arial". "Italic") if (!fontmap.hasOwnProperty(fontName)) { fontmap[fontName] = {}; } fontmap[fontName][fontStyle] = fontKey; }; var addFont = function addFont(postScriptName, fontName, fontStyle, encoding, isStandardFont) { isStandardFont = isStandardFont || false; var fontKey = 'F' + (Object.keys(fonts).length + 1).toString(10), // This is FontObject font = { 'id': fontKey, 'postScriptName': postScriptName, 'fontName': fontName, 'fontStyle': fontStyle, 'encoding': encoding, 'isStandardFont': isStandardFont, 'metadata': {} }; var instance = this; events.publish('addFont', { font: font, instance: instance }); if (fontKey !== undefined) { fonts[fontKey] = font; addToFontDictionary(fontKey, fontName, fontStyle); } return fontKey; }; var addFonts = function addFonts(arrayOfFonts) { for (var i = 0, l = standardFonts.length; i < l; i++) { var fontKey = addFont(arrayOfFonts[i][0], arrayOfFonts[i][1], arrayOfFonts[i][2], standardFonts[i][3], true); usedFonts[fontKey] = true; // adding aliases for standard fonts, this time matching the capitalization var parts = arrayOfFonts[i][0].split('-'); addToFontDictionary(fontKey, parts[0], parts[1] || ''); } events.publish('addFonts', { fonts: fonts, dictionary: fontmap }); }; var SAFE = function __safeCall(fn) { fn.foo = function __safeCallWrapper() { try { return fn.apply(this, arguments); } catch (e) { var stack = e.stack || ''; if (~stack.indexOf(' at ')) stack = stack.split(" at ")[1]; var m = "Error in function " + stack.split("\n")[0].split('<')[0] + ": " + e.message; if (global.console) { global.console.error(m, e); if (global.alert) alert(m); } else { throw new Error(m); } } }; fn.foo.bar = fn; return fn.foo; }; var to8bitStream = function to8bitStream(text, flags) { /** * PDF 1.3 spec: * "For text strings encoded in Unicode, the first two bytes must be 254 followed by * 255, representing the Unicode byte order marker, U+FEFF. (This sequence conflicts * with the PDFDocEncoding character sequence thorn ydieresis, which is unlikely * to be a meaningful beginning of a word or phrase.) The remainder of the * string consists of Unicode character codes, according to the UTF-16 encoding * specified in the Unicode standard, version 2.0. Commonly used Unicode values * are represented as 2 bytes per character, with the high-order byte appearing first * in the string." * * In other words, if there are chars in a string with char code above 255, we * recode the string to UCS2 BE - string doubles in length and BOM is prepended.