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