Canvas tainted by cross-origin data
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
Why CORS on Images with HTML Canvas?
This protects users from having private data exposed by using images to pull information from remote web sites without permission.
Source: MDN
The canvas has been tainted by cross-origin data local image
For security reasons, many browsers will complain if you try to do certain things (canvas image drawing among them), if you use a file://
URL.
You really should serve both the page and the images from a local HTTP server in order to avoid those restrictions.
Canvas image crossplatform insecure error
An updated look at Html5 Canvas with Cross-Domain content.
Here is an updated look at how cross-domain content affects the html5 canvas and how to work within the security restrictions that apply to cross-domain content
An update is useful today (2016-Jan) because there are several new(ish) methods to allow cross-domain images to be drawn to canvas without tainting the canvas.
Drawing cross-domain content on html5 canvas will cause it to be "tainted"
You can draw an image from another domain on the canvas and it will display on the canvas. Accessing resources from another domain is called "Cross Origin Resource Sharing" -- and is generally known as "CORS" for short.
Drawing CORS content (f.ex: images) will cause the canvas to be "tainted" for security reasons.
If the canvas is tainted you cannot use these canvas & context methods:
context.getImageData
to fetch the pixel data on the canvascanvas.toDataURL
to export the canvas as an image
You can't "trick" canvas into violating its CORS security restrictions -- hopefully you wouldn't even want to try! But you can draw cross-origin images without tainting the canvas by satisfying CORS security restrictions.
The "usual" (and simplest) way of handling images so they don't taint the canvas:
Put your images in the same domain as the webpage. You can have several physical servers delivering content but the image domain must be the same as the html code (or the javascript code) that creates the canvas. CORS restrictions are satisfied and the canvas is not tainted.
Notes about CORS while you're developing on your own computer
Solution#1(!): You can install a web server on your dev computer and serve both the web page files (.html, .js, etc) and your image files (.png, .jpg, etc) from one domain.
The folders of your development computer are declared to be different domains. So drawing an image from a subdirectory on your local disk will violate CORS restrictions because different local folders are different domains.
Solution#2: While doing development, you can put both your webpage files and your image files on your desktop and the images will be declared to be in the same domain and your canvas will not be tainted.
Satisfying CORS restrictions when images are on different domains
Solution#3: You can use cross-domain images on canvas without tainting it. To do that, you must satisfy these requirements:
Clientside: The image object must have the
crossOrigin
attribute set to allow cross-origin content. This property can be set within the html element tag or within javascript. Enabling settings are "anonymous" and "use-credentials".Serverside: The server must be configured to return header(s) indicating that the response contains authorized content.
More than 1 response header might be needed depending on configuration:
Access-Control-Allow-Origin
will return either anonymous authorization (*
) or will return specific authorization based on the request.
Access-Control-Allow-Credentials
is required if authentication requires additional information (like cookies).
Access-Control-Expose-Headers
gives the client access to additional response information.
Enabling cross-domain requests on the server can be complex, especially when serving content that is authorized based on client roles. For additional information about starting configuration, you can visit: http://enable-cors.org/index.html.
Using cross-domain image hosts that allow anonymous access to their images
Solution#4: Some public image hosts allow you to upload images which will be served to clients in a CORS compliant way. Several examples are: imgur and dropbox. Stackoverflow images are hosted on Imgur.
Here's an example of how to serve images on Dropbox.com in a CORS compliant way:
- Sign up for a Dropbox Account.
- You are given several default folders. Upload your images in the special "Public" folder. This is the folder that Dropbox gives CORS compliant anonymous access.
- Right-click on an image you want to serve and select "Copy public link". Your clipboard will have a link to your CORS compliant image.
- Load the image onto your page with the img tag or in javascript.
Here's example code to get a CORS compliant image object from Dropbox using javascript:
var img=new Image();
img.crossOrigin='anonymous';
img.src="https://dl.dropboxusercontent.com/u/139992952/multple/sun.png";
img.onload=start;
function start(){
context.drawImage(img,0,0);
// The canvas is not tainted so
// the following both work without errors
var url=canvas.toDataURL();
var imageData=context.getImageData(0,0,100,100);
}
New(ish): Satisfy CORS by having the clientside user give consent
CORS security restrictions are meant to stop bad people from secretly taking your information while leaving you unaware.
Until recently, browsers relied on client-server configuration to satisfy security requirements. Recently, browsers have begun allowing cross-origin content if the user is affirmatively involved in deciding what content is being used.
Solution#5: Chrome and Firefox now allow the client-user to right click the canvas & save the canvas as an image
. This is the manual equivalent of using canvas.toDataURL
to create an image object and save that image object to the local drive. CORS is satisfied because the user decided if the canvas content was appropriate to save to their local drive and they affirmatively right-click to initiate the download process.
Solution#6: You can use an input element, type='file'
to let the client-user select an image. The user can even select an internet URL (http://...). Again, CORS is satisfied because the user is involved in the selection process.
Here's example code showing how to listen for the user to select an image using an input:
// canvas varsvar canvas=document.createElement("canvas");var ctx=canvas.getContext("2d");
// define max resulting image width,height (after resizing)var maxW=100;var maxH=100;
// listen for user to select filesvar input = document.getElementById('input');input.addEventListener('change', handleFiles);
function handleFiles(e) { var img = new Image; img.onload = function(){ var iw=img.width; var ih=img.height; // scale down, if necessary if(iw>maxW || ih>maxH){ var scale=Math.min((maxW/iw),(maxH/ih)); iw*=scale; ih*=scale } // set canvas width/height to scaled size canvas.width=iw; canvas.height=ih; // draw+scale the img onto the canvas ctx.drawImage(img,0,0,iw,ih); // create a jpeg URL (with medium quality to save "weight") var jpg=canvas.toDataURL('image/jpeg',0.60); // In Demo: add the jpg to the window // In production, accumulate jpg's & send to server $('<img />',{src:jpg}).appendTo('body'); } // In Demo: Just process the first selected file // In production: process all selected files img.src = URL.createObjectURL(e.target.files[0]);}
body{ background-color: ivory; }#canvas{border:1px solid red;}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script><h4>You can even enter a web URI (http://...)</h4><input type="file" id="input"/><br>
HTML5 video screenshot via canvas using CORS
I have answered my own question.
What a horrible headache I now have.
The problem lies somewhere in the nuanced specification of the HTML5 video crossorigin/CORS specification.
I only tested in Chrome and Edge, but here is what you need to know at the time of writing:
Chrome
Loading your HTML5 video will fail if you have crossOrigin
set, but your video is being served from any port other than 80 and is not using https
:
THIS WILL FAIL
Client at http://www.myapp.com/player.html:
<video crossOrigin="anonymous" src="http://cdn.myapp.com:81/video.mp4"></video>
THIS WILL SUCCEED
Client at http://www.myapp.com/player.html:
<video crossOrigin="anonymous" src="https://cdn.myapp.com:81/video.mp4"></video>
Chrome and Edge
getImageData()
and toDataURL()
will be security blocked unless:
- crossorigin is set to
anonymous
oruse-credentials
(as defined here) before the video is loaded. If you do this too late, it will still fail.
All
Finally, if you are going to set crossOrigin
in javascript, be sure to use the correct casing for the javascript property: crossOrigin
(NOT crossorigin
)
I have written this up in a little more detail in my blog.
Tainted canvases may not be exported
For security reasons, your local drive is declared to be "other-domain" and will taint the canvas.
(That's because your most sensitive info is likely on your local drive!).
While testing try these workarounds:
Put all page related files (.html, .jpg, .js, .css, etc) on your desktop (not in sub-folders).
Post your images to a site that supports cross-domain sharing (like dropbox.com or GitHub). Be sure you put your images in dropbox's public folder and also set the cross origin flag when downloading the image (
var img=new Image(); img.crossOrigin="anonymous"
...)Install a webserver on your development computer (IIS and PHP web servers both have free editions that work nicely on a local computer).
Related Topics
Pass Vars to JavaScript Via the Src Attribute
Html 5 Video or Audio Playlist
Jquery Event Won't Fire After Ajax Call
How to Display a JavaScript Var in HTML Body
How to Simulate a Mouseover in Pure JavaScript That Activates the CSS ":Hover"
How to Access CSS Generated Content With JavaScript
Changing Width Property of a :Before CSS Selector Using Jquery
How to Return the Response from an Asynchronous Call
Compare Two Dates With JavaScript
Calculate Distance Between Two Points in Google Maps V3
How to Pass Parameter to Function Using in Addeventlistener
JavaScript Get Element by Name
How to Make Internet Explorer Emulate Pointer-Events:None
Toggle Show/Hide Div With Button
Add/Remove Class With Jquery Based on Vertical Scroll