static.js.jspdf.debug.js Maven / Gradle / Ivy
(function (factory) {
typeof define === 'function' && define.amd ? define(factory) :
factory();
}(function () { 'use strict';
/** @license
* jsPDF - PDF Document creation from JavaScript
* Version 1.5.3 Built on 2018-12-27T14:11:42.696Z
* CommitID d93d28db14
*
* Copyright (c) 2010-2016 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
* 2014 Kenneth Glassey, https://github.com/Gavvers
*
* Licensed under the MIT License
*
* Contributor(s):
* siefkenj, ahwolf, rickygu, Midnith, saintclair, eaparango,
* kim3er, mfo, alnorth, Flamenco
*/
function _typeof(obj) {
if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") {
_typeof = function (obj) {
return typeof obj;
};
} else {
_typeof = function (obj) {
return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
};
}
return _typeof(obj);
}
/**
* JavaScript Polyfill functions for jsPDF
* Collected from public resources by
* https://github.com/diegocr
*/
(function (global) {
if (_typeof(global.console) !== "object") {
// Console-polyfill. MIT license.
// https://github.com/paulmillr/console-polyfill
// Make it safe to do console.log() always.
global.console = {};
var con = global.console;
var prop, method;
var dummy = function dummy() {};
var properties = ['memory'];
var methods = ('assert,clear,count,debug,dir,dirxml,error,exception,group,' + 'groupCollapsed,groupEnd,info,log,markTimeline,profile,profiles,profileEnd,' + 'show,table,time,timeEnd,timeline,timelineEnd,timeStamp,trace,warn').split(',');
while (prop = properties.pop()) {
if (!con[prop]) con[prop] = {};
}
while (method = methods.pop()) {
if (!con[method]) con[method] = dummy;
}
}
var b64 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
if (typeof global.btoa === 'undefined') {
global.btoa = function (data) {
// discuss at: http://phpjs.org/functions/base64_encode/
// original by: Tyler Akins (http://rumkin.com)
// improved by: Bayron Guevara
// improved by: Thunder.m
// improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
// improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
// improved by: Rafal Kukawski (http://kukawski.pl)
// bugfixed by: Pellentesque Malesuada
// example 1: base64_encode('Kevin van Zonneveld');
// returns 1: 'S2V2aW4gdmFuIFpvbm5ldmVsZA=='
var o1,
o2,
o3,
h1,
h2,
h3,
h4,
bits,
i = 0,
ac = 0,
enc = '',
tmp_arr = [];
if (!data) {
return data;
}
do {
// pack three octets into four hexets
o1 = data.charCodeAt(i++);
o2 = data.charCodeAt(i++);
o3 = data.charCodeAt(i++);
bits = o1 << 16 | o2 << 8 | o3;
h1 = bits >> 18 & 0x3f;
h2 = bits >> 12 & 0x3f;
h3 = bits >> 6 & 0x3f;
h4 = bits & 0x3f; // use hexets to index into b64, and append result to encoded string
tmp_arr[ac++] = b64.charAt(h1) + b64.charAt(h2) + b64.charAt(h3) + b64.charAt(h4);
} while (i < data.length);
enc = tmp_arr.join('');
var r = data.length % 3;
return (r ? enc.slice(0, r - 3) : enc) + '==='.slice(r || 3);
};
}
if (typeof global.atob === 'undefined') {
global.atob = function (data) {
// discuss at: http://phpjs.org/functions/base64_decode/
// original by: Tyler Akins (http://rumkin.com)
// improved by: Thunder.m
// improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
// improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
// input by: Aman Gupta
// input by: Brett Zamir (http://brett-zamir.me)
// bugfixed by: Onno Marsman
// bugfixed by: Pellentesque Malesuada
// bugfixed by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
// example 1: base64_decode('S2V2aW4gdmFuIFpvbm5ldmVsZA==');
// returns 1: 'Kevin van Zonneveld'
var o1,
o2,
o3,
h1,
h2,
h3,
h4,
bits,
i = 0,
ac = 0,
dec = '',
tmp_arr = [];
if (!data) {
return data;
}
data += '';
do {
// unpack four hexets into three octets using index points in b64
h1 = b64.indexOf(data.charAt(i++));
h2 = b64.indexOf(data.charAt(i++));
h3 = b64.indexOf(data.charAt(i++));
h4 = b64.indexOf(data.charAt(i++));
bits = h1 << 18 | h2 << 12 | h3 << 6 | h4;
o1 = bits >> 16 & 0xff;
o2 = bits >> 8 & 0xff;
o3 = bits & 0xff;
if (h3 == 64) {
tmp_arr[ac++] = String.fromCharCode(o1);
} else if (h4 == 64) {
tmp_arr[ac++] = String.fromCharCode(o1, o2);
} else {
tmp_arr[ac++] = String.fromCharCode(o1, o2, o3);
}
} while (i < data.length);
dec = tmp_arr.join('');
return dec;
};
}
if (!Array.prototype.map) {
Array.prototype.map = function (fun
/*, thisArg */
) {
if (this === void 0 || this === null || typeof fun !== "function") throw new TypeError();
var t = Object(this),
len = t.length >>> 0,
res = new Array(len);
var thisArg = arguments.length > 1 ? arguments[1] : void 0;
for (var i = 0; i < len; i++) {
// NOTE: Absolute correctness would demand Object.defineProperty
// be used. But this method is fairly new, and failure is
// possible only if Object.prototype or Array.prototype
// has a property |i| (very unlikely), so use a less-correct
// but more portable alternative.
if (i in t) res[i] = fun.call(thisArg, t[i], i, t);
}
return res;
};
}
if (!Array.isArray) {
Array.isArray = function (arg) {
return Object.prototype.toString.call(arg) === '[object Array]';
};
}
if (!Array.prototype.forEach) {
Array.prototype.forEach = function (fun, thisArg) {
if (this === void 0 || this === null || typeof fun !== "function") throw new TypeError();
var t = Object(this),
len = t.length >>> 0;
for (var i = 0; i < len; i++) {
if (i in t) fun.call(thisArg, t[i], i, t);
}
};
} // https://tc39.github.io/ecma262/#sec-array.prototype.find
if (!Array.prototype.find) {
Object.defineProperty(Array.prototype, 'find', {
value: function value(predicate) {
// 1. Let O be ? ToObject(this value).
if (this == null) {
throw new TypeError('"this" is null or not defined');
}
var o = Object(this); // 2. Let len be ? ToLength(? Get(O, "length")).
var len = o.length >>> 0; // 3. If IsCallable(predicate) is false, throw a TypeError exception.
if (typeof predicate !== 'function') {
throw new TypeError('predicate must be a function');
} // 4. If thisArg was supplied, let T be thisArg; else let T be undefined.
var thisArg = arguments[1]; // 5. Let k be 0.
var k = 0; // 6. Repeat, while k < len
while (k < len) {
// a. Let Pk be ! ToString(k).
// b. Let kValue be ? Get(O, Pk).
// c. Let testResult be ToBoolean(? Call(predicate, T, « kValue, k, O »)).
// d. If testResult is true, return kValue.
var kValue = o[k];
if (predicate.call(thisArg, kValue, k, o)) {
return kValue;
} // e. Increase k by 1.
k++;
} // 7. Return undefined.
return undefined;
},
configurable: true,
writable: true
});
}
if (!Object.keys) {
Object.keys = function () {
var hasOwnProperty = Object.prototype.hasOwnProperty,
hasDontEnumBug = !{
toString: null
}.propertyIsEnumerable('toString'),
dontEnums = ['toString', 'toLocaleString', 'valueOf', 'hasOwnProperty', 'isPrototypeOf', 'propertyIsEnumerable', 'constructor'],
dontEnumsLength = dontEnums.length;
return function (obj) {
if (_typeof(obj) !== 'object' && (typeof obj !== 'function' || obj === null)) {
throw new TypeError();
}
var result = [],
prop,
i;
for (prop in obj) {
if (hasOwnProperty.call(obj, prop)) {
result.push(prop);
}
}
if (hasDontEnumBug) {
for (i = 0; i < dontEnumsLength; i++) {
if (hasOwnProperty.call(obj, dontEnums[i])) {
result.push(dontEnums[i]);
}
}
}
return result;
};
}();
}
if (typeof Object.assign != 'function') {
Object.assign = function (target) {
if (target == null) {
throw new TypeError('Cannot convert undefined or null to object');
}
target = Object(target);
for (var index = 1; index < arguments.length; index++) {
var source = arguments[index];
if (source != null) {
for (var key in source) {
if (Object.prototype.hasOwnProperty.call(source, key)) {
target[key] = source[key];
}
}
}
}
return target;
};
}
if (!String.prototype.trim) {
String.prototype.trim = function () {
return this.replace(/^\s+|\s+$/g, '');
};
}
if (!String.prototype.trimLeft) {
String.prototype.trimLeft = function () {
return this.replace(/^\s+/g, "");
};
}
if (!String.prototype.trimRight) {
String.prototype.trimRight = function () {
return this.replace(/\s+$/g, "");
};
}
Number.isInteger = Number.isInteger || function (value) {
return typeof value === 'number' && isFinite(value) && Math.floor(value) === value;
};
})(typeof self !== "undefined" && self || typeof window !== "undefined" && window || typeof global !== "undefined" && global || Function('return typeof this === "object" && this.content')() || Function('return this')()); // `self` is undefined in Firefox for Android content script context
// while `this` is nsIContentFrameMessageManager
// with an attribute `content` that corresponds to the window
/**
* Creates new jsPDF document object instance.
* @name jsPDF
* @class
* @param orientation {string/Object} Orientation of the first page. Possible values are "portrait" or "landscape" (or shortcuts "p" (Default), "l").
* Can also be an options object.
* @param unit {string} Measurement unit to be used when coordinates are specified.
* Possible values are "pt" (points), "mm" (Default), "cm", "in" or "px".
* @param format {string/Array} The format of the first page. Can be:- a0 - a10
- b0 - b10
- c0 - c10
- dl
- letter
- government-letter
- legal
- junior-legal
- ledger
- tabloid
- credit-card
* Default is "a4". If you want to use your own format just pass instead of one of the above predefined formats the size as an number-array, e.g. [595.28, 841.89]
* @returns {jsPDF} jsPDF-instance
* @description
* If the first parameter (orientation) is an object, it will be interpreted as an object of named parameters
* ```
* {
* orientation: 'p',
* unit: 'mm',
* format: 'a4',
* hotfixes: [] // an array of hotfix strings to enable
* }
* ```
*/
var jsPDF = function (global) {
/**
* jsPDF's Internal PubSub Implementation.
* Backward compatible rewritten on 2014 by
* Diego Casorran, https://github.com/diegocr
*
* @class
* @name PubSub
* @ignore
*/
function PubSub(context) {
if (_typeof(context) !== 'object') {
throw new Error('Invalid Context passed to initialize PubSub (jsPDF-module)');
}
var topics = {};
this.subscribe = function (topic, callback, once) {
once = once || false;
if (typeof topic !== 'string' || typeof callback !== 'function' || typeof once !== 'boolean') {
throw new Error('Invalid arguments passed to PubSub.subscribe (jsPDF-module)');
}
if (!topics.hasOwnProperty(topic)) {
topics[topic] = {};
}
var token = Math.random().toString(35);
topics[topic][token] = [callback, !!once];
return token;
};
this.unsubscribe = function (token) {
for (var topic in topics) {
if (topics[topic][token]) {
delete topics[topic][token];
if (Object.keys(topics[topic]).length === 0) {
delete topics[topic];
}
return true;
}
}
return false;
};
this.publish = function (topic) {
if (topics.hasOwnProperty(topic)) {
var args = Array.prototype.slice.call(arguments, 1),
tokens = [];
for (var token in topics[topic]) {
var sub = topics[topic][token];
try {
sub[0].apply(context, args);
} catch (ex) {
if (global.console) {
console.error('jsPDF PubSub Error', ex.message, ex);
}
}
if (sub[1]) tokens.push(token);
}
if (tokens.length) tokens.forEach(this.unsubscribe);
}
};
this.getTopics = function () {
return topics;
};
}
/**
* @constructor
* @private
*/
function jsPDF(orientation, unit, format, compressPdf) {
var options = {};
var filters = [];
var userUnit = 1.0;
if (_typeof(orientation) === 'object') {
options = orientation;
orientation = options.orientation;
unit = options.unit || unit;
format = options.format || format;
compressPdf = options.compress || options.compressPdf || compressPdf;
filters = options.filters || (compressPdf === true ? ['FlateEncode'] : filters);
userUnit = typeof options.userUnit === "number" ? Math.abs(options.userUnit) : 1.0;
}
unit = unit || 'mm';
orientation = ('' + (orientation || 'P')).toLowerCase();
var putOnlyUsedFonts = options.putOnlyUsedFonts || true;
var usedFonts = {};
var API = {
internal: {},
__private__: {}
};
API.__private__.PubSub = PubSub;
var pdfVersion = '1.3';
var getPdfVersion = API.__private__.getPdfVersion = function () {
return pdfVersion;
};
var setPdfVersion = API.__private__.setPdfVersion = function (value) {
pdfVersion = value;
}; // Size in pt of various paper formats
var pageFormats = {
'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]
};
var getPageFormats = API.__private__.getPageFormats = function () {
return pageFormats;
};
var getPageFormat = API.__private__.getPageFormat = function (value) {
return pageFormats[value];
};
if (typeof format === "string") {
format = getPageFormat(format);
}
format = format || getPageFormat('a4');
var f2 = API.f2 = API.__private__.f2 = function (number) {
if (isNaN(number)) {
throw new Error('Invalid argument passed to jsPDF.f2');
}
return number.toFixed(2); // Ie, %.2f
};
var f3 = API.__private__.f3 = function (number) {
if (isNaN(number)) {
throw new Error('Invalid argument passed to jsPDF.f3');
}
return number.toFixed(3); // Ie, %.3f
};
var fileId = '00000000000000000000000000000000';
var getFileId = API.__private__.getFileId = function () {
return fileId;
};
var setFileId = API.__private__.setFileId = function (value) {
value = value || "12345678901234567890123456789012".split('').map(function () {
return "ABCDEF0123456789".charAt(Math.floor(Math.random() * 16));
}).join('');
fileId = value;
return fileId;
};
/**
* @name setFileId
* @memberOf jsPDF
* @function
* @instance
* @param {string} value GUID.
* @returns {jsPDF}
*/
API.setFileId = function (value) {
setFileId(value);
return this;
};
/**
* @name getFileId
* @memberOf jsPDF
* @function
* @instance
*
* @returns {string} GUID.
*/
API.getFileId = function () {
return getFileId();
};
var creationDate;
var convertDateToPDFDate = API.__private__.convertDateToPDFDate = function (parmDate) {
var result = '';
var tzoffset = parmDate.getTimezoneOffset(),
tzsign = tzoffset < 0 ? '+' : '-',
tzhour = Math.floor(Math.abs(tzoffset / 60)),
tzmin = Math.abs(tzoffset % 60),
timeZoneString = [tzsign, padd2(tzhour), "'", padd2(tzmin), "'"].join('');
result = ['D:', parmDate.getFullYear(), padd2(parmDate.getMonth() + 1), padd2(parmDate.getDate()), padd2(parmDate.getHours()), padd2(parmDate.getMinutes()), padd2(parmDate.getSeconds()), timeZoneString].join('');
return result;
};
var convertPDFDateToDate = API.__private__.convertPDFDateToDate = function (parmPDFDate) {
var year = parseInt(parmPDFDate.substr(2, 4), 10);
var month = parseInt(parmPDFDate.substr(6, 2), 10) - 1;
var date = parseInt(parmPDFDate.substr(8, 2), 10);
var hour = parseInt(parmPDFDate.substr(10, 2), 10);
var minutes = parseInt(parmPDFDate.substr(12, 2), 10);
var seconds = parseInt(parmPDFDate.substr(14, 2), 10);
var timeZoneHour = parseInt(parmPDFDate.substr(16, 2), 10);
var timeZoneMinutes = parseInt(parmPDFDate.substr(20, 2), 10);
var resultingDate = new Date(year, month, date, hour, minutes, seconds, 0);
return resultingDate;
};
var setCreationDate = API.__private__.setCreationDate = function (date) {
var tmpCreationDateString;
var regexPDFCreationDate = /^D:(20[0-2][0-9]|203[0-7]|19[7-9][0-9])(0[0-9]|1[0-2])([0-2][0-9]|3[0-1])(0[0-9]|1[0-9]|2[0-3])(0[0-9]|[1-5][0-9])(0[0-9]|[1-5][0-9])(\+0[0-9]|\+1[0-4]|\-0[0-9]|\-1[0-1])\'(0[0-9]|[1-5][0-9])\'?$/;
if (typeof date === "undefined") {
date = new Date();
}
if (_typeof(date) === "object" && Object.prototype.toString.call(date) === "[object Date]") {
tmpCreationDateString = convertDateToPDFDate(date);
} else if (regexPDFCreationDate.test(date)) {
tmpCreationDateString = date;
} else {
throw new Error('Invalid argument passed to jsPDF.setCreationDate');
}
creationDate = tmpCreationDateString;
return creationDate;
};
var getCreationDate = API.__private__.getCreationDate = function (type) {
var result = creationDate;
if (type === "jsDate") {
result = convertPDFDateToDate(creationDate);
}
return result;
};
/**
* @name setCreationDate
* @memberOf jsPDF
* @function
* @instance
* @param {Object} date
* @returns {jsPDF}
*/
API.setCreationDate = function (date) {
setCreationDate(date);
return this;
};
/**
* @name getCreationDate
* @memberOf jsPDF
* @function
* @instance
* @param {Object} type
* @returns {Object}
*/
API.getCreationDate = function (type) {
return getCreationDate(type);
};
var padd2 = API.__private__.padd2 = function (number) {
return ('0' + parseInt(number)).slice(-2);
};
var outToPages = !1; // switches where out() prints. outToPages true = push to pages obj. outToPages false = doc builder content
var pages = [];
var content = [];
var currentPage;
var content_length = 0;
var customOutputDestination;
var setOutputDestination = API.__private__.setCustomOutputDestination = function (destination) {
customOutputDestination = destination;
};
var resetOutputDestination = API.__private__.resetCustomOutputDestination = function (destination) {
customOutputDestination = undefined;
};
var out = API.__private__.out = function (string) {
var writeArray;
string = typeof string === "string" ? string : string.toString();
if (typeof customOutputDestination === "undefined") {
writeArray = outToPages ? pages[currentPage] : content;
} else {
writeArray = customOutputDestination;
}
writeArray.push(string);
if (!outToPages) {
content_length += string.length + 1;
}
return writeArray;
};
var write = API.__private__.write = function (value) {
return out(arguments.length === 1 ? value.toString() : Array.prototype.join.call(arguments, ' '));
};
var getArrayBuffer = API.__private__.getArrayBuffer = function (data) {
var len = data.length,
ab = new ArrayBuffer(len),
u8 = new Uint8Array(ab);
while (len--) {
u8[len] = data.charCodeAt(len);
}
return ab;
};
var standardFonts = [['Helvetica', "helvetica", "normal", 'WinAnsiEncoding'], ['Helvetica-Bold', "helvetica", "bold", 'WinAnsiEncoding'], ['Helvetica-Oblique', "helvetica", "italic", 'WinAnsiEncoding'], ['Helvetica-BoldOblique', "helvetica", "bolditalic", 'WinAnsiEncoding'], ['Courier', "courier", "normal", 'WinAnsiEncoding'], ['Courier-Bold', "courier", "bold", 'WinAnsiEncoding'], ['Courier-Oblique', "courier", "italic", 'WinAnsiEncoding'], ['Courier-BoldOblique', "courier", "bolditalic", 'WinAnsiEncoding'], ['Times-Roman', "times", "normal", 'WinAnsiEncoding'], ['Times-Bold', "times", "bold", 'WinAnsiEncoding'], ['Times-Italic', "times", "italic", 'WinAnsiEncoding'], ['Times-BoldItalic', "times", "bolditalic", 'WinAnsiEncoding'], ['ZapfDingbats', "zapfdingbats", "normal", null], ['Symbol', "symbol", "normal", null]];
var getStandardFonts = API.__private__.getStandardFonts = function (data) {
return standardFonts;
};
var activeFontSize = options.fontSize || 16;
/**
* Sets font size for upcoming text elements.
*
* @param {number} size Font size in points.
* @function
* @instance
* @returns {jsPDF}
* @memberOf jsPDF
* @name setFontSize
*/
var setFontSize = API.__private__.setFontSize = API.setFontSize = function (size) {
activeFontSize = size;
return this;
};
/**
* Gets the fontsize for upcoming text elements.
*
* @function
* @instance
* @returns {number}
* @memberOf jsPDF
* @name getFontSize
*/
var getFontSize = API.__private__.getFontSize = API.getFontSize = function () {
return activeFontSize;
};
var R2L = options.R2L || false;
/**
* Set value of R2L functionality.
*
* @param {boolean} value
* @function
* @instance
* @returns {jsPDF} jsPDF-instance
* @memberOf jsPDF
* @name setR2L
*/
var setR2L = API.__private__.setR2L = API.setR2L = function (value) {
R2L = value;
return this;
};
/**
* Get value of R2L functionality.
*
* @function
* @instance
* @returns {boolean} jsPDF-instance
* @memberOf jsPDF
* @name getR2L
*/
var getR2L = API.__private__.getR2L = API.getR2L = function (value) {
return R2L;
};
var zoomMode; // default: 1;
var setZoomMode = API.__private__.setZoomMode = function (zoom) {
var validZoomModes = [undefined, null, 'fullwidth', 'fullheight', 'fullpage', 'original'];
if (/^\d*\.?\d*\%$/.test(zoom)) {
zoomMode = zoom;
} else if (!isNaN(zoom)) {
zoomMode = parseInt(zoom, 10);
} else if (validZoomModes.indexOf(zoom) !== -1) {
zoomMode = zoom;
} else {
throw new Error('zoom must be Integer (e.g. 2), a percentage Value (e.g. 300%) or fullwidth, fullheight, fullpage, original. "' + zoom + '" is not recognized.');
}
};
var getZoomMode = API.__private__.getZoomMode = function () {
return zoomMode;
};
var pageMode; // default: 'UseOutlines';
var setPageMode = API.__private__.setPageMode = function (pmode) {
var validPageModes = [undefined, null, 'UseNone', 'UseOutlines', 'UseThumbs', 'FullScreen'];
if (validPageModes.indexOf(pmode) == -1) {
throw new Error('Page mode must be one of UseNone, UseOutlines, UseThumbs, or FullScreen. "' + pmode + '" is not recognized.');
}
pageMode = pmode;
};
var getPageMode = API.__private__.getPageMode = function () {
return pageMode;
};
var layoutMode; // default: 'continuous';
var setLayoutMode = API.__private__.setLayoutMode = function (layout) {
var validLayoutModes = [undefined, null, 'continuous', 'single', 'twoleft', 'tworight', 'two'];
if (validLayoutModes.indexOf(layout) == -1) {
throw new Error('Layout mode must be one of continuous, single, twoleft, tworight. "' + layout + '" is not recognized.');
}
layoutMode = layout;
};
var getLayoutMode = API.__private__.getLayoutMode = function () {
return layoutMode;
};
/**
* Set the display mode options of the page like zoom and layout.
*
* @name setDisplayMode
* @memberOf jsPDF
* @function
* @instance
* @param {integer|String} zoom You can pass an integer or percentage as
* a string. 2 will scale the document up 2x, '200%' will scale up by the
* same amount. You can also set it to 'fullwidth', 'fullheight',
* 'fullpage', or 'original'.
*
* Only certain PDF readers support this, such as Adobe Acrobat.
*
* @param {string} layout Layout mode can be: 'continuous' - this is the
* default continuous scroll. 'single' - the single page mode only shows one
* page at a time. 'twoleft' - two column left mode, first page starts on
* the left, and 'tworight' - pages are laid out in two columns, with the
* first page on the right. This would be used for books.
* @param {string} pmode 'UseOutlines' - it shows the
* outline of the document on the left. 'UseThumbs' - shows thumbnails along
* the left. 'FullScreen' - prompts the user to enter fullscreen mode.
*
* @returns {jsPDF}
*/
var setDisplayMode = API.__private__.setDisplayMode = API.setDisplayMode = function (zoom, layout, pmode) {
setZoomMode(zoom);
setLayoutMode(layout);
setPageMode(pmode);
return this;
};
var documentProperties = {
'title': '',
'subject': '',
'author': '',
'keywords': '',
'creator': ''
};
var getDocumentProperty = API.__private__.getDocumentProperty = function (key) {
if (Object.keys(documentProperties).indexOf(key) === -1) {
throw new Error('Invalid argument passed to jsPDF.getDocumentProperty');
}
return documentProperties[key];
};
var getDocumentProperties = API.__private__.getDocumentProperties = function (properties) {
return documentProperties;
};
/**
* Adds a properties to the PDF document.
*
* @param {Object} A property_name-to-property_value object structure.
* @function
* @instance
* @returns {jsPDF}
* @memberOf jsPDF
* @name setDocumentProperties
*/
var setDocumentProperties = API.__private__.setDocumentProperties = API.setProperties = API.setDocumentProperties = 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;
};
var setDocumentProperty = API.__private__.setDocumentProperty = function (key, value) {
if (Object.keys(documentProperties).indexOf(key) === -1) {
throw new Error('Invalid arguments passed to jsPDF.setDocumentProperty');
}
return documentProperties[key] = value;
};
var objectNumber = 0; // 'n' Current object number
var offsets = []; // List of offsets. Activated and reset by buildDocument(). Pupulated by various calls buildDocument makes.
var fonts = {}; // collection of font objects, where key is fontKey - a dynamically created label for a given font.
var fontmap = {}; // mapping structure fontName > fontStyle > font key - performance layer. See addFont()
var activeFontKey; // will be string representing the KEY of the font as combination of fontName + fontStyle
var k; // Scale factor
var page = 0;
var pagesContext = [];
var additionalObjects = [];
var events = new PubSub(API);
var hotfixes = options.hotfixes || [];
var newObject = API.__private__.newObject = function () {
var oid = newObjectDeferred();
newObjectDeferredBegin(oid, true);
return oid;
}; // Does not output the object. The caller must call newObjectDeferredBegin(oid) before outputing any data
var newObjectDeferred = API.__private__.newObjectDeferred = function () {
objectNumber++;
offsets[objectNumber] = function () {
return content_length;
};
return objectNumber;
};
var newObjectDeferredBegin = function newObjectDeferredBegin(oid, doOutput) {
doOutput = typeof doOutput === 'boolean' ? doOutput : false;
offsets[oid] = content_length;
if (doOutput) {
out(oid + ' 0 obj');
}
return oid;
}; // Does not output the object until after the pages have been output.
// Returns an object containing the objectId and content.
// All pages have been added so the object ID can be estimated to start right after.
// This does not modify the current objectNumber; It must be updated after the newObjects are output.
var newAdditionalObject = API.__private__.newAdditionalObject = function () {
var objId = newObjectDeferred();
var obj = {
objId: objId,
content: ''
};
additionalObjects.push(obj);
return obj;
};
var rootDictionaryObjId = newObjectDeferred();
var resourceDictionaryObjId = newObjectDeferred(); /////////////////////
// Private functions
/////////////////////
var decodeColorString = API.__private__.decodeColorString = function (color) {
var colorEncoded = color.split(' ');
if (colorEncoded.length === 2 && (colorEncoded[1] === 'g' || colorEncoded[1] === 'G')) {
// convert grayscale value to rgb so that it can be converted to hex for consistency
var floatVal = parseFloat(colorEncoded[0]);
colorEncoded = [floatVal, floatVal, floatVal, 'r'];
}
var colorAsRGB = '#';
for (var i = 0; i < 3; i++) {
colorAsRGB += ('0' + Math.floor(parseFloat(colorEncoded[i]) * 255).toString(16)).slice(-2);
}
return colorAsRGB;
};
var encodeColorString = API.__private__.encodeColorString = function (options) {
var color;
if (typeof options === "string") {
options = {
ch1: options
};
}
var ch1 = options.ch1;
var ch2 = options.ch2;
var ch3 = options.ch3;
var ch4 = options.ch4;
var precision = options.precision;
var letterArray = options.pdfColorType === "draw" ? ['G', 'RG', 'K'] : ['g', 'rg', 'k'];
if (typeof ch1 === "string" && ch1.charAt(0) !== '#') {
var rgbColor = new RGBColor(ch1);
if (rgbColor.ok) {
ch1 = rgbColor.toHex();
} else if (!/^\d*\.?\d*$/.test(ch1)) {
throw new Error('Invalid color "' + ch1 + '" passed to jsPDF.encodeColorString.');
}
} //convert short rgb to long form
if (typeof ch1 === "string" && /^#[0-9A-Fa-f]{3}$/.test(ch1)) {
ch1 = '#' + ch1[1] + ch1[1] + ch1[2] + ch1[2] + ch1[3] + ch1[3];
}
if (typeof ch1 === "string" && /^#[0-9A-Fa-f]{6}$/.test(ch1)) {
var hex = parseInt(ch1.substr(1), 16);
ch1 = hex >> 16 & 255;
ch2 = hex >> 8 & 255;
ch3 = hex & 255;
}
if (typeof ch2 === "undefined" || typeof ch4 === "undefined" && ch1 === ch2 && ch2 === ch3) {
// Gray color space.
if (typeof ch1 === "string") {
color = ch1 + " " + letterArray[0];
} else {
switch (options.precision) {
case 2:
color = f2(ch1 / 255) + " " + letterArray[0];
break;
case 3:
default:
color = f3(ch1 / 255) + " " + letterArray[0];
}
}
} else if (typeof ch4 === "undefined" || _typeof(ch4) === "object") {
// assume RGBA
if (ch4 && !isNaN(ch4.a)) {
//TODO Implement transparency.
//WORKAROUND use white for now, if transparent, otherwise handle as rgb
if (ch4.a === 0) {
color = ['1.000', '1.000', '1.000', letterArray[1]].join(" ");
return color;
}
} // assume RGB
if (typeof ch1 === "string") {
color = [ch1, ch2, ch3, letterArray[1]].join(" ");
} else {
switch (options.precision) {
case 2:
color = [f2(ch1 / 255), f2(ch2 / 255), f2(ch3 / 255), letterArray[1]].join(" ");
break;
default:
case 3:
color = [f3(ch1 / 255), f3(ch2 / 255), f3(ch3 / 255), letterArray[1]].join(" ");
}
}
} else {
// assume CMYK
if (typeof ch1 === 'string') {
color = [ch1, ch2, ch3, ch4, letterArray[2]].join(" ");
} else {
switch (options.precision) {
case 2:
color = [f2(ch1 / 255), f2(ch2 / 255), f2(ch3 / 255), f2(ch4 / 255), letterArray[2]].join(" ");
break;
case 3:
default:
color = [f3(ch1 / 255), f3(ch2 / 255), f3(ch3 / 255), f3(ch4 / 255), letterArray[2]].join(" ");
}
}
}
return color;
};
var getFilters = API.__private__.getFilters = function () {
return filters;
};
var putStream = API.__private__.putStream = function (options) {
options = options || {};
var data = options.data || '';
var filters = options.filters || getFilters();
var alreadyAppliedFilters = options.alreadyAppliedFilters || [];
var addLength1 = options.addLength1 || false;
var valueOfLength1 = data.length;
var processedData = {};
if (filters === true) {
filters = ['FlateEncode'];
}
var keyValues = options.additionalKeyValues || [];
if (typeof jsPDF.API.processDataByFilters !== 'undefined') {
processedData = jsPDF.API.processDataByFilters(data, filters);
} else {
processedData = {
data: data,
reverseChain: []
};
}
var filterAsString = processedData.reverseChain + (Array.isArray(alreadyAppliedFilters) ? alreadyAppliedFilters.join(' ') : alreadyAppliedFilters.toString());
if (processedData.data.length !== 0) {
keyValues.push({
key: 'Length',
value: processedData.data.length
});
if (addLength1 === true) {
keyValues.push({
key: 'Length1',
value: valueOfLength1
});
}
}
if (filterAsString.length != 0) {
//if (filters.length === 0 && alreadyAppliedFilters.length === 1 && typeof alreadyAppliedFilters !== "undefined") {
if (filterAsString.split('/').length - 1 === 1) {
keyValues.push({
key: 'Filter',
value: filterAsString
});
} else {
keyValues.push({
key: 'Filter',
value: '[' + filterAsString + ']'
});
}
}
out('<<');
for (var i = 0; i < keyValues.length; i++) {
out('/' + keyValues[i].key + ' ' + keyValues[i].value);
}
out('>>');
if (processedData.data.length !== 0) {
out('stream');
out(processedData.data);
out('endstream');
}
};
var putPage = API.__private__.putPage = function (page) {
var mediaBox = page.mediaBox;
var pageNumber = page.number;
var data = page.data;
var pageObjectNumber = page.objId;
var pageContentsObjId = page.contentsObjId;
newObjectDeferredBegin(pageObjectNumber, true);
var wPt = pagesContext[currentPage].mediaBox.topRightX - pagesContext[currentPage].mediaBox.bottomLeftX;
var hPt = pagesContext[currentPage].mediaBox.topRightY - pagesContext[currentPage].mediaBox.bottomLeftY;
out('<>');
out('endobj'); // Page content
var pageContent = data.join('\n');
newObjectDeferredBegin(pageContentsObjId, true);
putStream({
data: pageContent,
filters: getFilters()
});
out('endobj');
return pageObjectNumber;
};
var putPages = API.__private__.putPages = function () {
var n,
i,
pageObjectNumbers = [];
for (n = 1; n <= page; n++) {
pagesContext[n].objId = newObjectDeferred();
pagesContext[n].contentsObjId = newObjectDeferred();
}
for (n = 1; n <= page; n++) {
pageObjectNumbers.push(putPage({
number: n,
data: pages[n],
objId: pagesContext[n].objId,
contentsObjId: pagesContext[n].contentsObjId,
mediaBox: pagesContext[n].mediaBox,
cropBox: pagesContext[n].cropBox,
bleedBox: pagesContext[n].bleedBox,
trimBox: pagesContext[n].trimBox,
artBox: pagesContext[n].artBox,
userUnit: pagesContext[n].userUnit,
rootDictionaryObjId: rootDictionaryObjId,
resourceDictionaryObjId: resourceDictionaryObjId
}));
}
newObjectDeferredBegin(rootDictionaryObjId, true);
out('<>');
out('endobj');
events.publish('postPutPages');
};
var putFont = function putFont(font) {
events.publish('putFont', {
font: font,
out: out,
newObject: newObject,
putStream: putStream
});
if (font.isAlreadyPutted !== true) {
font.objectNumber = newObject();
out('<<');
out('/Type /Font');
out('/BaseFont /' + font.postScriptName);
out('/Subtype /Type1');
if (typeof font.encoding === 'string') {
out('/Encoding /' + font.encoding);
}
out('/FirstChar 32');
out('/LastChar 255');
out('>>');
out('endobj');
}
};
var putFonts = function putFonts() {
for (var fontKey in fonts) {
if (fonts.hasOwnProperty(fontKey)) {
if (putOnlyUsedFonts === false || putOnlyUsedFonts === true && usedFonts.hasOwnProperty(fontKey)) {
putFont(fonts[fontKey]);
}
}
}
};
var putResourceDictionary = function putResourceDictionary() {
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)) {
if (putOnlyUsedFonts === false || putOnlyUsedFonts === true && usedFonts.hasOwnProperty(fontKey)) {
out('/' + fontKey + ' ' + fonts[fontKey].objectNumber + ' 0 R');
}
}
}
out('>>');
out('/XObject <<');
events.publish('putXobjectDict');
out('>>');
};
var putResources = function putResources() {
putFonts();
events.publish('putResources');
newObjectDeferredBegin(resourceDictionaryObjId, true);
out('<<');
putResourceDictionary();
out('>>');
out('endobj');
events.publish('postPutResources');
};
var putAdditionalObjects = function putAdditionalObjects() {
events.publish('putAdditionalObjects');
for (var i = 0; i < additionalObjects.length; i++) {
var obj = additionalObjects[i];
newObjectDeferredBegin(obj.objId, true);
out(obj.content);
out('endobj');
}
events.publish('postPutAdditionalObjects');
};
var addToFontDictionary = function addToFontDictionary(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;
};
var addFont = function addFont(postScriptName, fontName, fontStyle, encoding, isStandardFont) {
isStandardFont = isStandardFont || false;
var fontKey = 'F' + (Object.keys(fonts).length + 1).toString(10),
// This is FontObject
font = {
'id': fontKey,
'postScriptName': postScriptName,
'fontName': fontName,
'fontStyle': fontStyle,
'encoding': encoding,
'isStandardFont': isStandardFont,
'metadata': {}
};
var instance = this;
events.publish('addFont', {
font: font,
instance: instance
});
if (fontKey !== undefined) {
fonts[fontKey] = font;
addToFontDictionary(fontKey, fontName, fontStyle);
}
return fontKey;
};
var addFonts = function addFonts(arrayOfFonts) {
for (var i = 0, l = standardFonts.length; i < l; i++) {
var fontKey = addFont(arrayOfFonts[i][0], arrayOfFonts[i][1], arrayOfFonts[i][2], standardFonts[i][3], true);
usedFonts[fontKey] = true; // adding aliases for standard fonts, this time matching the capitalization
var parts = arrayOfFonts[i][0].split('-');
addToFontDictionary(fontKey, parts[0], parts[1] || '');
}
events.publish('addFonts', {
fonts: fonts,
dictionary: fontmap
});
};
var 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;
};
var to8bitStream = function to8bitStream(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);
};
var pdfEscape = API.__private__.pdfEscape = API.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, '\\)');
};
var beginPage = API.__private__.beginPage = function (width, height) {
var tmp; // Dimensions are stored as user units and converted to points on output
var orientation = typeof height === 'string' && height.toLowerCase();
if (typeof width === 'string') {
if (tmp = getPageFormat(width.toLowerCase())) {
width = tmp[0];
height = tmp[1];
}
}
if (Array.isArray(width)) {
height = width[1];
width = width[0];
}
if (isNaN(width) || isNaN(height)) {
width = format[0];
height = format[1];
}
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;
}
}
if (width > 14400 || height > 14400) {
console.warn('A page in a PDF can not be wider or taller than 14400 userUnit. jsPDF limits the width/height to 14400');
width = Math.min(14400, width);
height = Math.min(14400, height);
}
format = [width, height];
outToPages = true;
pages[++page] = [];
pagesContext[page] = {
objId: 0,
contentsObjId: 0,
userUnit: Number(userUnit),
artBox: null,
bleedBox: null,
cropBox: null,
trimBox: null,
mediaBox: {
bottomLeftX: 0,
bottomLeftY: 0,
topRightX: Number(width),
topRightY: Number(height)
}
};
_setPage(page);
};
var _addPage = function _addPage() {
beginPage.apply(this, arguments); // Set line width
setLineWidth(lineWidth); // Set draw color
out(strokeColor); // resurrecting non-default line caps, joins
if (lineCapID !== 0) {
out(lineCapID + ' J');
}
if (lineJoinID !== 0) {
out(lineJoinID + ' j');
}
events.publish('addPage', {
pageNumber: page
});
};
var _deletePage = function _deletePage(n) {
if (n > 0 && n <= page) {
pages.splice(n, 1);
page--;
if (currentPage > page) {
currentPage = page;
}
this.setPage(currentPage);
}
};
var _setPage = function _setPage(n) {
if (n > 0 && n <= page) {
currentPage = n;
}
};
var getNumberOfPages = API.__private__.getNumberOfPages = API.getNumberOfPages = function () {
return pages.length - 1;
};
/**
* 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.
* @ignore
*/
var _getFont = function getFont(fontName, fontStyle, options) {
var key = undefined,
fontNameLowerCase;
options = options || {};
fontName = fontName !== undefined ? fontName : fonts[activeFontKey].fontName;
fontStyle = fontStyle !== undefined ? fontStyle : fonts[activeFontKey].fontStyle;
fontNameLowerCase = fontName.toLowerCase();
if (fontmap[fontNameLowerCase] !== undefined && fontmap[fontNameLowerCase][fontStyle] !== undefined) {
key = fontmap[fontNameLowerCase][fontStyle];
} else if (fontmap[fontName] !== undefined && fontmap[fontName][fontStyle] !== undefined) {
key = fontmap[fontName][fontStyle];
} else {
if (options.disableWarning === false) {
console.warn("Unable to look up font label for font '" + fontName + "', '" + fontStyle + "'. Refer to getFontList() for available fonts.");
}
}
if (!key && !options.noFallback) {
key = fontmap['times'][fontStyle];
if (key == null) {
key = fontmap['times']['normal'];
}
}
return key;
};
var putInfo = API.__private__.putInfo = function () {
newObject();
out('<<');
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]) + ')');
}
}
out('/CreationDate (' + creationDate + ')');
out('>>');
out('endobj');
};
var putCatalog = API.__private__.putCatalog = function (options) {
options = options || {};
var tmpRootDictionaryObjId = options.rootDictionaryObjId || rootDictionaryObjId;
newObject();
out('<<');
out('/Type /Catalog');
out('/Pages ' + tmpRootDictionaryObjId + ' 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');
out('>>');
out('endobj');
};
var putTrailer = API.__private__.putTrailer = function () {
out('trailer');
out('<<');
out('/Size ' + (objectNumber + 1));
out('/Root ' + objectNumber + ' 0 R');
out('/Info ' + (objectNumber - 1) + ' 0 R');
out("/ID [ <" + fileId + "> <" + fileId + "> ]");
out('>>');
};
var putHeader = API.__private__.putHeader = function () {
out('%PDF-' + pdfVersion);
out("%\xBA\xDF\xAC\xE0");
};
var putXRef = API.__private__.putXRef = function () {
var i = 1;
var p = "0000000000";
out('xref');
out('0 ' + (objectNumber + 1));
out('0000000000 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 {
if (typeof offsets[i] !== "undefined") {
out((p + offsets[i]).slice(-10) + ' 00000 n ');
} else {
out('0000000000 00000 n ');
}
}
}
};
var buildDocument = API.__private__.buildDocument = function () {
outToPages = false; // switches out() to content
//reset fields relevant for objectNumber generation and xref.
objectNumber = 0;
content_length = 0;
content = [];
offsets = [];
additionalObjects = [];
rootDictionaryObjId = newObjectDeferred();
resourceDictionaryObjId = newObjectDeferred();
events.publish('buildDocument');
putHeader();
putPages();
putAdditionalObjects();
putResources();
putInfo();
putCatalog();
var offsetOfXRef = content_length;
putXRef();
putTrailer();
out('startxref');
out('' + offsetOfXRef);
out('%%EOF');
outToPages = true;
return content.join('\n');
};
var getBlob = API.__private__.getBlob = function (data) {
return new Blob([getArrayBuffer(data)], {
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. Possible values are 'arraybuffer', 'blob', 'bloburi'/'bloburl', 'datauristring'/'dataurlstring', 'datauri'/'dataurl', 'dataurlnewwindow'.
* @param {Object} options An object providing some additional signalling to PDF generator. Possible options are 'filename'.
*
* @function
* @instance
* @returns {jsPDF}
* @memberOf jsPDF
* @name output
*/
var output = API.output = API.__private__.output = SAFE(function output(type, options) {
options = options || {};
var pdfDocument = buildDocument();
if (typeof options === "string") {
options = {
filename: options
};
} else {
options.filename = options.filename || 'generated.pdf';
}
switch (type) {
case undefined:
return pdfDocument;
case 'save':
API.save(options.filename);
break;
case 'arraybuffer':
return getArrayBuffer(pdfDocument);
case 'blob':
return getBlob(pdfDocument);
case 'bloburi':
case 'bloburl':
// Developer is responsible of calling revokeObjectURL
if (typeof global.URL !== "undefined" && typeof global.URL.createObjectURL === "function") {
return global.URL && global.URL.createObjectURL(getBlob(pdfDocument)) || void 0;
} else {
console.warn('bloburl is not supported by your system, because URL.createObjectURL is not supported by your browser.');
}
break;
case 'datauristring':
case 'dataurlstring':
return 'data:application/pdf;filename=' + options.filename + ';base64,' + btoa(pdfDocument);
case 'dataurlnewwindow':
var htmlForNewWindow = '' + '' + '' + '' + '';
var nW = global.open();
if (nW !== null) {
nW.document.write(htmlForNewWindow);
}
if (nW || typeof safari === "undefined") return nW;
/* pass through */
case 'datauri':
case 'dataurl':
return global.document.location.href = 'data:application/pdf;filename=' + options.filename + ';base64,' + btoa(pdfDocument);
default:
return null;
}
});
/**
* Used to see if a supplied hotfix was requested when the pdf instance was created.
* @param {string} hotfixName - The name of the hotfix to check.
* @returns {boolean}
*/
var hasHotfix = function hasHotfix(hotfixName) {
return Array.isArray(hotfixes) === true && hotfixes.indexOf(hotfixName) > -1;
};
switch (unit) {
case 'pt':
k = 1;
break;
case 'mm':
k = 72 / 25.4;
break;
case 'cm':
k = 72 / 2.54;
break;
case 'in':
k = 72;
break;
case 'px':
if (hasHotfix('px_scaling') == true) {
k = 72 / 96;
} else {
k = 96 / 72;
}
break;
case 'pc':
k = 12;
break;
case 'em':
k = 12;
break;
case 'ex':
k = 6;
break;
default:
throw new Error('Invalid unit: ' + unit);
}
setCreationDate();
setFileId(); //---------------------------------------
// Public API
var getPageInfo = API.__private__.getPageInfo = function (pageNumberOneBased) {
if (isNaN(pageNumberOneBased) || pageNumberOneBased % 1 !== 0) {
throw new Error('Invalid argument passed to jsPDF.getPageInfo');
}
var objId = pagesContext[pageNumberOneBased].objId;
return {
objId: objId,
pageNumber: pageNumberOneBased,
pageContext: pagesContext[pageNumberOneBased]
};
};
var getPageInfoByObjId = API.__private__.getPageInfoByObjId = function (objId) {
for (var pageNumber in pagesContext) {
if (pagesContext[pageNumber].objId === objId) {
break;
}
}
if (isNaN(objId) || objId % 1 !== 0) {
throw new Error('Invalid argument passed to jsPDF.getPageInfoByObjId');
}
return getPageInfo(pageNumber);
};
var getCurrentPageInfo = API.__private__.getCurrentPageInfo = function () {
return {
objId: pagesContext[currentPage].objId,
pageNumber: currentPage,
pageContext: pagesContext[currentPage]
};
};
/**
* Adds (and transfers the focus to) new page to the PDF document.
* @param format {String/Array} The format of the new page. Can be: - a0 - a10
- b0 - b10
- c0 - c10
- dl
- letter
- government-letter
- legal
- junior-legal
- ledger
- tabloid
- credit-card
* Default is "a4". If you want to use your own format just pass instead of one of the above predefined formats the size as an number-array, e.g. [595.28, 841.89]
* @param orientation {string} Orientation of the new page. Possible values are "portrait" or "landscape" (or shortcuts "p" (Default), "l").
* @function
* @instance
* @returns {jsPDF}
*
* @memberOf jsPDF
* @name addPage
*/
API.addPage = function () {
_addPage.apply(this, arguments);
return this;
};
/**
* Adds (and transfers the focus to) new page to the PDF document.
* @function
* @instance
* @returns {jsPDF}
*
* @memberOf jsPDF
* @name setPage
* @param {number} page Switch the active page to the page number specified.
* @example
* doc = jsPDF()
* doc.addPage()
* doc.addPage()
* doc.text('I am on page 3', 10, 10)
* doc.setPage(1)
* doc.text('I am on page 1', 10, 10)
*/
API.setPage = function () {
_setPage.apply(this, arguments);
return this;
};
/**
* @name insertPage
* @memberOf jsPDF
*
* @function
* @instance
* @param {Object} beforePage
* @returns {jsPDF}
*/
API.insertPage = function (beforePage) {
this.addPage();
this.movePage(currentPage, beforePage);
return this;
};
/**
* @name movePage
* @memberOf jsPDF
* @function
* @instance
* @param {Object} targetPage
* @param {Object} beforePage
* @returns {jsPDF}
*/
API.movePage = function (targetPage, beforePage) {
if (targetPage > beforePage) {
var tmpPages = pages[targetPage];
var tmpPagesContext = pagesContext[targetPage];
for (var i = targetPage; i > beforePage; i--) {
pages[i] = pages[i - 1];
pagesContext[i] = pagesContext[i - 1];
}
pages[beforePage] = tmpPages;
pagesContext[beforePage] = tmpPagesContext;
this.setPage(beforePage);
} else if (targetPage < beforePage) {
var tmpPages = pages[targetPage];
var tmpPagesContext = pagesContext[targetPage];
for (var i = targetPage; i < beforePage; i++) {
pages[i] = pages[i + 1];
pagesContext[i] = pagesContext[i + 1];
}
pages[beforePage] = tmpPages;
pagesContext[beforePage] = tmpPagesContext;
this.setPage(beforePage);
}
return this;
};
/**
* Deletes a page from the PDF.
* @name deletePage
* @memberOf jsPDF
* @function
* @instance
* @returns {jsPDF}
*/
API.deletePage = function () {
_deletePage.apply(this, arguments);
return this;
};
/**
* Adds text to page. Supports adding multiline text when 'text' argument is an Array of Strings.
*
* @function
* @instance
* @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} [options] - Collection of settings signaling how the text must be encoded.
* @param {string} [options.align=left] - The alignment of the text, possible values: left, center, right, justify.
* @param {string} [options.baseline=alphabetic] - Sets text baseline used when drawing the text, possible values: alphabetic, ideographic, bottom, top, middle.
* @param {string} [options.angle=0] - Rotate the text counterclockwise. Expects the angle in degree.
* @param {string} [options.charSpace=0] - The space between each letter.
* @param {string} [options.lineHeightFactor=1.15] - The lineheight of each line.
* @param {string} [options.flags] - Flags for to8bitStream.
* @param {string} [options.flags.noBOM=true] - Don't add BOM to Unicode-text.
* @param {string} [options.flags.autoencode=true] - Autoencode the Text.
* @param {string} [options.maxWidth=0] - Split the text by given width, 0 = no split.
* @param {string} [options.renderingMode=fill] - Set how the text should be rendered, possible values: fill, stroke, fillThenStroke, invisible, fillAndAddForClipping, strokeAndAddPathForClipping, fillThenStrokeAndAddToPathForClipping, addToPathForClipping.
* @returns {jsPDF}
* @memberOf jsPDF
* @name text
*/
var text = API.__private__.text = API.text = function (text, x, y, options) {
/**
* 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
*/
//backwardsCompatibility
var tmp; // 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' && typeof x === 'number' && (typeof y === 'string' || Array.isArray(y))) {
tmp = y;
y = x;
x = text;
text = tmp;
}
var flags = arguments[3];
var angle = arguments[4];
var align = arguments[5];
if (_typeof(flags) !== "object" || flags === null) {
if (typeof angle === 'string') {
align = angle;
angle = null;
}
if (typeof flags === 'string') {
align = flags;
flags = null;
}
if (typeof flags === 'number') {
angle = flags;
flags = null;
}
options = {
flags: flags,
angle: angle,
align: align
};
}
flags = flags || {};
flags.noBOM = flags.noBOM || true;
flags.autoencode = flags.autoencode || true;
if (isNaN(x) || isNaN(y) || typeof text === "undefined" || text === null) {
throw new Error('Invalid arguments passed to jsPDF.text');
}
if (text.length === 0) {
return scope;
}
var xtra = '';
var isHex = false;
var lineHeight = typeof options.lineHeightFactor === 'number' ? options.lineHeightFactor : lineHeightFactor;
var scope = options.scope || this;
function ESC(s) {
s = s.split("\t").join(Array(options.TabLen || 9).join(" "));
return pdfEscape(s, flags);
}
function transformTextToSpecialArray(text) {
//we don't want to destroy original text array, so cloning it
var sa = text.concat();
var da = [];
var len = sa.length;
var curDa; //we do array.join('text that must not be PDFescaped")
//thus, pdfEscape each component separately
while (len--) {
curDa = sa.shift();
if (typeof curDa === "string") {
da.push(curDa);
} else {
if (Array.isArray(text) && curDa.length === 1) {
da.push(curDa[0]);
} else {
da.push([curDa[0], curDa[1], curDa[2]]);
}
}
}
return da;
}
function processTextByFunction(text, processingFunction) {
var result;
if (typeof text === 'string') {
result = processingFunction(text)[0];
} else if (Array.isArray(text)) {
//we don't want to destroy original text array, so cloning it
var sa = text.concat();
var da = [];
var len = sa.length;
var curDa;
var tmpResult; //we do array.join('text that must not be PDFescaped")
//thus, pdfEscape each component separately
while (len--) {
curDa = sa.shift();
if (typeof curDa === "string") {
da.push(processingFunction(curDa)[0]);
} else if (Array.isArray(curDa) && curDa[0] === "string") {
tmpResult = processingFunction(curDa[0], curDa[1], curDa[2]);
da.push([tmpResult[0], tmpResult[1], tmpResult[2]]);
}
}
result = da;
}
return result;
} //Check if text is of type String
var textIsOfTypeString = false;
var tmpTextIsOfTypeString = true;
if (typeof text === 'string') {
textIsOfTypeString = true;
} else if (Array.isArray(text)) {
//we don't want to destroy original text array, so cloning it
var sa = text.concat();
var da = [];
var len = sa.length;
var curDa; //we do array.join('text that must not be PDFescaped")
//thus, pdfEscape each component separately
while (len--) {
curDa = sa.shift();
if (typeof curDa !== "string" || Array.isArray(curDa) && typeof curDa[0] !== "string") {
tmpTextIsOfTypeString = false;
}
}
textIsOfTypeString = tmpTextIsOfTypeString;
}
if (textIsOfTypeString === false) {
throw new Error('Type of text must be string or Array. "' + text + '" is not recognized.');
} //Escaping
var activeFontEncoding = fonts[activeFontKey].encoding;
if (activeFontEncoding === "WinAnsiEncoding" || activeFontEncoding === "StandardEncoding") {
text = processTextByFunction(text, function (text, posX, posY) {
return [ESC(text), posX, posY];
});
} //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.
//Convert text into an array anyway to simplify
//later code.
if (typeof text === 'string') {
if (text.match(/[\r?\n]/)) {
text = text.split(/\r\n|\r|\n/g);
} else {
text = [text];
}
} //baseline
var height = activeFontSize / scope.internal.scaleFactor;
var descent = height * (lineHeightFactor - 1);
switch (options.baseline) {
case 'bottom':
y -= descent;
break;
case 'top':
y += height - descent;
break;
case 'hanging':
y += height - 2 * descent;
break;
case 'middle':
y += height / 2 - descent;
break;
case 'ideographic':
case 'alphabetic':
default:
// do nothing, everything is fine
break;
} //multiline
var maxWidth = options.maxWidth || 0;
if (maxWidth > 0) {
if (typeof text === 'string') {
text = scope.splitTextToSize(text, maxWidth);
} else if (Object.prototype.toString.call(text) === '[object Array]') {
text = scope.splitTextToSize(text.join(" "), maxWidth);
}
} //creating Payload-Object to make text byRef
var payload = {
text: text,
x: x,
y: y,
options: options,
mutex: {
pdfEscape: pdfEscape,
activeFontKey: activeFontKey,
fonts: fonts,
activeFontSize: activeFontSize
}
};
events.publish('preProcessText', payload);
text = payload.text;
options = payload.options; //angle
var angle = options.angle;
var k = scope.internal.scaleFactor;
var transformationMatrix = [];
if (angle) {
angle *= Math.PI / 180;
var c = Math.cos(angle),
s = Math.sin(angle);
transformationMatrix = [f2(c), f2(s), f2(s * -1), f2(c)];
} //charSpace
var charSpace = options.charSpace;
if (typeof charSpace !== 'undefined') {
xtra += f3(charSpace * k) + " Tc\n";
} //lang
var lang = options.lang;
var tmpRenderingMode = -1;
var parmRenderingMode = typeof options.renderingMode !== "undefined" ? options.renderingMode : options.stroke;
var pageContext = scope.internal.getCurrentPageInfo().pageContext;
switch (parmRenderingMode) {
case 0:
case false:
case 'fill':
tmpRenderingMode = 0;
break;
case 1:
case true:
case 'stroke':
tmpRenderingMode = 1;
break;
case 2:
case 'fillThenStroke':
tmpRenderingMode = 2;
break;
case 3:
case 'invisible':
tmpRenderingMode = 3;
break;
case 4:
case 'fillAndAddForClipping':
tmpRenderingMode = 4;
break;
case 5:
case 'strokeAndAddPathForClipping':
tmpRenderingMode = 5;
break;
case 6:
case 'fillThenStrokeAndAddToPathForClipping':
tmpRenderingMode = 6;
break;
case 7:
case 'addToPathForClipping':
tmpRenderingMode = 7;
break;
}
var usedRenderingMode = typeof pageContext.usedRenderingMode !== 'undefined' ? pageContext.usedRenderingMode : -1; //if the coder wrote it explicitly to use a specific
//renderingMode, then use it
if (tmpRenderingMode !== -1) {
xtra += tmpRenderingMode + " Tr\n"; //otherwise check if we used the rendering Mode already
//if so then set the rendering Mode...
} else if (usedRenderingMode !== -1) {
xtra += "0 Tr\n";
}
if (tmpRenderingMode !== -1) {
pageContext.usedRenderingMode = tmpRenderingMode;
} //align
var align = options.align || 'left';
var leading = activeFontSize * lineHeight;
var pageWidth = scope.internal.pageSize.getWidth();
var k = scope.internal.scaleFactor;
var activeFont = fonts[activeFontKey];
var charSpace = options.charSpace || activeCharSpace;
var maxWidth = options.maxWidth || 0;
var lineWidths;
var flags = {};
var wordSpacingPerLine = [];
if (Object.prototype.toString.call(text) === '[object Array]') {
var da = transformTextToSpecialArray(text);
var newY;
var maxLineLength;
var lineWidths;
if (align !== "left") {
lineWidths = da.map(function (v) {
return scope.getStringUnitWidth(v, {
font: activeFont,
charSpace: charSpace,
fontSize: activeFontSize
}) * activeFontSize / k;
});
}
var maxLineLength = Math.max.apply(Math, lineWidths); //The first line uses the "main" Td setting,
//and the subsequent lines are offset by the
//previous line's x coordinate.
var prevWidth = 0;
var delta;
var newX;
if (align === "right") {
x -= lineWidths[0];
text = [];
for (var i = 0, len = da.length; i < len; i++) {
delta = maxLineLength - lineWidths[i];
if (i === 0) {
newX = getHorizontalCoordinate(x);
newY = getVerticalCoordinate(y);
} else {
newX = (prevWidth - lineWidths[i]) * k;
newY = -leading;
}
text.push([da[i], newX, newY]);
prevWidth = lineWidths[i];
}
} else if (align === "center") {
x -= lineWidths[0] / 2;
text = [];
for (var i = 0, len = da.length; i < len; i++) {
delta = (maxLineLength - lineWidths[i]) / 2;
if (i === 0) {
newX = getHorizontalCoordinate(x);
newY = getVerticalCoordinate(y);
} else {
newX = (prevWidth - lineWidths[i]) / 2 * k;
newY = -leading;
}
text.push([da[i], newX, newY]);
prevWidth = lineWidths[i];
}
} else if (align === "left") {
text = [];
for (var i = 0, len = da.length; i < len; i++) {
newY = i === 0 ? getVerticalCoordinate(y) : -leading;
newX = i === 0 ? getHorizontalCoordinate(x) : 0; //text.push([da[i], newX, newY]);
text.push(da[i]);
}
} else if (align === "justify") {
text = [];
var maxWidth = maxWidth !== 0 ? maxWidth : pageWidth;
for (var i = 0, len = da.length; i < len; i++) {
newY = i === 0 ? getVerticalCoordinate(y) : -leading;
newX = i === 0 ? getHorizontalCoordinate(x) : 0;
if (i < len - 1) {
wordSpacingPerLine.push(((maxWidth - lineWidths[i]) / (da[i].split(" ").length - 1) * k).toFixed(2));
}
text.push([da[i], newX, newY]);
}
} else {
throw new Error('Unrecognized alignment option, use "left", "center", "right" or "justify".');
}
} //R2L
var doReversing = typeof options.R2L === "boolean" ? options.R2L : R2L;
if (doReversing === true) {
text = processTextByFunction(text, function (text, posX, posY) {
return [text.split("").reverse().join(""), posX, posY];
});
} //creating Payload-Object to make text byRef
var payload = {
text: text,
x: x,
y: y,
options: options,
mutex: {
pdfEscape: pdfEscape,
activeFontKey: activeFontKey,
fonts: fonts,
activeFontSize: activeFontSize
}
};
events.publish('postProcessText', payload);
text = payload.text;
isHex = payload.mutex.isHex;
var da = transformTextToSpecialArray(text);
text = [];
var variant = 0;
var len = da.length;
var posX;
var posY;
var content;
var wordSpacing = '';
for (var i = 0; i < len; i++) {
wordSpacing = '';
if (!Array.isArray(da[i])) {
posX = getHorizontalCoordinate(x);
posY = getVerticalCoordinate(y);
content = (isHex ? "<" : "(") + da[i] + (isHex ? ">" : ")");
} else {
posX = parseFloat(da[i][1]);
posY = parseFloat(da[i][2]);
content = (isHex ? "<" : "(") + da[i][0] + (isHex ? ">" : ")");
variant = 1;
}
if (wordSpacingPerLine !== undefined && wordSpacingPerLine[i] !== undefined) {
wordSpacing = wordSpacingPerLine[i] + " Tw\n";
}
if (transformationMatrix.length !== 0 && i === 0) {
text.push(wordSpacing + transformationMatrix.join(" ") + " " + posX.toFixed(2) + " " + posY.toFixed(2) + " Tm\n" + content);
} else if (variant === 1 || variant === 0 && i === 0) {
text.push(wordSpacing + posX.toFixed(2) + " " + posY.toFixed(2) + " Td\n" + content);
} else {
text.push(wordSpacing + content);
}
}
if (variant === 0) {
text = text.join(" Tj\nT* ");
} else {
text = text.join(" Tj\n");
}
text += " Tj\n";
var result = 'BT\n/' + activeFontKey + ' ' + activeFontSize + ' Tf\n' + // font face, style, size
(activeFontSize * lineHeight).toFixed(2) + ' TL\n' + // line spacing
textColor + '\n';
result += xtra;
result += text;
result += "ET";
out(result);
usedFonts[activeFontKey] = true;
return scope;
};
/**
* Letter spacing method to print text with gaps
*
* @function
* @instance
* @param {String|Array} text String to be added to the page.
* @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} spacing Spacing (in units declared at inception)
* @returns {jsPDF}
* @memberOf jsPDF
* @name lstext
* @deprecated We'll be removing this function. It doesn't take character width into account.
*/
var lstext = API.__private__.lstext = API.lstext = function (text, x, y, charSpace) {
console.warn('jsPDF.lstext is deprecated');
return this.text(text, x, y, {
charSpace: charSpace
});
};
/**
*
* @name clip
* @function
* @instance
* @param {string} rule
* @returns {jsPDF}
* @memberOf jsPDF
* @description All .clip() after calling drawing ops with a style argument of null.
*/
var clip = API.__private__.clip = API.clip = function (rule) {
// Call .clip() after calling drawing ops with a style argument of null
// W is the PDF clipping op
if ('evenodd' === rule) {
out('W*');
} else {
out('W');
} // End the path object without filling or stroking it.
// This operator is a path-painting no-op, used primarily for the side effect of changing the current clipping path
// (see Section 4.4.3, “Clipping Path Operators”)
out('n');
};
/**
* This fixes the previous function clip(). Perhaps the 'stroke path' hack was due to the missing 'n' instruction?
* We introduce the fixed version so as to not break API.
* @param fillRule
* @ignore
*/
var clip_fixed = API.__private__.clip_fixed = API.clip_fixed = function (rule) {
console.log("clip_fixed is deprecated");
API.clip(rule);
};
var isValidStyle = API.__private__.isValidStyle = function (style) {
var validStyleVariants = [undefined, null, 'S', 'F', 'DF', 'FD', 'f', 'f*', 'B', 'B*'];
var result = false;
if (validStyleVariants.indexOf(style) !== -1) {
result = true;
}
return result;
};
var getStyle = API.__private__.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;
};
/**
* Draw a line on the current page.
*
* @name line
* @function
* @instance
* @param {number} x1
* @param {number} y1
* @param {number} x2
* @param {number} y2
* @returns {jsPDF}
* @memberOf jsPDF
*/
var line = API.__private__.line = API.line = function (x1, y1, x2, y2) {
if (isNaN(x1) || isNaN(y1) || isNaN(x2) || isNaN(y2)) {
throw new Error('Invalid arguments passed to jsPDF.line');
}
return this.lines([[x2 - x1, y2 - y1]], x1, y1);
};
/**
* 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, [1,1], 'F', false) // 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
* @instance
* @returns {jsPDF}
* @memberOf jsPDF
* @name lines
*/
var lines = API.__private__.lines = API.lines = function (lines, x, y, scale, style, closed) {
var scalex, scaley, i, l, leg, x2, y2, x3, y3, x4, y4, tmp; // 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];
closed = closed || false;
if (isNaN(x) || isNaN(y) || !Array.isArray(lines) || !Array.isArray(scale) || !isValidStyle(style) || typeof closed !== 'boolean') {
throw new Error('Invalid arguments passed to jsPDF.lines');
} // starting point
out(f3(getHorizontalCoordinate(x)) + ' ' + f3(getVerticalCoordinate(y)) + ' 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(getHorizontalCoordinate(x4)) + ' ' + f3(getVerticalCoordinate(y4)) + ' 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(getHorizontalCoordinate(x2)) + ' ' + f3(getVerticalCoordinate(y2)) + ' ' + f3(getHorizontalCoordinate(x3)) + ' ' + f3(getVerticalCoordinate(y3)) + ' ' + f3(getHorizontalCoordinate(x4)) + ' ' + f3(getVerticalCoordinate(y4)) + ' 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
* @instance
* @returns {jsPDF}
* @memberOf jsPDF
* @name rect
*/
var rect = API.__private__.rect = API.rect = function (x, y, w, h, style) {
if (isNaN(x) || isNaN(y) || isNaN(w) || isNaN(h) || !isValidStyle(style)) {
throw new Error('Invalid arguments passed to jsPDF.rect');
}
out([f2(getHorizontalCoordinate(x)), f2(getVerticalCoordinate(y)), 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
* @instance
* @returns {jsPDF}
* @memberOf jsPDF
* @name triangle
*/
var triangle = API.__private__.triangle = API.triangle = function (x1, y1, x2, y2, x3, y3, style) {
if (isNaN(x1) || isNaN(y1) || isNaN(x2) || isNaN(y2) || isNaN(x3) || isNaN(y3) || !isValidStyle(style)) {
throw new Error('Invalid arguments passed to jsPDF.triangle');
}
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} ry 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
* @instance
* @returns {jsPDF}
* @memberOf jsPDF
* @name roundedRect
*/
var roundedRect = API.__private__.roundedRect = API.roundedRect = function (x, y, w, h, rx, ry, style) {
if (isNaN(x) || isNaN(y) || isNaN(w) || isNaN(h) || isNaN(rx) || isNaN(ry) || !isValidStyle(style)) {
throw new Error('Invalid arguments passed to jsPDF.roundedRect');
}
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} ry 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
* @instance
* @returns {jsPDF}
* @memberOf jsPDF
* @name ellipse
*/
var ellise = API.__private__.ellipse = API.ellipse = function (x, y, rx, ry, style) {
if (isNaN(x) || isNaN(y) || isNaN(rx) || isNaN(ry) || !isValidStyle(style)) {
throw new Error('Invalid arguments passed to jsPDF.ellipse');
}
var lx = 4 / 3 * (Math.SQRT2 - 1) * rx,
ly = 4 / 3 * (Math.SQRT2 - 1) * ry;
out([f2(getHorizontalCoordinate(x + rx)), f2(getVerticalCoordinate(y)), 'm', f2(getHorizontalCoordinate(x + rx)), f2(getVerticalCoordinate(y - ly)), f2(getHorizontalCoordinate(x + lx)), f2(getVerticalCoordinate(y - ry)), f2(getHorizontalCoordinate(x)), f2(getVerticalCoordinate(y - ry)), 'c'].join(' '));
out([f2(getHorizontalCoordinate(x - lx)), f2(getVerticalCoordinate(y - ry)), f2(getHorizontalCoordinate(x - rx)), f2(getVerticalCoordinate(y - ly)), f2(getHorizontalCoordinate(x - rx)), f2(getVerticalCoordinate(y)), 'c'].join(' '));
out([f2(getHorizontalCoordinate(x - rx)), f2(getVerticalCoordinate(y + ly)), f2(getHorizontalCoordinate(x - lx)), f2(getVerticalCoordinate(y + ry)), f2(getHorizontalCoordinate(x)), f2(getVerticalCoordinate(y + ry)), 'c'].join(' '));
out([f2(getHorizontalCoordinate(x + lx)), f2(getVerticalCoordinate(y + ry)), f2(getHorizontalCoordinate(x + rx)), f2(getVerticalCoordinate(y + ly)), f2(getHorizontalCoordinate(x + rx)), f2(getVerticalCoordinate(y)), '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
* @instance
* @returns {jsPDF}
* @memberOf jsPDF
* @name circle
*/
var circle = API.__private__.circle = API.circle = function (x, y, r, style) {
if (isNaN(x) || isNaN(y) || isNaN(r) || !isValidStyle(style)) {
throw new Error('Invalid arguments passed to jsPDF.circle');
}
return this.ellipse(x, y, r, r, style);
};
/**
* 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
* @instance
* @returns {jsPDF}
* @memberOf jsPDF
* @name setFont
*/
API.setFont = function (fontName, fontStyle) {
activeFontKey = _getFont(fontName, fontStyle, {
disableWarning: false
});
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
* @instance
* @returns {jsPDF}
* @memberOf 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
* @instance
* @returns {Object} Like {'times':['normal', 'italic', ... ], 'arial':['normal', 'bold', ... ], ... }
* @memberOf jsPDF
* @name getFontList
*/
var getFontList = API.__private__.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 to the current instance.
*
* @property {string} postScriptName PDF specification full name for the font.
* @property {string} id PDF-document-instance-specific label assinged to the font.
* @property {string} fontStyle Style of the Font.
* @property {Object} encoding Encoding_name-to-Font_metrics_object mapping.
* @function
* @instance
* @memberOf jsPDF
* @name addFont
*/
API.addFont = function (postScriptName, fontName, fontStyle, encoding) {
encoding = encoding || 'Identity-H';
addFont.call(this, postScriptName, fontName, fontStyle, encoding);
};
var lineWidth = options.lineWidth || 0.200025; // 2mm
/**
* Sets line width for upcoming lines.
*
* @param {number} width Line width (in units declared at inception of PDF document).
* @function
* @instance
* @returns {jsPDF}
* @memberOf jsPDF
* @name setLineWidth
*/
var setLineWidth = API.__private__.setLineWidth = API.setLineWidth = function (width) {
out((width * k).toFixed(2) + ' w');
return this;
};
/**
* Sets the dash pattern for upcoming lines.
*
* To reset the settings simply call the method without any parameters.
* @param {array} dashArray The pattern of the line, expects numbers.
* @param {number} dashPhase The phase at which the dash pattern starts.
* @function
* @instance
* @returns {jsPDF}
* @memberOf jsPDF
* @name setLineDash
*/
var setLineDash = API.__private__.setLineDash = jsPDF.API.setLineDash = function (dashArray, dashPhase) {
dashArray = dashArray || [];
dashPhase = dashPhase || 0;
if (isNaN(dashPhase) || !Array.isArray(dashArray)) {
throw new Error('Invalid arguments passed to jsPDF.setLineDash');
}
dashArray = dashArray.map(function (x) {
return (x * k).toFixed(3);
}).join(' ');
dashPhase = parseFloat((dashPhase * k).toFixed(3));
out('[' + dashArray + '] ' + dashPhase + ' d');
return this;
};
var lineHeightFactor;
var getLineHeight = API.__private__.getLineHeight = API.getLineHeight = function () {
return activeFontSize * lineHeightFactor;
};
var lineHeightFactor;
var getLineHeight = API.__private__.getLineHeight = API.getLineHeight = function () {
return activeFontSize * lineHeightFactor;
};
/**
* Sets the LineHeightFactor of proportion.
*
* @param {number} value LineHeightFactor value. Default: 1.15.
* @function
* @instance
* @returns {jsPDF}
* @memberOf jsPDF
* @name setLineHeightFactor
*/
var setLineHeightFactor = API.__private__.setLineHeightFactor = API.setLineHeightFactor = function (value) {
value = value || 1.15;
if (typeof value === "number") {
lineHeightFactor = value;
}
return this;
};
/**
* Gets the LineHeightFactor, default: 1.15.
*
* @function
* @instance
* @returns {number} lineHeightFactor
* @memberOf jsPDF
* @name getLineHeightFactor
*/
var getLineHeightFactor = API.__private__.getLineHeightFactor = API.getLineHeightFactor = function () {
return lineHeightFactor;
};
setLineHeightFactor(options.lineHeight);
var getHorizontalCoordinate = API.__private__.getHorizontalCoordinate = function (value) {
return value * k;
};
var getVerticalCoordinate = API.__private__.getVerticalCoordinate = function (value) {
return pagesContext[currentPage].mediaBox.topRightY - pagesContext[currentPage].mediaBox.bottomLeftY - value * k;
};
var getHorizontalCoordinateString = API.__private__.getHorizontalCoordinateString = function (value) {
return f2(value * k);
};
var getVerticalCoordinateString = API.__private__.getVerticalCoordinateString = function (value) {
return f2(pagesContext[currentPage].mediaBox.topRightY - pagesContext[currentPage].mediaBox.bottomLeftY - value * k);
};
var strokeColor = options.strokeColor || '0 G';
/**
* Gets the stroke color for upcoming elements.
*
* @function
* @instance
* @returns {string} colorAsHex
* @memberOf jsPDF
* @name getDrawColor
*/
var getStrokeColor = API.__private__.getStrokeColor = API.getDrawColor = function () {
return decodeColorString(strokeColor);
};
/**
* 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 or {string} ch1 color value in hexadecimal, example: '#FFFFFF'.
* @param {Number|String} ch2 Color channel value.
* @param {Number|String} ch3 Color channel value.
* @param {Number|String} ch4 Color channel value.
*
* @function
* @instance
* @returns {jsPDF}
* @memberOf jsPDF
* @name setDrawColor
*/
var setStrokeColor = API.__private__.setStrokeColor = API.setDrawColor = function (ch1, ch2, ch3, ch4) {
var options = {
"ch1": ch1,
"ch2": ch2,
"ch3": ch3,
"ch4": ch4,
"pdfColorType": "draw",
"precision": 2
};
strokeColor = encodeColorString(options);
out(strokeColor);
return this;
};
var fillColor = options.fillColor || '0 g';
/**
* Gets the fill color for upcoming elements.
*
* @function
* @instance
* @returns {string} colorAsHex
* @memberOf jsPDF
* @name getFillColor
*/
var getFillColor = API.__private__.getFillColor = API.getFillColor = function () {
return decodeColorString(fillColor);
};
/**
* 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 or {string} ch1 color value in hexadecimal, example: '#FFFFFF'.
* @param {Number|String} ch2 Color channel value.
* @param {Number|String} ch3 Color channel value.
* @param {Number|String} ch4 Color channel value.
*
* @function
* @instance
* @returns {jsPDF}
* @memberOf jsPDF
* @name setFillColor
*/
var setFillColor = API.__private__.setFillColor = API.setFillColor = function (ch1, ch2, ch3, ch4) {
var options = {
"ch1": ch1,
"ch2": ch2,
"ch3": ch3,
"ch4": ch4,
"pdfColorType": "fill",
"precision": 2
};
fillColor = encodeColorString(options);
out(fillColor);
return this;
};
var textColor = options.textColor || '0 g';
/**
* Gets the text color for upcoming elements.
*
* @function
* @instance
* @returns {string} colorAsHex
* @memberOf jsPDF
* @name getTextColor
*/
var getTextColor = API.__private__.getTextColor = API.getTextColor = function () {
return decodeColorString(textColor);
};
/**
* Sets the text 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 or {string} ch1 color value in hexadecimal, example: '#FFFFFF'.
* @param {Number|String} ch2 Color channel value.
* @param {Number|String} ch3 Color channel value.
* @param {Number|String} ch4 Color channel value.
*
* @function
* @instance
* @returns {jsPDF}
* @memberOf jsPDF
* @name setTextColor
*/
var setTextColor = API.__private__.setTextColor = API.setTextColor = function (ch1, ch2, ch3, ch4) {
var options = {
"ch1": ch1,
"ch2": ch2,
"ch3": ch3,
"ch4": ch4,
"pdfColorType": "text",
"precision": 3
};
textColor = encodeColorString(options);
return this;
};
var activeCharSpace = options.charSpace || 0;
/**
* Get global value of CharSpace.
*
* @function
* @instance
* @returns {number} charSpace
* @memberOf jsPDF
* @name getCharSpace
*/
var getCharSpace = API.__private__.getCharSpace = API.getCharSpace = function () {
return activeCharSpace;
};
/**
* Set global value of CharSpace.
*
* @param {number} charSpace
* @function
* @instance
* @returns {jsPDF} jsPDF-instance
* @memberOf jsPDF
* @name setCharSpace
*/
var setCharSpace = API.__private__.setCharSpace = API.setCharSpace = function (charSpace) {
if (isNaN(charSpace)) {
throw new Error('Invalid argument passed to jsPDF.setCharSpace');
}
activeCharSpace = charSpace;
return this;
};
var lineCapID = 0;
/**
* Is an Object providing a mapping from human-readable to
* integer flag values designating the varieties of line cap
* and join styles.
*
* @memberOf 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
* @instance
* @returns {jsPDF}
* @memberOf jsPDF
* @name setLineCap
*/
var setLineCap = API.__private__.setLineCap = API.setLineCap = function (style) {
var id = API.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;
};
var lineJoinID = 0;
/**
* 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
* @instance
* @returns {jsPDF}
* @memberOf jsPDF
* @name setLineJoin
*/
var setLineJoin = API.__private__.setLineJoin = API.setLineJoin = function (style) {
var id = API.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;
};
var miterLimit;
/**
* Sets the miterLimit property, which effects the maximum miter length.
*
* @param {number} length The length of the miter
* @function
* @instance
* @returns {jsPDF}
* @memberOf jsPDF
* @name setMiterLimit
*/
var setMiterLimit = API.__private__.setMiterLimit = API.setMiterLimit = function (length) {
length = length || 0;
if (isNaN(length)) {
throw new Error('Invalid argument passed to jsPDF.setMiterLimit');
}
miterLimit = parseFloat(f2(length * k));
out(miterLimit + ' M');
return this;
};
/**
* Saves as PDF document. An alias of jsPDF.output('save', 'filename.pdf').
* Uses FileSaver.js-method saveAs.
*
* @memberOf jsPDF
* @name save
* @function
* @instance
* @param {string} filename The filename including extension.
* @param {Object} options An Object with additional options, possible options: 'returnPromise'.
* @returns {jsPDF} jsPDF-instance
*/
API.save = function (filename, options) {
filename = filename || 'generated.pdf';
options = options || {};
options.returnPromise = options.returnPromise || false;
if (options.returnPromise === false) {
saveAs(getBlob(buildDocument()), filename);
if (typeof saveAs.unload === 'function') {
if (global.setTimeout) {
setTimeout(saveAs.unload, 911);
}
}
} else {
return new Promise(function (resolve, reject) {
try {
var result = saveAs(getBlob(buildDocument()), filename);
if (typeof saveAs.unload === 'function') {
if (global.setTimeout) {
setTimeout(saveAs.unload, 911);
}
}
resolve(result);
} catch (e) {
reject(e.message);
}
});
}
}; // 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];
}
}
}
/**
* Object exposing internal API to plugins
* @public
* @ignore
*/
API.internal = {
'pdfEscape': pdfEscape,
'getStyle': getStyle,
'getFont': function getFont() {
return fonts[_getFont.apply(API, arguments)];
},
'getFontSize': getFontSize,
'getCharSpace': getCharSpace,
'getTextColor': getTextColor,
'getLineHeight': getLineHeight,
'getLineHeightFactor': getLineHeightFactor,
'write': write,
'getHorizontalCoordinate': getHorizontalCoordinate,
'getVerticalCoordinate': getVerticalCoordinate,
'getCoordinateString': getHorizontalCoordinateString,
'getVerticalCoordinateString': getVerticalCoordinateString,
'collections': {},
'newObject': newObject,
'newAdditionalObject': newAdditionalObject,
'newObjectDeferred': newObjectDeferred,
'newObjectDeferredBegin': newObjectDeferredBegin,
'getFilters': getFilters,
'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': {
getWidth: function getWidth() {
return (pagesContext[currentPage].mediaBox.topRightX - pagesContext[currentPage].mediaBox.bottomLeftX) / k;
},
setWidth: function setWidth(value) {
pagesContext[currentPage].mediaBox.topRightX = value * k + pagesContext[currentPage].mediaBox.bottomLeftX;
},
getHeight: function getHeight() {
return (pagesContext[currentPage].mediaBox.topRightY - pagesContext[currentPage].mediaBox.bottomLeftY) / k;
},
setHeight: function setHeight(value) {
pagesContext[currentPage].mediaBox.topRightY = value * k + pagesContext[currentPage].mediaBox.bottomLeftY;
}
},
'output': output,
'getNumberOfPages': getNumberOfPages,
'pages': pages,
'out': out,
'f2': f2,
'f3': f3,
'getPageInfo': getPageInfo,
'getPageInfoByObjId': getPageInfoByObjId,
'getCurrentPageInfo': getCurrentPageInfo,
'getPDFVersion': getPdfVersion,
'hasHotfix': hasHotfix //Expose the hasHotfix check so plugins can also check them.
};
Object.defineProperty(API.internal.pageSize, 'width', {
get: function get() {
return (pagesContext[currentPage].mediaBox.topRightX - pagesContext[currentPage].mediaBox.bottomLeftX) / k;
},
set: function set(value) {
pagesContext[currentPage].mediaBox.topRightX = value * k + pagesContext[currentPage].mediaBox.bottomLeftX;
},
enumerable: true,
configurable: true
});
Object.defineProperty(API.internal.pageSize, 'height', {
get: function get() {
return (pagesContext[currentPage].mediaBox.topRightY - pagesContext[currentPage].mediaBox.bottomLeftY) / k;
},
set: function set(value) {
pagesContext[currentPage].mediaBox.topRightY = value * k + pagesContext[currentPage].mediaBox.bottomLeftY;
},
enumerable: true,
configurable: true
}); //////////////////////////////////////////////////////
// continuing initialization of jsPDF Document object
//////////////////////////////////////////////////////
// Add the first page automatically
addFonts(standardFonts);
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.
*
* @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: []
};
/**
* The version of jsPDF.
* @name version
* @type {string}
* @memberOf jsPDF
*/
jsPDF.version = '1.5.3';
if (typeof define === 'function' && define.amd) {
define('jsPDF', function () {
return jsPDF;
});
} else if (typeof module !== 'undefined' && module.exports) {
module.exports = jsPDF;
module.exports.jsPDF = jsPDF;
} else {
global.jsPDF = jsPDF;
}
return jsPDF;
}(typeof self !== "undefined" && self || typeof window !== "undefined" && window || typeof global !== "undefined" && global || Function('return typeof this === "object" && this.content')() || Function('return this')()); // `self` is undefined in Firefox for Android content script context
// while `this` is nsIContentFrameMessageManager
// with an attribute `content` that corresponds to the window
/*rollup-keeper-start*/
window.tmp = jsPDF;
/*rollup-keeper-end*/
/**
* @license
* Copyright (c) 2016 Alexander Weidt,
* https://github.com/BiggA94
*
* Licensed under the MIT License. http://opensource.org/licenses/mit-license
*/
/**
* jsPDF AcroForm Plugin
* @module AcroForm
*/
(function (jsPDFAPI, globalObj) {
var scope;
var scaleFactor = 1;
var pdfEscape = function pdfEscape(value) {
return value.replace(/\\/g, '\\\\').replace(/\(/g, '\\(').replace(/\)/g, '\\)');
};
var pdfUnescape = function pdfUnescape(value) {
return value.replace(/\\\\/g, '\\').replace(/\\\(/g, '(').replace(/\\\)/g, ')');
};
var f2 = function f2(number) {
if (isNaN(number)) {
throw new Error('Invalid argument passed to jsPDF.f2');
}
return number.toFixed(2); // Ie, %.2f
};
var f5 = function f5(number) {
if (isNaN(number)) {
throw new Error('Invalid argument passed to jsPDF.f2');
}
return number.toFixed(5); // Ie, %.2f
};
jsPDFAPI.__acroform__ = {};
var inherit = function inherit(child, parent) {
child.prototype = Object.create(parent.prototype);
child.prototype.constructor = child;
};
var scale = function scale(x) {
return x * scaleFactor;
};
var antiScale = function antiScale(x) {
return x / scaleFactor;
};
var createFormXObject = function createFormXObject(formObject) {
var xobj = new AcroFormXObject();
var height = AcroFormAppearance.internal.getHeight(formObject) || 0;
var width = AcroFormAppearance.internal.getWidth(formObject) || 0;
xobj.BBox = [0, 0, Number(f2(width)), Number(f2(height))];
return xobj;
};
/**
* Bit-Operations
*/
var setBit = jsPDFAPI.__acroform__.setBit = function (number, bitPosition) {
number = number || 0;
bitPosition = bitPosition || 0;
if (isNaN(number) || isNaN(bitPosition)) {
throw new Error('Invalid arguments passed to jsPDF.API.__acroform__.setBit');
}
var bitMask = 1 << bitPosition;
number |= bitMask;
return number;
};
var clearBit = jsPDFAPI.__acroform__.clearBit = function (number, bitPosition) {
number = number || 0;
bitPosition = bitPosition || 0;
if (isNaN(number) || isNaN(bitPosition)) {
throw new Error('Invalid arguments passed to jsPDF.API.__acroform__.clearBit');
}
var bitMask = 1 << bitPosition;
number &= ~bitMask;
return number;
};
var getBit = jsPDFAPI.__acroform__.getBit = function (number, bitPosition) {
if (isNaN(number) || isNaN(bitPosition)) {
throw new Error('Invalid arguments passed to jsPDF.API.__acroform__.getBit');
}
return (number & 1 << bitPosition) === 0 ? 0 : 1;
};
/*
* Ff starts counting the bit position at 1 and not like javascript at 0
*/
var getBitForPdf = jsPDFAPI.__acroform__.getBitForPdf = function (number, bitPosition) {
if (isNaN(number) || isNaN(bitPosition)) {
throw new Error('Invalid arguments passed to jsPDF.API.__acroform__.getBitForPdf');
}
return getBit(number, bitPosition - 1);
};
var setBitForPdf = jsPDFAPI.__acroform__.setBitForPdf = function (number, bitPosition) {
if (isNaN(number) || isNaN(bitPosition)) {
throw new Error('Invalid arguments passed to jsPDF.API.__acroform__.setBitForPdf');
}
return setBit(number, bitPosition - 1);
};
var clearBitForPdf = jsPDFAPI.__acroform__.clearBitForPdf = function (number, bitPosition, value) {
if (isNaN(number) || isNaN(bitPosition)) {
throw new Error('Invalid arguments passed to jsPDF.API.__acroform__.clearBitForPdf');
}
return clearBit(number, bitPosition - 1);
};
var calculateCoordinates = jsPDFAPI.__acroform__.calculateCoordinates = function (args) {
var getHorizontalCoordinate = this.internal.getHorizontalCoordinate;
var getVerticalCoordinate = this.internal.getVerticalCoordinate;
var x = args[0];
var y = args[1];
var w = args[2];
var h = args[3];
var coordinates = {};
coordinates.lowerLeft_X = getHorizontalCoordinate(x) || 0;
coordinates.lowerLeft_Y = getVerticalCoordinate(y + h) || 0;
coordinates.upperRight_X = getHorizontalCoordinate(x + w) || 0;
coordinates.upperRight_Y = getVerticalCoordinate(y) || 0;
return [Number(f2(coordinates.lowerLeft_X)), Number(f2(coordinates.lowerLeft_Y)), Number(f2(coordinates.upperRight_X)), Number(f2(coordinates.upperRight_Y))];
};
var calculateAppearanceStream = function calculateAppearanceStream(formObject) {
if (formObject.appearanceStreamContent) {
return formObject.appearanceStreamContent;
}
if (!formObject.V && !formObject.DV) {
return;
} // else calculate it
var stream = [];
var text = formObject.V || formObject.DV;
var calcRes = calculateX(formObject, text);
var fontKey = scope.internal.getFont(formObject.fontName, formObject.fontStyle).id; //PDF 32000-1:2008, page 444
stream.push('/Tx BMC');
stream.push('q');
stream.push('BT'); // Begin Text
stream.push(scope.__private__.encodeColorString(formObject.color));
stream.push('/' + fontKey + ' ' + f2(calcRes.fontSize) + ' Tf');
stream.push('1 0 0 1 0 0 Tm'); // Transformation Matrix
stream.push(calcRes.text);
stream.push('ET'); // End Text
stream.push('Q');
stream.push('EMC');
var appearanceStreamContent = new createFormXObject(formObject);
appearanceStreamContent.stream = stream.join("\n");
return appearanceStreamContent;
};
var calculateX = function calculateX(formObject, text) {
var maxFontSize = formObject.maxFontSize || 12;
var font = formObject.fontName;
var returnValue = {
text: "",
fontSize: ""
}; // Remove Brackets
text = text.substr(0, 1) == '(' ? text.substr(1) : text;
text = text.substr(text.length - 1) == ')' ? text.substr(0, text.length - 1) : text; // split into array of words
var textSplit = text.split(' ');
var color = scope.__private__.encodeColorString(formObject.color);
var fontSize = maxFontSize; // The Starting fontSize (The Maximum)
var lineSpacing = 2;
var borderPadding = 2;
var height = AcroFormAppearance.internal.getHeight(formObject) || 0;
height = height < 0 ? -height : height;
var width = AcroFormAppearance.internal.getWidth(formObject) || 0;
width = width < 0 ? -width : width;
var isSmallerThanWidth = function isSmallerThanWidth(i, lastLine, fontSize) {
if (i + 1 < textSplit.length) {
var tmp = lastLine + " " + textSplit[i + 1];
var TextWidth = calculateFontSpace(tmp, formObject, fontSize).width;
var FieldWidth = width - 2 * borderPadding;
return TextWidth <= FieldWidth;
} else {
return false;
}
};
fontSize++;
FontSize: while (true) {
var text = "";
fontSize--;
var textHeight = calculateFontSpace("3", formObject, fontSize).height;
var startY = formObject.multiline ? height - fontSize : (height - textHeight) / 2;
startY += lineSpacing;
var startX = -borderPadding;
var lastY = startY;
var firstWordInLine = 0,
lastWordInLine = 0;
var lastLength = 0;
if (fontSize <= 0) {
// In case, the Text doesn't fit at all
fontSize = 12;
text = "(...) Tj\n";
text += "% Width of Text: " + calculateFontSpace(text, formObject, fontSize).width + ", FieldWidth:" + width + "\n";
break;
}
lastLength = calculateFontSpace(textSplit[0] + " ", formObject, fontSize).width;
var lastLine = "";
var lineCount = 0;
Line: for (var i in textSplit) {
if (textSplit.hasOwnProperty(i)) {
lastLine += textSplit[i] + " "; // Remove last blank
lastLine = lastLine.substr(lastLine.length - 1) == " " ? lastLine.substr(0, lastLine.length - 1) : lastLine;
var key = parseInt(i);
lastLength = calculateFontSpace(lastLine + " ", formObject, fontSize).width;
var nextLineIsSmaller = isSmallerThanWidth(key, lastLine, fontSize);
var isLastWord = i >= textSplit.length - 1;
if (nextLineIsSmaller && !isLastWord) {
lastLine += " ";
continue; // Line
} else if (!nextLineIsSmaller && !isLastWord) {
if (!formObject.multiline) {
continue FontSize;
} else {
if ((textHeight + lineSpacing) * (lineCount + 2) + lineSpacing > height) {
// If the Text is higher than the
// FieldObject
continue FontSize;
}
lastWordInLine = key; // go on
}
} else if (isLastWord) {
lastWordInLine = key;
} else {
if (formObject.multiline && (textHeight + lineSpacing) * (lineCount + 2) + lineSpacing > height) {
// If the Text is higher than the FieldObject
continue FontSize;
}
}
var line = '';
for (var x = firstWordInLine; x <= lastWordInLine; x++) {
line += textSplit[x] + ' ';
} // Remove last blank
line = line.substr(line.length - 1) == " " ? line.substr(0, line.length - 1) : line; // lastLength -= blankSpace.width;
lastLength = calculateFontSpace(line, formObject, fontSize).width; // Calculate startX
switch (formObject.textAlign) {
case 'right':
startX = width - lastLength - borderPadding;
break;
case 'center':
startX = (width - lastLength) / 2;
break;
case 'left':
default:
startX = borderPadding;
break;
}
text += f2(startX) + ' ' + f2(lastY) + ' Td\n';
text += '(' + pdfEscape(line) + ') Tj\n'; // reset X in PDF
text += -f2(startX) + ' 0 Td\n'; // After a Line, adjust y position
lastY = -(fontSize + lineSpacing);
lastLength = 0;
firstWordInLine = lastWordInLine + 1;
lineCount++;
lastLine = "";
continue Line;
}
}
break;
}
returnValue.text = text;
returnValue.fontSize = fontSize;
return returnValue;
};
/**
* Small workaround for calculating the TextMetric approximately.
*
* @param text
* @param fontsize
* @returns {TextMetrics} (Has Height and Width)
*/
var calculateFontSpace = function calculateFontSpace(text, formObject, fontSize) {
var font = scope.internal.getFont(formObject.fontName, formObject.fontStyle);
var width = scope.getStringUnitWidth(text, {
font: font,
fontSize: parseFloat(fontSize),
charSpace: 0
}) * parseFloat(fontSize);
var height = scope.getStringUnitWidth("3", {
font: font,
fontSize: parseFloat(fontSize),
charSpace: 0
}) * parseFloat(fontSize) * 1.5;
return {
height: height,
width: width
};
};
var acroformPluginTemplate = {
fields: [],
xForms: [],
/**
* acroFormDictionaryRoot contains information about the AcroForm
* Dictionary 0: The Event-Token, the AcroFormDictionaryCallback has
* 1: The Object ID of the Root
*/
acroFormDictionaryRoot: null,
/**
* After the PDF gets evaluated, the reference to the root has to be
* reset, this indicates, whether the root has already been printed
* out
*/
printedOut: false,
internal: null,
isInitialized: false
};
var annotReferenceCallback = function annotReferenceCallback() {
//set objId to undefined and force it to get a new objId on buildDocument
scope.internal.acroformPlugin.acroFormDictionaryRoot.objId = undefined;
var fields = scope.internal.acroformPlugin.acroFormDictionaryRoot.Fields;
for (var i in fields) {
if (fields.hasOwnProperty(i)) {
var formObject = fields[i]; //set objId to undefined and force it to get a new objId on buildDocument
formObject.objId = undefined; // add Annot Reference!
if (formObject.hasAnnotation) {
// If theres an Annotation Widget in the Form Object, put the
// Reference in the /Annot array
createAnnotationReference.call(scope, formObject);
}
}
}
};
var putForm = function putForm(formObject) {
if (scope.internal.acroformPlugin.printedOut) {
scope.internal.acroformPlugin.printedOut = false;
scope.internal.acroformPlugin.acroFormDictionaryRoot = null;
}
if (!scope.internal.acroformPlugin.acroFormDictionaryRoot) {
initializeAcroForm.call(scope);
}
scope.internal.acroformPlugin.acroFormDictionaryRoot.Fields.push(formObject);
};
/**
* Create the Reference to the widgetAnnotation, so that it gets referenced
* in the Annot[] int the+ (Requires the Annotation Plugin)
*/
var createAnnotationReference = function createAnnotationReference(object) {
var options = {
type: 'reference',
object: object
};
var findEntry = function findEntry(entry) {
return entry.type === options.type && entry.object === options.object;
};
if (scope.internal.getPageInfo(object.page).pageContext.annotations.find(findEntry) === undefined) {
scope.internal.getPageInfo(object.page).pageContext.annotations.push(options);
}
}; // Callbacks
var putCatalogCallback = function putCatalogCallback() {
// Put reference to AcroForm to DocumentCatalog
if (typeof scope.internal.acroformPlugin.acroFormDictionaryRoot != 'undefined') {
// for safety, shouldn't normally be the case
scope.internal.write('/AcroForm ' + scope.internal.acroformPlugin.acroFormDictionaryRoot.objId + ' ' + 0 + ' R');
} else {
throw new Error('putCatalogCallback: Root missing.');
}
};
/**
* Adds /Acroform X 0 R to Document Catalog, and creates the AcroForm
* Dictionary
*/
var AcroFormDictionaryCallback = function AcroFormDictionaryCallback() {
// Remove event
scope.internal.events.unsubscribe(scope.internal.acroformPlugin.acroFormDictionaryRoot._eventID);
delete scope.internal.acroformPlugin.acroFormDictionaryRoot._eventID;
scope.internal.acroformPlugin.printedOut = true;
};
/**
* Creates the single Fields and writes them into the Document
*
* If fieldArray is set, use the fields that are inside it instead of the
* fields from the AcroRoot (for the FormXObjects...)
*/
var createFieldCallback = function createFieldCallback(fieldArray) {
var standardFields = !fieldArray;
if (!fieldArray) {
// in case there is no fieldArray specified, we want to print out
// the Fields of the AcroForm
// Print out Root
scope.internal.newObjectDeferredBegin(scope.internal.acroformPlugin.acroFormDictionaryRoot.objId, true);
scope.internal.acroformPlugin.acroFormDictionaryRoot.putStream();
}
var fieldArray = fieldArray || scope.internal.acroformPlugin.acroFormDictionaryRoot.Kids;
for (var i in fieldArray) {
if (fieldArray.hasOwnProperty(i)) {
var fieldObject = fieldArray[i];
var keyValueList = [];
var oldRect = fieldObject.Rect;
if (fieldObject.Rect) {
fieldObject.Rect = calculateCoordinates.call(this, fieldObject.Rect);
} // Start Writing the Object
scope.internal.newObjectDeferredBegin(fieldObject.objId, true);
fieldObject.DA = AcroFormAppearance.createDefaultAppearanceStream(fieldObject);
if (_typeof(fieldObject) === "object" && typeof fieldObject.getKeyValueListForStream === "function") {
keyValueList = fieldObject.getKeyValueListForStream();
}
fieldObject.Rect = oldRect;
if (fieldObject.hasAppearanceStream && !fieldObject.appearanceStreamContent) {
// Calculate Appearance
var appearance = calculateAppearanceStream.call(this, fieldObject);
keyValueList.push({
key: 'AP',
value: "<>"
});
scope.internal.acroformPlugin.xForms.push(appearance);
} // Assume AppearanceStreamContent is a Array with N,R,D (at least
// one of them!)
if (fieldObject.appearanceStreamContent) {
var appearanceStreamString = ""; // Iterate over N,R and D
for (var k in fieldObject.appearanceStreamContent) {
if (fieldObject.appearanceStreamContent.hasOwnProperty(k)) {
var value = fieldObject.appearanceStreamContent[k];
appearanceStreamString += "/" + k + " ";
appearanceStreamString += "<<";
if (Object.keys(value).length >= 1 || Array.isArray(value)) {
// appearanceStream is an Array or Object!
for (var i in value) {
if (value.hasOwnProperty(i)) {
var obj = value[i];
if (typeof obj === 'function') {
// if Function is referenced, call it in order
// to get the FormXObject
obj = obj.call(this, fieldObject);
}
appearanceStreamString += "/" + i + " " + obj + " "; // In case the XForm is already used, e.g. OffState
// of CheckBoxes, don't add it
if (!(scope.internal.acroformPlugin.xForms.indexOf(obj) >= 0)) scope.internal.acroformPlugin.xForms.push(obj);
}
}
} else {
var obj = value;
if (typeof obj === 'function') {
// if Function is referenced, call it in order to
// get the FormXObject
obj = obj.call(this, fieldObject);
}
appearanceStreamString += "/" + i + " " + obj;
if (!(scope.internal.acroformPlugin.xForms.indexOf(obj) >= 0)) scope.internal.acroformPlugin.xForms.push(obj);
}
appearanceStreamString += ">>";
}
} // appearance stream is a normal Object..
keyValueList.push({
key: 'AP',
value: "<<\n" + appearanceStreamString + ">>"
});
}
scope.internal.putStream({
additionalKeyValues: keyValueList
});
scope.internal.out("endobj");
}
}
if (standardFields) {
createXFormObjectCallback.call(this, scope.internal.acroformPlugin.xForms);
}
};
var createXFormObjectCallback = function createXFormObjectCallback(fieldArray) {
for (var i in fieldArray) {
if (fieldArray.hasOwnProperty(i)) {
var key = i;
var fieldObject = fieldArray[i]; // Start Writing the Object
scope.internal.newObjectDeferredBegin(fieldObject && fieldObject.objId, true);
if (_typeof(fieldObject) === "object" && typeof fieldObject.putStream === "function") {
fieldObject.putStream();
}
delete fieldArray[key];
}
}
};
var initializeAcroForm = function initializeAcroForm() {
if (this.internal !== undefined && (this.internal.acroformPlugin === undefined || this.internal.acroformPlugin.isInitialized === false)) {
scope = this;
AcroFormField.FieldNum = 0;
this.internal.acroformPlugin = JSON.parse(JSON.stringify(acroformPluginTemplate));
if (this.internal.acroformPlugin.acroFormDictionaryRoot) {
throw new Error("Exception while creating AcroformDictionary");
}
scaleFactor = scope.internal.scaleFactor; // The Object Number of the AcroForm Dictionary
scope.internal.acroformPlugin.acroFormDictionaryRoot = new AcroFormDictionary(); // add Callback for creating the AcroForm Dictionary
scope.internal.acroformPlugin.acroFormDictionaryRoot._eventID = scope.internal.events.subscribe('postPutResources', AcroFormDictionaryCallback);
scope.internal.events.subscribe('buildDocument', annotReferenceCallback); // buildDocument
// Register event, that is triggered when the DocumentCatalog is
// written, in order to add /AcroForm
scope.internal.events.subscribe('putCatalog', putCatalogCallback); // Register event, that creates all Fields
scope.internal.events.subscribe('postPutPages', createFieldCallback);
scope.internal.acroformPlugin.isInitialized = true;
}
}; //PDF 32000-1:2008, page 26, 7.3.6
var arrayToPdfArray = jsPDFAPI.__acroform__.arrayToPdfArray = function (array) {
if (Array.isArray(array)) {
var content = '[';
for (var i = 0; i < array.length; i++) {
if (i !== 0) {
content += ' ';
}
switch (_typeof(array[i])) {
case 'boolean':
case 'number':
case 'object':
content += array[i].toString();
break;
case 'string':
if (array[i].substr(0, 1) !== '/') {
content += '(' + pdfEscape(array[i].toString()) + ')';
} else {
content += array[i].toString();
}
break;
}
}
content += ']';
return content;
}
throw new Error('Invalid argument passed to jsPDF.__acroform__.arrayToPdfArray');
};
function getMatches(string, regex, index) {
index || (index = 1); // default to the first capturing group
var matches = [];
var match;
while (match = regex.exec(string)) {
matches.push(match[index]);
}
return matches;
}
var pdfArrayToStringArray = function pdfArrayToStringArray(array) {
var result = [];
if (typeof array === "string") {
result = getMatches(array, /\((.*?)\)/g);
}
return result;
};
var toPdfString = function toPdfString(string) {
string = string || "";
string.toString();
string = '(' + pdfEscape(string) + ')';
return string;
}; // ##########################
// Classes
// ##########################
/**
* @class AcroFormPDFObject
* @classdesc A AcroFormPDFObject
*/
var AcroFormPDFObject = function AcroFormPDFObject() {
var _objId;
/** *
* @name AcroFormPDFObject#objId
* @type {any}
*/
Object.defineProperty(this, 'objId', {
configurable: true,
get: function get() {
if (!_objId) {
_objId = scope.internal.newObjectDeferred();
}
if (!_objId) {
throw new Error("AcroFormPDFObject: Couldn't create Object ID");
}
return _objId;
},
set: function set(value) {
_objId = value;
}
});
};
/**
* @function AcroFormPDFObject.toString
*/
AcroFormPDFObject.prototype.toString = function () {
return this.objId + " 0 R";
};
AcroFormPDFObject.prototype.putStream = function () {
var keyValueList = this.getKeyValueListForStream();
scope.internal.putStream({
data: this.stream,
additionalKeyValues: keyValueList
});
scope.internal.out("endobj");
};
/**
* Returns an key-value-List of all non-configurable Variables from the Object
*
* @name getKeyValueListForStream
* @returns {string}
*/
AcroFormPDFObject.prototype.getKeyValueListForStream = function () {
var createKeyValueListFromFieldObject = function createKeyValueListFromFieldObject(fieldObject) {
var keyValueList = [];
var keys = Object.getOwnPropertyNames(fieldObject).filter(function (key) {
return key != 'content' && key != 'appearanceStreamContent' && key.substring(0, 1) != "_";
});
for (var i in keys) {
if (Object.getOwnPropertyDescriptor(fieldObject, keys[i]).configurable === false) {
var key = keys[i];
var value = fieldObject[key];
if (value) {
if (Array.isArray(value)) {
keyValueList.push({
key: key,
value: arrayToPdfArray(value)
});
} else if (value instanceof AcroFormPDFObject) {
// In case it is a reference to another PDFObject,
// take the reference number
keyValueList.push({
key: key,
value: value.objId + " 0 R"
});
} else if (typeof value !== "function") {
keyValueList.push({
key: key,
value: value
});
}
}
}
}
return keyValueList;
};
return createKeyValueListFromFieldObject(this);
};
var AcroFormXObject = function AcroFormXObject() {
AcroFormPDFObject.call(this);
Object.defineProperty(this, 'Type', {
value: "/XObject",
configurable: false,
writeable: true
});
Object.defineProperty(this, 'Subtype', {
value: "/Form",
configurable: false,
writeable: true
});
Object.defineProperty(this, 'FormType', {
value: 1,
configurable: false,
writeable: true
});
var _BBox = [];
Object.defineProperty(this, 'BBox', {
configurable: false,
writeable: true,
get: function get() {
return _BBox;
},
set: function set(value) {
_BBox = value;
}
});
Object.defineProperty(this, 'Resources', {
value: "2 0 R",
configurable: false,
writeable: true
});
var _stream;
Object.defineProperty(this, 'stream', {
enumerable: false,
configurable: true,
set: function set(value) {
_stream = value.trim();
},
get: function get() {
if (_stream) {
return _stream;
} else {
return null;
}
}
});
};
inherit(AcroFormXObject, AcroFormPDFObject);
var AcroFormDictionary = function AcroFormDictionary() {
AcroFormPDFObject.call(this);
var _Kids = [];
Object.defineProperty(this, 'Kids', {
enumerable: false,
configurable: true,
get: function get() {
if (_Kids.length > 0) {
return _Kids;
} else {
return;
}
}
});
Object.defineProperty(this, 'Fields', {
enumerable: false,
configurable: false,
get: function get() {
return _Kids;
}
}); // Default Appearance
var _DA;
Object.defineProperty(this, 'DA', {
enumerable: false,
configurable: false,
get: function get() {
if (!_DA) {
return;
}
return '(' + _DA + ')';
},
set: function set(value) {
_DA = value;
}
});
};
inherit(AcroFormDictionary, AcroFormPDFObject);
/**
* The Field Object contains the Variables, that every Field needs
*
* @class AcroFormField
* @classdesc An AcroForm FieldObject
*/
var AcroFormField = function AcroFormField() {
AcroFormPDFObject.call(this); //Annotation-Flag See Table 165
var _F = 4;
Object.defineProperty(this, 'F', {
enumerable: false,
configurable: false,
get: function get() {
return _F;
},
set: function set(value) {
if (!isNaN(value)) {
_F = value;
} else {
throw new Error('Invalid value "' + value + '" for attribute F supplied.');
}
}
});
/**
* (PDF 1.2) If set, print the annotation when the page is printed. If clear, never print the annotation, regardless of wether is is displayed on the screen.
* NOTE 2 This can be useful for annotations representing interactive pushbuttons, which would serve no meaningful purpose on the printed page.
*
* @name AcroFormField#showWhenPrinted
* @default true
* @type {boolean}
*/
Object.defineProperty(this, 'showWhenPrinted', {
enumerable: true,
configurable: true,
get: function get() {
return Boolean(getBitForPdf(_F, 3));
},
set: function set(value) {
if (Boolean(value) === true) {
this.F = setBitForPdf(_F, 3);
} else {
this.F = clearBitForPdf(_F, 3);
}
}
});
var _Ff = 0;
Object.defineProperty(this, 'Ff', {
enumerable: false,
configurable: false,
get: function get() {
return _Ff;
},
set: function set(value) {
if (!isNaN(value)) {
_Ff = value;
} else {
throw new Error('Invalid value "' + value + '" for attribute Ff supplied.');
}
}
});
var _Rect = [];
Object.defineProperty(this, 'Rect', {
enumerable: false,
configurable: false,
get: function get() {
if (_Rect.length === 0) {
return;
}
return _Rect;
},
set: function set(value) {
if (typeof value !== "undefined") {
_Rect = value;
} else {
_Rect = [];
}
}
});
/**
* The x-position of the field.
*
* @name AcroFormField#x
* @default null
* @type {number}
*/
Object.defineProperty(this, 'x', {
enumerable: true,
configurable: true,
get: function get() {
if (!_Rect || isNaN(_Rect[0])) {
return 0;
}
return antiScale(_Rect[0]);
},
set: function set(value) {
_Rect[0] = scale(value);
}
});
/**
* The y-position of the field.
*
* @name AcroFormField#y
* @default null
* @type {number}
*/
Object.defineProperty(this, 'y', {
enumerable: true,
configurable: true,
get: function get() {
if (!_Rect || isNaN(_Rect[1])) {
return 0;
}
return antiScale(_Rect[1]);
},
set: function set(value) {
_Rect[1] = scale(value);
}
});
/**
* The width of the field.
*
* @name AcroFormField#width
* @default null
* @type {number}
*/
Object.defineProperty(this, 'width', {
enumerable: true,
configurable: true,
get: function get() {
if (!_Rect || isNaN(_Rect[2])) {
return 0;
}
return antiScale(_Rect[2]);
},
set: function set(value) {
_Rect[2] = scale(value);
}
});
/**
* The height of the field.
*
* @name AcroFormField#height
* @default null
* @type {number}
*/
Object.defineProperty(this, 'height', {
enumerable: true,
configurable: true,
get: function get() {
if (!_Rect || isNaN(_Rect[3])) {
return 0;
}
return antiScale(_Rect[3]);
},
set: function set(value) {
_Rect[3] = scale(value);
}
});
var _FT = "";
Object.defineProperty(this, 'FT', {
enumerable: true,
configurable: false,
get: function get() {
return _FT;
},
set: function set(value) {
switch (value) {
case '/Btn':
case '/Tx':
case '/Ch':
case '/Sig':
_FT = value;
break;
default:
throw new Error('Invalid value "' + value + '" for attribute FT supplied.');
}
}
});
var _T = null;
Object.defineProperty(this, 'T', {
enumerable: true,
configurable: false,
get: function get() {
if (!_T || _T.length < 1) {
// In case of a Child from a Radio´Group, you don't need a FieldName
if (this instanceof AcroFormChildClass) {
return;
}
_T = "FieldObject" + AcroFormField.FieldNum++;
}
return '(' + pdfEscape(_T) + ')';
},
set: function set(value) {
_T = value.toString();
}
});
/**
* (Optional) The partial field name (see 12.7.3.2, “Field Names”).
*
* @name AcroFormField#fieldName
* @default null
* @type {string}
*/
Object.defineProperty(this, 'fieldName', {
configurable: true,
enumerable: true,
get: function get() {
return _T;
},
set: function set(value) {
_T = value;
}
});
var _fontName = 'helvetica';
/**
* The fontName of the font to be used.
*
* @name AcroFormField#fontName
* @default 'helvetica'
* @type {string}
*/
Object.defineProperty(this, 'fontName', {
enumerable: true,
configurable: true,
get: function get() {
return _fontName;
},
set: function set(value) {
_fontName = value;
}
});
var _fontStyle = 'normal';
/**
* The fontStyle of the font to be used.
*
* @name AcroFormField#fontStyle
* @default 'normal'
* @type {string}
*/
Object.defineProperty(this, 'fontStyle', {
enumerable: true,
configurable: true,
get: function get() {
return _fontStyle;
},
set: function set(value) {
_fontStyle = value;
}
});
var _fontSize = 0;
/**
* The fontSize of the font to be used.
*
* @name AcroFormField#fontSize
* @default 0 (for auto)
* @type {number}
*/
Object.defineProperty(this, 'fontSize', {
enumerable: true,
configurable: true,
get: function get() {
return antiScale(_fontSize);
},
set: function set(value) {
_fontSize = scale(value);
}
});
var _maxFontSize = 50;
/**
* The maximum fontSize of the font to be used.
*
* @name AcroFormField#maxFontSize
* @default 0 (for auto)
* @type {number}
*/
Object.defineProperty(this, 'maxFontSize', {
enumerable: true,
configurable: true,
get: function get() {
return antiScale(_maxFontSize);
},
set: function set(value) {
_maxFontSize = scale(value);
}
});
var _color = 'black';
/**
* The color of the text
*
* @name AcroFormField#color
* @default 'black'
* @type {string|rgba}
*/
Object.defineProperty(this, 'color', {
enumerable: true,
configurable: true,
get: function get() {
return _color;
},
set: function set(value) {
_color = value;
}
});
var _DA = '/F1 0 Tf 0 g'; // Defines the default appearance (Needed for variable Text)
Object.defineProperty(this, 'DA', {
enumerable: true,
configurable: false,
get: function get() {
if (!_DA || this instanceof AcroFormChildClass || this instanceof AcroFormTextField) {
return;
}
return toPdfString(_DA);
},
set: function set(value) {
value = value.toString();
_DA = value;
}
});
var _DV = null;
Object.defineProperty(this, 'DV', {
enumerable: false,
configurable: false,
get: function get() {
if (!_DV) {
return;
}
if (this instanceof AcroFormButton === false) {
return toPdfString(_DV);
}
return _DV;
},
set: function set(value) {
value = value.toString();
if (this instanceof AcroFormButton === false) {
if (value.substr(0, 1) === '(') {
_DV = pdfUnescape(value.substr(1, value.length - 2));
} else {
_DV = pdfUnescape(value);
}
} else {
_DV = value;
}
}
});
/**
* (Optional; inheritable) The default value to which the field reverts when a reset-form action is executed (see 12.7.5.3, “Reset-Form Action”). The format of this value is the same as that of value.
*
* @name AcroFormField#defaultValue
* @default null
* @type {any}
*/
Object.defineProperty(this, 'defaultValue', {
enumerable: true,
configurable: true,
get: function get() {
if (this instanceof AcroFormButton === true) {
return pdfUnescape(_DV.substr(1, _DV.length - 1));
} else {
return _DV;
}
},
set: function set(value) {
value = value.toString();
if (this instanceof AcroFormButton === true) {
_DV = '/' + value;
} else {
_DV = value;
}
}
});
var _V = null;
Object.defineProperty(this, 'V', {
enumerable: false,
configurable: false,
get: function get() {
if (!_V) {
return;
}
if (this instanceof AcroFormButton === false) {
return toPdfString(_V);
}
return _V;
},
set: function set(value) {
value = value.toString();
if (this instanceof AcroFormButton === false) {
if (value.substr(0, 1) === '(') {
_V = pdfUnescape(value.substr(1, value.length - 2));
} else {
_V = pdfUnescape(value);
}
} else {
_V = value;
}
}
});
/**
* (Optional; inheritable) The field’s value, whose format varies depending on the field type. See the descriptions of individual field types for further information.
*
* @name AcroFormField#value
* @default null
* @type {any}
*/
Object.defineProperty(this, 'value', {
enumerable: true,
configurable: true,
get: function get() {
if (this instanceof AcroFormButton === true) {
return pdfUnescape(_V.substr(1, _V.length - 1));
} else {
return _V;
}
},
set: function set(value) {
value = value.toString();
if (this instanceof AcroFormButton === true) {
_V = '/' + value;
} else {
_V = value;
}
}
});
/**
* Check if field has annotations
*
* @name AcroFormField#hasAnnotation
* @readonly
* @type {boolean}
*/
Object.defineProperty(this, 'hasAnnotation', {
enumerable: true,
configurable: true,
get: function get() {
return this.Rect;
}
});
Object.defineProperty(this, 'Type', {
enumerable: true,
configurable: false,
get: function get() {
return this.hasAnnotation ? "/Annot" : null;
}
});
Object.defineProperty(this, 'Subtype', {
enumerable: true,
configurable: false,
get: function get() {
return this.hasAnnotation ? "/Widget" : null;
}
});
var _hasAppearanceStream = false;
/**
* true if field has an appearanceStream
*
* @name AcroFormField#hasAppearanceStream
* @readonly
* @type {boolean}
*/
Object.defineProperty(this, 'hasAppearanceStream', {
enumerable: true,
configurable: true,
writeable: true,
get: function get() {
return _hasAppearanceStream;
},
set: function set(value) {
value = Boolean(value);
_hasAppearanceStream = value;
}
});
/**
* The page on which the AcroFormField is placed
*
* @name AcroFormField#page
* @type {number}
*/
var _page;
Object.defineProperty(this, 'page', {
enumerable: true,
configurable: true,
writeable: true,
get: function get() {
if (!_page) {
return;
}
return _page;
},
set: function set(value) {
_page = value;
}
});
/**
* If set, the user may not change the value of the field. Any associated widget annotations will not interact with the user; that is, they will not respond to mouse clicks or change their appearance in response to mouse motions. This flag is useful for fields whose values are computed or imported from a database.
*
* @name AcroFormField#readOnly
* @default false
* @type {boolean}
*/
Object.defineProperty(this, 'readOnly', {
enumerable: true,
configurable: true,
get: function get() {
return Boolean(getBitForPdf(this.Ff, 1));
},
set: function set(value) {
if (Boolean(value) === true) {
this.Ff = setBitForPdf(this.Ff, 1);
} else {
this.Ff = clearBitForPdf(this.Ff, 1);
}
}
});
/**
* If set, the field shall have a value at the time it is exported by a submitform action (see 12.7.5.2, “Submit-Form Action”).
*
* @name AcroFormField#required
* @default false
* @type {boolean}
*/
Object.defineProperty(this, 'required', {
enumerable: true,
configurable: true,
get: function get() {
return Boolean(getBitForPdf(this.Ff, 2));
},
set: function set(value) {
if (Boolean(value) === true) {
this.Ff = setBitForPdf(this.Ff, 2);
} else {
this.Ff = clearBitForPdf(this.Ff, 2);
}
}
});
/**
* If set, the field shall not be exported by a submit-form action (see 12.7.5.2, “Submit-Form Action”)
*
* @name AcroFormField#noExport
* @default false
* @type {boolean}
*/
Object.defineProperty(this, 'noExport', {
enumerable: true,
configurable: true,
get: function get() {
return Boolean(getBitForPdf(this.Ff, 3));
},
set: function set(value) {
if (Boolean(value) === true) {
this.Ff = setBitForPdf(this.Ff, 3);
} else {
this.Ff = clearBitForPdf(this.Ff, 3);
}
}
});
var _Q = null;
Object.defineProperty(this, 'Q', {
enumerable: true,
configurable: false,
get: function get() {
if (_Q === null) {
return;
}
return _Q;
},
set: function set(value) {
if ([0, 1, 2].indexOf(value) !== -1) {
_Q = value;
} else {
throw new Error('Invalid value "' + value + '" for attribute Q supplied.');
}
}
});
/**
* (Optional; inheritable) A code specifying the form of quadding (justification) that shall be used in displaying the text:
* 'left', 'center', 'right'
*
* @name AcroFormField#textAlign
* @default 'left'
* @type {string}
*/
Object.defineProperty(this, 'textAlign', {
get: function get() {
var result = 'left';
switch (_Q) {
case 0:
default:
result = 'left';
break;
case 1:
result = 'center';
break;
case 2:
result = 'right';
break;
}
return result;
},
configurable: true,
enumerable: true,
set: function set(value) {
switch (value) {
case 'right':
case 2:
_Q = 2;
break;
case 'center':
case 1:
_Q = 1;
break;
case 'left':
case 0:
default:
_Q = 0;
}
}
});
};
inherit(AcroFormField, AcroFormPDFObject);
/**
* @class AcroFormChoiceField
* @extends AcroFormField
*/
var AcroFormChoiceField = function AcroFormChoiceField() {
AcroFormField.call(this); // Field Type = Choice Field
this.FT = "/Ch"; // options
this.V = '()';
this.fontName = 'zapfdingbats'; // Top Index
var _TI = 0;
Object.defineProperty(this, 'TI', {
enumerable: true,
configurable: false,
get: function get() {
return _TI;
},
set: function set(value) {
_TI = value;
}
});
/**
* (Optional) For scrollable list boxes, the top index (the index in the Opt array of the first option visible in the list). Default value: 0.
*
* @name AcroFormChoiceField#topIndex
* @default 0
* @type {number}
*/
Object.defineProperty(this, 'topIndex', {
enumerable: true,
configurable: true,
get: function get() {
return _TI;
},
set: function set(value) {
_TI = value;
}
});
var _Opt = [];
Object.defineProperty(this, 'Opt', {
enumerable: true,
configurable: false,
get: function get() {
return arrayToPdfArray(_Opt);
},
set: function set(value) {
_Opt = pdfArrayToStringArray(value);
}
});
/**
* @memberof AcroFormChoiceField
* @name getOptions
* @function
* @instance
* @returns {array} array of Options
*/
this.getOptions = function () {
return _Opt;
};
/**
* @memberof AcroFormChoiceField
* @name setOptions
* @function
* @instance
* @param {array} value
*/
this.setOptions = function (value) {
_Opt = value;
if (this.sort) {
_Opt.sort();
}
};
/**
* @memberof AcroFormChoiceField
* @name addOption
* @function
* @instance
* @param {string} value
*/
this.addOption = function (value) {
value = value || "";
value = value.toString();
_Opt.push(value);
if (this.sort) {
_Opt.sort();
}
};
/**
* @memberof AcroFormChoiceField
* @name removeOption
* @function
* @instance
* @param {string} value
* @param {boolean} allEntries (default: false)
*/
this.removeOption = function (value, allEntries) {
allEntries = allEntries || false;
value = value || "";
value = value.toString();
while (_Opt.indexOf(value) !== -1) {
_Opt.splice(_Opt.indexOf(value), 1);
if (allEntries === false) {
break;
}
}
};
/**
* If set, the field is a combo box; if clear, the field is a list box.
*
* @name AcroFormChoiceField#combo
* @default false
* @type {boolean}
*/
Object.defineProperty(this, 'combo', {
enumerable: true,
configurable: true,
get: function get() {
return Boolean(getBitForPdf(this.Ff, 18));
},
set: function set(value) {
if (Boolean(value) === true) {
this.Ff = setBitForPdf(this.Ff, 18);
} else {
this.Ff = clearBitForPdf(this.Ff, 18);
}
}
});
/**
* If set, the combo box shall include an editable text box as well as a drop-down list; if clear, it shall include only a drop-down list. This flag shall be used only if the Combo flag is set.
*
* @name AcroFormChoiceField#edit
* @default false
* @type {boolean}
*/
Object.defineProperty(this, 'edit', {
enumerable: true,
configurable: true,
get: function get() {
return Boolean(getBitForPdf(this.Ff, 19));
},
set: function set(value) {
//PDF 32000-1:2008, page 444
if (this.combo === true) {
if (Boolean(value) === true) {
this.Ff = setBitForPdf(this.Ff, 19);
} else {
this.Ff = clearBitForPdf(this.Ff, 19);
}
}
}
});
/**
* If set, the field’s option items shall be sorted alphabetically. This flag is intended for use by writers, not by readers. Conforming readers shall display the options in the order in which they occur in the Opt array (see Table 231).
*
* @name AcroFormChoiceField#sort
* @default false
* @type {boolean}
*/
Object.defineProperty(this, 'sort', {
enumerable: true,
configurable: true,
get: function get() {
return Boolean(getBitForPdf(this.Ff, 20));
},
set: function set(value) {
if (Boolean(value) === true) {
this.Ff = setBitForPdf(this.Ff, 20);
_Opt.sort();
} else {
this.Ff = clearBitForPdf(this.Ff, 20);
}
}
});
/**
* (PDF 1.4) If set, more than one of the field’s option items may be selected simultaneously; if clear, at most one item shall be selected
*
* @name AcroFormChoiceField#multiSelect
* @default false
* @type {boolean}
*/
Object.defineProperty(this, 'multiSelect', {
enumerable: true,
configurable: true,
get: function get() {
return Boolean(getBitForPdf(this.Ff, 22));
},
set: function set(value) {
if (Boolean(value) === true) {
this.Ff = setBitForPdf(this.Ff, 22);
} else {
this.Ff = clearBitForPdf(this.Ff, 22);
}
}
});
/**
* (PDF 1.4) If set, text entered in the field shall not be spellchecked. This flag shall not be used unless the Combo and Edit flags are both set.
*
* @name AcroFormChoiceField#doNotSpellCheck
* @default false
* @type {boolean}
*/
Object.defineProperty(this, 'doNotSpellCheck', {
enumerable: true,
configurable: true,
get: function get() {
return Boolean(getBitForPdf(this.Ff, 23));
},
set: function set(value) {
if (Boolean(value) === true) {
this.Ff = setBitForPdf(this.Ff, 23);
} else {
this.Ff = clearBitForPdf(this.Ff, 23);
}
}
});
/**
* (PDF 1.5) If set, the new value shall be committed as soon as a selection is made (commonly with the pointing device). In this case, supplying a value for a field involves three actions: selecting the field for fill-in, selecting a choice for the fill-in value, and leaving that field, which finalizes or “commits” the data choice and triggers any actions associated with the entry or changing of this data. If this flag is on, then processing does not wait for leaving the field action to occur, but immediately proceeds to the third step.
* This option enables applications to perform an action once a selection is made, without requiring the user to exit the field. If clear, the new value is not committed until the user exits the field.
*
* @name AcroFormChoiceField#commitOnSelChange
* @default false
* @type {boolean}
*/
Object.defineProperty(this, 'commitOnSelChange', {
enumerable: true,
configurable: true,
get: function get() {
return Boolean(getBitForPdf(this.Ff, 27));
},
set: function set(value) {
if (Boolean(value) === true) {
this.Ff = setBitForPdf(this.Ff, 27);
} else {
this.Ff = clearBitForPdf(this.Ff, 27);
}
}
});
this.hasAppearanceStream = false;
};
inherit(AcroFormChoiceField, AcroFormField);
/**
* @class AcroFormListBox
* @extends AcroFormChoiceField
* @extends AcroFormField
*/
var AcroFormListBox = function AcroFormListBox() {
AcroFormChoiceField.call(this);
this.fontName = 'helvetica'; //PDF 32000-1:2008, page 444
this.combo = false;
};
inherit(AcroFormListBox, AcroFormChoiceField);
/**
* @class AcroFormComboBox
* @extends AcroFormListBox
* @extends AcroFormChoiceField
* @extends AcroFormField
*/
var AcroFormComboBox = function AcroFormComboBox() {
AcroFormListBox.call(this);
this.combo = true;
};
inherit(AcroFormComboBox, AcroFormListBox);
/**
* @class AcroFormEditBox
* @extends AcroFormComboBox
* @extends AcroFormListBox
* @extends AcroFormChoiceField
* @extends AcroFormField
*/
var AcroFormEditBox = function AcroFormEditBox() {
AcroFormComboBox.call(this);
this.edit = true;
};
inherit(AcroFormEditBox, AcroFormComboBox);
/**
* @class AcroFormButton
* @extends AcroFormField
*/
var AcroFormButton = function AcroFormButton() {
AcroFormField.call(this);
this.FT = "/Btn";
/**
* (Radio buttons only) If set, exactly one radio button shall be selected at all times; selecting the currently selected button has no effect. If clear, clicking the selected button deselects it, leaving no button selected.
*
* @name AcroFormButton#noToggleToOff
* @type {boolean}
*/
Object.defineProperty(this, 'noToggleToOff', {
enumerable: true,
configurable: true,
get: function get() {
return Boolean(getBitForPdf(this.Ff, 15));
},
set: function set(value) {
if (Boolean(value) === true) {
this.Ff = setBitForPdf(this.Ff, 15);
} else {
this.Ff = clearBitForPdf(this.Ff, 15);
}
}
});
/**
* If set, the field is a set of radio buttons; if clear, the field is a checkbox. This flag may be set only if the Pushbutton flag is clear.
*
* @name AcroFormButton#radio
* @type {boolean}
*/
Object.defineProperty(this, 'radio', {
enumerable: true,
configurable: true,
get: function get() {
return Boolean(getBitForPdf(this.Ff, 16));
},
set: function set(value) {
if (Boolean(value) === true) {
this.Ff = setBitForPdf(this.Ff, 16);
} else {
this.Ff = clearBitForPdf(this.Ff, 16);
}
}
});
/**
* If set, the field is a pushbutton that does not retain a permanent value.
*
* @name AcroFormButton#pushButton
* @type {boolean}
*/
Object.defineProperty(this, 'pushButton', {
enumerable: true,
configurable: true,
get: function get() {
return Boolean(getBitForPdf(this.Ff, 17));
},
set: function set(value) {
if (Boolean(value) === true) {
this.Ff = setBitForPdf(this.Ff, 17);
} else {
this.Ff = clearBitForPdf(this.Ff, 17);
}
}
});
/**
* (PDF 1.5) If set, a group of radio buttons within a radio button field that use the same value for the on state will turn on and off in unison; that is if one is checked, they are all checked. If clear, the buttons are mutually exclusive (the same behavior as HTML radio buttons).
*
* @name AcroFormButton#radioIsUnison
* @type {boolean}
*/
Object.defineProperty(this, 'radioIsUnison', {
enumerable: true,
configurable: true,
get: function get() {
return Boolean(getBitForPdf(this.Ff, 26));
},
set: function set(value) {
if (Boolean(value) === true) {
this.Ff = setBitForPdf(this.Ff, 26);
} else {
this.Ff = clearBitForPdf(this.Ff, 26);
}
}
});
var _MK = {};
Object.defineProperty(this, 'MK', {
enumerable: false,
configurable: false,
get: function get() {
if (Object.keys(_MK).length !== 0) {
var result = [];
result.push('<<');
var key;
for (key in _MK) {
result.push('/' + key + ' (' + _MK[key] + ')');
}
result.push('>>');
return result.join('\n');
}
return;
},
set: function set(value) {
if (_typeof(value) === "object") {
_MK = value;
}
}
});
/**
* From the PDF reference:
* (Optional, button fields only) The widget annotation's normal caption which shall be displayed when it is not interacting with the user.
* Unlike the remaining entries listed in this Table which apply only to widget annotations associated with pushbutton fields (see Pushbuttons in 12.7.4.2, "Button Fields"), the CA entry may be used with any type of button field, including check boxes (see Check Boxes in 12.7.4.2, "Button Fields") and radio buttons (Radio Buttons in 12.7.4.2, "Button Fields").
*
* - '8' = Cross,
* - 'l' = Circle,
* - '' = nothing
* @name AcroFormButton#caption
* @type {string}
*/
Object.defineProperty(this, 'caption', {
enumerable: true,
configurable: true,
get: function get() {
return _MK.CA || '';
},
set: function set(value) {
if (typeof value === "string") {
_MK.CA = value;
}
}
});
var _AS;
Object.defineProperty(this, 'AS', {
enumerable: false,
configurable: false,
get: function get() {
return _AS;
},
set: function set(value) {
_AS = value;
}
});
/**
* (Required if the appearance dictionary AP contains one or more subdictionaries; PDF 1.2) The annotation's appearance state, which selects the applicable appearance stream from an appearance subdictionary (see Section 12.5.5, "Appearance Streams")
*
* @name AcroFormButton#appearanceState
* @type {any}
*/
Object.defineProperty(this, 'appearanceState', {
enumerable: true,
configurable: true,
get: function get() {
return _AS.substr(1, _AS.length - 1);
},
set: function set(value) {
_AS = '/' + value;
}
});
};
inherit(AcroFormButton, AcroFormField);
/**
* @class AcroFormPushButton
* @extends AcroFormButton
* @extends AcroFormField
*/
var AcroFormPushButton = function AcroFormPushButton() {
AcroFormButton.call(this);
this.pushButton = true;
};
inherit(AcroFormPushButton, AcroFormButton);
/**
* @class AcroFormRadioButton
* @extends AcroFormButton
* @extends AcroFormField
*/
var AcroFormRadioButton = function AcroFormRadioButton() {
AcroFormButton.call(this);
this.radio = true;
this.pushButton = false;
var _Kids = [];
Object.defineProperty(this, 'Kids', {
enumerable: true,
configurable: false,
get: function get() {
return _Kids;
},
set: function set(value) {
if (typeof value !== "undefined") {
_Kids = value;
} else {
_Kids = [];
}
}
});
};
inherit(AcroFormRadioButton, AcroFormButton);
/**
* The Child class of a RadioButton (the radioGroup) -> The single Buttons
*
* @class AcroFormChildClass
* @extends AcroFormField
* @ignore
*/
var AcroFormChildClass = function AcroFormChildClass() {
AcroFormField.call(this);
var _parent;
Object.defineProperty(this, 'Parent', {
enumerable: false,
configurable: false,
get: function get() {
return _parent;
},
set: function set(value) {
_parent = value;
}
});
var _optionName;
Object.defineProperty(this, 'optionName', {
enumerable: false,
configurable: true,
get: function get() {
return _optionName;
},
set: function set(value) {
_optionName = value;
}
});
var _MK = {};
Object.defineProperty(this, 'MK', {
enumerable: false,
configurable: false,
get: function get() {
var result = [];
result.push('<<');
var key;
for (key in _MK) {
result.push('/' + key + ' (' + _MK[key] + ')');
}
result.push('>>');
return result.join('\n');
},
set: function set(value) {
if (_typeof(value) === "object") {
_MK = value;
}
}
});
/**
* From the PDF reference:
* (Optional, button fields only) The widget annotation's normal caption which shall be displayed when it is not interacting with the user.
* Unlike the remaining entries listed in this Table which apply only to widget annotations associated with pushbutton fields (see Pushbuttons in 12.7.4.2, "Button Fields"), the CA entry may be used with any type of button field, including check boxes (see Check Boxes in 12.7.4.2, "Button Fields") and radio buttons (Radio Buttons in 12.7.4.2, "Button Fields").
*
* - '8' = Cross,
* - 'l' = Circle,
* - '' = nothing
* @name AcroFormButton#caption
* @type {string}
*/
Object.defineProperty(this, 'caption', {
enumerable: true,
configurable: true,
get: function get() {
return _MK.CA || '';
},
set: function set(value) {
if (typeof value === "string") {
_MK.CA = value;
}
}
});
var _AS;
Object.defineProperty(this, 'AS', {
enumerable: false,
configurable: false,
get: function get() {
return _AS;
},
set: function set(value) {
_AS = value;
}
});
/**
* (Required if the appearance dictionary AP contains one or more subdictionaries; PDF 1.2) The annotation's appearance state, which selects the applicable appearance stream from an appearance subdictionary (see Section 12.5.5, "Appearance Streams")
*
* @name AcroFormButton#appearanceState
* @type {any}
*/
Object.defineProperty(this, 'appearanceState', {
enumerable: true,
configurable: true,
get: function get() {
return _AS.substr(1, _AS.length - 1);
},
set: function set(value) {
_AS = '/' + value;
}
});
this.optionName = name;
this.caption = 'l';
this.appearanceState = 'Off'; // todo: set AppearanceType as variable that can be set from the
// outside...
this._AppearanceType = AcroFormAppearance.RadioButton.Circle; // The Default appearanceType is the Circle
this.appearanceStreamContent = this._AppearanceType.createAppearanceStream(name);
};
inherit(AcroFormChildClass, AcroFormField);
AcroFormRadioButton.prototype.setAppearance = function (appearance) {
if (!('createAppearanceStream' in appearance && 'getCA' in appearance)) {
throw new Error("Couldn't assign Appearance to RadioButton. Appearance was Invalid!");
return;
}
for (var objId in this.Kids) {
if (this.Kids.hasOwnProperty(objId)) {
var child = this.Kids[objId];
child.appearanceStreamContent = appearance.createAppearanceStream(child.optionName);
child.caption = appearance.getCA();
}
}
};
AcroFormRadioButton.prototype.createOption = function (name) {
var kidCount = this.Kids.length; // Create new Child for RadioGroup
var child = new AcroFormChildClass();
child.Parent = this;
child.optionName = name; // Add to Parent
this.Kids.push(child);
addField.call(this, child);
return child;
};
/**
* @class AcroFormCheckBox
* @extends AcroFormButton
* @extends AcroFormField
*/
var AcroFormCheckBox = function AcroFormCheckBox() {
AcroFormButton.call(this);
this.fontName = 'zapfdingbats';
this.caption = '3';
this.appearanceState = 'On';
this.value = "On";
this.textAlign = 'center';
this.appearanceStreamContent = AcroFormAppearance.CheckBox.createAppearanceStream();
};
inherit(AcroFormCheckBox, AcroFormButton);
/**
* @class AcroFormTextField
* @extends AcroFormField
*/
var AcroFormTextField = function AcroFormTextField() {
AcroFormField.call(this);
this.FT = '/Tx';
/**
* If set, the field may contain multiple lines of text; if clear, the field’s text shall be restricted to a single line.
*
* @name AcroFormTextField#multiline
* @type {boolean}
*/
Object.defineProperty(this, 'multiline', {
enumerable: true,
configurable: true,
get: function get() {
return Boolean(getBitForPdf(this.Ff, 13));
},
set: function set(value) {
if (Boolean(value) === true) {
this.Ff = setBitForPdf(this.Ff, 13);
} else {
this.Ff = clearBitForPdf(this.Ff, 13);
}
}
});
/**
* (PDF 1.4) If set, the text entered in the field represents the pathname of a file whose contents shall be submitted as the value of the field.
*
* @name AcroFormTextField#fileSelect
* @type {boolean}
*/
Object.defineProperty(this, 'fileSelect', {
enumerable: true,
configurable: true,
get: function get() {
return Boolean(getBitForPdf(this.Ff, 21));
},
set: function set(value) {
if (Boolean(value) === true) {
this.Ff = setBitForPdf(this.Ff, 21);
} else {
this.Ff = clearBitForPdf(this.Ff, 21);
}
}
});
/**
* (PDF 1.4) If set, text entered in the field shall not be spell-checked.
*
* @name AcroFormTextField#doNotSpellCheck
* @type {boolean}
*/
Object.defineProperty(this, 'doNotSpellCheck', {
enumerable: true,
configurable: true,
get: function get() {
return Boolean(getBitForPdf(this.Ff, 23));
},
set: function set(value) {
if (Boolean(value) === true) {
this.Ff = setBitForPdf(this.Ff, 23);
} else {
this.Ff = clearBitForPdf(this.Ff, 23);
}
}
});
/**
* (PDF 1.4) If set, the field shall not scroll (horizontally for single-line fields, vertically for multiple-line fields) to accommodate more text than fits within its annotation rectangle. Once the field is full, no further text shall be accepted for interactive form filling; for noninteractive form filling, the filler should take care not to add more character than will visibly fit in the defined area.
*
* @name AcroFormTextField#doNotScroll
* @type {boolean}
*/
Object.defineProperty(this, 'doNotScroll', {
enumerable: true,
configurable: true,
get: function get() {
return Boolean(getBitForPdf(this.Ff, 24));
},
set: function set(value) {
if (Boolean(value) === true) {
this.Ff = setBitForPdf(this.Ff, 24);
} else {
this.Ff = clearBitForPdf(this.Ff, 24);
}
}
});
/**
* (PDF 1.5) May be set only if the MaxLen entry is present in the text field dictionary (see Table 229) and if the Multiline, Password, and FileSelect flags are clear. If set, the field shall be automatically divided into as many equally spaced positions, or combs, as the value of MaxLen, and the text is laid out into those combs.
*
* @name AcroFormTextField#comb
* @type {boolean}
*/
Object.defineProperty(this, 'comb', {
enumerable: true,
configurable: true,
get: function get() {
return Boolean(getBitForPdf(this.Ff, 25));
},
set: function set(value) {
if (Boolean(value) === true) {
this.Ff = setBitForPdf(this.Ff, 25);
} else {
this.Ff = clearBitForPdf(this.Ff, 25);
}
}
});
/**
* (PDF 1.5) If set, the value of this field shall be a rich text string (see 12.7.3.4, “Rich Text Strings”). If the field has a value, the RV entry of the field dictionary (Table 222) shall specify the rich text string.
*
* @name AcroFormTextField#richText
* @type {boolean}
*/
Object.defineProperty(this, 'richText', {
enumerable: true,
configurable: true,
get: function get() {
return Boolean(getBitForPdf(this.Ff, 26));
},
set: function set(value) {
if (Boolean(value) === true) {
this.Ff = setBitForPdf(this.Ff, 26);
} else {
this.Ff = clearBitForPdf(this.Ff, 26);
}
}
});
var _MaxLen = null;
Object.defineProperty(this, 'MaxLen', {
enumerable: true,
configurable: false,
get: function get() {
return _MaxLen;
},
set: function set(value) {
_MaxLen = value;
}
});
/**
* (Optional; inheritable) The maximum length of the field’s text, in characters.
*
* @name AcroFormTextField#maxLength
* @type {number}
*/
Object.defineProperty(this, 'maxLength', {
enumerable: true,
configurable: true,
get: function get() {
return _MaxLen;
},
set: function set(value) {
if (Number.isInteger(value)) {
_MaxLen = value;
}
}
});
Object.defineProperty(this, 'hasAppearanceStream', {
enumerable: true,
configurable: true,
get: function get() {
return this.V || this.DV;
}
});
};
inherit(AcroFormTextField, AcroFormField);
/**
* @class AcroFormPasswordField
* @extends AcroFormTextField
* @extends AcroFormField
*/
var AcroFormPasswordField = function AcroFormPasswordField() {
AcroFormTextField.call(this);
/**
* If set, the field is intended for entering a secure password that should not be echoed visibly to the screen. Characters typed from the keyboard shall instead be echoed in some unreadable form, such as asterisks or bullet characters.
* NOTE To protect password confidentiality, readers should never store the value of the text field in the PDF file if this flag is set.
*
* @name AcroFormTextField#password
* @type {boolean}
*/
Object.defineProperty(this, 'password', {
enumerable: true,
configurable: true,
get: function get() {
return Boolean(getBitForPdf(this.Ff, 14));
},
set: function set(value) {
if (Boolean(value) === true) {
this.Ff = setBitForPdf(this.Ff, 14);
} else {
this.Ff = clearBitForPdf(this.Ff, 14);
}
}
});
this.password = true;
};
inherit(AcroFormPasswordField, AcroFormTextField); // Contains Methods for creating standard appearances
var AcroFormAppearance = {
CheckBox: {
createAppearanceStream: function createAppearanceStream() {
var appearance = {
N: {
On: AcroFormAppearance.CheckBox.YesNormal
},
D: {
On: AcroFormAppearance.CheckBox.YesPushDown,
Off: AcroFormAppearance.CheckBox.OffPushDown
}
};
return appearance;
},
/**
* Returns the standard On Appearance for a CheckBox
*
* @returns {AcroFormXObject}
*/
YesPushDown: function YesPushDown(formObject) {
var xobj = createFormXObject(formObject);
var stream = [];
var fontKey = scope.internal.getFont(formObject.fontName, formObject.fontStyle).id;
var encodedColor = scope.__private__.encodeColorString(formObject.color);
var calcRes = calculateX(formObject, formObject.caption);
stream.push("0.749023 g");
stream.push("0 0 " + f2(AcroFormAppearance.internal.getWidth(formObject)) + " " + f2(AcroFormAppearance.internal.getHeight(formObject)) + " re");
stream.push("f");
stream.push("BMC");
stream.push("q");
stream.push("0 0 1 rg");
stream.push("/" + fontKey + " " + f2(calcRes.fontSize) + " Tf " + encodedColor);
stream.push("BT");
stream.push(calcRes.text);
stream.push("ET");
stream.push("Q");
stream.push("EMC");
xobj.stream = stream.join("\n");
return xobj;
},
YesNormal: function YesNormal(formObject) {
var xobj = createFormXObject(formObject);
var fontKey = scope.internal.getFont(formObject.fontName, formObject.fontStyle).id;
var encodedColor = scope.__private__.encodeColorString(formObject.color);
var stream = [];
var height = AcroFormAppearance.internal.getHeight(formObject);
var width = AcroFormAppearance.internal.getWidth(formObject);
var calcRes = calculateX(formObject, formObject.caption);
stream.push("1 g");
stream.push("0 0 " + f2(width) + " " + f2(height) + " re");
stream.push("f");
stream.push("q");
stream.push("0 0 1 rg");
stream.push("0 0 " + f2(width - 1) + " " + f2(height - 1) + " re");
stream.push("W");
stream.push("n");
stream.push("0 g");
stream.push("BT");
stream.push("/" + fontKey + " " + f2(calcRes.fontSize) + " Tf " + encodedColor);
stream.push(calcRes.text);
stream.push("ET");
stream.push("Q");
xobj.stream = stream.join("\n");
return xobj;
},
/**
* Returns the standard Off Appearance for a CheckBox
*
* @returns {AcroFormXObject}
*/
OffPushDown: function OffPushDown(formObject) {
var xobj = createFormXObject(formObject);
var stream = [];
stream.push("0.749023 g");
stream.push("0 0 " + f2(AcroFormAppearance.internal.getWidth(formObject)) + " " + f2(AcroFormAppearance.internal.getHeight(formObject)) + " re");
stream.push("f");
xobj.stream = stream.join("\n");
return xobj;
}
},
RadioButton: {
Circle: {
createAppearanceStream: function createAppearanceStream(name) {
var appearanceStreamContent = {
D: {
'Off': AcroFormAppearance.RadioButton.Circle.OffPushDown
},
N: {}
};
appearanceStreamContent.N[name] = AcroFormAppearance.RadioButton.Circle.YesNormal;
appearanceStreamContent.D[name] = AcroFormAppearance.RadioButton.Circle.YesPushDown;
return appearanceStreamContent;
},
getCA: function getCA() {
return 'l';
},
YesNormal: function YesNormal(formObject) {
var xobj = createFormXObject(formObject);
var stream = []; // Make the Radius of the Circle relative to min(height, width) of formObject
var DotRadius = AcroFormAppearance.internal.getWidth(formObject) <= AcroFormAppearance.internal.getHeight(formObject) ? AcroFormAppearance.internal.getWidth(formObject) / 4 : AcroFormAppearance.internal.getHeight(formObject) / 4; // The Borderpadding...
DotRadius = Number((DotRadius * 0.9).toFixed(5));
var c = AcroFormAppearance.internal.Bezier_C;
var DotRadiusBezier = Number((DotRadius * c).toFixed(5));
/*
* The Following is a Circle created with Bezier-Curves.
*/
stream.push("q");
stream.push("1 0 0 1 " + f5(AcroFormAppearance.internal.getWidth(formObject) / 2) + " " + f5(AcroFormAppearance.internal.getHeight(formObject) / 2) + " cm");
stream.push(DotRadius + " 0 m");
stream.push(DotRadius + " " + DotRadiusBezier + " " + DotRadiusBezier + " " + DotRadius + " 0 " + DotRadius + " c");
stream.push("-" + DotRadiusBezier + " " + DotRadius + " -" + DotRadius + " " + DotRadiusBezier + " -" + DotRadius + " 0 c");
stream.push("-" + DotRadius + " -" + DotRadiusBezier + " -" + DotRadiusBezier + " -" + DotRadius + " 0 -" + DotRadius + " c");
stream.push(DotRadiusBezier + " -" + DotRadius + " " + DotRadius + " -" + DotRadiusBezier + " " + DotRadius + " 0 c");
stream.push("f");
stream.push("Q");
xobj.stream = stream.join("\n");
return xobj;
},
YesPushDown: function YesPushDown(formObject) {
var xobj = createFormXObject(formObject);
var stream = [];
var DotRadius = AcroFormAppearance.internal.getWidth(formObject) <= AcroFormAppearance.internal.getHeight(formObject) ? AcroFormAppearance.internal.getWidth(formObject) / 4 : AcroFormAppearance.internal.getHeight(formObject) / 4; // The Borderpadding...
var DotRadius = Number((DotRadius * 0.9).toFixed(5)); // Save results for later use; no need to waste
// processor ticks on doing math
var k = Number((DotRadius * 2).toFixed(5));
var kc = Number((k * AcroFormAppearance.internal.Bezier_C).toFixed(5));
var dc = Number((DotRadius * AcroFormAppearance.internal.Bezier_C).toFixed(5));
stream.push("0.749023 g");
stream.push("q");
stream.push("1 0 0 1 " + f5(AcroFormAppearance.internal.getWidth(formObject) / 2) + " " + f5(AcroFormAppearance.internal.getHeight(formObject) / 2) + " cm");
stream.push(k + " 0 m");
stream.push(k + " " + kc + " " + kc + " " + k + " 0 " + k + " c");
stream.push("-" + kc + " " + k + " -" + k + " " + kc + " -" + k + " 0 c");
stream.push("-" + k + " -" + kc + " -" + kc + " -" + k + " 0 -" + k + " c");
stream.push(kc + " -" + k + " " + k + " -" + kc + " " + k + " 0 c");
stream.push("f");
stream.push("Q");
stream.push("0 g");
stream.push("q");
stream.push("1 0 0 1 " + f5(AcroFormAppearance.internal.getWidth(formObject) / 2) + " " + f5(AcroFormAppearance.internal.getHeight(formObject) / 2) + " cm");
stream.push(DotRadius + " 0 m");
stream.push("" + DotRadius + " " + dc + " " + dc + " " + DotRadius + " 0 " + DotRadius + " c");
stream.push("-" + dc + " " + DotRadius + " -" + DotRadius + " " + dc + " -" + DotRadius + " 0 c");
stream.push("-" + DotRadius + " -" + dc + " -" + dc + " -" + DotRadius + " 0 -" + DotRadius + " c");
stream.push(dc + " -" + DotRadius + " " + DotRadius + " -" + dc + " " + DotRadius + " 0 c");
stream.push("f");
stream.push("Q");
xobj.stream = stream.join("\n");
return xobj;
},
OffPushDown: function OffPushDown(formObject) {
var xobj = createFormXObject(formObject);
var stream = [];
var DotRadius = AcroFormAppearance.internal.getWidth(formObject) <= AcroFormAppearance.internal.getHeight(formObject) ? AcroFormAppearance.internal.getWidth(formObject) / 4 : AcroFormAppearance.internal.getHeight(formObject) / 4; // The Borderpadding...
var DotRadius = Number((DotRadius * 0.9).toFixed(5)); // Save results for later use; no need to waste
// processor ticks on doing math
var k = Number((DotRadius * 2).toFixed(5));
var kc = Number((k * AcroFormAppearance.internal.Bezier_C).toFixed(5));
stream.push("0.749023 g");
stream.push("q");
stream.push("1 0 0 1 " + f5(AcroFormAppearance.internal.getWidth(formObject) / 2) + " " + f5(AcroFormAppearance.internal.getHeight(formObject) / 2) + " cm");
stream.push(k + " 0 m");
stream.push(k + " " + kc + " " + kc + " " + k + " 0 " + k + " c");
stream.push("-" + kc + " " + k + " -" + k + " " + kc + " -" + k + " 0 c");
stream.push("-" + k + " -" + kc + " -" + kc + " -" + k + " 0 -" + k + " c");
stream.push(kc + " -" + k + " " + k + " -" + kc + " " + k + " 0 c");
stream.push("f");
stream.push("Q");
xobj.stream = stream.join("\n");
return xobj;
}
},
Cross: {
/**
* Creates the Actual AppearanceDictionary-References
*
* @param {string} name
* @returns {Object}
* @ignore
*/
createAppearanceStream: function createAppearanceStream(name) {
var appearanceStreamContent = {
D: {
'Off': AcroFormAppearance.RadioButton.Cross.OffPushDown
},
N: {}
};
appearanceStreamContent.N[name] = AcroFormAppearance.RadioButton.Cross.YesNormal;
appearanceStreamContent.D[name] = AcroFormAppearance.RadioButton.Cross.YesPushDown;
return appearanceStreamContent;
},
getCA: function getCA() {
return '8';
},
YesNormal: function YesNormal(formObject) {
var xobj = createFormXObject(formObject);
var stream = [];
var cross = AcroFormAppearance.internal.calculateCross(formObject);
stream.push("q");
stream.push("1 1 " + f2(AcroFormAppearance.internal.getWidth(formObject) - 2) + " " + f2(AcroFormAppearance.internal.getHeight(formObject) - 2) + " re");
stream.push("W");
stream.push("n");
stream.push(f2(cross.x1.x) + " " + f2(cross.x1.y) + " m");
stream.push(f2(cross.x2.x) + " " + f2(cross.x2.y) + " l");
stream.push(f2(cross.x4.x) + " " + f2(cross.x4.y) + " m");
stream.push(f2(cross.x3.x) + " " + f2(cross.x3.y) + " l");
stream.push("s");
stream.push("Q");
xobj.stream = stream.join("\n");
return xobj;
},
YesPushDown: function YesPushDown(formObject) {
var xobj = createFormXObject(formObject);
var cross = AcroFormAppearance.internal.calculateCross(formObject);
var stream = [];
stream.push("0.749023 g");
stream.push("0 0 " + f2(AcroFormAppearance.internal.getWidth(formObject)) + " " + f2(AcroFormAppearance.internal.getHeight(formObject)) + " re");
stream.push("f");
stream.push("q");
stream.push("1 1 " + f2(AcroFormAppearance.internal.getWidth(formObject) - 2) + " " + f2(AcroFormAppearance.internal.getHeight(formObject) - 2) + " re");
stream.push("W");
stream.push("n");
stream.push(f2(cross.x1.x) + " " + f2(cross.x1.y) + " m");
stream.push(f2(cross.x2.x) + " " + f2(cross.x2.y) + " l");
stream.push(f2(cross.x4.x) + " " + f2(cross.x4.y) + " m");
stream.push(f2(cross.x3.x) + " " + f2(cross.x3.y) + " l");
stream.push("s");
stream.push("Q");
xobj.stream = stream.join("\n");
return xobj;
},
OffPushDown: function OffPushDown(formObject) {
var xobj = createFormXObject(formObject);
var stream = [];
stream.push("0.749023 g");
stream.push("0 0 " + f2(AcroFormAppearance.internal.getWidth(formObject)) + " " + f2(AcroFormAppearance.internal.getHeight(formObject)) + " re");
stream.push("f");
xobj.stream = stream.join("\n");
return xobj;
}
}
},
/**
* Returns the standard Appearance
*
* @returns {AcroFormXObject}
*/
createDefaultAppearanceStream: function createDefaultAppearanceStream(formObject) {
// Set Helvetica to Standard Font (size: auto)
// Color: Black
var fontKey = scope.internal.getFont(formObject.fontName, formObject.fontStyle).id;
var encodedColor = scope.__private__.encodeColorString(formObject.color);
var fontSize = formObject.fontSize;
var result = '/' + fontKey + ' ' + fontSize + ' Tf ' + encodedColor;
return result;
}
};
AcroFormAppearance.internal = {
Bezier_C: 0.551915024494,
calculateCross: function calculateCross(formObject) {
var width = AcroFormAppearance.internal.getWidth(formObject);
var height = AcroFormAppearance.internal.getHeight(formObject);
var a = Math.min(width, height);
var cross = {
x1: {
// upperLeft
x: (width - a) / 2,
y: (height - a) / 2 + a // height - borderPadding
},
x2: {
// lowerRight
x: (width - a) / 2 + a,
y: (height - a) / 2 // borderPadding
},
x3: {
// lowerLeft
x: (width - a) / 2,
y: (height - a) / 2 // borderPadding
},
x4: {
// upperRight
x: (width - a) / 2 + a,
y: (height - a) / 2 + a // height - borderPadding
}
};
return cross;
}
};
AcroFormAppearance.internal.getWidth = function (formObject) {
var result = 0;
if (_typeof(formObject) === "object") {
result = scale(formObject.Rect[2]);
}
return result;
};
AcroFormAppearance.internal.getHeight = function (formObject) {
var result = 0;
if (_typeof(formObject) === "object") {
result = scale(formObject.Rect[3]);
}
return result;
}; // Public:
/**
* Add an AcroForm-Field to the jsPDF-instance
*
* @name addField
* @function
* @instance
* @param {Object} fieldObject
* @returns {jsPDF}
*/
var addField = jsPDFAPI.addField = function (fieldObject) {
initializeAcroForm.call(this);
if (fieldObject instanceof AcroFormField) {
putForm.call(this, fieldObject);
} else {
throw new Error('Invalid argument passed to jsPDF.addField.');
}
fieldObject.page = scope.internal.getCurrentPageInfo().pageNumber;
return this;
};
/**
* @name addButton
* @function
* @instance
* @param {AcroFormButton} options
* @returns {jsPDF}
* @deprecated
*/
var addButton = jsPDFAPI.addButton = function (button) {
if (button instanceof AcroFormButton === false) {
throw new Error('Invalid argument passed to jsPDF.addButton.');
}
return addField.call(this, button);
};
/**
* @name addTextField
* @function
* @instance
* @param {AcroFormTextField} textField
* @returns {jsPDF}
* @deprecated
*/
var addTextField = jsPDFAPI.addTextField = function (textField) {
if (textField instanceof AcroFormTextField === false) {
throw new Error('Invalid argument passed to jsPDF.addTextField.');
}
return addField.call(this, textField);
};
/**
* @name addChoiceField
* @function
* @instance
* @param {AcroFormChoiceField}
* @returns {jsPDF}
* @deprecated
*/
var addChoiceField = jsPDFAPI.addChoiceField = function (choiceField) {
if (choiceField instanceof AcroFormChoiceField === false) {
throw new Error('Invalid argument passed to jsPDF.addChoiceField.');
}
return addField.call(this, choiceField);
};
if (_typeof(globalObj) == "object" && typeof globalObj["ChoiceField"] === "undefined" && typeof globalObj["ListBox"] === "undefined" && typeof globalObj["ComboBox"] === "undefined" && typeof globalObj["EditBox"] === "undefined" && typeof globalObj["Button"] === "undefined" && typeof globalObj["PushButton"] === "undefined" && typeof globalObj["RadioButton"] === "undefined" && typeof globalObj["CheckBox"] === "undefined" && typeof globalObj["TextField"] === "undefined" && typeof globalObj["PasswordField"] === "undefined") {
globalObj["ChoiceField"] = AcroFormChoiceField;
globalObj["ListBox"] = AcroFormListBox;
globalObj["ComboBox"] = AcroFormComboBox;
globalObj["EditBox"] = AcroFormEditBox;
globalObj["Button"] = AcroFormButton;
globalObj["PushButton"] = AcroFormPushButton;
globalObj["RadioButton"] = AcroFormRadioButton;
globalObj["CheckBox"] = AcroFormCheckBox;
globalObj["TextField"] = AcroFormTextField;
globalObj["PasswordField"] = AcroFormPasswordField; // backwardsCompatibility
globalObj["AcroForm"] = {
Appearance: AcroFormAppearance
};
} else {
console.warn("AcroForm-Classes are not populated into global-namespace, because the class-Names exist already.");
}
jsPDFAPI.AcroFormChoiceField = AcroFormChoiceField;
jsPDFAPI.AcroFormListBox = AcroFormListBox;
jsPDFAPI.AcroFormComboBox = AcroFormComboBox;
jsPDFAPI.AcroFormEditBox = AcroFormEditBox;
jsPDFAPI.AcroFormButton = AcroFormButton;
jsPDFAPI.AcroFormPushButton = AcroFormPushButton;
jsPDFAPI.AcroFormRadioButton = AcroFormRadioButton;
jsPDFAPI.AcroFormCheckBox = AcroFormCheckBox;
jsPDFAPI.AcroFormTextField = AcroFormTextField;
jsPDFAPI.AcroFormPasswordField = AcroFormPasswordField;
jsPDFAPI.AcroFormAppearance = AcroFormAppearance;
jsPDFAPI.AcroForm = {
ChoiceField: AcroFormChoiceField,
ListBox: AcroFormListBox,
ComboBox: AcroFormComboBox,
EditBox: AcroFormEditBox,
Button: AcroFormButton,
PushButton: AcroFormPushButton,
RadioButton: AcroFormRadioButton,
CheckBox: AcroFormCheckBox,
TextField: AcroFormTextField,
PasswordField: AcroFormPasswordField,
Appearance: AcroFormAppearance
};
})(jsPDF.API, typeof window !== "undefined" && window || typeof global !== "undefined" && global);
/** @license
* jsPDF addImage plugin
* Copyright (c) 2012 Jason Siefken, https://github.com/siefkenj/
* 2013 Chris Dowling, https://github.com/gingerchris
* 2013 Trinh Ho, https://github.com/ineedfat
* 2013 Edwin Alejandro Perez, https://github.com/eaparango
* 2013 Norah Smith, https://github.com/burnburnrocket
* 2014 Diego Casorran, https://github.com/diegocr
* 2014 James Robb, https://github.com/jamesbrobb
*
*
*/
/**
* @name addImage
* @module
*/
(function (jsPDFAPI) {
var namespace = 'addImage_';
var imageFileTypeHeaders = {
PNG: [[0x89, 0x50, 0x4e, 0x47]],
TIFF: [[0x4D, 0x4D, 0x00, 0x2A], //Motorola
[0x49, 0x49, 0x2A, 0x00] //Intel
],
JPEG: [[0xFF, 0xD8, 0xFF, 0xE0, undefined, undefined, 0x4A, 0x46, 0x49, 0x46, 0x00], //JFIF
[0xFF, 0xD8, 0xFF, 0xE1, undefined, undefined, 0x45, 0x78, 0x69, 0x66, 0x00, 0x00] //Exif
],
JPEG2000: [[0x00, 0x00, 0x00, 0x0C, 0x6A, 0x50, 0x20, 0x20]],
GIF87a: [[0x47, 0x49, 0x46, 0x38, 0x37, 0x61]],
GIF89a: [[0x47, 0x49, 0x46, 0x38, 0x39, 0x61]],
BMP: [[0x42, 0x4D], //BM - Windows 3.1x, 95, NT, ... etc.
[0x42, 0x41], //BA - OS/2 struct bitmap array
[0x43, 0x49], //CI - OS/2 struct color icon
[0x43, 0x50], //CP - OS/2 const color pointer
[0x49, 0x43], //IC - OS/2 struct icon
[0x50, 0x54] //PT - OS/2 pointer
]
};
/**
* Recognize filetype of Image by magic-bytes
*
* https://en.wikipedia.org/wiki/List_of_file_signatures
*
* @name getImageFileTypeByImageData
* @public
* @function
* @param {string|arraybuffer} imageData imageData as binary String or arraybuffer
* @param {string} format format of file if filetype-recognition fails, e.g. 'JPEG'
*
* @returns {string} filetype of Image
*/
var getImageFileTypeByImageData = jsPDFAPI.getImageFileTypeByImageData = function (imageData, fallbackFormat) {
fallbackFormat = fallbackFormat || 'UNKNOWN';
var i;
var j;
var result = 'UNKNOWN';
var headerSchemata;
var compareResult;
var fileType;
if (jsPDFAPI.isArrayBufferView(imageData)) {
imageData = jsPDFAPI.arrayBufferToBinaryString(imageData);
}
for (fileType in imageFileTypeHeaders) {
headerSchemata = imageFileTypeHeaders[fileType];
for (i = 0; i < headerSchemata.length; i += 1) {
compareResult = true;
for (j = 0; j < headerSchemata[i].length; j += 1) {
if (headerSchemata[i][j] === undefined) {
continue;
}
if (headerSchemata[i][j] !== imageData.charCodeAt(j)) {
compareResult = false;
break;
}
}
if (compareResult === true) {
result = fileType;
break;
}
}
}
if (result === 'UNKNOWN' && fallbackFormat !== 'UNKNOWN') {
console.warn('FileType of Image not recognized. Processing image as "' + fallbackFormat + '".');
result = fallbackFormat;
}
return result;
}; // Image functionality ported from pdf.js
var putImage = function putImage(img) {
var objectNumber = this.internal.newObject(),
out = this.internal.write,
putStream = this.internal.putStream,
getFilters = this.internal.getFilters;
var filters = getFilters();
while (filters.indexOf('FlateEncode') !== -1) {
filters.splice(filters.indexOf('FlateEncode'), 1);
}
img['n'] = objectNumber;
var additionalKeyValues = [];
additionalKeyValues.push({
key: 'Type',
value: '/XObject'
});
additionalKeyValues.push({
key: 'Subtype',
value: '/Image'
});
additionalKeyValues.push({
key: 'Width',
value: img['w']
});
additionalKeyValues.push({
key: 'Height',
value: img['h']
});
if (img['cs'] === this.color_spaces.INDEXED) {
additionalKeyValues.push({
key: 'ColorSpace',
value: '[/Indexed /DeviceRGB ' // if an indexed png defines more than one colour with transparency, we've created a smask
+ (img['pal'].length / 3 - 1) + ' ' + ('smask' in img ? objectNumber + 2 : objectNumber + 1) + ' 0 R]'
});
} else {
additionalKeyValues.push({
key: 'ColorSpace',
value: '/' + img['cs']
});
if (img['cs'] === this.color_spaces.DEVICE_CMYK) {
additionalKeyValues.push({
key: 'Decode',
value: '[1 0 1 0 1 0 1 0]'
});
}
}
additionalKeyValues.push({
key: 'BitsPerComponent',
value: img['bpc']
});
if ('dp' in img) {
additionalKeyValues.push({
key: 'DecodeParms',
value: '<<' + img['dp'] + '>>'
});
}
if ('trns' in img && img['trns'].constructor == Array) {
var trns = '',
i = 0,
len = img['trns'].length;
for (; i < len; i++) {
trns += img['trns'][i] + ' ' + img['trns'][i] + ' ';
}
additionalKeyValues.push({
key: 'Mask',
value: '[' + trns + ']'
});
}
if ('smask' in img) {
additionalKeyValues.push({
key: 'SMask',
value: objectNumber + 1 + ' 0 R'
});
}
var alreadyAppliedFilters = typeof img['f'] !== "undefined" ? ['/' + img['f']] : undefined;
putStream({
data: img['data'],
additionalKeyValues: additionalKeyValues,
alreadyAppliedFilters: alreadyAppliedFilters
});
out('endobj'); // Soft mask
if ('smask' in img) {
var dp = '/Predictor ' + img['p'] + ' /Colors 1 /BitsPerComponent ' + img['bpc'] + ' /Columns ' + img['w'];
var smask = {
'w': img['w'],
'h': img['h'],
'cs': 'DeviceGray',
'bpc': img['bpc'],
'dp': dp,
'data': img['smask']
};
if ('f' in img) smask.f = img['f'];
putImage.call(this, smask);
} //Palette
if (img['cs'] === this.color_spaces.INDEXED) {
this.internal.newObject(); //out('<< /Filter / ' + img['f'] +' /Length ' + img['pal'].length + '>>');
//putStream(zlib.compress(img['pal']));
putStream({
data: this.arrayBufferToBinaryString(new Uint8Array(img['pal']))
});
out('endobj');
}
},
putResourcesCallback = function putResourcesCallback() {
var images = this.internal.collections[namespace + 'images'];
for (var i in images) {
putImage.call(this, images[i]);
}
},
putXObjectsDictCallback = function putXObjectsDictCallback() {
var images = this.internal.collections[namespace + 'images'],
out = this.internal.write,
image;
for (var i in images) {
image = images[i];
out('/I' + image['i'], image['n'], '0', 'R');
}
},
checkCompressValue = function checkCompressValue(value) {
if (value && typeof value === 'string') value = value.toUpperCase();
return value in jsPDFAPI.image_compression ? value : jsPDFAPI.image_compression.NONE;
},
getImages = function getImages() {
var images = this.internal.collections[namespace + 'images']; //first run, so initialise stuff
if (!images) {
this.internal.collections[namespace + 'images'] = images = {};
this.internal.events.subscribe('putResources', putResourcesCallback);
this.internal.events.subscribe('putXobjectDict', putXObjectsDictCallback);
}
return images;
},
getImageIndex = function getImageIndex(images) {
var imageIndex = 0;
if (images) {
// this is NOT the first time this method is ran on this instance of jsPDF object.
imageIndex = Object.keys ? Object.keys(images).length : function (o) {
var i = 0;
for (var e in o) {
if (o.hasOwnProperty(e)) {
i++;
}
}
return i;
}(images);
}
return imageIndex;
},
notDefined = function notDefined(value) {
return typeof value === 'undefined' || value === null || value.length === 0;
},
generateAliasFromImageData = function generateAliasFromImageData(imageData) {
if (typeof imageData === 'string') {
return jsPDFAPI.sHashCode(imageData);
}
if (jsPDFAPI.isArrayBufferView(imageData)) {
return jsPDFAPI.sHashCode(jsPDFAPI.arrayBufferToBinaryString(imageData));
}
return null;
},
isImageTypeSupported = function isImageTypeSupported(type) {
return typeof jsPDFAPI["process" + type.toUpperCase()] === "function";
},
isDOMElement = function isDOMElement(object) {
return _typeof(object) === 'object' && object.nodeType === 1;
},
createDataURIFromElement = function createDataURIFromElement(element, format) {
//if element is an image which uses data url definition, just return the dataurl
if (element.nodeName === 'IMG' && element.hasAttribute('src')) {
var src = '' + element.getAttribute('src'); //is base64 encoded dataUrl, directly process it
if (src.indexOf('data:image/') === 0) {
return unescape(src);
} //it is probably an url, try to load it
var tmpImageData = jsPDFAPI.loadFile(src);
if (tmpImageData !== undefined) {
return btoa(tmpImageData);
}
}
if (element.nodeName === 'CANVAS') {
var canvas = element;
return element.toDataURL('image/jpeg', 1.0);
} //absolute fallback method
var canvas = document.createElement('canvas');
canvas.width = element.clientWidth || element.width;
canvas.height = element.clientHeight || element.height;
var ctx = canvas.getContext('2d');
if (!ctx) {
throw 'addImage requires canvas to be supported by browser.';
}
ctx.drawImage(element, 0, 0, canvas.width, canvas.height);
return canvas.toDataURL(('' + format).toLowerCase() == 'png' ? 'image/png' : 'image/jpeg');
},
checkImagesForAlias = function checkImagesForAlias(alias, images) {
var cached_info;
if (images) {
for (var e in images) {
if (alias === images[e].alias) {
cached_info = images[e];
break;
}
}
}
return cached_info;
},
determineWidthAndHeight = function determineWidthAndHeight(w, h, info) {
if (!w && !h) {
w = -96;
h = -96;
}
if (w < 0) {
w = -1 * info['w'] * 72 / w / this.internal.scaleFactor;
}
if (h < 0) {
h = -1 * info['h'] * 72 / h / this.internal.scaleFactor;
}
if (w === 0) {
w = h * info['w'] / info['h'];
}
if (h === 0) {
h = w * info['h'] / info['w'];
}
return [w, h];
},
writeImageToPDF = function writeImageToPDF(x, y, w, h, info, index, images, rotation) {
var dims = determineWidthAndHeight.call(this, w, h, info),
coord = this.internal.getCoordinateString,
vcoord = this.internal.getVerticalCoordinateString;
w = dims[0];
h = dims[1];
images[index] = info;
if (rotation) {
rotation *= Math.PI / 180;
var c = Math.cos(rotation);
var s = Math.sin(rotation); //like in pdf Reference do it 4 digits instead of 2
var f4 = function f4(number) {
return number.toFixed(4);
};
var rotationTransformationMatrix = [f4(c), f4(s), f4(s * -1), f4(c), 0, 0, 'cm'];
}
this.internal.write('q'); //Save graphics state
if (rotation) {
this.internal.write([1, '0', '0', 1, coord(x), vcoord(y + h), 'cm'].join(' ')); //Translate
this.internal.write(rotationTransformationMatrix.join(' ')); //Rotate
this.internal.write([coord(w), '0', '0', coord(h), '0', '0', 'cm'].join(' ')); //Scale
} else {
this.internal.write([coord(w), '0', '0', coord(h), coord(x), vcoord(y + h), 'cm'].join(' ')); //Translate and Scale
}
this.internal.write('/I' + info['i'] + ' Do'); //Paint Image
this.internal.write('Q'); //Restore graphics state
};
/**
* COLOR SPACES
*/
jsPDFAPI.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',
SEPARATION: 'Separation',
DEVICE_N: 'DeviceN'
};
/**
* DECODE METHODS
*/
jsPDFAPI.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'
};
/**
* IMAGE COMPRESSION TYPES
*/
jsPDFAPI.image_compression = {
NONE: 'NONE',
FAST: 'FAST',
MEDIUM: 'MEDIUM',
SLOW: 'SLOW'
};
/**
* @name sHashCode
* @function
* @param {string} str
* @returns {string}
*/
jsPDFAPI.sHashCode = function (str) {
str = str || "";
var hash = 0,
i,
chr;
if (str.length === 0) return hash;
for (i = 0; i < str.length; i++) {
chr = str.charCodeAt(i);
hash = (hash << 5) - hash + chr;
hash |= 0; // Convert to 32bit integer
}
return hash;
};
/**
* @name isString
* @function
* @param {any} object
* @returns {boolean}
*/
jsPDFAPI.isString = function (object) {
return typeof object === 'string';
};
/**
* Validates if given String is a valid Base64-String
*
* @name validateStringAsBase64
* @public
* @function
* @param {String} possible Base64-String
*
* @returns {boolean}
*/
jsPDFAPI.validateStringAsBase64 = function (possibleBase64String) {
possibleBase64String = possibleBase64String || '';
possibleBase64String.toString().trim();
var result = true;
if (possibleBase64String.length === 0) {
result = false;
}
if (possibleBase64String.length % 4 !== 0) {
result = false;
}
if (/^[A-Za-z0-9+\/]+$/.test(possibleBase64String.substr(0, possibleBase64String.length - 2)) === false) {
result = false;
}
if (/^[A-Za-z0-9\/][A-Za-z0-9+\/]|[A-Za-z0-9+\/]=|==$/.test(possibleBase64String.substr(-2)) === false) {
result = false;
}
return result;
};
/**
* Strips out and returns info from a valid base64 data URI
*
* @name extractInfoFromBase64DataURI
* @function
* @param {string} dataUrl a valid data URI of format 'data:[][;base64],'
* @returns {Array}an Array containing the following
* [0] the complete data URI
* [1]
* [2] format - the second part of the mime-type i.e 'png' in 'image/png'
* [4]
*/
jsPDFAPI.extractInfoFromBase64DataURI = function (dataURI) {
return /^data:([\w]+?\/([\w]+?));\S*;*base64,(.+)$/g.exec(dataURI);
};
/**
* Strips out and returns info from a valid base64 data URI
*
* @name extractImageFromDataUrl
* @function
* @param {string} dataUrl a valid data URI of format 'data:[][;base64],'
* @returns {Array}an Array containing the following
* [0] the complete data URI
* [1]
* [2] format - the second part of the mime-type i.e 'png' in 'image/png'
* [4]
*/
jsPDFAPI.extractImageFromDataUrl = function (dataUrl) {
dataUrl = dataUrl || '';
var dataUrlParts = dataUrl.split('base64,');
var result = null;
if (dataUrlParts.length === 2) {
var extractedInfo = /^data:(\w*\/\w*);*(charset=[\w=-]*)*;*$/.exec(dataUrlParts[0]);
if (Array.isArray(extractedInfo)) {
result = {
mimeType: extractedInfo[1],
charset: extractedInfo[2],
data: dataUrlParts[1]
};
}
}
return result;
};
/**
* Check to see if ArrayBuffer is supported
*
* @name supportsArrayBuffer
* @function
* @returns {boolean}
*/
jsPDFAPI.supportsArrayBuffer = function () {
return typeof ArrayBuffer !== 'undefined' && typeof Uint8Array !== 'undefined';
};
/**
* Tests supplied object to determine if ArrayBuffer
*
* @name isArrayBuffer
* @function
* @param {Object} object an Object
*
* @returns {boolean}
*/
jsPDFAPI.isArrayBuffer = function (object) {
if (!this.supportsArrayBuffer()) return false;
return object instanceof ArrayBuffer;
};
/**
* Tests supplied object to determine if it implements the ArrayBufferView (TypedArray) interface
*
* @name isArrayBufferView
* @function
* @param {Object} object an Object
* @returns {boolean}
*/
jsPDFAPI.isArrayBufferView = function (object) {
if (!this.supportsArrayBuffer()) return false;
if (typeof Uint32Array === 'undefined') return false;
return object instanceof Int8Array || object instanceof Uint8Array || typeof Uint8ClampedArray !== 'undefined' && object instanceof Uint8ClampedArray || object instanceof Int16Array || object instanceof Uint16Array || object instanceof Int32Array || object instanceof Uint32Array || object instanceof Float32Array || object instanceof Float64Array;
};
/**
* Convert the Buffer to a Binary String
*
* @name binaryStringToUint8Array
* @public
* @function
* @param {ArrayBuffer} BinaryString with ImageData
*
* @returns {Uint8Array}
*/
jsPDFAPI.binaryStringToUint8Array = function (binary_string) {
/*
* not sure how efficient this will be will bigger files. Is there a native method?
*/
var len = binary_string.length;
var bytes = new Uint8Array(len);
for (var i = 0; i < len; i++) {
bytes[i] = binary_string.charCodeAt(i);
}
return bytes;
};
/**
* Convert the Buffer to a Binary String
*
* @name arrayBufferToBinaryString
* @public
* @function
* @param {ArrayBuffer} ArrayBuffer with ImageData
*
* @returns {String}
*/
jsPDFAPI.arrayBufferToBinaryString = function (buffer) {
// if (typeof Uint8Array !== 'undefined' && typeof Uint8Array.prototype.reduce !== 'undefined') {
// return new Uint8Array(buffer).reduce(function (data, byte) {
// return data.push(String.fromCharCode(byte)), data;
// }, []).join('');
// }
if (typeof atob === "function") {
return atob(this.arrayBufferToBase64(buffer));
}
};
/**
* Converts an ArrayBuffer directly to base64
*
* Taken from http://jsperf.com/encoding-xhr-image-data/31
*
* Need to test if this is a better solution for larger files
*
* @name arrayBufferToBase64
* @param {arraybuffer} arrayBuffer
* @public
* @function
*
* @returns {string}
*/
jsPDFAPI.arrayBufferToBase64 = function (arrayBuffer) {
var base64 = '';
var encodings = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
var bytes = new Uint8Array(arrayBuffer);
var byteLength = bytes.byteLength;
var byteRemainder = byteLength % 3;
var mainLength = byteLength - byteRemainder;
var a, b, c, d;
var chunk; // Main loop deals with bytes in chunks of 3
for (var i = 0; i < mainLength; i = i + 3) {
// Combine the three bytes into a single integer
chunk = bytes[i] << 16 | bytes[i + 1] << 8 | bytes[i + 2]; // Use bitmasks to extract 6-bit segments from the triplet
a = (chunk & 16515072) >> 18; // 16515072 = (2^6 - 1) << 18
b = (chunk & 258048) >> 12; // 258048 = (2^6 - 1) << 12
c = (chunk & 4032) >> 6; // 4032 = (2^6 - 1) << 6
d = chunk & 63; // 63 = 2^6 - 1
// Convert the raw binary segments to the appropriate ASCII encoding
base64 += encodings[a] + encodings[b] + encodings[c] + encodings[d];
} // Deal with the remaining bytes and padding
if (byteRemainder == 1) {
chunk = bytes[mainLength];
a = (chunk & 252) >> 2; // 252 = (2^6 - 1) << 2
// Set the 4 least significant bits to zero
b = (chunk & 3) << 4; // 3 = 2^2 - 1
base64 += encodings[a] + encodings[b] + '==';
} else if (byteRemainder == 2) {
chunk = bytes[mainLength] << 8 | bytes[mainLength + 1];
a = (chunk & 64512) >> 10; // 64512 = (2^6 - 1) << 10
b = (chunk & 1008) >> 4; // 1008 = (2^6 - 1) << 4
// Set the 2 least significant bits to zero
c = (chunk & 15) << 2; // 15 = 2^4 - 1
base64 += encodings[a] + encodings[b] + encodings[c] + '=';
}
return base64;
};
/**
*
* @name createImageInfo
* @param {Object} data
* @param {number} wd width
* @param {number} ht height
* @param {Object} cs colorSpace
* @param {number} bpc bits per channel
* @param {any} f
* @param {number} imageIndex
* @param {string} alias
* @param {any} dp
* @param {any} trns
* @param {any} pal
* @param {any} smask
* @param {any} p
* @public
* @function
*
* @returns {Object}
*/
jsPDFAPI.createImageInfo = function (data, wd, ht, cs, bpc, f, imageIndex, alias, dp, trns, pal, smask, p) {
var info = {
alias: alias,
w: wd,
h: ht,
cs: cs,
bpc: bpc,
i: imageIndex,
data: data // n: objectNumber will be added by putImage code
};
if (f) info.f = f;
if (dp) info.dp = dp;
if (trns) info.trns = trns;
if (pal) info.pal = pal;
if (smask) info.smask = smask;
if (p) info.p = p; // predictor parameter for PNG compression
return info;
};
/**
* Adds an Image to the PDF.
*
* @name addImage
* @public
* @function
* @param {string/Image-Element/Canvas-Element/Uint8Array} imageData imageData as base64 encoded DataUrl or Image-HTMLElement or Canvas-HTMLElement
* @param {string} format format of file if filetype-recognition fails, e.g. 'JPEG'
* @param {number} x x Coordinate (in units declared at inception of PDF document) against left edge of the page
* @param {number} y y Coordinate (in units declared at inception of PDF document) against upper edge of the page
* @param {number} width width of the image (in units declared at inception of PDF document)
* @param {number} height height of the Image (in units declared at inception of PDF document)
* @param {string} alias alias of the image (if used multiple times)
* @param {string} compression compression of the generated JPEG, can have the values 'NONE', 'FAST', 'MEDIUM' and 'SLOW'
* @param {number} rotation rotation of the image in degrees (0-359)
*
* @returns jsPDF
*/
jsPDFAPI.addImage = function (imageData, format, x, y, w, h, alias, compression, rotation) {
var tmpImageData = '';
if (typeof format !== 'string') {
var tmp = h;
h = w;
w = y;
y = x;
x = format;
format = tmp;
}
if (_typeof(imageData) === 'object' && !isDOMElement(imageData) && "imageData" in imageData) {
var options = imageData;
imageData = options.imageData;
format = options.format || format || 'UNKNOWN';
x = options.x || x || 0;
y = options.y || y || 0;
w = options.w || w;
h = options.h || h;
alias = options.alias || alias;
compression = options.compression || compression;
rotation = options.rotation || options.angle || rotation;
} //If compression is not explicitly set, determine if we should use compression
var filters = this.internal.getFilters();
if (compression === undefined && filters.indexOf('FlateEncode') !== -1) {
compression = 'SLOW';
}
if (typeof imageData === "string") {
imageData = unescape(imageData);
}
if (isNaN(x) || isNaN(y)) {
console.error('jsPDF.addImage: Invalid coordinates', arguments);
throw new Error('Invalid coordinates passed to jsPDF.addImage');
}
var images = getImages.call(this),
info,
dataAsBinaryString;
if (!(info = checkImagesForAlias(imageData, images))) {
if (isDOMElement(imageData)) imageData = createDataURIFromElement(imageData, format);
if (notDefined(alias)) alias = generateAliasFromImageData(imageData);
if (!(info = checkImagesForAlias(alias, images))) {
if (this.isString(imageData)) {
tmpImageData = this.convertStringToImageData(imageData);
if (tmpImageData !== '') {
imageData = tmpImageData;
} else {
tmpImageData = jsPDFAPI.loadFile(imageData);
if (tmpImageData !== undefined) {
imageData = tmpImageData;
}
}
}
format = this.getImageFileTypeByImageData(imageData, format);
if (!isImageTypeSupported(format)) throw new Error('addImage does not support files of type \'' + format + '\', please ensure that a plugin for \'' + format + '\' support is added.');
/**
* need to test if it's more efficient to convert all binary strings
* to TypedArray - or should we just leave and process as string?
*/
if (this.supportsArrayBuffer()) {
// no need to convert if imageData is already uint8array
if (!(imageData instanceof Uint8Array)) {
dataAsBinaryString = imageData;
imageData = this.binaryStringToUint8Array(imageData);
}
}
info = this['process' + format.toUpperCase()](imageData, getImageIndex(images), alias, checkCompressValue(compression), dataAsBinaryString);
if (!info) {
throw new Error('An unknown error occurred whilst processing the image');
}
}
}
writeImageToPDF.call(this, x, y, w, h, info, info.i, images, rotation);
return this;
};
/**
* @name convertStringToImageData
* @function
* @param {string} stringData
* @returns {string} binary data
*/
jsPDFAPI.convertStringToImageData = function (stringData) {
var base64Info;
var imageData = '';
var rawData;
if (this.isString(stringData)) {
var base64Info = this.extractImageFromDataUrl(stringData);
rawData = base64Info !== null ? base64Info.data : stringData;
try {
imageData = atob(rawData);
} catch (e) {
if (!jsPDFAPI.validateStringAsBase64(rawData)) {
throw new Error('Supplied Data is not a valid base64-String jsPDF.convertStringToImageData ');
} else {
throw new Error('atob-Error in jsPDF.convertStringToImageData ' + e.message);
}
}
}
return imageData;
};
/**
* JPEG SUPPORT
**/
//takes a string imgData containing the raw bytes of
//a jpeg image and returns [width, height]
//Algorithm from: http://www.64lines.com/jpeg-width-height
var getJpegSize = function getJpegSize(imgData) {
var width, height, numcomponents; // Verify we have a valid jpeg header 0xff,0xd8,0xff,0xe0,?,?,'J','F','I','F',0x00
if (getImageFileTypeByImageData(imgData) !== 'JPEG') {
throw new Error('getJpegSize requires a binary string jpeg file');
}
var blockLength = imgData.charCodeAt(4) * 256 + imgData.charCodeAt(5);
var i = 4,
len = imgData.length;
while (i < len) {
i += blockLength;
if (imgData.charCodeAt(i) !== 0xff) {
throw new Error('getJpegSize could not find the size of the image');
}
if (imgData.charCodeAt(i + 1) === 0xc0 || //(SOF) Huffman - Baseline DCT
imgData.charCodeAt(i + 1) === 0xc1 || //(SOF) Huffman - Extended sequential DCT
imgData.charCodeAt(i + 1) === 0xc2 || // Progressive DCT (SOF2)
imgData.charCodeAt(i + 1) === 0xc3 || // Spatial (sequential) lossless (SOF3)
imgData.charCodeAt(i + 1) === 0xc4 || // Differential sequential DCT (SOF5)
imgData.charCodeAt(i + 1) === 0xc5 || // Differential progressive DCT (SOF6)
imgData.charCodeAt(i + 1) === 0xc6 || // Differential spatial (SOF7)
imgData.charCodeAt(i + 1) === 0xc7) {
height = imgData.charCodeAt(i + 5) * 256 + imgData.charCodeAt(i + 6);
width = imgData.charCodeAt(i + 7) * 256 + imgData.charCodeAt(i + 8);
numcomponents = imgData.charCodeAt(i + 9);
return [width, height, numcomponents];
} else {
i += 2;
blockLength = imgData.charCodeAt(i) * 256 + imgData.charCodeAt(i + 1);
}
}
},
getJpegSizeFromBytes = function getJpegSizeFromBytes(data) {
var hdr = data[0] << 8 | data[1];
if (hdr !== 0xFFD8) throw new Error('Supplied data is not a JPEG');
var len = data.length,
block = (data[4] << 8) + data[5],
pos = 4,
bytes,
width,
height,
numcomponents;
while (pos < len) {
pos += block;
bytes = readBytes(data, pos);
block = (bytes[2] << 8) + bytes[3];
if ((bytes[1] === 0xC0 || bytes[1] === 0xC2) && bytes[0] === 0xFF && block > 7) {
bytes = readBytes(data, pos + 5);
width = (bytes[2] << 8) + bytes[3];
height = (bytes[0] << 8) + bytes[1];
numcomponents = bytes[4];
return {
width: width,
height: height,
numcomponents: numcomponents
};
}
pos += 2;
}
throw new Error('getJpegSizeFromBytes could not find the size of the image');
},
readBytes = function readBytes(data, offset) {
return data.subarray(offset, offset + 5);
};
/**
* @ignore
*/
jsPDFAPI.processJPEG = function (data, index, alias, compression, dataAsBinaryString, colorSpace) {
var filter = this.decode.DCT_DECODE,
bpc = 8,
dims;
if (!this.isString(data) && !this.isArrayBuffer(data) && !this.isArrayBufferView(data)) {
return null;
}
if (this.isString(data)) {
dims = getJpegSize(data);
}
if (this.isArrayBuffer(data)) {
data = new Uint8Array(data);
}
if (this.isArrayBufferView(data)) {
dims = getJpegSizeFromBytes(data); // if we already have a stored binary string rep use that
data = dataAsBinaryString || this.arrayBufferToBinaryString(data);
}
if (colorSpace === undefined) {
switch (dims.numcomponents) {
case 1:
colorSpace = this.color_spaces.DEVICE_GRAY;
break;
case 4:
colorSpace = this.color_spaces.DEVICE_CMYK;
break;
default:
case 3:
colorSpace = this.color_spaces.DEVICE_RGB;
break;
}
}
return this.createImageInfo(data, dims.width, dims.height, colorSpace, bpc, filter, index, alias);
};
/**
* @ignore
*/
jsPDFAPI.processJPG = function ()
/*data, index, alias, compression, dataAsBinaryString*/
{
return this.processJPEG.apply(this, arguments);
};
/**
* @name getImageProperties
* @function
* @param {Object} imageData
* @returns {Object}
*/
jsPDFAPI.getImageProperties = function (imageData) {
var info;
var tmpImageData = '';
var format;
if (isDOMElement(imageData)) {
imageData = createDataURIFromElement(imageData);
}
if (this.isString(imageData)) {
tmpImageData = this.convertStringToImageData(imageData);
if (tmpImageData !== '') {
imageData = tmpImageData;
} else {
tmpImageData = jsPDFAPI.loadFile(imageData);
if (tmpImageData !== undefined) {
imageData = tmpImageData;
}
}
}
format = this.getImageFileTypeByImageData(imageData);
if (!isImageTypeSupported(format)) {
throw new Error('addImage does not support files of type \'' + format + '\', please ensure that a plugin for \'' + format + '\' support is added.');
}
/**
* need to test if it's more efficient to convert all binary strings
* to TypedArray - or should we just leave and process as string?
*/
if (this.supportsArrayBuffer()) {
// no need to convert if imageData is already uint8array
if (!(imageData instanceof Uint8Array)) {
imageData = this.binaryStringToUint8Array(imageData);
}
}
info = this['process' + format.toUpperCase()](imageData);
if (!info) {
throw new Error('An unknown error occurred whilst processing the image');
}
return {
fileType: format,
width: info.w,
height: info.h,
colorSpace: info.cs,
compressionMode: info.f,
bitsPerComponent: info.bpc
};
};
})(jsPDF.API);
/**
* @license
* Copyright (c) 2014 Steven Spungin (TwelveTone LLC) [email protected]
*
* Licensed under the MIT License.
* http://opensource.org/licenses/mit-license
*/
/**
* jsPDF Annotations PlugIn
*
* There are many types of annotations in a PDF document. Annotations are placed
* on a page at a particular location. They are not 'attached' to an object.
*
* This plugin current supports
* Goto Page (set pageNumber and top in options)
* Goto Name (set name and top in options)
* Goto URL (set url in options)
*
* The destination magnification factor can also be specified when goto is a page number or a named destination. (see documentation below)
* (set magFactor in options). XYZ is the default.
*
*
* Links, Text, Popup, and FreeText are supported.
*
*
* Options In PDF spec Not Implemented Yet
*
link border
* named target
* page coordinates
* destination page scaling and layout
* actions other than URL and GotoPage
* background / hover actions
*
* @name annotations
* @module
*/
/*
Destination Magnification Factors
See PDF 1.3 Page 386 for meanings and options
[supported]
XYZ (options; left top zoom)
Fit (no options)
FitH (options: top)
FitV (options: left)
[not supported]
FitR
FitB
FitBH
FitBV
*/
(function (jsPDFAPI) {
jsPDF.API.events.push(['addPage', function (addPageData) {
var pageInfo = this.internal.getPageInfo(addPageData.pageNumber);
pageInfo.pageContext.annotations = [];
}]);
jsPDFAPI.events.push(['putPage', function (putPageData) {
var pageInfo = this.internal.getPageInfoByObjId(putPageData.objId);
var pageAnnos = putPageData.pageContext.annotations;
var notEmpty = function notEmpty(obj) {
if (typeof obj != 'undefined') {
if (obj != '') {
return true;
}
}
};
var found = false;
for (var a = 0; a < pageAnnos.length && !found; a++) {
var anno = pageAnnos[a];
switch (anno.type) {
case 'link':
if (notEmpty(anno.options.url) || notEmpty(anno.options.pageNumber)) {
found = true;
break;
}
case 'reference':
case 'text':
case 'freetext':
found = true;
break;
}
}
if (found == false) {
return;
}
this.internal.write("/Annots [");
var pageHeight = this.internal.pageSize.height;
var getHorizontalCoordinateString = this.internal.getCoordinateString;
var getVerticalCoordinateString = this.internal.getVerticalCoordinateString;
for (var a = 0; a < pageAnnos.length; a++) {
var anno = pageAnnos[a];
switch (anno.type) {
case 'reference':
// References to Widget Annotations (for AcroForm Fields)
this.internal.write(' ' + anno.object.objId + ' 0 R ');
break;
case 'text':
// Create a an object for both the text and the popup
var objText = this.internal.newAdditionalObject();
var objPopup = this.internal.newAdditionalObject();
var title = anno.title || 'Note';
var rect = "/Rect [" + getHorizontalCoordinateString(anno.bounds.x) + " " + getVerticalCoordinateString(anno.bounds.y + anno.bounds.h) + " " + getHorizontalCoordinateString(anno.bounds.x + anno.bounds.w) + " " + getVerticalCoordinateString(anno.bounds.y) + "] ";
line = '<>';
objText.content = line;
var parent = objText.objId + ' 0 R';
var popoff = 30;
var rect = "/Rect [" + getHorizontalCoordinateString(anno.bounds.x + popoff) + " " + getVerticalCoordinateString(anno.bounds.y + anno.bounds.h) + " " + getHorizontalCoordinateString(anno.bounds.x + anno.bounds.w + popoff) + " " + getVerticalCoordinateString(anno.bounds.y) + "] ";
line = '<>';
objPopup.content = line;
this.internal.write(objText.objId, '0 R', objPopup.objId, '0 R');
break;
case 'freetext':
var rect = "/Rect [" + getHorizontalCoordinateString(anno.bounds.x) + " " + getVerticalCoordinateString(anno.bounds.y) + " " + getHorizontalCoordinateString(anno.bounds.x + anno.bounds.w) + " " + getVerticalCoordinateString(anno.bounds.y + anno.bounds.h) + "] ";
var color = anno.color || '#000000';
line = '<>';
this.internal.write(line);
break;
case 'link':
if (anno.options.name) {
var loc = this.annotations._nameMap[anno.options.name];
anno.options.pageNumber = loc.page;
anno.options.top = loc.y;
} else {
if (!anno.options.top) {
anno.options.top = 0;
}
}
var rect = "/Rect [" + getHorizontalCoordinateString(anno.x) + " " + getVerticalCoordinateString(anno.y) + " " + getHorizontalCoordinateString(anno.x + anno.w) + " " + getVerticalCoordinateString(anno.y + anno.h) + "] ";
var line = '';
if (anno.options.url) {
line = '<>';
} else if (anno.options.pageNumber) {
// first page is 0
var info = this.internal.getPageInfo(anno.options.pageNumber);
line = '<>";
this.internal.write(line);
}
break;
}
}
this.internal.write("]");
}]);
/**
* @name createAnnotation
* @function
* @param {Object} options
*/
jsPDFAPI.createAnnotation = function (options) {
var pageInfo = this.internal.getCurrentPageInfo();
switch (options.type) {
case 'link':
this.link(options.bounds.x, options.bounds.y, options.bounds.w, options.bounds.h, options);
break;
case 'text':
case 'freetext':
pageInfo.pageContext.annotations.push(options);
break;
}
};
/**
* Create a link
*
* valid options
* pageNumber or url [required]
* If pageNumber is specified, top and zoom may also be specified
* @name link
* @function
* @param {number} x
* @param {number} y
* @param {number} w
* @param {number} h
* @param {Object} options
*/
jsPDFAPI.link = function (x, y, w, h, options) {
var pageInfo = this.internal.getCurrentPageInfo();
pageInfo.pageContext.annotations.push({
x: x,
y: y,
w: w,
h: h,
options: options,
type: 'link'
});
};
/**
* Currently only supports single line text.
* Returns the width of the text/link
*
* @name textWithLink
* @function
* @param {string} text
* @param {number} x
* @param {number} y
* @param {Object} options
* @returns {number} width the width of the text/link
*/
jsPDFAPI.textWithLink = function (text, x, y, options) {
var width = this.getTextWidth(text);
var height = this.internal.getLineHeight() / this.internal.scaleFactor;
this.text(text, x, y); //TODO We really need the text baseline height to do this correctly.
// Or ability to draw text on top, bottom, center, or baseline.
y += height * .2;
this.link(x, y - height, width, height, options);
return width;
}; //TODO move into external library
/**
* @name getTextWidth
* @function
* @param {string} text
* @returns {number} txtWidth
*/
jsPDFAPI.getTextWidth = function (text) {
var fontSize = this.internal.getFontSize();
var txtWidth = this.getStringUnitWidth(text) * fontSize / this.internal.scaleFactor;
return txtWidth;
};
return this;
})(jsPDF.API);
/**
* @license
* Copyright (c) 2017 Aras Abbasi
*
* Licensed under the MIT License.
* http://opensource.org/licenses/mit-license
*/
/**
* jsPDF arabic parser PlugIn
*
* @name arabic
* @module
*/
(function (jsPDFAPI) {
/**
* Arabic shape substitutions: char code => (isolated, final, initial, medial).
* Arabic Substition A
*/
var arabicSubstitionA = {
0x0621: [0xFE80],
// ARABIC LETTER HAMZA
0x0622: [0xFE81, 0xFE82],
// ARABIC LETTER ALEF WITH MADDA ABOVE
0x0623: [0xFE83, 0xFE84],
// ARABIC LETTER ALEF WITH HAMZA ABOVE
0x0624: [0xFE85, 0xFE86],
// ARABIC LETTER WAW WITH HAMZA ABOVE
0x0625: [0xFE87, 0xFE88],
// ARABIC LETTER ALEF WITH HAMZA BELOW
0x0626: [0xFE89, 0xFE8A, 0xFE8B, 0xFE8C],
// ARABIC LETTER YEH WITH HAMZA ABOVE
0x0627: [0xFE8D, 0xFE8E],
// ARABIC LETTER ALEF
0x0628: [0xFE8F, 0xFE90, 0xFE91, 0xFE92],
// ARABIC LETTER BEH
0x0629: [0xFE93, 0xFE94],
// ARABIC LETTER TEH MARBUTA
0x062A: [0xFE95, 0xFE96, 0xFE97, 0xFE98],
// ARABIC LETTER TEH
0x062B: [0xFE99, 0xFE9A, 0xFE9B, 0xFE9C],
// ARABIC LETTER THEH
0x062C: [0xFE9D, 0xFE9E, 0xFE9F, 0xFEA0],
// ARABIC LETTER JEEM
0x062D: [0xFEA1, 0xFEA2, 0xFEA3, 0xFEA4],
// ARABIC LETTER HAH
0x062E: [0xFEA5, 0xFEA6, 0xFEA7, 0xFEA8],
// ARABIC LETTER KHAH
0x062F: [0xFEA9, 0xFEAA],
// ARABIC LETTER DAL
0x0630: [0xFEAB, 0xFEAC],
// ARABIC LETTER THAL
0x0631: [0xFEAD, 0xFEAE],
// ARABIC LETTER REH
0x0632: [0xFEAF, 0xFEB0],
// ARABIC LETTER ZAIN
0x0633: [0xFEB1, 0xFEB2, 0xFEB3, 0xFEB4],
// ARABIC LETTER SEEN
0x0634: [0xFEB5, 0xFEB6, 0xFEB7, 0xFEB8],
// ARABIC LETTER SHEEN
0x0635: [0xFEB9, 0xFEBA, 0xFEBB, 0xFEBC],
// ARABIC LETTER SAD
0x0636: [0xFEBD, 0xFEBE, 0xFEBF, 0xFEC0],
// ARABIC LETTER DAD
0x0637: [0xFEC1, 0xFEC2, 0xFEC3, 0xFEC4],
// ARABIC LETTER TAH
0x0638: [0xFEC5, 0xFEC6, 0xFEC7, 0xFEC8],
// ARABIC LETTER ZAH
0x0639: [0xFEC9, 0xFECA, 0xFECB, 0xFECC],
// ARABIC LETTER AIN
0x063A: [0xFECD, 0xFECE, 0xFECF, 0xFED0],
// ARABIC LETTER GHAIN
0x0641: [0xFED1, 0xFED2, 0xFED3, 0xFED4],
// ARABIC LETTER FEH
0x0642: [0xFED5, 0xFED6, 0xFED7, 0xFED8],
// ARABIC LETTER QAF
0x0643: [0xFED9, 0xFEDA, 0xFEDB, 0xFEDC],
// ARABIC LETTER KAF
0x0644: [0xFEDD, 0xFEDE, 0xFEDF, 0xFEE0],
// ARABIC LETTER LAM
0x0645: [0xFEE1, 0xFEE2, 0xFEE3, 0xFEE4],
// ARABIC LETTER MEEM
0x0646: [0xFEE5, 0xFEE6, 0xFEE7, 0xFEE8],
// ARABIC LETTER NOON
0x0647: [0xFEE9, 0xFEEA, 0xFEEB, 0xFEEC],
// ARABIC LETTER HEH
0x0648: [0xFEED, 0xFEEE],
// ARABIC LETTER WAW
0x0649: [0xFEEF, 0xFEF0, 64488, 64489],
// ARABIC LETTER ALEF MAKSURA
0x064A: [0xFEF1, 0xFEF2, 0xFEF3, 0xFEF4],
// ARABIC LETTER YEH
0x0671: [0xFB50, 0xFB51],
// ARABIC LETTER ALEF WASLA
0x0677: [0xFBDD],
// ARABIC LETTER U WITH HAMZA ABOVE
0x0679: [0xFB66, 0xFB67, 0xFB68, 0xFB69],
// ARABIC LETTER TTEH
0x067A: [0xFB5E, 0xFB5F, 0xFB60, 0xFB61],
// ARABIC LETTER TTEHEH
0x067B: [0xFB52, 0xFB53, 0xFB54, 0xFB55],
// ARABIC LETTER BEEH
0x067E: [0xFB56, 0xFB57, 0xFB58, 0xFB59],
// ARABIC LETTER PEH
0x067F: [0xFB62, 0xFB63, 0xFB64, 0xFB65],
// ARABIC LETTER TEHEH
0x0680: [0xFB5A, 0xFB5B, 0xFB5C, 0xFB5D],
// ARABIC LETTER BEHEH
0x0683: [0xFB76, 0xFB77, 0xFB78, 0xFB79],
// ARABIC LETTER NYEH
0x0684: [0xFB72, 0xFB73, 0xFB74, 0xFB75],
// ARABIC LETTER DYEH
0x0686: [0xFB7A, 0xFB7B, 0xFB7C, 0xFB7D],
// ARABIC LETTER TCHEH
0x0687: [0xFB7E, 0xFB7F, 0xFB80, 0xFB81],
// ARABIC LETTER TCHEHEH
0x0688: [0xFB88, 0xFB89],
// ARABIC LETTER DDAL
0x068C: [0xFB84, 0xFB85],
// ARABIC LETTER DAHAL
0x068D: [0xFB82, 0xFB83],
// ARABIC LETTER DDAHAL
0x068E: [0xFB86, 0xFB87],
// ARABIC LETTER DUL
0x0691: [0xFB8C, 0xFB8D],
// ARABIC LETTER RREH
0x0698: [0xFB8A, 0xFB8B],
// ARABIC LETTER JEH
0x06A4: [0xFB6A, 0xFB6B, 0xFB6C, 0xFB6D],
// ARABIC LETTER VEH
0x06A6: [0xFB6E, 0xFB6F, 0xFB70, 0xFB71],
// ARABIC LETTER PEHEH
0x06A9: [0xFB8E, 0xFB8F, 0xFB90, 0xFB91],
// ARABIC LETTER KEHEH
0x06AD: [0xFBD3, 0xFBD4, 0xFBD5, 0xFBD6],
// ARABIC LETTER NG
0x06AF: [0xFB92, 0xFB93, 0xFB94, 0xFB95],
// ARABIC LETTER GAF
0x06B1: [0xFB9A, 0xFB9B, 0xFB9C, 0xFB9D],
// ARABIC LETTER NGOEH
0x06B3: [0xFB96, 0xFB97, 0xFB98, 0xFB99],
// ARABIC LETTER GUEH
0x06BA: [0xFB9E, 0xFB9F],
// ARABIC LETTER NOON GHUNNA
0x06BB: [0xFBA0, 0xFBA1, 0xFBA2, 0xFBA3],
// ARABIC LETTER RNOON
0x06BE: [0xFBAA, 0xFBAB, 0xFBAC, 0xFBAD],
// ARABIC LETTER HEH DOACHASHMEE
0x06C0: [0xFBA4, 0xFBA5],
// ARABIC LETTER HEH WITH YEH ABOVE
0x06C1: [0xFBA6, 0xFBA7, 0xFBA8, 0xFBA9],
// ARABIC LETTER HEH GOAL
0x06C5: [0xFBE0, 0xFBE1],
// ARABIC LETTER KIRGHIZ OE
0x06C6: [0xFBD9, 0xFBDA],
// ARABIC LETTER OE
0x06C7: [0xFBD7, 0xFBD8],
// ARABIC LETTER U
0x06C8: [0xFBDB, 0xFBDC],
// ARABIC LETTER YU
0x06C9: [0xFBE2, 0xFBE3],
// ARABIC LETTER KIRGHIZ YU
0x06CB: [0xFBDE, 0xFBDF],
// ARABIC LETTER VE
0x06CC: [0xFBFC, 0xFBFD, 0xFBFE, 0xFBFF],
// ARABIC LETTER FARSI YEH
0x06D0: [0xFBE4, 0xFBE5, 0xFBE6, 0xFBE7],
//ARABIC LETTER E
0x06D2: [0xFBAE, 0xFBAF],
// ARABIC LETTER YEH BARREE
0x06D3: [0xFBB0, 0xFBB1] // ARABIC LETTER YEH BARREE WITH HAMZA ABOVE
};
var ligatures = {
0xFEDF: {
0xFE82: 0xFEF5,
// ARABIC LIGATURE LAM WITH ALEF WITH MADDA ABOVE ISOLATED FORM
0xFE84: 0xFEF7,
// ARABIC LIGATURE LAM WITH ALEF WITH HAMZA ABOVE ISOLATED FORM
0xFE88: 0xFEF9,
// ARABIC LIGATURE LAM WITH ALEF WITH HAMZA BELOW ISOLATED FORM
0xFE8E: 0xFEFB // ARABIC LIGATURE LAM WITH ALEF ISOLATED FORM
},
0xFEE0: {
0xFE82: 0xFEF6,
// ARABIC LIGATURE LAM WITH ALEF WITH MADDA ABOVE FINAL FORM
0xFE84: 0xFEF8,
// ARABIC LIGATURE LAM WITH ALEF WITH HAMZA ABOVE FINAL FORM
0xFE88: 0xFEFA,
// ARABIC LIGATURE LAM WITH ALEF WITH HAMZA BELOW FINAL FORM
0xFE8E: 0xFEFC // ARABIC LIGATURE LAM WITH ALEF FINAL FORM
},
0xFE8D: {
0xFEDF: {
0xFEE0: {
0xFEEA: 0xFDF2
}
}
},
// ALLAH
0x0651: {
0x064C: 0xFC5E,
// Shadda + Dammatan
0x064D: 0xFC5F,
// Shadda + Kasratan
0x064E: 0xFC60,
// Shadda + Fatha
0x064F: 0xFC61,
// Shadda + Damma
0x0650: 0xFC62 // Shadda + Kasra
}
};
var arabic_diacritics = {
1612: 64606,
// Shadda + Dammatan
1613: 64607,
// Shadda + Kasratan
1614: 64608,
// Shadda + Fatha
1615: 64609,
// Shadda + Damma
1616: 64610 // Shadda + Kasra
};
var alfletter = [1570, 1571, 1573, 1575];
var noChangeInForm = -1;
var isolatedForm = 0;
var finalForm = 1;
var initialForm = 2;
var medialForm = 3;
jsPDFAPI.__arabicParser__ = {}; //private
var isInArabicSubstitutionA = jsPDFAPI.__arabicParser__.isInArabicSubstitutionA = function (letter) {
return typeof arabicSubstitionA[letter.charCodeAt(0)] !== "undefined";
};
var isArabicLetter = jsPDFAPI.__arabicParser__.isArabicLetter = function (letter) {
return typeof letter === "string" && /^[\u0600-\u06FF\u0750-\u077F\u08A0-\u08FF\uFB50-\uFDFF\uFE70-\uFEFF]+$/.test(letter);
};
var isArabicEndLetter = jsPDFAPI.__arabicParser__.isArabicEndLetter = function (letter) {
return isArabicLetter(letter) && isInArabicSubstitutionA(letter) && arabicSubstitionA[letter.charCodeAt(0)].length <= 2;
};
var isArabicAlfLetter = jsPDFAPI.__arabicParser__.isArabicAlfLetter = function (letter) {
return isArabicLetter(letter) && alfletter.indexOf(letter.charCodeAt(0)) >= 0;
};
var arabicLetterHasIsolatedForm = jsPDFAPI.__arabicParser__.arabicLetterHasIsolatedForm = function (letter) {
return isArabicLetter(letter) && isInArabicSubstitutionA(letter) && arabicSubstitionA[letter.charCodeAt(0)].length >= 1;
};
var arabicLetterHasFinalForm = jsPDFAPI.__arabicParser__.arabicLetterHasFinalForm = function (letter) {
return isArabicLetter(letter) && isInArabicSubstitutionA(letter) && arabicSubstitionA[letter.charCodeAt(0)].length >= 2;
};
var arabicLetterHasInitialForm = jsPDFAPI.__arabicParser__.arabicLetterHasInitialForm = function (letter) {
return isArabicLetter(letter) && isInArabicSubstitutionA(letter) && arabicSubstitionA[letter.charCodeAt(0)].length >= 3;
};
var arabicLetterHasMedialForm = jsPDFAPI.__arabicParser__.arabicLetterHasMedialForm = function (letter) {
return isArabicLetter(letter) && isInArabicSubstitutionA(letter) && arabicSubstitionA[letter.charCodeAt(0)].length == 4;
};
var resolveLigatures = jsPDFAPI.__arabicParser__.resolveLigatures = function (letters) {
var i = 0;
var tmpLigatures = ligatures;
var position = isolatedForm;
var result = '';
var effectedLetters = 0;
for (i = 0; i < letters.length; i += 1) {
if (typeof tmpLigatures[letters.charCodeAt(i)] !== "undefined") {
effectedLetters++;
tmpLigatures = tmpLigatures[letters.charCodeAt(i)];
if (typeof tmpLigatures === "number") {
position = getCorrectForm(letters.charAt(i), letters.charAt(i - effectedLetters), letters.charAt(i + 1));
position = position !== -1 ? position : 0;
result += String.fromCharCode(tmpLigatures);
tmpLigatures = ligatures;
effectedLetters = 0;
}
if (i === letters.length - 1) {
tmpLigatures = ligatures;
result += letters.charAt(i - (effectedLetters - 1));
i = i - (effectedLetters - 1);
effectedLetters = 0;
}
} else {
tmpLigatures = ligatures;
result += letters.charAt(i - effectedLetters);
i = i - effectedLetters;
effectedLetters = 0;
}
}
return result;
};
var isArabicDiacritic = jsPDFAPI.__arabicParser__.isArabicDiacritic = function (letter) {
return letter !== undefined && arabic_diacritics[letter.charCodeAt(0)] !== undefined;
};
var getCorrectForm = jsPDFAPI.__arabicParser__.getCorrectForm = function (currentChar, beforeChar, nextChar) {
if (!isArabicLetter(currentChar)) {
return -1;
}
if (isInArabicSubstitutionA(currentChar) === false) {
return noChangeInForm;
}
if (!arabicLetterHasFinalForm(currentChar) || !isArabicLetter(beforeChar) && !isArabicLetter(nextChar) || !isArabicLetter(nextChar) && isArabicEndLetter(beforeChar) || isArabicEndLetter(currentChar) && !isArabicLetter(beforeChar) || isArabicEndLetter(currentChar) && isArabicAlfLetter(beforeChar) || isArabicEndLetter(currentChar) && isArabicEndLetter(beforeChar)) {
return isolatedForm;
}
if (arabicLetterHasMedialForm(currentChar) && isArabicLetter(beforeChar) && !isArabicEndLetter(beforeChar) && isArabicLetter(nextChar) && arabicLetterHasFinalForm(nextChar)) {
return medialForm;
}
if (isArabicEndLetter(currentChar) || !isArabicLetter(nextChar)) {
return finalForm;
}
return initialForm;
};
/**
* @name processArabic
* @function
* @param {string} text
* @param {boolean} reverse
* @returns {string}
*/
var processArabic = jsPDFAPI.__arabicParser__.processArabic = jsPDFAPI.processArabic = function (text) {
text = text || "";
var result = "";
var i = 0;
var j = 0;
var position = 0;
var currentLetter = "";
var prevLetter = "";
var nextLetter = "";
var words = text.split("\\s+");
var newWords = [];
for (i = 0; i < words.length; i += 1) {
newWords.push('');
for (j = 0; j < words[i].length; j += 1) {
currentLetter = words[i][j];
prevLetter = words[i][j - 1];
nextLetter = words[i][j + 1];
if (isArabicLetter(currentLetter)) {
position = getCorrectForm(currentLetter, prevLetter, nextLetter);
if (position !== -1) {
newWords[i] += String.fromCharCode(arabicSubstitionA[currentLetter.charCodeAt(0)][position]);
} else {
newWords[i] += currentLetter;
}
} else {
newWords[i] += currentLetter;
}
}
newWords[i] = resolveLigatures(newWords[i]);
}
result = newWords.join(' ');
return result;
};
var arabicParserFunction = function arabicParserFunction(args) {
var text = args.text;
var x = args.x;
var y = args.y;
var options = args.options || {};
var mutex = args.mutex || {};
var lang = options.lang;
var tmpText = [];
if (Object.prototype.toString.call(text) === '[object Array]') {
var i = 0;
tmpText = [];
for (i = 0; i < text.length; i += 1) {
if (Object.prototype.toString.call(text[i]) === '[object Array]') {
tmpText.push([processArabic(text[i][0]), text[i][1], text[i][2]]);
} else {
tmpText.push([processArabic(text[i])]);
}
}
args.text = tmpText;
} else {
args.text = processArabic(text);
}
};
jsPDFAPI.events.push(['preProcessText', arabicParserFunction]);
})(jsPDF.API);
/** @license
* jsPDF Autoprint Plugin
*
* Licensed under the MIT License.
* http://opensource.org/licenses/mit-license
*/
/**
* @name autoprint
* @module
*/
(function (jsPDFAPI) {
/**
* Makes the PDF automatically print. This works in Chrome, Firefox, Acrobat
* Reader.
*
* @name autoPrint
* @function
* @param {Object} options (optional) Set the attribute variant to 'non-conform' (default) or 'javascript' to activate different methods of automatic printing when opening in a PDF-viewer .
* @returns {jsPDF}
* @example
* var doc = new jsPDF();
* doc.text(10, 10, 'This is a test');
* doc.autoPrint({variant: 'non-conform'});
* doc.save('autoprint.pdf');
*/
jsPDFAPI.autoPrint = function (options) {
var refAutoPrintTag;
options = options || {};
options.variant = options.variant || 'non-conform';
switch (options.variant) {
case 'javascript':
//https://github.com/Rob--W/pdf.js/commit/c676ecb5a0f54677b9f3340c3ef2cf42225453bb
this.addJS('print({});');
break;
case 'non-conform':
default:
this.internal.events.subscribe('postPutResources', function () {
refAutoPrintTag = this.internal.newObject();
this.internal.out("<<");
this.internal.out("/S /Named");
this.internal.out("/Type /Action");
this.internal.out("/N /Print");
this.internal.out(">>");
this.internal.out("endobj");
});
this.internal.events.subscribe("putCatalog", function () {
this.internal.out("/OpenAction " + refAutoPrintTag + " 0 R");
});
break;
}
return this;
};
})(jsPDF.API);
/**
* @license
* Copyright (c) 2014 Steven Spungin (TwelveTone LLC) [email protected]
*
* Licensed under the MIT License.
* http://opensource.org/licenses/mit-license
*/
/**
* jsPDF Canvas PlugIn
* This plugin mimics the HTML5 Canvas
*
* The goal is to provide a way for current canvas users to print directly to a PDF.
* @name canvas
* @module
*/
(function (jsPDFAPI) {
/**
* @class Canvas
* @classdesc A Canvas Wrapper for jsPDF
*/
var Canvas = function Canvas() {
var jsPdfInstance = undefined;
Object.defineProperty(this, 'pdf', {
get: function get() {
return jsPdfInstance;
},
set: function set(value) {
jsPdfInstance = value;
}
});
var _width = 150;
/**
* The height property is a positive integer reflecting the height HTML attribute of the