HTML canvas dataURL output is blank when using multiple images - html

I am trying to add multiple images to a HTML canvas and then get a file that I can save using toDataURL()
I have this so far
const canvas = document.querySelector("canvas");
const context = canvas.getContext("2d");
myImage = new Image();
myImage.src = "https://via.placeholder.com/150";
myImage2 = new Image();
myImage2.src = "https://via.placeholder.com/250";
myImage3 = new Image();
myImage3.src = "https://via.placeholder.com/350";
myImage.addEventListener("load", ()=>{
context.drawImage(myImage, 0, 0, 100, 100);
});
myImage2.addEventListener("load", ()=>{
context.drawImage(myImage2, 150, 0, 100, 100);
});
myImage3.addEventListener("load", ()=>{
context.drawImage(myImage3, 300, 0, 100, 100);
});
var final = canvas.toDataURL();
console.log(final);
<canvas width="800"></canvas>
The image is generated in the canvas correctly and I can see it looks ok, but the dataurl output is blank, where am I going wrong?
I know there are solutions when using one image like at HTML5 Canvas toDataURL returns blank but as I am using multiple images, I am unsure how to apply this solution in my case

Related

How to show an uploaded image as a canvas background right away?

I'm using typescript to set as a canvas background an image uploaded by users. However, and I guess due to some binding issue, it only works when the user uploads the file two times. How could I wait for the image to load before trying to set it as a canvas background?
I have tried to run the canvas code only when the selectedFile variable is not null (see below) but I'm getting the same error.
<input type="file" (change)="onFileChanged($event)">
<canvas id="canvas"></canvas>
private selectedFile: File = null;
private imgURL: any;
onFileChanged(event){
if(event.target.files.length == 0) return;
this.selectedFile = <File> event.target.files[0];
var reader = new FileReader();
reader.readAsDataURL(this.selectedFile);
reader.onload = (_event) => {this.imgURL = reader.result;}
var canvas : any = document.getElementById("canvas");
var ctxt = canvas.getContext("2d");
var background = new Image();
background.src = this.imgURL;
background.onload = function () {
ctxt.drawImage(background, 0, 0, canvas.width, canvas.height);
};
}
I expect the canvas to show the selected image as a background. However, the first time the user uploads an image, the output is GET http://localhost:4200/undefined 404 (Not Found) Image (async). When the user uploads a different image, the background is updated to the first selected image.
I think all you need to do is put your canvas code inside of the reader.onload callback.
onFileChanged(event) {
if (event.target.files.length == 0) return;
this.selectedFile = < File > event.target.files[0];
var reader = new FileReader();
reader.readAsDataURL(this.selectedFile);
reader.onload = (_event) => {
this.imgURL = reader.result;
var canvas: any = document.getElementById("canvas");
var ctxt = canvas.getContext("2d");
var background = new Image();
background.src = this.imgURL;
background.onload = function() {
ctxt.drawImage(background, 0, 0, canvas.width, canvas.height);
};
}
}
You were likely getting your error because your .onload async callback had not triggered yet and this.imgURL would be undefined when you tried to use it. Now it waits until we have a value for imgURL before tying to use it.

Pass an image to a canvas with dataurl

I am trying to make an image being passed to a canvas from a weburl.
The code has been taken from this [question][1] which is accepted but for some reason it does not work on me on firefox or chrome.
Any ideas?
EDIT:
Here you are:
var myCanvas = document.getElementById('my_canvas_id');
var ctx = myCanvas.getContext('2d');
var img = new Image;
img.onload = function(){
ctx.drawImage(img,0,0); // Or at whatever offset you like
};
img.src = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAASwAAACWCAYAAABkW7XSAAAAxUlEQVR4nO3BMQEAAADCoPVPbQhfoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOA1v9QAATX68/0AAAAASUVORK5CYII=';
The reason nothing shows is that the provided Data-URI contains no data, that is, it is 300x150 fully transparent:
data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAASwAAACWCAYAAABkW7XSAAAAxUlEQVR4nO3BMQEAAADCoPVPbQhfoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOA1v9QAATX68/0AAAAASUVORK5CYII=
My guess is that you along the way saved an empty canvas as Data-URI using toDataURL() and is now using that for loading an image.
Try this URL instead and you will see it works (red image of 300x150):
data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAASwAAACWCAYAAABkW7XSAAACBUlEQVR4nO3UoQ0AIADEwN9/aVgBR5qcOF/Vne0AFOx3AMArwwIyDAvIMCwgw7CADMMCMgwLyDAsIMOwgAzDAjIMC8gwLCDDsIAMwwIyDAvIMCwgw7CADMMCMgwLyDAsIMOwgAzDAjIMC8gwLCDDsIAMwwIyDAvIMCwgw7CADMMCMgwLyDAsIMOwgAzDAjIMC8gwLCDDsIAMwwIyDAvIMCwgw7CADMMCMgwLyDAsIMOwgAzDAjIMC8gwLCDDsIAMwwIyDAvIMCwgw7CADMMCMgwLyDAsIMOwgAzDAjIMC8gwLCDDsIAMwwIyDAvIMCwgw7CADMMCMgwLyDAsIMOwgAzDAjIMC8gwLCDDsIAMwwIyDAvIMCwgw7CADMMCMgwLyDAsIMOwgAzDAjIMC8gwLCDDsIAMwwIyDAvIMCwgw7CADMMCMgwLyDAsIMOwgAzDAjIMC8gwLCDDsIAMwwIyDAvIMCwgw7CADMMCMgwLyDAsIMOwgAzDAjIMC8gwLCDDsIAMwwIyDAvIMCwgw7CADMMCMgwLyDAsIMOwgAzDAjIMC8gwLCDDsIAMwwIyDAvIMCwgw7CADMMCMgwLyDAsIMOwgAzDAjIMC8gwLCDDsIAMwwIyDAvIMCwgw7CADMMCMgwLyDAsIMOwgAzDAjIMC8gwLCDDsIAMwwIyDAvIMCwgw7CAjAsWoUTzPRjavAAAAABJRU5ErkJggg==
var myCanvas = document.getElementById('my_canvas_id');
var ctx = myCanvas.getContext('2d');
var img = new Image;
img.onload = function(){
ctx.drawImage(img,0,0); // Or at whatever offset you like
};
img.src = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAASwAAACWCAYAAABkW7XSAAACBUlEQVR4nO3UoQ0AIADEwN9/aVgBR5qcOF/Vne0AFOx3AMArwwIyDAvIMCwgw7CADMMCMgwLyDAsIMOwgAzDAjIMC8gwLCDDsIAMwwIyDAvIMCwgw7CADMMCMgwLyDAsIMOwgAzDAjIMC8gwLCDDsIAMwwIyDAvIMCwgw7CADMMCMgwLyDAsIMOwgAzDAjIMC8gwLCDDsIAMwwIyDAvIMCwgw7CADMMCMgwLyDAsIMOwgAzDAjIMC8gwLCDDsIAMwwIyDAvIMCwgw7CADMMCMgwLyDAsIMOwgAzDAjIMC8gwLCDDsIAMwwIyDAvIMCwgw7CADMMCMgwLyDAsIMOwgAzDAjIMC8gwLCDDsIAMwwIyDAvIMCwgw7CADMMCMgwLyDAsIMOwgAzDAjIMC8gwLCDDsIAMwwIyDAvIMCwgw7CADMMCMgwLyDAsIMOwgAzDAjIMC8gwLCDDsIAMwwIyDAvIMCwgw7CADMMCMgwLyDAsIMOwgAzDAjIMC8gwLCDDsIAMwwIyDAvIMCwgw7CADMMCMgwLyDAsIMOwgAzDAjIMC8gwLCDDsIAMwwIyDAvIMCwgw7CADMMCMgwLyDAsIMOwgAzDAjIMC8gwLCDDsIAMwwIyDAvIMCwgw7CADMMCMgwLyDAsIMOwgAzDAjIMC8gwLCDDsIAMwwIyDAvIMCwgw7CAjAsWoUTzPRjavAAAAABJRU5ErkJggg==";
<canvas id="my_canvas_id"></canvas>
var ctx=c.getContext("2d");
ctx.fillStyle="red";
ctx.fillRect(0,0,300,150);
document.write(c.toDataURL());
<canvas id="c"></canvas>

Use image for background of canvas

I am making the simple canvas application.
I want to use image for background of canvas.
I have found out that I should use drawImage(img,x,y).
This is my codes ,but drummap.img doesn't appear.
Where is wrong?
Test
<canvas id="leap-overlay"></canvas>
<script src="leap.js"></script>
<script>
var canvas = document.getElementById("leap-overlay");
// fullscreen
canvas.width = document.body.clientWidth;
canvas.height = document.body.clientHeight;
// create a rendering context
var ctx = canvas.getContext("2d");
ctx.translate(canvas.width/2,canvas.height);
var img = new Image();
img.src = "drummap.jpg";
ctx.drawImage(img,0,0,100,100);
Assuming that your image drummap.jpg is located in said directory, create the image, set the onload to use the new image, and then set the src (see):
var img = new Image();
img.onload = function () {
ctx.drawImage(img, 0, 0, 100, 100);
};
img.src = 'drummap.jpg';
I'm not sure how you're clearing your canvas or what your drawing, but remember your canvas is inherently transparent so feel free to give the canvas a css style background:
<canvas style = "background-image: url(pathtoyourimage.jpg);"></canvas>
Hope that helps.

How to swap images on HTML without libraries (like z-index)

I have a question !
In a html5 canvas, I create an "x" number of images. The last image created is always above the other. Is it possible to swap the depths of the images without the need for libraries? (I do not intend to reverse the order of the variables)
I want somethin like this (without kinetic):
http://www.html5canvastutorials.com/kineticjs/html5-canvas-shape-layering-with-kineticjs/
so, here is the code I'm using:
var canvas = document.getElementById("myCanvas");
var context = canvas.getContext("2d");
var imageObj = new Image();
imageObj.onload = function() {
context.drawImage(imageObj, 69, 50);
};
imageObj.src = "image1.png";
var imageObj2 = new Image();
imageObj2.onload = function() {
context.drawImage(imageObj2, 40, 30);
};
imageObj2.src = "image2.png";
/* I want to put "Image1.png" over "Image2.png" dynamically, for example, pressing a button, all this after render on the canvas */
Draw the furtherest images first. It might help to put the images in an array so you can just loop through them.
Otherwise, in the case of your example, this will fix it as you are drawing context.drawImage(imageObj, 69, 50); last. Think of it as if you would draw it on paper; what you draw last is above what you have already drawn.
var canvas = document.getElementById("myCanvas");
var context = canvas.getContext("2d");
var imageObj2 = new Image();
imageObj2.onload = function() {
context.drawImage(imageObj2, 40, 30);
};
imageObj2.src = "image2.png";
var imageObj = new Image();
imageObj.onload = function() {
context.drawImage(imageObj, 69, 50);
};
imageObj.src = "image1.png";
The order you draw the images matters. You will need to draw the images in the back first, then draw the closer ones.
Why don't you create a canvas object for every image and either show / hide them or adjust the z-index?

Base64 PNG data to HTML5 canvas

I want to load a PNG image encoded in Base64 to canvas element. I have this code:
<html>
<head>
</head>
<body>
<canvas id="c"></canvas>
<script type="text/javascript">
var canvas = document.getElementById("c");
var ctx = canvas.getContext("2d");
data = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAIAAAACDbGyAAAAAXNSR0IArs4c6QAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9oMCRUiMrIBQVkAAAAZdEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRoIEdJTVBXgQ4XAAAADElEQVQI12NgoC4AAABQAAEiE+h1AAAAAElFTkSuQmCC";
ctx.drawImage(data, 0, 0);
</script>
</body>
</html>
In Chrome 8 I get the error: Uncaught TypeError: Type error
And in Firefox's Firebug this: "The type of an object is incompatible with the expected type of the parameter associated to the object" code: "17"
In that base64 is 5x5px black PNG square that I have made in GIMP and turn it to base64 in GNU/Linux's program base64.
By the looks of it you need to actually pass drawImage an image object like so
var canvas = document.getElementById("c");
var ctx = canvas.getContext("2d");
var image = new Image();
image.onload = function() {
ctx.drawImage(image, 0, 0);
};
image.src = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAIAAAACDbGyAAAAAXNSR0IArs4c6QAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9oMCRUiMrIBQVkAAAAZdEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRoIEdJTVBXgQ4XAAAADElEQVQI12NgoC4AAABQAAEiE+h1AAAAAElFTkSuQmCC";
<canvas id="c"></canvas>
I've tried it in chrome and it works fine.
Jerryf's answer is fine, except for one flaw.
The onload event should be set before the src. Sometimes the src can
be loaded instantly and never fire the onload event.
(Like Totty.js pointed out.)
var canvas = document.getElementById("c");
var ctx = canvas.getContext("2d");
var image = new Image();
image.onload = function() {
ctx.drawImage(image, 0, 0);
};
image.src = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAIAAAACDbGyAAAAAXNSR0IArs4c6QAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9oMCRUiMrIBQVkAAAAZdEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRoIEdJTVBXgQ4XAAAADElEQVQI12NgoC4AAABQAAEiE+h1AAAAAElFTkSuQmCC";
....