mozilla
您的搜索结果

    将 DOM 对象绘制到 canvas 中

    前言

    我们推荐您先熟悉 JavaScriptCanvas APIDOM API,这样有助于理解这篇文章。

    如果您还熟悉 SVG 那就更好了。

    DOM 内容(如 HTML)绘制到 canvas 中是可行的,尽管这不常见(出于安全原因)。这篇文章源自 Robert O'Callahan 的博客,讲述如何按照规范安全地实现这个功能。

    概述

    您不能直接把 HTML 画到 canvas 上。您需要使用一个包含您想要呈现内容的 SVG 图像。为了绘制 HTML 内容,您要先使用 <foreignObject> 元素包含 HTML 内容,再将这个 SVG 图像绘制到您的 canvas 中。

    步骤

    夸张地说,这里唯一真正棘手的事情就是创建 SVG 图像。您需要做的所有事情是创建一个包含 XML 字符串的 SVG,然后根据下面的几部分构造一个 Blob

    1. blob 对象的 MIME 应为 "image/svg+xml"。
    2. 一个 <svg> 元素。
    3. 在 SVG 元素中包含的 <foreignObject> 元素。
    4. 包裹到 <foreignObject> 中的(格式化好的) HTML。

    如上所述,通过使用一个 object URL,我们可以内联 HTML 而不是从外部源加载它。当然,只要域与原始文档相同(不跨域),您也可以使用外部源。

    示例

    HTML

    <canvas id="canvas" style="border:2px solid black;" width="200" height="200">
    
    

    JavaScript

    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;

    效果:

    ScreenshotLive sample

    data 变量设置了我们想要绘制到 canvas 上的 SVG 图像的内容(里面包括了想要绘制的 HTML)。

    接下来通过调用 new Image() 我们创建了一个新的 HTML <img> 元素,然后嵌入 data、分配一个 object URL,再在图片载入时通过 drawImage() 把它绘制到画布中。

    安全性

    您可能想知道这是否安全:担心 canvas 会读取到敏感数据。答案是这样的:这个解决方案所依赖的 SVG 图像在实现上是非常严格的。SVG 图像不允许加载任何外部资源,即使看上去来自同一个域。资源如栅格化图像(如 JPEG 图像)或 <iframe> 需要用 data: URIs 来内联引入。

    此外,您也不能在 SVG 图像中各种引入脚本文件,因此不会有从其他脚本文件访问 DOM 的风险。SVG 图像中的 DOM 元素也不能接收事件的输入,因此无法将敏感信息载入到一个表单控件(如将完整路径载入到 file <input> 元素中)渲染再通过读取图像获取这些信息。

    已访问的链接样式(:visited)不会对 SVG 图像中的链接生效,因此无法获取浏览历史;SVG 图像中也不会渲染原生主题,因此借此检测用户的平台也会更困难。

    生成的 canvas 元素是纯净的,您可以通过调用 toBlob(function(blob){…}) 来返回 canvas 的数据块,或者 toDataURL() 来返回 Base64 编码的 data: URI。

    绘制 HTML

    由于 SVG 必须是是有效的 XML,因此您需要解析 HTML 来使它符合格式。下面的代码可以很方便地解析 HTML。

    var doc = document.implementation.createHTMLDocument("");
    doc.write(html);
    
    // You must manually set the xmlns if you intend to immediately serialize 
    // the HTML document to a string as opposed to appending it to a 
    // <foreignObject> in the DOM
    doc.documentElement.setAttribute("xmlns", doc.documentElement.namespaceURI);
    
    // Get well-formed markup
    html = (new XMLSerializer).serializeToString(doc);

    另请参阅

    文档标签和贡献者

    此页面的贡献者有: ziyunfei, chan, jtyjty99999, Breezewish
    最后编辑者: Breezewish,