Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

使用 apng-js 控制 apng 动画的播放 #31

Open
jrainlau opened this issue Jul 11, 2021 · 0 comments
Open

使用 apng-js 控制 apng 动画的播放 #31

jrainlau opened this issue Jul 11, 2021 · 0 comments
Labels

Comments

@jrainlau
Copy link
Owner

在最近的需求中,设计师给了我两个 apng 格式的动图,要求是在同样的位置,第一个动图播放1遍,第二个动图循环播放,中间要自然衔接和过渡。
open-platform-animate-1-new

open-platform-animate-2-new

apng 格式的动图是我第一次使用到的,我对它的了解仅仅局限于“会动的png图片”。后来几经搜索,总算是把 apng 的一些知识点给补全了。由于网上关于 apng 的资料非常多,因此就不在这里对 apng 进行过多的介绍了。

浏览器默认没有提供 api 让我们去操纵 apng,所以我们无法直接监听 apng 的播放事件,更无法控制它的播放动作。怎么办呢?还好有万能的 npm,直接搜索 apng 就出现了一个名为 apng-js 的库,它可以满足我们的需求。

apng-js 写得很简洁,其核心原理是按照 apng 的规范解析 apng 图片的数据,然后把它们绘制到 canvas 上。与此同时,它还提供了 api 让我们去控制 apng 图片的播放、暂停、复位,更能监听这些图片播放中产生的事件,使得我们拥有了对 apng 的完全控制权。废话不多说,直接上例子让我们看看 apng-js 是如何完成我们的需求的。

  1. 首先在 html 中把 <canvas> 元素准备好,然后引入 apng-js 库,初始化 canvas 的尺寸和图片资源。
<canvas id="canvas"></canvas>
// js file

import parseAPNG from "https://cdn.skypack.dev/[email protected]";

const img1Src = 'https://official-account-web-1251316161.cos.ap-guangzhou.myqcloud.com/mqq-static/open-platform-animate-1-new.png'
const img2Src = 'https://official-account-web-1251316161.cos.ap-guangzhou.myqcloud.com/mqq-static/open-platform-animate-2-new.png'

const canvas = document.querySelector('#canvas')
canvas.width = 640;
canvas.height = 540;
canvas.style = 'zoom: 0.75';
const ctx = canvas.getContext('2d');
  1. 由于 apng-js 只接受 ArrayBuffer 形式的数据,因此我们需要自行写函数来把 apng 转化成 ArrayBuffer。
// js file
// 获取图片并转化成 ArrayBuffer
function getImgBuffer(url) {
  return new Promise(async resolve => {
    const blob = await fetch(url).then(res => res.blob());
    const reader = new FileReader();
    reader.readAsArrayBuffer(blob);
    reader.onload = () => {
      resolve(reader.result);
    };
  });
}
  1. 拿到了 ArrayBuffer 格式的 apng 图片资源以后,就可以通过 apng-js 来进行解析并使用了。这里我创建了一个名为 createApngPlayer() 的公用函数,输出 apng-js 的 player 实例,方便我们的后续使用。
async function createApngPlayer(url, ctx, options = {}) {
  const imgBuffer = await getImgBuffer(url);
  const apng = parseAPNG(imgBuffer);
  Object.keys(options).forEach(key => {
    apng[key] = options[key];
  });
  const player = await apng.getPlayer(ctx);
  return player;
}
  1. 得到了 player 实例以后,就可以用它来控制 apng 的播放啦!
;(async () => {
  const player1 = await createApngPlayer(img1Src, ctx, { numPlays: 1 }); // 设置图1的 numPlays 为1,让其只播放一次
  const player2 = await createApngPlayer(img2Src, ctx);
  player1.play(); // 图1播放
  player1.on('end', () => { // 监听图1的播放,当其播放完毕时,马上开始图2的播放
    player2.play();
  });
})()

实现效果可以看我在 Codepen 的例子:
https://codepen.io/jrainlau/pen/abWmaNK

Kapture 2021-07-11 at 16 25 07

大功告成!

Repository owner deleted a comment from abinzhao Dec 13, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

1 participant