如何在画布中等比例调整视频大小?

10

当我在canvas上呈现视频元素时,我无法按比例缩放视频帧。

我尝试过的:

我阅读了如何在canvas中按比例调整图像大小? 的选定答案,但它对我没有起作用。我正在呈现HTML5视频帧,而不是图像。这可能看起来很不寻常,因此这里解释一下:video + canvas = magic

我试图适应相关问题的答案时遇到的问题可能是:

  • 也许视频大小与图像不同。
  • 也许我错误地将针对特定情况使用的答案转换为我的答案,因为它在多个位置使用混淆的静态测量值(“300”),而没有真正解释它们。

到目前为止我所拥有的:

目前,我的播放器可以适应视频并使其填充,但会拉伸以适应。

context.drawImage(videoPlayer, 0, 0, canvasPlayer.width, canvasPlayer.height); 
//canvasPlayer -> HTML5 canvas, videoPlayer -> HTML5 video element

我想知道(分别):

  • 如何在垂直方向上填充高度,同时保持比例。

  • 如何在水平方向上填充宽度,同时保持比例。

我该怎么做?


我对于 canvas 没有太多的经验,但是我知道在处理流体视频元素时,CSS 无法保持宽高比时我需要使用一种实质性的 hack 方法,即利用 padding 进行填充。这篇文章 是我在很多情况下所参考的。 - aug
3个回答

5
这里有一种方法可以让视频在canvas中按比例绘制(保持宽高比):
// 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>


1
你可以使用三元运算符来计算vRatiohRatio,但是条件后的两个表达式都是相同的。 - Iván Pérez

1
我为您制作了一个示例,请查看! 代码笔: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); 

我认为这不太正确 - 你按比例改变了画布的大小,但没有改变已经给定的画在画布上的图像的大小。 - stdob--
好的,我对这个例子做了一些修改,可能更正确。 - Tony Hsieh

0

@Tony Hsieh的解决方案中只需要稍微修复一下即可

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 ;
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接