how to create pixelated video with pure java script - javascript

I am trying to create a blurred face video (when there were squares)
everything is ok until I minimize the size of the square then it becomes so laggy
and slow even some times the video stop working for example when the blur = 1 ;
this is my code :
<!DOCTYPE html>
<html>
<head>
<style>
#canvas{
width: 400px;
}
</style>
</head>
<body>
<video id="video" controls width="300" height="300"></video>
<canvas id="canvas" width="1280" height="720" ></canvas>
<script>
// Get references to the video and canvas elements
var video = document.getElementById("video");
var canvas = document.getElementById("canvas");
var context = canvas.getContext("2d");
var videoSource = "111.mp4" ;
video.src = videoSource;
video.addEventListener("play", function() {
drawVideo();
});
function drawVideo() {
context.drawImage(video, 0, 0);
let blur = 20 ;
let originalImageData = context.getImageData( 0, 0, canvas.width, canvas.height ).data;
for (let y = 0; y < canvas.height; y += blur) {
for (let x = 0; x < canvas.width; x += blur) {
const pixelIndexPosition = (x + y * canvas.width) * 4;
context.fillStyle = `rgba(
${originalImageData[pixelIndexPosition]},
${originalImageData[pixelIndexPosition + 1]},
${originalImageData[pixelIndexPosition + 2]},
${originalImageData[pixelIndexPosition + 3]})`;
context.fillRect(x, y, blur, blur);
}
}
// Continue to draw the video
if (video.paused || video.ended) {
return;
}
requestAnimationFrame(drawVideo);
}
</script>
</body>
</html>

Related

Html5 canvas animation leaves a trail

I'm trying to make a little game to play around with canvas. I've decided to go for Flappy Bird as there are plenty of examples online. My goal was to make the game "responsive" for all devices. If you open it in a mobile or whichever screen, you should be able to play it normally.
For this purpose I drew a background image within the canvas that will adapt the height to the screen's height and repeat it through the x-axis.
The issue I'm having is that, when I animate the bird, this one leaves a trail behind it.
As like so:
An easy fix would be clearing the canvas as explained in this post:
Canvas image leaves weird trail when moving left
But it isn't possible because of the way I'm painting my background (I paint it once and repaint it if it resizes).
Question
How do I avoid this image trail with a static background? Is it maybe possible to have like a false static background that doesn't need to be repainted?
I obviously want to do it in the canvas, without needing to have an image in the html.
This is the code with the main functionality so that you can take a look:
const cvs = document.getElementById("canvas");
const ctx = cvs.getContext("2d");
cvs.style.height = "100vh";
cvs.style.width = "100vw";
var bird = new Image();
var bg = new Image();
bird.src = "https://lh3.googleusercontent.com/prntPuix7QxlhKXx6IBtTxv7PrdEJtmzFJ4mopScNS1_klze86BVNy3PqHbQn2UQ4JyJdix3XQ=w128-h128-e365";
bg.src = "https://opengameart.org/sites/default/files/bg_5.png";
let gravity = 1;
birdPositionY = 10;
birdPositionX = 50;
const draw = () => {
ctx.drawImage(bird, birdPositionX, birdPositionY);
birdPositionY += gravity;
birdPositionX += 3;
requestAnimationFrame(draw);
};
const resizeCanvas = () => {
const {
width,
height
} = cvs.getBoundingClientRect();
cvs.height = height;
cvs.width = width;
let x = 0,
y = 0;
while (x < cvs.width && y < cvs.height) {
ctx.drawImage(bg, x, y, 360, cvs.height);
x += bg.width;
}
};
bg.onload = () => {
resizeCanvas();
};
window.addEventListener("resize", resizeCanvas, false);
draw();
<!DOCTYPE html>
<html>
<head>
<title>Flappy Bird</title>
<meta name="viewport" content="width=device-width, user-scalable=no" />
<style>
html {
overflow: hidden;
}
body {
margin: 0;
}
canvas {
width: 100vw;
height: 100vh;
}
</style>
</head>
<body>
<canvas id="canvas"></canvas>
<script src="index.js"></script>
</body>
</html>
Hope it did make sense!
Thanks in advance!
Draw your background on a canvas that you will keep off-screen, then draw this canvas every frame on your visible one before you draw your moving parts.
const cvs = document.getElementById("canvas");
const ctx = cvs.getContext("2d");
// our backround canvas that we won't append in the doc ("off-screen")
const background = cvs.cloneNode();
const bg_ctx = background.getContext('2d');
cvs.style.height = "100vh";
cvs.style.width = "100vw";
var bird = new Image();
var bg = new Image();
bird.src = "https://lh3.googleusercontent.com/prntPuix7QxlhKXx6IBtTxv7PrdEJtmzFJ4mopScNS1_klze86BVNy3PqHbQn2UQ4JyJdix3XQ=w128-h128-e365";
bg.src = "https://opengameart.org/sites/default/files/bg_5.png";
let gravity = 1;
birdPositionY = 10;
birdPositionX = 50;
const draw = () => {
// first draw the background canvas
ctx.drawImage(background, 0,0);
// then your persona
ctx.drawImage(bird, birdPositionX, birdPositionY);
birdPositionY += gravity;
birdPositionX += 3;
requestAnimationFrame(draw);
};
const resizeCanvas = () => {
const {
width,
height
} = cvs.getBoundingClientRect();
// resize both canvases
cvs.height = background.height = height;
cvs.width = background.width = width;
let x = 0,
y = 0;
while (x < cvs.width && y < cvs.height) {
// draw on the off-screen canvas
bg_ctx.drawImage(bg, x, y, 360, cvs.height);
x += bg.width;
}
};
bg.onload = () => {
resizeCanvas();
draw();
};
window.addEventListener("resize", resizeCanvas, false);
<!DOCTYPE html>
<html>
<head>
<title>Flappy Bird</title>
<meta name="viewport" content="width=device-width, user-scalable=no" />
<style>
html {
overflow: hidden;
}
body {
margin: 0;
}
canvas {
width: 100vw;
height: 100vh;
}
</style>
</head>
<body>
<canvas id="canvas"></canvas>
<script src="index.js"></script>
</body>
</html>
I think you could just call resizeCanvas in your draw loop to redraw the background.
EDIT: Apparently that does not work. Another option is just drawing it in the draw loop like this:
const draw = () => {
ctx.clearRect(0, 0, cvs.width, cvs.height)
let x = 0, y = 0;
while (x < cvs.width && y < cvs.height) {
ctx.drawImage(bg, x, y, 360, cvs.height);
x += bg.width;
}
ctx.drawImage(bird, birdPositionX, birdPositionY);
birdPositionY += gravity;
birdPositionX += 3;
requestAnimationFrame(draw);
};
Edit: That did not work either. The other option would be to make two canvases and overlap them with one drawing the background and one drawing the bird.

Repeating image in a canvas with responsive height

I'm trying to create a canvas where I have an image as a background that repeats horizontally and adapts the height automatically.
I've managed to repeat the background image following the x-axis but I'm unable to make the height responsive.
This is my code so far:
const cvs = document.getElementById("canvas");
const ctx = cvs.getContext("2d");
const bg = new Image();
bg.src = "http://lorempixel.com/100/100";
const draw = () => {
const ptrn = ctx.createPattern(bg, "repeat-x");
ctx.fillStyle = ptrn;
ctx.fillRect(0, 0, canvas.width, canvas.height);
requestAnimationFrame(draw);
};
draw();
<!DOCTYPE html>
<html>
<head>
<title>Test</title>
</head>
<body>
<canvas id="canvas" width="1000" height="200"></canvas>
<script src="index.js"></script>
</body>
</html>
TLDR: I would like to be able to have an image within my canvas that repeats horizontally and its height is responsive.
Thanks in advance.
Hopefully the explanation in the comments answers your question. Feel free to ask for clarification.
const cvs = document.getElementById("canvas");
const ctx = cvs.getContext("2d");
// First stretch the canvas so we can get
// the full size of teh browser window
cvs.style.height = '100vh';
cvs.style.width = '100vw';
// Now adjust actual canvas size to match
const {width, height} = cvs.getBoundingClientRect();
cvs.height = height;
cvs.width = width;
const bg = new Image();
// Should always wait for onload
// before drawing to prevent race condition.
bg.onload = ()=>{
var x=0;
while(x < cvs.width){
ctx.drawImage(bg, x, 0, 100, cvs.height);
x += bg.width;
}
// draw the image a bunch of times
// var x=0, y=0;
// while(x < cvs.width && y < cvs.height){
// ctx.drawImage(bg, x, y);
// x += bg.width;
// if(x > cvs.width){
// x = 0;
// y += bg.height;
// }
// }
};
bg.src = "http://lorempixel.com/100/100";
<canvas id="canvas"></canvas>
<script src="index.js"></script>
If I got it right you want to fill the height and repeat horizontally, is that correct?
const cvs = document.getElementById("canvas");
const ctx = cvs.getContext("2d");
var bg = new Image();
bg.src = "http://lorempixel.com/100/100";
var tempCanvas = document.createElement("canvas"),
tCtx = tempCanvas.getContext("2d");
var imgWidth = 200;
var imgHeight = 200;
const draw = () => {
tempCanvas.width = imgWidth;
tempCanvas.height = imgHeight;
tCtx.drawImage(bg, 0, 0, 100, 100, 0, 0, imgWidth, imgHeight);
const ptrn = ctx.createPattern(tempCanvas , "repeat-x");
ctx.fillStyle = ptrn;
ctx.fillRect(0, 0, canvas.width, canvas.height);
requestAnimationFrame(draw);
};
bg.onload = () => {
draw();
}
<!DOCTYPE html>
<html>
<head>
<title>Test</title>
</head>
<body>
<canvas id="canvas" width="1000" height="200"></canvas>
<script src="index.js"></script>
</body>
</html>
try setting up the image size to match the canvas size just like that:
bg.src = "http://lorempixel.com/200/200";
Cheers! :)

Redraw or delete the existing canvas and create a new one with modified content

I am trying to delete the existing canvas and create a new one with the modified content (of the old one).
Below is the code I have tried.
/* Identifying the Canvas child inside the div parent */
var c = document.getElementById("myCanvasDiv"),
canv = '',
cv = '';
for (i = 0; i < c.childElementCount; i++) {
console.log(c.children[i].nodeName);
if (c.children[i].nodeName == "CANVAS") {
//console.log(c.children[i].getContext('2d'));
canv = c.children[i];
cv = c.children[i].getContext('2d');
}
}
var new_cv = cv
var items = new_cv.canvas.aa.nodes.bi.ud
var keys = []
/* Retrieving the keys */
for (var i in items){
//console.log(items[i].value.Zd["key"]);
keys.push(i + "|" +items[i].value.Zd["key"]);
}
/* Modifying the Content */
for (var i in items){
var strVal = items[i].value.Zd["key"];
//console.log(items[i].value.Zd["key"]);
for (var j in keys){
if(items[i].value.Zd["key"] && items[i].value.Zd["key"].substring(0,items[i].value.Zd["key"].length-1) == keys[j].split("|")[1]){
items[i].value.Zd["key"] = keys[j].split("|")[1];
}
}
console.log(strVal + "----->" + items[i].value.Zd["key"]);
}
/* Trying to reset the canvas content */
for (i = 0; i < c.childElementCount; i++) {
if (c.children[i].nodeName == "CANVAS") {
/*c.removeChild(c.children[i]);
var newcanvas = document.createElement("canvas");
newcanvas.id="canvas1";
newcanvas.getContext = new_cv;
c.appendChild(newcanvas);*/
//cHeight = c.children[i].height;
//cWidth = c.children[i].width;
//cv.clearRect(0,0,c.children[i].width,c.children[i].height);
//c.children[i] = new_cv;
//cv.setContext(new_cv);
canv.getContext = new_cv;
console.log(cv);
}
}
is there any way I can achieve this.
Thanks in advance.
The simplest way to do it is this:
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
ctx.fillStyle = "red";
ctx.fillRect(10, 10, 50, 50);
ctx.clearRect(0,0, c.width, c.height);
ctx.fillStyle = "black";
ctx.fillRect(10, 10, 50, 50);
<canvas id="myCanvas" width="300" height="150" style="border:1px solid #d3d3d3;">
Your browser does not support the HTML5 canvas tag.</canvas>
<button onclick="copy()">Copy</button>
<p id="cont"> FillStyle Content</p>
However if you want to use pixel manipulation (much more expensive) you can do this:
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
ctx.fillStyle = "red";
ctx.fillRect(10, 10, 50, 50);
var imgData = ctx.getImageData(0, 0, ctx.canvas.width, ctx.canvas.height);
// for every pixel if the red channel value is 255 (i.e. red) then make it black (0)
for (var i = 0; i < imgData.data.length; i += 4) {
if (imgData.data[i + 0] == 255) {
imgData.data[i + 0] = 0;
}
}
// put the modified image back
ctx.putImageData(imgData, 0, 0);
<canvas id="myCanvas" width="300" height="150" style="border:1px solid #d3d3d3;">
Your browser does not support the HTML5 canvas tag.</canvas>
<button onclick="copy()">Copy</button>
<p id="cont"> FillStyle Content</p>

JS Canvas: How to make rectangle go back and forth once it reaches the boundary

So I have this rectangle that animates across to the right. How can I get the rectangle to reverse it when it hits the boundaries. I'm trying to make it go back and forth.
<!DOCTYPE html>
<html>
<head>
<script type='text/javascript'>
window.onload=function(){
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
var x = 0;
var y = 50;
var width = 10;
var height = 10;
function animate() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.fillRect(x, y, width, height);
x++;
if(x <= 490) {
setTimeout(animate, 33);
}
}
animate();
}
</script>
</head>
<body>
<canvas id="canvas" width="500" height="400"
style="border: 1px solid #000000;"></canvas>
</body>
</html>
https://codepen.io/forTheLoveOfCode/pen/wqdpeg
Is that what you need? (link to codepen above).
var canvas = document.getElementById("canvas_id");
var context = canvas.getContext('2d');
var x=5;
var y=5;
var velocity = 10;
function move(){
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
x =x + velocity
if ((x+50)>canvas.width || x<0){
velocity *=-1;
}
draw()
}
function draw(){
context.fillStyle = "#E80C7A";
context.strokeStyle = "#000000";
context.lineWidth = '3';
context.fillRect(x, y, 50, 100);
context.strokeRect(x, y, 50, 100);
}
setInterval(move, 100);
<html>
<body>
<canvas id = "canvas_id">
</canvas>
</body>
</html>
here's a solution with boundaries detection
window.onload=function(){
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
var x = 0;
var y = 50;
var width = 10;
var height = 10;
var speed = 10; // speed
function animate() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.fillRect(x, y, width, height);
if(
(x >= 500 - width && speed > 0) || // going to the right and bound reached
(x <= 0 && speed < 0) // going to the left and bound reached
) {
speed *= -1; // inverting the direction
}
x += speed;
setTimeout(animate, 33);
}
animate();
}
<canvas id="canvas" width="500" height="400"
style="border: 1px solid #000000;"></canvas>
consider using requestAnimationFrame instead of setTimeout to do this kind of work.

Unable to put one canvas under another

I want to put a canvas under another. I am pretty new at javascript so i apologize in advance if the following code looks a bit messy. I want to make the canvas called "myCanvas" appear behind "coinAnimation". All responses are extremely appreciated.
HTML
<div id="wrapper">
<canvas id="coinAnimation" height="500" width="500"></canvas>
<canvas id="myCanvas" height="500" width="600"></canvas>
</div>
Javascript
<script type="text/javascript">
(function () {
var coin,
coinImage,
canvas;
function gameLoop () {
window.requestAnimationFrame(gameLoop);
coin.update();
coin.render();
}
function sprite (options) {
var that = {},
frameIndex = 0,
tickCount = 0,
ticksPerFrame = options.ticksPerFrame || 0,
numberOfFrames = options.numberOfFrames || 1;
that.context = options.context;
that.width = options.width;
that.height = options.height;
that.image = options.image;
that.update = function () {
tickCount += 1;
if (tickCount > ticksPerFrame) {
tickCount = 0;
// If the current frame index is in range
if (frameIndex < numberOfFrames - 1) {
// Go to the next frame
frameIndex += 1;
} else {
frameIndex = 0;
}
}
};
that.render = function () {
// Clear the canvas
that.context.clearRect(0, 0, that.width, that.height);
// Draw the animation
that.context.drawImage(
that.image,
frameIndex * that.width / numberOfFrames,
-110,
that.width / numberOfFrames,
that.height,
0,
0,
that.width / numberOfFrames,
that.height);
};
return that;
}
// Get canvas
canvas = document.getElementById("coinAnimation");
canvas.width = 600;
canvas.height = 300;
// Create sprite sheet
coinImage = new Image();
// Create sprite
coin = sprite({
context: canvas.getContext("2d"),
width: 1000,
height: 300,
image: coinImage,
numberOfFrames: 10,
ticksPerFrame: 7
});
// Load sprite sheet
coinImage.addEventListener("load", gameLoop);
coinImage.src = "images/test2.png";
} ());
</script>
<script type="text/javascript">
window.addEventListener('load', function () {
var
img = new Image,
ctx = document.getElementById('myCanvas').getContext('2d');
img.src = "images/back.png";
img.addEventListener('load', function () {
var interval = setInterval(function() {
var x = 0, y = 0;
return function () {
ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
ctx.drawImage(img, x, y);
x += -1;
if (x > ctx.canvas.width) {
x = 0;
}
};
}(), 1000/40);
}, false);
}, false);
</script>
See here: jsfilddle.net. I added the background colors to demonstrate positioning and z-index.
First, make the wrapper div position relative. This is the position that the container divs will be based off. Then make the container divs absolute positioned to (0,0). Then, set the z-index so that myCanvas is behind coinAnimation.
CSS:
#wrapper
{
position:relative;
}
#coinAnimation
{
background-color:blue;
position:absolute;
z-index:1;
}
#myCanvas
{
background-color:red;
position:absolute;
top:0px;
left:0px;
z-index:0;
}
HTML:
<div id="wrapper">
<canvas id="coinAnimation" height="500" width="500"></canvas>
<canvas id="myCanvas" height="500" width="600"></canvas>
</div>

Categories