有没有办法在 canvas 上渲染动画透明 gif 并更改帧之间的延迟

Is there a way to render animated transparent gif on canvas and change the delay between frames

我正在开发一个网站,可以为透明动画 gif(通常来自 giphy)提供 link,我想在 canvas 上渲染它(动画),同时保持动画 gif 的透明度。这样可以改变GIF的动画速度。

我试过使用以下

我试过很多不同的 gif,包括不是来自 giphy 的 Photoshop 和 After Effects 创建的,但没有结果。


fastgif(其中 all 是用 fetch 获取的解码 gif)

import { Decoder } from 'fastgif'
const d = new Decoder()
window.fetch('https://media.giphy.com/media/tTutsU63rnHC8/giphy.gif')
  .then((response) => response.arrayBuffer())
  .then((buffer) => d.decode(buffer))
  .then(async (frames) => {
  const canvas = document.createElement('canvas');
  canvas.width = all[0].imageData.width;
  canvas.height = all[0].imageData.height;
  const ctx = canvas.getContext('2d');
  let frame = 0;
  while (true) {
    ctx.putImageData(all[frame].imageData, 0, 0);
    await new Promise((resolve) => window.setTimeout(resolve, all[frame].delay));
    if (++frame === all.length) {
      frame = 0;
    }
  }
})

gifuct-js 这个我只试了渲染一帧看透明度能不能用,但是背景全黑,一点透明度都没有。

var tempCanvas = document.createElement('canvas')
var tempContext = tempCanvas.getContext('2d')

window.fetch('https://media.giphy.com/media/tTutsU63rnHC8/giphy.gif')
  .then((response) => response.arrayBuffer())
  .then((buffer) => new GIF(buffer))
  .then((gif) => gif.decompressFrames(true))
  .then(async (frames) => {
    const frame = frames[0]
    const dims = frame.dims
    c.width = dims.width
    c.height = dims.height
    tempCanvas.width = dims.width
    tempCanvas.height = dims.height
    const imageData = tempContext.createImageData(dims.width, dims.height)
    tempContext.putImageData(imageData, 0, 0)
    // set the patch data as an override
    imageData.data.set(frame.patch)
    let pix = imageData.data
    ctx.clearRect(0, 0, c.width, c.height)
    ctx.drawImage(tempCanvas, 0, 0)
    ctx.putImageData(imageData, 0, 0)
    image.src = tempCanvas.toDataURL('image/png')
  })

我希望渲染看起来像将 <img src='https://media.giphy.com/media/tTutsU63rnHC8/giphy.gif' /> 添加到网站。透明背景动画。

这是我发现的一种涉及 gifler 和 konvajs 的解决方案: https://konvajs.org/docs/sandbox/GIF_On_Canvas.html.

Update 这是一个解决方案,其中包括需要调整延迟(注意 onDrawFrame 函数中的注释。

var width = window.innerWidth;
var height = window.innerHeight;

var stage = new Konva.Stage({
  container: 'container',
  width: width,
  height: height,
});

var layer = new Konva.Layer();
stage.add(layer);

var canvas = document.createElement('canvas');
// use external library to parse and draw gif animation
function onDrawFrame(ctx, frame) {
  /*
    Here is where you can adust the delay between frames.
  */
  frame.delay = 80;
  // update canvas that we are using for Konva.Image
  ctx.clearRect(0, 0, canvas.width, canvas.height);
  ctx.drawImage(frame.buffer, frame.x, frame.y);
  // redraw the layer
  layer.draw();
}

gifler('https://media1.giphy.com/media/l4pTpdRiFv10jFlNC/200w_d.gif').frames(canvas, onDrawFrame, true);
// draw resulted canvas into the stage as Konva.Image
var image = new Konva.Image({
  image: canvas
});
layer.add(image);
<!DOCTYPE html>
<html>

<head>
  <script src="https://unpkg.com/konva@3.4.1/konva.min.js"></script>
  <script src="https://unpkg.com/gifler@0.1.0/gifler.min.js"></script>
  <meta charset="utf-8" />
  <style>
    body {
      margin: 0;
      padding: 0;
      overflow: hidden;
      background-color: #f0f0f0;
    }
  </style>
</head>

<body>
  <div id="container"></div>
</body>

</html>