2009-12-16 5 views
5

개요에있는 각 대상이 PDF의 다른 페이지를 참조하는 개요를 기반으로 PDF 파일을 분할하려면 pyPdf를 사용하고 싶습니다.개요를 기준으로 PDF를 분할

예 개요 :

 
main  --> points to page 1 
    sect1 --> points to page 1 
    sect2 --> points to page 15 
    sect3 --> points to page 22 

는 문서 또는 문서의 개요에 각 대상의 각 페이지를 반복하는 pyPdf 내에서 쉽게; 그러나, 나는 목적지가 가리키는 페이지 번호를 얻는 방법을 알아낼 수 없다.

누구나 개요의 각 대상에 대한 참조 페이지 번호를 찾는 방법을 알고 있습니까?

답변

6

내가 그것을 알아 냈 :

 
    class Darrell(pyPdf.PdfFileReader): 

     def getDestinationPageNumbers(self): 
      def _setup_outline_page_ids(outline, _result=None): 
       if _result is None: 
        _result = {} 
       for obj in outline: 
        if isinstance(obj, pyPdf.pdf.Destination): 
         _result[(id(obj), obj.title)] = obj.page.idnum 
        elif isinstance(obj, list): 
         _setup_outline_page_ids(obj, _result) 
       return _result 

      def _setup_page_id_to_num(pages=None, _result=None, _num_pages=None): 
       if _result is None: 
        _result = {} 
       if pages is None: 
        _num_pages = [] 
        pages = self.trailer["/Root"].getObject()["/Pages"].getObject() 
       t = pages["/Type"] 
       if t == "/Pages": 
        for page in pages["/Kids"]: 
         _result[page.idnum] = len(_num_pages) 
         _setup_page_id_to_num(page.getObject(), _result, _num_pages) 
       elif t == "/Page": 
        _num_pages.append(1) 
       return _result 

      outline_page_ids = _setup_outline_page_ids(self.getOutlines()) 
      page_id_to_page_numbers = _setup_page_id_to_num() 

      result = {} 
      for (_, title), page_idnum in outline_page_ids.iteritems(): 
       result[title] = page_id_to_page_numbers.get(page_idnum, '???') 
      return result 

    pdf = Darrell(open(PATH-TO-PDF, 'rb')) 
    template = '%-5s %s' 
    print template % ('page', 'title') 
    for p,t in sorted([(v,k) for k,v in pdf.getDestinationPageNumbers().iteritems()]): 
     print template % (p+1,t) 
1

대럴의 클래스는 PDF 파일에 대한 내용의 멀티 레벨 테이블을 생산하기 위해 약간 수정 될 수

합니다 (pdftk 툴킷에 pdftoc의 방식으로). 내 수정은 _setup_page_id_to_num에 하나 이상의 매개 변수를 추가합니다. 정수는 "level"이며 기본값은 1입니다. 각 호출은 레벨을 증가시킵니다. 결과에 페이지 번호 만 저장하는 대신 페이지 번호와 레벨 쌍을 저장합니다. 반환 된 결과를 사용할 때는 적절한 수정을해야합니다.

저는 LaTeX 섹션, 하위 섹션 등의 책갈피를 반영하는 사이드 바 목차가있는 "PDF 해킹"브라우저 기반 페이지 단위 문서 뷰어를 구현하는 데이 도구를 사용하고 있습니다. pdftk를 설치할 수 없지만 python을 사용할 수있는 공유 시스템에서 일하고 있습니다.

0

이것은 내가 찾고있는 것입니다. Darrell이 PdfFileReader에 추가 한 내용은 PyPDF2의 일부 여야합니다.

북마크로 PDF를 분할하기 위해 PyPDF2와 sejda-console을 사용하는 약간의 레시피를 작성했습니다. 제 경우에는 여러 레벨 1 섹션들이 있습니다. 이 스크립트를 사용하여 결과 파일에 의미있는 이름을 부여 할 수 있습니다. 댓글 읽기 어려울 수 때문에 @darrell 클래스에

import operator 
import os 
import subprocess 
import sys 
import time 

import PyPDF2 as pyPdf 

# need to have sejda-console installed 
# change this to point to your installation 
sejda = 'C:\\sejda-console-1.0.0.M2\\bin\\sejda-console.bat' 

class Darrell(pyPdf.PdfFileReader): 
    ... 

if __name__ == '__main__': 
    t0= time.time() 

    # get the name of the file to split as a command line arg 
    pdfname = sys.argv[1] 

    # open up the pdf 
    pdf = Darrell(open(pdfname, 'rb')) 

    # build list of (pagenumbers, newFileNames) 
    splitlist = [(1,'FrontMatter')] # Customize name of first section 

    template = '%-5s %s' 
    print template % ('Page', 'Title') 
    print '-'*72 
    for t,p in sorted(pdf.getDestinationPageNumbers().iteritems(), 
         key=operator.itemgetter(1)): 

     # Customize this to get it to split where you want 
     if t.startswith('Chapter') or \ 
      t.startswith('Preface') or \ 
      t.startswith('References'): 

      print template % (p+1, t) 

      # this customizes how files are renamed 
      new = t.replace('Chapter ', 'Chapter')\ 
        .replace(': ', '-')\ 
        .replace(': ', '-')\ 
        .replace(' ', '_') 
      splitlist.append((p+1, new)) 

    # call sejda tools and split document 
    call = sejda 
    call += ' splitbypages' 
    call += ' -f "%s"'%pdfname 
    call += ' -o ./' 
    call += ' -n ' 
    call += ' '.join([str(p) for p,t in splitlist[1:]]) 
    print '\n', call 
    subprocess.call(call) 
    print '\nsejda-console has completed.\n\n' 

    # rename the split files 
    for p,t in splitlist: 
     old ='./%i_'%p + pdfname 
     new = './' + t + '.pdf' 
     print 'renaming "%s"\n  to "%s"...'%(old, new), 

     try: 
      os.remove(new) 
     except OSError: 
      pass 

     try: 
      os.rename(old, new) 
      print' succeeded.\n' 
     except: 
      print' failed.\n' 

    print '\ndone. Spliting took %.2f seconds'%(time.time() - t0) 
0

작은 업데이트는 내가 대답으로 게시 UTF-8 윤곽을 구문 분석 할 수 있습니다.

  • pyPdf.generic.TextStringObject
  • pyPdf.generic.ByteStringObject

너무 _setup_outline_page_ids() 함수로부터의 출력이 실패 title 오브젝트에도 두 종류의 반환

문제는 두 가지 종류로 반환 될 수 pyPdf.pdf.Destination.title에 윤곽선 제목에 ASCII가 포함되어 있으면 ASCII 다음에 UnicodeDecodeError이 표시됩니다. 전체 클래스의

if isinstance(title, pyPdf.generic.TextStringObject): 
    title = title.encode('utf-8') 

:

class PdfOutline(pyPdf.PdfFileReader): 

    def getDestinationPageNumbers(self): 

     def _setup_outline_page_ids(outline, _result=None): 
      if _result is None: 
       _result = {} 
      for obj in outline: 
       if isinstance(obj, pyPdf.pdf.Destination): 
        _result[(id(obj), obj.title)] = obj.page.idnum 
       elif isinstance(obj, list): 
        _setup_outline_page_ids(obj, _result) 
      return _result 

     def _setup_page_id_to_num(pages=None, _result=None, _num_pages=None): 
      if _result is None: 
       _result = {} 
      if pages is None: 
       _num_pages = [] 
       pages = self.trailer["/Root"].getObject()["/Pages"].getObject() 
      t = pages["/Type"] 
      if t == "/Pages": 
       for page in pages["/Kids"]: 
        _result[page.idnum] = len(_num_pages) 
        _setup_page_id_to_num(page.getObject(), _result, _num_pages) 
      elif t == "/Page": 
       _num_pages.append(1) 
      return _result 

     outline_page_ids = _setup_outline_page_ids(self.getOutlines()) 
     page_id_to_page_numbers = _setup_page_id_to_num() 

     result = {} 
     for (_, title), page_idnum in outline_page_ids.iteritems(): 
      if isinstance(title, pyPdf.generic.TextStringObject): 
       title = title.encode('utf-8') 
      result[title] = page_id_to_page_numbers.get(page_idnum, '???') 
     return result 

나는 문제를 해결하기 위해이 코드를 추가
관련 문제