Trouble with getting Canvas Data after Drawing image - javascript

This code works well as it shoulds:
<script type="text/javascript">
var canvas = document.createElement("canvas");
canvas.id = "myCanvas";
canvas.style.height = "640px";
canvas.style.width = "384px";
canvas.style.position = "absolute";
canvas.style.border = "1px solid black";
document.body.appendChild(canvas);
var context = canvas.getContext('2d');
function getMousePos(canvas, evt) {
var rect = canvas.getBoundingClientRect();
return {
x: evt.clientX - rect.left,
y: evt.clientY - rect.top
};
}
canvas.addEventListener('mousemove', function(evt) {
var mousePos = getMousePos(canvas, evt);
var message = 'Mouse position: ' + mousePos.x + ',' + mousePos.y;
var imgd = context.getImageData(mousePos.x, mousePos.y, 1, 1);
var pix = imgd.data;
document.getElementById("listener").innerHTML = "<b><i>" + message + "<br>" + pix[3] + "</i></b>";
}, false);
</script>
<div id="listener" >
</div>
It basically writes the mouse Position to the "listener" div and the alpha of the current pixel (as long as there is no content, it's - of course - 0)
But when i add this code:
var img = new Image();
img.src = 'http://www.animefighters.de/images/armor_leatherbelly.png';
context.drawImage(img, 0, 0);
There wouldn't happen anything...
What am i doing wrong? Where is the mistake?
I want to draw some images to the canvas and, after that, get the pixel data (including mouse Position and alpha of the pixel) ...
how can i realize that?

You're trying to draw the image on the canvas before it is loaded, you need to draw it onload:
var img = new Image();
img.onload = function() {
context.drawImage(img, 0, 0);
}
img.src = 'http://www.animefighters.de/images/armor_leatherbelly.png';

Related

Loading video frames into javascript in google colab

I wish to present a video, frame by frame with the possibility of flipping between frames in google colab. I also wish to mark some rectangles and get the x,y,w,h of each rectangle.
As far as I could understand, the only way to click the output and gather data in google Collab is via a javascript call, which I am new to. I have split my video into a list called frames and written the following python\javascript code for my task:
def get_fxy_val(base64imgs):
js = Javascript('''
async function showImage(base64) {
var canvas = document.createElement('canvas');
var rect = {};
var drag = false;
var finish = false;
var clicks = [];
var img = document.createElement('img');
var frame = 0
var ctx = canvas.getContext('2d');
document.body.appendChild(canvas);
img = new Image();
img.onload = function () {
canvas.height = img.height;
canvas.width = img.width;
ctx.drawImage(img, 0, 0);
};
img.src = 'data:image/jpeg;base64,'+base64[frame];
var prev = document.createElement('button');
prev.innerHTML = '<';
prev.onclick = function() {
frame = frame -1;
if(frame<0){
frame = 0;
}
else{
// console.log(frame)
img.src = 'data:image/jpeg;base64,'+base64[frame];
};
};
document.body.appendChild(prev);
var next = document.createElement('button');
next.innerHTML = '>';
next.onclick = function() {
frame = frame+1;
if (frame>base64.length-1) {
// console.log(frame)
frame = base64.length-1
}
else{
img.src = 'data:image/jpeg;base64,'+base64[frame];
}
};
document.body.appendChild(next);
canvas.addEventListener('mousedown', mouseDown, false);
canvas.addEventListener('mouseup', mouseUp, false);
canvas.addEventListener('mousemove', mouseMove, false);
function mouseDown(e) {
rect.startX = e.pageX - this.offsetLeft;
rect.startY = e.pageY - this.offsetTop;
drag = true;
}
function mouseUp() {
drag = false;
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.drawImage(img, 0, 0);
if (rect.w<0){
rect.startX = rect.startX + rect.w
rect.w = rect.w*(-1)
}
if (rect.h<0){
rect.startY = rect.startY + rect.h
rect.h = rect.h*(-1)
}
ctx.strokeRect(rect.startX, rect.startY, rect.w, rect.h);
}
function mouseMove(e) {
if (drag) {
rect.w = (e.pageX - this.offsetLeft) - rect.startX;
rect.h = (e.pageY - this.offsetTop) - rect.startY;
ctx.strokeStyle = 'red';
ctx.lineWidth = 2;
ctx.strokeRect(rect.startX, rect.startY, rect.w, rect.h);
}
}
var saver = document.createElement('button');
saver.innerHTML = 'save rectangle';
saver.onclick = function() {
clicks.push([frame, rect.startX, rect.startY, rect.w, rect.h]);
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.drawImage(img, 0, 0);
};
document.body.appendChild(saver);
var finisher = document.createElement('button');
finisher.innerHTML = 'Done!';
finisher.onclick = function() {
};
document.body.appendChild(finisher);
await new Promise((resolve) => finisher.onclick = resolve);
document.body.removeChild(finisher)
document.body.removeChild(saver)
document.body.removeChild(next)
document.body.removeChild(prev)
document.body.removeChild(canvas)
return clicks
}
''')
display(js)
imgs = ["'"+b64img+"'" for b64img in base64imgs]
imgs = '[' + ','.join(imgs) +']'
data = eval_js(f"showImage({imgs})")
return data
I call it using:
base64imgs = [base64.b64encode(cv2.imencode('.jpg', img)[1]).decode() for img in frames]
data = get_fxy_val(base64imgs)
Everything works well for a small number of images, however for the full video Collab crushes and I cannot manage to find any logs to verify what is going on.
Two thoughts I had, which I do not know how to implement:
Reduce the images' memory size somehow. I cannot harm the aspect ratio so downsampling is not a possibility.
Load images directly from memory inside the javascript code. I have no idea how to implement this or if it is even possible.
Can I implement any of these? Is there another approach?
B.T.W, my video has images with size h,w,c = (1080, 1920, 3).

Drawimage is not drawing the x,y position of the image correctly

I'm trying to draw an image onto the canvas using drawimage:
ctx.drawImage(img, 20, 20);
However, the image appears to be drawing at a position(20, 40) relative to the top left of the canvas. I want it to be drawn at (20,20).
Here is a JS fiddle that illustrates the problem:
https://codepen.io/kapooky/pen/PoYzXeL
var canvas = document.querySelector('canvas');
var img = document.querySelector('img');
var ctx = canvas.getContext('2d');
ctx.drawImage(img, 20, 20);
//var imgData = ctx.getImageData(0,0,300,300);
function getCursorPosition(event) {
const rect = canvas.getBoundingClientRect();
var mouseX = event.clientX - rect.left;
var mouseY = event.clientY - rect.top;
// I've included helpful print statements for debugging purposes
console.log("x: " + mouseX + " y: " + mouseY);
}
canvas.addEventListener('mousedown', function (e) {
getCursorPosition(e);
});

JavaScript canvas - clearImage() - canvas.getBoundingClientRect

I cannot clear the cursor image (canvas.getBoundingClientRect) after the cursor moves across the canvas element! I am left with a trail of appended images on the canvas.
How can I clear the trail of appended images and still keep my customized cursor (canvas.getBoundingClientRect) visible each time the canvas is cleared?
See my code :
<script>
window.addEventListener("load", CanvasProperties, false);
//Global Variables
var canvas, context;
// Canvase Element - 2D Properties
function CanvasProperties(){
canvas = document.getElementById("canvas");
context = canvas.getContext("2d");
window.addEventListener("mousemove", CustomCursor, false);};
// Customized Cursor for Game's Canvas
function CustomCursor(e){
var canvasRect = canvas.getBoundingClientRect();
var xPosition = e.clientX - 5 - canvasRect.left;
var yPosition = e.clientY - 5 - canvasRect.top;
var img = new Image();
img.src = "hero.png";
context.drawImage(img, xPosition, yPosition, 80, 80);};
</script>
Yeah, this one was really hard to google. The answer I like the best: https://stackoverflow.com/a/2142549/607407
function CustomCursor(e){
var canvasRect = canvas.getBoundingClientRect();
var img = new Image();
img.src = "https://crossorigin.me/https://www.gravatar.com/avatar/5a061a72feb5b6580dadd5dcbc92d3b5?s=64&d=identicon&r=PG";
var xPosition = e.clientX - 5 - canvasRect.left-img.naturalWidth/2;
var yPosition = e.clientY - 5 - canvasRect.top- img.naturalHeight/2;
context.clearRect(0, 0, canvas.width, canvas.height);
context.drawImage(img, xPosition, yPosition, 80, 80);
};
Snippet:
//Global Variables - which is wrong
var canvas, context;
// Canvase Element - 2D Properties
function CanvasProperties(){
canvas = document.getElementById("canvas");
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
context = canvas.getContext("2d");
window.addEventListener("mousemove", CustomCursor, false);
}
// Customized Cursor for Game's Canvas
function CustomCursor(e){
var canvasRect = canvas.getBoundingClientRect();
var img = new Image();
img.src = "https://crossorigin.me/https://www.gravatar.com/avatar/5a061a72feb5b6580dadd5dcbc92d3b5?s=64&d=identicon&r=PG";
var xPosition = e.clientX - 5 - canvasRect.left-img.naturalWidth/2;
var yPosition = e.clientY - 5 - canvasRect.top- img.naturalHeight/2;
context.clearRect(0, 0, canvas.width, canvas.height);
context.drawImage(img, xPosition, yPosition, 80, 80);
};
CanvasProperties();
<canvas width="300" height="300" id="canvas" />
Customized Canvas Cursor - Works! :)
<!DOCTYPE html>
<html>
<body id="body" style="background-color:gray;">
<canvas id="canvas" width="600" height="400" style="background-color:white;
display:block; margin:1 auto;"> </canvas>
<script>
window.addEventListener("load", CanvasProperties, false);
//JavaScript Variables
var canvas, context;
// Canvase Element - 2D Properties
function CanvasProperties(){
canvas = document.getElementById("canvas");
context = canvas.getContext("2d");
window.addEventListener("mousemove", CustomCursor, false);
}
// Customized Cursor for Game's Canvas
function CustomCursor(e){
var canvasRect = canvas.getBoundingClientRect();
var img = new Image(); img.src = "hero.png";
var xPosition = e.clientX - 5 - canvasRect.left;
var yPosition = e.clientY - 5 - canvasRect.top;
context.clearRect(0, 0, canvas.width, canvas.height);
context.drawImage(img, xPosition, yPosition, 80, 80);
};
CanvasProperties();
</script>
</body>
</html>
You could just use css for this very easily, as the above stated in the comments, don't reinvent the wheel, javascript is still a lot slower than the native client the browser is running on. check out this https://davidwalsh.name/css-custom-cursor and you can use the canvas:hover to make it so it uses your custom cursor whenever the mouse is over it.

How to have two layers of Canvas one over another

I am making a canvas, where there is a large image and behind it there is another image. then by using mouse coordinate I made a circle around the cursor. This circle will work as a hole to reveal the hidden image under the background. I made it kinda but I cannot set the front image.
Have a look at my code please: JSFiddle
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
var x = 0;
var y = 0;
var width = 578;
var height = 400;
var imageObj = new Image();
imageObj.src = 'http://www.html5canvastutorials.com/demos/assets/darth-vader.jpg';
function writeMessage(canvas, message, x, y) {
var context = canvas.getContext('2d');
context.clearRect(0, 0, canvas.width, canvas.height);
var pattern = context.createPattern(imageObj, 'no-repeat');
context.fillStyle = pattern;
context.fill();
context.font = '28pt Calibri';
context.fillStyle = 'black';
//context.fillText(message, x, y);
context.beginPath();
context.arc(x, y, 50, 0, 2 * Math.PI);
context.stroke();
}
function getMousePos(canvas, evt) {
var rect = canvas.getBoundingClientRect();
return {
x: evt.clientX - rect.left,
y: evt.clientY - rect.top
};
}
canvas.addEventListener('mousemove', function (evt) {
var mousePos = getMousePos(canvas, evt);
//var message = 'Mouse position: ' + mousePos.x + ',' + mousePos.y;
writeMessage(canvas, message, mousePos.x, mousePos.y);
}, false);
context.fillStyle = 'black';
context.fill();
Can someone tell me please how to have an image as big as the canvas to cover it?
Thanks
It looks like you are on the right track. The easiest way to have an image where the circle is not in your setup, would be to set a background image on the canvas element, and use background-size: cover to make it fill the canvas area.
Working Example (see CSS in second block):
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
var x = 0;
var y = 0;
var width = 578;
var height = 400;
var imageObj = new Image();
imageObj.src = 'http://www.html5canvastutorials.com/demos/assets/darth-vader.jpg';
function writeMessage(canvas, message, x, y) {
var context = canvas.getContext('2d');
context.clearRect(0, 0, canvas.width, canvas.height);
var pattern = context.createPattern(imageObj, 'no-repeat');
context.fillStyle = pattern;
context.fill();
context.font = '28pt Calibri';
context.fillStyle = 'black';
//context.fillText(message, x, y);
context.beginPath();
context.arc(x, y, 50, 0, 2 * Math.PI);
context.stroke();
}
function getMousePos(canvas, evt) {
var rect = canvas.getBoundingClientRect();
return {
x: evt.clientX - rect.left,
y: evt.clientY - rect.top
};
}
canvas.addEventListener('mousemove', function (evt) {
var mousePos = getMousePos(canvas, evt);
var message = 'Mouse position: ' + mousePos.x + ',' + mousePos.y;
writeMessage(canvas, message, mousePos.x, mousePos.y);
}, false);
canvas, img {
display:block;
margin:1em auto;
border:1px solid black;
}
canvas {
background:url('http://img2.wikia.nocookie.net/__cb20090917002539/starwars/images/7/70/Vader_yelloweyes.jpg');
background-size: cover;
}
<canvas id="myCanvas" width="578" height="400"></canvas>
<p></p>
To get the foreground image to fill the canvas, and take care of the edge, you need to resize the image in another canvas.
Working Example:
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
var x = 0;
var y = 0;
var width = 578;
var height = 400;
var imageObj = new Image();
//Create another canvas to darw a resized image to.
var imageResized = document.createElement('canvas');
imageResized.width = width;
imageResized.height = height;
//Wait for the original image to low to draw the resize.
imageObj.onload = function() {
//Find hoe mauch to scale the image up to cover.
var scaleX = width / imageObj.width;
var scaleY = height / imageObj.height;
var scaleMax = Math.max(scaleX, scaleY);
var ctx = imageResized.getContext('2d');
ctx.scale(scaleMax, scaleMax);
ctx.drawImage(imageObj, 0, 0);
};
imageObj.src = 'http://www.html5canvastutorials.com/demos/assets/darth-vader.jpg';
function writeMessage(canvas, message, x, y) {
var context = canvas.getContext('2d');
context.clearRect(0, 0, canvas.width, canvas.height);
var pattern = context.createPattern(imageResized, 'no-repeat');//Use imageResized, not imageObj.
context.fillStyle = pattern;
context.fill();
context.font = '28pt Calibri';
context.fillStyle = 'black';
//context.fillText(message, x, y);
context.beginPath();
context.arc(x, y, 50, 0, 2 * Math.PI);
context.stroke();
}
function getMousePos(canvas, evt) {
var rect = canvas.getBoundingClientRect();
return {
x: evt.clientX - rect.left,
y: evt.clientY - rect.top
};
}
canvas.addEventListener('mousemove', function (evt) {
var mousePos = getMousePos(canvas, evt);
var message = 'Mouse position: ' + mousePos.x + ',' + mousePos.y;
writeMessage(canvas, message, mousePos.x, mousePos.y);
}, false);
canvas, img {
display:block;
margin:1em auto;
border:1px solid black;
}
canvas {
background:url('http://img2.wikia.nocookie.net/__cb20090917002539/starwars/images/7/70/Vader_yelloweyes.jpg');
background-size: cover;
}
<canvas id="myCanvas" width="578" height="400"></canvas>
<p></p>

Drawing a filled circle in a canvas on mouseclick

I want to draw a filled (or not filled) circle in a canvas on mouseclick, but I can't get my code to work properly, I've tried pretty much everything!
This is my HTML:
<div id="images"></div>
<canvas style="margin:0;padding:0;position:relative;left:50px;top:50px;" id="imgCanvas" width="250" height="250" onclick="draw(e)"></canvas>
and my current script:
var canvas = document.getElementById("imgCanvas");
var context = canvas.getContext("2d");
function createImageOnCanvas(imageId) {
canvas.style.display = "block";
document.getElementById("images").style.overflowY = "hidden";
var img = new Image(300, 300);
img.src = document.getElementById(imageId).src;
context.drawImage(img, (0), (0)); //onload....
}
function draw(e) {
var pos = getMousePos(canvas, e);
posx = pos.x;
posy = pos.y;
context.fillStyle = "#000000";
context.arc(posx, posy, 50, 0, 2 * Math.PI);
}
function getMousePos(canvas, evt) {
var rect = canvas.getBoundingClientRect();
return {
x: evt.clientX - rect.left,
y: evt.clientY - rect.top
};
}
The code works just fine if and only if I remove the "use strict";, but in this assignment I have to make a code that works even with it, which is my problem.
Here is the jsFiddle
Solved it myself.
function draw(e) {
var canvas = document.getElementById("imgCanvas");
var context = canvas.getContext("2d");
var rect = canvas.getBoundingClientRect();
var posx = e.clientX - rect.left;
var posy = e.clientY - rect.top;
context.fillStyle = "#000000";
context.beginPath();
context.arc(posx, posy, 50, 0, 2 * Math.PI);
context.fill();
}
This script works fine for me.

Categories

Resources