PAG介绍

Portable Animated Graphics 是一套完整的动画工作流解决方案。提供从 AE (Adobe After Effects) 导出插件,到桌面预览工具,再到覆盖 iOS,Android,macOS,Windows,Linux 和 Web 等各平台的渲染 SDK。

PAG 的目标是降低或消除动画研发相关的成本,打通设计师创作到
素材上线的自动化流程,不断输出运行时可编辑的高质量动画内容。

前情提要

公司移动端接入PAG去实现模版视频,产品一看不错嘛,web端也上!这样就有了接触的机会,PAG对接了许多桌面端的场景,目前web端项目刚起步,还不够成熟,不过影响我们学习使用,这里就给大家分享一下调试的坑与经验~~~

目前web端主要功能还是展示.pag文件,通过canvas展示动图效果或者视频效果,项目是 react18 做的pc与移动端官网。

实战

PAG-web文档
目前接入方式分为两种,Browser script直接引用、ESModule。下面分别介绍一下

Browser script

官方目前推荐这种方式,直接复制文档代码即可文档

说几个官方文档的问题点

  1. 微信端无法播放,可以使用视频解码器去解决,但很耗费性能,移动端同页面多个的情况下会卡,或者建议设计师使用矢量导出
  2. 官网使用unpkg cdn,可能被墙,所以上线项目要锁版本,并且换国内三方cdn或者放在自己服务器上

PAGInit()初始化的时候,默认会加载 libpag.js 同一目录下的 libpag.wasm 文件,所以除了.js文件,还要把其他文件下载下来放在同一目录。libpag为PAG SDK,ffavc为解码器代码。
请添加图片描述

完整demo

这个可以拿来直接用,通过iframe接入现有项目,不受技术栈的限制!!!

// 父页面 jsx
<iframe
    style={{ width: '100%', border: '0px', height: '100%' }}
    src='https://xxxx/pag.html'
    onLoad={(e)=>{
        const Iframe = e.target,
        iframeWindow= (Iframe.contentWindow || Iframe.contentDocument)
        iframeWindow.postMessage(pagsrc, '*') // 解决iframe跨域通信问题
    }}
></iframe>      
<!-- 子页面 pag.html -->
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        *{
            margin: 0;
            padding: 0;
        }
        html,body{
            height: 100%;
            overflow: hidden;
        }
        #pag{
            width: 100%;height: 100%;
        }
    </style>
</head>
<body>
    <canvas id="pag"></canvas>
    <script src="https://xxxx/libpag.min.js"></script>
    <script src="https://xxxx/ffavc.min.js"></script>
    <script>
    async function showUrl(e){
        const url = e.data
        // 实例化 PAG
        const PAG = await window.libpag.PAGInit();
        // 解码器
        const FFAVC = await window.ffavc.FFAVCInit();
        const ffavcDecoderFactory = new FFAVC.FFAVCDecoderFactory();
        PAG.registerSoftwareDecoderFactory(ffavcDecoderFactory);
        // 获取 PAG 素材数据
        const buffer = await fetch(url).then(
            (response) => response.arrayBuffer()
        );
        // 加载 PAG 素材为 PAGFile 对象
        const pagFile = await PAG.PAGFile.load(buffer);
        // 将画布尺寸设置为 PAGFile的尺寸
        const canvas = document.getElementById("pag");
        canvas.width = pagFile.width();
        canvas.height = pagFile.height();
        // 实例化 PAGView 对象
        const pagView = await PAG.PAGView.init(pagFile, canvas);
        pagView.setRepeatCount(0);
        // 播放 PAGView
        await pagView.play();
    }
    // iframe通信机制
    window.addEventListener("message", showUrl, false);
  </script>
</body>
</html>
ES Module

官方文档不完整,并且没有接入视频解码器ffavc,我是去看的github示例

需要注意的点

  1. 使用 ESModule 引入的方式需要注意,像 Webpack 和 Rollup 等打包工具是默认没有打包 .wasm 文件的。

两种解决方式

  1. 配置webpack,将.wasm文件打包到dist目录下。

  2. 初始化的时候传入locateFile参数,将文件地址传入。

    PAGInit({ locateFile: (file) => “https://pag.io/file/” + file, });

配置webpack

官网提供的是通过react-app-rewired配置的webpack,因为我已经eject暴露了配置文件,直接在webpack.config.js配置了,总体意思大差不差就是让程序找到./static/js/.wasm文件

npm i copy-webpack-plugin --save-dev
// 官网配置方式,eject就不用下载了
npm i react-app-rewired --save-dev
// webpack.config.js
const CopyWebpackPlugin = require('copy-webpack-plugin');
// plugin
plugins: [
    new CopyWebpackPlugin({
        patterns: [
          { from: path.resolve(__dirname, '../node_modules/libpag/lib/libpag.wasm'), to: './static/js/' },
          { from: path.resolve(__dirname, '../node_modules/ffavc/lib/ffavc.wasm'), to: './static/js/' }
        ],
    }),
      
    ...other
]      
完整demo
npm i libpag
// ffavc非必须根据是否需要解码器自选
npm i ffavc  
import React, {useEffect, useRef} from 'react'
import { PAGInit } from "libpag";

import { FFAVCInit } from 'ffavc';

export default function Pag(props) {
    const canvasEl = useRef(null)

    useEffect(() => {
        FFAVCInit().then((FFAVC) => {
            PAGInit().then((PAG) => {
                const ffavcDecoderFactory = new FFAVC.FFAVCDecoderFactory();
                PAG.registerSoftwareDecoderFactory(ffavcDecoderFactory);
                const url = props.src;
                fetch(url)
                  .then((response) => response.arrayBuffer())
                  .then(async (buffer) => {
                    const pagFile = await PAG.PAGFile.load(buffer);
                    const canvas = canvasEl.current;
                    canvas.width = pagFile.width();
                    canvas.height = pagFile.height();
                    const pagView = await PAG.PAGView.init(pagFile, canvas);
                    pagView.setRepeatCount(0);
                    await pagView.play();
                  });
              });
        })
    },[]);
    return (
        <canvas ref={canvasEl} style={{height:'100%',width:'100%'}}></canvas>
    )
}

需要注意的是,官方示例用的"react": "^17.0.2",react18 严格模式下(<React.StrictMode>) useEffect会执行两遍,动画初始化两遍会错乱。

结语

目前效果 pc端 > 移动端浏览器 > 移动端微信浏览器,首次加载会有些慢,项目进一步优化点在 ffavc软件解码器多个PAGView实例场景

其他问题看官方文档FAQ,先这样拜了个拜~~

Logo

更多推荐