libpag 官方渲染引擎全解析:从 PAG 文件格式、跨平台集成到源码构建实战

原创2026-10-03 13:27:421,208 阅读
文章标签:图形学音视频跨平台

libpag 官方渲染引擎全解析:从 PAG 文件格式、跨平台集成到源码构建实战

PAG(Portable Animated Graphics,便携式动画图形)是一种开源的动画记录文件格式,而 libpag 正是其官方实时渲染引擎。本指南以仓库根目录 README.md 为骨架,结合仓库内的核心源码(include/pag/、src/rendering/、CMakeLists.txt、DEPS)与配套工具文档(exporter/README.md、web/README.md),完整讲解 PAG 的格式特性与优势、iOS/Android/OpenHarmony/Web 四大平台的集成方式、可编辑动画的核心 API,以及从源码构建 libpag 的完整工程流程,帮助你快速上手并深入理解这套跨平台动画方案。

一、PAG 与 libpag:理解这套动画体系的定位

1.1 什么是 PAG 文件

PAG 是一个开源的文件格式,专门用于记录动画。动画的产出与消费链路分为三步:

  1. 设计师在 Adobe After Effects 中制作动效;
  2. 通过 PAGExporter 插件一键导出为 .pag 文件(插件源码位于仓库 exporter/,支持 macOS 与 Windows 双平台);
  3. 在 PAGViewer 桌面应用中预览效果(对应仓库 viewer/ 与 mac/、win/ 下的播放器工程)。

也就是说,libpag 负责"播放"环节——它是一个 PAG 文件的实时渲染库,能够同时渲染基于矢量(vector-based)和基于光栅(raster-based)的动画。

1.2 libpag 的跨平台覆盖

从 README.md 的 Introduction 可知,libpag 支持渲染的动画可在以下平台运行:

平台 说明
iOS 通过 CocoaPods 或 framework 集成
Android 通过 Maven AAR 集成
OpenHarmony 通过 OHPM HAR 集成
macOS / Windows / Linux 需从源码构建
Web 基于 WebAssembly + WebGL 的 SDK

仓库 web/README.md 进一步说明:Web 端 SDK 使用 WebAssembly 与 WebGL 构建,支持 PAG 的全部特性,并将 Wasm 模块的 JS 胶水代码与 .wasm 二进制拆分为 libpag.js 与 libpag.wasm 两个文件分发。

1.3 系统要求一览

根据 README.md 的 System Requirements 章节,各平台的最低运行版本为:

  • iOS 15.0+
  • Android 5.0+
  • HarmonyOS Next 5.0.0(12)+
  • macOS 12.0+
  • Windows 7.0+
  • Chrome 69.0+(Web)
  • Safari 15.0+(Web)

需要注意,README 声明当前只针对 iOS、Android、macOS、Web 与 OpenHarmony 发布预编译库,其他平台(如 Windows、Linux)需要从源码自行构建,具体构建方式见本文第五章。

二、PAG 的核心优势:为什么值得选择

README.md 的 Advantages 章节从四个维度阐述了 PAG 的设计理念,这里结合仓库源码逐一解读。

2.1 高效的文件格式:解码更快、体积更小

受益于高效的二进制格式设计,官方文档给出的对比数据为:PAG 文件解码速度约为 JSON 文件的 10 倍,同等动画的文件体积约小 50%。同时,设计者可以轻松地把位图或音视频媒体打包进单个 PAG 文件,无需额外附件。

仓库 src/codec/ 下的 Codec.cpp、TagHeader.cpp 以及 src/codec/tags/ 中上百个 tag 解析器(71 个 .h + 71 个 .cpp)正是这套二进制编解码体系的具体实现,每个动画属性对应独立的 tag 读写逻辑,从而避免了 JSON 文本解析的开销。

2.2 全量 AE 特性支持:矢量 + 光栅混合导出

其他方案往往只能导出有限的矢量 AE 特性,而 PAG 将矢量导出与光栅导出(BMP pre-composition)两种技术结合,可以在单个文件中支持全部 AE 动画——这意味着 AE 中的第三方插件效果也能被导出。

exporter/README.md 对导出策略有更精确的描述:

  • 纯矢量导出(Pure Vector Export):将 AE 合成导出为纯矢量文件,体积小、可无限缩放;
  • 混合导出(Hybrid Export):将 BMP 预合成与矢量结合,在支持全部 AE 特性的同时保持运行时可编辑性。

2.3 可量化的性能:PAGViewer 监控面板

PAGViewer 内置一个监控面板,显示 PAG 文件的归一化性能数据,让设计师无需开发人员介入即可审查和优化性能。PAGExporter 插件还内置大量自动优化技术。

2.4 运行时可编辑动画:视频模板类业务的利器

通过 PAG SDK 灵活的编辑 API,开发者可以:

  • 修改单个 PAG 文件的图层结构;
  • 将多个 PAG 文件组合进一个合成(composition);
  • 在运行时替换文字与图片,且所有预设动画效果自动生效。

这能显著减少视频模板类功能的编码工作量。第四章节将结合 PAGFile 源码详细展开这套编辑能力。

三、快速集成指南:四大平台接入实操

3.1 iOS:CocoaPods 集成

在 Podfile 中加入依赖并安装:

pod 'libpag'

然后执行:

pod install

安装完成后在代码中引入头文件:

#import <libpag/xxx.h>

除此之外,也可以直接从官方发布页下载 framework 手动集成。仓库 ios/ 与 mac/ 目录下提供了 PAGViewer 的 Xcode 工程以及 libpag.lds、libpag.modulemap 等打包配置。

3.2 Android:Maven + ProGuard

首先在项目根目录的 build.gradle 的 repositories 中加入 mavenCentral():

buildscript {
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:3.2.1'
    }
}

然后在 app/build.gradle 的 dependencies 中加入 libpag(4.0.5.10 应替换为最新发布版本):

dependencies {
    implementation 'com.tencent.tav:libpag:4.0.5.10'
}

为防止混淆导致的运行错误,需要在 proguard 规则中添加:

  -keep class org.libpag.** {*;}
  -keep class androidx.exifinterface.** {*;}

最后执行 gradle sync 并构建项目。仓库中 android/libpag/src/main/java/org/libpag/ 下的 PAGFile.java、PAGView.java(继承自 TextureView)等 48 个 Java 文件即为 Android 封装层。

3.3 OpenHarmony:OHPM 集成

可以通过 OHPM 直接安装:

ohpm install @tencent/libpag

也可以手动添加到应用模块的 oh-package.json5 中:

"dependencies": {
"@tencent/libpag": "^1.0.1",
}

然后运行:

ohpm install

仓库 ohos/libpag/ 提供了完整的 OpenHarmony 封装(31 个 .ets 文件)与 export.def、Index.ets 等工程文件。

3.4 Web:script 标签 + PAGInit

将以下代码复制进 HTML 文件并在浏览器打开即可运行:

<canvas class="canvas" id="pag"></canvas>
<script src="https://unpkg.com/libpag@latest/lib/libpag.min.js"></script>
<script>
  window.libpag.PAGInit().then((PAG) => {
    const url = 'https://pag.io/file/like.pag';
    fetch(url)
      .then((response) => response.blob())
      .then(async (blob) => {
        const file = new window.File([blob], url.replace(/(.*\/)*([^.]+)/i, '$2'));
        // Do Something.
      });
  });
</script>

web/README.md 给出了更完整的可运行示例:PAGInit() 初始化 Wasm 模块 → PAG.PAGFile.load(buffer) 加载文件 → 依据文件尺寸设置 canvas → PAG.PAGView.init(pagFile, canvas) 创建视图 → pagView.play() 播放。此外还提示了三点关键实践:

  1. 指定版本号:生产环境建议锁定版本(如 libpag@4.1.8)而非使用 @latest;
  2. locateFile 指定 wasm 路径:默认 libpag.wasm 与 libpag.js 同目录,可用 locateFile 回调按环境区分开发/生产路径;
  3. ESModule 场景需手动托管 wasm:常见打包工具会忽略 .wasm 文件,必须用 locateFile 指向自行上传服务器的 wasm 地址。

完整接入细节见 Web SDK Guide。

3.5 官方示例与 API 文档

README 提供了三个官方示例仓库(pag-ios / pag-android / pag-web)分别演示对应平台的 API 用法,并给出 iOS、Android、Web 三端的 API Reference 入口。仓库自身也附带了大量可直接运行的测试用例,例如 test/src/PAGFileTest.cpp 覆盖了 numTexts、numImages 等文件查询接口的断言(如 ASSERT_EQ(TestFile->numTexts(), 2)、ASSERT_EQ(TestFile->numImages(), 2))。

四、运行时编辑:从源码理解 PAG 核心 API

include/pag/pag.h 是 libpag 的 C++ 公共头文件,定义了 PAGImage、PAGFile、PAGComposition、PAGSurface、PAGPlayer 等核心类。本节聚焦运行时编辑能力背后的 API 设计与实现。

4.1 PAGFile:加载与可编辑性查询

PAGFile 继承自 PAGComposition(include/pag/pag.h),其核心职责是把磁盘/内存中的 PAG 二进制解码为可播放、可编辑的图层树。两个静态加载入口:

static std::shared_ptr<PAGFile> Load(const void* bytes, size_t length,
                                     const std::string& filePath = "");
static std::shared_ptr<PAGFile> Load(const std::string& filePath);

其底层实现位于 src/rendering/layers/PAGFile.cpp:先通过 File::Load 解析二进制文件,再由 BuildPAGLayer 按图层类型(Solid/Text/Shape/Image/PreCompose)递归构建 PAGLayer 对象树,最后回拨 gotoTime(0) 完成首帧定位。

Android 端 PAGFile.java 进一步提供了多形态的重载:

  • Load(String path):支持本地路径;若以 http:// 或 https:// 开头则视为网络 URL,此时必须在工作线程调用,否则可能抛出 NetworkOnMainThreadException;
  • LoadAsync(String path, LoadListener):异步加载,可在 UI 线程安全调用;
  • Load(byte[] bytes):从字节数组加载,绕过内部缓存;
  • Load(AssetManager manager, String fileName):直接从 assets 资源加载。

注意:同一路径加载的所有 PAGFile 共享内部缓存,缓存存活到所有 PAGFile 被释放;若文件内容可能变化,应改用 Load(byte[])。

可编辑性通过以下查询接口暴露(Android 与 C++ 接口一一对应):

  • numTexts() / numImages() / numVideos():返回可替换文字、图片与视频合成的数量;
  • getTextData(editableTextIndex):获取指定索引的默认文本数据;
  • getEditableIndices(LayerType):返回可编辑图层的索引集合,未出现在集合中的图层不应被当作可编辑对象;
  • tagLevel() / MaxSupportedTagLevel():文件所需 tag 级别与当前 SDK 支持的最高级别,用于版本兼容判断。

4.2 文字与图片替换:让模板动起来

替换操作是视频模板类业务的基石,PAGFile 提供:

void replaceText(int editableTextIndex, std::shared_ptr<TextDocument> textData);
void replaceImage(int editableImageIndex, std::shared_ptr<PAGImage> image);
void replaceImageByName(const std::string& layerName, std::shared_ptr<PAGImage> image);

传入 nullptr 会将对应内容重置为默认值。其中 PAGImage 的构造支持四种数据来源(include/pag/pag.h):

  • FromPath(const std::string& filePath):从图片文件路径创建;
  • FromBytes(const void* bytes, size_t length):从文件字节创建;
  • FromPixels(pixels, width, height, rowBytes, colorType, alphaType):从原始像素数据创建;
  • FromTexture(const BackendTexture&, ImageOrigin):从 GPU 后端纹理创建。

PAGImage 还内置了 PAGScaleMode scaleMode() / setScaleMode() 与 Matrix matrix() / setMatrix() 用于控制替换内容在图层内的呈现方式(详见 4.4 节)。

4.3 渲染链路:PAGSurface 与 PAGPlayer

播放与渲染由 PAGPlayer 与 PAGSurface 协作完成:

  • PAGSurface 提供多种 MakeFrom 工厂方法,支持从 Drawable、BackendRenderTarget、BackendTexture 创建表面;从纹理创建时若传入 forAsyncThread = true,内部会创建独立 GPU 上下文,配合信号量(flushAndSignalSemaphore() / wait())实现异步渲染同步;
  • PAGPlayer 承担合成调度:setComposition() 绑定 PAGComposition,setProgress() / nextFrame() 控制播放进度,flush() 将当前帧绘制到 Surface。

test/src/AsyncDecodeTest.cpp 展示了典型用法:TestPAGPlayer->setComposition(pagFile) → setProgress(0.5) → flush(),并通过检查 renderCache->sequenceCaches 的大小验证异步解码的缓存行为,可以作为二次开发的参考样板。

4.4 缩放模式与时间伸缩模式

替换图片与设置时长时会用到两组枚举,均定义在 include/pag/types.h。

PAGScaleMode(include/pag/types.h)定义内容如何缩放以适配目标区域:

取值 行为
None 内容不缩放
Stretch 拉伸以完全填充
LetterBox 保持宽高比缩放以完整容纳(默认值)
Zoom 保持宽高比缩放以填满,单轴会被裁剪

PAGTimeStretchMode(include/pag/types.h)定义文件时长被改变时如何拉伸时间轴:

取值 行为
None 保持原播放速度,内容时长不足时定格在最后一帧
Scale 改变播放速度以适配目标时长
Repeat 保持原速,内容时长不足时循环播放(默认模式)
RepeatInverted 保持原速,内容时长不足时倒序循环播放

PAGFile 上的 setDuration() 配合 timeStretchMode() 即可在运行时调整整段动画的时长,这在"进度条、倒计时、循环背景"等场景中非常实用。

五、从源码构建 libpag:工程环境与构建流程

5.1 分支管理与版本策略

README 明确了两类分支的职责:

  • main 分支:活跃开发分支,包含最新特性与缺陷修复;
  • release/ 分支:稳定里程碑分支,会定期从 main 创建 release/{version},创建后仅合入高优先级修复。

重要提示:本仓库只包含 PAG 4.0 以来的最新代码;PAG 3.0 的旧版本需要通过官方发布页下载预编译库。

5.2 构建前置条件

各平台构建工具链的最低版本要求如下(来自 README 的 Build Prerequisites):

工具 版本要求
Xcode 13.0+
GCC 9.0+
Visual Studio 2019+
NodeJS 14.14.0+
Ninja 1.9.0+
CMake 3.13.0+
QT 6.2.0+
NDK 28+(官方推荐 28.0.13004108)
Emscripten 3.1.58+

5.3 依赖管理:depsync 工具

libpag 使用 depsync 工具管理第三方依赖,依赖清单集中在仓库根目录的 DEPS 文件中。该文件以 repos 字段声明了十余个第三方仓库及其锁定 commit,例如:

  • tgfx:PAG 底层的跨平台图形引擎(仓库根目录另有 tgfx/,并在 DEPS 中锁定到 third_party/tgfx);
  • libavc:作为视频解码回退方案的 H.264 编解码库;
  • rttr:C++ 反射库,服务于运行时类型系统;
  • harfbuzz、SheenBidi、libxml2、lz4、woff2、libyuv、expat 等:分别服务于文本整形、双向文本布局、XML 解析、压缩、字体子集化与像素格式转换。

macOS 平台,在项目根目录执行:

./sync_deps.sh

该脚本会自动安装必要工具并同步所有第三方仓库。

其他平台,先确保安装最新版 Node.js(可能需要重启电脑),然后全局安装 depsync:

npm install -g depsync

再到项目根目录执行:

depsync

同步过程中可能需要输入 Git 账号密码,建议启用 git-credential-store,这样后续 CMakeList.txt 可以自动触发同步。

5.4 CMake 构建选项:按需裁剪功能

仓库根目录 CMakeLists.txt 定义了一系列构建开关,从源码构建时可根据目标平台和功能需求裁剪:

CMake 选项 默认值 作用
PAG_USE_OPENGL ON 允许使用 OpenGL 作为 GPU 后端
PAG_USE_SWIFTSHADER OFF 是否构建 SwiftShader 软件渲染库
PAG_USE_ANGLE OFF 是否构建 ANGLE 库
PAG_USE_QT OFF 是否构建 Qt 框架支持
PAG_USE_RTTR OFF 是否启用 RTTR 反射支持
PAG_USE_HARFBUZZ OFF 是否启用 HarfBuzz 文本整形
PAG_USE_C OFF 是否启用 C API 封装
PAG_BUILD_PAGX OFF 是否启用 PAGX 格式支持
PAG_BUILD_CLI OFF 是否构建命令行工具
PAG_BUILD_SVG / PAG_BUILD_HTML / PAG_BUILD_PPT OFF 是否启用 SVG/HTML/PPT 导入导出
PAG_USE_THREADS ON 是否支持多线程渲染(非 Web 或 pthread 构建时可用)

此外还按平台细分了编解码选项:iOS/Web 默认启用 PAG_USE_WEBP_DECODE,Android 默认启用 PAG_USE_FFAVC 回退解码器,非 OHOS 平台默认启用 PNG/JPEG/WEBP 的嵌入编解码支持;macOS/iOS 下 PAG_BUILD_FRAMEWORK 默认为 ON,其他平台默认关闭。

5.5 CLion 构建指引

依赖同步完成后,用 CLion 打开项目即可构建 PAG 库。

  • macOS:无需额外 CLion 配置;
  • Windows:需要先安装 VS2019 的 [Desktop development with C++] 与 [Universal Windows Platform development] 两个组件,然后在 CLion 的 File → Settings → Build, Execution, Deployment → Toolchains 中将工具链设为 Visual Studio,架构选择 **amd64(推荐)**或 x86。

如果 CMake 构建过程遇到问题,请升级到最新版 CMake 命令行工具后重试。

六、生态配套与许可证

6.1 PAGExporter:AE 一键导出插件

exporter/README.md 详述了 PAGExporter 的能力:它是 Adobe After Effects 插件,让设计师一键把 AE 动效导出为 PAG 文件,支持纯矢量/混合导出、AE 内实时预览、面板批量导出、不支持特性校验警告以及 PAGViewer 一键安装。其源码依赖 Qt 6.2.0+ 与 After Effects SDK 构建,exporter/ 下的 aecommand/、export/、ui/、utils/ 等模块即插件的命令分发、导出核心与界面实现。

6.2 PAGViewer:桌面预览与性能审查

仓库 viewer/、mac/PAGViewer、ios/PAGViewer 提供了跨平台查看器,集成了音频、编辑、渲染、性能剖析(viewer/src/profiling/)等模块,配合内置监控面板完成性能数据审查。

6.3 开源许可证

libpag 基于 Apache Version 2.0 License 开源(见 LICENSE.txt)。README 还特别说明:仓库中腾讯代码的版权声明此前登记在已注销的 "THL A29 Limited" 实体名下,后续所有分发副本应视为版权归属于 "Tencent"。使用 SDK 时应参照官方隐私政策,参与贡献前请阅读 CONTRIBUTING.md。

结语

从 README.md 出发可以看到,libpag 的价值在于一整套闭环:PAGExporter 负责生产、PAG 二进制格式负责高效存储、libpag 渲染引擎负责跨平台播放、运行时编辑 API 负责业务定制。结合 include/pag/pag.h、src/rendering/layers/PAGFile.cpp 与 CMakeLists.txt 等源码,你不仅能完成四大平台的快速接入,还能深入理解文件解码、图层树构建、文字图片替换与渲染调度的底层机制,为视频模板、动态特效等高阶场景打下扎实基础。

登录后查看全文
libpag