1(function (global, factory) { 2 typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : 3 typeof define === 'function' && define.amd ? define(factory) : 4 (global.jspdf = factory()); 5}(this, function () { 'use strict'; 6 7 var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { 8 return typeof obj; 9 } : function (obj) { 10 return obj && typeof Symbol === "function" && obj.constructor === Symbol ? "symbol" : typeof obj; 11 }; 12 13 /** @preserve 14 * jsPDF - PDF Document creation from JavaScript 15 * Version 1.3.2 Built on 2016-09-30T20:33:17.116Z 16 * CommitID 7d854cc77d 17 * 18 * Copyright (c) 2010-2014 James Hall <[email protected]>, https://github.com/MrRio/jsPDF 19 * 2010 Aaron Spike, https://github.com/acspike 20 * 2012 Willow Systems Corporation, willow-systems.com 21 * 2012 Pablo Hess, https://github.com/pablohess 22 * 2012 Florian Jenett, https://github.com/fjenett 23 * 2013 Warren Weckesser, https://github.com/warrenweckesser 24 * 2013 Youssef Beddad, https://github.com/lifof 25 * 2013 Lee Driscoll, https://github.com/lsdriscoll 26 * 2013 Stefan Slonevskiy, https://github.com/stefslon 27 * 2013 Jeremy Morel, https://github.com/jmorel 28 * 2013 Christoph Hartmann, https://github.com/chris-rock 29 * 2014 Juan Pablo Gaviria, https://github.com/juanpgaviria 30 * 2014 James Makes, https://github.com/dollaruw 31 * 2014 Diego Casorran, https://github.com/diegocr 32 * 2014 Steven Spungin, https://github.com/Flamenco 33 * 2014 Kenneth Glassey, https://github.com/Gavvers 34 * 35 * Licensed under the MIT License 36 * 37 * Contributor(s): 38 * siefkenj, ahwolf, rickygu, Midnith, saintclair, eaparango, 39 * kim3er, mfo, alnorth, Flamenco 40 */ 41 42 /** 43 * Creates new jsPDF document object instance. 44 * 45 * @class 46 * @param orientation One of "portrait" or "landscape" (or shortcuts "p" (Default), "l") 47 * @param unit Measurement unit to be used when coordinates are specified. 48 * One of "pt" (points), "mm" (Default), "cm", "in" 49 * @param format One of 'pageFormats' as shown below, default: a4 50 * @returns {jsPDF} 51 * @name jsPDF 52 */ 53 var jsPDF = function (global) { 54 'use strict'; 55 56 var pdfVersion = '1.3', 57 pageFormats = { // Size in pt of various paper formats 58 'a0': [2383.94, 3370.39], 'a1': [1683.78, 2383.94], 59 'a2': [1190.55, 1683.78], 'a3': [841.89, 1190.55], 60 'a4': [595.28, 841.89], 'a5': [419.53, 595.28], 61 'a6': [297.64, 419.53], 'a7': [209.76, 297.64], 62 'a8': [147.40, 209.76], 'a9': [104.88, 147.40], 63 'a10': [73.70, 104.88], 'b0': [2834.65, 4008.19], 64 'b1': [2004.09, 2834.65], 'b2': [1417.32, 2004.09], 65 'b3': [1000.63, 1417.32], 'b4': [708.66, 1000.63], 66 'b5': [498.90, 708.66], 'b6': [354.33, 498.90], 67 'b7': [249.45, 354.33], 'b8': [175.75, 249.45], 68 'b9': [124.72, 175.75], 'b10': [87.87, 124.72], 69 'c0': [2599.37, 3676.54], 'c1': [1836.85, 2599.37], 70 'c2': [1298.27, 1836.85], 'c3': [918.43, 1298.27], 71 'c4': [649.13, 918.43], 'c5': [459.21, 649.13], 72 'c6': [323.15, 459.21], 'c7': [229.61, 323.15], 73 'c8': [161.57, 229.61], 'c9': [113.39, 161.57], 74 'c10': [79.37, 113.39], 'dl': [311.81, 623.62], 75 'letter': [612, 792], 76 'government-letter': [576, 756], 77 'legal': [612, 1008], 78 'junior-legal': [576, 360], 79 'ledger': [1224, 792], 80 'tabloid': [792, 1224], 81 'credit-card': [153, 243] 82 }; 83 84 /** 85 * jsPDF's Internal PubSub Implementation.
86 * See mrrio.github.io/jsPDF/doc/symbols/PubSub.html 87 * Backward compatible rewritten on 2014 by 88 * Diego Casorran, https://github.com/diegocr 89 * 90 * @class 91 * @name PubSub 92 */ 93 function PubSub(context) { 94 var topics = {}; 95 96 this.subscribe = function (topic, callback, once) { 97 if (typeof callback !== 'function') { 98 return false; 99 } 100 101 if (!topics.hasOwnProperty(topic)) { 102 topics[topic] = {}; 103 } 104 105 var id = Math.random().toString(35); 106 topics[topic][id] = [callback, !!once]; 107 108 return id; 109 }; 110 111 this.unsubscribe = function (token) { 112 for (var topic in topics) { 113 if (topics[topic][token]) { 114 delete topics[topic][token]; 115 return true; 116 } 117 } 118 return false; 119 }; 120 121 this.publish = function (topic) { 122 if (topics.hasOwnProperty(topic)) { 123 var args = Array.prototype.slice.call(arguments, 1), 124 idr = []; 125 126 for (var id in topics[topic]) { 127 var sub = topics[topic][id]; 128 try { 129 sub[0].apply(context, args); 130 } catch (ex) { 131 if (global.console) { 132 console.error('jsPDF PubSub Error', ex.message, ex); 133 } 134 } 135 if (sub[1]) idr.push(id); 136 } 137 if (idr.length) idr.forEach(this.unsubscribe); 138 } 139 }; 140 } 141 142 /** 143 * @constructor 144 * @private 145 */ 146 function jsPDF(orientation, unit, format, compressPdf) { 147 var options = {}; 148 149 if ((typeof orientation === 'undefined' ? 'undefined' : _typeof(orientation)) === 'object') { 150 options = orientation; 151 152 orientation = options.orientation; 153 unit = options.unit || unit; 154 format = options.format || format; 155 compressPdf = options.compress || options.compressPdf || compressPdf; 156 } 157 158 // Default options 159 unit = unit || 'mm'; 160 format = format || 'a4'; 161 orientation = ('' + (orientation || 'P')).toLowerCase(); 162 163 var format_as_string = ('' + format).toLowerCase(), 164 compress = !!compressPdf && typeof Uint8Array === 'function', 165 textColor = options.textColor || '0 g', 166 drawColor = options.drawColor || '0 G', 167 activeFontSize = options.fontSize || 16, 168 lineHeightProportion = options.lineHeight || 1.15, 169 lineWidth = options.lineWidth || 0.200025, 170 // 2mm 171 objectNumber = 2, 172 // 'n' Current object number 173 outToPages = !1, 174 // switches where out() prints. outToPages true = push to pages obj. outToPages false = doc builder content 175 offsets = [], 176 // List of offsets. Activated and reset by buildDocument(). Pupulated by various calls buildDocument makes. 177 fonts = {}, 178 // collection of font objects, where key is fontKey - a dynamically created label for a given font. 179 fontmap = {}, 180 // mapping structure fontName > fontStyle > font key - performance layer. See addFont() 181 activeFontKey, 182 // will be string representing the KEY of the font as combination of fontName + fontStyle 183 k, 184 // Scale factor 185 tmp, 186 page = 0, 187 currentPage, 188 pages = [], 189 pagesContext = [], 190 // same index as pages and pagedim 191 pagedim = [], 192 content = [], 193 additionalObjects = [], 194 lineCapID = 0, 195 lineJoinID = 0, 196 content_length = 0, 197 pageWidth, 198 pageHeight, 199 pageMode, 200 zoomMode, 201 layoutMode, 202 documentProperties = { 203 'title': '', 204 'subject': '', 205 'author': '', 206 'keywords': '', 207 'creator': '' 208 }, 209 API = {}, 210 events = new PubSub(API), 211 212
213 ///////////////////// 214 // Private functions 215 ///////////////////// 216 f2 = function f2(number) { 217 return number.toFixed(2); // Ie, %.2f 218 }, 219 f3 = function f3(number) { 220 return number.toFixed(3); // Ie, %.3f 221 }, 222 padd2 = function padd2(number) { 223 return ('0' + parseInt(number)).slice(-2); 224 }, 225 out = function out(string) { 226 if (outToPages) { 227 /* set by beginPage */ 228 pages[currentPage].push(string); 229 } else { 230 // +1 for '\n' that will be used to join 'content' 231 content_length += string.length + 1; 232 content.push(string); 233 } 234 }, 235 newObject = function newObject() { 236 // Begin a new object 237 objectNumber++; 238 offsets[objectNumber] = content_length; 239 out(objectNumber + ' 0 obj'); 240 return objectNumber; 241 }, 242 243 // Does not output the object until after the pages have been output.
244 // Returns an object containing the objectId and content. 245 // All pages have been added so the object ID can be estimated to start right after. 246 // This does not modify the current objectNumber; It must be updated after the newObjects are output. 247 newAdditionalObject = function newAdditionalObject() { 248 var objId = pages.length * 2 + 1; 249 objId += additionalObjects.length; 250 var obj = { objId: objId, content: '' }; 251 additionalObjects.push(obj); 252 return obj; 253 }, 254 255 // Does not output the object. The caller must call newObjectDeferredBegin(oid) before outputing any data 256 newObjectDeferred = function newObjectDeferred() { 257 objectNumber++; 258 offsets[objectNumber] = function () { 259 return content_length; 260 }; 261 return objectNumber; 262 }, 263 newObjectDeferredBegin = function newObjectDeferredBegin(oid) { 264 offsets[oid] = content_length; 265 }, 266 putStream = function putStream(str) { 267 out('stream'); 268 out(str); 269 out('endstream'); 270 }, 271 putPages = function putPages() { 272 var n, 273 p, 274 arr, 275 i, 276 deflater, 277 adler32, 278 adler32cs, 279 wPt, 280 hPt, 281 pageObjectNumbers = []; 282 283 adler32cs = global.adler32cs || jsPDF.adler32cs; 284 if (compress && typeof adler32cs === 'undefined') { 285 compress = false; 286 } 287 288 // outToPages = false as set in endDocument(). out() writes to content. 289 290 for (n = 1; n <= page; n++) { 291 pageObjectNumbers.push(newObject()); 292 wPt = (pageWidth = pagedim[n].width) * k; 293 hPt = (pageHeight = pagedim[n].height) * k; 294 out('<</Type /Page'); 295 out('/Parent 1 0 R'); 296 out('/Resources 2 0 R'); 297 out('/MediaBox [0 0 ' + f2(wPt) + ' ' + f2(hPt) + ']'); 298 // Added for annotation plugin 299 events.publish('putPage', { pageNumber: n, page: pages[n] }); 300 out('/Contents ' + (objectNumber + 1) + ' 0 R'); 301 out('>>'); 302 out('endobj'); 303 304 // Page content 305 p = pages[n].join('\n'); 306 newObject(); 307 if (compress) { 308 arr = []; 309 i = p.length; 310 while (i--) { 311 arr[i] = p.charCodeAt(i); 312 } 313 adler32 = adler32cs.from(p); 314 deflater = new Deflater(6); 315 deflater.append(new Uint8Array(arr)); 316 p = deflater.flush(); 317 arr = new Uint8Array(p.length + 6); 318 arr.set(new Uint8Array([120, 156])), arr.set(p, 2); 319 arr.set(new Uint8Array([adler32 & 0xFF, adler32 >> 8 & 0xFF, adler32 >> 16 & 0xFF, adler32 >> 24 & 0xFF]), p.length + 2); 320 p = String.fromCharCode.apply(null, arr); 321 out('<</Length ' + p.length + ' /Filter [/FlateDecode]>>'); 322 } else { 323 out('<</Length ' + p.length + '>>'); 324 } 325 putStream(p); 326 out('endobj'); 327 } 328 offsets[1] = content_length; 329 out('1 0 obj'); 330 out('<</Type /Pages'); 331 var kids = '/Kids ['; 332 for (i = 0; i < page; i++) { 333 kids += pageObjectNumbers[i] + ' 0 R '; 334 } 335 out(kids + ']'); 336 out('/Count ' + page); 337 out('>>'); 338 out('endobj'); 339 events.publish('postPutPages'); 340 }, 341 putFont = function putFont(font) { 342 font.objectNumber = newObject(); 343 out('<</BaseFont/' + font.PostScriptName + '/Type/Font'); 344 if (typeof font.encoding === 'string') { 345 out('/Encoding/' + font.encoding); 346 } 347 out('/Subtype/Type1>>'); 348 out('endobj'); 349 }, 350 putFonts = function putFonts() { 351 for (var fontKey in fonts) { 352 if (fonts.hasOwnProperty(fontKey)) { 353 putFont(fonts[fontKey]); 354 } 355 } 356 }, 357 putXobjectDict = function putXobjectDict() { 358 // Loop through images, or other data objects 359 events.publish('putXobjectDict'); 360 }, 361 putResourceDictionary = function putResourceDictionary() { 362 out('/ProcSet [/PDF /Text /ImageB /ImageC /ImageI]'); 363 out('/Font <<'); 364 365 // Do this for each font, the '1' bit is the index of the font 366 for (var fontKey in fonts) { 367 if (fonts.hasOwnProperty(fontKey)) { 368 out('/' + fontKey + ' ' + fonts[fontKey].objectNumber + ' 0 R'); 369 } 370 } 371 out('>>'); 372 out('/XObject <<'); 373 putXobjectDict(); 374 out('>>'); 375 }, 376 putResources = function putResources() { 377 putFonts(); 378 events.publish('putResources'); 379 // Resource dictionary 380 offsets[2] = content_length; 381 out('2 0 obj'); 382 out('<<'); 383 putResourceDictionary(); 384 out('>>'); 385 out('endobj'); 386 events.publish('postPutResources'); 387 }, 388 putAdditionalObjects = function putAdditionalObjects() { 389 events.publish('putAdditionalObjects'); 390 for (var i = 0; i < additionalObjects.length; i++) { 391 var obj = additionalObjects[i]; 392 offsets[obj.objId] = content_length; 393 out(obj.objId + ' 0 obj'); 394 out(obj.content); 395 ; 396 out('endobj'); 397 } 398 objectNumber += additionalObjects.length; 399 events.publish('postPutAdditionalObjects'); 400 }, 401 addToFontDictionary = function addToFontDictionary(fontKey, fontName, fontStyle) { 402 // this is mapping structure for quick font key lookup. 403 // returns the KEY of the font (ex: "F1") for a given 404 // pair of font name and type (ex: "Arial". "Italic") 405 if (!fontmap.hasOwnProperty(fontName)) { 406 fontmap[fontName] = {}; 407 } 408 fontmap[fontName][fontStyle] = fontKey; 409 }, 410 411 /** 412 * FontObject describes a particular font as member of an instnace of jsPDF 413 * 414 * It's a collection of properties like 'id' (to be used in PDF stream), 415 * 'fontName' (font's family name), 'fontStyle' (font's style variant label) 416 * 417 * @class 418 * @public 419 * @property id {String} PDF-document-instance-specific label assinged to the font. 420 * @property PostScriptName {String} PDF specification full name for the font 421 * @property encoding {Object} Encoding_name-to-Font_metrics_object mapping. 422 * @name FontObject 423 */ 424 addFont = function addFont(PostScriptName, fontName, fontStyle, encoding) { 425 var fontKey = 'F' + (Object.keys(fonts).length + 1).toString(10), 426 427 // This is FontObject 428 font = fonts[fontKey] = { 429 'id': fontKey, 430 'PostScriptName': PostScriptName, 431 'fontName': fontName, 432 'fontStyle': fontStyle, 433 'encoding': encoding, 434 'metadata': {} 435 }; 436 addToFontDictionary(fontKey, fontName, fontStyle); 437 events.publish('addFont', font); 438 439 return fontKey; 440 }, 441 addFonts = function addFonts() { 442 443 var HELVETICA = "helvetica", 444 TIMES = "times", 445 COURIER = "courier", 446 NORMAL = "normal", 447 BOLD = "bold", 448 ITALIC = "italic", 449 BOLD_ITALIC = "bolditalic", 450 encoding = 'StandardEncoding', 451 ZAPF = "zapfdingbats", 452 standardFonts = [['Helvetica', HELVETICA, NORMAL], ['Helvetica-Bold', HELVETICA, BOLD], ['Helvetica-Oblique', HELVETICA, ITALIC], ['Helvetica-BoldOblique', HELVETICA, BOLD_ITALIC], ['Courier', COURIER, NORMAL], ['Courier-Bold', COURIER, BOLD], ['Courier-Oblique', COURIER, ITALIC], ['Courier-BoldOblique', COURIER, BOLD_ITALIC], ['Times-Roman', TIMES, NORMAL], ['Times-Bold', TIMES, BOLD], ['Times-Italic', TIMES, ITALIC], ['Times-BoldItalic', TIMES, BOLD_ITALIC], ['ZapfDingbats', ZAPF]]; 453 454 for (var i = 0, l = standardFonts.length; i < l; i++) { 455 var fontKey = addFont(standardFonts[i][0], standardFonts[i][1], standardFonts[i][2], encoding); 456 457 // adding aliases for standard fonts, this time matching the capitalization 458 var parts = standardFonts[i][0].split('-'); 459 addToFontDictionary(fontKey, parts[0], parts[1] || ''); 460 } 461 events.publish('addFonts', { fonts: fonts, dictionary: fontmap }); 462 }, 463 SAFE = function __safeCall(fn) { 464 fn.foo = function __safeCallWrapper() { 465 try { 466 return fn.apply(this, arguments); 467 } catch (e) { 468 var stack = e.stack || ''; 469 if (~stack.indexOf(' at ')) stack = stack.split(" at ")[1]; 470 var m = "Error in function " + stack.split("\n")[0].split('<')[0] + ": " + e.message; 471 if (global.console) { 472 global.console.error(m, e); 473 if (global.alert) alert(m); 474 } else { 475 throw new Error(m); 476 } 477 } 478 }; 479 fn.foo.bar = fn; 480 return fn.foo; 481 }, 482 to8bitStream = function to8bitStream(text, flags) { 483 /** 484 * PDF 1.3 spec:
485 * "For text strings encoded in Unicode, the first two bytes must be 254 followed by 486 * 255, representing the Unicode byte order marker, U+FEFF. (This sequence conflicts 487 * with the PDFDocEncoding character sequence thorn ydieresis, which is unlikely 488 * to be a meaningful beginning of a word or phrase.) The remainder of the 489 * string consists of Unicode character codes, according to the UTF-16 encoding 490 * specified in the Unicode standard, version 2.0. Commonly used Unicode values 491 * are represented as 2 bytes per character, with the high-order byte appearing first 492 * in the string." 493 * 494 * In other words, if there are chars in a string with char code above 255, we 495 * recode the string to UCS2 BE - string doubles in length and BOM is prepended. 496 * 497 * HOWEVER! 498 * Actual *content* (body) text (as opposed to strings used in document properties etc) 499 * does NOT expect BOM. There, it is treated as a literal GID (Glyph ID) 500 * 501 * Because of Adobe's focus on "you subset your fonts!" you are not supposed to have 502 * a font that maps directly Unicode (UCS2 / UTF16BE) code to font GID, but you could 503 * fudge it with "Identity-H" encoding and custom CIDtoGID map that mimics Unicode 504 * code page. There, however, all characters in the stream are treated as GIDs, 505 * including BOM, which is the reason we need to skip BOM in content text (i.e. that 506 * that is tied to a font). 507 * 508 * To signal this "special" PDFEscape / to8bitStream handling mode, 509 * API.text() function sets (unless you overwrite it with manual values 510 * given to API.text(.., flags) ) 511 * flags.autoencode = true 512 * flags.noBOM = true 513 * 514 * =================================================================================== 515 * `flags` properties relied upon: 516 * .sourceEncoding = string with encoding label. 517 * "Unicode" by default. = encoding of the incoming text. 518 * pass some non-existing encoding name 519 * (ex: 'Do not touch my strings! I know what I am doing.') 520 * to make encoding code skip the encoding step. 521 * .outputEncoding = Either valid PDF encoding name 522 * (must be supported by jsPDF font metrics, otherwise no encoding) 523 * or a JS object, where key = sourceCharCode, value = outputCharCode 524 * missing keys will be treated as: sourceCharCode === outputCharCode 525 * .noBOM 526 * See comment higher above for explanation for why this is important 527 * .autoencode 528 * See comment higher above for explanation for why this is important 529 */ 530 531 var i, l, sourceEncoding, encodingBlock, outputEncoding, newtext, isUnicode, ch, bch; 532 533 flags = flags || {}; 534 sourceEncoding = flags.sourceEncoding || 'Unicode'; 535 outputEncoding = flags.outputEncoding; 536 537 // This 'encoding' section relies on font metrics format 538 // attached to font objects by, among others, 539 // "Willow Systems' standard_font_metrics plugin" 540 // see jspdf.plugin.standard_font_metrics.js for format 541 // of the font.metadata.encoding Object. 542 // It should be something like 543 // .encoding = {'codePages':['WinANSI....'], 'WinANSI...':{code:code, ...}} 544 // .widths = {0:width, code:width, ..., 'fof':divisor} 545 // .kerning = {code:{previous_char_code:shift, ..., 'fof':-divisor},...} 546 if ((flags.autoencode || outputEncoding) && fonts[activeFontKey].metadata && fonts[activeFontKey].metadata[sourceEncoding] && fonts[activeFontKey].metadata[sourceEncoding].encoding) { 547 encodingBlock = fonts[activeFontKey].metadata[sourceEncoding].encoding; 548 549 // each font has default encoding. Some have it clearly defined. 550 if (!outputEncoding && fonts[activeFontKey].encoding) { 551 outputEncoding = fonts[activeFontKey].encoding; 552 } 553 554 // Hmmm, the above did not work? Let's try again, in different place. 555 if (!outputEncoding && encodingBlock.codePages) { 556 outputEncoding = encodingBlock.codePages[0]; // let's say, first one is the default 557 } 558 559 if (typeof outputEncoding === 'string') { 560 outputEncoding = encodingBlock[outputEncoding]; 561 } 562 // we want output encoding to be a JS Object, where 563 // key = sourceEncoding's character code and 564 // value = outputEncoding's character code. 565 if (outputEncoding) { 566 isUnicode = false;
567 newtext = []; 568 for (i = 0, l = text.length; i < l; i++) { 569 ch = outputEncoding[text.charCodeAt(i)]; 570 if (ch) { 571 newtext.push(String.fromCharCode(ch)); 572 } else { 573 newtext.push(text[i]); 574 } 575 576 // since we are looping over chars anyway, might as well 577 // check for residual unicodeness 578 if (newtext[i].charCodeAt(0) >> 8) { 579 /* more than 255 */ 580 isUnicode = true; 581 } 582 } 583 text = newtext.join(''); 584 } 585 } 586 587 i = text.length; 588 // isUnicode may be set to false above. Hence the triple-equal to undefined 589 while (isUnicode === undefined && i !== 0) { 590 if (text.charCodeAt(i - 1) >> 8) { 591 /* more than 255 */ 592 isUnicode = true; 593 } 594 i--; 595 } 596 if (!isUnicode) { 597 return text; 598 } 599 600 newtext = flags.noBOM ? [] : [254, 255]; 601 for (i = 0, l = text.length; i < l; i++) { 602 ch = text.charCodeAt(i); 603 bch = ch >> 8; // divide by 256 604 if (bch >> 8) { 605 /* something left after dividing by 256 second time */ 606 throw new Error("Character at position " + i + " of string '" + text + "' exceeds 16bits. Cannot be encoded into UCS-2 BE"); 607 } 608 newtext.push(bch); 609 newtext.push(ch - (bch << 8)); 610 } 611 return String.fromCharCode.apply(undefined, newtext); 612 }, 613 pdfEscape = function pdfEscape(text, flags) { 614 /** 615 * Replace '/', '(', and ')' with pdf-safe versions 616 * 617 * Doing to8bitStream does NOT make this PDF display unicode text. For that 618 * we also need to reference a unicode font and embed it - royal pain in the rear. 619 * 620 * There is still a benefit to to8bitStream - PDF simply cannot handle 16bit chars, 621 * which JavaScript Strings are happy to provide. So, while we still cannot display 622 * 2-byte characters property, at least CONDITIONALLY converting (entire string containing) 623 * 16bit chars to (USC-2-BE) 2-bytes per char + BOM streams we ensure that entire PDF 624 * is still parseable. 625 * This will allow immediate support for unicode in document properties strings. 626 */ 627 return to8bitStream(text, flags).replace(/\\/g, '\\\\').replace(/\(/g, '\\(').replace(/\)/g, '\\)'); 628 }, 629 putInfo = function putInfo() { 630 out('/Producer (jsPDF ' + jsPDF.version + ')'); 631 for (var key in documentProperties) { 632 if (documentProperties.hasOwnProperty(key) && documentProperties[key]) { 633 out('/' + key.substr(0, 1).toUpperCase() + key.substr(1) + ' (' + pdfEscape(documentProperties[key]) + ')'); 634 } 635 } 636 var created = new Date(), 637 tzoffset = created.getTimezoneOffset(), 638 tzsign = tzoffset < 0 ? '+' : '-', 639 tzhour = Math.floor(Math.abs(tzoffset / 60)), 640 tzmin = Math.abs(tzoffset % 60), 641 tzstr = [tzsign, padd2(tzhour), "'", padd2(tzmin), "'"].join(''); 642 out(['/CreationDate (D:', created.getFullYear(), padd2(created.getMonth() + 1), padd2(created.getDate()), padd2(created.getHours()), padd2(created.getMinutes()), padd2(created.getSeconds()), tzstr, ')'].join('')); 643 }, 644 putCatalog = function putCatalog() { 645 out('/Type /Catalog'); 646 out('/Pages 1 0 R'); 647 // PDF13ref Section 7.2.1 648 if (!zoomMode) zoomMode = 'fullwidth'; 649 switch (zoomMode) { 650 case 'fullwidth': 651 out('/OpenAction [3 0 R /FitH null]'); 652 break; 653 case 'fullheight': 654 out('/OpenAction [3 0 R /FitV null]'); 655 break; 656 case 'fullpage': 657 out('/OpenAction [3 0 R /Fit]'); 658 break; 659 case 'original': 660 out('/OpenAction [3 0 R /XYZ null null 1]'); 661 break; 662 default: 663 var pcn = '' + zoomMode; 664 if (pcn.substr(pcn.length - 1) === '%') zoomMode = parseInt(zoomMode) / 100; 665 if (typeof zoomMode === 'number') { 666 out('/OpenAction [3 0 R /XYZ null null ' + f2(zoomMode) + ']'); 667 } 668 } 669 if (!layoutMode) layoutMode = 'continuous'; 670 switch (layoutMode) { 671 case 'continuous': 672 out('/PageLayout /OneColumn'); 673 break; 674 case 'single': 675 out('/PageLayout /SinglePage'); 676 break; 677 case 'two': 678 case 'twoleft': 679 out('/PageLayout /TwoColumnLeft'); 680 break; 681 case 'tworight': 682 out('/PageLayout /TwoColumnRight'); 683 break; 684 } 685 if (pageMode) { 686 /** 687 * A name object specifying how the document should be displayed when opened: 688 * UseNone : Neither document outline nor thumbnail images visible -- DEFAULT 689 * UseOutlines : Document outline visible 690 * UseThumbs : Thumbnail images visible 691 * FullScreen : Full-screen mode, with no menu bar, window controls, or any other window visible 692 */ 693 out('/PageMode /' + pageMode); 694 } 695 events.publish('putCatalog'); 696 }, 697 putTrailer = function putTrailer() { 698 out('/Size ' + (objectNumber + 1)); 699 out('/Root ' + objectNumber + ' 0 R'); 700 out('/Info ' + (objectNumber - 1) + ' 0 R'); 701 }, 702 beginPage = function beginPage(width, height) { 703 // Dimensions are stored as user units and converted to points on output 704 var orientation = typeof height === 'string' && height.toLowerCase(); 705 if (typeof width === 'string') { 706 var format = width.toLowerCase(); 707 if (pageFormats.hasOwnProperty(format)) { 708 width = pageFormats[format][0] / k; 709 height = pageFormats[format][1] / k; 710 } 711 } 712 if (Array.isArray(width)) { 713 height = width[1]; 714 width = width[0]; 715 } 716 if (orientation) { 717 switch (orientation.substr(0, 1)) { 718 case 'l': 719 if (height > width) orientation = 's'; 720 break; 721 case 'p': 722 if (width > height) orientation = 's'; 723 break; 724 } 725 if (orientation === 's') { 726 tmp = width; 727 width = height; 728 height = tmp; 729 } 730 } 731 outToPages = true; 732 pages[++page] = []; 733 pagedim[page] = { 734 width: Number(width) || pageWidth, 735 height: Number(height) || pageHeight 736 }; 737 pagesContext[page] = {}; 738 _setPage(page); 739 }, 740 _addPage = function _addPage() { 741 beginPage.apply(this, arguments); 742 // Set line width 743 out(f2(lineWidth * k) + ' w'); 744 // Set draw color 745 out(drawColor); 746 // resurrecting non-default line caps, joins 747 if (lineCapID !== 0) { 748 out(lineCapID + ' J'); 749 } 750 if (lineJoinID !== 0) { 751 out(lineJoinID + ' j'); 752 } 753 events.publish('addPage', { pageNumber: page }); 754 }, 755 _deletePage = function _deletePage(n) { 756 if (n > 0 && n <= page) { 757 pages.splice(n, 1); 758 pagedim.splice(n, 1); 759 page--; 760 if (currentPage > page) { 761 currentPage = page; 762 } 763 this.setPage(currentPage); 764 } 765 }, 766 _setPage = function _setPage(n) { 767 if (n > 0 && n <= page) { 768 currentPage = n; 769 pageWidth = pagedim[n].width; 770 pageHeight = pagedim[n].height; 771 } 772 }, 773 774 /** 775 * Returns a document-specific font key - a label assigned to a 776 * font name + font type combination at the time the font was added 777 * to the font inventory. 778 * 779 * Font key is used as label for the desired font for a block of text 780 * to be added to the PDF document stream. 781 * @private 782 * @function 783 * @param fontName {String} can be undefined on "falthy" to indicate "use current" 784 * @param fontStyle {String} can be undefined on "falthy" to indicate "use current" 785 * @returns {String} Font key. 786 */ 787 _getFont = function _getFont(fontName, fontStyle) { 788 var key; 789 790 fontName = fontName !== undefined ? fontName : fonts[activeFontKey].fontName; 791 fontStyle = fontStyle !== undefined ? fontStyle : fonts[activeFontKey].fontStyle; 792 793 if (fontName !== undefined) { 794 fontName = fontName.toLowerCase(); 795 } 796 switch (fontName) { 797 case 'sans-serif': 798 case 'verdana': 799 case 'arial': 800 case 'helvetica': 801 fontName = 'helvetica'; 802 break; 803 case 'fixed': 804 case 'monospace': 805 case 'terminal': 806 case 'courier': 807 fontName = 'courier'; 808 break; 809 case 'serif': 810 case 'cursive': 811 case 'fantasy': 812 default: 813 fontName = 'times'; 814 break; 815 } 816 817 try { 818 // get a string like 'F3' - the KEY corresponding tot he font + type combination. 819 key = fontmap[fontName][fontStyle]; 820 } catch (e) {} 821 822 if (!key) { 823 //throw new Error("Unable to look up font label for font '" + fontName + "', '" 824 //+ fontStyle + "'. Refer to getFontList(
824) for available fonts."); 825 key = fontmap['times'][fontStyle]; 826 if (key == null) { 827 key = fontmap['times']['normal']; 828 } 829 } 830 return key; 831 }, 832 buildDocument = function buildDocument() { 833 outToPages = false; // switches out() to content 834 835 objectNumber = 2; 836 content_length = 0; 837 content = []; 838 offsets = []; 839 additionalObjects = []; 840 // Added for AcroForm 841 events.publish('buildDocument'); 842 843 // putHeader() 844 out('%PDF-' + pdfVersion); 845 846 putPages(); 847 848 // Must happen after putPages 849 // Modifies current object Id 850 putAdditionalObjects(); 851 852 putResources(); 853 854 // Info 855 newObject(); 856 out('<<'); 857 putInfo(); 858 out('>>'); 859 out('endobj'); 860 861 // Catalog 862 newObject(); 863 out('<<'); 864 putCatalog(); 865 out('>>'); 866 out('endobj'); 867 868 // Cross-ref 869 var o = content_length, 870 i, 871 p = "0000000000"; 872 out('xref'); 873 out('0 ' + (objectNumber + 1)); 874 out(p + ' 65535 f '); 875 for (i = 1; i <= objectNumber; i++) { 876 var offset = offsets[i]; 877 if (typeof offset === 'function') { 878 out((p + offsets[i]()).slice(-10) + ' 00000 n '); 879 } else { 880 out((p + offsets[i]).slice(-10) + ' 00000 n '); 881 } 882 } 883 // Trailer 884 out('trailer'); 885 out('<<'); 886 putTrailer(); 887 out('>>'); 888 out('startxref'); 889 out('' + o); 890 out('%%EOF'); 891 892 outToPages = true; 893 894 return content.join('\n'); 895 }, 896 getStyle = function getStyle(style) { 897 // see path-painting operators in PDF spec 898 var op = 'S'; // stroke 899 if (style === 'F') { 900 op = 'f'; // fill 901 } else if (style === 'FD' || style === 'DF') { 902 op = 'B'; // both 903 } else if (style === 'f' || style === 'f*' || style === 'B' || style === 'B*') { 904 /* 905 Allow direct use of these PDF path-painting operators: 906 - f fill using nonzero winding number rule 907 - f* fill using even-odd rule 908 - B fill then stroke with fill using non-zero winding number rule 909 - B* fill then stroke with fill using even-odd rule 910 */ 911 op = style; 912 } 913 return op; 914 }, 915 getArrayBuffer = function getArrayBuffer() { 916 var data = buildDocument(), 917 len = data.length, 918 ab = new ArrayBuffer(len), 919 u8 = new Uint8Array(ab); 920 921 while (len--) { 922 u8[len] = data.charCodeAt(len); 923 }return ab; 924 }, 925 getBlob = function getBlob() { 926 return new Blob([getArrayBuffer()], { type: "application/pdf" }); 927 }, 928 929 /** 930 * Generates the PDF document. 931 * 932 * If `type` argument is undefined, output is raw body of resulting PDF returned as a string. 933 * 934 * @param {String}
934 type A string identifying one of the possible output types. 935 * @param {Object} options An object providing some additional signalling to PDF generator. 936 * @function 937 * @returns {jsPDF} 938 * @methodOf jsPDF# 939 * @name output 940 */ 941 _output = SAFE(function (type, options) { 942 var datauri = ('' + type).substr(0, 6) === 'dataur' ? 'data:application/pdf;base64,' + btoa(buildDocument()) : 0; 943 944 switch (type) { 945 case undefined: 946 return buildDocument(); 947 case 'save': 948 if (navigator.getUserMedia) { 949 if (global.URL === undefined || global.URL.createObjectURL === undefined) { 950 return API.output('dataurlnewwindow'); 951 } 952 } 953 saveAs(getBlob(), options); 954 if (typeof saveAs.unload === 'function') { 955 if (global.setTimeout) { 956 setTimeout(saveAs.unload, 911); 957 } 958 } 959 break; 960 case 'arraybuffer': 961 return getArrayBuffer(); 962 case 'blob': 963 return getBlob(); 964 case 'bloburi': 965 case 'bloburl': 966 // User is responsible of calling revokeObjectURL 967 return global.URL && global.URL.createObjectURL(getBlob()) || void 0; 968 case 'datauristring': 969 case 'dataurlstring': 970 return datauri; 971 case 'dataurlnewwindow': 972 var nW = global.open(datauri); 973 if (nW || typeof safari === "undefined") return nW; 974 /* pass through */ 975 case 'datauri': 976 case 'dataurl': 977 return global.document.location.href = datauri; 978 default: 979 throw new Error('Output type "' + type + '" is not supported.'); 980 } 981 // @TODO: Add different output options 982 }); 983 984 switch (unit) { 985 case 'pt': 986 k = 1; 987 break; 988 case 'mm': 989 k = 72 / 25.4000508; 990 break; 991 case 'cm': 992 k = 72 / 2.54000508; 993 break; 994 case 'in': 995 k = 72; 996 break; 997 case 'px': 998 k = 96 / 72; 999 break; 1000 case 'pc': 1001 k = 12; 1002 break; 1003 case 'em': 1004 k = 12; 1005 break; 1006 case 'ex': 1007 k = 6; 1008 break; 1009 default: 1010 throw 'Invalid unit: ' + unit; 1011 } 1012 1013 //--------------------------------------- 1014 // Public API 1015 1016 /** 1017 * Object exposing internal API to plugins 1018 * @public 1019 */ 1020 API.internal = { 1021 'pdfEscape': pdfEscape, 1022 'getStyle': getStyle, 1023 /** 1024 * Returns {FontObject} describing a particular font. 1025 * @public 1026 * @function 1027 * @param fontName {String} (Optional) Font's family name 1028 * @param fontStyle {String} (Optional) Font's style variation name (Example:"Italic") 1029 * @returns {FontObject} 1030 */ 1031 'getFont': function getFont() { 1032 return fonts[_getFont.apply(API, arguments)]; 1033 }, 1034 'getFontSize': function getFontSize() { 1035 return activeFontSize; 1036 }, 1037 'getLineHeight': function getLineHeight() { 1038 return activeFontSize * lineHeightProportion; 1039 },
1040 'write': function write(string1 /*, string2, string3, etc */) { 1041 out(arguments.length === 1 ? string1 : Array.prototype.join.call(arguments, ' ')); 1042 }, 1043 'getCoordinateString': function getCoordinateString(value) { 1044 return f2(value * k); 1045 }, 1046 'getVerticalCoordinateString': function getVerticalCoordinateString(value) { 1047 return f2((pageHeight - value) * k); 1048 }, 1049 'collections': {}, 1050 'newObject': newObject, 1051 'newAdditionalObject': newAdditionalObject, 1052 'newObjectDeferred': newObjectDeferred, 1053 'newObjectDeferredBegin': newObjectDeferredBegin, 1054 'putStream': putStream, 1055 'events': events, 1056 // ratio that you use in multiplication of a given "size" number to arrive to 'point' 1057 // units of measurement. 1058 // scaleFactor is set at initialization of the document and calculated against the stated 1059 // default measurement units for the document. 1060 // If default is "mm", k is the number that will turn number in 'mm' into 'points' number. 1061 // through multiplication. 1062 'scaleFactor': k, 1063 'pageSize': { 1064 get width() { 1065 return pageWidth; 1066 }, 1067 get height() { 1068 return pageHeight; 1069 } 1070 }, 1071 'output': function output(type, options) { 1072 return _output(type, options); 1073 }, 1074 'getNumberOfPages': function getNumberOfPages() { 1075 return pages.length - 1; 1076 }, 1077 'pages': pages, 1078 'out': out, 1079 'f2': f2, 1080 'getPageInfo': function getPageInfo(pageNumberOneBased) { 1081 var objId = (pageNumberOneBased - 1) * 2 + 3; 1082 return { objId: objId, pageNumber: pageNumberOneBased, pageContext: pagesContext[pageNumberOneBased] }; 1083 }, 1084 'getCurrentPageInfo': function getCurrentPageInfo() { 1085 var objId = (currentPage - 1) * 2 + 3; 1086 return { objId: objId, pageNumber: currentPage, pageContext: pagesContext[currentPage] }; 1087 }, 1088 'getPDFVersion': function getPDFVersion() { 1089 return pdfVersion; 1090 } 1091 }; 1092 1093 /** 1094 * Adds (and transfers the focus to) new page to the PDF document. 1095 * @function 1096 * @returns {jsPDF} 1097 * 1098 * @methodOf jsPDF# 1099 * @name addPage 1100 */ 1101 API.addPage = function () { 1102 _addPage.apply(this, arguments); 1103 return this; 1104 }; 1105 API.setPage = function () { 1106 _setPage.apply(this, arguments); 1107 return this; 1108 }; 1109 API.insertPage = function (beforePage) { 1110 this.addPage(); 1111 this.movePage(currentPage, beforePage); 1112 return this; 1113 }; 1114 API.movePage = function (targetPage, beforePage) { 1115 if (targetPage > beforePage) { 1116 var tmpPages = pages[targetPage]; 1117 var tmpPagedim = pagedim[targetPage]; 1118 var tmpPagesContext = pagesContext[targetPage]; 1119 for (var i = targetPage; i > beforePage; i--) { 1120 pages[i] = pages[i - 1]; 1121 pagedim[i] = pagedim[i - 1]; 1122 pagesContext[i] = pagesContext[i - 1]; 1123 } 1124 pages[beforePage] = tmpPages; 1125 pagedim[beforePage] = tmpPagedim; 1126 pagesContext[beforePage] = tmpPagesContext; 1127 this.setPage(beforePage); 1128 } else if (targetPage < beforePage) { 1129 var tmpPages = pages[targetPage]; 1130 var tmpPagedim = pagedim[targetPage]; 1131 var tmpPagesContext = pagesContext[targetPage]; 1132 for (var i = targetPage; i < beforePage; i++) { 1133 pages[i] = pages[i + 1]; 1134 pagedim[i] = pagedim[i + 1]; 1135 pagesContext[i] = pagesContext[i + 1]; 1136 } 1137 pages[beforePage] = tmpPages; 1138 pagedim[beforePage] = tmpPagedim; 1139 pagesContext[beforePage] = tmpPagesContext; 1140 this.setPage(beforePage); 1141 } 1142 return this; 1143 }; 1144 1145 API.deletePage = function () { 1146 _deletePage.apply(this, arguments); 1147 return this; 1148 }; 1149 API.setDisplayMode = function (zoom, layout, pmode) { 1150 zoomMode = zoom; 1151 layoutMode = layout; 1152 pageMode = pmode; 1153 return this; 1154 }, 1155 1156 /** 1157 * Adds text to page. Supports adding multiline text when 'text' argument is an Array of Strings. 1158 * 1159 * @function 1160 * @param {String|Array}
1160 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. 1161 * @param {Number} x Coordinate (in units declared at inception of PDF document) against left edge of the page 1162 * @param {Number} y Coordinate (in units declared at inception of PDF document) against upper edge of the page 1163 * @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. 1164 * @returns {jsPDF} 1165 * @methodOf jsPDF# 1166 * @name text 1167 */ 1168 API.text = function (text, x, y, flags, angle, align) { 1169 /** 1170 * Inserts something like this into PDF 1171 * BT 1172 * /F1 16 Tf % Font name + size 1173 * 16 TL % How many units down for next line in multiline text 1174 * 0 g % color 1175 * 28.35 813.54 Td % position 1176 * (line one) Tj 1177 * T* (line two) Tj 1178 * T* (line three) Tj 1179 * ET 1180 */ 1181 function ESC(s) { 1182 s = s.split("\t").join(Array(options.TabLen || 9).join(" ")); 1183 return pdfEscape(s, flags); 1184 } 1185 1186 // Pre-August-2012 the order of arguments was function(x, y, text, flags) 1187 // in effort to make all calls have similar signature like 1188 // function(data, coordinates... , miscellaneous) 1189 // this method had its args flipped. 1190 // code below allows backward compatibility with old arg order. 1191 if (typeof text === 'number') { 1192 tmp = y; 1193 y = x; 1194 x = text; 1195 text = tmp; 1196 } 1197 1198 // If there are any newlines in text, we assume 1199 // the user wanted to print multiple lines, so break the 1200 // text up into an array. If the text is already an array, 1201 // we assume the user knows what they are doing. 1202 // Convert text into an array anyway to simplify 1203 // later code. 1204 if (typeof text === 'string') { 1205 if (text.match(/[\n\r]/)) { 1206 text = text.split(/\r\n|\r|\n/g); 1207 } else { 1208 text = [text]; 1209 } 1210 } 1211 if (typeof angle === 'string') { 1212 align = angle; 1213 angle = null; 1214 } 1215 if (typeof flags === 'string') { 1216 align = flags; 1217 flags = null; 1218 } 1219 if (typeof flags === 'number') { 1220 angle = flags; 1221 flags = null; 1222 } 1223 var xtra = '', 1224 mode = 'Td', 1225 todo; 1226 if (angle) { 1227 angle *= Math.PI / 180; 1228 var c = Math.cos(angle), 1229 s = Math.sin(angle); 1230 xtra = [f2(c), f2(s), f2(s * -1), f2(c), ''].join(" "); 1231 mode = 'Tm'; 1232 } 1233 flags = flags || {}; 1234 if (!('noBOM' in flags)) flags.noBOM = true; 1235 if (!('autoencode' in flags)) flags.autoencode = true; 1236 1237 var strokeOption = ''; 1238 var pageContext = this.internal.getCurrentPageInfo().pageContext; 1239 if (true === flags.stroke) { 1240 if (pageContext.lastTextWasStroke !== true) { 1241 strokeOption = '1 Tr\n'; 1242 pageContext.lastTextWasStroke = true; 1243 } 1244 } else { 1245 if (pageContext.lastTextWasStroke) { 1246 strokeOption = '0 Tr\n'; 1247 } 1248 pageContext.lastTextWasStroke = false;
1249 } 1250 1251 if (typeof this._runningPageHeight === 'undefined') { 1252 this._runningPageHeight = 0; 1253 } 1254 1255 if (typeof text === 'string') { 1256 text = ESC(text); 1257 } else if (Object.prototype.toString.call(text) === '[object Array]') { 1258 // we don't want to destroy original text array, so cloning it 1259 var sa = text.concat(), 1260 da = [], 1261 len = sa.length; 1262 // we do array.join('text that must not be PDFescaped") 1263 // thus, pdfEscape each component separately 1264 while (len--) { 1265 da.push(ESC(sa.shift())); 1266 } 1267 var linesLeft = Math.ceil((pageHeight - y - this._runningPageHeight) * k / (activeFontSize * lineHeightProportion)); 1268 if (0 <= linesLeft && linesLeft < da.length + 1) { 1269 //todo = da.splice(linesLeft-1); 1270 } 1271 1272 if (align) { 1273 var left, 1274 prevX, 1275 maxLineLength, 1276 leading = activeFontSize * lineHeightProportion, 1277 lineWidths = text.map(function (v) { 1278 return this.getStringUnitWidth(v) * activeFontSize / k; 1279 }, this); 1280 maxLineLength = Math.max.apply(Math, lineWidths); 1281 // The first line uses the "main" Td setting, 1282 // and the subsequent lines are offset by the 1283 // previous line's x coordinate. 1284 if (align === "center") { 1285 // The passed in x coordinate defines 1286 // the center point. 1287 left = x - maxLineLength / 2; 1288 x -= lineWidths[0] / 2; 1289 } else if (align === "right") { 1290 // The passed in x coordinate defines the 1291 // rightmost point of the text. 1292 left = x - maxLineLength; 1293 x -= lineWidths[0]; 1294 } else { 1295 throw new Error('Unrecognized alignment option, use "center" or "right".'); 1296 } 1297 prevX = x; 1298 text = da[0]; 1299 for (var i = 1, len = da.length; i < len; i++) { 1300 var delta = maxLineLength - lineWidths[i]; 1301 if (align === "center") delta /= 2; 1302 // T* = x-offset leading Td ( text ) 1303 text += ") Tj\n" + (left - prevX + delta) + " -" + leading + " Td (" + da[i]; 1304 prevX = left + delta; 1305 } 1306 } else { 1307 text = da.join(") Tj\nT* ("); 1308 } 1309 } else { 1310 throw new Error('Type of text must be string or Array. "' + text + '" is not recognized.'); 1311 } 1312 // Using "'" ("go next line and render text" mark) would save space but would complicate our rendering code, templates 1313 1314 // BT .. ET does NOT have default settings for Tf. You must state that explicitely every time for BT .. ET 1315 // if you want text transformation matrix (+ multiline) to work reliably (which reads sizes of things from font declarations) 1316 // Thus, there is NO useful, *reliable* concept of "default" font for a page. 1317 // The fact that "default" (reuse font used before) font worked before in basic cases is an accident 1318 // - readers dealing smartly with brokenness of jsPDF's markup. 1319 1320 var curY; 1321 1322 if (todo) { 1323 //this.addPage(); 1324 //this._runningPageHeight += y - (activeFontSize * 1.7 / k); 1325 //curY = f2(pageHeight - activeFontSize * 1.7 /k); 1326 } else { 1327 curY = f2((pageHeight - y) * k); 1328 } 1329 //curY = f2((pageHeight - (y - this._runningPageHeight)) * k); 1330 1331 // if (curY < 0){ 1332 // console.log('auto page break'); 1333 // this.addPage(); 1334 // this._runningPageHeight = y - (activeFontSize * 1.7 / k); 1335 // curY = f2(pageHeight - activeFontSize * 1.7 /k); 1336 // } 1337 1338 out('BT\n/' + activeFontKey + ' ' + activeFontSize + ' Tf\n' + // font face, style, size 1339 activeFontSize * lineHeightProportion + ' TL\n' + // line spacing 1340 strokeOption + // stroke option 1341 textColor + '\n' + xtra + f2(x * k) + ' ' + curY + ' ' + mode + '\n(' + text
1341+ ') Tj\nET'); 1342 1343 if (todo) { 1344 //this.text( todo, x, activeFontSize * 1.7 / k); 1345 //this.text( todo, x, this._runningPageHeight + (activeFontSize * 1.7 / k)); 1346 this.text(todo, x, y); // + (activeFontSize * 1.7 / k)); 1347 } 1348 1349 return this; 1350 }; 1351 1352 API.lstext = function (text, x, y, spacing) { 1353 for (var i = 0, len = text.length; i < len; i++, x += spacing) { 1354 this.text(text[i], x, y); 1355 } 1356 }; 1357 1358 API.line = function (x1, y1, x2, y2) { 1359 return this.lines([[x2 - x1, y2 - y1]], x1, y1); 1360 }; 1361 1362 API.clip = function () { 1363 // By patrick-roberts, github.com/MrRio/jsPDF/issues/328 1364 // Call .clip() after calling .rect() with a style argument of null 1365 out('W'); // clip 1366 out('S'); // stroke path; necessary for clip to work 1367 }; 1368 1369 /** 1370 * This fixes the previous function clip(). Perhaps the 'stroke path' hack was due to the missing 'n' instruction? 1371 * We introduce the fixed version so as to not break API. 1372 * @param fillRule 1373 */ 1374 API.clip_fixed = function (fillRule) { 1375 // Call .clip() after calling drawing ops with a style argument of null 1376 // W is the PDF clipping op 1377 if ('evenodd' === fillRule) { 1378 out('W*'); 1379 } else { 1380 out('W'); 1381 } 1382 // End the path object without filling or stroking it. 1383 // This operator is a path-painting no-op, used primarily for the side effect of changing the current clipping path 1384 // (see Section 4.4.3, âClipping Path Operatorsâ) 1385 out('n'); 1386 }; 1387 1388 /** 1389 * Adds series of curves (straight lines or cubic bezier curves) to canvas, starting at `x`, `y` coordinates. 1390 * All data points in `lines` are relative to last line origin. 1391 * `x`, `y` become x1,y1 for first line / curve in the set. 1392 * For lines you only need to specify [x2, y2] - (ending point) vector against x1, y1 starting point. 1393 * 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. 1394 * 1395 * @example .lines([[2,2],[-2,2],[1,1,2,2,3,3],[2,1]], 212,110, 10) // line, line, bezier curve, line 1396 * @param {Array} lines Array of *vector* shifts as pairs (lines) or sextets (cubic bezier curves). 1397 * @param {Number} x Coordinate (in units declared at inception of PDF document) against left edge of the page 1398 * @param {Number} y Coordinate (in units declared at inception of PDF document) against upper edge of the page 1399 * @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. 1400 * @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. 1401 * @param {Boolean} closed If true, the path is closed with a straight line from the end of the last curve to the starting point. 1402 * @function 1403 * @returns {jsPDF} 1404 * @methodOf jsPDF# 1405 * @name lines 1406 */ 1407 API.lines = function (lines, x, y, scale, style, closed) { 1408 var scalex, scaley, i, l, leg, x2, y2, x3, y3, x4, y4; 1409 1410 // Pre-August-2012 the order of arguments was function(x, y, lines, scale, style) 1411 // in effort to make all calls have similar signature like 1412 // function(content, coordinateX, coordinateY , miscellaneous) 1413 // this method had its args flipped. 1414 // code below allows backward compatibility with old arg order. 1415 if (typeof lines === 'number') { 1416 tmp = y; 1417 y = x; 1418 x = lines; 1419 lines = tmp; 1420 } 1421 1422 scale = scale || [1, 1]; 1423 1424 // starting point
1425 out(f3(x * k) + ' ' + f3((pageHeight - y) * k) + ' m '); 1426 1427 scalex = scale[0]; 1428 scaley = scale[1]; 1429 l = lines.length; 1430 //, x2, y2 // bezier only. In page default measurement "units", *after* scaling 1431 //, x3, y3 // bezier only. In page default measurement "units", *after* scaling 1432 // ending point for all, lines and bezier. . In page default measurement "units", *after* scaling 1433 x4 = x; // last / ending point = starting point for first item. 1434 y4 = y; // last / ending point = starting point for first item. 1435 1436 for (i = 0; i < l; i++) { 1437 leg = lines[i]; 1438 if (leg.length === 2) { 1439 // simple line 1440 x4 = leg[0] * scalex + x4; // here last x4 was prior ending point 1441 y4 = leg[1] * scaley + y4; // here last y4 was prior ending point 1442 out(f3(x4 * k) + ' ' + f3((pageHeight - y4) * k) + ' l'); 1443 } else { 1444 // bezier curve 1445 x2 = leg[0] * scalex + x4; // here last x4 is prior ending point 1446 y2 = leg[1] * scaley + y4; // here last y4 is prior ending point 1447 x3 = leg[2] * scalex + x4; // here last x4 is prior ending point 1448 y3 = leg[3] * scaley + y4; // here last y4 is prior ending point 1449 x4 = leg[4] * scalex + x4; // here last x4 was prior ending point 1450 y4 = leg[5] * scaley + y4; // here last y4 was prior ending point 1451 out(f3(x2 * k) + ' ' + f3((pageHeight - y2) * k) + ' ' + f3(x3 * k) + ' ' + f3((pageHeight - y3) * k) + ' ' + f3(x4 * k) + ' ' + f3((pageHeight - y4) * k) + ' c'); 1452 } 1453 } 1454 1455 if (closed) { 1456 out(' h'); 1457 } 1458 1459 // stroking / filling / both the path 1460 if (style !== null) { 1461 out(getStyle(style)); 1462 } 1463 return this; 1464 }; 1465 1466 /** 1467 * Adds a rectangle to PDF 1468 * 1469 * @param {Number} x Coordinate (in units declared at inception of PDF document) against left edge of the page 1470 * @param {Number} y Coordinate (in units declared at inception of PDF document) against upper edge of the page 1471 * @param {Number} w Width (in units declared at inception of PDF document) 1472 * @param {Number} h Height (in units declared at inception of PDF document) 1473 * @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. 1474 * @function 1475 * @returns {jsPDF} 1476 * @methodOf jsPDF# 1477 * @name rect 1478 */ 1479 API.rect = function (x, y, w, h, style) { 1480 var op = getStyle(style); 1481 out([f2(x * k), f2((pageHeight - y) * k), f2(w * k), f2(-h * k), 're'].join(' ')); 1482 1483 if (style !== null) { 1484 out(getStyle(style)); 1485 } 1486 1487 return this; 1488 }; 1489 1490 /** 1491 * Adds a triangle to PDF 1492 * 1493 * @param {Number} x1 Coordinate (in units declared at inception of PDF document) against left edge of the page 1494 * @param {Number} y1 Coordinate (in units declared at inception of PDF document) against upper edge of the page 1495 * @param {Number} x2 Coordinate (in units declared at inception of PDF document) against left edge of the page 1496 * @param {Number} y2 Coordinate (in units declared at inception of PDF document) against upper edge of the page 1497 * @param {Number} x3 Coordinate (in units declared at inception of PDF document) against left edge of the page 1498 * @param {Number} y3 Coordinate (in units declared at inception of PDF document) against upper edge of the page 1499 * @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. 1500 * @function 1501 * @returns {jsPDF} 1502 * @methodOf jsPDF# 1503 * @name triangle 1504 */ 1505 API.triangle = function (x1, y1, x2, y2, x3, y3, style) { 1506 this.lines([[x2 - x1, y2 - y1], // vector to point 2 1507 [x3 - x2, y3 - y2], // vector to point 3 1508 [x1 - x3, y1 - y3] // closing vector back to point 1 1509 ], x1, y1, // start of path 1510 [1, 1], style, true); 1511 return this; 1512 }; 1513 1514 /** 1515 * Adds a rectangle with rounded corners to PDF 1516 * 1517 * @param {Number} x Coordinate (in units declared at inception of PDF document) against left edge of the page 1518 * @param {Number} y Coordinate (in units declared at inception of PDF document) against upper edge of the page 1519 * @param {Number} w Width (in units declared at inception of PDF document) 1520 * @param {Number} h Height (in units declared at inception of PDF document) 1521 * @param {Number} rx Radius along x axis (in units declared at inception of PDF document) 1522 * @param {Number} rx Radius along y axis (in units declared at inception of PDF document) 1523 * @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. 1524 * @function 1525 * @returns {jsPDF} 1526 * @methodOf jsPDF# 1527 * @name roundedRect 1528 */ 1529 API.roundedRect = function (x, y, w, h, rx, ry, style) {
1530 var MyArc = 4 / 3 * (Math.SQRT2 - 1); 1531 this.lines([[w - 2 * rx, 0], [rx * MyArc, 0, rx, ry - ry * MyArc, rx, ry], [0, h - 2 * ry], [0, ry * MyArc, -(rx * MyArc), ry, -rx, ry], [-w + 2 * rx, 0], [-(rx * MyArc), 0, -rx, -(ry * MyArc), -rx, -ry], [0, -h + 2 * ry], [0, -(ry * MyArc), rx * MyArc, -ry, rx, -ry]], x + rx, y, // start of path 1532 [1, 1], style); 1533 return this; 1534 }; 1535 1536 /** 1537 * Adds an ellipse to PDF 1538 * 1539 * @param {Number} x Coordinate (in units declared at inception of PDF document) against left edge of the page 1540 * @param {Number} y Coordinate (in units declared at inception of PDF document) against upper edge of the page 1541 * @param {Number} rx Radius along x axis (in units declared at inception of PDF document) 1542 * @param {Number} rx Radius along y axis (in units declared at inception of PDF document) 1543 * @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. 1544 * @function 1545 * @returns {jsPDF} 1546 * @methodOf jsPDF# 1547 * @name ellipse 1548 */ 1549 API.ellipse = function (x, y, rx, ry, style) { 1550 var lx = 4 / 3 * (Math.SQRT2 - 1) * rx, 1551 ly = 4 / 3 * (Math.SQRT2 - 1) * ry; 1552 1553 out([f2((x + rx) * k), f2((pageHeight - y) * k), 'm', f2((x + rx) * k), f2((pageHeight - (y - ly)) * k), f2((x + lx) * k), f2((pageHeight - (y - ry)) * k), f2(x * k), f2((pageHeight - (y - ry)) * k), 'c'].join(' ')); 1554 out([f2((x - lx) * k), f2((pageHeight - (y - ry)) * k), f2((x - rx) * k), f2((pageHeight - (y - ly)) * k), f2((x - rx) * k), f2((pageHeight - y) * k), 'c'].join(' ')); 1555 out([f2((x - rx) * k), f2((pageHeight - (y + ly)) * k), f2((x - lx) * k), f2((pageHeight - (y + ry)) * k), f2(x * k), f2((pageHeight - (y + ry)) * k), 'c'].join(' ')); 1556 out([f2((x + lx) * k), f2((pageHeight - (y + ry)) * k), f2((x + rx) * k), f2((pageHeight - (y + ly)) * k), f2((x + rx) * k), f2((pageHeight - y) * k), 'c'].join(' ')); 1557 1558 if (style !== null) { 1559 out(getStyle(style)); 1560 } 1561 1562 return this; 1563 }; 1564 1565 /** 1566 * Adds an circle to PDF 1567 * 1568 * @param {Number} x Coordinate (in units declared at inception of PDF document) against left edge of the page 1569 * @param {Number} y Coordinate (in units declared at inception of PDF document) against upper edge of the page 1570 * @param {Number} r Radius (in units declared at inception of PDF document) 1571 * @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. 1572 * @function 1573 * @returns {jsPDF} 1574 * @methodOf jsPDF# 1575 * @name circle 1576 */ 1577 API.circle = function (x, y, r, style) { 1578 return this.ellipse(x, y, r, r, style); 1579 }; 1580 1581 /** 1582 * Adds a properties to the PDF document 1583 * 1584 * @param {Object} A property_name-to-property_value object structure. 1585 * @function 1586 * @returns {jsPDF} 1587 * @methodOf jsPDF# 1588 * @name setProperties 1589 */ 1590 API.setProperties = function (properties) { 1591 // copying only those properties we can render. 1592 for (var property in documentProperties) { 1593 if (documentProperties.hasOwnProperty(property) && properties[property]) { 1594 documentProperties[property] = properties[property]; 1595 } 1596 } 1597 return this; 1598 }; 1599 1600 /** 1601 * Sets font size for upcoming text elements. 1602 * 1603 * @param {Number} size Font size in points. 1604 * @function 1605 * @returns {jsPDF} 1606 * @methodOf jsPDF# 1607 * @name setFontSize 1608 */ 1609 API.setFontSize = function (size) { 1610 activeFontSize = size; 1611 return this; 1612 }; 1613 1614 /** 1615 * Sets text font face, variant for upcoming text elements.
1616 * See output of jsPDF.getFontList() for possible font names, styles. 1617 * 1618 * @param {String} fontName Font name or family. Example: "times" 1619 * @param {String} fontStyle Font style or variant. Example: "italic" 1620 * @function 1621 * @returns {jsPDF} 1622 * @methodOf jsPDF# 1623 * @name setFont 1624 */ 1625 API.setFont = function (fontName, fontStyle) { 1626 activeFontKey = _getFont(fontName, fontStyle); 1627 // if font is not found, the above line blows up and we never go further 1628 return this; 1629 }; 1630 1631 /** 1632 * Switches font style or variant for upcoming text elements, 1633 * while keeping the font face or family same. 1634 * See output of jsPDF.getFontList() for possible font names, styles. 1635 * 1636 * @param {String} style Font style or variant. Example: "italic" 1637 * @function 1638 * @returns {jsPDF} 1639 * @methodOf jsPDF# 1640 * @name setFontStyle 1641 */ 1642 API.setFontStyle = API.setFontType = function (style) { 1643 activeFontKey = _getFont(undefined, style); 1644 // if font is not found, the above line blows up and we never go further 1645 return this; 1646 }; 1647 1648 /** 1649 * Returns an object - a tree of fontName to fontStyle relationships available to 1650 * active PDF document. 1651 * 1652 * @public 1653 * @function 1654 * @returns {Object} Like {'times':['normal', 'italic', ... ], 'arial':['normal', 'bold', ... ], ... } 1655 * @methodOf jsPDF# 1656 * @name getFontList 1657 */ 1658 API.getFontList = function () { 1659 // TODO: iterate over fonts array or return copy of fontmap instead in case more are ever added. 1660 var list = {}, 1661 fontName, 1662 fontStyle, 1663 tmp; 1664 1665 for (fontName in fontmap) { 1666 if (fontmap.hasOwnProperty(fontName)) { 1667 list[fontName] = tmp = []; 1668 for (fontStyle in fontmap[fontName]) { 1669 if (fontmap[fontName].hasOwnProperty(fontStyle)) { 1670 tmp.push(fontStyle); 1671 } 1672 } 1673 } 1674 } 1675 1676 return list; 1677 }; 1678 1679 /** 1680 * Add a custom font. 1681 * 1682 * @param {String} Postscript name of the Font. Example: "Menlo-Regular" 1683 * @param {String} Name of font-family from @font-face definition. Example: "Menlo Regular" 1684 * @param {String} Font style. Example: "normal" 1685 * @function 1686 * @returns the {fontKey} (same as the internal method) 1687 * @methodOf jsPDF# 1688 * @name addFont 1689 */ 1690 API.addFont = function (postScriptName, fontName, fontStyle) { 1691 addFont(postScriptName, fontName, fontStyle, 'StandardEncoding'); 1692 }; 1693 1694 /** 1695 * Sets line width for upcoming lines. 1696 * 1697 * @param {Number} width Line width (in units declared at inception of PDF document) 1698 * @function 1699 * @returns {jsPDF} 1700 * @methodOf jsPDF# 1701 * @name setLineWidth 1702 */ 1703 API.setLineWidth = function (width) { 1704 out((width * k).toFixed(2) + ' w'); 1705 return this; 1706 }; 1707 1708 /** 1709 * Sets the stroke color for upcoming elements. 1710 * 1711 * Depending on the number of arguments given, Gray, RGB, or CMYK 1712 * color space is implied. 1713 * 1714 * When only ch1 is given, "Gray" color space is implied and it 1715 * must be a value in the range from 0.00 (solid black) to to 1.00 (white) 1716 * if values are communicated as String types, or in range from 0 (black) 1717 * to 255 (white) if communicated as Number type. 1718 * The RGB-like 0-255 range is provided for backward compatibility. 1719 * 1720 * When only ch1,ch2,ch3 are given, "RGB" color space is implied and each 1721 * value must be in the range from 0.00 (minimum intensity) to to 1.00 1722 * (max intensity) if values are communicated as String types, or 1723 * from 0 (min intensity) to to 255 (max intensity) if values are communicated 1724 * as Number types. 1725 * The RGB-like 0-255 range is provided for backward compatibility. 1726 * 1727 * When ch1,ch2,ch3,ch4 are given, "CMYK" color space is implied and each 1728 * value must be a in the range from 0.00 (0% concentration) to to 1729 * 1.00 (100% concentration) 1730 * 1731 * Because JavaScript treats fixed point numbers badly (rounds to 1732 * floating point nearest to binary representation) it is highly advised to 1733 * communicate the fractional numbers as String types, not JavaScript Number type. 1734 * 1735 * @param {Number|String} ch1 Color channel value 1736 * @param {Number|String} ch2 Color channel value 1737 * @param {Number|String} ch3 Color channel value 1738 * @param {Number|String} ch4 Color channel value 1739 * 1740 * @function 1741 * @returns {jsPDF} 1742 * @methodOf jsPDF# 1743 * @name setDrawColor 1744 */ 1745 API.setDrawColor = function (ch1, ch2, ch3, ch4) { 1746 var color; 1747 if (ch2 === undefined || ch4 === undefined && ch1 === ch2 === ch3) { 1748 // Gray color space. 1749 if (typeof ch1 === 'string') { 1750 color = ch1 + ' G'; 1751 } else { 1752 color = f2(ch1 / 255) + ' G'; 1753 } 1754 } else if (ch4 === undefined) { 1755 // RGB 1756 if (typeof ch1 === 'string') { 1757 color = [ch1, ch2, ch3, 'RG'].join(' '); 1758 } else { 1759 color = [f2(ch1 / 255), f2(ch2 / 255), f2(ch3 / 255), 'RG'].join(' '); 1760 } 1761 } else { 1762 // CMYK 1763 if (typeof ch1 === 'string') { 1764 color = [ch1, ch2, ch3, ch4, 'K'].join(' '); 1765 } else { 1766 color = [f2(ch1), f2(ch2), f2(ch3), f2(ch4), 'K'].join(' '); 1767 } 1768 } 1769 1770 out(color); 1771 return this; 1772 }; 1773 1774 /** 1775 * Sets the fill color for upcoming elements. 1776 *
1777 * Depending on the number of arguments given, Gray, RGB, or CMYK 1778 * color space is implied. 1779 * 1780 * When only ch1 is given, "Gray" color space is implied and it 1781 * must be a value in the range from 0.00 (solid black) to to 1.00 (white) 1782 * if values are communicated as String types, or in range from 0 (black) 1783 * to 255 (white) if communicated as Number type. 1784 * The RGB-like 0-255 range is provided for backward compatibility. 1785 * 1786 * When only ch1,ch2,ch3 are given, "RGB" color space is implied and each 1787 * value must be in the range from 0.00 (minimum intensity) to to 1.00 1788 * (max intensity) if values are communicated as String types, or 1789 * from 0 (min intensity) to to 255 (max intensity) if values are communicated 1790 * as Number types. 1791 * The RGB-like 0-255 range is provided for backward compatibility. 1792 * 1793 * When ch1,ch2,ch3,ch4 are given, "CMYK" color space is implied and each 1794 * value must be a in the range from 0.00 (0% concentration) to to 1795 * 1.00 (100% concentration) 1796 * 1797 * Because JavaScript treats fixed point numbers badly (rounds to 1798 * floating point nearest to binary representation) it is highly advised to 1799 * communicate the fractional numbers as String types, not JavaScript Number type. 1800 * 1801 * @param {Number|String} ch1 Color channel value 1802 * @param {Number|String} ch2 Color channel value 1803 * @param {Number|String} ch3 Color channel value 1804 * @param {Number|String} ch4 Color channel value 1805 * 1806 * @function 1807 * @returns {jsPDF} 1808 * @methodOf jsPDF# 1809 * @name setFillColor 1810 */ 1811 API.setFillColor = function (ch1, ch2, ch3, ch4) { 1812 var color; 1813 1814 if (ch2 === undefined || ch4 === undefined && ch1 === ch2 === ch3) { 1815 // Gray color space. 1816 if (typeof ch1 === 'string') { 1817 color = ch1 + ' g'; 1818 } else { 1819 color = f2(ch1 / 255) + ' g'; 1820 } 1821 } else if (ch4 === undefined || (typeof ch4 === 'undefined' ? 'undefined' : _typeof(ch4)) === 'object') { 1822 // RGB 1823 if (typeof ch1 === 'string') { 1824 color = [ch1, ch2, ch3, 'rg'].join(' '); 1825 } else { 1826 color = [f2(ch1 / 255), f2(ch2 / 255), f2(ch3 / 255), 'rg'].join(' '); 1827 } 1828 if (ch4 && ch4.a === 0) { 1829 //TODO Implement transparency. 1830 //WORKAROUND use white for now 1831 color = ['255', '255', '255', 'rg'].join(' '); 1832 } 1833 } else { 1834 // CMYK 1835 if (typeof ch1 === 'string') { 1836 color = [ch1, ch2, ch3, ch4, 'k'].join(' '); 1837 } else { 1838 color = [f2(ch1), f2(ch2), f2(ch3), f2(ch4), 'k'].join(' '); 1839 } 1840 } 1841 1842 out(color); 1843 return this; 1844 }; 1845 1846 /** 1847 * Sets the text color for upcoming elements. 1848 * If only one, first argument is given, 1849 * treats the value as gray-scale color value. 1850 * 1851 * @param {Number} r Red channel color value in range 0-255 or {String} r color value in hexadecimal, example: '#FFFFFF' 1852 * @param {Number} g Green channel color value in range 0-255 1853 * @param {Number} b Blue channel color value in range 0-255 1854 * @function 1855 * @returns {jsPDF} 1856 * @methodOf jsPDF# 1857 * @name setTextColor 1858 */ 1859 API.setTextColor = function (r, g, b) { 1860 if (typeof r === 'string' && /^#[0-9A-Fa-f]{6}$/.test(r)) { 1861 var hex = parseInt(r.substr(1), 16); 1862 r = hex >> 16 & 255; 1863 g = hex >> 8 & 255; 1864 b = hex & 255; 1865 } 1866 1867 if (r === 0 && g === 0 && b === 0 || typeof g === 'undefined') { 1868 textColor = f3(r / 255) + ' g'; 1869 } else { 1870 textColor = [f3(r / 255), f3(g / 255), f3(b / 255), 'rg'].join(' '); 1871 } 1872 return this; 1873 }; 1874 1875 /** 1876 * Is an Object providing a mapping from human-readable to 1877 * integer flag values designating the varieties of line cap 1878 * and join styles. 1879 * 1880 * @returns {Object} 1881 * @fieldOf jsPDF# 1882 * @name CapJoinStyles 1883 */ 1884 API.CapJoinStyles = { 1885 0: 0, 1886 'butt': 0, 1887 'but': 0, 1888 'miter': 0, 1889 1: 1, 1890 'round': 1, 1891 'rounded': 1, 1892 'circle': 1, 1893 2: 2, 1894 'projecting': 2, 1895 'project': 2, 1896 'square': 2, 1897 'bevel': 2 1898 }; 1899 1900 /** 1901 * Sets the line cap styles 1902 * See {jsPDF.CapJoinStyles} for variants 1903 * 1904 * @param {String|Number} style A string or number identifying the type of line cap 1905 * @function 1906 * @returns {jsPDF} 1907 * @methodOf jsPDF# 1908 * @name setLineCap 1909 */ 1910 API.setLineCap = function (style) { 1911 var id = this.CapJoinStyles[style]; 1912 if (id === undefined) { 1913 throw new Error("Line cap style of '" + style + "' is not recognized. See or extend .CapJoinStyles property for valid styles"); 1914 } 1915 lineCapID = id; 1916 out(id + ' J'); 1917 1918 return this; 1919 }; 1920 1921 /** 1922 * Sets the line join styles 1923 * See {jsPDF.CapJoinStyles} for variants 1924 * 1925 * @param {String|Number} style A string or number identifying the type of line join 1926 * @function 1927 * @returns {jsPDF} 1928 * @methodOf jsPDF# 1929 * @name setLineJoin 1930 */ 1931 API.setLineJoin = function (style) { 1932 var id = this.CapJoinStyles[style]; 1933 if (id === undefined) { 1934 throw new Error("Line join style of '" + style + "' is not recognized. See or extend .CapJoinStyles property for valid styles"); 1935 } 1936 lineJoinID = id; 1937 out(id + ' j'); 1938 1939 return this; 1940 }; 1941 1942 // Output is both an internal (for plugins) and external function 1943 API.output = _output; 1944 1945 /** 1946 * Saves as PDF document. An alias of jsPDF.output('save', 'filename.pdf') 1947 * @param {String} filename The filename including extension. 1948 * 1949 * @function 1950 * @returns {jsPDF} 1951 * @methodOf jsPDF# 1952 * @name save 1953 */ 1954 API.save = function (filename) { 1955 API.output('save', filename); 1956 }; 1957 1958 // applying plugins (more methods) ON TOP of built-in API. 1959 // this is intentional as we allow plugins to override 1960 // built-ins 1961 for (var plugin in jsPDF.API) { 1962 if (jsPDF.API.hasOwnProperty(plugin)) { 1963 if (plugin === 'events' && jsPDF.API.events.length) { 1964 (function (events, newEvents) { 1965 1966 // jsPDF.API.events is a JS Array of Arrays 1967 // where each Array is a pair of event name, handler 1968 // Events were added by plugins to the jsPDF instantiator. 1969 // These are always added to the new instance and some ran 1970 // during instantiation. 1971 var eventname, handler_and_args, i; 1972 1973 for (i = newEvents.length - 1; i !== -1; i--) { 1974 // subscribe takes 3 args: 'topic', function, runonce_flag 1975 // if undefined, runonce is false. 1976 // users can attach callback directly, 1977 // or they can attach an array with [callback, runonce_flag] 1978 // that's what the "apply" magic is for below.
1979 eventname = newEvents[i][0]; 1980 handler_and_args = newEvents[i][1]; 1981 events.subscribe.apply(events, [eventname].concat(typeof handler_and_args === 'function' ? [handler_and_args] : handler_and_args)); 1982 } 1983 })(events, jsPDF.API.events); 1984 } else { 1985 API[plugin] = jsPDF.API[plugin]; 1986 } 1987 } 1988 } 1989 1990 ////////////////////////////////////////////////////// 1991 // continuing initialization of jsPDF Document object 1992 ////////////////////////////////////////////////////// 1993 // Add the first page automatically 1994 addFonts(); 1995 activeFontKey = 'F1'; 1996 _addPage(format, orientation); 1997 1998 events.publish('initialized'); 1999 return API; 2000 } 2001 2002 /** 2003 * jsPDF.API is a STATIC property of jsPDF class. 2004 * jsPDF.API is an object you can add methods and properties to. 2005 * The methods / properties you add will show up in new jsPDF objects. 2006 * 2007 * One property is prepopulated. It is the 'events' Object. Plugin authors can add topics, 2008 * callbacks to this object. These will be reassigned to all new instances of jsPDF. 2009 * Examples: 2010 * jsPDF.API.events['initialized'] = function(){ 'this' is API object } 2011 * jsPDF.API.events['addFont'] = function(added_font_object){ 'this' is API object } 2012 * 2013 * @static 2014 * @public 2015 * @memberOf jsPDF 2016 * @name API 2017 * 2018 * @example 2019 * jsPDF.API.mymethod = function(){ 2020 * // 'this' will be ref to internal API object. see jsPDF source 2021 * // , so you can refer to built-in methods like so: 2022 * // this.line(....) 2023 * // this.text(....) 2024 * } 2025 * var pdfdoc = new jsPDF() 2026 * pdfdoc.mymethod() // <- !!!!!! 2027 */ 2028 jsPDF.API = { events: [] }; 2029 jsPDF.version = "1.3.2 2016-09-30T20:33:17.116Z:jameshall"; 2030 2031 if (typeof define === 'function' && define.amd) { 2032 define('jsPDF', function () { 2033 return jsPDF; 2034 }); 2035 } else if (typeof module !== 'undefined' && module.exports) { 2036 module.exports = jsPDF; 2037 } else { 2038 global.jsPDF = jsPDF; 2039 } 2040 return jsPDF; 2041 }(typeof self !== "undefined" && self || typeof window !== "undefined" && window || undefined); 2042 /*rollup-keeper-start*/window.tmp = jsPDF; 2043 2044 /** 2045 * jsPDF AcroForm Plugin 2046 * Copyright (c) 2016 Alexander Weidt, https://github.com/BiggA94 2047 * 2048 * Licensed under the MIT License. 2049 * http://opensource.org/licenses/mit-license 2050 */ 2051 2052 (window.AcroForm = function (jsPDFAPI) { 2053 'use strict'; 2054 2055 var AcroForm = window.AcroForm; 2056 2057 AcroForm.scale = function (x) { 2058 return x * (acroformPlugin.internal.scaleFactor / 1); // 1 = (96 / 72) 2059 }; 2060 AcroForm.antiScale = function (x) { 2061 return 1 / acroformPlugin.internal.scaleFactor * x; 2062 }; 2063 2064 var acroformPlugin = { 2065 fields: [], 2066 xForms: [], 2067 /** 2068 * acroFormDictionaryRoot contains information about the AcroForm Dictionary 2069 * 0: The Event-Token, the AcroFormDictionaryCallback has 2070 * 1: The Object ID of the Root 2071 */ 2072 acroFormDictionaryRoot: null, 2073 /** 2074 * After the PDF gets evaluated, the reference to the root has to be reset, 2075 * this indicates, whether the root has already been printed out 2076 */ 2077 printedOut: false, 2078 internal: null 2079 }; 2080 2081 jsPDF.API.acroformPlugin = acroformPlugin; 2082 2083 var annotReferenceCallback = function annotReferenceCallback() { 2084 for (var i in this.acroformPlugin.acroFormDictionaryRoot.Fields) { 2085 var formObject = this.acroformPlugin.acroFormDictionaryRoot.Fields[i]; 2086 // add Annot Reference!
2087 if (formObject.hasAnnotation) { 2088 // If theres an Annotation Widget in the Form Object, put the Reference in the /Annot array 2089 createAnnotationReference.call(this, formObject); 2090 } 2091 } 2092 }; 2093 2094 var createAcroForm = function createAcroForm() { 2095 if (this.acroformPlugin.acroFormDictionaryRoot) { 2096 //return; 2097 throw new Error("Exception while creating AcroformDictionary"); 2098 } 2099 2100 // The Object Number of the AcroForm Dictionary 2101 this.acroformPlugin.acroFormDictionaryRoot = new AcroForm.AcroFormDictionary(); 2102 2103 this.acroformPlugin.internal = this.internal; 2104 2105 // add Callback for creating the AcroForm Dictionary 2106 this.acroformPlugin.acroFormDictionaryRoot._eventID = this.internal.events.subscribe('postPutResources', AcroFormDictionaryCallback); 2107 2108 this.internal.events.subscribe('buildDocument', annotReferenceCallback); //buildDocument 2109 2110 // Register event, that is triggered when the DocumentCatalog is written, in order to add /AcroForm 2111 this.internal.events.subscribe('putCatalog', putCatalogCallback); 2112 2113 // Register event, that creates all Fields 2114 this.internal.events.subscribe('postPutPages', createFieldCallback); 2115 }; 2116 2117 /** 2118 * Create the Reference to the widgetAnnotation, so that it gets referenced in the Annot[] int the+ 2119 * (Requires the Annotation Plugin) 2120 */ 2121 var createAnnotationReference = function createAnnotationReference(object) { 2122 var options = { 2123 type: 'reference', 2124 object: object 2125 }; 2126 jsPDF.API.annotationPlugin.annotations[this.internal.getPageInfo(object.page).pageNumber].push(options); 2127 }; 2128 2129 var putForm = function putForm(formObject) { 2130 if (this.acroformPlugin.printedOut) { 2131 this.acroformPlugin.printedOut = false; 2132 this.acroformPlugin.acroFormDictionaryRoot = null; 2133 } 2134 if (!this.acroformPlugin.acroFormDictionaryRoot) { 2135 createAcroForm.call(this); 2136 } 2137 this.acroformPlugin.acroFormDictionaryRoot.Fields.push(formObject); 2138 }; 2139 2140 // Callbacks 2141 2142 var putCatalogCallback = function putCatalogCallback() { 2143 //Put reference to AcroForm to DocumentCatalog 2144 if (typeof this.acroformPlugin.acroFormDictionaryRoot != 'undefined') { 2145 // for safety, shouldn't normally be the case 2146 this.internal.write('/AcroForm ' + this.acroformPlugin.acroFormDictionaryRoot.objId + ' ' + 0 + ' R'); 2147 } else { 2148 console.log('Root missing...'); 2149 } 2150 }; 2151 2152 /** 2153 * Adds /Acroform X 0 R to Document Catalog, 2154 * and creates the AcroForm Dictionary 2155 */ 2156 var AcroFormDictionaryCallback = function AcroFormDictionaryCallback() { 2157 // Remove event 2158 this.internal.events.unsubscribe(this.acroformPlugin.acroFormDictionaryRoot._eventID); 2159 2160 delete this.acroformPlugin.acroFormDictionaryRoot._eventID; 2161 2162 this.acroformPlugin.printedOut = true; 2163 }; 2164 2165 /** 2166 * Creates the single Fields and writes them into the Document 2167 * 2168 * If fieldArray is set, use the fields that are inside it instead of the fields from the AcroRoot 2169 * (for the FormXObjects...) 2170 */ 2171 var createFieldCallback = function createFieldCallback(fieldArray) { 2172 var standardFields = !fieldArray; 2173 2174 if (!fieldArray) { 2175 // in case there is no fieldArray specified, we want to print out the Fields of the AcroForm 2176 // Print out Root 2177 this.internal.newObjectDeferredBegin(this.acroformPlugin.acroFormDictionaryRoot.objId); 2178 this.internal.out(this.acroformPlugin.acroFormDictionaryRoot.getString()); 2179 } 2180 2181 var fieldArray = fieldArray || this.acroformPlugin.acroFormDictionaryRoot.Kids; 2182 2183 for (var i in fieldArray) { 2184 var key = i; 2185 var form = fieldArray[i]; 2186 2187 var oldRect = form.Rect; 2188 2189 if (form.Rect) { 2190 form.Rect = AcroForm.internal.calculateCoordinates.call(this, form.Rect); 2191 } 2192 2193 // Start Writing the Object 2194 this.internal.newObjectDeferredBegin(form.objId); 2195 2196 var content = ""; 2197 content += form.objId + " 0 obj\n"; 2198 2199 content += "<<\n" + form.getContent(); 2200 2201 form.Rect = oldRect; 2202 2203 if (form.hasAppearanceStream && !form.appearanceStreamContent) { 2204 // Calculate Appearance 2205 var appearance = AcroForm.internal.calculateAppearanceStream.call(this, form); 2206 content += "/AP << /N " + appearance + " >>\n"; 2207 2208 this.acroformPlugin.xForms.push(appearance); 2209 } 2210 2211 // Assume AppearanceStreamContent is a Array with N,R,D (at least one of them!) 2212 if (form.appearanceStreamContent) { 2213 content += "/AP << "; 2214 // Iterate over N,R and D 2215 for (var k in form.appearanceStreamContent) { 2216 var value = form.appearanceStreamContent[k]; 2217 content += "/" + k + " "; 2218 content += "<< "; 2219 if (Object.keys(value).length >= 1 || Array.isArray(value)) { 2220 // appearanceStream is an Array or Object! 2221 for (var i in value) { 2222 var obj = value[i]; 2223 if (typeof obj === 'function') { 2224 // if Function is referenced, call it in order to get the FormXObject 2225 obj = obj.call(this, form); 2226 } 2227 content += "/" + i + " " + obj + " "; 2228 2229 // In case the XForm is already used, e.g. OffState of CheckBoxes, don't add it 2230 if (!(this.acroformPlugin.xForms.indexOf(obj) >= 0)) this.acroformPlugin.xForms.push(obj); 2231 } 2232 } else { 2233 var obj = value; 2234 if (typeof obj === 'function') { 2235 // if Function is referenced, call it in order to get the FormXObject 2236 obj = obj.call(this, form); 2237 } 2238 content += "/" + i + " " + obj + " \n"; 2239 if (!(this.acroformPlugin.xForms.indexOf(obj) >= 0)) this.acroformPlugin.xForms.push(obj); 2240 } 2241 content += " >>\n"; 2242 } 2243 2244 // appearance stream is a normal Object.. 2245 content += ">>\n"; 2246 } 2247 2248 content += ">>\nendobj\n"; 2249 2250 this.internal.out(content); 2251 } 2252 if (standardFields) { 2253 createXFormObjectCallback.call(this, this.acroformPlugin.xForms); 2254 } 2255 }; 2256 2257 var createXFormObjectCallback = function createXFormObjectCallback(fieldArray) { 2258 for (var i in fieldArray) { 2259 var key = i; 2260 var form = fieldArray[i]; 2261 // Start Writing the Object 2262 this.internal.newObjectDeferredBegin(form && form.objId); 2263 2264 var content = ""; 2265 content += form ? form.getString() : ''; 2266 this.internal.out(content); 2267 2268 delete fieldArray[key]; 2269 } 2270 }; 2271 2272 // Public: 2273 2274 jsPDFAPI.addField = function (fieldObject) { 2275 //var opt = parseOptions(fieldObject); 2276 if (fieldObject instanceof AcroForm.TextField) { 2277 addTextField.call(this, fieldObject); 2278 } else if (fieldObject instanceof AcroForm.ChoiceField) { 2279 addChoiceField.call(this, fieldObject); 2280 } else if (fieldObject instanceof AcroForm.Button) { 2281 addButton.call(this, fieldObject); 2282 } else if (fieldObject instanceof AcroForm.ChildClass) { 2283 putForm.call(this, fieldObject); 2284 } else if (fieldObject) { 2285 // try to put.. 2286 putForm.call(this, fieldObject); 2287 } 2288 fieldObject.page = this.acroformPlugin.internal.getCurrentPageInfo().pageNumber; 2289 return this; 2290 }; 2291 2292 // ############### sort in: 2293 2294 /** 2295 * Button 2296 * FT = Btn 2297 */ 2298 var addButton = function addButton(options) { 2299 var options = options || new AcroForm.Field(); 2300 2301 options.FT = '/Btn'; 2302 2303 /** 2304 * Calculating the Ff entry: 2305 * 2306 * The Ff entry contains flags, that have to be set bitwise 2307 * In the Following the number in the Comment is the BitPosition 2308 */ 2309 var flags = options.Ff || 0; 2310 2311 // 17, Pushbutton 2312 if (options.pushbutton) { 2313 // Options.pushbutton should be 1 or 0 2314 flags = AcroForm.internal.setBitPosition(flags, 17); 2315 delete options.pushbutton; 2316 } 2317 2318 //16, Radio 2319 if (options.radio) { 2320 //flags = options.Ff | options.radio << 15; 2321 flags = AcroForm.internal.setBitPosition(flags, 16); 2322 delete options.radio; 2323 } 2324 2325 // 15, NoToggleToOff (Radio buttons only 2326 if (options.noToggleToOff) { 2327 //flags = options.Ff | options.noToggleToOff << 14; 2328 flags = AcroForm.internal.setBitPosition(flags, 15); 2329 //delete options.noToggleToOff; 2330 } 2331 2332 // In case, there is no Flag set, it is a check-box 2333 options.Ff = flags; 2334 2335 putForm.call(this, options); 2336 }; 2337 2338 var addTextField = function addTextField(options) { 2339 var options = options || new AcroForm.Field(); 2340 2341 options.FT = '/Tx'; 2342 2343 /** 2344 * Calculating the Ff entry: 2345 * 2346 * The Ff entry contains flags, that have to be set bitwise 2347 * In the Following the number in the Comment is the BitPosition 2348 */ 2349 2350 var flags = options.Ff || 0; 2351 2352 // 13, multiline 2353 if (options.multiline) { 2354 // Set Flag 2355 flags = flags | 1 << 12; 2356 // Remove multiline from FieldObject 2357 //delete options.multiline; 2358 } 2359 2360 // 14, Password 2361 if (options.password) { 2362 flags = flags | 1 << 13; 2363 //delete options.password; 2364 } 2365 2366 // 21, FileSelect, PDF 1.4... 2367 if (options.fileSelect) { 2368 flags = flags | 1 << 20; 2369 //delete options.fileSelect; 2370 } 2371 2372 // 23, DoNotSpellCheck, PDF 1.4... 2373 if (options.doNotSpellCheck) { 2374 flags = flags | 1 << 22; 2375 //delete options.doNotSpellCheck; 2376 } 2377 2378 // 24, DoNotScroll, PDF 1.4... 2379 if (options.doNotScroll) { 2380 flags = flags | 1 << 23; 2381 //delete options.doNotScroll; 2382 } 2383 2384 options.Ff = options.Ff || flags; 2385
2386 // Add field 2387 putForm.call(this, options); 2388 }; 2389 2390 var addChoiceField = function addChoiceField(opt) { 2391 var options = opt || new AcroForm.Field(); 2392 2393 options.FT = '/Ch'; 2394 2395 /** 2396 * Calculating the Ff entry: 2397 * 2398 * The Ff entry contains flags, that have to be set bitwise 2399 * In the Following the number in the Comment is the BitPosition 2400 */ 2401 2402 var flags = options.Ff || 0; 2403 2404 // 18, Combo (If not set, the choiceField is a listBox!!) 2405 if (options.combo) { 2406 // Set Flag 2407 flags = AcroForm.internal.setBitPosition(flags, 18); 2408 // Remove combo from FieldObject 2409 delete options.combo; 2410 } 2411 2412 // 19, Edit 2413 if (options.edit) { 2414 flags = AcroForm.internal.setBitPosition(flags, 19); 2415 delete options.edit; 2416 } 2417 2418 // 20, Sort 2419 if (options.sort) { 2420 flags = AcroForm.internal.setBitPosition(flags, 20); 2421 delete options.sort; 2422 } 2423 2424 // 22, MultiSelect (PDF 1.4) 2425 if (options.multiSelect && this.internal.getPDFVersion() >= 1.4) { 2426 flags = AcroForm.internal.setBitPosition(flags, 22); 2427 delete options.multiSelect; 2428 } 2429 2430 // 23, DoNotSpellCheck (PDF 1.4) 2431 if (options.doNotSpellCheck && this.internal.getPDFVersion() >= 1.4) { 2432 flags = AcroForm.internal.setBitPosition(flags, 23); 2433 delete options.doNotSpellCheck; 2434 } 2435 2436 options.Ff = flags; 2437 2438 //options.hasAnnotation = true; 2439 2440 // Add field 2441 putForm.call(this, options); 2442 }; 2443 })(jsPDF.API); 2444 2445 var AcroForm = window.AcroForm; 2446 2447 AcroForm.internal = {}; 2448 2449 AcroForm.createFormXObject = function (formObject) { 2450 var xobj = new AcroForm.FormXObject(); 2451 var height = AcroForm.Appearance.internal.getHeight(formObject) || 0; 2452 var width = AcroForm.Appearance.internal.getWidth(formObject) || 0; 2453 xobj.BBox = [0, 0, width, height]; 2454 return xobj; 2455 }; 2456 2457 // Contains Methods for creating standard appearances 2458 AcroForm.Appearance = { 2459 CheckBox: { 2460 createAppearanceStream: function createAppearanceStream() { 2461 var appearance = { 2462 N: { 2463 On: AcroForm.Appearance.CheckBox.YesNormal 2464 }, 2465 D: { 2466 On: AcroForm.Appearance.CheckBox.YesPushDown, 2467 Off: AcroForm.Appearance.CheckBox.OffPushDown 2468 } 2469 }; 2470 2471 return appearance; 2472 }, 2473 /** 2474 * If any other icons are needed, the number between the brackets can be changed 2475 * @returns {string} 2476 */ 2477 createMK: function createMK() { 2478 // 3-> Hook 2479 return "<< /CA (3)>>"; 2480 }, 2481 /** 2482 * Returns the standard On Appearance for a CheckBox 2483 * @returns {AcroForm.FormXObject} 2484 */ 2485 YesPushDown: function YesPushDown(formObject) { 2486 var xobj = AcroForm.createFormXObject(formObject); 2487 var stream = ""; 2488 // F13 is ZapfDingbats (Symbolic) 2489 formObject.Q = 1; // set text-alignment as centered 2490 var calcRes = AcroForm.internal.calculateX(formObject, "3", "ZapfDingbats", 50); 2491 stream += "0.749023 g\n\ 2492 0 0 " + AcroForm.Appearance.internal.getWidth(formObject) + " " + AcroForm.Appearance.internal.getHeight(formObject) + " re\n\ 2493 f\n\ 2494 BMC\n\ 2495 q\n\ 2496 0 0 1 rg\n\ 2497 /F13 " + calcRes.fontSize + " Tf 0 g\n\ 2498 BT\n"; 2499 stream += calcRes.text; 2500 stream += "ET\n\ 2501 Q\n\ 2502 EMC\n"; 2503 xobj.stream = stream; 2504 return xobj; 2505 }, 2506 2507 YesNormal: function YesNormal(formObject) {
2508 var xobj = AcroForm.createFormXObject(formObject); 2509 var stream = ""; 2510 formObject.Q = 1; // set text-alignment as centered 2511 var calcRes = AcroForm.internal.calculateX(formObject, "3", "ZapfDingbats", AcroForm.Appearance.internal.getHeight(formObject) * 0.9); 2512 stream += "1 g\n\ 25130 0 " + AcroForm.Appearance.internal.getWidth(formObject) + " " + AcroForm.Appearance.internal.getHeight(formObject) + " re\n\ 2514f\n\ 2515q\n\ 25160 0 1 rg\n\ 25170 0 " + (AcroForm.Appearance.internal.getWidth(formObject) - 1) + " " + (AcroForm.Appearance.internal.getHeight(formObject) - 1) + " re\n\ 2518W\n\ 2519n\n\ 25200 g\n\ 2521BT\n\ 2522/F13 " + calcRes.fontSize + " Tf 0 g\n"; 2523 stream += calcRes.text; 2524 stream += "ET\n\ 2525 Q\n"; 2526 xobj.stream = stream; 2527 return xobj; 2528 }, 2529 2530 /** 2531 * Returns the standard Off Appearance for a CheckBox 2532 * @returns {AcroForm.FormXObject} 2533 */ 2534 OffPushDown: function OffPushDown(formObject) { 2535 var xobj = AcroForm.createFormXObject(formObject); 2536 var stream = ""; 2537 stream += "0.749023 g\n\ 2538 0 0 " + AcroForm.Appearance.internal.getWidth(formObject) + " " + AcroForm.Appearance.internal.getHeight(formObject) + " re\n\ 2539 f\n"; 2540 xobj.stream = stream; 2541 return xobj; 2542 } 2543 }, 2544 2545 RadioButton: { 2546 Circle: { 2547 createAppearanceStream: function createAppearanceStream(name) { 2548 var appearanceStreamContent = { 2549 D: { 2550 'Off': AcroForm.Appearance.RadioButton.Circle.OffPushDown 2551 }, 2552 N: {} 2553 }; 2554 appearanceStreamContent.N[name] = AcroForm.Appearance.RadioButton.Circle.YesNormal; 2555 appearanceStreamContent.D[name] = AcroForm.Appearance.RadioButton.Circle.YesPushDown; 2556 return appearanceStreamContent; 2557 }, 2558 createMK: function createMK() { 2559 return "<< /CA (l)>>"; 2560 }, 2561 2562 YesNormal: function YesNormal(formObject) { 2563 var xobj = AcroForm.createFormXObject(formObject); 2564 var stream = ""; 2565 // Make the Radius of the Circle relative to min(height, width) of formObject 2566 var DotRadius = AcroForm.Appearance.internal.getWidth(formObject) <= AcroForm.Appearance.internal.getHeight(formObject) ? AcroForm.Appearance.internal.getWidth(formObject) / 4 : AcroForm.Appearance.internal.getHeight(formObject) / 4; 2567 // The Borderpadding... 2568 DotRadius *= 0.9; 2569 var c = AcroForm.Appearance.internal.Bezier_C; 2570 /* 2571 The Following is a Circle created with Bezier-Curves. 2572 */ 2573 stream += "q\n\ 25741 0 0 1 " + AcroForm.Appearance.internal.getWidth(formObject) / 2 + " " + AcroForm.Appearance.internal.getHeight(formObject) / 2 + " cm\n\ 2575" + DotRadius + " 0 m\n\ 2576" + DotRadius + " " + DotRadius * c + " " + DotRadius * c + " " + DotRadius + " 0 " + DotRadius + " c\n\ 2577-" + DotRadius * c + " " + DotRadius + " -" + DotRadius + " " + DotRadius * c + " -" + DotRadius + " 0 c\n\ 2578-" + DotRadius + " -" + DotRadius * c + " -" + DotRadius * c + " -" + DotRadius + " 0 -" + DotRadius + " c\n\ 2579" + DotRadius * c + " -" + DotRadius + " " + DotRadius + " -" + DotRadius * c + " " + DotRadius + " 0 c\n\ 2580f\n\ 2581Q\n"; 2582 xobj.stream = stream; 2583 return xobj; 2584 }, 2585 YesPushDown: function YesPushDown(formObject) { 2586 var xobj = AcroForm.createFormXObject(formObject); 2587 var stream = ""; 2588 var DotRadius = AcroForm.Appearance.internal.getWidth(formObject) <= AcroForm.Appearance.internal.getHeight(formObject) ? AcroForm.Appearance.internal.getWidth(formObject) / 4 : AcroForm.Appearance.internal.getHeight(formOb
2588ject) / 4; 2589 // The Borderpadding... 2590 DotRadius *= 0.9; 2591 // Save results for later use; no need to waste processor ticks on doing math 2592 var k = DotRadius * 2; 2593 // var c = AcroForm.Appearance.internal.Bezier_C; 2594 var kc = k * AcroForm.Appearance.internal.Bezier_C; 2595 var dc = DotRadius * AcroForm.Appearance.internal.Bezier_C; 2596 // stream += "0.749023 g\n\ 2597 // q\n\ 2598 // 1 0 0 1 " + AcroForm.Appearance.internal.getWidth(formObject) / 2 + " " + AcroForm.Appearance.internal.getHeight(formObject) / 2 + " cm\n\ 2599 // " + DotRadius * 2 + " 0 m\n\ 2600 // " + DotRadius * 2 + " " + DotRadius * 2 * c + " " + DotRadius * 2 * c + " " + DotRadius * 2 + " 0 " + DotRadius * 2 + " c\n\ 2601 // -" + DotRadius * 2 * c + " " + DotRadius * 2 + " -" + DotRadius * 2 + " " + DotRadius * 2 * c + " -" + DotRadius * 2 + " 0 c\n\ 2602 // -" + DotRadius * 2 + " -" + DotRadius * 2 * c + " -" + DotRadius * 2 * c + " -" + DotRadius * 2 + " 0 -" + DotRadius * 2 + " c\n\ 2603 // " + DotRadius * 2 * c + " -" + DotRadius * 2 + " " + DotRadius * 2 + " -" + DotRadius * 2 * c + " " + DotRadius * 2 + " 0 c\n\ 2604 // f\n\ 2605 // Q\n\ 2606 // 0 g\n\ 2607 // q\n\ 2608 // 1 0 0 1 " + AcroForm.Appearance.internal.getWidth(formObject) / 2 + " " + AcroForm.Appearance.internal.getHeight(formObject) / 2 + " cm\n\ 2609 // " + DotRadius + " 0 m\n\ 2610 // " + DotRadius + " " + DotRadius * c + " " + DotRadius * c + " " + DotRadius + " 0 " + DotRadius + " c\n\ 2611 // -" + DotRadius * c + " " + DotRadius + " -" + DotRadius + " " + DotRadius * c + " -" + DotRadius + " 0 c\n\ 2612 // -" + DotRadius + " -" + DotRadius * c + " -" + DotRadius * c + " -" + DotRadius + " 0 -" + DotRadius + " c\n\ 2613 // " + DotRadius * c + " -" + DotRadius + " " + DotRadius + " -" + DotRadius * c + " " + DotRadius + " 0 c\n\ 2614 // f\n\ 2615 // Q\n"; 2616 2617 // FASTER VERSION with less processor ticks spent on math operations 2618 stream += "0.749023 g\n\ 2619 q\n\ 2620 1 0 0 1 " + AcroForm.Appearance.internal.getWidth(formObject) / 2 + " " + AcroForm.Appearance.internal.getHeight(formObject) / 2 + " cm\n\ 2621" + k + " 0 m\n\ 2622" + k + " " + kc + " " + kc + " " + k + " 0 " + k + " c\n\ 2623-" + kc + " " + k + " -" + k + " " + kc + " -" + k + " 0 c\n\ 2624-" + k + " -" + kc + " -" + kc + " -" + k + " 0 -" + k + " c\n\ 2625" + kc + " -" + k + " " + k + " -" + kc + " " + k + " 0 c\n\ 2626 f\n\ 2627 Q\n\ 2628 0 g\n\ 2629 q\n\ 2630 1 0 0 1 " + AcroForm.Appearance.internal.getWidth(formObject) / 2 + " " + AcroForm.Appearance.internal.getHeight(formObject) / 2 + " cm\n\ 2631" + DotRadius + " 0 m\n\ 2632" + DotRadius + " " + dc + " " + dc + " " + DotRadius + " 0 " + DotRadius + " c\n\ 2633-" + dc + " " + DotRadius + " -" + DotRadius + " " + dc + " -" + DotRadius + " 0 c\n\ 2634-" + DotRadius + " -" + dc + " -" + dc + " -" + DotRadius + " 0 -" + DotRadius + " c\n\ 2635" + dc + " -" + DotRadius + " " + DotRadius + " -" + dc + " " + DotRadius + " 0 c\n\ 2636 f\n\ 2637 Q\n"; 2638 xobj.stream = stream; 2639 return xobj; 2640 }, 2641 OffPushDown: function OffPushDown(formObject) { 2642 var xobj = AcroForm.createFormXObject(formObject); 2643 var stream = ""; 2644 var DotRadius = AcroForm.Appearance.internal.getWidth(formObject) <= AcroForm.Appearance.internal.getHeight(formObject) ? AcroForm.Appearance.internal.getWidth(formObject) / 4 : AcroForm.Appearance.internal.getHeight(formObject) / 4; 2645 // The Borderpadding... 2646 DotRadius *= 0.9; 2647 // Save results for later use; no need to waste processor ticks on doing math 2648 var k = DotRadius * 2; 2649 // var c = AcroForm.Appearance.internal.Bezier_C; 2650 var kc = k * AcroForm.Appearance.internal.Bezier_C; 2651 // stream += "0.749023 g\n\ 2652 // q\n\ 2653 // 1 0 0 1 " + AcroForm.Appearance.internal.getWidth(formObject) / 2 + " " + AcroForm.Appearance.internal.getHeight(formOb
2653ject) / 2 + " cm\n\ 2654 // " + DotRadius * 2 + " 0 m\n\ 2655 // " + DotRadius * 2 + " " + DotRadius * 2 * c + " " + DotRadius * 2 * c + " " + DotRadius * 2 + " 0 " + DotRadius * 2 + " c\n\ 2656 // -" + DotRadius * 2 * c + " " + DotRadius * 2 + " -" + DotRadius * 2 + " " + DotRadius * 2 * c + " -" + DotRadius * 2 + " 0 c\n\ 2657 // -" + DotRadius * 2 + " -" + DotRadius * 2 * c + " -" + DotRadius * 2 * c + " -" + DotRadius * 2 + " 0 -" + DotRadius * 2 + " c\n\ 2658 // " + DotRadius * 2 * c + " -" + DotRadius * 2 + " " + DotRadius * 2 + " -" + DotRadius * 2 * c + " " + DotRadius * 2 + " 0 c\n\ 2659 // f\n\ 2660 // Q\n"; 2661 2662 // FASTER VERSION with less processor ticks spent on math operations 2663 stream += "0.749023 g\n\ 2664 q\n\ 2665 1 0 0 1 " + AcroForm.Appearance.internal.getWidth(formObject) / 2 + " " + AcroForm.Appearance.internal.getHeight(formObject) / 2 + " cm\n\ 2666" + k + " 0 m\n\ 2667" + k + " " + kc + " " + kc + " " + k + " 0 " + k + " c\n\ 2668-" + kc + " " + k + " -" + k + " " + kc + " -" + k + " 0 c\n\ 2669-" + k + " -" + kc + " -" + kc + " -" + k + " 0 -" + k + " c\n\ 2670" + kc + " -" + k + " " + k + " -" + kc + " " + k + " 0 c\n\ 2671 f\n\ 2672 Q\n"; 2673 xobj.stream = stream; 2674 return xobj; 2675 } 2676 }, 2677 2678 Cross: { 2679 /** 2680 * Creates the Actual AppearanceDictionary-References 2681 * @param name 2682 * @returns 2683 */ 2684 createAppearanceStream: function createAppearanceStream(name) { 2685 var appearanceStreamContent = { 2686 D: { 2687 'Off': AcroForm.Appearance.RadioButton.Cross.OffPushDown 2688 }, 2689 N: {} 2690 }; 2691 appearanceStreamContent.N[name] = AcroForm.Appearance.RadioButton.Cross.YesNormal; 2692 appearanceStreamContent.D[name] = AcroForm.Appearance.RadioButton.Cross.YesPushDown; 2693 return appearanceStreamContent; 2694 }, 2695 createMK: function createMK() { 2696 return "<< /CA (8)>>"; 2697 }, 2698 2699 YesNormal: function YesNormal(formObject) { 2700 var xobj = AcroForm.createFormXObject(formObject); 2701 var stream = ""; 2702 var cross = AcroForm.Appearance.internal.calculateCross(formObject); 2703 stream += "q\n\ 2704 1 1 " + (AcroForm.Appearance.internal.getWidth(formObject) - 2) + " " + (AcroForm.Appearance.internal.getHeight(formObject) - 2) + " re\n\ 2705 W\n\ 2706 n\n\ 2707 " + cross.x1.x + " " + cross.x1.y + " m\n\ 2708 " + cross.x2.x + " " + cross.x2.y + " l\n\ 2709 " + cross.x4.x + " " + cross.x4.y + " m\n\ 2710 " + cross.x3.x + " " + cross.x3.y + " l\n\ 2711 s\n\ 2712 Q\n"; 2713 xobj.stream = stream; 2714 return xobj; 2715 }, 2716 YesPushDown: function YesPushDown(formObject) { 2717 var xobj = AcroForm.createFormXObject(formObject); 2718 var cross = AcroForm.Appearance.internal.calculateCross(formObject); 2719 var stream = ""; 2720 stream += "0.749023 g\n\ 2721 0 0 " + AcroForm.Appearance.internal.getWidth(formObject) + " " + AcroForm.Appearance.internal.getHeight(formObject) + " re\n\ 2722 f\n\ 2723 q\n\ 2724 1 1 " + (AcroForm.Appearance.internal.getWidth(formObject) - 2) + " " + (AcroForm.Appearance.internal.getHeight(formObject) - 2) + " re\n\ 2725 W\n\ 2726 n\n\ 2727 " + cross.x1.x + " " + cross.x1.y + " m\n\ 2728 " + cross.x2.x + " " + cross.x2.y + " l\n\ 2729 " + cross.x4.x + " " + cross.x4.y + " m\n\ 2730 " + cross.x3.x + " " + cross.x3.y + " l\n\ 2731 s\n\ 2732 Q\n"; 2733 xobj.stream = stream; 2734 return xobj; 2735 }, 2736 OffPushDown: function OffPushDown(formObject) { 2737 var xobj = AcroForm.createFormXObject(formOb
2737ject); 2738 var stream = ""; 2739 stream += "0.749023 g\n\ 2740 0 0 " + AcroForm.Appearance.internal.getWidth(formObject) + " " + AcroForm.Appearance.internal.getHeight(formObject) + " re\n\ 2741 f\n"; 2742 xobj.stream = stream; 2743 return xobj; 2744 } 2745 } 2746 }, 2747 2748 /** 2749 * Returns the standard Appearance 2750 * @returns {AcroForm.FormXObject} 2751 */ 2752 createDefaultAppearanceStream: function createDefaultAppearanceStream(formObject) { 2753 var stream = ""; 2754 // Set Helvetica to Standard Font (size: auto) 2755 // Color: Black 2756 stream += "/Helv 0 Tf 0 g"; 2757 return stream; 2758 } 2759 }; 2760 2761 AcroForm.Appearance.internal = { 2762 Bezier_C: 0.551915024494, 2763 2764 calculateCross: function calculateCross(formObject) { 2765 var min = function min(x, y) { 2766 return x > y ? y : x; 2767 }; 2768 2769 var width = AcroForm.Appearance.internal.getWidth(formObject); 2770 var height = AcroForm.Appearance.internal.getHeight(formObject); 2771 var a = min(width, height); 2772 var crossSize = a; 2773 var borderPadding = 2; // The Padding in px 2774 2775 2776 var cross = { 2777 x1: { // upperLeft 2778 x: (width - a) / 2, 2779 y: (height - a) / 2 + a }, 2780 x2: { // lowerRight 2781 x: (width - a) / 2 + a, 2782 y: (height - a) / 2 //borderPadding 2783 }, 2784 x3: { // lowerLeft 2785 x: (width - a) / 2, 2786 y: (height - a) / 2 //borderPadding 2787 }, 2788 x4: { // upperRight 2789 x: (width - a) / 2 + a, 2790 y: (height - a) / 2 + a } 2791 }; 2792 2793 return cross; 2794 } 2795 }; 2796 AcroForm.Appearance.internal.getWidth = function (formObject) { 2797 return formObject.Rect[2]; //(formObject.Rect[2] - formObject.Rect[0]) || 0; 2798 }; 2799 AcroForm.Appearance.internal.getHeight = function (formObject) { 2800 return formObject.Rect[3]; //(formObject.Rect[1] - formObject.Rect[3]) || 0; 2801 }; 2802 2803 // ########################## 2804 2805 //### For inheritance: 2806 AcroForm.internal.inherit = function (child, parent) { 2807 var ObjectCreate = Object.create || function (o) { 2808 var F = function F() {}; 2809 F.prototype = o; 2810 return new F(); 2811 }; 2812 child.prototype = Object.create(parent.prototype); 2813 child.prototype.constructor = child; 2814 }; 2815 2816 // ### Handy Functions: 2817 2818 AcroForm.internal.arrayToPdfArray = function (array) { 2819 if (Array.isArray(array)) { 2820 var content = ' ['; 2821 for (var i in array) { 2822 var element = array[i].toString(); 2823 content += element; 2824 content += i < array.length - 1 ? ' ' : ''; 2825 } 2826 content += ']'; 2827 2828 return content; 2829 } 2830 }; 2831 2832 AcroForm.internal.toPdfString = function (string) { 2833 string = string || ""; 2834 2835 // put Bracket at the Beginning of the String 2836 if (string.indexOf('(') !== 0) { 2837 string = '(' + string; 2838 } 2839 2840 if (string.substring(string.length - 1) != ')') { 2841 string += '('; 2842 } 2843 return string; 2844 }; 2845 2846 // ########################## 2847 // Classes 2848 // ########################## 2849 2850 2851 AcroForm.PDFObject = function () { 2852 // The Object ID in the PDF Object Model 2853 // todo 2854 var _objId; 2855 Object.defineProperty(this, 'objId', { 2856 get: function get() { 2857 if (!_objId) { 2858 if (this.internal) { 2859 _objId = this.internal.newObjectDeferred(); 2860 } else if (jsPDF.API.acroformPlugin.internal) { 2861 // todo - find better option, that doesn't rely on a Global Static var 2862 _objId = jsPDF.API.acroformPlugin.internal.newObjectDeferred(); 2863 } 2864 } 2865 if (!_objId) { 2866 console.log("Couldn't create Object ID"); 2867 } 2868 return _objId; 2869 }, 2870 configurable: false 2871 }); 2872 }; 2873 2874 AcroForm.PDFObject.prototype.toString = function () { 2875 return this.objId + " 0 R"; 2876 }; 2877 2878 AcroForm.PDFObject.prototype.getString = function () { 2879 var res = this.objId + " 0 obj\n<<"; 2880 var content = this.getContent(); 2881 2882 res += content + ">>\n"; 2883 if (this.stream) { 2884 res += "stream\n"; 2885 res += this.stream; 2886 res += "endstream\n"; 2887 } 2888 res += "endobj\n"; 2889 return res; 2890 }; 2891 2892 AcroForm.PDFObject.prototype.getContent = function () { 2893 /** 2894 * Prints out all enumerable Variables from the Object 2895 * @param fieldObject 2896 * @returns {string} 2897 */ 2898 var createContentFromFieldObject = function createContentFromFieldObject(fieldObject) { 2899 var content = ''; 2900 2901 var keys = Object.keys(fieldObject).filter(function (key) { 2902 return key != 'content' && key != 'appearanceStreamContent' && key.substring(0, 1) != "_"; 2903 }); 2904 2905 for (var i in keys) { 2906 var key = keys[i];
2907 var value = fieldObject[key]; 2908 2909 /*if (key == 'Rect' && value) { 2910 value = AcroForm.internal.calculateCoordinates.call(jsPDF.API.acroformPlugin.internal, value); 2911 }*/ 2912 2913 if (value) { 2914 if (Array.isArray(value)) { 2915 content += '/' + key + ' ' + AcroForm.internal.arrayToPdfArray(value) + "\n"; 2916 } else if (value instanceof AcroForm.PDFObject) { 2917 // In case it is a reference to another PDFObject, take the referennce number 2918 content += '/' + key + ' ' + value.objId + " 0 R" + "\n"; 2919 } else { 2920 content += '/' + key + ' ' + value + '\n'; 2921 } 2922 } 2923 } 2924 return content; 2925 }; 2926 2927 var object = ""; 2928 2929 object += createContentFromFieldObject(this); 2930 return object; 2931 }; 2932 2933 AcroForm.FormXObject = function () { 2934 AcroForm.PDFObject.call(this); 2935 this.Type = "/XObject"; 2936 this.Subtype = "/Form"; 2937 this.FormType = 1; 2938 this.BBox; 2939 this.Matrix; 2940 this.Resources = "2 0 R"; 2941 this.PieceInfo; 2942 var _stream; 2943 Object.defineProperty(this, 'Length', { 2944 enumerable: true, 2945 get: function get() { 2946 return _stream !== undefined ? _stream.length : 0; 2947 } 2948 }); 2949 Object.defineProperty(this, 'stream', { 2950 enumerable: false, 2951 set: function set(val) { 2952 _stream = val; 2953 }, 2954 get: function get() { 2955 if (_stream) { 2956 return _stream; 2957 } else { 2958 return null; 2959 } 2960 } 2961 }); 2962 }; 2963 2964 AcroForm.internal.inherit(AcroForm.FormXObject, AcroForm.PDFObject); 2965 2966 AcroForm.AcroFormDictionary = function () { 2967 AcroForm.PDFObject.call(this); 2968 var _Kids = []; 2969 Object.defineProperty(this, 'Kids', { 2970 enumerable: false, 2971 configurable: true, 2972 get: function get() { 2973 if (_Kids.length > 0) { 2974 return _Kids; 2975 } else { 2976 return; 2977 } 2978 } 2979 }); 2980 Object.defineProperty(this, 'Fields', { 2981 enumerable: true, 2982 configurable: true, 2983 get: function get() { 2984 return _Kids; 2985 } 2986 }); 2987 // Default Appearance 2988 this.DA; 2989 }; 2990 2991 AcroForm.internal.inherit(AcroForm.AcroFormDictionary, AcroForm.PDFObject); 2992 2993 // ##### The Objects, the User can Create: 2994 2995 2996 // The Field Object contains the Variables, that every Field needs 2997 // Rectangle for Appearance: lower_left_X, lower_left_Y, width, height 2998 AcroForm.Field = function () { 2999 'use strict'; 3000 3001 AcroForm.PDFObject.call(this); 3002 3003 var _Rect; 3004 Object.defineProperty(this, 'Rect', { 3005 enumerable: true, 3006 configurable: false, 3007 get: function get() { 3008 if (!_Rect) { 3009 return; 3010 } 3011 var tmp = _Rect; 3012 //var calculatedRes = AcroForm.internal.calculateCoordinates(_Rect); // do later! 3013 return tmp; 3014 }, 3015 set: function set(val) { 3016 _Rect = val; 3017 } 3018 }); 3019 3020 var _FT = ""; 3021 Object.defineProperty(this, 'FT', { 3022 enumerable: true, 3023 set: function set(val) { 3024 _FT = val; 3025 }, 3026 get: function get() { 3027 return _FT; 3028 } 3029 }); 3030 /** 3031 * The Partial name of the Field Object. 3032 * It has to be unique. 3033 */ 3034 var _T; 3035 3036 Object.defineProperty(this, 'T', { 3037 enumerable: true, 3038 configurable: false, 3039 set: function set(val) { 3040 _T = val; 3041 }, 3042 get: function get() { 3043 if (!_T || _T.length < 1) { 3044 if (this instanceof AcroForm.ChildClass) { 3045 // In case of a Child from a Radio´Group, you don't need a FieldName!!! 3046 return; 3047 } 3048 return "(FieldObject" + AcroForm.Field.FieldNum++ + ")"; 3049 } 3050 if (_T.substring(0, 1) == "(" && _T.substring(_T.length - 1)) { 3051 return _T; 3052 } 3053 return "(" + _T + ")"; 3054 } 3055 }); 3056 3057 var _DA; 3058 // Defines the default appearance (Needed for variable Text) 3059 Object.defineProperty(this, 'DA', { 3060 enumerable: true, 3061 get: function get() { 3062 if (!_DA) { 3063 return; 3064 } 3065 return '(' + _DA + ')'; 3066 }, 3067 set: function set(val) { 3068 _DA = val; 3069 } 3070 }); 3071 3072 var _DV; 3073 // Defines the default value 3074 Object.defineProperty(this, 'DV', { 3075 enumerable: true, 3076 configurable: true, 3077 get: function get() { 3078 if (!_DV) { 3079 return; 3080 } 3081 return _DV; 3082 }, 3083 set: function set(val) { 3084 _DV = val; 3085 } 3086 }); 3087 3088 //this.Type = "/Annot"; 3089 //this.Subtype = "/Widget"; 3090 Object.defineProperty(this, 'Type', { 3091 enumerable: true, 3092 get: function get() { 3093 return this.hasAnnotation ? "/Annot" : null; 3094 } 3095 }); 3096 3097 Object.defineProperty(this, 'Subtype', { 3098 enumerable: true, 3099 get: function get() { 3100 return this.hasAnnotation ? "/Widget" : null; 3101 } 3102 }); 3103 3104 /** 3105 * 3106 * @type {Array} 3107 */ 3108 this.BG; 3109 3110 Object.defineProperty(this, 'hasAnnotation', { 3111 enumerable: false, 3112 get: function get() { 3113 if (this.Rect || this.BC || this.BG) { 3114 return true; 3115 } 3116 return false;
3117 } 3118 }); 3119 3120 Object.defineProperty(this, 'hasAppearanceStream', { 3121 enumerable: false, 3122 configurable: true, 3123 writable: true 3124 }); 3125 3126 Object.defineProperty(this, 'page', { 3127 enumerable: false, 3128 configurable: true, 3129 writable: true 3130 }); 3131 }; 3132 AcroForm.Field.FieldNum = 0; 3133 3134 AcroForm.internal.inherit(AcroForm.Field, AcroForm.PDFObject); 3135 3136 AcroForm.ChoiceField = function () { 3137 AcroForm.Field.call(this); 3138 // Field Type = Choice Field 3139 this.FT = "/Ch"; 3140 // options 3141 this.Opt = []; 3142 this.V = '()'; 3143 // Top Index 3144 this.TI = 0; 3145 /** 3146 * Defines, whether the 3147 * @type {boolean} 3148 */ 3149 this.combo = false; 3150 /** 3151 * Defines, whether the Choice Field is an Edit Field. 3152 * An Edit Field is automatically an Combo Field. 3153 */ 3154 Object.defineProperty(this, 'edit', { 3155 enumerable: true, 3156 set: function set(val) { 3157 if (val == true) { 3158 this._edit = true; 3159 // ComboBox has to be true 3160 this.combo = true; 3161 } else { 3162 this._edit = false; 3163 } 3164 }, 3165 get: function get() { 3166 if (!this._edit) { 3167 return false; 3168 } 3169 return this._edit; 3170 }, 3171 configurable: false 3172 }); 3173 this.hasAppearanceStream = true; 3174 Object.defineProperty(this, 'V', { 3175 get: function get() { 3176 AcroForm.internal.toPdfString(); 3177 } 3178 }); 3179 }; 3180 AcroForm.internal.inherit(AcroForm.ChoiceField, AcroForm.Field); 3181 window["ChoiceField"] = AcroForm.ChoiceField; 3182 3183 AcroForm.ListBox = function () { 3184 AcroForm.ChoiceField.call(this); 3185 //var combo = true; 3186 }; 3187 AcroForm.internal.inherit(AcroForm.ListBox, AcroForm.ChoiceField); 3188 window["ListBox"] = AcroForm.ListBox; 3189 3190 AcroForm.ComboBox = function () { 3191 AcroForm.ListBox.call(this); 3192 this.combo = true; 3193 }; 3194 AcroForm.internal.inherit(AcroForm.ComboBox, AcroForm.ListBox); 3195 window["ComboBox"] = AcroForm.ComboBox; 3196 3197 AcroForm.EditBox = function () { 3198 AcroForm.ComboBox.call(this); 3199 this.edit = true; 3200 }; 3201 AcroForm.internal.inherit(AcroForm.EditBox, AcroForm.ComboBox); 3202 window["EditBox"] = AcroForm.EditBox; 3203 3204 AcroForm.Button = function () { 3205 AcroForm.Field.call(this); 3206 this.FT = "/Btn"; 3207 //this.hasAnnotation = true; 3208 }; 3209 AcroForm.internal.inherit(AcroForm.Button, AcroForm.Field); 3210 window["Button"] = AcroForm.Button; 3211 3212 AcroForm.PushButton = function () { 3213 AcroForm.Button.call(this); 3214 this.pushbutton = true; 3215 }; 3216 AcroForm.internal.inherit(AcroForm.PushButton, AcroForm.Button); 3217 window["PushButton"] = AcroForm.PushButton; 3218 3219 AcroForm.RadioButton = function () { 3220 AcroForm.Button.call(this); 3221 this.radio = true; 3222 var _Kids = []; 3223 Object.defineProperty(this, 'Kids', { 3224 enumerable: true, 3225 get: function get() { 3226 if (_Kids.length > 0) { 3227 return _Kids; 3228 } 3229 } 3230 }); 3231 3232 Object.defineProperty(this, '__Kids', { 3233 get: function get() { 3234 return _Kids; 3235 } 3236 }); 3237 3238 var _noToggleToOff; 3239 3240 Object.defineProperty(this, 'noToggleToOff', { 3241 enumerable: false, 3242 get: function get() { 3243 return _noToggleToOff; 3244 }, 3245 set: function set(val) { 3246 _noToggleToOff = val; 3247 } 3248 }); 3249 3250 //this.hasAnnotation = false; 3251 }; 3252 AcroForm.internal.inherit(AcroForm.RadioButton, AcroForm.Button); 3253 window["RadioButton"] = AcroForm.RadioButton; 3254 3255 /* 3256 * The Child classs of a RadioButton (the radioGroup) 3257 * -> The single Buttons 3258 */ 3259 AcroForm.ChildClass = function (parent, name) { 3260 AcroForm.Field.call(this); 3261 this.Parent = parent; 3262 3263 // todo: set AppearanceType as variable that can be set from the outside... 3264 this._AppearanceType = AcroForm.Appearance.RadioButton.Circle; // The Default appearanceType is the Circle 3265 this.appearanceStreamContent = this._AppearanceType.createAppearanceStream(name); 3266 3267 // Set Print in the Annot Flag
3268 this.F = AcroForm.internal.setBitPosition(this.F, 3, 1); 3269 3270 // Set AppearanceCharacteristicsDictionary with default appearance if field is not interacting with user 3271 this.MK = this._AppearanceType.createMK(); // (8) -> Cross, (1)-> Circle, ()-> nothing 3272 3273 // Default Appearance is Off 3274 this.AS = "/Off"; // + name; 3275 3276 this._Name = name; 3277 }; 3278 AcroForm.internal.inherit(AcroForm.ChildClass, AcroForm.Field); 3279 3280 AcroForm.RadioButton.prototype.setAppearance = function (appearance) { 3281 if (!('createAppearanceStream' in appearance && 'createMK' in appearance)) { 3282 console.log("Couldn't assign Appearance to RadioButton. Appearance was Invalid!"); 3283 return; 3284 } 3285 for (var i in this.__Kids) { 3286 var child = this.__Kids[i]; 3287 3288 child.appearanceStreamContent = appearance.createAppearanceStream(child._Name); 3289 child.MK = appearance.createMK(); 3290 } 3291 }; 3292 3293 AcroForm.RadioButton.prototype.createOption = function (name) { 3294 var parent = this; 3295 var kidCount = this.__Kids.length; 3296 3297 // Create new Child for RadioGroup 3298 var child = new AcroForm.ChildClass(parent, name); 3299 // Add to Parent 3300 this.__Kids.push(child); 3301 3302 jsPDF.API.addField(child); 3303 3304 return child; 3305 }; 3306 3307 AcroForm.CheckBox = function () { 3308 Button.call(this); 3309 this.appearanceStreamContent = AcroForm.Appearance.CheckBox.createAppearanceStream(); 3310 this.MK = AcroForm.Appearance.CheckBox.createMK(); 3311 this.AS = "/On"; 3312 this.V = "/On"; 3313 }; 3314 AcroForm.internal.inherit(AcroForm.CheckBox, AcroForm.Button); 3315 window["CheckBox"] = AcroForm.CheckBox; 3316 3317 AcroForm.TextField = function () { 3318 AcroForm.Field.call(this); 3319 this.DA = AcroForm.Appearance.createDefaultAppearanceStream(); 3320 this.F = 4; 3321 var _V; 3322 Object.defineProperty(this, 'V', { 3323 get: function get() { 3324 if (_V) { 3325 return "(" + _V + ")"; 3326 } else { 3327 return _V; 3328 } 3329 }, 3330 enumerable: true, 3331 set: function set(val) { 3332 _V = val; 3333 } 3334 }); 3335 3336 var _DV; 3337 Object.defineProperty(this, 'DV', { 3338 get: function get() { 3339 if (_DV) { 3340 return "(" + _DV + ")"; 3341 } else { 3342 return _DV; 3343 } 3344 }, 3345 enumerable: true, 3346 set: function set(val) { 3347 _DV = val; 3348 } 3349 }); 3350 3351 var _multiline = false; 3352 Object.defineProperty(this, 'multiline', { 3353 enumerable: false, 3354 get: function get() { 3355 return _multiline; 3356 }, 3357 set: function set(val) { 3358 _multiline = val; 3359 } 3360 }); 3361 3362 //this.multiline = false; 3363 //this.password = false; 3364 /** 3365 * For PDF 1.4 3366 * @type {boolean} 3367 */ 3368 //this.fileSelect = false; 3369 /** 3370 * For PDF 1.4 3371 * @type {boolean} 3372 */ 3373 //this.doNotSpellCheck = false; 3374 /** 3375 * For PDF 1.4 3376 * @type {boolean} 3377 */ 3378 //this.doNotScroll = false; 3379 3380 var _MaxLen = false; 3381 Object.defineProperty(this, 'MaxLen', { 3382 enumerable: true, 3383 get: function get() { 3384 return _MaxLen; 3385 }, 3386 set: function set(val) { 3387 _MaxLen = val; 3388 } 3389 }); 3390 3391 Object.defineProperty(this, 'hasAppearanceStream', { 3392 enumerable: false, 3393 get: function get() { 3394 return this.V || this.DV; 3395 } 3396 }); 3397 }; 3398 AcroForm.internal.inherit(AcroForm.TextField, AcroForm.Field); 3399 window["TextField"] = AcroForm.TextField; 3400 3401 AcroForm.PasswordField = function () { 3402 TextField.call(this); 3403 Object.defineProperty(this, 'password', { 3404 value: true, 3405 enumerable: false, 3406 configurable: false, 3407 writable: false 3408 }); 3409 }; 3410 AcroForm.internal.inherit(AcroForm.PasswordField, AcroForm.TextField); 3411 window["PasswordField"] = AcroForm.PasswordField; 3412 3413 // ############ internal functions 3414 3415 /* 3416 * small workaround for calculating the TextMetric approximately 3417 * @param text 3418 * @param fontsize 3419 * @returns {TextMetrics} (Has Height and Width) 3420 */ 3421 AcroForm.internal.calculateFontSpace = function (text, fontsize, fonttype) { 3422 var fonttype = fonttype || "helvetica"; 3423 //re-use canvas object for speed improvements 3424 var canvas = AcroForm.internal.calculateFontSpace.canvas || (AcroForm.internal.calculateFontSpace.canvas = document.createElement('canvas')); 3425 3426 var context = canvas.getContext('2d'); 3427 context.save(); 3428 var newFont = fontsize + " " + fonttype; 3429 context.font = newFont; 3430 var res = context.measureText(text);
3431 context.fontcolor = 'black'; 3432 // Calculate height: 3433 var context = canvas.getContext('2d'); 3434 res.height = context.measureText("3").width * 1.5; // 3 because in ZapfDingbats its a Hook and a 3 in normal fonts 3435 context.restore(); 3436 3437 var width = res.width; 3438 3439 return res; 3440 }; 3441 3442 AcroForm.internal.calculateX = function (formObject, text, font, maxFontSize) { 3443 var maxFontSize = maxFontSize || 12; 3444 var font = font || "helvetica"; 3445 var returnValue = { 3446 text: "", 3447 fontSize: "" 3448 }; 3449 // Remove Brackets 3450 text = text.substr(0, 1) == '(' ? text.substr(1) : text; 3451 text = text.substr(text.length - 1) == ')' ? text.substr(0, text.length - 1) : text; 3452 // split into array of words 3453 var textSplit = text.split(' '); 3454 3455 /** 3456 * the color could be ((alpha)||(r,g,b)||(c,m,y,k)) 3457 * @type {string} 3458 */ 3459 var color = "0 g\n"; 3460 var fontSize = maxFontSize; // The Starting fontSize (The Maximum) 3461 var lineSpacing = 2; 3462 var borderPadding = 2; 3463 3464 var height = AcroForm.Appearance.internal.getHeight(formObject) || 0; 3465 height = height < 0 ? -height : height; 3466 var width = AcroForm.Appearance.internal.getWidth(formObject) || 0; 3467 width = width < 0 ? -width : width; 3468 3469 var isSmallerThanWidth = function isSmallerThanWidth(i, lastLine, fontSize) { 3470 if (i + 1 < textSplit.length) { 3471 var tmp = lastLine + " " + textSplit[i + 1]; 3472 var TextWidth = AcroForm.internal.calculateFontSpace(tmp, fontSize + "px", font).width; 3473 var FieldWidth = width - 2 * borderPadding; 3474 return TextWidth <= FieldWidth; 3475 } else { 3476 return false; 3477 } 3478 }; 3479 3480 fontSize++; 3481 FontSize: while (true) { 3482 var text = ""; 3483 fontSize--; 3484 var textHeight = AcroForm.internal.calculateFontSpace("3", fontSize + "px", font).height; 3485 var startY = formObject.multiline ? height - fontSize : (height - textHeight) / 2; 3486 startY += lineSpacing; 3487 var startX = -borderPadding; 3488 3489 var lastX = startX, 3490 lastY = startY; 3491 var firstWordInLine = 0, 3492 lastWordInLine = 0; 3493 var lastLength = 0; 3494 3495 var y = 0; 3496 if (fontSize == 0) { 3497 // In case, the Text doesn't fit at all 3498 fontSize = 12; 3499 text = "(...) Tj\n"; 3500 text += "% Width of Text: " + AcroForm.internal.calculateFontSpace(text, "1px").width + ", FieldWidth:" + width + "\n"; 3501 break; 3502 } 3503 3504 lastLength = AcroForm.internal.calculateFontSpace(textSplit[0] + " ", fontSize + "px", font).width; 3505 3506 var lastLine = ""; 3507 var lineCount = 0; 3508 Line: for (var i in textSplit) { 3509 lastLine += textSplit[i] + " "; 3510 // Remove last blank 3511 lastLine = lastLine.substr(lastLine.length - 1) == " " ? lastLine.substr(0, lastLine.length - 1) : lastLine; 3512 var key = parseInt(i); 3513 lastLength = AcroForm.internal.calculateFontSpace(lastLine + " ", fontSize + "px", font).width; 3514 var nextLineIsSmaller = isSmallerThanWidth(key, lastLine, fontSize); 3515 var isLastWord = i >= textSplit.length - 1; 3516 if (nextLineIsSmaller && !isLastWord) { 3517 lastLine += " "; 3518 continue; // Line 3519 } else if (!nextLineIsSmaller && !isLastWord) { 3520 if (!formObject.multiline) { 3521 continue FontSize; 3522 } else { 3523 if ((textHeight + lineSpacing) * (lineCount + 2) + lineSpacing > height) { 3524 // If the Text is higher than the FieldObject 3525 continue FontSize; 3526 } 3527 lastWordInLine = key; 3528 // go on 3529 } 3530 } else if (isLastWord) { 3531 lastWordInLine = key; 3532 } else {
3533 if (formObject.multiline && (textHeight + lineSpacing) * (lineCount + 2) + lineSpacing > height) { 3534 // If the Text is higher than the FieldObject 3535 continue FontSize; 3536 } 3537 } 3538 3539 var line = ''; 3540 3541 for (var x = firstWordInLine; x <= lastWordInLine; x++) { 3542 line += textSplit[x] + ' '; 3543 } 3544 3545 // Remove last blank 3546 line = line.substr(line.length - 1) == " " ? line.substr(0, line.length - 1) : line; 3547 //lastLength -= blankSpace.width; 3548 lastLength = AcroForm.internal.calculateFontSpace(line, fontSize + "px", font).width; 3549 3550 // Calculate startX 3551 switch (formObject.Q) { 3552 case 2: 3553 // Right justified 3554 startX = width - lastLength - borderPadding; 3555 break; 3556 case 1: 3557 // Q = 1 := Text-Alignment: Center 3558 startX = (width - lastLength) / 2; 3559 break; 3560 case 0: 3561 default: 3562 startX = borderPadding; 3563 break; 3564 } 3565 text += startX + ' ' + lastY + ' Td\n'; 3566 text += '(' + line + ') Tj\n'; 3567 // reset X in PDF 3568 text += -startX + ' 0 Td\n'; 3569 3570 // After a Line, adjust y position 3571 lastY = -(fontSize + lineSpacing); 3572 lastX = startX; 3573 3574 // Reset for next iteration step 3575 lastLength = 0; 3576 firstWordInLine = lastWordInLine + 1; 3577 lineCount++; 3578 3579 lastLine = ""; 3580 continue Line; 3581 } 3582 break; 3583 } 3584 3585 returnValue.text = text; 3586 returnValue.fontSize = fontSize; 3587 3588 return returnValue; 3589 }; 3590 3591 AcroForm.internal.calculateAppearanceStream = function (formObject) { 3592 if (formObject.appearanceStreamContent) { 3593 // If appearanceStream is already set, use it 3594 return formObject.appearanceStreamContent; 3595 } 3596 3597 if (!formObject.V && !formObject.DV) { 3598 return; 3599 } 3600 3601 // else calculate it 3602 3603 var stream = ''; 3604 3605 var text = formObject.V || formObject.DV; 3606 3607 var calcRes = AcroForm.internal.calculateX(formObject, text); 3608 3609 stream += '/Tx BMC\n' + 'q\n' + 3610 //color + '\n' + 3611 '/F1 ' + calcRes.fontSize + ' Tf\n' + 3612 // Text Matrix 3613 '1 0 0 1 0 0 Tm\n'; 3614 // Begin Text 3615 stream += 'BT\n'; 3616 stream += calcRes.text; 3617 // End Text 3618 stream += 'ET\n'; 3619 stream += 'Q\n' + 'EMC\n'; 3620 3621 var appearanceStreamContent = new AcroForm.createFormXObject(formObject); 3622 3623 appearanceStreamContent.stream = stream; 3624 3625 var appearance = { 3626 N: { 3627 'Normal': appearanceStreamContent 3628 } 3629 }; 3630 3631 return appearanceStreamContent; 3632 }; 3633 3634 /* 3635 * Converts the Parameters from x,y,w,h to lowerLeftX, lowerLeftY, upperRightX, upperRightY 3636 * @param x 3637 * @param y 3638 * @param w 3639 * @param h 3640 * @returns {*[]} 3641 */ 3642 AcroForm.internal.calculateCoordinates = function (x, y, w, h) { 3643 var coordinates = {}; 3644 3645 if (this.internal) { 3646 var mmtopx = function mmtopx(x) { 3647 return x * this.internal.scaleFactor; 3648 }; 3649 3650 if (Array.isArray(x)) { 3651 x[0] = AcroForm.scale(x[0]); 3652 x[1] = AcroForm.scale(x[1]); 3653 x[2] = AcroForm.scale(x[2]); 3654 x[3] = AcroForm.scale(x[3]); 3655 3656 coordinates.lowerLeft_X = x[0] || 0; 3657 coordinates.lowerLeft_Y = mmtopx.call(this, this.internal.pageSize.height) - x[3] - x[1] || 0; 3658 coordinates.upperRight_X = x[0] + x[2] || 0; 3659 coordinates.upperRight_Y = mmtopx.call(this, this.internal.pageSize.height) - x[1] || 0; 3660 } else {
3661 x = AcroForm.scale(x); 3662 y = AcroForm.scale(y); 3663 w = AcroForm.scale(w); 3664 h = AcroForm.scale(h); 3665 coordinates.lowerLeft_X = x || 0; 3666 coordinates.lowerLeft_Y = this.internal.pageSize.height - y || 0; 3667 coordinates.upperRight_X = x + w || 0; 3668 coordinates.upperRight_Y = this.internal.pageSize.height - y + h || 0; 3669 } 3670 } else { 3671 // old method, that is fallback, if we can't get the pageheight, the coordinate-system starts from lower left 3672 if (Array.isArray(x)) { 3673 coordinates.lowerLeft_X = x[0] || 0; 3674 coordinates.lowerLeft_Y = x[1] || 0; 3675 coordinates.upperRight_X = x[0] + x[2] || 0; 3676 coordinates.upperRight_Y = x[1] + x[3] || 0; 3677 } else { 3678 coordinates.lowerLeft_X = x || 0; 3679 coordinates.lowerLeft_Y = y || 0; 3680 coordinates.upperRight_X = x + w || 0; 3681 coordinates.upperRight_Y = y + h || 0; 3682 } 3683 } 3684 3685 return [coordinates.lowerLeft_X, coordinates.lowerLeft_Y, coordinates.upperRight_X, coordinates.upperRight_Y]; 3686 }; 3687 3688 AcroForm.internal.calculateColor = function (r, g, b) { 3689 var color = new Array(3); 3690 color.r = r | 0; 3691 color.g = g | 0; 3692 color.b = b | 0; 3693 return color; 3694 }; 3695 3696 AcroForm.internal.getBitPosition = function (variable, position) { 3697 variable = variable || 0; 3698 var bitMask = 1; 3699 bitMask = bitMask << position - 1; 3700 return variable | bitMask; 3701 }; 3702 3703 AcroForm.internal.setBitPosition = function (variable, position, value) { 3704 variable = variable || 0; 3705 value = value || 1; 3706 3707 var bitMask = 1; 3708 bitMask = bitMask << position - 1; 3709 3710 if (value == 1) { 3711 // Set the Bit to 1 3712 var variable = variable | bitMask; 3713 } else { 3714 // Set the Bit to 0 3715 var variable = variable & ~bitMask; 3716 } 3717 3718 return variable; 3719 }; 3720 3721 /** 3722 * jsPDF addHTML PlugIn 3723 * Copyright (c) 2014 Diego Casorran 3724 * 3725 * Licensed under the MIT License. 3726 * http://opensource.org/licenses/mit-license 3727 */ 3728 3729 (function (jsPDFAPI) { 3730 'use strict'; 3731 3732 /** 3733 * Renders an HTML element to canvas object which added to the PDF 3734 * 3735 * This PlugIn requires html2canvas: https://github.com/niklasvh/html2canvas 3736 * OR rasterizeHTML: https://github.com/cburgmer/rasterizeHTML.js 3737 * 3738 * @public 3739 * @function 3740 * @param element {Mixed} HTML Element, or anything supported by html2canvas. 3741 * @param x {Number} starting X coordinate in jsPDF instance's declared units. 3742 * @param y {Number} starting Y coordinate in jsPDF instance's declared units. 3743 * @param options {Object} Additional options, check the code below. 3744 * @param callback {Function} to call when the rendering has finished. 3745 * 3746 * NOTE: Every parameter is optional except 'element' and 'callback', in such 3747 * case the image is positioned at 0x0 covering the whole PDF document 3748 * size. Ie, to easily take screenshots of webpages saving them to PDF. 3749 */ 3750 3751 jsPDFAPI.addHTML = function (element, x, y, options, callback) { 3752 'use strict'; 3753 3754 if (typeof html2canvas === 'undefined' && typeof rasterizeHTML === 'undefined') throw new Error('You need either ' + 'https://github.com/niklasvh/html2canvas' + ' or https://github.com/cburgmer/rasterizeHTML.js'); 3755 3756 if (typeof x !== 'number') { 3757 options = x; 3758 callback = y; 3759 } 3760 3761 if (typeof options === 'function') { 3762 callback = options; 3763 options = null; 3764 } 3765 3766 var I = this.internal, 3767 K = I.scaleFactor, 3768 W = I.pageSize.width, 3769 H = I.pageSize.height; 3770 3771 options = options || {}; 3772 options.onrendered = function (obj) { 3773 x = parseInt(x) || 0; 3774 y = parseInt(y) || 0; 3775 var dim = options.dim || {}; 3776 var h = dim.h || 0; 3777 var w = dim.w || Math.min(W, obj.width / K) - x; 3778 3779 var format = 'JPEG'; 3780 if (options.format) format = options.format; 3781 3782 if (obj.height > H && options.pagesplit) { 3783 var crop = function () { 3784 var cy = 0; 3785 while (1) { 3786 var canvas = document.createElement('canvas'); 3787 canvas.width = Math.min(W * K, obj.width); 3788 canvas.height = Math.min(H * K, obj.height - cy); 3789 var ctx = canvas.getContext('2d'); 3790 ctx.drawImage(obj, 0, cy, obj.width, canvas.height, 0, 0, canvas.width, canvas.height); 3791 var args = [canvas, x, cy ? 0 : y, canvas.width / K, canvas.height / K, format, null, 'SLOW']; 3792 this.addImage.apply(this, args); 3793 cy += canvas.height; 3794 if (cy >= obj.height) break; 3795 this.addPage(); 3796 }
3797 callback(w, cy, null, args); 3798 }.bind(this); 3799 if (obj.nodeName === 'CANVAS') { 3800 var img = new Image(); 3801 img.onload = crop; 3802 img.src = obj.toDataURL("image/png"); 3803 obj = img; 3804 } else { 3805 crop(); 3806 } 3807 } else { 3808 var alias = Math.random().toString(35); 3809 var args = [obj, x, y, w, h, format, alias, 'SLOW']; 3810 3811 this.addImage.apply(this, args); 3812 3813 callback(w, h, alias, args); 3814 } 3815 }.bind(this); 3816 3817 if (typeof html2canvas !== 'undefined' && !options.rstz) { 3818 return html2canvas(element, options); 3819 } 3820 3821 if (typeof rasterizeHTML !== 'undefined') { 3822 var meth = 'drawDocument'; 3823 if (typeof element === 'string') { 3824 meth = /^http/.test(element) ? 'drawURL' : 'drawHTML'; 3825 } 3826 options.width = options.width || W * K; 3827 return rasterizeHTML[meth](element, void 0, options).then(function (r) { 3828 options.onrendered(r.image); 3829 }, function (e) { 3830 callback(null, e); 3831 }); 3832 } 3833 3834 return null; 3835 }; 3836 })(jsPDF.API); 3837 3838 /** @preserve 3839 * jsPDF addImage plugin 3840 * Copyright (c) 2012 Jason Siefken, https://github.com/siefkenj/ 3841 * 2013 Chris Dowling, https://github.com/gingerchris 3842 * 2013 Trinh Ho, https://github.com/ineedfat 3843 * 2013 Edwin Alejandro Perez, https://github.com/eaparango 3844 * 2013 Norah Smith, https://github.com/burnburnrocket 3845 * 2014 Diego Casorran, https://github.com/diegocr 3846 * 2014 James Robb, https://github.com/jamesbrobb 3847 * 3848 * 3849 */ 3850 3851 ;(function (jsPDFAPI) { 3852 'use strict'; 3853 3854 var namespace = 'addImage_', 3855 supported_image_types = ['jpeg', 'jpg', 'png']; 3856 3857 // Image functionality ported from pdf.js 3858 var putImage = function putImage(img) { 3859 3860 var objectNumber = this.internal.newObject(), 3861 out = this.internal.write, 3862 putStream = this.internal.putStream; 3863 3864 img['n'] = objectNumber; 3865 3866 out('<</Type /XObject'); 3867 out('/Subtype /Image'); 3868 out('/Width ' + img['w']); 3869 out('/Height ' + img['h']); 3870 if (img['cs'] === this.color_spaces.INDEXED) { 3871 out('/ColorSpace [/Indexed /DeviceRGB ' 3872 // if an indexed png defines more than one colour with transparency, we've created a smask 3873 + (img['pal'].length / 3 - 1) + ' ' + ('smask' in img ? objectNumber + 2 : objectNumber + 1) + ' 0 R]'); 3874 } else { 3875 out('/ColorSpace /' + img['cs']); 3876 if (img['cs'] === this.color_spaces.DEVICE_CMYK) { 3877 out('/Decode [1 0 1 0 1 0 1 0]'); 3878 } 3879 } 3880 out('/BitsPerComponent ' + img['bpc']); 3881 if ('f' in img) { 3882 out('/Filter /' + img['f']); 3883 } 3884 if ('dp' in img) { 3885 out('/DecodeParms <<' + img['dp'] + '>>'); 3886 } 3887 if ('trns' in img && img['trns'].constructor == Array) { 3888 var trns = '', 3889 i = 0, 3890 len = img['trns'].length; 3891 for (; i < len; i++) { 3892 trns += img['trns'][i] + ' ' + img['trns'][i] + ' '; 3893 }out('/Mask [' + trns + ']'); 3894 } 3895 if ('smask' in img) { 3896 out('/SMask ' + (objectNumber + 1) + ' 0 R'); 3897 } 3898 out('/Length ' + img['data'].length + '>>'); 3899 3900 putStream(img['data']); 3901 3902 out('endobj'); 3903 3904 // Soft mask 3905 if ('smask' in img) { 3906 var dp = '/Predictor ' + img['p'] + ' /Colors 1 /BitsPerComponent ' + img['bpc'] + ' /Columns ' + img['w']; 3907 var smask = { 'w': img['w'], 'h': img['h'], 'cs': 'DeviceGray', 'bpc': img['bpc'], 'dp': dp, 'data': img['smask'] }; 3908 if ('f' in img) smask.f = img['f']; 3909 putImage.call(this, smask); 3910 } 3911 3912 //Palette
3913 if (img['cs'] === this.color_spaces.INDEXED) { 3914 3915 this.internal.newObject(); 3916 //out('<< /Filter / ' + img['f'] +' /Length ' + img['pal'].length + '>>'); 3917 //putStream(zlib.compress(img['pal'])); 3918 out('<< /Length ' + img['pal'].length + '>>'); 3919 putStream(this.arrayBufferToBinaryString(new Uint8Array(img['pal']))); 3920 out('endobj'); 3921 } 3922 }, 3923 putResourcesCallback = function putResourcesCallback() { 3924 var images = this.internal.collections[namespace + 'images']; 3925 for (var i in images) { 3926 putImage.call(this, images[i]); 3927 } 3928 }, 3929 putXObjectsDictCallback = function putXObjectsDictCallback() { 3930 var images = this.internal.collections[namespace + 'images'], 3931 out = this.internal.write, 3932 image; 3933 for (var i in images) { 3934 image = images[i]; 3935 out('/I' + image['i'], image['n'], '0', 'R'); 3936 } 3937 }, 3938 checkCompressValue = function checkCompressValue(value) { 3939 if (value && typeof value === 'string') value = value.toUpperCase(); 3940 return value in jsPDFAPI.image_compression ? value : jsPDFAPI.image_compression.NONE; 3941 }, 3942 getImages = function getImages() { 3943 var images = this.internal.collections[namespace + 'images']; 3944 //first run, so initialise stuff 3945 if (!images) { 3946 this.internal.collections[namespace + 'images'] = images = {}; 3947 this.internal.events.subscribe('putResources', putResourcesCallback); 3948 this.internal.events.subscribe('putXobjectDict', putXObjectsDictCallback); 3949 } 3950 3951 return images; 3952 }, 3953 getImageIndex = function getImageIndex(images) { 3954 var imageIndex = 0; 3955 3956 if (images) { 3957 // this is NOT the first time this method is ran on this instance of jsPDF object. 3958 imageIndex = Object.keys ? Object.keys(images).length : function (o) { 3959 var i = 0; 3960 for (var e in o) { 3961 if (o.hasOwnProperty(e)) { 3962 i++; 3963 } 3964 } 3965 return i; 3966 }(images); 3967 } 3968 3969 return imageIndex; 3970 }, 3971 notDefined = function notDefined(value) { 3972 return typeof value === 'undefined' || value === null; 3973 }, 3974 generateAliasFromData = function generateAliasFromData(data) { 3975 return typeof data === 'string' && jsPDFAPI.sHashCode(data); 3976 }, 3977 doesNotSupportImageType = function doesNotSupportImageType(type) { 3978 return supported_image_types.indexOf(type) === -1; 3979 }, 3980 processMethodNotEnabled = function processMethodNotEnabled(type) { 3981 return typeof jsPDFAPI['process' + type.toUpperCase()] !== 'function'; 3982 }, 3983 isDOMElement = function isDOMElement(object) { 3984 return (typeof object === 'undefined' ? 'undefined' : _typeof(object)) === 'object' && object.nodeType === 1; 3985 }, 3986 createDataURIFromElement = function createDataURIFromElement(element, format, angle) { 3987 3988 //if element is an image which uses data url definition, just return the dataurl 3989 if (element.nodeName === 'IMG' && element.hasAttribute('src')) { 3990 var src = '' + element.getAttribute('src'); 3991 if (!angle && src.indexOf('data:image/') === 0) return src; 3992 3993 // only if the user doesn't care about a format 3994 if (!format && /\.png(?:[?#].*)?$/i.test(src)) format = 'png'; 3995 } 3996 3997 if (element.nodeName === 'CANVAS') { 3998 var canvas = element; 3999 } else { 4000 var canvas = document.createElement('canvas'); 4001 canvas.width = element.clientWidth || element.width; 4002 canvas.height = element.clientHeight || element.height; 4003 4004 var ctx = canvas.getContext('2d'); 4005 if (!ctx) { 4006 throw 'addImage requires canvas to be supported by browser.'; 4007 } 4008 if (angle) { 4009 var x, 4010 y, 4011 b, 4012 c, 4013 s, 4014 w, 4015 h, 4016 to_radians = Math.PI / 180, 4017 angleInRadians; 4018 4019 if ((typeof angle === 'undefined' ? 'undefined' : _typeof(angle)) === 'object') { 4020 x = angle.x; 4021 y = angle.y; 4022 b = angle.bg; 4023 angle = angle.angle; 4024 } 4025 angleInRadians = angle * to_radians; 4026 c = Math.abs(Math.cos(angleInRadians)); 4027 s = Math.abs(Math.sin(angleInRadians)); 4028 w = canvas.width; 4029 h = canvas.height; 4030 canvas.width = h * s + w * c; 4031 canvas.height = h * c + w * s; 4032 4033 if (isNaN(x)) x = canvas.width / 2; 4034 if (isNaN(y)) y = canvas.height / 2; 4035 4036 ctx.clearRect(0, 0, canvas.width, canvas.height); 4037 ctx.fillStyle = b || 'white'; 4038 ctx.fillRect(0, 0, canvas.width, canvas.height); 4039 ctx.save(); 4040 ctx.translate(x, y); 4041 ctx.rotate(angleInRadians); 4042 ctx.drawImage(element, -(w / 2), -(h / 2)); 4043 ctx.rotate(-angleInRadians); 4044 ctx.translate(-x, -y);
4045 ctx.restore(); 4046 } else { 4047 ctx.drawImage(element, 0, 0, canvas.width, canvas.height); 4048 } 4049 } 4050 return canvas.toDataURL(('' + format).toLowerCase() == 'png' ? 'image/png' : 'image/jpeg'); 4051 }, 4052 checkImagesForAlias = function checkImagesForAlias(alias, images) { 4053 var cached_info; 4054 if (images) { 4055 for (var e in images) { 4056 if (alias === images[e].alias) { 4057 cached_info = images[e]; 4058 break; 4059 } 4060 } 4061 } 4062 return cached_info; 4063 }, 4064 determineWidthAndHeight = function determineWidthAndHeight(w, h, info) { 4065 if (!w && !h) { 4066 w = -96; 4067 h = -96; 4068 } 4069 if (w < 0) { 4070 w = -1 * info['w'] * 72 / w / this.internal.scaleFactor; 4071 } 4072 if (h < 0) { 4073 h = -1 * info['h'] * 72 / h / this.internal.scaleFactor; 4074 } 4075 if (w === 0) { 4076 w = h * info['w'] / info['h']; 4077 } 4078 if (h === 0) { 4079 h = w * info['h'] / info['w']; 4080 } 4081 4082 return [w, h]; 4083 }, 4084 writeImageToPDF = function writeImageToPDF(x, y, w, h, info, index, images) { 4085 var dims = determineWidthAndHeight.call(this, w, h, info), 4086 coord = this.internal.getCoordinateString, 4087 vcoord = this.internal.getVerticalCoordinateString; 4088 4089 w = dims[0]; 4090 h = dims[1]; 4091 4092 images[index] = info; 4093 4094 this.internal.write('q', coord(w), '0 0', coord(h) // TODO: check if this should be shifted by vcoord 4095 , coord(x), vcoord(y + h), 'cm /I' + info['i'], 'Do Q'); 4096 }; 4097 4098 /** 4099 * COLOR SPACES 4100 */ 4101 jsPDFAPI.color_spaces = { 4102 DEVICE_RGB: 'DeviceRGB', 4103 DEVICE_GRAY: 'DeviceGray', 4104 DEVICE_CMYK: 'DeviceCMYK', 4105 CAL_GREY: 'CalGray', 4106 CAL_RGB: 'CalRGB', 4107 LAB: 'Lab', 4108 ICC_BASED: 'ICCBased', 4109 INDEXED: 'Indexed', 4110 PATTERN: 'Pattern', 4111 SEPARATION: 'Separation', 4112 DEVICE_N: 'DeviceN' 4113 }; 4114 4115 /** 4116 * DECODE METHODS 4117 */ 4118 jsPDFAPI.decode = { 4119 DCT_DECODE: 'DCTDecode', 4120 FLATE_DECODE: 'FlateDecode', 4121 LZW_DECODE: 'LZWDecode', 4122 JPX_DECODE: 'JPXDecode', 4123 JBIG2_DECODE: 'JBIG2Decode', 4124 ASCII85_DECODE: 'ASCII85Decode', 4125 ASCII_HEX_DECODE: 'ASCIIHexDecode', 4126 RUN_LENGTH_DECODE: 'RunLengthDecode', 4127 CCITT_FAX_DECODE: 'CCITTFaxDecode' 4128 }; 4129 4130 /** 4131 * IMAGE COMPRESSION TYPES 4132 */ 4133 jsPDFAPI.image_compression = { 4134 NONE: 'NONE', 4135 FAST: 'FAST', 4136 MEDIUM: 'MEDIUM', 4137 SLOW: 'SLOW' 4138 }; 4139 4140 jsPDFAPI.sHashCode = function (str) { 4141 return Array.prototype.reduce && str.split("").reduce(function (a, b) { 4142 a = (a << 5) - a + b.charCodeAt(0);return a & a; 4143 }, 0); 4144 }; 4145 4146 jsPDFAPI.isString = function (object) { 4147 return typeof object === 'string'; 4148 }; 4149 4150 /** 4151 * Strips out and returns info from a valid base64 data URI 4152 * @param {String[dataURI]} a valid data URI of format 'data:[<MIME-type>][;base64],<data>' 4153 * @returns an Array containing the following 4154 * [0] the complete data URI 4155 * [1] <MIME-type> 4156 * [2] format - the second part of the mime-type i.e 'png' in 'image/png' 4157 * [4] <data> 4158 */ 4159 jsPDFAPI.extractInfoFromBase64DataURI = function (dataURI) { 4160 return (/^data:([\w]+?\/([\w]+?));base64,(.+?)$/g.exec(dataURI) 4161 ); 4162 }; 4163 4164 /** 4165 * Check to see if ArrayBuffer is supported 4166 */ 4167 jsPDFAPI.supportsArrayBuffer = function () { 4168 return typeof ArrayBuffer !== 'undefined' && typeof Uint8Array !== 'undefined'; 4169 }; 4170 4171 /** 4172 * Tests supplied object to determine if ArrayBuffer 4173 * @param {Object[object]} 4174 */ 4175 jsPDFAPI.isArrayBuffer = function (object) { 4176 if (!this.supportsArrayBuffer()) return false;
4177 return object instanceof ArrayBuffer; 4178 }; 4179 4180 /** 4181 * Tests supplied object to determine if it implements the ArrayBufferView (TypedArray) interface 4182 * @param {Object[object]} 4183 */ 4184 jsPDFAPI.isArrayBufferView = function (object) { 4185 if (!this.supportsArrayBuffer()) return false; 4186 if (typeof Uint32Array === 'undefined') return false; 4187 return object instanceof Int8Array || object instanceof Uint8Array || typeof Uint8ClampedArray !== 'undefined' && object instanceof Uint8ClampedArray || object instanceof Int16Array || object instanceof Uint16Array || object instanceof Int32Array || object instanceof Uint32Array || object instanceof Float32Array || object instanceof Float64Array; 4188 }; 4189 4190 /** 4191 * Exactly what it says on the tin 4192 */ 4193 jsPDFAPI.binaryStringToUint8Array = function (binary_string) { 4194 /* 4195 * not sure how efficient this will be will bigger files. Is there a native method? 4196 */ 4197 var len = binary_string.length; 4198 var bytes = new Uint8Array(len); 4199 for (var i = 0; i < len; i++) { 4200 bytes[i] = binary_string.charCodeAt(i); 4201 } 4202 return bytes; 4203 }; 4204 4205 /** 4206 * @see this discussion 4207 * http://stackoverflow.com/questions/6965107/converting-between-strings-and-arraybuffers 4208 * 4209 * As stated, i imagine the method below is highly inefficent for large files. 4210 * 4211 * Also of note from Mozilla, 4212 * 4213 * "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)." 4214 * 4215 * https://developer.mozilla.org/en-US/Add-ons/Code_snippets/StringView 4216 * 4217 * Although i'm strugglig to see how StringView solves this issue? Doesn't appear to be a direct method for conversion? 4218 * 4219 * Async method using Blob and FileReader could be best, but i'm not sure how to fit it into the flow? 4220 */ 4221 jsPDFAPI.arrayBufferToBinaryString = function (buffer) { 4222 /*if('TextDecoder' in window){ 4223 var decoder = new TextDecoder('ascii'); 4224 return decoder.decode(buffer); 4225 }*/ 4226 4227 if (this.isArrayBuffer(buffer)) buffer = new Uint8Array(buffer); 4228 4229 var binary_string = ''; 4230 var len = buffer.byteLength; 4231 for (var i = 0; i < len; i++) { 4232 binary_string += String.fromCharCode(buffer[i]); 4233 } 4234 return binary_string; 4235 /* 4236 * Another solution is the method below - convert array buffer straight to base64 and then use atob 4237 */ 4238 //return atob(this.arrayBufferToBase64(buffer)); 4239 }; 4240 4241 /** 4242 * Converts an ArrayBuffer directly to base64 4243 * 4244 * Taken from here 4245 * 4246 * http://jsperf.com/encoding-xhr-image-data/31 4247 * 4248 * Need to test if this is a better solution for larger files 4249 * 4250 */ 4251 jsPDFAPI.arrayBufferToBase64 = function (arrayBuffer) { 4252 var base64 = ''; 4253 var encodings = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'; 4254 4255 var bytes = new Uint8Array(arrayBuffer); 4256 var byteLength = bytes.byteLength; 4257 var byteRemainder = byteLength % 3; 4258 var mainLength = byteLength - byteRemainder; 4259 4260 var a, b, c, d; 4261 var chunk; 4262 4263 // Main loop deals with bytes in chunks of 3 4264 for (var i = 0; i < mainLength; i = i + 3) { 4265 // Combine the three bytes into a single integer 4266 chunk = bytes[i] << 16 | bytes[i + 1] << 8 | bytes[i + 2]; 4267 4268 // Use bitmasks to extract 6-bit segments from the triplet 4269 a = (chunk & 16515072) >> 18; // 16515072 = (2^6 - 1) << 18 4270 b = (chunk & 258048) >> 12; // 258048 = (2^6 - 1) << 12 4271 c = (chunk & 4032) >> 6; // 4032 = (2^6 - 1) << 6 4272 d = chunk & 63; // 63 = 2^6 - 1 4273 4274 // Convert the raw binary segments to the appropriate ASCII encoding 4275 base64 += encodings[a] + encodings[b] + encodings[c] + encodings[d]; 4276 } 4277 4278 // Deal with the remaining bytes and padding 4279 if (byteRemainder == 1) { 4280 chunk = bytes[mainLength]; 4281 4282 a = (chunk & 252) >> 2; // 252 = (2^6 - 1) << 2 4283 4284 // Set the 4 least significant bits to zero 4285 b = (chunk & 3) << 4; // 3 = 2^2 - 1 4286 4287 base64 += encodings[a] + encodings[b] + '=='; 4288 } else if (byteRemainder == 2) {
4289 chunk = bytes[mainLength] << 8 | bytes[mainLength + 1]; 4290 4291 a = (chunk & 64512) >> 10; // 64512 = (2^6 - 1) << 10 4292 b = (chunk & 1008) >> 4; // 1008 = (2^6 - 1) << 4 4293 4294 // Set the 2 least significant bits to zero 4295 c = (chunk & 15) << 2; // 15 = 2^4 - 1 4296 4297 base64 += encodings[a] + encodings[b] + encodings[c] + '='; 4298 } 4299 4300 return base64; 4301 }; 4302 4303 jsPDFAPI.createImageInfo = function (data, wd, ht, cs, bpc, f, imageIndex, alias, dp, trns, pal, smask, p) { 4304 var info = { 4305 alias: alias, 4306 w: wd, 4307 h: ht, 4308 cs: cs, 4309 bpc: bpc, 4310 i: imageIndex, 4311 data: data 4312 // n: objectNumber will be added by putImage code 4313 }; 4314 4315 if (f) info.f = f; 4316 if (dp) info.dp = dp; 4317 if (trns) info.trns = trns; 4318 if (pal) info.pal = pal; 4319 if (smask) info.smask = smask; 4320 if (p) info.p = p; // predictor parameter for PNG compression 4321 4322 return info; 4323 }; 4324 4325 jsPDFAPI.addImage = function (imageData, format, x, y, w, h, alias, compression, rotation) { 4326 'use strict'; 4327 4328 if (typeof format !== 'string') { 4329 var tmp = h; 4330 h = w; 4331 w = y; 4332 y = x; 4333 x = format; 4334 format = tmp; 4335 } 4336 4337 if ((typeof imageData === 'undefined' ? 'undefined' : _typeof(imageData)) === 'object' && !isDOMElement(imageData) && "imageData" in imageData) { 4338 var options = imageData; 4339 4340 imageData = options.imageData; 4341 format = options.format || format; 4342 x = options.x || x || 0; 4343 y = options.y || y || 0; 4344 w = options.w || w; 4345 h = options.h || h; 4346 alias = options.alias || alias; 4347 compression = options.compression || compression; 4348 rotation = options.rotation || options.angle || rotation; 4349 } 4350 4351 if (isNaN(x) || isNaN(y)) { 4352 console.error('jsPDF.addImage: Invalid coordinates', arguments); 4353 throw new Error('Invalid coordinates passed to jsPDF.addImage'); 4354 } 4355 4356 var images = getImages.call(this), 4357 info; 4358 4359 if (!(info = checkImagesForAlias(imageData, images))) { 4360 var dataAsBinaryString; 4361 4362 if (isDOMElement(imageData)) imageData = createDataURIFromElement(imageData, format, rotation); 4363 4364 if (notDefined(alias)) alias = generateAliasFromData(imageData); 4365 4366 if (!(info = checkImagesForAlias(alias, images))) { 4367 4368 if (this.isString(imageData)) { 4369 4370 var base64Info = this.extractInfoFromBase64DataURI(imageData); 4371 4372 if (base64Info) { 4373 4374 format = base64Info[2]; 4375 imageData = atob(base64Info[3]); //convert to binary string 4376 } else { 4377 4378 if (imageData.charCodeAt(0) === 0x89 && imageData.charCodeAt(1) === 0x50 && imageData.charCodeAt(2) === 0x4e && imageData.charCodeAt(3) === 0x47) format = 'png'; 4379 } 4380 } 4381 format = (format || 'JPEG').toLowerCase(); 4382 4383 if (doesNotSupportImageType(format)) throw new Error('addImage currently only supports formats ' + supported_image_types + ', not \'' + format + '\''); 4384 4385 if (processMethodNotEnabled(format)) throw new Error('please ensure that the plugin for \'' + format + '\' support is added'); 4386 4387 /** 4388 * need to test if it's more efficient to convert all binary strings 4389 * to TypedArray - or should we just leave and process as string? 4390 */ 4391 if (this.supportsArrayBuffer()) { 4392 // no need to convert if imageData is already uint8array 4393 if (!(imageData instanceof Uint8Array)) { 4394 dataAsBinaryString = imageData; 4395 imageData = this.binaryStringToUint8Array(imageData); 4396 } 4397 } 4398
4399 info = this['process' + format.toUpperCase()](imageData, getImageIndex(images), alias, checkCompressValue(compression), dataAsBinaryString); 4400 4401 if (!info) throw new Error('An unkwown error occurred whilst processing the image'); 4402 } 4403 } 4404 4405 writeImageToPDF.call(this, x, y, w, h, info, info.i, images); 4406 4407 return this; 4408 }; 4409 4410 /** 4411 * JPEG SUPPORT 4412 **/ 4413 4414 //takes a string imgData containing the raw bytes of 4415 //a jpeg image and returns [width, height] 4416 //Algorithm from: http://www.64lines.com/jpeg-width-height 4417 var getJpegSize = function getJpegSize(imgData) { 4418 'use strict'; 4419 4420 var width, height, numcomponents; 4421 // Verify we have a valid jpeg header 0xff,0xd8,0xff,0xe0,?,?,'J','F','I','F',0x00 4422 if (!imgData.charCodeAt(0) === 0xff || !imgData.charCodeAt(1) === 0xd8 || !imgData.charCodeAt(2) === 0xff || !imgData.charCodeAt(3) === 0xe0 || !imgData.charCodeAt(6) === 'J'.charCodeAt(0) || !imgData.charCodeAt(7) === 'F'.charCodeAt(0) || !imgData.charCodeAt(8) === 'I'.charCodeAt(0) || !imgData.charCodeAt(9) === 'F'.charCodeAt(0) || !imgData.charCodeAt(10) === 0x00) { 4423 throw new Error('getJpegSize requires a binary string jpeg file'); 4424 } 4425 var blockLength = imgData.charCodeAt(4) * 256 + imgData.charCodeAt(5); 4426 var i = 4, 4427 len = imgData.length; 4428 while (i < len) { 4429 i += blockLength; 4430 if (imgData.charCodeAt(i) !== 0xff) { 4431 throw new Error('getJpegSize could not find the size of the image'); 4432 } 4433 if (imgData.charCodeAt(i + 1) === 0xc0 || //(SOF) Huffman - Baseline DCT 4434 imgData.charCodeAt(i + 1) === 0xc1 || //(SOF) Huffman - Extended sequential DCT 4435 imgData.charCodeAt(i + 1) === 0xc2 || // Progressive DCT (SOF2) 4436 imgData.charCodeAt(i + 1) === 0xc3 || // Spatial (sequential) lossless (SOF3) 4437 imgData.charCodeAt(i + 1) === 0xc4 || // Differential sequential DCT (SOF5) 4438 imgData.charCodeAt(i + 1) === 0xc5 || // Differential progressive DCT (SOF6) 4439 imgData.charCodeAt(i + 1) === 0xc6 || // Differential spatial (SOF7) 4440 imgData.charCodeAt(i + 1) === 0xc7) { 4441 height = imgData.charCodeAt(i + 5) * 256 + imgData.charCodeAt(i + 6); 4442 width = imgData.charCodeAt(i + 7) * 256 + imgData.charCodeAt(i + 8); 4443 numcomponents = imgData.charCodeAt(i + 9); 4444 return [width, height, numcomponents]; 4445 } else { 4446 i += 2; 4447 blockLength = imgData.charCodeAt(i) * 256 + imgData.charCodeAt(i + 1); 4448 } 4449 } 4450 }, 4451 getJpegSizeFromBytes = function getJpegSizeFromBytes(data) { 4452 4453 var hdr = data[0] << 8 | data[1]; 4454 4455 if (hdr !== 0xFFD8) throw new Error('Supplied data is not a JPEG'); 4456 4457 var len = data.length, 4458 block = (data[4] << 8) + data[5], 4459 pos = 4, 4460 bytes, 4461 width, 4462 height, 4463 numcomponents; 4464 4465 while (pos < len) { 4466 pos += block; 4467 bytes = readBytes(data, pos); 4468 block = (bytes[2] << 8) + bytes[3]; 4469 if ((bytes[1] === 0xC0 || bytes[1] === 0xC2) && bytes[0] === 0xFF && block > 7) { 4470 bytes = readBytes(data, pos + 5); 4471 width = (bytes[2] << 8) + bytes[3]; 4472 height = (bytes[0] << 8) + bytes[1]; 4473 numcomponents = bytes[4]; 4474 return { width: width, height: height, numcomponents: numcomponents }; 4475 } 4476 4477 pos += 2; 4478 } 4479 4480 throw new Error('getJpegSizeFromBytes could not find the size of the image'); 4481 }, 4482 readBytes = function readBytes(data, offset) { 4483 return data.subarray(offset, offset + 5); 4484 }; 4485 4486 jsPDFAPI.processJPEG = function (data, index, alias, compression, dataAsBinaryString) { 4487 'use strict'; 4488 4489 var colorSpace = this.color_spaces.DEVICE_RGB, 4490 filter = this.decode.DCT_DECODE, 4491 bpc = 8, 4492 dims; 4493 4494 if (this.isString(data)) { 4495 dims = getJpegSize(data); 4496 return this.createImageInfo(data, dims[0], dims[1], dims[3] == 1 ? this.color_spaces.DEVICE_GRAY : colorSpace, bpc, filter, index, alias); 4497 } 4498 4499 if (this.isArrayBuffer(data)) data = new Uint8Array(data); 4500 4501 if (this.isArrayBufferView(data)) { 4502 4503 dims = getJpegSizeFromBytes(data); 4504 4505 // if we already have a stored binary string rep use that 4506 data = dataAsBinaryString || this.arrayBufferToBinaryString(data); 4507 4508 return this.createImageInfo(data, dims.width, dims.height, dims.numcomponents == 1 ? this.color_spaces.DEVICE_GRAY : colorSpace, bpc, filter, index, alias); 4509 } 4510 4511 return null; 4512 }; 4513
4514 jsPDFAPI.processJPG = function () /*data, index, alias, compression, dataAsBinaryString*/{ 4515 return this.processJPEG.apply(this, arguments); 4516 }; 4517 })(jsPDF.API); 4518 4519 /** 4520 * jsPDF Annotations PlugIn 4521 * Copyright (c) 2014 Steven Spungin (TwelveTone LLC) [email protected] 4522 * 4523 * Licensed under the MIT License. 4524 * http://opensource.org/licenses/mit-license 4525 */ 4526 4527 /** 4528 * There are many types of annotations in a PDF document. Annotations are placed 4529 * on a page at a particular location. They are not 'attached' to an object. 4530 * <br /> 4531 * This plugin current supports <br /> 4532 * <li> Goto Page (set pageNumber and top in options) 4533 * <li> Goto Name (set name and top in options) 4534 * <li> Goto URL (set url in options) 4535 * <p> 4536 * The destination magnification factor can also be specified when goto is a page number or a named destination. (see documentation below) 4537 * (set magFactor in options). XYZ is the default. 4538 * </p> 4539 * <p> 4540 * Links, Text, Popup, and FreeText are supported. 4541 * </p> 4542 * <p> 4543 * Options In PDF spec Not Implemented Yet 4544 * <li> link border 4545 * <li> named target 4546 * <li> page coordinates 4547 * <li> destination page scaling and layout 4548 * <li> actions other than URL and GotoPage 4549 * <li> background / hover actions 4550 * </p> 4551 */ 4552 4553 /* 4554 Destination Magnification Factors 4555 See PDF 1.3 Page 386 for meanings and options 4556 4557 [supported] 4558 XYZ (options; left top zoom) 4559 Fit (no options) 4560 FitH (options: top) 4561 FitV (options: left) 4562 4563 [not supported] 4564 FitR 4565 FitB 4566 FitBH 4567 FitBV 4568 */ 4569 4570 (function (jsPDFAPI) { 4571 'use strict'; 4572 4573 var annotationPlugin = { 4574 4575 /** 4576 * An array of arrays, indexed by <em>pageNumber</em>. 4577 */ 4578 annotations: [], 4579 4580 f2: function f2(number) { 4581 return number.toFixed(2); 4582 }, 4583 4584 notEmpty: function notEmpty(obj) { 4585 if (typeof obj != 'undefined') { 4586 if (obj != '') { 4587 return true; 4588 } 4589 } 4590 } 4591 }; 4592 4593 jsPDF.API.annotationPlugin = annotationPlugin; 4594 4595 jsPDF.API.events.push(['addPage', function (info) { 4596 this.annotationPlugin.annotations[info.pageNumber] = []; 4597 }]); 4598 4599 jsPDFAPI.events.push(['putPage', function (info) { 4600 //TODO store annotations in pageContext so reorder/remove will not affect them. 4601 var pageAnnos = this.annotationPlugin.annotations[info.pageNumber]; 4602 4603 var found = false; 4604 for (var a = 0; a < pageAnnos.length && !found; a++) { 4605 var anno = pageAnnos[a]; 4606 switch (anno.type) { 4607 case 'link': 4608 if (annotationPlugin.notEmpty(anno.options.url) || annotationPlugin.notEmpty(anno.options.pageNumber)) { 4609 found = true; 4610 break; 4611 } 4612 case 'reference': 4613 case 'text': 4614 case 'freetext': 4615 found = true; 4616 break; 4617 } 4618 } 4619 if (found == false) { 4620 return; 4621 } 4622 4623 this.internal.write("/Annots ["); 4624 var f2 = this.annotationPlugin.f2; 4625 var k = this.internal.scaleFactor; 4626 var pageHeight = this.internal.pageSize.height; 4627 var pageInfo = this.internal.getPageInfo(info.pageNumber); 4628 for (var a = 0; a < pageAnnos.length; a++) { 4629 var anno = pageAnnos[a]; 4630 4631 switch (anno.type) { 4632 case 'reference': 4633 // References to Widget Anotations (for AcroForm Fields) 4634 this.internal.write(' ' + anno.object.objId + ' 0 R '); 4635 break; 4636 case 'text': 4637 // Create a an object for both the text and the popup 4638 var objText = this.internal.newAdditionalObject(); 4639 var objPopup = this.internal.newAdditionalObject(); 4640 4641 var title = anno.title || 'Note'; 4642 var rect = "/Rect [" + f2(anno.bounds.x * k) + " " + f2(pageHeight - (anno.bounds.y + anno.bounds.h) * k) + " " + f2((anno.bounds.x + anno.bounds.w) * k) + " " + f2((pageHeight - anno.bounds.y) * k) + "] "; 4643 line = '<</Type /Annot /Subtype /' + 'Text' + ' ' + rect + '/Contents (' + anno.contents + ')'; 4644 line += ' /Popup ' + objPopup.objId + " 0 R"; 4645 line += ' /P ' + pageInfo.objId + " 0 R"; 4646 line += ' /T (' + title + ') >>'; 4647 objText.content = line; 4648 4649 var parent = objText.objId + ' 0 R'; 4650 var popoff = 30; 4651 var rect = "/Rect [" + f2((anno.bounds.x + popoff) * k) + " " + f2(pageHeight - (anno.bounds.y + anno.bounds.h) * k) + " " + f2((anno.bounds.x + anno.bounds.w + popoff) * k) + " " + f2((pageHeight - anno.bounds.y) * k) + "] "; 4652 //var rect2 = "/Rect [" + f2(anno.bounds.x * k) + " " + f2((pageHeight - anno.bounds.y) * k) + " " + f2(anno.bounds.x + anno.bounds.w * k) + " " + f2(pageHeight - (anno.bounds.y + anno.bounds.h) * k) + "] "; 4653 line = '<</Type /Annot /Subtype /' + 'Popup' + ' ' + rect + ' /Parent ' + parent; 4654 if (anno.open) { 4655 line += ' /Open true'; 4656 } 4657 line += ' >>'; 4658 objPopup.content = line; 4659 4660 this.internal.write(objText.objId, '0 R', objPopup.objId, '0 R'); 4661 4662 break; 4663 case 'freetext': 4664 var rect = "/Rect [" + f2(anno.bounds.x * k) + " " + f2((pageHeight - anno.bounds.y) * k) + " " + f2(anno.bounds.x + anno.bounds.w * k) + " " + f2(pageHeight - (anno.bounds.y + anno.bounds.h) * k) + "] "; 4665 var color = anno.color || '#000000'; 4666 line = '<</Type /Annot /Subtype /' + 'FreeText' + ' ' + rect + '/Contents (' + anno.contents + ')'; 4667 line += ' /DS(font: Helvetica,sans-serif 12.0pt; text-align:left; color:#' + color + ')'; 4668 line += ' /Border [0 0 0]'; 4669 line += ' >>'; 4670 this.internal.write(line); 4671 break; 4672 case 'link': 4673 if (anno.options.name) { 4674 var loc = this.annotations._nameMap[anno.options.name]; 4675 anno.options.pageNumber = loc.page; 4676 anno.options.top = loc.y; 4677 } else { 4678 if (!anno.options.top) { 4679 anno.options.top = 0; 4680 } 4681 } 4682 4683 //var pageHeight = this.internal.pageSize.height * this.internal.scaleFactor; 4684 var rect = "/Rect [" + f2(anno.x * k) + " " + f2((pageHeight - anno.y) * k) + " " + f2(anno.x + anno.w * k) + " " + f2(pageHeight - (anno.y + anno.h) * k) + "] "; 4685 4686 var line = ''; 4687 if (anno.options.url) { 4688 line = '<</Type /Annot /Subtype /Link ' + rect + '/Border [0 0 0] /A <</S /URI /URI (' + anno.options.url + ') >>'; 4689 } else if (anno.options.pageNumber) { 4690 // first page is 0 4691 var info = this.internal.getPageInfo(anno.options.pageNumber); 4692 line = '<</Type /Annot /Subtype /Link ' + rect + '/Border [0 0 0] /Dest [' + info.objId + " 0 R"; 4693 anno.options.magFactor = anno.options.magFactor || "XYZ"; 4694 switch (anno.options.magFactor) { 4695 case 'Fit': 4696 line += ' /Fit]'; 4697 break; 4698 case 'FitH': 4699 //anno.options.top = anno.options.top || f2(pageHeight * k); 4700 line += ' /FitH ' + anno.options.top + ']'; 4701 break; 4702 case 'FitV': 4703 anno.options.left = anno.options.left || 0; 4704 line += ' /FitV ' + anno.options.left + ']'; 4705 break; 4706 case 'XYZ': 4707 default: 4708 var top = f2((pageHeight - anno.options.top) * k); // || f2(pageHeight * k); 4709 anno.options.left = anno.options.left || 0; 4710 // 0 or null zoom will not change zoom factor 4711 if (typeof anno.options.zoom === 'undefined') { 4712 anno.options.zoom = 0; 4713 } 4714 line += ' /XYZ ' + anno.options.left + ' ' + top + ' ' + anno.options.zoom + ']'; 4715 break; 4716 } 4717 } else { 4718 // TODO error - should not be here 4719 } 4720 if (line != '') { 4721 line += " >>"; 4722 this.internal.write(line); 4723 } 4724 break; 4725 } 4726 } 4727 this.internal.write("]"); 4728 }]); 4729
4730 jsPDFAPI.createAnnotation = function (options) { 4731 switch (options.type) { 4732 case 'link': 4733 this.link(options.bounds.x, options.bounds.y, options.bounds.w, options.bounds.h, options); 4734 break; 4735 case 'text': 4736 case 'freetext': 4737 this.annotationPlugin.annotations[this.internal.getCurrentPageInfo().pageNumber].push(options); 4738 break; 4739 } 4740 }; 4741 4742 /** 4743 * valid options 4744 * <li> pageNumber or url [required] 4745 * <p>If pageNumber is specified, top and zoom may also be specified</p> 4746 */ 4747 jsPDFAPI.link = function (x, y, w, h, options) { 4748 'use strict'; 4749 4750 this.annotationPlugin.annotations[this.internal.getCurrentPageInfo().pageNumber].push({ 4751 x: x, 4752 y: y, 4753 w: w, 4754 h: h, 4755 options: options, 4756 type: 'link' 4757 }); 4758 }; 4759 4760 /** 4761 * valid options 4762 * <li> pageNumber or url [required] 4763 * <p>If pageNumber is specified, top and zoom may also be specified</p> 4764 */ 4765 jsPDFAPI.link = function (x, y, w, h, options) { 4766 'use strict'; 4767 4768 this.annotationPlugin.annotations[this.internal.getCurrentPageInfo().pageNumber].push({ 4769 x: x, 4770 y: y, 4771 w: w, 4772 h: h, 4773 options: options, 4774 type: 'link' 4775 }); 4776 }; 4777 4778 /** 4779 * Currently only supports single line text. 4780 * Returns the width of the text/link 4781 */ 4782 jsPDFAPI.textWithLink = function (text, x, y, options) { 4783 'use strict'; 4784 4785 var width = this.getTextWidth(text); 4786 var height = this.internal.getLineHeight(); 4787 this.text(text, x, y); 4788 //TODO We really need the text baseline height to do this correctly. 4789 // Or ability to draw text on top, bottom, center, or baseline. 4790 y += height * .2; 4791 this.link(x, y - height, width, height, options); 4792 return width; 4793 }; 4794 4795 //TODO move into external library 4796 jsPDFAPI.getTextWidth = function (text) { 4797 'use strict'; 4798 4799 var fontSize = this.internal.getFontSize(); 4800 var txtWidth = this.getStringUnitWidth(text) * fontSize / this.internal.scaleFactor; 4801 return txtWidth; 4802 }; 4803 4804 //TODO move into external library 4805 jsPDFAPI.getLineHeight = function () { 4806 return this.internal.getLineHeight(); 4807 }; 4808 4809 return this; 4810 })(jsPDF.API); 4811 4812 /** 4813 * jsPDF Autoprint Plugin 4814 * 4815 * Licensed under the MIT License. 4816 * http://opensource.org/licenses/mit-license 4817 */ 4818 4819 (function (jsPDFAPI) { 4820 'use strict'; 4821 4822 jsPDFAPI.autoPrint = function () { 4823 'use strict'; 4824 4825 var refAutoPrintTag; 4826 4827 this.internal.events.subscribe('postPutResources', function () { 4828 refAutoPrintTag = this.internal.newObject(); 4829 this.internal.write("<< /S/Named /Type/Action /N/Print >>", "endobj"); 4830 }); 4831 4832 this.internal.events.subscribe("putCatalog", function () { 4833 this.internal.write("/OpenAction " + refAutoPrintTag + " 0" + " R"); 4834 }); 4835 return this; 4836 }; 4837 })(jsPDF.API); 4838 4839 /** 4840 * jsPDF Canvas PlugIn 4841 * Copyright (c) 2014 Steven Spungin (TwelveTone LLC) [email protected] 4842 * 4843 * Licensed under the MIT License. 4844 * http://opensource.org/licenses/mit-license 4845 */ 4846 4847 /** 4848 * This plugin mimics the HTML5 Canvas 4849 * 4850 * The goal is to provide a way for current canvas users to print directly to a PDF. 4851 */ 4852 4853 (function (jsPDFAPI) { 4854 'use strict'; 4855 4856 jsPDFAPI.events.push(['initialized', function () { 4857 this.canvas.pdf = this; 4858 }]); 4859 4860 jsPDFAPI.canvas = { 4861 getContext: function getContext(name) { 4862 this.pdf.context2d._canvas = this; 4863 return this.pdf.context2d; 4864 }, 4865 style: {} 4866 }; 4867
4868 Object.defineProperty(jsPDFAPI.canvas, 'width', { 4869 get: function get() { 4870 return this._width; 4871 }, 4872 set: function set(value) { 4873 this._width = value; 4874 this.getContext('2d').pageWrapX = value + 1; 4875 } 4876 }); 4877 4878 Object.defineProperty(jsPDFAPI.canvas, 'height', { 4879 get: function get() { 4880 return this._height; 4881 }, 4882 set: function set(value) { 4883 this._height = value; 4884 this.getContext('2d').pageWrapY = value + 1; 4885 } 4886 }); 4887 4888 return this; 4889 })(jsPDF.API); 4890 4891 /** ==================================================================== 4892 * jsPDF Cell plugin 4893 * Copyright (c) 2013 Youssef Beddad, [email protected] 4894 * 2013 Eduardo Menezes de Morais, [email protected] 4895 * 2013 Lee Driscoll, https://github.com/lsdriscoll 4896 * 2014 Juan Pablo Gaviria, https://github.com/juanpgaviria 4897 * 2014 James Hall, [email protected] 4898 * 2014 Diego Casorran, https://github.com/diegocr 4899 * 4900 * 4901 * ==================================================================== 4902 */ 4903 4904 (function (jsPDFAPI) { 4905 'use strict'; 4906 /*jslint browser:true */ 4907 /*global document: false, jsPDF */ 4908 4909 var fontName, 4910 fontSize, 4911 fontStyle, 4912 padding = 3, 4913 margin = 13, 4914 headerFunction, 4915 lastCellPos = { x: undefined, y: undefined, w: undefined, h: undefined, ln: undefined }, 4916 pages = 1, 4917 setLastCellPosition = function setLastCellPosition(x, y, w, h, ln) { 4918 lastCellPos = { 'x': x, 'y': y, 'w': w, 'h': h, 'ln': ln }; 4919 }, 4920 getLastCellPosition = function getLastCellPosition() { 4921 return lastCellPos; 4922 }, 4923 NO_MARGINS = { left: 0, top: 0, bottom: 0 }; 4924 4925 jsPDFAPI.setHeaderFunction = function (func) { 4926 headerFunction = func; 4927 }; 4928 4929 jsPDFAPI.getTextDimensions = function (txt) { 4930 fontName = this.internal.getFont().fontName; 4931 fontSize = this.table_font_size || this.internal.getFontSize(); 4932 fontStyle = this.internal.getFont().fontStyle; 4933 // 1 pixel = 0.264583 mm and 1 mm = 72/25.4 point 4934 var px2pt = 0.264583 * 72 / 25.4, 4935 dimensions, 4936 text; 4937 4938 text = document.createElement('font'); 4939 text.id = "jsPDFCell"; 4940 4941 try { 4942 text.style.fontStyle = fontStyle; 4943 } catch (e) { 4944 text.style.fontWeight = fontStyle; 4945 } 4946 4947 text.style.fontName = fontName; 4948 text.style.fontSize = fontSize + 'pt'; 4949 try { 4950 text.textContent = txt; 4951 } catch (e) { 4952 text.innerText = txt; 4953 } 4954 4955 document.body.appendChild(text); 4956 4957 dimensions = { w: (text.offsetWidth + 1) * px2pt, h: (text.offsetHeight + 1) * px2pt }; 4958 4959 document.body.removeChild(text); 4960 4961 return dimensions; 4962 }; 4963 4964 jsPDFAPI.cellAddPage = function () { 4965 var margins = this.margins || NO_MARGINS; 4966 4967 this.addPage(); 4968 4969 setLastCellPosition(margins.left, margins.top, undefined, undefined); 4970 //setLastCellPosition(undefined, undefined, undefined, undefined, undefined); 4971 pages += 1; 4972 }; 4973 4974 jsPDFAPI.cellInitialize = function () { 4975 lastCellPos = { x: undefined, y: undefined, w: undefined, h: undefined, ln: undefined }; 4976 pages = 1; 4977 }; 4978 4979 jsPDFAPI.cell = function (x, y, w, h, txt, ln, align) { 4980 var curCell = getLastCellPosition(); 4981 var pgAdded = false; 4982 4983 // If this is not the first cell, we must change its position 4984 if (curCell.ln !== undefined) { 4985 if (curCell.ln === ln) { 4986 //Same line 4987 x = curCell.x + curCell.w; 4988 y = curCell.y; 4989 } else { 4990 //New line 4991 var margins = this.margins || NO_MARGINS; 4992 if (curCell.y + curCell.h + h + margin >= this.internal.pageSize.height - margins.bottom) { 4993 this.cellAddPage(); 4994 pgAdded = true; 4995 if (this.printHeaders && this.tableHeaderRow) { 4996 this.printHeaderRow(ln, true); 4997 } 4998 } 4999 //We ignore the passed y: the lines may have different heights 5000 y = getLastCellPosition().y + getLastCellPosition().h; 5001 if (pgAdded) y = margin + 10; 5002 } 5003 } 5004 5005 if (txt[0] !== undefined) { 5006 if (this.printingHeaderRow) { 5007 this.rect(x, y, w, h, 'FD'); 5008 } else { 5009 this.rect(x, y, w, h); 5010 } 5011 if (align === 'right') { 5012 if (!(txt instanceof Array)) { 5013 txt = [txt]; 5014 } 5015 for (var i = 0; i < txt.length; i++) { 5016 var currentLine = txt[i];
5017 var textSize = this.getStringUnitWidth(currentLine) * this.internal.getFontSize(); 5018 this.text(currentLine, x + w - textSize - padding, y + this.internal.getLineHeight() * (i + 1)); 5019 } 5020 } else { 5021 this.text(txt, x + padding, y + this.internal.getLineHeight()); 5022 } 5023 } 5024 setLastCellPosition(x, y, w, h, ln); 5025 return this; 5026 }; 5027 5028 /** 5029 * Return the maximum value from an array 5030 * @param array 5031 * @param comparisonFn 5032 * @returns {*} 5033 */ 5034 jsPDFAPI.arrayMax = function (array, comparisonFn) { 5035 var max = array[0], 5036 i, 5037 ln, 5038 item; 5039 5040 for (i = 0, ln = array.length; i < ln; i += 1) { 5041 item = array[i]; 5042 5043 if (comparisonFn) { 5044 if (comparisonFn(max, item) === -1) { 5045 max = item; 5046 } 5047 } else { 5048 if (item > max) { 5049 max = item; 5050 } 5051 } 5052 } 5053 5054 return max; 5055 }; 5056 5057 /** 5058 * Create a table from a set of data. 5059 * @param {Integer} [x] : left-position for top-left corner of table 5060 * @param {Integer} [y] top-position for top-left corner of table 5061 * @param {Object[]} [data] As array of objects containing key-value pairs corresponding to a row of data. 5062 * @param {String[]} [headers] Omit or null to auto-generate headers at a performance cost 5063 * @param {Object} [config.printHeaders] True to print column headers at the top of every page 5064 * @param {Object} [config.autoSize] True to dynamically set the column widths to match the widest cell value 5065 * @param {Object} [config.margins] margin values for left, top, bottom, and width 5066 * @param {Object} [config.fontSize] Integer fontSize to use (optional) 5067 */ 5068 5069 jsPDFAPI.table = function (x, y, data, headers, config) { 5070 if (!data) { 5071 throw 'No data for PDF table'; 5072 } 5073 5074 var headerNames = [], 5075 headerPrompts = [], 5076 header, 5077 i, 5078 ln, 5079 cln, 5080 columnMatrix = {}, 5081 columnWidths = {}, 5082 columnData, 5083 column, 5084 columnMinWidths = [], 5085 j, 5086 tableHeaderConfigs = [], 5087 model, 5088 jln, 5089 func, 5090 5091 5092 //set up defaults. If a value is provided in config, defaults will be overwritten: 5093 autoSize = false, 5094 printHeaders = true, 5095 fontSize = 12, 5096 margins = NO_MARGINS; 5097 5098 margins.width = this.internal.pageSize.width; 5099 5100 if (config) { 5101 //override config defaults if the user has specified non-default behavior: 5102 if (config.autoSize === true) { 5103 autoSize = true; 5104 } 5105 if (config.printHeaders === false) { 5106 printHeaders = false; 5107 } 5108 if (config.fontSize) { 5109 fontSize = config.fontSize; 5110 } 5111 if (config.css && typeof config.css['font-size'] !== "undefined") { 5112 fontSize = config.css['font-size'] * 16; 5113 } 5114 if (config.margins) { 5115 margins = config.margins; 5116 } 5117 } 5118 5119 /** 5120 * @property {Number} lnMod 5121 * Keep track of the current line number modifier used when creating cells 5122 */ 5123 this.lnMod = 0; 5124 lastCellPos = { x: undefined, y: undefined, w: undefined, h: undefined, ln: undefined }, pages = 1; 5125 5126 this.printHeaders = printHeaders; 5127 this.margins = margins; 5128 this.setFontSize(fontSize); 5129 this.table_font_size = fontSize; 5130 5131 // Set header values 5132 if (headers === undefined || headers === null) { 5133 // No headers defined so we derive from data 5134 headerNames = Object.keys(data[0]); 5135 } else if (headers[0] && typeof headers[0] !== 'string') { 5136 var px2pt = 0.264583 * 72 / 25.4; 5137 5138 // Split header configs into names and prompts 5139 for (i = 0, ln = headers.length; i < ln; i += 1) { 5140 header = headers[i]; 5141 headerNames.push(header.name); 5142 headerPrompts.push(header.prompt);
5143 columnWidths[header.name] = header.width * px2pt; 5144 } 5145 } else { 5146 headerNames = headers; 5147 } 5148 5149 if (autoSize) { 5150 // Create a matrix of columns e.g., {column_title: [row1_Record, row2_Record]} 5151 func = function func(rec) { 5152 return rec[header]; 5153 }; 5154 5155 for (i = 0, ln = headerNames.length; i < ln; i += 1) { 5156 header = headerNames[i]; 5157 5158 columnMatrix[header] = data.map(func); 5159 5160 // get header width 5161 columnMinWidths.push(this.getTextDimensions(headerPrompts[i] || header).w); 5162 column = columnMatrix[header]; 5163 5164 // get cell widths 5165 for (j = 0, cln = column.length; j < cln; j += 1) { 5166 columnData = column[j]; 5167 columnMinWidths.push(this.getTextDimensions(columnData).w); 5168 } 5169 5170 // get final column width 5171 columnWidths[header] = jsPDFAPI.arrayMax(columnMinWidths); 5172 5173 //have to reset 5174 columnMinWidths = []; 5175 } 5176 } 5177 5178 // -- Construct the table 5179 5180 if (printHeaders) { 5181 var lineHeight = this.calculateLineHeight(headerNames, columnWidths, headerPrompts.length ? headerPrompts : headerNames); 5182 5183 // Construct the header row 5184 for (i = 0, ln = headerNames.length; i < ln; i += 1) { 5185 header = headerNames[i]; 5186 tableHeaderConfigs.push([x, y, columnWidths[header], lineHeight, String(headerPrompts.length ? headerPrompts[i] : header)]); 5187 } 5188 5189 // Store the table header config 5190 this.setTableHeaderRow(tableHeaderConfigs); 5191 5192 // Print the header for the start of the table 5193 this.printHeaderRow(1, false); 5194 } 5195 5196 // Construct the data rows 5197 for (i = 0, ln = data.length; i < ln; i += 1) { 5198 var lineHeight; 5199 model = data[i]; 5200 lineHeight = this.calculateLineHeight(headerNames, columnWidths, model); 5201 5202 for (j = 0, jln = headerNames.length; j < jln; j += 1) { 5203 header = headerNames[j]; 5204 this.cell(x, y, columnWidths[header], lineHeight, model[header], i + 2, header.align); 5205 } 5206 } 5207 this.lastCellPos = lastCellPos; 5208 this.table_x = x; 5209 this.table_y = y; 5210 return this; 5211 }; 5212 /** 5213 * Calculate the height for containing the highest column 5214 * @param {String[]} headerNames is the header, used as keys to the data 5215 * @param {Integer[]} columnWidths is size of each column 5216 * @param {Object[]} model is the line of data we want to calculate the height of 5217 */ 5218 jsPDFAPI.calculateLineHeight = function (headerNames, columnWidths, model) { 5219 var header, 5220 lineHeight = 0; 5221 for (var j = 0; j < headerNames.length; j++) { 5222 header = headerNames[j]; 5223 model[header] = this.splitTextToSize(String(model[header]), columnWidths[header] - padding); 5224 var h = this.internal.getLineHeight() * model[header].length + padding; 5225 if (h > lineHeight) lineHeight = h; 5226 } 5227 return lineHeight; 5228 }; 5229 5230 /** 5231 * Store the config for outputting a table header 5232 * @param {Object[]} config 5233 * An array of cell configs that would define a header row: Each config matches the config used by jsPDFAPI.cell 5234 * except the ln parameter is excluded 5235 */ 5236 jsPDFAPI.setTableHeaderRow = function (config) { 5237 this.tableHeaderRow = config; 5238 }; 5239 5240 /** 5241 * Output the store header row 5242 * @param lineNumber The line number to output the header at 5243 */ 5244 jsPDFAPI.printHeaderRow = function (lineNumber, new_page) { 5245 if (!this.tableHeaderRow) { 5246 throw 'Property tableHeaderRow does not exist.'; 5247 } 5248 5249 var tableHeaderCell, tmpArray, i, ln; 5250 5251 this.printingHeaderRow = true; 5252 if (headerFunction !== undefined) { 5253 var position = headerFunction(this, pages); 5254 setLastCellPosition(position[0], position[1], position[2], position[3], -1); 5255 } 5256 this.setFontStyle('bold'); 5257 var tempHeaderConf = []; 5258 for (i = 0, ln = this.tableHeaderRow.length; i < ln; i += 1) { 5259 this.setFillColor(200, 200, 200); 5260 5261 tableHeaderCell = this.tableHeaderRow[i]; 5262 if (new_page) { 5263 this.margins.top = margin; 5264 tableHeaderCell[1] = this.margins && this.margins.top || 0; 5265 tempHeaderConf.push(tableHeaderCell); 5266 } 5267 tmpArray = [].concat(tableHeaderCell);
5268 this.cell.apply(this, tmpArray.concat(lineNumber)); 5269 } 5270 if (tempHeaderConf.length > 0) { 5271 this.setTableHeaderRow(tempHeaderConf); 5272 } 5273 this.setFontStyle('normal'); 5274 this.printingHeaderRow = false; 5275 }; 5276 })(jsPDF.API); 5277 5278 /** 5279 * jsPDF Context2D PlugIn Copyright (c) 2014 Steven Spungin (TwelveTone LLC) [email protected] 5280 * 5281 * Licensed under the MIT License. http://opensource.org/licenses/mit-license 5282 */ 5283 5284 /** 5285 * This plugin mimics the HTML5 Canvas's context2d. 5286 * 5287 * The goal is to provide a way for current canvas implementations to print directly to a PDF. 5288 */ 5289 5290 /** 5291 * TODO implement stroke opacity (refactor from fill() method ) 5292 * TODO transform angle and radii parameters 5293 */ 5294 5295 /** 5296 * require('jspdf.js'); require('lib/css_colors.js'); 5297 */ 5298 5299 (function (jsPDFAPI) { 5300 'use strict'; 5301 5302 jsPDFAPI.events.push(['initialized', function () { 5303 this.context2d.pdf = this; 5304 this.context2d.internal.pdf = this; 5305 this.context2d.ctx = new context(); 5306 this.context2d.ctxStack = []; 5307 this.context2d.path = []; 5308 }]); 5309 5310 jsPDFAPI.context2d = { 5311 pageWrapXEnabled: false, 5312 pageWrapYEnabled: false, 5313 pageWrapX: 9999999, 5314 pageWrapY: 9999999, 5315 ctx: new context(), 5316 f2: function f2(number) { 5317 return number.toFixed(2); 5318 }, 5319 5320 fillRect: function fillRect(x, y, w, h) { 5321 if (this._isFillTransparent()) { 5322 return; 5323 } 5324 x = this._wrapX(x); 5325 y = this._wrapY(y); 5326 5327 var xRect = this._matrix_map_rect(this.ctx._transform, { x: x, y: y, w: w, h: h }); 5328 this.pdf.rect(xRect.x, xRect.y, xRect.w, xRect.h, "f"); 5329 }, 5330 5331 strokeRect: function strokeRect(x, y, w, h) {
5332 if (this._isStrokeTransparent()) { 5333 return; 5334 } 5335 x = this._wrapX(x); 5336 y = this._wrapY(y); 5337 5338 var xRect = this._matrix_map_rect(this.ctx._transform, { x: x, y: y, w: w, h: h }); 5339 this.pdf.rect(xRect.x, xRect.y, xRect.w, xRect.h, "s"); 5340 }, 5341 5342 /** 5343 * We cannot clear PDF commands that were already written to PDF, so we use white instead. <br /> 5344 * As a special case, read a special flag (ignoreClearRect) and do nothing if it is set. 5345 * This results in all calls to clearRect() to do nothing, and keep the canvas transparent. 5346 * This flag is stored in the save/restore context and is managed the same way as other drawing states. 5347 * @param x 5348 * @param y 5349 * @param w 5350 * @param h 5351 */ 5352 clearRect: function clearRect(x, y, w, h) { 5353 if (this.ctx.ignoreClearRect) { 5354 return; 5355 } 5356 5357 x = this._wrapX(x); 5358 y = this._wrapY(y); 5359 5360 var xRect = this._matrix_map_rect(this.ctx._transform, { x: x, y: y, w: w, h: h }); 5361 this.save(); 5362 this.setFillStyle('#ffffff'); 5363 //TODO This is hack to fill with white. 5364 this.pdf.rect(xRect.x, xRect.y, xRect.w, xRect.h, "f"); 5365 this.restore(); 5366 }, 5367 5368 save: function save() { 5369 this.ctx._fontSize = this.pdf.internal.getFontSize(); 5370 var ctx = new context(); 5371 ctx.copy(this.ctx); 5372 this.ctxStack.push(this.ctx); 5373 this.ctx = ctx; 5374 }, 5375 5376 restore: function restore() { 5377 this.ctx = this.ctxStack.pop(); 5378 this.setFillStyle(this.ctx.fillStyle); 5379 this.setStrokeStyle(this.ctx.strokeStyle); 5380 this.setFont(this.ctx.font); 5381 this.pdf.setFontSize(this.ctx._fontSize); 5382 this.setLineCap(this.ctx.lineCap); 5383 this.setLineWidth(this.ctx.lineWidth); 5384 this.setLineJoin(this.ctx.lineJoin); 5385 }, 5386 5387 rect: function rect(x, y, w, h) { 5388 this.moveTo(x, y); 5389 this.lineTo(x + w, y); 5390 this.lineTo(x + w, y + h); 5391 this.lineTo(x, y + h); 5392 this.lineTo(x, y); //TODO not needed 5393 this.closePath(); 5394 }, 5395 5396 beginPath: function beginPath() { 5397 this.path = []; 5398 }, 5399 5400 closePath: function closePath() { 5401 this.path.push({ 5402 type: 'close' 5403 }); 5404 }, 5405 5406 _getRgba: function _getRgba(style) { 5407 // get the decimal values of r, g, and b; 5408 var rgba = {}; 5409 5410 if (this.internal.rxTransparent.test(style)) { 5411 rgba.r = 0; 5412 rgba.g = 0; 5413 rgba.b = 0; 5414 rgba.a = 0; 5415 } else { 5416 var m = this.internal.rxRgb.exec(style); 5417 if (m != null) { 5418 rgba.r = parseInt(m[1]); 5419 rgba.g = parseInt(m[2]); 5420 rgba.b = parseInt(m[3]); 5421 rgba.a = 1; 5422 } else { 5423 m = this.internal.rxRgba.exec(style); 5424 if (m != null) { 5425 rgba.r = parseInt(m[1]); 5426 rgba.g = parseInt(m[2]); 5427 rgba.b = parseInt(m[3]); 5428 rgba.a = parseFloat(m[4]); 5429 } else { 5430 rgba.a = 1; 5431 if (style.charAt(0) != '#') { 5432 style = CssColors.colorNameToHex(style); 5433 if (!style) { 5434 style = '#000000'; 5435 } 5436 } else {} 5437 5438 if (style.length === 4) { 5439 rgba.r = style.substring(1, 2); 5440 rgba.r += r; 5441 rgba.g = style.substring(2, 3); 5442 rgba.g += g; 5443 rgba.b = style.substring(3, 4); 5444 rgba.b += b; 5445 } else { 5446 rgba.r = style.substring(1, 3); 5447 rgba.g = style.substring(3, 5); 5448 rgba.b = style.substring(5, 7); 5449 } 5450 rgba.r = parseInt(rgba.r, 16); 5451 rgba.g = parseInt(rgba.g, 16); 5452 rgba.b = parseInt(rgba.b, 16); 5453 } 5454 } 5455 } 5456 rgba.style = style; 5457 return rgba; 5458 }, 5459 5460 setFillStyle: function setFillStyle(style) { 5461 // get the decimal values of r, g, and b; 5462 var r, g, b, a; 5463 5464 if (this.internal.rxTransparent.test(style)) { 5465 r = 0; 5466 g = 0; 5467 b = 0; 5468 a = 0; 5469 } else { 5470 var m = this.internal.rxRgb.exec(style); 5471 if (m != null) { 5472 r = parseInt(m[1]); 5473 g = parseInt(m[2]); 5474 b = parseInt(m[3]); 5475 a = 1; 5476 } else { 5477 m = this.internal.rxRgba.exec(style); 5478 if (m != null) { 5479 r = parseInt(m[1]); 5480 g = parseInt(m[2]); 5481 b = parseInt(m[3]); 5482 a = parseFloat(m[4]); 5483 } else { 5484 a = 1; 5485 if (style.charAt(0) != '#') { 5486 style = CssColors.colorNameToHex(style); 5487 if (!style) { 5488 style = '#000000'; 5489 } 5490 } else {} 5491 5492 if (style.length === 4) { 5493 r = style.substring(1, 2); 5494 r += r; 5495 g = style.substring(2, 3); 5496 g += g; 5497 b = style.substring(3, 4); 5498 b += b; 5499 } else { 5500 r = style.substring(1, 3); 5501 g = style.substring(3, 5); 5502 b = style.substring(5, 7); 5503 } 5504 r = parseInt(r, 16); 5505 g = parseInt(g, 16); 5506 b = parseInt(b, 16); 5507 } 5508 } 5509 } 5510 5511 this.ctx.fillStyle = style; 5512 this.ctx._isFillTransparent = a == 0; 5513 this.ctx._fillOpacity = a; 5514 5515 this.pdf.setFillColor(r, g, b, { 5516 a: a 5517 }); 5518 this.pdf.setTextColor(r, g, b, { 5519 a: a 5520 }); 5521 }, 5522 5523 setStrokeStyle: function setStrokeStyle(style) { 5524 var rgba = this._getRgba(style); 5525 5526 this.ctx.strokeStyle = rgba.style; 5527 this.ctx._isStrokeTransparent = rgba.a == 0; 5528 this.ctx._strokeOpacity = rgba.a; 5529 5530 //TODO jsPDF to handle rgba 5531 if (rgba.a === 0) { 5532 this.pdf.setDrawColor(255, 255, 255); 5533 } else if (rgba.a === 1) { 5534 this.pdf.setDrawColor(rgba.r, rgba.g, rgba.b); 5535 } else { 5536 //this.pdf.setDrawColor(rgba.r, rgba.g, rgba.b, {a: rgba.a}); 5537 this.pdf.setDrawColor(rgba.r, rgba.g, rgba.b); 5538 } 5539 }, 5540 5541 fillText: function fillText(text, x, y, maxWidth) {
5542 if (this._isFillTransparent()) { 5543 return; 5544 } 5545 x = this._wrapX(x); 5546 y = this._wrapY(y); 5547 5548 var xpt = this._matrix_map_point(this.ctx._transform, [x, y]); 5549 x = xpt[0]; 5550 y = xpt[1]; 5551 var rads = this._matrix_rotation(this.ctx._transform); 5552 var degs = rads * 57.2958; 5553 5554 //TODO only push the clip if it has not been applied to the current PDF context 5555 if (this.ctx._clip_path.length > 0) { 5556 var lines; 5557 if (window.outIntercept) { 5558 lines = window.outIntercept.type === 'group' ? window.outIntercept.stream : window.outIntercept; 5559 } else { 5560 lines = this.pdf.internal.pages[1]; 5561 } 5562 lines.push("q"); 5563 var origPath = this.path; 5564 this.path = this.ctx._clip_path; 5565 this.ctx._clip_path = []; 5566 this._fill(null, true); 5567 this.ctx._clip_path = this.path; 5568 this.path = origPath; 5569 } 5570 5571 this.pdf.text(text, x, this._getBaseline(y), null, degs); 5572 5573 if (this.ctx._clip_path.length > 0) { 5574 lines.push('Q'); 5575 } 5576 }, 5577 5578 strokeText: function strokeText(text, x, y, maxWidth) {
5579 if (this._isStrokeTransparent()) { 5580 return; 5581 } 5582 x = this._wrapX(x); 5583 y = this._wrapY(y); 5584 5585 var xpt = this._matrix_map_point(this.ctx._transform, [x, y]); 5586 x = xpt[0]; 5587 y = xpt[1]; 5588 var rads = this._matrix_rotation(this.ctx._transform); 5589 var degs = rads * 57.2958; 5590 5591 //TODO only push the clip if it has not been applied to the current PDF context 5592 if (this.ctx._clip_path.length > 0) { 5593 var lines; 5594 if (window.outIntercept) { 5595 lines = window.outIntercept.type === 'group' ? window.outIntercept.stream : window.outIntercept; 5596 } else { 5597 lines = this.pdf.internal.pages[1]; 5598 } 5599 lines.push("q"); 5600 var origPath = this.path; 5601 this.path = this.ctx._clip_path; 5602 this.ctx._clip_path = []; 5603 this._fill(null, true); 5604 this.ctx._clip_path = this.path; 5605 this.path = origPath; 5606 } 5607 5608 this.pdf.text(text, x, this._getBaseline(y), { 5609 stroke: true 5610 }, degs); 5611 5612 if (this.ctx._clip_path.length > 0) { 5613 lines.push('Q'); 5614 } 5615 }, 5616 5617 setFont: function setFont(font) { 5618 this.ctx.font = font; 5619 5620 //var rx = /\s*(\w+)\s+(\w+)\s+(\w+)\s+([\d\.]+)(px|pt|em)\s+["']?(\w+)['"]?/; 5621 var rx = /\s*(\w+)\s+(\w+)\s+(\w+)\s+([\d\.]+)(px|pt|em)\s+(.*)?/; 5622 m = rx.exec(font); 5623 if (m != null) { 5624 var fontStyle = m[1]; 5625 var fontVariant = m[2]; 5626 var fontWeight = m[3]; 5627 var fontSize = m[4]; 5628 var fontSizeUnit = m[5]; 5629 var fontFamily = m[6]; 5630 5631 if ('px' === fontSizeUnit) { 5632 fontSize = Math.floor(parseFloat(fontSize)); 5633 // fontSize = fontSize * 1.25; 5634 } else if ('em' === fontSizeUnit) { 5635 fontSize = Math.floor(parseFloat(fontSize) * this.pdf.getFontSize()); 5636 } else { 5637 fontSize = Math.floor(parseFloat(fontSize)); 5638 } 5639 5640 this.pdf.setFontSize(fontSize); 5641 5642 if (fontWeight === 'bold' || fontWeight === '700') { 5643 this.pdf.setFontStyle('bold'); 5644 } else { 5645 if (fontStyle === 'italic') { 5646 this.pdf.setFontStyle('italic'); 5647 } else { 5648 this.pdf.setFontStyle('normal'); 5649 } 5650 } 5651 5652 var name = fontFamily; 5653 var parts = name.toLowerCase().split(/\s*,\s*/); 5654 var jsPdfFontName; 5655 5656 if (parts.indexOf('arial') != -1) { 5657 jsPdfFontName = 'Arial'; 5658 } else if (parts.indexOf('verdana') != -1) { 5659 jsPdfFontName = 'Verdana'; 5660 } else if (parts.indexOf('helvetica') != -1) { 5661 jsPdfFontName = 'Helvetica'; 5662 } else if (parts.indexOf('sans-serif') != -1) { 5663 jsPdfFontName = 'sans-serif'; 5664 } else if (parts.indexOf('fixed') != -1) { 5665 jsPdfFontName = 'Fixed'; 5666 } else if (parts.indexOf('monospace') != -1) { 5667 jsPdfFontName = 'Monospace'; 5668 } else if (parts.indexOf('terminal') != -1) { 5669 jsPdfFontName = 'Terminal'; 5670 } else if (parts.indexOf('courier') != -1) { 5671 jsPdfFontName = 'Courier'; 5672 } else if (parts.indexOf('times') != -1) { 5673 jsPdfFontName = 'Times'; 5674 } else if (parts.indexOf('cursive') != -1) { 5675 jsPdfFontName = 'Cursive'; 5676 } else if (parts.indexOf('fantasy') != -1) { 5677 jsPdfFontName = 'Fantasy'; 5678 } else if (parts.indexOf('serif') != -1) { 5679 jsPdfFontName = 'Serif'; 5680 } else { 5681 jsPdfFontName = 'Serif'; 5682 } 5683 5684 //TODO check more cases 5685 var style; 5686 if ('bold' === fontWeight) { 5687 style = 'bold'; 5688 } else { 5689 style = 'normal'; 5690 } 5691 5692 this.pdf.setFont(jsPdfFontName, style); 5693 } else { 5694 var rx = /(\d+)(pt|px|em)\s+(\w+)\s*(\w+)?/; 5695 var m = rx.exec(font); 5696 if (m != null) { 5697 var size = m[1]; 5698 var unit = m[2]; 5699 var name = m[3]; 5700 var style = m[4]; 5701 if (!style) { 5702 style = 'normal'; 5703 } 5704 if ('em' === fontSizeUnit) { 5705 size = Math.floor(parseFloat(fontSize) * this.pdf.getFontSize()); 5706 } else { 5707 size = Math.floor(parseFloat(size)); 5708 } 5709 this.pdf.setFontSize(size); 5710 this.pdf.setFont(name, style); 5711 } 5712 } 5713 }, 5714 5715 setTextBaseline: function setTextBaseline(baseline) { 5716 this.ctx.textBaseline = baseline; 5717 }, 5718 5719 getTextBaseline: function getTextBaseline() { 5720 return this.ctx.textBaseline; 5721 }, 5722 5723 //TODO implement textAlign 5724 setTextAlign: function setTextAlign(align) { 5725 this.ctx.textAlign = align; 5726 }, 5727 5728 getTextAlign: function getTextAlign() { 5729 return this.ctx.textAlign; 5730 }, 5731 5732 setLineWidth: function setLineWidth(width) { 5733 this.ctx.lineWidth = width; 5734 this.pdf.setLineWidth(width); 5735 }, 5736 5737 setLineCap: function setLineCap(style) { 5738 this.ctx.lineCap = style; 5739 this.pdf.setLineCap(style); 5740 }, 5741 5742 setLineJoin: function setLineJoin(style) { 5743 this.ctx.lineJoin = style; 5744 this.pdf.setLineJoin(style); 5745 }, 5746 5747 moveTo: function moveTo(x, y) { 5748 x = this._wrapX(x); 5749 y = this._wrapY(y); 5750 5751 var xpt = this._matrix_map_point(this.ctx._transform, [x, y]); 5752 x = xpt[0]; 5753 y = xpt[1]; 5754 5755 var obj = { 5756 type: 'mt', 5757 x: x, 5758 y: y 5759 }; 5760 this.path.push(obj); 5761 }, 5762 5763 _wrapX: function _wrapX(x) { 5764 if (this.pageWrapXEnabled) { 5765 return x % this.pageWrapX; 5766 } else { 5767 return x; 5768 } 5769 }, 5770 5771 _wrapY: function _wrapY(y) { 5772 if (this.pageWrapYEnabled) { 5773 this._gotoPage(this._page(y)); 5774 return (y - this.lastBreak) % this.pageWrapY; 5775 } else { 5776 return y; 5777 } 5778 }, 5779 5780 transform: function transform(a, b, c, d, e, f) { 5781 //TODO apply to current transformation instead of replacing 5782 this.ctx._transform = [a, b, c, d, e, f]; 5783 }, 5784 5785 setTransform: function setTransform(a, b, c, d, e, f) { 5786 this.ctx._transform = [a, b, c, d, e, f]; 5787 }, 5788 5789 _getTransform: function _getTransform() { 5790 return this.ctx._transform; 5791 }, 5792 5793 lastBreak: 0, 5794 // Y Position of page breaks. 5795 pageBreaks: [], 5796 // returns: One-based Page Number 5797 // Should only be used if pageWrapYEnabled is true 5798 _page: function _page(y) { 5799 if (this.pageWrapYEnabled) { 5800 this.lastBreak = 0; 5801 var manualBreaks = 0; 5802 var autoBreaks = 0; 5803 for (var i = 0; i < this.pageBreaks.length; i++) { 5804 if (y >= this.pageBreaks[i]) { 5805 manualBreaks++; 5806 if (this.lastBreak === 0) { 5807 autoBreaks++; 5808 } 5809 var spaceBetweenLastBreak = this.pageBreaks[i] - this.lastBreak; 5810 this.lastBreak = this.pageBreaks[i]; 5811 var pagesSinceLastBreak = Math.floor(spaceBetweenLastBreak / this.pageWrapY); 5812 autoBreaks += pagesSinceLastBreak; 5813 } 5814 } 5815 if (this.lastBreak === 0) { 5816 var pagesSinceLastBreak = Math.floor(y / this.pageWrapY) + 1; 5817 autoBreaks += pagesSinceLastBreak; 5818 } 5819 return autoBreaks + manualBreaks; 5820 } else { 5821 return this.pdf.internal.getCurrentPageInfo().pageNumber; 5822 } 5823 }, 5824 5825 _gotoPage: function _gotoPage(pageOneBased) { 5826 // This is a stub to be overriden if needed 5827 }, 5828 5829 lineTo: function lineTo(x, y) { 5830 x = this._wrapX(x); 5831 y = this._wrapY(y); 5832 5833 var xpt = this._matrix_map_point(this.ctx._transform, [x, y]); 5834 x = xpt[0]; 5835 y = xpt[1]; 5836 5837 var obj = { 5838 type: 'lt', 5839 x: x, 5840 y: y 5841 }; 5842 this.path.push(obj); 5843 }, 5844 5845 bezierCurveTo: function bezierCurveTo(x1, y1, x2, y2, x, y) { 5846 x1 = this._wrapX(x1); 5847 y1 = this._wrapY(y1); 5848 x2 = this._wrapX(x2); 5849 y2 = this._wrapY(y2); 5850 x = this._wrapX(x); 5851 y = this._wrapY(y); 5852 5853 var xpt; 5854 xpt = this._matrix_map_point(this.ctx._transform, [x, y]); 5855 x = xpt[0]; 5856 y = xpt[1]; 5857 xpt = this._matrix_map_point(this.ctx._transform, [x1, y1]); 5858 x1 = xpt[0]; 5859 y1 = xpt[1]; 5860 xpt = this._matrix_map_point(this.ctx._transform, [x2, y2]); 5861 x2 = xpt[0]; 5862 y2 = xpt[1]; 5863 5864 var obj = { 5865 type: 'bct', 5866 x1: x1, 5867 y1: y1, 5868 x2: x2, 5869 y2: y2, 5870 x: x, 5871 y: y 5872 }; 5873 this.path.push(obj); 5874 }, 5875 5876 quadraticCurveTo: function quadraticCurveTo(x1, y1, x, y) { 5877 x1 = this._wrapX(x1); 5878 y1 = this._wrapY(y1); 5879 x = this._wrapX(x); 5880 y = this._wrapY(y); 5881 5882 var xpt; 5883 xpt = this._matrix_map_point(this.ctx._transform, [x, y]); 5884 x = xpt[0]; 5885 y = xpt[1]; 5886 xpt = this._matrix_map_point(this.ctx._transform, [x1, y1]); 5887 x1 = xpt[0]; 5888 y1 = xpt[1]; 5889 5890 var obj = { 5891 type: 'qct', 5892 x1: x1, 5893 y1: y1, 5894 x: x, 5895 y: y 5896 }; 5897 this.path.push(obj); 5898 }, 5899 5900 arc: function arc(x, y, radius, startAngle, endAngle, anticlockwise) { 5901 x = this._wrapX(x); 5902 y = this._wrapY(y); 5903 5904 var xpt = this._matrix_map_point(this.ctx._transform, [x, y]); 5905 x = xpt[0]; 5906 y = xpt[1]; 5907 5908 var obj = { 5909 type: 'arc', 5910 x: x, 5911 y: y, 5912 radius: radius, 5913 startAngle: startAngle, 5914 endAngle: endAngle, 5915 anticlockwise: anticlockwise 5916 }; 5917 this.path.push(obj); 5918 }, 5919 5920 drawImage: function drawImage(img, x, y, w, h, x2, y2, w2, h2) { 5921 if (x2 !== undefined) { 5922 x = x2; 5923 y = y2; 5924 w = w2; 5925 h = h2; 5926 } 5927 x = this._wrapX(x); 5928 y = this._wrapY(y); 5929 5930 var xRect = this._matrix_map_rect(this.ctx._transform, { x: x, y: y, w: w, h: h }); 5931 var xRect2 = this._matrix_map_rect(this.ctx._transform, { x: x2, y: y2, w: w2, h: h2 }); 5932 5933 // TODO implement source clipping and image scaling 5934 var format; 5935 var rx = /data:image\/(\w+).*/i; 5936 var m = rx.exec(img); 5937 if (m != null) { 5938 format = m[1]; 5939 } else { 5940 // format = "jpeg"; 5941 format = "png"; 5942 } 5943 5944 this.pdf.addImage(img, format, xRect.x, xRect.y, xRect.w, xRect.h); 5945 }, 5946 5947 /** 5948 * Multiply the first matrix by the second 5949 * @param m1 5950 * @param m2 5951 * @returns {*[]} 5952 * @private 5953 */ 5954 _matrix_multiply: function _matrix_multiply(m2, m1) { 5955 var sx = m1[0]; 5956 var shy = m1[1]; 5957 var shx = m1[2]; 5958 var sy = m1[3]; 5959 var tx = m1[4]; 5960 var ty = m1[5]; 5961 5962 var t0 = sx * m2[0] + shy * m2[2]; 5963 var t2 = shx * m2[0] + sy * m2[2]; 5964 var t4 = tx * m2[0] + ty * m2[2] + m2[4]; 5965 shy = sx * m2[1] + shy * m2[3]; 5966 sy = shx * m2[1] + sy * m2[3]; 5967 ty = tx * m2[1] + ty * m2[3] + m2[5]; 5968 sx = t0; 5969 shx = t2; 5970 tx = t4; 5971 5972 return [sx, shy, shx, sy, tx, ty]; 5973 }, 5974 5975 _matrix_rotation: function _matrix_rotation(m) { 5976 return Math.atan2(m[2], m[0]); 5977 }, 5978 5979 _matrix_decompose: function _matrix_decompose(matrix) { 5980 5981 var a = matrix[0]; 5982 var b = matrix[1]; 5983 var c = matrix[2]; 5984 var d = matrix[3]; 5985 5986 var scaleX = Math.sqrt(a * a + b * b); 5987 a /= scaleX; 5988 b /= scaleX; 5989 5990 var shear = a * c + b * d; 5991 c -= a * shear; 5992 d -= b * shear; 5993 5994 var scaleY = Math.sqrt(c * c + d * d); 5995 c /= scaleY; 5996 d /= scaleY; 5997 shear /= scaleY; 5998 5999 if (a * d < b * c) { 6000 a = -a; 6001 b = -b; 6002 shear = -shear; 6003 scaleX = -scaleX; 6004 } 6005 6006 return { 6007 scale: [scaleX, 0, 0, scaleY, 0, 0], 6008 translate: [1, 0, 0, 1, matrix[4], matrix[5]], 6009 rotate: [a, b, -b, a, 0, 0], 6010 skew: [1, 0, shear, 1, 0, 0] 6011 }; 6012 }, 6013 6014 _matrix_map_point: function _matrix_map_point(m1, pt) { 6015 var sx = m1[0]; 6016 var shy = m1[1]; 6017 var shx = m1[2]; 6018 var sy = m1[3]; 6019 var tx = m1[4]; 6020 var ty = m1[5]; 6021 6022 var px = pt[0]; 6023 var py = pt[1]; 6024 6025 var x = px * sx + py * shx + tx; 6026 var y = px * shy + py * sy + ty; 6027 return [x, y]; 6028 }, 6029 6030 _matrix_map_point_obj: function _matrix_map_point_obj(m1, pt) { 6031 var xpt = this._matrix_map_point(m1, [pt.x
6031, pt.y]); 6032 return { x: xpt[0], y: xpt[1] }; 6033 }, 6034 6035 _matrix_map_rect: function _matrix_map_rect(m1, rect) { 6036 var p1 = this._matrix_map_point(m1, [rect.x, rect.y]); 6037 var p2 = this._matrix_map_point(m1, [rect.x + rect.w, rect.y + rect.h]); 6038 return { x: p1[0], y: p1[1], w: p2[0] - p1[0], h: p2[1] - p1[1] }; 6039 }, 6040 6041 _matrix_is_identity: function _matrix_is_identity(m1) { 6042 if (m1[0] != 1) { 6043 return false; 6044 } 6045 if (m1[1] != 0) { 6046 return false; 6047 } 6048 if (m1[2] != 0) { 6049 return false; 6050 } 6051 if (m1[3] != 1) { 6052 return false; 6053 } 6054 if (m1[4] != 0) { 6055 return false; 6056 } 6057 if (m1[5] != 0) { 6058 return false; 6059 } 6060 return true; 6061 }, 6062 6063 rotate: function rotate(angle) { 6064 var matrix = [Math.cos(angle), Math.sin(angle), -Math.sin(angle), Math.cos(angle), 0.0, 0.0]; 6065 this.ctx._transform = this._matrix_multiply(this.ctx._transform, matrix); 6066 }, 6067 6068 scale: function scale(sx, sy) { 6069 var matrix = [sx, 0.0, 0.0, sy, 0.0, 0.0]; 6070 this.ctx._transform = this._matrix_multiply(this.ctx._transform, matrix); 6071 }, 6072 6073 translate: function translate(x, y) { 6074 var matrix = [1.0, 0.0, 0.0, 1.0, x, y]; 6075 this.ctx._transform = this._matrix_multiply(this.ctx._transform, matrix); 6076 }, 6077 6078 stroke: function stroke() { 6079 if (this.ctx._clip_path.length > 0) { 6080 6081 var lines; 6082 if (window.outIntercept) { 6083 lines = window.outIntercept.type === 'group' ? window.outIntercept.stream : window.outIntercept; 6084 } else { 6085 lines = this.pdf.internal.pages[1]; 6086 } 6087 lines.push("q"); 6088 6089 var origPath = this.path; 6090 this.path = this.ctx._clip_path; 6091 this.ctx._clip_path = []; 6092 this._stroke(true); 6093 6094 this.ctx._clip_path = this.path; 6095 this.path = origPath; 6096 this._stroke(false); 6097 6098 lines.push("Q"); 6099 } else { 6100 this._stroke(false); 6101 } 6102 }, 6103 6104 _stroke: function _stroke(isClip) {
6105 if (!isClip && this._isStrokeTransparent()) { 6106 return; 6107 } 6108 6109 //TODO opacity 6110 6111 var moves = []; 6112 var closed = false; 6113 6114 var xPath = this.path; 6115 6116 for (var i = 0; i < xPath.length; i++) { 6117 var pt = xPath[i]; 6118 switch (pt.type) { 6119 case 'mt': 6120 moves.push({ start: pt, deltas: [], abs: [] }); 6121 break; 6122 case 'lt': 6123 var delta = [pt.x - xPath[i - 1].x, pt.y - xPath[i - 1].y]; 6124 moves[moves.length - 1].deltas.push(delta); 6125 moves[moves.length - 1].abs.push(pt); 6126 break; 6127 case 'bct': 6128 var delta = [pt.x1 - xPath[i - 1].x, pt.y1 - xPath[i - 1].y, pt.x2 - xPath[i - 1].x, pt.y2 - xPath[i - 1].y, pt.x - xPath[i - 1].x, pt.y - xPath[i - 1].y]; 6129 moves[moves.length - 1].deltas.push(delta); 6130 break; 6131 case 'qct': 6132 // convert to bezier 6133 var x1 = xPath[i - 1].x + 2.0 / 3.0 * (pt.x1 - xPath[i - 1].x); 6134 var y1 = xPath[i - 1].y + 2.0 / 3.0 * (pt.y1 - xPath[i - 1].y); 6135 var x2 = pt.x + 2.0 / 3.0 * (pt.x1 - pt.x); 6136 var y2 = pt.y + 2.0 / 3.0 * (pt.y1 - pt.y); 6137 var x3 = pt.x; 6138 var y3 = pt.y; 6139 var delta = [x1 - xPath[i - 1].x, y1 - xPath[i - 1].y, x2 - xPath[i - 1].x, y2 - xPath[i - 1].y, x3 - xPath[i - 1].x, y3 - xPath[i - 1].y]; 6140 moves[moves.length - 1].deltas.push(delta); 6141 break; 6142 case 'arc': 6143 moves[moves.length - 1].arc = true; 6144 moves[moves.length - 1].abs.push(pt); 6145 break; 6146 case 'close': 6147 closed = true; 6148 break; 6149 } 6150 } 6151 6152 for (var i = 0; i < moves.length; i++) { 6153 var style; 6154 if (i == moves.length - 1) { 6155 style = 's'; 6156 } else { 6157 style = null; 6158 } 6159 if (moves[i].arc) { 6160 var arcs = moves[i].abs; 6161 for (var ii = 0; ii < arcs.length; ii++) { 6162 var arc = arcs[ii]; 6163 var start = arc.startAngle * 360 / (2 * Math.PI); 6164 var end = arc.endAngle * 360 / (2 * Math.PI); 6165 var x = arc.x; 6166 var y = arc.y; 6167 this.internal.arc2(this, x, y, arc.radius, start, end, arc.anticlockwise, style, isClip); 6168 } 6169 } else { 6170 var x = moves[i].start.x; 6171 var y = moves[i].start.y; 6172 if (!isClip) { 6173 this.pdf.lines(moves[i].deltas, x, y, null, style); 6174 } else { 6175 this.pdf.lines(moves[i].deltas, x, y, null, null); 6176 this.pdf.clip_fixed(); 6177 } 6178 } 6179 } 6180 }, 6181 6182 _isFillTransparent: function _isFillTransparent() { 6183 return this.ctx._isFillTransparent || this.globalAlpha == 0; 6184 }, 6185
6186 _isStrokeTransparent: function _isStrokeTransparent() { 6187 return this.ctx._isStrokeTransparent || this.globalAlpha == 0; 6188 }, 6189 6190 fill: function fill(fillRule) { 6191 //evenodd or nonzero (default) 6192 if (this.ctx._clip_path.length > 0) { 6193 6194 var lines; 6195 if (window.outIntercept) { 6196 lines = window.outIntercept.type === 'group' ? window.outIntercept.stream : window.outIntercept; 6197 } else { 6198 lines = this.pdf.internal.pages[1]; 6199 } 6200 lines.push("q"); 6201 6202 var origPath = this.path; 6203 this.path = this.ctx._clip_path; 6204 this.ctx._clip_path = []; 6205 this._fill(fillRule, true); 6206 6207 this.ctx._clip_path = this.path; 6208 this.path = origPath; 6209 this._fill(fillRule, false); 6210 6211 lines.push('Q'); 6212 } else { 6213 this._fill(fillRule, false); 6214 } 6215 }, 6216 6217 _fill: function _fill(fillRule, isClip) { 6218 if (this._isFillTransparent()) { 6219 return; 6220 } 6221 var v2Support = typeof this.pdf.internal.newObject2 === 'function'; 6222 6223 var lines; 6224 if (window.outIntercept) { 6225 lines = window.outIntercept.type === 'group' ? window.outIntercept.stream : window.outIntercept; 6226 } else { 6227 lines = this.pdf.internal.pages[1]; 6228 } 6229 6230 // if (this.ctx._clip_path.length > 0) { 6231 // lines.push('q'); 6232 // var oldPath = this.path; 6233 // this.path = this.ctx._clip_path; 6234 // this.ctx._clip_path = []; 6235 // this._fill(fillRule, true); 6236 // this.ctx._clip_path = this.path; 6237 // this.path = oldPath; 6238 // } 6239 6240 var moves = []; 6241 var outInterceptOld = window.outIntercept; 6242 6243 if (v2Support) { 6244 // Blend and Mask 6245 switch (this.ctx.globalCompositeOperation) { 6246 case 'normal': 6247 case 'source-over': 6248 break; 6249 case 'destination-in': 6250 case 'destination-out': 6251 //TODO this need to be added to the current group or page 6252 // define a mask stream 6253 var obj = this.pdf.internal.newStreamObject(); 6254 6255 // define a mask state 6256 var obj2 = this.pdf.internal.newObject2(); 6257 obj2.push('<</Type /ExtGState'); 6258 obj2.push('/SMask <</S /Alpha /G ' + obj.objId + ' 0 R>>'); // /S /Luminosity will need to define color space 6259 obj2.push('>>'); 6260 6261 // add mask to page resources 6262 var gsName = 'MASK' + obj2.objId; 6263 this.pdf.internal.addGraphicsState(gsName, obj2.objId); 6264 6265 var instruction = '/' + gsName + ' gs'; 6266 // add mask to page, group, or stream 6267 lines.splice(0, 0, 'q'); 6268 lines.splice(1, 0, instruction); 6269 lines.push('Q'); 6270 6271 window.outIntercept = obj; 6272 break; 6273 default: 6274 var dictionaryEntry = '/' + this.pdf.internal.blendModeMap[this.ctx.globalCompositeOperation.toUpperCase()]; 6275 if (dictionaryEntry) { 6276 this.pdf.internal.out(dictionaryEntry + ' gs'); 6277 } 6278 break; 6279 } 6280 } 6281 6282 var alpha = this.ctx.globalAlpha; 6283 if (this.ctx._fillOpacity < 1) { 6284 // TODO combine this with global opacity 6285 alpha = this.ctx._fillOpacity; 6286 } 6287 6288 //TODO check for an opacity graphics state that was already created
6289 //TODO do not set opacity if current value is already active 6290 if (v2Support) { 6291 var objOpac = this.pdf.internal.newObject2(); 6292 objOpac.push('<</Type /ExtGState'); 6293 //objOpac.push(this.ctx.globalAlpha + " CA"); // Stroke 6294 //objOpac.push(this.ctx.globalAlpha + " ca"); // Not Stroke 6295 objOpac.push('/CA ' + alpha); // Stroke 6296 objOpac.push('/ca ' + alpha); // Not Stroke 6297 objOpac.push('>>'); 6298 var gsName = 'GS_O_' + objOpac.objId; 6299 this.pdf.internal.addGraphicsState(gsName, objOpac.objId); 6300 this.pdf.internal.out('/' + gsName + ' gs'); 6301 } 6302 6303 var xPath = this.path; 6304 6305 for (var i = 0; i < xPath.length; i++) { 6306 var pt = xPath[i]; 6307 switch (pt.type) { 6308 case 'mt': 6309 moves.push({ start: pt, deltas: [], abs: [] }); 6310 break; 6311 case 'lt': 6312 var delta = [pt.x - xPath[i - 1].x, pt.y - xPath[i - 1].y]; 6313 moves[moves.length - 1].deltas.push(delta); 6314 moves[moves.length - 1].abs.push(pt); 6315 break; 6316 case 'bct': 6317 var delta = [pt.x1 - xPath[i - 1].x, pt.y1 - xPath[i - 1].y, pt.x2 - xPath[i - 1].x, pt.y2 - xPath[i - 1].y, pt.x - xPath[i - 1].x, pt.y - xPath[i - 1].y]; 6318 moves[moves.length - 1].deltas.push(delta); 6319 break; 6320 case 'qct': 6321 // convert to bezier 6322 var x1 = xPath[i - 1].x + 2.0 / 3.0 * (pt.x1 - xPath[i - 1].x); 6323 var y1 = xPath[i - 1].y + 2.0 / 3.0 * (pt.y1 - xPath[i - 1].y); 6324 var x2 = pt.x + 2.0 / 3.0 * (pt.x1 - pt.x); 6325 var y2 = pt.y + 2.0 / 3.0 * (pt.y1 - pt.y); 6326 var x3 = pt.x; 6327 var y3 = pt.y; 6328 var delta = [x1 - xPath[i - 1].x, y1 - xPath[i - 1].y, x2 - xPath[i - 1].x, y2 - xPath[i - 1].y, x3 - xPath[i - 1].x, y3 - xPath[i - 1].y]; 6329 moves[moves.length - 1].deltas.push(delta); 6330 break; 6331 case 'arc': 6332 //TODO this was hack to avoid out of bounds issue 6333 if (moves.length == 0) { 6334 moves.push({ start: { x: 0, y: 0 }, deltas: [], abs: [] }); 6335 } 6336 moves[moves.length - 1].arc = true; 6337 moves[moves.length - 1].abs.push(pt); 6338 break; 6339 case 'close': 6340 //moves[moves.length - 1].deltas.push('close'); 6341 break; 6342 } 6343 } 6344 6345 for (var i = 0; i < moves.length; i++) { 6346 var style; 6347 if (i == moves.length - 1) { 6348 style = 'f'; 6349 if (fillRule === 'evenodd') { 6350 style += '*'; 6351 } 6352 } else { 6353 style = null; 6354 } 6355 6356 if (moves[i].arc) { 6357 var arcs = moves[i].abs; 6358 for (var ii = 0; ii < arcs.length; ii++) { 6359 var arc = arcs[ii]; 6360 //TODO lines deltas were getting in here 6361 if (typeof arc.startAngle !== 'undefined') { 6362 var start = arc.startAngle * 360 / (2 * Math.PI); 6363 var end = arc.endAngle * 360 / (2 * Math.PI); 6364 // Add the current position (last move to) 6365 //var x = moves[i].start.x + arc.x; 6366 //var y = moves[i].start.y + arc.y; 6367 var x = arc.x; 6368 var y = arc.y; 6369 if (ii == 0) { 6370 this.internal.move2(this, x, y); 6371 } 6372 this.internal.arc2(this, x, y, arc.radius, start, end, arc.anticlockwise, null, isClip); 6373 } else { 6374 this.internal.line2(c2d, arc.x, arc.y); 6375 } 6376 } 6377 6378 // extra move bug causing close to resolve to wrong point 6379 var x = moves[i].start.x; 6380 var y = moves[i].start.y; 6381 this.internal.line2(c2d, x, y); 6382 6383 this.pdf.internal.out('h'); 6384 this.pdf.internal.out('f'); 6385 } else { 6386 var x = moves[i].start.x; 6387 var y = moves[i].start.y; 6388 if (!isClip) { 6389 this.pdf.lines(moves[i].deltas, x, y, null, style); 6390 } else { 6391 this.pdf.lines(moves[i].deltas, x, y, null, null);
6392 this.pdf.clip_fixed(); 6393 } 6394 } 6395 } 6396 6397 window.outIntercept = outInterceptOld; 6398 6399 // if (this.ctx._clip_path.length > 0) { 6400 // lines.push('Q'); 6401 // } 6402 }, 6403 6404 pushMask: function pushMask() { 6405 var v2Support = typeof this.pdf.internal.newObject2 === 'function'; 6406 6407 if (!v2Support) { 6408 console.log('jsPDF v2 not enabled'); 6409 return; 6410 } 6411 6412 // define a mask stream 6413 var obj = this.pdf.internal.newStreamObject(); 6414 6415 // define a mask state 6416 var obj2 = this.pdf.internal.newObject2(); 6417 obj2.push('<</Type /ExtGState'); 6418 obj2.push('/SMask <</S /Alpha /G ' + obj.objId + ' 0 R>>'); // /S /Luminosity will need to define color space 6419 obj2.push('>>'); 6420 6421 // add mask to page resources 6422 var gsName = 'MASK' + obj2.objId; 6423 this.pdf.internal.addGraphicsState(gsName, obj2.objId); 6424 6425 var instruction = '/' + gsName + ' gs'; 6426 this.pdf.internal.out(instruction); 6427 }, 6428 6429 clip: function clip() { 6430 //TODO do we reset the path, or just copy it? 6431 if (this.ctx._clip_path.length > 0) { 6432 for (var i = 0; i < this.path.length; i++) { 6433 this.ctx._clip_path.push(this.path[i]); 6434 } 6435 } else { 6436 this.ctx._clip_path = this.path; 6437 } 6438 this.path = []; 6439 }, 6440 6441 measureText: function measureText(text) { 6442 var pdf = this.pdf; 6443 return { 6444 getWidth: function getWidth() { 6445 var fontSize = pdf.internal.getFontSize(); 6446 var txtWidth = pdf.getStringUnitWidth(text) * fontSize / pdf.internal.scaleFactor; 6447 return txtWidth; 6448 }, 6449 6450 get width() { 6451 return this.getWidth(text); 6452 } 6453 }; 6454 }, 6455 _getBaseline: function _getBaseline(y) { 6456 var height = parseInt(this.pdf.internal.getFontSize()); 6457 // TODO Get descent from font descriptor 6458 var descent = height * .25; 6459 switch (this.ctx.textBaseline) { 6460 case 'bottom': 6461 return y - descent; 6462 case 'top': 6463 return y + height; 6464 case 'hanging': 6465 return y + height - descent; 6466 case 'middle': 6467 return y + height / 2 - descent; 6468 case 'ideographic': 6469 // TODO not implemented 6470 return y; 6471 case 'alphabetic': 6472 default: 6473 return y; 6474 } 6475 } 6476 }; 6477 6478 var c2d = jsPDFAPI.context2d; 6479 6480 // accessor methods 6481 Object.defineProperty(c2d, 'fillStyle', { 6482 set: function set(value) { 6483 this.setFillStyle(value); 6484 }, 6485 get: function get() { 6486 return this.ctx.fillStyle; 6487 } 6488 }); 6489 Object.defineProperty(c2d, 'strokeStyle', { 6490 set: function set(value) { 6491 this.setStrokeStyle(value); 6492 }, 6493 get: function get() { 6494 return this.ctx.strokeStyle; 6495 } 6496 }); 6497 Object.defineProperty(c2d, 'lineWidth', { 6498 set: function set(value) { 6499 this.setLineWidth(value); 6500 }, 6501 get: function get() { 6502 return this.ctx.lineWidth; 6503 } 6504 }); 6505 Object.defineProperty(c2d, 'lineCap', { 6506 set: function set(val) { 6507 this.setLineCap(val); 6508 }, 6509 get: function get() { 6510 return this.ctx.lineCap; 6511 } 6512 }); 6513 Object.defineProperty(c2d, 'lineJoin', { 6514 set: function set(val) { 6515 this.setLineJoin(val); 6516 }, 6517 get: function get() { 6518 return this.ctx.lineJoin; 6519 } 6520 }); 6521 Object.defineProperty(c2d, 'miterLimit', { 6522 set: function set(val) { 6523 this.ctx.miterLimit = val; 6524 }, 6525 get: function get() { 6526 return this.ctx.miterLimit; 6527 } 6528 }); 6529 Object.defineProperty(c2d, 'textBaseline', { 6530 set: function set(value) { 6531 this.setTextBaseline(value); 6532 }, 6533 get: function get() { 6534 return this.getTextBaseline(); 6535 } 6536 }); 6537 Object.defineProperty(c2d, 'textAlign', { 6538 set: function set(value) { 6539 this.setTextAlign(value); 6540 }, 6541 get: function get() { 6542 return this.getTextAlign(); 6543 } 6544 }); 6545 Object.defineProperty(c2d, 'font', { 6546 set: function set(value) { 6547 this.setFont(value); 6548 }, 6549 get: function get() { 6550 return this.ctx.font; 6551 } 6552 }); 6553 Object.defineProperty(c2d, 'globalCompositeOperation', { 6554 set: function set(value) { 6555 this.ctx.globalCompositeOperation = value; 6556 }, 6557 get: function get() { 6558 return this.ctx.globalCompositeOperation; 6559 } 6560 }); 6561 Object.defineProperty(c2d, 'globalAlpha', { 6562 set: function set(value) { 6563 this.ctx.globalAlpha = value; 6564 }, 6565 get: function get() { 6566 return this.ctx.globalAlpha; 6567 } 6568 }); 6569 // Not HTML API 6570 Object.defineProperty(c2d, 'ignoreClearRect', { 6571 set: function set(value) { 6572 this.ctx.ignoreClearRect = value; 6573 }, 6574 get: function get() { 6575 return this.ctx.ignoreClearRect; 6576 } 6577 }); 6578 // End Not HTML API 6579 6580 c2d.internal = {}; 6581 6582 c2d.internal.rxRgb = /rgb\s*\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)/; 6583 c2d.internal.rxRgba = /rgba\s*\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*,\s*([\d\.]+)\s*\)/; 6584 c2d.internal.rxTransparent = /transparent|rgba\s*\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*,\s*0+\s*\)/; 6585 6586 // http://hansmuller-flex.blogspot.com/2011/10/more-about-
6586approximating-circular-arcs.html 6587 c2d.internal.arc = function (c2d, xc, yc, r, a1, a2, anticlockwise, style) { 6588 var includeMove = true; 6589 6590 var k = this.pdf.internal.scaleFactor; 6591 var pageHeight = this.pdf.internal.pageSize.height; 6592 var f2 = this.pdf.internal.f2; 6593 6594 var a1r = a1 * (Math.PI / 180); 6595 var a2r = a2 * (Math.PI / 180); 6596 var curves = this.createArc(r, a1r, a2r, anticlockwise); 6597 var pathData = null; 6598 6599 for (var i = 0; i < curves.length; i++) { 6600 var curve = curves[i]; 6601 if (includeMove && i == 0) { 6602 this.pdf.internal.out([f2((curve.x1 + xc) * k), f2((pageHeight - (curve.y1 + yc)) * k), 'm', f2((curve.x2 + xc) * k), f2((pageHeight - (curve.y2 + yc)) * k), f2((curve.x3 + xc) * k), f2((pageHeight - (curve.y3 + yc)) * k), f2((curve.x4 + xc) * k), f2((pageHeight - (curve.y4 + yc)) * k), 'c'].join(' ')); 6603 } else { 6604 this.pdf.internal.out([f2((curve.x2 + xc) * k), f2((pageHeight - (curve.y2 + yc)) * k), f2((curve.x3 + xc) * k), f2((pageHeight - (curve.y3 + yc)) * k), f2((curve.x4 + xc) * k), f2((pageHeight - (curve.y4 + yc)) * k), 'c'].join(' ')); 6605 } 6606 6607 //c2d._lastPoint = {x: curve.x1 + xc, y: curve.y1 + yc}; 6608 c2d._lastPoint = { x: xc, y: yc }; 6609 // f2((curve.x1 + xc) * k), f2((pageHeight - (curve.y1 + yc)) * k), 'm', f2((curve.x2 + xc) * k), f2((pageHeight - (curve.y2 + yc)) * k), f2((curve.x3 + xc) * k), f2((pageHeight - (curve.y3 + yc)) * k), f2((curve.x4 + xc) * k), f2((pageHeight - (curve.y4 + yc)) * k), 'c' 6610 } 6611 6612 if (style !== null) { 6613 this.pdf.internal.out(this.pdf.internal.getStyle(style)); 6614 } 6615 }; 6616 6617 /** 6618 * 6619 * @param x Edge point X 6620 * @param y Edge point Y 6621 * @param r Radius 6622 * @param a1 start angle 6623 * @param a2 end angle 6624 * @param anticlockwise 6625 * @param style 6626 * @param isClip 6627 */ 6628 c2d.internal.arc2 = function (c2d, x, y, r, a1, a2, anticlockwise, style, isClip) { 6629 // we need to convert from cartesian to polar here methinks. 6630 var centerX = x; // + r; 6631 var centerY = y; 6632 6633 if (false) {} 6634 6635 if (!isClip) { 6636 this.arc(c2d, centerX, centerY, r, a1, a2, anticlockwise, style); 6637 } else { 6638 this.arc(c2d, centerX, centerY, r, a1, a2, anticlockwise, null); 6639 this.pdf.clip_fixed(); 6640 } 6641 }; 6642 6643 c2d.internal.move2 = function (c2d, x, y) { 6644 var k = this.pdf.internal.scaleFactor; 6645 var pageHeight = this.pdf.internal.pageSize.height; 6646 var f2 = this.pdf.internal.f2; 6647 6648 this.pdf.internal.out([f2(x * k), f2((pageHeight - y) * k), 'm'].join(' ')); 6649 c2d._lastPoint = { x: x, y: y }; 6650 }; 6651 6652 c2d.internal.line2 = function (c2d, dx, dy) { 6653 var k = this.pdf.internal.scaleFactor; 6654 var pageHeight = this.pdf.internal.pageSize.height; 6655 var f2 = this.pdf.internal.f2; 6656 6657 //var pt = {x: c2d._lastPoint.x + dx, y: c2d._lastPoint.y + dy}; 6658 var pt = { x: dx, y: dy }; 6659 6660 this.pdf.internal.out([f2(pt.x * k), f2((pageHeight - pt.y) * k), 'l'].join(' ')); 6661 //this.pdf.internal.out('f'); 6662 c2d._lastPoint = pt; 6663 }; 6664 6665 /** 6666 * Return a array of objects that represent bezier curves which approximate the circular arc centered at the origin, from startAngle to endAngle (radians) with the specified radius. 6667 * 6668 * Each bezier curve is an object with four points, where x1,y1 and x4,y4 are the arc's end points and x2,y2 and x3,y3 are the cubic bezier's control points. 6669 */ 6670 6671 c2d.internal.createArc = function (radius, startAngle, endAngle, anticlockwise) { 6672 6673 var EPSILON = 0.00001; // Roughly 1/1000th of a degree, see below 6674 6675 // normalize startAngle, endAngle to [-2PI, 2PI] 6676 var twoPI = Math.PI * 2; 6677 var startAngleN = startAngle; 6678 if (startAngleN < twoPI || startAngleN > twoPI) { 6679 startAngleN = startAngleN % twoPI; 6680 } 6681 var endAngleN = endAngle; 6682 if (endAngleN < twoPI || endAngleN > twoPI) { 6683 endAngleN = endAngleN % twoPI; 6684 } 6685 6686 // Compute the sequence of arc curves, up to PI/2 at a time. 6687 // Total arc angle is less than 2PI. 6688 var curves = []; 6689 var piOverTwo = Math.PI / 2.0; 6690 // var sgn = (startAngle < endAngle) ? +1 : -1; // clockwise or counterclockwise 6691 var sgn = anticlockwise ? -1 : +1; 6692 6693 var a1 = startAngle; 6694 for (var totalAngle = Math.min(twoPI, Math.abs(endAngleN - startAngleN)); totalAngle > EPSILON;) { 6695 var a2 = a1 + sgn * Math.min(totalAngle, piOverTwo); 6696 curves.push(this.createSmallArc(radius, a1, a2)); 6697 totalAngle -= Math.abs(a2 - a1); 6698 a1 = a2; 6699 } 6700 6701 return curves; 6702 }; 6703 6704 /** 6705 * Cubic bezier approximation of a circular arc centered at the origin, from (radians) a1 to a2, where a2-a1 < pi/2. The arc's radius is r. 6706 * 6707 * Returns an object with four points, where x1,y1 and x4,y4 are the arc's end points and x2,y2 and x3,y3 are the cub
6707ic bezier's control points. 6708 * 6709 * This algorithm is based on the approach described in: A. Riškus, "Approximation of a Cubic Bezier Curve by Circular Arcs and Vice Versa," Information Technology and Control, 35(4), 2006 pp. 371-378. 6710 */ 6711 6712 c2d.internal.createSmallArc = function (r, a1, a2) { 6713 // Compute all four points for an arc that subtends the same total angle 6714 // but is centered on the X-axis 6715 6716 var a = (a2 - a1) / 2.0; 6717 6718 var x4 = r * Math.cos(a); 6719 var y4 = r * Math.sin(a); 6720 var x1 = x4; 6721 var y1 = -y4; 6722 6723 var q1 = x1 * x1 + y1 * y1; 6724 var q2 = q1 + x1 * x4 + y1 * y4; 6725 var k2 = 4 / 3 * (Math.sqrt(2 * q1 * q2) - q2) / (x1 * y4 - y1 * x4); 6726 6727 var x2 = x1 - k2 * y1; 6728 var y2 = y1 + k2 * x1; 6729 var x3 = x2; 6730 var y3 = -y2; 6731 6732 // Find the arc points' actual locations by computing x1,y1 and x4,y4 6733 // and rotating the control points by a + a1 6734 6735 var ar = a + a1; 6736 var cos_ar = Math.cos(ar); 6737 var sin_ar = Math.sin(ar); 6738 6739 return { 6740 x1: r * Math.cos(a1), 6741 y1: r * Math.sin(a1), 6742 x2: x2 * cos_ar - y2 * sin_ar, 6743 y2: x2 * sin_ar + y2 * cos_ar, 6744 x3: x3 * cos_ar - y3 * sin_ar, 6745 y3: x3 * sin_ar + y3 * cos_ar, 6746 x4: r * Math.cos(a2), 6747 y4: r * Math.sin(a2) 6748 }; 6749 }; 6750 6751 function context() { 6752 this._isStrokeTransparent = false; 6753 this._strokeOpacity = 1; 6754 this.strokeStyle = '#000000'; 6755 this.fillStyle = '#000000'; 6756 this._isFillTransparent = false; 6757 this._fillOpacity = 1; 6758 this.font = "12pt times"; 6759 this.textBaseline = 'alphabetic'; // top,bottom,middle,ideographic,alphabetic,hanging 6760 this.textAlign = 'start'; 6761 this.lineWidth = 1; 6762 this.lineJoin = 'miter'; // round, bevel, miter 6763 this.lineCap = 'butt'; // butt, round, square 6764 this._transform = [1, 0, 0, 1, 0, 0]; // sx, shy, shx, sy, tx, ty 6765 this.globalCompositeOperation = 'normal'; 6766 this.globalAlpha = 1.0; 6767 this._clip_path = []; 6768 // TODO miter limit //default 10 6769 6770 // Not HTML API 6771 this.ignoreClearRect = false; 6772 6773 this.copy = function (ctx) { 6774 this._isStrokeTransparent = ctx._isStrokeTransparent; 6775 this._strokeOpacity = ctx._strokeOpacity; 6776 this.strokeStyle = ctx.strokeStyle; 6777 this._isFillTransparent = ctx._isFillTransparent; 6778 this._fillOpacity = ctx._fillOpacity; 6779 this.fillStyle = ctx.fillStyle; 6780 this.font = ctx.font; 6781 this.lineWidth = ctx.lineWidth; 6782 this.lineJoin = ctx.lineJoin; 6783 this.lineCap = ctx.lineCap; 6784 this.textBaseline = ctx.textBaseline; 6785 this.textAlign = ctx.textAlign; 6786 this._fontSize = ctx._fontSize; 6787 this._transform = ctx._transform.slice(0); 6788 this.globalCompositeOperation = ctx.globalCompositeOperation; 6789 this.globalAlpha = ctx.globalAlpha; 6790 this._clip_path = ctx._clip_path.slice(0); //TODO deep copy? 6791 6792 // Not HTML API 6793 this.ignoreClearRect = ctx.ignoreClearRect; 6794 }; 6795 } 6796 6797 return this; 6798 })(jsPDF.API); 6799 6800 /** @preserve 6801 * jsPDF fromHTML plugin. BETA stage. API subject to change. Needs browser 6802 * Copyright (c) 2012 Willow Systems Corporation, willow-systems.com 6803 * 2014 Juan Pablo Gaviria, https://github.com/juanpgaviria 6804 * 2014 Diego Casorran, https://github.com/diegocr 6805 * 2014 Daniel Husar, https://github.com/danielhusar 6806 * 2014 Wolfgang Gassler, https://github.com/woolfg 6807 * 2014 Steven Spungin, https://github.com/flamenco 6808 * 6809 * 6810 * ==================================================================== 6811 */ 6812 6813 (function (jsPDFAPI) { 6814 var clone, _DrillForContent, FontNameDB, FontStyleMap, TextAlignMap, FontWeightMap, FloatMap, ClearMap, GetCSS, PurgeWhiteSpace, Renderer, ResolveFont, ResolveUnitedNumber, UnitedNumberMap, elementHandledElsewhere, images, loadImgs, checkForFooter, process, tableToJson; 6815 clone = function () { 6816 return function (obj) { 6817 Clone.prototype = obj; 6818 return new Clone(); 6819 }; 6820 function Clone() {} 6821 }(); 6822 PurgeWhiteSpace = function PurgeWhiteSpace(array) { 6823 var fragment, i, l, lTrimmed, r, rTrimmed, trailingSpace; 6824 i = 0; 6825 l = array.length; 6826 fragment = void 0; 6827 lTrimmed = false;
6828 rTrimmed = false; 6829 while (!lTrimmed && i !== l) { 6830 fragment = array[i] = array[i].trimLeft(); 6831 if (fragment) { 6832 lTrimmed = true; 6833 } 6834 i++; 6835 } 6836 i = l - 1; 6837 while (l && !rTrimmed && i !== -1) { 6838 fragment = array[i] = array[i].trimRight(); 6839 if (fragment) { 6840 rTrimmed = true; 6841 } 6842 i--; 6843 } 6844 r = /\s+$/g; 6845 trailingSpace = true; 6846 i = 0; 6847 while (i !== l) { 6848 // Leave the line breaks intact 6849 if (array[i] != "\u2028") { 6850 fragment = array[i].replace(/\s+/g, " "); 6851 if (trailingSpace) { 6852 fragment = fragment.trimLeft(); 6853 } 6854 if (fragment) { 6855 trailingSpace = r.test(fragment); 6856 } 6857 array[i] = fragment; 6858 } 6859 i++; 6860 } 6861 return array; 6862 }; 6863 Renderer = function Renderer(pdf, x, y, settings) { 6864 this.pdf = pdf; 6865 this.x = x; 6866 this.y = y; 6867 this.settings = settings; 6868 //list of functions which are called after each element-rendering process 6869 this.watchFunctions = []; 6870 this.init(); 6871 return this; 6872 }; 6873 ResolveFont = function ResolveFont(css_font_family_string) { 6874 var name, part, parts; 6875 name = void 0; 6876 parts = css_font_family_string.split(","); 6877 part = parts.shift(); 6878 while (!name && part) { 6879 name = FontNameDB[part.trim().toLowerCase()]; 6880 part = parts.shift(); 6881 } 6882 return name; 6883 }; 6884 ResolveUnitedNumber = function ResolveUnitedNumber(css_line_height_string) { 6885 6886 //IE8 issues 6887 css_line_height_string = css_line_height_string === "auto" ? "0px" : css_line_height_string; 6888 if (css_line_height_string.indexOf("em") > -1 && !isNaN(Number(css_line_height_string.replace("em", "")))) { 6889 css_line_height_string = Number(css_line_height_string.replace("em", "")) * 18.719 + "px"; 6890 } 6891 if (css_line_height_string.indexOf("pt") > -1 && !isNaN(Number(css_line_height_string.replace("pt", "")))) { 6892 css_line_height_string = Number(css_line_height_string.replace("pt", "")) * 1.333 + "px"; 6893 } 6894 6895 var normal, undef, value; 6896 undef = void 0; 6897 normal = 16.00; 6898 value = UnitedNumberMap[css_line_height_string]; 6899 if (value) { 6900 return value; 6901 } 6902 value = { 6903 "xx-small": 9, 6904 "x-small": 11, 6905 small: 13, 6906 medium: 16, 6907 large: 19, 6908 "x-large": 23, 6909 "xx-large": 28, 6910 auto: 0 6911 }[{ css_line_height_string: css_line_height_string }]; 6912 6913 if (value !== undef) { 6914 return UnitedNumberMap[css_line_height_string] = value / normal; 6915 } 6916 if (value = parseFloat(css_line_height_string)) { 6917 return UnitedNumberMap[css_line_height_string] = value / normal; 6918 } 6919 value = css_line_height_string.match(/([\d\.]+)(px)/); 6920 if (value.length === 3) { 6921 return UnitedNumberMap[css_line_height_string] = parseFloat(value[1]) / normal; 6922 } 6923 return UnitedNumberMap[css_line_height_string] = 1; 6924 }; 6925 GetCSS = function GetCSS(element) { 6926 var css, tmp, computedCSSElement; 6927 computedCSSElement = function (el) { 6928 var compCSS; 6929 compCSS = function (el) { 6930 if (document.defaultView && document.defaultView.getComputedStyle) { 6931 return document.defaultView.getComputedStyle(el, null); 6932 } else if (el.currentStyle) { 6933 return el.currentStyle; 6934 } else { 6935 return el.style; 6936 } 6937 }(el); 6938 return function (prop) { 6939 prop = prop.replace(/-\D/g, function (match) { 6940 return match.charAt(1).toUpperCase(); 6941 }); 6942 return compCSS[prop]; 6943 }; 6944 }(element); 6945 css = {}; 6946 tmp = void 0; 6947 css["font-family"] = ResolveFont(computedCSSElement("font-family")) || "times"; 6948 css["font-style"] = FontStyleMap[computedCSSElement("font-style")] || "normal"; 6949 css["text-align"] = TextAlignMap[computedCSSElement("text-align")] || "left"; 6950 tmp = FontWeightMap[computedCSSElement("font-weight")] || "normal"; 6951 if (tmp === "bold") { 6952 if (css["font-style"] === "normal") { 6953 css["font-style"] = tmp; 6954 } else { 6955 css["font-style"] = tmp + css["font-style"]; 6956 } 6957 } 6958 css["font-size"] = ResolveUnitedNumber(computedCSSElement("font-size")) || 1; 6959 css["line-height"] = ResolveUnitedNumber(computedCSSElement("line-height")) || 1; 6960 css["display"] = computedCSSElement("display") === "inline" ? "inline" : "block"; 6961 6962 tmp = css["display"] === "block"; 6963 css["margin-top"] = tmp && ResolveUnitedNumber(computedCSSElement("margin-top")) || 0; 6964 css["margin-bottom"] = tmp && ResolveUnitedNumber(computedCSSElement("margin-bottom")) || 0; 6965 css["padding-top"] = tmp && ResolveUnitedNumber(computedCSSElement("padding-top")) || 0; 6966 css["padding-bottom"] = tmp && ResolveUnitedNumber(computedCSSElement("padding-bottom")) || 0; 6967 css["margin-left"] = tmp && ResolveUnitedNumber(computedCSSElement("margin-left")) || 0; 6968 css["margin-right"] = tmp && ResolveUnitedNumber(computedCSSElement("margin-right")) || 0; 6969 css["padding-left"] = tmp && ResolveUnitedNumber(computedCSSElement("padding-left")) || 0; 6970 css["padding-right"] = tmp && ResolveUnitedNumber(computedCSSElement("padding-right")) || 0; 6971 6972 css["page-break-before"] = computedCSSElement("page-break-before") || "auto"; 6973 6974 //float and clearing of floats 6975 css["float"] = FloatMap[computedCSSElement("cssFloat")] || "none"; 6976 css["clear"] = ClearMap[computedCSSElement("clear")] || "none"; 6977 6978 css["color"] = computedCSSElement("color"); 6979 6980 return css; 6981 }; 6982 elementHandledElsewhere = function elementHandledElsewhere(element, renderer, elementHandlers) { 6983 var handlers, i, isHandledElsewhere, l, t; 6984 isHandledElsewhere = false;
6985 i = void 0; 6986 l = void 0; 6987 t = void 0; 6988 handlers = elementHandlers["#" + element.id]; 6989 if (handlers) { 6990 if (typeof handlers === "function") { 6991 isHandledElsewhere = handlers(element, renderer); 6992 } else { 6993 i = 0; 6994 l = handlers.length; 6995 while (!isHandledElsewhere && i !== l) { 6996 isHandledElsewhere = handlers[i](element, renderer); 6997 i++; 6998 } 6999 } 7000 } 7001 handlers = elementHandlers[element.nodeName]; 7002 if (!isHandledElsewhere && handlers) { 7003 if (typeof handlers === "function") { 7004 isHandledElsewhere = handlers(element, renderer); 7005 } else { 7006 i = 0; 7007 l = handlers.length; 7008 while (!isHandledElsewhere && i !== l) { 7009 isHandledElsewhere = handlers[i](element, renderer); 7010 i++; 7011 } 7012 } 7013 } 7014 return isHandledElsewhere; 7015 }; 7016 tableToJson = function tableToJson(table, renderer) { 7017 var data, headers, i, j, rowData, tableRow, table_obj, table_with, cell, l; 7018 data = []; 7019 headers = []; 7020 i = 0; 7021 l = table.rows[0].cells.length; 7022 table_with = table.clientWidth; 7023 while (i < l) { 7024 cell = table.rows[0].cells[i]; 7025 headers[i] = { 7026 name: cell.textContent.toLowerCase().replace(/\s+/g, ''), 7027 prompt: cell.textContent.replace(/\r?\n/g, ''), 7028 width: cell.clientWidth / table_with * renderer.pdf.internal.pageSize.width 7029 }; 7030 i++; 7031 } 7032 i = 1; 7033 while (i < table.rows.length) { 7034 tableRow = table.rows[i]; 7035 rowData = {}; 7036 j = 0; 7037 while (j < tableRow.cells.length) { 7038 rowData[headers[j].name] = tableRow.cells[j].textContent.replace(/\r?\n/g, ''); 7039 j++; 7040 } 7041 data.push(rowData); 7042 i++; 7043 } 7044 return table_obj = { 7045 rows: data, 7046 headers: headers 7047 }; 7048 }; 7049 var SkipNode = { 7050 SCRIPT: 1, 7051 STYLE: 1, 7052 NOSCRIPT: 1, 7053 OBJECT: 1, 7054 EMBED: 1, 7055 SELECT: 1 7056 }; 7057 var listCount = 1; 7058 _DrillForContent = function DrillForContent(element, renderer, elementHandlers) { 7059 var cn, cns, fragmentCSS, i, isBlock, l, px2pt, table2json, cb; 7060 cns = element.childNodes; 7061 cn = void 0; 7062 fragmentCSS = GetCSS(element); 7063 isBlock = fragmentCSS.display === "block"; 7064 if (isBlock) { 7065 renderer.setBlockBoundary(); 7066 renderer.setBlockStyle(fragmentCSS); 7067 } 7068 px2pt = 0.264583 * 72 / 25.4; 7069 i = 0; 7070 l = cns.length; 7071 while (i < l) { 7072 cn = cns[i]; 7073 if ((typeof cn === "undefined" ? "undefined" : _typeof(cn)) === "object") { 7074 7075 //execute all watcher functions to e.g. reset floating 7076 renderer.executeWatchFunctions(cn); 7077 7078 /*** HEADER rendering **/ 7079 if (cn.nodeType === 1 && cn.nodeName === 'HEADER') { 7080 var header = cn; 7081 //store old top margin 7082 var oldMarginTop = renderer.pdf.margins_doc.top; 7083 //subscribe for new page event and render header first on every page 7084 renderer.pdf.internal.events.subscribe('addPage', function (pageInfo) { 7085 //set current y position to old margin 7086 renderer.y = oldMarginTop; 7087 //render all child nodes of the header element 7088 _DrillForContent(header, renderer, elementHandlers); 7089 //set margin to old margin + rendered header + 10 space to prevent overlapping 7090 //important for other plugins (e.g. table) to start rendering at correct position after header 7091 renderer.pdf.margins_doc.top = renderer.y + 10; 7092 renderer.y += 10; 7093 }, false); 7094 } 7095 7096 if (cn.nodeType === 8 && cn.nodeName === "#comment") { 7097 if (~cn.textContent.indexOf("ADD_PAGE")) { 7098 renderer.pdf.addPage(); 7099 renderer.y = renderer.pdf.margins_doc.top; 7100 } 7101 } else if (cn.nodeType === 1 && !SkipNode[cn.nodeName]) { 7102 /*** IMAGE RENDERING ***/ 7103 var cached_image; 7104 if (cn.nodeName === "IMG") { 7105 var url = cn.getAttribute("src"); 7106 cached_image = images[renderer.pdf.sHashCode(url) || url]; 7107 } 7108 if (cached_image) { 7109 if (renderer.pdf.internal.pageSize.height - renderer.pdf.margins_doc.bottom < renderer.y + cn.height && renderer.y > renderer.pdf.margins_doc.top) { 7110 renderer.pdf.addPage(); 7111 renderer.y = renderer.pdf.margins_doc.top; 7112 //check if we have to set back some values due to e.g. header rendering for new page 7113 renderer.executeWatchFunctions(cn); 7114 } 7115 7116 var imagesCSS = GetCSS(cn); 7117 var imageX = renderer.x; 7118 var fontToUnitRatio = 12 / renderer.pdf.internal.scaleFactor; 7119 7120 //define additional paddings, margins which have to be taken into account for margin calculations 7121 var additionalSpaceLeft = (imagesCSS["margin-left"] + imagesCSS["padding-left"]) * fontToUnitRatio; 7122 var additionalSpaceRight = (imagesCSS["margin-right"] + imagesCSS["padding-right"]) * fontToUnitRatio; 7123 var additionalSpaceTop = (imagesCSS["margin-top"] + imagesCSS["padding-top"]) * fontToUnitRatio; 7124 var additionalSpaceBottom = (imagesCSS["margin-bottom"] + imagesCSS["padding-bottom"]) * fontToUnitRatio; 7125 7126 //if float is set to right, move the image to the right border 7127 //add space if margin is set 7128 if (imagesCSS['float'] !== undefined && imagesCSS['float'] === 'right') { 7129 imageX += renderer.settings.width - cn.width - additionalSpaceRight; 7130 } else { 7131 imageX += additionalSpaceLeft; 7132 } 7133 7134 renderer.pdf.addImage(cached_image, imageX, renderer.y + additionalSpaceTop, cn.width, cn.height); 7135 cached_image = undefined; 7136 //if the float prop is specified we have to float the text around the image 7137 if (imagesCSS['float'] === 'right' || imagesCSS['float'] === 'left') { 7138 //add functiont to set back coordinates after image rendering 7139 renderer.watchFunctions.push(function (diffX, thresholdY, diffWidth, el) { 7140 //undo drawing box adaptions which were set by floating 7141 if (renderer.y >= thresholdY) { 7142 renderer.x += diffX; 7143 renderer.settings.width += diffWidth; 7144 return true; 7145 } else if (el && el.nodeType === 1 && !SkipNode[el.nodeName] && renderer.x + el.width > renderer.pdf.margins_doc.left + renderer.pdf.margins_doc.width) { 7146 renderer.x += diffX; 7147 renderer.y = thresholdY; 7148 renderer.settings.width += diffWidth; 7149 return true; 7150 } else { 7151 return false;
7152 } 7153 }.bind(this, imagesCSS['float'] === 'left' ? -cn.width - additionalSpaceLeft - additionalSpaceRight : 0, renderer.y + cn.height + additionalSpaceTop + additionalSpaceBottom, cn.width)); 7154 //reset floating by clear:both divs 7155 //just set cursorY after the floating element 7156 renderer.watchFunctions.push(function (yPositionAfterFloating, pages, el) { 7157 if (renderer.y < yPositionAfterFloating && pages === renderer.pdf.internal.getNumberOfPages()) { 7158 if (el.nodeType === 1 && GetCSS(el).clear === 'both') { 7159 renderer.y = yPositionAfterFloating; 7160 return true; 7161 } else { 7162 return false; 7163 } 7164 } else { 7165 return true; 7166 } 7167 }.bind(this, renderer.y + cn.height, renderer.pdf.internal.getNumberOfPages())); 7168 7169 //if floating is set we decrease the available width by the image width 7170 renderer.settings.width -= cn.width + additionalSpaceLeft + additionalSpaceRight; 7171 //if left just add the image width to the X coordinate 7172 if (imagesCSS['float'] === 'left') { 7173 renderer.x += cn.width + additionalSpaceLeft + additionalSpaceRight; 7174 } 7175 } else { 7176 //if no floating is set, move the rendering cursor after the image height 7177 renderer.y += cn.height + additionalSpaceTop + additionalSpaceBottom; 7178 } 7179 7180 /*** TABLE RENDERING ***/ 7181 } else if (cn.nodeName === "TABLE") { 7182 table2json = tableToJson(cn, renderer); 7183 renderer.y += 10; 7184 renderer.pdf.table(renderer.x, renderer.y, table2json.rows, table2json.headers, { 7185 autoSize: false, 7186 printHeaders: elementHandlers.printHeaders, 7187 margins: renderer.pdf.margins_doc, 7188 css: GetCSS(cn) 7189 }); 7190 renderer.y = renderer.pdf.lastCellPos.y + renderer.pdf.lastCellPos.h + 20; 7191 } else if (cn.nodeName === "OL" || cn.nodeName === "UL") { 7192 listCount = 1; 7193 if (!elementHandledElsewhere(cn, renderer, elementHandlers)) { 7194 _DrillForContent(cn, renderer, elementHandlers); 7195 } 7196 renderer.y += 10; 7197 } else if (cn.nodeName === "LI") { 7198 var temp = renderer.x; 7199 renderer.x += 20 / renderer.pdf.internal.scaleFactor; 7200 renderer.y += 3; 7201 if (!elementHandledElsewhere(cn, renderer, elementHandlers)) { 7202 _DrillForContent(cn, renderer, elementHandlers); 7203 } 7204 renderer.x = temp; 7205 } else if (cn.nodeName === "BR") { 7206 renderer.y += fragmentCSS["font-size"] * renderer.pdf.internal.scaleFactor; 7207 renderer.addText("\u2028", clone(fragmentCSS)); 7208 } else { 7209 if (!elementHandledElsewhere(cn, renderer, elementHandlers)) { 7210 _DrillForContent(cn, renderer, elementHandlers); 7211 } 7212 } 7213 } else if (cn.nodeType === 3) { 7214 var value = cn.nodeValue; 7215 if (cn.nodeValue && cn.parentNode.nodeName === "LI") { 7216 if (cn.parentNode.parentNode.nodeName === "OL") { 7217 value = listCount++ + '. ' + value; 7218 } else { 7219 var fontSize = fragmentCSS["font-size"]; 7220 var offsetX = (3 - fontSize * 0.75) * renderer.pdf.internal.scaleFactor; 7221 var offsetY = fontSize * 0.75 * renderer.pdf.internal.scaleFactor; 7222 var radius = fontSize * 1.74 / renderer.pdf.internal.scaleFactor; 7223 cb = function cb(x, y) { 7224 this.pdf.circle(x + offsetX, y + offsetY, radius, 'FD'); 7225 }; 7226 } 7227 } 7228 // Only add the text if the text node is in the body element 7229 // Add compatibility with IE11 7230 if (!!(cn.ownerDocument.body.compareDocumentPosition(cn) & 16)) { 7231 renderer.addText(value, fragmentCSS); 7232 } 7233 } else if (typeof cn === "string") { 7234 renderer.addText(cn, fragmentCSS); 7235 } 7236 } 7237 i++; 7238 } 7239 elementHandlers.outY = renderer.y; 7240 7241 if (isBlock) { 7242 return renderer.setBlockBoundary(cb); 7243 } 7244 }; 7245 images = {}; 7246 loadImgs = function loadImgs(element, renderer, elementHandlers, cb) { 7247 var imgs = element.getElementsByTagName('img'), 7248 l = imgs.length, 7249 found_images, 7250 x = 0; 7251 function done() { 7252 renderer.pdf.internal.events.publish('imagesLoaded'); 7253 cb(found_images); 7254 } 7255 function loadImage(url, width, height) { 7256 if (!url) return; 7257 var img = new Image(); 7258 found_images = ++x; 7259 img.crossOrigin = ''; 7260 img.onerror = img.onload = function () { 7261 if (img.complete) { 7262 //to support data urls in images, set width and height 7263 //as those values are not recognized automatically 7264 if (img.src.indexOf('data:image/') === 0) { 7265 img.width = width || img.width || 0; 7266 img.height = height || img.height || 0; 7267 } 7268 //if valid image add to known images array
7269 if (img.width + img.height) { 7270 var hash = renderer.pdf.sHashCode(url) || url; 7271 images[hash] = images[hash] || img; 7272 } 7273 } 7274 if (! --x) { 7275 done(); 7276 } 7277 }; 7278 img.src = url; 7279 } 7280 while (l--) { 7281 loadImage(imgs[l].getAttribute("src"), imgs[l].width, imgs[l].height); 7282 }return x || done(); 7283 }; 7284 checkForFooter = function checkForFooter(elem, renderer, elementHandlers) { 7285 //check if we can found a <footer> element 7286 var footer = elem.getElementsByTagName("footer"); 7287 if (footer.length > 0) { 7288 7289 footer = footer[0]; 7290 7291 //bad hack to get height of footer 7292 //creat dummy out and check new y after fake rendering 7293 var oldOut = renderer.pdf.internal.write; 7294 var oldY = renderer.y; 7295 renderer.pdf.internal.write = function () {}; 7296 _DrillForContent(footer, renderer, elementHandlers); 7297 var footerHeight = Math.ceil(renderer.y - oldY) + 5; 7298 renderer.y = oldY; 7299 renderer.pdf.internal.write = oldOut; 7300 7301 //add 20% to prevent overlapping 7302 renderer.pdf.margins_doc.bottom += footerHeight; 7303 7304 //Create function render header on every page 7305 var renderFooter = function renderFooter(pageInfo) { 7306 var pageNumber = pageInfo !== undefined ? pageInfo.pageNumber : 1; 7307 //set current y position to old margin 7308 var oldPosition = renderer.y; 7309 //render all child nodes of the header element 7310 renderer.y = renderer.pdf.internal.pageSize.height - renderer.pdf.margins_doc.bottom; 7311 renderer.pdf.margins_doc.bottom -= footerHeight; 7312 7313 //check if we have to add page numbers 7314 var spans = footer.getElementsByTagName('span'); 7315 for (var i = 0; i < spans.length; ++i) { 7316 //if we find some span element with class pageCounter, set the page 7317 if ((" " + spans[i].className + " ").replace(/[\n\t]/g, " ").indexOf(" pageCounter ") > -1) { 7318 spans[i].innerHTML = pageNumber; 7319 } 7320 //if we find some span element with class totalPages, set a variable which is replaced after rendering of all pages 7321 if ((" " + spans[i].className + " ").replace(/[\n\t]/g, " ").indexOf(" totalPages ") > -1) { 7322 spans[i].innerHTML = '###jsPDFVarTotalPages###'; 7323 } 7324 } 7325 7326 //render footer content 7327 _DrillForContent(footer, renderer, elementHandlers); 7328 //set bottom margin to previous height including the footer height 7329 renderer.pdf.margins_doc.bottom += footerHeight; 7330 //important for other plugins (e.g. table) to start rendering at correct position after header 7331 renderer.y = oldPosition; 7332 }; 7333 7334 //check if footer contains totalPages which should be replace at the disoposal of the document 7335 var spans = footer.getElementsByTagName('span'); 7336 for (var i = 0; i < spans.length; ++i) { 7337 if ((" " + spans[i].className + " ").replace(/[\n\t]/g, " ").indexOf(" totalPages ") > -1) { 7338 renderer.pdf.internal.events.subscribe('htmlRenderingFinished', renderer.pdf.putTotalPages.bind(renderer.pdf, '###jsPDFVarTotalPages###'), true); 7339 } 7340 } 7341 7342 //register event to render footer on every new page 7343 renderer.pdf.internal.events.subscribe('addPage', renderFooter, false); 7344 //render footer on first page 7345 renderFooter(); 7346 7347 //prevent footer rendering 7348 SkipNode['FOOTER'] = 1; 7349 } 7350 }; 7351 process = function process(pdf, element, x, y, settings, c
7351allback) { 7352 if (!element) return false; 7353 if (typeof element !== "string" && !element.parentNode) element = '' + element.innerHTML; 7354 if (typeof element === "string") { 7355 element = function (element) { 7356 var $frame, $hiddendiv, framename, visuallyhidden; 7357 framename = "jsPDFhtmlText" + Date.now().toString() + (Math.random() * 1000).toFixed(0); 7358 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;"; 7359 $hiddendiv = document.createElement('div'); 7360 $hiddendiv.style.cssText = visuallyhidden; 7361 $hiddendiv.innerHTML = "<iframe style=\"height:1px;width:1px\" name=\"" + framename + "\" />"; 7362 document.body.appendChild($hiddendiv); 7363 $frame = window.frames[framename]; 7364 $frame.document.open(); 7365 $frame.document.writeln(element); 7366 $frame.document.close(); 7367 return $frame.document.body; 7368 }(element.replace(/<\/?script[^>]*?>/gi, '')); 7369 } 7370 var r = new Renderer(pdf, x, y, settings), 7371 out; 7372 7373 // 1. load images 7374 // 2. prepare optional footer elements 7375 // 3. render content 7376 loadImgs.call(this, element, r, settings.elementHandlers, function (found_images) { 7377 checkForFooter(element, r, settings.elementHandlers); 7378 _DrillForContent(element, r, settings.elementHandlers); 7379 //send event dispose for final taks (e.g. footer totalpage replacement) 7380 r.pdf.internal.events.publish('htmlRenderingFinished'); 7381 out = r.dispose(); 7382 if (typeof callback === 'function') callback(out);else if (found_images) console.error('jsPDF Warning: rendering issues? provide a callback to fromHTML!'); 7383 }); 7384 return out || { x: r.x, y: r.y }; 7385 }; 7386 Renderer.prototype.init = function () { 7387 this.paragraph = { 7388 text: [], 7389 style: [] 7390 }; 7391 return this.pdf.internal.write("q"); 7392 }; 7393 Renderer.prototype.dispose = function () { 7394 this.pdf.internal.write("Q"); 7395 return { 7396 x: this.x, 7397 y: this.y, 7398 ready: true 7399 }; 7400 }; 7401 7402 //Checks if we have to execute some watcher functions 7403 //e.g. to end text floating around an image 7404 Renderer.prototype.executeWatchFunctions = function (el) { 7405 var ret = false;
7406 var narray = []; 7407 if (this.watchFunctions.length > 0) { 7408 for (var i = 0; i < this.watchFunctions.length; ++i) { 7409 if (this.watchFunctions[i](el) === true) { 7410 ret = true; 7411 } else { 7412 narray.push(this.watchFunctions[i]); 7413 } 7414 } 7415 this.watchFunctions = narray; 7416 } 7417 return ret; 7418 }; 7419 7420 Renderer.prototype.splitFragmentsIntoLines = function (fragments, styles) { 7421 var currentLineLength, defaultFontSize, ff, fontMetrics, fontMetricsCache, fragment, fragmentChopped, fragmentLength, fragmentSpecificMetrics, fs, k, line, lines, maxLineLength, style; 7422 defaultFontSize = 12; 7423 k = this.pdf.internal.scaleFactor; 7424 fontMetricsCache = {}; 7425 ff = void 0; 7426 fs = void 0; 7427 fontMetrics = void 0; 7428 fragment = void 0; 7429 style = void 0; 7430 fragmentSpecificMetrics = void 0; 7431 fragmentLength = void 0; 7432 fragmentChopped = void 0; 7433 line = []; 7434 lines = [line]; 7435 currentLineLength = 0; 7436 maxLineLength = this.settings.width; 7437 while (fragments.length) { 7438 fragment = fragments.shift(); 7439 style = styles.shift(); 7440 if (fragment) { 7441 ff = style["font-family"]; 7442 fs = style["font-style"]; 7443 fontMetrics = fontMetricsCache[ff + fs]; 7444 if (!fontMetrics) { 7445 fontMetrics = this.pdf.internal.getFont(ff, fs).metadata.Unicode; 7446 fontMetricsCache[ff + fs] = fontMetrics; 7447 } 7448 fragmentSpecificMetrics = { 7449 widths: fontMetrics.widths, 7450 kerning: fontMetrics.kerning, 7451 fontSize: style["font-size"] * defaultFontSize, 7452 textIndent: currentLineLength 7453 }; 7454 fragmentLength = this.pdf.getStringUnitWidth(fragment, fragmentSpecificMetrics) * fragmentSpecificMetrics.fontSize / k; 7455 if (fragment == "\u2028") { 7456 line = []; 7457 lines.push(line); 7458 } else if (currentLineLength + fragmentLength > maxLineLength) { 7459 fragmentChopped = this.pdf.splitTextToSize(fragment, maxLineLength, fragmentSpecificMetrics); 7460 line.push([fragmentChopped.shift(), style]); 7461 while (fragmentChopped.length) { 7462 line = [[fragmentChopped.shift(), style]]; 7463 lines.push(line); 7464 } 7465 currentLineLength = this.pdf.getStringUnitWidth(line[0][0], fragmentSpecificMetrics) * fragmentSpecificMetrics.fontSize / k; 7466 } else { 7467 line.push([fragment, style]); 7468 currentLineLength += fragmentLength; 7469 } 7470 } 7471 } 7472 7473 //if text alignment was set, set margin/indent of each line 7474 if (style['text-align'] !== undefined && (style['text-align'] === 'center' || style['text-align'] === 'right' || style['text-align'] === 'justify')) { 7475 for (var i = 0; i < lines.length; ++i) { 7476 var length = this.pdf.getStringUnitWidth(lines[i][0][0], fragmentSpecificMetrics) * fragmentSpecificMetrics.fontSize / k; 7477 //if there is more than on line we have to clone the style object as all lines hold a reference on this object 7478 if (i > 0) { 7479 lines[i][0][1] = clone(lines[i][0][1]); 7480 } 7481 var space = maxLineLength - length; 7482 7483 if (style['text-align'] === 'right') { 7484 lines[i][0][1]['margin-left'] = space; 7485 //if alignment is not right, it has to be center so split the space to the left and the right 7486 } else if (style['text-align'] === 'center') { 7487 lines[i][0][1]['margin-left'] = space / 2; 7488 //if justify was set, calculate the word spacing and define in by using the css property 7489 } else if (style['text-align'] === 'justify') {
7490 var countSpaces = lines[i][0][0].split(' ').length - 1; 7491 lines[i][0][1]['word-spacing'] = space / countSpaces; 7492 //ignore the last line in justify mode 7493 if (i === lines.length - 1) { 7494 lines[i][0][1]['word-spacing'] = 0; 7495 } 7496 } 7497 } 7498 } 7499 7500 return lines; 7501 }; 7502 Renderer.prototype.RenderTextFragment = function (text, style) { 7503 var defaultFontSize, font, maxLineHeight; 7504 7505 maxLineHeight = 0; 7506 defaultFontSize = 12; 7507 7508 if (this.pdf.internal.pageSize.height - this.pdf.margins_doc.bottom < this.y + this.pdf.internal.getFontSize()) { 7509 this.pdf.internal.write("ET", "Q"); 7510 this.pdf.addPage(); 7511 this.y = this.pdf.margins_doc.top; 7512 this.pdf.internal.write("q", "BT 0 g", this.pdf.internal.getCoordinateString(this.x), this.pdf.internal.getVerticalCoordinateString(this.y), style.color, "Td"); 7513 //move cursor by one line on new page 7514 maxLineHeight = Math.max(maxLineHeight, style["line-height"], style["font-size"]); 7515 this.pdf.internal.write(0, (-1 * defaultFontSize * maxLineHeight).toFixed(2), "Td"); 7516 } 7517 7518 font = this.pdf.internal.getFont(style["font-family"], style["font-style"]); 7519 7520 // text color 7521 var pdfTextColor = this.getPdfColor(style["color"]); 7522 if (pdfTextColor !== this.lastTextColor) { 7523 this.pdf.internal.write(pdfTextColor); 7524 this.lastTextColor = pdfTextColor; 7525 } 7526 7527 //set the word spacing for e.g. justify style 7528 if (style['word-spacing'] !== undefined && style['word-spacing'] > 0) { 7529 this.pdf.internal.write(style['word-spacing'].toFixed(2), "Tw"); 7530 } 7531 7532 this.pdf.internal.write("/" + font.id, (defaultFontSize * style["font-size"]).toFixed(2), "Tf", "(" + this.pdf.internal.pdfEscape(text) + ") Tj"); 7533 7534 //set the word spacing back to neutral => 0 7535 if (style['word-spacing'] !== undefined) { 7536 this.pdf.internal.write(0, "Tw"); 7537 } 7538 }; 7539 7540 // Accepts #FFFFFF, rgb(int,int,int), or CSS Color Name 7541 Renderer.prototype.getPdfColor = function (style) { 7542 var textColor; 7543 var r, g, b; 7544 7545 var rx = /rgb\s*\(\s*(\d+),\s*(\d+),\s*(\d+\s*)\)/; 7546 var m = rx.exec(style); 7547 if (m != null) { 7548 r = parseInt(m[1]); 7549 g = parseInt(m[2]); 7550 b = parseInt(m[3]); 7551 } else { 7552 if (style.charAt(0) != '#') { 7553 style = CssColors.colorNameToHex(style); 7554 if (!style) { 7555 style = '#000000'; 7556 } 7557 } 7558 r = style.substring(1, 3); 7559 r = parseInt(r, 16); 7560 g = style.substring(3, 5); 7561 g = parseInt(g, 16); 7562 b = style.substring(5, 7); 7563 b = parseInt(b, 16); 7564 } 7565 7566 if (typeof r === 'string' && /^#[0-9A-Fa-f]{6}$/.test(r)) { 7567 var hex = parseInt(r.substr(1), 16); 7568 r = hex >> 16 & 255; 7569 g = hex >> 8 & 255; 7570 b = hex & 255; 7571 } 7572 7573 var f3 = this.f3; 7574 if (r === 0 && g === 0 && b === 0 || typeof g === 'undefined') { 7575 textColor = f3(r / 255) + ' g'; 7576 } else { 7577 textColor = [f3(r / 255), f3(g / 255), f3(b / 255), 'rg'].join(' '); 7578 } 7579 return textColor; 7580 }; 7581 7582 Renderer.prototype.f3 = function (number) { 7583 return number.toFixed(3); // Ie, %.3f 7584 }, Renderer.prototype.renderParagraph = function (cb) { 7585 var blockstyle, defaultFontSize, fontToUnitRatio, fragments, i, l, line, lines, maxLineHeight, out, paragraphspacing_after, paragraphspacing_before, priorblockstyle, styles, fontSize; 7586 fragments = PurgeWhiteSpace(this.paragraph.text); 7587 styles = this.paragraph.style; 7588 blockstyle = this.paragraph.blockstyle; 7589 priorblockstyle = this.paragraph.priorblockstyle || {}; 7590 this.paragraph = { 7591 text: [], 7592 style: [], 7593 blockstyle: {}, 7594 priorblockstyle: blockstyle 7595 }; 7596 if (!fragments.join("").trim()) { 7597 return; 7598 } 7599 lines = this.splitFragmentsIntoLines(fragments, styles); 7600 line = void 0; 7601 maxLineHeight = void 0; 7602 defaultFontSize = 12; 7603 fontToUnitRatio = defaultFontSize / this.pdf.internal.scaleFactor; 7604 this.priorMarginBottom = this.priorMarginBottom || 0; 7605 paragraphspacing_before = (Math.max((blockstyle["margin-top"] || 0) - this.priorMarginBottom, 0) + (blockstyle["padding-top"] || 0)) * fontToUnitRatio; 7606 paragraphspacing_after = ((blockstyle["margin-bottom"] || 0) + (blockstyle["padding-bottom"] || 0)) * fontToUnitRatio; 7607 this.priorMarginBottom = blockstyle["margin-bottom"] || 0; 7608 7609 if (blockstyle['page-break-before'] === 'always') { 7610 this.pdf.addPage(); 7611 this.y = 0; 7612 paragraphspacing_before = ((blockstyle["margin-top"] || 0) + (blockstyle["padding-top"] || 0)) * fontToUnitRatio; 7613 } 7614 7615 out = this.pdf.internal.write; 7616 i = void 0; 7617 l = void 0; 7618 this.y += paragraphspacing_before; 7619 out("q", "BT 0 g", this.pdf.internal.getCoordinateString(this.x), this.pdf.internal.getVerticalCoordinateString(this.y), "Td"); 7620 7621 //stores the current indent of cursor position 7622 var currentIndent = 0; 7623 7624 while (lines.length) { 7625 line = lines.shift(); 7626 maxLineHeight = 0; 7627 i = 0; 7628 l = line.length; 7629 while (i !== l) { 7630 if (line[i][0].trim()) { 7631 maxLineHeight = Math.max(maxLineHeight, line[i][1]["line-height"], line[i][1]["font-size"]); 7632 fontSize = line[i][1]["font-size"] * 7; 7633 } 7634 i++; 7635 } 7636 //if we have to move the cursor to adapt the indent 7637 var indentMove = 0; 7638 var wantedIndent = 0; 7639 //if a margin was added (by e.g. a text-alignment), move the cursor 7640 if (line[0][1]["margin-left"] !== undefined && line[0][1]["margin-left"] > 0) { 7641 wantedIndent = this.pdf.internal.getCoordinateString(line[0][1]["margin-left"]); 7642 indentMove = wantedIndent - currentIndent; 7643 currentIndent = wantedIndent; 7644 } 7645 var indentMore = Math.max(blockstyle["margin-left"] || 0, 0) * fontToUnitRatio; 7646 //move the cursor 7647 out(indentMove + indentMore, (-1 * defaultFontSize * maxLineHeight).toFixed(2), "Td"); 7648 i = 0; 7649 l = line.length; 7650 while (i !== l) { 7651 if (line[i][0]) { 7652 this.RenderTextFragment(line[i][0], line[i][1]); 7653 } 7654 i++; 7655 } 7656 this.y += maxLineHeight * fontToUnitRatio; 7657 7658 //if some watcher function was executed successful, so e.g. margin and widths were changed, 7659 //reset line drawing and calculate position and lines again 7660 //e.g. to stop text floating around an image
7661 if (this.executeWatchFunctions(line[0][1]) && lines.length > 0) { 7662 var localFragments = []; 7663 var localStyles = []; 7664 //create fragment array of 7665 lines.forEach(function (localLine) { 7666 var i = 0; 7667 var l = localLine.length; 7668 while (i !== l) { 7669 if (localLine[i][0]) { 7670 localFragments.push(localLine[i][0] + ' '); 7671 localStyles.push(localLine[i][1]); 7672 } 7673 ++i; 7674 } 7675 }); 7676 //split lines again due to possible coordinate changes 7677 lines = this.splitFragmentsIntoLines(PurgeWhiteSpace(localFragments), localStyles); 7678 //reposition the current cursor 7679 out("ET", "Q"); 7680 out("q", "BT 0 g", this.pdf.internal.getCoordinateString(this.x), this.pdf.internal.getVerticalCoordinateString(this.y), "Td"); 7681 } 7682 } 7683 if (cb && typeof cb === "function") { 7684 cb.call(this, this.x - 9, this.y - fontSize / 2); 7685 } 7686 out("ET", "Q"); 7687 return this.y += paragraphspacing_after; 7688 }; 7689 Renderer.prototype.setBlockBoundary = function (cb) { 7690 return this.renderParagraph(cb); 7691 }; 7692 Renderer.prototype.setBlockStyle = function (css) { 7693 return this.paragraph.blockstyle = css; 7694 }; 7695 Renderer.prototype.addText = function (text, css) { 7696 this.paragraph.text.push(text); 7697 return this.paragraph.style.push(css); 7698 }; 7699 FontNameDB = { 7700 helvetica: "helvetica", 7701 "sans-serif": "helvetica", 7702 "times new roman": "times", 7703 serif: "times", 7704 times: "times", 7705 monospace: "courier", 7706 courier: "courier" 7707 }; 7708 FontWeightMap = { 7709 100: "normal", 7710 200: "normal", 7711 300: "normal", 7712 400: "normal", 7713 500: "bold", 7714 600: "bold", 7715 700: "bold", 7716 800: "bold", 7717 900: "bold", 7718 normal: "normal", 7719 bold: "bold", 7720 bolder: "bold", 7721 lighter: "normal" 7722 }; 7723 FontStyleMap = { 7724 normal: "normal", 7725 italic: "italic", 7726 oblique: "italic" 7727 }; 7728 TextAlignMap = { 7729 left: "left", 7730 right: "right", 7731 center: "center", 7732 justify: "justify" 7733 }; 7734 FloatMap = { 7735 none: 'none', 7736 right: 'right', 7737 left: 'left' 7738 }; 7739 ClearMap = { 7740 none: 'none', 7741 both: 'both' 7742 }; 7743 UnitedNumberMap = { 7744 normal: 1 7745 }; 7746 /** 7747 * Converts HTML-formatted text into formatted PDF text. 7748 * 7749 * Notes: 7750 * 2012-07-18 7751 * Plugin relies on having browser, DOM around. The HTML is pushed into dom and traversed. 7752 * Plugin relies on jQuery for CSS extraction. 7753 * Targeting HTML output from Markdown templating, which is a very simple 7754 * markup - div, span, em, strong, p. No br-based paragraph separation supported explicitly (but still may work.) 7755 * Images, tables are NOT supported. 7756 * 7757 * @public 7758 * @function 7759 * @param HTML {String or DOM Element} HTML-formatted text, or pointer to DOM element that is to be rendered into PDF. 7760 * @param x {Number} starting X coordinate in jsPDF instance's declared units. 7761 * @param y {Number} starting Y coordinate in jsPDF instance's declared units. 7762 * @param settings {Object} Additional / optional variables controlling parsing, rendering. 7763 * @returns {Object} jsPDF instance 7764 */ 7765 jsPDFAPI.fromHTML = function (HTML, x, y, settings, callback, margins) { 7766 "use strict"; 7767 7768 this.margins_doc = margins || { 7769 top: 0, 7770 bottom: 0 7771 }; 7772 if (!settings) settings = {}; 7773 if (!settings.elementHandlers) settings.elementHandlers = {}; 7774 7775 return process(this, HTML, isNaN(x) ? 4 : x, isNaN(y) ? 4 : y, settings, c
7775allback); 7776 }; 7777 })(jsPDF.API); 7778 7779 /** ==================================================================== 7780 * jsPDF JavaScript plugin 7781 * Copyright (c) 2013 Youssef Beddad, [email protected] 7782 * 7783 * 7784 * ==================================================================== 7785 */ 7786 7787 /*global jsPDF */ 7788 7789 (function (jsPDFAPI) { 7790 'use strict'; 7791 7792 var jsNamesObj, jsJsObj, text; 7793 jsPDFAPI.addJS = function (txt) { 7794 text = txt; 7795 this.internal.events.subscribe('postPutResources', function (txt) { 7796 jsNamesObj = this.internal.newObject(); 7797 this.internal.write('<< /Names [(EmbeddedJS) ' + (jsNamesObj + 1) + ' 0 R] >>', 'endobj'); 7798 jsJsObj = this.internal.newObject(); 7799 this.internal.write('<< /S /JavaScript /JS (', text, ') >>', 'endobj'); 7800 }); 7801 this.internal.events.subscribe('putCatalog', function () { 7802 if (jsNamesObj !== undefined && jsJsObj !== undefined) { 7803 this.internal.write('/Names <</JavaScript ' + jsNamesObj + ' 0 R>>'); 7804 } 7805 }); 7806 return this; 7807 }; 7808 })(jsPDF.API); 7809 7810 /** 7811 * jsPDF Outline PlugIn 7812 * Copyright (c) 2014 Steven Spungin (TwelveTone LLC) [email protected] 7813 * 7814 * Licensed under the MIT License. 7815 * http://opensource.org/licenses/mit-license 7816 */ 7817 7818 /** 7819 * Generates a PDF Outline 7820 */ 7821 ; 7822 (function (jsPDFAPI) { 7823 'use strict'; 7824 7825 jsPDFAPI.events.push(['postPutResources', function () { 7826 var pdf = this; 7827 var rx = /^(\d+) 0 obj$/; 7828 7829 // Write action goto objects for each page 7830 // this.outline.destsGoto = []; 7831 // for (var i = 0; i < totalPages; i++) { 7832 // var id = pdf.internal.newObject(); 7833 // this.outline.destsGoto.push(id); 7834 // pdf.internal.write("<</D[" + (i * 2 + 3) + " 0 R /XYZ null 7835 // null null]/S/GoTo>> endobj"); 7836 // } 7837 // 7838 // for (var i = 0; i < dests.length; i++) { 7839 // pdf.internal.write("(page_" + (i + 1) + ")" + dests[i] + " 0 7840 // R"); 7841 // } 7842 // 7843 if (this.outline.root.children.length > 0) { 7844 var lines = pdf.outline.render().split(/\r\n/); 7845 for (var i = 0; i < lines.length; i++) { 7846 var line = lines[i]; 7847 var m = rx.exec(line); 7848 if (m != null) { 7849 var oid = m[1]; 7850 pdf.internal.newObjectDeferredBegin(oid); 7851 } 7852 pdf.internal.write(line); 7853 } 7854 } 7855 7856 // This code will write named destination for each page reference 7857 // (page_1, etc) 7858 if (this.outline.createNamedDestinations) { 7859 var totalPages = this.internal.pages.length; 7860 // WARNING: this assumes jsPDF starts on page 3 and pageIDs 7861 // follow 5, 7, 9, etc 7862 // Write destination objects for each page 7863 var dests = []; 7864 for (var i = 0; i < totalPages; i++) { 7865 var id = pdf.internal.newObject(); 7866 dests.push(id); 7867 var info = pdf.internal.getPageInfo(i + 1); 7868 pdf.internal.write("<< /D[" + info.objId + " 0 R /XYZ null null null]>> endobj"); 7869 } 7870 7871 // assign a name for each destination 7872 var names2Oid = pdf.internal.newObject(); 7873 pdf.internal.write('<< /Names [ '); 7874 for (var i = 0; i < dests.length; i++) { 7875 pdf.internal.write("(page_" + (i + 1) + ")" + dests[i] + " 0 R"); 7876 } 7877 pdf.internal.write(' ] >>', 'endobj'); 7878 7879 // var kids = pdf.internal.newObject(); 7880 // pdf.internal.write('<< /Kids [ ' + names2Oid + ' 0 R'); 7881 // pdf.internal.write(' ] >>', 'endobj'); 7882 7883 var namesOid = pdf.internal.newObject();
vendor: 7,804 bytes, lines 7884-8091
7884 pdf.internal.write('<< /Dests ' + names2Oid + " 0 R"); 7885 pdf.internal.write('>>', 'endobj'); 7886 } 7887 }]); 7888 7889 jsPDFAPI.events.push(['putCatalog', function () { 7890 var pdf = this; 7891 if (pdf.outline.root.children.length > 0) { 7892 pdf.internal.write("/Outlines", this.outline.makeRef(this.outline.root)); 7893 if (this.outline.createNamedDestinations) { 7894 pdf.internal.write("/Names " + namesOid + " 0 R"); 7895 } 7896 // Open with Bookmarks showing 7897 // pdf.internal.write("/PageMode /UseOutlines"); 7898 } 7899 }]); 7900 7901 jsPDFAPI.events.push(['initialized', function () { 7902 var pdf = this; 7903 7904 pdf.outline = { 7905 createNamedDestinations: false, 7906 root: { 7907 children: [] 7908 } 7909 }; 7910 7911 var namesOid; 7912 var destsGoto = []; 7913 7914 /** 7915 * Options: pageNumber 7916 */ 7917 pdf.outline.add = function (parent, title, options) { 7918 var item = { 7919 title: title, 7920 options: options, 7921 children: [] 7922 }; 7923 if (parent == null) { 7924 parent = this.root; 7925 } 7926 parent.children.push(item); 7927 return item; 7928 }; 7929 7930 pdf.outline.render = function () { 7931 this.ctx = {}; 7932 this.ctx.val = ''; 7933 this.ctx.pdf = pdf; 7934 7935 this.genIds_r(this.root); 7936 this.renderRoot(this.root); 7937 this.renderItems(this.root); 7938 7939 return this.ctx.val; 7940 }; 7941 7942 pdf.outline.genIds_r = function (node) { 7943 node.id = pdf.internal.newObjectDeferred(); 7944 for (var i = 0; i < node.children.length; i++) { 7945 this.genIds_r(node.children[i]); 7946 } 7947 }; 7948 7949 pdf.outline.renderRoot = function (node) { 7950 this.objStart(node); 7951 this.line('/Type /Outlines'); 7952 if (node.children.length > 0) { 7953 this.line('/First ' + this.makeRef(node.children[0])); 7954 this.line('/Last ' + this.makeRef(node.children[node.children.length - 1])); 7955 } 7956 this.line('/Count ' + this.count_r({ 7957 count: 0 7958 }, node)); 7959 this.objEnd(); 7960 }; 7961 7962 pdf.outline.renderItems = function (node) { 7963 for (var i = 0; i < node.children.length; i++) { 7964 var item = node.children[i]; 7965 this.objStart(item); 7966 7967 this.line('/Title ' + this.makeString(item.title)); 7968 7969 this.line('/Parent ' + this.makeRef(node)); 7970 if (i > 0) { 7971 this.line('/Prev ' + this.makeRef(node.children[i - 1])); 7972 } 7973 if (i < node.children.length - 1) { 7974 this.line('/Next ' + this.makeRef(node.children[i + 1])); 7975 } 7976 if (item.children.length > 0) { 7977 this.line('/First ' + this.makeRef(item.children[0])); 7978 this.line('/Last ' + this.makeRef(item.children[item.children.length - 1])); 7979 } 7980 7981 var count = this.count = this.count_r({ 7982 count: 0 7983 }, item); 7984 if (count > 0) { 7985 this.line('/Count ' + count); 7986 } 7987 7988 if (item.options) { 7989 if (item.options.pageNumber) { 7990 // Explicit Destination 7991 //WARNING this assumes page ids are 3,5,7, etc. 7992 var info = pdf.internal.getPageInfo(item.options.pageNumber); 7993 this.line('/Dest ' + '[' + info.objId + ' 0 R /XYZ 0 ' + this.ctx.pdf.internal.pageSize.height + ' 0]'); 7994 // this line does not work on all clients (pageNumber instead of page ref) 7995 //this.line('/Dest ' + '[' + (item.options.pageNumber - 1) + ' /XYZ 0 ' + this.ctx.pdf.internal.pageSize.height + ' 0]'); 7996 7997 // Named Destination 7998 // this.line('/Dest (page_' + (item.options.pageNumber) + ')'); 7999 8000 // Action Destination 8001 // var id = pdf.internal.newObject(); 8002 // pdf.internal.write('<</D[' + (item.options.pageNumber - 1) + ' /XYZ null null null]/S/GoTo>> endobj'); 8003 // this.line('/A ' + id + ' 0 R' ); 8004 } 8005 } 8006 this.objEnd(); 8007 } 8008 for (var i = 0; i < node.children.length; i++) { 8009 var item = node.children[i]; 8010 this.renderItems(item); 8011 } 8012 }; 8013 8014 pdf.outline.line = function (text) { 8015 this.ctx.val += text + '\r\n'; 8016 }; 8017 8018 pdf.outline.makeRef = function (node) { 8019 return node.id + ' 0 R'; 8020 }; 8021 8022 pdf.outline.makeString = function (val) { 8023 return '(' + pdf.internal.pdfEscape(val) + ')'; 8024 }; 8025 8026 pdf.outline.objStart = function (node) { 8027 this.ctx.val += '\r\n' + node.id + ' 0 obj' + '\r\n<<\r\n'; 8028 }; 8029 8030 pdf.outline.objEnd = function (node) { 8031 this.ctx.val += '>> \r\n' + 'endobj' + '\r\n'; 8032 }; 8033 8034 pdf.outline.count_r = function (ctx, node) { 8035 for (var i = 0; i < node.children.length; i++) { 8036 ctx.count++; 8037 this.count_r(ctx, node.children[i]); 8038 } 8039 return ctx.count; 8040 }; 8041 }]); 8042 8043 return this; 8044 })(jsPDF.API); 8045 8046 /**@preserve 8047 * ==================================================================== 8048 * jsPDF PNG PlugIn 8049 * Copyright (c) 2014 James Robb, https://github.com/jamesbrobb 8050 * 8051 * 8052 * ==================================================================== 8053 */ 8054 8055 (function (jsPDFAPI) { 8056 'use strict'; 8057 8058 /* 8059 * @see http://www.w3.org/TR/PNG-Chunks.html 8060 * 8061 Color Allowed Interpretation 8062 Type Bit Depths 8063 0 1,2,4,8,16 Each pixel is a grayscale sample. 8064 2 8,16 Each pixel is an R,G,B triple. 8065 3 1,2,4,8 Each pixel is a palette index; 8066 a PLTE chunk must appear. 8067 4 8,16 Each pixel is a grayscale sample, 8068 followed by an alpha sample. 8069 6 8,16 Each pixel is an R,G,B triple, 8070 followed by an alpha sample. 8071 */ 8072 8073 /* 8074 * PNG filter method types 8075 * 8076 * @see http://www.w3.org/TR/PNG-Filters.html 8077 * @see http://www.libpng.org/pub/png/book/chapter09.html 8078 * 8079 * This is what the value 'Predictor' in decode params relates to 8080 * 8081 * 15 is "optimal prediction", which means the prediction algorithm can change from line to line. 8082 * 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. 8083 * 8084 0 None 8085 1 Sub 8086 2 Up 8087 3 Average 8088 4 Paeth 8089 */ 8090 8091 var doesNotHavePngJS = function doesNotHavePngJS() {
8092 return typeof PNG !== 'function' || typeof FlateStream !== 'function'; 8093 }, 8094 canCompress = function canCompress(value) { 8095 return value !== jsPDFAPI.image_compression.NONE && hasCompressionJS(); 8096 }, 8097 hasCompressionJS = function hasCompressionJS() { 8098 var inst = typeof Deflater === 'function'; 8099 if (!inst) throw new Error("requires deflate.js for compression"); 8100 return inst; 8101 }, 8102 compressBytes = function compressBytes(bytes, lineLength, colorsPerPixel, compression) { 8103 8104 var level = 5, 8105 filter_method = filterUp; 8106 8107 switch (compression) { 8108 8109 case jsPDFAPI.image_compression.FAST: 8110 8111 level = 3; 8112 filter_method = filterSub; 8113 break; 8114 8115 case jsPDFAPI.image_compression.MEDIUM: 8116 8117 level = 6; 8118 filter_method = filterAverage; 8119 break; 8120 8121 case jsPDFAPI.image_compression.SLOW: 8122 8123 level = 9; 8124 filter_method = filterPaeth; //uses to sum to choose best filter for each line 8125 break; 8126 } 8127 8128 bytes = applyPngFilterMethod(bytes, lineLength, colorsPerPixel, filter_method); 8129 8130 var header = new Uint8Array(createZlibHeader(level)); 8131 var checksum = adler32(bytes); 8132 8133 var deflate = new Deflater(level); 8134 var a = deflate.append(bytes); 8135 var cBytes = deflate.flush(); 8136 8137 var len = header.length + a.length + cBytes.length; 8138 8139 var cmpd = new Uint8Array(len + 4); 8140 cmpd.set(header); 8141 cmpd.set(a, header.length); 8142 cmpd.set(cBytes, header.length + a.length); 8143 8144 cmpd[len++] = checksum >>> 24 & 0xff; 8145 cmpd[len++] = checksum >>> 16 & 0xff; 8146 cmpd[len++] = checksum >>> 8 & 0xff; 8147 cmpd[len++] = checksum & 0xff; 8148 8149 return jsPDFAPI.arrayBufferToBinaryString(cmpd); 8150 }, 8151 createZlibHeader = function createZlibHeader(bytes, level) { 8152 /* 8153 * @see http://www.ietf.org/rfc/rfc1950.txt for zlib header 8154 */ 8155 var cm = 8; 8156 var cinfo = Math.LOG2E * Math.log(0x8000) - 8; 8157 var cmf = cinfo << 4 | cm; 8158 8159 var hdr = cmf << 8; 8160 var flevel = Math.min(3, (level - 1 & 0xff) >> 1); 8161 8162 hdr |= flevel << 6; 8163 hdr |= 0; //FDICT 8164 hdr += 31 - hdr % 31; 8165 8166 return [cmf, hdr & 0xff & 0xff]; 8167 }, 8168 adler32 = function adler32(array, param) { 8169 var adler = 1; 8170 var s1 = adler & 0xffff, 8171 s2 = adler >>> 16 & 0xffff; 8172 var len = array.length; 8173 var tlen; 8174 var i = 0; 8175 8176 while (len > 0) { 8177 tlen = len > param ? param : len; 8178 len -= tlen; 8179 do { 8180 s1 += array[i++]; 8181 s2 += s1; 8182 } while (--tlen); 8183 8184 s1 %= 65521; 8185 s2 %= 65521; 8186 } 8187 8188 return (s2 << 16 | s1) >>> 0; 8189 }, 8190 applyPngFilterMethod = function applyPngFilterMethod(bytes, lineLength, colorsPerPixel, filter_method) { 8191 var lines = bytes.length / lineLength, 8192 result = new Uint8Array(bytes.length + lines), 8193 filter_methods = getFilterMethods(), 8194 i = 0, 8195 line, 8196 prevLine, 8197 offset; 8198 8199 for (; i < lines; i++) { 8200 offset = i * lineLength; 8201 line = bytes.subarray(offset, offset + lineLength); 8202 8203 if (filter_method) {
8204 result.set(filter_method(line, colorsPerPixel, prevLine), offset + i); 8205 } else { 8206 8207 var j = 0, 8208 len = filter_methods.length, 8209 results = []; 8210 8211 for (; j < len; j++) { 8212 results[j] = filter_methods[j](line, colorsPerPixel, prevLine); 8213 }var ind = getIndexOfSmallestSum(results.concat()); 8214 8215 result.set(results[ind], offset + i); 8216 } 8217 8218 prevLine = line; 8219 } 8220 8221 return result; 8222 }, 8223 filterNone = function filterNone(line, colorsPerPixel, prevLine) { 8224 /*var result = new Uint8Array(line.length + 1); 8225 result[0] = 0; 8226 result.set(line, 1);*/ 8227 8228 var result = Array.apply([], line); 8229 result.unshift(0); 8230 8231 return result; 8232 }, 8233 filterSub = function filterSub(line, colorsPerPixel, prevLine) { 8234 var result = [], 8235 i = 0, 8236 len = line.length, 8237 left; 8238 8239 result[0] = 1; 8240 8241 for (; i < len; i++) { 8242 left = line[i - colorsPerPixel] || 0; 8243 result[i + 1] = line[i] - left + 0x0100 & 0xff;
8244 } 8245 8246 return result; 8247 }, 8248 filterUp = function filterUp(line, colorsPerPixel, prevLine) { 8249 var result = [], 8250 i = 0, 8251 len = line.length, 8252 up; 8253 8254 result[0] = 2; 8255 8256 for (; i < len; i++) { 8257 up = prevLine && prevLine[i] || 0; 8258 result[i + 1] = line[i] - up + 0x0100 & 0xff; 8259 } 8260 8261 return result; 8262 }, 8263 filterAverage = function filterAverage(line, colorsPerPixel, prevLine) { 8264 var result = [], 8265 i = 0, 8266 len = line.length, 8267 left, 8268 up; 8269 8270 result[0] = 3; 8271 8272 for (; i < len; i++) { 8273 left = line[i - colorsPerPixel] || 0; 8274 up = prevLine && prevLine[i] || 0; 8275 result[i + 1] = line[i] + 0x0100 - (left + up >>> 1) & 0xff; 8276 } 8277 8278 return result; 8279 }, 8280 filterPaeth = function filterPaeth(line, colorsPerPixel, prevLine) { 8281 var result = [], 8282 i = 0, 8283 len = line.length, 8284 left, 8285 up, 8286 upLeft, 8287 paeth; 8288 8289 result[0] = 4; 8290 8291 for (; i < len; i++) { 8292 left = line[i - colorsPerPixel] || 0; 8293 up = prevLine && prevLine[i] || 0; 8294 upLeft = prevLine && prevLine[i - colorsPerPixel] || 0; 8295 paeth = paethPredictor(left, up, upLeft); 8296 result[i + 1] = line[i] - paeth + 0x0100 & 0xff;
8297 } 8298 8299 return result; 8300 }, 8301 paethPredictor = function paethPredictor(left, up, upLeft) { 8302 8303 var p = left + up - upLeft, 8304 pLeft = Math.abs(p - left), 8305 pUp = Math.abs(p - up), 8306 pUpLeft = Math.abs(p - upLeft); 8307 8308 return pLeft <= pUp && pLeft <= pUpLeft ? left : pUp <= pUpLeft ? up : upLeft; 8309 }, 8310 getFilterMethods = function getFilterMethods() { 8311 return [filterNone, filterSub, filterUp, filterAverage, filterPaeth]; 8312 }, 8313 getIndexOfSmallestSum = function getIndexOfSmallestSum(arrays) { 8314 var i = 0, 8315 len = arrays.length, 8316 sum, 8317 min, 8318 ind; 8319 8320 while (i < len) { 8321 sum = absSum(arrays[i].slice(1)); 8322 8323 if (sum < min || !min) { 8324 min = sum; 8325 ind = i; 8326 } 8327 8328 i++; 8329 } 8330 8331 return ind; 8332 }, 8333 absSum = function absSum(array) { 8334 var i = 0, 8335 len = array.length, 8336 sum = 0; 8337 8338 while (i < len) { 8339 sum += Math.abs(array[i++]); 8340 }return sum; 8341 }, 8342 getPredictorFromCompression = function getPredictorFromCompression(compression) { 8343 var predictor; 8344 switch (compression) { 8345 case jsPDFAPI.image_compression.FAST: 8346 predictor = 11; 8347 break; 8348 8349 case jsPDFAPI.image_compression.MEDIUM: 8350 predictor = 13; 8351 break; 8352 8353 case jsPDFAPI.image_compression.SLOW: 8354 predictor = 14; 8355 break; 8356 } 8357 return predictor; 8358 }, 8359 logImg = function logImg(img) { 8360 console.log("width: " + img.width);
8361 console.log("height: " + img.height); 8362 console.log("bits: " + img.bits); 8363 console.log("colorType: " + img.colorType); 8364 console.log("transparency:"); 8365 console.log(img.transparency); 8366 console.log("text:"); 8367 console.log(img.text); 8368 console.log("compressionMethod: " + img.compressionMethod); 8369 console.log("filterMethod: " + img.filterMethod); 8370 console.log("interlaceMethod: " + img.interlaceMethod); 8371 console.log("imgData:"); 8372 console.log(img.imgData); 8373 console.log("palette:"); 8374 console.log(img.palette); 8375 console.log("colors: " + img.colors); 8376 console.log("colorSpace: " + img.colorSpace); 8377 console.log("pixelBitlength: " + img.pixelBitlength); 8378 console.log("hasAlphaChannel: " + img.hasAlphaChannel); 8379 }; 8380 8381 jsPDFAPI.processPNG = function (imageData, imageIndex, alias, compression, dataAsBinaryString) { 8382 'use strict'; 8383 8384 var colorSpace = this.color_spaces.DEVICE_RGB, 8385 decode = this.decode.FLATE_DECODE, 8386 bpc = 8, 8387 img, 8388 dp, 8389 trns, 8390 colors, 8391 pal, 8392 smask; 8393 8394 /* if(this.isString(imageData)) { 8395 }*/ 8396 8397 if (this.isArrayBuffer(imageData)) imageData = new Uint8Array(imageData); 8398 8399 if (this.isArrayBufferView(imageData)) { 8400 8401 if (doesNotHavePngJS()) throw new Error("PNG support requires png.js and zlib.js"); 8402 8403 img = new PNG(imageData); 8404 imageData = img.imgData; 8405 bpc = img.bits; 8406 colorSpace = img.colorSpace; 8407 colors = img.colors; 8408 8409 //logImg(img); 8410 8411 /* 8412 * colorType 6 - Each pixel is an R,G,B triple, followed by an alpha sample. 8413 * 8414 * colorType 4 - Each pixel is a grayscale sample, followed by an alpha sample. 8415 * 8416 * Extract alpha to create two separate images, using the alpha as a sMask 8417 */ 8418 if ([4, 6].indexOf(img.colorType) !== -1) { 8419 8420 /* 8421 * processes 8 bit RGBA and grayscale + alpha images 8422 */ 8423 if (img.bits === 8) { 8424 8425 var pixels = img.pixelBitlength == 32 ? new Uint32Array(img.decodePixels().buffer) : img.pixelBitlength == 16 ? new Uint16Array(img.decodePixels().buffer) : new Uint8Array(img.decodePixels().buffer), 8426 len = pixels.length, 8427 imgData = new Uint8Array(len * img.colors), 8428 alphaData = new Uint8Array(len), 8429 pDiff = img.pixelBitlength - img.bits, 8430 i = 0, 8431 n = 0, 8432 pixel, 8433 pbl; 8434 8435 for (; i < len; i++) { 8436 pixel = pixels[i]; 8437 pbl = 0; 8438 8439 while (pbl < pDiff) { 8440 8441 imgData[n++] = pixel >>> pbl & 0xff; 8442 pbl = pbl + img.bits; 8443 } 8444 8445 alphaData[i] = pixel >>> pbl & 0xff; 8446 } 8447 } 8448 8449 /* 8450 * processes 16 bit RGBA and grayscale + alpha images 8451 */ 8452 if (img.bits === 16) { 8453 8454 var pixels = new Uint32Array(img.decodePixels().buffer), 8455 len = pixels.length, 8456 imgData = new Uint8Array(len * (32 / img.pixelBitlength) * img.colors), 8457 alphaData = new Uint8Array(len * (32 / img.pixelBitlength)), 8458 hasColors = img.colors > 1, 8459 i = 0, 8460 n = 0, 8461 a = 0, 8462 pixel; 8463 8464 while (i < len) { 8465 pixel = pixels[i++]; 8466 8467 imgData[n++] = pixel >>> 0 & 0xFF; 8468 8469 if (hasColors) { 8470 imgData[n++] = pixel >>> 16 & 0xFF; 8471 8472 pixel = pixels[i++]; 8473 imgData[n++] = pixel >>> 0 & 0xFF; 8474 } 8475 8476 alphaData[a++] = pixel >>> 16 & 0xFF; 8477 } 8478 8479 bpc = 8; 8480 } 8481 8482 if (canCompress(compression)) { 8483 8484 imageData = compressBytes(imgData, img.width * img.colors, img.colors, compression); 8485 smask = compressBytes(alphaData, img.width, 1, compression); 8486 } else { 8487 8488 imageData = imgData; 8489 smask = alphaData; 8490 decode = null; 8491 } 8492 } 8493 8494 /* 8495 * Indexed png. Each pixel is a palette index. 8496 */ 8497 if (img.colorType === 3) { 8498 8499 colorSpace = this.color_spaces.INDEXED; 8500 pal = img.palette; 8501 8502 if (img.transparency.indexed) { 8503 8504 var trans = img.transparency.indexed; 8505 8506 var total = 0, 8507 i = 0, 8508 len = trans.length; 8509 8510 for (; i < len; ++i) { 8511 total += trans[i]; 8512 }total = total / 255; 8513 8514 /* 8515 * a single color is specified as 100% transparent (0), 8516 * so we set trns to use a /Mask with that index 8517 */ 8518 if (total === len - 1 && trans.indexOf(0) !== -1) { 8519 trns = [trans.indexOf(0)]; 8520 8521 /* 8522 * there's more than one colour within the palette that specifies 8523 * a transparency value less than 255, so we unroll the pixels to create an image sMask 8524 */ 8525 } else if (total !== len) { 8526 8527 var pixels = img.decodePixels(), 8528 alphaData = new Uint8Array(pixels.length), 8529 i = 0, 8530 len = pixels.length; 8531 8532 for (; i < len; i++) { 8533 alphaData[i] = trans[pixels[i]]; 8534 }smask = compressBytes(alphaData, img.width, 1); 8535 } 8536 } 8537 } 8538 8539 var predictor = getPredictorFromCompression(compression); 8540 8541 if (decode === this.decode.FLATE_DECODE) dp = '/Predictor ' + predictor + ' /Colors ' + colors + ' /BitsPerComponent ' + bpc + ' /Columns ' + img.width;else 8542 //remove 'Predictor' as it applies to the type of png filter applied to its IDAT - we only apply with compression 8543 dp = '/Colors ' + colors + ' /BitsPerComponent ' + bpc + ' /Columns ' + img.width; 8544 8545 if (this.isArrayBuffer(imageData) || this.isArrayBufferView(imageData)) imageData = this.arrayBufferToBinaryString(imageData); 8546 8547 if (smask && this.isArrayBuffer(smask) || this.isArrayBufferView(smask)) smask = this.arrayBufferToBinaryString(smask); 8548 8549 return this.createImageInfo(imageData, img.width, img.height, colorSpace, bpc, decode, imageIndex, alias, dp, trns, pal, smask, predictor); 8550 } 8551 8552 throw new Error("Unsupported PNG image data, try using JPEG instead."); 8553 }; 8554 })(jsPDF.API); 8555 8556 /** 8557 * jsPDF Autoprint Plugin 8558 * 8559 * Licensed under the MIT License. 8560 * http://opensource.org/licenses/mit-license 8561 */ 8562 8563 (function (jsPDFAPI) { 8564 'use strict'; 8565 8566 jsPDFAPI.autoPrint = function () { 8567 'use strict'; 8568 8569 var refAutoPrintTag; 8570 8571 this.internal.events.subscribe('postPutResources', function () { 8572 refAutoPrintTag = this.internal.newObject(); 8573 this.internal.write("<< /S/Named /Type/Action /N/Print >>", "endobj"); 8574 }); 8575 8576 this.internal.events.subscribe("putCatalog", function () { 8577 this.internal.write("/OpenAction " + refAutoPrintTag + " 0" + " R"); 8578 }); 8579 return this; 8580 }; 8581 })(jsPDF.API); 8582 8583 /** @preserve 8584 * jsPDF split_text_to_size plugin - MIT license. 8585 * Copyright (c) 2012 Willow Systems Corporation, willow-systems.com 8586 * 2014 Diego Casorran, https://github.com/diegocr 8587 */ 8588 /** 8589 * 8590 * ==================================================================== 8591 */ 8592 8593 ;(function (API) { 8594 'use strict'; 8595 8596 /** 8597 Returns an array of length matching length of the 'word' string, with each 8598 cell ocupied by the width of the char in that position. 8599 8600 @function 8601 @param word {String} 8602 @param widths {Object} 8603 @param kerning {Object} 8604 @returns {Array} 8605 */ 8606 8607 var getCharWidthsArray = API.getCharWidthsArray = function (text, options) { 8608 8609 if (!options) { 8610 options = {}; 8611 } 8612 8613 var widths = options.widths ? options.widths : this.internal.getFont().metadata.Unicode.widths, 8614 widthsFractionOf = widths.fof ? widths.fof : 1, 8615 kerning = options.kerning ? options.kerning : this.internal.getFont().metadata.Unicode.kerning, 8616 kerningFractionOf = kerning.fof ? kerning.fof : 1; 8617 8618 // console.log("widths, kergnings", widths, kerning) 8619 8620 var i, 8621 l, 8622 char_code, 8623 prior_char_code = 0 // for kerning 8624 , 8625 default_char_width = widths[0] || widthsFractionOf, 8626 output = []; 8627 8628 for (i = 0, l = text.length; i < l; i++) { 8629 char_code = text.charCodeAt(i); 8630 output.push((widths[char_code] || default_char_width) / widthsFractionOf + (kerning[char_code] && kerning[char_code][prior_char_code] || 0) / kerningFractionOf); 8631 prior_char_code = char_code; 8632 } 8633 8634 return output; 8635 }; 8636 var getArraySum = function getArraySum(array) { 8637 var i = array.length, 8638 output = 0; 8639 while (i) { 8640 ;i--; 8641 output += array[i]; 8642 } 8643 return output; 8644 }; 8645 /**
8646 Returns a widths of string in a given font, if the font size is set as 1 point. 8647 8648 In other words, this is "proportional" value. For 1 unit of font size, the length 8649 of the string will be that much. 8650 8651 Multiply by font size to get actual width in *points* 8652 Then divide by 72 to get inches or divide by (72/25.6) to get 'mm' etc. 8653 8654 @public 8655 @function 8656 @param 8657 @returns {Type} 8658 */ 8659 var getStringUnitWidth = API.getStringUnitWidth = function (text, options) { 8660 return getArraySum(getCharWidthsArray.call(this, text, options)); 8661 }; 8662 8663 /** 8664 returns array of lines 8665 */ 8666 var splitLongWord = function splitLongWord(word, widths_array, firstLineMaxLen, maxLen) { 8667 var answer = []; 8668 8669 // 1st, chop off the piece that can fit on the hanging line. 8670 var i = 0, 8671 l = word.length, 8672 workingLen = 0; 8673 while (i !== l && workingLen + widths_array[i] < firstLineMaxLen) { 8674 workingLen += widths_array[i];i++; 8675 } 8676 // this is first line. 8677 answer.push(word.slice(0, i)); 8678 8679 // 2nd. Split the rest into maxLen pieces. 8680 var startOfLine = i; 8681 workingLen = 0; 8682 while (i !== l) { 8683 if (workingLen + widths_array[i] > maxLen) { 8684 answer.push(word.slice(startOfLine, i)); 8685 workingLen = 0; 8686 startOfLine = i; 8687 } 8688 workingLen += widths_array[i];i++; 8689 } 8690 if (startOfLine !== i) { 8691 answer.push(word.slice(startOfLine, i)); 8692 } 8693 8694 return answer; 8695 }; 8696 8697 // Note, all sizing inputs for this function must be in "font measurement units" 8698 // By default, for PDF, it's "point". 8699 var splitParagraphIntoLines = function splitParagraphIntoLines(text, maxlen, options) { 8700 // at this time works only on Western scripts, ones with space char 8701 // separating the words. Feel free to expand. 8702 8703 if (!options) { 8704 options = {}; 8705 } 8706 8707 var line = [], 8708 lines = [line], 8709 line_length = options.textIndent || 0, 8710 separator_length = 0, 8711 current_word_length = 0, 8712 word, 8713 widths_array, 8714 words = text.split(' '), 8715 spaceCharWidth = getCharWidthsArray(' ', options)[0], 8716 i, 8717 l, 8718 tmp, 8719 lineIndent; 8720 8721 if (options.lineIndent === -1) { 8722 lineIndent = words[0].length + 2; 8723 } else { 8724 lineIndent = options.lineIndent || 0; 8725 } 8726 if (lineIndent) { 8727 var pad = Array(lineIndent).join(" "), 8728 wrds = []; 8729 words.map(function (wrd) { 8730 wrd = wrd.split(/\s*\n/); 8731 if (wrd.length > 1) { 8732 wrds = wrds.concat(wrd.map(function (wrd, idx) { 8733 return (idx && wrd.length ? "\n" : "") + wrd; 8734 })); 8735 } else { 8736 wrds.push(wrd[0]); 8737 } 8738 }); 8739 words = wrds; 8740 lineIndent = getStringUnitWidth(pad, options); 8741 } 8742 8743 for (i = 0, l = words.length; i < l; i++) { 8744 var force = 0; 8745 8746 word = words[i]; 8747 if (lineIndent && word[0] == "\n") { 8748 word = word.substr(1); 8749 force = 1; 8750 } 8751 widths_array = getCharWidthsArray(word, options); 8752 current_word_length = getArraySum(widths_array); 8753 8754 if (line_length + separator_length + current_word_length > maxlen || force) { 8755 if (current_word_length > maxlen) { 8756 // this happens when you have space-less long URLs for example. 8757 // we just chop these to size. We do NOT insert hiphens 8758 tmp = splitLongWord(word, widths_array, maxlen - (line_length + separator_length), maxlen); 8759 // first line we add to existing line object 8760 line.push(tmp.shift()); // it's ok to have extra space indicator there 8761 // last line we make into new line object 8762 line = [tmp.pop()]; 8763 // lines in the middle we apped to lines object as whole lines 8764 while (tmp.length) { 8765 lines.push([tmp.shift()]); // single fragment occupies whole line 8766 } 8767 current_word_length = getArraySum(widths_array.slice(word.length - line[0].length)); 8768 } else { 8769 // just put it on a new line 8770 line = [word]; 8771 } 8772 8773 // now we attach new line to lines 8774 lines.push(line); 8775 line_length = current_word_length + lineIndent; 8776 separator_length = spaceCharWidth; 8777 } else { 8778 line.push(word); 8779 8780 line_length += separator_length + current_word_length; 8781 separator_length = spaceCharWidth; 8782 } 8783 } 8784 8785 if (lineIndent) { 8786 var postProcess = function postProcess(ln, idx) { 8787 return (idx ? pad : '') + ln.join(" "); 8788 }; 8789 } else { 8790 var postProcess = function postProcess(ln) { 8791 return ln.join(" "); 8792 }; 8793 } 8794 8795 return lines.map(postProcess); 8796 }; 8797 8798 /**
8799 Splits a given string into an array of strings. Uses 'size' value 8800 (in measurement units declared as default for the jsPDF instance) 8801 and the font's "widths" and "Kerning" tables, where available, to 8802 determine display length of a given string for a given font. 8803 8804 We use character's 100% of unit size (height) as width when Width 8805 table or other default width is not available. 8806 8807 @public 8808 @function 8809 @param text {String} Unencoded, regular JavaScript (Unicode, UTF-16 / UCS-2) string. 8810 @param size {Number} Nominal number, measured in units default to this instance of jsPDF. 8811 @param options {Object} Optional flags needed for chopper to do the right thing. 8812 @returns {Array} with strings chopped to size. 8813 */ 8814 API.splitTextToSize = function (text, maxlen, options) { 8815 'use strict'; 8816 8817 if (!options) { 8818 options = {}; 8819 } 8820 8821 var fsize = options.fontSize || this.internal.getFontSize(), 8822 newOptions = function (options) { 8823 var widths = { 0: 1 }, 8824 kerning = {}; 8825 8826 if (!options.widths || !options.kerning) { 8827 var f = this.internal.getFont(options.fontName, options.fontStyle), 8828 encoding = 'Unicode'; 8829 // NOT UTF8, NOT UTF16BE/LE, NOT UCS2BE/LE 8830 // Actual JavaScript-native String's 16bit char codes used. 8831 // no multi-byte logic here 8832 8833 if (f.metadata[encoding]) { 8834 return { 8835 widths: f.metadata[encoding].widths || widths, 8836 kerning: f.metadata[encoding].kerning || kerning 8837 }; 8838 } 8839 } else { 8840 return { 8841 widths: options.widths, 8842 kerning: options.kerning 8843 }; 8844 } 8845 8846 // then use default values 8847 return { 8848 widths: widths, 8849 kerning: kerning 8850 }; 8851 }.call(this, options); 8852 8853 // first we split on end-of-line chars 8854 var paragraphs; 8855 if (Array.isArray(text)) { 8856 paragraphs = text; 8857 } else { 8858 paragraphs = text.split(/\r?\n/); 8859 } 8860 8861 // now we convert size (max length of line) into "font size units" 8862 // at present time, the "font size unit" is always 'point' 8863 // 'proportional' means, "in proportion to font size" 8864 var fontUnit_maxLen = 1.0 * this.internal.scaleFactor * maxlen / fsize; 8865 // at this time, fsize is always in "points" regardless of the default measurement unit of the doc. 8866 // this may change in the future? 8867 // until then, proportional_maxlen is likely to be in 'points' 8868 8869 // If first line is to be indented (shorter or longer) than maxLen 8870 // we indicate that by using CSS-style "text-indent" option. 8871 // here it's in font units too (which is likely 'points') 8872 // it can be negative (which makes the first line longer than maxLen) 8873 newOptions.textIndent = options.textIndent ? options.textIndent * 1.0 * this.internal.scaleFactor / fsize : 0; 8874 newOptions.lineIndent = options.lineIndent; 8875 8876 var i, 8877 l, 8878 output = []; 8879 for (i = 0, l = paragraphs.length; i < l; i++) { 8880 output = output.concat(splitParagraphIntoLines(paragraphs[i], fontUnit_maxLen, newOptions)); 8881 } 8882 8883 return output; 8884 }; 8885 })(jsPDF.API); 8886 8887 /** @preserve 8888 jsPDF standard_fonts_metrics plugin 8889 Copyright (c) 2012 Willow Systems Corporation, willow-systems.com 8890 MIT license. 8891 */ 8892 /** 8893 * 8894 * ==================================================================== 8895 */ 8896 8897 ;(function (API) { 8898 'use strict'; 8899 8900 /* 8901 # reference (Python) versions of 'compress' and 'uncompress' 8902 # only 'uncompress' function is featured lower as JavaScript 8903 # if you want to unit test "roundtrip", just transcribe the reference 8904 # 'compress' function from Python into JavaScript 8905 8906 def compress(data): 8907 8908 keys = '0123456789abcdef' 8909 values = 'klmnopqrstuvwxyz' 8910 mapping = dict(zip(keys, values)) 8911 vals = [] 8912 for key in data.keys(): 8913 value = data[key] 8914 try: 8915 keystring = hex(key)[2:] 8916 keystring = keystring[:-1] + mapping[keystring[-1:]] 8917 except: 8918 keystring = key.join(["'","'"]) 8919 #print('Keystring is %s' % keystring) 8920 8921 try: 8922 if value < 0: 8923 valuestring = hex(value)[3:] 8924 numberprefix = '-' 8925 else: 8926 valuestring = hex(value)[2:] 8927 numberprefix = '' 8928 valuestring = numberprefix + valuestring[:-1] + mapping[valuestring[-1:]] 8929 except: 8930 if type(value) == dict: 8931 valuestring = compress(value) 8932 else:
8933 raise Exception("Don't know what to do with value type %s" % type(value)) 8934 8935 vals.append(keystring+valuestring) 8936 8937 return '{' + ''.join(vals) + '}' 8938 8939 def uncompress(data): 8940 8941 decoded = '0123456789abcdef' 8942 encoded = 'klmnopqrstuvwxyz' 8943 mapping = dict(zip(encoded, decoded)) 8944 8945 sign = +1 8946 stringmode = False 8947 stringparts = [] 8948 8949 output = {} 8950 8951 activeobject = output 8952 parentchain = [] 8953 8954 keyparts = '' 8955 valueparts = '' 8956 8957 key = None 8958 8959 ending = set(encoded) 8960 8961 i = 1 8962 l = len(data) - 1 # stripping starting, ending {} 8963 while i != l: # stripping {} 8964 # -, {, }, ' are special. 8965 8966 ch = data[i] 8967 i += 1 8968 8969 if ch == "'": 8970 if stringmode: 8971 # end of string mode 8972 stringmode = False 8973 key = ''.join(stringparts) 8974 else: 8975 # start of string mode 8976 stringmode = True 8977 stringparts = [] 8978 elif stringmode == True: 8979 #print("Adding %s to stringpart" % ch) 8980 stringparts.append(ch) 8981 8982 elif ch == '{': 8983 # start of object 8984 parentchain.append( [activeobject, key] ) 8985 activeobject = {} 8986 key = None 8987 #DEBUG = True 8988 elif ch == '}': 8989 # end of object 8990 parent, key = parentchain.pop() 8991 parent[key] = activeobject 8992 key = None 8993 activeobject = parent 8994 #DEBUG = False 8995 8996 elif ch == '-': 8997 sign = -1 8998 else: 8999 # must be number 9000 if key == None: 9001 #debug("In Key. It is '%s', ch is '%s'" % (keyparts, ch)) 9002 if ch in ending: 9003 #debug("End of key") 9004 keyparts += mapping[ch] 9005 key = int(keyparts, 16) * sign 9006 sign = +1 9007 keyparts = '' 9008 else: 9009 keyparts += ch 9010 else: 9011 #debug("In value. It is '%s', ch is '%s'" % (valueparts, ch)) 9012 if ch in ending: 9013 #debug("End of value") 9014 valueparts += mapping[ch] 9015 activeobject[key] = int(valueparts, 16) * sign 9016 sign = +1 9017 key = None 9018 valueparts = '' 9019 else: 9020 valueparts += ch 9021 9022 #debug(activeobject) 9023 9024 return output 9025 9026 */ 9027 9028 /** 9029 Uncompresses data compressed into custom, base16-like format. 9030 @public 9031 @function 9032 @param 9033 @returns {Type} 9034 */ 9035 9036 var uncompress = function uncompress(data) { 9037 9038 var decoded = '0123456789abcdef', 9039 encoded = 'klmnopqrstuvwxyz', 9040 mapping = {}; 9041 9042 for (var i = 0; i < encoded.length; i++) { 9043 mapping[encoded[i]] = decoded[i]; 9044 } 9045 9046 var undef, 9047 output = {}, 9048 sign = 1, 9049 stringparts // undef. will be [] in string mode 9050 9051 , 9052 activeobject = output, 9053 parentchain = [], 9054 parent_key_pair, 9055 keyparts = '', 9056 valueparts = '', 9057 key // undef. will be Truthy when Key is resolved. 9058 , 9059 datalen = data.length - 1 // stripping ending } 9060 , 9061 ch; 9062 9063 i = 1; // stripping starting { 9064 9065 while (i != datalen) { 9066 // - { } ' are special. 9067 9068 ch = data[i]; 9069 i += 1; 9070 9071 if (ch == "'") { 9072 if (stringparts) { 9073 // end of string mode 9074 key = stringparts.join(''); 9075 stringparts = undef; 9076 } else { 9077 // start of string mode 9078 stringparts = []; 9079 } 9080 } else if (stringparts) { 9081 stringparts.push(ch); 9082 } else if (ch == '{') { 9083 // start of object 9084 parentchain.push([activeobject, key]); 9085 activeobject = {}; 9086 key = undef; 9087 } else if (ch == '}') { 9088 // end of object 9089 parent_key_pair = parentchain.pop(); 9090 parent_key_pair[0][parent_key_pair[1]] = activeobject; 9091 key = undef; 9092 activeobject = parent_key_pair[0]; 9093 } else if (ch == '-') { 9094 sign = -1; 9095 } else { 9096 // must be number 9097 if (key === undef) { 9098 if (mapping.hasOwnProperty(ch)) { 9099 keyparts += mapping[ch]; 9100 key = parseInt(keyparts, 16) * sign; 9101 sign = +1; 9102 keyparts = ''; 9103 } else { 9104 keyparts += ch; 9105 } 9106 } else { 9107 if (mapping.hasOwnProperty(ch)) { 9108 valueparts += mapping[ch]; 9109 activeobject[key] = parseInt(valueparts, 16) * sign; 9110 sign = +1; 9111 key = undef; 9112 valueparts = ''; 9113 } else { 9114 valueparts += ch; 9115 } 9116 } 9117 } 9118 } // end while 9119 9120 return output; 9121 }; 9122 9123 // encoding = 'Unicode' 9124 // NOT UTF8, NOT UTF16BE/LE, NOT UCS2BE/LE. NO clever BOM behavior 9125 // Actual 16bit char codes used. 9126 // no multi-byte logic here 9127 9128 // Unicode characters to WinAnsiEncoding: 9129 // {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} 9130 // as you can see, all Unicode chars are outside of 0-255 range. No char code conflicts. 9131 // this means that you can give Win cp1252 encoded strings to jsPDF for rendering directly 9132 // as well as give strings with some (supported by these fonts) Unicode characters and 9133 // these will be mapped to win cp1252
9134 // for example, you can send char code (cp1252) 0x80 or (unicode) 0x20AC, getting "Euro" glyph displayed in both cases. 9135 9136 var encodingBlock = { 9137 'codePages': ['WinAnsiEncoding'], 9138 'WinAnsiEncoding': uncompress("{19m8n201n9q201o9r201s9l201t9m201u8m201w9n201x9o201y8o202k8q202l8r202m9p202q8p20aw8k203k8t203t8v203u9v2cq8s212m9t15m8w15n9w2dw9s16k8u16l9u17s9z17x8y17y9y}") 9139 }, 9140 encodings = { 'Unicode': { 9141 'Courier': encodingBlock, 9142 'Courier-Bold': encodingBlock, 9143 'Courier-BoldOblique': encodingBlock, 9144 'Courier-Oblique': encodingBlock, 9145 'Helvetica': encodingBlock, 9146 'Helvetica-Bold': encodingBlock, 9147 'Helvetica-BoldOblique': encodingBlock, 9148 'Helvetica-Oblique': encodingBlock, 9149 'Times-Roman': encodingBlock, 9150 'Times-Bold': encodingBlock, 9151 'Times-BoldItalic': encodingBlock, 9152 'Times-Italic': encodingBlock 9153 // , 'Symbol' 9154 // , 'ZapfDingbats' 9155 } } 9156 /** 9157 Resources: 9158 Font metrics data is reprocessed derivative of contents of 9159 "Font Metrics for PDF Core 14 Fonts" package, which exhibits the following copyright and license: 9160 9161 Copyright (c) 1989, 1990, 1991, 1992, 1993, 1997 Adobe Systems Incorporated. All Rights Reserved. 9162 9163 This file and the 14 PostScript(R) AFM files it accompanies may be used, 9164 copied, and distributed for any purpose and without charge, with or without
9165 modification, provided that all copyright notices are retained; that the AFM 9166 files are not distributed without this file; that all modifications to this 9167 file or any of the AFM files are prominently noted in the modified file(s); 9168 and that this paragraph is not modified. Adobe Systems has no responsibility 9169 or obligation to support the use of the AFM files. 9170 9171 */ 9172 , 9173 fontMetrics = { 'Unicode': { 9174 // all sizing numbers are n/fontMetricsFractionOf = one font size unit 9175 // this means that if fontMetricsFractionOf = 1000, and letter A's width is 476, it's 9176 // width is 476/1000 or 47.6% of its height (regardless of font size) 9177 // At this time this value applies to "widths" and "kerning" numbers. 9178 9179 // char code 0 represents "default" (average) width - use it for chars missing in this table. 9180 // key 'fof' represents the "fontMetricsFractionOf" value 9181 9182 'Courier-Oblique': uncompress("{'widths'{k3w'fof'6o}'kerning'{'fof'-6o}}"), 9183 '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}}}"), 9184 'Helvetica-Bold': uncompress("{'widths'{k3s2q4scx1w201n3r201o6o201s1w201t1w201u1w201w3m201x3m201y3m2k1w2l2l202m2n2n3r2o3r2p5t202q6o2r1s2s2l2t2l2u2r2v3u2w1w2x2l2y1w2z1w3k3r3l3r3m3r3n3r3o3r3p3r3q3r3r3r3s3r203t2l203u2l3v2l3w3u3x3u3y3u3z3x4k6l4l4s4m4s4n4s4o4s4p4m4q3x4r4y4s4s4t1w4u3r4v4s4w3x4x5n4y4s4z4y5k4m5l4y5m4s5n4m5o3x5p4s5q4m5r5y5s4m5t4m5u3x5v2l5w1w5x2l5y3u5z3r6k2l6l3r6m3x6n3r6o3x6p3r6q2l6r3x6s3x6t1w6u1w6v3r6w1w6x5t6y3x6z3x7k3x7l3x7m2r7n3r7o2l7p3x7q3r7r4y7s3r7t3r7u3m7v2r7w1w7x2r7y3u202l3rcl4sal2lam3ran3rao3rap3rar3ras2lat4tau2pav3raw3uay4taz2lbk2sbl3u'fof'6obo2lbp3xbq3rbr1wbs2lbu2obv3rbz3xck4s202k3rcm4scn4sco4scp4scq6ocr4scs4mct4mcu4mcv4mcw1w2m2zcy1wcz1wdl4sdm4y
9184dn4ydo4ydp4ydq4yds4ydt4sdu4sdv4sdw4sdz3xek3rel3rem3ren3reo3rep3req5ter3res3ret3reu3rev3rew1wex1wey1wez1wfl3xfm3xfn3xfo3xfp3xfq3xfr3ufs3xft3xfu3xfv3xfw3xfz3r203k6o212m6o2dw2l2cq2l3t3r3u2l17s4m19m3r}'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}}}"), 9185 'Courier': uncompress("{'widths'{k3w'fof'6o}'kerning'{'fof'-6o}}"), 9186 'Courier-BoldOblique': uncompress("{'widths'{k3w'fof'6o}'kerning'{'fof'-6o}}"), 9187 '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}}}") 9188 //, 'Symbol': uncompress("{'widths'{k3uaw4r19m3m2k1t2l2l202m2y2n3m2p5n202q6o3k3m2s2l2t2l2v3r2w1t3m3m2y1t2z1wbk2sbl3r'fof'6o3n3m3o3m3p3m3q3m3r3m3s3m3t3m3u1w3v1w3w3r3x3r3y3r3z2wbp3t3l3m5v2l5x2l5z3m2q4yfr3r7v3k7w1o7x3k}'kerning'{'fof'-6o}}") 9189 , 'Helvetica': uncompress("{'widths'{k3p2q4mcx1w201n3r201o6o201s1q201t1q201u1q201w2l201x2l201y2l2k1w2l1w202m2n2n3r2o3r2p5t202q6o2r1n2s2l2t2l2u2r2v3u2w1w2x2l2y1w2z1w3k3r3l3r3m3r3n3r3o3r3p3r3q3r3r3r3s3r203t2l203u2l3v1w3w3u3x3u3y3u3z3r4k6p4l4m4m4m4n4s4o4s4p4m4q3x4r4y4s4s4t1w4u3m4v4m4w3r4x5n4y4s4z4y5k4m5l4y5m4s5n4m5o3x5p4s5q4m5r5y5s4m5t4m5u3x5v1w5w1w5x1w5y2z5z3r6k2l6l3r6m3r6n3m6o3r6p3r6q1w6r3r6s3r6t1q6u1q6v3m6w1q6x5n6y3r6z3r7k3r7l3r7m2l7n3m7o1w7p3r7q3m7r4s7s3m7t3m7u3m7v2l7w1u7x2l7y3u202l3rcl4mal2lam3ran3rao3rap3rar3ras2lat4tau2pav3raw3uay4taz2lbk2sbl3u'fof'6obo2lbp3rbr1wbs2lbu2obv3rbz3xck4m202k3rcm4mcn4mco4mcp4mcq6ocr4scs4mct4mcu4mcv4mcw1w2m2ncy1wcz1wdl4sdm4y
9189dn4ydo4ydp4ydq4yds4ydt4sdu4sdv4sdw4sdz3xek3rel3rem3ren3reo3rep3req5ter3mes3ret3reu3rev3rew1wex1wey1wez1wfl3rfm3rfn3rfo3rfp3rfq3rfr3ufs3xft3rfu3rfv3rfw3rfz3m203k6o212m6o2dw2l2cq2l3t3r3u1w17s4m19m3r}'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}}}"), 9190 'Helvetica-BoldOblique': uncompress("{'widths'{k3s2q4scx1w201n3r201o6o201s1w201t1w201u1w201w3m201x3m201y3m2k1w2l2l202m2n2n3r2o3r2p5t202q6o2r1s2s2l2t2l2u2r2v3u2w1w2x2l2y1w2z1w3k3r3l3r3m3r3n3r3o3r3p3r3q3r3r3r3s3r203t2l203u2l3v2l3w3u3x3u3y3u3z3x4k6l4l4s4m4s4n4s4o4s4p4m4q3x4r4y4s4s4t1w4u3r4v4s4w3x4x5n4y4s4z4y5k4m5l4y5m4s5n4m5o3x5p4s5q4m5r5y5s4m5t4m5u3x5v2l5w1w5x2l5y3u5z3r6k2l6l3r6m3x6n3r6o3x6p3r6q2l6r3x6s3x6t1w6u1w6v3r6w1w6x5t6y3x6z3x7k3x7l3x7m2r7n3r7o2l7p3x7q3r7r4y7s3r7t3r7u3m7v2r7w1w7x2r7y3u202l3rcl4sal2lam3ran3rao3rap3rar3ras2lat4tau2pav3raw3uay4taz2lbk2sbl3u'fof'6obo2lbp3xbq3rbr1wbs2lbu2obv3rbz3xck4s202k3rcm4scn4sco4scp4scq6ocr4scs4mct4mcu4mcv4mcw1w2m2zcy1wcz1wdl4sdm4y
9190dn4ydo4ydp4ydq4yds4ydt4sdu4sdv4sdw4sdz3xek3rel3rem3ren3reo3rep3req5ter3res3ret3reu3rev3rew1wex1wey1wez1wfl3xfm3xfn3xfo3xfp3xfq3xfr3ufs3xft3xfu3xfv3xfw3xfz3r203k6o212m6o2dw2l2cq2l3t3r3u2l17s4m19m3r}'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}}}") 9191 //, 'ZapfDingbats': uncompress("{'widths'{k4u2k1w'fof'6o}'kerning'{'fof'-6o}}") 9192 , 'Courier-Bold': uncompress("{'widths'{k3w'fof'6o}'kerning'{'fof'-6o}}"), 9193 '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}
9193fv{17su5tu5qs}fw{17su5tu5qs}}}"), 9194 '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}}}"), 9195 'Helvetica-Oblique': uncompress("{'widths'{k3p2q4mcx1w201n3r201o6o201s1q201t1q201u1q201w2l201x2l201y2l2k1w2l1w202m2n2n3r2o3r2p5t202q6o2r1n2s2l2t2l2u2r2v3u2w1w2x2l2y1w2z1w3k3r3l3r3m3r3n3r3o3r3p3r3q3r3r3r3s3r203t2l203u2l3v1w3w3u3x3u3y3u3z3r4k6p4l4m4m4m4n4s4o4s4p4m4q3x4r4y4s4s4t1w4u3m4v4m4w3r4x5n4y4s4z4y5k4m5l4y5m4s5n4m5o3x5p4s5q4m5r5y5s4m5t4m5u3x5v1w5w1w5x1w5y2z5z3r6k2l6l3r6m3r6n3m6o3r6p3r6q1w6r3r6s3r6t1q6u1q6v3m6w1q6x5n6y3r6z3r7k3r7l3r7m2l7n3m7o1w7p3r7q3m7r4s7s3m7t3m7u3m7v2l7w1u7x2l7y3u202l3rcl4mal2lam3ran3rao3rap3rar3ras2lat4tau2pav3raw3uay4taz2lbk2sbl3u'fof'6obo2lbp3rbr1wbs2lbu2obv3rbz3xck4m202k3rcm4mcn4mco4mcp4mcq6ocr4scs4mct4mcu4mcv4mcw1w2m2ncy1wcz1wdl4sdm4y
9195dn4ydo4ydp4ydq4yds4ydt4sdu4sdv4sdw4sdz3xek3rel3rem3ren3reo3rep3req5ter3mes3ret3reu3rev3rew1wex1wey1wez1wfl3rfm3rfn3rfo3rfp3rfq3rfr3ufs3xft3rfu3rfv3rfw3rfz3m203k6o212m6o2dw2l2cq2l3t3r3u1w17s4m19m3r}'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}}}") 9196 } }; 9197 9198 /* 9199 This event handler is fired when a new jsPDF object is initialized 9200 This event handler appends metrics data to standard fonts within 9201 that jsPDF instance. The metrics are mapped over Unicode character 9202 codes, NOT CIDs or other codes matching the StandardEncoding table of the 9203 standard PDF fonts. 9204 Future: 9205 Also included is the encoding maping table, converting Unicode (UCS-2, UTF-16) 9206 char codes to StandardEncoding character codes. The encoding table is to be used 9207 somewhere around "pdfEscape" call. 9208 */ 9209 9210 API.events.push(['addFont', function (font) { 9211 var metrics, 9212 unicode_section, 9213 encoding = 'Unicode', 9214 encodingBlock; 9215 9216 metrics = fontMetrics[encoding][font.PostScriptName]; 9217 if (metrics) { 9218 if (font.metadata[encoding]) { 9219 unicode_section = font.metadata[encoding]; 9220 } else { 9221 unicode_section = font.metadata[encoding] = {}; 9222 } 9223 9224 unicode_section.widths = metrics.widths; 9225 unicode_section.kerning = metrics.kerning; 9226 } 9227 9228 encodingBlock = encodings[encoding][font.PostScriptName]; 9229 if (encodingBlock) { 9230 if (font.metadata[encoding]) { 9231 unicode_section = font.metadata[encoding]; 9232 } else { 9233 unicode_section = font.metadata[encoding] = {}; 9234 } 9235 9236 unicode_section.encoding = encodingBlock; 9237 if (encodingBlock.codePages && encodingBlock.codePages.length) { 9238 font.encoding = encodingBlock.codePages[0]; 9239 } 9240 } 9241 }]); // end of adding event handler 9242 })(jsPDF.API); 9243 9244 /** @preserve 9245 jsPDF SVG plugin 9246 Copyright (c) 2012 Willow Systems Corporation, willow-systems.com 9247 */ 9248 /** 9249 * 9250 * ==================================================================== 9251 */ 9252 9253 ;(function (jsPDFAPI) { 9254 'use strict'; 9255 9256 /** 9257 Parses SVG XML and converts only some of the SVG elements into 9258 PDF elements. 9259 9260 Supports: 9261 paths 9262 9263 @public 9264 @function 9265 @param 9266 @returns {Type} 9267 */ 9268 9269 jsPDFAPI.addSVG = function (svgtext, x, y, w, h) { 9270 // 'this' is _jsPDF object returned when jsPDF is inited (new jsPDF()) 9271 9272 var undef; 9273 9274 if (x === undef || y === undef) { 9275 throw new Error("addSVG needs values for 'x' and 'y'"); 9276 } 9277 9278 function InjectCSS(cssbody, document) { 9279 var styletag = document.createElement('style'); 9280 styletag.type = 'text/css'; 9281 if (styletag.styleSheet) { 9282 // ie 9283 styletag.styleSheet.cssText = cssbody; 9284 } else { 9285 // others 9286 styletag.appendChild(document.createTextNode(cssbody)); 9287 } 9288 document.getElementsByTagName("head")[0].appendChild(styletag); 9289 } 9290 9291 function createWorkerNode(document) { 9292 9293 var frameID = 'childframe' // Date.now().toString() + '_' + (Math.random() * 100).toString() 9294 , 9295 frame = document.createElement('iframe'); 9296 9297 InjectCSS('.jsPDF_sillysvg_iframe {display:none;position:absolute;}', document); 9298 9299 frame.name = frameID; 9300 frame.setAttribute("width", 0); 9301 frame.setAttribute("height", 0); 9302 frame.setAttribute("frameborder", "0"); 9303 frame.setAttribute("scrolling", "no"); 9304 frame.setAttribute("seamless", "seamless"); 9305 frame.setAttribute("class", "jsPDF_sillysvg_iframe"); 9306 9307 document.body.appendChild(frame); 9308 9309 return frame; 9310 } 9311 9312 function attachSVGToWorkerNode(svgtext, frame) { 9313 var framedoc = (frame.contentWindow || frame.contentDocument).document; 9314 framedoc.write(svgtext); 9315 framedoc.close(); 9316 return framedoc.getElementsByTagName('svg')[0]; 9317 } 9318 9319 function convertPathToPDFLinesArgs(path) { 9320 'use strict'; 9321 // we will use 'lines' method call. it needs: 9322 // - starting coordinate pair 9323 // - array of arrays of vector shifts (2-len for line, 6 len for bezier) 9324 // - scale array [horizontal, vertical] ratios 9325 // - style (stroke, fill, both) 9326 9327 var x = parseFloat(path[1]), 9328 y = parseFloat(path[2]), 9329 vectors = [], 9330 position = 3, 9331 len = path.length; 9332 9333 while (position < len) { 9334 if (path[position] === 'c') { 9335 vectors.push([parseFloat(path[position + 1]), parseFloat(path[position + 2]), parseFloat(path[position + 3]), parseFloat(path[position + 4]), parseFloat(path[position + 5]), parseFloat(path[position + 6])]); 9336 position += 7; 9337 } else if (path[position] === 'l') { 9338 vectors.push([parseFloat(path[position + 1]), parseFloat(path[position + 2])]); 9339 position += 3; 9340 } else { 9341 position += 1; 9342 } 9343 } 9344 return [x, y, vectors]; 9345 } 9346
9347 var workernode = createWorkerNode(document), 9348 svgnode = attachSVGToWorkerNode(svgtext, workernode), 9349 scale = [1, 1], 9350 svgw = parseFloat(svgnode.getAttribute('width')), 9351 svgh = parseFloat(svgnode.getAttribute('height')); 9352 9353 if (svgw && svgh) { 9354 // setting both w and h makes image stretch to size. 9355 // this may distort the image, but fits your demanded size 9356 if (w && h) { 9357 scale = [w / svgw, h / svgh]; 9358 } 9359 // if only one is set, that value is set as max and SVG 9360 // is scaled proportionately. 9361 else if (w) { 9362 scale = [w / svgw, w / svgw]; 9363 } else if (h) { 9364 scale = [h / svgh, h / svgh]; 9365 } 9366 } 9367 9368 var i, 9369 l, 9370 tmp, 9371 linesargs, 9372 items = svgnode.childNodes; 9373 for (i = 0, l = items.length; i < l; i++) { 9374 tmp = items[i]; 9375 if (tmp.tagName && tmp.tagName.toUpperCase() === 'PATH') { 9376 linesargs = convertPathToPDFLinesArgs(tmp.getAttribute("d").split(' ')); 9377 // path start x coordinate 9378 linesargs[0] = linesargs[0] * scale[0] + x; // where x is upper left X of image 9379 // path start y coordinate 9380 linesargs[1] = linesargs[1] * scale[1] + y; // where y is upper left Y of image 9381 // the rest of lines are vectors. these will adjust with scale value auto. 9382 this.lines.call(this, linesargs[2] // lines 9383 , linesargs[0] // starting x 9384 , linesargs[1] // starting y 9385 , scale); 9386 } 9387 } 9388 9389 // clean up 9390 // workernode.parentNode.removeChild(workernode) 9391 9392 return this; 9393 }; 9394 })(jsPDF.API); 9395 9396 /** ==================================================================== 9397 * jsPDF total_pages plugin 9398 * Copyright (c) 2013 Eduardo Menezes de Morais, [email protected] 9399 * 9400 * 9401 * ==================================================================== 9402 */ 9403 9404 (function (jsPDFAPI) { 9405 'use strict'; 9406 9407 jsPDFAPI.putTotalPages = function (pageExpression) { 9408 'use strict'; 9409 9410 var replaceExpression = new RegExp(pageExpression, 'g'); 9411 for (var n = 1; n <= this.internal.getNumberOfPages(); n++) { 9412 for (var i = 0; i < this.internal.pages[n].length; i++) { 9413 this.internal.pages[n][i] = this.internal.pages[n][i].replace(replaceExpression, this.internal.getNumberOfPages()); 9414 } 9415 } 9416 return this; 9417 }; 9418 })(jsPDF.API); 9419 9420 /** ==================================================================== 9421 * jsPDF XMP metadata plugin 9422 * Copyright (c) 2016 Jussi Utunen, [email protected] 9423 * 9424 * 9425 * ==================================================================== 9426 */ 9427 9428 /*global jsPDF */ 9429 9430 /** 9431 * Adds XMP formatted metadata to PDF 9432 * 9433 * @param {String} metadata The actual metadata to be added. The metadata shall be stored as XMP simple value. Note that if the metadata string contains XML markup characters "<", ">" or "&", those characters should be written using XML entities. 9434 * @param {String} namespaceuri Sets the namespace URI for the metadata. Last character should be slash or hash. 9435 * @function 9436 * @returns {jsPDF} 9437 * @methodOf jsPDF# 9438 * @name addMetadata 9439 */ 9440 9441 (function (jsPDFAPI) { 9442 'use strict'; 9443 9444 var xmpmetadata = ""; 9445 var xmpnamespaceuri = ""; 9446 var metadata_object_number = ""; 9447 9448 jsPDFAPI.addMetadata = function (metadata, namespaceuri) { 9449 xmpnamespaceuri = namespaceuri || "http://jspdf.default.namespaceuri/"; //The namespace URI for an XMP name shall not be empty 9450 xmpmetadata = metadata; 9451 this.internal.events.subscribe('postPutResources', function () { 9452 if (!xmpmetadata) { 9453 metadata_object_number = ""; 9454 } else { 9455 var xmpmeta_beginning = '<x:xmpmeta xmlns:x="adobe:ns:meta/">'; 9456 var rdf_beginning = '<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"><rdf:Description rdf:about="" xmlns:jspdf="' + xmpnamespaceuri + '"><jspdf:metadata>'; 9457 var rdf_ending = '</jspdf:metadata></rdf:Description></rdf:RDF>'; 9458 var xmpmeta_ending = '</x:xmpmeta>'; 9459 var utf8_xmpmeta_beginning = unescape(encodeURIComponent(xmpmeta_beginning)); 9460 var utf8_rdf_beginning = unescape(encodeURIComponent(rdf_beginning)); 9461 var utf8_metadata = unescape(encodeURIComponent(xmpmetadata)); 9462 var utf8_rdf_ending = unescape(encodeURIComponent(rdf_ending)); 9463 var utf8_xmpmeta_ending = unescape(encodeURIComponent(xmpmeta_ending)); 9464 9465 var total_len = utf8_rdf_beginning.length + utf8_metadata.length + utf8_rdf_ending.length + utf8_xmpmeta_beginning.length + utf8_xmpmeta_ending.length; 9466 9467 metadata_object_number = this.internal.newObject();
vendor: 9,917 bytes, lines 9468-9709
9468 this.internal.write('<< /Type /Metadata /Subtype /XML /Length ' + total_len + ' >>'); 9469 this.internal.write('stream'); 9470 this.internal.write(utf8_xmpmeta_beginning + utf8_rdf_beginning + utf8_metadata + utf8_rdf_ending + utf8_xmpmeta_ending); 9471 this.internal.write('endstream'); 9472 this.internal.write('endobj'); 9473 } 9474 }); 9475 this.internal.events.subscribe('putCatalog', function () { 9476 if (metadata_object_number) { 9477 this.internal.write('/Metadata ' + metadata_object_number + ' 0 R'); 9478 } 9479 }); 9480 return this; 9481 }; 9482 })(jsPDF.API); 9483 9484 /* Blob.js 9485 * A Blob implementation. 9486 * 2014-07-24 9487 * 9488 * By Eli Grey, http://eligrey.com 9489 * By Devin Samarin, https://github.com/dsamarin 9490 * License: X11/MIT 9491 * See https://github.com/eligrey/Blob.js/blob/master/LICENSE.md 9492 */ 9493 9494 /*global self, unescape */ 9495 /*jslint bitwise: true, regexp: true, confusion: true, es5: true, vars: true, white: true, 9496 plusplus: true */ 9497 9498 /*! @source http://purl.eligrey.com/github/Blob.js/blob/master/Blob.js */ 9499 9500 (function (view) { 9501 "use strict"; 9502 9503 view.URL = view.URL || view.webkitURL; 9504 9505 if (view.Blob && view.URL) { 9506 try { 9507 new Blob; 9508 return; 9509 } catch (e) {} 9510 } 9511 9512 // Internally we use a BlobBuilder implementation to base Blob off of 9513 // in order to support older browsers that only have BlobBuilder 9514 var BlobBuilder = view.BlobBuilder || view.WebKitBlobBuilder || view.MozBlobBuilder || (function(view) { 9515 var 9516 get_class = function(object) { 9517 return Object.prototype.toString.call(object).match(/^\[object\s(.*)\]$/)[1]; 9518 } 9519 , FakeBlobBuilder = function BlobBuilder() { 9520 this.data = []; 9521 } 9522 , FakeBlob = function Blob(data, type, encoding) { 9523 this.data = data; 9524 this.size = data.length; 9525 this.type = type; 9526 this.encoding = encoding; 9527 } 9528 , FBB_proto = FakeBlobBuilder.prototype 9529 , FB_proto = FakeBlob.prototype 9530 , FileReaderSync = view.FileReaderSync 9531 , FileException = function(type) { 9532 this.code = this[this.name = type]; 9533 } 9534 , file_ex_codes = ( 9535 "NOT_FOUND_ERR SECURITY_ERR ABORT_ERR NOT_READABLE_ERR ENCODING_ERR " 9536 + "NO_MODIFICATION_ALLOWED_ERR INVALID_STATE_ERR SYNTAX_ERR" 9537 ).split(" ") 9538 , file_ex_code = file_ex_codes.length 9539 , real_URL = view.URL || view.webkitURL || view 9540 , real_create_object_URL = real_URL.createObjectURL 9541 , real_revoke_object_URL = real_URL.revokeObjectURL 9542 , URL = real_URL 9543 , btoa = view.btoa 9544 , atob = view.atob 9545 9546 , ArrayBuffer = view.ArrayBuffer 9547 , Uint8Array = view.Uint8Array 9548 9549 , origin = /^[\w-]+:\/*\[?[\w\.:-]+\]?(?::[0-9]+)?/ 9550 ; 9551 FakeBlob.fake = FB_proto.fake = true; 9552 while (file_ex_code--) { 9553 FileException.prototype[file_ex_codes[file_ex_code]] = file_ex_code + 1; 9554 } 9555 // Polyfill URL 9556 if (!real_URL.createObjectURL) { 9557 URL = view.URL = function(uri) { 9558 var 9559 uri_info = document.createElementNS("http://www.w3.org/1999/xhtml", "a") 9560 , uri_origin 9561 ; 9562 uri_info.href = uri; 9563 if (!("origin" in uri_info)) { 9564 if (uri_info.protocol.toLowerCase() === "data:") { 9565 uri_info.origin = null; 9566 } else { 9567 uri_origin = uri.match(origin); 9568 uri_info.origin = uri_origin && uri_origin[1]; 9569 } 9570 } 9571 return uri_info; 9572 }; 9573 } 9574 URL.createObjectURL = function(blob) { 9575 var 9576 type = blob.type 9577 , data_URI_header 9578 ; 9579 if (type === null) { 9580 type = "application/octet-stream"; 9581 } 9582 if (blob instanceof FakeBlob) { 9583 data_URI_header = "data:" + type; 9584 if (blob.encoding === "base64") { 9585 return data_URI_header + ";base64," + blob.data; 9586 } else if (blob.encoding === "URI") { 9587 return data_URI_header + "," + decodeURIComponent(blob.data); 9588 } if (btoa) { 9589 return data_URI_header + ";base64," + btoa(blob.data); 9590 } else { 9591 return data_URI_header + "," + encodeURIComponent(blob.data); 9592 } 9593 } else if (real_create_object_URL) { 9594 return real_create_object_URL.call(real_URL, blob); 9595 } 9596 }; 9597 URL.revokeObjectURL = function(object_URL) { 9598 if (object_URL.substring(0, 5) !== "data:" && real_revoke_object_URL) { 9599 real_revoke_object_URL.call(real_URL, object_URL); 9600 } 9601 }; 9602 FBB_proto.append = function(data/*, endings*/) { 9603 var bb = this.data; 9604 // decode data to a binary string 9605 if (Uint8Array && (data instanceof ArrayBuffer || data instanceof Uint8Array)) { 9606 var 9607 str = "" 9608 , buf = new Uint8Array(data) 9609 , i = 0 9610 , buf_len = buf.length 9611 ; 9612 for (; i < buf_len; i++) { 9613 str += String.fromCharCode(buf[i]); 9614 } 9615 bb.push(str); 9616 } else if (get_class(data) === "Blob" || get_class(data) === "File") { 9617 if (FileReaderSync) { 9618 var fr = new FileReaderSync; 9619 bb.push(fr.readAsBinaryString(data)); 9620 } else { 9621 // async FileReader won't work as BlobBuilder is sync 9622 throw new FileException("NOT_READABLE_ERR"); 9623 } 9624 } else if (data instanceof FakeBlob) { 9625 if (data.encoding === "base64" && atob) { 9626 bb.push(atob(data.data)); 9627 } else if (data.encoding === "URI") { 9628 bb.push(decodeURIComponent(data.data)); 9629 } else if (data.encoding === "raw") { 9630 bb.push(data.data); 9631 } 9632 } else { 9633 if (typeof data !== "string") { 9634 data += ""; // convert unsupported types to strings 9635 } 9636 // decode UTF-16 to binary string 9637 bb.push(unescape(encodeURIComponent(data))); 9638 } 9639 }; 9640 FBB_proto.getBlob = function(type) { 9641 if (!arguments.length) { 9642 type = null; 9643 } 9644 return new FakeBlob(this.data.join(""), type, "raw"); 9645 }; 9646 FBB_proto.toString = function() { 9647 return "[object BlobBuilder]"; 9648 }; 9649 FB_proto.slice = function(start, end, type) { 9650 var args = arguments.length; 9651 if (args < 3) { 9652 type = null; 9653 } 9654 return new FakeBlob( 9655 this.data.slice(start, args > 1 ? end : this.data.length) 9656 , type 9657 , this.encoding 9658 ); 9659 }; 9660 FB_proto.toString = function() { 9661 return "[object Blob]"; 9662 }; 9663 FB_proto.close = function() { 9664 this.size = 0; 9665 delete this.data; 9666 }; 9667 return FakeBlobBuilder; 9668 }(view)); 9669 9670 view.Blob = function(blobParts, options) { 9671 var type = options ? (options.type || "") : ""; 9672 var builder = new BlobBuilder(); 9673 if (blobParts) { 9674 for (var i = 0, len = blobParts.length; i < len; i++) { 9675 if (Uint8Array && blobParts[i] instanceof Uint8Array) { 9676 builder.append(blobParts[i].buffer); 9677 } 9678 else { 9679 builder.append(blobParts[i]); 9680 } 9681 } 9682 } 9683 var blob = builder.getBlob(type); 9684 if (!blob.slice && blob.webkitSlice) { 9685 blob.slice = blob.webkitSlice; 9686 } 9687 return blob; 9688 }; 9689 9690 var getPrototypeOf = Object.getPrototypeOf || function(object) { 9691 return object.__proto__; 9692 }; 9693 view.Blob.prototype = getPrototypeOf(new view.Blob()); 9694 }(typeof self !== "undefined" && self || typeof window !== "undefined" && window || undefined.content || undefined)); 9695 9696 /* FileSaver.js 9697 * A saveAs() FileSaver implementation. 9698 * 1.1.20151003 9699 * 9700 * By Eli Grey, http://eligrey.com 9701 * License: MIT 9702 * See https://github.com/eligrey/FileSaver.js/blob/master/LICENSE.md 9703 */ 9704 9705 /*global self */ 9706 /*jslint bitwise: true, indent: 4, laxbreak: true, laxcomma: true, smarttabs: true, plusplus: true */ 9707 9708 /*! @source http://purl.eligrey.com/github/FileSaver.js/blob/master/FileSaver.js */ 9709
9710 var saveAs = saveAs || (function(view) { 9711 "use strict"; 9712 // IE <10 is explicitly unsupported 9713 if (typeof navigator !== "undefined" && /MSIE [1-9]\./.test(navigator.userAgent)) { 9714 return; 9715 } 9716 var 9717 doc = view.document 9718 // only get URL when necessary in case Blob.js hasn't overridden it yet 9719 , get_URL = function() { 9720 return view.URL || view.webkitURL || view; 9721 } 9722 , save_link = doc.createElementNS("http://www.w3.org/1999/xhtml", "a") 9723 , can_use_save_link = "download" in save_link 9724 , click = function(node) { 9725 var event = new MouseEvent("click"); 9726 node.dispatchEvent(event); 9727 } 9728 , is_safari = /Version\/[\d\.]+.*Safari/.test(navigator.userAgent) 9729 , webkit_req_fs = view.webkitRequestFileSystem 9730 , req_fs = view.requestFileSystem || webkit_req_fs || view.mozRequestFileSystem 9731 , throw_outside = function(ex) { 9732 (view.setImmediate || view.setTimeout)(function() { 9733 throw ex; 9734 }, 0); 9735 } 9736 , force_saveable_type = "application/octet-stream" 9737 , fs_min_size = 0 9738 // See https://code.google.com/p/chromium/issues/detail?id=375297#c7 and 9739 // https://github.com/eligrey/FileSaver.js/commit/485930a#commitcomment-8768047 9740 // for the reasoning behind the timeout and revocation flow 9741 , arbitrary_revoke_timeout = 500 // in ms 9742 , revoke = function(file) { 9743 var revoker = function() { 9744 if (typeof file === "string") { // file is an object URL 9745 get_URL().revokeObjectURL(file); 9746 } else { // file is a File 9747 file.remove(); 9748 } 9749 }; 9750 if (view.chrome) { 9751 revoker(); 9752 } else { 9753 setTimeout(revoker, arbitrary_revoke_timeout); 9754 } 9755 } 9756 , dispatch = function(filesaver, event_types, event) { 9757 event_types = [].concat(event_types); 9758 var i = event_types.length; 9759 while (i--) { 9760 var listener = filesaver["on" + event_types[i]]; 9761 if (typeof listener === "function") { 9762 try { 9763 listener.call(filesaver, event || filesaver); 9764 } catch (ex) { 9765 throw_outside(ex); 9766 } 9767 } 9768 } 9769 } 9770 , auto_bom = function(blob) { 9771 // prepend BOM for UTF-8 XML and text/* types (including HTML) 9772 if (/^\s*(?:text\/\S*|application\/xml|\S*\/\S*\+xml)\s*;.*charset\s*=\s*utf-8/i.test(blob.type)) { 9773 return new Blob(["\ufeff", blob], {type: blob.type}); 9774 } 9775 return blob; 9776 } 9777 , FileSaver = function(blob, name, no_auto_bom) { 9778 if (!no_auto_bom) { 9779 blob = auto_bom(blob); 9780 } 9781 // First try a.download, then web filesystem, then object URLs 9782 var 9783 filesaver = this 9784 , type = blob.type 9785 , blob_changed = false 9786 , object_url 9787 , target_view 9788 , dispatch_all = function() { 9789 dispatch(filesaver, "writestart progress write writeend".split(" ")); 9790 } 9791 // on any filesys errors revert to saving with object URLs 9792 , fs_error = function() { 9793 if (target_view && is_safari && typeof FileReader !== "undefined") { 9794 // Safari doesn't allow downloading of blob urls 9795 var reader = new FileReader(); 9796 reader.onloadend = function() { 9797 var base64Data = reader.result; 9798 target_view.location.href = "data:attachment/file" + base64Data.slice(base64Data.search(/[,;]/)); 9799 filesaver.readyState = filesaver.DONE; 9800 dispatch_all(); 9801 };
9802 reader.readAsDataURL(blob); 9803 filesaver.readyState = filesaver.INIT; 9804 return; 9805 } 9806 // don't create more object URLs than needed 9807 if (blob_changed || !object_url) { 9808 object_url = get_URL().createObjectURL(blob); 9809 } 9810 if (target_view) { 9811 target_view.location.href = object_url; 9812 } else { 9813 var new_tab = view.open(object_url, "_blank"); 9814 if (new_tab == undefined && is_safari) { 9815 //Apple do not allow window.open, see http://bit.ly/1kZffRI 9816 view.location.href = object_url 9817 } 9818 } 9819 filesaver.readyState = filesaver.DONE; 9820 dispatch_all(); 9821 revoke(object_url); 9822 } 9823 , abortable = function(func) { 9824 return function() { 9825 if (filesaver.readyState !== filesaver.DONE) { 9826 return func.apply(this, arguments); 9827 } 9828 }; 9829 } 9830 , create_if_not_found = {create: true, exclusive: false} 9831 , slice 9832 ; 9833 filesaver.readyState = filesaver.INIT; 9834 if (!name) { 9835 name = "download"; 9836 } 9837 if (can_use_save_link) { 9838 object_url = get_URL().createObjectURL(blob); 9839 setTimeout(function() { 9840 save_link.href = object_url;
9841 save_link.download = name; 9842 click(save_link); 9843 dispatch_all(); 9844 revoke(object_url); 9845 filesaver.readyState = filesaver.DONE; 9846 }); 9847 return; 9848 } 9849 // Object and web filesystem URLs have a problem saving in Google Chrome when 9850 // viewed in a tab, so I force save with application/octet-stream 9851 // http://code.google.com/p/chromium/issues/detail?id=91158 9852 // Update: Google errantly closed 91158, I submitted it again: 9853 // https://code.google.com/p/chromium/issues/detail?id=389642 9854 if (view.chrome && type && type !== force_saveable_type) { 9855 slice = blob.slice || blob.webkitSlice; 9856 blob = slice.call(blob, 0, blob.size, force_saveable_type); 9857 blob_changed = true; 9858 } 9859 // Since I can't be sure that the guessed media type will trigger a download 9860 // in WebKit, I append .download to the filename. 9861 // https://bugs.webkit.org/show_bug.cgi?id=65440 9862 if (webkit_req_fs && name !== "download") { 9863 name += ".download"; 9864 } 9865 if (type === force_saveable_type || webkit_req_fs) { 9866 target_view = view; 9867 } 9868 if (!req_fs) { 9869 fs_error(); 9870 return; 9871 } 9872 fs_min_size += blob.size; 9873 req_fs(view.TEMPORARY, fs_min_size, abortable(function(fs) { 9874 fs.root.getDirectory("saved", create_if_not_found, abortable(function(dir) { 9875 var save = function() { 9876 dir.getFile(name, create_if_not_found, abortable(function(file) { 9877 file.createWriter(abortable(function(writer) { 9878 writer.onwriteend = function(event) { 9879 target_view.location.href = file.toURL(); 9880 filesaver.readyState = filesaver.DONE; 9881 dispatch(filesaver, "writeend", event); 9882 revoke(file); 9883 }; 9884 writer.onerror = function() { 9885 var error = writer.error; 9886 if (error.code !== error.ABORT_ERR) { 9887 fs_error(); 9888 } 9889 }; 9890 "writestart progress write abort".split(" ").forEach(function(event) { 9891 writer["on" + event] = filesaver["on" + event]; 9892 }); 9893 writer.write(blob); 9894 filesaver.abort = function() { 9895 writer.abort(); 9896 filesaver.readyState = filesaver.DONE; 9897 }; 9898 filesaver.readyState = filesaver.WRITING; 9899 }), fs_error); 9900 }), fs_error); 9901 }; 9902 dir.getFile(name, {create: false}, abortable(function(file) { 9903 // delete file if it already exists 9904 file.remove(); 9905 save(); 9906 }), abortable(function(ex) { 9907 if (ex.code === ex.NOT_FOUND_ERR) { 9908 save(); 9909 } else { 9910 fs_error(); 9911 } 9912 })); 9913 }), fs_error); 9914 }), fs_error); 9915 } 9916 , FS_proto = FileSaver.prototype 9917 , saveAs = function(blob, name, no_auto_bom) { 9918 return new FileSaver(blob, name, no_auto_bom); 9919 } 9920 ; 9921 // IE 10+ (native saveAs) 9922 if (typeof navigator !== "undefined" && navigator.msSaveOrOpenBlob) { 9923 return function(blob, name, no_auto_bom) { 9924 if (!no_auto_bom) { 9925 blob = auto_bom(blob); 9926 } 9927 return navigator.msSaveOrOpenBlob(blob, name || "download"); 9928 }; 9929 } 9930 9931 FS_proto.abort = function() { 9932 var filesaver = this; 9933 filesaver.readyState = filesaver.DONE; 9934 dispatch(filesaver, "abort"); 9935 }; 9936 FS_proto.readyState = FS_proto.INIT = 0; 9937 FS_proto.WRITING = 1; 9938 FS_proto.DONE = 2; 9939 9940 FS_proto.error = 9941 FS_proto.onwritestart = 9942 FS_proto.onprogress = 9943 FS_proto.onwrite = 9944 FS_proto.onabort = 9945 FS_proto.onerror = 9946 FS_proto.onwriteend = 9947 null; 9948 9949 return saveAs; 9950 }( 9951 typeof self !== "undefined" && self 9952 || typeof window !== "undefined" && window 9953 || undefined.content 9954 )); 9955 // `self` is undefined in Firefox for Android content script context 9956 // while `this` is nsIContentFrameMessageManager 9957 // with an attribute `content` that corresponds to the window 9958 9959 if (typeof module !== "undefined" && module.exports) {
9960 module.exports.saveAs = saveAs; 9961 } else if ((typeof define !== "undefined" && define !== null) && (define.amd != null)) { 9962 define([], function() { 9963 return saveAs; 9964 }); 9965 } 9966 9967 /* 9968 * Copyright (c) 2012 chick307 <[email protected]> 9969 * 9970 * Licensed under the MIT License. 9971 * http://opensource.org/licenses/mit-license 9972 */ 9973 9974 void function(global, callback) { 9975 if (typeof module === 'object') { 9976 module.exports = callback(); 9977 } else if (typeof define === 'function') { 9978 define(callback); 9979 } else { 9980 global.adler32cs = callback(); 9981 } 9982 }(jsPDF, function() { 9983 var _hasArrayBuffer = typeof ArrayBuffer === 'function' && 9984 typeof Uint8Array === 'function'; 9985 9986 var _Buffer = null, _isBuffer = (function() { 9987 if (!_hasArrayBuffer) 9988 return function _isBuffer() { return false }; 9989 9990 try { 9991 var buffer = {}; 9992 if (typeof buffer.Buffer === 'function') 9993 _Buffer = buffer.Buffer; 9994 } catch (error) {} 9995 9996 return function _isBuffer(value) { 9997 return value instanceof ArrayBuffer || 9998 _Buffer !== null && value instanceof _Buffer; 9999 }; 10000 }()); 10001 10002 var _utf8ToBinary = (function() { 10003 if (_Buffer !== null) { 10004 return function _utf8ToBinary(utf8String) { 10005 return new _Buffer(utf8String, 'utf8').toString('binary'); 10006 }; 10007 } else { 10008 return function _utf8ToBinary(utf8String) { 10009 return unescape(encodeURIComponent(utf8String)); 10010 }; 10011 } 10012 }()); 10013 10014 var MOD = 65521; 10015 10016 var _update = function _update(checksum, binaryString) { 10017 var a = checksum & 0xFFFF, b = checksum >>> 16; 10018 for (var i = 0, length = binaryString.length; i < length; i++) { 10019 a = (a + (binaryString.charCodeAt(i) & 0xFF)) % MOD; 10020 b = (b + a) % MOD; 10021 } 10022 return (b << 16 | a) >>> 0; 10023 }; 10024 10025 var _updateUint8Array = function _updateUint8Array(checksum, uint8Array) { 10026 var a = checksum & 0xFFFF, b = checksum >>> 16; 10027 for (var i = 0, length = uint8Array.length, x; i < length; i++) { 10028 a = (a + uint8Array[i]) % MOD; 10029 b = (b + a) % MOD; 10030 } 10031 return (b << 16 | a) >>> 0 10032 }; 10033 10034 var exports = {}; 10035 10036 var Adler32 = exports.Adler32 = (function() { 10037 var ctor = function Adler32(checksum) { 10038 if (!(this instanceof ctor)) { 10039 throw new TypeError( 10040 'Constructor cannot called be as a function.'); 10041 } 10042 if (!isFinite(checksum = checksum == null ? 1 : +checksum)) { 10043 throw new Error( 10044 'First arguments needs to be a finite number.'); 10045 } 10046 this.checksum = checksum >>> 0; 10047 }; 10048 10049 var proto = ctor.prototype = {}; 10050 proto.constructor = ctor; 10051 10052 ctor.from = function(from) { 10053 from.prototype = proto; 10054 return from; 10055 }(function from(binaryString) { 10056 if (!(this instanceof ctor)) { 10057 throw new TypeError( 10058 'Constructor cannot called be as a function.'); 10059 } 10060 if (binaryString == null) 10061 throw new Error('First argument needs to be a string.'); 10062 this.checksum = _update(1, binaryString.toString()); 10063 }); 10064 10065 ctor.fromUtf8 = function(fromUtf8) { 10066 fromUtf8.prototype = proto; 10067 return fromUtf8; 10068 }(function fromUtf8(utf8String) { 10069 if (!(this instanceof ctor)) { 10070 throw new TypeError( 10071 'Constructor cannot called be as a function.'); 10072 } 10073 if (utf8String == null) 10074 throw new Error('First argument needs to be a string.'); 10075 var binaryString = _utf8ToBinary(utf8String.toString()); 10076 this.checksum = _update(1, binaryString); 10077 }); 10078 10079 if (_hasArrayBuffer) { 10080 ctor.fromBuffer = function(fromBuffer) { 10081 fromBuffer.prototype = proto; 10082 return fromBuffer; 10083 }(function fromBuffer(buffer) { 10084 if (!(this instanceof ctor)) { 10085 throw new TypeError( 10086 'Constructor cannot called be as a function.'); 10087 } 10088 if (!_isBuffer(buffer)) 10089 throw new Error('First argument needs to be ArrayBuffer.'); 10090 var array = new Uint8Array(buffer); 10091 return this.checksum = _updateUint8Array(1, array); 10092 }); 10093 } 10094 10095 proto.update = function update(binaryString) { 10096 if (binaryString == null) 10097 throw new Error('First argument needs to be a string.'); 10098 binaryString = binaryString.toString(); 10099 return this.checksum = _update(this.checksum, binaryString); 10100 }; 10101
10102 proto.updateUtf8 = function updateUtf8(utf8String) { 10103 if (utf8String == null) 10104 throw new Error('First argument needs to be a string.'); 10105 var binaryString = _utf8ToBinary(utf8String.toString()); 10106 return this.checksum = _update(this.checksum, binaryString); 10107 }; 10108 10109 if (_hasArrayBuffer) { 10110 proto.updateBuffer = function updateBuffer(buffer) { 10111 if (!_isBuffer(buffer)) 10112 throw new Error('First argument needs to be ArrayBuffer.'); 10113 var array = new Uint8Array(buffer); 10114 return this.checksum = _updateUint8Array(this.checksum, array); 10115 }; 10116 } 10117 10118 proto.clone = function clone() { 10119 return new Adler32(this.checksum); 10120 }; 10121 10122 return ctor; 10123 }()); 10124 10125 exports.from = function from(binaryString) { 10126 if (binaryString == null) 10127 throw new Error('First argument needs to be a string.'); 10128 return _update(1, binaryString.toString()); 10129 }; 10130 10131 exports.fromUtf8 = function fromUtf8(utf8String) { 10132 if (utf8String == null) 10133 throw new Error('First argument needs to be a string.'); 10134 var binaryString = _utf8ToBinary(utf8String.toString()); 10135 return _update(1, binaryString); 10136 }; 10137 10138 if (_hasArrayBuffer) { 10139 exports.fromBuffer = function fromBuffer(buffer) { 10140 if (!_isBuffer(buffer)) 10141 throw new Error('First argument need to be ArrayBuffer.'); 10142 var array = new Uint8Array(buffer); 10143 return _updateUint8Array(1, array); 10144 }; 10145 } 10146 10147 return exports; 10148 }); 10149 10150 /** 10151 * CssColors 10152 * Copyright (c) 2014 Steven Spungin (TwelveTone LLC) [email protected] 10153 * 10154 * Licensed under the MIT License. 10155 * http://opensource.org/licenses/mit-license 10156 */ 10157 10158 /** 10159 * Usage CssColors('red'); 10160 * Returns RGB hex color with '#' prefix 10161 */ 10162 10163 var CssColors = {}; 10164 CssColors._colorsTable = { 10165 "aliceblue" : "#f0f8ff", 10166 "antiquewhite" : "#faebd7", 10167 "aqua" : "#00ffff", 10168 "aquamarine" : "#7fffd4", 10169 "azure" : "#f0ffff", 10170 "beige" : "#f5f5dc", 10171 "bisque" : "#ffe4c4", 10172 "black" : "#000000", 10173 "blanchedalmond" : "#ffebcd", 10174 "blue" : "#0000ff", 10175 "blueviolet" : "#8a2be2", 10176 "brown" : "#a52a2a", 10177 "burlywood" : "#deb887", 10178 "cadetblue" : "#5f9ea0", 10179 "chartreuse" : "#7fff00", 10180 "chocolate" : "#d2691e", 10181 "coral" : "#ff7f50", 10182 "cornflowerblue" : "#6495ed", 10183 "cornsilk" : "#fff8dc", 10184 "crimson" : "#dc143c", 10185 "cyan" : "#00ffff", 10186 "darkblue" : "#00008b", 10187 "darkcyan" : "#008b8b", 10188 "darkgoldenrod" : "#b8860b", 10189 "darkgray" : "#a9a9a9", 10190 "darkgreen" : "#006400", 10191 "darkkhaki" : "#bdb76b", 10192 "darkmagenta" : "#8b008b", 10193 "darkolivegreen" : "#556b2f", 10194 "darkorange" : "#ff8c00", 10195 "darkorchid" : "#9932cc", 10196 "darkred" : "#8b0000", 10197 "darksalmon" : "#e9967a", 10198 "darkseagreen" : "#8fbc8f", 10199 "darkslateblue" : "#483d8b", 10200 "darkslategray" : "#2f4f4f", 10201 "darkturquoise" : "#00ced1", 10202 "darkviolet" : "#9400d3", 10203 "deeppink" : "#ff1493", 10204 "deepskyblue" : "#00bfff", 10205 "dimgray" : "#696969", 10206 "dodgerblue" : "#1e90ff", 10207 "firebrick" : "#b22222", 10208 "floralwhite" : "#fffaf0", 10209 "forestgreen" : "#228b22", 10210 "fuchsia" : "#ff00ff", 10211 "gainsboro" : "#dcdcdc", 10212 "ghostwhite" : "#f8f8ff", 10213 "gold" : "#ffd700", 10214 "goldenrod" : "#daa520", 10215 "gray" : "#808080", 10216 "green" : "#008000", 10217 "greenyellow" : "#adff2f", 10218 "honeydew" : "#f0fff0", 10219 "hotpink" : "#ff69b4", 10220 "indianred " : "#cd5c5c", 10221 "indigo" : "#4b0082", 10222 "ivory" : "#fffff0", 10223 "khaki" : "#f0e68c", 10224 "lavender" : "#e6e6fa", 10225 "lavenderblush" : "#fff0f5", 10226 "lawngreen" : "#7cfc00", 10227 "lemonchiffon" : "#fffacd", 10228 "lightblue" : "#add8e6", 10229 "lightcoral" : "#f08080", 10230 "lightcyan" : "#e0ffff", 10231 "lightgoldenrodyellow" : "#fafad2", 10232 "lightgrey" : "#d3d3d3", 10233 "lightgreen" : "#90ee90", 10234 "lightpink" : "#ffb6c1", 10235 "lightsalmon" : "#ffa07a", 10236 "lightseagreen" : "#20b2aa", 10237 "lightskyblue" : "#87cefa", 10238 "lightslategray" : "#778899", 10239 "lightsteelblue" : "#b0c4de", 10240 "lightyellow" : "#ffffe0", 10241 "lime" : "#00ff00", 10242 "limegreen" : "#32cd32", 10243 "linen" : "#faf0e6", 10244 "magenta" : "#ff00ff", 10245 "maroon" : "#800000", 10246 "mediumaquamarine" : "#66cdaa", 10247 "mediumblue" : "#0000cd", 10248 "mediumorchid" : "#ba55d3", 10249 "mediumpurple" : "#9370d8", 10250 "mediumseagreen" : "#3cb371", 10251 "mediumslateblue" : "#7b68ee", 10252 "mediumspringgreen" : "#00fa9a", 10253 "mediumturquoise" : "#48d1cc", 10254 "mediumvioletred" : "#c71585", 10255 "midnightblue" : "#191970", 10256 "mintcream" : "#f5fffa", 10257 "mistyrose" : "#ffe4e1", 10258 "moccasin" : "#ffe4b5", 10259 "navajowhite" : "#ffdead", 10260 "navy" : "#000080", 10261 "oldlace" : "#fdf5e6", 10262 "olive" : "#808000", 10263 "olivedrab" : "#6b8e23", 10264 "orange" : "#ffa500", 10265 "orangered" : "#ff4500", 10266 "orchid" : "#da70d6", 10267 "palegoldenrod" : "#eee8aa", 10268 "palegreen" : "#98fb98", 10269 "paleturquoise" : "#afeeee", 10270 "palevioletred" : "#d87093", 10271 "papayawhip" : "#ffefd5", 10272 "peachpuff" : "#ffdab9", 10273 "peru" : "#cd853f", 10274 "pink" : "#ffc0cb", 10275 "plum" : "#dda0dd", 10276 "powderblue" : "#b0e0e6", 10277 "purple" : "#800080", 10278 "red" : "#ff0000", 10279 "rosybrown" : "#bc8f8f", 10280 "royalblue" : "#4169e1", 10281 "saddlebrown" : "#8b4513", 10282 "salmon" : "#fa8072", 10283 "sandybrown" : "#f4a460", 10284 "seagreen" : "#2e8b57", 10285 "seashell" : "#fff5ee", 10286 "sienna" : "#a0522d", 10287 "silver" : "#c0c0c0", 10288 "skyblue" : "#87ceeb", 10289 "slateblue" : "#6a5acd", 10290 "slategray" : "#708090", 10291 "snow" : "#fffafa", 10292 "springgreen" : "#00ff7f", 10293 "steelblue" : "#4682b4", 10294 "tan" : "#d2b48c", 10295 "teal" : "#008080", 10296 "thistle" : "#d8bfd8", 10297 "tomato" : "#ff6347", 10298 "turquoise" : "#40e0d0", 10299 "violet" : "#ee82ee", 10300 "wheat" : "#f5deb3", 10301 "white" : "#ffffff", 10302 "whitesmoke" : "#f5f5f5", 10303 "yellow" : "#ffff00", 10304 "yellowgreen" : "#9acd32" 10305 }; 10306
10307 CssColors.colorNameToHex = function(color) { 10308 color = color.toLowerCase(); 10309 if (typeof this._colorsTable[color] != 'undefined') 10310 return this._colorsTable[color]; 10311 10312 return false; 10313 }; 10314 10315 /* 10316 Deflate.js - https://github.com/gildas-lormeau/zip.js 10317 Copyright (c) 2013 Gildas Lormeau. All rights reserved. 10318 10319 Redistribution and use in source and binary forms, with or without 10320 modification, are permitted provided that the following conditions are met: 10321 10322 1. Redistributions of source code must retain the above copyright notice, 10323 this list of conditions and the following disclaimer. 10324 10325 2. Redistributions in binary form must reproduce the above copyright 10326 notice, this list of conditions and the following disclaimer in 10327 the documentation and/or other materials provided with the distribution. 10328 10329 3. The names of the authors may not be used to endorse or promote products 10330 derived from this software without specific prior written permission. 10331 10332 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, 10333 INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 10334 FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, 10335 INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, 10336 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 10337 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, 10338 OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 10339 LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 10340 NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 10341 EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 10342 */ 10343 10344 /* 10345 * This program is based on JZlib 1.0.2 ymnk, JCraft,Inc. 10346 * JZlib is based on zlib-1.1.3, so all credit should go authors 10347 * Jean-loup Gailly([email protected]) and Mark Adler([email protected]) 10348 * and contributors of zlib. 10349 */ 10350 10351 var Deflater = (function(obj) { 10352 10353 // Global 10354 10355 var MAX_BITS = 15; 10356 var D_CODES = 30; 10357 var BL_CODES = 19; 10358 10359 var LENGTH_CODES = 29; 10360 var LITERALS = 256; 10361 var L_CODES = (LITERALS + 1 + LENGTH_CODES); 10362 var HEAP_SIZE = (2 * L_CODES + 1); 10363 10364 var END_BLOCK = 256; 10365 10366 // Bit length codes must not exceed MAX_BL_BITS bits 10367 var MAX_BL_BITS = 7; 10368 10369 // repeat previous bit length 3-6 times (2 bits of repeat count) 10370 var REP_3_6 = 16; 10371 10372 // repeat a zero length 3-10 times (3 bits of repeat count) 10373 var REPZ_3_10 = 17; 10374 10375 // repeat a zero length 11-138 times (7 bits of repeat count) 10376 var REPZ_11_138 = 18; 10377 10378 // The lengths of the bit length codes are sent in order of decreasing 10379 // probability, to avoid transmitting the lengths for unused bit 10380 // length codes. 10381 10382 var Buf_size = 8 * 2; 10383 10384 // JZlib version : "1.0.2" 10385 var Z_DEFAULT_COMPRESSION = -1; 10386 10387 // compression strategy 10388 var Z_FILTERED = 1; 10389 var Z_HUFFMAN_ONLY = 2; 10390 var Z_DEFAULT_STRATEGY = 0; 10391 10392 var Z_NO_FLUSH = 0; 10393 var Z_PARTIAL_FLUSH = 1; 10394 var Z_FULL_FLUSH = 3; 10395 var Z_FINISH = 4; 10396 10397 var Z_OK = 0; 10398 var Z_STREAM_END = 1; 10399 var Z_NEED_DICT = 2; 10400 var Z_STREAM_ERROR = -2; 10401 var Z_DATA_ERROR = -3; 10402 var Z_BUF_ERROR = -5; 10403 10404 // Tree 10405 10406 // see definition of array dist_code below 10407 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, 10408 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, 10409 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, 10410 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, 10411 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, 10412 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, 10413 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, 10414 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, 10415 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, 10416 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, 10417 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, 10418 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, 10419 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, 10420 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 ]; 10421 10422 function Tree() { 10423 var that = this; 10424 10425 // dyn_tree; // the dynamic tree 10426 // max_code; // largest code with non zero frequency 10427 // stat_desc; // the corresponding static tree 10428 10429 // Compute the optimal bit lengths for a tree and update the total bit 10430 // length 10431 // for the current block. 10432 // IN assertion: the fields freq and dad are set, heap[heap_max] and 10433 // above are the tree nodes sorted by increasing frequency. 10434 // OUT assertions: the field len is set to the optimal bit length, the 10435 // array bl_count contains the frequencies for each bit length. 10436 // The length opt_len is updated; static_len is also updated if stree is 10437 // not null.
10438 function gen_bitlen(s) { 10439 var tree = that.dyn_tree; 10440 var stree = that.stat_desc.static_tree; 10441 var extra = that.stat_desc.extra_bits; 10442 var base = that.stat_desc.extra_base; 10443 var max_length = that.stat_desc.max_length; 10444 var h; // heap index 10445 var n, m; // iterate over the tree elements 10446 var bits; // bit length 10447 var xbits; // extra bits 10448 var f; // frequency 10449 var overflow = 0; // number of elements with bit length too large 10450 10451 for (bits = 0; bits <= MAX_BITS; bits++) 10452 s.bl_count[bits] = 0; 10453 10454 // In a first pass, compute the optimal bit lengths (which may 10455 // overflow in the case of the bit length tree). 10456 tree[s.heap[s.heap_max] * 2 + 1] = 0; // root of the heap 10457 10458 for (h = s.heap_max + 1; h < HEAP_SIZE; h++) { 10459 n = s.heap[h]; 10460 bits = tree[tree[n * 2 + 1] * 2 + 1] + 1; 10461 if (bits > max_length) { 10462 bits = max_length; 10463 overflow++; 10464 } 10465 tree[n * 2 + 1] = bits; 10466 // We overwrite tree[n*2+1] which is no longer needed 10467 10468 if (n > that.max_code) 10469 continue; // not a leaf node 10470 10471 s.bl_count[bits]++; 10472 xbits = 0; 10473 if (n >= base) 10474 xbits = extra[n - base]; 10475 f = tree[n * 2]; 10476 s.opt_len += f * (bits + xbits); 10477 if (stree) 10478 s.static_len += f * (stree[n * 2 + 1] + xbits); 10479 } 10480 if (overflow === 0) 10481 return; 10482 10483 // This happens for example on obj2 and pic of the Calgary corpus 10484 // Find the first bit length which could increase: 10485 do { 10486 bits = max_length - 1; 10487 while (s.bl_count[bits] === 0) 10488 bits--; 10489 s.bl_count[bits]--; // move one leaf down the tree 10490 s.bl_count[bits + 1] += 2; // move one overflow item as its brother 10491 s.bl_count[max_length]--; 10492 // The brother of the overflow item also moves one step up, 10493 // but this does not affect bl_count[max_length] 10494 overflow -= 2; 10495 } while (overflow > 0); 10496 10497 for (bits = max_length; bits !== 0; bits--) { 10498 n = s.bl_count[bits]; 10499 while (n !== 0) { 10500 m = s.heap[--h]; 10501 if (m > that.max_code) 10502 continue; 10503 if (tree[m * 2 + 1] != bits) { 10504 s.opt_len += (bits - tree[m * 2 + 1]) * tree[m * 2]; 10505 tree[m * 2 + 1] = bits; 10506 } 10507 n--; 10508 } 10509 } 10510 } 10511 10512 // Reverse the first len bits of a code, using straightforward code (a 10513 // faster 10514 // method would use a table) 10515 // IN assertion: 1 <= len <= 15 10516 function bi_reverse(code, // the value to invert 10517 len // its bit length 10518 ) { 10519 var res = 0; 10520 do { 10521 res |= code & 1; 10522 code >>>= 1; 10523 res <<= 1; 10524 } while (--len > 0); 10525 return res >>> 1; 10526 } 10527 10528 // Generate the codes for a given tree and bit counts (which need not be 10529 // optimal). 10530 // IN assertion: the array bl_count contains the bit length statistics for 10531 // the given tree and the field len is set for all tree elements. 10532 // OUT assertion: the field code is set for all tree elements of non 10533 // zero code length. 10534 function gen_codes(tree, // the tree to decorate 10535 max_code, // largest code with non zero frequency 10536 bl_count // number of codes at each bit length 10537 ) { 10538 var next_code = []; // next code value for each 10539 // bit length 10540 var code = 0; // running code value 10541 var bits; // bit index 10542 var n; // code index 10543 var len; 10544 10545 // The distribution counts are first used to generate the code values 10546 // without bit reversal. 10547 for (bits = 1; bits <= MAX_BITS; bits++) { 10548 next_code[bits] = code = ((code + bl_count[bits - 1]) << 1); 10549 } 10550 10551 // Check that the bit counts in bl_count are consistent. The last code 10552 // must be all ones. 10553 // Assert (code + bl_count[MAX_BITS]-1 == (1<<MAX_BITS)-1, 10554 // "inconsistent bit counts"); 10555 // Tracev((stderr,"\ngen_codes: max_code %d ", max_code)); 10556 10557 for (n = 0; n <= max_code; n++) { 10558 len = tree[n * 2 + 1]; 10559 if (len === 0) 10560 continue; 10561 // Now reverse the bits 10562 tree[n * 2] = bi_reverse(next_code[len]++, len); 10563 } 10564 } 10565 10566 // Construct one Huffman tree and assigns the code bit strings and lengths. 10567 // Update the total bit length for the current block. 10568 // IN assertion: the field freq is set for all tree elements. 10569 // OUT assertions: the fields len and code are set to the optimal bit length 10570 // and corresponding code. The length opt_len is updated; static_len is 10571 // also updated if stree is not null. The field max_code is set. 10572 that.build_tree = function(s) { 10573 var tree = that.dyn_tree; 10574 var stree = that.stat_desc.static_tree; 10575 var elems = that.stat_desc.elems; 10576 var n, m; // iterate over heap elements 10577 var max_code = -1; // largest code with non zero frequency 10578 var node; // new node being created 10579 10580 // Construct the initial heap, with least frequent element in 10581 // heap[1]. The sons of heap[n] are heap[2*n] and heap[2*n+1]. 10582 // heap[0] is not used. 10583 s.heap_len = 0; 10584 s.heap_max = HEAP_SIZE; 10585 10586 for (n = 0; n < elems; n++) { 10587 if (tree[n * 2] !== 0) { 10588 s.heap[++s.heap_len] = max_code = n; 10589 s.depth[n] = 0; 10590 } else { 10591 tree[n * 2 + 1] = 0; 10592 } 10593 } 10594 10595 // The pkzip format requires that at least one distance code exists, 10596 // and that at least one bit should be sent even if there is only one 10597 // possible code. So to avoid special checks later on we force at least 10598 // two codes of non zero frequency. 10599 while (s.heap_len < 2) { 10600 node = s.heap[++s.heap_len] = max_code < 2 ? ++max_code : 0; 10601 tree[node * 2] = 1; 10602 s.depth[node] = 0; 10603 s.opt_len--; 10604 if (stree) 10605 s.static_len -= stree[node * 2 + 1]; 10606 // node is 0 or 1 so it does not have extra bits 10607 } 10608 that.max_code = max_code; 10609 10610 // The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree, 10611 // establish sub-heaps of increasing lengths: 10612 10613 for (n = Math.floor(s.heap_len / 2); n >= 1; n--) 10614 s.pqdownheap(tree, n); 10615 10616 // Construct the Huffman tree by repeatedly combining the least two 10617 // frequent nodes. 10618 10619 node = elems; // next internal node of the tree 10620 do { 10621 // n = node of least frequency 10622 n = s.heap[1]; 10623 s.heap[1] = s.heap[s.heap_len--]; 10624 s.pqdownheap(tree, 1); 10625 m = s.heap[1]; // m = node of next least frequency 10626 10627 s.heap[--s.heap_max] = n; // keep the nodes sorted by frequency 10628 s.heap[--s.heap_max] = m; 10629 10630 // Create a new node father of n and m 10631 tree[node * 2] = (tree[n * 2] + tree[m * 2]); 10632 s.depth[node] = Math.max(s.depth[n], s.depth[m]) + 1; 10633 tree[n * 2 + 1] = tree[m * 2 + 1] = node; 10634 10635 // and insert the new node in the heap 10636 s.heap[1] = node++; 10637 s.pqdownheap(tree, 1); 10638 } while (s.heap_len >= 2); 10639 10640 s.heap[--s.heap_max] = s.heap[1]; 10641 10642 // At this point, the fields freq and dad are set. We can now 10643 // generate the bit lengths. 10644 10645 gen_bitlen(s); 10646 10647 // The field len is now set, we can generate the bit codes 10648 gen_codes(tree, that.max_code, s.bl_count); 10649 }; 10650 10651 } 10652 10653 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, 10654 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, 10655 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, 10656 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, 10657 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, 10658 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, 10659 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 ]; 10660 10661 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 ]; 10662 10663 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, 10664 24576 ]; 10665 10666 // Mapping from a distance to a distance code. dist is the distance - 1 and 10667 // must not have side effects. _dist_code[256] and _dist_code[257] are never 10668 // used. 10669 Tree.d_code = function(dist) { 10670 return ((dist) < 256 ? _dist_code[dist] : _dist_code[256 + ((dist) >>> 7)]); 10671 }; 10672 10673 // extra bits for each length code 10674 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 ]; 10675 10676 // extra bits for each distance code 10677 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 ]; 10678 10679 // extra bits for each bit length code 10680 Tree.extra_blbits = [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 3, 7 ]; 10681 10682 Tree.bl_order = [ 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 ]; 10683 10684 // StaticTree 10685 10686 function StaticTree(static_tree, extra_bits, extra_base, elems, max_length) { 10687 var that = this; 10688 that.static_tree = static_tree; 10689 that.extra_bits = extra_bits; 10690 that.extra_base = extra_base; 10691 that.elems = elems; 10692 that.max_length = max_length; 10693 } 10694 10695 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, 10696 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, 10697 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, 10698 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, 10699 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, 10700 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, 10701 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, 10702 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
107025, 9, 147, 9, 403, 9, 83, 9, 339, 9, 211, 9, 467, 9, 10703 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, 10704 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, 10705 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, 10706 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, 10707 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, 10708 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, 10709 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, 10710 99, 8, 227, 8 ]; 10711 10712 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, 10713 25, 5, 5, 5, 21, 5, 13, 5, 29, 5, 3, 5, 19, 5, 11, 5, 27, 5, 7, 5, 23, 5 ]; 10714 10715 StaticTree.static_l_desc = new StaticTree(StaticTree.static_ltree, Tree.extra_lbits, LITERALS + 1, L_CODES, MAX_BITS); 10716 10717 StaticTree.static_d_desc = new StaticTree(StaticTree.static_dtree, Tree.extra_dbits, 0, D_CODES, MAX_BITS); 10718 10719 StaticTree.static_bl_desc = new StaticTree(null, Tree.extra_blbits, 0, BL_CODES, MAX_BL_BITS); 10720 10721 // Deflate 10722 10723 var MAX_MEM_LEVEL = 9; 10724 var DEF_MEM_LEVEL = 8; 10725 10726 function Config(good_length, max_lazy, nice_length, max_chain, func) { 10727 var that = this; 10728 that.good_length = good_length; 10729 that.max_lazy = max_lazy; 10730 that.nice_length = nice_length; 10731 that.max_chain = max_chain; 10732 that.func = func; 10733 } 10734 10735 var STORED = 0; 10736 var FAST = 1; 10737 var SLOW = 2; 10738 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), 10739 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), 10740 new Config(32, 128, 258, 1024, SLOW), new Config(32, 258, 258, 4096, SLOW) ]; 10741 10742 var z_errmsg = [ "need dictionary", // Z_NEED_DICT 10743 // 2 10744 "stream end", // Z_STREAM_END 1 10745 "", // Z_OK 0 10746 "", // Z_ERRNO (-1) 10747 "stream error", // Z_STREAM_ERROR (-2) 10748 "data error", // Z_DATA_ERROR (-3) 10749 "", // Z_MEM_ERROR (-4) 10750 "buffer error", // Z_BUF_ERROR (-5) 10751 "",// Z_VERSION_ERROR (-6) 10752 "" ]; 10753 10754 // block not completed, need more input or more output 10755 var NeedMore = 0; 10756 10757 // block flush performed 10758 var BlockDone = 1; 10759 10760 // finish started, need only more output at next deflate 10761 var FinishStarted = 2; 10762 10763 // finish done, accept no more input or output 10764 var FinishDone = 3; 10765 10766 // preset dictionary flag in zlib header 10767 var PRESET_DICT = 0x20; 10768 10769 var INIT_STATE = 42; 10770 var BUSY_STATE = 113; 10771 var FINISH_STATE = 666; 10772 10773 // The deflate compression method 10774 var Z_DEFLATED = 8; 10775 10776 var STORED_BLOCK = 0; 10777 var STATIC_TREES = 1; 10778 var DYN_TREES = 2; 10779 10780 var MIN_MATCH = 3; 10781 var MAX_MATCH = 258; 10782 var MIN_LOOKAHEAD = (MAX_MATCH + MIN_MATCH + 1); 10783 10784 function smaller(tree, n, m, depth) { 10785 var tn2 = tree[n * 2]; 10786 var tm2 = tree[m * 2]; 10787 return (tn2 < tm2 || (tn2 == tm2 && depth[n] <= depth[m])); 10788 } 10789 10790 function Deflate() { 10791 10792 var that = this; 10793 var strm; // pointer back to this zlib stream 10794 var status; // as the name implies 10795 // pending_buf; // output still pending 10796 var pending_buf_size; // size of pending_buf 10797 // pending_out; // next pending byte to output to the stream 10798 // pending; // nb of bytes in the pending buffer 10799 var method; // STORED (for zip only) or DEFLATED 10800 var last_flush; // value of flush param for previous deflate call 10801 10802 var w_size; // LZ77 window size (32K by default) 10803 var w_bits; // log2(w_size) (8..16) 10804 var w_mask; // w_size - 1 10805 10806 var window; 10807 // Sliding window. Input bytes are read into the second half of the window, 10808 // and move to the first half later to keep a dictionary of at least wSize 10809 // bytes. With this organization, matches are limited to a distance of 10810 // wSize-MAX_MATCH bytes, but this ensures that IO is always 10811 // performed with a length multiple of the block size. Also, it limits 10812 // the window size to 64K, which is quite useful on MSDOS. 10813 // To do: use the user input buffer as sliding window. 10814 10815 var window_size; 10816 // Actual size of window: 2*wSize, except when the user input buffer 10817 // is directly used as sliding window. 10818 10819 var prev; 10820 // Link to older string with same hash index. To limit the size of this 10821 // array to 64K, this link is maintained only for the last 32K strings. 10822 // An index in this array is thus a window index modulo 32K. 10823 10824 var head; // Heads of the hash chains or NIL. 10825 10826 var ins_h;
10826 // hash index of string to be inserted 10827 var hash_size; // number of elements in hash table 10828 var hash_bits; // log2(hash_size) 10829 var hash_mask; // hash_size-1 10830 10831 // Number of bits by which ins_h must be shifted at each input 10832 // step. It must be such that after MIN_MATCH steps, the oldest 10833 // byte no longer takes part in the hash key, that is: 10834 // hash_shift * MIN_MATCH >= hash_bits 10835 var hash_shift; 10836 10837 // Window position at the beginning of the current output block. Gets 10838 // negative when the window is moved backwards. 10839 10840 var block_start; 10841 10842 var match_length; // length of best match 10843 var prev_match; // previous match 10844 var match_available; // set if previous match exists 10845 var strstart; // start of string to insert 10846 var match_start; // start of matching string 10847 var lookahead; // number of valid bytes ahead in window 10848 10849 // Length of the best match at previous step. Matches not greater than this 10850 // are discarded. This is used in the lazy match evaluation. 10851 var prev_length; 10852 10853 // To speed up deflation, hash chains are never searched beyond this 10854 // length. A higher limit improves compression ratio but degrades the speed. 10855 var max_chain_length; 10856 10857 // Attempt to find a better match only when the current match is strictly 10858 // smaller than this value. This mechanism is used only for compression 10859 // levels >= 4. 10860 var max_lazy_match; 10861 10862 // Insert new strings in the hash table only if the match length is not 10863 // greater than this length. This saves time but degrades compression. 10864 // max_insert_length is used only for compression levels <= 3. 10865 10866 var level; // compression level (1..9) 10867 var strategy; // favor or force Huffman coding 10868 10869 // Use a faster search when the previous match is longer than this 10870 var good_match; 10871 10872 // Stop searching when current match exceeds this 10873 var nice_match; 10874 10875 var dyn_ltree; // literal and length tree 10876 var dyn_dtree; // distance tree 10877 var bl_tree; // Huffman tree for bit lengths 10878 10879 var l_desc = new Tree(); // desc for literal tree 10880 var d_desc = new Tree(); // desc for distance tree 10881 var bl_desc = new Tree(); // desc for bit length tree 10882 10883 // that.heap_len; // number of elements in the heap 10884 // that.heap_max; // element of largest frequency 10885 // The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used. 10886 // The same heap array is used to build all trees. 10887 10888 // Depth of each subtree used as tie breaker for trees of equal frequency 10889 that.depth = []; 10890 10891 var l_buf; // index for literals or lengths */ 10892 10893 // Size of match buffer for literals/lengths. There are 4 reasons for 10894 // limiting lit_bufsize to 64K: 10895 // - frequencies can be kept in 16 bit counters 10896 // - if compression is not successful for the first block, all input 10897 // data is still in the window so we can still emit a stored block even 10898 // when input comes from standard input. (This can also be done for 10899 // all blocks if lit_bufsize is not greater than 32K.) 10900 // - if compression is not successful for a file smaller than 64K, we can 10901 // even emit a stored file instead of a stored block (saving 5 bytes). 10902 // This is applicable only for zip (not gzip or zlib). 10903 // - creating new Huffman trees less frequently may not provide fast 10904 // adaptation to changes in the input data statistics. (Take for 10905 // example a binary file with poorly compressible code followed by 10906 // a highly compressible string table.) Smaller buffer sizes give 10907 // fast adaptation but have of course the overhead of transmitting 10908 // trees more frequently.
10909 // - I can't count above 4 10910 var lit_bufsize; 10911 10912 var last_lit; // running index in l_buf 10913 10914 // Buffer for distances. To simplify the code, d_buf and l_buf have 10915 // the same number of elements. To use different lengths, an extra flag 10916 // array would be necessary. 10917 10918 var d_buf; // index of pendig_buf 10919 10920 // that.opt_len; // bit length of current block with optimal trees 10921 // that.static_len; // bit length of current block with static trees 10922 var matches; // number of string matches in current block 10923 var last_eob_len; // bit length of EOB code for last block 10924 10925 // Output buffer. bits are inserted starting at the bottom (least 10926 // significant bits). 10927 var bi_buf; 10928 10929 // Number of valid bits in bi_buf. All bits above the last valid bit 10930 // are always zero. 10931 var bi_valid; 10932 10933 // number of codes at each bit length for an optimal tree 10934 that.bl_count = []; 10935 10936 // heap used to build the Huffman trees 10937 that.heap = []; 10938 10939 dyn_ltree = []; 10940 dyn_dtree = []; 10941 bl_tree = []; 10942 10943 function lm_init() { 10944 var i; 10945 window_size = 2 * w_size; 10946 10947 head[hash_size - 1] = 0; 10948 for (i = 0; i < hash_size - 1; i++) { 10949 head[i] = 0; 10950 } 10951 10952 // Set the default configuration parameters: 10953 max_lazy_match = config_table[level].max_lazy; 10954 good_match = config_table[level].good_length; 10955 nice_match = config_table[level].nice_length; 10956 max_chain_length = config_table[level].max_chain; 10957 10958 strstart = 0; 10959 block_start = 0; 10960 lookahead = 0; 10961 match_length = prev_length = MIN_MATCH - 1; 10962 match_available = 0; 10963 ins_h = 0; 10964 } 10965 10966 function init_block() { 10967 var i; 10968 // Initialize the trees. 10969 for (i = 0; i < L_CODES; i++) 10970 dyn_ltree[i * 2] = 0; 10971 for (i = 0; i < D_CODES; i++) 10972 dyn_dtree[i * 2] = 0; 10973 for (i = 0; i < BL_CODES; i++) 10974 bl_tree[i * 2] = 0; 10975 10976 dyn_ltree[END_BLOCK * 2] = 1; 10977 that.opt_len = that.static_len = 0; 10978 last_lit = matches = 0; 10979 } 10980 10981 // Initialize the tree data structures for a new zlib stream. 10982 function tr_init() { 10983 10984 l_desc.dyn_tree = dyn_ltree; 10985 l_desc.stat_desc = StaticTree.static_l_desc; 10986 10987 d_desc.dyn_tree = dyn_dtree; 10988 d_desc.stat_desc = StaticTree.static_d_desc; 10989 10990 bl_desc.dyn_tree = bl_tree; 10991 bl_desc.stat_desc = StaticTree.static_bl_desc; 10992 10993 bi_buf = 0; 10994 bi_valid = 0; 10995 last_eob_len = 8; // enough lookahead for inflate 10996 10997 // Initialize the first block of the first file: 10998 init_block(); 10999 } 11000 11001 // Restore the heap property by moving down the tree starting at node k, 11002 // exchanging a node with the smallest of its two sons if necessary, 11003 // stopping 11004 // when the heap property is re-established (each father smaller than its 11005 // two sons). 11006 that.pqdownheap = function(tree, // the tree to restore 11007 k // node to move down 11008 ) { 11009 var heap = that.heap; 11010 var v = heap[k]; 11011 var j = k << 1; // left son of k 11012 while (j <= that.heap_len) { 11013 // Set j to the smallest of the two sons: 11014 if (j < that.heap_len && smaller(tree, heap[j + 1], heap[j], that.depth)) { 11015 j++; 11016 } 11017 // Exit if v is smaller than both sons 11018 if (smaller(tree, v, heap[j], that.depth)) 11019 break; 11020 11021 // Exchange v with the smallest son 11022 heap[k] = heap[j]; 11023 k = j; 11024 // And continue down the tree, setting j to the left son of k 11025 j <<= 1; 11026 } 11027 heap[k] = v; 11028 }; 11029 11030 // Scan a literal or distance tree to determine the frequencies of the codes 11031 // in the bit length tree. 11032 function scan_tree(tree,// the tree to be scanned 11033 max_code // and its largest code of non zero frequency 11034 ) { 11035 var n; // iterates over all tree elements 11036 var prevlen = -1; // last emitted length 11037 var curlen; // length of current code 11038 var nextlen = tree[0 * 2 + 1]; // length of next code 11039 var count = 0; // repeat count of the current code 11040 var max_count = 7; // max repeat count 11041 var min_count = 4; // min repeat count 11042 11043 if (nextlen === 0) { 11044 max_count = 138; 11045 min_count = 3; 11046 } 11047 tree[(max_code + 1) * 2 + 1] = 0xffff; // guard 11048 11049 for (n = 0; n <= max_code; n++) { 11050 curlen = nextlen; 11051 nextlen = tree[(n + 1) * 2 + 1]; 11052 if (++count < max_count && curlen == nextlen) { 11053 continue; 11054 } else if (count < min_count) { 11055 bl_tree[curlen * 2] += count; 11056 } else if (curlen !== 0) { 11057 if (curlen != prevlen) 11058 bl_tree[curlen * 2]++; 11059 bl_tree[REP_3_6 * 2]++; 11060 } else if (count <= 10) { 11061 bl_tree[REPZ_3_10 * 2]++; 11062 } else { 11063 bl_tree[REPZ_11_138 * 2]++; 11064 } 11065 count = 0; 11066 prevlen = curlen; 11067 if (nextlen === 0) { 11068 max_count = 138; 11069 min_count = 3; 11070 } else if (curlen == nextlen) { 11071 max_count = 6; 11072 min_count = 3; 11073 } else { 11074 max_count = 7; 11075 min_count = 4; 11076 } 11077 } 11078 } 11079 11080 // Construct the Huffman tree for the bit lengths and return the index in 11081 // bl_order of the last bit length code to send. 11082 function build_bl_tree() { 11083 var max_blindex; // index of last bit length code of non zero freq 11084 11085 // Determine the bit length frequencies for literal and distance trees 11086 scan_tree(dyn_ltree, l_desc.max_code); 11087 scan_tree(dyn_dtree, d_desc.max_code); 11088 11089 // Build the bit length tree: 11090 bl_desc.build_tree(that); 11091 // opt_len now includes the length of the tree representations, except 11092 // the lengths of the bit lengths codes and the 5+5+4 bits for the 11093 // counts. 11094 11095 // Determine the number of bit length codes to send. The pkzip format 11096 // requires that at least 4 bit length codes be sent. (appnote.txt says 11097 // 3 but the actual value used is 4.) 11098 for (max_blindex = BL_CODES - 1; max_blindex >= 3; max_blindex--) { 11099 if (bl_tree[Tree.bl_order[max_blindex] * 2 + 1] !== 0) 11100 break; 11101 } 11102 // Update opt_len to include the bit length tree and counts 11103 that.opt_len += 3 * (max_blindex + 1) + 5 + 5 + 4; 11104 11105 return max_blindex; 11106 } 11107 11108 // Output a byte on the stream. 11109 // IN assertion: there is enough room in pending_buf. 11110 function put_byte(p) { 11111 that.pending_buf[that.pending++] = p; 11112 } 11113 11114 function put_short(w) { 11115 put_byte(w & 0xff); 11116 put_byte((w >>> 8) & 0xff); 11117 } 11118 11119 function putShortMSB(b) { 11120 put_byte((b >> 8) & 0xff); 11121 put_byte((b & 0xff) & 0xff); 11122 } 11123 11124 function send_bits(value, length) { 11125 var val, len = length; 11126 if (bi_valid > Buf_size - len) { 11127 val = value; 11128 // bi_buf |= (val << bi_valid); 11129 bi_buf |= ((val << bi_valid) & 0xffff); 11130 put_short(bi_buf); 11131 bi_buf = val >>> (Buf_size - bi_valid); 11132 bi_valid += len - Buf_size; 11133 } else { 11134 // bi_buf |= (value) << bi_valid; 11135 bi_buf |= (((value) << bi_valid) & 0xffff); 11136 bi_valid += len; 11137 } 11138 } 11139 11140 function send_code(c, tree) { 11141 var c2 = c * 2; 11142 send_bits(tree[c2] & 0xffff, tree[c2 + 1] & 0xffff); 11143 } 11144 11145 // Send a literal or distance tree in compressed form, using the codes in 11146 // bl_tree. 11147 function send_tree(tree,// the tree to be sent 11148 max_code // and its largest code of non zero frequency 11149 ) { 11150 var n; // iterates over all tree elements 11151 var prevlen = -1; // last emitted length 11152 var curlen; // length of current code 11153 var nextlen = tree[0 * 2 + 1]; // length of next code 11154 var count = 0; // repeat count of the current code 11155 var max_count = 7; // max repeat count 11156 var min_count = 4; // min repeat count 11157 11158 if (nextlen === 0) { 11159 max_count = 138; 11160 min_count = 3; 11161 } 11162 11163 for (n = 0; n <= max_code; n++) { 11164 curlen = nextlen; 11165 nextlen = tree[(n + 1) * 2 + 1]; 11166 if (++count < max_count && curlen == nextlen) { 11167 continue; 11168 } else if (count < min_count) { 11169 do { 11170 send_code(curlen, bl_tree); 11171 } while (--count !== 0); 11172 } else if (curlen !== 0) { 11173 if (curlen != prevlen) { 11174 send_code(curlen, bl_tree); 11175 count--; 11176 } 11177 send_code(REP_3_6, bl_tree); 11178 send_bits(count - 3, 2); 11179 } else if (count <= 10) { 11180 send_code(REPZ_3_10, bl_tree); 11181 send_bits(count - 3, 3); 11182 } else { 11183 send_code(REPZ_11_138, bl_tree); 11184 send_bits(count - 11, 7); 11185 } 11186 count = 0; 11187 prevlen = curlen; 11188 if (nextlen === 0) { 11189 max_count = 138; 11190 min_count = 3; 11191 } else if (curlen == nextlen) { 11192 max_count = 6; 11193 min_count = 3; 11194 } else { 11195 max_count = 7; 11196 min_count = 4; 11197 } 11198 } 11199 } 11200 11201 // Send the header for a block using dynamic Huffman trees: the counts, the 11202 // lengths of the bit length codes, the literal tree and the distance tree. 11203 // IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4. 11204 function send_all_trees(lcodes, dcodes, blcodes) { 11205 var rank; // index in bl_order 11206 11207 send_bits(lcodes - 257, 5); // not +255 as stated in appnote.txt 11208 send_bits(dcodes - 1, 5); 11209 send_bits(blcodes - 4, 4); // not -3 as stated in appnote.txt 11210 for (rank = 0; rank < blcodes; rank++) { 11211 send_bits(bl_tree[Tree.bl_order[rank] * 2 + 1], 3); 11212 } 11213 send_tree(dyn_ltree, lcodes - 1); // literal tree 11214 send_tree(dyn_dtree, dcodes - 1); // distance tree 11215 } 11216 11217 // Flush the bit buffer, keeping at most 7 bits in it. 11218 function bi_flush() { 11219 if (bi_valid == 16) { 11220 put_short(bi_buf); 11221 bi_buf = 0; 11222 bi_valid = 0; 11223 } else if (bi_valid >= 8) { 11224 put_byte(bi_buf & 0xff); 11225 bi_buf >>>= 8; 11226 bi_valid -= 8; 11227 } 11228 } 11229 11230 // Send one empty static block to give enough lookahead for inflate. 11231 // This takes 10 bits, of which 7 may remain in the bit buffer. 11232 // The current inflate code requires 9 bits of lookahead. If the 11233 // last two codes for the previous block (real code plus EOB) were coded 11234 // on 5 bits or less, inflate may have only 5+3 bits of lookahead to decode 11235 // the last real code. In this case we send two empty static blocks instead 11236 // of one. (There are no problems if the previous block
11236is stored or fixed.) 11237 // To simplify the code, we assume the worst case of last real code encoded 11238 // on one bit only. 11239 function _tr_align() { 11240 send_bits(STATIC_TREES << 1, 3); 11241 send_code(END_BLOCK, StaticTree.static_ltree); 11242 11243 bi_flush(); 11244 11245 // Of the 10 bits for the empty block, we have already sent 11246 // (10 - bi_valid) bits. The lookahead for the last real code (before 11247 // the EOB of the previous block) was thus at least one plus the length 11248 // of the EOB plus what we have just sent of the empty static block. 11249 if (1 + last_eob_len + 10 - bi_valid < 9) { 11250 send_bits(STATIC_TREES << 1, 3); 11251 send_code(END_BLOCK, StaticTree.static_ltree); 11252 bi_flush(); 11253 } 11254 last_eob_len = 7; 11255 } 11256 11257 // Save the match info and tally the frequency counts. Return true if 11258 // the current block must be flushed. 11259 function _tr_tally(dist, // distance of matched string 11260 lc // match length-MIN_MATCH or unmatched char (if dist==0) 11261 ) { 11262 var out_length, in_length, dcode; 11263 that.pending_buf[d_buf + last_lit * 2] = (dist >>> 8) & 0xff;
11264 that.pending_buf[d_buf + last_lit * 2 + 1] = dist & 0xff; 11265 11266 that.pending_buf[l_buf + last_lit] = lc & 0xff; 11267 last_lit++; 11268 11269 if (dist === 0) { 11270 // lc is the unmatched char 11271 dyn_ltree[lc * 2]++; 11272 } else { 11273 matches++; 11274 // Here, lc is the match length - MIN_MATCH 11275 dist--; // dist = match distance - 1 11276 dyn_ltree[(Tree._length_code[lc] + LITERALS + 1) * 2]++; 11277 dyn_dtree[Tree.d_code(dist) * 2]++; 11278 } 11279 11280 if ((last_lit & 0x1fff) === 0 && level > 2) { 11281 // Compute an upper bound for the compressed length 11282 out_length = last_lit * 8; 11283 in_length = strstart - block_start; 11284 for (dcode = 0; dcode < D_CODES; dcode++) { 11285 out_length += dyn_dtree[dcode * 2] * (5 + Tree.extra_dbits[dcode]); 11286 } 11287 out_length >>>= 3; 11288 if ((matches < Math.floor(last_lit / 2)) && out_length < Math.floor(in_length / 2)) 11289 return true; 11290 } 11291 11292 return (last_lit == lit_bufsize - 1); 11293 // We avoid equality with lit_bufsize because of wraparound at 64K 11294 // on 16 bit machines and because stored blocks are restricted to 11295 // 64K-1 bytes. 11296 } 11297 11298 // Send the block data compressed using the given Huffman trees 11299 function compress_block(ltree, dtree) { 11300 var dist; // distance of matched string 11301 var lc; // match length or unmatched char (if dist === 0) 11302 var lx = 0; // running index in l_buf 11303 var code; // the code to send 11304 var extra; // number of extra bits to send 11305 11306 if (last_lit !== 0) { 11307 do { 11308 dist = ((that.pending_buf[d_buf + lx * 2] << 8) & 0xff00) | (that.pending_buf[d_buf + lx * 2 + 1] & 0xff); 11309 lc = (that.pending_buf[l_buf + lx]) & 0xff; 11310 lx++; 11311 11312 if (dist === 0) { 11313 send_code(lc, ltree); // send a literal byte 11314 } else { 11315 // Here, lc is the match length - MIN_MATCH 11316 code = Tree._length_code[lc]; 11317 11318 send_code(code + LITERALS + 1, ltree); // send the length 11319 // code 11320 extra = Tree.extra_lbits[code]; 11321 if (extra !== 0) { 11322 lc -= Tree.base_length[code]; 11323 send_bits(lc, extra); // send the extra length bits 11324 } 11325 dist--; // dist is now the match distance - 1 11326 code = Tree.d_code(dist); 11327 11328 send_code(code, dtree); // send the distance code 11329 extra = Tree.extra_dbits[code]; 11330 if (extra !== 0) { 11331 dist -= Tree.base_dist[code]; 11332 send_bits(dist, extra); // send the extra distance bits 11333 } 11334 } // literal or match pair ? 11335 11336 // Check that the overlay between pending_buf and d_buf+l_buf is 11337 // ok: 11338 } while (lx < last_lit); 11339 } 11340 11341 send_code(END_BLOCK, ltree); 11342 last_eob_len = ltree[END_BLOCK * 2 + 1]; 11343 } 11344 11345 // Flush the bit buffer and align the output on a byte boundary 11346 function bi_windup() { 11347 if (bi_valid > 8) { 11348 put_short(bi_buf); 11349 } else if (bi_valid > 0) { 11350 put_byte(bi_buf & 0xff); 11351 } 11352 bi_buf = 0; 11353 bi_valid = 0; 11354 } 11355 11356 // Copy a stored block, storing first the length and its 11357 // one's complement if requested. 11358 function copy_block(buf, // the input data 11359 len, // its length 11360 header // true if block header must be written 11361 ) { 11362 bi_windup(); // align on byte boundary 11363 last_eob_len = 8; // enough lookahead for inflate 11364 11365 if (header) { 11366 put_short(len); 11367 put_short(~len); 11368 } 11369 11370 that.pending_buf.set(window.subarray(buf, buf + len), that.pending); 11371 that.pending += len; 11372 } 11373 11374 // Send a stored block 11375 function _tr_stored_block(buf, // input block 11376 stored_len, // length of input block 11377 eof // true if this is the last block for a file 11378 ) { 11379 send_bits((STORED_BLOCK << 1) + (eof ? 1 : 0), 3); // send block type 11380 copy_block(buf, stored_len, true); // with header 11381 } 11382 11383 // Determine the best encoding for the current block: dynamic trees, static 11384 // trees or store, and output the encoded block to the zip file. 11385 function _tr_flush_block(buf, // input block, or NULL if too old 11386 stored_len, // length of input block 11387 eof // true if this is the last block for a file 11388 ) { 11389 var opt_lenb, static_lenb;// opt_len and static_len in bytes 11390 var max_blindex = 0; // index of last bit length code of non zero freq 11391 11392 // Build the Huffman trees unless a stored block is forced 11393 if (level > 0) { 11394 // Construct the literal and distance trees 11395 l_desc.build_tree(that); 11396 11397 d_desc.build_tree(that); 11398 11399 // At this point, opt_len and static_len are the total bit lengths 11400 // of 11401 // the compressed block data, excluding the tree representations. 11402 11403 // Build the bit length tree for the above two trees, and get the 11404 // index 11405 // in bl_order of the last bit length code to send. 11406 max_blindex = build_bl_tree(); 11407 11408 // Determine the best encoding. Compute first the block length in 11409 // bytes 11410 opt_lenb = (that.opt_len + 3 + 7) >>> 3; 11411 static_lenb = (that.static_len + 3 + 7) >>> 3; 11412 11413 if (static_lenb <= opt_lenb) 11414 opt_lenb = static_lenb; 11415 } else { 11416 opt_lenb = static_lenb = stored_len + 5; // force a stored block 11417 } 11418
11419 if ((stored_len + 4 <= opt_lenb) && buf != -1) { 11420 // 4: two words for the lengths 11421 // The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE. 11422 // Otherwise we can't have processed more than WSIZE input bytes 11423 // since 11424 // the last block flush, because compression would have been 11425 // successful. If LIT_BUFSIZE <= WSIZE, it is never too late to 11426 // transform a block into a stored block. 11427 _tr_stored_block(buf, stored_len, eof); 11428 } else if (static_lenb == opt_lenb) { 11429 send_bits((STATIC_TREES << 1) + (eof ? 1 : 0), 3); 11430 compress_block(StaticTree.static_ltree, StaticTree.static_dtree); 11431 } else { 11432 send_bits((DYN_TREES << 1) + (eof ? 1 : 0), 3); 11433 send_all_trees(l_desc.max_code + 1, d_desc.max_code + 1, max_blindex + 1); 11434 compress_block(dyn_ltree, dyn_dtree); 11435 } 11436 11437 // The above check is made mod 2^32, for files larger than 512 MB 11438 // and uLong implemented on 32 bits. 11439 11440 init_block(); 11441 11442 if (eof) { 11443 bi_windup(); 11444 } 11445 } 11446 11447 function flush_block_only(eof) { 11448 _tr_flush_block(block_start >= 0 ? block_start : -1, strstart - block_start, eof); 11449 block_start = strstart; 11450 strm.flush_pending(); 11451 } 11452 11453 // Fill the window when the lookahead becomes insufficient. 11454 // Updates strstart and lookahead. 11455 // 11456 // IN assertion: lookahead < MIN_LOOKAHEAD 11457 // OUT assertions: strstart <= window_size-MIN_LOOKAHEAD 11458 // At least one byte has been read, or avail_in === 0; reads are 11459 // performed for at least two bytes (required for the zip translate_eol 11460 // option -- not supported here). 11461 function fill_window() { 11462 var n, m; 11463 var p; 11464 var more; // Amount of free space at the end of the window. 11465 11466 do { 11467 more = (window_size - lookahead - strstart); 11468 11469 // Deal with !@#$% 64K limit: 11470 if (more === 0 && strstart === 0 && lookahead === 0) { 11471 more = w_size; 11472 } else if (more == -1) { 11473 // Very unlikely, but possible on 16 bit machine if strstart == 11474 // 0 11475 // and lookahead == 1 (input done one byte at time) 11476 more--; 11477 11478 // If the window is almost full and there is insufficient 11479 // lookahead, 11480 // move the upper half to the lower one to make room in the 11481 // upper half. 11482 } else if (strstart >= w_size + w_size - MIN_LOOKAHEAD) { 11483 window.set(window.subarray(w_size, w_size + w_size), 0); 11484 11485 match_start -= w_size; 11486 strstart -= w_size; // we now have strstart >= MAX_DIST 11487 block_start -= w_size; 11488 11489 // Slide the hash table (could be avoided with 32 bit values 11490 // at the expense of memory usage). We slide even when level == 11491 // 0 11492 // to keep the hash table consistent if we switch back to level 11493 // > 0 11494 // later. (Using level 0 permanently is not an optimal usage of 11495 // zlib, so we don't care about this pathological case.) 11496 11497 n = hash_size; 11498 p = n; 11499 do { 11500 m = (head[--p] & 0xffff); 11501 head[p] = (m >= w_size ? m - w_size : 0); 11502 } while (--n !== 0); 11503 11504 n = w_size; 11505 p = n; 11506 do { 11507 m = (prev[--p] & 0xffff); 11508 prev[p] = (m >= w_size ? m - w_size : 0); 11509 // If n is not on any hash chain, prev[n] is garbage but 11510 // its value will never be used. 11511 } while (--n !== 0); 11512 more += w_size; 11513 } 11514 11515 if (strm.avail_in === 0) 11516 return; 11517 11518 // If there was no sliding: 11519 // strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 && 11520 // more == window_size - lookahead - strstart 11521 // => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1) 11522 // => more >= window_size - 2*WSIZE + 2 11523 // In the BIG_MEM or MMAP case (not yet supported), 11524 // window_size == input_size + MIN_LOOKAHEAD && 11525 // strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD. 11526 // Otherwise, window_size == 2*WSIZE so more >= 2. 11527 // If there was sliding, more >= WSIZE. So in all cases, more >= 2. 11528 11529 n = strm.read_buf(window, strstart + lookahead, more); 11530 lookahead += n; 11531 11532 // Initialize the hash value now that we have some input
11532: 11533 if (lookahead >= MIN_MATCH) { 11534 ins_h = window[strstart] & 0xff; 11535 ins_h = (((ins_h) << hash_shift) ^ (window[strstart + 1] & 0xff)) & hash_mask; 11536 } 11537 // If the whole input has less than MIN_MATCH bytes, ins_h is 11538 // garbage, 11539 // but this is not important since only literal bytes will be 11540 // emitted. 11541 } while (lookahead < MIN_LOOKAHEAD && strm.avail_in !== 0); 11542 } 11543 11544 // Copy without compression as much as possible from the input stream, 11545 // return 11546 // the current block state. 11547 // This function does not insert new strings in the dictionary since 11548 // uncompressible data is probably not useful. This function is used 11549 // only for the level=0 compression option. 11550 // NOTE: this function should be optimized to avoid extra copying from 11551 // window to pending_buf. 11552 function deflate_stored(flush) { 11553 // Stored blocks are limited to 0xffff bytes, pending_buf is limited 11554 // to pending_buf_size, and each stored block has a 5 byte header: 11555 11556 var max_block_size = 0xffff; 11557 var max_start; 11558 11559 if (max_block_size > pending_buf_size - 5) { 11560 max_block_size = pending_buf_size - 5; 11561 } 11562 11563 // Copy as much as possible from input to output: 11564 while (true) { 11565 // Fill the window as much as possible: 11566 if (lookahead <= 1) { 11567 fill_window(); 11568 if (lookahead === 0 && flush == Z_NO_FLUSH) 11569 return NeedMore; 11570 if (lookahead === 0) 11571 break; // flush the current block 11572 } 11573 11574 strstart += lookahead; 11575 lookahead = 0; 11576 11577 // Emit a stored block if pending_buf will be full: 11578 max_start = block_start + max_block_size; 11579 if (strstart === 0 || strstart >= max_start) { 11580 // strstart === 0 is possible when wraparound on 16-bit machine 11581 lookahead = (strstart - max_start); 11582 strstart = max_start; 11583 11584 flush_block_only(false); 11585 if (strm.avail_out === 0) 11586 return NeedMore; 11587 11588 } 11589 11590 // Flush if we may have to slide, otherwise block_start may become 11591 // negative and the data will be gone: 11592 if (strstart - block_start >= w_size - MIN_LOOKAHEAD) { 11593 flush_block_only(false); 11594 if (strm.avail_out === 0) 11595 return NeedMore; 11596 } 11597 } 11598 11599 flush_block_only(flush == Z_FINISH); 11600 if (strm.avail_out === 0) 11601 return (flush == Z_FINISH) ? FinishStarted : NeedMore; 11602 11603 return flush == Z_FINISH ? FinishDone : BlockDone; 11604 } 11605 11606 function longest_match(cur_match) { 11607 var chain_length = max_chain_length; // max hash chain length 11608 var scan = strstart; // current string 11609 var match; // matched string 11610 var len; // length of current match 11611 var best_len = prev_length; // best match length so far 11612 var limit = strstart > (w_size - MIN_LOOKAHEAD) ? strstart - (w_size - MIN_LOOKAHEAD) : 0; 11613 var _nice_match = nice_match; 11614 11615 // Stop when cur_match becomes <= limit. To simplify the code, 11616 // we prevent matches with the string of window index 0. 11617 11618 var wmask = w_mask; 11619 11620 var strend = strstart + MAX_MATCH; 11621 var scan_end1 = window[scan + best_len - 1]; 11622 var scan_end = window[scan + best_len]; 11623 11624 // The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 11625 // 16. 11626 // It is easy to get rid of this optimization if necessary. 11627
11628 // Do not waste too much time if we already have a good match: 11629 if (prev_length >= good_match) { 11630 chain_length >>= 2; 11631 } 11632 11633 // Do not look for matches beyond the end of the input. This is 11634 // necessary 11635 // to make deflate deterministic. 11636 if (_nice_match > lookahead) 11637 _nice_match = lookahead; 11638 11639 do { 11640 match = cur_match; 11641 11642 // Skip to next match if the match length cannot increase 11643 // or if the match length is less than 2: 11644 if (window[match + best_len] != scan_end || window[match + best_len - 1] != scan_end1 || window[match] != window[scan] 11645 || window[++match] != window[scan + 1]) 11646 continue; 11647 11648 // The check at best_len-1 can be removed because it will be made 11649 // again later. (This heuristic is not always a win.) 11650 // It is not necessary to compare scan[2] and match[2] since they 11651 // are always equal when the other bytes match, given that 11652 // the hash keys are equal and that HASH_BITS >= 8. 11653 scan += 2; 11654 match++; 11655 11656 // We check for insufficient lookahead only every 8th comparison; 11657 // the 256th check will be made at strstart+258. 11658 do { 11659 } while (window[++scan] == window[++match] && window[++scan] == window[++match] && window[++scan] == window[++match] 11660 && window[++scan] == window[++match] && window[++scan] == window[++match] && window[++scan] == window[++match] 11661 && window[++scan] == window[++match] && window[++scan] == window[++match] && scan < strend); 11662 11663 len = MAX_MATCH - (strend - scan); 11664 scan = strend - MAX_MATCH; 11665 11666 if (len > best_len) { 11667 match_start = cur_match; 11668 best_len = len; 11669 if (len >= _nice_match) 11670 break; 11671 scan_end1 = window[scan + best_len - 1]; 11672 scan_end = window[scan + best_len]; 11673 } 11674 11675 } while ((cur_match = (prev[cur_match & wmask] & 0xffff)) > limit && --chain_length !== 0); 11676 11677 if (best_len <= lookahead) 11678 return best_len; 11679 return lookahead; 11680 } 11681 11682 // Compress as much as possible from the input stream, return the current 11683 // block state. 11684 // This function does not perform lazy evaluation of matches and inserts 11685 // new strings in the dictionary only for unmatched strings or for short 11686 // matches. It is used only for the fast compression options. 11687 function deflate_fast(flush) { 11688 // short hash_head = 0; // head of the hash chain 11689 var hash_head = 0; // head of the hash chain 11690 var bflush; // set if current block must be flushed 11691 11692 while (true) { 11693 // Make sure that we always have enough lookahead, except 11694 // at the end of the input file. We need MAX_MATCH bytes 11695 // for the next match, plus MIN_MATCH bytes to insert the 11696 // string following the next match. 11697 if (lookahead < MIN_LOOKAHEAD) { 11698 fill_window(); 11699 if (lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) { 11700 return NeedMore; 11701 } 11702 if (lookahead === 0) 11703 break; // flush the current block 11704 } 11705 11706 // Insert the string window[strstart .. strstart+2] in the 11707 // dictionary, and set hash_head to the head of the hash chain: 11708 if (lookahead >= MIN_MATCH) { 11709 ins_h = (((ins_h) << hash_shift) ^ (window[(strstart) + (MIN_MATCH - 1)] & 0xff)) & hash_mask; 11710
11711 // prev[strstart&w_mask]=hash_head=head[ins_h]; 11712 hash_head = (head[ins_h] & 0xffff); 11713 prev[strstart & w_mask] = head[ins_h]; 11714 head[ins_h] = strstart; 11715 } 11716 11717 // Find the longest match, discarding those <= prev_length. 11718 // At this point we have always match_length < MIN_MATCH 11719 11720 if (hash_head !== 0 && ((strstart - hash_head) & 0xffff) <= w_size - MIN_LOOKAHEAD) { 11721 // To simplify the code, we prevent matches with the string 11722 // of window index 0 (in particular we have to avoid a match 11723 // of the string with itself at the start of the input file). 11724 if (strategy != Z_HUFFMAN_ONLY) { 11725 match_length = longest_match(hash_head); 11726 } 11727 // longest_match() sets match_start 11728 } 11729 if (match_length >= MIN_MATCH) { 11730 // check_match(strstart, match_start, match_length); 11731 11732 bflush = _tr_tally(strstart - match_start, match_length - MIN_MATCH); 11733 11734 lookahead -= match_length; 11735 11736 // Insert new strings in the hash table only if the match length 11737 // is not too large. This saves time but degrades compression. 11738 if (match_length <= max_lazy_match && lookahead >= MIN_MATCH) { 11739 match_length--; // string at strstart already in hash table 11740 do { 11741 strstart++; 11742 11743 ins_h = ((ins_h << hash_shift) ^ (window[(strstart) + (MIN_MATCH - 1)] & 0xff)) & hash_mask; 11744 // prev[strstart&w_mask]=hash_head=head[ins_h]; 11745 hash_head = (head[ins_h] & 0xffff); 11746 prev[strstart & w_mask] = head[ins_h]; 11747 head[ins_h] = strstart; 11748 11749 // strstart never exceeds WSIZE-MAX_MATCH, so there are 11750 // always MIN_MATCH bytes ahead. 11751 } while (--match_length !== 0); 11752 strstart++; 11753 } else { 11754 strstart += match_length; 11755 match_length = 0; 11756 ins_h = window[strstart] & 0xff; 11757 11758 ins_h = (((ins_h) << hash_shift) ^ (window[strstart + 1] & 0xff)) & hash_mask; 11759 // If lookahead < MIN_MATCH, ins_h is garbage, but it does 11760 // not 11761 // matter since it will be recomputed at next deflate call. 11762 } 11763 } else { 11764 // No match, output a literal byte 11765 11766 bflush = _tr_tally(0, window[strstart] & 0xff); 11767 lookahead--; 11768 strstart++; 11769 } 11770 if (bflush) { 11771 11772 flush_block_only(false); 11773 if (strm.avail_out === 0) 11774 return NeedMore; 11775 } 11776 } 11777 11778 flush_block_only(flush == Z_FINISH); 11779 if (strm.avail_out === 0) { 11780 if (flush == Z_FINISH) 11781 return FinishStarted; 11782 else 11783 return NeedMore; 11784 } 11785 return flush == Z_FINISH ? FinishDone : BlockDone; 11786 } 11787 11788 // Same as above, but achieves better compression. We use a lazy 11789 // evaluation for matches: a match is finally adopted only if there is 11790 // no better match at the next window position. 11791 function deflate_slow(flush) { 11792 // short hash_head = 0; // head of hash chain 11793 var hash_head = 0; // head of hash chain 11794 var bflush; // set if current block must be flushed 11795 var max_insert; 11796 11797 // Process the input block. 11798 while (true) { 11799 // Make sure that we always have enough lookahead, except 11800 // at the end of the input file. We need MAX_MATCH bytes 11801 // for the next match, plus MIN_MATCH bytes to insert the 11802 // string following the next match. 11803 11804 if (lookahead < MIN_LOOKAHEAD) { 11805 fill_window(); 11806 if (lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) { 11807 return NeedMore; 11808 } 11809 if (lookahead === 0) 11810 break; // flush the current block 11811 } 11812 11813 // Insert the string window[strstart .. strstart+2] in the 11814 // dictionary, and set hash_head to the head of the hash chain: 11815 11816 if (lookahead >= MIN_MATCH) { 11817 ins_h = (((ins_h) << hash_shift) ^ (window[(strstart) + (MIN_MATCH - 1)] & 0xff)) & hash_mask;
11818 // prev[strstart&w_mask]=hash_head=head[ins_h]; 11819 hash_head = (head[ins_h] & 0xffff); 11820 prev[strstart & w_mask] = head[ins_h]; 11821 head[ins_h] = strstart; 11822 } 11823 11824 // Find the longest match, discarding those <= prev_length. 11825 prev_length = match_length; 11826 prev_match = match_start; 11827 match_length = MIN_MATCH - 1; 11828 11829 if (hash_head !== 0 && prev_length < max_lazy_match && ((strstart - hash_head) & 0xffff) <= w_size - MIN_LOOKAHEAD) { 11830 // To simplify the code, we prevent matches with the string 11831 // of window index 0 (in particular we have to avoid a match 11832 // of the string with itself at the start of the input file). 11833 11834 if (strategy != Z_HUFFMAN_ONLY) { 11835 match_length = longest_match(hash_head); 11836 } 11837 // longest_match() sets match_start 11838 11839 if (match_length <= 5 && (strategy == Z_FILTERED || (match_length == MIN_MATCH && strstart - match_start > 4096))) { 11840 11841 // If prev_match is also MIN_MATCH, match_start is garbage 11842 // but we will ignore the current match anyway. 11843 match_length = MIN_MATCH - 1; 11844 } 11845 } 11846 11847 // If there was a match at the previous step and the current 11848 // match is not better, output the previous match: 11849 if (prev_length >= MIN_MATCH && match_length <= prev_length) { 11850 max_insert = strstart + lookahead - MIN_MATCH; 11851 // Do not insert strings in hash table beyond this. 11852 11853 // check_match(strstart-1, prev_match, prev_length); 11854 11855 bflush = _tr_tally(strstart - 1 - prev_match, prev_length - MIN_MATCH); 11856 11857 // Insert in hash table all strings up to the end of the match. 11858 // strstart-1 and strstart are already inserted. If there is not 11859 // enough lookahead, the last two strings are not inserted in 11860 // the hash table. 11861 lookahead -= prev_length - 1; 11862 prev_length -= 2; 11863 do { 11864 if (++strstart <= max_insert) { 11865 ins_h = (((ins_h) << hash_shift) ^ (window[(strstart) + (MIN_MATCH - 1)] & 0xff)) & hash_mask; 11866 // prev[strstart&w_mask]=hash_head=head[ins_h]; 11867 hash_head = (head[ins_h] & 0xffff); 11868 prev[strstart & w_mask] = head[ins_h]; 11869 head[ins_h] = strstart; 11870 } 11871 } while (--prev_length !== 0); 11872 match_available = 0; 11873 match_length = MIN_MATCH - 1; 11874 strstart++; 11875 11876 if (bflush) { 11877 flush_block_only(false); 11878 if (strm.avail_out === 0) 11879 return NeedMore; 11880 } 11881 } else if (match_available !== 0) { 11882 11883 // If there was no match at the previous position, output a 11884 // single literal. If there was a match but the current match 11885 // is longer, truncate the previous match to a single literal. 11886 11887 bflush = _tr_tally(0, window[strstart - 1] & 0xff); 11888 11889 if (bflush) { 11890 flush_block_only(false); 11891 } 11892 strstart++; 11893 lookahead--; 11894 if (strm.avail_out === 0) 11895 return NeedMore; 11896 } else { 11897 // There is no previous match to compare with, wait for 11898 // the next step to decide. 11899 11900 match_available = 1; 11901 strstart++; 11902 lookahead--; 11903 } 11904 } 11905 11906 if (match_available !== 0) { 11907 bflush = _tr_tally(0, window[strstart - 1] & 0xff); 11908 match_available = 0; 11909 } 11910 flush_block_only(flush == Z_FINISH); 11911 11912 if (strm.avail_out === 0) { 11913 if (flush == Z_FINISH) 11914 return FinishStarted; 11915 else 11916 return NeedMore; 11917 } 11918 11919 return flush == Z_FINISH ? FinishDone : BlockDone; 11920 } 11921 11922 function deflateReset(strm) { 11923 strm.total_in = strm.total_out = 0; 11924 strm.msg = null; // 11925 11926 that.pending = 0; 11927 that.pending_out = 0; 11928 11929 status = BUSY_STATE; 11930 11931 last_flush = Z_NO_FLUSH; 11932 11933 tr_init(); 11934 lm_init(); 11935 return Z_OK; 11936 } 11937 11938 that.deflateInit = function(strm, _level, bits, _method, memLevel, _strategy) { 11939 if (!_method) 11940 _method = Z_DEFLATED; 11941 if (!memLevel) 11942 memLevel = DEF_MEM_LEVEL; 11943 if (!_strategy) 11944 _strategy = Z_DEFAULT_STRATEGY; 11945 11946 // byte[] my_version=ZLIB_VERSION; 11947 11948 // 11949 // if (!version || version[0] != my_version[0] 11950 // || stream_size != sizeof(z_stream)) { 11951 // return Z_VERSION_ERROR; 11952 // } 11953 11954 strm.msg = null; 11955 11956 if (_level == Z_DEFAULT_COMPRESSION) 11957 _level = 6; 11958 11959 if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || _method != Z_DEFLATED || bits < 9 || bits > 15 || _level < 0 || _level > 9 || _strategy < 0 11960 || _strategy > Z_HUFFMAN_ONLY) { 11961 return Z_STREAM_ERROR; 11962 } 11963 11964 strm.dstate = that; 11965 11966 w_bits = bits; 11967 w_size = 1 << w_bits; 11968 w_mask = w_size - 1; 11969 11970 hash_bits = memLevel + 7; 11971 hash_size = 1 << hash_bits; 11972 hash_mask = hash_size - 1; 11973 hash_shift = Math.floor((hash_bits + MIN_MATCH - 1) / MIN_MATCH); 11974 11975 window = new Uint8Array(w_size * 2); 11976 prev = []; 11977 head = []; 11978 11979 lit_bufsize = 1 << (memLevel + 6); // 16K elements by default 11980 11981 // We overlay pending_buf and d_buf+l_buf. This works since the average 11982 // output size for (length,distance) codes is <= 24 bits. 11983 that.pending_buf = new Uint8Array(lit_bufsize * 4); 11984 pending_buf_size = lit_bufsize * 4; 11985 11986 d_buf = Math.floor(lit_bufsize / 2); 11987 l_buf = (1 + 2) * lit_bufsize; 11988 11989 level = _level; 11990 11991 strategy = _strategy; 11992 method = _method & 0xff;
11993 11994 return deflateReset(strm); 11995 }; 11996 11997 that.deflateEnd = function() { 11998 if (status != INIT_STATE && status != BUSY_STATE && status != FINISH_STATE) { 11999 return Z_STREAM_ERROR; 12000 } 12001 // Deallocate in reverse order of allocations: 12002 that.pending_buf = null; 12003 head = null; 12004 prev = null; 12005 window = null; 12006 // free 12007 that.dstate = null; 12008 return status == BUSY_STATE ? Z_DATA_ERROR : Z_OK; 12009 }; 12010 12011 that.deflateParams = function(strm, _level, _strategy) { 12012 var err = Z_OK; 12013 12014 if (_level == Z_DEFAULT_COMPRESSION) { 12015 _level = 6; 12016 } 12017 if (_level < 0 || _level > 9 || _strategy < 0 || _strategy > Z_HUFFMAN_ONLY) { 12018 return Z_STREAM_ERROR; 12019 } 12020 12021 if (config_table[level].func != config_table[_level].func && strm.total_in !== 0) { 12022 // Flush the last buffer: 12023 err = strm.deflate(Z_PARTIAL_FLUSH); 12024 } 12025 12026 if (level != _level) { 12027 level = _level; 12028 max_lazy_match = config_table[level].max_lazy; 12029 good_match = config_table[level].good_length; 12030 nice_match = config_table[level].nice_length; 12031 max_chain_length = config_table[level].max_chain; 12032 } 12033 strategy = _strategy; 12034 return err; 12035 }; 12036 12037 that.deflateSetDictionary = function(strm, dictionary, dictLength) { 12038 var length = dictLength; 12039 var n, index = 0; 12040 12041 if (!dictionary || status != INIT_STATE) 12042 return Z_STREAM_ERROR; 12043 12044 if (length < MIN_MATCH) 12045 return Z_OK; 12046 if (length > w_size - MIN_LOOKAHEAD) { 12047 length = w_size - MIN_LOOKAHEAD; 12048 index = dictLength - length; // use the tail of the dictionary 12049 } 12050 window.set(dictionary.subarray(index, index + length), 0); 12051 12052 strstart = length; 12053 block_start = length; 12054 12055 // Insert all strings in the hash table (except for the last two bytes). 12056 // s->lookahead stays null, so s->ins_h will be recomputed at the next 12057 // call of fill_window. 12058 12059 ins_h = window[0] & 0xff; 12060 ins_h = (((ins_h) << hash_shift) ^ (window[1] & 0xff)) & hash_mask; 12061 12062 for (n = 0; n <= length - MIN_MATCH; n++) { 12063 ins_h = (((ins_h) << hash_shift) ^ (window[(n) + (MIN_MATCH - 1)] & 0xff)) & hash_mask; 12064 prev[n & w_mask] = head[ins_h]; 12065 head[ins_h] = n; 12066 } 12067 return Z_OK; 12068 }; 12069 12070 that.deflate = function(_strm, flush) { 12071 var i, header, level_flags, old_flush, bstate; 12072 12073 if (flush > Z_FINISH || flush < 0) { 12074 return Z_STREAM_ERROR; 12075 } 12076 12077 if (!_strm.next_out || (!_strm.next_in && _strm.avail_in !== 0) || (status == FINISH_STATE && flush != Z_FINISH)) { 12078 _strm.msg = z_errmsg[Z_NEED_DICT - (Z_STREAM_ERROR)]; 12079 return Z_STREAM_ERROR; 12080 } 12081 if (_strm.avail_out === 0) { 12082 _strm.msg = z_errmsg[Z_NEED_DICT - (Z_BUF_ERROR)]; 12083 return Z_BUF_ERROR; 12084 } 12085 12086 strm = _strm; // just in case 12087 old_flush = last_flush; 12088 last_flush = flush; 12089 12090 // Write the zlib header 12091 if (status == INIT_STATE) { 12092 header = (Z_DEFLATED + ((w_bits - 8) << 4)) << 8; 12093 level_flags = ((level - 1) & 0xff) >> 1; 12094 12095 if (level_flags > 3) 12096 level_flags = 3; 12097 header |= (level_flags << 6); 12098 if (strstart !== 0) 12099 header |= PRESET_DICT; 12100 header += 31 - (header % 31); 12101 12102 status = BUSY_STATE; 12103 putShortMSB(header); 12104 } 12105 12106 // Flush as much pending output as possible 12107 if (that.pending !== 0) { 12108 strm.flush_pending(); 12109 if (strm.avail_out === 0) { 12110 // console.log(" avail_out==0"); 12111 // Since avail_out is 0, deflate will be called again with 12112 // more output space, but possibly with both pending and 12113 // avail_in equal to zero. There won't be anything to do, 12114 // but this is not an error situation so make sure we 12115 // return OK instead of BUF_ERROR at next call of deflate: 12116 last_flush = -1; 12117 return Z_OK; 12118 } 12119 12120 // Make sure there is something to do and avoid duplicate 12121 // consecutive 12122 // flushes. For repeated and useless calls with Z_FINISH, we keep 12123 // returning Z_STREAM_END instead of Z_BUFF_ERROR. 12124 } else if (strm.avail_in === 0 && flush <= old_flush && flush != Z_FINISH) { 12125 strm.msg = z_errmsg[Z_NEED_DICT - (Z_BUF_ERROR)];
12126 return Z_BUF_ERROR; 12127 } 12128 12129 // User must not provide more input after the first FINISH: 12130 if (status == FINISH_STATE && strm.avail_in !== 0) { 12131 _strm.msg = z_errmsg[Z_NEED_DICT - (Z_BUF_ERROR)]; 12132 return Z_BUF_ERROR; 12133 } 12134 12135 // Start a new block or continue the current one. 12136 if (strm.avail_in !== 0 || lookahead !== 0 || (flush != Z_NO_FLUSH && status != FINISH_STATE)) { 12137 bstate = -1; 12138 switch (config_table[level].func) { 12139 case STORED: 12140 bstate = deflate_stored(flush); 12141 break; 12142 case FAST: 12143 bstate = deflate_fast(flush); 12144 break; 12145 case SLOW: 12146 bstate = deflate_slow(flush); 12147 break; 12148 default: 12149 } 12150 12151 if (bstate == FinishStarted || bstate == FinishDone) { 12152 status = FINISH_STATE; 12153 } 12154 if (bstate == NeedMore || bstate == FinishStarted) { 12155 if (strm.avail_out === 0) { 12156 last_flush = -1; // avoid BUF_ERROR next call, see above 12157 } 12158 return Z_OK; 12159 // If flush != Z_NO_FLUSH && avail_out === 0, the next call 12160 // of deflate should use the same flush parameter to make sure 12161 // that the flush is complete. So we don't have to output an 12162 // empty block here, this will be done at next call. This also 12163 // ensures that for a very small output buffer, we emit at most 12164 // one empty block. 12165 } 12166 12167 if (bstate == BlockDone) { 12168 if (flush == Z_PARTIAL_FLUSH) { 12169 _tr_align(); 12170 } else { // FULL_FLUSH or SYNC_FLUSH 12171 _tr_stored_block(0, 0, false); 12172 // For a full flush, this empty block will be recognized 12173 // as a special marker by inflate_sync(). 12174 if (flush == Z_FULL_FLUSH) { 12175 // state.head[s.hash_size-1]=0; 12176 for (i = 0; i < hash_size/*-1*/; i++) 12177 // forget history 12178 head[i] = 0; 12179 } 12180 } 12181 strm.flush_pending(); 12182 if (strm.avail_out === 0) { 12183 last_flush = -1; // avoid BUF_ERROR at next call, see above 12184 return Z_OK; 12185 } 12186 } 12187 } 12188 12189 if (flush != Z_FINISH) 12190 return Z_OK; 12191 return Z_STREAM_END; 12192 }; 12193 } 12194 12195 // ZStream 12196 12197 function ZStream() { 12198 var that = this; 12199 that.next_in_index = 0; 12200 that.next_out_index = 0; 12201 // that.next_in; // next input byte 12202 that.avail_in = 0; // number of bytes available at next_in 12203 that.total_in = 0; // total nb of input bytes read so far 12204 // that.next_out; // next output byte should be put there 12205 that.avail_out = 0; // remaining free space at next_out 12206 that.total_out = 0; // total nb of bytes output so far 12207 // that.msg; 12208 // that.dstate; 12209 } 12210 12211 ZStream.prototype = { 12212 deflateInit : function(level, bits) { 12213 var that = this; 12214 that.dstate = new Deflate(); 12215 if (!bits) 12216 bits = MAX_BITS; 12217 return that.dstate.deflateInit(that, level, bits); 12218 }, 12219 12220 deflate : function(flush) { 12221 var that = this; 12222 if (!that.dstate) { 12223 return Z_STREAM_ERROR; 12224 } 12225 return that.dstate.deflate(that, flush); 12226 }, 12227 12228 deflateEnd : function() { 12229 var that = this; 12230 if (!that.dstate) 12231 return Z_STREAM_ERROR; 12232 var ret = that.dstate.deflateEnd(); 12233 that.dstate = null; 12234 return ret; 12235 }, 12236 12237 deflateParams : function(level, strategy) { 12238 var that = this; 12239 if (!that.dstate) 12240 return Z_STREAM_ERROR; 12241 return that.dstate.deflateParams(that, level, strategy); 12242 }, 12243 12244 deflateSetDictionary : function(dictionary, dictLength) { 12245 var that = this; 12246 if (!that.dstate) 12247 return Z_STREAM_ERROR; 12248 return that.dstate.deflateSetDictionary(that, dictionary, dictLength); 12249 }, 12250 12251 // Read a new buffer from the current input stream, update the 12252 // total number of bytes read. All deflate() input goes through 12253 // this function so some applications may wish to modify it to avoid 12254 // allocating a large strm->next_in buffer and copying from it. 12255 // (See also flush_pending()). 12256 read_buf : function(buf, start, size) { 12257 var that = this; 12258 var len = that.avail_in; 12259 if (len > size) 12260 len = size; 12261 if (len === 0) 12262 return 0; 12263 that.avail_in -= len; 12264 buf.set(that.next_in.subarray(that.next_in_index, that.next_in_index + len), start); 12265 that.next_in_index += len; 12266 that.total_in += len; 12267 return len; 12268 }, 12269 12270 // Flush as much pending output as possible. All deflate() output goes 12271 // through this function so some applications may wish to modify it 12272 // to avoid allocating a large strm->next_out buffer and copying into it. 12273 // (See also read_buf()). 12274 flush_pending : function() { 12275 var that = this; 12276 var len = that.dstate.pending; 12277 12278 if (len > that.avail_out) 12279 len = that.avail_out; 12280 if (len === 0) 12281 return; 12282 12283 // if (that.dstate.pending_buf.length <= that.dstate.pending_out || that.next_out.length <= that.next_out_index 12284 // || that.dstate.pending_buf.length < (that.dstate.pending_out + len) || that.next_out.length < (that.next_out_index + 12285 // len)) { 12286 // console.log(that.dstate.pending_buf.length + ", " + that.dstate.pending_out + ", " + that.next_out.length + ", " + 12287 // that.next_out_index + ", " + len); 12288 // console.log("avail_out=" + that.avail_out); 12289 // } 12290 12291 that.next_out.set(that.dstate.pending_buf.subarray(that.dstate.pending_out, that.dstate.pending_out + len), that.next_out_index); 12292 12293 that.next_out_index += len; 12294 that.dstate.pending_out += len; 12295 that.total_out += len; 12296 that.avail_out -= len; 12297 that.dstate.pending -= len; 12298 if (that.dstate.pending === 0) { 12299 that.dstate.pending_out = 0; 12300 } 12301 } 12302 }; 12303 12304 // Deflater 12305 12306 return function Deflater(level) { 12307 var that = this; 12308 var z = new ZStream(); 12309 var bufsize = 512; 12310 var flush = Z_NO_FLUSH; 12311 var buf = new Uint8Array(bufsize); 12312 12313 if (typeof level == "undefined") 12314 level = Z_DEFAULT_COMPRESSION; 12315 z.deflateInit(level); 12316 z.next_out = buf; 12317 12318 that.append = function(data, onprogress) { 12319 var err, buffers = [], lastIndex = 0, bufferIndex = 0, bufferSize = 0, array; 12320 if (!data.length) 12321 return; 12322 z.next_in_index = 0; 12323 z.next_in = data; 12324 z.avail_in = data.length; 12325 do { 12326 z.next_out_index = 0; 12327 z.avail_out = bufsize; 12328 err = z.deflate(flush); 12329 if (err != Z_OK) 12330 throw "deflating: " + z.msg; 12331 if (z.next_out_index) 12332 if (z.next_out_index == bufsize) 12333 buffers.push(new Uint8Array(buf)); 12334 else 12335 buffers.push(new Uint8Array(buf.subarray(0, z.next_out_index))); 12336 bufferSize += z.next_out_index; 12337 if (onprogress && z.next_in_index > 0 && z.next_in_index != lastIndex) { 12338 onprogress(z.next_in_index); 12339 lastIndex = z.next_in_index; 12340 } 12341 } while (z.avail_in > 0 || z.avail_out === 0); 12342 array = new Uint8Array(bufferSize);
12343 buffers.forEach(function(chunk) { 12344 array.set(chunk, bufferIndex); 12345 bufferIndex += chunk.length; 12346 }); 12347 return array; 12348 }; 12349 that.flush = function() { 12350 var err, buffers = [], bufferIndex = 0, bufferSize = 0, array; 12351 do { 12352 z.next_out_index = 0; 12353 z.avail_out = bufsize; 12354 err = z.deflate(Z_FINISH); 12355 if (err != Z_STREAM_END && err != Z_OK) 12356 throw "deflating: " + z.msg; 12357 if (bufsize - z.avail_out > 0) 12358 buffers.push(new Uint8Array(buf.subarray(0, z.next_out_index))); 12359 bufferSize += z.next_out_index; 12360 } while (z.avail_in > 0 || z.avail_out === 0); 12361 z.deflateEnd(); 12362 array = new Uint8Array(bufferSize); 12363 buffers.forEach(function(chunk) { 12364 array.set(chunk, bufferIndex); 12365 bufferIndex += chunk.length; 12366 }); 12367 return array; 12368 }; 12369 }; 12370 })(undefined); 12371 12372 12373 /* 12374 html2canvas 0.5.0-beta3 <http://html2canvas.hertzen.com> 12375 Copyright (c) 2016 Niklas von Hertzen 12376 12377 Released under License 12378 */ 12379 12380 !function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{var f;"undefined"!=typeof window?f=window:"undefined"!=typeof global?f=global:"undefined"!=typeof self&&(f=self),f.html2canvas=e()}}(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(_dereq_,module,exports){ 12381 (function (global){ 12382 /*! http://mths.be/punycode v1.2.4 by @mathias */ 12383 ;(function(root) { 12384 12385 /** Detect free variables */ 12386 var freeExports = typeof exports == 'object' && exports; 12387 var freeModule = typeof module == 'object' && module && 12388 module.exports == freeExports && module; 12389 var freeGlobal = typeof global == 'object' && global; 12390 if (freeGlobal.global === freeGlobal || freeGlobal.window === freeGlobal) { 12391 root = freeGlobal; 12392 } 12393 12394 /** 12395 * The `punycode` object. 12396 * @name punycode 12397 * @type Object 12398 */ 12399 var punycode, 12400 12401 /** Highest positive signed 32-bit float value */ 12402 maxInt = 2147483647, // aka. 0x7FFFFFFF or 2^31-1 12403 12404 /** Bootstring parameters */ 12405 base = 36, 12406 tMin = 1, 12407 tMax = 26, 12408 skew = 38, 12409 damp = 700, 12410 initialBias = 72, 12411 initialN = 128, // 0x80 12412 delimiter = '-', // '\x2D' 12413 12414 /** Regular expressions */ 12415 regexPunycode = /^xn--/, 12416 regexNonASCII = /[^ -~]/, // unprintable ASCII chars + non-ASCII chars 12417 regexSeparators = /\x2E|\u3002|\uFF0E|\uFF61/g, // RFC 3490 separators 12418 12419 /** Error messages */ 12420 errors = { 12421 'overflow': 'Overflow: input needs wider integers to process', 12422 'not-basic': 'Illegal input >= 0x80 (not a basic code point)', 12423 'invalid-input': 'Invalid input' 12424 }, 12425 12426 /** Convenience shortcuts */ 12427 baseMinusTMin = base - tMin, 12428 floor = Math.floor,
12429 stringFromCharCode = String.fromCharCode, 12430 12431 /** Temporary variable */ 12432 key; 12433 12434 /*--------------------------------------------------------------------------*/ 12435 12436 /** 12437 * A generic error utility function. 12438 * @private 12439 * @param {String} type The error type. 12440 * @returns {Error} Throws a `RangeError` with the applicable error message. 12441 */ 12442 function error(type) { 12443 throw RangeError(errors[type]); 12444 } 12445 12446 /** 12447 * A generic `Array#map` utility function. 12448 * @private 12449 * @param {Array} array The array to iterate over. 12450 * @param {Function} callback The function that gets called for every array 12451 * item. 12452 * @returns {Array} A new array of values returned by the callback function. 12453 */ 12454 function map(array, fn) { 12455 var length = array.length; 12456 while (length--) { 12457 array[length] = fn(array[length]); 12458 } 12459 return array; 12460 } 12461 12462 /** 12463 * A simple `Array#map`-like wrapper to work with domain name strings. 12464 * @private 12465 * @param {String} domain The domain name. 12466 * @param {Function} callback The function that gets called for every 12467 * character. 12468 * @returns {Array} A new string of characters returned by the callback 12469 * function. 12470 */ 12471 function mapDomain(string, fn) { 12472 return map(string.split(regexSeparators), fn).join('.'); 12473 } 12474 12475 /** 12476 * Creates an array containing the numeric code points of each Unicode 12477 * character in the string. While JavaScript uses UCS-2 internally, 12478 * this function will convert a pair of surrogate halves (each of which 12479 * UCS-2 exposes as separate characters) into a single code point, 12480 * matching UTF-16. 12481 * @see `punycode.ucs2.encode` 12482 * @see <http://mathiasbynens.be/notes/javascript-encoding> 12483 * @memberOf punycode.ucs2 12484 * @name decode 12485 * @param {String} string The Unicode input string (UCS-2). 12486 * @returns {Array} The new array of code points. 12487 */ 12488 function ucs2decode(string) { 12489 var output = [], 12490 counter = 0, 12491 length = string.length, 12492 value, 12493 extra; 12494 while (counter < length) { 12495 value = string.charCodeAt(counter++); 12496 if (value >= 0xD800 && value <= 0xDBFF && counter < length) { 12497 // high surrogate, and there is a next character 12498 extra = string.charCodeAt(counter++); 12499 if ((extra & 0xFC00) == 0xDC00) { // low surrogate 12500 output.push(((value & 0x3FF) << 10) + (extra & 0x3FF) + 0x10000); 12501 } else { 12502 // unmatched surrogate; only append this code unit, in case the next 12503 // code unit is the high surrogate of a surrogate pair 12504 output.push(value); 12505 counter--; 12506 } 12507 } else { 12508 output.push(value); 12509 } 12510 } 12511 return output; 12512 } 12513 12514 /** 12515 * Creates a string based on an array of numeric code points. 12516 * @see `punycode.ucs2.decode` 12517 * @memberOf punycode.ucs2 12518 * @name encode 12519 * @param {Array} codePoints The array of numeric code points. 12520 * @returns {String} The new Unicode string (UCS-2). 12521 */ 12522 function ucs2encode(array) { 12523 return map(array, function(value) { 12524 var output = ''; 12525 if (value > 0xFFFF) { 12526 value -= 0x10000; 12527 output += stringFromCharCode(value >>>
vendor: 14,930 bytes, lines 12527-12844
12527 10 & 0x3FF | 0xD800); 12528 value = 0xDC00 | value & 0x3FF; 12529 } 12530 output += stringFromCharCode(value); 12531 return output; 12532 }).join(''); 12533 } 12534 12535 /** 12536 * Converts a basic code point into a digit/integer. 12537 * @see `digitToBasic()` 12538 * @private 12539 * @param {Number} codePoint The basic numeric code point value. 12540 * @returns {Number} The numeric value of a basic code point (for use in 12541 * representing integers) in the range `0` to `base - 1`, or `base` if 12542 * the code point does not represent a value. 12543 */ 12544 function basicToDigit(codePoint) { 12545 if (codePoint - 48 < 10) { 12546 return codePoint - 22; 12547 } 12548 if (codePoint - 65 < 26) { 12549 return codePoint - 65; 12550 } 12551 if (codePoint - 97 < 26) { 12552 return codePoint - 97; 12553 } 12554 return base; 12555 } 12556 12557 /** 12558 * Converts a digit/integer into a basic code point. 12559 * @see `basicToDigit()` 12560 * @private 12561 * @param {Number} digit The numeric value of a basic code point. 12562 * @returns {Number} The basic code point whose value (when used for 12563 * representing integers) is `digit`, which needs to be in the range 12564 * `0` to `base - 1`. If `flag` is non-zero, the uppercase form is 12565 * used; else, the lowercase form is used. The behavior is undefined 12566 * if `flag` is non-zero and `digit` has no uppercase form. 12567 */ 12568 function digitToBasic(digit, flag) { 12569 // 0..25 map to ASCII a..z or A..Z 12570 // 26..35 map to ASCII 0..9 12571 return digit + 22 + 75 * (digit < 26) - ((flag != 0) << 5); 12572 } 12573 12574 /** 12575 * Bias adaptation function as per section 3.4 of RFC 3492. 12576 * http://tools.ietf.org/html/rfc3492#section-3.4 12577 * @private 12578 */ 12579 function adapt(delta, numPoints, firstTime) { 12580 var k = 0; 12581 delta = firstTime ? floor(delta / damp) : delta >> 1; 12582 delta += floor(delta / numPoints); 12583 for (/* no initialization */; delta > baseMinusTMin * tMax >> 1; k += base) { 12584 delta = floor(delta / baseMinusTMin); 12585 } 12586 return floor(k + (baseMinusTMin + 1) * delta / (delta + skew)); 12587 } 12588 12589 /** 12590 * Converts a Punycode string of ASCII-only symbols to a string of Unicode 12591 * symbols. 12592 * @memberOf punycode 12593 * @param {String} input The Punycode string of ASCII-only symbols. 12594 * @returns {String} The resulting string of Unicode symbols. 12595 */ 12596 function decode(input) { 12597 // Don't use UCS-2 12598 var output = [], 12599 inputLength = input.length, 12600 out, 12601 i = 0, 12602 n = initialN, 12603 bias = initialBias, 12604 basic, 12605 j, 12606 index, 12607 oldi, 12608 w, 12609 k, 12610 digit, 12611 t, 12612 /** Cached calculation results */ 12613 baseMinusT; 12614 12615 // Handle the basic code points: let `basic` be the number of input code 12616 // points before the last delimiter, or `0` if there is none, then copy 12617 // the first basic code points to the output. 12618 12619 basic = input.lastIndexOf(delimiter); 12620 if (basic < 0) { 12621 basic = 0; 12622 } 12623 12624 for (j = 0; j < basic; ++j) { 12625 // if it's not a basic code point 12626 if (input.charCodeAt(j) >= 0x80) { 12627 error('not-basic'); 12628 } 12629 output.push(input.charCodeAt(j)); 12630 } 12631 12632 // Main decoding loop: start just after the last delimiter if any basic code 12633 // points were copied; start at the beginning otherwise. 12634 12635 for (index = basic > 0 ? basic + 1 : 0; index < inputLength; /* no final expression */) { 12636 12637 // `index` is the index of the next character to be consumed. 12638 // Decode a generalized variable-length integer into `delta`, 12639 // which gets added to `i`. The overflow checking is easier 12640 // if we increase `i` as we go, then subtract off its starting 12641 // value at the end to obtain `delta`. 12642 for (oldi = i, w = 1, k = base; /* no condition */; k += base) { 12643 12644 if (index >= inputLength) { 12645 error('invalid-input'); 12646 } 12647 12648 digit = basicToDigit(input.charCodeAt(index++)); 12649 12650 if (digit >= base || digit > floor((maxInt - i) / w)) { 12651 error('overflow'); 12652 } 12653 12654 i += digit * w; 12655 t = k <= bias ? tMin : (k >= bias + tMax ? tMax : k - bias); 12656 12657 if (digit < t) { 12658 break; 12659 } 12660 12661 baseMinusT = base - t; 12662 if (w > floor(maxInt / baseMinusT)) { 12663 error('overflow'); 12664 } 12665 12666 w *= baseMinusT; 12667 12668 } 12669 12670 out = output.length + 1; 12671 bias = adapt(i - oldi, out, oldi == 0); 12672 12673 // `i` was supposed to wrap around from `out` to `0`, 12674 // incrementing `n` each time, so we'll fix that now: 12675 if (floor(i / out) > maxInt - n) { 12676 error('overflow'); 12677 } 12678 12679 n += floor(i / out); 12680 i %= out; 12681 12682 // Insert `n` at position `i` of the output 12683 output.splice(i++, 0, n); 12684 12685 } 12686 12687 return ucs2encode(output); 12688 } 12689 12690 /** 12691 * Converts a string of Unicode symbols to a Punycode string of ASCII-only 12692 * symbols. 12693 * @memberOf punycode 12694 * @param {String} input The string of Unicode symbols. 12695 * @returns {String} The resulting Punycode string of ASCII-only symbols. 12696 */ 12697 function encode(input) { 12698 var n, 12699 delta, 12700 handledCPCount, 12701 basicLength, 12702 bias, 12703 j, 12704 m, 12705 q, 12706 k, 12707 t, 12708 currentValue, 12709 output = [], 12710 /** `inputLength` will hold the number of code points in `input`. */ 12711 inputLength, 12712 /** Cached calculation results */ 12713 handledCPCountPlusOne, 12714 baseMinusT, 12715 qMinusT; 12716 12717 // Convert the input in UCS-2 to Unicode 12718 input = ucs2decode(input); 12719 12720 // Cache the length 12721 inputLength = input.length; 12722 12723 // Initialize the state 12724 n = initialN; 12725 delta = 0; 12726 bias = initialBias; 12727 12728 // Handle the basic code points 12729 for (j = 0; j < inputLength; ++j) { 12730 currentValue = input[j]; 12731 if (currentValue < 0x80) { 12732 output.push(stringFromCharCode(currentValue)); 12733 } 12734 } 12735 12736 handledCPCount = basicLength = output.length; 12737 12738 // `handledCPCount` is the number of code points that have been handled; 12739 // `basicLength` is the number of basic code points. 12740 12741 // Finish the basic string - if it is not empty - with a delimiter 12742 if (basicLength) { 12743 output.push(delimiter); 12744 } 12745 12746 // Main encoding loop: 12747 while (handledCPCount < inputLength) { 12748 12749 // All non-basic code points < n have been handled already. Find the next 12750 // larger one: 12751 for (m = maxInt, j = 0; j < inputLength; ++j) { 12752 currentValue = input[j]; 12753 if (currentValue >= n && currentValue < m) { 12754 m = currentValue; 12755 } 12756 } 12757 12758 // Increase `delta` enough to advance the decoder's <n,i> state to <m,0>, 12759 // but guard against overflow 12760 handledCPCountPlusOne = handledCPCount + 1; 12761 if (m - n > floor((maxInt - delta) / handledCPCountPlusOne)) { 12762 error('overflow'); 12763 } 12764 12765 delta += (m - n) * handledCPCountPlusOne; 12766 n = m; 12767 12768 for (j = 0; j < inputLength; ++j) { 12769 currentValue = input[j]; 12770 12771 if (currentValue < n && ++delta > maxInt) { 12772 error('overflow'); 12773 } 12774 12775 if (currentValue == n) { 12776 // Represent delta as a generalized variable-length integer 12777 for (q = delta, k = base; /* no condition */; k += base) { 12778 t = k <= bias ? tMin : (k >= bias + tMax ? tMax : k - bias); 12779 if (q < t) { 12780 break; 12781 } 12782 qMinusT = q - t; 12783 baseMinusT = base - t; 12784 output.push( 12785 stringFromCharCode(digitToBasic(t + qMinusT % baseMinusT, 0)) 12786 ); 12787 q = floor(qMinusT / baseMinusT); 12788 } 12789 12790 output.push(stringFromCharCode(digitToBasic(q, 0))); 12791 bias = adapt(delta, handledCPCountPlusOne, handledCPCount == basicLength); 12792 delta = 0; 12793 ++handledCPCount; 12794 } 12795 } 12796 12797 ++delta; 12798 ++n; 12799 12800 } 12801 return output.join(''); 12802 } 12803 12804 /** 12805 * Converts a Punycode string representing a domain name to Unicode. Only the 12806 * Punycoded parts of the domain name will be converted, i.e. it doesn't 12807 * matter if you call it on a string that has already been converted to 12808 * Unicode. 12809 * @memberOf punycode 12810 * @param {String} domain The Punycode domain name to convert to Unicode. 12811 * @returns {String} The Unicode representation of the given Punycode 12812 * string. 12813 */ 12814 function toUnicode(domain) { 12815 return mapDomain(domain, function(string) { 12816 return regexPunycode.test(string) 12817 ? decode(string.slice(4).toLowerCase()) 12818 : string; 12819 }); 12820 } 12821 12822 /** 12823 * Converts a Unicode string representing a domain name to Punycode. Only the 12824 * non-ASCII parts of the domain name will be converted, i.e. it doesn't 12825 * matter if you call it with a domain that's already in ASCII. 12826 * @memberOf punycode 12827 * @param {String} domain The domain name to convert, as a Unicode string. 12828 * @returns {String} The Punycode representation of the given domain name. 12829 */ 12830 function toASCII(domain) { 12831 return mapDomain(domain, function(string) { 12832 return regexNonASCII.test(string) 12833 ? 'xn--' + encode(string) 12834 : string; 12835 }); 12836 } 12837 12838 /*--------------------------------------------------------------------------*/ 12839 12840 /** Define the public API */ 12841 punycode = { 12842 /** 12843 * A string representing the current Punycode.js version number. 12844 * @memberOf punycode
12845 * @type String 12846 */ 12847 'version': '1.2.4', 12848 /** 12849 * An object of methods to convert from JavaScript's internal character 12850 * representation (UCS-2) to Unicode code points, and back. 12851 * @see <http://mathiasbynens.be/notes/javascript-encoding> 12852 * @memberOf punycode 12853 * @type Object 12854 */ 12855 'ucs2': { 12856 'decode': ucs2decode, 12857 'encode': ucs2encode 12858 }, 12859 'decode': decode, 12860 'encode': encode, 12861 'toASCII': toASCII, 12862 'toUnicode': toUnicode 12863 }; 12864 12865 /** Expose `punycode` */ 12866 // Some AMD build optimizers, like r.js, check for specific condition patterns 12867 // like the following: 12868 if ( 12869 typeof define == 'function' && 12870 typeof define.amd == 'object' && 12871 define.amd 12872 ) { 12873 define('punycode', function() { 12874 return punycode; 12875 }); 12876 } else if (freeExports && !freeExports.nodeType) { 12877 if (freeModule) { // in Node.js or RingoJS v0.8.0+ 12878 freeModule.exports = punycode; 12879 } else { // in Narwhal or RingoJS v0.7.0- 12880 for (key in punycode) { 12881 punycode.hasOwnProperty(key) && (freeExports[key] = punycode[key]); 12882 } 12883 } 12884 } else { // in Rhino or a web browser 12885 root.punycode = punycode; 12886 } 12887 12888 }(this)); 12889 12890 }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) 12891 },{}],2:[function(_dereq_,module,exports){ 12892 var log = _dereq_('./log'); 12893 12894 function restoreOwnerScroll(ownerDocument, x, y) { 12895 if (ownerDocument.defaultView && (x !== ownerDocument.defaultView.pageXOffset || y !== ownerDocument.defaultView.pageYOffset)) { 12896 ownerDocument.defaultView.scrollTo(x, y); 12897 } 12898 } 12899 12900 function cloneCanvasContents(canvas, clonedCanvas) { 12901 try { 12902 if (clonedCanvas) { 12903 clonedCanvas.width = canvas.width; 12904 clonedCanvas.height = canvas.height; 12905 clonedCanvas.getContext("2d").putImageData(canvas.getContext("2d").getImageData(0, 0, canvas.width, canvas.height), 0, 0); 12906 } 12907 } catch(e) { 12908 log("Unable to copy canvas content from", canvas, e); 12909 } 12910 } 12911 12912 function cloneNode(node, javascriptEnabled) { 12913 var clone = node.nodeType === 3 ? document.createTextNode(node.nodeValue) : node.cloneNode(false); 12914 12915 var child = node.firstChild; 12916 while(child) { 12917 if (javascriptEnabled === true || child.nodeType !== 1 || child.nodeName !== 'SCRIPT') { 12918 clone.appendChild(cloneNode(child, javascriptEnabled)); 12919 } 12920 child = child.nextSibling; 12921 } 12922 12923 if (node.nodeType === 1) { 12924 clone._scrollTop = node.scrollTop; 12925 clone._scrollLeft = node.scrollLeft; 12926 if (node.nodeName === "CANVAS") { 12927 cloneCanvasContents(node, clone); 12928 } else if (node.nodeName === "TEXTAREA" || node.nodeName === "SELECT") { 12929 clone.value = node.value; 12930 } 12931 } 12932 12933 return clone; 12934 } 12935 12936 function initNode(node) { 12937 if (node.nodeType === 1) { 12938 node.scrollTop = node._scrollTop; 12939 node.scrollLeft = node._scrollLeft; 12940 12941 var child = node.firstChild; 12942 while(child) { 12943 initNode(child); 12944 child = child.nextSibling; 12945 } 12946 } 12947 } 12948 12949 module.exports = function(ownerDocument, containerDocument, width, height, options, x ,y) { 12950 var documentElement = cloneNode(ownerDocument.documentElement, options.javascriptEnabled); 12951 var container = containerDocument.createElement("iframe"); 12952 12953 container.className = "html2canvas-container"; 12954 container.style.visibility = "hidden"; 12955 container.style.position = "fixed"; 12956 container.style.left = "-10000px"; 12957 container.style.top = "0px"; 12958 container.style.border = "0"; 12959 container.width = width; 12960 container.height = height; 12961 container.scrolling = "no"; // ios won't scroll without it 12962 containerDocument.body.appendChild(container); 12963 12964 return new Promise(function(resolve) { 12965 var documentClone = container.contentWindow.document; 12966 12967 /* Chrome doesn't detect relative background-images assigned in inline <style> sheets when fetched through getComputedStyle 12968 if window url is about:blank, we can assign the url to current by writing onto the document 12969 */ 12970 container.contentWindow.onload = container.onload = function() { 12971 var interval = setInterval(function() { 12972 if (documentClone.body.childNodes.length > 0) { 12973 initNode(documentClone.documentElement); 12974 clearInterval(interval); 12975 if (options.type === "view") { 12976 container.contentWindow.scrollTo(x, y); 12977 if ((/(iPad|iPhone|iPod)/g).test(navigator.userAgent) && (container.contentWindow.scrollY !== y || container.contentWindow.scrollX !== x)) { 12978 documentClone.documentElement.style.top = (-y) + "px"; 12979 documentClone.documentElement.style.left = (-x) + "px"; 12980 documentClone.documentElement.style.position = 'absolute'; 12981 } 12982 } 12983 resolve(container); 12984 } 12985 }, 50); 12986 }; 12987 12988 documentClone.open(); 12989 documentClone.write("<!DOCTYPE html><html></html>"); 12990 // Chrome scrolls the parent document for some reason after the write to the cloned window??? 12991 restoreOwnerScroll(ownerDocument, x, y); 12992 documentClone.replaceChild(documentClone.adoptNode(documentElement), documentClone.documentElement); 12993 documentClone.close(); 12994 }); 12995 }; 12996 12997 },{"./log":13}],3:[function(_dereq_,module,exports){ 12998 // http://dev.w3.org/csswg/css-color/ 12999 13000 function Color(value) { 13001 this.r = 0; 13002 this.g = 0; 13003 this.b = 0; 13004 this.a = null; 13005 var result = this.fromArray(value) || 13006 this.namedColor(value) || 13007 this.rgb(value) || 13008 this.rgba(value) || 13009 this.hex6(value) || 13010 this.hex3(value); 13011 } 13012 13013 Color.prototype.darken = function(amount) { 13014 var a = 1 - amount; 13015 return new Color([ 13016 Math.round(this.r * a), 13017 Math.round(this.g * a), 13018 Math.round(this.b * a), 13019 this.a 13020 ]); 13021 }; 13022 13023 Color.prototype.isTransparent = function() { 13024 return this.a === 0; 13025 }; 13026 13027 Color.prototype.isBlack = function() { 13028 return this.r === 0 && this.g === 0 && this.b === 0; 13029 }; 13030 13031 Color.prototype.fromArray = function(array) { 13032 if (Array.isArray(array)) { 13033 this.r = Math.min(array[0], 255); 13034 this.g = Math.min(array[1], 255); 13035 this.b = Math.min(array[2], 255); 13036 if (array.length > 3) { 13037 this.a = array[3]; 13038 } 13039 } 13040 13041 return (Array.isArray(array)); 13042 }; 13043 13044 var _hex3 = /^#([a-f0-9]{3})$/i; 13045 13046 Color.prototype.hex3 = function(value) { 13047 var match = null; 13048 if ((match = value.match(_hex3)) !== null) { 13049 this.r = parseInt(match[1][0] + match[1][0], 16); 13050 this.g = parseInt(match[1][1] + match[1][1], 16); 13051 this.b = parseInt(match[1][2] + match[1][2], 16); 13052 } 13053 return match !== null; 13054 }; 13055 13056 var _hex6 = /^#([a-f0-9]{6})$/i; 13057 13058 Color.prototype.hex6 = function(value) { 13059 var match = null; 13060 if ((match = value.match(_hex6)) !== null) { 13061 this.r = parseInt(match[1].substring(0, 2), 16); 13062 this.g = parseInt(match[1].substring(2, 4), 16); 13063 this.b = parseInt(match[1].substring(4, 6), 16); 13064 } 13065 return match !== null; 13066 }; 13067 13068 13069 var _rgb = /^rgb\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*\)$/; 13070 13071 Color.prototype.rgb = function(value) { 13072 var match = null; 13073 if ((match = value.match(_rgb)) !== null) { 13074 this.r = Number(match[1]); 13075 this.g = Number(match[2]); 13076 this.b = Number(match[3]); 13077 } 13078 return match !== null; 13079 }; 13080 13081 var _rgba = /^rgba\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d?\.?\d+)\s*\)$/; 13082 13083 Color.prototype.rgba = function(value) { 13084 var match = null; 13085 if ((match = value.match(_rgba)) !== null) { 13086 this.r = Number(match[1]); 13087 this.g = Number(match[2]); 13088 this.b = Number(match[3]); 13089 this.a = Number(match[4]); 13090 } 13091 return match !== null; 13092 }; 13093 13094 Color.prototype.toString = function() { 13095 return this.a !== null && this.a !== 1 ? 13096 "rgba(" + [this.r, this.g, this.b, this.a].join(",") + ")" : 13097 "rgb(" + [this.r, this.g, this.b].join(",") + ")"; 13098 }; 13099 13100 Color.prototype.namedColor = function(value) { 13101 value = value.toLowerCase(); 13102 var color = colors[value]; 13103 if (color) { 13104 this.r = color[0]; 13105 this.g = color[1]; 13106 this.b = color[2]; 13107 } else if (value === "transparent") { 13108 this.r = this.g = this.b = this.a = 0; 13109 return true; 13110 } 13111 13112 return !!color; 13113 }; 13114 13115 Color.prototype.isColor = true; 13116 13117 // JSON.stringify([].slice.call($$('.named-color-table tr'), 1).map(function(row) { return [row.childNodes[3].textContent, row.childNodes[5].textContent.trim().split(",").map(Number)] }).reduce(function(data, row) {data[row[0]] = row[1]; return data}, {})) 13118 var colors = { 13119 "aliceblue": [240, 248, 255], 13120 "antiquewhite": [250, 235, 215], 13121 "aqua": [0, 255, 255], 13122 "aquamarine": [127, 255, 212], 13123 "azure": [240, 255, 255], 13124 "beige": [245, 245, 220], 13125 "bisque": [255, 228, 196], 13126 "black": [0, 0, 0], 13127 "blanchedalmond": [255, 235, 205], 13128 "blue": [0, 0, 255], 13129 "blueviolet": [138, 43, 226], 13130 "brown": [165, 42, 42], 13131 "burlywood": [222, 184, 135], 13132 "cadetblue": [95, 158, 160], 13133 "chartreuse": [127, 255, 0], 13134 "chocolate": [210, 105, 30], 13135 "coral": [255, 127, 80], 13136 "cornflowerblue": [100, 149, 237], 13137 "cornsilk": [255, 248, 220], 13138 "crimson": [220, 20, 60], 13139 "cyan": [0, 255, 255], 13140 "darkblue": [0, 0, 139], 13141 "darkcyan": [0, 139, 139], 13142 "darkgoldenrod": [184, 134, 11], 13143 "darkgray": [169, 169, 169], 13144 "darkgreen": [0, 100, 0], 13145 "darkgrey": [169, 169, 169], 13146 "darkkhaki": [189, 183, 107], 13147 "darkmagenta": [139, 0, 139], 13148 "darkolivegreen": [85, 107, 47], 13149 "darkorange": [255, 140, 0], 13150 "darkorchid": [153, 50, 204], 13151 "darkred": [139, 0, 0], 13152 "darksalmon": [233, 150, 122], 13153 "darkseagreen": [143, 188, 143], 13154 "darkslateblue": [72, 61, 139], 13155 "darkslategray": [47, 79, 79], 13156 "darkslategrey": [47, 79, 79],
13157 "darkturquoise": [0, 206, 209], 13158 "darkviolet": [148, 0, 211], 13159 "deeppink": [255, 20, 147], 13160 "deepskyblue": [0, 191, 255], 13161 "dimgray": [105, 105, 105], 13162 "dimgrey": [105, 105, 105], 13163 "dodgerblue": [30, 144, 255], 13164 "firebrick": [178, 34, 34], 13165 "floralwhite": [255, 250, 240], 13166 "forestgreen": [34, 139, 34], 13167 "fuchsia": [255, 0, 255], 13168 "gainsboro": [220, 220, 220], 13169 "ghostwhite": [248, 248, 255], 13170 "gold": [255, 215, 0], 13171 "goldenrod": [218, 165, 32], 13172 "gray": [128, 128, 128], 13173 "green": [0, 128, 0], 13174 "greenyellow": [173, 255, 47], 13175 "grey": [128, 128, 128], 13176 "honeydew": [240, 255, 240], 13177 "hotpink": [255, 105, 180], 13178 "indianred": [205, 92, 92], 13179 "indigo": [75, 0, 130], 13180 "ivory": [255, 255, 240], 13181 "khaki": [240, 230, 140], 13182 "lavender": [230, 230, 250], 13183 "lavenderblush": [255, 240, 245], 13184 "lawngreen": [124, 252, 0], 13185 "lemonchiffon": [255, 250, 205], 13186 "lightblue": [173, 216, 230], 13187 "lightcoral": [240, 128, 128], 13188 "lightcyan": [224, 255, 255], 13189 "lightgoldenrodyellow": [250, 250, 210], 13190 "lightgray": [211, 211, 211], 13191 "lightgreen": [144, 238, 144], 13192 "lightgrey": [211, 211, 211], 13193 "lightpink": [255, 182, 193], 13194 "lightsalmon": [255, 160, 122], 13195 "lightseagreen": [32, 178, 170], 13196 "lightskyblue": [135, 206, 250], 13197 "lightslategray": [119, 136, 153], 13198 "lightslategrey": [119, 136, 153], 13199 "lightsteelblue": [176, 196, 222], 13200 "lightyellow": [255, 255, 224], 13201 "lime": [0, 255, 0], 13202 "limegreen": [50, 205, 50], 13203 "linen": [250, 240, 230], 13204 "magenta": [255, 0, 255], 13205 "maroon": [128, 0, 0], 13206 "mediumaquamarine": [102, 205, 170], 13207 "mediumblue": [0, 0, 205], 13208 "mediumorchid": [186, 85, 211], 13209 "mediumpurple": [147, 112, 219], 13210 "mediumseagreen": [60, 179, 113], 13211 "mediumslateblue": [123, 104, 238], 13212 "mediumspringgreen": [0, 250, 154], 13213 "mediumturquoise": [72, 209, 204], 13214 "mediumvioletred": [199, 21, 133], 13215 "midnightblue": [25, 25, 112], 13216 "mintcream": [245, 255, 250], 13217 "mistyrose": [255, 228, 225], 13218 "moccasin": [255, 228, 181], 13219 "navajowhite": [255, 222, 173], 13220 "navy": [0, 0, 128], 13221 "oldlace": [253, 245, 230], 13222 "olive": [128, 128, 0], 13223 "olivedrab": [107, 142, 35], 13224 "orange": [255, 165, 0], 13225 "orangered": [255, 69, 0], 13226 "orchid": [218, 112, 214], 13227 "palegoldenrod": [238, 232, 170], 13228 "palegreen": [152, 251, 152], 13229 "paleturquoise": [175, 238, 238], 13230 "palevioletred": [219, 112, 147], 13231 "papayawhip": [255, 239, 213], 13232 "peachpuff": [255, 218, 185], 13233 "peru": [205, 133, 63], 13234 "pink": [255, 192, 203], 13235 "plum": [221, 160, 221], 13236 "powderblue": [176, 224, 230], 13237 "purple": [128, 0, 128], 13238 "rebeccapurple": [102, 51, 153], 13239 "red": [255, 0, 0], 13240 "rosybrown": [188, 143, 143], 13241 "royalblue": [65, 105, 225], 13242 "saddlebrown": [139, 69, 19], 13243 "salmon": [250, 128, 114], 13244 "sandybrown": [244, 164, 96], 13245 "seagreen": [46, 139, 87], 13246 "seashell": [255, 245, 238], 13247 "sienna": [160, 82, 45], 13248 "silver": [192, 192, 192], 13249 "skyblue": [135, 206, 235], 13250 "slateblue": [106, 90, 205], 13251 "slategray": [112, 128, 144], 13252 "slategrey": [112, 128, 144], 13253 "snow": [255, 250, 250], 13254 "springgreen": [0, 255, 127], 13255 "steelblue": [70, 130, 180], 13256 "tan": [210, 180, 140], 13257 "teal": [0, 128, 128], 13258 "thistle": [216, 191, 216], 13259 "tomato": [255, 99, 71],
13260 "turquoise": [64, 224, 208], 13261 "violet": [238, 130, 238], 13262 "wheat": [245, 222, 179], 13263 "white": [255, 255, 255], 13264 "whitesmoke": [245, 245, 245], 13265 "yellow": [255, 255, 0], 13266 "yellowgreen": [154, 205, 50] 13267 }; 13268 13269 module.exports = Color; 13270 13271 },{}],4:[function(_dereq_,module,exports){ 13272 var Support = _dereq_('./support'); 13273 var CanvasRenderer = _dereq_('./renderers/canvas'); 13274 var ImageLoader = _dereq_('./imageloader'); 13275 var NodeParser = _dereq_('./nodeparser'); 13276 var NodeContainer = _dereq_('./nodecontainer'); 13277 var log = _dereq_('./log'); 13278 var utils = _dereq_('./utils'); 13279 var createWindowClone = _dereq_('./clone'); 13280 var loadUrlDocument = _dereq_('./proxy').loadUrlDocument; 13281 var getBounds = utils.getBounds; 13282 13283 var html2canvasNodeAttribute = "data-html2canvas-node"; 13284 var html2canvasCloneIndex = 0; 13285 13286 function html2canvas(nodeList, options) { 13287 var index = html2canvasCloneIndex++; 13288 options = options || {}; 13289 if (options.logging) { 13290 log.options.logging = true; 13291 log.options.start = Date.now(); 13292 } 13293 13294 options.async = typeof(options.async) === "undefined" ? true : options.async; 13295 options.allowTaint = typeof(options.allowTaint) === "undefined" ? false : options.allowTaint; 13296 options.removeContainer = typeof(options.removeContainer) === "undefined" ? true : options.removeContainer; 13297 options.javascriptEnabled = typeof(options.javascriptEnabled) === "undefined" ? false : options.javascriptEnabled; 13298 options.imageTimeout = typeof(options.imageTimeout) === "undefined" ? 10000 : options.imageTimeout; 13299 options.renderer = typeof(options.renderer) === "function" ? options.renderer : CanvasRenderer; 13300 options.strict = !!options.strict; 13301 13302 if (typeof(nodeList) === "string") { 13303 if (typeof(options.proxy) !== "string") { 13304 return Promise.reject("Proxy must be used when rendering url"); 13305 } 13306 var width = options.width != null ? options.width : window.innerWidth; 13307 var height = options.height != null ? options.height : window.innerHeight; 13308 return loadUrlDocument(absoluteUrl(nodeList), options.proxy, document, width, height, options).then(function(container) { 13309 return renderWindow(container.contentWindow.document.documentElement, container, options, width, height); 13310 }); 13311 } 13312 13313 var node = ((nodeList === undefined) ? [document.documentElement] : ((nodeList.length) ? nodeList : [nodeList]))[0]; 13314 node.setAttribute(html2canvasNodeAttribute + index, index); 13315 return renderDocument(node.ownerDocument, options, node.ownerDocument.defaultView.innerWidth, node.ownerDocument.defaultView.innerHeight, index).then(function(canvas) { 13316 if (typeof(options.onrendered) === "function") { 13317 log("options.onrendered is deprecated, html2canvas returns a Promise containing the canvas"); 13318 options.onrendered(canvas); 13319 } 13320 return canvas; 13321 }); 13322 } 13323 13324 html2canvas.CanvasRenderer = CanvasRenderer; 13325 html2canvas.NodeContainer = NodeContainer; 13326 html2canvas.log = log; 13327 html2canvas.utils = utils; 13328 13329 var html2canvasExport = (typeof(document) === "undefined" || typeof(Object.create) !== "function" || typeof(document.createElement("canvas").getContext) !== "function") ? function() { 13330 return Promise.reject("No canvas support"); 13331 } : html2canvas; 13332 13333 module.exports = html2canvasExport; 13334 13335 if (typeof(define) === 'function' && define.amd) { 13336 define('html2canvas', [], function() { 13337 return html2canvasExport; 13338 }); 13339 } 13340 13341 function renderDocument(document, options, windowWidth, windowHeight, html2canvasIndex) { 13342 return createWindowClone(document, document, windowWidth, windowHeight, options, document.defaultView.pageXOffset, document.defaultView.pageYOffset).then(function(container) { 13343 log("Document cloned"); 13344 var attributeName = html2canvasNodeAttribute + html2canvasIndex; 13345 var selector = "[" + attributeName + "='" + html2canvasIndex + "']"; 13346 document.querySelector(selector).removeAttribute(attributeName); 13347 var clonedWindow = container.contentWindow; 13348 var node = clonedWindow.document.querySelector(selector); 13349 var oncloneHandler = (typeof(options.onclone)
13349=== "function") ? Promise.resolve(options.onclone(clonedWindow.document)) : Promise.resolve(true); 13350 return oncloneHandler.then(function() { 13351 return renderWindow(node, container, options, windowWidth, windowHeight); 13352 }); 13353 }); 13354 } 13355 13356 function renderWindow(node, container, options, windowWidth, windowHeight) { 13357 var clonedWindow = container.contentWindow; 13358 var support = new Support(clonedWindow.document); 13359 var imageLoader = new ImageLoader(options, support); 13360 var bounds = getBounds(node); 13361 var width = options.type === "view" ? windowWidth : documentWidth(clonedWindow.document); 13362 var height = options.type === "view" ? windowHeight : documentHeight(clonedWindow.document); 13363 var renderer = new options.renderer(width, height, imageLoader, options, document); 13364 var parser = new NodeParser(node, renderer, support, imageLoader, options); 13365 return parser.ready.then(function() { 13366 log("Finished rendering"); 13367 var canvas; 13368 13369 if (options.type === "view") { 13370 canvas = crop(renderer.canvas, {width: renderer.canvas.width, height: renderer.canvas.height, top: 0, left: 0, x: 0, y: 0}); 13371 } else if (node === clonedWindow.document.body || node === clonedWindow.document.documentElement || options.canvas != null) { 13372 canvas = renderer.canvas; 13373 } else { 13374 canvas = crop(renderer.canvas, {width: options.width != null ? options.width : bounds.width, height: options.height != null ? options.height : bounds.height, top: bounds.top, left: bounds.left, x: 0, y: 0}); 13375 } 13376 13377 cleanupContainer(container, options); 13378 return canvas; 13379 }); 13380 } 13381 13382 function cleanupContainer(container, options) { 13383 if (options.removeContainer) { 13384 container.parentNode.removeChild(container); 13385 log("Cleaned up container"); 13386 } 13387 } 13388 13389 function crop(canvas, bounds) { 13390 var croppedCanvas = document.createElement("canvas"); 13391 var x1 = Math.min(canvas.width - 1, Math.max(0, bounds.left)); 13392 var x2 = Math.min(canvas.width, Math.max(1, bounds.left + bounds.width)); 13393 var y1 = Math.min(canvas.height - 1, Math.max(0, bounds.top)); 13394 var y2 = Math.min(canvas.height, Math.max(1, bounds.top + bounds.height)); 13395 croppedCanvas.width = bounds.width; 13396 croppedCanvas.height = bounds.height; 13397 var width = x2-x1; 13398 var height = y2-y1; 13399 log("Cropping canvas at:", "left:", bounds.left, "top:", bounds.top, "width:", width, "height:", height); 13400 log("Resulting crop with width", bounds.width, "and height", bounds.height, "with x", x1, "and y", y1); 13401 croppedCanvas.getContext("2d").drawImage(canvas, x1, y1, width, height, bounds.x, bounds.y, width, height); 13402 return croppedCanvas; 13403 } 13404 13405 function documentWidth (doc) { 13406 return Math.max( 13407 Math.max(doc.body.scrollWidth, doc.documentElement.scrollWidth), 13408 Math.max(doc.body.offsetWidth, doc.documentElement.offsetWidth), 13409 Math.max(doc.body.clientWidth, doc.documentElement.clientWidth) 13410 ); 13411 } 13412 13413 function documentHeight (doc) { 13414 return Math.max( 13415 Math.max(doc.body.scrollHeight, doc.documentElement.scrollHeight), 13416 Math.max(doc.body.offsetHeight, doc.documentElement.offsetHeight), 13417 Math.max(doc.body.clientHeight, doc.documentElement.clientHeight) 13418 ); 13419 } 13420 13421 function absoluteUrl(url) { 13422 var link = document.createElement("a"); 13423 link.href = url; 13424 link.href = link.href; 13425 return link; 13426 } 13427 13428 },{"./clone":2,"./imageloader":11,"./log":13,"./nodecontainer":14,"./nodeparser":15,"./proxy":16,"./renderers/canvas":20,"./support":22,"./utils":26}],5:[function(_dereq_,module,exports){ 13429 var log = _dereq_('./log'); 13430 var smallImage = _dereq_('./utils').smallImage; 13431 13432 function DummyImageContainer(src) { 13433 this.src = src; 13434 log("DummyImageContainer for", src); 13435 if (!this.promise || !this.image) { 13436 log("Initiating DummyImageContainer"); 13437 DummyImageContainer.prototype.image = new Image(); 13438 var image = this.image; 13439 DummyImageContainer.prototype.promise = new Promise(function(resolve, reject) { 13440 image.onload = resolve; 13441 image.onerror = reject; 13442 image.src = smallImage(); 13443 if (image.complete === true) { 13444 resolve(image); 13445 } 13446 }); 13447 } 13448 } 13449 13450 module.exports = DummyImageContainer; 13451 13452 }
13452,{"./log":13,"./utils":26}],6:[function(_dereq_,module,exports){ 13453 var smallImage = _dereq_('./utils').smallImage; 13454 13455 function Font(family, size) { 13456 var container = document.createElement('div'), 13457 img = document.createElement('img'), 13458 span = document.createElement('span'), 13459 sampleText = 'Hidden Text', 13460 baseline, 13461 middle; 13462 13463 container.style.visibility = "hidden"; 13464 container.style.fontFamily = family; 13465 container.style.fontSize = size; 13466 container.style.margin = 0; 13467 container.style.padding = 0; 13468 13469 document.body.appendChild(container); 13470 13471 img.src = smallImage(); 13472 img.width = 1; 13473 img.height = 1; 13474 13475 img.style.margin = 0; 13476 img.style.padding = 0; 13477 img.style.verticalAlign = "baseline"; 13478 13479 span.style.fontFamily = family; 13480 span.style.fontSize = size; 13481 span.style.margin = 0; 13482 span.style.padding = 0; 13483 13484 span.appendChild(document.createTextNode(sampleText)); 13485 container.appendChild(span); 13486 container.appendChild(img); 13487 baseline = (img.offsetTop - span.offsetTop) + 1; 13488 13489 container.removeChild(span); 13490 container.appendChild(document.createTextNode(sampleText)); 13491 13492 container.style.lineHeight = "normal"; 13493 img.style.verticalAlign = "super"; 13494 13495 middle = (img.offsetTop-container.offsetTop) + 1; 13496 13497 document.body.removeChild(container); 13498 13499 this.baseline = baseline; 13500 this.lineWidth = 1; 13501 this.middle = middle; 13502 } 13503 13504 module.exports = Font; 13505 13506 },{"./utils":26}],7:[function(_dereq_,module,exports){ 13507 var Font = _dereq_('./font'); 13508 13509 function FontMetrics() { 13510 this.data = {}; 13511 } 13512 13513 FontMetrics.prototype.getMetrics = function(family, size) { 13514 if (this.data[family + "-" + size] === undefined) { 13515 this.data[family + "-" + size] = new Font(family, size); 13516 } 13517 return this.data[family + "-" + size]; 13518 }; 13519 13520 module.exports = FontMetrics; 13521 13522 },{"./font":6}],8:[function(_dereq_,module,exports){ 13523 var utils = _dereq_('./utils'); 13524 var getBounds = utils.getBounds; 13525 var loadUrlDocument = _dereq_('./proxy').loadUrlDocument; 13526 13527 function FrameContainer(container, sameOrigin, options) { 13528 this.image = null; 13529 this.src = container; 13530 var self = this; 13531 var bounds = getBounds(container); 13532 this.promise = (!sameOrigin ? this.proxyLoad(options.proxy, bounds, options) : new Promise(function(resolve) { 13533 if (container.contentWindow.document.URL === "about:blank" || container.contentWindow.document.documentElement == null) { 13534 container.contentWindow.onload = container.onload = function() { 13535 resolve(container); 13536 }; 13537 } else { 13538 resolve(container); 13539 } 13540 })).then(function(container) { 13541 var html2canvas = _dereq_('./core'); 13542 return html2canvas(container.contentWindow.document.documentElement, {type: 'view', width: container.width, height: container.height, proxy: options.proxy, javascriptEnabled: options.javascriptEnabled, removeContainer: options.removeContainer, allowTaint: options.allowTaint, imageTimeout: options.imageTimeout / 2}); 13543 }).then(function(canvas) { 13544 return self.image = canvas; 13545 }); 13546 } 13547 13548 FrameContainer.prototype.proxyLoad = function(proxy, bounds, options) { 13549 var container = this.src; 13550 return loadUrlDocument(container.src, proxy, container.ownerDocument, bounds.width, bounds.height, options); 13551 }; 13552 13553 module.exports = FrameContainer; 13554 13555 },{"./core":4,"./proxy":16,"./utils":26}],9:[function(_dereq_,module,exports){ 13556 function GradientContainer(imageData) { 13557 this.src = imageData.value; 13558 this.colorStops = []; 13559 this.type = null; 13560 this.x0 = 0.5; 13561 this.y0 = 0.5; 13562 this.x1 = 0.5; 13563 this.y1 = 0.5; 13564 this.promise = Promise.resolve(true); 13565 } 13566 13567 GradientContainer.TYPES = { 13568 LINEAR: 1, 13569 RADIAL: 2 13570 }; 13571 13572 // TODO: support hsl[a], negative %/length values 13573 // TODO: support <angle> (e.g. -?\d{1,3}(?:\.\d+)deg, etc. : https://developer.mozilla.org/docs/Web/CSS/angle ) 13574 GradientContainer.REGEXP_COLORSTOP = /^\s*(rgba?\(\s*\d{1,3},\s*\d{1,3},\s*\d{1,3}(?:,\s*[0-9\.]+)?\s*\)|[a-z]{3,20}|#[a-f0-9]{3,6})(?:\s+(\d{1,3}(?:\.\d+)?)(%|px)?)?(?:\s|$)/i; 13575 13576 module.exports = GradientContainer; 13577 13578 },{}],10:[function(_dereq_,module,exports){ 13579 function ImageContainer(src, cors) { 13580 this.src = src; 13581 this.image = new Image(); 13582 var self = this; 13583 this.tainted = null; 13584 this.promise = new Promise(function(resolve, reject) { 13585 self.image.onload = resolve; 13586 self.image.onerror = reject; 13587 if (cors) { 13588 self.image.crossOrigin = "anonymous"; 13589 } 13590 self.image.src = src; 13591 if (self.image.complete === true) { 13592 resolve(self.image); 13593 } 13594 }); 13595 } 13596 13597 module.exports = ImageContainer; 13598 13599 },{}],11:[function(_dereq_,module,exports){ 13600 var log = _dereq_('./log'); 13601 var ImageContainer = _dereq_('./imagecontainer'); 13602 var DummyImageContainer = _dereq_('./dummyimagecontainer'); 13603 var ProxyImageContainer = _dereq_('./proxyimagecontainer'); 13604 var FrameContainer = _dereq_('./framecontainer'); 13605 var SVGContainer = _dereq_('./svgcontainer'); 13606 var SVGNodeContainer = _dereq_('./svgnodecontainer'); 13607 var LinearGradientContainer = _dereq_('./lineargradientcontainer'); 13608 var WebkitGradientContainer = _dereq_('./webkitgradientcontainer'); 13609 var bind = _dereq_('./utils').bind; 13610 13611 function ImageLoader(options, support) { 13612 this.link = null; 13613 this.options = options; 13614 this.support = support; 13615 this.origin = this.getOrigin(window.location.href); 13616 } 13617 13618 ImageLoader.prototype.findImages = function(nodes) { 13619 var images = []; 13620 nodes.reduce(function(imageNodes, container) { 13621 switch(container.node.nodeName) { 13622 case "IMG": 13623 return imageNodes.concat([{ 13624 args: [container.node.src], 13625 method: "url" 13626 }]); 13627 case "svg": 13628 case "IFRAME": 13629 return imageNodes.concat([{ 13630 args: [container.node], 13631 method: container.node.nodeName 13632 }]); 13633 } 13634 return imageNodes; 13635 }
13635, []).forEach(this.addImage(images, this.loadImage), this); 13636 return images; 13637 }; 13638 13639 ImageLoader.prototype.findBackgroundImage = function(images, container) { 13640 container.parseBackgroundImages().filter(this.hasImageBackground).forEach(this.addImage(images, this.loadImage), this); 13641 return images; 13642 }; 13643 13644 ImageLoader.prototype.addImage = function(images, callback) { 13645 return function(newImage) { 13646 newImage.args.forEach(function(image) { 13647 if (!this.imageExists(images, image)) { 13648 images.splice(0, 0, callback.call(this, newImage)); 13649 log('Added image #' + (images.length), typeof(image) === "string" ? image.substring(0, 100) : image); 13650 } 13651 }, this); 13652 }; 13653 }; 13654 13655 ImageLoader.prototype.hasImageBackground = function(imageData) { 13656 return imageData.method !== "none"; 13657 }; 13658 13659 ImageLoader.prototype.loadImage = function(imageData) { 13660 if (imageData.method === "url") { 13661 var src = imageData.args[0]; 13662 if (this.isSVG(src) && !this.support.svg && !this.options.allowTaint) { 13663 return new SVGContainer(src); 13664 } else if (src.match(/data:image\/.*;base64,/i)) { 13665 return new ImageContainer(src.replace(/url\(['"]{0,}|['"]{0,}\)$/ig, ''), false); 13666 } else if (this.isSameOrigin(src) || this.options.allowTaint === true || this.isSVG(src)) { 13667 return new ImageContainer(src, false); 13668 } else if (this.support.cors && !this.options.allowTaint && this.options.useCORS) { 13669 return new ImageContainer(src, true); 13670 } else if (this.options.proxy) { 13671 return new ProxyImageContainer(src, this.options.proxy); 13672 } else { 13673 return new DummyImageContainer(src); 13674 } 13675 } else if (imageData.method === "linear-gradient") { 13676 return new LinearGradientContainer(imageData); 13677 } else if (imageData.method === "gradient") { 13678 return new WebkitGradientContainer(imageData); 13679 } else if (imageData.method === "svg") { 13680 return new SVGNodeContainer(imageData.args[0], this.support.svg); 13681 } else if (imageData.method === "IFRAME") { 13682 return new FrameContainer(imageData.args[0], this.isSameOrigin(imageData.args[0].src), this.options); 13683 } else { 13684 return new DummyImageContainer(imageData); 13685 } 13686 }; 13687 13688 ImageLoader.prototype.isSVG = function(src) { 13689 return src.substring(src.length - 3).toLowerCase() === "svg" || SVGContainer.prototype.isInline(src); 13690 }; 13691 13692 ImageLoader.prototype.imageExists = function(images, src) { 13693 return images.some(function(image) { 13694 return image.src === src; 13695 }); 13696 }; 13697 13698 ImageLoader.prototype.isSameOrigin = function(url) { 13699 return (this.getOrigin(url) === this.origin); 13700 }; 13701 13702 ImageLoader.prototype.getOrigin = function(url) { 13703 var link = this.link || (this.link = document.createElement("a")); 13704 link.href = url; 13705 link.href = link.href; // IE9, LOL! - http://jsfiddle.net/niklasvh/2e48b/ 13706 return link.protocol + link.hostname + link.port; 13707 }; 13708 13709 ImageLoader.prototype.getPromise = function(container) { 13710 return this.timeout(container, this.options.imageTimeout)['catch'](function() { 13711 var dummy = new DummyImageContainer(container.src); 13712 return dummy.promise.then(function(image) { 13713 container.image = image; 13714 }); 13715 }); 13716 }; 13717 13718 ImageLoader.prototype.get = function(src) { 13719 var found = null; 13720 return this.images.some(function(img) { 13721 return (found = img).src === src; 13722 }) ? found : null; 13723 }; 13724 13725 ImageLoader.prototype.fetch = function(nodes) { 13726 this.images = nodes.reduce(bind(this.findBackgroun
13726dImage, this), this.findImages(nodes)); 13727 this.images.forEach(function(image, index) { 13728 image.promise.then(function() { 13729 log("Succesfully loaded image #"+ (index+1), image); 13730 }, function(e) { 13731 log("Failed loading image #"+ (index+1), image, e); 13732 }); 13733 }); 13734 this.ready = Promise.all(this.images.map(this.getPromise, this)); 13735 log("Finished searching images"); 13736 return this; 13737 }; 13738 13739 ImageLoader.prototype.timeout = function(container, timeout) { 13740 var timer; 13741 var promise = Promise.race([container.promise, new Promise(function(res, reject) { 13742 timer = setTimeout(function() { 13743 log("Timed out loading image", container); 13744 reject(container); 13745 }, timeout); 13746 })]).then(function(container) { 13747 clearTimeout(timer); 13748 return container; 13749 }); 13750 promise['catch'](function() { 13751 clearTimeout(timer); 13752 }); 13753 return promise; 13754 }; 13755 13756 module.exports = ImageLoader; 13757 13758 },{"./dummyimagecontainer":5,"./framecontainer":8,"./imagecontainer":10,"./lineargradientcontainer":12,"./log":13,"./proxyimagecontainer":17,"./svgcontainer":23,"./svgnodecontainer":24,"./utils":26,"./webkitgradientcontainer":27}],12:[function(_dereq_,module,exports){ 13759 var GradientContainer = _dereq_('./gradientcontainer'); 13760 var Color = _dereq_('./color'); 13761 13762 function LinearGradientContainer(imageData) { 13763 GradientContainer.apply(this, arguments); 13764 this.type = GradientContainer.TYPES.LINEAR; 13765 13766 var hasDirection = LinearGradientContainer.REGEXP_DIRECTION.test( imageData.args[0] ) || 13767 !GradientContainer.REGEXP_COLORSTOP.test( imageData.args[0] ); 13768 13769 if (hasDirection) { 13770 imageData.args[0].split(/\s+/).reverse().forEach(function(position, index) { 13771 switch(position) { 13772 case "left": 13773 this.x0 = 0; 13774 this.x1 = 1; 13775 break; 13776 case "top": 13777 this.y0 = 0; 13778 this.y1 = 1; 13779 break; 13780 case "right": 13781 this.x0 = 1; 13782 this.x1 = 0; 13783 break; 13784 case "bottom": 13785 this.y0 = 1; 13786 this.y1 = 0; 13787 break; 13788 case "to": 13789 var y0 = this.y0; 13790 var x0 = this.x0; 13791 this.y0 = this.y1; 13792 this.x0 = this.x1; 13793 this.x1 = x0; 13794 this.y1 = y0; 13795 break; 13796 case "center": 13797 break; // centered by default 13798 // Firefox internally converts position keywords to percentages: 13799 // http://www.w3.org/TR/2010/WD-CSS2-20101207/colors.html#propdef-background-position 13800 default: // percentage or absolute length 13801 // TODO: support absolute start point positions (e.g., use bounds to convert px to a ratio) 13802 var ratio = parseFloat(position, 10) * 1e-2; 13803 if (isNaN(ratio)) { // invalid or unhandled value 13804 break; 13805 } 13806 if (index === 0) { 13807 this.y0 = ratio; 13808 this.y1 = 1 - this.y0; 13809 } else { 13810 this.x0 = ratio; 13811 this.x1 = 1 - this.x0; 13812 } 13813 break; 13814 } 13815 }, this); 13816 } else { 13817 this.y0 = 0; 13818 this.y1 = 1; 13819 } 13820 13821 this.colorStops = imageData.args.slice(hasDirection ? 1 : 0).map(function(colorStop) { 13822 var colorStopMatch = colorStop.match(GradientContainer.REGEXP_COLORSTOP); 13823 var value = +colorStopMatch[2]; 13824 var unit = value === 0 ? "%" : colorStopMatch[3]; // treat "0" as "0%" 13825 return { 13826 color: new Color(colorStopMatch[1]), 13827 // TODO: support absolute stop positions (e.g., compute gradient line length & convert px to ratio) 13828 stop: unit === "%" ? value / 100 : null 13829 }; 13830 }); 13831 13832 if (this.colorStops[0].stop === null) { 13833 this.colorStops[0].stop = 0; 13834 } 13835 13836 if (this.colorStops[this.colorStops.length - 1].stop === null) { 13837 this.colorStops[this.colorStops.length - 1].stop = 1; 13838 } 13839 13840 // calculates and fills-in explicit stop positions when omitted from rule 13841 this.colorStops.forEach(function(colorStop, index) { 13842 if (colorStop.stop === null) { 13843 this.colorStops.slice(index).some(function(find, count) { 13844 if (find.stop !== null) { 13845 colorStop.stop = ((find.stop - this.colorStops[index - 1].stop) / (count + 1)) + this.colorStops[index - 1].stop; 13846 return true; 13847 } else { 13848 return false;
13849 } 13850 }, this); 13851 } 13852 }, this); 13853 } 13854 13855 LinearGradientContainer.prototype = Object.create(GradientContainer.prototype); 13856 13857 // TODO: support <angle> (e.g. -?\d{1,3}(?:\.\d+)deg, etc. : https://developer.mozilla.org/docs/Web/CSS/angle ) 13858 LinearGradientContainer.REGEXP_DIRECTION = /^\s*(?:to|left|right|top|bottom|center|\d{1,3}(?:\.\d+)?%?)(?:\s|$)/i; 13859 13860 module.exports = LinearGradientContainer; 13861 13862 },{"./color":3,"./gradientcontainer":9}],13:[function(_dereq_,module,exports){ 13863 var logger = function() { 13864 if (logger.options.logging && window.console && window.console.log) { 13865 Function.prototype.bind.call(window.console.log, (window.console)).apply(window.console, [(Date.now() - logger.options.start) + "ms", "html2canvas:"].concat([].slice.call(arguments, 0))); 13866 } 13867 }; 13868 13869 logger.options = {logging: false}; 13870 module.exports = logger; 13871 13872 },{}],14:[function(_dereq_,module,exports){ 13873 var Color = _dereq_('./color'); 13874 var utils = _dereq_('./utils'); 13875 var getBounds = utils.getBounds; 13876 var parseBackgrounds = utils.parseBackgrounds; 13877 var offsetBounds = utils.offsetBounds; 13878 13879 function NodeContainer(node, parent) { 13880 this.node = node; 13881 this.parent = parent; 13882 this.stack = null; 13883 this.bounds = null; 13884 this.borders = null; 13885 this.clip = []; 13886 this.backgroundClip = []; 13887 this.offsetBounds = null; 13888 this.visible = null; 13889 this.computedStyles = null; 13890 this.colors = {}; 13891 this.styles = {}; 13892 this.backgroundImages = null; 13893 this.transformData = null; 13894 this.transformMatrix = null; 13895 this.isPseudoElement = false; 13896 this.opacity = null; 13897 } 13898 13899 NodeContainer.prototype.cloneTo = function(stack) { 13900 stack.visible = this.visible; 13901 stack.borders = this.borders; 13902 stack.bounds = this.bounds; 13903 stack.clip = this.clip; 13904 stack.backgroundClip = this.backgroundClip; 13905 stack.computedStyles = this.computedStyles; 13906 stack.styles = this.styles; 13907 stack.backgroundImages = this.backgroundImages; 13908 stack.opacity = this.opacity; 13909 }; 13910 13911 NodeContainer.prototype.getOpacity = function() { 13912 return this.opacity === null ? (this.opacity = this.cssFloat('opacity')) : this.opacity; 13913 }; 13914 13915 NodeContainer.prototype.assignStack = function(stack) { 13916 this.stack = stack; 13917 stack.children.push(this); 13918 }; 13919 13920 NodeContainer.prototype.isElementVisible = function() { 13921 return this.node.nodeType === Node.TEXT_NODE ? this.parent.visible : ( 13922 this.css('display') !== "none" && 13923 this.css('visibility') !== "hidden" && 13924 !this.node.hasAttribute("data-html2canvas-ignore") && 13925 (this.node.nodeName !== "INPUT" || this.node.getAttribute("type") !== "hidden") 13926 ); 13927 }; 13928 13929 NodeContainer.prototype.css = function(attribute) { 13930 if (!this.computedStyles) { 13931 this.computedStyles = this.isPseudoElement ? this.parent.computedStyle(this.before ? ":before" : ":after") : this.computedStyle(null); 13932 } 13933 13934 return this.styles[attribute] || (this.styles[attribute] = this.computedStyles[attribute]); 13935 }; 13936 13937 NodeContainer.prototype.prefixedCss = function(attribute) { 13938 var prefixes = ["webkit", "moz", "ms", "o"]; 13939 var value = this.css(attribute); 13940 if (value === undefined) { 13941 prefixes.some(function(prefix) { 13942 value = this.css(prefix + attribute.substr(0, 1).toUpperCase() + attribute.substr(1)); 13943 return value !== undefined; 13944 }, this); 13945 } 13946 return value === undefined ? null : value; 13947 }; 13948 13949 NodeContainer.prototype.computedStyle = function(type) { 13950 return this.node.ownerDocument.defaultView.getComputedStyle(this.node, type); 13951 }; 13952 13953 NodeContainer.prototype.cssInt = function(attribute) { 13954 var value = parseInt(this.css(attribute), 10); 13955 return (isNaN(value)) ? 0 : value; // borders in old IE are throwing 'medium' for demo.html 13956 }; 13957 13958 NodeContainer.prototype.color = function(attribute) { 13959 return this.colors[attribute] || (this.colors[attribute] = new Color(this.css(attribute))); 13960 }; 13961 13962 NodeContainer.prototype.cssFloat = function(attribute) { 13963 var value = parseFloat(this.css(attribute)); 13964 return (isNaN(value)) ? 0 : value; 13965 }; 13966 13967 NodeContainer.prototype.fontWeight = function() { 13968 var weight = this.css("fontWeight"); 13969 switch(parseInt(weight, 10)){ 13970 case 401: 13971 weight = "bold"; 13972 break; 13973 case 400: 13974 weight = "normal"; 13975 break; 13976 } 13977 return weight; 13978 }; 13979 13980 NodeContainer.prototype.parseClip = function() { 13981 var matches = this.css('clip').match(this.CLIP); 13982 if (matches) { 13983 return { 13984 top: parseInt(matches[1], 10), 13985 right: parseInt(matches[2], 10), 13986 bottom: parseInt(matches[3], 10), 13987 left: parseInt(matches[4], 10) 13988 }; 13989 } 13990 return null; 13991 }; 13992
13993 NodeContainer.prototype.parseBackgroundImages = function() { 13994 return this.backgroundImages || (this.backgroundImages = parseBackgrounds(this.css("backgroundImage"))); 13995 }; 13996 13997 NodeContainer.prototype.cssList = function(property, index) { 13998 var value = (this.css(property) || '').split(','); 13999 value = value[index || 0] || value[0] || 'auto'; 14000 value = value.trim().split(' '); 14001 if (value.length === 1) { 14002 value = [value[0], isPercentage(value[0]) ? 'auto' : value[0]]; 14003 } 14004 return value; 14005 }; 14006 14007 NodeContainer.prototype.parseBackgroundSize = function(bounds, image, index) { 14008 var size = this.cssList("backgroundSize", index); 14009 var width, height; 14010 14011 if (isPercentage(size[0])) { 14012 width = bounds.width * parseFloat(size[0]) / 100; 14013 } else if (/contain|cover/.test(size[0])) { 14014 var targetRatio = bounds.width / bounds.height, currentRatio = image.width / image.height; 14015 return (targetRatio < currentRatio ^ size[0] === 'contain') ? {width: bounds.height * currentRatio, height: bounds.height} : {width: bounds.width, height: bounds.width / currentRatio}; 14016 } else { 14017 width = parseInt(size[0], 10); 14018 } 14019 14020 if (size[0] === 'auto' && size[1] === 'auto') { 14021 height = image.height; 14022 } else if (size[1] === 'auto') { 14023 height = width / image.width * image.height; 14024 } else if (isPercentage(size[1])) { 14025 height = bounds.height * parseFloat(size[1]) / 100; 14026 } else { 14027 height = parseInt(size[1], 10); 14028 } 14029 14030 if (size[0] === 'auto') { 14031 width = height / image.height * image.width; 14032 } 14033 14034 return {width: width, height: height}; 14035 }; 14036 14037 NodeContainer.prototype.parseBackgroundPosition = function(bounds, image, index, backgroundSize) { 14038 var position = this.cssList('backgroundPosition', index); 14039 var left, top; 14040 14041 if (isPercentage(position[0])){ 14042 left = (bounds.width - (backgroundSize || image).width) * (parseFloat(position[0]) / 100); 14043 } else { 14044 left = parseInt(position[0], 10); 14045 } 14046 14047 if (position[1] === 'auto') { 14048 top = left / image.width * image.height; 14049 } else if (isPercentage(position[1])){ 14050 top = (bounds.height - (backgroundSize || image).height) * parseFloat(position[1]) / 100; 14051 } else { 14052 top = parseInt(position[1], 10); 14053 } 14054 14055 if (position[0] === 'auto') { 14056 left = top / image.height * image.width; 14057 } 14058 14059 return {left: left, top: top}; 14060 }; 14061 14062 NodeContainer.prototype.parseBackgroundRepeat = function(index) { 14063 return this.cssList("backgroundRepeat", index)[0]; 14064 }; 14065 14066 NodeContainer.prototype.parseTextShadows = function() { 14067 var textShadow = this.css("textShadow"); 14068 var results = []; 14069 14070 if (textShadow && textShadow !== 'none') { 14071 var shadows = textShadow.match(this.TEXT_SHADOW_PROPERTY); 14072 for (var i = 0; shadows && (i < shadows.length); i++) { 14073 var s = shadows[i].match(this.TEXT_SHADOW_VALUES); 14074 results.push({ 14075 color: new Color(s[0]), 14076 offsetX: s[1] ? parseFloat(s[1].replace('px', '')) : 0, 14077 offsetY: s[2] ? parseFloat(s[2].replace('px', '')) : 0, 14078 blur: s[3] ? s[3].replace('px', '') : 0 14079 }); 14080 } 14081 } 14082 return results; 14083 }; 14084 14085 NodeContainer.prototype.parseTransform = function() { 14086 if (!this.transformData) { 14087 if (this.hasTransform()) { 14088 var offset = this.parseBounds(); 14089 var origin = this.prefixedCss("transformOrigin").split(" ").map(removePx).map(asFloat); 14090 origin[0] += offset.left; 14091 origin[1] += offset.top; 14092 this.transformData = { 14093 origin: origin, 14094 matrix: this.parseTransformMatrix() 14095 }; 14096 } else { 14097 this.transformData = { 14098 origin: [0, 0], 14099 matrix: [1, 0, 0, 1, 0, 0] 14100 }; 14101 } 14102 } 14103 return this.transformData; 14104 }; 14105 14106 NodeContainer.prototype.parseTransformMatrix = function() { 14107 if (!this.transformMatrix) { 14108 var transform = this.prefixedCss("transform"); 14109 var matrix = transform ? parseMatrix(transform.match(this.MATRIX_PROPERTY)) : null; 14110 this.transformMatrix = matrix ? matrix : [1, 0, 0, 1, 0, 0]; 14111 } 14112 return this.transformMatrix; 14113 }; 14114 14115 NodeContainer.prototype.parseBounds = function() { 14116 return this.bounds || (this.bounds = this.hasTransform() ? offsetBounds(this.node) : getBounds(this.node)); 14117 }; 14118 14119 NodeContainer.prototype.hasTransform = function() { 14120 return this.parseTransformMatrix().join(",") !== "1,0,0,1,0,0" || (this.parent && this.parent.hasTransform()); 14121 }; 14122 14123 NodeContainer.prototype.getValue = function() { 14124 var value = this.node.value || ""; 14125 if (this.node.tagName === "SELECT") { 14126 value = selectionValue(this.node); 14127 } else if (this.node.type === "password") { 14128 value = Array(value.length + 1).join('\u2022'); // jshint ignore:line 14129 } 14130 return value.length === 0 ? (this.node.placeholder || "") : value; 14131 }; 14132 14133 NodeContainer.prototype.MATRIX_PROPERTY = /(matrix|matrix3d)\((.+)\)/; 14134 NodeContainer.prototype.TEXT_SHADOW_PROPERTY = /((rgba|rgb)\([^\)]+\)(\s-?\d+px){0,})/g; 14135 NodeContainer.prototype.TEXT_SHADOW_VALUES = /(-?\d+px)|(#.+)|(rgb\(.+\))|(rgba\(.+\))/g; 14136 NodeContainer.prototype.CLIP = /^rect\((\d+)px,? (\d+)px,? (\d+)px,? (\d+)px\)$/; 14137 14138 function selectionValue(node) { 14139 var option = node.options[node.selectedIndex || 0]; 14140 return option ? (option.text || "") : ""; 14141 } 14142 14143 function parseMatrix(match) { 14144 if (match && match[1] === "matrix") { 14145 return match[2].split(",").map(function(s) { 14146 return parseFloat(s.trim()); 14147 }); 14148 } else if (match && match[1] === "matrix3d") { 14149 var matrix3d = match[2].split(",").map(function(s) { 14150 return parseFloat(s.trim()); 14151 }); 14152 return [matrix3d[0], matrix3d[1], matrix3d[4], matrix3d[5], matrix3d[12], matrix3d[13]]; 14153 } 14154 } 14155 14156 function isPercentage(value) { 14157 return value.toString().indexOf("%") !== -1; 14158 } 14159 14160 function removePx(str) { 14161 return str.replace("px", ""); 14162 } 14163 14164 function asFloat(str) { 14165 return parseFloat(str); 14166 } 14167 14168 module.exports = NodeContainer; 14169 14170 },{"./color":3,"./utils":26}],15:[function(_dereq_,module,exports){ 14171 var log = _dereq_('./log'); 14172 var punycode = _dereq_('punycode'); 14173 var NodeContainer = _dereq_('./nodecontainer'); 14174 var TextContainer = _dereq_('./textcontainer'); 14175 var PseudoElementContainer = _dereq_('./pseudoelementcontainer'); 14176 var FontMetrics = _dereq_('./fontmetrics'); 14177 var Color = _dereq_('./color'); 14178 var StackingContext = _dereq_('./stackingcontext'); 14179 var utils = _dereq_('./utils'); 14180 var bind = utils.bind; 14181 var getBounds = utils.getBounds;
14182 var parseBackgrounds = utils.parseBackgrounds; 14183 var offsetBounds = utils.offsetBounds; 14184 14185 function NodeParser(element, renderer, support, imageLoader, options) { 14186 log("Starting NodeParser"); 14187 this.renderer = renderer; 14188 this.options = options; 14189 this.range = null; 14190 this.support = support; 14191 this.renderQueue = []; 14192 this.stack = new StackingContext(true, 1, element.ownerDocument, null); 14193 var parent = new NodeContainer(element, null); 14194 if (options.background) { 14195 renderer.rectangle(0, 0, renderer.width, renderer.height, new Color(options.background)); 14196 } 14197 if (element === element.ownerDocument.documentElement) { 14198 // http://www.w3.org/TR/css3-background/#special-backgrounds 14199 var canvasBackground = new NodeContainer(parent.color('backgroundColor').isTransparent() ? element.ownerDocument.body : element.ownerDocument.documentElement, null); 14200 renderer.rectangle(0, 0, renderer.width, renderer.height, canvasBackground.color('backgroundColor')); 14201 } 14202 parent.visibile = parent.isElementVisible(); 14203 this.createPseudoHideStyles(element.ownerDocument); 14204 this.disableAnimations(element.ownerDocument); 14205 this.nodes = flatten([parent].concat(this.getChildren(parent)).filter(function(container) { 14206 return container.visible = container.isElementVisible(); 14207 }).map(this.getPseudoElements, this)); 14208 this.fontMetrics = new FontMetrics(); 14209 log("Fetched nodes, total:", this.nodes.length); 14210 log("Calculate overflow clips"); 14211 this.calculateOverflowClips(); 14212 log("Start fetching images"); 14213 this.images = imageLoader.fetch(this.nodes.filter(isElement)); 14214 this.ready = this.images.ready.then(bind(function() { 14215 log("Images loaded, starting parsing"); 14216 log("Creating stacking contexts"); 14217 this.createStackingContexts(); 14218 log("Sorting stacking contexts"); 14219 this.sortStackingContexts(this.stack); 14220 this.parse(this.stack); 14221 log("Render queue created with " + this.renderQueue.length + " items"); 14222 return new Promise(bind(function(resolve) { 14223 if (!options.async) { 14224 this.renderQueue.forEach(this.paint, this); 14225 resolve(); 14226 } else if (typeof(options.async) === "function") { 14227 options.async.call(this, this.renderQueue, resolve); 14228 } else if (this.renderQueue.length > 0){ 14229 this.renderIndex = 0; 14230 this.asyncRenderer(this.renderQueue, resolve); 14231 } else { 14232 resolve(); 14233 } 14234 }, this)); 14235 }, this)); 14236 } 14237 14238 NodeParser.prototype.calculateOverflowClips = function() { 14239 this.nodes.forEach(function(container) { 14240 if (isElement(container)) { 14241 if (isPseudoElement(container)) { 14242 container.appendToDOM(); 14243 } 14244 container.borders = this.parseBorders(container); 14245 var clip = (container.css('overflow') === "hidden") ? [container.borders.clip] : []; 14246 var cssClip = container.parseClip(); 14247 if (cssClip && ["absolute", "fixed"].indexOf(container.css('position')) !== -1) { 14248 clip.push([["rect", 14249 container.bounds.left + cssClip.left, 14250 container.bounds.top + cssClip.top, 14251 cssClip.right - cssClip.left, 14252 cssClip.bottom - cssClip.top 14253 ]]); 14254 } 14255 container.clip = hasParentClip(container) ? container.parent.clip.concat(clip) : clip; 14256 container.backgroundClip = (container.css('overflow') !== "hidden") ? c
14256ontainer.clip.concat([container.borders.clip]) : container.clip; 14257 if (isPseudoElement(container)) { 14258 container.cleanDOM(); 14259 } 14260 } else if (isTextNode(container)) { 14261 container.clip = hasParentClip(container) ? container.parent.clip : []; 14262 } 14263 if (!isPseudoElement(container)) { 14264 container.bounds = null; 14265 } 14266 }, this); 14267 }; 14268 14269 function hasParentClip(container) { 14270 return container.parent && container.parent.clip.length; 14271 } 14272 14273 NodeParser.prototype.asyncRenderer = function(queue, resolve, asyncTimer) { 14274 asyncTimer = asyncTimer || Date.now(); 14275 this.paint(queue[this.renderIndex++]); 14276 if (queue.length === this.renderIndex) { 14277 resolve(); 14278 } else if (asyncTimer + 20 > Date.now()) { 14279 this.asyncRenderer(queue, resolve, asyncTimer); 14280 } else { 14281 setTimeout(bind(function() { 14282 this.asyncRenderer(queue, resolve); 14283 }, this), 0); 14284 } 14285 }; 14286 14287 NodeParser.prototype.createPseudoHideStyles = function(document) { 14288 this.createStyles(document, '.' + PseudoElementContainer.prototype.PSEUDO_HIDE_ELEMENT_CLASS_BEFORE + ':before { content: "" !important; display: none !important; }' + 14289 '.' + PseudoElementContainer.prototype.PSEUDO_HIDE_ELEMENT_CLASS_AFTER + ':after { content: "" !important; display: none !important; }'); 14290 }; 14291 14292 NodeParser.prototype.disableAnimations = function(document) { 14293 this.createStyles(document, '* { -webkit-animation: none !important; -moz-animation: none !important; -o-animation: none !important; animation: none !important; ' + 14294 '-webkit-transition: none !important; -moz-transition: none !important; -o-transition: none !important; transition: none !important;}'); 14295 }; 14296 14297 NodeParser.prototype.createStyles = function(document, styles) { 14298 var hidePseudoElements = document.createElement('style'); 14299 hidePseudoElements.innerHTML = styles; 14300 document.body.appendChild(hidePseudoElements); 14301 }; 14302 14303 NodeParser.prototype.getPseudoElements = function(container) { 14304 var nodes = [[container]]; 14305 if (container.node.nodeType === Node.ELEMENT_NODE) { 14306 var before = this.getPseudoElement(container, ":before"); 14307 var after = this.getPseudoElement(container, ":after"); 14308 14309 if (before) { 14310 nodes.push(before); 14311 } 14312 14313 if (after) { 14314 nodes.push(after); 14315 } 14316 } 14317 return flatten(nodes); 14318 }; 14319 14320 function toCamelCase(str) { 14321 return str.replace(/(\-[a-z])/g, function(match){ 14322 return match.toUpperCase().replace('-',''); 14323 }); 14324 } 14325 14326 NodeParser.prototype.getPseudoElement = function(container, type) { 14327 var style = container.computedStyle(type); 14328 if(!style || !style.content || style.content === "none" || style.content === "-moz-alt-content" || style.display === "none") { 14329 return null; 14330 } 14331 14332 var content = stripQuotes(style.content); 14333 var isImage = content.substr(0, 3) === 'url'; 14334 var pseudoNode = document.createElement(isImage ? 'img' : 'html2canvaspseudoelement'); 14335 var pseudoContainer = new PseudoElementContainer(pseudoNode, container, type); 14336 14337 for (var i = style.length-1; i >= 0; i--) { 14338 var property = toCamelCase(style.item(i)); 14339 pseudoNode.style[property] = style[property]; 14340 } 14341 14342 pseudoNode.className = PseudoElementContainer.prototype.PSEUDO_HIDE_ELEMENT_CLASS_BEFORE + " " + PseudoElementContainer.prototype.PSEUDO_HIDE_ELEMENT_CLASS_AFTER; 14343 14344 if (isImage) {
14345 pseudoNode.src = parseBackgrounds(content)[0].args[0]; 14346 return [pseudoContainer]; 14347 } else { 14348 var text = document.createTextNode(content); 14349 pseudoNode.appendChild(text); 14350 return [pseudoContainer, new TextContainer(text, pseudoContainer)]; 14351 } 14352 }; 14353 14354 14355 NodeParser.prototype.getChildren = function(parentContainer) { 14356 return flatten([].filter.call(parentContainer.node.childNodes, renderableNode).map(function(node) { 14357 var container = [node.nodeType === Node.TEXT_NODE ? new TextContainer(node, parentContainer) : new NodeContainer(node, parentContainer)].filter(nonIgnoredElement); 14358 return node.nodeType === Node.ELEMENT_NODE && container.length && node.tagName !== "TEXTAREA" ? (container[0].isElementVisible() ? container.concat(this.getChildren(container[0])) : []) : container; 14359 }, this)); 14360 }; 14361 14362 NodeParser.prototype.newStackingContext = function(container, hasOwnStacking) { 14363 var stack = new StackingContext(hasOwnStacking, container.getOpacity(), container.node, container.parent); 14364 container.cloneTo(stack); 14365 var parentStack = hasOwnStacking ? stack.getParentStack(this) : stack.parent.stack; 14366 parentStack.contexts.push(stack); 14367 container.stack = stack; 14368 }; 14369 14370 NodeParser.prototype.createStackingContexts = function() { 14371 this.nodes.forEach(function(container) { 14372 if (isElement(container) && (this.isRootElement(container) || hasOpacity(container) || isPositionedForStacking(container) || this.isBodyWithTransparentRoot(container) || container.hasTransform())) { 14373 this.newStackingContext(container, true); 14374 } else if (isElement(container) && ((isPositioned(container) && zIndex0(container)) || isInlineBlock(container) || isFloating(container))) { 14375 this.newStackingContext(container, false); 14376 } else { 14377 container.assignStack(container.parent.stack); 14378 } 14379 }, this); 14380 }; 14381 14382 NodeParser.prototype.isBodyWithTransparentRoot = function(container) { 14383 return container.node.nodeName === "BODY" && container.parent.color('backgroundColor').isTransparent(); 14384 }; 14385 14386 NodeParser.prototype.isRootElement = function(container) { 14387 return container.parent === null; 14388 }; 14389 14390 NodeParser.prototype.sortStackingContexts = function(stack) { 14391 stack.contexts.sort(zIndexSort(stack.contexts.slice(0)));
14392 stack.contexts.forEach(this.sortStackingContexts, this); 14393 }; 14394 14395 NodeParser.prototype.parseTextBounds = function(container) { 14396 return function(text, index, textList) { 14397 if (container.parent.css("textDecoration").substr(0, 4) !== "none" || text.trim().length !== 0) { 14398 if (this.support.rangeBounds && !container.parent.hasTransform()) { 14399 var offset = textList.slice(0, index).join("").length; 14400 return this.getRangeBounds(container.node, offset, text.length); 14401 } else if (container.node && typeof(container.node.data) === "string") { 14402 var replacementNode = container.node.splitText(text.length); 14403 var bounds = this.getWrapperBounds(container.node, container.parent.hasTransform()); 14404 container.node = replacementNode; 14405 return bounds; 14406 } 14407 } else if(!this.support.rangeBounds || container.parent.hasTransform()){ 14408 container.node = container.node.splitText(text.length); 14409 } 14410 return {}; 14411 }; 14412 }; 14413 14414 NodeParser.prototype.getWrapperBounds = function(node, transform) { 14415 var wrapper = node.ownerDocument.createElement('html2canvaswrapper'); 14416 var parent = node.parentNode, 14417 backupText = node.cloneNode(true); 14418 14419 wrapper.appendChild(node.cloneNode(true)); 14420 parent.replaceChild(wrapper, node); 14421 var bounds = transform ? offsetBounds(wrapper) : getBounds(wrapper); 14422 parent.replaceChild(backupText, wrapper); 14423 return bounds; 14424 }; 14425 14426 NodeParser.prototype.getRangeBounds = function(node, offset, length) { 14427 var range = this.range || (this.range = node.ownerDocument.createRange()); 14428 range.setStart(node, offset); 14429 range.setEnd(node, offset + length); 14430 return range.getBoundingClientRect(); 14431 }; 14432 14433 function ClearTransform() {} 14434 14435 NodeParser.prototype.parse = function(stack) { 14436 // http://www.w3.org/TR/CSS21/visuren.html#z-index 14437 var negativeZindex = stack.contexts.filter(negativeZIndex); // 2. the child stacking contexts with negative stack levels (most negative first). 14438 var descendantElements = stack.children.filter(isElement); 14439 var descendantNonFloats = descendantElements.filter(not(isFloating)); 14440 var nonInlineNonPositionedDescendants = descendantNonFloats.filter(not(isPositioned)).filter(not(inlineLevel)); // 3 the in-flow, non-inline-level, non-positioned descendants. 14441 var nonPositionedFloats = descendantElements.filter(not(isPositioned)).filter(isFloating); // 4. the non-positioned floats. 14442 var inFlow = descendantNonFloats.filter(not(isPositioned)).filter(inlineLevel); // 5. the in-flow, inline-level, non-positioned descendants, including inline tables and inline blocks. 14443 var stackLevel0 = stack.contexts.concat(descendantNonFloats.filter(isPositioned)).filter(zIndex0); // 6. the child stacking contexts with stack level 0 and the positioned descendants with stack level 0. 14444 var text = stack.children.filter(isTextNode).filter(hasText); 14445 var positiveZindex = stack.contexts.filter(positiveZIndex); // 7. the child stacking contexts with positive stack levels (least positive first). 14446 negativeZindex.concat(nonInlineNonPositionedDescendants).concat(nonPositionedFloats) 14447 .concat(inFlow).concat(stackLevel0).concat(text).concat(positiveZindex).forEach(function(container) { 14448 this.renderQueue.push(container); 14449 if (isStackingContext(container)) { 14450 this.parse(container); 14451 this.renderQueue.push(new ClearTransform()); 14452 } 14453 }, this); 14454 }; 14455 14456 NodeParser.prototype.paint = function(container) { 14457 try { 14458 if (container instanceof ClearTransform) {
14459 this.renderer.ctx.restore(); 14460 } else if (isTextNode(container)) { 14461 if (isPseudoElement(container.parent)) { 14462 container.parent.appendToDOM(); 14463 } 14464 this.paintText(container); 14465 if (isPseudoElement(container.parent)) { 14466 container.parent.cleanDOM(); 14467 } 14468 } else { 14469 this.paintNode(container); 14470 } 14471 } catch(e) { 14472 log(e); 14473 if (this.options.strict) { 14474 throw e; 14475 } 14476 } 14477 }; 14478 14479 NodeParser.prototype.paintNode = function(container) { 14480 if (isStackingContext(container)) { 14481 this.renderer.setOpacity(container.opacity); 14482 this.renderer.ctx.save(); 14483 if (container.hasTransform()) { 14484 this.renderer.setTransform(container.parseTransform()); 14485 } 14486 } 14487 14488 if (container.node.nodeName === "INPUT" && container.node.type === "checkbox") { 14489 this.paintCheckbox(container); 14490 } else if (container.node.nodeName === "INPUT" && container.node.type === "radio") { 14491 this.paintRadio(container); 14492 } else { 14493 this.paintElement(container); 14494 } 14495 }; 14496 14497 NodeParser.prototype.paintElement = function(container) { 14498 var bounds = container.parseBounds(); 14499 this.renderer.clip(container.backgroundClip, function() { 14500 this.renderer.renderBackground(container, bounds, container.borders.borders.map(getWidth)); 14501 }, this); 14502 14503 this.renderer.clip(container.clip, function() { 14504 this.renderer.renderBorders(container.borders.borders); 14505 }, this); 14506 14507 this.renderer.clip(container.backgroundClip, function() { 14508 switch (container.node.nodeName) { 14509 case "svg": 14510 case "IFRAME": 14511 var imgContainer = this.images.get(container.node); 14512 if (imgContainer) { 14513 this.renderer.renderImage(container, bounds, container.borders, imgContainer); 14514 } else { 14515 log("Error loading <" + container.node.nodeName + ">", container.node); 14516 } 14517 break; 14518 case "IMG": 14519 var imageContainer = this.images.get(container.node.src); 14520 if (imageContainer) { 14521 this.renderer.renderImage(container, bounds, container.borders, imageContainer); 14522 } else { 14523 log("Error loading <img>", container.node.src); 14524 } 14525 break; 14526 case "CANVAS": 14527 this.renderer.renderImage(container, bounds, container.borders, {image: container.node}); 14528 break; 14529 case "SELECT": 14530 case "INPUT": 14531 case "TEXTAREA": 14532 this.paintFormValue(container); 14533 break; 14534 } 14535 }, this); 14536 }; 14537 14538 NodeParser.prototype.paintCheckbox = function(container) { 14539 var b = container.parseBounds(); 14540 14541 var size = Math.min(b.width, b.height); 14542 var bounds = {width: size - 1, height: size - 1, top: b.top, left: b.left}; 14543 var r = [3, 3]; 14544 var radius = [r, r, r, r]; 14545 var borders = [1,1,1,1].map(function(w) { 14546 return {color: new Color('#A5A5A5'), width: w}; 14547 }); 14548 14549 var borderPoints = calculateCurvePoints(bounds, radius, borders); 14550 14551 this.renderer.clip(container.backgroundClip, function() { 14552 this.renderer.rectangle(bounds.left + 1, bounds.top + 1, bounds.width - 2, bounds.height - 2, new Color("#DEDEDE")); 14553 this.renderer.renderBorders(calculateBorders(borders, bounds, borderPoints, radius)); 14554 if (container.node.checked) { 14555 this.renderer.font(new Color('#424242'), 'normal', 'normal', 'bold', (size - 3) + "px", 'arial'); 14556 this.renderer.text("\u2714", bounds.left + size / 6, bounds.top + size - 1); 14557 } 14558 }, this); 14559 }; 14560 14561 NodeParser.prototype.paintRadio = function(container) { 14562 var bounds = container.parseBounds(); 14563 14564 var size = Math.min(bounds.width, bounds.height) - 2; 14565 14566 this.renderer.clip(container.backgroundClip, function() { 14567 this.renderer.circleStroke(bounds.left + 1, bounds.top + 1, size, new Color('#DEDEDE'), 1, new Color('#A5A5A5')); 14568 if (container.node.checked) { 14569 this.renderer.circle(Math.ceil(bounds.left + size / 4) + 1, Math.ceil(bounds.top + size / 4) + 1, Math.floor(size / 2), new Color('#424242')); 14570 } 14571 }, this); 14572 }; 14573 14574 NodeParser.prototype.paintFormValue = function(container) { 14575 var value = container.getValue(); 14576 if (value.length > 0) { 14577 var document = container.node.ownerDocument; 14578 var wrapper = document.createElement('html2canvaswrapper'); 14579 var properties = ['lineHeight', 'textAlign', 'fontFamily', 'fontWeight', 'fontSize', 'color', 14580 'paddingLeft', 'paddingTop', 'paddingRight', 'paddingBottom', 14581 'width', 'height', 'borderLeftStyle', 'borderTopStyle', 'borderLeftWidth', 'borderTopWidth', 14582 'boxSizing', 'whiteSpace', 'wordWrap']; 14583
14584 properties.forEach(function(property) { 14585 try { 14586 wrapper.style[property] = container.css(property); 14587 } catch(e) { 14588 // Older IE has issues with "border" 14589 log("html2canvas: Parse: Exception caught in renderFormValue: " + e.message); 14590 } 14591 }); 14592 var bounds = container.parseBounds(); 14593 wrapper.style.position = "fixed"; 14594 wrapper.style.left = bounds.left + "px"; 14595 wrapper.style.top = bounds.top + "px"; 14596 wrapper.textContent = value; 14597 document.body.appendChild(wrapper); 14598 this.paintText(new TextContainer(wrapper.firstChild, container)); 14599 document.body.removeChild(wrapper); 14600 } 14601 }; 14602 14603 NodeParser.prototype.paintText = function(container) { 14604 container.applyTextTransform(); 14605 var characters = punycode.ucs2.decode(container.node.data); 14606 var textList = (!this.options.letterRendering || noLetterSpacing(container)) && !hasUnicode(container.node.data) ? getWords(characters) : characters.map(function(character) { 14607 return punycode.ucs2.encode([character]); 14608 }); 14609 14610 var weight = container.parent.fontWeight(); 14611 var size = container.parent.css('fontSize'); 14612 var family = container.parent.css('fontFamily'); 14613 var shadows = container.parent.parseTextShadows(); 14614 14615 this.renderer.font(container.parent.color('color'), container.parent.css('fontStyle'), container.parent.css('fontVariant'), weight, size, family); 14616 if (shadows.length) { 14617 // TODO: support multiple text shadows 14618 this.renderer.fontShadow(shadows[0].color, shadows[0].offsetX, shadows[0].offsetY, shadows[0].blur); 14619 } else { 14620 this.renderer.clearShadow(); 14621 } 14622 14623 this.renderer.clip(container.parent.clip, function() { 14624 textList.map(this.parseTextBounds(container), this).forEach(function(bounds, index) { 14625 if (bounds) { 14626 this.renderer.text(textList[index], bounds.left, bounds.bottom); 14627 this.renderTextDecoration(container.parent, bounds, this.fontMetrics.getMetrics(family, size)); 14628 } 14629 }, this); 14630 }, this); 14631 }; 14632 14633 NodeParser.prototype.renderTextDecoration = function(container, bounds, metrics) { 14634 switch(container.css("textDecoration").split(" ")[0]) { 14635 case "underline": 14636 // Draws a line at the baseline of the font 14637 // TODO As some browsers display the line as more than 1px if the font-size is big, need to take that into account both in position and size 14638 this.renderer.rectangle(bounds.left, Math.round(bounds.top + metrics.baseline + metrics.lineWidth), bounds.width, 1, container.color("color")); 14639 break; 14640 case "overline": 14641 this.renderer.rectangle(bounds.left, Math.round(bounds.top), bounds.width, 1, container.color("color")); 14642 break; 14643 case "line-through": 14644 // TODO try and find exact position for line-through 14645 this.renderer.rectangle(bounds.left, Math.ceil(bounds.top + metrics.middle + metrics.lineWidth), bounds.width, 1, container.color("color")); 14646 break; 14647 } 14648 }; 14649 14650 var borderColorTransforms = { 14651 inset: [ 14652 ["darken", 0.60], 14653 ["darken", 0.10], 14654 ["darken", 0.10], 14655 ["darken", 0.60] 14656 ] 14657 }; 14658 14659 NodeParser.prototype.parseBorders = function(container) { 14660 var nodeBounds = container.parseBounds(); 14661 var radius = getBorderRadiusData(container); 14662 var borders = ["Top", "Right", "Bottom", "Left"].map(function(side, index) { 14663 var style = container.css('border' + side + 'Style'); 14664 var color = container.color('border' + side + 'Color'); 14665 if (style === "inset" && color.isBlack()) { 14666 color = new Color([255, 255, 255, color.a]); // this is wrong, but 14667 } 14668 var colorTransform = borderColorTransforms[style] ? borderColorTransforms[style][index] : null; 14669 return { 14670 width: container.cssInt('border' + side + 'Width'), 14671 color: colorTransform ? color[colorTransform[0]](colorTransform[1]) : color, 14672 args: null 14673 }; 14674 }); 14675 var borderPoints = calculateCurvePoints(nodeBounds, radius, borders); 14676 14677 return {
14678 clip: this.parseBackgroundClip(container, borderPoints, borders, radius, nodeBounds), 14679 borders: calculateBorders(borders, nodeBounds, borderPoints, radius) 14680 }; 14681 }; 14682 14683 function calculateBorders(borders, nodeBounds, borderPoints, radius) { 14684 return borders.map(function(border, borderSide) { 14685 if (border.width > 0) { 14686 var bx = nodeBounds.left; 14687 var by = nodeBounds.top; 14688 var bw = nodeBounds.width; 14689 var bh = nodeBounds.height - (borders[2].width); 14690 14691 switch(borderSide) { 14692 case 0: 14693 // top border 14694 bh = borders[0].width; 14695 border.args = drawSide({ 14696 c1: [bx, by], 14697 c2: [bx + bw, by], 14698 c3: [bx + bw - borders[1].width, by + bh], 14699 c4: [bx + borders[3].width, by + bh] 14700 }, radius[0], radius[1], 14701 borderPoints.topLeftOuter, borderPoints.topLeftInner, borderPoints.topRightOuter, borderPoints.topRightInner); 14702 break; 14703 case 1: 14704 // right border 14705 bx = nodeBounds.left + nodeBounds.width - (borders[1].width); 14706 bw = borders[1].width; 14707 14708 border.args = drawSide({ 14709 c1: [bx + bw, by], 14710 c2: [bx + bw, by + bh + borders[2].width], 14711 c3: [bx, by + bh], 14712 c4: [bx, by + borders[0].width] 14713 }, radius[1], radius[2], 14714 borderPoints.topRightOuter, borderPoints.topRightInner, borderPoints.bottomRightOuter, borderPoints.bottomRightInner); 14715 break; 14716 case 2: 14717 // bottom border 14718 by = (by + nodeBounds.height) - (borders[2].width); 14719 bh = borders[2].width; 14720 border.args = drawSide({ 14721 c1: [bx + bw, by + bh], 14722 c2: [bx, by + bh], 14723 c3: [bx + borders[3].width, by], 14724 c4: [bx + bw - borders[3].width, by] 14725 }, radius[2], radius[3], 14726 borderPoints.bottomRightOuter, borderPoints.bottomRightInner, borderPoints.bottomLeftOuter, borderPoints.bottomLeftInner); 14727 break; 14728 case 3: 14729 // left border 14730 bw = borders[3].width; 14731 border.args = drawSide({ 14732 c1: [bx, by + bh + borders[2].width], 14733 c2: [bx, by], 14734 c3: [bx + bw, by + borders[0].width], 14735 c4: [bx + bw, by + bh] 14736 }, radius[3], radius[0], 14737 borderPoints.bottomLeftOuter, borderPoints.bottomLeftInner, borderPoints.topLeftOuter, borderPoints.topLeftInner); 14738 break; 14739 } 14740 } 14741 return border; 14742 }); 14743 } 14744 14745 NodeParser.prototype.parseBackgroundClip = function(container, borderPoints, borders, radius, bounds) { 14746 var backgroundClip = container.css('backgroundClip'), 14747 borderArgs = []; 14748 14749 switch(backgroundClip) { 14750 case "content-box": 14751 case "padding-box": 14752 parseCorner(borderArgs, radius[0], radius[1], borderPoints.topLeftInner, borderPoints.topRightInner, bounds.left + borders[3].width, bounds.top + borders[0].width); 14753 parseCorner(borderArgs, radius[1], radius[2], borderPoints.topRightInner, borderPoints.bottomRightInner, bounds.left + bounds.width - borders[1].width, bounds.top + borders[0].width); 14754 parseCorner(borderArgs, radius[2], radius[3], borderPoints.bottomRightInner, borderPoints.bottomLeftInner, bounds.left + bounds.width - borders[1].width, bounds.top + bounds.height - borders[2].width); 14755 parseCorner(borderArgs, radius[3], radius[0], borderPoints.bottomLeftInner, borderPoints.topLeftInner, bounds.left + borders[3].width, bounds.top + bounds.height - borders[2].width); 14756 break; 14757 14758 default: 14759 parseCorner(borderArgs, radius[0], radius[1], borderPoints.topLeftOuter, borderPoints.topRightOuter, bounds.left, bounds.top); 14760 parseCorner(borderArgs, radius[1], radius[2], borderPoints.topRightOuter, borderPoints.bottomRightOuter, bounds.left + bounds.width, bounds.top); 14761 parseCorner(borderArgs, radius[2], radius[3], borderPoints.bottomRightOuter, borderPoints.bottomLeftOuter, bounds.left + bounds.width, bounds.top + bounds.height); 14762 parseCorner(borderArgs, radius[3], radius[0], borderPoints.bottomLeftOuter, borderPoints.topLeftOuter, bounds.left, bounds.top + bounds.height); 14763 break; 14764 } 14765 14766 return borderArgs; 14767 }; 14768 14769 function getCurvePoints(x, y, r1, r2) { 14770 var kappa = 4 * ((Math.sqrt(2) - 1) / 3); 14771 var ox = (r1) * kappa, // control point offset horizontal 14772 oy = (r2) * kappa, // control point offset vertical 14773 xm = x + r1, // x-middle 14774 ym = y + r2; // y-middle 14775 return { 14776 topLeft: bezierCurve({x: x, y: ym}, {x: x, y: ym - oy}, {x: xm - ox, y: y}, {x: xm, y: y}), 14777 topRight: bezierCurve({x: x, y: y}, {x: x + ox,y: y}, {x: xm, y: ym - oy}, {x: xm, y: ym}), 14778 bottomRight: bezierCurve({x: xm, y: y}, {x: xm, y: y + oy}, {x: x + ox, y: ym}, {x: x, y: ym}), 14779 bottomLeft: bezierCurve({x: xm, y: ym}, {x: xm - ox, y: ym}, {x: x, y: y + oy}, {x: x, y:y}) 14780 }; 14781 } 14782 14783 function calculateCurvePoints(bounds, borderRadius, borders) { 14784 var x = bounds.left, 14785 y = bounds.top, 14786 width = bounds.width, 14787 height = bounds.height, 14788 14789 tlh = borderRadius[0][0] < width / 2 ? borderRadius[0][0] : width / 2, 14790 tlv = borderRadius[0][1] < height / 2 ? borderRadius[0][1] : height / 2, 14791 trh = borderRadius[1][0] < width / 2 ? borderRadius[1][0] : width / 2, 14792 trv = borderRadius[1][1] < height / 2 ? borderRadius[1][1] : height / 2, 14793 brh = borderRadius[2][0] < width / 2 ? borderRadius[2][0] : width / 2, 14794 brv = borderRadius[2][1] < height / 2 ? borderRadius[2][1] : height / 2, 14795 blh = borderRadius[3][0] < width / 2 ? borderRadius[3][0] : width / 2, 14796 blv = borderRadius[3][1] < height / 2 ? borderRadius[3][1] : height / 2; 14797 14798 var topWidth = width - trh, 14799 rightHeight = height - brv, 14800 bottomWidth = width - brh, 14801 leftHeight = height - blv; 14802 14803 return { 14804 topLeftOuter: getCurvePoints(x, y, tlh, tlv).topLeft.subdivide(0.5), 14805 topLeftInner: getCurvePoints(x + borders[3].width, y + borders[0].width, Math.max(0, tlh - borders[3].width), Math.max(0, tlv - borders[0].width)).topLeft.subdivide(0.5), 14806 topRightOuter: getCurvePoints(x + topWidth, y, trh, trv).topRight.subdivide(0.5), 14807 topRightInner: getCurvePoints(x + Math.min(topWidth, width + borders[3].width), y + borders[0].width, (topWidth > width + borders[3].width) ? 0 :trh - borders[3].width, trv - borders[0].width).topRight.subdivide(0.5), 14808 bottomRightOuter: getCurvePoints(x + bottomWidth, y + rightHeight, brh, brv).bottomRight.subdivide(0.5), 14809 bottomRightInner: getCurvePoints(x + Math.min(bottomWidth, width - borders[3].width), y + Math.min(rightHeight, height + borders[0].width), Math.max(0, brh - borders[1].width), brv - borders[2].width).bottomRight.subdivide(0.5), 14810 bottomLeftOuter: getCurvePoints(x, y + leftHeight, blh, blv).bottomLeft.subdivide(0.5), 14811 bottomLeftInner: getCurvePoints(x + borders[3].width, y + leftHeight, Math.max(0, blh - borders[3].width), blv - borders[2].width).bottomLeft.subdivide(0.5) 14812 }; 14813 } 14814 14815 function bezierCurve(start, startControl, endControl, end) { 14816 var lerp = function (a, b, t) { 14817 return { 14818 x: a.x + (b.x - a.x) * t, 14819 y: a.y + (b.y - a.y) * t 14820 }; 14821 }; 14822 14823 return { 14824 start: start, 14825 startControl: startControl, 14826 endControl: endControl, 14827 end: end, 14828 subdivide: function(t) { 14829 var ab = lerp(start, startControl, t), 14830 bc = lerp(startControl, endControl, t), 14831 cd = lerp(endControl, end, t), 14832 abbc = lerp(ab, bc, t), 14833 bccd = lerp(bc, cd, t), 14834 dest = lerp(abbc, bccd, t); 14835 return [bezierCurve(start, ab, abbc, dest), bezierCurve(dest, bccd, cd, end)]; 14836 }, 14837 curveTo: function(borderArgs) { 14838 borderArgs.push(["bezierCurve", startControl.x, startControl.y, endControl.x, endControl.y, end.x, end.y]); 14839 }, 14840 curveToReversed: function(borderArgs) { 14841 borderArgs.push(["bezierCurve", endControl.x, endControl.y, startControl.x, startControl.y, start.x, start.y]); 14842 } 14843 }; 14844 } 14845 14846 function drawSide(borderData, radius1, radius2, outer1, inner1, outer2, inner2) { 14847 var borderArgs = []; 14848 14849 if (radius1[0] > 0 || radius1[1] > 0) { 14850 borderArgs.push(["line", outer1[1].start.x, outer1[1].start.y]); 14851 outer1[1].curveTo(borderArgs); 14852 } else { 14853 borderArgs.push([ "line", borderData.c1[0], borderData.c1[1]]); 14854 } 14855 14856 if (radius2[0] > 0 || radius2[1] > 0) { 14857 borderArgs.push(["line", outer2[0].start.x, outer2[0].start.y]); 14858 outer2[0].curveTo(borderArgs); 14859 borderArgs.push(["line", inner2[0].end.x, inner2[0].end.y]); 14860 inner2[0].curveToReversed(borderArgs); 14861 } else { 14862 borderArgs.push(["line", borderData.c2[0], borderData.c2[1]]); 14863 borderArgs.push(["line", borderData.c3[0], borderData.c3[1]]); 14864 } 14865 14866 if (radius1[0] > 0 || radius1[1] > 0) { 14867 borderArgs.push(["line", inner1[1].end.x, inner1[1].end.y]); 14868 inner1[1].curveToReversed(borderArgs); 14869 } else { 14870 borderArgs.push(["line", borderData.c4[0], borderData.c4[1]]); 14871 } 14872 14873 return borderArgs; 14874 } 14875 14876 function parseCorner(borderArgs, radius1, radius2, corner1, corner2, x, y) { 14877 if (radius1[0] > 0 || radius1[1] > 0) { 14878 borderArgs.push(["line", corner1[0].start.x, c
14878orner1[0].start.y]); 14879 corner1[0].curveTo(borderArgs); 14880 corner1[1].curveTo(borderArgs); 14881 } else { 14882 borderArgs.push(["line", x, y]); 14883 } 14884 14885 if (radius2[0] > 0 || radius2[1] > 0) { 14886 borderArgs.push(["line", corner2[0].start.x, corner2[0].start.y]); 14887 } 14888 } 14889 14890 function negativeZIndex(container) { 14891 return container.cssInt("zIndex") < 0; 14892 } 14893 14894 function positiveZIndex(container) { 14895 return container.cssInt("zIndex") > 0; 14896 } 14897 14898 function zIndex0(container) { 14899 return container.cssInt("zIndex") === 0; 14900 } 14901 14902 function inlineLevel(container) { 14903 return ["inline", "inline-block", "inline-table"].indexOf(container.css("display")) !== -1; 14904 } 14905 14906 function isStackingContext(container) { 14907 return (container instanceof StackingContext); 14908 } 14909 14910 function hasText(container) { 14911 return container.node.data.trim().length > 0; 14912 } 14913 14914 function noLetterSpacing(container) { 14915 return (/^(normal|none|0px)$/.test(container.parent.css("letterSpacing"))); 14916 } 14917 14918 function getBorderRadiusData(container) { 14919 return ["TopLeft", "TopRight", "BottomRight", "BottomLeft"].map(function(side) { 14920 var value = container.css('border' + side + 'Radius'); 14921 var arr = value.split(" "); 14922 if (arr.length <= 1) { 14923 arr[1] = arr[0]; 14924 } 14925 return arr.map(asInt); 14926 }); 14927 } 14928 14929 function renderableNode(node) { 14930 return (node.nodeType === Node.TEXT_NODE || node.nodeType === Node.ELEMENT_NODE); 14931 } 14932 14933 function isPositionedForStacking(container) { 14934 var position = container.css("position"); 14935 var zIndex = (["absolute", "relative", "fixed"].indexOf(position) !== -1) ? container.css("zIndex") : "auto"; 14936 return zIndex !== "auto"; 14937 } 14938 14939 function isPositioned(container) { 14940 return container.css("position") !== "static"; 14941 } 14942 14943 function isFloating(container) { 14944 return container.css("float") !== "none"; 14945 } 14946 14947 function isInlineBlock(container) { 14948 return ["inline-block", "inline-table"].indexOf(container.css("display")) !== -1; 14949 } 14950 14951 function not(callback) { 14952 var context = this; 14953 return function() { 14954 return !callback.apply(context, arguments); 14955 }; 14956 } 14957 14958 function isElement(container) { 14959 return container.node.nodeType === Node.ELEMENT_NODE; 14960 } 14961 14962 function isPseudoElement(container) { 14963 return container.isPseudoElement === true; 14964 } 14965 14966 function isTextNode(container) { 14967 return container.node.nodeType === Node.TEXT_NODE; 14968 } 14969 14970 function zIndexSort(contexts) { 14971 return function(a, b) { 14972 return (a.cssInt("zIndex") + (contexts.indexOf(a) / contexts.length)) - (b.cssInt("zIndex") + (contexts.indexOf(b) / contexts.length)); 14973 }; 14974 } 14975 14976 function hasOpacity(container) { 14977 return container.getOpacity() < 1; 14978 } 14979 14980 function asInt(value) { 14981 return parseInt(value, 10); 14982 } 14983 14984 function getWidth(border) { 14985 return border.width; 14986 } 14987 14988 function nonIgnoredElement(nodeContainer) { 14989 return (nodeContainer.node.nodeType !== Node.ELEMENT_NODE || ["SCRIPT", "HEAD", "TITLE", "OBJECT", "BR", "OPTION"].indexOf(nodeContainer.node.nodeName) === -1); 14990 } 14991 14992 function flatten(arrays) { 14993 return [].concat.apply([], arrays); 14994 } 14995 14996 function stripQuotes(content) { 14997 var first = content.substr(0, 1); 14998 return (first === content.substr(content.length - 1) && first.match(/'|"/)) ? content.substr(1, content.length - 2) : content; 14999 } 15000 15001 function getWords(characters) { 15002 var words = [], i = 0, onWordBoundary = false, word; 15003 while(characters.length) { 15004 if (isWordBoundary(characters[i]) === onWordBoundary) { 15005 word = characters.splice(0, i); 15006 if (word.length) { 15007 words.push(punycode.ucs2.encode(word)); 15008 } 15009 onWordBoundary =! onWordBoundary; 15010 i = 0; 15011 } else { 15012 i++; 15013 } 15014 15015 if (i >= characters.length) { 15016 word = characters.splice(0, i); 15017 if (word.length) { 15018 words.push(punycode.ucs2.encode(word)); 15019 } 15020 } 15021 } 15022 return words; 15023 } 15024 15025 function isWordBoundary(characterCode) { 15026 return [ 15027 32, // <space> 15028 13, // \r 15029 10, // \n 15030 9, // \t 15031 45 // - 15032 ].indexOf(characterCode) !== -1; 15033 } 15034 15035 function hasUnicode(string) { 15036 return (/[^\u0000-\u00ff]/).test(string); 15037 } 15038 15039 module.exports = NodeParser; 15040 15041 },{"./color":3,"./fontmetrics":7,"./log":13,"./nodecontainer":14,"./pseudoelementcontainer":18,"./stackingcontext":21,"./textcontainer":25,"./utils":26,"pu
15041nycode":1}],16:[function(_dereq_,module,exports){ 15042 var XHR = _dereq_('./xhr'); 15043 var utils = _dereq_('./utils'); 15044 var log = _dereq_('./log'); 15045 var createWindowClone = _dereq_('./clone'); 15046 var decode64 = utils.decode64; 15047 15048 function Proxy(src, proxyUrl, document) { 15049 var supportsCORS = ('withCredentials' in new XMLHttpRequest()); 15050 if (!proxyUrl) { 15051 return Promise.reject("No proxy configured"); 15052 } 15053 var callback = createCallback(supportsCORS); 15054 var url = createProxyUrl(proxyUrl, src, callback); 15055 15056 return supportsCORS ? XHR(url) : (jsonp(document, url, callback).then(function(response) { 15057 return decode64(response.content); 15058 })); 15059 } 15060 var proxyCount = 0; 15061 15062 function ProxyURL(src, proxyUrl, document) { 15063 var supportsCORSImage = ('crossOrigin' in new Image()); 15064 var callback = createCallback(supportsCORSImage); 15065 var url = createProxyUrl(proxyUrl, src, callback); 15066 return (supportsCORSImage ? Promise.resolve(url) : jsonp(document, url, callback).then(function(response) { 15067 return "data:" + response.type + ";base64," + response.content; 15068 })); 15069 } 15070 15071 function jsonp(document, url, callback) { 15072 return new Promise(function(resolve, reject) { 15073 var s = document.createElement("script"); 15074 var cleanup = function() { 15075 delete window.html2canvas.proxy[callback]; 15076 document.body.removeChild(s); 15077 }; 15078 window.html2canvas.proxy[callback] = function(response) { 15079 cleanup(); 15080 resolve(response); 15081 }; 15082 s.src = url; 15083 s.onerror = function(e) { 15084 cleanup(); 15085 reject(e); 15086 }; 15087 document.body.appendChild(s); 15088 }); 15089 } 15090 15091 function createCallback(useCORS) { 15092 return !useCORS ? "html2canvas_" + Date.now() + "_" + (++proxyCount) + "_" + Math.round(Math.random() * 100000) : ""; 15093 } 15094 15095 function createProxyUrl(proxyUrl, src, callback) { 15096 return proxyUrl + "?url=" + encodeURIComponent(src) + (callback.length ? "&callback=html2canvas.proxy." + callback : ""); 15097 } 15098 15099 function documentFromHTML(src) { 15100 return function(html) { 15101 var parser = new DOMParser(), doc; 15102 try { 15103 doc = parser.parseFromString(html, "text/html"); 15104 } catch(e) { 15105 log("DOMParser not supported, falling back to createHTMLDocument"); 15106 doc = document.implementation.createHTMLDocument(""); 15107 try { 15108 doc.open(); 15109 doc.write(html); 15110 doc.close(); 15111 } catch(ee) { 15112 log("createHTMLDocument write not supported, falling back to document.body.innerHTML"); 15113 doc.body.innerHTML = html; // ie9 doesnt support writing to documentElement 15114 } 15115 } 15116 15117 var b = doc.querySelector("base"); 15118 if (!b || !b.href.host) { 15119 var base = doc.createElement("base"); 15120 base.href = src; 15121 doc.head.insertBefore(base, doc.head.firstChild); 15122 } 15123 15124 return doc; 15125 }; 15126 } 15127 15128 function loadUrlDocument(src, proxy, document, width, height, options) { 15129 return new Proxy(src, proxy, window.document).then(documentFromHTML(src)).then(function(doc) { 15130 return createWindowClone(doc, document, width, height, options, 0, 0); 15131 }); 15132 } 15133 15134 exports.Proxy = Proxy; 15135 exports.ProxyURL = ProxyURL; 15136 exports.loadUrlDocument = loadUrlDocument; 15137 15138 }
15138,{"./clone":2,"./log":13,"./utils":26,"./xhr":28}],17:[function(_dereq_,module,exports){ 15139 var ProxyURL = _dereq_('./proxy').ProxyURL; 15140 15141 function ProxyImageContainer(src, proxy) { 15142 var link = document.createElement("a"); 15143 link.href = src; 15144 src = link.href; 15145 this.src = src; 15146 this.image = new Image(); 15147 var self = this; 15148 this.promise = new Promise(function(resolve, reject) { 15149 self.image.crossOrigin = "Anonymous"; 15150 self.image.onload = resolve; 15151 self.image.onerror = reject; 15152 15153 new ProxyURL(src, proxy, document).then(function(url) { 15154 self.image.src = url; 15155 })['catch'](reject); 15156 }); 15157 } 15158 15159 module.exports = ProxyImageContainer; 15160 15161 },{"./proxy":16}],18:[function(_dereq_,module,exports){ 15162 var NodeContainer = _dereq_('./nodecontainer'); 15163 15164 function PseudoElementContainer(node, parent, type) { 15165 NodeContainer.call(this, node, parent); 15166 this.isPseudoElement = true; 15167 this.before = type === ":before"; 15168 } 15169 15170 PseudoElementContainer.prototype.cloneTo = function(stack) { 15171 PseudoElementContainer.prototype.cloneTo.call(this, stack); 15172 stack.isPseudoElement = true; 15173 stack.before = this.before; 15174 }; 15175 15176 PseudoElementContainer.prototype = Object.create(NodeContainer.prototype); 15177 15178 PseudoElementContainer.prototype.appendToDOM = function() { 15179 if (this.before) { 15180 this.parent.node.insertBefore(this.node, this.parent.node.firstChild); 15181 } else { 15182 this.parent.node.appendChild(this.node); 15183 } 15184 this.parent.node.className += " " + this.getHideClass(); 15185 }; 15186 15187 PseudoElementContainer.prototype.cleanDOM = function() { 15188 this.node.parentNode.removeChild(this.node); 15189 this.parent.node.className = this.parent.node.className.replace(this.getHideClass(), ""); 15190 }; 15191 15192 PseudoElementContainer.prototype.getHideClass = function() { 15193 return this["PSEUDO_HIDE_ELEMENT_CLASS_" + (this.before ? "BEFORE" : "AFTER")]; 15194 }; 15195 15196 PseudoElementContainer.prototype.PSEUDO_HIDE_ELEMENT_CLASS_BEFORE = "___html2canvas___pseudoelement_before"; 15197 PseudoElementContainer.prototype.PSEUDO_HIDE_ELEMENT_CLASS_AFTER = "___html2canvas___pseudoelement_after"; 15198 15199 module.exports = PseudoElementContainer; 15200 15201 },{"./nodecontainer":14}],19:[function(_dereq_,module,exports){ 15202 var log = _dereq_('./log'); 15203
15204 function Renderer(width, height, images, options, document) { 15205 this.width = width; 15206 this.height = height; 15207 this.images = images; 15208 this.options = options; 15209 this.document = document; 15210 } 15211 15212 Renderer.prototype.renderImage = function(container, bounds, borderData, imageContainer) { 15213 var paddingLeft = container.cssInt('paddingLeft'), 15214 paddingTop = container.cssInt('paddingTop'), 15215 paddingRight = container.cssInt('paddingRight'), 15216 paddingBottom = container.cssInt('paddingBottom'), 15217 borders = borderData.borders; 15218 15219 var width = bounds.width - (borders[1].width + borders[3].width + paddingLeft + paddingRight); 15220 var height = bounds.height - (borders[0].width + borders[2].width + paddingTop + paddingBottom); 15221 this.drawImage( 15222 imageContainer, 15223 0, 15224 0, 15225 imageContainer.image.width || width, 15226 imageContainer.image.height || height, 15227 bounds.left + paddingLeft + borders[3].width, 15228 bounds.top + paddingTop + borders[0].width, 15229 width, 15230 height 15231 ); 15232 }; 15233 15234 Renderer.prototype.renderBackground = function(container, bounds, borderData) { 15235 if (bounds.height > 0 && bounds.width > 0) { 15236 this.renderBackgroundColor(container, bounds); 15237 this.renderBackgroundImage(container, bounds, borderData); 15238 } 15239 }; 15240 15241 Renderer.prototype.renderBackgroundColor = function(container, bounds) { 15242 var color = container.color("backgroundColor"); 15243 if (!color.isTransparent()) { 15244 this.rectangle(bounds.left, bounds.top, bounds.width, bounds.height, color); 15245 } 15246 }; 15247 15248 Renderer.prototype.renderBorders = function(borders) { 15249 borders.forEach(this.renderBorder, this); 15250 }; 15251 15252 Renderer.prototype.renderBorder = function(data) { 15253 if (!data.color.isTransparent() && data.args !== null) { 15254 this.drawShape(data.args, data.color); 15255 } 15256 }; 15257 15258 Renderer.prototype.renderBackgroundImage = function(container, bounds, borderData) { 15259 var backgroundImages = container.parseBackgroundImages(); 15260 backgroundImages.reverse().forEach(function(backgroundImage, index, arr) { 15261 switch(backgroundImage.method) { 15262 case "url": 15263 var image = this.images.get(backgroundImage.args[0]); 15264 if (image) { 15265 this.renderBackgroundRepeating(container, bounds, image, arr.length - (index+1), borderData); 15266 } else { 15267 log("Error loading background-image", backgroundImage.args[0]); 15268 } 15269 break; 15270 case "linear-gradient": 15271 case "gradient": 15272 var gradientImage = this.images.get(backgroundImage.value); 15273 if (gradientImage) { 15274 this.renderBackgroundGradient(gradientImage, bounds, borderData); 15275 } else { 15276 log("Error loading background-image", backgroundImage.args[0]); 15277 } 15278 break; 15279 case "none": 15280 break; 15281 default: 15282 log("Unknown background-image type", backgroundImage.args[0]); 15283 } 15284 }, this); 15285 }; 15286 15287 Renderer.prototype.renderBackgroundRepeating = function(container, bounds, imageContainer, index, borderData) {
15288 var size = container.parseBackgroundSize(bounds, imageContainer.image, index); 15289 var position = container.parseBackgroundPosition(bounds, imageContainer.image, index, size); 15290 var repeat = container.parseBackgroundRepeat(index); 15291 switch (repeat) { 15292 case "repeat-x": 15293 case "repeat no-repeat": 15294 this.backgroundRepeatShape(imageContainer, position, size, bounds, bounds.left + borderData[3], bounds.top + position.top + borderData[0], 99999, size.height, borderData); 15295 break; 15296 case "repeat-y": 15297 case "no-repeat repeat": 15298 this.backgroundRepeatShape(imageContainer, position, size, bounds, bounds.left + position.left + borderData[3], bounds.top + borderData[0], size.width, 99999, borderData); 15299 break; 15300 case "no-repeat": 15301 this.backgroundRepeatShape(imageContainer, position, size, bounds, bounds.left + position.left + borderData[3], bounds.top + position.top + borderData[0], size.width, size.height, borderData); 15302 break; 15303 default: 15304 this.renderBackgroundRepeat(imageContainer, position, size, {top: bounds.top, left: bounds.left}, borderData[3], borderData[0]); 15305 break; 15306 } 15307 }; 15308 15309 module.exports = Renderer; 15310 15311 },{"./log":13}],20:[function(_dereq_,module,exports){ 15312 var Renderer = _dereq_('../renderer'); 15313 var LinearGradientContainer = _dereq_('../lineargradientcontainer'); 15314 var log = _dereq_('../log'); 15315 15316 function CanvasRenderer(width, height) { 15317 Renderer.apply(this, arguments); 15318 this.canvas = this.options.canvas || this.document.createElement("canvas"); 15319 if (!this.options.canvas) { 15320 this.canvas.width = width; 15321 this.canvas.height = height; 15322 } 15323 this.ctx = this.canvas.getContext("2d"); 15324 this.taintCtx = this.document.createElement("canvas").getContext("2d"); 15325 this.ctx.textBaseline = "bottom"; 15326 this.variables = {}; 15327 log("Initialized CanvasRenderer with size", width, "x", height); 15328 } 15329 15330 CanvasRenderer.prototype = Object.create(Renderer.prototype); 15331 15332 CanvasRenderer.prototype.setFillStyle = function(fillStyle) { 15333 this.ctx.fillStyle = typeof(fillStyle) === "object" && !!fillStyle.isColor ? fillStyle.toString() : fillStyle; 15334 return this.ctx; 15335 }; 15336 15337 CanvasRenderer.prototype.rectangle = function(left, top, width, height, color) { 15338 this.setFillStyle(color).fillRect(left, top, width, height); 15339 }; 15340 15341 CanvasRenderer.prototype.circle = function(left, top, size, color) { 15342 this.setFillStyle(color); 15343 this.ctx.beginPath(); 15344 this.ctx.arc(left + size / 2, top + size / 2, size / 2, 0, Math.PI*2, true); 15345 this.ctx.closePath(); 15346 this.ctx.fill(); 15347 }; 15348 15349 CanvasRenderer.prototype.circleStroke = function(left, top, size, color, stroke, strokeColor) { 15350 this.circle(left, top, size, color); 15351 this.ctx.strokeStyle = strokeColor.toString(); 15352 this.ctx.stroke(); 15353 }; 15354 15355 CanvasRenderer.prototype.drawShape = function(shape, color) { 15356 this.shape(shape); 15357 this.setFillStyle(color).fill(); 15358 }; 15359 15360 CanvasRenderer.prototype.taints = function(imageContainer) { 15361 if (imageContainer.tainted === null) { 15362 this.taintCtx.drawImage(imageContainer.image, 0, 0); 15363 try { 15364 this.taintCtx.getImageData(0, 0, 1, 1); 15365 imageContainer.tainted = false; 15366 } catch(e) { 15367 this.taintCtx = document.createElement("canvas").getContext("2d"); 15368 imageContainer.tainted = true; 15369 } 15370 } 15371 15372 return imageContainer.tainted; 15373 }; 15374 15375 CanvasRenderer.prototype.drawImage = function(imageContainer, sx, sy, sw, sh, dx, dy, dw, dh) { 15376 if (!this.taints(imageContainer) || this.options.allowTaint) { 15377 this.ctx.drawImage(imageContainer.image, sx, sy, sw, sh, dx, dy, dw, dh); 15378 } 15379 }; 15380 15381 CanvasRenderer.prototype.clip = function(shapes, callback, context) { 15382 this.ctx.save();
15383 shapes.filter(hasEntries).forEach(function(shape) { 15384 this.shape(shape).clip(); 15385 }, this); 15386 callback.call(context); 15387 this.ctx.restore(); 15388 }; 15389 15390 CanvasRenderer.prototype.shape = function(shape) { 15391 this.ctx.beginPath(); 15392 shape.forEach(function(point, index) { 15393 if (point[0] === "rect") { 15394 this.ctx.rect.apply(this.ctx, point.slice(1)); 15395 } else { 15396 this.ctx[(index === 0) ? "moveTo" : point[0] + "To" ].apply(this.ctx, point.slice(1)); 15397 } 15398 }, this); 15399 this.ctx.closePath(); 15400 return this.ctx; 15401 }; 15402 15403 CanvasRenderer.prototype.font = function(color, style, variant, weight, size, family) { 15404 this.setFillStyle(color).font = [style, variant, weight, size, family].join(" ").split(",")[0]; 15405 }; 15406 15407 CanvasRenderer.prototype.fontShadow = function(color, offsetX, offsetY, blur) { 15408 this.setVariable("shadowColor", color.toString()) 15409 .setVariable("shadowOffsetY", offsetX) 15410 .setVariable("shadowOffsetX", offsetY) 15411 .setVariable("shadowBlur", blur); 15412 }; 15413 15414 CanvasRenderer.prototype.clearShadow = function() { 15415 this.setVariable("shadowColor", "rgba(0,0,0,0)"); 15416 }; 15417 15418 CanvasRenderer.prototype.setOpacity = function(opacity) { 15419 this.ctx.globalAlpha = opacity; 15420 }; 15421 15422 CanvasRenderer.prototype.setTransform = function(transform) { 15423 this.ctx.translate(transform.origin[0], transform.origin[1]); 15424 this.ctx.transform.apply(this.ctx, transform.matrix); 15425 this.ctx.translate(-transform.origin[0], -transform.origin[1]); 15426 }; 15427 15428 CanvasRenderer.prototype.setVariable = function(property, value) { 15429 if (this.variables[property] !== value) { 15430 this.variables[property] = this.ctx[property] = value; 15431 } 15432 15433 return this; 15434 }; 15435 15436 CanvasRenderer.prototype.text = function(text, left, bottom) { 15437 this.ctx.fillText(text, left, bottom); 15438 }; 15439 15440 CanvasRenderer.prototype.backgroundRepeatShape = function(imageContainer, backgroundPosition, size, bounds, left, top, width, height, borderData) { 15441 var shape = [ 15442 ["line", Math.round(left), Math.round(top)], 15443 ["line", Math.round(left + width), Math.round(top)], 15444 ["line", Math.round(left + width), Math.round(height + top)], 15445 ["line", Math.round(left), Math.round(height + top)] 15446 ]; 15447 this.clip([shape], function() { 15448 this.renderBackgroundRepeat(imageContainer, backgroundPosition, size, bounds, borderData[3], borderData[0]); 15449 }, this); 15450 }; 15451 15452 CanvasRenderer.prototype.renderBackgroundRepeat = function(imageContainer, backgroundPosition, size, bounds, borderLeft, borderTop) { 15453 var offsetX = Math.round(bounds.left + backgroundPosition.left + borderLeft), offsetY = Math.round(bounds.top + backgroundPosition.top + borderTop); 15454 this.setFillStyle(this.ctx.createPattern(this.resizeImage(imageContainer, size), "repeat")); 15455 this.ctx.translate(offsetX, offsetY); 15456 this.ctx.fill(); 15457 this.ctx.translate(-offsetX, -offsetY); 15458 }; 15459 15460 CanvasRenderer.prototype.renderBackgroundGradient = function(gradientImage, bounds) { 15461 if (gradientImage instanceof LinearGradientContainer) { 15462 var gradient = this.ctx.createLinearGradient( 15463 bounds.left + bounds.width * gradientImage.x0, 15464 bounds.top + bounds.height * gradientImage.y0, 15465 bounds.left + bounds.width * gradientImage.x1, 15466 bounds.top + bounds.height * gradientImage.y1); 15467 gradientImage.colorStops.forEach(function(colorStop) { 15468 gradient.addColorStop(colorStop.stop, colorStop.color.toString()); 15469 }); 15470 this.rectangle(bounds.left, bounds.top, bounds.width, bounds.height, gradient); 15471 } 15472 }; 15473 15474 CanvasRenderer.prototype.resizeImage = function(imageContainer, size) { 15475 var image = imageContainer.image; 15476 if(image.width === size.width && image.height === size.height) { 15477 return image; 15478 } 15479 15480 var ctx, canvas = document.createElement('canvas'); 15481 canvas.width = size.width; 15482 canvas.height = size.height; 15483 ctx = canvas.getContext("2d"); 15484 ctx.drawImage(image, 0, 0, image.width, image.height, 0, 0, size.width, size.height ); 15485 return canvas; 15486 }; 15487 15488 function hasEntries(array) { 15489 return array.length > 0; 15490 } 15491 15492 module.exports = CanvasRenderer; 15493 15494 },{"../lineargradientcontainer":12,"../log":13,"../renderer":19}],21:[function(_dereq_,module,exports){ 15495 var NodeContainer = _dereq_('./nodecontainer'); 15496 15497 function StackingContext(hasOwnStacking, opacity, element, parent) { 15498 NodeContainer.call(this, element, parent); 15499 this.ownStacking = hasOwnStacking; 15500 this.contexts = []; 15501 this.children = []; 15502 this.opacity = (this.parent ? this.parent.stack.opacity : 1) * opacity; 15503 } 15504 15505 StackingContext.prototype = Object.create(NodeContainer.prototype); 15506 15507 StackingContext.prototype.getParentStack = function(context) { 15508 var parentStack = (this.parent) ? this.parent.stack : null; 15509 return parentStack ? (parentStack.ownStacking ? parentStack : parentStack.getParentStack(context)) : context.stack; 15510 }; 15511 15512 module.exports = StackingContext; 15513 15514 },{"./nodecontainer":14}],22:[function(_dereq_,module,exports){ 15515 function Support(document) { 15516 this.rangeBounds = this.testRangeBounds(document); 15517 this.cors = this.testCORS(); 15518 this.svg = this.testSVG(); 15519 } 15520 15521 Support.prototype.testRangeBounds = function(document) { 15522 var range, testElement, rangeBounds, rangeHeight, support = false;
15523 15524 if (document.createRange) { 15525 range = document.createRange(); 15526 if (range.getBoundingClientRect) { 15527 testElement = document.createElement('boundtest'); 15528 testElement.style.height = "123px"; 15529 testElement.style.display = "block"; 15530 document.body.appendChild(testElement); 15531 15532 range.selectNode(testElement); 15533 rangeBounds = range.getBoundingClientRect(); 15534 rangeHeight = rangeBounds.height; 15535 15536 if (rangeHeight === 123) { 15537 support = true; 15538 } 15539 document.body.removeChild(testElement); 15540 } 15541 } 15542 15543 return support; 15544 }; 15545 15546 Support.prototype.testCORS = function() { 15547 return typeof((new Image()).crossOrigin) !== "undefined"; 15548 }; 15549 15550 Support.prototype.testSVG = function() { 15551 var img = new Image(); 15552 var canvas = document.createElement("canvas"); 15553 var ctx = canvas.getContext("2d"); 15554 img.src = "data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg'></svg>"; 15555 15556 try { 15557 ctx.drawImage(img, 0, 0); 15558 canvas.toDataURL(); 15559 } catch(e) { 15560 return false; 15561 } 15562 return true; 15563 }; 15564 15565 module.exports = Support; 15566 15567 },{}],23:[function(_dereq_,module,exports){ 15568 var XHR = _dereq_('./xhr'); 15569 var decode64 = _dereq_('./utils').decode64; 15570 15571 function SVGContainer(src) { 15572 this.src = src; 15573 this.image = null; 15574 var self = this; 15575 15576 this.promise = this.hasFabric().then(function() { 15577 return (self.isInline(src) ? Promise.resolve(self.inlineFormatting(src)) : XHR(src)); 15578 }).then(function(svg) { 15579 return new Promise(function(resolve) { 15580 window.html2canvas.svg.fabric.loadSVGFromString(svg, self.createCanvas.call(self, resolve)); 15581 }); 15582 }); 15583 } 15584 15585 SVGContainer.prototype.hasFabric = function() { 15586 return !window.html2canvas.svg || !window.html2canvas.svg.fabric ? Promise.reject(new Error("html2canvas.svg.js is not loaded, cannot render svg")) : Promise.resolve(); 15587 }; 15588 15589 SVGContainer.prototype.inlineFormatting = function(src) { 15590 return (/^data:image\/svg\+xml;base64,/.test(src)) ? this.decode64(this.removeContentType(src)) : this.removeContentType(src); 15591 }; 15592 15593 SVGContainer.prototype.removeContentType = function(src) { 15594 return src.replace(/^data:image\/svg\+xml(;base64)?,/,''); 15595 }; 15596 15597 SVGContainer.prototype.isInline = function(src) { 15598 return (/^data:image\/svg\+xml/i.test(src)); 15599 }; 15600 15601 SVGContainer.prototype.createCanvas = function(resolve) { 15602 var self = this; 15603 return function (objects, options) { 15604 var canvas = new window.html2canvas.svg.fabric.StaticCanvas('c'); 15605 self.image = canvas.lowerCanvasEl; 15606 canvas 15607 .setWidth(options.width) 15608 .setHeight(options.height) 15609 .add(window.html2canvas.svg.fabric.util.groupSVGElements(objects, options)) 15610 .renderAll(); 15611 resolve(canvas.lowerCanvasEl); 15612 }; 15613 }; 15614 15615 SVGContainer.prototype.decode64 = function(str) { 15616 return (typeof(window.atob) === "function") ? window.atob(str) : decode64(str); 15617 }; 15618 15619 module.exports = SVGContainer; 15620 15621 },{"./utils":26,"./xhr":28}],24:[function(_dereq_,module,exports){ 15622 var SVGContainer = _dereq_('./svgcontainer'); 15623 15624 function SVGNodeContainer(node, _native) { 15625 this.src = node; 15626 this.image = null; 15627 var self = this; 15628 15629 this.promise = _native ? new Promise(function(resolve, reject) { 15630 self.image = new Image(); 15631 self.image.onload = resolve; 15632 self.image.onerror = reject; 15633 self.image.src = "data:image/svg+xml," + (ne
15633w XMLSerializer()).serializeToString(node); 15634 if (self.image.complete === true) { 15635 resolve(self.image); 15636 } 15637 }) : this.hasFabric().then(function() { 15638 return new Promise(function(resolve) { 15639 window.html2canvas.svg.fabric.parseSVGDocument(node, self.createCanvas.call(self, resolve)); 15640 }); 15641 }); 15642 } 15643 15644 SVGNodeContainer.prototype = Object.create(SVGContainer.prototype); 15645 15646 module.exports = SVGNodeContainer; 15647 15648 },{"./svgcontainer":23}],25:[function(_dereq_,module,exports){ 15649 var NodeContainer = _dereq_('./nodecontainer'); 15650 15651 function TextContainer(node, parent) { 15652 NodeContainer.call(this, node, parent); 15653 } 15654 15655 TextContainer.prototype = Object.create(NodeContainer.prototype); 15656 15657 TextContainer.prototype.applyTextTransform = function() { 15658 this.node.data = this.transform(this.parent.css("textTransform")); 15659 }; 15660 15661 TextContainer.prototype.transform = function(transform) { 15662 var text = this.node.data; 15663 switch(transform){ 15664 case "lowercase": 15665 return text.toLowerCase(); 15666 case "capitalize": 15667 return text.replace(/(^|\s|:|-|\(|\))([a-z])/g, capitalize); 15668 case "uppercase": 15669 return text.toUpperCase(); 15670 default: 15671 return text; 15672 } 15673 }; 15674 15675 function capitalize(m, p1, p2) { 15676 if (m.length > 0) { 15677 return p1 + p2.toUpperCase(); 15678 } 15679 } 15680 15681 module.exports = TextContainer; 15682 15683 },{"./nodecontainer":14}],26:[function(_dereq_,module,exports){ 15684 exports.smallImage = function smallImage() { 15685 return "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7"; 15686 }; 15687 15688 exports.bind = function(callback, context) { 15689 return function() { 15690 return callback.apply(context, arguments); 15691 }; 15692 }; 15693 15694 /* 15695 * base64-arraybuffer 15696 * https://github.com/niklasvh/base64-arraybuffer 15697 * 15698 * Copyright (c) 2012 Niklas von Hertzen 15699 * Licensed under the MIT license. 15700 */ 15701 15702 exports.decode64 = function(base64) { 15703 var chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; 15704 var len = base64.length, i, encoded1, encoded2, encoded3, encoded4, byte1, byte2, byte3; 15705 15706 var output = ""; 15707 15708 for (i = 0; i < len; i+=4) { 15709 encoded1 = chars.indexOf(base64[i]); 15710 encoded2 = chars.indexOf(base64[i+1]); 15711 encoded3 = chars.indexOf(base64[i+2]); 15712 encoded4 = chars.indexOf(base64[i+3]); 15713 15714 byte1 = (encoded1 << 2) | (encoded2 >> 4); 15715 byte2 = ((encoded2 & 15) << 4) | (encoded3 >> 2); 15716 byte3 = ((encoded3 & 3) << 6) | encoded4; 15717 if (encoded3 === 64) { 15718 output += String.fromCharCode(byte1); 15719 } else if (encoded4 === 64 || encoded4 === -1) { 15720 output += String.fromCharCode(byte1, byte2); 15721 } else{ 15722 output += String.fromCharCode(byte1, byte2, byte3); 15723 } 15724 } 15725 15726 return output; 15727 }; 15728 15729 exports.getBounds = function(node) { 15730 if (node.getBoundingClientRect) { 15731 var clientRect = node.getBoundingClientRect(); 15732 var width = node.offsetWidth == null ? clientRect.width : node.offsetWidth; 15733 return { 15734 top: clientRect.top, 15735 bottom: clientRect.bottom || (clientRect.top + clientRect.height), 15736 right: clientRect.left + width, 15737 left: clientRect.left, 15738 width: width, 15739 height: node.offsetHeight == null ? clientRect.height : node.offsetHeight 15740 }; 15741 } 15742 return {}; 15743 }; 15744 15745 exports.offsetBounds = function(node) { 15746 var parent = node.offsetParent ? exports.offsetBounds(node.offsetParent) : {top: 0, left: 0}; 15747 15748 return { 15749 top: node.offsetTop + parent.top, 15750 bottom: node.offsetTop + node.offsetHeight + parent.top, 15751 right: node.offsetLeft + parent.left + node.offsetWidth, 15752 left: node.offsetLeft + parent.left, 15753 width: node.offsetWidth, 15754 height: node.offsetHeight 15755 }; 15756 }; 15757
15758 exports.parseBackgrounds = function(backgroundImage) { 15759 var whitespace = ' \r\n\t', 15760 method, definition, prefix, prefix_i, block, results = [], 15761 mode = 0, numParen = 0, quote, args; 15762 var appendResult = function() { 15763 if(method) { 15764 if (definition.substr(0, 1) === '"') { 15765 definition = definition.substr(1, definition.length - 2); 15766 } 15767 if (definition) { 15768 args.push(definition); 15769 } 15770 if (method.substr(0, 1) === '-' && (prefix_i = method.indexOf('-', 1 ) + 1) > 0) { 15771 prefix = method.substr(0, prefix_i); 15772 method = method.substr(prefix_i); 15773 } 15774 results.push({ 15775 prefix: prefix, 15776 method: method.toLowerCase(), 15777 value: block, 15778 args: args, 15779 image: null 15780 }); 15781 } 15782 args = []; 15783 method = prefix = definition = block = ''; 15784 }; 15785 args = []; 15786 method = prefix = definition = block = ''; 15787 backgroundImage.split("").forEach(function(c) { 15788 if (mode === 0 && whitespace.indexOf(c) > -1) { 15789 return; 15790 } 15791 switch(c) { 15792 case '"': 15793 if(!quote) { 15794 quote = c; 15795 } else if(quote === c) { 15796 quote = null; 15797 } 15798 break; 15799 case '(': 15800 if(quote) { 15801 break; 15802 } else if(mode === 0) { 15803 mode = 1; 15804 block += c; 15805 return; 15806 } else { 15807 numParen++; 15808 } 15809 break; 15810 case ')': 15811 if (quote) { 15812 break; 15813 } else if(mode === 1) { 15814 if(numParen === 0) { 15815 mode = 0; 15816 block += c; 15817 appendResult(); 15818 return; 15819 } else { 15820 numParen--; 15821 } 15822 } 15823 break; 15824 15825 case ',': 15826 if (quote) { 15827 break; 15828 } else if(mode === 0) { 15829 appendResult(); 15830 return; 15831 } else if (mode === 1) { 15832 if (numParen === 0 && !method.match(/^url$/i)) { 15833 args.push(definition); 15834 definition = ''; 15835 block += c; 15836 return; 15837 } 15838 } 15839 break; 15840 } 15841 15842 block += c; 15843 if (mode === 0) { 15844 method += c; 15845 } else { 15846 definition += c; 15847 } 15848 }); 15849 15850 appendResult(); 15851 return results; 15852 }; 15853 15854 },{}],27:[function(_dereq_,module,exports){ 15855 var GradientContainer = _dereq_('./gradientcontainer'); 15856 15857 function WebkitGradientContainer(imageData) { 15858 GradientContainer.apply(this, arguments); 15859 this.type = imageData.args[0] === "linear" ? GradientContainer.TYPES.LINEAR
15859: GradientContainer.TYPES.RADIAL; 15860 } 15861 15862 WebkitGradientContainer.prototype = Object.create(GradientContainer.prototype); 15863 15864 module.exports = WebkitGradientContainer; 15865 15866 },{"./gradientcontainer":9}],28:[function(_dereq_,module,exports){ 15867 function XHR(url) { 15868 return new Promise(function(resolve, reject) { 15869 var xhr = new XMLHttpRequest(); 15870 xhr.open('GET', url); 15871 15872 xhr.onload = function() { 15873 if (xhr.status === 200) { 15874 resolve(xhr.responseText); 15875 } else { 15876 reject(new Error(xhr.statusText)); 15877 } 15878 }; 15879 15880 xhr.onerror = function() { 15881 reject(new Error("Network Error")); 15882 }; 15883 15884 xhr.send(); 15885 }); 15886 } 15887 15888 module.exports = XHR; 15889 15890 },{}]},{},[4])(4) 15891 }); 15892 15893 // Generated by CoffeeScript 1.4.0 15894 15895 /* 15896 # PNG.js 15897 # Copyright (c) 2011 Devon Govett 15898 # MIT LICENSE 15899 # 15900 # 15901 */ 15902 15903 15904 (function(global) { 15905 var PNG; 15906 15907 PNG = (function() { 15908 var APNG_BLEND_OP_OVER, APNG_BLEND_OP_SOURCE, APNG_DISPOSE_OP_BACKGROUND, APNG_DISPOSE_OP_NONE, APNG_DISPOSE_OP_PREVIOUS, makeImage, scratchCanvas, scratchCtx; 15909 15910 PNG.load = function(url, canvas, callback) { 15911 var xhr, 15912 _this = this; 15913 if (typeof canvas === 'function') { 15914 callback = canvas; 15915 } 15916 xhr = new XMLHttpRequest; 15917 xhr.open("GET", url, true); 15918 xhr.responseType = "arraybuffer"; 15919 xhr.onload = function() { 15920 var data, png; 15921 data = new Uint8Array(xhr.response || xhr.mozResponseArrayBuffer); 15922 png = new PNG(data); 15923 if (typeof (canvas != null ? canvas.getContext : void 0) === 'function') { 15924 png.render(canvas); 15925 } 15926 return typeof callback === "function" ? callback(png) : void 0; 15927 }; 15928 return xhr.send(null); 15929 }; 15930 15931 APNG_DISPOSE_OP_NONE = 0; 15932 15933 APNG_DISPOSE_OP_BACKGROUND = 1; 15934 15935 APNG_DISPOSE_OP_PREVIOUS = 2; 15936 15937 APNG_BLEND_OP_SOURCE = 0; 15938 15939 APNG_BLEND_OP_OVER = 1; 15940 15941 function PNG(data) { 15942 var chunkSize, colors, palLen, delayDen, delayNum, frame, i, index, key, section, palShort, text, _i, _j, _ref; 15943 this.data = data; 15944 this.pos = 8; 15945 this.palette = []; 15946 this.imgData = []; 15947 this.transparency = {}; 15948 this.animation = null; 15949 this.text = {}; 15950 frame = null; 15951 while (true) { 15952 chunkSize = this.readUInt32(); 15953 section = ((function() { 15954 var _i, _results; 15955 _results = []; 15956 for (i = _i = 0; _i < 4; i = ++_i) { 15957 _results.push(String.fromCharCode(this.data[this.pos++])); 15958 } 15959 return _results; 15960 }).call(this)).join(''); 15961 switch (section) { 15962 case 'IHDR': 15963 this.width = this.readUInt32(); 15964 this.height = this.readUInt32(); 15965 this.bits = this.data[this.pos++]; 15966 this.colorType = this.data[this.pos++]; 15967 this.compressionMethod = this.data[this.pos++]; 15968 this.filterMethod = this.data[this.pos++]; 15969 this.interlaceMethod = this.data[this.pos++]; 15970 break; 15971 case 'acTL': 15972 this.animation = { 15973 numFrames: this.readUInt32(), 15974 numPlays: this.readUInt32() || Infinity, 15975 frames: [] 15976 }; 15977 break; 15978 case 'PLTE': 15979 this.palette = this.read(chunkSize); 15980 break; 15981 case 'fcTL': 15982 if (frame) { 15983 this.animation.frames.push(frame); 15984 } 15985 this.pos += 4; 15986 frame = { 15987 width: this.readUInt32(), 15988 height: this.readUInt32(), 15989 xOffset: this.readUInt32(), 15990 yOffset: this.readUInt32() 15991 }; 15992 delayNum = this.readUInt16(); 15993 delayDen = this.readUInt16() || 100; 15994 frame.delay = 1000 * delayNum / delayDen; 15995 frame.disposeOp = this.data[this.pos++]; 15996 frame.blendOp = this.data[this.pos++]; 15997 frame.data = []; 15998 break; 15999 case 'IDAT': 16000 case 'fdAT': 16001 if (section === 'fdAT') { 16002 this.pos += 4; 16003 chunkSize -= 4; 16004 } 16005 data = (frame != null ? frame.data : void 0) || this.imgData; 16006 for (i = _i = 0; 0 <= chunkSize ? _i < chunkSize : _i > chunkSize; i = 0 <= chunkSize ? ++_i : --_i) { 16007 data.push(this.data[this.pos++]); 16008 } 16009 break; 16010 case 'tRNS': 16011 this.transparency = {}; 16012 switch (this.colorType) { 16013 case 3: 16014 palLen = this.palette.length/3; 16015 this.transparency.indexed = this.read(chunkSize); 16016 if(this.transparency.indexed.length > palLen) 16017 throw new Error('More transparent colors than palette size'); 16018 /* 16019 * According to the PNG spec trns should be increased to the same size as palette if shorter 16020 */ 16021 //palShort = 255 - this.transparency.indexed.length; 16022 palShort = palLen - this.transparency.indexed.length; 16023 if (palShort > 0) { 16024 for (i = _j = 0; 0 <= palShort ? _j < palShort : _j > palShort; i = 0 <= palShort ? ++_j : --_j) { 16025 this.transparency.indexed.push(255); 16026 } 16027 } 16028 break; 16029 case 0: 16030 this.transparency.grayscale = this.read(chunkSize)[0]; 16031 break; 16032 case 2: 16033 this.transparency.rgb = this.read(chunkSize); 16034 } 16035 break; 16036 case 'tEXt': 16037 text = this.read(chunkSize); 16038 index = text.indexOf(0); 16039 key = String.fromCharCode.apply(String, text.slice(0, index)); 16040 this.text[key] = String.fromCharCode.apply(String, text.slice(index + 1)); 16041 break; 16042 case 'IEND': 16043 if (frame) { 16044 this.animation.frames.push(frame); 16045 } 16046 this.colors = (function() { 16047 switch (this.colorType) { 16048 case 0: 16049 case 3: 16050 case 4: 16051 return 1; 16052 case 2: 16053 case 6: 16054 return 3; 16055 } 16056 }).call(this); 16057 this.hasAlphaChannel = (_ref = this.colorType) === 4 || _ref === 6; 16058 colors = this.colors + (this.hasAlphaChannel ? 1 : 0); 16059 this.pixelBitlength = this.bits * colors; 16060 this.colorSpace = (function() { 16061 switch (this.colors) { 16062 case 1: 16063 return 'DeviceGray'; 16064 case 3: 16065 return 'DeviceRGB'; 16066 } 16067 }).call(this); 16068 this.imgData = new Uint8Array(this.imgData); 16069 return; 16070 default: 16071 this.pos += chunkSize; 16072 } 16073 this.pos += 4; 16074 if (this.pos > this.data.length) { 16075 throw new Error("Incomplete or corrupt PNG file"); 16076 } 16077 } 16078 return; 16079 } 16080 16081 PNG.prototype.read = function(bytes) { 16082 var i, _i, _results; 16083 _results = []; 16084 for (i = _i = 0; 0 <= bytes ? _i < bytes : _i > bytes; i = 0 <= bytes ? ++_i : --_i) { 16085 _results.push(this.data[this.pos++]); 16086 } 16087 return _results; 16088 }; 16089 16090 PNG.prototype.readUInt32 = function() { 16091 var b1, b2, b3, b4; 16092 b1 = this.data[this.pos++] << 24; 16093 b2 = this.data[this.pos++] << 16; 16094 b3 = this.data[this.pos++] << 8; 16095 b4 = this.data[this.pos++]; 16096 return b1 | b2 | b3 | b4; 16097 }; 16098
16099 PNG.prototype.readUInt16 = function() { 16100 var b1, b2; 16101 b1 = this.data[this.pos++] << 8; 16102 b2 = this.data[this.pos++]; 16103 return b1 | b2; 16104 }; 16105 16106 PNG.prototype.decodePixels = function(data) { 16107 var abyte, c, col, i, left, length, p, pa, paeth, pb, pc, pixelBytes, pixels, pos, row, scanlineLength, upper, upperLeft, _i, _j, _k, _l, _m; 16108 if (data == null) { 16109 data = this.imgData; 16110 } 16111 if (data.length === 0) { 16112 return new Uint8Array(0); 16113 } 16114 data = new FlateStream(data); 16115 data = data.getBytes(); 16116 pixelBytes = this.pixelBitlength / 8; 16117 scanlineLength = pixelBytes * this.width; 16118 pixels = new Uint8Array(scanlineLength * this.height); 16119 length = data.length; 16120 row = 0; 16121 pos = 0; 16122 c = 0; 16123 while (pos < length) { 16124 switch (data[pos++]) { 16125 case 0: 16126 for (i = _i = 0; _i < scanlineLength; i = _i += 1) { 16127 pixels[c++] = data[pos++]; 16128 } 16129 break; 16130 case 1: 16131 for (i = _j = 0; _j < scanlineLength; i = _j += 1) { 16132 abyte = data[pos++]; 16133 left = i < pixelBytes ? 0 : pixels[c - pixelBytes]; 16134 pixels[c++] = (abyte + left) % 256; 16135 } 16136 break; 16137 case 2: 16138 for (i = _k = 0; _k < scanlineLength; i = _k += 1) { 16139 abyte = data[pos++]; 16140 col = (i - (i % pixelBytes)) / pixelBytes; 16141 upper = row && pixels[(row - 1) * scanlineLength + col * pixelBytes + (i % pixelBytes)]; 16142 pixels[c++] = (upper + abyte) % 256; 16143 } 16144 break; 16145 case 3: 16146 for (i = _l = 0; _l < scanlineLength; i = _l += 1) { 16147 abyte = data[pos++]; 16148 col = (i - (i % pixelBytes)) / pixelBytes; 16149 left = i < pixelBytes ? 0 : pixels[c - pixelBytes]; 16150 upper = row && pixels[(row - 1) * scanlineLength + col * pixelBytes + (i % pixelBytes)]; 16151 pixels[c++] = (abyte + Math.floor((left + upper) / 2)) % 256; 16152 } 16153 break; 16154 case 4: 16155 for (i = _m = 0; _m < scanlineLength; i = _m += 1) { 16156 abyte = data[pos++]; 16157 col = (i - (i % pixelBytes)) / pixelBytes; 16158 left = i < pixelBytes ? 0 : pixels[c - pixelBytes]; 16159 if (row === 0) { 16160 upper = upperLeft = 0; 16161 } else { 16162 upper = pixels[(row - 1) * scanlineLength + col * pixelBytes + (i % pixelBytes)]; 16163 upperLeft = col && pixels[(row - 1) * scanlineLength + (col - 1) * pixelBytes + (i % pixelBytes)]; 16164 } 16165 p = left + upper - upperLeft; 16166 pa = Math.abs(p - left); 16167 pb = Math.abs(p - upper); 16168 pc = Math.abs(p - upperLeft); 16169 if (pa <= pb && pa <= pc) { 16170 paeth = left; 16171 } else if (pb <= pc) { 16172 paeth = upper; 16173 } else { 16174 paeth = upperLeft; 16175 } 16176 pixels[c++] = (abyte + paeth) % 256; 16177 } 16178 break; 16179 default: 16180 throw new Error("Invalid filter algorithm: " + data[pos - 1]); 16181 } 16182 row++; 16183 } 16184 return pixels; 16185 }; 16186 16187 PNG.prototype.decodePalette = function() { 16188 var c, i, length, palette, pos, ret, transparency, _i, _ref, _ref1; 16189 palette = this.palette; 16190 transparency = this.transparency.indexed || []; 16191 ret = new Uint8Array((transparency.length || 0) + palette.length); 16192 pos = 0; 16193 length = palette.length; 16194 c = 0; 16195 for (i = _i = 0, _ref = palette.length; _i < _ref; i = _i += 3) { 16196 ret[pos++] = palette[i]; 16197 ret[pos++] = palette[i + 1]; 16198 ret[pos++] = palette[i + 2]; 16199 ret[pos++] = (_ref1 = transparency[c++]) != null ? _ref1 : 255; 16200 } 16201 return ret; 16202 }; 16203 16204 PNG.prototype.copyToImageData = function(imageData, pixels) { 16205 var alpha, colors, data, i, input, j, k, length, palette, v, _ref; 16206 colors = this.colors; 16207 palette = null; 16208 alpha = this.hasAlphaChannel; 16209 if (this.palette.length) { 16210 palette = (_ref = this._decodedPalette) != null ? _ref : this._decodedPalette = this.decodePalette(); 16211 colors = 4; 16212 alpha = true; 16213 } 16214 data = imageData.data || imageData; 16215 length = data.length; 16216 input = palette || pixels; 16217 i = j = 0; 16218 if (colors === 1) { 16219 while (i < length) { 16220 k = palette ? pixels[i / 4] * 4 : j; 16221 v = input[k++]; 16222 data[i++] = v; 16223 data[i++] = v; 16224 data[i++] = v; 16225 data[i++] = alpha ? input[k++] : 255; 16226 j = k; 16227 } 16228 } else { 16229 while (i < length) { 16230 k = palette ? pixels[i / 4] * 4 : j; 16231 data[i++] = input[k++]; 16232 data[i++] = input[k++]; 16233 data[i++] = input[k++]; 16234 data[i++] = alpha ? input[k++] : 255; 16235 j = k; 16236 } 16237 } 16238 }; 16239 16240 PNG.prototype.decode = function() { 16241 var ret; 16242 ret = new Uint8Array(this.width * this.height * 4); 16243 this.copyToImageData(ret, this.decodePixels()); 16244 return ret; 16245 }; 16246 16247 try { 16248 scratchCanvas = global.document.createElement('canvas'); 16249 scratchCtx = scratchCanvas.getContext('2d'); 16250 } catch(e) { 16251 return -1; 16252 } 16253 16254 makeImage = function(imageData) { 16255 var img; 16256 scratchCtx.width = imageData.width; 16257 scratchCtx.height = imageData.height; 16258 scratchCtx.clearRect(0, 0, imageData.width, imageData.height); 16259 scratchCtx.putImageData(imageData, 0, 0); 16260 img = new Image; 16261 img.src = scratchCanvas.toDataURL(); 16262 return img; 16263 }; 16264 16265 PNG.prototype.decodeFrames = function(ctx) { 16266 var frame, i, imageData, pixels, _i, _len, _ref, _results; 16267 if (!this.animation) { 16268 return; 16269 } 16270 _ref = this.animation.frames; 16271 _results = []; 16272 for (i = _i = 0, _len = _ref.length; _i < _len; i = ++_i) { 16273 frame = _ref[i]; 16274 imageData = ctx.createImageData(frame.width, frame.height); 16275 pixels = this.decodePixels(new Uint8Array(frame.data)); 16276 this.copyToImageData(imageData, pixels); 16277 frame.imageData = imageData; 16278 _results.push(frame.image = makeImage(imageData)); 16279 } 16280 return _results; 16281 }; 16282 16283 PNG.prototype.renderFrame = function(ctx, number) { 16284 var frame, frames, prev; 16285 frames = this.animation.frames; 16286 frame = frames[number]; 16287 prev = frames[number - 1]; 16288 if (number === 0) { 16289 ctx.clearRect(0, 0, this.width, this.height); 16290 } 16291 if ((prev != null ? prev.disposeOp : void 0) === APNG_DISPOSE_OP_BACKGROUND) { 16292 ctx.clearRect(prev.xOffset, prev.yOffset, prev.width, prev.height); 16293 } else if ((prev != null ? prev.disposeOp : void 0) === APNG_DISPOSE_OP_PREVIOUS) { 16294 ctx.putImageData(prev.imageData, prev.xOffset, prev.yOffset); 16295 } 16296 if (frame.blendOp === APNG_BLEND_OP_SOURCE) { 16297 ctx.clearRect(frame.xOffset, frame.yOffset, frame.width, frame.height); 16298 } 16299 return ctx.drawImage(frame.image, frame.xOffset, frame.yOffset); 16300 }; 16301 16302 PNG.prototype.animate = function(ctx) { 16303 var doFrame, frameNumber, frames, numFrames, numPlays, _ref, 16304 _this = this; 16305 frameNumber = 0; 16306 _ref = this.animation, numFrames = _ref.numFrames, frames = _ref.frames, numPlays = _ref.numPlays; 16307 return (doFrame = function() { 16308 var f, frame; 16309 f = frameNumber++ % numFrames; 16310 frame = frames[f]; 16311 _this.renderFrame(ctx, f); 16312 if (numFrames > 1 && frameNumber / numFrames < numPlays) { 16313 return _this.animation._timeout = setTimeout(doFrame, frame.delay); 16314 } 16315 })(); 16316 }; 16317 16318 PNG.prototype.stopAnimation = function() { 16319 var _ref; 16320 return clearTimeout((_ref = this.animation) != null ? _ref._timeout : void 0); 16321 }; 16322 16323 PNG.prototype.render = function(canvas) { 16324 var ctx, data; 16325 if (canvas._png) { 16326 canvas._png.stopAnimation(); 16327 } 16328 canvas._png = this; 16329 canvas.width = this.width; 16330 canvas.height = this.height; 16331 ctx = canvas.getContext("2d"); 16332 if (this.animation) { 16333 this.decodeFrames(ctx); 16334 return this.animate(ctx); 16335 } else { 16336 data = ctx.createImageData(this.width, this.height); 16337 this.copyToImageData(data, this.decodePixels()); 16338 return ctx.putImageData(data, 0, 0); 16339 } 16340 }; 16341 16342 return PNG; 16343 16344 })(); 16345 16346 global.PNG = PNG; 16347 16348 })(typeof window !== "undefined" && window || undefined); 16349 16350 /* 16351 * Extracted from pdf.js
16352 * https://github.com/andreasgal/pdf.js 16353 * 16354 * Copyright (c) 2011 Mozilla Foundation 16355 * 16356 * Contributors: Andreas Gal <[email protected]> 16357 * Chris G Jones <[email protected]> 16358 * Shaon Barman <[email protected]> 16359 * Vivien Nicolas <[email protected]> 16360 * Justin D'Arcangelo <[email protected]> 16361 * Yury Delendik 16362 * 16363 * 16364 */ 16365 16366 var DecodeStream = (function() { 16367 function constructor() { 16368 this.pos = 0; 16369 this.bufferLength = 0; 16370 this.eof = false; 16371 this.buffer = null; 16372 } 16373 16374 constructor.prototype = { 16375 ensureBuffer: function decodestream_ensureBuffer(requested) { 16376 var buffer = this.buffer; 16377 var current = buffer ? buffer.byteLength : 0; 16378 if (requested < current) 16379 return buffer; 16380 var size = 512; 16381 while (size < requested) 16382 size <<= 1; 16383 var buffer2 = new Uint8Array(size); 16384 for (var i = 0; i < current; ++i) 16385 buffer2[i] = buffer[i]; 16386 return this.buffer = buffer2; 16387 }, 16388 getByte: function decodestream_getByte() { 16389 var pos = this.pos; 16390 while (this.bufferLength <= pos) { 16391 if (this.eof) 16392 return null; 16393 this.readBlock(); 16394 } 16395 return this.buffer[this.pos++]; 16396 }, 16397 getBytes: function decodestream_getBytes(length) { 16398 var pos = this.pos; 16399 16400 if (length) { 16401 this.ensureBuffer(pos + length); 16402 var end = pos + length; 16403 16404 while (!this.eof && this.bufferLength < end) 16405 this.readBlock(); 16406 16407 var bufEnd = this.bufferLength; 16408 if (end > bufEnd) 16409 end = bufEnd; 16410 } else { 16411 while (!this.eof) 16412 this.readBlock(); 16413 16414 var end = this.bufferLength; 16415 } 16416 16417 this.pos = end; 16418 return this.buffer.subarray(pos, end); 16419 }, 16420 lookChar: function decodestream_lookChar() { 16421 var pos = this.pos; 16422 while (this.bufferLength <= pos) { 16423 if (this.eof) 16424 return null; 16425 this.readBlock(); 16426 } 16427 return String.fromCharCode(this.buffer[this.pos]); 16428 }, 16429 getChar: function decodestream_getChar() { 16430 var pos = this.pos; 16431 while (this.bufferLength <= pos) { 16432 if (this.eof) 16433 return null; 16434 this.readBlock(); 16435 } 16436 return String.fromCharCode(this.buffer[this.pos++]); 16437 }, 16438 makeSubStream: function decodestream_makeSubstream(start, length, dict) { 16439 var end = start + length; 16440 while (this.bufferLength <= end && !this.eof) 16441 this.readBlock(); 16442 return new Stream(this.buffer, start, length, dict); 16443 }, 16444 skip: function decodestream_skip(n) { 16445 if (!n) 16446 n = 1; 16447 this.pos += n; 16448 }, 16449 reset: function decodestream_reset() { 16450 this.pos = 0; 16451 } 16452 }; 16453 16454 return constructor; 16455 })(); 16456 16457 var FlateStream = (function() { 16458 if (typeof Uint32Array === 'undefined') { 16459 return undefined; 16460 } 16461 var codeLenCodeMap = new Uint32Array([ 16462 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 16463 ]); 16464 16465 var lengthDecode = new Uint32Array([ 16466 0x00003, 0x00004, 0x00005, 0x00006, 0x00007, 0x00008, 0x00009, 0x0000a, 16467 0x1000b, 0x1000d, 0x1000f, 0x10011, 0x20013, 0x20017, 0x2001b, 0x2001f, 16468 0x30023, 0x3002b, 0x30033, 0x3003b, 0x40043, 0x40053, 0x40063, 0x40073, 16469 0x50083, 0x500a3, 0x500c3, 0x500e3, 0x00102, 0x00102, 0x00102 16470 ]); 16471 16472 var distDecode = new Uint32Array([ 16473 0x00001, 0x00002, 0x00003, 0x00004, 0x10005, 0x10007, 0x20009, 0x2000d, 16474 0x30011, 0x30019, 0x40021, 0x40031, 0x50041, 0x50061, 0x60081, 0x600c1, 16475 0x70101, 0x70181, 0x80201, 0x80301, 0x90401, 0x90601, 0xa0801, 0xa0c01, 16476 0xb1001, 0xb1801, 0xc2001, 0xc3001, 0xd4001, 0xd6001 16477 ]); 16478
16479 var fixedLitCodeTab = [new Uint32Array([ 16480 0x70100, 0x80050, 0x80010, 0x80118, 0x70110, 0x80070, 0x80030, 0x900c0, 16481 0x70108, 0x80060, 0x80020, 0x900a0, 0x80000, 0x80080, 0x80040, 0x900e0, 16482 0x70104, 0x80058, 0x80018, 0x90090, 0x70114, 0x80078, 0x80038, 0x900d0, 16483 0x7010c, 0x80068, 0x80028, 0x900b0, 0x80008, 0x80088, 0x80048, 0x900f0, 16484 0x70102, 0x80054, 0x80014, 0x8011c, 0x70112, 0x80074, 0x80034, 0x900c8, 16485 0x7010a, 0x80064, 0x80024, 0x900a8, 0x80004, 0x80084, 0x80044, 0x900e8, 16486 0x70106, 0x8005c, 0x8001c, 0x90098, 0x70116, 0x8007c, 0x8003c, 0x900d8, 16487 0x7010e, 0x8006c, 0x8002c, 0x900b8, 0x8000c, 0x8008c, 0x8004c, 0x900f8, 16488 0x70101, 0x80052, 0x80012, 0x8011a, 0x70111, 0x80072, 0x80032, 0x900c4, 16489 0x70109, 0x80062, 0x80022, 0x900a4, 0x80002, 0x80082, 0x80042, 0x900e4, 16490 0x70105, 0x8005a, 0x8001a, 0x90094, 0x70115, 0x8007a, 0x8003a, 0x900d4, 16491 0x7010d, 0x8006a, 0x8002a, 0x900b4, 0x8000a, 0x8008a, 0x8004a, 0x900f4, 16492 0x70103, 0x80056, 0x80016, 0x8011e, 0x70113, 0x80076, 0x80036, 0x900cc, 16493 0x7010b, 0x80066, 0x80026, 0x900ac, 0x80006, 0x80086, 0x80046, 0x900ec, 16494 0x70107, 0x8005e, 0x8001e, 0x9009c, 0x70117, 0x8007e, 0x8003e, 0x900dc, 16495 0x7010f, 0x8006e, 0x8002e, 0x900bc, 0x8000e, 0x8008e, 0x8004e, 0x900fc, 16496 0x70100, 0x80051, 0x80011, 0x80119, 0x70110, 0x80071, 0x80031, 0x900c2, 16497 0x70108, 0x80061, 0x80021, 0x900a2, 0x80001, 0x80081, 0x80041, 0x900e2, 16498 0x70104, 0x80059, 0x80019, 0x90092, 0x70114, 0x80079, 0x80039, 0x900d2, 16499 0x7010c, 0x80069, 0x80029, 0x900b2, 0x80009, 0x80089, 0x80049, 0x900f2, 16500 0x70102, 0x80055, 0x80015, 0x8011d, 0x70112, 0x80075, 0x80035, 0x900ca, 16501 0x7010a, 0x80065, 0x80025, 0x900aa, 0x80005, 0x80085, 0x80045, 0x900ea, 16502 0x70106, 0x8005d, 0x8001d, 0x9009a, 0x70116, 0x8007d, 0x8003d, 0x900da, 16503 0x7010e, 0x8006d, 0x8002d, 0x900ba, 0x8000d, 0x8008d, 0x8004d, 0x900fa, 16504 0x70101, 0x80053, 0x80013, 0x8011b, 0x70111, 0x80073, 0x80033, 0x900c6, 16505 0x70109, 0x80063, 0x80023, 0x900a6, 0x80003, 0x80083, 0x80043, 0x900e6, 16506 0x70105, 0x8005b, 0x8001b, 0x90096, 0x70115, 0x8007b, 0x8003b, 0x900d6, 16507 0x7010d, 0x8006b, 0x8002b, 0x900b6, 0x8000b, 0x8008b, 0x8004b, 0x900f6, 16508 0x70103, 0x80057, 0x80017, 0x8011f, 0x70113, 0x80077, 0x80037, 0x900ce, 16509 0x7010b, 0x80067, 0x80027, 0x900ae, 0x80007, 0x80087, 0x80047, 0x900ee, 16510 0x70107, 0x8005f, 0x8001f, 0x9009e, 0x70117, 0x8007f, 0x8003f, 0x900de, 16511 0x7010f, 0x8006f, 0x8002f, 0x900be, 0x8000f, 0x8008f, 0x8004f, 0x900fe, 16512 0x70100, 0x80050, 0x80010, 0x80118, 0x70110, 0x80070, 0x80030, 0x900c1, 16513 0x70108, 0x80060, 0x80020, 0x900a1, 0x80000, 0x80080, 0x80040, 0x900e1, 16514 0x70104, 0x80058, 0x80018, 0x90091, 0x70114, 0x80078, 0x80038, 0x900d1, 16515 0x7010c, 0x80068, 0x80028, 0x900b1, 0x80008, 0x80088, 0x80048, 0x900f1, 16516 0x70102, 0x80054, 0x80014, 0x8011c, 0x70112, 0x80074, 0x80034, 0x900c9, 16517 0x7010a, 0x80064, 0x80024, 0x900a9, 0x80004, 0x80084, 0x80044, 0x900e9, 16518 0x70106, 0x8005c, 0x8001c, 0x90099, 0x70116, 0x8007c, 0x8003c, 0x900d9, 16519 0x7010e, 0x8006c, 0x8002c, 0x900b9, 0x8000c, 0x8008c, 0x8004c, 0x900f9, 16520 0x70101, 0x80052, 0x80012, 0x8011a, 0x70111, 0x80072, 0x80032, 0x900c5, 16521 0x70109, 0x80062, 0x80022, 0x900a5, 0x80002, 0x80082, 0x80042, 0x900e5, 16522 0x70105, 0x8005a, 0x8001a, 0x90095, 0x70115, 0x8007a, 0x8003a, 0x900d5, 16523 0x7010d, 0x8006a, 0x8002a, 0x900b5, 0x8000a, 0x8008a, 0x8004a, 0x900f5, 16524 0x70103, 0x80056, 0x80016, 0x8011e, 0x70113, 0x80076, 0x80036, 0x900cd, 16525 0x7010b, 0x80066, 0x80026, 0x900ad, 0x80006, 0x80086, 0x80046, 0x900ed, 16526 0x70107, 0x8005e, 0x8001e, 0x9009d, 0x70117, 0x8007e, 0x8003e, 0x900dd, 16527 0x7010f, 0x8006e, 0x8002e, 0x900bd, 0x8000e, 0x8008e, 0x8004e, 0x900fd, 16528 0x70100, 0x80051, 0x80011, 0x80119, 0x70110, 0x80071, 0x80031, 0x900c3, 16529 0x70108, 0x80061, 0x80021, 0x900a3, 0x80001, 0x80081, 0x80041, 0x900e3, 16530 0x70104, 0x80059, 0x80019, 0x90093, 0x70114, 0x80079, 0x80039, 0x900d3, 16531 0x7010c, 0x80069, 0x80029, 0x900b3, 0x80009, 0x80089, 0x80049, 0x900f3, 16532 0x70102, 0x80055, 0x80015, 0x8011d, 0x70112, 0x80075, 0x80035, 0x900cb, 16533 0x7010a, 0x80065, 0x80025, 0x900ab, 0x80005, 0x80085, 0x80045, 0x900eb, 16534 0x70106, 0x8005d, 0x8001d, 0x9009b, 0x70116, 0x8007d, 0x8003d, 0x900db, 16535 0x7010e, 0x8006d, 0x8002d, 0x900bb, 0x8000d, 0x8008d, 0x8004d, 0x900fb, 16536 0x70101, 0x80053, 0x80013, 0x8011b, 0x70111, 0x80073, 0x80033, 0x900c7, 16537 0x70109, 0x80063, 0x80023, 0x900a7, 0x80003, 0x80083, 0x80043, 0x900e7, 16538 0x70105, 0x8005b, 0x8001b, 0x90097, 0x70115, 0x8007b, 0x8003b, 0x900d7, 16539 0x7010d, 0x8006b, 0x8002b, 0x900b7, 0x8000b, 0x8008b, 0x8004b,
165390x900f7, 16540 0x70103, 0x80057, 0x80017, 0x8011f, 0x70113, 0x80077, 0x80037, 0x900cf, 16541 0x7010b, 0x80067, 0x80027, 0x900af, 0x80007, 0x80087, 0x80047, 0x900ef, 16542 0x70107, 0x8005f, 0x8001f, 0x9009f, 0x70117, 0x8007f, 0x8003f, 0x900df, 16543 0x7010f, 0x8006f, 0x8002f, 0x900bf, 0x8000f, 0x8008f, 0x8004f, 0x900ff 16544 ]), 9]; 16545 16546 var fixedDistCodeTab = [new Uint32Array([ 16547 0x50000, 0x50010, 0x50008, 0x50018, 0x50004, 0x50014, 0x5000c, 0x5001c, 16548 0x50002, 0x50012, 0x5000a, 0x5001a, 0x50006, 0x50016, 0x5000e, 0x00000, 16549 0x50001, 0x50011, 0x50009, 0x50019, 0x50005, 0x50015, 0x5000d, 0x5001d, 16550 0x50003, 0x50013, 0x5000b, 0x5001b, 0x50007, 0x50017, 0x5000f, 0x00000 16551 ]), 5]; 16552 16553 function error(e) { 16554 throw new Error(e) 16555 } 16556 16557 function constructor(bytes) { 16558 //var bytes = stream.getBytes(); 16559 var bytesPos = 0; 16560 16561 var cmf = bytes[bytesPos++]; 16562 var flg = bytes[bytesPos++]; 16563 if (cmf == -1 || flg == -1) 16564 error('Invalid header in flate stream'); 16565 if ((cmf & 0x0f) != 0x08) 16566 error('Unknown compression method in flate stream'); 16567 if ((((cmf << 8) + flg) % 31) != 0) 16568 error('Bad FCHECK in flate stream'); 16569 if (flg & 0x20) 16570 error('FDICT bit set in flate stream'); 16571 16572 this.bytes = bytes; 16573 this.bytesPos = bytesPos; 16574 16575 this.codeSize = 0; 16576 this.codeBuf = 0; 16577 16578 DecodeStream.call(this); 16579 } 16580 16581 constructor.prototype = Object.create(DecodeStream.prototype); 16582 16583 constructor.prototype.getBits = function(bits) { 16584 var codeSize = this.codeSize; 16585 var codeBuf = this.codeBuf; 16586 var bytes = this.bytes; 16587 var bytesPos = this.bytesPos; 16588 16589 var b; 16590 while (codeSize < bits) { 16591 if (typeof (b = bytes[bytesPos++]) == 'undefined') 16592 error('Bad encoding in flate stream'); 16593 codeBuf |= b << codeSize; 16594 codeSize += 8; 16595 } 16596 b = codeBuf & ((1 << bits) - 1); 16597 this.codeBuf = codeBuf >> bits; 16598 this.codeSize = codeSize -= bits; 16599 this.bytesPos = bytesPos; 16600 return b; 16601 }; 16602 16603 constructor.prototype.getCode = function(table) { 16604 var codes = table[0]; 16605 var maxLen = table[1]; 16606 var codeSize = this.codeSize; 16607 var codeBuf = this.codeBuf; 16608 var bytes = this.bytes; 16609 var bytesPos = this.bytesPos; 16610 16611 while (codeSize < maxLen) { 16612 var b; 16613 if (typeof (b = bytes[bytesPos++]) == 'undefined') 16614 error('Bad encoding in flate stream'); 16615 codeBuf |= (b << codeSize); 16616 codeSize += 8; 16617 } 16618 var code = codes[codeBuf & ((1 << maxLen) - 1)]; 16619 var codeLen = code >> 16; 16620 var codeVal = code & 0xffff; 16621 if (codeSize == 0 || codeSize < codeLen || codeLen == 0) 16622 error('Bad encoding in flate stream'); 16623 this.codeBuf = (codeBuf >> codeLen); 16624 this.codeSize = (codeSize - codeLen); 16625 this.bytesPos = bytesPos; 16626 return codeVal; 16627 }; 16628 16629 constructor.prototype.generateHuffmanTable = function(lengths) { 16630 var n = lengths.length; 16631 16632 // find max code length 16633 var maxLen = 0; 16634 for (var i = 0; i < n; ++i) { 16635 if (lengths[i] > maxLen) 16636 maxLen = lengths[i]; 16637 } 16638 16639 // build the table 16640 var size = 1 << maxLen; 16641 var codes = new Uint32Array(size); 16642 for (var len = 1, code = 0, skip = 2; 16643 len <= maxLen; 16644 ++len, code <<= 1, skip <<= 1) { 16645 for (var val = 0; val < n; ++val) { 16646 if (lengths[val] == len) { 16647 // bit-reverse the code 16648 var code2 = 0; 16649 var t = code; 16650 for (var i = 0; i < len; ++i) { 16651 code2 = (code2 << 1) | (t & 1); 16652 t >>= 1; 16653 } 16654
16655 // fill the table entries 16656 for (var i = code2; i < size; i += skip) 16657 codes[i] = (len << 16) | val; 16658 16659 ++code; 16660 } 16661 } 16662 } 16663 16664 return [codes, maxLen]; 16665 }; 16666 16667 constructor.prototype.readBlock = function() { 16668 function repeat(stream, array, len, offset, what) { 16669 var repeat = stream.getBits(len) + offset; 16670 while (repeat-- > 0) 16671 array[i++] = what; 16672 } 16673 16674 // read block header 16675 var hdr = this.getBits(3); 16676 if (hdr & 1) 16677 this.eof = true; 16678 hdr >>= 1; 16679 16680 if (hdr == 0) { // uncompressed block 16681 var bytes = this.bytes; 16682 var bytesPos = this.bytesPos; 16683 var b; 16684 16685 if (typeof (b = bytes[bytesPos++]) == 'undefined') 16686 error('Bad block header in flate stream'); 16687 var blockLen = b; 16688 if (typeof (b = bytes[bytesPos++]) == 'undefined') 16689 error('Bad block header in flate stream'); 16690 blockLen |= (b << 8); 16691 if (typeof (b = bytes[bytesPos++]) == 'undefined') 16692 error('Bad block header in flate stream'); 16693 var check = b; 16694 if (typeof (b = bytes[bytesPos++]) == 'undefined') 16695 error('Bad block header in flate stream'); 16696 check |= (b << 8); 16697 if (check != (~blockLen & 0xffff)) 16698 error('Bad uncompressed block length in flate stream'); 16699 16700 this.codeBuf = 0; 16701 this.codeSize = 0; 16702 16703 var bufferLength = this.bufferLength; 16704 var buffer = this.ensureBuffer(bufferLength + blockLen); 16705 var end = bufferLength + blockLen; 16706 this.bufferLength = end; 16707 for (var n = bufferLength; n < end; ++n) { 16708 if (typeof (b = bytes[bytesPos++]) == 'undefined') { 16709 this.eof = true; 16710 break; 16711 } 16712 buffer[n] = b; 16713 } 16714 this.bytesPos = bytesPos; 16715 return; 16716 } 16717 16718 var litCodeTable; 16719 var distCodeTable; 16720 if (hdr == 1) { // compressed block, fixed codes 16721 litCodeTable = fixedLitCodeTab; 16722 distCodeTable = fixedDistCodeTab; 16723 } else if (hdr == 2) { // compressed block, dynamic codes 16724 var numLitCodes = this.getBits(5) + 257; 16725 var numDistCodes = this.getBits(5) + 1; 16726 var numCodeLenCodes = this.getBits(4) + 4; 16727 16728 // build the code lengths code table 16729 var codeLenCodeLengths = Array(codeLenCodeMap.length); 16730 var i = 0; 16731 while (i < numCodeLenCodes) 16732 codeLenCodeLengths[codeLenCodeMap[i++]] = this.getBits(3); 16733 var codeLenCodeTab = this.generateHuffmanTable(codeLenCodeLengths); 16734 16735 // build the literal and distance code tables 16736 var len = 0; 16737 var i = 0; 16738 var codes = numLitCodes + numDistCodes; 16739 var codeLengths = new Array(codes); 16740 while (i < codes) { 16741 var code = this.getCode(codeLenCodeTab); 16742 if (code == 16) { 16743 repeat(this, codeLengths, 2, 3, len); 16744 } else if (code == 17) { 16745 repeat(this, codeLengths, 3, 3, len = 0); 16746 } else if (code == 18) { 16747 repeat(this, codeLengths, 7, 11, len = 0); 16748 } else { 16749 codeLengths[i++] = len = code; 16750 } 16751 } 16752 16753 litCodeTable = 16754 this.generateHuffmanTable(codeLengths.slice(0, numLitCodes)); 16755 distCodeTable = 16756 this.generateHuffmanTable(codeLengths.slice(numLitCodes, codes)); 16757 } else { 16758 error('Unknown block type in flate stream'); 16759 } 16760 16761 var buffer = this.buffer; 16762 var limit = buffer ? buffer.length : 0; 16763 var pos = this.bufferLength; 16764 while (true) { 16765 var code1 = this.getCode(litCodeTable); 16766 if (code1 < 256) { 16767 if (pos + 1 >= limit) { 16768 buffer = this.ensureBuffer(pos + 1); 16769 limit = buffer.length; 16770 } 16771 buffer[pos++] = code1; 16772 continue; 16773 } 16774 if (code1 == 256) { 16775 this.bufferLength = pos; 16776 return; 16777 } 16778 code1 -= 257; 16779 code1 = lengthDecode[code1]; 16780 var code2 = code1 >> 16; 16781 if (code2 > 0) 16782 code2 = this.getBits(code2); 16783 var len = (code1 & 0xffff) + code2;
16784 code1 = this.getCode(distCodeTable); 16785 code1 = distDecode[code1]; 16786 code2 = code1 >> 16; 16787 if (code2 > 0) 16788 code2 = this.getBits(code2); 16789 var dist = (code1 & 0xffff) + code2; 16790 if (pos + len >= limit) { 16791 buffer = this.ensureBuffer(pos + len); 16792 limit = buffer.length; 16793 } 16794 for (var k = 0; k < len; ++k, ++pos) 16795 buffer[pos] = buffer[pos - dist]; 16796 } 16797 }; 16798 16799 return constructor; 16800 })(); 16801 16802 /** 16803 * JavaScript Polyfill functions for jsPDF 16804 * Collected from public resources by 16805 * https://github.com/diegocr 16806 */ 16807 16808 (function (global) { 16809 var b64 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='; 16810 16811 if (typeof global.btoa === 'undefined') { 16812 global.btoa = function(data) { 16813 // discuss at: http://phpjs.org/functions/base64_encode/ 16814 // original by: Tyler Akins (http://rumkin.com) 16815 // improved by: Bayron Guevara 16816 // improved by: Thunder.m 16817 // improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) 16818 // improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) 16819 // improved by: Rafal Kukawski (http://kukawski.pl) 16820 // bugfixed by: Pellentesque Malesuada 16821 // example 1: base64_encode('Kevin van Zonneveld'); 16822 // returns 1: 'S2V2aW4gdmFuIFpvbm5ldmVsZA==' 16823 16824 var o1,o2,o3,h1,h2,h3,h4,bits,i = 0,ac = 0,enc = '',tmp_arr = []; 16825 16826 if (!data) { 16827 return data; 16828 } 16829 16830 do { // pack three octets into four hexets 16831 o1 = data.charCodeAt(i++); 16832 o2 = data.charCodeAt(i++); 16833 o3 = data.charCodeAt(i++); 16834 16835 bits = o1 << 16 | o2 << 8 | o3; 16836 16837 h1 = bits >> 18 & 0x3f; 16838 h2 = bits >> 12 & 0x3f; 16839 h3 = bits >> 6 & 0x3f; 16840 h4 = bits & 0x3f; 16841 16842 // use hexets to index into b64, and append result to encoded string 16843 tmp_arr[ac++] = b64.charAt(h1) + b64.charAt(h2) + b64.charAt(h3) + b64.charAt(h4); 16844 } while (i < data.length); 16845 16846 enc = tmp_arr.join(''); 16847 16848 var r = data.length % 3; 16849 16850 return (r ? enc.slice(0, r - 3) : enc) + '==='.slice(r || 3); 16851 }; 16852 } 16853 16854 if (typeof global.atob === 'undefined') { 16855 global.atob = function(data) { 16856 // discuss at: http://phpjs.org/functions/base64_decode/ 16857 // original by: Tyler Akins (http://rumkin.com) 16858 // improved by: Thunder.m 16859 // improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) 16860 // improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) 16861 // input by: Aman Gupta 16862 // input by: Brett Zamir (http://brett-zamir.me) 16863 // bugfixed by: Onno Marsman 16864 // bugfixed by: Pellentesque Malesuada 16865 // bugfixed by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) 16866 // example 1: base64_decode('S2V2aW4gdmFuIFpvbm5ldmVsZA=='); 16867 // returns 1: 'Kevin van Zonneveld' 16868 16869 var o1,o2,o3,h1,h2,h3,h4,bits,i = 0,ac = 0,dec = '',tmp_arr = []; 16870 16871 if (!data) { 16872 return data; 16873 } 16874 16875 data += ''; 16876 16877 do { // unpack four hexets into three octets using index points in b64 16878 h1 = b64.indexOf(data.charAt(i++)); 16879 h2 = b64.indexOf(data.charAt(i++)); 16880 h3 = b64.indexOf(data.charAt(i++)); 16881 h4 = b64.indexOf(data.charAt(i++)); 16882 16883 bits = h1 << 18 | h2 << 12 | h3 << 6 | h4; 16884 16885 o1 = bits >> 16 & 0xff; 16886 o2 = bits >> 8 & 0xff; 16887 o3 = bits & 0xff;
16888 16889 if (h3 == 64) { 16890 tmp_arr[ac++] = String.fromCharCode(o1); 16891 } else if (h4 == 64) { 16892 tmp_arr[ac++] = String.fromCharCode(o1, o2); 16893 } else { 16894 tmp_arr[ac++] = String.fromCharCode(o1, o2, o3); 16895 } 16896 } while (i < data.length); 16897 16898 dec = tmp_arr.join(''); 16899 16900 return dec; 16901 }; 16902 } 16903 16904 if (!Array.prototype.map) { 16905 Array.prototype.map = function(fun /*, thisArg */) { 16906 if (this === void 0 || this === null || typeof fun !== "function") 16907 throw new TypeError(); 16908 16909 var t = Object(this), len = t.length >>> 0, res = new Array(len); 16910 var thisArg = arguments.length > 1 ? arguments[1] : void 0; 16911 for (var i = 0; i < len; i++) { 16912 // NOTE: Absolute correctness would demand Object.defineProperty 16913 // be used. But this method is fairly new, and failure is 16914 // possible only if Object.prototype or Array.prototype 16915 // has a property |i| (very unlikely), so use a less-correct 16916 // but more portable alternative. 16917 if (i in t) 16918 res[i] = fun.call(thisArg, t[i], i, t); 16919 } 16920 16921 return res; 16922 }; 16923 } 16924 16925 16926 if(!Array.isArray) { 16927 Array.isArray = function(arg) { 16928 return Object.prototype.toString.call(arg) === '[object Array]'; 16929 }; 16930 } 16931 16932 if (!Array.prototype.forEach) { 16933 Array.prototype.forEach = function(fun, thisArg) { 16934 "use strict"; 16935 16936 if (this === void 0 || this === null || typeof fun !== "function") 16937 throw new TypeError(); 16938 16939 var t = Object(this), len = t.length >>> 0; 16940 for (var i = 0; i < len; i++) { 16941 if (i in t) 16942 fun.call(thisArg, t[i], i, t); 16943 } 16944 }; 16945 } 16946 16947 if (!Object.keys) { 16948 Object.keys = (function () { 16949 'use strict'; 16950 16951 var hasOwnProperty = Object.prototype.hasOwnProperty, 16952 hasDontEnumBug = !({toString: null}).propertyIsEnumerable('toString'), 16953 dontEnums = ['toString','toLocaleString','valueOf','hasOwnProperty', 16954 'isPrototypeOf','propertyIsEnumerable','constructor'], 16955 dontEnumsLength = dontEnums.length; 16956 16957 return function (obj) { 16958 if (typeof obj !== 'object' && (typeof obj !== 'function' || obj === null)) { 16959 throw new TypeError(); 16960 } 16961 var result = [], prop, i; 16962 16963 for (prop in obj) { 16964 if (hasOwnProperty.call(obj, prop)) { 16965 result.push(prop); 16966 } 16967 } 16968 16969 if (hasDontEnumBug) { 16970 for (i = 0; i < dontEnumsLength; i++) { 16971 if (hasOwnProperty.call(obj, dontEnums[i])) { 16972 result.push(dontEnums[i]); 16973 } 16974 } 16975 } 16976 return result; 16977 }; 16978 }()); 16979 } 16980 16981 if (!String.prototype.trim) { 16982 String.prototype.trim = function () { 16983 return this.replace(/^\s+|\s+$/g, ''); 16984 }; 16985 } 16986 if (!String.prototype.trimLeft) { 16987 String.prototype.trimLeft = function() { 16988 return this.replace(/^\s+/g, ""); 16989 }; 16990 } 16991 if (!String.prototype.trimRight) { 16992 String.prototype.trimRight = function() { 16993 return this.replace(/\s+$/g, ""); 16994 }; 16995 } 16996 16997 })(typeof self !== "undefined" && self || typeof window !== "undefined" && window || undefined); 16998 16999 var jsPDF = jsPDF; 17000 17001 return jsPDF; 17002 17003}
vendor: 4 bytes, line 17003
17003));
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.