canvas has been tainted by cross-origin data work around - javascript

im writing a script (or editing and hacking things together) to edit the look of images on a page. I know the basics of javascript but this is my first time looking at canvas. so bear with me
I'm getting this error:
Unable to get image data from canvas because the canvas has been tainted by cross-origin data.
so heres my code snippet throwing the error:
var canvas = document.createElement('canvas'),
context = canvas.getContext('2d'),
height = img.naturalHeight || img.offsetHeight || img.height,
width = img.naturalWidth || img.offsetWidth || img.width,
imgData;
canvas.height = height;
canvas.width = width;
context.drawImage(img, 0, 0);
console.log(context);
try {
imgData = context.getImageData(0, 0, width, height);
} catch(e) {}
now i found this post :
http://bolsterweb.com/2012/06/grabbing-image-data-external-source-canvas-element/
but i have no idea how to make it fit my needs..
I know its all due to security and all that - but is there a work around to make it all happen?
Thanks
EDIT
Oh wait.. the error is because you can't getImageData.. so is there away to make it 'local'

To satisfy CORS, you can host your images on a CORS friendly site like dropbox.com
Then the security error will not be triggered if you speify image.crossOrigin="anonymous":
var image=new Image();
image.onload=function(){
}
image.crossOrigin="anonymous";
image.src="https://dl.dropboxusercontent.com/u/139992952/stackoverflow/colorhouse.png";
Here is code and a Fiddle: http://jsfiddle.net/m1erickson/4djSr/
<!doctype html>
<html>
<head>
<link rel="stylesheet" type="text/css" media="all" href="css/reset.css" /> <!-- reset css -->
<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>
<style>
body{ background-color: ivory; }
#canvas{border:1px solid red;}
</style>
<script>
$(function(){
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var image=new Image();
image.onload=function(){
ctx.drawImage(image,0,0);
// desaturation colors
var imgData=ctx.getImageData(0,0,canvas.width,canvas.height);
var data=imgData.data;
for(var i = 0; i < data.length; i += 4) {
var grayscale= 0.33*data[i]+0.5*data[i+1]+0.15*data[i+2];
data[i]=grayscale;
data[i+1]=grayscale;
data[i+2]=grayscale;
}
// write the modified image data
ctx.putImageData(imgData,0,0);
}
image.crossOrigin="anonymous";
image.src="https://dl.dropboxusercontent.com/u/139992952/stackoverflow/colorhouse.png";
}); // end $(function(){});
</script>
</head>
<body>
<canvas id="canvas" width=140 height=140></canvas>
</body>
</html>

I don't have enough reputation to actually add a comment (but I do have enough to respond to the question, huh??), I just wanted to add to markE's answer that I had to capitalize Anonymous.
image.crossOrigin = "Anonymous"

I found it works with chrome if you create a windows shortcut like this:
"C:\Program Files (x86)\Google\Chrome\Application\chrome.exe" --allow-file-access-from-files
Shut down chrome and start it via your shortcut.
Source:
https://github.com/mrdoob/three.js/wiki/How-to-run-things-locally
Related post:
Cross-origin image load denied on a local image with THREE.js on Chrome
I assume you are working with a local file without any web server.

Try adding crossorigin="anonymous" to the image element. For example
<img src="http://example.com/foo.jpg" crossorigin="anonymous"/>

Enabling CORS on the server side is a way out, But that's if you have access to the server side. That way the server serves CORS enabled images.

Related

canvas uses toDataURL("image/jpeg") to get a blank image

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div>Test</div>
<canvas id="canvas"></canvas>
<script>
const data = ""//long char,base64 in github
</script>
<script>
function watermarking(file, date, callback) {
const img = new Image();
img.src = file;
img.onload = function () {
const canvas = document.querySelector("canvas");
const ctx = canvas.getContext("2d");
let width = img.width;
let height = img.height;
canvas.width = width;
canvas.height = height;
ctx.drawImage(img, 0, 0, width, height);
const newBase64 = canvas.toDataURL("image/jpeg");
callback(newBase64);
};
img.onerror = (e) => {
console.log(e);
};
}
watermarking(data, "2022-11-11", (base64) => {
console.log("base64 url:", base64)
})
</script>
</body>
</html>
When I use this image to get base64 url, canvas toDataURL() gets a blank image, other images get the desired effect, I don't know why.
Result from chrome log, there are many A!!!!.
From the results, it should be that the asynchronous somewhere does not take effect, resulting in toDataURL or drawImage() getting a blank image.
enter link description here
There is definitely something odd happening here.
First thing to note, the image that's contained in your data seems to be corrupted, at least Photoshop refuses to open it claiming that "an unexpected end-of-file was encountered.".
And indeed trying with any other image or even the same opened in macOS Preview app, and saved with the same settings does work fine.
So the best is to reencode your image. If it happens more often, you may want to open a new question, explaining how you are producing this image.
As for the odd part, it's that the browser is actually able to open and decode that image, but it seems that Chrome won't do this decode before being asked but still will fire the load event, and it won't wait for the image to be decoded before returning from drawImage. This is a bug on their part. drawImage is synchronous, and it's supposed to wait for the image is decoded before returning. My educated guess is that Chrome expects the decoding to already have happened when the load event fires and thus they don't check in the drawImage code farther than is_loaded.
Anyway, a quick workaround for that is to call the HTMLImageElement.decode() method, which will return a Promise resolving when the decoding is entirely done, even for this seemingly broken image.
But once again the best for you is to reencode that image.

HTML 5 canvas toDataURL changed raw data

I use canvas to draw an image only, but toDataURL() value is different with raw data even if canvas did not change.
the code as blow:
<html>
<head>
<title>For test</title>
<script type="text/javascript">
window.onload = function() {
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
var img = document.getElementById("scream");
img.crossOrigin = 'Anonymous';
ctx.drawImage(img, 0, 0);
console.log(c.toDataURL().length);
console.log("data:img/jpg;base64,iVBORw0KGgoAAAANSUhEUgAAADUAAAAzCAIAAAC43dc6AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAABPSURBVGhD7dOhAQAgDMAw/n96GCyqZiK5oKZndtPX6Gv0NfoafY2+Rl+jr9HXrO8D/t4nW+lr9DX6Gn2NvkZfo6/R1+hr9DX6Gn3N7r6ZCxmTdxPs4RLCAAAAAElFTkSuQmCC".length);
}
</script>
</head>
<body>
<p>Image to use:</p>
<img id="scream" src="data:img/jpg;base64,iVBORw0KGgoAAAANSUhEUgAAADUAAAAzCAIAAAC43dc6AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAABPSURBVGhD7dOhAQAgDMAw/n96GCyqZiK5oKZndtPX6Gv0NfoafY2+Rl+jr9HXrO8D/t4nW+lr9DX6Gn2NvkZfo6/R1+hr9DX6Gn3N7r6ZCxmTdxPs4RLCAAAAAElFTkSuQmCC" /><p>
<p>Canvas:</p>
<canvas id="myCanvas" width="53" height="51"></canvas>
</body>
Simple: you are re-applying the jpeg compression, which is a lossy process. Unless your original image came from a from the same computer, it's a virtually impossibility that they would match exactly. Even if you used the exact same algo, you have to match the quality factor to get a re-encode match. I don't even see the quality being specified in the code (as an argument to toDataURL()).
Even if you used all the same settings, there's a slight bit of voodoo in these encoders, and a device resolution change, zooming, font updates, or a bogged down CPU can all (potentially) affect the output, due to the dynamic nature of canvas layout. Apps like photoshop are much more repeatable than browsers.

Drawing images to canvas with img.crossOrigin = "Anonymous" doesn't work

In a client-side standalone JS application, I'm trying to make it so I can call toDataURL() on a canvas on which I've drawn some images specified by a URL. Ie I can input into a textbox the url to any image (hosted on, say, imgur) that I want to draw on the canvas, click a "draw" button and it will draw on the canvas. The end user should be able to save their final render as a single image, for this I'm using toDataURL().
Anyway, until they actually fix that annoying "operation is insecure" error (gee, you're going to tell the end user what they can and can't do with their own data?) I followed a workaround that said to add the image to the DOM and set its crossOrigin property to "Anonmyous" and then draw it to the canvas.
Here's a full working simplified version of my code (but in reality there will be many more features):
<!DOCTYPE html5>
<html>
<head>
<style>
#canvas {border:10px solid green;background-color:black;}
#imgbox {border:2px solid black;}
</style>
</head>
<body>
<canvas id="canvas" width=336 height=336></canvas>
<br><br>
<input size=60 id="imgbox">
<input type="submit" value="Draw" onclick=draw()>
<script>
function draw() {
var canvas = document.getElementById("canvas");
var context = canvas.getContext("2d");
var img = new Image();
img.src = document.getElementById("imgbox").value;
img.crossOrigin = "Anonymous";
context.drawImage(img, 40, 40);
}
</script>
</body>
</html>
Without the img.crossOrigin = "Anonymous"; line, I could input http://i.imgur.com/c2wRzfD.jpg into the textbox and click draw and it would work. However as soon as I added that line, the whole thing broke and it won't even be drawn to the canvas at all.
What do I need to change to fix this? I really need to be able to implement the functionality for the end user to save their final image and it's extremely annoying that the people who wrote the html5 spec purposely introduced this bug.
You must set the CORS request before the src - just swap the lines into:
img.crossOrigin = "Anonymous";
img.src = document.getElementById("imgbox").value;
You will also need to add an onload handler to the image as loading is asynchronous:
img.onload = function() {
context.drawImage(this, 40, 40);
// call next step in your code here, f.ex: nextStep();
};
img.crossOrigin = "Anonymous";
img.src = document.getElementById("imgbox").value;
When the server requires authorization to access the images the value should be:
img.crossOrigin = "Use-Credentials";
Otherwise the browser will give up after receiving HTTP 401.
If your image disappears after setting cross origin to anonymous it means your server doesn't allow cross origin. If you're using amazon s3 to serve your images, you need to enable public access to your bucket, and then add cross origin policy (from templates). After that adding cross origin "anonymous" should work.

DOM Security Exception 18: Tainted Canvas

I'm nearly finished with a Javascript/HTML5-based game, and i've been testing it by using Chrome to open the HTML page on my local file system (i haven't uploaded anything anywhere). I'm using Chrome's file:// protocol to do this. But i'm running into a problem... At the beginning of the game, i display an image for a couple seconds before moving onto the menu screen. I pause the game by grabbing the canvas' pixel data, displaying that, then drawing a semi-transparent rectangle across the whole thing, with a crosshair as a custom pointer. However, Chrome is giving me trouble about a DOM Security Exception 18: "Unable to get image data from canvas because the canvas has been tainted by cross-origin data."
So i did some research on the Internet, and it turns out this is because Chrome sees that the image is grabbed from the local file system, and sees this as a security error. Using this question as a reference, i tried doing some research on Cross-Origin Resource Sharing, but quickly got lost. I figured it would be much easier to simply open the test HTML file using http:// and localhost like the question answerer suggested. But i have no idea how to do this, either.
I'd really like to use Chrome to continue testing my game (the developer tools accessed through Ctrl-Shift-I have proved to be invaluable), so i figured there were three solutions: Either figure out what CORS is and how to use it, learn how to open a local file using http://, or somehow hard-code my image data as a variable in my JavaScript script file (like a XPM file in C). I don't know how to do the first two, and i'm trying to avoid the third.
Yes, it’s probably time to download a local web server or sign up for a hosted server.
But if you want to continue testing without a server, you can sign up for a free dropbox.com account and host your images there.
Dropbox allows access to images using CORS friendly crossOrigin=”anonymous”.
Then CORS is no problem on Chrome & Mozilla. But, IE still fails to be CORS friendly—come on IE :(
Here’s how to load an image without CORS problems from dropbox (Chrome & Mozilla, not IE).
The “secret” is setting image.crossOrigin=”anonymous” before setting the image.src:
var externalImage2=document.createElement("img");
externalImage2.onload=function(){
canvas.width=externalImage2.width;
canvas.height=externalImage2.height;
ctx.drawImage(externalImage2,0,0);
// use getImageData to replace blue with yellow
var imageData=recolorImage(externalImage2,0,0,255,255,255,0);
// put the altered data back on the canvas
// this will FAIL on a CORS violation
ctxAnonymous.putImageData(imageData,0,0);
}
externalImage2.crossOrigin = "Anonymous";
externalImage2.src="https://dl.dropboxusercontent.com/u/139992952/stackoverflow/colorhouse.png";
Here is code and a Fiddle: http://jsfiddle.net/m1erickson/YdzHT/
<!doctype html>
<html>
<head>
<link rel="stylesheet" type="text/css" media="all" href="css/reset.css" /> <!-- reset css -->
<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>
<style>
body{ background-color: ivory; }
canvas{border:1px solid red;}
</style>
<script>
$(function(){
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var canvasCORS=document.getElementById("canvasCORS");
var ctxCORS=canvasCORS.getContext("2d");
var canvasAnonymous=document.getElementById("canvasAnonymous");
var ctxAnonymous=canvasAnonymous.getContext("2d");
// Using image WITHOUT crossOrigin=anonymous
// Fails in all browsers
var externalImage1=new Image();
externalImage1.onload=function(){
canvas.width=externalImage1.width;
canvas.height=externalImage1.height;
ctx.drawImage(externalImage1,0,0);
// use getImageData to replace blue with yellow
var imageData=recolorImage(externalImage1,0,0,255,255,255,0);
// put the altered data back on the canvas
// this will FAIL on a CORS violation
ctxCORS.putImageData(imageData,0,0);
}
externalImage1.src="https://dl.dropboxusercontent.com/u/139992952/stackoverflow/colorhouse.png";
// Using image WITH crossOrigin=anonymous
// Succeeds in Chrome+Mozilla, Still fails in IE
var externalImage2=new Image();
externalImage2.onload=function(){
canvas.width=externalImage2.width;
canvas.height=externalImage2.height;
ctx.drawImage(externalImage2,0,0);
// use getImageData to replace blue with yellow
var imageData=recolorImage(externalImage2,0,0,255,255,255,0);
// put the altered data back on the canvas
// this will FAIL on a CORS violation
ctxAnonymous.putImageData(imageData,0,0);
}
externalImage2.crossOrigin = "Anonymous";
externalImage2.src="https://dl.dropboxusercontent.com/u/139992952/stackoverflow/colorhouse.png";
function recolorImage(img,oldRed,oldGreen,oldBlue,newRed,newGreen,newBlue){
var c = document.createElement('canvas');
var ctx=c.getContext("2d");
var w = img.width;
var h = img.height;
c.width = w;
c.height = h;
// draw the image on the temporary canvas
ctx.drawImage(img, 0, 0, w, h);
// pull the entire image into an array of pixel data
var imageData = ctx.getImageData(0, 0, w, h);
// examine every pixel,
// change any old rgb to the new-rgb
for (var i=0;i<imageData.data.length;i+=4)
{
// is this pixel the old rgb?
if(imageData.data[i]==oldRed &&
imageData.data[i+1]==oldGreen &&
imageData.data[i+2]==oldBlue
){
// change to your new rgb
imageData.data[i]=newRed;
imageData.data[i+1]=newGreen;
imageData.data[i+2]=newBlue;
}
}
return(imageData);
}
}); // end $(function(){});
</script>
</head>
<body>
<p>Original external image</p>
<canvas id="canvas" width=140 height=140></canvas>
<p>.getImageData with .crossOrigin='anonymous'
<p>[Succeeds in Chrome+Mozilla, still fails in IE]</p>
<canvas id="canvasAnonymous" width=140 height=140></canvas>
<p>.getImageData without .crossOrigin='anonymous'
<p>[Fails on all browsers]</p>
<canvas id="canvasCORS" width=140 height=140></canvas>
</body>
</html>
Developing using the local file system is generally not a good idea for precisely the reason you have discovered. To use the localhost option you'll need a web server installed on your PC. Google for a WAMP package (Windows, Apache. MysQL, PHP) which should give you everything you need.
Unfortunately, CORS will only work for you if you have a web server!
[edit] You can get a WAMP server from wampserver.com, obviously!

How to fetch image from system to load in canvas in html5

I am using the following way:-
CODE
<!DOCTYPE HTML>
<html>
<head>
<style>
body {
margin: 0px;
padding: 0px;
}
#myCanvas {
border: 1px solid #9C9898;
}
</style>
<script>
window.onload = function() {
var canvas = document.getElementById("myCanvas");
var context = canvas.getContext("2d");
var imageObj = new Image();
imageObj.onload = function() {
context.drawImage(imageObj, 69, 50);
};
imageObj.src = "C:\Images\Demo.jpg";
};
</script>
</head>
<body>
<canvas id="myCanvas" width="578" height="400"></canvas>
</body>
</html>
i want to load this image in canvas. Is it right way to pass image URL in imageObj.src ?
or is there any other way to load the image ?
THANKS IN ADVANCE
You have it nearly right. If you are loading the file locally, you need to prefix your path with file:///:
imageObj.src = "file:///C:/Images/Demo.jpg"; // also, use forward slashes, not backslashes
I think all browsers will require you to have the image stored in the same directory as or in a subdirectory from the current HTML page, so that local HTML pages can't go grabbing things from all over your hard drive.
I'd suggest you make the path relative to your current HTML document. If the page is at file:///C:/Users/shanky/webpages/page.html then just use:
imageObj.src = "img/Demo.jpg";
to load an image located at file:///C:/Users/shanky/webpages/img/Demo.jpg. This makes it easier if you move your page to a new folder or host it on a server, where it no longer uses the file: protocol.
Note that most browsers are pretty finicky about the same origin policy for file: resources. It may be easier to host your application on a simple local server and access it with http://localhost.

Categories