Clone and render canvas content correctly

This commit is contained in:
Niklas von Hertzen 2014-09-27 18:00:14 +03:00
parent 3f3424e49c
commit f517a35781
4 changed files with 66 additions and 4 deletions

33
dist/html2canvas.js vendored
View File

@ -567,6 +567,8 @@ if (typeof(Object.create) !== "function" || typeof(document.createElement("canva
}(this));
var html2canvasNodeAttribute = "data-html2canvas-node";
var html2canvasCanvasCloneAttribute = "data-html2canvas-canvas-clone";
var html2canvasCanvasCloneIndex = 0;
window.html2canvas = function(nodeList, options) {
options = options || {};
@ -654,6 +656,7 @@ function smallImage() {
}
function createWindowClone(ownerDocument, containerDocument, width, height, options) {
labelCanvasElements(ownerDocument);
var documentElement = ownerDocument.documentElement.cloneNode(true),
container = containerDocument.createElement("iframe");
@ -671,7 +674,10 @@ function createWindowClone(ownerDocument, containerDocument, width, height, opti
if window url is about:blank, we can assign the url to current by writing onto the document
*/
container.contentWindow.onload = container.onload = function() {
resolve(container);
setTimeout(function() {
cloneCanvasContents(ownerDocument, documentClone);
resolve(container);
}, 0);
};
documentClone.open();
@ -685,6 +691,28 @@ function createWindowClone(ownerDocument, containerDocument, width, height, opti
});
}
function labelCanvasElements(ownerDocument) {
[].slice.call(ownerDocument.querySelectorAll("canvas"), 0).forEach(function(canvas) {
canvas.setAttribute(html2canvasCanvasCloneAttribute, "canvas-" + html2canvasCanvasCloneIndex++);
});
}
function cloneCanvasContents(ownerDocument, documentClone) {
[].slice.call(ownerDocument.querySelectorAll("[" + html2canvasCanvasCloneAttribute + "]"), 0).forEach(function(canvas) {
try {
var clonedCanvas = documentClone.querySelector('[' + html2canvasCanvasCloneAttribute + '="' + canvas.getAttribute(html2canvasCanvasCloneAttribute) + '"]');
if (clonedCanvas) {
clonedCanvas.width = canvas.width;
clonedCanvas.height = canvas.height;
clonedCanvas.getContext("2d").putImageData(canvas.getContext("2d").getImageData(0, 0, canvas.width, canvas.height), 0, 0);
}
} catch(e) {
log("Unable to copy canvas content from", canvas, e);
}
canvas.removeAttribute(html2canvasCanvasCloneAttribute);
});
}
function removeScriptNodes(parent) {
[].slice.call(parent.childNodes, 0).filter(isElementNode).forEach(function(node) {
if (node.tagName === "SCRIPT") {
@ -1726,6 +1754,9 @@ NodeParser.prototype.paintNode = function(container) {
log("Error loading <img>", container.node.src);
}
break;
case "CANVAS":
this.renderer.renderImage(container, bounds, container.borders, {image: container.node});
break;
case "SELECT":
case "INPUT":
case "TEXTAREA":

File diff suppressed because one or more lines are too long

View File

@ -1,4 +1,6 @@
var html2canvasNodeAttribute = "data-html2canvas-node";
var html2canvasCanvasCloneAttribute = "data-html2canvas-canvas-clone";
var html2canvasCanvasCloneIndex = 0;
window.html2canvas = function(nodeList, options) {
options = options || {};
@ -86,6 +88,7 @@ function smallImage() {
}
function createWindowClone(ownerDocument, containerDocument, width, height, options) {
labelCanvasElements(ownerDocument);
var documentElement = ownerDocument.documentElement.cloneNode(true),
container = containerDocument.createElement("iframe");
@ -103,7 +106,10 @@ function createWindowClone(ownerDocument, containerDocument, width, height, opti
if window url is about:blank, we can assign the url to current by writing onto the document
*/
container.contentWindow.onload = container.onload = function() {
resolve(container);
setTimeout(function() {
cloneCanvasContents(ownerDocument, documentClone);
resolve(container);
}, 0);
};
documentClone.open();
@ -117,6 +123,28 @@ function createWindowClone(ownerDocument, containerDocument, width, height, opti
});
}
function labelCanvasElements(ownerDocument) {
[].slice.call(ownerDocument.querySelectorAll("canvas"), 0).forEach(function(canvas) {
canvas.setAttribute(html2canvasCanvasCloneAttribute, "canvas-" + html2canvasCanvasCloneIndex++);
});
}
function cloneCanvasContents(ownerDocument, documentClone) {
[].slice.call(ownerDocument.querySelectorAll("[" + html2canvasCanvasCloneAttribute + "]"), 0).forEach(function(canvas) {
try {
var clonedCanvas = documentClone.querySelector('[' + html2canvasCanvasCloneAttribute + '="' + canvas.getAttribute(html2canvasCanvasCloneAttribute) + '"]');
if (clonedCanvas) {
clonedCanvas.width = canvas.width;
clonedCanvas.height = canvas.height;
clonedCanvas.getContext("2d").putImageData(canvas.getContext("2d").getImageData(0, 0, canvas.width, canvas.height), 0, 0);
}
} catch(e) {
log("Unable to copy canvas content from", canvas, e);
}
canvas.removeAttribute(html2canvasCanvasCloneAttribute);
});
}
function removeScriptNodes(parent) {
[].slice.call(parent.childNodes, 0).filter(isElementNode).forEach(function(node) {
if (node.tagName === "SCRIPT") {

View File

@ -294,6 +294,9 @@ NodeParser.prototype.paintNode = function(container) {
log("Error loading <img>", container.node.src);
}
break;
case "CANVAS":
this.renderer.renderImage(container, bounds, container.borders, {image: container.node});
break;
case "SELECT":
case "INPUT":
case "TEXTAREA":