使用Apache PDFBox查找PDF内部链接时目标页码返回-1如何解决
问题根源
你的代码本身没有逻辑错误,出现这两个现象是Word导出PDF的内部链接存储规则和PDFBox的API特性共同导致的:
- 内部跳转链接不需要绑定Action,只有指向外部资源的链接才会配置PDActionURI,所以
link.action返回null属于正常情况。 - 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
相关产品推荐
相关产品推荐

