I have create 2 canvas, load two differnt image and I want to merge both canvas and then display it as image in <div id="test"></div> tag.
Here is my code:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>canvas to image</title>
</head>
<body>
<div>
<canvas id="card_canvas" width="800" height="500"></canvas>
<canvas id="card_canvas2" width="800" height="500"></canvas>
</div>
<div id="test"></div>
<button onclick="canvasToImage()">canvas to image</button>
<script>
var img1 = new Image();
img1.src = "images/img1.jpg";
var cuimg;
function canvasToImage(){
var canvass1 = document.getElementById("card_canvas");
var canvass2 = document.getElementById("card_canvas2");
var ctx1 = canvass1.getContext('2d');
var ctx2 = canvass2.getContext('2d');
ctx1.drawImage(img1, 0, 0);
cuimg = new Image();
cuimg.onload = function(){
ctx2.drawImage(cuimg, 7, 92);
}
cuimg.src = "images/img2.jpg";
ctx1.drawImage(canvass2, 0, 0);
var imgdata = canvass1.toDataURL('image/png');
var mergeimg = document.createElement("img");
mergeimg.src = imgdata;
document.getElementById("test").appendChild(mergeimg);
}
</script>
</body>
</html>
Here is img1.jpg:
Here is img2.jpg:
This code ends up in displaying only background image:
I am expecting:
This can be achieve by simply setting following style on canvas2:
<canvas id="card_canvas2" style="position:absolute; left:0px; top:0px;"></canvas>
https://jsfiddle.net/jkjqd7gz/
I've been fiddling with your code a bit, and I think I've figured out the issue. javascript has a funny execution order at times that most people aren't aware of. Your onload lambda function is causing some of the issues your experiencing. Basically, you need to move your ctx1.drawImage(canvass2, 0, 0); line inside your lambda function just after ctx2.drawImage(cuimg, 7, 92); To understand what I mean open your code and hit the canvas to image button twice. The first time populates both canvasses, the second time puts the contents of canvass2 onto canvass1. I could probably explain exactly what's happening in terms of order of execution, but the explanation involves some difficult to understand concepts regarding parallelism, swap buffers, and race conditions.
To put it in a nutshell, whatever function you call ctx2.drawImage in, you need to then follow it with ctx1.drawImage. Honestly though, the best way to make composite images is to create a sprite class that stores an image, its postion, and layer information if desired. Then use a dynamic array to store the sprites. Always clear the canvas every time before you draw on it and loop through the contents of your arrays drawing each sprite in layer order on its respective canvass. Finally, I would use one set of functions to populate the canvas and a second to merge them.
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>canvas to image</title>
</head>
<body>
<div>
<canvas id="card_canvas" width="800" height="500"></canvas>
<canvas id="card_canvas2" width="800" height="500"></canvas>
</div>
<div id="test"></div>
<button onclick="popCanvas()">Populate Canvasses</button>
<button onclick="canvasToImage()">Canvas Combine</button>
<script>
var img1 = new Image();
img1.src = "images/img1.jpg";
var cuimg = new Image();
var canvass1 = document.getElementById("card_canvas");
var canvass2 = document.getElementById("card_canvas2");
function popCanvas(){
var ctx1 = canvass1.getContext('2d');
var ctx2 = canvass2.getContext('2d');
ctx1.clear()
ctx2.clear()
ctx1.drawImage(img1, 0, 0);
cuimg.onload = function(){
ctx2.drawImage(cuimg, 7, 92);
}
cuimg.src = "images/img2.jpg";
}
function canvasToImage(){
var ctx1 = canvass1.getContext('2d');
var ctx2 = canvass2.getContext('2d');
ctx1.drawImage(canvass2, 0, 0);
var imgdata = canvass1.toDataURL('image/png');
var mergeimg = document.createElement("img");
mergeimg.src = imgdata;
document.getElementById("test").appendChild(mergeimg);
}
</script>
</body>
</html>
Related
I'm new to js and html5 so here's what I'm doing : I'm working on a game that helps in teaching illustrator shortcuts, the firts level consist of 2 canvas one with an already existing image and the other blank and ready for user to draw on, on ctrl + s press(sure I disabled it's default action using jquery) I want to compare the content of those 2 canvas elements. I've found Image similarity api from deepai.org very useful and accurate, but it only accepts url or input="file" content, so I'm trying to find a way to upload (maybe) the drawn canvas as an image to a server and get the url like this : https://server.com/myaccount/images/img1.png and since i only upload one image I can pass that static url to the api in addition to the original image which will also have a static url so hopefully it compares.
I made a solution that works without a server. But I couldn't make it work in an online code repo like jsfiddle. So I put it on my own server for you to check. http://paulyro.com/paul/deepai/
For convenience I put everything in one file. Of course it would make sense to save the JS in a separate file. But I let that up to you.
For explanation: the red square in a black frame is the canvas. I generate two images and add them to the page. Then I send those images to the deepAI server when you press the button. You will only need one generated img, but for testing purpose I made 2.
Let me know if this is what you were looking for. Of course I expect you to adapt this solution to your exact needs ;)
This is the code:
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>DeepAiDemo</title>
<script src="https://cdnjs.deepai.org/deepai.min.js"></script>
<style rel="stylesheet">
canvas {
border: 1px solid black;
}
</style>
</head>
<body>
<canvas id="canvas1" width="200" height="200"></canvas>
<button name="button" onClick="load()">Press me</button>
<div style="position:absolute;left:400px; top:30px; height: 354px;" id="messages">Result will get here</div>
<script type="text/javascript">
(async function() {
var can = document.getElementById('canvas1');
var ctx = can.getContext('2d');
// create green canvas and make it an image
ctx.fillStyle = "green";
ctx.fillRect(75, 75, 50, 50);
var img = new Image();
img.src = can.toDataURL();
document.body.appendChild(img);
// create red canvas and make it an image
ctx.fillStyle = "red";
ctx.fillRect(75, 75, 50, 50);
var img2 = new Image();
img2.src = can.toDataURL();
document.body.appendChild(img2);
})()
const load = async () => {
document.getElementById('messages').innerHTML = "Waitng for response...";
deepai.setApiKey('xxxxxxxxxxxxxx');
var images = document.getElementsByTagName('img');
console.log("amount images: "+images.length);
console.log(images[0]);
console.log(images[1]);
var resp = await deepai.callStandardApi("image-similarity", {
image1: images[0],
image2: images[1],
});
console.log("response: ");
console.log(resp);
document.getElementById('messages').innerHTML = "Distance: " + resp.output.distance; //resp.output.distance contains the number from the server.
};
</script>
</body>
</html>
Cheers,
Paul
Im trying to set up a background image in my html canvas by creating a function that clears the canvas and draws the background image to fill the canvas. I've been trying to figure out where I went wrong and why no images are appearing on preview. (I've already double checked my links for spelling errors)
`<html>
<head>
<title>Apple Dropper</title>
<meta charset = "utf-8">
<script src ="proa1.js">
// set src of images in variables
var canvas = document.getElementById("myCanvas");
ctx = canvas.getContext("2d");
canvas.width = 600;
canvas.height = 400;
let bg = new Image();
bg.src = "projectimages/gifani.gif";
let pic = new Image(0,350);
pic.src = "projectimages/bucket.png";
let fish = new Image(300,0);
pic.src = "projectimages/fish.png";
// Make sure the image is loaded first otherwise nothing will draw.
bg.onload = function(){
ctx.drawImage(bg,0,0);
}
</script>
</head>
<body>
<h1>CPSC 1045 Apple Dropper Project</h1><br>
<h2>Alleluia Anteros</h2>
<!--- canvas --->
<canvas id="myCanvas" width="600" height="400" style="border:1px solid #000000;" >
</canvas>
<br>
<!--- control panel --->
</body>
</html>`
If you want a regular background image it would be much easier to do so using CSS. You would select the body tag and use the background-img property with the value of URL and put the URL of the image in the parenthesis. To make to cover the page you would have to use the property of background-size with the value of cover.
body{
background-img:url(bckgrndimg.png);
background-size:cover;
}
This is my htmlcode:
<!DOCTYPE html>
<html>
<head>
<title>test</title>
<script src="http://code.createjs.com/easeljs-0.7.0.min.js"></script>
<script src="Doge.js"></script>
</head>
<body bgcolor="#C7C7C7" onload="Start();">
<canvas id="DogeCanvas" width="480" height="320"></canvas>
</body>
</html>
And this is my Doge.js code:
function Start() {
var stage = new createjs.Stage("DogeCanvas");
var doge = new Image();
doge.src = "images/doge.jpg"
var bitmap = new createjs.Bitmap(doge);
stage.addChild(bitmap);
stage.update();
}
Why it doesn't show anything on the screen?
What is wrong?
The image is not loaded when the stage is updated. I posted an answer here:
ยป easeljs not showing bitmap
You can add a Ticker to the stage to constantly update it (which most applications do, since there is other things changing over time)
Listen for the onload of the image, and update the stage again
Preload the image with something like PreloadJS before you draw it to the stage.
As stated above you cannot draw your image until you have loaded it. Try this:
<!DOCTYPE HTML>
<html>
<title>Easel Test</title>
<head>
<script src="https://code.createjs.com/easeljs-0.8.0.min.js"></script>
<script>
var stage;
function init() {
stage = new createjs.Stage("myCanvas");
var image = new Image();
image.src = "path/image";
image.onload = handleImageLoad;
}
function handleImageLoad(event) {
var image = event.target;
var bitmap = new createjs.Bitmap(image);
stage.addChild(bitmap);
stage.update();
}
</script>
</head>
<body onload="init();">
<canvas id="myCanvas" width="960" height="580"></canvas>
</body>
</html>
I am trying to draw a canvas created through javascript on another canvas. But it is not working for me,
Here is my code,
<!DOCTYPE HTML>
<html>
<head>
</script>
<script>
window.onload = function(){
var can1 = document.createElement('canvas');
can1.width = 150;
can1.height = 140;
can1.style.cssText = 'top:2px;left:2px;border:2px solid black;';
var ctx1 = can1.getContext('2d');
var img=new Image();
img.src="images/211.jpg"
ctx1.drawImage(img,0,0);
var can = document.getElementById("c");
var ctx = can.getContext('2d');
ctx.drawImage(can1,0,0);
var canvas = document.getElementById("c");
window.open(canvas.toDataURL());
}
</script>
</head>
<body >
<canvas id="c" style = "position:absolute;top:150px;width:250px;height:350px;left:500px; border:2px solid black;"></canvas>
</body>
</html>
I think the problem was that, when you were trying to drawImage that image into the canvas, image was not ready. so if u do this it works perfectly:
<!DOCTYPE HTML>
<html>
<head>
<style>
body {
margin: 0px;
padding: 0px;
}
#myCanvas {
border: 1px solid #9C9898;
}
</style>
<script>
window.onload = function() {
var imageObj = new Image();
imageObj.src = "http://www.html5canvastutorials.com/demos/assets/darth-vader.jpg";
var dynamicCanvas = document.createElement("canvas");
var dynamicContext = dynamicCanvas.getContext("2d");
dynamicCanvas .height="400";
dynamicCanvas.width="578";
var canvas = document.getElementById("myCanvas");
var context = canvas.getContext("2d");
imageObj.onload = function() {
dynamicContext.drawImage(imageObj, 69, 50);
context=context.drawImage(dynamicCanvas,69,50);
window.open(canvas.toDataURL());
};
};
</script>
</head>
<body>
<canvas id="myCanvas" width="578" height="400"></canvas>
</body>
</html>
and you can adjust the height and width of the dynamic canvas.
if you remove that window.open statement, its perfect.
but there is a problem with canvas.toDataURL()
when you try to do canvas.toDataURL() for a local file, it gives a security error (if you inspect it through google chrome) i.e.
Uncaught Error: SECURITY_ERR: DOM Exception 18
you can know more about this error : here
(see if you are getting this error). anyways, the root cause is sorted out, and there's a new problem now altogether :D..anyways better luck!!
The problem with an incorrect image display using the original code of MJQ is that he doesn't stated the size of the second canvas directly through attributes - only through style. Thus browser created a canvas of default size (300x150 for FF) and then stretched it to 250x350.
So the following modification will solve the image display:
<canvas id="c" width="250" height="350" style = "position:absolute;top:150px;width:250px;height:350px;left:500px; border:2px solid black;"></canvas>
Maybe this will help someone in the future.
what are you taking about? your code is working.
(If am getting your question correctly) I added following lines after
can1.style.cssText='border:2px solid black;';
:
var ctx1 = can1.getContext('2d');
ctx1.rect(50, 50, 500, 500);
ctx1.fillStyle = '#8ED6FF';
ctx1.fill();
and upon execution, i see a beautiful rectangle inside!!
are you using html5 supporting browser??
I've got some code which takes a drawing made on in SVG with Raphael (a 400x400 image loaded into the SVG with Raphael), converts it to a canvas with canvg, and should then take canvas.toDataURL and make it an image. All of this should happen when a button is pushed. The first two steps work, but the third is glitchy. The first time I press the button, a 300x150 blank image is placed in the final div instead of the 400x400 image. If I press the button again, the image shows up fine (correct size and everything). I've tried to use both img.onload and the jquery version $(img).load but neither seems to keep the problem from happening. Therefore, I feel like it's an issue with the canvas having not been drawn completely yet but I can't prove that and I can't seem to make the code wait until it has been drawn. Below is all the code. I tried to make it a fiddle but I kept getting security errors with the image.
<!DOCTYPE html>
<html>
<head>
<script type="text/javascript" src="http://canvg.googlecode.com/svn/trunk/rgbcolor.js"></script>
<script type="text/javascript" src="http://canvg.googlecode.com/svn/trunk/canvg.js"></script>
<script type="text/javascript" src="scripts/jquery.js"></script>
<script type="text/javascript" src="scripts/raphael.js"></script>
<script type="text/javascript" src="scripts/excanvas.compiled.js"></script>
<script type="text/javascript">
$(document).ready(function(){
var nowX, nowY, R = Raphael("svg_drawing", 400, 400);
$($("svg").get(0)).attr("xmlns:xlink", "http://www.w3.org/1999/xlink");
var templ = R.image("images/band_clutch.jpg", 0, 0, 400, 400);
});
function toImg(){
var svg = $("#svg_drawing").html().replace(/>\s+/g, ">").replace(/\s+</g, "<");
var canvas = $("#canvas")[0];
canvg(canvas, svg);
var imgData = canvas.toDataURL('image/jpg');
var img = new Image();
$(img).load(function(){
$("#drawing_area").html("");
$(img).appendTo("#drawing_area");
});
img.src = imgData;
}
</script>
<title>Sandbox</title>
</head>
<body style="margin: 0; width:3000px">
<div id="svg_drawing" style="background-color:white;display:inline-block;height:400px;width:400px;border:1px solid black;"></div>
<canvas id="canvas" style="display:inline-block;height:400px;width:400px;border:1px solid red;"></canvas>
<div id="drawing_area" style="background-color:white;display:inline-block;height:400px;width:400px;border:1px solid black;"></div>
<button onclick="toImg()" style="display:inline-block;vertical-align:top;">Do it</button>
</body>
</html>
It sounds like the canvas area is staying at the default 350 x 150. Try setting
canvas.width = canvas.height = 400;
before drawing (keep the inline CSS as-is).
To fix the actual rendering issue, you need to tell the canvg method to do the toDataURI stuff asyncronously, once the rendering has been complete:
function toImg(){
var svg = $("#svg_drawing").html().replace(/>\s+/g, ">").replace(/\s+</g, "<");
var canvas = $("#canvas")[0];
canvg(canvas, svg, {
renderCallback : function(){
var imgData = canvas.toDataURL('image/jpg');
var img = new Image();
$(img).load(function(){
$("#drawing_area").html("");
$(img).appendTo("#drawing_area");
});
img.src = imgData;
}
});
}