页面组织
页面组织用于调整 PDF 文档的页面结构,包括插入、删除、移动、复制、旋转、提取、合并、替换页面,以及调整页面尺寸和页面框。福昕 PDF SDK(Web)主要通过 PDFDoc 提供这些能力。
如果使用 UIExtension,部分页面组织能力也会通过缩略图面板或相关 UI 组件提供。本文重点介绍通过 API 实现页面组织。
接口概览
| 任务 | 接口 |
|---|---|
| 获取页面信息 | getPageCount()、getPageByIndex()、PDFDoc.getAllBoxesByPageIndex();单页尺寸用 PDFPage.getWidth() / getHeight() |
| 获取单页信息 | PDFPage.getIndex()、getWidth()、getHeight()、getPageBox()、getAllBoxes()、isCropped()、isVirtual() |
| 插入空白页 | insertPage()、insertBlankPages() |
| 从 PDF 文件导入页面 | insertPages() |
| 从已打开文档合并页面 | mergePDFDoc();多来源可对目标文档多次调用,或配合 extractPages() + insertPages() |
| 删除页面 | removePage()、removePages() |
| 移动页面 | movePageTo()、movePagesTo() |
| 复制页面 | extractPages() 得到 PDF 数据后,用 insertPages() 插入到目标位置(同文档或他文档) |
| 替换页面 | removePage() / removePages() 后,用 insertPages() 或 mergePDFDoc() 写入来源页 |
| 提取页面 | extractPages() |
| 导出页面到其它文档 | extractPages() 得到 PDF 后,对目标 PDFDoc 调用 insertPages()(或先另存为文件再打开合并) |
| 旋转页面 | PDFDoc.rotatePages()、PDFPage.setRotation()、PDFPage.getRotation()、PDFPage.getRotationAngle() |
| 页面尺寸和页面框 | PDFDoc.setPagesBox()、PDFDoc.getAllBoxesByPageIndex()、PDFPage.setPageSize()、PDFPage.getPageBox()、PDFPage.getAllBoxes() |
获取当前文档
const pdfViewer = await pdfui.getPDFViewer();
const pdfDoc = pdfViewer.getCurrentPDFDoc();
if (!pdfDoc) {
throw new Error('当前没有打开文档');
}
页面范围通常使用二维数组表示。[[0]] 表示第 1 页,[[2, 4]] 表示第 3 页到第 5 页,[[0], [2, 4]] 表示第 1 页以及第 3 页到第 5 页。页面索引从 0 开始。
获取页面信息
const pageCount = pdfDoc.getPageCount();
const page = await pdfDoc.getPageByIndex(0);
// 单页逻辑尺寸(与 getWidth / getHeight 一致场景下常用)
const width = page.getWidth();
const height = page.getHeight();
// 指定页的各页面框(媒体框、裁剪框等)
const boxes = await pdfDoc.getAllBoxesByPageIndex(0);
console.log(boxes.mediaBox, boxes.cropBox);
获取到 PDFPage 后,也可以直接读取单页信息与页面框:
const pageIndex = page.getIndex();
const w = page.getWidth();
const h = page.getHeight();
// 读取某一类页面框:getPageBox(boxType),boxType 为 Box_Type 枚举,见 API Reference
const allBoxes = await page.getAllBoxes();
const isCropped = page.isCropped();
const isVirtual = page.isVirtual();
虚拟页通常不适合执行页面组织、创建表单控件、密文脱敏等会修改页面内容的操作。
插入空白页
PDFDoc.insertPage(pageIndex, width, height) 用于在指定位置插入空白页。页面尺寸单位为 point,1 英寸等于 72 point。
// 在第 1 页前插入一张 A4 尺寸空白页。
await pdfDoc.insertPage(0, 595, 842);
如果需要批量插入空白页,可以使用 insertBlankPages(pageRange, width, height)。
// 插入多张空白页。
await pdfDoc.insertBlankPages([[1, 3]], 595, 842);
从其他 PDF 导入页面
PDFDoc.insertPages(options) 用于从另一个 PDF 文件中导入页面。
await pdfDoc.insertPages({
destIndex: 1,
file,
password: '',
startIndex: 0,
endIndex: 2
});
常用参数如下:
| 参数 | 说明 |
|---|---|
destIndex | 当前文档中的插入位置。 |
file | 来源 PDF 文件,可以是 File、Blob、ArrayBuffer 等。 |
password | 来源 PDF 的打开密码,可为空。 |
startIndex | 来源 PDF 起始页索引。 |
endIndex | 来源 PDF 结束页索引。 |
flags | 导入选项,0 表示普通导入,1 表示带图层导入。 |
layerName | 带图层导入时使用的图层名称。 |
从已打开文档合并页面
如果来源文档已经加载为 PDFDoc,可以使用 mergePDFDoc(options) 将来源文档的页面合并到当前文档。
const sourceDoc = await pdfViewer.loadPDFDocByFile(sourceFile, {
password: ''
});
await pdfDoc.mergePDFDoc({
doc: sourceDoc,
insertIndex: pdfDoc.getPageCount(),
pages: [0, 1],
layerName: ''
});
pages 为空或未设置时,会导入来源文档的全部页面。insertIndex 小于等于 0 时插入到开头;未设置或大于等于当前页数时插入到末尾。
若需从多个已打开文档依次合并页面,可对当前文档多次调用 mergePDFDoc()(每次指定不同的 doc 与 pages),或先将来源文档 getFile() / extractPages() 得到 PDF 二进制,再对目标文档使用 insertPages()。
删除页面
// 删除第 1 页。
await pdfDoc.removePage(0);
// 删除多个页面范围。
await pdfDoc.removePages([[1, 3]]);
移动页面
// 将第 1 页移动到第 4 页位置。
await pdfDoc.movePageTo(0, 3);
// 将多个页面范围移动到目标位置。
await pdfDoc.movePagesTo([[0, 2]], 5);
复制和粘贴页面
SDK 还未提供单独的“剪贴板式”复制粘贴接口。实现同文档内复制若干页到另一位置时,可先 extractPages() 得到仅含选中页的 PDF 数据,再在当前文档上 insertPages() 插入该数据。
// 将第 1 页复制到第 3 页前(destIndex = 2)。extractPages 返回的临时 PDF 仅含所提取的页。
const extracted = await pdfDoc.extractPages([[0]]);
const blob = new Blob([extracted], { type: 'application/pdf' });
await pdfDoc.insertPages({
destIndex: 2,
file: blob,
password: '',
startIndex: 0,
endIndex: 0
});
若一次提取多页,临时 PDF 的页数为 insertPages 的 endIndex - startIndex + 1;可先对 extracted 使用 loadPDFDocByFile 读取 getPageCount(),或查阅 API Reference 中 extractPages / insertPages 的说明。跨文档时,对目标 PDFDoc 调用 insertPages()(file 为来源文件或上一步的 Blob),或使用 mergePDFDoc()。
旋转页面
PDFDoc.rotatePages(pageRange, rotation) 会修改 PDF 文档中的页面旋转信息,和 PDFViewer.rotateTo() 只改变视图显示不同。
// 将第 1 页到第 3 页旋转 90 度。
await pdfDoc.rotatePages([[0, 2]], 1);
rotation 使用 SDK 的页面旋转枚举值。常用值包括 0、1、2、3,分别对应 0、90、180、270 度。
如果已经拿到 PDFPage,也可以直接设置或读取单页旋转。
const page = await pdfDoc.getPageByIndex(0);
await page.setRotation(1);
const rotation = page.getRotation();
const rotationAngle = page.getRotationAngle();
提取页面
extractPages(pageRange) 可将指定页面提取为一份新的 PDF 文档流(类型以 API Reference 为准,一般为 ArrayBuffer)。不会修改当前文档。
const extracted = await pdfDoc.extractPages([[0, 2]]);
const extractedFile = new Blob([extracted], {
type: 'application/pdf'
});
导出页面到其它文档
将当前文档中的部分页“导出”到其它已打开的 PDFDoc 时,可先 extractPages(),再对目标文档调用 insertPages()(在目标位置插入临时 PDF 中的页范围)。
// 当前文档中提取第 1~2 页(索引 0、1),插入到 destDoc 末尾
const extracted = await pdfDoc.extractPages([[0, 1]]);
const blob = new Blob([extracted], { type: 'application/pdf' });
await destDoc.insertPages({
destIndex: destDoc.getPageCount(),
file: blob,
password: '',
startIndex: 0,
endIndex: 1
});
若需写入多个目标文档,对每个 destDoc 重复上述插入逻辑即可。
替换页面
SDK 还未提供单独的“就地替换”接口。可用先删除再插入或 先插入再删除 等方式组合实现:例如用来源 PDF 的若干页替换当前文档从某索引起的连续页。
// 用来源文件中的第 1 页替换当前文档的第 1 页:先删后插
await pdfDoc.removePage(0);
await pdfDoc.insertPages({
destIndex: 0,
file: sourceFile,
password: '',
startIndex: 0,
endIndex: 0
});
来源若为已打开的 PDFDoc,可先 getFile() 得到 Blob/File 再 insertPages,或使用上文 extractPages + insertPages 的流程。
设置页面尺寸和页面框
setPagesBox(options) 可调整页面尺寸、内容偏移和页面框。常用于裁剪页面、修改页面尺寸、移除白边等场景。
await pdfDoc.setPagesBox({
indexes: [0, 1],
width: 600,
height: 792,
offsetX: 40,
offsetY: 40,
boxes: {
cropBox: {
left: 0,
bottom: 0,
right: 600,
top: 792
}
}
});
读取指定页的页面框信息:
const boxes = await pdfDoc.getAllBoxesByPageIndex(0);
console.log(boxes.mediaBox, boxes.cropBox);
如果只需要去除白边,可以使用 removeWhiteMargin。
await pdfDoc.setPagesBox({
indexes: [0],
removeWhiteMargin: true
});
读取单页页面框可使用 PDFPage.getPageBox(boxType)、getAllBoxes();修改裁剪框等页面框请使用 PDFDoc.setPagesBox()(单页时传入 indexes: [pageIndex])。仅调整逻辑页面宽高时,可使用 PDFPage.setPageSize(width, height)。
const page = await pdfDoc.getPageByIndex(0);
const pageIndex = page.getIndex();
const allBoxes = await page.getAllBoxes();
console.log(allBoxes);
await pdfDoc.setPagesBox({
indexes: [pageIndex],
width: 600,
height: 792,
offsetX: 0,
offsetY: 0,
boxes: {
cropBox: {
left: 0,
bottom: 0,
right: 600,
top: 792
}
}
});
await page.setPageSize(600, 792);
getPageBox() 的 boxType 取值以 API Reference 中的 Box_Type 为准(如 Media、Crop、Trim、Art、Bleed 等)。
保存修改
页面组织操作会修改当前 PDFDoc。如需下载或上传修改后的文档,请在操作完成后调用 getFile()。
const file = await pdfDoc.getFile({
fileName: 'organized.pdf'
});
注意事项
- 页面索引从
0开始。 - 删除、移动、旋转等操作会改变文档结构,执行前建议确认用户意图。
PDFViewer.rotateTo()只改变查看器显示;如需保存页面旋转结果,应使用PDFDoc.rotatePages()。PDFPage.setRotation()适合单页旋转;PDFDoc.rotatePages()适合批量页面范围。- 调整页面框优先使用
PDFDoc.setPagesBox()(单页传入indexes: [i]即可);仅改宽高可用PDFPage.setPageSize()。 extractPages()返回 PDF 二进制数据,不会直接修改当前文档。- 使用
mergePDFDoc()时,来源PDFDoc在合并完成前应保持有效;若来源来自用户文件,也可用insertPages()避免长期持有多个文档实例。 - 处理大文档时,建议在 UI 中展示进度或禁用重复操作,避免用户连续触发页面组织任务。