js使用canvas实现视频截图
使用工具
视频播放器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实现视频截图相关推荐
- js截屏 video_用原生JS和html5进行视频截图并保存到本地
Video视频截图 body, h1, h2, p { margin:0; padding:0; } html { font-family:"微软雅黑"; background-c ...
- 用canvas做视频截图遇到的坑(已填坑)
最近负责了一个后台功能的扩展,因为没有前端,所以客串了一把前端,需求的内容是做一个视频截图的功能,这期间遇到了canvas 的跨域问题, Uncaught DOMException: Failed t ...
- 【Javascript】【视频录制】通过video标签和canvas实现视频截图录制和下载
录像原理 创建一个画布,video标签本身不具备记录画面功能,所以我们需要通过Canvas来达成这个功能 创建一个录制器,与CanvasStream绑定,这样画布绘制什么,录制器都能触发回调 创建一个 ...
- 基于Vue+canvas实现视频截图功能
开发过程中遇到一个实际问题,上传的视频需要提供视频封面(视频封面必填).封面可以自己制作并上传,但是这样需要脱离网站,用其他方式制作封面,使用体验并不友好,因此第一个想到的方案是:上传视频时,若人员未 ...
- js截屏 video_video结合canvas实现视频在线截图功能
给大家讲解下我前几天看到的一个有趣小demo:视频在线截图.以下是我修改和添加了新功能后的效果图: 是不是很酷,其实挺简单的,下面就给大家讲讲怎么弄哈. 这里主要分为三大块功能,首先是第一个: 利用U ...
- web实战:video结合canvas实现视频在线截图
给大家讲解下我前几天看到的一个有趣小demo:视频在线截图.以下是我修改和添加了新功能后的效果图: 是不是很酷,其实挺简单的,下面就给大家讲讲怎么弄哈. 这里主要分为三大块功能,首先是第一个: 利用U ...
- js截屏 video_canvas与html5实现视频截图功能
这段时间一直在研究canvas,突发奇想想做一个可以截屏视频的功能,然后把图片拉去做表情包,哈哈哈哈哈哈~~ 制作方法: 1.在页面中加载视频 在使用canvas制作这个截图功能时,首先必须保证页面上 ...
- video.js 视频截图、录制、自定义全屏,hls、flv、mp4视频播放
功能 video.js内嵌 截图.录制功能 (图片.视频会下载到本地) 自定义全屏 播放hls.flv.mp4 功能集合成Vue组件 参考 video.js components RecordRTC ...
- html中图片切割视频,canvas与html5实现视频截图功能示例
这段时间一直在研究canvas,突发奇想想做一个可以截屏视频的功能,然后把图片拉去做表情包,哈哈哈哈哈哈~~ 制作方法: 1.在页面中加载视频 在使用canvas制作这个截图功能时,首先必须保证页面上 ...
最新文章
- Redis高可用集群Redis Cluster搭建
- mysql添加自团_Mysql入门基础 数据库创建篇
- ajax中 get 和 post 的区别
- 深入理解分布式技术 - 缓存过期策略手写LRU
- springmvc 中@Controller和@RestController的区别
- mysql查询 百万_MySQL百万级数据分页查询优化
- Pro Android学习笔记(三三):Menu(4):Alternative菜单
- ~~朴素筛法求素数(附模板题)
- centos7 安装docker-ce ,最新版本docker,docker阿里云加速
- Unity3D 一些工具总结
- 15款免费的Wi-Fi安全测试工具
- 冰点还原精灵如何安装
- PivotGridControl与ChartControl控件结合使用(一)
- jQuery事件与事件对象
- html点击登陆、注册等时候出现等待图标代码
- 提升自己的最好方式是什么呢?
- xmos-XU208-128-QF48芯片简介
- oracle幂函数运算公式,幂函数公式_幂的运算法则公式14个
- 写推文满一年,分享 5 个小编常用的写作软件
- Spring中的静态工厂与实例工厂
热门文章
- 计算机硬盘容量分盘计算,硬盘分区容量精确计算公式 -电脑资料
- ros2 Navigation 学习笔记 第三章(the construct 网站)
- QT5中SQlite的常见问题(QSqlError(“8“, “Unable to fetch row“, “attempt to write a readonly database“)
- 【软件工程】第五章 结构化设计
- java并发编程(十五)——常见的几种阻塞队列
- c语言printf啥意思,printf在c语言中的意思是什么呢
- 磁盘虚拟化系列(一):qcow2文件、raw文件、qcow2镜像、vmdk文件
- 【Java 8】默认方法
- el-select下拉加载(实现懒加载)自定义loadmore事件
- GSMA公布“与CTIA合作的2019 MWC洛杉矶”的首批细节