GIF圖片裁剪出指定大小的GIF圖片

前言

最近在博客後臺上傳圖片的時候,忽然發現上傳gif圖片的時候裁剪圖片有問題。既無法裁剪gif指定區域的圖片,又無法裁剪指定區域生成一個新的指定大小的gif圖。原本想直接去找個裁剪的庫直接放上去的,可是找了半天也沒找到可以裁剪gif而後生成裁剪區域的gif的庫,因而就本身動手了。html

探索

若是隻是單純的在Gif上裁剪第一幀圖片,卻是有插件能實現,我用的就是react-cropper來進行圖片裁剪的。可是這個插件無法裁剪GIF生成另外一個GIF圖。前端

我要的效果是下面這樣的效果react

原圖

原圖

裁剪後的gif圖

原圖

而後就去查了下如何實現gif圖到gif圖的裁剪,雖然沒有找到對應的插件,可是找到了兩個開源的庫。git

  1. libgif-js 經過解析GIF,生成Canvas
  2. gif.js 把canvas轉換成GIF圖片

發現這兩個功能一組合不就能夠實現我要的那個效果了麼。github

上傳GIF => 經過解析GIF每一幀在Canvas上生成對應的圖像 => canvas轉成GIF

實現

libgif-js的實現過程

libgif-js是經過實現對gif路徑發起一個請求,而後經過解析請求回來的gif數據來生成GIF實例(包括每一幀的動畫,以及大小之類的基礎數據),而後經過GIF實例生成對應的canvastypescript

gif.js的實現過程

經過收集libgif-js轉換到canvas上面的每一幀的變化,來生成最終的GIFnpm

gif轉換到canvas的實現過程

首先到libgif-js這個項目中下載對應的js文件,由於這個庫並無上傳npm,因此須要本身去項目中下載。
libgif-js他這個封裝的是對HTML節點的操做,無法直接去用,由於我是上傳文件,獲取的File對象,因此須要對這個文件進行部分修改canvas

  1. 首先應該接收的是一個url路徑,能夠把File文件經過URL.createObjectURL(file)轉成成url,讓其進行XMLHttpRequest請求。 也能夠直接傳gif的連接。
  2. 而後須要傳裁剪的區域範圍。裁剪的範圍大小須要適配原gif的尺寸比例
  3. 去除libgif-js文件裏面不須要的代碼,只須要其中每一幀的圖像集合跟尺寸大小就行

canvas轉換到gif的實現過程

監聽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羣 公衆號
前端打雜羣
QQ羣:810018802
冬瓜書屋
公衆號:冬瓜書屋
相關文章
相關標籤/搜索