Merge pull request #34 from cobexer/rewrite-image-handling

rewrote image handling from using an array to an object
This commit is contained in:
Niklas von Hertzen 2011-11-26 10:15:40 -08:00
commit 961f6caf21
2 changed files with 131 additions and 95 deletions

View File

@ -48,7 +48,7 @@ html2canvas.Parse = function (element, images, opts) {
childrenLen; childrenLen;
images = images || []; images = images || {};
// Test whether we can use ranges to measure bounding boxes // Test whether we can use ranges to measure bounding boxes
// Opera doesn't provide valid bounds.height/bottom even though it supports the method. // Opera doesn't provide valid bounds.height/bottom even though it supports the method.
@ -514,28 +514,13 @@ html2canvas.Parse = function (element, images, opts) {
} }
function loadImage (src){ function loadImage (src){
var img = images[src];
var imgIndex = -1, if (img && img.succeeded === true) {
i, return img.img;
imgLen; } else {
if (images.indexOf){ return false;
imgIndex = images.indexOf(src); }
}else{
for(i = 0, imgLen = images.length; i < imgLen.length; i+=1){
if(images[i] === src) {
imgIndex = i;
break;
}
}
}
if (imgIndex > -1){
return images[imgIndex+1];
}else{
return false;
}
} }
@ -1004,8 +989,7 @@ html2canvas.Parse = function (element, images, opts) {
} }
}else{ }else{
html2canvas.log("html2canvas: Error loading background:" + background_image);
html2canvas.log("Error loading background:" + background_image);
//console.log(images); //console.log(images);
} }
@ -1164,8 +1148,8 @@ html2canvas.Parse = function (element, images, opts) {
bounds.height - (borders[0].width + borders[2].width + paddingTop + paddingBottom) //dh bounds.height - (borders[0].width + borders[2].width + paddingTop + paddingBottom) //dh
); );
}else { }else{
html2canvas.log("Error loading <img>:" + imgSrc); html2canvas.log("html2canvas: Error loading <img>:" + imgSrc);
} }
break; break;
case "INPUT": case "INPUT":

View File

@ -9,11 +9,16 @@
html2canvas.Preload = function(element, opts){ html2canvas.Preload = function(element, opts){
var options = { var options = {
"proxy": "http://html2canvas.appspot.com/" proxy: "http://html2canvas.appspot.com/",
timeout: 0 // no timeout
},
images = {
numLoaded: 0, // also failed are counted here
numFailed: 0,
numTotal: 0,
cleanupDone: false
}, },
images = [],
pageOrigin = window.location.protocol + window.location.host, pageOrigin = window.location.protocol + window.location.host,
imagesLoaded = 0,
methods, methods,
i, i,
count = 0, count = 0,
@ -36,24 +41,9 @@ html2canvas.Preload = function(element, opts){
} }
function getIndex(array,src){
var i, arrLen;
if (array.indexOf){
return array.indexOf(src);
}else{
for(i = 0, arrLen = array.length; i < arrLen; i+=1){
if(this[i] === src) {
return i;
}
}
return -1;
}
}
function start(){ function start(){
if (images.length === 0 || imagesLoaded === images.length/2){ html2canvas.log("html2canvas: start: images: " + images.numLoaded + " / " + images.numTotal + " (failed: " + images.numFailed + ")");
if (!images.firstRun && images.numLoaded >= images.numTotal){
/* /*
this.log('Finished loading '+this.imagesLoaded+' images, Started parsing'); this.log('Finished loading '+this.imagesLoaded+' images, Started parsing');
@ -63,20 +53,22 @@ html2canvas.Preload = function(element, opts){
if (typeof options.complete === "function"){ if (typeof options.complete === "function"){
options.complete(images); options.complete(images);
} }
html2canvas.log("Finished loading images: # " + images.numTotal + " (failed: " + images.numFailed + ")");
} }
} }
function proxyGetImage(url, img){ function proxyGetImage(url, img){
link.href = url;
url = link.href; // work around for pages with base href="" set
var callback_name, var callback_name,
scriptUrl = options.proxy, scriptUrl = options.proxy,
script; script,
imgObj = images[url];
link.href = url;
url = link.href; // work around for pages with base href="" set - WARNING: this may change the url -> so access imgObj from images map before changing that url!
callback_name = 'html2canvas_' + count; callback_name = 'html2canvas_' + count;
imgObj.callbackname = callback_name;
if (scriptUrl.indexOf("?") > -1) { if (scriptUrl.indexOf("?") > -1) {
scriptUrl += "&"; scriptUrl += "&";
@ -87,26 +79,35 @@ html2canvas.Preload = function(element, opts){
window[callback_name] = function(a){ window[callback_name] = function(a){
if (a.substring(0,6) === "error:"){ if (a.substring(0,6) === "error:"){
images.splice(getIndex(images, url), 2); imgObj.succeeded = false;
images.numLoaded++;
images.numFailed++;
start(); start();
}else{ } else {
img.onload = function(){ img.onload = function(){
imagesLoaded+=1; imgObj.succeeded = true;
start(); images.numLoaded++;
start();
}; };
img.src = a; img.src = a;
} }
delete window[callback_name]; window[callback_name] = undefined; // to work with IE<9 // NOTE: that the undefined callback property-name still exists on the window object (for IE<9)
try {
delete window[callback_name]; // for all browser that support this
} catch(ex) {}
script.parentNode.removeChild(script);
script = null;
imgObj.callbackname = undefined;
}; };
count += 1; count += 1;
script = doc.createElement("script"); script = doc.createElement("script");
script.setAttribute("src", scriptUrl); script.setAttribute("src", scriptUrl);
script.setAttribute("type", "text/javascript"); script.setAttribute("type", "text/javascript");
imgObj.script = script;
window.document.body.appendChild(script); window.document.body.appendChild(script);
/* /*
// enable xhr2 requests where available (no need for base64 / json) // enable xhr2 requests where available (no need for base64 / json)
@ -186,10 +187,10 @@ html2canvas.Preload = function(element, opts){
img = html2canvas.Generate.Gradient( background_image, html2canvas.Util.Bounds( el ) ); img = html2canvas.Generate.Gradient( background_image, html2canvas.Util.Bounds( el ) );
if ( img !== undefined ){ if ( img !== undefined ){
images.push(background_image); images[background_image] = { img: img, succeeded: true };
images.push(img); images.numTotal++;
imagesLoaded++; images.numLoaded++;
start(); start();
} }
@ -211,58 +212,110 @@ html2canvas.Preload = function(element, opts){
methods = { methods = {
loadImage: function( src ) { loadImage: function( src ) {
var img; var img;
if ( getIndex(images, src) === -1 ) { if ( images[src] === undefined ) {
if ( src.match(/data:image\/.*;base64,/i) ) { if ( src.match(/data:image\/.*;base64,/i) ) {
//Base64 src //Base64 src
img = new Image(); img = new Image();
img.src = src.replace(/url\(['"]{0,}|['"]{0,}\)$/ig, ''); img.src = src.replace(/url\(['"]{0,}|['"]{0,}\)$/ig, '');
images[src] = { img: img, succeeded: true };
images.push( src ); images.numTotal++;
images.push( img ); images.numLoaded++;
imagesLoaded+=1;
start(); start();
}else if ( isSameOrigin( src ) ) { }else if ( isSameOrigin( src ) ) {
images.push( src ); img = new Image();
img = new Image(); images[src] = { img: img };
images.numTotal++;
img.onload = function() { img.onload = function() {
imagesLoaded+=1; images.numLoaded++;
start(); images[src].succeeded = true;
start();
}; };
img.onerror = function() { img.onerror = function() {
images.splice( getIndex( images, img.src ), 2 ); images.numLoaded++;
start(); images.numFailed++;
images[src].succeeded = false;
start();
}; };
img.src = src; img.src = src;
images.push(img);
}else if ( options.proxy ){ }else if ( options.proxy ){
// console.log('b'+src); // console.log('b'+src);
images.push( src ); img = new Image();
img = new Image(); images[src] = { img: img };
images.numTotal++;
proxyGetImage( src, img ); proxyGetImage( src, img );
images.push( img );
} }
} }
},
cleanupDOM: function(cause) {
var img;
if (!images.cleanupDone) {
if (cause && typeof cause === "string") {
html2canvas.log("html2canvas: Cleanup because: " + cause);
} else {
html2canvas.log("html2canvas: Cleanup after timeout: " + options.timeout + " ms.");
}
for (src in images) {
if (images.hasOwnProperty(src)) {
img = images[src];
if (typeof img === "object" && img.callbackname && img.succeeded === undefined) {
// cancel proxy image request
window[img.callbackname] = undefined; // to work with IE<9 // NOTE: that the undefined callback property-name still exists on the window object (for IE<9)
try {
delete window[img.callbackname]; // for all browser that support this
} catch(ex) {}
if (img.script && img.script.parentNode) {
img.script.setAttribute("src", "about:blank"); // try to cancel running request
img.script.parentNode.removeChild(img.script);
}
images.numLoaded++;
images.numFailed++;
html2canvas.log("html2canvas: Cleaned up failed img: '" + src + "' Steps: " + images.numLoaded + " / " + images.numTotal);
}
}
}
// cancel any pending requests
if(window.stop !== undefined) {
window.stop();
} else if(document.execCommand !== undefined) {
document.execCommand("Stop", false);
}
if (document.close !== undefined) {
document.close();
}
images.cleanupDone = true;
if (!(cause && typeof cause === "string")) {
start();
}
}
},
renderingDone: function() {
if (timeoutTimer) {
window.clearTimeout(timeoutTimer);
}
} }
}; };
// add something to array if (options.timeout > 0) {
images.push('start'); timeoutTimer = window.setTimeout(methods.cleanupDOM, options.timeout);
}
var startTime = (new Date()).getTime();
this.log('html2canvas: Preload starts: finding background-images');
images.firstRun = true;
getImages( element ); getImages( element );
this.log('html2canvas: Preload: Finding images');
// load <img> images // load <img> images
for (i = 0; i < imgLen; i+=1){ for (i = 0; i < imgLen; i+=1){
var imgSrc = domImages[i].getAttribute( "src" ); var imgSrc = domImages[i].getAttribute( "src" );
@ -271,10 +324,9 @@ html2canvas.Preload = function(element, opts){
} }
} }
// remove 'start' images.firstRun = false;
images.splice(0, 1); this.log('html2canvas: Preload: Done.');
if ( images.numTotal === images.numLoaded ) {
if ( images.length === 0 ) {
start(); start();
} }