Conflicts:
	build/html2canvas.min.js
	dist/html2canvas.js
	src/core.js
This commit is contained in:
Scott Pierce 2014-09-04 16:20:49 -05:00
commit 52c669fe5b
16 changed files with 171 additions and 137 deletions

View File

@ -10,6 +10,7 @@
"boss": true,
"eqnull": true,
"browser": true,
"indent": 4,
"globals": {
"jQuery": true
},

View File

@ -25,7 +25,7 @@ module.exports = function(grunt) {
src: [
'src/promise.js', 'src/fallback.js', 'src/**/*.js'
],
dest: 'build/<%= pkg.name %>.js'
dest: 'dist/<%= pkg.name %>.js'
},
options:{
banner: meta.banner + meta.pre,
@ -71,7 +71,7 @@ module.exports = function(grunt) {
uglify: {
dist: {
src: ['<%= concat.dist.dest %>'],
dest: 'build/<%= pkg.name %>.min.js'
dest: 'dist/<%= pkg.name %>.min.js'
},
options: {
banner: meta.banner

View File

@ -1,10 +1,10 @@
{
"name": "html2canvas",
"version": "0.4.1",
"version": "0.5.0-alpha",
"description": "Screenshots with JavaScript",
"main": "build/html2canvas.js",
"main": "dist/html2canvas.js",
"ignore": [
"tests",
".travis.yml"
]
}
}

File diff suppressed because one or more lines are too long

View File

@ -1,5 +1,5 @@
/*
html2canvas 0.5.0-rc1 <http://html2canvas.hertzen.com>
html2canvas 0.5.0-alpha <http://html2canvas.hertzen.com>
Copyright (c) 2014 Niklas von Hertzen
Released under MIT License
@ -47,6 +47,7 @@ window.html2canvas = function(nodeList, options) {
}
options.async = typeof(options.async) === "undefined" ? true : options.async;
options.allowTaint = typeof(options.allowTaint) === "undefined" ? false : options.allowTaint;
options.removeContainer = typeof(options.removeContainer) === "undefined" ? true : options.removeContainer;
var node = ((nodeList === undefined) ? [document.documentElement] : ((nodeList.length) ? nodeList : [nodeList]))[0];
@ -72,7 +73,7 @@ function renderDocument(document, options, windowWidth, windowHeight) {
var bounds = getBounds(node);
var width = options.type === "view" ? Math.min(bounds.width, windowWidth) : documentWidth(clonedWindow.document);
var height = options.type === "view" ? Math.min(bounds.height, windowHeight) : documentHeight(clonedWindow.document);
var renderer = new CanvasRenderer(width, height, imageLoader);
var renderer = new CanvasRenderer(width, height, imageLoader, options);
var parser = new NodeParser(node, renderer, support, imageLoader, options);
return parser.ready.then(function() {
log("Finished rendering");
@ -263,6 +264,7 @@ function ImageContainer(src, cors) {
this.src = src;
this.image = new Image();
var self = this;
this.tainted = null;
this.promise = new Promise(function(resolve, reject) {
self.image.onload = resolve;
self.image.onerror = reject;
@ -1083,7 +1085,7 @@ NodeParser.prototype.paintNode = function(container) {
case "IMG":
var imageContainer = this.images.get(container.node.src);
if (imageContainer) {
this.renderer.renderImage(container, bounds, borderData, imageContainer.image);
this.renderer.renderImage(container, bounds, borderData, imageContainer);
} else {
log("Error loading <img>", container.node.src);
}
@ -1538,13 +1540,14 @@ function ProxyImageContainer(src, proxy) {
var proxyImageCount = 0;
function Renderer(width, height, images) {
function Renderer(width, height, images, options) {
this.width = width;
this.height = height;
this.images = images;
this.options = options;
}
Renderer.prototype.renderImage = function(container, bounds, borderData, image) {
Renderer.prototype.renderImage = function(container, bounds, borderData, imageContainer) {
var paddingLeft = container.cssInt('paddingLeft'),
paddingTop = container.cssInt('paddingTop'),
paddingRight = container.cssInt('paddingRight'),
@ -1552,11 +1555,11 @@ Renderer.prototype.renderImage = function(container, bounds, borderData, image)
borders = borderData.borders;
this.drawImage(
image,
imageContainer,
0,
0,
image.width,
image.height,
imageContainer.image.width,
imageContainer.image.height,
bounds.left + paddingLeft + borders[3].width,
bounds.top + paddingTop + borders[0].width,
bounds.width - (borders[1].width + borders[3].width + paddingLeft + paddingRight),
@ -1649,6 +1652,7 @@ function CanvasRenderer(width, height) {
this.canvas.width = width;
this.canvas.height = height;
this.ctx = this.canvas.getContext("2d");
this.taintCtx = document.createElement("canvas").getContext("2d");
this.ctx.textBaseline = "bottom";
this.variables = {};
log("Initialized CanvasRenderer");
@ -1670,8 +1674,25 @@ CanvasRenderer.prototype.drawShape = function(shape, color) {
this.setFillStyle(color).fill();
};
CanvasRenderer.prototype.drawImage = function(image, sx, sy, sw, sh, dx, dy, dw, dh) {
this.ctx.drawImage(image, sx, sy, sw, sh, dx, dy, dw, dh);
CanvasRenderer.prototype.taints = function(imageContainer) {
if (imageContainer.tainted === null) {
this.taintCtx.drawImage(imageContainer.image, 0, 0);
try {
this.taintCtx.getImageData(0, 0, 1, 1);
imageContainer.tainted = false;
} catch(e) {
this.taintCtx = document.createElement("canvas").getContext("2d");
imageContainer.tainted = true;
}
}
return imageContainer.tainted;
};
CanvasRenderer.prototype.drawImage = function(imageContainer, sx, sy, sw, sh, dx, dy, dw, dh) {
if (!this.taints(imageContainer)) {
this.ctx.drawImage(imageContainer.image, sx, sy, sw, sh, dx, dy, dw, dh);
}
};
CanvasRenderer.prototype.clip = function(shape, callback, context) {

8
dist/html2canvas.min.js vendored Normal file

File diff suppressed because one or more lines are too long

View File

@ -171,7 +171,7 @@
<p style="color: black; font-size: 1em; line-height: 1.3em; clear: both">
This is a nonsensical document, but syntactically valid HTML 4.0. All 100% conformant CSS1 agents should be able to render the document elements above this paragraph <b>indistinguishably</b> (to the pixel) from this reference rendering, (except font rasterization and form widgets). All discrepancies should be traceable to CSS1 implementation shortcomings. Once you have finished evaluating this test, you can return to the <A HREF="sec5526c.htm" style="text-decoration:none">parent page</A>.
</p>
<script type="text/javascript" src="../build/html2canvas.js"></script>
<script type="text/javascript" src="../dist/html2canvas.js"></script>
<script type="text/javascript">
html2canvas(document.body, {
onrendered: function(canvas) {

View File

@ -53,7 +53,7 @@
</div>
</div>
<script type="text/javascript" src="../build/html2canvas.js"></script>
<script type="text/javascript" src="../dist/html2canvas.js"></script>
<script type="text/javascript">
html2canvas(document.body, {
onrendered: function(canvas) {

View File

@ -2,7 +2,7 @@
"title": "html2canvas",
"name": "html2canvas",
"description": "Screenshots with JavaScript",
"version": "0.5.0-rc1",
"version": "0.5.0-alpha",
"author": {
"name": "Niklas von Hertzen",
"email": "niklasvh@gmail.com",
@ -20,7 +20,7 @@
"url": "https://github.com/niklasvh/html2canvas/issues"
},
"devDependencies": {
"baconjs": "0.7.11",
"baconjs": "^0.7.11",
"base64-arraybuffer": ">= 0.1.0",
"grunt": "^0.4.5",
"grunt-contrib-concat": "*",
@ -31,7 +31,7 @@
"grunt-contrib-watch": "~0.5.1",
"lodash": "^2.4.1",
"png-js": ">= 0.1.1",
"wd": "0.2.21"
"wd": "^0.2.21"
},
"scripts": {
"test": "grunt travis --verbose"

View File

@ -8,6 +8,7 @@ window.html2canvas = function(nodeList, options) {
}
options.async = typeof(options.async) === "undefined" ? true : options.async;
options.allowTaint = typeof(options.allowTaint) === "undefined" ? false : options.allowTaint;
options.removeContainer = typeof(options.removeContainer) === "undefined" ? true : options.removeContainer;
var node = ((nodeList === undefined) ? [document.documentElement] : ((nodeList.length) ? nodeList : [nodeList]))[0];
@ -33,7 +34,7 @@ function renderDocument(document, options, windowWidth, windowHeight) {
var bounds = getBounds(node);
var width = options.type === "view" ? Math.min(bounds.width, windowWidth) : documentWidth(clonedWindow.document);
var height = options.type === "view" ? Math.min(bounds.height, windowHeight) : documentHeight(clonedWindow.document);
var renderer = new CanvasRenderer(width, height, imageLoader);
var renderer = new CanvasRenderer(width, height, imageLoader, options);
var parser = new NodeParser(node, renderer, support, imageLoader, options);
return parser.ready.then(function() {
log("Finished rendering");

View File

@ -2,6 +2,7 @@ function ImageContainer(src, cors) {
this.src = src;
this.image = new Image();
var self = this;
this.tainted = null;
this.promise = new Promise(function(resolve, reject) {
self.image.onload = resolve;
self.image.onerror = reject;

View File

@ -254,7 +254,7 @@ NodeParser.prototype.paintNode = function(container) {
case "IMG":
var imageContainer = this.images.get(container.node.src);
if (imageContainer) {
this.renderer.renderImage(container, bounds, borderData, imageContainer.image);
this.renderer.renderImage(container, bounds, borderData, imageContainer);
} else {
log("Error loading <img>", container.node.src);
}

View File

@ -1,10 +1,11 @@
function Renderer(width, height, images) {
function Renderer(width, height, images, options) {
this.width = width;
this.height = height;
this.images = images;
this.options = options;
}
Renderer.prototype.renderImage = function(container, bounds, borderData, image) {
Renderer.prototype.renderImage = function(container, bounds, borderData, imageContainer) {
var paddingLeft = container.cssInt('paddingLeft'),
paddingTop = container.cssInt('paddingTop'),
paddingRight = container.cssInt('paddingRight'),
@ -12,11 +13,11 @@ Renderer.prototype.renderImage = function(container, bounds, borderData, image)
borders = borderData.borders;
this.drawImage(
image,
imageContainer,
0,
0,
image.width,
image.height,
imageContainer.image.width,
imageContainer.image.height,
bounds.left + paddingLeft + borders[3].width,
bounds.top + paddingTop + borders[0].width,
bounds.width - (borders[1].width + borders[3].width + paddingLeft + paddingRight),

View File

@ -4,6 +4,7 @@ function CanvasRenderer(width, height) {
this.canvas.width = width;
this.canvas.height = height;
this.ctx = this.canvas.getContext("2d");
this.taintCtx = document.createElement("canvas").getContext("2d");
this.ctx.textBaseline = "bottom";
this.variables = {};
log("Initialized CanvasRenderer");
@ -25,8 +26,25 @@ CanvasRenderer.prototype.drawShape = function(shape, color) {
this.setFillStyle(color).fill();
};
CanvasRenderer.prototype.drawImage = function(image, sx, sy, sw, sh, dx, dy, dw, dh) {
this.ctx.drawImage(image, sx, sy, sw, sh, dx, dy, dw, dh);
CanvasRenderer.prototype.taints = function(imageContainer) {
if (imageContainer.tainted === null) {
this.taintCtx.drawImage(imageContainer.image, 0, 0);
try {
this.taintCtx.getImageData(0, 0, 1, 1);
imageContainer.tainted = false;
} catch(e) {
this.taintCtx = document.createElement("canvas").getContext("2d");
imageContainer.tainted = true;
}
}
return imageContainer.tainted;
};
CanvasRenderer.prototype.drawImage = function(imageContainer, sx, sy, sw, sh, dx, dy, dw, dh) {
if (!this.taints(imageContainer)) {
this.ctx.drawImage(imageContainer.image, sx, sy, sw, sh, dx, dy, dw, dh);
}
};
CanvasRenderer.prototype.clip = function(shape, callback, context) {

View File

@ -1,86 +0,0 @@
/*
* jQuery helper plugin for examples and tests
*/
(function( $ ){
$.fn.html2canvas = function(options) {
if (options && options.profile && window.console && window.console.profile && window.location.search !== "?selenium2") {
window.console.profile();
}
var date = new Date(),
$message = null,
timeoutTimer = false,
timer = date.getTime();
options = options || {};
var promise = html2canvas(this, options);
promise.catch(function(err) {
console.log("html2canvas threw an error", err);
});
promise.then(function(canvas) {
var $canvas = $(canvas),
finishTime = new Date();
if (options && options.profile && window.console && window.console.profileEnd) {
window.console.profileEnd();
}
$canvas.addClass("html2canvas")
.css({
position: 'absolute',
left: 0,
top: 0
}).appendTo(document.body);
if (window.location.search !== "?selenium") {
$canvas.siblings().toggle();
$(window).click(function(){
$canvas.toggle().siblings().toggle();
throwMessage("Canvas Render " + ($canvas.is(':visible') ? "visible" : "hidden"));
});
throwMessage('Screenshot created in '+ ((finishTime.getTime()-timer)) + " ms<br />",4000);
} else {
$canvas.css('display', 'none');
}
// test if canvas is read-able
try {
$canvas[0].toDataURL();
} catch(e) {
if ($canvas[0].nodeName.toLowerCase() === "canvas") {
// TODO, maybe add a bit less offensive way to present this, but still something that can easily be noticed
window.alert("Canvas is tainted, unable to read data");
}
}
});
function throwMessage(msg,duration){
window.clearTimeout(timeoutTimer);
timeoutTimer = window.setTimeout(function(){
$message.fadeOut(function(){
$message.remove();
$message = null;
});
},duration || 2000);
if ($message)
$message.remove();
$message = $('<div />').html(msg).css({
margin:0,
padding:10,
background: "#000",
opacity:0.7,
position:"fixed",
top:10,
right:10,
fontFamily: 'Tahoma',
color:'#fff',
fontSize:12,
borderRadius:12,
width:'auto',
height:'auto',
textAlign:'center',
textDecoration:'none',
display:'none'
}).appendTo(document.body).fadeIn();
log(msg);
}
};
})( jQuery );

View File

@ -7,21 +7,100 @@
*/
var h2cSelector, h2cOptions;
(function(document, window) {
var srcStart = '<script type="text/javascript" src="', scrEnd = '"></script>';
document.write(srcStart + '/tests/assets/jquery-1.6.2.js' + scrEnd);
document.write(srcStart + '/tests/assets/jquery.plugin.html2canvas.js' + scrEnd);
var html2canvas = ['log', 'nodecontainer', 'stackingcontext', 'textcontainer', 'support', 'imagecontainer', 'dummyimagecontainer', 'proxyimagecontainer', 'gradientcontainer', 'lineargradientcontainer', 'webkitgradientcontainer',
'imageloader', 'nodeparser', 'font', 'fontmetrics', 'core', 'renderer', 'promise', 'renderers/canvas'], i;
if (window.location.search === "?selenium") {
document.write(srcStart + '/build/html2canvas.js' + scrEnd);
} else {
for (i = 0; i < html2canvas.length; ++i) {
document.write(srcStart + '/src/' + html2canvas[i] + '.js?' + Math.random() + scrEnd);
}
function appendScript(src) {
document.write('<script type="text/javascript" src="' + src + '.js?' + Math.random() + '"></script>');
}
var sources = ['log', 'nodecontainer', 'stackingcontext', 'textcontainer', 'support', 'imagecontainer', 'dummyimagecontainer', 'proxyimagecontainer', 'gradientcontainer',
'lineargradientcontainer', 'webkitgradientcontainer', 'imageloader', 'nodeparser', 'font', 'fontmetrics', 'core', 'renderer', 'promise', 'renderers/canvas'];
['/tests/assets/jquery-1.6.2'].concat(window.location.search === "?selenium" ? ['/dist/html2canvas'] : sources.map(function(src) { return '/src/' + src; })).forEach(appendScript);
window.onload = function() {
(function( $ ){
$.fn.html2canvas = function(options) {
if (options && options.profile && window.console && window.console.profile && window.location.search !== "?selenium2") {
window.console.profile();
}
var date = new Date(),
$message = null,
timeoutTimer = false,
timer = date.getTime();
options = options || {};
var promise = html2canvas(this, options);
promise['catch'](function(err) {
console.log("html2canvas threw an error", err);
});
promise.then(function(canvas) {
var $canvas = $(canvas),
finishTime = new Date();
if (options && options.profile && window.console && window.console.profileEnd) {
window.console.profileEnd();
}
$canvas.addClass("html2canvas")
.css({
position: 'absolute',
left: 0,
top: 0
}).appendTo(document.body);
if (window.location.search !== "?selenium") {
$canvas.siblings().toggle();
$(window).click(function(){
$canvas.toggle().siblings().toggle();
throwMessage("Canvas Render " + ($canvas.is(':visible') ? "visible" : "hidden"));
});
throwMessage('Screenshot created in '+ ((finishTime.getTime()-timer)) + " ms<br />",4000);
} else {
$canvas.css('display', 'none');
}
// test if canvas is read-able
try {
$canvas[0].toDataURL();
} catch(e) {
if ($canvas[0].nodeName.toLowerCase() === "canvas") {
// TODO, maybe add a bit less offensive way to present this, but still something that can easily be noticed
window.alert("Canvas is tainted, unable to read data");
}
}
});
function throwMessage(msg,duration){
window.clearTimeout(timeoutTimer);
timeoutTimer = window.setTimeout(function(){
$message.fadeOut(function(){
$message.remove();
$message = null;
});
},duration || 2000);
if ($message)
$message.remove();
$message = $('<div />').html(msg).css({
margin:0,
padding:10,
background: "#000",
opacity:0.7,
position:"fixed",
top:10,
right:10,
fontFamily: 'Tahoma',
color:'#fff',
fontSize:12,
borderRadius:12,
width:'auto',
height:'auto',
textAlign:'center',
textDecoration:'none',
display:'none'
}).appendTo(document.body).fadeIn();
log(msg);
}
};
})(jQuery);
h2cSelector = [document.documentElement];
if (window.setUp) {
@ -29,9 +108,7 @@ var h2cSelector, h2cOptions;
}
setTimeout(function() {
$(h2cSelector).html2canvas($.extend({
flashcanvas: "../external/flashcanvas.min.js",
logging: true,
profile: true,
proxy: "http://html2canvas.appspot.com/query",