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