I want to save my canvas to a img
. I have this function:
function save() {
document.getElementById("canvasimg").style.border = "2px solid";
var dataURL = canvas.toDataURL();
document.getElementById("canvasimg").src = dataURL;
document.getElementById("canvasimg").style.display = "inline";
}
It gives me error:
Uncaught SecurityError: Failed to execute 'toDataURL' on 'HTMLCanvasElement': Tainted canvases may not be exported.
What should I do?
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).
In the img tag set crossorigin to Anonymous.
<img crossorigin="anonymous" />
image.crossOrigin = 'Anonymous'
won't help once the image has been loaded. But if a reload is an option you can go for something like: document.querySelectorAll('img').forEach(image => { image.crossOrigin = 'Anonymous'; image.src += ' '; })
. See also this article on MDN for reference.
crossOrigin
worked.
If someone views on my answer, you maybe in this condition:
1. Trying to get a map screenshot in canvas using openlayers (version >= 3)
2. And viewed the example of exporting map
3. Using ol.source.XYZ to render map layer
Bingo!
Using ol.source.XYZ.crossOrigin = 'Anonymous' to solve your confuse. Or like following code:
var baseLayer = new ol.layer.Tile({
name: 'basic',
source: new ol.source.XYZ({
url: options.baseMap.basic,
crossOrigin: "Anonymous"
})
});
In OpenLayers6, something is changed with ES6. However, the code is similar.
import { XYZ } from 'ol/source'
import { Tile as TileLayer } from 'ol/layer'
const baseLayer = new TileLayer({
name : 'basic',
source: new XYZ({
url: 'example.tile.com/x/y/z', // your tile url
crossOrigin: 'Anonymous',
// remove this function config if the tile's src is nothing to decorate. It's usually to debug the src
tileLoadFunction: function(tile, src) {
tile.getImage().src = src
}
})
})
https://i.stack.imgur.com/qsgp8.png
If you're using ctx.drawImage()
function, you can do the following:
var img = loadImage('../yourimage.png', callback);
function loadImage(src, callback) {
var img = new Image();
img.onload = callback;
img.setAttribute('crossorigin', 'anonymous'); // works for me
img.src = src;
return img;
}
And in your callback you can now use ctx.drawImage
and export it using toDataURL
Tainted canvases may not be exported.
error message.
In my case I was drawing onto a canvas tag from a video with something like canvas.drawImage(video, 0, 0)
. To address the tainted canvas error I had to do two things:
<video id="video_source" crossorigin="anonymous">
<source src="http://crossdomain.example.com/myfile.mp4">
</video>
Ensure Access-Control-Allow-Origin header is set in the video source response (proper setup of crossdomain.example.com)
Set the video tag to have crossorigin="anonymous"
I resolved the problem using useCORS: true
option
html2canvas(document.getElementsByClassName("droppable-area")[0], { useCORS:true}).then(function (canvas){
var imgBase64 = canvas.toDataURL();
// console.log("imgBase64:", imgBase64);
var imgURL = "data:image/" + imgBase64;
var triggerDownload = $("<a>").attr("href", imgURL).attr("download", "layout_"+new Date().getTime()+".jpeg").appendTo("body");
triggerDownload[0].click();
triggerDownload.remove();
});
Seems like you are using an image from a URL that has not set correct Access-Control-Allow-Origin header and hence the issue.. You can fetch that image from your server and get it from your server to avoid CORS issues..
Check out CORS enabled image from MDN. Basically you must have a server hosting images with the appropriate Access-Control-Allow-Origin header.
You will be able to save those images to DOM Storage as if they were served from your domain otherwise you will run into security issue.
var img = new Image, canvas = document.createElement("canvas"), ctx = canvas.getContext("2d"), src = "http://example.com/image"; // insert image url here img.crossOrigin = "Anonymous"; img.onload = function() { canvas.width = img.width; canvas.height = img.height; ctx.drawImage( img, 0, 0 ); localStorage.setItem( "savedImageData", canvas.toDataURL("image/png") ); } img.src = src; // make sure the load event fires for cached images too if ( img.complete || img.complete === undefined ) { img.src = "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///ywAAAAAAQABAAACAUwAOw=="; img.src = src; }
This one can work smoothly in laravel.
First of all, you need to convert tainted canvas to blob. after that, you can upload a blob to serve and save it as an image. Return image URL in ajax call.
Here is an ajax call to upload canvas blob.
$("#downloadCollage").click(function(){
canvas.toBlob(function(blob){
var formDataToUpload = new FormData();
formDataToUpload.append("_token", "{{ csrf_token() }}");
formDataToUpload.append("image", blob);
$.ajax({
url:"{{ route('selfie_collage_upload') }}",
data: formDataToUpload,
type:"POST",
contentType:false,
processData:false,
cache:false,
dataType:"json",
error:function(err){
console.error(err);
},
success:function(data){
window.location.href= data.url;
},
complete:function(){
}
});
},'image/png');
link.click();
});
Just as a build on @markE's answer. You can serve your website via a local server. You won't have this error on a local server.
If you have PHP installed on your computer (some older MacOS versions has it preinstalled):
Open up your terminal/cmd Navigate into the folder where your website files are While in this folder, run the command php -S localhost:3000 Open up your browser and in the URL bar go to localhost:3000. Your website should be running there.
or
If you have Node.js installed on your computer:
Open up your terminal/cmd Navigate into the folder where your website files are While in this folder, run the command npm init -y Run npm install live-server -g or sudo npm install live-server -g on a mac Run live-server and it should automatically open up a new tab in the browser with your website open.
Note: remember to have an index.html file in the root of your folder or else you might have some issues.
php --version
to see what version you have installed.
httpd.conf
, but seems like it was there on older OSes. There is a line with comment: #PHP was deprecated in macOS 11 and removed from macOS 12
Both of your linked articles are just wrong. php --version
says command not found
, while php is not part of mac :)
I also solved this error by adding useCORS : true,
in my code like -
html2canvas($("#chart-section")[0], {
useCORS : true,
allowTaint : true,
scale : 0.98,
dpi : 500,
width: 1400, height: 900
}).then();
In my case I was testing it from my desktop, having CORS error even after saving image locally to sub-folder.
Solution:
Moved the folder to local server WAMP in my case. Worked perfect from local server.
Note: Works only when you have saved image locally.
For anyone who still encountering the same issue from S3 even after applying the server cross-origin settings, it probably a browser caching issue. So you need to make sure to disable the caching and test again, you can do that from the browser dev-tools -> network tab -> click on disable cash option -> try again:
https://i.stack.imgur.com/PhZPl.png
Success story sharing