將DOM內容HTML繪製到畫布中是有可能的但如何有把握地, 並且安全地實現它,就應該按照規範行事。你不能把HTML畫到canvas上。相反,你需要使用一個SVG圖像,其中包含你想要呈現的內容。可以使用<foreignobject> 元素包含HTML內容,之後把這個svg繪製到你的canvas中。
唯一真正棘手的事情可能是創建SVG圖像,所有你需要做的是創建一個包含XML字符串的SVG,然後按照下面的步驟構造一個Blob
blob對象的媒體類型mime爲 “image/svg+xml”.
<svg> 元素.
在svg元素中包含 <foreignobject> 元素.
(格式化好的) HTML ,被包裹到<foreignobject>中.
如上所述通過使用一個object URL,我們可以內聯HTML而不是從外部源加載它。當然,如果你喜歡你可以使用外部源,只要域與原始文件相同,比如:
<!DOCTYPE html>
<html>
<body>
<p><canvas id="canvas"style="border:2px solid black;" width="200"height="200"></canvas>
<script>
var canvas =document.getElementById("canvas");
var ctx =canvas.getContext("2d");
var data = "<svgxmlns='http://www.w3.org/2000/svg' width='200' height='200'>" +
"<foreignObject width='100%' height='100%'>" +
"<divxmlns='http://www.w3.org/1999/xhtml' style='font-size:40px'>" +
"<em>I</em>like <span style='color:white; text-shadow:0 0 2pxblue;'>cheese</span>" +
"</div>" +
"</foreignObject>" +
"</svg>";
var DOMURL = self.URL || self.webkitURL ||self;
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;
</script>
</body>
</html>
data變量設置了SVG圖像的內容(這包括HTML)我們希望繪製到我們的canvas中。通過調用 newImage()我們建立一個新的html <img> 元素,添加數據進去,指定一個object URL, 之後在圖片onload的時候調用 drawImage() 來把圖片繪製到畫布中.
您可能想知道這種方式是否安全,擔心canvas會讀取敏感數據。答案是這樣的:這個解決方案的實現依賴的SVG圖像是非常嚴格的。SVG圖像不允許加載任何外部資源,即使似乎來自同一個域。資源(如柵格圖像(如JPEG圖像)或<iframe>s 需要用 data: URIs來內聯引入。
此外,你不能在一個SVG圖像中引入腳本文件,所以沒有從其他腳本訪問DOM的風險,而且DOM元素在SVG圖像中不能接收事件的輸入,所以沒有辦法通過把隱私信息加載到一個表單控件(如一個文件的完整路徑 <input> 元素)然後渲染出來,之後通過讀取像素把這些信息取出。
訪問過的鏈接風格並不應用於SVG圖像中呈現的鏈接,所以歷史信息也不能被檢索,本地的主題也不呈現在SVG圖像中,這使得它很難確定用戶的平臺。
生成的canvas元素是純淨的,意味着你可以通過調用 toBlob(function(blob){…})來返回canvas的blob ,或者toDataURL()來返回 Base64-編碼的 data: URI。
SVG必須是合法的XML,你需要解析並把HTML轉爲規範的符合格式的。下面的代碼可以很方便的解析HTML
var doc =document.implementation.createHTMLDocument("");
doc.write(html);
// You must manually set the xmlns if youintend to immediately serialize the HTML
// document to a string as opposed toappending it to a <foreignObject> in the DOM
doc.documentElement.setAttribute("xmlns",doc.documentElement.namespaceURI);
// Get well-formed markup
html = (newXMLSerializer).serializeToString(doc);