前端使用canvas提取视频中帧的图片/图片上传本地预览

前端使用canvas提取视频中帧的图片

首先是html

1
2
3
4
5
6
7
8
9
10
<style>
img{
width: 300px;
height: 600px;
display: block;
}
</style>

<input type="file" name="videoFile" id="videoFileInput">

调用

1
2
3
4
5
6
7
8
9
10
var inputObj = document.querySelector("#videoFileInput");
inputObj.addEventListener("change",async function (file) {
//每隔1秒创建一张图片 从0秒到4秒逐帧创建
for(var i=0; i< 5; i++) {
const frame = await captureFrame(file.target.files[0],i * 1)
//拿到图片的blob和url 就可以在页面绘制图片了
createImg(frame)
}
})

核心代码

  • 从调用方法里接受一个视频文件,创建一个视频对象。通过URL.createObjectURL 可以创建出本地的视频地址
  • 使用canvas绘制视频 并且HTMLCanvasElement.toBlob()方法可以创建blob 有了blob 通过URL.createObjectURL又可以有 URL
  • 转换链条 canvas ==> blob ==> file对象 ==>上传
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
function captureFrame(vdoFile,time=0){

return new Promise((resolve, reject) => {
const vdo = document.createElement('video');
vdo.currentTime = time;
vdo.muted = true;
//由于此时浏览器没有加载视频,所以自动播放只播放当前这一帧就结束了,这样就可以让视频定格在我们指定的时间。
vdo.autoplay = true;

//通过URL.createObjectURL生成本地URL 可以传入一个file对象或者一个blob
//这个 URL 的生命周期和创建它的窗口中的 document 绑定。也就是说关掉窗口这个时候,URL 就会被释放。
//这个创建出来会是一个blob:xxxxx 放到浏览器可以直接访问,关闭掉页面窗口就销毁了
vdo.src = URL.createObjectURL(vdoFile)

//开始用canvas画视频,当视频可以播放的时候再话,因为可能视频没有加载完
vdo.addEventListener('canplay', async function () {
const frame = await drawVideo(vdo)
resolve(frame)

})

})

}


function drawVideo(vdo) {
return new Promise((resolve, reject) => {
const cvs = document.createElement('canvas');
cvs.width = vdo.videoWidth;
cvs.height = vdo.videoHeight;

const ctx = cvs.getContext('2d');
ctx.drawImage(vdo, 0, 0, cvs.width, cvs.height);

//这个方法是让canvas转换为blob 是个异步方法,所以要用promise
/**
* @returns {Promise} 1个视频的的file对象 可以上传 1个url可以用作预览
* url可以当做本地预览图片地址
* blob可以用户选中了这个图片后上传使用
*/
cvs.toBlob(blob => {
resolve({
file:new File([blob], "test.png", {type:"image/png"}),
url: URL.createObjectURL(blob)
})
})
})
}

function createImg(frame){

const img = document.createElement("img");
img.src = frame.url;
document.body.appendChild(img);
}

本地图片上传预览

  • 使用 FileReader 的 readAsDataURL 方法读取file对象,转为base64,就可以给img的src赋值了
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    const vdoInput = document.querySelector("#videoFileInput");

    vdoInput.addEventListener("change", async (e) => {
    const file = e.target.files[0];
    const reader = new FileReader();
    reader.onload = (e) => {
    createImg(e.target.result)
    }
    reader.readAsDataURL(file);
    })

    function createImg(data) {
    const img = document.createElement("img");
    img.src = data;
    document.body.appendChild(img);

    }