Javascript: How can I reliably derive ImageData from base64? [duplicate] - javascript

This question already has an answer here:
CanvasContext2D drawImage() issue [onload and CORS]
(1 answer)
Closed last month.
Consider the following MWE:
var canvas = document.createElement("canvas");
var ctx = canvas.getContext('2d');
var str = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAApgAAAKYB3X3/OAAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAANCSURBVEiJtZZPbBtFFMZ/M7ubXdtdb1xSFyeilBapySVU8h8OoFaooFSqiihIVIpQBKci6KEg9Q6H9kovIHoCIVQJJCKE1ENFjnAgcaSGC6rEnxBwA04Tx43t2FnvDAfjkNibxgHxnWb2e/u992bee7tCa00YFsffekFY+nUzFtjW0LrvjRXrCDIAaPLlW0nHL0SsZtVoaF98mLrx3pdhOqLtYPHChahZcYYO7KvPFxvRl5XPp1sN3adWiD1ZAqD6XYK1b/dvE5IWryTt2udLFedwc1+9kLp+vbbpoDh+6TklxBeAi9TL0taeWpdmZzQDry0AcO+jQ12RyohqqoYoo8RDwJrU+qXkjWtfi8Xxt58BdQuwQs9qC/afLwCw8tnQbqYAPsgxE1S6F3EAIXux2oQFKm0ihMsOF71dHYx+f3NND68ghCu1YIoePPQN1pGRABkJ6Bus96CutRZMydTl+TvuiRW1m3n0eDl0vRPcEysqdXn+jsQPsrHMquGeXEaY4Yk4wxWcY5V/9scqOMOVUFthatyTy8QyqwZ+kDURKoMWxNKr2EeqVKcTNOajqKoBgOE28U4tdQl5p5bwCw7BWquaZSzAPlwjlithJtp3pTImSqQRrb2Z8PHGigD4RZuNX6JYj6wj7O4TFLbCO/Mn/m8R+h6rYSUb3ekokRY6f/YukArN979jcW+V/S8g0eT/N3VN3kTqWbQ428m9/8k0P/1aIhF36PccEl6EhOcAUCrXKZXXWS3XKd2vc/TRBG9O5ELC17MmWubD2nKhUKZa26Ba2+D3P+4/MNCFwg59oWVeYhkzgN/JDR8deKBoD7Y+ljEjGZ0sosXVTvbc6RHirr2reNy1OXd6pJsQ+gqjk8VWFYmHrwBzW/n+uMPFiRwHB2I7ih8ciHFxIkd/3Omk5tCDV1t+2nNu5sxxpDFNx+huNhVT3/zMDz8usXC3ddaHBj1GHj/As08fwTS7Kt1HBTmyN29vdwAw+/wbwLVOJ3uAD1wi/dUH7Qei66PfyuRj4Ik9is+hglfbkbfR3cnZm7chlUWLdwmprtCohX4HUtlOcQjLYCu+fzGJH2QRKvP3UNz8bWk1qMxjGTOMThZ3kvgLI5AzFfo379UAAAAASUVORK5CYII="
var image = new Image();
image.src = str;
ctx.drawImage(image, 0, 0);
var imageData = ctx.getImageData(0, 0, image.width, image.height);
console.log('imageDataxD', imageData.data);
It runs roughly 40% of the time when testing locally in my browser. The error that I am getting states:
DOMException: Failed to execute 'getImageData' on 'CanvasRenderingContext2D': The source width is 0.
Why is the code receiving the width sometimes, and sometimes not?

Image onload event is required to work on bits of bitmap:
imgage.onload = function() {
// do work
};
image.src = "base64 code here";
Because when setting src, it downloads/gets content, allocates memory for bitmap, initializes the bitmap, then calls the onload.
There shouldn't be any problem if you set the onload function before setting src.

Related

Loading/security issue when drawing images on a canvas

My question might be stupid, but I'm stuck with a simple task.
I'm writing a web browser game where I load images from a local folder to a 2d canvas, then, at some time, redraw it with getImageData().
The code sample is the following
let img = new Image()
// img.crossOrigin = "anonymous"
img.src = "assets/hidden.png"
let ctx = document.getElementById("canvas").getContext("2d")
img.onload = () => {
console.log("loaded img", img.src)
ctx.drawImage(img, 0, 0)
let c = ctx.getImageData(0, 0, 10, 10)
}
The original problem was that calling getImageData() causes Uncaught DOMException: The operation is insecure.
So I added img.crossOrigin = "anonymous" (context.getImageData() operation is insecure) to overcome this, but now the image is not loaded at all. How do I normally use images in canvas?

No image width, canvas / constructor javascript / game [duplicate]

I am trying to paint an image on a canvas before I get its dataURL(), but the data returned is like empty.
When I check it in the console, I see there is a lot of A in the string : ("data:image/png;base64,iVBO..some random chars... bQhfoAAAAAAAAAA... a lot of A ...AAAASUVORK5CYII=")
When I try to append the canvas to the document, nothing is drawn either and I don't have any error thrown in the console.
What is the problem here ?
Here is my code :
var img = new Image();
img.src = "http://somerandomWebsite/picture.png";
var canvas = document.createElement('canvas');
canvas.width = img.width;
canvas.height = img.height;
var context = canvas.getContext('2d');
context.drawImage(img, 0,0); // this doesn't seem to work
var dataURL = canvas.toDataURL(); // this will give me a lot of "A"
doSomething(dataURL);
Also, when doing a quick refresh, the image gets drawn correctly onto the canvas but I've got an error message in the console and dataURL is empty.
The message in Firefox is : "SecurityError: The operation is insecure.",
in Chrome it is "Uncaught SecurityError: Failed to execute 'toDataURL' on 'HTMLCanvasElement': Tainted canvases may not be exported.",
and on IE I just get "SecurityError".
What does it mean ?
You have to wait that your image has loaded before you can paint it on the canvas.
To do so, simply use the load event handler of your <img> element :
// create a new image
var img = new Image();
// declare a function to call once the image has loaded
img.onload = function(){
var canvas = document.createElement('canvas');
canvas.width = img.width;
canvas.height = img.height;
var context = canvas.getContext('2d');
context.drawImage(img, 0,0);
var dataURL = canvas.toDataURL();
// now you can do something with the dataURL
doSomething(dataURL);
}
// now set the image's src
img.src = "http://somerandomWebsite/picture.png";
Also, for the canvas' context.toDataURL() and context.getImageData to work properly, you have to get your image resource in a cross-origin compliant way, otherwise the canvas is "tainted" which means that any method to get pixels data will be blocked.
If your image comes from the same server, no problem.
If your image is served from an external server, be sure that it allows yours in its cross-origin headers and set the img.crossOrigin to "use-credentials".
If the server does allow anonymous requests, you can set the img.crossOrigin to "anonymous".
Nota Bene : CORS header is sent by the server, the cross-origin attribute will only let it know that you want to use CORS to get the image data, in no way you can circumvent it if the server is not set properly.
Also some UserAgents (IE & Safari) still haven't implemented this attribute.
Edge Case : If some of your images are from your server and some are from a CORS compliant one, then you may want to use the onerror event handler which should fire if you set the cross-origin attribute to "anonymous" on a non CORS server.
function corsError(){
this.crossOrigin='';
this.src='';
this.removeEventListener('error', corsError, false);
}
img.addEventListener('error', corsError, false);

context.drawImage() doesn't work in html canvas? [duplicate]

I am trying to paint an image on a canvas before I get its dataURL(), but the data returned is like empty.
When I check it in the console, I see there is a lot of A in the string : ("data:image/png;base64,iVBO..some random chars... bQhfoAAAAAAAAAA... a lot of A ...AAAASUVORK5CYII=")
When I try to append the canvas to the document, nothing is drawn either and I don't have any error thrown in the console.
What is the problem here ?
Here is my code :
var img = new Image();
img.src = "http://somerandomWebsite/picture.png";
var canvas = document.createElement('canvas');
canvas.width = img.width;
canvas.height = img.height;
var context = canvas.getContext('2d');
context.drawImage(img, 0,0); // this doesn't seem to work
var dataURL = canvas.toDataURL(); // this will give me a lot of "A"
doSomething(dataURL);
Also, when doing a quick refresh, the image gets drawn correctly onto the canvas but I've got an error message in the console and dataURL is empty.
The message in Firefox is : "SecurityError: The operation is insecure.",
in Chrome it is "Uncaught SecurityError: Failed to execute 'toDataURL' on 'HTMLCanvasElement': Tainted canvases may not be exported.",
and on IE I just get "SecurityError".
What does it mean ?
You have to wait that your image has loaded before you can paint it on the canvas.
To do so, simply use the load event handler of your <img> element :
// create a new image
var img = new Image();
// declare a function to call once the image has loaded
img.onload = function(){
var canvas = document.createElement('canvas');
canvas.width = img.width;
canvas.height = img.height;
var context = canvas.getContext('2d');
context.drawImage(img, 0,0);
var dataURL = canvas.toDataURL();
// now you can do something with the dataURL
doSomething(dataURL);
}
// now set the image's src
img.src = "http://somerandomWebsite/picture.png";
Also, for the canvas' context.toDataURL() and context.getImageData to work properly, you have to get your image resource in a cross-origin compliant way, otherwise the canvas is "tainted" which means that any method to get pixels data will be blocked.
If your image comes from the same server, no problem.
If your image is served from an external server, be sure that it allows yours in its cross-origin headers and set the img.crossOrigin to "use-credentials".
If the server does allow anonymous requests, you can set the img.crossOrigin to "anonymous".
Nota Bene : CORS header is sent by the server, the cross-origin attribute will only let it know that you want to use CORS to get the image data, in no way you can circumvent it if the server is not set properly.
Also some UserAgents (IE & Safari) still haven't implemented this attribute.
Edge Case : If some of your images are from your server and some are from a CORS compliant one, then you may want to use the onerror event handler which should fire if you set the cross-origin attribute to "anonymous" on a non CORS server.
function corsError(){
this.crossOrigin='';
this.src='';
this.removeEventListener('error', corsError, false);
}
img.addEventListener('error', corsError, false);

canvas empty after adding image [duplicate]

I am trying to paint an image on a canvas before I get its dataURL(), but the data returned is like empty.
When I check it in the console, I see there is a lot of A in the string : ("data:image/png;base64,iVBO..some random chars... bQhfoAAAAAAAAAA... a lot of A ...AAAASUVORK5CYII=")
When I try to append the canvas to the document, nothing is drawn either and I don't have any error thrown in the console.
What is the problem here ?
Here is my code :
var img = new Image();
img.src = "http://somerandomWebsite/picture.png";
var canvas = document.createElement('canvas');
canvas.width = img.width;
canvas.height = img.height;
var context = canvas.getContext('2d');
context.drawImage(img, 0,0); // this doesn't seem to work
var dataURL = canvas.toDataURL(); // this will give me a lot of "A"
doSomething(dataURL);
Also, when doing a quick refresh, the image gets drawn correctly onto the canvas but I've got an error message in the console and dataURL is empty.
The message in Firefox is : "SecurityError: The operation is insecure.",
in Chrome it is "Uncaught SecurityError: Failed to execute 'toDataURL' on 'HTMLCanvasElement': Tainted canvases may not be exported.",
and on IE I just get "SecurityError".
What does it mean ?
You have to wait that your image has loaded before you can paint it on the canvas.
To do so, simply use the load event handler of your <img> element :
// create a new image
var img = new Image();
// declare a function to call once the image has loaded
img.onload = function(){
var canvas = document.createElement('canvas');
canvas.width = img.width;
canvas.height = img.height;
var context = canvas.getContext('2d');
context.drawImage(img, 0,0);
var dataURL = canvas.toDataURL();
// now you can do something with the dataURL
doSomething(dataURL);
}
// now set the image's src
img.src = "http://somerandomWebsite/picture.png";
Also, for the canvas' context.toDataURL() and context.getImageData to work properly, you have to get your image resource in a cross-origin compliant way, otherwise the canvas is "tainted" which means that any method to get pixels data will be blocked.
If your image comes from the same server, no problem.
If your image is served from an external server, be sure that it allows yours in its cross-origin headers and set the img.crossOrigin to "use-credentials".
If the server does allow anonymous requests, you can set the img.crossOrigin to "anonymous".
Nota Bene : CORS header is sent by the server, the cross-origin attribute will only let it know that you want to use CORS to get the image data, in no way you can circumvent it if the server is not set properly.
Also some UserAgents (IE & Safari) still haven't implemented this attribute.
Edge Case : If some of your images are from your server and some are from a CORS compliant one, then you may want to use the onerror event handler which should fire if you set the cross-origin attribute to "anonymous" on a non CORS server.
function corsError(){
this.crossOrigin='';
this.src='';
this.removeEventListener('error', corsError, false);
}
img.addEventListener('error', corsError, false);

Canvas toDataUrl increases file size of image

When using toDataUrl() to set the source of an image tag I am finding that the image when saved is a great deal larger than the original image.
In the example below I am not specifying a second param for the toDataUrl function so the default quality is being used. This is resulting in an image much larger that the original image size. When specifying 1 for full quality the image generated is even larger.
Does anybody know why this is happening or how I can stop it?
// create image
var image = document.createElement('img');
// set src using remote image location
image.src = 'test.jpg';
// wait til it has loaded
image.onload = function (){
// set up variables
var fWidth = image.width;
var fHeight = image.height;
// create canvas
var canvas = document.createElement('canvas');
canvas.id = 'canvas';
canvas.width = fWidth;
canvas.height = fHeight;
var context = canvas.getContext('2d');
// draw image to canvas
context.drawImage(image, 0, 0, fWidth, fHeight, 0, 0, fWidth, fHeight);
// get data url
dataUrl = canvas.toDataURL('image/jpeg');
// this image when saved is much larger than the image loaded in
document.write('<img src="' + dataUrl + '" />');
}
Thank you :D
Here is an example, unfortunately the image cannot be cross domain and so I am having to just pull one of the jsfiddle images.
http://jsfiddle.net/ptSUd/
The image is 7.4kb, if you then save the image which is being output you will see that it is 10kb. The difference is more noticeable with more detailed images. If you set the toDataUrl quality to 1, the image is then 17kb.
I am also using FireFox 10 for this, when using Chrome the image sizes are still larger but not by as much.
The string returned by the toDataURL() method does not represent the original data.
I have just performed some extensive tests, which showed that the created data-URL depends on the browser (not on the operating system).
Environment - md5 sum - file size
Original file - c9eaf8f2aeb1b383ff2f1c68c0ae1085 - 4776 bytes
WinXP Chrome 17.0.963.79 - 94913afdaba3421da6ddad642132354a - 7702 bytes
Linux Chrome 17.0.963.79 - 94913afdaba3421da6ddad642132354a - 7702 bytes
Linux Firefox 10.0.2 - 4f184006e00a44f6f2dae7ba3982895e - 3909 bytes
The method of getting the data-URI does not matter, the following snippet was used to verify that the data-URI from a file upload are also different:
Test case: http://jsfiddle.net/Fkykx/
<input type="file" id="file"><script>
document.getElementById('file').onchange=function() {
var filereader = new FileReader();
filereader.onload = function(event) {
var img = new Image();
img.onload = function() {
var c = document.createElement('canvas'); // Create canvas
c.width = img.width;
c.height = img.height; c.getContext('2d').drawImage(img,0,0,img.width,img.height);
var toAppend = new Image;
toAppend.title = 'Imported via upload, drawn in a canvas';
toAppend.src = c.toDataURL('image/png');
document.body.appendChild(toAppend);
}
img.src = event.target.result; // Set src from upload, original byte sequence
img.title = 'Imported via file upload';
document.body.appendChild(img);
};
filereader.readAsDataURL(this.files[0]);
}
</script>
The size of the image is determined mostly by the quality of the encoder built into the browser. It has very little to do with the size of the original image. Once you draw anything onto a canvas all you have are pixels, you no longer have the original image. toDataURL does not magically reconstitute an image that was painted onto the canvas. If you want a file with the same size as the original image: use the original image.
Looks like kirilloid and Rob nailed it. I had this issue too and it appears to be a combo:
the dataURL uses base64 encoding which makes it around 1.37 X larger
each browser processes the toDataURL function differently
base64 encoded image size
I tested my thumbnail generator in win8.1 firefox and chrome and got dataURL string sizes:
firefox = 3.72kB
chrome = 3.24kB
My original image when converted to dataURL went from 32kB to 45kB.
I think the base64 part is the larger factor so I guess my plan now is to convert the dataURL back to a binary byte array before I store it on the server (probably on the client side because my server's lazy).

Categories