diff --git a/.DS_Store b/.DS_Store index 762040a..7f1bd2b 100644 Binary files a/.DS_Store and b/.DS_Store differ diff --git a/fonts/Alegreya-Bold.ttf b/fonts/Alegreya-Bold.ttf deleted file mode 100755 index e843cea..0000000 Binary files a/fonts/Alegreya-Bold.ttf and /dev/null differ diff --git a/fonts/AlegreyaSans-Light.ttf b/fonts/AlegreyaSans-Light.ttf deleted file mode 100755 index b43efc9..0000000 Binary files a/fonts/AlegreyaSans-Light.ttf and /dev/null differ diff --git a/fonts/Chalkboard.ttc b/fonts/Chalkboard.ttc deleted file mode 100755 index 5ae65ee..0000000 Binary files a/fonts/Chalkboard.ttc and /dev/null differ diff --git a/fonts/CrimsonText-Bold.ttf b/fonts/CrimsonText-Bold.ttf deleted file mode 100755 index 783197a..0000000 Binary files a/fonts/CrimsonText-Bold.ttf and /dev/null differ diff --git a/fonts/CrimsonText-BoldItalic.ttf b/fonts/CrimsonText-BoldItalic.ttf deleted file mode 100755 index 4ecef6f..0000000 Binary files a/fonts/CrimsonText-BoldItalic.ttf and /dev/null differ diff --git a/fonts/CrimsonText-Italic.ttf b/fonts/CrimsonText-Italic.ttf deleted file mode 100755 index 036b340..0000000 Binary files a/fonts/CrimsonText-Italic.ttf and /dev/null differ diff --git a/fonts/CrimsonText-Roman.ttf b/fonts/CrimsonText-Roman.ttf deleted file mode 100755 index 67acd70..0000000 Binary files a/fonts/CrimsonText-Roman.ttf and /dev/null differ diff --git a/fonts/CrimsonText-Semibold.ttf b/fonts/CrimsonText-Semibold.ttf deleted file mode 100755 index 8569ad0..0000000 Binary files a/fonts/CrimsonText-Semibold.ttf and /dev/null differ diff --git a/fonts/CrimsonText-SemiboldItalic.ttf b/fonts/CrimsonText-SemiboldItalic.ttf deleted file mode 100755 index 5f04d7f..0000000 Binary files a/fonts/CrimsonText-SemiboldItalic.ttf and /dev/null differ diff --git a/fonts/GoodDog.ttf b/fonts/GoodDog.ttf deleted file mode 100755 index da5af27..0000000 Binary files a/fonts/GoodDog.ttf and /dev/null differ diff --git a/fonts/Merriweather-Regular.ttf b/fonts/Merriweather-Regular.ttf deleted file mode 100755 index 28a80e4..0000000 Binary files a/fonts/Merriweather-Regular.ttf and /dev/null differ diff --git a/fonts/SourceCodePro-Bold.ttf b/fonts/SourceCodePro-Bold.ttf deleted file mode 100755 index a56f1fa..0000000 Binary files a/fonts/SourceCodePro-Bold.ttf and /dev/null differ diff --git a/fonts/SourceCodePro-Regular.ttf b/fonts/SourceCodePro-Regular.ttf deleted file mode 100755 index b2cff92..0000000 Binary files a/fonts/SourceCodePro-Regular.ttf and /dev/null differ diff --git a/js/jspdf.PLUGINTEMPLATE.js b/js/jspdf.PLUGINTEMPLATE.js deleted file mode 100644 index ff8de4b..0000000 --- a/js/jspdf.PLUGINTEMPLATE.js +++ /dev/null @@ -1,45 +0,0 @@ -/** ==================================================================== - * jsPDF [NAME] plugin - * Copyright (c) 2013 [YOUR NAME HERE] [WAY TO CONTACT YOU HERE] - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE - * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION - * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * ==================================================================== - */ - -(function(jsPDFAPI) { -'use strict' - -jsPDFAPI.myFunction = function(args) { - 'use strict' - // `this` is _jsPDF object returned when jsPDF is inited (new jsPDF()) - // `this.internal` is a collection of useful, specific-to-raw-PDF-stream functions. - // for example, `this.internal.write` function allowing you to write directly to PDF stream. - // `this.line`, `this.text` etc are available directly. - // so if your plugin just wraps complex series of this.line or this.text or other public API calls, - // you don't need to look into `this.internal` - // See _jsPDF object in jspdf.js for complete list of what's available to you. - - - // it is good practice to return ref to jsPDF instance to make - // the calls chainable. - return this -} - -})(jsPDF.API) diff --git a/js/jspdf.js b/js/jspdf.js deleted file mode 100644 index 55126f2..0000000 --- a/js/jspdf.js +++ /dev/null @@ -1,1930 +0,0 @@ -/** @preserve - * jsPDF - PDF Document creation from JavaScript - * Version ${versionID} - * CommitID ${commitID} - * - * Copyright (c) 2010-2014 James Hall, https://github.com/MrRio/jsPDF - * 2010 Aaron Spike, https://github.com/acspike - * 2012 Willow Systems Corporation, willow-systems.com - * 2012 Pablo Hess, https://github.com/pablohess - * 2012 Florian Jenett, https://github.com/fjenett - * 2013 Warren Weckesser, https://github.com/warrenweckesser - * 2013 Youssef Beddad, https://github.com/lifof - * 2013 Lee Driscoll, https://github.com/lsdriscoll - * 2013 Stefan Slonevskiy, https://github.com/stefslon - * 2013 Jeremy Morel, https://github.com/jmorel - * 2013 Christoph Hartmann, https://github.com/chris-rock - * 2014 Juan Pablo Gaviria, https://github.com/juanpgaviria - * 2014 James Makes, https://github.com/dollaruw - * 2014 Diego Casorran, https://github.com/diegocr - * 2014 Steven Spungin, https://github.com/Flamenco - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE - * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION - * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - * Contributor(s): - * siefkenj, ahwolf, rickygu, Midnith, saintclair, eaparango, - * kim3er, mfo, alnorth, Flamenco - */ - -/** - * Creates new jsPDF document object instance. - * - * @class - * @param orientation One of "portrait" or "landscape" (or shortcuts "p" (Default), "l") - * @param unit Measurement unit to be used when coordinates are specified. - * One of "pt" (points), "mm" (Default), "cm", "in" - * @param format One of 'pageFormats' as shown below, default: a4 - * @returns {jsPDF} - * @name jsPDF - */ -var jsPDF = (function(global) { - 'use strict'; - var pdfVersion = '1.3', - pageFormats = { // Size in pt of various paper formats - 'a0' : [2383.94, 3370.39], 'a1' : [1683.78, 2383.94], - 'a2' : [1190.55, 1683.78], 'a3' : [ 841.89, 1190.55], - 'a4' : [ 595.28, 841.89], 'a5' : [ 419.53, 595.28], - 'a6' : [ 297.64, 419.53], 'a7' : [ 209.76, 297.64], - 'a8' : [ 147.40, 209.76], 'a9' : [ 104.88, 147.40], - 'a10' : [ 73.70, 104.88], 'b0' : [2834.65, 4008.19], - 'b1' : [2004.09, 2834.65], 'b2' : [1417.32, 2004.09], - 'b3' : [1000.63, 1417.32], 'b4' : [ 708.66, 1000.63], - 'b5' : [ 498.90, 708.66], 'b6' : [ 354.33, 498.90], - 'b7' : [ 249.45, 354.33], 'b8' : [ 175.75, 249.45], - 'b9' : [ 124.72, 175.75], 'b10' : [ 87.87, 124.72], - 'c0' : [2599.37, 3676.54], 'c1' : [1836.85, 2599.37], - 'c2' : [1298.27, 1836.85], 'c3' : [ 918.43, 1298.27], - 'c4' : [ 649.13, 918.43], 'c5' : [ 459.21, 649.13], - 'c6' : [ 323.15, 459.21], 'c7' : [ 229.61, 323.15], - 'c8' : [ 161.57, 229.61], 'c9' : [ 113.39, 161.57], - 'c10' : [ 79.37, 113.39], 'dl' : [ 311.81, 623.62], - 'letter' : [612, 792], - 'government-letter' : [576, 756], - 'legal' : [612, 1008], - 'junior-legal' : [576, 360], - 'ledger' : [1224, 792], - 'tabloid' : [792, 1224], - 'credit-card' : [153, 243] - }; - - /** - * jsPDF's Internal PubSub Implementation. - * See mrrio.github.io/jsPDF/doc/symbols/PubSub.html - * Backward compatible rewritten on 2014 by - * Diego Casorran, https://github.com/diegocr - * - * @class - * @name PubSub - */ - function PubSub(context) { - var topics = {}; - - this.subscribe = function(topic, callback, once) { - if(typeof callback !== 'function') { - return false; - } - - if(!topics.hasOwnProperty(topic)) { - topics[topic] = {}; - } - - var id = Math.random().toString(35); - topics[topic][id] = [callback,!!once]; - - return id; - }; - - this.unsubscribe = function(token) { - for(var topic in topics) { - if(topics[topic][token]) { - delete topics[topic][token]; - return true; - } - } - return false; - }; - - this.publish = function(topic) { - if(topics.hasOwnProperty(topic)) { - var args = Array.prototype.slice.call(arguments, 1), idr = []; - - for(var id in topics[topic]) { - var sub = topics[topic][id]; - try { - sub[0].apply(context, args); - } catch(ex) { - if(global.console) { - console.error('jsPDF PubSub Error', ex.message, ex); - } - } - if(sub[1]) idr.push(id); - } - if(idr.length) idr.forEach(this.unsubscribe); - } - }; - } - - /** - * @constructor - * @private - */ - function jsPDF(orientation, unit, format, compressPdf) { - var options = {}; - - if (typeof orientation === 'object') { - options = orientation; - - orientation = options.orientation; - unit = options.unit || unit; - format = options.format || format; - compressPdf = options.compress || options.compressPdf || compressPdf; - } - - // Default options - unit = unit || 'mm'; - format = format || 'a4'; - orientation = ('' + (orientation || 'P')).toLowerCase(); - - var format_as_string = ('' + format).toLowerCase(), - compress = !!compressPdf && typeof Uint8Array === 'function', - textColor = options.textColor || '0 g', - drawColor = options.drawColor || '0 G', - activeFontSize = options.fontSize || 16, - lineHeightProportion = options.lineHeight || 1.15, - lineWidth = options.lineWidth || 0.200025, // 2mm - objectNumber = 2, // 'n' Current object number - outToPages = !1, // switches where out() prints. outToPages true = push to pages obj. outToPages false = doc builder content - offsets = [], // List of offsets. Activated and reset by buildDocument(). Pupulated by various calls buildDocument makes. - fonts = {}, // collection of font objects, where key is fontKey - a dynamically created label for a given font. - fontmap = {}, // mapping structure fontName > fontStyle > font key - performance layer. See addFont() - activeFontKey, // will be string representing the KEY of the font as combination of fontName + fontStyle - k, // Scale factor - tmp, - page = 0, - currentPage, - pages = [], - pagedim = {}, - content = [], - lineCapID = 0, - lineJoinID = 0, - content_length = 0, - pageWidth, - pageHeight, - pageMode, - zoomMode, - layoutMode, - documentProperties = { - 'title' : '', - 'subject' : '', - 'author' : '', - 'keywords' : '', - 'creator' : '' - }, - API = {}, - events = new PubSub(API), - lastTextWasStroke = false, - - ///////////////////// - // Private functions - ///////////////////// - f2 = function(number) { - return number.toFixed(2); // Ie, %.2f - }, - f3 = function(number) { - return number.toFixed(3); // Ie, %.3f - }, - padd2 = function(number) { - return ('0' + parseInt(number)).slice(-2); - }, - out = function(string) { - if (outToPages) { - /* set by beginPage */ - pages[currentPage].push(string); - } else { - // +1 for '\n' that will be used to join 'content' - content_length += string.length + 1; - content.push(string); - } - }, - newObject = function() { - // Begin a new object - objectNumber++; - offsets[objectNumber] = content_length; - out(objectNumber + ' 0 obj'); - return objectNumber; - }, - // Does not output the object. The caller must call newObjectDeferredBegin(oid) before outputing any data - newObjectDeferred = function() { - objectNumber++; - offsets[objectNumber] = function(){ - return content_length; - }; - return objectNumber; - }, - newObjectDeferredBegin = function(oid) { - offsets[oid] = content_length; - }, - putStream = function(str) { - out('stream'); - out(str); - out('endstream'); - }, - putPages = function() { - var n,p,arr,i,deflater,adler32,adler32cs,wPt,hPt; - - adler32cs = global.adler32cs || jsPDF.adler32cs; - if (compress && typeof adler32cs === 'undefined') { - compress = false; - } - - // outToPages = false as set in endDocument(). out() writes to content. - - for (n = 1; n <= page; n++) { - newObject(); - wPt = (pageWidth = pagedim[n].width) * k; - hPt = (pageHeight = pagedim[n].height) * k; - out('<>'); - out('endobj'); - - // Page content - p = pages[n].join('\n'); - newObject(); - if (compress) { - arr = []; - i = p.length; - while(i--) { - arr[i] = p.charCodeAt(i); - } - adler32 = adler32cs.from(p); - deflater = new Deflater(6); - deflater.append(new Uint8Array(arr)); - p = deflater.flush(); - arr = new Uint8Array(p.length + 6); - arr.set(new Uint8Array([120, 156])), - arr.set(p, 2); - arr.set(new Uint8Array([adler32 & 0xFF, (adler32 >> 8) & 0xFF, (adler32 >> 16) & 0xFF, (adler32 >> 24) & 0xFF]), p.length+2); - p = String.fromCharCode.apply(null, arr); - out('<>'); - } else { - out('<>'); - } - putStream(p); - out('endobj'); - } - offsets[1] = content_length; - out('1 0 obj'); - out('<>'); - out('endobj'); - }, - putFont = function(font) { - font.objectNumber = newObject(); - out('<>'); - out('endobj'); - }, - putFonts = function() { - for (var fontKey in fonts) { - if (fonts.hasOwnProperty(fontKey)) { - putFont(fonts[fontKey]); - } - } - }, - putXobjectDict = function() { - // Loop through images, or other data objects - events.publish('putXobjectDict'); - }, - putResourceDictionary = function() { - out('/ProcSet [/PDF /Text /ImageB /ImageC /ImageI]'); - out('/Font <<'); - - // Do this for each font, the '1' bit is the index of the font - for (var fontKey in fonts) { - if (fonts.hasOwnProperty(fontKey)) { - out('/' + fontKey + ' ' + fonts[fontKey].objectNumber + ' 0 R'); - } - } - out('>>'); - out('/XObject <<'); - putXobjectDict(); - out('>>'); - }, - putResources = function() { - putFonts(); - events.publish('putResources'); - // Resource dictionary - offsets[2] = content_length; - out('2 0 obj'); - out('<<'); - putResourceDictionary(); - out('>>'); - out('endobj'); - events.publish('postPutResources'); - }, - addToFontDictionary = function(fontKey, fontName, fontStyle) { - // this is mapping structure for quick font key lookup. - // returns the KEY of the font (ex: "F1") for a given - // pair of font name and type (ex: "Arial". "Italic") - if (!fontmap.hasOwnProperty(fontName)) { - fontmap[fontName] = {}; - } - fontmap[fontName][fontStyle] = fontKey; - }, - /** - * FontObject describes a particular font as member of an instnace of jsPDF - * - * It's a collection of properties like 'id' (to be used in PDF stream), - * 'fontName' (font's family name), 'fontStyle' (font's style variant label) - * - * @class - * @public - * @property id {String} PDF-document-instance-specific label assinged to the font. - * @property PostScriptName {String} PDF specification full name for the font - * @property encoding {Object} Encoding_name-to-Font_metrics_object mapping. - * @name FontObject - */ - addFont = function(PostScriptName, fontName, fontStyle, encoding) { - var fontKey = 'F' + (Object.keys(fonts).length + 1).toString(10), - // This is FontObject - font = fonts[fontKey] = { - 'id' : fontKey, - 'PostScriptName' : PostScriptName, - 'fontName' : fontName, - 'fontStyle' : fontStyle, - 'encoding' : encoding, - 'metadata' : {} - }; - addToFontDictionary(fontKey, fontName, fontStyle); - events.publish('addFont', font); - - return fontKey; - }, - addFonts = function() { - - var HELVETICA = "helvetica", - TIMES = "times", - COURIER = "courier", - NORMAL = "normal", - BOLD = "bold", - ITALIC = "italic", - BOLD_ITALIC = "bolditalic", - encoding = 'StandardEncoding', - standardFonts = [ - ['Helvetica', HELVETICA, NORMAL], - ['Helvetica-Bold', HELVETICA, BOLD], - ['Helvetica-Oblique', HELVETICA, ITALIC], - ['Helvetica-BoldOblique', HELVETICA, BOLD_ITALIC], - ['Courier', COURIER, NORMAL], - ['Courier-Bold', COURIER, BOLD], - ['Courier-Oblique', COURIER, ITALIC], - ['Courier-BoldOblique', COURIER, BOLD_ITALIC], - ['Times-Roman', TIMES, NORMAL], - ['Times-Bold', TIMES, BOLD], - ['Times-Italic', TIMES, ITALIC], - ['Times-BoldItalic', TIMES, BOLD_ITALIC] - ]; - - for (var i = 0, l = standardFonts.length; i < l; i++) { - var fontKey = addFont( - standardFonts[i][0], - standardFonts[i][1], - standardFonts[i][2], - encoding); - - // adding aliases for standard fonts, this time matching the capitalization - var parts = standardFonts[i][0].split('-'); - addToFontDictionary(fontKey, parts[0], parts[1] || ''); - } - events.publish('addFonts', { fonts : fonts, dictionary : fontmap }); - }, - SAFE = function __safeCall(fn) { - fn.foo = function __safeCallWrapper() { - try { - return fn.apply(this, arguments); - } catch (e) { - var stack = e.stack || ''; - if(~stack.indexOf(' at ')) stack = stack.split(" at ")[1]; - var m = "Error in function " + stack.split("\n")[0].split('<')[0] + ": " + e.message; - if(global.console) { - global.console.error(m, e); - if(global.alert) alert(m); - } else { - throw new Error(m); - } - } - }; - fn.foo.bar = fn; - return fn.foo; - }, - to8bitStream = function(text, flags) { - /** - * PDF 1.3 spec: - * "For text strings encoded in Unicode, the first two bytes must be 254 followed by - * 255, representing the Unicode byte order marker, U+FEFF. (This sequence conflicts - * with the PDFDocEncoding character sequence thorn ydieresis, which is unlikely - * to be a meaningful beginning of a word or phrase.) The remainder of the - * string consists of Unicode character codes, according to the UTF-16 encoding - * specified in the Unicode standard, version 2.0. Commonly used Unicode values - * are represented as 2 bytes per character, with the high-order byte appearing first - * in the string." - * - * In other words, if there are chars in a string with char code above 255, we - * recode the string to UCS2 BE - string doubles in length and BOM is prepended. - * - * HOWEVER! - * Actual *content* (body) text (as opposed to strings used in document properties etc) - * does NOT expect BOM. There, it is treated as a literal GID (Glyph ID) - * - * Because of Adobe's focus on "you subset your fonts!" you are not supposed to have - * a font that maps directly Unicode (UCS2 / UTF16BE) code to font GID, but you could - * fudge it with "Identity-H" encoding and custom CIDtoGID map that mimics Unicode - * code page. There, however, all characters in the stream are treated as GIDs, - * including BOM, which is the reason we need to skip BOM in content text (i.e. that - * that is tied to a font). - * - * To signal this "special" PDFEscape / to8bitStream handling mode, - * API.text() function sets (unless you overwrite it with manual values - * given to API.text(.., flags) ) - * flags.autoencode = true - * flags.noBOM = true - * - * =================================================================================== - * `flags` properties relied upon: - * .sourceEncoding = string with encoding label. - * "Unicode" by default. = encoding of the incoming text. - * pass some non-existing encoding name - * (ex: 'Do not touch my strings! I know what I am doing.') - * to make encoding code skip the encoding step. - * .outputEncoding = Either valid PDF encoding name - * (must be supported by jsPDF font metrics, otherwise no encoding) - * or a JS object, where key = sourceCharCode, value = outputCharCode - * missing keys will be treated as: sourceCharCode === outputCharCode - * .noBOM - * See comment higher above for explanation for why this is important - * .autoencode - * See comment higher above for explanation for why this is important - */ - - var i,l,sourceEncoding,encodingBlock,outputEncoding,newtext,isUnicode,ch,bch; - - flags = flags || {}; - sourceEncoding = flags.sourceEncoding || 'Unicode'; - outputEncoding = flags.outputEncoding; - - // This 'encoding' section relies on font metrics format - // attached to font objects by, among others, - // "Willow Systems' standard_font_metrics plugin" - // see jspdf.plugin.standard_font_metrics.js for format - // of the font.metadata.encoding Object. - // It should be something like - // .encoding = {'codePages':['WinANSI....'], 'WinANSI...':{code:code, ...}} - // .widths = {0:width, code:width, ..., 'fof':divisor} - // .kerning = {code:{previous_char_code:shift, ..., 'fof':-divisor},...} - if ((flags.autoencode || outputEncoding) && - fonts[activeFontKey].metadata && - fonts[activeFontKey].metadata[sourceEncoding] && - fonts[activeFontKey].metadata[sourceEncoding].encoding) { - encodingBlock = fonts[activeFontKey].metadata[sourceEncoding].encoding; - - // each font has default encoding. Some have it clearly defined. - if (!outputEncoding && fonts[activeFontKey].encoding) { - outputEncoding = fonts[activeFontKey].encoding; - } - - // Hmmm, the above did not work? Let's try again, in different place. - if (!outputEncoding && encodingBlock.codePages) { - outputEncoding = encodingBlock.codePages[0]; // let's say, first one is the default - } - - if (typeof outputEncoding === 'string') { - outputEncoding = encodingBlock[outputEncoding]; - } - // we want output encoding to be a JS Object, where - // key = sourceEncoding's character code and - // value = outputEncoding's character code. - if (outputEncoding) { - isUnicode = false; - newtext = []; - for (i = 0, l = text.length; i < l; i++) { - ch = outputEncoding[text.charCodeAt(i)]; - if (ch) { - newtext.push( - String.fromCharCode(ch)); - } else { - newtext.push( - text[i]); - } - - // since we are looping over chars anyway, might as well - // check for residual unicodeness - if (newtext[i].charCodeAt(0) >> 8) { - /* more than 255 */ - isUnicode = true; - } - } - text = newtext.join(''); - } - } - - i = text.length; - // isUnicode may be set to false above. Hence the triple-equal to undefined - while (isUnicode === undefined && i !== 0) { - if (text.charCodeAt(i - 1) >> 8) { - /* more than 255 */ - isUnicode = true; - } - i--; - } - if (!isUnicode) { - return text; - } - - newtext = flags.noBOM ? [] : [254, 255]; - for (i = 0, l = text.length; i < l; i++) { - ch = text.charCodeAt(i); - bch = ch >> 8; // divide by 256 - if (bch >> 8) { - /* something left after dividing by 256 second time */ - throw new Error("Character at position " + i + " of string '" - + text + "' exceeds 16bits. Cannot be encoded into UCS-2 BE"); - } - newtext.push(bch); - newtext.push(ch - (bch << 8)); - } - return String.fromCharCode.apply(undefined, newtext); - }, - pdfEscape = function(text, flags) { - /** - * Replace '/', '(', and ')' with pdf-safe versions - * - * Doing to8bitStream does NOT make this PDF display unicode text. For that - * we also need to reference a unicode font and embed it - royal pain in the rear. - * - * There is still a benefit to to8bitStream - PDF simply cannot handle 16bit chars, - * which JavaScript Strings are happy to provide. So, while we still cannot display - * 2-byte characters property, at least CONDITIONALLY converting (entire string containing) - * 16bit chars to (USC-2-BE) 2-bytes per char + BOM streams we ensure that entire PDF - * is still parseable. - * This will allow immediate support for unicode in document properties strings. - */ - return to8bitStream(text, flags).replace(/\\/g, '\\\\').replace(/\(/g, '\\(').replace(/\)/g, '\\)'); - }, - putInfo = function() { - out('/Producer (jsPDF ' + jsPDF.version + ')'); - for(var key in documentProperties) { - if(documentProperties.hasOwnProperty(key) && documentProperties[key]) { - out('/'+key.substr(0,1).toUpperCase() + key.substr(1) - +' (' + pdfEscape(documentProperties[key]) + ')'); - } - } - var created = new Date(), - tzoffset = created.getTimezoneOffset(), - tzsign = tzoffset < 0 ? '+' : '-', - tzhour = Math.floor(Math.abs(tzoffset / 60)), - tzmin = Math.abs(tzoffset % 60), - tzstr = [tzsign, padd2(tzhour), "'", padd2(tzmin), "'"].join(''); - out(['/CreationDate (D:', - created.getFullYear(), - padd2(created.getMonth() + 1), - padd2(created.getDate()), - padd2(created.getHours()), - padd2(created.getMinutes()), - padd2(created.getSeconds()), tzstr, ')'].join('')); - }, - putCatalog = function() { - out('/Type /Catalog'); - out('/Pages 1 0 R'); - // PDF13ref Section 7.2.1 - if (!zoomMode) zoomMode = 'fullwidth'; - switch(zoomMode) { - case 'fullwidth' : out('/OpenAction [3 0 R /FitH null]'); break; - case 'fullheight' : out('/OpenAction [3 0 R /FitV null]'); break; - case 'fullpage' : out('/OpenAction [3 0 R /Fit]'); break; - case 'original' : out('/OpenAction [3 0 R /XYZ null null 1]'); break; - default: - var pcn = '' + zoomMode; - if (pcn.substr(pcn.length-1) === '%') - zoomMode = parseInt(zoomMode) / 100; - if (typeof zoomMode === 'number') { - out('/OpenAction [3 0 R /XYZ null null '+f2(zoomMode)+']'); - } - } - if (!layoutMode) layoutMode = 'continuous'; - switch(layoutMode) { - case 'continuous' : out('/PageLayout /OneColumn'); break; - case 'single' : out('/PageLayout /SinglePage'); break; - case 'two': - case 'twoleft' : out('/PageLayout /TwoColumnLeft'); break; - case 'tworight' : out('/PageLayout /TwoColumnRight'); break; - } - if (pageMode) { - /** - * A name object specifying how the document should be displayed when opened: - * UseNone : Neither document outline nor thumbnail images visible -- DEFAULT - * UseOutlines : Document outline visible - * UseThumbs : Thumbnail images visible - * FullScreen : Full-screen mode, with no menu bar, window controls, or any other window visible - */ - out('/PageMode /' + pageMode); - } - events.publish('putCatalog'); - }, - putTrailer = function() { - out('/Size ' + (objectNumber + 1)); - out('/Root ' + objectNumber + ' 0 R'); - out('/Info ' + (objectNumber - 1) + ' 0 R'); - }, - beginPage = function(width,height) { - // Dimensions are stored as user units and converted to points on output - var orientation = typeof height === 'string' && height.toLowerCase(); - if (typeof width === 'string') { - var format = width.toLowerCase(); - if (pageFormats.hasOwnProperty(format)) { - width = pageFormats[format][0] / k; - height = pageFormats[format][1] / k; - } - } - if (Array.isArray(width)) { - height = width[1]; - width = width[0]; - } - if (orientation) { - switch(orientation.substr(0,1)) { - case 'l': if (height > width ) orientation = 's'; break; - case 'p': if (width > height ) orientation = 's'; break; - } - if (orientation === 's') { tmp = width; width = height; height = tmp; } - } - outToPages = true; - pages[++page] = []; - pagedim[page] = { - width : Number(width) || pageWidth, - height : Number(height) || pageHeight - }; - _setPage(page); - }, - _addPage = function() { - beginPage.apply(this, arguments); - // Set line width - out(f2(lineWidth * k) + ' w'); - // Set draw color - out(drawColor); - // resurrecting non-default line caps, joins - if (lineCapID !== 0) { - out(lineCapID + ' J'); - } - if (lineJoinID !== 0) { - out(lineJoinID + ' j'); - } - events.publish('addPage', { pageNumber : page }); - }, - _setPage = function(n) { - if (n > 0 && n <= page) { - currentPage = n; - pageWidth = pagedim[n].width; - pageHeight = pagedim[n].height; - } - }, - /** - * Returns a document-specific font key - a label assigned to a - * font name + font type combination at the time the font was added - * to the font inventory. - * - * Font key is used as label for the desired font for a block of text - * to be added to the PDF document stream. - * @private - * @function - * @param fontName {String} can be undefined on "falthy" to indicate "use current" - * @param fontStyle {String} can be undefined on "falthy" to indicate "use current" - * @returns {String} Font key. - */ - getFont = function(fontName, fontStyle) { - var key; - - fontName = fontName !== undefined ? fontName : fonts[activeFontKey].fontName; - fontStyle = fontStyle !== undefined ? fontStyle : fonts[activeFontKey].fontStyle; - - try { - // get a string like 'F3' - the KEY corresponding tot he font + type combination. - key = fontmap[fontName][fontStyle]; - } catch (e) {} - - if (!key) { - throw new Error("Unable to look up font label for font '" + fontName + "', '" - + fontStyle + "'. Refer to getFontList() for available fonts."); - } - return key; - }, - buildDocument = function() { - - outToPages = false; // switches out() to content - objectNumber = 2; - content = []; - offsets = []; - - // putHeader() - out('%PDF-' + pdfVersion); - - putPages(); - - putResources(); - - // Info - newObject(); - out('<<'); - putInfo(); - out('>>'); - out('endobj'); - - // Catalog - newObject(); - out('<<'); - putCatalog(); - out('>>'); - out('endobj'); - - // Cross-ref - var o = content_length, i, p = "0000000000"; - out('xref'); - out('0 ' + (objectNumber + 1)); - out(p+' 65535 f '); - for (i = 1; i <= objectNumber; i++) { - var offset = offsets[i]; - if (typeof offset === 'function'){ - out((p + offsets[i]()).slice(-10) + ' 00000 n '); - }else{ - out((p + offsets[i]).slice(-10) + ' 00000 n '); - } - } - // Trailer - out('trailer'); - out('<<'); - putTrailer(); - out('>>'); - out('startxref'); - out(o); - out('%%EOF'); - - outToPages = true; - - return content.join('\n'); - }, - getStyle = function(style) { - // see path-painting operators in PDF spec - var op = 'S'; // stroke - if (style === 'F') { - op = 'f'; // fill - } else if (style === 'FD' || style === 'DF') { - op = 'B'; // both - } else if (style === 'f' || style === 'f*' || style === 'B' || style === 'B*') { - /* - Allow direct use of these PDF path-painting operators: - - f fill using nonzero winding number rule - - f* fill using even-odd rule - - B fill then stroke with fill using non-zero winding number rule - - B* fill then stroke with fill using even-odd rule - */ - op = style; - } - return op; - }, - getArrayBuffer = function() { - var data = buildDocument(), len = data.length, - ab = new ArrayBuffer(len), u8 = new Uint8Array(ab); - - while(len--) u8[len] = data.charCodeAt(len); - return ab; - }, - getBlob = function() { - return new Blob([getArrayBuffer()], { type : "application/pdf" }); - }, - /** - * Generates the PDF document. - * - * If `type` argument is undefined, output is raw body of resulting PDF returned as a string. - * - * @param {String} type A string identifying one of the possible output types. - * @param {Object} options An object providing some additional signalling to PDF generator. - * @function - * @returns {jsPDF} - * @methodOf jsPDF# - * @name output - */ - output = SAFE(function(type, options) { - var datauri = ('' + type).substr(0,6) === 'dataur' - ? 'data:application/pdf;base64,'+btoa(buildDocument()):0; - - switch (type) { - case undefined: - return buildDocument(); - case 'save': - if (navigator.getUserMedia) { - if (global.URL === undefined - || global.URL.createObjectURL === undefined) { - return API.output('dataurlnewwindow'); - } - } - saveAs(getBlob(), options); - if(typeof saveAs.unload === 'function') { - if(global.setTimeout) { - setTimeout(saveAs.unload,911); - } - } - break; - case 'arraybuffer': - return getArrayBuffer(); - case 'blob': - return getBlob(); - case 'bloburi': - case 'bloburl': - // User is responsible of calling revokeObjectURL - return global.URL && global.URL.createObjectURL(getBlob()) || void 0; - case 'datauristring': - case 'dataurlstring': - return datauri; - case 'dataurlnewwindow': - var nW = global.open(datauri); - if (nW || typeof safari === "undefined") return nW; - /* pass through */ - case 'datauri': - case 'dataurl': - return global.document.location.href = datauri; - default: - throw new Error('Output type "' + type + '" is not supported.'); - } - // @TODO: Add different output options - }); - - switch (unit) { - case 'pt': k = 1; break; - case 'mm': k = 72 / 25.4000508; break; - case 'cm': k = 72 / 2.54000508; break; - case 'in': k = 72; break; - case 'px': k = 96 / 72; break; - case 'pc': k = 12; break; - case 'em': k = 12; break; - case 'ex': k = 6; break; - default: - throw ('Invalid unit: ' + unit); - } - - //--------------------------------------- - // Public API - - /** - * Object exposing internal API to plugins - * @public - */ - API.internal = { - 'pdfEscape' : pdfEscape, - 'getStyle' : getStyle, - /** - * Returns {FontObject} describing a particular font. - * @public - * @function - * @param fontName {String} (Optional) Font's family name - * @param fontStyle {String} (Optional) Font's style variation name (Example:"Italic") - * @returns {FontObject} - */ - 'getFont' : function() { - return fonts[getFont.apply(API, arguments)]; - }, - 'getFontSize' : function() { - return activeFontSize; - }, - 'getLineHeight' : function() { - return activeFontSize * lineHeightProportion; - }, - 'write' : function(string1 /*, string2, string3, etc */) { - out(arguments.length === 1 ? string1 : Array.prototype.join.call(arguments, ' ')); - }, - 'getCoordinateString' : function(value) { - return f2(value * k); - }, - 'getVerticalCoordinateString' : function(value) { - return f2((pageHeight - value) * k); - }, - 'collections' : {}, - 'newObject' : newObject, - 'newObjectDeferred' : newObjectDeferred, - 'newObjectDeferredBegin' : newObjectDeferredBegin, - 'putStream' : putStream, - 'events' : events, - // ratio that you use in multiplication of a given "size" number to arrive to 'point' - // units of measurement. - // scaleFactor is set at initialization of the document and calculated against the stated - // default measurement units for the document. - // If default is "mm", k is the number that will turn number in 'mm' into 'points' number. - // through multiplication. - 'scaleFactor' : k, - 'pageSize' : { - get width() { - return pageWidth - }, - get height() { - return pageHeight - } - }, - 'output' : function(type, options) { - return output(type, options); - }, - 'getNumberOfPages' : function() { - return pages.length - 1; - }, - 'pages' : pages, - 'out' : out, - 'f2' : f2, - 'getPageInfo' : function(pageNumberOneBased){ - var objId = (pageNumberOneBased - 1) * 2 + 3; - return {objId:objId, pageNumber:pageNumberOneBased}; - }, - 'getCurrentPageInfo' : function(){ - var objId = (currentPage - 1) * 2 + 3; - return {objId:objId, pageNumber:currentPage}; - } - }; - - /** - * Adds (and transfers the focus to) new page to the PDF document. - * @function - * @returns {jsPDF} - * - * @methodOf jsPDF# - * @name addPage - */ - API.addPage = function() { - _addPage.apply(this, arguments); - return this; - }; - API.setPage = function() { - _setPage.apply(this, arguments); - return this; - }; - API.insertPage = function(beforePage) { - this.addPage(); - this.movePage(currentPage, beforePage); - return this; - }; - API.movePage = function(targetPage, beforePage) { - if (targetPage > beforePage){ - var tmpPages = pages[targetPage]; - var tmpPagedim = pagedim[targetPage]; - for (var i=targetPage; i>beforePage; i--){ - pages[i] = pages[i-1]; - pagedim[i] = pagedim[i-1]; - } - pages[beforePage] = tmpPages; - pagedim[beforePage] = tmpPagedim; - this.setPage(beforePage); - }else if (targetPage < beforePage){ - var tmpPages = pages[targetPage]; - var tmpPagedim = pagedim[targetPage]; - for (var i=targetPage; i page){ - currentPage = page; - } - this.setPage(currentPage); - return this; - }; - API.setDisplayMode = function(zoom, layout, pmode) { - zoomMode = zoom; - layoutMode = layout; - pageMode = pmode; - return this; - }, - - /** - * Adds text to page. Supports adding multiline text when 'text' argument is an Array of Strings. - * - * @function - * @param {String|Array} text String or array of strings to be added to the page. Each line is shifted one line down per font, spacing settings declared before this call. - * @param {Number} x Coordinate (in units declared at inception of PDF document) against left edge of the page - * @param {Number} y Coordinate (in units declared at inception of PDF document) against upper edge of the page - * @param {Object} flags Collection of settings signalling how the text must be encoded. Defaults are sane. If you think you want to pass some flags, you likely can read the source. - * @returns {jsPDF} - * @methodOf jsPDF# - * @name text - */ - API.text = function(text, x, y, flags, angle, align) { - /** - * Inserts something like this into PDF - * BT - * /F1 16 Tf % Font name + size - * 16 TL % How many units down for next line in multiline text - * 0 g % color - * 28.35 813.54 Td % position - * (line one) Tj - * T* (line two) Tj - * T* (line three) Tj - * ET - */ - function ESC(s) { - s = s.split("\t").join(Array(options.TabLen||9).join(" ")); - return pdfEscape(s, flags); - } - - // Pre-August-2012 the order of arguments was function(x, y, text, flags) - // in effort to make all calls have similar signature like - // function(data, coordinates... , miscellaneous) - // this method had its args flipped. - // code below allows backward compatibility with old arg order. - if (typeof text === 'number') { - tmp = y; - y = x; - x = text; - text = tmp; - } - - // If there are any newlines in text, we assume - // the user wanted to print multiple lines, so break the - // text up into an array. If the text is already an array, - // we assume the user knows what they are doing. - if (typeof text === 'string') { - if(text.match(/[\n\r]/)) { - text = text.split( /\r\n|\r|\n/g); - } else { - // Convert text into an array anyway - // to simplify later code. - text = [text]; - } - } - if (typeof angle === 'string') { - align = angle; - angle = null; - } - if (typeof flags === 'string') { - align = flags; - flags = null; - } - if (typeof flags === 'number') { - angle = flags; - flags = null; - } - var xtra = '',mode = 'Td', todo; - if (angle) { - angle *= (Math.PI / 180); - var c = Math.cos(angle), - s = Math.sin(angle); - xtra = [f2(c), f2(s), f2(s * -1), f2(c), ''].join(" "); - mode = 'Tm'; - } - flags = flags || {}; - if (!('noBOM' in flags)) - flags.noBOM = true; - if (!('autoencode' in flags)) - flags.autoencode = true; - - //TODO this might not work after object block changes - // It would be better to pass in a page context - var strokeOption = ''; - if (true === flags.stroke){ - if (this.lastTextWasStroke !== true){ - strokeOption = '1 Tr\n'; - this.lastTextWasStroke = true; - } - } - else{ - if (this.lastTextWasStroke){ - strokeOption = '0 Tr\n'; - } - this.lastTextWasStroke = false; - } - - if (text instanceof Array) { - // we don't want to destroy original text array, so cloning it - var sa = text.concat(), da = [], i, len = sa.length; - // we do array.join('text that must not be PDFescaped") - // thus, pdfEscape each component separately - while (len--) { - da.push(ESC(sa.shift())); - } - var linesLeft = Math.ceil((pageHeight - y) * k / (activeFontSize * lineHeightProportion)); - if (0 <= linesLeft && linesLeft < da.length + 1) { - todo = da.splice(linesLeft-1); - } - - if( align ) { - var prevX, - leading = activeFontSize * lineHeightProportion, - lineWidths = text.map( function( v ) { - return this.getStringUnitWidth( v ) * activeFontSize / k; - }, this ); - // The first line uses the "main" Td setting, - // and the subsequent lines are offset by the - // previous line's x coordinate. - if( align === "center" ) { - // The passed in x coordinate defines - // the center point. - x -= lineWidths[0] / 2; - } else if ( align === "right" ) { - // The passed in x coordinate defines the - // rightmost point of the text. - x -= lineWidths[0]; - } else { - throw new Error('Unrecognized alignment option, use "center" or "right".'); - } - prevX = x; - text = da[0]; - for ( i = 1, len = da.length ; i < len; i++ ) { - var delta = lineWidths[i-1] - lineWidths[i]; - if( align === "center" ) delta /= 2; - // T* = x-offset leading Td ( text ) - // PDF Spec 1.3 p.288 - text += ") Tj\n" + delta + " -" + leading + " Td (" + da[i]; - prevX += delta; - } - } else { - text = da.join(") Tj\nT* ("); - } - } else { - throw new Error('Type of text must be string or Array. "' + text + '" is not recognized.'); - } - // Using "'" ("go next line and render text" mark) would save space but would complicate our rendering code, templates - - // BT .. ET does NOT have default settings for Tf. You must state that explicitely every time for BT .. ET - // if you want text transformation matrix (+ multiline) to work reliably (which reads sizes of things from font declarations) - // Thus, there is NO useful, *reliable* concept of "default" font for a page. - // The fact that "default" (reuse font used before) font worked before in basic cases is an accident - // - readers dealing smartly with brokenness of jsPDF's markup. - out( - 'BT\n/' + - activeFontKey + ' ' + activeFontSize + ' Tf\n' + // font face, style, size - (activeFontSize * lineHeightProportion) + ' TL\n' + // line spacing - // (flags.lineHeight != undefined ? flags.lineHeight : activeFontSize ) + ' TL\n' + // line spacing - - strokeOption +// stroke option - textColor + - '\n' + xtra + f2(x * k) + ' ' + f2((pageHeight - y) * k) + ' ' + mode + '\n(' + - text + - ') Tj\nET'); - - if (todo) { - this.addPage(); - this.text( todo, x, activeFontSize * 1.7 / k); - } - - return this; - }; - - API.lstext = function(text, x, y, spacing) { - for (var i = 0, len = text.length ; i < len; i++, x += spacing) this.text(text[i], x, y); - }; - - API.line = function(x1, y1, x2, y2) { - return this.lines([[x2 - x1, y2 - y1]], x1, y1); - }; - - API.clip = function() { - // By patrick-roberts, github.com/MrRio/jsPDF/issues/328 - // Call .clip() after calling .rect() with a style argument of null - out('W') // clip - out('S') // stroke path; necessary for clip to work - }; - - /** - * Adds series of curves (straight lines or cubic bezier curves) to canvas, starting at `x`, `y` coordinates. - * All data points in `lines` are relative to last line origin. - * `x`, `y` become x1,y1 for first line / curve in the set. - * For lines you only need to specify [x2, y2] - (ending point) vector against x1, y1 starting point. - * For bezier curves you need to specify [x2,y2,x3,y3,x4,y4] - vectors to control points 1, 2, ending point. All vectors are against the start of the curve - x1,y1. - * - * @example .lines([[2,2],[-2,2],[1,1,2,2,3,3],[2,1]], 212,110, 10) // line, line, bezier curve, line - * @param {Array} lines Array of *vector* shifts as pairs (lines) or sextets (cubic bezier curves). - * @param {Number} x Coordinate (in units declared at inception of PDF document) against left edge of the page - * @param {Number} y Coordinate (in units declared at inception of PDF document) against upper edge of the page - * @param {Number} scale (Defaults to [1.0,1.0]) x,y Scaling factor for all vectors. Elements can be any floating number Sub-one makes drawing smaller. Over-one grows the drawing. Negative flips the direction. - * @param {String} style A string specifying the painting style or null. Valid styles include: 'S' [default] - stroke, 'F' - fill, and 'DF' (or 'FD') - fill then stroke. A null value postpones setting the style so that a shape may be composed using multiple method calls. The last drawing method call used to define the shape should not have a null style argument. - * @param {Boolean} closed If true, the path is closed with a straight line from the end of the last curve to the starting point. - * @function - * @returns {jsPDF} - * @methodOf jsPDF# - * @name lines - */ - API.lines = function(lines, x, y, scale, style, closed) { - var scalex,scaley,i,l,leg,x2,y2,x3,y3,x4,y4; - - // Pre-August-2012 the order of arguments was function(x, y, lines, scale, style) - // in effort to make all calls have similar signature like - // function(content, coordinateX, coordinateY , miscellaneous) - // this method had its args flipped. - // code below allows backward compatibility with old arg order. - if (typeof lines === 'number') { - tmp = y; - y = x; - x = lines; - lines = tmp; - } - - scale = scale || [1, 1]; - - // starting point - out(f3(x * k) + ' ' + f3((pageHeight - y) * k) + ' m '); - - scalex = scale[0]; - scaley = scale[1]; - l = lines.length; - //, x2, y2 // bezier only. In page default measurement "units", *after* scaling - //, x3, y3 // bezier only. In page default measurement "units", *after* scaling - // ending point for all, lines and bezier. . In page default measurement "units", *after* scaling - x4 = x; // last / ending point = starting point for first item. - y4 = y; // last / ending point = starting point for first item. - - for (i = 0; i < l; i++) { - leg = lines[i]; - if (leg.length === 2) { - // simple line - x4 = leg[0] * scalex + x4; // here last x4 was prior ending point - y4 = leg[1] * scaley + y4; // here last y4 was prior ending point - out(f3(x4 * k) + ' ' + f3((pageHeight - y4) * k) + ' l'); - } else { - // bezier curve - x2 = leg[0] * scalex + x4; // here last x4 is prior ending point - y2 = leg[1] * scaley + y4; // here last y4 is prior ending point - x3 = leg[2] * scalex + x4; // here last x4 is prior ending point - y3 = leg[3] * scaley + y4; // here last y4 is prior ending point - x4 = leg[4] * scalex + x4; // here last x4 was prior ending point - y4 = leg[5] * scaley + y4; // here last y4 was prior ending point - out( - f3(x2 * k) + ' ' + - f3((pageHeight - y2) * k) + ' ' + - f3(x3 * k) + ' ' + - f3((pageHeight - y3) * k) + ' ' + - f3(x4 * k) + ' ' + - f3((pageHeight - y4) * k) + ' c'); - } - } - - if (closed) { - out(' h'); - } - - // stroking / filling / both the path - if (style !== null) { - out(getStyle(style)); - } - return this; - }; - - /** - * Adds a rectangle to PDF - * - * @param {Number} x Coordinate (in units declared at inception of PDF document) against left edge of the page - * @param {Number} y Coordinate (in units declared at inception of PDF document) against upper edge of the page - * @param {Number} w Width (in units declared at inception of PDF document) - * @param {Number} h Height (in units declared at inception of PDF document) - * @param {String} style A string specifying the painting style or null. Valid styles include: 'S' [default] - stroke, 'F' - fill, and 'DF' (or 'FD') - fill then stroke. A null value postpones setting the style so that a shape may be composed using multiple method calls. The last drawing method call used to define the shape should not have a null style argument. - * @function - * @returns {jsPDF} - * @methodOf jsPDF# - * @name rect - */ - API.rect = function(x, y, w, h, style) { - var op = getStyle(style); - out([ - f2(x * k), - f2((pageHeight - y) * k), - f2(w * k), - f2(-h * k), - 're' - ].join(' ')); - - if (style !== null) { - out(getStyle(style)); - } - - return this; - }; - - /** - * Adds a triangle to PDF - * - * @param {Number} x1 Coordinate (in units declared at inception of PDF document) against left edge of the page - * @param {Number} y1 Coordinate (in units declared at inception of PDF document) against upper edge of the page - * @param {Number} x2 Coordinate (in units declared at inception of PDF document) against left edge of the page - * @param {Number} y2 Coordinate (in units declared at inception of PDF document) against upper edge of the page - * @param {Number} x3 Coordinate (in units declared at inception of PDF document) against left edge of the page - * @param {Number} y3 Coordinate (in units declared at inception of PDF document) against upper edge of the page - * @param {String} style A string specifying the painting style or null. Valid styles include: 'S' [default] - stroke, 'F' - fill, and 'DF' (or 'FD') - fill then stroke. A null value postpones setting the style so that a shape may be composed using multiple method calls. The last drawing method call used to define the shape should not have a null style argument. - * @function - * @returns {jsPDF} - * @methodOf jsPDF# - * @name triangle - */ - API.triangle = function(x1, y1, x2, y2, x3, y3, style) { - this.lines( - [ - [x2 - x1, y2 - y1], // vector to point 2 - [x3 - x2, y3 - y2], // vector to point 3 - [x1 - x3, y1 - y3]// closing vector back to point 1 - ], - x1, - y1, // start of path - [1, 1], - style, - true); - return this; - }; - - /** - * Adds a rectangle with rounded corners to PDF - * - * @param {Number} x Coordinate (in units declared at inception of PDF document) against left edge of the page - * @param {Number} y Coordinate (in units declared at inception of PDF document) against upper edge of the page - * @param {Number} w Width (in units declared at inception of PDF document) - * @param {Number} h Height (in units declared at inception of PDF document) - * @param {Number} rx Radius along x axis (in units declared at inception of PDF document) - * @param {Number} rx Radius along y axis (in units declared at inception of PDF document) - * @param {String} style A string specifying the painting style or null. Valid styles include: 'S' [default] - stroke, 'F' - fill, and 'DF' (or 'FD') - fill then stroke. A null value postpones setting the style so that a shape may be composed using multiple method calls. The last drawing method call used to define the shape should not have a null style argument. - * @function - * @returns {jsPDF} - * @methodOf jsPDF# - * @name roundedRect - */ - API.roundedRect = function(x, y, w, h, rx, ry, style) { - var MyArc = 4 / 3 * (Math.SQRT2 - 1); - this.lines( - [ - [(w - 2 * rx), 0], - [(rx * MyArc), 0, rx, ry - (ry * MyArc), rx, ry], - [0, (h - 2 * ry)], - [0, (ry * MyArc), - (rx * MyArc), ry, -rx, ry], - [(-w + 2 * rx), 0], - [ - (rx * MyArc), 0, -rx, - (ry * MyArc), -rx, -ry], - [0, (-h + 2 * ry)], - [0, - (ry * MyArc), (rx * MyArc), -ry, rx, -ry] - ], - x + rx, - y, // start of path - [1, 1], - style); - return this; - }; - - /** - * Adds an ellipse to PDF - * - * @param {Number} x Coordinate (in units declared at inception of PDF document) against left edge of the page - * @param {Number} y Coordinate (in units declared at inception of PDF document) against upper edge of the page - * @param {Number} rx Radius along x axis (in units declared at inception of PDF document) - * @param {Number} rx Radius along y axis (in units declared at inception of PDF document) - * @param {String} style A string specifying the painting style or null. Valid styles include: 'S' [default] - stroke, 'F' - fill, and 'DF' (or 'FD') - fill then stroke. A null value postpones setting the style so that a shape may be composed using multiple method calls. The last drawing method call used to define the shape should not have a null style argument. - * @function - * @returns {jsPDF} - * @methodOf jsPDF# - * @name ellipse - */ - API.ellipse = function(x, y, rx, ry, style) { - var lx = 4 / 3 * (Math.SQRT2 - 1) * rx, - ly = 4 / 3 * (Math.SQRT2 - 1) * ry; - - out([ - f2((x + rx) * k), - f2((pageHeight - y) * k), - 'm', - f2((x + rx) * k), - f2((pageHeight - (y - ly)) * k), - f2((x + lx) * k), - f2((pageHeight - (y - ry)) * k), - f2(x * k), - f2((pageHeight - (y - ry)) * k), - 'c' - ].join(' ')); - out([ - f2((x - lx) * k), - f2((pageHeight - (y - ry)) * k), - f2((x - rx) * k), - f2((pageHeight - (y - ly)) * k), - f2((x - rx) * k), - f2((pageHeight - y) * k), - 'c' - ].join(' ')); - out([ - f2((x - rx) * k), - f2((pageHeight - (y + ly)) * k), - f2((x - lx) * k), - f2((pageHeight - (y + ry)) * k), - f2(x * k), - f2((pageHeight - (y + ry)) * k), - 'c' - ].join(' ')); - out([ - f2((x + lx) * k), - f2((pageHeight - (y + ry)) * k), - f2((x + rx) * k), - f2((pageHeight - (y + ly)) * k), - f2((x + rx) * k), - f2((pageHeight - y) * k), - 'c' - ].join(' ')); - - if (style !== null) { - out(getStyle(style)); - } - - return this; - }; - - /** - * Adds an circle to PDF - * - * @param {Number} x Coordinate (in units declared at inception of PDF document) against left edge of the page - * @param {Number} y Coordinate (in units declared at inception of PDF document) against upper edge of the page - * @param {Number} r Radius (in units declared at inception of PDF document) - * @param {String} style A string specifying the painting style or null. Valid styles include: 'S' [default] - stroke, 'F' - fill, and 'DF' (or 'FD') - fill then stroke. A null value postpones setting the style so that a shape may be composed using multiple method calls. The last drawing method call used to define the shape should not have a null style argument. - * @function - * @returns {jsPDF} - * @methodOf jsPDF# - * @name circle - */ - API.circle = function(x, y, r, style) { - return this.ellipse(x, y, r, r, style); - }; - - /** - * Adds a properties to the PDF document - * - * @param {Object} A property_name-to-property_value object structure. - * @function - * @returns {jsPDF} - * @methodOf jsPDF# - * @name setProperties - */ - API.setProperties = function(properties) { - // copying only those properties we can render. - for (var property in documentProperties) { - if (documentProperties.hasOwnProperty(property) && properties[property]) { - documentProperties[property] = properties[property]; - } - } - return this; - }; - - /** - * Sets font size for upcoming text elements. - * - * @param {Number} size Font size in points. - * @function - * @returns {jsPDF} - * @methodOf jsPDF# - * @name setFontSize - */ - API.setFontSize = function(size) { - activeFontSize = size; - return this; - }; - - /** - * Sets text font face, variant for upcoming text elements. - * See output of jsPDF.getFontList() for possible font names, styles. - * - * @param {String} fontName Font name or family. Example: "times" - * @param {String} fontStyle Font style or variant. Example: "italic" - * @function - * @returns {jsPDF} - * @methodOf jsPDF# - * @name setFont - */ - API.setFont = function(fontName, fontStyle) { - activeFontKey = getFont(fontName, fontStyle); - // if font is not found, the above line blows up and we never go further - return this; - }; - - /** - * Switches font style or variant for upcoming text elements, - * while keeping the font face or family same. - * See output of jsPDF.getFontList() for possible font names, styles. - * - * @param {String} style Font style or variant. Example: "italic" - * @function - * @returns {jsPDF} - * @methodOf jsPDF# - * @name setFontStyle - */ - API.setFontStyle = API.setFontType = function(style) { - activeFontKey = getFont(undefined, style); - // if font is not found, the above line blows up and we never go further - return this; - }; - - /** - * Returns an object - a tree of fontName to fontStyle relationships available to - * active PDF document. - * - * @public - * @function - * @returns {Object} Like {'times':['normal', 'italic', ... ], 'arial':['normal', 'bold', ... ], ... } - * @methodOf jsPDF# - * @name getFontList - */ - API.getFontList = function() { - // TODO: iterate over fonts array or return copy of fontmap instead in case more are ever added. - var list = {},fontName,fontStyle,tmp; - - for (fontName in fontmap) { - if (fontmap.hasOwnProperty(fontName)) { - list[fontName] = tmp = []; - for (fontStyle in fontmap[fontName]) { - if (fontmap[fontName].hasOwnProperty(fontStyle)) { - tmp.push(fontStyle); - } - } - } - } - - return list; - }; - - /** - * Sets line width for upcoming lines. - * - * @param {Number} width Line width (in units declared at inception of PDF document) - * @function - * @returns {jsPDF} - * @methodOf jsPDF# - * @name setLineWidth - */ - API.setLineWidth = function(width) { - out((width * k).toFixed(2) + ' w'); - return this; - }; - - /** - * Sets the stroke color for upcoming elements. - * - * Depending on the number of arguments given, Gray, RGB, or CMYK - * color space is implied. - * - * When only ch1 is given, "Gray" color space is implied and it - * must be a value in the range from 0.00 (solid black) to to 1.00 (white) - * if values are communicated as String types, or in range from 0 (black) - * to 255 (white) if communicated as Number type. - * The RGB-like 0-255 range is provided for backward compatibility. - * - * When only ch1,ch2,ch3 are given, "RGB" color space is implied and each - * value must be in the range from 0.00 (minimum intensity) to to 1.00 - * (max intensity) if values are communicated as String types, or - * from 0 (min intensity) to to 255 (max intensity) if values are communicated - * as Number types. - * The RGB-like 0-255 range is provided for backward compatibility. - * - * When ch1,ch2,ch3,ch4 are given, "CMYK" color space is implied and each - * value must be a in the range from 0.00 (0% concentration) to to - * 1.00 (100% concentration) - * - * Because JavaScript treats fixed point numbers badly (rounds to - * floating point nearest to binary representation) it is highly advised to - * communicate the fractional numbers as String types, not JavaScript Number type. - * - * @param {Number|String} ch1 Color channel value - * @param {Number|String} ch2 Color channel value - * @param {Number|String} ch3 Color channel value - * @param {Number|String} ch4 Color channel value - * - * @function - * @returns {jsPDF} - * @methodOf jsPDF# - * @name setDrawColor - */ - API.setDrawColor = function(ch1, ch2, ch3, ch4) { - var color; - if (ch2 === undefined || (ch4 === undefined && ch1 === ch2 === ch3)) { - // Gray color space. - if (typeof ch1 === 'string') { - color = ch1 + ' G'; - } else { - color = f2(ch1 / 255) + ' G'; - } - } else if (ch4 === undefined) { - // RGB - if (typeof ch1 === 'string') { - color = [ch1, ch2, ch3, 'RG'].join(' '); - } else { - color = [f2(ch1 / 255), f2(ch2 / 255), f2(ch3 / 255), 'RG'].join(' '); - } - } else { - // CMYK - if (typeof ch1 === 'string') { - color = [ch1, ch2, ch3, ch4, 'K'].join(' '); - } else { - color = [f2(ch1), f2(ch2), f2(ch3), f2(ch4), 'K'].join(' '); - } - } - - out(color); - return this; - }; - - /** - * Sets the fill color for upcoming elements. - * - * Depending on the number of arguments given, Gray, RGB, or CMYK - * color space is implied. - * - * When only ch1 is given, "Gray" color space is implied and it - * must be a value in the range from 0.00 (solid black) to to 1.00 (white) - * if values are communicated as String types, or in range from 0 (black) - * to 255 (white) if communicated as Number type. - * The RGB-like 0-255 range is provided for backward compatibility. - * - * When only ch1,ch2,ch3 are given, "RGB" color space is implied and each - * value must be in the range from 0.00 (minimum intensity) to to 1.00 - * (max intensity) if values are communicated as String types, or - * from 0 (min intensity) to to 255 (max intensity) if values are communicated - * as Number types. - * The RGB-like 0-255 range is provided for backward compatibility. - * - * When ch1,ch2,ch3,ch4 are given, "CMYK" color space is implied and each - * value must be a in the range from 0.00 (0% concentration) to to - * 1.00 (100% concentration) - * - * Because JavaScript treats fixed point numbers badly (rounds to - * floating point nearest to binary representation) it is highly advised to - * communicate the fractional numbers as String types, not JavaScript Number type. - * - * @param {Number|String} ch1 Color channel value - * @param {Number|String} ch2 Color channel value - * @param {Number|String} ch3 Color channel value - * @param {Number|String} ch4 Color channel value - * - * @function - * @returns {jsPDF} - * @methodOf jsPDF# - * @name setFillColor - */ - API.setFillColor = function(ch1, ch2, ch3, ch4) { - var color; - - if (ch2 === undefined || (ch4 === undefined && ch1 === ch2 === ch3)) { - // Gray color space. - if (typeof ch1 === 'string') { - color = ch1 + ' g'; - } else { - color = f2(ch1 / 255) + ' g'; - } - } else if (ch4 === undefined) { - // RGB - if (typeof ch1 === 'string') { - color = [ch1, ch2, ch3, 'rg'].join(' '); - } else { - color = [f2(ch1 / 255), f2(ch2 / 255), f2(ch3 / 255), 'rg'].join(' '); - } - } else { - // CMYK - if (typeof ch1 === 'string') { - color = [ch1, ch2, ch3, ch4, 'k'].join(' '); - } else { - color = [f2(ch1), f2(ch2), f2(ch3), f2(ch4), 'k'].join(' '); - } - } - - out(color); - return this; - }; - - /** - * Sets the text color for upcoming elements. - * If only one, first argument is given, - * treats the value as gray-scale color value. - * - * @param {Number} r Red channel color value in range 0-255 or {String} r color value in hexadecimal, example: '#FFFFFF' - * @param {Number} g Green channel color value in range 0-255 - * @param {Number} b Blue channel color value in range 0-255 - * @function - * @returns {jsPDF} - * @methodOf jsPDF# - * @name setTextColor - */ - API.setTextColor = function(r, g, b) { - if ((typeof r === 'string') && /^#[0-9A-Fa-f]{6}$/.test(r)) { - var hex = parseInt(r.substr(1), 16); - r = (hex >> 16) & 255; - g = (hex >> 8) & 255; - b = (hex & 255); - } - - if ((r === 0 && g === 0 && b === 0) || (typeof g === 'undefined')) { - textColor = f3(r / 255) + ' g'; - } else { - textColor = [f3(r / 255), f3(g / 255), f3(b / 255), 'rg'].join(' '); - } - return this; - }; - - /** - * Is an Object providing a mapping from human-readable to - * integer flag values designating the varieties of line cap - * and join styles. - * - * @returns {Object} - * @fieldOf jsPDF# - * @name CapJoinStyles - */ - API.CapJoinStyles = { - 0 : 0, - 'butt' : 0, - 'but' : 0, - 'miter' : 0, - 1 : 1, - 'round' : 1, - 'rounded' : 1, - 'circle' : 1, - 2 : 2, - 'projecting' : 2, - 'project' : 2, - 'square' : 2, - 'bevel' : 2 - }; - - /** - * Sets the line cap styles - * See {jsPDF.CapJoinStyles} for variants - * - * @param {String|Number} style A string or number identifying the type of line cap - * @function - * @returns {jsPDF} - * @methodOf jsPDF# - * @name setLineCap - */ - API.setLineCap = function(style) { - var id = this.CapJoinStyles[style]; - if (id === undefined) { - throw new Error("Line cap style of '" + style + "' is not recognized. See or extend .CapJoinStyles property for valid styles"); - } - lineCapID = id; - out(id + ' J'); - - return this; - }; - - /** - * Sets the line join styles - * See {jsPDF.CapJoinStyles} for variants - * - * @param {String|Number} style A string or number identifying the type of line join - * @function - * @returns {jsPDF} - * @methodOf jsPDF# - * @name setLineJoin - */ - API.setLineJoin = function(style) { - var id = this.CapJoinStyles[style]; - if (id === undefined) { - throw new Error("Line join style of '" + style + "' is not recognized. See or extend .CapJoinStyles property for valid styles"); - } - lineJoinID = id; - out(id + ' j'); - - return this; - }; - - // Output is both an internal (for plugins) and external function - API.output = output; - - /** - * Saves as PDF document. An alias of jsPDF.output('save', 'filename.pdf') - * @param {String} filename The filename including extension. - * - * @function - * @returns {jsPDF} - * @methodOf jsPDF# - * @name save - */ - API.save = function(filename) { - API.output('save', filename); - }; - - // applying plugins (more methods) ON TOP of built-in API. - // this is intentional as we allow plugins to override - // built-ins - for (var plugin in jsPDF.API) { - if (jsPDF.API.hasOwnProperty(plugin)) { - if (plugin === 'events' && jsPDF.API.events.length) { - (function(events, newEvents) { - - // jsPDF.API.events is a JS Array of Arrays - // where each Array is a pair of event name, handler - // Events were added by plugins to the jsPDF instantiator. - // These are always added to the new instance and some ran - // during instantiation. - var eventname,handler_and_args,i; - - for (i = newEvents.length - 1; i !== -1; i--) { - // subscribe takes 3 args: 'topic', function, runonce_flag - // if undefined, runonce is false. - // users can attach callback directly, - // or they can attach an array with [callback, runonce_flag] - // that's what the "apply" magic is for below. - eventname = newEvents[i][0]; - handler_and_args = newEvents[i][1]; - events.subscribe.apply( - events, - [eventname].concat( - typeof handler_and_args === 'function' ? - [handler_and_args] : handler_and_args)); - } - }(events, jsPDF.API.events)); - } else { - API[plugin] = jsPDF.API[plugin]; - } - } - } - - ////////////////////////////////////////////////////// - // continuing initialization of jsPDF Document object - ////////////////////////////////////////////////////// - // Add the first page automatically - addFonts(); - activeFontKey = 'F1'; - _addPage(format, orientation); - - events.publish('initialized'); - return API; - } - - /** - * jsPDF.API is a STATIC property of jsPDF class. - * jsPDF.API is an object you can add methods and properties to. - * The methods / properties you add will show up in new jsPDF objects. - * - * One property is prepopulated. It is the 'events' Object. Plugin authors can add topics, - * callbacks to this object. These will be reassigned to all new instances of jsPDF. - * Examples: - * jsPDF.API.events['initialized'] = function(){ 'this' is API object } - * jsPDF.API.events['addFont'] = function(added_font_object){ 'this' is API object } - * - * @static - * @public - * @memberOf jsPDF - * @name API - * - * @example - * jsPDF.API.mymethod = function(){ - * // 'this' will be ref to internal API object. see jsPDF source - * // , so you can refer to built-in methods like so: - * // this.line(....) - * // this.text(....) - * } - * var pdfdoc = new jsPDF() - * pdfdoc.mymethod() // <- !!!!!! - */ - jsPDF.API = {events:[]}; - jsPDF.version = "1.0.0-trunk"; - - if (typeof define === 'function' && define.amd) { - define('jsPDF', function() { - return jsPDF; - }); - } else { - global.jsPDF = jsPDF; - } - return jsPDF; -}(typeof self !== "undefined" && self || typeof window !== "undefined" && window || this)); \ No newline at end of file diff --git a/js/jspdf.plugin.addimage.js b/js/jspdf.plugin.addimage.js deleted file mode 100644 index 5f18be7..0000000 --- a/js/jspdf.plugin.addimage.js +++ /dev/null @@ -1,223 +0,0 @@ -/** @preserve -jsPDF addImage plugin (JPEG only at this time) -Copyright (c) 2012 https://github.com/siefkenj/ -*/ - -/** - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE - * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION - * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * ==================================================================== - */ - -;(function(jsPDFAPI) { -'use strict' - -var namespace = 'addImage_' - -// 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(imgData) { - 'use strict' - var width, height; - // Verify we have a valid jpeg header 0xff,0xd8,0xff,0xe0,?,?,'J','F','I','F',0x00 - if (!imgData.charCodeAt(0) === 0xff || - !imgData.charCodeAt(1) === 0xd8 || - !imgData.charCodeAt(2) === 0xff || - !imgData.charCodeAt(3) === 0xe0 || - !imgData.charCodeAt(6) === 'J'.charCodeAt(0) || - !imgData.charCodeAt(7) === 'F'.charCodeAt(0) || - !imgData.charCodeAt(8) === 'I'.charCodeAt(0) || - !imgData.charCodeAt(9) === 'F'.charCodeAt(0) || - !imgData.charCodeAt(10) === 0x00) { - throw new Error('getJpegSize requires a binary 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) { - height = imgData.charCodeAt(i+5)*256 + imgData.charCodeAt(i+6); - width = imgData.charCodeAt(i+7)*256 + imgData.charCodeAt(i+8); - return [width, height]; - } else { - i += 2; - blockLength = imgData.charCodeAt(i)*256 + imgData.charCodeAt(i+1) - } - } -} -// Image functionality ported from pdf.js -, putImage = function(img) { - var objectNumber = this.internal.newObject() - , out = this.internal.write - , putStream = this.internal.putStream - - img['n'] = objectNumber - - out('<>'); - } - if ('trns' in img && img['trns'].constructor == Array) { - var trns = ''; - for ( var i = 0; i < img['trns'].length; i++) { - trns += (img[trns][i] + ' ' + img['trns'][i] + ' '); - out('/Mask [' + trns + ']'); - } - } - if ('smask' in img) { - out('/SMask ' + (objectNumber + 1) + ' 0 R'); - } - out('/Length ' + img['data'].length + '>>'); - - putStream(img['data']); - - out('endobj'); -} -, putResourcesCallback = function() { - var images = this.internal.collections[namespace + 'images'] - for ( var i in images ) { - putImage.call(this, images[i]) - } -} -, putXObjectsDictCallback = function(){ - 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' - ) - } -} - -jsPDFAPI.addImage = function(imageData, format, x, y, w, h) { - 'use strict' - if (typeof imageData === 'object' && imageData.nodeType === 1) { - var canvas = document.createElement('canvas'); - canvas.width = imageData.clientWidth; - canvas.height = imageData.clientHeight; - - var ctx = canvas.getContext('2d'); - if (!ctx) { - throw ('addImage requires canvas to be supported by browser.'); - } - ctx.drawImage(imageData, 0, 0, canvas.width, canvas.height); - imageData = canvas.toDataURL('image/jpeg'); - format = "JPEG"; - } - if (format.toUpperCase() !== 'JPEG') { - throw new Error('addImage currently only supports format \'JPEG\', not \''+format+'\''); - } - - var imageIndex - , images = this.internal.collections[namespace + 'images'] - , coord = this.internal.getCoordinateString - , vcoord = this.internal.getVerticalCoordinateString; - - // Detect if the imageData is raw binary or Data URL - if (imageData.substring(0, 23) === 'data:image/jpeg;base64,') { - imageData = atob(imageData.replace('data:image/jpeg;base64,', '')); - } - - 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) - } else { - // this is the first time this method is ran on this instance of jsPDF object. - imageIndex = 0 - this.internal.collections[namespace + 'images'] = images = {} - this.internal.events.subscribe('putResources', putResourcesCallback) - this.internal.events.subscribe('putXobjectDict', putXObjectsDictCallback) - } - - var dims = getJpegSize(imageData); - var info = { - w : dims[0], - h : dims[1], - cs : 'DeviceRGB', - bpc : 8, - f : 'DCTDecode', - i : imageIndex, - data : imageData - // n: objectNumber will be added by putImage code - - }; - images[imageIndex] = 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']; - } - - this.internal.write( - 'q' - , coord(w) - , '0 0' - , coord(h) // TODO: check if this should be shifted by vcoord - , coord(x) - , vcoord(y + h) - , 'cm /I'+info['i'] - , 'Do Q' - ) - - return this -} -})(jsPDF.API) diff --git a/js/jspdf.plugin.cell.js b/js/jspdf.plugin.cell.js deleted file mode 100644 index 23e014f..0000000 --- a/js/jspdf.plugin.cell.js +++ /dev/null @@ -1,372 +0,0 @@ -/** ==================================================================== - * jsPDF Cell plugin - * Copyright (c) 2013 Youssef Beddad, youssef.beddad@gmail.com - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE - * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION - * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * ==================================================================== - */ - -(function (jsPDFAPI) { - 'use strict'; - /*jslint browser:true */ - /*global document: false, jsPDF */ - - var maxLn = 0, - lnP = 0, - fontName, - fontSize, - fontStyle, - lastCellPos = { x: undefined, y: undefined, w: undefined, h: undefined, ln: undefined }, - pages = 1, - newPage = false, - setLastCellPosition = function (x, y, w, h, ln) { - lastCellPos = { x: x, y: y, w: w, h: h, ln: ln }; - }, - getLastCellPosition = function () { - return lastCellPos; - }, - setMaxLn = function (x) { - maxLn = x; - }, - getMaxLn = function () { - return maxLn; - }, - setLnP = function (x) { - lnP = x; - }, - getLnP = function (x) { - return lnP; - }; - - jsPDFAPI.getTextDimensions = function (txt) { - fontName = this.internal.getFont().fontName; - fontSize = this.internal.getFontSize(); - fontStyle = this.internal.getFont().fontStyle; - - // 1 pixel = 0.264583 mm and 1 mm = 72/25.4 point - var px2pt = 0.264583 * 72 / 25.4, - dimensions, - text; - - text = document.createElement('font'); - text.id = "jsPDFCell"; - text.style.fontStyle = fontStyle; - text.style.fontName = fontName; - text.style.fontSize = fontSize + 'pt'; - text.innerText = txt; - - document.body.appendChild(text); - - dimensions = { w: (text.offsetWidth + 1) * px2pt, h: (text.offsetHeight + 1) * px2pt}; - - document.body.removeChild(text); - - return dimensions; - }; - - jsPDFAPI.cellAddPage = function () { - this.addPage(); - setLastCellPosition(undefined, undefined, undefined, undefined, undefined); - newPage = true; - pages += 1; - setLnP(1); - }; - - jsPDFAPI.cellInitialize = function () { - maxLn = 0; - lastCellPos = { x: undefined, y: undefined, w: undefined, h: undefined, ln: undefined }; - pages = 1; - newPage = false; - setLnP(0); - }; - - jsPDFAPI.cell = function (x, y, w, h, txt, ln) { - this.lnMod = this.lnMod === undefined ? 0 : this.lnMod; - if (this.printingHeaderRow !== true && this.lnMod !== 0) { - ln = ln + this.lnMod; - } - - if ((((ln * h) + y + (h * 2)) / pages) >= this.internal.pageSize.height && pages === 1 && !newPage) { - this.cellAddPage(); - - if (this.printHeaders && this.tableHeaderRow) { - this.printHeaderRow(ln); - this.lnMod += 1; - ln += 1; - } - if (getMaxLn() === 0) { - setMaxLn(Math.round((this.internal.pageSize.height - (h * 2)) / h)); - } - } else if (newPage && getLastCellPosition().ln !== ln && getLnP() === getMaxLn()) { - this.cellAddPage(); - - if (this.printHeaders && this.tableHeaderRow) { - this.printHeaderRow(ln); - this.lnMod += 1; - ln += 1; - } - } - - var curCell = getLastCellPosition(), - dim = this.getTextDimensions(txt), - isNewLn = 1; - if (curCell.x !== undefined && curCell.ln === ln) { - x = curCell.x + curCell.w; - } - if (curCell.y !== undefined && curCell.y === y) { - y = curCell.y; - } - if (curCell.h !== undefined && curCell.h === h) { - h = curCell.h; - } - if (curCell.ln !== undefined && curCell.ln === ln) { - ln = curCell.ln; - isNewLn = 0; - } - if (newPage) { - y = h * (getLnP() + isNewLn); - } else { - y = (y + (h * Math.abs(getMaxLn() * pages - ln - getMaxLn()))); - } - this.rect(x, y, w, h); - this.text(txt, x + 3, y + h - 3); - setLnP(getLnP() + isNewLn); - setLastCellPosition(x, y, w, h, ln); - return this; - }; - - /** - * Return an array containing all of the owned keys of an Object - * @type {Function} - * @return {String[]} of Object keys - */ - jsPDFAPI.getKeys = (typeof Object.keys === 'function') - ? function (object) { - if (!object) { - return []; - } - return Object.keys(object); - } - : function (object) { - var keys = [], - property; - - for (property in object) { - if (object.hasOwnProperty(property)) { - keys.push(property); - } - } - - return keys; - }; - - /** - * Return the maximum value from an array - * @param array - * @param comparisonFn - * @returns {*} - */ - jsPDFAPI.arrayMax = function (array, comparisonFn) { - var max = array[0], - i, - ln, - item; - - for (i = 0, ln = array.length; i < ln; i += 1) { - item = array[i]; - - if (comparisonFn) { - if (comparisonFn(max, item) === -1) { - max = item; - } - } else { - if (item > max) { - max = item; - } - } - } - - return max; - }; - - /** - * Create a table from a set of data. - * @param {Object[]} data As array of objects containing key-value pairs - * @param {String[]} [headers] Omit or null to auto-generate headers at a performance cost - * @param {Object} [config.printHeaders] True to print column headers at the top of every page - * @param {Object} [config.autoSize] True to dynamically set the column widths to match the widest cell value - * @param {Object} [config.autoStretch] True to force the table to fit the width of the page - */ - jsPDFAPI.table = function (data, headers, config) { - - var headerNames = [], - headerPrompts = [], - header, - autoSize, - printHeaders, - autoStretch, - i, - ln, - columnMatrix = {}, - columnWidths = {}, - columnData, - column, - columnMinWidths = [], - j, - tableHeaderConfigs = [], - model, - jln, - func; - - /** - * @property {Number} lnMod - * Keep track of the current line number modifier used when creating cells - */ - this.lnMod = 0; - - if (config) { - autoSize = config.autoSize || false; - printHeaders = this.printHeaders = config.printHeaders || true; - autoStretch = config.autoStretch || true; - } - - if (!data) { - throw 'No data for PDF table'; - } - - // Set headers - if (headers === undefined || (headers === null)) { - - // No headers defined so we derive from data - headerNames = this.getKeys(data[0]); - - } else if (headers[0] && (typeof headers[0] !== 'string')) { - - // Split header configs into names and prompts - for (i = 0, ln = headers.length; i < ln; i += 1) { - header = headers[i]; - headerNames.push(header.name); - headerPrompts.push(header.prompt); - } - - } else { - headerNames = headers; - } - - if (config.autoSize) { - - // Create Columns Matrix - - func = function (rec) { - return rec[header]; - }; - - for (i = 0, ln = headerNames.length; i < ln; i += 1) { - header = headerNames[i]; - - columnMatrix[header] = data.map( - func - ); - - // get header width - columnMinWidths.push(this.getTextDimensions(headerPrompts[i] || header).w); - - column = columnMatrix[header]; - - // get cell widths - for (j = 0, ln = column.length; j < ln; j += 1) { - columnData = column[j]; - - columnMinWidths.push(this.getTextDimensions(columnData).w); - } - - // get final column width - columnWidths[header] = jsPDFAPI.arrayMax(columnMinWidths); - } - } - - // -- Construct the table - - if (config.printHeaders) { - - // Construct the header row - for (i = 0, ln = headerNames.length; i < ln; i += 1) { - header = headerNames[i]; - tableHeaderConfigs.push([10, 10, columnWidths[header], 25, String(headerPrompts.length ? headerPrompts[i] : header)]); - } - - // Store the table header config - this.setTableHeaderRow(tableHeaderConfigs); - - // Print the header for the start of the table - this.printHeaderRow(1); - } - - // Construct the data rows - for (i = 0, ln = data.length; i < ln; i += 1) { - model = data[i]; - - for (j = 0, jln = headerNames.length; j < jln; j += 1) { - header = headerNames[j]; - this.cell(10, 10, columnWidths[header], 25, String(model[header]), i + 2); - } - } - - return this; - }; - - /** - * Store the config for outputting a table header - * @param {Object[]} config - * An array of cell configs that would define a header row: Each config matches the config used by jsPDFAPI.cell - * except the ln parameter is excluded - */ - jsPDFAPI.setTableHeaderRow = function (config) { - this.tableHeaderRow = config; - }; - - /** - * Output the store header row - * @param lineNumber The line number to output the header at - */ - jsPDFAPI.printHeaderRow = function (lineNumber) { - if (!this.tableHeaderRow) { - throw 'Property tableHeaderRow does not exist.'; - } - - var tableHeaderCell, - tmpArray, - i, - ln; - - this.printingHeaderRow = true; - - for (i = 0, ln = this.tableHeaderRow.length; i < ln; i += 1) { - - tableHeaderCell = this.tableHeaderRow[i]; - tmpArray = [].concat(tableHeaderCell); - - this.cell.apply(this, tmpArray.concat(lineNumber)); - } - - this.printingHeaderRow = false; - }; - -}(jsPDF.API)); diff --git a/js/jspdf.plugin.from_html.js b/js/jspdf.plugin.from_html.js deleted file mode 100644 index 5930365..0000000 --- a/js/jspdf.plugin.from_html.js +++ /dev/null @@ -1,594 +0,0 @@ -/** @preserve -jsPDF fromHTML plugin. BETA stage. API subject to change. Needs browser, jQuery -Copyright (c) 2012 2012 Willow Systems Corporation, willow-systems.com -*/ -/* - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE - * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION - * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * ==================================================================== - */ - -;(function(jsPDFAPI) { -'use strict' - - -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,''); - }; -} - -function PurgeWhiteSpace(array){ - var i = 0, l = array.length, fragment - , lTrimmed = false - , rTrimmed = false - - while (!lTrimmed && i !== l) { - fragment = array[i] = array[i].trimLeft() - if (fragment) { - // there is something left there. - lTrimmed = true - } - ;i++; - } - - i = l - 1 - while (l && !rTrimmed && i !== -1) { - fragment = array[i] = array[i].trimRight() - if (fragment) { - // there is something left there. - rTrimmed = true - } - ;i--; - } - - var r = /\s+$/g - , trailingSpace = true // it's safe to assume we always trim start of display:block element's text. - - for (i = 0; i !== l; i++) { - fragment = array[i].replace(/\s+/g, ' ') - // if (l > 1) { - // console.log(i, trailingSpace, fragment) - // } - if (trailingSpace) { - fragment = fragment.trimLeft() - } - if (fragment) { - // meaning, it was not reduced to "" - // if it was, we don't want to clear trailingSpace flag. - trailingSpace = r.test(fragment) - } - array[i] = fragment - } - - return array -} - -function Renderer(pdf, x, y, settings) { - this.pdf = pdf - this.x = x - this.y = y - this.settings = settings - - this.init() - - return this -} - -Renderer.prototype.init = function(){ - - this.paragraph = { - 'text': [] - , 'style': [] - } - - this.pdf.internal.write( - 'q' - ) -} - -Renderer.prototype.dispose = function(){ - this.pdf.internal.write( - 'Q' // closes the 'q' in init() - ) - return { - 'x':this.x, 'y':this.y // bottom left of last line. = upper left of what comes after us. - // TODO: we cannot traverse pages yet, but need to figure out how to communicate that when we do. - // TODO: add more stats: number of lines, paragraphs etc. - } -} - -Renderer.prototype.splitFragmentsIntoLines = function(fragments, styles){ - var defaultFontSize = 12 // points - , k = this.pdf.internal.scaleFactor // when multiplied by this, converts jsPDF instance units into 'points' - - // var widths = options.widths ? options.widths : this.internal.getFont().metadata.Unicode.widths - // , kerning = options.kerning ? options.kerning : this.internal.getFont().metadata.Unicode.kerning - , fontMetricsCache = {} - , ff, fs - , fontMetrics - - , fragment // string, element of `fragments` - , style // object with properties with names similar to CSS. Holds pertinent style info for given fragment - , fragmentSpecificMetrics // fontMetrics + some indent and sizing properties populated. We reuse it, hence the bother. - , fragmentLength // fragment's length in jsPDF units - , fragmentChopped // will be array - fragment split into "lines" - - , line = [] // array of pairs of arrays [t,s], where t is text string, and s is style object for that t. - , lines = [line] // array of arrays of pairs of arrays - , currentLineLength = 0 // in jsPDF instance units (inches, cm etc) - , maxLineLength = this.settings.width // need to decide if this is the best way to know width of content. - - // this loop sorts text fragments (and associated style) - // into lines. Some fragments will be chopped into smaller - // fragments to be spread over multiple lines. - while (fragments.length) { - - fragment = fragments.shift() - style = styles.shift() - - // if not empty string - if (fragment) { - - ff = style['font-family'] - fs = style['font-style'] - - fontMetrics = fontMetricsCache[ff+fs] - if (!fontMetrics) { - fontMetrics = this.pdf.internal.getFont(ff, fs).metadata.Unicode - fontMetricsCache[ff+fs] = fontMetrics - } - - fragmentSpecificMetrics = { - 'widths': fontMetrics.widths - , 'kerning': fontMetrics.kerning - - // fontSize comes to us from CSS scraper as "proportion of normal" value - // , hence the multiplication - , 'fontSize': style['font-size'] * defaultFontSize - - // // these should not matter as we provide the metrics manually - // // if we would not, we would need these: - // , 'fontName': style.fontName - // , 'fontStyle': style.fontStyle - - // this is setting for "indent first line of paragraph", but we abuse it - // for continuing inline spans of text. Indent value = space in jsPDF instance units - // (whatever user passed to 'new jsPDF(orientation, units, size) - // already consumed on this line. May be zero, of course, for "start of line" - // it's used only on chopper, ignored in all "sizing" code - , 'textIndent': currentLineLength - } - - // in user units (inch, cm etc.) - fragmentLength = this.pdf.getStringUnitWidth( - fragment - , fragmentSpecificMetrics - ) * fragmentSpecificMetrics.fontSize / k - - if (currentLineLength + fragmentLength > maxLineLength) { - // whatever is already on the line + this new fragment - // will be longer than max len for a line. - // Hence, chopping fragment into lines: - fragmentChopped = this.pdf.splitTextToSize( - fragment - , maxLineLength - , fragmentSpecificMetrics - ) - - line.push([fragmentChopped.shift(), style]) - while (fragmentChopped.length){ - line = [[fragmentChopped.shift(), style]] - lines.push(line) - } - - currentLineLength = this.pdf.getStringUnitWidth( - // new line's first (and only) fragment's length is our new line length - line[0][0] - , fragmentSpecificMetrics - ) * fragmentSpecificMetrics.fontSize / k - } else { - // nice, we can fit this fragment on current line. Less work for us... - line.push([fragment, style]) - currentLineLength += fragmentLength - } - } - } - - return lines -} - -Renderer.prototype.RenderTextFragment = function(text, style) { - - var defaultFontSize = 12 - // , header = "/F1 16 Tf\n16 TL\n0 g" - , font = this.pdf.internal.getFont(style['font-family'], style['font-style']) - - this.pdf.internal.write( - '/' + font.id // font key - , (defaultFontSize * style['font-size']).toFixed(2) // font size comes as float = proportion to normal. - , 'Tf' // font def marker - , '('+this.pdf.internal.pdfEscape(text)+') Tj' - ) -} - -Renderer.prototype.renderParagraph = function(){ - - var fragments = PurgeWhiteSpace( this.paragraph.text ) - , styles = this.paragraph.style - , blockstyle = this.paragraph.blockstyle - , priorblockstype = this.paragraph.blockstyle || {} - this.paragraph = {'text':[], 'style':[], 'blockstyle':{}, 'priorblockstyle':blockstyle} - - if (!fragments.join('').trim()) { - /* if it's empty string */ - return - } // else there is something to draw - - var lines = this.splitFragmentsIntoLines(fragments, styles) - , line // will be array of array pairs [[t,s],[t,s],[t,s]...] where t = text, s = style object - - , maxLineHeight - , defaultFontSize = 12 - , fontToUnitRatio = defaultFontSize / this.pdf.internal.scaleFactor - - // these will be in pdf instance units - , paragraphspacing_before = ( - // we only use margin-top potion that is larger than margin-bottom of previous elem - // because CSS margins don't stack, they overlap. - Math.max( ( blockstyle['margin-top'] || 0 ) - ( priorblockstype['margin-bottom'] || 0 ), 0 ) + - ( blockstyle['padding-top'] || 0 ) - ) * fontToUnitRatio - , paragraphspacing_after = ( - ( blockstyle['margin-bottom'] || 0 ) + ( blockstyle['padding-bottom'] || 0 ) - ) * fontToUnitRatio - - , out = this.pdf.internal.write - - , i, l - - this.y += paragraphspacing_before - - out( - 'q' // canning the scope - , 'BT' // Begin Text - // and this moves the text start to desired position. - , this.pdf.internal.getCoordinateString(this.x) - , this.pdf.internal.getVerticalCoordinateString(this.y) - , 'Td' - ) - - // looping through lines - while (lines.length) { - line = lines.shift() - - maxLineHeight = 0 - - for (i = 0, l = line.length; i !== l; i++) { - if (line[i][0].trim()) { - maxLineHeight = Math.max(maxLineHeight, line[i][1]['line-height'], line[i][1]['font-size']) - } - } - - // current coordinates are "top left" corner of text box. Text must start from "lower left" - // so, lowering the current coord one line height. - out( - 0 - , (-1 * defaultFontSize * maxLineHeight).toFixed(2) // shifting down a line in native `points' means reducing y coordinate - , 'Td' - // , (defaultFontSize * maxLineHeight).toFixed(2) // line height comes as float = proportion to normal. - // , 'TL' // line height marker. Not sure we need it with "Td", but... - ) - - for (i = 0, l = line.length; i !== l; i++) { - if (line[i][0]) { - this.RenderTextFragment(line[i][0], line[i][1]) - } - } - - // y is in user units (cm, inch etc) - // maxLineHeight is ratio of defaultFontSize - // defaultFontSize is in points always. - // this.internal.scaleFactor is ratio of user unit to points. - // Dividing by it converts points to user units. - // vertical offset will be in user units. - // this.y is in user units. - this.y += maxLineHeight * fontToUnitRatio - } - - out( - 'ET' // End Text - , 'Q' // restore scope - ) - - this.y += paragraphspacing_after -} - -Renderer.prototype.setBlockBoundary = function(){ - this.renderParagraph() -} - -Renderer.prototype.setBlockStyle = function(css){ - this.paragraph.blockstyle = css -} - -Renderer.prototype.addText = function(text, css){ - this.paragraph.text.push(text) - this.paragraph.style.push(css) -} - - -//===================== -// these are DrillForContent and friends - -var FontNameDB = { - 'helvetica':'helvetica' - , 'sans-serif':'helvetica' - , 'serif':'times' - , 'times':'times' - , 'times new roman':'times' - , 'monospace':'courier' - , 'courier':'courier' -} -, FontWeightMap = {"100":'normal',"200":'normal',"300":'normal',"400":'normal',"500":'bold',"600":'bold',"700":'bold',"800":'bold',"900":'bold',"normal":'normal',"bold":'bold',"bolder":'bold',"lighter":'normal'} -, FontStyleMap = {'normal':'normal','italic':'italic','oblique':'italic'} -, UnitedNumberMap = {'normal':1} - -function ResolveFont(css_font_family_string){ - var name - , parts = css_font_family_string.split(',') // yes, we don't care about , inside quotes - , part = parts.shift() - - while (!name && part){ - name = FontNameDB[ part.trim().toLowerCase() ] - part = parts.shift() - } - return name -} - -// return ratio to "normal" font size. in other words, it's fraction of 16 pixels. -function ResolveUnitedNumber(css_line_height_string){ - var undef - , normal = 16.00 - , value = UnitedNumberMap[css_line_height_string] - if (value) { - return value - } - - // not in cache, ok. need to parse it. - - // Could it be a named value? - // we will use Windows 94dpi sizing with CSS2 suggested 1.2 step ratio - // where "normal" or "medium" is 16px - // see: http://style.cleverchimp.com/font_size_intervals/altintervals.html - value = ({ - 'xx-small':9 - , 'x-small':11 - , 'small':13 - , 'medium':16 - , 'large':19 - , 'x-large':23 - , 'xx-large':28 - , 'auto':0 - })[css_line_height_string] - if (value !== undef) { - // caching, returning - return UnitedNumberMap[css_line_height_string] = value / normal - } - - // not in cache, ok. need to parse it. - // is it int? - if (value = parseFloat(css_line_height_string)) { - // caching, returning - return UnitedNumberMap[css_line_height_string] = value / normal - } - - // must be a "united" value ('123em', '134px' etc.) - // most browsers convert it to px so, only handling the px - value = css_line_height_string.match( /([\d\.]+)(px)/ ) - if (value.length === 3) { - // caching, returning - return UnitedNumberMap[css_line_height_string] = parseFloat( value[1] ) / normal - } - - return UnitedNumberMap[css_line_height_string] = 1 -} - -function GetCSS(element){ - var $e = $(element) - , css = {} - , tmp - - css['font-family'] = ResolveFont( $e.css('font-family') ) || 'times' - css['font-style'] = FontStyleMap [ $e.css('font-style') ] || 'normal' - tmp = FontWeightMap[ $e.css('font-weight') ] || 'normal' - if (tmp === 'bold') { - if (css['font-style'] === 'normal') { - css['font-style'] = tmp - } else { - css['font-style'] = tmp + css['font-style'] // jsPDF's default fonts have it as "bolditalic" - } - } - - css['font-size'] = ResolveUnitedNumber( $e.css('font-size') ) || 1 // ratio to "normal" size - css['line-height'] = ResolveUnitedNumber( $e.css('line-height') ) || 1 // ratio to "normal" size - - css['display'] = $e.css('display') === 'inline' ? 'inline' : 'block' - - if (css['display'] === 'block'){ - css['margin-top'] = ResolveUnitedNumber( $e.css('margin-top') ) || 0 - css['margin-bottom'] = ResolveUnitedNumber( $e.css('margin-bottom') ) || 0 - css['padding-top'] = ResolveUnitedNumber( $e.css('padding-top') ) || 0 - css['padding-bottom'] = ResolveUnitedNumber( $e.css('padding-bottom') ) || 0 - } - - return css -} - -function elementHandledElsewhere(element, renderer, elementHandlers){ - var isHandledElsewhere = false - - var i, l, t - , handlers = elementHandlers['#'+element.id] - if (handlers) { - if (typeof handlers === 'function') { - isHandledElsewhere = handlers(element, renderer) - } else /* array */ { - i = 0 - l = handlers.length - while (!isHandledElsewhere && i !== l){ - isHandledElsewhere = handlers[i](element, renderer) - ;i++; - } - } - } - - handlers = elementHandlers[element.nodeName] - if (!isHandledElsewhere && handlers) { - if (typeof handlers === 'function') { - isHandledElsewhere = handlers(element, renderer) - } else /* array */ { - i = 0 - l = handlers.length - while (!isHandledElsewhere && i !== l){ - isHandledElsewhere = handlers[i](element, renderer) - ;i++; - } - } - } - - return isHandledElsewhere -} - -function DrillForContent(element, renderer, elementHandlers){ - var cns = element.childNodes - , cn - , fragmentCSS = GetCSS(element) - , isBlock = fragmentCSS.display === 'block' - - if (isBlock) { - renderer.setBlockBoundary() - renderer.setBlockStyle(fragmentCSS) - } - - for (var i = 0, l = cns.length; i < l ; i++){ - cn = cns[i] - - if (typeof cn === 'object') { - // Don't render the insides of script tags, they contain text nodes which then render - if (cn.nodeType === 1 && cn.nodeName != 'SCRIPT') { - if (!elementHandledElsewhere(cn, renderer, elementHandlers)) { - DrillForContent(cn, renderer, elementHandlers) - } - } else if (cn.nodeType === 3){ - renderer.addText( cn.nodeValue, fragmentCSS ) - } - } else if (typeof cn === 'string') { - renderer.addText( cn, fragmentCSS ) - } - } - - if (isBlock) { - renderer.setBlockBoundary() - } -} - -function process(pdf, element, x, y, settings) { - - // we operate on DOM elems. So HTML-formatted strings need to pushed into one - if (typeof element === 'string') { - element = (function(element) { - var framename = "jsPDFhtmlText" + Date.now().toString() + (Math.random() * 1000).toFixed(0) - , visuallyhidden = 'position: absolute !important;' + - 'clip: rect(1px 1px 1px 1px); /* IE6, IE7 */' + - 'clip: rect(1px, 1px, 1px, 1px);' + - 'padding:0 !important;' + - 'border:0 !important;' + - 'height: 1px !important;' + - 'width: 1px !important; ' + - 'top:auto;' + - 'left:-100px;' + - 'overflow: hidden;' - // TODO: clean up hidden div - , $hiddendiv = $( - '
' + - '