simplified API and cleaned up code

This commit is contained in:
Niklas von Hertzen 2012-03-02 18:05:03 +02:00
parent bf994849e0
commit c7d526c9ea
11 changed files with 203 additions and 143 deletions

View File

@ -37,7 +37,7 @@ For more information and examples, please visit the <a href="http://html2canvas.
### Changelog ###
v0.33 -
v0.33 - 2.3.2012
* SVG taint fix, and additional taint testing options for rendering (<a href="https://github.com/niklasvh/html2canvas/commit/2dc8b9385e656696cb019d615bdfa1d98b17d5d4">niklasvh</a>)
* Added support for CORS images and option to create canvas as tainted (<a href="https://github.com/niklasvh/html2canvas/commit/3ad49efa0032cde25c6ed32a39e35d1505d3b2ef">niklasvh</a>)

View File

@ -5,22 +5,21 @@
Released under MIT License
*/
"use strict";
var html2canvas = {};
var _html2canvas = {},
html2canvas;
html2canvas.logging = false;
function h2clog(a) {
if (html2canvas.logging && window.console && window.console.log) {
if (_html2canvas.logging && window.console && window.console.log) {
window.console.log(a);
}
}
html2canvas.log = h2clog; // for compatibility with the jquery plugin
_html2canvas.Util = {};
html2canvas.Util = {};
html2canvas.Util.backgroundImage = function (src) {
_html2canvas.Util.backgroundImage = function (src) {
if (/data:image\/.*;base64,/i.test( src ) || /^(-webkit|-moz|linear-gradient|-o-)/.test( src )) {
return src;
@ -37,7 +36,7 @@ html2canvas.Util.backgroundImage = function (src) {
return src;
};
html2canvas.Util.Bounds = function getBounds (el) {
_html2canvas.Util.Bounds = function getBounds (el) {
var clientRect,
bounds = {};
@ -70,9 +69,9 @@ html2canvas.Util.Bounds = function getBounds (el) {
} */
}
};
html2canvas.Util.getCSS = function (el, attribute) {
_html2canvas.Util.getCSS = function (el, attribute) {
// return jQuery(el).css(attribute);
/*
var val,
@ -126,7 +125,7 @@ html2canvas.Util.getCSS = function (el, attribute) {
};
html2canvas.Util.Extend = function (options, defaults) {
_html2canvas.Util.Extend = function (options, defaults) {
var key;
for (key in options) {
if (options.hasOwnProperty(key)) {
@ -136,7 +135,7 @@ html2canvas.Util.Extend = function (options, defaults) {
return defaults;
};
html2canvas.Util.Children = function(el) {
_html2canvas.Util.Children = function(el) {
// $(el).contents() !== el.childNodes, Opera / IE have issues with that
var children;
try {

View File

@ -6,11 +6,11 @@
Released under MIT License
*/
html2canvas.Generate = {};
_html2canvas.Generate = {};
html2canvas.Generate.Gradient = function(src, bounds) {
_html2canvas.Generate.Gradient = function(src, bounds) {
var canvas = document.createElement('canvas'),
ctx = canvas.getContext('2d'),
tmp,
@ -35,22 +35,24 @@ html2canvas.Generate.Gradient = function(src, bounds) {
var j = -1,
color = '',
chr;
while( j++ < input.length ) {
chr = input.charAt( j );
if (chr === ')') {
color += chr;
steps.push( color );
color = '';
while (j++ < input.length && input.charAt( j ) !== ',') {
j = input.indexOf(",", j) + 1;
if (j === 0) {
break;
}
// while (j++ < input.length && input.charAt( j ) !== ',') {}
} else {
color += chr;
}
}
}
if ( tmp = src.match(/-webkit-linear-gradient\((.*)\)/) ) {
if ( (tmp = src.match(/-webkit-linear-gradient\((.*)\)/)) !== null ) {
position = tmp[1].split( ",", 1 )[0];
getColors( tmp[1].substr( position.length + 2 ) );
@ -78,7 +80,7 @@ html2canvas.Generate.Gradient = function(src, bounds) {
}
} else if (tmp = src.match(/-webkit-gradient\(linear, (\d+)[%]{0,1} (\d+)[%]{0,1}, (\d+)[%]{0,1} (\d+)[%]{0,1}, from\((.*)\), to\((.*)\)\)/)) {
} else if ( (tmp = src.match(/-webkit-gradient\(linear, (\d+)[%]{0,1} (\d+)[%]{0,1}, (\d+)[%]{0,1} (\d+)[%]{0,1}, from\((.*)\), to\((.*)\)\)/)) !== null ) {
p0 = (tmp[1] * bounds.width) / 100;
p1 = (tmp[2] * bounds.height) / 100;
@ -88,7 +90,7 @@ html2canvas.Generate.Gradient = function(src, bounds) {
steps.push(tmp[5]);
steps.push(tmp[6]);
} else if (tmp = src.match(/-moz-linear-gradient\((\d+)[%]{0,1} (\d+)[%]{0,1}, (.*)\)/)) {
} else if ( (tmp = src.match(/-moz-linear-gradient\((\d+)[%]{0,1} (\d+)[%]{0,1}, (.*)\)/)) !== null ) {
p0 = (tmp[1] * bounds.width) / 100;
p1 = (tmp[2] * bounds.width) / 100;
@ -122,9 +124,9 @@ html2canvas.Generate.Gradient = function(src, bounds) {
return img;
}
};
html2canvas.Generate.ListAlpha = function(number) {
_html2canvas.Generate.ListAlpha = function(number) {
var tmp = "",
modulus;
@ -135,9 +137,9 @@ html2canvas.Generate.ListAlpha = function(number) {
}while((number*26) > 26);
return tmp;
}
};
html2canvas.Generate.ListRoman = function(number) {
_html2canvas.Generate.ListRoman = function(number) {
var romanArray = ["M", "CM", "D", "CD", "C", "XC", "L", "XL", "X", "IX", "V", "IV", "I"],
decimal = [1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1],
roman = "",
@ -157,4 +159,4 @@ html2canvas.Generate.ListRoman = function(number) {
return roman;
}
};

View File

@ -10,9 +10,8 @@
* New function for traversing elements
*/
html2canvas.Parse = function (element, images, opts) {
_html2canvas.Parse = function (element, images, options) {
window.scroll(0,0);
opts = opts || {};
// select body by default
if (element === undefined) {
@ -24,12 +23,7 @@ html2canvas.Parse = function (element, images, opts) {
rangeBounds: false
},
options = {
iframeDefault: "default",
ignoreElements: "IFRAME|OBJECT|PARAM",
useOverflow: true,
letterRendering: false
},
needReorder = false,
numDraws = 0,
fontData = {},
@ -47,7 +41,7 @@ html2canvas.Parse = function (element, images, opts) {
children,
childrenLen;
options = html2canvas.Util.Extend(opts, options);
images = images || {};
@ -106,7 +100,7 @@ html2canvas.Parse = function (element, images, opts) {
}
var getCSS = html2canvas.Util.getCSS;
var getCSS = _html2canvas.Util.getCSS;
function getCSSInt(element, attribute) {
var val = parseInt(getCSS(element, attribute), 10);
return (isNaN(val)) ? 0 : val; // borders in old IE are throwing 'medium' for demo.html
@ -354,7 +348,7 @@ html2canvas.Parse = function (element, images, opts) {
wrapElement.appendChild(oldTextNode.cloneNode(true));
parent.replaceChild(wrapElement, oldTextNode);
bounds = html2canvas.Util.Bounds(wrapElement);
bounds = _html2canvas.Util.Bounds(wrapElement);
textValue = oldTextNode.nodeValue;
@ -416,7 +410,7 @@ html2canvas.Parse = function (element, images, opts) {
element.insertBefore(boundElement, element.firstChild);
bounds = html2canvas.Util.Bounds( boundElement );
bounds = _html2canvas.Util.Bounds( boundElement );
element.removeChild( boundElement );
element.style.listStyleType = type;
return bounds;
@ -453,16 +447,16 @@ html2canvas.Parse = function (element, images, opts) {
}
break;
case "upper-roman":
text = html2canvas.Generate.ListRoman( currentIndex );
text = _html2canvas.Generate.ListRoman( currentIndex );
break;
case "lower-roman":
text = html2canvas.Generate.ListRoman( currentIndex ).toLowerCase();
text = _html2canvas.Generate.ListRoman( currentIndex ).toLowerCase();
break;
case "lower-alpha":
text = html2canvas.Generate.ListAlpha( currentIndex ).toLowerCase();
text = _html2canvas.Generate.ListAlpha( currentIndex ).toLowerCase();
break;
case "upper-alpha":
text = html2canvas.Generate.ListAlpha( currentIndex );
text = _html2canvas.Generate.ListAlpha( currentIndex );
break;
}
@ -495,20 +489,21 @@ html2canvas.Parse = function (element, images, opts) {
}else{
return;
/*
/*
TODO really need to figure out some more accurate way to try and find the position.
as defined in http://www.w3.org/TR/CSS21/generate.html#propdef-list-style-position, it does not even have a specified "correct" position, so each browser
may display it whatever way it feels like.
"The position of the list-item marker adjacent to floats is undefined in CSS 2.1. CSS 2.1 does not specify the precise location of the marker box or its position in the painting order"
*/
ctx.setVariable("textAlign", "right");
// this.setFont(stack.ctx, element, true);
x = elBounds.left - 10;
*/
}
y = listBounds.bottom;
drawText(text, x, y, ctx)
drawText(text, x, y, ctx);
}
@ -517,12 +512,12 @@ html2canvas.Parse = function (element, images, opts) {
}
function loadImage (src){
var img = images[src];
if (img && img.succeeded === true) {
return img.img;
} else {
return false;
}
var img = images[src];
if (img && img.succeeded === true) {
return img.img;
} else {
return false;
}
}
@ -548,15 +543,15 @@ html2canvas.Parse = function (element, images, opts) {
function setZ(zIndex, parentZ){
// TODO fix static elements overlapping relative/absolute elements under same stack, if they are defined after them
var newContext;
if (!parentZ){
this.zStack = h2czContext(0);
return this.zStack;
newContext = h2czContext(0);
return newContext;
}
if (zIndex !== "auto"){
needReorder = true;
var newContext = h2czContext(zIndex);
newContext = h2czContext(zIndex);
parentZ.children.push(newContext);
return newContext;
@ -669,7 +664,7 @@ html2canvas.Parse = function (element, images, opts) {
style = cssArr[i];
try {
valueWrap.style[style] = getCSS(el, style);
valueWrap.style[style] = getCSS(el, style);
} catch( e ) {
// Older IE has issues with "border"
h2clog("html2canvas: Parse: Exception caught in renderFormValue: " + e.message);
@ -718,8 +713,8 @@ html2canvas.Parse = function (element, images, opts) {
if (bgp !== undefined) {
return (bgp.split(",")[0] || "0 0").split(" ");
} else {
// Older IE uses -x and -y
return [ getCSS(el, "backgroundPositionX"), getCSS(el, "backgroundPositionY") ];
// Older IE uses -x and -y
return [ getCSS(el, "backgroundPositionX"), getCSS(el, "backgroundPositionY") ];
}
@ -882,7 +877,7 @@ html2canvas.Parse = function (element, images, opts) {
}
if ( typeof background_image !== "undefined" && /^(1|none)$/.test( background_image ) === false ) {
background_image = html2canvas.Util.backgroundImage( background_image );
background_image = _html2canvas.Util.backgroundImage( background_image );
image = loadImage( background_image );
@ -945,9 +940,7 @@ html2canvas.Parse = function (element, images, opts) {
bgsy = 0;
}
// bgh = Math.abs(bgh);
// bgw = Math.abs(bgw);
if (bgh>0 && bgw > 0){
renderImage(
ctx,
@ -961,9 +954,7 @@ html2canvas.Parse = function (element, images, opts) {
bgw, // destination width : 18
bgh // destination height : 1677
);
// ctx.drawImage(image,(bounds.left+bgp.left),(bounds.top+bgp.top));
}
break;
default:
@ -1017,7 +1008,7 @@ html2canvas.Parse = function (element, images, opts) {
function renderElement(el, parentStack){
var bounds = html2canvas.Util.Bounds(el),
var bounds = _html2canvas.Util.Bounds(el),
x = bounds.left,
y = bounds.top,
w = bounds.width,
@ -1066,7 +1057,7 @@ html2canvas.Parse = function (element, images, opts) {
// TODO correct overflow for absolute content residing under a static position
if (parentStack.clip){
stack.clip = html2canvas.Util.Extend( {}, parentStack.clip );
stack.clip = _html2canvas.Util.Extend( {}, parentStack.clip );
//stack.clip = parentStack.clip;
// stack.clip.height = stack.clip.height - parentStack.borders[2].width;
}
@ -1219,7 +1210,7 @@ html2canvas.Parse = function (element, images, opts) {
y + paddingTop + borders[0].width, // dy
bounds.width - (borders[1].width + borders[3].width + paddingLeft + paddingRight), //dw
bounds.height - (borders[0].width + borders[2].width + paddingTop + paddingBottom) //dh
);
);
break;
}
@ -1238,7 +1229,7 @@ html2canvas.Parse = function (element, images, opts) {
ctx = stack.ctx;
if ( !ignoreElementsRegExp.test( el.nodeName ) ) {
var elementChildren = html2canvas.Util.Children( el ),
var elementChildren = _html2canvas.Util.Children( el ),
i,
node,
childrenLen;
@ -1276,4 +1267,4 @@ function h2czContext(zindex) {
zindex: zindex,
children: []
};
};
}

View File

@ -6,15 +6,9 @@
Released under MIT License
*/
html2canvas.Preload = function(element, opts){
_html2canvas.Preload = function(element, options){
var options = {
proxy: "http://html2canvas.appspot.com/",
timeout: 0, // no timeout
useCORS: false, // try to load images as CORS (where available), before falling back to proxy
allowTaint: false // whether to allow images to taint the canvas, won't need proxy if set to true
},
images = {
var images = {
numLoaded: 0, // also failed are counted here
numFailed: 0,
numTotal: 0,
@ -35,9 +29,9 @@ html2canvas.Preload = function(element, opts){
link.href = window.location.href;
pageOrigin = link.protocol + link.host;
opts = opts || {};
options = html2canvas.Util.Extend(opts, options);
@ -121,7 +115,7 @@ html2canvas.Preload = function(element, opts){
// if (!this.ignoreRe.test(el.nodeName)){
//
var contents = html2canvas.Util.Children(el),
var contents = _html2canvas.Util.Children(el),
i,
contentsLen = contents.length,
background_image,
@ -148,7 +142,7 @@ html2canvas.Preload = function(element, opts){
// opera throws exception on external-content.html
try {
background_image = html2canvas.Util.getCSS(el, 'backgroundImage');
background_image = _html2canvas.Util.getCSS(el, 'backgroundImage');
}catch(e) {
h2clog("html2canvas: failed to get background-image - Exception: " + e.message);
}
@ -158,7 +152,7 @@ html2canvas.Preload = function(element, opts){
if (background_image.substring(0,7) === "-webkit" || background_image.substring(0,3) === "-o-" || background_image.substring(0,4) === "-moz") {
img = html2canvas.Generate.Gradient( background_image, html2canvas.Util.Bounds( el ) );
img = _html2canvas.Generate.Gradient( background_image, _html2canvas.Util.Bounds( el ) );
if ( img !== undefined ){
images[background_image] = {
@ -172,8 +166,8 @@ html2canvas.Preload = function(element, opts){
}
} else {
src = html2canvas.Util.backgroundImage(background_image.match(/data:image\/.*;base64,/i) ? background_image : background_image.split(",")[0]);
methods.loadImage(src);
src = _html2canvas.Util.backgroundImage(background_image.match(/data:image\/.*;base64,/i) ? background_image : background_image.split(",")[0]);
methods.loadImage(src);
}
/*
@ -198,7 +192,7 @@ html2canvas.Preload = function(element, opts){
img.onerror = function() {
if (img.crossOrigin === "anonymous") {
// CORS failed
// CORS failed
window.clearTimeout( imageObj.timer );
// let's try with proxy instead
@ -222,14 +216,6 @@ html2canvas.Preload = function(element, opts){
};
}
// work around for https://bugs.webkit.org/show_bug.cgi?id=80028
function isComplete() {
if (!this.img.complete) {
this.timer = window.setTimeout(this.img.customComplete, 100)
} else {
this.img.onerror();
}
}
methods = {
loadImage: function( src ) {
@ -238,11 +224,15 @@ html2canvas.Preload = function(element, opts){
img = new Image();
if ( src.match(/data:image\/.*;base64,/i) ) {
img.src = src.replace(/url\(['"]{0,}|['"]{0,}\)$/ig, '');
imageObj = images[src] = { img: img };
imageObj = images[src] = {
img: img
};
images.numTotal++;
setImageLoadHandlers(img, imageObj);
} else if ( isSameOrigin( src ) || options.allowTaint === true ) {
imageObj = images[src] = { img: img };
imageObj = images[src] = {
img: img
};
images.numTotal++;
setImageLoadHandlers(img, imageObj);
img.src = src;
@ -250,16 +240,27 @@ html2canvas.Preload = function(element, opts){
// attempt to load with CORS
img.crossOrigin = "anonymous";
imageObj = images[src] = { img: img };
imageObj = images[src] = {
img: img
};
images.numTotal++;
setImageLoadHandlers(img, imageObj);
img.src = src;
img.src = src;
img.customComplete = isComplete.bind(imageObj);
// work around for https://bugs.webkit.org/show_bug.cgi?id=80028
img.customComplete = function () {
if (!this.img.complete) {
this.timer = window.setTimeout(this.img.customComplete, 100);
} else {
this.img.onerror();
}
}.bind(imageObj);
img.customComplete();
} else if ( options.proxy ) {
imageObj = images[src] = { img: img };
imageObj = images[src] = {
img: img
};
images.numTotal++;
proxyGetImage( src, img, imageObj );
}

View File

@ -5,22 +5,15 @@
Released under MIT License
*/
html2canvas.Renderer = function(parseQueue, opts){
_html2canvas.Renderer = function(parseQueue, options){
var options = {
"width": null,
"height": null,
"renderer": "canvas",
"taintTest": true // do a taint test with all images before applying to canvas
},
queue = [],
var queue = [],
canvas,
usingFlashcanvas = false,
flashMaxSize = 2880, // flash bitmap limited to 2880x2880px // http://stackoverflow.com/questions/2033792/argumenterror-error-2015-invalid-bitmapdata
doc = document;
options = html2canvas.Util.Extend(opts, options);
@ -185,27 +178,27 @@ html2canvas.Renderer = function(parseQueue, opts){
if (queueLen === 1) {
if (typeof options.elements[ 0 ] === "object" && options.elements[ 0 ].nodeName !== "BODY" && usingFlashcanvas === false) {
// crop image to the bounds of selected (single) element
bounds = html2canvas.Util.Bounds( options.elements[ 0 ] );
bounds = _html2canvas.Util.Bounds( options.elements[ 0 ] );
newCanvas = doc.createElement('canvas');
newCanvas.width = bounds.width;
newCanvas.height = bounds.height;
ctx = newCanvas.getContext("2d");
ctx.drawImage( canvas, bounds.left, bounds.top, bounds.width, bounds.height, 0, 0, bounds.width, bounds.height );
delete canvas;
canvas = null;
return newCanvas;
}
} else {
} /*else {
// TODO clip and resize multiple elements
/*
for ( i = 0; i < queueLen; i+=1 ) {
if (options.elements[ i ] instanceof Element) {
}
}*/
}
}
*/

View File

@ -4,4 +4,79 @@
http://www.twitter.com/niklasvh
Released under MIT License
*/
*/
html2canvas = function( elements, opts ) {
var queue,
canvas,
options = {
// general
logging: false,
// preload options
proxy: "http://html2canvas.appspot.com/",
timeout: 0, // no timeout
useCORS: false, // try to load images as CORS (where available), before falling back to proxy
allowTaint: false, // whether to allow images to taint the canvas, won't need proxy if set to true
// parse options
iframeDefault: "default",
ignoreElements: "IFRAME|OBJECT|PARAM",
useOverflow: true,
letterRendering: false,
// render options
width: null,
height: null,
renderer: "canvas",
taintTest: true // do a taint test with all images before applying to canvas
};
options = _html2canvas.Util.Extend(opts, options);
_html2canvas.logging = options.logging;
options.complete = function( images ) {
if (typeof options.onpreloaded === "function") {
if ( options.onpreloaded( images ) === false ) {
return;
}
}
queue = _html2canvas.Parse( elements, images, options);
if (typeof options.onparsed === "function") {
if ( options.onparsed( queue ) === false ) {
return;
}
}
canvas = _html2canvas.Renderer(queue, options);
if (typeof options.onrendered === "function") {
options.onrendered( canvas );
}
};
// for pages without images, we still want this to be async, i.e. return methods before executing
window.setTimeout( function(){
_html2canvas.Preload( elements, options );
}, 0 );
return {
render: function( queue, opts ) {
return _html2canvas.Renderer( queue, _html2canvas.Util.Extend(opts, options) );
},
parse: function( elements, images, opts ) {
return _html2canvas.Parse( elements, images, _html2canvas.Util.Extend(opts, options) );
},
preload: function( elements, opts ) {
return _html2canvas.Preload( elements, _html2canvas.Util.Extend(opts, options) );
},
log: h2clog
};
};

View File

@ -1,6 +1,6 @@
(function() {
/* options, customize to your needs */
var server = '//html2canvas.hertzen.com/build',
var server = '//html2canvas.hertzen.com/js',
proxy = '//html2canvas.appspot.com',
debug = false,
profile = false;

View File

@ -7,17 +7,15 @@
console.profile();
}
var date = new Date(),
html2obj,
$message = null,
timeoutTimer = false,
timer = date.getTime();
options = options || {};
options.elements = this;
options.flashcanvas = "../external/flashcanvas.min.js";
html2canvas.logging = options && options.logging;
options.complete = function(images){
var queue = html2canvas.Parse(this[0], images, options),
$canvas = $(html2canvas.Renderer(queue, options)),
options.onrendered = function( canvas ) {
var $canvas = $(canvas),
finishTime = new Date();
if (options && options.profile && window.console && window.console.profileEnd) {
@ -45,9 +43,9 @@
alert("Canvas is tainted, unable to read data");
}
}
};
html2canvas.Preload(this[0], options);
html2obj = html2canvas(this[0], options);
function throwMessage(msg,duration){
window.clearTimeout(timeoutTimer);
@ -77,7 +75,7 @@
textDecoration:'none',
display:'none'
}).appendTo(document.body).fadeIn();
html2canvas.log(msg);
html2obj.log(msg);
}
};
})( jQuery );

View File

@ -6,22 +6,23 @@
Released under MIT License
*/
(function(document, window) {
var scrStart = '<script type="text/javascript" src="', scrEnd = '"></script>';
document.write(scrStart + '../external/jquery-1.6.2.js' + scrEnd);
var html2canvas = ['Core', 'Generate', 'Parse', 'Preload', 'Queue', 'Renderer', 'Util', 'plugins/jquery.plugin.html2canvas'], i;
for (i = 0; i < html2canvas.length; ++i) {
document.write(scrStart + '../src/' + html2canvas[i] + '.js' + scrEnd);
}
window.onload = function() {
if (window.setUp) {
window.setUp();
var scrStart = '<script type="text/javascript" src="', scrEnd = '"></script>';
document.write(scrStart + '../external/jquery-1.6.2.js' + scrEnd);
var html2canvas = ['Core', 'Generate', 'Parse', 'Preload', 'Queue', 'Renderer', 'Util', 'plugins/jquery.plugin.html2canvas'], i;
for (i = 0; i < html2canvas.length; ++i) {
document.write(scrStart + '../src/' + html2canvas[i] + '.js' + scrEnd);
}
setTimeout(function() {
$(document.body).html2canvas({
logging: true,
profile: true,
useCORS: true
});
}, 100);
};
window.onload = function() {
if (window.setUp) {
window.setUp();
}
setTimeout(function() {
$(document.body).html2canvas({
flashcanvas: "../external/flashcanvas.min.js",
logging: true,
profile: true,
useCORS: true
});
}, 100);
};
}(document, window));

View File

@ -1 +1 @@
v0.32
v0.33