如何在 C++ 中处理 PDF 文档
Aspose.PDF FOSS for C++ 是一个采用 MIT 许可证、无依赖的 C++20 库,使用 CMake 构建并链接 —— 无需添加包管理器导入。本指南将演示以 Document 为中心的核心工作流:打开已有的 PDF,检查其页面和元数据,提取文本,并将页面渲染为光栅图像。
分步指南
步骤 1:安装包
克隆仓库并将其作为子目录添加到你的 CMake 项目中:
git clone https://github.com/aspose-pdf-foss/Aspose.PDF-FOSS-for-Cpp.gitadd_subdirectory(Aspose.PDF-FOSS-for-Cpp)
target_link_libraries(your_app PRIVATE aspose_pdf_foss)或者单独配置并构建它:
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build通过针对头文件编译一个最小示例程序来验证工具链是否解析成功:
#include <aspose/pdf/document.hpp>
#include <iostream>
int main() {
Aspose::Pdf::Document doc;
std::cout << "Linked OK - pages: " << doc.Pages().Count() << "\n";
}一次成功的构建在新构建的空 Document 上打印 pages: 0,表明库已正确链接。
步骤 2:导入所需类
#include <aspose/pdf/document.hpp>
#include <aspose/pdf/document_info.hpp>
#include <aspose/pdf/page.hpp>
#include <aspose/pdf/page_collection.hpp>
#include <aspose/pdf/text_absorber.hpp>
#include <aspose/pdf/bmp_device.hpp>
#include <aspose/pdf/resolution.hpp>
#include <fstream>
#include <iostream>步骤 3:打开 PDF 文档并统计其页数
从文件路径构造一个 Document 以打开现有的 PDF。Document::Pages() 返回 PageCollection,而 Count() 报告它包含的页数:
Aspose::Pdf::Document doc("input.pdf");
std::cout << "Page count: " << doc.Pages().Count() << "\n";步骤 4:读取文档元数据
Document::Info() 返回一个带有标准 /Info 字典条目类型化读/写访问器的 DocumentInfo 对象:
auto& info = doc.Info();
std::cout << "Title: " << info.Title() << "\n";
std::cout << "Author: " << info.Author() << "\n";
std::cout << "Producer: " << info.Producer() << "\n";步骤 5:从页面提取文本
Aspose::Pdf::Text::TextAbsorber 遍历一个 Document 或单个 Page 并累积遇到的文本;Text() 随后返回结果。PageCollection 为从 1 开始计数,因此 Pages()[1] 为第一页:
auto page = doc.Pages()[1];
Aspose::Pdf::Text::TextAbsorber absorber;
absorber.Visit(page);
std::cout << absorber.Text() << "\n";Visit() 也可以直接接受整个 Document(absorber.Visit(doc)),当您希望将每页的文本连接在一起而不是单页时。
步骤 6:将页面渲染为光栅图像
BmpDevice 将 Page 渲染为未压缩的 BMP 图像。它的构造函数接受一个 Resolution,用于控制输出 DPI,Process() 将渲染后的字节写入任何 std::ostream:
Aspose::Pdf::Devices::BmpDevice device(Aspose::Pdf::Devices::Resolution(150));
std::ofstream imageOut("page1.bmp", std::ios::binary);
device.Process(page, imageOut);步骤 7:更新元数据并保存文档
对 DocumentInfo 的 setter 会暂存更改,这些更改会在下次 Save() 在所属的 Document 上运行时被刷新:
doc.Info().Title("Processed by Aspose.PDF FOSS for C++");
doc.Save("output.pdf");常见问题及解决方案
Accessing Pages()[0] throws std::out_of_range
PageCollection 使用 1 基索引,符合规范的 Aspose.PDF 语义——第一页是 Pages()[1]。索引小于 1 或大于 Count() 会抛出错误。
TextAbsorber::Text() 返回一个空字符串
Text() 返回最近一次 Visit() 调用累计的内容。请确认在读取 Text() 之前已实际调用了 Visit(),并且您访问的页面或文档包含可提取的文本,而不是仅有的扫描图像。
渲染出的 BMP 文件异常小或呈空白
较低的 Resolution 值会生成小尺寸的光栅图像。提高传递给 Resolution 的 DPI——例如,使用 Resolution(300) 以获得打印质量输出——并确认传递给 Process() 的页面索引是您所期望的。
DocumentInfo 字段读取回来的都是空字符串
并非所有 PDF 生成器都会写入标准的 /Info 条目。在假设元数据提取失败之前,请检查 Producer() 和 Creator() 是否为空值——空字符串是缺失键的定义结果。
使用…进行的更改 Info().Title(...) 未出现在已保存的文件中
DocumentInfo 变更在内存中暂存,仅在下次 Save() 在同一 Document 实例上运行时才会持久化。确保元数据编辑在 Save() 之前进行,而不是之后。
常见问题
在 Aspose.PDF FOSS for C++ 中,页面索引是从零开始还是从一开始?
从一开始。doc.Pages()[1] 始终是第一页。
TextAbsorber 能否仅从单页提取文本,而不是整个文档?
是的。Visit() 被重载以接受 Document — 这会提取每页的文本 — 或者单个 Page,仅提取该页的文本。
如果我仅从文档读取数据,是否需要调用 Save()?
不。Save() 仅在需要将更改写回文件时才必需,例如编辑 DocumentInfo 字段。读取页面计数、提取文本或渲染页面并不会修改文档。
我如何控制渲染页面的分辨率?
将 Resolution 值传递给设备的构造函数——例如,Resolution(150) 表示 150 DPI。更高的值会生成更大、保真度更高的栅格图像。
BmpDevice 生成什么格式?
未压缩的 BMP 图像直接写入传递给 Process() 的 std::ostream。