UNPKG

highcharts

Version:
1,522 lines (1,327 loc) 743 kB
(function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) : typeof define === 'function' && define.amd ? define(['exports'], factory) : (factory((global.jsPDF = {}))); }(this, (function (exports) { 'use strict'; /** * 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 () {}; 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); } }; } 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, ""); }; } })(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; } }); 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); } /** @license * jsPDF - PDF Document creation from JavaScript * Version 2.0.0 Built on 2019-01-22T15:32:38.220Z * CommitID 0110a2202b * * Copyright (c) 2015-2018 yWorks GmbH, http://www.yworks.com * 2015-2018 Lukas Holländer <lukas.hollaender@yworks.com>, https://github.com/HackbrettXXX * 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 */ /** * 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>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) { var pdfVersion = "1.3", pageFormats = { // Size in pt of various paper formats 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.4, 209.76], a9: [104.88, 147.4], a10: [73.7, 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.9, 708.66], b6: [354.33, 498.9], 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] }; /** * jsPDF's Internal PubSub Implementation. * Backward compatible rewritten on 2014 by * Diego Casorran, https://github.com/diegocr * * @class * @name PubSub * @ignore */ function PubSub(context) { var topics = {}; this.subscribe = function (topic, callback, once) { if (typeof callback !== "function") { return false; } if (!topics.hasOwnProperty(topic)) { topics[topic] = {}; } var id = Math.random().toString(35); topics[topic][id] = [callback, !!once]; return id; }; this.unsubscribe = function (token) { for (var topic in topics) { if (topics[topic][token]) { delete topics[topic][token]; return true; } } return false; }; this.publish = function (topic) { if (topics.hasOwnProperty(topic)) { var args = Array.prototype.slice.call(arguments, 1), idr = []; for (var id in topics[topic]) { var sub = topics[topic][id]; try { sub[0].apply(context, args); } catch (ex) { if (global.console) { console.error("jsPDF PubSub Error", ex.message, ex); } } if (sub[1]) idr.push(id); } if (idr.length) idr.forEach(this.unsubscribe); } }; } /** * @constructor * @private */ function jsPDF(orientation, unit, format, compressPdf) { var options = {}; if (_typeof(orientation) === "object") { options = orientation; orientation = options.orientation; unit = options.unit || unit; format = options.format || format; compressPdf = options.compress || options.compressPdf || compressPdf; } // Default options unit = unit || "mm"; format = format || "a4"; orientation = ("" + (orientation || "P")).toLowerCase(); var format_as_string = ("" + format).toLowerCase(), compress = !!compressPdf && typeof Uint8Array === "function", textColor = options.textColor || "0 g", drawColor = options.drawColor || "0 G", activeFontSize = options.fontSize || 16, activeCharSpace = options.charSpace || 0, R2L = options.R2L || false, lineHeightProportion = options.lineHeight || 1.15, lineWidth = options.lineWidth || 0.200025, // 2mm fileId = "00000000000000000000000000000000", objectNumber = 2, // 'n' Current object number outToPages = !1, // switches where out() prints. outToPages true = push to pages obj. outToPages false = doc builder content offsets = [], // List of offsets. Activated and reset by buildDocument(). Pupulated by various calls buildDocument makes. fonts = {}, // collection of font objects, where key is fontKey - a dynamically created label for a given font. fontmap = {}, // mapping structure fontName > fontStyle > font key - performance layer. See addFont() activeFontKey, // will be string representing the KEY of the font as combination of fontName + fontStyle fontStateStack = [], // patterns = {}, // collection of pattern objects patternMap = {}, // see fonts gStates = {}, // collection of graphic state objects gStatesMap = {}, // see fonts activeGState = null, k, // Scale factor tmp, page = 0, currentPage, pages = [], pagesContext = [], // same index as pages and pagedim pagedim = [], content = [], additionalObjects = [], lineCapID = 0, lineJoinID = 0, content_length = 0, renderTargets = {}, renderTargetMap = {}, renderTargetStack = [], pageX, pageY, pageMatrix, // only used for FormObjects pageWidth, pageHeight, pageMode, zoomMode, layoutMode, creationDate, documentProperties = { title: "", subject: "", author: "", keywords: "", creator: "" }, API = {}, ApiMode = { COMPAT: "compat", ADVANCED: "advanced" }, apiMode = ApiMode.COMPAT, events = new PubSub(API), hotfixes = options.hotfixes || [], ///////////////////// // Private functions ///////////////////// generateColorString = function generateColorString(options) { var color; 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(); } } //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 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(" "); } } // assume RGBA if (ch4 && ch4.a === 0) { //TODO Implement transparency. //WORKAROUND use white for now color = ["255", "255", "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), f2(ch2), f2(ch3), f2(ch4), letterArray[2]].join(" "); break; case 3: default: color = [f3(ch1), f3(ch2), f3(ch3), f3(ch4), letterArray[2]].join(" "); } } } return color; }, convertDateToPDFDate = function convertDateToPDFDate(parmDate) { var padd2 = function padd2(number) { return ("0" + parseInt(number)).slice(-2); }; 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; }, convertPDFDateToDate = function convertPDFDateToDate(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; }, setCreationDate = function setCreationDate(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 { tmpCreationDateString = convertDateToPDFDate(new Date()); } creationDate = tmpCreationDateString; return creationDate; }, getCreationDate = function getCreationDate(type) { var result = creationDate; if (type === "jsDate") { result = convertPDFDateToDate(creationDate); } return result; }, setFileId = function setFileId(value) { value = value || "12345678901234567890123456789012".split("").map(function () { return "ABCDEF0123456789".charAt(Math.floor(Math.random() * 16)); }).join(""); fileId = value; return fileId; }, getFileId = function getFileId() { return fileId; }, f2 = function f2(number) { return number.toFixed(2); // Ie, %.2f }, f3 = function f3(number) { return number.toFixed(3); // Ie, %.3f }, // high precision float hpf = function hpf(number) { return number.toFixed(16).replace(/0+$/, ""); }, scaleByK = function scaleByK(coordinate) { if (apiMode === ApiMode.COMPAT) { return coordinate * k; } else if (apiMode === ApiMode.ADVANCED) { return coordinate; } }, transformY = function transformY(y) { if (apiMode === ApiMode.COMPAT) { return pageHeight - y; } else if (apiMode === ApiMode.ADVANCED) { return y; } }, transformScaleY = function transformScaleY(y) { return scaleByK(transformY(y)); }, padd2Hex = function padd2Hex(hexString) { var s = "00" + hexString; return s.substr(s.length - 2); }, advancedApiModeTrap = function advancedApiModeTrap(methodName) { if (apiMode !== ApiMode.ADVANCED) { throw new Error(methodName + " is only available in 'advanced' API mode. " + "You need to call advancedAPI() first."); } }, out = function out(string) { string = typeof string === "string" ? string : string.toString(); if (outToPages) { /* set by beginPage */ pages[currentPage].push(string); } else { // +1 for '\n' that will be used to join 'content' content_length += string.length + 1; content.push(string); } }, newObject = function newObject() { // Begin a new object objectNumber++; offsets[objectNumber] = content_length; out(objectNumber + " 0 obj"); return objectNumber; }, // 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. newAdditionalObject = function newAdditionalObject() { var objId = pages.length * 2 + 1; objId += additionalObjects.length; var obj = { objId: objId, content: "" }; additionalObjects.push(obj); return obj; }, // Does not output the object. The caller must call newObjectDeferredBegin(oid) before outputing any data newObjectDeferred = function newObjectDeferred() { objectNumber++; offsets[objectNumber] = function () { return content_length; }; return objectNumber; }, newObjectDeferredBegin = function newObjectDeferredBegin(oid) { offsets[oid] = content_length; }, putStream = function putStream(str) { out("stream"); out(str); out("endstream"); }, appendBuffer = function appendBuffer(buffer1, buffer2) { var tmp = new Uint8Array(buffer1.byteLength + buffer2.byteLength); tmp.set(new Uint8Array(buffer1), 0); tmp.set(new Uint8Array(buffer2), buffer1.byteLength); return tmp; }, putPages = function putPages() { var n, p, arr, i, deflater, adler32, adler32cs, wPt, hPt, pageObjectNumbers = []; adler32cs = global.adler32cs || jsPDF.API.adler32cs; if (compress && typeof adler32cs === "undefined") { compress = false; } // outToPages = false as set in endDocument(). out() writes to content. for (n = 1; n <= page; n++) { pageObjectNumbers.push(newObject()); wPt = (pageWidth = pagedim[n].width) * k; hPt = (pageHeight = pagedim[n].height) * k; out("<</Type /Page"); out("/Parent 1 0 R"); out("/Resources 2 0 R"); out("/MediaBox [0 0 " + hpf(wPt) + " " + hpf(hPt) + "]"); // Added for annotation plugin events.publish("putPage", { pageNumber: n, page: pages[n] }); out("/Contents " + (objectNumber + 1) + " 0 R"); out(">>"); out("endobj"); // Page content p = pages[n].join("\n"); if (apiMode === ApiMode.ADVANCED) { // if the user forgot to switch back to COMPAT mode, we must balance the graphics stack again p += "\nQ"; } newObject(); if (compress) { arr = []; i = p.length; while (i--) { arr[i] = p.charCodeAt(i); } adler32 = adler32cs.from(p); deflater = new Deflater(6); p = deflater.append(new Uint8Array(arr)); p = appendBuffer(p, deflater.flush()); arr = new Uint8Array(p.byteLength + 6); arr.set(new Uint8Array([120, 156])); arr.set(p, 2); arr.set(new Uint8Array([adler32 & 0xff, adler32 >> 8 & 0xff, adler32 >> 16 & 0xff, adler32 >> 24 & 0xff]), p.byteLength + 2); var strings = [], chunkSize = 0xffff; // There is a maximum stack size. We cannot call String.fromCharCode with as many arguments as we want for (var j = 0; j * chunkSize < arr.length; j++) { strings.push(String.fromCharCode.apply(null, arr.subarray(j * chunkSize, (j + 1) * chunkSize))); } p = strings.join(''); out("<</Length " + p.length + " /Filter [/FlateDecode]>>"); } else { out("<</Length " + p.length + ">>"); } putStream(p); out("endobj"); } offsets[1] = content_length; out("1 0 obj"); 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"); }, 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"); } }, putFonts = function putFonts() { for (var fontKey in fonts) { if (fonts.hasOwnProperty(fontKey)) { putFont(fonts[fontKey]); } } }, putXObject = function putXObject(xObject) { xObject.objectNumber = newObject(); out("<<"); out("/Type /XObject"); out("/Subtype /Form"); out("/BBox [" + [hpf(xObject.x), hpf(xObject.y), hpf(xObject.x + xObject.width), hpf(xObject.y + xObject.height)].join(" ") + "]"); out("/Matrix [" + xObject.matrix.toString() + "]"); // TODO: /Resources var p = xObject.pages[1].join("\n"); out("/Length " + p.length); out(">>"); putStream(p); out("endobj"); }, putXObjects = function putXObjects() { for (var xObjectKey in renderTargets) { if (renderTargets.hasOwnProperty(xObjectKey)) { putXObject(renderTargets[xObjectKey]); } } }, interpolateAndEncodeRGBStream = function interpolateAndEncodeRGBStream(colors, numberSamples) { var tValues = []; var t; var dT = 1.0 / (numberSamples - 1); for (t = 0.0; t < 1.0; t += dT) { tValues.push(t); } tValues.push(1.0); // add first and last control point if not present if (colors[0].offset != 0.0) { var c0 = { offset: 0.0, color: colors[0].color }; colors.unshift(c0); } if (colors[colors.length - 1].offset != 1.0) { var c1 = { offset: 1.0, color: colors[colors.length - 1].color }; colors.push(c1); } var out = ""; var index = 0; for (var i = 0; i < tValues.length; i++) { t = tValues[i]; while (t > colors[index + 1].offset) { index++; } var a = colors[index].offset; var b = colors[index + 1].offset; var d = (t - a) / (b - a); var aColor = colors[index].color; var bColor = colors[index + 1].color; out += padd2Hex(Math.round((1 - d) * aColor[0] + d * bColor[0]).toString(16)) + padd2Hex(Math.round((1 - d) * aColor[1] + d * bColor[1]).toString(16)) + padd2Hex(Math.round((1 - d) * aColor[2] + d * bColor[2]).toString(16)); } return out.trim(); }, putShadingPattern = function putShadingPattern(pattern, numberSamples) { /* Axial patterns shade between the two points specified in coords, radial patterns between the inner and outer circle. The user can specify an array (colors) that maps t-Values in [0, 1] to RGB colors. These are now interpolated to equidistant samples and written to pdf as a sample (type 0) function. */ // The number of color samples that should be used to describe the shading. // The higher, the more accurate the gradient will be. numberSamples || (numberSamples = 21); var funcObjectNumber = newObject(); var stream = interpolateAndEncodeRGBStream(pattern.colors, numberSamples); out("<< /FunctionType 0"); out("/Domain [0.0 1.0]"); out("/Size [" + numberSamples + "]"); out("/BitsPerSample 8"); out("/Range [0.0 1.0 0.0 1.0 0.0 1.0]"); out("/Decode [0.0 1.0 0.0 1.0 0.0 1.0]"); out("/Length " + stream.length); // The stream is Hex encoded out("/Filter /ASCIIHexDecode"); out(">>"); putStream(stream); out("endobj"); pattern.objectNumber = newObject(); out("<< /ShadingType " + pattern.type); out("/ColorSpace /DeviceRGB"); var coords = "/Coords [" + hpf(parseFloat(pattern.coords[0])) + " " + // x1 hpf(parseFloat(pattern.coords[1])) + " "; // y1 if (pattern.type === 2) { // axial coords += hpf(parseFloat(pattern.coords[2])) + " " + // x2 hpf(parseFloat(pattern.coords[3])); // y2 } else { // radial coords += hpf(parseFloat(pattern.coords[2])) + " " + // r1 hpf(parseFloat(pattern.coords[3])) + " " + // x2 hpf(parseFloat(pattern.coords[4])) + " " + // y2 hpf(parseFloat(pattern.coords[5])); // r2 } coords += "]"; out(coords); if (pattern.matrix) { out("/Matrix [" + pattern.matrix.toString() + "]"); } out("/Function " + funcObjectNumber + " 0 R"); out("/Extend [true true]"); out(">>"); out("endobj"); }, putTilingPattern = function putTilingPattern(pattern) { var resourcesObjectNumber = newObject(); out("<<"); putResourceDictionary(); out(">>"); out("endobj"); pattern.objectNumber = newObject(); out("<< /Type /Pattern"); out("/PatternType 1"); // tiling pattern out("/PaintType 1"); // colored tiling pattern out("/TilingType 1"); // constant spacing out("/BBox [" + pattern.boundingBox.map(hpf).join(" ") + "]"); out("/XStep " + hpf(pattern.xStep)); out("/YStep " + hpf(pattern.yStep)); out("/Length " + pattern.stream.length); out("/Resources " + resourcesObjectNumber + " 0 R"); // TODO: resources pattern.matrix && out("/Matrix [" + pattern.matrix.toString() + "]"); out(">>"); putStream(pattern.stream); out("endobj"); }, putPatterns = function putPatterns() { var patternKey; for (patternKey in patterns) { if (patterns.hasOwnProperty(patternKey)) { if (patterns[patternKey] instanceof API.ShadingPattern) { putShadingPattern(patterns[patternKey]); } else if (patterns[patternKey] instanceof API.TilingPattern) { putTilingPattern(patterns[patternKey]); } } } }, putGState = function putGState(gState) { gState.objectNumber = newObject(); out("<<"); for (var p in gState) { switch (p) { case "opacity": out("/ca " + f2(gState[p])); break; case "stroke-opacity": out("/CA " + f2(gState[p])); break; } } out(">>"); out("endobj"); }, putGStates = function putGStates() { var gStateKey; for (gStateKey in gStates) { if (gStates.hasOwnProperty(gStateKey)) { putGState(gStates[gStateKey]); } } }, putXobjectDict = function putXobjectDict() { for (var xObjectKey in renderTargets) { if (renderTargets.hasOwnProperty(xObjectKey) && renderTargets[xObjectKey].objectNumber >= 0) { out("/" + xObjectKey + " " + renderTargets[xObjectKey].objectNumber + " 0 R"); } } events.publish("putXobjectDict"); }, putShadingPatternDict = function putShadingPatternDict() { for (var patternKey in patterns) { if (patterns.hasOwnProperty(patternKey) && patterns[patternKey] instanceof API.ShadingPattern && patterns[patternKey].objectNumber >= 0) { out("/" + patternKey + " " + patterns[patternKey].objectNumber + " 0 R"); } } events.publish("putShadingPatternDict"); }, putTilingPatternDict = function putTilingPatternDict() { for (var patternKey in patterns) { if (patterns.hasOwnProperty(patternKey) && patterns[patternKey] instanceof API.TilingPattern && patterns[patternKey].objectNumber >= 0) { out("/" + patternKey + " " + patterns[patternKey].objectNumber + " 0 R"); } } events.publish("putTilingPatternDict"); }, putGStatesDict = function putGStatesDict() { var gStateKey; for (gStateKey in gStates) { if (gStates.hasOwnProperty(gStateKey) && gStates[gStateKey].objectNumber >= 0) { out("/" + gStateKey + " " + gStates[gStateKey].objectNumber + " 0 R"); } } events.publish("putGStateDict"); }, 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)) { out("/" + fontKey + " " + fonts[fontKey].objectNumber + " 0 R"); } } out(">>"); out("/Shading <<"); putShadingPatternDict(); out(">>"); out("/Pattern <<"); putTilingPatternDict(); out(">>"); out("/ExtGState <<"); putGStatesDict(); out(">>"); out("/XObject <<"); putXobjectDict(); out(">>"); }, putResources = function putResources() { putFonts(); putGStates(); putXObjects(); putPatterns(); events.publish("putResources"); // Resource dictionary offsets[2] = content_length; out("2 0 obj"); out("<<"); putResourceDictionary(); out(">>"); out("endobj"); events.publish("postPutResources"); }, putAdditionalObjects = function putAdditionalObjects() { events.publish("putAdditionalObjects"); for (var i = 0; i < additionalObjects.length; i++) { var obj = additionalObjects[i]; offsets[obj.objId] = content_length; out(obj.objId + " 0 obj"); out(obj.content); out("endobj"); } objectNumber += additionalObjects.length; events.publish("postPutAdditionalObjects"); }, 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; }, 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; }, addFonts = function addFonts() { var HELVETICA = "helvetica", TIMES = "times", COURIER = "courier", NORMAL = "normal", BOLD = "bold", ITALIC = "italic", BOLD_ITALIC = "bolditalic", ZAPF = "zapfdingbats", SYMBOL = "symbol", standardFonts = [["Helvetica", HELVETICA, NORMAL, "WinAnsiEncoding"], ["Helvetica-B