image_creator.js 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728
  1. /**
  2. * DevExtreme (exporter/image_creator.js)
  3. * Version: 19.1.16
  4. * Build date: Tue Oct 18 2022
  5. *
  6. * Copyright (c) 2012 - 2022 Developer Express Inc. ALL RIGHTS RESERVED
  7. * Read about DevExtreme licensing here: https://js.devexpress.com/Licensing/
  8. */
  9. "use strict";
  10. var _renderer = require("../core/renderer");
  11. var _renderer2 = _interopRequireDefault(_renderer);
  12. var _color = require("../color");
  13. var _color2 = _interopRequireDefault(_color);
  14. var _type = require("../core/utils/type");
  15. var _svg = require("../core/utils/svg");
  16. var _svg2 = _interopRequireDefault(_svg);
  17. var _iterator = require("../core/utils/iterator");
  18. var _extend = require("../core/utils/extend");
  19. var _dom_adapter = require("../core/dom_adapter");
  20. var _dom_adapter2 = _interopRequireDefault(_dom_adapter);
  21. var _dom = require("../core/utils/dom");
  22. var _dom2 = _interopRequireDefault(_dom);
  23. var _window = require("../core/utils/window");
  24. var _window2 = _interopRequireDefault(_window);
  25. var _inflector = require("../core/utils/inflector");
  26. var _deferred = require("../core/utils/deferred");
  27. function _interopRequireDefault(obj) {
  28. return obj && obj.__esModule ? obj : {
  29. "default": obj
  30. }
  31. }
  32. var window = _window2.default.getWindow();
  33. var _math = Math;
  34. var PI = _math.PI;
  35. var _min = _math.min;
  36. var _abs = _math.abs;
  37. var _sqrt = _math.sqrt;
  38. var _pow = _math.pow;
  39. var _atan2 = _math.atan2;
  40. var _cos = _math.cos;
  41. var _sin = _math.sin;
  42. var _number = Number;
  43. var IMAGE_QUALITY = 1;
  44. var TEXT_DECORATION_LINE_WIDTH_COEFF = .05;
  45. var DEFAULT_FONT_SIZE = "10px";
  46. var DEFAULT_FONT_FAMILY = "sans-serif";
  47. var DEFAULT_TEXT_COLOR = "#000";
  48. function createCanvas(width, height, margin) {
  49. var canvas = (0, _renderer2.default)("<canvas>")[0];
  50. canvas.width = width + 2 * margin;
  51. canvas.height = height + 2 * margin;
  52. canvas.hidden = true;
  53. return canvas
  54. }
  55. function getStringFromCanvas(canvas, mimeType) {
  56. var dataURL = canvas.toDataURL(mimeType, IMAGE_QUALITY);
  57. var imageData = window.atob(dataURL.substring(("data:" + mimeType + ";base64,").length));
  58. return imageData
  59. }
  60. function arcTo(x1, y1, x2, y2, radius, largeArcFlag, clockwise, context) {
  61. var cBx = (x1 + x2) / 2;
  62. var cBy = (y1 + y2) / 2;
  63. var aB = _atan2(y1 - y2, x1 - x2);
  64. var k = largeArcFlag ? 1 : -1;
  65. aB += 90 * (PI / 180) * (clockwise ? 1 : -1);
  66. var opSide = _sqrt(_pow(x2 - x1, 2) + _pow(y2 - y1, 2)) / 2;
  67. var adjSide = _sqrt(_abs(_pow(radius, 2) - _pow(opSide, 2)));
  68. var centerX = cBx + k * (adjSide * _cos(aB));
  69. var centerY = cBy + k * (adjSide * _sin(aB));
  70. var startAngle = _atan2(y1 - centerY, x1 - centerX);
  71. var endAngle = _atan2(y2 - centerY, x2 - centerX);
  72. context.arc(centerX, centerY, radius, startAngle, endAngle, !clockwise)
  73. }
  74. function getElementOptions(element, rootAppended) {
  75. var attr = parseAttributes(element.attributes || {});
  76. var options = (0, _extend.extend)({}, attr, {
  77. text: element.textContent.replace(/\s+/g, " "),
  78. textAlign: "middle" === attr["text-anchor"] ? "center" : attr["text-anchor"]
  79. });
  80. var transform = attr.transform;
  81. var coords;
  82. if (transform) {
  83. coords = transform.match(/translate\(-*\d+([.]\d+)*(,*\s*-*\d+([.]\d+)*)*/);
  84. if (coords) {
  85. coords = coords[0].match(/-*\d+([.]\d+)*/g);
  86. options.translateX = _number(coords[0]);
  87. options.translateY = coords[1] ? _number(coords[1]) : 0
  88. }
  89. coords = transform.match(/rotate\(-*\d+([.]\d+)*(,*\s*-*\d+([.]\d+)*,*\s*-*\d+([.]\d+)*)*/);
  90. if (coords) {
  91. coords = coords[0].match(/-*\d+([.]\d+)*/g);
  92. options.rotationAngle = _number(coords[0]);
  93. options.rotationX = coords[1] && _number(coords[1]);
  94. options.rotationY = coords[2] && _number(coords[2])
  95. }
  96. coords = transform.match(/scale\(-*\d+([.]\d+)*(,*\s*-*\d+([.]\d+)*)*/);
  97. if (coords) {
  98. coords = coords[0].match(/-*\d+([.]\d+)*/g);
  99. options.scaleX = _number(coords[0]);
  100. if (coords.length > 1) {
  101. options.scaleY = _number(coords[1])
  102. } else {
  103. options.scaleY = options.scaleX
  104. }
  105. }
  106. }
  107. parseStyles(element, options, rootAppended);
  108. return options
  109. }
  110. function drawRect(context, options) {
  111. var x = options.x;
  112. var y = options.y;
  113. var width = options.width;
  114. var height = options.height;
  115. var cornerRadius = options.rx;
  116. if (!cornerRadius) {
  117. context.rect(x, y, width, height)
  118. } else {
  119. cornerRadius = _min(cornerRadius, width / 2, height / 2);
  120. context.save();
  121. context.translate(x, y);
  122. context.moveTo(width / 2, 0);
  123. context.arcTo(width, 0, width, height, cornerRadius);
  124. context.arcTo(width, height, 0, height, cornerRadius);
  125. context.arcTo(0, height, 0, 0, cornerRadius);
  126. context.arcTo(0, 0, cornerRadius, 0, cornerRadius);
  127. context.lineTo(width / 2, 0);
  128. context.restore()
  129. }
  130. }
  131. function drawImage(context, options, shared) {
  132. var d = new _deferred.Deferred;
  133. var image = new window.Image;
  134. image.onload = function() {
  135. context.save();
  136. context.globalAlpha = options.globalAlpha;
  137. transformElement(context, options);
  138. clipElement(context, options, shared);
  139. context.drawImage(image, options.x, options.y, options.width, options.height);
  140. context.restore();
  141. d.resolve()
  142. };
  143. image.onerror = function() {
  144. d.resolve()
  145. };
  146. image.setAttribute("crossOrigin", "anonymous");
  147. image.src = options.href || options["xlink:href"];
  148. return d
  149. }
  150. function drawPath(context, dAttr) {
  151. var dArray = dAttr.replace(/,/g, " ").split(/([A-Z])/i).filter(function(item) {
  152. return "" !== item.trim()
  153. });
  154. var i = 0;
  155. var prevParams;
  156. var prevParamsLen;
  157. do {
  158. var params = (dArray[i + 1] || "").trim().split(" ");
  159. switch (dArray[i]) {
  160. case "M":
  161. context.moveTo(_number(params[0]), _number(params[1]));
  162. i += 2;
  163. break;
  164. case "L":
  165. for (var j = 0; j < params.length / 2; j++) {
  166. context.lineTo(_number(params[2 * j]), _number(params[2 * j + 1]))
  167. }
  168. i += 2;
  169. break;
  170. case "C":
  171. context.bezierCurveTo(_number(params[0]), _number(params[1]), _number(params[2]), _number(params[3]), _number(params[4]), _number(params[5]));
  172. i += 2;
  173. break;
  174. case "a":
  175. prevParams = dArray[i - 1].trim().split(" ");
  176. prevParamsLen = prevParams.length - 1;
  177. arcTo(_number(prevParams[prevParamsLen - 1]), _number(prevParams[prevParamsLen]), _number(prevParams[prevParamsLen - 1]) + _number(params[5]), _number(prevParams[prevParamsLen]) + _number(params[6]), _number(params[0]), _number(params[3]), _number(params[4]), context);
  178. i += 2;
  179. break;
  180. case "A":
  181. prevParams = dArray[i - 1].trim().split(" ");
  182. prevParamsLen = prevParams.length - 1;
  183. arcTo(_number(prevParams[prevParamsLen - 1]), _number(prevParams[prevParamsLen]), _number(params[5]), _number(params[6]), _number(params[0]), _number(params[3]), _number(params[4]), context);
  184. i += 2;
  185. break;
  186. case "Z":
  187. context.closePath();
  188. i += 1
  189. }
  190. } while (i < dArray.length)
  191. }
  192. function parseStyles(element, options, rootAppended) {
  193. var style = element.style || {};
  194. var field;
  195. for (field in style) {
  196. if ("" !== style[field]) {
  197. options[(0, _inflector.camelize)(field)] = style[field]
  198. }
  199. }
  200. if (rootAppended && _dom_adapter2.default.isElementNode(element)) {
  201. style = window.getComputedStyle(element);
  202. ["fill", "stroke", "stroke-width", "font-family", "font-size", "font-style", "font-weight"].forEach(function(prop) {
  203. if (prop in style && "" !== style[prop]) {
  204. options[(0, _inflector.camelize)(prop)] = style[prop]
  205. }
  206. });
  207. ["opacity", "fill-opacity", "stroke-opacity"].forEach(function(prop) {
  208. if (prop in style && "" !== style[prop] && "1" !== style[prop]) {
  209. options[prop] = _number(style[prop])
  210. }
  211. })
  212. }
  213. options.textDecoration = options.textDecoration || options.textDecorationLine;
  214. options.globalAlpha = (0, _type.isDefined)(options.opacity) ? options.opacity : options.globalAlpha
  215. }
  216. function parseUrl(urlString) {
  217. var matches = urlString && urlString.match(/url\(.*#(.*?)["']?\)/i);
  218. return matches && matches[1]
  219. }
  220. function setFontStyle(context, options) {
  221. var fontParams = [];
  222. options.fontSize = options.fontSize || DEFAULT_FONT_SIZE;
  223. options.fontFamily || DEFAULT_FONT_FAMILY;
  224. options.fill = options.fill || DEFAULT_TEXT_COLOR;
  225. options.fontStyle && fontParams.push(options.fontStyle);
  226. options.fontWeight && fontParams.push(options.fontWeight);
  227. fontParams.push(options.fontSize);
  228. fontParams.push(options.fontFamily);
  229. context.font = fontParams.join(" ");
  230. context.textAlign = options.textAlign;
  231. context.fillStyle = options.fill;
  232. context.globalAlpha = options.globalAlpha
  233. }
  234. function drawText(context, options, shared) {
  235. setFontStyle(context, options);
  236. applyFilter(context, options, shared);
  237. options.text && context.fillText(options.text, options.x || 0, options.y || 0);
  238. strokeElement(context, options, true);
  239. drawTextDecoration(context, options, shared)
  240. }
  241. function drawTextDecoration(context, options, shared) {
  242. if (!options.textDecoration || "none" === options.textDecoration) {
  243. return
  244. }
  245. var x = options.x;
  246. var textWidth = context.measureText(options.text).width;
  247. var textHeight = parseInt(options.fontSize, 10);
  248. var lineHeight = textHeight * TEXT_DECORATION_LINE_WIDTH_COEFF < 1 ? 1 : textHeight * TEXT_DECORATION_LINE_WIDTH_COEFF;
  249. var y = options.y;
  250. switch (options.textDecoration) {
  251. case "line-through":
  252. y -= textHeight / 3 + lineHeight / 2;
  253. break;
  254. case "overline":
  255. y -= textHeight - lineHeight;
  256. break;
  257. case "underline":
  258. y += lineHeight
  259. }
  260. context.rect(x, y, textWidth, lineHeight);
  261. fillElement(context, options, shared);
  262. strokeElement(context, options)
  263. }
  264. function aggregateOpacity(options) {
  265. options.strokeOpacity = void 0 !== options["stroke-opacity"] ? options["stroke-opacity"] : 1;
  266. options.fillOpacity = void 0 !== options["fill-opacity"] ? options["fill-opacity"] : 1;
  267. if (void 0 !== options.opacity) {
  268. options.strokeOpacity *= options.opacity;
  269. options.fillOpacity *= options.opacity
  270. }
  271. }
  272. function hasTspan(element) {
  273. var nodes = element.childNodes;
  274. for (var i = 0; i < nodes.length; i++) {
  275. if ("tspan" === nodes[i].tagName) {
  276. return true
  277. }
  278. }
  279. return false
  280. }
  281. function drawTextElement(childNodes, context, options, shared) {
  282. var lines = [];
  283. var line;
  284. var offset = 0;
  285. for (var i = 0; i < childNodes.length; i++) {
  286. var element = childNodes[i];
  287. if (void 0 === element.tagName) {
  288. drawElement(element, context, options, shared)
  289. } else {
  290. if ("tspan" === element.tagName || "text" === element.tagName) {
  291. var elementOptions = getElementOptions(element, shared.rootAppended);
  292. var mergedOptions = (0, _extend.extend)({}, options, elementOptions);
  293. if ("tspan" === element.tagName && hasTspan(element)) {
  294. drawTextElement(element.childNodes, context, mergedOptions, shared);
  295. continue
  296. }
  297. mergedOptions.textAlign = "start";
  298. if (!line || void 0 !== elementOptions.x) {
  299. line = {
  300. elements: [],
  301. options: [],
  302. widths: [],
  303. offsets: []
  304. };
  305. lines.push(line)
  306. }
  307. if (void 0 !== elementOptions.y) {
  308. offset = 0
  309. }
  310. if (void 0 !== elementOptions.dy) {
  311. offset += parseFloat(elementOptions.dy)
  312. }
  313. line.elements.push(element);
  314. line.options.push(mergedOptions);
  315. line.offsets.push(offset);
  316. setFontStyle(context, mergedOptions);
  317. line.widths.push(context.measureText(mergedOptions.text).width)
  318. }
  319. }
  320. }
  321. lines.forEach(function(line) {
  322. var commonWidth = line.widths.reduce(function(commonWidth, width) {
  323. return commonWidth + width
  324. }, 0);
  325. var xDiff = 0;
  326. var currentOffset = 0;
  327. if ("center" === options.textAlign) {
  328. xDiff = commonWidth / 2
  329. }
  330. if ("end" === options.textAlign) {
  331. xDiff = commonWidth
  332. }
  333. line.options.forEach(function(o, index) {
  334. var width = line.widths[index];
  335. o.x = o.x - xDiff + currentOffset;
  336. o.y += line.offsets[index];
  337. currentOffset += width
  338. });
  339. line.elements.forEach(function(element, index) {
  340. drawTextElement(element.childNodes, context, line.options[index], shared)
  341. })
  342. })
  343. }
  344. function drawElement(element, context, parentOptions, shared) {
  345. var tagName = element.tagName;
  346. var isText = "text" === tagName || "tspan" === tagName || void 0 === tagName;
  347. var isImage = "image" === tagName;
  348. var options = (0, _extend.extend)({}, parentOptions, getElementOptions(element, shared.rootAppended));
  349. if ("hidden" === options.visibility || options["hidden-for-export"]) {
  350. return
  351. }
  352. context.save();
  353. !isImage && transformElement(context, options);
  354. clipElement(context, options, shared);
  355. aggregateOpacity(options);
  356. var promise;
  357. context.beginPath();
  358. switch (element.tagName) {
  359. case void 0:
  360. drawText(context, options, shared);
  361. break;
  362. case "text":
  363. case "tspan":
  364. drawTextElement(element.childNodes, context, options, shared);
  365. break;
  366. case "image":
  367. promise = drawImage(context, options, shared);
  368. break;
  369. case "path":
  370. drawPath(context, options.d);
  371. break;
  372. case "rect":
  373. drawRect(context, options);
  374. context.closePath();
  375. break;
  376. case "circle":
  377. context.arc(options.cx, options.cy, options.r, 0, 2 * PI, 1)
  378. }
  379. if (!isText) {
  380. applyFilter(context, options, shared);
  381. fillElement(context, options, shared);
  382. strokeElement(context, options)
  383. }
  384. applyGradient(context, options, shared, element);
  385. context.restore();
  386. return promise
  387. }
  388. function applyGradient(context, options, _ref, element) {
  389. var gradients = _ref.gradients;
  390. if (0 === gradients.length) {
  391. return
  392. }
  393. var id = parseUrl(options.fill);
  394. if (id && gradients[id]) {
  395. var box = element.getBBox();
  396. var gradient = context.createLinearGradient(box.x, 0, box.x + box.width, 0);
  397. gradients[id].forEach(function(opt) {
  398. var offset = parseInt(opt.offset.replace(/%/, ""));
  399. gradient.addColorStop(offset / 100, opt.stopColor)
  400. });
  401. context.globalAlpha = options.opacity;
  402. context.fillStyle = gradient;
  403. context.fill()
  404. }
  405. }
  406. function applyFilter(context, options, shared) {
  407. var filterOptions;
  408. var id = parseUrl(options.filter);
  409. if (id) {
  410. filterOptions = shared.filters[id];
  411. if (!filterOptions) {
  412. filterOptions = {
  413. offsetX: 0,
  414. offsetY: 0,
  415. blur: 0,
  416. color: "#000"
  417. }
  418. }
  419. context.shadowOffsetX = filterOptions.offsetX;
  420. context.shadowOffsetY = filterOptions.offsetY;
  421. context.shadowColor = filterOptions.color;
  422. context.shadowBlur = filterOptions.blur
  423. }
  424. }
  425. function transformElement(context, options) {
  426. context.translate(options.translateX || 0, options.translateY || 0);
  427. options.translateX = void 0;
  428. options.translateY = void 0;
  429. if (options.rotationAngle) {
  430. context.translate(options.rotationX || 0, options.rotationY || 0);
  431. context.rotate(options.rotationAngle * PI / 180);
  432. context.translate(-(options.rotationX || 0), -(options.rotationY || 0));
  433. options.rotationAngle = void 0;
  434. options.rotationX = void 0;
  435. options.rotationY = void 0
  436. }
  437. if (isFinite(options.scaleX)) {
  438. context.scale(options.scaleX, options.scaleY);
  439. options.scaleX = void 0;
  440. options.scaleY = void 0
  441. }
  442. }
  443. function clipElement(context, options, shared) {
  444. if (options["clip-path"]) {
  445. drawElement(shared.clipPaths[parseUrl(options["clip-path"])], context, {}, shared);
  446. context.clip();
  447. options["clip-path"] = void 0
  448. }
  449. }
  450. function hex2rgba(hexColor, alpha) {
  451. var color = new _color2.default(hexColor);
  452. return "rgba(" + color.r + "," + color.g + "," + color.b + "," + alpha + ")"
  453. }
  454. function createGradient(element) {
  455. var options = [];
  456. (0, _iterator.each)(element.childNodes, function(_, _ref2) {
  457. var attributes = _ref2.attributes;
  458. options.push({
  459. offset: attributes.offset.value,
  460. stopColor: attributes["stop-color"].value
  461. })
  462. });
  463. return options
  464. }
  465. function createFilter(element) {
  466. var color;
  467. var filterOptions = {};
  468. (0, _iterator.each)(element.childNodes, function(_, node) {
  469. var attr = node.attributes;
  470. if (!attr.result) {
  471. return
  472. }
  473. switch (attr.result.value) {
  474. case "gaussianBlurResult":
  475. filterOptions.blur = _number(attr.stdDeviation.value);
  476. break;
  477. case "offsetResult":
  478. filterOptions.offsetX = _number(attr.dx.value);
  479. filterOptions.offsetY = _number(attr.dy.value);
  480. break;
  481. case "floodResult":
  482. color = attr["flood-color"] ? attr["flood-color"].value : "#000";
  483. var opacity = attr["flood-opacity"] ? attr["flood-opacity"].value : 1;
  484. filterOptions.color = hex2rgba(color, opacity)
  485. }
  486. });
  487. return filterOptions
  488. }
  489. function asyncEach(array, callback) {
  490. var d = arguments.length > 2 && void 0 !== arguments[2] ? arguments[2] : new _deferred.Deferred;
  491. if (0 === array.length) {
  492. return d.resolve()
  493. }
  494. var result = callback(array[0]);
  495. function next() {
  496. asyncEach(Array.prototype.slice.call(array, 1), callback, d)
  497. }
  498. if ((0, _type.isPromise)(result)) {
  499. result.then(next)
  500. } else {
  501. next()
  502. }
  503. return d
  504. }
  505. function drawCanvasElements(elements, context, parentOptions, shared) {
  506. return asyncEach(elements, function(element) {
  507. switch (element.tagName && element.tagName.toLowerCase()) {
  508. case "g":
  509. case "svg":
  510. var options = (0, _extend.extend)({}, parentOptions, getElementOptions(element, shared.rootAppended));
  511. context.save();
  512. transformElement(context, options);
  513. clipElement(context, options, shared);
  514. var onDone = function() {
  515. context.restore()
  516. };
  517. var d = drawCanvasElements(element.childNodes, context, options, shared);
  518. if ((0, _type.isPromise)(d)) {
  519. d.then(onDone)
  520. } else {
  521. onDone()
  522. }
  523. return d;
  524. case "defs":
  525. return drawCanvasElements(element.childNodes, context, {}, shared);
  526. case "clippath":
  527. shared.clipPaths[element.attributes.id.textContent] = element.childNodes[0];
  528. break;
  529. case "pattern":
  530. shared.patterns[element.attributes.id.textContent] = element;
  531. break;
  532. case "filter":
  533. shared.filters[element.id] = createFilter(element);
  534. break;
  535. case "lineargradient":
  536. shared.gradients[element.attributes.id.textContent] = createGradient(element);
  537. break;
  538. default:
  539. return drawElement(element, context, parentOptions, shared)
  540. }
  541. })
  542. }
  543. function setLineDash(context, options) {
  544. var matches = options["stroke-dasharray"] && options["stroke-dasharray"].match(/(\d+)/g);
  545. if (matches && matches.length) {
  546. matches = (0, _iterator.map)(matches, function(item) {
  547. return _number(item)
  548. });
  549. context.setLineDash(matches)
  550. }
  551. }
  552. function strokeElement(context, options, isText) {
  553. var stroke = options.stroke;
  554. if (stroke && "none" !== stroke && 0 !== options["stroke-width"]) {
  555. setLineDash(context, options);
  556. context.lineJoin = options["stroke-linejoin"];
  557. context.lineWidth = options["stroke-width"];
  558. context.globalAlpha = options.strokeOpacity;
  559. context.strokeStyle = stroke;
  560. isText ? context.strokeText(options.text, options.x, options.y) : context.stroke();
  561. context.globalAlpha = 1
  562. }
  563. }
  564. function getPattern(context, pattern, shared) {
  565. var options = getElementOptions(pattern, shared.rootAppended);
  566. var patternCanvas = createCanvas(options.width, options.height, 0);
  567. var patternContext = patternCanvas.getContext("2d");
  568. drawCanvasElements(pattern.childNodes, patternContext, options, shared);
  569. return context.createPattern(patternCanvas, "repeat")
  570. }
  571. function fillElement(context, options, shared) {
  572. var fill = options.fill;
  573. if (fill && "none" !== fill) {
  574. if (fill.search(/url/) === -1) {
  575. context.fillStyle = fill
  576. } else {
  577. var pattern = shared.patterns[parseUrl(fill)];
  578. if (!pattern) {
  579. return
  580. }
  581. context.fillStyle = getPattern(context, pattern, shared)
  582. }
  583. context.globalAlpha = options.fillOpacity;
  584. context.fill();
  585. context.globalAlpha = 1
  586. }
  587. }
  588. var parseAttributes = function(attributes) {
  589. var newAttributes = {};
  590. var attr;
  591. (0, _iterator.each)(attributes, function(index, item) {
  592. attr = item.textContent;
  593. if (isFinite(attr)) {
  594. attr = _number(attr)
  595. }
  596. newAttributes[item.name.toLowerCase()] = attr
  597. });
  598. return newAttributes
  599. };
  600. function drawBackground(context, width, height, backgroundColor, margin) {
  601. context.fillStyle = backgroundColor || "#ffffff";
  602. context.fillRect(-margin, -margin, width + 2 * margin, height + 2 * margin)
  603. }
  604. function createInvisibleDiv() {
  605. var invisibleDiv = _dom_adapter2.default.createElement("div");
  606. invisibleDiv.style.left = "-9999px";
  607. invisibleDiv.style.position = "absolute";
  608. return invisibleDiv
  609. }
  610. function getCanvasFromSvg(markup, width, height, backgroundColor, margin) {
  611. var canvas = createCanvas(width, height, margin);
  612. var context = canvas.getContext("2d");
  613. var svgElem = _svg2.default.getSvgElement(markup);
  614. var invisibleDiv;
  615. var markupIsDomElement = _dom_adapter2.default.isElementNode(markup);
  616. context.translate(margin, margin);
  617. _dom_adapter2.default.getBody().appendChild(canvas);
  618. if (!markupIsDomElement) {
  619. invisibleDiv = createInvisibleDiv();
  620. invisibleDiv.appendChild(svgElem);
  621. _dom_adapter2.default.getBody().appendChild(invisibleDiv)
  622. }
  623. if (svgElem.attributes.direction) {
  624. canvas.dir = svgElem.attributes.direction.textContent
  625. }
  626. drawBackground(context, width, height, backgroundColor, margin);
  627. return drawCanvasElements(svgElem.childNodes, context, {}, {
  628. clipPaths: {},
  629. patterns: {},
  630. filters: {},
  631. gradients: {},
  632. rootAppended: markupIsDomElement && _dom2.default.contains(_dom_adapter2.default.getBody(), markup)
  633. }).then(function() {
  634. invisibleDiv && _dom_adapter2.default.getBody().removeChild(invisibleDiv);
  635. _dom_adapter2.default.getBody().removeChild(canvas);
  636. return canvas
  637. })
  638. }
  639. exports.imageCreator = {
  640. getImageData: function(markup, options) {
  641. var mimeType = "image/" + options.format;
  642. var width = options.width;
  643. var height = options.height;
  644. var backgroundColor = options.backgroundColor;
  645. if ((0, _type.isFunction)(options.__parseAttributesFn)) {
  646. parseAttributes = options.__parseAttributesFn
  647. }
  648. var deferred = new _deferred.Deferred;
  649. getCanvasFromSvg(markup, width, height, backgroundColor, options.margin).then(function(canvas) {
  650. deferred.resolve(getStringFromCanvas(canvas, mimeType))
  651. });
  652. return deferred
  653. },
  654. getData: function(markup, options) {
  655. var that = this;
  656. var deferred = new _deferred.Deferred;
  657. exports.imageCreator.getImageData(markup, options).then(function(binaryData) {
  658. var mimeType = "image/" + options.format;
  659. var data = (0, _type.isFunction)(window.Blob) && !options.forceProxy ? that._getBlob(binaryData, mimeType) : that._getBase64(binaryData);
  660. deferred.resolve(data)
  661. });
  662. return deferred
  663. },
  664. _getBlob: function(binaryData, mimeType) {
  665. var dataArray = new Uint8Array(binaryData.length);
  666. for (var i = 0; i < binaryData.length; i++) {
  667. dataArray[i] = binaryData.charCodeAt(i)
  668. }
  669. return new window.Blob([dataArray.buffer], {
  670. type: mimeType
  671. })
  672. },
  673. _getBase64: function(binaryData) {
  674. return window.btoa(binaryData)
  675. }
  676. };
  677. exports.getData = function(data, options, callback) {
  678. return exports.imageCreator.getData(data, options).then(callback)
  679. };
  680. exports.testFormats = function(formats) {
  681. var canvas = createCanvas(100, 100, 0);
  682. return formats.reduce(function(r, f) {
  683. var mimeType = ("image/" + f).toLowerCase();
  684. if (canvas.toDataURL(mimeType).indexOf(mimeType) !== -1) {
  685. r.supported.push(f)
  686. } else {
  687. r.unsupported.push(f)
  688. }
  689. return r
  690. }, {
  691. supported: [],
  692. unsupported: []
  693. })
  694. };