当前位置 博文首页 > cd-dongzi:GIF图片裁剪出指定大小的GIF图片

    cd-dongzi:GIF图片裁剪出指定大小的GIF图片

    作者:cd-dongzi 时间:2021-05-07 18:19

    前言

    最近在博客后台上传图片的时候,突然发现上传gif图片的时候裁剪图片有问题。既没法裁剪gif指定区域的图片,又没法裁剪指定区域生成一个新的指定大小的gif图。本来想直接去找个裁剪的库直接放上去的,但是找了半天也没找到能够裁剪gif然后生成裁剪区域的gif的库,于是就自己动手了。

    探索

    如果只是单纯的在Gif上裁剪第一帧图片,倒是有插件能实现,我用的就是react-cropper来进行图片裁剪的。但是这个插件没法裁剪GIF生成另一个GIF图。

    我要的效果是下面这样的效果

    原图

    原图

    裁剪后的gif图

    原图

    然后就去查了下如何实现gif图到gif图的裁剪,虽然没有找到对应的插件,但是找到了两个开源的库。

    1. libgif-js 通过解析GIF,生成Canvas
    2. gif.js 把canvas转换成GIF图片

    发现这两个功能一组合不就可以实现我要的那个效果了么。

    上传GIF => 通过解析GIF每一帧在Canvas上生成对应的图像 => canvas转成GIF

    实现

    libgif-js的实现过程

    libgif-js是通过实现对gif路径发起一个请求,然后通过解析请求回来的gif数据来生成GIF实例(包括每一帧的动画,以及大小之类的基础数据),然后通过GIF实例生成对应的canvas

    gif.js的实现过程

    通过收集libgif-js转换到canvas上面的每一帧的变化,来生成最终的GIF

    gif转换到canvas的实现过程

    首先到libgif-js这个项目中下载对应的js文件,因为这个库并没有上传npm,所以需要自己去项目中下载。
    libgif-js他这个封装的是对HTML节点的操作,没法直接去用,因为我是上传文件,获取的File对象,所以需要对这个文件进行部分修改

    1. 首先应该接收的是一个url路径,可以把File文件通过URL.createObjectURL(file)转成成url,让其进行XMLHttpRequest请求。 也可以直接传gif的链接。
    2. 然后需要传裁剪的区域范围。裁剪的范围大小需要适配原gif的尺寸比例
    3. 去除libgif-js文件里面不需要的代码,只需要其中每一帧的图像集合跟尺寸大小就行

    canvas转换到gif的实现过程

    监听gif绘制到canvas上的每一帧变化,然后gif.js收集每一帧的canvas变化,最后生成新的gif

    // 导出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文件。

    参考资源

    • libgif-js
    • gif.js

    本项目完整的代码:GitHub 仓库

    线上效果演示

    博客原文地址

    总结

    这个项目也没有做太多复杂的设置,满足裁剪GIF的功能就行,因为我目前只需要把gif裁剪成指定大小的gif就行,所以并没有做太多特制化的功能

    个人博客源码这个项目也上线了这个功能 | 博客源码项目地址

    我自己新创建了一个相互学习的群,无论你是准备入坑的小白,还是半路入行的同学,希望我们能一起分享与交流。
    QQ群:810018802, 点击加入

    QQ群 公众号
    前端打杂群
    QQ群:810018802
    冬瓜书屋
    公众号:冬瓜书屋
    bk
    下一篇:没有了