使用工具

视频播放器API:西瓜播放器

截图:canvas


实现步骤

1. 创建 canvas 元素,创建 canvas 上下文对象

const canvas = document.createElement('canvas');
const canvasCtx = canvas.getContext('2d');

2. 获取 video 元素 DOM节点,在 React 中也可以使用 useRef 获取

const video = document.getElementById('mse')?.firstElementChild;

3. 设置 canvas 画布宽高(此处设置为画布宽高与视频宽高相同)

canvas.width = video.videoWidth;
canvas.height = video.videoHeight;

4. 使用 drawImage() 方法将视频画面画在 canvasCtx 上

drawImage() 参数介绍

drawImage(image, dx, dy)

drawImage(image, dx, dy, dw, dh)

drawImage(image, sx, sy, sw, sh, dx, dy, dw, dh)

  • image:必选,要截取的 image 或者 video 元素
  • sx:可选,被截取图片的裁剪开始位置的 x 坐标
  • sy:可选,被截取图片的裁剪开始位置的 y 坐标
  • sw:可选,被截取图片的裁剪宽度
  • sh:可选,被截取图片的裁剪高度
  • dx:必选,裁剪图片放在画布上位置的 x 坐标
  • dy:必选,裁剪图片放在画布上位置的 y 坐标
  • dw:可选,裁剪图片放在画布上的宽度(放大或缩小)
  • dh:可选,裁剪图片放在画布上的高度(放大或缩小)
canvasCtx.drawImage(video,0,0,video.videoWidth,video.videoHeight,0,0,video.videoWidth,video.videoHeight,
);

5. 使用 toDataURL() 将 canvas 转为图片(base64)

const MIME_TYPE = 'image/png'; // 保存文件类型
const imgURL = canvas.toDataURL(MIME_TYPE);

6. 最后使用 a 标签将图片下载到本地

const dlLink = document.createElement('a');
dlLink.download = '截图'; // 文件名
dlLink.href = imgURL;
dlLink.dataset.downloadurl = [MIME_TYPE, dlLink.download, dlLink.href].join(':');
document.body.appendChild(dlLink);
dlLink.click();
document.body.removeChild(dlLink);

至此,即可实现基本的视频截图保存到本地的功能了。如下

截图为:


改进点

大部分时候,我们的播放器会固定宽高,视频需要根据播放器大小做自适应,所以在 video 视图中有一部分留白,如果我们想把这一部分留白也截到截图中,使得到的图片宽高就是 video 视图宽高,这里提供一个手动补全背景的方案。

1. 设置 canvas 画布宽高(设置为 video 视图宽高)

canvas.width = video.offsetWidth;
canvas.height = video.offsetHeight;

2. 手动在 canvasCtx 上填充播放器的背景色

canvasCtx.fillStyle = '#222125'; // 西瓜播放器背景色
canvasCtx.fillRect(0, 0, canvas.width, canvas.height);

3. 计算视频画面等比缩放后在画布中的大小

const imgWidth = Math.min(canvas.width, video.videoWidth * canvas.height / video.videoHeight);
const imgHeight = Math.min(canvas.height, video.videoHeight * canvas.width / video.videoWidth);

4. 使用 drawImage() 方法将视频画面画在 canvasCtx 上

canvasCtx.drawImage(video,0,0,video.videoWidth,video.videoHeight,(canvas.width - imgWidth) / 2,(canvas.height - imgHeight) / 2,imgWidth,imgHeight,
);

其余步骤按照之前的完成,改进后截图效果如下:


踩坑点

1. 如果遇到画布被污染,即

Uncaught DOMException: Failed to execute 'toDataURL' on 'HTMLCanvasElement': Tainted canvases may not be exported.

的报错信息,原因是你使用的视频资源是跨域请求。

这时我们需要在 video 标签中添加一个属性 crossorigin="anonymous"。这时,可成功截图。

注意:在给 video 标签动态添加 crossorigin 属性时,必须要在赋值 video.src 之前赋值 video.crossorigin,否则该属性不会生效。

2. (非常规问题,不感兴趣可以不看)笔者在做截图时遇到了另一个跨域的问题,应该算是西瓜播放器的问题吧,也在这里记录一下。如果请求的视频资源被重定向的话,video 的 src 属性为重定向前的地址,但实际资源是重定向后的地址,这样的情况会被 Safari 浏览器判定为跨域请求,所以会报画布污染的错误,笔者在这里的解决方法是:手动 fetch 一下,拿到视频重定向后的 url 再赋值给 video,这样即可绕过重定向。


完整代码

const canvas = document.createElement('canvas');
const canvasCtx = canvas.getContext('2d');
const video = document.getElementById('mse')?.firstElementChild;
canvas.width = video.offsetWidth;
canvas.height = video.offsetHeight;
canvasCtx.fillStyle = '#222125';
canvasCtx.fillRect(0, 0, canvas.width, canvas.height);
const imgWidth = Math.min(canvas.width, video.videoWidth * canvas.height / video.videoHeight);
const imgHeight = Math.min(canvas.height, video.videoHeight * canvas.width / video.videoWidth);
canvasCtx.drawImage(video,0,0,video.videoWidth,video.videoHeight,(canvas.width - imgWidth) / 2,(canvas.height - imgHeight) / 2,imgWidth,imgHeight,
);
const MIME_TYPE = 'image/png'; // 保存文件类型
const imgURL = canvas.toDataURL(MIME_TYPE);
const dlLink = document.createElement('a');
dlLink.download = '截图'; // 文件名
dlLink.href = imgURL;
dlLink.dataset.downloadurl = [MIME_TYPE, dlLink.download, dlLink.href].join(':');
document.body.appendChild(dlLink);
dlLink.click();
document.body.removeChild(dlLink);

js使用canvas实现视频截图相关推荐

  1. js截屏 video_用原生JS和html5进行视频截图并保存到本地

    Video视频截图 body, h1, h2, p { margin:0; padding:0; } html { font-family:"微软雅黑"; background-c ...

  2. 用canvas做视频截图遇到的坑(已填坑)

    最近负责了一个后台功能的扩展,因为没有前端,所以客串了一把前端,需求的内容是做一个视频截图的功能,这期间遇到了canvas 的跨域问题, Uncaught DOMException: Failed t ...

  3. 【Javascript】【视频录制】通过video标签和canvas实现视频截图录制和下载

    录像原理 创建一个画布,video标签本身不具备记录画面功能,所以我们需要通过Canvas来达成这个功能 创建一个录制器,与CanvasStream绑定,这样画布绘制什么,录制器都能触发回调 创建一个 ...

  4. 基于Vue+canvas实现视频截图功能

    开发过程中遇到一个实际问题,上传的视频需要提供视频封面(视频封面必填).封面可以自己制作并上传,但是这样需要脱离网站,用其他方式制作封面,使用体验并不友好,因此第一个想到的方案是:上传视频时,若人员未 ...

  5. js截屏 video_video结合canvas实现视频在线截图功能

    给大家讲解下我前几天看到的一个有趣小demo:视频在线截图.以下是我修改和添加了新功能后的效果图: 是不是很酷,其实挺简单的,下面就给大家讲讲怎么弄哈. 这里主要分为三大块功能,首先是第一个: 利用U ...

  6. web实战:video结合canvas实现视频在线截图

    给大家讲解下我前几天看到的一个有趣小demo:视频在线截图.以下是我修改和添加了新功能后的效果图: 是不是很酷,其实挺简单的,下面就给大家讲讲怎么弄哈. 这里主要分为三大块功能,首先是第一个: 利用U ...

  7. js截屏 video_canvas与html5实现视频截图功能

    这段时间一直在研究canvas,突发奇想想做一个可以截屏视频的功能,然后把图片拉去做表情包,哈哈哈哈哈哈~~ 制作方法: 1.在页面中加载视频 在使用canvas制作这个截图功能时,首先必须保证页面上 ...

  8. video.js 视频截图、录制、自定义全屏,hls、flv、mp4视频播放

    功能 video.js内嵌 截图.录制功能 (图片.视频会下载到本地) 自定义全屏 播放hls.flv.mp4 功能集合成Vue组件 参考 video.js components RecordRTC ...

  9. html中图片切割视频,canvas与html5实现视频截图功能示例

    这段时间一直在研究canvas,突发奇想想做一个可以截屏视频的功能,然后把图片拉去做表情包,哈哈哈哈哈哈~~ 制作方法: 1.在页面中加载视频 在使用canvas制作这个截图功能时,首先必须保证页面上 ...

最新文章

  1. Redis高可用集群Redis Cluster搭建
  2. mysql添加自团_Mysql入门基础 数据库创建篇
  3. ajax中 get 和 post 的区别
  4. 深入理解分布式技术 - 缓存过期策略手写LRU
  5. springmvc 中@Controller和@RestController的区别
  6. mysql查询 百万_MySQL百万级数据分页查询优化
  7. Pro Android学习笔记(三三):Menu(4):Alternative菜单
  8. ~~朴素筛法求素数(附模板题)
  9. centos7 安装docker-ce ,最新版本docker,docker阿里云加速
  10. Unity3D 一些工具总结
  11. 15款免费的Wi-Fi安全测试工具
  12. 冰点还原精灵如何安装
  13. PivotGridControl与ChartControl控件结合使用(一)
  14. jQuery事件与事件对象
  15. html点击登陆、注册等时候出现等待图标代码
  16. 提升自己的最好方式是什么呢?
  17. xmos-XU208-128-QF48芯片简介
  18. oracle幂函数运算公式,幂函数公式_幂的运算法则公式14个
  19. 写推文满一年,分享 5 个小编常用的写作软件
  20. Spring中的静态工厂与实例工厂

热门文章

  1. 计算机硬盘容量分盘计算,硬盘分区容量精确计算公式 -电脑资料
  2. ros2 Navigation 学习笔记 第三章(the construct 网站)
  3. QT5中SQlite的常见问题(QSqlError(“8“, “Unable to fetch row“, “attempt to write a readonly database“)
  4. 【软件工程】第五章 结构化设计
  5. java并发编程(十五)——常见的几种阻塞队列
  6. c语言printf啥意思,printf在c语言中的意思是什么呢
  7. 磁盘虚拟化系列(一):qcow2文件、raw文件、qcow2镜像、vmdk文件
  8. 【Java 8】默认方法
  9. el-select下拉加载(实现懒加载)自定义loadmore事件
  10. GSMA公布“与CTIA合作的2019 MWC洛杉矶”的首批细节