Skip to content

Commit 3ad49ef

Browse files
committed
added support for CORS images and option to create canvas as tainted
1 parent c86d12b commit 3ad49ef

File tree

5 files changed

+65
-33
lines changed

5 files changed

+65
-33
lines changed

readme.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ For more information and examples, please visit the <a href="http://html2canvas.
3838
### Changelog ###
3939

4040
v0.33 -
41-
41+
* Added support for CORS images and option to create canvas as tainted (<a href="#">niklasvh</a>)
4242
* Improved minification saved ~1K! (<a href="https://github.com/cobexer/html2canvas/commit/b82be022b2b9240bd503e078ac980bde2b953e43">cobexer</a>)
4343
* Added integrated support for Flashcanvas (<a href="https://github.com/niklasvh/html2canvas/commit/e9257191519f67d74fd5e364d8dee3c0963ba5fc">niklasvh</a>)
4444
* Fixed a variety of legacy IE bugs (<a href="https://github.com/niklasvh/html2canvas/commit/b65357c55d0701017bafcd357bc654b54d458f8f">niklasvh</a>)

src/Preload.js

Lines changed: 55 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,9 @@ html2canvas.Preload = function(element, opts){
1010

1111
var options = {
1212
proxy: "http://html2canvas.appspot.com/",
13-
timeout: 0 // no timeout
13+
timeout: 0, // no timeout
14+
useCORS: false, // try to load images as CORS (where available), before falling back to proxy
15+
allowTaint: false // whether to allow images to taint the canvas, won't need proxy if set to true
1416
},
1517
images = {
1618
numLoaded: 0, // also failed are counted here
@@ -26,6 +28,9 @@ html2canvas.Preload = function(element, opts){
2628
domImages = doc.images, // TODO probably should limit it to images present in the element only
2729
imgLen = domImages.length,
2830
link = doc.createElement("a"),
31+
supportCORS = (function( img ){
32+
return (img.crossOrigin !== undefined);
33+
})(new Image()),
2934
timeoutTimer;
3035

3136
link.href = window.location.href;
@@ -41,7 +46,7 @@ html2canvas.Preload = function(element, opts){
4146
function isSameOrigin(url){
4247
link.href = url;
4348
var origin = link.protocol + link.host;
44-
return ":" === origin || (origin === pageOrigin);
49+
return (origin === pageOrigin);
4550
}
4651

4752
function start(){
@@ -215,36 +220,78 @@ html2canvas.Preload = function(element, opts){
215220

216221
function setImageLoadHandlers(img, imageObj) {
217222
img.onload = function() {
223+
if ( imageObj.timer !== undefined ) {
224+
// CORS succeeded
225+
window.clearTimeout( imageObj.timer );
226+
}
218227
images.numLoaded++;
219228
imageObj.succeeded = true;
220229
start();
221230
};
222231
img.onerror = function() {
232+
233+
if (img.crossOrigin === "anonymous") {
234+
// CORS failed
235+
window.clearTimeout( imageObj.timer );
236+
237+
// let's try with proxy instead
238+
if ( options.proxy ) {
239+
var src = img.src;
240+
img = new Image();
241+
imageObj.img = img;
242+
img.src = src;
243+
244+
proxyGetImage( img.src, img, imageObj );
245+
return;
246+
}
247+
}
248+
249+
223250
images.numLoaded++;
224251
images.numFailed++;
225252
imageObj.succeeded = false;
226253
start();
254+
227255
};
228256
}
257+
258+
// work around for https://bugs.webkit.org/show_bug.cgi?id=80028
259+
function isComplete() {
260+
if (!this.img.complete) {
261+
this.timer = window.setTimeout(this.img.customComplete, 100)
262+
} else {
263+
this.img.onerror();
264+
}
265+
}
229266

230267
methods = {
231268
loadImage: function( src ) {
232-
var img, imageObj;
269+
var img, imageObj;
233270
if ( src && images[src] === undefined ) {
234-
img = new Image();
271+
img = new Image();
235272
if ( src.match(/data:image\/.*;base64,/i) ) {
236273
img.src = src.replace(/url\(['"]{0,}|['"]{0,}\)$/ig, '');
237274
imageObj = images[src] = { img: img };
238275
images.numTotal++;
239276
setImageLoadHandlers(img, imageObj);
240-
}
241-
else if ( isSameOrigin( src ) ) {
277+
} else if ( isSameOrigin( src ) || options.allowTaint === true ) {
242278
imageObj = images[src] = { img: img };
243279
images.numTotal++;
244280
setImageLoadHandlers(img, imageObj);
245281
img.src = src;
246-
}
247-
else if ( options.proxy ) {
282+
} else if ( supportCORS && !options.allowTaint && options.useCORS ) {
283+
// attempt to load with CORS
284+
285+
img.crossOrigin = "anonymous";
286+
imageObj = images[src] = { img: img };
287+
images.numTotal++;
288+
setImageLoadHandlers(img, imageObj);
289+
img.src = src;
290+
291+
img.customComplete = isComplete.bind(imageObj);
292+
img.customComplete();
293+
294+
} else if ( options.proxy ) {
248295
imageObj = images[src] = { img: img };
249296
images.numTotal++;
250297
proxyGetImage( src, img, imageObj );

src/Renderer.js

Lines changed: 3 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -127,35 +127,16 @@ html2canvas.Renderer = function(parseQueue, opts){
127127
if (renderItem.name === "fillRect") {
128128

129129
if (!usingFlashcanvas || renderItem['arguments'][0] + renderItem['arguments'][2] < flashMaxSize && renderItem['arguments'][1] + renderItem['arguments'][3] < flashMaxSize) {
130-
ctx.fillRect(
131-
renderItem['arguments'][0],
132-
renderItem['arguments'][1],
133-
renderItem['arguments'][2],
134-
renderItem['arguments'][3]
135-
);
130+
ctx.fillRect.apply( ctx, renderItem['arguments'] );
136131
}
137132
}else if(renderItem.name === "fillText") {
138133
if (!usingFlashcanvas || renderItem['arguments'][1] < flashMaxSize && renderItem['arguments'][2] < flashMaxSize) {
139-
ctx.fillText(
140-
renderItem['arguments'][0],
141-
renderItem['arguments'][1],
142-
renderItem['arguments'][2]
143-
);
134+
ctx.fillText.apply( ctx, renderItem['arguments'] );
144135
}
145136
}else if(renderItem.name === "drawImage") {
146137

147138
if (renderItem['arguments'][8] > 0 && renderItem['arguments'][7]){
148-
ctx.drawImage(
149-
renderItem['arguments'][0],
150-
renderItem['arguments'][1],
151-
renderItem['arguments'][2],
152-
renderItem['arguments'][3],
153-
renderItem['arguments'][4],
154-
renderItem['arguments'][5],
155-
renderItem['arguments'][6],
156-
renderItem['arguments'][7],
157-
renderItem['arguments'][8]
158-
);
139+
ctx.drawImage.apply( ctx, renderItem['arguments'] );
159140
}
160141
}
161142

tests/proxy.html

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
66
<script type="text/javascript" src="test.js"></script>
77

8-
<base href="http://www.google.com/" />
8+
<base href="http://www.google.com/" />
99
</head>
1010
<body>
1111
<h1>External image</h1>
@@ -14,5 +14,8 @@ <h1>External image</h1>
1414
<h1>External image (using &lt;base&gt; href)</h1>
1515
<img src="/logos/2011/gregormendel11-res.jpg" />
1616

17+
<h1>External image (CORS)</h1>
18+
<img src="http://publishmydata.com/assets/home/blue_bg.png" />
19+
1720
</body>
1821
</html>

tests/test.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@
1919
setTimeout(function() {
2020
$(document.body).html2canvas({
2121
logging: true,
22-
profile: true
22+
profile: true,
23+
useCORS: true
2324
});
2425
}, 100);
2526
};

0 commit comments

Comments
 (0)