Why not transfer the image from the canvas - javascript

I'm trying to convert an image from the canvas to the image, which can be saved by right-clicking mouse.
Everything works fine, but if I put Image on the canvas (drawImage), the image is not transferred.
Image on the left is, and it is not right.
Why?
I also put an example in the sandbox. http://jsfiddle.net/qS9qP/
<body>
<canvas id="myCanvas" width="200" height="200"></canvas>
<img src="f2.ico"/>
</body>
<script>
var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");
ctx.fillStyle = "rgb(200,0,0)";
ctx.fillRect (10, 10, 55, 50);
var img=new Image();
img.onload = function(){
ctx.drawImage(img, 10, 10);
}
img.src="http://www.cisco.com/favicon.ico"
// transfer canvas to image
document.images[0].src=document.getElementById("myCanvas").toDataURL("image/png");
</script>

toDataURL executes before the picture gets loaded. Try putting it in the onload function.
Also, you can not use images from other domains because of the Same Origin Policy, and it will throw a SecurityError:
Uncaught Error: SecurityError: DOM Exception 18
Now this will work: http://jsfiddle.net/DerekL/qS9qP/2/show/
var img = new Image();
img.onload = function () {
ctx.drawImage(img, 10, 10);
document.images[0].src = canvas.toDataURL("image/png"); //Put it inside
}
img.src = "http://jsfiddle.net/img/logo.png" //Same domain

#Derek and #robertklep are correct:
the image is drawn after the toDataURL call; and then
SecurityError: DOM Exception 18
The cross-domain problem is somewhat beyond the scope of this question, but to demonstrate the point, this can be made to work as you expect (by eliminating the DOM Exception):
http://jsfiddle.net/c24w/E3SPv/

Related

How to wait for the multiple images to load in the canvas and convert to base64?

I'm trying to get a base64 version of a canvas in HTML5.
Currently, the base64 image that I get from the canvas is blank.
I have found similar questions for example this one:
HTML Canvas image to Base64 problem
However, the issue that I have is that because I am adding 2 images in the canvas, I cannot use the example provided in those answers as most of them are using single image.
I understand that I have to wait until the canvas image is loaded properly before trying to get the base64 image. But I don't know how in my case.
This is my code:
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
context.canvas.width = 1000;
context.canvas.height = 1000;
var imageObj1 = new Image();
imageObj1.src = "http://www.offthegridnews.com/wp-content/uploads/2017/01/selfie-psuDOTedu.jpg";
imageObj1.onload = function() {
context.drawImage(imageObj1, 0, 180, canvas.width, canvas.height);
};
var imageObj2 = new Image();
imageObj2.src = "http://www.publicdomainpictures.net/pictures/150000/velka/banner-header-tapete-145002399028x.jpg"
imageObj2.onload = function() {
context.drawImage(imageObj2, 0, 0, canvas.width, 180);
};
// get png data url
//var pngUrl = canvas.toDataURL();
var pngUrl = canvas.toDataURL('image/png');
// get jpeg data url
var jpegUrl = canvas.toDataURL('image/jpeg');
$('#base').val(pngUrl);
<div class="contents" style="overflow-x:hidden; overflow-y:scroll;">
<div style="width:100%; height:90%;">
<canvas id="myCanvas" class="snap" style="width:100%; height:100%;" onclick="takephoto()"></canvas>
</div>
</div>
<p>
This is the base64 image
</p>
<textarea id="base">
</textarea>
and this is a working FIDDLE:
https://jsfiddle.net/3p3e6Ldu/1/
Can someone please advice on this issue?
Thanks in advance.
EDIT:
As suggested in the comments bellow, i tried to use a counter and when the counter reaches a specific number, I convert the canvas to base64.
Like so:https://jsfiddle.net/3p3e6Ldu/4/
In both your examples (the one from the question and the one from the comments), the order of commands does not really respect the async nature of the task at hand.
In your later example, you should put the if( count == 2 ) block inside the onload callbacks to make it work.
However, even then you will run into the next problem: You are loading the images from different domains. You can still draw them (either into the canvas or using an <img> tag), but you are not able to access their contents directly. Not even with the detour of using the <canvas> element.
I changed to code so it would work, if the images are hosted on the same domain. I also used a function to load the image and promises to handle the callbacks. The direct way of using callbacks and a counting variable, seem error-prone to me. If you check out the respective fiddle, you will notice the SecurityError shown. This is the result of the aforementioned problem with the Same-Origin-Policy I mentioned.
A previous question of mine in a similar direction was about how to detect, if I can still read the contents of a <canvas> after adding some images.
const canvas = document.getElementById('myCanvas');
const context = canvas.getContext('2d');
context.canvas.width = 1000;
context.canvas.height = 1000;
// function to retrieve an image
function loadImage(url) {
return new Promise((fulfill, reject) => {
let imageObj = new Image();
imageObj.onload = () => fulfill(imageObj);
imageObj.src = url;
});
}
// get images
Promise.all([
loadImage("http://www.offthegridnews.com/wp-content/uploads/2017/01/selfie-psuDOTedu.jpg"),
loadImage("http://www.publicdomainpictures.net/pictures/150000/velka/banner-header-tapete-145002399028x.jpg"),
])
.then((images) => {
// draw images to canvas
context.drawImage(images[0], 0, 180, canvas.width, canvas.height);
context.drawImage(images[1], 0, 0, canvas.width, 180);
// export to png/jpg
const pngUrl = canvas.toDataURL('image/png');
const jpegUrl = canvas.toDataURL('image/jpeg');
// show in textarea
$('#base').val(pngUrl);
})
.catch( (e) => alert(e) );

Canvas toDataURL() returns blank image in Firefox even with .onload and callbacks

I have a problem with toDataURL() function in FireFox
Imagine I have such base64 image:
var url = " data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxMTkgMTE5Ij48Zz48Y2lyY2xlIGN4PSI1NyIgY3k9IjYyIiByPSI1NyIgc3R5bGU9ImZpbGw6IHJnYigxNjAsIDE2MSwgMTYzKTsgb3BhY2l0eTogMC42OyIvPjxjaXJjbGUgY3g9IjU3IiBjeT0iNTciIHI9IjU3IiBzdHlsZT0iZmlsbDogcmdiKDEyMywgMjEwLCAyNDApOyIvPjxjaXJjbGUgY3g9IjU3IiBjeT0iNTciIHI9IjQ1IiBzdHlsZT0iZmlsbDogcmdiKDI1NSwgMjU1LCAyNTUpOyIvPjx0ZXh0IGR4PSI1NyIgZHk9IjY1IiB0ZXh0LWFuY2hvcj0ibWlkZGxlIiBzdHlsZT0iZm9udC1zaXplOjI1cHg7IGZpbGw6ICMyYjJmMmU7IGZvbnQtZmFtaWx5OiAnRElOUHJvIFJlZ3VsYXInLCBzYW5zLXNlcmlmOyBmb250LXdlaWdodDogYm9sZCI+MTUlPC90ZXh0PjwvZz48L3N2Zz4=";
And then I want to resize it and send new uri back:
function getImageUri(url, callback) {
image = new Image();
image.onload = function() {
var image = this;
var canvas = document.createElement('canvas'),
context = canvas.getContext('2d'),
dataURL;
context.drawImage(image, 0, 0, 60, 60);
callback(canvas.toDataURL());
}
image.src = url;
}
At the end I just call it to get new uri
getImageUri(url, function (uri) {
console.log(uri);
document.getElementById('circle').innerHTML = "<img src=" + uri + ">";
});
Here is the codepen of this example. It works in Chrome, but not in FireFox.
I've searched a lot for similar questions here and most of time the reason was use of image without waiting for its loading, but I have this .onload thing, right?
And also I've tried to make same actions as in this question, but FF is still showing just transparent image. Please help!
There’s a bug open in Firefox about this: drawImage() fails silently when drawing an SVG image without #width or #height.
You can fix it by adding (go figure) width and height to the SVG:
<svg
xmlns="http://www.w3.org/2000/svg"
width="119" height="119" viewBox="0 0 119 119">
…
Updated Codepen

canvas element unable to draw image

I wrote a few lines of code to draw an image but seems like it keeps on loading, I tried some W3 School code using the basic implementation but that works fine.
What is happening here is it looks like its stuck in some invisible loop and unable to draw an image.
<script>
var canvas=null;
var context=null;
setup=function(){
canvas=document.getElementById("my_canvas");
context=canvas.getContext('2d');
canvas.width=1200;
canvas.height=720;
img=new Image();
img.onload=onImageLoad;
img.src="http://imgge.bg.ac.rs/images/logo1.jpg";
context.drawImage(img,192,192);
};
onImageLoad=function(){
document.write("done !!");
context.drawImage(img,155,10);
};
setup();
</script>
I replaced your document.write() with a console.log() and it works fine:
var canvas = null;
var context = null;
var setup = function() {
canvas = document.getElementById("my_canvas");
context = canvas.getContext('2d');
canvas.width = 1200;
canvas.height = 720;
img = new Image();
img.onload = onImageLoad;
img.src = "http://imgge.bg.ac.rs/images/logo1.jpg";
context.drawImage(img, 192, 192);
};
onImageLoad = function() {
console.log("done !!");
context.drawImage(img, 155, 10);
};
setup();
<canvas id="my_canvas"></canvas>
For the reason why document.write() causes the canvas to not be displayed, read document.write() overwriting the document?
You might notice a difference between the first and consecutive runs due to img being cached by your browser. A cached image is immediately available for drawing within the setup() function.
First you don't need to write context.drawImage(img,192,192); two times only write inside the image.onload() function. when you write anything using using document.write("Done !"); , it will write the content on this document(HTML) page and may create problems. Instead of that write message on <p> tag instead of on whole document.
here is a snippet for your code:
var canvas=null;
var context=null;
setup=function(){
canvas=document.getElementById("my_canvas");
context=canvas.getContext('2d');
canvas.width=1200;
canvas.height=720;
img=new Image();
img.onload=onImageLoad;
img.src="http://imgge.bg.ac.rs/images/logo1.jpg";
//context.drawImage(img,192,192);
};
onImageLoad=function(){
context.drawImage(img,155,10);
document.getElementById("report").innerHTML="Done !";
};
setup();
<canvas id="my_canvas"></canvas>
<p id="report"></p>

html5-canvas: Conversion of Image file to DataURL throws Uncaught TypeError

I'm trying to get the Base64/Data URL of a chosen image file in Javascript. The user basically selects an image via the File Input control and the Data URL is generated. However, I get this error:
Uncaught TypeError: Failed to execute 'drawImage' on
'CanvasRenderingContext2D': The provided value is not of type
'(HTMLImageElement or HTMLVideoElement or HTMLCanvasElement or
ImageBitmap)'
HTML:
<body>
<form id="form1">
<div>
<input type="file" id="imageinput" onchange="testit(event)" />
<canvas width="300" height="300" id="mycanvas" style="display: none;"></canvas>
</div>
</form>
</body>
Javascript:
function testit(event) {
var myImage = URL.createObjectURL(event.target.files[0]);
var myCanvas = document.getElementById('mycanvas');
var ctx = myCanvas.getContext('2d');
ctx.drawImage(myImage, 0, 0);
var mydataURL = myCanvas.toDataURL('image/jpg');
alert(mydataURL);
}
Why isn't this code working, guys?
You can not draw an image from url directly to canvas. You have to create a image element/object to do that.
var myCanvas = document.getElementById('mycanvas');
var ctx = myCanvas.getContext('2d');
var img = new Image();
img.onload = function(){
ctx.drawImage(img, 0, 0);
alert(myCanvas.toDataURL('image/jpeg'));
};
img.src = URL.createObjectURL(event.target.files[0]);
Here we have created a image object and set the src to user selected image url. After the image is loaded we are adding it to the canvas.
EDIT:
Here we have one more problem. Whatever the image size is, you will always get 300x300 cropped dataurl of the image because of the static canvas width and height. So we can set the width and height to the canvas dynamically after the image loaded. We can use console.log() instead of alert() so that you can open and see the image from your console in your browser itself.
myCanvas.width = img.width;
myCanvas.height = img.height;
Here is the final code:
var myCanvas = document.getElementById('mycanvas');
var ctx = myCanvas.getContext('2d');
var img = new Image();
img.onload = function(){
myCanvas.width = img.width;
myCanvas.height = img.height;
ctx.drawImage(img, 0, 0);
console.log(myCanvas.toDataURL('image/jpeg'));
};
img.src = URL.createObjectURL(event.target.files[0]);
Here is the fiddle (i have made the canvas visible so that you can see the whole image and width and height change in canvas):
UPDATE:
As #Kaiido mentioned, It will produce PNG image since the 'image/jpg' is not the mimetype. 'image/jpeg' is the mimetype for both JPG and JPEG images.
Updated Fiddle:
http://jsfiddle.net/k7moorthi/r8soo95p/4/
You're trying to draw an object URL to the canvas. you need to create an image in memory first
http://jsfiddle.net/zmtu6t6c/4/
var myImageUrl = URL.createObjectURL(event.target.files[0]);
var myImage = new Image();
myImage.src = myImageUrl;
myImage.onload = function(){
... then do the canvas stuff
}

Drawing an image in its full size in a canvas works only on the second try in Mozilla Firefox

I'm trying to get images from users and draw in them stuff. But I'm getting strange behaviour in MF to only show the image in its full size in a canvas.
I have the following code:
<!DOCTYPE html>
<html>
<body>
<input type="file" id="input">
<div id="main"></div>
<script>
document.getElementById('input').onchange = function() {
var file_reader = new FileReader();
file_reader.onload = function() {
var img = new Image();
img.src = file_reader.result;
var canvas = document.createElement('canvas');
canvas.width = img.width;
canvas.height = img.height;
var ctx = canvas.getContext('2d');
ctx.drawImage(img, 0, 0, img.width, img.height)
document.getElementById('main').appendChild(canvas)
}
file_reader.readAsDataURL(document.getElementById('input').files[0])
}
</script>
</body>
</html>
In Chrome and Opera everything works fine, but in Mozilla Firefox when I choose an image nothing happens, the added canvas has width 0 and height 0. Then if I reselect it again it'll show up, and thus for each image, I have to select it once, nothing happens, and then on the second, third etc. times everything works fine. Why is this happening?
I'd give a try to draw the image on the canvas in the img.onload callback.

Categories

Resources