@mkhuda/dom-screenshot 0.0.2 → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. package/.gitattributes +1 -0
  2. package/EXAMPLES_QUICKSTART.md +240 -0
  3. package/README.md +534 -33
  4. package/TESTING.md +269 -0
  5. package/TESTING_STATUS.md +215 -0
  6. package/TEST_SETUP_SUMMARY.md +335 -0
  7. package/dist/dom-screenshot.d.ts +44 -272
  8. package/dist/dom-screenshot.d.ts.map +1 -0
  9. package/dist/dom-screenshot.esm.js +753 -0
  10. package/dist/dom-screenshot.esm.js.map +1 -0
  11. package/dist/dom-screenshot.min.js +2 -1
  12. package/dist/dom-screenshot.min.js.map +1 -0
  13. package/examples/README.md +211 -0
  14. package/examples/react-app/README.md +161 -0
  15. package/examples/react-app/index.html +12 -0
  16. package/examples/react-app/node_modules/.vite/deps/_metadata.json +46 -0
  17. package/examples/react-app/node_modules/.vite/deps/chunk-FK77NBP6.js +1895 -0
  18. package/examples/react-app/node_modules/.vite/deps/chunk-FK77NBP6.js.map +7 -0
  19. package/examples/react-app/node_modules/.vite/deps/chunk-VSODSHUF.js +21647 -0
  20. package/examples/react-app/node_modules/.vite/deps/chunk-VSODSHUF.js.map +7 -0
  21. package/examples/react-app/node_modules/.vite/deps/package.json +3 -0
  22. package/examples/react-app/node_modules/.vite/deps/react-dom.js +5 -0
  23. package/examples/react-app/node_modules/.vite/deps/react-dom.js.map +7 -0
  24. package/examples/react-app/node_modules/.vite/deps/react-dom_client.js +38 -0
  25. package/examples/react-app/node_modules/.vite/deps/react-dom_client.js.map +7 -0
  26. package/examples/react-app/node_modules/.vite/deps/react.js +4 -0
  27. package/examples/react-app/node_modules/.vite/deps/react.js.map +7 -0
  28. package/examples/react-app/node_modules/.vite/deps/react_jsx-dev-runtime.js +898 -0
  29. package/examples/react-app/node_modules/.vite/deps/react_jsx-dev-runtime.js.map +7 -0
  30. package/examples/react-app/node_modules/.vite/deps/react_jsx-runtime.js +910 -0
  31. package/examples/react-app/node_modules/.vite/deps/react_jsx-runtime.js.map +7 -0
  32. package/examples/react-app/package.json +21 -0
  33. package/examples/react-app/tsconfig.json +25 -0
  34. package/examples/react-app/tsconfig.node.json +10 -0
  35. package/examples/react-app/vite.config.ts +10 -0
  36. package/package.json +75 -43
  37. package/rollup.config.mjs +35 -0
  38. package/tests/README.md +394 -0
  39. package/tests/fixtures/html.ts +192 -0
  40. package/tests/fixtures/images.ts +86 -0
  41. package/tests/fixtures/styles.ts +288 -0
  42. package/tests/helpers/dom-helpers.ts +242 -0
  43. package/tests/mocks/canvas-mock.ts +94 -0
  44. package/tests/mocks/image-mock.ts +147 -0
  45. package/tests/mocks/xhr-mock.ts +202 -0
  46. package/tests/setup.ts +103 -0
  47. package/tests/unit/basic.test.ts +263 -0
  48. package/tests/unit/simple.test.ts +172 -0
  49. package/tsconfig.json +44 -20
  50. package/vitest.config.mts +35 -0
  51. package/rollup.config.js +0 -20
@@ -0,0 +1,753 @@
1
+ /**
2
+ * Default implementation options
3
+ */
4
+ const defaultOptions = {
5
+ imagePlaceholder: undefined,
6
+ cacheBust: false,
7
+ };
8
+ /**
9
+ * Main domtoimage module export
10
+ */
11
+ const domtoimage = {
12
+ toSvg,
13
+ toPng,
14
+ toJpeg,
15
+ toBlob,
16
+ toPixelData,
17
+ impl: {}, // Will be populated after object creation
18
+ };
19
+ // Initialize implementation after domtoimage object exists
20
+ Object.assign(domtoimage.impl, {
21
+ fontFaces: newFontFaces(),
22
+ images: newImages(),
23
+ util: newUtil(),
24
+ inliner: newInliner(),
25
+ options: {},
26
+ });
27
+ /**
28
+ * Render DOM node to SVG data URL
29
+ * @param node - The DOM Node object to render
30
+ * @param options - Rendering options
31
+ * @returns Promise fulfilled with a SVG image data URL
32
+ */
33
+ function toSvg(node, options) {
34
+ options = options || {};
35
+ copyOptions(options);
36
+ return Promise.resolve(node)
37
+ .then((node) => cloneNode(node, options.filter, true))
38
+ .then(embedFonts)
39
+ .then(inlineImages)
40
+ .then(applyOptions)
41
+ .then((clone) => {
42
+ const util = domtoimage.impl.util;
43
+ return makeSvgDataUri(clone, options.width || util.width(clone), options.height || util.height(clone));
44
+ });
45
+ function applyOptions(clone) {
46
+ if (!(clone instanceof Element))
47
+ return clone;
48
+ if (options.bgcolor)
49
+ clone.style.backgroundColor = options.bgcolor;
50
+ if (options.width)
51
+ clone.style.width = options.width + 'px';
52
+ if (options.height)
53
+ clone.style.height = options.height + 'px';
54
+ if (options.style) {
55
+ const styleObj = options.style;
56
+ Object.keys(styleObj).forEach((property) => {
57
+ clone.style[property] = styleObj[property];
58
+ });
59
+ }
60
+ return clone;
61
+ }
62
+ }
63
+ /**
64
+ * Render DOM node to PNG data URL
65
+ * @param node - The DOM Node object to render
66
+ * @param options - Rendering options
67
+ * @returns Promise fulfilled with a PNG image data URL
68
+ */
69
+ function toPng(node, options) {
70
+ return draw(node, options || {}).then((canvas) => {
71
+ return canvas.toDataURL();
72
+ });
73
+ }
74
+ /**
75
+ * Render DOM node to JPEG data URL
76
+ * @param node - The DOM Node object to render
77
+ * @param options - Rendering options
78
+ * @returns Promise fulfilled with a JPEG image data URL
79
+ */
80
+ function toJpeg(node, options) {
81
+ options = options || {};
82
+ return draw(node, options).then((canvas) => {
83
+ return canvas.toDataURL('image/jpeg', options.quality || 1.0);
84
+ });
85
+ }
86
+ /**
87
+ * Render DOM node to Blob
88
+ * @param node - The DOM Node object to render
89
+ * @param options - Rendering options
90
+ * @returns Promise fulfilled with a Blob
91
+ */
92
+ function toBlob(node, options) {
93
+ return draw(node, options || {}).then((canvas) => {
94
+ const util = domtoimage.impl.util;
95
+ return util.canvasToBlob(canvas);
96
+ });
97
+ }
98
+ /**
99
+ * Render DOM node to PixelData
100
+ * @param node - The DOM Node object to render
101
+ * @param options - Rendering options
102
+ * @returns Promise fulfilled with pixel data array
103
+ */
104
+ function toPixelData(node, options) {
105
+ return draw(node, options || {}).then((canvas) => {
106
+ const util = domtoimage.impl.util;
107
+ return canvas
108
+ .getContext('2d')
109
+ .getImageData(0, 0, util.width(node), util.height(node)).data;
110
+ });
111
+ }
112
+ function copyOptions(options) {
113
+ // Copy options to impl options for use in impl
114
+ if (typeof options.imagePlaceholder === 'undefined') {
115
+ domtoimage.impl.options.imagePlaceholder =
116
+ defaultOptions.imagePlaceholder;
117
+ }
118
+ else {
119
+ domtoimage.impl.options.imagePlaceholder = options.imagePlaceholder;
120
+ }
121
+ if (typeof options.cacheBust === 'undefined') {
122
+ domtoimage.impl.options.cacheBust = defaultOptions.cacheBust;
123
+ }
124
+ else {
125
+ domtoimage.impl.options.cacheBust = options.cacheBust;
126
+ }
127
+ }
128
+ function draw(domNode, options) {
129
+ return toSvg(domNode, options)
130
+ .then((svgUri) => {
131
+ const util = domtoimage.impl.util;
132
+ return util.makeImage(svgUri);
133
+ })
134
+ .then((image) => {
135
+ const util = domtoimage.impl.util;
136
+ return util.delay(100)(image);
137
+ })
138
+ .then((image) => {
139
+ const canvas = newCanvas(domNode);
140
+ canvas.getContext('2d').drawImage(image, 0, 0);
141
+ return canvas;
142
+ });
143
+ function newCanvas(domNode) {
144
+ const util = domtoimage.impl.util;
145
+ const canvas = document.createElement('canvas');
146
+ canvas.width = options.width || util.width(domNode);
147
+ canvas.height = options.height || util.height(domNode);
148
+ if (options.bgcolor) {
149
+ const ctx = canvas.getContext('2d');
150
+ ctx.fillStyle = options.bgcolor;
151
+ ctx.fillRect(0, 0, canvas.width, canvas.height);
152
+ }
153
+ return canvas;
154
+ }
155
+ }
156
+ function cloneNode(node, filter, root) {
157
+ if (!root && filter && !filter(node))
158
+ return Promise.resolve(undefined);
159
+ const util = domtoimage.impl.util;
160
+ return Promise.resolve(node)
161
+ .then(makeNodeCopy)
162
+ .then((clone) => cloneChildren(node, clone, filter))
163
+ .then((clone) => processClone(node, clone));
164
+ function makeNodeCopy(node) {
165
+ if (node instanceof HTMLCanvasElement)
166
+ return util.makeImage(node.toDataURL());
167
+ return node.cloneNode(false);
168
+ }
169
+ function cloneChildren(original, clone, filter) {
170
+ if (!clone)
171
+ return Promise.resolve(clone);
172
+ const children = original.childNodes;
173
+ if (children.length === 0)
174
+ return Promise.resolve(clone);
175
+ return cloneChildrenInOrder(clone, util.asArray(children), filter).then(() => clone);
176
+ function cloneChildrenInOrder(parent, children, filter) {
177
+ let done = Promise.resolve();
178
+ children.forEach((child) => {
179
+ done = done
180
+ .then(() => cloneNode(child, filter))
181
+ .then((childClone) => {
182
+ if (childClone)
183
+ parent.appendChild(childClone);
184
+ });
185
+ });
186
+ return done;
187
+ }
188
+ }
189
+ function processClone(original, originalClone) {
190
+ if (!originalClone)
191
+ return Promise.resolve(originalClone);
192
+ if (!(originalClone instanceof Element))
193
+ return Promise.resolve(originalClone);
194
+ const clone = originalClone;
195
+ return Promise.resolve()
196
+ .then(renderVideo)
197
+ .then(cloneStyle)
198
+ .then(clonePseudoElements)
199
+ .then(copyUserInput)
200
+ .then(fixSvg)
201
+ .then(() => {
202
+ return clone;
203
+ });
204
+ function renderVideo() {
205
+ if (!(clone instanceof HTMLVideoElement))
206
+ return;
207
+ const dimensions = window.getComputedStyle(original);
208
+ const canvas = document.createElement('canvas');
209
+ canvas.width = parseInt(dimensions.width, 10);
210
+ canvas.height = parseInt(dimensions.height, 10);
211
+ const ratio = Math.max(original.videoWidth / canvas.width, original.videoHeight / canvas.height);
212
+ const width = original.videoWidth / ratio;
213
+ const height = original.videoHeight / ratio;
214
+ const x = canvas.width / 2 - width / 2;
215
+ const y = canvas.height / 2 - height / 2;
216
+ const ctx = canvas.getContext('2d');
217
+ ctx.drawImage(original, x, y, width, height);
218
+ const newImage = new Image();
219
+ try {
220
+ newImage.src = canvas.toDataURL();
221
+ }
222
+ catch (err) {
223
+ newImage.src =
224
+ 'data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==';
225
+ }
226
+ // Replace video element with image in the cloned tree
227
+ const parentClone = clone.parentNode;
228
+ if (parentClone) {
229
+ parentClone.replaceChild(newImage, clone);
230
+ }
231
+ }
232
+ function cloneStyle() {
233
+ const computedStyle = window.getComputedStyle(original);
234
+ copyStyle(computedStyle, clone.style);
235
+ function copyStyle(source, target) {
236
+ if (source.cssText) {
237
+ target.cssText = source.cssText;
238
+ }
239
+ else {
240
+ copyProperties(source, target);
241
+ }
242
+ function copyProperties(source, target) {
243
+ const util = domtoimage.impl.util;
244
+ util.asArray(source).forEach((name) => {
245
+ target.setProperty(name, source.getPropertyValue(name), source.getPropertyPriority(name));
246
+ });
247
+ }
248
+ }
249
+ }
250
+ function clonePseudoElements() {
251
+ [':before', ':after'].forEach((element) => {
252
+ clonePseudoElement(element);
253
+ });
254
+ function clonePseudoElement(element) {
255
+ const style = window.getComputedStyle(original, element);
256
+ const content = style.getPropertyValue('content');
257
+ if (content === '' || content === 'none')
258
+ return;
259
+ const util = domtoimage.impl.util;
260
+ const className = util.uid();
261
+ clone.className = clone.className + ' ' + className;
262
+ const styleElement = document.createElement('style');
263
+ styleElement.appendChild(formatPseudoElementStyle(className, element, style));
264
+ clone.appendChild(styleElement);
265
+ function formatPseudoElementStyle(className, element, style) {
266
+ const selector = '.' + className + ':' + element;
267
+ const cssText = style.cssText
268
+ ? formatCssText(style)
269
+ : formatCssProperties(style);
270
+ return document.createTextNode(selector + '{' + cssText + '}');
271
+ function formatCssText(style) {
272
+ const content = style.getPropertyValue('content');
273
+ return style.cssText + ' content: ' + content + ';';
274
+ }
275
+ function formatCssProperties(style) {
276
+ const util = domtoimage.impl.util;
277
+ return (util
278
+ .asArray(style)
279
+ .map((name) => formatProperty(name))
280
+ .join('; ') + ';');
281
+ function formatProperty(name) {
282
+ return (name +
283
+ ': ' +
284
+ style.getPropertyValue(name) +
285
+ (style.getPropertyPriority(name) ? ' !important' : ''));
286
+ }
287
+ }
288
+ }
289
+ }
290
+ }
291
+ function copyUserInput() {
292
+ if (original instanceof HTMLTextAreaElement)
293
+ clone.innerHTML = original.value;
294
+ if (original instanceof HTMLInputElement)
295
+ clone.setAttribute('value', original.value);
296
+ }
297
+ function fixSvg() {
298
+ if (!(clone instanceof SVGElement))
299
+ return;
300
+ clone.setAttribute('xmlns', 'http://www.w3.org/2000/svg');
301
+ if (!(clone instanceof SVGRectElement))
302
+ return;
303
+ ['width', 'height'].forEach((attribute) => {
304
+ const value = clone.getAttribute(attribute);
305
+ if (!value)
306
+ return;
307
+ clone.style.setProperty(attribute, value);
308
+ });
309
+ }
310
+ }
311
+ }
312
+ function embedFonts(node) {
313
+ const fontFaces = domtoimage.impl.fontFaces;
314
+ return fontFaces.resolveAll().then((cssText) => {
315
+ const styleNode = document.createElement('style');
316
+ node.appendChild(styleNode);
317
+ styleNode.appendChild(document.createTextNode(cssText));
318
+ return node;
319
+ });
320
+ }
321
+ function inlineImages(node) {
322
+ const images = domtoimage.impl.images;
323
+ return images.inlineAll(node).then(() => node);
324
+ }
325
+ function makeSvgDataUri(node, width, height) {
326
+ domtoimage.impl.util;
327
+ return Promise.resolve(node)
328
+ .then((node) => {
329
+ node.setAttribute('xmlns', 'http://www.w3.org/1999/xhtml');
330
+ return new XMLSerializer().serializeToString(node);
331
+ })
332
+ .then((xhtml) => {
333
+ return ('<foreignObject x="0" y="0" width="100%" height="100%">' +
334
+ xhtml +
335
+ '</foreignObject>');
336
+ })
337
+ .then((foreignObject) => {
338
+ return ('<svg xmlns="http://www.w3.org/2000/svg" width="' +
339
+ width +
340
+ '" height="' +
341
+ height +
342
+ '">' +
343
+ foreignObject +
344
+ '</svg>');
345
+ })
346
+ .then((svg) => {
347
+ return 'data:image/svg+xml;charset=utf-8,' + encodeURIComponent(svg);
348
+ });
349
+ }
350
+ // ============================================================================
351
+ // UTILITY FUNCTIONS
352
+ // ============================================================================
353
+ function newUtil() {
354
+ const TIMEOUT = 30000;
355
+ return {
356
+ escapeMain,
357
+ parseExtension,
358
+ mimeType,
359
+ dataAsUrl,
360
+ isDataUrl,
361
+ canvasToBlob,
362
+ resolveUrl,
363
+ getAndEncode,
364
+ uid: uid(),
365
+ delay,
366
+ asArray,
367
+ escapeXhtml,
368
+ makeImage,
369
+ width,
370
+ height,
371
+ };
372
+ function mimes() {
373
+ const WOFF = 'application/font-woff';
374
+ const JPEG = 'image/jpeg';
375
+ return {
376
+ woff: WOFF,
377
+ woff2: WOFF,
378
+ ttf: 'application/font-truetype',
379
+ eot: 'application/vnd.ms-fontobject',
380
+ png: 'image/png',
381
+ jpg: JPEG,
382
+ jpeg: JPEG,
383
+ gif: 'image/gif',
384
+ tiff: 'image/tiff',
385
+ svg: 'image/svg+xml',
386
+ };
387
+ }
388
+ function parseExtension(url) {
389
+ const match = /\.([^\.\\/]*?)$/g.exec(url);
390
+ if (match)
391
+ return match[1];
392
+ else
393
+ return '';
394
+ }
395
+ function mimeType(url) {
396
+ const extension = parseExtension(url).toLowerCase();
397
+ return mimes()[extension] || '';
398
+ }
399
+ function isDataUrl(url) {
400
+ return url.search(/^(data:)/) !== -1;
401
+ }
402
+ function toBlob(canvas) {
403
+ return new Promise((resolve) => {
404
+ const binaryString = window.atob(canvas.toDataURL().split(',')[1]);
405
+ const length = binaryString.length;
406
+ const binaryArray = new Uint8Array(length);
407
+ for (let i = 0; i < length; i++)
408
+ binaryArray[i] = binaryString.charCodeAt(i);
409
+ resolve(new Blob([binaryArray], {
410
+ type: 'image/png',
411
+ }));
412
+ });
413
+ }
414
+ function canvasToBlob(canvas) {
415
+ if (canvas.toBlob) {
416
+ return new Promise((resolve) => {
417
+ canvas.toBlob((blob) => {
418
+ resolve(blob);
419
+ });
420
+ });
421
+ }
422
+ return toBlob(canvas);
423
+ }
424
+ function resolveUrl(url, baseUrl) {
425
+ const doc = document.implementation.createHTMLDocument();
426
+ const base = doc.createElement('base');
427
+ doc.head.appendChild(base);
428
+ const a = doc.createElement('a');
429
+ doc.body.appendChild(a);
430
+ base.href = baseUrl;
431
+ a.href = url;
432
+ return a.href;
433
+ }
434
+ function uid() {
435
+ let index = 0;
436
+ return function () {
437
+ return 'u' + fourRandomChars() + index++;
438
+ function fourRandomChars() {
439
+ return (('0000' + ((Math.random() * Math.pow(36, 4)) << 0).toString(36))).slice(-4);
440
+ }
441
+ };
442
+ }
443
+ function makeImage(uri) {
444
+ return new Promise((resolve, reject) => {
445
+ const image = new Image();
446
+ image.onload = () => {
447
+ resolve(image);
448
+ };
449
+ image.onerror = () => {
450
+ reject(new Error(`Failed to load image: ${uri}`));
451
+ };
452
+ image.src = uri;
453
+ });
454
+ }
455
+ function getAndEncode(url) {
456
+ if (domtoimage.impl.options.cacheBust) {
457
+ url +=
458
+ (/\?/.test(url) ? '&' : '?') + new Date().getTime();
459
+ }
460
+ return new Promise((resolve) => {
461
+ const request = new XMLHttpRequest();
462
+ request.onreadystatechange = done;
463
+ request.ontimeout = timeout;
464
+ request.responseType = 'blob';
465
+ request.timeout = TIMEOUT;
466
+ request.open('GET', url, true);
467
+ request.send();
468
+ let placeholder;
469
+ if (domtoimage.impl.options.imagePlaceholder) {
470
+ const split = domtoimage.impl.options.imagePlaceholder.split(/,/);
471
+ if (split && split[1]) {
472
+ placeholder = split[1];
473
+ }
474
+ }
475
+ function done() {
476
+ if (request.readyState !== 4)
477
+ return;
478
+ if (request.status !== 200) {
479
+ if (placeholder) {
480
+ resolve(placeholder);
481
+ }
482
+ else {
483
+ fail('cannot fetch resource: ' + url + ', status: ' + request.status);
484
+ }
485
+ return;
486
+ }
487
+ const encoder = new FileReader();
488
+ encoder.onloadend = () => {
489
+ const content = encoder.result.split(/,/)[1];
490
+ resolve(content);
491
+ };
492
+ encoder.readAsDataURL(request.response);
493
+ }
494
+ function timeout() {
495
+ if (placeholder) {
496
+ resolve(placeholder);
497
+ }
498
+ else {
499
+ fail('timeout of ' +
500
+ TIMEOUT +
501
+ 'ms occured while fetching resource: ' +
502
+ url);
503
+ }
504
+ }
505
+ function fail(message) {
506
+ console.error(message);
507
+ resolve('');
508
+ }
509
+ });
510
+ }
511
+ function dataAsUrl(content, type) {
512
+ return 'data:' + type + ';base64,' + content;
513
+ }
514
+ function escapeMain(string) {
515
+ return string.replace(/([.*+?^${}()|[\]\/\\])/g, '\\$1');
516
+ }
517
+ function delay(ms) {
518
+ return (arg) => {
519
+ return new Promise((resolve) => {
520
+ setTimeout(() => {
521
+ resolve(arg);
522
+ }, ms);
523
+ });
524
+ };
525
+ }
526
+ function asArray(arrayLike) {
527
+ const array = [];
528
+ const length = arrayLike.length;
529
+ for (let i = 0; i < length; i++)
530
+ array.push(arrayLike[i]);
531
+ return array;
532
+ }
533
+ function escapeXhtml(string) {
534
+ return string.replace(/#/g, '%23').replace(/\n/g, '%0A');
535
+ }
536
+ function width(node) {
537
+ const leftBorder = px(node, 'border-left-width');
538
+ const rightBorder = px(node, 'border-right-width');
539
+ return node.scrollWidth + leftBorder + rightBorder;
540
+ }
541
+ function height(node) {
542
+ const topBorder = px(node, 'border-top-width');
543
+ const bottomBorder = px(node, 'border-bottom-width');
544
+ return node.scrollHeight + topBorder + bottomBorder;
545
+ }
546
+ function px(node, styleProperty) {
547
+ const value = window
548
+ .getComputedStyle(node)
549
+ .getPropertyValue(styleProperty);
550
+ return parseFloat(value.replace('px', ''));
551
+ }
552
+ }
553
+ // ============================================================================
554
+ // INLINER
555
+ // ============================================================================
556
+ function newInliner() {
557
+ const URL_REGEX = /url\(['"]?([^'"]+?)['"]?\)/g;
558
+ const util = domtoimage.impl.util;
559
+ return {
560
+ inlineAll,
561
+ shouldProcess,
562
+ impl: {
563
+ readUrls,
564
+ inline,
565
+ },
566
+ };
567
+ function shouldProcess(string) {
568
+ return string.search(URL_REGEX) !== -1;
569
+ }
570
+ function readUrls(string) {
571
+ const result = [];
572
+ let match;
573
+ while ((match = URL_REGEX.exec(string)) !== null) {
574
+ result.push(match[1]);
575
+ }
576
+ return result.filter((url) => {
577
+ return !util.isDataUrl(url);
578
+ });
579
+ }
580
+ function inline(string, url, baseUrl, get) {
581
+ return Promise.resolve(url)
582
+ .then((url) => {
583
+ return baseUrl ? util.resolveUrl(url, baseUrl) : url;
584
+ })
585
+ .then((url) => {
586
+ return (get || util.getAndEncode)(url);
587
+ })
588
+ .then((data) => {
589
+ return util.dataAsUrl(data, util.mimeType(url));
590
+ })
591
+ .then((dataUrl) => {
592
+ return string.replace(urlAsRegex(url), '$1' + dataUrl + '$3');
593
+ });
594
+ function urlAsRegex(url) {
595
+ return new RegExp("(url\\(['\"]?)(" + util.escapeMain(url) + ")(['\"]?\\))", 'g');
596
+ }
597
+ }
598
+ function inlineAll(string, baseUrl, get) {
599
+ if (nothingToInline())
600
+ return Promise.resolve(string);
601
+ return Promise.resolve(string)
602
+ .then(() => readUrls(string))
603
+ .then((urls) => {
604
+ let done = Promise.resolve(string);
605
+ urls.forEach((url) => {
606
+ done = done.then((str) => {
607
+ return inline(str, url, baseUrl, get);
608
+ });
609
+ });
610
+ return done;
611
+ });
612
+ function nothingToInline() {
613
+ return !shouldProcess(string);
614
+ }
615
+ }
616
+ }
617
+ // ============================================================================
618
+ // FONT FACES
619
+ // ============================================================================
620
+ function newFontFaces() {
621
+ return {
622
+ resolveAll,
623
+ impl: {
624
+ readAll,
625
+ },
626
+ };
627
+ function resolveAll() {
628
+ return readAll()
629
+ .then((webFonts) => {
630
+ return Promise.all(webFonts.map((webFont) => {
631
+ return webFont.resolve();
632
+ }));
633
+ })
634
+ .then((cssStrings) => {
635
+ return cssStrings.join('\n');
636
+ });
637
+ }
638
+ function readAll() {
639
+ const util = domtoimage.impl.util;
640
+ return Promise.resolve(util.asArray(document.styleSheets))
641
+ .then(getCssRules)
642
+ .then(selectWebFontRules)
643
+ .then((rules) => {
644
+ return rules.map(newWebFont);
645
+ });
646
+ function selectWebFontRules(cssRules) {
647
+ const inliner = domtoimage.impl.inliner;
648
+ return cssRules
649
+ .filter((rule) => {
650
+ return rule.type === CSSRule.FONT_FACE_RULE;
651
+ })
652
+ .filter((rule) => {
653
+ return inliner.shouldProcess(rule.style.getPropertyValue('src'));
654
+ });
655
+ }
656
+ function getCssRules(styleSheets) {
657
+ const cssRules = [];
658
+ const sheetArray = Array.isArray(styleSheets) ? styleSheets : util.asArray(styleSheets);
659
+ sheetArray.forEach((sheet) => {
660
+ try {
661
+ util
662
+ .asArray(sheet.cssRules || [])
663
+ .forEach((rule) => {
664
+ cssRules.push(rule);
665
+ });
666
+ }
667
+ catch (e) {
668
+ console.log('Error while reading CSS rules from ' + sheet.href, e.toString());
669
+ }
670
+ });
671
+ return cssRules;
672
+ }
673
+ function newWebFont(webFontRule) {
674
+ return {
675
+ resolve() {
676
+ const baseUrl = webFontRule.parentStyleSheet?.href;
677
+ const inliner = domtoimage.impl.inliner;
678
+ return inliner.inlineAll(webFontRule.cssText, baseUrl);
679
+ },
680
+ src() {
681
+ return webFontRule.style.getPropertyValue('src');
682
+ },
683
+ };
684
+ }
685
+ }
686
+ }
687
+ // ============================================================================
688
+ // IMAGES
689
+ // ============================================================================
690
+ function newImages() {
691
+ return {
692
+ inlineAll,
693
+ impl: {
694
+ newImage,
695
+ },
696
+ };
697
+ function newImage(element) {
698
+ return {
699
+ inline,
700
+ };
701
+ function inline(get) {
702
+ const util = domtoimage.impl.util;
703
+ if (util.isDataUrl(element.src))
704
+ return Promise.resolve();
705
+ return Promise.resolve(element.src)
706
+ .then((src) => {
707
+ return (get || util.getAndEncode)(src);
708
+ })
709
+ .then((data) => {
710
+ return util.dataAsUrl(data, util.mimeType(element.src));
711
+ })
712
+ .then((dataUrl) => {
713
+ return new Promise((resolve, reject) => {
714
+ element.onload = () => {
715
+ resolve();
716
+ };
717
+ element.onerror = () => {
718
+ reject(new Error(`Failed to load image: ${element.src}`));
719
+ };
720
+ element.src = dataUrl;
721
+ });
722
+ });
723
+ }
724
+ }
725
+ function inlineAll(node) {
726
+ if (!(node instanceof Element))
727
+ return Promise.resolve(node);
728
+ const util = domtoimage.impl.util;
729
+ return inlineBackground(node).then(() => {
730
+ if (node instanceof HTMLImageElement)
731
+ return newImage(node).inline();
732
+ else
733
+ return Promise.all(util.asArray(node.childNodes).map((child) => {
734
+ return inlineAll(child);
735
+ })).then(() => undefined);
736
+ });
737
+ function inlineBackground(node) {
738
+ const background = node.style?.getPropertyValue('background');
739
+ if (!background)
740
+ return Promise.resolve(undefined);
741
+ const inliner = domtoimage.impl.inliner;
742
+ return inliner
743
+ .inlineAll(background)
744
+ .then((inlined) => {
745
+ node.style.setProperty('background', inlined, node.style.getPropertyPriority('background'));
746
+ })
747
+ .then(() => undefined);
748
+ }
749
+ }
750
+ }
751
+
752
+ export { domtoimage, toBlob, toJpeg, toPixelData, toPng, toSvg };
753
+ //# sourceMappingURL=dom-screenshot.esm.js.map