From 9daaa0beda731ba97feb322ca4f3790b9aeb22d9 Mon Sep 17 00:00:00 2001
From: unknown
Date: Wed, 13 May 2015 13:30:19 -0400
Subject: [PATCH 1/4] Changes to tableExport
---
jquery.base64.js | 249 ++----
jspdf/jspdf.js | 2240 +++++++++++++++++++++++++++++++++++++++-------
tableExport.js | 88 +-
3 files changed, 2064 insertions(+), 513 deletions(-)
diff --git a/jquery.base64.js b/jquery.base64.js
index 6c98f156..322a0f7b 100644
--- a/jquery.base64.js
+++ b/jquery.base64.js
@@ -1,190 +1,59 @@
-/*jslint adsafe: false, bitwise: true, browser: true, cap: false, css: false,
- debug: false, devel: true, eqeqeq: true, es5: false, evil: false,
- forin: false, fragment: false, immed: true, laxbreak: false, newcap: true,
- nomen: false, on: false, onevar: true, passfail: false, plusplus: true,
- regexp: false, rhino: true, safe: false, strict: false, sub: false,
- undef: true, white: false, widget: false, windows: false */
-/*global jQuery: false, window: false */
-//"use strict";
-
-/*
- * Original code (c) 2010 Nick Galbreath
- * http://code.google.com/p/stringencoders/source/browse/#svn/trunk/javascript
- *
- * jQuery port (c) 2010 Carlo Zottmann
- * http://github.com/carlo/jquery-base64
- *
- * Permission is hereby granted, free of charge, to any person
- * obtaining a copy of this software and associated documentation
- * files (the "Software"), to deal in the Software without
- * restriction, including without limitation the rights to use,
- * copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following
- * conditions:
- *
- * The above copyright notice and this permission notice shall be
- * included in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
- * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
- * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
- * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
-*/
-
-/* base64 encode/decode compatible with window.btoa/atob
- *
- * window.atob/btoa is a Firefox extension to convert binary data (the "b")
- * to base64 (ascii, the "a").
- *
- * It is also found in Safari and Chrome. It is not available in IE.
- *
- * if (!window.btoa) window.btoa = $.base64.encode
- * if (!window.atob) window.atob = $.base64.decode
- *
- * The original spec's for atob/btoa are a bit lacking
- * https://developer.mozilla.org/en/DOM/window.atob
- * https://developer.mozilla.org/en/DOM/window.btoa
- *
- * window.btoa and $.base64.encode takes a string where charCodeAt is [0,255]
- * If any character is not [0,255], then an exception is thrown.
- *
- * window.atob and $.base64.decode take a base64-encoded string
- * If the input length is not a multiple of 4, or contains invalid characters
- * then an exception is thrown.
- */
-
-jQuery.base64 = ( function( $ ) {
-
- var _PADCHAR = "=",
- _ALPHA = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",
- _VERSION = "1.0";
-
-
- function _getbyte64( s, i ) {
- // This is oddly fast, except on Chrome/V8.
- // Minimal or no improvement in performance by using a
- // object with properties mapping chars to value (eg. 'A': 0)
-
- var idx = _ALPHA.indexOf( s.charAt( i ) );
-
- if ( idx === -1 ) {
- throw "Cannot decode base64";
- }
-
- return idx;
- }
-
-
- function _decode( s ) {
- var pads = 0,
- i,
- b10,
- imax = s.length,
- x = [];
-
- s = String( s );
-
- if ( imax === 0 ) {
- return s;
- }
-
- if ( imax % 4 !== 0 ) {
- throw "Cannot decode base64";
- }
-
- if ( s.charAt( imax - 1 ) === _PADCHAR ) {
- pads = 1;
-
- if ( s.charAt( imax - 2 ) === _PADCHAR ) {
- pads = 2;
- }
-
- // either way, we want to ignore this last block
- imax -= 4;
- }
-
- for ( i = 0; i < imax; i += 4 ) {
- b10 = ( _getbyte64( s, i ) << 18 ) | ( _getbyte64( s, i + 1 ) << 12 ) | ( _getbyte64( s, i + 2 ) << 6 ) | _getbyte64( s, i + 3 );
- x.push( String.fromCharCode( b10 >> 16, ( b10 >> 8 ) & 0xff, b10 & 0xff ) );
- }
-
- switch ( pads ) {
- case 1:
- b10 = ( _getbyte64( s, i ) << 18 ) | ( _getbyte64( s, i + 1 ) << 12 ) | ( _getbyte64( s, i + 2 ) << 6 );
- x.push( String.fromCharCode( b10 >> 16, ( b10 >> 8 ) & 0xff ) );
- break;
-
- case 2:
- b10 = ( _getbyte64( s, i ) << 18) | ( _getbyte64( s, i + 1 ) << 12 );
- x.push( String.fromCharCode( b10 >> 16 ) );
- break;
- }
-
- return x.join( "" );
- }
-
-
- function _getbyte( s, i ) {
- var x = s.charCodeAt( i );
-
- if ( x > 255 ) {
- throw "INVALID_CHARACTER_ERR: DOM Exception 5";
- }
-
- return x;
- }
-
-
- function _encode( s ) {
- if ( arguments.length !== 1 ) {
- throw "SyntaxError: exactly one argument required";
- }
-
- s = String( s );
-
- var i,
- b10,
- x = [],
- imax = s.length - s.length % 3;
-
- if ( s.length === 0 ) {
- return s;
- }
-
- for ( i = 0; i < imax; i += 3 ) {
- b10 = ( _getbyte( s, i ) << 16 ) | ( _getbyte( s, i + 1 ) << 8 ) | _getbyte( s, i + 2 );
- x.push( _ALPHA.charAt( b10 >> 18 ) );
- x.push( _ALPHA.charAt( ( b10 >> 12 ) & 0x3F ) );
- x.push( _ALPHA.charAt( ( b10 >> 6 ) & 0x3f ) );
- x.push( _ALPHA.charAt( b10 & 0x3f ) );
- }
-
- switch ( s.length - imax ) {
- case 1:
- b10 = _getbyte( s, i ) << 16;
- x.push( _ALPHA.charAt( b10 >> 18 ) + _ALPHA.charAt( ( b10 >> 12 ) & 0x3F ) + _PADCHAR + _PADCHAR );
- break;
-
- case 2:
- b10 = ( _getbyte( s, i ) << 16 ) | ( _getbyte( s, i + 1 ) << 8 );
- x.push( _ALPHA.charAt( b10 >> 18 ) + _ALPHA.charAt( ( b10 >> 12 ) & 0x3F ) + _ALPHA.charAt( ( b10 >> 6 ) & 0x3f ) + _PADCHAR );
- break;
- }
-
- return x.join( "" );
- }
-
-
- return {
- decode: _decode,
- encode: _encode,
- VERSION: _VERSION
- };
-
-}( jQuery ) );
-
+jQuery.base64 = (function($) {
+
+ // private property
+ var keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
+
+ // private method for UTF-8 encoding
+ function utf8Encode(string) {
+ string = string.replace(/\r\n/g,"\n");
+ var utftext = "";
+ for (var n = 0; n < string.length; n++) {
+ var c = string.charCodeAt(n);
+ if (c < 128) {
+ utftext += String.fromCharCode(c);
+ }
+ else if((c > 127) && (c < 2048)) {
+ utftext += String.fromCharCode((c >> 6) | 192);
+ utftext += String.fromCharCode((c & 63) | 128);
+ }
+ else {
+ utftext += String.fromCharCode((c >> 12) | 224);
+ utftext += String.fromCharCode(((c >> 6) & 63) | 128);
+ utftext += String.fromCharCode((c & 63) | 128);
+ }
+ }
+ return utftext;
+ }
+
+ function encode(input) {
+ var output = "";
+ var chr1, chr2, chr3, enc1, enc2, enc3, enc4;
+ var i = 0;
+ input = utf8Encode(input);
+ while (i < input.length) {
+ chr1 = input.charCodeAt(i++);
+ chr2 = input.charCodeAt(i++);
+ chr3 = input.charCodeAt(i++);
+ enc1 = chr1 >> 2;
+ enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
+ enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
+ enc4 = chr3 & 63;
+ if (isNaN(chr2)) {
+ enc3 = enc4 = 64;
+ } else if (isNaN(chr3)) {
+ enc4 = 64;
+ }
+ output = output +
+ keyStr.charAt(enc1) + keyStr.charAt(enc2) +
+ keyStr.charAt(enc3) + keyStr.charAt(enc4);
+ }
+ return output;
+ }
+
+ return {
+ encode: function (str) {
+ return encode(str);
+ }
+ };
+
+}(jQuery));
\ No newline at end of file
diff --git a/jspdf/jspdf.js b/jspdf/jspdf.js
index 2e703c93..ca1c688a 100644
--- a/jspdf/jspdf.js
+++ b/jspdf/jspdf.js
@@ -1,303 +1,1943 @@
+/** @preserve
+ * jsPDF - PDF Document creation from JavaScript
+ * Version ${versionID}
+ * CommitID ${commitID}
+ *
+ * Copyright (c) 2010-2014 James Hall, https://github.com/MrRio/jsPDF
+ * 2010 Aaron Spike, https://github.com/acspike
+ * 2012 Willow Systems Corporation, willow-systems.com
+ * 2012 Pablo Hess, https://github.com/pablohess
+ * 2012 Florian Jenett, https://github.com/fjenett
+ * 2013 Warren Weckesser, https://github.com/warrenweckesser
+ * 2013 Youssef Beddad, https://github.com/lifof
+ * 2013 Lee Driscoll, https://github.com/lsdriscoll
+ * 2013 Stefan Slonevskiy, https://github.com/stefslon
+ * 2013 Jeremy Morel, https://github.com/jmorel
+ * 2013 Christoph Hartmann, https://github.com/chris-rock
+ * 2014 Juan Pablo Gaviria, https://github.com/juanpgaviria
+ * 2014 James Makes, https://github.com/dollaruw
+ * 2014 Diego Casorran, https://github.com/diegocr
+ * 2014 Steven Spungin, https://github.com/Flamenco
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Contributor(s):
+ * siefkenj, ahwolf, rickygu, Midnith, saintclair, eaparango,
+ * kim3er, mfo, alnorth, Flamenco
+ */
+
/**
- * jsPDF
- * (c) 2009 James Hall
- *
- * Some parts based on FPDF.
+ * Creates new jsPDF document object instance.
+ *
+ * @class
+ * @param orientation One of "portrait" or "landscape" (or shortcuts "p" (Default), "l")
+ * @param unit Measurement unit to be used when coordinates are specified.
+ * One of "pt" (points), "mm" (Default), "cm", "in"
+ * @param format One of 'pageFormats' as shown below, default: a4
+ * @returns {jsPDF}
+ * @name jsPDF
*/
+var jsPDF = (function(global) {
+ 'use strict';
+ var pdfVersion = '1.3',
+ pageFormats = { // Size in pt of various paper formats
+ 'a0' : [2383.94, 3370.39], 'a1' : [1683.78, 2383.94],
+ 'a2' : [1190.55, 1683.78], 'a3' : [ 841.89, 1190.55],
+ 'a4' : [ 595.28, 841.89], 'a5' : [ 419.53, 595.28],
+ 'a6' : [ 297.64, 419.53], 'a7' : [ 209.76, 297.64],
+ 'a8' : [ 147.40, 209.76], 'a9' : [ 104.88, 147.40],
+ 'a10' : [ 73.70, 104.88], 'b0' : [2834.65, 4008.19],
+ 'b1' : [2004.09, 2834.65], 'b2' : [1417.32, 2004.09],
+ 'b3' : [1000.63, 1417.32], 'b4' : [ 708.66, 1000.63],
+ 'b5' : [ 498.90, 708.66], 'b6' : [ 354.33, 498.90],
+ 'b7' : [ 249.45, 354.33], 'b8' : [ 175.75, 249.45],
+ 'b9' : [ 124.72, 175.75], 'b10' : [ 87.87, 124.72],
+ 'c0' : [2599.37, 3676.54], 'c1' : [1836.85, 2599.37],
+ 'c2' : [1298.27, 1836.85], 'c3' : [ 918.43, 1298.27],
+ 'c4' : [ 649.13, 918.43], 'c5' : [ 459.21, 649.13],
+ 'c6' : [ 323.15, 459.21], 'c7' : [ 229.61, 323.15],
+ 'c8' : [ 161.57, 229.61], 'c9' : [ 113.39, 161.57],
+ 'c10' : [ 79.37, 113.39], 'dl' : [ 311.81, 623.62],
+ 'letter' : [612, 792],
+ 'government-letter' : [576, 756],
+ 'legal' : [612, 1008],
+ 'junior-legal' : [576, 360],
+ 'ledger' : [1224, 792],
+ 'tabloid' : [792, 1224],
+ 'credit-card' : [153, 243]
+ };
+
+ /**
+ * jsPDF's Internal PubSub Implementation.
+ * See mrrio.github.io/jsPDF/doc/symbols/PubSub.html
+ * Backward compatible rewritten on 2014 by
+ * Diego Casorran, https://github.com/diegocr
+ *
+ * @class
+ * @name PubSub
+ */
+ function PubSub(context) {
+ var topics = {};
+
+ this.subscribe = function(topic, callback, once) {
+ if(typeof callback !== 'function') {
+ return false;
+ }
+
+ if(!topics.hasOwnProperty(topic)) {
+ topics[topic] = {};
+ }
+
+ var id = Math.random().toString(35);
+ topics[topic][id] = [callback,!!once];
+
+ return id;
+ };
+
+ this.unsubscribe = function(token) {
+ for(var topic in topics) {
+ if(topics[topic][token]) {
+ delete topics[topic][token];
+ return true;
+ }
+ }
+ return false;
+ };
+
+ this.publish = function(topic) {
+ if(topics.hasOwnProperty(topic)) {
+ var args = Array.prototype.slice.call(arguments, 1), idr = [];
+
+ for(var id in topics[topic]) {
+ var sub = topics[topic][id];
+ try {
+ sub[0].apply(context, args);
+ } catch(ex) {
+ if(global.console) {
+ console.error('jsPDF PubSub Error', ex.message, ex);
+ }
+ }
+ if(sub[1]) idr.push(id);
+ }
+ if(idr.length) idr.forEach(this.unsubscribe);
+ }
+ };
+ }
+
+ /**
+ * @constructor
+ * @private
+ */
+ function jsPDF(orientation, unit, format, compressPdf) {
+ var options = {};
+
+ if (typeof orientation === 'object') {
+ options = orientation;
+
+ orientation = options.orientation;
+ unit = options.unit || unit;
+ format = options.format || format;
+ compressPdf = options.compress || options.compressPdf || compressPdf;
+ }
+
+ // Default options
+ unit = unit || 'mm';
+ format = format || 'a4';
+ orientation = ('' + (orientation || 'P')).toLowerCase();
+
+ var format_as_string = ('' + format).toLowerCase(),
+ compress = !!compressPdf && typeof Uint8Array === 'function',
+ textColor = options.textColor || '0 g',
+ drawColor = options.drawColor || '0 G',
+ activeFontSize = options.fontSize || 16,
+ lineHeightProportion = options.lineHeight || 1.15,
+ lineWidth = options.lineWidth || 0.200025, // 2mm
+ objectNumber = 2, // 'n' Current object number
+ outToPages = !1, // switches where out() prints. outToPages true = push to pages obj. outToPages false = doc builder content
+ offsets = [], // List of offsets. Activated and reset by buildDocument(). Pupulated by various calls buildDocument makes.
+ fonts = {}, // collection of font objects, where key is fontKey - a dynamically created label for a given font.
+ fontmap = {}, // mapping structure fontName > fontStyle > font key - performance layer. See addFont()
+ activeFontKey, // will be string representing the KEY of the font as combination of fontName + fontStyle
+ k, // Scale factor
+ tmp,
+ page = 0,
+ currentPage,
+ pages = [],
+ pagedim = {},
+ content = [],
+ lineCapID = 0,
+ lineJoinID = 0,
+ content_length = 0,
+ pageWidth,
+ pageHeight,
+ pageMode,
+ zoomMode,
+ layoutMode,
+ documentProperties = {
+ 'title' : '',
+ 'subject' : '',
+ 'author' : '',
+ 'keywords' : '',
+ 'creator' : ''
+ },
+ API = {},
+ events = new PubSub(API),
+ lastTextWasStroke = false,
+
+ /////////////////////
+ // Private functions
+ /////////////////////
+ f2 = function(number) {
+ return number.toFixed(2); // Ie, %.2f
+ },
+ f3 = function(number) {
+ return number.toFixed(3); // Ie, %.3f
+ },
+ padd2 = function(number) {
+ return ('0' + parseInt(number)).slice(-2);
+ },
+ out = function(string) {
+ if (outToPages) {
+ /* set by beginPage */
+ pages[currentPage].push(string);
+ } else {
+ // +1 for '\n' that will be used to join 'content'
+ content_length += string.length + 1;
+ content.push(string);
+ }
+ },
+ newObject = function() {
+ // Begin a new object
+ objectNumber++;
+ offsets[objectNumber] = content_length;
+ out(objectNumber + ' 0 obj');
+ return objectNumber;
+ },
+ // Does not output the object. The caller must call newObjectDeferredBegin(oid) before outputing any data
+ newObjectDeferred = function() {
+ objectNumber++;
+ offsets[objectNumber] = function(){
+ return content_length;
+ };
+ return objectNumber;
+ },
+ newObjectDeferredBegin = function(oid) {
+ offsets[oid] = content_length;
+ },
+ putStream = function(str) {
+ out('stream');
+ out(str);
+ out('endstream');
+ },
+ putPages = function() {
+ var n,p,arr,i,deflater,adler32,adler32cs,wPt,hPt;
+
+ adler32cs = global.adler32cs || jsPDF.adler32cs;
+ if (compress && typeof adler32cs === 'undefined') {
+ compress = false;
+ }
+
+ // outToPages = false as set in endDocument(). out() writes to content.
+
+ for (n = 1; n <= page; n++) {
+ newObject();
+ wPt = (pageWidth = pagedim[n].width) * k;
+ hPt = (pageHeight = pagedim[n].height) * k;
+ out('<>');
+ out('endobj');
+
+ // Page content
+ p = pages[n].join('\n');
+ newObject();
+ if (compress) {
+ arr = [];
+ i = p.length;
+ while(i--) {
+ arr[i] = p.charCodeAt(i);
+ }
+ adler32 = adler32cs.from(p);
+ deflater = new Deflater(6);
+ deflater.append(new Uint8Array(arr));
+ p = deflater.flush();
+ arr = new Uint8Array(p.length + 6);
+ arr.set(new Uint8Array([120, 156])),
+ arr.set(p, 2);
+ arr.set(new Uint8Array([adler32 & 0xFF, (adler32 >> 8) & 0xFF, (adler32 >> 16) & 0xFF, (adler32 >> 24) & 0xFF]), p.length+2);
+ p = String.fromCharCode.apply(null, arr);
+ out('<>');
+ } else {
+ out('<>');
+ }
+ putStream(p);
+ out('endobj');
+ }
+ offsets[1] = content_length;
+ out('1 0 obj');
+ out('<< page; i++) {
+ kids += (3 + 2 * i) + ' 0 R ';
+ }
+ out(kids + ']');
+ out('/Count ' + page);
+ out('>>');
+ out('endobj');
+ },
+ putFont = function(font) {
+ font.objectNumber = newObject();
+ out('<>');
+ out('endobj');
+ },
+ putFonts = function() {
+ for (var fontKey in fonts) {
+ if (fonts.hasOwnProperty(fontKey)) {
+ putFont(fonts[fontKey]);
+ }
+ }
+ },
+ putXobjectDict = function() {
+ // Loop through images, or other data objects
+ events.publish('putXobjectDict');
+ },
+ putResourceDictionary = function() {
+ out('/ProcSet [/PDF /Text /ImageB /ImageC /ImageI]');
+ out('/Font <<');
+
+ // Do this for each font, the '1' bit is the index of the font
+ for (var fontKey in fonts) {
+ if (fonts.hasOwnProperty(fontKey)) {
+ out('/' + fontKey + ' ' + fonts[fontKey].objectNumber + ' 0 R');
+ }
+ }
+ out('>>');
+ out('/XObject <<');
+ putXobjectDict();
+ out('>>');
+ },
+ putResources = function() {
+ putFonts();
+ events.publish('putResources');
+ // Resource dictionary
+ offsets[2] = content_length;
+ out('2 0 obj');
+ out('<<');
+ putResourceDictionary();
+ out('>>');
+ out('endobj');
+ events.publish('postPutResources');
+ },
+ addToFontDictionary = function(fontKey, fontName, fontStyle) {
+ // this is mapping structure for quick font key lookup.
+ // returns the KEY of the font (ex: "F1") for a given
+ // pair of font name and type (ex: "Arial". "Italic")
+ if (!fontmap.hasOwnProperty(fontName)) {
+ fontmap[fontName] = {};
+ }
+ fontmap[fontName][fontStyle] = fontKey;
+ },
+ /**
+ * FontObject describes a particular font as member of an instnace of jsPDF
+ *
+ * It's a collection of properties like 'id' (to be used in PDF stream),
+ * 'fontName' (font's family name), 'fontStyle' (font's style variant label)
+ *
+ * @class
+ * @public
+ * @property id {String} PDF-document-instance-specific label assinged to the font.
+ * @property PostScriptName {String} PDF specification full name for the font
+ * @property encoding {Object} Encoding_name-to-Font_metrics_object mapping.
+ * @name FontObject
+ */
+ addFont = function(PostScriptName, fontName, fontStyle, encoding) {
+ var fontKey = 'F' + (Object.keys(fonts).length + 1).toString(10),
+ // This is FontObject
+ font = fonts[fontKey] = {
+ 'id' : fontKey,
+ 'PostScriptName' : PostScriptName,
+ 'fontName' : fontName,
+ 'fontStyle' : fontStyle,
+ 'encoding' : encoding,
+ 'metadata' : {}
+ };
+ addToFontDictionary(fontKey, fontName, fontStyle);
+ events.publish('addFont', font);
+
+ return fontKey;
+ },
+ addFonts = function() {
+
+ var HELVETICA = "helvetica",
+ TIMES = "times",
+ COURIER = "courier",
+ NORMAL = "normal",
+ BOLD = "bold",
+ ITALIC = "italic",
+ BOLD_ITALIC = "bolditalic",
+ encoding = 'StandardEncoding',
+ 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]
+ ];
+
+ for (var i = 0, l = standardFonts.length; i < l; i++) {
+ var fontKey = addFont(
+ standardFonts[i][0],
+ standardFonts[i][1],
+ standardFonts[i][2],
+ encoding);
+
+ // adding aliases for standard fonts, this time matching the capitalization
+ var parts = standardFonts[i][0].split('-');
+ addToFontDictionary(fontKey, parts[0], parts[1] || '');
+ }
+ events.publish('addFonts', { fonts : fonts, dictionary : fontmap });
+ },
+ SAFE = function __safeCall(fn) {
+ fn.foo = function __safeCallWrapper() {
+ try {
+ return fn.apply(this, arguments);
+ } catch (e) {
+ var stack = e.stack || '';
+ if(~stack.indexOf(' at ')) stack = stack.split(" at ")[1];
+ var m = "Error in function " + stack.split("\n")[0].split('<')[0] + ": " + e.message;
+ if(global.console) {
+ global.console.error(m, e);
+ if(global.alert) alert(m);
+ } else {
+ throw new Error(m);
+ }
+ }
+ };
+ fn.foo.bar = fn;
+ return fn.foo;
+ },
+ to8bitStream = function(text, flags) {
+ /**
+ * PDF 1.3 spec:
+ * "For text strings encoded in Unicode, the first two bytes must be 254 followed by
+ * 255, representing the Unicode byte order marker, U+FEFF. (This sequence conflicts
+ * with the PDFDocEncoding character sequence thorn ydieresis, which is unlikely
+ * to be a meaningful beginning of a word or phrase.) The remainder of the
+ * string consists of Unicode character codes, according to the UTF-16 encoding
+ * specified in the Unicode standard, version 2.0. Commonly used Unicode values
+ * are represented as 2 bytes per character, with the high-order byte appearing first
+ * in the string."
+ *
+ * In other words, if there are chars in a string with char code above 255, we
+ * recode the string to UCS2 BE - string doubles in length and BOM is prepended.
+ *
+ * HOWEVER!
+ * Actual *content* (body) text (as opposed to strings used in document properties etc)
+ * does NOT expect BOM. There, it is treated as a literal GID (Glyph ID)
+ *
+ * Because of Adobe's focus on "you subset your fonts!" you are not supposed to have
+ * a font that maps directly Unicode (UCS2 / UTF16BE) code to font GID, but you could
+ * fudge it with "Identity-H" encoding and custom CIDtoGID map that mimics Unicode
+ * code page. There, however, all characters in the stream are treated as GIDs,
+ * including BOM, which is the reason we need to skip BOM in content text (i.e. that
+ * that is tied to a font).
+ *
+ * To signal this "special" PDFEscape / to8bitStream handling mode,
+ * API.text() function sets (unless you overwrite it with manual values
+ * given to API.text(.., flags) )
+ * flags.autoencode = true
+ * flags.noBOM = true
+ *
+ * ===================================================================================
+ * `flags` properties relied upon:
+ * .sourceEncoding = string with encoding label.
+ * "Unicode" by default. = encoding of the incoming text.
+ * pass some non-existing encoding name
+ * (ex: 'Do not touch my strings! I know what I am doing.')
+ * to make encoding code skip the encoding step.
+ * .outputEncoding = Either valid PDF encoding name
+ * (must be supported by jsPDF font metrics, otherwise no encoding)
+ * or a JS object, where key = sourceCharCode, value = outputCharCode
+ * missing keys will be treated as: sourceCharCode === outputCharCode
+ * .noBOM
+ * See comment higher above for explanation for why this is important
+ * .autoencode
+ * See comment higher above for explanation for why this is important
+ */
+
+ var i,l,sourceEncoding,encodingBlock,outputEncoding,newtext,isUnicode,ch,bch;
+
+ flags = flags || {};
+ sourceEncoding = flags.sourceEncoding || 'Unicode';
+ outputEncoding = flags.outputEncoding;
+
+ // This 'encoding' section relies on font metrics format
+ // attached to font objects by, among others,
+ // "Willow Systems' standard_font_metrics plugin"
+ // see jspdf.plugin.standard_font_metrics.js for format
+ // of the font.metadata.encoding Object.
+ // It should be something like
+ // .encoding = {'codePages':['WinANSI....'], 'WinANSI...':{code:code, ...}}
+ // .widths = {0:width, code:width, ..., 'fof':divisor}
+ // .kerning = {code:{previous_char_code:shift, ..., 'fof':-divisor},...}
+ if ((flags.autoencode || outputEncoding) &&
+ fonts[activeFontKey].metadata &&
+ fonts[activeFontKey].metadata[sourceEncoding] &&
+ fonts[activeFontKey].metadata[sourceEncoding].encoding) {
+ encodingBlock = fonts[activeFontKey].metadata[sourceEncoding].encoding;
+
+ // each font has default encoding. Some have it clearly defined.
+ if (!outputEncoding && fonts[activeFontKey].encoding) {
+ outputEncoding = fonts[activeFontKey].encoding;
+ }
+
+ // Hmmm, the above did not work? Let's try again, in different place.
+ if (!outputEncoding && encodingBlock.codePages) {
+ outputEncoding = encodingBlock.codePages[0]; // let's say, first one is the default
+ }
+
+ if (typeof outputEncoding === 'string') {
+ outputEncoding = encodingBlock[outputEncoding];
+ }
+ // we want output encoding to be a JS Object, where
+ // key = sourceEncoding's character code and
+ // value = outputEncoding's character code.
+ if (outputEncoding) {
+ isUnicode = false;
+ newtext = [];
+ for (i = 0, l = text.length; i < l; i++) {
+ ch = outputEncoding[text.charCodeAt(i)];
+ if (ch) {
+ newtext.push(
+ String.fromCharCode(ch));
+ } else {
+ newtext.push(
+ text[i]);
+ }
+
+ // since we are looping over chars anyway, might as well
+ // check for residual unicodeness
+ if (newtext[i].charCodeAt(0) >> 8) {
+ /* more than 255 */
+ isUnicode = true;
+ }
+ }
+ text = newtext.join('');
+ }
+ }
+
+ i = text.length;
+ // isUnicode may be set to false above. Hence the triple-equal to undefined
+ while (isUnicode === undefined && i !== 0) {
+ if (text.charCodeAt(i - 1) >> 8) {
+ /* more than 255 */
+ isUnicode = true;
+ }
+ i--;
+ }
+ if (!isUnicode) {
+ return text;
+ }
+
+ newtext = flags.noBOM ? [] : [254, 255];
+ for (i = 0, l = text.length; i < l; i++) {
+ ch = text.charCodeAt(i);
+ bch = ch >> 8; // divide by 256
+ if (bch >> 8) {
+ /* something left after dividing by 256 second time */
+ throw new Error("Character at position " + i + " of string '"
+ + text + "' exceeds 16bits. Cannot be encoded into UCS-2 BE");
+ }
+ newtext.push(bch);
+ newtext.push(ch - (bch << 8));
+ }
+ return String.fromCharCode.apply(undefined, newtext);
+ },
+ pdfEscape = function(text, flags) {
+ /**
+ * Replace '/', '(', and ')' with pdf-safe versions
+ *
+ * Doing to8bitStream does NOT make this PDF display unicode text. For that
+ * we also need to reference a unicode font and embed it - royal pain in the rear.
+ *
+ * There is still a benefit to to8bitStream - PDF simply cannot handle 16bit chars,
+ * which JavaScript Strings are happy to provide. So, while we still cannot display
+ * 2-byte characters property, at least CONDITIONALLY converting (entire string containing)
+ * 16bit chars to (USC-2-BE) 2-bytes per char + BOM streams we ensure that entire PDF
+ * is still parseable.
+ * This will allow immediate support for unicode in document properties strings.
+ */
+ return to8bitStream(text, flags).replace(/\\/g, '\\\\').replace(/\(/g, '\\(').replace(/\)/g, '\\)');
+ },
+ putInfo = function() {
+ out('/Producer (jsPDF ' + jsPDF.version + ')');
+ for(var key in documentProperties) {
+ if(documentProperties.hasOwnProperty(key) && documentProperties[key]) {
+ out('/'+key.substr(0,1).toUpperCase() + key.substr(1)
+ +' (' + pdfEscape(documentProperties[key]) + ')');
+ }
+ }
+ var created = new Date(),
+ tzoffset = created.getTimezoneOffset(),
+ tzsign = tzoffset < 0 ? '+' : '-',
+ tzhour = Math.floor(Math.abs(tzoffset / 60)),
+ tzmin = Math.abs(tzoffset % 60),
+ tzstr = [tzsign, padd2(tzhour), "'", padd2(tzmin), "'"].join('');
+ out(['/CreationDate (D:',
+ created.getFullYear(),
+ padd2(created.getMonth() + 1),
+ padd2(created.getDate()),
+ padd2(created.getHours()),
+ padd2(created.getMinutes()),
+ padd2(created.getSeconds()), tzstr, ')'].join(''));
+ },
+ putCatalog = function() {
+ out('/Type /Catalog');
+ out('/Pages 1 0 R');
+ // PDF13ref Section 7.2.1
+ if (!zoomMode) zoomMode = 'fullwidth';
+ switch(zoomMode) {
+ case 'fullwidth' : out('/OpenAction [3 0 R /FitH null]'); break;
+ case 'fullheight' : out('/OpenAction [3 0 R /FitV null]'); break;
+ case 'fullpage' : out('/OpenAction [3 0 R /Fit]'); break;
+ case 'original' : out('/OpenAction [3 0 R /XYZ null null 1]'); break;
+ default:
+ var pcn = '' + zoomMode;
+ if (pcn.substr(pcn.length-1) === '%')
+ zoomMode = parseInt(zoomMode) / 100;
+ if (typeof zoomMode === 'number') {
+ out('/OpenAction [3 0 R /XYZ null null '+f2(zoomMode)+']');
+ }
+ }
+ if (!layoutMode) layoutMode = 'continuous';
+ switch(layoutMode) {
+ case 'continuous' : out('/PageLayout /OneColumn'); break;
+ case 'single' : out('/PageLayout /SinglePage'); break;
+ case 'two':
+ case 'twoleft' : out('/PageLayout /TwoColumnLeft'); break;
+ case 'tworight' : out('/PageLayout /TwoColumnRight'); break;
+ }
+ if (pageMode) {
+ /**
+ * A name object specifying how the document should be displayed when opened:
+ * UseNone : Neither document outline nor thumbnail images visible -- DEFAULT
+ * UseOutlines : Document outline visible
+ * UseThumbs : Thumbnail images visible
+ * FullScreen : Full-screen mode, with no menu bar, window controls, or any other window visible
+ */
+ out('/PageMode /' + pageMode);
+ }
+ events.publish('putCatalog');
+ },
+ putTrailer = function() {
+ out('/Size ' + (objectNumber + 1));
+ out('/Root ' + objectNumber + ' 0 R');
+ out('/Info ' + (objectNumber - 1) + ' 0 R');
+ },
+ beginPage = function(width,height) {
+ // Dimensions are stored as user units and converted to points on output
+ var orientation = typeof height === 'string' && height.toLowerCase();
+ if (typeof width === 'string') {
+ var format = width.toLowerCase();
+ if (pageFormats.hasOwnProperty(format)) {
+ width = pageFormats[format][0] / k;
+ height = pageFormats[format][1] / k;
+ }
+ }
+ if (Array.isArray(width)) {
+ height = width[1];
+ width = width[0];
+ }
+ if (orientation) {
+ switch(orientation.substr(0,1)) {
+ case 'l': if (height > width ) orientation = 's'; break;
+ case 'p': if (width > height ) orientation = 's'; break;
+ }
+ if (orientation === 's') { tmp = width; width = height; height = tmp; }
+ }
+ outToPages = true;
+ pages[++page] = [];
+ pagedim[page] = {
+ width : Number(width) || pageWidth,
+ height : Number(height) || pageHeight
+ };
+ _setPage(page);
+ },
+ _addPage = function() {
+ beginPage.apply(this, arguments);
+ // Set line width
+ out(f2(lineWidth * k) + ' w');
+ // Set draw color
+ out(drawColor);
+ // resurrecting non-default line caps, joins
+ if (lineCapID !== 0) {
+ out(lineCapID + ' J');
+ }
+ if (lineJoinID !== 0) {
+ out(lineJoinID + ' j');
+ }
+ events.publish('addPage', { pageNumber : page });
+ },
+ _setPage = function(n) {
+ if (n > 0 && n <= page) {
+ currentPage = n;
+ pageWidth = pagedim[n].width;
+ pageHeight = pagedim[n].height;
+ }
+ },
+ /**
+ * Returns a document-specific font key - a label assigned to a
+ * font name + font type combination at the time the font was added
+ * to the font inventory.
+ *
+ * Font key is used as label for the desired font for a block of text
+ * to be added to the PDF document stream.
+ * @private
+ * @function
+ * @param fontName {String} can be undefined on "falthy" to indicate "use current"
+ * @param fontStyle {String} can be undefined on "falthy" to indicate "use current"
+ * @returns {String} Font key.
+ */
+ getFont = function(fontName, fontStyle) {
+ var key;
+
+ fontName = fontName !== undefined ? fontName : fonts[activeFontKey].fontName;
+ fontStyle = fontStyle !== undefined ? fontStyle : fonts[activeFontKey].fontStyle;
+
+ try {
+ // get a string like 'F3' - the KEY corresponding tot he font + type combination.
+ key = fontmap[fontName][fontStyle];
+ } catch (e) {}
+
+ if (!key) {
+ throw new Error("Unable to look up font label for font '" + fontName + "', '"
+ + fontStyle + "'. Refer to getFontList() for available fonts.");
+ }
+ return key;
+ },
+ buildDocument = function() {
+
+ outToPages = false; // switches out() to content
+ objectNumber = 2;
+ content = [];
+ offsets = [];
+
+ // putHeader()
+ out('%PDF-' + pdfVersion);
+
+ putPages();
+
+ putResources();
+
+ // Info
+ newObject();
+ out('<<');
+ putInfo();
+ out('>>');
+ out('endobj');
+
+ // Catalog
+ newObject();
+ out('<<');
+ putCatalog();
+ out('>>');
+ out('endobj');
+
+ // Cross-ref
+ var o = content_length, i, p = "0000000000";
+ out('xref');
+ out('0 ' + (objectNumber + 1));
+ out(p+' 65535 f ');
+ for (i = 1; i <= objectNumber; i++) {
+ var offset = offsets[i];
+ if (typeof offset === 'function'){
+ out((p + offsets[i]()).slice(-10) + ' 00000 n ');
+ }else{
+ out((p + offsets[i]).slice(-10) + ' 00000 n ');
+ }
+ }
+ // Trailer
+ out('trailer');
+ out('<<');
+ putTrailer();
+ out('>>');
+ out('startxref');
+ out(o);
+ out('%%EOF');
+
+ outToPages = true;
+
+ return content.join('\n');
+ },
+ getStyle = function(style) {
+ // see path-painting operators in PDF spec
+ var op = 'S'; // stroke
+ if (style === 'F') {
+ op = 'f'; // fill
+ } else if (style === 'FD' || style === 'DF') {
+ op = 'B'; // both
+ } else if (style === 'f' || style === 'f*' || style === 'B' || style === 'B*') {
+ /*
+ Allow direct use of these PDF path-painting operators:
+ - f fill using nonzero winding number rule
+ - f* fill using even-odd rule
+ - B fill then stroke with fill using non-zero winding number rule
+ - B* fill then stroke with fill using even-odd rule
+ */
+ op = style;
+ }
+ return op;
+ },
+ getArrayBuffer = function() {
+ var data = buildDocument(), len = data.length,
+ ab = new ArrayBuffer(len), u8 = new Uint8Array(ab);
+
+ while(len--) u8[len] = data.charCodeAt(len);
+ return ab;
+ },
+ getBlob = function() {
+ return new Blob([getArrayBuffer()], { type : "application/pdf" });
+ },
+ /**
+ * Generates the PDF document.
+ *
+ * If `type` argument is undefined, output is raw body of resulting PDF returned as a string.
+ *
+ * @param {String} type A string identifying one of the possible output types.
+ * @param {Object} options An object providing some additional signalling to PDF generator.
+ * @function
+ * @returns {jsPDF}
+ * @methodOf jsPDF#
+ * @name output
+ */
+ output = SAFE(function(type, options) {
+ var datauri = ('' + type).substr(0,6) === 'dataur'
+ ? 'data:application/pdf;base64,'+btoa(buildDocument()):0;
+
+ switch (type) {
+ case undefined:
+ return buildDocument();
+ case 'save':
+ if (navigator.getUserMedia) {
+ if (global.URL === undefined
+ || global.URL.createObjectURL === undefined) {
+ return API.output('dataurlnewwindow');
+ }
+ }
+ saveAs(getBlob(), options);
+ if(typeof saveAs.unload === 'function') {
+ if(global.setTimeout) {
+ setTimeout(saveAs.unload,911);
+ }
+ }
+ break;
+ case 'arraybuffer':
+ return getArrayBuffer();
+ case 'blob':
+ return getBlob();
+ case 'bloburi':
+ case 'bloburl':
+ // User is responsible of calling revokeObjectURL
+ return global.URL && global.URL.createObjectURL(getBlob()) || void 0;
+ case 'datauristring':
+ case 'dataurlstring':
+ return datauri;
+ case 'dataurlnewwindow':
+ var nW = global.open(datauri);
+ if (nW || typeof safari === "undefined") return nW;
+ /* pass through */
+ case 'datauri':
+ case 'dataurl':
+ return global.document.location.href = datauri;
+ default:
+ throw new Error('Output type "' + type + '" is not supported.');
+ }
+ // @TODO: Add different output options
+ });
+
+ switch (unit) {
+ case 'pt': k = 1; break;
+ case 'mm': k = 72 / 25.4000508; break;
+ case 'cm': k = 72 / 2.54000508; break;
+ case 'in': k = 72; break;
+ case 'px': k = 96 / 72; break;
+ case 'pc': k = 12; break;
+ case 'em': k = 12; break;
+ case 'ex': k = 6; break;
+ default:
+ throw ('Invalid unit: ' + unit);
+ }
+
+ //---------------------------------------
+ // Public API
+
+ /**
+ * Object exposing internal API to plugins
+ * @public
+ */
+ API.internal = {
+ 'pdfEscape' : pdfEscape,
+ 'getStyle' : getStyle,
+ /**
+ * Returns {FontObject} describing a particular font.
+ * @public
+ * @function
+ * @param fontName {String} (Optional) Font's family name
+ * @param fontStyle {String} (Optional) Font's style variation name (Example:"Italic")
+ * @returns {FontObject}
+ */
+ 'getFont' : function() {
+ return fonts[getFont.apply(API, arguments)];
+ },
+ 'getFontSize' : function() {
+ return activeFontSize;
+ },
+ 'getLineHeight' : function() {
+ return activeFontSize * lineHeightProportion;
+ },
+ 'write' : function(string1 /*, string2, string3, etc */) {
+ out(arguments.length === 1 ? string1 : Array.prototype.join.call(arguments, ' '));
+ },
+ 'getCoordinateString' : function(value) {
+ return f2(value * k);
+ },
+ 'getVerticalCoordinateString' : function(value) {
+ return f2((pageHeight - value) * k);
+ },
+ 'collections' : {},
+ 'newObject' : newObject,
+ 'newObjectDeferred' : newObjectDeferred,
+ 'newObjectDeferredBegin' : newObjectDeferredBegin,
+ 'putStream' : putStream,
+ 'events' : events,
+ // ratio that you use in multiplication of a given "size" number to arrive to 'point'
+ // units of measurement.
+ // scaleFactor is set at initialization of the document and calculated against the stated
+ // default measurement units for the document.
+ // If default is "mm", k is the number that will turn number in 'mm' into 'points' number.
+ // through multiplication.
+ 'scaleFactor' : k,
+ 'pageSize' : {
+ get width() {
+ return pageWidth
+ },
+ get height() {
+ return pageHeight
+ }
+ },
+ 'output' : function(type, options) {
+ return output(type, options);
+ },
+ 'getNumberOfPages' : function() {
+ return pages.length - 1;
+ },
+ 'pages' : pages,
+ 'out' : out,
+ 'f2' : f2,
+ 'getPageInfo' : function(pageNumberOneBased){
+ var objId = (pageNumberOneBased - 1) * 2 + 3;
+ return {objId:objId, pageNumber:pageNumberOneBased};
+ },
+ 'getCurrentPageInfo' : function(){
+ var objId = (currentPage - 1) * 2 + 3;
+ return {objId:objId, pageNumber:currentPage};
+ }
+ };
+
+ /**
+ * Adds (and transfers the focus to) new page to the PDF document.
+ * @function
+ * @returns {jsPDF}
+ *
+ * @methodOf jsPDF#
+ * @name addPage
+ */
+ API.addPage = function() {
+ _addPage.apply(this, arguments);
+ return this;
+ };
+ API.setPage = function() {
+ _setPage.apply(this, arguments);
+ return this;
+ };
+ API.insertPage = function(beforePage) {
+ this.addPage();
+ this.movePage(currentPage, beforePage);
+ return this;
+ };
+ API.movePage = function(targetPage, beforePage) {
+ if (targetPage > beforePage){
+ var tmpPages = pages[targetPage];
+ var tmpPagedim = pagedim[targetPage];
+ for (var i=targetPage; i>beforePage; i--){
+ pages[i] = pages[i-1];
+ pagedim[i] = pagedim[i-1];
+ }
+ pages[beforePage] = tmpPages;
+ pagedim[beforePage] = tmpPagedim;
+ this.setPage(beforePage);
+ }else if (targetPage < beforePage){
+ var tmpPages = pages[targetPage];
+ var tmpPagedim = pagedim[targetPage];
+ for (var i=targetPage; i< page; i++){
+ pages[i] = pages[i+1];
+ pagedim[i] = pagedim[i+1];
+ }
+ page--;
+ if (currentPage > page){
+ currentPage = page;
+ }
+ this.setPage(currentPage);
+ return this;
+ };
+ API.setDisplayMode = function(zoom, layout, pmode) {
+ zoomMode = zoom;
+ layoutMode = layout;
+ pageMode = pmode;
+ return this;
+ },
+
+ /**
+ * Adds text to page. Supports adding multiline text when 'text' argument is an Array of Strings.
+ *
+ * @function
+ * @param {String|Array} text String or array of strings to be added to the page. Each line is shifted one line down per font, spacing settings declared before this call.
+ * @param {Number} x Coordinate (in units declared at inception of PDF document) against left edge of the page
+ * @param {Number} y Coordinate (in units declared at inception of PDF document) against upper edge of the page
+ * @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.
+ * @returns {jsPDF}
+ * @methodOf jsPDF#
+ * @name text
+ */
+ API.text = function(text, x, y, flags, angle, align) {
+ /**
+ * Inserts something like this into PDF
+ * BT
+ * /F1 16 Tf % Font name + size
+ * 16 TL % How many units down for next line in multiline text
+ * 0 g % color
+ * 28.35 813.54 Td % position
+ * (line one) Tj
+ * T* (line two) Tj
+ * T* (line three) Tj
+ * ET
+ */
+ function ESC(s) {
+ s = s.split("\t").join(Array(options.TabLen||9).join(" "));
+ return pdfEscape(s, flags);
+ }
+
+ // Pre-August-2012 the order of arguments was function(x, y, text, flags)
+ // in effort to make all calls have similar signature like
+ // function(data, coordinates... , miscellaneous)
+ // this method had its args flipped.
+ // code below allows backward compatibility with old arg order.
+ if (typeof text === 'number') {
+ tmp = y;
+ y = x;
+ x = text;
+ text = tmp;
+ }
+
+ // If there are any newlines in text, we assume
+ // the user wanted to print multiple lines, so break the
+ // text up into an array. If the text is already an array,
+ // we assume the user knows what they are doing.
+ if (typeof text === 'string') {
+ if(text.match(/[\n\r]/)) {
+ text = text.split( /\r\n|\r|\n/g);
+ } else {
+ // Convert text into an array anyway
+ // to simplify later code.
+ text = [text];
+ }
+ }
+ if (typeof angle === 'string') {
+ align = angle;
+ angle = null;
+ }
+ if (typeof flags === 'string') {
+ align = flags;
+ flags = null;
+ }
+ if (typeof flags === 'number') {
+ angle = flags;
+ flags = null;
+ }
+ var xtra = '',mode = 'Td', todo;
+ if (angle) {
+ angle *= (Math.PI / 180);
+ var c = Math.cos(angle),
+ s = Math.sin(angle);
+ xtra = [f2(c), f2(s), f2(s * -1), f2(c), ''].join(" ");
+ mode = 'Tm';
+ }
+ flags = flags || {};
+ if (!('noBOM' in flags))
+ flags.noBOM = true;
+ if (!('autoencode' in flags))
+ flags.autoencode = true;
+
+ //TODO this might not work after object block changes
+ // It would be better to pass in a page context
+ var strokeOption = '';
+ if (true === flags.stroke){
+ if (this.lastTextWasStroke !== true){
+ strokeOption = '1 Tr\n';
+ this.lastTextWasStroke = true;
+ }
+ }
+ else{
+ if (this.lastTextWasStroke){
+ strokeOption = '0 Tr\n';
+ }
+ this.lastTextWasStroke = false;
+ }
+
+ if (text instanceof Array) {
+ // we don't want to destroy original text array, so cloning it
+ var sa = text.concat(), da = [], i, len = sa.length;
+ // we do array.join('text that must not be PDFescaped")
+ // thus, pdfEscape each component separately
+ while (len--) {
+ da.push(ESC(sa.shift()));
+ }
+ var linesLeft = Math.ceil((pageHeight - y) * k / (activeFontSize * lineHeightProportion));
+ if (0 <= linesLeft && linesLeft < da.length + 1) {
+ todo = da.splice(linesLeft-1);
+ }
+
+ if( align ) {
+ var prevX,
+ leading = activeFontSize * lineHeightProportion,
+ lineWidths = text.map( function( v ) {
+ return this.getStringUnitWidth( v ) * activeFontSize / k;
+ }, this );
+ // The first line uses the "main" Td setting,
+ // and the subsequent lines are offset by the
+ // previous line's x coordinate.
+ if( align === "center" ) {
+ // The passed in x coordinate defines
+ // the center point.
+ x -= lineWidths[0] / 2;
+ } else if ( align === "right" ) {
+ // The passed in x coordinate defines the
+ // rightmost point of the text.
+ x -= lineWidths[0];
+ } else {
+ throw new Error('Unrecognized alignment option, use "center" or "right".');
+ }
+ prevX = x;
+ text = da[0];
+ for ( i = 1, len = da.length ; i < len; i++ ) {
+ var delta = lineWidths[i-1] - lineWidths[i];
+ if( align === "center" ) delta /= 2;
+ // T* = x-offset leading Td ( text )
+ // PDF Spec 1.3 p.288
+ text += ") Tj\n" + delta + " -" + leading + " Td (" + da[i];
+ prevX += delta;
+ }
+ } else {
+ text = da.join(") Tj\nT* (");
+ }
+ } else {
+ throw new Error('Type of text must be string or Array. "' + text + '" is not recognized.');
+ }
+ // Using "'" ("go next line and render text" mark) would save space but would complicate our rendering code, templates
+
+ // BT .. ET does NOT have default settings for Tf. You must state that explicitely every time for BT .. ET
+ // if you want text transformation matrix (+ multiline) to work reliably (which reads sizes of things from font declarations)
+ // Thus, there is NO useful, *reliable* concept of "default" font for a page.
+ // The fact that "default" (reuse font used before) font worked before in basic cases is an accident
+ // - readers dealing smartly with brokenness of jsPDF's markup.
+ out(
+ 'BT\n/' +
+ activeFontKey + ' ' + activeFontSize + ' Tf\n' + // font face, style, size
+ (activeFontSize * lineHeightProportion) + ' TL\n' + // line spacing
+ strokeOption +// stroke option
+ textColor +
+ '\n' + xtra + f2(x * k) + ' ' + f2((pageHeight - y) * k) + ' ' + mode + '\n(' +
+ text +
+ ') Tj\nET');
+
+ if (todo) {
+ this.addPage();
+ this.text( todo, x, activeFontSize * 1.7 / k);
+ }
+
+ return this;
+ };
+
+ API.lstext = function(text, x, y, spacing) {
+ for (var i = 0, len = text.length ; i < len; i++, x += spacing) this.text(text[i], x, y);
+ };
+
+ API.line = function(x1, y1, x2, y2) {
+ return this.lines([[x2 - x1, y2 - y1]], x1, y1);
+ };
+
+ API.clip = function() {
+ // By patrick-roberts, github.com/MrRio/jsPDF/issues/328
+ // Call .clip() after calling .rect() with a style argument of null
+ out('W') // clip
+ out('S') // stroke path; necessary for clip to work
+ };
+
+ /**
+ * Adds series of curves (straight lines or cubic bezier curves) to canvas, starting at `x`, `y` coordinates.
+ * All data points in `lines` are relative to last line origin.
+ * `x`, `y` become x1,y1 for first line / curve in the set.
+ * For lines you only need to specify [x2, y2] - (ending point) vector against x1, y1 starting point.
+ * 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.
+ *
+ * @example .lines([[2,2],[-2,2],[1,1,2,2,3,3],[2,1]], 212,110, 10) // line, line, bezier curve, line
+ * @param {Array} lines Array of *vector* shifts as pairs (lines) or sextets (cubic bezier curves).
+ * @param {Number} x Coordinate (in units declared at inception of PDF document) against left edge of the page
+ * @param {Number} y Coordinate (in units declared at inception of PDF document) against upper edge of the page
+ * @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.
+ * @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.
+ * @param {Boolean} closed If true, the path is closed with a straight line from the end of the last curve to the starting point.
+ * @function
+ * @returns {jsPDF}
+ * @methodOf jsPDF#
+ * @name lines
+ */
+ API.lines = function(lines, x, y, scale, style, closed) {
+ var scalex,scaley,i,l,leg,x2,y2,x3,y3,x4,y4;
+
+ // Pre-August-2012 the order of arguments was function(x, y, lines, scale, style)
+ // in effort to make all calls have similar signature like
+ // function(content, coordinateX, coordinateY , miscellaneous)
+ // this method had its args flipped.
+ // code below allows backward compatibility with old arg order.
+ if (typeof lines === 'number') {
+ tmp = y;
+ y = x;
+ x = lines;
+ lines = tmp;
+ }
+
+ scale = scale || [1, 1];
+
+ // starting point
+ out(f3(x * k) + ' ' + f3((pageHeight - y) * k) + ' m ');
+
+ scalex = scale[0];
+ scaley = scale[1];
+ l = lines.length;
+ //, x2, y2 // bezier only. In page default measurement "units", *after* scaling
+ //, x3, y3 // bezier only. In page default measurement "units", *after* scaling
+ // ending point for all, lines and bezier. . In page default measurement "units", *after* scaling
+ x4 = x; // last / ending point = starting point for first item.
+ y4 = y; // last / ending point = starting point for first item.
+
+ for (i = 0; i < l; i++) {
+ leg = lines[i];
+ if (leg.length === 2) {
+ // simple line
+ x4 = leg[0] * scalex + x4; // here last x4 was prior ending point
+ y4 = leg[1] * scaley + y4; // here last y4 was prior ending point
+ out(f3(x4 * k) + ' ' + f3((pageHeight - y4) * k) + ' l');
+ } else {
+ // bezier curve
+ x2 = leg[0] * scalex + x4; // here last x4 is prior ending point
+ y2 = leg[1] * scaley + y4; // here last y4 is prior ending point
+ x3 = leg[2] * scalex + x4; // here last x4 is prior ending point
+ y3 = leg[3] * scaley + y4; // here last y4 is prior ending point
+ x4 = leg[4] * scalex + x4; // here last x4 was prior ending point
+ y4 = leg[5] * scaley + y4; // here last y4 was prior ending point
+ out(
+ f3(x2 * k) + ' ' +
+ f3((pageHeight - y2) * k) + ' ' +
+ f3(x3 * k) + ' ' +
+ f3((pageHeight - y3) * k) + ' ' +
+ f3(x4 * k) + ' ' +
+ f3((pageHeight - y4) * k) + ' c');
+ }
+ }
+
+ if (closed) {
+ out(' h');
+ }
+
+ // stroking / filling / both the path
+ if (style !== null) {
+ out(getStyle(style));
+ }
+ return this;
+ };
+
+ /**
+ * Adds a rectangle to PDF
+ *
+ * @param {Number} x Coordinate (in units declared at inception of PDF document) against left edge of the page
+ * @param {Number} y Coordinate (in units declared at inception of PDF document) against upper edge of the page
+ * @param {Number} w Width (in units declared at inception of PDF document)
+ * @param {Number} h Height (in units declared at inception of PDF document)
+ * @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.
+ * @function
+ * @returns {jsPDF}
+ * @methodOf jsPDF#
+ * @name rect
+ */
+ API.rect = function(x, y, w, h, style) {
+ var op = getStyle(style);
+ out([
+ f2(x * k),
+ f2((pageHeight - y) * k),
+ f2(w * k),
+ f2(-h * k),
+ 're'
+ ].join(' '));
+
+ if (style !== null) {
+ out(getStyle(style));
+ }
+
+ return this;
+ };
+
+ /**
+ * Adds a triangle to PDF
+ *
+ * @param {Number} x1 Coordinate (in units declared at inception of PDF document) against left edge of the page
+ * @param {Number} y1 Coordinate (in units declared at inception of PDF document) against upper edge of the page
+ * @param {Number} x2 Coordinate (in units declared at inception of PDF document) against left edge of the page
+ * @param {Number} y2 Coordinate (in units declared at inception of PDF document) against upper edge of the page
+ * @param {Number} x3 Coordinate (in units declared at inception of PDF document) against left edge of the page
+ * @param {Number} y3 Coordinate (in units declared at inception of PDF document) against upper edge of the page
+ * @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.
+ * @function
+ * @returns {jsPDF}
+ * @methodOf jsPDF#
+ * @name triangle
+ */
+ API.triangle = function(x1, y1, x2, y2, x3, y3, style) {
+ this.lines(
+ [
+ [x2 - x1, y2 - y1], // vector to point 2
+ [x3 - x2, y3 - y2], // vector to point 3
+ [x1 - x3, y1 - y3]// closing vector back to point 1
+ ],
+ x1,
+ y1, // start of path
+ [1, 1],
+ style,
+ true);
+ return this;
+ };
+
+ /**
+ * Adds a rectangle with rounded corners to PDF
+ *
+ * @param {Number} x Coordinate (in units declared at inception of PDF document) against left edge of the page
+ * @param {Number} y Coordinate (in units declared at inception of PDF document) against upper edge of the page
+ * @param {Number} w Width (in units declared at inception of PDF document)
+ * @param {Number} h Height (in units declared at inception of PDF document)
+ * @param {Number} rx Radius along x axis (in units declared at inception of PDF document)
+ * @param {Number} rx Radius along y axis (in units declared at inception of PDF document)
+ * @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.
+ * @function
+ * @returns {jsPDF}
+ * @methodOf jsPDF#
+ * @name roundedRect
+ */
+ API.roundedRect = function(x, y, w, h, rx, ry, style) {
+ var MyArc = 4 / 3 * (Math.SQRT2 - 1);
+ 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
+ [1, 1],
+ style);
+ return this;
+ };
+
+ /**
+ * Adds an ellipse to PDF
+ *
+ * @param {Number} x Coordinate (in units declared at inception of PDF document) against left edge of the page
+ * @param {Number} y Coordinate (in units declared at inception of PDF document) against upper edge of the page
+ * @param {Number} rx Radius along x axis (in units declared at inception of PDF document)
+ * @param {Number} rx Radius along y axis (in units declared at inception of PDF document)
+ * @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.
+ * @function
+ * @returns {jsPDF}
+ * @methodOf jsPDF#
+ * @name ellipse
+ */
+ API.ellipse = function(x, y, rx, ry, style) {
+ var lx = 4 / 3 * (Math.SQRT2 - 1) * rx,
+ ly = 4 / 3 * (Math.SQRT2 - 1) * ry;
+
+ 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(' '));
+ 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(' '));
+ 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(' '));
+ 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(' '));
+
+ if (style !== null) {
+ out(getStyle(style));
+ }
+
+ return this;
+ };
+
+ /**
+ * Adds an circle to PDF
+ *
+ * @param {Number} x Coordinate (in units declared at inception of PDF document) against left edge of the page
+ * @param {Number} y Coordinate (in units declared at inception of PDF document) against upper edge of the page
+ * @param {Number} r Radius (in units declared at inception of PDF document)
+ * @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.
+ * @function
+ * @returns {jsPDF}
+ * @methodOf jsPDF#
+ * @name circle
+ */
+ API.circle = function(x, y, r, style) {
+ return this.ellipse(x, y, r, r, style);
+ };
+
+ /**
+ * Adds a properties to the PDF document
+ *
+ * @param {Object} A property_name-to-property_value object structure.
+ * @function
+ * @returns {jsPDF}
+ * @methodOf jsPDF#
+ * @name setProperties
+ */
+ API.setProperties = function(properties) {
+ // copying only those properties we can render.
+ for (var property in documentProperties) {
+ if (documentProperties.hasOwnProperty(property) && properties[property]) {
+ documentProperties[property] = properties[property];
+ }
+ }
+ return this;
+ };
+
+ /**
+ * Sets font size for upcoming text elements.
+ *
+ * @param {Number} size Font size in points.
+ * @function
+ * @returns {jsPDF}
+ * @methodOf jsPDF#
+ * @name setFontSize
+ */
+ API.setFontSize = function(size) {
+ activeFontSize = size;
+ return this;
+ };
+
+ /**
+ * Sets text font face, variant for upcoming text elements.
+ * See output of jsPDF.getFontList() for possible font names, styles.
+ *
+ * @param {String} fontName Font name or family. Example: "times"
+ * @param {String} fontStyle Font style or variant. Example: "italic"
+ * @function
+ * @returns {jsPDF}
+ * @methodOf jsPDF#
+ * @name setFont
+ */
+ API.setFont = function(fontName, fontStyle) {
+ activeFontKey = getFont(fontName, fontStyle);
+ // if font is not found, the above line blows up and we never go further
+ return this;
+ };
+
+ /**
+ * Switches font style or variant for upcoming text elements,
+ * while keeping the font face or family same.
+ * See output of jsPDF.getFontList() for possible font names, styles.
+ *
+ * @param {String} style Font style or variant. Example: "italic"
+ * @function
+ * @returns {jsPDF}
+ * @methodOf jsPDF#
+ * @name setFontStyle
+ */
+ API.setFontStyle = API.setFontType = function(style) {
+ activeFontKey = getFont(undefined, style);
+ // if font is not found, the above line blows up and we never go further
+ return this;
+ };
+
+ /**
+ * Returns an object - a tree of fontName to fontStyle relationships available to
+ * active PDF document.
+ *
+ * @public
+ * @function
+ * @returns {Object} Like {'times':['normal', 'italic', ... ], 'arial':['normal', 'bold', ... ], ... }
+ * @methodOf jsPDF#
+ * @name getFontList
+ */
+ API.getFontList = function() {
+ // TODO: iterate over fonts array or return copy of fontmap instead in case more are ever added.
+ var list = {},fontName,fontStyle,tmp;
+
+ for (fontName in fontmap) {
+ if (fontmap.hasOwnProperty(fontName)) {
+ list[fontName] = tmp = [];
+ for (fontStyle in fontmap[fontName]) {
+ if (fontmap[fontName].hasOwnProperty(fontStyle)) {
+ tmp.push(fontStyle);
+ }
+ }
+ }
+ }
+
+ return list;
+ };
+
+ /**
+ * Add a custom font.
+ *
+ * @param {String} Postscript name of the Font. Example: "Menlo-Regular"
+ * @param {String} Name of font-family from @font-face definition. Example: "Menlo Regular"
+ * @param {String} Font style. Example: "normal"
+ * @function
+ * @returns the {fontKey} (same as the internal method)
+ * @methodOf jsPDF#
+ * @name addFont
+ */
+ API.addFont = function(postScriptName, fontName, fontStyle) {
+ addFont(postScriptName, fontName, fontStyle, 'StandardEncoding');
+ };
+
+ /**
+ * Sets line width for upcoming lines.
+ *
+ * @param {Number} width Line width (in units declared at inception of PDF document)
+ * @function
+ * @returns {jsPDF}
+ * @methodOf jsPDF#
+ * @name setLineWidth
+ */
+ API.setLineWidth = function(width) {
+ out((width * k).toFixed(2) + ' w');
+ return this;
+ };
+
+ /**
+ * Sets the stroke color for upcoming elements.
+ *
+ * Depending on the number of arguments given, Gray, RGB, or CMYK
+ * color space is implied.
+ *
+ * When only ch1 is given, "Gray" color space is implied and it
+ * must be a value in the range from 0.00 (solid black) to to 1.00 (white)
+ * if values are communicated as String types, or in range from 0 (black)
+ * to 255 (white) if communicated as Number type.
+ * The RGB-like 0-255 range is provided for backward compatibility.
+ *
+ * When only ch1,ch2,ch3 are given, "RGB" color space is implied and each
+ * value must be in the range from 0.00 (minimum intensity) to to 1.00
+ * (max intensity) if values are communicated as String types, or
+ * from 0 (min intensity) to to 255 (max intensity) if values are communicated
+ * as Number types.
+ * The RGB-like 0-255 range is provided for backward compatibility.
+ *
+ * When ch1,ch2,ch3,ch4 are given, "CMYK" color space is implied and each
+ * value must be a in the range from 0.00 (0% concentration) to to
+ * 1.00 (100% concentration)
+ *
+ * Because JavaScript treats fixed point numbers badly (rounds to
+ * floating point nearest to binary representation) it is highly advised to
+ * communicate the fractional numbers as String types, not JavaScript Number type.
+ *
+ * @param {Number|String} ch1 Color channel value
+ * @param {Number|String} ch2 Color channel value
+ * @param {Number|String} ch3 Color channel value
+ * @param {Number|String} ch4 Color channel value
+ *
+ * @function
+ * @returns {jsPDF}
+ * @methodOf jsPDF#
+ * @name setDrawColor
+ */
+ API.setDrawColor = function(ch1, ch2, ch3, ch4) {
+ var color;
+ if (ch2 === undefined || (ch4 === undefined && ch1 === ch2 === ch3)) {
+ // Gray color space.
+ if (typeof ch1 === 'string') {
+ color = ch1 + ' G';
+ } else {
+ color = f2(ch1 / 255) + ' G';
+ }
+ } else if (ch4 === undefined) {
+ // RGB
+ if (typeof ch1 === 'string') {
+ color = [ch1, ch2, ch3, 'RG'].join(' ');
+ } else {
+ color = [f2(ch1 / 255), f2(ch2 / 255), f2(ch3 / 255), 'RG'].join(' ');
+ }
+ } else {
+ // CMYK
+ if (typeof ch1 === 'string') {
+ color = [ch1, ch2, ch3, ch4, 'K'].join(' ');
+ } else {
+ color = [f2(ch1), f2(ch2), f2(ch3), f2(ch4), 'K'].join(' ');
+ }
+ }
+
+ out(color);
+ return this;
+ };
+
+ /**
+ * Sets the fill color for upcoming elements.
+ *
+ * Depending on the number of arguments given, Gray, RGB, or CMYK
+ * color space is implied.
+ *
+ * When only ch1 is given, "Gray" color space is implied and it
+ * must be a value in the range from 0.00 (solid black) to to 1.00 (white)
+ * if values are communicated as String types, or in range from 0 (black)
+ * to 255 (white) if communicated as Number type.
+ * The RGB-like 0-255 range is provided for backward compatibility.
+ *
+ * When only ch1,ch2,ch3 are given, "RGB" color space is implied and each
+ * value must be in the range from 0.00 (minimum intensity) to to 1.00
+ * (max intensity) if values are communicated as String types, or
+ * from 0 (min intensity) to to 255 (max intensity) if values are communicated
+ * as Number types.
+ * The RGB-like 0-255 range is provided for backward compatibility.
+ *
+ * When ch1,ch2,ch3,ch4 are given, "CMYK" color space is implied and each
+ * value must be a in the range from 0.00 (0% concentration) to to
+ * 1.00 (100% concentration)
+ *
+ * Because JavaScript treats fixed point numbers badly (rounds to
+ * floating point nearest to binary representation) it is highly advised to
+ * communicate the fractional numbers as String types, not JavaScript Number type.
+ *
+ * @param {Number|String} ch1 Color channel value
+ * @param {Number|String} ch2 Color channel value
+ * @param {Number|String} ch3 Color channel value
+ * @param {Number|String} ch4 Color channel value
+ *
+ * @function
+ * @returns {jsPDF}
+ * @methodOf jsPDF#
+ * @name setFillColor
+ */
+ API.setFillColor = function(ch1, ch2, ch3, ch4) {
+ var color;
+
+ if (ch2 === undefined || (ch4 === undefined && ch1 === ch2 === ch3)) {
+ // Gray color space.
+ if (typeof ch1 === 'string') {
+ color = ch1 + ' g';
+ } else {
+ color = f2(ch1 / 255) + ' g';
+ }
+ } else if (ch4 === undefined) {
+ // RGB
+ if (typeof ch1 === 'string') {
+ color = [ch1, ch2, ch3, 'rg'].join(' ');
+ } else {
+ color = [f2(ch1 / 255), f2(ch2 / 255), f2(ch3 / 255), 'rg'].join(' ');
+ }
+ } else {
+ // CMYK
+ if (typeof ch1 === 'string') {
+ color = [ch1, ch2, ch3, ch4, 'k'].join(' ');
+ } else {
+ color = [f2(ch1), f2(ch2), f2(ch3), f2(ch4), 'k'].join(' ');
+ }
+ }
+
+ out(color);
+ return this;
+ };
+
+ /**
+ * Sets the text color for upcoming elements.
+ * If only one, first argument is given,
+ * treats the value as gray-scale color value.
+ *
+ * @param {Number} r Red channel color value in range 0-255 or {String} r color value in hexadecimal, example: '#FFFFFF'
+ * @param {Number} g Green channel color value in range 0-255
+ * @param {Number} b Blue channel color value in range 0-255
+ * @function
+ * @returns {jsPDF}
+ * @methodOf jsPDF#
+ * @name setTextColor
+ */
+ API.setTextColor = function(r, g, b) {
+ if ((typeof r === 'string') && /^#[0-9A-Fa-f]{6}$/.test(r)) {
+ var hex = parseInt(r.substr(1), 16);
+ r = (hex >> 16) & 255;
+ g = (hex >> 8) & 255;
+ b = (hex & 255);
+ }
+
+ if ((r === 0 && g === 0 && b === 0) || (typeof g === 'undefined')) {
+ textColor = f3(r / 255) + ' g';
+ } else {
+ textColor = [f3(r / 255), f3(g / 255), f3(b / 255), 'rg'].join(' ');
+ }
+ return this;
+ };
+
+ /**
+ * Is an Object providing a mapping from human-readable to
+ * integer flag values designating the varieties of line cap
+ * and join styles.
+ *
+ * @returns {Object}
+ * @fieldOf jsPDF#
+ * @name CapJoinStyles
+ */
+ API.CapJoinStyles = {
+ 0 : 0,
+ 'butt' : 0,
+ 'but' : 0,
+ 'miter' : 0,
+ 1 : 1,
+ 'round' : 1,
+ 'rounded' : 1,
+ 'circle' : 1,
+ 2 : 2,
+ 'projecting' : 2,
+ 'project' : 2,
+ 'square' : 2,
+ 'bevel' : 2
+ };
+
+ /**
+ * Sets the line cap styles
+ * See {jsPDF.CapJoinStyles} for variants
+ *
+ * @param {String|Number} style A string or number identifying the type of line cap
+ * @function
+ * @returns {jsPDF}
+ * @methodOf jsPDF#
+ * @name setLineCap
+ */
+ API.setLineCap = function(style) {
+ var id = this.CapJoinStyles[style];
+ if (id === undefined) {
+ throw new Error("Line cap style of '" + style + "' is not recognized. See or extend .CapJoinStyles property for valid styles");
+ }
+ lineCapID = id;
+ out(id + ' J');
+
+ return this;
+ };
+
+ /**
+ * Sets the line join styles
+ * See {jsPDF.CapJoinStyles} for variants
+ *
+ * @param {String|Number} style A string or number identifying the type of line join
+ * @function
+ * @returns {jsPDF}
+ * @methodOf jsPDF#
+ * @name setLineJoin
+ */
+ API.setLineJoin = function(style) {
+ var id = this.CapJoinStyles[style];
+ if (id === undefined) {
+ throw new Error("Line join style of '" + style + "' is not recognized. See or extend .CapJoinStyles property for valid styles");
+ }
+ lineJoinID = id;
+ out(id + ' j');
+
+ return this;
+ };
+
+ // Output is both an internal (for plugins) and external function
+ API.output = output;
+
+ /**
+ * Saves as PDF document. An alias of jsPDF.output('save', 'filename.pdf')
+ * @param {String} filename The filename including extension.
+ *
+ * @function
+ * @returns {jsPDF}
+ * @methodOf jsPDF#
+ * @name save
+ */
+ API.save = function(filename) {
+ API.output('save', filename);
+ };
+
+ // applying plugins (more methods) ON TOP of built-in API.
+ // this is intentional as we allow plugins to override
+ // built-ins
+ for (var plugin in jsPDF.API) {
+ if (jsPDF.API.hasOwnProperty(plugin)) {
+ if (plugin === 'events' && jsPDF.API.events.length) {
+ (function(events, newEvents) {
+
+ // jsPDF.API.events is a JS Array of Arrays
+ // where each Array is a pair of event name, handler
+ // Events were added by plugins to the jsPDF instantiator.
+ // These are always added to the new instance and some ran
+ // during instantiation.
+ var eventname,handler_and_args,i;
+
+ for (i = newEvents.length - 1; i !== -1; i--) {
+ // subscribe takes 3 args: 'topic', function, runonce_flag
+ // if undefined, runonce is false.
+ // users can attach callback directly,
+ // or they can attach an array with [callback, runonce_flag]
+ // that's what the "apply" magic is for below.
+ eventname = newEvents[i][0];
+ handler_and_args = newEvents[i][1];
+ events.subscribe.apply(
+ events,
+ [eventname].concat(
+ typeof handler_and_args === 'function' ?
+ [handler_and_args] : handler_and_args));
+ }
+ }(events, jsPDF.API.events));
+ } else {
+ API[plugin] = jsPDF.API[plugin];
+ }
+ }
+ }
+
+ //////////////////////////////////////////////////////
+ // continuing initialization of jsPDF Document object
+ //////////////////////////////////////////////////////
+ // Add the first page automatically
+ addFonts();
+ activeFontKey = 'F1';
+ _addPage(format, orientation);
+
+ events.publish('initialized');
+ return API;
+ }
+
+ /**
+ * jsPDF.API is a STATIC property of jsPDF class.
+ * jsPDF.API is an object you can add methods and properties to.
+ * The methods / properties you add will show up in new jsPDF objects.
+ *
+ * One property is prepopulated. It is the 'events' Object. Plugin authors can add topics,
+ * callbacks to this object. These will be reassigned to all new instances of jsPDF.
+ * Examples:
+ * jsPDF.API.events['initialized'] = function(){ 'this' is API object }
+ * jsPDF.API.events['addFont'] = function(added_font_object){ 'this' is API object }
+ *
+ * @static
+ * @public
+ * @memberOf jsPDF
+ * @name API
+ *
+ * @example
+ * jsPDF.API.mymethod = function(){
+ * // 'this' will be ref to internal API object. see jsPDF source
+ * // , so you can refer to built-in methods like so:
+ * // this.line(....)
+ * // this.text(....)
+ * }
+ * var pdfdoc = new jsPDF()
+ * pdfdoc.mymethod() // <- !!!!!!
+ */
+ jsPDF.API = {events:[]};
+ jsPDF.version = "1.0.0-trunk";
-var jsPDF = function(){
-
- // Private properties
- var version = '20090504';
- var buffer = '';
-
- var pdfVersion = '1.3'; // PDF Version
- var defaultPageFormat = 'a4';
- var pageFormats = { // Size in mm of various paper formats
- 'a3': [841.89, 1190.55],
- 'a4': [595.28, 841.89],
- 'a5': [420.94, 595.28],
- 'letter': [612, 792],
- 'legal': [612, 1008]
- };
- var textColor = '0 g';
- var page = 0;
- var objectNumber = 2; // 'n' Current object number
- var state = 0; // Current document state
- var pages = new Array();
- var offsets = new Array(); // List of offsets
- var lineWidth = 0.200025; // 2mm
- var pageHeight;
- var k; // Scale factor
- var unit = 'mm'; // Default to mm for units
- var fontNumber; // TODO: This is temp, replace with real font handling
- var documentProperties = {};
- var fontSize = 16; // Default font size
- var pageFontSize = 16;
-
- // Initilisation
- if (unit == 'pt') {
- k = 1;
- } else if(unit == 'mm') {
- k = 72/25.4;
- } else if(unit == 'cm') {
- k = 72/2.54;
- } else if(unit == 'in') {
- k = 72;
- }
-
- // Private functions
- var newObject = function() {
- //Begin a new object
- objectNumber ++;
- offsets[objectNumber] = buffer.length;
- out(objectNumber + ' 0 obj');
- }
-
-
- var putHeader = function() {
- out('%PDF-' + pdfVersion);
- }
-
- var putPages = function() {
-
- // TODO: Fix, hardcoded to a4 portrait
- var wPt = pageWidth * k;
- var hPt = pageHeight * k;
-
- for(n=1; n <= page; n++) {
- newObject();
- out('<>');
- out('endobj');
-
- //Page content
- p = pages[n];
- newObject();
- out('<>');
- putStream(p);
- out('endobj');
- }
- offsets[1] = buffer.length;
- out('1 0 obj');
- out('<< page; i++) {
- kids += (3 + 2 * i) + ' 0 R ';
- }
- out(kids + ']');
- out('/Count ' + page);
- out(sprintf('/MediaBox [0 0 %.2f %.2f]', wPt, hPt));
- out('>>');
- out('endobj');
- }
-
- var putStream = function(str) {
- out('stream');
- out(str);
- out('endstream');
- }
-
- var putResources = function() {
- putFonts();
- putImages();
-
- //Resource dictionary
- offsets[2] = buffer.length;
- out('2 0 obj');
- out('<<');
- putResourceDictionary();
- out('>>');
- out('endobj');
- }
-
- var putFonts = function() {
- // TODO: Only supports core font hardcoded to Helvetica
- newObject();
- fontNumber = objectNumber;
- name = 'Helvetica';
- out('<>');
- out('endobj');
- }
-
- var putImages = function() {
- // TODO
- }
-
- var putResourceDictionary = function() {
- out('/ProcSet [/PDF /Text /ImageB /ImageC /ImageI]');
- out('/Font <<');
- // Do this for each font, the '1' bit is the index of the font
- // fontNumber is currently the object number related to 'putFonts'
- out('/F1 ' + fontNumber + ' 0 R');
- out('>>');
- out('/XObject <<');
- putXobjectDict();
- out('>>');
- }
-
- var putXobjectDict = function() {
- // TODO
- // Loop through images
- }
-
-
- var putInfo = function() {
- out('/Producer (jsPDF ' + version + ')');
- if(documentProperties.title != undefined) {
- out('/Title (' + pdfEscape(documentProperties.title) + ')');
- }
- if(documentProperties.subject != undefined) {
- out('/Subject (' + pdfEscape(documentProperties.subject) + ')');
- }
- if(documentProperties.author != undefined) {
- out('/Author (' + pdfEscape(documentProperties.author) + ')');
- }
- if(documentProperties.keywords != undefined) {
- out('/Keywords (' + pdfEscape(documentProperties.keywords) + ')');
- }
- if(documentProperties.creator != undefined) {
- out('/Creator (' + pdfEscape(documentProperties.creator) + ')');
- }
- var created = new Date();
- var year = created.getFullYear();
- var month = (created.getMonth() + 1);
- var day = created.getDate();
- var hour = created.getHours();
- var minute = created.getMinutes();
- var second = created.getSeconds();
- out('/CreationDate (D:' + sprintf('%02d%02d%02d%02d%02d%02d', year, month, day, hour, minute, second) + ')');
- }
-
- var putCatalog = function () {
- out('/Type /Catalog');
- out('/Pages 1 0 R');
- // TODO: Add zoom and layout modes
- out('/OpenAction [3 0 R /FitH null]');
- out('/PageLayout /OneColumn');
- }
-
- function putTrailer() {
- out('/Size ' + (objectNumber + 1));
- out('/Root ' + objectNumber + ' 0 R');
- out('/Info ' + (objectNumber - 1) + ' 0 R');
- }
-
- var endDocument = function() {
- state = 1;
- putHeader();
- putPages();
-
- putResources();
- //Info
- newObject();
- out('<<');
- putInfo();
- out('>>');
- out('endobj');
-
- //Catalog
- newObject();
- out('<<');
- putCatalog();
- out('>>');
- out('endobj');
-
- //Cross-ref
- var o = buffer.length;
- out('xref');
- out('0 ' + (objectNumber + 1));
- out('0000000000 65535 f ');
- for (var i=1; i <= objectNumber; i++) {
- out(sprintf('%010d 00000 n ', offsets[i]));
- }
- //Trailer
- out('trailer');
- out('<<');
- putTrailer();
- out('>>');
- out('startxref');
- out(o);
- out('%%EOF');
- state = 3;
- }
-
- var beginPage = function() {
- page ++;
- // Do dimension stuff
- state = 2;
- pages[page] = '';
-
- // TODO: Hardcoded at A4 and portrait
- pageHeight = pageFormats['a4'][1] / k;
- pageWidth = pageFormats['a4'][0] / k;
- }
-
- var out = function(string) {
- if(state == 2) {
- pages[page] += string + '\n';
- } else {
- buffer += string + '\n';
- }
- }
-
- var _addPage = function() {
- beginPage();
- // Set line width
- out(sprintf('%.2f w', (lineWidth * k)));
-
- // Set font - TODO
- // 16 is the font size
- pageFontSize = fontSize;
- out('BT /F1 ' + parseInt(fontSize) + '.00 Tf ET');
- }
-
- // Add the first page automatically
- _addPage();
-
- // Escape text
- var pdfEscape = function(text) {
- return text.replace(/\\/g, '\\\\').replace(/\(/g, '\\(').replace(/\)/g, '\\)');
- }
-
- return {
- addPage: function() {
- _addPage();
- },
- text: function(x, y, text) {
- // need page height
- if(pageFontSize != fontSize) {
- out('BT /F1 ' + parseInt(fontSize) + '.00 Tf ET');
- pageFontSize = fontSize;
- }
- var str = sprintf('BT %.2f %.2f Td (%s) Tj ET', x * k, (pageHeight - y) * k, pdfEscape(text));
- out(str);
- },
- setProperties: function(properties) {
- documentProperties = properties;
- },
- addImage: function(imageData, format, x, y, w, h) {
-
- },
- output: function(type, options) {
- endDocument();
- if(type == undefined) {
- return buffer;
- }
- if(type == 'datauri') {
- document.location.href = 'data:application/pdf;base64,' + Base64.encode(buffer);
- }
- // @TODO: Add different output options
- },
- setFontSize: function(size) {
- fontSize = size;
- }
- }
-
-};
+ if (typeof define === 'function' && define.amd) {
+ define('jsPDF', function() {
+ return jsPDF;
+ });
+ } else {
+ global.jsPDF = jsPDF;
+ }
+ return jsPDF;
+}(typeof self !== "undefined" && self || typeof window !== "undefined" && window || this));
\ No newline at end of file
diff --git a/tableExport.js b/tableExport.js
index 1bfaa0fc..f9d9d241 100644
--- a/tableExport.js
+++ b/tableExport.js
@@ -28,7 +28,7 @@ THE SOFTWARE.*/
ignoreColumn: [],
tableName:'yourTableName',
type:'csv',
- pdfFontSize:14,
+ pdfFontSize:6,
pdfLeftMargin:20,
escape:'true',
htmlContent:'false',
@@ -215,9 +215,9 @@ THE SOFTWARE.*/
//console.log($(this).html());
var excel="";
// Header
- $(el).find('thead').find('tr').each(function() {
+ $(el).find('.rt-headers').each(function() {
excel += "";
- $(this).filter(':visible').find('th').each(function(index,data) {
+ $(this).filter(':visible').find('.rt-header-anchor-text').each(function(index,data) {
if ($(this).css('display') != 'none'){
if(defaults.ignoreColumn.indexOf(index) == -1){
excel += "| " + parseString($(this))+ " | ";
@@ -232,8 +232,13 @@ THE SOFTWARE.*/
// Row Vs Column
var rowCount=1;
$(el).find('tbody').find('tr').each(function() {
+ if( $(this).find('td').first().text().match("Grand Total") ) {
+ rowCount++;
+ return;
+ }
excel += "
";
var colCount=0;
+
$(this).filter(':visible').find('td').each(function(index,data) {
if ($(this).css('display') != 'none'){
if(defaults.ignoreColumn.indexOf(index) == -1){
@@ -289,39 +294,73 @@ THE SOFTWARE.*/
});
}else if(defaults.type == 'pdf'){
- var doc = new jsPDF('p','pt', 'a4', true);
+ var doc = new jsPDF('l','pt', 'letter', true);
doc.setFontSize(defaults.pdfFontSize);
-
+ var widths = [];
// Header
var startColPosition=defaults.pdfLeftMargin;
- $(el).find('thead').find('tr').each(function() {
- $(this).filter(':visible').find('th').each(function(index,data) {
+ $(el).find('.rt-headers').each(function() {
+ $(this).filter(':visible').find('.rt-header-anchor-text').each(function(index,data) {
if ($(this).css('display') != 'none'){
if(defaults.ignoreColumn.indexOf(index) == -1){
- var colPosition = startColPosition+ (index * 50);
- doc.text(colPosition,20, parseString($(this)));
+ widths[index] = parseString($(this)).length * 3.5;
}
}
});
- });
-
-
- // Row Vs Column
+ });
+
+ $(el).find('tbody').find('tr').each(function(index,data) {
+ if( $(this).find('td').first().text().match("Grand Total") ) {
+ return;
+ }
+ $(this).filter(':visible').find('td').each(function(index,data) {
+ if ($(this).css('display') != 'none'){
+ if(defaults.ignoreColumn.indexOf(index) == -1){
+ var currentLength = parseString($(this)).length * 3.5;
+ if( !widths[index] || widths[index] < currentLength )
+ widths[index] = currentLength;
+ }
+ }
+
+ });
+
+ });
+
+ console.log(widths);
+
+ $(el).find('.rt-headers').each(function() {
+ $(this).filter(':visible').find('.rt-header-anchor-text').each(function(index,data) {
+ if ($(this).css('display') != 'none'){
+ if(defaults.ignoreColumn.indexOf(index) == -1){
+ var colPosition = startColPosition + widths.reduce(function(prev,current,idx){
+ return idx <= index ? prev + current : prev;
+ });
+ doc.text(colPosition,20, parseString($(this)));
+ }
+ }
+ });
+ });
+ // Row Vs Column
var startRowPosition = 20; var page =1;var rowPosition=0;
$(el).find('tbody').find('tr').each(function(index,data) {
+ if( $(this).find('td').first().text().match("Grand Total") ) {
+ return;
+ }
rowCalc = index+1;
- if (rowCalc % 26 == 0){
- doc.addPage();
- page++;
- startRowPosition=startRowPosition+10;
- }
- rowPosition=(startRowPosition + (rowCalc * 10)) - ((page -1) * 280);
+ if (rowCalc % 50 == 0){
+ doc.addPage();
+ page++;
+ startRowPosition=startRowPosition+10;
+ }
+ rowPosition=(startRowPosition + (rowCalc * 10)) - ((page -1) * 280);
$(this).filter(':visible').find('td').each(function(index,data) {
if ($(this).css('display') != 'none'){
if(defaults.ignoreColumn.indexOf(index) == -1){
- var colPosition = startColPosition+ (index * 50);
+ var colPosition = startColPosition + widths.reduce(function(prev,current,idx){
+ return idx <= index ? prev + current : prev;
+ });
doc.text(colPosition,rowPosition, parseString($(this)));
}
}
@@ -343,10 +382,13 @@ THE SOFTWARE.*/
}else{
content_data = data.text().trim();
}
+
+ content_data = content_data.replace(/[^\x00-\x7F]/g, "");
+ content_data = content_data.substr(0,20);
- if(defaults.escape == 'true'){
- content_data = escape(content_data);
- }
+ //if(defaults.escape == 'true'){
+ // content_data = escape(content_data);
+ //}
From 580c151ce5c7a3891e22248524b8e1d2cd17239f Mon Sep 17 00:00:00 2001
From: unknown
Date: Thu, 14 May 2015 10:05:56 -0400
Subject: [PATCH 2/4] Removing extra files, updating jspdf
---
jspdf/jspdf.js | 1947 +--------------------------------------
tableExport.jquery.json | 1 -
tableExport.js | 401 --------
3 files changed, 4 insertions(+), 2345 deletions(-)
delete mode 100644 tableExport.jquery.json
delete mode 100644 tableExport.js
diff --git a/jspdf/jspdf.js b/jspdf/jspdf.js
index ca1c688a..ab551d70 100644
--- a/jspdf/jspdf.js
+++ b/jspdf/jspdf.js
@@ -1,1943 +1,4 @@
-/** @preserve
- * jsPDF - PDF Document creation from JavaScript
- * Version ${versionID}
- * CommitID ${commitID}
- *
- * Copyright (c) 2010-2014 James Hall, https://github.com/MrRio/jsPDF
- * 2010 Aaron Spike, https://github.com/acspike
- * 2012 Willow Systems Corporation, willow-systems.com
- * 2012 Pablo Hess, https://github.com/pablohess
- * 2012 Florian Jenett, https://github.com/fjenett
- * 2013 Warren Weckesser, https://github.com/warrenweckesser
- * 2013 Youssef Beddad, https://github.com/lifof
- * 2013 Lee Driscoll, https://github.com/lsdriscoll
- * 2013 Stefan Slonevskiy, https://github.com/stefslon
- * 2013 Jeremy Morel, https://github.com/jmorel
- * 2013 Christoph Hartmann, https://github.com/chris-rock
- * 2014 Juan Pablo Gaviria, https://github.com/juanpgaviria
- * 2014 James Makes, https://github.com/dollaruw
- * 2014 Diego Casorran, https://github.com/diegocr
- * 2014 Steven Spungin, https://github.com/Flamenco
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice shall be
- * included in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
- * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
- * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
- * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- *
- * Contributor(s):
- * siefkenj, ahwolf, rickygu, Midnith, saintclair, eaparango,
- * kim3er, mfo, alnorth, Flamenco
- */
-
-/**
- * Creates new jsPDF document object instance.
- *
- * @class
- * @param orientation One of "portrait" or "landscape" (or shortcuts "p" (Default), "l")
- * @param unit Measurement unit to be used when coordinates are specified.
- * One of "pt" (points), "mm" (Default), "cm", "in"
- * @param format One of 'pageFormats' as shown below, default: a4
- * @returns {jsPDF}
- * @name jsPDF
- */
-var jsPDF = (function(global) {
- 'use strict';
- var pdfVersion = '1.3',
- pageFormats = { // Size in pt of various paper formats
- 'a0' : [2383.94, 3370.39], 'a1' : [1683.78, 2383.94],
- 'a2' : [1190.55, 1683.78], 'a3' : [ 841.89, 1190.55],
- 'a4' : [ 595.28, 841.89], 'a5' : [ 419.53, 595.28],
- 'a6' : [ 297.64, 419.53], 'a7' : [ 209.76, 297.64],
- 'a8' : [ 147.40, 209.76], 'a9' : [ 104.88, 147.40],
- 'a10' : [ 73.70, 104.88], 'b0' : [2834.65, 4008.19],
- 'b1' : [2004.09, 2834.65], 'b2' : [1417.32, 2004.09],
- 'b3' : [1000.63, 1417.32], 'b4' : [ 708.66, 1000.63],
- 'b5' : [ 498.90, 708.66], 'b6' : [ 354.33, 498.90],
- 'b7' : [ 249.45, 354.33], 'b8' : [ 175.75, 249.45],
- 'b9' : [ 124.72, 175.75], 'b10' : [ 87.87, 124.72],
- 'c0' : [2599.37, 3676.54], 'c1' : [1836.85, 2599.37],
- 'c2' : [1298.27, 1836.85], 'c3' : [ 918.43, 1298.27],
- 'c4' : [ 649.13, 918.43], 'c5' : [ 459.21, 649.13],
- 'c6' : [ 323.15, 459.21], 'c7' : [ 229.61, 323.15],
- 'c8' : [ 161.57, 229.61], 'c9' : [ 113.39, 161.57],
- 'c10' : [ 79.37, 113.39], 'dl' : [ 311.81, 623.62],
- 'letter' : [612, 792],
- 'government-letter' : [576, 756],
- 'legal' : [612, 1008],
- 'junior-legal' : [576, 360],
- 'ledger' : [1224, 792],
- 'tabloid' : [792, 1224],
- 'credit-card' : [153, 243]
- };
-
- /**
- * jsPDF's Internal PubSub Implementation.
- * See mrrio.github.io/jsPDF/doc/symbols/PubSub.html
- * Backward compatible rewritten on 2014 by
- * Diego Casorran, https://github.com/diegocr
- *
- * @class
- * @name PubSub
- */
- function PubSub(context) {
- var topics = {};
-
- this.subscribe = function(topic, callback, once) {
- if(typeof callback !== 'function') {
- return false;
- }
-
- if(!topics.hasOwnProperty(topic)) {
- topics[topic] = {};
- }
-
- var id = Math.random().toString(35);
- topics[topic][id] = [callback,!!once];
-
- return id;
- };
-
- this.unsubscribe = function(token) {
- for(var topic in topics) {
- if(topics[topic][token]) {
- delete topics[topic][token];
- return true;
- }
- }
- return false;
- };
-
- this.publish = function(topic) {
- if(topics.hasOwnProperty(topic)) {
- var args = Array.prototype.slice.call(arguments, 1), idr = [];
-
- for(var id in topics[topic]) {
- var sub = topics[topic][id];
- try {
- sub[0].apply(context, args);
- } catch(ex) {
- if(global.console) {
- console.error('jsPDF PubSub Error', ex.message, ex);
- }
- }
- if(sub[1]) idr.push(id);
- }
- if(idr.length) idr.forEach(this.unsubscribe);
- }
- };
- }
-
- /**
- * @constructor
- * @private
- */
- function jsPDF(orientation, unit, format, compressPdf) {
- var options = {};
-
- if (typeof orientation === 'object') {
- options = orientation;
-
- orientation = options.orientation;
- unit = options.unit || unit;
- format = options.format || format;
- compressPdf = options.compress || options.compressPdf || compressPdf;
- }
-
- // Default options
- unit = unit || 'mm';
- format = format || 'a4';
- orientation = ('' + (orientation || 'P')).toLowerCase();
-
- var format_as_string = ('' + format).toLowerCase(),
- compress = !!compressPdf && typeof Uint8Array === 'function',
- textColor = options.textColor || '0 g',
- drawColor = options.drawColor || '0 G',
- activeFontSize = options.fontSize || 16,
- lineHeightProportion = options.lineHeight || 1.15,
- lineWidth = options.lineWidth || 0.200025, // 2mm
- objectNumber = 2, // 'n' Current object number
- outToPages = !1, // switches where out() prints. outToPages true = push to pages obj. outToPages false = doc builder content
- offsets = [], // List of offsets. Activated and reset by buildDocument(). Pupulated by various calls buildDocument makes.
- fonts = {}, // collection of font objects, where key is fontKey - a dynamically created label for a given font.
- fontmap = {}, // mapping structure fontName > fontStyle > font key - performance layer. See addFont()
- activeFontKey, // will be string representing the KEY of the font as combination of fontName + fontStyle
- k, // Scale factor
- tmp,
- page = 0,
- currentPage,
- pages = [],
- pagedim = {},
- content = [],
- lineCapID = 0,
- lineJoinID = 0,
- content_length = 0,
- pageWidth,
- pageHeight,
- pageMode,
- zoomMode,
- layoutMode,
- documentProperties = {
- 'title' : '',
- 'subject' : '',
- 'author' : '',
- 'keywords' : '',
- 'creator' : ''
- },
- API = {},
- events = new PubSub(API),
- lastTextWasStroke = false,
-
- /////////////////////
- // Private functions
- /////////////////////
- f2 = function(number) {
- return number.toFixed(2); // Ie, %.2f
- },
- f3 = function(number) {
- return number.toFixed(3); // Ie, %.3f
- },
- padd2 = function(number) {
- return ('0' + parseInt(number)).slice(-2);
- },
- out = function(string) {
- if (outToPages) {
- /* set by beginPage */
- pages[currentPage].push(string);
- } else {
- // +1 for '\n' that will be used to join 'content'
- content_length += string.length + 1;
- content.push(string);
- }
- },
- newObject = function() {
- // Begin a new object
- objectNumber++;
- offsets[objectNumber] = content_length;
- out(objectNumber + ' 0 obj');
- return objectNumber;
- },
- // Does not output the object. The caller must call newObjectDeferredBegin(oid) before outputing any data
- newObjectDeferred = function() {
- objectNumber++;
- offsets[objectNumber] = function(){
- return content_length;
- };
- return objectNumber;
- },
- newObjectDeferredBegin = function(oid) {
- offsets[oid] = content_length;
- },
- putStream = function(str) {
- out('stream');
- out(str);
- out('endstream');
- },
- putPages = function() {
- var n,p,arr,i,deflater,adler32,adler32cs,wPt,hPt;
-
- adler32cs = global.adler32cs || jsPDF.adler32cs;
- if (compress && typeof adler32cs === 'undefined') {
- compress = false;
- }
-
- // outToPages = false as set in endDocument(). out() writes to content.
-
- for (n = 1; n <= page; n++) {
- newObject();
- wPt = (pageWidth = pagedim[n].width) * k;
- hPt = (pageHeight = pagedim[n].height) * k;
- out('<>');
- out('endobj');
-
- // Page content
- p = pages[n].join('\n');
- newObject();
- if (compress) {
- arr = [];
- i = p.length;
- while(i--) {
- arr[i] = p.charCodeAt(i);
- }
- adler32 = adler32cs.from(p);
- deflater = new Deflater(6);
- deflater.append(new Uint8Array(arr));
- p = deflater.flush();
- arr = new Uint8Array(p.length + 6);
- arr.set(new Uint8Array([120, 156])),
- arr.set(p, 2);
- arr.set(new Uint8Array([adler32 & 0xFF, (adler32 >> 8) & 0xFF, (adler32 >> 16) & 0xFF, (adler32 >> 24) & 0xFF]), p.length+2);
- p = String.fromCharCode.apply(null, arr);
- out('<>');
- } else {
- out('<>');
- }
- putStream(p);
- out('endobj');
- }
- offsets[1] = content_length;
- out('1 0 obj');
- out('<< page; i++) {
- kids += (3 + 2 * i) + ' 0 R ';
- }
- out(kids + ']');
- out('/Count ' + page);
- out('>>');
- out('endobj');
- },
- putFont = function(font) {
- font.objectNumber = newObject();
- out('<>');
- out('endobj');
- },
- putFonts = function() {
- for (var fontKey in fonts) {
- if (fonts.hasOwnProperty(fontKey)) {
- putFont(fonts[fontKey]);
- }
- }
- },
- putXobjectDict = function() {
- // Loop through images, or other data objects
- events.publish('putXobjectDict');
- },
- putResourceDictionary = function() {
- out('/ProcSet [/PDF /Text /ImageB /ImageC /ImageI]');
- out('/Font <<');
-
- // Do this for each font, the '1' bit is the index of the font
- for (var fontKey in fonts) {
- if (fonts.hasOwnProperty(fontKey)) {
- out('/' + fontKey + ' ' + fonts[fontKey].objectNumber + ' 0 R');
- }
- }
- out('>>');
- out('/XObject <<');
- putXobjectDict();
- out('>>');
- },
- putResources = function() {
- putFonts();
- events.publish('putResources');
- // Resource dictionary
- offsets[2] = content_length;
- out('2 0 obj');
- out('<<');
- putResourceDictionary();
- out('>>');
- out('endobj');
- events.publish('postPutResources');
- },
- addToFontDictionary = function(fontKey, fontName, fontStyle) {
- // this is mapping structure for quick font key lookup.
- // returns the KEY of the font (ex: "F1") for a given
- // pair of font name and type (ex: "Arial". "Italic")
- if (!fontmap.hasOwnProperty(fontName)) {
- fontmap[fontName] = {};
- }
- fontmap[fontName][fontStyle] = fontKey;
- },
- /**
- * FontObject describes a particular font as member of an instnace of jsPDF
- *
- * It's a collection of properties like 'id' (to be used in PDF stream),
- * 'fontName' (font's family name), 'fontStyle' (font's style variant label)
- *
- * @class
- * @public
- * @property id {String} PDF-document-instance-specific label assinged to the font.
- * @property PostScriptName {String} PDF specification full name for the font
- * @property encoding {Object} Encoding_name-to-Font_metrics_object mapping.
- * @name FontObject
- */
- addFont = function(PostScriptName, fontName, fontStyle, encoding) {
- var fontKey = 'F' + (Object.keys(fonts).length + 1).toString(10),
- // This is FontObject
- font = fonts[fontKey] = {
- 'id' : fontKey,
- 'PostScriptName' : PostScriptName,
- 'fontName' : fontName,
- 'fontStyle' : fontStyle,
- 'encoding' : encoding,
- 'metadata' : {}
- };
- addToFontDictionary(fontKey, fontName, fontStyle);
- events.publish('addFont', font);
-
- return fontKey;
- },
- addFonts = function() {
-
- var HELVETICA = "helvetica",
- TIMES = "times",
- COURIER = "courier",
- NORMAL = "normal",
- BOLD = "bold",
- ITALIC = "italic",
- BOLD_ITALIC = "bolditalic",
- encoding = 'StandardEncoding',
- 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]
- ];
-
- for (var i = 0, l = standardFonts.length; i < l; i++) {
- var fontKey = addFont(
- standardFonts[i][0],
- standardFonts[i][1],
- standardFonts[i][2],
- encoding);
-
- // adding aliases for standard fonts, this time matching the capitalization
- var parts = standardFonts[i][0].split('-');
- addToFontDictionary(fontKey, parts[0], parts[1] || '');
- }
- events.publish('addFonts', { fonts : fonts, dictionary : fontmap });
- },
- SAFE = function __safeCall(fn) {
- fn.foo = function __safeCallWrapper() {
- try {
- return fn.apply(this, arguments);
- } catch (e) {
- var stack = e.stack || '';
- if(~stack.indexOf(' at ')) stack = stack.split(" at ")[1];
- var m = "Error in function " + stack.split("\n")[0].split('<')[0] + ": " + e.message;
- if(global.console) {
- global.console.error(m, e);
- if(global.alert) alert(m);
- } else {
- throw new Error(m);
- }
- }
- };
- fn.foo.bar = fn;
- return fn.foo;
- },
- to8bitStream = function(text, flags) {
- /**
- * PDF 1.3 spec:
- * "For text strings encoded in Unicode, the first two bytes must be 254 followed by
- * 255, representing the Unicode byte order marker, U+FEFF. (This sequence conflicts
- * with the PDFDocEncoding character sequence thorn ydieresis, which is unlikely
- * to be a meaningful beginning of a word or phrase.) The remainder of the
- * string consists of Unicode character codes, according to the UTF-16 encoding
- * specified in the Unicode standard, version 2.0. Commonly used Unicode values
- * are represented as 2 bytes per character, with the high-order byte appearing first
- * in the string."
- *
- * In other words, if there are chars in a string with char code above 255, we
- * recode the string to UCS2 BE - string doubles in length and BOM is prepended.
- *
- * HOWEVER!
- * Actual *content* (body) text (as opposed to strings used in document properties etc)
- * does NOT expect BOM. There, it is treated as a literal GID (Glyph ID)
- *
- * Because of Adobe's focus on "you subset your fonts!" you are not supposed to have
- * a font that maps directly Unicode (UCS2 / UTF16BE) code to font GID, but you could
- * fudge it with "Identity-H" encoding and custom CIDtoGID map that mimics Unicode
- * code page. There, however, all characters in the stream are treated as GIDs,
- * including BOM, which is the reason we need to skip BOM in content text (i.e. that
- * that is tied to a font).
- *
- * To signal this "special" PDFEscape / to8bitStream handling mode,
- * API.text() function sets (unless you overwrite it with manual values
- * given to API.text(.., flags) )
- * flags.autoencode = true
- * flags.noBOM = true
- *
- * ===================================================================================
- * `flags` properties relied upon:
- * .sourceEncoding = string with encoding label.
- * "Unicode" by default. = encoding of the incoming text.
- * pass some non-existing encoding name
- * (ex: 'Do not touch my strings! I know what I am doing.')
- * to make encoding code skip the encoding step.
- * .outputEncoding = Either valid PDF encoding name
- * (must be supported by jsPDF font metrics, otherwise no encoding)
- * or a JS object, where key = sourceCharCode, value = outputCharCode
- * missing keys will be treated as: sourceCharCode === outputCharCode
- * .noBOM
- * See comment higher above for explanation for why this is important
- * .autoencode
- * See comment higher above for explanation for why this is important
- */
-
- var i,l,sourceEncoding,encodingBlock,outputEncoding,newtext,isUnicode,ch,bch;
-
- flags = flags || {};
- sourceEncoding = flags.sourceEncoding || 'Unicode';
- outputEncoding = flags.outputEncoding;
-
- // This 'encoding' section relies on font metrics format
- // attached to font objects by, among others,
- // "Willow Systems' standard_font_metrics plugin"
- // see jspdf.plugin.standard_font_metrics.js for format
- // of the font.metadata.encoding Object.
- // It should be something like
- // .encoding = {'codePages':['WinANSI....'], 'WinANSI...':{code:code, ...}}
- // .widths = {0:width, code:width, ..., 'fof':divisor}
- // .kerning = {code:{previous_char_code:shift, ..., 'fof':-divisor},...}
- if ((flags.autoencode || outputEncoding) &&
- fonts[activeFontKey].metadata &&
- fonts[activeFontKey].metadata[sourceEncoding] &&
- fonts[activeFontKey].metadata[sourceEncoding].encoding) {
- encodingBlock = fonts[activeFontKey].metadata[sourceEncoding].encoding;
-
- // each font has default encoding. Some have it clearly defined.
- if (!outputEncoding && fonts[activeFontKey].encoding) {
- outputEncoding = fonts[activeFontKey].encoding;
- }
-
- // Hmmm, the above did not work? Let's try again, in different place.
- if (!outputEncoding && encodingBlock.codePages) {
- outputEncoding = encodingBlock.codePages[0]; // let's say, first one is the default
- }
-
- if (typeof outputEncoding === 'string') {
- outputEncoding = encodingBlock[outputEncoding];
- }
- // we want output encoding to be a JS Object, where
- // key = sourceEncoding's character code and
- // value = outputEncoding's character code.
- if (outputEncoding) {
- isUnicode = false;
- newtext = [];
- for (i = 0, l = text.length; i < l; i++) {
- ch = outputEncoding[text.charCodeAt(i)];
- if (ch) {
- newtext.push(
- String.fromCharCode(ch));
- } else {
- newtext.push(
- text[i]);
- }
-
- // since we are looping over chars anyway, might as well
- // check for residual unicodeness
- if (newtext[i].charCodeAt(0) >> 8) {
- /* more than 255 */
- isUnicode = true;
- }
- }
- text = newtext.join('');
- }
- }
-
- i = text.length;
- // isUnicode may be set to false above. Hence the triple-equal to undefined
- while (isUnicode === undefined && i !== 0) {
- if (text.charCodeAt(i - 1) >> 8) {
- /* more than 255 */
- isUnicode = true;
- }
- i--;
- }
- if (!isUnicode) {
- return text;
- }
-
- newtext = flags.noBOM ? [] : [254, 255];
- for (i = 0, l = text.length; i < l; i++) {
- ch = text.charCodeAt(i);
- bch = ch >> 8; // divide by 256
- if (bch >> 8) {
- /* something left after dividing by 256 second time */
- throw new Error("Character at position " + i + " of string '"
- + text + "' exceeds 16bits. Cannot be encoded into UCS-2 BE");
- }
- newtext.push(bch);
- newtext.push(ch - (bch << 8));
- }
- return String.fromCharCode.apply(undefined, newtext);
- },
- pdfEscape = function(text, flags) {
- /**
- * Replace '/', '(', and ')' with pdf-safe versions
- *
- * Doing to8bitStream does NOT make this PDF display unicode text. For that
- * we also need to reference a unicode font and embed it - royal pain in the rear.
- *
- * There is still a benefit to to8bitStream - PDF simply cannot handle 16bit chars,
- * which JavaScript Strings are happy to provide. So, while we still cannot display
- * 2-byte characters property, at least CONDITIONALLY converting (entire string containing)
- * 16bit chars to (USC-2-BE) 2-bytes per char + BOM streams we ensure that entire PDF
- * is still parseable.
- * This will allow immediate support for unicode in document properties strings.
- */
- return to8bitStream(text, flags).replace(/\\/g, '\\\\').replace(/\(/g, '\\(').replace(/\)/g, '\\)');
- },
- putInfo = function() {
- out('/Producer (jsPDF ' + jsPDF.version + ')');
- for(var key in documentProperties) {
- if(documentProperties.hasOwnProperty(key) && documentProperties[key]) {
- out('/'+key.substr(0,1).toUpperCase() + key.substr(1)
- +' (' + pdfEscape(documentProperties[key]) + ')');
- }
- }
- var created = new Date(),
- tzoffset = created.getTimezoneOffset(),
- tzsign = tzoffset < 0 ? '+' : '-',
- tzhour = Math.floor(Math.abs(tzoffset / 60)),
- tzmin = Math.abs(tzoffset % 60),
- tzstr = [tzsign, padd2(tzhour), "'", padd2(tzmin), "'"].join('');
- out(['/CreationDate (D:',
- created.getFullYear(),
- padd2(created.getMonth() + 1),
- padd2(created.getDate()),
- padd2(created.getHours()),
- padd2(created.getMinutes()),
- padd2(created.getSeconds()), tzstr, ')'].join(''));
- },
- putCatalog = function() {
- out('/Type /Catalog');
- out('/Pages 1 0 R');
- // PDF13ref Section 7.2.1
- if (!zoomMode) zoomMode = 'fullwidth';
- switch(zoomMode) {
- case 'fullwidth' : out('/OpenAction [3 0 R /FitH null]'); break;
- case 'fullheight' : out('/OpenAction [3 0 R /FitV null]'); break;
- case 'fullpage' : out('/OpenAction [3 0 R /Fit]'); break;
- case 'original' : out('/OpenAction [3 0 R /XYZ null null 1]'); break;
- default:
- var pcn = '' + zoomMode;
- if (pcn.substr(pcn.length-1) === '%')
- zoomMode = parseInt(zoomMode) / 100;
- if (typeof zoomMode === 'number') {
- out('/OpenAction [3 0 R /XYZ null null '+f2(zoomMode)+']');
- }
- }
- if (!layoutMode) layoutMode = 'continuous';
- switch(layoutMode) {
- case 'continuous' : out('/PageLayout /OneColumn'); break;
- case 'single' : out('/PageLayout /SinglePage'); break;
- case 'two':
- case 'twoleft' : out('/PageLayout /TwoColumnLeft'); break;
- case 'tworight' : out('/PageLayout /TwoColumnRight'); break;
- }
- if (pageMode) {
- /**
- * A name object specifying how the document should be displayed when opened:
- * UseNone : Neither document outline nor thumbnail images visible -- DEFAULT
- * UseOutlines : Document outline visible
- * UseThumbs : Thumbnail images visible
- * FullScreen : Full-screen mode, with no menu bar, window controls, or any other window visible
- */
- out('/PageMode /' + pageMode);
- }
- events.publish('putCatalog');
- },
- putTrailer = function() {
- out('/Size ' + (objectNumber + 1));
- out('/Root ' + objectNumber + ' 0 R');
- out('/Info ' + (objectNumber - 1) + ' 0 R');
- },
- beginPage = function(width,height) {
- // Dimensions are stored as user units and converted to points on output
- var orientation = typeof height === 'string' && height.toLowerCase();
- if (typeof width === 'string') {
- var format = width.toLowerCase();
- if (pageFormats.hasOwnProperty(format)) {
- width = pageFormats[format][0] / k;
- height = pageFormats[format][1] / k;
- }
- }
- if (Array.isArray(width)) {
- height = width[1];
- width = width[0];
- }
- if (orientation) {
- switch(orientation.substr(0,1)) {
- case 'l': if (height > width ) orientation = 's'; break;
- case 'p': if (width > height ) orientation = 's'; break;
- }
- if (orientation === 's') { tmp = width; width = height; height = tmp; }
- }
- outToPages = true;
- pages[++page] = [];
- pagedim[page] = {
- width : Number(width) || pageWidth,
- height : Number(height) || pageHeight
- };
- _setPage(page);
- },
- _addPage = function() {
- beginPage.apply(this, arguments);
- // Set line width
- out(f2(lineWidth * k) + ' w');
- // Set draw color
- out(drawColor);
- // resurrecting non-default line caps, joins
- if (lineCapID !== 0) {
- out(lineCapID + ' J');
- }
- if (lineJoinID !== 0) {
- out(lineJoinID + ' j');
- }
- events.publish('addPage', { pageNumber : page });
- },
- _setPage = function(n) {
- if (n > 0 && n <= page) {
- currentPage = n;
- pageWidth = pagedim[n].width;
- pageHeight = pagedim[n].height;
- }
- },
- /**
- * Returns a document-specific font key - a label assigned to a
- * font name + font type combination at the time the font was added
- * to the font inventory.
- *
- * Font key is used as label for the desired font for a block of text
- * to be added to the PDF document stream.
- * @private
- * @function
- * @param fontName {String} can be undefined on "falthy" to indicate "use current"
- * @param fontStyle {String} can be undefined on "falthy" to indicate "use current"
- * @returns {String} Font key.
- */
- getFont = function(fontName, fontStyle) {
- var key;
-
- fontName = fontName !== undefined ? fontName : fonts[activeFontKey].fontName;
- fontStyle = fontStyle !== undefined ? fontStyle : fonts[activeFontKey].fontStyle;
-
- try {
- // get a string like 'F3' - the KEY corresponding tot he font + type combination.
- key = fontmap[fontName][fontStyle];
- } catch (e) {}
-
- if (!key) {
- throw new Error("Unable to look up font label for font '" + fontName + "', '"
- + fontStyle + "'. Refer to getFontList() for available fonts.");
- }
- return key;
- },
- buildDocument = function() {
-
- outToPages = false; // switches out() to content
- objectNumber = 2;
- content = [];
- offsets = [];
-
- // putHeader()
- out('%PDF-' + pdfVersion);
-
- putPages();
-
- putResources();
-
- // Info
- newObject();
- out('<<');
- putInfo();
- out('>>');
- out('endobj');
-
- // Catalog
- newObject();
- out('<<');
- putCatalog();
- out('>>');
- out('endobj');
-
- // Cross-ref
- var o = content_length, i, p = "0000000000";
- out('xref');
- out('0 ' + (objectNumber + 1));
- out(p+' 65535 f ');
- for (i = 1; i <= objectNumber; i++) {
- var offset = offsets[i];
- if (typeof offset === 'function'){
- out((p + offsets[i]()).slice(-10) + ' 00000 n ');
- }else{
- out((p + offsets[i]).slice(-10) + ' 00000 n ');
- }
- }
- // Trailer
- out('trailer');
- out('<<');
- putTrailer();
- out('>>');
- out('startxref');
- out(o);
- out('%%EOF');
-
- outToPages = true;
-
- return content.join('\n');
- },
- getStyle = function(style) {
- // see path-painting operators in PDF spec
- var op = 'S'; // stroke
- if (style === 'F') {
- op = 'f'; // fill
- } else if (style === 'FD' || style === 'DF') {
- op = 'B'; // both
- } else if (style === 'f' || style === 'f*' || style === 'B' || style === 'B*') {
- /*
- Allow direct use of these PDF path-painting operators:
- - f fill using nonzero winding number rule
- - f* fill using even-odd rule
- - B fill then stroke with fill using non-zero winding number rule
- - B* fill then stroke with fill using even-odd rule
- */
- op = style;
- }
- return op;
- },
- getArrayBuffer = function() {
- var data = buildDocument(), len = data.length,
- ab = new ArrayBuffer(len), u8 = new Uint8Array(ab);
-
- while(len--) u8[len] = data.charCodeAt(len);
- return ab;
- },
- getBlob = function() {
- return new Blob([getArrayBuffer()], { type : "application/pdf" });
- },
- /**
- * Generates the PDF document.
- *
- * If `type` argument is undefined, output is raw body of resulting PDF returned as a string.
- *
- * @param {String} type A string identifying one of the possible output types.
- * @param {Object} options An object providing some additional signalling to PDF generator.
- * @function
- * @returns {jsPDF}
- * @methodOf jsPDF#
- * @name output
- */
- output = SAFE(function(type, options) {
- var datauri = ('' + type).substr(0,6) === 'dataur'
- ? 'data:application/pdf;base64,'+btoa(buildDocument()):0;
-
- switch (type) {
- case undefined:
- return buildDocument();
- case 'save':
- if (navigator.getUserMedia) {
- if (global.URL === undefined
- || global.URL.createObjectURL === undefined) {
- return API.output('dataurlnewwindow');
- }
- }
- saveAs(getBlob(), options);
- if(typeof saveAs.unload === 'function') {
- if(global.setTimeout) {
- setTimeout(saveAs.unload,911);
- }
- }
- break;
- case 'arraybuffer':
- return getArrayBuffer();
- case 'blob':
- return getBlob();
- case 'bloburi':
- case 'bloburl':
- // User is responsible of calling revokeObjectURL
- return global.URL && global.URL.createObjectURL(getBlob()) || void 0;
- case 'datauristring':
- case 'dataurlstring':
- return datauri;
- case 'dataurlnewwindow':
- var nW = global.open(datauri);
- if (nW || typeof safari === "undefined") return nW;
- /* pass through */
- case 'datauri':
- case 'dataurl':
- return global.document.location.href = datauri;
- default:
- throw new Error('Output type "' + type + '" is not supported.');
- }
- // @TODO: Add different output options
- });
-
- switch (unit) {
- case 'pt': k = 1; break;
- case 'mm': k = 72 / 25.4000508; break;
- case 'cm': k = 72 / 2.54000508; break;
- case 'in': k = 72; break;
- case 'px': k = 96 / 72; break;
- case 'pc': k = 12; break;
- case 'em': k = 12; break;
- case 'ex': k = 6; break;
- default:
- throw ('Invalid unit: ' + unit);
- }
-
- //---------------------------------------
- // Public API
-
- /**
- * Object exposing internal API to plugins
- * @public
- */
- API.internal = {
- 'pdfEscape' : pdfEscape,
- 'getStyle' : getStyle,
- /**
- * Returns {FontObject} describing a particular font.
- * @public
- * @function
- * @param fontName {String} (Optional) Font's family name
- * @param fontStyle {String} (Optional) Font's style variation name (Example:"Italic")
- * @returns {FontObject}
- */
- 'getFont' : function() {
- return fonts[getFont.apply(API, arguments)];
- },
- 'getFontSize' : function() {
- return activeFontSize;
- },
- 'getLineHeight' : function() {
- return activeFontSize * lineHeightProportion;
- },
- 'write' : function(string1 /*, string2, string3, etc */) {
- out(arguments.length === 1 ? string1 : Array.prototype.join.call(arguments, ' '));
- },
- 'getCoordinateString' : function(value) {
- return f2(value * k);
- },
- 'getVerticalCoordinateString' : function(value) {
- return f2((pageHeight - value) * k);
- },
- 'collections' : {},
- 'newObject' : newObject,
- 'newObjectDeferred' : newObjectDeferred,
- 'newObjectDeferredBegin' : newObjectDeferredBegin,
- 'putStream' : putStream,
- 'events' : events,
- // ratio that you use in multiplication of a given "size" number to arrive to 'point'
- // units of measurement.
- // scaleFactor is set at initialization of the document and calculated against the stated
- // default measurement units for the document.
- // If default is "mm", k is the number that will turn number in 'mm' into 'points' number.
- // through multiplication.
- 'scaleFactor' : k,
- 'pageSize' : {
- get width() {
- return pageWidth
- },
- get height() {
- return pageHeight
- }
- },
- 'output' : function(type, options) {
- return output(type, options);
- },
- 'getNumberOfPages' : function() {
- return pages.length - 1;
- },
- 'pages' : pages,
- 'out' : out,
- 'f2' : f2,
- 'getPageInfo' : function(pageNumberOneBased){
- var objId = (pageNumberOneBased - 1) * 2 + 3;
- return {objId:objId, pageNumber:pageNumberOneBased};
- },
- 'getCurrentPageInfo' : function(){
- var objId = (currentPage - 1) * 2 + 3;
- return {objId:objId, pageNumber:currentPage};
- }
- };
-
- /**
- * Adds (and transfers the focus to) new page to the PDF document.
- * @function
- * @returns {jsPDF}
- *
- * @methodOf jsPDF#
- * @name addPage
- */
- API.addPage = function() {
- _addPage.apply(this, arguments);
- return this;
- };
- API.setPage = function() {
- _setPage.apply(this, arguments);
- return this;
- };
- API.insertPage = function(beforePage) {
- this.addPage();
- this.movePage(currentPage, beforePage);
- return this;
- };
- API.movePage = function(targetPage, beforePage) {
- if (targetPage > beforePage){
- var tmpPages = pages[targetPage];
- var tmpPagedim = pagedim[targetPage];
- for (var i=targetPage; i>beforePage; i--){
- pages[i] = pages[i-1];
- pagedim[i] = pagedim[i-1];
- }
- pages[beforePage] = tmpPages;
- pagedim[beforePage] = tmpPagedim;
- this.setPage(beforePage);
- }else if (targetPage < beforePage){
- var tmpPages = pages[targetPage];
- var tmpPagedim = pagedim[targetPage];
- for (var i=targetPage; i< page; i++){
- pages[i] = pages[i+1];
- pagedim[i] = pagedim[i+1];
- }
- page--;
- if (currentPage > page){
- currentPage = page;
- }
- this.setPage(currentPage);
- return this;
- };
- API.setDisplayMode = function(zoom, layout, pmode) {
- zoomMode = zoom;
- layoutMode = layout;
- pageMode = pmode;
- return this;
- },
-
- /**
- * Adds text to page. Supports adding multiline text when 'text' argument is an Array of Strings.
- *
- * @function
- * @param {String|Array} text String or array of strings to be added to the page. Each line is shifted one line down per font, spacing settings declared before this call.
- * @param {Number} x Coordinate (in units declared at inception of PDF document) against left edge of the page
- * @param {Number} y Coordinate (in units declared at inception of PDF document) against upper edge of the page
- * @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.
- * @returns {jsPDF}
- * @methodOf jsPDF#
- * @name text
- */
- API.text = function(text, x, y, flags, angle, align) {
- /**
- * Inserts something like this into PDF
- * BT
- * /F1 16 Tf % Font name + size
- * 16 TL % How many units down for next line in multiline text
- * 0 g % color
- * 28.35 813.54 Td % position
- * (line one) Tj
- * T* (line two) Tj
- * T* (line three) Tj
- * ET
- */
- function ESC(s) {
- s = s.split("\t").join(Array(options.TabLen||9).join(" "));
- return pdfEscape(s, flags);
- }
-
- // Pre-August-2012 the order of arguments was function(x, y, text, flags)
- // in effort to make all calls have similar signature like
- // function(data, coordinates... , miscellaneous)
- // this method had its args flipped.
- // code below allows backward compatibility with old arg order.
- if (typeof text === 'number') {
- tmp = y;
- y = x;
- x = text;
- text = tmp;
- }
-
- // If there are any newlines in text, we assume
- // the user wanted to print multiple lines, so break the
- // text up into an array. If the text is already an array,
- // we assume the user knows what they are doing.
- if (typeof text === 'string') {
- if(text.match(/[\n\r]/)) {
- text = text.split( /\r\n|\r|\n/g);
- } else {
- // Convert text into an array anyway
- // to simplify later code.
- text = [text];
- }
- }
- if (typeof angle === 'string') {
- align = angle;
- angle = null;
- }
- if (typeof flags === 'string') {
- align = flags;
- flags = null;
- }
- if (typeof flags === 'number') {
- angle = flags;
- flags = null;
- }
- var xtra = '',mode = 'Td', todo;
- if (angle) {
- angle *= (Math.PI / 180);
- var c = Math.cos(angle),
- s = Math.sin(angle);
- xtra = [f2(c), f2(s), f2(s * -1), f2(c), ''].join(" ");
- mode = 'Tm';
- }
- flags = flags || {};
- if (!('noBOM' in flags))
- flags.noBOM = true;
- if (!('autoencode' in flags))
- flags.autoencode = true;
-
- //TODO this might not work after object block changes
- // It would be better to pass in a page context
- var strokeOption = '';
- if (true === flags.stroke){
- if (this.lastTextWasStroke !== true){
- strokeOption = '1 Tr\n';
- this.lastTextWasStroke = true;
- }
- }
- else{
- if (this.lastTextWasStroke){
- strokeOption = '0 Tr\n';
- }
- this.lastTextWasStroke = false;
- }
-
- if (text instanceof Array) {
- // we don't want to destroy original text array, so cloning it
- var sa = text.concat(), da = [], i, len = sa.length;
- // we do array.join('text that must not be PDFescaped")
- // thus, pdfEscape each component separately
- while (len--) {
- da.push(ESC(sa.shift()));
- }
- var linesLeft = Math.ceil((pageHeight - y) * k / (activeFontSize * lineHeightProportion));
- if (0 <= linesLeft && linesLeft < da.length + 1) {
- todo = da.splice(linesLeft-1);
- }
-
- if( align ) {
- var prevX,
- leading = activeFontSize * lineHeightProportion,
- lineWidths = text.map( function( v ) {
- return this.getStringUnitWidth( v ) * activeFontSize / k;
- }, this );
- // The first line uses the "main" Td setting,
- // and the subsequent lines are offset by the
- // previous line's x coordinate.
- if( align === "center" ) {
- // The passed in x coordinate defines
- // the center point.
- x -= lineWidths[0] / 2;
- } else if ( align === "right" ) {
- // The passed in x coordinate defines the
- // rightmost point of the text.
- x -= lineWidths[0];
- } else {
- throw new Error('Unrecognized alignment option, use "center" or "right".');
- }
- prevX = x;
- text = da[0];
- for ( i = 1, len = da.length ; i < len; i++ ) {
- var delta = lineWidths[i-1] - lineWidths[i];
- if( align === "center" ) delta /= 2;
- // T* = x-offset leading Td ( text )
- // PDF Spec 1.3 p.288
- text += ") Tj\n" + delta + " -" + leading + " Td (" + da[i];
- prevX += delta;
- }
- } else {
- text = da.join(") Tj\nT* (");
- }
- } else {
- throw new Error('Type of text must be string or Array. "' + text + '" is not recognized.');
- }
- // Using "'" ("go next line and render text" mark) would save space but would complicate our rendering code, templates
-
- // BT .. ET does NOT have default settings for Tf. You must state that explicitely every time for BT .. ET
- // if you want text transformation matrix (+ multiline) to work reliably (which reads sizes of things from font declarations)
- // Thus, there is NO useful, *reliable* concept of "default" font for a page.
- // The fact that "default" (reuse font used before) font worked before in basic cases is an accident
- // - readers dealing smartly with brokenness of jsPDF's markup.
- out(
- 'BT\n/' +
- activeFontKey + ' ' + activeFontSize + ' Tf\n' + // font face, style, size
- (activeFontSize * lineHeightProportion) + ' TL\n' + // line spacing
- strokeOption +// stroke option
- textColor +
- '\n' + xtra + f2(x * k) + ' ' + f2((pageHeight - y) * k) + ' ' + mode + '\n(' +
- text +
- ') Tj\nET');
-
- if (todo) {
- this.addPage();
- this.text( todo, x, activeFontSize * 1.7 / k);
- }
-
- return this;
- };
-
- API.lstext = function(text, x, y, spacing) {
- for (var i = 0, len = text.length ; i < len; i++, x += spacing) this.text(text[i], x, y);
- };
-
- API.line = function(x1, y1, x2, y2) {
- return this.lines([[x2 - x1, y2 - y1]], x1, y1);
- };
-
- API.clip = function() {
- // By patrick-roberts, github.com/MrRio/jsPDF/issues/328
- // Call .clip() after calling .rect() with a style argument of null
- out('W') // clip
- out('S') // stroke path; necessary for clip to work
- };
-
- /**
- * Adds series of curves (straight lines or cubic bezier curves) to canvas, starting at `x`, `y` coordinates.
- * All data points in `lines` are relative to last line origin.
- * `x`, `y` become x1,y1 for first line / curve in the set.
- * For lines you only need to specify [x2, y2] - (ending point) vector against x1, y1 starting point.
- * 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.
- *
- * @example .lines([[2,2],[-2,2],[1,1,2,2,3,3],[2,1]], 212,110, 10) // line, line, bezier curve, line
- * @param {Array} lines Array of *vector* shifts as pairs (lines) or sextets (cubic bezier curves).
- * @param {Number} x Coordinate (in units declared at inception of PDF document) against left edge of the page
- * @param {Number} y Coordinate (in units declared at inception of PDF document) against upper edge of the page
- * @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.
- * @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.
- * @param {Boolean} closed If true, the path is closed with a straight line from the end of the last curve to the starting point.
- * @function
- * @returns {jsPDF}
- * @methodOf jsPDF#
- * @name lines
- */
- API.lines = function(lines, x, y, scale, style, closed) {
- var scalex,scaley,i,l,leg,x2,y2,x3,y3,x4,y4;
-
- // Pre-August-2012 the order of arguments was function(x, y, lines, scale, style)
- // in effort to make all calls have similar signature like
- // function(content, coordinateX, coordinateY , miscellaneous)
- // this method had its args flipped.
- // code below allows backward compatibility with old arg order.
- if (typeof lines === 'number') {
- tmp = y;
- y = x;
- x = lines;
- lines = tmp;
- }
-
- scale = scale || [1, 1];
-
- // starting point
- out(f3(x * k) + ' ' + f3((pageHeight - y) * k) + ' m ');
-
- scalex = scale[0];
- scaley = scale[1];
- l = lines.length;
- //, x2, y2 // bezier only. In page default measurement "units", *after* scaling
- //, x3, y3 // bezier only. In page default measurement "units", *after* scaling
- // ending point for all, lines and bezier. . In page default measurement "units", *after* scaling
- x4 = x; // last / ending point = starting point for first item.
- y4 = y; // last / ending point = starting point for first item.
-
- for (i = 0; i < l; i++) {
- leg = lines[i];
- if (leg.length === 2) {
- // simple line
- x4 = leg[0] * scalex + x4; // here last x4 was prior ending point
- y4 = leg[1] * scaley + y4; // here last y4 was prior ending point
- out(f3(x4 * k) + ' ' + f3((pageHeight - y4) * k) + ' l');
- } else {
- // bezier curve
- x2 = leg[0] * scalex + x4; // here last x4 is prior ending point
- y2 = leg[1] * scaley + y4; // here last y4 is prior ending point
- x3 = leg[2] * scalex + x4; // here last x4 is prior ending point
- y3 = leg[3] * scaley + y4; // here last y4 is prior ending point
- x4 = leg[4] * scalex + x4; // here last x4 was prior ending point
- y4 = leg[5] * scaley + y4; // here last y4 was prior ending point
- out(
- f3(x2 * k) + ' ' +
- f3((pageHeight - y2) * k) + ' ' +
- f3(x3 * k) + ' ' +
- f3((pageHeight - y3) * k) + ' ' +
- f3(x4 * k) + ' ' +
- f3((pageHeight - y4) * k) + ' c');
- }
- }
-
- if (closed) {
- out(' h');
- }
-
- // stroking / filling / both the path
- if (style !== null) {
- out(getStyle(style));
- }
- return this;
- };
-
- /**
- * Adds a rectangle to PDF
- *
- * @param {Number} x Coordinate (in units declared at inception of PDF document) against left edge of the page
- * @param {Number} y Coordinate (in units declared at inception of PDF document) against upper edge of the page
- * @param {Number} w Width (in units declared at inception of PDF document)
- * @param {Number} h Height (in units declared at inception of PDF document)
- * @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.
- * @function
- * @returns {jsPDF}
- * @methodOf jsPDF#
- * @name rect
- */
- API.rect = function(x, y, w, h, style) {
- var op = getStyle(style);
- out([
- f2(x * k),
- f2((pageHeight - y) * k),
- f2(w * k),
- f2(-h * k),
- 're'
- ].join(' '));
-
- if (style !== null) {
- out(getStyle(style));
- }
-
- return this;
- };
-
- /**
- * Adds a triangle to PDF
- *
- * @param {Number} x1 Coordinate (in units declared at inception of PDF document) against left edge of the page
- * @param {Number} y1 Coordinate (in units declared at inception of PDF document) against upper edge of the page
- * @param {Number} x2 Coordinate (in units declared at inception of PDF document) against left edge of the page
- * @param {Number} y2 Coordinate (in units declared at inception of PDF document) against upper edge of the page
- * @param {Number} x3 Coordinate (in units declared at inception of PDF document) against left edge of the page
- * @param {Number} y3 Coordinate (in units declared at inception of PDF document) against upper edge of the page
- * @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.
- * @function
- * @returns {jsPDF}
- * @methodOf jsPDF#
- * @name triangle
- */
- API.triangle = function(x1, y1, x2, y2, x3, y3, style) {
- this.lines(
- [
- [x2 - x1, y2 - y1], // vector to point 2
- [x3 - x2, y3 - y2], // vector to point 3
- [x1 - x3, y1 - y3]// closing vector back to point 1
- ],
- x1,
- y1, // start of path
- [1, 1],
- style,
- true);
- return this;
- };
-
- /**
- * Adds a rectangle with rounded corners to PDF
- *
- * @param {Number} x Coordinate (in units declared at inception of PDF document) against left edge of the page
- * @param {Number} y Coordinate (in units declared at inception of PDF document) against upper edge of the page
- * @param {Number} w Width (in units declared at inception of PDF document)
- * @param {Number} h Height (in units declared at inception of PDF document)
- * @param {Number} rx Radius along x axis (in units declared at inception of PDF document)
- * @param {Number} rx Radius along y axis (in units declared at inception of PDF document)
- * @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.
- * @function
- * @returns {jsPDF}
- * @methodOf jsPDF#
- * @name roundedRect
- */
- API.roundedRect = function(x, y, w, h, rx, ry, style) {
- var MyArc = 4 / 3 * (Math.SQRT2 - 1);
- 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
- [1, 1],
- style);
- return this;
- };
-
- /**
- * Adds an ellipse to PDF
- *
- * @param {Number} x Coordinate (in units declared at inception of PDF document) against left edge of the page
- * @param {Number} y Coordinate (in units declared at inception of PDF document) against upper edge of the page
- * @param {Number} rx Radius along x axis (in units declared at inception of PDF document)
- * @param {Number} rx Radius along y axis (in units declared at inception of PDF document)
- * @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.
- * @function
- * @returns {jsPDF}
- * @methodOf jsPDF#
- * @name ellipse
- */
- API.ellipse = function(x, y, rx, ry, style) {
- var lx = 4 / 3 * (Math.SQRT2 - 1) * rx,
- ly = 4 / 3 * (Math.SQRT2 - 1) * ry;
-
- 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(' '));
- 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(' '));
- 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(' '));
- 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(' '));
-
- if (style !== null) {
- out(getStyle(style));
- }
-
- return this;
- };
-
- /**
- * Adds an circle to PDF
- *
- * @param {Number} x Coordinate (in units declared at inception of PDF document) against left edge of the page
- * @param {Number} y Coordinate (in units declared at inception of PDF document) against upper edge of the page
- * @param {Number} r Radius (in units declared at inception of PDF document)
- * @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.
- * @function
- * @returns {jsPDF}
- * @methodOf jsPDF#
- * @name circle
- */
- API.circle = function(x, y, r, style) {
- return this.ellipse(x, y, r, r, style);
- };
-
- /**
- * Adds a properties to the PDF document
- *
- * @param {Object} A property_name-to-property_value object structure.
- * @function
- * @returns {jsPDF}
- * @methodOf jsPDF#
- * @name setProperties
- */
- API.setProperties = function(properties) {
- // copying only those properties we can render.
- for (var property in documentProperties) {
- if (documentProperties.hasOwnProperty(property) && properties[property]) {
- documentProperties[property] = properties[property];
- }
- }
- return this;
- };
-
- /**
- * Sets font size for upcoming text elements.
- *
- * @param {Number} size Font size in points.
- * @function
- * @returns {jsPDF}
- * @methodOf jsPDF#
- * @name setFontSize
- */
- API.setFontSize = function(size) {
- activeFontSize = size;
- return this;
- };
-
- /**
- * Sets text font face, variant for upcoming text elements.
- * See output of jsPDF.getFontList() for possible font names, styles.
- *
- * @param {String} fontName Font name or family. Example: "times"
- * @param {String} fontStyle Font style or variant. Example: "italic"
- * @function
- * @returns {jsPDF}
- * @methodOf jsPDF#
- * @name setFont
- */
- API.setFont = function(fontName, fontStyle) {
- activeFontKey = getFont(fontName, fontStyle);
- // if font is not found, the above line blows up and we never go further
- return this;
- };
-
- /**
- * Switches font style or variant for upcoming text elements,
- * while keeping the font face or family same.
- * See output of jsPDF.getFontList() for possible font names, styles.
- *
- * @param {String} style Font style or variant. Example: "italic"
- * @function
- * @returns {jsPDF}
- * @methodOf jsPDF#
- * @name setFontStyle
- */
- API.setFontStyle = API.setFontType = function(style) {
- activeFontKey = getFont(undefined, style);
- // if font is not found, the above line blows up and we never go further
- return this;
- };
-
- /**
- * Returns an object - a tree of fontName to fontStyle relationships available to
- * active PDF document.
- *
- * @public
- * @function
- * @returns {Object} Like {'times':['normal', 'italic', ... ], 'arial':['normal', 'bold', ... ], ... }
- * @methodOf jsPDF#
- * @name getFontList
- */
- API.getFontList = function() {
- // TODO: iterate over fonts array or return copy of fontmap instead in case more are ever added.
- var list = {},fontName,fontStyle,tmp;
-
- for (fontName in fontmap) {
- if (fontmap.hasOwnProperty(fontName)) {
- list[fontName] = tmp = [];
- for (fontStyle in fontmap[fontName]) {
- if (fontmap[fontName].hasOwnProperty(fontStyle)) {
- tmp.push(fontStyle);
- }
- }
- }
- }
-
- return list;
- };
-
- /**
- * Add a custom font.
- *
- * @param {String} Postscript name of the Font. Example: "Menlo-Regular"
- * @param {String} Name of font-family from @font-face definition. Example: "Menlo Regular"
- * @param {String} Font style. Example: "normal"
- * @function
- * @returns the {fontKey} (same as the internal method)
- * @methodOf jsPDF#
- * @name addFont
- */
- API.addFont = function(postScriptName, fontName, fontStyle) {
- addFont(postScriptName, fontName, fontStyle, 'StandardEncoding');
- };
-
- /**
- * Sets line width for upcoming lines.
- *
- * @param {Number} width Line width (in units declared at inception of PDF document)
- * @function
- * @returns {jsPDF}
- * @methodOf jsPDF#
- * @name setLineWidth
- */
- API.setLineWidth = function(width) {
- out((width * k).toFixed(2) + ' w');
- return this;
- };
-
- /**
- * Sets the stroke color for upcoming elements.
- *
- * Depending on the number of arguments given, Gray, RGB, or CMYK
- * color space is implied.
- *
- * When only ch1 is given, "Gray" color space is implied and it
- * must be a value in the range from 0.00 (solid black) to to 1.00 (white)
- * if values are communicated as String types, or in range from 0 (black)
- * to 255 (white) if communicated as Number type.
- * The RGB-like 0-255 range is provided for backward compatibility.
- *
- * When only ch1,ch2,ch3 are given, "RGB" color space is implied and each
- * value must be in the range from 0.00 (minimum intensity) to to 1.00
- * (max intensity) if values are communicated as String types, or
- * from 0 (min intensity) to to 255 (max intensity) if values are communicated
- * as Number types.
- * The RGB-like 0-255 range is provided for backward compatibility.
- *
- * When ch1,ch2,ch3,ch4 are given, "CMYK" color space is implied and each
- * value must be a in the range from 0.00 (0% concentration) to to
- * 1.00 (100% concentration)
- *
- * Because JavaScript treats fixed point numbers badly (rounds to
- * floating point nearest to binary representation) it is highly advised to
- * communicate the fractional numbers as String types, not JavaScript Number type.
- *
- * @param {Number|String} ch1 Color channel value
- * @param {Number|String} ch2 Color channel value
- * @param {Number|String} ch3 Color channel value
- * @param {Number|String} ch4 Color channel value
- *
- * @function
- * @returns {jsPDF}
- * @methodOf jsPDF#
- * @name setDrawColor
- */
- API.setDrawColor = function(ch1, ch2, ch3, ch4) {
- var color;
- if (ch2 === undefined || (ch4 === undefined && ch1 === ch2 === ch3)) {
- // Gray color space.
- if (typeof ch1 === 'string') {
- color = ch1 + ' G';
- } else {
- color = f2(ch1 / 255) + ' G';
- }
- } else if (ch4 === undefined) {
- // RGB
- if (typeof ch1 === 'string') {
- color = [ch1, ch2, ch3, 'RG'].join(' ');
- } else {
- color = [f2(ch1 / 255), f2(ch2 / 255), f2(ch3 / 255), 'RG'].join(' ');
- }
- } else {
- // CMYK
- if (typeof ch1 === 'string') {
- color = [ch1, ch2, ch3, ch4, 'K'].join(' ');
- } else {
- color = [f2(ch1), f2(ch2), f2(ch3), f2(ch4), 'K'].join(' ');
- }
- }
-
- out(color);
- return this;
- };
-
- /**
- * Sets the fill color for upcoming elements.
- *
- * Depending on the number of arguments given, Gray, RGB, or CMYK
- * color space is implied.
- *
- * When only ch1 is given, "Gray" color space is implied and it
- * must be a value in the range from 0.00 (solid black) to to 1.00 (white)
- * if values are communicated as String types, or in range from 0 (black)
- * to 255 (white) if communicated as Number type.
- * The RGB-like 0-255 range is provided for backward compatibility.
- *
- * When only ch1,ch2,ch3 are given, "RGB" color space is implied and each
- * value must be in the range from 0.00 (minimum intensity) to to 1.00
- * (max intensity) if values are communicated as String types, or
- * from 0 (min intensity) to to 255 (max intensity) if values are communicated
- * as Number types.
- * The RGB-like 0-255 range is provided for backward compatibility.
- *
- * When ch1,ch2,ch3,ch4 are given, "CMYK" color space is implied and each
- * value must be a in the range from 0.00 (0% concentration) to to
- * 1.00 (100% concentration)
- *
- * Because JavaScript treats fixed point numbers badly (rounds to
- * floating point nearest to binary representation) it is highly advised to
- * communicate the fractional numbers as String types, not JavaScript Number type.
- *
- * @param {Number|String} ch1 Color channel value
- * @param {Number|String} ch2 Color channel value
- * @param {Number|String} ch3 Color channel value
- * @param {Number|String} ch4 Color channel value
- *
- * @function
- * @returns {jsPDF}
- * @methodOf jsPDF#
- * @name setFillColor
- */
- API.setFillColor = function(ch1, ch2, ch3, ch4) {
- var color;
-
- if (ch2 === undefined || (ch4 === undefined && ch1 === ch2 === ch3)) {
- // Gray color space.
- if (typeof ch1 === 'string') {
- color = ch1 + ' g';
- } else {
- color = f2(ch1 / 255) + ' g';
- }
- } else if (ch4 === undefined) {
- // RGB
- if (typeof ch1 === 'string') {
- color = [ch1, ch2, ch3, 'rg'].join(' ');
- } else {
- color = [f2(ch1 / 255), f2(ch2 / 255), f2(ch3 / 255), 'rg'].join(' ');
- }
- } else {
- // CMYK
- if (typeof ch1 === 'string') {
- color = [ch1, ch2, ch3, ch4, 'k'].join(' ');
- } else {
- color = [f2(ch1), f2(ch2), f2(ch3), f2(ch4), 'k'].join(' ');
- }
- }
-
- out(color);
- return this;
- };
-
- /**
- * Sets the text color for upcoming elements.
- * If only one, first argument is given,
- * treats the value as gray-scale color value.
- *
- * @param {Number} r Red channel color value in range 0-255 or {String} r color value in hexadecimal, example: '#FFFFFF'
- * @param {Number} g Green channel color value in range 0-255
- * @param {Number} b Blue channel color value in range 0-255
- * @function
- * @returns {jsPDF}
- * @methodOf jsPDF#
- * @name setTextColor
- */
- API.setTextColor = function(r, g, b) {
- if ((typeof r === 'string') && /^#[0-9A-Fa-f]{6}$/.test(r)) {
- var hex = parseInt(r.substr(1), 16);
- r = (hex >> 16) & 255;
- g = (hex >> 8) & 255;
- b = (hex & 255);
- }
-
- if ((r === 0 && g === 0 && b === 0) || (typeof g === 'undefined')) {
- textColor = f3(r / 255) + ' g';
- } else {
- textColor = [f3(r / 255), f3(g / 255), f3(b / 255), 'rg'].join(' ');
- }
- return this;
- };
-
- /**
- * Is an Object providing a mapping from human-readable to
- * integer flag values designating the varieties of line cap
- * and join styles.
- *
- * @returns {Object}
- * @fieldOf jsPDF#
- * @name CapJoinStyles
- */
- API.CapJoinStyles = {
- 0 : 0,
- 'butt' : 0,
- 'but' : 0,
- 'miter' : 0,
- 1 : 1,
- 'round' : 1,
- 'rounded' : 1,
- 'circle' : 1,
- 2 : 2,
- 'projecting' : 2,
- 'project' : 2,
- 'square' : 2,
- 'bevel' : 2
- };
-
- /**
- * Sets the line cap styles
- * See {jsPDF.CapJoinStyles} for variants
- *
- * @param {String|Number} style A string or number identifying the type of line cap
- * @function
- * @returns {jsPDF}
- * @methodOf jsPDF#
- * @name setLineCap
- */
- API.setLineCap = function(style) {
- var id = this.CapJoinStyles[style];
- if (id === undefined) {
- throw new Error("Line cap style of '" + style + "' is not recognized. See or extend .CapJoinStyles property for valid styles");
- }
- lineCapID = id;
- out(id + ' J');
-
- return this;
- };
-
- /**
- * Sets the line join styles
- * See {jsPDF.CapJoinStyles} for variants
- *
- * @param {String|Number} style A string or number identifying the type of line join
- * @function
- * @returns {jsPDF}
- * @methodOf jsPDF#
- * @name setLineJoin
- */
- API.setLineJoin = function(style) {
- var id = this.CapJoinStyles[style];
- if (id === undefined) {
- throw new Error("Line join style of '" + style + "' is not recognized. See or extend .CapJoinStyles property for valid styles");
- }
- lineJoinID = id;
- out(id + ' j');
-
- return this;
- };
-
- // Output is both an internal (for plugins) and external function
- API.output = output;
-
- /**
- * Saves as PDF document. An alias of jsPDF.output('save', 'filename.pdf')
- * @param {String} filename The filename including extension.
- *
- * @function
- * @returns {jsPDF}
- * @methodOf jsPDF#
- * @name save
- */
- API.save = function(filename) {
- API.output('save', filename);
- };
-
- // applying plugins (more methods) ON TOP of built-in API.
- // this is intentional as we allow plugins to override
- // built-ins
- for (var plugin in jsPDF.API) {
- if (jsPDF.API.hasOwnProperty(plugin)) {
- if (plugin === 'events' && jsPDF.API.events.length) {
- (function(events, newEvents) {
-
- // jsPDF.API.events is a JS Array of Arrays
- // where each Array is a pair of event name, handler
- // Events were added by plugins to the jsPDF instantiator.
- // These are always added to the new instance and some ran
- // during instantiation.
- var eventname,handler_and_args,i;
-
- for (i = newEvents.length - 1; i !== -1; i--) {
- // subscribe takes 3 args: 'topic', function, runonce_flag
- // if undefined, runonce is false.
- // users can attach callback directly,
- // or they can attach an array with [callback, runonce_flag]
- // that's what the "apply" magic is for below.
- eventname = newEvents[i][0];
- handler_and_args = newEvents[i][1];
- events.subscribe.apply(
- events,
- [eventname].concat(
- typeof handler_and_args === 'function' ?
- [handler_and_args] : handler_and_args));
- }
- }(events, jsPDF.API.events));
- } else {
- API[plugin] = jsPDF.API[plugin];
- }
- }
- }
-
- //////////////////////////////////////////////////////
- // continuing initialization of jsPDF Document object
- //////////////////////////////////////////////////////
- // Add the first page automatically
- addFonts();
- activeFontKey = 'F1';
- _addPage(format, orientation);
-
- events.publish('initialized');
- return API;
- }
-
- /**
- * jsPDF.API is a STATIC property of jsPDF class.
- * jsPDF.API is an object you can add methods and properties to.
- * The methods / properties you add will show up in new jsPDF objects.
- *
- * One property is prepopulated. It is the 'events' Object. Plugin authors can add topics,
- * callbacks to this object. These will be reassigned to all new instances of jsPDF.
- * Examples:
- * jsPDF.API.events['initialized'] = function(){ 'this' is API object }
- * jsPDF.API.events['addFont'] = function(added_font_object){ 'this' is API object }
- *
- * @static
- * @public
- * @memberOf jsPDF
- * @name API
- *
- * @example
- * jsPDF.API.mymethod = function(){
- * // 'this' will be ref to internal API object. see jsPDF source
- * // , so you can refer to built-in methods like so:
- * // this.line(....)
- * // this.text(....)
- * }
- * var pdfdoc = new jsPDF()
- * pdfdoc.mymethod() // <- !!!!!!
- */
- jsPDF.API = {events:[]};
- jsPDF.version = "1.0.0-trunk";
-
- if (typeof define === 'function' && define.amd) {
- define('jsPDF', function() {
- return jsPDF;
- });
- } else {
- global.jsPDF = jsPDF;
- }
- return jsPDF;
-}(typeof self !== "undefined" && self || typeof window !== "undefined" && window || this));
\ No newline at end of file
+!function(t,e){e["true"]=t;var n=function(t){"use strict";function e(e){var n={};this.subscribe=function(t,e,r){if("function"!=typeof e)return!1;n.hasOwnProperty(t)||(n[t]={});var s=Math.random().toString(35);return n[t][s]=[e,!!r],s},this.unsubscribe=function(t){for(var e in n)if(n[e][t])return delete n[e][t],!0;return!1},this.publish=function(r){if(n.hasOwnProperty(r)){var s=Array.prototype.slice.call(arguments,1),i=[];for(var o in n[r]){var a=n[r][o];try{a[0].apply(e,s)}catch(u){t.console&&console.error("jsPDF PubSub Error",u.message,u)}a[1]&&i.push(o)}i.length&&i.forEach(this.unsubscribe)}}}function n(a,u,c,l){var f={};"object"==typeof a&&(f=a,a=f.orientation,u=f.unit||u,c=f.format||c,l=f.compress||f.compressPdf||l),u=u||"mm",c=c||"a4",a=(""+(a||"P")).toLowerCase();var d,h,p,m,w,g,y,v,b,q=((""+c).toLowerCase(),!!l&&"function"==typeof Uint8Array),x=f.textColor||"0 g",k=f.drawColor||"0 G",_=f.fontSize||16,A=f.lineHeight||1.15,C=f.lineWidth||.200025,S=2,E=!1,z=[],T={},I={},B=0,O=[],P={},R=[],F=0,D=0,U=0,N={title:"",subject:"",author:"",keywords:"",creator:""},L={},j=new e(L),M=function(t){return t.toFixed(2)},H=function(t){return t.toFixed(3)},G=function(t){return("0"+parseInt(t)).slice(-2)},W=function(t){E?O[m].push(t):(U+=t.length+1,R.push(t))},V=function(){return S++,z[S]=U,W(S+" 0 obj"),S},J=function(t){W("stream"),W(t),W("endstream")},X=function(){var e,r,i,o,a,u,c,l,f;for(c=t.adler32cs||n.adler32cs,q&&"undefined"==typeof c&&(q=!1),e=1;B>=e;e++){if(V(),l=(w=P[e].width)*h,f=(g=P[e].height)*h,W("<>"),W("endobj"),r=O[e].join("\n"),V(),q){for(i=[],o=r.length;o--;)i[o]=r.charCodeAt(o);u=c.from(r),a=new s(6),a.append(new Uint8Array(i)),r=a.flush(),i=new Uint8Array(r.length+6),i.set(new Uint8Array([120,156])),i.set(r,2),i.set(new Uint8Array([255&u,u>>8&255,u>>16&255,u>>24&255]),r.length+2),r=String.fromCharCode.apply(null,i),W("<>")}else W("<>");J(r),W("endobj")}z[1]=U,W("1 0 obj"),W("<o;o++)d+=3+2*o+" 0 R ";W(d+"]"),W("/Count "+B),W(">>"),W("endobj")},Y=function(t){t.objectNumber=V(),W("<>"),W("endobj")},K=function(){for(var t in T)T.hasOwnProperty(t)&&Y(T[t])},Q=function(){j.publish("putXobjectDict")},$=function(){W("/ProcSet [/PDF /Text /ImageB /ImageC /ImageI]"),W("/Font <<");for(var t in T)T.hasOwnProperty(t)&&W("/"+t+" "+T[t].objectNumber+" 0 R");W(">>"),W("/XObject <<"),Q(),W(">>")},Z=function(){K(),j.publish("putResources"),z[2]=U,W("2 0 obj"),W("<<"),$(),W(">>"),W("endobj"),j.publish("postPutResources")},te=function(t,e,n){I.hasOwnProperty(e)||(I[e]={}),I[e][n]=t},ee=function(t,e,n,r){var s="F"+(Object.keys(T).length+1).toString(10),i=T[s]={id:s,PostScriptName:t,fontName:e,fontStyle:n,encoding:r,metadata:{}};return te(s,e,n),j.publish("addFont",i),s},ne=function(){for(var t="helvetica",e="times",n="courier",r="normal",s="bold",i="italic",o="bolditalic",a="StandardEncoding",u=[["Helvetica",t,r],["Helvetica-Bold",t,s],["Helvetica-Oblique",t,i],["Helvetica-BoldOblique",t,o],["Courier",n,r],["Courier-Bold",n,s],["Courier-Oblique",n,i],["Courier-BoldOblique",n,o],["Times-Roman",e,r],["Times-Bold",e,s],["Times-Italic",e,i],["Times-BoldItalic",e,o]],c=0,l=u.length;l>c;c++){var f=ee(u[c][0],u[c][1],u[c][2],a),d=u[c][0].split("-");te(f,d[0],d[1]||"")}j.publish("addFonts",{fonts:T,dictionary:I})},re=function(e){return e.foo=function(){try{return e.apply(this,arguments)}catch(n){var r=n.stack||"";~r.indexOf(" at ")&&(r=r.split(" at ")[1]);var s="Error in function "+r.split("\n")[0].split("<")[0]+": "+n.message;if(!t.console)throw new Error(s);t.console.error(s,n),t.alert&&alert(s)}},e.foo.bar=e,e.foo},se=function(t,e){var n,r,s,i,o,a,u,c,l;if(e=e||{},s=e.sourceEncoding||"Unicode",o=e.outputEncoding,(e.autoencode||o)&&T[d].metadata&&T[d].metadata[s]&&T[d].metadata[s].encoding&&(i=T[d].metadata[s].encoding,!o&&T[d].encoding&&(o=T[d].encoding),!o&&i.codePages&&(o=i.codePages[0]),"string"==typeof o&&(o=i[o]),o)){for(u=!1,a=[],n=0,r=t.length;r>n;n++)c=o[t.charCodeAt(n)],a.push(c?String.fromCharCode(c):t[n]),a[n].charCodeAt(0)>>8&&(u=!0);t=a.join("")}for(n=t.length;void 0===u&&0!==n;)t.charCodeAt(n-1)>>8&&(u=!0),n--;if(!u)return t;for(a=e.noBOM?[]:[254,255],n=0,r=t.length;r>n;n++){if(c=t.charCodeAt(n),l=c>>8,l>>8)throw new Error("Character at position "+n+" of string '"+t+"' exceeds 16bits. Cannot be encoded into UCS-2 BE");a.push(l),a.push(c-(l<<8))}return String.fromCharCode.apply(void 0,a)},ie=function(t,e){return se(t,e).replace(/\\/g,"\\\\").replace(/\(/g,"\\(").replace(/\)/g,"\\)")},oe=function(){W("/Producer (jsPDF "+n.version+")");for(var t in N)N.hasOwnProperty(t)&&N[t]&&W("/"+t.substr(0,1).toUpperCase()+t.substr(1)+" ("+ie(N[t])+")");var e=new Date,r=e.getTimezoneOffset(),s=0>r?"+":"-",i=Math.floor(Math.abs(r/60)),o=Math.abs(r%60),a=[s,G(i),"'",G(o),"'"].join("");W(["/CreationDate (D:",e.getFullYear(),G(e.getMonth()+1),G(e.getDate()),G(e.getHours()),G(e.getMinutes()),G(e.getSeconds()),a,")"].join(""))},ae=function(){switch(W("/Type /Catalog"),W("/Pages 1 0 R"),v||(v="fullwidth"),v){case"fullwidth":W("/OpenAction [3 0 R /FitH null]");break;case"fullheight":W("/OpenAction [3 0 R /FitV null]");break;case"fullpage":W("/OpenAction [3 0 R /Fit]");break;case"original":W("/OpenAction [3 0 R /XYZ null null 1]");break;default:var t=""+v;"%"===t.substr(t.length-1)&&(v=parseInt(v)/100),"number"==typeof v&&W("/OpenAction [3 0 R /XYZ null null "+M(v)+"]")}switch(b||(b="continuous"),b){case"continuous":W("/PageLayout /OneColumn");break;case"single":W("/PageLayout /SinglePage");break;case"two":case"twoleft":W("/PageLayout /TwoColumnLeft");break;case"tworight":W("/PageLayout /TwoColumnRight")}y&&W("/PageMode /"+y),j.publish("putCatalog")},ue=function(){W("/Size "+(S+1)),W("/Root "+S+" 0 R"),W("/Info "+(S-1)+" 0 R")},ce=function(t,e){var n="string"==typeof e&&e.toLowerCase();if("string"==typeof t){var r=t.toLowerCase();o.hasOwnProperty(r)&&(t=o[r][0]/h,e=o[r][1]/h)}if(Array.isArray(t)&&(e=t[1],t=t[0]),n){switch(n.substr(0,1)){case"l":e>t&&(n="s");break;case"p":t>e&&(n="s")}"s"===n&&(p=t,t=e,e=p)}E=!0,O[++B]=[],P[B]={width:Number(t)||w,height:Number(e)||g},fe(B)},le=function(){ce.apply(this,arguments),W(M(C*h)+" w"),W(k),0!==F&&W(F+" J"),0!==D&&W(D+" j"),j.publish("addPage",{pageNumber:B})},fe=function(t){t>0&&B>=t&&(m=t,w=P[t].width,g=P[t].height)},de=function(t,e){var n;t=void 0!==t?t:T[d].fontName,e=void 0!==e?e:T[d].fontStyle;try{n=I[t][e]}catch(r){}if(!n)throw new Error("Unable to look up font label for font '"+t+"', '"+e+"'. Refer to getFontList() for available fonts.");return n},he=function(){E=!1,S=2,R=[],z=[],W("%PDF-"+i),X(),Z(),V(),W("<<"),oe(),W(">>"),W("endobj"),V(),W("<<"),ae(),W(">>"),W("endobj");var t,e=U,n="0000000000";for(W("xref"),W("0 "+(S+1)),W(n+" 65535 f "),t=1;S>=t;t++)W((n+z[t]).slice(-10)+" 00000 n ");return W("trailer"),W("<<"),ue(),W(">>"),W("startxref"),W(e),W("%%EOF"),E=!0,R.join("\n")},pe=function(t){var e="S";return"F"===t?e="f":"FD"===t||"DF"===t?e="B":("f"===t||"f*"===t||"B"===t||"B*"===t)&&(e=t),e},me=function(){for(var t=he(),e=t.length,n=new ArrayBuffer(e),r=new Uint8Array(n);e--;)r[e]=t.charCodeAt(e);return n},we=function(){return new Blob([me()],{type:"application/pdf"})},ge=re(function(e,n){var s="dataur"===(""+e).substr(0,6)?"data:application/pdf;base64,"+btoa(he()):0;switch(e){case void 0:return he();case"save":if(navigator.getUserMedia&&(void 0===t.URL||void 0===t.URL.createObjectURL))return L.output("dataurlnewwindow");r(we(),n),"function"==typeof r.unload&&t.setTimeout&&setTimeout(r.unload,911);break;case"arraybuffer":return me();case"blob":return we();case"bloburi":case"bloburl":return t.URL&&t.URL.createObjectURL(we())||void 0;case"datauristring":case"dataurlstring":return s;case"dataurlnewwindow":var i=t.open(s);if(i||"undefined"==typeof safari)return i;case"datauri":case"dataurl":return t.document.location.href=s;default:throw new Error('Output type "'+e+'" is not supported.')}});switch(u){case"pt":h=1;break;case"mm":h=72/25.4;break;case"cm":h=72/2.54;break;case"in":h=72;break;case"px":h=96/72;break;case"pc":h=12;break;case"em":h=12;break;case"ex":h=6;break;default:throw"Invalid unit: "+u}L.internal={pdfEscape:ie,getStyle:pe,getFont:function(){return T[de.apply(L,arguments)]},getFontSize:function(){return _},getLineHeight:function(){return _*A},write:function(t){W(1===arguments.length?t:Array.prototype.join.call(arguments," "))},getCoordinateString:function(t){return M(t*h)},getVerticalCoordinateString:function(t){return M((g-t)*h)},collections:{},newObject:V,putStream:J,events:j,scaleFactor:h,pageSize:{get width(){return w},get height(){return g}},output:function(t,e){return ge(t,e)},getNumberOfPages:function(){return O.length-1},pages:O},L.addPage=function(){return le.apply(this,arguments),this},L.setPage=function(){return fe.apply(this,arguments),this},L.setDisplayMode=function(t,e,n){return v=t,b=e,y=n,this},L.text=function(t,e,n,r,s){function i(t){return t=t.split(" ").join(Array(f.TabLen||9).join(" ")),ie(t,r)}"number"==typeof t&&(p=n,n=e,e=t,t=p),"string"==typeof t&&t.match(/[\n\r]/)&&(t=t.split(/\r\n|\r|\n/g)),"number"==typeof r&&(s=r,r=null);var o,a="",u="Td";if(s){s*=Math.PI/180;var c=Math.cos(s),l=Math.sin(s);a=[M(c),M(l),M(-1*l),M(c),""].join(" "),u="Tm"}if(r=r||{},"noBOM"in r||(r.noBOM=!0),"autoencode"in r||(r.autoencode=!0),"string"==typeof t)t=i(t);else{if(!(t instanceof Array))throw new Error('Type of text must be string or Array. "'+t+'" is not recognized.');for(var m=t.concat(),w=[],y=m.length;y--;)w.push(i(m.shift()));var v=Math.ceil((g-n)*h/(_*A));v>=0&&vs;s++,e+=r)this.text(t[s],e,n)},L.line=function(t,e,n,r){return this.lines([[n-t,r-e]],t,e)},L.clip=function(){W("W"),W("S")},L.lines=function(t,e,n,r,s,i){var o,a,u,c,l,f,d,m,w,y,v;for("number"==typeof t&&(p=n,n=e,e=t,t=p),r=r||[1,1],W(H(e*h)+" "+H((g-n)*h)+" m "),o=r[0],a=r[1],c=t.length,y=e,v=n,u=0;c>u;u++)l=t[u],2===l.length?(y=l[0]*o+y,v=l[1]*a+v,W(H(y*h)+" "+H((g-v)*h)+" l")):(f=l[0]*o+y,d=l[1]*a+v,m=l[2]*o+y,w=l[3]*a+v,y=l[4]*o+y,v=l[5]*a+v,W(H(f*h)+" "+H((g-d)*h)+" "+H(m*h)+" "+H((g-w)*h)+" "+H(y*h)+" "+H((g-v)*h)+" c"));return i&&W(" h"),null!==s&&W(pe(s)),this},L.rect=function(t,e,n,r,s){pe(s);return W([M(t*h),M((g-e)*h),M(n*h),M(-r*h),"re"].join(" ")),null!==s&&W(pe(s)),this},L.triangle=function(t,e,n,r,s,i,o){return this.lines([[n-t,r-e],[s-n,i-r],[t-s,e-i]],t,e,[1,1],o,!0),this},L.roundedRect=function(t,e,n,r,s,i,o){var a=4/3*(Math.SQRT2-1);return this.lines([[n-2*s,0],[s*a,0,s,i-i*a,s,i],[0,r-2*i],[0,i*a,-(s*a),i,-s,i],[-n+2*s,0],[-(s*a),0,-s,-(i*a),-s,-i],[0,-r+2*i],[0,-(i*a),s*a,-i,s,-i]],t+s,e,[1,1],o),this},L.ellipse=function(t,e,n,r,s){var i=4/3*(Math.SQRT2-1)*n,o=4/3*(Math.SQRT2-1)*r;return W([M((t+n)*h),M((g-e)*h),"m",M((t+n)*h),M((g-(e-o))*h),M((t+i)*h),M((g-(e-r))*h),M(t*h),M((g-(e-r))*h),"c"].join(" ")),W([M((t-i)*h),M((g-(e-r))*h),M((t-n)*h),M((g-(e-o))*h),M((t-n)*h),M((g-e)*h),"c"].join(" ")),W([M((t-n)*h),M((g-(e+o))*h),M((t-i)*h),M((g-(e+r))*h),M(t*h),M((g-(e+r))*h),"c"].join(" ")),W([M((t+i)*h),M((g-(e+r))*h),M((t+n)*h),M((g-(e+o))*h),M((t+n)*h),M((g-e)*h),"c"].join(" ")),null!==s&&W(pe(s)),this},L.circle=function(t,e,n,r){return this.ellipse(t,e,n,n,r)},L.setProperties=function(t){for(var e in N)N.hasOwnProperty(e)&&t[e]&&(N[e]=t[e]);return this},L.setFontSize=function(t){return _=t,this},L.setFont=function(t,e){return d=de(t,e),this},L.setFontStyle=L.setFontType=function(t){return d=de(void 0,t),this},L.getFontList=function(){var t,e,n,r={};for(t in I)if(I.hasOwnProperty(t)){r[t]=n=[];for(e in I[t])I[t].hasOwnProperty(e)&&n.push(e)}return r},L.setLineWidth=function(t){return W((t*h).toFixed(2)+" w"),this},L.setDrawColor=function(t,e,n,r){var s;return s=void 0===e||void 0===r&&t===e===n?"string"==typeof t?t+" G":M(t/255)+" G":void 0===r?"string"==typeof t?[t,e,n,"RG"].join(" "):[M(t/255),M(e/255),M(n/255),"RG"].join(" "):"string"==typeof t?[t,e,n,r,"K"].join(" "):[M(t),M(e),M(n),M(r),"K"].join(" "),W(s),this},L.setFillColor=function(t,e,n,r){var s;return s=void 0===e||void 0===r&&t===e===n?"string"==typeof t?t+" g":M(t/255)+" g":void 0===r?"string"==typeof t?[t,e,n,"rg"].join(" "):[M(t/255),M(e/255),M(n/255),"rg"].join(" "):"string"==typeof t?[t,e,n,r,"k"].join(" "):[M(t),M(e),M(n),M(r),"k"].join(" "),W(s),this},L.setTextColor=function(t,e,n){if("string"==typeof t&&/^#[0-9A-Fa-f]{6}$/.test(t)){var r=parseInt(t.substr(1),16);t=r>>16&255,e=r>>8&255,n=255&r}return x=0===t&&0===e&&0===n||"undefined"==typeof e?H(t/255)+" g":[H(t/255),H(e/255),H(n/255),"rg"].join(" "),this},L.CapJoinStyles={0:0,butt:0,but:0,miter:0,1:1,round:1,rounded:1,circle:1,2:2,projecting:2,project:2,square:2,bevel:2},L.setLineCap=function(t){var e=this.CapJoinStyles[t];if(void 0===e)throw new Error("Line cap style of '"+t+"' is not recognized. See or extend .CapJoinStyles property for valid styles");return F=e,W(e+" J"),this},L.setLineJoin=function(t){var e=this.CapJoinStyles[t];if(void 0===e)throw new Error("Line join style of '"+t+"' is not recognized. See or extend .CapJoinStyles property for valid styles");return D=e,W(e+" j"),this},L.output=ge,L.save=function(t){L.output("save",t)};for(var ye in n.API)n.API.hasOwnProperty(ye)&&("events"===ye&&n.API.events.length?!function(t,e){var n,r,s;for(s=e.length-1;-1!==s;s--)n=e[s][0],r=e[s][1],t.subscribe.apply(t,[n].concat("function"==typeof r?[r]:r))}(j,n.API.events):L[ye]=n.API[ye]);return ne(),d="F1",le(c,a),j.publish("initialized"),L}var i="1.3",o={a0:[2383.94,3370.39],a1:[1683.78,2383.94],a2:[1190.55,1683.78],a3:[841.89,1190.55],a4:[595.28,841.89],a5:[419.53,595.28],a6:[297.64,419.53],a7:[209.76,297.64],a8:[147.4,209.76],a9:[104.88,147.4],a10:[73.7,104.88],b0:[2834.65,4008.19],b1:[2004.09,2834.65],b2:[1417.32,2004.09],b3:[1000.63,1417.32],b4:[708.66,1000.63],b5:[498.9,708.66],b6:[354.33,498.9],b7:[249.45,354.33],b8:[175.75,249.45],b9:[124.72,175.75],b10:[87.87,124.72],c0:[2599.37,3676.54],c1:[1836.85,2599.37],c2:[1298.27,1836.85],c3:[918.43,1298.27],c4:[649.13,918.43],c5:[459.21,649.13],c6:[323.15,459.21],c7:[229.61,323.15],c8:[161.57,229.61],c9:[113.39,161.57],c10:[79.37,113.39],dl:[311.81,623.62],letter:[612,792],"government-letter":[576,756],legal:[612,1008],"junior-legal":[576,360],ledger:[1224,792],tabloid:[792,1224],"credit-card":[153,243]};return n.API={events:[]},n.version="1.0.272-git 2014-09-29T15:09:diegocr","function"==typeof define&&define.amd?define("jsPDF",function(){return n}):t.jsPDF=n,n}("undefined"!=typeof self&&self||"undefined"!=typeof window&&window||this);!function(t){"use strict";t.addHTML=function(t,e,n,r,s){if("undefined"==typeof html2canvas&&"undefined"==typeof rasterizeHTML)throw new Error("You need either https://github.com/niklasvh/html2canvas or https://github.com/cburgmer/rasterizeHTML.js");"number"!=typeof e&&(r=e,s=n),"function"==typeof r&&(s=r,r=null);var i=this.internal,o=i.scaleFactor,a=i.pageSize.width,u=i.pageSize.height;if(r=r||{},r.onrendered=function(t){e=parseInt(e)||0,n=parseInt(n)||0;var i=r.dim||{},c=i.h||0,l=i.w||Math.min(a,t.width/o)-e,f="JPEG";if(r.format&&(f=r.format),t.height>u&&r.pagesplit){var d=function(){for(var r=0;;){var i=document.createElement("canvas");i.width=Math.min(a*o,t.width),i.height=Math.min(u*o,t.height-r);var c=i.getContext("2d");c.drawImage(t,0,r,t.width,i.height,0,0,i.width,i.height);var d=[i,e,r?0:n,i.width/o,i.height/o,f,null,"SLOW"];if(this.addImage.apply(this,d),r+=i.height,r>=t.height)break;this.addPage()}s(l,r,null,d)}.bind(this);if("CANVAS"===t.nodeName){var h=new Image;h.onload=d,h.src=t.toDataURL("image/png"),t=h}else d()}else{var p=Math.random().toString(35),m=[t,e,n,l,c,f,p,"SLOW"];this.addImage.apply(this,m),s(l,c,p,m)}}.bind(this),"undefined"!=typeof html2canvas&&!r.rstz)return html2canvas(t,r);if("undefined"!=typeof rasterizeHTML){var c="drawDocument";return"string"==typeof t&&(c=/^http/.test(t)?"drawURL":"drawHTML"),r.width=r.width||a*o,rasterizeHTML[c](t,void 0,r).then(function(t){r.onrendered(t.image)},function(t){s(null,t)})}return null}}(n.API),function(t){"use strict";var e="addImage_",n=["jpeg","jpg","png"],r=function(t){var e=this.internal.newObject(),n=this.internal.write,s=this.internal.putStream;if(t.n=e,n("<<<"+t.dp+">>"),"trns"in t&&t.trns.constructor==Array){for(var i="",o=0,a=t.trns.length;a>o;o++)i+=t.trns[o]+" "+t.trns[o]+" ";n("/Mask ["+i+"]")}if("smask"in t&&n("/SMask "+(e+1)+" 0 R"),n("/Length "+t.data.length+">>"),s(t.data),n("endobj"),"smask"in t){var u="/Predictor 15 /Colors 1 /BitsPerComponent "+t.bpc+" /Columns "+t.w,c={w:t.w,h:t.h,cs:"DeviceGray",bpc:t.bpc,dp:u,data:t.smask};"f"in t&&(c.f=t.f),r.call(this,c)}t.cs===this.color_spaces.INDEXED&&(this.internal.newObject(),n("<< /Length "+t.pal.length+">>"),s(this.arrayBufferToBinaryString(new Uint8Array(t.pal))),n("endobj"))},s=function(){var t=this.internal.collections[e+"images"];for(var n in t)r.call(this,t[n])},i=function(){var t,n=this.internal.collections[e+"images"],r=this.internal.write;for(var s in n)t=n[s],r("/I"+t.i,t.n,"0","R")},o=function(e){return e&&"string"==typeof e&&(e=e.toUpperCase()),e in t.image_compression?e:t.image_compression.NONE},a=function(){var t=this.internal.collections[e+"images"];return t||(this.internal.collections[e+"images"]=t={},this.internal.events.subscribe("putResources",s),this.internal.events.subscribe("putXobjectDict",i)),t},u=function(t){var e=0;return t&&(e=Object.keys?Object.keys(t).length:function(t){var e=0;for(var n in t)t.hasOwnProperty(n)&&e++;return e}(t)),e},c=function(t){return"undefined"==typeof t||null===t},l=function(e){return"string"==typeof e&&t.sHashCode(e)},f=function(t){return-1===n.indexOf(t)},d=function(e){return"function"!=typeof t["process"+e.toUpperCase()]},h=function(t){return"object"==typeof t&&1===t.nodeType},p=function(t,e,n){if("IMG"===t.nodeName&&t.hasAttribute("src")){var r=""+t.getAttribute("src");if(!n&&0===r.indexOf("data:image/"))return r;!e&&/\.png(?:[?#].*)?$/i.test(r)&&(e="png")}if("CANVAS"===t.nodeName)var s=t;else{var s=document.createElement("canvas");s.width=t.clientWidth||t.width,s.height=t.clientHeight||t.height;var i=s.getContext("2d");if(!i)throw"addImage requires canvas to be supported by browser.";if(n){var o,a,u,c,l,f,d,h,p=Math.PI/180;"object"==typeof n&&(o=n.x,a=n.y,u=n.bg,n=n.angle),h=n*p,c=Math.abs(Math.cos(h)),l=Math.abs(Math.sin(h)),f=s.width,d=s.height,s.width=d*l+f*c,s.height=d*c+f*l,isNaN(o)&&(o=s.width/2),isNaN(a)&&(a=s.height/2),i.clearRect(0,0,s.width,s.height),i.fillStyle=u||"white",i.fillRect(0,0,s.width,s.height),i.save(),i.translate(o,a),i.rotate(h),i.drawImage(t,-(f/2),-(d/2)),i.rotate(-h),i.translate(-o,-a),i.restore()}else i.drawImage(t,0,0,s.width,s.height)}return s.toDataURL("png"==(""+e).toLowerCase()?"image/png":"image/jpeg")},m=function(t,e){var n;if(e)for(var r in e)if(t===e[r].alias){n=e[r];break}return n},w=function(t,e,n){return t||e||(t=-96,e=-96),0>t&&(t=-1*n.w*72/t/this.internal.scaleFactor),0>e&&(e=-1*n.h*72/e/this.internal.scaleFactor),0===t&&(t=e*n.w/n.h),0===e&&(e=t*n.h/n.w),[t,e]},g=function(t,e,n,r,s,i,o){var a=w.call(this,n,r,s),u=this.internal.getCoordinateString,c=this.internal.getVerticalCoordinateString;n=a[0],r=a[1],o[i]=s,this.internal.write("q",u(n),"0 0",u(r),u(t),c(e+r),"cm /I"+s.i,"Do Q")};t.color_spaces={DEVICE_RGB:"DeviceRGB",DEVICE_GRAY:"DeviceGray",DEVICE_CMYK:"DeviceCMYK",CAL_GREY:"CalGray",CAL_RGB:"CalRGB",LAB:"Lab",ICC_BASED:"ICCBased",INDEXED:"Indexed",PATTERN:"Pattern",SEPERATION:"Seperation",DEVICE_N:"DeviceN"},t.decode={DCT_DECODE:"DCTDecode",FLATE_DECODE:"FlateDecode",LZW_DECODE:"LZWDecode",JPX_DECODE:"JPXDecode",JBIG2_DECODE:"JBIG2Decode",ASCII85_DECODE:"ASCII85Decode",ASCII_HEX_DECODE:"ASCIIHexDecode",RUN_LENGTH_DECODE:"RunLengthDecode",CCITT_FAX_DECODE:"CCITTFaxDecode"},t.image_compression={NONE:"NONE",FAST:"FAST",MEDIUM:"MEDIUM",SLOW:"SLOW"},t.sHashCode=function(t){return Array.prototype.reduce&&t.split("").reduce(function(t,e){return t=(t<<5)-t+e.charCodeAt(0),t&t},0)},t.isString=function(t){return"string"==typeof t},t.extractInfoFromBase64DataURI=function(t){return/^data:([\w]+?\/([\w]+?));base64,(.+?)$/g.exec(t)},t.supportsArrayBuffer=function(){return"undefined"!=typeof ArrayBuffer&&"undefined"!=typeof Uint8Array},t.isArrayBuffer=function(t){return this.supportsArrayBuffer()?t instanceof ArrayBuffer:!1},t.isArrayBufferView=function(t){return this.supportsArrayBuffer()?"undefined"==typeof Uint32Array?!1:t instanceof Int8Array||t instanceof Uint8Array||"undefined"!=typeof Uint8ClampedArray&&t instanceof Uint8ClampedArray||t instanceof Int16Array||t instanceof Uint16Array||t instanceof Int32Array||t instanceof Uint32Array||t instanceof Float32Array||t instanceof Float64Array:!1},t.binaryStringToUint8Array=function(t){for(var e=t.length,n=new Uint8Array(e),r=0;e>r;r++)n[r]=t.charCodeAt(r);return n},t.arrayBufferToBinaryString=function(t){this.isArrayBuffer(t)&&(t=new Uint8Array(t));for(var e="",n=t.byteLength,r=0;n>r;r++)e+=String.fromCharCode(t[r]);return e},t.arrayBufferToBase64=function(t){for(var e,n,r,s,i,o="",a="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",u=new Uint8Array(t),c=u.byteLength,l=c%3,f=c-l,d=0;f>d;d+=3)i=u[d]<<16|u[d+1]<<8|u[d+2],e=(16515072&i)>>18,n=(258048&i)>>12,r=(4032&i)>>6,s=63&i,o+=a[e]+a[n]+a[r]+a[s];return 1==l?(i=u[f],e=(252&i)>>2,n=(3&i)<<4,o+=a[e]+a[n]+"=="):2==l&&(i=u[f]<<8|u[f+1],e=(64512&i)>>10,n=(1008&i)>>4,r=(15&i)<<2,o+=a[e]+a[n]+a[r]+"="),o},t.createImageInfo=function(t,e,n,r,s,i,o,a,u,c,l,f){var d={alias:a,w:e,h:n,cs:r,bpc:s,i:o,data:t};return i&&(d.f=i),u&&(d.dp=u),c&&(d.trns=c),l&&(d.pal=l),f&&(d.smask=f),d},t.addImage=function(t,e,r,s,i,w,y,v,b){if("string"!=typeof e){var q=w;w=i,i=s,s=r,r=e,e=q}if("object"==typeof t&&!h(t)&&"imageData"in t){var x=t;t=x.imageData,e=x.format||e,r=x.x||r||0,s=x.y||s||0,i=x.w||i,w=x.h||w,y=x.alias||y,v=x.compression||v,b=x.rotation||x.angle||b}if(isNaN(r)||isNaN(s))throw console.error("jsPDF.addImage: Invalid coordinates",arguments),new Error("Invalid coordinates passed to jsPDF.addImage");var k,_=a.call(this);if(!(k=m(t,_))){var A;if(h(t)&&(t=p(t,e,b)),c(y)&&(y=l(t)),!(k=m(y,_))){if(this.isString(t)){var C=this.extractInfoFromBase64DataURI(t);C?(e=C[2],t=atob(C[3])):137===t.charCodeAt(0)&&80===t.charCodeAt(1)&&78===t.charCodeAt(2)&&71===t.charCodeAt(3)&&(e="png")}if(e=(e||"JPEG").toLowerCase(),f(e))throw new Error("addImage currently only supports formats "+n+", not '"+e+"'");if(d(e))throw new Error("please ensure that the plugin for '"+e+"' support is added");if(this.supportsArrayBuffer()&&(A=t,t=this.binaryStringToUint8Array(t)),k=this["process"+e.toUpperCase()](t,u(_),y,o(v),A),!k)throw new Error("An unkwown error occurred whilst processing the image")}}return g.call(this,r,s,i,w,k,k.i,_),this};var y=function(t){var e,n,r;if(255===!t.charCodeAt(0)||216===!t.charCodeAt(1)||255===!t.charCodeAt(2)||224===!t.charCodeAt(3)||!t.charCodeAt(6)==="J".charCodeAt(0)||!t.charCodeAt(7)==="F".charCodeAt(0)||!t.charCodeAt(8)==="I".charCodeAt(0)||!t.charCodeAt(9)==="F".charCodeAt(0)||0===!t.charCodeAt(10))throw new Error("getJpegSize requires a binary string jpeg file");for(var s=256*t.charCodeAt(4)+t.charCodeAt(5),i=4,o=t.length;o>i;){if(i+=s,255!==t.charCodeAt(i))throw new Error("getJpegSize could not find the size of the image");if(192===t.charCodeAt(i+1)||193===t.charCodeAt(i+1)||194===t.charCodeAt(i+1)||195===t.charCodeAt(i+1)||196===t.charCodeAt(i+1)||197===t.charCodeAt(i+1)||198===t.charCodeAt(i+1)||199===t.charCodeAt(i+1))return n=256*t.charCodeAt(i+5)+t.charCodeAt(i+6),e=256*t.charCodeAt(i+7)+t.charCodeAt(i+8),r=t.charCodeAt(i+9),[e,n,r];i+=2,s=256*t.charCodeAt(i)+t.charCodeAt(i+1)}},v=function(t){var e=t[0]<<8|t[1];if(65496!==e)throw new Error("Supplied data is not a JPEG");for(var n,r,s,i,o=t.length,a=(t[4]<<8)+t[5],u=4;o>u;){if(u+=a,n=b(t,u),a=(n[2]<<8)+n[3],(192===n[1]||194===n[1])&&255===n[0]&&a>7)return n=b(t,u+5),r=(n[2]<<8)+n[3],s=(n[0]<<8)+n[1],i=n[4],{width:r,height:s,numcomponents:i};u+=2}throw new Error("getJpegSizeFromBytes could not find the size of the image")},b=function(t,e){return t.subarray(e,e+5)};t.processJPEG=function(t,e,n,r,s){var i,o=this.color_spaces.DEVICE_RGB,a=this.decode.DCT_DECODE,u=8;return this.isString(t)?(i=y(t),this.createImageInfo(t,i[0],i[1],1==i[3]?this.color_spaces.DEVICE_GRAY:o,u,a,e,n)):(this.isArrayBuffer(t)&&(t=new Uint8Array(t)),this.isArrayBufferView(t)?(i=v(t),t=s||this.arrayBufferToBinaryString(t),this.createImageInfo(t,i.width,i.height,1==i.numcomponents?this.color_spaces.DEVICE_GRAY:o,u,a,e,n)):null)},t.processJPG=function(){return this.processJPEG.apply(this,arguments)}}(n.API),function(t){"use strict";t.autoPrint=function(){var t;return this.internal.events.subscribe("postPutResources",function(){t=this.internal.newObject(),this.internal.write("<< /S/Named /Type/Action /N/Print >>","endobj")}),this.internal.events.subscribe("putCatalog",function(){this.internal.write("/OpenAction "+t+" 0 R")}),this}}(n.API),function(t){"use strict";var e,n,r,s,i=3,o=13,a={x:void 0,y:void 0,w:void 0,h:void 0,ln:void 0},u=1,c=function(t,e,n,r,s){a={x:t,y:e,w:n,h:r,ln:s}},l=function(){return a},f={left:0,top:0,bottom:0};t.setHeaderFunction=function(t){s=t},t.getTextDimensions=function(t){e=this.internal.getFont().fontName,n=this.table_font_size||this.internal.getFontSize(),r=this.internal.getFont().fontStyle;var s,i,o=19.049976/25.4;return i=document.createElement("font"),i.id="jsPDFCell",i.style.fontStyle=r,i.style.fontName=e,i.style.fontSize=n+"pt",i.textContent=t,document.body.appendChild(i),s={w:(i.offsetWidth+1)*o,h:(i.offsetHeight+1)*o},document.body.removeChild(i),s},t.cellAddPage=function(){var t=this.margins||f;this.addPage(),c(t.left,t.top,void 0,void 0),u+=1},t.cellInitialize=function(){a={x:void 0,y:void 0,w:void 0,h:void 0,ln:void 0},u=1},t.cell=function(t,e,n,r,s,a,u){var d=l();if(void 0!==d.ln)if(d.ln===a)t=d.x+d.w,e=d.y;else{var h=this.margins||f;d.y+d.h+r+o>=this.internal.pageSize.height-h.bottom&&(this.cellAddPage(),this.printHeaders&&this.tableHeaderRow&&this.printHeaderRow(a,!0)),e=l().y+l().h}if(void 0!==s[0])if(this.printingHeaderRow?this.rect(t,e,n,r,"FD"):this.rect(t,e,n,r),"right"===u){if(s instanceof Array)for(var p=0;pn;n+=1)s=t[n],e?-1===e(i,s)&&(i=s):s>i&&(i=s);return i},t.table=function(e,n,r,s,i){if(!r)throw"No data for PDF table";var o,c,l,d,h,p,m,w,g,y,v=[],b=[],q={},x={},k=[],_=[],A=!1,C=!0,S=12,E=f;if(E.width=this.internal.pageSize.width,i&&(i.autoSize===!0&&(A=!0),i.printHeaders===!1&&(C=!1),i.fontSize&&(S=i.fontSize),i.margins&&(E=i.margins)),this.lnMod=0,a={x:void 0,y:void 0,w:void 0,h:void 0,ln:void 0},u=1,this.printHeaders=C,this.margins=E,this.setFontSize(S),this.table_font_size=S,void 0===s||null===s)v=Object.keys(r[0]);else if(s[0]&&"string"!=typeof s[0]){var z=19.049976/25.4;for(c=0,l=s.length;l>c;c+=1)o=s[c],v.push(o.name),b.push(o.prompt),x[o.name]=o.width*z}else v=s;if(A)for(y=function(t){return t[o]},c=0,l=v.length;l>c;c+=1){for(o=v[c],q[o]=r.map(y),k.push(this.getTextDimensions(b[c]||o).w),p=q[o],m=0,d=p.length;d>m;m+=1)h=p[m],k.push(this.getTextDimensions(h).w);x[o]=t.arrayMax(k)}if(C){var T=this.calculateLineHeight(v,x,b.length?b:v);for(c=0,l=v.length;l>c;c+=1)o=v[c],_.push([e,n,x[o],T,String(b.length?b[c]:o)]);this.setTableHeaderRow(_),this.printHeaderRow(1,!1)}for(c=0,l=r.length;l>c;c+=1){var T;for(w=r[c],T=this.calculateLineHeight(v,x,w),m=0,g=v.length;g>m;m+=1)o=v[m],this.cell(e,n,x[o],T,w[o],c+2,o.align)}return this.lastCellPos=a,this.table_x=e,this.table_y=n,this},t.calculateLineHeight=function(t,e,n){for(var r,s=0,o=0;os&&(s=a)}return s},t.setTableHeaderRow=function(t){this.tableHeaderRow=t},t.printHeaderRow=function(t,e){if(!this.tableHeaderRow)throw"Property tableHeaderRow does not exist.";var n,r,i,o;if(this.printingHeaderRow=!0,void 0!==s){var a=s(this,u);c(a[0],a[1],a[2],a[3],-1)}this.setFontStyle("bold");var l=[];for(i=0,o=this.tableHeaderRow.length;o>i;i+=1)this.setFillColor(200,200,200),n=this.tableHeaderRow[i],e&&(n[1]=this.margins&&this.margins.top||0,l.push(n)),r=[].concat(n),this.cell.apply(this,r.concat(t));l.length>0&&this.setTableHeaderRow(l),this.setFontStyle("normal"),this.printingHeaderRow=!1}}(n.API),function(t){var e,n,r,s,i,o,a,u,c,l,f,d,h,p,m,w,g,y,v;e=function(){function t(){}return function(e){return t.prototype=e,new t}}(),c=function(t){var e,n,r,s,i,o,a;for(n=0,r=t.length,e=void 0,s=!1,o=!1;!s&&n!==r;)e=t[n]=t[n].trimLeft(),e&&(s=!0),n++;for(n=r-1;r&&!o&&-1!==n;)e=t[n]=t[n].trimRight(),e&&(o=!0),n--;for(i=/\s+$/g,a=!0,n=0;n!==r;)e=t[n].replace(/\s+/g," "),a&&(e=e.trimLeft()),e&&(a=i.test(e)),t[n]=e,n++;return t},l=function(t,e,n,r){return this.pdf=t,this.x=e,this.y=n,this.settings=r,this.watchFunctions=[],this.init(),this},f=function(t){var e,n,s;for(e=void 0,s=t.split(","),n=s.shift();!e&&n;)e=r[n.trim().toLowerCase()],n=s.shift();return e},d=function(t){t="auto"===t?"0px":t,t.indexOf("em")>-1&&!isNaN(Number(t.replace("em","")))&&(t=18.719*Number(t.replace("em",""))+"px"),t.indexOf("pt")>-1&&!isNaN(Number(t.replace("pt","")))&&(t=1.333*Number(t.replace("pt",""))+"px");var e,n,r;return n=void 0,e=16,(r=h[t])?r:(r={"xx-small":9,"x-small":11,small:13,medium:16,large:19,"x-large":23,"xx-large":28,auto:0}[{css_line_height_string:t}],r!==n?h[t]=r/e:(r=parseFloat(t))?h[t]=r/e:(r=t.match(/([\d\.]+)(px)/),h[t]=3===r.length?parseFloat(r[1])/e:1))},u=function(t){var e,n,r;return r=function(t){var e;return e=function(t){return document.defaultView&&document.defaultView.getComputedStyle?document.defaultView.getComputedStyle(t,null):t.currentStyle?t.currentStyle:t.style}(t),function(t){return t=t.replace(/-\D/g,function(t){return t.charAt(1).toUpperCase()}),e[t]}}(t),e={},n=void 0,e["font-family"]=f(r("font-family"))||"times",e["font-style"]=s[r("font-style")]||"normal",e["text-align"]=TextAlignMap[r("text-align")]||"left",n=i[r("font-weight")]||"normal","bold"===n&&(e["font-style"]="normal"===e["font-style"]?n:n+e["font-style"]),e["font-size"]=d(r("font-size"))||1,e["line-height"]=d(r("line-height"))||1,e.display="inline"===r("display")?"inline":"block",n="block"===e.display,e["margin-top"]=n&&d(r("margin-top"))||0,e["margin-bottom"]=n&&d(r("margin-bottom"))||0,e["padding-top"]=n&&d(r("padding-top"))||0,e["padding-bottom"]=n&&d(r("padding-bottom"))||0,e["margin-left"]=n&&d(r("margin-left"))||0,e["margin-right"]=n&&d(r("margin-right"))||0,e["padding-left"]=n&&d(r("padding-left"))||0,e["padding-right"]=n&&d(r("padding-right"))||0,e["float"]=o[r("cssFloat")]||"none",e.clear=a[r("clear")]||"none",e},p=function(t,e,n){var r,s,i,o,a;if(i=!1,s=void 0,o=void 0,a=void 0,r=n["#"+t.id])if("function"==typeof r)i=r(t,e);else for(s=0,o=r.length;!i&&s!==o;)i=r[s](t,e),s++;if(r=n[t.nodeName],!i&&r)if("function"==typeof r)i=r(t,e);else for(s=0,o=r.length;!i&&s!==o;)i=r[s](t,e),s++;return i},v=function(t,e){var n,r,s,i,o,a,u,c,l,f;
+ for(n=[],r=[],s=0,f=t.rows[0].cells.length,c=t.clientWidth;f>s;)l=t.rows[0].cells[s],r[s]={name:l.textContent.toLowerCase().replace(/\s+/g,""),prompt:l.textContent.replace(/\r?\n/g,""),width:l.clientWidth/c*e.pdf.internal.pageSize.width},s++;for(s=1;sa;){if(s=i[a],"object"==typeof s){if(e.executeWatchFunctions(s),1===s.nodeType&&"HEADER"===s.nodeName){var w=s,g=e.pdf.margins_doc.top;e.pdf.internal.events.subscribe("addPage",function(){e.y=g,n(w,e,r),e.pdf.margins_doc.top=e.y+10,e.y+=10},!1)}if(8===s.nodeType&&"#comment"===s.nodeName)~s.textContent.indexOf("ADD_PAGE")&&(e.pdf.addPage(),e.y=e.pdf.margins_doc.top);else if(1!==s.nodeType||b[s.nodeName])if(3===s.nodeType){var y=s.nodeValue;if(s.nodeValue&&"LI"===s.parentNode.nodeName)if("OL"===s.parentNode.parentNode.nodeName)y=q++ +". "+y;else{var x=16*o["font-size"],k=2;x>20&&(k=3),h=function(t,e){this.pdf.circle(t,e,k,"FD")}}e.addText(y,o)}else"string"==typeof s&&e.addText(s,o);else{var _;if("IMG"===s.nodeName){var A=s.getAttribute("src");_=m[e.pdf.sHashCode(A)||A]}if(_){e.pdf.internal.pageSize.height-e.pdf.margins_doc.bottome.pdf.margins_doc.top&&(e.pdf.addPage(),e.y=e.pdf.margins_doc.top,e.executeWatchFunctions(s));var C=u(s),S=e.x,E=12/e.pdf.internal.scaleFactor,z=(C["margin-left"]+C["padding-left"])*E,T=(C["margin-right"]+C["padding-right"])*E,I=(C["margin-top"]+C["padding-top"])*E,B=(C["margin-bottom"]+C["padding-bottom"])*E;S+=void 0!==C["float"]&&"right"===C["float"]?e.settings.width-s.width-T:z,e.pdf.addImage(_,S,e.y+I,s.width,s.height),_=void 0,"right"===C["float"]||"left"===C["float"]?(e.watchFunctions.push(function(t,n,r,s){return e.y>=n?(e.x+=t,e.settings.width+=r,!0):s&&1===s.nodeType&&!b[s.nodeName]&&e.x+s.width>e.pdf.margins_doc.left+e.pdf.margins_doc.width?(e.x+=t,e.y=n,e.settings.width+=r,!0):!1}.bind(this,"left"===C["float"]?-s.width-z-T:0,e.y+s.height+I+B,s.width)),e.watchFunctions.push(function(t,n,r){return e.y0){s=s[0];var i=e.pdf.internal.write,o=e.y;e.pdf.internal.write=function(){},n(s,e,r);var a=Math.ceil(e.y-o)+5;e.y=o,e.pdf.internal.write=i,e.pdf.margins_doc.bottom+=a;for(var u=function(t){var i=void 0!==t?t.pageNumber:1,o=e.y;e.y=e.pdf.internal.pageSize.height-e.pdf.margins_doc.bottom,e.pdf.margins_doc.bottom-=a;for(var u=s.getElementsByTagName("span"),c=0;c-1&&(u[c].innerHTML=i),(" "+u[c].className+" ").replace(/[\n\t]/g," ").indexOf(" totalPages ")>-1&&(u[c].innerHTML="###jsPDFVarTotalPages###");n(s,e,r),e.pdf.margins_doc.bottom+=a,e.y=o},c=s.getElementsByTagName("span"),l=0;l-1&&e.pdf.internal.events.subscribe("htmlRenderingFinished",e.pdf.putTotalPages.bind(e.pdf,"###jsPDFVarTotalPages###"),!0);e.pdf.internal.events.subscribe("addPage",u,!1),u(),b.FOOTER=1}},y=function(t,e,r,s,i,o){if(!e)return!1;"string"==typeof e||e.parentNode||(e=""+e.innerHTML),"string"==typeof e&&(e=function(t){var e,n,r,s;return r="jsPDFhtmlText"+Date.now().toString()+(1e3*Math.random()).toFixed(0),s="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;",n=document.createElement("div"),n.style.cssText=s,n.innerHTML='