最近做的小程序有个海报分享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。
以下为完整例子
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
| 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资源,就可以灵活控制选择哪一帧了。