Canvas绘图包含GIF动画问题

· 2 min read

最近做的小程序有个海报分享feat,大致做法是将一些图片+文本都绘制在一个海报Canvas上,Canvas同时支持输出为dataURL,因此下载也就很简单。但图片资源中有一种是GIF,它是动态资源,包含多帧,测试发现GIF资源在绘制海报时没有问题,但疑问是GIF动画生成静态图片时使用的哪一帧,同时如果想改怎么做呢?借着假期,了解下。

canvas.getContext(‘2d’).drawImage

绘制海报使用的即该函数,因为GIF的每帧可能是不同的,因此查看几个典型的GIF,对比发现,绘制时,使用的会是GIF的第一帧。

在Mac下可以使用preview 来预览GIF,显示的数字即帧数。

指定绘制的GIF帧

本身Canvas或者HTMLImageElement没有提供这种能力,但是第三方类库libgif可以解决该问题。

主要是使用函数superGifEl.move_to(50); superGifEl.pause();移动到指定帧后,再停止播放,获得该上下文下的canvas。

以下为完整例子

 const canvas = document.getElementById('canvas');
      const ctx = canvas.getContext('2d');
      const parentEl = document.createElement('div');
      parentEl.style.display = 'none';
      const imgEl = new Image(60, 45);
      imgEl.src = './5-160914192R4.gif';
      parentEl.appendChild(imgEl);
      const superGifEl = new SuperGif({ gif: imgEl });
      superGifEl.load(function () {
        superGifEl.move_to(50);
        superGifEl.pause();
        drawImageForGif();
        console.log('The number of frames in the gif:' + superGifEl.get_length());
      });

      function drawImageForGif() {
        canvas.width = imgEl.naturalWidth;
        canvas.height = imgEl.naturalHeight;
        console.log(superGifEl.get_canvas().toDataURL('image/png'));
        ctx.drawImage(
          superGifEl.get_canvas(),
          0,
          0,
          imgEl.naturalWidth,
          imgEl.naturalHeight
        );
      }

      function downloadURI(uri, name) {
        var link = document.createElement('a');
        link.download = name;
        link.href = uri;
        document.body.appendChild(link);
        link.click();
        document.body.removeChild(link);
        delete link;
      }
      function download() {
        downloadURI(canvas.toDataURL('image/png'), 'wp.png');
      }

一个小坑

之所以需要const parentEl = document.createElement('div');,是因为libgif的实现中,牵扯到使用GIF资源的父元素,因为这里使用的Image构造函数,而不是document.createElement,因此没有父元素,为了避免控制台报错,所以增加了隐藏的父元素。

微信小程序组件-Painter

微信小程序中支持Canvas绘图,但Canvas原生API操作起来还是繁琐,为了方便,这里我使用Painter组件来操作。

Painer组件中对于图片资源支持URL形式,而SuperGif=>Canvas=>toDataURL,因此小程序中这问题就有解了。

写在最后

如上方案,在海报分享时,遇到GIF资源,就可以灵活控制选择哪一帧了。