Reputation:
I'm having trouble proportionally scaling the video frame when rendering a video element on canvas.
I read the selected answer to How to proportionally resize an image in canvas? but it did not work for me. I'm rendering an HTML5 video frame rather than an image. This might seem unusual, so here it is explained: video + canvas = magic
My problem with adapting the answer to that related question might have been:
Right now, my player works, fitting the video to it, but it stretches to fit.
context.drawImage(videoPlayer, 0, 0, canvasPlayer.width, canvasPlayer.height);
//canvasPlayer -> HTML5 canvas, videoPlayer -> HTML5 video element
I'd like to know (respectively):
how to fill the height vertically, remaining proportional.
how to fill the width horizontally, remaining proportional.
How can I do this?
Upvotes: 10
Views: 11220
Reputation: 1
Just a little fix in @Tony Hsieh solution
if ( video_width > video_height ){
target_width = c.width;
target_height = c.width / ratio;
y_of_video = (c.height - target_height) / 2 ;
} else{
target_width = c.height * ratio;
target_height = c.height;
x_of_video = (c.width - target_width) / 2 ;
}
Upvotes: 0
Reputation: 136736
Here is a way to get the video drawn proportionally into the canvas (keeping the aspectRatio):
// var c = canvasElement, v=videoElement;
// fill vertically
var vRatio = (c.height / v.videoHeight) * v.videoWidth;
ctx.drawImage(v, 0,0, vRatio, c.height);
// fill horizontally
var hRatio = (c.width / v.videoWidth) * v.videoHeight;
ctx.drawImage(v, 0,0, c.width, hRatio);
function draw(){
// fill vertically
var vratio = (c.height / v.videoHeight) * v.videoWidth;
ctx.drawImage(v, 0,0, vratio, c.height);
// fill horizontally
var hratio = (c.width / v.videoWidth) * v.videoHeight;
ctx1.drawImage(v, 0,0, c1.width, hratio);
requestAnimationFrame(draw);
}
var c=document.createElement('canvas');
c.width = 640;
c.height= 480;
var ctx = c.getContext('2d')
var c1 = c.cloneNode(true);
var ctx1 = c1.getContext('2d')
var v = document.createElement('video');
v.controls=true;
document.body.appendChild(document.createTextNode('fill vertical\n'));
document.body.appendChild(c);
document.body.appendChild(document.createTextNode('fill horizontal\n'));
document.body.appendChild(c1);
document.body.appendChild(document.createTextNode('original'));
document.body.appendChild(v);
var anim;
v.onplaying = function(){
anim = requestAnimationFrame(draw);
};
v.onpause= function(){
cancelAnimationFrame(anim);
};
v.onloadedmetadata = function(){v.play();};
v.src = 'http://media.w3.org/2010/05/sintel/trailer.mp4';
var inputs = document.querySelectorAll('input');
inputs[0].addEventListener('change', inpHandler);
inputs[1].addEventListener('change', inpHandler);
function inpHandler(){
c[this.name]=this.value;
c1[this.name]=this.value;
v.currentTime=0;
v.play();
}
canvas{border:solid 1px;}
canvas,video{ display:block;}
<label for="width">width</label>
<input name="width" type="number" value="640"/>
<label for="height">height</label>
<input name="height" type="number" value="480"/></br>
Upvotes: 5
Reputation: 163
I make a example for you, check it out!
code pen : http://codepen.io/cstony0917/pen/BNvxZP?editors=101
var v = document.getElementById("video1");
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
var i;
var video_width = v.offsetWidth;
var video_height = v.offsetHeight;
var ratio = video_width / video_height;
var target_width;
var target_height;
var y_of_video = 0;
var x_of_video = 0
if ( video_width > video_height ){
target_width = c.width;
target_height = c.width / ratio;
y_of_video = (c.height - target_height) / 2 ;
}else{
target_width = c.height;
target_height = c.height * ratio;
x_of_video = (c.width - target_width) / 2 ;
}
v.addEventListener("play", function() {
i = window.setInterval(function() {
ctx.drawImage(v, x_of_video, y_of_video, target_width, target_height);
},20);
}, false);
v.addEventListener("pause", function() {window.clearInterval(i);}, false);
v.addEventListener("ended", function() {clearInterval(i);}, false);
Upvotes: 1