ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

MuPDF JavaScript OutlineIterator 完全指南:遍历、查询与编辑文档书签

2026/10/5 15:06:35 拓冰建站 浏览量
MuPDF JavaScript OutlineIterator 完全指南:遍历、查询与编辑文档书签 图形学图像处理【免费下载链接】mupdfmupdf mirror项目地址https://gitcode.com/gh_mirrors/mu/mupdf点击查看免费下载OutlineIterator是 MuPDF JavaScript 绑定中用于**遍历、查询和编辑文档大纲Outline**的核心游标式接口。在 PDF 语境下文档大纲即目录Table of Contents或书签Bookmarks。通过Document.prototype.outlineIterator()获得实例后你可以在大纲树中上下左右移动游标、读取当前条目、以及在任意位置插入、删除或更新条目从而在不重建文档的情况下完成书签级编辑。读完本文你将掌握 OutlineIterator 的全部导航返回码、样式标志位、每个实例方法的语义与典型用法并了解其背后的 C 层实现fz_outline_iterator与 WASM 绑定代码。背景MuPDF 的大纲系统与迭代器设计MuPDF 的大纲Outline是一棵树每个节点包含标题title、跳转目标uri/page、展开状态is_open与样式标志flags。C 层的数据结构定义在 include/mupdf/fitz/outline.hfz_outline是基于结构体的只读树形 API通过fz_load_outline一次性整体加载fz_outline_iterator是基于游标的 API适合需要定位 修改的场景例如在某个同级列表的末尾插入新书签。两者可以互相转换fz_load_outline_from_iterator负责把迭代器内容还原成结构体树。JavaScript 层的Document.loadOutline()返回嵌套的OutlineItem[]数组只读视图而outlineIterator()返回可移动、可编辑的OutlineIterator实例。因此需要修改书签时应使用迭代器需要一次性读取整棵树时使用 loadOutline。在 WASM 绑定 platform/wasm/lib/mupdf.ts 中OutlineIterator被实现为Userdatafz_outline_iterator其内存生命周期由_wasm_drop_outline_iterator管理outlineIterator() { return new OutlineIterator(libmupdf._wasm_new_outline_iterator(this.pointer)) } export class OutlineIterator extends Userdatafz_outline_iterator { static override readonly _drop libmupdf._wasm_drop_outline_iterator // ... }获取实例OutlineIterator没有公开构造函数文档标注为|no_new|实例只能通过Document.prototype.outlineIterator()获得var doc new mupdf.Document(pdfData); // 以 PDF 数据打开文档 var iter doc.outlineIterator();C 层对应的创建入口是fz_new_outline_iterator/fz_new_outline_iterator_of_size见 source/fitz/outline.c 与 include/mupdf/fitz/outline.h。该迭代器由文档驱动每个文档类型提供自己的迭代器实现因此拿到实例后即可直接使用无需手动释放——绑定层的引用计数与 drop 机制会自动处理。常量Constants导航返回码next()、prev()、up()、down()等移动方法统一返回以下三个枚举值之一C 层定义在enum fz_outline_iterator_stateinclude/mupdf/fitz/outline.h常量值含义OutlineIterator.ITERATOR_DID_NOT_MOVE-1无法按请求方向移动已到边界如第一个条目的 prev、最后一个条目的 nextOutlineIterator.ITERATOR_AT_ITEM0新位置存在有效条目item()会返回非 null 结果OutlineIterator.ITERATOR_AT_EMPTY1新位置没有条目但允许在此处插入新条目这正是可走到列表末尾之后的设计目的在 TypeScript 绑定中三者被显式定义为类静态常量platform/wasm/lib/mupdf.tsstatic readonly ITERATOR_DID_NOT_MOVE -1 static readonly ITERATOR_AT_ITEM 0 static readonly ITERATOR_AT_EMPTY 1样式标志位用于描述大纲条目的字体样式为位标志bit flags可组合使用常量值含义OutlineIterator.FLAG_BOLD1位 0 置位表示条目样式为加粗OutlineIterator.FLAG_ITALIC2位 1 置位表示条目样式为斜体C 层对应enum fz_outline_flagFZ_OUTLINE_FLAG_BOLD 1、FZ_OUTLINE_FLAG_ITALIC 2。注意当前 JS 接口的OutlineItem对象docs/reference/javascript/types/OutlineItem.rst只暴露title、uri、open、down、page字段样式标志位目前主要存在于 C 层数据结构中fz_outline.flags字段JS 侧暂未在item()返回对象中直接透出。实例方法详解item() — 读取当前条目返回当前游标位置的OutlineItem若游标不在有效条目上例如刚移动到列表末尾之后的空位返回null。var obj outlineIterator.item() // obj 形如 { title: Chapter 1, uri: #page3, open: false }C 层语义include/mupdf/fitz/outline.h返回的fz_outline_item *只在下一次移动之前有效因此拿到对象后应立即读取所需字段不要跨移动操作缓存指针。WASM 绑定每次调用都会从堆中取出并拷贝出 title / uri / open 字段组装成纯 JS 对象后返回天然规避了指针失效问题item() { let item libmupdf._wasm_outline_iterator_item(this.pointer) if (item) { let title_ptr libmupdf._wasm_outline_item_get_title(item) let uri_ptr libmupdf._wasm_outline_item_get_uri(item) let is_open libmupdf._wasm_outline_item_get_is_open(item) return { title: title_ptr ? fromString(title_ptr) : undefined, uri: uri_ptr ? fromString(uri_ptr) : undefined, open: !!is_open, } as OutlineItem } return null }移动方法next / prev / up / down四个移动方法把游标分别移到下一个同级条目、上一个同级条目、父级条目向上、第一个子条目向下。返回值统一遵循导航返回码约定var result outlineIterator.next() // -1 | 0 | 1 var result outlineIterator.prev() // -1 | 0 | 1 var result outlineIterator.up() // -1 | 0 | 1 var result outlineIterator.down() // -1 | 0 | 1C 层对该文档类型未实现某方向移动的情况直接返回-1见 source/fitz/outline.c 中fz_outline_iterator_next/prev/up/down的iter-xxx NULL检查。典型使用模式是配合item()做整树遍历// 从根级第一个条目开始depth-first 打印整棵大纲 let iter doc.outlineIterator(); let depth 0; while (true) { let it iter.item(); if (it) { console.log( .repeat(depth) (it.title || (untitled))); let r iter.down(); if (r 0) { depth; continue; } // 有子条目深入一层 } else { let r iter.next(); if (r 1) { /* 列表末尾空位 */ } } if (iter.next() -1 iter.up() -1) break; // ... 需要更严谨的栈式遍历时可用显式栈记录 depth }insert(item) — 在当前位置之前插入在当前游标位置之前插入一个新条目。插入后游标位置不改变仍指向原来的条目。返回值为当前位置的状态码0当前位置有有效条目1当前位置没有有效条目但可插入。var result outlineIterator.insert(item) // item 形如 { title: New Chapter, uri: #page7, open: false }C 层注意事项include/mupdf/fitz/outline.h插入的数据会被拷贝调用方保留原对象所有权对于 PDF 文档is_open字段会被忽略——PDF 规范把所有无子节点条目视为关闭状态而新插入的条目天然没有子节点因此一律以is_open false写入。WASM 绑定的insert只接受title、uri、open三个字段platform/wasm/lib/mupdf.tsinsert(item: OutlineItem) { return libmupdf._wasm_outline_iterator_insert(this.pointer, STRING_OPT(item.title), STRING2_OPT(item.uri), item.open) }在列表末尾追加条目是文档特别强调的场景先不断调用next()直到返回1ITERATOR_AT_EMPTY即已走到最后一个同级条目之后的空位此时再insert(item)即可把条目追加到列表尾部。delete() — 删除当前条目删除当前游标位置的条目删除后游标隐式移动到下一个条目。返回值为移动后的位置状态码与next()约定一致0表示新位置有有效条目1表示新位置无有效条目但可插入。outlineIterator.delete()C 层语义见 include/mupdf/fitz/outline.h 中fz_outline_iterator_delete的注释Delete the current item. This implicitly moves us to the next item, and the return code is as forfz_outline_iterator_next.。因此删除后如果需要继续处理同层后续条目直接再次item()读取即可无需额外调用next()。update(item) — 更新当前条目属性用传入条目对象的属性覆盖更新当前条目的属性标题、URI、展开状态。无返回值。outlineIterator.update(item) // item 形如 { title: Renamed Title, uri: #page10, open: true }WASM 绑定实现update(item: OutlineItem) { libmupdf._wasm_outline_iterator_update(this.pointer, STRING_OPT(item.title), STRING2_OPT(item.uri), item.open) }C 层对应fz_outline_iterator_updateinclude/mupdf/fitz/outline.h。注意对于不支持编辑的文档类型C 层的insert/delete/update会抛出FZ_ERROR_ARGUMENT异常消息为 Document type does not support Outline editing见 source/fitz/outline.c调用时应对此做好异常处理。与其他大纲 API 的关系Document.loadOutline() 返回嵌套的OutlineItem[]是整棵大纲树的只读快照而outlineIterator()返回可移动、可编辑的游标。两者在 WASM 绑定中共享OutlineItem对象形态title/uri/open/down/page定义见 OutlineItem.rst。底层fz_load_outline_from_iteratorsource/fitz/outline.c展示了迭代器 → 结构体树的转换路径它会递归调用item()、down()、next()并用fz_resolve_link把 URI 解析为具体页码page字段。编辑能力并非所有文档类型都支持C 层通过函数指针是否为 NULL 来判定iter-insert NULL时抛异常这解释了为什么迭代器接口统一、但各文档驱动能力不同。完整示例遍历、追加与重命名书签// 1. 遍历并打印整棵大纲深度优先使用显式栈 function dumpOutline(doc) { const iter doc.outlineIterator(); const stack [0]; // 记录每个条目的层级 while (true) { const it iter.item(); if (it) { console.log( .repeat(stack[stack.length - 1]) (it.title ?? (no title))); if (iter.down() 0) { stack.push(stack.length); continue; } } if (iter.next() -1) { if (iter.up() -1) break; // 已回到根级末尾 stack.pop(); } } } // 2. 在根级列表末尾追加一个新书签 function appendOutlineItem(doc, title, uri) { const iter doc.outlineIterator(); // 先走进根级第一个条目 while (iter.item() null iter.next() ! -1) { /* 定位 */ } while (iter.next() ! -1) { /* 走到同级最后一个条目之后的空位 */ } return iter.insert({ title, uri, open: false }); // 返回 1 (ITERATOR_AT_EMPTY) 表示插入成功落在空位 } // 3. 重命名当前条目 function renameCurrent(iter, newTitle) { const it iter.item(); if (!it) return false; iter.update({ title: newTitle, uri: it.uri, open: it.open }); return true; } // 4. 删除当前条目并自动前进 iter.delete(); const nextItem iter.item(); // 已是删除后的下一个条目可能为 null小结OutlineIterator是 MuPDF JS 绑定中实现大纲定位 编辑的标准接口四个移动方法配合ITERATOR_DID_NOT_MOVE / ITERATOR_AT_ITEM / ITERATOR_AT_EMPTY三个返回码完成任意方向游走item()读取当前条目insert/delete/update完成书签级增删改。其语义直接映射 C 层fz_outline_iteratorinclude/mupdf/fitz/outline.hWASM 绑定platform/wasm/lib/mupdf.ts负责内存生命周期与纯 JS 对象转换。在 PDF 文档中大纲 目录 书签因此这套接口可直接用于构建书签编辑器、文档重组工具或阅读器的目录导航增强功能。赞分享图形学图像处理【免费下载链接】mupdfmupdf mirror项目地址https://gitcode.com/gh_mirrors/mu/mupdf点击查看免费下载相关推荐Cayley Gizmo API 权威指南JavaScript 图遍历查询语言全解析Cayley Gizmo API 权威指南JavaScript 图遍历查询语言全解析 导读 Gizmo 是 Cayley 图数据库内置的 JavaScrip图数据库数据库后端Formily 核心查询模型 Query 完全指南字段查询、遍历与取值Formily 核心查询模型 Query 完全指南字段查询、遍历与取值 Formily 的表单模型Form与字段模型Field中 query 方法返前端UI组件Cayley Gizmo API 完全指南用 JavaScript 查询图数据库的路径遍历方法Cayley Gizmo API 完全指南用 JavaScript 查询图数据库的路径遍历方法 Gizmo 是 Cayley 图数据库内置的 JavaScri图数据库数据库后端上一篇Git Cherry-pick高级用法git_training教你精准移植代码提交下一篇InternLM2-1.8B-Reward进阶技巧Best of N采样实现高质量内容生成创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考