🫡我在掘金写文章:一气之下开源 视频转无水印GIF 插件

🤬 一战落败

无数个日日夜夜,当我们在社区 Blog 中挥洒笔墨写作时,或多或少都遇到过这样一个问题:

当你想在文章中插入一个视频,用更直观的方式展示技术细节或操作流程时,却发现:

系统只允许从指定视频平台选择,而不支持直接上传本地视频。

这就很让人头大。

我只是想展示几个几秒钟的小片段,根本不值得专门去某个平台上传一条视频。于是很多人选择------放弃

或者另辟蹊径:

👉 把视频转换成 GIF,再作为图片上传。

这听起来是个不错的解决方案------但实际体验却往往是这样的:

  • 仅可免费体验几次
  • 导出 GIF 带水印
  • 想要去水印?------充钱

一句话总结:

这些网站不是帮你做图,是想让你"入坑"。


🫡 二战转折

既然如此,那就自己动手!

自己开发一个 🎬 "视频转 GIF" 浏览器插件

一. 设计思路

graph TD 用户操作 --> 点击插件 点击插件 --> 文件选择 文件选择 --> 设置生成参数 设置生成参数 --> 帧率-FPS 设置生成参数 --> 像素尺寸-分辨率 设置生成参数 --> 画质-Quality 设置生成参数 --> 时长截取-Duration 设置生成参数 --> 点击生成-GIF 点击生成-GIF --> gif.js处理视频帧 gif.js处理视频帧 --> 生成-GIF文件流 生成-GIF文件流 --> 预览生成效果 生成-GIF文件流 --> 拖曳上传 生成-GIF文件流 --> 一键下载-无水印GIF

这个流程图展示了 视频转 GIF 浏览器插件 的操作流程:

  1. 用户首先 选择本地视频,可以通过文件选择上传。
  2. 接着在 设置生成参数 阶段,用户可调整 帧率-FPS、像素尺寸-分辨率、画质-Quality、时长截取->Duration
  3. 完成参数设置后,点击 生成 GIF ,由 gif.js 处理视频帧生成 GIF 文件流。
  4. 最后,用户可以 预览生成效果 ,满意后直接进行 拖曳上传 或一键下载 无水印 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.jsgif.worker.js 是我们开发所必需的。

我们可以在GitHub中下载这两个文件,放置在项目中,以供调用。

地址: github.com/jnordberg/g...


① gif.js作用
  • 核心库文件 ,提供主接口 GIF,用于创建 GIF 实例、设置参数和控制生成流程。

  • 它主要做两件事:

    1. 接收帧数据(canvas/image/video)
    2. 将帧传给 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 文件。

😎 成功上岸

🎉🎉🎉 开发完成之后,咱们直接开始实装测试

一. 浏览器加载插件

加载插件流程:

  1. 打开浏览器,输入 浏览器名称://extensions/ 进入扩展程序页面
    (如:edge://extensions/)
  2. 开启右上角的 开发者模式
  3. 点击 加载已解压的扩展程序
  4. 选择插件所在的文件夹(vedioToGif文件夹
  5. 插件安装成功后,会在浏览器右上角显示图标

二. 插件测试


① 插件使用示例

完整展示 本插件 的 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时长 |


源码

传送门🚪

请各位 彦祖 给我点个👍

相关推荐
地方地方3 小时前
深入理解 instanceof 操作符:从原理到手动实现
前端·javascript
哀木3 小时前
useRef 为什么不能作为 useEffect 的依赖项
前端
渣哥3 小时前
事务崩了别怪数据库!三大核心要素没掌握才是根本原因
javascript·后端·面试
渣哥4 小时前
你以为自动开启?Spring 事务支持其实还需要这几步!
javascript·后端·面试
Kisang.4 小时前
【HarmonyOS】窗口管理实战指南
前端·华为·typescript·harmonyos·鸿蒙
诗书画唱4 小时前
Fabric.js 完全指南:从入门到实战的Canvas绘图引擎详解
运维·javascript·fabric
折翼的恶魔4 小时前
前端学习之布局
前端·学习
颜酱4 小时前
理解 Webpack 的构建过程(实现原理),并实现一个 mini 版
前端·javascript·webpack
aesthetician4 小时前
Node.js 24.10.0: 拥抱现代 JavaScript 与增强性能
开发语言·javascript·node.js