前端Q

我是winty,专注分享前端知识和各类前端资源,乐于分享各种有趣的事,关注我,一起做个有趣的人~

公众号

点击上方 前端Q,关注公众号

回复加群,加入前端Q技术交流群

英文 | https://javascript.plainenglish.io/how-to-convert-a-video-clip-to-a-gif-file-with-client-side-javascript-56575d093191

作为一个程序员,一个热爱技术写作的人,把自己的知识经验通过文字呈现在读者面前,并且让读者通过文字,就能将知识进行学以致用,其实,是非常有调整性的一件事情,因为,它需要我与读者保持有效沟通,既不浪费读者的时间,也不浪费自己的时间,同时还要保证读者能够读有所获。

由于技术文章的质量很大程度上取决于其内容的易消化程度,因此,我倾向于利用以图形交换格式 (GIF) 格式编码的屏幕截图,以尽可能减少额外的文本描述块。例如,在更倾向于 Web 开发内容的文章中,例如:

在这种情况下,我总是发现嵌入动画 GIF 来演示我创建的开源工具的任何用法是有益的:

鉴于 Microsoft Powerpoint 的内置屏幕录制功能很容易访问,虽然,可以轻松完成自己的屏幕录制以输出屏幕截图,但我觉得更有益的探索领域将是 - 易于访问转换视频的工具 将屏幕截图(.mp4、.avi 等)转换为 .GIF 图像文件。

— 注意:按照惯例,如果要渲染动画短片(≤ 30 秒),则 GIF 文件更合适。

使用 GIFEncoder.js 将视频构建到 GIF Maker

为了构建浏览器实用程序,如下所示:

这 3 个 JavaScript 插件是必需的:

  • GIFEncoder.js

  • LZWEncoder.js

  • NeuQuant.js

仅供参考:这些插件最初是由 GitHub 用户 Kevin Kwok(创建者)从 GitHub repo jsgif 中检索到的。

视频到 GIF 转换概述

先决条件:包含在上述3个文件中+ b64.js如下:

<script type="text/javascript" src="LZWEncoder.js"></script>
<script type="text/javascript" src="NeuQuant.js"></script>
<script type="text/javascript" src="GIFEncoder.js"></script>
<script type="text/javascript" src="b64.js"></script>

技术实施——总共 4 个步骤

步骤(1):上传视频片段(≤30秒)

因此,在 HTML 代码中,包含一个简单的用户输入界面:

<input id='inputVideoClipFile' type='file' multiple='false'
accept='.mp4,.webm,.avi,.mpeg,.flv,.mov,.3gp' />

将事件处理程序(onchange)标记到上面并继续在 JavaScript 中初始化 FileReader 实例:

inputVideoClipFile.onchange = function(uploadFle) {let file = inputVideoClipFile.files[0];
let fileName=file.name;let fileSize=(file.size/1024).toFixed(2);let fileType=file.type;
let fileredr = new FileReader();
fileredr.onload = function (fle) {var b64Str=fle.target.result;
}; // end file-reader onloadfileredr.readAsDataURL(file);
};

请注意,新的 FileReader() 实例调用 readAsDataURL,因此分配给 b64Str 的视频文件内容被读取为 Base64 字符串。

从文件对象中检索视频文件的信息以供稍后显示。

步骤(2):处理视频二进制数据并提取帧,有两个主要部分需要考虑:

Part I. 通过创建 <video></video> DOM 元素并在 JavaScript 中分配相应的属性来预览视频内容以供显示.

// rendered as <video></video> in HTML code
var videoObj = document.createElement('video');
var displayedHeight=500;
if(videoObj.canPlayType(fileType)) {videoObj.setAttribute('id','inputVideo');videoObj.setAttribute('src', b64Str);videoObj.setAttribute('height', displayedHeight);
}

注意b64Str是前面步骤中FileReader()读取的视频文件数据。

第二部分,帧提取——每个视频帧都指的是剪辑在唯一时间戳的图像快照。

由于 GIF 文件是通过合并一组连续的图像创建的,因此,对于视频的每一次时间图形更新,都需要提取一个嵌入了图像数据的帧,用于后续的 GIF 创建过程。

虽然不能直接从 DOM 元素 <video></video> 中提取每个视频帧所需的图像数据,但可以将 <video></video> 中的预览内容渲染到 <canvas></canvas> 元素上 帧图像数据提取。

接下来,在 JavaScript 中创建一个 <canvas></canvas> 元素并为其分配相应的属性(类似于 <video></video>):

var vidHeight=videoObj.videoHeight;
var vidWidth=videoObj.videoWidth;
var bitmap = document.createElement('canvas');
bitmap.setAttribute('id', 'bitmap');
bitmap.setAttribute('width', vidWidth);
bitmap.setAttribute('height', vidHeight);

请注意,vidWidth 和 vidHeight 是从 <video></video> 检索的。(这些是剪辑的原始尺寸。)

接下来的几行代码基于标记到每个元素的 'id' 属性来引用 <video></video> 和 <canvas></canvas>:

const inputVideo=document.getElementById('inputVideo');
const bitmapCanvas=document.getElementById('bitmap');
const bitmapCtx = bitmapCanvas.getContext('2d');
inputVideo.muted = true;
inputVideo.loop = false;
inputVideo.autoplay=true;
const background = () => {bitmapCtx.fillStyle = '#FFFFFF';bitmapCtx.fillRect(0, 0, vidWidth, vidHeight);
};

由于视频设置为自动播放,当播放事件被发出时,这会触发 background() 的执行,它不仅将 GIF 背景填充为白色,而且还设置了绘制到 canvas 元素上的每一帧的尺寸:

const step = async() => {let bgStatus=await background();await new Promise(resolve => {bitmapCtx.drawImage(inputVideo, 0, 0, vidWidth, vidHeight);frameB64Str = bitmapCanvas.toDataURL();resolve();});window.requestAnimationFrame(step);
};
inputVideo.addEventListener('play', () => {step();window.requestAnimationFrame(step);
});

window.requestAnimationFrame(step) 接受一个回调函数(即step())来处理每一帧的图像数据。

bitmapCtx.drawImage() 继续将每个图像快照渲染到画布上,以便 bitmapCanvas.toDataURL() 返回每个快照的 base64 编码图像。

步骤(3):依次合并所有图像快照

最后实现了JS插件GIFEncoder.js。使用与上面相同的代码片段,以下粗体代码行指的是 GIFEncoder 编码器捕获嵌入在 <canvas></canvas> 中的每个数据帧的实例。

const encoder = new GIFEncoder(vidWidth, vidHeight);
encoder.setRepeat(0);
encoder.setDelay(500);
const step = async() => {let bgStatus=await background();await new Promise(resolve => {bitmapCtx.drawImage(inputVideo, 0, 0, vidWidth, vidHeight);frameB64Str = bitmapCanvas.toDataURL();encoder.addFrame(bitmapCtx);resolve();});window.requestAnimationFrame(step);
};
inputVideo.addEventListener('play', () => {encoder.start();step();window.requestAnimationFrame(step);
});

当上传的视频最终播放完整时长时,应在 GIFEncoder 调用方法 finish() 的地方发出结束事件:

inputVideo.addEventListener('ended', () => {encoder.finish();
});

步骤 (4):通过 GIFEncoder 创建 GIF

要从编码器中提取所有帧的合并版本(即 GIF 输出),需要实现以下 JavaScript 代码片段:

var fileType='image/gif';
var readableStream=encoder.stream();
var binary_gif=readableStream.getData();
var b64Str='data:'+fileType+';base64,'+encode64(binary_gif);

encode64() 是 b64.js 中的一种方法,用于将 GIFEncoder 捕获的流数据转换为 Base64 格式。

b64Str 通过合并 GIFEncoder 中存在的所有帧来引用为 GIF 文件编码的数据。因此,在 HTML 代码中,继续包含:<img id='outputGif' src='${b64Str}' alt='${fileName}' /> 以预览输出 GIF 文件。

最后创建一个GIF文件的下载链接,如下:

let dwnlnk = document.createElement('a');
dwnlnk.download = fileName;
dwnlnk.innerHTML = `												

如何使用客户端 JavaScript 将视频剪辑转换为 GIF 文件相关推荐

  1. 分享视频剪辑转换为mp3音频保存

    如何将视频转换为音频保存呢?给大家分享一个批量剪辑转换的方法,下面一起来看操作步骤 吧.希望大家可以用到吧. 准备多个视频保存一起方便提取演示,每个视频都是mp4格式视频. 在电脑上打开视频剪辑高手, ...

  2. 视频怎么转换为音频文件?快来掌握这几种方式

      大家平时在下载网课资源进行学习的时候,看久了眼睛也会开始疲劳,而且有些视频的画面看起来很枯燥.其实我们可以使用一些软件把视频中的音频分离出来,直接收听音频也可以学到知识,而且我们还可以处理其他的事 ...

  3. moviepy音视频剪辑:视频剪辑基类VideoClip的属性及方法详解

    ☞ ░ 前往老猿Python博文目录 ░ 一.概述 在<moviepy音视频剪辑:moviepy中的剪辑基类Clip详解>和<moviepy音视频剪辑:moviepy中的剪辑基类Cl ...

  4. moviepy音视频剪辑基类VideoClip的write_videofile方法codec、bitrate、preset、audio_bitrate、audio_nbytes等参数的作用

    ☞ ░ 前往老猿Python博文目录 ░ moviepy音视频剪辑模块的视频剪辑基类write_videofile方法用于将视频剪辑输出到文件,调用语法如下: write_videofile(self ...

  5. 如何使用视频剪辑软件将qsv格式视频转换为MP4格式 1

    在闲暇的时光中很多朋友会通过观看视频来度过,但是我们的手机不是所有格式的视频都可以播放,遇到不兼容的格式,我们就需要使用视频转换器来转换格式了.送福利啦~小编将在这篇文章里为大家介绍视频剪辑格式转换软 ...

  6. 视频剪辑:如何将竖屏视频转换为横屏视频

    小编最近经常看到有人会问小编要怎么样才能把竖屏视频转为横屏视频啊?今天,小编就给大家分享一个办法来教大家要如何将竖屏视频转为横屏视频. 首先,第一步,我们要打开[视频剪辑高手]并登录账号,新人小伙伴们 ...

  7. 剪映VS会声会影哪个好用,视频剪辑软件剪映会声会影之间对比之

    随着网络视频的发展,越来越多的人开始学习视频剪辑,毕竟技多不压身,而在众多剪辑软件中,剪映和会声会影是很适合新手使用的软件,那剪映与会声会影的区别有哪些?剪映会声会影哪个好用?下面就仔细说说. 一.剪 ...

  8. Final Cut Pro X mac版专业的视频剪辑软件

    Final Cut Pro X是mac客户端最专业的视频剪辑软件,拥有最完善的视频处理功能,可以编辑不同分辨率的视频,搭配本站的fcpx插件使用效果更佳.新版的Final Cut Pro X for ...

  9. 解读Google Analytics(分析)客户端javascript代码

    /** * 代码翻译:周培公 * 电子邮件:peigong@foxmail.com * 腾讯微博:http://t.qq.com/lanxmail * 新浪微博:http://weibo.com/17 ...

最新文章

  1. java跨域权重_爱站权重查询 API 接口请求调用
  2. 第7周实践项目2.2 求解报数问题
  3. 数据结构 - 数组模拟一般队列
  4. 使用MailMessage.AlternateViews时遇到的小问题
  5. less编译工具koala(考拉)和rem的使用
  6. 24.Plugin System
  7. SQL2005备份如何在SQL2000上还原
  8. AppleAlc 工具 dump-coeff的使用方法
  9. rls自适应滤波器matlab实现,Matlab自适应滤波器设计Demo——LMS,RLS
  10. php集成开发环境哪个最好,推荐几个好用的PHP集成开发环境
  11. 京东自动抢购茅台脚本
  12. API接口设计的五大公共参数
  13. CAP定理以及BASE定理详解
  14. D. Concatenated Multiples
  15. TAMER——Training an Agent Manually Via Evaluative Reinforcement
  16. 【C#公共帮助类】枚举独特类
  17. 使用OFBIZ的理由和不使用OFBIZ的理由
  18. Docker 快速上手学习入门教程 1
  19. Spring Boot 项目 - API 文档搜索引擎
  20. 电磁场与仿真软件(19)

热门文章

  1. QProcess调用外部程序
  2. Sandcastle方法生成c#.net帮助类帮助文档chm
  3. 免费虚拟服务器多开软件,云服务器多开模拟器
  4. 描述DNS解析的工作过程
  5. 计算机系运动会横幅怎么写,运动会横幅标语(精选50条)
  6. Autowire 和 @Resource 的区别
  7. DeFi猎手丨一文读懂DeFi的7种新玩法,实现最大化收益
  8. 写在开头的话:有心人,天不负
  9. 两人取石子游戏 组合数学-博弈问题
  10. linux中.sh脚本的编写