UNPKG

pdfmake

Version:

Client/server side PDF printing in pure JavaScript

1,772 lines (1,770 loc) 124 kB
"use strict"; var SVGtoPDF = function (doc, svg, x, y, options) { "use strict"; const NamedColors = { aliceblue: [240, 248, 255], antiquewhite: [250, 235, 215], aqua: [0, 255, 255], aquamarine: [127, 255, 212], azure: [240, 255, 255], beige: [245, 245, 220], bisque: [255, 228, 196], black: [0, 0, 0], blanchedalmond: [255, 235, 205], blue: [0, 0, 255], blueviolet: [138, 43, 226], brown: [165, 42, 42], burlywood: [222, 184, 135], cadetblue: [95, 158, 160], chartreuse: [127, 255, 0], chocolate: [210, 105, 30], coral: [255, 127, 80], cornflowerblue: [100, 149, 237], cornsilk: [255, 248, 220], crimson: [220, 20, 60], cyan: [0, 255, 255], darkblue: [0, 0, 139], darkcyan: [0, 139, 139], darkgoldenrod: [184, 134, 11], darkgray: [169, 169, 169], darkgrey: [169, 169, 169], darkgreen: [0, 100, 0], darkkhaki: [189, 183, 107], darkmagenta: [139, 0, 139], darkolivegreen: [85, 107, 47], darkorange: [255, 140, 0], darkorchid: [153, 50, 204], darkred: [139, 0, 0], darksalmon: [233, 150, 122], darkseagreen: [143, 188, 143], darkslateblue: [72, 61, 139], darkslategray: [47, 79, 79], darkslategrey: [47, 79, 79], darkturquoise: [0, 206, 209], darkviolet: [148, 0, 211], deeppink: [255, 20, 147], deepskyblue: [0, 191, 255], dimgray: [105, 105, 105], dimgrey: [105, 105, 105], dodgerblue: [30, 144, 255], firebrick: [178, 34, 34], floralwhite: [255, 250, 240], forestgreen: [34, 139, 34], fuchsia: [255, 0, 255], gainsboro: [220, 220, 220], ghostwhite: [248, 248, 255], gold: [255, 215, 0], goldenrod: [218, 165, 32], gray: [128, 128, 128], grey: [128, 128, 128], green: [0, 128, 0], greenyellow: [173, 255, 47], honeydew: [240, 255, 240], hotpink: [255, 105, 180], indianred: [205, 92, 92], indigo: [75, 0, 130], ivory: [255, 255, 240], khaki: [240, 230, 140], lavender: [230, 230, 250], lavenderblush: [255, 240, 245], lawngreen: [124, 252, 0], lemonchiffon: [255, 250, 205], lightblue: [173, 216, 230], lightcoral: [240, 128, 128], lightcyan: [224, 255, 255], lightgoldenrodyellow: [250, 250, 210], lightgray: [211, 211, 211], lightgrey: [211, 211, 211], lightgreen: [144, 238, 144], lightpink: [255, 182, 193], lightsalmon: [255, 160, 122], lightseagreen: [32, 178, 170], lightskyblue: [135, 206, 250], lightslategray: [119, 136, 153], lightslategrey: [119, 136, 153], lightsteelblue: [176, 196, 222], lightyellow: [255, 255, 224], lime: [0, 255, 0], limegreen: [50, 205, 50], linen: [250, 240, 230], magenta: [255, 0, 255], maroon: [128, 0, 0], mediumaquamarine: [102, 205, 170], mediumblue: [0, 0, 205], mediumorchid: [186, 85, 211], mediumpurple: [147, 112, 219], mediumseagreen: [60, 179, 113], mediumslateblue: [123, 104, 238], mediumspringgreen: [0, 250, 154], mediumturquoise: [72, 209, 204], mediumvioletred: [199, 21, 133], midnightblue: [25, 25, 112], mintcream: [245, 255, 250], mistyrose: [255, 228, 225], moccasin: [255, 228, 181], navajowhite: [255, 222, 173], navy: [0, 0, 128], oldlace: [253, 245, 230], olive: [128, 128, 0], olivedrab: [107, 142, 35], orange: [255, 165, 0], orangered: [255, 69, 0], orchid: [218, 112, 214], palegoldenrod: [238, 232, 170], palegreen: [152, 251, 152], paleturquoise: [175, 238, 238], palevioletred: [219, 112, 147], papayawhip: [255, 239, 213], peachpuff: [255, 218, 185], peru: [205, 133, 63], pink: [255, 192, 203], plum: [221, 160, 221], powderblue: [176, 224, 230], purple: [128, 0, 128], rebeccapurple: [102, 51, 153], red: [255, 0, 0], rosybrown: [188, 143, 143], royalblue: [65, 105, 225], saddlebrown: [139, 69, 19], salmon: [250, 128, 114], sandybrown: [244, 164, 96], seagreen: [46, 139, 87], seashell: [255, 245, 238], sienna: [160, 82, 45], silver: [192, 192, 192], skyblue: [135, 206, 235], slateblue: [106, 90, 205], slategray: [112, 128, 144], slategrey: [112, 128, 144], snow: [255, 250, 250], springgreen: [0, 255, 127], steelblue: [70, 130, 180], tan: [210, 180, 140], teal: [0, 128, 128], thistle: [216, 191, 216], tomato: [255, 99, 71], turquoise: [64, 224, 208], violet: [238, 130, 238], wheat: [245, 222, 179], white: [255, 255, 255], whitesmoke: [245, 245, 245], yellow: [255, 255, 0] }; const DefaultColors = { black: [NamedColors.black, 1], white: [NamedColors.white, 1], transparent: [NamedColors.black, 0] }; const Entities = { quot: 34, amp: 38, lt: 60, gt: 62, apos: 39, OElig: 338, oelig: 339, Scaron: 352, scaron: 353, Yuml: 376, circ: 710, tilde: 732, ensp: 8194, emsp: 8195, thinsp: 8201, zwnj: 8204, zwj: 8205, lrm: 8206, rlm: 8207, ndash: 8211, mdash: 8212, lsquo: 8216, rsquo: 8217, sbquo: 8218, ldquo: 8220, rdquo: 8221, bdquo: 8222, dagger: 8224, Dagger: 8225, permil: 8240, lsaquo: 8249, rsaquo: 8250, euro: 8364, nbsp: 160, iexcl: 161, cent: 162, pound: 163, curren: 164, yen: 165, brvbar: 166, sect: 167, uml: 168, copy: 169, ordf: 170, laquo: 171, not: 172, shy: 173, reg: 174, macr: 175, deg: 176, plusmn: 177, sup2: 178, sup3: 179, acute: 180, micro: 181, para: 182, middot: 183, cedil: 184, sup1: 185, ordm: 186, raquo: 187, frac14: 188, frac12: 189, frac34: 190, iquest: 191, Agrave: 192, Aacute: 193, Acirc: 194, Atilde: 195, Auml: 196, Aring: 197, AElig: 198, Ccedil: 199, Egrave: 200, Eacute: 201, Ecirc: 202, Euml: 203, Igrave: 204, Iacute: 205, Icirc: 206, Iuml: 207, ETH: 208, Ntilde: 209, Ograve: 210, Oacute: 211, Ocirc: 212, Otilde: 213, Ouml: 214, times: 215, Oslash: 216, Ugrave: 217, Uacute: 218, Ucirc: 219, Uuml: 220, Yacute: 221, THORN: 222, szlig: 223, agrave: 224, aacute: 225, acirc: 226, atilde: 227, auml: 228, aring: 229, aelig: 230, ccedil: 231, egrave: 232, eacute: 233, ecirc: 234, euml: 235, igrave: 236, iacute: 237, icirc: 238, iuml: 239, eth: 240, ntilde: 241, ograve: 242, oacute: 243, ocirc: 244, otilde: 245, ouml: 246, divide: 247, oslash: 248, ugrave: 249, uacute: 250, ucirc: 251, uuml: 252, yacute: 253, thorn: 254, yuml: 255, fnof: 402, Alpha: 913, Beta: 914, Gamma: 915, Delta: 916, Epsilon: 917, Zeta: 918, Eta: 919, Theta: 920, Iota: 921, Kappa: 922, Lambda: 923, Mu: 924, Nu: 925, Xi: 926, Omicron: 927, Pi: 928, Rho: 929, Sigma: 931, Tau: 932, Upsilon: 933, Phi: 934, Chi: 935, Psi: 936, Omega: 937, alpha: 945, beta: 946, gamma: 947, delta: 948, epsilon: 949, zeta: 950, eta: 951, theta: 952, iota: 953, kappa: 954, lambda: 955, mu: 956, nu: 957, xi: 958, omicron: 959, pi: 960, rho: 961, sigmaf: 962, sigma: 963, tau: 964, upsilon: 965, phi: 966, chi: 967, psi: 968, omega: 969, thetasym: 977, upsih: 978, piv: 982, bull: 8226, hellip: 8230, prime: 8242, Prime: 8243, oline: 8254, frasl: 8260, weierp: 8472, image: 8465, real: 8476, trade: 8482, alefsym: 8501, larr: 8592, uarr: 8593, rarr: 8594, darr: 8595, harr: 8596, crarr: 8629, lArr: 8656, uArr: 8657, rArr: 8658, dArr: 8659, hArr: 8660, forall: 8704, part: 8706, exist: 8707, empty: 8709, nabla: 8711, isin: 8712, notin: 8713, ni: 8715, prod: 8719, sum: 8721, minus: 8722, lowast: 8727, radic: 8730, prop: 8733, infin: 8734, ang: 8736, and: 8743, or: 8744, cap: 8745, cup: 8746, int: 8747, there4: 8756, sim: 8764, cong: 8773, asymp: 8776, ne: 8800, equiv: 8801, le: 8804, ge: 8805, sub: 8834, sup: 8835, nsub: 8836, sube: 8838, supe: 8839, oplus: 8853, otimes: 8855, perp: 8869, sdot: 8901, lceil: 8968, rceil: 8969, lfloor: 8970, rfloor: 8971, lang: 9001, rang: 9002, loz: 9674, spades: 9824, clubs: 9827, hearts: 9829, diams: 9830 }; const PathArguments = { A: 7, a: 7, C: 6, c: 6, H: 1, h: 1, L: 2, l: 2, M: 2, m: 2, Q: 4, q: 4, S: 4, s: 4, T: 2, t: 2, V: 1, v: 1, Z: 0, z: 0 }; const PathFlags = { A3: true, A4: true, a3: true, a4: true }; const Properties = { 'color': { inherit: true, initial: undefined }, 'visibility': { inherit: true, initial: 'visible', values: { 'hidden': 'hidden', 'collapse': 'hidden', 'visible': 'visible' } }, 'fill': { inherit: true, initial: DefaultColors.black }, 'stroke': { inherit: true, initial: 'none' }, 'stop-color': { inherit: false, initial: DefaultColors.black }, 'fill-opacity': { inherit: true, initial: 1 }, 'stroke-opacity': { inherit: true, initial: 1 }, 'stop-opacity': { inherit: false, initial: 1 }, 'fill-rule': { inherit: true, initial: 'nonzero', values: { 'nonzero': 'nonzero', 'evenodd': 'evenodd' } }, 'clip-rule': { inherit: true, initial: 'nonzero', values: { 'nonzero': 'nonzero', 'evenodd': 'evenodd' } }, 'stroke-width': { inherit: true, initial: 1 }, 'stroke-dasharray': { inherit: true, initial: [] }, 'stroke-dashoffset': { inherit: true, initial: 0 }, 'stroke-miterlimit': { inherit: true, initial: 4 }, 'stroke-linejoin': { inherit: true, initial: 'miter', values: { 'miter': 'miter', 'round': 'round', 'bevel': 'bevel' } }, 'stroke-linecap': { inherit: true, initial: 'butt', values: { 'butt': 'butt', 'round': 'round', 'square': 'square' } }, 'font-size': { inherit: true, initial: 16, values: { 'xx-small': 9, 'x-small': 10, 'small': 13, 'medium': 16, 'large': 18, 'x-large': 24, 'xx-large': 32 } }, 'font-family': { inherit: true, initial: 'sans-serif' }, 'font-weight': { inherit: true, initial: 'normal', values: { '600': 'bold', '700': 'bold', '800': 'bold', '900': 'bold', 'bold': 'bold', 'bolder': 'bold', '500': 'normal', '400': 'normal', '300': 'normal', '200': 'normal', '100': 'normal', 'normal': 'normal', 'lighter': 'normal' } }, 'font-style': { inherit: true, initial: 'normal', values: { 'italic': 'italic', 'oblique': 'italic', 'normal': 'normal' } }, 'text-anchor': { inherit: true, initial: 'start', values: { 'start': 'start', 'middle': 'middle', 'end': 'end' } }, 'direction': { inherit: true, initial: 'ltr', values: { 'ltr': 'ltr', 'rtl': 'rtl' } }, 'dominant-baseline': { inherit: true, initial: 'baseline', values: { 'auto': 'baseline', 'baseline': 'baseline', 'before-edge': 'before-edge', 'text-before-edge': 'before-edge', 'middle': 'middle', 'central': 'central', 'after-edge': 'after-edge', 'text-after-edge': 'after-edge', 'ideographic': 'ideographic', 'alphabetic': 'alphabetic', 'hanging': 'hanging', 'mathematical': 'mathematical' } }, 'alignment-baseline': { inherit: false, initial: undefined, values: { 'auto': 'baseline', 'baseline': 'baseline', 'before-edge': 'before-edge', 'text-before-edge': 'before-edge', 'middle': 'middle', 'central': 'central', 'after-edge': 'after-edge', 'text-after-edge': 'after-edge', 'ideographic': 'ideographic', 'alphabetic': 'alphabetic', 'hanging': 'hanging', 'mathematical': 'mathematical' } }, 'baseline-shift': { inherit: true, initial: 'baseline', values: { 'baseline': 'baseline', 'sub': 'sub', 'super': 'super' } }, 'word-spacing': { inherit: true, initial: 0, values: { normal: 0 } }, 'letter-spacing': { inherit: true, initial: 0, values: { normal: 0 } }, 'text-decoration': { inherit: false, initial: 'none', values: { 'none': 'none', 'underline': 'underline', 'overline': 'overline', 'line-through': 'line-through' } }, 'xml:space': { inherit: true, initial: 'default', css: 'white-space', values: { 'preserve': 'preserve', 'default': 'default', 'pre': 'preserve', 'pre-line': 'preserve', 'pre-wrap': 'preserve', 'nowrap': 'default' } }, 'marker-start': { inherit: true, initial: 'none' }, 'marker-mid': { inherit: true, initial: 'none' }, 'marker-end': { inherit: true, initial: 'none' }, 'opacity': { inherit: false, initial: 1 }, 'transform': { inherit: false, initial: [1, 0, 0, 1, 0, 0] }, 'display': { inherit: false, initial: 'inline', values: { 'none': 'none', 'inline': 'inline', 'block': 'inline' } }, 'clip-path': { inherit: false, initial: 'none' }, 'mask': { inherit: false, initial: 'none' }, 'overflow': { inherit: false, initial: 'hidden', values: { 'hidden': 'hidden', 'scroll': 'hidden', 'visible': 'visible' } } }; function docBeginGroup(bbox) { let group = new function PDFGroup() {}(); group.name = 'G' + (doc._groupCount = (doc._groupCount || 0) + 1); group.resources = doc.ref(); group.xobj = doc.ref({ Type: 'XObject', Subtype: 'Form', FormType: 1, BBox: bbox, Group: { S: 'Transparency', CS: 'DeviceRGB', I: true, K: false }, Resources: group.resources }); group.xobj.write(''); group.savedMatrix = doc._ctm; group.savedPage = doc.page; groupStack.push(group); doc._ctm = [1, 0, 0, 1, 0, 0]; doc.page = { width: doc.page.width, height: doc.page.height, write: function (data) { group.xobj.write(data); }, fonts: {}, xobjects: {}, ext_gstates: {}, patterns: {} }; return group; } function docEndGroup(group) { if (group !== groupStack.pop()) { throw 'Group not matching'; } if (Object.keys(doc.page.fonts).length) { group.resources.data.Font = doc.page.fonts; } if (Object.keys(doc.page.xobjects).length) { group.resources.data.XObject = doc.page.xobjects; } if (Object.keys(doc.page.ext_gstates).length) { group.resources.data.ExtGState = doc.page.ext_gstates; } if (Object.keys(doc.page.patterns).length) { group.resources.data.Pattern = doc.page.patterns; } group.resources.end(); group.xobj.end(); doc._ctm = group.savedMatrix; doc.page = group.savedPage; } function docInsertGroup(group) { doc.page.xobjects[group.name] = group.xobj; doc.addContent('/' + group.name + ' Do'); } function docApplyMask(group, clip) { let name = 'M' + (doc._maskCount = (doc._maskCount || 0) + 1); let gstate = doc.ref({ Type: 'ExtGState', CA: 1, ca: 1, BM: 'Normal', SMask: { S: 'Luminosity', G: group.xobj, BC: clip ? [0, 0, 0] : [1, 1, 1] } }); gstate.end(); doc.page.ext_gstates[name] = gstate; doc.addContent('/' + name + ' gs'); } function docCreatePattern(group, dx, dy, matrix) { let pattern = new function PDFPattern() {}(); pattern.group = group; pattern.dx = dx; pattern.dy = dy; pattern.matrix = matrix || [1, 0, 0, 1, 0, 0]; return pattern; } function docUsePattern(pattern, stroke) { let name = 'P' + (doc._patternCount = (doc._patternCount || 0) + 1); let ref = doc.ref({ Type: 'Pattern', PatternType: 1, PaintType: 1, TilingType: 2, BBox: [0, 0, pattern.dx, pattern.dy], XStep: pattern.dx, YStep: pattern.dy, Matrix: multiplyMatrix(doc._ctm, pattern.matrix), Resources: { ProcSet: ['PDF', 'Text', 'ImageB', 'ImageC', 'ImageI'], XObject: function () { let temp = {}; temp[pattern.group.name] = pattern.group.xobj; return temp; }() } }); ref.write('/' + pattern.group.name + ' Do'); ref.end(); doc.page.patterns[name] = ref; if (stroke) { doc.addContent('/Pattern CS'); doc.addContent('/' + name + ' SCN'); } else { doc.addContent('/Pattern cs'); doc.addContent('/' + name + ' scn'); } } function docBeginText(font, size) { if (!doc.page.fonts[font.id]) { doc.page.fonts[font.id] = font.ref(); } doc.addContent('BT').addContent('/' + font.id + ' ' + size + ' Tf'); } function docSetTextMatrix(a, b, c, d, e, f) { doc.addContent(validateNumber(a) + ' ' + validateNumber(b) + ' ' + validateNumber(-c) + ' ' + validateNumber(-d) + ' ' + validateNumber(e) + ' ' + validateNumber(f) + ' Tm'); } function docSetTextMode(fill, stroke) { let mode = fill && stroke ? 2 : stroke ? 1 : fill ? 0 : 3; doc.addContent(mode + ' Tr'); } function docWriteGlyph(glyph) { doc.addContent('<' + glyph + '> Tj'); } function docEndText() { doc.addContent('ET'); } function docFillColor(color) { if (color[0].constructor.name === 'PDFPattern') { doc.fillOpacity(color[1]); docUsePattern(color[0], false); } else { doc.fillColor(color[0], color[1]); } } function docStrokeColor(color) { if (color[0].constructor.name === 'PDFPattern') { doc.strokeOpacity(color[1]); docUsePattern(color[0], true); } else { doc.strokeColor(color[0], color[1]); } } function docInsertLink(x, y, w, h, url) { let ref = doc.ref({ Type: 'Annot', Subtype: 'Link', Rect: [x, y, w, h], Border: [0, 0, 0], A: { S: 'URI', URI: new String(url) } }); ref.end(); links.push(ref); } function parseXml(xml) { let SvgNode = function (tag, type, value, error) { this.error = error; this.nodeName = tag; this.nodeValue = value; this.nodeType = type; this.attributes = Object.create(null); this.childNodes = []; this.parentNode = null; this.id = ''; this.textContent = ''; this.classList = []; }; SvgNode.prototype.getAttribute = function (attr) { return this.attributes[attr] != null ? this.attributes[attr] : null; }; SvgNode.prototype.getElementById = function (id) { let result = null; (function recursive(node) { if (result) { return; } if (node.nodeType === 1) { if (node.id === id) { result = node; } for (let i = 0; i < node.childNodes.length; i++) { recursive(node.childNodes[i]); } } })(this); return result; }; SvgNode.prototype.getElementsByTagName = function (tag) { let result = []; (function recursive(node) { if (node.nodeType === 1) { if (node.nodeName === tag) { result.push(node); } for (let i = 0; i < node.childNodes.length; i++) { recursive(node.childNodes[i]); } } })(this); return result; }; let parser = new StringParser(xml.trim()), result, child, error = false; let recursive = function () { let temp, child; if (temp = parser.match(/^<([\w:.-]+)\s*/, true)) { // Opening tag let node = new SvgNode(temp[1], 1, null, error); while (temp = parser.match(/^([\w:.-]+)(?:\s*=\s*"([^"]*)"|\s*=\s*'([^']*)')?\s*/, true)) { // Attribute let attr = temp[1], value = decodeEntities(temp[2] || temp[3] || ''); if (!node.attributes[attr]) { node.attributes[attr] = value; if (attr === 'id') { node.id = value; } if (attr === 'class') { node.classList = value.split(' '); } } else { warningCallback('parseXml: duplicate attribute "' + attr + '"'); error = true; } } if (parser.match(/^>/)) { // End of opening tag while (child = recursive()) { node.childNodes.push(child); child.parentNode = node; node.textContent += child.nodeType === 3 || child.nodeType === 4 ? child.nodeValue : child.textContent; } if (temp = parser.match(/^<\/([\w:.-]+)\s*>/, true)) { // Closing tag if (temp[1] === node.nodeName) { return node; } else { warningCallback('parseXml: tag not matching, opening "' + node.nodeName + '" & closing "' + temp[1] + '"'); error = true; return node; } } else { warningCallback('parseXml: tag not matching, opening "' + node.nodeName + '" & not closing'); error = true; return node; } } else if (parser.match(/^\/>/)) { // Self-closing tag return node; } else { warningCallback('parseXml: tag could not be parsed "' + node.nodeName + '"'); error = true; } } else if (temp = parser.match(/^<!--[\s\S]*?-->/)) { // Comment return new SvgNode(null, 8, temp, error); } else if (temp = parser.match(/^<\?[\s\S]*?\?>/)) { // Processing instructions return new SvgNode(null, 7, temp, error); } else if (temp = parser.match(/^<!DOCTYPE\s*([\s\S]*?)>/)) { // Doctype return new SvgNode(null, 10, temp, error); } else if (temp = parser.match(/^<!\[CDATA\[([\s\S]*?)\]\]>/, true)) { // Cdata node return new SvgNode('#cdata-section', 4, temp[1], error); } else if (temp = parser.match(/^([^<]+)/, true)) { // Text node return new SvgNode('#text', 3, decodeEntities(temp[1]), error); } }; while (child = recursive()) { if (child.nodeType === 1 && !result) { result = child; } else if (child.nodeType === 1 || child.nodeType === 3 && child.nodeValue.trim() !== '') { warningCallback('parseXml: data after document end has been discarded'); } } if (parser.matchAll()) { warningCallback('parseXml: parsing error'); } return result; } ; function decodeEntities(str) { return str.replace(/&(?:#([0-9]+)|#[xX]([0-9A-Fa-f]+)|([0-9A-Za-z]+));/g, function (mt, m0, m1, m2) { if (m0) { return String.fromCharCode(parseInt(m0, 10)); } else if (m1) { return String.fromCharCode(parseInt(m1, 16)); } else if (m2 && Entities[m2]) { return String.fromCharCode(Entities[m2]); } else { return mt; } }); } function parseColor(raw) { let temp, result; raw = (raw || '').trim(); if (temp = NamedColors[raw]) { result = [temp.slice(), 1]; } else if (temp = raw.match(/^rgba\(\s*([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9.]+)\s*\)$/i)) { temp[1] = parseInt(temp[1]); temp[2] = parseInt(temp[2]); temp[3] = parseInt(temp[3]); temp[4] = parseFloat(temp[4]); if (temp[1] < 256 && temp[2] < 256 && temp[3] < 256 && temp[4] <= 1) { result = [temp.slice(1, 4), temp[4]]; } } else if (temp = raw.match(/^rgb\(\s*([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\s*\)$/i)) { temp[1] = parseInt(temp[1]); temp[2] = parseInt(temp[2]); temp[3] = parseInt(temp[3]); if (temp[1] < 256 && temp[2] < 256 && temp[3] < 256) { result = [temp.slice(1, 4), 1]; } } else if (temp = raw.match(/^rgb\(\s*([0-9.]+)%\s*,\s*([0-9.]+)%\s*,\s*([0-9.]+)%\s*\)$/i)) { temp[1] = 2.55 * parseFloat(temp[1]); temp[2] = 2.55 * parseFloat(temp[2]); temp[3] = 2.55 * parseFloat(temp[3]); if (temp[1] < 256 && temp[2] < 256 && temp[3] < 256) { result = [temp.slice(1, 4), 1]; } } else if (temp = raw.match(/^#([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})$/i)) { result = [[parseInt(temp[1], 16), parseInt(temp[2], 16), parseInt(temp[3], 16)], 1]; } else if (temp = raw.match(/^#([0-9a-f])([0-9a-f])([0-9a-f])$/i)) { result = [[0x11 * parseInt(temp[1], 16), 0x11 * parseInt(temp[2], 16), 0x11 * parseInt(temp[3], 16)], 1]; } return colorCallback ? colorCallback(result, raw) : result; } function opacityToColor(color, opacity, isMask) { let newColor = color[0].slice(), newOpacity = color[1] * opacity; if (isMask) { for (let i = 0; i < color.length; i++) { newColor[i] *= newOpacity; } return [newColor, 1]; } else { return [newColor, newOpacity]; } } function multiplyMatrix() { function multiply(a, b) { return [a[0] * b[0] + a[2] * b[1], a[1] * b[0] + a[3] * b[1], a[0] * b[2] + a[2] * b[3], a[1] * b[2] + a[3] * b[3], a[0] * b[4] + a[2] * b[5] + a[4], a[1] * b[4] + a[3] * b[5] + a[5]]; } let result = arguments[0]; for (let i = 1; i < arguments.length; i++) { result = multiply(result, arguments[i]); } return result; } function transformPoint(p, m) { return [m[0] * p[0] + m[2] * p[1] + m[4], m[1] * p[0] + m[3] * p[1] + m[5]]; } function getGlobalMatrix() { let ctm = doc._ctm; for (let i = groupStack.length - 1; i >= 0; i--) { ctm = multiplyMatrix(groupStack[i].savedMatrix, ctm); } return ctm; } function getPageBBox() { return new SvgShape().M(0, 0).L(doc.page.width, 0).L(doc.page.width, doc.page.height).L(0, doc.page.height).transform(inverseMatrix(getGlobalMatrix())).getBoundingBox(); } function inverseMatrix(m) { let dt = m[0] * m[3] - m[1] * m[2]; return [m[3] / dt, -m[1] / dt, -m[2] / dt, m[0] / dt, (m[2] * m[5] - m[3] * m[4]) / dt, (m[1] * m[4] - m[0] * m[5]) / dt]; } function validateMatrix(m) { let m0 = validateNumber(m[0]), m1 = validateNumber(m[1]), m2 = validateNumber(m[2]), m3 = validateNumber(m[3]), m4 = validateNumber(m[4]), m5 = validateNumber(m[5]); if (isNotEqual(m0 * m3 - m1 * m2, 0)) { return [m0, m1, m2, m3, m4, m5]; } } function solveEquation(curve) { let a = curve[2] || 0, b = curve[1] || 0, c = curve[0] || 0; if (isEqual(a, 0) && isEqual(b, 0)) { return []; } else if (isEqual(a, 0)) { return [-c / b]; } else { let d = b * b - 4 * a * c; if (isNotEqual(d, 0) && d > 0) { return [(-b + Math.sqrt(d)) / (2 * a), (-b - Math.sqrt(d)) / (2 * a)]; } else if (isEqual(d, 0)) { return [-b / (2 * a)]; } else { return []; } } } function getCurveValue(t, curve) { return (curve[0] || 0) + (curve[1] || 0) * t + (curve[2] || 0) * t * t + (curve[3] || 0) * t * t * t; } function isEqual(number, ref) { return Math.abs(number - ref) < 1e-10; } function isNotEqual(number, ref) { return Math.abs(number - ref) >= 1e-10; } function validateNumber(n) { return n > -1e21 && n < 1e21 ? Math.round(n * 1e6) / 1e6 : 0; } function isArrayLike(v) { return typeof v === 'object' && v !== null && typeof v.length === 'number'; } function parseTranform(v) { let parser = new StringParser((v || '').trim()), result = [1, 0, 0, 1, 0, 0], temp; while (temp = parser.match(/^([A-Za-z]+)\s*[(]([^(]+)[)]/, true)) { let func = temp[1], nums = [], parser2 = new StringParser(temp[2].trim()), temp2; while (temp2 = parser2.matchNumber()) { nums.push(Number(temp2)); parser2.matchSeparator(); } if (func === 'matrix' && nums.length === 6) { result = multiplyMatrix(result, [nums[0], nums[1], nums[2], nums[3], nums[4], nums[5]]); } else if (func === 'translate' && nums.length === 2) { result = multiplyMatrix(result, [1, 0, 0, 1, nums[0], nums[1]]); } else if (func === 'translate' && nums.length === 1) { result = multiplyMatrix(result, [1, 0, 0, 1, nums[0], 0]); } else if (func === 'scale' && nums.length === 2) { result = multiplyMatrix(result, [nums[0], 0, 0, nums[1], 0, 0]); } else if (func === 'scale' && nums.length === 1) { result = multiplyMatrix(result, [nums[0], 0, 0, nums[0], 0, 0]); } else if (func === 'rotate' && nums.length === 3) { let a = nums[0] * Math.PI / 180; result = multiplyMatrix(result, [1, 0, 0, 1, nums[1], nums[2]], [Math.cos(a), Math.sin(a), -Math.sin(a), Math.cos(a), 0, 0], [1, 0, 0, 1, -nums[1], -nums[2]]); } else if (func === 'rotate' && nums.length === 1) { let a = nums[0] * Math.PI / 180; result = multiplyMatrix(result, [Math.cos(a), Math.sin(a), -Math.sin(a), Math.cos(a), 0, 0]); } else if (func === 'skewX' && nums.length === 1) { let a = nums[0] * Math.PI / 180; result = multiplyMatrix(result, [1, 0, Math.tan(a), 1, 0, 0]); } else if (func === 'skewY' && nums.length === 1) { let a = nums[0] * Math.PI / 180; result = multiplyMatrix(result, [1, Math.tan(a), 0, 1, 0, 0]); } else { return; } parser.matchSeparator(); } if (parser.matchAll()) { return; } return result; } function parseAspectRatio(aspectRatio, availWidth, availHeight, elemWidth, elemHeight, initAlign) { let temp = (aspectRatio || '').trim().match(/^(none)$|^x(Min|Mid|Max)Y(Min|Mid|Max)(?:\s+(meet|slice))?$/) || [], ratioType = temp[1] || temp[4] || 'meet', xAlign = temp[2] || 'Mid', yAlign = temp[3] || 'Mid', scaleX = availWidth / elemWidth, scaleY = availHeight / elemHeight, dx = { 'Min': 0, 'Mid': 0.5, 'Max': 1 }[xAlign] - (initAlign || 0), dy = { 'Min': 0, 'Mid': 0.5, 'Max': 1 }[yAlign] - (initAlign || 0); if (ratioType === 'slice') { scaleY = scaleX = Math.max(scaleX, scaleY); } else if (ratioType === 'meet') { scaleY = scaleX = Math.min(scaleX, scaleY); } return [scaleX, 0, 0, scaleY, dx * (availWidth - elemWidth * scaleX), dy * (availHeight - elemHeight * scaleY)]; } function parseStyleAttr(v) { let result = Object.create(null); v = (v || '').trim().split(/;/); for (let i = 0; i < v.length; i++) { let key = (v[i].split(':')[0] || '').trim(), value = (v[i].split(':')[1] || '').trim(); if (key) { result[key] = value; } } if (result['marker']) { if (!result['marker-start']) { result['marker-start'] = result['marker']; } if (!result['marker-mid']) { result['marker-mid'] = result['marker']; } if (!result['marker-end']) { result['marker-end'] = result['marker']; } } if (result['font']) { let fontFamily = null, fontSize = null, fontStyle = "normal", fontWeight = "normal", fontVariant = "normal"; let parts = result['font'].split(/\s+/); for (let i = 0; i < parts.length; i++) { switch (parts[i]) { case "normal": break; case "italic": case "oblique": fontStyle = parts[i]; break; case "small-caps": fontVariant = parts[i]; break; case "bold": case "bolder": case "lighter": case "100": case "200": case "300": case "400": case "500": case "600": case "700": case "800": case "900": fontWeight = parts[i]; break; default: if (!fontSize) { fontSize = parts[i].split('/')[0]; } else { if (!fontFamily) { fontFamily = parts[i]; } else { fontFamily += ' ' + parts[i]; } } break; } } if (!result['font-style']) { result['font-style'] = fontStyle; } if (!result['font-variant']) { result['font-variant'] = fontVariant; } if (!result['font-weight']) { result['font-weight'] = fontWeight; } if (!result['font-size']) { result['font-size'] = fontSize; } if (!result['font-family']) { result['font-family'] = fontFamily; } } return result; } function parseSelector(v) { let parts = v.split(/(?=[.#])/g), ids = [], classes = [], tags = [], temp; for (let i = 0; i < parts.length; i++) { if (temp = parts[i].match(/^[#]([_A-Za-z0-9-]+)$/)) { ids.push(temp[1]); } else if (temp = parts[i].match(/^[.]([_A-Za-z0-9-]+)$/)) { classes.push(temp[1]); } else if (temp = parts[i].match(/^([_A-Za-z0-9-]+)$/)) { tags.push(temp[1]); } else if (parts[i] !== '*') { return; } } return { tags: tags, ids: ids, classes: classes, specificity: ids.length * 10000 + classes.length * 100 + tags.length }; } function parseStyleSheet(v) { let parser = new StringParser(v.trim()), rules = [], rule; while (rule = parser.match(/^\s*([^\{\}]*?)\s*\{([^\{\}]*?)\}/, true)) { let selectors = rule[1].split(/\s*,\s*/g), css = parseStyleAttr(rule[2]); for (let i = 0; i < selectors.length; i++) { let selector = parseSelector(selectors[i]); if (selector) { rules.push({ selector: selector, css: css }); } } } return rules; } function matchesSelector(elem, selector) { if (elem.nodeType !== 1) { return false; } for (let i = 0; i < selector.tags.length; i++) { if (selector.tags[i] !== elem.nodeName) { return false; } } for (let i = 0; i < selector.ids.length; i++) { if (selector.ids[i] !== elem.id) { return false; } } for (let i = 0; i < selector.classes.length; i++) { if (elem.classList.indexOf(selector.classes[i]) === -1) { return false; } } return true; } function getStyle(elem) { let result = Object.create(null); let specificities = Object.create(null); for (let i = 0; i < styleRules.length; i++) { let rule = styleRules[i]; if (matchesSelector(elem, rule.selector)) { for (let key in rule.css) { if (!(specificities[key] > rule.selector.specificity)) { result[key] = rule.css[key]; specificities[key] = rule.selector.specificity; } } } } return result; } function combineArrays(array1, array2) { return array1.concat(array2.slice(array1.length)); } function getAscent(font, size) { return Math.max(font.ascender, (font.bbox[3] || font.bbox.maxY) * (font.scale || 1)) * size / 1000; } function getDescent(font, size) { return Math.min(font.descender, (font.bbox[1] || font.bbox.minY) * (font.scale || 1)) * size / 1000; } function getXHeight(font, size) { return (font.xHeight || 0.5 * (font.ascender - font.descender)) * size / 1000; } function getBaseline(font, size, baseline, shift) { let dy1, dy2; switch (baseline) { case 'middle': dy1 = 0.5 * getXHeight(font, size); break; case 'central': dy1 = 0.5 * (getDescent(font, size) + getAscent(font, size)); break; case 'after-edge': case 'text-after-edge': dy1 = getDescent(font, size); break; case 'alphabetic': case 'auto': case 'baseline': dy1 = 0; break; case 'mathematical': dy1 = 0.5 * getAscent(font, size); break; case 'hanging': dy1 = 0.8 * getAscent(font, size); break; case 'before-edge': case 'text-before-edge': dy1 = getAscent(font, size); break; default: dy1 = 0; break; } switch (shift) { case 'baseline': dy2 = 0; break; case 'super': dy2 = 0.6 * size; break; case 'sub': dy2 = -0.6 * size; break; default: dy2 = shift; break; } return dy1 - dy2; } function getTextPos(font, size, text) { let encoded = font.encode('' + text), hex = encoded[0], pos = encoded[1], data = []; for (let i = 0; i < hex.length; i++) { let unicode = font.unicode ? font.unicode[parseInt(hex[i], 16)] : [text.charCodeAt(i)]; data.push({ glyph: hex[i], unicode: unicode, width: pos[i].advanceWidth * size / 1000, xOffset: pos[i].xOffset * size / 1000, yOffset: pos[i].yOffset * size / 1000, xAdvance: pos[i].xAdvance * size / 1000, yAdvance: pos[i].yAdvance * size / 1000 }); } return data; } function createSVGElement(obj, inherits) { switch (obj.nodeName) { case 'use': return new SvgElemUse(obj, inherits); case 'symbol': return new SvgElemSymbol(obj, inherits); case 'g': return new SvgElemGroup(obj, inherits); case 'a': return new SvgElemLink(obj, inherits); case 'svg': return new SvgElemSvg(obj, inherits); case 'image': return new SVGElemImage(obj, inherits); case 'rect': return new SvgElemRect(obj, inherits); case 'circle': return new SvgElemCircle(obj, inherits); case 'ellipse': return new SvgElemEllipse(obj, inherits); case 'line': return new SvgElemLine(obj, inherits); case 'polyline': return new SvgElemPolyline(obj, inherits); case 'polygon': return new SvgElemPolygon(obj, inherits); case 'path': return new SvgElemPath(obj, inherits); case 'text': return new SvgElemText(obj, inherits); case 'tspan': return new SvgElemTspan(obj, inherits); case 'textPath': return new SvgElemTextPath(obj, inherits); case '#text': case '#cdata-section': return new SvgElemTextNode(obj, inherits); default: return new SvgElem(obj, inherits); } } var StringParser = function (str) { this.match = function (exp, all) { let temp = str.match(exp); if (!temp || temp.index !== 0) { return; } str = str.substring(temp[0].length); return all ? temp : temp[0]; }; this.matchSeparator = function () { return this.match(/^(?:\s*,\s*|\s*|)/); }; this.matchSpace = function () { return this.match(/^(?:\s*)/); }; this.matchLengthUnit = function () { return this.match(/^(?:px|pt|cm|mm|in|pc|em|ex|%|)/); }; this.matchNumber = function () { return this.match(/^(?:[-+]?(?:[0-9]+[.][0-9]+|[0-9]+[.]|[.][0-9]+|[0-9]+)(?:[eE][-+]?[0-9]+)?)/); }; this.matchAll = function () { return this.match(/^[\s\S]+/); }; }; var BezierSegment = function (p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y) { let divisions = 6 * precision; let equationX = [p1x, -3 * p1x + 3 * c1x, 3 * p1x - 6 * c1x + 3 * c2x, -p1x + 3 * c1x - 3 * c2x + p2x]; let equationY = [p1y, -3 * p1y + 3 * c1y, 3 * p1y - 6 * c1y + 3 * c2y, -p1y + 3 * c1y - 3 * c2y + p2y]; let derivativeX = [-3 * p1x + 3 * c1x, 6 * p1x - 12 * c1x + 6 * c2x, -3 * p1x + 9 * c1x - 9 * c2x + 3 * p2x]; let derivativeY = [-3 * p1y + 3 * c1y, 6 * p1y - 12 * c1y + 6 * c2y, -3 * p1y + 9 * c1y - 9 * c2y + 3 * p2y]; let lengthMap = [0]; for (let i = 1; i <= divisions; i++) { let t = (i - 0.5) / divisions; let dx = getCurveValue(t, derivativeX) / divisions, dy = getCurveValue(t, derivativeY) / divisions, l = Math.sqrt(dx * dx + dy * dy); lengthMap[i] = lengthMap[i - 1] + l; } this.totalLength = lengthMap[divisions]; this.startPoint = [p1x, p1y, isEqual(p1x, c1x) && isEqual(p1y, c1y) ? Math.atan2(c2y - c1y, c2x - c1x) : Math.atan2(c1y - p1y, c1x - p1x)]; this.endPoint = [p2x, p2y, isEqual(c2x, p2x) && isEqual(c2y, p2y) ? Math.atan2(c2y - c1y, c2x - c1x) : Math.atan2(p2y - c2y, p2x - c2x)]; this.getBoundingBox = function () { let temp; let minX = getCurveValue(0, equationX), minY = getCurveValue(0, equationY), maxX = getCurveValue(1, equationX), maxY = getCurveValue(1, equationY); if (minX > maxX) { temp = maxX; maxX = minX; minX = temp; } if (minY > maxY) { temp = maxY; maxY = minY; minY = temp; } let rootsX = solveEquation(derivativeX); for (let i = 0; i < rootsX.length; i++) { if (rootsX[i] >= 0 && rootsX[i] <= 1) { let x = getCurveValue(rootsX[i], equationX); if (x < minX) { minX = x; } if (x > maxX) { maxX = x; } } } let rootsY = solveEquation(derivativeY); for (let i = 0; i < rootsY.length; i++) { if (rootsY[i] >= 0 && rootsY[i] <= 1) { let y = getCurveValue(rootsY[i], equationY); if (y < minY) { minY = y; } if (y > maxY) { maxY = y; } } } return [minX, minY, maxX, maxY]; }; this.getPointAtLength = function (l) { if (isEqual(l, 0)) { return this.startPoint; } if (isEqual(l, this.totalLength)) { return this.endPoint; } if (l < 0 || l > this.totalLength) { return; } for (let i = 1; i <= divisions; i++) { let l1 = lengthMap[i - 1], l2 = lengthMap[i]; if (l1 <= l && l <= l2) { let t = (i - (l2 - l) / (l2 - l1)) / divisions, x = getCurveValue(t, equationX), y = getCurveValue(t, equationY), dx = getCurveValue(t, derivativeX), dy = getCurveValue(t, derivativeY); return [x, y, Math.atan2(dy, dx)]; } } }; }; var LineSegment = function (p1x, p1y, p2x, p2y) { this.totalLength = Math.sqrt((p2x - p1x) * (p2x - p1x) + (p2y - p1y) * (p2y - p1y)); this.startPoint = [p1x, p1y, Math.atan2(p2y - p1y, p2x - p1x)]; this.endPoint = [p2x, p2y, Math.atan2(p2y - p1y, p2x - p1x)]; this.getBoundingBox = function () { return [Math.min(this.startPoint[0], this.endPoint[0]), Math.min(this.startPoint[1], this.endPoint[1]), Math.max(this.startPoint[0], this.endPoint[0]), Math.max(this.startPoint[1], this.endPoint[1])]; }; this.getPointAtLength = function (l) { if (l >= 0 && l <= this.totalLength) { let r = l / this.totalLength || 0, x = this.startPoint[0] + r * (this.endPoint[0] - this.startPoint[0]), y = this.startPoint[1] + r * (this.endPoint[1] - this.startPoint[1]); return [x, y, this.startPoint[2]]; } }; }; var SvgShape = function () { this.pathCommands = []; this.pathSegments = []; this.startPoint = null; this.endPoint = null; this.totalLength = 0; let startX = 0, startY = 0, currX = 0, currY = 0, lastCom, lastCtrlX, lastCtrlY; this.move = function (x, y) { startX = currX = x; startY = currY = y; return null; }; this.line = function (x, y) { let segment = new LineSegment(currX, currY, x, y); currX = x; currY = y; return segment; }; this.curve = function (c1x, c1y, c2x, c2y, x, y) { let segment = new BezierSegment(currX, currY, c1x, c1y, c2x, c2y, x, y); currX = x; currY = y; return segment; }; this.close = function () { let segment = new LineSegment(currX, currY, startX, startY); currX = startX; currY = startY; return segment; }; this.addCommand = function (data) { this.pathCommands.push(data); let segment = this[data[0]].apply(this, data.slice(3)); if (segment) { segment.hasStart = data[1]; segment.hasEnd = data[2]; this.startPoint = this.startPoint || segment.startPoint; this.endPoint = segment.endPoint; this.pathSegments.push(segment); this.totalLength += segment.totalLength; } }; this.M = function (x, y) { this.addCommand(['move', true, true, x, y]); lastCom = 'M'; return this; }; this.m = function (x, y) { return this.M(currX + x, currY + y); }; this.Z = this.z = function () { this.addCommand(['close', true, true]); lastCom = 'Z'; return this; }; this.L = function (x, y) { this.addCommand(['line', true, true, x, y]); lastCom = 'L'; return this; }; this.l = function (x, y) { return this.L(currX + x, currY + y); }; this.H = function (x) { return this.L(x, currY); }; this.h = function (x) { return this.L(currX + x, currY); }; this.V = function (y) { return this.L(currX, y); }; this.v = function (y) { return this.L(currX, currY + y); }; this.C = function (c1x, c1y, c2x, c2y, x, y) { this.addCommand(['curve', true, true, c1x, c1y, c2x, c2y, x, y]); lastCom = 'C'; lastCtrlX = c2x; lastCtrlY = c2y; return this; }; this.c = function (c1x, c1y, c2x, c2y, x, y) { return this.C(currX + c1x, currY + c1y, currX + c2x, currY + c2y, currX + x, currY + y); }; this.S = function (c1x, c1y, x, y) { return this.C(currX + (lastCom === 'C' ? currX - lastCtrlX : 0), currY + (lastCom === 'C' ? currY - lastCtrlY : 0), c1x, c1y, x, y); }; this.s = function (c1x, c1y, x, y) { return this.C(currX + (lastCom === 'C' ? currX - lastCtrlX : 0), currY + (lastCom === 'C' ? currY - lastCtrlY : 0), currX + c1x, currY + c1y, currX + x, currY + y); }; this.Q = function (cx, cy, x, y) { let c1x = currX + 2 / 3 * (cx - currX), c1y = currY + 2 / 3 * (cy - currY), c2x = x + 2 / 3 * (cx - x), c2y = y + 2 / 3 * (cy - y); this.addCommand(['curve', true, true, c1x, c1y, c2x, c2y, x, y]); lastCom = 'Q'; lastCtrlX = cx; lastCtrlY = cy; return this; }; this.q = function (c1x, c1y, x, y) { return this.Q(currX + c1x, currY + c1y, currX + x, currY + y); }; this.T = function (x, y) { return this.Q(currX + (lastCom === 'Q' ? currX - lastCtrlX : 0), currY + (lastCom === 'Q' ? currY - lastCtrlY : 0), x, y); }; this.t = function (x, y) { return this.Q(currX + (lastCom === 'Q' ? currX - lastCtrlX : 0), currY + (lastCom === 'Q' ? currY - lastCtrlY : 0), currX + x, currY + y); }; this.A = function (rx, ry, fi, fa, fs, x, y) { if (isEqual(rx, 0) || isEqual(ry, 0)) { this.addCommand(['line', true, true, x, y]); } else { fi = fi * (Math.PI / 180); rx = Math.abs(rx); ry = Math.abs(ry); fa = 1 * !!fa; fs = 1 * !!fs; let x1 = Math.cos(fi) * (currX - x) / 2 + Math.sin(fi) * (currY - y) / 2, y1 = Math.cos(fi) * (currY - y) / 2 - Math.sin(fi) * (currX - x) / 2, lambda = x1 * x1 / (rx * rx) + y1 * y1 / (ry * ry); if (lambda > 1) { rx *= Math.sqrt(lambda); ry *= Math.sqrt(lambda); } let r = Math.sqrt(Math.max(0, rx * rx * ry * ry - rx * rx * y1 * y1 - ry * ry * x1 * x1) / (rx * rx * y1 * y1 + ry * ry * x1 * x1)), x2 = (fa === fs ? -1 : 1) * r * rx * y1 / ry, y2 = (fa === fs ? 1 : -1) * r * ry * x1 / rx; let cx = Math.cos(fi) * x2 - Math.sin(fi) * y2 + (currX + x) / 2, cy = Math.sin(fi) * x2 + Math.cos(fi) * y2 + (currY + y) / 2, th1 = Math.atan2((y1 - y2) / ry, (x1 - x2) / rx), th2 = Math.atan2((-y1 - y2) / ry, (-x1 - x2) / rx); if (fs === 0 && th2 - th1 > 0) { th2 -= 2 * Math.PI; } else if (fs === 1 && th2 - th1 < 0) { th2 += 2 * Math.PI; } let segms = Math.ceil(Math.abs(th2 - th1) / (Math.PI / precision)); for (let i = 0; i < segms