Passing Video File Input to p5js Canvas - javascript

I am trying to use Bootstrap to create a prettier interface to upload a video file rather than the p5js "createFileInput()" function. I want the video in p5js so I can overlay animations onto it. For some reason my code is displaying the video twice as soon as I use the function "createVideo" and if I try and hide the DOM that is the second video outside of the canvas it disappears from the p5js canvas. Here is my code:
var view = {
vid: "",
cHeight: 500,
cWidth: 700,
xVid: 0,
yVid: 0,
};
function setup() {
let cnv = createCanvas(view.cWidth, view.cHeight);
cnv.id("p5jsCanvas");
}
function draw() {
if (view.vid) {
// We have an uploaded video so draw it
//background(0);
console.log(view.vid.id());
image(view.vid, view.xVid, view.yVid);
} else {
background(0);
}
}
$("#videoFileUpload").on("change", function() {
var fileName = $(this).val().split("\\").pop();
$(this).siblings(".custom-file-label").addClass("selected").html(fileName);
if (this.files && this.files[0]) {
console.log(this.files[0]);
var fileLocation = URL.createObjectURL(this.files[0]);
console.log(fileLocation);
view.vid = createVideo([fileLocation], resizeVid);
view.vid.id("poseVid");
}
});
function resizeVid(){
// If the height is greater than the width use the height to scale and AUTO for the width
if (view.vid.height > view.vid.width){
console.log("height > width");
view.vid.size(AUTO, cHeight);
} else { // Else if the width is greater than or equal to the height use the width to scale and AUTO for the height
view.vid.size(view.cWidth, AUTO);
}
// Reset location of the video
let currW = $("#poseVid").attr('width');
let currH = $("#poseVid").attr('height');
view.xVid = (view.cWidth - currW)/2;
view.yVid = (view.cHeight - currH)/2;
}

I realized that I needed to use hide() on the video element and then provide a way to "play" the element in p5js and then it worked. I also added removing the id if it existed already so that I could upload a different video after one was already uploaded.
var view = {
vid: "",
cHeight: 500,
cWidth: 700,
xVid: 0,
yVid: 0,
};
function setup() {
let cnv = createCanvas(view.cWidth, view.cHeight);
cnv.id("p5jsCanvas");
}
function draw() {
if (view.vid) {
// We have an uploaded video so draw it
//background(0);
console.log(view.vid.id());
image(view.vid, view.xVid, view.yVid);
} else {
background(0);
}
}
$("#videoFileUpload").on("change", function() {
var fileName = $(this).val().split("\\").pop();
$(this).siblings(".custom-file-label").addClass("selected").html(fileName);
if (this.files && this.files[0]) {
console.log(this.files[0]);
var fileLocation = URL.createObjectURL(this.files[0]);
console.log(fileLocation);
$("#poseVid").remove(); // ADDED
view.vid = createVideo([fileLocation], resizeVid);
// view.vid.id("poseVid"); // MOVED TO resizeVid function
}
});
// ADDED FUNCTION JUST TO TEST THE PLAYBACK
function mousePressed() {
view.vid.loop(); // set the video to loop and start playing
}
function resizeVid(){
// If the height is greater than the width use the height to scale and AUTO for the width
view.vid.id("poseVid"); //MOVED INTO THIS FUNCTION
$("#poseVid").hide(); //ADDED
if (view.vid.height > view.vid.width){
console.log("height > width");
view.vid.size(AUTO, cHeight);
} else { // Else if the width is greater than or equal to the height use the width to scale and AUTO for the height
view.vid.size(view.cWidth, AUTO);
}
// Reset location of the video
let currW = $("#poseVid").attr('width');
let currH = $("#poseVid").attr('height');
view.xVid = (view.cWidth - currW)/2;
view.yVid = (view.cHeight - currH)/2;
}

Related

Extract exif data/rotate image added to fabric.js canvas

In my web app users can take photos on their phones from input type file.
Before I used js load image library to automatically detect EXIF data and rotate it if neccessary.
Now I've switched to fabric.js library because I want to allow users to draw on the canvas image before uploading it.
The problem is that I don't know how to get image exif data, or rotate the image when using fabric.js.
My code:
Getting the image from indexed db
var image;
localforage.getItem('photo').then(function(value) {
image = value;
// THIS IS OLD CODE, BEFORE I USER js-load-image to automatically detect exif data
// and rotate if neccessary, then I just appended the result to wrapper
// $("#preview-wrapper").empty();
// if (image) {
// loadImage(
// image,
// function(img) {
// $("#preview-wrapper").append(img);
// },
// {orientation: true} // Options
// );
// }
})
loadFabricOnImageLoad(); // append image to fabric canvas
Fabric.js function
function loadFabricOnImageLoad(){
if(typeof image !== "undefined" && image){
let loaded = false;
if (loaded) {return;}
var c = document.getElementById('myCanvas');
canvas = new fabric.Canvas(c);
canvas.setWidth(width);
canvas.setHeight(500);
canvas.selection = false;
var url = URL.createObjectURL(image);
fabric.Image.fromURL(url, function(img) {
img.set({
left: 0,
right: 0,
top: 0,
});
img.scaleToWidth(width);
canvas.add(img);
canvas.setHeight(img.getScaledHeight());
$("#canvas-loader").hide();
});
fabric.Object.prototype.set({
evented: false
});
canvas.freeDrawingBrush = new fabric['PencilBrush'](canvas);
canvas.freeDrawingBrush.color = 'Red';
canvas.freeDrawingBrush.width = 6;
loaded = true;
} else {
setTimeout(loadFabricOnImageLoad, 250);
}
}
I've managed to do it myself after all by getting the exif data from image file:
localforage.getItem('photo').then(function(value) {
image = value;
// extract the exif data from image file using exif.js
EXIF.getData(image, function() {
let obj = EXIF.getAllTags(this);
imageOrientation = obj.Orientation;
console.log( imageOrientation );
});
})
I had to do a lot of scaling and resizing to get the size of rotated image and canvas correctly:
function loadFabricOnImageLoad(){
if(typeof image !== "undefined" && image){
let loaded = false;
if (loaded) {return;}
var c = document.getElementById('myCanvas');
canvas = new fabric.Canvas(c);
canvas.setWidth(width);
canvas.setHeight(500);
canvas.selection = false;
var url = URL.createObjectURL(image);
fabric.Image.fromURL(url, function(img) {
img.scaleToWidth(canvas.width);
if(imageOrientation == 3 || imageOrientation == 6 || imageOrientation == 8) {
img.scaleToHeight(canvas.height);
canvas.setHeight(img.getScaledHeight());
canvas.add(img);
img.scaleToWidth(canvas.height);
img.scaleToHeight(canvas.width);
img.rotate(getDegreesForOrientation(imageOrientation));
img.center();
} else {
canvas.setHeight(img.getScaledHeight());
canvas.add(img);
}
$("#canvas-loader").hide();
});
// console.log('slika '+JSON.stringify(fabric.Image));
fabric.Object.prototype.set({
evented: false
});
canvas.freeDrawingBrush = new fabric['PencilBrush'](canvas);
canvas.freeDrawingBrush.color = 'Red';
canvas.freeDrawingBrush.width = 6;
loaded = true;
} else {
setTimeout(loadFabricOnImageLoad, 250);
}
}
I know this is already answered but I'd like to suggest different library. exif-js is dead - buggy and no longer maintained, with hundred of unsolved issues.
I would like you to try exifr which i started developing out of frustrations with exif-js.

How can I check image orientation in Angular before uploading image

I just want to image being upload on my website must portrait or square and I don't want to crop image, image to be uploaded must be portrait or square by default I have searched number of website \ number method use but none worked
know I am trying this method but it also not working because it is running async
if give landscape image in given code it runs if which should not run as
hasError must be true but doesn't because if condition run before the above code could complete so what can I do
let hasError = false;
image = event.target.files[0];
if (image) {
var img = new Image();
img.src = window.URL.createObjectURL(image);
img.onload = function () {
height = img.naturalHeight;
width = img.naturalWidth;
console.log(hasError); // prints false
if (height < width) {
hasError = true; // prints true
console.log(hasError);
}
window.URL.revokeObjectURL(img.src);
}
console.log(hasError); //prints flase
}
if(!hasError){
....
}
I think you should create a function and move your image validation into your function and use a callback to find out the image has error or not.
var fileInput = document.querySelector('input[type="file"]');
var preview = document.getElementById('preview'); //img tag
previewImage(function(hasError){
if (!hasError){
//do something
}
});
function previewImage(callback){
fileInput.addEventListener('change', function(e) {
preview.onload = function() {
height = this.naturalHeight;
width = this.naturalWidth;
if (height < width) {
callback(true);
}
window.URL.revokeObjectURL(this.src);
callback(false);
};
var url = URL.createObjectURL(e.target.files[0]);
preview.setAttribute('src', url);
}, false);
}

How to avoid flickering images with keypress?

I have a piece of code where a user has to press 0 to mute the sound or 1 to play the sound of a music piece. If the sound is muted, the image changes and otherwise when the music plays.
var audio = new Audio();
window.onload = function geluidMaken() {
audio.src = "../Geluiden/Achtergrond_Geluid.mp3";
audio.play();
audio.loop = true;
window.addEventListener("keypress", function geluidsKnoppen() {
var codeGeluid = event.which || event.keyCode;
if(codeGeluid == 48) {
var geluidAanKnop = new Image();
geluidAanKnop.src = "../Afbeeldingen/Sound_Button.png";
mijnObject.drawImage(geluidAanKnop, (canvas.width/2)-25, 850, geluidAanKnop.width, geluidAanKnop.height);
audio.muted = true;
}
else if(codeGeluid = 49) {
var geluidAfKnop = new Image();
geluidAfKnop.src = "../Afbeeldingen/Mute_Button.png";
mijnObject.drawImage(geluidAfKnop, (canvas.width/2)-25, 850, geluidAfKnop.width, geluidAfKnop.height);
audio.muted = false;
}
});
}
I have also a other piece of code where I render all my other functions
function tekenenObjecten() {
mijnObject.clearRect(0, 0, canvas.width, canvas.height);
makenBalkKort();
makenBal();
makenMuur();
makenBord();
The images aren't visible on the canvas but when I click on the keys 0 or 1 the images appears and dissapears directly. How to make sure the images stay on the canvas and change when the 0 or 1 is pressed?
When working with a canvas in html5, remember that when you redraw a frame, you remove everything that is on the canvas, then draw everything you want to see in the new frame.
In your keypress handler, you draw the image once. When a new frame is drawn in the other part of your code, the canvas is cleared, and you never redraw it.
What you want to do is probably have a placeholder that is always drawn, then only change it source and let the main loop take care of it.
var audioKnop = new Image();
var audioAanSource = "../Afbeeldingen/Sound_Button.png";
var audioMuteSource = "../Afbeeldingen/Mute_Button.png";
function init() {
audioKnop.src = audioMuteSource;
}
function tekenenObjecten() {
mijnObject.clearRect(0, 0, canvas.width, canvas.height);
makenBalkKort();
makenBal();
makenMuur();
makenBord();
maakAudioButton();
}
function maakAudioButton() {
mijnObject.drawImage(audioKnop, (canvas.width/2)-25, 850, audioKnop.width, audioKnop.height);
}
window.addEventListener("keypress", function () {
var codeGeluid = event.which || event.keyCode;
if(codeGeluid == 48) {
audioKnop.src = audioAanSource;
audio.muted = true;
} else if(codeGeluid == 49) {
audioKnop.src = audioMuteSource;
audio.muted = false;
}
});

ActivePointer location not updating

I'm making a sidescroller using Phaser (latest version) and I want the player's projectiles to go towards the pointer when the player clicks, like they do in this example http://phaser.io/examples/v2/games/tanks. I've used some of the code from the example but in my game, the activePointer x and y co-ordinates seem to only initialise when the game starts and never change. So when the player shoots, it's always going towards the same co-ordinates.
I have the following code (note I have removed bits about item collection, enemies etc. for posting on here):
var SideScroller = SideScroller || {};
var startPosX = 100;
var startPosY = 300;
var shooter;
var playerBullets;
var nextFire = 0;
var fireRate = 100;
var cursors;
var currentLoc;
SideScroller.Game = function () {};
SideScroller.Game.prototype = {
create: function () {
//create player
//params = (game, startPositionX,startPositionY, key, frame)
this.player = this.game.add.sprite(startPosX, startPosY, 'player');
//get canvas width and height for later use
canvasWidth = this.game.canvas.width;
canvasHeight = this.game.canvas.height;
//create enemy
var x = this.game.rnd.between(80, this.game.world.width);
var y = this.game.rnd.between(0, 113);
// Point to shoot projectiles from
// allows rotation, if this had been done on the player object, the graphic would have rotated, which we don't want
this.shooter = this.game.add.sprite(startPosX, startPosY, 'blank');
this.shooter.anchor.setTo(0.5, 0.5);
//make a group of player projectiles
playerBullets = this.game.add.group();
playerBullets.enableBody = true;
playerBullets.physicsBodyType = Phaser.Physics.ARCADE;
playerBullets.createMultiple(1000, 'peePower');
playerBullets.setAll('anchor.x', 0.5);
playerBullets.setAll('anchor.y', 0.5);
playerBullets.setAll('outOfBoundsKill', true);
playerBullets.setAll('checkWorldBounds', true);
//enable physics on the player
this.game.physics.arcade.enable(this.player);
//bring player shooting point to the top (not totally necessary)
this.shooter.bringToTop();
//player gravity
this.player.body.gravity.y = gravity;
//player collides with all four edges of the game world
this.player.body.collideWorldBounds = true;
this.player.anchor.setTo(0.5, 0.5);
//the camera will follow the player in the world
this.game.camera.follow(this.player);
//move player with cursor keys
cursors = this.game.input.keyboard.createCursorKeys();
},
update: function () {
currentLoc = this.game.input.activePointer;
//collision between player and platforms
this.game.physics.arcade.collide(this.player, this.blockedLayer, null, null, this);
//make co-ordinates match
this.shooter.x = this.player.x;
this.shooter.y = this.player.y;
//this.shooter's angle towards
this.shooter.rotation = this.game.physics.arcade.angleToPointer(this.shooter, this.game.input.activePointer);
//only respond to keys if the player is alive
if (this.player.alive) {
this.player.body.velocity.x = 0;
if (this.game.input.activePointer.isDown) {
console.log("pointer is down");
this.fire();
}
else if (cursors.right.isDown) {
this.playerForward();
}
else if (cursors.left.isDown) {
this.playerBack();
}
else if (cursors.up.isDown) {
this.playerJump();
}
else if (cursors.down.isDown) {
this.fire();
this.playerDuck();
}
}
},
fire: function () {
//for debugging
console.log("fire was called");
console.log(this.game.input.activePointer.x);
console.log(this.game.input.activePointer.y);
if (this.game.time.now > nextFire && playerBullets.countDead() > 0)
{
nextFire = this.game.time.now + fireRate;
var bullet = playerBullets.getFirstExists(false);
bullet.reset(this.shooter.x, this.shooter.y);
currentLoc = this.game.input.activePointer;
bullet.rotation = this.game.physics.arcade.moveToPointer(bullet, 1000, currentLoc, 1000);
console.log(this.game.input.activePointer);
}
},
playerForward: function () {
this.player.loadTexture('player');
this.player.body.setSize(this.player.standDimensions.width, this.player.standDimensions.height);
this.player.body.velocity.x = 700;
this.player.isMoving = true;
//console.log("Forward height:" + this.player.standDimensions.height);
//console.log("Forward width:" + this.player.standDimensions.width);
},
playerBack: function () {
this.player.loadTexture('playerBack');
this.player.body.velocity.x -= 700;
this.player.isMoving = true;
},
playerJump: function () {
if (this.player.body.blocked.down) {
this.player.body.velocity.y -= 700;
this.player.loadTexture('playerJump');
//console.log("Jump height:" + this.player.jumpDimensions.height);
//console.log("Jump width:" + this.player.jumpDimensions.width);
}
},
playerDuck: function () {
//change image and update the body size for the physics engine
this.player.loadTexture('playerDuck');
this.player.body.setSize(this.player.duckedDimensions.width, this.player.duckedDimensions.height);
//keep track of whether player is ducked or not
this.player.isDucked = true;
},
playerDead: function () {
//set to dead (this doesn't affect rendering)
this.player.alive = false;
//stop moving to the right
this.player.body.velocity.x = 0;
//change sprite image
this.player.loadTexture('playerDead');
},
};
Shooter is a blank sprite on top of the player (much like the turret in the tank example) to allow for rotation without the player rotating (please let me know also if there's a better way to do that!).
I tried updating the currentLoc variable in the update method to the activePointer location but that didn't work.
In addition, this condition has never been hit:
if (this.game.input.activePointer.isDown) {
console.log("pointer is down");
this.fire();
}
So something must be going awry with detecting mouse clicks and I don't know if that's part of the problem?
I think you should look it up in the API. There are few points in your code that are questionable.
http://phaser.io/docs/2.3.0/Phaser.Pointer.html
http://phaser.io/docs/2.3.0/Phaser.Physics.Arcade.html#moveToPointer
The point is that you are actually giving the reference to the pointer (to currentLoc) but not the position. So it should always fire to 0;0.
And for the isDown detection, have you done it in the update function or somewhere else?
Hope i could help!

html5 canvas code blanking out

I am in desperate need to fix a problem I have in html5 canvas. I am making an educational game, but after adding another photo and making the necessary code changes, but the canvas blanked out. I reverted the changes, but the problem persisted. I spent the past week or so trying to fix it, but I've run out of ideas :( Here is the relevent code (if anyone needs another part, just say so):
// Create the canvas
var canvas = document.createElement("canvas");
var ctx = canvas.getContext("2d");
canvas.width = 1041;
canvas.height = 550;
document.body.appendChild(canvas);
// Background image
var bgReady = false;
var bgImage = new Image();
bgImage.onload = function () {
bgReady = true;
};
bgImage.src = "images/introbackground.png";
//.... rest of the photos load like this so I won't put it...
// Level 1 background 1 image
var bbg1Ready = false;
var bbg1Image = new Image();
bbg1Image.onload = function () {
bbg1Ready = false; //Exception since it shouldn't load at the beginning
};
bbg1Image.src = "images/pollutedbeach1.png";
// Game objects
var hero = {
speed: 200 // movement in pixels per second
};
var level1;
var level2;
var biolevel = false;
//...Code to make the hero picture move with arrow keys and to reset the game are skipped...
if (hero.x <= (level1.x + 345)
&& level1.x <= (hero.x + 32)
&& hero.y <= (level1.y +50)
&& level1.y <= (hero.y + 32)){
biolevel = true;
return biolevel;
}
var render = function () {
if (bgReady) {
ctx.drawImage(bgImage, 0, 0);
}
//...The same for all photos previously loaded...
if (biolevel == true){
level1Ready = false;
level2Ready = false;
bbg1Ready = true;
hero.speed = 125;
}
};
//...Then the main game loop to animate it...
Sorry It's kind of long, but I really need a solution. Thanks!

Categories

Resources