Skip to content

Commit

Permalink
Clone and render canvas content correctly
Browse files Browse the repository at this point in the history
  • Loading branch information
niklasvh committed Sep 27, 2014
1 parent 3f3424e commit f517a35
Show file tree
Hide file tree
Showing 4 changed files with 66 additions and 4 deletions.
33 changes: 32 additions & 1 deletion dist/html2canvas.js
Expand Up @@ -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 || {};
Expand Down Expand Up @@ -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");

Expand All @@ -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();
Expand All @@ -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") {
Expand Down Expand Up @@ -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":
Expand Down
4 changes: 2 additions & 2 deletions dist/html2canvas.min.js

Large diffs are not rendered by default.

30 changes: 29 additions & 1 deletion src/core.js
@@ -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 || {};
Expand Down Expand Up @@ -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");

Expand All @@ -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();
Expand All @@ -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") {
Expand Down
3 changes: 3 additions & 0 deletions src/nodeparser.js
Expand Up @@ -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":
Expand Down

0 comments on commit f517a35

Please sign in to comment.