UNPKG

jspdf

Version:

PDF Document creation from JavaScript

1,529 lines (1,256 loc) 880 kB
(function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) : typeof define === 'function' && define.amd ? define(['exports'], factory) : (global = global || self, factory(global.jsPDF = {})); }(this, function (exports) { 'use strict'; /** @license * jsPDF - PDF Document creation from JavaScript * Version 1.5.2 Built on 2018-12-20T15:49:00.470Z * CommitID 81f5c40ca4 * * 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 (function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? factory() : typeof define === 'function' && define.amd ? define(factory) : factory(); })(window, function () { /** * @this {Promise} */ function finallyConstructor(callback) { var constructor = this.constructor; return this.then(function (value) { return constructor.resolve(callback()).then(function () { return value; }); }, function (reason) { return constructor.resolve(callback()).then(function () { return constructor.reject(reason); }); }); } // Store setTimeout reference so promise-polyfill will be unaffected by // other code modifying setTimeout (like sinon.useFakeTimers()) var setTimeoutFunc = setTimeout; function noop() {} // Polyfill for Function.prototype.bind function bind(fn, thisArg) { return function () { fn.apply(thisArg, arguments); }; } /** * @constructor * @param {Function} fn */ function Promise(fn) { if (!(this instanceof Promise)) throw new TypeError('Promises must be constructed via new'); if (typeof fn !== 'function') throw new TypeError('not a function'); /** @type {!number} */ this._state = 0; /** @type {!boolean} */ this._handled = false; /** @type {Promise|undefined} */ this._value = undefined; /** @type {!Array<!Function>} */ this._deferreds = []; doResolve(fn, this); } function handle(self, deferred) { while (self._state === 3) { self = self._value; } if (self._state === 0) { self._deferreds.push(deferred); return; } self._handled = true; Promise._immediateFn(function () { var cb = self._state === 1 ? deferred.onFulfilled : deferred.onRejected; if (cb === null) { (self._state === 1 ? resolve : reject)(deferred.promise, self._value); return; } var ret; try { ret = cb(self._value); } catch (e) { reject(deferred.promise, e); return; } resolve(deferred.promise, ret); }); } function resolve(self, newValue) { try { // Promise Resolution Procedure: https://github.com/promises-aplus/promises-spec#the-promise-resolution-procedure if (newValue === self) throw new TypeError('A promise cannot be resolved with itself.'); if (newValue && (typeof newValue === 'object' || typeof newValue === 'function')) { var then = newValue.then; if (newValue instanceof Promise) { self._state = 3; self._value = newValue; finale(self); return; } else if (typeof then === 'function') { doResolve(bind(then, newValue), self); return; } } self._state = 1; self._value = newValue; finale(self); } catch (e) { reject(self, e); } } function reject(self, newValue) { self._state = 2; self._value = newValue; finale(self); } function finale(self) { if (self._state === 2 && self._deferreds.length === 0) { Promise._immediateFn(function () { if (!self._handled) { Promise._unhandledRejectionFn(self._value); } }); } for (var i = 0, len = self._deferreds.length; i < len; i++) { handle(self, self._deferreds[i]); } self._deferreds = null; } /** * @constructor */ function Handler(onFulfilled, onRejected, promise) { this.onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : null; this.onRejected = typeof onRejected === 'function' ? onRejected : null; this.promise = promise; } /** * Take a potentially misbehaving resolver function and make sure * onFulfilled and onRejected are only called once. * * Makes no guarantees about asynchrony. */ function doResolve(fn, self) { var done = false; try { fn(function (value) { if (done) return; done = true; resolve(self, value); }, function (reason) { if (done) return; done = true; reject(self, reason); }); } catch (ex) { if (done) return; done = true; reject(self, ex); } } Promise.prototype['catch'] = function (onRejected) { return this.then(null, onRejected); }; Promise.prototype.then = function (onFulfilled, onRejected) { // @ts-ignore var prom = new this.constructor(noop); handle(this, new Handler(onFulfilled, onRejected, prom)); return prom; }; Promise.prototype['finally'] = finallyConstructor; Promise.all = function (arr) { return new Promise(function (resolve, reject) { if (!arr || typeof arr.length === 'undefined') throw new TypeError('Promise.all accepts an array'); var args = Array.prototype.slice.call(arr); if (args.length === 0) return resolve([]); var remaining = args.length; function res(i, val) { try { if (val && (typeof val === 'object' || typeof val === 'function')) { var then = val.then; if (typeof then === 'function') { then.call(val, function (val) { res(i, val); }, reject); return; } } args[i] = val; if (--remaining === 0) { resolve(args); } } catch (ex) { reject(ex); } } for (var i = 0; i < args.length; i++) { res(i, args[i]); } }); }; Promise.resolve = function (value) { if (value && typeof value === 'object' && value.constructor === Promise) { return value; } return new Promise(function (resolve) { resolve(value); }); }; Promise.reject = function (value) { return new Promise(function (resolve, reject) { reject(value); }); }; Promise.race = function (values) { return new Promise(function (resolve, reject) { for (var i = 0, len = values.length; i < len; i++) { values[i].then(resolve, reject); } }); }; // Use polyfill for setImmediate for performance gains Promise._immediateFn = typeof setImmediate === 'function' && function (fn) { setImmediate(fn); } || function (fn) { setTimeoutFunc(fn, 0); }; Promise._unhandledRejectionFn = function _unhandledRejectionFn(err) { if (typeof console !== 'undefined' && console) { console.warn('Possible Unhandled Promise Rejection:', err); // eslint-disable-line no-console } }; /** @suppress {undefinedVars} */ var globalNS = function () { // the only reliable means to get the global object is // `Function('return this')()` // However, this causes CSP violations in Chrome apps. if (typeof self !== 'undefined') { return self; } if (typeof window !== 'undefined') { return window; } if (typeof global !== 'undefined') { return global; } throw new Error('unable to locate global object'); }(); if (!('Promise' in globalNS)) { globalNS['Promise'] = Promise; } else if (!globalNS.Promise.prototype['finally']) { globalNS.Promise.prototype['finally'] = finallyConstructor; } }); /** * 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(pagesContext[currentPage].mediaBox.topRightX) + ' ' + f2(pagesContext[currentPage].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.bottom