You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Apache PDFBox查找PDF内部链接时目标页码返回-1如何解决

问题根源

你的代码本身没有逻辑错误,出现这两个现象是Word导出PDF的内部链接存储规则和PDFBox的API特性共同导致的:

  1. 内部跳转链接不需要绑定Action,只有指向外部资源的链接才会配置PDActionURI,所以link.action返回null属于正常情况。
  2. Word导出的PDF中,内部链接的Destination存储的是目标页的对象引用,而不是页码数值,PDFBox的PDPageXYZDestination.pageNumber字段只有在目标存储为显式页码时才会返回有效值,用对象引用的场景下默认返回-1。

解决方法

你不需要依赖pageNumber字段,直接从Destination中拿到页面对象,再手动计算它在文档中的页码即可,修改后的代码如下:

import org.apache.pdfbox.pdmodel.PDDocument
import org.apache.pdfbox.pdmodel.interactive.action.PDActionURI
import org.apache.pdfbox.pdmodel.interactive.annotation.PDAnnotationLink
import org.apache.pdfbox.pdmodel.interactive.documentnavigation.destination.PDPageXYZDestination
import java.io.File

fun findAnnotationsTest() {
    val pdfPath = "LinkedPDF.pdf"
    val doc = PDDocument.load(File(pdfPath))
    // 提前构建页面对象到页码的映射,页码从1开始计数
    val pageToIndexMap = doc.pages.mapIndexed { index, pdPage -> pdPage to index + 1 }.toMap()
    var pageNo = 0
    for (page in doc.pages) {
        pageNo++
        for (annotation in page.annotations) {
            val subtype = annotation.subtype
            println("Found Annotation ($subtype) on page $pageNo")
            if (annotation is PDAnnotationLink) {
                val aname = annotation.annotationName
                println("\t\tfound Link  named $aname on page $pageNo")
                val link = annotation
                println("\t\tas string: " + link.toString());
                println("\t\tdestination: " + link.destination);
                val dest = link.destination
                val destClass = dest::class
                println("\t\tdest class is $destClass")
                if(dest is PDPageXYZDestination){
                    // 拿到目标页对象,再查映射表得到真实页码
                    val targetPage = dest.page
                    val realPageNumber = pageToIndexMap[targetPage]
                    println("\t\tdest page number is $realPageNumber")
                }

                val action = link.action

                if (action == null) {
                    println("\t\tNo action, this is a normal internal jump link")
                    continue
                }
                if (action is PDActionURI)
                    println("\t\tURI action is ${action.uri}")
                else
                    println("\t\tother action is ${action::class}")
            }
            else{
                println("\tNOT a link")
            }
        }
    }
    doc.close()
}

补充说明

代码中提前构建了页面对象到页码的映射表,避免遍历查询页码的性能损耗,如果你处理的PDF页数很少,也可以直接调用doc.pages.indexOf(targetPage) + 1获取页码。注意用完文档后要调用close()方法释放资源,避免内存泄漏。

内容的提问来源于stack exchange,提问作者fmkatz

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.28 23:27:03