I'm getting the following javascript error when I try to get data from a canvas element:
Error: canvas.toDataURL() not supported. [Exception... "The operation is insecure." code: "18" nsresult: "0x80530012 (SecurityError)"...
The canvas is drawn from an image served from a different domain, but I'm using a proxy to add these 2 lines to the image response header:
access-control-allow-origin: *
access-control-allow-credentials: true
What am I missing?
Thanks,
Ted
To make a proper CORS request, you must set the image's cross origin property to "Anonymous". This example is from the Mozilla Developer Network.
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;
}
The browser support excludes any known version of IE, and unreleased versions of Safari. Firefox and Chrome have years of support.
Related
I'm trying to add an image from a different url using a function and im getting an issue with cors saying my request is blocked.
I tried adding a cossOrigin attribute to the image and it still dosnt seem to work
function getDataUri(url, callback) {
var image = new Image();
image.crossOrigin = "Anonymous"
image.onload = function () {
var canvas = document.createElement('canvas');
canvas.width = this.naturalWidth; // or 'width' if you want a special/scaled size
canvas.height = this.naturalHeight; // or 'height' if you want a special/scaled size
canvas.getContext('2d').drawImage(this, 0, 0);
// Get raw image data
// callback(canvas.toDataURL('image/png').replace(/^data:image\/(png|jpg);base64,/, ''));
// ... or get as Data URI
callback(canvas.toDataURL('image/png'));
};
image.src = url;
}
getDataUri(imageurl, function (dataURI) {
})
Access to image at 'imageurl' from origin 'http://localhost:8000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
I always do: image.setAttribute('crossOrigin', '');
I tried to convert the image to base64 string using javascript/angularjs following the code showed on this stacko page, you can also check the code in detail here.
function toDataURL(src, callback, outputFormat) {
var img = new Image();
img.crossOrigin = 'Anonymous';
img.onload = function() {
var canvas = document.createElement('CANVAS');
var ctx = canvas.getContext('2d');
var dataURL;
canvas.height = this.naturalHeight;
canvas.width = this.naturalWidth;
ctx.drawImage(this, 0, 0);
dataURL = canvas.toDataURL(outputFormat);
callback(dataURL);
};
img.src = src;
if (img.complete || img.complete === undefined) {
img.src = "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///ywAAAAAAQABAAACAUwAOw==";
img.src = src;
}
}
toDataURL(
'https://www.gravatar.com/avatar/d50c83cc0c6523b4d3f6085295c953e0',
function(dataUrl) {
console.log('RESULT:', dataUrl)
}
)
I call this function in the init inside the controller but when i load the page the image doesn't load the first time, but if i load the page again the image does load. I also made a button to call the function again, and as expected the image loads just fine after i load the page and press the button.
Debugging the code i found that the image only loads if it gets to the last if statement which, as by the detailed code, is flushing the cache. But since it's trying by the second time wouldn't this be the normal approach?
if (img.complete || img.complete === undefined) {
img.src = "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///ywAAAAAAQABAAACAUwAOw==";
img.src = src;
}
After getting here it goes on to img.onload and loads the image again, this time the image loads just fine.
What am i missing? Do i need to do something to wait the image to load? Can i do something to make it load later? Or is it something else?
Turns out i wasn't addressing the fact that ImgPreview from ui-cropper can be used, therefore there wasn't any need to convert the image. I only made a $scope in the view to get that ImgPreview and send that to the database. Sadly i can't provide any code.
I have a div where users can drag and drop an image and then, using FileReader, I get the base64 of the image. Works fine.
dropper.ondrop = function (e) {
e.preventDefault();
var file = e.dataTransfer.files[0];
var reader = new FileReader();
reader.readAsDataURL(file);
};
My issue is if I have a browser window open and drag and drop an image from the browser I get the error:
Failed to execute 'readAsDataURL' on 'FileReader':
parameter 1 is not of type 'Blob'.
Now, is there any turnaround to get the base64 of an image dragged from the browser window?
Ultimately, is there is a way to get the image URL and then the actual base64 with a server side curl request?
Any idea?
You can use e.dataTransfer.getData('url') to tell whether there's a URL available. Like this:
var url = e.dataTransfer.getData('url');
if(url){
console.log('Url');
console.log(url);
}else{
console.log('File');
var file = e.dataTransfer.files[0];
var reader = new FileReader();
reader.readAsDataURL(file);
}
Then, having the URL, you can load an img element and use draw it on a canvas to grab the base64 representation. Like this:
var img = document.createElement('img');
img.crossOrigin = 'anonymous';
img.onload = function(){
var canvas = document.createElement('canvas');
canvas.width = this.width;
canvas.height = this.height;
var context = canvas.getContext('2d');
context.drawImage(this, 0, 0);
console.log(canvas.toDataURL());
};
img.src = url;
This would be the "final" product:
var dropper = document.querySelector('div');
dropper.ondragover = function(e) {
e.preventDefault();
}
dropper.ondrop = function (e) {
e.preventDefault();
var url = e.dataTransfer.getData('url');
if(url){
console.log('Url');
console.log(url);
var img = document.createElement('img');
img.crossOrigin = 'anonymous';
img.onload = function(){
var canvas = document.createElement('canvas');
canvas.width = this.width;
canvas.height = this.height;
var context = canvas.getContext('2d');
context.drawImage(this, 0, 0);
console.log(canvas.toDataURL());
};
img.src = url;
}else{
console.log('File');
var file = e.dataTransfer.files[0];
var reader = new FileReader();
reader.readAsDataURL(file);
}
};
div{
border:1px solid red;
height:240px;
width:100%;
}
<div>Drop here</div>
Also available here: https://jsfiddle.net/8u6Lprrb/1/
The first parameter comes through with the "http://" or "https://" protocol instead of the expected "file://" protocol. and thats why you cant read it with the HTML5 FILE API, so you may want to download and save the file first before trying to read the contents.
on the other hand, you can update an img tag's src attribute with the retrieved url and skip the readDataAsUrl() portion to hotlink the image.
I scraping some pages (I know, I know, I shouldn't, but the info from our intranet is not available in any other reliable way). So I inject a small $(...).each(... $.ajax({})); JavaScript and this works fine.
I got most info out of it, but now I need the images. I can get the URL, but I need to store them on the server (or on my local machine first). I can't use the URL because the images are behind username/password authentication.
Can I send them with a $.ajax(multipart/form post - new FormData()) construct?
All idea's welcome.
One idea is to encode them as base64 strings and store them that way. Here's a fiddle demonstrating the method: http://jsfiddle.net/c8n9d4ce/
I also found this fiddle that likewise demonstrates this method.
My code from the fiddle:
var canvas = document.getElementById("myCanvas");
var srcImg = document.getElementById("sourceImage");
var final = document.getElementById("base64Image");
var img = new Image();
img.crossOrigin = 'Anonymous';
img.onload = function(){
canvas.height = this.height;
canvas.width = this.width;
canvas.getContext('2d').drawImage(this,0,0);
var dataURL = canvas.toDataURL();
canvas = null;
final.src = dataURL;
};
img.src = srcImg.src;
img {
max-width: 100%;
}
<h1>Original Image</h1>
<img src="https://i.imgur.com/5YJ3HQ9.jpg" id="sourceImage">
<h1>Canvas Rendered Image</h1>
<canvas id="myCanvas"></canvas>
<h1>Base64 Encoded Image</h1>
<img id="base64Image">
Seems the way to go, I tried, but got this error: "Cross-origin image load denied by Cross-Origin Resource Sharing policy". I tried the snippet on this webpage (just copy/paste into the console).
function getDataURL(srcImg, done) {
var img = new Image();
img.crossOrigin = 'Anonymous';
img.onload = function(){
var canvas = document.createElement('canvas');
canvas.height = this.height;
canvas.width = this.width;
canvas.getContext('2d').drawImage(this,0,0);
done(canvas.toDataURL());
};
img.src = srcImg.src;
}
getDataURL($("img")[0], function(data) {
console.log(data);
});
I'm loading an image in js and draw it into a canvas. After drawing, i retrieve imageData from the canvas:
var img = new Image();
img.onload = function() {
canvas.drawImage(img, 0, 0);
originalImageData = canvas.getImageData(0,0,width, height)); //chrome fails
}
img.src = 'picture.jpeg';
This works perfectly both in Safari and Firefox, but fails in Chrome with the following message:
Unable to get image data from canvas because the canvas has been tainted by cross-origin data.
The javascript file and the image are located in the same directory, so i don't understand the behavior of chorme.
To enable CORS (Cross-Origin Resource Sharing) for your images pass the HTTP header with the image response:
Access-Control-Allow-Origin: *
The origin is determined by domain and protocol (e.g. http and https are not the same) of the webpage and not the location of the script.
If you are running locally using file:// this is generally always seen as a cross domain issue; so its better to go via
http://localhost/
To solve the cross domain issue with file://, you can start chrome with the parameter
--allow-file-access-from-files
var img = new Image();
img.onload = function() {
canvas.drawImage(img, 0, 0);
originalImageData = canvas.getImageData(0,0,width, height)); //chrome will not fail
}
img.crossOrigin = 'http://profile.ak.fbcdn.net/crossdomain.xml';//crossdomain xml file, this is facebook example
img.src = 'picture.jpeg';
Hope this helps
var canvas = document.createElement("canvas");
var ctx = canvas.getContext("2d");
var img = new Image();
img.crossOrigin = "anonymous";
img.onload = function() {
canvas.width = img.width;
canvas.height = img.height;
ctx.drawImage(img, 0, 0);
originalImageData = ctx.canvas.toDataURL();
}
img.src = 'picture.jpeg';
hope this helps.
If the server response headers contains Access-Control-Allow-Origin: *, then you can fix it from client side: Add an attribute to the image or video.
<img src="..." crossorigin="Anonymous" />
<video src="..." crossorigin="Anonymous"></video>
Otherwise you have to use server side proxy.