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

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.

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.

Javascript: Download image from img tag which's src url supports only one time request and Tainted by crossOrigin

I have an image in my html dom
(the green border image) it has a img tag and having a src url.
I've tried with fetch by retrieving blob but request isn't supporting second request. Server is refusing to get image for second time.
So I've tried with canvas with
ctx.drawImage(imgNode, 0,0)
and tried placing it in dom. The canvas copies the image.
But when I tried getting toDataURL and getImageData
it shows following errors.
Later, I tried with imgnode.crossOrigin = 'anonymouse'
But then Image breaks.
I've checked by right click > copy image Then I can paste image somewhere else.
So how am I supposed to save this image/copy this image in my local disk.
I'm using selenium with python. I want to retrieve image.
Run this javascript code on the page and create an alert(). You can change the "image/jpeg" to png or as it is.
function getBase64Image(img) {
var canvas = document.createElement("canvas");
canvas.width = img.width;
canvas.height = img.height;
var ctx = canvas.getContext("2d");
ctx.drawImage(img, 0, 0);
var dataURL = canvas.toDataURL("image/jpeg");
return dataURL.replace(/^data:image\/(png|jpg|jpeg);base64,/, "");
}
alert(getBase64Image(document.getElementById("ImgCaptcha")))
In your application, make a listener to the alert and capture the base64 image value.

How can I make a image appear in javascript (and scroll whilst zoomed in)

I am very new to JavaScript. I'm trying to create a basic infinite runner game, but I'm stuck on one little issue. I need a image to print out on my HTML canvas, but when I try to nothing happens. I am creating this game with basic JavaScript. No AJAX/jQuery. Here's my code, and what I have tried.
//this is my code as of right now for printing images.
function make_base () {
base_image = new Image();
base_image.src = 'picture.png'
}
//draw the image to the canvas 2d context
cc.drawImage(base_image, 0, 0);
What this is doing, is nothing. It is not showing any sign of a image. Here's some other code I've gotten, as from w3schools (they're awesome :) )
//image source by html hidden element
var img = document.getElementById("picture");
cc.drawImage(img, 10, 10);
</script>
<image src="picture.png" id="picture" hidden></image>
This is doing the same thing that the new code is doing. Showing absolutely nothing. I'm not sure why, I've tried with Google Chrome, Firefox, and Internet Explorer. All of them with the file uploaded to my website, and with file:///c:/users/name/desktop/js/one.html. Nothing is showing up on the canvas for some strange reason. I've also told Chrome to always use JavaScript. Not only this, but how can I make it zoom in, and scroll from left to right (I can add the blocks/variables that "kill"/make the player restart)?
You probably need to wait for the image to load before trying to draw it.
const c = document.querySelector('canvas')
const cc = c.getContext('2d');
drawImage();
function drawImage() {
const image = new Image();
image.onload = function() {
cc.drawImage(image, 0, 0)
}
image.src = "//placecage.com/200/300"
}
<canvas width="500" height="500"></canvas>
Also, it's <img> not <image>. I haven't checked this, but some browsers don't allow loading things if you're on file://, you'll have to spin up a small server and serve from localhost.

canvas has been tainted by cross-origin data work around

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.

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!

Categories