· 7 years ago · Mar 01, 2019, 01:00 AM
1/** @preserve
2 * jsPDF - PDF Document creation from JavaScript
3 * Version 1.0.272-git Built on 2014-09-29T15:09
4 * CommitID d4770725ca
5 *
6 * Copyright (c) 2010-2014 James Hall, https://github.com/MrRio/jsPDF
7 * 2010 Aaron Spike, https://github.com/acspike
8 * 2012 Willow Systems Corporation, willow-systems.com
9 * 2012 Pablo Hess, https://github.com/pablohess
10 * 2012 Florian Jenett, https://github.com/fjenett
11 * 2013 Warren Weckesser, https://github.com/warrenweckesser
12 * 2013 Youssef Beddad, https://github.com/lifof
13 * 2013 Lee Driscoll, https://github.com/lsdriscoll
14 * 2013 Stefan Slonevskiy, https://github.com/stefslon
15 * 2013 Jeremy Morel, https://github.com/jmorel
16 * 2013 Christoph Hartmann, https://github.com/chris-rock
17 * 2014 Juan Pablo Gaviria, https://github.com/juanpgaviria
18 * 2014 James Makes, https://github.com/dollaruw
19 * 2014 Diego Casorran, https://github.com/diegocr
20 *
21 * Permission is hereby granted, free of charge, to any person obtaining
22 * a copy of this software and associated documentation files (the
23 * "Software"), to deal in the Software without restriction, including
24 * without limitation the rights to use, copy, modify, merge, publish,
25 * distribute, sublicense, and/or sell copies of the Software, and to
26 * permit persons to whom the Software is furnished to do so, subject to
27 * the following conditions:
28 *
29 * The above copyright notice and this permission notice shall be
30 * included in all copies or substantial portions of the Software.
31 *
32 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
33 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
34 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
35 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
36 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
37 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
38 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
39 *
40 * Contributor(s):
41 * siefkenj, ahwolf, rickygu, Midnith, saintclair, eaparango,
42 * kim3er, mfo, alnorth,
43 */
44
45/**
46 * Creates new jsPDF document object instance.
47 *
48 * @class
49 * @param orientation One of "portrait" or "landscape" (or shortcuts "p" (Default), "l")
50 * @param unit Measurement unit to be used when coordinates are specified.
51 * One of "pt" (points), "mm" (Default), "cm", "in"
52 * @param format One of 'pageFormats' as shown below, default: a4
53 * @returns {jsPDF}
54 * @name jsPDF
55 */
56var jsPDF = (function(global) {
57 'use strict';
58 var pdfVersion = '1.3',
59 pageFormats = { // Size in pt of various paper formats
60 'a0' : [2383.94, 3370.39], 'a1' : [1683.78, 2383.94],
61 'a2' : [1190.55, 1683.78], 'a3' : [ 841.89, 1190.55],
62 'a4' : [ 595.28, 841.89], 'a5' : [ 419.53, 595.28],
63 'a6' : [ 297.64, 419.53], 'a7' : [ 209.76, 297.64],
64 'a8' : [ 147.40, 209.76], 'a9' : [ 104.88, 147.40],
65 'a10' : [ 73.70, 104.88], 'b0' : [2834.65, 4008.19],
66 'b1' : [2004.09, 2834.65], 'b2' : [1417.32, 2004.09],
67 'b3' : [1000.63, 1417.32], 'b4' : [ 708.66, 1000.63],
68 'b5' : [ 498.90, 708.66], 'b6' : [ 354.33, 498.90],
69 'b7' : [ 249.45, 354.33], 'b8' : [ 175.75, 249.45],
70 'b9' : [ 124.72, 175.75], 'b10' : [ 87.87, 124.72],
71 'c0' : [2599.37, 3676.54], 'c1' : [1836.85, 2599.37],
72 'c2' : [1298.27, 1836.85], 'c3' : [ 918.43, 1298.27],
73 'c4' : [ 649.13, 918.43], 'c5' : [ 459.21, 649.13],
74 'c6' : [ 323.15, 459.21], 'c7' : [ 229.61, 323.15],
75 'c8' : [ 161.57, 229.61], 'c9' : [ 113.39, 161.57],
76 'c10' : [ 79.37, 113.39], 'dl' : [ 311.81, 623.62],
77 'letter' : [612, 792],
78 'government-letter' : [576, 756],
79 'legal' : [612, 1008],
80 'junior-legal' : [576, 360],
81 'ledger' : [1224, 792],
82 'tabloid' : [792, 1224],
83 'credit-card' : [153, 243]
84 };
85
86 /**
87 * jsPDF's Internal PubSub Implementation.
88 * See mrrio.github.io/jsPDF/doc/symbols/PubSub.html
89 * Backward compatible rewritten on 2014 by
90 * Diego Casorran, https://github.com/diegocr
91 *
92 * @class
93 * @name PubSub
94 */
95 function PubSub(context) {
96 var topics = {};
97
98 this.subscribe = function(topic, callback, once) {
99 if(typeof callback !== 'function') {
100 return false;
101 }
102
103 if(!topics.hasOwnProperty(topic)) {
104 topics[topic] = {};
105 }
106
107 var id = Math.random().toString(35);
108 topics[topic][id] = [callback,!!once];
109
110 return id;
111 };
112
113 this.unsubscribe = function(token) {
114 for(var topic in topics) {
115 if(topics[topic][token]) {
116 delete topics[topic][token];
117 return true;
118 }
119 }
120 return false;
121 };
122
123 this.publish = function(topic) {
124 if(topics.hasOwnProperty(topic)) {
125 var args = Array.prototype.slice.call(arguments, 1), idr = [];
126
127 for(var id in topics[topic]) {
128 var sub = topics[topic][id];
129 try {
130 sub[0].apply(context, args);
131 } catch(ex) {
132 if(global.console) {
133 console.error('jsPDF PubSub Error', ex.message, ex);
134 }
135 }
136 if(sub[1]) idr.push(id);
137 }
138 if(idr.length) idr.forEach(this.unsubscribe);
139 }
140 };
141 }
142
143 /**
144 * @constructor
145 * @private
146 */
147 function jsPDF(orientation, unit, format, compressPdf) {
148 var options = {};
149
150 if (typeof orientation === 'object') {
151 options = orientation;
152
153 orientation = options.orientation;
154 unit = options.unit || unit;
155 format = options.format || format;
156 compressPdf = options.compress || options.compressPdf || compressPdf;
157 }
158
159 // Default options
160 unit = unit || 'mm';
161 format = format || 'a4';
162 orientation = ('' + (orientation || 'P')).toLowerCase();
163
164 var format_as_string = ('' + format).toLowerCase(),
165 compress = !!compressPdf && typeof Uint8Array === 'function',
166 textColor = options.textColor || '0 g',
167 drawColor = options.drawColor || '0 G',
168 activeFontSize = options.fontSize || 16,
169 lineHeightProportion = options.lineHeight || 1.15,
170 lineWidth = options.lineWidth || 0.200025, // 2mm
171 objectNumber = 2, // 'n' Current object number
172 outToPages = !1, // switches where out() prints. outToPages true = push to pages obj. outToPages false = doc builder content
173 offsets = [], // List of offsets. Activated and reset by buildDocument(). Pupulated by various calls buildDocument makes.
174 fonts = {}, // collection of font objects, where key is fontKey - a dynamically created label for a given font.
175 fontmap = {}, // mapping structure fontName > fontStyle > font key - performance layer. See addFont()
176 activeFontKey, // will be string representing the KEY of the font as combination of fontName + fontStyle
177 k, // Scale factor
178 tmp,
179 page = 0,
180 currentPage,
181 pages = [],
182 pagedim = {},
183 content = [],
184 lineCapID = 0,
185 lineJoinID = 0,
186 content_length = 0,
187 pageWidth,
188 pageHeight,
189 pageMode,
190 zoomMode,
191 layoutMode,
192 documentProperties = {
193 'title' : '',
194 'subject' : '',
195 'author' : '',
196 'keywords' : '',
197 'creator' : ''
198 },
199 API = {},
200 events = new PubSub(API),
201
202 /////////////////////
203 // Private functions
204 /////////////////////
205 f2 = function(number) {
206 return number.toFixed(2); // Ie, %.2f
207 },
208 f3 = function(number) {
209 return number.toFixed(3); // Ie, %.3f
210 },
211 padd2 = function(number) {
212 return ('0' + parseInt(number)).slice(-2);
213 },
214 out = function(string) {
215 if (outToPages) {
216 /* set by beginPage */
217 pages[currentPage].push(string);
218 } else {
219 // +1 for '\n' that will be used to join 'content'
220 content_length += string.length + 1;
221 content.push(string);
222 }
223 },
224 newObject = function() {
225 // Begin a new object
226 objectNumber++;
227 offsets[objectNumber] = content_length;
228 out(objectNumber + ' 0 obj');
229 return objectNumber;
230 },
231 putStream = function(str) {
232 out('stream');
233 out(str);
234 out('endstream');
235 },
236 putPages = function() {
237 var n,p,arr,i,deflater,adler32,adler32cs,wPt,hPt;
238
239 adler32cs = global.adler32cs || jsPDF.adler32cs;
240 if (compress && typeof adler32cs === 'undefined') {
241 compress = false;
242 }
243
244 // outToPages = false as set in endDocument(). out() writes to content.
245
246 for (n = 1; n <= page; n++) {
247 newObject();
248 wPt = (pageWidth = pagedim[n].width) * k;
249 hPt = (pageHeight = pagedim[n].height) * k;
250 out('<</Type /Page');
251 out('/Parent 1 0 R');
252 out('/Resources 2 0 R');
253 out('/MediaBox [0 0 ' + f2(wPt) + ' ' + f2(hPt) + ']');
254 out('/Contents ' + (objectNumber + 1) + ' 0 R>>');
255 out('endobj');
256
257 // Page content
258 p = pages[n].join('\n');
259 newObject();
260 if (compress) {
261 arr = [];
262 i = p.length;
263 while(i--) {
264 arr[i] = p.charCodeAt(i);
265 }
266 adler32 = adler32cs.from(p);
267 deflater = new Deflater(6);
268 deflater.append(new Uint8Array(arr));
269 p = deflater.flush();
270 arr = new Uint8Array(p.length + 6);
271 arr.set(new Uint8Array([120, 156])),
272 arr.set(p, 2);
273 arr.set(new Uint8Array([adler32 & 0xFF, (adler32 >> 8) & 0xFF, (adler32 >> 16) & 0xFF, (adler32 >> 24) & 0xFF]), p.length+2);
274 p = String.fromCharCode.apply(null, arr);
275 out('<</Length ' + p.length + ' /Filter [/FlateDecode]>>');
276 } else {
277 out('<</Length ' + p.length + '>>');
278 }
279 putStream(p);
280 out('endobj');
281 }
282 offsets[1] = content_length;
283 out('1 0 obj');
284 out('<</Type /Pages');
285 var kids = '/Kids [';
286 for (i = 0; i < page; i++) {
287 kids += (3 + 2 * i) + ' 0 R ';
288 }
289 out(kids + ']');
290 out('/Count ' + page);
291 out('>>');
292 out('endobj');
293 },
294 putFont = function(font) {
295 font.objectNumber = newObject();
296 out('<</BaseFont/' + font.PostScriptName + '/Type/Font');
297 if (typeof font.encoding === 'string') {
298 out('/Encoding/' + font.encoding);
299 }
300 out('/Subtype/Type1>>');
301 out('endobj');
302 },
303 putFonts = function() {
304 for (var fontKey in fonts) {
305 if (fonts.hasOwnProperty(fontKey)) {
306 putFont(fonts[fontKey]);
307 }
308 }
309 },
310 putXobjectDict = function() {
311 // Loop through images, or other data objects
312 events.publish('putXobjectDict');
313 },
314 putResourceDictionary = function() {
315 out('/ProcSet [/PDF /Text /ImageB /ImageC /ImageI]');
316 out('/Font <<');
317
318 // Do this for each font, the '1' bit is the index of the font
319 for (var fontKey in fonts) {
320 if (fonts.hasOwnProperty(fontKey)) {
321 out('/' + fontKey + ' ' + fonts[fontKey].objectNumber + ' 0 R');
322 }
323 }
324 out('>>');
325 out('/XObject <<');
326 putXobjectDict();
327 out('>>');
328 },
329 putResources = function() {
330 putFonts();
331 events.publish('putResources');
332 // Resource dictionary
333 offsets[2] = content_length;
334 out('2 0 obj');
335 out('<<');
336 putResourceDictionary();
337 out('>>');
338 out('endobj');
339 events.publish('postPutResources');
340 },
341 addToFontDictionary = function(fontKey, fontName, fontStyle) {
342 // this is mapping structure for quick font key lookup.
343 // returns the KEY of the font (ex: "F1") for a given
344 // pair of font name and type (ex: "Arial". "Italic")
345 if (!fontmap.hasOwnProperty(fontName)) {
346 fontmap[fontName] = {};
347 }
348 fontmap[fontName][fontStyle] = fontKey;
349 },
350 /**
351 * FontObject describes a particular font as member of an instnace of jsPDF
352 *
353 * It's a collection of properties like 'id' (to be used in PDF stream),
354 * 'fontName' (font's family name), 'fontStyle' (font's style variant label)
355 *
356 * @class
357 * @public
358 * @property id {String} PDF-document-instance-specific label assinged to the font.
359 * @property PostScriptName {String} PDF specification full name for the font
360 * @property encoding {Object} Encoding_name-to-Font_metrics_object mapping.
361 * @name FontObject
362 */
363 addFont = function(PostScriptName, fontName, fontStyle, encoding) {
364 var fontKey = 'F' + (Object.keys(fonts).length + 1).toString(10),
365 // This is FontObject
366 font = fonts[fontKey] = {
367 'id' : fontKey,
368 'PostScriptName' : PostScriptName,
369 'fontName' : fontName,
370 'fontStyle' : fontStyle,
371 'encoding' : encoding,
372 'metadata' : {}
373 };
374 addToFontDictionary(fontKey, fontName, fontStyle);
375 events.publish('addFont', font);
376
377 return fontKey;
378 },
379 addFonts = function() {
380
381 var HELVETICA = "helvetica",
382 TIMES = "times",
383 COURIER = "courier",
384 NORMAL = "normal",
385 BOLD = "bold",
386 ITALIC = "italic",
387 BOLD_ITALIC = "bolditalic",
388 encoding = 'StandardEncoding',
389 standardFonts = [
390 ['Helvetica', HELVETICA, NORMAL],
391 ['Helvetica-Bold', HELVETICA, BOLD],
392 ['Helvetica-Oblique', HELVETICA, ITALIC],
393 ['Helvetica-BoldOblique', HELVETICA, BOLD_ITALIC],
394 ['Courier', COURIER, NORMAL],
395 ['Courier-Bold', COURIER, BOLD],
396 ['Courier-Oblique', COURIER, ITALIC],
397 ['Courier-BoldOblique', COURIER, BOLD_ITALIC],
398 ['Times-Roman', TIMES, NORMAL],
399 ['Times-Bold', TIMES, BOLD],
400 ['Times-Italic', TIMES, ITALIC],
401 ['Times-BoldItalic', TIMES, BOLD_ITALIC]
402 ];
403
404 for (var i = 0, l = standardFonts.length; i < l; i++) {
405 var fontKey = addFont(
406 standardFonts[i][0],
407 standardFonts[i][1],
408 standardFonts[i][2],
409 encoding);
410
411 // adding aliases for standard fonts, this time matching the capitalization
412 var parts = standardFonts[i][0].split('-');
413 addToFontDictionary(fontKey, parts[0], parts[1] || '');
414 }
415 events.publish('addFonts', { fonts : fonts, dictionary : fontmap });
416 },
417 SAFE = function __safeCall(fn) {
418 fn.foo = function __safeCallWrapper() {
419 try {
420 return fn.apply(this, arguments);
421 } catch (e) {
422 var stack = e.stack || '';
423 if(~stack.indexOf(' at ')) stack = stack.split(" at ")[1];
424 var m = "Error in function " + stack.split("\n")[0].split('<')[0] + ": " + e.message;
425 if(global.console) {
426 global.console.error(m, e);
427 if(global.alert) alert(m);
428 } else {
429 throw new Error(m);
430 }
431 }
432 };
433 fn.foo.bar = fn;
434 return fn.foo;
435 },
436 to8bitStream = function(text, flags) {
437 /**
438 * PDF 1.3 spec:
439 * "For text strings encoded in Unicode, the first two bytes must be 254 followed by
440 * 255, representing the Unicode byte order marker, U+FEFF. (This sequence conflicts
441 * with the PDFDocEncoding character sequence thorn ydieresis, which is unlikely
442 * to be a meaningful beginning of a word or phrase.) The remainder of the
443 * string consists of Unicode character codes, according to the UTF-16 encoding
444 * specified in the Unicode standard, version 2.0. Commonly used Unicode values
445 * are represented as 2 bytes per character, with the high-order byte appearing first
446 * in the string."
447 *
448 * In other words, if there are chars in a string with char code above 255, we
449 * recode the string to UCS2 BE - string doubles in length and BOM is prepended.
450 *
451 * HOWEVER!
452 * Actual *content* (body) text (as opposed to strings used in document properties etc)
453 * does NOT expect BOM. There, it is treated as a literal GID (Glyph ID)
454 *
455 * Because of Adobe's focus on "you subset your fonts!" you are not supposed to have
456 * a font that maps directly Unicode (UCS2 / UTF16BE) code to font GID, but you could
457 * fudge it with "Identity-H" encoding and custom CIDtoGID map that mimics Unicode
458 * code page. There, however, all characters in the stream are treated as GIDs,
459 * including BOM, which is the reason we need to skip BOM in content text (i.e. that
460 * that is tied to a font).
461 *
462 * To signal this "special" PDFEscape / to8bitStream handling mode,
463 * API.text() function sets (unless you overwrite it with manual values
464 * given to API.text(.., flags) )
465 * flags.autoencode = true
466 * flags.noBOM = true
467 *
468 * ===================================================================================
469 * `flags` properties relied upon:
470 * .sourceEncoding = string with encoding label.
471 * "Unicode" by default. = encoding of the incoming text.
472 * pass some non-existing encoding name
473 * (ex: 'Do not touch my strings! I know what I am doing.')
474 * to make encoding code skip the encoding step.
475 * .outputEncoding = Either valid PDF encoding name
476 * (must be supported by jsPDF font metrics, otherwise no encoding)
477 * or a JS object, where key = sourceCharCode, value = outputCharCode
478 * missing keys will be treated as: sourceCharCode === outputCharCode
479 * .noBOM
480 * See comment higher above for explanation for why this is important
481 * .autoencode
482 * See comment higher above for explanation for why this is important
483 */
484
485 var i,l,sourceEncoding,encodingBlock,outputEncoding,newtext,isUnicode,ch,bch;
486
487 flags = flags || {};
488 sourceEncoding = flags.sourceEncoding || 'Unicode';
489 outputEncoding = flags.outputEncoding;
490
491 // This 'encoding' section relies on font metrics format
492 // attached to font objects by, among others,
493 // "Willow Systems' standard_font_metrics plugin"
494 // see jspdf.plugin.standard_font_metrics.js for format
495 // of the font.metadata.encoding Object.
496 // It should be something like
497 // .encoding = {'codePages':['WinANSI....'], 'WinANSI...':{code:code, ...}}
498 // .widths = {0:width, code:width, ..., 'fof':divisor}
499 // .kerning = {code:{previous_char_code:shift, ..., 'fof':-divisor},...}
500 if ((flags.autoencode || outputEncoding) &&
501 fonts[activeFontKey].metadata &&
502 fonts[activeFontKey].metadata[sourceEncoding] &&
503 fonts[activeFontKey].metadata[sourceEncoding].encoding) {
504 encodingBlock = fonts[activeFontKey].metadata[sourceEncoding].encoding;
505
506 // each font has default encoding. Some have it clearly defined.
507 if (!outputEncoding && fonts[activeFontKey].encoding) {
508 outputEncoding = fonts[activeFontKey].encoding;
509 }
510
511 // Hmmm, the above did not work? Let's try again, in different place.
512 if (!outputEncoding && encodingBlock.codePages) {
513 outputEncoding = encodingBlock.codePages[0]; // let's say, first one is the default
514 }
515
516 if (typeof outputEncoding === 'string') {
517 outputEncoding = encodingBlock[outputEncoding];
518 }
519 // we want output encoding to be a JS Object, where
520 // key = sourceEncoding's character code and
521 // value = outputEncoding's character code.
522 if (outputEncoding) {
523 isUnicode = false;
524 newtext = [];
525 for (i = 0, l = text.length; i < l; i++) {
526 ch = outputEncoding[text.charCodeAt(i)];
527 if (ch) {
528 newtext.push(
529 String.fromCharCode(ch));
530 } else {
531 newtext.push(
532 text[i]);
533 }
534
535 // since we are looping over chars anyway, might as well
536 // check for residual unicodeness
537 if (newtext[i].charCodeAt(0) >> 8) {
538 /* more than 255 */
539 isUnicode = true;
540 }
541 }
542 text = newtext.join('');
543 }
544 }
545
546 i = text.length;
547 // isUnicode may be set to false above. Hence the triple-equal to undefined
548 while (isUnicode === undefined && i !== 0) {
549 if (text.charCodeAt(i - 1) >> 8) {
550 /* more than 255 */
551 isUnicode = true;
552 }
553 i--;
554 }
555 if (!isUnicode) {
556 return text;
557 }
558
559 newtext = flags.noBOM ? [] : [254, 255];
560 for (i = 0, l = text.length; i < l; i++) {
561 ch = text.charCodeAt(i);
562 bch = ch >> 8; // divide by 256
563 if (bch >> 8) {
564 /* something left after dividing by 256 second time */
565 throw new Error("Character at position " + i + " of string '"
566 + text + "' exceeds 16bits. Cannot be encoded into UCS-2 BE");
567 }
568 newtext.push(bch);
569 newtext.push(ch - (bch << 8));
570 }
571 return String.fromCharCode.apply(undefined, newtext);
572 },
573 pdfEscape = function(text, flags) {
574 /**
575 * Replace '/', '(', and ')' with pdf-safe versions
576 *
577 * Doing to8bitStream does NOT make this PDF display unicode text. For that
578 * we also need to reference a unicode font and embed it - royal pain in the rear.
579 *
580 * There is still a benefit to to8bitStream - PDF simply cannot handle 16bit chars,
581 * which JavaScript Strings are happy to provide. So, while we still cannot display
582 * 2-byte characters property, at least CONDITIONALLY converting (entire string containing)
583 * 16bit chars to (USC-2-BE) 2-bytes per char + BOM streams we ensure that entire PDF
584 * is still parseable.
585 * This will allow immediate support for unicode in document properties strings.
586 */
587 return to8bitStream(text, flags).replace(/\\/g, '\\\\').replace(/\(/g, '\\(').replace(/\)/g, '\\)');
588 },
589 putInfo = function() {
590 out('/Producer (jsPDF ' + jsPDF.version + ')');
591 for(var key in documentProperties) {
592 if(documentProperties.hasOwnProperty(key) && documentProperties[key]) {
593 out('/'+key.substr(0,1).toUpperCase() + key.substr(1)
594 +' (' + pdfEscape(documentProperties[key]) + ')');
595 }
596 }
597 var created = new Date(),
598 tzoffset = created.getTimezoneOffset(),
599 tzsign = tzoffset < 0 ? '+' : '-',
600 tzhour = Math.floor(Math.abs(tzoffset / 60)),
601 tzmin = Math.abs(tzoffset % 60),
602 tzstr = [tzsign, padd2(tzhour), "'", padd2(tzmin), "'"].join('');
603 out(['/CreationDate (D:',
604 created.getFullYear(),
605 padd2(created.getMonth() + 1),
606 padd2(created.getDate()),
607 padd2(created.getHours()),
608 padd2(created.getMinutes()),
609 padd2(created.getSeconds()), tzstr, ')'].join(''));
610 },
611 putCatalog = function() {
612 out('/Type /Catalog');
613 out('/Pages 1 0 R');
614 // PDF13ref Section 7.2.1
615 if (!zoomMode) zoomMode = 'fullwidth';
616 switch(zoomMode) {
617 case 'fullwidth' : out('/OpenAction [3 0 R /FitH null]'); break;
618 case 'fullheight' : out('/OpenAction [3 0 R /FitV null]'); break;
619 case 'fullpage' : out('/OpenAction [3 0 R /Fit]'); break;
620 case 'original' : out('/OpenAction [3 0 R /XYZ null null 1]'); break;
621 default:
622 var pcn = '' + zoomMode;
623 if (pcn.substr(pcn.length-1) === '%')
624 zoomMode = parseInt(zoomMode) / 100;
625 if (typeof zoomMode === 'number') {
626 out('/OpenAction [3 0 R /XYZ null null '+f2(zoomMode)+']');
627 }
628 }
629 if (!layoutMode) layoutMode = 'continuous';
630 switch(layoutMode) {
631 case 'continuous' : out('/PageLayout /OneColumn'); break;
632 case 'single' : out('/PageLayout /SinglePage'); break;
633 case 'two':
634 case 'twoleft' : out('/PageLayout /TwoColumnLeft'); break;
635 case 'tworight' : out('/PageLayout /TwoColumnRight'); break;
636 }
637 if (pageMode) {
638 /**
639 * A name object specifying how the document should be displayed when opened:
640 * UseNone : Neither document outline nor thumbnail images visible -- DEFAULT
641 * UseOutlines : Document outline visible
642 * UseThumbs : Thumbnail images visible
643 * FullScreen : Full-screen mode, with no menu bar, window controls, or any other window visible
644 */
645 out('/PageMode /' + pageMode);
646 }
647 events.publish('putCatalog');
648 },
649 putTrailer = function() {
650 out('/Size ' + (objectNumber + 1));
651 out('/Root ' + objectNumber + ' 0 R');
652 out('/Info ' + (objectNumber - 1) + ' 0 R');
653 },
654 beginPage = function(width,height) {
655 // Dimensions are stored as user units and converted to points on output
656 var orientation = typeof height === 'string' && height.toLowerCase();
657 if (typeof width === 'string') {
658 var format = width.toLowerCase();
659 if (pageFormats.hasOwnProperty(format)) {
660 width = pageFormats[format][0] / k;
661 height = pageFormats[format][1] / k;
662 }
663 }
664 if (Array.isArray(width)) {
665 height = width[1];
666 width = width[0];
667 }
668 if (orientation) {
669 switch(orientation.substr(0,1)) {
670 case 'l': if (height > width ) orientation = 's'; break;
671 case 'p': if (width > height ) orientation = 's'; break;
672 }
673 if (orientation === 's') { tmp = width; width = height; height = tmp; }
674 }
675 outToPages = true;
676 pages[++page] = [];
677 pagedim[page] = {
678 width : Number(width) || pageWidth,
679 height : Number(height) || pageHeight
680 };
681 _setPage(page);
682 },
683 _addPage = function() {
684 beginPage.apply(this, arguments);
685 // Set line width
686 out(f2(lineWidth * k) + ' w');
687 // Set draw color
688 out(drawColor);
689 // resurrecting non-default line caps, joins
690 if (lineCapID !== 0) {
691 out(lineCapID + ' J');
692 }
693 if (lineJoinID !== 0) {
694 out(lineJoinID + ' j');
695 }
696 events.publish('addPage', { pageNumber : page });
697 },
698 _setPage = function(n) {
699 if (n > 0 && n <= page) {
700 currentPage = n;
701 pageWidth = pagedim[n].width;
702 pageHeight = pagedim[n].height;
703 }
704 },
705 /**
706 * Returns a document-specific font key - a label assigned to a
707 * font name + font type combination at the time the font was added
708 * to the font inventory.
709 *
710 * Font key is used as label for the desired font for a block of text
711 * to be added to the PDF document stream.
712 * @private
713 * @function
714 * @param fontName {String} can be undefined on "falthy" to indicate "use current"
715 * @param fontStyle {String} can be undefined on "falthy" to indicate "use current"
716 * @returns {String} Font key.
717 */
718 getFont = function(fontName, fontStyle) {
719 var key;
720
721 fontName = fontName !== undefined ? fontName : fonts[activeFontKey].fontName;
722 fontStyle = fontStyle !== undefined ? fontStyle : fonts[activeFontKey].fontStyle;
723
724 try {
725 // get a string like 'F3' - the KEY corresponding tot he font + type combination.
726 key = fontmap[fontName][fontStyle];
727 } catch (e) {}
728
729 if (!key) {
730 throw new Error("Unable to look up font label for font '" + fontName + "', '"
731 + fontStyle + "'. Refer to getFontList() for available fonts.");
732 }
733 return key;
734 },
735 buildDocument = function() {
736
737 outToPages = false; // switches out() to content
738 objectNumber = 2;
739 content = [];
740 offsets = [];
741
742 // putHeader()
743 out('%PDF-' + pdfVersion);
744
745 putPages();
746
747 putResources();
748
749 // Info
750 newObject();
751 out('<<');
752 putInfo();
753 out('>>');
754 out('endobj');
755
756 // Catalog
757 newObject();
758 out('<<');
759 putCatalog();
760 out('>>');
761 out('endobj');
762
763 // Cross-ref
764 var o = content_length, i, p = "0000000000";
765 out('xref');
766 out('0 ' + (objectNumber + 1));
767 out(p+' 65535 f ');
768 for (i = 1; i <= objectNumber; i++) {
769 out((p + offsets[i]).slice(-10) + ' 00000 n ');
770 }
771 // Trailer
772 out('trailer');
773 out('<<');
774 putTrailer();
775 out('>>');
776 out('startxref');
777 out(o);
778 out('%%EOF');
779
780 outToPages = true;
781
782 return content.join('\n');
783 },
784 getStyle = function(style) {
785 // see path-painting operators in PDF spec
786 var op = 'S'; // stroke
787 if (style === 'F') {
788 op = 'f'; // fill
789 } else if (style === 'FD' || style === 'DF') {
790 op = 'B'; // both
791 } else if (style === 'f' || style === 'f*' || style === 'B' || style === 'B*') {
792 /*
793 Allow direct use of these PDF path-painting operators:
794 - f fill using nonzero winding number rule
795 - f* fill using even-odd rule
796 - B fill then stroke with fill using non-zero winding number rule
797 - B* fill then stroke with fill using even-odd rule
798 */
799 op = style;
800 }
801 return op;
802 },
803 getArrayBuffer = function() {
804 var data = buildDocument(), len = data.length,
805 ab = new ArrayBuffer(len), u8 = new Uint8Array(ab);
806
807 while(len--) u8[len] = data.charCodeAt(len);
808 return ab;
809 },
810 getBlob = function() {
811 return new Blob([getArrayBuffer()], { type : "application/pdf" });
812 },
813 /**
814 * Generates the PDF document.
815 *
816 * If `type` argument is undefined, output is raw body of resulting PDF returned as a string.
817 *
818 * @param {String} type A string identifying one of the possible output types.
819 * @param {Object} options An object providing some additional signalling to PDF generator.
820 * @function
821 * @returns {jsPDF}
822 * @methodOf jsPDF#
823 * @name output
824 */
825 output = SAFE(function(type, options) {
826 var datauri = ('' + type).substr(0,6) === 'dataur'
827 ? 'data:application/pdf;base64,'+btoa(buildDocument()):0;
828
829 switch (type) {
830 case undefined:
831 return buildDocument();
832 case 'save':
833 if (navigator.getUserMedia) {
834 if (global.URL === undefined
835 || global.URL.createObjectURL === undefined) {
836 return API.output('dataurlnewwindow');
837 }
838 }
839 saveAs(getBlob(), options);
840 if(typeof saveAs.unload === 'function') {
841 if(global.setTimeout) {
842 setTimeout(saveAs.unload,911);
843 }
844 }
845 break;
846 case 'arraybuffer':
847 return getArrayBuffer();
848 case 'blob':
849 return getBlob();
850 case 'bloburi':
851 case 'bloburl':
852 // User is responsible of calling revokeObjectURL
853 return global.URL && global.URL.createObjectURL(getBlob()) || void 0;
854 case 'datauristring':
855 case 'dataurlstring':
856 return datauri;
857 case 'dataurlnewwindow':
858 var nW = global.open(datauri);
859 if (nW || typeof safari === "undefined") return nW;
860 /* pass through */
861 case 'datauri':
862 case 'dataurl':
863 return global.document.location.href = datauri;
864 default:
865 throw new Error('Output type "' + type + '" is not supported.');
866 }
867 // @TODO: Add different output options
868 });
869
870 switch (unit) {
871 case 'pt': k = 1; break;
872 case 'mm': k = 72 / 25.4; break;
873 case 'cm': k = 72 / 2.54; break;
874 case 'in': k = 72; break;
875 case 'px': k = 96 / 72; break;
876 case 'pc': k = 12; break;
877 case 'em': k = 12; break;
878 case 'ex': k = 6; break;
879 default:
880 throw ('Invalid unit: ' + unit);
881 }
882
883 //---------------------------------------
884 // Public API
885
886 /**
887 * Object exposing internal API to plugins
888 * @public
889 */
890 API.internal = {
891 'pdfEscape' : pdfEscape,
892 'getStyle' : getStyle,
893 /**
894 * Returns {FontObject} describing a particular font.
895 * @public
896 * @function
897 * @param fontName {String} (Optional) Font's family name
898 * @param fontStyle {String} (Optional) Font's style variation name (Example:"Italic")
899 * @returns {FontObject}
900 */
901 'getFont' : function() {
902 return fonts[getFont.apply(API, arguments)];
903 },
904 'getFontSize' : function() {
905 return activeFontSize;
906 },
907 'getLineHeight' : function() {
908 return activeFontSize * lineHeightProportion;
909 },
910 'write' : function(string1 /*, string2, string3, etc */) {
911 out(arguments.length === 1 ? string1 : Array.prototype.join.call(arguments, ' '));
912 },
913 'getCoordinateString' : function(value) {
914 return f2(value * k);
915 },
916 'getVerticalCoordinateString' : function(value) {
917 return f2((pageHeight - value) * k);
918 },
919 'collections' : {},
920 'newObject' : newObject,
921 'putStream' : putStream,
922 'events' : events,
923 // ratio that you use in multiplication of a given "size" number to arrive to 'point'
924 // units of measurement.
925 // scaleFactor is set at initialization of the document and calculated against the stated
926 // default measurement units for the document.
927 // If default is "mm", k is the number that will turn number in 'mm' into 'points' number.
928 // through multiplication.
929 'scaleFactor' : k,
930 'pageSize' : {
931 get width() {
932 return pageWidth
933 },
934 get height() {
935 return pageHeight
936 }
937 },
938 'output' : function(type, options) {
939 return output(type, options);
940 },
941 'getNumberOfPages' : function() {
942 return pages.length - 1;
943 },
944 'pages' : pages
945 };
946
947 /**
948 * Adds (and transfers the focus to) new page to the PDF document.
949 * @function
950 * @returns {jsPDF}
951 *
952 * @methodOf jsPDF#
953 * @name addPage
954 */
955 API.addPage = function() {
956 _addPage.apply(this, arguments);
957 return this;
958 };
959 API.setPage = function() {
960 _setPage.apply(this, arguments);
961 return this;
962 };
963 API.setDisplayMode = function(zoom, layout, pmode) {
964 zoomMode = zoom;
965 layoutMode = layout;
966 pageMode = pmode;
967 return this;
968 },
969
970 /**
971 * Adds text to page. Supports adding multiline text when 'text' argument is an Array of Strings.
972 *
973 * @function
974 * @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.
975 * @param {Number} x Coordinate (in units declared at inception of PDF document) against left edge of the page
976 * @param {Number} y Coordinate (in units declared at inception of PDF document) against upper edge of the page
977 * @param {Object} flags Collection of settings signalling how the text must be encoded. Defaults are sane. If you think you want to pass some flags, you likely can read the source.
978 * @returns {jsPDF}
979 * @methodOf jsPDF#
980 * @name text
981 */
982 API.text = function(text, x, y, flags, angle) {
983 /**
984 * Inserts something like this into PDF
985 * BT
986 * /F1 16 Tf % Font name + size
987 * 16 TL % How many units down for next line in multiline text
988 * 0 g % color
989 * 28.35 813.54 Td % position
990 * (line one) Tj
991 * T* (line two) Tj
992 * T* (line three) Tj
993 * ET
994 */
995 function ESC(s) {
996 s = s.split("\t").join(Array(options.TabLen||9).join(" "));
997 return pdfEscape(s, flags);
998 }
999
1000 // Pre-August-2012 the order of arguments was function(x, y, text, flags)
1001 // in effort to make all calls have similar signature like
1002 // function(data, coordinates... , miscellaneous)
1003 // this method had its args flipped.
1004 // code below allows backward compatibility with old arg order.
1005 if (typeof text === 'number') {
1006 tmp = y;
1007 y = x;
1008 x = text;
1009 text = tmp;
1010 }
1011
1012 // If there are any newlines in text, we assume
1013 // the user wanted to print multiple lines, so break the
1014 // text up into an array. If the text is already an array,
1015 // we assume the user knows what they are doing.
1016 if (typeof text === 'string' && text.match(/[\n\r]/)) {
1017 text = text.split(/\r\n|\r|\n/g);
1018 }
1019 if (typeof flags === 'number') {
1020 angle = flags;
1021 flags = null;
1022 }
1023 var xtra = '',mode = 'Td', todo;
1024 if (angle) {
1025 angle *= (Math.PI / 180);
1026 var c = Math.cos(angle),
1027 s = Math.sin(angle);
1028 xtra = [f2(c), f2(s), f2(s * -1), f2(c), ''].join(" ");
1029 mode = 'Tm';
1030 }
1031 flags = flags || {};
1032 if (!('noBOM' in flags))
1033 flags.noBOM = true;
1034 if (!('autoencode' in flags))
1035 flags.autoencode = true;
1036
1037 if (typeof text === 'string') {
1038 text = ESC(text);
1039 } else if (text instanceof Array) {
1040 // we don't want to destroy original text array, so cloning it
1041 var sa = text.concat(), da = [], len = sa.length;
1042 // we do array.join('text that must not be PDFescaped")
1043 // thus, pdfEscape each component separately
1044 while (len--) {
1045 da.push(ESC(sa.shift()));
1046 }
1047 var linesLeft = Math.ceil((pageHeight - y) * k / (activeFontSize * lineHeightProportion));
1048 if (0 <= linesLeft && linesLeft < da.length + 1) {
1049 todo = da.splice(linesLeft-1);
1050 }
1051 text = da.join(") Tj\nT* (");
1052 } else {
1053 throw new Error('Type of text must be string or Array. "' + text + '" is not recognized.');
1054 }
1055 // Using "'" ("go next line and render text" mark) would save space but would complicate our rendering code, templates
1056
1057 // BT .. ET does NOT have default settings for Tf. You must state that explicitely every time for BT .. ET
1058 // if you want text transformation matrix (+ multiline) to work reliably (which reads sizes of things from font declarations)
1059 // Thus, there is NO useful, *reliable* concept of "default" font for a page.
1060 // The fact that "default" (reuse font used before) font worked before in basic cases is an accident
1061 // - readers dealing smartly with brokenness of jsPDF's markup.
1062 out(
1063 'BT\n/' +
1064 activeFontKey + ' ' + activeFontSize + ' Tf\n' + // font face, style, size
1065 (activeFontSize * lineHeightProportion) + ' TL\n' + // line spacing
1066 textColor +
1067 '\n' + xtra + f2(x * k) + ' ' + f2((pageHeight - y) * k) + ' ' + mode + '\n(' +
1068 text +
1069 ') Tj\nET');
1070
1071 if (todo) {
1072 this.addPage();
1073 this.text( todo, x, activeFontSize * 1.7 / k);
1074 }
1075
1076 return this;
1077 };
1078
1079 API.lstext = function(text, x, y, spacing) {
1080 for (var i = 0, len = text.length ; i < len; i++, x += spacing) this.text(text[i], x, y);
1081 };
1082
1083 API.line = function(x1, y1, x2, y2) {
1084 return this.lines([[x2 - x1, y2 - y1]], x1, y1);
1085 };
1086
1087 API.clip = function() {
1088 // By patrick-roberts, github.com/MrRio/jsPDF/issues/328
1089 // Call .clip() after calling .rect() with a style argument of null
1090 out('W') // clip
1091 out('S') // stroke path; necessary for clip to work
1092 };
1093
1094 /**
1095 * Adds series of curves (straight lines or cubic bezier curves) to canvas, starting at `x`, `y` coordinates.
1096 * All data points in `lines` are relative to last line origin.
1097 * `x`, `y` become x1,y1 for first line / curve in the set.
1098 * For lines you only need to specify [x2, y2] - (ending point) vector against x1, y1 starting point.
1099 * 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.
1100 *
1101 * @example .lines([[2,2],[-2,2],[1,1,2,2,3,3],[2,1]], 212,110, 10) // line, line, bezier curve, line
1102 * @param {Array} lines Array of *vector* shifts as pairs (lines) or sextets (cubic bezier curves).
1103 * @param {Number} x Coordinate (in units declared at inception of PDF document) against left edge of the page
1104 * @param {Number} y Coordinate (in units declared at inception of PDF document) against upper edge of the page
1105 * @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.
1106 * @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.
1107 * @param {Boolean} closed If true, the path is closed with a straight line from the end of the last curve to the starting point.
1108 * @function
1109 * @returns {jsPDF}
1110 * @methodOf jsPDF#
1111 * @name lines
1112 */
1113 API.lines = function(lines, x, y, scale, style, closed) {
1114 var scalex,scaley,i,l,leg,x2,y2,x3,y3,x4,y4;
1115
1116 // Pre-August-2012 the order of arguments was function(x, y, lines, scale, style)
1117 // in effort to make all calls have similar signature like
1118 // function(content, coordinateX, coordinateY , miscellaneous)
1119 // this method had its args flipped.
1120 // code below allows backward compatibility with old arg order.
1121 if (typeof lines === 'number') {
1122 tmp = y;
1123 y = x;
1124 x = lines;
1125 lines = tmp;
1126 }
1127
1128 scale = scale || [1, 1];
1129
1130 // starting point
1131 out(f3(x * k) + ' ' + f3((pageHeight - y) * k) + ' m ');
1132
1133 scalex = scale[0];
1134 scaley = scale[1];
1135 l = lines.length;
1136 //, x2, y2 // bezier only. In page default measurement "units", *after* scaling
1137 //, x3, y3 // bezier only. In page default measurement "units", *after* scaling
1138 // ending point for all, lines and bezier. . In page default measurement "units", *after* scaling
1139 x4 = x; // last / ending point = starting point for first item.
1140 y4 = y; // last / ending point = starting point for first item.
1141
1142 for (i = 0; i < l; i++) {
1143 leg = lines[i];
1144 if (leg.length === 2) {
1145 // simple line
1146 x4 = leg[0] * scalex + x4; // here last x4 was prior ending point
1147 y4 = leg[1] * scaley + y4; // here last y4 was prior ending point
1148 out(f3(x4 * k) + ' ' + f3((pageHeight - y4) * k) + ' l');
1149 } else {
1150 // bezier curve
1151 x2 = leg[0] * scalex + x4; // here last x4 is prior ending point
1152 y2 = leg[1] * scaley + y4; // here last y4 is prior ending point
1153 x3 = leg[2] * scalex + x4; // here last x4 is prior ending point
1154 y3 = leg[3] * scaley + y4; // here last y4 is prior ending point
1155 x4 = leg[4] * scalex + x4; // here last x4 was prior ending point
1156 y4 = leg[5] * scaley + y4; // here last y4 was prior ending point
1157 out(
1158 f3(x2 * k) + ' ' +
1159 f3((pageHeight - y2) * k) + ' ' +
1160 f3(x3 * k) + ' ' +
1161 f3((pageHeight - y3) * k) + ' ' +
1162 f3(x4 * k) + ' ' +
1163 f3((pageHeight - y4) * k) + ' c');
1164 }
1165 }
1166
1167 if (closed) {
1168 out(' h');
1169 }
1170
1171 // stroking / filling / both the path
1172 if (style !== null) {
1173 out(getStyle(style));
1174 }
1175 return this;
1176 };
1177
1178 /**
1179 * Adds a rectangle to PDF
1180 *
1181 * @param {Number} x Coordinate (in units declared at inception of PDF document) against left edge of the page
1182 * @param {Number} y Coordinate (in units declared at inception of PDF document) against upper edge of the page
1183 * @param {Number} w Width (in units declared at inception of PDF document)
1184 * @param {Number} h Height (in units declared at inception of PDF document)
1185 * @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.
1186 * @function
1187 * @returns {jsPDF}
1188 * @methodOf jsPDF#
1189 * @name rect
1190 */
1191 API.rect = function(x, y, w, h, style) {
1192 var op = getStyle(style);
1193 out([
1194 f2(x * k),
1195 f2((pageHeight - y) * k),
1196 f2(w * k),
1197 f2(-h * k),
1198 're'
1199 ].join(' '));
1200
1201 if (style !== null) {
1202 out(getStyle(style));
1203 }
1204
1205 return this;
1206 };
1207
1208 /**
1209 * Adds a triangle to PDF
1210 *
1211 * @param {Number} x1 Coordinate (in units declared at inception of PDF document) against left edge of the page
1212 * @param {Number} y1 Coordinate (in units declared at inception of PDF document) against upper edge of the page
1213 * @param {Number} x2 Coordinate (in units declared at inception of PDF document) against left edge of the page
1214 * @param {Number} y2 Coordinate (in units declared at inception of PDF document) against upper edge of the page
1215 * @param {Number} x3 Coordinate (in units declared at inception of PDF document) against left edge of the page
1216 * @param {Number} y3 Coordinate (in units declared at inception of PDF document) against upper edge of the page
1217 * @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.
1218 * @function
1219 * @returns {jsPDF}
1220 * @methodOf jsPDF#
1221 * @name triangle
1222 */
1223 API.triangle = function(x1, y1, x2, y2, x3, y3, style) {
1224 this.lines(
1225 [
1226 [x2 - x1, y2 - y1], // vector to point 2
1227 [x3 - x2, y3 - y2], // vector to point 3
1228 [x1 - x3, y1 - y3]// closing vector back to point 1
1229 ],
1230 x1,
1231 y1, // start of path
1232 [1, 1],
1233 style,
1234 true);
1235 return this;
1236 };
1237
1238 /**
1239 * Adds a rectangle with rounded corners to PDF
1240 *
1241 * @param {Number} x Coordinate (in units declared at inception of PDF document) against left edge of the page
1242 * @param {Number} y Coordinate (in units declared at inception of PDF document) against upper edge of the page
1243 * @param {Number} w Width (in units declared at inception of PDF document)
1244 * @param {Number} h Height (in units declared at inception of PDF document)
1245 * @param {Number} rx Radius along x axis (in units declared at inception of PDF document)
1246 * @param {Number} rx Radius along y axis (in units declared at inception of PDF document)
1247 * @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.
1248 * @function
1249 * @returns {jsPDF}
1250 * @methodOf jsPDF#
1251 * @name roundedRect
1252 */
1253 API.roundedRect = function(x, y, w, h, rx, ry, style) {
1254 var MyArc = 4 / 3 * (Math.SQRT2 - 1);
1255 this.lines(
1256 [
1257 [(w - 2 * rx), 0],
1258 [(rx * MyArc), 0, rx, ry - (ry * MyArc), rx, ry],
1259 [0, (h - 2 * ry)],
1260 [0, (ry * MyArc), - (rx * MyArc), ry, -rx, ry],
1261 [(-w + 2 * rx), 0],
1262 [ - (rx * MyArc), 0, -rx, - (ry * MyArc), -rx, -ry],
1263 [0, (-h + 2 * ry)],
1264 [0, - (ry * MyArc), (rx * MyArc), -ry, rx, -ry]
1265 ],
1266 x + rx,
1267 y, // start of path
1268 [1, 1],
1269 style);
1270 return this;
1271 };
1272
1273 /**
1274 * Adds an ellipse to PDF
1275 *
1276 * @param {Number} x Coordinate (in units declared at inception of PDF document) against left edge of the page
1277 * @param {Number} y Coordinate (in units declared at inception of PDF document) against upper edge of the page
1278 * @param {Number} rx Radius along x axis (in units declared at inception of PDF document)
1279 * @param {Number} rx Radius along y axis (in units declared at inception of PDF document)
1280 * @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.
1281 * @function
1282 * @returns {jsPDF}
1283 * @methodOf jsPDF#
1284 * @name ellipse
1285 */
1286 API.ellipse = function(x, y, rx, ry, style) {
1287 var lx = 4 / 3 * (Math.SQRT2 - 1) * rx,
1288 ly = 4 / 3 * (Math.SQRT2 - 1) * ry;
1289
1290 out([
1291 f2((x + rx) * k),
1292 f2((pageHeight - y) * k),
1293 'm',
1294 f2((x + rx) * k),
1295 f2((pageHeight - (y - ly)) * k),
1296 f2((x + lx) * k),
1297 f2((pageHeight - (y - ry)) * k),
1298 f2(x * k),
1299 f2((pageHeight - (y - ry)) * k),
1300 'c'
1301 ].join(' '));
1302 out([
1303 f2((x - lx) * k),
1304 f2((pageHeight - (y - ry)) * k),
1305 f2((x - rx) * k),
1306 f2((pageHeight - (y - ly)) * k),
1307 f2((x - rx) * k),
1308 f2((pageHeight - y) * k),
1309 'c'
1310 ].join(' '));
1311 out([
1312 f2((x - rx) * k),
1313 f2((pageHeight - (y + ly)) * k),
1314 f2((x - lx) * k),
1315 f2((pageHeight - (y + ry)) * k),
1316 f2(x * k),
1317 f2((pageHeight - (y + ry)) * k),
1318 'c'
1319 ].join(' '));
1320 out([
1321 f2((x + lx) * k),
1322 f2((pageHeight - (y + ry)) * k),
1323 f2((x + rx) * k),
1324 f2((pageHeight - (y + ly)) * k),
1325 f2((x + rx) * k),
1326 f2((pageHeight - y) * k),
1327 'c'
1328 ].join(' '));
1329
1330 if (style !== null) {
1331 out(getStyle(style));
1332 }
1333
1334 return this;
1335 };
1336
1337 /**
1338 * Adds an circle to PDF
1339 *
1340 * @param {Number} x Coordinate (in units declared at inception of PDF document) against left edge of the page
1341 * @param {Number} y Coordinate (in units declared at inception of PDF document) against upper edge of the page
1342 * @param {Number} r Radius (in units declared at inception of PDF document)
1343 * @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.
1344 * @function
1345 * @returns {jsPDF}
1346 * @methodOf jsPDF#
1347 * @name circle
1348 */
1349 API.circle = function(x, y, r, style) {
1350 return this.ellipse(x, y, r, r, style);
1351 };
1352
1353 /**
1354 * Adds a properties to the PDF document
1355 *
1356 * @param {Object} A property_name-to-property_value object structure.
1357 * @function
1358 * @returns {jsPDF}
1359 * @methodOf jsPDF#
1360 * @name setProperties
1361 */
1362 API.setProperties = function(properties) {
1363 // copying only those properties we can render.
1364 for (var property in documentProperties) {
1365 if (documentProperties.hasOwnProperty(property) && properties[property]) {
1366 documentProperties[property] = properties[property];
1367 }
1368 }
1369 return this;
1370 };
1371
1372 /**
1373 * Sets font size for upcoming text elements.
1374 *
1375 * @param {Number} size Font size in points.
1376 * @function
1377 * @returns {jsPDF}
1378 * @methodOf jsPDF#
1379 * @name setFontSize
1380 */
1381 API.setFontSize = function(size) {
1382 activeFontSize = size;
1383 return this;
1384 };
1385
1386 /**
1387 * Sets text font face, variant for upcoming text elements.
1388 * See output of jsPDF.getFontList() for possible font names, styles.
1389 *
1390 * @param {String} fontName Font name or family. Example: "times"
1391 * @param {String} fontStyle Font style or variant. Example: "italic"
1392 * @function
1393 * @returns {jsPDF}
1394 * @methodOf jsPDF#
1395 * @name setFont
1396 */
1397 API.setFont = function(fontName, fontStyle) {
1398 activeFontKey = getFont(fontName, fontStyle);
1399 // if font is not found, the above line blows up and we never go further
1400 return this;
1401 };
1402
1403 /**
1404 * Switches font style or variant for upcoming text elements,
1405 * while keeping the font face or family same.
1406 * See output of jsPDF.getFontList() for possible font names, styles.
1407 *
1408 * @param {String} style Font style or variant. Example: "italic"
1409 * @function
1410 * @returns {jsPDF}
1411 * @methodOf jsPDF#
1412 * @name setFontStyle
1413 */
1414 API.setFontStyle = API.setFontType = function(style) {
1415 activeFontKey = getFont(undefined, style);
1416 // if font is not found, the above line blows up and we never go further
1417 return this;
1418 };
1419
1420 /**
1421 * Returns an object - a tree of fontName to fontStyle relationships available to
1422 * active PDF document.
1423 *
1424 * @public
1425 * @function
1426 * @returns {Object} Like {'times':['normal', 'italic', ... ], 'arial':['normal', 'bold', ... ], ... }
1427 * @methodOf jsPDF#
1428 * @name getFontList
1429 */
1430 API.getFontList = function() {
1431 // TODO: iterate over fonts array or return copy of fontmap instead in case more are ever added.
1432 var list = {},fontName,fontStyle,tmp;
1433
1434 for (fontName in fontmap) {
1435 if (fontmap.hasOwnProperty(fontName)) {
1436 list[fontName] = tmp = [];
1437 for (fontStyle in fontmap[fontName]) {
1438 if (fontmap[fontName].hasOwnProperty(fontStyle)) {
1439 tmp.push(fontStyle);
1440 }
1441 }
1442 }
1443 }
1444
1445 return list;
1446 };
1447
1448 /**
1449 * Sets line width for upcoming lines.
1450 *
1451 * @param {Number} width Line width (in units declared at inception of PDF document)
1452 * @function
1453 * @returns {jsPDF}
1454 * @methodOf jsPDF#
1455 * @name setLineWidth
1456 */
1457 API.setLineWidth = function(width) {
1458 out((width * k).toFixed(2) + ' w');
1459 return this;
1460 };
1461
1462 /**
1463 * Sets the stroke color for upcoming elements.
1464 *
1465 * Depending on the number of arguments given, Gray, RGB, or CMYK
1466 * color space is implied.
1467 *
1468 * When only ch1 is given, "Gray" color space is implied and it
1469 * must be a value in the range from 0.00 (solid black) to to 1.00 (white)
1470 * if values are communicated as String types, or in range from 0 (black)
1471 * to 255 (white) if communicated as Number type.
1472 * The RGB-like 0-255 range is provided for backward compatibility.
1473 *
1474 * When only ch1,ch2,ch3 are given, "RGB" color space is implied and each
1475 * value must be in the range from 0.00 (minimum intensity) to to 1.00
1476 * (max intensity) if values are communicated as String types, or
1477 * from 0 (min intensity) to to 255 (max intensity) if values are communicated
1478 * as Number types.
1479 * The RGB-like 0-255 range is provided for backward compatibility.
1480 *
1481 * When ch1,ch2,ch3,ch4 are given, "CMYK" color space is implied and each
1482 * value must be a in the range from 0.00 (0% concentration) to to
1483 * 1.00 (100% concentration)
1484 *
1485 * Because JavaScript treats fixed point numbers badly (rounds to
1486 * floating point nearest to binary representation) it is highly advised to
1487 * communicate the fractional numbers as String types, not JavaScript Number type.
1488 *
1489 * @param {Number|String} ch1 Color channel value
1490 * @param {Number|String} ch2 Color channel value
1491 * @param {Number|String} ch3 Color channel value
1492 * @param {Number|String} ch4 Color channel value
1493 *
1494 * @function
1495 * @returns {jsPDF}
1496 * @methodOf jsPDF#
1497 * @name setDrawColor
1498 */
1499 API.setDrawColor = function(ch1, ch2, ch3, ch4) {
1500 var color;
1501 if (ch2 === undefined || (ch4 === undefined && ch1 === ch2 === ch3)) {
1502 // Gray color space.
1503 if (typeof ch1 === 'string') {
1504 color = ch1 + ' G';
1505 } else {
1506 color = f2(ch1 / 255) + ' G';
1507 }
1508 } else if (ch4 === undefined) {
1509 // RGB
1510 if (typeof ch1 === 'string') {
1511 color = [ch1, ch2, ch3, 'RG'].join(' ');
1512 } else {
1513 color = [f2(ch1 / 255), f2(ch2 / 255), f2(ch3 / 255), 'RG'].join(' ');
1514 }
1515 } else {
1516 // CMYK
1517 if (typeof ch1 === 'string') {
1518 color = [ch1, ch2, ch3, ch4, 'K'].join(' ');
1519 } else {
1520 color = [f2(ch1), f2(ch2), f2(ch3), f2(ch4), 'K'].join(' ');
1521 }
1522 }
1523
1524 out(color);
1525 return this;
1526 };
1527
1528 /**
1529 * Sets the fill color for upcoming elements.
1530 *
1531 * Depending on the number of arguments given, Gray, RGB, or CMYK
1532 * color space is implied.
1533 *
1534 * When only ch1 is given, "Gray" color space is implied and it
1535 * must be a value in the range from 0.00 (solid black) to to 1.00 (white)
1536 * if values are communicated as String types, or in range from 0 (black)
1537 * to 255 (white) if communicated as Number type.
1538 * The RGB-like 0-255 range is provided for backward compatibility.
1539 *
1540 * When only ch1,ch2,ch3 are given, "RGB" color space is implied and each
1541 * value must be in the range from 0.00 (minimum intensity) to to 1.00
1542 * (max intensity) if values are communicated as String types, or
1543 * from 0 (min intensity) to to 255 (max intensity) if values are communicated
1544 * as Number types.
1545 * The RGB-like 0-255 range is provided for backward compatibility.
1546 *
1547 * When ch1,ch2,ch3,ch4 are given, "CMYK" color space is implied and each
1548 * value must be a in the range from 0.00 (0% concentration) to to
1549 * 1.00 (100% concentration)
1550 *
1551 * Because JavaScript treats fixed point numbers badly (rounds to
1552 * floating point nearest to binary representation) it is highly advised to
1553 * communicate the fractional numbers as String types, not JavaScript Number type.
1554 *
1555 * @param {Number|String} ch1 Color channel value
1556 * @param {Number|String} ch2 Color channel value
1557 * @param {Number|String} ch3 Color channel value
1558 * @param {Number|String} ch4 Color channel value
1559 *
1560 * @function
1561 * @returns {jsPDF}
1562 * @methodOf jsPDF#
1563 * @name setFillColor
1564 */
1565 API.setFillColor = function(ch1, ch2, ch3, ch4) {
1566 var color;
1567
1568 if (ch2 === undefined || (ch4 === undefined && ch1 === ch2 === ch3)) {
1569 // Gray color space.
1570 if (typeof ch1 === 'string') {
1571 color = ch1 + ' g';
1572 } else {
1573 color = f2(ch1 / 255) + ' g';
1574 }
1575 } else if (ch4 === undefined) {
1576 // RGB
1577 if (typeof ch1 === 'string') {
1578 color = [ch1, ch2, ch3, 'rg'].join(' ');
1579 } else {
1580 color = [f2(ch1 / 255), f2(ch2 / 255), f2(ch3 / 255), 'rg'].join(' ');
1581 }
1582 } else {
1583 // CMYK
1584 if (typeof ch1 === 'string') {
1585 color = [ch1, ch2, ch3, ch4, 'k'].join(' ');
1586 } else {
1587 color = [f2(ch1), f2(ch2), f2(ch3), f2(ch4), 'k'].join(' ');
1588 }
1589 }
1590
1591 out(color);
1592 return this;
1593 };
1594
1595 /**
1596 * Sets the text color for upcoming elements.
1597 * If only one, first argument is given,
1598 * treats the value as gray-scale color value.
1599 *
1600 * @param {Number} r Red channel color value in range 0-255 or {String} r color value in hexadecimal, example: '#FFFFFF'
1601 * @param {Number} g Green channel color value in range 0-255
1602 * @param {Number} b Blue channel color value in range 0-255
1603 * @function
1604 * @returns {jsPDF}
1605 * @methodOf jsPDF#
1606 * @name setTextColor
1607 */
1608 API.setTextColor = function(r, g, b) {
1609 if ((typeof r === 'string') && /^#[0-9A-Fa-f]{6}$/.test(r)) {
1610 var hex = parseInt(r.substr(1), 16);
1611 r = (hex >> 16) & 255;
1612 g = (hex >> 8) & 255;
1613 b = (hex & 255);
1614 }
1615
1616 if ((r === 0 && g === 0 && b === 0) || (typeof g === 'undefined')) {
1617 textColor = f3(r / 255) + ' g';
1618 } else {
1619 textColor = [f3(r / 255), f3(g / 255), f3(b / 255), 'rg'].join(' ');
1620 }
1621 return this;
1622 };
1623
1624 /**
1625 * Is an Object providing a mapping from human-readable to
1626 * integer flag values designating the varieties of line cap
1627 * and join styles.
1628 *
1629 * @returns {Object}
1630 * @fieldOf jsPDF#
1631 * @name CapJoinStyles
1632 */
1633 API.CapJoinStyles = {
1634 0 : 0,
1635 'butt' : 0,
1636 'but' : 0,
1637 'miter' : 0,
1638 1 : 1,
1639 'round' : 1,
1640 'rounded' : 1,
1641 'circle' : 1,
1642 2 : 2,
1643 'projecting' : 2,
1644 'project' : 2,
1645 'square' : 2,
1646 'bevel' : 2
1647 };
1648
1649 /**
1650 * Sets the line cap styles
1651 * See {jsPDF.CapJoinStyles} for variants
1652 *
1653 * @param {String|Number} style A string or number identifying the type of line cap
1654 * @function
1655 * @returns {jsPDF}
1656 * @methodOf jsPDF#
1657 * @name setLineCap
1658 */
1659 API.setLineCap = function(style) {
1660 var id = this.CapJoinStyles[style];
1661 if (id === undefined) {
1662 throw new Error("Line cap style of '" + style + "' is not recognized. See or extend .CapJoinStyles property for valid styles");
1663 }
1664 lineCapID = id;
1665 out(id + ' J');
1666
1667 return this;
1668 };
1669
1670 /**
1671 * Sets the line join styles
1672 * See {jsPDF.CapJoinStyles} for variants
1673 *
1674 * @param {String|Number} style A string or number identifying the type of line join
1675 * @function
1676 * @returns {jsPDF}
1677 * @methodOf jsPDF#
1678 * @name setLineJoin
1679 */
1680 API.setLineJoin = function(style) {
1681 var id = this.CapJoinStyles[style];
1682 if (id === undefined) {
1683 throw new Error("Line join style of '" + style + "' is not recognized. See or extend .CapJoinStyles property for valid styles");
1684 }
1685 lineJoinID = id;
1686 out(id + ' j');
1687
1688 return this;
1689 };
1690
1691 // Output is both an internal (for plugins) and external function
1692 API.output = output;
1693
1694 /**
1695 * Saves as PDF document. An alias of jsPDF.output('save', 'filename.pdf')
1696 * @param {String} filename The filename including extension.
1697 *
1698 * @function
1699 * @returns {jsPDF}
1700 * @methodOf jsPDF#
1701 * @name save
1702 */
1703 API.save = function(filename) {
1704 API.output('save', filename);
1705 };
1706
1707 // applying plugins (more methods) ON TOP of built-in API.
1708 // this is intentional as we allow plugins to override
1709 // built-ins
1710 for (var plugin in jsPDF.API) {
1711 if (jsPDF.API.hasOwnProperty(plugin)) {
1712 if (plugin === 'events' && jsPDF.API.events.length) {
1713 (function(events, newEvents) {
1714
1715 // jsPDF.API.events is a JS Array of Arrays
1716 // where each Array is a pair of event name, handler
1717 // Events were added by plugins to the jsPDF instantiator.
1718 // These are always added to the new instance and some ran
1719 // during instantiation.
1720 var eventname,handler_and_args,i;
1721
1722 for (i = newEvents.length - 1; i !== -1; i--) {
1723 // subscribe takes 3 args: 'topic', function, runonce_flag
1724 // if undefined, runonce is false.
1725 // users can attach callback directly,
1726 // or they can attach an array with [callback, runonce_flag]
1727 // that's what the "apply" magic is for below.
1728 eventname = newEvents[i][0];
1729 handler_and_args = newEvents[i][1];
1730 events.subscribe.apply(
1731 events,
1732 [eventname].concat(
1733 typeof handler_and_args === 'function' ?
1734 [handler_and_args] : handler_and_args));
1735 }
1736 }(events, jsPDF.API.events));
1737 } else {
1738 API[plugin] = jsPDF.API[plugin];
1739 }
1740 }
1741 }
1742
1743 //////////////////////////////////////////////////////
1744 // continuing initialization of jsPDF Document object
1745 //////////////////////////////////////////////////////
1746 // Add the first page automatically
1747 addFonts();
1748 activeFontKey = 'F1';
1749 _addPage(format, orientation);
1750
1751 events.publish('initialized');
1752 return API;
1753 }
1754
1755 /**
1756 * jsPDF.API is a STATIC property of jsPDF class.
1757 * jsPDF.API is an object you can add methods and properties to.
1758 * The methods / properties you add will show up in new jsPDF objects.
1759 *
1760 * One property is prepopulated. It is the 'events' Object. Plugin authors can add topics,
1761 * callbacks to this object. These will be reassigned to all new instances of jsPDF.
1762 * Examples:
1763 * jsPDF.API.events['initialized'] = function(){ 'this' is API object }
1764 * jsPDF.API.events['addFont'] = function(added_font_object){ 'this' is API object }
1765 *
1766 * @static
1767 * @public
1768 * @memberOf jsPDF
1769 * @name API
1770 *
1771 * @example
1772 * jsPDF.API.mymethod = function(){
1773 * // 'this' will be ref to internal API object. see jsPDF source
1774 * // , so you can refer to built-in methods like so:
1775 * // this.line(....)
1776 * // this.text(....)
1777 * }
1778 * var pdfdoc = new jsPDF()
1779 * pdfdoc.mymethod() // <- !!!!!!
1780 */
1781 jsPDF.API = {events:[]};
1782 jsPDF.version = "1.0.272-debug 2014-09-29T15:09:diegocr";
1783
1784 if (typeof define === 'function' && define.amd) {
1785 define('jsPDF', function() {
1786 return jsPDF;
1787 });
1788 } else {
1789 global.jsPDF = jsPDF;
1790 }
1791 return jsPDF;
1792}(typeof self !== "undefined" && self || typeof window !== "undefined" && window || this));
1793/**
1794 * jsPDF addHTML PlugIn
1795 * Copyright (c) 2014 Diego Casorran
1796 *
1797 * Licensed under the MIT License.
1798 * http://opensource.org/licenses/mit-license
1799 */
1800
1801(function (jsPDFAPI) {
1802 'use strict';
1803
1804 /**
1805 * Renders an HTML element to canvas object which added as an image to the PDF
1806 *
1807 * This PlugIn requires html2canvas: https://github.com/niklasvh/html2canvas
1808 * OR rasterizeHTML: https://github.com/cburgmer/rasterizeHTML.js
1809 *
1810 * @public
1811 * @function
1812 * @param element {Mixed} HTML Element, or anything supported by html2canvas.
1813 * @param x {Number} starting X coordinate in jsPDF instance's declared units.
1814 * @param y {Number} starting Y coordinate in jsPDF instance's declared units.
1815 * @param options {Object} Additional options, check the code below.
1816 * @param callback {Function} to call when the rendering has finished.
1817 *
1818 * NOTE: Every parameter is optional except 'element' and 'callback', in such
1819 * case the image is positioned at 0x0 covering the whole PDF document
1820 * size. Ie, to easily take screenshoots of webpages saving them to PDF.
1821 */
1822 jsPDFAPI.addHTML = function (element, x, y, options, callback) {
1823 'use strict';
1824
1825 if(typeof html2canvas === 'undefined' && typeof rasterizeHTML === 'undefined')
1826 throw new Error('You need either '
1827 +'https://github.com/niklasvh/html2canvas'
1828 +' or https://github.com/cburgmer/rasterizeHTML.js');
1829
1830 if(typeof x !== 'number') {
1831 options = x;
1832 callback = y;
1833 }
1834
1835 if(typeof options === 'function') {
1836 callback = options;
1837 options = null;
1838 }
1839
1840 var I = this.internal, K = I.scaleFactor, W = I.pageSize.width, H = I.pageSize.height;
1841
1842 options = options || {};
1843 options.onrendered = function(obj) {
1844 x = parseInt(x) || 0;
1845 y = parseInt(y) || 0;
1846 var dim = options.dim || {};
1847 var h = dim.h || 0;
1848 var w = dim.w || Math.min(W,obj.width/K) - x;
1849
1850 var format = 'JPEG';
1851 if(options.format)
1852 format = options.format;
1853
1854 if(obj.height > H && options.pagesplit) {
1855 var crop = function() {
1856 var cy = 0;
1857 while(1) {
1858 var canvas = document.createElement('canvas');
1859 canvas.width = Math.min(W*K,obj.width);
1860 canvas.height = Math.min(H*K,obj.height-cy);
1861 var ctx = canvas.getContext('2d');
1862 ctx.drawImage(obj,0,cy,obj.width,canvas.height,0,0,canvas.width,canvas.height);
1863 var args = [canvas, x,cy?0:y,canvas.width/K,canvas.height/K, format,null,'SLOW'];
1864 this.addImage.apply(this, args);
1865 cy += canvas.height;
1866 if(cy >= obj.height) break;
1867 this.addPage();
1868 }
1869 callback(w,cy,null,args);
1870 }.bind(this);
1871 if(obj.nodeName === 'CANVAS') {
1872 var img = new Image();
1873 img.onload = crop;
1874 img.src = obj.toDataURL("image/png");
1875 obj = img;
1876 } else {
1877 crop();
1878 }
1879 } else {
1880 var alias = Math.random().toString(35);
1881 var args = [obj, x,y,w,h, format,alias,'SLOW'];
1882
1883 this.addImage.apply(this, args);
1884
1885 callback(w,h,alias,args);
1886 }
1887 }.bind(this);
1888
1889 if(typeof html2canvas !== 'undefined' && !options.rstz) {
1890 return html2canvas(element, options);
1891 }
1892
1893 if(typeof rasterizeHTML !== 'undefined') {
1894 var meth = 'drawDocument';
1895 if(typeof element === 'string') {
1896 meth = /^http/.test(element) ? 'drawURL' : 'drawHTML';
1897 }
1898 options.width = options.width || (W*K);
1899 return rasterizeHTML[meth](element, void 0, options).then(function(r) {
1900 options.onrendered(r.image);
1901 }, function(e) {
1902 callback(null,e);
1903 });
1904 }
1905
1906 return null;
1907 };
1908})(jsPDF.API);
1909/** @preserve
1910 * jsPDF addImage plugin
1911 * Copyright (c) 2012 Jason Siefken, https://github.com/siefkenj/
1912 * 2013 Chris Dowling, https://github.com/gingerchris
1913 * 2013 Trinh Ho, https://github.com/ineedfat
1914 * 2013 Edwin Alejandro Perez, https://github.com/eaparango
1915 * 2013 Norah Smith, https://github.com/burnburnrocket
1916 * 2014 Diego Casorran, https://github.com/diegocr
1917 * 2014 James Robb, https://github.com/jamesbrobb
1918 *
1919 * Permission is hereby granted, free of charge, to any person obtaining
1920 * a copy of this software and associated documentation files (the
1921 * "Software"), to deal in the Software without restriction, including
1922 * without limitation the rights to use, copy, modify, merge, publish,
1923 * distribute, sublicense, and/or sell copies of the Software, and to
1924 * permit persons to whom the Software is furnished to do so, subject to
1925 * the following conditions:
1926 *
1927 * The above copyright notice and this permission notice shall be
1928 * included in all copies or substantial portions of the Software.
1929 *
1930 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
1931 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
1932 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
1933 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
1934 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
1935 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
1936 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
1937 */
1938
1939;(function(jsPDFAPI) {
1940 'use strict'
1941
1942 var namespace = 'addImage_',
1943 supported_image_types = ['jpeg', 'jpg', 'png'];
1944
1945 // Image functionality ported from pdf.js
1946 var putImage = function(img) {
1947
1948 var objectNumber = this.internal.newObject()
1949 , out = this.internal.write
1950 , putStream = this.internal.putStream
1951
1952 img['n'] = objectNumber
1953
1954 out('<</Type /XObject')
1955 out('/Subtype /Image')
1956 out('/Width ' + img['w'])
1957 out('/Height ' + img['h'])
1958 if (img['cs'] === this.color_spaces.INDEXED) {
1959 out('/ColorSpace [/Indexed /DeviceRGB '
1960 // if an indexed png defines more than one colour with transparency, we've created a smask
1961 + (img['pal'].length / 3 - 1) + ' ' + ('smask' in img ? objectNumber + 2 : objectNumber + 1)
1962 + ' 0 R]');
1963 } else {
1964 out('/ColorSpace /' + img['cs']);
1965 if (img['cs'] === this.color_spaces.DEVICE_CMYK) {
1966 out('/Decode [1 0 1 0 1 0 1 0]');
1967 }
1968 }
1969 out('/BitsPerComponent ' + img['bpc']);
1970 if ('f' in img) {
1971 out('/Filter /' + img['f']);
1972 }
1973 if ('dp' in img) {
1974 out('/DecodeParms <<' + img['dp'] + '>>');
1975 }
1976 if ('trns' in img && img['trns'].constructor == Array) {
1977 var trns = '',
1978 i = 0,
1979 len = img['trns'].length;
1980 for (; i < len; i++)
1981 trns += (img['trns'][i] + ' ' + img['trns'][i] + ' ');
1982 out('/Mask [' + trns + ']');
1983 }
1984 if ('smask' in img) {
1985 out('/SMask ' + (objectNumber + 1) + ' 0 R');
1986 }
1987 out('/Length ' + img['data'].length + '>>');
1988
1989 putStream(img['data']);
1990
1991 out('endobj');
1992
1993 // Soft mask
1994 if ('smask' in img) {
1995 var dp = '/Predictor 15 /Colors 1 /BitsPerComponent ' + img['bpc'] + ' /Columns ' + img['w'];
1996 var smask = {'w': img['w'], 'h': img['h'], 'cs': 'DeviceGray', 'bpc': img['bpc'], 'dp': dp, 'data': img['smask']};
1997 if ('f' in img)
1998 smask.f = img['f'];
1999 putImage.call(this, smask);
2000 }
2001
2002 //Palette
2003 if (img['cs'] === this.color_spaces.INDEXED) {
2004
2005 this.internal.newObject();
2006 //out('<< /Filter / ' + img['f'] +' /Length ' + img['pal'].length + '>>');
2007 //putStream(zlib.compress(img['pal']));
2008 out('<< /Length ' + img['pal'].length + '>>');
2009 putStream(this.arrayBufferToBinaryString(new Uint8Array(img['pal'])));
2010 out('endobj');
2011 }
2012 }
2013 , putResourcesCallback = function() {
2014 var images = this.internal.collections[namespace + 'images']
2015 for ( var i in images ) {
2016 putImage.call(this, images[i])
2017 }
2018 }
2019 , putXObjectsDictCallback = function(){
2020 var images = this.internal.collections[namespace + 'images']
2021 , out = this.internal.write
2022 , image
2023 for (var i in images) {
2024 image = images[i]
2025 out(
2026 '/I' + image['i']
2027 , image['n']
2028 , '0'
2029 , 'R'
2030 )
2031 }
2032 }
2033 , checkCompressValue = function(value) {
2034 if(value && typeof value === 'string')
2035 value = value.toUpperCase();
2036 return value in jsPDFAPI.image_compression ? value : jsPDFAPI.image_compression.NONE;
2037 }
2038 , getImages = function() {
2039 var images = this.internal.collections[namespace + 'images'];
2040 //first run, so initialise stuff
2041 if(!images) {
2042 this.internal.collections[namespace + 'images'] = images = {};
2043 this.internal.events.subscribe('putResources', putResourcesCallback);
2044 this.internal.events.subscribe('putXobjectDict', putXObjectsDictCallback);
2045 }
2046
2047 return images;
2048 }
2049 , getImageIndex = function(images) {
2050 var imageIndex = 0;
2051
2052 if (images){
2053 // this is NOT the first time this method is ran on this instance of jsPDF object.
2054 imageIndex = Object.keys ?
2055 Object.keys(images).length :
2056 (function(o){
2057 var i = 0
2058 for (var e in o){if(o.hasOwnProperty(e)){ i++ }}
2059 return i
2060 })(images)
2061 }
2062
2063 return imageIndex;
2064 }
2065 , notDefined = function(value) {
2066 return typeof value === 'undefined' || value === null;
2067 }
2068 , generateAliasFromData = function(data) {
2069 return typeof data === 'string' && jsPDFAPI.sHashCode(data);
2070 }
2071 , doesNotSupportImageType = function(type) {
2072 return supported_image_types.indexOf(type) === -1;
2073 }
2074 , processMethodNotEnabled = function(type) {
2075 return typeof jsPDFAPI['process' + type.toUpperCase()] !== 'function';
2076 }
2077 , isDOMElement = function(object) {
2078 return typeof object === 'object' && object.nodeType === 1;
2079 }
2080 , createDataURIFromElement = function(element, format, angle) {
2081
2082 //if element is an image which uses data url defintion, just return the dataurl
2083 if (element.nodeName === 'IMG' && element.hasAttribute('src')) {
2084 var src = ''+element.getAttribute('src');
2085 if (!angle && src.indexOf('data:image/') === 0) return src;
2086
2087 // only if the user doesn't care about a format
2088 if (!format && /\.png(?:[?#].*)?$/i.test(src)) format = 'png';
2089 }
2090
2091 if(element.nodeName === 'CANVAS') {
2092 var canvas = element;
2093 } else {
2094 var canvas = document.createElement('canvas');
2095 canvas.width = element.clientWidth || element.width;
2096 canvas.height = element.clientHeight || element.height;
2097
2098 var ctx = canvas.getContext('2d');
2099 if (!ctx) {
2100 throw ('addImage requires canvas to be supported by browser.');
2101 }
2102 if (angle) {
2103 var x, y, b, c, s, w, h, to_radians = Math.PI/180, angleInRadians;
2104
2105 if (typeof angle === 'object') {
2106 x = angle.x;
2107 y = angle.y;
2108 b = angle.bg;
2109 angle = angle.angle;
2110 }
2111 angleInRadians = angle*to_radians;
2112 c = Math.abs(Math.cos(angleInRadians));
2113 s = Math.abs(Math.sin(angleInRadians));
2114 w = canvas.width;
2115 h = canvas.height;
2116 canvas.width = h * s + w * c;
2117 canvas.height = h * c + w * s;
2118
2119 if (isNaN(x)) x = canvas.width / 2;
2120 if (isNaN(y)) y = canvas.height / 2;
2121
2122 ctx.clearRect(0,0,canvas.width, canvas.height);
2123 ctx.fillStyle = b || 'white';
2124 ctx.fillRect(0, 0, canvas.width, canvas.height);
2125 ctx.save();
2126 ctx.translate(x, y);
2127 ctx.rotate(angleInRadians);
2128 ctx.drawImage(element, -(w/2), -(h/2));
2129 ctx.rotate(-angleInRadians);
2130 ctx.translate(-x, -y);
2131 ctx.restore();
2132 } else {
2133 ctx.drawImage(element, 0, 0, canvas.width, canvas.height);
2134 }
2135 }
2136 return canvas.toDataURL((''+format).toLowerCase() == 'png' ? 'image/png' : 'image/jpeg');
2137 }
2138 ,checkImagesForAlias = function(alias, images) {
2139 var cached_info;
2140 if(images) {
2141 for(var e in images) {
2142 if(alias === images[e].alias) {
2143 cached_info = images[e];
2144 break;
2145 }
2146 }
2147 }
2148 return cached_info;
2149 }
2150 ,determineWidthAndHeight = function(w, h, info) {
2151 if (!w && !h) {
2152 w = -96;
2153 h = -96;
2154 }
2155 if (w < 0) {
2156 w = (-1) * info['w'] * 72 / w / this.internal.scaleFactor;
2157 }
2158 if (h < 0) {
2159 h = (-1) * info['h'] * 72 / h / this.internal.scaleFactor;
2160 }
2161 if (w === 0) {
2162 w = h * info['w'] / info['h'];
2163 }
2164 if (h === 0) {
2165 h = w * info['h'] / info['w'];
2166 }
2167
2168 return [w, h];
2169 }
2170 , writeImageToPDF = function(x, y, w, h, info, index, images) {
2171 var dims = determineWidthAndHeight.call(this, w, h, info),
2172 coord = this.internal.getCoordinateString,
2173 vcoord = this.internal.getVerticalCoordinateString;
2174
2175 w = dims[0];
2176 h = dims[1];
2177
2178 images[index] = info;
2179
2180 this.internal.write(
2181 'q'
2182 , coord(w)
2183 , '0 0'
2184 , coord(h) // TODO: check if this should be shifted by vcoord
2185 , coord(x)
2186 , vcoord(y + h)
2187 , 'cm /I'+info['i']
2188 , 'Do Q'
2189 )
2190 };
2191
2192 /**
2193 * COLOR SPACES
2194 */
2195 jsPDFAPI.color_spaces = {
2196 DEVICE_RGB:'DeviceRGB',
2197 DEVICE_GRAY:'DeviceGray',
2198 DEVICE_CMYK:'DeviceCMYK',
2199 CAL_GREY:'CalGray',
2200 CAL_RGB:'CalRGB',
2201 LAB:'Lab',
2202 ICC_BASED:'ICCBased',
2203 INDEXED:'Indexed',
2204 PATTERN:'Pattern',
2205 SEPERATION:'Seperation',
2206 DEVICE_N:'DeviceN'
2207 };
2208
2209 /**
2210 * DECODE METHODS
2211 */
2212 jsPDFAPI.decode = {
2213 DCT_DECODE:'DCTDecode',
2214 FLATE_DECODE:'FlateDecode',
2215 LZW_DECODE:'LZWDecode',
2216 JPX_DECODE:'JPXDecode',
2217 JBIG2_DECODE:'JBIG2Decode',
2218 ASCII85_DECODE:'ASCII85Decode',
2219 ASCII_HEX_DECODE:'ASCIIHexDecode',
2220 RUN_LENGTH_DECODE:'RunLengthDecode',
2221 CCITT_FAX_DECODE:'CCITTFaxDecode'
2222 };
2223
2224 /**
2225 * IMAGE COMPRESSION TYPES
2226 */
2227 jsPDFAPI.image_compression = {
2228 NONE: 'NONE',
2229 FAST: 'FAST',
2230 MEDIUM: 'MEDIUM',
2231 SLOW: 'SLOW'
2232 };
2233
2234 jsPDFAPI.sHashCode = function(str) {
2235 return Array.prototype.reduce && str.split("").reduce(function(a,b){a=((a<<5)-a)+b.charCodeAt(0);return a&a},0);
2236 };
2237
2238 jsPDFAPI.isString = function(object) {
2239 return typeof object === 'string';
2240 };
2241
2242 /**
2243 * Strips out and returns info from a valid base64 data URI
2244 * @param {String[dataURI]} a valid data URI of format 'data:[<MIME-type>][;base64],<data>'
2245 * @returns an Array containing the following
2246 * [0] the complete data URI
2247 * [1] <MIME-type>
2248 * [2] format - the second part of the mime-type i.e 'png' in 'image/png'
2249 * [4] <data>
2250 */
2251 jsPDFAPI.extractInfoFromBase64DataURI = function(dataURI) {
2252 return /^data:([\w]+?\/([\w]+?));base64,(.+?)$/g.exec(dataURI);
2253 };
2254
2255 /**
2256 * Check to see if ArrayBuffer is supported
2257 */
2258 jsPDFAPI.supportsArrayBuffer = function() {
2259 return typeof ArrayBuffer !== 'undefined' && typeof Uint8Array !== 'undefined';
2260 };
2261
2262 /**
2263 * Tests supplied object to determine if ArrayBuffer
2264 * @param {Object[object]}
2265 */
2266 jsPDFAPI.isArrayBuffer = function(object) {
2267 if(!this.supportsArrayBuffer())
2268 return false;
2269 return object instanceof ArrayBuffer;
2270 };
2271
2272 /**
2273 * Tests supplied object to determine if it implements the ArrayBufferView (TypedArray) interface
2274 * @param {Object[object]}
2275 */
2276 jsPDFAPI.isArrayBufferView = function(object) {
2277 if(!this.supportsArrayBuffer())
2278 return false;
2279 if(typeof Uint32Array === 'undefined')
2280 return false;
2281 return (object instanceof Int8Array ||
2282 object instanceof Uint8Array ||
2283 (typeof Uint8ClampedArray !== 'undefined' && object instanceof Uint8ClampedArray) ||
2284 object instanceof Int16Array ||
2285 object instanceof Uint16Array ||
2286 object instanceof Int32Array ||
2287 object instanceof Uint32Array ||
2288 object instanceof Float32Array ||
2289 object instanceof Float64Array );
2290 };
2291
2292 /**
2293 * Exactly what it says on the tin
2294 */
2295 jsPDFAPI.binaryStringToUint8Array = function(binary_string) {
2296 /*
2297 * not sure how efficient this will be will bigger files. Is there a native method?
2298 */
2299 var len = binary_string.length;
2300 var bytes = new Uint8Array( len );
2301 for (var i = 0; i < len; i++) {
2302 bytes[i] = binary_string.charCodeAt(i);
2303 }
2304 return bytes;
2305 };
2306
2307 /**
2308 * @see this discussion
2309 * http://stackoverflow.com/questions/6965107/converting-between-strings-and-arraybuffers
2310 *
2311 * As stated, i imagine the method below is highly inefficent for large files.
2312 *
2313 * Also of note from Mozilla,
2314 *
2315 * "However, this is slow and error-prone, due to the need for multiple conversions (especially if the binary data is not actually byte-format data, but, for example, 32-bit integers or floats)."
2316 *
2317 * https://developer.mozilla.org/en-US/Add-ons/Code_snippets/StringView
2318 *
2319 * Although i'm strugglig to see how StringView solves this issue? Doesn't appear to be a direct method for conversion?
2320 *
2321 * Async method using Blob and FileReader could be best, but i'm not sure how to fit it into the flow?
2322 */
2323 jsPDFAPI.arrayBufferToBinaryString = function(buffer) {
2324 if(this.isArrayBuffer(buffer))
2325 buffer = new Uint8Array(buffer);
2326
2327 var binary_string = '';
2328 var len = buffer.byteLength;
2329 for (var i = 0; i < len; i++) {
2330 binary_string += String.fromCharCode(buffer[i]);
2331 }
2332 return binary_string;
2333 /*
2334 * Another solution is the method below - convert array buffer straight to base64 and then use atob
2335 */
2336 //return atob(this.arrayBufferToBase64(buffer));
2337 };
2338
2339 /**
2340 * Converts an ArrayBuffer directly to base64
2341 *
2342 * Taken from here
2343 *
2344 * http://jsperf.com/encoding-xhr-image-data/31
2345 *
2346 * Need to test if this is a better solution for larger files
2347 *
2348 */
2349 jsPDFAPI.arrayBufferToBase64 = function(arrayBuffer) {
2350 var base64 = ''
2351 var encodings = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
2352
2353 var bytes = new Uint8Array(arrayBuffer)
2354 var byteLength = bytes.byteLength
2355 var byteRemainder = byteLength % 3
2356 var mainLength = byteLength - byteRemainder
2357
2358 var a, b, c, d
2359 var chunk
2360
2361 // Main loop deals with bytes in chunks of 3
2362 for (var i = 0; i < mainLength; i = i + 3) {
2363 // Combine the three bytes into a single integer
2364 chunk = (bytes[i] << 16) | (bytes[i + 1] << 8) | bytes[i + 2]
2365
2366 // Use bitmasks to extract 6-bit segments from the triplet
2367 a = (chunk & 16515072) >> 18 // 16515072 = (2^6 - 1) << 18
2368 b = (chunk & 258048) >> 12 // 258048 = (2^6 - 1) << 12
2369 c = (chunk & 4032) >> 6 // 4032 = (2^6 - 1) << 6
2370 d = chunk & 63 // 63 = 2^6 - 1
2371
2372 // Convert the raw binary segments to the appropriate ASCII encoding
2373 base64 += encodings[a] + encodings[b] + encodings[c] + encodings[d]
2374 }
2375
2376 // Deal with the remaining bytes and padding
2377 if (byteRemainder == 1) {
2378 chunk = bytes[mainLength]
2379
2380 a = (chunk & 252) >> 2 // 252 = (2^6 - 1) << 2
2381
2382 // Set the 4 least significant bits to zero
2383 b = (chunk & 3) << 4 // 3 = 2^2 - 1
2384
2385 base64 += encodings[a] + encodings[b] + '=='
2386 } else if (byteRemainder == 2) {
2387 chunk = (bytes[mainLength] << 8) | bytes[mainLength + 1]
2388
2389 a = (chunk & 64512) >> 10 // 64512 = (2^6 - 1) << 10
2390 b = (chunk & 1008) >> 4 // 1008 = (2^6 - 1) << 4
2391
2392 // Set the 2 least significant bits to zero
2393 c = (chunk & 15) << 2 // 15 = 2^4 - 1
2394
2395 base64 += encodings[a] + encodings[b] + encodings[c] + '='
2396 }
2397
2398 return base64
2399 };
2400
2401 jsPDFAPI.createImageInfo = function(data, wd, ht, cs, bpc, f, imageIndex, alias, dp, trns, pal, smask) {
2402 var info = {
2403 alias:alias,
2404 w : wd,
2405 h : ht,
2406 cs : cs,
2407 bpc : bpc,
2408 i : imageIndex,
2409 data : data
2410 // n: objectNumber will be added by putImage code
2411 };
2412
2413 if(f) info.f = f;
2414 if(dp) info.dp = dp;
2415 if(trns) info.trns = trns;
2416 if(pal) info.pal = pal;
2417 if(smask) info.smask = smask;
2418
2419 return info;
2420 };
2421
2422 jsPDFAPI.addImage = function(imageData, format, x, y, w, h, alias, compression, rotation) {
2423 'use strict'
2424
2425 if(typeof format !== 'string') {
2426 var tmp = h;
2427 h = w;
2428 w = y;
2429 y = x;
2430 x = format;
2431 format = tmp;
2432 }
2433
2434 if (typeof imageData === 'object' && !isDOMElement(imageData) && "imageData" in imageData) {
2435 var options = imageData;
2436
2437 imageData = options.imageData;
2438 format = options.format || format;
2439 x = options.x || x || 0;
2440 y = options.y || y || 0;
2441 w = options.w || w;
2442 h = options.h || h;
2443 alias = options.alias || alias;
2444 compression = options.compression || compression;
2445 rotation = options.rotation || options.angle || rotation;
2446 }
2447
2448 if (isNaN(x) || isNaN(y))
2449 {
2450 console.error('jsPDF.addImage: Invalid coordinates', arguments);
2451 throw new Error('Invalid coordinates passed to jsPDF.addImage');
2452 }
2453
2454 var images = getImages.call(this), info;
2455
2456 if (!(info = checkImagesForAlias(imageData, images))) {
2457 var dataAsBinaryString;
2458
2459 if(isDOMElement(imageData))
2460 imageData = createDataURIFromElement(imageData, format, rotation);
2461
2462 if(notDefined(alias))
2463 alias = generateAliasFromData(imageData);
2464
2465 if (!(info = checkImagesForAlias(alias, images))) {
2466
2467 if(this.isString(imageData)) {
2468
2469 var base64Info = this.extractInfoFromBase64DataURI(imageData);
2470
2471 if(base64Info) {
2472
2473 format = base64Info[2];
2474 imageData = atob(base64Info[3]);//convert to binary string
2475
2476 } else {
2477
2478 if (imageData.charCodeAt(0) === 0x89 &&
2479 imageData.charCodeAt(1) === 0x50 &&
2480 imageData.charCodeAt(2) === 0x4e &&
2481 imageData.charCodeAt(3) === 0x47 ) format = 'png';
2482 }
2483 }
2484 format = (format || 'JPEG').toLowerCase();
2485
2486 if(doesNotSupportImageType(format))
2487 throw new Error('addImage currently only supports formats ' + supported_image_types + ', not \''+format+'\'');
2488
2489 if(processMethodNotEnabled(format))
2490 throw new Error('please ensure that the plugin for \''+format+'\' support is added');
2491
2492 /**
2493 * need to test if it's more efficent to convert all binary strings
2494 * to TypedArray - or should we just leave and process as string?
2495 */
2496 if(this.supportsArrayBuffer()) {
2497 dataAsBinaryString = imageData;
2498 imageData = this.binaryStringToUint8Array(imageData);
2499 }
2500
2501 info = this['process' + format.toUpperCase()](
2502 imageData,
2503 getImageIndex(images),
2504 alias,
2505 checkCompressValue(compression),
2506 dataAsBinaryString
2507 );
2508
2509 if(!info)
2510 throw new Error('An unkwown error occurred whilst processing the image');
2511 }
2512 }
2513
2514 writeImageToPDF.call(this, x, y, w, h, info, info.i, images);
2515
2516 return this
2517 };
2518
2519 /**
2520 * JPEG SUPPORT
2521 **/
2522
2523 //takes a string imgData containing the raw bytes of
2524 //a jpeg image and returns [width, height]
2525 //Algorithm from: http://www.64lines.com/jpeg-width-height
2526 var getJpegSize = function(imgData) {
2527 'use strict'
2528 var width, height, numcomponents;
2529 // Verify we have a valid jpeg header 0xff,0xd8,0xff,0xe0,?,?,'J','F','I','F',0x00
2530 if (!imgData.charCodeAt(0) === 0xff ||
2531 !imgData.charCodeAt(1) === 0xd8 ||
2532 !imgData.charCodeAt(2) === 0xff ||
2533 !imgData.charCodeAt(3) === 0xe0 ||
2534 !imgData.charCodeAt(6) === 'J'.charCodeAt(0) ||
2535 !imgData.charCodeAt(7) === 'F'.charCodeAt(0) ||
2536 !imgData.charCodeAt(8) === 'I'.charCodeAt(0) ||
2537 !imgData.charCodeAt(9) === 'F'.charCodeAt(0) ||
2538 !imgData.charCodeAt(10) === 0x00) {
2539 throw new Error('getJpegSize requires a binary string jpeg file')
2540 }
2541 var blockLength = imgData.charCodeAt(4)*256 + imgData.charCodeAt(5);
2542 var i = 4, len = imgData.length;
2543 while ( i < len ) {
2544 i += blockLength;
2545 if (imgData.charCodeAt(i) !== 0xff) {
2546 throw new Error('getJpegSize could not find the size of the image');
2547 }
2548 if (imgData.charCodeAt(i+1) === 0xc0 || //(SOF) Huffman - Baseline DCT
2549 imgData.charCodeAt(i+1) === 0xc1 || //(SOF) Huffman - Extended sequential DCT
2550 imgData.charCodeAt(i+1) === 0xc2 || // Progressive DCT (SOF2)
2551 imgData.charCodeAt(i+1) === 0xc3 || // Spatial (sequential) lossless (SOF3)
2552 imgData.charCodeAt(i+1) === 0xc4 || // Differential sequential DCT (SOF5)
2553 imgData.charCodeAt(i+1) === 0xc5 || // Differential progressive DCT (SOF6)
2554 imgData.charCodeAt(i+1) === 0xc6 || // Differential spatial (SOF7)
2555 imgData.charCodeAt(i+1) === 0xc7) {
2556 height = imgData.charCodeAt(i+5)*256 + imgData.charCodeAt(i+6);
2557 width = imgData.charCodeAt(i+7)*256 + imgData.charCodeAt(i+8);
2558 numcomponents = imgData.charCodeAt(i+9);
2559 return [width, height, numcomponents];
2560 } else {
2561 i += 2;
2562 blockLength = imgData.charCodeAt(i)*256 + imgData.charCodeAt(i+1)
2563 }
2564 }
2565 }
2566 , getJpegSizeFromBytes = function(data) {
2567
2568 var hdr = (data[0] << 8) | data[1];
2569
2570 if(hdr !== 0xFFD8)
2571 throw new Error('Supplied data is not a JPEG');
2572
2573 var len = data.length,
2574 block = (data[4] << 8) + data[5],
2575 pos = 4,
2576 bytes, width, height, numcomponents;
2577
2578 while(pos < len) {
2579 pos += block;
2580 bytes = readBytes(data, pos);
2581 block = (bytes[2] << 8) + bytes[3];
2582 if((bytes[1] === 0xC0 || bytes[1] === 0xC2) && bytes[0] === 0xFF && block > 7) {
2583 bytes = readBytes(data, pos + 5);
2584 width = (bytes[2] << 8) + bytes[3];
2585 height = (bytes[0] << 8) + bytes[1];
2586 numcomponents = bytes[4];
2587 return {width:width, height:height, numcomponents: numcomponents};
2588 }
2589
2590 pos+=2;
2591 }
2592
2593 throw new Error('getJpegSizeFromBytes could not find the size of the image');
2594 }
2595 , readBytes = function(data, offset) {
2596 return data.subarray(offset, offset+ 5);
2597 };
2598
2599 jsPDFAPI.processJPEG = function(data, index, alias, compression, dataAsBinaryString) {
2600 'use strict'
2601 var colorSpace = this.color_spaces.DEVICE_RGB,
2602 filter = this.decode.DCT_DECODE,
2603 bpc = 8,
2604 dims;
2605
2606 if(this.isString(data)) {
2607 dims = getJpegSize(data);
2608 return this.createImageInfo(data, dims[0], dims[1], dims[3] == 1 ? this.color_spaces.DEVICE_GRAY:colorSpace, bpc, filter, index, alias);
2609 }
2610
2611 if(this.isArrayBuffer(data))
2612 data = new Uint8Array(data);
2613
2614 if(this.isArrayBufferView(data)) {
2615
2616 dims = getJpegSizeFromBytes(data);
2617
2618 // if we already have a stored binary string rep use that
2619 data = dataAsBinaryString || this.arrayBufferToBinaryString(data);
2620
2621 return this.createImageInfo(data, dims.width, dims.height, dims.numcomponents == 1 ? this.color_spaces.DEVICE_GRAY:colorSpace, bpc, filter, index, alias);
2622 }
2623
2624 return null;
2625 };
2626
2627 jsPDFAPI.processJPG = function(/*data, index, alias, compression, dataAsBinaryString*/) {
2628 return this.processJPEG.apply(this, arguments);
2629 }
2630
2631})(jsPDF.API);
2632(function (jsPDFAPI) {
2633 'use strict';
2634
2635 jsPDFAPI.autoPrint = function () {
2636 'use strict'
2637 var refAutoPrintTag;
2638
2639 this.internal.events.subscribe('postPutResources', function () {
2640 refAutoPrintTag = this.internal.newObject()
2641 this.internal.write("<< /S/Named /Type/Action /N/Print >>", "endobj");
2642 });
2643
2644 this.internal.events.subscribe("putCatalog", function () {
2645 this.internal.write("/OpenAction " + refAutoPrintTag + " 0" + " R");
2646 });
2647 return this;
2648 };
2649})(jsPDF.API);
2650/** ====================================================================
2651 * jsPDF Cell plugin
2652 * Copyright (c) 2013 Youssef Beddad, youssef.beddad@gmail.com
2653 * 2013 Eduardo Menezes de Morais, eduardo.morais@usp.br
2654 * 2013 Lee Driscoll, https://github.com/lsdriscoll
2655 * 2014 Juan Pablo Gaviria, https://github.com/juanpgaviria
2656 * 2014 James Hall, james@parall.ax
2657 * 2014 Diego Casorran, https://github.com/diegocr
2658 *
2659 * Permission is hereby granted, free of charge, to any person obtaining
2660 * a copy of this software and associated documentation files (the
2661 * "Software"), to deal in the Software without restriction, including
2662 * without limitation the rights to use, copy, modify, merge, publish,
2663 * distribute, sublicense, and/or sell copies of the Software, and to
2664 * permit persons to whom the Software is furnished to do so, subject to
2665 * the following conditions:
2666 *
2667 * The above copyright notice and this permission notice shall be
2668 * included in all copies or substantial portions of the Software.
2669 *
2670 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
2671 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
2672 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
2673 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
2674 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
2675 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
2676 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
2677 * ====================================================================
2678 */
2679
2680(function (jsPDFAPI) {
2681 'use strict';
2682 /*jslint browser:true */
2683 /*global document: false, jsPDF */
2684
2685 var fontName,
2686 fontSize,
2687 fontStyle,
2688 padding = 3,
2689 margin = 13,
2690 headerFunction,
2691 lastCellPos = { x: undefined, y: undefined, w: undefined, h: undefined, ln: undefined },
2692 pages = 1,
2693 setLastCellPosition = function (x, y, w, h, ln) {
2694 lastCellPos = { 'x': x, 'y': y, 'w': w, 'h': h, 'ln': ln };
2695 },
2696 getLastCellPosition = function () {
2697 return lastCellPos;
2698 },
2699 NO_MARGINS = {left:0, top:0, bottom: 0};
2700
2701 jsPDFAPI.setHeaderFunction = function (func) {
2702 headerFunction = func;
2703 };
2704
2705 jsPDFAPI.getTextDimensions = function (txt) {
2706 fontName = this.internal.getFont().fontName;
2707 fontSize = this.table_font_size || this.internal.getFontSize();
2708 fontStyle = this.internal.getFont().fontStyle;
2709 // 1 pixel = 0.264583 mm and 1 mm = 72/25.4 point
2710 var px2pt = 0.264583 * 72 / 25.4,
2711 dimensions,
2712 text;
2713
2714 text = document.createElement('font');
2715 text.id = "jsPDFCell";
2716 text.style.fontStyle = fontStyle;
2717 text.style.fontName = fontName;
2718 text.style.fontSize = fontSize + 'pt';
2719 text.textContent = txt;
2720
2721 document.body.appendChild(text);
2722
2723 dimensions = { w: (text.offsetWidth + 1) * px2pt, h: (text.offsetHeight + 1) * px2pt};
2724
2725 document.body.removeChild(text);
2726
2727 return dimensions;
2728 };
2729
2730 jsPDFAPI.cellAddPage = function () {
2731 var margins = this.margins || NO_MARGINS;
2732
2733 this.addPage();
2734
2735 setLastCellPosition(margins.left, margins.top, undefined, undefined);
2736 //setLastCellPosition(undefined, undefined, undefined, undefined, undefined);
2737 pages += 1;
2738 };
2739
2740 jsPDFAPI.cellInitialize = function () {
2741 lastCellPos = { x: undefined, y: undefined, w: undefined, h: undefined, ln: undefined };
2742 pages = 1;
2743 };
2744
2745 jsPDFAPI.cell = function (x, y, w, h, txt, ln, align) {
2746 var curCell = getLastCellPosition();
2747
2748 // If this is not the first cell, we must change its position
2749 if (curCell.ln !== undefined) {
2750 if (curCell.ln === ln) {
2751 //Same line
2752 x = curCell.x + curCell.w;
2753 y = curCell.y;
2754 } else {
2755 //New line
2756 var margins = this.margins || NO_MARGINS;
2757 if ((curCell.y + curCell.h + h + margin) >= this.internal.pageSize.height - margins.bottom) {
2758 this.cellAddPage();
2759 if (this.printHeaders && this.tableHeaderRow) {
2760 this.printHeaderRow(ln, true);
2761 }
2762 }
2763 //We ignore the passed y: the lines may have diferent heights
2764 y = (getLastCellPosition().y + getLastCellPosition().h);
2765
2766 }
2767 }
2768
2769 if (txt[0] !== undefined) {
2770 if (this.printingHeaderRow) {
2771 this.rect(x, y, w, h, 'FD');
2772 } else {
2773 this.rect(x, y, w, h);
2774 }
2775 if (align === 'right') {
2776 if (txt instanceof Array) {
2777 for(var i = 0; i<txt.length; i++) {
2778 var currentLine = txt[i];
2779 var textSize = this.getStringUnitWidth(currentLine) * this.internal.getFontSize();
2780 this.text(currentLine, x + w - textSize - padding, y + this.internal.getLineHeight()*(i+1));
2781 }
2782 }
2783 } else {
2784 this.text(txt, x + padding, y + this.internal.getLineHeight());
2785 }
2786 }
2787 setLastCellPosition(x, y, w, h, ln);
2788 return this;
2789 };
2790
2791 /**
2792 * Return the maximum value from an array
2793 * @param array
2794 * @param comparisonFn
2795 * @returns {*}
2796 */
2797 jsPDFAPI.arrayMax = function (array, comparisonFn) {
2798 var max = array[0],
2799 i,
2800 ln,
2801 item;
2802
2803 for (i = 0, ln = array.length; i < ln; i += 1) {
2804 item = array[i];
2805
2806 if (comparisonFn) {
2807 if (comparisonFn(max, item) === -1) {
2808 max = item;
2809 }
2810 } else {
2811 if (item > max) {
2812 max = item;
2813 }
2814 }
2815 }
2816
2817 return max;
2818 };
2819
2820 /**
2821 * Create a table from a set of data.
2822 * @param {Integer} [x] : left-position for top-left corner of table
2823 * @param {Integer} [y] top-position for top-left corner of table
2824 * @param {Object[]} [data] As array of objects containing key-value pairs corresponding to a row of data.
2825 * @param {String[]} [headers] Omit or null to auto-generate headers at a performance cost
2826
2827 * @param {Object} [config.printHeaders] True to print column headers at the top of every page
2828 * @param {Object} [config.autoSize] True to dynamically set the column widths to match the widest cell value
2829 * @param {Object} [config.margins] margin values for left, top, bottom, and width
2830 * @param {Object} [config.fontSize] Integer fontSize to use (optional)
2831 */
2832
2833 jsPDFAPI.table = function (x,y, data, headers, config) {
2834 if (!data) {
2835 throw 'No data for PDF table';
2836 }
2837
2838 var headerNames = [],
2839 headerPrompts = [],
2840 header,
2841 i,
2842 ln,
2843 cln,
2844 columnMatrix = {},
2845 columnWidths = {},
2846 columnData,
2847 column,
2848 columnMinWidths = [],
2849 j,
2850 tableHeaderConfigs = [],
2851 model,
2852 jln,
2853 func,
2854
2855 //set up defaults. If a value is provided in config, defaults will be overwritten:
2856 autoSize = false,
2857 printHeaders = true,
2858 fontSize = 12,
2859 margins = NO_MARGINS;
2860
2861 margins.width = this.internal.pageSize.width;
2862
2863 if (config) {
2864 //override config defaults if the user has specified non-default behavior:
2865 if(config.autoSize === true) {
2866 autoSize = true;
2867 }
2868 if(config.printHeaders === false) {
2869 printHeaders = false;
2870 }
2871 if(config.fontSize){
2872 fontSize = config.fontSize;
2873 }
2874 if(config.margins){
2875 margins = config.margins;
2876 }
2877 }
2878
2879 /**
2880 * @property {Number} lnMod
2881 * Keep track of the current line number modifier used when creating cells
2882 */
2883 this.lnMod = 0;
2884 lastCellPos = { x: undefined, y: undefined, w: undefined, h: undefined, ln: undefined },
2885 pages = 1;
2886
2887 this.printHeaders = printHeaders;
2888 this.margins = margins;
2889 this.setFontSize(fontSize);
2890 this.table_font_size = fontSize;
2891
2892 // Set header values
2893 if (headers === undefined || (headers === null)) {
2894 // No headers defined so we derive from data
2895 headerNames = Object.keys(data[0]);
2896
2897 } else if (headers[0] && (typeof headers[0] !== 'string')) {
2898 var px2pt = 0.264583 * 72 / 25.4;
2899
2900 // Split header configs into names and prompts
2901 for (i = 0, ln = headers.length; i < ln; i += 1) {
2902 header = headers[i];
2903 headerNames.push(header.name);
2904 headerPrompts.push(header.prompt);
2905 columnWidths[header.name] = header.width *px2pt;
2906 }
2907
2908 } else {
2909 headerNames = headers;
2910 }
2911
2912 if (autoSize) {
2913 // Create a matrix of columns e.g., {column_title: [row1_Record, row2_Record]}
2914 func = function (rec) {
2915 return rec[header];
2916 };
2917
2918 for (i = 0, ln = headerNames.length; i < ln; i += 1) {
2919 header = headerNames[i];
2920
2921 columnMatrix[header] = data.map(
2922 func
2923 );
2924
2925 // get header width
2926 columnMinWidths.push(this.getTextDimensions(headerPrompts[i] || header).w);
2927 column = columnMatrix[header];
2928
2929 // get cell widths
2930 for (j = 0, cln = column.length; j < cln; j += 1) {
2931 columnData = column[j];
2932 columnMinWidths.push(this.getTextDimensions(columnData).w);
2933 }
2934
2935 // get final column width
2936 columnWidths[header] = jsPDFAPI.arrayMax(columnMinWidths);
2937 }
2938 }
2939
2940 // -- Construct the table
2941
2942 if (printHeaders) {
2943 var lineHeight = this.calculateLineHeight(headerNames, columnWidths, headerPrompts.length?headerPrompts:headerNames);
2944
2945 // Construct the header row
2946 for (i = 0, ln = headerNames.length; i < ln; i += 1) {
2947 header = headerNames[i];
2948 tableHeaderConfigs.push([x, y, columnWidths[header], lineHeight, String(headerPrompts.length ? headerPrompts[i] : header)]);
2949 }
2950
2951 // Store the table header config
2952 this.setTableHeaderRow(tableHeaderConfigs);
2953
2954 // Print the header for the start of the table
2955 this.printHeaderRow(1, false);
2956 }
2957
2958 // Construct the data rows
2959 for (i = 0, ln = data.length; i < ln; i += 1) {
2960 var lineHeight;
2961 model = data[i];
2962 lineHeight = this.calculateLineHeight(headerNames, columnWidths, model);
2963
2964 for (j = 0, jln = headerNames.length; j < jln; j += 1) {
2965 header = headerNames[j];
2966 this.cell(x, y, columnWidths[header], lineHeight, model[header], i + 2, header.align);
2967 }
2968 }
2969 this.lastCellPos = lastCellPos;
2970 this.table_x = x;
2971 this.table_y = y;
2972 return this;
2973 };
2974 /**
2975 * Calculate the height for containing the highest column
2976 * @param {String[]} headerNames is the header, used as keys to the data
2977 * @param {Integer[]} columnWidths is size of each column
2978 * @param {Object[]} model is the line of data we want to calculate the height of
2979 */
2980 jsPDFAPI.calculateLineHeight = function (headerNames, columnWidths, model) {
2981 var header, lineHeight = 0;
2982 for (var j = 0; j < headerNames.length; j++) {
2983 header = headerNames[j];
2984 model[header] = this.splitTextToSize(String(model[header]), columnWidths[header] - padding);
2985 var h = this.internal.getLineHeight() * model[header].length + padding;
2986 if (h > lineHeight)
2987 lineHeight = h;
2988 }
2989 return lineHeight;
2990 };
2991
2992 /**
2993 * Store the config for outputting a table header
2994 * @param {Object[]} config
2995 * An array of cell configs that would define a header row: Each config matches the config used by jsPDFAPI.cell
2996 * except the ln parameter is excluded
2997 */
2998 jsPDFAPI.setTableHeaderRow = function (config) {
2999 this.tableHeaderRow = config;
3000 };
3001
3002 /**
3003 * Output the store header row
3004 * @param lineNumber The line number to output the header at
3005 */
3006 jsPDFAPI.printHeaderRow = function (lineNumber, new_page) {
3007 if (!this.tableHeaderRow) {
3008 throw 'Property tableHeaderRow does not exist.';
3009 }
3010
3011 var tableHeaderCell,
3012 tmpArray,
3013 i,
3014 ln;
3015
3016 this.printingHeaderRow = true;
3017 if (headerFunction !== undefined) {
3018 var position = headerFunction(this, pages);
3019 setLastCellPosition(position[0], position[1], position[2], position[3], -1);
3020 }
3021 this.setFontStyle('bold');
3022 var tempHeaderConf = [];
3023 for (i = 0, ln = this.tableHeaderRow.length; i < ln; i += 1) {
3024 this.setFillColor(200,200,200);
3025
3026 tableHeaderCell = this.tableHeaderRow[i];
3027 if (new_page) {
3028 tableHeaderCell[1] = this.margins && this.margins.top || 0;
3029 tempHeaderConf.push(tableHeaderCell);
3030 }
3031 tmpArray = [].concat(tableHeaderCell);
3032 this.cell.apply(this, tmpArray.concat(lineNumber));
3033 }
3034 if (tempHeaderConf.length > 0){
3035 this.setTableHeaderRow(tempHeaderConf);
3036 }
3037 this.setFontStyle('normal');
3038 this.printingHeaderRow = false;
3039 };
3040
3041})(jsPDF.API);
3042/** @preserve
3043 * jsPDF fromHTML plugin. BETA stage. API subject to change. Needs browser
3044 * Copyright (c) 2012 Willow Systems Corporation, willow-systems.com
3045 * 2014 Juan Pablo Gaviria, https://github.com/juanpgaviria
3046 * 2014 Diego Casorran, https://github.com/diegocr
3047 * 2014 Daniel Husar, https://github.com/danielhusar
3048 * 2014 Wolfgang Gassler, https://github.com/woolfg
3049 *
3050 * Permission is hereby granted, free of charge, to any person obtaining
3051 * a copy of this software and associated documentation files (the
3052 * "Software"), to deal in the Software without restriction, including
3053 * without limitation the rights to use, copy, modify, merge, publish,
3054 * distribute, sublicense, and/or sell copies of the Software, and to
3055 * permit persons to whom the Software is furnished to do so, subject to
3056 * the following conditions:
3057 *
3058 * The above copyright notice and this permission notice shall be
3059 * included in all copies or substantial portions of the Software.
3060 *
3061 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
3062 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
3063 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
3064 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
3065 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
3066 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
3067 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
3068 * ====================================================================
3069 */
3070
3071(function (jsPDFAPI) {
3072 var clone,
3073 DrillForContent,
3074 FontNameDB,
3075 FontStyleMap,
3076 FontWeightMap,
3077 FloatMap,
3078 ClearMap,
3079 GetCSS,
3080 PurgeWhiteSpace,
3081 Renderer,
3082 ResolveFont,
3083 ResolveUnitedNumber,
3084 UnitedNumberMap,
3085 elementHandledElsewhere,
3086 images,
3087 loadImgs,
3088 checkForFooter,
3089 process,
3090 tableToJson;
3091 clone = (function () {
3092 return function (obj) {
3093 Clone.prototype = obj;
3094 return new Clone()
3095 };
3096 function Clone() {}
3097 })();
3098 PurgeWhiteSpace = function (array) {
3099 var fragment,
3100 i,
3101 l,
3102 lTrimmed,
3103 r,
3104 rTrimmed,
3105 trailingSpace;
3106 i = 0;
3107 l = array.length;
3108 fragment = void 0;
3109 lTrimmed = false;
3110 rTrimmed = false;
3111 while (!lTrimmed && i !== l) {
3112 fragment = array[i] = array[i].trimLeft();
3113 if (fragment) {
3114 lTrimmed = true;
3115 }
3116 i++;
3117 }
3118 i = l - 1;
3119 while (l && !rTrimmed && i !== -1) {
3120 fragment = array[i] = array[i].trimRight();
3121 if (fragment) {
3122 rTrimmed = true;
3123 }
3124 i--;
3125 }
3126 r = /\s+$/g;
3127 trailingSpace = true;
3128 i = 0;
3129 while (i !== l) {
3130 fragment = array[i].replace(/\s+/g, " ");
3131 if (trailingSpace) {
3132 fragment = fragment.trimLeft();
3133 }
3134 if (fragment) {
3135 trailingSpace = r.test(fragment);
3136 }
3137 array[i] = fragment;
3138 i++;
3139 }
3140 return array;
3141 };
3142 Renderer = function (pdf, x, y, settings) {
3143 this.pdf = pdf;
3144 this.x = x;
3145 this.y = y;
3146 this.settings = settings;
3147 //list of functions which are called after each element-rendering process
3148 this.watchFunctions = [];
3149 this.init();
3150 return this;
3151 };
3152 ResolveFont = function (css_font_family_string) {
3153 var name,
3154 part,
3155 parts;
3156 name = void 0;
3157 parts = css_font_family_string.split(",");
3158 part = parts.shift();
3159 while (!name && part) {
3160 name = FontNameDB[part.trim().toLowerCase()];
3161 part = parts.shift();
3162 }
3163 return name;
3164 };
3165 ResolveUnitedNumber = function (css_line_height_string) {
3166
3167 //IE8 issues
3168 css_line_height_string = css_line_height_string === "auto" ? "0px" : css_line_height_string;
3169 if (css_line_height_string.indexOf("em") > -1 && !isNaN(Number(css_line_height_string.replace("em", "")))) {
3170 css_line_height_string = Number(css_line_height_string.replace("em", "")) * 18.719 + "px";
3171 }
3172 if (css_line_height_string.indexOf("pt") > -1 && !isNaN(Number(css_line_height_string.replace("pt", "")))) {
3173 css_line_height_string = Number(css_line_height_string.replace("pt", "")) * 1.333 + "px";
3174 }
3175
3176 var normal,
3177 undef,
3178 value;
3179 undef = void 0;
3180 normal = 16.00;
3181 value = UnitedNumberMap[css_line_height_string];
3182 if (value) {
3183 return value;
3184 }
3185 value = {
3186 "xx-small" : 9,
3187 "x-small" : 11,
3188 small : 13,
3189 medium : 16,
3190 large : 19,
3191 "x-large" : 23,
3192 "xx-large" : 28,
3193 auto : 0
3194 }[{ css_line_height_string : css_line_height_string }];
3195
3196 if (value !== undef) {
3197 return UnitedNumberMap[css_line_height_string] = value / normal;
3198 }
3199 if (value = parseFloat(css_line_height_string)) {
3200 return UnitedNumberMap[css_line_height_string] = value / normal;
3201 }
3202 value = css_line_height_string.match(/([\d\.]+)(px)/);
3203 if (value.length === 3) {
3204 return UnitedNumberMap[css_line_height_string] = parseFloat(value[1]) / normal;
3205 }
3206 return UnitedNumberMap[css_line_height_string] = 1;
3207 };
3208 GetCSS = function (element) {
3209 var css,tmp,computedCSSElement;
3210 computedCSSElement = (function (el) {
3211 var compCSS;
3212 compCSS = (function (el) {
3213 if (document.defaultView && document.defaultView.getComputedStyle) {
3214 return document.defaultView.getComputedStyle(el, null);
3215 } else if (el.currentStyle) {
3216 return el.currentStyle;
3217 } else {
3218 return el.style;
3219 }
3220 })(el);
3221 return function (prop) {
3222 prop = prop.replace(/-\D/g, function (match) {
3223 return match.charAt(1).toUpperCase();
3224 });
3225 return compCSS[prop];
3226 };
3227 })(element);
3228 css = {};
3229 tmp = void 0;
3230 css["font-family"] = ResolveFont(computedCSSElement("font-family")) || "times";
3231 css["font-style"] = FontStyleMap[computedCSSElement("font-style")] || "normal";
3232 css["text-align"] = TextAlignMap[computedCSSElement("text-align")] || "left";
3233 tmp = FontWeightMap[computedCSSElement("font-weight")] || "normal";
3234 if (tmp === "bold") {
3235 if (css["font-style"] === "normal") {
3236 css["font-style"] = tmp;
3237 } else {
3238 css["font-style"] = tmp + css["font-style"];
3239 }
3240 }
3241 css["font-size"] = ResolveUnitedNumber(computedCSSElement("font-size")) || 1;
3242 css["line-height"] = ResolveUnitedNumber(computedCSSElement("line-height")) || 1;
3243 css["display"] = (computedCSSElement("display") === "inline" ? "inline" : "block");
3244
3245 tmp = (css["display"] === "block");
3246 css["margin-top"] = tmp && ResolveUnitedNumber(computedCSSElement("margin-top")) || 0;
3247 css["margin-bottom"] = tmp && ResolveUnitedNumber(computedCSSElement("margin-bottom")) || 0;
3248 css["padding-top"] = tmp && ResolveUnitedNumber(computedCSSElement("padding-top")) || 0;
3249 css["padding-bottom"] = tmp && ResolveUnitedNumber(computedCSSElement("padding-bottom")) || 0;
3250 css["margin-left"] = tmp && ResolveUnitedNumber(computedCSSElement("margin-left")) || 0;
3251 css["margin-right"] = tmp && ResolveUnitedNumber(computedCSSElement("margin-right")) || 0;
3252 css["padding-left"] = tmp && ResolveUnitedNumber(computedCSSElement("padding-left")) || 0;
3253 css["padding-right"] = tmp && ResolveUnitedNumber(computedCSSElement("padding-right")) || 0;
3254
3255 //float and clearing of floats
3256 css["float"] = FloatMap[computedCSSElement("cssFloat")] || "none";
3257 css["clear"] = ClearMap[computedCSSElement("clear")] || "none";
3258 return css;
3259 };
3260 elementHandledElsewhere = function (element, renderer, elementHandlers) {
3261 var handlers,
3262 i,
3263 isHandledElsewhere,
3264 l,
3265 t;
3266 isHandledElsewhere = false;
3267 i = void 0;
3268 l = void 0;
3269 t = void 0;
3270 handlers = elementHandlers["#" + element.id];
3271 if (handlers) {
3272 if (typeof handlers === "function") {
3273 isHandledElsewhere = handlers(element, renderer);
3274 } else {
3275 i = 0;
3276 l = handlers.length;
3277 while (!isHandledElsewhere && i !== l) {
3278 isHandledElsewhere = handlers[i](element, renderer);
3279 i++;
3280 }
3281 }
3282 }
3283 handlers = elementHandlers[element.nodeName];
3284 if (!isHandledElsewhere && handlers) {
3285 if (typeof handlers === "function") {
3286 isHandledElsewhere = handlers(element, renderer);
3287 } else {
3288 i = 0;
3289 l = handlers.length;
3290 while (!isHandledElsewhere && i !== l) {
3291 isHandledElsewhere = handlers[i](element, renderer);
3292 i++;
3293 }
3294 }
3295 }
3296 return isHandledElsewhere;
3297 };
3298 tableToJson = function (table, renderer) {
3299 var data,
3300 headers,
3301 i,
3302 j,
3303 rowData,
3304 tableRow,
3305 table_obj,
3306 table_with,
3307 cell,
3308 l;
3309 data = [];
3310 headers = [];
3311 i = 0;
3312 l = table.rows[0].cells.length;
3313 table_with = table.clientWidth;
3314 while (i < l) {
3315 cell = table.rows[0].cells[i];
3316 headers[i] = {
3317 name : cell.textContent.toLowerCase().replace(/\s+/g, ''),
3318 prompt : cell.textContent.replace(/\r?\n/g, ''),
3319 width : (cell.clientWidth / table_with) * renderer.pdf.internal.pageSize.width
3320 };
3321 i++;
3322 }
3323 i = 1;
3324 while (i < table.rows.length) {
3325 tableRow = table.rows[i];
3326 rowData = {};
3327 j = 0;
3328 while (j < tableRow.cells.length) {
3329 rowData[headers[j].name] = tableRow.cells[j].textContent.replace(/\r?\n/g, '');
3330 j++;
3331 }
3332 data.push(rowData);
3333 i++;
3334 }
3335 return table_obj = {
3336 rows : data,
3337 headers : headers
3338 };
3339 };
3340 var SkipNode = {
3341 SCRIPT : 1,
3342 STYLE : 1,
3343 NOSCRIPT : 1,
3344 OBJECT : 1,
3345 EMBED : 1,
3346 SELECT : 1
3347 };
3348 var listCount = 1;
3349 DrillForContent = function (element, renderer, elementHandlers) {
3350 var cn,
3351 cns,
3352 fragmentCSS,
3353 i,
3354 isBlock,
3355 l,
3356 px2pt,
3357 table2json,
3358 cb;
3359 cns = element.childNodes;
3360 cn = void 0;
3361 fragmentCSS = GetCSS(element);
3362 isBlock = fragmentCSS.display === "block";
3363 if (isBlock) {
3364 renderer.setBlockBoundary();
3365 renderer.setBlockStyle(fragmentCSS);
3366 }
3367 px2pt = 0.264583 * 72 / 25.4;
3368 i = 0;
3369 l = cns.length;
3370 while (i < l) {
3371 cn = cns[i];
3372 if (typeof cn === "object") {
3373
3374 //execute all watcher functions to e.g. reset floating
3375 renderer.executeWatchFunctions(cn);
3376
3377 /*** HEADER rendering **/
3378 if (cn.nodeType === 1 && cn.nodeName === 'HEADER') {
3379 var header = cn;
3380 //store old top margin
3381 var oldMarginTop = renderer.pdf.margins_doc.top;
3382 //subscribe for new page event and render header first on every page
3383 renderer.pdf.internal.events.subscribe('addPage', function (pageInfo) {
3384 //set current y position to old margin
3385 renderer.y = oldMarginTop;
3386 //render all child nodes of the header element
3387 DrillForContent(header, renderer, elementHandlers);
3388 //set margin to old margin + rendered header + 10 space to prevent overlapping
3389 //important for other plugins (e.g. table) to start rendering at correct position after header
3390 renderer.pdf.margins_doc.top = renderer.y + 10;
3391 renderer.y += 10;
3392 }, false);
3393 }
3394
3395 if (cn.nodeType === 8 && cn.nodeName === "#comment") {
3396 if (~cn.textContent.indexOf("ADD_PAGE")) {
3397 renderer.pdf.addPage();
3398 renderer.y = renderer.pdf.margins_doc.top;
3399 }
3400
3401 } else if (cn.nodeType === 1 && !SkipNode[cn.nodeName]) {
3402 /*** IMAGE RENDERING ***/
3403 var cached_image;
3404 if (cn.nodeName === "IMG") {
3405 var url = cn.getAttribute("src");
3406 cached_image = images[renderer.pdf.sHashCode(url) || url];
3407 }
3408 if (cached_image) {
3409 if ((renderer.pdf.internal.pageSize.height - renderer.pdf.margins_doc.bottom < renderer.y + cn.height) && (renderer.y > renderer.pdf.margins_doc.top)) {
3410 renderer.pdf.addPage();
3411 renderer.y = renderer.pdf.margins_doc.top;
3412 //check if we have to set back some values due to e.g. header rendering for new page
3413 renderer.executeWatchFunctions(cn);
3414 }
3415
3416 var imagesCSS = GetCSS(cn);
3417 var imageX = renderer.x;
3418 var fontToUnitRatio = 12 / renderer.pdf.internal.scaleFactor;
3419
3420 //define additional paddings, margins which have to be taken into account for margin calculations
3421 var additionalSpaceLeft = (imagesCSS["margin-left"] + imagesCSS["padding-left"])*fontToUnitRatio;
3422 var additionalSpaceRight = (imagesCSS["margin-right"] + imagesCSS["padding-right"])*fontToUnitRatio;
3423 var additionalSpaceTop = (imagesCSS["margin-top"] + imagesCSS["padding-top"])*fontToUnitRatio;
3424 var additionalSpaceBottom = (imagesCSS["margin-bottom"] + imagesCSS["padding-bottom"])*fontToUnitRatio;
3425
3426 //if float is set to right, move the image to the right border
3427 //add space if margin is set
3428 if (imagesCSS['float'] !== undefined && imagesCSS['float'] === 'right') {
3429 imageX += renderer.settings.width - cn.width - additionalSpaceRight;
3430 } else {
3431 imageX += additionalSpaceLeft;
3432 }
3433
3434 renderer.pdf.addImage(cached_image, imageX, renderer.y + additionalSpaceTop, cn.width, cn.height);
3435 cached_image = undefined;
3436 //if the float prop is specified we have to float the text around the image
3437 if (imagesCSS['float'] === 'right' || imagesCSS['float'] === 'left') {
3438 //add functiont to set back coordinates after image rendering
3439 renderer.watchFunctions.push((function(diffX , thresholdY, diffWidth, el) {
3440 //undo drawing box adaptions which were set by floating
3441 if (renderer.y >= thresholdY) {
3442 renderer.x += diffX;
3443 renderer.settings.width += diffWidth;
3444 return true;
3445 } else if(el && el.nodeType === 1 && !SkipNode[el.nodeName] && renderer.x+el.width > (renderer.pdf.margins_doc.left + renderer.pdf.margins_doc.width)) {
3446 renderer.x += diffX;
3447 renderer.y = thresholdY;
3448 renderer.settings.width += diffWidth;
3449 return true;
3450 } else {
3451 return false;
3452 }
3453 }).bind(this, (imagesCSS['float'] === 'left') ? -cn.width-additionalSpaceLeft-additionalSpaceRight : 0, renderer.y+cn.height+additionalSpaceTop+additionalSpaceBottom, cn.width));
3454 //reset floating by clear:both divs
3455 //just set cursorY after the floating element
3456 renderer.watchFunctions.push((function(yPositionAfterFloating, pages, el) {
3457 if (renderer.y < yPositionAfterFloating && pages === renderer.pdf.internal.getNumberOfPages()) {
3458 if (el.nodeType === 1 && GetCSS(el).clear === 'both') {
3459 renderer.y = yPositionAfterFloating;
3460 return true;
3461 } else {
3462 return false;
3463 }
3464 } else {
3465 return true;
3466 }
3467 }).bind(this, renderer.y+cn.height, renderer.pdf.internal.getNumberOfPages()));
3468
3469 //if floating is set we decrease the available width by the image width
3470 renderer.settings.width -= cn.width+additionalSpaceLeft+additionalSpaceRight;
3471 //if left just add the image width to the X coordinate
3472 if (imagesCSS['float'] === 'left') {
3473 renderer.x += cn.width+additionalSpaceLeft+additionalSpaceRight;
3474 }
3475 } else {
3476 //if no floating is set, move the rendering cursor after the image height
3477 renderer.y += cn.height + additionalSpaceBottom;
3478 }
3479
3480 /*** TABLE RENDERING ***/
3481 } else if (cn.nodeName === "TABLE") {
3482 table2json = tableToJson(cn, renderer);
3483 renderer.y += 10;
3484 renderer.pdf.table(renderer.x, renderer.y, table2json.rows, table2json.headers, {
3485 autoSize : false,
3486 printHeaders : true,
3487 margins : renderer.pdf.margins_doc
3488 });
3489 renderer.y = renderer.pdf.lastCellPos.y + renderer.pdf.lastCellPos.h + 20;
3490 } else if (cn.nodeName === "OL" || cn.nodeName === "UL") {
3491 listCount = 1;
3492 if (!elementHandledElsewhere(cn, renderer, elementHandlers)) {
3493 DrillForContent(cn, renderer, elementHandlers);
3494 }
3495 renderer.y += 10;
3496 } else if (cn.nodeName === "LI") {
3497 var temp = renderer.x;
3498 renderer.x += cn.parentNode.nodeName === "UL" ? 22 : 10;
3499 renderer.y += 3;
3500 if (!elementHandledElsewhere(cn, renderer, elementHandlers)) {
3501 DrillForContent(cn, renderer, elementHandlers);
3502 }
3503 renderer.x = temp;
3504 } else if (cn.nodeName === "BR") {
3505 renderer.y += fragmentCSS["font-size"] * renderer.pdf.internal.scaleFactor;
3506 } else {
3507 if (!elementHandledElsewhere(cn, renderer, elementHandlers)) {
3508 DrillForContent(cn, renderer, elementHandlers);
3509 }
3510 }
3511 } else if (cn.nodeType === 3) {
3512 var value = cn.nodeValue;
3513 if (cn.nodeValue && cn.parentNode.nodeName === "LI") {
3514 if (cn.parentNode.parentNode.nodeName === "OL") {
3515 value = listCount++ + '. ' + value;
3516 } else {
3517 var fontPx = fragmentCSS["font-size"] * 16;
3518 var radius = 2;
3519 if (fontPx > 20) {
3520 radius = 3;
3521 }
3522 cb = function (x, y) {
3523 this.pdf.circle(x, y, radius, 'FD');
3524 };
3525 }
3526 }
3527 renderer.addText(value, fragmentCSS);
3528 } else if (typeof cn === "string") {
3529 renderer.addText(cn, fragmentCSS);
3530 }
3531 }
3532 i++;
3533 }
3534
3535 if (isBlock) {
3536 return renderer.setBlockBoundary(cb);
3537 }
3538 };
3539 images = {};
3540 loadImgs = function (element, renderer, elementHandlers, cb) {
3541 var imgs = element.getElementsByTagName('img'),
3542 l = imgs.length, found_images,
3543 x = 0;
3544 function done() {
3545 renderer.pdf.internal.events.publish('imagesLoaded');
3546 cb(found_images);
3547 }
3548 function loadImage(url, width, height) {
3549 if (!url)
3550 return;
3551 var img = new Image();
3552 found_images = ++x;
3553 img.crossOrigin = '';
3554 img.onerror = img.onload = function () {
3555 if(img.complete) {
3556 //to support data urls in images, set width and height
3557 //as those values are not recognized automatically
3558 if (img.src.indexOf('data:image/') === 0) {
3559 img.width = width || img.width || 0;
3560 img.height = height || img.height || 0;
3561 }
3562 //if valid image add to known images array
3563 if (img.width + img.height) {
3564 var hash = renderer.pdf.sHashCode(url) || url;
3565 images[hash] = images[hash] || img;
3566 }
3567 }
3568 if(!--x) {
3569 done();
3570 }
3571 };
3572 img.src = url;
3573 }
3574 while (l--)
3575 loadImage(imgs[l].getAttribute("src"),imgs[l].width,imgs[l].height);
3576 return x || done();
3577 };
3578 checkForFooter = function (elem, renderer, elementHandlers) {
3579 //check if we can found a <footer> element
3580 var footer = elem.getElementsByTagName("footer");
3581 if (footer.length > 0) {
3582
3583 footer = footer[0];
3584
3585 //bad hack to get height of footer
3586 //creat dummy out and check new y after fake rendering
3587 var oldOut = renderer.pdf.internal.write;
3588 var oldY = renderer.y;
3589 renderer.pdf.internal.write = function () {};
3590 DrillForContent(footer, renderer, elementHandlers);
3591 var footerHeight = Math.ceil(renderer.y - oldY) + 5;
3592 renderer.y = oldY;
3593 renderer.pdf.internal.write = oldOut;
3594
3595 //add 20% to prevent overlapping
3596 renderer.pdf.margins_doc.bottom += footerHeight;
3597
3598 //Create function render header on every page
3599 var renderFooter = function (pageInfo) {
3600 var pageNumber = pageInfo !== undefined ? pageInfo.pageNumber : 1;
3601 //set current y position to old margin
3602 var oldPosition = renderer.y;
3603 //render all child nodes of the header element
3604 renderer.y = renderer.pdf.internal.pageSize.height - renderer.pdf.margins_doc.bottom;
3605 renderer.pdf.margins_doc.bottom -= footerHeight;
3606
3607 //check if we have to add page numbers
3608 var spans = footer.getElementsByTagName('span');
3609 for (var i = 0; i < spans.length; ++i) {
3610 //if we find some span element with class pageCounter, set the page
3611 if ((" " + spans[i].className + " ").replace(/[\n\t]/g, " ").indexOf(" pageCounter ") > -1) {
3612 spans[i].innerHTML = pageNumber;
3613 }
3614 //if we find some span element with class totalPages, set a variable which is replaced after rendering of all pages
3615 if ((" " + spans[i].className + " ").replace(/[\n\t]/g, " ").indexOf(" totalPages ") > -1) {
3616 spans[i].innerHTML = '###jsPDFVarTotalPages###';
3617 }
3618 }
3619
3620 //render footer content
3621 DrillForContent(footer, renderer, elementHandlers);
3622 //set bottom margin to previous height including the footer height
3623 renderer.pdf.margins_doc.bottom += footerHeight;
3624 //important for other plugins (e.g. table) to start rendering at correct position after header
3625 renderer.y = oldPosition;
3626 };
3627
3628 //check if footer contains totalPages which shoudl be replace at the disoposal of the document
3629 var spans = footer.getElementsByTagName('span');
3630 for (var i = 0; i < spans.length; ++i) {
3631 if ((" " + spans[i].className + " ").replace(/[\n\t]/g, " ").indexOf(" totalPages ") > -1) {
3632 renderer.pdf.internal.events.subscribe('htmlRenderingFinished', renderer.pdf.putTotalPages.bind(renderer.pdf, '###jsPDFVarTotalPages###'), true);
3633 }
3634 }
3635
3636 //register event to render footer on every new page
3637 renderer.pdf.internal.events.subscribe('addPage', renderFooter, false);
3638 //render footer on first page
3639 renderFooter();
3640
3641 //prevent footer rendering
3642 SkipNode['FOOTER'] = 1;
3643 }
3644 };
3645 process = function (pdf, element, x, y, settings, callback) {
3646 if (!element)
3647 return false;
3648 if (typeof element !== "string" && !element.parentNode)
3649 element = '' + element.innerHTML;
3650 if (typeof element === "string") {
3651 element = (function (element) {
3652 var $frame,
3653 $hiddendiv,
3654 framename,
3655 visuallyhidden;
3656 framename = "jsPDFhtmlText" + Date.now().toString() + (Math.random() * 1000).toFixed(0);
3657 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;";
3658 $hiddendiv = document.createElement('div');
3659 $hiddendiv.style.cssText = visuallyhidden;
3660 $hiddendiv.innerHTML = "<iframe style=\"height:1px;width:1px\" name=\"" + framename + "\" />";
3661 document.body.appendChild($hiddendiv);
3662 $frame = window.frames[framename];
3663 $frame.document.body.innerHTML = element;
3664 return $frame.document.body;
3665 })(element.replace(/<\/?script[^>]*?>/gi, ''));
3666 }
3667 var r = new Renderer(pdf, x, y, settings), out;
3668
3669 // 1. load images
3670 // 2. prepare optional footer elements
3671 // 3. render content
3672 loadImgs.call(this, element, r, settings.elementHandlers, function (found_images) {
3673 checkForFooter( element, r, settings.elementHandlers);
3674 DrillForContent(element, r, settings.elementHandlers);
3675 //send event dispose for final taks (e.g. footer totalpage replacement)
3676 r.pdf.internal.events.publish('htmlRenderingFinished');
3677 out = r.dispose();
3678 if (typeof callback === 'function') callback(out);
3679 else if (found_images) console.error('jsPDF Warning: rendering issues? provide a callback to fromHTML!');
3680 });
3681 return out || {x: r.x, y:r.y};
3682 };
3683 Renderer.prototype.init = function () {
3684 this.paragraph = {
3685 text : [],
3686 style : []
3687 };
3688 return this.pdf.internal.write("q");
3689 };
3690 Renderer.prototype.dispose = function () {
3691 this.pdf.internal.write("Q");
3692 return {
3693 x : this.x,
3694 y : this.y,
3695 ready:true
3696 };
3697 };
3698
3699 //Checks if we have to execute some watcher functions
3700 //e.g. to end text floating around an image
3701 Renderer.prototype.executeWatchFunctions = function(el) {
3702 var ret = false;
3703 var narray = [];
3704 if (this.watchFunctions.length > 0) {
3705 for(var i=0; i< this.watchFunctions.length; ++i) {
3706 if (this.watchFunctions[i](el) === true) {
3707 ret = true;
3708 } else {
3709 narray.push(this.watchFunctions[i]);
3710 }
3711 }
3712 this.watchFunctions = narray;
3713 }
3714 return ret;
3715 };
3716
3717 Renderer.prototype.splitFragmentsIntoLines = function (fragments, styles) {
3718 var currentLineLength,
3719 defaultFontSize,
3720 ff,
3721 fontMetrics,
3722 fontMetricsCache,
3723 fragment,
3724 fragmentChopped,
3725 fragmentLength,
3726 fragmentSpecificMetrics,
3727 fs,
3728 k,
3729 line,
3730 lines,
3731 maxLineLength,
3732 style;
3733 defaultFontSize = 12;
3734 k = this.pdf.internal.scaleFactor;
3735 fontMetricsCache = {};
3736 ff = void 0;
3737 fs = void 0;
3738 fontMetrics = void 0;
3739 fragment = void 0;
3740 style = void 0;
3741 fragmentSpecificMetrics = void 0;
3742 fragmentLength = void 0;
3743 fragmentChopped = void 0;
3744 line = [];
3745 lines = [line];
3746 currentLineLength = 0;
3747 maxLineLength = this.settings.width;
3748 while (fragments.length) {
3749 fragment = fragments.shift();
3750 style = styles.shift();
3751 if (fragment) {
3752 ff = style["font-family"];
3753 fs = style["font-style"];
3754 fontMetrics = fontMetricsCache[ff + fs];
3755 if (!fontMetrics) {
3756 fontMetrics = this.pdf.internal.getFont(ff, fs).metadata.Unicode;
3757 fontMetricsCache[ff + fs] = fontMetrics;
3758 }
3759 fragmentSpecificMetrics = {
3760 widths : fontMetrics.widths,
3761 kerning : fontMetrics.kerning,
3762 fontSize : style["font-size"] * defaultFontSize,
3763 textIndent : currentLineLength
3764 };
3765 fragmentLength = this.pdf.getStringUnitWidth(fragment, fragmentSpecificMetrics) * fragmentSpecificMetrics.fontSize / k;
3766 if (currentLineLength + fragmentLength > maxLineLength) {
3767 fragmentChopped = this.pdf.splitTextToSize(fragment, maxLineLength, fragmentSpecificMetrics);
3768 line.push([fragmentChopped.shift(), style]);
3769 while (fragmentChopped.length) {
3770 line = [[fragmentChopped.shift(), style]];
3771 lines.push(line);
3772 }
3773 currentLineLength = this.pdf.getStringUnitWidth(line[0][0], fragmentSpecificMetrics) * fragmentSpecificMetrics.fontSize / k;
3774 } else {
3775 line.push([fragment, style]);
3776 currentLineLength += fragmentLength;
3777 }
3778 }
3779 }
3780
3781 //if text alignment was set, set margin/indent of each line
3782 if (style['text-align'] !== undefined && (style['text-align'] === 'center' || style['text-align'] === 'right' || style['text-align'] === 'justify')) {
3783 for (var i = 0; i < lines.length; ++i) {
3784 var length = this.pdf.getStringUnitWidth(lines[i][0][0], fragmentSpecificMetrics) * fragmentSpecificMetrics.fontSize / k;
3785 //if there is more than on line we have to clone the style object as all lines hold a reference on this object
3786 if (i > 0) {
3787 lines[i][0][1] = clone(lines[i][0][1]);
3788 }
3789 var space = (maxLineLength - length);
3790
3791 if (style['text-align'] === 'right') {
3792 lines[i][0][1]['margin-left'] = space;
3793 //if alignment is not right, it has to be center so split the space to the left and the right
3794 } else if (style['text-align'] === 'center') {
3795 lines[i][0][1]['margin-left'] = space / 2;
3796 //if justify was set, calculate the word spacing and define in by using the css property
3797 } else if (style['text-align'] === 'justify') {
3798 var countSpaces = lines[i][0][0].split(' ').length - 1;
3799 lines[i][0][1]['word-spacing'] = space / countSpaces;
3800 //ignore the last line in justify mode
3801 if (i === (lines.length - 1)) {
3802 lines[i][0][1]['word-spacing'] = 0;
3803 }
3804 }
3805 }
3806 }
3807
3808 return lines;
3809 };
3810 Renderer.prototype.RenderTextFragment = function (text, style) {
3811 var defaultFontSize,
3812 font,
3813 maxLineHeight;
3814
3815 maxLineHeight = 0;
3816 defaultFontSize = 12;
3817
3818 if (this.pdf.internal.pageSize.height - this.pdf.margins_doc.bottom < this.y + this.pdf.internal.getFontSize()) {
3819 this.pdf.internal.write("ET", "Q");
3820 this.pdf.addPage();
3821 this.y = this.pdf.margins_doc.top;
3822 this.pdf.internal.write("q", "BT 0 g", this.pdf.internal.getCoordinateString(this.x), this.pdf.internal.getVerticalCoordinateString(this.y), "Td");
3823 //move cursor by one line on new page
3824 maxLineHeight = Math.max(maxLineHeight, style["line-height"], style["font-size"]);
3825 this.pdf.internal.write(0, (-1 * defaultFontSize * maxLineHeight).toFixed(2), "Td");
3826 }
3827
3828 font = this.pdf.internal.getFont(style["font-family"], style["font-style"]);
3829
3830 //set the word spacing for e.g. justify style
3831 if (style['word-spacing'] !== undefined && style['word-spacing'] > 0) {
3832 this.pdf.internal.write(style['word-spacing'].toFixed(2), "Tw");
3833 }
3834
3835 this.pdf.internal.write("/" + font.id, (defaultFontSize * style["font-size"]).toFixed(2), "Tf", "(" + this.pdf.internal.pdfEscape(text) + ") Tj");
3836
3837 //set the word spacing back to neutral => 0
3838 if (style['word-spacing'] !== undefined) {
3839 this.pdf.internal.write(0, "Tw");
3840 }
3841 };
3842 Renderer.prototype.renderParagraph = function (cb) {
3843 var blockstyle,
3844 defaultFontSize,
3845 fontToUnitRatio,
3846 fragments,
3847 i,
3848 l,
3849 line,
3850 lines,
3851 maxLineHeight,
3852 out,
3853 paragraphspacing_after,
3854 paragraphspacing_before,
3855 priorblockstype,
3856 styles,
3857 fontSize;
3858 fragments = PurgeWhiteSpace(this.paragraph.text);
3859 styles = this.paragraph.style;
3860 blockstyle = this.paragraph.blockstyle;
3861 priorblockstype = this.paragraph.blockstyle || {};
3862 this.paragraph = {
3863 text : [],
3864 style : [],
3865 blockstyle : {},
3866 priorblockstyle : blockstyle
3867 };
3868 if (!fragments.join("").trim()) {
3869 return;
3870 }
3871 lines = this.splitFragmentsIntoLines(fragments, styles);
3872 line = void 0;
3873 maxLineHeight = void 0;
3874 defaultFontSize = 12;
3875 fontToUnitRatio = defaultFontSize / this.pdf.internal.scaleFactor;
3876 paragraphspacing_before = (Math.max((blockstyle["margin-top"] || 0) - (priorblockstype["margin-bottom"] || 0), 0) + (blockstyle["padding-top"] || 0)) * fontToUnitRatio;
3877 paragraphspacing_after = ((blockstyle["margin-bottom"] || 0) + (blockstyle["padding-bottom"] || 0)) * fontToUnitRatio;
3878 out = this.pdf.internal.write;
3879 i = void 0;
3880 l = void 0;
3881 this.y += paragraphspacing_before;
3882 out("q", "BT 0 g", this.pdf.internal.getCoordinateString(this.x), this.pdf.internal.getVerticalCoordinateString(this.y), "Td");
3883
3884 //stores the current indent of cursor position
3885 var currentIndent = 0;
3886
3887 while (lines.length) {
3888 line = lines.shift();
3889 maxLineHeight = 0;
3890 i = 0;
3891 l = line.length;
3892 while (i !== l) {
3893 if (line[i][0].trim()) {
3894 maxLineHeight = Math.max(maxLineHeight, line[i][1]["line-height"], line[i][1]["font-size"]);
3895 fontSize = line[i][1]["font-size"] * 7;
3896 }
3897 i++;
3898 }
3899 //if we have to move the cursor to adapt the indent
3900 var indentMove = 0;
3901 //if a margin was added (by e.g. a text-alignment), move the cursor
3902 if (line[0][1]["margin-left"] !== undefined && line[0][1]["margin-left"] > 0) {
3903 wantedIndent = this.pdf.internal.getCoordinateString(line[0][1]["margin-left"]);
3904 indentMove = wantedIndent - currentIndent;
3905 currentIndent = wantedIndent;
3906 }
3907 //move the cursor
3908 out(indentMove, (-1 * defaultFontSize * maxLineHeight).toFixed(2), "Td");
3909 i = 0;
3910 l = line.length;
3911 while (i !== l) {
3912 if (line[i][0]) {
3913 this.RenderTextFragment(line[i][0], line[i][1]);
3914 }
3915 i++;
3916 }
3917 this.y += maxLineHeight * fontToUnitRatio;
3918
3919 //if some watcher function was executed sucessful, so e.g. margin and widths were changed,
3920 //reset line drawing and calculate position and lines again
3921 //e.g. to stop text floating around an image
3922 if (this.executeWatchFunctions(line[0][1]) && lines.length > 0) {
3923 var localFragments = [];
3924 var localStyles = [];
3925 //create fragement array of
3926 lines.forEach(function(localLine) {
3927 var i = 0;
3928 var l = localLine.length;
3929 while (i !== l) {
3930 if (localLine[i][0]) {
3931 localFragments.push(localLine[i][0]+' ');
3932 localStyles.push(localLine[i][1]);
3933 }
3934 ++i;
3935 }
3936 });
3937 //split lines again due to possible coordinate changes
3938 lines = this.splitFragmentsIntoLines(PurgeWhiteSpace(localFragments), localStyles);
3939 //reposition the current cursor
3940 out("ET", "Q");
3941 out("q", "BT 0 g", this.pdf.internal.getCoordinateString(this.x), this.pdf.internal.getVerticalCoordinateString(this.y), "Td");
3942 }
3943
3944 }
3945 if (cb && typeof cb === "function") {
3946 cb.call(this, this.x - 9, this.y - fontSize / 2);
3947 }
3948 out("ET", "Q");
3949 return this.y += paragraphspacing_after;
3950 };
3951 Renderer.prototype.setBlockBoundary = function (cb) {
3952 return this.renderParagraph(cb);
3953 };
3954 Renderer.prototype.setBlockStyle = function (css) {
3955 return this.paragraph.blockstyle = css;
3956 };
3957 Renderer.prototype.addText = function (text, css) {
3958 this.paragraph.text.push(text);
3959 return this.paragraph.style.push(css);
3960 };
3961 FontNameDB = {
3962 helvetica : "helvetica",
3963 "sans-serif" : "helvetica",
3964 "times new roman" : "times",
3965 serif : "times",
3966 times : "times",
3967 monospace : "courier",
3968 courier : "courier"
3969 };
3970 FontWeightMap = {
3971 100 : "normal",
3972 200 : "normal",
3973 300 : "normal",
3974 400 : "normal",
3975 500 : "bold",
3976 600 : "bold",
3977 700 : "bold",
3978 800 : "bold",
3979 900 : "bold",
3980 normal : "normal",
3981 bold : "bold",
3982 bolder : "bold",
3983 lighter : "normal"
3984 };
3985 FontStyleMap = {
3986 normal : "normal",
3987 italic : "italic",
3988 oblique : "italic"
3989 };
3990 TextAlignMap = {
3991 left : "left",
3992 right : "right",
3993 center : "center",
3994 justify : "justify"
3995 };
3996 FloatMap = {
3997 none : 'none',
3998 right: 'right',
3999 left: 'left'
4000 };
4001 ClearMap = {
4002 none : 'none',
4003 both : 'both'
4004 };
4005 UnitedNumberMap = {
4006 normal : 1
4007 };
4008 /**
4009 * Converts HTML-formatted text into formatted PDF text.
4010 *
4011 * Notes:
4012 * 2012-07-18
4013 * Plugin relies on having browser, DOM around. The HTML is pushed into dom and traversed.
4014 * Plugin relies on jQuery for CSS extraction.
4015 * Targeting HTML output from Markdown templating, which is a very simple
4016 * markup - div, span, em, strong, p. No br-based paragraph separation supported explicitly (but still may work.)
4017 * Images, tables are NOT supported.
4018 *
4019 * @public
4020 * @function
4021 * @param HTML {String or DOM Element} HTML-formatted text, or pointer to DOM element that is to be rendered into PDF.
4022 * @param x {Number} starting X coordinate in jsPDF instance's declared units.
4023 * @param y {Number} starting Y coordinate in jsPDF instance's declared units.
4024 * @param settings {Object} Additional / optional variables controlling parsing, rendering.
4025 * @returns {Object} jsPDF instance
4026 */
4027 jsPDFAPI.fromHTML = function (HTML, x, y, settings, callback, margins) {
4028 "use strict";
4029
4030 this.margins_doc = margins || {
4031 top : 0,
4032 bottom : 0
4033 };
4034 if (!settings)
4035 settings = {};
4036 if (!settings.elementHandlers)
4037 settings.elementHandlers = {};
4038
4039 return process(this, HTML, isNaN(x) ? 4 : x, isNaN(y) ? 4 : y, settings, callback);
4040 };
4041})(jsPDF.API);
4042/** ====================================================================
4043 * jsPDF JavaScript plugin
4044 * Copyright (c) 2013 Youssef Beddad, youssef.beddad@gmail.com
4045 *
4046 * Permission is hereby granted, free of charge, to any person obtaining
4047 * a copy of this software and associated documentation files (the
4048 * "Software"), to deal in the Software without restriction, including
4049 * without limitation the rights to use, copy, modify, merge, publish,
4050 * distribute, sublicense, and/or sell copies of the Software, and to
4051 * permit persons to whom the Software is furnished to do so, subject to
4052 * the following conditions:
4053 *
4054 * The above copyright notice and this permission notice shall be
4055 * included in all copies or substantial portions of the Software.
4056 *
4057 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
4058 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
4059 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
4060 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
4061 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
4062 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
4063 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
4064 * ====================================================================
4065 */
4066
4067/*global jsPDF */
4068
4069(function (jsPDFAPI) {
4070 'use strict';
4071 var jsNamesObj, jsJsObj, text;
4072 jsPDFAPI.addJS = function (txt) {
4073 text = txt;
4074 this.internal.events.subscribe(
4075 'postPutResources',
4076 function (txt) {
4077 jsNamesObj = this.internal.newObject();
4078 this.internal.write('<< /Names [(EmbeddedJS) ' + (jsNamesObj + 1) + ' 0 R] >>', 'endobj');
4079 jsJsObj = this.internal.newObject();
4080 this.internal.write('<< /S /JavaScript /JS (', text, ') >>', 'endobj');
4081 }
4082 );
4083 this.internal.events.subscribe(
4084 'putCatalog',
4085 function () {
4086 if (jsNamesObj !== undefined && jsJsObj !== undefined) {
4087 this.internal.write('/Names <</JavaScript ' + jsNamesObj + ' 0 R>>');
4088 }
4089 }
4090 );
4091 return this;
4092 };
4093}(jsPDF.API));
4094/**@preserve
4095 * ====================================================================
4096 * jsPDF PNG PlugIn
4097 * Copyright (c) 2014 James Robb, https://github.com/jamesbrobb
4098 *
4099 * Permission is hereby granted, free of charge, to any person obtaining
4100 * a copy of this software and associated documentation files (the
4101 * "Software"), to deal in the Software without restriction, including
4102 * without limitation the rights to use, copy, modify, merge, publish,
4103 * distribute, sublicense, and/or sell copies of the Software, and to
4104 * permit persons to whom the Software is furnished to do so, subject to
4105 * the following conditions:
4106 *
4107 * The above copyright notice and this permission notice shall be
4108 * included in all copies or substantial portions of the Software.
4109 *
4110 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
4111 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
4112 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
4113 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
4114 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
4115 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
4116 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
4117 * ====================================================================
4118 */
4119
4120(function(jsPDFAPI) {
4121'use strict'
4122
4123 /*
4124 * @see http://www.w3.org/TR/PNG-Chunks.html
4125 *
4126 Color Allowed Interpretation
4127 Type Bit Depths
4128
4129 0 1,2,4,8,16 Each pixel is a grayscale sample.
4130
4131 2 8,16 Each pixel is an R,G,B triple.
4132
4133 3 1,2,4,8 Each pixel is a palette index;
4134 a PLTE chunk must appear.
4135
4136 4 8,16 Each pixel is a grayscale sample,
4137 followed by an alpha sample.
4138
4139 6 8,16 Each pixel is an R,G,B triple,
4140 followed by an alpha sample.
4141 */
4142
4143 /*
4144 * PNG filter method types
4145 *
4146 * @see http://www.w3.org/TR/PNG-Filters.html
4147 * @see http://www.libpng.org/pub/png/book/chapter09.html
4148 *
4149 * This is what the value 'Predictor' in decode params relates to
4150 *
4151 * 15 is "optimal prediction", which means the prediction algorithm can change from line to line.
4152 * 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.
4153 *
4154 0 None
4155 1 Sub
4156 2 Up
4157 3 Average
4158 4 Paeth
4159 */
4160
4161 var doesNotHavePngJS = function() {
4162 return typeof PNG !== 'function' || typeof FlateStream !== 'function';
4163 }
4164 , canCompress = function(value) {
4165 return value !== jsPDFAPI.image_compression.NONE && hasCompressionJS();
4166 }
4167 , hasCompressionJS = function() {
4168 var inst = typeof Deflater === 'function';
4169 if(!inst)
4170 throw new Error("requires deflate.js for compression")
4171 return inst;
4172 }
4173 , compressBytes = function(bytes, lineLength, colorsPerPixel, compression) {
4174
4175 var level = 5,
4176 filter_method = filterUp;
4177
4178 switch(compression) {
4179
4180 case jsPDFAPI.image_compression.FAST:
4181
4182 level = 3;
4183 filter_method = filterSub;
4184 break;
4185
4186 case jsPDFAPI.image_compression.MEDIUM:
4187
4188 level = 6;
4189 filter_method = filterAverage;
4190 break;
4191
4192 case jsPDFAPI.image_compression.SLOW:
4193
4194 level = 9;
4195 filter_method = filterPaeth;//uses to sum to choose best filter for each line
4196 break;
4197 }
4198
4199 bytes = applyPngFilterMethod(bytes, lineLength, colorsPerPixel, filter_method);
4200
4201 var header = new Uint8Array(createZlibHeader(level));
4202 var checksum = adler32(bytes);
4203
4204 var deflate = new Deflater(level);
4205 var a = deflate.append(bytes);
4206 var cBytes = deflate.flush();
4207
4208 var len = header.length + a.length + cBytes.length;
4209
4210 var cmpd = new Uint8Array(len + 4);
4211 cmpd.set(header);
4212 cmpd.set(a, header.length);
4213 cmpd.set(cBytes, header.length + a.length);
4214
4215 cmpd[len++] = (checksum >>> 24) & 0xff;
4216 cmpd[len++] = (checksum >>> 16) & 0xff;
4217 cmpd[len++] = (checksum >>> 8) & 0xff;
4218 cmpd[len++] = checksum & 0xff;
4219
4220 return jsPDFAPI.arrayBufferToBinaryString(cmpd);
4221 }
4222 , createZlibHeader = function(bytes, level){
4223 /*
4224 * @see http://www.ietf.org/rfc/rfc1950.txt for zlib header
4225 */
4226 var cm = 8;
4227 var cinfo = Math.LOG2E * Math.log(0x8000) - 8;
4228 var cmf = (cinfo << 4) | cm;
4229
4230 var hdr = cmf << 8;
4231 var flevel = Math.min(3, ((level - 1) & 0xff) >> 1);
4232
4233 hdr |= (flevel << 6);
4234 hdr |= 0;//FDICT
4235 hdr += 31 - (hdr % 31);
4236
4237 return [cmf, (hdr & 0xff) & 0xff];
4238 }
4239 , adler32 = function(array, param) {
4240 var adler = 1;
4241 var s1 = adler & 0xffff,
4242 s2 = (adler >>> 16) & 0xffff;
4243 var len = array.length;
4244 var tlen;
4245 var i = 0;
4246
4247 while (len > 0) {
4248 tlen = len > param ? param : len;
4249 len -= tlen;
4250 do {
4251 s1 += array[i++];
4252 s2 += s1;
4253 } while (--tlen);
4254
4255 s1 %= 65521;
4256 s2 %= 65521;
4257 }
4258
4259 return ((s2 << 16) | s1) >>> 0;
4260 }
4261 , applyPngFilterMethod = function(bytes, lineLength, colorsPerPixel, filter_method) {
4262 var lines = bytes.length / lineLength,
4263 result = new Uint8Array(bytes.length + lines),
4264 filter_methods = getFilterMethods(),
4265 i = 0, line, prevLine, offset;
4266
4267 for(; i < lines; i++) {
4268 offset = i * lineLength;
4269 line = bytes.subarray(offset, offset + lineLength);
4270
4271 if(filter_method) {
4272 result.set(filter_method(line, colorsPerPixel, prevLine), offset + i);
4273
4274 }else{
4275
4276 var j = 0,
4277 len = filter_methods.length,
4278 results = [];
4279
4280 for(; j < len; j++)
4281 results[j] = filter_methods[j](line, colorsPerPixel, prevLine);
4282
4283 var ind = getIndexOfSmallestSum(results.concat());
4284
4285 result.set(results[ind], offset + i);
4286 }
4287
4288 prevLine = line;
4289 }
4290
4291 return result;
4292 }
4293 , filterNone = function(line, colorsPerPixel, prevLine) {
4294 /*var result = new Uint8Array(line.length + 1);
4295 result[0] = 0;
4296 result.set(line, 1);*/
4297
4298 var result = Array.apply([], line);
4299 result.unshift(0);
4300
4301 return result;
4302 }
4303 , filterSub = function(line, colorsPerPixel, prevLine) {
4304 var result = [],
4305 i = 0,
4306 len = line.length,
4307 left;
4308
4309 result[0] = 1;
4310
4311 for(; i < len; i++) {
4312 left = line[i - colorsPerPixel] || 0;
4313 result[i + 1] = (line[i] - left + 0x0100) & 0xff;
4314 }
4315
4316 return result;
4317 }
4318 , filterUp = function(line, colorsPerPixel, prevLine) {
4319 var result = [],
4320 i = 0,
4321 len = line.length,
4322 up;
4323
4324 result[0] = 2;
4325
4326 for(; i < len; i++) {
4327 up = prevLine && prevLine[i] || 0;
4328 result[i + 1] = (line[i] - up + 0x0100) & 0xff;
4329 }
4330
4331 return result;
4332 }
4333 , filterAverage = function(line, colorsPerPixel, prevLine) {
4334 var result = [],
4335 i = 0,
4336 len = line.length,
4337 left,
4338 up;
4339
4340 result[0] = 3;
4341
4342 for(; i < len; i++) {
4343 left = line[i - colorsPerPixel] || 0;
4344 up = prevLine && prevLine[i] || 0;
4345 result[i + 1] = (line[i] + 0x0100 - ((left + up) >>> 1)) & 0xff;
4346 }
4347
4348 return result;
4349 }
4350 , filterPaeth = function(line, colorsPerPixel, prevLine) {
4351 var result = [],
4352 i = 0,
4353 len = line.length,
4354 left,
4355 up,
4356 upLeft,
4357 paeth;
4358
4359 result[0] = 4;
4360
4361 for(; i < len; i++) {
4362 left = line[i - colorsPerPixel] || 0;
4363 up = prevLine && prevLine[i] || 0;
4364 upLeft = prevLine && prevLine[i - colorsPerPixel] || 0;
4365 paeth = paethPredictor(left, up, upLeft);
4366 result[i + 1] = (line[i] - paeth + 0x0100) & 0xff;
4367 }
4368
4369 return result;
4370 }
4371 ,paethPredictor = function(left, up, upLeft) {
4372
4373 var p = left + up - upLeft,
4374 pLeft = Math.abs(p - left),
4375 pUp = Math.abs(p - up),
4376 pUpLeft = Math.abs(p - upLeft);
4377
4378 return (pLeft <= pUp && pLeft <= pUpLeft) ? left : (pUp <= pUpLeft) ? up : upLeft;
4379 }
4380 , getFilterMethods = function() {
4381 return [filterNone, filterSub, filterUp, filterAverage, filterPaeth];
4382 }
4383 ,getIndexOfSmallestSum = function(arrays) {
4384 var i = 0,
4385 len = arrays.length,
4386 sum, min, ind;
4387
4388 while(i < len) {
4389 sum = absSum(arrays[i].slice(1));
4390
4391 if(sum < min || !min) {
4392 min = sum;
4393 ind = i;
4394 }
4395
4396 i++;
4397 }
4398
4399 return ind;
4400 }
4401 , absSum = function(array) {
4402 var i = 0,
4403 len = array.length,
4404 sum = 0;
4405
4406 while(i < len)
4407 sum += Math.abs(array[i++]);
4408
4409 return sum;
4410 }
4411 , logImg = function(img) {
4412 console.log("width: " + img.width);
4413 console.log("height: " + img.height);
4414 console.log("bits: " + img.bits);
4415 console.log("colorType: " + img.colorType);
4416 console.log("transparency:");
4417 console.log(img.transparency);
4418 console.log("text:");
4419 console.log(img.text);
4420 console.log("compressionMethod: " + img.compressionMethod);
4421 console.log("filterMethod: " + img.filterMethod);
4422 console.log("interlaceMethod: " + img.interlaceMethod);
4423 console.log("imgData:");
4424 console.log(img.imgData);
4425 console.log("palette:");
4426 console.log(img.palette);
4427 console.log("colors: " + img.colors);
4428 console.log("colorSpace: " + img.colorSpace);
4429 console.log("pixelBitlength: " + img.pixelBitlength);
4430 console.log("hasAlphaChannel: " + img.hasAlphaChannel);
4431 };
4432
4433
4434
4435
4436 jsPDFAPI.processPNG = function(imageData, imageIndex, alias, compression, dataAsBinaryString) {
4437 'use strict'
4438
4439 var colorSpace = this.color_spaces.DEVICE_RGB,
4440 decode = this.decode.FLATE_DECODE,
4441 bpc = 8,
4442 img, dp, trns,
4443 colors, pal, smask;
4444
4445 /* if(this.isString(imageData)) {
4446
4447 }*/
4448
4449 if(this.isArrayBuffer(imageData))
4450 imageData = new Uint8Array(imageData);
4451
4452 if(this.isArrayBufferView(imageData)) {
4453
4454 if(doesNotHavePngJS())
4455 throw new Error("PNG support requires png.js and zlib.js");
4456
4457 img = new PNG(imageData);
4458 imageData = img.imgData;
4459 bpc = img.bits;
4460 colorSpace = img.colorSpace;
4461 colors = img.colors;
4462
4463 //logImg(img);
4464
4465 /*
4466 * colorType 6 - Each pixel is an R,G,B triple, followed by an alpha sample.
4467 *
4468 * colorType 4 - Each pixel is a grayscale sample, followed by an alpha sample.
4469 *
4470 * Extract alpha to create two separate images, using the alpha as a sMask
4471 */
4472 if([4,6].indexOf(img.colorType) !== -1) {
4473
4474 /*
4475 * processes 8 bit RGBA and grayscale + alpha images
4476 */
4477 if(img.bits === 8) {
4478
4479 var pixelsArrayType = window['Uint' + img.pixelBitlength + 'Array'],
4480 pixels = new pixelsArrayType(img.decodePixels().buffer),
4481 len = pixels.length,
4482 imgData = new Uint8Array(len * img.colors),
4483 alphaData = new Uint8Array(len),
4484 pDiff = img.pixelBitlength - img.bits,
4485 i = 0, n = 0, pixel, pbl;
4486
4487 for(; i < len; i++) {
4488 pixel = pixels[i];
4489 pbl = 0;
4490
4491 while(pbl < pDiff) {
4492
4493 imgData[n++] = ( pixel >>> pbl ) & 0xff;
4494 pbl = pbl + img.bits;
4495 }
4496
4497 alphaData[i] = ( pixel >>> pbl ) & 0xff;
4498 }
4499 }
4500
4501 /*
4502 * processes 16 bit RGBA and grayscale + alpha images
4503 */
4504 if(img.bits === 16) {
4505
4506 var pixels = new Uint32Array(img.decodePixels().buffer),
4507 len = pixels.length,
4508 imgData = new Uint8Array((len * (32 / img.pixelBitlength) ) * img.colors),
4509 alphaData = new Uint8Array(len * (32 / img.pixelBitlength) ),
4510 hasColors = img.colors > 1,
4511 i = 0, n = 0, a = 0, pixel;
4512
4513 while(i < len) {
4514 pixel = pixels[i++];
4515
4516 imgData[n++] = (pixel >>> 0) & 0xFF;
4517
4518 if(hasColors) {
4519 imgData[n++] = (pixel >>> 16) & 0xFF;
4520
4521 pixel = pixels[i++];
4522 imgData[n++] = (pixel >>> 0) & 0xFF;
4523 }
4524
4525 alphaData[a++] = (pixel >>> 16) & 0xFF;
4526 }
4527
4528 bpc = 8;
4529 }
4530
4531 if(canCompress(compression)) {
4532
4533 imageData = compressBytes(imgData, img.width * img.colors, img.colors, compression);
4534 smask = compressBytes(alphaData, img.width, 1, compression);
4535
4536 }else{
4537
4538 imageData = imgData;
4539 smask = alphaData;
4540 decode = null;
4541 }
4542 }
4543
4544 /*
4545 * Indexed png. Each pixel is a palette index.
4546 */
4547 if(img.colorType === 3) {
4548
4549 colorSpace = this.color_spaces.INDEXED;
4550 pal = img.palette;
4551
4552 if(img.transparency.indexed) {
4553
4554 var trans = img.transparency.indexed;
4555
4556 var total = 0,
4557 i = 0,
4558 len = trans.length;
4559
4560 for(; i<len; ++i)
4561 total += trans[i];
4562
4563 total = total / 255;
4564
4565 /*
4566 * a single color is specified as 100% transparent (0),
4567 * so we set trns to use a /Mask with that index
4568 */
4569 if(total === len - 1 && trans.indexOf(0) !== -1) {
4570 trns = [trans.indexOf(0)];
4571
4572 /*
4573 * there's more than one colour within the palette that specifies
4574 * a transparency value less than 255, so we unroll the pixels to create an image sMask
4575 */
4576 }else if(total !== len){
4577
4578 var pixels = img.decodePixels(),
4579 alphaData = new Uint8Array(pixels.length),
4580 i = 0,
4581 len = pixels.length;
4582
4583 for(; i < len; i++)
4584 alphaData[i] = trans[pixels[i]];
4585
4586 smask = compressBytes(alphaData, img.width, 1);
4587 }
4588 }
4589 }
4590
4591 if(decode === this.decode.FLATE_DECODE)
4592 dp = '/Predictor 15 /Colors '+ colors +' /BitsPerComponent '+ bpc +' /Columns '+ img.width;
4593 else
4594 //remove 'Predictor' as it applies to the type of png filter applied to its IDAT - we only apply with compression
4595 dp = '/Colors '+ colors +' /BitsPerComponent '+ bpc +' /Columns '+ img.width;
4596
4597 if(this.isArrayBuffer(imageData) || this.isArrayBufferView(imageData))
4598 imageData = this.arrayBufferToBinaryString(imageData);
4599
4600 if(smask && this.isArrayBuffer(smask) || this.isArrayBufferView(smask))
4601 smask = this.arrayBufferToBinaryString(smask);
4602
4603 return this.createImageInfo(imageData, img.width, img.height, colorSpace,
4604 bpc, decode, imageIndex, alias, dp, trns, pal, smask);
4605 }
4606
4607 throw new Error("Unsupported PNG image data, try using JPEG instead.");
4608 }
4609
4610})(jsPDF.API)
4611/** @preserve
4612jsPDF Silly SVG plugin
4613Copyright (c) 2012 Willow Systems Corporation, willow-systems.com
4614*/
4615/**
4616 * Permission is hereby granted, free of charge, to any person obtaining
4617 * a copy of this software and associated documentation files (the
4618 * "Software"), to deal in the Software without restriction, including
4619 * without limitation the rights to use, copy, modify, merge, publish,
4620 * distribute, sublicense, and/or sell copies of the Software, and to
4621 * permit persons to whom the Software is furnished to do so, subject to
4622 * the following conditions:
4623 *
4624 * The above copyright notice and this permission notice shall be
4625 * included in all copies or substantial portions of the Software.
4626 *
4627 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
4628 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
4629 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
4630 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
4631 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
4632 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
4633 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
4634 * ====================================================================
4635 */
4636
4637;(function(jsPDFAPI) {
4638'use strict'
4639
4640/**
4641Parses SVG XML and converts only some of the SVG elements into
4642PDF elements.
4643
4644Supports:
4645 paths
4646
4647@public
4648@function
4649@param
4650@returns {Type}
4651*/
4652jsPDFAPI.addSVG = function(svgtext, x, y, w, h) {
4653 // 'this' is _jsPDF object returned when jsPDF is inited (new jsPDF())
4654
4655 var undef
4656
4657 if (x === undef || y === undef) {
4658 throw new Error("addSVG needs values for 'x' and 'y'");
4659 }
4660
4661 function InjectCSS(cssbody, document) {
4662 var styletag = document.createElement('style');
4663 styletag.type = 'text/css';
4664 if (styletag.styleSheet) {
4665 // ie
4666 styletag.styleSheet.cssText = cssbody;
4667 } else {
4668 // others
4669 styletag.appendChild(document.createTextNode(cssbody));
4670 }
4671 document.getElementsByTagName("head")[0].appendChild(styletag);
4672 }
4673
4674 function createWorkerNode(document){
4675
4676 var frameID = 'childframe' // Date.now().toString() + '_' + (Math.random() * 100).toString()
4677 , frame = document.createElement('iframe')
4678
4679 InjectCSS(
4680 '.jsPDF_sillysvg_iframe {display:none;position:absolute;}'
4681 , document
4682 )
4683
4684 frame.name = frameID
4685 frame.setAttribute("width", 0)
4686 frame.setAttribute("height", 0)
4687 frame.setAttribute("frameborder", "0")
4688 frame.setAttribute("scrolling", "no")
4689 frame.setAttribute("seamless", "seamless")
4690 frame.setAttribute("class", "jsPDF_sillysvg_iframe")
4691
4692 document.body.appendChild(frame)
4693
4694 return frame
4695 }
4696
4697 function attachSVGToWorkerNode(svgtext, frame){
4698 var framedoc = ( frame.contentWindow || frame.contentDocument ).document
4699 framedoc.write(svgtext)
4700 framedoc.close()
4701 return framedoc.getElementsByTagName('svg')[0]
4702 }
4703
4704 function convertPathToPDFLinesArgs(path){
4705 'use strict'
4706 // we will use 'lines' method call. it needs:
4707 // - starting coordinate pair
4708 // - array of arrays of vector shifts (2-len for line, 6 len for bezier)
4709 // - scale array [horizontal, vertical] ratios
4710 // - style (stroke, fill, both)
4711
4712 var x = parseFloat(path[1])
4713 , y = parseFloat(path[2])
4714 , vectors = []
4715 , position = 3
4716 , len = path.length
4717
4718 while (position < len){
4719 if (path[position] === 'c'){
4720 vectors.push([
4721 parseFloat(path[position + 1])
4722 , parseFloat(path[position + 2])
4723 , parseFloat(path[position + 3])
4724 , parseFloat(path[position + 4])
4725 , parseFloat(path[position + 5])
4726 , parseFloat(path[position + 6])
4727 ])
4728 position += 7
4729 } else if (path[position] === 'l') {
4730 vectors.push([
4731 parseFloat(path[position + 1])
4732 , parseFloat(path[position + 2])
4733 ])
4734 position += 3
4735 } else {
4736 position += 1
4737 }
4738 }
4739 return [x,y,vectors]
4740 }
4741
4742 var workernode = createWorkerNode(document)
4743 , svgnode = attachSVGToWorkerNode(svgtext, workernode)
4744 , scale = [1,1]
4745 , svgw = parseFloat(svgnode.getAttribute('width'))
4746 , svgh = parseFloat(svgnode.getAttribute('height'))
4747
4748 if (svgw && svgh) {
4749 // setting both w and h makes image stretch to size.
4750 // this may distort the image, but fits your demanded size
4751 if (w && h) {
4752 scale = [w / svgw, h / svgh]
4753 }
4754 // if only one is set, that value is set as max and SVG
4755 // is scaled proportionately.
4756 else if (w) {
4757 scale = [w / svgw, w / svgw]
4758 } else if (h) {
4759 scale = [h / svgh, h / svgh]
4760 }
4761 }
4762
4763 var i, l, tmp
4764 , linesargs
4765 , items = svgnode.childNodes
4766 for (i = 0, l = items.length; i < l; i++) {
4767 tmp = items[i]
4768 if (tmp.tagName && tmp.tagName.toUpperCase() === 'PATH') {
4769 linesargs = convertPathToPDFLinesArgs( tmp.getAttribute("d").split(' ') )
4770 // path start x coordinate
4771 linesargs[0] = linesargs[0] * scale[0] + x // where x is upper left X of image
4772 // path start y coordinate
4773 linesargs[1] = linesargs[1] * scale[1] + y // where y is upper left Y of image
4774 // the rest of lines are vectors. these will adjust with scale value auto.
4775 this.lines.call(
4776 this
4777 , linesargs[2] // lines
4778 , linesargs[0] // starting x
4779 , linesargs[1] // starting y
4780 , scale
4781 )
4782 }
4783 }
4784
4785 // clean up
4786 // workernode.parentNode.removeChild(workernode)
4787
4788 return this
4789}
4790
4791})(jsPDF.API);
4792/** @preserve
4793 * jsPDF split_text_to_size plugin - MIT license.
4794 * Copyright (c) 2012 Willow Systems Corporation, willow-systems.com
4795 * 2014 Diego Casorran, https://github.com/diegocr
4796 */
4797/**
4798 * Permission is hereby granted, free of charge, to any person obtaining
4799 * a copy of this software and associated documentation files (the
4800 * "Software"), to deal in the Software without restriction, including
4801 * without limitation the rights to use, copy, modify, merge, publish,
4802 * distribute, sublicense, and/or sell copies of the Software, and to
4803 * permit persons to whom the Software is furnished to do so, subject to
4804 * the following conditions:
4805 *
4806 * The above copyright notice and this permission notice shall be
4807 * included in all copies or substantial portions of the Software.
4808 *
4809 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
4810 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
4811 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
4812 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
4813 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
4814 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
4815 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
4816 * ====================================================================
4817 */
4818
4819;(function(API) {
4820'use strict'
4821
4822/**
4823Returns an array of length matching length of the 'word' string, with each
4824cell ocupied by the width of the char in that position.
4825
4826@function
4827@param word {String}
4828@param widths {Object}
4829@param kerning {Object}
4830@returns {Array}
4831*/
4832var getCharWidthsArray = API.getCharWidthsArray = function(text, options){
4833
4834 if (!options) {
4835 options = {}
4836 }
4837
4838 var widths = options.widths ? options.widths : this.internal.getFont().metadata.Unicode.widths
4839 , widthsFractionOf = widths.fof ? widths.fof : 1
4840 , kerning = options.kerning ? options.kerning : this.internal.getFont().metadata.Unicode.kerning
4841 , kerningFractionOf = kerning.fof ? kerning.fof : 1
4842
4843 // console.log("widths, kergnings", widths, kerning)
4844
4845 var i, l
4846 , char_code
4847 , prior_char_code = 0 // for kerning
4848 , default_char_width = widths[0] || widthsFractionOf
4849 , output = []
4850
4851 for (i = 0, l = text.length; i < l; i++) {
4852 char_code = text.charCodeAt(i)
4853 output.push(
4854 ( widths[char_code] || default_char_width ) / widthsFractionOf +
4855 ( kerning[char_code] && kerning[char_code][prior_char_code] || 0 ) / kerningFractionOf
4856 )
4857 prior_char_code = char_code
4858 }
4859
4860 return output
4861}
4862var getArraySum = function(array){
4863 var i = array.length
4864 , output = 0
4865 while(i){
4866 ;i--;
4867 output += array[i]
4868 }
4869 return output
4870}
4871/**
4872Returns a widths of string in a given font, if the font size is set as 1 point.
4873
4874In other words, this is "proportional" value. For 1 unit of font size, the length
4875of the string will be that much.
4876
4877Multiply by font size to get actual width in *points*
4878Then divide by 72 to get inches or divide by (72/25.6) to get 'mm' etc.
4879
4880@public
4881@function
4882@param
4883@returns {Type}
4884*/
4885var getStringUnitWidth = API.getStringUnitWidth = function(text, options) {
4886 return getArraySum(getCharWidthsArray.call(this, text, options))
4887}
4888
4889/**
4890returns array of lines
4891*/
4892var splitLongWord = function(word, widths_array, firstLineMaxLen, maxLen){
4893 var answer = []
4894
4895 // 1st, chop off the piece that can fit on the hanging line.
4896 var i = 0
4897 , l = word.length
4898 , workingLen = 0
4899 while (i !== l && workingLen + widths_array[i] < firstLineMaxLen){
4900 workingLen += widths_array[i]
4901 ;i++;
4902 }
4903 // this is first line.
4904 answer.push(word.slice(0, i))
4905
4906 // 2nd. Split the rest into maxLen pieces.
4907 var startOfLine = i
4908 workingLen = 0
4909 while (i !== l){
4910 if (workingLen + widths_array[i] > maxLen) {
4911 answer.push(word.slice(startOfLine, i))
4912 workingLen = 0
4913 startOfLine = i
4914 }
4915 workingLen += widths_array[i]
4916 ;i++;
4917 }
4918 if (startOfLine !== i) {
4919 answer.push(word.slice(startOfLine, i))
4920 }
4921
4922 return answer
4923}
4924
4925// Note, all sizing inputs for this function must be in "font measurement units"
4926// By default, for PDF, it's "point".
4927var splitParagraphIntoLines = function(text, maxlen, options){
4928 // at this time works only on Western scripts, ones with space char
4929 // separating the words. Feel free to expand.
4930
4931 if (!options) {
4932 options = {}
4933 }
4934
4935 var line = []
4936 , lines = [line]
4937 , line_length = options.textIndent || 0
4938 , separator_length = 0
4939 , current_word_length = 0
4940 , word
4941 , widths_array
4942 , words = text.split(' ')
4943 , spaceCharWidth = getCharWidthsArray(' ', options)[0]
4944 , i, l, tmp, lineIndent
4945
4946 if(options.lineIndent === -1) {
4947 lineIndent = words[0].length +2;
4948 } else {
4949 lineIndent = options.lineIndent || 0;
4950 }
4951 if(lineIndent) {
4952 var pad = Array(lineIndent).join(" "), wrds = [];
4953 words.map(function(wrd) {
4954 wrd = wrd.split(/\s*\n/);
4955 if(wrd.length > 1) {
4956 wrds = wrds.concat(wrd.map(function(wrd, idx) {
4957 return (idx && wrd.length ? "\n":"") + wrd;
4958 }));
4959 } else {
4960 wrds.push(wrd[0]);
4961 }
4962 });
4963 words = wrds;
4964 lineIndent = getStringUnitWidth(pad, options);
4965 }
4966
4967 for (i = 0, l = words.length; i < l; i++) {
4968 var force = 0;
4969
4970 word = words[i]
4971 if(lineIndent && word[0] == "\n") {
4972 word = word.substr(1);
4973 force = 1;
4974 }
4975 widths_array = getCharWidthsArray(word, options)
4976 current_word_length = getArraySum(widths_array)
4977
4978 if (line_length + separator_length + current_word_length > maxlen || force) {
4979 if (current_word_length > maxlen) {
4980 // this happens when you have space-less long URLs for example.
4981 // we just chop these to size. We do NOT insert hiphens
4982 tmp = splitLongWord(word, widths_array, maxlen - (line_length + separator_length), maxlen)
4983 // first line we add to existing line object
4984 line.push(tmp.shift()) // it's ok to have extra space indicator there
4985 // last line we make into new line object
4986 line = [tmp.pop()]
4987 // lines in the middle we apped to lines object as whole lines
4988 while(tmp.length){
4989 lines.push([tmp.shift()]) // single fragment occupies whole line
4990 }
4991 current_word_length = getArraySum( widths_array.slice(word.length - line[0].length) )
4992 } else {
4993 // just put it on a new line
4994 line = [word]
4995 }
4996
4997 // now we attach new line to lines
4998 lines.push(line)
4999 line_length = current_word_length + lineIndent
5000 separator_length = spaceCharWidth
5001
5002 } else {
5003 line.push(word)
5004
5005 line_length += separator_length + current_word_length
5006 separator_length = spaceCharWidth
5007 }
5008 }
5009
5010 if(lineIndent) {
5011 var postProcess = function(ln, idx) {
5012 return (idx ? pad : '') + ln.join(" ");
5013 };
5014 } else {
5015 var postProcess = function(ln) { return ln.join(" ")};
5016 }
5017
5018 return lines.map(postProcess);
5019}
5020
5021/**
5022Splits a given string into an array of strings. Uses 'size' value
5023(in measurement units declared as default for the jsPDF instance)
5024and the font's "widths" and "Kerning" tables, where availabe, to
5025determine display length of a given string for a given font.
5026
5027We use character's 100% of unit size (height) as width when Width
5028table or other default width is not available.
5029
5030@public
5031@function
5032@param text {String} Unencoded, regular JavaScript (Unicode, UTF-16 / UCS-2) string.
5033@param size {Number} Nominal number, measured in units default to this instance of jsPDF.
5034@param options {Object} Optional flags needed for chopper to do the right thing.
5035@returns {Array} with strings chopped to size.
5036*/
5037API.splitTextToSize = function(text, maxlen, options) {
5038 'use strict'
5039
5040 if (!options) {
5041 options = {}
5042 }
5043
5044 var fsize = options.fontSize || this.internal.getFontSize()
5045 , newOptions = (function(options){
5046 var widths = {0:1}
5047 , kerning = {}
5048
5049 if (!options.widths || !options.kerning) {
5050 var f = this.internal.getFont(options.fontName, options.fontStyle)
5051 , encoding = 'Unicode'
5052 // NOT UTF8, NOT UTF16BE/LE, NOT UCS2BE/LE
5053 // Actual JavaScript-native String's 16bit char codes used.
5054 // no multi-byte logic here
5055
5056 if (f.metadata[encoding]) {
5057 return {
5058 widths: f.metadata[encoding].widths || widths
5059 , kerning: f.metadata[encoding].kerning || kerning
5060 }
5061 }
5062 } else {
5063 return {
5064 widths: options.widths
5065 , kerning: options.kerning
5066 }
5067 }
5068
5069 // then use default values
5070 return {
5071 widths: widths
5072 , kerning: kerning
5073 }
5074 }).call(this, options)
5075
5076 // first we split on end-of-line chars
5077 var paragraphs
5078 if(Array.isArray(text)) {
5079 paragraphs = text;
5080 } else {
5081 paragraphs = text.split(/\r?\n/);
5082 }
5083
5084 // now we convert size (max length of line) into "font size units"
5085 // at present time, the "font size unit" is always 'point'
5086 // 'proportional' means, "in proportion to font size"
5087 var fontUnit_maxLen = 1.0 * this.internal.scaleFactor * maxlen / fsize
5088 // at this time, fsize is always in "points" regardless of the default measurement unit of the doc.
5089 // this may change in the future?
5090 // until then, proportional_maxlen is likely to be in 'points'
5091
5092 // If first line is to be indented (shorter or longer) than maxLen
5093 // we indicate that by using CSS-style "text-indent" option.
5094 // here it's in font units too (which is likely 'points')
5095 // it can be negative (which makes the first line longer than maxLen)
5096 newOptions.textIndent = options.textIndent ?
5097 options.textIndent * 1.0 * this.internal.scaleFactor / fsize :
5098 0
5099 newOptions.lineIndent = options.lineIndent;
5100
5101 var i, l
5102 , output = []
5103 for (i = 0, l = paragraphs.length; i < l; i++) {
5104 output = output.concat(
5105 splitParagraphIntoLines(
5106 paragraphs[i]
5107 , fontUnit_maxLen
5108 , newOptions
5109 )
5110 )
5111 }
5112
5113 return output
5114}
5115
5116})(jsPDF.API);
5117/** @preserve
5118jsPDF standard_fonts_metrics plugin
5119Copyright (c) 2012 Willow Systems Corporation, willow-systems.com
5120MIT license.
5121*/
5122/**
5123 * Permission is hereby granted, free of charge, to any person obtaining
5124 * a copy of this software and associated documentation files (the
5125 * "Software"), to deal in the Software without restriction, including
5126 * without limitation the rights to use, copy, modify, merge, publish,
5127 * distribute, sublicense, and/or sell copies of the Software, and to
5128 * permit persons to whom the Software is furnished to do so, subject to
5129 * the following conditions:
5130 *
5131 * The above copyright notice and this permission notice shall be
5132 * included in all copies or substantial portions of the Software.
5133 *
5134 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
5135 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
5136 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
5137 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
5138 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
5139 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
5140 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
5141 * ====================================================================
5142 */
5143
5144;(function(API) {
5145'use strict'
5146
5147/*
5148# reference (Python) versions of 'compress' and 'uncompress'
5149# only 'uncompress' function is featured lower as JavaScript
5150# if you want to unit test "roundtrip", just transcribe the reference
5151# 'compress' function from Python into JavaScript
5152
5153def compress(data):
5154
5155 keys = '0123456789abcdef'
5156 values = 'klmnopqrstuvwxyz'
5157 mapping = dict(zip(keys, values))
5158 vals = []
5159 for key in data.keys():
5160 value = data[key]
5161 try:
5162 keystring = hex(key)[2:]
5163 keystring = keystring[:-1] + mapping[keystring[-1:]]
5164 except:
5165 keystring = key.join(["'","'"])
5166 #print('Keystring is %s' % keystring)
5167
5168 try:
5169 if value < 0:
5170 valuestring = hex(value)[3:]
5171 numberprefix = '-'
5172 else:
5173 valuestring = hex(value)[2:]
5174 numberprefix = ''
5175 valuestring = numberprefix + valuestring[:-1] + mapping[valuestring[-1:]]
5176 except:
5177 if type(value) == dict:
5178 valuestring = compress(value)
5179 else:
5180 raise Exception("Don't know what to do with value type %s" % type(value))
5181
5182 vals.append(keystring+valuestring)
5183
5184 return '{' + ''.join(vals) + '}'
5185
5186def uncompress(data):
5187
5188 decoded = '0123456789abcdef'
5189 encoded = 'klmnopqrstuvwxyz'
5190 mapping = dict(zip(encoded, decoded))
5191
5192 sign = +1
5193 stringmode = False
5194 stringparts = []
5195
5196 output = {}
5197
5198 activeobject = output
5199 parentchain = []
5200
5201 keyparts = ''
5202 valueparts = ''
5203
5204 key = None
5205
5206 ending = set(encoded)
5207
5208 i = 1
5209 l = len(data) - 1 # stripping starting, ending {}
5210 while i != l: # stripping {}
5211 # -, {, }, ' are special.
5212
5213 ch = data[i]
5214 i += 1
5215
5216 if ch == "'":
5217 if stringmode:
5218 # end of string mode
5219 stringmode = False
5220 key = ''.join(stringparts)
5221 else:
5222 # start of string mode
5223 stringmode = True
5224 stringparts = []
5225 elif stringmode == True:
5226 #print("Adding %s to stringpart" % ch)
5227 stringparts.append(ch)
5228
5229 elif ch == '{':
5230 # start of object
5231 parentchain.append( [activeobject, key] )
5232 activeobject = {}
5233 key = None
5234 #DEBUG = True
5235 elif ch == '}':
5236 # end of object
5237 parent, key = parentchain.pop()
5238 parent[key] = activeobject
5239 key = None
5240 activeobject = parent
5241 #DEBUG = False
5242
5243 elif ch == '-':
5244 sign = -1
5245 else:
5246 # must be number
5247 if key == None:
5248 #debug("In Key. It is '%s', ch is '%s'" % (keyparts, ch))
5249 if ch in ending:
5250 #debug("End of key")
5251 keyparts += mapping[ch]
5252 key = int(keyparts, 16) * sign
5253 sign = +1
5254 keyparts = ''
5255 else:
5256 keyparts += ch
5257 else:
5258 #debug("In value. It is '%s', ch is '%s'" % (valueparts, ch))
5259 if ch in ending:
5260 #debug("End of value")
5261 valueparts += mapping[ch]
5262 activeobject[key] = int(valueparts, 16) * sign
5263 sign = +1
5264 key = None
5265 valueparts = ''
5266 else:
5267 valueparts += ch
5268
5269 #debug(activeobject)
5270
5271 return output
5272
5273*/
5274
5275/**
5276Uncompresses data compressed into custom, base16-like format.
5277@public
5278@function
5279@param
5280@returns {Type}
5281*/
5282var uncompress = function(data){
5283
5284 var decoded = '0123456789abcdef'
5285 , encoded = 'klmnopqrstuvwxyz'
5286 , mapping = {}
5287
5288 for (var i = 0; i < encoded.length; i++){
5289 mapping[encoded[i]] = decoded[i]
5290 }
5291
5292 var undef
5293 , output = {}
5294 , sign = 1
5295 , stringparts // undef. will be [] in string mode
5296
5297 , activeobject = output
5298 , parentchain = []
5299 , parent_key_pair
5300 , keyparts = ''
5301 , valueparts = ''
5302 , key // undef. will be Truthy when Key is resolved.
5303 , datalen = data.length - 1 // stripping ending }
5304 , ch
5305
5306 i = 1 // stripping starting {
5307
5308 while (i != datalen){
5309 // - { } ' are special.
5310
5311 ch = data[i]
5312 i += 1
5313
5314 if (ch == "'"){
5315 if (stringparts){
5316 // end of string mode
5317 key = stringparts.join('')
5318 stringparts = undef
5319 } else {
5320 // start of string mode
5321 stringparts = []
5322 }
5323 } else if (stringparts){
5324 stringparts.push(ch)
5325 } else if (ch == '{'){
5326 // start of object
5327 parentchain.push( [activeobject, key] )
5328 activeobject = {}
5329 key = undef
5330 } else if (ch == '}'){
5331 // end of object
5332 parent_key_pair = parentchain.pop()
5333 parent_key_pair[0][parent_key_pair[1]] = activeobject
5334 key = undef
5335 activeobject = parent_key_pair[0]
5336 } else if (ch == '-'){
5337 sign = -1
5338 } else {
5339 // must be number
5340 if (key === undef) {
5341 if (mapping.hasOwnProperty(ch)){
5342 keyparts += mapping[ch]
5343 key = parseInt(keyparts, 16) * sign
5344 sign = +1
5345 keyparts = ''
5346 } else {
5347 keyparts += ch
5348 }
5349 } else {
5350 if (mapping.hasOwnProperty(ch)){
5351 valueparts += mapping[ch]
5352 activeobject[key] = parseInt(valueparts, 16) * sign
5353 sign = +1
5354 key = undef
5355 valueparts = ''
5356 } else {
5357 valueparts += ch
5358 }
5359 }
5360 }
5361 } // end while
5362
5363 return output
5364}
5365
5366// encoding = 'Unicode'
5367// NOT UTF8, NOT UTF16BE/LE, NOT UCS2BE/LE. NO clever BOM behavior
5368// Actual 16bit char codes used.
5369// no multi-byte logic here
5370
5371// Unicode characters to WinAnsiEncoding:
5372// {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}
5373// as you can see, all Unicode chars are outside of 0-255 range. No char code conflicts.
5374// this means that you can give Win cp1252 encoded strings to jsPDF for rendering directly
5375// as well as give strings with some (supported by these fonts) Unicode characters and
5376// these will be mapped to win cp1252
5377// for example, you can send char code (cp1252) 0x80 or (unicode) 0x20AC, getting "Euro" glyph displayed in both cases.
5378
5379var encodingBlock = {
5380 'codePages': ['WinAnsiEncoding']
5381 , 'WinAnsiEncoding': uncompress("{19m8n201n9q201o9r201s9l201t9m201u8m201w9n201x9o201y8o202k8q202l8r202m9p202q8p20aw8k203k8t203t8v203u9v2cq8s212m9t15m8w15n9w2dw9s16k8u16l9u17s9z17x8y17y9y}")
5382}
5383, encodings = {'Unicode':{
5384 'Courier': encodingBlock
5385 , 'Courier-Bold': encodingBlock
5386 , 'Courier-BoldOblique': encodingBlock
5387 , 'Courier-Oblique': encodingBlock
5388 , 'Helvetica': encodingBlock
5389 , 'Helvetica-Bold': encodingBlock
5390 , 'Helvetica-BoldOblique': encodingBlock
5391 , 'Helvetica-Oblique': encodingBlock
5392 , 'Times-Roman': encodingBlock
5393 , 'Times-Bold': encodingBlock
5394 , 'Times-BoldItalic': encodingBlock
5395 , 'Times-Italic': encodingBlock
5396// , 'Symbol'
5397// , 'ZapfDingbats'
5398}}
5399/**
5400Resources:
5401Font metrics data is reprocessed derivative of contents of
5402"Font Metrics for PDF Core 14 Fonts" package, which exhibits the following copyright and license:
5403
5404Copyright (c) 1989, 1990, 1991, 1992, 1993, 1997 Adobe Systems Incorporated. All Rights Reserved.
5405
5406This file and the 14 PostScript(R) AFM files it accompanies may be used,
5407copied, and distributed for any purpose and without charge, with or without
5408modification, provided that all copyright notices are retained; that the AFM
5409files are not distributed without this file; that all modifications to this
5410file or any of the AFM files are prominently noted in the modified file(s);
5411and that this paragraph is not modified. Adobe Systems has no responsibility
5412or obligation to support the use of the AFM files.
5413
5414*/
5415, fontMetrics = {'Unicode':{
5416 // all sizing numbers are n/fontMetricsFractionOf = one font size unit
5417 // this means that if fontMetricsFractionOf = 1000, and letter A's width is 476, it's
5418 // width is 476/1000 or 47.6% of its height (regardless of font size)
5419 // At this time this value applies to "widths" and "kerning" numbers.
5420
5421 // char code 0 represents "default" (average) width - use it for chars missing in this table.
5422 // key 'fof' represents the "fontMetricsFractionOf" value
5423
5424 'Courier-Oblique': uncompress("{'widths'{k3w'fof'6o}'kerning'{'fof'-6o}}")
5425 , '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}}}")
5426 , '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}}}")
5427 , 'Courier': uncompress("{'widths'{k3w'fof'6o}'kerning'{'fof'-6o}}")
5428 , 'Courier-BoldOblique': uncompress("{'widths'{k3w'fof'6o}'kerning'{'fof'-6o}}")
5429 , '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}}}")
5430 //, 'Symbol': uncompress("{'widths'{k3uaw4r19m3m2k1t2l2l202m2y2n3m2p5n202q6o3k3m2s2l2t2l2v3r2w1t3m3m2y1t2z1wbk2sbl3r'fof'6o3n3m3o3m3p3m3q3m3r3m3s3m3t3m3u1w3v1w3w3r3x3r3y3r3z2wbp3t3l3m5v2l5x2l5z3m2q4yfr3r7v3k7w1o7x3k}'kerning'{'fof'-6o}}")
5431 , '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}}}")
5432 , '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}}}")
5433 //, 'ZapfDingbats': uncompress("{'widths'{k4u2k1w'fof'6o}'kerning'{'fof'-6o}}")
5434 , 'Courier-Bold': uncompress("{'widths'{k3w'fof'6o}'kerning'{'fof'-6o}}")
5435 , '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}}}")
5436 , '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}}}")
5437 , '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}}}")
5438}};
5439
5440/*
5441This event handler is fired when a new jsPDF object is initialized
5442This event handler appends metrics data to standard fonts within
5443that jsPDF instance. The metrics are mapped over Unicode character
5444codes, NOT CIDs or other codes matching the StandardEncoding table of the
5445standard PDF fonts.
5446Future:
5447Also included is the encoding maping table, converting Unicode (UCS-2, UTF-16)
5448char codes to StandardEncoding character codes. The encoding table is to be used
5449somewhere around "pdfEscape" call.
5450*/
5451
5452API.events.push([
5453 'addFonts'
5454 ,function(fontManagementObjects) {
5455 // fontManagementObjects is {
5456 // 'fonts':font_ID-keyed hash of font objects
5457 // , 'dictionary': lookup object, linking ["FontFamily"]['Style'] to font ID
5458 //}
5459 var font
5460 , fontID
5461 , metrics
5462 , unicode_section
5463 , encoding = 'Unicode'
5464 , encodingBlock
5465
5466 for (fontID in fontManagementObjects.fonts){
5467 if (fontManagementObjects.fonts.hasOwnProperty(fontID)) {
5468 font = fontManagementObjects.fonts[fontID]
5469
5470 // // we only ship 'Unicode' mappings and metrics. No need for loop.
5471 // // still, leaving this for the future.
5472
5473 // for (encoding in fontMetrics){
5474 // if (fontMetrics.hasOwnProperty(encoding)) {
5475
5476 metrics = fontMetrics[encoding][font.PostScriptName]
5477 if (metrics) {
5478 if (font.metadata[encoding]) {
5479 unicode_section = font.metadata[encoding]
5480 } else {
5481 unicode_section = font.metadata[encoding] = {}
5482 }
5483
5484 unicode_section.widths = metrics.widths
5485 unicode_section.kerning = metrics.kerning
5486 }
5487 // }
5488 // }
5489 // for (encoding in encodings){
5490 // if (encodings.hasOwnProperty(encoding)) {
5491 encodingBlock = encodings[encoding][font.PostScriptName]
5492 if (encodingBlock) {
5493 if (font.metadata[encoding]) {
5494 unicode_section = font.metadata[encoding]
5495 } else {
5496 unicode_section = font.metadata[encoding] = {}
5497 }
5498
5499 unicode_section.encoding = encodingBlock
5500 if (encodingBlock.codePages && encodingBlock.codePages.length) {
5501 font.encoding = encodingBlock.codePages[0]
5502 }
5503 }
5504 // }
5505 // }
5506 }
5507 }
5508 }
5509]) // end of adding event handler
5510
5511})(jsPDF.API);
5512/** ====================================================================
5513 * jsPDF total_pages plugin
5514 * Copyright (c) 2013 Eduardo Menezes de Morais, eduardo.morais@usp.br
5515 *
5516 * Permission is hereby granted, free of charge, to any person obtaining
5517 * a copy of this software and associated documentation files (the
5518 * "Software"), to deal in the Software without restriction, including
5519 * without limitation the rights to use, copy, modify, merge, publish,
5520 * distribute, sublicense, and/or sell copies of the Software, and to
5521 * permit persons to whom the Software is furnished to do so, subject to
5522 * the following conditions:
5523 *
5524 * The above copyright notice and this permission notice shall be
5525 * included in all copies or substantial portions of the Software.
5526 *
5527 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
5528 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
5529 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
5530 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
5531 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
5532 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
5533 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
5534 * ====================================================================
5535 */
5536
5537(function(jsPDFAPI) {
5538'use strict';
5539
5540jsPDFAPI.putTotalPages = function(pageExpression) {
5541 'use strict';
5542 var replaceExpression = new RegExp(pageExpression, 'g');
5543 for (var n = 1; n <= this.internal.getNumberOfPages(); n++) {
5544 for (var i = 0; i < this.internal.pages[n].length; i++)
5545 this.internal.pages[n][i] = this.internal.pages[n][i].replace(replaceExpression, this.internal.getNumberOfPages());
5546 }
5547 return this;
5548};
5549
5550})(jsPDF.API);
5551/* Blob.js
5552 * A Blob implementation.
5553 * 2014-07-24
5554 *
5555 * By Eli Grey, http://eligrey.com
5556 * By Devin Samarin, https://github.com/dsamarin
5557 * License: X11/MIT
5558 * See https://github.com/eligrey/Blob.js/blob/master/LICENSE.md
5559 */
5560
5561/*global self, unescape */
5562/*jslint bitwise: true, regexp: true, confusion: true, es5: true, vars: true, white: true,
5563 plusplus: true */
5564
5565/*! @source http://purl.eligrey.com/github/Blob.js/blob/master/Blob.js */
5566
5567(function (view) {
5568 "use strict";
5569
5570 view.URL = view.URL || view.webkitURL;
5571
5572 if (view.Blob && view.URL) {
5573 try {
5574 new Blob;
5575 return;
5576 } catch (e) {}
5577 }
5578
5579 // Internally we use a BlobBuilder implementation to base Blob off of
5580 // in order to support older browsers that only have BlobBuilder
5581 var BlobBuilder = view.BlobBuilder || view.WebKitBlobBuilder || view.MozBlobBuilder || (function(view) {
5582 var
5583 get_class = function(object) {
5584 return Object.prototype.toString.call(object).match(/^\[object\s(.*)\]$/)[1];
5585 }
5586 , FakeBlobBuilder = function BlobBuilder() {
5587 this.data = [];
5588 }
5589 , FakeBlob = function Blob(data, type, encoding) {
5590 this.data = data;
5591 this.size = data.length;
5592 this.type = type;
5593 this.encoding = encoding;
5594 }
5595 , FBB_proto = FakeBlobBuilder.prototype
5596 , FB_proto = FakeBlob.prototype
5597 , FileReaderSync = view.FileReaderSync
5598 , FileException = function(type) {
5599 this.code = this[this.name = type];
5600 }
5601 , file_ex_codes = (
5602 "NOT_FOUND_ERR SECURITY_ERR ABORT_ERR NOT_READABLE_ERR ENCODING_ERR "
5603 + "NO_MODIFICATION_ALLOWED_ERR INVALID_STATE_ERR SYNTAX_ERR"
5604 ).split(" ")
5605 , file_ex_code = file_ex_codes.length
5606 , real_URL = view.URL || view.webkitURL || view
5607 , real_create_object_URL = real_URL.createObjectURL
5608 , real_revoke_object_URL = real_URL.revokeObjectURL
5609 , URL = real_URL
5610 , btoa = view.btoa
5611 , atob = view.atob
5612
5613 , ArrayBuffer = view.ArrayBuffer
5614 , Uint8Array = view.Uint8Array
5615
5616 , origin = /^[\w-]+:\/*\[?[\w\.:-]+\]?(?::[0-9]+)?/
5617 ;
5618 FakeBlob.fake = FB_proto.fake = true;
5619 while (file_ex_code--) {
5620 FileException.prototype[file_ex_codes[file_ex_code]] = file_ex_code + 1;
5621 }
5622 // Polyfill URL
5623 if (!real_URL.createObjectURL) {
5624 URL = view.URL = function(uri) {
5625 var
5626 uri_info = document.createElementNS("http://www.w3.org/1999/xhtml", "a")
5627 , uri_origin
5628 ;
5629 uri_info.href = uri;
5630 if (!("origin" in uri_info)) {
5631 if (uri_info.protocol.toLowerCase() === "data:") {
5632 uri_info.origin = null;
5633 } else {
5634 uri_origin = uri.match(origin);
5635 uri_info.origin = uri_origin && uri_origin[1];
5636 }
5637 }
5638 return uri_info;
5639 };
5640 }
5641 URL.createObjectURL = function(blob) {
5642 var
5643 type = blob.type
5644 , data_URI_header
5645 ;
5646 if (type === null) {
5647 type = "application/octet-stream";
5648 }
5649 if (blob instanceof FakeBlob) {
5650 data_URI_header = "data:" + type;
5651 if (blob.encoding === "base64") {
5652 return data_URI_header + ";base64," + blob.data;
5653 } else if (blob.encoding === "URI") {
5654 return data_URI_header + "," + decodeURIComponent(blob.data);
5655 } if (btoa) {
5656 return data_URI_header + ";base64," + btoa(blob.data);
5657 } else {
5658 return data_URI_header + "," + encodeURIComponent(blob.data);
5659 }
5660 } else if (real_create_object_URL) {
5661 return real_create_object_URL.call(real_URL, blob);
5662 }
5663 };
5664 URL.revokeObjectURL = function(object_URL) {
5665 if (object_URL.substring(0, 5) !== "data:" && real_revoke_object_URL) {
5666 real_revoke_object_URL.call(real_URL, object_URL);
5667 }
5668 };
5669 FBB_proto.append = function(data/*, endings*/) {
5670 var bb = this.data;
5671 // decode data to a binary string
5672 if (Uint8Array && (data instanceof ArrayBuffer || data instanceof Uint8Array)) {
5673 var
5674 str = ""
5675 , buf = new Uint8Array(data)
5676 , i = 0
5677 , buf_len = buf.length
5678 ;
5679 for (; i < buf_len; i++) {
5680 str += String.fromCharCode(buf[i]);
5681 }
5682 bb.push(str);
5683 } else if (get_class(data) === "Blob" || get_class(data) === "File") {
5684 if (FileReaderSync) {
5685 var fr = new FileReaderSync;
5686 bb.push(fr.readAsBinaryString(data));
5687 } else {
5688 // async FileReader won't work as BlobBuilder is sync
5689 throw new FileException("NOT_READABLE_ERR");
5690 }
5691 } else if (data instanceof FakeBlob) {
5692 if (data.encoding === "base64" && atob) {
5693 bb.push(atob(data.data));
5694 } else if (data.encoding === "URI") {
5695 bb.push(decodeURIComponent(data.data));
5696 } else if (data.encoding === "raw") {
5697 bb.push(data.data);
5698 }
5699 } else {
5700 if (typeof data !== "string") {
5701 data += ""; // convert unsupported types to strings
5702 }
5703 // decode UTF-16 to binary string
5704 bb.push(unescape(encodeURIComponent(data)));
5705 }
5706 };
5707 FBB_proto.getBlob = function(type) {
5708 if (!arguments.length) {
5709 type = null;
5710 }
5711 return new FakeBlob(this.data.join(""), type, "raw");
5712 };
5713 FBB_proto.toString = function() {
5714 return "[object BlobBuilder]";
5715 };
5716 FB_proto.slice = function(start, end, type) {
5717 var args = arguments.length;
5718 if (args < 3) {
5719 type = null;
5720 }
5721 return new FakeBlob(
5722 this.data.slice(start, args > 1 ? end : this.data.length)
5723 , type
5724 , this.encoding
5725 );
5726 };
5727 FB_proto.toString = function() {
5728 return "[object Blob]";
5729 };
5730 FB_proto.close = function() {
5731 this.size = 0;
5732 delete this.data;
5733 };
5734 return FakeBlobBuilder;
5735 }(view));
5736
5737 view.Blob = function(blobParts, options) {
5738 var type = options ? (options.type || "") : "";
5739 var builder = new BlobBuilder();
5740 if (blobParts) {
5741 for (var i = 0, len = blobParts.length; i < len; i++) {
5742 builder.append(blobParts[i]);
5743 }
5744 }
5745 return builder.getBlob(type);
5746 };
5747}(typeof self !== "undefined" && self || typeof window !== "undefined" && window || this.content || this));
5748/* FileSaver.js
5749 * A saveAs() FileSaver implementation.
5750 * 2014-08-29
5751 *
5752 * By Eli Grey, http://eligrey.com
5753 * License: X11/MIT
5754 * See https://github.com/eligrey/FileSaver.js/blob/master/LICENSE.md
5755 */
5756
5757/*global self */
5758/*jslint bitwise: true, indent: 4, laxbreak: true, laxcomma: true, smarttabs: true, plusplus: true */
5759
5760/*! @source http://purl.eligrey.com/github/FileSaver.js/blob/master/FileSaver.js */
5761
5762var saveAs = saveAs
5763 // IE 10+ (native saveAs)
5764 || (typeof navigator !== "undefined" &&
5765 navigator.msSaveOrOpenBlob && navigator.msSaveOrOpenBlob.bind(navigator))
5766 // Everyone else
5767 || (function(view) {
5768 "use strict";
5769 // IE <10 is explicitly unsupported
5770 if (typeof navigator !== "undefined" &&
5771 /MSIE [1-9]\./.test(navigator.userAgent)) {
5772 return;
5773 }
5774 var
5775 doc = view.document
5776 // only get URL when necessary in case Blob.js hasn't overridden it yet
5777 , get_URL = function() {
5778 return view.URL || view.webkitURL || view;
5779 }
5780 , save_link = doc.createElementNS("http://www.w3.org/1999/xhtml", "a")
5781 , can_use_save_link = "download" in save_link
5782 , click = function(node) {
5783 var event = doc.createEvent("MouseEvents");
5784 event.initMouseEvent(
5785 "click", true, false, view, 0, 0, 0, 0, 0
5786 , false, false, false, false, 0, null
5787 );
5788 node.dispatchEvent(event);
5789 }
5790 , webkit_req_fs = view.webkitRequestFileSystem
5791 , req_fs = view.requestFileSystem || webkit_req_fs || view.mozRequestFileSystem
5792 , throw_outside = function(ex) {
5793 (view.setImmediate || view.setTimeout)(function() {
5794 throw ex;
5795 }, 0);
5796 }
5797 , force_saveable_type = "application/octet-stream"
5798 , fs_min_size = 0
5799 // See https://code.google.com/p/chromium/issues/detail?id=375297#c7 for
5800 // the reasoning behind the timeout and revocation flow
5801 , arbitrary_revoke_timeout = 10
5802 , revoke = function(file) {
5803 var revoker = function() {
5804 if (typeof file === "string") { // file is an object URL
5805 get_URL().revokeObjectURL(file);
5806 } else { // file is a File
5807 file.remove();
5808 }
5809 };
5810 if (view.chrome) {
5811 revoker();
5812 } else {
5813 setTimeout(revoker, arbitrary_revoke_timeout);
5814 }
5815 }
5816 , dispatch = function(filesaver, event_types, event) {
5817 event_types = [].concat(event_types);
5818 var i = event_types.length;
5819 while (i--) {
5820 var listener = filesaver["on" + event_types[i]];
5821 if (typeof listener === "function") {
5822 try {
5823 listener.call(filesaver, event || filesaver);
5824 } catch (ex) {
5825 throw_outside(ex);
5826 }
5827 }
5828 }
5829 }
5830 , FileSaver = function(blob, name) {
5831 // First try a.download, then web filesystem, then object URLs
5832 var
5833 filesaver = this
5834 , type = blob.type
5835 , blob_changed = false
5836 , object_url
5837 , target_view
5838 , dispatch_all = function() {
5839 dispatch(filesaver, "writestart progress write writeend".split(" "));
5840 }
5841 // on any filesys errors revert to saving with object URLs
5842 , fs_error = function() {
5843 // don't create more object URLs than needed
5844 if (blob_changed || !object_url) {
5845 object_url = get_URL().createObjectURL(blob);
5846 }
5847 if (target_view) {
5848 target_view.location.href = object_url;
5849 } else {
5850 var new_tab = view.open(object_url, "_blank");
5851 if (new_tab == undefined && typeof safari !== "undefined") {
5852 //Apple do not allow window.open, see http://bit.ly/1kZffRI
5853 view.location.href = object_url
5854 }
5855 }
5856 filesaver.readyState = filesaver.DONE;
5857 dispatch_all();
5858 revoke(object_url);
5859 }
5860 , abortable = function(func) {
5861 return function() {
5862 if (filesaver.readyState !== filesaver.DONE) {
5863 return func.apply(this, arguments);
5864 }
5865 };
5866 }
5867 , create_if_not_found = {create: true, exclusive: false}
5868 , slice
5869 ;
5870 filesaver.readyState = filesaver.INIT;
5871 if (!name) {
5872 name = "download";
5873 }
5874 if (can_use_save_link) {
5875 object_url = get_URL().createObjectURL(blob);
5876 save_link.href = object_url;
5877 save_link.download = name;
5878 click(save_link);
5879 filesaver.readyState = filesaver.DONE;
5880 dispatch_all();
5881 revoke(object_url);
5882 return;
5883 }
5884 // Object and web filesystem URLs have a problem saving in Google Chrome when
5885 // viewed in a tab, so I force save with application/octet-stream
5886 // http://code.google.com/p/chromium/issues/detail?id=91158
5887 // Update: Google errantly closed 91158, I submitted it again:
5888 // https://code.google.com/p/chromium/issues/detail?id=389642
5889 if (view.chrome && type && type !== force_saveable_type) {
5890 slice = blob.slice || blob.webkitSlice;
5891 blob = slice.call(blob, 0, blob.size, force_saveable_type);
5892 blob_changed = true;
5893 }
5894 // Since I can't be sure that the guessed media type will trigger a download
5895 // in WebKit, I append .download to the filename.
5896 // https://bugs.webkit.org/show_bug.cgi?id=65440
5897 if (webkit_req_fs && name !== "download") {
5898 name += ".download";
5899 }
5900 if (type === force_saveable_type || webkit_req_fs) {
5901 target_view = view;
5902 }
5903 if (!req_fs) {
5904 fs_error();
5905 return;
5906 }
5907 fs_min_size += blob.size;
5908 req_fs(view.TEMPORARY, fs_min_size, abortable(function(fs) {
5909 fs.root.getDirectory("saved", create_if_not_found, abortable(function(dir) {
5910 var save = function() {
5911 dir.getFile(name, create_if_not_found, abortable(function(file) {
5912 file.createWriter(abortable(function(writer) {
5913 writer.onwriteend = function(event) {
5914 target_view.location.href = file.toURL();
5915 filesaver.readyState = filesaver.DONE;
5916 dispatch(filesaver, "writeend", event);
5917 revoke(file);
5918 };
5919 writer.onerror = function() {
5920 var error = writer.error;
5921 if (error.code !== error.ABORT_ERR) {
5922 fs_error();
5923 }
5924 };
5925 "writestart progress write abort".split(" ").forEach(function(event) {
5926 writer["on" + event] = filesaver["on" + event];
5927 });
5928 writer.write(blob);
5929 filesaver.abort = function() {
5930 writer.abort();
5931 filesaver.readyState = filesaver.DONE;
5932 };
5933 filesaver.readyState = filesaver.WRITING;
5934 }), fs_error);
5935 }), fs_error);
5936 };
5937 dir.getFile(name, {create: false}, abortable(function(file) {
5938 // delete file if it already exists
5939 file.remove();
5940 save();
5941 }), abortable(function(ex) {
5942 if (ex.code === ex.NOT_FOUND_ERR) {
5943 save();
5944 } else {
5945 fs_error();
5946 }
5947 }));
5948 }), fs_error);
5949 }), fs_error);
5950 }
5951 , FS_proto = FileSaver.prototype
5952 , saveAs = function(blob, name) {
5953 return new FileSaver(blob, name);
5954 }
5955 ;
5956 FS_proto.abort = function() {
5957 var filesaver = this;
5958 filesaver.readyState = filesaver.DONE;
5959 dispatch(filesaver, "abort");
5960 };
5961 FS_proto.readyState = FS_proto.INIT = 0;
5962 FS_proto.WRITING = 1;
5963 FS_proto.DONE = 2;
5964
5965 FS_proto.error =
5966 FS_proto.onwritestart =
5967 FS_proto.onprogress =
5968 FS_proto.onwrite =
5969 FS_proto.onabort =
5970 FS_proto.onerror =
5971 FS_proto.onwriteend =
5972 null;
5973
5974 return saveAs;
5975}(
5976 typeof self !== "undefined" && self
5977 || typeof window !== "undefined" && window
5978 || this.content
5979));
5980// `self` is undefined in Firefox for Android content script context
5981// while `this` is nsIContentFrameMessageManager
5982// with an attribute `content` that corresponds to the window
5983
5984if (typeof module !== "undefined" && module !== null) {
5985 module.exports = saveAs;
5986} else if ((typeof define !== "undefined" && 0)) {
5987 define([], function() {
5988 return saveAs;
5989 });
5990}
5991/*
5992 * Copyright (c) 2012 chick307 <chick307@gmail.com>
5993 *
5994 * Licensed under the MIT License.
5995 * http://opensource.org/licenses/mit-license
5996 */
5997
5998void function(global, callback) {
5999 if (typeof module === 'object') {
6000 module.exports = callback();
6001 } else if (0 === 'function') {
6002 define(callback);
6003 } else {
6004 global.adler32cs = callback();
6005 }
6006}(jsPDF, function() {
6007 var _hasArrayBuffer = typeof ArrayBuffer === 'function' &&
6008 typeof Uint8Array === 'function';
6009
6010 var _Buffer = null, _isBuffer = (function() {
6011 if (!_hasArrayBuffer)
6012 return function _isBuffer() { return false };
6013
6014 try {
6015 var buffer = require('buffer');
6016 if (typeof buffer.Buffer === 'function')
6017 _Buffer = buffer.Buffer;
6018 } catch (error) {}
6019
6020 return function _isBuffer(value) {
6021 return value instanceof ArrayBuffer ||
6022 _Buffer !== null && value instanceof _Buffer;
6023 };
6024 }());
6025
6026 var _utf8ToBinary = (function() {
6027 if (_Buffer !== null) {
6028 return function _utf8ToBinary(utf8String) {
6029 return new _Buffer(utf8String, 'utf8').toString('binary');
6030 };
6031 } else {
6032 return function _utf8ToBinary(utf8String) {
6033 return unescape(encodeURIComponent(utf8String));
6034 };
6035 }
6036 }());
6037
6038 var MOD = 65521;
6039
6040 var _update = function _update(checksum, binaryString) {
6041 var a = checksum & 0xFFFF, b = checksum >>> 16;
6042 for (var i = 0, length = binaryString.length; i < length; i++) {
6043 a = (a + (binaryString.charCodeAt(i) & 0xFF)) % MOD;
6044 b = (b + a) % MOD;
6045 }
6046 return (b << 16 | a) >>> 0;
6047 };
6048
6049 var _updateUint8Array = function _updateUint8Array(checksum, uint8Array) {
6050 var a = checksum & 0xFFFF, b = checksum >>> 16;
6051 for (var i = 0, length = uint8Array.length, x; i < length; i++) {
6052 a = (a + uint8Array[i]) % MOD;
6053 b = (b + a) % MOD;
6054 }
6055 return (b << 16 | a) >>> 0
6056 };
6057
6058 var exports = {};
6059
6060 var Adler32 = exports.Adler32 = (function() {
6061 var ctor = function Adler32(checksum) {
6062 if (!(this instanceof ctor)) {
6063 throw new TypeError(
6064 'Constructor cannot called be as a function.');
6065 }
6066 if (!isFinite(checksum = checksum == null ? 1 : +checksum)) {
6067 throw new Error(
6068 'First arguments needs to be a finite number.');
6069 }
6070 this.checksum = checksum >>> 0;
6071 };
6072
6073 var proto = ctor.prototype = {};
6074 proto.constructor = ctor;
6075
6076 ctor.from = function(from) {
6077 from.prototype = proto;
6078 return from;
6079 }(function from(binaryString) {
6080 if (!(this instanceof ctor)) {
6081 throw new TypeError(
6082 'Constructor cannot called be as a function.');
6083 }
6084 if (binaryString == null)
6085 throw new Error('First argument needs to be a string.');
6086 this.checksum = _update(1, binaryString.toString());
6087 });
6088
6089 ctor.fromUtf8 = function(fromUtf8) {
6090 fromUtf8.prototype = proto;
6091 return fromUtf8;
6092 }(function fromUtf8(utf8String) {
6093 if (!(this instanceof ctor)) {
6094 throw new TypeError(
6095 'Constructor cannot called be as a function.');
6096 }
6097 if (utf8String == null)
6098 throw new Error('First argument needs to be a string.');
6099 var binaryString = _utf8ToBinary(utf8String.toString());
6100 this.checksum = _update(1, binaryString);
6101 });
6102
6103 if (_hasArrayBuffer) {
6104 ctor.fromBuffer = function(fromBuffer) {
6105 fromBuffer.prototype = proto;
6106 return fromBuffer;
6107 }(function fromBuffer(buffer) {
6108 if (!(this instanceof ctor)) {
6109 throw new TypeError(
6110 'Constructor cannot called be as a function.');
6111 }
6112 if (!_isBuffer(buffer))
6113 throw new Error('First argument needs to be ArrayBuffer.');
6114 var array = new Uint8Array(buffer);
6115 return this.checksum = _updateUint8Array(1, array);
6116 });
6117 }
6118
6119 proto.update = function update(binaryString) {
6120 if (binaryString == null)
6121 throw new Error('First argument needs to be a string.');
6122 binaryString = binaryString.toString();
6123 return this.checksum = _update(this.checksum, binaryString);
6124 };
6125
6126 proto.updateUtf8 = function updateUtf8(utf8String) {
6127 if (utf8String == null)
6128 throw new Error('First argument needs to be a string.');
6129 var binaryString = _utf8ToBinary(utf8String.toString());
6130 return this.checksum = _update(this.checksum, binaryString);
6131 };
6132
6133 if (_hasArrayBuffer) {
6134 proto.updateBuffer = function updateBuffer(buffer) {
6135 if (!_isBuffer(buffer))
6136 throw new Error('First argument needs to be ArrayBuffer.');
6137 var array = new Uint8Array(buffer);
6138 return this.checksum = _updateUint8Array(this.checksum, array);
6139 };
6140 }
6141
6142 proto.clone = function clone() {
6143 return new Adler32(this.checksum);
6144 };
6145
6146 return ctor;
6147 }());
6148
6149 exports.from = function from(binaryString) {
6150 if (binaryString == null)
6151 throw new Error('First argument needs to be a string.');
6152 return _update(1, binaryString.toString());
6153 };
6154
6155 exports.fromUtf8 = function fromUtf8(utf8String) {
6156 if (utf8String == null)
6157 throw new Error('First argument needs to be a string.');
6158 var binaryString = _utf8ToBinary(utf8String.toString());
6159 return _update(1, binaryString);
6160 };
6161
6162 if (_hasArrayBuffer) {
6163 exports.fromBuffer = function fromBuffer(buffer) {
6164 if (!_isBuffer(buffer))
6165 throw new Error('First argument need to be ArrayBuffer.');
6166 var array = new Uint8Array(buffer);
6167 return _updateUint8Array(1, array);
6168 };
6169 }
6170
6171 return exports;
6172});
6173/*
6174 Deflate.js - https://github.com/gildas-lormeau/zip.js
6175 Copyright (c) 2013 Gildas Lormeau. All rights reserved.
6176
6177 Redistribution and use in source and binary forms, with or without
6178 modification, are permitted provided that the following conditions are met:
6179
6180 1. Redistributions of source code must retain the above copyright notice,
6181 this list of conditions and the following disclaimer.
6182
6183 2. Redistributions in binary form must reproduce the above copyright
6184 notice, this list of conditions and the following disclaimer in
6185 the documentation and/or other materials provided with the distribution.
6186
6187 3. The names of the authors may not be used to endorse or promote products
6188 derived from this software without specific prior written permission.
6189
6190 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
6191 INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
6192 FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
6193 INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
6194 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
6195 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
6196 OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
6197 LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
6198 NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
6199 EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
6200 */
6201
6202/*
6203 * This program is based on JZlib 1.0.2 ymnk, JCraft,Inc.
6204 * JZlib is based on zlib-1.1.3, so all credit should go authors
6205 * Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu)
6206 * and contributors of zlib.
6207 */
6208
6209var Deflater = (function(obj) {
6210
6211 // Global
6212
6213 var MAX_BITS = 15;
6214 var D_CODES = 30;
6215 var BL_CODES = 19;
6216
6217 var LENGTH_CODES = 29;
6218 var LITERALS = 256;
6219 var L_CODES = (LITERALS + 1 + LENGTH_CODES);
6220 var HEAP_SIZE = (2 * L_CODES + 1);
6221
6222 var END_BLOCK = 256;
6223
6224 // Bit length codes must not exceed MAX_BL_BITS bits
6225 var MAX_BL_BITS = 7;
6226
6227 // repeat previous bit length 3-6 times (2 bits of repeat count)
6228 var REP_3_6 = 16;
6229
6230 // repeat a zero length 3-10 times (3 bits of repeat count)
6231 var REPZ_3_10 = 17;
6232
6233 // repeat a zero length 11-138 times (7 bits of repeat count)
6234 var REPZ_11_138 = 18;
6235
6236 // The lengths of the bit length codes are sent in order of decreasing
6237 // probability, to avoid transmitting the lengths for unused bit
6238 // length codes.
6239
6240 var Buf_size = 8 * 2;
6241
6242 // JZlib version : "1.0.2"
6243 var Z_DEFAULT_COMPRESSION = -1;
6244
6245 // compression strategy
6246 var Z_FILTERED = 1;
6247 var Z_HUFFMAN_ONLY = 2;
6248 var Z_DEFAULT_STRATEGY = 0;
6249
6250 var Z_NO_FLUSH = 0;
6251 var Z_PARTIAL_FLUSH = 1;
6252 var Z_FULL_FLUSH = 3;
6253 var Z_FINISH = 4;
6254
6255 var Z_OK = 0;
6256 var Z_STREAM_END = 1;
6257 var Z_NEED_DICT = 2;
6258 var Z_STREAM_ERROR = -2;
6259 var Z_DATA_ERROR = -3;
6260 var Z_BUF_ERROR = -5;
6261
6262 // Tree
6263
6264 // see definition of array dist_code below
6265 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,
6266 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,
6267 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,
6268 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,
6269 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,
6270 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,
6271 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,
6272 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,
6273 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,
6274 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,
6275 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,
6276 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,
6277 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,
6278 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 ];
6279
6280 function Tree() {
6281 var that = this;
6282
6283 // dyn_tree; // the dynamic tree
6284 // max_code; // largest code with non zero frequency
6285 // stat_desc; // the corresponding static tree
6286
6287 // Compute the optimal bit lengths for a tree and update the total bit
6288 // length
6289 // for the current block.
6290 // IN assertion: the fields freq and dad are set, heap[heap_max] and
6291 // above are the tree nodes sorted by increasing frequency.
6292 // OUT assertions: the field len is set to the optimal bit length, the
6293 // array bl_count contains the frequencies for each bit length.
6294 // The length opt_len is updated; static_len is also updated if stree is
6295 // not null.
6296 function gen_bitlen(s) {
6297 var tree = that.dyn_tree;
6298 var stree = that.stat_desc.static_tree;
6299 var extra = that.stat_desc.extra_bits;
6300 var base = that.stat_desc.extra_base;
6301 var max_length = that.stat_desc.max_length;
6302 var h; // heap index
6303 var n, m; // iterate over the tree elements
6304 var bits; // bit length
6305 var xbits; // extra bits
6306 var f; // frequency
6307 var overflow = 0; // number of elements with bit length too large
6308
6309 for (bits = 0; bits <= MAX_BITS; bits++)
6310 s.bl_count[bits] = 0;
6311
6312 // In a first pass, compute the optimal bit lengths (which may
6313 // overflow in the case of the bit length tree).
6314 tree[s.heap[s.heap_max] * 2 + 1] = 0; // root of the heap
6315
6316 for (h = s.heap_max + 1; h < HEAP_SIZE; h++) {
6317 n = s.heap[h];
6318 bits = tree[tree[n * 2 + 1] * 2 + 1] + 1;
6319 if (bits > max_length) {
6320 bits = max_length;
6321 overflow++;
6322 }
6323 tree[n * 2 + 1] = bits;
6324 // We overwrite tree[n*2+1] which is no longer needed
6325
6326 if (n > that.max_code)
6327 continue; // not a leaf node
6328
6329 s.bl_count[bits]++;
6330 xbits = 0;
6331 if (n >= base)
6332 xbits = extra[n - base];
6333 f = tree[n * 2];
6334 s.opt_len += f * (bits + xbits);
6335 if (stree)
6336 s.static_len += f * (stree[n * 2 + 1] + xbits);
6337 }
6338 if (overflow === 0)
6339 return;
6340
6341 // This happens for example on obj2 and pic of the Calgary corpus
6342 // Find the first bit length which could increase:
6343 do {
6344 bits = max_length - 1;
6345 while (s.bl_count[bits] === 0)
6346 bits--;
6347 s.bl_count[bits]--; // move one leaf down the tree
6348 s.bl_count[bits + 1] += 2; // move one overflow item as its brother
6349 s.bl_count[max_length]--;
6350 // The brother of the overflow item also moves one step up,
6351 // but this does not affect bl_count[max_length]
6352 overflow -= 2;
6353 } while (overflow > 0);
6354
6355 for (bits = max_length; bits !== 0; bits--) {
6356 n = s.bl_count[bits];
6357 while (n !== 0) {
6358 m = s.heap[--h];
6359 if (m > that.max_code)
6360 continue;
6361 if (tree[m * 2 + 1] != bits) {
6362 s.opt_len += (bits - tree[m * 2 + 1]) * tree[m * 2];
6363 tree[m * 2 + 1] = bits;
6364 }
6365 n--;
6366 }
6367 }
6368 }
6369
6370 // Reverse the first len bits of a code, using straightforward code (a
6371 // faster
6372 // method would use a table)
6373 // IN assertion: 1 <= len <= 15
6374 function bi_reverse(code, // the value to invert
6375 len // its bit length
6376 ) {
6377 var res = 0;
6378 do {
6379 res |= code & 1;
6380 code >>>= 1;
6381 res <<= 1;
6382 } while (--len > 0);
6383 return res >>> 1;
6384 }
6385
6386 // Generate the codes for a given tree and bit counts (which need not be
6387 // optimal).
6388 // IN assertion: the array bl_count contains the bit length statistics for
6389 // the given tree and the field len is set for all tree elements.
6390 // OUT assertion: the field code is set for all tree elements of non
6391 // zero code length.
6392 function gen_codes(tree, // the tree to decorate
6393 max_code, // largest code with non zero frequency
6394 bl_count // number of codes at each bit length
6395 ) {
6396 var next_code = []; // next code value for each
6397 // bit length
6398 var code = 0; // running code value
6399 var bits; // bit index
6400 var n; // code index
6401 var len;
6402
6403 // The distribution counts are first used to generate the code values
6404 // without bit reversal.
6405 for (bits = 1; bits <= MAX_BITS; bits++) {
6406 next_code[bits] = code = ((code + bl_count[bits - 1]) << 1);
6407 }
6408
6409 // Check that the bit counts in bl_count are consistent. The last code
6410 // must be all ones.
6411 // Assert (code + bl_count[MAX_BITS]-1 == (1<<MAX_BITS)-1,
6412 // "inconsistent bit counts");
6413 // Tracev((stderr,"\ngen_codes: max_code %d ", max_code));
6414
6415 for (n = 0; n <= max_code; n++) {
6416 len = tree[n * 2 + 1];
6417 if (len === 0)
6418 continue;
6419 // Now reverse the bits
6420 tree[n * 2] = bi_reverse(next_code[len]++, len);
6421 }
6422 }
6423
6424 // Construct one Huffman tree and assigns the code bit strings and lengths.
6425 // Update the total bit length for the current block.
6426 // IN assertion: the field freq is set for all tree elements.
6427 // OUT assertions: the fields len and code are set to the optimal bit length
6428 // and corresponding code. The length opt_len is updated; static_len is
6429 // also updated if stree is not null. The field max_code is set.
6430 that.build_tree = function(s) {
6431 var tree = that.dyn_tree;
6432 var stree = that.stat_desc.static_tree;
6433 var elems = that.stat_desc.elems;
6434 var n, m; // iterate over heap elements
6435 var max_code = -1; // largest code with non zero frequency
6436 var node; // new node being created
6437
6438 // Construct the initial heap, with least frequent element in
6439 // heap[1]. The sons of heap[n] are heap[2*n] and heap[2*n+1].
6440 // heap[0] is not used.
6441 s.heap_len = 0;
6442 s.heap_max = HEAP_SIZE;
6443
6444 for (n = 0; n < elems; n++) {
6445 if (tree[n * 2] !== 0) {
6446 s.heap[++s.heap_len] = max_code = n;
6447 s.depth[n] = 0;
6448 } else {
6449 tree[n * 2 + 1] = 0;
6450 }
6451 }
6452
6453 // The pkzip format requires that at least one distance code exists,
6454 // and that at least one bit should be sent even if there is only one
6455 // possible code. So to avoid special checks later on we force at least
6456 // two codes of non zero frequency.
6457 while (s.heap_len < 2) {
6458 node = s.heap[++s.heap_len] = max_code < 2 ? ++max_code : 0;
6459 tree[node * 2] = 1;
6460 s.depth[node] = 0;
6461 s.opt_len--;
6462 if (stree)
6463 s.static_len -= stree[node * 2 + 1];
6464 // node is 0 or 1 so it does not have extra bits
6465 }
6466 that.max_code = max_code;
6467
6468 // The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree,
6469 // establish sub-heaps of increasing lengths:
6470
6471 for (n = Math.floor(s.heap_len / 2); n >= 1; n--)
6472 s.pqdownheap(tree, n);
6473
6474 // Construct the Huffman tree by repeatedly combining the least two
6475 // frequent nodes.
6476
6477 node = elems; // next internal node of the tree
6478 do {
6479 // n = node of least frequency
6480 n = s.heap[1];
6481 s.heap[1] = s.heap[s.heap_len--];
6482 s.pqdownheap(tree, 1);
6483 m = s.heap[1]; // m = node of next least frequency
6484
6485 s.heap[--s.heap_max] = n; // keep the nodes sorted by frequency
6486 s.heap[--s.heap_max] = m;
6487
6488 // Create a new node father of n and m
6489 tree[node * 2] = (tree[n * 2] + tree[m * 2]);
6490 s.depth[node] = Math.max(s.depth[n], s.depth[m]) + 1;
6491 tree[n * 2 + 1] = tree[m * 2 + 1] = node;
6492
6493 // and insert the new node in the heap
6494 s.heap[1] = node++;
6495 s.pqdownheap(tree, 1);
6496 } while (s.heap_len >= 2);
6497
6498 s.heap[--s.heap_max] = s.heap[1];
6499
6500 // At this point, the fields freq and dad are set. We can now
6501 // generate the bit lengths.
6502
6503 gen_bitlen(s);
6504
6505 // The field len is now set, we can generate the bit codes
6506 gen_codes(tree, that.max_code, s.bl_count);
6507 };
6508
6509 }
6510
6511 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,
6512 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,
6513 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,
6514 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,
6515 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,
6516 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,
6517 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 ];
6518
6519 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 ];
6520
6521 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,
6522 24576 ];
6523
6524 // Mapping from a distance to a distance code. dist is the distance - 1 and
6525 // must not have side effects. _dist_code[256] and _dist_code[257] are never
6526 // used.
6527 Tree.d_code = function(dist) {
6528 return ((dist) < 256 ? _dist_code[dist] : _dist_code[256 + ((dist) >>> 7)]);
6529 };
6530
6531 // extra bits for each length code
6532 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 ];
6533
6534 // extra bits for each distance code
6535 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 ];
6536
6537 // extra bits for each bit length code
6538 Tree.extra_blbits = [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 3, 7 ];
6539
6540 Tree.bl_order = [ 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 ];
6541
6542 // StaticTree
6543
6544 function StaticTree(static_tree, extra_bits, extra_base, elems, max_length) {
6545 var that = this;
6546 that.static_tree = static_tree;
6547 that.extra_bits = extra_bits;
6548 that.extra_base = extra_base;
6549 that.elems = elems;
6550 that.max_length = max_length;
6551 }
6552
6553 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,
6554 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,
6555 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,
6556 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,
6557 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,
6558 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,
6559 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,
6560 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,
6561 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,
6562 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,
6563 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,
6564 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,
6565 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,
6566 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,
6567 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,
6568 99, 8, 227, 8 ];
6569
6570 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,
6571 25, 5, 5, 5, 21, 5, 13, 5, 29, 5, 3, 5, 19, 5, 11, 5, 27, 5, 7, 5, 23, 5 ];
6572
6573 StaticTree.static_l_desc = new StaticTree(StaticTree.static_ltree, Tree.extra_lbits, LITERALS + 1, L_CODES, MAX_BITS);
6574
6575 StaticTree.static_d_desc = new StaticTree(StaticTree.static_dtree, Tree.extra_dbits, 0, D_CODES, MAX_BITS);
6576
6577 StaticTree.static_bl_desc = new StaticTree(null, Tree.extra_blbits, 0, BL_CODES, MAX_BL_BITS);
6578
6579 // Deflate
6580
6581 var MAX_MEM_LEVEL = 9;
6582 var DEF_MEM_LEVEL = 8;
6583
6584 function Config(good_length, max_lazy, nice_length, max_chain, func) {
6585 var that = this;
6586 that.good_length = good_length;
6587 that.max_lazy = max_lazy;
6588 that.nice_length = nice_length;
6589 that.max_chain = max_chain;
6590 that.func = func;
6591 }
6592
6593 var STORED = 0;
6594 var FAST = 1;
6595 var SLOW = 2;
6596 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),
6597 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),
6598 new Config(32, 128, 258, 1024, SLOW), new Config(32, 258, 258, 4096, SLOW) ];
6599
6600 var z_errmsg = [ "need dictionary", // Z_NEED_DICT
6601 // 2
6602 "stream end", // Z_STREAM_END 1
6603 "", // Z_OK 0
6604 "", // Z_ERRNO (-1)
6605 "stream error", // Z_STREAM_ERROR (-2)
6606 "data error", // Z_DATA_ERROR (-3)
6607 "", // Z_MEM_ERROR (-4)
6608 "buffer error", // Z_BUF_ERROR (-5)
6609 "",// Z_VERSION_ERROR (-6)
6610 "" ];
6611
6612 // block not completed, need more input or more output
6613 var NeedMore = 0;
6614
6615 // block flush performed
6616 var BlockDone = 1;
6617
6618 // finish started, need only more output at next deflate
6619 var FinishStarted = 2;
6620
6621 // finish done, accept no more input or output
6622 var FinishDone = 3;
6623
6624 // preset dictionary flag in zlib header
6625 var PRESET_DICT = 0x20;
6626
6627 var INIT_STATE = 42;
6628 var BUSY_STATE = 113;
6629 var FINISH_STATE = 666;
6630
6631 // The deflate compression method
6632 var Z_DEFLATED = 8;
6633
6634 var STORED_BLOCK = 0;
6635 var STATIC_TREES = 1;
6636 var DYN_TREES = 2;
6637
6638 var MIN_MATCH = 3;
6639 var MAX_MATCH = 258;
6640 var MIN_LOOKAHEAD = (MAX_MATCH + MIN_MATCH + 1);
6641
6642 function smaller(tree, n, m, depth) {
6643 var tn2 = tree[n * 2];
6644 var tm2 = tree[m * 2];
6645 return (tn2 < tm2 || (tn2 == tm2 && depth[n] <= depth[m]));
6646 }
6647
6648 function Deflate() {
6649
6650 var that = this;
6651 var strm; // pointer back to this zlib stream
6652 var status; // as the name implies
6653 // pending_buf; // output still pending
6654 var pending_buf_size; // size of pending_buf
6655 // pending_out; // next pending byte to output to the stream
6656 // pending; // nb of bytes in the pending buffer
6657 var method; // STORED (for zip only) or DEFLATED
6658 var last_flush; // value of flush param for previous deflate call
6659
6660 var w_size; // LZ77 window size (32K by default)
6661 var w_bits; // log2(w_size) (8..16)
6662 var w_mask; // w_size - 1
6663
6664 var window;
6665 // Sliding window. Input bytes are read into the second half of the window,
6666 // and move to the first half later to keep a dictionary of at least wSize
6667 // bytes. With this organization, matches are limited to a distance of
6668 // wSize-MAX_MATCH bytes, but this ensures that IO is always
6669 // performed with a length multiple of the block size. Also, it limits
6670 // the window size to 64K, which is quite useful on MSDOS.
6671 // To do: use the user input buffer as sliding window.
6672
6673 var window_size;
6674 // Actual size of window: 2*wSize, except when the user input buffer
6675 // is directly used as sliding window.
6676
6677 var prev;
6678 // Link to older string with same hash index. To limit the size of this
6679 // array to 64K, this link is maintained only for the last 32K strings.
6680 // An index in this array is thus a window index modulo 32K.
6681
6682 var head; // Heads of the hash chains or NIL.
6683
6684 var ins_h; // hash index of string to be inserted
6685 var hash_size; // number of elements in hash table
6686 var hash_bits; // log2(hash_size)
6687 var hash_mask; // hash_size-1
6688
6689 // Number of bits by which ins_h must be shifted at each input
6690 // step. It must be such that after MIN_MATCH steps, the oldest
6691 // byte no longer takes part in the hash key, that is:
6692 // hash_shift * MIN_MATCH >= hash_bits
6693 var hash_shift;
6694
6695 // Window position at the beginning of the current output block. Gets
6696 // negative when the window is moved backwards.
6697
6698 var block_start;
6699
6700 var match_length; // length of best match
6701 var prev_match; // previous match
6702 var match_available; // set if previous match exists
6703 var strstart; // start of string to insert
6704 var match_start; // start of matching string
6705 var lookahead; // number of valid bytes ahead in window
6706
6707 // Length of the best match at previous step. Matches not greater than this
6708 // are discarded. This is used in the lazy match evaluation.
6709 var prev_length;
6710
6711 // To speed up deflation, hash chains are never searched beyond this
6712 // length. A higher limit improves compression ratio but degrades the speed.
6713 var max_chain_length;
6714
6715 // Attempt to find a better match only when the current match is strictly
6716 // smaller than this value. This mechanism is used only for compression
6717 // levels >= 4.
6718 var max_lazy_match;
6719
6720 // Insert new strings in the hash table only if the match length is not
6721 // greater than this length. This saves time but degrades compression.
6722 // max_insert_length is used only for compression levels <= 3.
6723
6724 var level; // compression level (1..9)
6725 var strategy; // favor or force Huffman coding
6726
6727 // Use a faster search when the previous match is longer than this
6728 var good_match;
6729
6730 // Stop searching when current match exceeds this
6731 var nice_match;
6732
6733 var dyn_ltree; // literal and length tree
6734 var dyn_dtree; // distance tree
6735 var bl_tree; // Huffman tree for bit lengths
6736
6737 var l_desc = new Tree(); // desc for literal tree
6738 var d_desc = new Tree(); // desc for distance tree
6739 var bl_desc = new Tree(); // desc for bit length tree
6740
6741 // that.heap_len; // number of elements in the heap
6742 // that.heap_max; // element of largest frequency
6743 // The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used.
6744 // The same heap array is used to build all trees.
6745
6746 // Depth of each subtree used as tie breaker for trees of equal frequency
6747 that.depth = [];
6748
6749 var l_buf; // index for literals or lengths */
6750
6751 // Size of match buffer for literals/lengths. There are 4 reasons for
6752 // limiting lit_bufsize to 64K:
6753 // - frequencies can be kept in 16 bit counters
6754 // - if compression is not successful for the first block, all input
6755 // data is still in the window so we can still emit a stored block even
6756 // when input comes from standard input. (This can also be done for
6757 // all blocks if lit_bufsize is not greater than 32K.)
6758 // - if compression is not successful for a file smaller than 64K, we can
6759 // even emit a stored file instead of a stored block (saving 5 bytes).
6760 // This is applicable only for zip (not gzip or zlib).
6761 // - creating new Huffman trees less frequently may not provide fast
6762 // adaptation to changes in the input data statistics. (Take for
6763 // example a binary file with poorly compressible code followed by
6764 // a highly compressible string table.) Smaller buffer sizes give
6765 // fast adaptation but have of course the overhead of transmitting
6766 // trees more frequently.
6767 // - I can't count above 4
6768 var lit_bufsize;
6769
6770 var last_lit; // running index in l_buf
6771
6772 // Buffer for distances. To simplify the code, d_buf and l_buf have
6773 // the same number of elements. To use different lengths, an extra flag
6774 // array would be necessary.
6775
6776 var d_buf; // index of pendig_buf
6777
6778 // that.opt_len; // bit length of current block with optimal trees
6779 // that.static_len; // bit length of current block with static trees
6780 var matches; // number of string matches in current block
6781 var last_eob_len; // bit length of EOB code for last block
6782
6783 // Output buffer. bits are inserted starting at the bottom (least
6784 // significant bits).
6785 var bi_buf;
6786
6787 // Number of valid bits in bi_buf. All bits above the last valid bit
6788 // are always zero.
6789 var bi_valid;
6790
6791 // number of codes at each bit length for an optimal tree
6792 that.bl_count = [];
6793
6794 // heap used to build the Huffman trees
6795 that.heap = [];
6796
6797 dyn_ltree = [];
6798 dyn_dtree = [];
6799 bl_tree = [];
6800
6801 function lm_init() {
6802 var i;
6803 window_size = 2 * w_size;
6804
6805 head[hash_size - 1] = 0;
6806 for (i = 0; i < hash_size - 1; i++) {
6807 head[i] = 0;
6808 }
6809
6810 // Set the default configuration parameters:
6811 max_lazy_match = config_table[level].max_lazy;
6812 good_match = config_table[level].good_length;
6813 nice_match = config_table[level].nice_length;
6814 max_chain_length = config_table[level].max_chain;
6815
6816 strstart = 0;
6817 block_start = 0;
6818 lookahead = 0;
6819 match_length = prev_length = MIN_MATCH - 1;
6820 match_available = 0;
6821 ins_h = 0;
6822 }
6823
6824 function init_block() {
6825 var i;
6826 // Initialize the trees.
6827 for (i = 0; i < L_CODES; i++)
6828 dyn_ltree[i * 2] = 0;
6829 for (i = 0; i < D_CODES; i++)
6830 dyn_dtree[i * 2] = 0;
6831 for (i = 0; i < BL_CODES; i++)
6832 bl_tree[i * 2] = 0;
6833
6834 dyn_ltree[END_BLOCK * 2] = 1;
6835 that.opt_len = that.static_len = 0;
6836 last_lit = matches = 0;
6837 }
6838
6839 // Initialize the tree data structures for a new zlib stream.
6840 function tr_init() {
6841
6842 l_desc.dyn_tree = dyn_ltree;
6843 l_desc.stat_desc = StaticTree.static_l_desc;
6844
6845 d_desc.dyn_tree = dyn_dtree;
6846 d_desc.stat_desc = StaticTree.static_d_desc;
6847
6848 bl_desc.dyn_tree = bl_tree;
6849 bl_desc.stat_desc = StaticTree.static_bl_desc;
6850
6851 bi_buf = 0;
6852 bi_valid = 0;
6853 last_eob_len = 8; // enough lookahead for inflate
6854
6855 // Initialize the first block of the first file:
6856 init_block();
6857 }
6858
6859 // Restore the heap property by moving down the tree starting at node k,
6860 // exchanging a node with the smallest of its two sons if necessary,
6861 // stopping
6862 // when the heap property is re-established (each father smaller than its
6863 // two sons).
6864 that.pqdownheap = function(tree, // the tree to restore
6865 k // node to move down
6866 ) {
6867 var heap = that.heap;
6868 var v = heap[k];
6869 var j = k << 1; // left son of k
6870 while (j <= that.heap_len) {
6871 // Set j to the smallest of the two sons:
6872 if (j < that.heap_len && smaller(tree, heap[j + 1], heap[j], that.depth)) {
6873 j++;
6874 }
6875 // Exit if v is smaller than both sons
6876 if (smaller(tree, v, heap[j], that.depth))
6877 break;
6878
6879 // Exchange v with the smallest son
6880 heap[k] = heap[j];
6881 k = j;
6882 // And continue down the tree, setting j to the left son of k
6883 j <<= 1;
6884 }
6885 heap[k] = v;
6886 };
6887
6888 // Scan a literal or distance tree to determine the frequencies of the codes
6889 // in the bit length tree.
6890 function scan_tree(tree,// the tree to be scanned
6891 max_code // and its largest code of non zero frequency
6892 ) {
6893 var n; // iterates over all tree elements
6894 var prevlen = -1; // last emitted length
6895 var curlen; // length of current code
6896 var nextlen = tree[0 * 2 + 1]; // length of next code
6897 var count = 0; // repeat count of the current code
6898 var max_count = 7; // max repeat count
6899 var min_count = 4; // min repeat count
6900
6901 if (nextlen === 0) {
6902 max_count = 138;
6903 min_count = 3;
6904 }
6905 tree[(max_code + 1) * 2 + 1] = 0xffff; // guard
6906
6907 for (n = 0; n <= max_code; n++) {
6908 curlen = nextlen;
6909 nextlen = tree[(n + 1) * 2 + 1];
6910 if (++count < max_count && curlen == nextlen) {
6911 continue;
6912 } else if (count < min_count) {
6913 bl_tree[curlen * 2] += count;
6914 } else if (curlen !== 0) {
6915 if (curlen != prevlen)
6916 bl_tree[curlen * 2]++;
6917 bl_tree[REP_3_6 * 2]++;
6918 } else if (count <= 10) {
6919 bl_tree[REPZ_3_10 * 2]++;
6920 } else {
6921 bl_tree[REPZ_11_138 * 2]++;
6922 }
6923 count = 0;
6924 prevlen = curlen;
6925 if (nextlen === 0) {
6926 max_count = 138;
6927 min_count = 3;
6928 } else if (curlen == nextlen) {
6929 max_count = 6;
6930 min_count = 3;
6931 } else {
6932 max_count = 7;
6933 min_count = 4;
6934 }
6935 }
6936 }
6937
6938 // Construct the Huffman tree for the bit lengths and return the index in
6939 // bl_order of the last bit length code to send.
6940 function build_bl_tree() {
6941 var max_blindex; // index of last bit length code of non zero freq
6942
6943 // Determine the bit length frequencies for literal and distance trees
6944 scan_tree(dyn_ltree, l_desc.max_code);
6945 scan_tree(dyn_dtree, d_desc.max_code);
6946
6947 // Build the bit length tree:
6948 bl_desc.build_tree(that);
6949 // opt_len now includes the length of the tree representations, except
6950 // the lengths of the bit lengths codes and the 5+5+4 bits for the
6951 // counts.
6952
6953 // Determine the number of bit length codes to send. The pkzip format
6954 // requires that at least 4 bit length codes be sent. (appnote.txt says
6955 // 3 but the actual value used is 4.)
6956 for (max_blindex = BL_CODES - 1; max_blindex >= 3; max_blindex--) {
6957 if (bl_tree[Tree.bl_order[max_blindex] * 2 + 1] !== 0)
6958 break;
6959 }
6960 // Update opt_len to include the bit length tree and counts
6961 that.opt_len += 3 * (max_blindex + 1) + 5 + 5 + 4;
6962
6963 return max_blindex;
6964 }
6965
6966 // Output a byte on the stream.
6967 // IN assertion: there is enough room in pending_buf.
6968 function put_byte(p) {
6969 that.pending_buf[that.pending++] = p;
6970 }
6971
6972 function put_short(w) {
6973 put_byte(w & 0xff);
6974 put_byte((w >>> 8) & 0xff);
6975 }
6976
6977 function putShortMSB(b) {
6978 put_byte((b >> 8) & 0xff);
6979 put_byte((b & 0xff) & 0xff);
6980 }
6981
6982 function send_bits(value, length) {
6983 var val, len = length;
6984 if (bi_valid > Buf_size - len) {
6985 val = value;
6986 // bi_buf |= (val << bi_valid);
6987 bi_buf |= ((val << bi_valid) & 0xffff);
6988 put_short(bi_buf);
6989 bi_buf = val >>> (Buf_size - bi_valid);
6990 bi_valid += len - Buf_size;
6991 } else {
6992 // bi_buf |= (value) << bi_valid;
6993 bi_buf |= (((value) << bi_valid) & 0xffff);
6994 bi_valid += len;
6995 }
6996 }
6997
6998 function send_code(c, tree) {
6999 var c2 = c * 2;
7000 send_bits(tree[c2] & 0xffff, tree[c2 + 1] & 0xffff);
7001 }
7002
7003 // Send a literal or distance tree in compressed form, using the codes in
7004 // bl_tree.
7005 function send_tree(tree,// the tree to be sent
7006 max_code // and its largest code of non zero frequency
7007 ) {
7008 var n; // iterates over all tree elements
7009 var prevlen = -1; // last emitted length
7010 var curlen; // length of current code
7011 var nextlen = tree[0 * 2 + 1]; // length of next code
7012 var count = 0; // repeat count of the current code
7013 var max_count = 7; // max repeat count
7014 var min_count = 4; // min repeat count
7015
7016 if (nextlen === 0) {
7017 max_count = 138;
7018 min_count = 3;
7019 }
7020
7021 for (n = 0; n <= max_code; n++) {
7022 curlen = nextlen;
7023 nextlen = tree[(n + 1) * 2 + 1];
7024 if (++count < max_count && curlen == nextlen) {
7025 continue;
7026 } else if (count < min_count) {
7027 do {
7028 send_code(curlen, bl_tree);
7029 } while (--count !== 0);
7030 } else if (curlen !== 0) {
7031 if (curlen != prevlen) {
7032 send_code(curlen, bl_tree);
7033 count--;
7034 }
7035 send_code(REP_3_6, bl_tree);
7036 send_bits(count - 3, 2);
7037 } else if (count <= 10) {
7038 send_code(REPZ_3_10, bl_tree);
7039 send_bits(count - 3, 3);
7040 } else {
7041 send_code(REPZ_11_138, bl_tree);
7042 send_bits(count - 11, 7);
7043 }
7044 count = 0;
7045 prevlen = curlen;
7046 if (nextlen === 0) {
7047 max_count = 138;
7048 min_count = 3;
7049 } else if (curlen == nextlen) {
7050 max_count = 6;
7051 min_count = 3;
7052 } else {
7053 max_count = 7;
7054 min_count = 4;
7055 }
7056 }
7057 }
7058
7059 // Send the header for a block using dynamic Huffman trees: the counts, the
7060 // lengths of the bit length codes, the literal tree and the distance tree.
7061 // IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4.
7062 function send_all_trees(lcodes, dcodes, blcodes) {
7063 var rank; // index in bl_order
7064
7065 send_bits(lcodes - 257, 5); // not +255 as stated in appnote.txt
7066 send_bits(dcodes - 1, 5);
7067 send_bits(blcodes - 4, 4); // not -3 as stated in appnote.txt
7068 for (rank = 0; rank < blcodes; rank++) {
7069 send_bits(bl_tree[Tree.bl_order[rank] * 2 + 1], 3);
7070 }
7071 send_tree(dyn_ltree, lcodes - 1); // literal tree
7072 send_tree(dyn_dtree, dcodes - 1); // distance tree
7073 }
7074
7075 // Flush the bit buffer, keeping at most 7 bits in it.
7076 function bi_flush() {
7077 if (bi_valid == 16) {
7078 put_short(bi_buf);
7079 bi_buf = 0;
7080 bi_valid = 0;
7081 } else if (bi_valid >= 8) {
7082 put_byte(bi_buf & 0xff);
7083 bi_buf >>>= 8;
7084 bi_valid -= 8;
7085 }
7086 }
7087
7088 // Send one empty static block to give enough lookahead for inflate.
7089 // This takes 10 bits, of which 7 may remain in the bit buffer.
7090 // The current inflate code requires 9 bits of lookahead. If the
7091 // last two codes for the previous block (real code plus EOB) were coded
7092 // on 5 bits or less, inflate may have only 5+3 bits of lookahead to decode
7093 // the last real code. In this case we send two empty static blocks instead
7094 // of one. (There are no problems if the previous block is stored or fixed.)
7095 // To simplify the code, we assume the worst case of last real code encoded
7096 // on one bit only.
7097 function _tr_align() {
7098 send_bits(STATIC_TREES << 1, 3);
7099 send_code(END_BLOCK, StaticTree.static_ltree);
7100
7101 bi_flush();
7102
7103 // Of the 10 bits for the empty block, we have already sent
7104 // (10 - bi_valid) bits. The lookahead for the last real code (before
7105 // the EOB of the previous block) was thus at least one plus the length
7106 // of the EOB plus what we have just sent of the empty static block.
7107 if (1 + last_eob_len + 10 - bi_valid < 9) {
7108 send_bits(STATIC_TREES << 1, 3);
7109 send_code(END_BLOCK, StaticTree.static_ltree);
7110 bi_flush();
7111 }
7112 last_eob_len = 7;
7113 }
7114
7115 // Save the match info and tally the frequency counts. Return true if
7116 // the current block must be flushed.
7117 function _tr_tally(dist, // distance of matched string
7118 lc // match length-MIN_MATCH or unmatched char (if dist==0)
7119 ) {
7120 var out_length, in_length, dcode;
7121 that.pending_buf[d_buf + last_lit * 2] = (dist >>> 8) & 0xff;
7122 that.pending_buf[d_buf + last_lit * 2 + 1] = dist & 0xff;
7123
7124 that.pending_buf[l_buf + last_lit] = lc & 0xff;
7125 last_lit++;
7126
7127 if (dist === 0) {
7128 // lc is the unmatched char
7129 dyn_ltree[lc * 2]++;
7130 } else {
7131 matches++;
7132 // Here, lc is the match length - MIN_MATCH
7133 dist--; // dist = match distance - 1
7134 dyn_ltree[(Tree._length_code[lc] + LITERALS + 1) * 2]++;
7135 dyn_dtree[Tree.d_code(dist) * 2]++;
7136 }
7137
7138 if ((last_lit & 0x1fff) === 0 && level > 2) {
7139 // Compute an upper bound for the compressed length
7140 out_length = last_lit * 8;
7141 in_length = strstart - block_start;
7142 for (dcode = 0; dcode < D_CODES; dcode++) {
7143 out_length += dyn_dtree[dcode * 2] * (5 + Tree.extra_dbits[dcode]);
7144 }
7145 out_length >>>= 3;
7146 if ((matches < Math.floor(last_lit / 2)) && out_length < Math.floor(in_length / 2))
7147 return true;
7148 }
7149
7150 return (last_lit == lit_bufsize - 1);
7151 // We avoid equality with lit_bufsize because of wraparound at 64K
7152 // on 16 bit machines and because stored blocks are restricted to
7153 // 64K-1 bytes.
7154 }
7155
7156 // Send the block data compressed using the given Huffman trees
7157 function compress_block(ltree, dtree) {
7158 var dist; // distance of matched string
7159 var lc; // match length or unmatched char (if dist === 0)
7160 var lx = 0; // running index in l_buf
7161 var code; // the code to send
7162 var extra; // number of extra bits to send
7163
7164 if (last_lit !== 0) {
7165 do {
7166 dist = ((that.pending_buf[d_buf + lx * 2] << 8) & 0xff00) | (that.pending_buf[d_buf + lx * 2 + 1] & 0xff);
7167 lc = (that.pending_buf[l_buf + lx]) & 0xff;
7168 lx++;
7169
7170 if (dist === 0) {
7171 send_code(lc, ltree); // send a literal byte
7172 } else {
7173 // Here, lc is the match length - MIN_MATCH
7174 code = Tree._length_code[lc];
7175
7176 send_code(code + LITERALS + 1, ltree); // send the length
7177 // code
7178 extra = Tree.extra_lbits[code];
7179 if (extra !== 0) {
7180 lc -= Tree.base_length[code];
7181 send_bits(lc, extra); // send the extra length bits
7182 }
7183 dist--; // dist is now the match distance - 1
7184 code = Tree.d_code(dist);
7185
7186 send_code(code, dtree); // send the distance code
7187 extra = Tree.extra_dbits[code];
7188 if (extra !== 0) {
7189 dist -= Tree.base_dist[code];
7190 send_bits(dist, extra); // send the extra distance bits
7191 }
7192 } // literal or match pair ?
7193
7194 // Check that the overlay between pending_buf and d_buf+l_buf is
7195 // ok:
7196 } while (lx < last_lit);
7197 }
7198
7199 send_code(END_BLOCK, ltree);
7200 last_eob_len = ltree[END_BLOCK * 2 + 1];
7201 }
7202
7203 // Flush the bit buffer and align the output on a byte boundary
7204 function bi_windup() {
7205 if (bi_valid > 8) {
7206 put_short(bi_buf);
7207 } else if (bi_valid > 0) {
7208 put_byte(bi_buf & 0xff);
7209 }
7210 bi_buf = 0;
7211 bi_valid = 0;
7212 }
7213
7214 // Copy a stored block, storing first the length and its
7215 // one's complement if requested.
7216 function copy_block(buf, // the input data
7217 len, // its length
7218 header // true if block header must be written
7219 ) {
7220 bi_windup(); // align on byte boundary
7221 last_eob_len = 8; // enough lookahead for inflate
7222
7223 if (header) {
7224 put_short(len);
7225 put_short(~len);
7226 }
7227
7228 that.pending_buf.set(window.subarray(buf, buf + len), that.pending);
7229 that.pending += len;
7230 }
7231
7232 // Send a stored block
7233 function _tr_stored_block(buf, // input block
7234 stored_len, // length of input block
7235 eof // true if this is the last block for a file
7236 ) {
7237 send_bits((STORED_BLOCK << 1) + (eof ? 1 : 0), 3); // send block type
7238 copy_block(buf, stored_len, true); // with header
7239 }
7240
7241 // Determine the best encoding for the current block: dynamic trees, static
7242 // trees or store, and output the encoded block to the zip file.
7243 function _tr_flush_block(buf, // input block, or NULL if too old
7244 stored_len, // length of input block
7245 eof // true if this is the last block for a file
7246 ) {
7247 var opt_lenb, static_lenb;// opt_len and static_len in bytes
7248 var max_blindex = 0; // index of last bit length code of non zero freq
7249
7250 // Build the Huffman trees unless a stored block is forced
7251 if (level > 0) {
7252 // Construct the literal and distance trees
7253 l_desc.build_tree(that);
7254
7255 d_desc.build_tree(that);
7256
7257 // At this point, opt_len and static_len are the total bit lengths
7258 // of
7259 // the compressed block data, excluding the tree representations.
7260
7261 // Build the bit length tree for the above two trees, and get the
7262 // index
7263 // in bl_order of the last bit length code to send.
7264 max_blindex = build_bl_tree();
7265
7266 // Determine the best encoding. Compute first the block length in
7267 // bytes
7268 opt_lenb = (that.opt_len + 3 + 7) >>> 3;
7269 static_lenb = (that.static_len + 3 + 7) >>> 3;
7270
7271 if (static_lenb <= opt_lenb)
7272 opt_lenb = static_lenb;
7273 } else {
7274 opt_lenb = static_lenb = stored_len + 5; // force a stored block
7275 }
7276
7277 if ((stored_len + 4 <= opt_lenb) && buf != -1) {
7278 // 4: two words for the lengths
7279 // The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE.
7280 // Otherwise we can't have processed more than WSIZE input bytes
7281 // since
7282 // the last block flush, because compression would have been
7283 // successful. If LIT_BUFSIZE <= WSIZE, it is never too late to
7284 // transform a block into a stored block.
7285 _tr_stored_block(buf, stored_len, eof);
7286 } else if (static_lenb == opt_lenb) {
7287 send_bits((STATIC_TREES << 1) + (eof ? 1 : 0), 3);
7288 compress_block(StaticTree.static_ltree, StaticTree.static_dtree);
7289 } else {
7290 send_bits((DYN_TREES << 1) + (eof ? 1 : 0), 3);
7291 send_all_trees(l_desc.max_code + 1, d_desc.max_code + 1, max_blindex + 1);
7292 compress_block(dyn_ltree, dyn_dtree);
7293 }
7294
7295 // The above check is made mod 2^32, for files larger than 512 MB
7296 // and uLong implemented on 32 bits.
7297
7298 init_block();
7299
7300 if (eof) {
7301 bi_windup();
7302 }
7303 }
7304
7305 function flush_block_only(eof) {
7306 _tr_flush_block(block_start >= 0 ? block_start : -1, strstart - block_start, eof);
7307 block_start = strstart;
7308 strm.flush_pending();
7309 }
7310
7311 // Fill the window when the lookahead becomes insufficient.
7312 // Updates strstart and lookahead.
7313 //
7314 // IN assertion: lookahead < MIN_LOOKAHEAD
7315 // OUT assertions: strstart <= window_size-MIN_LOOKAHEAD
7316 // At least one byte has been read, or avail_in === 0; reads are
7317 // performed for at least two bytes (required for the zip translate_eol
7318 // option -- not supported here).
7319 function fill_window() {
7320 var n, m;
7321 var p;
7322 var more; // Amount of free space at the end of the window.
7323
7324 do {
7325 more = (window_size - lookahead - strstart);
7326
7327 // Deal with !@#$% 64K limit:
7328 if (more === 0 && strstart === 0 && lookahead === 0) {
7329 more = w_size;
7330 } else if (more == -1) {
7331 // Very unlikely, but possible on 16 bit machine if strstart ==
7332 // 0
7333 // and lookahead == 1 (input done one byte at time)
7334 more--;
7335
7336 // If the window is almost full and there is insufficient
7337 // lookahead,
7338 // move the upper half to the lower one to make room in the
7339 // upper half.
7340 } else if (strstart >= w_size + w_size - MIN_LOOKAHEAD) {
7341 window.set(window.subarray(w_size, w_size + w_size), 0);
7342
7343 match_start -= w_size;
7344 strstart -= w_size; // we now have strstart >= MAX_DIST
7345 block_start -= w_size;
7346
7347 // Slide the hash table (could be avoided with 32 bit values
7348 // at the expense of memory usage). We slide even when level ==
7349 // 0
7350 // to keep the hash table consistent if we switch back to level
7351 // > 0
7352 // later. (Using level 0 permanently is not an optimal usage of
7353 // zlib, so we don't care about this pathological case.)
7354
7355 n = hash_size;
7356 p = n;
7357 do {
7358 m = (head[--p] & 0xffff);
7359 head[p] = (m >= w_size ? m - w_size : 0);
7360 } while (--n !== 0);
7361
7362 n = w_size;
7363 p = n;
7364 do {
7365 m = (prev[--p] & 0xffff);
7366 prev[p] = (m >= w_size ? m - w_size : 0);
7367 // If n is not on any hash chain, prev[n] is garbage but
7368 // its value will never be used.
7369 } while (--n !== 0);
7370 more += w_size;
7371 }
7372
7373 if (strm.avail_in === 0)
7374 return;
7375
7376 // If there was no sliding:
7377 // strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 &&
7378 // more == window_size - lookahead - strstart
7379 // => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1)
7380 // => more >= window_size - 2*WSIZE + 2
7381 // In the BIG_MEM or MMAP case (not yet supported),
7382 // window_size == input_size + MIN_LOOKAHEAD &&
7383 // strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD.
7384 // Otherwise, window_size == 2*WSIZE so more >= 2.
7385 // If there was sliding, more >= WSIZE. So in all cases, more >= 2.
7386
7387 n = strm.read_buf(window, strstart + lookahead, more);
7388 lookahead += n;
7389
7390 // Initialize the hash value now that we have some input:
7391 if (lookahead >= MIN_MATCH) {
7392 ins_h = window[strstart] & 0xff;
7393 ins_h = (((ins_h) << hash_shift) ^ (window[strstart + 1] & 0xff)) & hash_mask;
7394 }
7395 // If the whole input has less than MIN_MATCH bytes, ins_h is
7396 // garbage,
7397 // but this is not important since only literal bytes will be
7398 // emitted.
7399 } while (lookahead < MIN_LOOKAHEAD && strm.avail_in !== 0);
7400 }
7401
7402 // Copy without compression as much as possible from the input stream,
7403 // return
7404 // the current block state.
7405 // This function does not insert new strings in the dictionary since
7406 // uncompressible data is probably not useful. This function is used
7407 // only for the level=0 compression option.
7408 // NOTE: this function should be optimized to avoid extra copying from
7409 // window to pending_buf.
7410 function deflate_stored(flush) {
7411 // Stored blocks are limited to 0xffff bytes, pending_buf is limited
7412 // to pending_buf_size, and each stored block has a 5 byte header:
7413
7414 var max_block_size = 0xffff;
7415 var max_start;
7416
7417 if (max_block_size > pending_buf_size - 5) {
7418 max_block_size = pending_buf_size - 5;
7419 }
7420
7421 // Copy as much as possible from input to output:
7422 while (true) {
7423 // Fill the window as much as possible:
7424 if (lookahead <= 1) {
7425 fill_window();
7426 if (lookahead === 0 && flush == Z_NO_FLUSH)
7427 return NeedMore;
7428 if (lookahead === 0)
7429 break; // flush the current block
7430 }
7431
7432 strstart += lookahead;
7433 lookahead = 0;
7434
7435 // Emit a stored block if pending_buf will be full:
7436 max_start = block_start + max_block_size;
7437 if (strstart === 0 || strstart >= max_start) {
7438 // strstart === 0 is possible when wraparound on 16-bit machine
7439 lookahead = (strstart - max_start);
7440 strstart = max_start;
7441
7442 flush_block_only(false);
7443 if (strm.avail_out === 0)
7444 return NeedMore;
7445
7446 }
7447
7448 // Flush if we may have to slide, otherwise block_start may become
7449 // negative and the data will be gone:
7450 if (strstart - block_start >= w_size - MIN_LOOKAHEAD) {
7451 flush_block_only(false);
7452 if (strm.avail_out === 0)
7453 return NeedMore;
7454 }
7455 }
7456
7457 flush_block_only(flush == Z_FINISH);
7458 if (strm.avail_out === 0)
7459 return (flush == Z_FINISH) ? FinishStarted : NeedMore;
7460
7461 return flush == Z_FINISH ? FinishDone : BlockDone;
7462 }
7463
7464 function longest_match(cur_match) {
7465 var chain_length = max_chain_length; // max hash chain length
7466 var scan = strstart; // current string
7467 var match; // matched string
7468 var len; // length of current match
7469 var best_len = prev_length; // best match length so far
7470 var limit = strstart > (w_size - MIN_LOOKAHEAD) ? strstart - (w_size - MIN_LOOKAHEAD) : 0;
7471 var _nice_match = nice_match;
7472
7473 // Stop when cur_match becomes <= limit. To simplify the code,
7474 // we prevent matches with the string of window index 0.
7475
7476 var wmask = w_mask;
7477
7478 var strend = strstart + MAX_MATCH;
7479 var scan_end1 = window[scan + best_len - 1];
7480 var scan_end = window[scan + best_len];
7481
7482 // The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of
7483 // 16.
7484 // It is easy to get rid of this optimization if necessary.
7485
7486 // Do not waste too much time if we already have a good match:
7487 if (prev_length >= good_match) {
7488 chain_length >>= 2;
7489 }
7490
7491 // Do not look for matches beyond the end of the input. This is
7492 // necessary
7493 // to make deflate deterministic.
7494 if (_nice_match > lookahead)
7495 _nice_match = lookahead;
7496
7497 do {
7498 match = cur_match;
7499
7500 // Skip to next match if the match length cannot increase
7501 // or if the match length is less than 2:
7502 if (window[match + best_len] != scan_end || window[match + best_len - 1] != scan_end1 || window[match] != window[scan]
7503 || window[++match] != window[scan + 1])
7504 continue;
7505
7506 // The check at best_len-1 can be removed because it will be made
7507 // again later. (This heuristic is not always a win.)
7508 // It is not necessary to compare scan[2] and match[2] since they
7509 // are always equal when the other bytes match, given that
7510 // the hash keys are equal and that HASH_BITS >= 8.
7511 scan += 2;
7512 match++;
7513
7514 // We check for insufficient lookahead only every 8th comparison;
7515 // the 256th check will be made at strstart+258.
7516 do {
7517 } while (window[++scan] == window[++match] && window[++scan] == window[++match] && window[++scan] == window[++match]
7518 && window[++scan] == window[++match] && window[++scan] == window[++match] && window[++scan] == window[++match]
7519 && window[++scan] == window[++match] && window[++scan] == window[++match] && scan < strend);
7520
7521 len = MAX_MATCH - (strend - scan);
7522 scan = strend - MAX_MATCH;
7523
7524 if (len > best_len) {
7525 match_start = cur_match;
7526 best_len = len;
7527 if (len >= _nice_match)
7528 break;
7529 scan_end1 = window[scan + best_len - 1];
7530 scan_end = window[scan + best_len];
7531 }
7532
7533 } while ((cur_match = (prev[cur_match & wmask] & 0xffff)) > limit && --chain_length !== 0);
7534
7535 if (best_len <= lookahead)
7536 return best_len;
7537 return lookahead;
7538 }
7539
7540 // Compress as much as possible from the input stream, return the current
7541 // block state.
7542 // This function does not perform lazy evaluation of matches and inserts
7543 // new strings in the dictionary only for unmatched strings or for short
7544 // matches. It is used only for the fast compression options.
7545 function deflate_fast(flush) {
7546 // short hash_head = 0; // head of the hash chain
7547 var hash_head = 0; // head of the hash chain
7548 var bflush; // set if current block must be flushed
7549
7550 while (true) {
7551 // Make sure that we always have enough lookahead, except
7552 // at the end of the input file. We need MAX_MATCH bytes
7553 // for the next match, plus MIN_MATCH bytes to insert the
7554 // string following the next match.
7555 if (lookahead < MIN_LOOKAHEAD) {
7556 fill_window();
7557 if (lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) {
7558 return NeedMore;
7559 }
7560 if (lookahead === 0)
7561 break; // flush the current block
7562 }
7563
7564 // Insert the string window[strstart .. strstart+2] in the
7565 // dictionary, and set hash_head to the head of the hash chain:
7566 if (lookahead >= MIN_MATCH) {
7567 ins_h = (((ins_h) << hash_shift) ^ (window[(strstart) + (MIN_MATCH - 1)] & 0xff)) & hash_mask;
7568
7569 // prev[strstart&w_mask]=hash_head=head[ins_h];
7570 hash_head = (head[ins_h] & 0xffff);
7571 prev[strstart & w_mask] = head[ins_h];
7572 head[ins_h] = strstart;
7573 }
7574
7575 // Find the longest match, discarding those <= prev_length.
7576 // At this point we have always match_length < MIN_MATCH
7577
7578 if (hash_head !== 0 && ((strstart - hash_head) & 0xffff) <= w_size - MIN_LOOKAHEAD) {
7579 // To simplify the code, we prevent matches with the string
7580 // of window index 0 (in particular we have to avoid a match
7581 // of the string with itself at the start of the input file).
7582 if (strategy != Z_HUFFMAN_ONLY) {
7583 match_length = longest_match(hash_head);
7584 }
7585 // longest_match() sets match_start
7586 }
7587 if (match_length >= MIN_MATCH) {
7588 // check_match(strstart, match_start, match_length);
7589
7590 bflush = _tr_tally(strstart - match_start, match_length - MIN_MATCH);
7591
7592 lookahead -= match_length;
7593
7594 // Insert new strings in the hash table only if the match length
7595 // is not too large. This saves time but degrades compression.
7596 if (match_length <= max_lazy_match && lookahead >= MIN_MATCH) {
7597 match_length--; // string at strstart already in hash table
7598 do {
7599 strstart++;
7600
7601 ins_h = ((ins_h << hash_shift) ^ (window[(strstart) + (MIN_MATCH - 1)] & 0xff)) & hash_mask;
7602 // prev[strstart&w_mask]=hash_head=head[ins_h];
7603 hash_head = (head[ins_h] & 0xffff);
7604 prev[strstart & w_mask] = head[ins_h];
7605 head[ins_h] = strstart;
7606
7607 // strstart never exceeds WSIZE-MAX_MATCH, so there are
7608 // always MIN_MATCH bytes ahead.
7609 } while (--match_length !== 0);
7610 strstart++;
7611 } else {
7612 strstart += match_length;
7613 match_length = 0;
7614 ins_h = window[strstart] & 0xff;
7615
7616 ins_h = (((ins_h) << hash_shift) ^ (window[strstart + 1] & 0xff)) & hash_mask;
7617 // If lookahead < MIN_MATCH, ins_h is garbage, but it does
7618 // not
7619 // matter since it will be recomputed at next deflate call.
7620 }
7621 } else {
7622 // No match, output a literal byte
7623
7624 bflush = _tr_tally(0, window[strstart] & 0xff);
7625 lookahead--;
7626 strstart++;
7627 }
7628 if (bflush) {
7629
7630 flush_block_only(false);
7631 if (strm.avail_out === 0)
7632 return NeedMore;
7633 }
7634 }
7635
7636 flush_block_only(flush == Z_FINISH);
7637 if (strm.avail_out === 0) {
7638 if (flush == Z_FINISH)
7639 return FinishStarted;
7640 else
7641 return NeedMore;
7642 }
7643 return flush == Z_FINISH ? FinishDone : BlockDone;
7644 }
7645
7646 // Same as above, but achieves better compression. We use a lazy
7647 // evaluation for matches: a match is finally adopted only if there is
7648 // no better match at the next window position.
7649 function deflate_slow(flush) {
7650 // short hash_head = 0; // head of hash chain
7651 var hash_head = 0; // head of hash chain
7652 var bflush; // set if current block must be flushed
7653 var max_insert;
7654
7655 // Process the input block.
7656 while (true) {
7657 // Make sure that we always have enough lookahead, except
7658 // at the end of the input file. We need MAX_MATCH bytes
7659 // for the next match, plus MIN_MATCH bytes to insert the
7660 // string following the next match.
7661
7662 if (lookahead < MIN_LOOKAHEAD) {
7663 fill_window();
7664 if (lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) {
7665 return NeedMore;
7666 }
7667 if (lookahead === 0)
7668 break; // flush the current block
7669 }
7670
7671 // Insert the string window[strstart .. strstart+2] in the
7672 // dictionary, and set hash_head to the head of the hash chain:
7673
7674 if (lookahead >= MIN_MATCH) {
7675 ins_h = (((ins_h) << hash_shift) ^ (window[(strstart) + (MIN_MATCH - 1)] & 0xff)) & hash_mask;
7676 // prev[strstart&w_mask]=hash_head=head[ins_h];
7677 hash_head = (head[ins_h] & 0xffff);
7678 prev[strstart & w_mask] = head[ins_h];
7679 head[ins_h] = strstart;
7680 }
7681
7682 // Find the longest match, discarding those <= prev_length.
7683 prev_length = match_length;
7684 prev_match = match_start;
7685 match_length = MIN_MATCH - 1;
7686
7687 if (hash_head !== 0 && prev_length < max_lazy_match && ((strstart - hash_head) & 0xffff) <= w_size - MIN_LOOKAHEAD) {
7688 // To simplify the code, we prevent matches with the string
7689 // of window index 0 (in particular we have to avoid a match
7690 // of the string with itself at the start of the input file).
7691
7692 if (strategy != Z_HUFFMAN_ONLY) {
7693 match_length = longest_match(hash_head);
7694 }
7695 // longest_match() sets match_start
7696
7697 if (match_length <= 5 && (strategy == Z_FILTERED || (match_length == MIN_MATCH && strstart - match_start > 4096))) {
7698
7699 // If prev_match is also MIN_MATCH, match_start is garbage
7700 // but we will ignore the current match anyway.
7701 match_length = MIN_MATCH - 1;
7702 }
7703 }
7704
7705 // If there was a match at the previous step and the current
7706 // match is not better, output the previous match:
7707 if (prev_length >= MIN_MATCH && match_length <= prev_length) {
7708 max_insert = strstart + lookahead - MIN_MATCH;
7709 // Do not insert strings in hash table beyond this.
7710
7711 // check_match(strstart-1, prev_match, prev_length);
7712
7713 bflush = _tr_tally(strstart - 1 - prev_match, prev_length - MIN_MATCH);
7714
7715 // Insert in hash table all strings up to the end of the match.
7716 // strstart-1 and strstart are already inserted. If there is not
7717 // enough lookahead, the last two strings are not inserted in
7718 // the hash table.
7719 lookahead -= prev_length - 1;
7720 prev_length -= 2;
7721 do {
7722 if (++strstart <= max_insert) {
7723 ins_h = (((ins_h) << hash_shift) ^ (window[(strstart) + (MIN_MATCH - 1)] & 0xff)) & hash_mask;
7724 // prev[strstart&w_mask]=hash_head=head[ins_h];
7725 hash_head = (head[ins_h] & 0xffff);
7726 prev[strstart & w_mask] = head[ins_h];
7727 head[ins_h] = strstart;
7728 }
7729 } while (--prev_length !== 0);
7730 match_available = 0;
7731 match_length = MIN_MATCH - 1;
7732 strstart++;
7733
7734 if (bflush) {
7735 flush_block_only(false);
7736 if (strm.avail_out === 0)
7737 return NeedMore;
7738 }
7739 } else if (match_available !== 0) {
7740
7741 // If there was no match at the previous position, output a
7742 // single literal. If there was a match but the current match
7743 // is longer, truncate the previous match to a single literal.
7744
7745 bflush = _tr_tally(0, window[strstart - 1] & 0xff);
7746
7747 if (bflush) {
7748 flush_block_only(false);
7749 }
7750 strstart++;
7751 lookahead--;
7752 if (strm.avail_out === 0)
7753 return NeedMore;
7754 } else {
7755 // There is no previous match to compare with, wait for
7756 // the next step to decide.
7757
7758 match_available = 1;
7759 strstart++;
7760 lookahead--;
7761 }
7762 }
7763
7764 if (match_available !== 0) {
7765 bflush = _tr_tally(0, window[strstart - 1] & 0xff);
7766 match_available = 0;
7767 }
7768 flush_block_only(flush == Z_FINISH);
7769
7770 if (strm.avail_out === 0) {
7771 if (flush == Z_FINISH)
7772 return FinishStarted;
7773 else
7774 return NeedMore;
7775 }
7776
7777 return flush == Z_FINISH ? FinishDone : BlockDone;
7778 }
7779
7780 function deflateReset(strm) {
7781 strm.total_in = strm.total_out = 0;
7782 strm.msg = null; //
7783
7784 that.pending = 0;
7785 that.pending_out = 0;
7786
7787 status = BUSY_STATE;
7788
7789 last_flush = Z_NO_FLUSH;
7790
7791 tr_init();
7792 lm_init();
7793 return Z_OK;
7794 }
7795
7796 that.deflateInit = function(strm, _level, bits, _method, memLevel, _strategy) {
7797 if (!_method)
7798 _method = Z_DEFLATED;
7799 if (!memLevel)
7800 memLevel = DEF_MEM_LEVEL;
7801 if (!_strategy)
7802 _strategy = Z_DEFAULT_STRATEGY;
7803
7804 // byte[] my_version=ZLIB_VERSION;
7805
7806 //
7807 // if (!version || version[0] != my_version[0]
7808 // || stream_size != sizeof(z_stream)) {
7809 // return Z_VERSION_ERROR;
7810 // }
7811
7812 strm.msg = null;
7813
7814 if (_level == Z_DEFAULT_COMPRESSION)
7815 _level = 6;
7816
7817 if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || _method != Z_DEFLATED || bits < 9 || bits > 15 || _level < 0 || _level > 9 || _strategy < 0
7818 || _strategy > Z_HUFFMAN_ONLY) {
7819 return Z_STREAM_ERROR;
7820 }
7821
7822 strm.dstate = that;
7823
7824 w_bits = bits;
7825 w_size = 1 << w_bits;
7826 w_mask = w_size - 1;
7827
7828 hash_bits = memLevel + 7;
7829 hash_size = 1 << hash_bits;
7830 hash_mask = hash_size - 1;
7831 hash_shift = Math.floor((hash_bits + MIN_MATCH - 1) / MIN_MATCH);
7832
7833 window = new Uint8Array(w_size * 2);
7834 prev = [];
7835 head = [];
7836
7837 lit_bufsize = 1 << (memLevel + 6); // 16K elements by default
7838
7839 // We overlay pending_buf and d_buf+l_buf. This works since the average
7840 // output size for (length,distance) codes is <= 24 bits.
7841 that.pending_buf = new Uint8Array(lit_bufsize * 4);
7842 pending_buf_size = lit_bufsize * 4;
7843
7844 d_buf = Math.floor(lit_bufsize / 2);
7845 l_buf = (1 + 2) * lit_bufsize;
7846
7847 level = _level;
7848
7849 strategy = _strategy;
7850 method = _method & 0xff;
7851
7852 return deflateReset(strm);
7853 };
7854
7855 that.deflateEnd = function() {
7856 if (status != INIT_STATE && status != BUSY_STATE && status != FINISH_STATE) {
7857 return Z_STREAM_ERROR;
7858 }
7859 // Deallocate in reverse order of allocations:
7860 that.pending_buf = null;
7861 head = null;
7862 prev = null;
7863 window = null;
7864 // free
7865 that.dstate = null;
7866 return status == BUSY_STATE ? Z_DATA_ERROR : Z_OK;
7867 };
7868
7869 that.deflateParams = function(strm, _level, _strategy) {
7870 var err = Z_OK;
7871
7872 if (_level == Z_DEFAULT_COMPRESSION) {
7873 _level = 6;
7874 }
7875 if (_level < 0 || _level > 9 || _strategy < 0 || _strategy > Z_HUFFMAN_ONLY) {
7876 return Z_STREAM_ERROR;
7877 }
7878
7879 if (config_table[level].func != config_table[_level].func && strm.total_in !== 0) {
7880 // Flush the last buffer:
7881 err = strm.deflate(Z_PARTIAL_FLUSH);
7882 }
7883
7884 if (level != _level) {
7885 level = _level;
7886 max_lazy_match = config_table[level].max_lazy;
7887 good_match = config_table[level].good_length;
7888 nice_match = config_table[level].nice_length;
7889 max_chain_length = config_table[level].max_chain;
7890 }
7891 strategy = _strategy;
7892 return err;
7893 };
7894
7895 that.deflateSetDictionary = function(strm, dictionary, dictLength) {
7896 var length = dictLength;
7897 var n, index = 0;
7898
7899 if (!dictionary || status != INIT_STATE)
7900 return Z_STREAM_ERROR;
7901
7902 if (length < MIN_MATCH)
7903 return Z_OK;
7904 if (length > w_size - MIN_LOOKAHEAD) {
7905 length = w_size - MIN_LOOKAHEAD;
7906 index = dictLength - length; // use the tail of the dictionary
7907 }
7908 window.set(dictionary.subarray(index, index + length), 0);
7909
7910 strstart = length;
7911 block_start = length;
7912
7913 // Insert all strings in the hash table (except for the last two bytes).
7914 // s->lookahead stays null, so s->ins_h will be recomputed at the next
7915 // call of fill_window.
7916
7917 ins_h = window[0] & 0xff;
7918 ins_h = (((ins_h) << hash_shift) ^ (window[1] & 0xff)) & hash_mask;
7919
7920 for (n = 0; n <= length - MIN_MATCH; n++) {
7921 ins_h = (((ins_h) << hash_shift) ^ (window[(n) + (MIN_MATCH - 1)] & 0xff)) & hash_mask;
7922 prev[n & w_mask] = head[ins_h];
7923 head[ins_h] = n;
7924 }
7925 return Z_OK;
7926 };
7927
7928 that.deflate = function(_strm, flush) {
7929 var i, header, level_flags, old_flush, bstate;
7930
7931 if (flush > Z_FINISH || flush < 0) {
7932 return Z_STREAM_ERROR;
7933 }
7934
7935 if (!_strm.next_out || (!_strm.next_in && _strm.avail_in !== 0) || (status == FINISH_STATE && flush != Z_FINISH)) {
7936 _strm.msg = z_errmsg[Z_NEED_DICT - (Z_STREAM_ERROR)];
7937 return Z_STREAM_ERROR;
7938 }
7939 if (_strm.avail_out === 0) {
7940 _strm.msg = z_errmsg[Z_NEED_DICT - (Z_BUF_ERROR)];
7941 return Z_BUF_ERROR;
7942 }
7943
7944 strm = _strm; // just in case
7945 old_flush = last_flush;
7946 last_flush = flush;
7947
7948 // Write the zlib header
7949 if (status == INIT_STATE) {
7950 header = (Z_DEFLATED + ((w_bits - 8) << 4)) << 8;
7951 level_flags = ((level - 1) & 0xff) >> 1;
7952
7953 if (level_flags > 3)
7954 level_flags = 3;
7955 header |= (level_flags << 6);
7956 if (strstart !== 0)
7957 header |= PRESET_DICT;
7958 header += 31 - (header % 31);
7959
7960 status = BUSY_STATE;
7961 putShortMSB(header);
7962 }
7963
7964 // Flush as much pending output as possible
7965 if (that.pending !== 0) {
7966 strm.flush_pending();
7967 if (strm.avail_out === 0) {
7968 // console.log(" avail_out==0");
7969 // Since avail_out is 0, deflate will be called again with
7970 // more output space, but possibly with both pending and
7971 // avail_in equal to zero. There won't be anything to do,
7972 // but this is not an error situation so make sure we
7973 // return OK instead of BUF_ERROR at next call of deflate:
7974 last_flush = -1;
7975 return Z_OK;
7976 }
7977
7978 // Make sure there is something to do and avoid duplicate
7979 // consecutive
7980 // flushes. For repeated and useless calls with Z_FINISH, we keep
7981 // returning Z_STREAM_END instead of Z_BUFF_ERROR.
7982 } else if (strm.avail_in === 0 && flush <= old_flush && flush != Z_FINISH) {
7983 strm.msg = z_errmsg[Z_NEED_DICT - (Z_BUF_ERROR)];
7984 return Z_BUF_ERROR;
7985 }
7986
7987 // User must not provide more input after the first FINISH:
7988 if (status == FINISH_STATE && strm.avail_in !== 0) {
7989 _strm.msg = z_errmsg[Z_NEED_DICT - (Z_BUF_ERROR)];
7990 return Z_BUF_ERROR;
7991 }
7992
7993 // Start a new block or continue the current one.
7994 if (strm.avail_in !== 0 || lookahead !== 0 || (flush != Z_NO_FLUSH && status != FINISH_STATE)) {
7995 bstate = -1;
7996 switch (config_table[level].func) {
7997 case STORED:
7998 bstate = deflate_stored(flush);
7999 break;
8000 case FAST:
8001 bstate = deflate_fast(flush);
8002 break;
8003 case SLOW:
8004 bstate = deflate_slow(flush);
8005 break;
8006 default:
8007 }
8008
8009 if (bstate == FinishStarted || bstate == FinishDone) {
8010 status = FINISH_STATE;
8011 }
8012 if (bstate == NeedMore || bstate == FinishStarted) {
8013 if (strm.avail_out === 0) {
8014 last_flush = -1; // avoid BUF_ERROR next call, see above
8015 }
8016 return Z_OK;
8017 // If flush != Z_NO_FLUSH && avail_out === 0, the next call
8018 // of deflate should use the same flush parameter to make sure
8019 // that the flush is complete. So we don't have to output an
8020 // empty block here, this will be done at next call. This also
8021 // ensures that for a very small output buffer, we emit at most
8022 // one empty block.
8023 }
8024
8025 if (bstate == BlockDone) {
8026 if (flush == Z_PARTIAL_FLUSH) {
8027 _tr_align();
8028 } else { // FULL_FLUSH or SYNC_FLUSH
8029 _tr_stored_block(0, 0, false);
8030 // For a full flush, this empty block will be recognized
8031 // as a special marker by inflate_sync().
8032 if (flush == Z_FULL_FLUSH) {
8033 // state.head[s.hash_size-1]=0;
8034 for (i = 0; i < hash_size/*-1*/; i++)
8035 // forget history
8036 head[i] = 0;
8037 }
8038 }
8039 strm.flush_pending();
8040 if (strm.avail_out === 0) {
8041 last_flush = -1; // avoid BUF_ERROR at next call, see above
8042 return Z_OK;
8043 }
8044 }
8045 }
8046
8047 if (flush != Z_FINISH)
8048 return Z_OK;
8049 return Z_STREAM_END;
8050 };
8051 }
8052
8053 // ZStream
8054
8055 function ZStream() {
8056 var that = this;
8057 that.next_in_index = 0;
8058 that.next_out_index = 0;
8059 // that.next_in; // next input byte
8060 that.avail_in = 0; // number of bytes available at next_in
8061 that.total_in = 0; // total nb of input bytes read so far
8062 // that.next_out; // next output byte should be put there
8063 that.avail_out = 0; // remaining free space at next_out
8064 that.total_out = 0; // total nb of bytes output so far
8065 // that.msg;
8066 // that.dstate;
8067 }
8068
8069 ZStream.prototype = {
8070 deflateInit : function(level, bits) {
8071 var that = this;
8072 that.dstate = new Deflate();
8073 if (!bits)
8074 bits = MAX_BITS;
8075 return that.dstate.deflateInit(that, level, bits);
8076 },
8077
8078 deflate : function(flush) {
8079 var that = this;
8080 if (!that.dstate) {
8081 return Z_STREAM_ERROR;
8082 }
8083 return that.dstate.deflate(that, flush);
8084 },
8085
8086 deflateEnd : function() {
8087 var that = this;
8088 if (!that.dstate)
8089 return Z_STREAM_ERROR;
8090 var ret = that.dstate.deflateEnd();
8091 that.dstate = null;
8092 return ret;
8093 },
8094
8095 deflateParams : function(level, strategy) {
8096 var that = this;
8097 if (!that.dstate)
8098 return Z_STREAM_ERROR;
8099 return that.dstate.deflateParams(that, level, strategy);
8100 },
8101
8102 deflateSetDictionary : function(dictionary, dictLength) {
8103 var that = this;
8104 if (!that.dstate)
8105 return Z_STREAM_ERROR;
8106 return that.dstate.deflateSetDictionary(that, dictionary, dictLength);
8107 },
8108
8109 // Read a new buffer from the current input stream, update the
8110 // total number of bytes read. All deflate() input goes through
8111 // this function so some applications may wish to modify it to avoid
8112 // allocating a large strm->next_in buffer and copying from it.
8113 // (See also flush_pending()).
8114 read_buf : function(buf, start, size) {
8115 var that = this;
8116 var len = that.avail_in;
8117 if (len > size)
8118 len = size;
8119 if (len === 0)
8120 return 0;
8121 that.avail_in -= len;
8122 buf.set(that.next_in.subarray(that.next_in_index, that.next_in_index + len), start);
8123 that.next_in_index += len;
8124 that.total_in += len;
8125 return len;
8126 },
8127
8128 // Flush as much pending output as possible. All deflate() output goes
8129 // through this function so some applications may wish to modify it
8130 // to avoid allocating a large strm->next_out buffer and copying into it.
8131 // (See also read_buf()).
8132 flush_pending : function() {
8133 var that = this;
8134 var len = that.dstate.pending;
8135
8136 if (len > that.avail_out)
8137 len = that.avail_out;
8138 if (len === 0)
8139 return;
8140
8141 // if (that.dstate.pending_buf.length <= that.dstate.pending_out || that.next_out.length <= that.next_out_index
8142 // || that.dstate.pending_buf.length < (that.dstate.pending_out + len) || that.next_out.length < (that.next_out_index +
8143 // len)) {
8144 // console.log(that.dstate.pending_buf.length + ", " + that.dstate.pending_out + ", " + that.next_out.length + ", " +
8145 // that.next_out_index + ", " + len);
8146 // console.log("avail_out=" + that.avail_out);
8147 // }
8148
8149 that.next_out.set(that.dstate.pending_buf.subarray(that.dstate.pending_out, that.dstate.pending_out + len), that.next_out_index);
8150
8151 that.next_out_index += len;
8152 that.dstate.pending_out += len;
8153 that.total_out += len;
8154 that.avail_out -= len;
8155 that.dstate.pending -= len;
8156 if (that.dstate.pending === 0) {
8157 that.dstate.pending_out = 0;
8158 }
8159 }
8160 };
8161
8162 // Deflater
8163
8164 return function Deflater(level) {
8165 var that = this;
8166 var z = new ZStream();
8167 var bufsize = 512;
8168 var flush = Z_NO_FLUSH;
8169 var buf = new Uint8Array(bufsize);
8170
8171 if (typeof level == "undefined")
8172 level = Z_DEFAULT_COMPRESSION;
8173 z.deflateInit(level);
8174 z.next_out = buf;
8175
8176 that.append = function(data, onprogress) {
8177 var err, buffers = [], lastIndex = 0, bufferIndex = 0, bufferSize = 0, array;
8178 if (!data.length)
8179 return;
8180 z.next_in_index = 0;
8181 z.next_in = data;
8182 z.avail_in = data.length;
8183 do {
8184 z.next_out_index = 0;
8185 z.avail_out = bufsize;
8186 err = z.deflate(flush);
8187 if (err != Z_OK)
8188 throw "deflating: " + z.msg;
8189 if (z.next_out_index)
8190 if (z.next_out_index == bufsize)
8191 buffers.push(new Uint8Array(buf));
8192 else
8193 buffers.push(new Uint8Array(buf.subarray(0, z.next_out_index)));
8194 bufferSize += z.next_out_index;
8195 if (onprogress && z.next_in_index > 0 && z.next_in_index != lastIndex) {
8196 onprogress(z.next_in_index);
8197 lastIndex = z.next_in_index;
8198 }
8199 } while (z.avail_in > 0 || z.avail_out === 0);
8200 array = new Uint8Array(bufferSize);
8201 buffers.forEach(function(chunk) {
8202 array.set(chunk, bufferIndex);
8203 bufferIndex += chunk.length;
8204 });
8205 return array;
8206 };
8207 that.flush = function() {
8208 var err, buffers = [], bufferIndex = 0, bufferSize = 0, array;
8209 do {
8210 z.next_out_index = 0;
8211 z.avail_out = bufsize;
8212 err = z.deflate(Z_FINISH);
8213 if (err != Z_STREAM_END && err != Z_OK)
8214 throw "deflating: " + z.msg;
8215 if (bufsize - z.avail_out > 0)
8216 buffers.push(new Uint8Array(buf.subarray(0, z.next_out_index)));
8217 bufferSize += z.next_out_index;
8218 } while (z.avail_in > 0 || z.avail_out === 0);
8219 z.deflateEnd();
8220 array = new Uint8Array(bufferSize);
8221 buffers.forEach(function(chunk) {
8222 array.set(chunk, bufferIndex);
8223 bufferIndex += chunk.length;
8224 });
8225 return array;
8226 };
8227 };
8228})(this);
8229// Generated by CoffeeScript 1.4.0
8230
8231/*
8232# PNG.js
8233# Copyright (c) 2011 Devon Govett
8234# MIT LICENSE
8235#
8236# Permission is hereby granted, free of charge, to any person obtaining a copy of this
8237# software and associated documentation files (the "Software"), to deal in the Software
8238# without restriction, including without limitation the rights to use, copy, modify, merge,
8239# publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
8240# to whom the Software is furnished to do so, subject to the following conditions:
8241#
8242# The above copyright notice and this permission notice shall be included in all copies or
8243# substantial portions of the Software.
8244#
8245# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
8246# BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
8247# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
8248# DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
8249# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
8250*/
8251
8252
8253(function(global) {
8254 var PNG;
8255
8256 PNG = (function() {
8257 var APNG_BLEND_OP_OVER, APNG_BLEND_OP_SOURCE, APNG_DISPOSE_OP_BACKGROUND, APNG_DISPOSE_OP_NONE, APNG_DISPOSE_OP_PREVIOUS, makeImage, scratchCanvas, scratchCtx;
8258
8259 PNG.load = function(url, canvas, callback) {
8260 var xhr,
8261 _this = this;
8262 if (typeof canvas === 'function') {
8263 callback = canvas;
8264 }
8265 xhr = new XMLHttpRequest;
8266 xhr.open("GET", url, true);
8267 xhr.responseType = "arraybuffer";
8268 xhr.onload = function() {
8269 var data, png;
8270 data = new Uint8Array(xhr.response || xhr.mozResponseArrayBuffer);
8271 png = new PNG(data);
8272 if (typeof (canvas != null ? canvas.getContext : void 0) === 'function') {
8273 png.render(canvas);
8274 }
8275 return typeof callback === "function" ? callback(png) : void 0;
8276 };
8277 return xhr.send(null);
8278 };
8279
8280 APNG_DISPOSE_OP_NONE = 0;
8281
8282 APNG_DISPOSE_OP_BACKGROUND = 1;
8283
8284 APNG_DISPOSE_OP_PREVIOUS = 2;
8285
8286 APNG_BLEND_OP_SOURCE = 0;
8287
8288 APNG_BLEND_OP_OVER = 1;
8289
8290 function PNG(data) {
8291 var chunkSize, colors, palLen, delayDen, delayNum, frame, i, index, key, section, palShort, text, _i, _j, _ref;
8292 this.data = data;
8293 this.pos = 8;
8294 this.palette = [];
8295 this.imgData = [];
8296 this.transparency = {};
8297 this.animation = null;
8298 this.text = {};
8299 frame = null;
8300 while (true) {
8301 chunkSize = this.readUInt32();
8302 section = ((function() {
8303 var _i, _results;
8304 _results = [];
8305 for (i = _i = 0; _i < 4; i = ++_i) {
8306 _results.push(String.fromCharCode(this.data[this.pos++]));
8307 }
8308 return _results;
8309 }).call(this)).join('');
8310 switch (section) {
8311 case 'IHDR':
8312 this.width = this.readUInt32();
8313 this.height = this.readUInt32();
8314 this.bits = this.data[this.pos++];
8315 this.colorType = this.data[this.pos++];
8316 this.compressionMethod = this.data[this.pos++];
8317 this.filterMethod = this.data[this.pos++];
8318 this.interlaceMethod = this.data[this.pos++];
8319 break;
8320 case 'acTL':
8321 this.animation = {
8322 numFrames: this.readUInt32(),
8323 numPlays: this.readUInt32() || Infinity,
8324 frames: []
8325 };
8326 break;
8327 case 'PLTE':
8328 this.palette = this.read(chunkSize);
8329 break;
8330 case 'fcTL':
8331 if (frame) {
8332 this.animation.frames.push(frame);
8333 }
8334 this.pos += 4;
8335 frame = {
8336 width: this.readUInt32(),
8337 height: this.readUInt32(),
8338 xOffset: this.readUInt32(),
8339 yOffset: this.readUInt32()
8340 };
8341 delayNum = this.readUInt16();
8342 delayDen = this.readUInt16() || 100;
8343 frame.delay = 1000 * delayNum / delayDen;
8344 frame.disposeOp = this.data[this.pos++];
8345 frame.blendOp = this.data[this.pos++];
8346 frame.data = [];
8347 break;
8348 case 'IDAT':
8349 case 'fdAT':
8350 if (section === 'fdAT') {
8351 this.pos += 4;
8352 chunkSize -= 4;
8353 }
8354 data = (frame != null ? frame.data : void 0) || this.imgData;
8355 for (i = _i = 0; 0 <= chunkSize ? _i < chunkSize : _i > chunkSize; i = 0 <= chunkSize ? ++_i : --_i) {
8356 data.push(this.data[this.pos++]);
8357 }
8358 break;
8359 case 'tRNS':
8360 this.transparency = {};
8361 switch (this.colorType) {
8362 case 3:
8363 palLen = this.palette.length/3;
8364 this.transparency.indexed = this.read(chunkSize);
8365 if(this.transparency.indexed.length > palLen)
8366 throw new Error('More transparent colors than palette size');
8367 /*
8368 * According to the PNG spec trns should be increased to the same size as palette if shorter
8369 */
8370 //palShort = 255 - this.transparency.indexed.length;
8371 palShort = palLen - this.transparency.indexed.length;
8372 if (palShort > 0) {
8373 for (i = _j = 0; 0 <= palShort ? _j < palShort : _j > palShort; i = 0 <= palShort ? ++_j : --_j) {
8374 this.transparency.indexed.push(255);
8375 }
8376 }
8377 break;
8378 case 0:
8379 this.transparency.grayscale = this.read(chunkSize)[0];
8380 break;
8381 case 2:
8382 this.transparency.rgb = this.read(chunkSize);
8383 }
8384 break;
8385 case 'tEXt':
8386 text = this.read(chunkSize);
8387 index = text.indexOf(0);
8388 key = String.fromCharCode.apply(String, text.slice(0, index));
8389 this.text[key] = String.fromCharCode.apply(String, text.slice(index + 1));
8390 break;
8391 case 'IEND':
8392 if (frame) {
8393 this.animation.frames.push(frame);
8394 }
8395 this.colors = (function() {
8396 switch (this.colorType) {
8397 case 0:
8398 case 3:
8399 case 4:
8400 return 1;
8401 case 2:
8402 case 6:
8403 return 3;
8404 }
8405 }).call(this);
8406 this.hasAlphaChannel = (_ref = this.colorType) === 4 || _ref === 6;
8407 colors = this.colors + (this.hasAlphaChannel ? 1 : 0);
8408 this.pixelBitlength = this.bits * colors;
8409 this.colorSpace = (function() {
8410 switch (this.colors) {
8411 case 1:
8412 return 'DeviceGray';
8413 case 3:
8414 return 'DeviceRGB';
8415 }
8416 }).call(this);
8417 this.imgData = new Uint8Array(this.imgData);
8418 return;
8419 default:
8420 this.pos += chunkSize;
8421 }
8422 this.pos += 4;
8423 if (this.pos > this.data.length) {
8424 throw new Error("Incomplete or corrupt PNG file");
8425 }
8426 }
8427 return;
8428 }
8429
8430 PNG.prototype.read = function(bytes) {
8431 var i, _i, _results;
8432 _results = [];
8433 for (i = _i = 0; 0 <= bytes ? _i < bytes : _i > bytes; i = 0 <= bytes ? ++_i : --_i) {
8434 _results.push(this.data[this.pos++]);
8435 }
8436 return _results;
8437 };
8438
8439 PNG.prototype.readUInt32 = function() {
8440 var b1, b2, b3, b4;
8441 b1 = this.data[this.pos++] << 24;
8442 b2 = this.data[this.pos++] << 16;
8443 b3 = this.data[this.pos++] << 8;
8444 b4 = this.data[this.pos++];
8445 return b1 | b2 | b3 | b4;
8446 };
8447
8448 PNG.prototype.readUInt16 = function() {
8449 var b1, b2;
8450 b1 = this.data[this.pos++] << 8;
8451 b2 = this.data[this.pos++];
8452 return b1 | b2;
8453 };
8454
8455 PNG.prototype.decodePixels = function(data) {
8456 var abyte, c, col, i, left, length, p, pa, paeth, pb, pc, pixelBytes, pixels, pos, row, scanlineLength, upper, upperLeft, _i, _j, _k, _l, _m;
8457 if (data == null) {
8458 data = this.imgData;
8459 }
8460 if (data.length === 0) {
8461 return new Uint8Array(0);
8462 }
8463 data = new FlateStream(data);
8464 data = data.getBytes();
8465 pixelBytes = this.pixelBitlength / 8;
8466 scanlineLength = pixelBytes * this.width;
8467 pixels = new Uint8Array(scanlineLength * this.height);
8468 length = data.length;
8469 row = 0;
8470 pos = 0;
8471 c = 0;
8472 while (pos < length) {
8473 switch (data[pos++]) {
8474 case 0:
8475 for (i = _i = 0; _i < scanlineLength; i = _i += 1) {
8476 pixels[c++] = data[pos++];
8477 }
8478 break;
8479 case 1:
8480 for (i = _j = 0; _j < scanlineLength; i = _j += 1) {
8481 abyte = data[pos++];
8482 left = i < pixelBytes ? 0 : pixels[c - pixelBytes];
8483 pixels[c++] = (abyte + left) % 256;
8484 }
8485 break;
8486 case 2:
8487 for (i = _k = 0; _k < scanlineLength; i = _k += 1) {
8488 abyte = data[pos++];
8489 col = (i - (i % pixelBytes)) / pixelBytes;
8490 upper = row && pixels[(row - 1) * scanlineLength + col * pixelBytes + (i % pixelBytes)];
8491 pixels[c++] = (upper + abyte) % 256;
8492 }
8493 break;
8494 case 3:
8495 for (i = _l = 0; _l < scanlineLength; i = _l += 1) {
8496 abyte = data[pos++];
8497 col = (i - (i % pixelBytes)) / pixelBytes;
8498 left = i < pixelBytes ? 0 : pixels[c - pixelBytes];
8499 upper = row && pixels[(row - 1) * scanlineLength + col * pixelBytes + (i % pixelBytes)];
8500 pixels[c++] = (abyte + Math.floor((left + upper) / 2)) % 256;
8501 }
8502 break;
8503 case 4:
8504 for (i = _m = 0; _m < scanlineLength; i = _m += 1) {
8505 abyte = data[pos++];
8506 col = (i - (i % pixelBytes)) / pixelBytes;
8507 left = i < pixelBytes ? 0 : pixels[c - pixelBytes];
8508 if (row === 0) {
8509 upper = upperLeft = 0;
8510 } else {
8511 upper = pixels[(row - 1) * scanlineLength + col * pixelBytes + (i % pixelBytes)];
8512 upperLeft = col && pixels[(row - 1) * scanlineLength + (col - 1) * pixelBytes + (i % pixelBytes)];
8513 }
8514 p = left + upper - upperLeft;
8515 pa = Math.abs(p - left);
8516 pb = Math.abs(p - upper);
8517 pc = Math.abs(p - upperLeft);
8518 if (pa <= pb && pa <= pc) {
8519 paeth = left;
8520 } else if (pb <= pc) {
8521 paeth = upper;
8522 } else {
8523 paeth = upperLeft;
8524 }
8525 pixels[c++] = (abyte + paeth) % 256;
8526 }
8527 break;
8528 default:
8529 throw new Error("Invalid filter algorithm: " + data[pos - 1]);
8530 }
8531 row++;
8532 }
8533 return pixels;
8534 };
8535
8536 PNG.prototype.decodePalette = function() {
8537 var c, i, length, palette, pos, ret, transparency, _i, _ref, _ref1;
8538 palette = this.palette;
8539 transparency = this.transparency.indexed || [];
8540 ret = new Uint8Array((transparency.length || 0) + palette.length);
8541 pos = 0;
8542 length = palette.length;
8543 c = 0;
8544 for (i = _i = 0, _ref = palette.length; _i < _ref; i = _i += 3) {
8545 ret[pos++] = palette[i];
8546 ret[pos++] = palette[i + 1];
8547 ret[pos++] = palette[i + 2];
8548 ret[pos++] = (_ref1 = transparency[c++]) != null ? _ref1 : 255;
8549 }
8550 return ret;
8551 };
8552
8553 PNG.prototype.copyToImageData = function(imageData, pixels) {
8554 var alpha, colors, data, i, input, j, k, length, palette, v, _ref;
8555 colors = this.colors;
8556 palette = null;
8557 alpha = this.hasAlphaChannel;
8558 if (this.palette.length) {
8559 palette = (_ref = this._decodedPalette) != null ? _ref : this._decodedPalette = this.decodePalette();
8560 colors = 4;
8561 alpha = true;
8562 }
8563 data = imageData.data || imageData;
8564 length = data.length;
8565 input = palette || pixels;
8566 i = j = 0;
8567 if (colors === 1) {
8568 while (i < length) {
8569 k = palette ? pixels[i / 4] * 4 : j;
8570 v = input[k++];
8571 data[i++] = v;
8572 data[i++] = v;
8573 data[i++] = v;
8574 data[i++] = alpha ? input[k++] : 255;
8575 j = k;
8576 }
8577 } else {
8578 while (i < length) {
8579 k = palette ? pixels[i / 4] * 4 : j;
8580 data[i++] = input[k++];
8581 data[i++] = input[k++];
8582 data[i++] = input[k++];
8583 data[i++] = alpha ? input[k++] : 255;
8584 j = k;
8585 }
8586 }
8587 };
8588
8589 PNG.prototype.decode = function() {
8590 var ret;
8591 ret = new Uint8Array(this.width * this.height * 4);
8592 this.copyToImageData(ret, this.decodePixels());
8593 return ret;
8594 };
8595
8596 try {
8597 scratchCanvas = global.document.createElement('canvas');
8598 scratchCtx = scratchCanvas.getContext('2d');
8599 } catch(e) {
8600 return -1;
8601 }
8602
8603 makeImage = function(imageData) {
8604 var img;
8605 scratchCtx.width = imageData.width;
8606 scratchCtx.height = imageData.height;
8607 scratchCtx.clearRect(0, 0, imageData.width, imageData.height);
8608 scratchCtx.putImageData(imageData, 0, 0);
8609 img = new Image;
8610 img.src = scratchCanvas.toDataURL();
8611 return img;
8612 };
8613
8614 PNG.prototype.decodeFrames = function(ctx) {
8615 var frame, i, imageData, pixels, _i, _len, _ref, _results;
8616 if (!this.animation) {
8617 return;
8618 }
8619 _ref = this.animation.frames;
8620 _results = [];
8621 for (i = _i = 0, _len = _ref.length; _i < _len; i = ++_i) {
8622 frame = _ref[i];
8623 imageData = ctx.createImageData(frame.width, frame.height);
8624 pixels = this.decodePixels(new Uint8Array(frame.data));
8625 this.copyToImageData(imageData, pixels);
8626 frame.imageData = imageData;
8627 _results.push(frame.image = makeImage(imageData));
8628 }
8629 return _results;
8630 };
8631
8632 PNG.prototype.renderFrame = function(ctx, number) {
8633 var frame, frames, prev;
8634 frames = this.animation.frames;
8635 frame = frames[number];
8636 prev = frames[number - 1];
8637 if (number === 0) {
8638 ctx.clearRect(0, 0, this.width, this.height);
8639 }
8640 if ((prev != null ? prev.disposeOp : void 0) === APNG_DISPOSE_OP_BACKGROUND) {
8641 ctx.clearRect(prev.xOffset, prev.yOffset, prev.width, prev.height);
8642 } else if ((prev != null ? prev.disposeOp : void 0) === APNG_DISPOSE_OP_PREVIOUS) {
8643 ctx.putImageData(prev.imageData, prev.xOffset, prev.yOffset);
8644 }
8645 if (frame.blendOp === APNG_BLEND_OP_SOURCE) {
8646 ctx.clearRect(frame.xOffset, frame.yOffset, frame.width, frame.height);
8647 }
8648 return ctx.drawImage(frame.image, frame.xOffset, frame.yOffset);
8649 };
8650
8651 PNG.prototype.animate = function(ctx) {
8652 var doFrame, frameNumber, frames, numFrames, numPlays, _ref,
8653 _this = this;
8654 frameNumber = 0;
8655 _ref = this.animation, numFrames = _ref.numFrames, frames = _ref.frames, numPlays = _ref.numPlays;
8656 return (doFrame = function() {
8657 var f, frame;
8658 f = frameNumber++ % numFrames;
8659 frame = frames[f];
8660 _this.renderFrame(ctx, f);
8661 if (numFrames > 1 && frameNumber / numFrames < numPlays) {
8662 return _this.animation._timeout = setTimeout(doFrame, frame.delay);
8663 }
8664 })();
8665 };
8666
8667 PNG.prototype.stopAnimation = function() {
8668 var _ref;
8669 return clearTimeout((_ref = this.animation) != null ? _ref._timeout : void 0);
8670 };
8671
8672 PNG.prototype.render = function(canvas) {
8673 var ctx, data;
8674 if (canvas._png) {
8675 canvas._png.stopAnimation();
8676 }
8677 canvas._png = this;
8678 canvas.width = this.width;
8679 canvas.height = this.height;
8680 ctx = canvas.getContext("2d");
8681 if (this.animation) {
8682 this.decodeFrames(ctx);
8683 return this.animate(ctx);
8684 } else {
8685 data = ctx.createImageData(this.width, this.height);
8686 this.copyToImageData(data, this.decodePixels());
8687 return ctx.putImageData(data, 0, 0);
8688 }
8689 };
8690
8691 return PNG;
8692
8693 })();
8694
8695 global.PNG = PNG;
8696
8697})(typeof window !== "undefined" && window || this);
8698/*
8699 * Extracted from pdf.js
8700 * https://github.com/andreasgal/pdf.js
8701 *
8702 * Copyright (c) 2011 Mozilla Foundation
8703 *
8704 * Contributors: Andreas Gal <gal@mozilla.com>
8705 * Chris G Jones <cjones@mozilla.com>
8706 * Shaon Barman <shaon.barman@gmail.com>
8707 * Vivien Nicolas <21@vingtetun.org>
8708 * Justin D'Arcangelo <justindarc@gmail.com>
8709 * Yury Delendik
8710 *
8711 * Permission is hereby granted, free of charge, to any person obtaining a
8712 * copy of this software and associated documentation files (the "Software"),
8713 * to deal in the Software without restriction, including without limitation
8714 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8715 * and/or sell copies of the Software, and to permit persons to whom the
8716 * Software is furnished to do so, subject to the following conditions:
8717 *
8718 * The above copyright notice and this permission notice shall be included in
8719 * all copies or substantial portions of the Software.
8720 *
8721 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
8722 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
8723 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
8724 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
8725 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
8726 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
8727 * DEALINGS IN THE SOFTWARE.
8728 */
8729
8730var DecodeStream = (function() {
8731 function constructor() {
8732 this.pos = 0;
8733 this.bufferLength = 0;
8734 this.eof = false;
8735 this.buffer = null;
8736 }
8737
8738 constructor.prototype = {
8739 ensureBuffer: function decodestream_ensureBuffer(requested) {
8740 var buffer = this.buffer;
8741 var current = buffer ? buffer.byteLength : 0;
8742 if (requested < current)
8743 return buffer;
8744 var size = 512;
8745 while (size < requested)
8746 size <<= 1;
8747 var buffer2 = new Uint8Array(size);
8748 for (var i = 0; i < current; ++i)
8749 buffer2[i] = buffer[i];
8750 return this.buffer = buffer2;
8751 },
8752 getByte: function decodestream_getByte() {
8753 var pos = this.pos;
8754 while (this.bufferLength <= pos) {
8755 if (this.eof)
8756 return null;
8757 this.readBlock();
8758 }
8759 return this.buffer[this.pos++];
8760 },
8761 getBytes: function decodestream_getBytes(length) {
8762 var pos = this.pos;
8763
8764 if (length) {
8765 this.ensureBuffer(pos + length);
8766 var end = pos + length;
8767
8768 while (!this.eof && this.bufferLength < end)
8769 this.readBlock();
8770
8771 var bufEnd = this.bufferLength;
8772 if (end > bufEnd)
8773 end = bufEnd;
8774 } else {
8775 while (!this.eof)
8776 this.readBlock();
8777
8778 var end = this.bufferLength;
8779 }
8780
8781 this.pos = end;
8782 return this.buffer.subarray(pos, end);
8783 },
8784 lookChar: function decodestream_lookChar() {
8785 var pos = this.pos;
8786 while (this.bufferLength <= pos) {
8787 if (this.eof)
8788 return null;
8789 this.readBlock();
8790 }
8791 return String.fromCharCode(this.buffer[this.pos]);
8792 },
8793 getChar: function decodestream_getChar() {
8794 var pos = this.pos;
8795 while (this.bufferLength <= pos) {
8796 if (this.eof)
8797 return null;
8798 this.readBlock();
8799 }
8800 return String.fromCharCode(this.buffer[this.pos++]);
8801 },
8802 makeSubStream: function decodestream_makeSubstream(start, length, dict) {
8803 var end = start + length;
8804 while (this.bufferLength <= end && !this.eof)
8805 this.readBlock();
8806 return new Stream(this.buffer, start, length, dict);
8807 },
8808 skip: function decodestream_skip(n) {
8809 if (!n)
8810 n = 1;
8811 this.pos += n;
8812 },
8813 reset: function decodestream_reset() {
8814 this.pos = 0;
8815 }
8816 };
8817
8818 return constructor;
8819})();
8820
8821var FlateStream = (function() {
8822 if (typeof Uint32Array === 'undefined') {
8823 return undefined;
8824 }
8825 var codeLenCodeMap = new Uint32Array([
8826 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15
8827 ]);
8828
8829 var lengthDecode = new Uint32Array([
8830 0x00003, 0x00004, 0x00005, 0x00006, 0x00007, 0x00008, 0x00009, 0x0000a,
8831 0x1000b, 0x1000d, 0x1000f, 0x10011, 0x20013, 0x20017, 0x2001b, 0x2001f,
8832 0x30023, 0x3002b, 0x30033, 0x3003b, 0x40043, 0x40053, 0x40063, 0x40073,
8833 0x50083, 0x500a3, 0x500c3, 0x500e3, 0x00102, 0x00102, 0x00102
8834 ]);
8835
8836 var distDecode = new Uint32Array([
8837 0x00001, 0x00002, 0x00003, 0x00004, 0x10005, 0x10007, 0x20009, 0x2000d,
8838 0x30011, 0x30019, 0x40021, 0x40031, 0x50041, 0x50061, 0x60081, 0x600c1,
8839 0x70101, 0x70181, 0x80201, 0x80301, 0x90401, 0x90601, 0xa0801, 0xa0c01,
8840 0xb1001, 0xb1801, 0xc2001, 0xc3001, 0xd4001, 0xd6001
8841 ]);
8842
8843 var fixedLitCodeTab = [new Uint32Array([
8844 0x70100, 0x80050, 0x80010, 0x80118, 0x70110, 0x80070, 0x80030, 0x900c0,
8845 0x70108, 0x80060, 0x80020, 0x900a0, 0x80000, 0x80080, 0x80040, 0x900e0,
8846 0x70104, 0x80058, 0x80018, 0x90090, 0x70114, 0x80078, 0x80038, 0x900d0,
8847 0x7010c, 0x80068, 0x80028, 0x900b0, 0x80008, 0x80088, 0x80048, 0x900f0,
8848 0x70102, 0x80054, 0x80014, 0x8011c, 0x70112, 0x80074, 0x80034, 0x900c8,
8849 0x7010a, 0x80064, 0x80024, 0x900a8, 0x80004, 0x80084, 0x80044, 0x900e8,
8850 0x70106, 0x8005c, 0x8001c, 0x90098, 0x70116, 0x8007c, 0x8003c, 0x900d8,
8851 0x7010e, 0x8006c, 0x8002c, 0x900b8, 0x8000c, 0x8008c, 0x8004c, 0x900f8,
8852 0x70101, 0x80052, 0x80012, 0x8011a, 0x70111, 0x80072, 0x80032, 0x900c4,
8853 0x70109, 0x80062, 0x80022, 0x900a4, 0x80002, 0x80082, 0x80042, 0x900e4,
8854 0x70105, 0x8005a, 0x8001a, 0x90094, 0x70115, 0x8007a, 0x8003a, 0x900d4,
8855 0x7010d, 0x8006a, 0x8002a, 0x900b4, 0x8000a, 0x8008a, 0x8004a, 0x900f4,
8856 0x70103, 0x80056, 0x80016, 0x8011e, 0x70113, 0x80076, 0x80036, 0x900cc,
8857 0x7010b, 0x80066, 0x80026, 0x900ac, 0x80006, 0x80086, 0x80046, 0x900ec,
8858 0x70107, 0x8005e, 0x8001e, 0x9009c, 0x70117, 0x8007e, 0x8003e, 0x900dc,
8859 0x7010f, 0x8006e, 0x8002e, 0x900bc, 0x8000e, 0x8008e, 0x8004e, 0x900fc,
8860 0x70100, 0x80051, 0x80011, 0x80119, 0x70110, 0x80071, 0x80031, 0x900c2,
8861 0x70108, 0x80061, 0x80021, 0x900a2, 0x80001, 0x80081, 0x80041, 0x900e2,
8862 0x70104, 0x80059, 0x80019, 0x90092, 0x70114, 0x80079, 0x80039, 0x900d2,
8863 0x7010c, 0x80069, 0x80029, 0x900b2, 0x80009, 0x80089, 0x80049, 0x900f2,
8864 0x70102, 0x80055, 0x80015, 0x8011d, 0x70112, 0x80075, 0x80035, 0x900ca,
8865 0x7010a, 0x80065, 0x80025, 0x900aa, 0x80005, 0x80085, 0x80045, 0x900ea,
8866 0x70106, 0x8005d, 0x8001d, 0x9009a, 0x70116, 0x8007d, 0x8003d, 0x900da,
8867 0x7010e, 0x8006d, 0x8002d, 0x900ba, 0x8000d, 0x8008d, 0x8004d, 0x900fa,
8868 0x70101, 0x80053, 0x80013, 0x8011b, 0x70111, 0x80073, 0x80033, 0x900c6,
8869 0x70109, 0x80063, 0x80023, 0x900a6, 0x80003, 0x80083, 0x80043, 0x900e6,
8870 0x70105, 0x8005b, 0x8001b, 0x90096, 0x70115, 0x8007b, 0x8003b, 0x900d6,
8871 0x7010d, 0x8006b, 0x8002b, 0x900b6, 0x8000b, 0x8008b, 0x8004b, 0x900f6,
8872 0x70103, 0x80057, 0x80017, 0x8011f, 0x70113, 0x80077, 0x80037, 0x900ce,
8873 0x7010b, 0x80067, 0x80027, 0x900ae, 0x80007, 0x80087, 0x80047, 0x900ee,
8874 0x70107, 0x8005f, 0x8001f, 0x9009e, 0x70117, 0x8007f, 0x8003f, 0x900de,
8875 0x7010f, 0x8006f, 0x8002f, 0x900be, 0x8000f, 0x8008f, 0x8004f, 0x900fe,
8876 0x70100, 0x80050, 0x80010, 0x80118, 0x70110, 0x80070, 0x80030, 0x900c1,
8877 0x70108, 0x80060, 0x80020, 0x900a1, 0x80000, 0x80080, 0x80040, 0x900e1,
8878 0x70104, 0x80058, 0x80018, 0x90091, 0x70114, 0x80078, 0x80038, 0x900d1,
8879 0x7010c, 0x80068, 0x80028, 0x900b1, 0x80008, 0x80088, 0x80048, 0x900f1,
8880 0x70102, 0x80054, 0x80014, 0x8011c, 0x70112, 0x80074, 0x80034, 0x900c9,
8881 0x7010a, 0x80064, 0x80024, 0x900a9, 0x80004, 0x80084, 0x80044, 0x900e9,
8882 0x70106, 0x8005c, 0x8001c, 0x90099, 0x70116, 0x8007c, 0x8003c, 0x900d9,
8883 0x7010e, 0x8006c, 0x8002c, 0x900b9, 0x8000c, 0x8008c, 0x8004c, 0x900f9,
8884 0x70101, 0x80052, 0x80012, 0x8011a, 0x70111, 0x80072, 0x80032, 0x900c5,
8885 0x70109, 0x80062, 0x80022, 0x900a5, 0x80002, 0x80082, 0x80042, 0x900e5,
8886 0x70105, 0x8005a, 0x8001a, 0x90095, 0x70115, 0x8007a, 0x8003a, 0x900d5,
8887 0x7010d, 0x8006a, 0x8002a, 0x900b5, 0x8000a, 0x8008a, 0x8004a, 0x900f5,
8888 0x70103, 0x80056, 0x80016, 0x8011e, 0x70113, 0x80076, 0x80036, 0x900cd,
8889 0x7010b, 0x80066, 0x80026, 0x900ad, 0x80006, 0x80086, 0x80046, 0x900ed,
8890 0x70107, 0x8005e, 0x8001e, 0x9009d, 0x70117, 0x8007e, 0x8003e, 0x900dd,
8891 0x7010f, 0x8006e, 0x8002e, 0x900bd, 0x8000e, 0x8008e, 0x8004e, 0x900fd,
8892 0x70100, 0x80051, 0x80011, 0x80119, 0x70110, 0x80071, 0x80031, 0x900c3,
8893 0x70108, 0x80061, 0x80021, 0x900a3, 0x80001, 0x80081, 0x80041, 0x900e3,
8894 0x70104, 0x80059, 0x80019, 0x90093, 0x70114, 0x80079, 0x80039, 0x900d3,
8895 0x7010c, 0x80069, 0x80029, 0x900b3, 0x80009, 0x80089, 0x80049, 0x900f3,
8896 0x70102, 0x80055, 0x80015, 0x8011d, 0x70112, 0x80075, 0x80035, 0x900cb,
8897 0x7010a, 0x80065, 0x80025, 0x900ab, 0x80005, 0x80085, 0x80045, 0x900eb,
8898 0x70106, 0x8005d, 0x8001d, 0x9009b, 0x70116, 0x8007d, 0x8003d, 0x900db,
8899 0x7010e, 0x8006d, 0x8002d, 0x900bb, 0x8000d, 0x8008d, 0x8004d, 0x900fb,
8900 0x70101, 0x80053, 0x80013, 0x8011b, 0x70111, 0x80073, 0x80033, 0x900c7,
8901 0x70109, 0x80063, 0x80023, 0x900a7, 0x80003, 0x80083, 0x80043, 0x900e7,
8902 0x70105, 0x8005b, 0x8001b, 0x90097, 0x70115, 0x8007b, 0x8003b, 0x900d7,
8903 0x7010d, 0x8006b, 0x8002b, 0x900b7, 0x8000b, 0x8008b, 0x8004b, 0x900f7,
8904 0x70103, 0x80057, 0x80017, 0x8011f, 0x70113, 0x80077, 0x80037, 0x900cf,
8905 0x7010b, 0x80067, 0x80027, 0x900af, 0x80007, 0x80087, 0x80047, 0x900ef,
8906 0x70107, 0x8005f, 0x8001f, 0x9009f, 0x70117, 0x8007f, 0x8003f, 0x900df,
8907 0x7010f, 0x8006f, 0x8002f, 0x900bf, 0x8000f, 0x8008f, 0x8004f, 0x900ff
8908 ]), 9];
8909
8910 var fixedDistCodeTab = [new Uint32Array([
8911 0x50000, 0x50010, 0x50008, 0x50018, 0x50004, 0x50014, 0x5000c, 0x5001c,
8912 0x50002, 0x50012, 0x5000a, 0x5001a, 0x50006, 0x50016, 0x5000e, 0x00000,
8913 0x50001, 0x50011, 0x50009, 0x50019, 0x50005, 0x50015, 0x5000d, 0x5001d,
8914 0x50003, 0x50013, 0x5000b, 0x5001b, 0x50007, 0x50017, 0x5000f, 0x00000
8915 ]), 5];
8916
8917 function error(e) {
8918 throw new Error(e)
8919 }
8920
8921 function constructor(bytes) {
8922 //var bytes = stream.getBytes();
8923 var bytesPos = 0;
8924
8925 var cmf = bytes[bytesPos++];
8926 var flg = bytes[bytesPos++];
8927 if (cmf == -1 || flg == -1)
8928 error('Invalid header in flate stream');
8929 if ((cmf & 0x0f) != 0x08)
8930 error('Unknown compression method in flate stream');
8931 if ((((cmf << 8) + flg) % 31) != 0)
8932 error('Bad FCHECK in flate stream');
8933 if (flg & 0x20)
8934 error('FDICT bit set in flate stream');
8935
8936 this.bytes = bytes;
8937 this.bytesPos = bytesPos;
8938
8939 this.codeSize = 0;
8940 this.codeBuf = 0;
8941
8942 DecodeStream.call(this);
8943 }
8944
8945 constructor.prototype = Object.create(DecodeStream.prototype);
8946
8947 constructor.prototype.getBits = function(bits) {
8948 var codeSize = this.codeSize;
8949 var codeBuf = this.codeBuf;
8950 var bytes = this.bytes;
8951 var bytesPos = this.bytesPos;
8952
8953 var b;
8954 while (codeSize < bits) {
8955 if (typeof (b = bytes[bytesPos++]) == 'undefined')
8956 error('Bad encoding in flate stream');
8957 codeBuf |= b << codeSize;
8958 codeSize += 8;
8959 }
8960 b = codeBuf & ((1 << bits) - 1);
8961 this.codeBuf = codeBuf >> bits;
8962 this.codeSize = codeSize -= bits;
8963 this.bytesPos = bytesPos;
8964 return b;
8965 };
8966
8967 constructor.prototype.getCode = function(table) {
8968 var codes = table[0];
8969 var maxLen = table[1];
8970 var codeSize = this.codeSize;
8971 var codeBuf = this.codeBuf;
8972 var bytes = this.bytes;
8973 var bytesPos = this.bytesPos;
8974
8975 while (codeSize < maxLen) {
8976 var b;
8977 if (typeof (b = bytes[bytesPos++]) == 'undefined')
8978 error('Bad encoding in flate stream');
8979 codeBuf |= (b << codeSize);
8980 codeSize += 8;
8981 }
8982 var code = codes[codeBuf & ((1 << maxLen) - 1)];
8983 var codeLen = code >> 16;
8984 var codeVal = code & 0xffff;
8985 if (codeSize == 0 || codeSize < codeLen || codeLen == 0)
8986 error('Bad encoding in flate stream');
8987 this.codeBuf = (codeBuf >> codeLen);
8988 this.codeSize = (codeSize - codeLen);
8989 this.bytesPos = bytesPos;
8990 return codeVal;
8991 };
8992
8993 constructor.prototype.generateHuffmanTable = function(lengths) {
8994 var n = lengths.length;
8995
8996 // find max code length
8997 var maxLen = 0;
8998 for (var i = 0; i < n; ++i) {
8999 if (lengths[i] > maxLen)
9000 maxLen = lengths[i];
9001 }
9002
9003 // build the table
9004 var size = 1 << maxLen;
9005 var codes = new Uint32Array(size);
9006 for (var len = 1, code = 0, skip = 2;
9007 len <= maxLen;
9008 ++len, code <<= 1, skip <<= 1) {
9009 for (var val = 0; val < n; ++val) {
9010 if (lengths[val] == len) {
9011 // bit-reverse the code
9012 var code2 = 0;
9013 var t = code;
9014 for (var i = 0; i < len; ++i) {
9015 code2 = (code2 << 1) | (t & 1);
9016 t >>= 1;
9017 }
9018
9019 // fill the table entries
9020 for (var i = code2; i < size; i += skip)
9021 codes[i] = (len << 16) | val;
9022
9023 ++code;
9024 }
9025 }
9026 }
9027
9028 return [codes, maxLen];
9029 };
9030
9031 constructor.prototype.readBlock = function() {
9032 function repeat(stream, array, len, offset, what) {
9033 var repeat = stream.getBits(len) + offset;
9034 while (repeat-- > 0)
9035 array[i++] = what;
9036 }
9037
9038 // read block header
9039 var hdr = this.getBits(3);
9040 if (hdr & 1)
9041 this.eof = true;
9042 hdr >>= 1;
9043
9044 if (hdr == 0) { // uncompressed block
9045 var bytes = this.bytes;
9046 var bytesPos = this.bytesPos;
9047 var b;
9048
9049 if (typeof (b = bytes[bytesPos++]) == 'undefined')
9050 error('Bad block header in flate stream');
9051 var blockLen = b;
9052 if (typeof (b = bytes[bytesPos++]) == 'undefined')
9053 error('Bad block header in flate stream');
9054 blockLen |= (b << 8);
9055 if (typeof (b = bytes[bytesPos++]) == 'undefined')
9056 error('Bad block header in flate stream');
9057 var check = b;
9058 if (typeof (b = bytes[bytesPos++]) == 'undefined')
9059 error('Bad block header in flate stream');
9060 check |= (b << 8);
9061 if (check != (~blockLen & 0xffff))
9062 error('Bad uncompressed block length in flate stream');
9063
9064 this.codeBuf = 0;
9065 this.codeSize = 0;
9066
9067 var bufferLength = this.bufferLength;
9068 var buffer = this.ensureBuffer(bufferLength + blockLen);
9069 var end = bufferLength + blockLen;
9070 this.bufferLength = end;
9071 for (var n = bufferLength; n < end; ++n) {
9072 if (typeof (b = bytes[bytesPos++]) == 'undefined') {
9073 this.eof = true;
9074 break;
9075 }
9076 buffer[n] = b;
9077 }
9078 this.bytesPos = bytesPos;
9079 return;
9080 }
9081
9082 var litCodeTable;
9083 var distCodeTable;
9084 if (hdr == 1) { // compressed block, fixed codes
9085 litCodeTable = fixedLitCodeTab;
9086 distCodeTable = fixedDistCodeTab;
9087 } else if (hdr == 2) { // compressed block, dynamic codes
9088 var numLitCodes = this.getBits(5) + 257;
9089 var numDistCodes = this.getBits(5) + 1;
9090 var numCodeLenCodes = this.getBits(4) + 4;
9091
9092 // build the code lengths code table
9093 var codeLenCodeLengths = Array(codeLenCodeMap.length);
9094 var i = 0;
9095 while (i < numCodeLenCodes)
9096 codeLenCodeLengths[codeLenCodeMap[i++]] = this.getBits(3);
9097 var codeLenCodeTab = this.generateHuffmanTable(codeLenCodeLengths);
9098
9099 // build the literal and distance code tables
9100 var len = 0;
9101 var i = 0;
9102 var codes = numLitCodes + numDistCodes;
9103 var codeLengths = new Array(codes);
9104 while (i < codes) {
9105 var code = this.getCode(codeLenCodeTab);
9106 if (code == 16) {
9107 repeat(this, codeLengths, 2, 3, len);
9108 } else if (code == 17) {
9109 repeat(this, codeLengths, 3, 3, len = 0);
9110 } else if (code == 18) {
9111 repeat(this, codeLengths, 7, 11, len = 0);
9112 } else {
9113 codeLengths[i++] = len = code;
9114 }
9115 }
9116
9117 litCodeTable =
9118 this.generateHuffmanTable(codeLengths.slice(0, numLitCodes));
9119 distCodeTable =
9120 this.generateHuffmanTable(codeLengths.slice(numLitCodes, codes));
9121 } else {
9122 error('Unknown block type in flate stream');
9123 }
9124
9125 var buffer = this.buffer;
9126 var limit = buffer ? buffer.length : 0;
9127 var pos = this.bufferLength;
9128 while (true) {
9129 var code1 = this.getCode(litCodeTable);
9130 if (code1 < 256) {
9131 if (pos + 1 >= limit) {
9132 buffer = this.ensureBuffer(pos + 1);
9133 limit = buffer.length;
9134 }
9135 buffer[pos++] = code1;
9136 continue;
9137 }
9138 if (code1 == 256) {
9139 this.bufferLength = pos;
9140 return;
9141 }
9142 code1 -= 257;
9143 code1 = lengthDecode[code1];
9144 var code2 = code1 >> 16;
9145 if (code2 > 0)
9146 code2 = this.getBits(code2);
9147 var len = (code1 & 0xffff) + code2;
9148 code1 = this.getCode(distCodeTable);
9149 code1 = distDecode[code1];
9150 code2 = code1 >> 16;
9151 if (code2 > 0)
9152 code2 = this.getBits(code2);
9153 var dist = (code1 & 0xffff) + code2;
9154 if (pos + len >= limit) {
9155 buffer = this.ensureBuffer(pos + len);
9156 limit = buffer.length;
9157 }
9158 for (var k = 0; k < len; ++k, ++pos)
9159 buffer[pos] = buffer[pos - dist];
9160 }
9161 };
9162
9163 return constructor;
9164})();/**
9165 * JavaScript Polyfill functions for jsPDF
9166 * Collected from public resources by
9167 * https://github.com/diegocr
9168 */
9169
9170(function (global) {
9171 var b64 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
9172
9173 if (typeof global.btoa === 'undefined') {
9174 global.btoa = function(data) {
9175 // discuss at: http://phpjs.org/functions/base64_encode/
9176 // original by: Tyler Akins (http://rumkin.com)
9177 // improved by: Bayron Guevara
9178 // improved by: Thunder.m
9179 // improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
9180 // improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
9181 // improved by: Rafal Kukawski (http://kukawski.pl)
9182 // bugfixed by: Pellentesque Malesuada
9183 // example 1: base64_encode('Kevin van Zonneveld');
9184 // returns 1: 'S2V2aW4gdmFuIFpvbm5ldmVsZA=='
9185
9186 var o1,o2,o3,h1,h2,h3,h4,bits,i = 0,ac = 0,enc = '',tmp_arr = [];
9187
9188 if (!data) {
9189 return data;
9190 }
9191
9192 do { // pack three octets into four hexets
9193 o1 = data.charCodeAt(i++);
9194 o2 = data.charCodeAt(i++);
9195 o3 = data.charCodeAt(i++);
9196
9197 bits = o1 << 16 | o2 << 8 | o3;
9198
9199 h1 = bits >> 18 & 0x3f;
9200 h2 = bits >> 12 & 0x3f;
9201 h3 = bits >> 6 & 0x3f;
9202 h4 = bits & 0x3f;
9203
9204 // use hexets to index into b64, and append result to encoded string
9205 tmp_arr[ac++] = b64.charAt(h1) + b64.charAt(h2) + b64.charAt(h3) + b64.charAt(h4);
9206 } while (i < data.length);
9207
9208 enc = tmp_arr.join('');
9209
9210 var r = data.length % 3;
9211
9212 return (r ? enc.slice(0, r - 3) : enc) + '==='.slice(r || 3);
9213 };
9214 }
9215
9216 if (typeof global.atob === 'undefined') {
9217 global.atob = function(data) {
9218 // discuss at: http://phpjs.org/functions/base64_decode/
9219 // original by: Tyler Akins (http://rumkin.com)
9220 // improved by: Thunder.m
9221 // improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
9222 // improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
9223 // input by: Aman Gupta
9224 // input by: Brett Zamir (http://brett-zamir.me)
9225 // bugfixed by: Onno Marsman
9226 // bugfixed by: Pellentesque Malesuada
9227 // bugfixed by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
9228 // example 1: base64_decode('S2V2aW4gdmFuIFpvbm5ldmVsZA==');
9229 // returns 1: 'Kevin van Zonneveld'
9230
9231 var o1,o2,o3,h1,h2,h3,h4,bits,i = 0,ac = 0,dec = '',tmp_arr = [];
9232
9233 if (!data) {
9234 return data;
9235 }
9236
9237 data += '';
9238
9239 do { // unpack four hexets into three octets using index points in b64
9240 h1 = b64.indexOf(data.charAt(i++));
9241 h2 = b64.indexOf(data.charAt(i++));
9242 h3 = b64.indexOf(data.charAt(i++));
9243 h4 = b64.indexOf(data.charAt(i++));
9244
9245 bits = h1 << 18 | h2 << 12 | h3 << 6 | h4;
9246
9247 o1 = bits >> 16 & 0xff;
9248 o2 = bits >> 8 & 0xff;
9249 o3 = bits & 0xff;
9250
9251 if (h3 == 64) {
9252 tmp_arr[ac++] = String.fromCharCode(o1);
9253 } else if (h4 == 64) {
9254 tmp_arr[ac++] = String.fromCharCode(o1, o2);
9255 } else {
9256 tmp_arr[ac++] = String.fromCharCode(o1, o2, o3);
9257 }
9258 } while (i < data.length);
9259
9260 dec = tmp_arr.join('');
9261
9262 return dec;
9263 };
9264 }
9265
9266 if (!Array.prototype.map) {
9267 Array.prototype.map = function(fun /*, thisArg */) {
9268 if (this === void 0 || this === null || typeof fun !== "function")
9269 throw new TypeError();
9270
9271 var t = Object(this), len = t.length >>> 0, res = new Array(len);
9272 var thisArg = arguments.length > 1 ? arguments[1] : void 0;
9273 for (var i = 0; i < len; i++) {
9274 // NOTE: Absolute correctness would demand Object.defineProperty
9275 // be used. But this method is fairly new, and failure is
9276 // possible only if Object.prototype or Array.prototype
9277 // has a property |i| (very unlikely), so use a less-correct
9278 // but more portable alternative.
9279 if (i in t)
9280 res[i] = fun.call(thisArg, t[i], i, t);
9281 }
9282
9283 return res;
9284 };
9285 }
9286
9287
9288 if(!Array.isArray) {
9289 Array.isArray = function(arg) {
9290 return Object.prototype.toString.call(arg) === '[object Array]';
9291 };
9292 }
9293
9294 if (!Array.prototype.forEach) {
9295 Array.prototype.forEach = function(fun, thisArg) {
9296 "use strict";
9297
9298 if (this === void 0 || this === null || typeof fun !== "function")
9299 throw new TypeError();
9300
9301 var t = Object(this), len = t.length >>> 0;
9302 for (var i = 0; i < len; i++) {
9303 if (i in t)
9304 fun.call(thisArg, t[i], i, t);
9305 }
9306 };
9307 }
9308
9309 if (!Object.keys) {
9310 Object.keys = (function () {
9311 'use strict';
9312
9313 var hasOwnProperty = Object.prototype.hasOwnProperty,
9314 hasDontEnumBug = !({toString: null}).propertyIsEnumerable('toString'),
9315 dontEnums = ['toString','toLocaleString','valueOf','hasOwnProperty',
9316 'isPrototypeOf','propertyIsEnumerable','constructor'],
9317 dontEnumsLength = dontEnums.length;
9318
9319 return function (obj) {
9320 if (typeof obj !== 'object' && (typeof obj !== 'function' || obj === null)) {
9321 throw new TypeError();
9322 }
9323 var result = [], prop, i;
9324
9325 for (prop in obj) {
9326 if (hasOwnProperty.call(obj, prop)) {
9327 result.push(prop);
9328 }
9329 }
9330
9331 if (hasDontEnumBug) {
9332 for (i = 0; i < dontEnumsLength; i++) {
9333 if (hasOwnProperty.call(obj, dontEnums[i])) {
9334 result.push(dontEnums[i]);
9335 }
9336 }
9337 }
9338 return result;
9339 };
9340 }());
9341 }
9342
9343 if (!String.prototype.trim) {
9344 String.prototype.trim = function () {
9345 return this.replace(/^\s+|\s+$/g, '');
9346 };
9347 }
9348 if (!String.prototype.trimLeft) {
9349 String.prototype.trimLeft = function() {
9350 return this.replace(/^\s+/g, "");
9351 };
9352 }
9353 if (!String.prototype.trimRight) {
9354 String.prototype.trimRight = function() {
9355 return this.replace(/\s+$/g, "");
9356 };
9357 }
9358
9359})(typeof self !== "undefined" && self || typeof window !== "undefined" && window || this);