qq15725 / modern-screenshot

📸 Quickly generate image from DOM node using HTML5 canvas and SVG
https://toolpkg.com/html-to-image
MIT License
504 stars 36 forks source link

iled to drawImage DOMException: Failed to execute 'drawImage' on 'CanvasRenderingContext2D': The HTMLImageElement provided is in the 'broken' state. #20

Closed xudesheng closed 1 year ago

xudesheng commented 1 year ago

我把这个嵌入了另外一个App(jquery的),总是无论时下载图片,还是将图片添加到Dom中,都报相同的错误。

Failed to drawImage DOMException: Failed to execute 'drawImage' on 'CanvasRenderingContext2D': The HTMLImageElement provided is in the 'broken' state.

编译后的代码,在这个位置:

function ut(e, t) {
        return p(this, null, function*() {
            const {log: n, timeout: r, drawImageCount: a, drawImageInterval: i} = t;
            n.time("image to canvas");
            const o = yield _(e, {
                timeout: r
            })
              , {canvas: s, context2d: c} = ft(e.ownerDocument, t)
              , l = ()=>{
                try {
                    c == null || c.drawImage(o, 0, 0, s.width, s.height)

源码错误出在image-to-canvas.ts中的第20行:

context2d?.drawImage(loaded, 0, 0, canvas.width, canvas.height)

我的环境:MacOS M1 Ventera 13.3.1 Browser: Chrome, Firefox latest version.错误相同。 我的代码:

window.modernScreenshot.domToPng(runtimeElement).then(dataUrl => {
            const link = document.createElement('a')
            link.download = 'screenshot.png'
            link.href = dataUrl
            link.click()
          })
          .catch(function (error) {
              console.error("modern screenshot:",error);
          });

或者:

window.modernScreenshot.domToPng(document.body).then(function (dataUrl){
             var img = new Image();
             img.src = dataUrl;
             document.body.appendChild(img);
         }).catch(function (error){
             console.error("dom to png error:",error);
         })
qq15725 commented 1 year ago

没有出现一条 Failed image load 的警告吗?多半是包含 <foreign-object> 的 svg 元素转 svg+xml 作为图像后解码异常了

可以尝试使用 window.modernScreenshot.domToForeignObjectSvg 将 dom 转成包含 <foreign-object> 的 svg 元素

function svgToDataUrl(svg: SVGElement) {
  const xhtml = new XMLSerializer()
    .serializeToString(svg)
    // https://www.w3.org/TR/xml/#charsets
    // eslint-disable-next-line no-control-regex
    .replace(/[\u0000-\u0008\u000B\u000C\u000E-\u001F\uD800-\uDFFF\uFFFE\uFFFF]/ug, '')
  return `data:image/svg+xml;charset=utf-8,${ encodeURIComponent(xhtml) }`
}

然后通过这个 svgToDataUrl 把 url 贴出来(数据可能有点大)或者直接 Chrome 点开(svg+xml 浏览器会提示异常)

xudesheng commented 1 year ago
This page contains the following errors:
error on line 9 at column 339: Opening and ending tag mismatch: style line 1 and body
Below is a rendering of the page up to the first error.
mbinedExtensions.20230421_043143.js:68 Not allowed to navigate top frame to data URL: 
window.modernScreenshot.domToForeignObjectSvg(runtimeElement)
            .then(data =>{
                 return svgToDataUrl(data);
             })
            .then(dataUrl => {
                 console.log("svg to url:" + dataUrl);
                 const link = document.createElement('a');
                 link.href = dataUrl;
                 link.click();
             })
            .catch(function (error){
                 console.error("dom to foreign obj:"+error);
             });

这个是新的报错。 url有142k。

xudesheng commented 1 year ago
function svgToDataUrl(svg) {
          const xhtml = new XMLSerializer()
            .serializeToString(svg)
            // https://www.w3.org/TR/xml/#charsets
            // eslint-disable-next-line no-control-regex
            .replace(/[\u0000-\u0008\u000B\u000C\u000E-\u001F\uD800-\uDFFF\uFFFE\uFFFF]/ug, '');
           console.log(xhtml);
          return `data:image/svg+xml;charset=utf-8,${ encodeURIComponent(xhtml) }`
        }

发现生成的xml,不合法。在debug哪里导致的。

qq15725 commented 1 year ago
This page contains the following errors:
error on line 9 at column 339: Opening and ending tag mismatch: style line 1 and body
Below is a rendering of the page up to the first error.

只能根据查看当前 svg+xml 已渲染的片段推断下文那一处异常的

本质还是因为 new XMLSerializer().serializeToString() 序列化的 xml 还不是完全可用的(无解)

看能否提供 data-url 或者 line 9 at column 339 部分上下文的截图

qq15725 commented 1 year ago

image-to-canvas.ts 中

context2d?.drawImage(loaded, 0, 0, canvas.width, canvas.height)

画的就是这个 xml 序列化后的 svg+xml data-uri 所以需要查看 xml 因为什么引发的浏览器解析异常

xudesheng commented 1 year ago

终于将bug找出来了,是我code里面的bug,button里面多了一个“,页面显示正确,也不报错。但就是导致这个转xml出错。多谢。