user2076675
user2076675

Reputation:

How do I proportionally resize a video in canvas?

I'm having trouble proportionally scaling the video frame when rendering a video element on canvas.

What I've tried:

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:

What I have so far

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 can I do this?

Upvotes: 10

Views: 11220

Answers (3)

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

Kaiido
Kaiido

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

Tony Hsieh
Tony Hsieh

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

Related Questions