原生JS实现视频截图

视频截图效果预览

利用Canvas进行截图

要用原生js实现视频截图,可以利用canvas的绘图功能 ctx.drawImage,只需要获取到视频标签,就可以通过drawImage把视频当前帧图像绘制在canvas画布上。

javascript 复制代码
const video = document.querySelector('video')
const canvas = document.createElement('canvas')
const w = video.videoWidth
const h = video.videoHeight
canvas.width = w
canvas.height = h
const ctx = canvas.getContext('2d')
ctx.drawImage(video, 0, 0, w, h)

接下来,需要把画布转化为图片,canvas提供了两个2D转换为图片的方法:canvas.toDataURL()canvas.toBlob()

canvas.toDataURL(mimeType, qualityArgument)方法

toDataURL可以把图片转换成base64格式的图片,是一个同步方法,使用很简单,在上面已经绘制好画布的基础上,只需要下面一行代码就可以获取到当前视频帧的截图了

javascript 复制代码
const imageUrl = canvas.toDataURL("image/png")
console.log(imageUrl)

可以看到,它最终生成了一个很长字符串的base64图片地址。

canvas.toBlob(callback, mimeType, qualityArgument)方法

这个方法相比上一个方法的优点是它是异步的,所以有一个callback回调,这个callback回调方法默认的第一个参数就是转换好的blob文件信息,本文也想重点介绍这种方法的使用

先说明一下这个方法的三个参数:

参数 类型 是否必传 说明
callback Function toBlob()方法执行成功后的回调方法,支持一个参数,表示当前转换的Blob对象
mimeType String 表示需要转换的图像的mimeType类型。默认值是image/png,还可以是image/jpeg,甚至image/webp(前提浏览器支持)等
qualityArgument Number 表示转换的图片质量。范围是0到1。由于Canvas的toBlob()方法转PNG是无损的,因此,此参数默认是没有效的,除非,指定图片mimeType是image/jpeg或者image/webp,此时默认压缩值是0.92

使用写法如下:

javascript 复制代码
canvas.toBlob((blob) => {
  console.log(blob)
}, 'image/png', 0.92)

可以看到方法执行得到的是当前转换的Blob对象

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

将Blob对象转化为图片地址

下面介绍三种方法进行转化:

方式一: 通过URL.createObjectURL()方法将Blob转化为URL

javascript 复制代码
canvas.toBlob((blob) => {
  const imageUrl = URL.createObjectURL(blob)
  console.log(1, imageUrl)
}, 'image/jpeg', 1)

如下图所示,转化得到的是一个bold流的图片地址。

方式二: 通过FileReader将Blob转化为DataURL

javascript 复制代码
canvas.toBlob((blob) => {
  const reader = new FileReader()
  reader.readAsDataURL(blob)
  reader.onload = () => {
    const imageUrl = reader.result
    console.log(2, imageUrl)
  }
}, 'image/webp', 1)

如下图所示,转化得到的是一个base64的图片地址。

方式三: 通过ajax将Blob上传到服务器

javascript 复制代码
canvas.toBlob((blob) => {
    const formData = new FormData()
    formData.append('file', blob) // 这里的'file'是接口接收参数的字段名,需要根据实际情况改变
    const xhr = new XMLHttpRequest()
    xhr.onload = () => {
      const imageUrl = JSON.parse(xhr.responseText).data // 接口回调参数,需要根据实际情况处理
      console.log(3, imageUrl)
    }
    xhr.open('POST', '/api/upload', true) // '/api/upload'是上传接口,需要根据实际情况改变
    xhr.send(formData)
}, 'image/webp', 1)

由此就会将图片上传到你的文件服务器里,最终可以得到一个你自己文件服务器下对应的图片地址。

toBlob()方法的兼容

首先,toBlob()方法IE9浏览器不支持,因为Blob数据格式IE10+才支持。

然后,对于IE浏览器,toBlob()的兼容性有些奇怪,IE10浏览器支持ms私有前缀的toBlob()方法,完整方法名称是msToBlob()。而IE11+,toBlob()方法却不支持。

但是,我们可以基于toDataURL()方法进行polyfill,性能相对会差一些,JavaScript代码如下:

javascript 复制代码
if (!HTMLCanvasElement.prototype.toBlob) {
  Object.defineProperty(HTMLCanvasElement.prototype, 'toBlob', {
    value: function (callback, type, quality) {
      var canvas = this
      setTimeout(function() {
        var binStr = atob( canvas.toDataURL(type, quality).split(',')[1] )
        var len = binStr.length
        var arr = new Uint8Array(len)

        for (var i = 0; i < len; i++) {
          arr[i] = binStr.charCodeAt(i)
        }

        callback(new Blob([arr], { type: type || 'image/png' }))
      })
    }
  })
}

注意事项

使用外部链接播放视频的话需要在视频标签上设置允许跨域的处理,添加属性crossOrigin='anonymous'即可,

html 复制代码
<video className="videoTag" crossOrigin='anonymous' controls>
     <source src="https://www.w3school.com.cn/example/html5/mov_bbb.mp4" type='video/mp4' />
</video>

或者,在js里处理

javascript 复制代码
const video = document.querySelector(".videoTag")
video.setAttribute('crossOrigin', 'anonymous')
video.load()

否则会报以下错误:

完整封装示例

最后,给出一个利用toBlob进行视频截图,最终获取base64图片地址的封装方法,代码示例如下:

javascript 复制代码
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
      const ctx = canvas.getContext('2d')
      ctx.drawImage(video, 0, 0, w, h)
      canvas.toBlob((blob) => {
        // 通过FileReader将Blob转化为DataURL
        const reader = new FileReader()
        reader.readAsDataURL(blob)
        reader.onload = () => {
          const imageUrl = reader.result
          resolve(imageUrl)
        }
      }, 'image/webp', 1) // 根据需要可以自行配置这里的两个参数
    })
}

调用方法:

javascript 复制代码
const videoTag = document.querySelector(".videoTag")
const dataUrl = await getBase64ByVideo(videoTag)
相关推荐
德育处主任9 小时前
p5.js 用 beginGeometry () 和 endGeometry () 打造自定义 3D 模型
前端·前端框架·canvas
德育处主任2 天前
p5.js 3D模型(model)入门指南
前端·前端框架·canvas
VincentFHR3 天前
Three.js 利用 shader 实现 3D 热力图
前端·three.js·canvas
德育处主任4 天前
p5.js 加载 3D 模型(loadModel)
前端·数据可视化·canvas
用户2519162427115 天前
Canvas之颜色渐变
前端·javascript·canvas
德育处主任5 天前
p5.js 从零开始创建 3D 模型,createModel入门指南
前端·数据可视化·canvas
德育处主任5 天前
p5.js 三角形triangle的用法
前端·数据可视化·canvas
德育处主任6 天前
p5.js 正方形square的基础用法
前端·数据可视化·canvas
德育处主任6 天前
p5.js 矩形rect绘制教程
前端·数据可视化·canvas
用户2519162427117 天前
Canvas之图像合成
前端·javascript·canvas