6
头图

Preface

Recently, when uploading pictures in the background of the blog, I suddenly found that there was a problem with cropping pictures when uploading gif pictures. It is impossible to crop the picture in the specified area of the gif, and it is impossible to crop the specified area to generate a new gif image of the specified size. Originally intended to go directly to a cutting library directly put up, but look for a long time can not find cut and then generate gif gif crop area of library, so he do it yourself.

explore

If you simply crop the first frame of the picture on the Gif, there are plug-ins that can do it. I use react- to crop the picture. But this plug-in cannot crop the GIF to generate another GIF image.

The effect I want is the following effect

Original image

原图

Cropped gif

原图

Then I checked how to cut the gif image to the gif image. Although I didn't find the corresponding plug-in, I found two open source libraries.

  1. libgif-js Generate Canvas by parsing GIF
  2. gif.js Convert canvas to GIF image

I found that a combination of these two functions can achieve the effect I want.

Upload GIF => Generate a corresponding image on Canvas by parsing each frame of GIF => Convert canvas to GIF

achieve

The realization process of libgif-js

libgif-js is to initiate a request to the gif path, and then generate a GIF instance (including the animation of each frame, and basic data such as size) by parsing the gif data returned by the request, and then generate the corresponding canvas

The realization process of gif.js

GIF is generated by collecting the changes of each frame of libgif-js converted to the canvas.

The realization process of converting gif to canvas

First, download the corresponding js file in the libgif-js project, because this library does not upload npm, so you need to download it in the project yourself.
libgif-js He encapsulates the HTML node, which cannot be used directly, because I uploaded a file and obtained the File object, so I need to modify this file partially

  1. The first thing that should be received is a url path. You can convert the File file to URL.createObjectURL(file) url , and let it make a XMLHttpRequest request. You can also directly pass the link of gif
  2. Then you need to pass the cropped area. The size of the cropping range needs to be adapted to the size ratio of the original gif
  3. Remove the libgif-js file, and only need the image collection and size of each frame.

The realization process of canvas to gif

Monitor every frame change of the gif drawn on the canvas, then gif.js collects the canvas change of each frame, and finally generate a new 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)
  ...
})

This generates a cropped gif file.

Reference Resources

The complete code of this project: GitHub repository

online effect demonstration

Original blog address

to sum up

This project did not do too many complicated settings, just to meet the function of cropping GIF, because I only need to crop the gif to a gif of a specified size at present, so there are not too many special functions.

Personal blog source code project also launched this function | blog source code project address

I have created a new group to learn from each other. Whether you are a Xiaobai who is about to enter the pit, or a classmate who is halfway into the industry, I hope we can share and communicate together.
QQ group: 810018802, click to join
QQ groupthe public
Front end miscellaneous group
QQ群:810018802
Winter Melon Bookstore
公众号:冬瓜书屋

咚子
3.3k 声望12.5k 粉丝

一个前端