MuPDF JavaScript 链接(Link)对象完全指南:从读取页面超链接到创建文档内外部链接
图形学图像处理【免费下载链接】mupdfmupdf mirror项目地址https://gitcode.com/gh_mirrors/mu/mupdf点击查看免费下载Link 对象是 MuPDF JavaScript 绑定中描述页面链接的核心数据结构承载了链接的可点击区域bounding box与目标 URI。本文以 docs/reference/javascript/types/Link.rst 为骨架结合 C 层fz_link实现、WASM 与 Java 绑定源码系统讲解如何用getLinks()读取链接、如何用isExternal()区分站内/站外跳转、如何用createLink()与formatLinkURI()在页面上创建新链接并深入解释链接判定与解析的底层原理。读完本文你将能独立完成读取 PDF 全部超链接判断链接跳转类型向文档页面写入内外链三类实战任务。Link 对象是什么在 MuPDF 中Link 对象包含两类信息bounds边界框链接在页面上的可点击区域以Rect矩形表示URI目标地址链接的跳转目的地。链接分为两种类型文档内部链接internal指向同一文档内的其他页面例如目录跳转、脚注引用外部链接external指向其他文档或 Web 资源例如https://example.com、mailto:testexample.com。判断链接属于哪一种调用Link.prototype.isExternal()若要进一步把内部链接 URI 解析为具体的文档页码或目标位置则配合Document.prototype.resolveLink()/Document.prototype.resolveLinkDestination()使用。这三者组成了 MuPDF 链接处理的完整闭环判定 → 解析 → 定位。Link 对象本身没有公开构造函数它属于只读获取或由创建操作返回的对象获取已有链接通过 Page.prototype.getLinks() 获得页面上所有链接的数组创建新链接通过 Page.prototype.createLink() 在页面上写入链接。因此实际使用中你接触 Link 对象的入口永远是Page而链接目标的解析与格式化则依赖Document。获取页面上的所有链接getLinks()Page.prototype.getLinks()返回页面上全部链接组成的数组若页面没有链接则返回空数组。每个返回的元素都是一个 Link 对象它带有bounds属性并依据内/外链类型携带page或uri属性var links page.getLinks() var link links[0] var linkDestination doc.resolveLink(link)从 WASM 绑定 platform/wasm/lib/mupdf.ts 的实现可以看到getLinks()会遍历 C 层的fz_link单向链表对每个节点调用_wasm_keep_link增加引用计数后包装成 JS 对象getLinks() { let links: Link[] [] let link libmupdf._wasm_load_links(this.pointer) while (link) { links.push(new Link(libmupdf._wasm_keep_link(link))) link libmupdf._wasm_link_get_next(link) } return links }这里的next指针、引用计数refs、以及链接列表顺序与页面上的显示顺序无关等语义都直接对应 C 层 include/mupdf/fitz/link.h 中fz_link结构体的设计链接以链表形式挂在页面对象上rect保存未变换坐标下的点击区域uri保存目标地址。Link 的核心实例方法Link 对象暴露五个实例方法读取/设置边界框、读取/设置 URI、判断内外部。它们分别映射到 WASM 绑定的同名方法与 C 层的fz_link_set_rect_fn/fz_link_set_uri_fn回调见 include/mupdf/fitz/link.h。getBounds()读取链接的点击区域返回描述链接在页面上位置的矩形var rect link.getBounds()返回值类型为Rect。Rect是一个四元组[x0, y0, x1, y1]表示矩形左上角与右下角坐标。WASM 侧通过_wasm_link_get_rect将 C 层fz_rect转换为 JS 数组返回见 platform/wasm/lib/mupdf.ts。setBounds(rect)设置链接的点击区域修改链接在页面上的可点击范围link.setBounds([0, 0, 100, 100])参数rect为Rect类型即期望的边界框。C 层通过fz_set_link_rectinclude/mupdf/fitz/link.h写入fz_link的rect字段。注意坐标系使用页面坐标空间具体约定可参考 docs/reference/common/coordinate-system.md。getURI()读取链接目标返回描述链接目标的字符串 URIvar uri link.getURI()返回值处理逻辑与isExternal()紧密相关若isExternal()返回true则该 URI 是可直接交给浏览器使用的地址如https://example.com若返回false则该 URI 是文档内部链接编码需传给Document.prototype.resolveLink()才能访问目标页面。setURI(uri)设置链接目标将链接目标设置为给定 URIlink.setURI(#page1viewFitV,0)参数uri为字符串。若要创建指向文档内其他页面的链接推荐先通过Document.prototype.formatLinkURI()生成规范的内部链接 URI 再传入而不是手写 URI 字符串。isExternal()判断链接是否外部返回布尔值指示链接是否为外部链接var isExternal link.isExternal()判定规则只要链接 URI 以合法 scheme 冒号开头即被定义为外部链接。例如https://example.com→ externalmailto:testexample.com→ external#page1viewFitV,0→ 非 external内部链接。底层判定逻辑由 C 函数fz_is_external_link实现source/fitz/link.c规则非常明确int fz_is_external_link(fz_context *ctx, const char *uri) { const char *mark; /* ... 以合法 scheme 后跟 : 开头则返回 true ... */ if (!uri) return 0; /* scheme 必须以字母开头 */ if ((*uri a || *uri z) (*uri A || *uri Z)) return 0; uri; mark uri; /* 后续字符可为字母、数字、、-、. */ while ((*uri a *uri z) || (*uri A *uri Z) || (*uri 0 *uri 9) || (*uri ) || (*uri -) || (*uri .)) uri; return uri[0] : (uri - mark) 1; }要点归纳scheme 首字符必须是字母a-z或A-Z后续字符允许字母、数字、、-、.最终必须紧跟一个:且 scheme 长度大于 1即字母 冒号至少两个字符。这一规则在 Java 绑定 platform/java/src/com/artifex/mupdf/fitz/Link.java 与 WASM 绑定 platform/wasm/lib/mupdf.ts正则/^\w[\w-.]*:/中保持一致是跨语言统一的语义。解析文档内部链接resolveLink() 与 resolveLinkDestination()拿到内部链接 URI 后需要用Document的方法把它解析成可定位的目标。Document 提供两个方法见 docs/reference/javascript/types/Document.rstresolveLink(link)解析为页码var pageNumber document.resolveLink(my_link)参数可以是 Link 对象或 URI 字符串返回目标页的页码数字number。WASM 实现中传入 Link 对象时会先取出其 URI 再调用_wasm_resolve_link见 platform/wasm/lib/mupdf.ts。resolveLinkDestination(link)解析为链接目标详情var linkDestination document.resolveLinkDestination(linkuri)返回LinkDestination对象包含目标位置的结构化信息目标所在的chapter、page以及视图类型type与x/y/w/h/zoom等定位参数。C 层与之对应的是fz_link_dest结构include/mupdf/fitz/link.h其中视图类型枚举fz_link_dest_type包括FIT、FIT_B、FIT_H、FIT_BH、FIT_V、FIT_BV、FIT_R、XYZ等——这正是 PDF 规范中 GoTo 目标的各种适配视图模式。WASM 绑定 platform/wasm/lib/mupdf.ts 将 C 层fz_link_dest的各字段逐一取出包装成包含type、chapter、page、x、y等键的 JS 对象。一个真实的仓库示例文档 docs/examples/copy-outline.js 演示了复制目录大纲的典型用法——先对大纲节点调用input.resolveLink(node.uri)得到页码再构造新的内部链接 URIfunction copy_outline_rec(cursor, input, list) { list.forEach(function (node) { var page input.resolveLink(node.uri) cursor.insert({ title: node.title, uri: #page (page 1) }) if (node.down) { cursor.prev() cursor.down() copy_outline_rec(cursor, input, node.down) } }) }这段代码展示了解析内部链接 → 拿到目标页 → 重新生成 URI的完整链路。创建链接createLink() 与 formatLinkURI()在页面上创建链接Page.prototype.createLink(rect, uri)用给定矩形与目标 URI 在页面上创建新链接docs/reference/javascript/types/Page.rst// 创建一个跳转到外部 URL 的链接 var link page.createLink([0, 0, 100, 50], https://example.com) // 创建一个跳转到文档内其他页面的链接 var link page.createLink([0, 100, 100, 150], #page1viewFitV,0)参数说明rectRect类型链接在页面上覆盖的活动区域destinationUri字符串目标 URI。返回值是新创建的Link对象。WASM 绑定通过_wasm_create_link完成见 platform/wasm/lib/mupdf.ts。生成文档内部链接 URIformatLinkURI()创建指向文档内其他页面的链接时不要手写 URI 字符串应先用Document.prototype.formatLinkURI(linkDestination)把目标位置对象格式化为标准 URIdocs/reference/javascript/types/Document.rstvar uri document.formatLinkURI({ chapter: 0, page: 42, type: FitV, x: 0, y: 0, width: 100, height: 50, zoom: 1 }) page.createLink([0, 0, 100, 100], uri)linkDestination参数是一个描述目标位置的对象常用字段及其含义字段含义chapter目标所在章节号多章节文档如 EPUB 用单文档通常为 0page目标页码type视图适配类型如FitV、FitH、Fit、XYZ等对应 C 层fz_link_dest_type枚举x/y目标位置的横向/纵向坐标依视图类型而定width/height视图窗口尺寸部分视图类型使用zoom缩放倍数这样生成的 URI形如#page42viewFitV,0可直接传给createLink()保证内部链接格式正确、可被resolveLink()反向解析。删除链接deleteLink()与创建对应Page.prototype.deleteLink(link)从页面移除指定链接docs/reference/javascript/types/Page.rstpage.deleteLink(link_obj)参数为要删除的 Link 对象。WASM 绑定调用_wasm_delete_link见 platform/wasm/lib/mupdf.ts。底层实现fz_link 结构与跨语言绑定Link 的 JavaScript API 并非孤立存在它直接映射到 C 层的数据结构与回调函数。核心结构体定义在 include/mupdf/fitz/link.htypedef struct fz_link { int refs; /* 引用计数 */ struct fz_link *next; /* 同页下一个链接链表 */ fz_rect rect; /* 点击区域未变换坐标 */ char *uri; /* 目标 URI */ fz_link_set_rect_fn *set_rect_fn; /* 设置边界回调 */ fz_link_set_uri_fn *set_uri_fn; /* 设置 URI 回调 */ fz_link_drop_link_fn *drop; /* 释放回调 */ } fz_link;几个值得注意的设计点引用计数管理fz_keep_link递增引用fz_drop_link递减减到零时销毁由于是链表结构释放头节点会级联释放整个链接链include/mupdf/fitz/link.h。WASM 的getLinks()里对每个节点_wasm_keep_link正是为了在 JS 侧安全持有引用。可派生结构fz_new_derived_link宏允许不同文档格式PDF、XPS、EPUB 等派生出各自的链接子类实现格式相关的 set 回调。URI 的两种形态fz_link的uri字段统一承载内部/外部两种目标区分工作完全交给fz_is_external_link见上文源码解析工作交给fz_resolve_link系列函数。跨语言绑定侧除 WASMplatform/wasm/lib/mupdf.ts外Java 绑定在 platform/java/src/com/artifex/mupdf/fitz/Link.java 中提供了完全同构的 APIgetBounds/setBounds/getURI/setURI/isExternal其中isExternal用纯 Java 复刻了 scheme 判定算法。这意味着链接对象的语义在各语言绑定间完全一致掌握了 JavaScript 用法即可触类旁通。实战组合示例统计页面内外部链接并跳转将上述 API 串联起来即可实现遍历文档所有页面统计内/外部链接并解析目标的常见需求var doc new Document(input.pdf); for (var i 0; i doc.loadAllPages().length; i) { var page doc.loadPage(i); var links page.getLinks(); links.forEach(function (link) { var uri link.getURI(); if (link.isExternal()) { console.log(外部链接: uri 区域: link.getBounds()); } else { // 内部链接解析为页码并打印 var pageNumber doc.resolveLink(link); console.log(内部链接 - 第 pageNumber 页 区域: link.getBounds()); } }); }要点回顾用page.getLinks()获取链接数组空页返回空数组用link.isExternal()区分内外链规则合法 scheme 后跟冒号即为外部外部链接 URI 可直接交给浏览器内部链接 URI 用doc.resolveLink()解析页码或用doc.resolveLinkDestination()获取结构化目标写链接用page.createLink(rect, uri)内部目标 URI 建议经doc.formatLinkURI()生成删除链接用page.deleteLink(link)。以上 API 的完整签名与示例还可分别查阅 docs/reference/javascript/types/Page.rst 与 docs/reference/javascript/types/Document.rst以及 WASM 示例 docs/examples/copy-outline.js。赞分享图形学图像处理【免费下载链接】mupdfmupdf mirror项目地址https://gitcode.com/gh_mirrors/mu/mupdf点击查看免费下载相关推荐SumatraPDF 内核解析MuPDF JavaScript 绑定中的 Link 链接对象getBounds / getURI / isExternal 全指南SumatraPDF 内核解析MuPDF JavaScript 绑定中的 Link 链接对象getBounds / getURI / isExternal桌面应用文档使用 docx 在 Word 文档中创建内部与外部超链接Hyperlinks完整指南使用 docx 在 Word 文档中创建内部与外部超链接Hyperlinks完整指南 导读 本文以 docx 项目中的 hyperlinks.md http文档PHPWord 超链接addLink完整指南从外部链接到内部书签的实现与原理PHPWord 超链接addLink完整指南从外部链接到内部书签的实现与原理 本指南以 PHPWord 官方文档 docs/usage/elements/后端上一篇终极指南如何用Nucleus Co-Op让单机游戏变多人派对下一篇Sunshine游戏串流终极指南三步搭建你的私人云游戏平台创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

相关新闻

支付系统如何在不确定世界里把账算到分毫不差?看Awesome Architecture的状态机、幂等与对账

支付系统如何在不确定世界里把账算到分毫不差?看Awesome Architecture的状态机、幂等与对账

支付系统如何在不确定世界里把账算到分毫不差?看Awesome Architecture的状态机、幂等与对账 【免费下载链接】awesome-architecture 🧭 Architecture-first system design: 26 bilingual tutorials, 25 architecture templates, and 6 end-to-end cases …

2026/10/5 2:16:31 阅读更多 →
第六章 TypeScript MCP Server:独立综合项目与能力验收

第六章 TypeScript MCP Server:独立综合项目与能力验收

系列文章目录 第一章 TypeScript MCP Server:从零到一(已更新)第二章 TypeScript MCP Server:提取业务逻辑与建立自动化测试(已更新)第三章 TypeScript MCP Server:分析 package.json 与处理文…

2026/10/5 2:16:31 阅读更多 →
第五章 TypeScript MCP Server:Resources、Prompts 与结构化输出

第五章 TypeScript MCP Server:Resources、Prompts 与结构化输出

系列文章目录 第一章 TypeScript MCP Server:从零到一(已更新)第二章 TypeScript MCP Server:提取业务逻辑与建立自动化测试(已更新)第三章 TypeScript MCP Server:分析 package.json 与处理文…

2026/10/5 2:16:31 阅读更多 →

最新新闻

GD32F103入门实践:环境配置、工程模板搭建与烧写全流程解析

GD32F103入门实践:环境配置、工程模板搭建与烧写全流程解析

GD32F103入门实践(一)配置环境,搭建工程模板,烧写程序 先说说我为什么写这个系列。这几年国产MCU用得多,GD32F103是绕不开的一颗料。它和STM32F103的引脚、寄存器级兼容,价格又低一截,很多产品…

2026/10/5 14:36:12 阅读更多 →
VMware Workstation Pro 16安装Ubuntu 20.04虚拟机完整指南

VMware Workstation Pro 16安装Ubuntu 20.04虚拟机完整指南

我这些年装 Ubuntu 虚拟机,装到闭着眼睛都能把新建虚拟机的向导点完。每次有新人问“我在 Windows 上想跑 Linux,到底用哪个方案”,我给的建议基本没变过——VMware Workstation Pro 16 搭配 Ubuntu 20.04 LTS。这套组合不算新潮,…

2026/10/5 14:36:12 阅读更多 →
中小企业网络设计课程设计全攻略:VLAN划分到仿真验证一步到位

中小企业网络设计课程设计全攻略:VLAN划分到仿真验证一步到位

简介:这是一份计算机网络课程设计报告文档,主题为中小企业网络设计,面向高校计算机相关专业学生及需要撰写同类课程设计报告的读者。文档以小组形式完成,围绕新盟科技公司等百人以下企业的实际建网场景,从需求分析、可…

2026/10/5 14:36:12 阅读更多 →
C++可视化窗口从零实战:从Win32到消息循环与框架迁移

C++可视化窗口从零实战:从Win32到消息循环与框架迁移

1. 写可视化窗口之前,先想清楚这几件事先直接说结论:用C写可视化窗口,很多人第一反应是“去网上找个图形库”,然后一头扎进Qt、wxWidgets、SFML的海洋里,折腾半天连窗口都没弹出来,反而被编译错误劝退。我见…

2026/10/5 14:36:12 阅读更多 →
如何挑选品质可靠的水泥雕塑品牌?专家揭秘选择技巧

如何挑选品质可靠的水泥雕塑品牌?专家揭秘选择技巧

如何挑选品质可靠的水泥雕塑品牌?专家揭秘选择技巧在城市公共艺术和景观设计中,水泥雕塑扮演着至关重要的角色。它们不仅能够提升环境的艺术氛围,还能成为城市的标志性符号。然而,市场上水泥雕塑品牌众多,如何挑选一个…

2026/10/5 14:36:12 阅读更多 →
YOLOv5源码深度解析:用Debug逐行追踪特征图变化

YOLOv5源码深度解析:用Debug逐行追踪特征图变化

写代码的人应该都有过这种经历:模型能跑通,精度也还算行,但你要是突然问一句“这中间特征图到底是怎么变的?”,自己心里立刻就没底了。我接触yolov5源码这件事拖了很久,原因很简单——平时调用detect.py和t…

2026/10/5 14:35:12 阅读更多 →

日新闻

马斯克杀回智能体战场,Grok 4.5万亿参数撑腰,Cursor接手数字白领项目:用TaoToken统一Key跑通多模型Agent工作流

马斯克杀回智能体战场,Grok 4.5万亿参数撑腰,Cursor接手数字白领项目:用TaoToken统一Key跑通多模型Agent工作流

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/5 0:00:22 阅读更多 →
AI编程工具插件机制详解:plugin.json配置与加载失败排查指南

AI编程工具插件机制详解:plugin.json配置与加载失败排查指南

1. 从“plugins”这个词说起:它到底在解决什么问题如果你最近在折腾 AI 编程工具,尤其是 Cursor、Codex CLI、Claude Code 这类带 CLI 的编辑器或命令行助手,那你大概率绕不开一个词——plugins。这个词本身不新鲜,从浏览器到 IDE…

2026/10/5 0:00:23 阅读更多 →
第26课:OpenClaw|日志审计与问题诊断:把日志链路改到 TaoToken 的排查清单

第26课:OpenClaw|日志审计与问题诊断:把日志链路改到 TaoToken 的排查清单

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/5 0:00:23 阅读更多 →

周新闻

KT148A语音芯片外挂8002D功放的工程实践指南

KT148A语音芯片外挂8002D功放的工程实践指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/5 5:06:42 阅读更多 →
LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/5 1:10:22 阅读更多 →
ARM架构深度解析:从RISC设计理念到交叉编译实战

ARM架构深度解析:从RISC设计理念到交叉编译实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/5 3:06:17 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/4 11:40:45 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/4 9:43:54 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/4 20:14:29 阅读更多 →