PluginProbe
PDF & Print by BestWebSoft – WordPress Posts and Pages PDF Generator Plugin / trunk
PDF & Print by BestWebSoft – WordPress Posts and Pages PDF Generator Plugin vtrunk
trunk 1.5 1.6 1.7 1.7.1 1.7.2 1.7.3 1.7.4 1.7.5 1.7.6 1.7.7 1.7.8 1.7.9 1.8.0 1.8.1 1.8.2 1.8.3 1.8.4 1.8.5 1.8.6 1.8.7 1.8.8 1.8.9 1.9.0 1.9.1 All 71 releases
pdf-print / js / jspdf.js

jspdf.js in PDF & Print by BestWebSoft – WordPress Posts and Pages PDF Generator Plugin trunk, at js/jspdf.js

25,665 lines 859.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 (function (factory) {
2 typeof define === 'function' && define.amd ? define(factory) :
3 factory();
4 }(function () { 'use strict';
5
6 /** @license
7 * jsPDF - PDF Document creation from JavaScript
8 * Version 1.5.3 Built on 2018-12-27T14:11:42.696Z
9 * CommitID d93d28db14
10 *
11 * Copyright (c) 2010-2016 James Hall <james@parall.ax>, https://github.com/MrRio/jsPDF
12 * 2010 Aaron Spike, https://github.com/acspike
13 * 2012 Willow Systems Corporation, willow-systems.com
14 * 2012 Pablo Hess, https://github.com/pablohess
15 * 2012 Florian Jenett, https://github.com/fjenett
16 * 2013 Warren Weckesser, https://github.com/warrenweckesser
17 * 2013 Youssef Beddad, https://github.com/lifof
18 * 2013 Lee Driscoll, https://github.com/lsdriscoll
19 * 2013 Stefan Slonevskiy, https://github.com/stefslon
20 * 2013 Jeremy Morel, https://github.com/jmorel
21 * 2013 Christoph Hartmann, https://github.com/chris-rock
22 * 2014 Juan Pablo Gaviria, https://github.com/juanpgaviria
23 * 2014 James Makes, https://github.com/dollaruw
24 * 2014 Diego Casorran, https://github.com/diegocr
25 * 2014 Steven Spungin, https://github.com/Flamenco
26 * 2014 Kenneth Glassey, https://github.com/Gavvers
27 *
28 * Licensed under the MIT License
29 *
30 * Contributor(s):
31 * siefkenj, ahwolf, rickygu, Midnith, saintclair, eaparango,
32 * kim3er, mfo, alnorth, Flamenco
33 */
34
35 function _typeof(obj) {
36 if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") {
37 _typeof = function (obj) {
38 return typeof obj;
39 };
40 } else {
41 _typeof = function (obj) {
42 return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
43 };
44 }
45
46 return _typeof(obj);
47 }
48
49 /**
50 * JavaScript Polyfill functions for jsPDF
51 * Collected from public resources by
52 * https://github.com/diegocr
53 */
54 (function (global) {
55 if (_typeof(global.console) !== "object") {
56 // Console-polyfill. MIT license.
57 // https://github.com/paulmillr/console-polyfill
58 // Make it safe to do console.log() always.
59 global.console = {};
60 var con = global.console;
61 var prop, method;
62
63 var dummy = function dummy() {};
64
65 var properties = ['memory'];
66 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(',');
67
68 while (prop = properties.pop()) {
69 if (!con[prop]) con[prop] = {};
70 }
71
72 while (method = methods.pop()) {
73 if (!con[method]) con[method] = dummy;
74 }
75 }
76
77 var b64 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
78
79 if (typeof global.btoa === 'undefined') {
80 global.btoa = function (data) {
81 // discuss at: http://phpjs.org/functions/base64_encode/
82 // original by: Tyler Akins (http://rumkin.com)
83 // improved by: Bayron Guevara
84 // improved by: Thunder.m
85 // improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
86 // improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
87 // improved by: Rafal Kukawski (http://kukawski.pl)
88 // bugfixed by: Pellentesque Malesuada
89 // example 1: base64_encode('Kevin van Zonneveld');
90 // returns 1: 'S2V2aW4gdmFuIFpvbm5ldmVsZA=='
91 var o1,
92 o2,
93 o3,
94 h1,
95 h2,
96 h3,
97 h4,
98 bits,
99 i = 0,
100 ac = 0,
101 enc = '',
102 tmp_arr = [];
103
104 if (!data) {
105 return data;
106 }
107
108 do {
109 // pack three octets into four hexets
110 o1 = data.charCodeAt(i++);
111 o2 = data.charCodeAt(i++);
112 o3 = data.charCodeAt(i++);
113 bits = o1 << 16 | o2 << 8 | o3;
114 h1 = bits >> 18 & 0x3f;
115 h2 = bits >> 12 & 0x3f;
116 h3 = bits >> 6 & 0x3f;
117 h4 = bits & 0x3f; // use hexets to index into b64, and append result to encoded string
118
119 tmp_arr[ac++] = b64.charAt(h1) + b64.charAt(h2) + b64.charAt(h3) + b64.charAt(h4);
120 } while (i < data.length);
121
122 enc = tmp_arr.join('');
123 var r = data.length % 3;
124 return (r ? enc.slice(0, r - 3) : enc) + '==='.slice(r || 3);
125 };
126 }
127
128 if (typeof global.atob === 'undefined') {
129 global.atob = function (data) {
130 // discuss at: http://phpjs.org/functions/base64_decode/
131 // original by: Tyler Akins (http://rumkin.com)
132 // improved by: Thunder.m
133 // improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
134 // improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
135 // input by: Aman Gupta
136 // input by: Brett Zamir (http://brett-zamir.me)
137 // bugfixed by: Onno Marsman
138 // bugfixed by: Pellentesque Malesuada
139 // bugfixed by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
140 // example 1: base64_decode('S2V2aW4gdmFuIFpvbm5ldmVsZA==');
141 // returns 1: 'Kevin van Zonneveld'
142 var o1,
143 o2,
144 o3,
145 h1,
146 h2,
147 h3,
148 h4,
149 bits,
150 i = 0,
151 ac = 0,
152 dec = '',
153 tmp_arr = [];
154
155 if (!data) {
156 return data;
157 }
158
159 data += '';
160
161 do {
162 // unpack four hexets into three octets using index points in b64
163 h1 = b64.indexOf(data.charAt(i++));
164 h2 = b64.indexOf(data.charAt(i++));
165 h3 = b64.indexOf(data.charAt(i++));
166 h4 = b64.indexOf(data.charAt(i++));
167 bits = h1 << 18 | h2 << 12 | h3 << 6 | h4;
168 o1 = bits >> 16 & 0xff;
169 o2 = bits >> 8 & 0xff;
170 o3 = bits & 0xff;
171
172 if (h3 == 64) {
173 tmp_arr[ac++] = String.fromCharCode(o1);
174 } else if (h4 == 64) {
175 tmp_arr[ac++] = String.fromCharCode(o1, o2);
176 } else {
177 tmp_arr[ac++] = String.fromCharCode(o1, o2, o3);
178 }
179 } while (i < data.length);
180
181 dec = tmp_arr.join('');
182 return dec;
183 };
184 }
185
186 if (!Array.prototype.map) {
187 Array.prototype.map = function (fun
188 /*, thisArg */
189 ) {
190 if (this === void 0 || this === null || typeof fun !== "function") throw new TypeError();
191 var t = Object(this),
192 len = t.length >>> 0,
193 res = new Array(len);
194 var thisArg = arguments.length > 1 ? arguments[1] : void 0;
195
196 for (var i = 0; i < len; i++) {
197 // NOTE: Absolute correctness would demand Object.defineProperty
198 // be used. But this method is fairly new, and failure is
199 // possible only if Object.prototype or Array.prototype
200 // has a property |i| (very unlikely), so use a less-correct
201 // but more portable alternative.
202 if (i in t) res[i] = fun.call(thisArg, t[i], i, t);
203 }
204
205 return res;
206 };
207 }
208
209 if (!Array.isArray) {
210 Array.isArray = function (arg) {
211 return Object.prototype.toString.call(arg) === '[object Array]';
212 };
213 }
214
215 if (!Array.prototype.forEach) {
216 Array.prototype.forEach = function (fun, thisArg) {
217
218 if (this === void 0 || this === null || typeof fun !== "function") throw new TypeError();
219 var t = Object(this),
220 len = t.length >>> 0;
221
222 for (var i = 0; i < len; i++) {
223 if (i in t) fun.call(thisArg, t[i], i, t);
224 }
225 };
226 } // https://tc39.github.io/ecma262/#sec-array.prototype.find
227
228
229 if (!Array.prototype.find) {
230 Object.defineProperty(Array.prototype, 'find', {
231 value: function value(predicate) {
232 // 1. Let O be ? ToObject(this value).
233 if (this == null) {
234 throw new TypeError('"this" is null or not defined');
235 }
236
237 var o = Object(this); // 2. Let len be ? ToLength(? Get(O, "length")).
238
239 var len = o.length >>> 0; // 3. If IsCallable(predicate) is false, throw a TypeError exception.
240
241 if (typeof predicate !== 'function') {
242 throw new TypeError('predicate must be a function');
243 } // 4. If thisArg was supplied, let T be thisArg; else let T be undefined.
244
245
246 var thisArg = arguments[1]; // 5. Let k be 0.
247
248 var k = 0; // 6. Repeat, while k < len
249
250 while (k < len) {
251 // a. Let Pk be ! ToString(k).
252 // b. Let kValue be ? Get(O, Pk).
253 // c. Let testResult be ToBoolean(? Call(predicate, T, « kValue, k, O »)).
254 // d. If testResult is true, return kValue.
255 var kValue = o[k];
256
257 if (predicate.call(thisArg, kValue, k, o)) {
258 return kValue;
259 } // e. Increase k by 1.
260
261
262 k++;
263 } // 7. Return undefined.
264
265
266 return undefined;
267 },
268 configurable: true,
269 writable: true
270 });
271 }
272
273 if (!Object.keys) {
274 Object.keys = function () {
275
276 var hasOwnProperty = Object.prototype.hasOwnProperty,
277 hasDontEnumBug = !{
278 toString: null
279 }.propertyIsEnumerable('toString'),
280 dontEnums = ['toString', 'toLocaleString', 'valueOf', 'hasOwnProperty', 'isPrototypeOf', 'propertyIsEnumerable', 'constructor'],
281 dontEnumsLength = dontEnums.length;
282 return function (obj) {
283 if (_typeof(obj) !== 'object' && (typeof obj !== 'function' || obj === null)) {
284 throw new TypeError();
285 }
286
287 var result = [],
288 prop,
289 i;
290
291 for (prop in obj) {
292 if (hasOwnProperty.call(obj, prop)) {
293 result.push(prop);
294 }
295 }
296
297 if (hasDontEnumBug) {
298 for (i = 0; i < dontEnumsLength; i++) {
299 if (hasOwnProperty.call(obj, dontEnums[i])) {
300 result.push(dontEnums[i]);
301 }
302 }
303 }
304
305 return result;
306 };
307 }();
308 }
309
310 if (typeof Object.assign != 'function') {
311 Object.assign = function (target) {
312
313 if (target == null) {
314 throw new TypeError('Cannot convert undefined or null to object');
315 }
316
317 target = Object(target);
318
319 for (var index = 1; index < arguments.length; index++) {
320 var source = arguments[index];
321
322 if (source != null) {
323 for (var key in source) {
324 if (Object.prototype.hasOwnProperty.call(source, key)) {
325 target[key] = source[key];
326 }
327 }
328 }
329 }
330
331 return target;
332 };
333 }
334
335 if (!String.prototype.trim) {
336 String.prototype.trim = function () {
337 return this.replace(/^\s+|\s+$/g, '');
338 };
339 }
340
341 if (!String.prototype.trimLeft) {
342 String.prototype.trimLeft = function () {
343 return this.replace(/^\s+/g, "");
344 };
345 }
346
347 if (!String.prototype.trimRight) {
348 String.prototype.trimRight = function () {
349 return this.replace(/\s+$/g, "");
350 };
351 }
352
353 Number.isInteger = Number.isInteger || function (value) {
354 return typeof value === 'number' && isFinite(value) && Math.floor(value) === value;
355 };
356 })(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
357 // while `this` is nsIContentFrameMessageManager
358 // with an attribute `content` that corresponds to the window
359
360 /**
361 * Creates new jsPDF document object instance.
362 * @name jsPDF
363 * @class
364 * @param orientation {string/Object} Orientation of the first page. Possible values are "portrait" or "landscape" (or shortcuts "p" (Default), "l").<br />
365 * Can also be an options object.
366 * @param unit {string} Measurement unit to be used when coordinates are specified.<br />
367 * Possible values are "pt" (points), "mm" (Default), "cm", "in" or "px".
368 * @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 />
369 * 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]
370 * @returns {jsPDF} jsPDF-instance
371 * @description
372 * If the first parameter (orientation) is an object, it will be interpreted as an object of named parameters
373 * ```
374 * {
375 * orientation: 'p',
376 * unit: 'mm',
377 * format: 'a4',
378 * hotfixes: [] // an array of hotfix strings to enable
379 * }
380 * ```
381 */
382 var jsPDF = function (global) {
383 /**
384 * jsPDF's Internal PubSub Implementation.
385 * Backward compatible rewritten on 2014 by
386 * Diego Casorran, https://github.com/diegocr
387 *
388 * @class
389 * @name PubSub
390 * @ignore
391 */
392
393 function PubSub(context) {
394 if (_typeof(context) !== 'object') {
395 throw new Error('Invalid Context passed to initialize PubSub (jsPDF-module)');
396 }
397
398 var topics = {};
399
400 this.subscribe = function (topic, callback, once) {
401 once = once || false;
402
403 if (typeof topic !== 'string' || typeof callback !== 'function' || typeof once !== 'boolean') {
404 throw new Error('Invalid arguments passed to PubSub.subscribe (jsPDF-module)');
405 }
406
407 if (!topics.hasOwnProperty(topic)) {
408 topics[topic] = {};
409 }
410
411 var token = Math.random().toString(35);
412 topics[topic][token] = [callback, !!once];
413 return token;
414 };
415
416 this.unsubscribe = function (token) {
417 for (var topic in topics) {
418 if (topics[topic][token]) {
419 delete topics[topic][token];
420
421 if (Object.keys(topics[topic]).length === 0) {
422 delete topics[topic];
423 }
424
425 return true;
426 }
427 }
428
429 return false;
430 };
431
432 this.publish = function (topic) {
433 if (topics.hasOwnProperty(topic)) {
434 var args = Array.prototype.slice.call(arguments, 1),
435 tokens = [];
436
437 for (var token in topics[topic]) {
438 var sub = topics[topic][token];
439
440 try {
441 sub[0].apply(context, args);
442 } catch (ex) {
443 if (global.console) {
444 console.error('jsPDF PubSub Error', ex.message, ex);
445 }
446 }
447
448 if (sub[1]) tokens.push(token);
449 }
450
451 if (tokens.length) tokens.forEach(this.unsubscribe);
452 }
453 };
454
455 this.getTopics = function () {
456 return topics;
457 };
458 }
459 /**
460 * @constructor
461 * @private
462 */
463
464
465 function jsPDF(orientation, unit, format, compressPdf) {
466 var options = {};
467 var filters = [];
468 var userUnit = 1.0;
469
470 if (_typeof(orientation) === 'object') {
471 options = orientation;
472 orientation = options.orientation;
473 unit = options.unit || unit;
474 format = options.format || format;
475 compressPdf = options.compress || options.compressPdf || compressPdf;
476 filters = options.filters || (compressPdf === true ? ['FlateEncode'] : filters);
477 userUnit = typeof options.userUnit === "number" ? Math.abs(options.userUnit) : 1.0;
478 }
479
480 unit = unit || 'mm';
481 orientation = ('' + (orientation || 'P')).toLowerCase();
482 var putOnlyUsedFonts = options.putOnlyUsedFonts || true;
483 var usedFonts = {};
484 var API = {
485 internal: {},
486 __private__: {}
487 };
488 API.__private__.PubSub = PubSub;
489 var pdfVersion = '1.3';
490
491 var getPdfVersion = API.__private__.getPdfVersion = function () {
492 return pdfVersion;
493 };
494
495 var setPdfVersion = API.__private__.setPdfVersion = function (value) {
496 pdfVersion = value;
497 }; // Size in pt of various paper formats
498
499
500 var pageFormats = {
501 'a0': [2383.94, 3370.39],
502 'a1': [1683.78, 2383.94],
503 'a2': [1190.55, 1683.78],
504 'a3': [841.89, 1190.55],
505 'a4': [595.28, 841.89],
506 'a5': [419.53, 595.28],
507 'a6': [297.64, 419.53],
508 'a7': [209.76, 297.64],
509 'a8': [147.40, 209.76],
510 'a9': [104.88, 147.40],
511 'a10': [73.70, 104.88],
512 'b0': [2834.65, 4008.19],
513 'b1': [2004.09, 2834.65],
514 'b2': [1417.32, 2004.09],
515 'b3': [1000.63, 1417.32],
516 'b4': [708.66, 1000.63],
517 'b5': [498.90, 708.66],
518 'b6': [354.33, 498.90],
519 'b7': [249.45, 354.33],
520 'b8': [175.75, 249.45],
521 'b9': [124.72, 175.75],
522 'b10': [87.87, 124.72],
523 'c0': [2599.37, 3676.54],
524 'c1': [1836.85, 2599.37],
525 'c2': [1298.27, 1836.85],
526 'c3': [918.43, 1298.27],
527 'c4': [649.13, 918.43],
528 'c5': [459.21, 649.13],
529 'c6': [323.15, 459.21],
530 'c7': [229.61, 323.15],
531 'c8': [161.57, 229.61],
532 'c9': [113.39, 161.57],
533 'c10': [79.37, 113.39],
534 'dl': [311.81, 623.62],
535 'letter': [612, 792],
536 'government-letter': [576, 756],
537 'legal': [612, 1008],
538 'junior-legal': [576, 360],
539 'ledger': [1224, 792],
540 'tabloid': [792, 1224],
541 'credit-card': [153, 243]
542 };
543
544 var getPageFormats = API.__private__.getPageFormats = function () {
545 return pageFormats;
546 };
547
548 var getPageFormat = API.__private__.getPageFormat = function (value) {
549 return pageFormats[value];
550 };
551
552 if (typeof format === "string") {
553 format = getPageFormat(format);
554 }
555
556 format = format || getPageFormat('a4');
557
558 var f2 = API.f2 = API.__private__.f2 = function (number) {
559 if (isNaN(number)) {
560 throw new Error('Invalid argument passed to jsPDF.f2');
561 }
562
563 return number.toFixed(2); // Ie, %.2f
564 };
565
566 var f3 = API.__private__.f3 = function (number) {
567 if (isNaN(number)) {
568 throw new Error('Invalid argument passed to jsPDF.f3');
569 }
570
571 return number.toFixed(3); // Ie, %.3f
572 };
573
574 var fileId = '00000000000000000000000000000000';
575
576 var getFileId = API.__private__.getFileId = function () {
577 return fileId;
578 };
579
580 var setFileId = API.__private__.setFileId = function (value) {
581 value = value || "12345678901234567890123456789012".split('').map(function () {
582 return "ABCDEF0123456789".charAt(Math.floor(Math.random() * 16));
583 }).join('');
584 fileId = value;
585 return fileId;
586 };
587 /**
588 * @name setFileId
589 * @memberOf jsPDF
590 * @function
591 * @instance
592 * @param {string} value GUID.
593 * @returns {jsPDF}
594 */
595
596
597 API.setFileId = function (value) {
598 setFileId(value);
599 return this;
600 };
601 /**
602 * @name getFileId
603 * @memberOf jsPDF
604 * @function
605 * @instance
606 *
607 * @returns {string} GUID.
608 */
609
610
611 API.getFileId = function () {
612 return getFileId();
613 };
614
615 var creationDate;
616
617 var convertDateToPDFDate = API.__private__.convertDateToPDFDate = function (parmDate) {
618 var result = '';
619 var tzoffset = parmDate.getTimezoneOffset(),
620 tzsign = tzoffset < 0 ? '+' : '-',
621 tzhour = Math.floor(Math.abs(tzoffset / 60)),
622 tzmin = Math.abs(tzoffset % 60),
623 timeZoneString = [tzsign, padd2(tzhour), "'", padd2(tzmin), "'"].join('');
624 result = ['D:', parmDate.getFullYear(), padd2(parmDate.getMonth() + 1), padd2(parmDate.getDate()), padd2(parmDate.getHours()), padd2(parmDate.getMinutes()), padd2(parmDate.getSeconds()), timeZoneString].join('');
625 return result;
626 };
627
628 var convertPDFDateToDate = API.__private__.convertPDFDateToDate = function (parmPDFDate) {
629 var year = parseInt(parmPDFDate.substr(2, 4), 10);
630 var month = parseInt(parmPDFDate.substr(6, 2), 10) - 1;
631 var date = parseInt(parmPDFDate.substr(8, 2), 10);
632 var hour = parseInt(parmPDFDate.substr(10, 2), 10);
633 var minutes = parseInt(parmPDFDate.substr(12, 2), 10);
634 var seconds = parseInt(parmPDFDate.substr(14, 2), 10);
635 var timeZoneHour = parseInt(parmPDFDate.substr(16, 2), 10);
636 var timeZoneMinutes = parseInt(parmPDFDate.substr(20, 2), 10);
637 var resultingDate = new Date(year, month, date, hour, minutes, seconds, 0);
638 return resultingDate;
639 };
640
641 var setCreationDate = API.__private__.setCreationDate = function (date) {
642 var tmpCreationDateString;
643 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])\'?$/;
644
645 if (typeof date === "undefined") {
646 date = new Date();
647 }
648
649 if (_typeof(date) === "object" && Object.prototype.toString.call(date) === "[object Date]") {
650 tmpCreationDateString = convertDateToPDFDate(date);
651 } else if (regexPDFCreationDate.test(date)) {
652 tmpCreationDateString = date;
653 } else {
654 throw new Error('Invalid argument passed to jsPDF.setCreationDate');
655 }
656
657 creationDate = tmpCreationDateString;
658 return creationDate;
659 };
660
661 var getCreationDate = API.__private__.getCreationDate = function (type) {
662 var result = creationDate;
663
664 if (type === "jsDate") {
665 result = convertPDFDateToDate(creationDate);
666 }
667
668 return result;
669 };
670 /**
671 * @name setCreationDate
672 * @memberOf jsPDF
673 * @function
674 * @instance
675 * @param {Object} date
676 * @returns {jsPDF}
677 */
678
679
680 API.setCreationDate = function (date) {
681 setCreationDate(date);
682 return this;
683 };
684 /**
685 * @name getCreationDate
686 * @memberOf jsPDF
687 * @function
688 * @instance
689 * @param {Object} type
690 * @returns {Object}
691 */
692
693
694 API.getCreationDate = function (type) {
695 return getCreationDate(type);
696 };
697
698 var padd2 = API.__private__.padd2 = function (number) {
699 return ('0' + parseInt(number)).slice(-2);
700 };
701
702 var outToPages = !1; // switches where out() prints. outToPages true = push to pages obj. outToPages false = doc builder content
703
704 var pages = [];
705 var content = [];
706 var currentPage;
707 var content_length = 0;
708 var customOutputDestination;
709
710 var setOutputDestination = API.__private__.setCustomOutputDestination = function (destination) {
711 customOutputDestination = destination;
712 };
713
714 var resetOutputDestination = API.__private__.resetCustomOutputDestination = function (destination) {
715 customOutputDestination = undefined;
716 };
717
718 var out = API.__private__.out = function (string) {
719 var writeArray;
720 string = typeof string === "string" ? string : string.toString();
721
722 if (typeof customOutputDestination === "undefined") {
723 writeArray = outToPages ? pages[currentPage] : content;
724 } else {
725 writeArray = customOutputDestination;
726 }
727
728 writeArray.push(string);
729
730 if (!outToPages) {
731 content_length += string.length + 1;
732 }
733
734 return writeArray;
735 };
736
737 var write = API.__private__.write = function (value) {
738 return out(arguments.length === 1 ? value.toString() : Array.prototype.join.call(arguments, ' '));
739 };
740
741 var getArrayBuffer = API.__private__.getArrayBuffer = function (data) {
742 var len = data.length,
743 ab = new ArrayBuffer(len),
744 u8 = new Uint8Array(ab);
745
746 while (len--) {
747 u8[len] = data.charCodeAt(len);
748 }
749
750 return ab;
751 };
752
753 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]];
754
755 var getStandardFonts = API.__private__.getStandardFonts = function (data) {
756 return standardFonts;
757 };
758
759 var activeFontSize = options.fontSize || 16;
760 /**
761 * Sets font size for upcoming text elements.
762 *
763 * @param {number} size Font size in points.
764 * @function
765 * @instance
766 * @returns {jsPDF}
767 * @memberOf jsPDF
768 * @name setFontSize
769 */
770
771 var setFontSize = API.__private__.setFontSize = API.setFontSize = function (size) {
772 activeFontSize = size;
773 return this;
774 };
775 /**
776 * Gets the fontsize for upcoming text elements.
777 *
778 * @function
779 * @instance
780 * @returns {number}
781 * @memberOf jsPDF
782 * @name getFontSize
783 */
784
785
786 var getFontSize = API.__private__.getFontSize = API.getFontSize = function () {
787 return activeFontSize;
788 };
789
790 var R2L = options.R2L || false;
791 /**
792 * Set value of R2L functionality.
793 *
794 * @param {boolean} value
795 * @function
796 * @instance
797 * @returns {jsPDF} jsPDF-instance
798 * @memberOf jsPDF
799 * @name setR2L
800 */
801
802 var setR2L = API.__private__.setR2L = API.setR2L = function (value) {
803 R2L = value;
804 return this;
805 };
806 /**
807 * Get value of R2L functionality.
808 *
809 * @function
810 * @instance
811 * @returns {boolean} jsPDF-instance
812 * @memberOf jsPDF
813 * @name getR2L
814 */
815
816
817 var getR2L = API.__private__.getR2L = API.getR2L = function (value) {
818 return R2L;
819 };
820
821 var zoomMode; // default: 1;
822
823 var setZoomMode = API.__private__.setZoomMode = function (zoom) {
824 var validZoomModes = [undefined, null, 'fullwidth', 'fullheight', 'fullpage', 'original'];
825
826 if (/^\d*\.?\d*\%$/.test(zoom)) {
827 zoomMode = zoom;
828 } else if (!isNaN(zoom)) {
829 zoomMode = parseInt(zoom, 10);
830 } else if (validZoomModes.indexOf(zoom) !== -1) {
831 zoomMode = zoom;
832 } else {
833 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.');
834 }
835 };
836
837 var getZoomMode = API.__private__.getZoomMode = function () {
838 return zoomMode;
839 };
840
841 var pageMode; // default: 'UseOutlines';
842
843 var setPageMode = API.__private__.setPageMode = function (pmode) {
844 var validPageModes = [undefined, null, 'UseNone', 'UseOutlines', 'UseThumbs', 'FullScreen'];
845
846 if (validPageModes.indexOf(pmode) == -1) {
847 throw new Error('Page mode must be one of UseNone, UseOutlines, UseThumbs, or FullScreen. "' + pmode + '" is not recognized.');
848 }
849
850 pageMode = pmode;
851 };
852
853 var getPageMode = API.__private__.getPageMode = function () {
854 return pageMode;
855 };
856
857 var layoutMode; // default: 'continuous';
858
859 var setLayoutMode = API.__private__.setLayoutMode = function (layout) {
860 var validLayoutModes = [undefined, null, 'continuous', 'single', 'twoleft', 'tworight', 'two'];
861
862 if (validLayoutModes.indexOf(layout) == -1) {
863 throw new Error('Layout mode must be one of continuous, single, twoleft, tworight. "' + layout + '" is not recognized.');
864 }
865
866 layoutMode = layout;
867 };
868
869 var getLayoutMode = API.__private__.getLayoutMode = function () {
870 return layoutMode;
871 };
872 /**
873 * Set the display mode options of the page like zoom and layout.
874 *
875 * @name setDisplayMode
876 * @memberOf jsPDF
877 * @function
878 * @instance
879 * @param {integer|String} zoom You can pass an integer or percentage as
880 * a string. 2 will scale the document up 2x, '200%' will scale up by the
881 * same amount. You can also set it to 'fullwidth', 'fullheight',
882 * 'fullpage', or 'original'.
883 *
884 * Only certain PDF readers support this, such as Adobe Acrobat.
885 *
886 * @param {string} layout Layout mode can be: 'continuous' - this is the
887 * default continuous scroll. 'single' - the single page mode only shows one
888 * page at a time. 'twoleft' - two column left mode, first page starts on
889 * the left, and 'tworight' - pages are laid out in two columns, with the
890 * first page on the right. This would be used for books.
891 * @param {string} pmode 'UseOutlines' - it shows the
892 * outline of the document on the left. 'UseThumbs' - shows thumbnails along
893 * the left. 'FullScreen' - prompts the user to enter fullscreen mode.
894 *
895 * @returns {jsPDF}
896 */
897
898
899 var setDisplayMode = API.__private__.setDisplayMode = API.setDisplayMode = function (zoom, layout, pmode) {
900 setZoomMode(zoom);
901 setLayoutMode(layout);
902 setPageMode(pmode);
903 return this;
904 };
905
906 var documentProperties = {
907 'title': '',
908 'subject': '',
909 'author': '',
910 'keywords': '',
911 'creator': ''
912 };
913
914 var getDocumentProperty = API.__private__.getDocumentProperty = function (key) {
915 if (Object.keys(documentProperties).indexOf(key) === -1) {
916 throw new Error('Invalid argument passed to jsPDF.getDocumentProperty');
917 }
918
919 return documentProperties[key];
920 };
921
922 var getDocumentProperties = API.__private__.getDocumentProperties = function (properties) {
923 return documentProperties;
924 };
925 /**
926 * Adds a properties to the PDF document.
927 *
928 * @param {Object} A property_name-to-property_value object structure.
929 * @function
930 * @instance
931 * @returns {jsPDF}
932 * @memberOf jsPDF
933 * @name setDocumentProperties
934 */
935
936
937 var setDocumentProperties = API.__private__.setDocumentProperties = API.setProperties = API.setDocumentProperties = function (properties) {
938 // copying only those properties we can render.
939 for (var property in documentProperties) {
940 if (documentProperties.hasOwnProperty(property) && properties[property]) {
941 documentProperties[property] = properties[property];
942 }
943 }
944
945 return this;
946 };
947
948 var setDocumentProperty = API.__private__.setDocumentProperty = function (key, value) {
949 if (Object.keys(documentProperties).indexOf(key) === -1) {
950 throw new Error('Invalid arguments passed to jsPDF.setDocumentProperty');
951 }
952
953 return documentProperties[key] = value;
954 };
955
956 var objectNumber = 0; // 'n' Current object number
957
958 var offsets = []; // List of offsets. Activated and reset by buildDocument(). Pupulated by various calls buildDocument makes.
959
960 var fonts = {}; // collection of font objects, where key is fontKey - a dynamically created label for a given font.
961
962 var fontmap = {}; // mapping structure fontName > fontStyle > font key - performance layer. See addFont()
963
964 var activeFontKey; // will be string representing the KEY of the font as combination of fontName + fontStyle
965
966 var k; // Scale factor
967
968 var page = 0;
969 var pagesContext = [];
970 var additionalObjects = [];
971 var events = new PubSub(API);
972 var hotfixes = options.hotfixes || [];
973
974 var newObject = API.__private__.newObject = function () {
975 var oid = newObjectDeferred();
976 newObjectDeferredBegin(oid, true);
977 return oid;
978 }; // Does not output the object. The caller must call newObjectDeferredBegin(oid) before outputing any data
979
980
981 var newObjectDeferred = API.__private__.newObjectDeferred = function () {
982 objectNumber++;
983
984 offsets[objectNumber] = function () {
985 return content_length;
986 };
987
988 return objectNumber;
989 };
990
991 var newObjectDeferredBegin = function newObjectDeferredBegin(oid, doOutput) {
992 doOutput = typeof doOutput === 'boolean' ? doOutput : false;
993 offsets[oid] = content_length;
994
995 if (doOutput) {
996 out(oid + ' 0 obj');
997 }
998
999 return oid;
1000 }; // Does not output the object until after the pages have been output.
1001 // Returns an object containing the objectId and content.
1002 // All pages have been added so the object ID can be estimated to start right after.
1003 // This does not modify the current objectNumber; It must be updated after the newObjects are output.
1004
1005
1006 var newAdditionalObject = API.__private__.newAdditionalObject = function () {
1007 var objId = newObjectDeferred();
1008 var obj = {
1009 objId: objId,
1010 content: ''
1011 };
1012 additionalObjects.push(obj);
1013 return obj;
1014 };
1015
1016 var rootDictionaryObjId = newObjectDeferred();
1017 var resourceDictionaryObjId = newObjectDeferred(); /////////////////////
1018 // Private functions
1019 /////////////////////
1020
1021 var decodeColorString = API.__private__.decodeColorString = function (color) {
1022 var colorEncoded = color.split(' ');
1023
1024 if (colorEncoded.length === 2 && (colorEncoded[1] === 'g' || colorEncoded[1] === 'G')) {
1025 // convert grayscale value to rgb so that it can be converted to hex for consistency
1026 var floatVal = parseFloat(colorEncoded[0]);
1027 colorEncoded = [floatVal, floatVal, floatVal, 'r'];
1028 }
1029
1030 var colorAsRGB = '#';
1031
1032 for (var i = 0; i < 3; i++) {
1033 colorAsRGB += ('0' + Math.floor(parseFloat(colorEncoded[i]) * 255).toString(16)).slice(-2);
1034 }
1035
1036 return colorAsRGB;
1037 };
1038
1039 var encodeColorString = API.__private__.encodeColorString = function (options) {
1040 var color;
1041
1042 if (typeof options === "string") {
1043 options = {
1044 ch1: options
1045 };
1046 }
1047
1048 var ch1 = options.ch1;
1049 var ch2 = options.ch2;
1050 var ch3 = options.ch3;
1051 var ch4 = options.ch4;
1052 var precision = options.precision;
1053 var letterArray = options.pdfColorType === "draw" ? ['G', 'RG', 'K'] : ['g', 'rg', 'k'];
1054
1055 if (typeof ch1 === "string" && ch1.charAt(0) !== '#') {
1056 var rgbColor = new RGBColor(ch1);
1057
1058 if (rgbColor.ok) {
1059 ch1 = rgbColor.toHex();
1060 } else if (!/^\d*\.?\d*$/.test(ch1)) {
1061 throw new Error('Invalid color "' + ch1 + '" passed to jsPDF.encodeColorString.');
1062 }
1063 } //convert short rgb to long form
1064
1065
1066 if (typeof ch1 === "string" && /^#[0-9A-Fa-f]{3}$/.test(ch1)) {
1067 ch1 = '#' + ch1[1] + ch1[1] + ch1[2] + ch1[2] + ch1[3] + ch1[3];
1068 }
1069
1070 if (typeof ch1 === "string" && /^#[0-9A-Fa-f]{6}$/.test(ch1)) {
1071 var hex = parseInt(ch1.substr(1), 16);
1072 ch1 = hex >> 16 & 255;
1073 ch2 = hex >> 8 & 255;
1074 ch3 = hex & 255;
1075 }
1076
1077 if (typeof ch2 === "undefined" || typeof ch4 === "undefined" && ch1 === ch2 && ch2 === ch3) {
1078 // Gray color space.
1079 if (typeof ch1 === "string") {
1080 color = ch1 + " " + letterArray[0];
1081 } else {
1082 switch (options.precision) {
1083 case 2:
1084 color = f2(ch1 / 255) + " " + letterArray[0];
1085 break;
1086
1087 case 3:
1088 default:
1089 color = f3(ch1 / 255) + " " + letterArray[0];
1090 }
1091 }
1092 } else if (typeof ch4 === "undefined" || _typeof(ch4) === "object") {
1093 // assume RGBA
1094 if (ch4 && !isNaN(ch4.a)) {
1095 //TODO Implement transparency.
1096 //WORKAROUND use white for now, if transparent, otherwise handle as rgb
1097 if (ch4.a === 0) {
1098 color = ['1.000', '1.000', '1.000', letterArray[1]].join(" ");
1099 return color;
1100 }
1101 } // assume RGB
1102
1103
1104 if (typeof ch1 === "string") {
1105 color = [ch1, ch2, ch3, letterArray[1]].join(" ");
1106 } else {
1107 switch (options.precision) {
1108 case 2:
1109 color = [f2(ch1 / 255), f2(ch2 / 255), f2(ch3 / 255), letterArray[1]].join(" ");
1110 break;
1111
1112 default:
1113 case 3:
1114 color = [f3(ch1 / 255), f3(ch2 / 255), f3(ch3 / 255), letterArray[1]].join(" ");
1115 }
1116 }
1117 } else {
1118 // assume CMYK
1119 if (typeof ch1 === 'string') {
1120 color = [ch1, ch2, ch3, ch4, letterArray[2]].join(" ");
1121 } else {
1122 switch (options.precision) {
1123 case 2:
1124 color = [f2(ch1 / 255), f2(ch2 / 255), f2(ch3 / 255), f2(ch4 / 255), letterArray[2]].join(" ");
1125 break;
1126
1127 case 3:
1128 default:
1129 color = [f3(ch1 / 255), f3(ch2 / 255), f3(ch3 / 255), f3(ch4 / 255), letterArray[2]].join(" ");
1130 }
1131 }
1132 }
1133
1134 return color;
1135 };
1136
1137 var getFilters = API.__private__.getFilters = function () {
1138 return filters;
1139 };
1140
1141 var putStream = API.__private__.putStream = function (options) {
1142 options = options || {};
1143 var data = options.data || '';
1144 var filters = options.filters || getFilters();
1145 var alreadyAppliedFilters = options.alreadyAppliedFilters || [];
1146 var addLength1 = options.addLength1 || false;
1147 var valueOfLength1 = data.length;
1148 var processedData = {};
1149
1150 if (filters === true) {
1151 filters = ['FlateEncode'];
1152 }
1153
1154 var keyValues = options.additionalKeyValues || [];
1155
1156 if (typeof jsPDF.API.processDataByFilters !== 'undefined') {
1157 processedData = jsPDF.API.processDataByFilters(data, filters);
1158 } else {
1159 processedData = {
1160 data: data,
1161 reverseChain: []
1162 };
1163 }
1164
1165 var filterAsString = processedData.reverseChain + (Array.isArray(alreadyAppliedFilters) ? alreadyAppliedFilters.join(' ') : alreadyAppliedFilters.toString());
1166
1167 if (processedData.data.length !== 0) {
1168 keyValues.push({
1169 key: 'Length',
1170 value: processedData.data.length
1171 });
1172
1173 if (addLength1 === true) {
1174 keyValues.push({
1175 key: 'Length1',
1176 value: valueOfLength1
1177 });
1178 }
1179 }
1180
1181 if (filterAsString.length != 0) {
1182 //if (filters.length === 0 && alreadyAppliedFilters.length === 1 && typeof alreadyAppliedFilters !== "undefined") {
1183 if (filterAsString.split('/').length - 1 === 1) {
1184 keyValues.push({
1185 key: 'Filter',
1186 value: filterAsString
1187 });
1188 } else {
1189 keyValues.push({
1190 key: 'Filter',
1191 value: '[' + filterAsString + ']'
1192 });
1193 }
1194 }
1195
1196 out('<<');
1197
1198 for (var i = 0; i < keyValues.length; i++) {
1199 out('/' + keyValues[i].key + ' ' + keyValues[i].value);
1200 }
1201
1202 out('>>');
1203
1204 if (processedData.data.length !== 0) {
1205 out('stream');
1206 out(processedData.data);
1207 out('endstream');
1208 }
1209 };
1210
1211 var putPage = API.__private__.putPage = function (page) {
1212 var mediaBox = page.mediaBox;
1213 var pageNumber = page.number;
1214 var data = page.data;
1215 var pageObjectNumber = page.objId;
1216 var pageContentsObjId = page.contentsObjId;
1217 newObjectDeferredBegin(pageObjectNumber, true);
1218 var wPt = pagesContext[currentPage].mediaBox.topRightX - pagesContext[currentPage].mediaBox.bottomLeftX;
1219 var hPt = pagesContext[currentPage].mediaBox.topRightY - pagesContext[currentPage].mediaBox.bottomLeftY;
1220 out('<</Type /Page');
1221 out('/Parent ' + page.rootDictionaryObjId + ' 0 R');
1222 out('/Resources ' + page.resourceDictionaryObjId + ' 0 R');
1223 out('/MediaBox [' + parseFloat(f2(page.mediaBox.bottomLeftX)) + ' ' + parseFloat(f2(page.mediaBox.bottomLeftY)) + ' ' + f2(page.mediaBox.topRightX) + ' ' + f2(page.mediaBox.topRightY) + ']');
1224
1225 if (page.cropBox !== null) {
1226 out('/CropBox [' + f2(page.cropBox.bottomLeftX) + ' ' + f2(page.cropBox.bottomLeftY) + ' ' + f2(page.cropBox.topRightX) + ' ' + f2(page.cropBox.topRightY) + ']');
1227 }
1228
1229 if (page.bleedBox !== null) {
1230 out('/BleedBox [' + f2(page.bleedBox.bottomLeftX) + ' ' + f2(page.bleedBox.bottomLeftY) + ' ' + f2(page.bleedBox.topRightX) + ' ' + f2(page.bleedBox.topRightY) + ']');
1231 }
1232
1233 if (page.trimBox !== null) {
1234 out('/TrimBox [' + f2(page.trimBox.bottomLeftX) + ' ' + f2(page.trimBox.bottomLeftY) + ' ' + f2(page.trimBox.topRightX) + ' ' + f2(page.trimBox.topRightY) + ']');
1235 }
1236
1237 if (page.artBox !== null) {
1238 out('/ArtBox [' + f2(page.artBox.bottomLeftX) + ' ' + f2(page.artBox.bottomLeftY) + ' ' + f2(page.artBox.topRightX) + ' ' + f2(page.artBox.topRightY) + ']');
1239 }
1240
1241 if (typeof page.userUnit === "number" && page.userUnit !== 1.0) {
1242 out('/UserUnit ' + page.userUnit);
1243 }
1244
1245 events.publish('putPage', {
1246 objId: pageObjectNumber,
1247 pageContext: pagesContext[pageNumber],
1248 pageNumber: pageNumber,
1249 page: data
1250 });
1251 out('/Contents ' + pageContentsObjId + ' 0 R');
1252 out('>>');
1253 out('endobj'); // Page content
1254
1255 var pageContent = data.join('\n');
1256 newObjectDeferredBegin(pageContentsObjId, true);
1257 putStream({
1258 data: pageContent,
1259 filters: getFilters()
1260 });
1261 out('endobj');
1262 return pageObjectNumber;
1263 };
1264
1265 var putPages = API.__private__.putPages = function () {
1266 var n,
1267 i,
1268 pageObjectNumbers = [];
1269
1270 for (n = 1; n <= page; n++) {
1271 pagesContext[n].objId = newObjectDeferred();
1272 pagesContext[n].contentsObjId = newObjectDeferred();
1273 }
1274
1275 for (n = 1; n <= page; n++) {
1276 pageObjectNumbers.push(putPage({
1277 number: n,
1278 data: pages[n],
1279 objId: pagesContext[n].objId,
1280 contentsObjId: pagesContext[n].contentsObjId,
1281 mediaBox: pagesContext[n].mediaBox,
1282 cropBox: pagesContext[n].cropBox,
1283 bleedBox: pagesContext[n].bleedBox,
1284 trimBox: pagesContext[n].trimBox,
1285 artBox: pagesContext[n].artBox,
1286 userUnit: pagesContext[n].userUnit,
1287 rootDictionaryObjId: rootDictionaryObjId,
1288 resourceDictionaryObjId: resourceDictionaryObjId
1289 }));
1290 }
1291
1292 newObjectDeferredBegin(rootDictionaryObjId, true);
1293 out('<</Type /Pages');
1294 var kids = '/Kids [';
1295
1296 for (i = 0; i < page; i++) {
1297 kids += pageObjectNumbers[i] + ' 0 R ';
1298 }
1299
1300 out(kids + ']');
1301 out('/Count ' + page);
1302 out('>>');
1303 out('endobj');
1304 events.publish('postPutPages');
1305 };
1306
1307 var putFont = function putFont(font) {
1308 events.publish('putFont', {
1309 font: font,
1310 out: out,
1311 newObject: newObject,
1312 putStream: putStream
1313 });
1314
1315 if (font.isAlreadyPutted !== true) {
1316 font.objectNumber = newObject();
1317 out('<<');
1318 out('/Type /Font');
1319 out('/BaseFont /' + font.postScriptName);
1320 out('/Subtype /Type1');
1321
1322 if (typeof font.encoding === 'string') {
1323 out('/Encoding /' + font.encoding);
1324 }
1325
1326 out('/FirstChar 32');
1327 out('/LastChar 255');
1328 out('>>');
1329 out('endobj');
1330 }
1331 };
1332
1333 var putFonts = function putFonts() {
1334 for (var fontKey in fonts) {
1335 if (fonts.hasOwnProperty(fontKey)) {
1336 if (putOnlyUsedFonts === false || putOnlyUsedFonts === true && usedFonts.hasOwnProperty(fontKey)) {
1337 putFont(fonts[fontKey]);
1338 }
1339 }
1340 }
1341 };
1342
1343 var putResourceDictionary = function putResourceDictionary() {
1344 out('/ProcSet [/PDF /Text /ImageB /ImageC /ImageI]');
1345 out('/Font <<'); // Do this for each font, the '1' bit is the index of the font
1346
1347 for (var fontKey in fonts) {
1348 if (fonts.hasOwnProperty(fontKey)) {
1349 if (putOnlyUsedFonts === false || putOnlyUsedFonts === true && usedFonts.hasOwnProperty(fontKey)) {
1350 out('/' + fontKey + ' ' + fonts[fontKey].objectNumber + ' 0 R');
1351 }
1352 }
1353 }
1354
1355 out('>>');
1356 out('/XObject <<');
1357 events.publish('putXobjectDict');
1358 out('>>');
1359 };
1360
1361 var putResources = function putResources() {
1362 putFonts();
1363 events.publish('putResources');
1364 newObjectDeferredBegin(resourceDictionaryObjId, true);
1365 out('<<');
1366 putResourceDictionary();
1367 out('>>');
1368 out('endobj');
1369 events.publish('postPutResources');
1370 };
1371
1372 var putAdditionalObjects = function putAdditionalObjects() {
1373 events.publish('putAdditionalObjects');
1374
1375 for (var i = 0; i < additionalObjects.length; i++) {
1376 var obj = additionalObjects[i];
1377 newObjectDeferredBegin(obj.objId, true);
1378 out(obj.content);
1379 out('endobj');
1380 }
1381
1382 events.publish('postPutAdditionalObjects');
1383 };
1384
1385 var addToFontDictionary = function addToFontDictionary(fontKey, fontName, fontStyle) {
1386 // this is mapping structure for quick font key lookup.
1387 // returns the KEY of the font (ex: "F1") for a given
1388 // pair of font name and type (ex: "Arial". "Italic")
1389 if (!fontmap.hasOwnProperty(fontName)) {
1390 fontmap[fontName] = {};
1391 }
1392
1393 fontmap[fontName][fontStyle] = fontKey;
1394 };
1395
1396 var addFont = function addFont(postScriptName, fontName, fontStyle, encoding, isStandardFont) {
1397 isStandardFont = isStandardFont || false;
1398 var fontKey = 'F' + (Object.keys(fonts).length + 1).toString(10),
1399 // This is FontObject
1400 font = {
1401 'id': fontKey,
1402 'postScriptName': postScriptName,
1403 'fontName': fontName,
1404 'fontStyle': fontStyle,
1405 'encoding': encoding,
1406 'isStandardFont': isStandardFont,
1407 'metadata': {}
1408 };
1409 var instance = this;
1410 events.publish('addFont', {
1411 font: font,
1412 instance: instance
1413 });
1414
1415 if (fontKey !== undefined) {
1416 fonts[fontKey] = font;
1417 addToFontDictionary(fontKey, fontName, fontStyle);
1418 }
1419
1420 return fontKey;
1421 };
1422
1423 var addFonts = function addFonts(arrayOfFonts) {
1424 for (var i = 0, l = standardFonts.length; i < l; i++) {
1425 var fontKey = addFont(arrayOfFonts[i][0], arrayOfFonts[i][1], arrayOfFonts[i][2], standardFonts[i][3], true);
1426 usedFonts[fontKey] = true; // adding aliases for standard fonts, this time matching the capitalization
1427
1428 var parts = arrayOfFonts[i][0].split('-');
1429 addToFontDictionary(fontKey, parts[0], parts[1] || '');
1430 }
1431
1432 events.publish('addFonts', {
1433 fonts: fonts,
1434 dictionary: fontmap
1435 });
1436 };
1437
1438 var SAFE = function __safeCall(fn) {
1439 fn.foo = function __safeCallWrapper() {
1440 try {
1441 return fn.apply(this, arguments);
1442 } catch (e) {
1443 var stack = e.stack || '';
1444 if (~stack.indexOf(' at ')) stack = stack.split(" at ")[1];
1445 var m = "Error in function " + stack.split("\n")[0].split('<')[0] + ": " + e.message;
1446
1447 if (global.console) {
1448 global.console.error(m, e);
1449 if (global.alert) alert(m);
1450 } else {
1451 throw new Error(m);
1452 }
1453 }
1454 };
1455
1456 fn.foo.bar = fn;
1457 return fn.foo;
1458 };
1459
1460 var to8bitStream = function to8bitStream(text, flags) {
1461 /**
1462 * PDF 1.3 spec:
1463 * "For text strings encoded in Unicode, the first two bytes must be 254 followed by
1464 * 255, representing the Unicode byte order marker, U+FEFF. (This sequence conflicts
1465 * with the PDFDocEncoding character sequence thorn ydieresis, which is unlikely
1466 * to be a meaningful beginning of a word or phrase.) The remainder of the
1467 * string consists of Unicode character codes, according to the UTF-16 encoding
1468 * specified in the Unicode standard, version 2.0. Commonly used Unicode values
1469 * are represented as 2 bytes per character, with the high-order byte appearing first
1470 * in the string."
1471 *
1472 * In other words, if there are chars in a string with char code above 255, we
1473 * recode the string to UCS2 BE - string doubles in length and BOM is prepended.
1474 *
1475 * HOWEVER!
1476 * Actual *content* (body) text (as opposed to strings used in document properties etc)
1477 * does NOT expect BOM. There, it is treated as a literal GID (Glyph ID)
1478 *
1479 * Because of Adobe's focus on "you subset your fonts!" you are not supposed to have
1480 * a font that maps directly Unicode (UCS2 / UTF16BE) code to font GID, but you could
1481 * fudge it with "Identity-H" encoding and custom CIDtoGID map that mimics Unicode
1482 * code page. There, however, all characters in the stream are treated as GIDs,
1483 * including BOM, which is the reason we need to skip BOM in content text (i.e. that
1484 * that is tied to a font).
1485 *
1486 * To signal this "special" PDFEscape / to8bitStream handling mode,
1487 * API.text() function sets (unless you overwrite it with manual values
1488 * given to API.text(.., flags) )
1489 * flags.autoencode = true
1490 * flags.noBOM = true
1491 *
1492 * ===================================================================================
1493 * `flags` properties relied upon:
1494 * .sourceEncoding = string with encoding label.
1495 * "Unicode" by default. = encoding of the incoming text.
1496 * pass some non-existing encoding name
1497 * (ex: 'Do not touch my strings! I know what I am doing.')
1498 * to make encoding code skip the encoding step.
1499 * .outputEncoding = Either valid PDF encoding name
1500 * (must be supported by jsPDF font metrics, otherwise no encoding)
1501 * or a JS object, where key = sourceCharCode, value = outputCharCode
1502 * missing keys will be treated as: sourceCharCode === outputCharCode
1503 * .noBOM
1504 * See comment higher above for explanation for why this is important
1505 * .autoencode
1506 * See comment higher above for explanation for why this is important
1507 */
1508 var i, l, sourceEncoding, encodingBlock, outputEncoding, newtext, isUnicode, ch, bch;
1509 flags = flags || {};
1510 sourceEncoding = flags.sourceEncoding || 'Unicode';
1511 outputEncoding = flags.outputEncoding; // This 'encoding' section relies on font metrics format
1512 // attached to font objects by, among others,
1513 // "Willow Systems' standard_font_metrics plugin"
1514 // see jspdf.plugin.standard_font_metrics.js for format
1515 // of the font.metadata.encoding Object.
1516 // It should be something like
1517 // .encoding = {'codePages':['WinANSI....'], 'WinANSI...':{code:code, ...}}
1518 // .widths = {0:width, code:width, ..., 'fof':divisor}
1519 // .kerning = {code:{previous_char_code:shift, ..., 'fof':-divisor},...}
1520
1521 if ((flags.autoencode || outputEncoding) && fonts[activeFontKey].metadata && fonts[activeFontKey].metadata[sourceEncoding] && fonts[activeFontKey].metadata[sourceEncoding].encoding) {
1522 encodingBlock = fonts[activeFontKey].metadata[sourceEncoding].encoding; // each font has default encoding. Some have it clearly defined.
1523
1524 if (!outputEncoding && fonts[activeFontKey].encoding) {
1525 outputEncoding = fonts[activeFontKey].encoding;
1526 } // Hmmm, the above did not work? Let's try again, in different place.
1527
1528
1529 if (!outputEncoding && encodingBlock.codePages) {
1530 outputEncoding = encodingBlock.codePages[0]; // let's say, first one is the default
1531 }
1532
1533 if (typeof outputEncoding === 'string') {
1534 outputEncoding = encodingBlock[outputEncoding];
1535 } // we want output encoding to be a JS Object, where
1536 // key = sourceEncoding's character code and
1537 // value = outputEncoding's character code.
1538
1539
1540 if (outputEncoding) {
1541 isUnicode = false;
1542 newtext = [];
1543
1544 for (i = 0, l = text.length; i < l; i++) {
1545 ch = outputEncoding[text.charCodeAt(i)];
1546
1547 if (ch) {
1548 newtext.push(String.fromCharCode(ch));
1549 } else {
1550 newtext.push(text[i]);
1551 } // since we are looping over chars anyway, might as well
1552 // check for residual unicodeness
1553
1554
1555 if (newtext[i].charCodeAt(0) >> 8) {
1556 /* more than 255 */
1557 isUnicode = true;
1558 }
1559 }
1560
1561 text = newtext.join('');
1562 }
1563 }
1564
1565 i = text.length; // isUnicode may be set to false above. Hence the triple-equal to undefined
1566
1567 while (isUnicode === undefined && i !== 0) {
1568 if (text.charCodeAt(i - 1) >> 8) {
1569 /* more than 255 */
1570 isUnicode = true;
1571 }
1572
1573 i--;
1574 }
1575
1576 if (!isUnicode) {
1577 return text;
1578 }
1579
1580 newtext = flags.noBOM ? [] : [254, 255];
1581
1582 for (i = 0, l = text.length; i < l; i++) {
1583 ch = text.charCodeAt(i);
1584 bch = ch >> 8; // divide by 256
1585
1586 if (bch >> 8) {
1587 /* something left after dividing by 256 second time */
1588 throw new Error("Character at position " + i + " of string '" + text + "' exceeds 16bits. Cannot be encoded into UCS-2 BE");
1589 }
1590
1591 newtext.push(bch);
1592 newtext.push(ch - (bch << 8));
1593 }
1594
1595 return String.fromCharCode.apply(undefined, newtext);
1596 };
1597
1598 var pdfEscape = API.__private__.pdfEscape = API.pdfEscape = function (text, flags) {
1599 /**
1600 * Replace '/', '(', and ')' with pdf-safe versions
1601 *
1602 * Doing to8bitStream does NOT make this PDF display unicode text. For that
1603 * we also need to reference a unicode font and embed it - royal pain in the rear.
1604 *
1605 * There is still a benefit to to8bitStream - PDF simply cannot handle 16bit chars,
1606 * which JavaScript Strings are happy to provide. So, while we still cannot display
1607 * 2-byte characters property, at least CONDITIONALLY converting (entire string containing)
1608 * 16bit chars to (USC-2-BE) 2-bytes per char + BOM streams we ensure that entire PDF
1609 * is still parseable.
1610 * This will allow immediate support for unicode in document properties strings.
1611 */
1612 return to8bitStream(text, flags).replace(/\\/g, '\\\\').replace(/\(/g, '\\(').replace(/\)/g, '\\)');
1613 };
1614
1615 var beginPage = API.__private__.beginPage = function (width, height) {
1616 var tmp; // Dimensions are stored as user units and converted to points on output
1617
1618 var orientation = typeof height === 'string' && height.toLowerCase();
1619
1620 if (typeof width === 'string') {
1621 if (tmp = getPageFormat(width.toLowerCase())) {
1622 width = tmp[0];
1623 height = tmp[1];
1624 }
1625 }
1626
1627 if (Array.isArray(width)) {
1628 height = width[1];
1629 width = width[0];
1630 }
1631
1632 if (isNaN(width) || isNaN(height)) {
1633 width = format[0];
1634 height = format[1];
1635 }
1636
1637 if (orientation) {
1638 switch (orientation.substr(0, 1)) {
1639 case 'l':
1640 if (height > width) orientation = 's';
1641 break;
1642
1643 case 'p':
1644 if (width > height) orientation = 's';
1645 break;
1646 }
1647
1648 if (orientation === 's') {
1649 tmp = width;
1650 width = height;
1651 height = tmp;
1652 }
1653 }
1654
1655 if (width > 14400 || height > 14400) {
1656 console.warn('A page in a PDF can not be wider or taller than 14400 userUnit. jsPDF limits the width/height to 14400');
1657 width = Math.min(14400, width);
1658 height = Math.min(14400, height);
1659 }
1660
1661 format = [width, height];
1662 outToPages = true;
1663 pages[++page] = [];
1664 pagesContext[page] = {
1665 objId: 0,
1666 contentsObjId: 0,
1667 userUnit: Number(userUnit),
1668 artBox: null,
1669 bleedBox: null,
1670 cropBox: null,
1671 trimBox: null,
1672 mediaBox: {
1673 bottomLeftX: 0,
1674 bottomLeftY: 0,
1675 topRightX: Number(width),
1676 topRightY: Number(height)
1677 }
1678 };
1679
1680 _setPage(page);
1681 };
1682
1683 var _addPage = function _addPage() {
1684 beginPage.apply(this, arguments); // Set line width
1685
1686 setLineWidth(lineWidth); // Set draw color
1687
1688 out(strokeColor); // resurrecting non-default line caps, joins
1689
1690 if (lineCapID !== 0) {
1691 out(lineCapID + ' J');
1692 }
1693
1694 if (lineJoinID !== 0) {
1695 out(lineJoinID + ' j');
1696 }
1697
1698 events.publish('addPage', {
1699 pageNumber: page
1700 });
1701 };
1702
1703 var _deletePage = function _deletePage(n) {
1704 if (n > 0 && n <= page) {
1705 pages.splice(n, 1);
1706 page--;
1707
1708 if (currentPage > page) {
1709 currentPage = page;
1710 }
1711
1712 this.setPage(currentPage);
1713 }
1714 };
1715
1716 var _setPage = function _setPage(n) {
1717 if (n > 0 && n <= page) {
1718 currentPage = n;
1719 }
1720 };
1721
1722 var getNumberOfPages = API.__private__.getNumberOfPages = API.getNumberOfPages = function () {
1723 return pages.length - 1;
1724 };
1725 /**
1726 * Returns a document-specific font key - a label assigned to a
1727 * font name + font type combination at the time the font was added
1728 * to the font inventory.
1729 *
1730 * Font key is used as label for the desired font for a block of text
1731 * to be added to the PDF document stream.
1732 * @private
1733 * @function
1734 * @param fontName {string} can be undefined on "falthy" to indicate "use current"
1735 * @param fontStyle {string} can be undefined on "falthy" to indicate "use current"
1736 * @returns {string} Font key.
1737 * @ignore
1738 */
1739
1740
1741 var _getFont = function getFont(fontName, fontStyle, options) {
1742 var key = undefined,
1743 fontNameLowerCase;
1744 options = options || {};
1745 fontName = fontName !== undefined ? fontName : fonts[activeFontKey].fontName;
1746 fontStyle = fontStyle !== undefined ? fontStyle : fonts[activeFontKey].fontStyle;
1747 fontNameLowerCase = fontName.toLowerCase();
1748
1749 if (fontmap[fontNameLowerCase] !== undefined && fontmap[fontNameLowerCase][fontStyle] !== undefined) {
1750 key = fontmap[fontNameLowerCase][fontStyle];
1751 } else if (fontmap[fontName] !== undefined && fontmap[fontName][fontStyle] !== undefined) {
1752 key = fontmap[fontName][fontStyle];
1753 } else {
1754 if (options.disableWarning === false) {
1755 console.warn("Unable to look up font label for font '" + fontName + "', '" + fontStyle + "'. Refer to getFontList() for available fonts.");
1756 }
1757 }
1758
1759 if (!key && !options.noFallback) {
1760 key = fontmap['times'][fontStyle];
1761
1762 if (key == null) {
1763 key = fontmap['times']['normal'];
1764 }
1765 }
1766
1767 return key;
1768 };
1769
1770 var putInfo = API.__private__.putInfo = function () {
1771 newObject();
1772 out('<<');
1773 out('/Producer (jsPDF ' + jsPDF.version + ')');
1774
1775 for (var key in documentProperties) {
1776 if (documentProperties.hasOwnProperty(key) && documentProperties[key]) {
1777 out('/' + key.substr(0, 1).toUpperCase() + key.substr(1) + ' (' + pdfEscape(documentProperties[key]) + ')');
1778 }
1779 }
1780
1781 out('/CreationDate (' + creationDate + ')');
1782 out('>>');
1783 out('endobj');
1784 };
1785
1786 var putCatalog = API.__private__.putCatalog = function (options) {
1787 options = options || {};
1788 var tmpRootDictionaryObjId = options.rootDictionaryObjId || rootDictionaryObjId;
1789 newObject();
1790 out('<<');
1791 out('/Type /Catalog');
1792 out('/Pages ' + tmpRootDictionaryObjId + ' 0 R'); // PDF13ref Section 7.2.1
1793
1794 if (!zoomMode) zoomMode = 'fullwidth';
1795
1796 switch (zoomMode) {
1797 case 'fullwidth':
1798 out('/OpenAction [3 0 R /FitH null]');
1799 break;
1800
1801 case 'fullheight':
1802 out('/OpenAction [3 0 R /FitV null]');
1803 break;
1804
1805 case 'fullpage':
1806 out('/OpenAction [3 0 R /Fit]');
1807 break;
1808
1809 case 'original':
1810 out('/OpenAction [3 0 R /XYZ null null 1]');
1811 break;
1812
1813 default:
1814 var pcn = '' + zoomMode;
1815 if (pcn.substr(pcn.length - 1) === '%') zoomMode = parseInt(zoomMode) / 100;
1816
1817 if (typeof zoomMode === 'number') {
1818 out('/OpenAction [3 0 R /XYZ null null ' + f2(zoomMode) + ']');
1819 }
1820
1821 }
1822
1823 if (!layoutMode) layoutMode = 'continuous';
1824
1825 switch (layoutMode) {
1826 case 'continuous':
1827 out('/PageLayout /OneColumn');
1828 break;
1829
1830 case 'single':
1831 out('/PageLayout /SinglePage');
1832 break;
1833
1834 case 'two':
1835 case 'twoleft':
1836 out('/PageLayout /TwoColumnLeft');
1837 break;
1838
1839 case 'tworight':
1840 out('/PageLayout /TwoColumnRight');
1841 break;
1842 }
1843
1844 if (pageMode) {
1845 /**
1846 * A name object specifying how the document should be displayed when opened:
1847 * UseNone : Neither document outline nor thumbnail images visible -- DEFAULT
1848 * UseOutlines : Document outline visible
1849 * UseThumbs : Thumbnail images visible
1850 * FullScreen : Full-screen mode, with no menu bar, window controls, or any other window visible
1851 */
1852 out('/PageMode /' + pageMode);
1853 }
1854
1855 events.publish('putCatalog');
1856 out('>>');
1857 out('endobj');
1858 };
1859
1860 var putTrailer = API.__private__.putTrailer = function () {
1861 out('trailer');
1862 out('<<');
1863 out('/Size ' + (objectNumber + 1));
1864 out('/Root ' + objectNumber + ' 0 R');
1865 out('/Info ' + (objectNumber - 1) + ' 0 R');
1866 out("/ID [ <" + fileId + "> <" + fileId + "> ]");
1867 out('>>');
1868 };
1869
1870 var putHeader = API.__private__.putHeader = function () {
1871 out('%PDF-' + pdfVersion);
1872 out("%\xBA\xDF\xAC\xE0");
1873 };
1874
1875 var putXRef = API.__private__.putXRef = function () {
1876 var i = 1;
1877 var p = "0000000000";
1878 out('xref');
1879 out('0 ' + (objectNumber + 1));
1880 out('0000000000 65535 f ');
1881
1882 for (i = 1; i <= objectNumber; i++) {
1883 var offset = offsets[i];
1884
1885 if (typeof offset === 'function') {
1886 out((p + offsets[i]()).slice(-10) + ' 00000 n ');
1887 } else {
1888 if (typeof offsets[i] !== "undefined") {
1889 out((p + offsets[i]).slice(-10) + ' 00000 n ');
1890 } else {
1891 out('0000000000 00000 n ');
1892 }
1893 }
1894 }
1895 };
1896
1897 var buildDocument = API.__private__.buildDocument = function () {
1898 outToPages = false; // switches out() to content
1899 //reset fields relevant for objectNumber generation and xref.
1900
1901 objectNumber = 0;
1902 content_length = 0;
1903 content = [];
1904 offsets = [];
1905 additionalObjects = [];
1906 rootDictionaryObjId = newObjectDeferred();
1907 resourceDictionaryObjId = newObjectDeferred();
1908 events.publish('buildDocument');
1909 putHeader();
1910 putPages();
1911 putAdditionalObjects();
1912 putResources();
1913 putInfo();
1914 putCatalog();
1915 var offsetOfXRef = content_length;
1916 putXRef();
1917 putTrailer();
1918 out('startxref');
1919 out('' + offsetOfXRef);
1920 out('%%EOF');
1921 outToPages = true;
1922 return content.join('\n');
1923 };
1924
1925 var getBlob = API.__private__.getBlob = function (data) {
1926 return new Blob([getArrayBuffer(data)], {
1927 type: "application/pdf"
1928 });
1929 };
1930 /**
1931 * Generates the PDF document.
1932 *
1933 * If `type` argument is undefined, output is raw body of resulting PDF returned as a string.
1934 *
1935 * @param {string} type A string identifying one of the possible output types. Possible values are 'arraybuffer', 'blob', 'bloburi'/'bloburl', 'datauristring'/'dataurlstring', 'datauri'/'dataurl', 'dataurlnewwindow'.
1936 * @param {Object} options An object providing some additional signalling to PDF generator. Possible options are 'filename'.
1937 *
1938 * @function
1939 * @instance
1940 * @returns {jsPDF}
1941 * @memberOf jsPDF
1942 * @name output
1943 */
1944
1945
1946 var output = API.output = API.__private__.output = SAFE(function output(type, options) {
1947 options = options || {};
1948 var pdfDocument = buildDocument();
1949
1950 if (typeof options === "string") {
1951 options = {
1952 filename: options
1953 };
1954 } else {
1955 options.filename = options.filename || 'generated.pdf';
1956 }
1957
1958 switch (type) {
1959 case undefined:
1960 return pdfDocument;
1961
1962 case 'save':
1963 API.save(options.filename);
1964 break;
1965
1966 case 'arraybuffer':
1967 return getArrayBuffer(pdfDocument);
1968
1969 case 'blob':
1970 return getBlob(pdfDocument);
1971
1972 case 'bloburi':
1973 case 'bloburl':
1974 // Developer is responsible of calling revokeObjectURL
1975 if (typeof global.URL !== "undefined" && typeof global.URL.createObjectURL === "function") {
1976 return global.URL && global.URL.createObjectURL(getBlob(pdfDocument)) || void 0;
1977 } else {
1978 console.warn('bloburl is not supported by your system, because URL.createObjectURL is not supported by your browser.');
1979 }
1980
1981 break;
1982
1983 case 'datauristring':
1984 case 'dataurlstring':
1985 return 'data:application/pdf;filename=' + options.filename + ';base64,' + btoa(pdfDocument);
1986
1987 case 'dataurlnewwindow':
1988 var htmlForNewWindow = '<html>' + '<style>html, body { padding: 0; margin: 0; } iframe { width: 100%; height: 100%; border: 0;} </style>' + '<body>' + '<iframe src="' + this.output('datauristring') + '"></iframe>' + '</body></html>';
1989 var nW = global.open();
1990
1991 if (nW !== null) {
1992 nW.document.write(htmlForNewWindow);
1993 }
1994
1995 if (nW || typeof safari === "undefined") return nW;
1996
1997 /* pass through */
1998
1999 case 'datauri':
2000 case 'dataurl':
2001 return global.document.location.href = 'data:application/pdf;filename=' + options.filename + ';base64,' + btoa(pdfDocument);
2002
2003 default:
2004 return null;
2005 }
2006 });
2007 /**
2008 * Used to see if a supplied hotfix was requested when the pdf instance was created.
2009 * @param {string} hotfixName - The name of the hotfix to check.
2010 * @returns {boolean}
2011 */
2012
2013 var hasHotfix = function hasHotfix(hotfixName) {
2014 return Array.isArray(hotfixes) === true && hotfixes.indexOf(hotfixName) > -1;
2015 };
2016
2017 switch (unit) {
2018 case 'pt':
2019 k = 1;
2020 break;
2021
2022 case 'mm':
2023 k = 72 / 25.4;
2024 break;
2025
2026 case 'cm':
2027 k = 72 / 2.54;
2028 break;
2029
2030 case 'in':
2031 k = 72;
2032 break;
2033
2034 case 'px':
2035 if (hasHotfix('px_scaling') == true) {
2036 k = 72 / 96;
2037 } else {
2038 k = 96 / 72;
2039 }
2040
2041 break;
2042
2043 case 'pc':
2044 k = 12;
2045 break;
2046
2047 case 'em':
2048 k = 12;
2049 break;
2050
2051 case 'ex':
2052 k = 6;
2053 break;
2054
2055 default:
2056 throw new Error('Invalid unit: ' + unit);
2057 }
2058
2059 setCreationDate();
2060 setFileId(); //---------------------------------------
2061 // Public API
2062
2063 var getPageInfo = API.__private__.getPageInfo = function (pageNumberOneBased) {
2064 if (isNaN(pageNumberOneBased) || pageNumberOneBased % 1 !== 0) {
2065 throw new Error('Invalid argument passed to jsPDF.getPageInfo');
2066 }
2067
2068 var objId = pagesContext[pageNumberOneBased].objId;
2069 return {
2070 objId: objId,
2071 pageNumber: pageNumberOneBased,
2072 pageContext: pagesContext[pageNumberOneBased]
2073 };
2074 };
2075
2076 var getPageInfoByObjId = API.__private__.getPageInfoByObjId = function (objId) {
2077
2078 for (var pageNumber in pagesContext) {
2079 if (pagesContext[pageNumber].objId === objId) {
2080 break;
2081 }
2082 }
2083
2084 if (isNaN(objId) || objId % 1 !== 0) {
2085 throw new Error('Invalid argument passed to jsPDF.getPageInfoByObjId');
2086 }
2087
2088 return getPageInfo(pageNumber);
2089 };
2090
2091 var getCurrentPageInfo = API.__private__.getCurrentPageInfo = function () {
2092 return {
2093 objId: pagesContext[currentPage].objId,
2094 pageNumber: currentPage,
2095 pageContext: pagesContext[currentPage]
2096 };
2097 };
2098 /**
2099 * Adds (and transfers the focus to) new page to the PDF document.
2100 * @param format {String/Array} The format of the new 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 />
2101 * 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]
2102 * @param orientation {string} Orientation of the new page. Possible values are "portrait" or "landscape" (or shortcuts "p" (Default), "l").
2103 * @function
2104 * @instance
2105 * @returns {jsPDF}
2106 *
2107 * @memberOf jsPDF
2108 * @name addPage
2109 */
2110
2111
2112 API.addPage = function () {
2113 _addPage.apply(this, arguments);
2114
2115 return this;
2116 };
2117 /**
2118 * Adds (and transfers the focus to) new page to the PDF document.
2119 * @function
2120 * @instance
2121 * @returns {jsPDF}
2122 *
2123 * @memberOf jsPDF
2124 * @name setPage
2125 * @param {number} page Switch the active page to the page number specified.
2126 * @example
2127 * doc = jsPDF()
2128 * doc.addPage()
2129 * doc.addPage()
2130 * doc.text('I am on page 3', 10, 10)
2131 * doc.setPage(1)
2132 * doc.text('I am on page 1', 10, 10)
2133 */
2134
2135
2136 API.setPage = function () {
2137 _setPage.apply(this, arguments);
2138
2139 return this;
2140 };
2141 /**
2142 * @name insertPage
2143 * @memberOf jsPDF
2144 *
2145 * @function
2146 * @instance
2147 * @param {Object} beforePage
2148 * @returns {jsPDF}
2149 */
2150
2151
2152 API.insertPage = function (beforePage) {
2153 this.addPage();
2154 this.movePage(currentPage, beforePage);
2155 return this;
2156 };
2157 /**
2158 * @name movePage
2159 * @memberOf jsPDF
2160 * @function
2161 * @instance
2162 * @param {Object} targetPage
2163 * @param {Object} beforePage
2164 * @returns {jsPDF}
2165 */
2166
2167
2168 API.movePage = function (targetPage, beforePage) {
2169 if (targetPage > beforePage) {
2170 var tmpPages = pages[targetPage];
2171 var tmpPagesContext = pagesContext[targetPage];
2172
2173 for (var i = targetPage; i > beforePage; i--) {
2174 pages[i] = pages[i - 1];
2175 pagesContext[i] = pagesContext[i - 1];
2176 }
2177
2178 pages[beforePage] = tmpPages;
2179 pagesContext[beforePage] = tmpPagesContext;
2180 this.setPage(beforePage);
2181 } else if (targetPage < beforePage) {
2182 var tmpPages = pages[targetPage];
2183 var tmpPagesContext = pagesContext[targetPage];
2184
2185 for (var i = targetPage; i < beforePage; i++) {
2186 pages[i] = pages[i + 1];
2187 pagesContext[i] = pagesContext[i + 1];
2188 }
2189
2190 pages[beforePage] = tmpPages;
2191 pagesContext[beforePage] = tmpPagesContext;
2192 this.setPage(beforePage);
2193 }
2194
2195 return this;
2196 };
2197 /**
2198 * Deletes a page from the PDF.
2199 * @name deletePage
2200 * @memberOf jsPDF
2201 * @function
2202 * @instance
2203 * @returns {jsPDF}
2204 */
2205
2206
2207 API.deletePage = function () {
2208 _deletePage.apply(this, arguments);
2209
2210 return this;
2211 };
2212 /**
2213 * Adds text to page. Supports adding multiline text when 'text' argument is an Array of Strings.
2214 *
2215 * @function
2216 * @instance
2217 * @param {String|Array} text String or array of strings to be added to the page. Each line is shifted one line down per font, spacing settings declared before this call.
2218 * @param {number} x Coordinate (in units declared at inception of PDF document) against left edge of the page.
2219 * @param {number} y Coordinate (in units declared at inception of PDF document) against upper edge of the page.
2220 * @param {Object} [options] - Collection of settings signaling how the text must be encoded.
2221 * @param {string} [options.align=left] - The alignment of the text, possible values: left, center, right, justify.
2222 * @param {string} [options.baseline=alphabetic] - Sets text baseline used when drawing the text, possible values: alphabetic, ideographic, bottom, top, middle.
2223 * @param {string} [options.angle=0] - Rotate the text counterclockwise. Expects the angle in degree.
2224 * @param {string} [options.charSpace=0] - The space between each letter.
2225 * @param {string} [options.lineHeightFactor=1.15] - The lineheight of each line.
2226 * @param {string} [options.flags] - Flags for to8bitStream.
2227 * @param {string} [options.flags.noBOM=true] - Don't add BOM to Unicode-text.
2228 * @param {string} [options.flags.autoencode=true] - Autoencode the Text.
2229 * @param {string} [options.maxWidth=0] - Split the text by given width, 0 = no split.
2230 * @param {string} [options.renderingMode=fill] - Set how the text should be rendered, possible values: fill, stroke, fillThenStroke, invisible, fillAndAddForClipping, strokeAndAddPathForClipping, fillThenStrokeAndAddToPathForClipping, addToPathForClipping.
2231 * @returns {jsPDF}
2232 * @memberOf jsPDF
2233 * @name text
2234 */
2235
2236
2237 var text = API.__private__.text = API.text = function (text, x, y, options) {
2238 /**
2239 * Inserts something like this into PDF
2240 * BT
2241 * /F1 16 Tf % Font name + size
2242 * 16 TL % How many units down for next line in multiline text
2243 * 0 g % color
2244 * 28.35 813.54 Td % position
2245 * (line one) Tj
2246 * T* (line two) Tj
2247 * T* (line three) Tj
2248 * ET
2249 */
2250 //backwardsCompatibility
2251 var tmp; // Pre-August-2012 the order of arguments was function(x, y, text, flags)
2252 // in effort to make all calls have similar signature like
2253 // function(data, coordinates... , miscellaneous)
2254 // this method had its args flipped.
2255 // code below allows backward compatibility with old arg order.
2256
2257 if (typeof text === 'number' && typeof x === 'number' && (typeof y === 'string' || Array.isArray(y))) {
2258 tmp = y;
2259 y = x;
2260 x = text;
2261 text = tmp;
2262 }
2263
2264 var flags = arguments[3];
2265 var angle = arguments[4];
2266 var align = arguments[5];
2267
2268 if (_typeof(flags) !== "object" || flags === null) {
2269 if (typeof angle === 'string') {
2270 align = angle;
2271 angle = null;
2272 }
2273
2274 if (typeof flags === 'string') {
2275 align = flags;
2276 flags = null;
2277 }
2278
2279 if (typeof flags === 'number') {
2280 angle = flags;
2281 flags = null;
2282 }
2283
2284 options = {
2285 flags: flags,
2286 angle: angle,
2287 align: align
2288 };
2289 }
2290
2291 flags = flags || {};
2292 flags.noBOM = flags.noBOM || true;
2293 flags.autoencode = flags.autoencode || true;
2294
2295 if (isNaN(x) || isNaN(y) || typeof text === "undefined" || text === null) {
2296 throw new Error('Invalid arguments passed to jsPDF.text');
2297 }
2298
2299 if (text.length === 0) {
2300 return scope;
2301 }
2302
2303 var xtra = '';
2304 var isHex = false;
2305 var lineHeight = typeof options.lineHeightFactor === 'number' ? options.lineHeightFactor : lineHeightFactor;
2306 var scope = options.scope || this;
2307
2308 function ESC(s) {
2309 s = s.split("\t").join(Array(options.TabLen || 9).join(" "));
2310 return pdfEscape(s, flags);
2311 }
2312
2313 function transformTextToSpecialArray(text) {
2314 //we don't want to destroy original text array, so cloning it
2315 var sa = text.concat();
2316 var da = [];
2317 var len = sa.length;
2318 var curDa; //we do array.join('text that must not be PDFescaped")
2319 //thus, pdfEscape each component separately
2320
2321 while (len--) {
2322 curDa = sa.shift();
2323
2324 if (typeof curDa === "string") {
2325 da.push(curDa);
2326 } else {
2327 if (Array.isArray(text) && curDa.length === 1) {
2328 da.push(curDa[0]);
2329 } else {
2330 da.push([curDa[0], curDa[1], curDa[2]]);
2331 }
2332 }
2333 }
2334
2335 return da;
2336 }
2337
2338 function processTextByFunction(text, processingFunction) {
2339 var result;
2340
2341 if (typeof text === 'string') {
2342 result = processingFunction(text)[0];
2343 } else if (Array.isArray(text)) {
2344 //we don't want to destroy original text array, so cloning it
2345 var sa = text.concat();
2346 var da = [];
2347 var len = sa.length;
2348 var curDa;
2349 var tmpResult; //we do array.join('text that must not be PDFescaped")
2350 //thus, pdfEscape each component separately
2351
2352 while (len--) {
2353 curDa = sa.shift();
2354
2355 if (typeof curDa === "string") {
2356 da.push(processingFunction(curDa)[0]);
2357 } else if (Array.isArray(curDa) && curDa[0] === "string") {
2358 tmpResult = processingFunction(curDa[0], curDa[1], curDa[2]);
2359 da.push([tmpResult[0], tmpResult[1], tmpResult[2]]);
2360 }
2361 }
2362
2363 result = da;
2364 }
2365
2366 return result;
2367 } //Check if text is of type String
2368
2369
2370 var textIsOfTypeString = false;
2371 var tmpTextIsOfTypeString = true;
2372
2373 if (typeof text === 'string') {
2374 textIsOfTypeString = true;
2375 } else if (Array.isArray(text)) {
2376 //we don't want to destroy original text array, so cloning it
2377 var sa = text.concat();
2378 var da = [];
2379 var len = sa.length;
2380 var curDa; //we do array.join('text that must not be PDFescaped")
2381 //thus, pdfEscape each component separately
2382
2383 while (len--) {
2384 curDa = sa.shift();
2385
2386 if (typeof curDa !== "string" || Array.isArray(curDa) && typeof curDa[0] !== "string") {
2387 tmpTextIsOfTypeString = false;
2388 }
2389 }
2390
2391 textIsOfTypeString = tmpTextIsOfTypeString;
2392 }
2393
2394 if (textIsOfTypeString === false) {
2395 throw new Error('Type of text must be string or Array. "' + text + '" is not recognized.');
2396 } //Escaping
2397
2398
2399 var activeFontEncoding = fonts[activeFontKey].encoding;
2400
2401 if (activeFontEncoding === "WinAnsiEncoding" || activeFontEncoding === "StandardEncoding") {
2402 text = processTextByFunction(text, function (text, posX, posY) {
2403 return [ESC(text), posX, posY];
2404 });
2405 } //If there are any newlines in text, we assume
2406 //the user wanted to print multiple lines, so break the
2407 //text up into an array. If the text is already an array,
2408 //we assume the user knows what they are doing.
2409 //Convert text into an array anyway to simplify
2410 //later code.
2411
2412
2413 if (typeof text === 'string') {
2414 if (text.match(/[\r?\n]/)) {
2415 text = text.split(/\r\n|\r|\n/g);
2416 } else {
2417 text = [text];
2418 }
2419 } //baseline
2420
2421
2422 var height = activeFontSize / scope.internal.scaleFactor;
2423 var descent = height * (lineHeightFactor - 1);
2424
2425 switch (options.baseline) {
2426 case 'bottom':
2427 y -= descent;
2428 break;
2429
2430 case 'top':
2431 y += height - descent;
2432 break;
2433
2434 case 'hanging':
2435 y += height - 2 * descent;
2436 break;
2437
2438 case 'middle':
2439 y += height / 2 - descent;
2440 break;
2441
2442 case 'ideographic':
2443 case 'alphabetic':
2444 default:
2445 // do nothing, everything is fine
2446 break;
2447 } //multiline
2448
2449
2450 var maxWidth = options.maxWidth || 0;
2451
2452 if (maxWidth > 0) {
2453 if (typeof text === 'string') {
2454 text = scope.splitTextToSize(text, maxWidth);
2455 } else if (Object.prototype.toString.call(text) === '[object Array]') {
2456 text = scope.splitTextToSize(text.join(" "), maxWidth);
2457 }
2458 } //creating Payload-Object to make text byRef
2459
2460
2461 var payload = {
2462 text: text,
2463 x: x,
2464 y: y,
2465 options: options,
2466 mutex: {
2467 pdfEscape: pdfEscape,
2468 activeFontKey: activeFontKey,
2469 fonts: fonts,
2470 activeFontSize: activeFontSize
2471 }
2472 };
2473 events.publish('preProcessText', payload);
2474 text = payload.text;
2475 options = payload.options; //angle
2476
2477 var angle = options.angle;
2478 var k = scope.internal.scaleFactor;
2479 var transformationMatrix = [];
2480
2481 if (angle) {
2482 angle *= Math.PI / 180;
2483 var c = Math.cos(angle),
2484 s = Math.sin(angle);
2485 transformationMatrix = [f2(c), f2(s), f2(s * -1), f2(c)];
2486 } //charSpace
2487
2488
2489 var charSpace = options.charSpace;
2490
2491 if (typeof charSpace !== 'undefined') {
2492 xtra += f3(charSpace * k) + " Tc\n";
2493 } //lang
2494
2495
2496 var lang = options.lang;
2497 var tmpRenderingMode = -1;
2498 var parmRenderingMode = typeof options.renderingMode !== "undefined" ? options.renderingMode : options.stroke;
2499 var pageContext = scope.internal.getCurrentPageInfo().pageContext;
2500
2501 switch (parmRenderingMode) {
2502 case 0:
2503 case false:
2504 case 'fill':
2505 tmpRenderingMode = 0;
2506 break;
2507
2508 case 1:
2509 case true:
2510 case 'stroke':
2511 tmpRenderingMode = 1;
2512 break;
2513
2514 case 2:
2515 case 'fillThenStroke':
2516 tmpRenderingMode = 2;
2517 break;
2518
2519 case 3:
2520 case 'invisible':
2521 tmpRenderingMode = 3;
2522 break;
2523
2524 case 4:
2525 case 'fillAndAddForClipping':
2526 tmpRenderingMode = 4;
2527 break;
2528
2529 case 5:
2530 case 'strokeAndAddPathForClipping':
2531 tmpRenderingMode = 5;
2532 break;
2533
2534 case 6:
2535 case 'fillThenStrokeAndAddToPathForClipping':
2536 tmpRenderingMode = 6;
2537 break;
2538
2539 case 7:
2540 case 'addToPathForClipping':
2541 tmpRenderingMode = 7;
2542 break;
2543 }
2544
2545 var usedRenderingMode = typeof pageContext.usedRenderingMode !== 'undefined' ? pageContext.usedRenderingMode : -1; //if the coder wrote it explicitly to use a specific
2546 //renderingMode, then use it
2547
2548 if (tmpRenderingMode !== -1) {
2549 xtra += tmpRenderingMode + " Tr\n"; //otherwise check if we used the rendering Mode already
2550 //if so then set the rendering Mode...
2551 } else if (usedRenderingMode !== -1) {
2552 xtra += "0 Tr\n";
2553 }
2554
2555 if (tmpRenderingMode !== -1) {
2556 pageContext.usedRenderingMode = tmpRenderingMode;
2557 } //align
2558
2559
2560 var align = options.align || 'left';
2561 var leading = activeFontSize * lineHeight;
2562 var pageWidth = scope.internal.pageSize.getWidth();
2563 var k = scope.internal.scaleFactor;
2564 var activeFont = fonts[activeFontKey];
2565 var charSpace = options.charSpace || activeCharSpace;
2566 var maxWidth = options.maxWidth || 0;
2567 var lineWidths;
2568 var flags = {};
2569 var wordSpacingPerLine = [];
2570
2571 if (Object.prototype.toString.call(text) === '[object Array]') {
2572 var da = transformTextToSpecialArray(text);
2573 var newY;
2574 var maxLineLength;
2575 var lineWidths;
2576
2577 if (align !== "left") {
2578 lineWidths = da.map(function (v) {
2579 return scope.getStringUnitWidth(v, {
2580 font: activeFont,
2581 charSpace: charSpace,
2582 fontSize: activeFontSize
2583 }) * activeFontSize / k;
2584 });
2585 }
2586
2587 var maxLineLength = Math.max.apply(Math, lineWidths); //The first line uses the "main" Td setting,
2588 //and the subsequent lines are offset by the
2589 //previous line's x coordinate.
2590
2591 var prevWidth = 0;
2592 var delta;
2593 var newX;
2594
2595 if (align === "right") {
2596 x -= lineWidths[0];
2597 text = [];
2598
2599 for (var i = 0, len = da.length; i < len; i++) {
2600 delta = maxLineLength - lineWidths[i];
2601
2602 if (i === 0) {
2603 newX = getHorizontalCoordinate(x);
2604 newY = getVerticalCoordinate(y);
2605 } else {
2606 newX = (prevWidth - lineWidths[i]) * k;
2607 newY = -leading;
2608 }
2609
2610 text.push([da[i], newX, newY]);
2611 prevWidth = lineWidths[i];
2612 }
2613 } else if (align === "center") {
2614 x -= lineWidths[0] / 2;
2615 text = [];
2616
2617 for (var i = 0, len = da.length; i < len; i++) {
2618 delta = (maxLineLength - lineWidths[i]) / 2;
2619
2620 if (i === 0) {
2621 newX = getHorizontalCoordinate(x);
2622 newY = getVerticalCoordinate(y);
2623 } else {
2624 newX = (prevWidth - lineWidths[i]) / 2 * k;
2625 newY = -leading;
2626 }
2627
2628 text.push([da[i], newX, newY]);
2629 prevWidth = lineWidths[i];
2630 }
2631 } else if (align === "left") {
2632 text = [];
2633
2634 for (var i = 0, len = da.length; i < len; i++) {
2635 newY = i === 0 ? getVerticalCoordinate(y) : -leading;
2636 newX = i === 0 ? getHorizontalCoordinate(x) : 0; //text.push([da[i], newX, newY]);
2637
2638 text.push(da[i]);
2639 }
2640 } else if (align === "justify") {
2641 text = [];
2642 var maxWidth = maxWidth !== 0 ? maxWidth : pageWidth;
2643
2644 for (var i = 0, len = da.length; i < len; i++) {
2645 newY = i === 0 ? getVerticalCoordinate(y) : -leading;
2646 newX = i === 0 ? getHorizontalCoordinate(x) : 0;
2647
2648 if (i < len - 1) {
2649 wordSpacingPerLine.push(((maxWidth - lineWidths[i]) / (da[i].split(" ").length - 1) * k).toFixed(2));
2650 }
2651
2652 text.push([da[i], newX, newY]);
2653 }
2654 } else {
2655 throw new Error('Unrecognized alignment option, use "left", "center", "right" or "justify".');
2656 }
2657 } //R2L
2658
2659
2660 var doReversing = typeof options.R2L === "boolean" ? options.R2L : R2L;
2661
2662 if (doReversing === true) {
2663 text = processTextByFunction(text, function (text, posX, posY) {
2664 return [text.split("").reverse().join(""), posX, posY];
2665 });
2666 } //creating Payload-Object to make text byRef
2667
2668
2669 var payload = {
2670 text: text,
2671 x: x,
2672 y: y,
2673 options: options,
2674 mutex: {
2675 pdfEscape: pdfEscape,
2676 activeFontKey: activeFontKey,
2677 fonts: fonts,
2678 activeFontSize: activeFontSize
2679 }
2680 };
2681 events.publish('postProcessText', payload);
2682 text = payload.text;
2683 isHex = payload.mutex.isHex;
2684 var da = transformTextToSpecialArray(text);
2685 text = [];
2686 var variant = 0;
2687 var len = da.length;
2688 var posX;
2689 var posY;
2690 var content;
2691 var wordSpacing = '';
2692
2693 for (var i = 0; i < len; i++) {
2694 wordSpacing = '';
2695
2696 if (!Array.isArray(da[i])) {
2697 posX = getHorizontalCoordinate(x);
2698 posY = getVerticalCoordinate(y);
2699 content = (isHex ? "<" : "(") + da[i] + (isHex ? ">" : ")");
2700 } else {
2701 posX = parseFloat(da[i][1]);
2702 posY = parseFloat(da[i][2]);
2703 content = (isHex ? "<" : "(") + da[i][0] + (isHex ? ">" : ")");
2704 variant = 1;
2705 }
2706
2707 if (wordSpacingPerLine !== undefined && wordSpacingPerLine[i] !== undefined) {
2708 wordSpacing = wordSpacingPerLine[i] + " Tw\n";
2709 }
2710
2711 if (transformationMatrix.length !== 0 && i === 0) {
2712 text.push(wordSpacing + transformationMatrix.join(" ") + " " + posX.toFixed(2) + " " + posY.toFixed(2) + " Tm\n" + content);
2713 } else if (variant === 1 || variant === 0 && i === 0) {
2714 text.push(wordSpacing + posX.toFixed(2) + " " + posY.toFixed(2) + " Td\n" + content);
2715 } else {
2716 text.push(wordSpacing + content);
2717 }
2718 }
2719
2720 if (variant === 0) {
2721 text = text.join(" Tj\nT* ");
2722 } else {
2723 text = text.join(" Tj\n");
2724 }
2725
2726 text += " Tj\n";
2727 var result = 'BT\n/' + activeFontKey + ' ' + activeFontSize + ' Tf\n' + // font face, style, size
2728 (activeFontSize * lineHeight).toFixed(2) + ' TL\n' + // line spacing
2729 textColor + '\n';
2730 result += xtra;
2731 result += text;
2732 result += "ET";
2733 out(result);
2734 usedFonts[activeFontKey] = true;
2735 return scope;
2736 };
2737 /**
2738 * Letter spacing method to print text with gaps
2739 *
2740 * @function
2741 * @instance
2742 * @param {String|Array} text String to be added to the page.
2743 * @param {number} x Coordinate (in units declared at inception of PDF document) against left edge of the page
2744 * @param {number} y Coordinate (in units declared at inception of PDF document) against upper edge of the page
2745 * @param {number} spacing Spacing (in units declared at inception)
2746 * @returns {jsPDF}
2747 * @memberOf jsPDF
2748 * @name lstext
2749 * @deprecated We'll be removing this function. It doesn't take character width into account.
2750 */
2751
2752
2753 var lstext = API.__private__.lstext = API.lstext = function (text, x, y, charSpace) {
2754 console.warn('jsPDF.lstext is deprecated');
2755 return this.text(text, x, y, {
2756 charSpace: charSpace
2757 });
2758 };
2759 /**
2760 *
2761 * @name clip
2762 * @function
2763 * @instance
2764 * @param {string} rule
2765 * @returns {jsPDF}
2766 * @memberOf jsPDF
2767 * @description All .clip() after calling drawing ops with a style argument of null.
2768 */
2769
2770
2771 var clip = API.__private__.clip = API.clip = function (rule) {
2772 // Call .clip() after calling drawing ops with a style argument of null
2773 // W is the PDF clipping op
2774 if ('evenodd' === rule) {
2775 out('W*');
2776 } else {
2777 out('W');
2778 } // End the path object without filling or stroking it.
2779 // This operator is a path-painting no-op, used primarily for the side effect of changing the current clipping path
2780 // (see Section 4.4.3, “Clipping Path Operators”)
2781
2782
2783 out('n');
2784 };
2785 /**
2786 * This fixes the previous function clip(). Perhaps the 'stroke path' hack was due to the missing 'n' instruction?
2787 * We introduce the fixed version so as to not break API.
2788 * @param fillRule
2789 * @ignore
2790 */
2791
2792
2793 var clip_fixed = API.__private__.clip_fixed = API.clip_fixed = function (rule) {
2794 console.log("clip_fixed is deprecated");
2795 API.clip(rule);
2796 };
2797
2798 var isValidStyle = API.__private__.isValidStyle = function (style) {
2799 var validStyleVariants = [undefined, null, 'S', 'F', 'DF', 'FD', 'f', 'f*', 'B', 'B*'];
2800 var result = false;
2801
2802 if (validStyleVariants.indexOf(style) !== -1) {
2803 result = true;
2804 }
2805
2806 return result;
2807 };
2808
2809 var getStyle = API.__private__.getStyle = function (style) {
2810 // see path-painting operators in PDF spec
2811 var op = 'S'; // stroke
2812
2813 if (style === 'F') {
2814 op = 'f'; // fill
2815 } else if (style === 'FD' || style === 'DF') {
2816 op = 'B'; // both
2817 } else if (style === 'f' || style === 'f*' || style === 'B' || style === 'B*') {
2818 /*
2819 Allow direct use of these PDF path-painting operators:
2820 - f fill using nonzero winding number rule
2821 - f* fill using even-odd rule
2822 - B fill then stroke with fill using non-zero winding number rule
2823 - B* fill then stroke with fill using even-odd rule
2824 */
2825 op = style;
2826 }
2827
2828 return op;
2829 };
2830 /**
2831 * Draw a line on the current page.
2832 *
2833 * @name line
2834 * @function
2835 * @instance
2836 * @param {number} x1
2837 * @param {number} y1
2838 * @param {number} x2
2839 * @param {number} y2
2840 * @returns {jsPDF}
2841 * @memberOf jsPDF
2842 */
2843
2844
2845 var line = API.__private__.line = API.line = function (x1, y1, x2, y2) {
2846 if (isNaN(x1) || isNaN(y1) || isNaN(x2) || isNaN(y2)) {
2847 throw new Error('Invalid arguments passed to jsPDF.line');
2848 }
2849
2850 return this.lines([[x2 - x1, y2 - y1]], x1, y1);
2851 };
2852 /**
2853 * Adds series of curves (straight lines or cubic bezier curves) to canvas, starting at `x`, `y` coordinates.
2854 * All data points in `lines` are relative to last line origin.
2855 * `x`, `y` become x1,y1 for first line / curve in the set.
2856 * For lines you only need to specify [x2, y2] - (ending point) vector against x1, y1 starting point.
2857 * For bezier curves you need to specify [x2,y2,x3,y3,x4,y4] - vectors to control points 1, 2, ending point. All vectors are against the start of the curve - x1,y1.
2858 *
2859 * @example .lines([[2,2],[-2,2],[1,1,2,2,3,3],[2,1]], 212,110, [1,1], 'F', false) // line, line, bezier curve, line
2860 * @param {Array} lines Array of *vector* shifts as pairs (lines) or sextets (cubic bezier curves).
2861 * @param {number} x Coordinate (in units declared at inception of PDF document) against left edge of the page.
2862 * @param {number} y Coordinate (in units declared at inception of PDF document) against upper edge of the page.
2863 * @param {number} scale (Defaults to [1.0,1.0]) x,y Scaling factor for all vectors. Elements can be any floating number Sub-one makes drawing smaller. Over-one grows the drawing. Negative flips the direction.
2864 * @param {string} style A string specifying the painting style or null. Valid styles include: 'S' [default] - stroke, 'F' - fill, and 'DF' (or 'FD') - fill then stroke. A null value postpones setting the style so that a shape may be composed using multiple method calls. The last drawing method call used to define the shape should not have a null style argument.
2865 * @param {boolean} closed If true, the path is closed with a straight line from the end of the last curve to the starting point.
2866 * @function
2867 * @instance
2868 * @returns {jsPDF}
2869 * @memberOf jsPDF
2870 * @name lines
2871 */
2872
2873
2874 var lines = API.__private__.lines = API.lines = function (lines, x, y, scale, style, closed) {
2875 var scalex, scaley, i, l, leg, x2, y2, x3, y3, x4, y4, tmp; // Pre-August-2012 the order of arguments was function(x, y, lines, scale, style)
2876 // in effort to make all calls have similar signature like
2877 // function(content, coordinateX, coordinateY , miscellaneous)
2878 // this method had its args flipped.
2879 // code below allows backward compatibility with old arg order.
2880
2881 if (typeof lines === 'number') {
2882 tmp = y;
2883 y = x;
2884 x = lines;
2885 lines = tmp;
2886 }
2887
2888 scale = scale || [1, 1];
2889 closed = closed || false;
2890
2891 if (isNaN(x) || isNaN(y) || !Array.isArray(lines) || !Array.isArray(scale) || !isValidStyle(style) || typeof closed !== 'boolean') {
2892 throw new Error('Invalid arguments passed to jsPDF.lines');
2893 } // starting point
2894
2895
2896 out(f3(getHorizontalCoordinate(x)) + ' ' + f3(getVerticalCoordinate(y)) + ' m ');
2897 scalex = scale[0];
2898 scaley = scale[1];
2899 l = lines.length; //, x2, y2 // bezier only. In page default measurement "units", *after* scaling
2900 //, x3, y3 // bezier only. In page default measurement "units", *after* scaling
2901 // ending point for all, lines and bezier. . In page default measurement "units", *after* scaling
2902
2903 x4 = x; // last / ending point = starting point for first item.
2904
2905 y4 = y; // last / ending point = starting point for first item.
2906
2907 for (i = 0; i < l; i++) {
2908 leg = lines[i];
2909
2910 if (leg.length === 2) {
2911 // simple line
2912 x4 = leg[0] * scalex + x4; // here last x4 was prior ending point
2913
2914 y4 = leg[1] * scaley + y4; // here last y4 was prior ending point
2915
2916 out(f3(getHorizontalCoordinate(x4)) + ' ' + f3(getVerticalCoordinate(y4)) + ' l');
2917 } else {
2918 // bezier curve
2919 x2 = leg[0] * scalex + x4; // here last x4 is prior ending point
2920
2921 y2 = leg[1] * scaley + y4; // here last y4 is prior ending point
2922
2923 x3 = leg[2] * scalex + x4; // here last x4 is prior ending point
2924
2925 y3 = leg[3] * scaley + y4; // here last y4 is prior ending point
2926
2927 x4 = leg[4] * scalex + x4; // here last x4 was prior ending point
2928
2929 y4 = leg[5] * scaley + y4; // here last y4 was prior ending point
2930
2931 out(f3(getHorizontalCoordinate(x2)) + ' ' + f3(getVerticalCoordinate(y2)) + ' ' + f3(getHorizontalCoordinate(x3)) + ' ' + f3(getVerticalCoordinate(y3)) + ' ' + f3(getHorizontalCoordinate(x4)) + ' ' + f3(getVerticalCoordinate(y4)) + ' c');
2932 }
2933 }
2934
2935 if (closed) {
2936 out(' h');
2937 } // stroking / filling / both the path
2938
2939
2940 if (style !== null) {
2941 out(getStyle(style));
2942 }
2943
2944 return this;
2945 };
2946 /**
2947 * Adds a rectangle to PDF.
2948 *
2949 * @param {number} x Coordinate (in units declared at inception of PDF document) against left edge of the page.
2950 * @param {number} y Coordinate (in units declared at inception of PDF document) against upper edge of the page.
2951 * @param {number} w Width (in units declared at inception of PDF document).
2952 * @param {number} h Height (in units declared at inception of PDF document).
2953 * @param {string} style A string specifying the painting style or null. Valid styles include: 'S' [default] - stroke, 'F' - fill, and 'DF' (or 'FD') - fill then stroke. A null value postpones setting the style so that a shape may be composed using multiple method calls. The last drawing method call used to define the shape should not have a null style argument.
2954 * @function
2955 * @instance
2956 * @returns {jsPDF}
2957 * @memberOf jsPDF
2958 * @name rect
2959 */
2960
2961
2962 var rect = API.__private__.rect = API.rect = function (x, y, w, h, style) {
2963 if (isNaN(x) || isNaN(y) || isNaN(w) || isNaN(h) || !isValidStyle(style)) {
2964 throw new Error('Invalid arguments passed to jsPDF.rect');
2965 }
2966
2967 out([f2(getHorizontalCoordinate(x)), f2(getVerticalCoordinate(y)), f2(w * k), f2(-h * k), 're'].join(' '));
2968
2969 if (style !== null) {
2970 out(getStyle(style));
2971 }
2972
2973 return this;
2974 };
2975 /**
2976 * Adds a triangle to PDF.
2977 *
2978 * @param {number} x1 Coordinate (in units declared at inception of PDF document) against left edge of the page.
2979 * @param {number} y1 Coordinate (in units declared at inception of PDF document) against upper edge of the page.
2980 * @param {number} x2 Coordinate (in units declared at inception of PDF document) against left edge of the page.
2981 * @param {number} y2 Coordinate (in units declared at inception of PDF document) against upper edge of the page.
2982 * @param {number} x3 Coordinate (in units declared at inception of PDF document) against left edge of the page.
2983 * @param {number} y3 Coordinate (in units declared at inception of PDF document) against upper edge of the page.
2984 * @param {string} style A string specifying the painting style or null. Valid styles include: 'S' [default] - stroke, 'F' - fill, and 'DF' (or 'FD') - fill then stroke. A null value postpones setting the style so that a shape may be composed using multiple method calls. The last drawing method call used to define the shape should not have a null style argument.
2985 * @function
2986 * @instance
2987 * @returns {jsPDF}
2988 * @memberOf jsPDF
2989 * @name triangle
2990 */
2991
2992
2993 var triangle = API.__private__.triangle = API.triangle = function (x1, y1, x2, y2, x3, y3, style) {
2994 if (isNaN(x1) || isNaN(y1) || isNaN(x2) || isNaN(y2) || isNaN(x3) || isNaN(y3) || !isValidStyle(style)) {
2995 throw new Error('Invalid arguments passed to jsPDF.triangle');
2996 }
2997
2998 this.lines([[x2 - x1, y2 - y1], // vector to point 2
2999 [x3 - x2, y3 - y2], // vector to point 3
3000 [x1 - x3, y1 - y3] // closing vector back to point 1
3001 ], x1, y1, // start of path
3002 [1, 1], style, true);
3003 return this;
3004 };
3005 /**
3006 * Adds a rectangle with rounded corners to PDF.
3007 *
3008 * @param {number} x Coordinate (in units declared at inception of PDF document) against left edge of the page.
3009 * @param {number} y Coordinate (in units declared at inception of PDF document) against upper edge of the page.
3010 * @param {number} w Width (in units declared at inception of PDF document).
3011 * @param {number} h Height (in units declared at inception of PDF document).
3012 * @param {number} rx Radius along x axis (in units declared at inception of PDF document).
3013 * @param {number} ry Radius along y axis (in units declared at inception of PDF document).
3014 * @param {string} style A string specifying the painting style or null. Valid styles include: 'S' [default] - stroke, 'F' - fill, and 'DF' (or 'FD') - fill then stroke. A null value postpones setting the style so that a shape may be composed using multiple method calls. The last drawing method call used to define the shape should not have a null style argument.
3015 * @function
3016 * @instance
3017 * @returns {jsPDF}
3018 * @memberOf jsPDF
3019 * @name roundedRect
3020 */
3021
3022
3023 var roundedRect = API.__private__.roundedRect = API.roundedRect = function (x, y, w, h, rx, ry, style) {
3024 if (isNaN(x) || isNaN(y) || isNaN(w) || isNaN(h) || isNaN(rx) || isNaN(ry) || !isValidStyle(style)) {
3025 throw new Error('Invalid arguments passed to jsPDF.roundedRect');
3026 }
3027
3028 var MyArc = 4 / 3 * (Math.SQRT2 - 1);
3029 this.lines([[w - 2 * rx, 0], [rx * MyArc, 0, rx, ry - ry * MyArc, rx, ry], [0, h - 2 * ry], [0, ry * MyArc, -(rx * MyArc), ry, -rx, ry], [-w + 2 * rx, 0], [-(rx * MyArc), 0, -rx, -(ry * MyArc), -rx, -ry], [0, -h + 2 * ry], [0, -(ry * MyArc), rx * MyArc, -ry, rx, -ry]], x + rx, y, // start of path
3030 [1, 1], style);
3031 return this;
3032 };
3033 /**
3034 * Adds an ellipse to PDF.
3035 *
3036 * @param {number} x Coordinate (in units declared at inception of PDF document) against left edge of the page.
3037 * @param {number} y Coordinate (in units declared at inception of PDF document) against upper edge of the page.
3038 * @param {number} rx Radius along x axis (in units declared at inception of PDF document).
3039 * @param {number} ry Radius along y axis (in units declared at inception of PDF document).
3040 * @param {string} style A string specifying the painting style or null. Valid styles include: 'S' [default] - stroke, 'F' - fill, and 'DF' (or 'FD') - fill then stroke. A null value postpones setting the style so that a shape may be composed using multiple method calls. The last drawing method call used to define the shape should not have a null style argument.
3041 * @function
3042 * @instance
3043 * @returns {jsPDF}
3044 * @memberOf jsPDF
3045 * @name ellipse
3046 */
3047
3048
3049 var ellise = API.__private__.ellipse = API.ellipse = function (x, y, rx, ry, style) {
3050 if (isNaN(x) || isNaN(y) || isNaN(rx) || isNaN(ry) || !isValidStyle(style)) {
3051 throw new Error('Invalid arguments passed to jsPDF.ellipse');
3052 }
3053
3054 var lx = 4 / 3 * (Math.SQRT2 - 1) * rx,
3055 ly = 4 / 3 * (Math.SQRT2 - 1) * ry;
3056 out([f2(getHorizontalCoordinate(x + rx)), f2(getVerticalCoordinate(y)), 'm', f2(getHorizontalCoordinate(x + rx)), f2(getVerticalCoordinate(y - ly)), f2(getHorizontalCoordinate(x + lx)), f2(getVerticalCoordinate(y - ry)), f2(getHorizontalCoordinate(x)), f2(getVerticalCoordinate(y - ry)), 'c'].join(' '));
3057 out([f2(getHorizontalCoordinate(x - lx)), f2(getVerticalCoordinate(y - ry)), f2(getHorizontalCoordinate(x - rx)), f2(getVerticalCoordinate(y - ly)), f2(getHorizontalCoordinate(x - rx)), f2(getVerticalCoordinate(y)), 'c'].join(' '));
3058 out([f2(getHorizontalCoordinate(x - rx)), f2(getVerticalCoordinate(y + ly)), f2(getHorizontalCoordinate(x - lx)), f2(getVerticalCoordinate(y + ry)), f2(getHorizontalCoordinate(x)), f2(getVerticalCoordinate(y + ry)), 'c'].join(' '));
3059 out([f2(getHorizontalCoordinate(x + lx)), f2(getVerticalCoordinate(y + ry)), f2(getHorizontalCoordinate(x + rx)), f2(getVerticalCoordinate(y + ly)), f2(getHorizontalCoordinate(x + rx)), f2(getVerticalCoordinate(y)), 'c'].join(' '));
3060
3061 if (style !== null) {
3062 out(getStyle(style));
3063 }
3064
3065 return this;
3066 };
3067 /**
3068 * Adds an circle to PDF.
3069 *
3070 * @param {number} x Coordinate (in units declared at inception of PDF document) against left edge of the page.
3071 * @param {number} y Coordinate (in units declared at inception of PDF document) against upper edge of the page.
3072 * @param {number} r Radius (in units declared at inception of PDF document).
3073 * @param {string} style A string specifying the painting style or null. Valid styles include: 'S' [default] - stroke, 'F' - fill, and 'DF' (or 'FD') - fill then stroke. A null value postpones setting the style so that a shape may be composed using multiple method calls. The last drawing method call used to define the shape should not have a null style argument.
3074 * @function
3075 * @instance
3076 * @returns {jsPDF}
3077 * @memberOf jsPDF
3078 * @name circle
3079 */
3080
3081
3082 var circle = API.__private__.circle = API.circle = function (x, y, r, style) {
3083 if (isNaN(x) || isNaN(y) || isNaN(r) || !isValidStyle(style)) {
3084 throw new Error('Invalid arguments passed to jsPDF.circle');
3085 }
3086
3087 return this.ellipse(x, y, r, r, style);
3088 };
3089 /**
3090 * Sets text font face, variant for upcoming text elements.
3091 * See output of jsPDF.getFontList() for possible font names, styles.
3092 *
3093 * @param {string} fontName Font name or family. Example: "times".
3094 * @param {string} fontStyle Font style or variant. Example: "italic".
3095 * @function
3096 * @instance
3097 * @returns {jsPDF}
3098 * @memberOf jsPDF
3099 * @name setFont
3100 */
3101
3102
3103 API.setFont = function (fontName, fontStyle) {
3104 activeFontKey = _getFont(fontName, fontStyle, {
3105 disableWarning: false
3106 });
3107 return this;
3108 };
3109 /**
3110 * Switches font style or variant for upcoming text elements,
3111 * while keeping the font face or family same.
3112 * See output of jsPDF.getFontList() for possible font names, styles.
3113 *
3114 * @param {string} style Font style or variant. Example: "italic".
3115 * @function
3116 * @instance
3117 * @returns {jsPDF}
3118 * @memberOf jsPDF
3119 * @name setFontStyle
3120 */
3121
3122
3123 API.setFontStyle = API.setFontType = function (style) {
3124 activeFontKey = _getFont(undefined, style); // if font is not found, the above line blows up and we never go further
3125
3126 return this;
3127 };
3128 /**
3129 * Returns an object - a tree of fontName to fontStyle relationships available to
3130 * active PDF document.
3131 *
3132 * @public
3133 * @function
3134 * @instance
3135 * @returns {Object} Like {'times':['normal', 'italic', ... ], 'arial':['normal', 'bold', ... ], ... }
3136 * @memberOf jsPDF
3137 * @name getFontList
3138 */
3139
3140
3141 var getFontList = API.__private__.getFontList = API.getFontList = function () {
3142 // TODO: iterate over fonts array or return copy of fontmap instead in case more are ever added.
3143 var list = {},
3144 fontName,
3145 fontStyle,
3146 tmp;
3147
3148 for (fontName in fontmap) {
3149 if (fontmap.hasOwnProperty(fontName)) {
3150 list[fontName] = tmp = [];
3151
3152 for (fontStyle in fontmap[fontName]) {
3153 if (fontmap[fontName].hasOwnProperty(fontStyle)) {
3154 tmp.push(fontStyle);
3155 }
3156 }
3157 }
3158 }
3159
3160 return list;
3161 };
3162 /**
3163 * Add a custom font to the current instance.
3164 *
3165 * @property {string} postScriptName PDF specification full name for the font.
3166 * @property {string} id PDF-document-instance-specific label assinged to the font.
3167 * @property {string} fontStyle Style of the Font.
3168 * @property {Object} encoding Encoding_name-to-Font_metrics_object mapping.
3169 * @function
3170 * @instance
3171 * @memberOf jsPDF
3172 * @name addFont
3173 */
3174
3175
3176 API.addFont = function (postScriptName, fontName, fontStyle, encoding) {
3177 encoding = encoding || 'Identity-H';
3178 addFont.call(this, postScriptName, fontName, fontStyle, encoding);
3179 };
3180
3181 var lineWidth = options.lineWidth || 0.200025; // 2mm
3182
3183 /**
3184 * Sets line width for upcoming lines.
3185 *
3186 * @param {number} width Line width (in units declared at inception of PDF document).
3187 * @function
3188 * @instance
3189 * @returns {jsPDF}
3190 * @memberOf jsPDF
3191 * @name setLineWidth
3192 */
3193
3194 var setLineWidth = API.__private__.setLineWidth = API.setLineWidth = function (width) {
3195 out((width * k).toFixed(2) + ' w');
3196 return this;
3197 };
3198 /**
3199 * Sets the dash pattern for upcoming lines.
3200 *
3201 * To reset the settings simply call the method without any parameters.
3202 * @param {array} dashArray The pattern of the line, expects numbers.
3203 * @param {number} dashPhase The phase at which the dash pattern starts.
3204 * @function
3205 * @instance
3206 * @returns {jsPDF}
3207 * @memberOf jsPDF
3208 * @name setLineDash
3209 */
3210
3211
3212 var setLineDash = API.__private__.setLineDash = jsPDF.API.setLineDash = function (dashArray, dashPhase) {
3213 dashArray = dashArray || [];
3214 dashPhase = dashPhase || 0;
3215
3216 if (isNaN(dashPhase) || !Array.isArray(dashArray)) {
3217 throw new Error('Invalid arguments passed to jsPDF.setLineDash');
3218 }
3219
3220 dashArray = dashArray.map(function (x) {
3221 return (x * k).toFixed(3);
3222 }).join(' ');
3223 dashPhase = parseFloat((dashPhase * k).toFixed(3));
3224 out('[' + dashArray + '] ' + dashPhase + ' d');
3225 return this;
3226 };
3227
3228 var lineHeightFactor;
3229
3230 var getLineHeight = API.__private__.getLineHeight = API.getLineHeight = function () {
3231 return activeFontSize * lineHeightFactor;
3232 };
3233
3234 var lineHeightFactor;
3235
3236 var getLineHeight = API.__private__.getLineHeight = API.getLineHeight = function () {
3237 return activeFontSize * lineHeightFactor;
3238 };
3239 /**
3240 * Sets the LineHeightFactor of proportion.
3241 *
3242 * @param {number} value LineHeightFactor value. Default: 1.15.
3243 * @function
3244 * @instance
3245 * @returns {jsPDF}
3246 * @memberOf jsPDF
3247 * @name setLineHeightFactor
3248 */
3249
3250
3251 var setLineHeightFactor = API.__private__.setLineHeightFactor = API.setLineHeightFactor = function (value) {
3252 value = value || 1.15;
3253
3254 if (typeof value === "number") {
3255 lineHeightFactor = value;
3256 }
3257
3258 return this;
3259 };
3260 /**
3261 * Gets the LineHeightFactor, default: 1.15.
3262 *
3263 * @function
3264 * @instance
3265 * @returns {number} lineHeightFactor
3266 * @memberOf jsPDF
3267 * @name getLineHeightFactor
3268 */
3269
3270
3271 var getLineHeightFactor = API.__private__.getLineHeightFactor = API.getLineHeightFactor = function () {
3272 return lineHeightFactor;
3273 };
3274
3275 setLineHeightFactor(options.lineHeight);
3276
3277 var getHorizontalCoordinate = API.__private__.getHorizontalCoordinate = function (value) {
3278 return value * k;
3279 };
3280
3281 var getVerticalCoordinate = API.__private__.getVerticalCoordinate = function (value) {
3282 return pagesContext[currentPage].mediaBox.topRightY - pagesContext[currentPage].mediaBox.bottomLeftY - value * k;
3283 };
3284
3285 var getHorizontalCoordinateString = API.__private__.getHorizontalCoordinateString = function (value) {
3286 return f2(value * k);
3287 };
3288
3289 var getVerticalCoordinateString = API.__private__.getVerticalCoordinateString = function (value) {
3290 return f2(pagesContext[currentPage].mediaBox.topRightY - pagesContext[currentPage].mediaBox.bottomLeftY - value * k);
3291 };
3292
3293 var strokeColor = options.strokeColor || '0 G';
3294 /**
3295 * Gets the stroke color for upcoming elements.
3296 *
3297 * @function
3298 * @instance
3299 * @returns {string} colorAsHex
3300 * @memberOf jsPDF
3301 * @name getDrawColor
3302 */
3303
3304 var getStrokeColor = API.__private__.getStrokeColor = API.getDrawColor = function () {
3305 return decodeColorString(strokeColor);
3306 };
3307 /**
3308 * Sets the stroke color for upcoming elements.
3309 *
3310 * Depending on the number of arguments given, Gray, RGB, or CMYK
3311 * color space is implied.
3312 *
3313 * When only ch1 is given, "Gray" color space is implied and it
3314 * must be a value in the range from 0.00 (solid black) to to 1.00 (white)
3315 * if values are communicated as String types, or in range from 0 (black)
3316 * to 255 (white) if communicated as Number type.
3317 * The RGB-like 0-255 range is provided for backward compatibility.
3318 *
3319 * When only ch1,ch2,ch3 are given, "RGB" color space is implied and each
3320 * value must be in the range from 0.00 (minimum intensity) to to 1.00
3321 * (max intensity) if values are communicated as String types, or
3322 * from 0 (min intensity) to to 255 (max intensity) if values are communicated
3323 * as Number types.
3324 * The RGB-like 0-255 range is provided for backward compatibility.
3325 *
3326 * When ch1,ch2,ch3,ch4 are given, "CMYK" color space is implied and each
3327 * value must be a in the range from 0.00 (0% concentration) to to
3328 * 1.00 (100% concentration)
3329 *
3330 * Because JavaScript treats fixed point numbers badly (rounds to
3331 * floating point nearest to binary representation) it is highly advised to
3332 * communicate the fractional numbers as String types, not JavaScript Number type.
3333 *
3334 * @param {Number|String} ch1 Color channel value or {string} ch1 color value in hexadecimal, example: '#FFFFFF'.
3335 * @param {Number|String} ch2 Color channel value.
3336 * @param {Number|String} ch3 Color channel value.
3337 * @param {Number|String} ch4 Color channel value.
3338 *
3339 * @function
3340 * @instance
3341 * @returns {jsPDF}
3342 * @memberOf jsPDF
3343 * @name setDrawColor
3344 */
3345
3346
3347 var setStrokeColor = API.__private__.setStrokeColor = API.setDrawColor = function (ch1, ch2, ch3, ch4) {
3348 var options = {
3349 "ch1": ch1,
3350 "ch2": ch2,
3351 "ch3": ch3,
3352 "ch4": ch4,
3353 "pdfColorType": "draw",
3354 "precision": 2
3355 };
3356 strokeColor = encodeColorString(options);
3357 out(strokeColor);
3358 return this;
3359 };
3360
3361 var fillColor = options.fillColor || '0 g';
3362 /**
3363 * Gets the fill color for upcoming elements.
3364 *
3365 * @function
3366 * @instance
3367 * @returns {string} colorAsHex
3368 * @memberOf jsPDF
3369 * @name getFillColor
3370 */
3371
3372 var getFillColor = API.__private__.getFillColor = API.getFillColor = function () {
3373 return decodeColorString(fillColor);
3374 };
3375 /**
3376 * Sets the fill color for upcoming elements.
3377 *
3378 * Depending on the number of arguments given, Gray, RGB, or CMYK
3379 * color space is implied.
3380 *
3381 * When only ch1 is given, "Gray" color space is implied and it
3382 * must be a value in the range from 0.00 (solid black) to to 1.00 (white)
3383 * if values are communicated as String types, or in range from 0 (black)
3384 * to 255 (white) if communicated as Number type.
3385 * The RGB-like 0-255 range is provided for backward compatibility.
3386 *
3387 * When only ch1,ch2,ch3 are given, "RGB" color space is implied and each
3388 * value must be in the range from 0.00 (minimum intensity) to to 1.00
3389 * (max intensity) if values are communicated as String types, or
3390 * from 0 (min intensity) to to 255 (max intensity) if values are communicated
3391 * as Number types.
3392 * The RGB-like 0-255 range is provided for backward compatibility.
3393 *
3394 * When ch1,ch2,ch3,ch4 are given, "CMYK" color space is implied and each
3395 * value must be a in the range from 0.00 (0% concentration) to to
3396 * 1.00 (100% concentration)
3397 *
3398 * Because JavaScript treats fixed point numbers badly (rounds to
3399 * floating point nearest to binary representation) it is highly advised to
3400 * communicate the fractional numbers as String types, not JavaScript Number type.
3401 *
3402 * @param {Number|String} ch1 Color channel value or {string} ch1 color value in hexadecimal, example: '#FFFFFF'.
3403 * @param {Number|String} ch2 Color channel value.
3404 * @param {Number|String} ch3 Color channel value.
3405 * @param {Number|String} ch4 Color channel value.
3406 *
3407 * @function
3408 * @instance
3409 * @returns {jsPDF}
3410 * @memberOf jsPDF
3411 * @name setFillColor
3412 */
3413
3414
3415 var setFillColor = API.__private__.setFillColor = API.setFillColor = function (ch1, ch2, ch3, ch4) {
3416 var options = {
3417 "ch1": ch1,
3418 "ch2": ch2,
3419 "ch3": ch3,
3420 "ch4": ch4,
3421 "pdfColorType": "fill",
3422 "precision": 2
3423 };
3424 fillColor = encodeColorString(options);
3425 out(fillColor);
3426 return this;
3427 };
3428
3429 var textColor = options.textColor || '0 g';
3430 /**
3431 * Gets the text color for upcoming elements.
3432 *
3433 * @function
3434 * @instance
3435 * @returns {string} colorAsHex
3436 * @memberOf jsPDF
3437 * @name getTextColor
3438 */
3439
3440 var getTextColor = API.__private__.getTextColor = API.getTextColor = function () {
3441 return decodeColorString(textColor);
3442 };
3443 /**
3444 * Sets the text color for upcoming elements.
3445 *
3446 * Depending on the number of arguments given, Gray, RGB, or CMYK
3447 * color space is implied.
3448 *
3449 * When only ch1 is given, "Gray" color space is implied and it
3450 * must be a value in the range from 0.00 (solid black) to to 1.00 (white)
3451 * if values are communicated as String types, or in range from 0 (black)
3452 * to 255 (white) if communicated as Number type.
3453 * The RGB-like 0-255 range is provided for backward compatibility.
3454 *
3455 * When only ch1,ch2,ch3 are given, "RGB" color space is implied and each
3456 * value must be in the range from 0.00 (minimum intensity) to to 1.00
3457 * (max intensity) if values are communicated as String types, or
3458 * from 0 (min intensity) to to 255 (max intensity) if values are communicated
3459 * as Number types.
3460 * The RGB-like 0-255 range is provided for backward compatibility.
3461 *
3462 * When ch1,ch2,ch3,ch4 are given, "CMYK" color space is implied and each
3463 * value must be a in the range from 0.00 (0% concentration) to to
3464 * 1.00 (100% concentration)
3465 *
3466 * Because JavaScript treats fixed point numbers badly (rounds to
3467 * floating point nearest to binary representation) it is highly advised to
3468 * communicate the fractional numbers as String types, not JavaScript Number type.
3469 *
3470 * @param {Number|String} ch1 Color channel value or {string} ch1 color value in hexadecimal, example: '#FFFFFF'.
3471 * @param {Number|String} ch2 Color channel value.
3472 * @param {Number|String} ch3 Color channel value.
3473 * @param {Number|String} ch4 Color channel value.
3474 *
3475 * @function
3476 * @instance
3477 * @returns {jsPDF}
3478 * @memberOf jsPDF
3479 * @name setTextColor
3480 */
3481
3482
3483 var setTextColor = API.__private__.setTextColor = API.setTextColor = function (ch1, ch2, ch3, ch4) {
3484 var options = {
3485 "ch1": ch1,
3486 "ch2": ch2,
3487 "ch3": ch3,
3488 "ch4": ch4,
3489 "pdfColorType": "text",
3490 "precision": 3
3491 };
3492 textColor = encodeColorString(options);
3493 return this;
3494 };
3495
3496 var activeCharSpace = options.charSpace || 0;
3497 /**
3498 * Get global value of CharSpace.
3499 *
3500 * @function
3501 * @instance
3502 * @returns {number} charSpace
3503 * @memberOf jsPDF
3504 * @name getCharSpace
3505 */
3506
3507 var getCharSpace = API.__private__.getCharSpace = API.getCharSpace = function () {
3508 return activeCharSpace;
3509 };
3510 /**
3511 * Set global value of CharSpace.
3512 *
3513 * @param {number} charSpace
3514 * @function
3515 * @instance
3516 * @returns {jsPDF} jsPDF-instance
3517 * @memberOf jsPDF
3518 * @name setCharSpace
3519 */
3520
3521
3522 var setCharSpace = API.__private__.setCharSpace = API.setCharSpace = function (charSpace) {
3523 if (isNaN(charSpace)) {
3524 throw new Error('Invalid argument passed to jsPDF.setCharSpace');
3525 }
3526
3527 activeCharSpace = charSpace;
3528 return this;
3529 };
3530
3531 var lineCapID = 0;
3532 /**
3533 * Is an Object providing a mapping from human-readable to
3534 * integer flag values designating the varieties of line cap
3535 * and join styles.
3536 *
3537 * @memberOf jsPDF
3538 * @name CapJoinStyles
3539 */
3540
3541 API.CapJoinStyles = {
3542 0: 0,
3543 'butt': 0,
3544 'but': 0,
3545 'miter': 0,
3546 1: 1,
3547 'round': 1,
3548 'rounded': 1,
3549 'circle': 1,
3550 2: 2,
3551 'projecting': 2,
3552 'project': 2,
3553 'square': 2,
3554 'bevel': 2
3555 };
3556 /**
3557 * Sets the line cap styles.
3558 * See {jsPDF.CapJoinStyles} for variants.
3559 *
3560 * @param {String|Number} style A string or number identifying the type of line cap.
3561 * @function
3562 * @instance
3563 * @returns {jsPDF}
3564 * @memberOf jsPDF
3565 * @name setLineCap
3566 */
3567
3568 var setLineCap = API.__private__.setLineCap = API.setLineCap = function (style) {
3569 var id = API.CapJoinStyles[style];
3570
3571 if (id === undefined) {
3572 throw new Error("Line cap style of '" + style + "' is not recognized. See or extend .CapJoinStyles property for valid styles");
3573 }
3574
3575 lineCapID = id;
3576 out(id + ' J');
3577 return this;
3578 };
3579
3580 var lineJoinID = 0;
3581 /**
3582 * Sets the line join styles.
3583 * See {jsPDF.CapJoinStyles} for variants.
3584 *
3585 * @param {String|Number} style A string or number identifying the type of line join.
3586 * @function
3587 * @instance
3588 * @returns {jsPDF}
3589 * @memberOf jsPDF
3590 * @name setLineJoin
3591 */
3592
3593 var setLineJoin = API.__private__.setLineJoin = API.setLineJoin = function (style) {
3594 var id = API.CapJoinStyles[style];
3595
3596 if (id === undefined) {
3597 throw new Error("Line join style of '" + style + "' is not recognized. See or extend .CapJoinStyles property for valid styles");
3598 }
3599
3600 lineJoinID = id;
3601 out(id + ' j');
3602 return this;
3603 };
3604
3605 var miterLimit;
3606 /**
3607 * Sets the miterLimit property, which effects the maximum miter length.
3608 *
3609 * @param {number} length The length of the miter
3610 * @function
3611 * @instance
3612 * @returns {jsPDF}
3613 * @memberOf jsPDF
3614 * @name setMiterLimit
3615 */
3616
3617 var setMiterLimit = API.__private__.setMiterLimit = API.setMiterLimit = function (length) {
3618 length = length || 0;
3619
3620 if (isNaN(length)) {
3621 throw new Error('Invalid argument passed to jsPDF.setMiterLimit');
3622 }
3623
3624 miterLimit = parseFloat(f2(length * k));
3625 out(miterLimit + ' M');
3626 return this;
3627 };
3628 /**
3629 * Saves as PDF document. An alias of jsPDF.output('save', 'filename.pdf').
3630 * Uses FileSaver.js-method saveAs.
3631 *
3632 * @memberOf jsPDF
3633 * @name save
3634 * @function
3635 * @instance
3636 * @param {string} filename The filename including extension.
3637 * @param {Object} options An Object with additional options, possible options: 'returnPromise'.
3638 * @returns {jsPDF} jsPDF-instance
3639 */
3640
3641
3642 API.save = function (filename, options) {
3643 filename = filename || 'generated.pdf';
3644 options = options || {};
3645 options.returnPromise = options.returnPromise || false;
3646
3647 if (options.returnPromise === false) {
3648 saveAs(getBlob(buildDocument()), filename);
3649
3650 if (typeof saveAs.unload === 'function') {
3651 if (global.setTimeout) {
3652 setTimeout(saveAs.unload, 911);
3653 }
3654 }
3655 } else {
3656 return new Promise(function (resolve, reject) {
3657 try {
3658 var result = saveAs(getBlob(buildDocument()), filename);
3659
3660 if (typeof saveAs.unload === 'function') {
3661 if (global.setTimeout) {
3662 setTimeout(saveAs.unload, 911);
3663 }
3664 }
3665
3666 resolve(result);
3667 } catch (e) {
3668 reject(e.message);
3669 }
3670 });
3671 }
3672 }; // applying plugins (more methods) ON TOP of built-in API.
3673 // this is intentional as we allow plugins to override
3674 // built-ins
3675
3676
3677 for (var plugin in jsPDF.API) {
3678 if (jsPDF.API.hasOwnProperty(plugin)) {
3679 if (plugin === 'events' && jsPDF.API.events.length) {
3680 (function (events, newEvents) {
3681 // jsPDF.API.events is a JS Array of Arrays
3682 // where each Array is a pair of event name, handler
3683 // Events were added by plugins to the jsPDF instantiator.
3684 // These are always added to the new instance and some ran
3685 // during instantiation.
3686 var eventname, handler_and_args, i;
3687
3688 for (i = newEvents.length - 1; i !== -1; i--) {
3689 // subscribe takes 3 args: 'topic', function, runonce_flag
3690 // if undefined, runonce is false.
3691 // users can attach callback directly,
3692 // or they can attach an array with [callback, runonce_flag]
3693 // that's what the "apply" magic is for below.
3694 eventname = newEvents[i][0];
3695 handler_and_args = newEvents[i][1];
3696 events.subscribe.apply(events, [eventname].concat(typeof handler_and_args === 'function' ? [handler_and_args] : handler_and_args));
3697 }
3698 })(events, jsPDF.API.events);
3699 } else {
3700 API[plugin] = jsPDF.API[plugin];
3701 }
3702 }
3703 }
3704 /**
3705 * Object exposing internal API to plugins
3706 * @public
3707 * @ignore
3708 */
3709
3710
3711 API.internal = {
3712 'pdfEscape': pdfEscape,
3713 'getStyle': getStyle,
3714 'getFont': function getFont() {
3715 return fonts[_getFont.apply(API, arguments)];
3716 },
3717 'getFontSize': getFontSize,
3718 'getCharSpace': getCharSpace,
3719 'getTextColor': getTextColor,
3720 'getLineHeight': getLineHeight,
3721 'getLineHeightFactor': getLineHeightFactor,
3722 'write': write,
3723 'getHorizontalCoordinate': getHorizontalCoordinate,
3724 'getVerticalCoordinate': getVerticalCoordinate,
3725 'getCoordinateString': getHorizontalCoordinateString,
3726 'getVerticalCoordinateString': getVerticalCoordinateString,
3727 'collections': {},
3728 'newObject': newObject,
3729 'newAdditionalObject': newAdditionalObject,
3730 'newObjectDeferred': newObjectDeferred,
3731 'newObjectDeferredBegin': newObjectDeferredBegin,
3732 'getFilters': getFilters,
3733 'putStream': putStream,
3734 'events': events,
3735 // ratio that you use in multiplication of a given "size" number to arrive to 'point'
3736 // units of measurement.
3737 // scaleFactor is set at initialization of the document and calculated against the stated
3738 // default measurement units for the document.
3739 // If default is "mm", k is the number that will turn number in 'mm' into 'points' number.
3740 // through multiplication.
3741 'scaleFactor': k,
3742 'pageSize': {
3743 getWidth: function getWidth() {
3744 return (pagesContext[currentPage].mediaBox.topRightX - pagesContext[currentPage].mediaBox.bottomLeftX) / k;
3745 },
3746 setWidth: function setWidth(value) {
3747 pagesContext[currentPage].mediaBox.topRightX = value * k + pagesContext[currentPage].mediaBox.bottomLeftX;
3748 },
3749 getHeight: function getHeight() {
3750 return (pagesContext[currentPage].mediaBox.topRightY - pagesContext[currentPage].mediaBox.bottomLeftY) / k;
3751 },
3752 setHeight: function setHeight(value) {
3753 pagesContext[currentPage].mediaBox.topRightY = value * k + pagesContext[currentPage].mediaBox.bottomLeftY;
3754 }
3755 },
3756 'output': output,
3757 'getNumberOfPages': getNumberOfPages,
3758 'pages': pages,
3759 'out': out,
3760 'f2': f2,
3761 'f3': f3,
3762 'getPageInfo': getPageInfo,
3763 'getPageInfoByObjId': getPageInfoByObjId,
3764 'getCurrentPageInfo': getCurrentPageInfo,
3765 'getPDFVersion': getPdfVersion,
3766 'hasHotfix': hasHotfix //Expose the hasHotfix check so plugins can also check them.
3767
3768 };
3769 Object.defineProperty(API.internal.pageSize, 'width', {
3770 get: function get() {
3771 return (pagesContext[currentPage].mediaBox.topRightX - pagesContext[currentPage].mediaBox.bottomLeftX) / k;
3772 },
3773 set: function set(value) {
3774 pagesContext[currentPage].mediaBox.topRightX = value * k + pagesContext[currentPage].mediaBox.bottomLeftX;
3775 },
3776 enumerable: true,
3777 configurable: true
3778 });
3779 Object.defineProperty(API.internal.pageSize, 'height', {
3780 get: function get() {
3781 return (pagesContext[currentPage].mediaBox.topRightY - pagesContext[currentPage].mediaBox.bottomLeftY) / k;
3782 },
3783 set: function set(value) {
3784 pagesContext[currentPage].mediaBox.topRightY = value * k + pagesContext[currentPage].mediaBox.bottomLeftY;
3785 },
3786 enumerable: true,
3787 configurable: true
3788 }); //////////////////////////////////////////////////////
3789 // continuing initialization of jsPDF Document object
3790 //////////////////////////////////////////////////////
3791 // Add the first page automatically
3792
3793 addFonts(standardFonts);
3794 activeFontKey = 'F1';
3795
3796 _addPage(format, orientation);
3797
3798 events.publish('initialized');
3799 return API;
3800 }
3801 /**
3802 * jsPDF.API is a STATIC property of jsPDF class.
3803 * jsPDF.API is an object you can add methods and properties to.
3804 * The methods / properties you add will show up in new jsPDF objects.
3805 *
3806 * One property is prepopulated. It is the 'events' Object. Plugin authors can add topics,
3807 * callbacks to this object. These will be reassigned to all new instances of jsPDF.
3808 *
3809 * @static
3810 * @public
3811 * @memberOf jsPDF
3812 * @name API
3813 *
3814 * @example
3815 * jsPDF.API.mymethod = function(){
3816 * // 'this' will be ref to internal API object. see jsPDF source
3817 * // , so you can refer to built-in methods like so:
3818 * // this.line(....)
3819 * // this.text(....)
3820 * }
3821 * var pdfdoc = new jsPDF()
3822 * pdfdoc.mymethod() // <- !!!!!!
3823 */
3824
3825
3826 jsPDF.API = {
3827 events: []
3828 };
3829 /**
3830 * The version of jsPDF.
3831 * @name version
3832 * @type {string}
3833 * @memberOf jsPDF
3834 */
3835
3836 jsPDF.version = '1.5.3';
3837
3838 if (typeof define === 'function' && define.amd) {
3839 define('jsPDF', function () {
3840 return jsPDF;
3841 });
3842 } else if (typeof module !== 'undefined' && module.exports) {
3843 module.exports = jsPDF;
3844 module.exports.jsPDF = jsPDF;
3845 } else {
3846 global.jsPDF = jsPDF;
3847 }
3848
3849 return jsPDF;
3850 }(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
3851 // while `this` is nsIContentFrameMessageManager
3852 // with an attribute `content` that corresponds to the window
3853
3854 /*rollup-keeper-start*/
3855
3856
3857 window.tmp = jsPDF;
3858 /*rollup-keeper-end*/
3859
3860 /**
3861 * @license
3862 * Copyright (c) 2016 Alexander Weidt,
3863 * https://github.com/BiggA94
3864 *
3865 * Licensed under the MIT License. http://opensource.org/licenses/mit-license
3866 */
3867
3868 /**
3869 * jsPDF AcroForm Plugin
3870 * @module AcroForm
3871 */
3872 (function (jsPDFAPI, globalObj) {
3873
3874 var scope;
3875 var scaleFactor = 1;
3876
3877 var pdfEscape = function pdfEscape(value) {
3878 return value.replace(/\\/g, '\\\\').replace(/\(/g, '\\(').replace(/\)/g, '\\)');
3879 };
3880
3881 var pdfUnescape = function pdfUnescape(value) {
3882 return value.replace(/\\\\/g, '\\').replace(/\\\(/g, '(').replace(/\\\)/g, ')');
3883 };
3884
3885 var f2 = function f2(number) {
3886 if (isNaN(number)) {
3887 throw new Error('Invalid argument passed to jsPDF.f2');
3888 }
3889
3890 return number.toFixed(2); // Ie, %.2f
3891 };
3892
3893 var f5 = function f5(number) {
3894 if (isNaN(number)) {
3895 throw new Error('Invalid argument passed to jsPDF.f2');
3896 }
3897
3898 return number.toFixed(5); // Ie, %.2f
3899 };
3900
3901 jsPDFAPI.__acroform__ = {};
3902
3903 var inherit = function inherit(child, parent) {
3904
3905 child.prototype = Object.create(parent.prototype);
3906 child.prototype.constructor = child;
3907 };
3908
3909 var scale = function scale(x) {
3910 return x * scaleFactor;
3911 };
3912
3913 var antiScale = function antiScale(x) {
3914 return x / scaleFactor;
3915 };
3916
3917 var createFormXObject = function createFormXObject(formObject) {
3918 var xobj = new AcroFormXObject();
3919 var height = AcroFormAppearance.internal.getHeight(formObject) || 0;
3920 var width = AcroFormAppearance.internal.getWidth(formObject) || 0;
3921 xobj.BBox = [0, 0, Number(f2(width)), Number(f2(height))];
3922 return xobj;
3923 };
3924 /**
3925 * Bit-Operations
3926 */
3927
3928
3929 var setBit = jsPDFAPI.__acroform__.setBit = function (number, bitPosition) {
3930 number = number || 0;
3931 bitPosition = bitPosition || 0;
3932
3933 if (isNaN(number) || isNaN(bitPosition)) {
3934 throw new Error('Invalid arguments passed to jsPDF.API.__acroform__.setBit');
3935 }
3936
3937 var bitMask = 1 << bitPosition;
3938 number |= bitMask;
3939 return number;
3940 };
3941
3942 var clearBit = jsPDFAPI.__acroform__.clearBit = function (number, bitPosition) {
3943 number = number || 0;
3944 bitPosition = bitPosition || 0;
3945
3946 if (isNaN(number) || isNaN(bitPosition)) {
3947 throw new Error('Invalid arguments passed to jsPDF.API.__acroform__.clearBit');
3948 }
3949
3950 var bitMask = 1 << bitPosition;
3951 number &= ~bitMask;
3952 return number;
3953 };
3954
3955 var getBit = jsPDFAPI.__acroform__.getBit = function (number, bitPosition) {
3956 if (isNaN(number) || isNaN(bitPosition)) {
3957 throw new Error('Invalid arguments passed to jsPDF.API.__acroform__.getBit');
3958 }
3959
3960 return (number & 1 << bitPosition) === 0 ? 0 : 1;
3961 };
3962 /*
3963 * Ff starts counting the bit position at 1 and not like javascript at 0
3964 */
3965
3966
3967 var getBitForPdf = jsPDFAPI.__acroform__.getBitForPdf = function (number, bitPosition) {
3968 if (isNaN(number) || isNaN(bitPosition)) {
3969 throw new Error('Invalid arguments passed to jsPDF.API.__acroform__.getBitForPdf');
3970 }
3971
3972 return getBit(number, bitPosition - 1);
3973 };
3974
3975 var setBitForPdf = jsPDFAPI.__acroform__.setBitForPdf = function (number, bitPosition) {
3976 if (isNaN(number) || isNaN(bitPosition)) {
3977 throw new Error('Invalid arguments passed to jsPDF.API.__acroform__.setBitForPdf');
3978 }
3979
3980 return setBit(number, bitPosition - 1);
3981 };
3982
3983 var clearBitForPdf = jsPDFAPI.__acroform__.clearBitForPdf = function (number, bitPosition, value) {
3984 if (isNaN(number) || isNaN(bitPosition)) {
3985 throw new Error('Invalid arguments passed to jsPDF.API.__acroform__.clearBitForPdf');
3986 }
3987
3988 return clearBit(number, bitPosition - 1);
3989 };
3990
3991 var calculateCoordinates = jsPDFAPI.__acroform__.calculateCoordinates = function (args) {
3992 var getHorizontalCoordinate = this.internal.getHorizontalCoordinate;
3993 var getVerticalCoordinate = this.internal.getVerticalCoordinate;
3994 var x = args[0];
3995 var y = args[1];
3996 var w = args[2];
3997 var h = args[3];
3998 var coordinates = {};
3999 coordinates.lowerLeft_X = getHorizontalCoordinate(x) || 0;
4000 coordinates.lowerLeft_Y = getVerticalCoordinate(y + h) || 0;
4001 coordinates.upperRight_X = getHorizontalCoordinate(x + w) || 0;
4002 coordinates.upperRight_Y = getVerticalCoordinate(y) || 0;
4003 return [Number(f2(coordinates.lowerLeft_X)), Number(f2(coordinates.lowerLeft_Y)), Number(f2(coordinates.upperRight_X)), Number(f2(coordinates.upperRight_Y))];
4004 };
4005
4006 var calculateAppearanceStream = function calculateAppearanceStream(formObject) {
4007 if (formObject.appearanceStreamContent) {
4008 return formObject.appearanceStreamContent;
4009 }
4010
4011 if (!formObject.V && !formObject.DV) {
4012 return;
4013 } // else calculate it
4014
4015
4016 var stream = [];
4017 var text = formObject.V || formObject.DV;
4018 var calcRes = calculateX(formObject, text);
4019 var fontKey = scope.internal.getFont(formObject.fontName, formObject.fontStyle).id; //PDF 32000-1:2008, page 444
4020
4021 stream.push('/Tx BMC');
4022 stream.push('q');
4023 stream.push('BT'); // Begin Text
4024
4025 stream.push(scope.__private__.encodeColorString(formObject.color));
4026 stream.push('/' + fontKey + ' ' + f2(calcRes.fontSize) + ' Tf');
4027 stream.push('1 0 0 1 0 0 Tm'); // Transformation Matrix
4028
4029 stream.push(calcRes.text);
4030 stream.push('ET'); // End Text
4031
4032 stream.push('Q');
4033 stream.push('EMC');
4034 var appearanceStreamContent = new createFormXObject(formObject);
4035 appearanceStreamContent.stream = stream.join("\n");
4036 return appearanceStreamContent;
4037 };
4038
4039 var calculateX = function calculateX(formObject, text) {
4040 var maxFontSize = formObject.maxFontSize || 12;
4041 var font = formObject.fontName;
4042 var returnValue = {
4043 text: "",
4044 fontSize: ""
4045 }; // Remove Brackets
4046
4047 text = text.substr(0, 1) == '(' ? text.substr(1) : text;
4048 text = text.substr(text.length - 1) == ')' ? text.substr(0, text.length - 1) : text; // split into array of words
4049
4050 var textSplit = text.split(' ');
4051
4052 var color = scope.__private__.encodeColorString(formObject.color);
4053
4054 var fontSize = maxFontSize; // The Starting fontSize (The Maximum)
4055
4056 var lineSpacing = 2;
4057 var borderPadding = 2;
4058 var height = AcroFormAppearance.internal.getHeight(formObject) || 0;
4059 height = height < 0 ? -height : height;
4060 var width = AcroFormAppearance.internal.getWidth(formObject) || 0;
4061 width = width < 0 ? -width : width;
4062
4063 var isSmallerThanWidth = function isSmallerThanWidth(i, lastLine, fontSize) {
4064 if (i + 1 < textSplit.length) {
4065 var tmp = lastLine + " " + textSplit[i + 1];
4066 var TextWidth = calculateFontSpace(tmp, formObject, fontSize).width;
4067 var FieldWidth = width - 2 * borderPadding;
4068 return TextWidth <= FieldWidth;
4069 } else {
4070 return false;
4071 }
4072 };
4073
4074 fontSize++;
4075
4076 FontSize: while (true) {
4077 var text = "";
4078 fontSize--;
4079 var textHeight = calculateFontSpace("3", formObject, fontSize).height;
4080 var startY = formObject.multiline ? height - fontSize : (height - textHeight) / 2;
4081 startY += lineSpacing;
4082 var startX = -borderPadding;
4083 var lastY = startY;
4084 var firstWordInLine = 0,
4085 lastWordInLine = 0;
4086 var lastLength = 0;
4087
4088 if (fontSize <= 0) {
4089 // In case, the Text doesn't fit at all
4090 fontSize = 12;
4091 text = "(...) Tj\n";
4092 text += "% Width of Text: " + calculateFontSpace(text, formObject, fontSize).width + ", FieldWidth:" + width + "\n";
4093 break;
4094 }
4095
4096 lastLength = calculateFontSpace(textSplit[0] + " ", formObject, fontSize).width;
4097 var lastLine = "";
4098 var lineCount = 0;
4099
4100 Line: for (var i in textSplit) {
4101 if (textSplit.hasOwnProperty(i)) {
4102 lastLine += textSplit[i] + " "; // Remove last blank
4103
4104 lastLine = lastLine.substr(lastLine.length - 1) == " " ? lastLine.substr(0, lastLine.length - 1) : lastLine;
4105 var key = parseInt(i);
4106 lastLength = calculateFontSpace(lastLine + " ", formObject, fontSize).width;
4107 var nextLineIsSmaller = isSmallerThanWidth(key, lastLine, fontSize);
4108 var isLastWord = i >= textSplit.length - 1;
4109
4110 if (nextLineIsSmaller && !isLastWord) {
4111 lastLine += " ";
4112 continue; // Line
4113 } else if (!nextLineIsSmaller && !isLastWord) {
4114 if (!formObject.multiline) {
4115 continue FontSize;
4116 } else {
4117 if ((textHeight + lineSpacing) * (lineCount + 2) + lineSpacing > height) {
4118 // If the Text is higher than the
4119 // FieldObject
4120 continue FontSize;
4121 }
4122
4123 lastWordInLine = key; // go on
4124 }
4125 } else if (isLastWord) {
4126 lastWordInLine = key;
4127 } else {
4128 if (formObject.multiline && (textHeight + lineSpacing) * (lineCount + 2) + lineSpacing > height) {
4129 // If the Text is higher than the FieldObject
4130 continue FontSize;
4131 }
4132 }
4133
4134 var line = '';
4135
4136 for (var x = firstWordInLine; x <= lastWordInLine; x++) {
4137 line += textSplit[x] + ' ';
4138 } // Remove last blank
4139
4140
4141 line = line.substr(line.length - 1) == " " ? line.substr(0, line.length - 1) : line; // lastLength -= blankSpace.width;
4142
4143 lastLength = calculateFontSpace(line, formObject, fontSize).width; // Calculate startX
4144
4145 switch (formObject.textAlign) {
4146 case 'right':
4147 startX = width - lastLength - borderPadding;
4148 break;
4149
4150 case 'center':
4151 startX = (width - lastLength) / 2;
4152 break;
4153
4154 case 'left':
4155 default:
4156 startX = borderPadding;
4157 break;
4158 }
4159
4160 text += f2(startX) + ' ' + f2(lastY) + ' Td\n';
4161 text += '(' + pdfEscape(line) + ') Tj\n'; // reset X in PDF
4162
4163 text += -f2(startX) + ' 0 Td\n'; // After a Line, adjust y position
4164
4165 lastY = -(fontSize + lineSpacing);
4166
4167 lastLength = 0;
4168 firstWordInLine = lastWordInLine + 1;
4169 lineCount++;
4170 lastLine = "";
4171 continue Line;
4172 }
4173 }
4174
4175 break;
4176 }
4177
4178 returnValue.text = text;
4179 returnValue.fontSize = fontSize;
4180 return returnValue;
4181 };
4182 /**
4183 * Small workaround for calculating the TextMetric approximately.
4184 *
4185 * @param text
4186 * @param fontsize
4187 * @returns {TextMetrics} (Has Height and Width)
4188 */
4189
4190
4191 var calculateFontSpace = function calculateFontSpace(text, formObject, fontSize) {
4192 var font = scope.internal.getFont(formObject.fontName, formObject.fontStyle);
4193 var width = scope.getStringUnitWidth(text, {
4194 font: font,
4195 fontSize: parseFloat(fontSize),
4196 charSpace: 0
4197 }) * parseFloat(fontSize);
4198 var height = scope.getStringUnitWidth("3", {
4199 font: font,
4200 fontSize: parseFloat(fontSize),
4201 charSpace: 0
4202 }) * parseFloat(fontSize) * 1.5;
4203 return {
4204 height: height,
4205 width: width
4206 };
4207 };
4208
4209 var acroformPluginTemplate = {
4210 fields: [],
4211 xForms: [],
4212
4213 /**
4214 * acroFormDictionaryRoot contains information about the AcroForm
4215 * Dictionary 0: The Event-Token, the AcroFormDictionaryCallback has
4216 * 1: The Object ID of the Root
4217 */
4218 acroFormDictionaryRoot: null,
4219
4220 /**
4221 * After the PDF gets evaluated, the reference to the root has to be
4222 * reset, this indicates, whether the root has already been printed
4223 * out
4224 */
4225 printedOut: false,
4226 internal: null,
4227 isInitialized: false
4228 };
4229
4230 var annotReferenceCallback = function annotReferenceCallback() {
4231 //set objId to undefined and force it to get a new objId on buildDocument
4232 scope.internal.acroformPlugin.acroFormDictionaryRoot.objId = undefined;
4233 var fields = scope.internal.acroformPlugin.acroFormDictionaryRoot.Fields;
4234
4235 for (var i in fields) {
4236 if (fields.hasOwnProperty(i)) {
4237 var formObject = fields[i]; //set objId to undefined and force it to get a new objId on buildDocument
4238
4239 formObject.objId = undefined; // add Annot Reference!
4240
4241 if (formObject.hasAnnotation) {
4242 // If theres an Annotation Widget in the Form Object, put the
4243 // Reference in the /Annot array
4244 createAnnotationReference.call(scope, formObject);
4245 }
4246 }
4247 }
4248 };
4249
4250 var putForm = function putForm(formObject) {
4251 if (scope.internal.acroformPlugin.printedOut) {
4252 scope.internal.acroformPlugin.printedOut = false;
4253 scope.internal.acroformPlugin.acroFormDictionaryRoot = null;
4254 }
4255
4256 if (!scope.internal.acroformPlugin.acroFormDictionaryRoot) {
4257 initializeAcroForm.call(scope);
4258 }
4259
4260 scope.internal.acroformPlugin.acroFormDictionaryRoot.Fields.push(formObject);
4261 };
4262 /**
4263 * Create the Reference to the widgetAnnotation, so that it gets referenced
4264 * in the Annot[] int the+ (Requires the Annotation Plugin)
4265 */
4266
4267
4268 var createAnnotationReference = function createAnnotationReference(object) {
4269 var options = {
4270 type: 'reference',
4271 object: object
4272 };
4273
4274 var findEntry = function findEntry(entry) {
4275 return entry.type === options.type && entry.object === options.object;
4276 };
4277
4278 if (scope.internal.getPageInfo(object.page).pageContext.annotations.find(findEntry) === undefined) {
4279 scope.internal.getPageInfo(object.page).pageContext.annotations.push(options);
4280 }
4281 }; // Callbacks
4282
4283
4284 var putCatalogCallback = function putCatalogCallback() {
4285 // Put reference to AcroForm to DocumentCatalog
4286 if (typeof scope.internal.acroformPlugin.acroFormDictionaryRoot != 'undefined') {
4287 // for safety, shouldn't normally be the case
4288 scope.internal.write('/AcroForm ' + scope.internal.acroformPlugin.acroFormDictionaryRoot.objId + ' ' + 0 + ' R');
4289 } else {
4290 throw new Error('putCatalogCallback: Root missing.');
4291 }
4292 };
4293 /**
4294 * Adds /Acroform X 0 R to Document Catalog, and creates the AcroForm
4295 * Dictionary
4296 */
4297
4298
4299 var AcroFormDictionaryCallback = function AcroFormDictionaryCallback() {
4300 // Remove event
4301 scope.internal.events.unsubscribe(scope.internal.acroformPlugin.acroFormDictionaryRoot._eventID);
4302 delete scope.internal.acroformPlugin.acroFormDictionaryRoot._eventID;
4303 scope.internal.acroformPlugin.printedOut = true;
4304 };
4305 /**
4306 * Creates the single Fields and writes them into the Document
4307 *
4308 * If fieldArray is set, use the fields that are inside it instead of the
4309 * fields from the AcroRoot (for the FormXObjects...)
4310 */
4311
4312
4313 var createFieldCallback = function createFieldCallback(fieldArray) {
4314 var standardFields = !fieldArray;
4315
4316 if (!fieldArray) {
4317 // in case there is no fieldArray specified, we want to print out
4318 // the Fields of the AcroForm
4319 // Print out Root
4320 scope.internal.newObjectDeferredBegin(scope.internal.acroformPlugin.acroFormDictionaryRoot.objId, true);
4321 scope.internal.acroformPlugin.acroFormDictionaryRoot.putStream();
4322 }
4323
4324 var fieldArray = fieldArray || scope.internal.acroformPlugin.acroFormDictionaryRoot.Kids;
4325
4326 for (var i in fieldArray) {
4327 if (fieldArray.hasOwnProperty(i)) {
4328 var fieldObject = fieldArray[i];
4329 var keyValueList = [];
4330 var oldRect = fieldObject.Rect;
4331
4332 if (fieldObject.Rect) {
4333 fieldObject.Rect = calculateCoordinates.call(this, fieldObject.Rect);
4334 } // Start Writing the Object
4335
4336
4337 scope.internal.newObjectDeferredBegin(fieldObject.objId, true);
4338 fieldObject.DA = AcroFormAppearance.createDefaultAppearanceStream(fieldObject);
4339
4340 if (_typeof(fieldObject) === "object" && typeof fieldObject.getKeyValueListForStream === "function") {
4341 keyValueList = fieldObject.getKeyValueListForStream();
4342 }
4343
4344 fieldObject.Rect = oldRect;
4345
4346 if (fieldObject.hasAppearanceStream && !fieldObject.appearanceStreamContent) {
4347 // Calculate Appearance
4348 var appearance = calculateAppearanceStream.call(this, fieldObject);
4349 keyValueList.push({
4350 key: 'AP',
4351 value: "<</N " + appearance + ">>"
4352 });
4353 scope.internal.acroformPlugin.xForms.push(appearance);
4354 } // Assume AppearanceStreamContent is a Array with N,R,D (at least
4355 // one of them!)
4356
4357
4358 if (fieldObject.appearanceStreamContent) {
4359 var appearanceStreamString = ""; // Iterate over N,R and D
4360
4361 for (var k in fieldObject.appearanceStreamContent) {
4362 if (fieldObject.appearanceStreamContent.hasOwnProperty(k)) {
4363 var value = fieldObject.appearanceStreamContent[k];
4364 appearanceStreamString += "/" + k + " ";
4365 appearanceStreamString += "<<";
4366
4367 if (Object.keys(value).length >= 1 || Array.isArray(value)) {
4368 // appearanceStream is an Array or Object!
4369 for (var i in value) {
4370 if (value.hasOwnProperty(i)) {
4371 var obj = value[i];
4372
4373 if (typeof obj === 'function') {
4374 // if Function is referenced, call it in order
4375 // to get the FormXObject
4376 obj = obj.call(this, fieldObject);
4377 }
4378
4379 appearanceStreamString += "/" + i + " " + obj + " "; // In case the XForm is already used, e.g. OffState
4380 // of CheckBoxes, don't add it
4381
4382 if (!(scope.internal.acroformPlugin.xForms.indexOf(obj) >= 0)) scope.internal.acroformPlugin.xForms.push(obj);
4383 }
4384 }
4385 } else {
4386 var obj = value;
4387
4388 if (typeof obj === 'function') {
4389 // if Function is referenced, call it in order to
4390 // get the FormXObject
4391 obj = obj.call(this, fieldObject);
4392 }
4393
4394 appearanceStreamString += "/" + i + " " + obj;
4395 if (!(scope.internal.acroformPlugin.xForms.indexOf(obj) >= 0)) scope.internal.acroformPlugin.xForms.push(obj);
4396 }
4397
4398 appearanceStreamString += ">>";
4399 }
4400 } // appearance stream is a normal Object..
4401
4402
4403 keyValueList.push({
4404 key: 'AP',
4405 value: "<<\n" + appearanceStreamString + ">>"
4406 });
4407 }
4408
4409 scope.internal.putStream({
4410 additionalKeyValues: keyValueList
4411 });
4412 scope.internal.out("endobj");
4413 }
4414 }
4415
4416 if (standardFields) {
4417 createXFormObjectCallback.call(this, scope.internal.acroformPlugin.xForms);
4418 }
4419 };
4420
4421 var createXFormObjectCallback = function createXFormObjectCallback(fieldArray) {
4422 for (var i in fieldArray) {
4423 if (fieldArray.hasOwnProperty(i)) {
4424 var key = i;
4425 var fieldObject = fieldArray[i]; // Start Writing the Object
4426
4427 scope.internal.newObjectDeferredBegin(fieldObject && fieldObject.objId, true);
4428
4429 if (_typeof(fieldObject) === "object" && typeof fieldObject.putStream === "function") {
4430 fieldObject.putStream();
4431 }
4432
4433 delete fieldArray[key];
4434 }
4435 }
4436 };
4437
4438 var initializeAcroForm = function initializeAcroForm() {
4439 if (this.internal !== undefined && (this.internal.acroformPlugin === undefined || this.internal.acroformPlugin.isInitialized === false)) {
4440 scope = this;
4441 AcroFormField.FieldNum = 0;
4442 this.internal.acroformPlugin = JSON.parse(JSON.stringify(acroformPluginTemplate));
4443
4444 if (this.internal.acroformPlugin.acroFormDictionaryRoot) {
4445 throw new Error("Exception while creating AcroformDictionary");
4446 }
4447
4448 scaleFactor = scope.internal.scaleFactor; // The Object Number of the AcroForm Dictionary
4449
4450 scope.internal.acroformPlugin.acroFormDictionaryRoot = new AcroFormDictionary(); // add Callback for creating the AcroForm Dictionary
4451
4452 scope.internal.acroformPlugin.acroFormDictionaryRoot._eventID = scope.internal.events.subscribe('postPutResources', AcroFormDictionaryCallback);
4453 scope.internal.events.subscribe('buildDocument', annotReferenceCallback); // buildDocument
4454 // Register event, that is triggered when the DocumentCatalog is
4455 // written, in order to add /AcroForm
4456
4457 scope.internal.events.subscribe('putCatalog', putCatalogCallback); // Register event, that creates all Fields
4458
4459 scope.internal.events.subscribe('postPutPages', createFieldCallback);
4460 scope.internal.acroformPlugin.isInitialized = true;
4461 }
4462 }; //PDF 32000-1:2008, page 26, 7.3.6
4463
4464
4465 var arrayToPdfArray = jsPDFAPI.__acroform__.arrayToPdfArray = function (array) {
4466 if (Array.isArray(array)) {
4467 var content = '[';
4468
4469 for (var i = 0; i < array.length; i++) {
4470 if (i !== 0) {
4471 content += ' ';
4472 }
4473
4474 switch (_typeof(array[i])) {
4475 case 'boolean':
4476 case 'number':
4477 case 'object':
4478 content += array[i].toString();
4479 break;
4480
4481 case 'string':
4482 if (array[i].substr(0, 1) !== '/') {
4483 content += '(' + pdfEscape(array[i].toString()) + ')';
4484 } else {
4485 content += array[i].toString();
4486 }
4487
4488 break;
4489 }
4490 }
4491
4492 content += ']';
4493 return content;
4494 }
4495
4496 throw new Error('Invalid argument passed to jsPDF.__acroform__.arrayToPdfArray');
4497 };
4498
4499 function getMatches(string, regex, index) {
4500 index || (index = 1); // default to the first capturing group
4501
4502 var matches = [];
4503 var match;
4504
4505 while (match = regex.exec(string)) {
4506 matches.push(match[index]);
4507 }
4508
4509 return matches;
4510 }
4511
4512 var pdfArrayToStringArray = function pdfArrayToStringArray(array) {
4513 var result = [];
4514
4515 if (typeof array === "string") {
4516 result = getMatches(array, /\((.*?)\)/g);
4517 }
4518
4519 return result;
4520 };
4521
4522 var toPdfString = function toPdfString(string) {
4523 string = string || "";
4524 string.toString();
4525 string = '(' + pdfEscape(string) + ')';
4526 return string;
4527 }; // ##########################
4528 // Classes
4529 // ##########################
4530
4531 /**
4532 * @class AcroFormPDFObject
4533 * @classdesc A AcroFormPDFObject
4534 */
4535
4536
4537 var AcroFormPDFObject = function AcroFormPDFObject() {
4538 var _objId;
4539 /** *
4540 * @name AcroFormPDFObject#objId
4541 * @type {any}
4542 */
4543
4544
4545 Object.defineProperty(this, 'objId', {
4546 configurable: true,
4547 get: function get() {
4548 if (!_objId) {
4549 _objId = scope.internal.newObjectDeferred();
4550 }
4551
4552 if (!_objId) {
4553 throw new Error("AcroFormPDFObject: Couldn't create Object ID");
4554 }
4555
4556 return _objId;
4557 },
4558 set: function set(value) {
4559 _objId = value;
4560 }
4561 });
4562 };
4563 /**
4564 * @function AcroFormPDFObject.toString
4565 */
4566
4567
4568 AcroFormPDFObject.prototype.toString = function () {
4569 return this.objId + " 0 R";
4570 };
4571
4572 AcroFormPDFObject.prototype.putStream = function () {
4573 var keyValueList = this.getKeyValueListForStream();
4574 scope.internal.putStream({
4575 data: this.stream,
4576 additionalKeyValues: keyValueList
4577 });
4578 scope.internal.out("endobj");
4579 };
4580 /**
4581 * Returns an key-value-List of all non-configurable Variables from the Object
4582 *
4583 * @name getKeyValueListForStream
4584 * @returns {string}
4585 */
4586
4587
4588 AcroFormPDFObject.prototype.getKeyValueListForStream = function () {
4589 var createKeyValueListFromFieldObject = function createKeyValueListFromFieldObject(fieldObject) {
4590 var keyValueList = [];
4591 var keys = Object.getOwnPropertyNames(fieldObject).filter(function (key) {
4592 return key != 'content' && key != 'appearanceStreamContent' && key.substring(0, 1) != "_";
4593 });
4594
4595 for (var i in keys) {
4596 if (Object.getOwnPropertyDescriptor(fieldObject, keys[i]).configurable === false) {
4597 var key = keys[i];
4598 var value = fieldObject[key];
4599
4600 if (value) {
4601 if (Array.isArray(value)) {
4602 keyValueList.push({
4603 key: key,
4604 value: arrayToPdfArray(value)
4605 });
4606 } else if (value instanceof AcroFormPDFObject) {
4607 // In case it is a reference to another PDFObject,
4608 // take the reference number
4609 keyValueList.push({
4610 key: key,
4611 value: value.objId + " 0 R"
4612 });
4613 } else if (typeof value !== "function") {
4614 keyValueList.push({
4615 key: key,
4616 value: value
4617 });
4618 }
4619 }
4620 }
4621 }
4622
4623 return keyValueList;
4624 };
4625
4626 return createKeyValueListFromFieldObject(this);
4627 };
4628
4629 var AcroFormXObject = function AcroFormXObject() {
4630 AcroFormPDFObject.call(this);
4631 Object.defineProperty(this, 'Type', {
4632 value: "/XObject",
4633 configurable: false,
4634 writeable: true
4635 });
4636 Object.defineProperty(this, 'Subtype', {
4637 value: "/Form",
4638 configurable: false,
4639 writeable: true
4640 });
4641 Object.defineProperty(this, 'FormType', {
4642 value: 1,
4643 configurable: false,
4644 writeable: true
4645 });
4646 var _BBox = [];
4647 Object.defineProperty(this, 'BBox', {
4648 configurable: false,
4649 writeable: true,
4650 get: function get() {
4651 return _BBox;
4652 },
4653 set: function set(value) {
4654 _BBox = value;
4655 }
4656 });
4657 Object.defineProperty(this, 'Resources', {
4658 value: "2 0 R",
4659 configurable: false,
4660 writeable: true
4661 });
4662
4663 var _stream;
4664
4665 Object.defineProperty(this, 'stream', {
4666 enumerable: false,
4667 configurable: true,
4668 set: function set(value) {
4669 _stream = value.trim();
4670 },
4671 get: function get() {
4672 if (_stream) {
4673 return _stream;
4674 } else {
4675 return null;
4676 }
4677 }
4678 });
4679 };
4680
4681 inherit(AcroFormXObject, AcroFormPDFObject);
4682
4683 var AcroFormDictionary = function AcroFormDictionary() {
4684 AcroFormPDFObject.call(this);
4685 var _Kids = [];
4686 Object.defineProperty(this, 'Kids', {
4687 enumerable: false,
4688 configurable: true,
4689 get: function get() {
4690 if (_Kids.length > 0) {
4691 return _Kids;
4692 } else {
4693 return;
4694 }
4695 }
4696 });
4697 Object.defineProperty(this, 'Fields', {
4698 enumerable: false,
4699 configurable: false,
4700 get: function get() {
4701 return _Kids;
4702 }
4703 }); // Default Appearance
4704
4705 var _DA;
4706
4707 Object.defineProperty(this, 'DA', {
4708 enumerable: false,
4709 configurable: false,
4710 get: function get() {
4711 if (!_DA) {
4712 return;
4713 }
4714
4715 return '(' + _DA + ')';
4716 },
4717 set: function set(value) {
4718 _DA = value;
4719 }
4720 });
4721 };
4722
4723 inherit(AcroFormDictionary, AcroFormPDFObject);
4724 /**
4725 * The Field Object contains the Variables, that every Field needs
4726 *
4727 * @class AcroFormField
4728 * @classdesc An AcroForm FieldObject
4729 */
4730
4731 var AcroFormField = function AcroFormField() {
4732 AcroFormPDFObject.call(this); //Annotation-Flag See Table 165
4733
4734 var _F = 4;
4735 Object.defineProperty(this, 'F', {
4736 enumerable: false,
4737 configurable: false,
4738 get: function get() {
4739 return _F;
4740 },
4741 set: function set(value) {
4742 if (!isNaN(value)) {
4743 _F = value;
4744 } else {
4745 throw new Error('Invalid value "' + value + '" for attribute F supplied.');
4746 }
4747 }
4748 });
4749 /**
4750 * (PDF 1.2) If set, print the annotation when the page is printed. If clear, never print the annotation, regardless of wether is is displayed on the screen.
4751 * NOTE 2 This can be useful for annotations representing interactive pushbuttons, which would serve no meaningful purpose on the printed page.
4752 *
4753 * @name AcroFormField#showWhenPrinted
4754 * @default true
4755 * @type {boolean}
4756 */
4757
4758 Object.defineProperty(this, 'showWhenPrinted', {
4759 enumerable: true,
4760 configurable: true,
4761 get: function get() {
4762 return Boolean(getBitForPdf(_F, 3));
4763 },
4764 set: function set(value) {
4765 if (Boolean(value) === true) {
4766 this.F = setBitForPdf(_F, 3);
4767 } else {
4768 this.F = clearBitForPdf(_F, 3);
4769 }
4770 }
4771 });
4772 var _Ff = 0;
4773 Object.defineProperty(this, 'Ff', {
4774 enumerable: false,
4775 configurable: false,
4776 get: function get() {
4777 return _Ff;
4778 },
4779 set: function set(value) {
4780 if (!isNaN(value)) {
4781 _Ff = value;
4782 } else {
4783 throw new Error('Invalid value "' + value + '" for attribute Ff supplied.');
4784 }
4785 }
4786 });
4787 var _Rect = [];
4788 Object.defineProperty(this, 'Rect', {
4789 enumerable: false,
4790 configurable: false,
4791 get: function get() {
4792 if (_Rect.length === 0) {
4793 return;
4794 }
4795
4796 return _Rect;
4797 },
4798 set: function set(value) {
4799 if (typeof value !== "undefined") {
4800 _Rect = value;
4801 } else {
4802 _Rect = [];
4803 }
4804 }
4805 });
4806 /**
4807 * The x-position of the field.
4808 *
4809 * @name AcroFormField#x
4810 * @default null
4811 * @type {number}
4812 */
4813
4814 Object.defineProperty(this, 'x', {
4815 enumerable: true,
4816 configurable: true,
4817 get: function get() {
4818 if (!_Rect || isNaN(_Rect[0])) {
4819 return 0;
4820 }
4821
4822 return antiScale(_Rect[0]);
4823 },
4824 set: function set(value) {
4825 _Rect[0] = scale(value);
4826 }
4827 });
4828 /**
4829 * The y-position of the field.
4830 *
4831 * @name AcroFormField#y
4832 * @default null
4833 * @type {number}
4834 */
4835
4836 Object.defineProperty(this, 'y', {
4837 enumerable: true,
4838 configurable: true,
4839 get: function get() {
4840 if (!_Rect || isNaN(_Rect[1])) {
4841 return 0;
4842 }
4843
4844 return antiScale(_Rect[1]);
4845 },
4846 set: function set(value) {
4847 _Rect[1] = scale(value);
4848 }
4849 });
4850 /**
4851 * The width of the field.
4852 *
4853 * @name AcroFormField#width
4854 * @default null
4855 * @type {number}
4856 */
4857
4858 Object.defineProperty(this, 'width', {
4859 enumerable: true,
4860 configurable: true,
4861 get: function get() {
4862 if (!_Rect || isNaN(_Rect[2])) {
4863 return 0;
4864 }
4865
4866 return antiScale(_Rect[2]);
4867 },
4868 set: function set(value) {
4869 _Rect[2] = scale(value);
4870 }
4871 });
4872 /**
4873 * The height of the field.
4874 *
4875 * @name AcroFormField#height
4876 * @default null
4877 * @type {number}
4878 */
4879
4880 Object.defineProperty(this, 'height', {
4881 enumerable: true,
4882 configurable: true,
4883 get: function get() {
4884 if (!_Rect || isNaN(_Rect[3])) {
4885 return 0;
4886 }
4887
4888 return antiScale(_Rect[3]);
4889 },
4890 set: function set(value) {
4891 _Rect[3] = scale(value);
4892 }
4893 });
4894 var _FT = "";
4895 Object.defineProperty(this, 'FT', {
4896 enumerable: true,
4897 configurable: false,
4898 get: function get() {
4899 return _FT;
4900 },
4901 set: function set(value) {
4902 switch (value) {
4903 case '/Btn':
4904 case '/Tx':
4905 case '/Ch':
4906 case '/Sig':
4907 _FT = value;
4908 break;
4909
4910 default:
4911 throw new Error('Invalid value "' + value + '" for attribute FT supplied.');
4912 }
4913 }
4914 });
4915 var _T = null;
4916 Object.defineProperty(this, 'T', {
4917 enumerable: true,
4918 configurable: false,
4919 get: function get() {
4920 if (!_T || _T.length < 1) {
4921 // In case of a Child from a Radio´Group, you don't need a FieldName
4922 if (this instanceof AcroFormChildClass) {
4923 return;
4924 }
4925
4926 _T = "FieldObject" + AcroFormField.FieldNum++;
4927 }
4928
4929 return '(' + pdfEscape(_T) + ')';
4930 },
4931 set: function set(value) {
4932 _T = value.toString();
4933 }
4934 });
4935 /**
4936 * (Optional) The partial field name (see 12.7.3.2, “Field Names”).
4937 *
4938 * @name AcroFormField#fieldName
4939 * @default null
4940 * @type {string}
4941 */
4942
4943 Object.defineProperty(this, 'fieldName', {
4944 configurable: true,
4945 enumerable: true,
4946 get: function get() {
4947 return _T;
4948 },
4949 set: function set(value) {
4950 _T = value;
4951 }
4952 });
4953 var _fontName = 'helvetica';
4954 /**
4955 * The fontName of the font to be used.
4956 *
4957 * @name AcroFormField#fontName
4958 * @default 'helvetica'
4959 * @type {string}
4960 */
4961
4962 Object.defineProperty(this, 'fontName', {
4963 enumerable: true,
4964 configurable: true,
4965 get: function get() {
4966 return _fontName;
4967 },
4968 set: function set(value) {
4969 _fontName = value;
4970 }
4971 });
4972 var _fontStyle = 'normal';
4973 /**
4974 * The fontStyle of the font to be used.
4975 *
4976 * @name AcroFormField#fontStyle
4977 * @default 'normal'
4978 * @type {string}
4979 */
4980
4981 Object.defineProperty(this, 'fontStyle', {
4982 enumerable: true,
4983 configurable: true,
4984 get: function get() {
4985 return _fontStyle;
4986 },
4987 set: function set(value) {
4988 _fontStyle = value;
4989 }
4990 });
4991 var _fontSize = 0;
4992 /**
4993 * The fontSize of the font to be used.
4994 *
4995 * @name AcroFormField#fontSize
4996 * @default 0 (for auto)
4997 * @type {number}
4998 */
4999
5000 Object.defineProperty(this, 'fontSize', {
5001 enumerable: true,
5002 configurable: true,
5003 get: function get() {
5004 return antiScale(_fontSize);
5005 },
5006 set: function set(value) {
5007 _fontSize = scale(value);
5008 }
5009 });
5010 var _maxFontSize = 50;
5011 /**
5012 * The maximum fontSize of the font to be used.
5013 *
5014 * @name AcroFormField#maxFontSize
5015 * @default 0 (for auto)
5016 * @type {number}
5017 */
5018
5019 Object.defineProperty(this, 'maxFontSize', {
5020 enumerable: true,
5021 configurable: true,
5022 get: function get() {
5023 return antiScale(_maxFontSize);
5024 },
5025 set: function set(value) {
5026 _maxFontSize = scale(value);
5027 }
5028 });
5029 var _color = 'black';
5030 /**
5031 * The color of the text
5032 *
5033 * @name AcroFormField#color
5034 * @default 'black'
5035 * @type {string|rgba}
5036 */
5037
5038 Object.defineProperty(this, 'color', {
5039 enumerable: true,
5040 configurable: true,
5041 get: function get() {
5042 return _color;
5043 },
5044 set: function set(value) {
5045 _color = value;
5046 }
5047 });
5048 var _DA = '/F1 0 Tf 0 g'; // Defines the default appearance (Needed for variable Text)
5049
5050 Object.defineProperty(this, 'DA', {
5051 enumerable: true,
5052 configurable: false,
5053 get: function get() {
5054 if (!_DA || this instanceof AcroFormChildClass || this instanceof AcroFormTextField) {
5055 return;
5056 }
5057
5058 return toPdfString(_DA);
5059 },
5060 set: function set(value) {
5061 value = value.toString();
5062 _DA = value;
5063 }
5064 });
5065 var _DV = null;
5066 Object.defineProperty(this, 'DV', {
5067 enumerable: false,
5068 configurable: false,
5069 get: function get() {
5070 if (!_DV) {
5071 return;
5072 }
5073
5074 if (this instanceof AcroFormButton === false) {
5075 return toPdfString(_DV);
5076 }
5077
5078 return _DV;
5079 },
5080 set: function set(value) {
5081 value = value.toString();
5082
5083 if (this instanceof AcroFormButton === false) {
5084 if (value.substr(0, 1) === '(') {
5085 _DV = pdfUnescape(value.substr(1, value.length - 2));
5086 } else {
5087 _DV = pdfUnescape(value);
5088 }
5089 } else {
5090 _DV = value;
5091 }
5092 }
5093 });
5094 /**
5095 * (Optional; inheritable) The default value to which the field reverts when a reset-form action is executed (see 12.7.5.3, “Reset-Form Action”). The format of this value is the same as that of value.
5096 *
5097 * @name AcroFormField#defaultValue
5098 * @default null
5099 * @type {any}
5100 */
5101
5102 Object.defineProperty(this, 'defaultValue', {
5103 enumerable: true,
5104 configurable: true,
5105 get: function get() {
5106 if (this instanceof AcroFormButton === true) {
5107 return pdfUnescape(_DV.substr(1, _DV.length - 1));
5108 } else {
5109 return _DV;
5110 }
5111 },
5112 set: function set(value) {
5113 value = value.toString();
5114
5115 if (this instanceof AcroFormButton === true) {
5116 _DV = '/' + value;
5117 } else {
5118 _DV = value;
5119 }
5120 }
5121 });
5122 var _V = null;
5123 Object.defineProperty(this, 'V', {
5124 enumerable: false,
5125 configurable: false,
5126 get: function get() {
5127 if (!_V) {
5128 return;
5129 }
5130
5131 if (this instanceof AcroFormButton === false) {
5132 return toPdfString(_V);
5133 }
5134
5135 return _V;
5136 },
5137 set: function set(value) {
5138 value = value.toString();
5139
5140 if (this instanceof AcroFormButton === false) {
5141 if (value.substr(0, 1) === '(') {
5142 _V = pdfUnescape(value.substr(1, value.length - 2));
5143 } else {
5144 _V = pdfUnescape(value);
5145 }
5146 } else {
5147 _V = value;
5148 }
5149 }
5150 });
5151 /**
5152 * (Optional; inheritable) The field’s value, whose format varies depending on the field type. See the descriptions of individual field types for further information.
5153 *
5154 * @name AcroFormField#value
5155 * @default null
5156 * @type {any}
5157 */
5158
5159 Object.defineProperty(this, 'value', {
5160 enumerable: true,
5161 configurable: true,
5162 get: function get() {
5163 if (this instanceof AcroFormButton === true) {
5164 return pdfUnescape(_V.substr(1, _V.length - 1));
5165 } else {
5166 return _V;
5167 }
5168 },
5169 set: function set(value) {
5170 value = value.toString();
5171
5172 if (this instanceof AcroFormButton === true) {
5173 _V = '/' + value;
5174 } else {
5175 _V = value;
5176 }
5177 }
5178 });
5179 /**
5180 * Check if field has annotations
5181 *
5182 * @name AcroFormField#hasAnnotation
5183 * @readonly
5184 * @type {boolean}
5185 */
5186
5187 Object.defineProperty(this, 'hasAnnotation', {
5188 enumerable: true,
5189 configurable: true,
5190 get: function get() {
5191 return this.Rect;
5192 }
5193 });
5194 Object.defineProperty(this, 'Type', {
5195 enumerable: true,
5196 configurable: false,
5197 get: function get() {
5198 return this.hasAnnotation ? "/Annot" : null;
5199 }
5200 });
5201 Object.defineProperty(this, 'Subtype', {
5202 enumerable: true,
5203 configurable: false,
5204 get: function get() {
5205 return this.hasAnnotation ? "/Widget" : null;
5206 }
5207 });
5208 var _hasAppearanceStream = false;
5209 /**
5210 * true if field has an appearanceStream
5211 *
5212 * @name AcroFormField#hasAppearanceStream
5213 * @readonly
5214 * @type {boolean}
5215 */
5216
5217 Object.defineProperty(this, 'hasAppearanceStream', {
5218 enumerable: true,
5219 configurable: true,
5220 writeable: true,
5221 get: function get() {
5222 return _hasAppearanceStream;
5223 },
5224 set: function set(value) {
5225 value = Boolean(value);
5226 _hasAppearanceStream = value;
5227 }
5228 });
5229 /**
5230 * The page on which the AcroFormField is placed
5231 *
5232 * @name AcroFormField#page
5233 * @type {number}
5234 */
5235
5236 var _page;
5237
5238 Object.defineProperty(this, 'page', {
5239 enumerable: true,
5240 configurable: true,
5241 writeable: true,
5242 get: function get() {
5243 if (!_page) {
5244 return;
5245 }
5246
5247 return _page;
5248 },
5249 set: function set(value) {
5250 _page = value;
5251 }
5252 });
5253 /**
5254 * If set, the user may not change the value of the field. Any associated widget annotations will not interact with the user; that is, they will not respond to mouse clicks or change their appearance in response to mouse motions. This flag is useful for fields whose values are computed or imported from a database.
5255 *
5256 * @name AcroFormField#readOnly
5257 * @default false
5258 * @type {boolean}
5259 */
5260
5261 Object.defineProperty(this, 'readOnly', {
5262 enumerable: true,
5263 configurable: true,
5264 get: function get() {
5265 return Boolean(getBitForPdf(this.Ff, 1));
5266 },
5267 set: function set(value) {
5268 if (Boolean(value) === true) {
5269 this.Ff = setBitForPdf(this.Ff, 1);
5270 } else {
5271 this.Ff = clearBitForPdf(this.Ff, 1);
5272 }
5273 }
5274 });
5275 /**
5276 * If set, the field shall have a value at the time it is exported by a submitform action (see 12.7.5.2, “Submit-Form Action”).
5277 *
5278 * @name AcroFormField#required
5279 * @default false
5280 * @type {boolean}
5281 */
5282
5283 Object.defineProperty(this, 'required', {
5284 enumerable: true,
5285 configurable: true,
5286 get: function get() {
5287 return Boolean(getBitForPdf(this.Ff, 2));
5288 },
5289 set: function set(value) {
5290 if (Boolean(value) === true) {
5291 this.Ff = setBitForPdf(this.Ff, 2);
5292 } else {
5293 this.Ff = clearBitForPdf(this.Ff, 2);
5294 }
5295 }
5296 });
5297 /**
5298 * If set, the field shall not be exported by a submit-form action (see 12.7.5.2, “Submit-Form Action”)
5299 *
5300 * @name AcroFormField#noExport
5301 * @default false
5302 * @type {boolean}
5303 */
5304
5305 Object.defineProperty(this, 'noExport', {
5306 enumerable: true,
5307 configurable: true,
5308 get: function get() {
5309 return Boolean(getBitForPdf(this.Ff, 3));
5310 },
5311 set: function set(value) {
5312 if (Boolean(value) === true) {
5313 this.Ff = setBitForPdf(this.Ff, 3);
5314 } else {
5315 this.Ff = clearBitForPdf(this.Ff, 3);
5316 }
5317 }
5318 });
5319 var _Q = null;
5320 Object.defineProperty(this, 'Q', {
5321 enumerable: true,
5322 configurable: false,
5323 get: function get() {
5324 if (_Q === null) {
5325 return;
5326 }
5327
5328 return _Q;
5329 },
5330 set: function set(value) {
5331 if ([0, 1, 2].indexOf(value) !== -1) {
5332 _Q = value;
5333 } else {
5334 throw new Error('Invalid value "' + value + '" for attribute Q supplied.');
5335 }
5336 }
5337 });
5338 /**
5339 * (Optional; inheritable) A code specifying the form of quadding (justification) that shall be used in displaying the text:
5340 * 'left', 'center', 'right'
5341 *
5342 * @name AcroFormField#textAlign
5343 * @default 'left'
5344 * @type {string}
5345 */
5346
5347 Object.defineProperty(this, 'textAlign', {
5348 get: function get() {
5349 var result = 'left';
5350
5351 switch (_Q) {
5352 case 0:
5353 default:
5354 result = 'left';
5355 break;
5356
5357 case 1:
5358 result = 'center';
5359 break;
5360
5361 case 2:
5362 result = 'right';
5363 break;
5364 }
5365
5366 return result;
5367 },
5368 configurable: true,
5369 enumerable: true,
5370 set: function set(value) {
5371 switch (value) {
5372 case 'right':
5373 case 2:
5374 _Q = 2;
5375 break;
5376
5377 case 'center':
5378 case 1:
5379 _Q = 1;
5380 break;
5381
5382 case 'left':
5383 case 0:
5384 default:
5385 _Q = 0;
5386 }
5387 }
5388 });
5389 };
5390
5391 inherit(AcroFormField, AcroFormPDFObject);
5392 /**
5393 * @class AcroFormChoiceField
5394 * @extends AcroFormField
5395 */
5396
5397 var AcroFormChoiceField = function AcroFormChoiceField() {
5398 AcroFormField.call(this); // Field Type = Choice Field
5399
5400 this.FT = "/Ch"; // options
5401
5402 this.V = '()';
5403 this.fontName = 'zapfdingbats'; // Top Index
5404
5405 var _TI = 0;
5406 Object.defineProperty(this, 'TI', {
5407 enumerable: true,
5408 configurable: false,
5409 get: function get() {
5410 return _TI;
5411 },
5412 set: function set(value) {
5413 _TI = value;
5414 }
5415 });
5416 /**
5417 * (Optional) For scrollable list boxes, the top index (the index in the Opt array of the first option visible in the list). Default value: 0.
5418 *
5419 * @name AcroFormChoiceField#topIndex
5420 * @default 0
5421 * @type {number}
5422 */
5423
5424 Object.defineProperty(this, 'topIndex', {
5425 enumerable: true,
5426 configurable: true,
5427 get: function get() {
5428 return _TI;
5429 },
5430 set: function set(value) {
5431 _TI = value;
5432 }
5433 });
5434 var _Opt = [];
5435 Object.defineProperty(this, 'Opt', {
5436 enumerable: true,
5437 configurable: false,
5438 get: function get() {
5439 return arrayToPdfArray(_Opt);
5440 },
5441 set: function set(value) {
5442 _Opt = pdfArrayToStringArray(value);
5443 }
5444 });
5445 /**
5446 * @memberof AcroFormChoiceField
5447 * @name getOptions
5448 * @function
5449 * @instance
5450 * @returns {array} array of Options
5451 */
5452
5453 this.getOptions = function () {
5454 return _Opt;
5455 };
5456 /**
5457 * @memberof AcroFormChoiceField
5458 * @name setOptions
5459 * @function
5460 * @instance
5461 * @param {array} value
5462 */
5463
5464
5465 this.setOptions = function (value) {
5466 _Opt = value;
5467
5468 if (this.sort) {
5469 _Opt.sort();
5470 }
5471 };
5472 /**
5473 * @memberof AcroFormChoiceField
5474 * @name addOption
5475 * @function
5476 * @instance
5477 * @param {string} value
5478 */
5479
5480
5481 this.addOption = function (value) {
5482 value = value || "";
5483 value = value.toString();
5484
5485 _Opt.push(value);
5486
5487 if (this.sort) {
5488 _Opt.sort();
5489 }
5490 };
5491 /**
5492 * @memberof AcroFormChoiceField
5493 * @name removeOption
5494 * @function
5495 * @instance
5496 * @param {string} value
5497 * @param {boolean} allEntries (default: false)
5498 */
5499
5500
5501 this.removeOption = function (value, allEntries) {
5502 allEntries = allEntries || false;
5503 value = value || "";
5504 value = value.toString();
5505
5506 while (_Opt.indexOf(value) !== -1) {
5507 _Opt.splice(_Opt.indexOf(value), 1);
5508
5509 if (allEntries === false) {
5510 break;
5511 }
5512 }
5513 };
5514 /**
5515 * If set, the field is a combo box; if clear, the field is a list box.
5516 *
5517 * @name AcroFormChoiceField#combo
5518 * @default false
5519 * @type {boolean}
5520 */
5521
5522
5523 Object.defineProperty(this, 'combo', {
5524 enumerable: true,
5525 configurable: true,
5526 get: function get() {
5527 return Boolean(getBitForPdf(this.Ff, 18));
5528 },
5529 set: function set(value) {
5530 if (Boolean(value) === true) {
5531 this.Ff = setBitForPdf(this.Ff, 18);
5532 } else {
5533 this.Ff = clearBitForPdf(this.Ff, 18);
5534 }
5535 }
5536 });
5537 /**
5538 * If set, the combo box shall include an editable text box as well as a drop-down list; if clear, it shall include only a drop-down list. This flag shall be used only if the Combo flag is set.
5539 *
5540 * @name AcroFormChoiceField#edit
5541 * @default false
5542 * @type {boolean}
5543 */
5544
5545 Object.defineProperty(this, 'edit', {
5546 enumerable: true,
5547 configurable: true,
5548 get: function get() {
5549 return Boolean(getBitForPdf(this.Ff, 19));
5550 },
5551 set: function set(value) {
5552 //PDF 32000-1:2008, page 444
5553 if (this.combo === true) {
5554 if (Boolean(value) === true) {
5555 this.Ff = setBitForPdf(this.Ff, 19);
5556 } else {
5557 this.Ff = clearBitForPdf(this.Ff, 19);
5558 }
5559 }
5560 }
5561 });
5562 /**
5563 * If set, the field’s option items shall be sorted alphabetically. This flag is intended for use by writers, not by readers. Conforming readers shall display the options in the order in which they occur in the Opt array (see Table 231).
5564 *
5565 * @name AcroFormChoiceField#sort
5566 * @default false
5567 * @type {boolean}
5568 */
5569
5570 Object.defineProperty(this, 'sort', {
5571 enumerable: true,
5572 configurable: true,
5573 get: function get() {
5574 return Boolean(getBitForPdf(this.Ff, 20));
5575 },
5576 set: function set(value) {
5577 if (Boolean(value) === true) {
5578 this.Ff = setBitForPdf(this.Ff, 20);
5579
5580 _Opt.sort();
5581 } else {
5582 this.Ff = clearBitForPdf(this.Ff, 20);
5583 }
5584 }
5585 });
5586 /**
5587 * (PDF 1.4) If set, more than one of the field’s option items may be selected simultaneously; if clear, at most one item shall be selected
5588 *
5589 * @name AcroFormChoiceField#multiSelect
5590 * @default false
5591 * @type {boolean}
5592 */
5593
5594 Object.defineProperty(this, 'multiSelect', {
5595 enumerable: true,
5596 configurable: true,
5597 get: function get() {
5598 return Boolean(getBitForPdf(this.Ff, 22));
5599 },
5600 set: function set(value) {
5601 if (Boolean(value) === true) {
5602 this.Ff = setBitForPdf(this.Ff, 22);
5603 } else {
5604 this.Ff = clearBitForPdf(this.Ff, 22);
5605 }
5606 }
5607 });
5608 /**
5609 * (PDF 1.4) If set, text entered in the field shall not be spellchecked. This flag shall not be used unless the Combo and Edit flags are both set.
5610 *
5611 * @name AcroFormChoiceField#doNotSpellCheck
5612 * @default false
5613 * @type {boolean}
5614 */
5615
5616 Object.defineProperty(this, 'doNotSpellCheck', {
5617 enumerable: true,
5618 configurable: true,
5619 get: function get() {
5620 return Boolean(getBitForPdf(this.Ff, 23));
5621 },
5622 set: function set(value) {
5623 if (Boolean(value) === true) {
5624 this.Ff = setBitForPdf(this.Ff, 23);
5625 } else {
5626 this.Ff = clearBitForPdf(this.Ff, 23);
5627 }
5628 }
5629 });
5630 /**
5631 * (PDF 1.5) If set, the new value shall be committed as soon as a selection is made (commonly with the pointing device). In this case, supplying a value for a field involves three actions: selecting the field for fill-in, selecting a choice for the fill-in value, and leaving that field, which finalizes or “commits” the data choice and triggers any actions associated with the entry or changing of this data. If this flag is on, then processing does not wait for leaving the field action to occur, but immediately proceeds to the third step.
5632 * This option enables applications to perform an action once a selection is made, without requiring the user to exit the field. If clear, the new value is not committed until the user exits the field.
5633 *
5634 * @name AcroFormChoiceField#commitOnSelChange
5635 * @default false
5636 * @type {boolean}
5637 */
5638
5639 Object.defineProperty(this, 'commitOnSelChange', {
5640 enumerable: true,
5641 configurable: true,
5642 get: function get() {
5643 return Boolean(getBitForPdf(this.Ff, 27));
5644 },
5645 set: function set(value) {
5646 if (Boolean(value) === true) {
5647 this.Ff = setBitForPdf(this.Ff, 27);
5648 } else {
5649 this.Ff = clearBitForPdf(this.Ff, 27);
5650 }
5651 }
5652 });
5653 this.hasAppearanceStream = false;
5654 };
5655
5656 inherit(AcroFormChoiceField, AcroFormField);
5657 /**
5658 * @class AcroFormListBox
5659 * @extends AcroFormChoiceField
5660 * @extends AcroFormField
5661 */
5662
5663 var AcroFormListBox = function AcroFormListBox() {
5664 AcroFormChoiceField.call(this);
5665 this.fontName = 'helvetica'; //PDF 32000-1:2008, page 444
5666
5667 this.combo = false;
5668 };
5669
5670 inherit(AcroFormListBox, AcroFormChoiceField);
5671 /**
5672 * @class AcroFormComboBox
5673 * @extends AcroFormListBox
5674 * @extends AcroFormChoiceField
5675 * @extends AcroFormField
5676 */
5677
5678 var AcroFormComboBox = function AcroFormComboBox() {
5679 AcroFormListBox.call(this);
5680 this.combo = true;
5681 };
5682
5683 inherit(AcroFormComboBox, AcroFormListBox);
5684 /**
5685 * @class AcroFormEditBox
5686 * @extends AcroFormComboBox
5687 * @extends AcroFormListBox
5688 * @extends AcroFormChoiceField
5689 * @extends AcroFormField
5690 */
5691
5692 var AcroFormEditBox = function AcroFormEditBox() {
5693 AcroFormComboBox.call(this);
5694 this.edit = true;
5695 };
5696
5697 inherit(AcroFormEditBox, AcroFormComboBox);
5698 /**
5699 * @class AcroFormButton
5700 * @extends AcroFormField
5701 */
5702
5703 var AcroFormButton = function AcroFormButton() {
5704 AcroFormField.call(this);
5705 this.FT = "/Btn";
5706 /**
5707 * (Radio buttons only) If set, exactly one radio button shall be selected at all times; selecting the currently selected button has no effect. If clear, clicking the selected button deselects it, leaving no button selected.
5708 *
5709 * @name AcroFormButton#noToggleToOff
5710 * @type {boolean}
5711 */
5712
5713 Object.defineProperty(this, 'noToggleToOff', {
5714 enumerable: true,
5715 configurable: true,
5716 get: function get() {
5717 return Boolean(getBitForPdf(this.Ff, 15));
5718 },
5719 set: function set(value) {
5720 if (Boolean(value) === true) {
5721 this.Ff = setBitForPdf(this.Ff, 15);
5722 } else {
5723 this.Ff = clearBitForPdf(this.Ff, 15);
5724 }
5725 }
5726 });
5727 /**
5728 * If set, the field is a set of radio buttons; if clear, the field is a checkbox. This flag may be set only if the Pushbutton flag is clear.
5729 *
5730 * @name AcroFormButton#radio
5731 * @type {boolean}
5732 */
5733
5734 Object.defineProperty(this, 'radio', {
5735 enumerable: true,
5736 configurable: true,
5737 get: function get() {
5738 return Boolean(getBitForPdf(this.Ff, 16));
5739 },
5740 set: function set(value) {
5741 if (Boolean(value) === true) {
5742 this.Ff = setBitForPdf(this.Ff, 16);
5743 } else {
5744 this.Ff = clearBitForPdf(this.Ff, 16);
5745 }
5746 }
5747 });
5748 /**
5749 * If set, the field is a pushbutton that does not retain a permanent value.
5750 *
5751 * @name AcroFormButton#pushButton
5752 * @type {boolean}
5753 */
5754
5755 Object.defineProperty(this, 'pushButton', {
5756 enumerable: true,
5757 configurable: true,
5758 get: function get() {
5759 return Boolean(getBitForPdf(this.Ff, 17));
5760 },
5761 set: function set(value) {
5762 if (Boolean(value) === true) {
5763 this.Ff = setBitForPdf(this.Ff, 17);
5764 } else {
5765 this.Ff = clearBitForPdf(this.Ff, 17);
5766 }
5767 }
5768 });
5769 /**
5770 * (PDF 1.5) If set, a group of radio buttons within a radio button field that use the same value for the on state will turn on and off in unison; that is if one is checked, they are all checked. If clear, the buttons are mutually exclusive (the same behavior as HTML radio buttons).
5771 *
5772 * @name AcroFormButton#radioIsUnison
5773 * @type {boolean}
5774 */
5775
5776 Object.defineProperty(this, 'radioIsUnison', {
5777 enumerable: true,
5778 configurable: true,
5779 get: function get() {
5780 return Boolean(getBitForPdf(this.Ff, 26));
5781 },
5782 set: function set(value) {
5783 if (Boolean(value) === true) {
5784 this.Ff = setBitForPdf(this.Ff, 26);
5785 } else {
5786 this.Ff = clearBitForPdf(this.Ff, 26);
5787 }
5788 }
5789 });
5790 var _MK = {};
5791 Object.defineProperty(this, 'MK', {
5792 enumerable: false,
5793 configurable: false,
5794 get: function get() {
5795 if (Object.keys(_MK).length !== 0) {
5796 var result = [];
5797 result.push('<<');
5798 var key;
5799
5800 for (key in _MK) {
5801 result.push('/' + key + ' (' + _MK[key] + ')');
5802 }
5803
5804 result.push('>>');
5805 return result.join('\n');
5806 }
5807
5808 return;
5809 },
5810 set: function set(value) {
5811 if (_typeof(value) === "object") {
5812 _MK = value;
5813 }
5814 }
5815 });
5816 /**
5817 * From the PDF reference:
5818 * (Optional, button fields only) The widget annotation's normal caption which shall be displayed when it is not interacting with the user.
5819 * Unlike the remaining entries listed in this Table which apply only to widget annotations associated with pushbutton fields (see Pushbuttons in 12.7.4.2, "Button Fields"), the CA entry may be used with any type of button field, including check boxes (see Check Boxes in 12.7.4.2, "Button Fields") and radio buttons (Radio Buttons in 12.7.4.2, "Button Fields").
5820 *
5821 * - '8' = Cross,
5822 * - 'l' = Circle,
5823 * - '' = nothing
5824 * @name AcroFormButton#caption
5825 * @type {string}
5826 */
5827
5828 Object.defineProperty(this, 'caption', {
5829 enumerable: true,
5830 configurable: true,
5831 get: function get() {
5832 return _MK.CA || '';
5833 },
5834 set: function set(value) {
5835 if (typeof value === "string") {
5836 _MK.CA = value;
5837 }
5838 }
5839 });
5840
5841 var _AS;
5842
5843 Object.defineProperty(this, 'AS', {
5844 enumerable: false,
5845 configurable: false,
5846 get: function get() {
5847 return _AS;
5848 },
5849 set: function set(value) {
5850 _AS = value;
5851 }
5852 });
5853 /**
5854 * (Required if the appearance dictionary AP contains one or more subdictionaries; PDF 1.2) The annotation's appearance state, which selects the applicable appearance stream from an appearance subdictionary (see Section 12.5.5, "Appearance Streams")
5855 *
5856 * @name AcroFormButton#appearanceState
5857 * @type {any}
5858 */
5859
5860 Object.defineProperty(this, 'appearanceState', {
5861 enumerable: true,
5862 configurable: true,
5863 get: function get() {
5864 return _AS.substr(1, _AS.length - 1);
5865 },
5866 set: function set(value) {
5867 _AS = '/' + value;
5868 }
5869 });
5870 };
5871
5872 inherit(AcroFormButton, AcroFormField);
5873 /**
5874 * @class AcroFormPushButton
5875 * @extends AcroFormButton
5876 * @extends AcroFormField
5877 */
5878
5879 var AcroFormPushButton = function AcroFormPushButton() {
5880 AcroFormButton.call(this);
5881 this.pushButton = true;
5882 };
5883
5884 inherit(AcroFormPushButton, AcroFormButton);
5885 /**
5886 * @class AcroFormRadioButton
5887 * @extends AcroFormButton
5888 * @extends AcroFormField
5889 */
5890
5891 var AcroFormRadioButton = function AcroFormRadioButton() {
5892 AcroFormButton.call(this);
5893 this.radio = true;
5894 this.pushButton = false;
5895 var _Kids = [];
5896 Object.defineProperty(this, 'Kids', {
5897 enumerable: true,
5898 configurable: false,
5899 get: function get() {
5900 return _Kids;
5901 },
5902 set: function set(value) {
5903 if (typeof value !== "undefined") {
5904 _Kids = value;
5905 } else {
5906 _Kids = [];
5907 }
5908 }
5909 });
5910 };
5911
5912 inherit(AcroFormRadioButton, AcroFormButton);
5913 /**
5914 * The Child class of a RadioButton (the radioGroup) -> The single Buttons
5915 *
5916 * @class AcroFormChildClass
5917 * @extends AcroFormField
5918 * @ignore
5919 */
5920
5921 var AcroFormChildClass = function AcroFormChildClass() {
5922 AcroFormField.call(this);
5923
5924 var _parent;
5925
5926 Object.defineProperty(this, 'Parent', {
5927 enumerable: false,
5928 configurable: false,
5929 get: function get() {
5930 return _parent;
5931 },
5932 set: function set(value) {
5933 _parent = value;
5934 }
5935 });
5936
5937 var _optionName;
5938
5939 Object.defineProperty(this, 'optionName', {
5940 enumerable: false,
5941 configurable: true,
5942 get: function get() {
5943 return _optionName;
5944 },
5945 set: function set(value) {
5946 _optionName = value;
5947 }
5948 });
5949 var _MK = {};
5950 Object.defineProperty(this, 'MK', {
5951 enumerable: false,
5952 configurable: false,
5953 get: function get() {
5954 var result = [];
5955 result.push('<<');
5956 var key;
5957
5958 for (key in _MK) {
5959 result.push('/' + key + ' (' + _MK[key] + ')');
5960 }
5961
5962 result.push('>>');
5963 return result.join('\n');
5964 },
5965 set: function set(value) {
5966 if (_typeof(value) === "object") {
5967 _MK = value;
5968 }
5969 }
5970 });
5971 /**
5972 * From the PDF reference:
5973 * (Optional, button fields only) The widget annotation's normal caption which shall be displayed when it is not interacting with the user.
5974 * Unlike the remaining entries listed in this Table which apply only to widget annotations associated with pushbutton fields (see Pushbuttons in 12.7.4.2, "Button Fields"), the CA entry may be used with any type of button field, including check boxes (see Check Boxes in 12.7.4.2, "Button Fields") and radio buttons (Radio Buttons in 12.7.4.2, "Button Fields").
5975 *
5976 * - '8' = Cross,
5977 * - 'l' = Circle,
5978 * - '' = nothing
5979 * @name AcroFormButton#caption
5980 * @type {string}
5981 */
5982
5983 Object.defineProperty(this, 'caption', {
5984 enumerable: true,
5985 configurable: true,
5986 get: function get() {
5987 return _MK.CA || '';
5988 },
5989 set: function set(value) {
5990 if (typeof value === "string") {
5991 _MK.CA = value;
5992 }
5993 }
5994 });
5995
5996 var _AS;
5997
5998 Object.defineProperty(this, 'AS', {
5999 enumerable: false,
6000 configurable: false,
6001 get: function get() {
6002 return _AS;
6003 },
6004 set: function set(value) {
6005 _AS = value;
6006 }
6007 });
6008 /**
6009 * (Required if the appearance dictionary AP contains one or more subdictionaries; PDF 1.2) The annotation's appearance state, which selects the applicable appearance stream from an appearance subdictionary (see Section 12.5.5, "Appearance Streams")
6010 *
6011 * @name AcroFormButton#appearanceState
6012 * @type {any}
6013 */
6014
6015 Object.defineProperty(this, 'appearanceState', {
6016 enumerable: true,
6017 configurable: true,
6018 get: function get() {
6019 return _AS.substr(1, _AS.length - 1);
6020 },
6021 set: function set(value) {
6022 _AS = '/' + value;
6023 }
6024 });
6025 this.optionName = name;
6026 this.caption = 'l';
6027 this.appearanceState = 'Off'; // todo: set AppearanceType as variable that can be set from the
6028 // outside...
6029
6030 this._AppearanceType = AcroFormAppearance.RadioButton.Circle; // The Default appearanceType is the Circle
6031
6032 this.appearanceStreamContent = this._AppearanceType.createAppearanceStream(name);
6033 };
6034
6035 inherit(AcroFormChildClass, AcroFormField);
6036
6037 AcroFormRadioButton.prototype.setAppearance = function (appearance) {
6038 if (!('createAppearanceStream' in appearance && 'getCA' in appearance)) {
6039 throw new Error("Couldn't assign Appearance to RadioButton. Appearance was Invalid!");
6040 return;
6041 }
6042
6043 for (var objId in this.Kids) {
6044 if (this.Kids.hasOwnProperty(objId)) {
6045 var child = this.Kids[objId];
6046 child.appearanceStreamContent = appearance.createAppearanceStream(child.optionName);
6047 child.caption = appearance.getCA();
6048 }
6049 }
6050 };
6051
6052 AcroFormRadioButton.prototype.createOption = function (name) {
6053 var kidCount = this.Kids.length; // Create new Child for RadioGroup
6054
6055 var child = new AcroFormChildClass();
6056 child.Parent = this;
6057 child.optionName = name; // Add to Parent
6058
6059 this.Kids.push(child);
6060 addField.call(this, child);
6061 return child;
6062 };
6063 /**
6064 * @class AcroFormCheckBox
6065 * @extends AcroFormButton
6066 * @extends AcroFormField
6067 */
6068
6069
6070 var AcroFormCheckBox = function AcroFormCheckBox() {
6071 AcroFormButton.call(this);
6072 this.fontName = 'zapfdingbats';
6073 this.caption = '3';
6074 this.appearanceState = 'On';
6075 this.value = "On";
6076 this.textAlign = 'center';
6077 this.appearanceStreamContent = AcroFormAppearance.CheckBox.createAppearanceStream();
6078 };
6079
6080 inherit(AcroFormCheckBox, AcroFormButton);
6081 /**
6082 * @class AcroFormTextField
6083 * @extends AcroFormField
6084 */
6085
6086 var AcroFormTextField = function AcroFormTextField() {
6087 AcroFormField.call(this);
6088 this.FT = '/Tx';
6089 /**
6090 * If set, the field may contain multiple lines of text; if clear, the field’s text shall be restricted to a single line.
6091 *
6092 * @name AcroFormTextField#multiline
6093 * @type {boolean}
6094 */
6095
6096 Object.defineProperty(this, 'multiline', {
6097 enumerable: true,
6098 configurable: true,
6099 get: function get() {
6100 return Boolean(getBitForPdf(this.Ff, 13));
6101 },
6102 set: function set(value) {
6103 if (Boolean(value) === true) {
6104 this.Ff = setBitForPdf(this.Ff, 13);
6105 } else {
6106 this.Ff = clearBitForPdf(this.Ff, 13);
6107 }
6108 }
6109 });
6110 /**
6111 * (PDF 1.4) If set, the text entered in the field represents the pathname of a file whose contents shall be submitted as the value of the field.
6112 *
6113 * @name AcroFormTextField#fileSelect
6114 * @type {boolean}
6115 */
6116
6117 Object.defineProperty(this, 'fileSelect', {
6118 enumerable: true,
6119 configurable: true,
6120 get: function get() {
6121 return Boolean(getBitForPdf(this.Ff, 21));
6122 },
6123 set: function set(value) {
6124 if (Boolean(value) === true) {
6125 this.Ff = setBitForPdf(this.Ff, 21);
6126 } else {
6127 this.Ff = clearBitForPdf(this.Ff, 21);
6128 }
6129 }
6130 });
6131 /**
6132 * (PDF 1.4) If set, text entered in the field shall not be spell-checked.
6133 *
6134 * @name AcroFormTextField#doNotSpellCheck
6135 * @type {boolean}
6136 */
6137
6138 Object.defineProperty(this, 'doNotSpellCheck', {
6139 enumerable: true,
6140 configurable: true,
6141 get: function get() {
6142 return Boolean(getBitForPdf(this.Ff, 23));
6143 },
6144 set: function set(value) {
6145 if (Boolean(value) === true) {
6146 this.Ff = setBitForPdf(this.Ff, 23);
6147 } else {
6148 this.Ff = clearBitForPdf(this.Ff, 23);
6149 }
6150 }
6151 });
6152 /**
6153 * (PDF 1.4) If set, the field shall not scroll (horizontally for single-line fields, vertically for multiple-line fields) to accommodate more text than fits within its annotation rectangle. Once the field is full, no further text shall be accepted for interactive form filling; for noninteractive form filling, the filler should take care not to add more character than will visibly fit in the defined area.
6154 *
6155 * @name AcroFormTextField#doNotScroll
6156 * @type {boolean}
6157 */
6158
6159 Object.defineProperty(this, 'doNotScroll', {
6160 enumerable: true,
6161 configurable: true,
6162 get: function get() {
6163 return Boolean(getBitForPdf(this.Ff, 24));
6164 },
6165 set: function set(value) {
6166 if (Boolean(value) === true) {
6167 this.Ff = setBitForPdf(this.Ff, 24);
6168 } else {
6169 this.Ff = clearBitForPdf(this.Ff, 24);
6170 }
6171 }
6172 });
6173 /**
6174 * (PDF 1.5) May be set only if the MaxLen entry is present in the text field dictionary (see Table 229) and if the Multiline, Password, and FileSelect flags are clear. If set, the field shall be automatically divided into as many equally spaced positions, or combs, as the value of MaxLen, and the text is laid out into those combs.
6175 *
6176 * @name AcroFormTextField#comb
6177 * @type {boolean}
6178 */
6179
6180 Object.defineProperty(this, 'comb', {
6181 enumerable: true,
6182 configurable: true,
6183 get: function get() {
6184 return Boolean(getBitForPdf(this.Ff, 25));
6185 },
6186 set: function set(value) {
6187 if (Boolean(value) === true) {
6188 this.Ff = setBitForPdf(this.Ff, 25);
6189 } else {
6190 this.Ff = clearBitForPdf(this.Ff, 25);
6191 }
6192 }
6193 });
6194 /**
6195 * (PDF 1.5) If set, the value of this field shall be a rich text string (see 12.7.3.4, “Rich Text Strings”). If the field has a value, the RV entry of the field dictionary (Table 222) shall specify the rich text string.
6196 *
6197 * @name AcroFormTextField#richText
6198 * @type {boolean}
6199 */
6200
6201 Object.defineProperty(this, 'richText', {
6202 enumerable: true,
6203 configurable: true,
6204 get: function get() {
6205 return Boolean(getBitForPdf(this.Ff, 26));
6206 },
6207 set: function set(value) {
6208 if (Boolean(value) === true) {
6209 this.Ff = setBitForPdf(this.Ff, 26);
6210 } else {
6211 this.Ff = clearBitForPdf(this.Ff, 26);
6212 }
6213 }
6214 });
6215 var _MaxLen = null;
6216 Object.defineProperty(this, 'MaxLen', {
6217 enumerable: true,
6218 configurable: false,
6219 get: function get() {
6220 return _MaxLen;
6221 },
6222 set: function set(value) {
6223 _MaxLen = value;
6224 }
6225 });
6226 /**
6227 * (Optional; inheritable) The maximum length of the field’s text, in characters.
6228 *
6229 * @name AcroFormTextField#maxLength
6230 * @type {number}
6231 */
6232
6233 Object.defineProperty(this, 'maxLength', {
6234 enumerable: true,
6235 configurable: true,
6236 get: function get() {
6237 return _MaxLen;
6238 },
6239 set: function set(value) {
6240 if (Number.isInteger(value)) {
6241 _MaxLen = value;
6242 }
6243 }
6244 });
6245 Object.defineProperty(this, 'hasAppearanceStream', {
6246 enumerable: true,
6247 configurable: true,
6248 get: function get() {
6249 return this.V || this.DV;
6250 }
6251 });
6252 };
6253
6254 inherit(AcroFormTextField, AcroFormField);
6255 /**
6256 * @class AcroFormPasswordField
6257 * @extends AcroFormTextField
6258 * @extends AcroFormField
6259 */
6260
6261 var AcroFormPasswordField = function AcroFormPasswordField() {
6262 AcroFormTextField.call(this);
6263 /**
6264 * If set, the field is intended for entering a secure password that should not be echoed visibly to the screen. Characters typed from the keyboard shall instead be echoed in some unreadable form, such as asterisks or bullet characters.
6265 * NOTE To protect password confidentiality, readers should never store the value of the text field in the PDF file if this flag is set.
6266 *
6267 * @name AcroFormTextField#password
6268 * @type {boolean}
6269 */
6270
6271 Object.defineProperty(this, 'password', {
6272 enumerable: true,
6273 configurable: true,
6274 get: function get() {
6275 return Boolean(getBitForPdf(this.Ff, 14));
6276 },
6277 set: function set(value) {
6278 if (Boolean(value) === true) {
6279 this.Ff = setBitForPdf(this.Ff, 14);
6280 } else {
6281 this.Ff = clearBitForPdf(this.Ff, 14);
6282 }
6283 }
6284 });
6285 this.password = true;
6286 };
6287
6288 inherit(AcroFormPasswordField, AcroFormTextField); // Contains Methods for creating standard appearances
6289
6290 var AcroFormAppearance = {
6291 CheckBox: {
6292 createAppearanceStream: function createAppearanceStream() {
6293 var appearance = {
6294 N: {
6295 On: AcroFormAppearance.CheckBox.YesNormal
6296 },
6297 D: {
6298 On: AcroFormAppearance.CheckBox.YesPushDown,
6299 Off: AcroFormAppearance.CheckBox.OffPushDown
6300 }
6301 };
6302 return appearance;
6303 },
6304
6305 /**
6306 * Returns the standard On Appearance for a CheckBox
6307 *
6308 * @returns {AcroFormXObject}
6309 */
6310 YesPushDown: function YesPushDown(formObject) {
6311 var xobj = createFormXObject(formObject);
6312 var stream = [];
6313 var fontKey = scope.internal.getFont(formObject.fontName, formObject.fontStyle).id;
6314
6315 var encodedColor = scope.__private__.encodeColorString(formObject.color);
6316
6317 var calcRes = calculateX(formObject, formObject.caption);
6318 stream.push("0.749023 g");
6319 stream.push("0 0 " + f2(AcroFormAppearance.internal.getWidth(formObject)) + " " + f2(AcroFormAppearance.internal.getHeight(formObject)) + " re");
6320 stream.push("f");
6321 stream.push("BMC");
6322 stream.push("q");
6323 stream.push("0 0 1 rg");
6324 stream.push("/" + fontKey + " " + f2(calcRes.fontSize) + " Tf " + encodedColor);
6325 stream.push("BT");
6326 stream.push(calcRes.text);
6327 stream.push("ET");
6328 stream.push("Q");
6329 stream.push("EMC");
6330 xobj.stream = stream.join("\n");
6331 return xobj;
6332 },
6333 YesNormal: function YesNormal(formObject) {
6334 var xobj = createFormXObject(formObject);
6335 var fontKey = scope.internal.getFont(formObject.fontName, formObject.fontStyle).id;
6336
6337 var encodedColor = scope.__private__.encodeColorString(formObject.color);
6338
6339 var stream = [];
6340 var height = AcroFormAppearance.internal.getHeight(formObject);
6341 var width = AcroFormAppearance.internal.getWidth(formObject);
6342 var calcRes = calculateX(formObject, formObject.caption);
6343 stream.push("1 g");
6344 stream.push("0 0 " + f2(width) + " " + f2(height) + " re");
6345 stream.push("f");
6346 stream.push("q");
6347 stream.push("0 0 1 rg");
6348 stream.push("0 0 " + f2(width - 1) + " " + f2(height - 1) + " re");
6349 stream.push("W");
6350 stream.push("n");
6351 stream.push("0 g");
6352 stream.push("BT");
6353 stream.push("/" + fontKey + " " + f2(calcRes.fontSize) + " Tf " + encodedColor);
6354 stream.push(calcRes.text);
6355 stream.push("ET");
6356 stream.push("Q");
6357 xobj.stream = stream.join("\n");
6358 return xobj;
6359 },
6360
6361 /**
6362 * Returns the standard Off Appearance for a CheckBox
6363 *
6364 * @returns {AcroFormXObject}
6365 */
6366 OffPushDown: function OffPushDown(formObject) {
6367 var xobj = createFormXObject(formObject);
6368 var stream = [];
6369 stream.push("0.749023 g");
6370 stream.push("0 0 " + f2(AcroFormAppearance.internal.getWidth(formObject)) + " " + f2(AcroFormAppearance.internal.getHeight(formObject)) + " re");
6371 stream.push("f");
6372 xobj.stream = stream.join("\n");
6373 return xobj;
6374 }
6375 },
6376 RadioButton: {
6377 Circle: {
6378 createAppearanceStream: function createAppearanceStream(name) {
6379 var appearanceStreamContent = {
6380 D: {
6381 'Off': AcroFormAppearance.RadioButton.Circle.OffPushDown
6382 },
6383 N: {}
6384 };
6385 appearanceStreamContent.N[name] = AcroFormAppearance.RadioButton.Circle.YesNormal;
6386 appearanceStreamContent.D[name] = AcroFormAppearance.RadioButton.Circle.YesPushDown;
6387 return appearanceStreamContent;
6388 },
6389 getCA: function getCA() {
6390 return 'l';
6391 },
6392 YesNormal: function YesNormal(formObject) {
6393 var xobj = createFormXObject(formObject);
6394 var stream = []; // Make the Radius of the Circle relative to min(height, width) of formObject
6395
6396 var DotRadius = AcroFormAppearance.internal.getWidth(formObject) <= AcroFormAppearance.internal.getHeight(formObject) ? AcroFormAppearance.internal.getWidth(formObject) / 4 : AcroFormAppearance.internal.getHeight(formObject) / 4; // The Borderpadding...
6397
6398 DotRadius = Number((DotRadius * 0.9).toFixed(5));
6399 var c = AcroFormAppearance.internal.Bezier_C;
6400 var DotRadiusBezier = Number((DotRadius * c).toFixed(5));
6401 /*
6402 * The Following is a Circle created with Bezier-Curves.
6403 */
6404
6405 stream.push("q");
6406 stream.push("1 0 0 1 " + f5(AcroFormAppearance.internal.getWidth(formObject) / 2) + " " + f5(AcroFormAppearance.internal.getHeight(formObject) / 2) + " cm");
6407 stream.push(DotRadius + " 0 m");
6408 stream.push(DotRadius + " " + DotRadiusBezier + " " + DotRadiusBezier + " " + DotRadius + " 0 " + DotRadius + " c");
6409 stream.push("-" + DotRadiusBezier + " " + DotRadius + " -" + DotRadius + " " + DotRadiusBezier + " -" + DotRadius + " 0 c");
6410 stream.push("-" + DotRadius + " -" + DotRadiusBezier + " -" + DotRadiusBezier + " -" + DotRadius + " 0 -" + DotRadius + " c");
6411 stream.push(DotRadiusBezier + " -" + DotRadius + " " + DotRadius + " -" + DotRadiusBezier + " " + DotRadius + " 0 c");
6412 stream.push("f");
6413 stream.push("Q");
6414 xobj.stream = stream.join("\n");
6415 return xobj;
6416 },
6417 YesPushDown: function YesPushDown(formObject) {
6418 var xobj = createFormXObject(formObject);
6419 var stream = [];
6420 var DotRadius = AcroFormAppearance.internal.getWidth(formObject) <= AcroFormAppearance.internal.getHeight(formObject) ? AcroFormAppearance.internal.getWidth(formObject) / 4 : AcroFormAppearance.internal.getHeight(formObject) / 4; // The Borderpadding...
6421
6422 var DotRadius = Number((DotRadius * 0.9).toFixed(5)); // Save results for later use; no need to waste
6423 // processor ticks on doing math
6424
6425 var k = Number((DotRadius * 2).toFixed(5));
6426 var kc = Number((k * AcroFormAppearance.internal.Bezier_C).toFixed(5));
6427 var dc = Number((DotRadius * AcroFormAppearance.internal.Bezier_C).toFixed(5));
6428 stream.push("0.749023 g");
6429 stream.push("q");
6430 stream.push("1 0 0 1 " + f5(AcroFormAppearance.internal.getWidth(formObject) / 2) + " " + f5(AcroFormAppearance.internal.getHeight(formObject) / 2) + " cm");
6431 stream.push(k + " 0 m");
6432 stream.push(k + " " + kc + " " + kc + " " + k + " 0 " + k + " c");
6433 stream.push("-" + kc + " " + k + " -" + k + " " + kc + " -" + k + " 0 c");
6434 stream.push("-" + k + " -" + kc + " -" + kc + " -" + k + " 0 -" + k + " c");
6435 stream.push(kc + " -" + k + " " + k + " -" + kc + " " + k + " 0 c");
6436 stream.push("f");
6437 stream.push("Q");
6438 stream.push("0 g");
6439 stream.push("q");
6440 stream.push("1 0 0 1 " + f5(AcroFormAppearance.internal.getWidth(formObject) / 2) + " " + f5(AcroFormAppearance.internal.getHeight(formObject) / 2) + " cm");
6441 stream.push(DotRadius + " 0 m");
6442 stream.push("" + DotRadius + " " + dc + " " + dc + " " + DotRadius + " 0 " + DotRadius + " c");
6443 stream.push("-" + dc + " " + DotRadius + " -" + DotRadius + " " + dc + " -" + DotRadius + " 0 c");
6444 stream.push("-" + DotRadius + " -" + dc + " -" + dc + " -" + DotRadius + " 0 -" + DotRadius + " c");
6445 stream.push(dc + " -" + DotRadius + " " + DotRadius + " -" + dc + " " + DotRadius + " 0 c");
6446 stream.push("f");
6447 stream.push("Q");
6448 xobj.stream = stream.join("\n");
6449 return xobj;
6450 },
6451 OffPushDown: function OffPushDown(formObject) {
6452 var xobj = createFormXObject(formObject);
6453 var stream = [];
6454 var DotRadius = AcroFormAppearance.internal.getWidth(formObject) <= AcroFormAppearance.internal.getHeight(formObject) ? AcroFormAppearance.internal.getWidth(formObject) / 4 : AcroFormAppearance.internal.getHeight(formObject) / 4; // The Borderpadding...
6455
6456 var DotRadius = Number((DotRadius * 0.9).toFixed(5)); // Save results for later use; no need to waste
6457 // processor ticks on doing math
6458
6459 var k = Number((DotRadius * 2).toFixed(5));
6460 var kc = Number((k * AcroFormAppearance.internal.Bezier_C).toFixed(5));
6461 stream.push("0.749023 g");
6462 stream.push("q");
6463 stream.push("1 0 0 1 " + f5(AcroFormAppearance.internal.getWidth(formObject) / 2) + " " + f5(AcroFormAppearance.internal.getHeight(formObject) / 2) + " cm");
6464 stream.push(k + " 0 m");
6465 stream.push(k + " " + kc + " " + kc + " " + k + " 0 " + k + " c");
6466 stream.push("-" + kc + " " + k + " -" + k + " " + kc + " -" + k + " 0 c");
6467 stream.push("-" + k + " -" + kc + " -" + kc + " -" + k + " 0 -" + k + " c");
6468 stream.push(kc + " -" + k + " " + k + " -" + kc + " " + k + " 0 c");
6469 stream.push("f");
6470 stream.push("Q");
6471 xobj.stream = stream.join("\n");
6472 return xobj;
6473 }
6474 },
6475 Cross: {
6476 /**
6477 * Creates the Actual AppearanceDictionary-References
6478 *
6479 * @param {string} name
6480 * @returns {Object}
6481 * @ignore
6482 */
6483 createAppearanceStream: function createAppearanceStream(name) {
6484 var appearanceStreamContent = {
6485 D: {
6486 'Off': AcroFormAppearance.RadioButton.Cross.OffPushDown
6487 },
6488 N: {}
6489 };
6490 appearanceStreamContent.N[name] = AcroFormAppearance.RadioButton.Cross.YesNormal;
6491 appearanceStreamContent.D[name] = AcroFormAppearance.RadioButton.Cross.YesPushDown;
6492 return appearanceStreamContent;
6493 },
6494 getCA: function getCA() {
6495 return '8';
6496 },
6497 YesNormal: function YesNormal(formObject) {
6498 var xobj = createFormXObject(formObject);
6499 var stream = [];
6500 var cross = AcroFormAppearance.internal.calculateCross(formObject);
6501 stream.push("q");
6502 stream.push("1 1 " + f2(AcroFormAppearance.internal.getWidth(formObject) - 2) + " " + f2(AcroFormAppearance.internal.getHeight(formObject) - 2) + " re");
6503 stream.push("W");
6504 stream.push("n");
6505 stream.push(f2(cross.x1.x) + " " + f2(cross.x1.y) + " m");
6506 stream.push(f2(cross.x2.x) + " " + f2(cross.x2.y) + " l");
6507 stream.push(f2(cross.x4.x) + " " + f2(cross.x4.y) + " m");
6508 stream.push(f2(cross.x3.x) + " " + f2(cross.x3.y) + " l");
6509 stream.push("s");
6510 stream.push("Q");
6511 xobj.stream = stream.join("\n");
6512 return xobj;
6513 },
6514 YesPushDown: function YesPushDown(formObject) {
6515 var xobj = createFormXObject(formObject);
6516 var cross = AcroFormAppearance.internal.calculateCross(formObject);
6517 var stream = [];
6518 stream.push("0.749023 g");
6519 stream.push("0 0 " + f2(AcroFormAppearance.internal.getWidth(formObject)) + " " + f2(AcroFormAppearance.internal.getHeight(formObject)) + " re");
6520 stream.push("f");
6521 stream.push("q");
6522 stream.push("1 1 " + f2(AcroFormAppearance.internal.getWidth(formObject) - 2) + " " + f2(AcroFormAppearance.internal.getHeight(formObject) - 2) + " re");
6523 stream.push("W");
6524 stream.push("n");
6525 stream.push(f2(cross.x1.x) + " " + f2(cross.x1.y) + " m");
6526 stream.push(f2(cross.x2.x) + " " + f2(cross.x2.y) + " l");
6527 stream.push(f2(cross.x4.x) + " " + f2(cross.x4.y) + " m");
6528 stream.push(f2(cross.x3.x) + " " + f2(cross.x3.y) + " l");
6529 stream.push("s");
6530 stream.push("Q");
6531 xobj.stream = stream.join("\n");
6532 return xobj;
6533 },
6534 OffPushDown: function OffPushDown(formObject) {
6535 var xobj = createFormXObject(formObject);
6536 var stream = [];
6537 stream.push("0.749023 g");
6538 stream.push("0 0 " + f2(AcroFormAppearance.internal.getWidth(formObject)) + " " + f2(AcroFormAppearance.internal.getHeight(formObject)) + " re");
6539 stream.push("f");
6540 xobj.stream = stream.join("\n");
6541 return xobj;
6542 }
6543 }
6544 },
6545
6546 /**
6547 * Returns the standard Appearance
6548 *
6549 * @returns {AcroFormXObject}
6550 */
6551 createDefaultAppearanceStream: function createDefaultAppearanceStream(formObject) {
6552 // Set Helvetica to Standard Font (size: auto)
6553 // Color: Black
6554 var fontKey = scope.internal.getFont(formObject.fontName, formObject.fontStyle).id;
6555
6556 var encodedColor = scope.__private__.encodeColorString(formObject.color);
6557
6558 var fontSize = formObject.fontSize;
6559 var result = '/' + fontKey + ' ' + fontSize + ' Tf ' + encodedColor;
6560 return result;
6561 }
6562 };
6563 AcroFormAppearance.internal = {
6564 Bezier_C: 0.551915024494,
6565 calculateCross: function calculateCross(formObject) {
6566 var width = AcroFormAppearance.internal.getWidth(formObject);
6567 var height = AcroFormAppearance.internal.getHeight(formObject);
6568 var a = Math.min(width, height);
6569
6570 var cross = {
6571 x1: {
6572 // upperLeft
6573 x: (width - a) / 2,
6574 y: (height - a) / 2 + a // height - borderPadding
6575
6576 },
6577 x2: {
6578 // lowerRight
6579 x: (width - a) / 2 + a,
6580 y: (height - a) / 2 // borderPadding
6581
6582 },
6583 x3: {
6584 // lowerLeft
6585 x: (width - a) / 2,
6586 y: (height - a) / 2 // borderPadding
6587
6588 },
6589 x4: {
6590 // upperRight
6591 x: (width - a) / 2 + a,
6592 y: (height - a) / 2 + a // height - borderPadding
6593
6594 }
6595 };
6596 return cross;
6597 }
6598 };
6599
6600 AcroFormAppearance.internal.getWidth = function (formObject) {
6601 var result = 0;
6602
6603 if (_typeof(formObject) === "object") {
6604 result = scale(formObject.Rect[2]);
6605 }
6606
6607 return result;
6608 };
6609
6610 AcroFormAppearance.internal.getHeight = function (formObject) {
6611 var result = 0;
6612
6613 if (_typeof(formObject) === "object") {
6614 result = scale(formObject.Rect[3]);
6615 }
6616
6617 return result;
6618 }; // Public:
6619
6620 /**
6621 * Add an AcroForm-Field to the jsPDF-instance
6622 *
6623 * @name addField
6624 * @function
6625 * @instance
6626 * @param {Object} fieldObject
6627 * @returns {jsPDF}
6628 */
6629
6630
6631 var addField = jsPDFAPI.addField = function (fieldObject) {
6632 initializeAcroForm.call(this);
6633
6634 if (fieldObject instanceof AcroFormField) {
6635 putForm.call(this, fieldObject);
6636 } else {
6637 throw new Error('Invalid argument passed to jsPDF.addField.');
6638 }
6639
6640 fieldObject.page = scope.internal.getCurrentPageInfo().pageNumber;
6641 return this;
6642 };
6643 /**
6644 * @name addButton
6645 * @function
6646 * @instance
6647 * @param {AcroFormButton} options
6648 * @returns {jsPDF}
6649 * @deprecated
6650 */
6651
6652
6653 var addButton = jsPDFAPI.addButton = function (button) {
6654 if (button instanceof AcroFormButton === false) {
6655 throw new Error('Invalid argument passed to jsPDF.addButton.');
6656 }
6657
6658 return addField.call(this, button);
6659 };
6660 /**
6661 * @name addTextField
6662 * @function
6663 * @instance
6664 * @param {AcroFormTextField} textField
6665 * @returns {jsPDF}
6666 * @deprecated
6667 */
6668
6669
6670 var addTextField = jsPDFAPI.addTextField = function (textField) {
6671 if (textField instanceof AcroFormTextField === false) {
6672 throw new Error('Invalid argument passed to jsPDF.addTextField.');
6673 }
6674
6675 return addField.call(this, textField);
6676 };
6677 /**
6678 * @name addChoiceField
6679 * @function
6680 * @instance
6681 * @param {AcroFormChoiceField}
6682 * @returns {jsPDF}
6683 * @deprecated
6684 */
6685
6686
6687 var addChoiceField = jsPDFAPI.addChoiceField = function (choiceField) {
6688 if (choiceField instanceof AcroFormChoiceField === false) {
6689 throw new Error('Invalid argument passed to jsPDF.addChoiceField.');
6690 }
6691
6692 return addField.call(this, choiceField);
6693 };
6694
6695 if (_typeof(globalObj) == "object" && typeof globalObj["ChoiceField"] === "undefined" && typeof globalObj["ListBox"] === "undefined" && typeof globalObj["ComboBox"] === "undefined" && typeof globalObj["EditBox"] === "undefined" && typeof globalObj["Button"] === "undefined" && typeof globalObj["PushButton"] === "undefined" && typeof globalObj["RadioButton"] === "undefined" && typeof globalObj["CheckBox"] === "undefined" && typeof globalObj["TextField"] === "undefined" && typeof globalObj["PasswordField"] === "undefined") {
6696 globalObj["ChoiceField"] = AcroFormChoiceField;
6697 globalObj["ListBox"] = AcroFormListBox;
6698 globalObj["ComboBox"] = AcroFormComboBox;
6699 globalObj["EditBox"] = AcroFormEditBox;
6700 globalObj["Button"] = AcroFormButton;
6701 globalObj["PushButton"] = AcroFormPushButton;
6702 globalObj["RadioButton"] = AcroFormRadioButton;
6703 globalObj["CheckBox"] = AcroFormCheckBox;
6704 globalObj["TextField"] = AcroFormTextField;
6705 globalObj["PasswordField"] = AcroFormPasswordField; // backwardsCompatibility
6706
6707 globalObj["AcroForm"] = {
6708 Appearance: AcroFormAppearance
6709 };
6710 } else {
6711 console.warn("AcroForm-Classes are not populated into global-namespace, because the class-Names exist already.");
6712 }
6713
6714 jsPDFAPI.AcroFormChoiceField = AcroFormChoiceField;
6715 jsPDFAPI.AcroFormListBox = AcroFormListBox;
6716 jsPDFAPI.AcroFormComboBox = AcroFormComboBox;
6717 jsPDFAPI.AcroFormEditBox = AcroFormEditBox;
6718 jsPDFAPI.AcroFormButton = AcroFormButton;
6719 jsPDFAPI.AcroFormPushButton = AcroFormPushButton;
6720 jsPDFAPI.AcroFormRadioButton = AcroFormRadioButton;
6721 jsPDFAPI.AcroFormCheckBox = AcroFormCheckBox;
6722 jsPDFAPI.AcroFormTextField = AcroFormTextField;
6723 jsPDFAPI.AcroFormPasswordField = AcroFormPasswordField;
6724 jsPDFAPI.AcroFormAppearance = AcroFormAppearance;
6725 jsPDFAPI.AcroForm = {
6726 ChoiceField: AcroFormChoiceField,
6727 ListBox: AcroFormListBox,
6728 ComboBox: AcroFormComboBox,
6729 EditBox: AcroFormEditBox,
6730 Button: AcroFormButton,
6731 PushButton: AcroFormPushButton,
6732 RadioButton: AcroFormRadioButton,
6733 CheckBox: AcroFormCheckBox,
6734 TextField: AcroFormTextField,
6735 PasswordField: AcroFormPasswordField,
6736 Appearance: AcroFormAppearance
6737 };
6738 })(jsPDF.API, typeof window !== "undefined" && window || typeof global !== "undefined" && global);
6739
6740 /** @license
6741 * jsPDF addImage plugin
6742 * Copyright (c) 2012 Jason Siefken, https://github.com/siefkenj/
6743 * 2013 Chris Dowling, https://github.com/gingerchris
6744 * 2013 Trinh Ho, https://github.com/ineedfat
6745 * 2013 Edwin Alejandro Perez, https://github.com/eaparango
6746 * 2013 Norah Smith, https://github.com/burnburnrocket
6747 * 2014 Diego Casorran, https://github.com/diegocr
6748 * 2014 James Robb, https://github.com/jamesbrobb
6749 *
6750 *
6751 */
6752
6753 /**
6754 * @name addImage
6755 * @module
6756 */
6757 (function (jsPDFAPI) {
6758
6759 var namespace = 'addImage_';
6760 var imageFileTypeHeaders = {
6761 PNG: [[0x89, 0x50, 0x4e, 0x47]],
6762 TIFF: [[0x4D, 0x4D, 0x00, 0x2A], //Motorola
6763 [0x49, 0x49, 0x2A, 0x00] //Intel
6764 ],
6765 JPEG: [[0xFF, 0xD8, 0xFF, 0xE0, undefined, undefined, 0x4A, 0x46, 0x49, 0x46, 0x00], //JFIF
6766 [0xFF, 0xD8, 0xFF, 0xE1, undefined, undefined, 0x45, 0x78, 0x69, 0x66, 0x00, 0x00] //Exif
6767 ],
6768 JPEG2000: [[0x00, 0x00, 0x00, 0x0C, 0x6A, 0x50, 0x20, 0x20]],
6769 GIF87a: [[0x47, 0x49, 0x46, 0x38, 0x37, 0x61]],
6770 GIF89a: [[0x47, 0x49, 0x46, 0x38, 0x39, 0x61]],
6771 BMP: [[0x42, 0x4D], //BM - Windows 3.1x, 95, NT, ... etc.
6772 [0x42, 0x41], //BA - OS/2 struct bitmap array
6773 [0x43, 0x49], //CI - OS/2 struct color icon
6774 [0x43, 0x50], //CP - OS/2 const color pointer
6775 [0x49, 0x43], //IC - OS/2 struct icon
6776 [0x50, 0x54] //PT - OS/2 pointer
6777 ]
6778 };
6779 /**
6780 * Recognize filetype of Image by magic-bytes
6781 *
6782 * https://en.wikipedia.org/wiki/List_of_file_signatures
6783 *
6784 * @name getImageFileTypeByImageData
6785 * @public
6786 * @function
6787 * @param {string|arraybuffer} imageData imageData as binary String or arraybuffer
6788 * @param {string} format format of file if filetype-recognition fails, e.g. 'JPEG'
6789 *
6790 * @returns {string} filetype of Image
6791 */
6792
6793 var getImageFileTypeByImageData = jsPDFAPI.getImageFileTypeByImageData = function (imageData, fallbackFormat) {
6794 fallbackFormat = fallbackFormat || 'UNKNOWN';
6795 var i;
6796 var j;
6797 var result = 'UNKNOWN';
6798 var headerSchemata;
6799 var compareResult;
6800 var fileType;
6801
6802 if (jsPDFAPI.isArrayBufferView(imageData)) {
6803 imageData = jsPDFAPI.arrayBufferToBinaryString(imageData);
6804 }
6805
6806 for (fileType in imageFileTypeHeaders) {
6807 headerSchemata = imageFileTypeHeaders[fileType];
6808
6809 for (i = 0; i < headerSchemata.length; i += 1) {
6810 compareResult = true;
6811
6812 for (j = 0; j < headerSchemata[i].length; j += 1) {
6813 if (headerSchemata[i][j] === undefined) {
6814 continue;
6815 }
6816
6817 if (headerSchemata[i][j] !== imageData.charCodeAt(j)) {
6818 compareResult = false;
6819 break;
6820 }
6821 }
6822
6823 if (compareResult === true) {
6824 result = fileType;
6825 break;
6826 }
6827 }
6828 }
6829
6830 if (result === 'UNKNOWN' && fallbackFormat !== 'UNKNOWN') {
6831 console.warn('FileType of Image not recognized. Processing image as "' + fallbackFormat + '".');
6832 result = fallbackFormat;
6833 }
6834
6835 return result;
6836 }; // Image functionality ported from pdf.js
6837
6838
6839 var putImage = function putImage(img) {
6840 var objectNumber = this.internal.newObject(),
6841 out = this.internal.write,
6842 putStream = this.internal.putStream,
6843 getFilters = this.internal.getFilters;
6844 var filters = getFilters();
6845
6846 while (filters.indexOf('FlateEncode') !== -1) {
6847 filters.splice(filters.indexOf('FlateEncode'), 1);
6848 }
6849
6850 img['n'] = objectNumber;
6851 var additionalKeyValues = [];
6852 additionalKeyValues.push({
6853 key: 'Type',
6854 value: '/XObject'
6855 });
6856 additionalKeyValues.push({
6857 key: 'Subtype',
6858 value: '/Image'
6859 });
6860 additionalKeyValues.push({
6861 key: 'Width',
6862 value: img['w']
6863 });
6864 additionalKeyValues.push({
6865 key: 'Height',
6866 value: img['h']
6867 });
6868
6869 if (img['cs'] === this.color_spaces.INDEXED) {
6870 additionalKeyValues.push({
6871 key: 'ColorSpace',
6872 value: '[/Indexed /DeviceRGB ' // if an indexed png defines more than one colour with transparency, we've created a smask
6873 + (img['pal'].length / 3 - 1) + ' ' + ('smask' in img ? objectNumber + 2 : objectNumber + 1) + ' 0 R]'
6874 });
6875 } else {
6876 additionalKeyValues.push({
6877 key: 'ColorSpace',
6878 value: '/' + img['cs']
6879 });
6880
6881 if (img['cs'] === this.color_spaces.DEVICE_CMYK) {
6882 additionalKeyValues.push({
6883 key: 'Decode',
6884 value: '[1 0 1 0 1 0 1 0]'
6885 });
6886 }
6887 }
6888
6889 additionalKeyValues.push({
6890 key: 'BitsPerComponent',
6891 value: img['bpc']
6892 });
6893
6894 if ('dp' in img) {
6895 additionalKeyValues.push({
6896 key: 'DecodeParms',
6897 value: '<<' + img['dp'] + '>>'
6898 });
6899 }
6900
6901 if ('trns' in img && img['trns'].constructor == Array) {
6902 var trns = '',
6903 i = 0,
6904 len = img['trns'].length;
6905
6906 for (; i < len; i++) {
6907 trns += img['trns'][i] + ' ' + img['trns'][i] + ' ';
6908 }
6909
6910 additionalKeyValues.push({
6911 key: 'Mask',
6912 value: '[' + trns + ']'
6913 });
6914 }
6915
6916 if ('smask' in img) {
6917 additionalKeyValues.push({
6918 key: 'SMask',
6919 value: objectNumber + 1 + ' 0 R'
6920 });
6921 }
6922
6923 var alreadyAppliedFilters = typeof img['f'] !== "undefined" ? ['/' + img['f']] : undefined;
6924 putStream({
6925 data: img['data'],
6926 additionalKeyValues: additionalKeyValues,
6927 alreadyAppliedFilters: alreadyAppliedFilters
6928 });
6929 out('endobj'); // Soft mask
6930
6931 if ('smask' in img) {
6932 var dp = '/Predictor ' + img['p'] + ' /Colors 1 /BitsPerComponent ' + img['bpc'] + ' /Columns ' + img['w'];
6933 var smask = {
6934 'w': img['w'],
6935 'h': img['h'],
6936 'cs': 'DeviceGray',
6937 'bpc': img['bpc'],
6938 'dp': dp,
6939 'data': img['smask']
6940 };
6941 if ('f' in img) smask.f = img['f'];
6942 putImage.call(this, smask);
6943 } //Palette
6944
6945
6946 if (img['cs'] === this.color_spaces.INDEXED) {
6947 this.internal.newObject(); //out('<< /Filter / ' + img['f'] +' /Length ' + img['pal'].length + '>>');
6948 //putStream(zlib.compress(img['pal']));
6949
6950 putStream({
6951 data: this.arrayBufferToBinaryString(new Uint8Array(img['pal']))
6952 });
6953 out('endobj');
6954 }
6955 },
6956 putResourcesCallback = function putResourcesCallback() {
6957 var images = this.internal.collections[namespace + 'images'];
6958
6959 for (var i in images) {
6960 putImage.call(this, images[i]);
6961 }
6962 },
6963 putXObjectsDictCallback = function putXObjectsDictCallback() {
6964 var images = this.internal.collections[namespace + 'images'],
6965 out = this.internal.write,
6966 image;
6967
6968 for (var i in images) {
6969 image = images[i];
6970 out('/I' + image['i'], image['n'], '0', 'R');
6971 }
6972 },
6973 checkCompressValue = function checkCompressValue(value) {
6974 if (value && typeof value === 'string') value = value.toUpperCase();
6975 return value in jsPDFAPI.image_compression ? value : jsPDFAPI.image_compression.NONE;
6976 },
6977 getImages = function getImages() {
6978 var images = this.internal.collections[namespace + 'images']; //first run, so initialise stuff
6979
6980 if (!images) {
6981 this.internal.collections[namespace + 'images'] = images = {};
6982 this.internal.events.subscribe('putResources', putResourcesCallback);
6983 this.internal.events.subscribe('putXobjectDict', putXObjectsDictCallback);
6984 }
6985
6986 return images;
6987 },
6988 getImageIndex = function getImageIndex(images) {
6989 var imageIndex = 0;
6990
6991 if (images) {
6992 // this is NOT the first time this method is ran on this instance of jsPDF object.
6993 imageIndex = Object.keys ? Object.keys(images).length : function (o) {
6994 var i = 0;
6995
6996 for (var e in o) {
6997 if (o.hasOwnProperty(e)) {
6998 i++;
6999 }
7000 }
7001
7002 return i;
7003 }(images);
7004 }
7005
7006 return imageIndex;
7007 },
7008 notDefined = function notDefined(value) {
7009 return typeof value === 'undefined' || value === null || value.length === 0;
7010 },
7011 generateAliasFromImageData = function generateAliasFromImageData(imageData) {
7012 if (typeof imageData === 'string') {
7013 return jsPDFAPI.sHashCode(imageData);
7014 }
7015
7016 if (jsPDFAPI.isArrayBufferView(imageData)) {
7017 return jsPDFAPI.sHashCode(jsPDFAPI.arrayBufferToBinaryString(imageData));
7018 }
7019
7020 return null;
7021 },
7022 isImageTypeSupported = function isImageTypeSupported(type) {
7023 return typeof jsPDFAPI["process" + type.toUpperCase()] === "function";
7024 },
7025 isDOMElement = function isDOMElement(object) {
7026 return _typeof(object) === 'object' && object.nodeType === 1;
7027 },
7028 createDataURIFromElement = function createDataURIFromElement(element, format) {
7029 //if element is an image which uses data url definition, just return the dataurl
7030 if (element.nodeName === 'IMG' && element.hasAttribute('src')) {
7031 var src = '' + element.getAttribute('src'); //is base64 encoded dataUrl, directly process it
7032
7033 if (src.indexOf('data:image/') === 0) {
7034 return unescape(src);
7035 } //it is probably an url, try to load it
7036
7037
7038 var tmpImageData = jsPDFAPI.loadFile(src);
7039
7040 if (tmpImageData !== undefined) {
7041 return btoa(tmpImageData);
7042 }
7043 }
7044
7045 if (element.nodeName === 'CANVAS') {
7046 var canvas = element;
7047 return element.toDataURL('image/jpeg', 1.0);
7048 } //absolute fallback method
7049
7050
7051 var canvas = document.createElement('canvas');
7052 canvas.width = element.clientWidth || element.width;
7053 canvas.height = element.clientHeight || element.height;
7054 var ctx = canvas.getContext('2d');
7055
7056 if (!ctx) {
7057 throw 'addImage requires canvas to be supported by browser.';
7058 }
7059
7060 ctx.drawImage(element, 0, 0, canvas.width, canvas.height);
7061 return canvas.toDataURL(('' + format).toLowerCase() == 'png' ? 'image/png' : 'image/jpeg');
7062 },
7063 checkImagesForAlias = function checkImagesForAlias(alias, images) {
7064 var cached_info;
7065
7066 if (images) {
7067 for (var e in images) {
7068 if (alias === images[e].alias) {
7069 cached_info = images[e];
7070 break;
7071 }
7072 }
7073 }
7074
7075 return cached_info;
7076 },
7077 determineWidthAndHeight = function determineWidthAndHeight(w, h, info) {
7078 if (!w && !h) {
7079 w = -96;
7080 h = -96;
7081 }
7082
7083 if (w < 0) {
7084 w = -1 * info['w'] * 72 / w / this.internal.scaleFactor;
7085 }
7086
7087 if (h < 0) {
7088 h = -1 * info['h'] * 72 / h / this.internal.scaleFactor;
7089 }
7090
7091 if (w === 0) {
7092 w = h * info['w'] / info['h'];
7093 }
7094
7095 if (h === 0) {
7096 h = w * info['h'] / info['w'];
7097 }
7098
7099 return [w, h];
7100 },
7101 writeImageToPDF = function writeImageToPDF(x, y, w, h, info, index, images, rotation) {
7102 var dims = determineWidthAndHeight.call(this, w, h, info),
7103 coord = this.internal.getCoordinateString,
7104 vcoord = this.internal.getVerticalCoordinateString;
7105 w = dims[0];
7106 h = dims[1];
7107 images[index] = info;
7108
7109 if (rotation) {
7110 rotation *= Math.PI / 180;
7111 var c = Math.cos(rotation);
7112 var s = Math.sin(rotation); //like in pdf Reference do it 4 digits instead of 2
7113
7114 var f4 = function f4(number) {
7115 return number.toFixed(4);
7116 };
7117
7118 var rotationTransformationMatrix = [f4(c), f4(s), f4(s * -1), f4(c), 0, 0, 'cm'];
7119 }
7120
7121 this.internal.write('q'); //Save graphics state
7122
7123 if (rotation) {
7124 this.internal.write([1, '0', '0', 1, coord(x), vcoord(y + h), 'cm'].join(' ')); //Translate
7125
7126 this.internal.write(rotationTransformationMatrix.join(' ')); //Rotate
7127
7128 this.internal.write([coord(w), '0', '0', coord(h), '0', '0', 'cm'].join(' ')); //Scale
7129 } else {
7130 this.internal.write([coord(w), '0', '0', coord(h), coord(x), vcoord(y + h), 'cm'].join(' ')); //Translate and Scale
7131 }
7132
7133 this.internal.write('/I' + info['i'] + ' Do'); //Paint Image
7134
7135 this.internal.write('Q'); //Restore graphics state
7136 };
7137 /**
7138 * COLOR SPACES
7139 */
7140
7141
7142 jsPDFAPI.color_spaces = {
7143 DEVICE_RGB: 'DeviceRGB',
7144 DEVICE_GRAY: 'DeviceGray',
7145 DEVICE_CMYK: 'DeviceCMYK',
7146 CAL_GREY: 'CalGray',
7147 CAL_RGB: 'CalRGB',
7148 LAB: 'Lab',
7149 ICC_BASED: 'ICCBased',
7150 INDEXED: 'Indexed',
7151 PATTERN: 'Pattern',
7152 SEPARATION: 'Separation',
7153 DEVICE_N: 'DeviceN'
7154 };
7155 /**
7156 * DECODE METHODS
7157 */
7158
7159 jsPDFAPI.decode = {
7160 DCT_DECODE: 'DCTDecode',
7161 FLATE_DECODE: 'FlateDecode',
7162 LZW_DECODE: 'LZWDecode',
7163 JPX_DECODE: 'JPXDecode',
7164 JBIG2_DECODE: 'JBIG2Decode',
7165 ASCII85_DECODE: 'ASCII85Decode',
7166 ASCII_HEX_DECODE: 'ASCIIHexDecode',
7167 RUN_LENGTH_DECODE: 'RunLengthDecode',
7168 CCITT_FAX_DECODE: 'CCITTFaxDecode'
7169 };
7170 /**
7171 * IMAGE COMPRESSION TYPES
7172 */
7173
7174 jsPDFAPI.image_compression = {
7175 NONE: 'NONE',
7176 FAST: 'FAST',
7177 MEDIUM: 'MEDIUM',
7178 SLOW: 'SLOW'
7179 };
7180 /**
7181 * @name sHashCode
7182 * @function
7183 * @param {string} str
7184 * @returns {string}
7185 */
7186
7187 jsPDFAPI.sHashCode = function (str) {
7188 str = str || "";
7189 var hash = 0,
7190 i,
7191 chr;
7192 if (str.length === 0) return hash;
7193
7194 for (i = 0; i < str.length; i++) {
7195 chr = str.charCodeAt(i);
7196 hash = (hash << 5) - hash + chr;
7197 hash |= 0; // Convert to 32bit integer
7198 }
7199
7200 return hash;
7201 };
7202 /**
7203 * @name isString
7204 * @function
7205 * @param {any} object
7206 * @returns {boolean}
7207 */
7208
7209
7210 jsPDFAPI.isString = function (object) {
7211 return typeof object === 'string';
7212 };
7213 /**
7214 * Validates if given String is a valid Base64-String
7215 *
7216 * @name validateStringAsBase64
7217 * @public
7218 * @function
7219 * @param {String} possible Base64-String
7220 *
7221 * @returns {boolean}
7222 */
7223
7224
7225 jsPDFAPI.validateStringAsBase64 = function (possibleBase64String) {
7226 possibleBase64String = possibleBase64String || '';
7227 possibleBase64String.toString().trim();
7228 var result = true;
7229
7230 if (possibleBase64String.length === 0) {
7231 result = false;
7232 }
7233
7234 if (possibleBase64String.length % 4 !== 0) {
7235 result = false;
7236 }
7237
7238 if (/^[A-Za-z0-9+\/]+$/.test(possibleBase64String.substr(0, possibleBase64String.length - 2)) === false) {
7239 result = false;
7240 }
7241
7242 if (/^[A-Za-z0-9\/][A-Za-z0-9+\/]|[A-Za-z0-9+\/]=|==$/.test(possibleBase64String.substr(-2)) === false) {
7243 result = false;
7244 }
7245
7246 return result;
7247 };
7248 /**
7249 * Strips out and returns info from a valid base64 data URI
7250 *
7251 * @name extractInfoFromBase64DataURI
7252 * @function
7253 * @param {string} dataUrl a valid data URI of format 'data:[<MIME-type>][;base64],<data>'
7254 * @returns {Array}an Array containing the following
7255 * [0] the complete data URI
7256 * [1] <MIME-type>
7257 * [2] format - the second part of the mime-type i.e 'png' in 'image/png'
7258 * [4] <data>
7259 */
7260
7261
7262 jsPDFAPI.extractInfoFromBase64DataURI = function (dataURI) {
7263 return /^data:([\w]+?\/([\w]+?));\S*;*base64,(.+)$/g.exec(dataURI);
7264 };
7265 /**
7266 * Strips out and returns info from a valid base64 data URI
7267 *
7268 * @name extractImageFromDataUrl
7269 * @function
7270 * @param {string} dataUrl a valid data URI of format 'data:[<MIME-type>][;base64],<data>'
7271 * @returns {Array}an Array containing the following
7272 * [0] the complete data URI
7273 * [1] <MIME-type>
7274 * [2] format - the second part of the mime-type i.e 'png' in 'image/png'
7275 * [4] <data>
7276 */
7277
7278
7279 jsPDFAPI.extractImageFromDataUrl = function (dataUrl) {
7280 dataUrl = dataUrl || '';
7281 var dataUrlParts = dataUrl.split('base64,');
7282 var result = null;
7283
7284 if (dataUrlParts.length === 2) {
7285 var extractedInfo = /^data:(\w*\/\w*);*(charset=[\w=-]*)*;*$/.exec(dataUrlParts[0]);
7286
7287 if (Array.isArray(extractedInfo)) {
7288 result = {
7289 mimeType: extractedInfo[1],
7290 charset: extractedInfo[2],
7291 data: dataUrlParts[1]
7292 };
7293 }
7294 }
7295
7296 return result;
7297 };
7298 /**
7299 * Check to see if ArrayBuffer is supported
7300 *
7301 * @name supportsArrayBuffer
7302 * @function
7303 * @returns {boolean}
7304 */
7305
7306
7307 jsPDFAPI.supportsArrayBuffer = function () {
7308 return typeof ArrayBuffer !== 'undefined' && typeof Uint8Array !== 'undefined';
7309 };
7310 /**
7311 * Tests supplied object to determine if ArrayBuffer
7312 *
7313 * @name isArrayBuffer
7314 * @function
7315 * @param {Object} object an Object
7316 *
7317 * @returns {boolean}
7318 */
7319
7320
7321 jsPDFAPI.isArrayBuffer = function (object) {
7322 if (!this.supportsArrayBuffer()) return false;
7323 return object instanceof ArrayBuffer;
7324 };
7325 /**
7326 * Tests supplied object to determine if it implements the ArrayBufferView (TypedArray) interface
7327 *
7328 * @name isArrayBufferView
7329 * @function
7330 * @param {Object} object an Object
7331 * @returns {boolean}
7332 */
7333
7334
7335 jsPDFAPI.isArrayBufferView = function (object) {
7336 if (!this.supportsArrayBuffer()) return false;
7337 if (typeof Uint32Array === 'undefined') return false;
7338 return object instanceof Int8Array || object instanceof Uint8Array || typeof Uint8ClampedArray !== 'undefined' && object instanceof Uint8ClampedArray || object instanceof Int16Array || object instanceof Uint16Array || object instanceof Int32Array || object instanceof Uint32Array || object instanceof Float32Array || object instanceof Float64Array;
7339 };
7340 /**
7341 * Convert the Buffer to a Binary String
7342 *
7343 * @name binaryStringToUint8Array
7344 * @public
7345 * @function
7346 * @param {ArrayBuffer} BinaryString with ImageData
7347 *
7348 * @returns {Uint8Array}
7349 */
7350
7351
7352 jsPDFAPI.binaryStringToUint8Array = function (binary_string) {
7353 /*
7354 * not sure how efficient this will be will bigger files. Is there a native method?
7355 */
7356 var len = binary_string.length;
7357 var bytes = new Uint8Array(len);
7358
7359 for (var i = 0; i < len; i++) {
7360 bytes[i] = binary_string.charCodeAt(i);
7361 }
7362
7363 return bytes;
7364 };
7365 /**
7366 * Convert the Buffer to a Binary String
7367 *
7368 * @name arrayBufferToBinaryString
7369 * @public
7370 * @function
7371 * @param {ArrayBuffer} ArrayBuffer with ImageData
7372 *
7373 * @returns {String}
7374 */
7375
7376
7377 jsPDFAPI.arrayBufferToBinaryString = function (buffer) {
7378 // if (typeof Uint8Array !== 'undefined' && typeof Uint8Array.prototype.reduce !== 'undefined') {
7379 // return new Uint8Array(buffer).reduce(function (data, byte) {
7380 // return data.push(String.fromCharCode(byte)), data;
7381 // }, []).join('');
7382 // }
7383 if (typeof atob === "function") {
7384 return atob(this.arrayBufferToBase64(buffer));
7385 }
7386 };
7387 /**
7388 * Converts an ArrayBuffer directly to base64
7389 *
7390 * Taken from http://jsperf.com/encoding-xhr-image-data/31
7391 *
7392 * Need to test if this is a better solution for larger files
7393 *
7394 * @name arrayBufferToBase64
7395 * @param {arraybuffer} arrayBuffer
7396 * @public
7397 * @function
7398 *
7399 * @returns {string}
7400 */
7401
7402
7403 jsPDFAPI.arrayBufferToBase64 = function (arrayBuffer) {
7404 var base64 = '';
7405 var encodings = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
7406 var bytes = new Uint8Array(arrayBuffer);
7407 var byteLength = bytes.byteLength;
7408 var byteRemainder = byteLength % 3;
7409 var mainLength = byteLength - byteRemainder;
7410 var a, b, c, d;
7411 var chunk; // Main loop deals with bytes in chunks of 3
7412
7413 for (var i = 0; i < mainLength; i = i + 3) {
7414 // Combine the three bytes into a single integer
7415 chunk = bytes[i] << 16 | bytes[i + 1] << 8 | bytes[i + 2]; // Use bitmasks to extract 6-bit segments from the triplet
7416
7417 a = (chunk & 16515072) >> 18; // 16515072 = (2^6 - 1) << 18
7418
7419 b = (chunk & 258048) >> 12; // 258048 = (2^6 - 1) << 12
7420
7421 c = (chunk & 4032) >> 6; // 4032 = (2^6 - 1) << 6
7422
7423 d = chunk & 63; // 63 = 2^6 - 1
7424 // Convert the raw binary segments to the appropriate ASCII encoding
7425
7426 base64 += encodings[a] + encodings[b] + encodings[c] + encodings[d];
7427 } // Deal with the remaining bytes and padding
7428
7429
7430 if (byteRemainder == 1) {
7431 chunk = bytes[mainLength];
7432 a = (chunk & 252) >> 2; // 252 = (2^6 - 1) << 2
7433 // Set the 4 least significant bits to zero
7434
7435 b = (chunk & 3) << 4; // 3 = 2^2 - 1
7436
7437 base64 += encodings[a] + encodings[b] + '==';
7438 } else if (byteRemainder == 2) {
7439 chunk = bytes[mainLength] << 8 | bytes[mainLength + 1];
7440 a = (chunk & 64512) >> 10; // 64512 = (2^6 - 1) << 10
7441
7442 b = (chunk & 1008) >> 4; // 1008 = (2^6 - 1) << 4
7443 // Set the 2 least significant bits to zero
7444
7445 c = (chunk & 15) << 2; // 15 = 2^4 - 1
7446
7447 base64 += encodings[a] + encodings[b] + encodings[c] + '=';
7448 }
7449
7450 return base64;
7451 };
7452 /**
7453 *
7454 * @name createImageInfo
7455 * @param {Object} data
7456 * @param {number} wd width
7457 * @param {number} ht height
7458 * @param {Object} cs colorSpace
7459 * @param {number} bpc bits per channel
7460 * @param {any} f
7461 * @param {number} imageIndex
7462 * @param {string} alias
7463 * @param {any} dp
7464 * @param {any} trns
7465 * @param {any} pal
7466 * @param {any} smask
7467 * @param {any} p
7468 * @public
7469 * @function
7470 *
7471 * @returns {Object}
7472 */
7473
7474
7475 jsPDFAPI.createImageInfo = function (data, wd, ht, cs, bpc, f, imageIndex, alias, dp, trns, pal, smask, p) {
7476 var info = {
7477 alias: alias,
7478 w: wd,
7479 h: ht,
7480 cs: cs,
7481 bpc: bpc,
7482 i: imageIndex,
7483 data: data // n: objectNumber will be added by putImage code
7484
7485 };
7486 if (f) info.f = f;
7487 if (dp) info.dp = dp;
7488 if (trns) info.trns = trns;
7489 if (pal) info.pal = pal;
7490 if (smask) info.smask = smask;
7491 if (p) info.p = p; // predictor parameter for PNG compression
7492
7493 return info;
7494 };
7495 /**
7496 * Adds an Image to the PDF.
7497 *
7498 * @name addImage
7499 * @public
7500 * @function
7501 * @param {string/Image-Element/Canvas-Element/Uint8Array} imageData imageData as base64 encoded DataUrl or Image-HTMLElement or Canvas-HTMLElement
7502 * @param {string} format format of file if filetype-recognition fails, e.g. 'JPEG'
7503 * @param {number} x x Coordinate (in units declared at inception of PDF document) against left edge of the page
7504 * @param {number} y y Coordinate (in units declared at inception of PDF document) against upper edge of the page
7505 * @param {number} width width of the image (in units declared at inception of PDF document)
7506 * @param {number} height height of the Image (in units declared at inception of PDF document)
7507 * @param {string} alias alias of the image (if used multiple times)
7508 * @param {string} compression compression of the generated JPEG, can have the values 'NONE', 'FAST', 'MEDIUM' and 'SLOW'
7509 * @param {number} rotation rotation of the image in degrees (0-359)
7510 *
7511 * @returns jsPDF
7512 */
7513
7514
7515 jsPDFAPI.addImage = function (imageData, format, x, y, w, h, alias, compression, rotation) {
7516
7517 var tmpImageData = '';
7518
7519 if (typeof format !== 'string') {
7520 var tmp = h;
7521 h = w;
7522 w = y;
7523 y = x;
7524 x = format;
7525 format = tmp;
7526 }
7527
7528 if (_typeof(imageData) === 'object' && !isDOMElement(imageData) && "imageData" in imageData) {
7529 var options = imageData;
7530 imageData = options.imageData;
7531 format = options.format || format || 'UNKNOWN';
7532 x = options.x || x || 0;
7533 y = options.y || y || 0;
7534 w = options.w || w;
7535 h = options.h || h;
7536 alias = options.alias || alias;
7537 compression = options.compression || compression;
7538 rotation = options.rotation || options.angle || rotation;
7539 } //If compression is not explicitly set, determine if we should use compression
7540
7541
7542 var filters = this.internal.getFilters();
7543
7544 if (compression === undefined && filters.indexOf('FlateEncode') !== -1) {
7545 compression = 'SLOW';
7546 }
7547
7548 if (typeof imageData === "string") {
7549 imageData = unescape(imageData);
7550 }
7551
7552 if (isNaN(x) || isNaN(y)) {
7553 console.error('jsPDF.addImage: Invalid coordinates', arguments);
7554 throw new Error('Invalid coordinates passed to jsPDF.addImage');
7555 }
7556
7557 var images = getImages.call(this),
7558 info,
7559 dataAsBinaryString;
7560
7561 if (!(info = checkImagesForAlias(imageData, images))) {
7562 if (isDOMElement(imageData)) imageData = createDataURIFromElement(imageData, format);
7563 if (notDefined(alias)) alias = generateAliasFromImageData(imageData);
7564
7565 if (!(info = checkImagesForAlias(alias, images))) {
7566 if (this.isString(imageData)) {
7567 tmpImageData = this.convertStringToImageData(imageData);
7568
7569 if (tmpImageData !== '') {
7570 imageData = tmpImageData;
7571 } else {
7572 tmpImageData = jsPDFAPI.loadFile(imageData);
7573
7574 if (tmpImageData !== undefined) {
7575 imageData = tmpImageData;
7576 }
7577 }
7578 }
7579
7580 format = this.getImageFileTypeByImageData(imageData, format);
7581 if (!isImageTypeSupported(format)) throw new Error('addImage does not support files of type \'' + format + '\', please ensure that a plugin for \'' + format + '\' support is added.');
7582 /**
7583 * need to test if it's more efficient to convert all binary strings
7584 * to TypedArray - or should we just leave and process as string?
7585 */
7586
7587 if (this.supportsArrayBuffer()) {
7588 // no need to convert if imageData is already uint8array
7589 if (!(imageData instanceof Uint8Array)) {
7590 dataAsBinaryString = imageData;
7591 imageData = this.binaryStringToUint8Array(imageData);
7592 }
7593 }
7594
7595 info = this['process' + format.toUpperCase()](imageData, getImageIndex(images), alias, checkCompressValue(compression), dataAsBinaryString);
7596
7597 if (!info) {
7598 throw new Error('An unknown error occurred whilst processing the image');
7599 }
7600 }
7601 }
7602
7603 writeImageToPDF.call(this, x, y, w, h, info, info.i, images, rotation);
7604 return this;
7605 };
7606 /**
7607 * @name convertStringToImageData
7608 * @function
7609 * @param {string} stringData
7610 * @returns {string} binary data
7611 */
7612
7613
7614 jsPDFAPI.convertStringToImageData = function (stringData) {
7615 var base64Info;
7616 var imageData = '';
7617 var rawData;
7618
7619 if (this.isString(stringData)) {
7620 var base64Info = this.extractImageFromDataUrl(stringData);
7621 rawData = base64Info !== null ? base64Info.data : stringData;
7622
7623 try {
7624 imageData = atob(rawData);
7625 } catch (e) {
7626 if (!jsPDFAPI.validateStringAsBase64(rawData)) {
7627 throw new Error('Supplied Data is not a valid base64-String jsPDF.convertStringToImageData ');
7628 } else {
7629 throw new Error('atob-Error in jsPDF.convertStringToImageData ' + e.message);
7630 }
7631 }
7632 }
7633
7634 return imageData;
7635 };
7636 /**
7637 * JPEG SUPPORT
7638 **/
7639 //takes a string imgData containing the raw bytes of
7640 //a jpeg image and returns [width, height]
7641 //Algorithm from: http://www.64lines.com/jpeg-width-height
7642
7643
7644 var getJpegSize = function getJpegSize(imgData) {
7645
7646 var width, height, numcomponents; // Verify we have a valid jpeg header 0xff,0xd8,0xff,0xe0,?,?,'J','F','I','F',0x00
7647
7648 if (getImageFileTypeByImageData(imgData) !== 'JPEG') {
7649 throw new Error('getJpegSize requires a binary string jpeg file');
7650 }
7651
7652 var blockLength = imgData.charCodeAt(4) * 256 + imgData.charCodeAt(5);
7653 var i = 4,
7654 len = imgData.length;
7655
7656 while (i < len) {
7657 i += blockLength;
7658
7659 if (imgData.charCodeAt(i) !== 0xff) {
7660 throw new Error('getJpegSize could not find the size of the image');
7661 }
7662
7663 if (imgData.charCodeAt(i + 1) === 0xc0 || //(SOF) Huffman - Baseline DCT
7664 imgData.charCodeAt(i + 1) === 0xc1 || //(SOF) Huffman - Extended sequential DCT
7665 imgData.charCodeAt(i + 1) === 0xc2 || // Progressive DCT (SOF2)
7666 imgData.charCodeAt(i + 1) === 0xc3 || // Spatial (sequential) lossless (SOF3)
7667 imgData.charCodeAt(i + 1) === 0xc4 || // Differential sequential DCT (SOF5)
7668 imgData.charCodeAt(i + 1) === 0xc5 || // Differential progressive DCT (SOF6)
7669 imgData.charCodeAt(i + 1) === 0xc6 || // Differential spatial (SOF7)
7670 imgData.charCodeAt(i + 1) === 0xc7) {
7671 height = imgData.charCodeAt(i + 5) * 256 + imgData.charCodeAt(i + 6);
7672 width = imgData.charCodeAt(i + 7) * 256 + imgData.charCodeAt(i + 8);
7673 numcomponents = imgData.charCodeAt(i + 9);
7674 return [width, height, numcomponents];
7675 } else {
7676 i += 2;
7677 blockLength = imgData.charCodeAt(i) * 256 + imgData.charCodeAt(i + 1);
7678 }
7679 }
7680 },
7681 getJpegSizeFromBytes = function getJpegSizeFromBytes(data) {
7682 var hdr = data[0] << 8 | data[1];
7683 if (hdr !== 0xFFD8) throw new Error('Supplied data is not a JPEG');
7684 var len = data.length,
7685 block = (data[4] << 8) + data[5],
7686 pos = 4,
7687 bytes,
7688 width,
7689 height,
7690 numcomponents;
7691
7692 while (pos < len) {
7693 pos += block;
7694 bytes = readBytes(data, pos);
7695 block = (bytes[2] << 8) + bytes[3];
7696
7697 if ((bytes[1] === 0xC0 || bytes[1] === 0xC2) && bytes[0] === 0xFF && block > 7) {
7698 bytes = readBytes(data, pos + 5);
7699 width = (bytes[2] << 8) + bytes[3];
7700 height = (bytes[0] << 8) + bytes[1];
7701 numcomponents = bytes[4];
7702 return {
7703 width: width,
7704 height: height,
7705 numcomponents: numcomponents
7706 };
7707 }
7708
7709 pos += 2;
7710 }
7711
7712 throw new Error('getJpegSizeFromBytes could not find the size of the image');
7713 },
7714 readBytes = function readBytes(data, offset) {
7715 return data.subarray(offset, offset + 5);
7716 };
7717 /**
7718 * @ignore
7719 */
7720
7721
7722 jsPDFAPI.processJPEG = function (data, index, alias, compression, dataAsBinaryString, colorSpace) {
7723
7724 var filter = this.decode.DCT_DECODE,
7725 bpc = 8,
7726 dims;
7727
7728 if (!this.isString(data) && !this.isArrayBuffer(data) && !this.isArrayBufferView(data)) {
7729 return null;
7730 }
7731
7732 if (this.isString(data)) {
7733 dims = getJpegSize(data);
7734 }
7735
7736 if (this.isArrayBuffer(data)) {
7737 data = new Uint8Array(data);
7738 }
7739
7740 if (this.isArrayBufferView(data)) {
7741 dims = getJpegSizeFromBytes(data); // if we already have a stored binary string rep use that
7742
7743 data = dataAsBinaryString || this.arrayBufferToBinaryString(data);
7744 }
7745
7746 if (colorSpace === undefined) {
7747 switch (dims.numcomponents) {
7748 case 1:
7749 colorSpace = this.color_spaces.DEVICE_GRAY;
7750 break;
7751
7752 case 4:
7753 colorSpace = this.color_spaces.DEVICE_CMYK;
7754 break;
7755
7756 default:
7757 case 3:
7758 colorSpace = this.color_spaces.DEVICE_RGB;
7759 break;
7760 }
7761 }
7762
7763 return this.createImageInfo(data, dims.width, dims.height, colorSpace, bpc, filter, index, alias);
7764 };
7765 /**
7766 * @ignore
7767 */
7768
7769
7770 jsPDFAPI.processJPG = function ()
7771 /*data, index, alias, compression, dataAsBinaryString*/
7772 {
7773 return this.processJPEG.apply(this, arguments);
7774 };
7775 /**
7776 * @name getImageProperties
7777 * @function
7778 * @param {Object} imageData
7779 * @returns {Object}
7780 */
7781
7782
7783 jsPDFAPI.getImageProperties = function (imageData) {
7784 var info;
7785 var tmpImageData = '';
7786 var format;
7787
7788 if (isDOMElement(imageData)) {
7789 imageData = createDataURIFromElement(imageData);
7790 }
7791
7792 if (this.isString(imageData)) {
7793 tmpImageData = this.convertStringToImageData(imageData);
7794
7795 if (tmpImageData !== '') {
7796 imageData = tmpImageData;
7797 } else {
7798 tmpImageData = jsPDFAPI.loadFile(imageData);
7799
7800 if (tmpImageData !== undefined) {
7801 imageData = tmpImageData;
7802 }
7803 }
7804 }
7805
7806 format = this.getImageFileTypeByImageData(imageData);
7807
7808 if (!isImageTypeSupported(format)) {
7809 throw new Error('addImage does not support files of type \'' + format + '\', please ensure that a plugin for \'' + format + '\' support is added.');
7810 }
7811 /**
7812 * need to test if it's more efficient to convert all binary strings
7813 * to TypedArray - or should we just leave and process as string?
7814 */
7815
7816
7817 if (this.supportsArrayBuffer()) {
7818 // no need to convert if imageData is already uint8array
7819 if (!(imageData instanceof Uint8Array)) {
7820 imageData = this.binaryStringToUint8Array(imageData);
7821 }
7822 }
7823
7824 info = this['process' + format.toUpperCase()](imageData);
7825
7826 if (!info) {
7827 throw new Error('An unknown error occurred whilst processing the image');
7828 }
7829
7830 return {
7831 fileType: format,
7832 width: info.w,
7833 height: info.h,
7834 colorSpace: info.cs,
7835 compressionMode: info.f,
7836 bitsPerComponent: info.bpc
7837 };
7838 };
7839 })(jsPDF.API);
7840
7841 /**
7842 * @license
7843 * Copyright (c) 2014 Steven Spungin (TwelveTone LLC) steven@twelvetone.tv
7844 *
7845 * Licensed under the MIT License.
7846 * http://opensource.org/licenses/mit-license
7847 */
7848
7849 /**
7850 * jsPDF Annotations PlugIn
7851 *
7852 * There are many types of annotations in a PDF document. Annotations are placed
7853 * on a page at a particular location. They are not 'attached' to an object.
7854 * <br />
7855 * This plugin current supports <br />
7856 * <li> Goto Page (set pageNumber and top in options)
7857 * <li> Goto Name (set name and top in options)
7858 * <li> Goto URL (set url in options)
7859 * <p>
7860 * The destination magnification factor can also be specified when goto is a page number or a named destination. (see documentation below)
7861 * (set magFactor in options). XYZ is the default.
7862 * </p>
7863 * <p>
7864 * Links, Text, Popup, and FreeText are supported.
7865 * </p>
7866 * <p>
7867 * Options In PDF spec Not Implemented Yet
7868 * <li> link border
7869 * <li> named target
7870 * <li> page coordinates
7871 * <li> destination page scaling and layout
7872 * <li> actions other than URL and GotoPage
7873 * <li> background / hover actions
7874 * </p>
7875 * @name annotations
7876 * @module
7877 */
7878
7879 /*
7880 Destination Magnification Factors
7881 See PDF 1.3 Page 386 for meanings and options
7882
7883 [supported]
7884 XYZ (options; left top zoom)
7885 Fit (no options)
7886 FitH (options: top)
7887 FitV (options: left)
7888
7889 [not supported]
7890 FitR
7891 FitB
7892 FitBH
7893 FitBV
7894 */
7895 (function (jsPDFAPI) {
7896
7897 jsPDF.API.events.push(['addPage', function (addPageData) {
7898 var pageInfo = this.internal.getPageInfo(addPageData.pageNumber);
7899 pageInfo.pageContext.annotations = [];
7900 }]);
7901 jsPDFAPI.events.push(['putPage', function (putPageData) {
7902 var pageInfo = this.internal.getPageInfoByObjId(putPageData.objId);
7903 var pageAnnos = putPageData.pageContext.annotations;
7904
7905 var notEmpty = function notEmpty(obj) {
7906 if (typeof obj != 'undefined') {
7907 if (obj != '') {
7908 return true;
7909 }
7910 }
7911 };
7912
7913 var found = false;
7914
7915 for (var a = 0; a < pageAnnos.length && !found; a++) {
7916 var anno = pageAnnos[a];
7917
7918 switch (anno.type) {
7919 case 'link':
7920 if (notEmpty(anno.options.url) || notEmpty(anno.options.pageNumber)) {
7921 found = true;
7922 break;
7923 }
7924
7925 case 'reference':
7926 case 'text':
7927 case 'freetext':
7928 found = true;
7929 break;
7930 }
7931 }
7932
7933 if (found == false) {
7934 return;
7935 }
7936
7937 this.internal.write("/Annots [");
7938 var pageHeight = this.internal.pageSize.height;
7939 var getHorizontalCoordinateString = this.internal.getCoordinateString;
7940 var getVerticalCoordinateString = this.internal.getVerticalCoordinateString;
7941
7942 for (var a = 0; a < pageAnnos.length; a++) {
7943 var anno = pageAnnos[a];
7944
7945 switch (anno.type) {
7946 case 'reference':
7947 // References to Widget Annotations (for AcroForm Fields)
7948 this.internal.write(' ' + anno.object.objId + ' 0 R ');
7949 break;
7950
7951 case 'text':
7952 // Create a an object for both the text and the popup
7953 var objText = this.internal.newAdditionalObject();
7954 var objPopup = this.internal.newAdditionalObject();
7955 var title = anno.title || 'Note';
7956 var rect = "/Rect [" + getHorizontalCoordinateString(anno.bounds.x) + " " + getVerticalCoordinateString(anno.bounds.y + anno.bounds.h) + " " + getHorizontalCoordinateString(anno.bounds.x + anno.bounds.w) + " " + getVerticalCoordinateString(anno.bounds.y) + "] ";
7957 line = '<</Type /Annot /Subtype /' + 'Text' + ' ' + rect + '/Contents (' + anno.contents + ')';
7958 line += ' /Popup ' + objPopup.objId + " 0 R";
7959 line += ' /P ' + pageInfo.objId + " 0 R";
7960 line += ' /T (' + title + ') >>';
7961 objText.content = line;
7962 var parent = objText.objId + ' 0 R';
7963 var popoff = 30;
7964 var rect = "/Rect [" + getHorizontalCoordinateString(anno.bounds.x + popoff) + " " + getVerticalCoordinateString(anno.bounds.y + anno.bounds.h) + " " + getHorizontalCoordinateString(anno.bounds.x + anno.bounds.w + popoff) + " " + getVerticalCoordinateString(anno.bounds.y) + "] ";
7965 line = '<</Type /Annot /Subtype /' + 'Popup' + ' ' + rect + ' /Parent ' + parent;
7966
7967 if (anno.open) {
7968 line += ' /Open true';
7969 }
7970
7971 line += ' >>';
7972 objPopup.content = line;
7973 this.internal.write(objText.objId, '0 R', objPopup.objId, '0 R');
7974 break;
7975
7976 case 'freetext':
7977 var rect = "/Rect [" + getHorizontalCoordinateString(anno.bounds.x) + " " + getVerticalCoordinateString(anno.bounds.y) + " " + getHorizontalCoordinateString(anno.bounds.x + anno.bounds.w) + " " + getVerticalCoordinateString(anno.bounds.y + anno.bounds.h) + "] ";
7978 var color = anno.color || '#000000';
7979 line = '<</Type /Annot /Subtype /' + 'FreeText' + ' ' + rect + '/Contents (' + anno.contents + ')';
7980 line += ' /DS(font: Helvetica,sans-serif 12.0pt; text-align:left; color:#' + color + ')';
7981 line += ' /Border [0 0 0]';
7982 line += ' >>';
7983 this.internal.write(line);
7984 break;
7985
7986 case 'link':
7987 if (anno.options.name) {
7988 var loc = this.annotations._nameMap[anno.options.name];
7989 anno.options.pageNumber = loc.page;
7990 anno.options.top = loc.y;
7991 } else {
7992 if (!anno.options.top) {
7993 anno.options.top = 0;
7994 }
7995 }
7996
7997 var rect = "/Rect [" + getHorizontalCoordinateString(anno.x) + " " + getVerticalCoordinateString(anno.y) + " " + getHorizontalCoordinateString(anno.x + anno.w) + " " + getVerticalCoordinateString(anno.y + anno.h) + "] ";
7998 var line = '';
7999
8000 if (anno.options.url) {
8001 line = '<</Type /Annot /Subtype /Link ' + rect + '/Border [0 0 0] /A <</S /URI /URI (' + anno.options.url + ') >>';
8002 } else if (anno.options.pageNumber) {
8003 // first page is 0
8004 var info = this.internal.getPageInfo(anno.options.pageNumber);
8005 line = '<</Type /Annot /Subtype /Link ' + rect + '/Border [0 0 0] /Dest [' + info.objId + " 0 R";
8006 anno.options.magFactor = anno.options.magFactor || "XYZ";
8007
8008 switch (anno.options.magFactor) {
8009 case 'Fit':
8010 line += ' /Fit]';
8011 break;
8012
8013 case 'FitH':
8014 line += ' /FitH ' + anno.options.top + ']';
8015 break;
8016
8017 case 'FitV':
8018 anno.options.left = anno.options.left || 0;
8019 line += ' /FitV ' + anno.options.left + ']';
8020 break;
8021
8022 case 'XYZ':
8023 default:
8024 var top = getVerticalCoordinateString(anno.options.top);
8025 anno.options.left = anno.options.left || 0; // 0 or null zoom will not change zoom factor
8026
8027 if (typeof anno.options.zoom === 'undefined') {
8028 anno.options.zoom = 0;
8029 }
8030
8031 line += ' /XYZ ' + anno.options.left + ' ' + top + ' ' + anno.options.zoom + ']';
8032 break;
8033 }
8034 }
8035
8036 if (line != '') {
8037 line += " >>";
8038 this.internal.write(line);
8039 }
8040
8041 break;
8042 }
8043 }
8044
8045 this.internal.write("]");
8046 }]);
8047 /**
8048 * @name createAnnotation
8049 * @function
8050 * @param {Object} options
8051 */
8052
8053 jsPDFAPI.createAnnotation = function (options) {
8054 var pageInfo = this.internal.getCurrentPageInfo();
8055
8056 switch (options.type) {
8057 case 'link':
8058 this.link(options.bounds.x, options.bounds.y, options.bounds.w, options.bounds.h, options);
8059 break;
8060
8061 case 'text':
8062 case 'freetext':
8063 pageInfo.pageContext.annotations.push(options);
8064 break;
8065 }
8066 };
8067 /**
8068 * Create a link
8069 *
8070 * valid options
8071 * <li> pageNumber or url [required]
8072 * <p>If pageNumber is specified, top and zoom may also be specified</p>
8073 * @name link
8074 * @function
8075 * @param {number} x
8076 * @param {number} y
8077 * @param {number} w
8078 * @param {number} h
8079 * @param {Object} options
8080 */
8081
8082
8083 jsPDFAPI.link = function (x, y, w, h, options) {
8084 var pageInfo = this.internal.getCurrentPageInfo();
8085 pageInfo.pageContext.annotations.push({
8086 x: x,
8087 y: y,
8088 w: w,
8089 h: h,
8090 options: options,
8091 type: 'link'
8092 });
8093 };
8094 /**
8095 * Currently only supports single line text.
8096 * Returns the width of the text/link
8097 *
8098 * @name textWithLink
8099 * @function
8100 * @param {string} text
8101 * @param {number} x
8102 * @param {number} y
8103 * @param {Object} options
8104 * @returns {number} width the width of the text/link
8105 */
8106
8107
8108 jsPDFAPI.textWithLink = function (text, x, y, options) {
8109 var width = this.getTextWidth(text);
8110 var height = this.internal.getLineHeight() / this.internal.scaleFactor;
8111 this.text(text, x, y); //TODO We really need the text baseline height to do this correctly.
8112 // Or ability to draw text on top, bottom, center, or baseline.
8113
8114 y += height * .2;
8115 this.link(x, y - height, width, height, options);
8116 return width;
8117 }; //TODO move into external library
8118
8119 /**
8120 * @name getTextWidth
8121 * @function
8122 * @param {string} text
8123 * @returns {number} txtWidth
8124 */
8125
8126
8127 jsPDFAPI.getTextWidth = function (text) {
8128 var fontSize = this.internal.getFontSize();
8129 var txtWidth = this.getStringUnitWidth(text) * fontSize / this.internal.scaleFactor;
8130 return txtWidth;
8131 };
8132
8133 return this;
8134 })(jsPDF.API);
8135
8136 /**
8137 * @license
8138 * Copyright (c) 2017 Aras Abbasi
8139 *
8140 * Licensed under the MIT License.
8141 * http://opensource.org/licenses/mit-license
8142 */
8143
8144 /**
8145 * jsPDF arabic parser PlugIn
8146 *
8147 * @name arabic
8148 * @module
8149 */
8150 (function (jsPDFAPI) {
8151 /**
8152 * Arabic shape substitutions: char code => (isolated, final, initial, medial).
8153 * Arabic Substition A
8154 */
8155
8156 var arabicSubstitionA = {
8157 0x0621: [0xFE80],
8158 // ARABIC LETTER HAMZA
8159 0x0622: [0xFE81, 0xFE82],
8160 // ARABIC LETTER ALEF WITH MADDA ABOVE
8161 0x0623: [0xFE83, 0xFE84],
8162 // ARABIC LETTER ALEF WITH HAMZA ABOVE
8163 0x0624: [0xFE85, 0xFE86],
8164 // ARABIC LETTER WAW WITH HAMZA ABOVE
8165 0x0625: [0xFE87, 0xFE88],
8166 // ARABIC LETTER ALEF WITH HAMZA BELOW
8167 0x0626: [0xFE89, 0xFE8A, 0xFE8B, 0xFE8C],
8168 // ARABIC LETTER YEH WITH HAMZA ABOVE
8169 0x0627: [0xFE8D, 0xFE8E],
8170 // ARABIC LETTER ALEF
8171 0x0628: [0xFE8F, 0xFE90, 0xFE91, 0xFE92],
8172 // ARABIC LETTER BEH
8173 0x0629: [0xFE93, 0xFE94],
8174 // ARABIC LETTER TEH MARBUTA
8175 0x062A: [0xFE95, 0xFE96, 0xFE97, 0xFE98],
8176 // ARABIC LETTER TEH
8177 0x062B: [0xFE99, 0xFE9A, 0xFE9B, 0xFE9C],
8178 // ARABIC LETTER THEH
8179 0x062C: [0xFE9D, 0xFE9E, 0xFE9F, 0xFEA0],
8180 // ARABIC LETTER JEEM
8181 0x062D: [0xFEA1, 0xFEA2, 0xFEA3, 0xFEA4],
8182 // ARABIC LETTER HAH
8183 0x062E: [0xFEA5, 0xFEA6, 0xFEA7, 0xFEA8],
8184 // ARABIC LETTER KHAH
8185 0x062F: [0xFEA9, 0xFEAA],
8186 // ARABIC LETTER DAL
8187 0x0630: [0xFEAB, 0xFEAC],
8188 // ARABIC LETTER THAL
8189 0x0631: [0xFEAD, 0xFEAE],
8190 // ARABIC LETTER REH
8191 0x0632: [0xFEAF, 0xFEB0],
8192 // ARABIC LETTER ZAIN
8193 0x0633: [0xFEB1, 0xFEB2, 0xFEB3, 0xFEB4],
8194 // ARABIC LETTER SEEN
8195 0x0634: [0xFEB5, 0xFEB6, 0xFEB7, 0xFEB8],
8196 // ARABIC LETTER SHEEN
8197 0x0635: [0xFEB9, 0xFEBA, 0xFEBB, 0xFEBC],
8198 // ARABIC LETTER SAD
8199 0x0636: [0xFEBD, 0xFEBE, 0xFEBF, 0xFEC0],
8200 // ARABIC LETTER DAD
8201 0x0637: [0xFEC1, 0xFEC2, 0xFEC3, 0xFEC4],
8202 // ARABIC LETTER TAH
8203 0x0638: [0xFEC5, 0xFEC6, 0xFEC7, 0xFEC8],
8204 // ARABIC LETTER ZAH
8205 0x0639: [0xFEC9, 0xFECA, 0xFECB, 0xFECC],
8206 // ARABIC LETTER AIN
8207 0x063A: [0xFECD, 0xFECE, 0xFECF, 0xFED0],
8208 // ARABIC LETTER GHAIN
8209 0x0641: [0xFED1, 0xFED2, 0xFED3, 0xFED4],
8210 // ARABIC LETTER FEH
8211 0x0642: [0xFED5, 0xFED6, 0xFED7, 0xFED8],
8212 // ARABIC LETTER QAF
8213 0x0643: [0xFED9, 0xFEDA, 0xFEDB, 0xFEDC],
8214 // ARABIC LETTER KAF
8215 0x0644: [0xFEDD, 0xFEDE, 0xFEDF, 0xFEE0],
8216 // ARABIC LETTER LAM
8217 0x0645: [0xFEE1, 0xFEE2, 0xFEE3, 0xFEE4],
8218 // ARABIC LETTER MEEM
8219 0x0646: [0xFEE5, 0xFEE6, 0xFEE7, 0xFEE8],
8220 // ARABIC LETTER NOON
8221 0x0647: [0xFEE9, 0xFEEA, 0xFEEB, 0xFEEC],
8222 // ARABIC LETTER HEH
8223 0x0648: [0xFEED, 0xFEEE],
8224 // ARABIC LETTER WAW
8225 0x0649: [0xFEEF, 0xFEF0, 64488, 64489],
8226 // ARABIC LETTER ALEF MAKSURA
8227 0x064A: [0xFEF1, 0xFEF2, 0xFEF3, 0xFEF4],
8228 // ARABIC LETTER YEH
8229 0x0671: [0xFB50, 0xFB51],
8230 // ARABIC LETTER ALEF WASLA
8231 0x0677: [0xFBDD],
8232 // ARABIC LETTER U WITH HAMZA ABOVE
8233 0x0679: [0xFB66, 0xFB67, 0xFB68, 0xFB69],
8234 // ARABIC LETTER TTEH
8235 0x067A: [0xFB5E, 0xFB5F, 0xFB60, 0xFB61],
8236 // ARABIC LETTER TTEHEH
8237 0x067B: [0xFB52, 0xFB53, 0xFB54, 0xFB55],
8238 // ARABIC LETTER BEEH
8239 0x067E: [0xFB56, 0xFB57, 0xFB58, 0xFB59],
8240 // ARABIC LETTER PEH
8241 0x067F: [0xFB62, 0xFB63, 0xFB64, 0xFB65],
8242 // ARABIC LETTER TEHEH
8243 0x0680: [0xFB5A, 0xFB5B, 0xFB5C, 0xFB5D],
8244 // ARABIC LETTER BEHEH
8245 0x0683: [0xFB76, 0xFB77, 0xFB78, 0xFB79],
8246 // ARABIC LETTER NYEH
8247 0x0684: [0xFB72, 0xFB73, 0xFB74, 0xFB75],
8248 // ARABIC LETTER DYEH
8249 0x0686: [0xFB7A, 0xFB7B, 0xFB7C, 0xFB7D],
8250 // ARABIC LETTER TCHEH
8251 0x0687: [0xFB7E, 0xFB7F, 0xFB80, 0xFB81],
8252 // ARABIC LETTER TCHEHEH
8253 0x0688: [0xFB88, 0xFB89],
8254 // ARABIC LETTER DDAL
8255 0x068C: [0xFB84, 0xFB85],
8256 // ARABIC LETTER DAHAL
8257 0x068D: [0xFB82, 0xFB83],
8258 // ARABIC LETTER DDAHAL
8259 0x068E: [0xFB86, 0xFB87],
8260 // ARABIC LETTER DUL
8261 0x0691: [0xFB8C, 0xFB8D],
8262 // ARABIC LETTER RREH
8263 0x0698: [0xFB8A, 0xFB8B],
8264 // ARABIC LETTER JEH
8265 0x06A4: [0xFB6A, 0xFB6B, 0xFB6C, 0xFB6D],
8266 // ARABIC LETTER VEH
8267 0x06A6: [0xFB6E, 0xFB6F, 0xFB70, 0xFB71],
8268 // ARABIC LETTER PEHEH
8269 0x06A9: [0xFB8E, 0xFB8F, 0xFB90, 0xFB91],
8270 // ARABIC LETTER KEHEH
8271 0x06AD: [0xFBD3, 0xFBD4, 0xFBD5, 0xFBD6],
8272 // ARABIC LETTER NG
8273 0x06AF: [0xFB92, 0xFB93, 0xFB94, 0xFB95],
8274 // ARABIC LETTER GAF
8275 0x06B1: [0xFB9A, 0xFB9B, 0xFB9C, 0xFB9D],
8276 // ARABIC LETTER NGOEH
8277 0x06B3: [0xFB96, 0xFB97, 0xFB98, 0xFB99],
8278 // ARABIC LETTER GUEH
8279 0x06BA: [0xFB9E, 0xFB9F],
8280 // ARABIC LETTER NOON GHUNNA
8281 0x06BB: [0xFBA0, 0xFBA1, 0xFBA2, 0xFBA3],
8282 // ARABIC LETTER RNOON
8283 0x06BE: [0xFBAA, 0xFBAB, 0xFBAC, 0xFBAD],
8284 // ARABIC LETTER HEH DOACHASHMEE
8285 0x06C0: [0xFBA4, 0xFBA5],
8286 // ARABIC LETTER HEH WITH YEH ABOVE
8287 0x06C1: [0xFBA6, 0xFBA7, 0xFBA8, 0xFBA9],
8288 // ARABIC LETTER HEH GOAL
8289 0x06C5: [0xFBE0, 0xFBE1],
8290 // ARABIC LETTER KIRGHIZ OE
8291 0x06C6: [0xFBD9, 0xFBDA],
8292 // ARABIC LETTER OE
8293 0x06C7: [0xFBD7, 0xFBD8],
8294 // ARABIC LETTER U
8295 0x06C8: [0xFBDB, 0xFBDC],
8296 // ARABIC LETTER YU
8297 0x06C9: [0xFBE2, 0xFBE3],
8298 // ARABIC LETTER KIRGHIZ YU
8299 0x06CB: [0xFBDE, 0xFBDF],
8300 // ARABIC LETTER VE
8301 0x06CC: [0xFBFC, 0xFBFD, 0xFBFE, 0xFBFF],
8302 // ARABIC LETTER FARSI YEH
8303 0x06D0: [0xFBE4, 0xFBE5, 0xFBE6, 0xFBE7],
8304 //ARABIC LETTER E
8305 0x06D2: [0xFBAE, 0xFBAF],
8306 // ARABIC LETTER YEH BARREE
8307 0x06D3: [0xFBB0, 0xFBB1] // ARABIC LETTER YEH BARREE WITH HAMZA ABOVE
8308
8309 };
8310 var ligatures = {
8311 0xFEDF: {
8312 0xFE82: 0xFEF5,
8313 // ARABIC LIGATURE LAM WITH ALEF WITH MADDA ABOVE ISOLATED FORM
8314 0xFE84: 0xFEF7,
8315 // ARABIC LIGATURE LAM WITH ALEF WITH HAMZA ABOVE ISOLATED FORM
8316 0xFE88: 0xFEF9,
8317 // ARABIC LIGATURE LAM WITH ALEF WITH HAMZA BELOW ISOLATED FORM
8318 0xFE8E: 0xFEFB // ARABIC LIGATURE LAM WITH ALEF ISOLATED FORM
8319
8320 },
8321 0xFEE0: {
8322 0xFE82: 0xFEF6,
8323 // ARABIC LIGATURE LAM WITH ALEF WITH MADDA ABOVE FINAL FORM
8324 0xFE84: 0xFEF8,
8325 // ARABIC LIGATURE LAM WITH ALEF WITH HAMZA ABOVE FINAL FORM
8326 0xFE88: 0xFEFA,
8327 // ARABIC LIGATURE LAM WITH ALEF WITH HAMZA BELOW FINAL FORM
8328 0xFE8E: 0xFEFC // ARABIC LIGATURE LAM WITH ALEF FINAL FORM
8329
8330 },
8331 0xFE8D: {
8332 0xFEDF: {
8333 0xFEE0: {
8334 0xFEEA: 0xFDF2
8335 }
8336 }
8337 },
8338 // ALLAH
8339 0x0651: {
8340 0x064C: 0xFC5E,
8341 // Shadda + Dammatan
8342 0x064D: 0xFC5F,
8343 // Shadda + Kasratan
8344 0x064E: 0xFC60,
8345 // Shadda + Fatha
8346 0x064F: 0xFC61,
8347 // Shadda + Damma
8348 0x0650: 0xFC62 // Shadda + Kasra
8349
8350 }
8351 };
8352 var arabic_diacritics = {
8353 1612: 64606,
8354 // Shadda + Dammatan
8355 1613: 64607,
8356 // Shadda + Kasratan
8357 1614: 64608,
8358 // Shadda + Fatha
8359 1615: 64609,
8360 // Shadda + Damma
8361 1616: 64610 // Shadda + Kasra
8362
8363 };
8364 var alfletter = [1570, 1571, 1573, 1575];
8365 var noChangeInForm = -1;
8366 var isolatedForm = 0;
8367 var finalForm = 1;
8368 var initialForm = 2;
8369 var medialForm = 3;
8370 jsPDFAPI.__arabicParser__ = {}; //private
8371
8372 var isInArabicSubstitutionA = jsPDFAPI.__arabicParser__.isInArabicSubstitutionA = function (letter) {
8373 return typeof arabicSubstitionA[letter.charCodeAt(0)] !== "undefined";
8374 };
8375
8376 var isArabicLetter = jsPDFAPI.__arabicParser__.isArabicLetter = function (letter) {
8377 return typeof letter === "string" && /^[\u0600-\u06FF\u0750-\u077F\u08A0-\u08FF\uFB50-\uFDFF\uFE70-\uFEFF]+$/.test(letter);
8378 };
8379
8380 var isArabicEndLetter = jsPDFAPI.__arabicParser__.isArabicEndLetter = function (letter) {
8381 return isArabicLetter(letter) && isInArabicSubstitutionA(letter) && arabicSubstitionA[letter.charCodeAt(0)].length <= 2;
8382 };
8383
8384 var isArabicAlfLetter = jsPDFAPI.__arabicParser__.isArabicAlfLetter = function (letter) {
8385 return isArabicLetter(letter) && alfletter.indexOf(letter.charCodeAt(0)) >= 0;
8386 };
8387
8388 var arabicLetterHasIsolatedForm = jsPDFAPI.__arabicParser__.arabicLetterHasIsolatedForm = function (letter) {
8389 return isArabicLetter(letter) && isInArabicSubstitutionA(letter) && arabicSubstitionA[letter.charCodeAt(0)].length >= 1;
8390 };
8391
8392 var arabicLetterHasFinalForm = jsPDFAPI.__arabicParser__.arabicLetterHasFinalForm = function (letter) {
8393 return isArabicLetter(letter) && isInArabicSubstitutionA(letter) && arabicSubstitionA[letter.charCodeAt(0)].length >= 2;
8394 };
8395
8396 var arabicLetterHasInitialForm = jsPDFAPI.__arabicParser__.arabicLetterHasInitialForm = function (letter) {
8397 return isArabicLetter(letter) && isInArabicSubstitutionA(letter) && arabicSubstitionA[letter.charCodeAt(0)].length >= 3;
8398 };
8399
8400 var arabicLetterHasMedialForm = jsPDFAPI.__arabicParser__.arabicLetterHasMedialForm = function (letter) {
8401 return isArabicLetter(letter) && isInArabicSubstitutionA(letter) && arabicSubstitionA[letter.charCodeAt(0)].length == 4;
8402 };
8403
8404 var resolveLigatures = jsPDFAPI.__arabicParser__.resolveLigatures = function (letters) {
8405 var i = 0;
8406 var tmpLigatures = ligatures;
8407 var position = isolatedForm;
8408 var result = '';
8409 var effectedLetters = 0;
8410
8411 for (i = 0; i < letters.length; i += 1) {
8412 if (typeof tmpLigatures[letters.charCodeAt(i)] !== "undefined") {
8413 effectedLetters++;
8414 tmpLigatures = tmpLigatures[letters.charCodeAt(i)];
8415
8416 if (typeof tmpLigatures === "number") {
8417 position = getCorrectForm(letters.charAt(i), letters.charAt(i - effectedLetters), letters.charAt(i + 1));
8418 position = position !== -1 ? position : 0;
8419 result += String.fromCharCode(tmpLigatures);
8420 tmpLigatures = ligatures;
8421 effectedLetters = 0;
8422 }
8423
8424 if (i === letters.length - 1) {
8425 tmpLigatures = ligatures;
8426 result += letters.charAt(i - (effectedLetters - 1));
8427 i = i - (effectedLetters - 1);
8428 effectedLetters = 0;
8429 }
8430 } else {
8431 tmpLigatures = ligatures;
8432 result += letters.charAt(i - effectedLetters);
8433 i = i - effectedLetters;
8434 effectedLetters = 0;
8435 }
8436 }
8437
8438 return result;
8439 };
8440
8441 var isArabicDiacritic = jsPDFAPI.__arabicParser__.isArabicDiacritic = function (letter) {
8442 return letter !== undefined && arabic_diacritics[letter.charCodeAt(0)] !== undefined;
8443 };
8444
8445 var getCorrectForm = jsPDFAPI.__arabicParser__.getCorrectForm = function (currentChar, beforeChar, nextChar) {
8446
8447 if (!isArabicLetter(currentChar)) {
8448 return -1;
8449 }
8450
8451 if (isInArabicSubstitutionA(currentChar) === false) {
8452 return noChangeInForm;
8453 }
8454
8455 if (!arabicLetterHasFinalForm(currentChar) || !isArabicLetter(beforeChar) && !isArabicLetter(nextChar) || !isArabicLetter(nextChar) && isArabicEndLetter(beforeChar) || isArabicEndLetter(currentChar) && !isArabicLetter(beforeChar) || isArabicEndLetter(currentChar) && isArabicAlfLetter(beforeChar) || isArabicEndLetter(currentChar) && isArabicEndLetter(beforeChar)) {
8456 return isolatedForm;
8457 }
8458
8459 if (arabicLetterHasMedialForm(currentChar) && isArabicLetter(beforeChar) && !isArabicEndLetter(beforeChar) && isArabicLetter(nextChar) && arabicLetterHasFinalForm(nextChar)) {
8460 return medialForm;
8461 }
8462
8463 if (isArabicEndLetter(currentChar) || !isArabicLetter(nextChar)) {
8464 return finalForm;
8465 }
8466
8467 return initialForm;
8468 };
8469 /**
8470 * @name processArabic
8471 * @function
8472 * @param {string} text
8473 * @param {boolean} reverse
8474 * @returns {string}
8475 */
8476
8477
8478 var processArabic = jsPDFAPI.__arabicParser__.processArabic = jsPDFAPI.processArabic = function (text) {
8479 text = text || "";
8480 var result = "";
8481 var i = 0;
8482 var j = 0;
8483 var position = 0;
8484 var currentLetter = "";
8485 var prevLetter = "";
8486 var nextLetter = "";
8487 var words = text.split("\\s+");
8488 var newWords = [];
8489
8490 for (i = 0; i < words.length; i += 1) {
8491 newWords.push('');
8492
8493 for (j = 0; j < words[i].length; j += 1) {
8494 currentLetter = words[i][j];
8495 prevLetter = words[i][j - 1];
8496 nextLetter = words[i][j + 1];
8497
8498 if (isArabicLetter(currentLetter)) {
8499 position = getCorrectForm(currentLetter, prevLetter, nextLetter);
8500
8501 if (position !== -1) {
8502 newWords[i] += String.fromCharCode(arabicSubstitionA[currentLetter.charCodeAt(0)][position]);
8503 } else {
8504 newWords[i] += currentLetter;
8505 }
8506 } else {
8507 newWords[i] += currentLetter;
8508 }
8509 }
8510
8511 newWords[i] = resolveLigatures(newWords[i]);
8512 }
8513
8514 result = newWords.join(' ');
8515 return result;
8516 };
8517
8518 var arabicParserFunction = function arabicParserFunction(args) {
8519 var text = args.text;
8520 var x = args.x;
8521 var y = args.y;
8522 var options = args.options || {};
8523 var mutex = args.mutex || {};
8524 var lang = options.lang;
8525 var tmpText = [];
8526
8527 if (Object.prototype.toString.call(text) === '[object Array]') {
8528 var i = 0;
8529 tmpText = [];
8530
8531 for (i = 0; i < text.length; i += 1) {
8532 if (Object.prototype.toString.call(text[i]) === '[object Array]') {
8533 tmpText.push([processArabic(text[i][0]), text[i][1], text[i][2]]);
8534 } else {
8535 tmpText.push([processArabic(text[i])]);
8536 }
8537 }
8538
8539 args.text = tmpText;
8540 } else {
8541 args.text = processArabic(text);
8542 }
8543 };
8544
8545 jsPDFAPI.events.push(['preProcessText', arabicParserFunction]);
8546 })(jsPDF.API);
8547
8548 /** @license
8549 * jsPDF Autoprint Plugin
8550 *
8551 * Licensed under the MIT License.
8552 * http://opensource.org/licenses/mit-license
8553 */
8554
8555 /**
8556 * @name autoprint
8557 * @module
8558 */
8559 (function (jsPDFAPI) {
8560 /**
8561 * Makes the PDF automatically print. This works in Chrome, Firefox, Acrobat
8562 * Reader.
8563 *
8564 * @name autoPrint
8565 * @function
8566 * @param {Object} options (optional) Set the attribute variant to 'non-conform' (default) or 'javascript' to activate different methods of automatic printing when opening in a PDF-viewer .
8567 * @returns {jsPDF}
8568 * @example
8569 * var doc = new jsPDF();
8570 * doc.text(10, 10, 'This is a test');
8571 * doc.autoPrint({variant: 'non-conform'});
8572 * doc.save('autoprint.pdf');
8573 */
8574
8575 jsPDFAPI.autoPrint = function (options) {
8576
8577 var refAutoPrintTag;
8578 options = options || {};
8579 options.variant = options.variant || 'non-conform';
8580
8581 switch (options.variant) {
8582 case 'javascript':
8583 //https://github.com/Rob--W/pdf.js/commit/c676ecb5a0f54677b9f3340c3ef2cf42225453bb
8584 this.addJS('print({});');
8585 break;
8586
8587 case 'non-conform':
8588 default:
8589 this.internal.events.subscribe('postPutResources', function () {
8590 refAutoPrintTag = this.internal.newObject();
8591 this.internal.out("<<");
8592 this.internal.out("/S /Named");
8593 this.internal.out("/Type /Action");
8594 this.internal.out("/N /Print");
8595 this.internal.out(">>");
8596 this.internal.out("endobj");
8597 });
8598 this.internal.events.subscribe("putCatalog", function () {
8599 this.internal.out("/OpenAction " + refAutoPrintTag + " 0 R");
8600 });
8601 break;
8602 }
8603
8604 return this;
8605 };
8606 })(jsPDF.API);
8607
8608 /**
8609 * @license
8610 * Copyright (c) 2014 Steven Spungin (TwelveTone LLC) steven@twelvetone.tv
8611 *
8612 * Licensed under the MIT License.
8613 * http://opensource.org/licenses/mit-license
8614 */
8615
8616 /**
8617 * jsPDF Canvas PlugIn
8618 * This plugin mimics the HTML5 Canvas
8619 *
8620 * The goal is to provide a way for current canvas users to print directly to a PDF.
8621 * @name canvas
8622 * @module
8623 */
8624 (function (jsPDFAPI) {
8625 /**
8626 * @class Canvas
8627 * @classdesc A Canvas Wrapper for jsPDF
8628 */
8629
8630 var Canvas = function Canvas() {
8631 var jsPdfInstance = undefined;
8632 Object.defineProperty(this, 'pdf', {
8633 get: function get() {
8634 return jsPdfInstance;
8635 },
8636 set: function set(value) {
8637 jsPdfInstance = value;
8638 }
8639 });
8640 var _width = 150;
8641 /**
8642 * The height property is a positive integer reflecting the height HTML attribute of the <canvas> element interpreted in CSS pixels. When the attribute is not specified, or if it is set to an invalid value, like a negative, the default value of 150 is used.
8643 * This is one of the two properties, the other being width, that controls the size of the canvas.
8644 *
8645 * @name width
8646 */
8647
8648 Object.defineProperty(this, 'width', {
8649 get: function get() {
8650 return _width;
8651 },
8652 set: function set(value) {
8653 if (isNaN(value) || Number.isInteger(value) === false || value < 0) {
8654 _width = 150;
8655 } else {
8656 _width = value;
8657 }
8658
8659 if (this.getContext('2d').pageWrapXEnabled) {
8660 this.getContext('2d').pageWrapX = _width + 1;
8661 }
8662 }
8663 });
8664 var _height = 300;
8665 /**
8666 * The width property is a positive integer reflecting the width HTML attribute of the <canvas> element interpreted in CSS pixels. When the attribute is not specified, or if it is set to an invalid value, like a negative, the default value of 300 is used.
8667 * This is one of the two properties, the other being height, that controls the size of the canvas.
8668 *
8669 * @name height
8670 */
8671
8672 Object.defineProperty(this, 'height', {
8673 get: function get() {
8674 return _height;
8675 },
8676 set: function set(value) {
8677 if (isNaN(value) || Number.isInteger(value) === false || value < 0) {
8678 _height = 300;
8679 } else {
8680 _height = value;
8681 }
8682
8683 if (this.getContext('2d').pageWrapYEnabled) {
8684 this.getContext('2d').pageWrapY = _height + 1;
8685 }
8686 }
8687 });
8688 var _childNodes = [];
8689 Object.defineProperty(this, 'childNodes', {
8690 get: function get() {
8691 return _childNodes;
8692 },
8693 set: function set(value) {
8694 _childNodes = value;
8695 }
8696 });
8697 var _style = {};
8698 Object.defineProperty(this, 'style', {
8699 get: function get() {
8700 return _style;
8701 },
8702 set: function set(value) {
8703 _style = value;
8704 }
8705 });
8706 Object.defineProperty(this, 'parentNode', {
8707 get: function get() {
8708 return false;
8709 }
8710 });
8711 };
8712 /**
8713 * The getContext() method returns a drawing context on the canvas, or null if the context identifier is not supported.
8714 *
8715 * @name getContext
8716 * @function
8717 * @param {string} contextType Is a String containing the context identifier defining the drawing context associated to the canvas. Possible value is "2d", leading to the creation of a Context2D object representing a two-dimensional rendering context.
8718 * @param {object} contextAttributes
8719 */
8720
8721
8722 Canvas.prototype.getContext = function (contextType, contextAttributes) {
8723 contextType = contextType || '2d';
8724 var key;
8725
8726 if (contextType !== '2d') {
8727 return null;
8728 }
8729
8730 for (key in contextAttributes) {
8731 if (this.pdf.context2d.hasOwnProperty(key)) {
8732 this.pdf.context2d[key] = contextAttributes[key];
8733 }
8734 }
8735
8736 this.pdf.context2d._canvas = this;
8737 return this.pdf.context2d;
8738 };
8739 /**
8740 * The toDataURL() method is just a stub to throw an error if accidently called.
8741 *
8742 * @name toDataURL
8743 * @function
8744 */
8745
8746
8747 Canvas.prototype.toDataURL = function () {
8748 throw new Error('toDataURL is not implemented.');
8749 };
8750
8751 jsPDFAPI.events.push(['initialized', function () {
8752 this.canvas = new Canvas();
8753 this.canvas.pdf = this;
8754 }]);
8755 return this;
8756 })(jsPDF.API);
8757
8758 /**
8759 * @license
8760 * ====================================================================
8761 * Copyright (c) 2013 Youssef Beddad, youssef.beddad@gmail.com
8762 * 2013 Eduardo Menezes de Morais, eduardo.morais@usp.br
8763 * 2013 Lee Driscoll, https://github.com/lsdriscoll
8764 * 2014 Juan Pablo Gaviria, https://github.com/juanpgaviria
8765 * 2014 James Hall, james@parall.ax
8766 * 2014 Diego Casorran, https://github.com/diegocr
8767 *
8768 *
8769 * ====================================================================
8770 */
8771
8772 /**
8773 * @name cell
8774 * @module
8775 */
8776 (function (jsPDFAPI) {
8777 /*jslint browser:true */
8778
8779 /*global document: false, jsPDF */
8780
8781 var padding = 3,
8782 margin = 13,
8783 headerFunction,
8784 lastCellPos = {
8785 x: undefined,
8786 y: undefined,
8787 w: undefined,
8788 h: undefined,
8789 ln: undefined
8790 },
8791 pages = 1,
8792 setLastCellPosition = function setLastCellPosition(x, y, w, h, ln) {
8793 lastCellPos = {
8794 'x': x,
8795 'y': y,
8796 'w': w,
8797 'h': h,
8798 'ln': ln
8799 };
8800 },
8801 getLastCellPosition = function getLastCellPosition() {
8802 return lastCellPos;
8803 },
8804 NO_MARGINS = {
8805 left: 0,
8806 top: 0,
8807 bottom: 0
8808 };
8809 /**
8810 * @name setHeaderFunction
8811 * @function
8812 * @param {function} func
8813 */
8814
8815
8816 jsPDFAPI.setHeaderFunction = function (func) {
8817 headerFunction = func;
8818 };
8819 /**
8820 * @name getTextDimensions
8821 * @function
8822 * @param {string} txt
8823 * @returns {Object} dimensions
8824 */
8825
8826
8827 jsPDFAPI.getTextDimensions = function (text, options) {
8828 var fontSize = this.table_font_size || this.internal.getFontSize();
8829 var fontStyle = this.internal.getFont().fontStyle;
8830 options = options || {};
8831 var scaleFactor = options.scaleFactor || this.internal.scaleFactor;
8832 var width = 0;
8833 var amountOfLines = 0;
8834 var height = 0;
8835 var tempWidth = 0;
8836
8837 if (typeof text === 'string') {
8838 width = this.getStringUnitWidth(text) * fontSize;
8839
8840 if (width !== 0) {
8841 amountOfLines = 1;
8842 }
8843 } else if (Object.prototype.toString.call(text) === '[object Array]') {
8844 for (var i = 0; i < text.length; i++) {
8845 tempWidth = this.getStringUnitWidth(text[i]) * fontSize;
8846
8847 if (width < tempWidth) {
8848 width = tempWidth;
8849 }
8850 }
8851
8852 if (width !== 0) {
8853 amountOfLines = text.length;
8854 }
8855 } else {
8856 throw new Error('getTextDimensions expects text-parameter to be of type String or an Array of Strings.');
8857 }
8858
8859 width = width / scaleFactor;
8860 height = Math.max((amountOfLines * fontSize * this.getLineHeightFactor() - fontSize * (this.getLineHeightFactor() - 1)) / scaleFactor, 0);
8861 return {
8862 w: width,
8863 h: height
8864 };
8865 };
8866 /**
8867 * @name cellAddPage
8868 * @function
8869 */
8870
8871
8872 jsPDFAPI.cellAddPage = function () {
8873 var margins = this.margins || NO_MARGINS;
8874 this.addPage();
8875 setLastCellPosition(margins.left, margins.top, undefined, undefined); //setLastCellPosition(undefined, undefined, undefined, undefined, undefined);
8876
8877 pages += 1;
8878 };
8879 /**
8880 * @name cellInitialize
8881 * @function
8882 */
8883
8884
8885 jsPDFAPI.cellInitialize = function () {
8886 lastCellPos = {
8887 x: undefined,
8888 y: undefined,
8889 w: undefined,
8890 h: undefined,
8891 ln: undefined
8892 };
8893 pages = 1;
8894 };
8895 /**
8896 * @name cell
8897 * @function
8898 * @param {number} x
8899 * @param {number} y
8900 * @param {number} w
8901 * @param {number} h
8902 * @param {string} txt
8903 * @param {number} ln lineNumber
8904 * @param {string} align
8905 * @return {jsPDF} jsPDF-instance
8906 */
8907
8908
8909 jsPDFAPI.cell = function (x, y, w, h, txt, ln, align) {
8910 var curCell = getLastCellPosition();
8911 var pgAdded = false; // If this is not the first cell, we must change its position
8912
8913 if (curCell.ln !== undefined) {
8914 if (curCell.ln === ln) {
8915 //Same line
8916 x = curCell.x + curCell.w;
8917 y = curCell.y;
8918 } else {
8919 //New line
8920 var margins = this.margins || NO_MARGINS;
8921
8922 if (curCell.y + curCell.h + h + margin >= this.internal.pageSize.getHeight() - margins.bottom) {
8923 this.cellAddPage();
8924 pgAdded = true;
8925
8926 if (this.printHeaders && this.tableHeaderRow) {
8927 this.printHeaderRow(ln, true);
8928 }
8929 } //We ignore the passed y: the lines may have different heights
8930
8931
8932 y = getLastCellPosition().y + getLastCellPosition().h;
8933 if (pgAdded) y = margin + 10;
8934 }
8935 }
8936
8937 if (txt[0] !== undefined) {
8938 if (this.printingHeaderRow) {
8939 this.rect(x, y, w, h, 'FD');
8940 } else {
8941 this.rect(x, y, w, h);
8942 }
8943
8944 if (align === 'right') {
8945 if (!(txt instanceof Array)) {
8946 txt = [txt];
8947 }
8948
8949 for (var i = 0; i < txt.length; i++) {
8950 var currentLine = txt[i];
8951 var textSize = this.getStringUnitWidth(currentLine) * this.internal.getFontSize() / this.internal.scaleFactor;
8952 this.text(currentLine, x + w - textSize - padding, y + this.internal.getLineHeight() * (i + 1));
8953 }
8954 } else {
8955 this.text(txt, x + padding, y + this.internal.getLineHeight());
8956 }
8957 }
8958
8959 setLastCellPosition(x, y, w, h, ln);
8960 return this;
8961 };
8962 /**
8963 * Return the maximum value from an array
8964 *
8965 * @name arrayMax
8966 * @function
8967 * @param {Array} array
8968 * @param comparisonFn
8969 * @returns {number}
8970 */
8971
8972
8973 jsPDFAPI.arrayMax = function (array, comparisonFn) {
8974 var max = array[0],
8975 i,
8976 ln,
8977 item;
8978
8979 for (i = 0, ln = array.length; i < ln; i += 1) {
8980 item = array[i];
8981
8982 if (comparisonFn) {
8983 if (comparisonFn(max, item) === -1) {
8984 max = item;
8985 }
8986 } else {
8987 if (item > max) {
8988 max = item;
8989 }
8990 }
8991 }
8992
8993 return max;
8994 };
8995 /**
8996 * Create a table from a set of data.
8997 * @name table
8998 * @function
8999 * @param {Integer} [x] : left-position for top-left corner of table
9000 * @param {Integer} [y] top-position for top-left corner of table
9001 * @param {Object[]} [data] As array of objects containing key-value pairs corresponding to a row of data.
9002 * @param {String[]} [headers] Omit or null to auto-generate headers at a performance cost
9003 * @param {Object} [config.printHeaders] True to print column headers at the top of every page
9004 * @param {Object} [config.autoSize] True to dynamically set the column widths to match the widest cell value
9005 * @param {Object} [config.margins] margin values for left, top, bottom, and width
9006 * @param {Object} [config.fontSize] Integer fontSize to use (optional)
9007 * @returns {jsPDF} jsPDF-instance
9008 */
9009
9010
9011 jsPDFAPI.table = function (x, y, data, headers, config) {
9012 if (!data) {
9013 throw 'No data for PDF table';
9014 }
9015
9016 var headerNames = [],
9017 headerPrompts = [],
9018 header,
9019 i,
9020 ln,
9021 cln,
9022 columnMatrix = {},
9023 columnWidths = {},
9024 columnData,
9025 column,
9026 columnMinWidths = [],
9027 j,
9028 tableHeaderConfigs = [],
9029 model,
9030 jln,
9031 func,
9032 //set up defaults. If a value is provided in config, defaults will be overwritten:
9033 autoSize = false,
9034 printHeaders = true,
9035 fontSize = 12,
9036 margins = NO_MARGINS;
9037 margins.width = this.internal.pageSize.getWidth();
9038
9039 if (config) {
9040 //override config defaults if the user has specified non-default behavior:
9041 if (config.autoSize === true) {
9042 autoSize = true;
9043 }
9044
9045 if (config.printHeaders === false) {
9046 printHeaders = false;
9047 }
9048
9049 if (config.fontSize) {
9050 fontSize = config.fontSize;
9051 }
9052
9053 if (config.css && typeof config.css['font-size'] !== "undefined") {
9054 fontSize = config.css['font-size'] * 16;
9055 }
9056
9057 if (config.margins) {
9058 margins = config.margins;
9059 }
9060 }
9061 /**
9062 * @property {Number} lnMod
9063 * Keep track of the current line number modifier used when creating cells
9064 */
9065
9066
9067 this.lnMod = 0;
9068 lastCellPos = {
9069 x: undefined,
9070 y: undefined,
9071 w: undefined,
9072 h: undefined,
9073 ln: undefined
9074 }, pages = 1;
9075 this.printHeaders = printHeaders;
9076 this.margins = margins;
9077 this.setFontSize(fontSize);
9078 this.table_font_size = fontSize; // Set header values
9079
9080 if (headers === undefined || headers === null) {
9081 // No headers defined so we derive from data
9082 headerNames = Object.keys(data[0]);
9083 } else if (headers[0] && typeof headers[0] !== 'string') {
9084 var px2pt = 0.264583 * 72 / 25.4; // Split header configs into names and prompts
9085
9086 for (i = 0, ln = headers.length; i < ln; i += 1) {
9087 header = headers[i];
9088 headerNames.push(header.name);
9089 headerPrompts.push(header.prompt);
9090 columnWidths[header.name] = header.width * px2pt;
9091 }
9092 } else {
9093 headerNames = headers;
9094 }
9095
9096 if (autoSize) {
9097 // Create a matrix of columns e.g., {column_title: [row1_Record, row2_Record]}
9098 func = function func(rec) {
9099 return rec[header];
9100 };
9101
9102 for (i = 0, ln = headerNames.length; i < ln; i += 1) {
9103 header = headerNames[i];
9104 columnMatrix[header] = data.map(func); // get header width
9105
9106 columnMinWidths.push(this.getTextDimensions(headerPrompts[i] || header, {
9107 scaleFactor: 1
9108 }).w);
9109 column = columnMatrix[header]; // get cell widths
9110
9111 for (j = 0, cln = column.length; j < cln; j += 1) {
9112 columnData = column[j];
9113 columnMinWidths.push(this.getTextDimensions(columnData, {
9114 scaleFactor: 1
9115 }).w);
9116 } // get final column width
9117
9118
9119 columnWidths[header] = jsPDFAPI.arrayMax(columnMinWidths); //have to reset
9120
9121 columnMinWidths = [];
9122 }
9123 } // -- Construct the table
9124
9125
9126 if (printHeaders) {
9127 var lineHeight = this.calculateLineHeight(headerNames, columnWidths, headerPrompts.length ? headerPrompts : headerNames); // Construct the header row
9128
9129 for (i = 0, ln = headerNames.length; i < ln; i += 1) {
9130 header = headerNames[i];
9131 tableHeaderConfigs.push([x, y, columnWidths[header], lineHeight, String(headerPrompts.length ? headerPrompts[i] : header)]);
9132 } // Store the table header config
9133
9134
9135 this.setTableHeaderRow(tableHeaderConfigs); // Print the header for the start of the table
9136
9137 this.printHeaderRow(1, false);
9138 } // Construct the data rows
9139
9140
9141 for (i = 0, ln = data.length; i < ln; i += 1) {
9142 var lineHeight;
9143 model = data[i];
9144 lineHeight = this.calculateLineHeight(headerNames, columnWidths, model);
9145
9146 for (j = 0, jln = headerNames.length; j < jln; j += 1) {
9147 header = headerNames[j];
9148 this.cell(x, y, columnWidths[header], lineHeight, model[header], i + 2, header.align);
9149 }
9150 }
9151
9152 this.lastCellPos = lastCellPos;
9153 this.table_x = x;
9154 this.table_y = y;
9155 return this;
9156 };
9157 /**
9158 * Calculate the height for containing the highest column
9159 *
9160 * @name calculateLineHeight
9161 * @function
9162 * @param {String[]} headerNames is the header, used as keys to the data
9163 * @param {Integer[]} columnWidths is size of each column
9164 * @param {Object[]} model is the line of data we want to calculate the height of
9165 * @returns {number} lineHeight
9166 */
9167
9168
9169 jsPDFAPI.calculateLineHeight = function (headerNames, columnWidths, model) {
9170 var header,
9171 lineHeight = 0;
9172
9173 for (var j = 0; j < headerNames.length; j++) {
9174 header = headerNames[j];
9175 model[header] = this.splitTextToSize(String(model[header]), columnWidths[header] - padding);
9176 var h = this.internal.getLineHeight() * model[header].length + padding;
9177 if (h > lineHeight) lineHeight = h;
9178 }
9179
9180 return lineHeight;
9181 };
9182 /**
9183 * Store the config for outputting a table header
9184 *
9185 * @name setTableHeaderRow
9186 * @function
9187 * @param {Object[]} config
9188 * An array of cell configs that would define a header row: Each config matches the config used by jsPDFAPI.cell
9189 * except the ln parameter is excluded
9190 */
9191
9192
9193 jsPDFAPI.setTableHeaderRow = function (config) {
9194 this.tableHeaderRow = config;
9195 };
9196 /**
9197 * Output the store header row
9198 *
9199 * @name printHeaderRow
9200 * @function
9201 * @param {number} lineNumber The line number to output the header at
9202 * @param {boolean} new_page
9203 */
9204
9205
9206 jsPDFAPI.printHeaderRow = function (lineNumber, new_page) {
9207 if (!this.tableHeaderRow) {
9208 throw 'Property tableHeaderRow does not exist.';
9209 }
9210
9211 var tableHeaderCell, tmpArray, i, ln;
9212 this.printingHeaderRow = true;
9213
9214 if (headerFunction !== undefined) {
9215 var position = headerFunction(this, pages);
9216 setLastCellPosition(position[0], position[1], position[2], position[3], -1);
9217 }
9218
9219 this.setFontStyle('bold');
9220 var tempHeaderConf = [];
9221
9222 for (i = 0, ln = this.tableHeaderRow.length; i < ln; i += 1) {
9223 this.setFillColor(200, 200, 200);
9224 tableHeaderCell = this.tableHeaderRow[i];
9225
9226 if (new_page) {
9227 this.margins.top = margin;
9228 tableHeaderCell[1] = this.margins && this.margins.top || 0;
9229 tempHeaderConf.push(tableHeaderCell);
9230 }
9231
9232 tmpArray = [].concat(tableHeaderCell);
9233 this.cell.apply(this, tmpArray.concat(lineNumber));
9234 }
9235
9236 if (tempHeaderConf.length > 0) {
9237 this.setTableHeaderRow(tempHeaderConf);
9238 }
9239
9240 this.setFontStyle('normal');
9241 this.printingHeaderRow = false;
9242 };
9243 })(jsPDF.API);
9244
9245 /**
9246 * jsPDF Context2D PlugIn Copyright (c) 2014 Steven Spungin (TwelveTone LLC) steven@twelvetone.tv
9247 *
9248 * Licensed under the MIT License. http://opensource.org/licenses/mit-license
9249 */
9250
9251 /**
9252 * This plugin mimics the HTML5 CanvasRenderingContext2D.
9253 *
9254 * The goal is to provide a way for current canvas implementations to print directly to a PDF.
9255 *
9256 * @name context2d
9257 * @module
9258 */
9259 (function (jsPDFAPI, globalObj) {
9260
9261 var ContextLayer = function ContextLayer(ctx) {
9262 ctx = ctx || {};
9263 this.isStrokeTransparent = ctx.isStrokeTransparent || false;
9264 this.strokeOpacity = ctx.strokeOpacity || 1;
9265 this.strokeStyle = ctx.strokeStyle || '#000000';
9266 this.fillStyle = ctx.fillStyle || '#000000';
9267 this.isFillTransparent = ctx.isFillTransparent || false;
9268 this.fillOpacity = ctx.fillOpacity || 1;
9269 this.font = ctx.font || '10px sans-serif';
9270 this.textBaseline = ctx.textBaseline || 'alphabetic';
9271 this.textAlign = ctx.textAlign || 'left';
9272 this.lineWidth = ctx.lineWidth || 1;
9273 this.lineJoin = ctx.lineJoin || 'miter';
9274 this.lineCap = ctx.lineCap || 'butt';
9275 this.path = ctx.path || [];
9276 this.transform = typeof ctx.transform !== 'undefined' ? ctx.transform.clone() : new Matrix();
9277 this.globalCompositeOperation = ctx.globalCompositeOperation || 'normal';
9278 this.globalAlpha = ctx.globalAlpha || 1.0;
9279 this.clip_path = ctx.clip_path || [];
9280 this.currentPoint = ctx.currentPoint || new Point();
9281 this.miterLimit = ctx.miterLimit || 10.0;
9282 this.lastPoint = ctx.lastPoint || new Point();
9283 this.ignoreClearRect = typeof ctx.ignoreClearRect === "boolean" ? ctx.ignoreClearRect : true;
9284 return this;
9285 }; //stub
9286
9287
9288 var f2, f3, getHorizontalCoordinateString, getVerticalCoordinateString, getHorizontalCoordinate, getVerticalCoordinate;
9289 jsPDFAPI.events.push(['initialized', function () {
9290 this.context2d = new Context2D(this);
9291 f2 = this.internal.f2;
9292 f3 = this.internal.f3;
9293 getHorizontalCoordinateString = this.internal.getCoordinateString;
9294 getVerticalCoordinateString = this.internal.getVerticalCoordinateString;
9295 getHorizontalCoordinate = this.internal.getHorizontalCoordinate;
9296 getVerticalCoordinate = this.internal.getVerticalCoordinate;
9297 }]);
9298
9299 var Context2D = function Context2D(pdf) {
9300 Object.defineProperty(this, 'canvas', {
9301 get: function get() {
9302 return {
9303 parentNode: false,
9304 style: false
9305 };
9306 }
9307 });
9308 Object.defineProperty(this, 'pdf', {
9309 get: function get() {
9310 return pdf;
9311 }
9312 });
9313 var _pageWrapXEnabled = false;
9314 /**
9315 * @name pageWrapXEnabled
9316 * @type {boolean}
9317 * @default false
9318 */
9319
9320 Object.defineProperty(this, 'pageWrapXEnabled', {
9321 get: function get() {
9322 return _pageWrapXEnabled;
9323 },
9324 set: function set(value) {
9325 _pageWrapXEnabled = Boolean(value);
9326 }
9327 });
9328 var _pageWrapYEnabled = false;
9329 /**
9330 * @name pageWrapYEnabled
9331 * @type {boolean}
9332 * @default true
9333 */
9334
9335 Object.defineProperty(this, 'pageWrapYEnabled', {
9336 get: function get() {
9337 return _pageWrapYEnabled;
9338 },
9339 set: function set(value) {
9340 _pageWrapYEnabled = Boolean(value);
9341 }
9342 });
9343 var _posX = 0;
9344 /**
9345 * @name posX
9346 * @type {number}
9347 * @default 0
9348 */
9349
9350 Object.defineProperty(this, 'posX', {
9351 get: function get() {
9352 return _posX;
9353 },
9354 set: function set(value) {
9355 if (!isNaN(value)) {
9356 _posX = value;
9357 }
9358 }
9359 });
9360 var _posY = 0;
9361 /**
9362 * @name posY
9363 * @type {number}
9364 * @default 0
9365 */
9366
9367 Object.defineProperty(this, 'posY', {
9368 get: function get() {
9369 return _posY;
9370 },
9371 set: function set(value) {
9372 if (!isNaN(value)) {
9373 _posY = value;
9374 }
9375 }
9376 });
9377 var _autoPaging = false;
9378 /**
9379 * @name autoPaging
9380 * @type {boolean}
9381 * @default true
9382 */
9383
9384 Object.defineProperty(this, 'autoPaging', {
9385 get: function get() {
9386 return _autoPaging;
9387 },
9388 set: function set(value) {
9389 _autoPaging = Boolean(value);
9390 }
9391 });
9392 var lastBreak = 0;
9393 /**
9394 * @name lastBreak
9395 * @type {number}
9396 * @default 0
9397 */
9398
9399 Object.defineProperty(this, 'lastBreak', {
9400 get: function get() {
9401 return lastBreak;
9402 },
9403 set: function set(value) {
9404 lastBreak = value;
9405 }
9406 });
9407 var pageBreaks = [];
9408 /**
9409 * Y Position of page breaks.
9410 * @name pageBreaks
9411 * @type {number}
9412 * @default 0
9413 */
9414
9415 Object.defineProperty(this, 'pageBreaks', {
9416 get: function get() {
9417 return pageBreaks;
9418 },
9419 set: function set(value) {
9420 pageBreaks = value;
9421 }
9422 });
9423
9424 var _ctx = new ContextLayer();
9425 /**
9426 * @name ctx
9427 * @type {object}
9428 * @default {}
9429 */
9430
9431
9432 Object.defineProperty(this, 'ctx', {
9433 get: function get() {
9434 return _ctx;
9435 },
9436 set: function set(value) {
9437 if (value instanceof ContextLayer) {
9438 _ctx = value;
9439 }
9440 }
9441 });
9442 /**
9443 * @name path
9444 * @type {array}
9445 * @default []
9446 */
9447
9448 Object.defineProperty(this, 'path', {
9449 get: function get() {
9450 return _ctx.path;
9451 },
9452 set: function set(value) {
9453 _ctx.path = value;
9454 }
9455 });
9456 /**
9457 * @name ctxStack
9458 * @type {array}
9459 * @default []
9460 */
9461
9462 var _ctxStack = [];
9463 Object.defineProperty(this, 'ctxStack', {
9464 get: function get() {
9465 return _ctxStack;
9466 },
9467 set: function set(value) {
9468 _ctxStack = value;
9469 }
9470 });
9471 /**
9472 * Sets or returns the color, gradient, or pattern used to fill the drawing
9473 *
9474 * @name fillStyle
9475 * @default #000000
9476 * @property {(color|gradient|pattern)} value The color of the drawing. Default value is #000000<br />
9477 * A gradient object (linear or radial) used to fill the drawing (not supported by context2d)<br />
9478 * A pattern object to use to fill the drawing (not supported by context2d)
9479 */
9480
9481 Object.defineProperty(this, 'fillStyle', {
9482 get: function get() {
9483 return this.ctx.fillStyle;
9484 },
9485 set: function set(value) {
9486 var rgba;
9487 rgba = getRGBA(value);
9488 this.ctx.fillStyle = rgba.style;
9489 this.ctx.isFillTransparent = rgba.a === 0;
9490 this.ctx.fillOpacity = rgba.a;
9491 this.pdf.setFillColor(rgba.r, rgba.g, rgba.b, {
9492 a: rgba.a
9493 });
9494 this.pdf.setTextColor(rgba.r, rgba.g, rgba.b, {
9495 a: rgba.a
9496 });
9497 }
9498 });
9499 /**
9500 * Sets or returns the color, gradient, or pattern used for strokes
9501 *
9502 * @name strokeStyle
9503 * @default #000000
9504 * @property {color} color A CSS color value that indicates the stroke color of the drawing. Default value is #000000 (not supported by context2d)
9505 * @property {gradient} gradient A gradient object (linear or radial) used to create a gradient stroke (not supported by context2d)
9506 * @property {pattern} pattern A pattern object used to create a pattern stroke (not supported by context2d)
9507 */
9508
9509 Object.defineProperty(this, 'strokeStyle', {
9510 get: function get() {
9511 return this.ctx.strokeStyle;
9512 },
9513 set: function set(value) {
9514 var rgba = getRGBA(value);
9515 this.ctx.strokeStyle = rgba.style;
9516 this.ctx.isStrokeTransparent = rgba.a === 0;
9517 this.ctx.strokeOpacity = rgba.a;
9518
9519 if (rgba.a === 0) {
9520 this.pdf.setDrawColor(255, 255, 255);
9521 } else if (rgba.a === 1) {
9522 this.pdf.setDrawColor(rgba.r, rgba.g, rgba.b);
9523 } else {
9524 this.pdf.setDrawColor(rgba.r, rgba.g, rgba.b);
9525 }
9526 }
9527 });
9528 /**
9529 * Sets or returns the style of the end caps for a line
9530 *
9531 * @name lineCap
9532 * @default butt
9533 * @property {(butt|round|square)} lineCap butt A flat edge is added to each end of the line <br/>
9534 * round A rounded end cap is added to each end of the line<br/>
9535 * square A square end cap is added to each end of the line<br/>
9536 */
9537
9538 Object.defineProperty(this, 'lineCap', {
9539 get: function get() {
9540 return this.ctx.lineCap;
9541 },
9542 set: function set(value) {
9543 if (['butt', 'round', 'square'].indexOf(value) !== -1) {
9544 this.ctx.lineCap = value;
9545 this.pdf.setLineCap(value);
9546 }
9547 }
9548 });
9549 /**
9550 * Sets or returns the current line width
9551 *
9552 * @name lineWidth
9553 * @default 1
9554 * @property {number} lineWidth The current line width, in pixels
9555 */
9556
9557 Object.defineProperty(this, 'lineWidth', {
9558 get: function get() {
9559 return this.ctx.lineWidth;
9560 },
9561 set: function set(value) {
9562 if (!isNaN(value)) {
9563 this.ctx.lineWidth = value;
9564 this.pdf.setLineWidth(value);
9565 }
9566 }
9567 });
9568 /**
9569 * Sets or returns the type of corner created, when two lines meet
9570 */
9571
9572 Object.defineProperty(this, 'lineJoin', {
9573 get: function get() {
9574 return this.ctx.lineJoin;
9575 },
9576 set: function set(value) {
9577 if (['bevel', 'round', 'miter'].indexOf(value) !== -1) {
9578 this.ctx.lineJoin = value;
9579 this.pdf.setLineJoin(value);
9580 }
9581 }
9582 });
9583 /**
9584 * A number specifying the miter limit ratio in coordinate space units. Zero, negative, Infinity, and NaN values are ignored. The default value is 10.0.
9585 *
9586 * @name miterLimit
9587 * @default 10
9588 */
9589
9590 Object.defineProperty(this, 'miterLimit', {
9591 get: function get() {
9592 return this.ctx.miterLimit;
9593 },
9594 set: function set(value) {
9595 if (!isNaN(value)) {
9596 this.ctx.miterLimit = value;
9597 this.pdf.setMiterLimit(value);
9598 }
9599 }
9600 });
9601 Object.defineProperty(this, 'textBaseline', {
9602 get: function get() {
9603 return this.ctx.textBaseline;
9604 },
9605 set: function set(value) {
9606 this.ctx.textBaseline = value;
9607 }
9608 });
9609 Object.defineProperty(this, 'textAlign', {
9610 get: function get() {
9611 return this.ctx.textAlign;
9612 },
9613 set: function set(value) {
9614 if (['right', 'end', 'center', 'left', 'start'].indexOf(value) !== -1) {
9615 this.ctx.textAlign = value;
9616 }
9617 }
9618 });
9619 Object.defineProperty(this, 'font', {
9620 get: function get() {
9621 return this.ctx.font;
9622 },
9623 set: function set(value) {
9624 this.ctx.font = value;
9625 var rx, matches; //source: https://stackoverflow.com/a/10136041
9626
9627 rx = /^\s*(?=(?:(?:[-a-z]+\s*){0,2}(italic|oblique))?)(?=(?:(?:[-a-z]+\s*){0,2}(small-caps))?)(?=(?:(?:[-a-z]+\s*){0,2}(bold(?:er)?|lighter|[1-9]00))?)(?:(?:normal|\1|\2|\3)\s*){0,3}((?:xx?-)?(?:small|large)|medium|smaller|larger|[.\d]+(?:\%|in|[cem]m|ex|p[ctx]))(?:\s*\/\s*(normal|[.\d]+(?:\%|in|[cem]m|ex|p[ctx])))?\s*([-_,\"\'\sa-z]+?)\s*$/i;
9628 matches = rx.exec(value);
9629
9630 if (matches !== null) {
9631 var fontStyle = matches[1];
9632 var fontVariant = matches[2];
9633 var fontWeight = matches[3];
9634 var fontSize = matches[4];
9635 var fontSizeUnit = matches[5];
9636 var fontFamily = matches[6];
9637 } else {
9638 return;
9639 }
9640
9641 if ('px' === fontSizeUnit) {
9642 fontSize = Math.floor(parseFloat(fontSize));
9643 } else if ('em' === fontSizeUnit) {
9644 fontSize = Math.floor(parseFloat(fontSize) * this.pdf.getFontSize());
9645 } else {
9646 fontSize = Math.floor(parseFloat(fontSize));
9647 }
9648
9649 this.pdf.setFontSize(fontSize);
9650 var style = '';
9651
9652 if (fontWeight === 'bold' || parseInt(fontWeight, 10) >= 700 || fontStyle === 'bold') {
9653 style = 'bold';
9654 }
9655
9656 if (fontStyle === 'italic') {
9657 style += 'italic';
9658 }
9659
9660 if (style.length === 0) {
9661 style = 'normal';
9662 }
9663
9664 var jsPdfFontName = '';
9665 var parts = fontFamily.toLowerCase().replace(/"|'/g, '').split(/\s*,\s*/);
9666 var fallbackFonts = {
9667 arial: 'Helvetica',
9668 verdana: 'Helvetica',
9669 helvetica: 'Helvetica',
9670 'sans-serif': 'Helvetica',
9671 fixed: 'Courier',
9672 monospace: 'Courier',
9673 terminal: 'Courier',
9674 courier: 'Courier',
9675 times: 'Times',
9676 cursive: 'Times',
9677 fantasy: 'Times',
9678 serif: 'Times'
9679 };
9680
9681 for (var i = 0; i < parts.length; i++) {
9682 if (this.pdf.internal.getFont(parts[i], style, {
9683 noFallback: true,
9684 disableWarning: true
9685 }) !== undefined) {
9686 jsPdfFontName = parts[i];
9687 break;
9688 } else if (style === 'bolditalic' && this.pdf.internal.getFont(parts[i], 'bold', {
9689 noFallback: true,
9690 disableWarning: true
9691 }) !== undefined) {
9692 jsPdfFontName = parts[i];
9693 style = 'bold';
9694 } else if (this.pdf.internal.getFont(parts[i], 'normal', {
9695 noFallback: true,
9696 disableWarning: true
9697 }) !== undefined) {
9698 jsPdfFontName = parts[i];
9699 style = 'normal';
9700 break;
9701 }
9702 }
9703
9704 if (jsPdfFontName === '') {
9705 for (var i = 0; i < parts.length; i++) {
9706 if (fallbackFonts[parts[i]]) {
9707 jsPdfFontName = fallbackFonts[parts[i]];
9708 break;
9709 }
9710 }
9711 }
9712
9713 jsPdfFontName = jsPdfFontName === '' ? 'Times' : jsPdfFontName;
9714 this.pdf.setFont(jsPdfFontName, style);
9715 }
9716 });
9717 Object.defineProperty(this, 'globalCompositeOperation', {
9718 get: function get() {
9719 return this.ctx.globalCompositeOperation;
9720 },
9721 set: function set(value) {
9722 this.ctx.globalCompositeOperation = value;
9723 }
9724 });
9725 Object.defineProperty(this, 'globalAlpha', {
9726 get: function get() {
9727 return this.ctx.globalAlpha;
9728 },
9729 set: function set(value) {
9730 this.ctx.globalAlpha = value;
9731 }
9732 }); // Not HTML API
9733
9734 Object.defineProperty(this, 'ignoreClearRect', {
9735 get: function get() {
9736 return this.ctx.ignoreClearRect;
9737 },
9738 set: function set(value) {
9739 this.ctx.ignoreClearRect = Boolean(value);
9740 }
9741 });
9742 };
9743
9744 Context2D.prototype.fill = function () {
9745 pathPreProcess.call(this, 'fill', false);
9746 };
9747 /**
9748 * Actually draws the path you have defined
9749 *
9750 * @name stroke
9751 * @function
9752 * @description The stroke() method actually draws the path you have defined with all those moveTo() and lineTo() methods. The default color is black.
9753 */
9754
9755
9756 Context2D.prototype.stroke = function () {
9757 pathPreProcess.call(this, 'stroke', false);
9758 };
9759 /**
9760 * Begins a path, or resets the current
9761 *
9762 * @name beginPath
9763 * @function
9764 * @description The beginPath() method begins a path, or resets the current path.
9765 */
9766
9767
9768 Context2D.prototype.beginPath = function () {
9769 this.path = [{
9770 type: 'begin'
9771 }];
9772 };
9773 /**
9774 * Moves the path to the specified point in the canvas, without creating a line
9775 *
9776 * @name moveTo
9777 * @function
9778 * @param x {Number} The x-coordinate of where to move the path to
9779 * @param y {Number} The y-coordinate of where to move the path to
9780 */
9781
9782
9783 Context2D.prototype.moveTo = function (x, y) {
9784 if (isNaN(x) || isNaN(y)) {
9785 console.error('jsPDF.context2d.moveTo: Invalid arguments', arguments);
9786 throw new Error('Invalid arguments passed to jsPDF.context2d.moveTo');
9787 }
9788
9789 var pt = this.ctx.transform.applyToPoint(new Point(x, y));
9790 this.path.push({
9791 type: 'mt',
9792 x: pt.x,
9793 y: pt.y
9794 });
9795 this.ctx.lastPoint = new Point(x, y);
9796 };
9797 /**
9798 * Creates a path from the current point back to the starting point
9799 *
9800 * @name closePath
9801 * @function
9802 * @description The closePath() method creates a path from the current point back to the starting point.
9803 */
9804
9805
9806 Context2D.prototype.closePath = function () {
9807 var pathBegin = new Point(0, 0);
9808 var i = 0;
9809
9810 for (i = this.path.length - 1; i !== -1; i--) {
9811 if (this.path[i].type === 'begin') {
9812 if (_typeof(this.path[i + 1]) === 'object' && typeof this.path[i + 1].x === 'number') {
9813 pathBegin = new Point(this.path[i + 1].x, this.path[i + 1].y);
9814 this.path.push({
9815 type: 'lt',
9816 x: pathBegin.x,
9817 y: pathBegin.y
9818 });
9819 break;
9820 }
9821 }
9822 }
9823
9824 if (_typeof(this.path[i + 2]) === 'object' && typeof this.path[i + 2].x === 'number') {
9825 this.path.push(JSON.parse(JSON.stringify(this.path[i + 2])));
9826 }
9827
9828 this.path.push({
9829 type: 'close'
9830 });
9831 this.ctx.lastPoint = new Point(pathBegin.x, pathBegin.y);
9832 };
9833 /**
9834 * Adds a new point and creates a line to that point from the last specified point in the canvas
9835 *
9836 * @name lineTo
9837 * @function
9838 * @param x The x-coordinate of where to create the line to
9839 * @param y The y-coordinate of where to create the line to
9840 * @description The lineTo() method adds a new point and creates a line TO that point FROM the last specified point in the canvas (this method does not draw the line).
9841 */
9842
9843
9844 Context2D.prototype.lineTo = function (x, y) {
9845 if (isNaN(x) || isNaN(y)) {
9846 console.error('jsPDF.context2d.lineTo: Invalid arguments', arguments);
9847 throw new Error('Invalid arguments passed to jsPDF.context2d.lineTo');
9848 }
9849
9850 var pt = this.ctx.transform.applyToPoint(new Point(x, y));
9851 this.path.push({
9852 type: 'lt',
9853 x: pt.x,
9854 y: pt.y
9855 });
9856 this.ctx.lastPoint = new Point(pt.x, pt.y);
9857 };
9858 /**
9859 * Clips a region of any shape and size from the original canvas
9860 *
9861 * @name clip
9862 * @function
9863 * @description The clip() method clips a region of any shape and size from the original canvas.
9864 */
9865
9866
9867 Context2D.prototype.clip = function () {
9868 this.ctx.clip_path = JSON.parse(JSON.stringify(this.path));
9869 pathPreProcess.call(this, null, true);
9870 };
9871 /**
9872 * Creates a cubic Bézier curve
9873 *
9874 * @name quadraticCurveTo
9875 * @function
9876 * @param cpx {Number} The x-coordinate of the Bézier control point
9877 * @param cpy {Number} The y-coordinate of the Bézier control point
9878 * @param x {Number} The x-coordinate of the ending point
9879 * @param y {Number} The y-coordinate of the ending point
9880 * @description The quadraticCurveTo() method adds a point to the current path by using the specified control points that represent a quadratic Bézier curve.<br /><br /> A quadratic Bézier curve requires two points. The first point is a control point that is used in the quadratic Bézier calculation and the second point is the ending point for the curve. The starting point for the curve is the last point in the current path. If a path does not exist, use the beginPath() and moveTo() methods to define a starting point.
9881 */
9882
9883
9884 Context2D.prototype.quadraticCurveTo = function (cpx, cpy, x, y) {
9885 if (isNaN(x) || isNaN(y) || isNaN(cpx) || isNaN(cpy)) {
9886 console.error('jsPDF.context2d.quadraticCurveTo: Invalid arguments', arguments);
9887 throw new Error('Invalid arguments passed to jsPDF.context2d.quadraticCurveTo');
9888 }
9889
9890 var pt0 = this.ctx.transform.applyToPoint(new Point(x, y));
9891 var pt1 = this.ctx.transform.applyToPoint(new Point(cpx, cpy));
9892 this.path.push({
9893 type: 'qct',
9894 x1: pt1.x,
9895 y1: pt1.y,
9896 x: pt0.x,
9897 y: pt0.y
9898 });
9899 this.ctx.lastPoint = new Point(pt0.x, pt0.y);
9900 };
9901 /**
9902 * Creates a cubic Bézier curve
9903 *
9904 * @name bezierCurveTo
9905 * @function
9906 * @param cp1x {Number} The x-coordinate of the first Bézier control point
9907 * @param cp1y {Number} The y-coordinate of the first Bézier control point
9908 * @param cp2x {Number} The x-coordinate of the second Bézier control point
9909 * @param cp2y {Number} The y-coordinate of the second Bézier control point
9910 * @param x {Number} The x-coordinate of the ending point
9911 * @param y {Number} The y-coordinate of the ending point
9912 * @description The bezierCurveTo() method adds a point to the current path by using the specified control points that represent a cubic Bézier curve. <br /><br />A cubic bezier curve requires three points. The first two points are control points that are used in the cubic Bézier calculation and the last point is the ending point for the curve. The starting point for the curve is the last point in the current path. If a path does not exist, use the beginPath() and moveTo() methods to define a starting point.
9913 */
9914
9915
9916 Context2D.prototype.bezierCurveTo = function (cp1x, cp1y, cp2x, cp2y, x, y) {
9917 if (isNaN(x) || isNaN(y) || isNaN(cp1x) || isNaN(cp1y) || isNaN(cp2x) || isNaN(cp2y)) {
9918 console.error('jsPDF.context2d.bezierCurveTo: Invalid arguments', arguments);
9919 throw new Error('Invalid arguments passed to jsPDF.context2d.bezierCurveTo');
9920 }
9921
9922 var pt0 = this.ctx.transform.applyToPoint(new Point(x, y));
9923 var pt1 = this.ctx.transform.applyToPoint(new Point(cp1x, cp1y));
9924 var pt2 = this.ctx.transform.applyToPoint(new Point(cp2x, cp2y));
9925 this.path.push({
9926 type: 'bct',
9927 x1: pt1.x,
9928 y1: pt1.y,
9929 x2: pt2.x,
9930 y2: pt2.y,
9931 x: pt0.x,
9932 y: pt0.y
9933 });
9934 this.ctx.lastPoint = new Point(pt0.x, pt0.y);
9935 };
9936 /**
9937 * Creates an arc/curve (used to create circles, or parts of circles)
9938 *
9939 * @name arc
9940 * @function
9941 * @param x {Number} The x-coordinate of the center of the circle
9942 * @param y {Number} The y-coordinate of the center of the circle
9943 * @param radius {Number} The radius of the circle
9944 * @param startAngle {Number} The starting angle, in radians (0 is at the 3 o'clock position of the arc's circle)
9945 * @param endAngle {Number} The ending angle, in radians
9946 * @param counterclockwise {Boolean} Optional. Specifies whether the drawing should be counterclockwise or clockwise. False is default, and indicates clockwise, while true indicates counter-clockwise.
9947 * @description The arc() method creates an arc/curve (used to create circles, or parts of circles).
9948 */
9949
9950
9951 Context2D.prototype.arc = function (x, y, radius, startAngle, endAngle, counterclockwise) {
9952 if (isNaN(x) || isNaN(y) || isNaN(radius) || isNaN(startAngle) || isNaN(endAngle)) {
9953 console.error('jsPDF.context2d.arc: Invalid arguments', arguments);
9954 throw new Error('Invalid arguments passed to jsPDF.context2d.arc');
9955 }
9956
9957 counterclockwise = Boolean(counterclockwise);
9958
9959 if (!this.ctx.transform.isIdentity) {
9960 var xpt = this.ctx.transform.applyToPoint(new Point(x, y));
9961 x = xpt.x;
9962 y = xpt.y;
9963 var x_radPt = this.ctx.transform.applyToPoint(new Point(0, radius));
9964 var x_radPt0 = this.ctx.transform.applyToPoint(new Point(0, 0));
9965 radius = Math.sqrt(Math.pow(x_radPt.x - x_radPt0.x, 2) + Math.pow(x_radPt.y - x_radPt0.y, 2));
9966 }
9967
9968 if (Math.abs(endAngle - startAngle) >= 2 * Math.PI) {
9969 startAngle = 0;
9970 endAngle = 2 * Math.PI;
9971 }
9972
9973 this.path.push({
9974 type: 'arc',
9975 x: x,
9976 y: y,
9977 radius: radius,
9978 startAngle: startAngle,
9979 endAngle: endAngle,
9980 counterclockwise: counterclockwise
9981 }); // this.ctx.lastPoint(new Point(pt.x,pt.y));
9982 };
9983 /**
9984 * Creates an arc/curve between two tangents
9985 *
9986 * @name arcTo
9987 * @function
9988 * @param x1 {Number} The x-coordinate of the first tangent
9989 * @param y1 {Number} The y-coordinate of the first tangent
9990 * @param x2 {Number} The x-coordinate of the second tangent
9991 * @param y2 {Number} The y-coordinate of the second tangent
9992 * @param radius The radius of the arc
9993 * @description The arcTo() method creates an arc/curve between two tangents on the canvas.
9994 */
9995
9996
9997 Context2D.prototype.arcTo = function (x1, y1, x2, y2, radius) {
9998 throw new Error('arcTo not implemented.');
9999 };
10000 /**
10001 * Creates a rectangle
10002 *
10003 * @name rect
10004 * @function
10005 * @param x {Number} The x-coordinate of the upper-left corner of the rectangle
10006 * @param y {Number} The y-coordinate of the upper-left corner of the rectangle
10007 * @param w {Number} The width of the rectangle, in pixels
10008 * @param h {Number} The height of the rectangle, in pixels
10009 * @description The rect() method creates a rectangle.
10010 */
10011
10012
10013 Context2D.prototype.rect = function (x, y, w, h) {
10014 if (isNaN(x) || isNaN(y) || isNaN(w) || isNaN(h)) {
10015 console.error('jsPDF.context2d.rect: Invalid arguments', arguments);
10016 throw new Error('Invalid arguments passed to jsPDF.context2d.rect');
10017 }
10018
10019 this.moveTo(x, y);
10020 this.lineTo(x + w, y);
10021 this.lineTo(x + w, y + h);
10022 this.lineTo(x, y + h);
10023 this.lineTo(x, y);
10024 this.lineTo(x + w, y);
10025 this.lineTo(x, y);
10026 };
10027 /**
10028 * Draws a "filled" rectangle
10029 *
10030 * @name fillRect
10031 * @function
10032 * @param x {Number} The x-coordinate of the upper-left corner of the rectangle
10033 * @param y {Number} The y-coordinate of the upper-left corner of the rectangle
10034 * @param w {Number} The width of the rectangle, in pixels
10035 * @param h {Number} The height of the rectangle, in pixels
10036 * @description The fillRect() method draws a "filled" rectangle. The default color of the fill is black.
10037 */
10038
10039
10040 Context2D.prototype.fillRect = function (x, y, w, h) {
10041 if (isNaN(x) || isNaN(y) || isNaN(w) || isNaN(h)) {
10042 console.error('jsPDF.context2d.fillRect: Invalid arguments', arguments);
10043 throw new Error('Invalid arguments passed to jsPDF.context2d.fillRect');
10044 }
10045
10046 if (isFillTransparent.call(this)) {
10047 return;
10048 }
10049
10050 var tmp = {};
10051
10052 if (this.lineCap !== 'butt') {
10053 tmp.lineCap = this.lineCap;
10054 this.lineCap = 'butt';
10055 }
10056
10057 if (this.lineJoin !== 'miter') {
10058 tmp.lineJoin = this.lineJoin;
10059 this.lineJoin = 'miter';
10060 }
10061
10062 this.beginPath();
10063 this.rect(x, y, w, h);
10064 this.fill();
10065
10066 if (tmp.hasOwnProperty('lineCap')) {
10067 this.lineCap = tmp.lineCap;
10068 }
10069
10070 if (tmp.hasOwnProperty('lineJoin')) {
10071 this.lineJoin = tmp.lineJoin;
10072 }
10073 };
10074 /**
10075 * Draws a rectangle (no fill)
10076 *
10077 * @name strokeRect
10078 * @function
10079 * @param x {Number} The x-coordinate of the upper-left corner of the rectangle
10080 * @param y {Number} The y-coordinate of the upper-left corner of the rectangle
10081 * @param w {Number} The width of the rectangle, in pixels
10082 * @param h {Number} The height of the rectangle, in pixels
10083 * @description The strokeRect() method draws a rectangle (no fill). The default color of the stroke is black.
10084 */
10085
10086
10087 Context2D.prototype.strokeRect = function strokeRect(x, y, w, h) {
10088 if (isNaN(x) || isNaN(y) || isNaN(w) || isNaN(h)) {
10089 console.error('jsPDF.context2d.strokeRect: Invalid arguments', arguments);
10090 throw new Error('Invalid arguments passed to jsPDF.context2d.strokeRect');
10091 }
10092
10093 if (isStrokeTransparent.call(this)) {
10094 return;
10095 }
10096
10097 this.beginPath();
10098 this.rect(x, y, w, h);
10099 this.stroke();
10100 };
10101 /**
10102 * Clears the specified pixels within a given rectangle
10103 *
10104 * @name clearRect
10105 * @function
10106 * @param x {Number} The x-coordinate of the upper-left corner of the rectangle
10107 * @param y {Number} The y-coordinate of the upper-left corner of the rectangle
10108 * @param w {Number} The width of the rectangle to clear, in pixels
10109 * @param h {Number} The height of the rectangle to clear, in pixels
10110 * @description We cannot clear PDF commands that were already written to PDF, so we use white instead. <br />
10111 * As a special case, read a special flag (ignoreClearRect) and do nothing if it is set.
10112 * This results in all calls to clearRect() to do nothing, and keep the canvas transparent.
10113 * This flag is stored in the save/restore context and is managed the same way as other drawing states.
10114 *
10115 */
10116
10117
10118 Context2D.prototype.clearRect = function (x, y, w, h) {
10119 if (isNaN(x) || isNaN(y) || isNaN(w) || isNaN(h)) {
10120 console.error('jsPDF.context2d.clearRect: Invalid arguments', arguments);
10121 throw new Error('Invalid arguments passed to jsPDF.context2d.clearRect');
10122 }
10123
10124 if (this.ignoreClearRect) {
10125 return;
10126 }
10127
10128 this.fillStyle = '#ffffff';
10129 this.fillRect(x, y, w, h);
10130 };
10131 /**
10132 * Saves the state of the current context
10133 *
10134 * @name save
10135 * @function
10136 */
10137
10138
10139 Context2D.prototype.save = function (doStackPush) {
10140 doStackPush = typeof doStackPush === 'boolean' ? doStackPush : true;
10141 var tmpPageNumber = this.pdf.internal.getCurrentPageInfo().pageNumber;
10142
10143 for (var i = 0; i < this.pdf.internal.getNumberOfPages(); i++) {
10144 this.pdf.setPage(i + 1);
10145 this.pdf.internal.out('q');
10146 }
10147
10148 this.pdf.setPage(tmpPageNumber);
10149
10150 if (doStackPush) {
10151 this.ctx.fontSize = this.pdf.internal.getFontSize();
10152 var ctx = new ContextLayer(this.ctx);
10153 this.ctxStack.push(this.ctx);
10154 this.ctx = ctx;
10155 }
10156 };
10157 /**
10158 * Returns previously saved path state and attributes
10159 *
10160 * @name restore
10161 * @function
10162 */
10163
10164
10165 Context2D.prototype.restore = function (doStackPop) {
10166 doStackPop = typeof doStackPop === 'boolean' ? doStackPop : true;
10167 var tmpPageNumber = this.pdf.internal.getCurrentPageInfo().pageNumber;
10168
10169 for (var i = 0; i < this.pdf.internal.getNumberOfPages(); i++) {
10170 this.pdf.setPage(i + 1);
10171 this.pdf.internal.out('Q');
10172 }
10173
10174 this.pdf.setPage(tmpPageNumber);
10175
10176 if (doStackPop && this.ctxStack.length !== 0) {
10177 this.ctx = this.ctxStack.pop();
10178 this.fillStyle = this.ctx.fillStyle;
10179 this.strokeStyle = this.ctx.strokeStyle;
10180 this.font = this.ctx.font;
10181 this.lineCap = this.ctx.lineCap;
10182 this.lineWidth = this.ctx.lineWidth;
10183 this.lineJoin = this.ctx.lineJoin;
10184 }
10185 };
10186 /**
10187 * @name toDataURL
10188 * @function
10189 */
10190
10191
10192 Context2D.prototype.toDataURL = function () {
10193 throw new Error('toDataUrl not implemented.');
10194 }; //helper functions
10195
10196 /**
10197 * Get the decimal values of r, g, b and a
10198 *
10199 * @name getRGBA
10200 * @function
10201 * @private
10202 * @ignore
10203 */
10204
10205
10206 var getRGBA = function getRGBA(style) {
10207 var rxRgb = /rgb\s*\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)/;
10208 var rxRgba = /rgba\s*\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*,\s*([\d\.]+)\s*\)/;
10209 var rxTransparent = /transparent|rgba\s*\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*,\s*0+\s*\)/;
10210 var r, g, b, a;
10211
10212 if (style.isCanvasGradient === true) {
10213 style = style.getColor();
10214 }
10215
10216 if (!style) {
10217 return {
10218 r: 0,
10219 g: 0,
10220 b: 0,
10221 a: 0,
10222 style: style
10223 };
10224 }
10225
10226 if (rxTransparent.test(style)) {
10227 r = 0;
10228 g = 0;
10229 b = 0;
10230 a = 0;
10231 } else {
10232 var matches = rxRgb.exec(style);
10233
10234 if (matches !== null) {
10235 r = parseInt(matches[1]);
10236 g = parseInt(matches[2]);
10237 b = parseInt(matches[3]);
10238 a = 1;
10239 } else {
10240 matches = rxRgba.exec(style);
10241
10242 if (matches !== null) {
10243 r = parseInt(matches[1]);
10244 g = parseInt(matches[2]);
10245 b = parseInt(matches[3]);
10246 a = parseFloat(matches[4]);
10247 } else {
10248 a = 1;
10249
10250 if (typeof style === "string" && style.charAt(0) !== '#') {
10251 var rgbColor = new RGBColor(style);
10252
10253 if (rgbColor.ok) {
10254 style = rgbColor.toHex();
10255 } else {
10256 style = '#000000';
10257 }
10258 }
10259
10260 if (style.length === 4) {
10261 r = style.substring(1, 2);
10262 r += r;
10263 g = style.substring(2, 3);
10264 g += g;
10265 b = style.substring(3, 4);
10266 b += b;
10267 } else {
10268 r = style.substring(1, 3);
10269 g = style.substring(3, 5);
10270 b = style.substring(5, 7);
10271 }
10272
10273 r = parseInt(r, 16);
10274 g = parseInt(g, 16);
10275 b = parseInt(b, 16);
10276 }
10277 }
10278 }
10279
10280 return {
10281 r: r,
10282 g: g,
10283 b: b,
10284 a: a,
10285 style: style
10286 };
10287 };
10288 /**
10289 * @name isFillTransparent
10290 * @function
10291 * @private
10292 * @ignore
10293 * @returns {Boolean}
10294 */
10295
10296
10297 var isFillTransparent = function isFillTransparent() {
10298 return this.ctx.isFillTransparent || this.globalAlpha == 0;
10299 };
10300 /**
10301 * @name isStrokeTransparent
10302 * @function
10303 * @private
10304 * @ignore
10305 * @returns {Boolean}
10306 */
10307
10308
10309 var isStrokeTransparent = function isStrokeTransparent() {
10310 return Boolean(this.ctx.isStrokeTransparent || this.globalAlpha == 0);
10311 };
10312 /**
10313 * Draws "filled" text on the canvas
10314 *
10315 * @name fillText
10316 * @function
10317 * @param text {String} Specifies the text that will be written on the canvas
10318 * @param x {Number} The x coordinate where to start painting the text (relative to the canvas)
10319 * @param y {Number} The y coordinate where to start painting the text (relative to the canvas)
10320 * @param maxWidth {Number} Optional. The maximum allowed width of the text, in pixels
10321 * @description The fillText() method draws filled text on the canvas. The default color of the text is black.
10322 */
10323
10324
10325 Context2D.prototype.fillText = function (text, x, y, maxWidth) {
10326 if (isNaN(x) || isNaN(y) || typeof text !== 'string') {
10327 console.error('jsPDF.context2d.fillText: Invalid arguments', arguments);
10328 throw new Error('Invalid arguments passed to jsPDF.context2d.fillText');
10329 }
10330
10331 maxWidth = isNaN(maxWidth) ? undefined : maxWidth;
10332
10333 if (isFillTransparent.call(this)) {
10334 return;
10335 }
10336
10337 y = getBaseline.call(this, y);
10338 var degs = rad2deg(this.ctx.transform.rotation); // We only use X axis as scale hint
10339
10340 var scale = this.ctx.transform.scaleX;
10341 putText.call(this, {
10342 text: text,
10343 x: x,
10344 y: y,
10345 scale: scale,
10346 angle: degs,
10347 align: this.textAlign,
10348 maxWidth: maxWidth
10349 });
10350 };
10351 /**
10352 * Draws text on the canvas (no fill)
10353 *
10354 * @name strokeText
10355 * @function
10356 * @param text {String} Specifies the text that will be written on the canvas
10357 * @param x {Number} The x coordinate where to start painting the text (relative to the canvas)
10358 * @param y {Number} The y coordinate where to start painting the text (relative to the canvas)
10359 * @param maxWidth {Number} Optional. The maximum allowed width of the text, in pixels
10360 * @description The strokeText() method draws text (with no fill) on the canvas. The default color of the text is black.
10361 */
10362
10363
10364 Context2D.prototype.strokeText = function (text, x, y, maxWidth) {
10365 if (isNaN(x) || isNaN(y) || typeof text !== 'string') {
10366 console.error('jsPDF.context2d.strokeText: Invalid arguments', arguments);
10367 throw new Error('Invalid arguments passed to jsPDF.context2d.strokeText');
10368 }
10369
10370 if (isStrokeTransparent.call(this)) {
10371 return;
10372 }
10373
10374 maxWidth = isNaN(maxWidth) ? undefined : maxWidth;
10375 y = getBaseline.call(this, y);
10376 var degs = rad2deg(this.ctx.transform.rotation);
10377 var scale = this.ctx.transform.scaleX;
10378 putText.call(this, {
10379 text: text,
10380 x: x,
10381 y: y,
10382 scale: scale,
10383 renderingMode: 'stroke',
10384 angle: degs,
10385 align: this.textAlign,
10386 maxWidth: maxWidth
10387 });
10388 };
10389 /**
10390 * Returns an object that contains the width of the specified text
10391 *
10392 * @name measureText
10393 * @function
10394 * @param text {String} The text to be measured
10395 * @description The measureText() method returns an object that contains the width of the specified text, in pixels.
10396 * @returns {Number}
10397 */
10398
10399
10400 Context2D.prototype.measureText = function (text) {
10401 if (typeof text !== 'string') {
10402 console.error('jsPDF.context2d.measureText: Invalid arguments', arguments);
10403 throw new Error('Invalid arguments passed to jsPDF.context2d.measureText');
10404 }
10405
10406 var pdf = this.pdf;
10407 var k = this.pdf.internal.scaleFactor;
10408 var fontSize = pdf.internal.getFontSize();
10409 var txtWidth = pdf.getStringUnitWidth(text) * fontSize / pdf.internal.scaleFactor;
10410 txtWidth *= Math.round(k * 96 / 72 * 10000) / 10000;
10411
10412 var TextMetrics = function TextMetrics(options) {
10413 options = options || {};
10414
10415 var _width = options.width || 0;
10416
10417 Object.defineProperty(this, 'width', {
10418 get: function get() {
10419 return _width;
10420 }
10421 });
10422 return this;
10423 };
10424
10425 return new TextMetrics({
10426 width: txtWidth
10427 });
10428 }; //Transformations
10429
10430 /**
10431 * Scales the current drawing bigger or smaller
10432 *
10433 * @name scale
10434 * @function
10435 * @param scalewidth {Number} Scales the width of the current drawing (1=100%, 0.5=50%, 2=200%, etc.)
10436 * @param scaleheight {Number} Scales the height of the current drawing (1=100%, 0.5=50%, 2=200%, etc.)
10437 * @description The scale() method scales the current drawing, bigger or smaller.
10438 */
10439
10440
10441 Context2D.prototype.scale = function (scalewidth, scaleheight) {
10442 if (isNaN(scalewidth) || isNaN(scaleheight)) {
10443 console.error('jsPDF.context2d.scale: Invalid arguments', arguments);
10444 throw new Error('Invalid arguments passed to jsPDF.context2d.scale');
10445 }
10446
10447 var matrix = new Matrix(scalewidth, 0.0, 0.0, scaleheight, 0.0, 0.0);
10448 this.ctx.transform = this.ctx.transform.multiply(matrix);
10449 };
10450 /**
10451 * Rotates the current drawing
10452 *
10453 * @name rotate
10454 * @function
10455 * @param angle {Number} The rotation angle, in radians.
10456 * @description To calculate from degrees to radians: degrees*Math.PI/180. <br />
10457 * Example: to rotate 5 degrees, specify the following: 5*Math.PI/180
10458 */
10459
10460
10461 Context2D.prototype.rotate = function (angle) {
10462 if (isNaN(angle)) {
10463 console.error('jsPDF.context2d.rotate: Invalid arguments', arguments);
10464 throw new Error('Invalid arguments passed to jsPDF.context2d.rotate');
10465 }
10466
10467 var matrix = new Matrix(Math.cos(angle), Math.sin(angle), -Math.sin(angle), Math.cos(angle), 0.0, 0.0);
10468 this.ctx.transform = this.ctx.transform.multiply(matrix);
10469 };
10470 /**
10471 * Remaps the (0,0) position on the canvas
10472 *
10473 * @name translate
10474 * @function
10475 * @param x {Number} The value to add to horizontal (x) coordinates
10476 * @param y {Number} The value to add to vertical (y) coordinates
10477 * @description The translate() method remaps the (0,0) position on the canvas.
10478 */
10479
10480
10481 Context2D.prototype.translate = function (x, y) {
10482 if (isNaN(x) || isNaN(y)) {
10483 console.error('jsPDF.context2d.translate: Invalid arguments', arguments);
10484 throw new Error('Invalid arguments passed to jsPDF.context2d.translate');
10485 }
10486
10487 var matrix = new Matrix(1.0, 0.0, 0.0, 1.0, x, y);
10488 this.ctx.transform = this.ctx.transform.multiply(matrix);
10489 };
10490 /**
10491 * Replaces the current transformation matrix for the drawing
10492 *
10493 * @name transform
10494 * @function
10495 * @param a {Number} Horizontal scaling
10496 * @param b {Number} Horizontal skewing
10497 * @param c {Number} Vertical skewing
10498 * @param d {Number} Vertical scaling
10499 * @param e {Number} Horizontal moving
10500 * @param f {Number} Vertical moving
10501 * @description Each object on the canvas has a current transformation matrix.<br /><br />The transform() method replaces the current transformation matrix. It multiplies the current transformation matrix with the matrix described by:<br /><br /><br /><br />a c e<br /><br />b d f<br /><br />0 0 1<br /><br />In other words, the transform() method lets you scale, rotate, move, and skew the current context.
10502 */
10503
10504
10505 Context2D.prototype.transform = function (a, b, c, d, e, f) {
10506 if (isNaN(a) || isNaN(b) || isNaN(c) || isNaN(d) || isNaN(e) || isNaN(f)) {
10507 console.error('jsPDF.context2d.transform: Invalid arguments', arguments);
10508 throw new Error('Invalid arguments passed to jsPDF.context2d.transform');
10509 }
10510
10511 var matrix = new Matrix(a, b, c, d, e, f);
10512 this.ctx.transform = this.ctx.transform.multiply(matrix);
10513 };
10514 /**
10515 * Resets the current transform to the identity matrix. Then runs transform()
10516 *
10517 * @name setTransform
10518 * @function
10519 * @param a {Number} Horizontal scaling
10520 * @param b {Number} Horizontal skewing
10521 * @param c {Number} Vertical skewing
10522 * @param d {Number} Vertical scaling
10523 * @param e {Number} Horizontal moving
10524 * @param f {Number} Vertical moving
10525 * @description Each object on the canvas has a current transformation matrix. <br /><br />The setTransform() method resets the current transform to the identity matrix, and then runs transform() with the same arguments.<br /><br />In other words, the setTransform() method lets you scale, rotate, move, and skew the current context.
10526 */
10527
10528
10529 Context2D.prototype.setTransform = function (a, b, c, d, e, f) {
10530 a = isNaN(a) ? 1 : a;
10531 b = isNaN(b) ? 0 : b;
10532 c = isNaN(c) ? 0 : c;
10533 d = isNaN(d) ? 1 : d;
10534 e = isNaN(e) ? 0 : e;
10535 f = isNaN(f) ? 0 : f;
10536 this.ctx.transform = new Matrix(a, b, c, d, e, f);
10537 };
10538 /**
10539 * Draws an image, canvas, or video onto the canvas
10540 *
10541 * @function
10542 * @param img {} Specifies the image, canvas, or video element to use
10543 * @param sx {Number} Optional. The x coordinate where to start clipping
10544 * @param sy {Number} Optional. The y coordinate where to start clipping
10545 * @param swidth {Number} Optional. The width of the clipped image
10546 * @param sheight {Number} Optional. The height of the clipped image
10547 * @param x {Number} The x coordinate where to place the image on the canvas
10548 * @param y {Number} The y coordinate where to place the image on the canvas
10549 * @param width {Number} Optional. The width of the image to use (stretch or reduce the image)
10550 * @param height {Number} Optional. The height of the image to use (stretch or reduce the image)
10551 */
10552
10553
10554 Context2D.prototype.drawImage = function (img, sx, sy, swidth, sheight, x, y, width, height) {
10555 var imageProperties = this.pdf.getImageProperties(img);
10556 var factorX = 1;
10557 var factorY = 1;
10558 var clipFactorX = 1;
10559 var clipFactorY = 1;
10560 var scaleFactorX = 1;
10561
10562 if (typeof swidth !== 'undefined' && typeof width !== 'undefined') {
10563 clipFactorX = width / swidth;
10564 clipFactorY = height / sheight;
10565 factorX = imageProperties.width / swidth * width / swidth;
10566 factorY = imageProperties.height / sheight * height / sheight;
10567 } //is sx and sy are set and x and y not, set x and y with values of sx and sy
10568
10569
10570 if (typeof x === 'undefined') {
10571 x = sx;
10572 y = sy;
10573 sx = 0;
10574 sy = 0;
10575 }
10576
10577 if (typeof swidth !== 'undefined' && typeof width === 'undefined') {
10578 width = swidth;
10579 height = sheight;
10580 }
10581
10582 if (typeof swidth === 'undefined' && typeof width === 'undefined') {
10583 width = imageProperties.width;
10584 height = imageProperties.height;
10585 }
10586
10587 var decomposedTransformationMatrix = this.ctx.transform.decompose();
10588 var angle = rad2deg(decomposedTransformationMatrix.rotate.shx);
10589 scaleFactorX = decomposedTransformationMatrix.scale.sx;
10590 scaleFactorX = decomposedTransformationMatrix.scale.sy;
10591 var matrix = new Matrix();
10592 matrix = matrix.multiply(decomposedTransformationMatrix.translate);
10593 matrix = matrix.multiply(decomposedTransformationMatrix.skew);
10594 matrix = matrix.multiply(decomposedTransformationMatrix.scale);
10595 var mP = matrix.applyToPoint(new Point(width, height));
10596 var xRect = matrix.applyToRectangle(new Rectangle(x - sx * clipFactorX, y - sy * clipFactorY, swidth * factorX, sheight * factorY));
10597 var pageArray = getPagesByPath.call(this, xRect);
10598 var pages = [];
10599
10600 for (var ii = 0; ii < pageArray.length; ii += 1) {
10601 if (pages.indexOf(pageArray[ii]) === -1) {
10602 pages.push(pageArray[ii]);
10603 }
10604 }
10605
10606 pages.sort();
10607 var clipPath;
10608
10609 if (this.autoPaging) {
10610 var min = pages[0];
10611 var max = pages[pages.length - 1];
10612
10613 for (var i = min; i < max + 1; i++) {
10614 this.pdf.setPage(i);
10615
10616 if (this.ctx.clip_path.length !== 0) {
10617 var tmpPaths = this.path;
10618 clipPath = JSON.parse(JSON.stringify(this.ctx.clip_path));
10619 this.path = pathPositionRedo(clipPath, this.posX, -1 * this.pdf.internal.pageSize.height * (i - 1) + this.posY);
10620 drawPaths.call(this, 'fill', true);
10621 this.path = tmpPaths;
10622 }
10623
10624 var tmpRect = JSON.parse(JSON.stringify(xRect));
10625 tmpRect = pathPositionRedo([tmpRect], this.posX, -1 * this.pdf.internal.pageSize.height * (i - 1) + this.posY)[0];
10626 this.pdf.addImage(img, 'jpg', tmpRect.x, tmpRect.y, tmpRect.w, tmpRect.h, null, null, angle);
10627 }
10628 } else {
10629 this.pdf.addImage(img, 'jpg', xRect.x, xRect.y, xRect.w, xRect.h, null, null, angle);
10630 }
10631 };
10632
10633 var getPagesByPath = function getPagesByPath(path, pageWrapX, pageWrapY) {
10634 var result = [];
10635 pageWrapX = pageWrapX || this.pdf.internal.pageSize.width;
10636 pageWrapY = pageWrapY || this.pdf.internal.pageSize.height;
10637
10638 switch (path.type) {
10639 default:
10640 case 'mt':
10641 case 'lt':
10642 result.push(Math.floor((path.y + this.posY) / pageWrapY) + 1);
10643 break;
10644
10645 case 'arc':
10646 result.push(Math.floor((path.y + this.posY - path.radius) / pageWrapY) + 1);
10647 result.push(Math.floor((path.y + this.posY + path.radius) / pageWrapY) + 1);
10648 break;
10649
10650 case 'qct':
10651 var rectOfQuadraticCurve = getQuadraticCurveBoundary(this.ctx.lastPoint.x, this.ctx.lastPoint.y, path.x1, path.y1, path.x, path.y);
10652 result.push(Math.floor(rectOfQuadraticCurve.y / pageWrapY) + 1);
10653 result.push(Math.floor((rectOfQuadraticCurve.y + rectOfQuadraticCurve.h) / pageWrapY) + 1);
10654 break;
10655
10656 case 'bct':
10657 var rectOfBezierCurve = getBezierCurveBoundary(this.ctx.lastPoint.x, this.ctx.lastPoint.y, path.x1, path.y1, path.x2, path.y2, path.x, path.y);
10658 result.push(Math.floor(rectOfBezierCurve.y / pageWrapY) + 1);
10659 result.push(Math.floor((rectOfBezierCurve.y + rectOfBezierCurve.h) / pageWrapY) + 1);
10660 break;
10661
10662 case 'rect':
10663 result.push(Math.floor((path.y + this.posY) / pageWrapY) + 1);
10664 result.push(Math.floor((path.y + path.h + this.posY) / pageWrapY) + 1);
10665 }
10666
10667 for (var i = 0; i < result.length; i += 1) {
10668 while (this.pdf.internal.getNumberOfPages() < result[i]) {
10669 addPage.call(this);
10670 }
10671 }
10672
10673 return result;
10674 };
10675
10676 var addPage = function addPage() {
10677 var fillStyle = this.fillStyle;
10678 var strokeStyle = this.strokeStyle;
10679 var font = this.font;
10680 var lineCap = this.lineCap;
10681 var lineWidth = this.lineWidth;
10682 var lineJoin = this.lineJoin;
10683 this.pdf.addPage();
10684 this.fillStyle = fillStyle;
10685 this.strokeStyle = strokeStyle;
10686 this.font = font;
10687 this.lineCap = lineCap;
10688 this.lineWidth = lineWidth;
10689 this.lineJoin = lineJoin;
10690 };
10691
10692 var pathPositionRedo = function pathPositionRedo(paths, x, y) {
10693 for (var i = 0; i < paths.length; i++) {
10694 switch (paths[i].type) {
10695 case 'bct':
10696 paths[i].x2 += x;
10697 paths[i].y2 += y;
10698
10699 case 'qct':
10700 paths[i].x1 += x;
10701 paths[i].y1 += y;
10702
10703 case 'mt':
10704 case 'lt':
10705 case 'arc':
10706 default:
10707 paths[i].x += x;
10708 paths[i].y += y;
10709 }
10710 }
10711
10712 return paths;
10713 };
10714
10715 var pathPreProcess = function pathPreProcess(rule, isClip) {
10716 var fillStyle = this.fillStyle;
10717 var strokeStyle = this.strokeStyle;
10718 var font = this.font;
10719 var lineCap = this.lineCap;
10720 var lineWidth = this.lineWidth;
10721 var lineJoin = this.lineJoin;
10722 var origPath = JSON.parse(JSON.stringify(this.path));
10723 var xPath = JSON.parse(JSON.stringify(this.path));
10724 var clipPath;
10725 var tmpPath;
10726 var pages = [];
10727
10728 for (var i = 0; i < xPath.length; i++) {
10729 if (typeof xPath[i].x !== "undefined") {
10730 var page = getPagesByPath.call(this, xPath[i]);
10731
10732 for (var ii = 0; ii < page.length; ii += 1) {
10733 if (pages.indexOf(page[ii]) === -1) {
10734 pages.push(page[ii]);
10735 }
10736 }
10737 }
10738 }
10739
10740 for (var i = 0; i < pages.length; i++) {
10741 while (this.pdf.internal.getNumberOfPages() < pages[i]) {
10742 addPage.call(this);
10743 }
10744 }
10745
10746 pages.sort();
10747
10748 if (this.autoPaging) {
10749 var min = pages[0];
10750 var max = pages[pages.length - 1];
10751
10752 for (var i = min; i < max + 1; i++) {
10753 this.pdf.setPage(i);
10754 this.fillStyle = fillStyle;
10755 this.strokeStyle = strokeStyle;
10756 this.lineCap = lineCap;
10757 this.lineWidth = lineWidth;
10758 this.lineJoin = lineJoin;
10759
10760 if (this.ctx.clip_path.length !== 0) {
10761 var tmpPaths = this.path;
10762 clipPath = JSON.parse(JSON.stringify(this.ctx.clip_path));
10763 this.path = pathPositionRedo(clipPath, this.posX, -1 * this.pdf.internal.pageSize.height * (i - 1) + this.posY);
10764 drawPaths.call(this, rule, true);
10765 this.path = tmpPaths;
10766 }
10767
10768 tmpPath = JSON.parse(JSON.stringify(origPath));
10769 this.path = pathPositionRedo(tmpPath, this.posX, -1 * this.pdf.internal.pageSize.height * (i - 1) + this.posY);
10770
10771 if (isClip === false || i === 0) {
10772 drawPaths.call(this, rule, isClip);
10773 }
10774 }
10775 } else {
10776 drawPaths.call(this, rule, isClip);
10777 }
10778
10779 this.path = origPath;
10780 };
10781 /**
10782 * Processes the paths
10783 *
10784 * @function
10785 * @param rule {String}
10786 * @param isClip {Boolean}
10787 * @private
10788 * @ignore
10789 */
10790
10791
10792 var drawPaths = function drawPaths(rule, isClip) {
10793 if (rule === 'stroke' && !isClip && isStrokeTransparent.call(this)) {
10794 return;
10795 }
10796
10797 if (rule !== 'stroke' && !isClip && isFillTransparent.call(this)) {
10798 return;
10799 }
10800
10801 var moves = [];
10802 var alpha = this.ctx.globalAlpha;
10803
10804 if (this.ctx.fillOpacity < 1) {
10805 alpha = this.ctx.fillOpacity;
10806 }
10807
10808 var xPath = this.path;
10809
10810 for (var i = 0; i < xPath.length; i++) {
10811 var pt = xPath[i];
10812
10813 switch (pt.type) {
10814 case 'begin':
10815 moves.push({
10816 begin: true
10817 });
10818 break;
10819
10820 case 'close':
10821 moves.push({
10822 close: true
10823 });
10824 break;
10825
10826 case 'mt':
10827 moves.push({
10828 start: pt,
10829 deltas: [],
10830 abs: []
10831 });
10832 break;
10833
10834 case 'lt':
10835 var iii = moves.length;
10836
10837 if (!isNaN(xPath[i - 1].x)) {
10838 var delta = [pt.x - xPath[i - 1].x, pt.y - xPath[i - 1].y];
10839
10840 if (iii > 0) {
10841 for (iii; iii >= 0; iii--) {
10842 if (moves[iii - 1].close !== true && moves[iii - 1].begin !== true) {
10843 moves[iii - 1].deltas.push(delta);
10844 moves[iii - 1].abs.push(pt);
10845 break;
10846 }
10847 }
10848 }
10849 }
10850
10851 break;
10852
10853 case 'bct':
10854 var delta = [pt.x1 - xPath[i - 1].x, pt.y1 - xPath[i - 1].y, pt.x2 - xPath[i - 1].x, pt.y2 - xPath[i - 1].y, pt.x - xPath[i - 1].x, pt.y - xPath[i - 1].y];
10855 moves[moves.length - 1].deltas.push(delta);
10856 break;
10857
10858 case 'qct':
10859 var x1 = xPath[i - 1].x + 2.0 / 3.0 * (pt.x1 - xPath[i - 1].x);
10860 var y1 = xPath[i - 1].y + 2.0 / 3.0 * (pt.y1 - xPath[i - 1].y);
10861 var x2 = pt.x + 2.0 / 3.0 * (pt.x1 - pt.x);
10862 var y2 = pt.y + 2.0 / 3.0 * (pt.y1 - pt.y);
10863 var x3 = pt.x;
10864 var y3 = pt.y;
10865 var delta = [x1 - xPath[i - 1].x, y1 - xPath[i - 1].y, x2 - xPath[i - 1].x, y2 - xPath[i - 1].y, x3 - xPath[i - 1].x, y3 - xPath[i - 1].y];
10866 moves[moves.length - 1].deltas.push(delta);
10867 break;
10868
10869 case 'arc':
10870 moves.push({
10871 deltas: [],
10872 abs: [],
10873 arc: true
10874 });
10875
10876 if (Array.isArray(moves[moves.length - 1].abs)) {
10877 moves[moves.length - 1].abs.push(pt);
10878 }
10879
10880 break;
10881 }
10882 }
10883
10884 var style;
10885
10886 if (!isClip) {
10887 if (rule === 'stroke') {
10888 style = 'stroke';
10889 } else {
10890 style = 'fill';
10891 }
10892 } else {
10893 style = null;
10894 }
10895
10896 for (var i = 0; i < moves.length; i++) {
10897 if (moves[i].arc) {
10898 var arcs = moves[i].abs;
10899
10900 for (var ii = 0; ii < arcs.length; ii++) {
10901 var arc = arcs[ii];
10902
10903 if (typeof arc.startAngle !== 'undefined') {
10904 var start = rad2deg(arc.startAngle);
10905 var end = rad2deg(arc.endAngle);
10906 var x = arc.x;
10907 var y = arc.y;
10908 drawArc.call(this, x, y, arc.radius, start, end, arc.counterclockwise, style, isClip);
10909 } else {
10910 drawLine.call(this, arc.x, arc.y);
10911 }
10912 }
10913 }
10914
10915 if (!moves[i].arc) {
10916 if (moves[i].close !== true && moves[i].begin !== true) {
10917 var x = moves[i].start.x;
10918 var y = moves[i].start.y;
10919 drawLines.call(this, moves[i].deltas, x, y, null, null);
10920 }
10921 }
10922 }
10923
10924 if (style) {
10925 putStyle.call(this, style);
10926 }
10927
10928 if (isClip) {
10929 doClip.call(this);
10930 }
10931 };
10932
10933 var getBaseline = function getBaseline(y) {
10934 var height = this.pdf.internal.getFontSize() / this.pdf.internal.scaleFactor;
10935 var descent = height * (this.pdf.internal.getLineHeightFactor() - 1);
10936
10937 switch (this.ctx.textBaseline) {
10938 case 'bottom':
10939 return y - descent;
10940
10941 case 'top':
10942 return y + height - descent;
10943
10944 case 'hanging':
10945 return y + height - 2 * descent;
10946
10947 case 'middle':
10948 return y + height / 2 - descent;
10949
10950 case 'ideographic':
10951 // TODO not implemented
10952 return y;
10953
10954 case 'alphabetic':
10955 default:
10956 return y;
10957 }
10958 };
10959
10960 Context2D.prototype.createLinearGradient = function createLinearGradient() {
10961 var canvasGradient = function canvasGradient() {};
10962
10963 canvasGradient.colorStops = [];
10964
10965 canvasGradient.addColorStop = function (offset, color) {
10966 this.colorStops.push([offset, color]);
10967 };
10968
10969 canvasGradient.getColor = function () {
10970 if (this.colorStops.length === 0) {
10971 return '#000000';
10972 }
10973
10974 return this.colorStops[0][1];
10975 };
10976
10977 canvasGradient.isCanvasGradient = true;
10978 return canvasGradient;
10979 };
10980
10981 Context2D.prototype.createPattern = function createPattern() {
10982 return this.createLinearGradient();
10983 };
10984
10985 Context2D.prototype.createRadialGradient = function createRadialGradient() {
10986 return this.createLinearGradient();
10987 };
10988 /**
10989 *
10990 * @param x Edge point X
10991 * @param y Edge point Y
10992 * @param r Radius
10993 * @param a1 start angle
10994 * @param a2 end angle
10995 * @param counterclockwise
10996 * @param style
10997 * @param isClip
10998 */
10999
11000
11001 var drawArc = function drawArc(x, y, r, a1, a2, counterclockwise, style, isClip) {
11002 var k = this.pdf.internal.scaleFactor;
11003 var a1r = deg2rad(a1);
11004 var a2r = deg2rad(a2);
11005 var curves = createArc.call(this, r, a1r, a2r, counterclockwise);
11006
11007 for (var i = 0; i < curves.length; i++) {
11008 var curve = curves[i];
11009
11010 if (i === 0) {
11011 doMove.call(this, curve.x1 + x, curve.y1 + y);
11012 }
11013 drawCurve.call(this, x, y, curve.x2, curve.y2, curve.x3, curve.y3, curve.x4, curve.y4);
11014 }
11015
11016 if (!isClip) {
11017 putStyle.call(this, style);
11018 } else {
11019 doClip.call(this);
11020 }
11021 };
11022
11023 var putStyle = function putStyle(style) {
11024 switch (style) {
11025 case 'stroke':
11026 this.pdf.internal.out('S');
11027 break;
11028
11029 case 'fill':
11030 this.pdf.internal.out('f');
11031 break;
11032 }
11033 };
11034
11035 var doClip = function doClip() {
11036 this.pdf.clip();
11037 };
11038
11039 var doMove = function doMove(x, y) {
11040 this.pdf.internal.out(getHorizontalCoordinateString(x) + ' ' + getVerticalCoordinateString(y) + ' m');
11041 };
11042
11043 var putText = function putText(options) {
11044 var textAlign;
11045
11046 switch (options.align) {
11047 case 'right':
11048 case 'end':
11049 textAlign = 'right';
11050 break;
11051
11052 case 'center':
11053 textAlign = 'center';
11054 break;
11055
11056 case 'left':
11057 case 'start':
11058 default:
11059 textAlign = 'left';
11060 break;
11061 }
11062
11063 var pt = this.ctx.transform.applyToPoint(new Point(options.x, options.y));
11064 var decomposedTransformationMatrix = this.ctx.transform.decompose();
11065 var matrix = new Matrix();
11066 matrix = matrix.multiply(decomposedTransformationMatrix.translate);
11067 matrix = matrix.multiply(decomposedTransformationMatrix.skew);
11068 matrix = matrix.multiply(decomposedTransformationMatrix.scale);
11069 var textDimensions = this.pdf.getTextDimensions(options.text);
11070 var textRect = this.ctx.transform.applyToRectangle(new Rectangle(options.x, options.y, textDimensions.w, textDimensions.h));
11071 var textXRect = matrix.applyToRectangle(new Rectangle(options.x, options.y - textDimensions.h, textDimensions.w, textDimensions.h));
11072 var pageArray = getPagesByPath.call(this, textXRect);
11073 var pages = [];
11074
11075 for (var ii = 0; ii < pageArray.length; ii += 1) {
11076 if (pages.indexOf(pageArray[ii]) === -1) {
11077 pages.push(pageArray[ii]);
11078 }
11079 }
11080
11081 pages.sort();
11082 var clipPath;
11083
11084 if (this.autoPaging === true) {
11085 var min = pages[0];
11086 var max = pages[pages.length - 1];
11087
11088 for (var i = min; i < max + 1; i++) {
11089 this.pdf.setPage(i);
11090
11091 if (this.ctx.clip_path.length !== 0) {
11092 var tmpPaths = this.path;
11093 clipPath = JSON.parse(JSON.stringify(this.ctx.clip_path));
11094 this.path = pathPositionRedo(clipPath, this.posX, -1 * this.pdf.internal.pageSize.height * (i - 1) + this.posY);
11095 drawPaths.call(this, 'fill', true);
11096 this.path = tmpPaths;
11097 }
11098
11099 var tmpRect = JSON.parse(JSON.stringify(textRect));
11100 tmpRect = pathPositionRedo([tmpRect], this.posX, -1 * this.pdf.internal.pageSize.height * (i - 1) + this.posY)[0];
11101
11102 if (options.scale >= 0.01) {
11103 var oldSize = this.pdf.internal.getFontSize();
11104 this.pdf.setFontSize(oldSize * options.scale);
11105 }
11106
11107 this.pdf.text(options.text, tmpRect.x, tmpRect.y, {
11108 angle: options.angle,
11109 align: textAlign,
11110 renderingMode: options.renderingMode,
11111 maxWidth: options.maxWidth
11112 });
11113
11114 if (options.scale >= 0.01) {
11115 this.pdf.setFontSize(oldSize);
11116 }
11117 }
11118 } else {
11119 if (options.scale >= 0.01) {
11120 var oldSize = this.pdf.internal.getFontSize();
11121 this.pdf.setFontSize(oldSize * options.scale);
11122 }
11123
11124 this.pdf.text(options.text, pt.x + this.posX, pt.y + this.posY, {
11125 angle: options.angle,
11126 align: textAlign,
11127 renderingMode: options.renderingMode,
11128 maxWidth: options.maxWidth
11129 });
11130
11131 if (options.scale >= 0.01) {
11132 this.pdf.setFontSize(oldSize);
11133 }
11134 }
11135 };
11136
11137 var drawLine = function drawLine(x, y, prevX, prevY) {
11138 prevX = prevX || 0;
11139 prevY = prevY || 0;
11140 this.pdf.internal.out(getHorizontalCoordinateString(x + prevX) + ' ' + getVerticalCoordinateString(y + prevY) + ' l');
11141 };
11142
11143 var drawLines = function drawLines(lines, x, y) {
11144 return this.pdf.lines(lines, x, y, null, null);
11145 };
11146
11147 var drawCurve = function drawCurve(x, y, x1, y1, x2, y2, x3, y3) {
11148 this.pdf.internal.out([f2(getHorizontalCoordinate(x1 + x)), f2(getVerticalCoordinate(y1 + y)), f2(getHorizontalCoordinate(x2 + x)), f2(getVerticalCoordinate(y2 + y)), f2(getHorizontalCoordinate(x3 + x)), f2(getVerticalCoordinate(y3 + y)), 'c'].join(' '));
11149 };
11150 /**
11151 * Return a array of objects that represent bezier curves which approximate the circular arc centered at the origin, from startAngle to endAngle (radians) with the specified radius.
11152 *
11153 * Each bezier curve is an object with four points, where x1,y1 and x4,y4 are the arc's end points and x2,y2 and x3,y3 are the cubic bezier's control points.
11154 * @function createArc
11155 */
11156
11157
11158 var createArc = function createArc(radius, startAngle, endAngle, anticlockwise) {
11159 var EPSILON = 0.00001; // Roughly 1/1000th of a degree, see below // normalize startAngle, endAngle to [-2PI, 2PI]
11160
11161 var twoPI = Math.PI * 2;
11162 var startAngleN = startAngle;
11163
11164 if (startAngleN < twoPI || startAngleN > twoPI) {
11165 startAngleN = startAngleN % twoPI;
11166 }
11167
11168 var endAngleN = endAngle;
11169
11170 if (endAngleN < twoPI || endAngleN > twoPI) {
11171 endAngleN = endAngleN % twoPI;
11172 } // Compute the sequence of arc curves, up to PI/2 at a time. // Total arc angle is less than 2PI.
11173
11174
11175 var curves = [];
11176 var piOverTwo = Math.PI / 2.0; //var sgn = (startAngle < endAngle) ? +1 : -1; // clockwise or counterclockwise
11177
11178 var sgn = anticlockwise ? -1 : +1;
11179 var a1 = startAngle;
11180
11181 for (var totalAngle = Math.min(twoPI, Math.abs(endAngleN - startAngleN)); totalAngle > EPSILON;) {
11182 var a2 = a1 + sgn * Math.min(totalAngle, piOverTwo);
11183 curves.push(createSmallArc.call(this, radius, a1, a2));
11184 totalAngle -= Math.abs(a2 - a1);
11185 a1 = a2;
11186 }
11187
11188 return curves;
11189 };
11190 /**
11191 * Cubic bezier approximation of a circular arc centered at the origin, from (radians) a1 to a2, where a2-a1 < pi/2. The arc's radius is r.
11192 *
11193 * Returns an object with four points, where x1,y1 and x4,y4 are the arc's end points and x2,y2 and x3,y3 are the cubic bezier's control points.
11194 *
11195 * This algorithm is based on the approach described in: A. Riškus, "Approximation of a Cubic Bezier Curve by Circular Arcs and Vice Versa," Information Technology and Control, 35(4), 2006 pp. 371-378.
11196 */
11197
11198
11199 var createSmallArc = function createSmallArc(r, a1, a2) {
11200 var a = (a2 - a1) / 2.0;
11201 var x4 = r * Math.cos(a);
11202 var y4 = r * Math.sin(a);
11203 var x1 = x4;
11204 var y1 = -y4;
11205 var q1 = x1 * x1 + y1 * y1;
11206 var q2 = q1 + x1 * x4 + y1 * y4;
11207 var k2 = 4 / 3 * (Math.sqrt(2 * q1 * q2) - q2) / (x1 * y4 - y1 * x4);
11208 var x2 = x1 - k2 * y1;
11209 var y2 = y1 + k2 * x1;
11210 var x3 = x2;
11211 var y3 = -y2;
11212 var ar = a + a1;
11213 var cos_ar = Math.cos(ar);
11214 var sin_ar = Math.sin(ar);
11215 return {
11216 x1: r * Math.cos(a1),
11217 y1: r * Math.sin(a1),
11218 x2: x2 * cos_ar - y2 * sin_ar,
11219 y2: x2 * sin_ar + y2 * cos_ar,
11220 x3: x3 * cos_ar - y3 * sin_ar,
11221 y3: x3 * sin_ar + y3 * cos_ar,
11222 x4: r * Math.cos(a2),
11223 y4: r * Math.sin(a2)
11224 };
11225 };
11226
11227 var rad2deg = function rad2deg(value) {
11228 return value * 180 / Math.PI;
11229 };
11230
11231 var deg2rad = function deg2rad(deg) {
11232 return deg * Math.PI / 180;
11233 };
11234
11235 var getQuadraticCurveBoundary = function getQuadraticCurveBoundary(sx, sy, cpx, cpy, ex, ey) {
11236 var midX1 = sx + (cpx - sx) * 0.50;
11237 var midY1 = sy + (cpy - sy) * 0.50;
11238 var midX2 = ex + (cpx - ex) * 0.50;
11239 var midY2 = ey + (cpy - ey) * 0.50;
11240 var resultX1 = Math.min(sx, ex, midX1, midX2);
11241 var resultX2 = Math.max(sx, ex, midX1, midX2);
11242 var resultY1 = Math.min(sy, ey, midY1, midY2);
11243 var resultY2 = Math.max(sy, ey, midY1, midY2);
11244 return new Rectangle(resultX1, resultY1, resultX2 - resultX1, resultY2 - resultY1);
11245 }; //De Casteljau algorithm
11246
11247
11248 var getBezierCurveBoundary = function getBezierCurveBoundary(ax, ay, bx, by, cx, cy, dx, dy) {
11249 var tobx = bx - ax;
11250 var toby = by - ay;
11251 var tocx = cx - bx;
11252 var tocy = cy - by;
11253 var todx = dx - cx;
11254 var tody = dy - cy;
11255 var precision = 40;
11256 var d, px, py, qx, qy, rx, ry, tx, ty, sx, sy, x, y, i, minx, miny, maxx, maxy, toqx, toqy, torx, tory, totx, toty;
11257
11258 for (var i = 0; i < precision + 1; i++) {
11259 d = i / precision;
11260 px = ax + d * tobx;
11261 py = ay + d * toby;
11262 qx = bx + d * tocx;
11263 qy = by + d * tocy;
11264 rx = cx + d * todx;
11265 ry = cy + d * tody;
11266 toqx = qx - px;
11267 toqy = qy - py;
11268 torx = rx - qx;
11269 tory = ry - qy;
11270 sx = px + d * toqx;
11271 sy = py + d * toqy;
11272 tx = qx + d * torx;
11273 ty = qy + d * tory;
11274 totx = tx - sx;
11275 toty = ty - sy;
11276 x = sx + d * totx;
11277 y = sy + d * toty;
11278
11279 if (i == 0) {
11280 minx = x;
11281 miny = y;
11282 maxx = x;
11283 maxy = y;
11284 } else {
11285 minx = Math.min(minx, x);
11286 miny = Math.min(miny, y);
11287 maxx = Math.max(maxx, x);
11288 maxy = Math.max(maxy, y);
11289 }
11290 }
11291
11292 return new Rectangle(Math.round(minx), Math.round(miny), Math.round(maxx - minx), Math.round(maxy - miny));
11293 };
11294
11295 var Point = function Point(x, y) {
11296 var _x = x || 0;
11297
11298 Object.defineProperty(this, 'x', {
11299 enumerable: true,
11300 get: function get() {
11301 return _x;
11302 },
11303 set: function set(value) {
11304 if (!isNaN(value)) {
11305 _x = parseFloat(value);
11306 }
11307 }
11308 });
11309
11310 var _y = y || 0;
11311
11312 Object.defineProperty(this, 'y', {
11313 enumerable: true,
11314 get: function get() {
11315 return _y;
11316 },
11317 set: function set(value) {
11318 if (!isNaN(value)) {
11319 _y = parseFloat(value);
11320 }
11321 }
11322 });
11323 var _type = 'pt';
11324 Object.defineProperty(this, 'type', {
11325 enumerable: true,
11326 get: function get() {
11327 return _type;
11328 },
11329 set: function set(value) {
11330 _type = value.toString();
11331 }
11332 });
11333 return this;
11334 };
11335
11336 var Rectangle = function Rectangle(x, y, w, h) {
11337 Point.call(this, x, y);
11338 this.type = 'rect';
11339
11340 var _w = w || 0;
11341
11342 Object.defineProperty(this, 'w', {
11343 enumerable: true,
11344 get: function get() {
11345 return _w;
11346 },
11347 set: function set(value) {
11348 if (!isNaN(value)) {
11349 _w = parseFloat(value);
11350 }
11351 }
11352 });
11353
11354 var _h = h || 0;
11355
11356 Object.defineProperty(this, 'h', {
11357 enumerable: true,
11358 get: function get() {
11359 return _h;
11360 },
11361 set: function set(value) {
11362 if (!isNaN(value)) {
11363 _h = parseFloat(value);
11364 }
11365 }
11366 });
11367 return this;
11368 };
11369
11370 var Matrix = function Matrix(sx, shy, shx, sy, tx, ty) {
11371 var _matrix = [];
11372 Object.defineProperty(this, 'sx', {
11373 get: function get() {
11374 return _matrix[0];
11375 },
11376 set: function set(value) {
11377 _matrix[0] = Math.round(value * 100000) / 100000;
11378 }
11379 });
11380 Object.defineProperty(this, 'shy', {
11381 get: function get() {
11382 return _matrix[1];
11383 },
11384 set: function set(value) {
11385 _matrix[1] = Math.round(value * 100000) / 100000;
11386 }
11387 });
11388 Object.defineProperty(this, 'shx', {
11389 get: function get() {
11390 return _matrix[2];
11391 },
11392 set: function set(value) {
11393 _matrix[2] = Math.round(value * 100000) / 100000;
11394 }
11395 });
11396 Object.defineProperty(this, 'sy', {
11397 get: function get() {
11398 return _matrix[3];
11399 },
11400 set: function set(value) {
11401 _matrix[3] = Math.round(value * 100000) / 100000;
11402 }
11403 });
11404 Object.defineProperty(this, 'tx', {
11405 get: function get() {
11406 return _matrix[4];
11407 },
11408 set: function set(value) {
11409 _matrix[4] = Math.round(value * 100000) / 100000;
11410 }
11411 });
11412 Object.defineProperty(this, 'ty', {
11413 get: function get() {
11414 return _matrix[5];
11415 },
11416 set: function set(value) {
11417 _matrix[5] = Math.round(value * 100000) / 100000;
11418 }
11419 });
11420 Object.defineProperty(this, 'rotation', {
11421 get: function get() {
11422 return Math.atan2(this.shx, this.sx);
11423 }
11424 });
11425 Object.defineProperty(this, 'scaleX', {
11426 get: function get() {
11427 return this.decompose().scale.sx;
11428 }
11429 });
11430 Object.defineProperty(this, 'scaleY', {
11431 get: function get() {
11432 return this.decompose().scale.sy;
11433 }
11434 });
11435 Object.defineProperty(this, 'isIdentity', {
11436 get: function get() {
11437 if (this.sx !== 1) {
11438 return false;
11439 }
11440
11441 if (this.shy !== 0) {
11442 return false;
11443 }
11444
11445 if (this.shx !== 0) {
11446 return false;
11447 }
11448
11449 if (this.sy !== 1) {
11450 return false;
11451 }
11452
11453 if (this.tx !== 0) {
11454 return false;
11455 }
11456
11457 if (this.ty !== 0) {
11458 return false;
11459 }
11460
11461 return true;
11462 }
11463 });
11464 this.sx = !isNaN(sx) ? sx : 1;
11465 this.shy = !isNaN(shy) ? shy : 0;
11466 this.shx = !isNaN(shx) ? shx : 0;
11467 this.sy = !isNaN(sy) ? sy : 1;
11468 this.tx = !isNaN(tx) ? tx : 0;
11469 this.ty = !isNaN(ty) ? ty : 0;
11470 return this;
11471 };
11472 /**
11473 * Multiply the matrix with given Matrix
11474 *
11475 * @function multiply
11476 * @param matrix
11477 * @returns {Matrix}
11478 * @private
11479 * @ignore
11480 */
11481
11482
11483 Matrix.prototype.multiply = function (matrix) {
11484 var sx = matrix.sx * this.sx + matrix.shy * this.shx;
11485 var shy = matrix.sx * this.shy + matrix.shy * this.sy;
11486 var shx = matrix.shx * this.sx + matrix.sy * this.shx;
11487 var sy = matrix.shx * this.shy + matrix.sy * this.sy;
11488 var tx = matrix.tx * this.sx + matrix.ty * this.shx + this.tx;
11489 var ty = matrix.tx * this.shy + matrix.ty * this.sy + this.ty;
11490 return new Matrix(sx, shy, shx, sy, tx, ty);
11491 };
11492 /**
11493 * @function decompose
11494 * @private
11495 * @ignore
11496 */
11497
11498
11499 Matrix.prototype.decompose = function () {
11500 var a = this.sx;
11501 var b = this.shy;
11502 var c = this.shx;
11503 var d = this.sy;
11504 var e = this.tx;
11505 var f = this.ty;
11506 var scaleX = Math.sqrt(a * a + b * b);
11507 a /= scaleX;
11508 b /= scaleX;
11509 var shear = a * c + b * d;
11510 c -= a * shear;
11511 d -= b * shear;
11512 var scaleY = Math.sqrt(c * c + d * d);
11513 c /= scaleY;
11514 d /= scaleY;
11515 shear /= scaleY;
11516
11517 if (a * d < b * c) {
11518 a = -a;
11519 b = -b;
11520 shear = -shear;
11521 scaleX = -scaleX;
11522 }
11523
11524 return {
11525 scale: new Matrix(scaleX, 0, 0, scaleY, 0, 0),
11526 translate: new Matrix(1, 0, 0, 1, e, f),
11527 rotate: new Matrix(a, b, -b, a, 0, 0),
11528 skew: new Matrix(1, 0, shear, 1, 0, 0)
11529 };
11530 };
11531 /**
11532 * @function applyToPoint
11533 * @private
11534 * @ignore
11535 */
11536
11537
11538 Matrix.prototype.applyToPoint = function (pt) {
11539 var x = pt.x * this.sx + pt.y * this.shx + this.tx;
11540 var y = pt.x * this.shy + pt.y * this.sy + this.ty;
11541 return new Point(x, y);
11542 };
11543 /**
11544 * @function applyToRectangle
11545 * @private
11546 * @ignore
11547 */
11548
11549
11550 Matrix.prototype.applyToRectangle = function (rect) {
11551 var pt1 = this.applyToPoint(rect);
11552 var pt2 = this.applyToPoint(new Point(rect.x + rect.w, rect.y + rect.h));
11553 return new Rectangle(pt1.x, pt1.y, pt2.x - pt1.x, pt2.y - pt1.y);
11554 };
11555 /**
11556 * @function clone
11557 * @private
11558 * @ignore
11559 */
11560
11561
11562 Matrix.prototype.clone = function () {
11563 var sx = this.sx;
11564 var shy = this.shy;
11565 var shx = this.shx;
11566 var sy = this.sy;
11567 var tx = this.tx;
11568 var ty = this.ty;
11569 return new Matrix(sx, shy, shx, sy, tx, ty);
11570 };
11571 })(jsPDF.API, typeof self !== 'undefined' && self || typeof window !== 'undefined' && window || typeof global !== 'undefined' && global || Function('return typeof this === "object" && this.content')() || Function('return this')());
11572
11573 /**
11574 * jsPDF filters PlugIn
11575 * Copyright (c) 2014 Aras Abbasi
11576 *
11577 * Licensed under the MIT License.
11578 * http://opensource.org/licenses/mit-license
11579 */
11580 (function (jsPDFAPI) {
11581
11582 var ASCII85Encode = function ASCII85Encode(a) {
11583 var b, c, d, e, f, g, h, i, j, k;
11584
11585 for (!/[^\x00-\xFF]/.test(a), b = "\x00\x00\x00\x00".slice(a.length % 4 || 4), a += b, c = [], d = 0, e = a.length; e > d; d += 4) {
11586 f = (a.charCodeAt(d) << 24) + (a.charCodeAt(d + 1) << 16) + (a.charCodeAt(d + 2) << 8) + a.charCodeAt(d + 3), 0 !== f ? (k = f % 85, f = (f - k) / 85, j = f % 85, f = (f - j) / 85, i = f % 85, f = (f - i) / 85, h = f % 85, f = (f - h) / 85, g = f % 85, c.push(g + 33, h + 33, i + 33, j + 33, k + 33)) : c.push(122);
11587 }
11588
11589 return function (a, b) {
11590 for (var c = b; c > 0; c--) {
11591 a.pop();
11592 }
11593 }(c, b.length), String.fromCharCode.apply(String, c) + "~>";
11594 };
11595
11596 var ASCII85Decode = function ASCII85Decode(a) {
11597 var c,
11598 d,
11599 e,
11600 f,
11601 g,
11602 h = String,
11603 l = "length",
11604 w = 255,
11605 x = "charCodeAt",
11606 y = "slice",
11607 z = "replace";
11608
11609 for ("~>" === a[y](-2), a = a[y](0, -2)[z](/\s/g, "")[z]("z", "!!!!!"), c = "uuuuu"[y](a[l] % 5 || 5), a += c, e = [], f = 0, g = a[l]; g > f; f += 5) {
11610 d = 52200625 * (a[x](f) - 33) + 614125 * (a[x](f + 1) - 33) + 7225 * (a[x](f + 2) - 33) + 85 * (a[x](f + 3) - 33) + (a[x](f + 4) - 33), e.push(w & d >> 24, w & d >> 16, w & d >> 8, w & d);
11611 }
11612
11613 return function (a, b) {
11614 for (var c = b; c > 0; c--) {
11615 a.pop();
11616 }
11617 }(e, c[l]), h.fromCharCode.apply(h, e);
11618 };
11619 /**
11620 * TODO: Not Tested:
11621 //https://gist.github.com/revolunet/843889
11622 // LZW-compress a string
11623 var LZWEncode = function(s, options) {
11624 options = Object.assign({
11625 predictor: 1,
11626 colors: 1,
11627 bitsPerComponent: 8,
11628 columns: 1,
11629 earlyChange: 1
11630 }, options);
11631 var dict = {};
11632 var data = (s + "").split("");
11633 var out = [];
11634 var currChar;
11635 var phrase = data[0];
11636 var code = 256; //0xe000
11637 for (var i=1; i<data.length; i++) {
11638 currChar=data[i];
11639 if (dict['_' + phrase + currChar] != null) {
11640 phrase += currChar;
11641 }
11642 else {
11643 out.push(phrase.length > 1 ? dict['_'+phrase] : phrase.charCodeAt(0));
11644 dict['_' + phrase + currChar] = code;
11645 code++;
11646 phrase=currChar;
11647 }
11648 }
11649 out.push(phrase.length > 1 ? dict['_'+phrase] : phrase.charCodeAt(0));
11650 for (var i=0; i<out.length; i++) {
11651 out[i] = String.fromCharCode(out[i]);
11652 }
11653 return out.join("");
11654 }
11655 // Decompress an LZW-encoded string
11656 var LZWDecode = function(s, options) {
11657 options = Object.assign({
11658 predictor: 1,
11659 colors: 1,
11660 bitsPerComponent: 8,
11661 columns: 1,
11662 earlyChange: 1
11663 }, options);
11664 var dict = {};
11665 var data = (s + "").split("");
11666 var currChar = data[0];
11667 var oldPhrase = currChar;
11668 var out = [currChar];
11669 var code = 256;
11670 var phrase;
11671 for (var i=1; i<data.length; i++) {
11672 var currCode = data[i].charCodeAt(0);
11673 if (currCode < 256) {
11674 phrase = data[i];
11675 }
11676 else {
11677 phrase = dict['_'+currCode] ? dict['_'+currCode] : (oldPhrase + currChar);
11678 }
11679 out.push(phrase);
11680 currChar = phrase.charAt(0);
11681 dict['_'+code] = oldPhrase + currChar;
11682 code++;
11683 oldPhrase = phrase;
11684 }
11685 return out.join("");
11686 }
11687 */
11688
11689
11690 var ASCIIHexEncode = function ASCIIHexEncode(value) {
11691 var result = '';
11692 var i;
11693
11694 for (var i = 0; i < value.length; i += 1) {
11695 result += ("0" + value.charCodeAt(i).toString(16)).slice(-2);
11696 }
11697
11698 result += '>';
11699 return result;
11700 };
11701
11702 var ASCIIHexDecode = function ASCIIHexDecode(value) {
11703 var regexCheckIfHex = new RegExp(/^([0-9A-Fa-f]{2})+$/);
11704 value = value.replace(/\s/g, '');
11705
11706 if (value.indexOf(">") !== -1) {
11707 value = value.substr(0, value.indexOf(">"));
11708 }
11709
11710 if (value.length % 2) {
11711 value += "0";
11712 }
11713
11714 if (regexCheckIfHex.test(value) === false) {
11715 return "";
11716 }
11717
11718 var result = '';
11719 var i;
11720
11721 for (var i = 0; i < value.length; i += 2) {
11722 result += String.fromCharCode("0x" + (value[i] + value[i + 1]));
11723 }
11724
11725 return result;
11726 };
11727
11728 var FlateEncode = function FlateEncode(data, options) {
11729 options = Object.assign({
11730 predictor: 1,
11731 colors: 1,
11732 bitsPerComponent: 8,
11733 columns: 1
11734 }, options);
11735 var arr = [];
11736 var i = data.length;
11737 var adler32;
11738 var deflater;
11739
11740 while (i--) {
11741 arr[i] = data.charCodeAt(i);
11742 }
11743
11744 adler32 = jsPDFAPI.adler32cs.from(data);
11745 deflater = new Deflater(6);
11746 deflater.append(new Uint8Array(arr));
11747 data = deflater.flush();
11748 arr = new Uint8Array(data.length + 6);
11749 arr.set(new Uint8Array([120, 156])), arr.set(data, 2);
11750 arr.set(new Uint8Array([adler32 & 0xFF, adler32 >> 8 & 0xFF, adler32 >> 16 & 0xFF, adler32 >> 24 & 0xFF]), data.length + 2);
11751 data = String.fromCharCode.apply(null, arr);
11752 return data;
11753 };
11754
11755 jsPDFAPI.processDataByFilters = function (origData, filterChain) {
11756
11757 var i = 0;
11758 var data = origData || '';
11759 var reverseChain = [];
11760 filterChain = filterChain || [];
11761
11762 if (typeof filterChain === "string") {
11763 filterChain = [filterChain];
11764 }
11765
11766 for (i = 0; i < filterChain.length; i += 1) {
11767 switch (filterChain[i]) {
11768 case "ASCII85Decode":
11769 case "/ASCII85Decode":
11770 data = ASCII85Decode(data);
11771 reverseChain.push("/ASCII85Encode");
11772 break;
11773
11774 case "ASCII85Encode":
11775 case "/ASCII85Encode":
11776 data = ASCII85Encode(data);
11777 reverseChain.push("/ASCII85Decode");
11778 break;
11779
11780 case "ASCIIHexDecode":
11781 case "/ASCIIHexDecode":
11782 data = ASCIIHexDecode(data);
11783 reverseChain.push("/ASCIIHexEncode");
11784 break;
11785
11786 case "ASCIIHexEncode":
11787 case "/ASCIIHexEncode":
11788 data = ASCIIHexEncode(data);
11789 reverseChain.push("/ASCIIHexDecode");
11790 break;
11791
11792 case "FlateEncode":
11793 case "/FlateEncode":
11794 data = FlateEncode(data);
11795 reverseChain.push("/FlateDecode");
11796 break;
11797
11798 /**
11799 case "LZWDecode":
11800 case "/LZWDecode":
11801 data = LZWDecode(data);
11802 reverseChain.push("/LZWEncode");
11803 break;
11804 case "LZWEncode":
11805 case "/LZWEncode":
11806 data = LZWEncode(data);
11807 reverseChain.push("/LZWDecode");
11808 break;
11809 */
11810
11811 default:
11812 throw "The filter: \"" + filterChain[i] + "\" is not implemented";
11813 }
11814 }
11815
11816 return {
11817 data: data,
11818 reverseChain: reverseChain.reverse().join(" ")
11819 };
11820 };
11821 })(jsPDF.API);
11822
11823 /**
11824 * jsPDF fileloading PlugIn
11825 * Copyright (c) 2018 Aras Abbasi (aras.abbasi@gmail.com)
11826 *
11827 * Licensed under the MIT License.
11828 * http://opensource.org/licenses/mit-license
11829 */
11830
11831 /**
11832 * @name fileloading
11833 * @module
11834 */
11835 (function (jsPDFAPI) {
11836 /**
11837 * @name loadFile
11838 * @function
11839 * @param {string} url
11840 * @param {boolean} sync
11841 * @param {function} callback
11842 * @returns {string|undefined} result
11843 */
11844
11845 jsPDFAPI.loadFile = function (url, sync, callback) {
11846 sync = sync || true;
11847
11848 callback = callback || function () {};
11849
11850 var result;
11851
11852 var xhr = function xhr(url, sync, callback) {
11853 var req = new XMLHttpRequest();
11854 var byteArray = [];
11855 var i = 0;
11856
11857 var sanitizeUnicode = function sanitizeUnicode(data) {
11858 var dataLength = data.length;
11859 var StringFromCharCode = String.fromCharCode; //Transform Unicode to ASCII
11860
11861 for (i = 0; i < dataLength; i += 1) {
11862 byteArray.push(StringFromCharCode(data.charCodeAt(i) & 0xff));
11863 }
11864
11865 return byteArray.join("");
11866 };
11867
11868 req.open('GET', url, !sync); // XHR binary charset opt by Marcus Granado 2006 [http://mgran.blogspot.com]
11869
11870 req.overrideMimeType('text\/plain; charset=x-user-defined');
11871
11872 if (sync === false) {
11873 req.onload = function () {
11874 return sanitizeUnicode(this.responseText);
11875 };
11876 }
11877
11878 req.send(null);
11879
11880 if (req.status !== 200) {
11881 console.warn('Unable to load file "' + url + '"');
11882 return;
11883 }
11884
11885 if (sync) {
11886 return sanitizeUnicode(req.responseText);
11887 }
11888 };
11889
11890 try {
11891 result = xhr(url, sync, callback);
11892 } catch (e) {
11893 result = undefined;
11894 }
11895
11896 return result;
11897 };
11898 /**
11899 * @name loadImageFile
11900 * @function
11901 * @param {string} path
11902 * @param {boolean} sync
11903 * @param {function} callback
11904 */
11905
11906
11907 jsPDFAPI.loadImageFile = jsPDFAPI.loadFile;
11908 })(jsPDF.API);
11909
11910 /**
11911 * Copyright (c) 2018 Erik Koopmans
11912 * Released under the MIT License.
11913 *
11914 * Licensed under the MIT License.
11915 * http://opensource.org/licenses/mit-license
11916 */
11917
11918 /**
11919 * jsPDF html PlugIn
11920 *
11921 * @name html
11922 * @module
11923 */
11924 (function (jsPDFAPI, global) {
11925 /**
11926 * Determine the type of a variable/object.
11927 *
11928 * @private
11929 * @ignore
11930 */
11931
11932 var objType = function objType(obj) {
11933 var type = _typeof(obj);
11934
11935 if (type === 'undefined') return 'undefined';else if (type === 'string' || obj instanceof String) return 'string';else if (type === 'number' || obj instanceof Number) return 'number';else if (type === 'function' || obj instanceof Function) return 'function';else if (!!obj && obj.constructor === Array) return 'array';else if (obj && obj.nodeType === 1) return 'element';else if (type === 'object') return 'object';else return 'unknown';
11936 };
11937 /**
11938 * Create an HTML element with optional className, innerHTML, and style.
11939 *
11940 * @private
11941 * @ignore
11942 */
11943
11944
11945 var createElement = function createElement(tagName, opt) {
11946 var el = document.createElement(tagName);
11947 if (opt.className) el.className = opt.className;
11948
11949 if (opt.innerHTML) {
11950 el.innerHTML = opt.innerHTML;
11951 var scripts = el.getElementsByTagName('script');
11952
11953 for (var i = scripts.length; i-- > 0; null) {
11954 scripts[i].parentNode.removeChild(scripts[i]);
11955 }
11956 }
11957
11958 for (var key in opt.style) {
11959 el.style[key] = opt.style[key];
11960 }
11961
11962 return el;
11963 };
11964 /**
11965 * Deep-clone a node and preserve contents/properties.
11966 *
11967 * @private
11968 * @ignore
11969 */
11970
11971
11972 var cloneNode = function cloneNode(node, javascriptEnabled) {
11973 // Recursively clone the node.
11974 var clone = node.nodeType === 3 ? document.createTextNode(node.nodeValue) : node.cloneNode(false);
11975
11976 for (var child = node.firstChild; child; child = child.nextSibling) {
11977 if (javascriptEnabled === true || child.nodeType !== 1 || child.nodeName !== 'SCRIPT') {
11978 clone.appendChild(cloneNode(child, javascriptEnabled));
11979 }
11980 }
11981
11982 if (node.nodeType === 1) {
11983 // Preserve contents/properties of special nodes.
11984 if (node.nodeName === 'CANVAS') {
11985 clone.width = node.width;
11986 clone.height = node.height;
11987 clone.getContext('2d').drawImage(node, 0, 0);
11988 } else if (node.nodeName === 'TEXTAREA' || node.nodeName === 'SELECT') {
11989 clone.value = node.value;
11990 } // Preserve the node's scroll position when it loads.
11991
11992
11993 clone.addEventListener('load', function () {
11994 clone.scrollTop = node.scrollTop;
11995 clone.scrollLeft = node.scrollLeft;
11996 }, true);
11997 } // Return the cloned node.
11998
11999
12000 return clone;
12001 };
12002 /* ----- CONSTRUCTOR ----- */
12003
12004
12005 var Worker = function Worker(opt) {
12006 // Create the root parent for the proto chain, and the starting Worker.
12007 var root = Object.assign(Worker.convert(Promise.resolve()), JSON.parse(JSON.stringify(Worker.template)));
12008 var self = Worker.convert(Promise.resolve(), root); // Set progress, optional settings, and return.
12009
12010 self = self.setProgress(1, Worker, 1, [Worker]);
12011 self = self.set(opt);
12012 return self;
12013 }; // Boilerplate for subclassing Promise.
12014
12015
12016 Worker.prototype = Object.create(Promise.prototype);
12017 Worker.prototype.constructor = Worker; // Converts/casts promises into Workers.
12018
12019 Worker.convert = function convert(promise, inherit) {
12020 // Uses prototypal inheritance to receive changes made to ancestors' properties.
12021 promise.__proto__ = inherit || Worker.prototype;
12022 return promise;
12023 };
12024
12025 Worker.template = {
12026 prop: {
12027 src: null,
12028 container: null,
12029 overlay: null,
12030 canvas: null,
12031 img: null,
12032 pdf: null,
12033 pageSize: null,
12034 callback: function callback() {}
12035 },
12036 progress: {
12037 val: 0,
12038 state: null,
12039 n: 0,
12040 stack: []
12041 },
12042 opt: {
12043 filename: 'file.pdf',
12044 margin: [0, 0, 0, 0],
12045 enableLinks: true,
12046 x: 0,
12047 y: 0,
12048 html2canvas: {},
12049 jsPDF: {}
12050 }
12051 };
12052 /* ----- FROM / TO ----- */
12053
12054 Worker.prototype.from = function from(src, type) {
12055 function getType(src) {
12056 switch (objType(src)) {
12057 case 'string':
12058 return 'string';
12059
12060 case 'element':
12061 return src.nodeName.toLowerCase === 'canvas' ? 'canvas' : 'element';
12062
12063 default:
12064 return 'unknown';
12065 }
12066 }
12067
12068 return this.then(function from_main() {
12069 type = type || getType(src);
12070
12071 switch (type) {
12072 case 'string':
12073 return this.set({
12074 src: createElement('div', {
12075 innerHTML: src
12076 })
12077 });
12078
12079 case 'element':
12080 return this.set({
12081 src: src
12082 });
12083
12084 case 'canvas':
12085 return this.set({
12086 canvas: src
12087 });
12088
12089 case 'img':
12090 return this.set({
12091 img: src
12092 });
12093
12094 default:
12095 return this.error('Unknown source type.');
12096 }
12097 });
12098 };
12099
12100 Worker.prototype.to = function to(target) {
12101 // Route the 'to' request to the appropriate method.
12102 switch (target) {
12103 case 'container':
12104 return this.toContainer();
12105
12106 case 'canvas':
12107 return this.toCanvas();
12108
12109 case 'img':
12110 return this.toImg();
12111
12112 case 'pdf':
12113 return this.toPdf();
12114
12115 default:
12116 return this.error('Invalid target.');
12117 }
12118 };
12119
12120 Worker.prototype.toContainer = function toContainer() {
12121 // Set up function prerequisites.
12122 var prereqs = [function checkSrc() {
12123 return this.prop.src || this.error('Cannot duplicate - no source HTML.');
12124 }, function checkPageSize() {
12125 return this.prop.pageSize || this.setPageSize();
12126 }];
12127 return this.thenList(prereqs).then(function toContainer_main() {
12128 // Define the CSS styles for the container and its overlay parent.
12129 var overlayCSS = {
12130 position: 'fixed',
12131 overflow: 'hidden',
12132 zIndex: 1000,
12133 left: '-100000px',
12134 right: 0,
12135 bottom: 0,
12136 top: 0
12137 };
12138 var containerCSS = {
12139 position: 'relative',
12140 display: 'inline-block',
12141 width: Math.max(this.prop.src.clientWidth, this.prop.src.scrollWidth, this.prop.src.offsetWidth) + 'px',
12142 left: 0,
12143 right: 0,
12144 top: 0,
12145 margin: 'auto',
12146 backgroundColor: 'white'
12147 }; // Set the overlay to hidden (could be changed in the future to provide a print preview).
12148
12149 var source = cloneNode(this.prop.src, this.opt.html2canvas.javascriptEnabled);
12150
12151 if (source.tagName === 'BODY') {
12152 containerCSS.height = Math.max(document.body.scrollHeight, document.body.offsetHeight, document.documentElement.clientHeight, document.documentElement.scrollHeight, document.documentElement.offsetHeight) + 'px';
12153 }
12154
12155 this.prop.overlay = createElement('div', {
12156 className: 'html2pdf__overlay',
12157 style: overlayCSS
12158 });
12159 this.prop.container = createElement('div', {
12160 className: 'html2pdf__container',
12161 style: containerCSS
12162 });
12163 this.prop.container.appendChild(source);
12164 this.prop.container.firstChild.appendChild(createElement('div', {
12165 style: {
12166 clear: 'both',
12167 border: '0 none transparent',
12168 margin: 0,
12169 padding: 0,
12170 height: 0
12171 }
12172 }));
12173 this.prop.container.style.float = 'none';
12174 this.prop.overlay.appendChild(this.prop.container);
12175 document.body.appendChild(this.prop.overlay);
12176 this.prop.container.firstChild.style.position = 'relative';
12177 this.prop.container.height = Math.max(this.prop.container.firstChild.clientHeight, this.prop.container.firstChild.scrollHeight, this.prop.container.firstChild.offsetHeight) + 'px';
12178 });
12179 };
12180
12181 Worker.prototype.toCanvas = function toCanvas() {
12182 // Set up function prerequisites.
12183 var prereqs = [function checkContainer() {
12184 return document.body.contains(this.prop.container) || this.toContainer();
12185 }]; // Fulfill prereqs then create the canvas.
12186
12187 return this.thenList(prereqs).then(function toCanvas_main() {
12188 // Handle old-fashioned 'onrendered' argument.
12189 var options = Object.assign({}, this.opt.html2canvas);
12190 delete options.onrendered;
12191
12192 if (!this.isHtml2CanvasLoaded()) {
12193 return;
12194 }
12195
12196 return html2canvas(this.prop.container, options);
12197 }).then(function toCanvas_post(canvas) {
12198 // Handle old-fashioned 'onrendered' argument.
12199 var onRendered = this.opt.html2canvas.onrendered || function () {};
12200
12201 onRendered(canvas);
12202 this.prop.canvas = canvas;
12203 document.body.removeChild(this.prop.overlay);
12204 });
12205 };
12206
12207 Worker.prototype.toContext2d = function toContext2d() {
12208 // Set up function prerequisites.
12209 var prereqs = [function checkContainer() {
12210 return document.body.contains(this.prop.container) || this.toContainer();
12211 }]; // Fulfill prereqs then create the canvas.
12212
12213 return this.thenList(prereqs).then(function toContext2d_main() {
12214 // Handle old-fashioned 'onrendered' argument.
12215 var pdf = this.opt.jsPDF;
12216 var options = Object.assign({
12217 async: true,
12218 allowTaint: true,
12219 backgroundColor: '#ffffff',
12220 imageTimeout: 15000,
12221 logging: true,
12222 proxy: null,
12223 removeContainer: true,
12224 foreignObjectRendering: false,
12225 useCORS: false
12226 }, this.opt.html2canvas);
12227 delete options.onrendered;
12228 pdf.context2d.autoPaging = true;
12229 pdf.context2d.posX = this.opt.x;
12230 pdf.context2d.posY = this.opt.y;
12231 options.windowHeight = options.windowHeight || 0;
12232 options.windowHeight = options.windowHeight == 0 ? Math.max(this.prop.container.clientHeight, this.prop.container.scrollHeight, this.prop.container.offsetHeight) : options.windowHeight;
12233
12234 if (!this.isHtml2CanvasLoaded()) {
12235 return;
12236 }
12237
12238 return html2canvas(this.prop.container, options);
12239 }).then(function toContext2d_post(canvas) {
12240 // Handle old-fashioned 'onrendered' argument.
12241 var onRendered = this.opt.html2canvas.onrendered || function () {};
12242
12243 onRendered(canvas);
12244 this.prop.canvas = canvas;
12245 document.body.removeChild(this.prop.overlay);
12246 });
12247 };
12248
12249 Worker.prototype.toImg = function toImg() {
12250 // Set up function prerequisites.
12251 var prereqs = [function checkCanvas() {
12252 return this.prop.canvas || this.toCanvas();
12253 }]; // Fulfill prereqs then create the image.
12254
12255 return this.thenList(prereqs).then(function toImg_main() {
12256 var imgData = this.prop.canvas.toDataURL('image/' + this.opt.image.type, this.opt.image.quality);
12257 this.prop.img = document.createElement('img');
12258 this.prop.img.src = imgData;
12259 });
12260 };
12261
12262 Worker.prototype.toPdf = function toPdf() {
12263 // Set up function prerequisites.
12264 var prereqs = [function checkContext2d() {
12265 return this.toContext2d();
12266 } //function checkCanvas() { return this.prop.canvas || this.toCanvas(); }
12267 ]; // Fulfill prereqs then create the image.
12268
12269 return this.thenList(prereqs).then(function toPdf_main() {
12270 // Create local copies of frequently used properties.
12271 this.prop.pdf = this.prop.pdf || this.opt.jsPDF;
12272 });
12273 };
12274 /* ----- OUTPUT / SAVE ----- */
12275
12276
12277 Worker.prototype.output = function output(type, options, src) {
12278 // Redirect requests to the correct function (outputPdf / outputImg).
12279 src = src || 'pdf';
12280
12281 if (src.toLowerCase() === 'img' || src.toLowerCase() === 'image') {
12282 return this.outputImg(type, options);
12283 } else {
12284 return this.outputPdf(type, options);
12285 }
12286 };
12287
12288 Worker.prototype.outputPdf = function outputPdf(type, options) {
12289 // Set up function prerequisites.
12290 var prereqs = [function checkPdf() {
12291 return this.prop.pdf || this.toPdf();
12292 }]; // Fulfill prereqs then perform the appropriate output.
12293
12294 return this.thenList(prereqs).then(function outputPdf_main() {
12295 /* Currently implemented output types:
12296 * https://rawgit.com/MrRio/jsPDF/master/docs/jspdf.js.html#line992
12297 * save(options), arraybuffer, blob, bloburi/bloburl,
12298 * datauristring/dataurlstring, dataurlnewwindow, datauri/dataurl
12299 */
12300 return this.prop.pdf.output(type, options);
12301 });
12302 };
12303
12304 Worker.prototype.outputImg = function outputImg(type, options) {
12305 // Set up function prerequisites.
12306 var prereqs = [function checkImg() {
12307 return this.prop.img || this.toImg();
12308 }]; // Fulfill prereqs then perform the appropriate output.
12309
12310 return this.thenList(prereqs).then(function outputImg_main() {
12311 switch (type) {
12312 case undefined:
12313 case 'img':
12314 return this.prop.img;
12315
12316 case 'datauristring':
12317 case 'dataurlstring':
12318 return this.prop.img.src;
12319
12320 case 'datauri':
12321 case 'dataurl':
12322 return document.location.href = this.prop.img.src;
12323
12324 default:
12325 throw 'Image output type "' + type + '" is not supported.';
12326 }
12327 });
12328 };
12329
12330 Worker.prototype.isHtml2CanvasLoaded = function () {
12331 var result = typeof global.html2canvas !== "undefined";
12332
12333 if (!result) {
12334 console.error("html2canvas not loaded.");
12335 }
12336
12337 return result;
12338 };
12339
12340 Worker.prototype.save = function save(filename) {
12341 // Set up function prerequisites.
12342 var prereqs = [function checkPdf() {
12343 return this.prop.pdf || this.toPdf();
12344 }];
12345
12346 if (!this.isHtml2CanvasLoaded()) {
12347 return;
12348 } // Fulfill prereqs, update the filename (if provided), and save the PDF.
12349
12350
12351 return this.thenList(prereqs).set(filename ? {
12352 filename: filename
12353 } : null).then(function save_main() {
12354 this.prop.pdf.save(this.opt.filename);
12355 });
12356 };
12357
12358 Worker.prototype.doCallback = function doCallback(filename) {
12359 // Set up function prerequisites.
12360 var prereqs = [function checkPdf() {
12361 return this.prop.pdf || this.toPdf();
12362 }];
12363
12364 if (!this.isHtml2CanvasLoaded()) {
12365 return;
12366 } // Fulfill prereqs, update the filename (if provided), and save the PDF.
12367
12368
12369 return this.thenList(prereqs).then(function doCallback_main() {
12370 this.prop.callback(this.prop.pdf);
12371 });
12372 };
12373 /* ----- SET / GET ----- */
12374
12375
12376 Worker.prototype.set = function set(opt) {
12377 // TODO: Implement ordered pairs?
12378 // Silently ignore invalid or empty input.
12379 if (objType(opt) !== 'object') {
12380 return this;
12381 } // Build an array of setter functions to queue.
12382
12383
12384 var fns = Object.keys(opt || {}).map(function (key) {
12385 if (key in Worker.template.prop) {
12386 // Set pre-defined properties.
12387 return function set_prop() {
12388 this.prop[key] = opt[key];
12389 };
12390 } else {
12391 switch (key) {
12392 case 'margin':
12393 return this.setMargin.bind(this, opt.margin);
12394
12395 case 'jsPDF':
12396 return function set_jsPDF() {
12397 this.opt.jsPDF = opt.jsPDF;
12398 return this.setPageSize();
12399 };
12400
12401 case 'pageSize':
12402 return this.setPageSize.bind(this, opt.pageSize);
12403
12404 default:
12405 // Set any other properties in opt.
12406 return function set_opt() {
12407 this.opt[key] = opt[key];
12408 };
12409 }
12410 }
12411 }, this); // Set properties within the promise chain.
12412
12413 return this.then(function set_main() {
12414 return this.thenList(fns);
12415 });
12416 };
12417
12418 Worker.prototype.get = function get(key, cbk) {
12419 return this.then(function get_main() {
12420 // Fetch the requested property, either as a predefined prop or in opt.
12421 var val = key in Worker.template.prop ? this.prop[key] : this.opt[key];
12422 return cbk ? cbk(val) : val;
12423 });
12424 };
12425
12426 Worker.prototype.setMargin = function setMargin(margin) {
12427 return this.then(function setMargin_main() {
12428 // Parse the margin property.
12429 switch (objType(margin)) {
12430 case 'number':
12431 margin = [margin, margin, margin, margin];
12432
12433 case 'array':
12434 if (margin.length === 2) {
12435 margin = [margin[0], margin[1], margin[0], margin[1]];
12436 }
12437
12438 if (margin.length === 4) {
12439 break;
12440 }
12441
12442 default:
12443 return this.error('Invalid margin array.');
12444 } // Set the margin property, then update pageSize.
12445
12446
12447 this.opt.margin = margin;
12448 }).then(this.setPageSize);
12449 };
12450
12451 Worker.prototype.setPageSize = function setPageSize(pageSize) {
12452 function toPx(val, k) {
12453 return Math.floor(val * k / 72 * 96);
12454 }
12455
12456 return this.then(function setPageSize_main() {
12457 // Retrieve page-size based on jsPDF settings, if not explicitly provided.
12458 pageSize = pageSize || jsPDF.getPageSize(this.opt.jsPDF); // Add 'inner' field if not present.
12459
12460 if (!pageSize.hasOwnProperty('inner')) {
12461 pageSize.inner = {
12462 width: pageSize.width - this.opt.margin[1] - this.opt.margin[3],
12463 height: pageSize.height - this.opt.margin[0] - this.opt.margin[2]
12464 };
12465 pageSize.inner.px = {
12466 width: toPx(pageSize.inner.width, pageSize.k),
12467 height: toPx(pageSize.inner.height, pageSize.k)
12468 };
12469 pageSize.inner.ratio = pageSize.inner.height / pageSize.inner.width;
12470 } // Attach pageSize to this.
12471
12472
12473 this.prop.pageSize = pageSize;
12474 });
12475 };
12476
12477 Worker.prototype.setProgress = function setProgress(val, state, n, stack) {
12478 // Immediately update all progress values.
12479 if (val != null) this.progress.val = val;
12480 if (state != null) this.progress.state = state;
12481 if (n != null) this.progress.n = n;
12482 if (stack != null) this.progress.stack = stack;
12483 this.progress.ratio = this.progress.val / this.progress.state; // Return this for command chaining.
12484
12485 return this;
12486 };
12487
12488 Worker.prototype.updateProgress = function updateProgress(val, state, n, stack) {
12489 // Immediately update all progress values, using setProgress.
12490 return this.setProgress(val ? this.progress.val + val : null, state ? state : null, n ? this.progress.n + n : null, stack ? this.progress.stack.concat(stack) : null);
12491 };
12492 /* ----- PROMISE MAPPING ----- */
12493
12494
12495 Worker.prototype.then = function then(onFulfilled, onRejected) {
12496 // Wrap `this` for encapsulation.
12497 var self = this;
12498 return this.thenCore(onFulfilled, onRejected, function then_main(onFulfilled, onRejected) {
12499 // Update progress while queuing, calling, and resolving `then`.
12500 self.updateProgress(null, null, 1, [onFulfilled]);
12501 return Promise.prototype.then.call(this, function then_pre(val) {
12502 self.updateProgress(null, onFulfilled);
12503 return val;
12504 }).then(onFulfilled, onRejected).then(function then_post(val) {
12505 self.updateProgress(1);
12506 return val;
12507 });
12508 });
12509 };
12510
12511 Worker.prototype.thenCore = function thenCore(onFulfilled, onRejected, thenBase) {
12512 // Handle optional thenBase parameter.
12513 thenBase = thenBase || Promise.prototype.then; // Wrap `this` for encapsulation and bind it to the promise handlers.
12514
12515 var self = this;
12516
12517 if (onFulfilled) {
12518 onFulfilled = onFulfilled.bind(self);
12519 }
12520
12521 if (onRejected) {
12522 onRejected = onRejected.bind(self);
12523 } // Cast self into a Promise to avoid polyfills recursively defining `then`.
12524
12525
12526 var isNative = Promise.toString().indexOf('[native code]') !== -1 && Promise.name === 'Promise';
12527 var selfPromise = isNative ? self : Worker.convert(Object.assign({}, self), Promise.prototype); // Return the promise, after casting it into a Worker and preserving props.
12528
12529 var returnVal = thenBase.call(selfPromise, onFulfilled, onRejected);
12530 return Worker.convert(returnVal, self.__proto__);
12531 };
12532
12533 Worker.prototype.thenExternal = function thenExternal(onFulfilled, onRejected) {
12534 // Call `then` and return a standard promise (exits the Worker chain).
12535 return Promise.prototype.then.call(this, onFulfilled, onRejected);
12536 };
12537
12538 Worker.prototype.thenList = function thenList(fns) {
12539 // Queue a series of promise 'factories' into the promise chain.
12540 var self = this;
12541 fns.forEach(function thenList_forEach(fn) {
12542 self = self.thenCore(fn);
12543 });
12544 return self;
12545 };
12546
12547 Worker.prototype['catch'] = function (onRejected) {
12548 // Bind `this` to the promise handler, call `catch`, and return a Worker.
12549 if (onRejected) {
12550 onRejected = onRejected.bind(this);
12551 }
12552
12553 var returnVal = Promise.prototype['catch'].call(this, onRejected);
12554 return Worker.convert(returnVal, this);
12555 };
12556
12557 Worker.prototype.catchExternal = function catchExternal(onRejected) {
12558 // Call `catch` and return a standard promise (exits the Worker chain).
12559 return Promise.prototype['catch'].call(this, onRejected);
12560 };
12561
12562 Worker.prototype.error = function error(msg) {
12563 // Throw the error in the Promise chain.
12564 return this.then(function error_main() {
12565 throw new Error(msg);
12566 });
12567 };
12568 /* ----- ALIASES ----- */
12569
12570
12571 Worker.prototype.using = Worker.prototype.set;
12572 Worker.prototype.saveAs = Worker.prototype.save;
12573 Worker.prototype.export = Worker.prototype.output;
12574 Worker.prototype.run = Worker.prototype.then; // Get dimensions of a PDF page, as determined by jsPDF.
12575
12576 jsPDF.getPageSize = function (orientation, unit, format) {
12577 // Decode options object
12578 if (_typeof(orientation) === 'object') {
12579 var options = orientation;
12580 orientation = options.orientation;
12581 unit = options.unit || unit;
12582 format = options.format || format;
12583 } // Default options
12584
12585
12586 unit = unit || 'mm';
12587 format = format || 'a4';
12588 orientation = ('' + (orientation || 'P')).toLowerCase();
12589 var format_as_string = ('' + format).toLowerCase(); // Size in pt of various paper formats
12590
12591 var pageFormats = {
12592 'a0': [2383.94, 3370.39],
12593 'a1': [1683.78, 2383.94],
12594 'a2': [1190.55, 1683.78],
12595 'a3': [841.89, 1190.55],
12596 'a4': [595.28, 841.89],
12597 'a5': [419.53, 595.28],
12598 'a6': [297.64, 419.53],
12599 'a7': [209.76, 297.64],
12600 'a8': [147.40, 209.76],
12601 'a9': [104.88, 147.40],
12602 'a10': [73.70, 104.88],
12603 'b0': [2834.65, 4008.19],
12604 'b1': [2004.09, 2834.65],
12605 'b2': [1417.32, 2004.09],
12606 'b3': [1000.63, 1417.32],
12607 'b4': [708.66, 1000.63],
12608 'b5': [498.90, 708.66],
12609 'b6': [354.33, 498.90],
12610 'b7': [249.45, 354.33],
12611 'b8': [175.75, 249.45],
12612 'b9': [124.72, 175.75],
12613 'b10': [87.87, 124.72],
12614 'c0': [2599.37, 3676.54],
12615 'c1': [1836.85, 2599.37],
12616 'c2': [1298.27, 1836.85],
12617 'c3': [918.43, 1298.27],
12618 'c4': [649.13, 918.43],
12619 'c5': [459.21, 649.13],
12620 'c6': [323.15, 459.21],
12621 'c7': [229.61, 323.15],
12622 'c8': [161.57, 229.61],
12623 'c9': [113.39, 161.57],
12624 'c10': [79.37, 113.39],
12625 'dl': [311.81, 623.62],
12626 'letter': [612, 792],
12627 'government-letter': [576, 756],
12628 'legal': [612, 1008],
12629 'junior-legal': [576, 360],
12630 'ledger': [1224, 792],
12631 'tabloid': [792, 1224],
12632 'credit-card': [153, 243]
12633 }; // Unit conversion
12634
12635 switch (unit) {
12636 case 'pt':
12637 var k = 1;
12638 break;
12639
12640 case 'mm':
12641 var k = 72 / 25.4;
12642 break;
12643
12644 case 'cm':
12645 var k = 72 / 2.54;
12646 break;
12647
12648 case 'in':
12649 var k = 72;
12650 break;
12651
12652 case 'px':
12653 var k = 72 / 96;
12654 break;
12655
12656 case 'pc':
12657 var k = 12;
12658 break;
12659
12660 case 'em':
12661 var k = 12;
12662 break;
12663
12664 case 'ex':
12665 var k = 6;
12666 break;
12667
12668 default:
12669 throw 'Invalid unit: ' + unit;
12670 } // Dimensions are stored as user units and converted to points on output
12671
12672
12673 if (pageFormats.hasOwnProperty(format_as_string)) {
12674 var pageHeight = pageFormats[format_as_string][1] / k;
12675 var pageWidth = pageFormats[format_as_string][0] / k;
12676 } else {
12677 try {
12678 var pageHeight = format[1];
12679 var pageWidth = format[0];
12680 } catch (err) {
12681 throw new Error('Invalid format: ' + format);
12682 }
12683 } // Handle page orientation
12684
12685
12686 if (orientation === 'p' || orientation === 'portrait') {
12687 orientation = 'p';
12688
12689 if (pageWidth > pageHeight) {
12690 var tmp = pageWidth;
12691 pageWidth = pageHeight;
12692 pageHeight = tmp;
12693 }
12694 } else if (orientation === 'l' || orientation === 'landscape') {
12695 orientation = 'l';
12696
12697 if (pageHeight > pageWidth) {
12698 var tmp = pageWidth;
12699 pageWidth = pageHeight;
12700 pageHeight = tmp;
12701 }
12702 } else {
12703 throw 'Invalid orientation: ' + orientation;
12704 } // Return information (k is the unit conversion ratio from pts)
12705
12706
12707 var info = {
12708 'width': pageWidth,
12709 'height': pageHeight,
12710 'unit': unit,
12711 'k': k
12712 };
12713 return info;
12714 };
12715 /**
12716 * Generate a PDF from an HTML element or string using.
12717 *
12718 * @name html
12719 * @function
12720 * @param {Element|string} source The source element or HTML string.
12721 * @param {Object=} options An object of optional settings.
12722 * @description The Plugin needs html2canvas from niklasvh
12723 */
12724
12725
12726 jsPDFAPI.html = function (src, options) {
12727
12728 options = options || {};
12729
12730 options.callback = options.callback || function () {};
12731
12732 options.html2canvas = options.html2canvas || {};
12733 options.html2canvas.canvas = options.html2canvas.canvas || this.canvas;
12734 options.jsPDF = options.jsPDF || this; // Create a new worker with the given options.
12735
12736 var pdf = options.jsPDF;
12737 var worker = new Worker(options);
12738
12739 if (!options.worker) {
12740 // If worker is not set to true, perform the traditional 'simple' operation.
12741 return worker.from(src).doCallback();
12742 } else {
12743 // Otherwise, return the worker for new Promise-based operation.
12744 return worker;
12745 }
12746
12747 return this;
12748 };
12749 })(jsPDF.API, typeof window !== "undefined" && window || typeof global !== "undefined" && global);
12750
12751 /**
12752 * @license
12753 * ====================================================================
12754 * Copyright (c) 2013 Youssef Beddad, youssef.beddad@gmail.com
12755 *
12756 *
12757 * ====================================================================
12758 */
12759
12760 /*global jsPDF */
12761
12762 /**
12763 * jsPDF JavaScript plugin
12764 *
12765 * @name javascript
12766 * @module
12767 */
12768 (function (jsPDFAPI) {
12769
12770 var jsNamesObj, jsJsObj, text;
12771 /**
12772 * @name addJS
12773 * @function
12774 * @param {string} javascript The javascript to be embedded into the PDF-file.
12775 * @returns {jsPDF}
12776 */
12777
12778 jsPDFAPI.addJS = function (javascript) {
12779 text = javascript;
12780 this.internal.events.subscribe('postPutResources', function (javascript) {
12781 jsNamesObj = this.internal.newObject();
12782 this.internal.out('<<');
12783 this.internal.out('/Names [(EmbeddedJS) ' + (jsNamesObj + 1) + ' 0 R]');
12784 this.internal.out('>>');
12785 this.internal.out('endobj');
12786 jsJsObj = this.internal.newObject();
12787 this.internal.out('<<');
12788 this.internal.out('/S /JavaScript');
12789 this.internal.out('/JS (' + text + ')');
12790 this.internal.out('>>');
12791 this.internal.out('endobj');
12792 });
12793 this.internal.events.subscribe('putCatalog', function () {
12794 if (jsNamesObj !== undefined && jsJsObj !== undefined) {
12795 this.internal.out('/Names <</JavaScript ' + jsNamesObj + ' 0 R>>');
12796 }
12797 });
12798 return this;
12799 };
12800 })(jsPDF.API);
12801
12802 /**
12803 * @license
12804 * Copyright (c) 2014 Steven Spungin (TwelveTone LLC) steven@twelvetone.tv
12805 *
12806 * Licensed under the MIT License.
12807 * http://opensource.org/licenses/mit-license
12808 */
12809
12810 (function (jsPDFAPI) {
12811
12812 jsPDFAPI.events.push(['postPutResources', function () {
12813 var pdf = this;
12814 var rx = /^(\d+) 0 obj$/; // Write action goto objects for each page
12815 // this.outline.destsGoto = [];
12816 // for (var i = 0; i < totalPages; i++) {
12817 // var id = pdf.internal.newObject();
12818 // this.outline.destsGoto.push(id);
12819 // pdf.internal.write("<</D[" + (i * 2 + 3) + " 0 R /XYZ null
12820 // null null]/S/GoTo>> endobj");
12821 // }
12822 //
12823 // for (var i = 0; i < dests.length; i++) {
12824 // pdf.internal.write("(page_" + (i + 1) + ")" + dests[i] + " 0
12825 // R");
12826 // }
12827 //
12828
12829 if (this.outline.root.children.length > 0) {
12830 var lines = pdf.outline.render().split(/\r\n/);
12831
12832 for (var i = 0; i < lines.length; i++) {
12833 var line = lines[i];
12834 var m = rx.exec(line);
12835
12836 if (m != null) {
12837 var oid = m[1];
12838 pdf.internal.newObjectDeferredBegin(oid, false);
12839 }
12840
12841 pdf.internal.write(line);
12842 }
12843 } // This code will write named destination for each page reference
12844 // (page_1, etc)
12845
12846
12847 if (this.outline.createNamedDestinations) {
12848 var totalPages = this.internal.pages.length; // WARNING: this assumes jsPDF starts on page 3 and pageIDs
12849 // follow 5, 7, 9, etc
12850 // Write destination objects for each page
12851
12852 var dests = [];
12853
12854 for (var i = 0; i < totalPages; i++) {
12855 var id = pdf.internal.newObject();
12856 dests.push(id);
12857 var info = pdf.internal.getPageInfo(i + 1);
12858 pdf.internal.write("<< /D[" + info.objId + " 0 R /XYZ null null null]>> endobj");
12859 } // assign a name for each destination
12860
12861
12862 var names2Oid = pdf.internal.newObject();
12863 pdf.internal.write('<< /Names [ ');
12864
12865 for (var i = 0; i < dests.length; i++) {
12866 pdf.internal.write("(page_" + (i + 1) + ")" + dests[i] + " 0 R");
12867 }
12868
12869 pdf.internal.write(' ] >>', 'endobj'); // var kids = pdf.internal.newObject();
12870 // pdf.internal.write('<< /Kids [ ' + names2Oid + ' 0 R');
12871 // pdf.internal.write(' ] >>', 'endobj');
12872
12873 var namesOid = pdf.internal.newObject();
12874 pdf.internal.write('<< /Dests ' + names2Oid + " 0 R");
12875 pdf.internal.write('>>', 'endobj');
12876 }
12877 }]);
12878 jsPDFAPI.events.push(['putCatalog', function () {
12879 var pdf = this;
12880
12881 if (pdf.outline.root.children.length > 0) {
12882 pdf.internal.write("/Outlines", this.outline.makeRef(this.outline.root));
12883
12884 if (this.outline.createNamedDestinations) {
12885 pdf.internal.write("/Names " + namesOid + " 0 R");
12886 } // Open with Bookmarks showing
12887 // pdf.internal.write("/PageMode /UseOutlines");
12888
12889 }
12890 }]);
12891 jsPDFAPI.events.push(['initialized', function () {
12892 var pdf = this;
12893 pdf.outline = {
12894 createNamedDestinations: false,
12895 root: {
12896 children: []
12897 }
12898 };
12899 /**
12900 * Options: pageNumber
12901 */
12902
12903 pdf.outline.add = function (parent, title, options) {
12904 var item = {
12905 title: title,
12906 options: options,
12907 children: []
12908 };
12909
12910 if (parent == null) {
12911 parent = this.root;
12912 }
12913
12914 parent.children.push(item);
12915 return item;
12916 };
12917
12918 pdf.outline.render = function () {
12919 this.ctx = {};
12920 this.ctx.val = '';
12921 this.ctx.pdf = pdf;
12922 this.genIds_r(this.root);
12923 this.renderRoot(this.root);
12924 this.renderItems(this.root);
12925 return this.ctx.val;
12926 };
12927
12928 pdf.outline.genIds_r = function (node) {
12929 node.id = pdf.internal.newObjectDeferred();
12930
12931 for (var i = 0; i < node.children.length; i++) {
12932 this.genIds_r(node.children[i]);
12933 }
12934 };
12935
12936 pdf.outline.renderRoot = function (node) {
12937 this.objStart(node);
12938 this.line('/Type /Outlines');
12939
12940 if (node.children.length > 0) {
12941 this.line('/First ' + this.makeRef(node.children[0]));
12942 this.line('/Last ' + this.makeRef(node.children[node.children.length - 1]));
12943 }
12944
12945 this.line('/Count ' + this.count_r({
12946 count: 0
12947 }, node));
12948 this.objEnd();
12949 };
12950
12951 pdf.outline.renderItems = function (node) {
12952 var getHorizontalCoordinateString = this.ctx.pdf.internal.getCoordinateString;
12953 var getVerticalCoordinateString = this.ctx.pdf.internal.getVerticalCoordinateString;
12954
12955 for (var i = 0; i < node.children.length; i++) {
12956 var item = node.children[i];
12957 this.objStart(item);
12958 this.line('/Title ' + this.makeString(item.title));
12959 this.line('/Parent ' + this.makeRef(node));
12960
12961 if (i > 0) {
12962 this.line('/Prev ' + this.makeRef(node.children[i - 1]));
12963 }
12964
12965 if (i < node.children.length - 1) {
12966 this.line('/Next ' + this.makeRef(node.children[i + 1]));
12967 }
12968
12969 if (item.children.length > 0) {
12970 this.line('/First ' + this.makeRef(item.children[0]));
12971 this.line('/Last ' + this.makeRef(item.children[item.children.length - 1]));
12972 }
12973
12974 var count = this.count = this.count_r({
12975 count: 0
12976 }, item);
12977
12978 if (count > 0) {
12979 this.line('/Count ' + count);
12980 }
12981
12982 if (item.options) {
12983 if (item.options.pageNumber) {
12984 // Explicit Destination
12985 //WARNING this assumes page ids are 3,5,7, etc.
12986 var info = pdf.internal.getPageInfo(item.options.pageNumber);
12987 this.line('/Dest ' + '[' + info.objId + ' 0 R /XYZ 0 ' + getVerticalCoordinateString(0) + ' 0]'); // this line does not work on all clients (pageNumber instead of page ref)
12988 //this.line('/Dest ' + '[' + (item.options.pageNumber - 1) + ' /XYZ 0 ' + this.ctx.pdf.internal.pageSize.getHeight() + ' 0]');
12989 // Named Destination
12990 // this.line('/Dest (page_' + (item.options.pageNumber) + ')');
12991 // Action Destination
12992 // var id = pdf.internal.newObject();
12993 // pdf.internal.write('<</D[' + (item.options.pageNumber - 1) + ' /XYZ null null null]/S/GoTo>> endobj');
12994 // this.line('/A ' + id + ' 0 R' );
12995 }
12996 }
12997
12998 this.objEnd();
12999 }
13000
13001 for (var i = 0; i < node.children.length; i++) {
13002 var item = node.children[i];
13003 this.renderItems(item);
13004 }
13005 };
13006
13007 pdf.outline.line = function (text) {
13008 this.ctx.val += text + '\r\n';
13009 };
13010
13011 pdf.outline.makeRef = function (node) {
13012 return node.id + ' 0 R';
13013 };
13014
13015 pdf.outline.makeString = function (val) {
13016 return '(' + pdf.internal.pdfEscape(val) + ')';
13017 };
13018
13019 pdf.outline.objStart = function (node) {
13020 this.ctx.val += '\r\n' + node.id + ' 0 obj' + '\r\n<<\r\n';
13021 };
13022
13023 pdf.outline.objEnd = function (node) {
13024 this.ctx.val += '>> \r\n' + 'endobj' + '\r\n';
13025 };
13026
13027 pdf.outline.count_r = function (ctx, node) {
13028 for (var i = 0; i < node.children.length; i++) {
13029 ctx.count++;
13030 this.count_r(ctx, node.children[i]);
13031 }
13032
13033 return ctx.count;
13034 };
13035 }]);
13036 return this;
13037 })(jsPDF.API);
13038
13039 /**
13040 * @license
13041 *
13042 * Copyright (c) 2014 James Robb, https://github.com/jamesbrobb
13043 *
13044 *
13045 * ====================================================================
13046 */
13047
13048 /**
13049 * jsPDF PNG PlugIn
13050 * @name png_support
13051 * @module
13052 */
13053 (function (jsPDFAPI) {
13054 /*
13055 * @see http://www.w3.org/TR/PNG-Chunks.html
13056 *
13057 Color Allowed Interpretation
13058 Type Bit Depths
13059 0 1,2,4,8,16 Each pixel is a grayscale sample.
13060 2 8,16 Each pixel is an R,G,B triple.
13061 3 1,2,4,8 Each pixel is a palette index;
13062 a PLTE chunk must appear.
13063 4 8,16 Each pixel is a grayscale sample,
13064 followed by an alpha sample.
13065 6 8,16 Each pixel is an R,G,B triple,
13066 followed by an alpha sample.
13067 */
13068
13069 /*
13070 * PNG filter method types
13071 *
13072 * @see http://www.w3.org/TR/PNG-Filters.html
13073 * @see http://www.libpng.org/pub/png/book/chapter09.html
13074 *
13075 * This is what the value 'Predictor' in decode params relates to
13076 *
13077 * 15 is "optimal prediction", which means the prediction algorithm can change from line to line.
13078 * In that case, you actually have to read the first byte off each line for the prediction algorthim (which should be 0-4, corresponding to PDF 10-14) and select the appropriate unprediction algorithm based on that byte.
13079 *
13080 0 None
13081 1 Sub
13082 2 Up
13083 3 Average
13084 4 Paeth
13085 */
13086
13087 var doesNotHavePngJS = function doesNotHavePngJS() {
13088 return typeof PNG !== 'function' || typeof FlateStream !== 'function';
13089 },
13090 canCompress = function canCompress(value) {
13091 return value !== jsPDFAPI.image_compression.NONE && hasCompressionJS();
13092 },
13093 hasCompressionJS = function hasCompressionJS() {
13094 var inst = typeof Deflater === 'function';
13095 if (!inst) throw new Error("requires deflate.js for compression");
13096 return inst;
13097 },
13098 compressBytes = function compressBytes(bytes, lineLength, colorsPerPixel, compression) {
13099 var level = 5,
13100 filter_method = filterUp;
13101
13102 switch (compression) {
13103 case jsPDFAPI.image_compression.FAST:
13104 level = 3;
13105 filter_method = filterSub;
13106 break;
13107
13108 case jsPDFAPI.image_compression.MEDIUM:
13109 level = 6;
13110 filter_method = filterAverage;
13111 break;
13112
13113 case jsPDFAPI.image_compression.SLOW:
13114 level = 9;
13115 filter_method = filterPaeth; //uses to sum to choose best filter for each line
13116
13117 break;
13118 }
13119
13120 bytes = applyPngFilterMethod(bytes, lineLength, colorsPerPixel, filter_method);
13121 var header = new Uint8Array(createZlibHeader(level));
13122 var checksum = adler32(bytes);
13123 var deflate = new Deflater(level);
13124 var a = deflate.append(bytes);
13125 var cBytes = deflate.flush();
13126 var len = header.length + a.length + cBytes.length;
13127 var cmpd = new Uint8Array(len + 4);
13128 cmpd.set(header);
13129 cmpd.set(a, header.length);
13130 cmpd.set(cBytes, header.length + a.length);
13131 cmpd[len++] = checksum >>> 24 & 0xff;
13132 cmpd[len++] = checksum >>> 16 & 0xff;
13133 cmpd[len++] = checksum >>> 8 & 0xff;
13134 cmpd[len++] = checksum & 0xff;
13135 return jsPDFAPI.arrayBufferToBinaryString(cmpd);
13136 },
13137 createZlibHeader = function createZlibHeader(bytes, level) {
13138 /*
13139 * @see http://www.ietf.org/rfc/rfc1950.txt for zlib header
13140 */
13141 var cm = 8;
13142 var cinfo = Math.LOG2E * Math.log(0x8000) - 8;
13143 var cmf = cinfo << 4 | cm;
13144 var hdr = cmf << 8;
13145 var flevel = Math.min(3, (level - 1 & 0xff) >> 1);
13146 hdr |= flevel << 6;
13147 hdr |= 0; //FDICT
13148
13149 hdr += 31 - hdr % 31;
13150 return [cmf, hdr & 0xff & 0xff];
13151 },
13152 adler32 = function adler32(array, param) {
13153 var adler = 1;
13154 var s1 = adler & 0xffff,
13155 s2 = adler >>> 16 & 0xffff;
13156 var len = array.length;
13157 var tlen;
13158 var i = 0;
13159
13160 while (len > 0) {
13161 tlen = len > param ? param : len;
13162 len -= tlen;
13163
13164 do {
13165 s1 += array[i++];
13166 s2 += s1;
13167 } while (--tlen);
13168
13169 s1 %= 65521;
13170 s2 %= 65521;
13171 }
13172
13173 return (s2 << 16 | s1) >>> 0;
13174 },
13175 applyPngFilterMethod = function applyPngFilterMethod(bytes, lineLength, colorsPerPixel, filter_method) {
13176 var lines = bytes.length / lineLength,
13177 result = new Uint8Array(bytes.length + lines),
13178 filter_methods = getFilterMethods(),
13179 i = 0,
13180 line,
13181 prevLine,
13182 offset;
13183
13184 for (; i < lines; i++) {
13185 offset = i * lineLength;
13186 line = bytes.subarray(offset, offset + lineLength);
13187
13188 if (filter_method) {
13189 result.set(filter_method(line, colorsPerPixel, prevLine), offset + i);
13190 } else {
13191 var j = 0,
13192 len = filter_methods.length,
13193 results = [];
13194
13195 for (; j < len; j++) {
13196 results[j] = filter_methods[j](line, colorsPerPixel, prevLine);
13197 }
13198
13199 var ind = getIndexOfSmallestSum(results.concat());
13200 result.set(results[ind], offset + i);
13201 }
13202
13203 prevLine = line;
13204 }
13205
13206 return result;
13207 },
13208 filterNone = function filterNone(line, colorsPerPixel, prevLine) {
13209 /*var result = new Uint8Array(line.length + 1);
13210 result[0] = 0;
13211 result.set(line, 1);*/
13212 var result = Array.apply([], line);
13213 result.unshift(0);
13214 return result;
13215 },
13216 filterSub = function filterSub(line, colorsPerPixel, prevLine) {
13217 var result = [],
13218 i = 0,
13219 len = line.length,
13220 left;
13221 result[0] = 1;
13222
13223 for (; i < len; i++) {
13224 left = line[i - colorsPerPixel] || 0;
13225 result[i + 1] = line[i] - left + 0x0100 & 0xff;
13226 }
13227
13228 return result;
13229 },
13230 filterUp = function filterUp(line, colorsPerPixel, prevLine) {
13231 var result = [],
13232 i = 0,
13233 len = line.length,
13234 up;
13235 result[0] = 2;
13236
13237 for (; i < len; i++) {
13238 up = prevLine && prevLine[i] || 0;
13239 result[i + 1] = line[i] - up + 0x0100 & 0xff;
13240 }
13241
13242 return result;
13243 },
13244 filterAverage = function filterAverage(line, colorsPerPixel, prevLine) {
13245 var result = [],
13246 i = 0,
13247 len = line.length,
13248 left,
13249 up;
13250 result[0] = 3;
13251
13252 for (; i < len; i++) {
13253 left = line[i - colorsPerPixel] || 0;
13254 up = prevLine && prevLine[i] || 0;
13255 result[i + 1] = line[i] + 0x0100 - (left + up >>> 1) & 0xff;
13256 }
13257
13258 return result;
13259 },
13260 filterPaeth = function filterPaeth(line, colorsPerPixel, prevLine) {
13261 var result = [],
13262 i = 0,
13263 len = line.length,
13264 left,
13265 up,
13266 upLeft,
13267 paeth;
13268 result[0] = 4;
13269
13270 for (; i < len; i++) {
13271 left = line[i - colorsPerPixel] || 0;
13272 up = prevLine && prevLine[i] || 0;
13273 upLeft = prevLine && prevLine[i - colorsPerPixel] || 0;
13274 paeth = paethPredictor(left, up, upLeft);
13275 result[i + 1] = line[i] - paeth + 0x0100 & 0xff;
13276 }
13277
13278 return result;
13279 },
13280 paethPredictor = function paethPredictor(left, up, upLeft) {
13281 var p = left + up - upLeft,
13282 pLeft = Math.abs(p - left),
13283 pUp = Math.abs(p - up),
13284 pUpLeft = Math.abs(p - upLeft);
13285 return pLeft <= pUp && pLeft <= pUpLeft ? left : pUp <= pUpLeft ? up : upLeft;
13286 },
13287 getFilterMethods = function getFilterMethods() {
13288 return [filterNone, filterSub, filterUp, filterAverage, filterPaeth];
13289 },
13290 getIndexOfSmallestSum = function getIndexOfSmallestSum(arrays) {
13291 var i = 0,
13292 len = arrays.length,
13293 sum,
13294 min,
13295 ind;
13296
13297 while (i < len) {
13298 sum = absSum(arrays[i].slice(1));
13299
13300 if (sum < min || !min) {
13301 min = sum;
13302 ind = i;
13303 }
13304
13305 i++;
13306 }
13307
13308 return ind;
13309 },
13310 absSum = function absSum(array) {
13311 var i = 0,
13312 len = array.length,
13313 sum = 0;
13314
13315 while (i < len) {
13316 sum += Math.abs(array[i++]);
13317 }
13318
13319 return sum;
13320 },
13321 getPredictorFromCompression = function getPredictorFromCompression(compression) {
13322 var predictor;
13323
13324 switch (compression) {
13325 case jsPDFAPI.image_compression.FAST:
13326 predictor = 11;
13327 break;
13328
13329 case jsPDFAPI.image_compression.MEDIUM:
13330 predictor = 13;
13331 break;
13332
13333 case jsPDFAPI.image_compression.SLOW:
13334 predictor = 14;
13335 break;
13336
13337 default:
13338 predictor = 12;
13339 break;
13340 }
13341
13342 return predictor;
13343 };
13344 /**
13345 *
13346 * @name processPNG
13347 * @function
13348 * @ignore
13349 */
13350
13351
13352 jsPDFAPI.processPNG = function (imageData, imageIndex, alias, compression, dataAsBinaryString) {
13353
13354 var colorSpace = this.color_spaces.DEVICE_RGB,
13355 decode = this.decode.FLATE_DECODE,
13356 bpc = 8,
13357 img,
13358 dp,
13359 trns,
13360 colors,
13361 pal,
13362 smask;
13363 /* if(this.isString(imageData)) {
13364 }*/
13365
13366 if (this.isArrayBuffer(imageData)) imageData = new Uint8Array(imageData);
13367
13368 if (this.isArrayBufferView(imageData)) {
13369 if (doesNotHavePngJS()) throw new Error("PNG support requires png.js and zlib.js");
13370 img = new PNG(imageData);
13371 imageData = img.imgData;
13372 bpc = img.bits;
13373 colorSpace = img.colorSpace;
13374 colors = img.colors; //logImg(img);
13375
13376 /*
13377 * colorType 6 - Each pixel is an R,G,B triple, followed by an alpha sample.
13378 *
13379 * colorType 4 - Each pixel is a grayscale sample, followed by an alpha sample.
13380 *
13381 * Extract alpha to create two separate images, using the alpha as a sMask
13382 */
13383
13384 if ([4, 6].indexOf(img.colorType) !== -1) {
13385 /*
13386 * processes 8 bit RGBA and grayscale + alpha images
13387 */
13388 if (img.bits === 8) {
13389 var pixels = img.pixelBitlength == 32 ? new Uint32Array(img.decodePixels().buffer) : img.pixelBitlength == 16 ? new Uint16Array(img.decodePixels().buffer) : new Uint8Array(img.decodePixels().buffer),
13390 len = pixels.length,
13391 imgData = new Uint8Array(len * img.colors),
13392 alphaData = new Uint8Array(len),
13393 pDiff = img.pixelBitlength - img.bits,
13394 i = 0,
13395 n = 0,
13396 pixel,
13397 pbl;
13398
13399 for (; i < len; i++) {
13400 pixel = pixels[i];
13401 pbl = 0;
13402
13403 while (pbl < pDiff) {
13404 imgData[n++] = pixel >>> pbl & 0xff;
13405 pbl = pbl + img.bits;
13406 }
13407
13408 alphaData[i] = pixel >>> pbl & 0xff;
13409 }
13410 }
13411 /*
13412 * processes 16 bit RGBA and grayscale + alpha images
13413 */
13414
13415
13416 if (img.bits === 16) {
13417 var pixels = new Uint32Array(img.decodePixels().buffer),
13418 len = pixels.length,
13419 imgData = new Uint8Array(len * (32 / img.pixelBitlength) * img.colors),
13420 alphaData = new Uint8Array(len * (32 / img.pixelBitlength)),
13421 hasColors = img.colors > 1,
13422 i = 0,
13423 n = 0,
13424 a = 0,
13425 pixel;
13426
13427 while (i < len) {
13428 pixel = pixels[i++];
13429 imgData[n++] = pixel >>> 0 & 0xFF;
13430
13431 if (hasColors) {
13432 imgData[n++] = pixel >>> 16 & 0xFF;
13433 pixel = pixels[i++];
13434 imgData[n++] = pixel >>> 0 & 0xFF;
13435 }
13436
13437 alphaData[a++] = pixel >>> 16 & 0xFF;
13438 }
13439
13440 bpc = 8;
13441 }
13442
13443 if (canCompress(compression)) {
13444 imageData = compressBytes(imgData, img.width * img.colors, img.colors, compression);
13445 smask = compressBytes(alphaData, img.width, 1, compression);
13446 } else {
13447 imageData = imgData;
13448 smask = alphaData;
13449 decode = null;
13450 }
13451 }
13452 /*
13453 * Indexed png. Each pixel is a palette index.
13454 */
13455
13456
13457 if (img.colorType === 3) {
13458 colorSpace = this.color_spaces.INDEXED;
13459 pal = img.palette;
13460
13461 if (img.transparency.indexed) {
13462 var trans = img.transparency.indexed;
13463 var total = 0,
13464 i = 0,
13465 len = trans.length;
13466
13467 for (; i < len; ++i) {
13468 total += trans[i];
13469 }
13470
13471 total = total / 255;
13472 /*
13473 * a single color is specified as 100% transparent (0),
13474 * so we set trns to use a /Mask with that index
13475 */
13476
13477 if (total === len - 1 && trans.indexOf(0) !== -1) {
13478 trns = [trans.indexOf(0)];
13479 /*
13480 * there's more than one colour within the palette that specifies
13481 * a transparency value less than 255, so we unroll the pixels to create an image sMask
13482 */
13483 } else if (total !== len) {
13484 var pixels = img.decodePixels(),
13485 alphaData = new Uint8Array(pixels.length),
13486 i = 0,
13487 len = pixels.length;
13488
13489 for (; i < len; i++) {
13490 alphaData[i] = trans[pixels[i]];
13491 }
13492
13493 smask = compressBytes(alphaData, img.width, 1);
13494 }
13495 }
13496 }
13497
13498 var predictor = getPredictorFromCompression(compression);
13499 if (decode === this.decode.FLATE_DECODE) dp = '/Predictor ' + predictor + ' /Colors ' + colors + ' /BitsPerComponent ' + bpc + ' /Columns ' + img.width;else //remove 'Predictor' as it applies to the type of png filter applied to its IDAT - we only apply with compression
13500 dp = '/Colors ' + colors + ' /BitsPerComponent ' + bpc + ' /Columns ' + img.width;
13501 if (this.isArrayBuffer(imageData) || this.isArrayBufferView(imageData)) imageData = this.arrayBufferToBinaryString(imageData);
13502 if (smask && this.isArrayBuffer(smask) || this.isArrayBufferView(smask)) smask = this.arrayBufferToBinaryString(smask);
13503 return this.createImageInfo(imageData, img.width, img.height, colorSpace, bpc, decode, imageIndex, alias, dp, trns, pal, smask, predictor);
13504 }
13505
13506 throw new Error("Unsupported PNG image data, try using JPEG instead.");
13507 };
13508 })(jsPDF.API);
13509
13510 /**
13511 * @license
13512 * Copyright (c) 2017 Aras Abbasi
13513 *
13514 * Licensed under the MIT License.
13515 * http://opensource.org/licenses/mit-license
13516 */
13517
13518 /**
13519 * jsPDF gif Support PlugIn
13520 *
13521 * @name gif_support
13522 * @module
13523 */
13524 (function (jsPDFAPI) {
13525
13526 jsPDFAPI.processGIF89A = function (imageData, imageIndex, alias, compression, dataAsBinaryString) {
13527 var reader = new GifReader(imageData);
13528 var width = reader.width,
13529 height = reader.height;
13530 var qu = 100;
13531 var pixels = [];
13532 reader.decodeAndBlitFrameRGBA(0, pixels);
13533 var rawImageData = {
13534 data: pixels,
13535 width: width,
13536 height: height
13537 };
13538 var encoder = new JPEGEncoder(qu);
13539 var data = encoder.encode(rawImageData, qu);
13540 return jsPDFAPI.processJPEG.call(this, data, imageIndex, alias, compression);
13541 };
13542
13543 jsPDFAPI.processGIF87A = jsPDFAPI.processGIF89A;
13544 })(jsPDF.API);
13545
13546 /**
13547 * Copyright (c) 2018 Aras Abbasi
13548 *
13549 * Licensed under the MIT License.
13550 * http://opensource.org/licenses/mit-license
13551 */
13552
13553 /**
13554 * jsPDF bmp Support PlugIn
13555 * @name bmp_support
13556 * @module
13557 */
13558 (function (jsPDFAPI) {
13559
13560 jsPDFAPI.processBMP = function (imageData, imageIndex, alias, compression, dataAsBinaryString) {
13561 var reader = new BmpDecoder(imageData, false);
13562 var width = reader.width,
13563 height = reader.height;
13564 var qu = 100;
13565 var pixels = reader.getData();
13566 var rawImageData = {
13567 data: pixels,
13568 width: width,
13569 height: height
13570 };
13571 var encoder = new JPEGEncoder(qu);
13572 var data = encoder.encode(rawImageData, qu);
13573 return jsPDFAPI.processJPEG.call(this, data, imageIndex, alias, compression);
13574 };
13575 })(jsPDF.API);
13576
13577 /**
13578 * @license
13579 * Licensed under the MIT License.
13580 * http://opensource.org/licenses/mit-license
13581 */
13582
13583 /**
13584 * jsPDF setLanguage Plugin
13585 *
13586 * @name setLanguage
13587 * @module
13588 */
13589 (function (jsPDFAPI) {
13590 /**
13591 * Add Language Tag to the generated PDF
13592 *
13593 * @name setLanguage
13594 * @function
13595 * @param {string} langCode The Language code as ISO-639-1 (e.g. 'en') or as country language code (e.g. 'en-GB').
13596 * @returns {jsPDF}
13597 * @example
13598 * var doc = new jsPDF()
13599 * doc.text(10, 10, 'This is a test')
13600 * doc.setLanguage("en-US")
13601 * doc.save('english.pdf')
13602 */
13603
13604 jsPDFAPI.setLanguage = function (langCode) {
13605
13606 var langCodes = {
13607 "af": "Afrikaans",
13608 "sq": "Albanian",
13609 "ar": "Arabic (Standard)",
13610 "ar-DZ": "Arabic (Algeria)",
13611 "ar-BH": "Arabic (Bahrain)",
13612 "ar-EG": "Arabic (Egypt)",
13613 "ar-IQ": "Arabic (Iraq)",
13614 "ar-JO": "Arabic (Jordan)",
13615 "ar-KW": "Arabic (Kuwait)",
13616 "ar-LB": "Arabic (Lebanon)",
13617 "ar-LY": "Arabic (Libya)",
13618 "ar-MA": "Arabic (Morocco)",
13619 "ar-OM": "Arabic (Oman)",
13620 "ar-QA": "Arabic (Qatar)",
13621 "ar-SA": "Arabic (Saudi Arabia)",
13622 "ar-SY": "Arabic (Syria)",
13623 "ar-TN": "Arabic (Tunisia)",
13624 "ar-AE": "Arabic (U.A.E.)",
13625 "ar-YE": "Arabic (Yemen)",
13626 "an": "Aragonese",
13627 "hy": "Armenian",
13628 "as": "Assamese",
13629 "ast": "Asturian",
13630 "az": "Azerbaijani",
13631 "eu": "Basque",
13632 "be": "Belarusian",
13633 "bn": "Bengali",
13634 "bs": "Bosnian",
13635 "br": "Breton",
13636 "bg": "Bulgarian",
13637 "my": "Burmese",
13638 "ca": "Catalan",
13639 "ch": "Chamorro",
13640 "ce": "Chechen",
13641 "zh": "Chinese",
13642 "zh-HK": "Chinese (Hong Kong)",
13643 "zh-CN": "Chinese (PRC)",
13644 "zh-SG": "Chinese (Singapore)",
13645 "zh-TW": "Chinese (Taiwan)",
13646 "cv": "Chuvash",
13647 "co": "Corsican",
13648 "cr": "Cree",
13649 "hr": "Croatian",
13650 "cs": "Czech",
13651 "da": "Danish",
13652 "nl": "Dutch (Standard)",
13653 "nl-BE": "Dutch (Belgian)",
13654 "en": "English",
13655 "en-AU": "English (Australia)",
13656 "en-BZ": "English (Belize)",
13657 "en-CA": "English (Canada)",
13658 "en-IE": "English (Ireland)",
13659 "en-JM": "English (Jamaica)",
13660 "en-NZ": "English (New Zealand)",
13661 "en-PH": "English (Philippines)",
13662 "en-ZA": "English (South Africa)",
13663 "en-TT": "English (Trinidad & Tobago)",
13664 "en-GB": "English (United Kingdom)",
13665 "en-US": "English (United States)",
13666 "en-ZW": "English (Zimbabwe)",
13667 "eo": "Esperanto",
13668 "et": "Estonian",
13669 "fo": "Faeroese",
13670 "fj": "Fijian",
13671 "fi": "Finnish",
13672 "fr": "French (Standard)",
13673 "fr-BE": "French (Belgium)",
13674 "fr-CA": "French (Canada)",
13675 "fr-FR": "French (France)",
13676 "fr-LU": "French (Luxembourg)",
13677 "fr-MC": "French (Monaco)",
13678 "fr-CH": "French (Switzerland)",
13679 "fy": "Frisian",
13680 "fur": "Friulian",
13681 "gd": "Gaelic (Scots)",
13682 "gd-IE": "Gaelic (Irish)",
13683 "gl": "Galacian",
13684 "ka": "Georgian",
13685 "de": "German (Standard)",
13686 "de-AT": "German (Austria)",
13687 "de-DE": "German (Germany)",
13688 "de-LI": "German (Liechtenstein)",
13689 "de-LU": "German (Luxembourg)",
13690 "de-CH": "German (Switzerland)",
13691 "el": "Greek",
13692 "gu": "Gujurati",
13693 "ht": "Haitian",
13694 "he": "Hebrew",
13695 "hi": "Hindi",
13696 "hu": "Hungarian",
13697 "is": "Icelandic",
13698 "id": "Indonesian",
13699 "iu": "Inuktitut",
13700 "ga": "Irish",
13701 "it": "Italian (Standard)",
13702 "it-CH": "Italian (Switzerland)",
13703 "ja": "Japanese",
13704 "kn": "Kannada",
13705 "ks": "Kashmiri",
13706 "kk": "Kazakh",
13707 "km": "Khmer",
13708 "ky": "Kirghiz",
13709 "tlh": "Klingon",
13710 "ko": "Korean",
13711 "ko-KP": "Korean (North Korea)",
13712 "ko-KR": "Korean (South Korea)",
13713 "la": "Latin",
13714 "lv": "Latvian",
13715 "lt": "Lithuanian",
13716 "lb": "Luxembourgish",
13717 "mk": "FYRO Macedonian",
13718 "ms": "Malay",
13719 "ml": "Malayalam",
13720 "mt": "Maltese",
13721 "mi": "Maori",
13722 "mr": "Marathi",
13723 "mo": "Moldavian",
13724 "nv": "Navajo",
13725 "ng": "Ndonga",
13726 "ne": "Nepali",
13727 "no": "Norwegian",
13728 "nb": "Norwegian (Bokmal)",
13729 "nn": "Norwegian (Nynorsk)",
13730 "oc": "Occitan",
13731 "or": "Oriya",
13732 "om": "Oromo",
13733 "fa": "Persian",
13734 "fa-IR": "Persian/Iran",
13735 "pl": "Polish",
13736 "pt": "Portuguese",
13737 "pt-BR": "Portuguese (Brazil)",
13738 "pa": "Punjabi",
13739 "pa-IN": "Punjabi (India)",
13740 "pa-PK": "Punjabi (Pakistan)",
13741 "qu": "Quechua",
13742 "rm": "Rhaeto-Romanic",
13743 "ro": "Romanian",
13744 "ro-MO": "Romanian (Moldavia)",
13745 "ru": "Russian",
13746 "ru-MO": "Russian (Moldavia)",
13747 "sz": "Sami (Lappish)",
13748 "sg": "Sango",
13749 "sa": "Sanskrit",
13750 "sc": "Sardinian",
13751 "sd": "Sindhi",
13752 "si": "Singhalese",
13753 "sr": "Serbian",
13754 "sk": "Slovak",
13755 "sl": "Slovenian",
13756 "so": "Somani",
13757 "sb": "Sorbian",
13758 "es": "Spanish",
13759 "es-AR": "Spanish (Argentina)",
13760 "es-BO": "Spanish (Bolivia)",
13761 "es-CL": "Spanish (Chile)",
13762 "es-CO": "Spanish (Colombia)",
13763 "es-CR": "Spanish (Costa Rica)",
13764 "es-DO": "Spanish (Dominican Republic)",
13765 "es-EC": "Spanish (Ecuador)",
13766 "es-SV": "Spanish (El Salvador)",
13767 "es-GT": "Spanish (Guatemala)",
13768 "es-HN": "Spanish (Honduras)",
13769 "es-MX": "Spanish (Mexico)",
13770 "es-NI": "Spanish (Nicaragua)",
13771 "es-PA": "Spanish (Panama)",
13772 "es-PY": "Spanish (Paraguay)",
13773 "es-PE": "Spanish (Peru)",
13774 "es-PR": "Spanish (Puerto Rico)",
13775 "es-ES": "Spanish (Spain)",
13776 "es-UY": "Spanish (Uruguay)",
13777 "es-VE": "Spanish (Venezuela)",
13778 "sx": "Sutu",
13779 "sw": "Swahili",
13780 "sv": "Swedish",
13781 "sv-FI": "Swedish (Finland)",
13782 "sv-SV": "Swedish (Sweden)",
13783 "ta": "Tamil",
13784 "tt": "Tatar",
13785 "te": "Teluga",
13786 "th": "Thai",
13787 "tig": "Tigre",
13788 "ts": "Tsonga",
13789 "tn": "Tswana",
13790 "tr": "Turkish",
13791 "tk": "Turkmen",
13792 "uk": "Ukrainian",
13793 "hsb": "Upper Sorbian",
13794 "ur": "Urdu",
13795 "ve": "Venda",
13796 "vi": "Vietnamese",
13797 "vo": "Volapuk",
13798 "wa": "Walloon",
13799 "cy": "Welsh",
13800 "xh": "Xhosa",
13801 "ji": "Yiddish",
13802 "zu": "Zulu"
13803 };
13804
13805 if (this.internal.languageSettings === undefined) {
13806 this.internal.languageSettings = {};
13807 this.internal.languageSettings.isSubscribed = false;
13808 }
13809
13810 if (langCodes[langCode] !== undefined) {
13811 this.internal.languageSettings.languageCode = langCode;
13812
13813 if (this.internal.languageSettings.isSubscribed === false) {
13814 this.internal.events.subscribe("putCatalog", function () {
13815 this.internal.write("/Lang (" + this.internal.languageSettings.languageCode + ")");
13816 });
13817 this.internal.languageSettings.isSubscribed = true;
13818 }
13819 }
13820
13821 return this;
13822 };
13823 })(jsPDF.API);
13824
13825 /** @license
13826 * MIT license.
13827 * Copyright (c) 2012 Willow Systems Corporation, willow-systems.com
13828 * 2014 Diego Casorran, https://github.com/diegocr
13829 *
13830 *
13831 * ====================================================================
13832 */
13833
13834 /**
13835 * jsPDF split_text_to_size plugin
13836 *
13837 * @name split_text_to_size
13838 * @module
13839 */
13840 (function (API) {
13841 /**
13842 * Returns an array of length matching length of the 'word' string, with each
13843 * cell occupied by the width of the char in that position.
13844 *
13845 * @name getCharWidthsArray
13846 * @function
13847 * @param {string} text
13848 * @param {Object} options
13849 * @returns {Array}
13850 */
13851
13852 var getCharWidthsArray = API.getCharWidthsArray = function (text, options) {
13853 options = options || {};
13854 var activeFont = options.font || this.internal.getFont();
13855 var fontSize = options.fontSize || this.internal.getFontSize();
13856 var charSpace = options.charSpace || this.internal.getCharSpace();
13857 var widths = options.widths ? options.widths : activeFont.metadata.Unicode.widths;
13858 var widthsFractionOf = widths.fof ? widths.fof : 1;
13859 var kerning = options.kerning ? options.kerning : activeFont.metadata.Unicode.kerning;
13860 var kerningFractionOf = kerning.fof ? kerning.fof : 1;
13861 var i;
13862 var l;
13863 var char_code;
13864 var prior_char_code = 0; //for kerning
13865
13866 var default_char_width = widths[0] || widthsFractionOf;
13867 var output = [];
13868
13869 for (i = 0, l = text.length; i < l; i++) {
13870 char_code = text.charCodeAt(i);
13871
13872 if (typeof activeFont.metadata.widthOfString === "function") {
13873 output.push((activeFont.metadata.widthOfGlyph(activeFont.metadata.characterToGlyph(char_code)) + charSpace * (1000 / fontSize) || 0) / 1000);
13874 } else {
13875 output.push((widths[char_code] || default_char_width) / widthsFractionOf + (kerning[char_code] && kerning[char_code][prior_char_code] || 0) / kerningFractionOf);
13876 }
13877
13878 prior_char_code = char_code;
13879 }
13880
13881 return output;
13882 };
13883 /**
13884 * Calculate the sum of a number-array
13885 *
13886 * @name getArraySum
13887 * @public
13888 * @function
13889 * @param {Array} array Array of numbers
13890 * @returns {number}
13891 */
13892
13893
13894 var getArraySum = API.getArraySum = function (array) {
13895 var i = array.length,
13896 output = 0;
13897
13898 while (i) {
13899 i--;
13900 output += array[i];
13901 }
13902
13903 return output;
13904 };
13905 /**
13906 * Returns a widths of string in a given font, if the font size is set as 1 point.
13907 *
13908 * In other words, this is "proportional" value. For 1 unit of font size, the length
13909 * of the string will be that much.
13910 *
13911 * Multiply by font size to get actual width in *points*
13912 * Then divide by 72 to get inches or divide by (72/25.6) to get 'mm' etc.
13913 *
13914 * @name getStringUnitWidth
13915 * @public
13916 * @function
13917 * @param {string} text
13918 * @param {string} options
13919 * @returns {number} result
13920 */
13921
13922
13923 var getStringUnitWidth = API.getStringUnitWidth = function (text, options) {
13924 options = options || {};
13925 var fontSize = options.fontSize || this.internal.getFontSize();
13926 var font = options.font || this.internal.getFont();
13927 var charSpace = options.charSpace || this.internal.getCharSpace();
13928 var result = 0;
13929
13930 if (typeof font.metadata.widthOfString === "function") {
13931 result = font.metadata.widthOfString(text, fontSize, charSpace) / fontSize;
13932 } else {
13933 result = getArraySum(getCharWidthsArray.apply(this, arguments));
13934 }
13935
13936 return result;
13937 };
13938 /**
13939 returns array of lines
13940 */
13941
13942
13943 var splitLongWord = function splitLongWord(word, widths_array, firstLineMaxLen, maxLen) {
13944 var answer = []; // 1st, chop off the piece that can fit on the hanging line.
13945
13946 var i = 0,
13947 l = word.length,
13948 workingLen = 0;
13949
13950 while (i !== l && workingLen + widths_array[i] < firstLineMaxLen) {
13951 workingLen += widths_array[i];
13952 i++;
13953 } // this is first line.
13954
13955
13956 answer.push(word.slice(0, i)); // 2nd. Split the rest into maxLen pieces.
13957
13958 var startOfLine = i;
13959 workingLen = 0;
13960
13961 while (i !== l) {
13962 if (workingLen + widths_array[i] > maxLen) {
13963 answer.push(word.slice(startOfLine, i));
13964 workingLen = 0;
13965 startOfLine = i;
13966 }
13967
13968 workingLen += widths_array[i];
13969 i++;
13970 }
13971
13972 if (startOfLine !== i) {
13973 answer.push(word.slice(startOfLine, i));
13974 }
13975
13976 return answer;
13977 }; // Note, all sizing inputs for this function must be in "font measurement units"
13978 // By default, for PDF, it's "point".
13979
13980
13981 var splitParagraphIntoLines = function splitParagraphIntoLines(text, maxlen, options) {
13982 // at this time works only on Western scripts, ones with space char
13983 // separating the words. Feel free to expand.
13984 if (!options) {
13985 options = {};
13986 }
13987
13988 var line = [],
13989 lines = [line],
13990 line_length = options.textIndent || 0,
13991 separator_length = 0,
13992 current_word_length = 0,
13993 word,
13994 widths_array,
13995 words = text.split(' '),
13996 spaceCharWidth = getCharWidthsArray.apply(this, [' ', options])[0],
13997 i,
13998 l,
13999 tmp,
14000 lineIndent;
14001
14002 if (options.lineIndent === -1) {
14003 lineIndent = words[0].length + 2;
14004 } else {
14005 lineIndent = options.lineIndent || 0;
14006 }
14007
14008 if (lineIndent) {
14009 var pad = Array(lineIndent).join(" "),
14010 wrds = [];
14011 words.map(function (wrd) {
14012 wrd = wrd.split(/\s*\n/);
14013
14014 if (wrd.length > 1) {
14015 wrds = wrds.concat(wrd.map(function (wrd, idx) {
14016 return (idx && wrd.length ? "\n" : "") + wrd;
14017 }));
14018 } else {
14019 wrds.push(wrd[0]);
14020 }
14021 });
14022 words = wrds;
14023 lineIndent = getStringUnitWidth.apply(this, [pad, options]);
14024 }
14025
14026 for (i = 0, l = words.length; i < l; i++) {
14027 var force = 0;
14028 word = words[i];
14029
14030 if (lineIndent && word[0] == "\n") {
14031 word = word.substr(1);
14032 force = 1;
14033 }
14034
14035 widths_array = getCharWidthsArray.apply(this, [word, options]);
14036 current_word_length = getArraySum(widths_array);
14037
14038 if (line_length + separator_length + current_word_length > maxlen || force) {
14039 if (current_word_length > maxlen) {
14040 // this happens when you have space-less long URLs for example.
14041 // we just chop these to size. We do NOT insert hiphens
14042 tmp = splitLongWord.apply(this, [word, widths_array, maxlen - (line_length + separator_length), maxlen]); // first line we add to existing line object
14043
14044 line.push(tmp.shift()); // it's ok to have extra space indicator there
14045 // last line we make into new line object
14046
14047 line = [tmp.pop()]; // lines in the middle we apped to lines object as whole lines
14048
14049 while (tmp.length) {
14050 lines.push([tmp.shift()]); // single fragment occupies whole line
14051 }
14052
14053 current_word_length = getArraySum(widths_array.slice(word.length - (line[0] ? line[0].length : 0)));
14054 } else {
14055 // just put it on a new line
14056 line = [word];
14057 } // now we attach new line to lines
14058
14059
14060 lines.push(line);
14061 line_length = current_word_length + lineIndent;
14062 separator_length = spaceCharWidth;
14063 } else {
14064 line.push(word);
14065 line_length += separator_length + current_word_length;
14066 separator_length = spaceCharWidth;
14067 }
14068 }
14069
14070 if (lineIndent) {
14071 var postProcess = function postProcess(ln, idx) {
14072 return (idx ? pad : '') + ln.join(" ");
14073 };
14074 } else {
14075 var postProcess = function postProcess(ln) {
14076 return ln.join(" ");
14077 };
14078 }
14079
14080 return lines.map(postProcess);
14081 };
14082 /**
14083 * Splits a given string into an array of strings. Uses 'size' value
14084 * (in measurement units declared as default for the jsPDF instance)
14085 * and the font's "widths" and "Kerning" tables, where available, to
14086 * determine display length of a given string for a given font.
14087 *
14088 * We use character's 100% of unit size (height) as width when Width
14089 * table or other default width is not available.
14090 *
14091 * @name splitTextToSize
14092 * @public
14093 * @function
14094 * @param {string} text Unencoded, regular JavaScript (Unicode, UTF-16 / UCS-2) string.
14095 * @param {number} size Nominal number, measured in units default to this instance of jsPDF.
14096 * @param {Object} options Optional flags needed for chopper to do the right thing.
14097 * @returns {Array} array Array with strings chopped to size.
14098 */
14099
14100
14101 API.splitTextToSize = function (text, maxlen, options) {
14102
14103 options = options || {};
14104
14105 var fsize = options.fontSize || this.internal.getFontSize(),
14106 newOptions = function (options) {
14107 var widths = {
14108 0: 1
14109 },
14110 kerning = {};
14111
14112 if (!options.widths || !options.kerning) {
14113 var f = this.internal.getFont(options.fontName, options.fontStyle),
14114 encoding = 'Unicode'; // NOT UTF8, NOT UTF16BE/LE, NOT UCS2BE/LE
14115 // Actual JavaScript-native String's 16bit char codes used.
14116 // no multi-byte logic here
14117
14118 if (f.metadata[encoding]) {
14119 return {
14120 widths: f.metadata[encoding].widths || widths,
14121 kerning: f.metadata[encoding].kerning || kerning
14122 };
14123 } else {
14124 return {
14125 font: f.metadata,
14126 fontSize: this.internal.getFontSize(),
14127 charSpace: this.internal.getCharSpace()
14128 };
14129 }
14130 } else {
14131 return {
14132 widths: options.widths,
14133 kerning: options.kerning
14134 };
14135 } // then use default values
14136
14137
14138 return {
14139 widths: widths,
14140 kerning: kerning
14141 };
14142 }.call(this, options); // first we split on end-of-line chars
14143
14144
14145 var paragraphs;
14146
14147 if (Array.isArray(text)) {
14148 paragraphs = text;
14149 } else {
14150 paragraphs = text.split(/\r?\n/);
14151 } // now we convert size (max length of line) into "font size units"
14152 // at present time, the "font size unit" is always 'point'
14153 // 'proportional' means, "in proportion to font size"
14154
14155
14156 var fontUnit_maxLen = 1.0 * this.internal.scaleFactor * maxlen / fsize; // at this time, fsize is always in "points" regardless of the default measurement unit of the doc.
14157 // this may change in the future?
14158 // until then, proportional_maxlen is likely to be in 'points'
14159 // If first line is to be indented (shorter or longer) than maxLen
14160 // we indicate that by using CSS-style "text-indent" option.
14161 // here it's in font units too (which is likely 'points')
14162 // it can be negative (which makes the first line longer than maxLen)
14163
14164 newOptions.textIndent = options.textIndent ? options.textIndent * 1.0 * this.internal.scaleFactor / fsize : 0;
14165 newOptions.lineIndent = options.lineIndent;
14166 var i,
14167 l,
14168 output = [];
14169
14170 for (i = 0, l = paragraphs.length; i < l; i++) {
14171 output = output.concat(splitParagraphIntoLines.apply(this, [paragraphs[i], fontUnit_maxLen, newOptions]));
14172 }
14173
14174 return output;
14175 };
14176 })(jsPDF.API);
14177
14178 /** @license
14179 jsPDF standard_fonts_metrics plugin
14180 * Copyright (c) 2012 Willow Systems Corporation, willow-systems.com
14181 * MIT license.
14182 *
14183 * ====================================================================
14184 */
14185
14186 (function (API) {
14187 /*
14188 # reference (Python) versions of 'compress' and 'uncompress'
14189 # only 'uncompress' function is featured lower as JavaScript
14190 # if you want to unit test "roundtrip", just transcribe the reference
14191 # 'compress' function from Python into JavaScript
14192
14193 def compress(data):
14194
14195 keys = '0123456789abcdef'
14196 values = 'klmnopqrstuvwxyz'
14197 mapping = dict(zip(keys, values))
14198 vals = []
14199 for key in data.keys():
14200 value = data[key]
14201 try:
14202 keystring = hex(key)[2:]
14203 keystring = keystring[:-1] + mapping[keystring[-1:]]
14204 except:
14205 keystring = key.join(["'","'"])
14206 #print('Keystring is %s' % keystring)
14207
14208 try:
14209 if value < 0:
14210 valuestring = hex(value)[3:]
14211 numberprefix = '-'
14212 else:
14213 valuestring = hex(value)[2:]
14214 numberprefix = ''
14215 valuestring = numberprefix + valuestring[:-1] + mapping[valuestring[-1:]]
14216 except:
14217 if type(value) == dict:
14218 valuestring = compress(value)
14219 else:
14220 raise Exception("Don't know what to do with value type %s" % type(value))
14221
14222 vals.append(keystring+valuestring)
14223
14224 return '{' + ''.join(vals) + '}'
14225
14226 def uncompress(data):
14227
14228 decoded = '0123456789abcdef'
14229 encoded = 'klmnopqrstuvwxyz'
14230 mapping = dict(zip(encoded, decoded))
14231
14232 sign = +1
14233 stringmode = False
14234 stringparts = []
14235
14236 output = {}
14237
14238 activeobject = output
14239 parentchain = []
14240
14241 keyparts = ''
14242 valueparts = ''
14243
14244 key = None
14245
14246 ending = set(encoded)
14247
14248 i = 1
14249 l = len(data) - 1 # stripping starting, ending {}
14250 while i != l: # stripping {}
14251 # -, {, }, ' are special.
14252
14253 ch = data[i]
14254 i += 1
14255
14256 if ch == "'":
14257 if stringmode:
14258 # end of string mode
14259 stringmode = False
14260 key = ''.join(stringparts)
14261 else:
14262 # start of string mode
14263 stringmode = True
14264 stringparts = []
14265 elif stringmode == True:
14266 #print("Adding %s to stringpart" % ch)
14267 stringparts.append(ch)
14268
14269 elif ch == '{':
14270 # start of object
14271 parentchain.append( [activeobject, key] )
14272 activeobject = {}
14273 key = None
14274 #DEBUG = True
14275 elif ch == '}':
14276 # end of object
14277 parent, key = parentchain.pop()
14278 parent[key] = activeobject
14279 key = None
14280 activeobject = parent
14281 #DEBUG = False
14282
14283 elif ch == '-':
14284 sign = -1
14285 else:
14286 # must be number
14287 if key == None:
14288 #debug("In Key. It is '%s', ch is '%s'" % (keyparts, ch))
14289 if ch in ending:
14290 #debug("End of key")
14291 keyparts += mapping[ch]
14292 key = int(keyparts, 16) * sign
14293 sign = +1
14294 keyparts = ''
14295 else:
14296 keyparts += ch
14297 else:
14298 #debug("In value. It is '%s', ch is '%s'" % (valueparts, ch))
14299 if ch in ending:
14300 #debug("End of value")
14301 valueparts += mapping[ch]
14302 activeobject[key] = int(valueparts, 16) * sign
14303 sign = +1
14304 key = None
14305 valueparts = ''
14306 else:
14307 valueparts += ch
14308
14309 #debug(activeobject)
14310
14311 return output
14312
14313 */
14314
14315 /**
14316 Uncompresses data compressed into custom, base16-like format.
14317 @public
14318 @function
14319 @param
14320 @returns {Type}
14321 */
14322
14323 var uncompress = function uncompress(data) {
14324 var decoded = '0123456789abcdef',
14325 encoded = 'klmnopqrstuvwxyz',
14326 mapping = {};
14327
14328 for (var i = 0; i < encoded.length; i++) {
14329 mapping[encoded[i]] = decoded[i];
14330 }
14331
14332 var undef,
14333 output = {},
14334 sign = 1,
14335 stringparts // undef. will be [] in string mode
14336 ,
14337 activeobject = output,
14338 parentchain = [],
14339 parent_key_pair,
14340 keyparts = '',
14341 valueparts = '',
14342 key // undef. will be Truthy when Key is resolved.
14343 ,
14344 datalen = data.length - 1 // stripping ending }
14345 ,
14346 ch;
14347 i = 1; // stripping starting {
14348
14349 while (i != datalen) {
14350 // - { } ' are special.
14351 ch = data[i];
14352 i += 1;
14353
14354 if (ch == "'") {
14355 if (stringparts) {
14356 // end of string mode
14357 key = stringparts.join('');
14358 stringparts = undef;
14359 } else {
14360 // start of string mode
14361 stringparts = [];
14362 }
14363 } else if (stringparts) {
14364 stringparts.push(ch);
14365 } else if (ch == '{') {
14366 // start of object
14367 parentchain.push([activeobject, key]);
14368 activeobject = {};
14369 key = undef;
14370 } else if (ch == '}') {
14371 // end of object
14372 parent_key_pair = parentchain.pop();
14373 parent_key_pair[0][parent_key_pair[1]] = activeobject;
14374 key = undef;
14375 activeobject = parent_key_pair[0];
14376 } else if (ch == '-') {
14377 sign = -1;
14378 } else {
14379 // must be number
14380 if (key === undef) {
14381 if (mapping.hasOwnProperty(ch)) {
14382 keyparts += mapping[ch];
14383 key = parseInt(keyparts, 16) * sign;
14384 sign = +1;
14385 keyparts = '';
14386 } else {
14387 keyparts += ch;
14388 }
14389 } else {
14390 if (mapping.hasOwnProperty(ch)) {
14391 valueparts += mapping[ch];
14392 activeobject[key] = parseInt(valueparts, 16) * sign;
14393 sign = +1;
14394 key = undef;
14395 valueparts = '';
14396 } else {
14397 valueparts += ch;
14398 }
14399 }
14400 }
14401 } // end while
14402
14403
14404 return output;
14405 }; // encoding = 'Unicode'
14406 // NOT UTF8, NOT UTF16BE/LE, NOT UCS2BE/LE. NO clever BOM behavior
14407 // Actual 16bit char codes used.
14408 // no multi-byte logic here
14409 // Unicode characters to WinAnsiEncoding:
14410 // {402: 131, 8211: 150, 8212: 151, 8216: 145, 8217: 146, 8218: 130, 8220: 147, 8221: 148, 8222: 132, 8224: 134, 8225: 135, 8226: 149, 8230: 133, 8364: 128, 8240:137, 8249: 139, 8250: 155, 710: 136, 8482: 153, 338: 140, 339: 156, 732: 152, 352: 138, 353: 154, 376: 159, 381: 142, 382: 158}
14411 // as you can see, all Unicode chars are outside of 0-255 range. No char code conflicts.
14412 // this means that you can give Win cp1252 encoded strings to jsPDF for rendering directly
14413 // as well as give strings with some (supported by these fonts) Unicode characters and
14414 // these will be mapped to win cp1252
14415 // for example, you can send char code (cp1252) 0x80 or (unicode) 0x20AC, getting "Euro" glyph displayed in both cases.
14416
14417
14418 var encodingBlock = {
14419 'codePages': ['WinAnsiEncoding'],
14420 'WinAnsiEncoding': uncompress("{19m8n201n9q201o9r201s9l201t9m201u8m201w9n201x9o201y8o202k8q202l8r202m9p202q8p20aw8k203k8t203t8v203u9v2cq8s212m9t15m8w15n9w2dw9s16k8u16l9u17s9z17x8y17y9y}")
14421 },
14422 encodings = {
14423 'Unicode': {
14424 'Courier': encodingBlock,
14425 'Courier-Bold': encodingBlock,
14426 'Courier-BoldOblique': encodingBlock,
14427 'Courier-Oblique': encodingBlock,
14428 'Helvetica': encodingBlock,
14429 'Helvetica-Bold': encodingBlock,
14430 'Helvetica-BoldOblique': encodingBlock,
14431 'Helvetica-Oblique': encodingBlock,
14432 'Times-Roman': encodingBlock,
14433 'Times-Bold': encodingBlock,
14434 'Times-BoldItalic': encodingBlock,
14435 'Times-Italic': encodingBlock // , 'Symbol'
14436 // , 'ZapfDingbats'
14437
14438 }
14439 },
14440 fontMetrics = {
14441 'Unicode': {
14442 // all sizing numbers are n/fontMetricsFractionOf = one font size unit
14443 // this means that if fontMetricsFractionOf = 1000, and letter A's width is 476, it's
14444 // width is 476/1000 or 47.6% of its height (regardless of font size)
14445 // At this time this value applies to "widths" and "kerning" numbers.
14446 // char code 0 represents "default" (average) width - use it for chars missing in this table.
14447 // key 'fof' represents the "fontMetricsFractionOf" value
14448 'Courier-Oblique': uncompress("{'widths'{k3w'fof'6o}'kerning'{'fof'-6o}}"),
14449 'Times-BoldItalic': uncompress("{'widths'{k3o2q4ycx2r201n3m201o6o201s2l201t2l201u2l201w3m201x3m201y3m2k1t2l2r202m2n2n3m2o3m2p5n202q6o2r1w2s2l2t2l2u3m2v3t2w1t2x2l2y1t2z1w3k3m3l3m3m3m3n3m3o3m3p3m3q3m3r3m3s3m203t2l203u2l3v2l3w3t3x3t3y3t3z3m4k5n4l4m4m4m4n4m4o4s4p4m4q4m4r4s4s4y4t2r4u3m4v4m4w3x4x5t4y4s4z4s5k3x5l4s5m4m5n3r5o3x5p4s5q4m5r5t5s4m5t3x5u3x5v2l5w1w5x2l5y3t5z3m6k2l6l3m6m3m6n2w6o3m6p2w6q2l6r3m6s3r6t1w6u1w6v3m6w1w6x4y6y3r6z3m7k3m7l3m7m2r7n2r7o1w7p3r7q2w7r4m7s3m7t2w7u2r7v2n7w1q7x2n7y3t202l3mcl4mal2ram3man3mao3map3mar3mas2lat4uau1uav3maw3way4uaz2lbk2sbl3t'fof'6obo2lbp3tbq3mbr1tbs2lbu1ybv3mbz3mck4m202k3mcm4mcn4mco4mcp4mcq5ycr4mcs4mct4mcu4mcv4mcw2r2m3rcy2rcz2rdl4sdm4sdn4sdo4sdp4sdq4sds4sdt4sdu4sdv4sdw4sdz3mek3mel3mem3men3meo3mep3meq4ser2wes2wet2weu2wev2wew1wex1wey1wez1wfl3rfm3mfn3mfo3mfp3mfq3mfr3tfs3mft3rfu3rfv3rfw3rfz2w203k6o212m6o2dw2l2cq2l3t3m3u2l17s3x19m3m}'kerning'{cl{4qu5kt5qt5rs17ss5ts}201s{201ss}201t{cks4lscmscnscoscpscls2wu2yu201ts}201x{2wu2yu}2k{201ts}2w{4qx5kx5ou5qx5rs17su5tu}2x{17su5tu5ou}2y{4qx5kx5ou5qx5rs17ss5ts}'fof'-6ofn{17sw5tw5ou5qw5rs}7t{cksclscmscnscoscps4ls}3u{17su5tu5os5qs}3v{17su5tu5os5qs}7p{17su5tu}ck{4qu5kt5qt5rs17ss5ts}4l{4qu5kt5qt5rs17ss5ts}cm{4qu5kt5qt5rs17ss5ts}cn{4qu5kt5qt5rs17ss5ts}co{4qu5kt5qt5rs17ss5ts}cp{4qu5kt5qt5rs17ss5ts}6l{4qu5ou5qw5rt17su5tu}5q{ckuclucmucnucoucpu4lu}5r{ckuclucmucnucoucpu4lu}7q{cksclscmscnscoscps4ls}6p{4qu5ou5qw5rt17sw5tw}ek{4qu5ou5qw5rt17su5tu}el{4qu5ou5qw5rt17su5tu}em{4qu5ou5qw5rt17su5tu}en{4qu5ou5qw5rt17su5tu}eo{4qu5ou5qw5rt17su5tu}ep{4qu5ou5qw5rt17su5tu}es{17ss5ts5qs4qu}et{4qu5ou5qw5rt17sw5tw}eu{4qu5ou5qw5rt17ss5ts}ev{17ss5ts5qs4qu}6z{17sw5tw5ou5qw5rs}fm{17sw5tw5ou5qw5rs}7n{201ts}fo{17sw5tw5ou5qw5rs}fp{17sw5tw5ou5qw5rs}fq{17sw5tw5ou5qw5rs}7r{cksclscmscnscoscps4ls}fs{17sw5tw5ou5qw5rs}ft{17su5tu}fu{17su5tu}fv{17su5tu}fw{17su5tu}fz{cksclscmscnscoscps4ls}}}"),
14450 'Helvetica-Bold': uncompress("{'widths'{k3s2q4scx1w201n3r201o6o201s1w201t1w201u1w201w3m201x3m201y3m2k1w2l2l202m2n2n3r2o3r2p5t202q6o2r1s2s2l2t2l2u2r2v3u2w1w2x2l2y1w2z1w3k3r3l3r3m3r3n3r3o3r3p3r3q3r3r3r3s3r203t2l203u2l3v2l3w3u3x3u3y3u3z3x4k6l4l4s4m4s4n4s4o4s4p4m4q3x4r4y4s4s4t1w4u3r4v4s4w3x4x5n4y4s4z4y5k4m5l4y5m4s5n4m5o3x5p4s5q4m5r5y5s4m5t4m5u3x5v2l5w1w5x2l5y3u5z3r6k2l6l3r6m3x6n3r6o3x6p3r6q2l6r3x6s3x6t1w6u1w6v3r6w1w6x5t6y3x6z3x7k3x7l3x7m2r7n3r7o2l7p3x7q3r7r4y7s3r7t3r7u3m7v2r7w1w7x2r7y3u202l3rcl4sal2lam3ran3rao3rap3rar3ras2lat4tau2pav3raw3uay4taz2lbk2sbl3u'fof'6obo2lbp3xbq3rbr1wbs2lbu2obv3rbz3xck4s202k3rcm4scn4sco4scp4scq6ocr4scs4mct4mcu4mcv4mcw1w2m2zcy1wcz1wdl4sdm4ydn4ydo4ydp4ydq4yds4ydt4sdu4sdv4sdw4sdz3xek3rel3rem3ren3reo3rep3req5ter3res3ret3reu3rev3rew1wex1wey1wez1wfl3xfm3xfn3xfo3xfp3xfq3xfr3ufs3xft3xfu3xfv3xfw3xfz3r203k6o212m6o2dw2l2cq2l3t3r3u2l17s4m19m3r}'kerning'{cl{4qs5ku5ot5qs17sv5tv}201t{2ww4wy2yw}201w{2ks}201x{2ww4wy2yw}2k{201ts201xs}2w{7qs4qu5kw5os5qw5rs17su5tu7tsfzs}2x{5ow5qs}2y{7qs4qu5kw5os5qw5rs17su5tu7tsfzs}'fof'-6o7p{17su5tu5ot}ck{4qs5ku5ot5qs17sv5tv}4l{4qs5ku5ot5qs17sv5tv}cm{4qs5ku5ot5qs17sv5tv}cn{4qs5ku5ot5qs17sv5tv}co{4qs5ku5ot5qs17sv5tv}cp{4qs5ku5ot5qs17sv5tv}6l{17st5tt5os}17s{2kwclvcmvcnvcovcpv4lv4wwckv}5o{2kucltcmtcntcotcpt4lt4wtckt}5q{2ksclscmscnscoscps4ls4wvcks}5r{2ks4ws}5t{2kwclvcmvcnvcovcpv4lv4wwckv}eo{17st5tt5os}fu{17su5tu5ot}6p{17ss5ts}ek{17st5tt5os}el{17st5tt5os}em{17st5tt5os}en{17st5tt5os}6o{201ts}ep{17st5tt5os}es{17ss5ts}et{17ss5ts}eu{17ss5ts}ev{17ss5ts}6z{17su5tu5os5qt}fm{17su5tu5os5qt}fn{17su5tu5os5qt}fo{17su5tu5os5qt}fp{17su5tu5os5qt}fq{17su5tu5os5qt}fs{17su5tu5os5qt}ft{17su5tu5ot}7m{5os}fv{17su5tu5ot}fw{17su5tu5ot}}}"),
14451 'Courier': uncompress("{'widths'{k3w'fof'6o}'kerning'{'fof'-6o}}"),
14452 'Courier-BoldOblique': uncompress("{'widths'{k3w'fof'6o}'kerning'{'fof'-6o}}"),
14453 'Times-Bold': uncompress("{'widths'{k3q2q5ncx2r201n3m201o6o201s2l201t2l201u2l201w3m201x3m201y3m2k1t2l2l202m2n2n3m2o3m2p6o202q6o2r1w2s2l2t2l2u3m2v3t2w1t2x2l2y1t2z1w3k3m3l3m3m3m3n3m3o3m3p3m3q3m3r3m3s3m203t2l203u2l3v2l3w3t3x3t3y3t3z3m4k5x4l4s4m4m4n4s4o4s4p4m4q3x4r4y4s4y4t2r4u3m4v4y4w4m4x5y4y4s4z4y5k3x5l4y5m4s5n3r5o4m5p4s5q4s5r6o5s4s5t4s5u4m5v2l5w1w5x2l5y3u5z3m6k2l6l3m6m3r6n2w6o3r6p2w6q2l6r3m6s3r6t1w6u2l6v3r6w1w6x5n6y3r6z3m7k3r7l3r7m2w7n2r7o2l7p3r7q3m7r4s7s3m7t3m7u2w7v2r7w1q7x2r7y3o202l3mcl4sal2lam3man3mao3map3mar3mas2lat4uau1yav3maw3tay4uaz2lbk2sbl3t'fof'6obo2lbp3rbr1tbs2lbu2lbv3mbz3mck4s202k3mcm4scn4sco4scp4scq6ocr4scs4mct4mcu4mcv4mcw2r2m3rcy2rcz2rdl4sdm4ydn4ydo4ydp4ydq4yds4ydt4sdu4sdv4sdw4sdz3rek3mel3mem3men3meo3mep3meq4ser2wes2wet2weu2wev2wew1wex1wey1wez1wfl3rfm3mfn3mfo3mfp3mfq3mfr3tfs3mft3rfu3rfv3rfw3rfz3m203k6o212m6o2dw2l2cq2l3t3m3u2l17s4s19m3m}'kerning'{cl{4qt5ks5ot5qy5rw17sv5tv}201t{cks4lscmscnscoscpscls4wv}2k{201ts}2w{4qu5ku7mu5os5qx5ru17su5tu}2x{17su5tu5ou5qs}2y{4qv5kv7mu5ot5qz5ru17su5tu}'fof'-6o7t{cksclscmscnscoscps4ls}3u{17su5tu5os5qu}3v{17su5tu5os5qu}fu{17su5tu5ou5qu}7p{17su5tu5ou5qu}ck{4qt5ks5ot5qy5rw17sv5tv}4l{4qt5ks5ot5qy5rw17sv5tv}cm{4qt5ks5ot5qy5rw17sv5tv}cn{4qt5ks5ot5qy5rw17sv5tv}co{4qt5ks5ot5qy5rw17sv5tv}cp{4qt5ks5ot5qy5rw17sv5tv}6l{17st5tt5ou5qu}17s{ckuclucmucnucoucpu4lu4wu}5o{ckuclucmucnucoucpu4lu4wu}5q{ckzclzcmzcnzcozcpz4lz4wu}5r{ckxclxcmxcnxcoxcpx4lx4wu}5t{ckuclucmucnucoucpu4lu4wu}7q{ckuclucmucnucoucpu4lu}6p{17sw5tw5ou5qu}ek{17st5tt5qu}el{17st5tt5ou5qu}em{17st5tt5qu}en{17st5tt5qu}eo{17st5tt5qu}ep{17st5tt5ou5qu}es{17ss5ts5qu}et{17sw5tw5ou5qu}eu{17sw5tw5ou5qu}ev{17ss5ts5qu}6z{17sw5tw5ou5qu5rs}fm{17sw5tw5ou5qu5rs}fn{17sw5tw5ou5qu5rs}fo{17sw5tw5ou5qu5rs}fp{17sw5tw5ou5qu5rs}fq{17sw5tw5ou5qu5rs}7r{cktcltcmtcntcotcpt4lt5os}fs{17sw5tw5ou5qu5rs}ft{17su5tu5ou5qu}7m{5os}fv{17su5tu5ou5qu}fw{17su5tu5ou5qu}fz{cksclscmscnscoscps4ls}}}"),
14454 'Symbol': uncompress("{'widths'{k3uaw4r19m3m2k1t2l2l202m2y2n3m2p5n202q6o3k3m2s2l2t2l2v3r2w1t3m3m2y1t2z1wbk2sbl3r'fof'6o3n3m3o3m3p3m3q3m3r3m3s3m3t3m3u1w3v1w3w3r3x3r3y3r3z2wbp3t3l3m5v2l5x2l5z3m2q4yfr3r7v3k7w1o7x3k}'kerning'{'fof'-6o}}"),
14455 'Helvetica': uncompress("{'widths'{k3p2q4mcx1w201n3r201o6o201s1q201t1q201u1q201w2l201x2l201y2l2k1w2l1w202m2n2n3r2o3r2p5t202q6o2r1n2s2l2t2l2u2r2v3u2w1w2x2l2y1w2z1w3k3r3l3r3m3r3n3r3o3r3p3r3q3r3r3r3s3r203t2l203u2l3v1w3w3u3x3u3y3u3z3r4k6p4l4m4m4m4n4s4o4s4p4m4q3x4r4y4s4s4t1w4u3m4v4m4w3r4x5n4y4s4z4y5k4m5l4y5m4s5n4m5o3x5p4s5q4m5r5y5s4m5t4m5u3x5v1w5w1w5x1w5y2z5z3r6k2l6l3r6m3r6n3m6o3r6p3r6q1w6r3r6s3r6t1q6u1q6v3m6w1q6x5n6y3r6z3r7k3r7l3r7m2l7n3m7o1w7p3r7q3m7r4s7s3m7t3m7u3m7v2l7w1u7x2l7y3u202l3rcl4mal2lam3ran3rao3rap3rar3ras2lat4tau2pav3raw3uay4taz2lbk2sbl3u'fof'6obo2lbp3rbr1wbs2lbu2obv3rbz3xck4m202k3rcm4mcn4mco4mcp4mcq6ocr4scs4mct4mcu4mcv4mcw1w2m2ncy1wcz1wdl4sdm4ydn4ydo4ydp4ydq4yds4ydt4sdu4sdv4sdw4sdz3xek3rel3rem3ren3reo3rep3req5ter3mes3ret3reu3rev3rew1wex1wey1wez1wfl3rfm3rfn3rfo3rfp3rfq3rfr3ufs3xft3rfu3rfv3rfw3rfz3m203k6o212m6o2dw2l2cq2l3t3r3u1w17s4m19m3r}'kerning'{5q{4wv}cl{4qs5kw5ow5qs17sv5tv}201t{2wu4w1k2yu}201x{2wu4wy2yu}17s{2ktclucmucnu4otcpu4lu4wycoucku}2w{7qs4qz5k1m17sy5ow5qx5rsfsu5ty7tufzu}2x{17sy5ty5oy5qs}2y{7qs4qz5k1m17sy5ow5qx5rsfsu5ty7tufzu}'fof'-6o7p{17sv5tv5ow}ck{4qs5kw5ow5qs17sv5tv}4l{4qs5kw5ow5qs17sv5tv}cm{4qs5kw5ow5qs17sv5tv}cn{4qs5kw5ow5qs17sv5tv}co{4qs5kw5ow5qs17sv5tv}cp{4qs5kw5ow5qs17sv5tv}6l{17sy5ty5ow}do{17st5tt}4z{17st5tt}7s{fst}dm{17st5tt}dn{17st5tt}5o{ckwclwcmwcnwcowcpw4lw4wv}dp{17st5tt}dq{17st5tt}7t{5ow}ds{17st5tt}5t{2ktclucmucnu4otcpu4lu4wycoucku}fu{17sv5tv5ow}6p{17sy5ty5ow5qs}ek{17sy5ty5ow}el{17sy5ty5ow}em{17sy5ty5ow}en{5ty}eo{17sy5ty5ow}ep{17sy5ty5ow}es{17sy5ty5qs}et{17sy5ty5ow5qs}eu{17sy5ty5ow5qs}ev{17sy5ty5ow5qs}6z{17sy5ty5ow5qs}fm{17sy5ty5ow5qs}fn{17sy5ty5ow5qs}fo{17sy5ty5ow5qs}fp{17sy5ty5qs}fq{17sy5ty5ow5qs}7r{5ow}fs{17sy5ty5ow5qs}ft{17sv5tv5ow}7m{5ow}fv{17sv5tv5ow}fw{17sv5tv5ow}}}"),
14456 'Helvetica-BoldOblique': uncompress("{'widths'{k3s2q4scx1w201n3r201o6o201s1w201t1w201u1w201w3m201x3m201y3m2k1w2l2l202m2n2n3r2o3r2p5t202q6o2r1s2s2l2t2l2u2r2v3u2w1w2x2l2y1w2z1w3k3r3l3r3m3r3n3r3o3r3p3r3q3r3r3r3s3r203t2l203u2l3v2l3w3u3x3u3y3u3z3x4k6l4l4s4m4s4n4s4o4s4p4m4q3x4r4y4s4s4t1w4u3r4v4s4w3x4x5n4y4s4z4y5k4m5l4y5m4s5n4m5o3x5p4s5q4m5r5y5s4m5t4m5u3x5v2l5w1w5x2l5y3u5z3r6k2l6l3r6m3x6n3r6o3x6p3r6q2l6r3x6s3x6t1w6u1w6v3r6w1w6x5t6y3x6z3x7k3x7l3x7m2r7n3r7o2l7p3x7q3r7r4y7s3r7t3r7u3m7v2r7w1w7x2r7y3u202l3rcl4sal2lam3ran3rao3rap3rar3ras2lat4tau2pav3raw3uay4taz2lbk2sbl3u'fof'6obo2lbp3xbq3rbr1wbs2lbu2obv3rbz3xck4s202k3rcm4scn4sco4scp4scq6ocr4scs4mct4mcu4mcv4mcw1w2m2zcy1wcz1wdl4sdm4ydn4ydo4ydp4ydq4yds4ydt4sdu4sdv4sdw4sdz3xek3rel3rem3ren3reo3rep3req5ter3res3ret3reu3rev3rew1wex1wey1wez1wfl3xfm3xfn3xfo3xfp3xfq3xfr3ufs3xft3xfu3xfv3xfw3xfz3r203k6o212m6o2dw2l2cq2l3t3r3u2l17s4m19m3r}'kerning'{cl{4qs5ku5ot5qs17sv5tv}201t{2ww4wy2yw}201w{2ks}201x{2ww4wy2yw}2k{201ts201xs}2w{7qs4qu5kw5os5qw5rs17su5tu7tsfzs}2x{5ow5qs}2y{7qs4qu5kw5os5qw5rs17su5tu7tsfzs}'fof'-6o7p{17su5tu5ot}ck{4qs5ku5ot5qs17sv5tv}4l{4qs5ku5ot5qs17sv5tv}cm{4qs5ku5ot5qs17sv5tv}cn{4qs5ku5ot5qs17sv5tv}co{4qs5ku5ot5qs17sv5tv}cp{4qs5ku5ot5qs17sv5tv}6l{17st5tt5os}17s{2kwclvcmvcnvcovcpv4lv4wwckv}5o{2kucltcmtcntcotcpt4lt4wtckt}5q{2ksclscmscnscoscps4ls4wvcks}5r{2ks4ws}5t{2kwclvcmvcnvcovcpv4lv4wwckv}eo{17st5tt5os}fu{17su5tu5ot}6p{17ss5ts}ek{17st5tt5os}el{17st5tt5os}em{17st5tt5os}en{17st5tt5os}6o{201ts}ep{17st5tt5os}es{17ss5ts}et{17ss5ts}eu{17ss5ts}ev{17ss5ts}6z{17su5tu5os5qt}fm{17su5tu5os5qt}fn{17su5tu5os5qt}fo{17su5tu5os5qt}fp{17su5tu5os5qt}fq{17su5tu5os5qt}fs{17su5tu5os5qt}ft{17su5tu5ot}7m{5os}fv{17su5tu5ot}fw{17su5tu5ot}}}"),
14457 'ZapfDingbats': uncompress("{'widths'{k4u2k1w'fof'6o}'kerning'{'fof'-6o}}"),
14458 'Courier-Bold': uncompress("{'widths'{k3w'fof'6o}'kerning'{'fof'-6o}}"),
14459 'Times-Italic': uncompress("{'widths'{k3n2q4ycx2l201n3m201o5t201s2l201t2l201u2l201w3r201x3r201y3r2k1t2l2l202m2n2n3m2o3m2p5n202q5t2r1p2s2l2t2l2u3m2v4n2w1t2x2l2y1t2z1w3k3m3l3m3m3m3n3m3o3m3p3m3q3m3r3m3s3m203t2l203u2l3v2l3w4n3x4n3y4n3z3m4k5w4l3x4m3x4n4m4o4s4p3x4q3x4r4s4s4s4t2l4u2w4v4m4w3r4x5n4y4m4z4s5k3x5l4s5m3x5n3m5o3r5p4s5q3x5r5n5s3x5t3r5u3r5v2r5w1w5x2r5y2u5z3m6k2l6l3m6m3m6n2w6o3m6p2w6q1w6r3m6s3m6t1w6u1w6v2w6w1w6x4s6y3m6z3m7k3m7l3m7m2r7n2r7o1w7p3m7q2w7r4m7s2w7t2w7u2r7v2s7w1v7x2s7y3q202l3mcl3xal2ram3man3mao3map3mar3mas2lat4wau1vav3maw4nay4waz2lbk2sbl4n'fof'6obo2lbp3mbq3obr1tbs2lbu1zbv3mbz3mck3x202k3mcm3xcn3xco3xcp3xcq5tcr4mcs3xct3xcu3xcv3xcw2l2m2ucy2lcz2ldl4mdm4sdn4sdo4sdp4sdq4sds4sdt4sdu4sdv4sdw4sdz3mek3mel3mem3men3meo3mep3meq4mer2wes2wet2weu2wev2wew1wex1wey1wez1wfl3mfm3mfn3mfo3mfp3mfq3mfr4nfs3mft3mfu3mfv3mfw3mfz2w203k6o212m6m2dw2l2cq2l3t3m3u2l17s3r19m3m}'kerning'{cl{5kt4qw}201s{201sw}201t{201tw2wy2yy6q-t}201x{2wy2yy}2k{201tw}2w{7qs4qy7rs5ky7mw5os5qx5ru17su5tu}2x{17ss5ts5os}2y{7qs4qy7rs5ky7mw5os5qx5ru17su5tu}'fof'-6o6t{17ss5ts5qs}7t{5os}3v{5qs}7p{17su5tu5qs}ck{5kt4qw}4l{5kt4qw}cm{5kt4qw}cn{5kt4qw}co{5kt4qw}cp{5kt4qw}6l{4qs5ks5ou5qw5ru17su5tu}17s{2ks}5q{ckvclvcmvcnvcovcpv4lv}5r{ckuclucmucnucoucpu4lu}5t{2ks}6p{4qs5ks5ou5qw5ru17su5tu}ek{4qs5ks5ou5qw5ru17su5tu}el{4qs5ks5ou5qw5ru17su5tu}em{4qs5ks5ou5qw5ru17su5tu}en{4qs5ks5ou5qw5ru17su5tu}eo{4qs5ks5ou5qw5ru17su5tu}ep{4qs5ks5ou5qw5ru17su5tu}es{5ks5qs4qs}et{4qs5ks5ou5qw5ru17su5tu}eu{4qs5ks5qw5ru17su5tu}ev{5ks5qs4qs}ex{17ss5ts5qs}6z{4qv5ks5ou5qw5ru17su5tu}fm{4qv5ks5ou5qw5ru17su5tu}fn{4qv5ks5ou5qw5ru17su5tu}fo{4qv5ks5ou5qw5ru17su5tu}fp{4qv5ks5ou5qw5ru17su5tu}fq{4qv5ks5ou5qw5ru17su5tu}7r{5os}fs{4qv5ks5ou5qw5ru17su5tu}ft{17su5tu5qs}fu{17su5tu5qs}fv{17su5tu5qs}fw{17su5tu5qs}}}"),
14460 'Times-Roman': uncompress("{'widths'{k3n2q4ycx2l201n3m201o6o201s2l201t2l201u2l201w2w201x2w201y2w2k1t2l2l202m2n2n3m2o3m2p5n202q6o2r1m2s2l2t2l2u3m2v3s2w1t2x2l2y1t2z1w3k3m3l3m3m3m3n3m3o3m3p3m3q3m3r3m3s3m203t2l203u2l3v1w3w3s3x3s3y3s3z2w4k5w4l4s4m4m4n4m4o4s4p3x4q3r4r4s4s4s4t2l4u2r4v4s4w3x4x5t4y4s4z4s5k3r5l4s5m4m5n3r5o3x5p4s5q4s5r5y5s4s5t4s5u3x5v2l5w1w5x2l5y2z5z3m6k2l6l2w6m3m6n2w6o3m6p2w6q2l6r3m6s3m6t1w6u1w6v3m6w1w6x4y6y3m6z3m7k3m7l3m7m2l7n2r7o1w7p3m7q3m7r4s7s3m7t3m7u2w7v3k7w1o7x3k7y3q202l3mcl4sal2lam3man3mao3map3mar3mas2lat4wau1vav3maw3say4waz2lbk2sbl3s'fof'6obo2lbp3mbq2xbr1tbs2lbu1zbv3mbz2wck4s202k3mcm4scn4sco4scp4scq5tcr4mcs3xct3xcu3xcv3xcw2l2m2tcy2lcz2ldl4sdm4sdn4sdo4sdp4sdq4sds4sdt4sdu4sdv4sdw4sdz3mek2wel2wem2wen2weo2wep2weq4mer2wes2wet2weu2wev2wew1wex1wey1wez1wfl3mfm3mfn3mfo3mfp3mfq3mfr3sfs3mft3mfu3mfv3mfw3mfz3m203k6o212m6m2dw2l2cq2l3t3m3u1w17s4s19m3m}'kerning'{cl{4qs5ku17sw5ou5qy5rw201ss5tw201ws}201s{201ss}201t{ckw4lwcmwcnwcowcpwclw4wu201ts}2k{201ts}2w{4qs5kw5os5qx5ru17sx5tx}2x{17sw5tw5ou5qu}2y{4qs5kw5os5qx5ru17sx5tx}'fof'-6o7t{ckuclucmucnucoucpu4lu5os5rs}3u{17su5tu5qs}3v{17su5tu5qs}7p{17sw5tw5qs}ck{4qs5ku17sw5ou5qy5rw201ss5tw201ws}4l{4qs5ku17sw5ou5qy5rw201ss5tw201ws}cm{4qs5ku17sw5ou5qy5rw201ss5tw201ws}cn{4qs5ku17sw5ou5qy5rw201ss5tw201ws}co{4qs5ku17sw5ou5qy5rw201ss5tw201ws}cp{4qs5ku17sw5ou5qy5rw201ss5tw201ws}6l{17su5tu5os5qw5rs}17s{2ktclvcmvcnvcovcpv4lv4wuckv}5o{ckwclwcmwcnwcowcpw4lw4wu}5q{ckyclycmycnycoycpy4ly4wu5ms}5r{cktcltcmtcntcotcpt4lt4ws}5t{2ktclvcmvcnvcovcpv4lv4wuckv}7q{cksclscmscnscoscps4ls}6p{17su5tu5qw5rs}ek{5qs5rs}el{17su5tu5os5qw5rs}em{17su5tu5os5qs5rs}en{17su5qs5rs}eo{5qs5rs}ep{17su5tu5os5qw5rs}es{5qs}et{17su5tu5qw5rs}eu{17su5tu5qs5rs}ev{5qs}6z{17sv5tv5os5qx5rs}fm{5os5qt5rs}fn{17sv5tv5os5qx5rs}fo{17sv5tv5os5qx5rs}fp{5os5qt5rs}fq{5os5qt5rs}7r{ckuclucmucnucoucpu4lu5os}fs{17sv5tv5os5qx5rs}ft{17ss5ts5qs}fu{17sw5tw5qs}fv{17sw5tw5qs}fw{17ss5ts5qs}fz{ckuclucmucnucoucpu4lu5os5rs}}}"),
14461 'Helvetica-Oblique': uncompress("{'widths'{k3p2q4mcx1w201n3r201o6o201s1q201t1q201u1q201w2l201x2l201y2l2k1w2l1w202m2n2n3r2o3r2p5t202q6o2r1n2s2l2t2l2u2r2v3u2w1w2x2l2y1w2z1w3k3r3l3r3m3r3n3r3o3r3p3r3q3r3r3r3s3r203t2l203u2l3v1w3w3u3x3u3y3u3z3r4k6p4l4m4m4m4n4s4o4s4p4m4q3x4r4y4s4s4t1w4u3m4v4m4w3r4x5n4y4s4z4y5k4m5l4y5m4s5n4m5o3x5p4s5q4m5r5y5s4m5t4m5u3x5v1w5w1w5x1w5y2z5z3r6k2l6l3r6m3r6n3m6o3r6p3r6q1w6r3r6s3r6t1q6u1q6v3m6w1q6x5n6y3r6z3r7k3r7l3r7m2l7n3m7o1w7p3r7q3m7r4s7s3m7t3m7u3m7v2l7w1u7x2l7y3u202l3rcl4mal2lam3ran3rao3rap3rar3ras2lat4tau2pav3raw3uay4taz2lbk2sbl3u'fof'6obo2lbp3rbr1wbs2lbu2obv3rbz3xck4m202k3rcm4mcn4mco4mcp4mcq6ocr4scs4mct4mcu4mcv4mcw1w2m2ncy1wcz1wdl4sdm4ydn4ydo4ydp4ydq4yds4ydt4sdu4sdv4sdw4sdz3xek3rel3rem3ren3reo3rep3req5ter3mes3ret3reu3rev3rew1wex1wey1wez1wfl3rfm3rfn3rfo3rfp3rfq3rfr3ufs3xft3rfu3rfv3rfw3rfz3m203k6o212m6o2dw2l2cq2l3t3r3u1w17s4m19m3r}'kerning'{5q{4wv}cl{4qs5kw5ow5qs17sv5tv}201t{2wu4w1k2yu}201x{2wu4wy2yu}17s{2ktclucmucnu4otcpu4lu4wycoucku}2w{7qs4qz5k1m17sy5ow5qx5rsfsu5ty7tufzu}2x{17sy5ty5oy5qs}2y{7qs4qz5k1m17sy5ow5qx5rsfsu5ty7tufzu}'fof'-6o7p{17sv5tv5ow}ck{4qs5kw5ow5qs17sv5tv}4l{4qs5kw5ow5qs17sv5tv}cm{4qs5kw5ow5qs17sv5tv}cn{4qs5kw5ow5qs17sv5tv}co{4qs5kw5ow5qs17sv5tv}cp{4qs5kw5ow5qs17sv5tv}6l{17sy5ty5ow}do{17st5tt}4z{17st5tt}7s{fst}dm{17st5tt}dn{17st5tt}5o{ckwclwcmwcnwcowcpw4lw4wv}dp{17st5tt}dq{17st5tt}7t{5ow}ds{17st5tt}5t{2ktclucmucnu4otcpu4lu4wycoucku}fu{17sv5tv5ow}6p{17sy5ty5ow5qs}ek{17sy5ty5ow}el{17sy5ty5ow}em{17sy5ty5ow}en{5ty}eo{17sy5ty5ow}ep{17sy5ty5ow}es{17sy5ty5qs}et{17sy5ty5ow5qs}eu{17sy5ty5ow5qs}ev{17sy5ty5ow5qs}6z{17sy5ty5ow5qs}fm{17sy5ty5ow5qs}fn{17sy5ty5ow5qs}fo{17sy5ty5ow5qs}fp{17sy5ty5qs}fq{17sy5ty5ow5qs}7r{5ow}fs{17sy5ty5ow5qs}ft{17sv5tv5ow}7m{5ow}fv{17sv5tv5ow}fw{17sv5tv5ow}}}")
14462 }
14463 };
14464 /*
14465 This event handler is fired when a new jsPDF object is initialized
14466 This event handler appends metrics data to standard fonts within
14467 that jsPDF instance. The metrics are mapped over Unicode character
14468 codes, NOT CIDs or other codes matching the StandardEncoding table of the
14469 standard PDF fonts.
14470 Future:
14471 Also included is the encoding maping table, converting Unicode (UCS-2, UTF-16)
14472 char codes to StandardEncoding character codes. The encoding table is to be used
14473 somewhere around "pdfEscape" call.
14474 */
14475
14476 API.events.push(['addFont', function (data) {
14477 var font = data.font;
14478 var metrics,
14479 unicode_section,
14480 encoding = 'Unicode',
14481 encodingBlock;
14482 metrics = fontMetrics[encoding][font.postScriptName];
14483
14484 if (metrics) {
14485 if (font.metadata[encoding]) {
14486 unicode_section = font.metadata[encoding];
14487 } else {
14488 unicode_section = font.metadata[encoding] = {};
14489 }
14490
14491 unicode_section.widths = metrics.widths;
14492 unicode_section.kerning = metrics.kerning;
14493 }
14494
14495 encodingBlock = encodings[encoding][font.postScriptName];
14496
14497 if (encodingBlock) {
14498 if (font.metadata[encoding]) {
14499 unicode_section = font.metadata[encoding];
14500 } else {
14501 unicode_section = font.metadata[encoding] = {};
14502 }
14503
14504 unicode_section.encoding = encodingBlock;
14505
14506 if (encodingBlock.codePages && encodingBlock.codePages.length) {
14507 font.encoding = encodingBlock.codePages[0];
14508 }
14509 }
14510 }]); // end of adding event handler
14511 })(jsPDF.API);
14512
14513 /**
14514 * @license
14515 * Licensed under the MIT License.
14516 * http://opensource.org/licenses/mit-license
14517 */
14518
14519 /**
14520 * @name ttfsupport
14521 * @module
14522 */
14523 (function (jsPDF, global) {
14524
14525 jsPDF.API.events.push(['addFont', function (data) {
14526 var font = data.font;
14527 var instance = data.instance;
14528
14529 if (typeof instance !== "undefined" && instance.existsFileInVFS(font.postScriptName)) {
14530 var file = instance.getFileFromVFS(font.postScriptName);
14531
14532 if (typeof file !== "string") {
14533 throw new Error("Font is not stored as string-data in vFS, import fonts or remove declaration doc.addFont('" + font.postScriptName + "').");
14534 }
14535
14536 font.metadata = jsPDF.API.TTFFont.open(font.postScriptName, font.fontName, file, font.encoding);
14537 font.metadata.Unicode = font.metadata.Unicode || {
14538 encoding: {},
14539 kerning: {},
14540 widths: []
14541 };
14542 font.metadata.glyIdsUsed = [0];
14543 } else if (font.isStandardFont === false) {
14544 throw new Error("Font does not exist in vFS, import fonts or remove declaration doc.addFont('" + font.postScriptName + "').");
14545 }
14546 }]); // end of adding event handler
14547 })(jsPDF, typeof self !== "undefined" && self || typeof global !== "undefined" && global || typeof window !== "undefined" && window || Function("return this")());
14548
14549 /** @license
14550 * Copyright (c) 2012 Willow Systems Corporation, willow-systems.com
14551 *
14552 *
14553 * ====================================================================
14554 */
14555
14556 (function (jsPDFAPI) {
14557 /**
14558 * Parses SVG XML and converts only some of the SVG elements into
14559 * PDF elements.
14560 *
14561 * Supports:
14562 * paths
14563 *
14564 * @name addSvg
14565 * @public
14566 * @function
14567 * @param {string} SVG-Data as Text
14568 * @param {number} x Coordinate (in units declared at inception of PDF document) against left edge of the page
14569 * @param {number} y Coordinate (in units declared at inception of PDF document) against upper edge of the page
14570 * @param {number} width of SVG (in units declared at inception of PDF document)
14571 * @param {number} height of SVG (in units declared at inception of PDF document)
14572 * @returns {Object} jsPDF-instance
14573 */
14574
14575 jsPDFAPI.addSvg = function (svgtext, x, y, w, h) {
14576 // 'this' is _jsPDF object returned when jsPDF is inited (new jsPDF())
14577 var undef;
14578
14579 if (x === undef || y === undef) {
14580 throw new Error("addSVG needs values for 'x' and 'y'");
14581 }
14582
14583 function InjectCSS(cssbody, document) {
14584 var styletag = document.createElement('style');
14585 styletag.type = 'text/css';
14586
14587 if (styletag.styleSheet) {
14588 // ie
14589 styletag.styleSheet.cssText = cssbody;
14590 } else {
14591 // others
14592 styletag.appendChild(document.createTextNode(cssbody));
14593 }
14594
14595 document.getElementsByTagName("head")[0].appendChild(styletag);
14596 }
14597
14598 function createWorkerNode(document) {
14599 var frameID = 'childframe' // Date.now().toString() + '_' + (Math.random() * 100).toString()
14600 ,
14601 frame = document.createElement('iframe');
14602 InjectCSS('.jsPDF_sillysvg_iframe {display:none;position:absolute;}', document);
14603 frame.name = frameID;
14604 frame.setAttribute("width", 0);
14605 frame.setAttribute("height", 0);
14606 frame.setAttribute("frameborder", "0");
14607 frame.setAttribute("scrolling", "no");
14608 frame.setAttribute("seamless", "seamless");
14609 frame.setAttribute("class", "jsPDF_sillysvg_iframe");
14610 document.body.appendChild(frame);
14611 return frame;
14612 }
14613
14614 function attachSVGToWorkerNode(svgtext, frame) {
14615 var framedoc = (frame.contentWindow || frame.contentDocument).document;
14616 framedoc.write(svgtext);
14617 framedoc.close();
14618 return framedoc.getElementsByTagName('svg')[0];
14619 }
14620
14621 function convertPathToPDFLinesArgs(path) {
14622 // - starting coordinate pair
14623 // - array of arrays of vector shifts (2-len for line, 6 len for bezier)
14624 // - scale array [horizontal, vertical] ratios
14625 // - style (stroke, fill, both)
14626
14627 var x = parseFloat(path[1]),
14628 y = parseFloat(path[2]),
14629 vectors = [],
14630 position = 3,
14631 len = path.length;
14632
14633 while (position < len) {
14634 if (path[position] === 'c') {
14635 vectors.push([parseFloat(path[position + 1]), parseFloat(path[position + 2]), parseFloat(path[position + 3]), parseFloat(path[position + 4]), parseFloat(path[position + 5]), parseFloat(path[position + 6])]);
14636 position += 7;
14637 } else if (path[position] === 'l') {
14638 vectors.push([parseFloat(path[position + 1]), parseFloat(path[position + 2])]);
14639 position += 3;
14640 } else {
14641 position += 1;
14642 }
14643 }
14644
14645 return [x, y, vectors];
14646 }
14647
14648 var workernode = createWorkerNode(document),
14649 svgnode = attachSVGToWorkerNode(svgtext, workernode),
14650 scale = [1, 1],
14651 svgw = parseFloat(svgnode.getAttribute('width')),
14652 svgh = parseFloat(svgnode.getAttribute('height'));
14653
14654 if (svgw && svgh) {
14655 // setting both w and h makes image stretch to size.
14656 // this may distort the image, but fits your demanded size
14657 if (w && h) {
14658 scale = [w / svgw, h / svgh];
14659 } // if only one is set, that value is set as max and SVG
14660 // is scaled proportionately.
14661 else if (w) {
14662 scale = [w / svgw, w / svgw];
14663 } else if (h) {
14664 scale = [h / svgh, h / svgh];
14665 }
14666 }
14667
14668 var i,
14669 l,
14670 tmp,
14671 linesargs,
14672 items = svgnode.childNodes;
14673
14674 for (i = 0, l = items.length; i < l; i++) {
14675 tmp = items[i];
14676
14677 if (tmp.tagName && tmp.tagName.toUpperCase() === 'PATH') {
14678 linesargs = convertPathToPDFLinesArgs(tmp.getAttribute("d").split(' ')); // path start x coordinate
14679
14680 linesargs[0] = linesargs[0] * scale[0] + x; // where x is upper left X of image
14681 // path start y coordinate
14682
14683 linesargs[1] = linesargs[1] * scale[1] + y; // where y is upper left Y of image
14684 // the rest of lines are vectors. these will adjust with scale value auto.
14685
14686 this.lines.call(this, linesargs[2] // lines
14687 , linesargs[0] // starting x
14688 , linesargs[1] // starting y
14689 , scale);
14690 }
14691 } // clean up
14692 // workernode.parentNode.removeChild(workernode)
14693
14694
14695 return this;
14696 }; //fallback
14697
14698
14699 jsPDFAPI.addSVG = jsPDFAPI.addSvg;
14700 /**
14701 * Parses SVG XML and saves it as image into the PDF.
14702 *
14703 * Depends on canvas-element and canvg
14704 *
14705 * @name addSvgAsImage
14706 * @public
14707 * @function
14708 * @param {string} SVG-Data as Text
14709 * @param {number} x Coordinate (in units declared at inception of PDF document) against left edge of the page
14710 * @param {number} y Coordinate (in units declared at inception of PDF document) against upper edge of the page
14711 * @param {number} width of SVG-Image (in units declared at inception of PDF document)
14712 * @param {number} height of SVG-Image (in units declared at inception of PDF document)
14713 * @param {string} alias of SVG-Image (if used multiple times)
14714 * @param {string} compression of the generated JPEG, can have the values 'NONE', 'FAST', 'MEDIUM' and 'SLOW'
14715 * @param {number} rotation of the image in degrees (0-359)
14716 *
14717 * @returns jsPDF jsPDF-instance
14718 */
14719
14720 jsPDFAPI.addSvgAsImage = function (svg, x, y, w, h, alias, compression, rotation) {
14721 if (isNaN(x) || isNaN(y)) {
14722 console.error('jsPDF.addSvgAsImage: Invalid coordinates', arguments);
14723 throw new Error('Invalid coordinates passed to jsPDF.addSvgAsImage');
14724 }
14725
14726 if (isNaN(w) || isNaN(h)) {
14727 console.error('jsPDF.addSvgAsImage: Invalid measurements', arguments);
14728 throw new Error('Invalid measurements (width and/or height) passed to jsPDF.addSvgAsImage');
14729 }
14730
14731 var canvas = document.createElement('canvas');
14732 canvas.width = w;
14733 canvas.height = h;
14734 var ctx = canvas.getContext('2d');
14735 ctx.fillStyle = '#fff'; /// set white fill style
14736
14737 ctx.fillRect(0, 0, canvas.width, canvas.height); //load a svg snippet in the canvas with id = 'drawingArea'
14738
14739 canvg(canvas, svg, {
14740 ignoreMouse: true,
14741 ignoreAnimation: true,
14742 ignoreDimensions: true,
14743 ignoreClear: true
14744 });
14745 this.addImage(canvas.toDataURL("image/jpeg", 1.0), x, y, w, h, compression, rotation);
14746 return this;
14747 };
14748 })(jsPDF.API);
14749
14750 /**
14751 * @license
14752 * ====================================================================
14753 * Copyright (c) 2013 Eduardo Menezes de Morais, eduardo.morais@usp.br
14754 *
14755 *
14756 * ====================================================================
14757 */
14758
14759 /**
14760 * jsPDF total_pages plugin
14761 * @name total_pages
14762 * @module
14763 */
14764 (function (jsPDFAPI) {
14765 /**
14766 * @name putTotalPages
14767 * @function
14768 * @param {string} pageExpression Regular Expression
14769 * @returns {jsPDF} jsPDF-instance
14770 */
14771
14772 jsPDFAPI.putTotalPages = function (pageExpression) {
14773
14774 var replaceExpression;
14775 var totalNumberOfPages = 0;
14776
14777 if (parseInt(this.internal.getFont().id.substr(1), 10) < 15) {
14778 replaceExpression = new RegExp(pageExpression, 'g');
14779 totalNumberOfPages = this.internal.getNumberOfPages();
14780 } else {
14781 replaceExpression = new RegExp(this.pdfEscape16(pageExpression, this.internal.getFont()), 'g');
14782 totalNumberOfPages = this.pdfEscape16(this.internal.getNumberOfPages() + '', this.internal.getFont());
14783 }
14784
14785 for (var n = 1; n <= this.internal.getNumberOfPages(); n++) {
14786 for (var i = 0; i < this.internal.pages[n].length; i++) {
14787 this.internal.pages[n][i] = this.internal.pages[n][i].replace(replaceExpression, totalNumberOfPages);
14788 }
14789 }
14790
14791 return this;
14792 };
14793 })(jsPDF.API);
14794
14795 /**
14796 * jsPDF viewerPreferences Plugin
14797 * @author Aras Abbasi (github.com/arasabbasi)
14798 * Licensed under the MIT License.
14799 * http://opensource.org/licenses/mit-license
14800 */
14801
14802 /**
14803 * Adds the ability to set ViewerPreferences and by thus
14804 * controlling the way the document is to be presented on the
14805 * screen or in print.
14806 * @name viewerpreferences
14807 * @module
14808 */
14809 (function (jsPDFAPI) {
14810 /**
14811 * Set the ViewerPreferences of the generated PDF
14812 *
14813 * @name viewerPreferences
14814 * @function
14815 * @public
14816 * @param {Object} options Array with the ViewerPreferences<br />
14817 * Example: doc.viewerPreferences({"FitWindow":true});<br />
14818 * <br />
14819 * You can set following preferences:<br />
14820 * <br/>
14821 * <b>HideToolbar</b> <i>(boolean)</i><br />
14822 * Default value: false<br />
14823 * <br />
14824 * <b>HideMenubar</b> <i>(boolean)</i><br />
14825 * Default value: false.<br />
14826 * <br />
14827 * <b>HideWindowUI</b> <i>(boolean)</i><br />
14828 * Default value: false.<br />
14829 * <br />
14830 * <b>FitWindow</b> <i>(boolean)</i><br />
14831 * Default value: false.<br />
14832 * <br />
14833 * <b>CenterWindow</b> <i>(boolean)</i><br />
14834 * Default value: false<br />
14835 * <br />
14836 * <b>DisplayDocTitle</b> <i>(boolean)</i><br />
14837 * Default value: false.<br />
14838 * <br />
14839 * <b>NonFullScreenPageMode</b> <i>(string)</i><br />
14840 * Possible values: UseNone, UseOutlines, UseThumbs, UseOC<br />
14841 * Default value: UseNone<br/>
14842 * <br />
14843 * <b>Direction</b> <i>(string)</i><br />
14844 * Possible values: L2R, R2L<br />
14845 * Default value: L2R.<br />
14846 * <br />
14847 * <b>ViewArea</b> <i>(string)</i><br />
14848 * Possible values: MediaBox, CropBox, TrimBox, BleedBox, ArtBox<br />
14849 * Default value: CropBox.<br />
14850 * <br />
14851 * <b>ViewClip</b> <i>(string)</i><br />
14852 * Possible values: MediaBox, CropBox, TrimBox, BleedBox, ArtBox<br />
14853 * Default value: CropBox<br />
14854 * <br />
14855 * <b>PrintArea</b> <i>(string)</i><br />
14856 * Possible values: MediaBox, CropBox, TrimBox, BleedBox, ArtBox<br />
14857 * Default value: CropBox<br />
14858 * <br />
14859 * <b>PrintClip</b> <i>(string)</i><br />
14860 * Possible values: MediaBox, CropBox, TrimBox, BleedBox, ArtBox<br />
14861 * Default value: CropBox.<br />
14862 * <br />
14863 * <b>PrintScaling</b> <i>(string)</i><br />
14864 * Possible values: AppDefault, None<br />
14865 * Default value: AppDefault.<br />
14866 * <br />
14867 * <b>Duplex</b> <i>(string)</i><br />
14868 * Possible values: Simplex, DuplexFlipLongEdge, DuplexFlipShortEdge
14869 * Default value: none<br />
14870 * <br />
14871 * <b>PickTrayByPDFSize</b> <i>(boolean)</i><br />
14872 * Default value: false<br />
14873 * <br />
14874 * <b>PrintPageRange</b> <i>(Array)</i><br />
14875 * Example: [[1,5], [7,9]]<br />
14876 * Default value: as defined by PDF viewer application<br />
14877 * <br />
14878 * <b>NumCopies</b> <i>(Number)</i><br />
14879 * Possible values: 1, 2, 3, 4, 5<br />
14880 * Default value: 1<br />
14881 * <br />
14882 * For more information see the PDF Reference, sixth edition on Page 577
14883 * @param {boolean} doReset True to reset the settings
14884 * @function
14885 * @returns jsPDF jsPDF-instance
14886 * @example
14887 * var doc = new jsPDF()
14888 * doc.text('This is a test', 10, 10)
14889 * doc.viewerPreferences({'FitWindow': true}, true)
14890 * doc.save("viewerPreferences.pdf")
14891 *
14892 * // Example printing 10 copies, using cropbox, and hiding UI.
14893 * doc.viewerPreferences({
14894 * 'HideWindowUI': true,
14895 * 'PrintArea': 'CropBox',
14896 * 'NumCopies': 10
14897 * })
14898 */
14899
14900 jsPDFAPI.viewerPreferences = function (options, doReset) {
14901 options = options || {};
14902 doReset = doReset || false;
14903 var configuration;
14904 var configurationTemplate = {
14905 "HideToolbar": {
14906 defaultValue: false,
14907 value: false,
14908 type: "boolean",
14909 explicitSet: false,
14910 valueSet: [true, false],
14911 pdfVersion: 1.3
14912 },
14913 "HideMenubar": {
14914 defaultValue: false,
14915 value: false,
14916 type: "boolean",
14917 explicitSet: false,
14918 valueSet: [true, false],
14919 pdfVersion: 1.3
14920 },
14921 "HideWindowUI": {
14922 defaultValue: false,
14923 value: false,
14924 type: "boolean",
14925 explicitSet: false,
14926 valueSet: [true, false],
14927 pdfVersion: 1.3
14928 },
14929 "FitWindow": {
14930 defaultValue: false,
14931 value: false,
14932 type: "boolean",
14933 explicitSet: false,
14934 valueSet: [true, false],
14935 pdfVersion: 1.3
14936 },
14937 "CenterWindow": {
14938 defaultValue: false,
14939 value: false,
14940 type: "boolean",
14941 explicitSet: false,
14942 valueSet: [true, false],
14943 pdfVersion: 1.3
14944 },
14945 "DisplayDocTitle": {
14946 defaultValue: false,
14947 value: false,
14948 type: "boolean",
14949 explicitSet: false,
14950 valueSet: [true, false],
14951 pdfVersion: 1.4
14952 },
14953 "NonFullScreenPageMode": {
14954 defaultValue: "UseNone",
14955 value: "UseNone",
14956 type: "name",
14957 explicitSet: false,
14958 valueSet: ["UseNone", "UseOutlines", "UseThumbs", "UseOC"],
14959 pdfVersion: 1.3
14960 },
14961 "Direction": {
14962 defaultValue: "L2R",
14963 value: "L2R",
14964 type: "name",
14965 explicitSet: false,
14966 valueSet: ["L2R", "R2L"],
14967 pdfVersion: 1.3
14968 },
14969 "ViewArea": {
14970 defaultValue: "CropBox",
14971 value: "CropBox",
14972 type: "name",
14973 explicitSet: false,
14974 valueSet: ["MediaBox", "CropBox", "TrimBox", "BleedBox", "ArtBox"],
14975 pdfVersion: 1.4
14976 },
14977 "ViewClip": {
14978 defaultValue: "CropBox",
14979 value: "CropBox",
14980 type: "name",
14981 explicitSet: false,
14982 valueSet: ["MediaBox", "CropBox", "TrimBox", "BleedBox", "ArtBox"],
14983 pdfVersion: 1.4
14984 },
14985 "PrintArea": {
14986 defaultValue: "CropBox",
14987 value: "CropBox",
14988 type: "name",
14989 explicitSet: false,
14990 valueSet: ["MediaBox", "CropBox", "TrimBox", "BleedBox", "ArtBox"],
14991 pdfVersion: 1.4
14992 },
14993 "PrintClip": {
14994 defaultValue: "CropBox",
14995 value: "CropBox",
14996 type: "name",
14997 explicitSet: false,
14998 valueSet: ["MediaBox", "CropBox", "TrimBox", "BleedBox", "ArtBox"],
14999 pdfVersion: 1.4
15000 },
15001 "PrintScaling": {
15002 defaultValue: "AppDefault",
15003 value: "AppDefault",
15004 type: "name",
15005 explicitSet: false,
15006 valueSet: ["AppDefault", "None"],
15007 pdfVersion: 1.6
15008 },
15009 "Duplex": {
15010 defaultValue: "",
15011 value: "none",
15012 type: "name",
15013 explicitSet: false,
15014 valueSet: ["Simplex", "DuplexFlipShortEdge", "DuplexFlipLongEdge", "none"],
15015 pdfVersion: 1.7
15016 },
15017 "PickTrayByPDFSize": {
15018 defaultValue: false,
15019 value: false,
15020 type: "boolean",
15021 explicitSet: false,
15022 valueSet: [true, false],
15023 pdfVersion: 1.7
15024 },
15025 "PrintPageRange": {
15026 defaultValue: "",
15027 value: "",
15028 type: "array",
15029 explicitSet: false,
15030 valueSet: null,
15031 pdfVersion: 1.7
15032 },
15033 "NumCopies": {
15034 defaultValue: 1,
15035 value: 1,
15036 type: "integer",
15037 explicitSet: false,
15038 valueSet: null,
15039 pdfVersion: 1.7
15040 }
15041 };
15042 var configurationKeys = Object.keys(configurationTemplate);
15043 var rangeArray = [];
15044 var i = 0;
15045 var j = 0;
15046 var k = 0;
15047 var isValid = true;
15048 var method;
15049 var value;
15050
15051 function arrayContainsElement(array, element) {
15052 var iterator;
15053 var result = false;
15054
15055 for (iterator = 0; iterator < array.length; iterator += 1) {
15056 if (array[iterator] === element) {
15057 result = true;
15058 }
15059 }
15060
15061 return result;
15062 }
15063
15064 if (this.internal.viewerpreferences === undefined) {
15065 this.internal.viewerpreferences = {};
15066 this.internal.viewerpreferences.configuration = JSON.parse(JSON.stringify(configurationTemplate));
15067 this.internal.viewerpreferences.isSubscribed = false;
15068 }
15069
15070 configuration = this.internal.viewerpreferences.configuration;
15071
15072 if (options === "reset" || doReset === true) {
15073 var len = configurationKeys.length;
15074
15075 for (k = 0; k < len; k += 1) {
15076 configuration[configurationKeys[k]].value = configuration[configurationKeys[k]].defaultValue;
15077 configuration[configurationKeys[k]].explicitSet = false;
15078 }
15079 }
15080
15081 if (_typeof(options) === "object") {
15082 for (method in options) {
15083 value = options[method];
15084
15085 if (arrayContainsElement(configurationKeys, method) && value !== undefined) {
15086 if (configuration[method].type === "boolean" && typeof value === "boolean") {
15087 configuration[method].value = value;
15088 } else if (configuration[method].type === "name" && arrayContainsElement(configuration[method].valueSet, value)) {
15089 configuration[method].value = value;
15090 } else if (configuration[method].type === "integer" && Number.isInteger(value)) {
15091 configuration[method].value = value;
15092 } else if (configuration[method].type === "array") {
15093 for (i = 0; i < value.length; i += 1) {
15094 isValid = true;
15095
15096 if (value[i].length === 1 && typeof value[i][0] === "number") {
15097 rangeArray.push(String(value[i] - 1));
15098 } else if (value[i].length > 1) {
15099 for (j = 0; j < value[i].length; j += 1) {
15100 if (typeof value[i][j] !== "number") {
15101 isValid = false;
15102 }
15103 }
15104
15105 if (isValid === true) {
15106 rangeArray.push([value[i][0] - 1, value[i][1] - 1].join(" "));
15107 }
15108 }
15109 }
15110
15111 configuration[method].value = "[" + rangeArray.join(" ") + "]";
15112 } else {
15113 configuration[method].value = configuration[method].defaultValue;
15114 }
15115
15116 configuration[method].explicitSet = true;
15117 }
15118 }
15119 }
15120
15121 if (this.internal.viewerpreferences.isSubscribed === false) {
15122 this.internal.events.subscribe("putCatalog", function () {
15123 var pdfDict = [];
15124 var vPref;
15125
15126 for (vPref in configuration) {
15127 if (configuration[vPref].explicitSet === true) {
15128 if (configuration[vPref].type === "name") {
15129 pdfDict.push("/" + vPref + " /" + configuration[vPref].value);
15130 } else {
15131 pdfDict.push("/" + vPref + " " + configuration[vPref].value);
15132 }
15133 }
15134 }
15135
15136 if (pdfDict.length !== 0) {
15137 this.internal.write("/ViewerPreferences\n<<\n" + pdfDict.join("\n") + "\n>>");
15138 }
15139 });
15140 this.internal.viewerpreferences.isSubscribed = true;
15141 }
15142
15143 this.internal.viewerpreferences.configuration = configuration;
15144 return this;
15145 };
15146 })(jsPDF.API);
15147
15148 /** ====================================================================
15149 * jsPDF XMP metadata plugin
15150 * Copyright (c) 2016 Jussi Utunen, u-jussi@suomi24.fi
15151 *
15152 *
15153 * ====================================================================
15154 */
15155
15156 /*global jsPDF */
15157
15158 /**
15159 * @name xmp_metadata
15160 * @module
15161 */
15162 (function (jsPDFAPI) {
15163
15164 var xmpmetadata = "";
15165 var xmpnamespaceuri = "";
15166 var metadata_object_number = "";
15167 /**
15168 * Adds XMP formatted metadata to PDF
15169 *
15170 * @name addMetadata
15171 * @function
15172 * @param {String} metadata The actual metadata to be added. The metadata shall be stored as XMP simple value. Note that if the metadata string contains XML markup characters "<", ">" or "&", those characters should be written using XML entities.
15173 * @param {String} namespaceuri Sets the namespace URI for the metadata. Last character should be slash or hash.
15174 * @returns {jsPDF} jsPDF-instance
15175 */
15176
15177 jsPDFAPI.addMetadata = function (metadata, namespaceuri) {
15178 xmpnamespaceuri = namespaceuri || "http://jspdf.default.namespaceuri/"; //The namespace URI for an XMP name shall not be empty
15179
15180 xmpmetadata = metadata;
15181 this.internal.events.subscribe('postPutResources', function () {
15182 if (!xmpmetadata) {
15183 metadata_object_number = "";
15184 } else {
15185 var xmpmeta_beginning = '<x:xmpmeta xmlns:x="adobe:ns:meta/">';
15186 var rdf_beginning = '<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"><rdf:Description rdf:about="" xmlns:jspdf="' + xmpnamespaceuri + '"><jspdf:metadata>';
15187 var rdf_ending = '</jspdf:metadata></rdf:Description></rdf:RDF>';
15188 var xmpmeta_ending = '</x:xmpmeta>';
15189 var utf8_xmpmeta_beginning = unescape(encodeURIComponent(xmpmeta_beginning));
15190 var utf8_rdf_beginning = unescape(encodeURIComponent(rdf_beginning));
15191 var utf8_metadata = unescape(encodeURIComponent(xmpmetadata));
15192 var utf8_rdf_ending = unescape(encodeURIComponent(rdf_ending));
15193 var utf8_xmpmeta_ending = unescape(encodeURIComponent(xmpmeta_ending));
15194 var total_len = utf8_rdf_beginning.length + utf8_metadata.length + utf8_rdf_ending.length + utf8_xmpmeta_beginning.length + utf8_xmpmeta_ending.length;
15195 metadata_object_number = this.internal.newObject();
15196 this.internal.write('<< /Type /Metadata /Subtype /XML /Length ' + total_len + ' >>');
15197 this.internal.write('stream');
15198 this.internal.write(utf8_xmpmeta_beginning + utf8_rdf_beginning + utf8_metadata + utf8_rdf_ending + utf8_xmpmeta_ending);
15199 this.internal.write('endstream');
15200 this.internal.write('endobj');
15201 }
15202 });
15203 this.internal.events.subscribe('putCatalog', function () {
15204 if (metadata_object_number) {
15205 this.internal.write('/Metadata ' + metadata_object_number + ' 0 R');
15206 }
15207 });
15208 return this;
15209 };
15210 })(jsPDF.API);
15211
15212 /**
15213 * @name utf8
15214 * @module
15215 */
15216 (function (jsPDF, global) {
15217
15218 var jsPDFAPI = jsPDF.API;
15219 /**************************************************/
15220
15221 /* function : toHex */
15222
15223 /* comment : Replace str with a hex string. */
15224
15225 /**************************************************/
15226
15227 function toHex(str) {
15228 var hex = '';
15229
15230 for (var i = 0; i < str.length; i++) {
15231 hex += '' + str.charCodeAt(i).toString(16);
15232 }
15233
15234 return hex;
15235 }
15236 /***************************************************************************************************/
15237
15238 /* function : pdfEscape16 */
15239
15240 /* comment : The character id of a 2-byte string is converted to a hexadecimal number by obtaining */
15241
15242 /* the corresponding glyph id and width, and then adding padding to the string. */
15243
15244 /***************************************************************************************************/
15245
15246
15247 var pdfEscape16 = jsPDFAPI.pdfEscape16 = function (text, font) {
15248 var widths = font.metadata.Unicode.widths;
15249 var padz = ["", "0", "00", "000", "0000"];
15250 var ar = [""];
15251
15252 for (var i = 0, l = text.length, t; i < l; ++i) {
15253 t = font.metadata.characterToGlyph(text.charCodeAt(i));
15254 font.metadata.glyIdsUsed.push(t);
15255 font.metadata.toUnicode[t] = text.charCodeAt(i);
15256
15257 if (widths.indexOf(t) == -1) {
15258 widths.push(t);
15259 widths.push([parseInt(font.metadata.widthOfGlyph(t), 10)]);
15260 }
15261
15262 if (t == '0') {
15263 //Spaces are not allowed in cmap.
15264 return ar.join("");
15265 } else {
15266 t = t.toString(16);
15267 ar.push(padz[4 - t.length], t);
15268 }
15269 }
15270
15271 return ar.join("");
15272 };
15273
15274 var toUnicodeCmap = function toUnicodeCmap(map) {
15275 var code, codes, range, unicode, unicodeMap, _i, _len;
15276
15277 unicodeMap = '/CIDInit /ProcSet findresource begin\n12 dict begin\nbegincmap\n/CIDSystemInfo <<\n /Registry (Adobe)\n /Ordering (UCS)\n /Supplement 0\n>> def\n/CMapName /Adobe-Identity-UCS def\n/CMapType 2 def\n1 begincodespacerange\n<0000><ffff>\nendcodespacerange';
15278 codes = Object.keys(map).sort(function (a, b) {
15279 return a - b;
15280 });
15281 range = [];
15282
15283 for (_i = 0, _len = codes.length; _i < _len; _i++) {
15284 code = codes[_i];
15285
15286 if (range.length >= 100) {
15287 unicodeMap += "\n" + range.length + " beginbfchar\n" + range.join('\n') + "\nendbfchar";
15288 range = [];
15289 }
15290
15291 unicode = ('0000' + map[code].toString(16)).slice(-4);
15292 code = ('0000' + (+code).toString(16)).slice(-4);
15293 range.push("<" + code + "><" + unicode + ">");
15294 }
15295
15296 if (range.length) {
15297 unicodeMap += "\n" + range.length + " beginbfchar\n" + range.join('\n') + "\nendbfchar\n";
15298 }
15299
15300 unicodeMap += 'endcmap\nCMapName currentdict /CMap defineresource pop\nend\nend';
15301 return unicodeMap;
15302 };
15303
15304 var identityHFunction = function identityHFunction(font, out, newObject, putStream) {
15305 if (font.metadata instanceof jsPDF.API.TTFFont && font.encoding === 'Identity-H') {
15306 //Tag with Identity-H
15307 var widths = font.metadata.Unicode.widths;
15308 var data = font.metadata.subset.encode(font.metadata.glyIdsUsed, 1);
15309 var pdfOutput = data;
15310 var pdfOutput2 = "";
15311
15312 for (var i = 0; i < pdfOutput.length; i++) {
15313 pdfOutput2 += String.fromCharCode(pdfOutput[i]);
15314 }
15315
15316 var fontTable = newObject();
15317 putStream({
15318 data: pdfOutput2,
15319 addLength1: true
15320 });
15321 out('endobj');
15322 var cmap = newObject();
15323 var cmapData = toUnicodeCmap(font.metadata.toUnicode);
15324 putStream({
15325 data: cmapData,
15326 addLength1: true
15327 });
15328 out('endobj');
15329 var fontDescriptor = newObject();
15330 out('<<');
15331 out('/Type /FontDescriptor');
15332 out('/FontName /' + font.fontName);
15333 out('/FontFile2 ' + fontTable + ' 0 R');
15334 out('/FontBBox ' + jsPDF.API.PDFObject.convert(font.metadata.bbox));
15335 out('/Flags ' + font.metadata.flags);
15336 out('/StemV ' + font.metadata.stemV);
15337 out('/ItalicAngle ' + font.metadata.italicAngle);
15338 out('/Ascent ' + font.metadata.ascender);
15339 out('/Descent ' + font.metadata.decender);
15340 out('/CapHeight ' + font.metadata.capHeight);
15341 out('>>');
15342 out('endobj');
15343 var DescendantFont = newObject();
15344 out('<<');
15345 out('/Type /Font');
15346 out('/BaseFont /' + font.fontName);
15347 out('/FontDescriptor ' + fontDescriptor + ' 0 R');
15348 out('/W ' + jsPDF.API.PDFObject.convert(widths));
15349 out('/CIDToGIDMap /Identity');
15350 out('/DW 1000');
15351 out('/Subtype /CIDFontType2');
15352 out('/CIDSystemInfo');
15353 out('<<');
15354 out('/Supplement 0');
15355 out('/Registry (Adobe)');
15356 out('/Ordering (' + font.encoding + ')');
15357 out('>>');
15358 out('>>');
15359 out('endobj');
15360 font.objectNumber = newObject();
15361 out('<<');
15362 out('/Type /Font');
15363 out('/Subtype /Type0');
15364 out('/ToUnicode ' + cmap + ' 0 R');
15365 out('/BaseFont /' + font.fontName);
15366 out('/Encoding /' + font.encoding);
15367 out('/DescendantFonts [' + DescendantFont + ' 0 R]');
15368 out('>>');
15369 out('endobj');
15370 font.isAlreadyPutted = true;
15371 }
15372 };
15373
15374 jsPDFAPI.events.push(['putFont', function (args) {
15375 identityHFunction(args.font, args.out, args.newObject, args.putStream);
15376 }]);
15377
15378 var winAnsiEncodingFunction = function winAnsiEncodingFunction(font, out, newObject, putStream) {
15379 if (font.metadata instanceof jsPDF.API.TTFFont && font.encoding === 'WinAnsiEncoding') {
15380 //Tag with WinAnsi encoding
15381 var widths = font.metadata.Unicode.widths;
15382 var data = font.metadata.rawData;
15383 var pdfOutput = data;
15384 var pdfOutput2 = "";
15385
15386 for (var i = 0; i < pdfOutput.length; i++) {
15387 pdfOutput2 += String.fromCharCode(pdfOutput[i]);
15388 }
15389
15390 var fontTable = newObject();
15391 putStream({
15392 data: pdfOutput2,
15393 addLength1: true
15394 });
15395 out('endobj');
15396 var cmap = newObject();
15397 var cmapData = toUnicodeCmap(font.metadata.toUnicode);
15398 putStream({
15399 data: cmapData,
15400 addLength1: true
15401 });
15402 out('endobj');
15403 var fontDescriptor = newObject();
15404 out('<<');
15405 out('/Descent ' + font.metadata.decender);
15406 out('/CapHeight ' + font.metadata.capHeight);
15407 out('/StemV ' + font.metadata.stemV);
15408 out('/Type /FontDescriptor');
15409 out('/FontFile2 ' + fontTable + ' 0 R');
15410 out('/Flags 96');
15411 out('/FontBBox ' + jsPDF.API.PDFObject.convert(font.metadata.bbox));
15412 out('/FontName /' + font.fontName);
15413 out('/ItalicAngle ' + font.metadata.italicAngle);
15414 out('/Ascent ' + font.metadata.ascender);
15415 out('>>');
15416 out('endobj');
15417 font.objectNumber = newObject();
15418
15419 for (var i = 0; i < font.metadata.hmtx.widths.length; i++) {
15420 font.metadata.hmtx.widths[i] = parseInt(font.metadata.hmtx.widths[i] * (1000 / font.metadata.head.unitsPerEm)); //Change the width of Em units to Point units.
15421 }
15422
15423 out('<</Subtype/TrueType/Type/Font/ToUnicode ' + cmap + ' 0 R/BaseFont/' + font.fontName + '/FontDescriptor ' + fontDescriptor + ' 0 R' + '/Encoding/' + font.encoding + ' /FirstChar 29 /LastChar 255 /Widths ' + jsPDF.API.PDFObject.convert(font.metadata.hmtx.widths) + '>>');
15424 out('endobj');
15425 font.isAlreadyPutted = true;
15426 }
15427 };
15428
15429 jsPDFAPI.events.push(['putFont', function (args) {
15430 winAnsiEncodingFunction(args.font, args.out, args.newObject, args.putStream);
15431 }]);
15432
15433 var utf8TextFunction = function utf8TextFunction(args) {
15434 var text = args.text || '';
15435 var x = args.x;
15436 var y = args.y;
15437 var options = args.options || {};
15438 var mutex = args.mutex || {};
15439 var pdfEscape = mutex.pdfEscape;
15440 var activeFontKey = mutex.activeFontKey;
15441 var fonts = mutex.fonts;
15442 var key,
15443 fontSize = mutex.activeFontSize;
15444 var str = '',
15445 s = 0,
15446 cmapConfirm;
15447 var strText = '';
15448 var key = activeFontKey;
15449 var encoding = fonts[key].encoding;
15450
15451 if (fonts[key].encoding !== 'Identity-H') {
15452 return {
15453 text: text,
15454 x: x,
15455 y: y,
15456 options: options,
15457 mutex: mutex
15458 };
15459 }
15460 strText = text;
15461 key = activeFontKey;
15462
15463 if (Object.prototype.toString.call(text) === '[object Array]') {
15464 strText = text[0];
15465 }
15466
15467 for (s = 0; s < strText.length; s += 1) {
15468 if (fonts[key].metadata.hasOwnProperty('cmap')) {
15469 cmapConfirm = fonts[key].metadata.cmap.unicode.codeMap[strText[s].charCodeAt(0)];
15470 /*
15471 if (Object.prototype.toString.call(text) === '[object Array]') {
15472 var i = 0;
15473 // for (i = 0; i < text.length; i += 1) {
15474 if (Object.prototype.toString.call(text[s]) === '[object Array]') {
15475 cmapConfirm = fonts[key].metadata.cmap.unicode.codeMap[strText[s][0].charCodeAt(0)]; //Make sure the cmap has the corresponding glyph id
15476 } else {
15477
15478 }
15479 //}
15480
15481 } else {
15482 cmapConfirm = fonts[key].metadata.cmap.unicode.codeMap[strText[s].charCodeAt(0)]; //Make sure the cmap has the corresponding glyph id
15483 }*/
15484 }
15485
15486 if (!cmapConfirm) {
15487 if (strText[s].charCodeAt(0) < 256 && fonts[key].metadata.hasOwnProperty('Unicode')) {
15488 str += strText[s];
15489 } else {
15490 str += '';
15491 }
15492 } else {
15493 str += strText[s];
15494 }
15495 }
15496
15497 var result = '';
15498
15499 if (parseInt(key.slice(1)) < 14 || encoding === 'WinAnsiEncoding') {
15500 //For the default 13 font
15501 result = toHex(pdfEscape(str, key));
15502 } else if (encoding === 'Identity-H') {
15503 result = pdfEscape16(str, fonts[key]);
15504 }
15505
15506 mutex.isHex = true;
15507 return {
15508 text: result,
15509 x: x,
15510 y: y,
15511 options: options,
15512 mutex: mutex
15513 };
15514 };
15515
15516 var utf8EscapeFunction = function utf8EscapeFunction(parms) {
15517 var text = parms.text || '',
15518 x = parms.x,
15519 y = parms.y,
15520 options = parms.options,
15521 mutex = parms.mutex;
15522 var lang = options.lang;
15523 var tmpText = [];
15524 var args = {
15525 text: text,
15526 x: x,
15527 y: y,
15528 options: options,
15529 mutex: mutex
15530 };
15531
15532 if (Object.prototype.toString.call(text) === '[object Array]') {
15533 var i = 0;
15534
15535 for (i = 0; i < text.length; i += 1) {
15536 if (Object.prototype.toString.call(text[i]) === '[object Array]') {
15537 if (text[i].length === 3) {
15538 tmpText.push([utf8TextFunction(Object.assign({}, args, {
15539 text: text[i][0]
15540 })).text, text[i][1], text[i][2]]);
15541 } else {
15542 tmpText.push(utf8TextFunction(Object.assign({}, args, {
15543 text: text[i]
15544 })).text);
15545 }
15546 } else {
15547 tmpText.push(utf8TextFunction(Object.assign({}, args, {
15548 text: text[i]
15549 })).text);
15550 }
15551 }
15552
15553 parms.text = tmpText;
15554 } else {
15555 parms.text = utf8TextFunction(Object.assign({}, args, {
15556 text: text
15557 })).text;
15558 }
15559 };
15560
15561 jsPDFAPI.events.push(['postProcessText', utf8EscapeFunction]);
15562 })(jsPDF, typeof self !== "undefined" && self || typeof global !== "undefined" && global || typeof window !== "undefined" && window || Function("return this")());
15563
15564 /**
15565 * jsPDF virtual FileSystem functionality
15566 *
15567 * Licensed under the MIT License.
15568 * http://opensource.org/licenses/mit-license
15569 */
15570
15571 /**
15572 * Use the vFS to handle files
15573 *
15574 * @name vFS
15575 * @module
15576 */
15577 (function (jsPDFAPI) {
15578
15579 var _initializeVFS = function _initializeVFS(instance) {
15580 if (typeof instance === "undefined") {
15581 return false;
15582 }
15583
15584 if (typeof instance.vFS === "undefined") {
15585 instance.vFS = {};
15586 }
15587
15588 return true;
15589 };
15590 /**
15591 * Check if the file exists in the vFS
15592 *
15593 * @name existsFileInVFS
15594 * @function
15595 * @param {string} Possible filename in the vFS.
15596 * @returns {boolean}
15597 * @example
15598 * doc.existsFileInVFS("someFile.txt");
15599 */
15600
15601
15602 jsPDFAPI.existsFileInVFS = function (filename) {
15603 if (_initializeVFS(this.internal)) {
15604 return typeof this.internal.vFS[filename] !== "undefined";
15605 }
15606
15607 return false;
15608 };
15609 /**
15610 * Add a file to the vFS
15611 *
15612 * @name addFileToVFS
15613 * @function
15614 * @param {string} filename The name of the file which should be added.
15615 * @param {string} filecontent The content of the file.
15616 * @returns {jsPDF}
15617 * @example
15618 * doc.addFileToVFS("someFile.txt", "BADFACE1");
15619 */
15620
15621
15622 jsPDFAPI.addFileToVFS = function (filename, filecontent) {
15623 _initializeVFS(this.internal);
15624
15625 this.internal.vFS[filename] = filecontent;
15626 return this;
15627 };
15628 /**
15629 * Get the file from the vFS
15630 *
15631 * @name getFileFromVFS
15632 * @function
15633 * @param {string} The name of the file which gets requested.
15634 * @returns {string}
15635 * @example
15636 * doc.getFileFromVFS("someFile.txt");
15637 */
15638
15639
15640 jsPDFAPI.getFileFromVFS = function (filename) {
15641 _initializeVFS(this.internal);
15642
15643 if (typeof this.internal.vFS[filename] !== "undefined") {
15644 return this.internal.vFS[filename];
15645 }
15646
15647 return null;
15648 };
15649 })(jsPDF.API);
15650
15651 /**
15652 * jsPDF addHTML PlugIn
15653 * Copyright (c) 2014 Diego Casorran
15654 *
15655 * Licensed under the MIT License.
15656 * http://opensource.org/licenses/mit-license
15657 */
15658 (function (jsPDFAPI) {
15659 /**
15660 * Renders an HTML element to canvas object which added to the PDF
15661 *
15662 * This feature requires [html2canvas](https://github.com/niklasvh/html2canvas)
15663 * or [rasterizeHTML](https://github.com/cburgmer/rasterizeHTML.js)
15664 *
15665 * @returns {jsPDF}
15666 * @name addHTML
15667 * @param element {Mixed} HTML Element, or anything supported by html2canvas.
15668 * @param x {Number} starting X coordinate in jsPDF instance's declared units.
15669 * @param y {Number} starting Y coordinate in jsPDF instance's declared units.
15670 * @param options {Object} Additional options, check the code below.
15671 * @param callback {Function} to call when the rendering has finished.
15672 * NOTE: Every parameter is optional except 'element' and 'callback', in such
15673 * case the image is positioned at 0x0 covering the whole PDF document
15674 * size. Ie, to easily take screenshots of webpages saving them to PDF.
15675 * @deprecated This is being replace with a vector-supporting API. See
15676 * [this link](https://cdn.rawgit.com/MrRio/jsPDF/master/examples/html2pdf/showcase_supported_html.html)
15677 */
15678
15679 jsPDFAPI.addHTML = function (element, x, y, options, callback) {
15680
15681 if (typeof html2canvas === 'undefined' && typeof rasterizeHTML === 'undefined') throw new Error('You need either ' + 'https://github.com/niklasvh/html2canvas' + ' or https://github.com/cburgmer/rasterizeHTML.js');
15682
15683 if (typeof x !== 'number') {
15684 options = x;
15685 callback = y;
15686 }
15687
15688 if (typeof options === 'function') {
15689 callback = options;
15690 options = null;
15691 }
15692
15693 if (typeof callback !== 'function') {
15694 callback = function callback() {};
15695 }
15696
15697 var I = this.internal,
15698 K = I.scaleFactor,
15699 W = I.pageSize.getWidth(),
15700 H = I.pageSize.getHeight();
15701 options = options || {};
15702
15703 options.onrendered = function (obj) {
15704 x = parseInt(x) || 0;
15705 y = parseInt(y) || 0;
15706 var dim = options.dim || {};
15707 var margin = Object.assign({
15708 top: 0,
15709 right: 0,
15710 bottom: 0,
15711 left: 0,
15712 useFor: 'content'
15713 }, options.margin);
15714 var h = dim.h || Math.min(H, obj.height / K);
15715 var w = dim.w || Math.min(W, obj.width / K) - x;
15716 var format = options.format || 'JPEG';
15717 var imageCompression = options.imageCompression || 'SLOW';
15718 var notFittingHeight = obj.height > H - margin.top - margin.bottom;
15719
15720 if (notFittingHeight && options.pagesplit) {
15721 var cropArea = function cropArea(parmObj, parmX, parmY, parmWidth, parmHeight) {
15722 var canvas = document.createElement('canvas');
15723 canvas.height = parmHeight;
15724 canvas.width = parmWidth;
15725 var ctx = canvas.getContext('2d');
15726 ctx.mozImageSmoothingEnabled = false;
15727 ctx.webkitImageSmoothingEnabled = false;
15728 ctx.msImageSmoothingEnabled = false;
15729 ctx.imageSmoothingEnabled = false;
15730 ctx.fillStyle = options.backgroundColor || '#ffffff';
15731 ctx.fillRect(0, 0, parmWidth, parmHeight);
15732 ctx.drawImage(parmObj, parmX, parmY, parmWidth, parmHeight, 0, 0, parmWidth, parmHeight);
15733 return canvas;
15734 };
15735
15736 var crop = function () {
15737 var cy = 0;
15738 var cx = 0;
15739 var position = {};
15740 var isOverWide = false;
15741 var width;
15742 var height;
15743
15744 while (1) {
15745 cx = 0;
15746 position.top = cy !== 0 ? margin.top : y;
15747 position.left = cy !== 0 ? margin.left : x;
15748 isOverWide = (W - margin.left - margin.right) * K < obj.width;
15749
15750 if (margin.useFor === "content") {
15751 if (cy === 0) {
15752 width = Math.min((W - margin.left) * K, obj.width);
15753 height = Math.min((H - margin.top) * K, obj.height - cy);
15754 } else {
15755 width = Math.min(W * K, obj.width);
15756 height = Math.min(H * K, obj.height - cy);
15757 position.top = 0;
15758 }
15759 } else {
15760 width = Math.min((W - margin.left - margin.right) * K, obj.width);
15761 height = Math.min((H - margin.bottom - margin.top) * K, obj.height - cy);
15762 }
15763
15764 if (isOverWide) {
15765 while (1) {
15766 if (margin.useFor === "content") {
15767 if (cx === 0) {
15768 width = Math.min((W - margin.left) * K, obj.width);
15769 } else {
15770 width = Math.min(W * K, obj.width - cx);
15771 position.left = 0;
15772 }
15773 }
15774
15775 var canvas = cropArea(obj, cx, cy, width, height);
15776 var args = [canvas, position.left, position.top, canvas.width / K, canvas.height / K, format, null, imageCompression];
15777 this.addImage.apply(this, args);
15778 cx += width;
15779
15780 if (cx >= obj.width) {
15781 break;
15782 }
15783
15784 this.addPage();
15785 }
15786 } else {
15787 var canvas = cropArea(obj, 0, cy, width, height);
15788 var args = [canvas, position.left, position.top, canvas.width / K, canvas.height / K, format, null, imageCompression];
15789 this.addImage.apply(this, args);
15790 }
15791
15792 cy += height;
15793
15794 if (cy >= obj.height) {
15795 break;
15796 }
15797
15798 this.addPage();
15799 }
15800
15801 callback(w, cy, null, args);
15802 }.bind(this);
15803
15804 if (obj.nodeName === 'CANVAS') {
15805 var img = new Image();
15806 img.onload = crop;
15807 img.src = obj.toDataURL("image/png");
15808 obj = img;
15809 } else {
15810 crop();
15811 }
15812 } else {
15813 var alias = Math.random().toString(35);
15814 var args = [obj, x, y, w, h, format, alias, imageCompression];
15815 this.addImage.apply(this, args);
15816 callback(w, h, alias, args);
15817 }
15818 }.bind(this);
15819
15820 if (typeof html2canvas !== 'undefined' && !options.rstz) {
15821 return html2canvas(element, options);
15822 }
15823
15824 if (typeof rasterizeHTML !== 'undefined') {
15825 var meth = 'drawDocument';
15826
15827 if (typeof element === 'string') {
15828 meth = /^http/.test(element) ? 'drawURL' : 'drawHTML';
15829 }
15830
15831 options.width = options.width || W * K;
15832 return rasterizeHTML[meth](element, void 0, options).then(function (r) {
15833 options.onrendered(r.image);
15834 }, function (e) {
15835 callback(null, e);
15836 });
15837 }
15838
15839 return null;
15840 };
15841 })(jsPDF.API);
15842
15843 /**
15844 * jsPDF fromHTML plugin. BETA stage. API subject to change. Needs browser
15845 * Copyright (c) 2012 Willow Systems Corporation, willow-systems.com
15846 * 2014 Juan Pablo Gaviria, https://github.com/juanpgaviria
15847 * 2014 Diego Casorran, https://github.com/diegocr
15848 * 2014 Daniel Husar, https://github.com/danielhusar
15849 * 2014 Wolfgang Gassler, https://github.com/woolfg
15850 * 2014 Steven Spungin, https://github.com/flamenco
15851 *
15852 * @license
15853 *
15854 * ====================================================================
15855 */
15856 (function (jsPDFAPI) {
15857 var clone, _DrillForContent, FontNameDB, FontStyleMap, TextAlignMap, FontWeightMap, FloatMap, ClearMap, GetCSS, PurgeWhiteSpace, Renderer, ResolveFont, ResolveUnitedNumber, UnitedNumberMap, elementHandledElsewhere, images, loadImgs, checkForFooter, process, tableToJson;
15858
15859 clone = function () {
15860 return function (obj) {
15861 Clone.prototype = obj;
15862 return new Clone();
15863 };
15864
15865 function Clone() {}
15866 }();
15867
15868 PurgeWhiteSpace = function PurgeWhiteSpace(array) {
15869 var fragment, i, l, lTrimmed, r, rTrimmed, trailingSpace;
15870 i = 0;
15871 l = array.length;
15872 fragment = void 0;
15873 lTrimmed = false;
15874 rTrimmed = false;
15875
15876 while (!lTrimmed && i !== l) {
15877 fragment = array[i] = array[i].trimLeft();
15878
15879 if (fragment) {
15880 lTrimmed = true;
15881 }
15882
15883 i++;
15884 }
15885
15886 i = l - 1;
15887
15888 while (l && !rTrimmed && i !== -1) {
15889 fragment = array[i] = array[i].trimRight();
15890
15891 if (fragment) {
15892 rTrimmed = true;
15893 }
15894
15895 i--;
15896 }
15897
15898 r = /\s+$/g;
15899 trailingSpace = true;
15900 i = 0;
15901
15902 while (i !== l) {
15903 // Leave the line breaks intact
15904 if (array[i] != "\u2028") {
15905 fragment = array[i].replace(/\s+/g, " ");
15906
15907 if (trailingSpace) {
15908 fragment = fragment.trimLeft();
15909 }
15910
15911 if (fragment) {
15912 trailingSpace = r.test(fragment);
15913 }
15914
15915 array[i] = fragment;
15916 }
15917
15918 i++;
15919 }
15920
15921 return array;
15922 };
15923
15924 Renderer = function Renderer(pdf, x, y, settings) {
15925 this.pdf = pdf;
15926 this.x = x;
15927 this.y = y;
15928 this.settings = settings; //list of functions which are called after each element-rendering process
15929
15930 this.watchFunctions = [];
15931 this.init();
15932 return this;
15933 };
15934
15935 ResolveFont = function ResolveFont(css_font_family_string) {
15936 var name, part, parts;
15937 name = void 0;
15938 parts = css_font_family_string.split(",");
15939 part = parts.shift();
15940
15941 while (!name && part) {
15942 name = FontNameDB[part.trim().toLowerCase()];
15943 part = parts.shift();
15944 }
15945
15946 return name;
15947 };
15948
15949 ResolveUnitedNumber = function ResolveUnitedNumber(css_line_height_string) {
15950 //IE8 issues
15951 css_line_height_string = css_line_height_string === "auto" ? "0px" : css_line_height_string;
15952
15953 if (css_line_height_string.indexOf("em") > -1 && !isNaN(Number(css_line_height_string.replace("em", "")))) {
15954 css_line_height_string = Number(css_line_height_string.replace("em", "")) * 18.719 + "px";
15955 }
15956
15957 if (css_line_height_string.indexOf("pt") > -1 && !isNaN(Number(css_line_height_string.replace("pt", "")))) {
15958 css_line_height_string = Number(css_line_height_string.replace("pt", "")) * 1.333 + "px";
15959 }
15960
15961 var normal, undef, value;
15962 undef = void 0;
15963 normal = 16.00;
15964 value = UnitedNumberMap[css_line_height_string];
15965
15966 if (value) {
15967 return value;
15968 }
15969
15970 value = {
15971 "xx-small": 9,
15972 "x-small": 11,
15973 small: 13,
15974 medium: 16,
15975 large: 19,
15976 "x-large": 23,
15977 "xx-large": 28,
15978 auto: 0
15979 }[css_line_height_string];
15980
15981 if (value !== undef) {
15982 return UnitedNumberMap[css_line_height_string] = value / normal;
15983 }
15984
15985 if (value = parseFloat(css_line_height_string)) {
15986 return UnitedNumberMap[css_line_height_string] = value / normal;
15987 }
15988
15989 value = css_line_height_string.match(/([\d\.]+)(px)/);
15990
15991 if (Array.isArray(value) && value.length === 3) {
15992 return UnitedNumberMap[css_line_height_string] = parseFloat(value[1]) / normal;
15993 }
15994
15995 return UnitedNumberMap[css_line_height_string] = 1;
15996 };
15997
15998 GetCSS = function GetCSS(element) {
15999 var css, tmp, computedCSSElement;
16000
16001 computedCSSElement = function (el) {
16002 var compCSS;
16003
16004 compCSS = function (el) {
16005 if (document.defaultView && document.defaultView.getComputedStyle) {
16006 return document.defaultView.getComputedStyle(el, null);
16007 } else if (el.currentStyle) {
16008 return el.currentStyle;
16009 } else {
16010 return el.style;
16011 }
16012 }(el);
16013
16014 return function (prop) {
16015 prop = prop.replace(/-\D/g, function (match) {
16016 return match.charAt(1).toUpperCase();
16017 });
16018 return compCSS[prop];
16019 };
16020 }(element);
16021
16022 css = {};
16023 tmp = void 0;
16024 css["font-family"] = ResolveFont(computedCSSElement("font-family")) || "times";
16025 css["font-style"] = FontStyleMap[computedCSSElement("font-style")] || "normal";
16026 css["text-align"] = TextAlignMap[computedCSSElement("text-align")] || "left";
16027 tmp = FontWeightMap[computedCSSElement("font-weight")] || "normal";
16028
16029 if (tmp === "bold") {
16030 if (css["font-style"] === "normal") {
16031 css["font-style"] = tmp;
16032 } else {
16033 css["font-style"] = tmp + css["font-style"];
16034 }
16035 }
16036
16037 css["font-size"] = ResolveUnitedNumber(computedCSSElement("font-size")) || 1;
16038 css["line-height"] = ResolveUnitedNumber(computedCSSElement("line-height")) || 1;
16039 css["display"] = computedCSSElement("display") === "inline" ? "inline" : "block";
16040 tmp = css["display"] === "block";
16041 css["margin-top"] = tmp && ResolveUnitedNumber(computedCSSElement("margin-top")) || 0;
16042 css["margin-bottom"] = tmp && ResolveUnitedNumber(computedCSSElement("margin-bottom")) || 0;
16043 css["padding-top"] = tmp && ResolveUnitedNumber(computedCSSElement("padding-top")) || 0;
16044 css["padding-bottom"] = tmp && ResolveUnitedNumber(computedCSSElement("padding-bottom")) || 0;
16045 css["margin-left"] = tmp && ResolveUnitedNumber(computedCSSElement("margin-left")) || 0;
16046 css["margin-right"] = tmp && ResolveUnitedNumber(computedCSSElement("margin-right")) || 0;
16047 css["padding-left"] = tmp && ResolveUnitedNumber(computedCSSElement("padding-left")) || 0;
16048 css["padding-right"] = tmp && ResolveUnitedNumber(computedCSSElement("padding-right")) || 0;
16049 css["page-break-before"] = computedCSSElement("page-break-before") || "auto"; //float and clearing of floats
16050
16051 css["float"] = FloatMap[computedCSSElement("cssFloat")] || "none";
16052 css["clear"] = ClearMap[computedCSSElement("clear")] || "none";
16053 css["color"] = computedCSSElement("color");
16054 return css;
16055 };
16056
16057 elementHandledElsewhere = function elementHandledElsewhere(element, renderer, elementHandlers) {
16058 var handlers, i, isHandledElsewhere, l, classNames;
16059 isHandledElsewhere = false;
16060 i = void 0;
16061 l = void 0;
16062 handlers = elementHandlers["#" + element.id];
16063
16064 if (handlers) {
16065 if (typeof handlers === "function") {
16066 isHandledElsewhere = handlers(element, renderer);
16067 } else {
16068 i = 0;
16069 l = handlers.length;
16070
16071 while (!isHandledElsewhere && i !== l) {
16072 isHandledElsewhere = handlers[i](element, renderer);
16073 i++;
16074 }
16075 }
16076 }
16077
16078 handlers = elementHandlers[element.nodeName];
16079
16080 if (!isHandledElsewhere && handlers) {
16081 if (typeof handlers === "function") {
16082 isHandledElsewhere = handlers(element, renderer);
16083 } else {
16084 i = 0;
16085 l = handlers.length;
16086
16087 while (!isHandledElsewhere && i !== l) {
16088 isHandledElsewhere = handlers[i](element, renderer);
16089 i++;
16090 }
16091 }
16092 } // Try class names
16093
16094
16095 classNames = typeof element.className === 'string' ? element.className.split(' ') : [];
16096
16097 for (i = 0; i < classNames.length; i++) {
16098 handlers = elementHandlers['.' + classNames[i]];
16099
16100 if (!isHandledElsewhere && handlers) {
16101 if (typeof handlers === "function") {
16102 isHandledElsewhere = handlers(element, renderer);
16103 } else {
16104 i = 0;
16105 l = handlers.length;
16106
16107 while (!isHandledElsewhere && i !== l) {
16108 isHandledElsewhere = handlers[i](element, renderer);
16109 i++;
16110 }
16111 }
16112 }
16113 }
16114
16115 return isHandledElsewhere;
16116 };
16117
16118 tableToJson = function tableToJson(table, renderer) {
16119 var data, headers, i, j, rowData, tableRow, table_obj, table_with, cell, l;
16120 data = [];
16121 headers = [];
16122 i = 0;
16123 l = table.rows[0].cells.length;
16124 table_with = table.clientWidth;
16125
16126 while (i < l) {
16127 cell = table.rows[0].cells[i];
16128 headers[i] = {
16129 name: cell.textContent.toLowerCase().replace(/\s+/g, ''),
16130 prompt: cell.textContent.replace(/\r?\n/g, ''),
16131 width: cell.clientWidth / table_with * renderer.pdf.internal.pageSize.getWidth()
16132 };
16133 i++;
16134 }
16135
16136 i = 1;
16137
16138 while (i < table.rows.length) {
16139 tableRow = table.rows[i];
16140 rowData = {};
16141 j = 0;
16142
16143 while (j < tableRow.cells.length) {
16144 rowData[headers[j].name] = tableRow.cells[j].textContent.replace(/\r?\n/g, '');
16145 j++;
16146 }
16147
16148 data.push(rowData);
16149 i++;
16150 }
16151
16152 return table_obj = {
16153 rows: data,
16154 headers: headers
16155 };
16156 };
16157
16158 var SkipNode = {
16159 SCRIPT: 1,
16160 STYLE: 1,
16161 NOSCRIPT: 1,
16162 OBJECT: 1,
16163 EMBED: 1,
16164 SELECT: 1
16165 };
16166 var listCount = 1;
16167
16168 _DrillForContent = function DrillForContent(element, renderer, elementHandlers) {
16169 var cn, cns, fragmentCSS, i, isBlock, l, table2json, cb;
16170 cns = element.childNodes;
16171 cn = void 0;
16172 fragmentCSS = GetCSS(element);
16173 isBlock = fragmentCSS.display === "block";
16174
16175 if (isBlock) {
16176 renderer.setBlockBoundary();
16177 renderer.setBlockStyle(fragmentCSS);
16178 }
16179 i = 0;
16180 l = cns.length;
16181
16182 while (i < l) {
16183 cn = cns[i];
16184
16185 if (_typeof(cn) === "object") {
16186 //execute all watcher functions to e.g. reset floating
16187 renderer.executeWatchFunctions(cn);
16188 /*** HEADER rendering **/
16189
16190 if (cn.nodeType === 1 && cn.nodeName === 'HEADER') {
16191 var header = cn; //store old top margin
16192
16193 var oldMarginTop = renderer.pdf.margins_doc.top; //subscribe for new page event and render header first on every page
16194
16195 renderer.pdf.internal.events.subscribe('addPage', function (pageInfo) {
16196 //set current y position to old margin
16197 renderer.y = oldMarginTop; //render all child nodes of the header element
16198
16199 _DrillForContent(header, renderer, elementHandlers); //set margin to old margin + rendered header + 10 space to prevent overlapping
16200 //important for other plugins (e.g. table) to start rendering at correct position after header
16201
16202
16203 renderer.pdf.margins_doc.top = renderer.y + 10;
16204 renderer.y += 10;
16205 }, false);
16206 }
16207
16208 if (cn.nodeType === 8 && cn.nodeName === "#comment") {
16209 if (~cn.textContent.indexOf("ADD_PAGE")) {
16210 renderer.pdf.addPage();
16211 renderer.y = renderer.pdf.margins_doc.top;
16212 }
16213 } else if (cn.nodeType === 1 && !SkipNode[cn.nodeName]) {
16214 /*** IMAGE RENDERING ***/
16215 var cached_image;
16216
16217 if (cn.nodeName === "IMG") {
16218 var url = cn.getAttribute("src");
16219 cached_image = images[renderer.pdf.sHashCode(url) || url];
16220 }
16221
16222 if (cached_image) {
16223 if (renderer.pdf.internal.pageSize.getHeight() - renderer.pdf.margins_doc.bottom < renderer.y + cn.height && renderer.y > renderer.pdf.margins_doc.top) {
16224 renderer.pdf.addPage();
16225 renderer.y = renderer.pdf.margins_doc.top; //check if we have to set back some values due to e.g. header rendering for new page
16226
16227 renderer.executeWatchFunctions(cn);
16228 }
16229
16230 var imagesCSS = GetCSS(cn);
16231 var imageX = renderer.x;
16232 var fontToUnitRatio = 12 / renderer.pdf.internal.scaleFactor; //define additional paddings, margins which have to be taken into account for margin calculations
16233
16234 var additionalSpaceLeft = (imagesCSS["margin-left"] + imagesCSS["padding-left"]) * fontToUnitRatio;
16235 var additionalSpaceRight = (imagesCSS["margin-right"] + imagesCSS["padding-right"]) * fontToUnitRatio;
16236 var additionalSpaceTop = (imagesCSS["margin-top"] + imagesCSS["padding-top"]) * fontToUnitRatio;
16237 var additionalSpaceBottom = (imagesCSS["margin-bottom"] + imagesCSS["padding-bottom"]) * fontToUnitRatio; //if float is set to right, move the image to the right border
16238 //add space if margin is set
16239
16240 if (imagesCSS['float'] !== undefined && imagesCSS['float'] === 'right') {
16241 imageX += renderer.settings.width - cn.width - additionalSpaceRight;
16242 } else {
16243 imageX += additionalSpaceLeft;
16244 }
16245
16246 renderer.pdf.addImage(cached_image, imageX, renderer.y + additionalSpaceTop, cn.width, cn.height);
16247 cached_image = undefined; //if the float prop is specified we have to float the text around the image
16248
16249 if (imagesCSS['float'] === 'right' || imagesCSS['float'] === 'left') {
16250 //add functiont to set back coordinates after image rendering
16251 renderer.watchFunctions.push(function (diffX, thresholdY, diffWidth, el) {
16252 //undo drawing box adaptions which were set by floating
16253 if (renderer.y >= thresholdY) {
16254 renderer.x += diffX;
16255 renderer.settings.width += diffWidth;
16256 return true;
16257 } else if (el && el.nodeType === 1 && !SkipNode[el.nodeName] && renderer.x + el.width > renderer.pdf.margins_doc.left + renderer.pdf.margins_doc.width) {
16258 renderer.x += diffX;
16259 renderer.y = thresholdY;
16260 renderer.settings.width += diffWidth;
16261 return true;
16262 } else {
16263 return false;
16264 }
16265 }.bind(this, imagesCSS['float'] === 'left' ? -cn.width - additionalSpaceLeft - additionalSpaceRight : 0, renderer.y + cn.height + additionalSpaceTop + additionalSpaceBottom, cn.width)); //reset floating by clear:both divs
16266 //just set cursorY after the floating element
16267
16268 renderer.watchFunctions.push(function (yPositionAfterFloating, pages, el) {
16269 if (renderer.y < yPositionAfterFloating && pages === renderer.pdf.internal.getNumberOfPages()) {
16270 if (el.nodeType === 1 && GetCSS(el).clear === 'both') {
16271 renderer.y = yPositionAfterFloating;
16272 return true;
16273 } else {
16274 return false;
16275 }
16276 } else {
16277 return true;
16278 }
16279 }.bind(this, renderer.y + cn.height, renderer.pdf.internal.getNumberOfPages())); //if floating is set we decrease the available width by the image width
16280
16281 renderer.settings.width -= cn.width + additionalSpaceLeft + additionalSpaceRight; //if left just add the image width to the X coordinate
16282
16283 if (imagesCSS['float'] === 'left') {
16284 renderer.x += cn.width + additionalSpaceLeft + additionalSpaceRight;
16285 }
16286 } else {
16287 //if no floating is set, move the rendering cursor after the image height
16288 renderer.y += cn.height + additionalSpaceTop + additionalSpaceBottom;
16289 }
16290 /*** TABLE RENDERING ***/
16291
16292 } else if (cn.nodeName === "TABLE") {
16293 table2json = tableToJson(cn, renderer);
16294 renderer.y += 10;
16295 renderer.pdf.table(renderer.x, renderer.y, table2json.rows, table2json.headers, {
16296 autoSize: false,
16297 printHeaders: elementHandlers.printHeaders,
16298 margins: renderer.pdf.margins_doc,
16299 css: GetCSS(cn)
16300 });
16301 renderer.y = renderer.pdf.lastCellPos.y + renderer.pdf.lastCellPos.h + 20;
16302 } else if (cn.nodeName === "OL" || cn.nodeName === "UL") {
16303 listCount = 1;
16304
16305 if (!elementHandledElsewhere(cn, renderer, elementHandlers)) {
16306 _DrillForContent(cn, renderer, elementHandlers);
16307 }
16308
16309 renderer.y += 10;
16310 } else if (cn.nodeName === "LI") {
16311 var temp = renderer.x;
16312 renderer.x += 20 / renderer.pdf.internal.scaleFactor;
16313 renderer.y += 3;
16314
16315 if (!elementHandledElsewhere(cn, renderer, elementHandlers)) {
16316 _DrillForContent(cn, renderer, elementHandlers);
16317 }
16318
16319 renderer.x = temp;
16320 } else if (cn.nodeName === "BR") {
16321 renderer.y += fragmentCSS["font-size"] * renderer.pdf.internal.scaleFactor;
16322 renderer.addText("\u2028", clone(fragmentCSS));
16323 } else {
16324 if (!elementHandledElsewhere(cn, renderer, elementHandlers)) {
16325 _DrillForContent(cn, renderer, elementHandlers);
16326 }
16327 }
16328 } else if (cn.nodeType === 3) {
16329 var value = cn.nodeValue;
16330
16331 if (cn.nodeValue && cn.parentNode.nodeName === "LI") {
16332 if (cn.parentNode.parentNode.nodeName === "OL") {
16333 value = listCount++ + '. ' + value;
16334 } else {
16335 var fontSize = fragmentCSS["font-size"];
16336 var offsetX = (3 - fontSize * 0.75) * renderer.pdf.internal.scaleFactor;
16337 var offsetY = fontSize * 0.75 * renderer.pdf.internal.scaleFactor;
16338 var radius = fontSize * 1.74 / renderer.pdf.internal.scaleFactor;
16339
16340 cb = function cb(x, y) {
16341 this.pdf.circle(x + offsetX, y + offsetY, radius, 'FD');
16342 };
16343 }
16344 } // Only add the text if the text node is in the body element
16345 // Add compatibility with IE11
16346
16347
16348 if (!!(cn.ownerDocument.body.compareDocumentPosition(cn) & 16)) {
16349 renderer.addText(value, fragmentCSS);
16350 }
16351 } else if (typeof cn === "string") {
16352 renderer.addText(cn, fragmentCSS);
16353 }
16354 }
16355
16356 i++;
16357 }
16358
16359 elementHandlers.outY = renderer.y;
16360
16361 if (isBlock) {
16362 return renderer.setBlockBoundary(cb);
16363 }
16364 };
16365
16366 images = {};
16367
16368 loadImgs = function loadImgs(element, renderer, elementHandlers, cb) {
16369 var imgs = element.getElementsByTagName('img'),
16370 l = imgs.length,
16371 found_images,
16372 x = 0;
16373
16374 function done() {
16375 renderer.pdf.internal.events.publish('imagesLoaded');
16376 cb(found_images);
16377 }
16378
16379 function loadImage(url, width, height) {
16380 if (!url) return;
16381 var img = new Image();
16382 found_images = ++x;
16383 img.crossOrigin = '';
16384
16385 img.onerror = img.onload = function () {
16386 if (img.complete) {
16387 //to support data urls in images, set width and height
16388 //as those values are not recognized automatically
16389 if (img.src.indexOf('data:image/') === 0) {
16390 img.width = width || img.width || 0;
16391 img.height = height || img.height || 0;
16392 } //if valid image add to known images array
16393
16394
16395 if (img.width + img.height) {
16396 var hash = renderer.pdf.sHashCode(url) || url;
16397 images[hash] = images[hash] || img;
16398 }
16399 }
16400
16401 if (! --x) {
16402 done();
16403 }
16404 };
16405
16406 img.src = url;
16407 }
16408
16409 while (l--) {
16410 loadImage(imgs[l].getAttribute("src"), imgs[l].width, imgs[l].height);
16411 }
16412
16413 return x || done();
16414 };
16415
16416 checkForFooter = function checkForFooter(elem, renderer, elementHandlers) {
16417 //check if we can found a <footer> element
16418 var footer = elem.getElementsByTagName("footer");
16419
16420 if (footer.length > 0) {
16421 footer = footer[0]; //bad hack to get height of footer
16422 //creat dummy out and check new y after fake rendering
16423
16424 var oldOut = renderer.pdf.internal.write;
16425 var oldY = renderer.y;
16426
16427 renderer.pdf.internal.write = function () {};
16428
16429 _DrillForContent(footer, renderer, elementHandlers);
16430
16431 var footerHeight = Math.ceil(renderer.y - oldY) + 5;
16432 renderer.y = oldY;
16433 renderer.pdf.internal.write = oldOut; //add 20% to prevent overlapping
16434
16435 renderer.pdf.margins_doc.bottom += footerHeight; //Create function render header on every page
16436
16437 var renderFooter = function renderFooter(pageInfo) {
16438 var pageNumber = pageInfo !== undefined ? pageInfo.pageNumber : 1; //set current y position to old margin
16439
16440 var oldPosition = renderer.y; //render all child nodes of the header element
16441
16442 renderer.y = renderer.pdf.internal.pageSize.getHeight() - renderer.pdf.margins_doc.bottom;
16443 renderer.pdf.margins_doc.bottom -= footerHeight; //check if we have to add page numbers
16444
16445 var spans = footer.getElementsByTagName('span');
16446
16447 for (var i = 0; i < spans.length; ++i) {
16448 //if we find some span element with class pageCounter, set the page
16449 if ((" " + spans[i].className + " ").replace(/[\n\t]/g, " ").indexOf(" pageCounter ") > -1) {
16450 spans[i].innerHTML = pageNumber;
16451 } //if we find some span element with class totalPages, set a variable which is replaced after rendering of all pages
16452
16453
16454 if ((" " + spans[i].className + " ").replace(/[\n\t]/g, " ").indexOf(" totalPages ") > -1) {
16455 spans[i].innerHTML = '###jsPDFVarTotalPages###';
16456 }
16457 } //render footer content
16458
16459
16460 _DrillForContent(footer, renderer, elementHandlers); //set bottom margin to previous height including the footer height
16461
16462
16463 renderer.pdf.margins_doc.bottom += footerHeight; //important for other plugins (e.g. table) to start rendering at correct position after header
16464
16465 renderer.y = oldPosition;
16466 }; //check if footer contains totalPages which should be replace at the disoposal of the document
16467
16468
16469 var spans = footer.getElementsByTagName('span');
16470
16471 for (var i = 0; i < spans.length; ++i) {
16472 if ((" " + spans[i].className + " ").replace(/[\n\t]/g, " ").indexOf(" totalPages ") > -1) {
16473 renderer.pdf.internal.events.subscribe('htmlRenderingFinished', renderer.pdf.putTotalPages.bind(renderer.pdf, '###jsPDFVarTotalPages###'), true);
16474 }
16475 } //register event to render footer on every new page
16476
16477
16478 renderer.pdf.internal.events.subscribe('addPage', renderFooter, false); //render footer on first page
16479
16480 renderFooter(); //prevent footer rendering
16481
16482 SkipNode['FOOTER'] = 1;
16483 }
16484 };
16485
16486 process = function process(pdf, element, x, y, settings, callback) {
16487 if (!element) return false;
16488 if (typeof element !== "string" && !element.parentNode) element = '' + element.innerHTML;
16489
16490 if (typeof element === "string") {
16491 element = function (element) {
16492 var $frame, $hiddendiv, framename, visuallyhidden;
16493 framename = "jsPDFhtmlText" + Date.now().toString() + (Math.random() * 1000).toFixed(0);
16494 visuallyhidden = "position: absolute !important;" + "clip: rect(1px 1px 1px 1px); /* IE6, IE7 */" + "clip: rect(1px, 1px, 1px, 1px);" + "padding:0 !important;" + "border:0 !important;" + "height: 1px !important;" + "width: 1px !important; " + "top:auto;" + "left:-100px;" + "overflow: hidden;";
16495 $hiddendiv = document.createElement('div');
16496 $hiddendiv.style.cssText = visuallyhidden;
16497 $hiddendiv.innerHTML = "<iframe style=\"height:1px;width:1px\" name=\"" + framename + "\" />";
16498 document.body.appendChild($hiddendiv);
16499 $frame = window.frames[framename];
16500 $frame.document.open();
16501 $frame.document.writeln(element);
16502 $frame.document.close();
16503 return $frame.document.body;
16504 }(element.replace(/<\/?script[^>]*?>/gi, ''));
16505 }
16506
16507 var r = new Renderer(pdf, x, y, settings),
16508 out; // 1. load images
16509 // 2. prepare optional footer elements
16510 // 3. render content
16511
16512 loadImgs.call(this, element, r, settings.elementHandlers, function (found_images) {
16513 checkForFooter(element, r, settings.elementHandlers);
16514
16515 _DrillForContent(element, r, settings.elementHandlers); //send event dispose for final taks (e.g. footer totalpage replacement)
16516
16517
16518 r.pdf.internal.events.publish('htmlRenderingFinished');
16519 out = r.dispose();
16520 if (typeof callback === 'function') callback(out);else if (found_images) console.error('jsPDF Warning: rendering issues? provide a callback to fromHTML!');
16521 });
16522 return out || {
16523 x: r.x,
16524 y: r.y
16525 };
16526 };
16527
16528 Renderer.prototype.init = function () {
16529 this.paragraph = {
16530 text: [],
16531 style: []
16532 };
16533 return this.pdf.internal.write("q");
16534 };
16535
16536 Renderer.prototype.dispose = function () {
16537 this.pdf.internal.write("Q");
16538 return {
16539 x: this.x,
16540 y: this.y,
16541 ready: true
16542 };
16543 }; //Checks if we have to execute some watcher functions
16544 //e.g. to end text floating around an image
16545
16546
16547 Renderer.prototype.executeWatchFunctions = function (el) {
16548 var ret = false;
16549 var narray = [];
16550
16551 if (this.watchFunctions.length > 0) {
16552 for (var i = 0; i < this.watchFunctions.length; ++i) {
16553 if (this.watchFunctions[i](el) === true) {
16554 ret = true;
16555 } else {
16556 narray.push(this.watchFunctions[i]);
16557 }
16558 }
16559
16560 this.watchFunctions = narray;
16561 }
16562
16563 return ret;
16564 };
16565
16566 Renderer.prototype.splitFragmentsIntoLines = function (fragments, styles) {
16567 var currentLineLength, defaultFontSize, ff, fontMetrics, fontMetricsCache, fragment, fragmentChopped, fragmentLength, fragmentSpecificMetrics, fs, k, line, lines, maxLineLength, style;
16568 defaultFontSize = 12;
16569 k = this.pdf.internal.scaleFactor;
16570 fontMetricsCache = {};
16571 ff = void 0;
16572 fs = void 0;
16573 fontMetrics = void 0;
16574 fragment = void 0;
16575 style = void 0;
16576 fragmentSpecificMetrics = void 0;
16577 fragmentLength = void 0;
16578 fragmentChopped = void 0;
16579 line = [];
16580 lines = [line];
16581 currentLineLength = 0;
16582 maxLineLength = this.settings.width;
16583
16584 while (fragments.length) {
16585 fragment = fragments.shift();
16586 style = styles.shift();
16587
16588 if (fragment) {
16589 ff = style["font-family"];
16590 fs = style["font-style"];
16591 fontMetrics = fontMetricsCache[ff + fs];
16592
16593 if (!fontMetrics) {
16594 fontMetrics = this.pdf.internal.getFont(ff, fs).metadata.Unicode;
16595 fontMetricsCache[ff + fs] = fontMetrics;
16596 }
16597
16598 fragmentSpecificMetrics = {
16599 widths: fontMetrics.widths,
16600 kerning: fontMetrics.kerning,
16601 fontSize: style["font-size"] * defaultFontSize,
16602 textIndent: currentLineLength
16603 };
16604 fragmentLength = this.pdf.getStringUnitWidth(fragment, fragmentSpecificMetrics) * fragmentSpecificMetrics.fontSize / k;
16605
16606 if (fragment == "\u2028") {
16607 line = [];
16608 lines.push(line);
16609 } else if (currentLineLength + fragmentLength > maxLineLength) {
16610 fragmentChopped = this.pdf.splitTextToSize(fragment, maxLineLength, fragmentSpecificMetrics);
16611 line.push([fragmentChopped.shift(), style]);
16612
16613 while (fragmentChopped.length) {
16614 line = [[fragmentChopped.shift(), style]];
16615 lines.push(line);
16616 }
16617
16618 currentLineLength = this.pdf.getStringUnitWidth(line[0][0], fragmentSpecificMetrics) * fragmentSpecificMetrics.fontSize / k;
16619 } else {
16620 line.push([fragment, style]);
16621 currentLineLength += fragmentLength;
16622 }
16623 }
16624 } //if text alignment was set, set margin/indent of each line
16625
16626
16627 if (style['text-align'] !== undefined && (style['text-align'] === 'center' || style['text-align'] === 'right' || style['text-align'] === 'justify')) {
16628 for (var i = 0; i < lines.length; ++i) {
16629 var length = this.pdf.getStringUnitWidth(lines[i][0][0], fragmentSpecificMetrics) * fragmentSpecificMetrics.fontSize / k; //if there is more than on line we have to clone the style object as all lines hold a reference on this object
16630
16631 if (i > 0) {
16632 lines[i][0][1] = clone(lines[i][0][1]);
16633 }
16634
16635 var space = maxLineLength - length;
16636
16637 if (style['text-align'] === 'right') {
16638 lines[i][0][1]['margin-left'] = space; //if alignment is not right, it has to be center so split the space to the left and the right
16639 } else if (style['text-align'] === 'center') {
16640 lines[i][0][1]['margin-left'] = space / 2; //if justify was set, calculate the word spacing and define in by using the css property
16641 } else if (style['text-align'] === 'justify') {
16642 var countSpaces = lines[i][0][0].split(' ').length - 1;
16643 lines[i][0][1]['word-spacing'] = space / countSpaces; //ignore the last line in justify mode
16644
16645 if (i === lines.length - 1) {
16646 lines[i][0][1]['word-spacing'] = 0;
16647 }
16648 }
16649 }
16650 }
16651
16652 return lines;
16653 };
16654
16655 Renderer.prototype.RenderTextFragment = function (text, style) {
16656 var defaultFontSize, font, maxLineHeight;
16657 maxLineHeight = 0;
16658 defaultFontSize = 12;
16659
16660 if (this.pdf.internal.pageSize.getHeight() - this.pdf.margins_doc.bottom < this.y + this.pdf.internal.getFontSize()) {
16661 this.pdf.internal.write("ET", "Q");
16662 this.pdf.addPage();
16663 this.y = this.pdf.margins_doc.top;
16664 this.pdf.internal.write("q", "BT", this.getPdfColor(style.color), this.pdf.internal.getCoordinateString(this.x), this.pdf.internal.getVerticalCoordinateString(this.y), "Td"); //move cursor by one line on new page
16665
16666 maxLineHeight = Math.max(maxLineHeight, style["line-height"], style["font-size"]);
16667 this.pdf.internal.write(0, (-1 * defaultFontSize * maxLineHeight).toFixed(2), "Td");
16668 }
16669
16670 font = this.pdf.internal.getFont(style["font-family"], style["font-style"]); // text color
16671
16672 var pdfTextColor = this.getPdfColor(style["color"]);
16673
16674 if (pdfTextColor !== this.lastTextColor) {
16675 this.pdf.internal.write(pdfTextColor);
16676 this.lastTextColor = pdfTextColor;
16677 } //set the word spacing for e.g. justify style
16678
16679
16680 if (style['word-spacing'] !== undefined && style['word-spacing'] > 0) {
16681 this.pdf.internal.write(style['word-spacing'].toFixed(2), "Tw");
16682 }
16683
16684 this.pdf.internal.write("/" + font.id, (defaultFontSize * style["font-size"]).toFixed(2), "Tf", "(" + this.pdf.internal.pdfEscape(text) + ") Tj"); //set the word spacing back to neutral => 0
16685
16686 if (style['word-spacing'] !== undefined) {
16687 this.pdf.internal.write(0, "Tw");
16688 }
16689 }; // Accepts #FFFFFF, rgb(int,int,int), or CSS Color Name
16690
16691
16692 Renderer.prototype.getPdfColor = function (style) {
16693 var textColor;
16694 var r, g, b;
16695 var rx = /rgb\s*\(\s*(\d+),\s*(\d+),\s*(\d+\s*)\)/;
16696 var m = rx.exec(style);
16697
16698 if (m != null) {
16699 r = parseInt(m[1]);
16700 g = parseInt(m[2]);
16701 b = parseInt(m[3]);
16702 } else {
16703 if (typeof style === "string" && style.charAt(0) != '#') {
16704 var rgbColor = new RGBColor(style);
16705
16706 if (rgbColor.ok) {
16707 style = rgbColor.toHex();
16708 } else {
16709 style = '#000000';
16710 }
16711 }
16712
16713 r = style.substring(1, 3);
16714 r = parseInt(r, 16);
16715 g = style.substring(3, 5);
16716 g = parseInt(g, 16);
16717 b = style.substring(5, 7);
16718 b = parseInt(b, 16);
16719 }
16720
16721 if (typeof r === 'string' && /^#[0-9A-Fa-f]{6}$/.test(r)) {
16722 var hex = parseInt(r.substr(1), 16);
16723 r = hex >> 16 & 255;
16724 g = hex >> 8 & 255;
16725 b = hex & 255;
16726 }
16727
16728 var f3 = this.f3;
16729
16730 if (r === 0 && g === 0 && b === 0 || typeof g === 'undefined') {
16731 textColor = f3(r / 255) + ' g';
16732 } else {
16733 textColor = [f3(r / 255), f3(g / 255), f3(b / 255), 'rg'].join(' ');
16734 }
16735
16736 return textColor;
16737 };
16738
16739 Renderer.prototype.f3 = function (number) {
16740 return number.toFixed(3); // Ie, %.3f
16741 }, Renderer.prototype.renderParagraph = function (cb) {
16742 var blockstyle, defaultFontSize, fontToUnitRatio, fragments, i, l, line, lines, maxLineHeight, out, paragraphspacing_after, paragraphspacing_before, priorblockstyle, styles, fontSize;
16743 fragments = PurgeWhiteSpace(this.paragraph.text);
16744 styles = this.paragraph.style;
16745 blockstyle = this.paragraph.blockstyle;
16746 priorblockstyle = this.paragraph.priorblockstyle || {};
16747 this.paragraph = {
16748 text: [],
16749 style: [],
16750 blockstyle: {},
16751 priorblockstyle: blockstyle
16752 };
16753
16754 if (!fragments.join("").trim()) {
16755 return;
16756 }
16757
16758 lines = this.splitFragmentsIntoLines(fragments, styles);
16759 line = void 0;
16760 maxLineHeight = void 0;
16761 defaultFontSize = 12;
16762 fontToUnitRatio = defaultFontSize / this.pdf.internal.scaleFactor;
16763 this.priorMarginBottom = this.priorMarginBottom || 0;
16764 paragraphspacing_before = (Math.max((blockstyle["margin-top"] || 0) - this.priorMarginBottom, 0) + (blockstyle["padding-top"] || 0)) * fontToUnitRatio;
16765 paragraphspacing_after = ((blockstyle["margin-bottom"] || 0) + (blockstyle["padding-bottom"] || 0)) * fontToUnitRatio;
16766 this.priorMarginBottom = blockstyle["margin-bottom"] || 0;
16767
16768 if (blockstyle['page-break-before'] === 'always') {
16769 this.pdf.addPage();
16770 this.y = 0;
16771 paragraphspacing_before = ((blockstyle["margin-top"] || 0) + (blockstyle["padding-top"] || 0)) * fontToUnitRatio;
16772 }
16773
16774 out = this.pdf.internal.write;
16775 i = void 0;
16776 l = void 0;
16777 this.y += paragraphspacing_before;
16778 out("q", "BT 0 g", this.pdf.internal.getCoordinateString(this.x), this.pdf.internal.getVerticalCoordinateString(this.y), "Td"); //stores the current indent of cursor position
16779
16780 var currentIndent = 0;
16781
16782 while (lines.length) {
16783 line = lines.shift();
16784 maxLineHeight = 0;
16785 i = 0;
16786 l = line.length;
16787
16788 while (i !== l) {
16789 if (line[i][0].trim()) {
16790 maxLineHeight = Math.max(maxLineHeight, line[i][1]["line-height"], line[i][1]["font-size"]);
16791 fontSize = line[i][1]["font-size"] * 7;
16792 }
16793
16794 i++;
16795 } //if we have to move the cursor to adapt the indent
16796
16797
16798 var indentMove = 0;
16799 var wantedIndent = 0; //if a margin was added (by e.g. a text-alignment), move the cursor
16800
16801 if (line[0][1]["margin-left"] !== undefined && line[0][1]["margin-left"] > 0) {
16802 wantedIndent = this.pdf.internal.getCoordinateString(line[0][1]["margin-left"]);
16803 indentMove = wantedIndent - currentIndent;
16804 currentIndent = wantedIndent;
16805 }
16806
16807 var indentMore = Math.max(blockstyle["margin-left"] || 0, 0) * fontToUnitRatio; //move the cursor
16808
16809 out(indentMove + indentMore, (-1 * defaultFontSize * maxLineHeight).toFixed(2), "Td");
16810 i = 0;
16811 l = line.length;
16812
16813 while (i !== l) {
16814 if (line[i][0]) {
16815 this.RenderTextFragment(line[i][0], line[i][1]);
16816 }
16817
16818 i++;
16819 }
16820
16821 this.y += maxLineHeight * fontToUnitRatio; //if some watcher function was executed successful, so e.g. margin and widths were changed,
16822 //reset line drawing and calculate position and lines again
16823 //e.g. to stop text floating around an image
16824
16825 if (this.executeWatchFunctions(line[0][1]) && lines.length > 0) {
16826 var localFragments = [];
16827 var localStyles = []; //create fragment array of
16828
16829 lines.forEach(function (localLine) {
16830 var i = 0;
16831 var l = localLine.length;
16832
16833 while (i !== l) {
16834 if (localLine[i][0]) {
16835 localFragments.push(localLine[i][0] + ' ');
16836 localStyles.push(localLine[i][1]);
16837 }
16838
16839 ++i;
16840 }
16841 }); //split lines again due to possible coordinate changes
16842
16843 lines = this.splitFragmentsIntoLines(PurgeWhiteSpace(localFragments), localStyles); //reposition the current cursor
16844
16845 out("ET", "Q");
16846 out("q", "BT 0 g", this.pdf.internal.getCoordinateString(this.x), this.pdf.internal.getVerticalCoordinateString(this.y), "Td");
16847 }
16848 }
16849
16850 if (cb && typeof cb === "function") {
16851 cb.call(this, this.x - 9, this.y - fontSize / 2);
16852 }
16853
16854 out("ET", "Q");
16855 return this.y += paragraphspacing_after;
16856 };
16857
16858 Renderer.prototype.setBlockBoundary = function (cb) {
16859 return this.renderParagraph(cb);
16860 };
16861
16862 Renderer.prototype.setBlockStyle = function (css) {
16863 return this.paragraph.blockstyle = css;
16864 };
16865
16866 Renderer.prototype.addText = function (text, css) {
16867 this.paragraph.text.push(text);
16868 return this.paragraph.style.push(css);
16869 };
16870
16871 FontNameDB = {
16872 helvetica: "helvetica",
16873 "sans-serif": "helvetica",
16874 "times new roman": "times",
16875 serif: "times",
16876 times: "times",
16877 monospace: "courier",
16878 courier: "courier"
16879 };
16880 FontWeightMap = {
16881 100: "normal",
16882 200: "normal",
16883 300: "normal",
16884 400: "normal",
16885 500: "bold",
16886 600: "bold",
16887 700: "bold",
16888 800: "bold",
16889 900: "bold",
16890 normal: "normal",
16891 bold: "bold",
16892 bolder: "bold",
16893 lighter: "normal"
16894 };
16895 FontStyleMap = {
16896 normal: "normal",
16897 italic: "italic",
16898 oblique: "italic"
16899 };
16900 TextAlignMap = {
16901 left: "left",
16902 right: "right",
16903 center: "center",
16904 justify: "justify"
16905 };
16906 FloatMap = {
16907 none: 'none',
16908 right: 'right',
16909 left: 'left'
16910 };
16911 ClearMap = {
16912 none: 'none',
16913 both: 'both'
16914 };
16915 UnitedNumberMap = {
16916 normal: 1
16917 };
16918 /**
16919 * Converts HTML-formatted text into formatted PDF text.
16920 *
16921 * Notes:
16922 * 2012-07-18
16923 * Plugin relies on having browser, DOM around. The HTML is pushed into dom and traversed.
16924 * Plugin relies on jQuery for CSS extraction.
16925 * Targeting HTML output from Markdown templating, which is a very simple
16926 * markup - div, span, em, strong, p. No br-based paragraph separation supported explicitly (but still may work.)
16927 * Images, tables are NOT supported.
16928 *
16929 * @public
16930 * @function
16931 * @param HTML {String|Object} HTML-formatted text, or pointer to DOM element that is to be rendered into PDF.
16932 * @param x {Number} starting X coordinate in jsPDF instance's declared units.
16933 * @param y {Number} starting Y coordinate in jsPDF instance's declared units.
16934 * @param settings {Object} Additional / optional variables controlling parsing, rendering.
16935 * @returns {Object} jsPDF instance
16936 */
16937
16938 jsPDFAPI.fromHTML = function (HTML, x, y, settings, callback, margins) {
16939
16940 this.margins_doc = margins || {
16941 top: 0,
16942 bottom: 0
16943 };
16944 if (!settings) settings = {};
16945 if (!settings.elementHandlers) settings.elementHandlers = {};
16946 return process(this, HTML, isNaN(x) ? 4 : x, isNaN(y) ? 4 : y, settings, callback);
16947 };
16948 })(jsPDF.API);
16949
16950 /**
16951 * html2pdf.js
16952 * Copyright (c) 2014 Steven Spungin (TwelveTone LLC) steven@twelvetone.tv
16953 *
16954 * Licensed under the MIT License.
16955 * http://opensource.org/licenses/mit-license
16956 */
16957 (function (jsPDFAPI, globalObj) {
16958 globalObj.html2pdf = function (html, pdf, callback) {
16959 var canvas = pdf.canvas;
16960
16961 if (!canvas) {
16962 alert('jsPDF canvas plugin not installed');
16963 return;
16964 }
16965
16966 canvas.pdf = pdf;
16967 pdf.annotations = {
16968 _nameMap: [],
16969 createAnnotation: function createAnnotation(href, bounds) {
16970 var x = pdf.context2d._wrapX(bounds.left);
16971
16972 var y = pdf.context2d._wrapY(bounds.top);
16973
16974 var page = pdf.context2d._page(bounds.top);
16975
16976 var options;
16977 var index = href.indexOf('#');
16978
16979 if (index >= 0) {
16980 options = {
16981 name: href.substring(index + 1)
16982 };
16983 } else {
16984 options = {
16985 url: href
16986 };
16987 }
16988
16989 pdf.link(x, y, bounds.right - bounds.left, bounds.bottom - bounds.top, options);
16990 },
16991 setName: function setName(name, bounds) {
16992 var x = pdf.context2d._wrapX(bounds.left);
16993
16994 var y = pdf.context2d._wrapY(bounds.top);
16995
16996 var page = pdf.context2d._page(bounds.top);
16997
16998 this._nameMap[name] = {
16999 page: page,
17000 x: x,
17001 y: y
17002 };
17003 }
17004 };
17005 canvas.annotations = pdf.annotations;
17006
17007 pdf.context2d._pageBreakAt = function (y) {
17008 this.pageBreaks.push(y);
17009 };
17010
17011 pdf.context2d._gotoPage = function (pageOneBased) {
17012 while (pdf.internal.getNumberOfPages() < pageOneBased) {
17013 pdf.addPage();
17014 }
17015
17016 pdf.setPage(pageOneBased);
17017 };
17018
17019 var htmlElement;
17020 var height;
17021
17022 if (typeof html === 'string') {
17023 // remove all scripts
17024 html = html.replace(/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi, '');
17025 var iframe = document.createElement('iframe'); //iframe.style.width = canvas.width;
17026 //iframe.src = "";
17027 //iframe.document.domain =
17028
17029 document.body.appendChild(iframe);
17030 var doc;
17031 var body;
17032 doc = iframe.contentDocument;
17033
17034 if (doc == undefined || doc == null) {
17035 doc = iframe.contentWindow.document;
17036 } //iframe.setAttribute('style', 'position:absolute;right:0; top:0; bottom:0; height:100%; width:500px');
17037
17038
17039 doc.open();
17040 doc.write(html);
17041 doc.close();
17042 htmlElement = doc.body;
17043 body = doc.body || {}, html = doc.documentElement || {};
17044 height = Math.max(body.scrollHeight, body.offsetHeight, html.clientHeight, html.scrollHeight, html.offsetHeight);
17045 } else {
17046 htmlElement = html;
17047 body = html.body || {}, height = Math.max(body.scrollHeight, body.offsetHeight, html.clientHeight, html.scrollHeight, html.offsetHeight);
17048 }
17049
17050 height = pdf.internal.pageSize.getHeight();
17051 var options = {
17052 async: true,
17053 allowTaint: true,
17054 backgroundColor: '#ffffff',
17055 canvas: canvas,
17056 imageTimeout: 15000,
17057 logging: true,
17058 proxy: null,
17059 removeContainer: true,
17060 foreignObjectRendering: false,
17061 useCORS: false,
17062 windowHeight: height,
17063 scrollY: height
17064 };
17065 pdf.context2d.pageWrapYEnabled = true;
17066 pdf.context2d.pageWrapY = pdf.internal.pageSize.getHeight();
17067 var promise = html2canvas(htmlElement, options).then(function (canvas) {
17068 if (callback) {
17069 if (iframe) {
17070 iframe.parentElement.removeChild(iframe);
17071 }
17072
17073 callback(pdf);
17074 }
17075 });
17076 };
17077 })(jsPDF.API, typeof window !== "undefined" && window || typeof global !== "undefined" && global);
17078 /*rollup-keeper-start*/
17079
17080
17081 window.tmp = html2pdf;
17082 /*rollup-keeper-end*/
17083
17084 /* Blob.js
17085 * A Blob, File, FileReader & URL implementation.
17086 * 2018-08-09
17087 *
17088 * By Eli Grey, http://eligrey.com
17089 * By Jimmy Wärting, https://github.com/jimmywarting
17090 * License: MIT
17091 * See https://github.com/eligrey/Blob.js/blob/master/LICENSE.md
17092 */
17093
17094 (function (global) {
17095 var BlobBuilder = global.BlobBuilder || global.WebKitBlobBuilder || global.MSBlobBuilder || global.MozBlobBuilder;
17096
17097 global.URL = global.URL || global.webkitURL || function (href, a) {
17098 a = document.createElement('a');
17099 a.href = href;
17100 return a;
17101 };
17102
17103 var origBlob = global.Blob;
17104 var createObjectURL = URL.createObjectURL;
17105 var revokeObjectURL = URL.revokeObjectURL;
17106 var strTag = global.Symbol && global.Symbol.toStringTag;
17107 var blobSupported = false;
17108 var blobSupportsArrayBufferView = false;
17109 var arrayBufferSupported = !!global.ArrayBuffer;
17110 var blobBuilderSupported = BlobBuilder && BlobBuilder.prototype.append && BlobBuilder.prototype.getBlob;
17111
17112 try {
17113 // Check if Blob constructor is supported
17114 blobSupported = new Blob(['ä']).size === 2; // Check if Blob constructor supports ArrayBufferViews
17115 // Fails in Safari 6, so we need to map to ArrayBuffers there.
17116
17117 blobSupportsArrayBufferView = new Blob([new Uint8Array([1, 2])]).size === 2;
17118 } catch (e) {}
17119 /**
17120 * Helper function that maps ArrayBufferViews to ArrayBuffers
17121 * Used by BlobBuilder constructor and old browsers that didn't
17122 * support it in the Blob constructor.
17123 */
17124
17125
17126 function mapArrayBufferViews(ary) {
17127 return ary.map(function (chunk) {
17128 if (chunk.buffer instanceof ArrayBuffer) {
17129 var buf = chunk.buffer; // if this is a subarray, make a copy so we only
17130 // include the subarray region from the underlying buffer
17131
17132 if (chunk.byteLength !== buf.byteLength) {
17133 var copy = new Uint8Array(chunk.byteLength);
17134 copy.set(new Uint8Array(buf, chunk.byteOffset, chunk.byteLength));
17135 buf = copy.buffer;
17136 }
17137
17138 return buf;
17139 }
17140
17141 return chunk;
17142 });
17143 }
17144
17145 function BlobBuilderConstructor(ary, options) {
17146 options = options || {};
17147 var bb = new BlobBuilder();
17148 mapArrayBufferViews(ary).forEach(function (part) {
17149 bb.append(part);
17150 });
17151 return options.type ? bb.getBlob(options.type) : bb.getBlob();
17152 }
17153
17154 function BlobConstructor(ary, options) {
17155 return new origBlob(mapArrayBufferViews(ary), options || {});
17156 }
17157
17158 if (global.Blob) {
17159 BlobBuilderConstructor.prototype = Blob.prototype;
17160 BlobConstructor.prototype = Blob.prototype;
17161 }
17162
17163 function FakeBlobBuilder() {
17164 function toUTF8Array(str) {
17165 var utf8 = [];
17166
17167 for (var i = 0; i < str.length; i++) {
17168 var charcode = str.charCodeAt(i);
17169 if (charcode < 0x80) utf8.push(charcode);else if (charcode < 0x800) {
17170 utf8.push(0xc0 | charcode >> 6, 0x80 | charcode & 0x3f);
17171 } else if (charcode < 0xd800 || charcode >= 0xe000) {
17172 utf8.push(0xe0 | charcode >> 12, 0x80 | charcode >> 6 & 0x3f, 0x80 | charcode & 0x3f);
17173 } // surrogate pair
17174 else {
17175 i++; // UTF-16 encodes 0x10000-0x10FFFF by
17176 // subtracting 0x10000 and splitting the
17177 // 20 bits of 0x0-0xFFFFF into two halves
17178
17179 charcode = 0x10000 + ((charcode & 0x3ff) << 10 | str.charCodeAt(i) & 0x3ff);
17180 utf8.push(0xf0 | charcode >> 18, 0x80 | charcode >> 12 & 0x3f, 0x80 | charcode >> 6 & 0x3f, 0x80 | charcode & 0x3f);
17181 }
17182 }
17183
17184 return utf8;
17185 }
17186
17187 function fromUtf8Array(array) {
17188 var out, i, len, c;
17189 var char2, char3;
17190 out = "";
17191 len = array.length;
17192 i = 0;
17193
17194 while (i < len) {
17195 c = array[i++];
17196
17197 switch (c >> 4) {
17198 case 0:
17199 case 1:
17200 case 2:
17201 case 3:
17202 case 4:
17203 case 5:
17204 case 6:
17205 case 7:
17206 // 0xxxxxxx
17207 out += String.fromCharCode(c);
17208 break;
17209
17210 case 12:
17211 case 13:
17212 // 110x xxxx 10xx xxxx
17213 char2 = array[i++];
17214 out += String.fromCharCode((c & 0x1F) << 6 | char2 & 0x3F);
17215 break;
17216
17217 case 14:
17218 // 1110 xxxx 10xx xxxx 10xx xxxx
17219 char2 = array[i++];
17220 char3 = array[i++];
17221 out += String.fromCharCode((c & 0x0F) << 12 | (char2 & 0x3F) << 6 | (char3 & 0x3F) << 0);
17222 break;
17223 }
17224 }
17225
17226 return out;
17227 }
17228
17229 function isDataView(obj) {
17230 return obj && DataView.prototype.isPrototypeOf(obj);
17231 }
17232
17233 function bufferClone(buf) {
17234 var view = new Array(buf.byteLength);
17235 var array = new Uint8Array(buf);
17236 var i = view.length;
17237
17238 while (i--) {
17239 view[i] = array[i];
17240 }
17241
17242 return view;
17243 }
17244
17245 function encodeByteArray(input) {
17246 var byteToCharMap = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
17247 var output = [];
17248
17249 for (var i = 0; i < input.length; i += 3) {
17250 var byte1 = input[i];
17251 var haveByte2 = i + 1 < input.length;
17252 var byte2 = haveByte2 ? input[i + 1] : 0;
17253 var haveByte3 = i + 2 < input.length;
17254 var byte3 = haveByte3 ? input[i + 2] : 0;
17255 var outByte1 = byte1 >> 2;
17256 var outByte2 = (byte1 & 0x03) << 4 | byte2 >> 4;
17257 var outByte3 = (byte2 & 0x0F) << 2 | byte3 >> 6;
17258 var outByte4 = byte3 & 0x3F;
17259
17260 if (!haveByte3) {
17261 outByte4 = 64;
17262
17263 if (!haveByte2) {
17264 outByte3 = 64;
17265 }
17266 }
17267
17268 output.push(byteToCharMap[outByte1], byteToCharMap[outByte2], byteToCharMap[outByte3], byteToCharMap[outByte4]);
17269 }
17270
17271 return output.join('');
17272 }
17273
17274 var create = Object.create || function (a) {
17275 function c() {}
17276
17277 c.prototype = a;
17278 return new c();
17279 };
17280
17281 if (arrayBufferSupported) {
17282 var viewClasses = ['[object Int8Array]', '[object Uint8Array]', '[object Uint8ClampedArray]', '[object Int16Array]', '[object Uint16Array]', '[object Int32Array]', '[object Uint32Array]', '[object Float32Array]', '[object Float64Array]'];
17283
17284 var isArrayBufferView = ArrayBuffer.isView || function (obj) {
17285 return obj && viewClasses.indexOf(Object.prototype.toString.call(obj)) > -1;
17286 };
17287 }
17288 /********************************************************/
17289
17290 /* Blob constructor */
17291
17292 /********************************************************/
17293
17294
17295 function Blob(chunks, opts) {
17296 chunks = chunks || [];
17297
17298 for (var i = 0, len = chunks.length; i < len; i++) {
17299 var chunk = chunks[i];
17300
17301 if (chunk instanceof Blob) {
17302 chunks[i] = chunk._buffer;
17303 } else if (typeof chunk === 'string') {
17304 chunks[i] = toUTF8Array(chunk);
17305 } else if (arrayBufferSupported && (ArrayBuffer.prototype.isPrototypeOf(chunk) || isArrayBufferView(chunk))) {
17306 chunks[i] = bufferClone(chunk);
17307 } else if (arrayBufferSupported && isDataView(chunk)) {
17308 chunks[i] = bufferClone(chunk.buffer);
17309 } else {
17310 chunks[i] = toUTF8Array(String(chunk));
17311 }
17312 }
17313
17314 this._buffer = [].concat.apply([], chunks);
17315 this.size = this._buffer.length;
17316 this.type = opts ? opts.type || '' : '';
17317 }
17318
17319 Blob.prototype.slice = function (start, end, type) {
17320 var slice = this._buffer.slice(start || 0, end || this._buffer.length);
17321
17322 return new Blob([slice], {
17323 type: type
17324 });
17325 };
17326
17327 Blob.prototype.toString = function () {
17328 return '[object Blob]';
17329 };
17330 /********************************************************/
17331
17332 /* File constructor */
17333
17334 /********************************************************/
17335
17336
17337 function File(chunks, name, opts) {
17338 opts = opts || {};
17339 var a = Blob.call(this, chunks, opts) || this;
17340 a.name = name;
17341 a.lastModifiedDate = opts.lastModified ? new Date(opts.lastModified) : new Date();
17342 a.lastModified = +a.lastModifiedDate;
17343 return a;
17344 }
17345
17346 File.prototype = create(Blob.prototype);
17347 File.prototype.constructor = File;
17348 if (Object.setPrototypeOf) Object.setPrototypeOf(File, Blob);else {
17349 try {
17350 File.__proto__ = Blob;
17351 } catch (e) {}
17352 }
17353
17354 File.prototype.toString = function () {
17355 return '[object File]';
17356 };
17357 /********************************************************/
17358
17359 /* FileReader constructor */
17360
17361 /********************************************************/
17362
17363
17364 function FileReader() {
17365 if (!(this instanceof FileReader)) throw new TypeError("Failed to construct 'FileReader': Please use the 'new' operator, this DOM object constructor cannot be called as a function.");
17366 var delegate = document.createDocumentFragment();
17367 this.addEventListener = delegate.addEventListener;
17368
17369 this.dispatchEvent = function (evt) {
17370 var local = this['on' + evt.type];
17371 if (typeof local === 'function') local(evt);
17372 delegate.dispatchEvent(evt);
17373 };
17374
17375 this.removeEventListener = delegate.removeEventListener;
17376 }
17377
17378 function _read(fr, blob, kind) {
17379 if (!(blob instanceof Blob)) throw new TypeError("Failed to execute '" + kind + "' on 'FileReader': parameter 1 is not of type 'Blob'.");
17380 fr.result = '';
17381 setTimeout(function () {
17382 this.readyState = FileReader.LOADING;
17383 fr.dispatchEvent(new Event('load'));
17384 fr.dispatchEvent(new Event('loadend'));
17385 });
17386 }
17387
17388 FileReader.EMPTY = 0;
17389 FileReader.LOADING = 1;
17390 FileReader.DONE = 2;
17391 FileReader.prototype.error = null;
17392 FileReader.prototype.onabort = null;
17393 FileReader.prototype.onerror = null;
17394 FileReader.prototype.onload = null;
17395 FileReader.prototype.onloadend = null;
17396 FileReader.prototype.onloadstart = null;
17397 FileReader.prototype.onprogress = null;
17398
17399 FileReader.prototype.readAsDataURL = function (blob) {
17400 _read(this, blob, 'readAsDataURL');
17401
17402 this.result = 'data:' + blob.type + ';base64,' + encodeByteArray(blob._buffer);
17403 };
17404
17405 FileReader.prototype.readAsText = function (blob) {
17406 _read(this, blob, 'readAsText');
17407
17408 this.result = fromUtf8Array(blob._buffer);
17409 };
17410
17411 FileReader.prototype.readAsArrayBuffer = function (blob) {
17412 _read(this, blob, 'readAsText');
17413
17414 this.result = blob._buffer.slice();
17415 };
17416
17417 FileReader.prototype.abort = function () {};
17418 /********************************************************/
17419
17420 /* URL */
17421
17422 /********************************************************/
17423
17424
17425 URL.createObjectURL = function (blob) {
17426 return blob instanceof Blob ? 'data:' + blob.type + ';base64,' + encodeByteArray(blob._buffer) : createObjectURL.call(URL, blob);
17427 };
17428
17429 URL.revokeObjectURL = function (url) {
17430 revokeObjectURL && revokeObjectURL.call(URL, url);
17431 };
17432 /********************************************************/
17433
17434 /* XHR */
17435
17436 /********************************************************/
17437
17438
17439 var _send = global.XMLHttpRequest && global.XMLHttpRequest.prototype.send;
17440
17441 if (_send) {
17442 XMLHttpRequest.prototype.send = function (data) {
17443 if (data instanceof Blob) {
17444 this.setRequestHeader('Content-Type', data.type);
17445
17446 _send.call(this, fromUtf8Array(data._buffer));
17447 } else {
17448 _send.call(this, data);
17449 }
17450 };
17451 }
17452
17453 global.FileReader = FileReader;
17454 global.File = File;
17455 global.Blob = Blob;
17456 }
17457
17458 if (strTag) {
17459 try {
17460 File.prototype[strTag] = 'File';
17461 Blob.prototype[strTag] = 'Blob';
17462 FileReader.prototype[strTag] = 'FileReader';
17463 } catch (e) {}
17464 }
17465
17466 function fixFileAndXHR() {
17467 var isIE = !!global.ActiveXObject || '-ms-scroll-limit' in document.documentElement.style && '-ms-ime-align' in document.documentElement.style; // Monkey patched
17468 // IE don't set Content-Type header on XHR whose body is a typed Blob
17469 // https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/6047383
17470
17471 var _send = global.XMLHttpRequest && global.XMLHttpRequest.prototype.send;
17472
17473 if (isIE && _send) {
17474 XMLHttpRequest.prototype.send = function (data) {
17475 if (data instanceof Blob) {
17476 this.setRequestHeader('Content-Type', data.type);
17477
17478 _send.call(this, data);
17479 } else {
17480 _send.call(this, data);
17481 }
17482 };
17483 }
17484
17485 try {
17486 new File([], '');
17487 } catch (e) {
17488 try {
17489 var klass = new Function('class File extends Blob {' + 'constructor(chunks, name, opts) {' + 'opts = opts || {};' + 'super(chunks, opts || {});' + 'this.name = name;' + 'this.lastModifiedDate = opts.lastModified ? new Date(opts.lastModified) : new Date;' + 'this.lastModified = +this.lastModifiedDate;' + '}};' + 'return new File([], ""), File')();
17490 global.File = klass;
17491 } catch (e) {
17492 var klass = function klass(b, d, c) {
17493 var blob = new Blob(b, c);
17494 var t = c && void 0 !== c.lastModified ? new Date(c.lastModified) : new Date();
17495 blob.name = d;
17496 blob.lastModifiedDate = t;
17497 blob.lastModified = +t;
17498
17499 blob.toString = function () {
17500 return '[object File]';
17501 };
17502
17503 if (strTag) blob[strTag] = 'File';
17504 return blob;
17505 };
17506
17507 global.File = klass;
17508 }
17509 }
17510 }
17511
17512 if (blobSupported) {
17513 fixFileAndXHR();
17514 global.Blob = blobSupportsArrayBufferView ? global.Blob : BlobConstructor;
17515 } else if (blobBuilderSupported) {
17516 fixFileAndXHR();
17517 global.Blob = BlobBuilderConstructor;
17518 } else {
17519 FakeBlobBuilder();
17520 }
17521 })(typeof self !== "undefined" && self || typeof window !== "undefined" && window || typeof global !== "undefined" && global || Function('return typeof this === "object" && this.content')() || Function('return this')());
17522
17523 /* FileSaver.js
17524 * A saveAs() FileSaver implementation.
17525 * 1.3.8
17526 * 2018-03-22 14:03:47
17527 *
17528 * By Eli Grey, https://eligrey.com
17529 * License: MIT
17530 * See https://github.com/eligrey/FileSaver.js/blob/master/LICENSE.md
17531 */
17532
17533 /*global self */
17534
17535 /*jslint bitwise: true, indent: 4, laxbreak: true, laxcomma: true, smarttabs: true, plusplus: true */
17536
17537 /*! @source http://purl.eligrey.com/github/FileSaver.js/blob/master/src/FileSaver.js */
17538 var saveAs = saveAs || function (view) {
17539
17540 if (typeof view === "undefined" || typeof navigator !== "undefined" && /MSIE [1-9]\./.test(navigator.userAgent)) {
17541 return;
17542 }
17543
17544 var doc = view.document // only get URL when necessary in case Blob.js hasn't overridden it yet
17545 ,
17546 get_URL = function () {
17547 return view.URL || view.webkitURL || view;
17548 },
17549 save_link = doc.createElementNS("http://www.w3.org/1999/xhtml", "a"),
17550 can_use_save_link = "download" in save_link,
17551 click = function (node) {
17552 var event = new MouseEvent("click");
17553 node.dispatchEvent(event);
17554 },
17555 is_safari = /constructor/i.test(view.HTMLElement) || view.safari,
17556 is_chrome_ios = /CriOS\/[\d]+/.test(navigator.userAgent),
17557 setImmediate = view.setImmediate || view.setTimeout,
17558 throw_outside = function (ex) {
17559 setImmediate(function () {
17560 throw ex;
17561 }, 0);
17562 },
17563 force_saveable_type = "application/octet-stream" // the Blob API is fundamentally broken as there is no "downloadfinished" event to subscribe to
17564 ,
17565 arbitrary_revoke_timeout = 1000 * 40 // in ms
17566 ,
17567 revoke = function (file) {
17568 var revoker = function () {
17569 if (typeof file === "string") {
17570 // file is an object URL
17571 get_URL().revokeObjectURL(file);
17572 } else {
17573 // file is a File
17574 file.remove();
17575 }
17576 };
17577
17578 setTimeout(revoker, arbitrary_revoke_timeout);
17579 },
17580 dispatch = function (filesaver, event_types, event) {
17581 event_types = [].concat(event_types);
17582 var i = event_types.length;
17583
17584 while (i--) {
17585 var listener = filesaver["on" + event_types[i]];
17586
17587 if (typeof listener === "function") {
17588 try {
17589 listener.call(filesaver, event || filesaver);
17590 } catch (ex) {
17591 throw_outside(ex);
17592 }
17593 }
17594 }
17595 },
17596 auto_bom = function (blob) {
17597 // prepend BOM for UTF-8 XML and text/* types (including HTML)
17598 // note: your browser will automatically convert UTF-16 U+FEFF to EF BB BF
17599 if (/^\s*(?:text\/\S*|application\/xml|\S*\/\S*\+xml)\s*;.*charset\s*=\s*utf-8/i.test(blob.type)) {
17600 return new Blob([String.fromCharCode(0xFEFF), blob], {
17601 type: blob.type
17602 });
17603 }
17604
17605 return blob;
17606 },
17607 FileSaver = function (blob, name, no_auto_bom) {
17608 if (!no_auto_bom) {
17609 blob = auto_bom(blob);
17610 } // First try a.download, then web filesystem, then object URLs
17611
17612
17613 var filesaver = this,
17614 type = blob.type,
17615 force = type === force_saveable_type,
17616 object_url,
17617 dispatch_all = function () {
17618 dispatch(filesaver, "writestart progress write writeend".split(" "));
17619 } // on any filesys errors revert to saving with object URLs
17620 ,
17621 fs_error = function () {
17622 if ((is_chrome_ios || force && is_safari) && view.FileReader) {
17623 // Safari doesn't allow downloading of blob urls
17624 var reader = new FileReader();
17625
17626 reader.onloadend = function () {
17627 var url = is_chrome_ios ? reader.result : reader.result.replace(/^data:[^;]*;/, 'data:attachment/file;');
17628 var popup = view.open(url, '_blank');
17629 if (!popup) view.location.href = url;
17630 url = undefined; // release reference before dispatching
17631
17632 filesaver.readyState = filesaver.DONE;
17633 dispatch_all();
17634 };
17635
17636 reader.readAsDataURL(blob);
17637 filesaver.readyState = filesaver.INIT;
17638 return;
17639 } // don't create more object URLs than needed
17640
17641
17642 if (!object_url) {
17643 object_url = get_URL().createObjectURL(blob);
17644 }
17645
17646 if (force) {
17647 view.location.href = object_url;
17648 } else {
17649 var opened = view.open(object_url, "_blank");
17650
17651 if (!opened) {
17652 // Apple does not allow window.open, see https://developer.apple.com/library/safari/documentation/Tools/Conceptual/SafariExtensionGuide/WorkingwithWindowsandTabs/WorkingwithWindowsandTabs.html
17653 view.location.href = object_url;
17654 }
17655 }
17656
17657 filesaver.readyState = filesaver.DONE;
17658 dispatch_all();
17659 revoke(object_url);
17660 };
17661
17662 filesaver.readyState = filesaver.INIT;
17663
17664 if (can_use_save_link) {
17665 object_url = get_URL().createObjectURL(blob);
17666 setImmediate(function () {
17667 save_link.href = object_url;
17668 save_link.download = name;
17669 click(save_link);
17670 dispatch_all();
17671 revoke(object_url);
17672 filesaver.readyState = filesaver.DONE;
17673 }, 0);
17674 return;
17675 }
17676
17677 fs_error();
17678 },
17679 FS_proto = FileSaver.prototype,
17680 saveAs = function (blob, name, no_auto_bom) {
17681 return new FileSaver(blob, name || blob.name || "download", no_auto_bom);
17682 }; // IE 10+ (native saveAs)
17683
17684
17685 if (typeof navigator !== "undefined" && navigator.msSaveOrOpenBlob) {
17686 return function (blob, name, no_auto_bom) {
17687 name = name || blob.name || "download";
17688
17689 if (!no_auto_bom) {
17690 blob = auto_bom(blob);
17691 }
17692
17693 return navigator.msSaveOrOpenBlob(blob, name);
17694 };
17695 } // todo: detect chrome extensions & packaged apps
17696 //save_link.target = "_blank";
17697
17698
17699 FS_proto.abort = function () {};
17700
17701 FS_proto.readyState = FS_proto.INIT = 0;
17702 FS_proto.WRITING = 1;
17703 FS_proto.DONE = 2;
17704 FS_proto.error = FS_proto.onwritestart = FS_proto.onprogress = FS_proto.onwrite = FS_proto.onabort = FS_proto.onerror = FS_proto.onwriteend = null;
17705 return saveAs;
17706 }(typeof self !== "undefined" && self || typeof window !== "undefined" && window || undefined);
17707
17708 // (c) Dean McNamee <dean@gmail.com>, 2013.
17709 //
17710 // https://github.com/deanm/omggif
17711 //
17712 //
17713 //
17714 // omggif is a JavaScript implementation of a GIF 89a encoder and decoder,
17715 // including animation and compression. It does not rely on any specific
17716 // underlying system, so should run in the browser, Node, or Plask.
17717 function GifWriter(buf, width, height, gopts) {
17718 var p = 0;
17719 var gopts = gopts === undefined ? {} : gopts;
17720 var loop_count = gopts.loop === undefined ? null : gopts.loop;
17721 var global_palette = gopts.palette === undefined ? null : gopts.palette;
17722 if (width <= 0 || height <= 0 || width > 65535 || height > 65535) throw "Width/Height invalid.";
17723
17724 function check_palette_and_num_colors(palette) {
17725 var num_colors = palette.length;
17726 if (num_colors < 2 || num_colors > 256 || num_colors & num_colors - 1) throw "Invalid code/color length, must be power of 2 and 2 .. 256.";
17727 return num_colors;
17728 } // - Header.
17729
17730
17731 buf[p++] = 0x47;
17732 buf[p++] = 0x49;
17733 buf[p++] = 0x46; // GIF
17734
17735 buf[p++] = 0x38;
17736 buf[p++] = 0x39;
17737 buf[p++] = 0x61; // 89a
17738 // Handling of Global Color Table (palette) and background index.
17739
17740 var gp_num_colors_pow2 = 0;
17741 var background = 0;
17742
17743 if (global_palette !== null) {
17744 var gp_num_colors = check_palette_and_num_colors(global_palette);
17745
17746 while (gp_num_colors >>= 1) ++gp_num_colors_pow2;
17747
17748 gp_num_colors = 1 << gp_num_colors_pow2;
17749 --gp_num_colors_pow2;
17750
17751 if (gopts.background !== undefined) {
17752 background = gopts.background;
17753 if (background >= gp_num_colors) throw "Background index out of range."; // The GIF spec states that a background index of 0 should be ignored, so
17754 // this is probably a mistake and you really want to set it to another
17755 // slot in the palette. But actually in the end most browsers, etc end
17756 // up ignoring this almost completely (including for dispose background).
17757
17758 if (background === 0) throw "Background index explicitly passed as 0.";
17759 }
17760 } // - Logical Screen Descriptor.
17761 // NOTE(deanm): w/h apparently ignored by implementations, but set anyway.
17762
17763
17764 buf[p++] = width & 0xff;
17765 buf[p++] = width >> 8 & 0xff;
17766 buf[p++] = height & 0xff;
17767 buf[p++] = height >> 8 & 0xff; // NOTE: Indicates 0-bpp original color resolution (unused?).
17768
17769 buf[p++] = (global_palette !== null ? 0x80 : 0) | // Global Color Table Flag.
17770 gp_num_colors_pow2; // NOTE: No sort flag (unused?).
17771
17772 buf[p++] = background; // Background Color Index.
17773
17774 buf[p++] = 0; // Pixel aspect ratio (unused?).
17775 // - Global Color Table
17776
17777 if (global_palette !== null) {
17778 for (var i = 0, il = global_palette.length; i < il; ++i) {
17779 var rgb = global_palette[i];
17780 buf[p++] = rgb >> 16 & 0xff;
17781 buf[p++] = rgb >> 8 & 0xff;
17782 buf[p++] = rgb & 0xff;
17783 }
17784 }
17785
17786 if (loop_count !== null) {
17787 // Netscape block for looping.
17788 if (loop_count < 0 || loop_count > 65535) throw "Loop count invalid."; // Extension code, label, and length.
17789
17790 buf[p++] = 0x21;
17791 buf[p++] = 0xff;
17792 buf[p++] = 0x0b; // NETSCAPE2.0
17793
17794 buf[p++] = 0x4e;
17795 buf[p++] = 0x45;
17796 buf[p++] = 0x54;
17797 buf[p++] = 0x53;
17798 buf[p++] = 0x43;
17799 buf[p++] = 0x41;
17800 buf[p++] = 0x50;
17801 buf[p++] = 0x45;
17802 buf[p++] = 0x32;
17803 buf[p++] = 0x2e;
17804 buf[p++] = 0x30; // Sub-block
17805
17806 buf[p++] = 0x03;
17807 buf[p++] = 0x01;
17808 buf[p++] = loop_count & 0xff;
17809 buf[p++] = loop_count >> 8 & 0xff;
17810 buf[p++] = 0x00; // Terminator.
17811 }
17812
17813 var ended = false;
17814
17815 this.addFrame = function (x, y, w, h, indexed_pixels, opts) {
17816 if (ended === true) {
17817 --p;
17818 ended = false;
17819 } // Un-end.
17820
17821
17822 opts = opts === undefined ? {} : opts; // TODO(deanm): Bounds check x, y. Do they need to be within the virtual
17823 // canvas width/height, I imagine?
17824
17825 if (x < 0 || y < 0 || x > 65535 || y > 65535) throw "x/y invalid.";
17826 if (w <= 0 || h <= 0 || w > 65535 || h > 65535) throw "Width/Height invalid.";
17827 if (indexed_pixels.length < w * h) throw "Not enough pixels for the frame size.";
17828 var using_local_palette = true;
17829 var palette = opts.palette;
17830
17831 if (palette === undefined || palette === null) {
17832 using_local_palette = false;
17833 palette = global_palette;
17834 }
17835
17836 if (palette === undefined || palette === null) throw "Must supply either a local or global palette.";
17837 var num_colors = check_palette_and_num_colors(palette); // Compute the min_code_size (power of 2), destroying num_colors.
17838
17839 var min_code_size = 0;
17840
17841 while (num_colors >>= 1) ++min_code_size;
17842
17843 num_colors = 1 << min_code_size; // Now we can easily get it back.
17844
17845 var delay = opts.delay === undefined ? 0 : opts.delay; // From the spec:
17846 // 0 - No disposal specified. The decoder is
17847 // not required to take any action.
17848 // 1 - Do not dispose. The graphic is to be left
17849 // in place.
17850 // 2 - Restore to background color. The area used by the
17851 // graphic must be restored to the background color.
17852 // 3 - Restore to previous. The decoder is required to
17853 // restore the area overwritten by the graphic with
17854 // what was there prior to rendering the graphic.
17855 // 4-7 - To be defined.
17856 // NOTE(deanm): Dispose background doesn't really work, apparently most
17857 // browsers ignore the background palette index and clear to transparency.
17858
17859 var disposal = opts.disposal === undefined ? 0 : opts.disposal;
17860 if (disposal < 0 || disposal > 3) // 4-7 is reserved.
17861 throw "Disposal out of range.";
17862 var use_transparency = false;
17863 var transparent_index = 0;
17864
17865 if (opts.transparent !== undefined && opts.transparent !== null) {
17866 use_transparency = true;
17867 transparent_index = opts.transparent;
17868 if (transparent_index < 0 || transparent_index >= num_colors) throw "Transparent color index.";
17869 }
17870
17871 if (disposal !== 0 || use_transparency || delay !== 0) {
17872 // - Graphics Control Extension
17873 buf[p++] = 0x21;
17874 buf[p++] = 0xf9; // Extension / Label.
17875
17876 buf[p++] = 4; // Byte size.
17877
17878 buf[p++] = disposal << 2 | (use_transparency === true ? 1 : 0);
17879 buf[p++] = delay & 0xff;
17880 buf[p++] = delay >> 8 & 0xff;
17881 buf[p++] = transparent_index; // Transparent color index.
17882
17883 buf[p++] = 0; // Block Terminator.
17884 } // - Image Descriptor
17885
17886
17887 buf[p++] = 0x2c; // Image Seperator.
17888
17889 buf[p++] = x & 0xff;
17890 buf[p++] = x >> 8 & 0xff; // Left.
17891
17892 buf[p++] = y & 0xff;
17893 buf[p++] = y >> 8 & 0xff; // Top.
17894
17895 buf[p++] = w & 0xff;
17896 buf[p++] = w >> 8 & 0xff;
17897 buf[p++] = h & 0xff;
17898 buf[p++] = h >> 8 & 0xff; // NOTE: No sort flag (unused?).
17899 // TODO(deanm): Support interlace.
17900
17901 buf[p++] = using_local_palette === true ? 0x80 | min_code_size - 1 : 0; // - Local Color Table
17902
17903 if (using_local_palette === true) {
17904 for (var i = 0, il = palette.length; i < il; ++i) {
17905 var rgb = palette[i];
17906 buf[p++] = rgb >> 16 & 0xff;
17907 buf[p++] = rgb >> 8 & 0xff;
17908 buf[p++] = rgb & 0xff;
17909 }
17910 }
17911
17912 p = GifWriterOutputLZWCodeStream(buf, p, min_code_size < 2 ? 2 : min_code_size, indexed_pixels);
17913 };
17914
17915 this.end = function () {
17916 if (ended === false) {
17917 buf[p++] = 0x3b; // Trailer.
17918
17919 ended = true;
17920 }
17921
17922 return p;
17923 };
17924 } // Main compression routine, palette indexes -> LZW code stream.
17925 // |index_stream| must have at least one entry.
17926
17927
17928 function GifWriterOutputLZWCodeStream(buf, p, min_code_size, index_stream) {
17929 buf[p++] = min_code_size;
17930 var cur_subblock = p++; // Pointing at the length field.
17931
17932 var clear_code = 1 << min_code_size;
17933 var code_mask = clear_code - 1;
17934 var eoi_code = clear_code + 1;
17935 var next_code = eoi_code + 1;
17936 var cur_code_size = min_code_size + 1; // Number of bits per code.
17937
17938 var cur_shift = 0; // We have at most 12-bit codes, so we should have to hold a max of 19
17939 // bits here (and then we would write out).
17940
17941 var cur = 0;
17942
17943 function emit_bytes_to_buffer(bit_block_size) {
17944 while (cur_shift >= bit_block_size) {
17945 buf[p++] = cur & 0xff;
17946 cur >>= 8;
17947 cur_shift -= 8;
17948
17949 if (p === cur_subblock + 256) {
17950 // Finished a subblock.
17951 buf[cur_subblock] = 255;
17952 cur_subblock = p++;
17953 }
17954 }
17955 }
17956
17957 function emit_code(c) {
17958 cur |= c << cur_shift;
17959 cur_shift += cur_code_size;
17960 emit_bytes_to_buffer(8);
17961 } // I am not an expert on the topic, and I don't want to write a thesis.
17962 // However, it is good to outline here the basic algorithm and the few data
17963 // structures and optimizations here that make this implementation fast.
17964 // The basic idea behind LZW is to build a table of previously seen runs
17965 // addressed by a short id (herein called output code). All data is
17966 // referenced by a code, which represents one or more values from the
17967 // original input stream. All input bytes can be referenced as the same
17968 // value as an output code. So if you didn't want any compression, you
17969 // could more or less just output the original bytes as codes (there are
17970 // some details to this, but it is the idea). In order to achieve
17971 // compression, values greater then the input range (codes can be up to
17972 // 12-bit while input only 8-bit) represent a sequence of previously seen
17973 // inputs. The decompressor is able to build the same mapping while
17974 // decoding, so there is always a shared common knowledge between the
17975 // encoding and decoder, which is also important for "timing" aspects like
17976 // how to handle variable bit width code encoding.
17977 //
17978 // One obvious but very important consequence of the table system is there
17979 // is always a unique id (at most 12-bits) to map the runs. 'A' might be
17980 // 4, then 'AA' might be 10, 'AAA' 11, 'AAAA' 12, etc. This relationship
17981 // can be used for an effecient lookup strategy for the code mapping. We
17982 // need to know if a run has been seen before, and be able to map that run
17983 // to the output code. Since we start with known unique ids (input bytes),
17984 // and then from those build more unique ids (table entries), we can
17985 // continue this chain (almost like a linked list) to always have small
17986 // integer values that represent the current byte chains in the encoder.
17987 // This means instead of tracking the input bytes (AAAABCD) to know our
17988 // current state, we can track the table entry for AAAABC (it is guaranteed
17989 // to exist by the nature of the algorithm) and the next character D.
17990 // Therefor the tuple of (table_entry, byte) is guaranteed to also be
17991 // unique. This allows us to create a simple lookup key for mapping input
17992 // sequences to codes (table indices) without having to store or search
17993 // any of the code sequences. So if 'AAAA' has a table entry of 12, the
17994 // tuple of ('AAAA', K) for any input byte K will be unique, and can be our
17995 // key. This leads to a integer value at most 20-bits, which can always
17996 // fit in an SMI value and be used as a fast sparse array / object key.
17997 // Output code for the current contents of the index buffer.
17998
17999
18000 var ib_code = index_stream[0] & code_mask; // Load first input index.
18001
18002 var code_table = {}; // Key'd on our 20-bit "tuple".
18003
18004 emit_code(clear_code); // Spec says first code should be a clear code.
18005 // First index already loaded, process the rest of the stream.
18006
18007 for (var i = 1, il = index_stream.length; i < il; ++i) {
18008 var k = index_stream[i] & code_mask;
18009 var cur_key = ib_code << 8 | k; // (prev, k) unique tuple.
18010
18011 var cur_code = code_table[cur_key]; // buffer + k.
18012 // Check if we have to create a new code table entry.
18013
18014 if (cur_code === undefined) {
18015 // We don't have buffer + k.
18016 // Emit index buffer (without k).
18017 // This is an inline version of emit_code, because this is the core
18018 // writing routine of the compressor (and V8 cannot inline emit_code
18019 // because it is a closure here in a different context). Additionally
18020 // we can call emit_byte_to_buffer less often, because we can have
18021 // 30-bits (from our 31-bit signed SMI), and we know our codes will only
18022 // be 12-bits, so can safely have 18-bits there without overflow.
18023 // emit_code(ib_code);
18024 cur |= ib_code << cur_shift;
18025 cur_shift += cur_code_size;
18026
18027 while (cur_shift >= 8) {
18028 buf[p++] = cur & 0xff;
18029 cur >>= 8;
18030 cur_shift -= 8;
18031
18032 if (p === cur_subblock + 256) {
18033 // Finished a subblock.
18034 buf[cur_subblock] = 255;
18035 cur_subblock = p++;
18036 }
18037 }
18038
18039 if (next_code === 4096) {
18040 // Table full, need a clear.
18041 emit_code(clear_code);
18042 next_code = eoi_code + 1;
18043 cur_code_size = min_code_size + 1;
18044 code_table = {};
18045 } else {
18046 // Table not full, insert a new entry.
18047 // Increase our variable bit code sizes if necessary. This is a bit
18048 // tricky as it is based on "timing" between the encoding and
18049 // decoder. From the encoders perspective this should happen after
18050 // we've already emitted the index buffer and are about to create the
18051 // first table entry that would overflow our current code bit size.
18052 if (next_code >= 1 << cur_code_size) ++cur_code_size;
18053 code_table[cur_key] = next_code++; // Insert into code table.
18054 }
18055
18056 ib_code = k; // Index buffer to single input k.
18057 } else {
18058 ib_code = cur_code; // Index buffer to sequence in code table.
18059 }
18060 }
18061
18062 emit_code(ib_code); // There will still be something in the index buffer.
18063
18064 emit_code(eoi_code); // End Of Information.
18065 // Flush / finalize the sub-blocks stream to the buffer.
18066
18067 emit_bytes_to_buffer(1); // Finish the sub-blocks, writing out any unfinished lengths and
18068 // terminating with a sub-block of length 0. If we have already started
18069 // but not yet used a sub-block it can just become the terminator.
18070
18071 if (cur_subblock + 1 === p) {
18072 // Started but unused.
18073 buf[cur_subblock] = 0;
18074 } else {
18075 // Started and used, write length and additional terminator block.
18076 buf[cur_subblock] = p - cur_subblock - 1;
18077 buf[p++] = 0;
18078 }
18079
18080 return p;
18081 }
18082
18083 function GifReader(buf) {
18084 var p = 0; // - Header (GIF87a or GIF89a).
18085
18086 if (buf[p++] !== 0x47 || buf[p++] !== 0x49 || buf[p++] !== 0x46 || buf[p++] !== 0x38 || (buf[p++] + 1 & 0xfd) !== 0x38 || buf[p++] !== 0x61) {
18087 throw "Invalid GIF 87a/89a header.";
18088 } // - Logical Screen Descriptor.
18089
18090
18091 var width = buf[p++] | buf[p++] << 8;
18092 var height = buf[p++] | buf[p++] << 8;
18093 var pf0 = buf[p++]; // <Packed Fields>.
18094
18095 var global_palette_flag = pf0 >> 7;
18096 var num_global_colors_pow2 = pf0 & 0x7;
18097 var num_global_colors = 1 << num_global_colors_pow2 + 1;
18098 var background = buf[p++];
18099 buf[p++]; // Pixel aspect ratio (unused?).
18100
18101 var global_palette_offset = null;
18102
18103 if (global_palette_flag) {
18104 global_palette_offset = p;
18105 p += num_global_colors * 3; // Seek past palette.
18106 }
18107
18108 var no_eof = true;
18109 var frames = [];
18110 var delay = 0;
18111 var transparent_index = null;
18112 var disposal = 0; // 0 - No disposal specified.
18113
18114 var loop_count = null;
18115 this.width = width;
18116 this.height = height;
18117
18118 while (no_eof && p < buf.length) {
18119 switch (buf[p++]) {
18120 case 0x21:
18121 // Graphics Control Extension Block
18122 switch (buf[p++]) {
18123 case 0xff:
18124 // Application specific block
18125 // Try if it's a Netscape block (with animation loop counter).
18126 if (buf[p] !== 0x0b || // 21 FF already read, check block size.
18127 // NETSCAPE2.0
18128 buf[p + 1] == 0x4e && buf[p + 2] == 0x45 && buf[p + 3] == 0x54 && buf[p + 4] == 0x53 && buf[p + 5] == 0x43 && buf[p + 6] == 0x41 && buf[p + 7] == 0x50 && buf[p + 8] == 0x45 && buf[p + 9] == 0x32 && buf[p + 10] == 0x2e && buf[p + 11] == 0x30 && // Sub-block
18129 buf[p + 12] == 0x03 && buf[p + 13] == 0x01 && buf[p + 16] == 0) {
18130 p += 14;
18131 loop_count = buf[p++] | buf[p++] << 8;
18132 p++; // Skip terminator.
18133 } else {
18134 // We don't know what it is, just try to get past it.
18135 p += 12;
18136
18137 while (true) {
18138 // Seek through subblocks.
18139 var block_size = buf[p++];
18140 if (block_size === 0) break;
18141 p += block_size;
18142 }
18143 }
18144
18145 break;
18146
18147 case 0xf9:
18148 // Graphics Control Extension
18149 if (buf[p++] !== 0x4 || buf[p + 4] !== 0) throw "Invalid graphics extension block.";
18150 var pf1 = buf[p++];
18151 delay = buf[p++] | buf[p++] << 8;
18152 transparent_index = buf[p++];
18153 if ((pf1 & 1) === 0) transparent_index = null;
18154 disposal = pf1 >> 2 & 0x7;
18155 p++; // Skip terminator.
18156
18157 break;
18158
18159 case 0xfe:
18160 // Comment Extension.
18161 while (true) {
18162 // Seek through subblocks.
18163 var block_size = buf[p++];
18164 if (block_size === 0) break; // console.log(buf.slice(p, p+block_size).toString('ascii'));
18165
18166 p += block_size;
18167 }
18168
18169 break;
18170
18171 default:
18172 throw "Unknown graphic control label: 0x" + buf[p - 1].toString(16);
18173 }
18174
18175 break;
18176
18177 case 0x2c:
18178 // Image Descriptor.
18179 var x = buf[p++] | buf[p++] << 8;
18180 var y = buf[p++] | buf[p++] << 8;
18181 var w = buf[p++] | buf[p++] << 8;
18182 var h = buf[p++] | buf[p++] << 8;
18183 var pf2 = buf[p++];
18184 var local_palette_flag = pf2 >> 7;
18185 var interlace_flag = pf2 >> 6 & 1;
18186 var num_local_colors_pow2 = pf2 & 0x7;
18187 var num_local_colors = 1 << num_local_colors_pow2 + 1;
18188 var palette_offset = global_palette_offset;
18189 var has_local_palette = false;
18190
18191 if (local_palette_flag) {
18192 var has_local_palette = true;
18193 palette_offset = p; // Override with local palette.
18194
18195 p += num_local_colors * 3; // Seek past palette.
18196 }
18197
18198 var data_offset = p;
18199 p++; // codesize
18200
18201 while (true) {
18202 var block_size = buf[p++];
18203 if (block_size === 0) break;
18204 p += block_size;
18205 }
18206
18207 frames.push({
18208 x: x,
18209 y: y,
18210 width: w,
18211 height: h,
18212 has_local_palette: has_local_palette,
18213 palette_offset: palette_offset,
18214 data_offset: data_offset,
18215 data_length: p - data_offset,
18216 transparent_index: transparent_index,
18217 interlaced: !!interlace_flag,
18218 delay: delay,
18219 disposal: disposal
18220 });
18221 break;
18222
18223 case 0x3b:
18224 // Trailer Marker (end of file).
18225 no_eof = false;
18226 break;
18227
18228 default:
18229 throw "Unknown gif block: 0x" + buf[p - 1].toString(16);
18230 break;
18231 }
18232 }
18233
18234 this.numFrames = function () {
18235 return frames.length;
18236 };
18237
18238 this.loopCount = function () {
18239 return loop_count;
18240 };
18241
18242 this.frameInfo = function (frame_num) {
18243 if (frame_num < 0 || frame_num >= frames.length) throw "Frame index out of range.";
18244 return frames[frame_num];
18245 };
18246
18247 this.decodeAndBlitFrameBGRA = function (frame_num, pixels) {
18248 var frame = this.frameInfo(frame_num);
18249 var num_pixels = frame.width * frame.height;
18250 var index_stream = new Uint8Array(num_pixels); // At most 8-bit indices.
18251
18252 GifReaderLZWOutputIndexStream(buf, frame.data_offset, index_stream, num_pixels);
18253 var palette_offset = frame.palette_offset; // NOTE(deanm): It seems to be much faster to compare index to 256 than
18254 // to === null. Not sure why, but CompareStub_EQ_STRICT shows up high in
18255 // the profile, not sure if it's related to using a Uint8Array.
18256
18257 var trans = frame.transparent_index;
18258 if (trans === null) trans = 256; // We are possibly just blitting to a portion of the entire frame.
18259 // That is a subrect within the framerect, so the additional pixels
18260 // must be skipped over after we finished a scanline.
18261
18262 var framewidth = frame.width;
18263 var framestride = width - framewidth;
18264 var xleft = framewidth; // Number of subrect pixels left in scanline.
18265 // Output indicies of the top left and bottom right corners of the subrect.
18266
18267 var opbeg = (frame.y * width + frame.x) * 4;
18268 var opend = ((frame.y + frame.height) * width + frame.x) * 4;
18269 var op = opbeg;
18270 var scanstride = framestride * 4; // Use scanstride to skip past the rows when interlacing. This is skipping
18271 // 7 rows for the first two passes, then 3 then 1.
18272
18273 if (frame.interlaced === true) {
18274 scanstride += (framewidth + framestride) * 4 * 7; // Pass 1.
18275 }
18276
18277 var interlaceskip = 8; // Tracking the row interval in the current pass.
18278
18279 for (var i = 0, il = index_stream.length; i < il; ++i) {
18280 var index = index_stream[i];
18281
18282 if (xleft === 0) {
18283 // Beginning of new scan line
18284 op += scanstride;
18285 xleft = framewidth;
18286
18287 if (op >= opend) {
18288 // Catch the wrap to switch passes when interlacing.
18289 scanstride = framestride + (framewidth + framestride) * 4 * (interlaceskip - 1); // interlaceskip / 2 * 4 is interlaceskip << 1.
18290
18291 op = opbeg + (framewidth + framestride) * (interlaceskip << 1);
18292 interlaceskip >>= 1;
18293 }
18294 }
18295
18296 if (index === trans) {
18297 op += 4;
18298 } else {
18299 var r = buf[palette_offset + index * 3];
18300 var g = buf[palette_offset + index * 3 + 1];
18301 var b = buf[palette_offset + index * 3 + 2];
18302 pixels[op++] = b;
18303 pixels[op++] = g;
18304 pixels[op++] = r;
18305 pixels[op++] = 255;
18306 }
18307
18308 --xleft;
18309 }
18310 }; // I will go to copy and paste hell one day...
18311
18312
18313 this.decodeAndBlitFrameRGBA = function (frame_num, pixels) {
18314 var frame = this.frameInfo(frame_num);
18315 var num_pixels = frame.width * frame.height;
18316 var index_stream = new Uint8Array(num_pixels); // At most 8-bit indices.
18317
18318 GifReaderLZWOutputIndexStream(buf, frame.data_offset, index_stream, num_pixels);
18319 var palette_offset = frame.palette_offset; // NOTE(deanm): It seems to be much faster to compare index to 256 than
18320 // to === null. Not sure why, but CompareStub_EQ_STRICT shows up high in
18321 // the profile, not sure if it's related to using a Uint8Array.
18322
18323 var trans = frame.transparent_index;
18324 if (trans === null) trans = 256; // We are possibly just blitting to a portion of the entire frame.
18325 // That is a subrect within the framerect, so the additional pixels
18326 // must be skipped over after we finished a scanline.
18327
18328 var framewidth = frame.width;
18329 var framestride = width - framewidth;
18330 var xleft = framewidth; // Number of subrect pixels left in scanline.
18331 // Output indicies of the top left and bottom right corners of the subrect.
18332
18333 var opbeg = (frame.y * width + frame.x) * 4;
18334 var opend = ((frame.y + frame.height) * width + frame.x) * 4;
18335 var op = opbeg;
18336 var scanstride = framestride * 4; // Use scanstride to skip past the rows when interlacing. This is skipping
18337 // 7 rows for the first two passes, then 3 then 1.
18338
18339 if (frame.interlaced === true) {
18340 scanstride += (framewidth + framestride) * 4 * 7; // Pass 1.
18341 }
18342
18343 var interlaceskip = 8; // Tracking the row interval in the current pass.
18344
18345 for (var i = 0, il = index_stream.length; i < il; ++i) {
18346 var index = index_stream[i];
18347
18348 if (xleft === 0) {
18349 // Beginning of new scan line
18350 op += scanstride;
18351 xleft = framewidth;
18352
18353 if (op >= opend) {
18354 // Catch the wrap to switch passes when interlacing.
18355 scanstride = framestride + (framewidth + framestride) * 4 * (interlaceskip - 1); // interlaceskip / 2 * 4 is interlaceskip << 1.
18356
18357 op = opbeg + (framewidth + framestride) * (interlaceskip << 1);
18358 interlaceskip >>= 1;
18359 }
18360 }
18361
18362 if (index === trans) {
18363 op += 4;
18364 } else {
18365 var r = buf[palette_offset + index * 3];
18366 var g = buf[palette_offset + index * 3 + 1];
18367 var b = buf[palette_offset + index * 3 + 2];
18368 pixels[op++] = r;
18369 pixels[op++] = g;
18370 pixels[op++] = b;
18371 pixels[op++] = 255;
18372 }
18373
18374 --xleft;
18375 }
18376 };
18377 }
18378
18379 function GifReaderLZWOutputIndexStream(code_stream, p, output, output_length) {
18380 var min_code_size = code_stream[p++];
18381 var clear_code = 1 << min_code_size;
18382 var eoi_code = clear_code + 1;
18383 var next_code = eoi_code + 1;
18384 var cur_code_size = min_code_size + 1; // Number of bits per code.
18385 // NOTE: This shares the same name as the encoder, but has a different
18386 // meaning here. Here this masks each code coming from the code stream.
18387
18388 var code_mask = (1 << cur_code_size) - 1;
18389 var cur_shift = 0;
18390 var cur = 0;
18391 var op = 0; // Output pointer.
18392
18393 var subblock_size = code_stream[p++]; // TODO(deanm): Would using a TypedArray be any faster? At least it would
18394 // solve the fast mode / backing store uncertainty.
18395 // var code_table = Array(4096);
18396
18397 var code_table = new Int32Array(4096); // Can be signed, we only use 20 bits.
18398
18399 var prev_code = null; // Track code-1.
18400
18401 while (true) {
18402 // Read up to two bytes, making sure we always 12-bits for max sized code.
18403 while (cur_shift < 16) {
18404 if (subblock_size === 0) break; // No more data to be read.
18405
18406 cur |= code_stream[p++] << cur_shift;
18407 cur_shift += 8;
18408
18409 if (subblock_size === 1) {
18410 // Never let it get to 0 to hold logic above.
18411 subblock_size = code_stream[p++]; // Next subblock.
18412 } else {
18413 --subblock_size;
18414 }
18415 } // TODO(deanm): We should never really get here, we should have received
18416 // and EOI.
18417
18418
18419 if (cur_shift < cur_code_size) break;
18420 var code = cur & code_mask;
18421 cur >>= cur_code_size;
18422 cur_shift -= cur_code_size; // TODO(deanm): Maybe should check that the first code was a clear code,
18423 // at least this is what you're supposed to do. But actually our encoder
18424 // now doesn't emit a clear code first anyway.
18425
18426 if (code === clear_code) {
18427 // We don't actually have to clear the table. This could be a good idea
18428 // for greater error checking, but we don't really do any anyway. We
18429 // will just track it with next_code and overwrite old entries.
18430 next_code = eoi_code + 1;
18431 cur_code_size = min_code_size + 1;
18432 code_mask = (1 << cur_code_size) - 1; // Don't update prev_code ?
18433
18434 prev_code = null;
18435 continue;
18436 } else if (code === eoi_code) {
18437 break;
18438 } // We have a similar situation as the decoder, where we want to store
18439 // variable length entries (code table entries), but we want to do in a
18440 // faster manner than an array of arrays. The code below stores sort of a
18441 // linked list within the code table, and then "chases" through it to
18442 // construct the dictionary entries. When a new entry is created, just the
18443 // last byte is stored, and the rest (prefix) of the entry is only
18444 // referenced by its table entry. Then the code chases through the
18445 // prefixes until it reaches a single byte code. We have to chase twice,
18446 // first to compute the length, and then to actually copy the data to the
18447 // output (backwards, since we know the length). The alternative would be
18448 // storing something in an intermediate stack, but that doesn't make any
18449 // more sense. I implemented an approach where it also stored the length
18450 // in the code table, although it's a bit tricky because you run out of
18451 // bits (12 + 12 + 8), but I didn't measure much improvements (the table
18452 // entries are generally not the long). Even when I created benchmarks for
18453 // very long table entries the complexity did not seem worth it.
18454 // The code table stores the prefix entry in 12 bits and then the suffix
18455 // byte in 8 bits, so each entry is 20 bits.
18456
18457
18458 var chase_code = code < next_code ? code : prev_code; // Chase what we will output, either {CODE} or {CODE-1}.
18459
18460 var chase_length = 0;
18461 var chase = chase_code;
18462
18463 while (chase > clear_code) {
18464 chase = code_table[chase] >> 8;
18465 ++chase_length;
18466 }
18467
18468 var k = chase;
18469 var op_end = op + chase_length + (chase_code !== code ? 1 : 0);
18470
18471 if (op_end > output_length) {
18472 console.log("Warning, gif stream longer than expected.");
18473 return;
18474 } // Already have the first byte from the chase, might as well write it fast.
18475
18476
18477 output[op++] = k;
18478 op += chase_length;
18479 var b = op; // Track pointer, writing backwards.
18480
18481 if (chase_code !== code) // The case of emitting {CODE-1} + k.
18482 output[op++] = k;
18483 chase = chase_code;
18484
18485 while (chase_length--) {
18486 chase = code_table[chase];
18487 output[--b] = chase & 0xff; // Write backwards.
18488
18489 chase >>= 8; // Pull down to the prefix code.
18490 }
18491
18492 if (prev_code !== null && next_code < 4096) {
18493 code_table[next_code++] = prev_code << 8 | k; // TODO(deanm): Figure out this clearing vs code growth logic better. I
18494 // have an feeling that it should just happen somewhere else, for now it
18495 // is awkward between when we grow past the max and then hit a clear code.
18496 // For now just check if we hit the max 12-bits (then a clear code should
18497 // follow, also of course encoded in 12-bits).
18498
18499 if (next_code >= code_mask + 1 && cur_code_size < 12) {
18500 ++cur_code_size;
18501 code_mask = code_mask << 1 | 1;
18502 }
18503 }
18504
18505 prev_code = code;
18506 }
18507
18508 if (op !== output_length) {
18509 console.log("Warning, gif stream shorter than expected.");
18510 }
18511
18512 return output;
18513 }
18514
18515 try {
18516 exports.GifWriter = GifWriter;
18517 exports.GifReader = GifReader;
18518 } catch (e) {} // CommonJS.
18519
18520 /*rollup-keeper-start*/
18521
18522
18523 window.tmp = GifReader;
18524 /*rollup-keeper-end*/
18525
18526 /*
18527 * Copyright (c) 2012 chick307 <chick307@gmail.com>
18528 *
18529 * Licensed under the MIT License.
18530 * http://opensource.org/licenses/mit-license
18531 */
18532 (function (jsPDF, callback) {
18533 jsPDF.API.adler32cs = callback();
18534 })(jsPDF, function () {
18535 var _hasArrayBuffer = typeof ArrayBuffer === 'function' && typeof Uint8Array === 'function';
18536
18537 var _Buffer = null,
18538 _isBuffer = function () {
18539 if (!_hasArrayBuffer) return function _isBuffer() {
18540 return false;
18541 };
18542
18543 try {
18544 var buffer = {};
18545 if (typeof buffer.Buffer === 'function') _Buffer = buffer.Buffer;
18546 } catch (error) {}
18547
18548 return function _isBuffer(value) {
18549 return value instanceof ArrayBuffer || _Buffer !== null && value instanceof _Buffer;
18550 };
18551 }();
18552
18553 var _utf8ToBinary = function () {
18554 if (_Buffer !== null) {
18555 return function _utf8ToBinary(utf8String) {
18556 return new _Buffer(utf8String, 'utf8').toString('binary');
18557 };
18558 } else {
18559 return function _utf8ToBinary(utf8String) {
18560 return unescape(encodeURIComponent(utf8String));
18561 };
18562 }
18563 }();
18564
18565 var MOD = 65521;
18566
18567 var _update = function _update(checksum, binaryString) {
18568 var a = checksum & 0xFFFF,
18569 b = checksum >>> 16;
18570
18571 for (var i = 0, length = binaryString.length; i < length; i++) {
18572 a = (a + (binaryString.charCodeAt(i) & 0xFF)) % MOD;
18573 b = (b + a) % MOD;
18574 }
18575
18576 return (b << 16 | a) >>> 0;
18577 };
18578
18579 var _updateUint8Array = function _updateUint8Array(checksum, uint8Array) {
18580 var a = checksum & 0xFFFF,
18581 b = checksum >>> 16;
18582
18583 for (var i = 0, length = uint8Array.length; i < length; i++) {
18584 a = (a + uint8Array[i]) % MOD;
18585 b = (b + a) % MOD;
18586 }
18587
18588 return (b << 16 | a) >>> 0;
18589 };
18590
18591 var exports = {};
18592
18593 var Adler32 = exports.Adler32 = function () {
18594 var ctor = function Adler32(checksum) {
18595 if (!(this instanceof ctor)) {
18596 throw new TypeError('Constructor cannot called be as a function.');
18597 }
18598
18599 if (!isFinite(checksum = checksum == null ? 1 : +checksum)) {
18600 throw new Error('First arguments needs to be a finite number.');
18601 }
18602
18603 this.checksum = checksum >>> 0;
18604 };
18605
18606 var proto = ctor.prototype = {};
18607 proto.constructor = ctor;
18608
18609 ctor.from = function (from) {
18610 from.prototype = proto;
18611 return from;
18612 }(function from(binaryString) {
18613 if (!(this instanceof ctor)) {
18614 throw new TypeError('Constructor cannot called be as a function.');
18615 }
18616
18617 if (binaryString == null) throw new Error('First argument needs to be a string.');
18618 this.checksum = _update(1, binaryString.toString());
18619 });
18620
18621 ctor.fromUtf8 = function (fromUtf8) {
18622 fromUtf8.prototype = proto;
18623 return fromUtf8;
18624 }(function fromUtf8(utf8String) {
18625 if (!(this instanceof ctor)) {
18626 throw new TypeError('Constructor cannot called be as a function.');
18627 }
18628
18629 if (utf8String == null) throw new Error('First argument needs to be a string.');
18630
18631 var binaryString = _utf8ToBinary(utf8String.toString());
18632
18633 this.checksum = _update(1, binaryString);
18634 });
18635
18636 if (_hasArrayBuffer) {
18637 ctor.fromBuffer = function (fromBuffer) {
18638 fromBuffer.prototype = proto;
18639 return fromBuffer;
18640 }(function fromBuffer(buffer) {
18641 if (!(this instanceof ctor)) {
18642 throw new TypeError('Constructor cannot called be as a function.');
18643 }
18644
18645 if (!_isBuffer(buffer)) throw new Error('First argument needs to be ArrayBuffer.');
18646 var array = new Uint8Array(buffer);
18647 return this.checksum = _updateUint8Array(1, array);
18648 });
18649 }
18650
18651 proto.update = function update(binaryString) {
18652 if (binaryString == null) throw new Error('First argument needs to be a string.');
18653 binaryString = binaryString.toString();
18654 return this.checksum = _update(this.checksum, binaryString);
18655 };
18656
18657 proto.updateUtf8 = function updateUtf8(utf8String) {
18658 if (utf8String == null) throw new Error('First argument needs to be a string.');
18659
18660 var binaryString = _utf8ToBinary(utf8String.toString());
18661
18662 return this.checksum = _update(this.checksum, binaryString);
18663 };
18664
18665 if (_hasArrayBuffer) {
18666 proto.updateBuffer = function updateBuffer(buffer) {
18667 if (!_isBuffer(buffer)) throw new Error('First argument needs to be ArrayBuffer.');
18668 var array = new Uint8Array(buffer);
18669 return this.checksum = _updateUint8Array(this.checksum, array);
18670 };
18671 }
18672
18673 proto.clone = function clone() {
18674 return new Adler32(this.checksum);
18675 };
18676
18677 return ctor;
18678 }();
18679
18680 exports.from = function from(binaryString) {
18681 if (binaryString == null) throw new Error('First argument needs to be a string.');
18682 return _update(1, binaryString.toString());
18683 };
18684
18685 exports.fromUtf8 = function fromUtf8(utf8String) {
18686 if (utf8String == null) throw new Error('First argument needs to be a string.');
18687
18688 var binaryString = _utf8ToBinary(utf8String.toString());
18689
18690 return _update(1, binaryString);
18691 };
18692
18693 if (_hasArrayBuffer) {
18694 exports.fromBuffer = function fromBuffer(buffer) {
18695 if (!_isBuffer(buffer)) throw new Error('First argument need to be ArrayBuffer.');
18696 var array = new Uint8Array(buffer);
18697 return _updateUint8Array(1, array);
18698 };
18699 }
18700
18701 return exports;
18702 });
18703
18704 /**
18705 * Unicode Bidi Engine based on the work of Alex Shensis (@asthensis)
18706 * MIT License
18707 */
18708 (function (jsPDF) {
18709 /**
18710 * Table of Unicode types.
18711 *
18712 * Generated by:
18713 *
18714 * var bidi = require("./bidi/index");
18715 * var bidi_accumulate = bidi.slice(0, 256).concat(bidi.slice(0x0500, 0x0500 + 256 * 3)).
18716 * concat(bidi.slice(0x2000, 0x2000 + 256)).concat(bidi.slice(0xFB00, 0xFB00 + 256)).
18717 * concat(bidi.slice(0xFE00, 0xFE00 + 2 * 256));
18718 *
18719 * for( var i = 0; i < bidi_accumulate.length; i++) {
18720 * if(bidi_accumulate[i] === undefined || bidi_accumulate[i] === 'ON')
18721 * bidi_accumulate[i] = 'N'; //mark as neutral to conserve space and substitute undefined
18722 * }
18723 * var bidiAccumulateStr = 'return [ "' + bidi_accumulate.toString().replace(/,/g, '", "') + '" ];';
18724 * require("fs").writeFile('unicode-types.js', bidiAccumulateStr);
18725 *
18726 * Based on:
18727 * https://github.com/mathiasbynens/unicode-8.0.0
18728 */
18729
18730 var bidiUnicodeTypes = ["BN", "BN", "BN", "BN", "BN", "BN", "BN", "BN", "BN", "S", "B", "S", "WS", "B", "BN", "BN", "BN", "BN", "BN", "BN", "BN", "BN", "BN", "BN", "BN", "BN", "BN", "BN", "B", "B", "B", "S", "WS", "N", "N", "ET", "ET", "ET", "N", "N", "N", "N", "N", "ES", "CS", "ES", "CS", "CS", "EN", "EN", "EN", "EN", "EN", "EN", "EN", "EN", "EN", "EN", "CS", "N", "N", "N", "N", "N", "N", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "N", "N", "N", "N", "N", "N", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "N", "N", "N", "N", "BN", "BN", "BN", "BN", "BN", "BN", "B", "BN", "BN", "BN", "BN", "BN", "BN", "BN", "BN", "BN", "BN", "BN", "BN", "BN", "BN", "BN", "BN", "BN", "BN", "BN", "BN", "BN", "BN", "BN", "BN", "BN", "BN", "CS", "N", "ET", "ET", "ET", "ET", "N", "N", "N", "N", "L", "N", "N", "BN", "N", "N", "ET", "ET", "EN", "EN", "N", "L", "N", "N", "N", "EN", "L", "N", "N", "N", "N", "N", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "N", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "N", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "N", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "N", "N", "L", "L", "L", "L", "L", "L", "L", "N", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "N", "L", "N", "N", "N", "N", "N", "ET", "N", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "R", "NSM", "R", "NSM", "NSM", "R", "NSM", "NSM", "R", "NSM", "N", "N", "N", "N", "N", "N", "N", "N", "R", "R", "R", "R", "R", "R", "R", "R", "R", "R", "R", "R", "R", "R", "R", "R", "R", "R", "R", "R", "R", "R", "R", "R", "R", "R", "R", "N", "N", "N", "N", "N", "R", "R", "R", "R", "R", "N", "N", "N", "N", "N", "N", "N", "N", "N", "N", "N", "AN", "AN", "AN", "AN", "AN", "AN", "N", "N", "AL", "ET", "ET", "AL", "CS", "AL", "N", "N", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "AL", "AL", "N", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "AN", "AN", "AN", "AN", "AN", "AN", "AN", "AN", "AN", "AN", "ET", "AN", "AN", "AL", "AL", "AL", "NSM", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "AN", "N", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "AL", "AL", "NSM", "NSM", "N", "NSM", "NSM", "NSM", "NSM", "AL", "AL", "EN", "EN", "EN", "EN", "EN", "EN", "EN", "EN", "EN", "EN", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "N", "AL", "AL", "NSM", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "N", "N", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "AL", "N", "N", "N", "N", "N", "N", "N", "N", "N", "N", "N", "N", "N", "N", "R", "R", "R", "R", "R", "R", "R", "R", "R", "R", "R", "R", "R", "R", "R", "R", "R", "R", "R", "R", "R", "R", "R", "R", "R", "R", "R", "R", "R", "R", "R", "R", "R", "R", "R", "R", "R", "R", "R", "R", "R", "R", "R", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "R", "R", "N", "N", "N", "N", "R", "N", "N", "N", "N", "N", "WS", "WS", "WS", "WS", "WS", "WS", "WS", "WS", "WS", "WS", "WS", "BN", "BN", "BN", "L", "R", "N", "N", "N", "N", "N", "N", "N", "N", "N", "N", "N", "N", "N", "N", "N", "N", "N", "N", "N", "N", "N", "N", "N", "N", "WS", "B", "LRE", "RLE", "PDF", "LRO", "RLO", "CS", "ET", "ET", "ET", "ET", "ET", "N", "N", "N", "N", "N", "N", "N", "N", "N", "N", "N", "N", "N", "N", "N", "CS", "N", "N", "N", "N", "N", "N", "N", "N", "N", "N", "N", "N", "N", "N", "N", "N", "N", "N", "N", "N", "N", "N", "N", "N", "N", "N", "WS", "BN", "BN", "BN", "BN", "BN", "N", "LRI", "RLI", "FSI", "PDI", "BN", "BN", "BN", "BN", "BN", "BN", "EN", "L", "N", "N", "EN", "EN", "EN", "EN", "EN", "EN", "ES", "ES", "N", "N", "N", "L", "EN", "EN", "EN", "EN", "EN", "EN", "EN", "EN", "EN", "EN", "ES", "ES", "N", "N", "N", "N", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "N", "N", "N", "ET", "ET", "ET", "ET", "ET", "ET", "ET", "ET", "ET", "ET", "ET", "ET", "ET", "ET", "ET", "ET", "ET", "ET", "ET", "ET", "ET", "ET", "ET", "ET", "ET", "ET", "ET", "ET", "ET", "ET", "ET", "N", "N", "N", "N", "N", "N", "N", "N", "N", "N", "N", "N", "N", "N", "N", "N", "N", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "N", "N", "N", "N", "N", "N", "N", "N", "N", "N", "N", "N", "N", "N", "N", "L", "L", "L", "L", "L", "L", "L", "N", "N", "N", "N", "N", "N", "N", "N", "N", "N", "N", "N", "L", "L", "L", "L", "L", "N", "N", "N", "N", "N", "R", "NSM", "R", "R", "R", "R", "R", "R", "R", "R", "R", "R", "ES", "R", "R", "R", "R", "R", "R", "R", "R", "R", "R", "R", "R", "R", "N", "R", "R", "R", "R", "R", "N", "R", "N", "R", "R", "N", "R", "R", "N", "R", "R", "R", "R", "R", "R", "R", "R", "R", "R", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "N", "N", "N", "N", "N", "N", "N", "N", "N", "N", "N", "N", "N", "N", "N", "N", "N", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "N", "N", "N", "N", "N", "N", "N", "N", "N", "N", "N", "N", "N", "N", "N", "N", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "N", "N", "N", "N", "N", "N", "N", "N", "N", "N", "N", "N", "N", "N", "N", "N", "N", "N", "N", "N", "N", "N", "N", "N", "N", "N", "N", "N", "N", "N", "N", "N", "CS", "N", "CS", "N", "N", "CS", "N", "N", "N", "N", "N", "N", "N", "N", "N", "ET", "N", "N", "ES", "ES", "N", "N", "N", "N", "N", "ET", "ET", "N", "N", "N", "N", "N", "AL", "AL", "AL", "AL", "AL", "N", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "N", "N", "BN", "N", "N", "N", "ET", "ET", "ET", "N", "N", "N", "N", "N", "ES", "CS", "ES", "CS", "CS", "EN", "EN", "EN", "EN", "EN", "EN", "EN", "EN", "EN", "EN", "CS", "N", "N", "N", "N", "N", "N", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "N", "N", "N", "N", "N", "N", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "N", "N", "N", "N", "N", "N", "N", "N", "N", "N", "N", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "N", "N", "N", "L", "L", "L", "L", "L", "L", "N", "N", "L", "L", "L", "L", "L", "L", "N", "N", "L", "L", "L", "L", "L", "L", "N", "N", "L", "L", "L", "N", "N", "N", "ET", "ET", "N", "N", "N", "ET", "ET", "N", "N", "N", "N", "N", "N", "N", "N", "N", "N", "N", "N", "N", "N", "N", "N", "N", "N", "N", "N", "N", "N", "N", "N", "N"];
18731 /**
18732 * Unicode Bidi algorithm compliant Bidi engine.
18733 * For reference see http://unicode.org/reports/tr9/
18734 */
18735
18736 /**
18737 * constructor ( options )
18738 *
18739 * Initializes Bidi engine
18740 *
18741 * @param {Object} See 'setOptions' below for detailed description.
18742 * options are cashed between invocation of 'doBidiReorder' method
18743 *
18744 * sample usage pattern of BidiEngine:
18745 * var opt = {
18746 * isInputVisual: true,
18747 * isInputRtl: false,
18748 * isOutputVisual: false,
18749 * isOutputRtl: false,
18750 * isSymmetricSwapping: true
18751 * }
18752 * var sourceToTarget = [], levels = [];
18753 * var bidiEng = Globalize.bidiEngine(opt);
18754 * var src = "text string to be reordered";
18755 * var ret = bidiEng.doBidiReorder(src, sourceToTarget, levels);
18756 */
18757
18758 jsPDF.__bidiEngine__ = jsPDF.prototype.__bidiEngine__ = function (options) {
18759 var _UNICODE_TYPES = _bidiUnicodeTypes;
18760 var _STATE_TABLE_LTR = [[0, 3, 0, 1, 0, 0, 0], [0, 3, 0, 1, 2, 2, 0], [0, 3, 0, 0x11, 2, 0, 1], [0, 3, 5, 5, 4, 1, 0], [0, 3, 0x15, 0x15, 4, 0, 1], [0, 3, 5, 5, 4, 2, 0]];
18761 var _STATE_TABLE_RTL = [[2, 0, 1, 1, 0, 1, 0], [2, 0, 1, 1, 0, 2, 0], [2, 0, 2, 1, 3, 2, 0], [2, 0, 2, 0x21, 3, 1, 1]];
18762 var _TYPE_NAMES_MAP = {
18763 "L": 0,
18764 "R": 1,
18765 "EN": 2,
18766 "AN": 3,
18767 "N": 4,
18768 "B": 5,
18769 "S": 6
18770 };
18771 var _UNICODE_RANGES_MAP = {
18772 0: 0,
18773 5: 1,
18774 6: 2,
18775 7: 3,
18776 0x20: 4,
18777 0xFB: 5,
18778 0xFE: 6,
18779 0xFF: 7
18780 };
18781 var _SWAP_TABLE = ["(", ")", "(", "<", ">", "<", "[", "]", "[", "{", "}", "{", "\xAB", "\xBB", "\xAB", "\u2039", "\u203A", "\u2039", "\u2045", "\u2046", "\u2045", "\u207D", "\u207E", "\u207D", "\u208D", "\u208E", "\u208D", "\u2264", "\u2265", "\u2264", "\u2329", "\u232A", "\u2329", "\uFE59", "\uFE5A", "\uFE59", "\uFE5B", "\uFE5C", "\uFE5B", "\uFE5D", "\uFE5E", "\uFE5D", "\uFE64", "\uFE65", "\uFE64"];
18782
18783 var _LTR_RANGES_REG_EXPR = new RegExp(/^([1-4|9]|1[0-9]|2[0-9]|3[0168]|4[04589]|5[012]|7[78]|159|16[0-9]|17[0-2]|21[569]|22[03489]|250)$/);
18784
18785 var _lastArabic = false,
18786 _hasUbatB,
18787 _hasUbatS,
18788 DIR_LTR = 0,
18789 DIR_RTL = 1,
18790 _isInVisual,
18791 _isInRtl,
18792 _isOutVisual,
18793 _isOutRtl,
18794 _isSymmetricSwapping,
18795 _dir = DIR_LTR;
18796
18797 this.__bidiEngine__ = {};
18798
18799 var _init = function _init(text, sourceToTargetMap) {
18800 if (sourceToTargetMap) {
18801 for (var i = 0; i < text.length; i++) {
18802 sourceToTargetMap[i] = i;
18803 }
18804 }
18805
18806 if (_isInRtl === undefined) {
18807 _isInRtl = _isContextualDirRtl(text);
18808 }
18809
18810 if (_isOutRtl === undefined) {
18811 _isOutRtl = _isContextualDirRtl(text);
18812 }
18813 }; // for reference see 3.2 in http://unicode.org/reports/tr9/
18814 //
18815
18816
18817 var _getCharType = function _getCharType(ch) {
18818 var charCode = ch.charCodeAt(),
18819 range = charCode >> 8,
18820 rangeIdx = _UNICODE_RANGES_MAP[range];
18821
18822 if (rangeIdx !== undefined) {
18823 return _UNICODE_TYPES[rangeIdx * 256 + (charCode & 0xFF)];
18824 } else if (range === 0xFC || range === 0xFD) {
18825 return "AL";
18826 } else if (_LTR_RANGES_REG_EXPR.test(range)) {
18827 //unlikely case
18828 return "L";
18829 } else if (range === 8) {
18830 // even less likely
18831 return "R";
18832 }
18833
18834 return "N"; //undefined type, mark as neutral
18835 };
18836
18837 var _isContextualDirRtl = function _isContextualDirRtl(text) {
18838 for (var i = 0, charType; i < text.length; i++) {
18839 charType = _getCharType(text.charAt(i));
18840
18841 if (charType === "L") {
18842 return false;
18843 } else if (charType === "R") {
18844 return true;
18845 }
18846 }
18847
18848 return false;
18849 }; // for reference see 3.3.4 & 3.3.5 in http://unicode.org/reports/tr9/
18850 //
18851
18852
18853 var _resolveCharType = function _resolveCharType(chars, types, resolvedTypes, index) {
18854 var cType = types[index],
18855 wType,
18856 nType,
18857 i,
18858 len;
18859
18860 switch (cType) {
18861 case "L":
18862 case "R":
18863 _lastArabic = false;
18864 break;
18865
18866 case "N":
18867 case "AN":
18868 break;
18869
18870 case "EN":
18871 if (_lastArabic) {
18872 cType = "AN";
18873 }
18874
18875 break;
18876
18877 case "AL":
18878 _lastArabic = true;
18879 cType = "R";
18880 break;
18881
18882 case "WS":
18883 cType = "N";
18884 break;
18885
18886 case "CS":
18887 if (index < 1 || index + 1 >= types.length || (wType = resolvedTypes[index - 1]) !== "EN" && wType !== "AN" || (nType = types[index + 1]) !== "EN" && nType !== "AN") {
18888 cType = "N";
18889 } else if (_lastArabic) {
18890 nType = "AN";
18891 }
18892
18893 cType = nType === wType ? nType : "N";
18894 break;
18895
18896 case "ES":
18897 wType = index > 0 ? resolvedTypes[index - 1] : "B";
18898 cType = wType === "EN" && index + 1 < types.length && types[index + 1] === "EN" ? "EN" : "N";
18899 break;
18900
18901 case "ET":
18902 if (index > 0 && resolvedTypes[index - 1] === "EN") {
18903 cType = "EN";
18904 break;
18905 } else if (_lastArabic) {
18906 cType = "N";
18907 break;
18908 }
18909
18910 i = index + 1;
18911 len = types.length;
18912
18913 while (i < len && types[i] === "ET") {
18914 i++;
18915 }
18916
18917 if (i < len && types[i] === "EN") {
18918 cType = "EN";
18919 } else {
18920 cType = "N";
18921 }
18922
18923 break;
18924
18925 case "NSM":
18926 if (_isInVisual && !_isInRtl) {
18927 //V->L
18928 len = types.length;
18929 i = index + 1;
18930
18931 while (i < len && types[i] === "NSM") {
18932 i++;
18933 }
18934
18935 if (i < len) {
18936 var c = chars[index];
18937 var rtlCandidate = c >= 0x0591 && c <= 0x08FF || c === 0xFB1E;
18938 wType = types[i];
18939
18940 if (rtlCandidate && (wType === "R" || wType === "AL")) {
18941 cType = "R";
18942 break;
18943 }
18944 }
18945 }
18946
18947 if (index < 1 || (wType = types[index - 1]) === "B") {
18948 cType = "N";
18949 } else {
18950 cType = resolvedTypes[index - 1];
18951 }
18952
18953 break;
18954
18955 case "B":
18956 _lastArabic = false;
18957 _hasUbatB = true;
18958 cType = _dir;
18959 break;
18960
18961 case "S":
18962 _hasUbatS = true;
18963 cType = "N";
18964 break;
18965
18966 case "LRE":
18967 case "RLE":
18968 case "LRO":
18969 case "RLO":
18970 case "PDF":
18971 _lastArabic = false;
18972 break;
18973
18974 case "BN":
18975 cType = "N";
18976 break;
18977 }
18978
18979 return cType;
18980 };
18981
18982 var _handleUbatS = function _handleUbatS(types, levels, length) {
18983 for (var i = 0; i < length; i++) {
18984 if (types[i] === "S") {
18985 levels[i] = _dir;
18986
18987 for (var j = i - 1; j >= 0; j--) {
18988 if (types[j] === "WS") {
18989 levels[j] = _dir;
18990 } else {
18991 break;
18992 }
18993 }
18994 }
18995 }
18996 };
18997
18998 var _invertString = function _invertString(text, sourceToTargetMap, levels) {
18999 var charArray = text.split("");
19000
19001 if (levels) {
19002 _computeLevels(charArray, levels, {
19003 hiLevel: _dir
19004 });
19005 }
19006
19007 charArray.reverse();
19008 sourceToTargetMap && sourceToTargetMap.reverse();
19009 return charArray.join("");
19010 }; // For reference see 3.3 in http://unicode.org/reports/tr9/
19011 //
19012
19013
19014 var _computeLevels = function _computeLevels(chars, levels, params) {
19015 var action,
19016 condition,
19017 i,
19018 index,
19019 newLevel,
19020 prevState,
19021 condPos = -1,
19022 len = chars.length,
19023 newState = 0,
19024 resolvedTypes = [],
19025 stateTable = _dir ? _STATE_TABLE_RTL : _STATE_TABLE_LTR,
19026 types = [];
19027 _lastArabic = false;
19028 _hasUbatB = false;
19029 _hasUbatS = false;
19030
19031 for (i = 0; i < len; i++) {
19032 types[i] = _getCharType(chars[i]);
19033 }
19034
19035 for (index = 0; index < len; index++) {
19036 prevState = newState;
19037 resolvedTypes[index] = _resolveCharType(chars, types, resolvedTypes, index);
19038 newState = stateTable[prevState][_TYPE_NAMES_MAP[resolvedTypes[index]]];
19039 action = newState & 0xF0;
19040 newState &= 0x0F;
19041 levels[index] = newLevel = stateTable[newState][5];
19042
19043 if (action > 0) {
19044 if (action === 0x10) {
19045 for (i = condPos; i < index; i++) {
19046 levels[i] = 1;
19047 }
19048
19049 condPos = -1;
19050 } else {
19051 condPos = -1;
19052 }
19053 }
19054
19055 condition = stateTable[newState][6];
19056
19057 if (condition) {
19058 if (condPos === -1) {
19059 condPos = index;
19060 }
19061 } else {
19062 if (condPos > -1) {
19063 for (i = condPos; i < index; i++) {
19064 levels[i] = newLevel;
19065 }
19066
19067 condPos = -1;
19068 }
19069 }
19070
19071 if (types[index] === "B") {
19072 levels[index] = 0;
19073 }
19074
19075 params.hiLevel |= newLevel;
19076 }
19077
19078 if (_hasUbatS) {
19079 _handleUbatS(types, levels, len);
19080 }
19081 }; // for reference see 3.4 in http://unicode.org/reports/tr9/
19082 //
19083
19084
19085 var _invertByLevel = function _invertByLevel(level, charArray, sourceToTargetMap, levels, params) {
19086 if (params.hiLevel < level) {
19087 return;
19088 }
19089
19090 if (level === 1 && _dir === DIR_RTL && !_hasUbatB) {
19091 charArray.reverse();
19092 sourceToTargetMap && sourceToTargetMap.reverse();
19093 return;
19094 }
19095
19096 var ch,
19097 high,
19098 end,
19099 low,
19100 len = charArray.length,
19101 start = 0;
19102
19103 while (start < len) {
19104 if (levels[start] >= level) {
19105 end = start + 1;
19106
19107 while (end < len && levels[end] >= level) {
19108 end++;
19109 }
19110
19111 for (low = start, high = end - 1; low < high; low++, high--) {
19112 ch = charArray[low];
19113 charArray[low] = charArray[high];
19114 charArray[high] = ch;
19115
19116 if (sourceToTargetMap) {
19117 ch = sourceToTargetMap[low];
19118 sourceToTargetMap[low] = sourceToTargetMap[high];
19119 sourceToTargetMap[high] = ch;
19120 }
19121 }
19122
19123 start = end;
19124 }
19125
19126 start++;
19127 }
19128 }; // for reference see 7 & BD16 in http://unicode.org/reports/tr9/
19129 //
19130
19131
19132 var _symmetricSwap = function _symmetricSwap(charArray, levels, params) {
19133 if (params.hiLevel !== 0 && _isSymmetricSwapping) {
19134 for (var i = 0, index; i < charArray.length; i++) {
19135 if (levels[i] === 1) {
19136 index = _SWAP_TABLE.indexOf(charArray[i]);
19137
19138 if (index >= 0) {
19139 charArray[i] = _SWAP_TABLE[index + 1];
19140 }
19141 }
19142 }
19143 }
19144 };
19145
19146 var _reorder = function _reorder(text, sourceToTargetMap, levels) {
19147 var charArray = text.split(""),
19148 params = {
19149 hiLevel: _dir
19150 };
19151
19152 if (!levels) {
19153 levels = [];
19154 }
19155
19156 _computeLevels(charArray, levels, params);
19157
19158 _symmetricSwap(charArray, levels, params);
19159
19160 _invertByLevel(DIR_RTL + 1, charArray, sourceToTargetMap, levels, params);
19161
19162 _invertByLevel(DIR_RTL, charArray, sourceToTargetMap, levels, params);
19163
19164 return charArray.join("");
19165 }; // doBidiReorder( text, sourceToTargetMap, levels )
19166 // Performs Bidi reordering by implementing Unicode Bidi algorithm.
19167 // Returns reordered string
19168 // @text [String]:
19169 // - input string to be reordered, this is input parameter
19170 // $sourceToTargetMap [Array] (optional)
19171 // - resultant mapping between input and output strings, this is output parameter
19172 // $levels [Array] (optional)
19173 // - array of calculated Bidi levels, , this is output parameter
19174
19175
19176 this.__bidiEngine__.doBidiReorder = function (text, sourceToTargetMap, levels) {
19177 _init(text, sourceToTargetMap);
19178
19179 if (!_isInVisual && _isOutVisual && !_isOutRtl) {
19180 // LLTR->VLTR, LRTL->VLTR
19181 _dir = _isInRtl ? DIR_RTL : DIR_LTR;
19182 text = _reorder(text, sourceToTargetMap, levels);
19183 } else if (_isInVisual && _isOutVisual && _isInRtl ^ _isOutRtl) {
19184 // VRTL->VLTR, VLTR->VRTL
19185 _dir = _isInRtl ? DIR_RTL : DIR_LTR;
19186 text = _invertString(text, sourceToTargetMap, levels);
19187 } else if (!_isInVisual && _isOutVisual && _isOutRtl) {
19188 // LLTR->VRTL, LRTL->VRTL
19189 _dir = _isInRtl ? DIR_RTL : DIR_LTR;
19190 text = _reorder(text, sourceToTargetMap, levels);
19191 text = _invertString(text, sourceToTargetMap);
19192 } else if (_isInVisual && !_isInRtl && !_isOutVisual && !_isOutRtl) {
19193 // VLTR->LLTR
19194 _dir = DIR_LTR;
19195 text = _reorder(text, sourceToTargetMap, levels);
19196 } else if (_isInVisual && !_isOutVisual && _isInRtl ^ _isOutRtl) {
19197 // VLTR->LRTL, VRTL->LLTR
19198 text = _invertString(text, sourceToTargetMap);
19199
19200 if (_isInRtl) {
19201 //LLTR -> VLTR
19202 _dir = DIR_LTR;
19203 text = _reorder(text, sourceToTargetMap, levels);
19204 } else {
19205 //LRTL -> VRTL
19206 _dir = DIR_RTL;
19207 text = _reorder(text, sourceToTargetMap, levels);
19208 text = _invertString(text, sourceToTargetMap);
19209 }
19210 } else if (_isInVisual && _isInRtl && !_isOutVisual && _isOutRtl) {
19211 // VRTL->LRTL
19212 _dir = DIR_RTL;
19213 text = _reorder(text, sourceToTargetMap, levels);
19214 text = _invertString(text, sourceToTargetMap);
19215 } else if (!_isInVisual && !_isOutVisual && _isInRtl ^ _isOutRtl) {
19216 // LRTL->LLTR, LLTR->LRTL
19217 var isSymmetricSwappingOrig = _isSymmetricSwapping;
19218
19219 if (_isInRtl) {
19220 //LRTL->LLTR
19221 _dir = DIR_RTL;
19222 text = _reorder(text, sourceToTargetMap, levels);
19223 _dir = DIR_LTR;
19224 _isSymmetricSwapping = false;
19225 text = _reorder(text, sourceToTargetMap, levels);
19226 _isSymmetricSwapping = isSymmetricSwappingOrig;
19227 } else {
19228 //LLTR->LRTL
19229 _dir = DIR_LTR;
19230 text = _reorder(text, sourceToTargetMap, levels);
19231 text = _invertString(text, sourceToTargetMap);
19232 _dir = DIR_RTL;
19233 _isSymmetricSwapping = false;
19234 text = _reorder(text, sourceToTargetMap, levels);
19235 _isSymmetricSwapping = isSymmetricSwappingOrig;
19236 text = _invertString(text, sourceToTargetMap);
19237 }
19238 }
19239
19240 return text;
19241 };
19242 /**
19243 * @name setOptions( options )
19244 * @function
19245 * Sets options for Bidi conversion
19246 * @param {Object}:
19247 * - isInputVisual {boolean} (defaults to false): allowed values: true(Visual mode), false(Logical mode)
19248 * - isInputRtl {boolean}: allowed values true(Right-to-left direction), false (Left-to-right directiion), undefined(Contectual direction, i.e.direction defined by first strong character of input string)
19249 * - isOutputVisual {boolean} (defaults to false): allowed values: true(Visual mode), false(Logical mode)
19250 * - isOutputRtl {boolean}: allowed values true(Right-to-left direction), false (Left-to-right directiion), undefined(Contectual direction, i.e.direction defined by first strong characterof input string)
19251 * - isSymmetricSwapping {boolean} (defaults to false): allowed values true(needs symmetric swapping), false (no need in symmetric swapping),
19252 */
19253
19254
19255 this.__bidiEngine__.setOptions = function (options) {
19256 if (options) {
19257 _isInVisual = options.isInputVisual;
19258 _isOutVisual = options.isOutputVisual;
19259 _isInRtl = options.isInputRtl;
19260 _isOutRtl = options.isOutputRtl;
19261 _isSymmetricSwapping = options.isSymmetricSwapping;
19262 }
19263 };
19264
19265 this.__bidiEngine__.setOptions(options);
19266
19267 return this.__bidiEngine__;
19268 };
19269
19270 var _bidiUnicodeTypes = bidiUnicodeTypes;
19271 var bidiEngine = new jsPDF.__bidiEngine__({
19272 isInputVisual: true
19273 });
19274
19275 var bidiEngineFunction = function bidiEngineFunction(args) {
19276 var text = args.text;
19277 var x = args.x;
19278 var y = args.y;
19279 var options = args.options || {};
19280 var mutex = args.mutex || {};
19281 var lang = options.lang;
19282 var tmpText = [];
19283
19284 if (Object.prototype.toString.call(text) === '[object Array]') {
19285 var i = 0;
19286 tmpText = [];
19287
19288 for (i = 0; i < text.length; i += 1) {
19289 if (Object.prototype.toString.call(text[i]) === '[object Array]') {
19290 tmpText.push([bidiEngine.doBidiReorder(text[i][0]), text[i][1], text[i][2]]);
19291 } else {
19292 tmpText.push([bidiEngine.doBidiReorder(text[i])]);
19293 }
19294 }
19295
19296 args.text = tmpText;
19297 } else {
19298 args.text = bidiEngine.doBidiReorder(text);
19299 }
19300 };
19301
19302 jsPDF.API.events.push(['postProcessText', bidiEngineFunction]);
19303 })(jsPDF);
19304
19305 /*
19306 Copyright (c) 2008, Adobe Systems Incorporated
19307 All rights reserved.
19308
19309 Redistribution and use in source and binary forms, with or without
19310 modification, are permitted provided that the following conditions are
19311 met:
19312
19313 * Redistributions of source code must retain the above copyright notice,
19314 this list of conditions and the following disclaimer.
19315
19316 * Redistributions in binary form must reproduce the above copyright
19317 notice, this list of conditions and the following disclaimer in the
19318 documentation and/or other materials provided with the distribution.
19319
19320 * Neither the name of Adobe Systems Incorporated nor the names of its
19321 contributors may be used to endorse or promote products derived from
19322 this software without specific prior written permission.
19323
19324 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
19325 IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
19326 THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19327 PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
19328 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19329 EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19330 PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
19331 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
19332 LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
19333 NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
19334 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
19335 */
19336
19337 /*
19338 JPEG encoder ported to JavaScript and optimized by Andreas Ritter, www.bytestrom.eu, 11/2009
19339
19340 Basic GUI blocking jpeg encoder
19341 */
19342 function JPEGEncoder(quality) {
19343 var ffloor = Math.floor;
19344 var YTable = new Array(64);
19345 var UVTable = new Array(64);
19346 var fdtbl_Y = new Array(64);
19347 var fdtbl_UV = new Array(64);
19348 var YDC_HT;
19349 var UVDC_HT;
19350 var YAC_HT;
19351 var UVAC_HT;
19352 var bitcode = new Array(65535);
19353 var category = new Array(65535);
19354 var outputfDCTQuant = new Array(64);
19355 var DU = new Array(64);
19356 var byteout = [];
19357 var bytenew = 0;
19358 var bytepos = 7;
19359 var YDU = new Array(64);
19360 var UDU = new Array(64);
19361 var VDU = new Array(64);
19362 var clt = new Array(256);
19363 var RGB_YUV_TABLE = new Array(2048);
19364 var currentQuality;
19365 var ZigZag = [0, 1, 5, 6, 14, 15, 27, 28, 2, 4, 7, 13, 16, 26, 29, 42, 3, 8, 12, 17, 25, 30, 41, 43, 9, 11, 18, 24, 31, 40, 44, 53, 10, 19, 23, 32, 39, 45, 52, 54, 20, 22, 33, 38, 46, 51, 55, 60, 21, 34, 37, 47, 50, 56, 59, 61, 35, 36, 48, 49, 57, 58, 62, 63];
19366 var std_dc_luminance_nrcodes = [0, 0, 1, 5, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0];
19367 var std_dc_luminance_values = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11];
19368 var std_ac_luminance_nrcodes = [0, 0, 2, 1, 3, 3, 2, 4, 3, 5, 5, 4, 4, 0, 0, 1, 0x7d];
19369 var std_ac_luminance_values = [0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07, 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08, 0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0, 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa];
19370 var std_dc_chrominance_nrcodes = [0, 0, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0];
19371 var std_dc_chrominance_values = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11];
19372 var std_ac_chrominance_nrcodes = [0, 0, 2, 1, 2, 4, 4, 3, 4, 7, 5, 4, 4, 0, 1, 2, 0x77];
19373 var std_ac_chrominance_values = [0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21, 0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71, 0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91, 0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0, 0x15, 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34, 0xe1, 0x25, 0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa];
19374
19375 function initQuantTables(sf) {
19376 var YQT = [16, 11, 10, 16, 24, 40, 51, 61, 12, 12, 14, 19, 26, 58, 60, 55, 14, 13, 16, 24, 40, 57, 69, 56, 14, 17, 22, 29, 51, 87, 80, 62, 18, 22, 37, 56, 68, 109, 103, 77, 24, 35, 55, 64, 81, 104, 113, 92, 49, 64, 78, 87, 103, 121, 120, 101, 72, 92, 95, 98, 112, 100, 103, 99];
19377
19378 for (var i = 0; i < 64; i++) {
19379 var t = ffloor((YQT[i] * sf + 50) / 100);
19380
19381 if (t < 1) {
19382 t = 1;
19383 } else if (t > 255) {
19384 t = 255;
19385 }
19386
19387 YTable[ZigZag[i]] = t;
19388 }
19389
19390 var UVQT = [17, 18, 24, 47, 99, 99, 99, 99, 18, 21, 26, 66, 99, 99, 99, 99, 24, 26, 56, 99, 99, 99, 99, 99, 47, 66, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99];
19391
19392 for (var j = 0; j < 64; j++) {
19393 var u = ffloor((UVQT[j] * sf + 50) / 100);
19394
19395 if (u < 1) {
19396 u = 1;
19397 } else if (u > 255) {
19398 u = 255;
19399 }
19400
19401 UVTable[ZigZag[j]] = u;
19402 }
19403
19404 var aasf = [1.0, 1.387039845, 1.306562965, 1.175875602, 1.0, 0.785694958, 0.541196100, 0.275899379];
19405 var k = 0;
19406
19407 for (var row = 0; row < 8; row++) {
19408 for (var col = 0; col < 8; col++) {
19409 fdtbl_Y[k] = 1.0 / (YTable[ZigZag[k]] * aasf[row] * aasf[col] * 8.0);
19410 fdtbl_UV[k] = 1.0 / (UVTable[ZigZag[k]] * aasf[row] * aasf[col] * 8.0);
19411 k++;
19412 }
19413 }
19414 }
19415
19416 function computeHuffmanTbl(nrcodes, std_table) {
19417 var codevalue = 0;
19418 var pos_in_table = 0;
19419 var HT = new Array();
19420
19421 for (var k = 1; k <= 16; k++) {
19422 for (var j = 1; j <= nrcodes[k]; j++) {
19423 HT[std_table[pos_in_table]] = [];
19424 HT[std_table[pos_in_table]][0] = codevalue;
19425 HT[std_table[pos_in_table]][1] = k;
19426 pos_in_table++;
19427 codevalue++;
19428 }
19429
19430 codevalue *= 2;
19431 }
19432
19433 return HT;
19434 }
19435
19436 function initHuffmanTbl() {
19437 YDC_HT = computeHuffmanTbl(std_dc_luminance_nrcodes, std_dc_luminance_values);
19438 UVDC_HT = computeHuffmanTbl(std_dc_chrominance_nrcodes, std_dc_chrominance_values);
19439 YAC_HT = computeHuffmanTbl(std_ac_luminance_nrcodes, std_ac_luminance_values);
19440 UVAC_HT = computeHuffmanTbl(std_ac_chrominance_nrcodes, std_ac_chrominance_values);
19441 }
19442
19443 function initCategoryNumber() {
19444 var nrlower = 1;
19445 var nrupper = 2;
19446
19447 for (var cat = 1; cat <= 15; cat++) {
19448 //Positive numbers
19449 for (var nr = nrlower; nr < nrupper; nr++) {
19450 category[32767 + nr] = cat;
19451 bitcode[32767 + nr] = [];
19452 bitcode[32767 + nr][1] = cat;
19453 bitcode[32767 + nr][0] = nr;
19454 } //Negative numbers
19455
19456
19457 for (var nrneg = -(nrupper - 1); nrneg <= -nrlower; nrneg++) {
19458 category[32767 + nrneg] = cat;
19459 bitcode[32767 + nrneg] = [];
19460 bitcode[32767 + nrneg][1] = cat;
19461 bitcode[32767 + nrneg][0] = nrupper - 1 + nrneg;
19462 }
19463
19464 nrlower <<= 1;
19465 nrupper <<= 1;
19466 }
19467 }
19468
19469 function initRGBYUVTable() {
19470 for (var i = 0; i < 256; i++) {
19471 RGB_YUV_TABLE[i] = 19595 * i;
19472 RGB_YUV_TABLE[i + 256 >> 0] = 38470 * i;
19473 RGB_YUV_TABLE[i + 512 >> 0] = 7471 * i + 0x8000;
19474 RGB_YUV_TABLE[i + 768 >> 0] = -11059 * i;
19475 RGB_YUV_TABLE[i + 1024 >> 0] = -21709 * i;
19476 RGB_YUV_TABLE[i + 1280 >> 0] = 32768 * i + 0x807FFF;
19477 RGB_YUV_TABLE[i + 1536 >> 0] = -27439 * i;
19478 RGB_YUV_TABLE[i + 1792 >> 0] = -5329 * i;
19479 }
19480 } // IO functions
19481
19482
19483 function writeBits(bs) {
19484 var value = bs[0];
19485 var posval = bs[1] - 1;
19486
19487 while (posval >= 0) {
19488 if (value & 1 << posval) {
19489 bytenew |= 1 << bytepos;
19490 }
19491
19492 posval--;
19493 bytepos--;
19494
19495 if (bytepos < 0) {
19496 if (bytenew == 0xFF) {
19497 writeByte(0xFF);
19498 writeByte(0);
19499 } else {
19500 writeByte(bytenew);
19501 }
19502
19503 bytepos = 7;
19504 bytenew = 0;
19505 }
19506 }
19507 }
19508
19509 function writeByte(value) {
19510 //byteout.push(clt[value]); // write char directly instead of converting later
19511 byteout.push(value);
19512 }
19513
19514 function writeWord(value) {
19515 writeByte(value >> 8 & 0xFF);
19516 writeByte(value & 0xFF);
19517 } // DCT & quantization core
19518
19519
19520 function fDCTQuant(data, fdtbl) {
19521 var d0, d1, d2, d3, d4, d5, d6, d7;
19522 /* Pass 1: process rows. */
19523
19524 var dataOff = 0;
19525 var i;
19526 var I8 = 8;
19527 var I64 = 64;
19528
19529 for (i = 0; i < I8; ++i) {
19530 d0 = data[dataOff];
19531 d1 = data[dataOff + 1];
19532 d2 = data[dataOff + 2];
19533 d3 = data[dataOff + 3];
19534 d4 = data[dataOff + 4];
19535 d5 = data[dataOff + 5];
19536 d6 = data[dataOff + 6];
19537 d7 = data[dataOff + 7];
19538 var tmp0 = d0 + d7;
19539 var tmp7 = d0 - d7;
19540 var tmp1 = d1 + d6;
19541 var tmp6 = d1 - d6;
19542 var tmp2 = d2 + d5;
19543 var tmp5 = d2 - d5;
19544 var tmp3 = d3 + d4;
19545 var tmp4 = d3 - d4;
19546 /* Even part */
19547
19548 var tmp10 = tmp0 + tmp3;
19549 /* phase 2 */
19550
19551 var tmp13 = tmp0 - tmp3;
19552 var tmp11 = tmp1 + tmp2;
19553 var tmp12 = tmp1 - tmp2;
19554 data[dataOff] = tmp10 + tmp11;
19555 /* phase 3 */
19556
19557 data[dataOff + 4] = tmp10 - tmp11;
19558 var z1 = (tmp12 + tmp13) * 0.707106781;
19559 /* c4 */
19560
19561 data[dataOff + 2] = tmp13 + z1;
19562 /* phase 5 */
19563
19564 data[dataOff + 6] = tmp13 - z1;
19565 /* Odd part */
19566
19567 tmp10 = tmp4 + tmp5;
19568 /* phase 2 */
19569
19570 tmp11 = tmp5 + tmp6;
19571 tmp12 = tmp6 + tmp7;
19572 /* The rotator is modified from fig 4-8 to avoid extra negations. */
19573
19574 var z5 = (tmp10 - tmp12) * 0.382683433;
19575 /* c6 */
19576
19577 var z2 = 0.541196100 * tmp10 + z5;
19578 /* c2-c6 */
19579
19580 var z4 = 1.306562965 * tmp12 + z5;
19581 /* c2+c6 */
19582
19583 var z3 = tmp11 * 0.707106781;
19584 /* c4 */
19585
19586 var z11 = tmp7 + z3;
19587 /* phase 5 */
19588
19589 var z13 = tmp7 - z3;
19590 data[dataOff + 5] = z13 + z2;
19591 /* phase 6 */
19592
19593 data[dataOff + 3] = z13 - z2;
19594 data[dataOff + 1] = z11 + z4;
19595 data[dataOff + 7] = z11 - z4;
19596 dataOff += 8;
19597 /* advance pointer to next row */
19598 }
19599 /* Pass 2: process columns. */
19600
19601
19602 dataOff = 0;
19603
19604 for (i = 0; i < I8; ++i) {
19605 d0 = data[dataOff];
19606 d1 = data[dataOff + 8];
19607 d2 = data[dataOff + 16];
19608 d3 = data[dataOff + 24];
19609 d4 = data[dataOff + 32];
19610 d5 = data[dataOff + 40];
19611 d6 = data[dataOff + 48];
19612 d7 = data[dataOff + 56];
19613 var tmp0p2 = d0 + d7;
19614 var tmp7p2 = d0 - d7;
19615 var tmp1p2 = d1 + d6;
19616 var tmp6p2 = d1 - d6;
19617 var tmp2p2 = d2 + d5;
19618 var tmp5p2 = d2 - d5;
19619 var tmp3p2 = d3 + d4;
19620 var tmp4p2 = d3 - d4;
19621 /* Even part */
19622
19623 var tmp10p2 = tmp0p2 + tmp3p2;
19624 /* phase 2 */
19625
19626 var tmp13p2 = tmp0p2 - tmp3p2;
19627 var tmp11p2 = tmp1p2 + tmp2p2;
19628 var tmp12p2 = tmp1p2 - tmp2p2;
19629 data[dataOff] = tmp10p2 + tmp11p2;
19630 /* phase 3 */
19631
19632 data[dataOff + 32] = tmp10p2 - tmp11p2;
19633 var z1p2 = (tmp12p2 + tmp13p2) * 0.707106781;
19634 /* c4 */
19635
19636 data[dataOff + 16] = tmp13p2 + z1p2;
19637 /* phase 5 */
19638
19639 data[dataOff + 48] = tmp13p2 - z1p2;
19640 /* Odd part */
19641
19642 tmp10p2 = tmp4p2 + tmp5p2;
19643 /* phase 2 */
19644
19645 tmp11p2 = tmp5p2 + tmp6p2;
19646 tmp12p2 = tmp6p2 + tmp7p2;
19647 /* The rotator is modified from fig 4-8 to avoid extra negations. */
19648
19649 var z5p2 = (tmp10p2 - tmp12p2) * 0.382683433;
19650 /* c6 */
19651
19652 var z2p2 = 0.541196100 * tmp10p2 + z5p2;
19653 /* c2-c6 */
19654
19655 var z4p2 = 1.306562965 * tmp12p2 + z5p2;
19656 /* c2+c6 */
19657
19658 var z3p2 = tmp11p2 * 0.707106781;
19659 /* c4 */
19660
19661 var z11p2 = tmp7p2 + z3p2;
19662 /* phase 5 */
19663
19664 var z13p2 = tmp7p2 - z3p2;
19665 data[dataOff + 40] = z13p2 + z2p2;
19666 /* phase 6 */
19667
19668 data[dataOff + 24] = z13p2 - z2p2;
19669 data[dataOff + 8] = z11p2 + z4p2;
19670 data[dataOff + 56] = z11p2 - z4p2;
19671 dataOff++;
19672 /* advance pointer to next column */
19673 } // Quantize/descale the coefficients
19674
19675
19676 var fDCTQuant;
19677
19678 for (i = 0; i < I64; ++i) {
19679 // Apply the quantization and scaling factor & Round to nearest integer
19680 fDCTQuant = data[i] * fdtbl[i];
19681 outputfDCTQuant[i] = fDCTQuant > 0.0 ? fDCTQuant + 0.5 | 0 : fDCTQuant - 0.5 | 0; //outputfDCTQuant[i] = fround(fDCTQuant);
19682 }
19683
19684 return outputfDCTQuant;
19685 }
19686
19687 function writeAPP0() {
19688 writeWord(0xFFE0); // marker
19689
19690 writeWord(16); // length
19691
19692 writeByte(0x4A); // J
19693
19694 writeByte(0x46); // F
19695
19696 writeByte(0x49); // I
19697
19698 writeByte(0x46); // F
19699
19700 writeByte(0); // = "JFIF",'\0'
19701
19702 writeByte(1); // versionhi
19703
19704 writeByte(1); // versionlo
19705
19706 writeByte(0); // xyunits
19707
19708 writeWord(1); // xdensity
19709
19710 writeWord(1); // ydensity
19711
19712 writeByte(0); // thumbnwidth
19713
19714 writeByte(0); // thumbnheight
19715 }
19716
19717 function writeSOF0(width, height) {
19718 writeWord(0xFFC0); // marker
19719
19720 writeWord(17); // length, truecolor YUV JPG
19721
19722 writeByte(8); // precision
19723
19724 writeWord(height);
19725 writeWord(width);
19726 writeByte(3); // nrofcomponents
19727
19728 writeByte(1); // IdY
19729
19730 writeByte(0x11); // HVY
19731
19732 writeByte(0); // QTY
19733
19734 writeByte(2); // IdU
19735
19736 writeByte(0x11); // HVU
19737
19738 writeByte(1); // QTU
19739
19740 writeByte(3); // IdV
19741
19742 writeByte(0x11); // HVV
19743
19744 writeByte(1); // QTV
19745 }
19746
19747 function writeDQT() {
19748 writeWord(0xFFDB); // marker
19749
19750 writeWord(132); // length
19751
19752 writeByte(0);
19753
19754 for (var i = 0; i < 64; i++) {
19755 writeByte(YTable[i]);
19756 }
19757
19758 writeByte(1);
19759
19760 for (var j = 0; j < 64; j++) {
19761 writeByte(UVTable[j]);
19762 }
19763 }
19764
19765 function writeDHT() {
19766 writeWord(0xFFC4); // marker
19767
19768 writeWord(0x01A2); // length
19769
19770 writeByte(0); // HTYDCinfo
19771
19772 for (var i = 0; i < 16; i++) {
19773 writeByte(std_dc_luminance_nrcodes[i + 1]);
19774 }
19775
19776 for (var j = 0; j <= 11; j++) {
19777 writeByte(std_dc_luminance_values[j]);
19778 }
19779
19780 writeByte(0x10); // HTYACinfo
19781
19782 for (var k = 0; k < 16; k++) {
19783 writeByte(std_ac_luminance_nrcodes[k + 1]);
19784 }
19785
19786 for (var l = 0; l <= 161; l++) {
19787 writeByte(std_ac_luminance_values[l]);
19788 }
19789
19790 writeByte(1); // HTUDCinfo
19791
19792 for (var m = 0; m < 16; m++) {
19793 writeByte(std_dc_chrominance_nrcodes[m + 1]);
19794 }
19795
19796 for (var n = 0; n <= 11; n++) {
19797 writeByte(std_dc_chrominance_values[n]);
19798 }
19799
19800 writeByte(0x11); // HTUACinfo
19801
19802 for (var o = 0; o < 16; o++) {
19803 writeByte(std_ac_chrominance_nrcodes[o + 1]);
19804 }
19805
19806 for (var p = 0; p <= 161; p++) {
19807 writeByte(std_ac_chrominance_values[p]);
19808 }
19809 }
19810
19811 function writeSOS() {
19812 writeWord(0xFFDA); // marker
19813
19814 writeWord(12); // length
19815
19816 writeByte(3); // nrofcomponents
19817
19818 writeByte(1); // IdY
19819
19820 writeByte(0); // HTY
19821
19822 writeByte(2); // IdU
19823
19824 writeByte(0x11); // HTU
19825
19826 writeByte(3); // IdV
19827
19828 writeByte(0x11); // HTV
19829
19830 writeByte(0); // Ss
19831
19832 writeByte(0x3f); // Se
19833
19834 writeByte(0); // Bf
19835 }
19836
19837 function processDU(CDU, fdtbl, DC, HTDC, HTAC) {
19838 var EOB = HTAC[0x00];
19839 var M16zeroes = HTAC[0xF0];
19840 var pos;
19841 var I16 = 16;
19842 var I63 = 63;
19843 var I64 = 64;
19844 var DU_DCT = fDCTQuant(CDU, fdtbl); //ZigZag reorder
19845
19846 for (var j = 0; j < I64; ++j) {
19847 DU[ZigZag[j]] = DU_DCT[j];
19848 }
19849
19850 var Diff = DU[0] - DC;
19851 DC = DU[0]; //Encode DC
19852
19853 if (Diff == 0) {
19854 writeBits(HTDC[0]); // Diff might be 0
19855 } else {
19856 pos = 32767 + Diff;
19857 writeBits(HTDC[category[pos]]);
19858 writeBits(bitcode[pos]);
19859 } //Encode ACs
19860
19861
19862 var end0pos = 63; // was const... which is crazy
19863
19864 for (; end0pos > 0 && DU[end0pos] == 0; end0pos--) {}
19865
19866 if (end0pos == 0) {
19867 writeBits(EOB);
19868 return DC;
19869 }
19870
19871 var i = 1;
19872 var lng;
19873
19874 while (i <= end0pos) {
19875 var startpos = i;
19876
19877 for (; DU[i] == 0 && i <= end0pos; ++i) {}
19878
19879 var nrzeroes = i - startpos;
19880
19881 if (nrzeroes >= I16) {
19882 lng = nrzeroes >> 4;
19883
19884 for (var nrmarker = 1; nrmarker <= lng; ++nrmarker) {
19885 writeBits(M16zeroes);
19886 }
19887
19888 nrzeroes = nrzeroes & 0xF;
19889 }
19890
19891 pos = 32767 + DU[i];
19892 writeBits(HTAC[(nrzeroes << 4) + category[pos]]);
19893 writeBits(bitcode[pos]);
19894 i++;
19895 }
19896
19897 if (end0pos != I63) {
19898 writeBits(EOB);
19899 }
19900
19901 return DC;
19902 }
19903
19904 function initCharLookupTable() {
19905 var sfcc = String.fromCharCode;
19906
19907 for (var i = 0; i < 256; i++) {
19908 ///// ACHTUNG // 255
19909 clt[i] = sfcc(i);
19910 }
19911 }
19912
19913 this.encode = function (image, quality) // image data object
19914 {
19915 var time_start = new Date().getTime();
19916 if (quality) setQuality(quality); // Initialize bit writer
19917
19918 byteout = new Array();
19919 bytenew = 0;
19920 bytepos = 7; // Add JPEG headers
19921
19922 writeWord(0xFFD8); // SOI
19923
19924 writeAPP0();
19925 writeDQT();
19926 writeSOF0(image.width, image.height);
19927 writeDHT();
19928 writeSOS(); // Encode 8x8 macroblocks
19929
19930 var DCY = 0;
19931 var DCU = 0;
19932 var DCV = 0;
19933 bytenew = 0;
19934 bytepos = 7;
19935 this.encode.displayName = "_encode_";
19936 var imageData = image.data;
19937 var width = image.width;
19938 var height = image.height;
19939 var quadWidth = width * 4;
19940 var x,
19941 y = 0;
19942 var r, g, b;
19943 var start, p, col, row, pos;
19944
19945 while (y < height) {
19946 x = 0;
19947
19948 while (x < quadWidth) {
19949 start = quadWidth * y + x;
19950 p = start;
19951 col = -1;
19952 row = 0;
19953
19954 for (pos = 0; pos < 64; pos++) {
19955 row = pos >> 3; // /8
19956
19957 col = (pos & 7) * 4; // %8
19958
19959 p = start + row * quadWidth + col;
19960
19961 if (y + row >= height) {
19962 // padding bottom
19963 p -= quadWidth * (y + 1 + row - height);
19964 }
19965
19966 if (x + col >= quadWidth) {
19967 // padding right
19968 p -= x + col - quadWidth + 4;
19969 }
19970
19971 r = imageData[p++];
19972 g = imageData[p++];
19973 b = imageData[p++];
19974 /* // calculate YUV values dynamically
19975 YDU[pos]=((( 0.29900)*r+( 0.58700)*g+( 0.11400)*b))-128; //-0x80
19976 UDU[pos]=(((-0.16874)*r+(-0.33126)*g+( 0.50000)*b));
19977 VDU[pos]=((( 0.50000)*r+(-0.41869)*g+(-0.08131)*b));
19978 */
19979 // use lookup table (slightly faster)
19980
19981 YDU[pos] = (RGB_YUV_TABLE[r] + RGB_YUV_TABLE[g + 256 >> 0] + RGB_YUV_TABLE[b + 512 >> 0] >> 16) - 128;
19982 UDU[pos] = (RGB_YUV_TABLE[r + 768 >> 0] + RGB_YUV_TABLE[g + 1024 >> 0] + RGB_YUV_TABLE[b + 1280 >> 0] >> 16) - 128;
19983 VDU[pos] = (RGB_YUV_TABLE[r + 1280 >> 0] + RGB_YUV_TABLE[g + 1536 >> 0] + RGB_YUV_TABLE[b + 1792 >> 0] >> 16) - 128;
19984 }
19985
19986 DCY = processDU(YDU, fdtbl_Y, DCY, YDC_HT, YAC_HT);
19987 DCU = processDU(UDU, fdtbl_UV, DCU, UVDC_HT, UVAC_HT);
19988 DCV = processDU(VDU, fdtbl_UV, DCV, UVDC_HT, UVAC_HT);
19989 x += 32;
19990 }
19991
19992 y += 8;
19993 } ////////////////////////////////////////////////////////////////
19994 // Do the bit alignment of the EOI marker
19995
19996
19997 if (bytepos >= 0) {
19998 var fillbits = [];
19999 fillbits[1] = bytepos + 1;
20000 fillbits[0] = (1 << bytepos + 1) - 1;
20001 writeBits(fillbits);
20002 }
20003
20004 writeWord(0xFFD9); //EOI
20005
20006 return new Uint8Array(byteout);
20007 };
20008
20009 function setQuality(quality) {
20010 if (quality <= 0) {
20011 quality = 1;
20012 }
20013
20014 if (quality > 100) {
20015 quality = 100;
20016 }
20017
20018 if (currentQuality == quality) return; // don't recalc if unchanged
20019
20020 var sf = 0;
20021
20022 if (quality < 50) {
20023 sf = Math.floor(5000 / quality);
20024 } else {
20025 sf = Math.floor(200 - quality * 2);
20026 }
20027
20028 initQuantTables(sf);
20029 currentQuality = quality; //console.log('Quality set to: '+quality +'%');
20030 }
20031
20032 function init() {
20033 var time_start = new Date().getTime();
20034 if (!quality) quality = 50; // Create tables
20035
20036 initCharLookupTable();
20037 initHuffmanTbl();
20038 initCategoryNumber();
20039 initRGBYUVTable();
20040 setQuality(quality);
20041 var duration = new Date().getTime() - time_start; //console.log('Initialization '+ duration + 'ms');
20042 }
20043
20044 init();
20045 }
20046 /*rollup-keeper-start*/
20047
20048 window.tmp = JPEGEncoder;
20049 /*rollup-keeper-end*/
20050
20051 /**
20052 * @author shaozilee
20053 *
20054 * Bmp format decoder,support 1bit 4bit 8bit 24bit bmp
20055 *
20056 */
20057 function BmpDecoder(buffer, is_with_alpha) {
20058 this.pos = 0;
20059 this.buffer = buffer;
20060 this.datav = new DataView(buffer.buffer);
20061 this.is_with_alpha = !!is_with_alpha;
20062 this.bottom_up = true;
20063 this.flag = String.fromCharCode(this.buffer[0]) + String.fromCharCode(this.buffer[1]);
20064 this.pos += 2;
20065 if (["BM", "BA", "CI", "CP", "IC", "PT"].indexOf(this.flag) === -1) throw new Error("Invalid BMP File");
20066 this.parseHeader();
20067 this.parseBGR();
20068 }
20069
20070 BmpDecoder.prototype.parseHeader = function () {
20071 this.fileSize = this.datav.getUint32(this.pos, true);
20072 this.pos += 4;
20073 this.reserved = this.datav.getUint32(this.pos, true);
20074 this.pos += 4;
20075 this.offset = this.datav.getUint32(this.pos, true);
20076 this.pos += 4;
20077 this.headerSize = this.datav.getUint32(this.pos, true);
20078 this.pos += 4;
20079 this.width = this.datav.getUint32(this.pos, true);
20080 this.pos += 4;
20081 this.height = this.datav.getInt32(this.pos, true);
20082 this.pos += 4;
20083 this.planes = this.datav.getUint16(this.pos, true);
20084 this.pos += 2;
20085 this.bitPP = this.datav.getUint16(this.pos, true);
20086 this.pos += 2;
20087 this.compress = this.datav.getUint32(this.pos, true);
20088 this.pos += 4;
20089 this.rawSize = this.datav.getUint32(this.pos, true);
20090 this.pos += 4;
20091 this.hr = this.datav.getUint32(this.pos, true);
20092 this.pos += 4;
20093 this.vr = this.datav.getUint32(this.pos, true);
20094 this.pos += 4;
20095 this.colors = this.datav.getUint32(this.pos, true);
20096 this.pos += 4;
20097 this.importantColors = this.datav.getUint32(this.pos, true);
20098 this.pos += 4;
20099
20100 if (this.bitPP === 16 && this.is_with_alpha) {
20101 this.bitPP = 15;
20102 }
20103
20104 if (this.bitPP < 15) {
20105 var len = this.colors === 0 ? 1 << this.bitPP : this.colors;
20106 this.palette = new Array(len);
20107
20108 for (var i = 0; i < len; i++) {
20109 var blue = this.datav.getUint8(this.pos++, true);
20110 var green = this.datav.getUint8(this.pos++, true);
20111 var red = this.datav.getUint8(this.pos++, true);
20112 var quad = this.datav.getUint8(this.pos++, true);
20113 this.palette[i] = {
20114 red: red,
20115 green: green,
20116 blue: blue,
20117 quad: quad
20118 };
20119 }
20120 }
20121
20122 if (this.height < 0) {
20123 this.height *= -1;
20124 this.bottom_up = false;
20125 }
20126 };
20127
20128 BmpDecoder.prototype.parseBGR = function () {
20129 this.pos = this.offset;
20130
20131 try {
20132 var bitn = "bit" + this.bitPP;
20133 var len = this.width * this.height * 4;
20134 this.data = new Uint8Array(len);
20135 this[bitn]();
20136 } catch (e) {
20137 console.log("bit decode error:" + e);
20138 }
20139 };
20140
20141 BmpDecoder.prototype.bit1 = function () {
20142 var xlen = Math.ceil(this.width / 8);
20143 var mode = xlen % 4;
20144 var y = this.height >= 0 ? this.height - 1 : -this.height;
20145
20146 for (var y = this.height - 1; y >= 0; y--) {
20147 var line = this.bottom_up ? y : this.height - 1 - y;
20148
20149 for (var x = 0; x < xlen; x++) {
20150 var b = this.datav.getUint8(this.pos++, true);
20151 var location = line * this.width * 4 + x * 8 * 4;
20152
20153 for (var i = 0; i < 8; i++) {
20154 if (x * 8 + i < this.width) {
20155 var rgb = this.palette[b >> 7 - i & 0x1];
20156 this.data[location + i * 4] = rgb.blue;
20157 this.data[location + i * 4 + 1] = rgb.green;
20158 this.data[location + i * 4 + 2] = rgb.red;
20159 this.data[location + i * 4 + 3] = 0xFF;
20160 } else {
20161 break;
20162 }
20163 }
20164 }
20165
20166 if (mode != 0) {
20167 this.pos += 4 - mode;
20168 }
20169 }
20170 };
20171
20172 BmpDecoder.prototype.bit4 = function () {
20173 var xlen = Math.ceil(this.width / 2);
20174 var mode = xlen % 4;
20175
20176 for (var y = this.height - 1; y >= 0; y--) {
20177 var line = this.bottom_up ? y : this.height - 1 - y;
20178
20179 for (var x = 0; x < xlen; x++) {
20180 var b = this.datav.getUint8(this.pos++, true);
20181 var location = line * this.width * 4 + x * 2 * 4;
20182 var before = b >> 4;
20183 var after = b & 0x0F;
20184 var rgb = this.palette[before];
20185 this.data[location] = rgb.blue;
20186 this.data[location + 1] = rgb.green;
20187 this.data[location + 2] = rgb.red;
20188 this.data[location + 3] = 0xFF;
20189 if (x * 2 + 1 >= this.width) break;
20190 rgb = this.palette[after];
20191 this.data[location + 4] = rgb.blue;
20192 this.data[location + 4 + 1] = rgb.green;
20193 this.data[location + 4 + 2] = rgb.red;
20194 this.data[location + 4 + 3] = 0xFF;
20195 }
20196
20197 if (mode != 0) {
20198 this.pos += 4 - mode;
20199 }
20200 }
20201 };
20202
20203 BmpDecoder.prototype.bit8 = function () {
20204 var mode = this.width % 4;
20205
20206 for (var y = this.height - 1; y >= 0; y--) {
20207 var line = this.bottom_up ? y : this.height - 1 - y;
20208
20209 for (var x = 0; x < this.width; x++) {
20210 var b = this.datav.getUint8(this.pos++, true);
20211 var location = line * this.width * 4 + x * 4;
20212
20213 if (b < this.palette.length) {
20214 var rgb = this.palette[b];
20215 this.data[location] = rgb.red;
20216 this.data[location + 1] = rgb.green;
20217 this.data[location + 2] = rgb.blue;
20218 this.data[location + 3] = 0xFF;
20219 } else {
20220 this.data[location] = 0xFF;
20221 this.data[location + 1] = 0xFF;
20222 this.data[location + 2] = 0xFF;
20223 this.data[location + 3] = 0xFF;
20224 }
20225 }
20226
20227 if (mode != 0) {
20228 this.pos += 4 - mode;
20229 }
20230 }
20231 };
20232
20233 BmpDecoder.prototype.bit15 = function () {
20234 var dif_w = this.width % 3;
20235
20236 var _11111 = parseInt("11111", 2),
20237 _1_5 = _11111;
20238
20239 for (var y = this.height - 1; y >= 0; y--) {
20240 var line = this.bottom_up ? y : this.height - 1 - y;
20241
20242 for (var x = 0; x < this.width; x++) {
20243 var B = this.datav.getUint16(this.pos, true);
20244 this.pos += 2;
20245 var blue = (B & _1_5) / _1_5 * 255 | 0;
20246 var green = (B >> 5 & _1_5) / _1_5 * 255 | 0;
20247 var red = (B >> 10 & _1_5) / _1_5 * 255 | 0;
20248 var alpha = B >> 15 ? 0xFF : 0x00;
20249 var location = line * this.width * 4 + x * 4;
20250 this.data[location] = red;
20251 this.data[location + 1] = green;
20252 this.data[location + 2] = blue;
20253 this.data[location + 3] = alpha;
20254 } //skip extra bytes
20255
20256
20257 this.pos += dif_w;
20258 }
20259 };
20260
20261 BmpDecoder.prototype.bit16 = function () {
20262 var dif_w = this.width % 3;
20263
20264 var _11111 = parseInt("11111", 2),
20265 _1_5 = _11111;
20266
20267 var _111111 = parseInt("111111", 2),
20268 _1_6 = _111111;
20269
20270 for (var y = this.height - 1; y >= 0; y--) {
20271 var line = this.bottom_up ? y : this.height - 1 - y;
20272
20273 for (var x = 0; x < this.width; x++) {
20274 var B = this.datav.getUint16(this.pos, true);
20275 this.pos += 2;
20276 var alpha = 0xFF;
20277 var blue = (B & _1_5) / _1_5 * 255 | 0;
20278 var green = (B >> 5 & _1_6) / _1_6 * 255 | 0;
20279 var red = (B >> 11) / _1_5 * 255 | 0;
20280 var location = line * this.width * 4 + x * 4;
20281 this.data[location] = red;
20282 this.data[location + 1] = green;
20283 this.data[location + 2] = blue;
20284 this.data[location + 3] = alpha;
20285 } //skip extra bytes
20286
20287
20288 this.pos += dif_w;
20289 }
20290 };
20291
20292 BmpDecoder.prototype.bit24 = function () {
20293 //when height > 0
20294 for (var y = this.height - 1; y >= 0; y--) {
20295 var line = this.bottom_up ? y : this.height - 1 - y;
20296
20297 for (var x = 0; x < this.width; x++) {
20298 var blue = this.datav.getUint8(this.pos++, true);
20299 var green = this.datav.getUint8(this.pos++, true);
20300 var red = this.datav.getUint8(this.pos++, true);
20301 var location = line * this.width * 4 + x * 4;
20302 this.data[location] = red;
20303 this.data[location + 1] = green;
20304 this.data[location + 2] = blue;
20305 this.data[location + 3] = 0xFF;
20306 } //skip extra bytes
20307
20308
20309 this.pos += this.width % 4;
20310 }
20311 };
20312 /**
20313 * add 32bit decode func
20314 * @author soubok
20315 */
20316
20317
20318 BmpDecoder.prototype.bit32 = function () {
20319 //when height > 0
20320 for (var y = this.height - 1; y >= 0; y--) {
20321 var line = this.bottom_up ? y : this.height - 1 - y;
20322
20323 for (var x = 0; x < this.width; x++) {
20324 var blue = this.datav.getUint8(this.pos++, true);
20325 var green = this.datav.getUint8(this.pos++, true);
20326 var red = this.datav.getUint8(this.pos++, true);
20327 var alpha = this.datav.getUint8(this.pos++, true);
20328 var location = line * this.width * 4 + x * 4;
20329 this.data[location] = red;
20330 this.data[location + 1] = green;
20331 this.data[location + 2] = blue;
20332 this.data[location + 3] = alpha;
20333 } //skip extra bytes
20334 //this.pos += (this.width % 4);
20335
20336 }
20337 };
20338
20339 BmpDecoder.prototype.getData = function () {
20340 return this.data;
20341 };
20342 /*rollup-keeper-start*/
20343
20344
20345 window.tmp = BmpDecoder;
20346 /*rollup-keeper-end*/
20347
20348 /*
20349 Copyright (c) 2013 Gildas Lormeau. All rights reserved.
20350
20351 Redistribution and use in source and binary forms, with or without
20352 modification, are permitted provided that the following conditions are met:
20353
20354 1. Redistributions of source code must retain the above copyright notice,
20355 this list of conditions and the following disclaimer.
20356
20357 2. Redistributions in binary form must reproduce the above copyright
20358 notice, this list of conditions and the following disclaimer in
20359 the documentation and/or other materials provided with the distribution.
20360
20361 3. The names of the authors may not be used to endorse or promote products
20362 derived from this software without specific prior written permission.
20363
20364 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
20365 INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
20366 FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
20367 INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
20368 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
20369 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
20370 OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
20371 LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
20372 NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
20373 EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
20374 */
20375
20376 /*
20377 * This program is based on JZlib 1.0.2 ymnk, JCraft,Inc.
20378 * JZlib is based on zlib-1.1.3, so all credit should go authors
20379 * Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu)
20380 * and contributors of zlib.
20381 */
20382 (function (global) {
20383
20384 var MAX_BITS = 15;
20385 var D_CODES = 30;
20386 var BL_CODES = 19;
20387 var LENGTH_CODES = 29;
20388 var LITERALS = 256;
20389 var L_CODES = LITERALS + 1 + LENGTH_CODES;
20390 var HEAP_SIZE = 2 * L_CODES + 1;
20391 var END_BLOCK = 256; // Bit length codes must not exceed MAX_BL_BITS bits
20392
20393 var MAX_BL_BITS = 7; // repeat previous bit length 3-6 times (2 bits of repeat count)
20394
20395 var REP_3_6 = 16; // repeat a zero length 3-10 times (3 bits of repeat count)
20396
20397 var REPZ_3_10 = 17; // repeat a zero length 11-138 times (7 bits of repeat count)
20398
20399 var REPZ_11_138 = 18; // The lengths of the bit length codes are sent in order of decreasing
20400 // probability, to avoid transmitting the lengths for unused bit
20401 // length codes.
20402
20403 var Buf_size = 8 * 2; // JZlib version : "1.0.2"
20404
20405 var Z_DEFAULT_COMPRESSION = -1; // compression strategy
20406
20407 var Z_FILTERED = 1;
20408 var Z_HUFFMAN_ONLY = 2;
20409 var Z_DEFAULT_STRATEGY = 0;
20410 var Z_NO_FLUSH = 0;
20411 var Z_PARTIAL_FLUSH = 1;
20412 var Z_FULL_FLUSH = 3;
20413 var Z_FINISH = 4;
20414 var Z_OK = 0;
20415 var Z_STREAM_END = 1;
20416 var Z_NEED_DICT = 2;
20417 var Z_STREAM_ERROR = -2;
20418 var Z_DATA_ERROR = -3;
20419 var Z_BUF_ERROR = -5; // Tree
20420 // see definition of array dist_code below
20421
20422 var _dist_code = [0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 16, 17, 18, 18, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29];
20423
20424 function Tree() {
20425 var that = this; // dyn_tree; // the dynamic tree
20426 // max_code; // largest code with non zero frequency
20427 // stat_desc; // the corresponding static tree
20428 // Compute the optimal bit lengths for a tree and update the total bit
20429 // length
20430 // for the current block.
20431 // IN assertion: the fields freq and dad are set, heap[heap_max] and
20432 // above are the tree nodes sorted by increasing frequency.
20433 // OUT assertions: the field len is set to the optimal bit length, the
20434 // array bl_count contains the frequencies for each bit length.
20435 // The length opt_len is updated; static_len is also updated if stree is
20436 // not null.
20437
20438 function gen_bitlen(s) {
20439 var tree = that.dyn_tree;
20440 var stree = that.stat_desc.static_tree;
20441 var extra = that.stat_desc.extra_bits;
20442 var base = that.stat_desc.extra_base;
20443 var max_length = that.stat_desc.max_length;
20444 var h; // heap index
20445
20446 var n, m; // iterate over the tree elements
20447
20448 var bits; // bit length
20449
20450 var xbits; // extra bits
20451
20452 var f; // frequency
20453
20454 var overflow = 0; // number of elements with bit length too large
20455
20456 for (bits = 0; bits <= MAX_BITS; bits++) {
20457 s.bl_count[bits] = 0;
20458 } // In a first pass, compute the optimal bit lengths (which may
20459 // overflow in the case of the bit length tree).
20460
20461
20462 tree[s.heap[s.heap_max] * 2 + 1] = 0; // root of the heap
20463
20464 for (h = s.heap_max + 1; h < HEAP_SIZE; h++) {
20465 n = s.heap[h];
20466 bits = tree[tree[n * 2 + 1] * 2 + 1] + 1;
20467
20468 if (bits > max_length) {
20469 bits = max_length;
20470 overflow++;
20471 }
20472
20473 tree[n * 2 + 1] = bits; // We overwrite tree[n*2+1] which is no longer needed
20474
20475 if (n > that.max_code) continue; // not a leaf node
20476
20477 s.bl_count[bits]++;
20478 xbits = 0;
20479 if (n >= base) xbits = extra[n - base];
20480 f = tree[n * 2];
20481 s.opt_len += f * (bits + xbits);
20482 if (stree) s.static_len += f * (stree[n * 2 + 1] + xbits);
20483 }
20484
20485 if (overflow === 0) return; // This happens for example on obj2 and pic of the Calgary corpus
20486 // Find the first bit length which could increase:
20487
20488 do {
20489 bits = max_length - 1;
20490
20491 while (s.bl_count[bits] === 0) {
20492 bits--;
20493 }
20494
20495 s.bl_count[bits]--; // move one leaf down the tree
20496
20497 s.bl_count[bits + 1] += 2; // move one overflow item as its brother
20498
20499 s.bl_count[max_length]--; // The brother of the overflow item also moves one step up,
20500 // but this does not affect bl_count[max_length]
20501
20502 overflow -= 2;
20503 } while (overflow > 0);
20504
20505 for (bits = max_length; bits !== 0; bits--) {
20506 n = s.bl_count[bits];
20507
20508 while (n !== 0) {
20509 m = s.heap[--h];
20510 if (m > that.max_code) continue;
20511
20512 if (tree[m * 2 + 1] != bits) {
20513 s.opt_len += (bits - tree[m * 2 + 1]) * tree[m * 2];
20514 tree[m * 2 + 1] = bits;
20515 }
20516
20517 n--;
20518 }
20519 }
20520 } // Reverse the first len bits of a code, using straightforward code (a
20521 // faster
20522 // method would use a table)
20523 // IN assertion: 1 <= len <= 15
20524
20525
20526 function bi_reverse(code, // the value to invert
20527 len // its bit length
20528 ) {
20529 var res = 0;
20530
20531 do {
20532 res |= code & 1;
20533 code >>>= 1;
20534 res <<= 1;
20535 } while (--len > 0);
20536
20537 return res >>> 1;
20538 } // Generate the codes for a given tree and bit counts (which need not be
20539 // optimal).
20540 // IN assertion: the array bl_count contains the bit length statistics for
20541 // the given tree and the field len is set for all tree elements.
20542 // OUT assertion: the field code is set for all tree elements of non
20543 // zero code length.
20544
20545
20546 function gen_codes(tree, // the tree to decorate
20547 max_code, // largest code with non zero frequency
20548 bl_count // number of codes at each bit length
20549 ) {
20550 var next_code = []; // next code value for each
20551 // bit length
20552
20553 var code = 0; // running code value
20554
20555 var bits; // bit index
20556
20557 var n; // code index
20558
20559 var len; // The distribution counts are first used to generate the code values
20560 // without bit reversal.
20561
20562 for (bits = 1; bits <= MAX_BITS; bits++) {
20563 next_code[bits] = code = code + bl_count[bits - 1] << 1;
20564 } // Check that the bit counts in bl_count are consistent. The last code
20565 // must be all ones.
20566 // Assert (code + bl_count[MAX_BITS]-1 == (1<<MAX_BITS)-1,
20567 // "inconsistent bit counts");
20568 // Tracev((stderr,"\ngen_codes: max_code %d ", max_code));
20569
20570
20571 for (n = 0; n <= max_code; n++) {
20572 len = tree[n * 2 + 1];
20573 if (len === 0) continue; // Now reverse the bits
20574
20575 tree[n * 2] = bi_reverse(next_code[len]++, len);
20576 }
20577 } // Construct one Huffman tree and assigns the code bit strings and lengths.
20578 // Update the total bit length for the current block.
20579 // IN assertion: the field freq is set for all tree elements.
20580 // OUT assertions: the fields len and code are set to the optimal bit length
20581 // and corresponding code. The length opt_len is updated; static_len is
20582 // also updated if stree is not null. The field max_code is set.
20583
20584
20585 that.build_tree = function (s) {
20586 var tree = that.dyn_tree;
20587 var stree = that.stat_desc.static_tree;
20588 var elems = that.stat_desc.elems;
20589 var n, m; // iterate over heap elements
20590
20591 var max_code = -1; // largest code with non zero frequency
20592
20593 var node; // new node being created
20594 // Construct the initial heap, with least frequent element in
20595 // heap[1]. The sons of heap[n] are heap[2*n] and heap[2*n+1].
20596 // heap[0] is not used.
20597
20598 s.heap_len = 0;
20599 s.heap_max = HEAP_SIZE;
20600
20601 for (n = 0; n < elems; n++) {
20602 if (tree[n * 2] !== 0) {
20603 s.heap[++s.heap_len] = max_code = n;
20604 s.depth[n] = 0;
20605 } else {
20606 tree[n * 2 + 1] = 0;
20607 }
20608 } // The pkzip format requires that at least one distance code exists,
20609 // and that at least one bit should be sent even if there is only one
20610 // possible code. So to avoid special checks later on we force at least
20611 // two codes of non zero frequency.
20612
20613
20614 while (s.heap_len < 2) {
20615 node = s.heap[++s.heap_len] = max_code < 2 ? ++max_code : 0;
20616 tree[node * 2] = 1;
20617 s.depth[node] = 0;
20618 s.opt_len--;
20619 if (stree) s.static_len -= stree[node * 2 + 1]; // node is 0 or 1 so it does not have extra bits
20620 }
20621
20622 that.max_code = max_code; // The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree,
20623 // establish sub-heaps of increasing lengths:
20624
20625 for (n = Math.floor(s.heap_len / 2); n >= 1; n--) {
20626 s.pqdownheap(tree, n);
20627 } // Construct the Huffman tree by repeatedly combining the least two
20628 // frequent nodes.
20629
20630
20631 node = elems; // next internal node of the tree
20632
20633 do {
20634 // n = node of least frequency
20635 n = s.heap[1];
20636 s.heap[1] = s.heap[s.heap_len--];
20637 s.pqdownheap(tree, 1);
20638 m = s.heap[1]; // m = node of next least frequency
20639
20640 s.heap[--s.heap_max] = n; // keep the nodes sorted by frequency
20641
20642 s.heap[--s.heap_max] = m; // Create a new node father of n and m
20643
20644 tree[node * 2] = tree[n * 2] + tree[m * 2];
20645 s.depth[node] = Math.max(s.depth[n], s.depth[m]) + 1;
20646 tree[n * 2 + 1] = tree[m * 2 + 1] = node; // and insert the new node in the heap
20647
20648 s.heap[1] = node++;
20649 s.pqdownheap(tree, 1);
20650 } while (s.heap_len >= 2);
20651
20652 s.heap[--s.heap_max] = s.heap[1]; // At this point, the fields freq and dad are set. We can now
20653 // generate the bit lengths.
20654
20655 gen_bitlen(s); // The field len is now set, we can generate the bit codes
20656
20657 gen_codes(tree, that.max_code, s.bl_count);
20658 };
20659 }
20660
20661 Tree._length_code = [0, 1, 2, 3, 4, 5, 6, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 12, 12, 13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, 19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28];
20662 Tree.base_length = [0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 20, 24, 28, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 0];
20663 Tree.base_dist = [0, 1, 2, 3, 4, 6, 8, 12, 16, 24, 32, 48, 64, 96, 128, 192, 256, 384, 512, 768, 1024, 1536, 2048, 3072, 4096, 6144, 8192, 12288, 16384, 24576]; // Mapping from a distance to a distance code. dist is the distance - 1 and
20664 // must not have side effects. _dist_code[256] and _dist_code[257] are never
20665 // used.
20666
20667 Tree.d_code = function (dist) {
20668 return dist < 256 ? _dist_code[dist] : _dist_code[256 + (dist >>> 7)];
20669 }; // extra bits for each length code
20670
20671
20672 Tree.extra_lbits = [0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0]; // extra bits for each distance code
20673
20674 Tree.extra_dbits = [0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13]; // extra bits for each bit length code
20675
20676 Tree.extra_blbits = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 3, 7];
20677 Tree.bl_order = [16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15]; // StaticTree
20678
20679 function StaticTree(static_tree, extra_bits, extra_base, elems, max_length) {
20680 var that = this;
20681 that.static_tree = static_tree;
20682 that.extra_bits = extra_bits;
20683 that.extra_base = extra_base;
20684 that.elems = elems;
20685 that.max_length = max_length;
20686 }
20687
20688 StaticTree.static_ltree = [12, 8, 140, 8, 76, 8, 204, 8, 44, 8, 172, 8, 108, 8, 236, 8, 28, 8, 156, 8, 92, 8, 220, 8, 60, 8, 188, 8, 124, 8, 252, 8, 2, 8, 130, 8, 66, 8, 194, 8, 34, 8, 162, 8, 98, 8, 226, 8, 18, 8, 146, 8, 82, 8, 210, 8, 50, 8, 178, 8, 114, 8, 242, 8, 10, 8, 138, 8, 74, 8, 202, 8, 42, 8, 170, 8, 106, 8, 234, 8, 26, 8, 154, 8, 90, 8, 218, 8, 58, 8, 186, 8, 122, 8, 250, 8, 6, 8, 134, 8, 70, 8, 198, 8, 38, 8, 166, 8, 102, 8, 230, 8, 22, 8, 150, 8, 86, 8, 214, 8, 54, 8, 182, 8, 118, 8, 246, 8, 14, 8, 142, 8, 78, 8, 206, 8, 46, 8, 174, 8, 110, 8, 238, 8, 30, 8, 158, 8, 94, 8, 222, 8, 62, 8, 190, 8, 126, 8, 254, 8, 1, 8, 129, 8, 65, 8, 193, 8, 33, 8, 161, 8, 97, 8, 225, 8, 17, 8, 145, 8, 81, 8, 209, 8, 49, 8, 177, 8, 113, 8, 241, 8, 9, 8, 137, 8, 73, 8, 201, 8, 41, 8, 169, 8, 105, 8, 233, 8, 25, 8, 153, 8, 89, 8, 217, 8, 57, 8, 185, 8, 121, 8, 249, 8, 5, 8, 133, 8, 69, 8, 197, 8, 37, 8, 165, 8, 101, 8, 229, 8, 21, 8, 149, 8, 85, 8, 213, 8, 53, 8, 181, 8, 117, 8, 245, 8, 13, 8, 141, 8, 77, 8, 205, 8, 45, 8, 173, 8, 109, 8, 237, 8, 29, 8, 157, 8, 93, 8, 221, 8, 61, 8, 189, 8, 125, 8, 253, 8, 19, 9, 275, 9, 147, 9, 403, 9, 83, 9, 339, 9, 211, 9, 467, 9, 51, 9, 307, 9, 179, 9, 435, 9, 115, 9, 371, 9, 243, 9, 499, 9, 11, 9, 267, 9, 139, 9, 395, 9, 75, 9, 331, 9, 203, 9, 459, 9, 43, 9, 299, 9, 171, 9, 427, 9, 107, 9, 363, 9, 235, 9, 491, 9, 27, 9, 283, 9, 155, 9, 411, 9, 91, 9, 347, 9, 219, 9, 475, 9, 59, 9, 315, 9, 187, 9, 443, 9, 123, 9, 379, 9, 251, 9, 507, 9, 7, 9, 263, 9, 135, 9, 391, 9, 71, 9, 327, 9, 199, 9, 455, 9, 39, 9, 295, 9, 167, 9, 423, 9, 103, 9, 359, 9, 231, 9, 487, 9, 23, 9, 279, 9, 151, 9, 407, 9, 87, 9, 343, 9, 215, 9, 471, 9, 55, 9, 311, 9, 183, 9, 439, 9, 119, 9, 375, 9, 247, 9, 503, 9, 15, 9, 271, 9, 143, 9, 399, 9, 79, 9, 335, 9, 207, 9, 463, 9, 47, 9, 303, 9, 175, 9, 431, 9, 111, 9, 367, 9, 239, 9, 495, 9, 31, 9, 287, 9, 159, 9, 415, 9, 95, 9, 351, 9, 223, 9, 479, 9, 63, 9, 319, 9, 191, 9, 447, 9, 127, 9, 383, 9, 255, 9, 511, 9, 0, 7, 64, 7, 32, 7, 96, 7, 16, 7, 80, 7, 48, 7, 112, 7, 8, 7, 72, 7, 40, 7, 104, 7, 24, 7, 88, 7, 56, 7, 120, 7, 4, 7, 68, 7, 36, 7, 100, 7, 20, 7, 84, 7, 52, 7, 116, 7, 3, 8, 131, 8, 67, 8, 195, 8, 35, 8, 163, 8, 99, 8, 227, 8];
20689 StaticTree.static_dtree = [0, 5, 16, 5, 8, 5, 24, 5, 4, 5, 20, 5, 12, 5, 28, 5, 2, 5, 18, 5, 10, 5, 26, 5, 6, 5, 22, 5, 14, 5, 30, 5, 1, 5, 17, 5, 9, 5, 25, 5, 5, 5, 21, 5, 13, 5, 29, 5, 3, 5, 19, 5, 11, 5, 27, 5, 7, 5, 23, 5];
20690 StaticTree.static_l_desc = new StaticTree(StaticTree.static_ltree, Tree.extra_lbits, LITERALS + 1, L_CODES, MAX_BITS);
20691 StaticTree.static_d_desc = new StaticTree(StaticTree.static_dtree, Tree.extra_dbits, 0, D_CODES, MAX_BITS);
20692 StaticTree.static_bl_desc = new StaticTree(null, Tree.extra_blbits, 0, BL_CODES, MAX_BL_BITS); // Deflate
20693
20694 var MAX_MEM_LEVEL = 9;
20695 var DEF_MEM_LEVEL = 8;
20696
20697 function Config(good_length, max_lazy, nice_length, max_chain, func) {
20698 var that = this;
20699 that.good_length = good_length;
20700 that.max_lazy = max_lazy;
20701 that.nice_length = nice_length;
20702 that.max_chain = max_chain;
20703 that.func = func;
20704 }
20705
20706 var STORED = 0;
20707 var FAST = 1;
20708 var SLOW = 2;
20709 var config_table = [new Config(0, 0, 0, 0, STORED), new Config(4, 4, 8, 4, FAST), new Config(4, 5, 16, 8, FAST), new Config(4, 6, 32, 32, FAST), new Config(4, 4, 16, 16, SLOW), new Config(8, 16, 32, 32, SLOW), new Config(8, 16, 128, 128, SLOW), new Config(8, 32, 128, 256, SLOW), new Config(32, 128, 258, 1024, SLOW), new Config(32, 258, 258, 4096, SLOW)];
20710 var z_errmsg = ["need dictionary", // Z_NEED_DICT
20711 // 2
20712 "stream end", // Z_STREAM_END 1
20713 "", // Z_OK 0
20714 "", // Z_ERRNO (-1)
20715 "stream error", // Z_STREAM_ERROR (-2)
20716 "data error", // Z_DATA_ERROR (-3)
20717 "", // Z_MEM_ERROR (-4)
20718 "buffer error", // Z_BUF_ERROR (-5)
20719 "", // Z_VERSION_ERROR (-6)
20720 ""]; // block not completed, need more input or more output
20721
20722 var NeedMore = 0; // block flush performed
20723
20724 var BlockDone = 1; // finish started, need only more output at next deflate
20725
20726 var FinishStarted = 2; // finish done, accept no more input or output
20727
20728 var FinishDone = 3; // preset dictionary flag in zlib header
20729
20730 var PRESET_DICT = 0x20;
20731 var INIT_STATE = 42;
20732 var BUSY_STATE = 113;
20733 var FINISH_STATE = 666; // The deflate compression method
20734
20735 var Z_DEFLATED = 8;
20736 var STORED_BLOCK = 0;
20737 var STATIC_TREES = 1;
20738 var DYN_TREES = 2;
20739 var MIN_MATCH = 3;
20740 var MAX_MATCH = 258;
20741 var MIN_LOOKAHEAD = MAX_MATCH + MIN_MATCH + 1;
20742
20743 function smaller(tree, n, m, depth) {
20744 var tn2 = tree[n * 2];
20745 var tm2 = tree[m * 2];
20746 return tn2 < tm2 || tn2 == tm2 && depth[n] <= depth[m];
20747 }
20748
20749 function Deflate() {
20750 var that = this;
20751 var strm; // pointer back to this zlib stream
20752
20753 var status; // as the name implies
20754 // pending_buf; // output still pending
20755
20756 var pending_buf_size; // size of pending_buf
20757
20758 var last_flush; // value of flush param for previous deflate call
20759
20760 var w_size; // LZ77 window size (32K by default)
20761
20762 var w_bits; // log2(w_size) (8..16)
20763
20764 var w_mask; // w_size - 1
20765
20766 var window; // Sliding window. Input bytes are read into the second half of the window,
20767 // and move to the first half later to keep a dictionary of at least wSize
20768 // bytes. With this organization, matches are limited to a distance of
20769 // wSize-MAX_MATCH bytes, but this ensures that IO is always
20770 // performed with a length multiple of the block size. Also, it limits
20771 // the window size to 64K, which is quite useful on MSDOS.
20772 // To do: use the user input buffer as sliding window.
20773
20774 var window_size; // Actual size of window: 2*wSize, except when the user input buffer
20775 // is directly used as sliding window.
20776
20777 var prev; // Link to older string with same hash index. To limit the size of this
20778 // array to 64K, this link is maintained only for the last 32K strings.
20779 // An index in this array is thus a window index modulo 32K.
20780
20781 var head; // Heads of the hash chains or NIL.
20782
20783 var ins_h; // hash index of string to be inserted
20784
20785 var hash_size; // number of elements in hash table
20786
20787 var hash_bits; // log2(hash_size)
20788
20789 var hash_mask; // hash_size-1
20790 // Number of bits by which ins_h must be shifted at each input
20791 // step. It must be such that after MIN_MATCH steps, the oldest
20792 // byte no longer takes part in the hash key, that is:
20793 // hash_shift * MIN_MATCH >= hash_bits
20794
20795 var hash_shift; // Window position at the beginning of the current output block. Gets
20796 // negative when the window is moved backwards.
20797
20798 var block_start;
20799 var match_length; // length of best match
20800
20801 var prev_match; // previous match
20802
20803 var match_available; // set if previous match exists
20804
20805 var strstart; // start of string to insert
20806
20807 var match_start; // start of matching string
20808
20809 var lookahead; // number of valid bytes ahead in window
20810 // Length of the best match at previous step. Matches not greater than this
20811 // are discarded. This is used in the lazy match evaluation.
20812
20813 var prev_length; // To speed up deflation, hash chains are never searched beyond this
20814 // length. A higher limit improves compression ratio but degrades the speed.
20815
20816 var max_chain_length; // Attempt to find a better match only when the current match is strictly
20817 // smaller than this value. This mechanism is used only for compression
20818 // levels >= 4.
20819
20820 var max_lazy_match; // Insert new strings in the hash table only if the match length is not
20821 // greater than this length. This saves time but degrades compression.
20822 // max_insert_length is used only for compression levels <= 3.
20823
20824 var level; // compression level (1..9)
20825
20826 var strategy; // favor or force Huffman coding
20827 // Use a faster search when the previous match is longer than this
20828
20829 var good_match; // Stop searching when current match exceeds this
20830
20831 var nice_match;
20832 var dyn_ltree; // literal and length tree
20833
20834 var dyn_dtree; // distance tree
20835
20836 var bl_tree; // Huffman tree for bit lengths
20837
20838 var l_desc = new Tree(); // desc for literal tree
20839
20840 var d_desc = new Tree(); // desc for distance tree
20841
20842 var bl_desc = new Tree(); // desc for bit length tree
20843 // that.heap_len; // number of elements in the heap
20844 // that.heap_max; // element of largest frequency
20845 // The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used.
20846 // The same heap array is used to build all trees.
20847 // Depth of each subtree used as tie breaker for trees of equal frequency
20848
20849 that.depth = [];
20850 var l_buf; // index for literals or lengths */
20851 // Size of match buffer for literals/lengths. There are 4 reasons for
20852 // limiting lit_bufsize to 64K:
20853 // - frequencies can be kept in 16 bit counters
20854 // - if compression is not successful for the first block, all input
20855 // data is still in the window so we can still emit a stored block even
20856 // when input comes from standard input. (This can also be done for
20857 // all blocks if lit_bufsize is not greater than 32K.)
20858 // - if compression is not successful for a file smaller than 64K, we can
20859 // even emit a stored file instead of a stored block (saving 5 bytes).
20860 // This is applicable only for zip (not gzip or zlib).
20861 // - creating new Huffman trees less frequently may not provide fast
20862 // adaptation to changes in the input data statistics. (Take for
20863 // example a binary file with poorly compressible code followed by
20864 // a highly compressible string table.) Smaller buffer sizes give
20865 // fast adaptation but have of course the overhead of transmitting
20866 // trees more frequently.
20867 // - I can't count above 4
20868
20869 var lit_bufsize;
20870 var last_lit; // running index in l_buf
20871 // Buffer for distances. To simplify the code, d_buf and l_buf have
20872 // the same number of elements. To use different lengths, an extra flag
20873 // array would be necessary.
20874
20875 var d_buf; // index of pendig_buf
20876 // that.opt_len; // bit length of current block with optimal trees
20877 // that.static_len; // bit length of current block with static trees
20878
20879 var matches; // number of string matches in current block
20880
20881 var last_eob_len; // bit length of EOB code for last block
20882 // Output buffer. bits are inserted starting at the bottom (least
20883 // significant bits).
20884
20885 var bi_buf; // Number of valid bits in bi_buf. All bits above the last valid bit
20886 // are always zero.
20887
20888 var bi_valid; // number of codes at each bit length for an optimal tree
20889
20890 that.bl_count = []; // heap used to build the Huffman trees
20891
20892 that.heap = [];
20893 dyn_ltree = [];
20894 dyn_dtree = [];
20895 bl_tree = [];
20896
20897 function lm_init() {
20898 var i;
20899 window_size = 2 * w_size;
20900 head[hash_size - 1] = 0;
20901
20902 for (i = 0; i < hash_size - 1; i++) {
20903 head[i] = 0;
20904 } // Set the default configuration parameters:
20905
20906
20907 max_lazy_match = config_table[level].max_lazy;
20908 good_match = config_table[level].good_length;
20909 nice_match = config_table[level].nice_length;
20910 max_chain_length = config_table[level].max_chain;
20911 strstart = 0;
20912 block_start = 0;
20913 lookahead = 0;
20914 match_length = prev_length = MIN_MATCH - 1;
20915 match_available = 0;
20916 ins_h = 0;
20917 }
20918
20919 function init_block() {
20920 var i; // Initialize the trees.
20921
20922 for (i = 0; i < L_CODES; i++) {
20923 dyn_ltree[i * 2] = 0;
20924 }
20925
20926 for (i = 0; i < D_CODES; i++) {
20927 dyn_dtree[i * 2] = 0;
20928 }
20929
20930 for (i = 0; i < BL_CODES; i++) {
20931 bl_tree[i * 2] = 0;
20932 }
20933
20934 dyn_ltree[END_BLOCK * 2] = 1;
20935 that.opt_len = that.static_len = 0;
20936 last_lit = matches = 0;
20937 } // Initialize the tree data structures for a new zlib stream.
20938
20939
20940 function tr_init() {
20941 l_desc.dyn_tree = dyn_ltree;
20942 l_desc.stat_desc = StaticTree.static_l_desc;
20943 d_desc.dyn_tree = dyn_dtree;
20944 d_desc.stat_desc = StaticTree.static_d_desc;
20945 bl_desc.dyn_tree = bl_tree;
20946 bl_desc.stat_desc = StaticTree.static_bl_desc;
20947 bi_buf = 0;
20948 bi_valid = 0;
20949 last_eob_len = 8; // enough lookahead for inflate
20950 // Initialize the first block of the first file:
20951
20952 init_block();
20953 } // Restore the heap property by moving down the tree starting at node k,
20954 // exchanging a node with the smallest of its two sons if necessary,
20955 // stopping
20956 // when the heap property is re-established (each father smaller than its
20957 // two sons).
20958
20959
20960 that.pqdownheap = function (tree, // the tree to restore
20961 k // node to move down
20962 ) {
20963 var heap = that.heap;
20964 var v = heap[k];
20965 var j = k << 1; // left son of k
20966
20967 while (j <= that.heap_len) {
20968 // Set j to the smallest of the two sons:
20969 if (j < that.heap_len && smaller(tree, heap[j + 1], heap[j], that.depth)) {
20970 j++;
20971 } // Exit if v is smaller than both sons
20972
20973
20974 if (smaller(tree, v, heap[j], that.depth)) break; // Exchange v with the smallest son
20975
20976 heap[k] = heap[j];
20977 k = j; // And continue down the tree, setting j to the left son of k
20978
20979 j <<= 1;
20980 }
20981
20982 heap[k] = v;
20983 }; // Scan a literal or distance tree to determine the frequencies of the codes
20984 // in the bit length tree.
20985
20986
20987 function scan_tree(tree, // the tree to be scanned
20988 max_code // and its largest code of non zero frequency
20989 ) {
20990 var n; // iterates over all tree elements
20991
20992 var prevlen = -1; // last emitted length
20993
20994 var curlen; // length of current code
20995
20996 var nextlen = tree[0 * 2 + 1]; // length of next code
20997
20998 var count = 0; // repeat count of the current code
20999
21000 var max_count = 7; // max repeat count
21001
21002 var min_count = 4; // min repeat count
21003
21004 if (nextlen === 0) {
21005 max_count = 138;
21006 min_count = 3;
21007 }
21008
21009 tree[(max_code + 1) * 2 + 1] = 0xffff; // guard
21010
21011 for (n = 0; n <= max_code; n++) {
21012 curlen = nextlen;
21013 nextlen = tree[(n + 1) * 2 + 1];
21014
21015 if (++count < max_count && curlen == nextlen) {
21016 continue;
21017 } else if (count < min_count) {
21018 bl_tree[curlen * 2] += count;
21019 } else if (curlen !== 0) {
21020 if (curlen != prevlen) bl_tree[curlen * 2]++;
21021 bl_tree[REP_3_6 * 2]++;
21022 } else if (count <= 10) {
21023 bl_tree[REPZ_3_10 * 2]++;
21024 } else {
21025 bl_tree[REPZ_11_138 * 2]++;
21026 }
21027
21028 count = 0;
21029 prevlen = curlen;
21030
21031 if (nextlen === 0) {
21032 max_count = 138;
21033 min_count = 3;
21034 } else if (curlen == nextlen) {
21035 max_count = 6;
21036 min_count = 3;
21037 } else {
21038 max_count = 7;
21039 min_count = 4;
21040 }
21041 }
21042 } // Construct the Huffman tree for the bit lengths and return the index in
21043 // bl_order of the last bit length code to send.
21044
21045
21046 function build_bl_tree() {
21047 var max_blindex; // index of last bit length code of non zero freq
21048 // Determine the bit length frequencies for literal and distance trees
21049
21050 scan_tree(dyn_ltree, l_desc.max_code);
21051 scan_tree(dyn_dtree, d_desc.max_code); // Build the bit length tree:
21052
21053 bl_desc.build_tree(that); // opt_len now includes the length of the tree representations, except
21054 // the lengths of the bit lengths codes and the 5+5+4 bits for the
21055 // counts.
21056 // Determine the number of bit length codes to send. The pkzip format
21057 // requires that at least 4 bit length codes be sent. (appnote.txt says
21058 // 3 but the actual value used is 4.)
21059
21060 for (max_blindex = BL_CODES - 1; max_blindex >= 3; max_blindex--) {
21061 if (bl_tree[Tree.bl_order[max_blindex] * 2 + 1] !== 0) break;
21062 } // Update opt_len to include the bit length tree and counts
21063
21064
21065 that.opt_len += 3 * (max_blindex + 1) + 5 + 5 + 4;
21066 return max_blindex;
21067 } // Output a byte on the stream.
21068 // IN assertion: there is enough room in pending_buf.
21069
21070
21071 function put_byte(p) {
21072 that.pending_buf[that.pending++] = p;
21073 }
21074
21075 function put_short(w) {
21076 put_byte(w & 0xff);
21077 put_byte(w >>> 8 & 0xff);
21078 }
21079
21080 function putShortMSB(b) {
21081 put_byte(b >> 8 & 0xff);
21082 put_byte(b & 0xff & 0xff);
21083 }
21084
21085 function send_bits(value, length) {
21086 var val,
21087 len = length;
21088
21089 if (bi_valid > Buf_size - len) {
21090 val = value; // bi_buf |= (val << bi_valid);
21091
21092 bi_buf |= val << bi_valid & 0xffff;
21093 put_short(bi_buf);
21094 bi_buf = val >>> Buf_size - bi_valid;
21095 bi_valid += len - Buf_size;
21096 } else {
21097 // bi_buf |= (value) << bi_valid;
21098 bi_buf |= value << bi_valid & 0xffff;
21099 bi_valid += len;
21100 }
21101 }
21102
21103 function send_code(c, tree) {
21104 var c2 = c * 2;
21105 send_bits(tree[c2] & 0xffff, tree[c2 + 1] & 0xffff);
21106 } // Send a literal or distance tree in compressed form, using the codes in
21107 // bl_tree.
21108
21109
21110 function send_tree(tree, // the tree to be sent
21111 max_code // and its largest code of non zero frequency
21112 ) {
21113 var n; // iterates over all tree elements
21114
21115 var prevlen = -1; // last emitted length
21116
21117 var curlen; // length of current code
21118
21119 var nextlen = tree[0 * 2 + 1]; // length of next code
21120
21121 var count = 0; // repeat count of the current code
21122
21123 var max_count = 7; // max repeat count
21124
21125 var min_count = 4; // min repeat count
21126
21127 if (nextlen === 0) {
21128 max_count = 138;
21129 min_count = 3;
21130 }
21131
21132 for (n = 0; n <= max_code; n++) {
21133 curlen = nextlen;
21134 nextlen = tree[(n + 1) * 2 + 1];
21135
21136 if (++count < max_count && curlen == nextlen) {
21137 continue;
21138 } else if (count < min_count) {
21139 do {
21140 send_code(curlen, bl_tree);
21141 } while (--count !== 0);
21142 } else if (curlen !== 0) {
21143 if (curlen != prevlen) {
21144 send_code(curlen, bl_tree);
21145 count--;
21146 }
21147
21148 send_code(REP_3_6, bl_tree);
21149 send_bits(count - 3, 2);
21150 } else if (count <= 10) {
21151 send_code(REPZ_3_10, bl_tree);
21152 send_bits(count - 3, 3);
21153 } else {
21154 send_code(REPZ_11_138, bl_tree);
21155 send_bits(count - 11, 7);
21156 }
21157
21158 count = 0;
21159 prevlen = curlen;
21160
21161 if (nextlen === 0) {
21162 max_count = 138;
21163 min_count = 3;
21164 } else if (curlen == nextlen) {
21165 max_count = 6;
21166 min_count = 3;
21167 } else {
21168 max_count = 7;
21169 min_count = 4;
21170 }
21171 }
21172 } // Send the header for a block using dynamic Huffman trees: the counts, the
21173 // lengths of the bit length codes, the literal tree and the distance tree.
21174 // IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4.
21175
21176
21177 function send_all_trees(lcodes, dcodes, blcodes) {
21178 var rank; // index in bl_order
21179
21180 send_bits(lcodes - 257, 5); // not +255 as stated in appnote.txt
21181
21182 send_bits(dcodes - 1, 5);
21183 send_bits(blcodes - 4, 4); // not -3 as stated in appnote.txt
21184
21185 for (rank = 0; rank < blcodes; rank++) {
21186 send_bits(bl_tree[Tree.bl_order[rank] * 2 + 1], 3);
21187 }
21188
21189 send_tree(dyn_ltree, lcodes - 1); // literal tree
21190
21191 send_tree(dyn_dtree, dcodes - 1); // distance tree
21192 } // Flush the bit buffer, keeping at most 7 bits in it.
21193
21194
21195 function bi_flush() {
21196 if (bi_valid == 16) {
21197 put_short(bi_buf);
21198 bi_buf = 0;
21199 bi_valid = 0;
21200 } else if (bi_valid >= 8) {
21201 put_byte(bi_buf & 0xff);
21202 bi_buf >>>= 8;
21203 bi_valid -= 8;
21204 }
21205 } // Send one empty static block to give enough lookahead for inflate.
21206 // This takes 10 bits, of which 7 may remain in the bit buffer.
21207 // The current inflate code requires 9 bits of lookahead. If the
21208 // last two codes for the previous block (real code plus EOB) were coded
21209 // on 5 bits or less, inflate may have only 5+3 bits of lookahead to decode
21210 // the last real code. In this case we send two empty static blocks instead
21211 // of one. (There are no problems if the previous block is stored or fixed.)
21212 // To simplify the code, we assume the worst case of last real code encoded
21213 // on one bit only.
21214
21215
21216 function _tr_align() {
21217 send_bits(STATIC_TREES << 1, 3);
21218 send_code(END_BLOCK, StaticTree.static_ltree);
21219 bi_flush(); // Of the 10 bits for the empty block, we have already sent
21220 // (10 - bi_valid) bits. The lookahead for the last real code (before
21221 // the EOB of the previous block) was thus at least one plus the length
21222 // of the EOB plus what we have just sent of the empty static block.
21223
21224 if (1 + last_eob_len + 10 - bi_valid < 9) {
21225 send_bits(STATIC_TREES << 1, 3);
21226 send_code(END_BLOCK, StaticTree.static_ltree);
21227 bi_flush();
21228 }
21229
21230 last_eob_len = 7;
21231 } // Save the match info and tally the frequency counts. Return true if
21232 // the current block must be flushed.
21233
21234
21235 function _tr_tally(dist, // distance of matched string
21236 lc // match length-MIN_MATCH or unmatched char (if dist==0)
21237 ) {
21238 var out_length, in_length, dcode;
21239 that.pending_buf[d_buf + last_lit * 2] = dist >>> 8 & 0xff;
21240 that.pending_buf[d_buf + last_lit * 2 + 1] = dist & 0xff;
21241 that.pending_buf[l_buf + last_lit] = lc & 0xff;
21242 last_lit++;
21243
21244 if (dist === 0) {
21245 // lc is the unmatched char
21246 dyn_ltree[lc * 2]++;
21247 } else {
21248 matches++; // Here, lc is the match length - MIN_MATCH
21249
21250 dist--; // dist = match distance - 1
21251
21252 dyn_ltree[(Tree._length_code[lc] + LITERALS + 1) * 2]++;
21253 dyn_dtree[Tree.d_code(dist) * 2]++;
21254 }
21255
21256 if ((last_lit & 0x1fff) === 0 && level > 2) {
21257 // Compute an upper bound for the compressed length
21258 out_length = last_lit * 8;
21259 in_length = strstart - block_start;
21260
21261 for (dcode = 0; dcode < D_CODES; dcode++) {
21262 out_length += dyn_dtree[dcode * 2] * (5 + Tree.extra_dbits[dcode]);
21263 }
21264
21265 out_length >>>= 3;
21266 if (matches < Math.floor(last_lit / 2) && out_length < Math.floor(in_length / 2)) return true;
21267 }
21268
21269 return last_lit == lit_bufsize - 1; // We avoid equality with lit_bufsize because of wraparound at 64K
21270 // on 16 bit machines and because stored blocks are restricted to
21271 // 64K-1 bytes.
21272 } // Send the block data compressed using the given Huffman trees
21273
21274
21275 function compress_block(ltree, dtree) {
21276 var dist; // distance of matched string
21277
21278 var lc; // match length or unmatched char (if dist === 0)
21279
21280 var lx = 0; // running index in l_buf
21281
21282 var code; // the code to send
21283
21284 var extra; // number of extra bits to send
21285
21286 if (last_lit !== 0) {
21287 do {
21288 dist = that.pending_buf[d_buf + lx * 2] << 8 & 0xff00 | that.pending_buf[d_buf + lx * 2 + 1] & 0xff;
21289 lc = that.pending_buf[l_buf + lx] & 0xff;
21290 lx++;
21291
21292 if (dist === 0) {
21293 send_code(lc, ltree); // send a literal byte
21294 } else {
21295 // Here, lc is the match length - MIN_MATCH
21296 code = Tree._length_code[lc];
21297 send_code(code + LITERALS + 1, ltree); // send the length
21298 // code
21299
21300 extra = Tree.extra_lbits[code];
21301
21302 if (extra !== 0) {
21303 lc -= Tree.base_length[code];
21304 send_bits(lc, extra); // send the extra length bits
21305 }
21306
21307 dist--; // dist is now the match distance - 1
21308
21309 code = Tree.d_code(dist);
21310 send_code(code, dtree); // send the distance code
21311
21312 extra = Tree.extra_dbits[code];
21313
21314 if (extra !== 0) {
21315 dist -= Tree.base_dist[code];
21316 send_bits(dist, extra); // send the extra distance bits
21317 }
21318 } // literal or match pair ?
21319 // Check that the overlay between pending_buf and d_buf+l_buf is
21320 // ok:
21321
21322 } while (lx < last_lit);
21323 }
21324
21325 send_code(END_BLOCK, ltree);
21326 last_eob_len = ltree[END_BLOCK * 2 + 1];
21327 } // Flush the bit buffer and align the output on a byte boundary
21328
21329
21330 function bi_windup() {
21331 if (bi_valid > 8) {
21332 put_short(bi_buf);
21333 } else if (bi_valid > 0) {
21334 put_byte(bi_buf & 0xff);
21335 }
21336
21337 bi_buf = 0;
21338 bi_valid = 0;
21339 } // Copy a stored block, storing first the length and its
21340 // one's complement if requested.
21341
21342
21343 function copy_block(buf, // the input data
21344 len, // its length
21345 header // true if block header must be written
21346 ) {
21347 bi_windup(); // align on byte boundary
21348
21349 last_eob_len = 8; // enough lookahead for inflate
21350
21351 if (header) {
21352 put_short(len);
21353 put_short(~len);
21354 }
21355
21356 that.pending_buf.set(window.subarray(buf, buf + len), that.pending);
21357 that.pending += len;
21358 } // Send a stored block
21359
21360
21361 function _tr_stored_block(buf, // input block
21362 stored_len, // length of input block
21363 eof // true if this is the last block for a file
21364 ) {
21365 send_bits((STORED_BLOCK << 1) + (eof ? 1 : 0), 3); // send block type
21366
21367 copy_block(buf, stored_len, true); // with header
21368 } // Determine the best encoding for the current block: dynamic trees, static
21369 // trees or store, and output the encoded block to the zip file.
21370
21371
21372 function _tr_flush_block(buf, // input block, or NULL if too old
21373 stored_len, // length of input block
21374 eof // true if this is the last block for a file
21375 ) {
21376 var opt_lenb, static_lenb; // opt_len and static_len in bytes
21377
21378 var max_blindex = 0; // index of last bit length code of non zero freq
21379 // Build the Huffman trees unless a stored block is forced
21380
21381 if (level > 0) {
21382 // Construct the literal and distance trees
21383 l_desc.build_tree(that);
21384 d_desc.build_tree(that); // At this point, opt_len and static_len are the total bit lengths
21385 // of
21386 // the compressed block data, excluding the tree representations.
21387 // Build the bit length tree for the above two trees, and get the
21388 // index
21389 // in bl_order of the last bit length code to send.
21390
21391 max_blindex = build_bl_tree(); // Determine the best encoding. Compute first the block length in
21392 // bytes
21393
21394 opt_lenb = that.opt_len + 3 + 7 >>> 3;
21395 static_lenb = that.static_len + 3 + 7 >>> 3;
21396 if (static_lenb <= opt_lenb) opt_lenb = static_lenb;
21397 } else {
21398 opt_lenb = static_lenb = stored_len + 5; // force a stored block
21399 }
21400
21401 if (stored_len + 4 <= opt_lenb && buf != -1) {
21402 // 4: two words for the lengths
21403 // The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE.
21404 // Otherwise we can't have processed more than WSIZE input bytes
21405 // since
21406 // the last block flush, because compression would have been
21407 // successful. If LIT_BUFSIZE <= WSIZE, it is never too late to
21408 // transform a block into a stored block.
21409 _tr_stored_block(buf, stored_len, eof);
21410 } else if (static_lenb == opt_lenb) {
21411 send_bits((STATIC_TREES << 1) + (eof ? 1 : 0), 3);
21412 compress_block(StaticTree.static_ltree, StaticTree.static_dtree);
21413 } else {
21414 send_bits((DYN_TREES << 1) + (eof ? 1 : 0), 3);
21415 send_all_trees(l_desc.max_code + 1, d_desc.max_code + 1, max_blindex + 1);
21416 compress_block(dyn_ltree, dyn_dtree);
21417 } // The above check is made mod 2^32, for files larger than 512 MB
21418 // and uLong implemented on 32 bits.
21419
21420
21421 init_block();
21422
21423 if (eof) {
21424 bi_windup();
21425 }
21426 }
21427
21428 function flush_block_only(eof) {
21429 _tr_flush_block(block_start >= 0 ? block_start : -1, strstart - block_start, eof);
21430
21431 block_start = strstart;
21432 strm.flush_pending();
21433 } // Fill the window when the lookahead becomes insufficient.
21434 // Updates strstart and lookahead.
21435 //
21436 // IN assertion: lookahead < MIN_LOOKAHEAD
21437 // OUT assertions: strstart <= window_size-MIN_LOOKAHEAD
21438 // At least one byte has been read, or avail_in === 0; reads are
21439 // performed for at least two bytes (required for the zip translate_eol
21440 // option -- not supported here).
21441
21442
21443 function fill_window() {
21444 var n, m;
21445 var p;
21446 var more; // Amount of free space at the end of the window.
21447
21448 do {
21449 more = window_size - lookahead - strstart; // Deal with !@#$% 64K limit:
21450
21451 if (more === 0 && strstart === 0 && lookahead === 0) {
21452 more = w_size;
21453 } else if (more == -1) {
21454 // Very unlikely, but possible on 16 bit machine if strstart ==
21455 // 0
21456 // and lookahead == 1 (input done one byte at time)
21457 more--; // If the window is almost full and there is insufficient
21458 // lookahead,
21459 // move the upper half to the lower one to make room in the
21460 // upper half.
21461 } else if (strstart >= w_size + w_size - MIN_LOOKAHEAD) {
21462 window.set(window.subarray(w_size, w_size + w_size), 0);
21463 match_start -= w_size;
21464 strstart -= w_size; // we now have strstart >= MAX_DIST
21465
21466 block_start -= w_size; // Slide the hash table (could be avoided with 32 bit values
21467 // at the expense of memory usage). We slide even when level ==
21468 // 0
21469 // to keep the hash table consistent if we switch back to level
21470 // > 0
21471 // later. (Using level 0 permanently is not an optimal usage of
21472 // zlib, so we don't care about this pathological case.)
21473
21474 n = hash_size;
21475 p = n;
21476
21477 do {
21478 m = head[--p] & 0xffff;
21479 head[p] = m >= w_size ? m - w_size : 0;
21480 } while (--n !== 0);
21481
21482 n = w_size;
21483 p = n;
21484
21485 do {
21486 m = prev[--p] & 0xffff;
21487 prev[p] = m >= w_size ? m - w_size : 0; // If n is not on any hash chain, prev[n] is garbage but
21488 // its value will never be used.
21489 } while (--n !== 0);
21490
21491 more += w_size;
21492 }
21493
21494 if (strm.avail_in === 0) return; // If there was no sliding:
21495 // strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 &&
21496 // more == window_size - lookahead - strstart
21497 // => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1)
21498 // => more >= window_size - 2*WSIZE + 2
21499 // In the BIG_MEM or MMAP case (not yet supported),
21500 // window_size == input_size + MIN_LOOKAHEAD &&
21501 // strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD.
21502 // Otherwise, window_size == 2*WSIZE so more >= 2.
21503 // If there was sliding, more >= WSIZE. So in all cases, more >= 2.
21504
21505 n = strm.read_buf(window, strstart + lookahead, more);
21506 lookahead += n; // Initialize the hash value now that we have some input:
21507
21508 if (lookahead >= MIN_MATCH) {
21509 ins_h = window[strstart] & 0xff;
21510 ins_h = (ins_h << hash_shift ^ window[strstart + 1] & 0xff) & hash_mask;
21511 } // If the whole input has less than MIN_MATCH bytes, ins_h is
21512 // garbage,
21513 // but this is not important since only literal bytes will be
21514 // emitted.
21515
21516 } while (lookahead < MIN_LOOKAHEAD && strm.avail_in !== 0);
21517 } // Copy without compression as much as possible from the input stream,
21518 // return
21519 // the current block state.
21520 // This function does not insert new strings in the dictionary since
21521 // uncompressible data is probably not useful. This function is used
21522 // only for the level=0 compression option.
21523 // NOTE: this function should be optimized to avoid extra copying from
21524 // window to pending_buf.
21525
21526
21527 function deflate_stored(flush) {
21528 // Stored blocks are limited to 0xffff bytes, pending_buf is limited
21529 // to pending_buf_size, and each stored block has a 5 byte header:
21530 var max_block_size = 0xffff;
21531 var max_start;
21532
21533 if (max_block_size > pending_buf_size - 5) {
21534 max_block_size = pending_buf_size - 5;
21535 } // Copy as much as possible from input to output:
21536
21537
21538 while (true) {
21539 // Fill the window as much as possible:
21540 if (lookahead <= 1) {
21541 fill_window();
21542 if (lookahead === 0 && flush == Z_NO_FLUSH) return NeedMore;
21543 if (lookahead === 0) break; // flush the current block
21544 }
21545
21546 strstart += lookahead;
21547 lookahead = 0; // Emit a stored block if pending_buf will be full:
21548
21549 max_start = block_start + max_block_size;
21550
21551 if (strstart === 0 || strstart >= max_start) {
21552 // strstart === 0 is possible when wraparound on 16-bit machine
21553 lookahead = strstart - max_start;
21554 strstart = max_start;
21555 flush_block_only(false);
21556 if (strm.avail_out === 0) return NeedMore;
21557 } // Flush if we may have to slide, otherwise block_start may become
21558 // negative and the data will be gone:
21559
21560
21561 if (strstart - block_start >= w_size - MIN_LOOKAHEAD) {
21562 flush_block_only(false);
21563 if (strm.avail_out === 0) return NeedMore;
21564 }
21565 }
21566
21567 flush_block_only(flush == Z_FINISH);
21568 if (strm.avail_out === 0) return flush == Z_FINISH ? FinishStarted : NeedMore;
21569 return flush == Z_FINISH ? FinishDone : BlockDone;
21570 }
21571
21572 function longest_match(cur_match) {
21573 var chain_length = max_chain_length; // max hash chain length
21574
21575 var scan = strstart; // current string
21576
21577 var match; // matched string
21578
21579 var len; // length of current match
21580
21581 var best_len = prev_length; // best match length so far
21582
21583 var limit = strstart > w_size - MIN_LOOKAHEAD ? strstart - (w_size - MIN_LOOKAHEAD) : 0;
21584 var _nice_match = nice_match; // Stop when cur_match becomes <= limit. To simplify the code,
21585 // we prevent matches with the string of window index 0.
21586
21587 var wmask = w_mask;
21588 var strend = strstart + MAX_MATCH;
21589 var scan_end1 = window[scan + best_len - 1];
21590 var scan_end = window[scan + best_len]; // The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of
21591 // 16.
21592 // It is easy to get rid of this optimization if necessary.
21593 // Do not waste too much time if we already have a good match:
21594
21595 if (prev_length >= good_match) {
21596 chain_length >>= 2;
21597 } // Do not look for matches beyond the end of the input. This is
21598 // necessary
21599 // to make deflate deterministic.
21600
21601
21602 if (_nice_match > lookahead) _nice_match = lookahead;
21603
21604 do {
21605 match = cur_match; // Skip to next match if the match length cannot increase
21606 // or if the match length is less than 2:
21607
21608 if (window[match + best_len] != scan_end || window[match + best_len - 1] != scan_end1 || window[match] != window[scan] || window[++match] != window[scan + 1]) continue; // The check at best_len-1 can be removed because it will be made
21609 // again later. (This heuristic is not always a win.)
21610 // It is not necessary to compare scan[2] and match[2] since they
21611 // are always equal when the other bytes match, given that
21612 // the hash keys are equal and that HASH_BITS >= 8.
21613
21614 scan += 2;
21615 match++; // We check for insufficient lookahead only every 8th comparison;
21616 // the 256th check will be made at strstart+258.
21617
21618 do {} while (window[++scan] == window[++match] && window[++scan] == window[++match] && window[++scan] == window[++match] && window[++scan] == window[++match] && window[++scan] == window[++match] && window[++scan] == window[++match] && window[++scan] == window[++match] && window[++scan] == window[++match] && scan < strend);
21619
21620 len = MAX_MATCH - (strend - scan);
21621 scan = strend - MAX_MATCH;
21622
21623 if (len > best_len) {
21624 match_start = cur_match;
21625 best_len = len;
21626 if (len >= _nice_match) break;
21627 scan_end1 = window[scan + best_len - 1];
21628 scan_end = window[scan + best_len];
21629 }
21630 } while ((cur_match = prev[cur_match & wmask] & 0xffff) > limit && --chain_length !== 0);
21631
21632 if (best_len <= lookahead) return best_len;
21633 return lookahead;
21634 } // Compress as much as possible from the input stream, return the current
21635 // block state.
21636 // This function does not perform lazy evaluation of matches and inserts
21637 // new strings in the dictionary only for unmatched strings or for short
21638 // matches. It is used only for the fast compression options.
21639
21640
21641 function deflate_fast(flush) {
21642 // short hash_head = 0; // head of the hash chain
21643 var hash_head = 0; // head of the hash chain
21644
21645 var bflush; // set if current block must be flushed
21646
21647 while (true) {
21648 // Make sure that we always have enough lookahead, except
21649 // at the end of the input file. We need MAX_MATCH bytes
21650 // for the next match, plus MIN_MATCH bytes to insert the
21651 // string following the next match.
21652 if (lookahead < MIN_LOOKAHEAD) {
21653 fill_window();
21654
21655 if (lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) {
21656 return NeedMore;
21657 }
21658
21659 if (lookahead === 0) break; // flush the current block
21660 } // Insert the string window[strstart .. strstart+2] in the
21661 // dictionary, and set hash_head to the head of the hash chain:
21662
21663
21664 if (lookahead >= MIN_MATCH) {
21665 ins_h = (ins_h << hash_shift ^ window[strstart + (MIN_MATCH - 1)] & 0xff) & hash_mask; // prev[strstart&w_mask]=hash_head=head[ins_h];
21666
21667 hash_head = head[ins_h] & 0xffff;
21668 prev[strstart & w_mask] = head[ins_h];
21669 head[ins_h] = strstart;
21670 } // Find the longest match, discarding those <= prev_length.
21671 // At this point we have always match_length < MIN_MATCH
21672
21673
21674 if (hash_head !== 0 && (strstart - hash_head & 0xffff) <= w_size - MIN_LOOKAHEAD) {
21675 // To simplify the code, we prevent matches with the string
21676 // of window index 0 (in particular we have to avoid a match
21677 // of the string with itself at the start of the input file).
21678 if (strategy != Z_HUFFMAN_ONLY) {
21679 match_length = longest_match(hash_head);
21680 } // longest_match() sets match_start
21681
21682 }
21683
21684 if (match_length >= MIN_MATCH) {
21685 // check_match(strstart, match_start, match_length);
21686 bflush = _tr_tally(strstart - match_start, match_length - MIN_MATCH);
21687 lookahead -= match_length; // Insert new strings in the hash table only if the match length
21688 // is not too large. This saves time but degrades compression.
21689
21690 if (match_length <= max_lazy_match && lookahead >= MIN_MATCH) {
21691 match_length--; // string at strstart already in hash table
21692
21693 do {
21694 strstart++;
21695 ins_h = (ins_h << hash_shift ^ window[strstart + (MIN_MATCH - 1)] & 0xff) & hash_mask; // prev[strstart&w_mask]=hash_head=head[ins_h];
21696
21697 hash_head = head[ins_h] & 0xffff;
21698 prev[strstart & w_mask] = head[ins_h];
21699 head[ins_h] = strstart; // strstart never exceeds WSIZE-MAX_MATCH, so there are
21700 // always MIN_MATCH bytes ahead.
21701 } while (--match_length !== 0);
21702
21703 strstart++;
21704 } else {
21705 strstart += match_length;
21706 match_length = 0;
21707 ins_h = window[strstart] & 0xff;
21708 ins_h = (ins_h << hash_shift ^ window[strstart + 1] & 0xff) & hash_mask; // If lookahead < MIN_MATCH, ins_h is garbage, but it does
21709 // not
21710 // matter since it will be recomputed at next deflate call.
21711 }
21712 } else {
21713 // No match, output a literal byte
21714 bflush = _tr_tally(0, window[strstart] & 0xff);
21715 lookahead--;
21716 strstart++;
21717 }
21718
21719 if (bflush) {
21720 flush_block_only(false);
21721 if (strm.avail_out === 0) return NeedMore;
21722 }
21723 }
21724
21725 flush_block_only(flush == Z_FINISH);
21726
21727 if (strm.avail_out === 0) {
21728 if (flush == Z_FINISH) return FinishStarted;else return NeedMore;
21729 }
21730
21731 return flush == Z_FINISH ? FinishDone : BlockDone;
21732 } // Same as above, but achieves better compression. We use a lazy
21733 // evaluation for matches: a match is finally adopted only if there is
21734 // no better match at the next window position.
21735
21736
21737 function deflate_slow(flush) {
21738 // short hash_head = 0; // head of hash chain
21739 var hash_head = 0; // head of hash chain
21740
21741 var bflush; // set if current block must be flushed
21742
21743 var max_insert; // Process the input block.
21744
21745 while (true) {
21746 // Make sure that we always have enough lookahead, except
21747 // at the end of the input file. We need MAX_MATCH bytes
21748 // for the next match, plus MIN_MATCH bytes to insert the
21749 // string following the next match.
21750 if (lookahead < MIN_LOOKAHEAD) {
21751 fill_window();
21752
21753 if (lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) {
21754 return NeedMore;
21755 }
21756
21757 if (lookahead === 0) break; // flush the current block
21758 } // Insert the string window[strstart .. strstart+2] in the
21759 // dictionary, and set hash_head to the head of the hash chain:
21760
21761
21762 if (lookahead >= MIN_MATCH) {
21763 ins_h = (ins_h << hash_shift ^ window[strstart + (MIN_MATCH - 1)] & 0xff) & hash_mask; // prev[strstart&w_mask]=hash_head=head[ins_h];
21764
21765 hash_head = head[ins_h] & 0xffff;
21766 prev[strstart & w_mask] = head[ins_h];
21767 head[ins_h] = strstart;
21768 } // Find the longest match, discarding those <= prev_length.
21769
21770
21771 prev_length = match_length;
21772 prev_match = match_start;
21773 match_length = MIN_MATCH - 1;
21774
21775 if (hash_head !== 0 && prev_length < max_lazy_match && (strstart - hash_head & 0xffff) <= w_size - MIN_LOOKAHEAD) {
21776 // To simplify the code, we prevent matches with the string
21777 // of window index 0 (in particular we have to avoid a match
21778 // of the string with itself at the start of the input file).
21779 if (strategy != Z_HUFFMAN_ONLY) {
21780 match_length = longest_match(hash_head);
21781 } // longest_match() sets match_start
21782
21783
21784 if (match_length <= 5 && (strategy == Z_FILTERED || match_length == MIN_MATCH && strstart - match_start > 4096)) {
21785 // If prev_match is also MIN_MATCH, match_start is garbage
21786 // but we will ignore the current match anyway.
21787 match_length = MIN_MATCH - 1;
21788 }
21789 } // If there was a match at the previous step and the current
21790 // match is not better, output the previous match:
21791
21792
21793 if (prev_length >= MIN_MATCH && match_length <= prev_length) {
21794 max_insert = strstart + lookahead - MIN_MATCH; // Do not insert strings in hash table beyond this.
21795 // check_match(strstart-1, prev_match, prev_length);
21796
21797 bflush = _tr_tally(strstart - 1 - prev_match, prev_length - MIN_MATCH); // Insert in hash table all strings up to the end of the match.
21798 // strstart-1 and strstart are already inserted. If there is not
21799 // enough lookahead, the last two strings are not inserted in
21800 // the hash table.
21801
21802 lookahead -= prev_length - 1;
21803 prev_length -= 2;
21804
21805 do {
21806 if (++strstart <= max_insert) {
21807 ins_h = (ins_h << hash_shift ^ window[strstart + (MIN_MATCH - 1)] & 0xff) & hash_mask; // prev[strstart&w_mask]=hash_head=head[ins_h];
21808
21809 hash_head = head[ins_h] & 0xffff;
21810 prev[strstart & w_mask] = head[ins_h];
21811 head[ins_h] = strstart;
21812 }
21813 } while (--prev_length !== 0);
21814
21815 match_available = 0;
21816 match_length = MIN_MATCH - 1;
21817 strstart++;
21818
21819 if (bflush) {
21820 flush_block_only(false);
21821 if (strm.avail_out === 0) return NeedMore;
21822 }
21823 } else if (match_available !== 0) {
21824 // If there was no match at the previous position, output a
21825 // single literal. If there was a match but the current match
21826 // is longer, truncate the previous match to a single literal.
21827 bflush = _tr_tally(0, window[strstart - 1] & 0xff);
21828
21829 if (bflush) {
21830 flush_block_only(false);
21831 }
21832
21833 strstart++;
21834 lookahead--;
21835 if (strm.avail_out === 0) return NeedMore;
21836 } else {
21837 // There is no previous match to compare with, wait for
21838 // the next step to decide.
21839 match_available = 1;
21840 strstart++;
21841 lookahead--;
21842 }
21843 }
21844
21845 if (match_available !== 0) {
21846 bflush = _tr_tally(0, window[strstart - 1] & 0xff);
21847 match_available = 0;
21848 }
21849
21850 flush_block_only(flush == Z_FINISH);
21851
21852 if (strm.avail_out === 0) {
21853 if (flush == Z_FINISH) return FinishStarted;else return NeedMore;
21854 }
21855
21856 return flush == Z_FINISH ? FinishDone : BlockDone;
21857 }
21858
21859 function deflateReset(strm) {
21860 strm.total_in = strm.total_out = 0;
21861 strm.msg = null; //
21862
21863 that.pending = 0;
21864 that.pending_out = 0;
21865 status = BUSY_STATE;
21866 last_flush = Z_NO_FLUSH;
21867 tr_init();
21868 lm_init();
21869 return Z_OK;
21870 }
21871
21872 that.deflateInit = function (strm, _level, bits, _method, memLevel, _strategy) {
21873 if (!_method) _method = Z_DEFLATED;
21874 if (!memLevel) memLevel = DEF_MEM_LEVEL;
21875 if (!_strategy) _strategy = Z_DEFAULT_STRATEGY; // byte[] my_version=ZLIB_VERSION;
21876 //
21877 // if (!version || version[0] != my_version[0]
21878 // || stream_size != sizeof(z_stream)) {
21879 // return Z_VERSION_ERROR;
21880 // }
21881
21882 strm.msg = null;
21883 if (_level == Z_DEFAULT_COMPRESSION) _level = 6;
21884
21885 if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || _method != Z_DEFLATED || bits < 9 || bits > 15 || _level < 0 || _level > 9 || _strategy < 0 || _strategy > Z_HUFFMAN_ONLY) {
21886 return Z_STREAM_ERROR;
21887 }
21888
21889 strm.dstate = that;
21890 w_bits = bits;
21891 w_size = 1 << w_bits;
21892 w_mask = w_size - 1;
21893 hash_bits = memLevel + 7;
21894 hash_size = 1 << hash_bits;
21895 hash_mask = hash_size - 1;
21896 hash_shift = Math.floor((hash_bits + MIN_MATCH - 1) / MIN_MATCH);
21897 window = new Uint8Array(w_size * 2);
21898 prev = [];
21899 head = [];
21900 lit_bufsize = 1 << memLevel + 6; // 16K elements by default
21901 // We overlay pending_buf and d_buf+l_buf. This works since the average
21902 // output size for (length,distance) codes is <= 24 bits.
21903
21904 that.pending_buf = new Uint8Array(lit_bufsize * 4);
21905 pending_buf_size = lit_bufsize * 4;
21906 d_buf = Math.floor(lit_bufsize / 2);
21907 l_buf = (1 + 2) * lit_bufsize;
21908 level = _level;
21909 strategy = _strategy;
21910 return deflateReset(strm);
21911 };
21912
21913 that.deflateEnd = function () {
21914 if (status != INIT_STATE && status != BUSY_STATE && status != FINISH_STATE) {
21915 return Z_STREAM_ERROR;
21916 } // Deallocate in reverse order of allocations:
21917
21918
21919 that.pending_buf = null;
21920 head = null;
21921 prev = null;
21922 window = null; // free
21923
21924 that.dstate = null;
21925 return status == BUSY_STATE ? Z_DATA_ERROR : Z_OK;
21926 };
21927
21928 that.deflateParams = function (strm, _level, _strategy) {
21929 var err = Z_OK;
21930
21931 if (_level == Z_DEFAULT_COMPRESSION) {
21932 _level = 6;
21933 }
21934
21935 if (_level < 0 || _level > 9 || _strategy < 0 || _strategy > Z_HUFFMAN_ONLY) {
21936 return Z_STREAM_ERROR;
21937 }
21938
21939 if (config_table[level].func != config_table[_level].func && strm.total_in !== 0) {
21940 // Flush the last buffer:
21941 err = strm.deflate(Z_PARTIAL_FLUSH);
21942 }
21943
21944 if (level != _level) {
21945 level = _level;
21946 max_lazy_match = config_table[level].max_lazy;
21947 good_match = config_table[level].good_length;
21948 nice_match = config_table[level].nice_length;
21949 max_chain_length = config_table[level].max_chain;
21950 }
21951
21952 strategy = _strategy;
21953 return err;
21954 };
21955
21956 that.deflateSetDictionary = function (strm, dictionary, dictLength) {
21957 var length = dictLength;
21958 var n,
21959 index = 0;
21960 if (!dictionary || status != INIT_STATE) return Z_STREAM_ERROR;
21961 if (length < MIN_MATCH) return Z_OK;
21962
21963 if (length > w_size - MIN_LOOKAHEAD) {
21964 length = w_size - MIN_LOOKAHEAD;
21965 index = dictLength - length; // use the tail of the dictionary
21966 }
21967
21968 window.set(dictionary.subarray(index, index + length), 0);
21969 strstart = length;
21970 block_start = length; // Insert all strings in the hash table (except for the last two bytes).
21971 // s->lookahead stays null, so s->ins_h will be recomputed at the next
21972 // call of fill_window.
21973
21974 ins_h = window[0] & 0xff;
21975 ins_h = (ins_h << hash_shift ^ window[1] & 0xff) & hash_mask;
21976
21977 for (n = 0; n <= length - MIN_MATCH; n++) {
21978 ins_h = (ins_h << hash_shift ^ window[n + (MIN_MATCH - 1)] & 0xff) & hash_mask;
21979 prev[n & w_mask] = head[ins_h];
21980 head[ins_h] = n;
21981 }
21982
21983 return Z_OK;
21984 };
21985
21986 that.deflate = function (_strm, flush) {
21987 var i, header, level_flags, old_flush, bstate;
21988
21989 if (flush > Z_FINISH || flush < 0) {
21990 return Z_STREAM_ERROR;
21991 }
21992
21993 if (!_strm.next_out || !_strm.next_in && _strm.avail_in !== 0 || status == FINISH_STATE && flush != Z_FINISH) {
21994 _strm.msg = z_errmsg[Z_NEED_DICT - Z_STREAM_ERROR];
21995 return Z_STREAM_ERROR;
21996 }
21997
21998 if (_strm.avail_out === 0) {
21999 _strm.msg = z_errmsg[Z_NEED_DICT - Z_BUF_ERROR];
22000 return Z_BUF_ERROR;
22001 }
22002
22003 strm = _strm; // just in case
22004
22005 old_flush = last_flush;
22006 last_flush = flush; // Write the zlib header
22007
22008 if (status == INIT_STATE) {
22009 header = Z_DEFLATED + (w_bits - 8 << 4) << 8;
22010 level_flags = (level - 1 & 0xff) >> 1;
22011 if (level_flags > 3) level_flags = 3;
22012 header |= level_flags << 6;
22013 if (strstart !== 0) header |= PRESET_DICT;
22014 header += 31 - header % 31;
22015 status = BUSY_STATE;
22016 putShortMSB(header);
22017 } // Flush as much pending output as possible
22018
22019
22020 if (that.pending !== 0) {
22021 strm.flush_pending();
22022
22023 if (strm.avail_out === 0) {
22024 // console.log(" avail_out==0");
22025 // Since avail_out is 0, deflate will be called again with
22026 // more output space, but possibly with both pending and
22027 // avail_in equal to zero. There won't be anything to do,
22028 // but this is not an error situation so make sure we
22029 // return OK instead of BUF_ERROR at next call of deflate:
22030 last_flush = -1;
22031 return Z_OK;
22032 } // Make sure there is something to do and avoid duplicate
22033 // consecutive
22034 // flushes. For repeated and useless calls with Z_FINISH, we keep
22035 // returning Z_STREAM_END instead of Z_BUFF_ERROR.
22036
22037 } else if (strm.avail_in === 0 && flush <= old_flush && flush != Z_FINISH) {
22038 strm.msg = z_errmsg[Z_NEED_DICT - Z_BUF_ERROR];
22039 return Z_BUF_ERROR;
22040 } // User must not provide more input after the first FINISH:
22041
22042
22043 if (status == FINISH_STATE && strm.avail_in !== 0) {
22044 _strm.msg = z_errmsg[Z_NEED_DICT - Z_BUF_ERROR];
22045 return Z_BUF_ERROR;
22046 } // Start a new block or continue the current one.
22047
22048
22049 if (strm.avail_in !== 0 || lookahead !== 0 || flush != Z_NO_FLUSH && status != FINISH_STATE) {
22050 bstate = -1;
22051
22052 switch (config_table[level].func) {
22053 case STORED:
22054 bstate = deflate_stored(flush);
22055 break;
22056
22057 case FAST:
22058 bstate = deflate_fast(flush);
22059 break;
22060
22061 case SLOW:
22062 bstate = deflate_slow(flush);
22063 break;
22064
22065 default:
22066 }
22067
22068 if (bstate == FinishStarted || bstate == FinishDone) {
22069 status = FINISH_STATE;
22070 }
22071
22072 if (bstate == NeedMore || bstate == FinishStarted) {
22073 if (strm.avail_out === 0) {
22074 last_flush = -1; // avoid BUF_ERROR next call, see above
22075 }
22076
22077 return Z_OK; // If flush != Z_NO_FLUSH && avail_out === 0, the next call
22078 // of deflate should use the same flush parameter to make sure
22079 // that the flush is complete. So we don't have to output an
22080 // empty block here, this will be done at next call. This also
22081 // ensures that for a very small output buffer, we emit at most
22082 // one empty block.
22083 }
22084
22085 if (bstate == BlockDone) {
22086 if (flush == Z_PARTIAL_FLUSH) {
22087 _tr_align();
22088 } else {
22089 // FULL_FLUSH or SYNC_FLUSH
22090 _tr_stored_block(0, 0, false); // For a full flush, this empty block will be recognized
22091 // as a special marker by inflate_sync().
22092
22093
22094 if (flush == Z_FULL_FLUSH) {
22095 // state.head[s.hash_size-1]=0;
22096 for (i = 0; i < hash_size
22097 /*-1*/
22098 ; i++) {
22099 // forget history
22100 head[i] = 0;
22101 }
22102 }
22103 }
22104
22105 strm.flush_pending();
22106
22107 if (strm.avail_out === 0) {
22108 last_flush = -1; // avoid BUF_ERROR at next call, see above
22109
22110 return Z_OK;
22111 }
22112 }
22113 }
22114
22115 if (flush != Z_FINISH) return Z_OK;
22116 return Z_STREAM_END;
22117 };
22118 } // ZStream
22119
22120
22121 function ZStream() {
22122 var that = this;
22123 that.next_in_index = 0;
22124 that.next_out_index = 0; // that.next_in; // next input byte
22125
22126 that.avail_in = 0; // number of bytes available at next_in
22127
22128 that.total_in = 0; // total nb of input bytes read so far
22129 // that.next_out; // next output byte should be put there
22130
22131 that.avail_out = 0; // remaining free space at next_out
22132
22133 that.total_out = 0; // total nb of bytes output so far
22134 // that.msg;
22135 // that.dstate;
22136 }
22137
22138 ZStream.prototype = {
22139 deflateInit: function deflateInit(level, bits) {
22140 var that = this;
22141 that.dstate = new Deflate();
22142 if (!bits) bits = MAX_BITS;
22143 return that.dstate.deflateInit(that, level, bits);
22144 },
22145 deflate: function deflate(flush) {
22146 var that = this;
22147
22148 if (!that.dstate) {
22149 return Z_STREAM_ERROR;
22150 }
22151
22152 return that.dstate.deflate(that, flush);
22153 },
22154 deflateEnd: function deflateEnd() {
22155 var that = this;
22156 if (!that.dstate) return Z_STREAM_ERROR;
22157 var ret = that.dstate.deflateEnd();
22158 that.dstate = null;
22159 return ret;
22160 },
22161 deflateParams: function deflateParams(level, strategy) {
22162 var that = this;
22163 if (!that.dstate) return Z_STREAM_ERROR;
22164 return that.dstate.deflateParams(that, level, strategy);
22165 },
22166 deflateSetDictionary: function deflateSetDictionary(dictionary, dictLength) {
22167 var that = this;
22168 if (!that.dstate) return Z_STREAM_ERROR;
22169 return that.dstate.deflateSetDictionary(that, dictionary, dictLength);
22170 },
22171 // Read a new buffer from the current input stream, update the
22172 // total number of bytes read. All deflate() input goes through
22173 // this function so some applications may wish to modify it to avoid
22174 // allocating a large strm->next_in buffer and copying from it.
22175 // (See also flush_pending()).
22176 read_buf: function read_buf(buf, start, size) {
22177 var that = this;
22178 var len = that.avail_in;
22179 if (len > size) len = size;
22180 if (len === 0) return 0;
22181 that.avail_in -= len;
22182 buf.set(that.next_in.subarray(that.next_in_index, that.next_in_index + len), start);
22183 that.next_in_index += len;
22184 that.total_in += len;
22185 return len;
22186 },
22187 // Flush as much pending output as possible. All deflate() output goes
22188 // through this function so some applications may wish to modify it
22189 // to avoid allocating a large strm->next_out buffer and copying into it.
22190 // (See also read_buf()).
22191 flush_pending: function flush_pending() {
22192 var that = this;
22193 var len = that.dstate.pending;
22194 if (len > that.avail_out) len = that.avail_out;
22195 if (len === 0) return; // if (that.dstate.pending_buf.length <= that.dstate.pending_out || that.next_out.length <= that.next_out_index
22196 // || that.dstate.pending_buf.length < (that.dstate.pending_out + len) || that.next_out.length < (that.next_out_index +
22197 // len)) {
22198 // console.log(that.dstate.pending_buf.length + ", " + that.dstate.pending_out + ", " + that.next_out.length + ", " +
22199 // that.next_out_index + ", " + len);
22200 // console.log("avail_out=" + that.avail_out);
22201 // }
22202
22203 that.next_out.set(that.dstate.pending_buf.subarray(that.dstate.pending_out, that.dstate.pending_out + len), that.next_out_index);
22204 that.next_out_index += len;
22205 that.dstate.pending_out += len;
22206 that.total_out += len;
22207 that.avail_out -= len;
22208 that.dstate.pending -= len;
22209
22210 if (that.dstate.pending === 0) {
22211 that.dstate.pending_out = 0;
22212 }
22213 }
22214 }; // Deflater
22215
22216 function Deflater(options) {
22217 var that = this;
22218 var z = new ZStream();
22219 var bufsize = 512;
22220 var flush = Z_NO_FLUSH;
22221 var buf = new Uint8Array(bufsize);
22222 var level = options ? options.level : Z_DEFAULT_COMPRESSION;
22223 if (typeof level == "undefined") level = Z_DEFAULT_COMPRESSION;
22224 z.deflateInit(level);
22225 z.next_out = buf;
22226
22227 that.append = function (data, onprogress) {
22228 var err,
22229 buffers = [],
22230 lastIndex = 0,
22231 bufferIndex = 0,
22232 bufferSize = 0,
22233 array;
22234 if (!data.length) return;
22235 z.next_in_index = 0;
22236 z.next_in = data;
22237 z.avail_in = data.length;
22238
22239 do {
22240 z.next_out_index = 0;
22241 z.avail_out = bufsize;
22242 err = z.deflate(flush);
22243 if (err != Z_OK) throw new Error("deflating: " + z.msg);
22244 if (z.next_out_index) if (z.next_out_index == bufsize) buffers.push(new Uint8Array(buf));else buffers.push(new Uint8Array(buf.subarray(0, z.next_out_index)));
22245 bufferSize += z.next_out_index;
22246
22247 if (onprogress && z.next_in_index > 0 && z.next_in_index != lastIndex) {
22248 onprogress(z.next_in_index);
22249 lastIndex = z.next_in_index;
22250 }
22251 } while (z.avail_in > 0 || z.avail_out === 0);
22252
22253 array = new Uint8Array(bufferSize);
22254 buffers.forEach(function (chunk) {
22255 array.set(chunk, bufferIndex);
22256 bufferIndex += chunk.length;
22257 });
22258 return array;
22259 };
22260
22261 that.flush = function () {
22262 var err,
22263 buffers = [],
22264 bufferIndex = 0,
22265 bufferSize = 0,
22266 array;
22267
22268 do {
22269 z.next_out_index = 0;
22270 z.avail_out = bufsize;
22271 err = z.deflate(Z_FINISH);
22272 if (err != Z_STREAM_END && err != Z_OK) throw new Error("deflating: " + z.msg);
22273 if (bufsize - z.avail_out > 0) buffers.push(new Uint8Array(buf.subarray(0, z.next_out_index)));
22274 bufferSize += z.next_out_index;
22275 } while (z.avail_in > 0 || z.avail_out === 0);
22276
22277 z.deflateEnd();
22278 array = new Uint8Array(bufferSize);
22279 buffers.forEach(function (chunk) {
22280 array.set(chunk, bufferIndex);
22281 bufferIndex += chunk.length;
22282 });
22283 return array;
22284 };
22285 } // 'zip' may not be defined in z-worker and some tests
22286
22287
22288 var env = global.zip || global;
22289 env.Deflater = env._jzlib_Deflater = Deflater;
22290 })(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
22291 // while `this` is nsIContentFrameMessageManager
22292 // with an attribute `content` that corresponds to the window
22293
22294 /**
22295 * A class to parse color values
22296 * @author Stoyan Stefanov <sstoo@gmail.com>
22297 * {@link http://www.phpied.com/rgb-color-parser-in-javascript/}
22298 * @license Use it if you like it
22299 */
22300 (function (global) {
22301
22302 function RGBColor(color_string) {
22303 color_string = color_string || '';
22304 this.ok = false; // strip any leading #
22305
22306 if (color_string.charAt(0) == '#') {
22307 // remove # if any
22308 color_string = color_string.substr(1, 6);
22309 }
22310
22311 color_string = color_string.replace(/ /g, '');
22312 color_string = color_string.toLowerCase();
22313 var channels; // before getting into regexps, try simple matches
22314 // and overwrite the input
22315
22316 var simple_colors = {
22317 aliceblue: 'f0f8ff',
22318 antiquewhite: 'faebd7',
22319 aqua: '00ffff',
22320 aquamarine: '7fffd4',
22321 azure: 'f0ffff',
22322 beige: 'f5f5dc',
22323 bisque: 'ffe4c4',
22324 black: '000000',
22325 blanchedalmond: 'ffebcd',
22326 blue: '0000ff',
22327 blueviolet: '8a2be2',
22328 brown: 'a52a2a',
22329 burlywood: 'deb887',
22330 cadetblue: '5f9ea0',
22331 chartreuse: '7fff00',
22332 chocolate: 'd2691e',
22333 coral: 'ff7f50',
22334 cornflowerblue: '6495ed',
22335 cornsilk: 'fff8dc',
22336 crimson: 'dc143c',
22337 cyan: '00ffff',
22338 darkblue: '00008b',
22339 darkcyan: '008b8b',
22340 darkgoldenrod: 'b8860b',
22341 darkgray: 'a9a9a9',
22342 darkgreen: '006400',
22343 darkkhaki: 'bdb76b',
22344 darkmagenta: '8b008b',
22345 darkolivegreen: '556b2f',
22346 darkorange: 'ff8c00',
22347 darkorchid: '9932cc',
22348 darkred: '8b0000',
22349 darksalmon: 'e9967a',
22350 darkseagreen: '8fbc8f',
22351 darkslateblue: '483d8b',
22352 darkslategray: '2f4f4f',
22353 darkturquoise: '00ced1',
22354 darkviolet: '9400d3',
22355 deeppink: 'ff1493',
22356 deepskyblue: '00bfff',
22357 dimgray: '696969',
22358 dodgerblue: '1e90ff',
22359 feldspar: 'd19275',
22360 firebrick: 'b22222',
22361 floralwhite: 'fffaf0',
22362 forestgreen: '228b22',
22363 fuchsia: 'ff00ff',
22364 gainsboro: 'dcdcdc',
22365 ghostwhite: 'f8f8ff',
22366 gold: 'ffd700',
22367 goldenrod: 'daa520',
22368 gray: '808080',
22369 green: '008000',
22370 greenyellow: 'adff2f',
22371 honeydew: 'f0fff0',
22372 hotpink: 'ff69b4',
22373 indianred: 'cd5c5c',
22374 indigo: '4b0082',
22375 ivory: 'fffff0',
22376 khaki: 'f0e68c',
22377 lavender: 'e6e6fa',
22378 lavenderblush: 'fff0f5',
22379 lawngreen: '7cfc00',
22380 lemonchiffon: 'fffacd',
22381 lightblue: 'add8e6',
22382 lightcoral: 'f08080',
22383 lightcyan: 'e0ffff',
22384 lightgoldenrodyellow: 'fafad2',
22385 lightgrey: 'd3d3d3',
22386 lightgreen: '90ee90',
22387 lightpink: 'ffb6c1',
22388 lightsalmon: 'ffa07a',
22389 lightseagreen: '20b2aa',
22390 lightskyblue: '87cefa',
22391 lightslateblue: '8470ff',
22392 lightslategray: '778899',
22393 lightsteelblue: 'b0c4de',
22394 lightyellow: 'ffffe0',
22395 lime: '00ff00',
22396 limegreen: '32cd32',
22397 linen: 'faf0e6',
22398 magenta: 'ff00ff',
22399 maroon: '800000',
22400 mediumaquamarine: '66cdaa',
22401 mediumblue: '0000cd',
22402 mediumorchid: 'ba55d3',
22403 mediumpurple: '9370d8',
22404 mediumseagreen: '3cb371',
22405 mediumslateblue: '7b68ee',
22406 mediumspringgreen: '00fa9a',
22407 mediumturquoise: '48d1cc',
22408 mediumvioletred: 'c71585',
22409 midnightblue: '191970',
22410 mintcream: 'f5fffa',
22411 mistyrose: 'ffe4e1',
22412 moccasin: 'ffe4b5',
22413 navajowhite: 'ffdead',
22414 navy: '000080',
22415 oldlace: 'fdf5e6',
22416 olive: '808000',
22417 olivedrab: '6b8e23',
22418 orange: 'ffa500',
22419 orangered: 'ff4500',
22420 orchid: 'da70d6',
22421 palegoldenrod: 'eee8aa',
22422 palegreen: '98fb98',
22423 paleturquoise: 'afeeee',
22424 palevioletred: 'd87093',
22425 papayawhip: 'ffefd5',
22426 peachpuff: 'ffdab9',
22427 peru: 'cd853f',
22428 pink: 'ffc0cb',
22429 plum: 'dda0dd',
22430 powderblue: 'b0e0e6',
22431 purple: '800080',
22432 red: 'ff0000',
22433 rosybrown: 'bc8f8f',
22434 royalblue: '4169e1',
22435 saddlebrown: '8b4513',
22436 salmon: 'fa8072',
22437 sandybrown: 'f4a460',
22438 seagreen: '2e8b57',
22439 seashell: 'fff5ee',
22440 sienna: 'a0522d',
22441 silver: 'c0c0c0',
22442 skyblue: '87ceeb',
22443 slateblue: '6a5acd',
22444 slategray: '708090',
22445 snow: 'fffafa',
22446 springgreen: '00ff7f',
22447 steelblue: '4682b4',
22448 tan: 'd2b48c',
22449 teal: '008080',
22450 thistle: 'd8bfd8',
22451 tomato: 'ff6347',
22452 turquoise: '40e0d0',
22453 violet: 'ee82ee',
22454 violetred: 'd02090',
22455 wheat: 'f5deb3',
22456 white: 'ffffff',
22457 whitesmoke: 'f5f5f5',
22458 yellow: 'ffff00',
22459 yellowgreen: '9acd32'
22460 };
22461
22462 for (var key in simple_colors) {
22463 if (color_string == key) {
22464 color_string = simple_colors[key];
22465 }
22466 } // emd of simple type-in colors
22467 // array of color definition objects
22468
22469
22470 var color_defs = [{
22471 re: /^rgb\((\d{1,3}),\s*(\d{1,3}),\s*(\d{1,3})\)$/,
22472 example: ['rgb(123, 234, 45)', 'rgb(255,234,245)'],
22473 process: function process(bits) {
22474 return [parseInt(bits[1]), parseInt(bits[2]), parseInt(bits[3])];
22475 }
22476 }, {
22477 re: /^(\w{2})(\w{2})(\w{2})$/,
22478 example: ['#00ff00', '336699'],
22479 process: function process(bits) {
22480 return [parseInt(bits[1], 16), parseInt(bits[2], 16), parseInt(bits[3], 16)];
22481 }
22482 }, {
22483 re: /^(\w{1})(\w{1})(\w{1})$/,
22484 example: ['#fb0', 'f0f'],
22485 process: function process(bits) {
22486 return [parseInt(bits[1] + bits[1], 16), parseInt(bits[2] + bits[2], 16), parseInt(bits[3] + bits[3], 16)];
22487 }
22488 }]; // search through the definitions to find a match
22489
22490 for (var i = 0; i < color_defs.length; i++) {
22491 var re = color_defs[i].re;
22492 var processor = color_defs[i].process;
22493 var bits = re.exec(color_string);
22494
22495 if (bits) {
22496 channels = processor(bits);
22497 this.r = channels[0];
22498 this.g = channels[1];
22499 this.b = channels[2];
22500 this.ok = true;
22501 }
22502 } // validate/cleanup values
22503
22504
22505 this.r = this.r < 0 || isNaN(this.r) ? 0 : this.r > 255 ? 255 : this.r;
22506 this.g = this.g < 0 || isNaN(this.g) ? 0 : this.g > 255 ? 255 : this.g;
22507 this.b = this.b < 0 || isNaN(this.b) ? 0 : this.b > 255 ? 255 : this.b; // some getters
22508
22509 this.toRGB = function () {
22510 return 'rgb(' + this.r + ', ' + this.g + ', ' + this.b + ')';
22511 };
22512
22513 this.toHex = function () {
22514 var r = this.r.toString(16);
22515 var g = this.g.toString(16);
22516 var b = this.b.toString(16);
22517 if (r.length == 1) r = '0' + r;
22518 if (g.length == 1) g = '0' + g;
22519 if (b.length == 1) b = '0' + b;
22520 return '#' + r + g + b;
22521 };
22522 }
22523
22524 global.RGBColor = RGBColor;
22525 })(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
22526 // while `this` is nsIContentFrameMessageManager
22527 // with an attribute `content` that corresponds to the window
22528
22529 /************************************************
22530 * Title : custom font *
22531 * Start Data : 2017. 01. 22. *
22532 * Comment : TEXT API *
22533 ************************************************/
22534
22535 /******************************
22536 * jsPDF extension API Design *
22537 * ****************************/
22538 (function (jsPDF) {
22539
22540 var PLUS = '+'.charCodeAt(0);
22541 var SLASH = '/'.charCodeAt(0);
22542 var NUMBER = '0'.charCodeAt(0);
22543 var LOWER = 'a'.charCodeAt(0);
22544 var UPPER = 'A'.charCodeAt(0);
22545 var PLUS_URL_SAFE = '-'.charCodeAt(0);
22546 var SLASH_URL_SAFE = '_'.charCodeAt(0);
22547 /*****************************************************************/
22548
22549 /* function : b64ToByteArray */
22550
22551 /* comment : Base64 encoded TTF file contents (b64) are decoded */
22552
22553 /* by Byte array and stored. */
22554
22555 /*****************************************************************/
22556
22557 var b64ToByteArray = function b64ToByteArray(b64) {
22558 var i, j, l, tmp, placeHolders, arr;
22559
22560 if (b64.length % 4 > 0) {
22561 throw new Error('Invalid string. Length must be a multiple of 4');
22562 } // the number of equal signs (place holders)
22563 // if there are two placeholders, than the two characters before it
22564 // represent one byte
22565 // if there is only one, then the three characters before it represent 2 bytes
22566 // this is just a cheap hack to not do indexOf twice
22567
22568
22569 var len = b64.length;
22570 placeHolders = '=' === b64.charAt(len - 2) ? 2 : '=' === b64.charAt(len - 1) ? 1 : 0; // base64 is 4/3 + up to two characters of the original data
22571
22572 arr = new Uint8Array(b64.length * 3 / 4 - placeHolders); // if there are placeholders, only get up to the last complete 4 chars
22573
22574 l = placeHolders > 0 ? b64.length - 4 : b64.length;
22575 var L = 0;
22576
22577 function push(v) {
22578 arr[L++] = v;
22579 }
22580
22581 for (i = 0, j = 0; i < l; i += 4, j += 3) {
22582 tmp = decode(b64.charAt(i)) << 18 | decode(b64.charAt(i + 1)) << 12 | decode(b64.charAt(i + 2)) << 6 | decode(b64.charAt(i + 3));
22583 push((tmp & 0xFF0000) >> 16);
22584 push((tmp & 0xFF00) >> 8);
22585 push(tmp & 0xFF);
22586 }
22587
22588 if (placeHolders === 2) {
22589 tmp = decode(b64.charAt(i)) << 2 | decode(b64.charAt(i + 1)) >> 4;
22590 push(tmp & 0xFF);
22591 } else if (placeHolders === 1) {
22592 tmp = decode(b64.charAt(i)) << 10 | decode(b64.charAt(i + 1)) << 4 | decode(b64.charAt(i + 2)) >> 2;
22593 push(tmp >> 8 & 0xFF);
22594 push(tmp & 0xFF);
22595 }
22596
22597 return arr;
22598 };
22599 /***************************************************************/
22600
22601 /* function : decode */
22602
22603 /* comment : Change the base64 encoded font's content to match */
22604
22605 /* the base64 index value. */
22606
22607 /***************************************************************/
22608
22609
22610 var decode = function decode(elt) {
22611 var code = elt.charCodeAt(0);
22612 if (code === PLUS || code === PLUS_URL_SAFE) return 62; // '+'
22613
22614 if (code === SLASH || code === SLASH_URL_SAFE) return 63; // '/'
22615
22616 if (code < NUMBER) return -1; //no match
22617
22618 if (code < NUMBER + 10) return code - NUMBER + 26 + 26;
22619 if (code < UPPER + 26) return code - UPPER;
22620 if (code < LOWER + 26) return code - LOWER + 26;
22621 };
22622
22623 jsPDF.API.TTFFont = function () {
22624 /************************************************************************/
22625
22626 /* function : open */
22627
22628 /* comment : Decode the encoded ttf content and create a TTFFont object. */
22629
22630 /************************************************************************/
22631 TTFFont.open = function (filename, name, vfs, encoding) {
22632 var contents;
22633
22634 if (typeof vfs !== "string") {
22635 throw new Error('Invalid argument supplied in TTFFont.open');
22636 }
22637
22638 contents = b64ToByteArray(vfs);
22639 return new TTFFont(contents, name, encoding);
22640 };
22641 /***************************************************************/
22642
22643 /* function : TTFFont gernerator */
22644
22645 /* comment : Decode TTF contents are parsed, Data, */
22646
22647 /* Subset object is created, and registerTTF function is called.*/
22648
22649 /***************************************************************/
22650
22651
22652 function TTFFont(rawData, name, encoding) {
22653 var data;
22654
22655 this.rawData = rawData;
22656 data = this.contents = new Data(rawData);
22657 this.contents.pos = 4;
22658
22659 if (data.readString(4) === 'ttcf') {
22660 if (!name) {
22661 throw new Error("Must specify a font name for TTC files.");
22662 }
22663 throw new Error("Font " + name + " not found in TTC file.");
22664 } else {
22665 data.pos = 0;
22666 this.parse();
22667 this.subset = new Subset(this);
22668 this.registerTTF();
22669 }
22670 }
22671 /********************************************************/
22672
22673 /* function : parse */
22674
22675 /* comment : TTF Parses the file contents by each table.*/
22676
22677 /********************************************************/
22678
22679
22680 TTFFont.prototype.parse = function () {
22681 this.directory = new Directory(this.contents);
22682 this.head = new HeadTable(this);
22683 this.name = new NameTable(this);
22684 this.cmap = new CmapTable(this);
22685 this.toUnicode = new Map();
22686 this.hhea = new HheaTable(this);
22687 this.maxp = new MaxpTable(this);
22688 this.hmtx = new HmtxTable(this);
22689 this.post = new PostTable(this);
22690 this.os2 = new OS2Table(this);
22691 this.loca = new LocaTable(this);
22692 this.glyf = new GlyfTable(this);
22693 this.ascender = this.os2.exists && this.os2.ascender || this.hhea.ascender;
22694 this.decender = this.os2.exists && this.os2.decender || this.hhea.decender;
22695 this.lineGap = this.os2.exists && this.os2.lineGap || this.hhea.lineGap;
22696 return this.bbox = [this.head.xMin, this.head.yMin, this.head.xMax, this.head.yMax];
22697 };
22698 /***************************************************************/
22699
22700 /* function : registerTTF */
22701
22702 /* comment : Get the value to assign pdf font descriptors. */
22703
22704 /***************************************************************/
22705
22706
22707 TTFFont.prototype.registerTTF = function () {
22708 var e, hi, low, raw, _ref;
22709
22710 this.scaleFactor = 1000.0 / this.head.unitsPerEm;
22711
22712 this.bbox = function () {
22713 var _i, _len, _ref, _results;
22714
22715 _ref = this.bbox;
22716 _results = [];
22717
22718 for (_i = 0, _len = _ref.length; _i < _len; _i++) {
22719 e = _ref[_i];
22720
22721 _results.push(Math.round(e * this.scaleFactor));
22722 }
22723
22724 return _results;
22725 }.call(this);
22726
22727 this.stemV = 0;
22728
22729 if (this.post.exists) {
22730 raw = this.post.italic_angle;
22731 hi = raw >> 16;
22732 low = raw & 0xFF;
22733
22734 if (hi & 0x8000 !== 0) {
22735 hi = -((hi ^ 0xFFFF) + 1);
22736 }
22737
22738 this.italicAngle = +("" + hi + "." + low);
22739 } else {
22740 this.italicAngle = 0;
22741 }
22742
22743 this.ascender = Math.round(this.ascender * this.scaleFactor);
22744 this.decender = Math.round(this.decender * this.scaleFactor);
22745 this.lineGap = Math.round(this.lineGap * this.scaleFactor);
22746 this.capHeight = this.os2.exists && this.os2.capHeight || this.ascender;
22747 this.xHeight = this.os2.exists && this.os2.xHeight || 0;
22748 this.familyClass = (this.os2.exists && this.os2.familyClass || 0) >> 8;
22749 this.isSerif = (_ref = this.familyClass) === 1 || _ref === 2 || _ref === 3 || _ref === 4 || _ref === 5 || _ref === 7;
22750 this.isScript = this.familyClass === 10;
22751 this.flags = 0;
22752
22753 if (this.post.isFixedPitch) {
22754 this.flags |= 1 << 0;
22755 }
22756
22757 if (this.isSerif) {
22758 this.flags |= 1 << 1;
22759 }
22760
22761 if (this.isScript) {
22762 this.flags |= 1 << 3;
22763 }
22764
22765 if (this.italicAngle !== 0) {
22766 this.flags |= 1 << 6;
22767 }
22768
22769 this.flags |= 1 << 5;
22770
22771 if (!this.cmap.unicode) {
22772 throw new Error('No unicode cmap for font');
22773 }
22774 };
22775
22776 TTFFont.prototype.characterToGlyph = function (character) {
22777 var _ref;
22778
22779 return ((_ref = this.cmap.unicode) != null ? _ref.codeMap[character] : void 0) || 0;
22780 };
22781
22782 TTFFont.prototype.widthOfGlyph = function (glyph) {
22783 var scale;
22784 scale = 1000.0 / this.head.unitsPerEm;
22785 return this.hmtx.forGlyph(glyph).advance * scale;
22786 };
22787
22788 TTFFont.prototype.widthOfString = function (string, size, charSpace) {
22789 var charCode, i, scale, width, _i, _ref, charSpace;
22790
22791 string = '' + string;
22792 width = 0;
22793
22794 for (i = _i = 0, _ref = string.length; 0 <= _ref ? _i < _ref : _i > _ref; i = 0 <= _ref ? ++_i : --_i) {
22795 charCode = string.charCodeAt(i);
22796 width += this.widthOfGlyph(this.characterToGlyph(charCode)) + charSpace * (1000 / size) || 0;
22797 }
22798
22799 scale = size / 1000;
22800 return width * scale;
22801 };
22802
22803 TTFFont.prototype.lineHeight = function (size, includeGap) {
22804 var gap;
22805
22806 if (includeGap == null) {
22807 includeGap = false;
22808 }
22809
22810 gap = includeGap ? this.lineGap : 0;
22811 return (this.ascender + gap - this.decender) / 1000 * size;
22812 };
22813
22814 return TTFFont;
22815 }();
22816 /************************************************************************************************/
22817
22818 /* function : Data */
22819
22820 /* comment : The ttf data decoded and stored in an array is read and written to the Data object.*/
22821
22822 /************************************************************************************************/
22823
22824
22825 var Data = function () {
22826 function Data(data) {
22827 this.data = data != null ? data : [];
22828 this.pos = 0;
22829 this.length = this.data.length;
22830 }
22831
22832 Data.prototype.readByte = function () {
22833 return this.data[this.pos++];
22834 };
22835
22836 Data.prototype.writeByte = function (byte) {
22837 return this.data[this.pos++] = byte;
22838 };
22839
22840 Data.prototype.readUInt32 = function () {
22841 var b1, b2, b3, b4;
22842 b1 = this.readByte() * 0x1000000;
22843 b2 = this.readByte() << 16;
22844 b3 = this.readByte() << 8;
22845 b4 = this.readByte();
22846 return b1 + b2 + b3 + b4;
22847 };
22848
22849 Data.prototype.writeUInt32 = function (val) {
22850 this.writeByte(val >>> 24 & 0xff);
22851 this.writeByte(val >> 16 & 0xff);
22852 this.writeByte(val >> 8 & 0xff);
22853 return this.writeByte(val & 0xff);
22854 };
22855
22856 Data.prototype.readInt32 = function () {
22857 var int;
22858 int = this.readUInt32();
22859
22860 if (int >= 0x80000000) {
22861 return int - 0x100000000;
22862 } else {
22863 return int;
22864 }
22865 };
22866
22867 Data.prototype.writeInt32 = function (val) {
22868 if (val < 0) {
22869 val += 0x100000000;
22870 }
22871
22872 return this.writeUInt32(val);
22873 };
22874
22875 Data.prototype.readUInt16 = function () {
22876 var b1, b2;
22877 b1 = this.readByte() << 8;
22878 b2 = this.readByte();
22879 return b1 | b2;
22880 };
22881
22882 Data.prototype.writeUInt16 = function (val) {
22883 this.writeByte(val >> 8 & 0xff);
22884 return this.writeByte(val & 0xff);
22885 };
22886
22887 Data.prototype.readInt16 = function () {
22888 var int;
22889 int = this.readUInt16();
22890
22891 if (int >= 0x8000) {
22892 return int - 0x10000;
22893 } else {
22894 return int;
22895 }
22896 };
22897
22898 Data.prototype.writeInt16 = function (val) {
22899 if (val < 0) {
22900 val += 0x10000;
22901 }
22902
22903 return this.writeUInt16(val);
22904 };
22905
22906 Data.prototype.readString = function (length) {
22907 var i, ret, _i;
22908
22909 ret = [];
22910
22911 for (i = _i = 0; 0 <= length ? _i < length : _i > length; i = 0 <= length ? ++_i : --_i) {
22912 ret[i] = String.fromCharCode(this.readByte());
22913 }
22914
22915 return ret.join('');
22916 };
22917
22918 Data.prototype.writeString = function (val) {
22919 var i, _i, _ref, _results;
22920
22921 _results = [];
22922
22923 for (i = _i = 0, _ref = val.length; 0 <= _ref ? _i < _ref : _i > _ref; i = 0 <= _ref ? ++_i : --_i) {
22924 _results.push(this.writeByte(val.charCodeAt(i)));
22925 }
22926
22927 return _results;
22928 };
22929 /*Data.prototype.stringAt = function (pos, length) {
22930 this.pos = pos;
22931 return this.readString(length);
22932 };*/
22933
22934
22935 Data.prototype.readShort = function () {
22936 return this.readInt16();
22937 };
22938
22939 Data.prototype.writeShort = function (val) {
22940 return this.writeInt16(val);
22941 };
22942
22943 Data.prototype.readLongLong = function () {
22944 var b1, b2, b3, b4, b5, b6, b7, b8;
22945 b1 = this.readByte();
22946 b2 = this.readByte();
22947 b3 = this.readByte();
22948 b4 = this.readByte();
22949 b5 = this.readByte();
22950 b6 = this.readByte();
22951 b7 = this.readByte();
22952 b8 = this.readByte();
22953
22954 if (b1 & 0x80) {
22955 return ((b1 ^ 0xff) * 0x100000000000000 + (b2 ^ 0xff) * 0x1000000000000 + (b3 ^ 0xff) * 0x10000000000 + (b4 ^ 0xff) * 0x100000000 + (b5 ^ 0xff) * 0x1000000 + (b6 ^ 0xff) * 0x10000 + (b7 ^ 0xff) * 0x100 + (b8 ^ 0xff) + 1) * -1;
22956 }
22957
22958 return b1 * 0x100000000000000 + b2 * 0x1000000000000 + b3 * 0x10000000000 + b4 * 0x100000000 + b5 * 0x1000000 + b6 * 0x10000 + b7 * 0x100 + b8;
22959 };
22960
22961 Data.prototype.writeLongLong = function (val) {
22962 var high, low;
22963 high = Math.floor(val / 0x100000000);
22964 low = val & 0xffffffff;
22965 this.writeByte(high >> 24 & 0xff);
22966 this.writeByte(high >> 16 & 0xff);
22967 this.writeByte(high >> 8 & 0xff);
22968 this.writeByte(high & 0xff);
22969 this.writeByte(low >> 24 & 0xff);
22970 this.writeByte(low >> 16 & 0xff);
22971 this.writeByte(low >> 8 & 0xff);
22972 return this.writeByte(low & 0xff);
22973 };
22974
22975 Data.prototype.readInt = function () {
22976 return this.readInt32();
22977 };
22978
22979 Data.prototype.writeInt = function (val) {
22980 return this.writeInt32(val);
22981 };
22982 /*Data.prototype.slice = function (start, end) {
22983 return this.data.slice(start, end);
22984 };*/
22985
22986
22987 Data.prototype.read = function (bytes) {
22988 var buf, i, _i;
22989
22990 buf = [];
22991
22992 for (i = _i = 0; 0 <= bytes ? _i < bytes : _i > bytes; i = 0 <= bytes ? ++_i : --_i) {
22993 buf.push(this.readByte());
22994 }
22995
22996 return buf;
22997 };
22998
22999 Data.prototype.write = function (bytes) {
23000 var byte, _i, _len, _results;
23001
23002 _results = [];
23003
23004 for (_i = 0, _len = bytes.length; _i < _len; _i++) {
23005 byte = bytes[_i];
23006
23007 _results.push(this.writeByte(byte));
23008 }
23009
23010 return _results;
23011 };
23012
23013 return Data;
23014 }();
23015
23016 var Directory = function () {
23017 var checksum;
23018 /*****************************************************************************************************/
23019
23020 /* function : Directory generator */
23021
23022 /* comment : Initialize the offset, tag, length, and checksum for each table for the font to be used.*/
23023
23024 /*****************************************************************************************************/
23025
23026 function Directory(data) {
23027 var entry, i, _i, _ref;
23028
23029 this.scalarType = data.readInt();
23030 this.tableCount = data.readShort();
23031 this.searchRange = data.readShort();
23032 this.entrySelector = data.readShort();
23033 this.rangeShift = data.readShort();
23034 this.tables = {};
23035
23036 for (i = _i = 0, _ref = this.tableCount; 0 <= _ref ? _i < _ref : _i > _ref; i = 0 <= _ref ? ++_i : --_i) {
23037 entry = {
23038 tag: data.readString(4),
23039 checksum: data.readInt(),
23040 offset: data.readInt(),
23041 length: data.readInt()
23042 };
23043 this.tables[entry.tag] = entry;
23044 }
23045 }
23046 /********************************************************************************************************/
23047
23048 /* function : encode */
23049
23050 /* comment : It encodes and stores the font table object and information used for the directory object. */
23051
23052 /********************************************************************************************************/
23053
23054
23055 Directory.prototype.encode = function (tables) {
23056 var adjustment, directory, directoryLength, entrySelector, headOffset, log2, offset, rangeShift, searchRange, sum, table, tableCount, tableData, tag;
23057 tableCount = Object.keys(tables).length;
23058 log2 = Math.log(2);
23059 searchRange = Math.floor(Math.log(tableCount) / log2) * 16;
23060 entrySelector = Math.floor(searchRange / log2);
23061 rangeShift = tableCount * 16 - searchRange;
23062 directory = new Data();
23063 directory.writeInt(this.scalarType);
23064 directory.writeShort(tableCount);
23065 directory.writeShort(searchRange);
23066 directory.writeShort(entrySelector);
23067 directory.writeShort(rangeShift);
23068 directoryLength = tableCount * 16;
23069 offset = directory.pos + directoryLength;
23070 headOffset = null;
23071 tableData = [];
23072
23073 for (tag in tables) {
23074 table = tables[tag];
23075 directory.writeString(tag);
23076 directory.writeInt(checksum(table));
23077 directory.writeInt(offset);
23078 directory.writeInt(table.length);
23079 tableData = tableData.concat(table);
23080
23081 if (tag === 'head') {
23082 headOffset = offset;
23083 }
23084
23085 offset += table.length;
23086
23087 while (offset % 4) {
23088 tableData.push(0);
23089 offset++;
23090 }
23091 }
23092
23093 directory.write(tableData);
23094 sum = checksum(directory.data);
23095 adjustment = 0xB1B0AFBA - sum;
23096 directory.pos = headOffset + 8;
23097 directory.writeUInt32(adjustment);
23098 return directory.data;
23099 };
23100 /***************************************************************/
23101
23102 /* function : checksum */
23103
23104 /* comment : Duplicate the table for the tag. */
23105
23106 /***************************************************************/
23107
23108
23109 checksum = function checksum(data) {
23110 var i, sum, tmp, _i, _ref;
23111
23112 data = __slice.call(data);
23113
23114 while (data.length % 4) {
23115 data.push(0);
23116 }
23117
23118 tmp = new Data(data);
23119 sum = 0;
23120
23121 for (i = _i = 0, _ref = data.length; _i < _ref; i = _i += 4) {
23122 sum += tmp.readUInt32();
23123 }
23124
23125 return sum & 0xFFFFFFFF;
23126 };
23127
23128 return Directory;
23129 }();
23130
23131 var Table,
23132 __hasProp = {}.hasOwnProperty,
23133 __extends = function __extends(child, parent) {
23134 for (var key in parent) {
23135 if (__hasProp.call(parent, key)) child[key] = parent[key];
23136 }
23137
23138 function ctor() {
23139 this.constructor = child;
23140 }
23141
23142 ctor.prototype = parent.prototype;
23143 child.prototype = new ctor();
23144 child.__super__ = parent.prototype;
23145 return child;
23146 };
23147 /***************************************************************/
23148
23149 /* function : Table */
23150
23151 /* comment : Save info for each table, and parse the table. */
23152
23153 /***************************************************************/
23154
23155 Table = function () {
23156 function Table(file) {
23157 var info;
23158 this.file = file;
23159 info = this.file.directory.tables[this.tag];
23160 this.exists = !!info;
23161
23162 if (info) {
23163 this.offset = info.offset, this.length = info.length;
23164 this.parse(this.file.contents);
23165 }
23166 }
23167
23168 Table.prototype.parse = function () {};
23169
23170 Table.prototype.encode = function () {};
23171
23172 Table.prototype.raw = function () {
23173 if (!this.exists) {
23174 return null;
23175 }
23176
23177 this.file.contents.pos = this.offset;
23178 return this.file.contents.read(this.length);
23179 };
23180
23181 return Table;
23182 }();
23183
23184 var HeadTable = function (_super) {
23185 __extends(HeadTable, _super);
23186
23187 function HeadTable() {
23188 return HeadTable.__super__.constructor.apply(this, arguments);
23189 }
23190
23191 HeadTable.prototype.tag = 'head';
23192
23193 HeadTable.prototype.parse = function (data) {
23194 data.pos = this.offset;
23195 this.version = data.readInt();
23196 this.revision = data.readInt();
23197 this.checkSumAdjustment = data.readInt();
23198 this.magicNumber = data.readInt();
23199 this.flags = data.readShort();
23200 this.unitsPerEm = data.readShort();
23201 this.created = data.readLongLong();
23202 this.modified = data.readLongLong();
23203 this.xMin = data.readShort();
23204 this.yMin = data.readShort();
23205 this.xMax = data.readShort();
23206 this.yMax = data.readShort();
23207 this.macStyle = data.readShort();
23208 this.lowestRecPPEM = data.readShort();
23209 this.fontDirectionHint = data.readShort();
23210 this.indexToLocFormat = data.readShort();
23211 return this.glyphDataFormat = data.readShort();
23212 };
23213
23214 HeadTable.prototype.encode = function (indexToLocFormat) {
23215 var table;
23216 table = new Data();
23217 table.writeInt(this.version);
23218 table.writeInt(this.revision);
23219 table.writeInt(this.checkSumAdjustment);
23220 table.writeInt(this.magicNumber);
23221 table.writeShort(this.flags);
23222 table.writeShort(this.unitsPerEm);
23223 table.writeLongLong(this.created);
23224 table.writeLongLong(this.modified);
23225 table.writeShort(this.xMin);
23226 table.writeShort(this.yMin);
23227 table.writeShort(this.xMax);
23228 table.writeShort(this.yMax);
23229 table.writeShort(this.macStyle);
23230 table.writeShort(this.lowestRecPPEM);
23231 table.writeShort(this.fontDirectionHint);
23232 table.writeShort(indexToLocFormat);
23233 table.writeShort(this.glyphDataFormat);
23234 return table.data;
23235 };
23236
23237 return HeadTable;
23238 }(Table);
23239 /************************************************************************************/
23240
23241 /* function : CmapEntry */
23242
23243 /* comment : Cmap Initializes and encodes object information (required by pdf spec).*/
23244
23245 /************************************************************************************/
23246
23247
23248 var CmapEntry = function () {
23249 function CmapEntry(data, offset) {
23250 var code, count, endCode, glyphId, glyphIds, i, idDelta, idRangeOffset, index, saveOffset, segCount, segCountX2, start, startCode, tail, _i, _j, _k, _len;
23251
23252 this.platformID = data.readUInt16();
23253 this.encodingID = data.readShort();
23254 this.offset = offset + data.readInt();
23255 saveOffset = data.pos;
23256 data.pos = this.offset;
23257 this.format = data.readUInt16();
23258 this.length = data.readUInt16();
23259 this.language = data.readUInt16();
23260 this.isUnicode = this.platformID === 3 && this.encodingID === 1 && this.format === 4 || this.platformID === 0 && this.format === 4;
23261 this.codeMap = {};
23262
23263 switch (this.format) {
23264 case 0:
23265 for (i = _i = 0; _i < 256; i = ++_i) {
23266 this.codeMap[i] = data.readByte();
23267 }
23268
23269 break;
23270
23271 case 4:
23272 segCountX2 = data.readUInt16();
23273 segCount = segCountX2 / 2;
23274 data.pos += 6;
23275
23276 endCode = function () {
23277 var _j, _results;
23278
23279 _results = [];
23280
23281 for (i = _j = 0; 0 <= segCount ? _j < segCount : _j > segCount; i = 0 <= segCount ? ++_j : --_j) {
23282 _results.push(data.readUInt16());
23283 }
23284
23285 return _results;
23286 }();
23287
23288 data.pos += 2;
23289
23290 startCode = function () {
23291 var _j, _results;
23292
23293 _results = [];
23294
23295 for (i = _j = 0; 0 <= segCount ? _j < segCount : _j > segCount; i = 0 <= segCount ? ++_j : --_j) {
23296 _results.push(data.readUInt16());
23297 }
23298
23299 return _results;
23300 }();
23301
23302 idDelta = function () {
23303 var _j, _results;
23304
23305 _results = [];
23306
23307 for (i = _j = 0; 0 <= segCount ? _j < segCount : _j > segCount; i = 0 <= segCount ? ++_j : --_j) {
23308 _results.push(data.readUInt16());
23309 }
23310
23311 return _results;
23312 }();
23313
23314 idRangeOffset = function () {
23315 var _j, _results;
23316
23317 _results = [];
23318
23319 for (i = _j = 0; 0 <= segCount ? _j < segCount : _j > segCount; i = 0 <= segCount ? ++_j : --_j) {
23320 _results.push(data.readUInt16());
23321 }
23322
23323 return _results;
23324 }();
23325
23326 count = (this.length - data.pos + this.offset) / 2;
23327
23328 glyphIds = function () {
23329 var _j, _results;
23330
23331 _results = [];
23332
23333 for (i = _j = 0; 0 <= count ? _j < count : _j > count; i = 0 <= count ? ++_j : --_j) {
23334 _results.push(data.readUInt16());
23335 }
23336
23337 return _results;
23338 }();
23339
23340 for (i = _j = 0, _len = endCode.length; _j < _len; i = ++_j) {
23341 tail = endCode[i];
23342 start = startCode[i];
23343
23344 for (code = _k = start; start <= tail ? _k <= tail : _k >= tail; code = start <= tail ? ++_k : --_k) {
23345 if (idRangeOffset[i] === 0) {
23346 glyphId = code + idDelta[i];
23347 } else {
23348 index = idRangeOffset[i] / 2 + (code - start) - (segCount - i);
23349 glyphId = glyphIds[index] || 0;
23350
23351 if (glyphId !== 0) {
23352 glyphId += idDelta[i];
23353 }
23354 }
23355
23356 this.codeMap[code] = glyphId & 0xFFFF;
23357 }
23358 }
23359
23360 }
23361
23362 data.pos = saveOffset;
23363 }
23364
23365 CmapEntry.encode = function (charmap, encoding) {
23366 var charMap, code, codeMap, codes, delta, deltas, diff, endCode, endCodes, entrySelector, glyphIDs, i, id, indexes, last, map, nextID, offset, old, rangeOffsets, rangeShift, result, searchRange, segCount, segCountX2, startCode, startCodes, startGlyph, subtable, _i, _j, _k, _l, _len, _len1, _len2, _len3, _len4, _len5, _len6, _len7, _m, _n, _name, _o, _p, _q;
23367
23368 subtable = new Data();
23369 codes = Object.keys(charmap).sort(function (a, b) {
23370 return a - b;
23371 });
23372
23373 switch (encoding) {
23374 case 'macroman':
23375 id = 0;
23376
23377 indexes = function () {
23378 var _i, _results;
23379
23380 _results = [];
23381
23382 for (i = _i = 0; _i < 256; i = ++_i) {
23383 _results.push(0);
23384 }
23385
23386 return _results;
23387 }();
23388
23389 map = {
23390 0: 0
23391 };
23392 codeMap = {};
23393
23394 for (_i = 0, _len = codes.length; _i < _len; _i++) {
23395 code = codes[_i];
23396
23397 if (map[_name = charmap[code]] == null) {
23398 map[_name] = ++id;
23399 }
23400
23401 codeMap[code] = {
23402 old: charmap[code],
23403 "new": map[charmap[code]]
23404 };
23405 indexes[code] = map[charmap[code]];
23406 }
23407
23408 subtable.writeUInt16(1);
23409 subtable.writeUInt16(0);
23410 subtable.writeUInt32(12);
23411 subtable.writeUInt16(0);
23412 subtable.writeUInt16(262);
23413 subtable.writeUInt16(0);
23414 subtable.write(indexes);
23415 return result = {
23416 charMap: codeMap,
23417 subtable: subtable.data,
23418 maxGlyphID: id + 1
23419 };
23420
23421 case 'unicode':
23422 startCodes = [];
23423 endCodes = [];
23424 nextID = 0;
23425 map = {};
23426 charMap = {};
23427 last = diff = null;
23428
23429 for (_j = 0, _len1 = codes.length; _j < _len1; _j++) {
23430 code = codes[_j];
23431 old = charmap[code];
23432
23433 if (map[old] == null) {
23434 map[old] = ++nextID;
23435 }
23436
23437 charMap[code] = {
23438 old: old,
23439 "new": map[old]
23440 };
23441 delta = map[old] - code;
23442
23443 if (last == null || delta !== diff) {
23444 if (last) {
23445 endCodes.push(last);
23446 }
23447
23448 startCodes.push(code);
23449 diff = delta;
23450 }
23451
23452 last = code;
23453 }
23454
23455 if (last) {
23456 endCodes.push(last);
23457 }
23458
23459 endCodes.push(0xFFFF);
23460 startCodes.push(0xFFFF);
23461 segCount = startCodes.length;
23462 segCountX2 = segCount * 2;
23463 searchRange = 2 * Math.pow(Math.log(segCount) / Math.LN2, 2);
23464 entrySelector = Math.log(searchRange / 2) / Math.LN2;
23465 rangeShift = 2 * segCount - searchRange;
23466 deltas = [];
23467 rangeOffsets = [];
23468 glyphIDs = [];
23469
23470 for (i = _k = 0, _len2 = startCodes.length; _k < _len2; i = ++_k) {
23471 startCode = startCodes[i];
23472 endCode = endCodes[i];
23473
23474 if (startCode === 0xFFFF) {
23475 deltas.push(0);
23476 rangeOffsets.push(0);
23477 break;
23478 }
23479
23480 startGlyph = charMap[startCode]["new"];
23481
23482 if (startCode - startGlyph >= 0x8000) {
23483 deltas.push(0);
23484 rangeOffsets.push(2 * (glyphIDs.length + segCount - i));
23485
23486 for (code = _l = startCode; startCode <= endCode ? _l <= endCode : _l >= endCode; code = startCode <= endCode ? ++_l : --_l) {
23487 glyphIDs.push(charMap[code]["new"]);
23488 }
23489 } else {
23490 deltas.push(startGlyph - startCode);
23491 rangeOffsets.push(0);
23492 }
23493 }
23494
23495 subtable.writeUInt16(3);
23496 subtable.writeUInt16(1);
23497 subtable.writeUInt32(12);
23498 subtable.writeUInt16(4);
23499 subtable.writeUInt16(16 + segCount * 8 + glyphIDs.length * 2);
23500 subtable.writeUInt16(0);
23501 subtable.writeUInt16(segCountX2);
23502 subtable.writeUInt16(searchRange);
23503 subtable.writeUInt16(entrySelector);
23504 subtable.writeUInt16(rangeShift);
23505
23506 for (_m = 0, _len3 = endCodes.length; _m < _len3; _m++) {
23507 code = endCodes[_m];
23508 subtable.writeUInt16(code);
23509 }
23510
23511 subtable.writeUInt16(0);
23512
23513 for (_n = 0, _len4 = startCodes.length; _n < _len4; _n++) {
23514 code = startCodes[_n];
23515 subtable.writeUInt16(code);
23516 }
23517
23518 for (_o = 0, _len5 = deltas.length; _o < _len5; _o++) {
23519 delta = deltas[_o];
23520 subtable.writeUInt16(delta);
23521 }
23522
23523 for (_p = 0, _len6 = rangeOffsets.length; _p < _len6; _p++) {
23524 offset = rangeOffsets[_p];
23525 subtable.writeUInt16(offset);
23526 }
23527
23528 for (_q = 0, _len7 = glyphIDs.length; _q < _len7; _q++) {
23529 id = glyphIDs[_q];
23530 subtable.writeUInt16(id);
23531 }
23532
23533 return result = {
23534 charMap: charMap,
23535 subtable: subtable.data,
23536 maxGlyphID: nextID + 1
23537 };
23538 }
23539 };
23540
23541 return CmapEntry;
23542 }();
23543
23544 var CmapTable = function (_super) {
23545 __extends(CmapTable, _super);
23546
23547 function CmapTable() {
23548 return CmapTable.__super__.constructor.apply(this, arguments);
23549 }
23550
23551 CmapTable.prototype.tag = 'cmap';
23552
23553 CmapTable.prototype.parse = function (data) {
23554 var entry, i, tableCount, _i;
23555
23556 data.pos = this.offset;
23557 this.version = data.readUInt16();
23558 tableCount = data.readUInt16();
23559 this.tables = [];
23560 this.unicode = null;
23561
23562 for (i = _i = 0; 0 <= tableCount ? _i < tableCount : _i > tableCount; i = 0 <= tableCount ? ++_i : --_i) {
23563 entry = new CmapEntry(data, this.offset);
23564 this.tables.push(entry);
23565
23566 if (entry.isUnicode) {
23567 if (this.unicode == null) {
23568 this.unicode = entry;
23569 }
23570 }
23571 }
23572
23573 return true;
23574 };
23575 /*************************************************************************/
23576
23577 /* function : encode */
23578
23579 /* comment : Encode the cmap table corresponding to the input character. */
23580
23581 /*************************************************************************/
23582
23583
23584 CmapTable.encode = function (charmap, encoding) {
23585 var result, table;
23586
23587 if (encoding == null) {
23588 encoding = 'macroman';
23589 }
23590
23591 result = CmapEntry.encode(charmap, encoding);
23592 table = new Data();
23593 table.writeUInt16(0);
23594 table.writeUInt16(1);
23595 result.table = table.data.concat(result.subtable);
23596 return result;
23597 };
23598
23599 return CmapTable;
23600 }(Table);
23601
23602 var HheaTable = function (_super) {
23603 __extends(HheaTable, _super);
23604
23605 function HheaTable() {
23606 return HheaTable.__super__.constructor.apply(this, arguments);
23607 }
23608
23609 HheaTable.prototype.tag = 'hhea';
23610
23611 HheaTable.prototype.parse = function (data) {
23612 data.pos = this.offset;
23613 this.version = data.readInt();
23614 this.ascender = data.readShort();
23615 this.decender = data.readShort();
23616 this.lineGap = data.readShort();
23617 this.advanceWidthMax = data.readShort();
23618 this.minLeftSideBearing = data.readShort();
23619 this.minRightSideBearing = data.readShort();
23620 this.xMaxExtent = data.readShort();
23621 this.caretSlopeRise = data.readShort();
23622 this.caretSlopeRun = data.readShort();
23623 this.caretOffset = data.readShort();
23624 data.pos += 4 * 2;
23625 this.metricDataFormat = data.readShort();
23626 return this.numberOfMetrics = data.readUInt16();
23627 };
23628 /*HheaTable.prototype.encode = function (ids) {
23629 var i, table, _i, _ref;
23630 table = new Data;
23631 table.writeInt(this.version);
23632 table.writeShort(this.ascender);
23633 table.writeShort(this.decender);
23634 table.writeShort(this.lineGap);
23635 table.writeShort(this.advanceWidthMax);
23636 table.writeShort(this.minLeftSideBearing);
23637 table.writeShort(this.minRightSideBearing);
23638 table.writeShort(this.xMaxExtent);
23639 table.writeShort(this.caretSlopeRise);
23640 table.writeShort(this.caretSlopeRun);
23641 table.writeShort(this.caretOffset);
23642 for (i = _i = 0, _ref = 4 * 2; 0 <= _ref ? _i < _ref : _i > _ref; i = 0 <= _ref ? ++_i : --_i) {
23643 table.writeByte(0);
23644 }
23645 table.writeShort(this.metricDataFormat);
23646 table.writeUInt16(ids.length);
23647 return table.data;
23648 };*/
23649
23650
23651 return HheaTable;
23652 }(Table);
23653
23654 var OS2Table = function (_super) {
23655 __extends(OS2Table, _super);
23656
23657 function OS2Table() {
23658 return OS2Table.__super__.constructor.apply(this, arguments);
23659 }
23660
23661 OS2Table.prototype.tag = 'OS/2';
23662
23663 OS2Table.prototype.parse = function (data) {
23664 var i;
23665 data.pos = this.offset;
23666 this.version = data.readUInt16();
23667 this.averageCharWidth = data.readShort();
23668 this.weightClass = data.readUInt16();
23669 this.widthClass = data.readUInt16();
23670 this.type = data.readShort();
23671 this.ySubscriptXSize = data.readShort();
23672 this.ySubscriptYSize = data.readShort();
23673 this.ySubscriptXOffset = data.readShort();
23674 this.ySubscriptYOffset = data.readShort();
23675 this.ySuperscriptXSize = data.readShort();
23676 this.ySuperscriptYSize = data.readShort();
23677 this.ySuperscriptXOffset = data.readShort();
23678 this.ySuperscriptYOffset = data.readShort();
23679 this.yStrikeoutSize = data.readShort();
23680 this.yStrikeoutPosition = data.readShort();
23681 this.familyClass = data.readShort();
23682
23683 this.panose = function () {
23684 var _i, _results;
23685
23686 _results = [];
23687
23688 for (i = _i = 0; _i < 10; i = ++_i) {
23689 _results.push(data.readByte());
23690 }
23691
23692 return _results;
23693 }();
23694
23695 this.charRange = function () {
23696 var _i, _results;
23697
23698 _results = [];
23699
23700 for (i = _i = 0; _i < 4; i = ++_i) {
23701 _results.push(data.readInt());
23702 }
23703
23704 return _results;
23705 }();
23706
23707 this.vendorID = data.readString(4);
23708 this.selection = data.readShort();
23709 this.firstCharIndex = data.readShort();
23710 this.lastCharIndex = data.readShort();
23711
23712 if (this.version > 0) {
23713 this.ascent = data.readShort();
23714 this.descent = data.readShort();
23715 this.lineGap = data.readShort();
23716 this.winAscent = data.readShort();
23717 this.winDescent = data.readShort();
23718
23719 this.codePageRange = function () {
23720 var _i, _results;
23721
23722 _results = [];
23723
23724 for (i = _i = 0; _i < 2; i = ++_i) {
23725 _results.push(data.readInt());
23726 }
23727
23728 return _results;
23729 }();
23730
23731 if (this.version > 1) {
23732 this.xHeight = data.readShort();
23733 this.capHeight = data.readShort();
23734 this.defaultChar = data.readShort();
23735 this.breakChar = data.readShort();
23736 return this.maxContext = data.readShort();
23737 }
23738 }
23739 };
23740 /*OS2Table.prototype.encode = function () {
23741 return this.raw();
23742 };*/
23743
23744
23745 return OS2Table;
23746 }(Table);
23747
23748 var PostTable = function (_super) {
23749
23750 __extends(PostTable, _super);
23751
23752 function PostTable() {
23753 return PostTable.__super__.constructor.apply(this, arguments);
23754 }
23755
23756 PostTable.prototype.tag = 'post';
23757
23758 PostTable.prototype.parse = function (data) {
23759 var i, length, numberOfGlyphs, _i, _results;
23760
23761 data.pos = this.offset;
23762 this.format = data.readInt();
23763 this.italicAngle = data.readInt();
23764 this.underlinePosition = data.readShort();
23765 this.underlineThickness = data.readShort();
23766 this.isFixedPitch = data.readInt();
23767 this.minMemType42 = data.readInt();
23768 this.maxMemType42 = data.readInt();
23769 this.minMemType1 = data.readInt();
23770 this.maxMemType1 = data.readInt();
23771
23772 switch (this.format) {
23773 case 0x00010000:
23774 break;
23775
23776 case 0x00020000:
23777 numberOfGlyphs = data.readUInt16();
23778 this.glyphNameIndex = [];
23779
23780 for (i = _i = 0; 0 <= numberOfGlyphs ? _i < numberOfGlyphs : _i > numberOfGlyphs; i = 0 <= numberOfGlyphs ? ++_i : --_i) {
23781 this.glyphNameIndex.push(data.readUInt16());
23782 }
23783
23784 this.names = [];
23785 _results = [];
23786
23787 while (data.pos < this.offset + this.length) {
23788 length = data.readByte();
23789
23790 _results.push(this.names.push(data.readString(length)));
23791 }
23792
23793 return _results;
23794 break;
23795
23796 case 0x00025000:
23797 numberOfGlyphs = data.readUInt16();
23798 return this.offsets = data.read(numberOfGlyphs);
23799
23800 case 0x00030000:
23801 break;
23802
23803 case 0x00040000:
23804 return this.map = function () {
23805 var _j, _ref, _results1;
23806
23807 _results1 = [];
23808
23809 for (i = _j = 0, _ref = this.file.maxp.numGlyphs; 0 <= _ref ? _j < _ref : _j > _ref; i = 0 <= _ref ? ++_j : --_j) {
23810 _results1.push(data.readUInt32());
23811 }
23812
23813 return _results1;
23814 }.call(this);
23815 }
23816 };
23817 return PostTable;
23818 }(Table);
23819 /*********************************************************************************************************/
23820
23821 /* function : NameEntry */
23822
23823 /* comment : Store copyright information, platformID, encodingID, and languageID in the NameEntry object.*/
23824
23825 /*********************************************************************************************************/
23826
23827
23828 var NameEntry = function () {
23829 function NameEntry(raw, entry) {
23830 this.raw = raw;
23831 this.length = raw.length;
23832 this.platformID = entry.platformID;
23833 this.encodingID = entry.encodingID;
23834 this.languageID = entry.languageID;
23835 }
23836
23837 return NameEntry;
23838 }();
23839
23840 var NameTable = function (_super) {
23841
23842 __extends(NameTable, _super);
23843
23844 function NameTable() {
23845 return NameTable.__super__.constructor.apply(this, arguments);
23846 }
23847
23848 NameTable.prototype.tag = 'name';
23849
23850 NameTable.prototype.parse = function (data) {
23851 var count, entries, entry, format, i, name, stringOffset, strings, text, _i, _j, _len, _name;
23852
23853 data.pos = this.offset;
23854 format = data.readShort();
23855 count = data.readShort();
23856 stringOffset = data.readShort();
23857 entries = [];
23858
23859 for (i = _i = 0; 0 <= count ? _i < count : _i > count; i = 0 <= count ? ++_i : --_i) {
23860 entries.push({
23861 platformID: data.readShort(),
23862 encodingID: data.readShort(),
23863 languageID: data.readShort(),
23864 nameID: data.readShort(),
23865 length: data.readShort(),
23866 offset: this.offset + stringOffset + data.readShort()
23867 });
23868 }
23869
23870 strings = {};
23871
23872 for (i = _j = 0, _len = entries.length; _j < _len; i = ++_j) {
23873 entry = entries[i];
23874 data.pos = entry.offset;
23875 text = data.readString(entry.length);
23876 name = new NameEntry(text, entry);
23877
23878 if (strings[_name = entry.nameID] == null) {
23879 strings[_name] = [];
23880 }
23881
23882 strings[entry.nameID].push(name);
23883 }
23884
23885 this.strings = strings;
23886 this.copyright = strings[0];
23887 this.fontFamily = strings[1];
23888 this.fontSubfamily = strings[2];
23889 this.uniqueSubfamily = strings[3];
23890 this.fontName = strings[4];
23891 this.version = strings[5];
23892
23893 try {
23894 this.postscriptName = strings[6][0].raw.replace(/[\x00-\x19\x80-\xff]/g, "");
23895 } catch (e) {
23896 this.postscriptName = strings[4][0].raw.replace(/[\x00-\x19\x80-\xff]/g, "");
23897 }
23898
23899 this.trademark = strings[7];
23900 this.manufacturer = strings[8];
23901 this.designer = strings[9];
23902 this.description = strings[10];
23903 this.vendorUrl = strings[11];
23904 this.designerUrl = strings[12];
23905 this.license = strings[13];
23906 this.licenseUrl = strings[14];
23907 this.preferredFamily = strings[15];
23908 this.preferredSubfamily = strings[17];
23909 this.compatibleFull = strings[18];
23910 return this.sampleText = strings[19];
23911 };
23912 /*NameTable.prototype.encode = function () {
23913 var id, list, nameID, nameTable, postscriptName, strCount, strTable, string, strings, table, val, _i, _len, _ref;
23914 strings = {};
23915 _ref = this.strings;
23916 for (id in _ref) {
23917 val = _ref[id];
23918 strings[id] = val;
23919 }
23920 postscriptName = new NameEntry("" + subsetTag + "+" + this.postscriptName, {
23921 platformID: 1
23922 , encodingID: 0
23923 , languageID: 0
23924 });
23925 strings[6] = [postscriptName];
23926 subsetTag = successorOf(subsetTag);
23927 strCount = 0;
23928 for (id in strings) {
23929 list = strings[id];
23930 if (list != null) {
23931 strCount += list.length;
23932 }
23933 }
23934 table = new Data;
23935 strTable = new Data;
23936 table.writeShort(0);
23937 table.writeShort(strCount);
23938 table.writeShort(6 + 12 * strCount);
23939 for (nameID in strings) {
23940 list = strings[nameID];
23941 if (list != null) {
23942 for (_i = 0, _len = list.length; _i < _len; _i++) {
23943 string = list[_i];
23944 table.writeShort(string.platformID);
23945 table.writeShort(string.encodingID);
23946 table.writeShort(string.languageID);
23947 table.writeShort(nameID);
23948 table.writeShort(string.length);
23949 table.writeShort(strTable.pos);
23950 strTable.writeString(string.raw);
23951 }
23952 }
23953 }
23954 return nameTable = {
23955 postscriptName: postscriptName.raw
23956 , table: table.data.concat(strTable.data)
23957 };
23958 };*/
23959
23960 return NameTable;
23961 }(Table);
23962
23963 var MaxpTable = function (_super) {
23964 __extends(MaxpTable, _super);
23965
23966 function MaxpTable() {
23967 return MaxpTable.__super__.constructor.apply(this, arguments);
23968 }
23969
23970 MaxpTable.prototype.tag = 'maxp';
23971
23972 MaxpTable.prototype.parse = function (data) {
23973 data.pos = this.offset;
23974 this.version = data.readInt();
23975 this.numGlyphs = data.readUInt16();
23976 this.maxPoints = data.readUInt16();
23977 this.maxContours = data.readUInt16();
23978 this.maxCompositePoints = data.readUInt16();
23979 this.maxComponentContours = data.readUInt16();
23980 this.maxZones = data.readUInt16();
23981 this.maxTwilightPoints = data.readUInt16();
23982 this.maxStorage = data.readUInt16();
23983 this.maxFunctionDefs = data.readUInt16();
23984 this.maxInstructionDefs = data.readUInt16();
23985 this.maxStackElements = data.readUInt16();
23986 this.maxSizeOfInstructions = data.readUInt16();
23987 this.maxComponentElements = data.readUInt16();
23988 return this.maxComponentDepth = data.readUInt16();
23989 };
23990 /*MaxpTable.prototype.encode = function (ids) {
23991 var table;
23992 table = new Data;
23993 table.writeInt(this.version);
23994 table.writeUInt16(ids.length);
23995 table.writeUInt16(this.maxPoints);
23996 table.writeUInt16(this.maxContours);
23997 table.writeUInt16(this.maxCompositePoints);
23998 table.writeUInt16(this.maxComponentContours);
23999 table.writeUInt16(this.maxZones);
24000 table.writeUInt16(this.maxTwilightPoints);
24001 table.writeUInt16(this.maxStorage);
24002 table.writeUInt16(this.maxFunctionDefs);
24003 table.writeUInt16(this.maxInstructionDefs);
24004 table.writeUInt16(this.maxStackElements);
24005 table.writeUInt16(this.maxSizeOfInstructions);
24006 table.writeUInt16(this.maxComponentElements);
24007 table.writeUInt16(this.maxComponentDepth);
24008 return table.data;
24009 };*/
24010
24011
24012 return MaxpTable;
24013 }(Table);
24014
24015 var HmtxTable = function (_super) {
24016 __extends(HmtxTable, _super);
24017
24018 function HmtxTable() {
24019 return HmtxTable.__super__.constructor.apply(this, arguments);
24020 }
24021
24022 HmtxTable.prototype.tag = 'hmtx';
24023
24024 HmtxTable.prototype.parse = function (data) {
24025 var i, last, lsbCount, m, _i, _j, _ref, _results;
24026
24027 data.pos = this.offset;
24028 this.metrics = [];
24029
24030 for (i = _i = 0, _ref = this.file.hhea.numberOfMetrics; 0 <= _ref ? _i < _ref : _i > _ref; i = 0 <= _ref ? ++_i : --_i) {
24031 this.metrics.push({
24032 advance: data.readUInt16(),
24033 lsb: data.readInt16()
24034 });
24035 }
24036
24037 lsbCount = this.file.maxp.numGlyphs - this.file.hhea.numberOfMetrics;
24038
24039 this.leftSideBearings = function () {
24040 var _j, _results;
24041
24042 _results = [];
24043
24044 for (i = _j = 0; 0 <= lsbCount ? _j < lsbCount : _j > lsbCount; i = 0 <= lsbCount ? ++_j : --_j) {
24045 _results.push(data.readInt16());
24046 }
24047
24048 return _results;
24049 }();
24050
24051 this.widths = function () {
24052 var _j, _len, _ref1, _results;
24053
24054 _ref1 = this.metrics;
24055 _results = [];
24056
24057 for (_j = 0, _len = _ref1.length; _j < _len; _j++) {
24058 m = _ref1[_j];
24059
24060 _results.push(m.advance);
24061 }
24062
24063 return _results;
24064 }.call(this);
24065
24066 last = this.widths[this.widths.length - 1];
24067 _results = [];
24068
24069 for (i = _j = 0; 0 <= lsbCount ? _j < lsbCount : _j > lsbCount; i = 0 <= lsbCount ? ++_j : --_j) {
24070 _results.push(this.widths.push(last));
24071 }
24072
24073 return _results;
24074 };
24075 /***************************************************************/
24076
24077 /* function : forGlyph */
24078
24079 /* comment : Returns the advance width and lsb for this glyph. */
24080
24081 /***************************************************************/
24082
24083
24084 HmtxTable.prototype.forGlyph = function (id) {
24085 var metrics;
24086
24087 if (id in this.metrics) {
24088 return this.metrics[id];
24089 }
24090
24091 return metrics = {
24092 advance: this.metrics[this.metrics.length - 1].advance,
24093 lsb: this.leftSideBearings[id - this.metrics.length]
24094 };
24095 };
24096 /*HmtxTable.prototype.encode = function (mapping) {
24097 var id, metric, table, _i, _len;
24098 table = new Data;
24099 for (_i = 0, _len = mapping.length; _i < _len; _i++) {
24100 id = mapping[_i];
24101 metric = this.forGlyph(id);
24102 table.writeUInt16(metric.advance);
24103 table.writeUInt16(metric.lsb);
24104 }
24105 return table.data;
24106 };*/
24107
24108
24109 return HmtxTable;
24110 }(Table);
24111
24112 var __slice = [].slice;
24113
24114 var GlyfTable = function (_super) {
24115 __extends(GlyfTable, _super);
24116
24117 function GlyfTable() {
24118 return GlyfTable.__super__.constructor.apply(this, arguments);
24119 }
24120
24121 GlyfTable.prototype.tag = 'glyf';
24122
24123 GlyfTable.prototype.parse = function (data) {
24124 return this.cache = {};
24125 };
24126
24127 GlyfTable.prototype.glyphFor = function (id) {
24128 id = id;
24129 var data, index, length, loca, numberOfContours, raw, xMax, xMin, yMax, yMin;
24130
24131 if (id in this.cache) {
24132 return this.cache[id];
24133 }
24134
24135 loca = this.file.loca;
24136 data = this.file.contents;
24137 index = loca.indexOf(id);
24138 length = loca.lengthOf(id);
24139
24140 if (length === 0) {
24141 return this.cache[id] = null;
24142 }
24143
24144 data.pos = this.offset + index;
24145 raw = new Data(data.read(length));
24146 numberOfContours = raw.readShort();
24147 xMin = raw.readShort();
24148 yMin = raw.readShort();
24149 xMax = raw.readShort();
24150 yMax = raw.readShort();
24151
24152 if (numberOfContours === -1) {
24153 this.cache[id] = new CompoundGlyph(raw, xMin, yMin, xMax, yMax);
24154 } else {
24155 this.cache[id] = new SimpleGlyph(raw, numberOfContours, xMin, yMin, xMax, yMax);
24156 }
24157
24158 return this.cache[id];
24159 };
24160
24161 GlyfTable.prototype.encode = function (glyphs, mapping, old2new) {
24162 var glyph, id, offsets, table, _i, _len;
24163
24164 table = [];
24165 offsets = [];
24166
24167 for (_i = 0, _len = mapping.length; _i < _len; _i++) {
24168 id = mapping[_i];
24169 glyph = glyphs[id];
24170 offsets.push(table.length);
24171
24172 if (glyph) {
24173 table = table.concat(glyph.encode(old2new));
24174 }
24175 }
24176
24177 offsets.push(table.length);
24178 return {
24179 table: table,
24180 offsets: offsets
24181 };
24182 };
24183
24184 return GlyfTable;
24185 }(Table);
24186
24187 var SimpleGlyph = function () {
24188 /**************************************************************************/
24189
24190 /* function : SimpleGlyph */
24191
24192 /* comment : Stores raw, xMin, yMin, xMax, and yMax values for this glyph.*/
24193
24194 /**************************************************************************/
24195 function SimpleGlyph(raw, numberOfContours, xMin, yMin, xMax, yMax) {
24196 this.raw = raw;
24197 this.numberOfContours = numberOfContours;
24198 this.xMin = xMin;
24199 this.yMin = yMin;
24200 this.xMax = xMax;
24201 this.yMax = yMax;
24202 this.compound = false;
24203 }
24204
24205 SimpleGlyph.prototype.encode = function () {
24206 return this.raw.data;
24207 };
24208
24209 return SimpleGlyph;
24210 }();
24211
24212 var CompoundGlyph = function () {
24213 var ARG_1_AND_2_ARE_WORDS, MORE_COMPONENTS, WE_HAVE_AN_X_AND_Y_SCALE, WE_HAVE_A_SCALE, WE_HAVE_A_TWO_BY_TWO;
24214 ARG_1_AND_2_ARE_WORDS = 0x0001;
24215 WE_HAVE_A_SCALE = 0x0008;
24216 MORE_COMPONENTS = 0x0020;
24217 WE_HAVE_AN_X_AND_Y_SCALE = 0x0040;
24218 WE_HAVE_A_TWO_BY_TWO = 0x0080;
24219 /********************************************************************************************************************/
24220
24221 /* function : CompoundGlypg generator */
24222
24223 /* comment : It stores raw, xMin, yMin, xMax, yMax, glyph id, and glyph offset for the corresponding compound glyph.*/
24224
24225 /********************************************************************************************************************/
24226
24227 function CompoundGlyph(raw, xMin, yMin, xMax, yMax) {
24228 var data, flags;
24229 this.raw = raw;
24230 this.xMin = xMin;
24231 this.yMin = yMin;
24232 this.xMax = xMax;
24233 this.yMax = yMax;
24234 this.compound = true;
24235 this.glyphIDs = [];
24236 this.glyphOffsets = [];
24237 data = this.raw;
24238
24239 while (true) {
24240 flags = data.readShort();
24241 this.glyphOffsets.push(data.pos);
24242 this.glyphIDs.push(data.readShort());
24243
24244 if (!(flags & MORE_COMPONENTS)) {
24245 break;
24246 }
24247
24248 if (flags & ARG_1_AND_2_ARE_WORDS) {
24249 data.pos += 4;
24250 } else {
24251 data.pos += 2;
24252 }
24253
24254 if (flags & WE_HAVE_A_TWO_BY_TWO) {
24255 data.pos += 8;
24256 } else if (flags & WE_HAVE_AN_X_AND_Y_SCALE) {
24257 data.pos += 4;
24258 } else if (flags & WE_HAVE_A_SCALE) {
24259 data.pos += 2;
24260 }
24261 }
24262 }
24263 /****************************************************************************************************************/
24264
24265 /* function : CompoundGlypg encode */
24266
24267 /* comment : After creating a table for the characters you typed, you call directory.encode to encode the table.*/
24268
24269 /****************************************************************************************************************/
24270
24271
24272 CompoundGlyph.prototype.encode = function (mapping) {
24273 var i, id, result, _i, _len, _ref;
24274
24275 result = new Data(__slice.call(this.raw.data));
24276 _ref = this.glyphIDs;
24277
24278 for (i = _i = 0, _len = _ref.length; _i < _len; i = ++_i) {
24279 id = _ref[i];
24280 result.pos = this.glyphOffsets[i];
24281 }
24282
24283 return result.data;
24284 };
24285
24286 return CompoundGlyph;
24287 }();
24288
24289 var LocaTable = function (_super) {
24290 __extends(LocaTable, _super);
24291
24292 function LocaTable() {
24293 return LocaTable.__super__.constructor.apply(this, arguments);
24294 }
24295
24296 LocaTable.prototype.tag = 'loca';
24297
24298 LocaTable.prototype.parse = function (data) {
24299 var format, i;
24300 data.pos = this.offset;
24301 format = this.file.head.indexToLocFormat;
24302
24303 if (format === 0) {
24304 return this.offsets = function () {
24305 var _i, _ref, _results;
24306
24307 _results = [];
24308
24309 for (i = _i = 0, _ref = this.length; _i < _ref; i = _i += 2) {
24310 _results.push(data.readUInt16() * 2);
24311 }
24312
24313 return _results;
24314 }.call(this);
24315 } else {
24316 return this.offsets = function () {
24317 var _i, _ref, _results;
24318
24319 _results = [];
24320
24321 for (i = _i = 0, _ref = this.length; _i < _ref; i = _i += 4) {
24322 _results.push(data.readUInt32());
24323 }
24324
24325 return _results;
24326 }.call(this);
24327 }
24328 };
24329
24330 LocaTable.prototype.indexOf = function (id) {
24331 return this.offsets[id];
24332 };
24333
24334 LocaTable.prototype.lengthOf = function (id) {
24335 return this.offsets[id + 1] - this.offsets[id];
24336 };
24337
24338 LocaTable.prototype.encode = function (offsets, activeGlyphs) {
24339 var LocaTable = new Uint32Array(this.offsets.length);
24340 var glyfPtr = 0;
24341 var listGlyf = 0;
24342
24343 for (var k = 0; k < LocaTable.length; ++k) {
24344 LocaTable[k] = glyfPtr;
24345
24346 if (listGlyf < activeGlyphs.length && activeGlyphs[listGlyf] == k) {
24347 ++listGlyf;
24348 LocaTable[k] = glyfPtr;
24349 var start = this.offsets[k];
24350 var len = this.offsets[k + 1] - start;
24351
24352 if (len > 0) {
24353 glyfPtr += len;
24354 }
24355 }
24356 }
24357
24358 var newLocaTable = new Array(LocaTable.length * 4);
24359
24360 for (var j = 0; j < LocaTable.length; ++j) {
24361 newLocaTable[4 * j + 3] = LocaTable[j] & 0x000000ff;
24362 newLocaTable[4 * j + 2] = (LocaTable[j] & 0x0000ff00) >> 8;
24363 newLocaTable[4 * j + 1] = (LocaTable[j] & 0x00ff0000) >> 16;
24364 newLocaTable[4 * j] = (LocaTable[j] & 0xff000000) >> 24;
24365 }
24366
24367 return newLocaTable;
24368 };
24369
24370 return LocaTable;
24371 }(Table);
24372 /************************************************************************************/
24373
24374 /* function : invert */
24375
24376 /* comment : Change the object's (key: value) to create an object with (value: key).*/
24377
24378 /************************************************************************************/
24379
24380
24381 var invert = function invert(object) {
24382 var key, ret, val;
24383 ret = {};
24384
24385 for (key in object) {
24386 val = object[key];
24387 ret[val] = key;
24388 }
24389
24390 return ret;
24391 };
24392 /*var successorOf = function (input) {
24393 var added, alphabet, carry, i, index, isUpperCase, last, length, next, result;
24394 alphabet = 'abcdefghijklmnopqrstuvwxyz';
24395 length = alphabet.length;
24396 result = input;
24397 i = input.length;
24398 while (i >= 0) {
24399 last = input.charAt(--i);
24400 if (isNaN(last)) {
24401 index = alphabet.indexOf(last.toLowerCase());
24402 if (index === -1) {
24403 next = last;
24404 carry = true;
24405 }
24406 else {
24407 next = alphabet.charAt((index + 1) % length);
24408 isUpperCase = last === last.toUpperCase();
24409 if (isUpperCase) {
24410 next = next.toUpperCase();
24411 }
24412 carry = index + 1 >= length;
24413 if (carry && i === 0) {
24414 added = isUpperCase ? 'A' : 'a';
24415 result = added + next + result.slice(1);
24416 break;
24417 }
24418 }
24419 }
24420 else {
24421 next = +last + 1;
24422 carry = next > 9;
24423 if (carry) {
24424 next = 0;
24425 }
24426 if (carry && i === 0) {
24427 result = '1' + next + result.slice(1);
24428 break;
24429 }
24430 }
24431 result = result.slice(0, i) + next + result.slice(i + 1);
24432 if (!carry) {
24433 break;
24434 }
24435 }
24436 return result;
24437 };*/
24438
24439
24440 var Subset = function () {
24441 function Subset(font) {
24442 this.font = font;
24443 this.subset = {};
24444 this.unicodes = {};
24445 this.next = 33;
24446 }
24447 /*Subset.prototype.use = function (character) {
24448 var i, _i, _ref;
24449 if (typeof character === 'string') {
24450 for (i = _i = 0, _ref = character.length; 0 <= _ref ? _i < _ref : _i > _ref; i = 0 <= _ref ? ++_i : --_i) {
24451 this.use(character.charCodeAt(i));
24452 }
24453 return;
24454 }
24455 if (!this.unicodes[character]) {
24456 this.subset[this.next] = character;
24457 return this.unicodes[character] = this.next++;
24458 }
24459 };*/
24460
24461 /*Subset.prototype.encodeText = function (text) {
24462 var char, i, string, _i, _ref;
24463 string = '';
24464 for (i = _i = 0, _ref = text.length; 0 <= _ref ? _i < _ref : _i > _ref; i = 0 <= _ref ? ++_i : --_i) {
24465 char = this.unicodes[text.charCodeAt(i)];
24466 string += String.fromCharCode(char);
24467 }
24468 return string;
24469 };*/
24470
24471 /***************************************************************/
24472
24473 /* function : generateCmap */
24474
24475 /* comment : Returns the unicode cmap for this font. */
24476
24477 /***************************************************************/
24478
24479
24480 Subset.prototype.generateCmap = function () {
24481 var mapping, roman, unicode, unicodeCmap, _ref;
24482
24483 unicodeCmap = this.font.cmap.tables[0].codeMap;
24484 mapping = {};
24485 _ref = this.subset;
24486
24487 for (roman in _ref) {
24488 unicode = _ref[roman];
24489 mapping[roman] = unicodeCmap[unicode];
24490 }
24491
24492 return mapping;
24493 };
24494 /*Subset.prototype.glyphIDs = function () {
24495 var ret, roman, unicode, unicodeCmap, val, _ref;
24496 unicodeCmap = this.font.cmap.tables[0].codeMap;
24497 ret = [0];
24498 _ref = this.subset;
24499 for (roman in _ref) {
24500 unicode = _ref[roman];
24501 val = unicodeCmap[unicode];
24502 if ((val != null) && __indexOf.call(ret, val) < 0) {
24503 ret.push(val);
24504 }
24505 }
24506 return ret.sort();
24507 };*/
24508
24509 /******************************************************************/
24510
24511 /* function : glyphsFor */
24512
24513 /* comment : Returns simple glyph objects for the input character.*/
24514
24515 /******************************************************************/
24516
24517
24518 Subset.prototype.glyphsFor = function (glyphIDs) {
24519 var additionalIDs, glyph, glyphs, id, _i, _len, _ref;
24520
24521 glyphs = {};
24522
24523 for (_i = 0, _len = glyphIDs.length; _i < _len; _i++) {
24524 id = glyphIDs[_i];
24525 glyphs[id] = this.font.glyf.glyphFor(id);
24526 }
24527
24528 additionalIDs = [];
24529
24530 for (id in glyphs) {
24531 glyph = glyphs[id];
24532
24533 if (glyph != null ? glyph.compound : void 0) {
24534 additionalIDs.push.apply(additionalIDs, glyph.glyphIDs);
24535 }
24536 }
24537
24538 if (additionalIDs.length > 0) {
24539 _ref = this.glyphsFor(additionalIDs);
24540
24541 for (id in _ref) {
24542 glyph = _ref[id];
24543 glyphs[id] = glyph;
24544 }
24545 }
24546
24547 return glyphs;
24548 };
24549 /***************************************************************/
24550
24551 /* function : encode */
24552
24553 /* comment : Encode various tables for the characters you use. */
24554
24555 /***************************************************************/
24556
24557
24558 Subset.prototype.encode = function (glyID, indexToLocFormat) {
24559 var cmap, code, glyf, glyphs, id, ids, loca, new2old, newIDs, nextGlyphID, old2new, oldID, oldIDs, tables, _ref;
24560
24561 cmap = CmapTable.encode(this.generateCmap(), 'unicode');
24562 glyphs = this.glyphsFor(glyID);
24563 old2new = {
24564 0: 0
24565 };
24566 _ref = cmap.charMap;
24567
24568 for (code in _ref) {
24569 ids = _ref[code];
24570 old2new[ids.old] = ids["new"];
24571 }
24572
24573 nextGlyphID = cmap.maxGlyphID;
24574
24575 for (oldID in glyphs) {
24576 if (!(oldID in old2new)) {
24577 old2new[oldID] = nextGlyphID++;
24578 }
24579 }
24580
24581 new2old = invert(old2new);
24582 newIDs = Object.keys(new2old).sort(function (a, b) {
24583 return a - b;
24584 });
24585
24586 oldIDs = function () {
24587 var _i, _len, _results;
24588
24589 _results = [];
24590
24591 for (_i = 0, _len = newIDs.length; _i < _len; _i++) {
24592 id = newIDs[_i];
24593
24594 _results.push(new2old[id]);
24595 }
24596
24597 return _results;
24598 }();
24599
24600 glyf = this.font.glyf.encode(glyphs, oldIDs, old2new);
24601 loca = this.font.loca.encode(glyf.offsets, oldIDs);
24602 tables = {
24603 cmap: this.font.cmap.raw(),
24604 glyf: glyf.table,
24605 loca: loca,
24606 hmtx: this.font.hmtx.raw(),
24607 hhea: this.font.hhea.raw(),
24608 maxp: this.font.maxp.raw(),
24609 post: this.font.post.raw(),
24610 name: this.font.name.raw(),
24611 head: this.font.head.encode(indexToLocFormat)
24612 };
24613
24614 if (this.font.os2.exists) {
24615 tables['OS/2'] = this.font.os2.raw();
24616 }
24617
24618 return this.font.directory.encode(tables);
24619 };
24620
24621 return Subset;
24622 }();
24623
24624 jsPDF.API.PDFObject = function () {
24625 var pad;
24626
24627 function PDFObject() {}
24628
24629 pad = function pad(str, length) {
24630 return (Array(length + 1).join('0') + str).slice(-length);
24631 };
24632 /*****************************************************************************/
24633
24634 /* function : convert */
24635
24636 /* comment :Converts pdf tag's / FontBBox and array values in / W to strings */
24637
24638 /*****************************************************************************/
24639
24640
24641 PDFObject.convert = function (object) {
24642 var e, items, key, out, val;
24643
24644 if (Array.isArray(object)) {
24645 items = function () {
24646 var _i, _len, _results;
24647
24648 _results = [];
24649
24650 for (_i = 0, _len = object.length; _i < _len; _i++) {
24651 e = object[_i];
24652
24653 _results.push(PDFObject.convert(e));
24654 }
24655
24656 return _results;
24657 }().join(' ');
24658
24659 return '[' + items + ']';
24660 } else if (typeof object === 'string') {
24661 return '/' + object;
24662 } else if (object != null ? object.isString : void 0) {
24663 return '(' + object + ')';
24664 } else if (object instanceof Date) {
24665 return '(D:' + pad(object.getUTCFullYear(), 4) + pad(object.getUTCMonth(), 2) + pad(object.getUTCDate(), 2) + pad(object.getUTCHours(), 2) + pad(object.getUTCMinutes(), 2) + pad(object.getUTCSeconds(), 2) + 'Z)';
24666 } else if ({}.toString.call(object) === '[object Object]') {
24667 out = ['<<'];
24668
24669 for (key in object) {
24670 val = object[key];
24671 out.push('/' + key + ' ' + PDFObject.convert(val));
24672 }
24673
24674 out.push('>>');
24675 return out.join('\n');
24676 } else {
24677 return '' + object;
24678 }
24679 };
24680
24681 return PDFObject;
24682 }();
24683 })(jsPDF);
24684
24685 // Generated by CoffeeScript 1.4.0
24686
24687 /*
24688 # PNG.js
24689 # Copyright (c) 2011 Devon Govett
24690 # MIT LICENSE
24691 #
24692 #
24693 */
24694 (function (global) {
24695 var PNG;
24696
24697 PNG = function () {
24698 var APNG_BLEND_OP_SOURCE, APNG_DISPOSE_OP_BACKGROUND, APNG_DISPOSE_OP_PREVIOUS, makeImage, scratchCanvas, scratchCtx;
24699
24700 PNG.load = function (url, canvas, callback) {
24701 var xhr;
24702
24703 if (typeof canvas === 'function') {
24704 callback = canvas;
24705 }
24706
24707 xhr = new XMLHttpRequest();
24708 xhr.open("GET", url, true);
24709 xhr.responseType = "arraybuffer";
24710
24711 xhr.onload = function () {
24712 var data, png;
24713 data = new Uint8Array(xhr.response || xhr.mozResponseArrayBuffer);
24714 png = new PNG(data);
24715
24716 if (typeof (canvas != null ? canvas.getContext : void 0) === 'function') {
24717 png.render(canvas);
24718 }
24719
24720 return typeof callback === "function" ? callback(png) : void 0;
24721 };
24722
24723 return xhr.send(null);
24724 };
24725 APNG_DISPOSE_OP_BACKGROUND = 1;
24726 APNG_DISPOSE_OP_PREVIOUS = 2;
24727 APNG_BLEND_OP_SOURCE = 0;
24728
24729 function PNG(data) {
24730 var chunkSize, colors, palLen, delayDen, delayNum, frame, i, index, key, section, palShort, text, _i, _j, _ref;
24731
24732 this.data = data;
24733 this.pos = 8;
24734 this.palette = [];
24735 this.imgData = [];
24736 this.transparency = {};
24737 this.animation = null;
24738 this.text = {};
24739 frame = null;
24740
24741 while (true) {
24742 chunkSize = this.readUInt32();
24743
24744 section = function () {
24745 var _i, _results;
24746
24747 _results = [];
24748
24749 for (i = _i = 0; _i < 4; i = ++_i) {
24750 _results.push(String.fromCharCode(this.data[this.pos++]));
24751 }
24752
24753 return _results;
24754 }.call(this).join('');
24755
24756 switch (section) {
24757 case 'IHDR':
24758 this.width = this.readUInt32();
24759 this.height = this.readUInt32();
24760 this.bits = this.data[this.pos++];
24761 this.colorType = this.data[this.pos++];
24762 this.compressionMethod = this.data[this.pos++];
24763 this.filterMethod = this.data[this.pos++];
24764 this.interlaceMethod = this.data[this.pos++];
24765 break;
24766
24767 case 'acTL':
24768 this.animation = {
24769 numFrames: this.readUInt32(),
24770 numPlays: this.readUInt32() || Infinity,
24771 frames: []
24772 };
24773 break;
24774
24775 case 'PLTE':
24776 this.palette = this.read(chunkSize);
24777 break;
24778
24779 case 'fcTL':
24780 if (frame) {
24781 this.animation.frames.push(frame);
24782 }
24783
24784 this.pos += 4;
24785 frame = {
24786 width: this.readUInt32(),
24787 height: this.readUInt32(),
24788 xOffset: this.readUInt32(),
24789 yOffset: this.readUInt32()
24790 };
24791 delayNum = this.readUInt16();
24792 delayDen = this.readUInt16() || 100;
24793 frame.delay = 1000 * delayNum / delayDen;
24794 frame.disposeOp = this.data[this.pos++];
24795 frame.blendOp = this.data[this.pos++];
24796 frame.data = [];
24797 break;
24798
24799 case 'IDAT':
24800 case 'fdAT':
24801 if (section === 'fdAT') {
24802 this.pos += 4;
24803 chunkSize -= 4;
24804 }
24805
24806 data = (frame != null ? frame.data : void 0) || this.imgData;
24807
24808 for (i = _i = 0; 0 <= chunkSize ? _i < chunkSize : _i > chunkSize; i = 0 <= chunkSize ? ++_i : --_i) {
24809 data.push(this.data[this.pos++]);
24810 }
24811
24812 break;
24813
24814 case 'tRNS':
24815 this.transparency = {};
24816
24817 switch (this.colorType) {
24818 case 3:
24819 palLen = this.palette.length / 3;
24820 this.transparency.indexed = this.read(chunkSize);
24821 if (this.transparency.indexed.length > palLen) throw new Error('More transparent colors than palette size');
24822 /*
24823 * According to the PNG spec trns should be increased to the same size as palette if shorter
24824 */
24825 //palShort = 255 - this.transparency.indexed.length;
24826
24827 palShort = palLen - this.transparency.indexed.length;
24828
24829 if (palShort > 0) {
24830 for (i = _j = 0; 0 <= palShort ? _j < palShort : _j > palShort; i = 0 <= palShort ? ++_j : --_j) {
24831 this.transparency.indexed.push(255);
24832 }
24833 }
24834
24835 break;
24836
24837 case 0:
24838 this.transparency.grayscale = this.read(chunkSize)[0];
24839 break;
24840
24841 case 2:
24842 this.transparency.rgb = this.read(chunkSize);
24843 }
24844
24845 break;
24846
24847 case 'tEXt':
24848 text = this.read(chunkSize);
24849 index = text.indexOf(0);
24850 key = String.fromCharCode.apply(String, text.slice(0, index));
24851 this.text[key] = String.fromCharCode.apply(String, text.slice(index + 1));
24852 break;
24853
24854 case 'IEND':
24855 if (frame) {
24856 this.animation.frames.push(frame);
24857 }
24858
24859 this.colors = function () {
24860 switch (this.colorType) {
24861 case 0:
24862 case 3:
24863 case 4:
24864 return 1;
24865
24866 case 2:
24867 case 6:
24868 return 3;
24869 }
24870 }.call(this);
24871
24872 this.hasAlphaChannel = (_ref = this.colorType) === 4 || _ref === 6;
24873 colors = this.colors + (this.hasAlphaChannel ? 1 : 0);
24874 this.pixelBitlength = this.bits * colors;
24875
24876 this.colorSpace = function () {
24877 switch (this.colors) {
24878 case 1:
24879 return 'DeviceGray';
24880
24881 case 3:
24882 return 'DeviceRGB';
24883 }
24884 }.call(this);
24885
24886 this.imgData = new Uint8Array(this.imgData);
24887 return;
24888
24889 default:
24890 this.pos += chunkSize;
24891 }
24892
24893 this.pos += 4;
24894
24895 if (this.pos > this.data.length) {
24896 throw new Error("Incomplete or corrupt PNG file");
24897 }
24898 }
24899
24900 return;
24901 }
24902
24903 PNG.prototype.read = function (bytes) {
24904 var i, _i, _results;
24905
24906 _results = [];
24907
24908 for (i = _i = 0; 0 <= bytes ? _i < bytes : _i > bytes; i = 0 <= bytes ? ++_i : --_i) {
24909 _results.push(this.data[this.pos++]);
24910 }
24911
24912 return _results;
24913 };
24914
24915 PNG.prototype.readUInt32 = function () {
24916 var b1, b2, b3, b4;
24917 b1 = this.data[this.pos++] << 24;
24918 b2 = this.data[this.pos++] << 16;
24919 b3 = this.data[this.pos++] << 8;
24920 b4 = this.data[this.pos++];
24921 return b1 | b2 | b3 | b4;
24922 };
24923
24924 PNG.prototype.readUInt16 = function () {
24925 var b1, b2;
24926 b1 = this.data[this.pos++] << 8;
24927 b2 = this.data[this.pos++];
24928 return b1 | b2;
24929 };
24930
24931 PNG.prototype.decodePixels = function (data) {
24932 var pixelBytes = this.pixelBitlength / 8;
24933 var fullPixels = new Uint8Array(this.width * this.height * pixelBytes);
24934 var pos = 0;
24935
24936 var _this = this;
24937
24938 if (data == null) {
24939 data = this.imgData;
24940 }
24941
24942 if (data.length === 0) {
24943 return new Uint8Array(0);
24944 }
24945
24946 data = new FlateStream(data);
24947 data = data.getBytes();
24948
24949 function pass(x0, y0, dx, dy) {
24950 var abyte, c, col, i, left, length, p, pa, paeth, pb, pc, pixels, row, scanlineLength, upper, upperLeft, _i, _j, _k, _l, _m;
24951
24952 var w = Math.ceil((_this.width - x0) / dx),
24953 h = Math.ceil((_this.height - y0) / dy);
24954 var isFull = _this.width == w && _this.height == h;
24955 scanlineLength = pixelBytes * w;
24956 pixels = isFull ? fullPixels : new Uint8Array(scanlineLength * h);
24957 length = data.length;
24958 row = 0;
24959 c = 0;
24960
24961 while (row < h && pos < length) {
24962 switch (data[pos++]) {
24963 case 0:
24964 for (i = _i = 0; _i < scanlineLength; i = _i += 1) {
24965 pixels[c++] = data[pos++];
24966 }
24967
24968 break;
24969
24970 case 1:
24971 for (i = _j = 0; _j < scanlineLength; i = _j += 1) {
24972 abyte = data[pos++];
24973 left = i < pixelBytes ? 0 : pixels[c - pixelBytes];
24974 pixels[c++] = (abyte + left) % 256;
24975 }
24976
24977 break;
24978
24979 case 2:
24980 for (i = _k = 0; _k < scanlineLength; i = _k += 1) {
24981 abyte = data[pos++];
24982 col = (i - i % pixelBytes) / pixelBytes;
24983 upper = row && pixels[(row - 1) * scanlineLength + col * pixelBytes + i % pixelBytes];
24984 pixels[c++] = (upper + abyte) % 256;
24985 }
24986
24987 break;
24988
24989 case 3:
24990 for (i = _l = 0; _l < scanlineLength; i = _l += 1) {
24991 abyte = data[pos++];
24992 col = (i - i % pixelBytes) / pixelBytes;
24993 left = i < pixelBytes ? 0 : pixels[c - pixelBytes];
24994 upper = row && pixels[(row - 1) * scanlineLength + col * pixelBytes + i % pixelBytes];
24995 pixels[c++] = (abyte + Math.floor((left + upper) / 2)) % 256;
24996 }
24997
24998 break;
24999
25000 case 4:
25001 for (i = _m = 0; _m < scanlineLength; i = _m += 1) {
25002 abyte = data[pos++];
25003 col = (i - i % pixelBytes) / pixelBytes;
25004 left = i < pixelBytes ? 0 : pixels[c - pixelBytes];
25005
25006 if (row === 0) {
25007 upper = upperLeft = 0;
25008 } else {
25009 upper = pixels[(row - 1) * scanlineLength + col * pixelBytes + i % pixelBytes];
25010 upperLeft = col && pixels[(row - 1) * scanlineLength + (col - 1) * pixelBytes + i % pixelBytes];
25011 }
25012
25013 p = left + upper - upperLeft;
25014 pa = Math.abs(p - left);
25015 pb = Math.abs(p - upper);
25016 pc = Math.abs(p - upperLeft);
25017
25018 if (pa <= pb && pa <= pc) {
25019 paeth = left;
25020 } else if (pb <= pc) {
25021 paeth = upper;
25022 } else {
25023 paeth = upperLeft;
25024 }
25025
25026 pixels[c++] = (abyte + paeth) % 256;
25027 }
25028
25029 break;
25030
25031 default:
25032 throw new Error("Invalid filter algorithm: " + data[pos - 1]);
25033 }
25034
25035 if (!isFull) {
25036 var fullPos = ((y0 + row * dy) * _this.width + x0) * pixelBytes;
25037 var partPos = row * scanlineLength;
25038
25039 for (i = 0; i < w; i += 1) {
25040 for (var j = 0; j < pixelBytes; j += 1) {
25041 fullPixels[fullPos++] = pixels[partPos++];
25042 }
25043
25044 fullPos += (dx - 1) * pixelBytes;
25045 }
25046 }
25047
25048 row++;
25049 }
25050 }
25051
25052 if (_this.interlaceMethod == 1) {
25053 /*
25054 1 6 4 6 2 6 4 6
25055 7 7 7 7 7 7 7 7
25056 5 6 5 6 5 6 5 6
25057 7 7 7 7 7 7 7 7
25058 3 6 4 6 3 6 4 6
25059 7 7 7 7 7 7 7 7
25060 5 6 5 6 5 6 5 6
25061 7 7 7 7 7 7 7 7
25062 */
25063 pass(0, 0, 8, 8); // 1
25064
25065 /* NOTE these seem to follow the pattern:
25066 * pass(x, 0, 2*x, 2*x);
25067 * pass(0, x, x, 2*x);
25068 * with x being 4, 2, 1.
25069 */
25070
25071 pass(4, 0, 8, 8); // 2
25072
25073 pass(0, 4, 4, 8); // 3
25074
25075 pass(2, 0, 4, 4); // 4
25076
25077 pass(0, 2, 2, 4); // 5
25078
25079 pass(1, 0, 2, 2); // 6
25080
25081 pass(0, 1, 1, 2); // 7
25082 } else {
25083 pass(0, 0, 1, 1);
25084 }
25085
25086 return fullPixels;
25087 };
25088
25089 PNG.prototype.decodePalette = function () {
25090 var c, i, length, palette, pos, ret, transparency, _i, _ref, _ref1;
25091
25092 palette = this.palette;
25093 transparency = this.transparency.indexed || [];
25094 ret = new Uint8Array((transparency.length || 0) + palette.length);
25095 pos = 0;
25096 length = palette.length;
25097 c = 0;
25098
25099 for (i = _i = 0, _ref = palette.length; _i < _ref; i = _i += 3) {
25100 ret[pos++] = palette[i];
25101 ret[pos++] = palette[i + 1];
25102 ret[pos++] = palette[i + 2];
25103 ret[pos++] = (_ref1 = transparency[c++]) != null ? _ref1 : 255;
25104 }
25105
25106 return ret;
25107 };
25108
25109 PNG.prototype.copyToImageData = function (imageData, pixels) {
25110 var alpha, colors, data, i, input, j, k, length, palette, v, _ref;
25111
25112 colors = this.colors;
25113 palette = null;
25114 alpha = this.hasAlphaChannel;
25115
25116 if (this.palette.length) {
25117 palette = (_ref = this._decodedPalette) != null ? _ref : this._decodedPalette = this.decodePalette();
25118 colors = 4;
25119 alpha = true;
25120 }
25121
25122 data = imageData.data || imageData;
25123 length = data.length;
25124 input = palette || pixels;
25125 i = j = 0;
25126
25127 if (colors === 1) {
25128 while (i < length) {
25129 k = palette ? pixels[i / 4] * 4 : j;
25130 v = input[k++];
25131 data[i++] = v;
25132 data[i++] = v;
25133 data[i++] = v;
25134 data[i++] = alpha ? input[k++] : 255;
25135 j = k;
25136 }
25137 } else {
25138 while (i < length) {
25139 k = palette ? pixels[i / 4] * 4 : j;
25140 data[i++] = input[k++];
25141 data[i++] = input[k++];
25142 data[i++] = input[k++];
25143 data[i++] = alpha ? input[k++] : 255;
25144 j = k;
25145 }
25146 }
25147 };
25148
25149 PNG.prototype.decode = function () {
25150 var ret;
25151 ret = new Uint8Array(this.width * this.height * 4);
25152 this.copyToImageData(ret, this.decodePixels());
25153 return ret;
25154 };
25155
25156 try {
25157 scratchCanvas = global.document.createElement('canvas');
25158 scratchCtx = scratchCanvas.getContext('2d');
25159 } catch (e) {
25160 return -1;
25161 }
25162
25163 makeImage = function makeImage(imageData) {
25164 var img;
25165 scratchCtx.width = imageData.width;
25166 scratchCtx.height = imageData.height;
25167 scratchCtx.clearRect(0, 0, imageData.width, imageData.height);
25168 scratchCtx.putImageData(imageData, 0, 0);
25169 img = new Image();
25170 img.src = scratchCanvas.toDataURL();
25171 return img;
25172 };
25173
25174 PNG.prototype.decodeFrames = function (ctx) {
25175 var frame, i, imageData, pixels, _i, _len, _ref, _results;
25176
25177 if (!this.animation) {
25178 return;
25179 }
25180
25181 _ref = this.animation.frames;
25182 _results = [];
25183
25184 for (i = _i = 0, _len = _ref.length; _i < _len; i = ++_i) {
25185 frame = _ref[i];
25186 imageData = ctx.createImageData(frame.width, frame.height);
25187 pixels = this.decodePixels(new Uint8Array(frame.data));
25188 this.copyToImageData(imageData, pixels);
25189 frame.imageData = imageData;
25190
25191 _results.push(frame.image = makeImage(imageData));
25192 }
25193
25194 return _results;
25195 };
25196
25197 PNG.prototype.renderFrame = function (ctx, number) {
25198 var frame, frames, prev;
25199 frames = this.animation.frames;
25200 frame = frames[number];
25201 prev = frames[number - 1];
25202
25203 if (number === 0) {
25204 ctx.clearRect(0, 0, this.width, this.height);
25205 }
25206
25207 if ((prev != null ? prev.disposeOp : void 0) === APNG_DISPOSE_OP_BACKGROUND) {
25208 ctx.clearRect(prev.xOffset, prev.yOffset, prev.width, prev.height);
25209 } else if ((prev != null ? prev.disposeOp : void 0) === APNG_DISPOSE_OP_PREVIOUS) {
25210 ctx.putImageData(prev.imageData, prev.xOffset, prev.yOffset);
25211 }
25212
25213 if (frame.blendOp === APNG_BLEND_OP_SOURCE) {
25214 ctx.clearRect(frame.xOffset, frame.yOffset, frame.width, frame.height);
25215 }
25216
25217 return ctx.drawImage(frame.image, frame.xOffset, frame.yOffset);
25218 };
25219
25220 PNG.prototype.animate = function (ctx) {
25221 var _doFrame,
25222 frameNumber,
25223 frames,
25224 numFrames,
25225 numPlays,
25226 _ref,
25227 _this = this;
25228
25229 frameNumber = 0;
25230 _ref = this.animation, numFrames = _ref.numFrames, frames = _ref.frames, numPlays = _ref.numPlays;
25231 return (_doFrame = function doFrame() {
25232 var f, frame;
25233 f = frameNumber++ % numFrames;
25234 frame = frames[f];
25235
25236 _this.renderFrame(ctx, f);
25237
25238 if (numFrames > 1 && frameNumber / numFrames < numPlays) {
25239 return _this.animation._timeout = setTimeout(_doFrame, frame.delay);
25240 }
25241 })();
25242 };
25243
25244 PNG.prototype.stopAnimation = function () {
25245 var _ref;
25246
25247 return clearTimeout((_ref = this.animation) != null ? _ref._timeout : void 0);
25248 };
25249
25250 PNG.prototype.render = function (canvas) {
25251 var ctx, data;
25252
25253 if (canvas._png) {
25254 canvas._png.stopAnimation();
25255 }
25256
25257 canvas._png = this;
25258 canvas.width = this.width;
25259 canvas.height = this.height;
25260 ctx = canvas.getContext("2d");
25261
25262 if (this.animation) {
25263 this.decodeFrames(ctx);
25264 return this.animate(ctx);
25265 } else {
25266 data = ctx.createImageData(this.width, this.height);
25267 this.copyToImageData(data, this.decodePixels());
25268 return ctx.putImageData(data, 0, 0);
25269 }
25270 };
25271
25272 return PNG;
25273 }();
25274
25275 global.PNG = PNG;
25276 })(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
25277 // while `this` is nsIContentFrameMessageManager
25278 // with an attribute `content` that corresponds to the window
25279
25280 /*
25281 * Extracted from pdf.js
25282 * https://github.com/andreasgal/pdf.js
25283 *
25284 * Copyright (c) 2011 Mozilla Foundation
25285 *
25286 * Contributors: Andreas Gal <gal@mozilla.com>
25287 * Chris G Jones <cjones@mozilla.com>
25288 * Shaon Barman <shaon.barman@gmail.com>
25289 * Vivien Nicolas <21@vingtetun.org>
25290 * Justin D'Arcangelo <justindarc@gmail.com>
25291 * Yury Delendik
25292 *
25293 *
25294 */
25295 var DecodeStream = function () {
25296 function constructor() {
25297 this.pos = 0;
25298 this.bufferLength = 0;
25299 this.eof = false;
25300 this.buffer = null;
25301 }
25302
25303 constructor.prototype = {
25304 ensureBuffer: function decodestream_ensureBuffer(requested) {
25305 var buffer = this.buffer;
25306 var current = buffer ? buffer.byteLength : 0;
25307 if (requested < current) return buffer;
25308 var size = 512;
25309
25310 while (size < requested) {
25311 size <<= 1;
25312 }
25313
25314 var buffer2 = new Uint8Array(size);
25315
25316 for (var i = 0; i < current; ++i) {
25317 buffer2[i] = buffer[i];
25318 }
25319
25320 return this.buffer = buffer2;
25321 },
25322 getByte: function decodestream_getByte() {
25323 var pos = this.pos;
25324
25325 while (this.bufferLength <= pos) {
25326 if (this.eof) return null;
25327 this.readBlock();
25328 }
25329
25330 return this.buffer[this.pos++];
25331 },
25332 getBytes: function decodestream_getBytes(length) {
25333 var pos = this.pos;
25334
25335 if (length) {
25336 this.ensureBuffer(pos + length);
25337 var end = pos + length;
25338
25339 while (!this.eof && this.bufferLength < end) {
25340 this.readBlock();
25341 }
25342
25343 var bufEnd = this.bufferLength;
25344 if (end > bufEnd) end = bufEnd;
25345 } else {
25346 while (!this.eof) {
25347 this.readBlock();
25348 }
25349
25350 var end = this.bufferLength;
25351 }
25352
25353 this.pos = end;
25354 return this.buffer.subarray(pos, end);
25355 },
25356 lookChar: function decodestream_lookChar() {
25357 var pos = this.pos;
25358
25359 while (this.bufferLength <= pos) {
25360 if (this.eof) return null;
25361 this.readBlock();
25362 }
25363
25364 return String.fromCharCode(this.buffer[this.pos]);
25365 },
25366 getChar: function decodestream_getChar() {
25367 var pos = this.pos;
25368
25369 while (this.bufferLength <= pos) {
25370 if (this.eof) return null;
25371 this.readBlock();
25372 }
25373
25374 return String.fromCharCode(this.buffer[this.pos++]);
25375 },
25376 makeSubStream: function decodestream_makeSubstream(start, length, dict) {
25377 var end = start + length;
25378
25379 while (this.bufferLength <= end && !this.eof) {
25380 this.readBlock();
25381 }
25382
25383 return new Stream(this.buffer, start, length, dict);
25384 },
25385 skip: function decodestream_skip(n) {
25386 if (!n) n = 1;
25387 this.pos += n;
25388 },
25389 reset: function decodestream_reset() {
25390 this.pos = 0;
25391 }
25392 };
25393 return constructor;
25394 }();
25395
25396 var FlateStream = function () {
25397 if (typeof Uint32Array === 'undefined') {
25398 return undefined;
25399 }
25400
25401 var codeLenCodeMap = new Uint32Array([16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15]);
25402 var lengthDecode = new Uint32Array([0x00003, 0x00004, 0x00005, 0x00006, 0x00007, 0x00008, 0x00009, 0x0000a, 0x1000b, 0x1000d, 0x1000f, 0x10011, 0x20013, 0x20017, 0x2001b, 0x2001f, 0x30023, 0x3002b, 0x30033, 0x3003b, 0x40043, 0x40053, 0x40063, 0x40073, 0x50083, 0x500a3, 0x500c3, 0x500e3, 0x00102, 0x00102, 0x00102]);
25403 var distDecode = new Uint32Array([0x00001, 0x00002, 0x00003, 0x00004, 0x10005, 0x10007, 0x20009, 0x2000d, 0x30011, 0x30019, 0x40021, 0x40031, 0x50041, 0x50061, 0x60081, 0x600c1, 0x70101, 0x70181, 0x80201, 0x80301, 0x90401, 0x90601, 0xa0801, 0xa0c01, 0xb1001, 0xb1801, 0xc2001, 0xc3001, 0xd4001, 0xd6001]);
25404 var fixedLitCodeTab = [new Uint32Array([0x70100, 0x80050, 0x80010, 0x80118, 0x70110, 0x80070, 0x80030, 0x900c0, 0x70108, 0x80060, 0x80020, 0x900a0, 0x80000, 0x80080, 0x80040, 0x900e0, 0x70104, 0x80058, 0x80018, 0x90090, 0x70114, 0x80078, 0x80038, 0x900d0, 0x7010c, 0x80068, 0x80028, 0x900b0, 0x80008, 0x80088, 0x80048, 0x900f0, 0x70102, 0x80054, 0x80014, 0x8011c, 0x70112, 0x80074, 0x80034, 0x900c8, 0x7010a, 0x80064, 0x80024, 0x900a8, 0x80004, 0x80084, 0x80044, 0x900e8, 0x70106, 0x8005c, 0x8001c, 0x90098, 0x70116, 0x8007c, 0x8003c, 0x900d8, 0x7010e, 0x8006c, 0x8002c, 0x900b8, 0x8000c, 0x8008c, 0x8004c, 0x900f8, 0x70101, 0x80052, 0x80012, 0x8011a, 0x70111, 0x80072, 0x80032, 0x900c4, 0x70109, 0x80062, 0x80022, 0x900a4, 0x80002, 0x80082, 0x80042, 0x900e4, 0x70105, 0x8005a, 0x8001a, 0x90094, 0x70115, 0x8007a, 0x8003a, 0x900d4, 0x7010d, 0x8006a, 0x8002a, 0x900b4, 0x8000a, 0x8008a, 0x8004a, 0x900f4, 0x70103, 0x80056, 0x80016, 0x8011e, 0x70113, 0x80076, 0x80036, 0x900cc, 0x7010b, 0x80066, 0x80026, 0x900ac, 0x80006, 0x80086, 0x80046, 0x900ec, 0x70107, 0x8005e, 0x8001e, 0x9009c, 0x70117, 0x8007e, 0x8003e, 0x900dc, 0x7010f, 0x8006e, 0x8002e, 0x900bc, 0x8000e, 0x8008e, 0x8004e, 0x900fc, 0x70100, 0x80051, 0x80011, 0x80119, 0x70110, 0x80071, 0x80031, 0x900c2, 0x70108, 0x80061, 0x80021, 0x900a2, 0x80001, 0x80081, 0x80041, 0x900e2, 0x70104, 0x80059, 0x80019, 0x90092, 0x70114, 0x80079, 0x80039, 0x900d2, 0x7010c, 0x80069, 0x80029, 0x900b2, 0x80009, 0x80089, 0x80049, 0x900f2, 0x70102, 0x80055, 0x80015, 0x8011d, 0x70112, 0x80075, 0x80035, 0x900ca, 0x7010a, 0x80065, 0x80025, 0x900aa, 0x80005, 0x80085, 0x80045, 0x900ea, 0x70106, 0x8005d, 0x8001d, 0x9009a, 0x70116, 0x8007d, 0x8003d, 0x900da, 0x7010e, 0x8006d, 0x8002d, 0x900ba, 0x8000d, 0x8008d, 0x8004d, 0x900fa, 0x70101, 0x80053, 0x80013, 0x8011b, 0x70111, 0x80073, 0x80033, 0x900c6, 0x70109, 0x80063, 0x80023, 0x900a6, 0x80003, 0x80083, 0x80043, 0x900e6, 0x70105, 0x8005b, 0x8001b, 0x90096, 0x70115, 0x8007b, 0x8003b, 0x900d6, 0x7010d, 0x8006b, 0x8002b, 0x900b6, 0x8000b, 0x8008b, 0x8004b, 0x900f6, 0x70103, 0x80057, 0x80017, 0x8011f, 0x70113, 0x80077, 0x80037, 0x900ce, 0x7010b, 0x80067, 0x80027, 0x900ae, 0x80007, 0x80087, 0x80047, 0x900ee, 0x70107, 0x8005f, 0x8001f, 0x9009e, 0x70117, 0x8007f, 0x8003f, 0x900de, 0x7010f, 0x8006f, 0x8002f, 0x900be, 0x8000f, 0x8008f, 0x8004f, 0x900fe, 0x70100, 0x80050, 0x80010, 0x80118, 0x70110, 0x80070, 0x80030, 0x900c1, 0x70108, 0x80060, 0x80020, 0x900a1, 0x80000, 0x80080, 0x80040, 0x900e1, 0x70104, 0x80058, 0x80018, 0x90091, 0x70114, 0x80078, 0x80038, 0x900d1, 0x7010c, 0x80068, 0x80028, 0x900b1, 0x80008, 0x80088, 0x80048, 0x900f1, 0x70102, 0x80054, 0x80014, 0x8011c, 0x70112, 0x80074, 0x80034, 0x900c9, 0x7010a, 0x80064, 0x80024, 0x900a9, 0x80004, 0x80084, 0x80044, 0x900e9, 0x70106, 0x8005c, 0x8001c, 0x90099, 0x70116, 0x8007c, 0x8003c, 0x900d9, 0x7010e, 0x8006c, 0x8002c, 0x900b9, 0x8000c, 0x8008c, 0x8004c, 0x900f9, 0x70101, 0x80052, 0x80012, 0x8011a, 0x70111, 0x80072, 0x80032, 0x900c5, 0x70109, 0x80062, 0x80022, 0x900a5, 0x80002, 0x80082, 0x80042, 0x900e5, 0x70105, 0x8005a, 0x8001a, 0x90095, 0x70115, 0x8007a, 0x8003a, 0x900d5, 0x7010d, 0x8006a, 0x8002a, 0x900b5, 0x8000a, 0x8008a, 0x8004a, 0x900f5, 0x70103, 0x80056, 0x80016, 0x8011e, 0x70113, 0x80076, 0x80036, 0x900cd, 0x7010b, 0x80066, 0x80026, 0x900ad, 0x80006, 0x80086, 0x80046, 0x900ed, 0x70107, 0x8005e, 0x8001e, 0x9009d, 0x70117, 0x8007e, 0x8003e, 0x900dd, 0x7010f, 0x8006e, 0x8002e, 0x900bd, 0x8000e, 0x8008e, 0x8004e, 0x900fd, 0x70100, 0x80051, 0x80011, 0x80119, 0x70110, 0x80071, 0x80031, 0x900c3, 0x70108, 0x80061, 0x80021, 0x900a3, 0x80001, 0x80081, 0x80041, 0x900e3, 0x70104, 0x80059, 0x80019, 0x90093, 0x70114, 0x80079, 0x80039, 0x900d3, 0x7010c, 0x80069, 0x80029, 0x900b3, 0x80009, 0x80089, 0x80049, 0x900f3, 0x70102, 0x80055, 0x80015, 0x8011d, 0x70112, 0x80075, 0x80035, 0x900cb, 0x7010a, 0x80065, 0x80025, 0x900ab, 0x80005, 0x80085, 0x80045, 0x900eb, 0x70106, 0x8005d, 0x8001d, 0x9009b, 0x70116, 0x8007d, 0x8003d, 0x900db, 0x7010e, 0x8006d, 0x8002d, 0x900bb, 0x8000d, 0x8008d, 0x8004d, 0x900fb, 0x70101, 0x80053, 0x80013, 0x8011b, 0x70111, 0x80073, 0x80033, 0x900c7, 0x70109, 0x80063, 0x80023, 0x900a7, 0x80003, 0x80083, 0x80043, 0x900e7, 0x70105, 0x8005b, 0x8001b, 0x90097, 0x70115, 0x8007b, 0x8003b, 0x900d7, 0x7010d, 0x8006b, 0x8002b, 0x900b7, 0x8000b, 0x8008b, 0x8004b, 0x900f7, 0x70103, 0x80057, 0x80017, 0x8011f, 0x70113, 0x80077, 0x80037, 0x900cf, 0x7010b, 0x80067, 0x80027, 0x900af, 0x80007, 0x80087, 0x80047, 0x900ef, 0x70107, 0x8005f, 0x8001f, 0x9009f, 0x70117, 0x8007f, 0x8003f, 0x900df, 0x7010f, 0x8006f, 0x8002f, 0x900bf, 0x8000f, 0x8008f, 0x8004f, 0x900ff]), 9];
25405 var fixedDistCodeTab = [new Uint32Array([0x50000, 0x50010, 0x50008, 0x50018, 0x50004, 0x50014, 0x5000c, 0x5001c, 0x50002, 0x50012, 0x5000a, 0x5001a, 0x50006, 0x50016, 0x5000e, 0x00000, 0x50001, 0x50011, 0x50009, 0x50019, 0x50005, 0x50015, 0x5000d, 0x5001d, 0x50003, 0x50013, 0x5000b, 0x5001b, 0x50007, 0x50017, 0x5000f, 0x00000]), 5];
25406
25407 function error(e) {
25408 throw new Error(e);
25409 }
25410
25411 function constructor(bytes) {
25412 //var bytes = stream.getBytes();
25413 var bytesPos = 0;
25414 var cmf = bytes[bytesPos++];
25415 var flg = bytes[bytesPos++];
25416 if (cmf == -1 || flg == -1) error('Invalid header in flate stream');
25417 if ((cmf & 0x0f) != 0x08) error('Unknown compression method in flate stream');
25418 if (((cmf << 8) + flg) % 31 != 0) error('Bad FCHECK in flate stream');
25419 if (flg & 0x20) error('FDICT bit set in flate stream');
25420 this.bytes = bytes;
25421 this.bytesPos = bytesPos;
25422 this.codeSize = 0;
25423 this.codeBuf = 0;
25424 DecodeStream.call(this);
25425 }
25426
25427 constructor.prototype = Object.create(DecodeStream.prototype);
25428
25429 constructor.prototype.getBits = function (bits) {
25430 var codeSize = this.codeSize;
25431 var codeBuf = this.codeBuf;
25432 var bytes = this.bytes;
25433 var bytesPos = this.bytesPos;
25434 var b;
25435
25436 while (codeSize < bits) {
25437 if (typeof (b = bytes[bytesPos++]) == 'undefined') error('Bad encoding in flate stream');
25438 codeBuf |= b << codeSize;
25439 codeSize += 8;
25440 }
25441
25442 b = codeBuf & (1 << bits) - 1;
25443 this.codeBuf = codeBuf >> bits;
25444 this.codeSize = codeSize -= bits;
25445 this.bytesPos = bytesPos;
25446 return b;
25447 };
25448
25449 constructor.prototype.getCode = function (table) {
25450 var codes = table[0];
25451 var maxLen = table[1];
25452 var codeSize = this.codeSize;
25453 var codeBuf = this.codeBuf;
25454 var bytes = this.bytes;
25455 var bytesPos = this.bytesPos;
25456
25457 while (codeSize < maxLen) {
25458 var b;
25459 if (typeof (b = bytes[bytesPos++]) == 'undefined') error('Bad encoding in flate stream');
25460 codeBuf |= b << codeSize;
25461 codeSize += 8;
25462 }
25463
25464 var code = codes[codeBuf & (1 << maxLen) - 1];
25465 var codeLen = code >> 16;
25466 var codeVal = code & 0xffff;
25467 if (codeSize == 0 || codeSize < codeLen || codeLen == 0) error('Bad encoding in flate stream');
25468 this.codeBuf = codeBuf >> codeLen;
25469 this.codeSize = codeSize - codeLen;
25470 this.bytesPos = bytesPos;
25471 return codeVal;
25472 };
25473
25474 constructor.prototype.generateHuffmanTable = function (lengths) {
25475 var n = lengths.length; // find max code length
25476
25477 var maxLen = 0;
25478
25479 for (var i = 0; i < n; ++i) {
25480 if (lengths[i] > maxLen) maxLen = lengths[i];
25481 } // build the table
25482
25483
25484 var size = 1 << maxLen;
25485 var codes = new Uint32Array(size);
25486
25487 for (var len = 1, code = 0, skip = 2; len <= maxLen; ++len, code <<= 1, skip <<= 1) {
25488 for (var val = 0; val < n; ++val) {
25489 if (lengths[val] == len) {
25490 // bit-reverse the code
25491 var code2 = 0;
25492 var t = code;
25493
25494 for (var i = 0; i < len; ++i) {
25495 code2 = code2 << 1 | t & 1;
25496 t >>= 1;
25497 } // fill the table entries
25498
25499
25500 for (var i = code2; i < size; i += skip) {
25501 codes[i] = len << 16 | val;
25502 }
25503
25504 ++code;
25505 }
25506 }
25507 }
25508
25509 return [codes, maxLen];
25510 };
25511
25512 constructor.prototype.readBlock = function () {
25513 function repeat(stream, array, len, offset, what) {
25514 var repeat = stream.getBits(len) + offset;
25515
25516 while (repeat-- > 0) {
25517 array[i++] = what;
25518 }
25519 } // read block header
25520
25521
25522 var hdr = this.getBits(3);
25523 if (hdr & 1) this.eof = true;
25524 hdr >>= 1;
25525
25526 if (hdr == 0) {
25527 // uncompressed block
25528 var bytes = this.bytes;
25529 var bytesPos = this.bytesPos;
25530 var b;
25531 if (typeof (b = bytes[bytesPos++]) == 'undefined') error('Bad block header in flate stream');
25532 var blockLen = b;
25533 if (typeof (b = bytes[bytesPos++]) == 'undefined') error('Bad block header in flate stream');
25534 blockLen |= b << 8;
25535 if (typeof (b = bytes[bytesPos++]) == 'undefined') error('Bad block header in flate stream');
25536 var check = b;
25537 if (typeof (b = bytes[bytesPos++]) == 'undefined') error('Bad block header in flate stream');
25538 check |= b << 8;
25539 if (check != (~blockLen & 0xffff)) error('Bad uncompressed block length in flate stream');
25540 this.codeBuf = 0;
25541 this.codeSize = 0;
25542 var bufferLength = this.bufferLength;
25543 var buffer = this.ensureBuffer(bufferLength + blockLen);
25544 var end = bufferLength + blockLen;
25545 this.bufferLength = end;
25546
25547 for (var n = bufferLength; n < end; ++n) {
25548 if (typeof (b = bytes[bytesPos++]) == 'undefined') {
25549 this.eof = true;
25550 break;
25551 }
25552
25553 buffer[n] = b;
25554 }
25555
25556 this.bytesPos = bytesPos;
25557 return;
25558 }
25559
25560 var litCodeTable;
25561 var distCodeTable;
25562
25563 if (hdr == 1) {
25564 // compressed block, fixed codes
25565 litCodeTable = fixedLitCodeTab;
25566 distCodeTable = fixedDistCodeTab;
25567 } else if (hdr == 2) {
25568 // compressed block, dynamic codes
25569 var numLitCodes = this.getBits(5) + 257;
25570 var numDistCodes = this.getBits(5) + 1;
25571 var numCodeLenCodes = this.getBits(4) + 4; // build the code lengths code table
25572
25573 var codeLenCodeLengths = Array(codeLenCodeMap.length);
25574 var i = 0;
25575
25576 while (i < numCodeLenCodes) {
25577 codeLenCodeLengths[codeLenCodeMap[i++]] = this.getBits(3);
25578 }
25579
25580 var codeLenCodeTab = this.generateHuffmanTable(codeLenCodeLengths); // build the literal and distance code tables
25581
25582 var len = 0;
25583 var i = 0;
25584 var codes = numLitCodes + numDistCodes;
25585 var codeLengths = new Array(codes);
25586
25587 while (i < codes) {
25588 var code = this.getCode(codeLenCodeTab);
25589
25590 if (code == 16) {
25591 repeat(this, codeLengths, 2, 3, len);
25592 } else if (code == 17) {
25593 repeat(this, codeLengths, 3, 3, len = 0);
25594 } else if (code == 18) {
25595 repeat(this, codeLengths, 7, 11, len = 0);
25596 } else {
25597 codeLengths[i++] = len = code;
25598 }
25599 }
25600
25601 litCodeTable = this.generateHuffmanTable(codeLengths.slice(0, numLitCodes));
25602 distCodeTable = this.generateHuffmanTable(codeLengths.slice(numLitCodes, codes));
25603 } else {
25604 error('Unknown block type in flate stream');
25605 }
25606
25607 var buffer = this.buffer;
25608 var limit = buffer ? buffer.length : 0;
25609 var pos = this.bufferLength;
25610
25611 while (true) {
25612 var code1 = this.getCode(litCodeTable);
25613
25614 if (code1 < 256) {
25615 if (pos + 1 >= limit) {
25616 buffer = this.ensureBuffer(pos + 1);
25617 limit = buffer.length;
25618 }
25619
25620 buffer[pos++] = code1;
25621 continue;
25622 }
25623
25624 if (code1 == 256) {
25625 this.bufferLength = pos;
25626 return;
25627 }
25628
25629 code1 -= 257;
25630 code1 = lengthDecode[code1];
25631 var code2 = code1 >> 16;
25632 if (code2 > 0) code2 = this.getBits(code2);
25633 var len = (code1 & 0xffff) + code2;
25634 code1 = this.getCode(distCodeTable);
25635 code1 = distDecode[code1];
25636 code2 = code1 >> 16;
25637 if (code2 > 0) code2 = this.getBits(code2);
25638 var dist = (code1 & 0xffff) + code2;
25639
25640 if (pos + len >= limit) {
25641 buffer = this.ensureBuffer(pos + len);
25642 limit = buffer.length;
25643 }
25644
25645 for (var k = 0; k < len; ++k, ++pos) {
25646 buffer[pos] = buffer[pos - dist];
25647 }
25648 }
25649 };
25650
25651 return constructor;
25652 }();
25653 /*rollup-keeper-start*/
25654
25655
25656 window.tmp = FlateStream;
25657 /*rollup-keeper-end*/
25658
25659 }));
25660
25661 try {
25662 module.exports = jsPDF;
25663 }
25664 catch (e) {}
25665