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

如何用pikepdf将PDF1的大纲复制到重排后的PDF2中?

问题描述

我用pikepdf模块编写了代码,将PDF1的页面重排后保存为PDF2,代码如下:

import pikepdf

def Main():
    with pikepdf.open("pdf1.pdf") as sourcePDF:
        sourcePages = sourcePDF.pages
        targetPDF = pikepdf.Pdf.new()
        targetPages = targetPDF.pages
        # 根据指定列表重排页面
        for idx in [1, 7, 2, 3, 4, 5, 6, 0]:
            targetPages.append(sourcePages[idx])
        targetPDF.save("pdf2.pdf")
        
if __name__ == "__main__":
    Main()

请问能否将PDF1的大纲(书签等)也复制到PDF2中,并关联到对应的重排后页面?我尝试了以下代码,但无法正确使用copy_foreign方法:

with sourcePDF.open_outline() as sourceOutline:
    with targetPDF.open_outline() as targetOutline:
        for outline in sourceOutline.root:
            targetOutline.root.append(sourcePDF.copy_foreign(outline))
解决方案

可以实现,但不能直接复制书签——原书签关联的是原PDF的页面,重排后新PDF的页面顺序已改变,必须先建立原页面索引到新页面的映射,再复制书签并更新其目标页面。

修改后的完整代码

import pikepdf

def copy_outline_with_updated_pages(source_pdf, target_pdf, page_order):
    # 建立原页面索引到新PDF页面对象的映射
    page_map = {}
    for new_idx, old_idx in enumerate(page_order):
        # 记录原索引对应的新页面对象
        page_map[old_idx] = target_pdf.pages[new_idx]

    with source_pdf.open_outline() as source_outline, target_pdf.open_outline() as target_outline:
        def process_outline_item(item, parent=None):
            # 复制书签条目到目标PDF
            copied_item = source_pdf.copy_foreign(item)
            
            # 更新书签的目标页面
            if hasattr(copied_item, 'Dest'):
                # 处理直接指向页面的Dest
                if isinstance(copied_item.Dest, pikepdf.Page):
                    old_page_idx = source_pdf.pages.index(copied_item.Dest)
                    copied_item.Dest = page_map[old_page_idx]
                # 处理数组形式的Dest(PDF标准格式,第一个元素为页面)
                elif isinstance(copied_item.Dest, list) and isinstance(copied_item.Dest[0], pikepdf.Page):
                    old_page_idx = source_pdf.pages.index(copied_item.Dest[0])
                    copied_item.Dest[0] = page_map[old_page_idx]
            
            # 添加到目标大纲的对应位置
            if parent is None:
                target_outline.root.append(copied_item)
            else:
                parent.append(copied_item)
            
            # 递归处理子书签
            if hasattr(item, 'Kids'):
                for child in item.Kids:
                    process_outline_item(child, parent=copied_item)

        # 遍历原大纲的所有根条目
        for root_item in source_outline.root:
            process_outline_item(root_item)

def Main():
    # 页面重排顺序
    page_order = [1, 7, 2, 3, 4, 5, 6, 0]
    with pikepdf.open("pdf1.pdf") as sourcePDF:
        targetPDF = pikepdf.Pdf.new()
        targetPages = targetPDF.pages
        # 执行页面重排
        for idx in page_order:
            targetPages.append(sourcePDF.pages[idx])
        # 复制并更新大纲书签
        copy_outline_with_updated_pages(sourcePDF, targetPDF, page_order)
        targetPDF.save("pdf2.pdf")
        
if __name__ == "__main__":
    Main()

关键要点

  • 页面映射:通过page_map字典记录原PDF页面索引与新PDF页面对象的对应关系,确保书签指向重排后的正确页面。
  • 递归处理子书签:遍历书签的Kids属性,保证所有层级的子书签都能被正确复制和更新。
  • 兼容多种Dest格式:针对PDF书签常见的两种目标格式(直接页面引用、数组形式)做了适配,覆盖大多数场景。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 14:30:38