没错 这个是目录
本次内容采用vue3 进行演示
如果你需要gif裁剪为gif 请移步笔者此篇文章
准备工作
-
搭建一个 vue +vite的工程
-
下载
gif.js
gifuct-js
两个包 -
在
vite.config.js
的配置optimizeDeps
中添加两个依赖
截取视频片段转成gif
先说思路
video
标签播放的时候 我们读取某一帧的视频流,并且依次保存每一帧- 使用
gif.js
把依次保存的帧转成gif
初始代码
<template>
<div>
<h1>Vedio to gif</h1>
<div>
<video ref="videoRef" src="@/assets/demo.mp4" controls autoplay />
<div class="controls">
<button :disabled="isRecording" @click="startCapture"> 开始录制 </button>
<button :disabled="!isRecording" @click="stopCapture"> 停止录制 </button>
</div>
<div v-if="progress > 0" class="progress"> 处理中: {{ progress }}% </div>
<div v-if="gifUrl" class="output">
<h3>录制的GIF:</h3>
<img :src="gifUrl" alt="GIF 预览" />
<button @click="downloadGif">下载GIF</button>
<button @click="extractFrames">提取帧</button>
</div>
</div>
</div>
</template>
<script setup>
import GIF from 'gif.js'
import { onUnmounted, ref } from 'vue'
const videoReady = ref(true)
const videoRef = ref(null)
const isRecording = ref(false)
const progress = ref(0)
const gifUrl = ref(null)
const frames = ref([]) // 保存提取的帧
let gifRecorder = null
let captureInterval = null
</script>
<style scoped>
</style>
初始化gif渲染器
// 初始化GIF录制器
const initGifRecorder = () => {
if (gifRecorder) {
gifRecorder.abort()
}
gifRecorder = new GIF({
workers: 2,
quality: 10,
width: videoRef.value?.videoWidth || 320,
height: videoRef.value?.videoHeight || 240,
workerScript: '/gif.worker.js' // 确保这个文件在public目录下
})
console.log('GIF捕捉器初始化成功')
gifRecorder.on('progress', p => {
progress.value = Math.round(p * 100)
})
gifRecorder.on('finished', blob => {
gifUrl.value = URL.createObjectURL(blob)
// 自动下载
// downloadGif()
// 重置状态
isRecording.value = false
progress.value = 0
})
}
点击播放
// 开始录制
const startCapture = () => {
if (!videoRef.value || isRecording.value || !videoReady.value) return
initGifRecorder()
isRecording.value = true
captureInterval = setInterval(captureFrame, 100)
}
点击停止
// 停止录制
const stopCapture = () => {
if (!isRecording.value) return
clearInterval(captureInterval)
gifRecorder.render()
console.log('结束录制')
}
提取帧逻辑
const extractFrames = () => {
if (!videoRef.value) return
const canvas = document.createElement('canvas')
const ctx = canvas.getContext('2d')
canvas.width = videoRef.value.videoWidth
canvas.height = videoRef.value.videoHeight
// 确保视频帧已渲染
if (videoRef.value.readyState >= 2) {
// >= 2 表示视频数据已加载
ctx.drawImage(videoRef.value, 0, 0, canvas.width, canvas.height)
gifRecorder.addFrame(ctx, {
copy: true,
delay: 100
})
}
}
// 清理
onUnmounted(() => {
if (gifRecorder) {
gifRecorder.abort()
}
clearInterval(captureInterval)
})
下载逻辑
const downloadGif = () => {
const a = document.createElement('a')
a.href = gifUrl.value
a.download = `capture-${Date.now()}.gif`
a.click()
}