利用canvas实现视频截图

4,183 阅读3分钟

「这是我参与2022首次更文挑战的第20天,活动详情查看:2022首次更文挑战

前言

最近有需求需要实现对一个视频的截图,大部分第三方的视频插件底层截图的原理也都是基于canvas的,今天就来用canvas的方法实现一个对视频的截图。

实现视频截图

canvas.getContext("2d").drawImage

canvas实现截图方法实现的原理就是使用的canvas的drawImage方法实现,这个方法能传入的语法格式有三种,分别是:

ctx = canvas.getContext("2d")
ctx.drawImage(image, dx, dy);
ctx.drawImage(image, dx, dy, dWidth, dHeight);
ctx.drawImage(image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight);

传入两个参数

其中,dxdy 是必填参数,它们分别代表着 image的左上角在目标canvas上 X 轴坐标和image的左上角在目标canvas上 Y 轴坐标。

简而言之,就是确定图片在canvas中的位置的。

比如

ctx.drawImage(image, 0, 0)

代表从画布原点坐标开始绘制图片,图片不会被裁剪,宽高比保持不变

传入四个参数

传入的参数要是为四个,那么前两个参数为 dxdy,后两个参数就是 dWidthdHeight:

dWidthdHeight 分别代表着为图片开辟的可用宽高。

简单的说就是设置canvas显示图片的大小,比如:

ctx.drawImage(image, 0, 0, image.width, image.height)

这时候传入的可用宽高和图片完全相同,那么图片就不会被压缩,假设传入

ctx.drawImage(image, 0, 0, image.width, image.height / 2)

那么图片的高就会被压缩一倍:

image.png

传入八个参数

如果传入了八个参数,那么新增的四个参数,决定了如何去裁剪得到的图片

其中,前两个 sxsy 决定了图片裁剪开始的坐标,后两个 sWidthsHeight 决定了将会被裁剪区域的大小,比如:

ctx.drawImage(image,0, 0, 1000, 1500, 0, 0, image.width, image.height / 2)

那么得到的图片就会从 (0,0) 开始裁剪 1000宽 和 1500高 的大小。

image.png

实现截取视频

drawImage 的参数的第一位,不只是可以出传入image,他可以传入任何的 canvas 图像源,所以我们也可以传入一个video,这样就可以用上述的方法,去获取video此刻的某个位置的截图。

canvas.toDataURL 获取图片的地址

方法返回一个包含图片展示的 data URI 。可以使用 type 参数改变其类型,默认为 PNG 格式。

比如说:

console.log(canvas_.toDataURL("image/jpg"));
img.src = canvas_.toDataURL("image/jpg");

这样我们就能够获得当前截图的 data URI,将其赋给一张img图片,这样我们就能够实现截图功能并且获得截图的 data URI,下面其中一个图是 canvas 的 drawImage 画出来的,是一个 canvas 元素

image.png

另一个则是我们赋值出来的img图片,是一个img元素。

image.png

结尾放上详细代码

<!DOCTYPE html>

<html lang="en">
  <head>
    <meta charset="UTF-8" />

    <title>上传视频,进行预览,截取图片,并且获取时长</title>
  </head>
  <style>
    body {
      display: flex;
    }
  </style>
  <body>
    <div>
      <input type="file" onchange="changFile(this)" />
      <div id="showVideo"></div>
    </div>
    <div>
      <img id="image"  style=" margin: 23px 10px 0 10px;"/>
    </div>
    <div>
      <button onclick="manualCapture()">点击截图</button><br />
      <canvas id="canvas_"></canvas>
    </div>

    <script>
      function changFile(ele) {
        var videoFile = ele.files[0];
        var url = URL.createObjectURL(videoFile);
        console.log(url);
        var showVideo = document.getElementById("showVideo");
        var htmls =
          ' <video width="400px" id="video" height="auto" autoplay="autoplay" controls > <source src="' +
          url +
          '">您的浏览器不支持 HTML5 video 元素。</video>';
        showVideo.innerHTML = htmls;
      }
      function manualCapture() {
        var video_ = document.getElementById("video");
        var canvas_ = document.getElementById("canvas_");
        var ctx_ = canvas_.getContext("2d");
        const ratio = window.devicePixelRatio || 1;
        ctx_.scale(ratio, ratio);
        canvas_.width = video_.offsetWidth * ratio;
        canvas_.height = video_.offsetHeight * ratio;
        console.log(video_.clientHeight, video_.clientWidth);
        ctx_.drawImage(video_, 0, 0, canvas_.width, canvas_.height);
        var img = document.getElementById("image");
        console.log(canvas_.toDataURL("image/jpg"));
        img.src = canvas_.toDataURL("image/jpg");
      }
    </script>
  </body>
</html>

总结

本文只是非常简单的使用canvas截取了视频的图片,结合之前讲过的编辑器的自定义编辑,我们是否就能够实现一个一边记笔记一边看视频,并且自定义一个截图按钮呢?

具体的自定义编辑器功能可以看我之前的两片文章,介绍了相关的如何自定义一个编辑器按钮并且扩展它。结合今天的截图功能,就能够实现一个视频截图的功能块了。

带你定义自己的 editor.js 工具 - 掘金 (juejin.cn)
带你定义自己的 editor.js 工具 - 扩展自定义 - 掘金 (juejin.cn)