libpag macOS 集成实战指南:从 gen_mac 生成工程到 PAGViewer 示例解析

原创2026-10-03 17:22:541,958 阅读
文章标签:图形学音视频跨平台

libpag macOS 集成实战指南:从 gen_mac 生成工程到 PAGViewer 示例解析

导读

本文以仓库中 mac/README.md(含 中文版)为骨架,系统讲解如何在 macOS 平台将 libpag 渲染库集成到自己的项目:从环境准备、依赖同步,到使用 ./gen_mac 一键生成原生架构 Xcode 工程、按需指定架构与 CMake 编译选项,最后打开 PAGViewer.xcworkspace 运行演示。读完本文,你将掌握 libpag macOS 演示工程(pag-mac)的完整构建流程,并能从 PAGViewer 示例源码 与平台层实现(src/platform/mac)中理解 PAGView、PAGSurface、文本替换、像素缓冲渲染等核心 API 的实际用法。


一、pag-mac 是什么

pag-mac 是 libpag 仓库中一个最小化的 macOS 演示项目,其唯一目的是演示如何把 libpag 库集成进 macOS 应用。整个目录包含:

  • mac/gen_mac:Node.js 编写的工程生成脚本,负责同步依赖并调用 xcode-gen 产出 Xcode 工程;
  • mac/PAGViewer/:完整示例 App 源码,包含 AppDelegate、ViewController、DragFilePAGView(支持拖拽 .pag 文件播放)、WindowController、Info.plist、PAGViewer.entitlements、Main.storyboard 等;
  • mac/PAGViewer.xcodeproj/project.pbxproj:Xcode 工程描述文件;
  • mac/libpag.modulemap:Clang 模块映射,将 libpag 头文件暴露为 framework module libpag,内容为:
framework module libpag {
  umbrella header "libpag.h"
  export *

  module * { export * }
}

该文件是生成 libpag.framework 后供 Swift / Objective-C import libpag 使用的模块声明。libpag 的 macOS 平台接口(PAGView、PAGSurface 等)位于 src/platform/mac,平台的 Objective-C 公共头文件聚合在 src/platform/mac/libpag.h。

二、前置条件:先完成根目录环境配置

mac/README.md 明确要求:在开始构建演示项目之前,务必先仔细阅读仓库根目录的 README.md 并按其中说明配置开发环境。根 README 中与 macOS 平台强相关的关键信息包括:

  • 系统要求:macOS 12.0+;
  • 构建工具版本:Xcode 13.0+、GCC 9.0+、NodeJS 14.14.0+、Ninja 1.9.0+、CMake 3.13.0+(CLion 为官方推荐的开发 IDE,但对本演示工程非必需);
  • 依赖管理方式:libpag 使用 depsync 工具管理第三方依赖。

macOS 平台的依赖同步

在 macOS 上,直接运行仓库根目录的同步脚本即可自动安装所需工具并同步全部第三方仓库:

./sync_deps.sh

gen_mac 脚本内部其实也会自动执行 depsync(见下文源码解析),因此即使跳过手动同步,生成工程时也会触发同步流程。建议先手动执行一次,以便提前发现网络或 Git 凭据问题。

三、构建与运行:一条命令生成 Xcode 工程

在 mac/ 目录下运行(或直接双击):

./gen_mac

该命令默认生成运行在本机架构上的工程:

  • Apple Silicon Mac 上为 arm64;
  • Intel Mac 上为 x64。

指定目标架构:-a 选项

如果需要为特定架构生成工程,使用 -a 参数,例如在 Apple Silicon 上生成 x64 工程:

./gen_mac -a x64

生成的工程文件(PAGViewer.xcworkspace)位于 mac/ 目录下;仓库快照中可直接看到 mac/PAGViewer.xcodeproj/project.pbxproj,生成脚本会进一步产出工作区文件。最后启动 Xcode,打开 mac/PAGViewer.xcworkspace,即可编译运行。

透传 CMake 选项:-D 选项

gen_mac 支持通过 -D 直接透传 CMake 选项。例如生成带 WebP 编码支持的工程:

./gen_mac -DPAG_USE_WEBP_ENCODE=ON

从 CMakeLists.txt 的选项声明看,PAG_USE_WEBP_ENCODE 定义为 "Enable embedded WEBP encoding support",在 IOS/WEB 之外的平台分支(含 macOS)默认即为 ON,同时默认开启的还有 PAG_USE_PNG_DECODE/ENCODE、PAG_USE_JPEG_DECODE/ENCODE、PAG_USE_WEBP_DECODE;macOS/iOS 平台还会默认开启 PAG_BUILD_FRAMEWORK 与 PAG_USE_SYSTEM_LZ4(CMakeLists.txt)。因此 -D 主要用于按需覆盖默认值,例如关闭某项编解码能力以精简体积。其它可透传的选项(同为 CMake option 声明)还包括 PAG_USE_QT、PAG_USE_THREADS、PAG_BUILD_PAGX、PAG_BUILD_CLI 等,见 CMakeLists.txt。

四、gen_mac 脚本工作原理

mac/gen_mac 是一个 #!/usr/bin/env node 脚本,去掉 #!/usr/bin/env node 声明后全文仅十余行,核心流程如下:

process.chdir(__dirname);                 // 切换工作目录到 mac/
childProcess.execSync("depsync");         // 1. 先同步所有第三方依赖

process.argv.push("../");                 // 2. 工程根目录指向仓库根
process.argv.push("-w");                  //    以 workspace 模式生成
if (args.indexOf("-p") === -1 && args.indexOf("--platform") === -1) {
    process.argv.push("-p");              // 3. 未显式指定平台时
    process.argv.push("mac");             //    默认平台为 mac
}
require("../third_party/vendor_tools/xcode-gen");  // 4. 调用 xcode-gen 生成工程

要点解读:

  1. depsync 自动执行:gen_mac 内部会先运行 depsync,保证 third_party/vendor_tools 等依赖目录存在,这也解释了为什么直接双击 gen_mac 也能工作;
  2. 平台默认值:未传 -p/--platform 时默认 mac(ios/gen_ios 脚本结构完全相同,仅默认平台为 ios,可对比 ios/gen_ios);
  3. 透传机制:命令行中的 -a、-D 等参数会被原样追加进 process.argv 传给 xcode-gen,由其在生成 CMake 配置时转换为对应的架构与 CMake 选项。

五、示例工程源码解析

5.1 ViewController:加载、循环播放与文本替换

mac/PAGViewer/ViewController.m 是演示 App 的核心控制器,展示了 libpag macOS 最常用的三段式用法:

DragFilePAGView *view = [[DragFilePAGView alloc] initWithFrame:self.view.bounds];
NSString *path = [[NSBundle mainBundle] pathForResource:@"test2" ofType:@"pag"];
[view setPath:path];          // 从 Bundle 加载 .pag 文件
[view setRepeatCount:-1];     // 负值表示无限循环播放
[view play];                  // 开始播放

其中 setRepeatCount: 传入 -1 表示无限循环,这与 src/platform/mac/PAGView.h 中的注释一致:默认播放 1 次,设为 0 或负数则无限播放。

随后演示了运行时文本编辑——libpag 的核心能力之一:

PAGFile* pagFile = (PAGFile*)[view getComposition];
if ([pagFile numTexts] > 0) {
    PAGText* textData = [pagFile getTextData:0];
    textData.fontSize = textData.fontSize*0.5;      // 字号减半
    textData.text = @"运动文字遮罩替换😀文本";        // 替换文案
    [pagFile replaceText:0 data:textData];          // 写回文件
}

即:通过 getComposition 拿到 PAGFile,读取第 0 个文本的 PAGText 数据,修改字号与内容后调用 replaceText:data: 写回。所有编辑均基于原动画的图层结构,无需重新导出素材。

5.2 PixelBuffer 模式:离屏渲染与截图

ViewController.m 中还保留了一个被注释掉的 testPixelBufferMode 方法(//[self testPixelBufferMode];),演示不依赖 PAGView 的纯离屏渲染链路:

PAGSurface *pagSurface = [PAGSurface MakeOffscreen:CGSizeMake(pagFile.width, pagFile.height)];
PAGPlayer *pagPlayer = [[PAGPlayer alloc] init];
[pagPlayer setComposition:pagFile];
[pagPlayer setSurface:pagSurface];
// ... [pagFile replaceImage:0 data:pagImage]; 替换素材
[pagPlayer setProgress:0.5f];   // 定位到 50% 进度
[pagPlayer flush];              // 渲染一帧
CVPixelBufferRef result = [pagSurface makeSnapshot];  // 取回像素缓冲

核心链路为:PAGSurface MakeOffscreen: 创建离屏表面 → PAGPlayer 绑定 composition 与 surface → setProgress: 定位 → flush() 渲染 → makeSnapshot 导出 CVPixelBufferRef。这一模式适合视频模板类业务:替换图片(replaceImage:data:,图片来自 PAGImage FromPixelBuffer:)后逐帧渲染输出。

5.3 DragFilePAGView:拖拽 .pag 文件播放

mac/PAGViewer/DragFilePAGView.m 继承自 PAGView,仅实现 macOS 拖拽协议:

  • initWithFrame: 中注册 NSPasteboardTypeFileURL 拖拽类型;
  • draggingEntered: 返回 NSDragOperationCopy 接受拖入;
  • prepareForDragOperation: 从 NSPasteboard 读取 NSURL 列表,取最后一个 URL 的 path 调用 [self setPath:] 完成换文件播放。

由此,运行演示 App 后可直接把任意 .pag 文件拖入窗口即时预览,非常适合设计师与开发者联调。

六、PAGView 与 macOS 平台层实现

演示工程底层依赖的 PAGView 是 libpag 面向 macOS 的高层播放视图,其完整接口定义在 src/platform/mac/PAGView.h,实现位于 src/platform/mac/PAGView.mm,关键点:

  • 监听器协议 PAGViewListener:提供 onAnimationStart、onAnimationEnd、onAnimationCancel、onAnimationRepeat、onAnimationUpdate 五个可选回调,均只在 UI 线程调用;PAGView 对监听器只持有弱引用;
  • 播放控制:play / pause / stop / isPlaying / repeatCount,其中 play 在已播放时无副作用,动画到达终点后再次 play 会从头开始;
  • 文件加载:setPath: 按路径加载 .pag,内部有缓存——同一路径加载的所有 PAGFile 共享内部缓存,缓存存活到所有 PAGFile 释放为止(注释中提示可用 [PAGFile Load:size:] 绕过缓存);
  • 实现细节:PAGView 组合了 PAGPlayer + PAGSurface + PAGAnimator,initPAG 中强制 [animator setSync:YES](否则内部 surface 无法创建),并在 bounds/frame 变化时调用 [pagSurface updateSize] 自适应视图尺寸。

平台目录 src/platform/mac 还包含 GPU 绘制(GPUDrawable)、硬件解码(HardwareDecoder)、基于 CVDisplayLink 的 NativeDisplayLink 动画驱动等底层实现,PAGSurface 的 macOS 封装(PAGSurface.h / PAGSurface.m)则承载离屏与 GPU 表面的创建逻辑——这也正是 5.2 节离屏渲染链路能工作的原因。

七、常见问题与排查建议

  1. depsync 失败 / 同步卡住:gen_mac 首步会执行 depsync,需要 Node.js 14.14.0+;根 README 建议启用 git-credential-store,否则同步过程中可能反复要求输入 Git 账号密码;
  2. 架构不匹配:在 Apple Silicon 上若需在模拟/转译环境运行 x64 产物,请显式使用 ./gen_mac -a x64,反之亦然;默认行为是跟随本机架构(arm64 / x64);
  3. 打开的是 xcodeproj 而非 xcworkspace:文档指向 mac/PAGViewer.xcworkspace;仓库快照中已包含 mac/PAGViewer.xcodeproj/project.pbxproj,生成脚本以 -w 模式运行时会在构建阶段产出 workspace,若未生成可检查 third_party/vendor_tools/xcode-gen 是否随 depsync 同步完整;
  4. CMake 选项不生效:-D 选项是透传给 xcode-gen 再写入 CMake 配置的,可对照 CMakeLists.txt 中的 option(...) 声明确认选项名拼写(如 PAG_USE_WEBP_ENCODE),注意 macOS 上多数编解码选项默认即为 ON,-D 主要用于覆盖默认值。

结语

pag-mac 演示工程以最小代价展示了 libpag 在 macOS 上的完整接入路径:gen_mac 一条命令完成依赖同步与工程生成,-a 控制架构、-D 透传 CMake 选项;示例代码则覆盖了从 PAGView 播放、无限循环、运行时文本替换,到离屏 PixelBuffer 渲染与文件拖拽预览等核心场景。以此为起点,你可以在自己的 macOS 应用中通过 #import <libpag/PAGView.h> 等头文件直接接入 PAGView,快速落地 PAG 动画播放与编辑能力。

登录后查看全文
libpag