HTML5 Canvas getImageData and Same Origin Policy

I have a site running at pixie.strd6.com and images hosted through Amazon S3 with a CNAME for images.pixie.strd6.com.

I would like to be able to draw these images to an HTML5 canvas and call the getImageData method but it throws Error: SECURITY_ERR: DOM Exception 18

I have tried setting window.domain = "pixie.strd6.com", but that has no effect.

Additionally, $.get("http://dev.pixie.strd6.com/sprites/8516/thumb.png?1293830982", function(data) {console.log(data)}) also throws an error: XMLHttpRequest cannot load http://dev.pixie.strd6.com/sprites/8516/thumb.png?1293830982. Origin http://pixie.strd6.com is not allowed by Access-Control-Allow-Origin.

Ideally HTML5 canvas wouldn't block calling getImageData from subdomains. I've looked into setting an Access-Control-Allow-Origin header in S3, but haven't succeeded.

Any help or workarounds are greatly appreciated.


Amazon recently announced CORS support

We're delighted to announce support for Cross-Origin Resource Sharing (CORS) in Amazon S3. You can now easily build web applications that use JavaScript and HTML5 to interact with resources in Amazon S3, enabling you to implement HTML5 drag and drop uploads to Amazon S3, show upload progress, or update content. Until now, you needed to run a custom proxy server between your web application and Amazon S3 to support these capabilities.

How to enable CORS

To configure your bucket to allow cross-origin requests, you create a CORS configuration, an XML document with rules that identify the origins that you will allow to access your bucket, the operations (HTTP methods) will support for each origin, and other operation-specific information. You can add up to 100 rules to the configuration. You add the XML document as the cors subresource to the bucket.


One possible solution is to use nginx to act as a proxy. Here is how to configure urls going to http://pixie.strd6.com/s3/ to pass on through to S3, but the browser can still believe that it is non-cross domain.

location /s3/ {
  proxy_pass http://images.pixie.strd6.com/;
}

If you are using PHP, you can do something like:

    function fileExists($path){
        return (@fopen($path,"r")==true);
    }
    $ext = explode('.','https://cgdev-originals.s3.amazonaws.com/fp9emn.jpg');
    if(fileExists('https://cgdev-originals.s3.amazonaws.com/fp9emn.jpg')){
        $contents = file_get_contents('https://cgdev-originals.s3.amazonaws.com/fp9emn.jpg');
        header('Content-type: image/'.end($ext));
        echo $contents;
    }

And access the image by using that php file, like if the file is called generateImage.php you can do <img src="http://GENERATEPHPLOCATION/generateImage.php"/> and the external image url can be a get parameter for the file


Recently, I came across $.getImageData, by Max Novakovic. The page includes a couple of neat demos of fetching and operating on Flickr photos, along with some code examples.

It allows you to fetch an image in JavaScript-manipulable form from an arbitrary site. It works by appending a script to the page. The script then requests the image from a Google App Engine server. The server fetches the requested image and relays it converted to base64 to the script. When the script receives the base64, it passes the data to a callback, which can then draw it onto a canvas and begin messing with it.


In the past Amazon S3 didn't allow you to modify or add the access-control-allow-origin and access-control-allow-credentials HTTP headers so it may have been better to switch to a different service like Rackspace Cloud Files or some other service that does.

Add or modify the HTTP headers like this:

access-control-allow-origin: [your site]
access-control-allow-credentials: true

See http://www.w3.org/TR/cors/#use-cases for more information.

Using a service that allows you to modify the HTTP headers entirely solves the same origin problem.