부품을 기준으로 PDF 문서 분할

부품을 기준으로 PDF 문서 분할

(이것은XY 문제, 마지막에 컨텍스트에 대한 자세한 내용)

장 제목을 기준으로 PDF를 프로그래밍 방식으로 분할하는 방법이 있습니까? 그건

이 PDF에서 2개의 PDF를 생성합니다. 하나는 "XY" 부분까지 모든 것을 포함하고 두 번째는 다른 모든 것을 포함합니다.

페이지 번호를 기준으로 PDF를 분할하는 방법 알아보기, 그러나 더 많은 "의미"를 사용할 수 있습니까?

(간단히 말하면 원래 질문은 다음과 같습니다. NSF는 한 문서에 참조 목록을 갖고 다른 문서에 설명을 갖고 싶어하며 LaTeX/pandoc을 사용하여 문서를 생성하고 있으므로 모든 내용을 포함하고 싶습니다. 하나의 문서에서 사용하는 것이 더 간단하고 링크는 중요하지 않습니다.)

답변1

pdftk나는 이런 유형의 작업 에 사용하는 것을 좋아합니다 .

Latex를 사용하여 기본 문서를 생성하면 다음과 같을 것입니다:

\documentclass{report}
\usepackage{blindtext} % For lorem ipsum text
\usepackage{hyperref} % Turns chapters/sections into bookmarks

\begin{document}

\chapter{First Chapter}
\Blindtext[10]

\section{Subsection of chapter 1}
\Blindtext[3]

\chapter{Second Chapter}
\Blindtext[20]

\chapter{Third Chapter}
\Blindtext

\pdfbookmark{Example bookmark}{A}
\Blindtext

\end{document}

을 실행하면 pdflatex각 장에 대한 자동 북마크, 섹션 1.1에 대한 심층 북마크, 이후에 대한 수동 북마크 및 많은 lorem ipsum 구절이 포함된 13페이지 PDF가 생성됩니다.

이제 PDF 파일이 있으므로 이를 사용하여 pdftk이에 대한 통찰력을 얻을 수 있습니다. 자료가 너무 많아서 흥미로운 부분만 잘랐습니다.

$ pdftk sample.pdf dump_data
InfoBegin
...
NumberOfPages: 13
BookmarkBegin
BookmarkTitle: First Chapter
BookmarkLevel: 1
BookmarkPageNumber: 1
BookmarkBegin
BookmarkTitle: Subsection of chapter 1
BookmarkLevel: 2
BookmarkPageNumber: 3
BookmarkBegin
BookmarkTitle: Second Chapter
BookmarkLevel: 1
BookmarkPageNumber: 5
BookmarkBegin
BookmarkTitle: Third Chapter
BookmarkLevel: 1
BookmarkPageNumber: 11
BookmarkBegin
BookmarkTitle: Example bookmark
BookmarkLevel: 1
BookmarkPageNumber: 12
PageMediaBegin
...

레이블을 클릭하면 BookmarkBegin북마크가 있다는 것을 알 수 있습니다. 그것을 보면 BookmarkTitle: X우리는 1부에 도달했다는 것을 알 수 있습니다 X. BookmarkPageNumber:각 북마크에는 연관된 북마크가 있습니다. 이것을 분할에 사용할 수 있습니다. BookmarkLevel분할하려는 수준(장, 섹션, 하위 섹션)을 필터링하는 데 사용할 수도 있습니다 .


챕터 1과 챕터 2로 분할하고 싶다고 가정해 보겠습니다. 4페이지 이전에 분할을 추가해야 한다는 데이터를 보면 다음과 같습니다.

BookmarkTitle: Second Chapter
BookmarkPageNumber: 5

이제 페이지 번호가 있으므로 이를 pdftk분할에 사용할 수 있습니다. 여기에는 실제로 cat특정 페이지에서의 사용이 포함됩니다.

pdftk sample.pdf cat 1-4 output sample-1.pdf
pdftk sample.pdf cat 5-end output sample-2.pdf

보다 일반적인 접근 방식을 취하여 .pdf라는 pdf 스크립트로 작성해 보겠습니다 sample.pdf. 각 고급 북마크에서 PDF를 분할해 보겠습니다(해당 부분 필터링).

먼저 북마크 태그를 좀 더 쉽게 구문 분석할 수 있는 형식으로 변환하여 무언가를 쓸 수 있도록 하겠습니다. awk(다른 이름으로 저장하겠습니다 parser.awk)

#!/bin/awk -f
BEGIN {
    FS=": "
    OFS=";"
}
/^BookmarkBegin/ {
  if (this_level > 1) { # Only handle high-level sections
    next
  }
  if (this_page == "" || this_title == ""){
    next
  }
  if (last_page != "" && last_title != "") {
    print last_title, last_page, this_page-1
  }
  last_title=this_title
  last_page=this_page
  this_title=this_page=this_level=""
}
/^BookmarkTitle:/ {
    this_title=$2
}
/^BookmarkPageNumber:/ {
    this_page=$2
}
/^BookmarkLevel:/ {
    this_level=$2
}
END {
  print last_title, last_page, this_page-1
  print this_title, this_page, "end"
}

여기서는 헤더에 a가 포함되어 있지 않다고 가정하므로 ;이를 출력 구분 기호로 사용합니다. 스크립트는 다음을 출력합니다.

  1. 각 부분의 명칭
  2. 이 섹션의 홈 페이지
  3. 이 섹션의 마지막 페이지입니다.
$ pdftk sample.pdf dump_data | awk -f parser.awk
First Chapter;1;4
Second Chapter;5;10
Third Chapter;11;11
Example bookmark;12;end

이제 각 줄을 반복하고 pdftkbash에서 이것을 호출해 보겠습니다.

#!/bin/bash                                                                     
                                                                                
sequence=1                                                                      
                                                                                
pdftk sample.pdf dump_data | awk -f parser.awk | \                              
while IFS=";" \                                                                 
read -r title start end                                                         
do                                                                              
  pdftk sample.pdf cat "$start"-"$end" output sample-$sequence-"$title".pdf      
  sequence=$((sequence+1))                                                      
done                                                                                     

이로 인해 다음이 남습니다.

$ ls *.pdf
'sample-1-First Chapter.pdf'
'sample-2-Second Chapter.pdf'
'sample-3-Third Chapter.pdf'
'sample-4-Example bookmark.pdf'
sample.pdf

이에 대한 한 가지 제한 사항은 동일한 페이지에 여러 개의 북마크가 있거나 매우 적은 북마크가 있는 경우 약간 혼란스러울 수 있다는 것입니다.

답변2

작년에 저는 Python 라이브러리를 사용하여 py_pdf_parser비슷한 목표를 달성했습니다. pdfplumber게다가 MathPix API(유료이지만 최소한의 비용)를 사용하여 Latex로 최종 변환했습니다.

여기에서 내 스크립트를 확인하여 도움이 되는지 확인할 수 있습니다.https://github.com/sekerez/linear_algebra_done_right/blob/main/problems/extract_problems_from_pdf_book.py이 스크립트는 책에 있는 모든 문제를 추출하여 연습문제 번호와 문제 번호를 기준으로 데이터 구조로 깔끔하게 정리합니다. 단 몇 줄의 코드만으로 이런 작업을 수행할 수 있다는 사실이 놀랍습니다.

사용 사례에 맞게 스크립트를 조정해야 합니다. 각 PDF는 매우 다르기 때문에 기계가 PDF를 처리하기가 매우 어렵습니다. 따라서 PDF 형식을 기반으로 자신만의 스크립트를 수동으로 작성해야 합니다.

답변3

스튜어트의 대답거의 모든 도구가 제공되었지만 솔루션에 두 가지 중요한 편집을 수행했습니다.

  1. 사용일관성pdf디렉토리를 유지하십시오(pdftk는 디렉토리를 제거합니다).
  2. 명령이 파일을 장 수만큼 많은 장으로 분할하는 대신 파일을 두 부분으로 분할하도록 합니다.

parser.awk소스 코드가 호출되고 source.pdf문서를 분할하려는 섹션을 "부록"이라고 가정하고 Stewarts가 공유한 내용을 재사용하면 다음이 제공됩니다.

pdftk source.pdf dump_data | \
awk -f parser.awk  | \
grep Appendix | \
{ 
    IFS=";" ; \
    read -r title start end; \
    ./cpdf source.pdf  1-"`expr $start - 1`" -o A.pdf; \
    ./cpdf source.pdf "$start"-"$end" -o B.pdf;
}

이것

  1. 파일의 메타데이터를 덤프합니다.
  2. 해당 비트( title ; page start ; page ends)를 추출하고,
  3. 부록의 관련 부분을 잡고,
  4. read구분 기호를 다음으로 설정하세요 .;
  5. 제목을 title변수에 저장하고, 시작 페이지를 에 start, 끝 페이지를 에 저장합니다 end.
  6. start - 11부터 (부록 시작 전 페이지에 해당)까지의 모든 페이지를 A.pdf,
  7. 문서의 나머지 부분을 B.pdf.

관련 정보