JavaScript Draw in a Canvas Disappear After Setting crossOrigin as Anonymous - javascript

I am currently doing a javascript function that draws in an HTML canvas by doing some drawing inside of it AND loading an image from another website.
Everything was working fine until I needed to create a function to download it. At first, I was getting a security error because I didn't set the crossOrigin of the image I was loading as anonymous so I did. And then I was able to download the image. However, it made the image that I loaded in the canvas from the other website disappear. Any idea why?
Here is my function to download:
function download(){
var canvas=document.getElementById("canvas0");
$("#btn-download").on("click",(e)=>{
var data = canvas.toDataURL("data:image/png;");
var btn=document.getElementById("btn-download");
btn.href=data;
btn.download="Canvas.png";
});
}
And here is where I load the image and set the crossOrigin as anonymous.
img=new Image();
img.onload = function() {
context.drawImage(img, 285, 160);
};
img.src = 'somelink';
img.crossOrigin = "anonymous"
Thanks for your help!

Okay, after a lot of thinking, i realized that when the website was giving me the image, the Access-Control-Allow-Origin wasn't in the header SO it was impossible to avec the crossOrigin to anonymous.
If you have this problem, check in your console if the header has Access-Control-Allow-Origin or not.

Related

Delete exif data (xmp) from image in React

I have spent my entire day trying to delete EXIF data from images with React. I want to do this for try to solve another problem, when user uploads an image with XMP data, apparently AWS WAF blocks it (I didn't have problems with another kind of data, I dind't tried everything tho, but I used an image with camera information and blabla and it worked just fine. Plus, I deleted XMP data from problematic images with a software, and WAF didn't blocked it anymore). So, I want to delete XMP data (author, creator tool, etc.) before send it to server.
I'm using react-dropzone for upload the images, and today I tried different libraries for achieve this, without success. With exifr and exif-js I can see all the EXIF information (including XMP) and specificcaly the data that is causing the error in the upload, but I didn't find a way to remove that from the picture. On the other hand, I used piexifjs and worked fine for delete information, but I couldn't find XMP data!! Just gps, EXIF with camera and picture settings, plus a couple of thing not of my interest. What can I do? I'm able to see this information with exif-js and exifr, but I just can delete things with pixiefjs in which I can't see xmp data.
I do not provide code because it is not an error as such, I want library recommendations or, if exists, a way to configure piexifjs for find this kind of data. exif-js and exifr are for reading, not for removing.
Thanks a lot.
Here would be a sample code of mine:
With a right on the image you should be able to download the image and there should be no exif data included. But I am unsure if there is a better way to do that.
document.getElementById('upload').onchange = function() {
const img = new Image();
img.src = URL.createObjectURL(this.files[0]);
img.onload = function() {
//canvas
const canvas = document.createElement('canvas');
canvas.width = this.width;
canvas.height = this.height;
const ctx = canvas.getContext('2d');
ctx.drawImage(this, 0,0);
//image in html
newImg = document.getElementById('img');
newImg.src = canvas.toDataURL();
newImg.style.width = this.width;
newImg.style.height = this.height;
};
img.onerror = function() {console.error("The file is not an image")};
};
<!doctype html>
<html>
<head>
<meta charset="utf-8">
</head>
<body>
<input type="file" id="upload">
<img id="img"></img>
<script src="script.js"></script>
</body>
</html>
I'm unsure if it couldn't be simpler, but you could create a canvas with the size of the image, load the image into it, and write the image data from the canvas to a new image file.

CORS issue with canvas only when image is preloaded

My issue only arises when the loaded image was preloaded somewhere else. For example, when I somewhere use a <img>-tag with the src attribute.
Have a look at this code:
<canvas id="myCanvas" width="300" height="150" style="border:1px solid #d3d3d3;" ></canvas>
<img src="https://local-spaces.fra1.digitaloceanspaces.com/test.jpg" width="50"/>
<button onclick="show()">Load Canvas Picture</button>
<script>
function show() {
const c = document.getElementById("myCanvas");
const ctx = c.getContext("2d");
const img = new Image();
img.setAttribute('crossOrigin', 'anonymous');
img.onload = function(){
ctx.drawImage(img,0,0, 300, 150);
};
img.src = "https://local-spaces.fra1.digitaloceanspaces.com/test.jpg"
}
</script>
Note: If you are seeing the image in canvas correctly, please cache+hardreload your browser to see the error.
If you are clicking on the button and open your console, you will see that you are getting a CORS-error:
Access to image at
'https://local-spaces.fra1.digitaloceanspaces.com/test.jpg' from
origin 'null' has been blocked by CORS policy: No
'Access-Control-Allow-Origin' header is present on the requested
resource.
Now let's take the next example to see that it is working without preloading the image: https://jsfiddle.net/akzxp9vs/
Note: To make this example work, it's super important that you are deleting your cache + hard reload your browser.
Only then you see that the correct header response is giving back.
Any ideas what I can do?
The image is on the S3 Cloud of Digital Ocean, called Spaces. The image itself is set to public and the CORS setting are set to:
The browser needs to know to check for CORS permissions when the HTTP request is made (i.e. to include an Origin header etc).
When you create a new Image object, it uses the cached data from the <img> element.
Add a crossorigin attribute to the existing <img> element or remove that <img> element entirely.
I found a better solution to my problem. #Quentin's solution is principally right, but it's just not practicable. I tried to update all <img>-tags, however in my page I have dozens of packages that are using the <img>-tag as well.
For example Leaflet. It's like Google Maps, but with Open Street Maps. You just don't have the control over to set attributes like crossorigin in custom icons.
So there had to be another solution. It feels bad to use it, but it does the job.
const src = new URL(imgUrl);
src.searchParams.append('cors', Date.now());
return src.href;
This code appends to your URL a query parameter and forces Chrome to reload the image without being cached.

What does HTMLImageElement crossOrigin work?

I load an image and then I try to use this in the PIXI. But PIXI loads image again when I create a PIXI.Texture. If I set crossOrigin to "anonymous" it works fine and doesn't download a picture again. But how it works and what does it mean? Will it work on the internet or it works local only?
That's what I do that download image
image.crossOrigin = "anonymous";
image.src = "filePath";
image.addEventListener("load", doSomethingFunction, false);

html5 Image Filters with Canvas

I have download the source from this http://www.storminthecastle.com/projects/imagefilters1/. It is regarding some image manipulation in html5 canvas.
Inside the source, it will load the image located in a local directory...
function reset() {
imageURL = "./sandbox.jpg";
imageFilter = grayscale;
document.querySelector("#filename").innerHTML = "";
update();
}
The above is working in my project. But I am trying to load an image from an url, so I modified it to the following...
function reset() {
imageURL = "http://xxxxxx.jpg";
imageFilter = grayscale;
document.querySelector("#filename").innerHTML = "";
update();
}
When I test it, the image is being displayed correctly. However, all the features are not working anymore and I don't know why. I have no idea why it cannot take in url as the argument and I don't know how to modify it to make it work. Any helps?
Thanks for the link provided. I further read on the COR issue and managed to locate that line of coding to be added.
img.crossOrigin = '';
//img domain different from app domain
img.src = 'http://xxx.jpg';
Simply set the crossOrigin property of the image to make it work. Basically, this will allow cross domain image for manipulation. Without it, any cross domain will be blocked and you will get the security exception. Really thanks for the helps! :)
To add-on, I have only tested using Chrome and is working.

Download a Html5 canvas element as an image with the file extension with Javascript

I would like to be able to download a Html5 canvas element as an image with the file extension with Javascript.
The CanvasToImage library does not seem to be able to achieve this.
Here is my code so far which you can see at this JsFiddle.
<div id="canvas_container">
</div>
<p>
create
download
</p>
$("#create_image").click(function() {
var cnvs = createSmileyOnCanvas();
$('#canvas_container').append(cnvs);
});
$("#download_image").click(function() {
var img = $('#smiley_canvas').toDataURL("image/png");
var uriContent = "data:application/octet-stream," + encodeURIComponent(img);
window.open(uriContent, 'download smiley image');
});
function createSmileyOnCanvas() {
var canvas = document.createElement('canvas');
canvas.id = 'smiley_canvas';
var ctx = canvas.getContext('2d');
// Draw shapes
ctx.beginPath();
ctx.arc(75,75,50,0,Math.PI*2,true); // Outer circle
ctx.moveTo(110,75);
ctx.arc(75,75,35,0,Math.PI,false); // Mouth
ctx.moveTo(65,65);
ctx.arc(60,65,5,0,Math.PI*2,true); // Left eye
ctx.moveTo(95,65);
ctx.arc(90,65,5,0,Math.PI*2,true); // Right eye
ctx.stroke();
return canvas;
}
This seems to work for me:
<a id="downloadImgLink" onclick="$('#downloadImgLink').attr('href', canvas.toDataURL());" download="MyImage.png" href="#" target="_blank">Download Drawing</a>
In order to force/suggest a file name in the browser's download dialog, you would need to send the Content-Disposition: attachment; filename=foobar.png header.
This is not possible to do via window.open, so you're out of luck unless there are some browser-specific hacks for this.
If you really need the filename, you could try using the new download attribute in a, <a href="put stuff here" download="filename here">. It isn't very widely supported yet though.
Another alternative would be to first submit the data to the server using ajax, then redirect the browser to some server-side script which would then serve the data with the correct header.
Hi i have created a jquery plugin which will let you do the same task with ease but it also make use of php to download the image. let me explain how it works
Plugin has 2 sub function that you can call independently to add image to the canvas and the other one is to download the current image lying on the canvas.
Add image to the canvas
For this you need to pass the id of the canvas element and the path of the image you want to add
download image from the canvas
For this you need to pass the id of the canvas element
$('body').CanvasToPhp.upload({
canvasId: "canvas", // passing the canvasId
image: "455.jpg" // passing the image path
});
// downloading file
$('#download').click(function(){
$('body').CanvasToPhp.download({
canvasId: "canvas" // passing the canvas id
}); //
});
First you need to download the plugin file which you can find here http://www.thetutlage.com/post=TUT213
I have also created a little demo http://thetutlage.com/demo/canvasImageDownload

Categories