【问题标题】:How can I convert an HTML element to a canvas element?如何将 HTML 元素转换为画布元素?
【发布时间】:2011-02-13 12:28:17
【问题描述】:

能够将常规元素临时转换为canvas 将非常有用。例如,假设我有一个想要翻转的样式 div。我想动态创建一个画布,将HTMLElement“渲染”到画布中,隐藏原始元素并对画布进行动画处理。

可以吗?

【问题讨论】:

    标签: html canvas


    【解决方案1】:

    MDN 上查看本教程:https://developer.mozilla.org/en/HTML/Canvas/Drawing_DOM_objects_into_a_canvas (archived)

    它的关键技巧是:

    var canvas = document.getElementById('canvas');
    var ctx = canvas.getContext('2d');
    
    var data = '<svg xmlns="http://www.w3.org/2000/svg" width="200" height="200">' +
               '<foreignObject width="100%" height="100%">' +
               '<div xmlns="http://www.w3.org/1999/xhtml" style="font-size:40px">' +
                 '<em>I</em> like ' + 
                 '<span style="color:white; text-shadow:0 0 2px blue;">' +
                 'cheese</span>' +
               '</div>' +
               '</foreignObject>' +
               '</svg>';
    
    var DOMURL = window.URL || window.webkitURL || window;
    
    var img = new Image();
    var svg = new Blob([data], {type: 'image/svg+xml;charset=utf-8'});
    var url = DOMURL.createObjectURL(svg);
    
    img.onload = function () {
      ctx.drawImage(img, 0, 0);
      DOMURL.revokeObjectURL(url);
    }
    
    img.src = url;
    

    也就是说,它使用临时 SVG 图像HTML 内容作为“外来元素”包含在内,然后将所述 SVG 图像渲染到画布元素中。但是,以这种方式可以在 SVG 图像中包含的内容有很大的限制。 (有关详细信息,请参阅“安全性”部分 - 由于隐私和跨域问题,基本上它比 iframe 或 AJAX 受到更多限制。)

    【讨论】:

    • 这应该是公认的答案。帮助我将我的 API 写到 DOM 到画布(然后再写到图像)!
    • 感谢您的回答。所有浏览器都支持吗?
    • 备用链接不再有效
    • @darryn.ten 谢谢,有人添加了一个链接,指向原始内容的一个有点可疑的镜像,现在它似乎也移动了。有类似的“实时” URL,但我认为此时最好仅引用原始内容的 Archive.org 版本,我已经为此清理了我的答案。
    【解决方案2】:

    接下来的代码可以使用2种模式,模式1将html代码保存到图片,模式2将html代码保存到画布。

    此代码适用于库:https://github.com/tsayen/dom-to-image

    *“id_div”是要转换的元素html的id。

    **“canvas_out”是包含画布的 div 的 id 所以试试这段代码。 :

       function Guardardiv(id_div){
    
          var mode = 2 // default 1 (save to image), mode 2 = save to canvas
          console.log("Process start");
          var node = document.getElementById(id_div);
          // get the div that will contain the canvas
          var canvas_out = document.getElementById('canvas_out');
          var canvas = document.createElement('canvas');
          canvas.width = node.scrollWidth;
          canvas.height = node.scrollHeight;
    
          domtoimage.toPng(node).then(function (pngDataUrl) {
              var img = new Image();
              img.onload = function () {
              var context = canvas.getContext('2d');
              context.drawImage(img, 0, 0);
            };
    
            if (mode == 1){ // save to image
                 downloadURI(pngDataUrl, "salida.png");
            }else if (mode == 2){ // save to canvas
              img.src = pngDataUrl;
              canvas_out.appendChild(img);
    
            }
          console.log("Process finish");
        });
    
        }
    

    所以,如果你想保存到图像只需添加这个功能:

        function downloadURI(uri, name) {
            var link = document.createElement("a");
    
            link.download = name;
            link.href = uri;
            document.body.appendChild(link);
            link.click();   
        }
    

    使用示例:

     <html>
     <head>
     </script src="/dom-to-image.js"></script>
     </head> 
     <body>
     <div id="container">
       All content that want to transform
      </div>
      <button onclick="Guardardiv('container');">Convert<button> 
    
     <!-- if use mode 2 -->
     <div id="canvas_out"></div>
     </html>
    

    评论是否可行。 评论 si les sirvio :)

    【讨论】:

    • 我无法在 IE 上使用它。我尝试使用 ES6 承诺的 polyfill,但这也不起作用
    【解决方案3】:

    您可以使用dom-to-image 库(我是维护者)。
    以下是解决问题的方法:

    var parent = document.getElementById('my-node-parent');
    var node = document.getElementById('my-node');
    
    var canvas = document.createElement('canvas');
    canvas.width = node.scrollWidth;
    canvas.height = node.scrollHeight;
    
    domtoimage.toPng(node).then(function (pngDataUrl) {
        var img = new Image();
        img.onload = function () {
            var context = canvas.getContext('2d');
    
            context.translate(canvas.width, 0);
            context.scale(-1, 1);
            context.drawImage(img, 0, 0);
    
            parent.removeChild(node);
            parent.appendChild(canvas);
        };
    
        img.src = pngDataUrl;
    });
    

    And here is jsfiddle

    【讨论】:

    • 感谢这个库。 !!通过在 HTML 中添加

      ...

      对您的 jsfiddle 进行了小改动。现在,产量正在减少。请找到新的 jsfiddle [链接]jsfiddle.net/2zLL7wvn 我做错了什么吗?请帮忙。谢谢,
    • @junkle 似乎是因为 h1 标签周围的边距,可以通过设置高度、移除边距或将边距转换为填充来修复
    【解决方案4】:

    您可以省去转换,您可以使用CSS3 Transitions 翻转&lt;div&gt;&lt;ol&gt; 以及您想要的任何HTML 标记。下面是一些带有源代码解释的demo,可以看看和学习:http://www.webdesignerwall.com/trends/47-amazing-css3-animation-demos/

    【讨论】:

    • 我相信你的意思是好的,但是很多人,像我一样,通过特定的谷歌查询来解决这些问题,并且有人告诉我做一些不同的事情而不是我要求的事情是没有帮助。将样式化的 HTML 渲染到画布也意味着我可以将该 HTML 上传到 WebGL 纹理,并使用转换和着色器对格式化内容进行风格化演示。
    • 嗨@paniq,只是想让您介绍一种实际有效且易于掌握的替代技术。很抱歉打扰了您。
    • 很公平。 Stack Overflow 说,如果正在编辑原始答案,我可以收回我的反对票。所以,如果你这样做,我会收回它。抱歉,有点脾气暴躁。
    • 感谢您的洞察力,我认为想要将 HTML 转换为画布的人想要您发布的示例中可能已经存在的效果。所以我很高兴你在这个帖子中发帖。
    【解决方案5】:
    function convert() {
                        dom = document.getElementById('divname');
                        var script,
                        $this = this,
                        options = this.options,
                        runH2c = function(){
                            try {
                                var canvas =     window.html2canvas([ document.getElementById('divname') ], {
                                    onrendered: function( canvas ) {
    
                                    window.open(canvas.toDataURL());
    
                                    }
                                });
                            } catch( e ) {
                                $this.h2cDone = true;
                                log("Error in html2canvas: " + e.message);
                            }
                        };
    
                        if ( window.html2canvas === undefined && script === undefined ) {
                        } else {.
                            // html2canvas already loaded, just run it then
                            runH2c();
                        }
                    }
    

    【讨论】:

      【解决方案6】:

      为 DOM 元素设置动画最简单的解决方案是使用 CSS 过渡/动画,但我想您已经知道这一点,并且您尝试使用画布来完成 CSS 不允许您做的事情。 CSS custom filters 呢?如果您知道如何编写着色器,则可以以任何可以想象的方式转换您的元素。其他一些link 并且不要忘记检查CSS filter lab
      注意:您可能可以想象浏览器支持不好。

      【讨论】:

        【解决方案7】:

        在 natevw 引用的 Mozdev 帖子的基础上,我开始了一个小项目,在 Firefox、Chrome 和 Safari 中将 HTML 渲染到画布上。因此,例如,您可以简单地这样做:

        rasterizeHTML.drawHTML('<span class="color: green">This is HTML</span>' 
                             + '<img src="local_img.png"/>', canvas);
        

        源代码和更广泛的示例是here

        【讨论】:

          【解决方案8】:

          没有,抱歉。

          虽然规格说明:

          2D 上下文 API 的未来版本可能会提供一种将使用 CSS 渲染的文档片段直接渲染到画布的方法。

          这可能与您将得到的一样接近。

          很多人想要ctx.drawArbitraryHTML/Element 类型的交易,但没有这样的内置功能。

          唯一的例外是 Mozilla 独有的drawWindow,它将 DOM 窗口内容的快照绘制到画布中。此功能仅适用于以 Chrome(“仅限本地”)权限运行的代码。在普通的 HTML 页面中是不允许的。所以你可以用它来编写像 this one does 这样的 FireFox 扩展,仅此而已。

          【讨论】:

            【解决方案9】:

            有一个图书馆会尝试按照你说的去做。

            查看此示例并获取代码

            http://hertzen.com/experiments/jsfeedback/

            http://html2canvas.hertzen.com/

            从 html 读取 DOM 并将其渲染到画布上,在某些情况下会失败,但通常可以。

            【讨论】:

            • 太棒了!!考虑到所有因素,真的非常准确
            【解决方案10】:

            抱歉,浏览器不会将 HTML 渲染到画布中。

            如果可以的话,这将是一个潜在的安全风险,因为 HTML 可以包含来自第三方网站的内容(特别是图像和 iframe)。如果canvas 可以将 HTML 内容转换为图像,然后您读取图像数据,您就有可能从其他站点提取特权内容。

            要从 HTML 中获取画布,您基本上必须使用 drawImagefillText 从头开始​​编写自己的 HTML 渲染器,这可能是一项艰巨的任务。有one such attempt here,但它有点狡猾,距离完成还有很长的路要走。 (它甚至尝试从头开始解析 HTML/CSS,我认为这很疯狂!从应用了样式的真实 DOM 节点开始,并使用 getComputedStyle 和其中部分的相对位置读取样式会更容易使用offsetTop 等)

            【讨论】:

            • 那真是太糟糕了。能够“冻结”一个元素并以某种方式扭曲它,然后能够在以后“解冻”它,那就太好了。我不同意这将是一个 安全风险。这与能够使用 JS 读取 DOM 并窃取该信息没有什么不同(当然,对 JS 的任何沙盒约束都将应用相同的)。感谢您确认我怀疑的答案,bobince。
            • 是的,只是对一般 HTML 内容应用同源限制比跨文档脚本要复杂得多。您必须记录屏幕上包含任何第三方内容的每个矩形,并拒绝与其中任何一个相交的渲染请求 — 图像、iframe、视频/音频、带有背景图像的元素、所有对象/嵌入/applet 是否第三方(因为它们有自己的跨站规则)、SVG 等等。
            • 我不得不在安全问题上持不同意见。如果您可以访问他们的页面,那么您肯定可以访问比从他们页面的 .png 中收集到的更多信息。如果该页面可用,则该页面的屏幕截图不会打开新的安全漏洞!
            • 您可以将某人的页面包含在框架或其他嵌入方式中,而无需任何脚本访问。我可以&lt;iframe src="https://example-online-bank.com/mystatement"&gt; 在我的文档中包含一个目标页面,但我无法通过 DOM 访问该页面的内容,我应该无法通过截屏访问该信息。
            • “要从 HTML 中获取画布,您基本上必须使用 drawImage 和 fillText 从头开始​​编写自己的 HTML 渲染器,这可能是一项艰巨的任务。”但无论如何,请参阅 Aristos 提供的其他答案。它应该是 imo 接受的答案。
            猜你喜欢
            • 2016-11-08
            • 2013-08-03
            • 2011-10-30
            • 2016-08-27
            • 1970-01-01
            • 1970-01-01
            • 2014-05-19
            相关资源
            最近更新 更多