I developed a project that when registering, you have to take a picture. Customers asked for the camera or video tag to be at 100% screen height. However, above this camera/video goes a filter, so the video tag receives the width of this image/filter and the height of the screen every time. The video tag has an object-fit:cover to get 100%. The challenge now is to adjust this on the canvas, to make the image appear with the same size. The problem is the width because the width is the same as the filter, there is no way to actually know the width of the video.
Video component
<template>
<div class="takePhoto__camera">
<video ref="video" fullscreen="false" playsinline muted></video>
<img class="takePhoto__camera__filter" src="../../assets/images/filtro.png" ref="filter" alt="Filtro">
<button class="takePhoto__camera__btn" @click.prevent="photoTaken"></button>
</div>
</template>
<script>
import { mapMutations } from "vuex"
export default {
name: "ComponentCameraVideo",
data(){
return{
video: null,
localStream: null,
}
},
mounted(){
this.video = this.$refs.video;
this.init();
},
methods: {
...mapMutations(["SET_CAMERA"]),
init(){
const filter = document.querySelector(".takePhoto__camera__filter");
// Seta a classe ao body
document.body.classList.add("takingPicture");
filter.onload = () => {
// Pedir permissão para acessar a câmera
if('mediaDevices' in navigator && 'getUserMedia' in navigator.mediaDevices){
navigator.mediaDevices.getUserMedia({video: true}).then((stream) => {
this.video.srcObject = stream;
this.localStream = stream;
this.video.play();
this.setWidthVideo();
}).catch((error) => {
console.log(error)
alert(error);
})
}
else{
alert("Não foi possível acessar a câmera!");
}
}
},
photoTaken(){
// Remover a classe do body
document.body.classList.remove("takingPicture");
// Setar a câmera na variável vuex
this.SET_CAMERA(
{
"video" : {
element: this.video,
width: this.video.offsetWidth,
height: this.video.offsetHeight
},
"filter" : {
element: this.$refs.filter,
width: this.$refs.filter.offsetWidth,
height: this.$refs.filter.offsetHeight
},
"stream" : this.localStream,
}
);
// Emitir o evento
this.$emit("photoTaken");
// Parar a execução da câmera
// this.localStream.getTracks()[0].stop();
},
setWidthVideo(){
setTimeout(() => {
// Setar largura para o vídeo de acordo com o filtro
const video = document.querySelector(".takePhoto__camera video");
const filter = document.querySelector(".takePhoto__camera__filter");
video.style.width = filter.offsetWidth + "px";
video.style.height = innerHeight + "px";
}, 500)
}
},
}
</script>
Canvas component
<template>
<div class="takePhoto__showPhoto">
<canvas ref="canvas"></canvas>
<img :src="src" alt="Sua foto">
</div>
</template>
<script>
import { mapState, mapMutations } from "vuex"
export default {
name: "ComponentCameraCanvas",
data() {
return {
canvas: null,
src: "/",
};
},
computed: {
...mapState(["camera"])
},
mounted() {
this.canvas = this.$refs.canvas;
this.getPhoto()
},
methods: {
...mapMutations(["SET_PHOTO"]),
getPhoto(){
const ratio = (window.innerHeight < window.innerWidth) ? 16 / 9 : 9 / 16;
const ctx = this.canvas.getContext("2d");
// Setar tamanho para o Canvas
this.canvas.width = this.camera.filter.width;
this.canvas.height = this.camera.filter.height;
// Configs do canvas
ctx.imageSmoothingEnabled = true;
ctx.imageSmoothingQuality = "high";
// Filtro
let filter = new Image();
filter.src = this.camera.filter.element.src
// Inserindo as imagens no canvas
ctx.drawImage(this.camera.video.element, 0, 0);
ctx.drawImage(filter, 0, 0, this.camera.filter.width, this.camera.filter.height);
// Parar a execução da câmera
this.camera.stream.getTracks()[0].stop()
// Salvar na variável photo - vuex
this.SET_PHOTO(this.canvas.toDataURL("image/jpeg"));
// Motrar na tag image
this.src = this.canvas.toDataURL("image/jpeg");
},
},
}
</script>
<style lang="scss" scoped>
#picture {
display: block;
width: 100%;
height: 100vh;
box-sizing: border-box;
canvas {
display: block;
width: 100%;
height: 100%;
}
}
</style>
I'm using vue to store the values