翼度科技»论坛 编程开发 JavaScript 查看内容

原生JS实现视频截图

7

主题

7

帖子

21

积分

新手上路

Rank: 1

积分
21
视频截图效果预览


利用Canvas进行截图

要用原生js实现视频截图,可以利用canvas的绘图功能 ctx.drawImage,只需要获取到视频标签,就可以通过drawImage把视频当前帧图像绘制在canvas画布上。
  1. const video = document.querySelector('video')
  2. const canvas = document.createElement('canvas')
  3. const w = video.videoWidth
  4. const h = video.videoHeight
  5. canvas.width = w
  6. canvas.height = h
  7. const ctx = canvas.getContext('2d')
  8. ctx.drawImage(video, 0, 0, w, h)
复制代码
接下来,需要把画布转化为图片,canvas提供了两个2D转换为图片的方法:canvas.toDataURL()和canvas.toBlob()
canvas.toDataURL(mimeType, qualityArgument)方法

toDataURL可以把图片转换成base64格式的图片,是一个同步方法,使用很简单,在上面已经绘制好画布的基础上,只需要下面一行代码就可以获取到当前视频帧的截图了
  1. const imageUrl = canvas.toDataURL("image/png")
  2. console.log(imageUrl)
复制代码

可以看到,它最终生成了一个很长字符串的base64图片地址。
canvas.toBlob(callback, mimeType, qualityArgument)方法

这个方法相比上一个方法的优点是它是异步的,所以有一个callback回调,这个callback回调方法默认的第一个参数就是转换好的blob文件信息,本文也想重点介绍这种方法的使用
先说明一下这个方法的三个参数:
参数类型是否必传说明callbackFunction是toBlob()方法执行成功后的回调方法,支持一个参数,表示当前转换的Blob对象mimeTypeString否表示需要转换的图像的mimeType类型。默认值是image/png,还可以是image/jpeg,甚至image/webp(前提浏览器支持)等qualityArgumentNumber否表示转换的图片质量。范围是0到1。由于Canvas的toBlob()方法转PNG是无损的,因此,此参数默认是没有效的,除非,指定图片mimeType是image/jpeg或者image/webp,此时默认压缩值是0.92使用写法如下:
  1. canvas.toBlob((blob) => {
  2.   console.log(blob)
  3. }, 'image/png', 0.92)
复制代码
可以看到方法执行得到的是当前转换的Blob对象

那么剩下的就是要将此Blob对象进一步转化为可供img显示的图片地址。
将Blob对象转化为图片地址

下面介绍三种方法进行转化:
方式一: 通过URL.createObjectURL()方法将Blob转化为URL
  1. canvas.toBlob((blob) => {
  2.   const imageUrl = URL.createObjectURL(blob)
  3.   console.log(1, imageUrl)
  4. }, 'image/jpeg', 1)
复制代码
如下图所示,转化得到的是一个bold流的图片地址。

方式二: 通过FileReader将Blob转化为DataURL
  1. canvas.toBlob((blob) => {
  2.   const reader = new FileReader()
  3.   reader.readAsDataURL(blob)
  4.   reader.onload = () => {
  5.     const imageUrl = reader.result
  6.     console.log(2, imageUrl)
  7.   }
  8. }, 'image/webp', 1)
复制代码
如下图所示,转化得到的是一个base64的图片地址。

方式三: 通过ajax将Blob上传到服务器
  1. canvas.toBlob((blob) => {
  2.     const formData = new FormData()
  3.     formData.append('file', blob) // 这里的'file'是接口接收参数的字段名,需要根据实际情况改变
  4.     const xhr = new XMLHttpRequest()
  5.     xhr.onload = () => {
  6. <video className="videoTag" crossOrigin='anonymous' controls>
  7.      <source src="https://www.w3school.com.cn/example/html5/mov_bbb.mp4" type='video/mp4' />
  8. </video> const imageUrl = JSON.parse(xhr.responseText).data // 接口回调参数,需要根据实际情况处理
  9. <video className="videoTag" crossOrigin='anonymous' controls>
  10.      <source src="https://www.w3school.com.cn/example/html5/mov_bbb.mp4" type='video/mp4' />
  11. </video> console.log(3, imageUrl)
  12.     }
  13.     xhr.open('POST', '/api/upload', true) // '/api/upload'是上传接口,需要根据实际情况改变
  14.     xhr.send(formData)
  15. }, 'image/webp', 1)
复制代码
由此就会将图片上传到你的文件服务器里,最终可以得到一个你自己文件服务器下对应的图片地址。
toBlob()方法的兼容

首先,toBlob()方法IE9浏览器不支持,因为Blob数据格式IE10+才支持。
然后,对于IE浏览器,toBlob()的兼容性有些奇怪,IE10浏览器支持ms私有前缀的toBlob()方法,完整方法名称是msToBlob()。而IE11+,toBlob()方法却不支持。
但是,我们可以基于toDataURL()方法进行polyfill,性能相对会差一些,JavaScript代码如下:
  1. if (!HTMLCanvasElement.prototype.toBlob) {
  2.   Object.defineProperty(HTMLCanvasElement.prototype, 'toBlob', {
  3.     value: function (callback, type, quality) {
  4. <video className="videoTag" crossOrigin='anonymous' controls>
  5.      <source src="https://www.w3school.com.cn/example/html5/mov_bbb.mp4" type='video/mp4' />
  6. </video> var canvas = this
  7. <video className="videoTag" crossOrigin='anonymous' controls>
  8.      <source src="https://www.w3school.com.cn/example/html5/mov_bbb.mp4" type='video/mp4' />
  9. </video> setTimeout(function() {
  10. <video className="videoTag" crossOrigin='anonymous' controls>
  11.      <source src="https://www.w3school.com.cn/example/html5/mov_bbb.mp4" type='video/mp4' />
  12. </video>   var binStr = atob( canvas.toDataURL(type, quality).split(',')[1] )
  13. <video className="videoTag" crossOrigin='anonymous' controls>
  14.      <source src="https://www.w3school.com.cn/example/html5/mov_bbb.mp4" type='video/mp4' />
  15. </video>   var len = binStr.length
  16. <video className="videoTag" crossOrigin='anonymous' controls>
  17.      <source src="https://www.w3school.com.cn/example/html5/mov_bbb.mp4" type='video/mp4' />
  18. </video>   var arr = new Uint8Array(len)
  19. <video className="videoTag" crossOrigin='anonymous' controls>
  20.      <source src="https://www.w3school.com.cn/example/html5/mov_bbb.mp4" type='video/mp4' />
  21. </video>   for (var i = 0; i < len; i++) {
  22. <video className="videoTag" crossOrigin='anonymous' controls>
  23.      <source src="https://www.w3school.com.cn/example/html5/mov_bbb.mp4" type='video/mp4' />
  24. </video><video className="videoTag" crossOrigin='anonymous' controls>
  25.      <source src="https://www.w3school.com.cn/example/html5/mov_bbb.mp4" type='video/mp4' />
  26. </video>arr[i] = binStr.charCodeAt(i)
  27. <video className="videoTag" crossOrigin='anonymous' controls>
  28.      <source src="https://www.w3school.com.cn/example/html5/mov_bbb.mp4" type='video/mp4' />
  29. </video>   }
  30. <video className="videoTag" crossOrigin='anonymous' controls>
  31.      <source src="https://www.w3school.com.cn/example/html5/mov_bbb.mp4" type='video/mp4' />
  32. </video>   callback(new Blob([arr], { type: type || 'image/png' }))
  33. <video className="videoTag" crossOrigin='anonymous' controls>
  34.      <source src="https://www.w3school.com.cn/example/html5/mov_bbb.mp4" type='video/mp4' />
  35. </video> })
  36.     }
  37.   })
  38. }
复制代码
注意事项

使用外部链接播放视频的话需要在视频标签上设置允许跨域的处理,添加属性crossOrigin='anonymous'即可,
  1. <video className="videoTag" crossOrigin='anonymous' controls>
  2.      <source src="https://www.w3school.com.cn/example/html5/mov_bbb.mp4" type='video/mp4' />
  3. </video>
复制代码
或者,在js里处理
  1. const video = document.querySelector(".videoTag")
  2. video.setAttribute('crossOrigin', 'anonymous')
  3. video.load()
复制代码
否则会报以下错误:

完整封装示例

最后,给出一个利用toBlob进行视频截图,最终获取base64图片地址的封装方法,代码示例如下:
  1. function getBase64ByVideo(video) {    const canvas = document.createElement("canvas")    const w = video.videoWidth    const h = video.videoHeight    canvas.width = w    canvas.height = h    return new Promise((resolve, reject) => { // 由于toBlob方法是异步的,所以这里用Promise<video className="videoTag" crossOrigin='anonymous' controls>
  2.      <source src="https://www.w3school.com.cn/example/html5/mov_bbb.mp4" type='video/mp4' />
  3. </video> const ctx = canvas.getContext('2d')<video className="videoTag" crossOrigin='anonymous' controls>
  4.      <source src="https://www.w3school.com.cn/example/html5/mov_bbb.mp4" type='video/mp4' />
  5. </video> ctx.drawImage(video, 0, 0, w, h)<video className="videoTag" crossOrigin='anonymous' controls>
  6.      <source src="https://www.w3school.com.cn/example/html5/mov_bbb.mp4" type='video/mp4' />
  7. </video> canvas.toBlob((blob) => {<video className="videoTag" crossOrigin='anonymous' controls>
  8.      <source src="https://www.w3school.com.cn/example/html5/mov_bbb.mp4" type='video/mp4' />
  9. </video>   // 通过FileReader将Blob转化为DataURL<video className="videoTag" crossOrigin='anonymous' controls>
  10.      <source src="https://www.w3school.com.cn/example/html5/mov_bbb.mp4" type='video/mp4' />
  11. </video>   const reader = new FileReader()<video className="videoTag" crossOrigin='anonymous' controls>
  12.      <source src="https://www.w3school.com.cn/example/html5/mov_bbb.mp4" type='video/mp4' />
  13. </video>   reader.readAsDataURL(blob)<video className="videoTag" crossOrigin='anonymous' controls>
  14.      <source src="https://www.w3school.com.cn/example/html5/mov_bbb.mp4" type='video/mp4' />
  15. </video>   reader.onload = () => {<video className="videoTag" crossOrigin='anonymous' controls>
  16.      <source src="https://www.w3school.com.cn/example/html5/mov_bbb.mp4" type='video/mp4' />
  17. </video><video className="videoTag" crossOrigin='anonymous' controls>
  18.      <source src="https://www.w3school.com.cn/example/html5/mov_bbb.mp4" type='video/mp4' />
  19. </video>const imageUrl = reader.result<video className="videoTag" crossOrigin='anonymous' controls>
  20.      <source src="https://www.w3school.com.cn/example/html5/mov_bbb.mp4" type='video/mp4' />
  21. </video><video className="videoTag" crossOrigin='anonymous' controls>
  22.      <source src="https://www.w3school.com.cn/example/html5/mov_bbb.mp4" type='video/mp4' />
  23. </video>resolve(imageUrl)<video className="videoTag" crossOrigin='anonymous' controls>
  24.      <source src="https://www.w3school.com.cn/example/html5/mov_bbb.mp4" type='video/mp4' />
  25. </video>   }<video className="videoTag" crossOrigin='anonymous' controls>
  26.      <source src="https://www.w3school.com.cn/example/html5/mov_bbb.mp4" type='video/mp4' />
  27. </video> }, 'image/webp', 1) // 根据需要可以自行配置这里的两个参数    })}
复制代码
调用方法:
  1. const videoTag = document.querySelector(".videoTag")
  2. const dataUrl = await getBase64ByVideo(videoTag)
复制代码
来源:https://www.cnblogs.com/Marco-hui/p/17831577.html
免责声明:由于采集信息均来自互联网,如果侵犯了您的权益,请联系我们【E-Mail:cb@itdo.tech】 我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x

举报 回复 使用道具