libpag 官方渲染引擎全解析:从 PAG 文件格式、跨平台集成到源码构建实战
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 是一个开源的文件格式,专门用于记录动画。动画的产出与消费链路分为三步:
- 设计师在 Adobe After Effects 中制作动效;
- 通过 PAGExporter 插件一键导出为
.pag文件(插件源码位于仓库 exporter/,支持 macOS 与 Windows 双平台); - 在 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() 播放。此外还提示了三点关键实践:
- 指定版本号:生产环境建议锁定版本(如
libpag@4.1.8)而非使用@latest; - locateFile 指定 wasm 路径:默认
libpag.wasm与libpag.js同目录,可用locateFile回调按环境区分开发/生产路径; - 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 等源码,你不仅能完成四大平台的快速接入,还能深入理解文件解码、图层树构建、文字图片替换与渲染调度的底层机制,为视频模板、动态特效等高阶场景打下扎实基础。