最近在博客后台上传图片的时候,忽然发现上传gif图片的时候裁剪图片有问题。既无法裁剪gif指定区域的图片,又无法裁剪指定区域生成一个新的指定大小的gif图。原本想直接去找个裁剪的库直接放上去的,可是找了半天也没找到可以裁剪gif而后生成裁剪区域的gif的库,因而就本身动手了。html
若是只是单纯的在Gif上裁剪第一帧图片,却是有插件能实现,我用的就是react-cropper来进行图片裁剪的。可是这个插件无法裁剪GIF生成另外一个GIF图。前端
我要的效果是下面这样的效果react
原图
裁剪后的gif图
而后就去查了下如何实现gif图到gif图的裁剪,虽然没有找到对应的插件,可是找到了两个开源的库。git
发现这两个功能一组合不就能够实现我要的那个效果了么。github
上传GIF => 经过解析GIF每一帧在Canvas上生成对应的图像 => canvas转成GIF
libgif-js
是经过实现对gif路径发起一个请求,而后经过解析请求回来的gif数据来生成GIF实例(包括每一帧的动画,以及大小之类的基础数据),而后经过GIF实例生成对应的canvas
typescript
经过收集libgif-js
转换到canvas上面的每一帧的变化,来生成最终的GIF
。npm
首先到libgif-js这个项目中下载对应的js文件,由于这个库并无上传npm,因此须要本身去项目中下载。libgif-js
他这个封装的是对HTML
节点的操做,无法直接去用,由于我是上传文件,获取的File
对象,因此须要对这个文件进行部分修改canvas
url
路径,能够把File文件
经过URL.createObjectURL(file)
转成成url
,让其进行XMLHttpRequest
请求。 也能够直接传gif
的连接。libgif-js
文件里面不须要的代码,只须要其中每一帧的图像集合跟尺寸大小就行监听gif绘制到canvas上的每一帧变化,而后gif.js
收集每一帧的canvas变化,最后生成新的gifapp
// 导出gif实例, GifToCanvas实例是对libgif-js封装的修改,经过调用init方法,触发gif到canvas的绘制 const gifToCanvas = new GifToCanvas(url, { targetOffset: { dx: cropBoxData.left - canvasData.left, dy: cropBoxData.top - canvasData.top, width: canvasData.width, height: canvasData.height, sWidth: cropBoxData.width, sHeight: cropBoxData.height } }) // 启动gif转canvas gifToCanvas.init() // 经过 gif.js 库来收集由 GifToCanvas绘制出来的canvas里面的每一帧,最后生成gif的Blob源。 const gif = new GIF({ workers: 2, quality: 10, workerScript: '/static/js/gif.worker.js' }) const addFrame = (canvas: HTMLCanvasElement, delay: number) => { gif.addFrame(canvas, { copy: true, delay }) } // 监听每一帧的变化,收集每一帧的变化 gifToCanvas.on('progress', (canvas, delay) => { addFrame(canvas, delay) }) // 动画执行完毕,执行gif.render gifToCanvas.on('finished', (canvas, delay) => { addFrame(canvas, delay) gif.render() }) // canvas生成gif完毕,导出blob, 生成新的文件 gif.on('finished', (blob) => { const newFile = new File([blob], 'new.gif', { type: blob.type }) // 上传新的gif文件 const formDate = new FormData() formDate.append('file', newFile) ... })
这样就生成了一个裁剪后的gif文件。学习
参考资源
本项目完整的代码:GitHub 仓库
这个项目也没有作太多复杂的设置,知足裁剪GIF的功能就行,由于我目前只须要把gif裁剪成指定大小的gif就行,因此并无作太多特制化的功能
我的博客源码这个项目也上线了这个功能 | 博客源码项目地址
我本身新建立了一个相互学习的群,不管你是准备入坑的小白,仍是半路入行的同窗,但愿咱们能一块儿分享与交流。
QQ群:810018802, 点击加入
QQ群 | 公众号 |
---|---|
前端打杂群![]() |
冬瓜书屋![]() |