🤬 一战落败
无数个日日夜夜,当我们在社区 Blog 中挥洒笔墨写作时,或多或少都遇到过这样一个问题:
当你想在文章中插入一个视频,用更直观的方式展示技术细节或操作流程时,却发现:
系统只允许从指定视频平台选择,而不支持直接上传本地视频。
这就很让人头大。
我只是想展示几个几秒钟的小片段,根本不值得专门去某个平台上传一条视频。于是很多人选择------放弃。
或者另辟蹊径:
👉 把视频转换成 GIF,再作为图片上传。
这听起来是个不错的解决方案------但实际体验却往往是这样的:

- 仅可免费体验几次
- 导出 GIF 带水印
- 想要去水印?------充钱!
一句话总结:
这些网站不是帮你做图,是想让你"入坑"。

🫡 二战转折
既然如此,那就自己动手!
自己开发一个 🎬 "视频转 GIF" 浏览器插件

一. 设计思路
这个流程图展示了 视频转 GIF 浏览器插件 的操作流程:
- 用户首先 选择本地视频,可以通过文件选择上传。
- 接着在 设置生成参数 阶段,用户可调整 帧率-FPS、像素尺寸-分辨率、画质-Quality、时长截取->Duration。
- 完成参数设置后,点击 生成 GIF ,由
gif.js
处理视频帧生成 GIF 文件流。- 最后,用户可以 预览生成效果 ,满意后直接进行 拖曳上传 或一键下载 无水印 GIF。
二. 实现流程
1. 项目结构确立
perl
GifForge/
├─ manifest.json # 插件清单文件(必须)
├─ popup.html # 弹出界面 HTML
├─ popup.js # 弹出界面 JS
├─ popup.css # 弹出界面样式
├─ icons/ # 图标文件夹
│ ├─ icon16.png
│ ├─ icon48.png
│ └─ icon128.png
├─ lib/ # 第三方库或依赖(如 gif.js)
│ ├─ gif.js
| └─ gif.worker.js
└─ assets/ # 其他资源(如图片、示例视频等)
2. 插件清单文件配置
json
{
"manifest_version": 3,
"name": "GifForge",
"version": "1.0",
"description": "从本地上传视频文件,按要求提取帧,生成GIF并保存到本地",
"action": {
"default_popup": "popup.html",
"default_icon": {
"16": "icons/icon16.png",
"48": "icons/icon48.png",
"128": "icons/icon128.png"
}
},
"icons": {
"16": "icons/icon16.png",
"48": "icons/icon48.png",
"128": "icons/icon128.png"
},
"permissions": []
}
字段 | 说明 | 示例 / 备注 |
---|---|---|
manifest_version |
表示使用的 Manifest 版本。Chrome/Edge 推荐 V3,V3 与 V2 在后台脚本、权限和服务工作者加载方式上有区别。 | 3 |
name |
插件名称,在浏览器扩展管理界面、工具栏、商店中显示。 | "VideoToGif" |
version |
插件版本号,便于发布更新。遵循 主版本号.次版本号.修订号 规则。 | "1.0.0" |
description |
插件描述,告诉用户插件的功能。在浏览器扩展管理页面和商店中显示。 | "从本地上传视频文件,按要求提取帧,生成 GIF 并保存到本地" |
action |
配置点击浏览器工具栏图标时的行为。 - default_popup :指定弹出页面 HTML 文件,例如 popup.html 。 - default_icon :不同尺寸图标,用于工具栏显示。 |
"default_popup": "popup.html" |
icons |
插件图标,用于扩展管理界面、Chrome Web Store 等。建议提供 16px、48px、128px 三种尺寸以适配不同场景。 | "16": "icons/icon16.png" |
permissions |
插件所需权限列表。当前示例为空数组 [] ,可根据需要添加: - "storage" :访问浏览器本地存储 - "activeTab" :访问当前标签页内容 - "tabs" :获取或操作浏览器标签页 - "downloads" :下载文件 |
["storage","downloads"] |
可选扩展字段 | 提高功能: - content_scripts :自动注入的脚本,可操作指定网页的 DOM。 - background :后台脚本或服务工作者,处理全局任务。 - web_accessible_resources :声明可被页面访问的资源,如 worker 脚本。 |
- |
3. 弹出界面设计

html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>视频转GIF工具</title>
<link rel="stylesheet" href="popup.css">
</head>
<body>
<div class="container">
<h1>视频转GIF工具</h1>
<div class="file-input">
<label for="videoFile">选择视频文件</label>
<input type="file" id="videoFile" accept="video/*">
</div>
<div class="settings">
# 设置选项...
</div>
<div class="buttons">
<button id="generateBtn" disabled>生成GIF</button>
<button id="downloadBtn" disabled>下载GIF</button>
</div>
<div class="error" id="errorMsg"></div>
<div class="loading" id="loading">
<p>正在处理,请稍候...</p>
</div>
<div class="preview" id="preview">
<h3>预览</h3>
<div id="previewContainer">
<img id="previewImage" src="" alt="GIF预览">
</div>
</div>
</div>
</div>
</body>
</html>
4. 集成 gif.js
库
gif.js 库里有两个核心文件 gif.js
和 gif.worker.js
是我们开发所必需的。
我们可以在GitHub中下载这两个文件,放置在项目中,以供调用。

① gif.js作用
-
核心库文件 ,提供主接口
GIF
,用于创建 GIF 实例、设置参数和控制生成流程。 -
它主要做两件事:
- 接收帧数据(canvas/image/video)
- 将帧传给
gif.worker.js
处理
-
一般会在 popup.js / 前端页面脚本 中引用。
示例用法:
js
const gif = new GIF({
workers: 2, // 启动多少个 worker 线程
quality: 10, // 图像质量
width: 320,
height: 240
});
// 添加帧
gif.addFrame(canvasElement, {delay: 200});
// 监听完成
gif.on('finished', function(blob) {
const url = URL.createObjectURL(blob);
downloadLink.href = url;
});
② gif.worker.js作用
- Web Worker 文件,在独立线程中处理图像压缩、颜色量化、GIF 编码等耗时任务。
- 优势:不会阻塞主线程,保持页面响应流畅。
gif.js
内部会自动通过Worker
加载它,无需手动调用。- 注意:路径必须正确 ,否则
Worker
无法加载,GIF 生成失败。
在插件中一般放在 lib/
或 assets/
文件夹,并在初始化 GIF
时指定路径:
js
const gif = new GIF({
workers: 2,
workerScript: 'lib/gif.worker.js', // 指定 worker 文件路径
quality: 10
});
5. 转化逻辑实现
① 选择视频文件
用户通过文件选择或拖拽上传本地视频。
js
const videoFileInput = document.getElementById('videoFile');
videoFileInput.addEventListener('change', () => {
if (videoFileInput.files.length > 0) generateBtn.disabled = false;
else generateBtn.disabled = true;
downloadBtn.disabled = true;
preview.style.display = 'none';
gifUrl = null;
});
② 设置生成参数
包括帧率(FPS)、画质(Quality)、宽度(Width)、截取时长(Duration)。
js
const fps = parseInt(fpsInput.value); // 帧率
const quality = parseInt(qualityInput.value); // 画质
const width = parseInt(widthInput.value); // 宽度
const duration = parseInt(durationInput.value); // 截取时长
💡 高度由来
当用户只设置 GIF 的 宽度 时,视频的 高度 会根据原视频的宽高比例自动计算,从而保证生成的 GIF 不会变形。
计算公式:
<math xmlns="http://www.w3.org/1998/Math/MathML"> c a n v a s . h e i g h t = width × video原高度 video原宽度 {canvas.height} = \text{width} \times \frac{\text{video原高度}}{\text{video原宽度}} </math>canvas.height=width×video原宽度video原高度
代码示例:
js// 计算原视频高宽比 const aspectRatio = video.videoHeight / video.videoWidth; // 根据宽度自适应高度 canvas.height = Math.round(width * aspectRatio);
③ 初始化视频和 Canvas
创建隐藏的 <video>
元素读取视频帧,创建 <canvas>
用于绘制帧数据。
js
async function initVideoAndCanvas() {
video = document.createElement('video');
video.autoplay = false;
video.muted = true;
video.loop = false;
canvas = document.createElement('canvas');
ctx = canvas.getContext('2d');
}
④ 逐帧提取并生成 GIF
js
const gif = new GIF({
workers: 2,
quality: quality,
width: width,
height: Math.round(width * aspectRatio),
workerScript: 'lib/gif.worker.js'
});
function addFrame(currentFrame) {
if (currentFrame >= totalFrames) {
gif.render();
return;
}
video.currentTime = currentFrame / fps;
setTimeout(() => {
ctx.drawImage(video, 0, 0, canvas.width, canvas.height);
gif.addFrame(canvas, { copy: true, delay: 1000 / fps });
addFrame(currentFrame + 1);
}, 50);
}
按用户
设置
的帧率循环视频时间。将每帧
绘制
到 Canvas 并添加到 GIF 编码器。使用
gif.js
在 Worker 中编码生成
GIF 文件流。
5. 预览与下载
js
gif.on('finished', blob => {
const url = URL.createObjectURL(blob);
previewImage.src = url;
downloadBtn.disabled = false;
});
downloadBtn.addEventListener('click', () => {
if (gifUrl) {
const a = document.createElement('a');
a.href = gifUrl;
a.download = 'output.gif';
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
}
});
将生成的 GIF 显示在
预览
区域。启用下载按钮,用户可
保存
GIF 文件。
😎 成功上岸
🎉🎉🎉 开发完成之后,咱们直接开始实装测试!
一. 浏览器加载插件


加载插件流程:
- 打开浏览器,输入
浏览器名称://extensions/
进入扩展程序页面
(如:edge://extensions/)- 开启右上角的 开发者模式
- 点击 加载已解压的扩展程序
- 选择插件所在的文件夹(vedioToGif文件夹)
- 插件安装成功后,会在浏览器右上角显示图标
二. 插件测试
① 插件使用示例
完整展示
本插件
的 GIF 动画效果,并使用由自身生成。
② 同一 MP4视频 不同参数下的 GIF
|-----------------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------|
| 16px 10画质 10帧率 5时长 |
48px 10画质 10帧率 5时长 |
128px 1画质 1帧率 5时长 |
| 128 像素 4 画质 4 帧率 5时长 |
128像素 7画质 7帧率 5时长 |
128像素 7画质 7帧率 5时长 |
源码
请各位 彦祖 给我点个👍
