@@ -9,34 +9,46 @@ import { XMLNS } from "./lib";
99 */
1010async function inlineAllImages ( clone ) {
1111 const imgEls = clone . querySelectorAll ( 'img' ) ;
12- const promises = [ ] ;
13- imgEls . forEach ( imgEl => {
14- if ( imgEl . src && ! imgEl . src . startsWith ( 'data:' ) ) {
15- promises . push (
16- new Promise ( resolve => {
17- const image = new window . Image ( ) ;
18- image . crossOrigin = 'anonymous' ; // Try CORS
19- image . onload = function ( ) {
20- try {
21- const canvas = document . createElement ( 'canvas' ) ;
22- canvas . width = image . naturalWidth ;
23- canvas . height = image . naturalHeight ;
24- canvas . getContext ( '2d' ) . drawImage ( image , 0 , 0 ) ;
25- imgEl . src = canvas . toDataURL ( ) ;
26- } catch ( e ) {
27- // it's tainted
28- }
29- resolve ( ) ;
30- } ;
31- image . onerror = function ( ) { resolve ( ) ; } ;
32- image . src = imgEl . src ;
33- } )
34- ) ;
35- }
12+ const promises = Array . from ( imgEls ) . map ( imgEl => {
13+ return new Promise ( resolve => {
14+ if ( ! imgEl . src || imgEl . src . startsWith ( 'data:' ) ) return resolve ( ) ;
15+
16+ if ( imgEl . complete && imgEl . naturalWidth !== 0 ) {
17+ try {
18+ const canvas = document . createElement ( 'canvas' ) ;
19+ canvas . width = imgEl . naturalWidth ;
20+ canvas . height = imgEl . naturalHeight ;
21+ canvas . getContext ( '2d' ) . drawImage ( imgEl , 0 , 0 ) ;
22+ imgEl . src = canvas . toDataURL ( ) ;
23+ } catch ( e ) {
24+ // tainted
25+ }
26+ return resolve ( ) ;
27+ }
28+
29+ const image = new window . Image ( ) ;
30+ image . crossOrigin = 'anonymous' ;
31+ image . onload = function ( ) {
32+ try {
33+ const canvas = document . createElement ( 'canvas' ) ;
34+ canvas . width = image . naturalWidth ;
35+ canvas . height = image . naturalHeight ;
36+ canvas . getContext ( '2d' ) . drawImage ( image , 0 , 0 ) ;
37+ imgEl . src = canvas . toDataURL ( ) ;
38+ } catch ( e ) {
39+ // tainted
40+ }
41+ resolve ( ) ;
42+ } ;
43+ image . onerror = function ( ) { resolve ( ) ; } ;
44+ image . src = imgEl . src ;
45+ } ) ;
3646 } ) ;
47+
3748 await Promise . all ( promises ) ;
3849}
3950
51+
4052/**
4153 * Removes all elements in the given DOM subtree that have the data-dom-to-png-ignore attribute.
4254 * @param {HTMLElement } root - The root of the cloned DOM tree.
@@ -384,6 +396,23 @@ function walkAllAndApply(cloneNode, liveNode) {
384396 }
385397}
386398
399+ function forceInlineImageStyles ( clone , original ) {
400+ const originalImgs = Array . from ( original . querySelectorAll ( 'img' ) ) ;
401+ clone . querySelectorAll ( 'img' ) . forEach ( img => {
402+ const src = img . getAttribute ( 'src' ) ;
403+ const match = originalImgs . find ( oimg => oimg . getAttribute ( 'src' ) === src ) ;
404+ if ( match ) {
405+ const computedStyle = window . getComputedStyle ( match ) ;
406+ let styleString = '' ;
407+ for ( let j = 0 ; j < computedStyle . length ; j ++ ) {
408+ const property = computedStyle [ j ] ;
409+ styleString += `${ property } :${ computedStyle . getPropertyValue ( property ) } ;` ;
410+ }
411+ img . setAttribute ( 'style' , styleString ) ;
412+ }
413+ } ) ;
414+ }
415+
387416/**
388417 * Converts a DOM element (including HTML, SVG, and canvas) into a high-resolution PNG data URL.
389418 *
@@ -446,6 +475,9 @@ async function domToPng({ container, scale = 2 }) {
446475 inlineForeignObjectHTMLComputedStyles ( cloneSvg , liveSvg ) ;
447476 applyAllSvgComputedStylesInline ( cloneSvg ) ;
448477 setFontFamilyOnAllSvgTextElements ( cloneSvg , containerFontFamily ) ;
478+ forceInlineImageStyles ( cloneSvg , liveSvg ) ;
479+
480+ await inlineAllImages ( cloneSvg ) ;
449481
450482 const bbox = liveSvg . getBoundingClientRect ( ) ;
451483 const svgWidth = bbox . width ;
@@ -464,6 +496,7 @@ async function domToPng({ container, scale = 2 }) {
464496 }
465497
466498 applyAllComputedStylesDeep ( clone , container , containerFontFamily ) ;
499+ forceInlineImageStyles ( clone , container ) ;
467500 removeIgnoredElements ( clone ) ;
468501 await inlineAllImages ( clone ) ;
469502
0 commit comments