OFD 书签、大纲与目录
本节介绍 OFD 文档的三类导航与目录能力:书签(Bookmarks) 用于阅读器侧栏的平面跳转列表;大纲(Outline) 为可嵌套的树形导航,支持页内跳转或 URI;目录页(Catalog) 在文档正文中插入排版好的目录页(首页或次页)。取得 OFDDoc 请参阅 OFD 文档与页面。
任务场景
- 通过
GetBookmarks/CreateBookmarks取得书签集合并枚举、添加或删除书签。 - 为书签设置名称与跳转目标(
BookmarkDestinationInfo的page_index、x_pos、y_pos)。 - 使用
CreateOutline/GetOutline构建多级大纲树,配置页内跳转(SetDestination)或外部链接(SetURI)。 - 递归遍历
Outline子节点,读取标题、动作与目标信息。 - 调用
RemoveOutline清除整棵大纲树,或RemoveOutline(index)删除单个子节点。 - 配置
Catalog的位置、边距、字体格式与目录条目,通过OFDDoc::AddCatalog插入目录页。 - 在目录页中关联
Attachments集合,实现附件列表排版;附件准备请参阅 OFD 附件。 - 变更后通过
OFDPackage::Save/SaveAs持久化。
API 概览
| 功能 | C++ API(foxit::ofd) | 核心参数 / 描述 |
|---|---|---|
| 书签集合 | OFDDoc::GetBookmarks、CreateBookmarks | 无书签时须 CreateBookmarks |
| 书签操作 | Bookmarks | GetBookmarkCount、AddBookmark、RemoveBookmark |
| 书签实体 | Bookmark | SetName / GetName;SetDest / GetDest |
| 书签目标 | BookmarkDestinationInfo | page_index(0 起)、x_pos、y_pos(OFD 坐标) |
| 大纲根 | OFDDoc::CreateOutline、GetOutline、RemoveOutline | 创建/读取/删除整棵大纲 |
| 大纲节点 | Outline | AddOutline、GetOutline、RemoveOutline;SetTitle、EnableExpanded |
| 大纲跳转 | Outline::SetDestination、SetURI | 页内坐标跳转或 URI 外链;GetDestination 返回 ActionDestinationInfo |
| 目录页 | Catalog | SetPosition、SetMargin、SetFormat、AddItemInfo、AddAttachment |
| 目录位置 | Catalog::CatalogPositionType | e_CatalogPositionTypeFirstPage(首页前插入)、e_CatalogPositionTypeSecondPage(次页前插入) |
| 写入目录页 | OFDDoc::AddCatalog | 传入配置好的 Catalog 对象 |
| 持久化 | OFDPackage::Save、SaveAs | 书签/大纲/目录变更后须包层保存 |
书签(Bookmarks)
文档级书签为平面列表(无嵌套子书签 API)。通过 Bookmarks::AddBookmark 添加条目,用 BookmarkDestinationInfo 指定目标页索引与坐标。
c++
#include "ofd/fs_ofddoc.h"
#include "ofd/fs_ofdbookmark.h"
using namespace foxit;
using namespace foxit::ofd;
bool AddBookmarks(OFDDoc& doc) {
if (doc.IsEmpty()) {
return false;
}
Bookmarks bookmarks = doc.GetBookmarks();
if (bookmarks.IsEmpty()) {
bookmarks = doc.CreateBookmarks();
}
if (bookmarks.IsEmpty()) {
return false;
}
// 添加书签并设置跳转目标
Bookmark bm = bookmarks.AddBookmark();
if (bm.IsEmpty()) {
return false;
}
bm.SetName("第一章");
BookmarkDestinationInfo dest(0, 100.0f, 200.0f); // 第 0 页,坐标 (100, 200)
return bm.SetDest(dest);
}
java
import com.foxit.sdk.ofd.Bookmark;
import com.foxit.sdk.ofd.BookmarkDestinationInfo;
import com.foxit.sdk.ofd.Bookmarks;
import com.foxit.sdk.ofd.OFDDoc;
public class OFDBookmarkExample {
public static boolean addBookmarks(OFDDoc doc) throws Exception {
if (doc.isEmpty()) {
return false;
}
Bookmarks bookmarks = doc.getBookmarks();
if (bookmarks.isEmpty()) {
bookmarks = doc.createBookmarks();
}
if (bookmarks.isEmpty()) {
return false;
}
// 添加书签并设置跳转目标
Bookmark bm = bookmarks.addBookmark();
if (bm.isEmpty()) {
return false;
}
bm.setName("第一章");
BookmarkDestinationInfo dest = new BookmarkDestinationInfo(0, 100.0f, 200.0f);
return bm.setDest(dest);
}
}
遍历已有书签并读取属性:
c++
#include "ofd/fs_ofdbookmark.h"
using namespace foxit::ofd;
void TraverseBookmarks(Bookmarks& bookmarks) {
if (bookmarks.IsEmpty()) {
return;
}
int count = bookmarks.GetBookmarkCount();
for (int i = 0; i < count; ++i) {
Bookmark bm = bookmarks.GetBookmark(i);
if (bm.IsEmpty()) {
continue;
}
String name = bm.GetName();
BookmarkDestinationInfo dest = bm.GetDest();
(void)name;
(void)dest;
}
}
java
import com.foxit.sdk.ofd.Bookmark;
import com.foxit.sdk.ofd.BookmarkDestinationInfo;
import com.foxit.sdk.ofd.Bookmarks;
public class OFDTraverseBookmarksExample {
public static void traverseBookmarks(Bookmarks bookmarks) throws Exception {
if (bookmarks.isEmpty()) {
return;
}
int count = bookmarks.getBookmarkCount();
for (int i = 0; i < count; i++) {
Bookmark bm = bookmarks.getBookmark(i);
if (bm.isEmpty()) {
continue;
}
String name = bm.getName();
BookmarkDestinationInfo dest = bm.getDest();
}
}
}
大纲(Outline)
大纲为树形结构:根节点由 CreateOutline 取得,各级子节点通过 AddOutline 添加。节点可设置页内跳转(SetDestination(page_index, x, y))或 URI(SetURI),并控制默认展开状态(EnableExpanded)。
c++
#include "ofd/fs_ofddoc.h"
#include "ofd/fs_ofdoutline.h"
using namespace foxit::ofd;
bool BuildOutlineTree(OFDDoc& doc) {
if (doc.IsEmpty()) {
return false;
}
doc.RemoveOutline(); // 可选:清除已有大纲
Outline root = doc.CreateOutline();
if (root.IsEmpty()) {
return false;
}
// 一级节点:页内跳转
Outline chapter = root.AddOutline();
chapter.SetTitle("第一章");
chapter.EnableExpanded(true);
chapter.SetDestination(0, 0.0f, 0.0f);
// 二级节点
Outline section = chapter.AddOutline();
section.SetTitle("1.1 概述");
section.SetDestination(0, 0.0f, 100.0f);
// 一级节点:URI 外链
Outline link = root.AddOutline();
link.SetTitle("官方网站");
link.SetURI("https://www.foxitsoftware.com");
return root.GetOutlineCount() > 0;
}
java
import com.foxit.sdk.ofd.OFDDoc;
import com.foxit.sdk.ofd.Outline;
public class OFDOutlineExample {
public static boolean buildOutlineTree(OFDDoc doc) throws Exception {
if (doc.isEmpty()) {
return false;
}
doc.removeOutline();
Outline root = doc.createOutline();
if (root.isEmpty()) {
return false;
}
// 一级节点:页内跳转
Outline chapter = root.addOutline();
chapter.setTitle("第一章");
chapter.enableExpanded(true);
chapter.setDestination(0, 0.0f, 0.0f);
// 二级节点
Outline section = chapter.addOutline();
section.setTitle("1.1 概述");
section.setDestination(0, 0.0f, 100.0f);
// 一级节点:URI 外链
Outline link = root.addOutline();
link.setTitle("官方网站");
link.setURI("https://www.foxitsoftware.com");
return root.getOutlineCount() > 0;
}
}
读取已保存文档的大纲树时,自根节点递归调用 GetOutline(index)。页内跳转节点可通过 GetDestination() 取得 ActionDestinationInfo(含 page_id、left、top);URI 节点使用 GetURI()。
目录页(Catalog)
Catalog 用于在文档中插入物理目录页(非侧栏导航)。配置边距、各级字体格式与目录条目后,调用 OFDDoc::AddCatalog 写入文档;可选 AddAttachment 将附件集合排版进目录。
c++
#include "ofd/fs_ofddoc.h"
#include "ofd/fs_ofdcatalog.h"
#include "ofd/fs_ofdattachment.h"
using namespace foxit;
using namespace foxit::ofd;
bool AddCatalogPage(OFDDoc& doc) {
if (doc.IsEmpty() || doc.GetPageCount() == 0) {
return false;
}
Catalog catalog;
catalog.SetPosition(Catalog::e_CatalogPositionTypeFirstPage);
catalog.SetMargin(10.0f, 15.0f); // 横向/纵向边距(毫米)
// section:章节层级(从 0 起);font_size、lower_space 单位为毫米
catalog.SetFormat(0, "SimSun", 4.0f, 2.0f);
catalog.SetFormat(1, "SimHei", 3.5f, 1.5f);
// page_count 为目标页面索引(0 至 GetPageCount()-1)
if (!catalog.AddItemInfo("前言", 0)) {
return false;
}
if (!catalog.AddItemInfo("正文", doc.GetPageCount() - 1)) {
return false;
}
// 可选:关联附件集合(须非空,参见 attachment.md)
Attachments attachments = doc.GetAttachments();
if (!attachments.IsEmpty() && attachments.GetAttachmentCount() > 0) {
catalog.AddAttachment(attachments);
}
return doc.AddCatalog(catalog);
}
java
import com.foxit.sdk.ofd.Attachments;
import com.foxit.sdk.ofd.Catalog;
import com.foxit.sdk.ofd.OFDDoc;
public class OFDCatalogExample {
public static boolean addCatalogPage(OFDDoc doc) throws Exception {
if (doc.isEmpty() || doc.getPageCount() == 0) {
return false;
}
Catalog catalog = new Catalog();
catalog.setPosition(Catalog.e_CatalogPositionTypeFirstPage);
catalog.setMargin(10.0f, 15.0f);
catalog.setFormat(0, "SimSun", 4.0f, 2.0f);
catalog.setFormat(1, "SimHei", 3.5f, 1.5f);
if (!catalog.addItemInfo("前言", 0)) {
return false;
}
if (!catalog.addItemInfo("正文", doc.getPageCount() - 1)) {
return false;
}
Attachments attachments = doc.getAttachments();
if (!attachments.isEmpty() && attachments.getAttachmentCount() > 0) {
catalog.addAttachment(attachments);
}
return doc.addCatalog(catalog);
}
}
带精确坐标的目录条目可使用 AddItemInfo(title, page_count, x, y) 重载(x、y 单位为毫米)。
保存
书签、大纲或目录页变更后须包层保存。
c++
#include "ofd/fs_ofdpackage.h"
using namespace foxit::ofd;
bool SaveNavigationChanges(OFDPackage& package, const wchar_t* output_path) {
if (package.IsEmpty()) {
return false;
}
return package.SaveAs(WString(output_path));
}
java
import com.foxit.sdk.ofd.OFDPackage;
public class OFDSaveNavigationExample {
public static boolean saveNavigationChanges(OFDPackage pkg,
String outputPath) throws Exception {
if (pkg.isEmpty()) {
return false;
}
return pkg.saveAs(outputPath);
}
}
注意事项
- 三者区别:
Bookmarks为侧栏平面书签,不占物理页面;Outline为树形大纲(可嵌套),供阅读器导航面板;Catalog会在首页或次页前插入目录页,改变页序与页数。 - 书签 vs 大纲:书签 API 仅支持文档级平面列表;需要多级嵌套导航请使用
Outline。 - 页面索引:
BookmarkDestinationInfo::page_index与Catalog::AddItemInfo的page_count均为 0 起页面索引,须满足0 ≤ index < GetPageCount();超出范围时AddCatalog可能失败。 - 坐标:书签
x_pos/y_pos使用 OFD 页面坐标;仅跳转到页顶时可设为(0.0f, 0.0f)。大纲SetDestination参数含义与书签类似,读取时GetDestination返回page_id与left/top。 - 大纲动作:URI 节点调用
SetURI后不应再依赖GetDestination;页内跳转与 URI 互斥,读取时需区分(参见发布包ofd_outline示例中的异常处理)。 - 目录格式:
SetFormat的font_name须非空,font_size与lower_space须 ≥ 0;section表示目录层级(从 0 起)。 - 目录附件:
Catalog::AddAttachment要求传入非空且含至少一个附件的Attachments对象。 - 删除大纲:
OFDDoc::RemoveOutline()删除整棵大纲;单节点删除使用Outline::RemoveOutline(index)。 - 持久化:结构变更后须
OFDPackage::Save/SaveAs;插入目录页后页码可能变化,请重新核对跳转目标与目录条目索引。