0


JS实现视频转gif,react实现视频转gif,前端视频转gif.

前言:

本文介绍如何在前端实现视频转gif,虽然我用的是react+umi的框架,但实现该功能还是靠js,所以会不会react对本文的理解影响不大。
先看一下实现效果:选择视频文件上传,转换成gif并下载。下面这个gif就是使用本文的方法将mp4转成gif的。
在这里插入图片描述

实现思路:

首先介绍一下需要用到的工具——gif.js,它可以把多张图片转成gif。
所以我们要做的步骤如下:

  1. input标签上传视频文件。
  2. 使用canvas将视频内容绘制到画布上。
  3. 设置定时器,从播放视频开始到结束,每隔100ms(可按需自行设置)操作步骤2,可得到连续的截图。
  4. 使用gifjs把得到的截图转换成gif格式。

开始实现

(1)引入gif.js
git地址:https://gitcode.com/jnordberg/gif.js/blob/master/README.md
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
注意文档中说的,gif.js和gif.worker.js要写到一个路径下。我放到了public的dist文件下
在这里插入图片描述
(2)把元素确定好,一个input来上传文件,一个button确认按钮,一个video标签来显示上传的视频。 我是用react写的,render部分如下,用原生和vue的小伙伴自行改造。直接上代码。
注意gif.worker.js的路径一定要写对,否则会报错。特别是使用umi之类的框架,运行的时候相当于是webpakce已经进行了打包,然后本地起了一个服务,如果写的是相对路径"…/…/…/…/public/dist/gif.worker.js"这样的必然是找不到的,而且在进webpack打包的时候也会对文件名进行处理。建议和我一样写在public里面,这样打包的时候文件名也不会变成hash值。如果不能确定文件的路径,可以npm run build看一下gif.worker.js所处的位置,再来填写workerScript的路径。

import{useState, useRef}from'react'constGIF=require('../../../../public/dist/gif')let interval =null//定时器let clipImgs =[]//const delay =200//单位ms,时间间隔,间隔越短越流畅,但是生成的图片体积会越大。//文件转成base64functionconvertFileToBase64(file){returnnewPromise((resolve, reject)=>{const reader =newFileReader();
    reader.readAsDataURL(file);
    reader.onload=()=>resolve(reader.result);
    reader.onerror=error=>reject(error);});}//base64转imagefunctiongetImageFromBase64(base64Image){returnnewPromise((resolve, reject)=>{const img =newImage();
    img.src = base64Image;
    img.onload=()=>resolve(img);
    img.onerror = reject;});}constIndex=()=>{const fileRef =useRef();const videoRef =useRef();const[videoUrl,setVideoUrl]=useState()//video中source的src的值constconfirmFile=()=>{if(!fileRef.current.files?.[0]){return console.log('请选择文件')}setVideoUrl('')convertFileToBase64(fileRef.current.files?.[0]).then(base64Data=>{setVideoUrl(base64Data)//video的srcstart()//视频截图并转成gif}).catch(error=>{
        console.error('Error:', error);});}conststart=()=>{
    console.log('start');//每次开始重置以下值clearInterval(interval) 
    interval =null
    clipImgs =[]let video = videoRef.current //获取video元素
    video.addEventListener('canplay',function(){
      video.play()})

    video.addEventListener('play',function(){var canvas = document.createElement('canvas');// 根据视频大小调整画布尺寸
      canvas.width = video.videoWidth;
      canvas.height = video.videoHeight;// 获取上下文对象var context = canvas.getContext('2d');

      interval =setInterval(()=>{
        context.drawImage(video,0,0);// 将视频内容绘制到画布上var screenshotDataURL = canvas.toDataURL();// 转成Base64
        clipImgs.push(screenshotDataURL)//把所有截图放到一个数组里},delay)});//监听视频播放结束后,说明截图完成。定时器停止,清除定时器缓存,开始转换。
    video.addEventListener('ended',function(e){
      console.log('stop');clearInterval(interval)
      interval =nullmakeGIF()})}constmakeGIF=async()=>{//注意gif.worker.js的路径一定要写对,否则会报错。特别是使用umi之类的框架,运行的时候相当于是webpakce已经进行了打包,然后本地起了一个服务,如果写的是相对路径"../../../../public/dist/gif.worker.js"这样的必然是找不到的,而且在进webpack打包的时候也会对文件名进行处理。建议和我一样写在public里面,这样打包的时候文件名也不会变成hash值。如果不能确定文件的路径,可以npm run build看一下gif.worker.js所处的位置,再来填写workerScript的路径。const gif =newGIF({workers:2,quality:10,workerScript:'/dist/gif.worker.js'});const imgModel =awaitgetImageFromBase64(clipImgs[0])let canvas = document.createElement('canvas');const ctx = canvas.getContext('2d',{willReadFrequently:true});
    canvas.width = imgModel.naturalWidth;
    canvas.height = imgModel.naturalHeight;for(let i=0;i<clipImgs?.length;i++){let img =awaitgetImageFromBase64(clipImgs[i])
      gif.addFrame(img,{delay})}//生成后下载gif图片到本地
    gif.on('finished',function(blob){//生成图片链接var url =URL.createObjectURL(blob);let link = document.createElement('a')
      link.download = Math.random().toString().replace('0.','')+'.gif'
      link.href = url
      link.click()URL.revokeObjectURL(link.href)//释放URL对象});
    gif.render();}return<div><div><input type={'file'} ref={fileRef} accept={'video/*'}/><button onClick={confirmFile}>确定</button></div>{
      videoUrl?<video controls style={{maxHeight:'500px',maxWidth:'500px'}} ref={videoRef}><source src={videoUrl}/></video>:null}</div>}exportdefault Index

可完善内容:
1.截取的图片我没有做压缩
2.没有限制视频时长,如果视频太长可能会造成转换失败的问题,经测试10s内的视频是没问题的。
可根据需要自行完善哦。


原创不易,请给西瓜西西西瓜点个赞,谢谢各位看官。ღ( ´・ᴗ・` )比心


本文转载自: https://blog.csdn.net/qq_34297738/article/details/135385696
版权归原作者 西瓜西西西瓜 所有, 如有侵权,请联系我们删除。

“JS实现视频转gif,react实现视频转gif,前端视频转gif.”的评论:

还没有评论