Canvas tainted by cross-origin data

51,616

Solution 1

You cannot reset the crossOrigin flag once it is tainted, but if you know before hand what the image is you can convert it to a data url, see Drawing an image from a data URL to a canvas

But no, you cannot and should not be using getImageData() from external sources that don't support CORS

Solution 2

While the question is very old the problem remains and there is little on the web to solve it. I came up with a solution I want to share:

You can use the image (or video) without the crossorigin attribute set first and test if you can get a HEAD request thru to the same resource via AJAX. If that fails, you cannot use the resource. if it succeeds you can add the attribute and re-set the source of the image/video with a timestamp attached which reloads it.

This workaround allows you to show your resource to the user and simply hide some functions if CORS is not supported.

HTML:

<img id="testImage" src="path/to/image.png?_t=1234">

JavaScript:

var target = $("#testImage")[0];
    currentSrcUrl = target.src.split("_t=").join("_t=1"); // add a leading 1 to the ts
$.ajax({
    url: currentSrcUrl,
    type:'HEAD',
    withCredentials: true
})
.done(function() {
    // things worked out, we can add the CORS attribute and reset the source
    target.crossOrigin = "anonymous";
    target.src = currentSrcUrl;
    console.warn("Download enabled - CORS Headers present or not required");
    /* show make-image-out-of-canvas-functions here */
})
.fail(function() {
    console.warn("Download disabled - CORS Headers missing");
    /* ... or hide make-image-out-of-canvas-functions here */
});

Tested and working in IE10+11 and current Chrome 31, FF25, Safari 6 (Desktop). In IE10 and FF you might encounter a problem if and only if you try to access http-files from a https-script. I don't know about a workaround for that yet.

UPDATE Jan 2014:

The required CORS headers for this should be as follows (Apache config syntax):

Header set Access-Control-Allow-Origin "*"
Header set Access-Control-Allow-Headers "referer, range, accept-encoding, x-requested-with"

the x-header is required for the ajax request only. It's not used by all but by most browsers as far as I can tell

Solution 3

Also worth noting that the CORS will apply if you are working locally regardless of if the resource is in the same directory as the index.html file you are working with. For me this mean the CORS problems disappeared when I uploaded it to my server, since that has a domain.

Solution 4

You can use base64 of the image on canvas, While converting into base64 you can use a proxy URL (https://cors-anywhere.herokuapp.com/) before your image path to avoid cross-origin issue

check full details here

https://stackoverflow.com/a/44199382/5172571

var getDataUri = function (targetUrl, callback) {
    var xhr = new XMLHttpRequest();
    xhr.onload = function () {
        var reader = new FileReader();
        reader.onloadend = function () {
            callback(reader.result);
        };
        reader.readAsDataURL(xhr.response);
    };
    var proxyUrl = 'https://cors-anywhere.herokuapp.com/';
    xhr.open('GET', proxyUrl + targetUrl);
    xhr.responseType = 'blob';
    xhr.send();
};
getDataUri(path, function (base64) {
    // base64 availlable here
})
Share:
51,616
clwen
Author by

clwen

A data geek and Python enthusiast.

Updated on July 09, 2022

Comments

  • clwen
    clwen almost 2 years

    I'm loading a motion jpeg from third-party site, which I can trust. I'm trying to getImageData() but the browser (Chrome 23.0) complains that:

    Unable to get image data from canvas because the canvas has been tainted by
    cross-origin data.
    

    There are some similar questions on SO, but they are using local file and I'm using third party media. My script runs on a shared server and I don't own the remote server.

    I tried img.crossOrigin = 'Anonymous' or img.crossOrigin = '' (see this post on the Chromium blog about CORS), but it didn't help. Any idea on how can I getImageData on a canvas with cross-origin data? Thanks!

  • clwen
    clwen over 11 years
    Thanks for replying. Not sure we can apply toDataURL() to mjpeg, but I'll give it a try. Why no? security reason? Is there specific configuration external server should do? Or even they don't have that configuration, I can use toDataURL to do so.
  • Paul Kaplan
    Paul Kaplan over 11 years
    Here is a fairly comprehensive guide on CORS support html5rocks.com/en/tutorials/cors. And yeah it is a large security issue.
  • Meekohi
    Meekohi over 11 years
    Can this work even with CORS? I have not had success with it.
  • clwen
    clwen over 10 years
    Thanks for replying. So for "working" you meant that one could do getImageData on this external resource? If we do the workaround as you mentioned.
  • chadpeppers
    chadpeppers over 10 years
    This is correct as I had the same issue. I am using phpstorm to view it, which uses a mock server itself and works.
  • Tomáš Zato
    Tomáš Zato over 9 years
    How do I know before hand? Imagine you've got an <img> tag and you have no idea what it is... How do you know if you can draw it or if you need to load it using crossorigin="anonymous"?
  • Noumenon
    Noumenon almost 8 years
    I work locally by using python -m http.server port 8080 in my working folder, then visiting http://localhost:8080.
  • Kristopher Ives
    Kristopher Ives almost 8 years
    For PHP you can use php --server localhost:8080
  • avocado
    avocado almost 8 years
    @Noumenon, +1 for the python server hint
  • Kaiido
    Kaiido over 7 years
    Old answer, but just to note that the other way around seems easier : first set the crossOrigin of your img tag, listen to its error event handler, set the remote src, if it fires, you know you'll taint the canvas.
  • gbtimmon
    gbtimmon over 5 years
    @TomášZato You dont, because that is exactly what CORS is trying to prevent. It should only be allow IF you know before hand what the image is and if it is safe.
  • tmpmachine
    tmpmachine over 3 years
    Here's another option: you can cache the image with Cache API