PDF 스킬
JSON 명세로 PDF를 생성하고, AcroForm 양식을 만들고 채우며(레이아웃 린트 및 시각적 오버레이 포함), 텍스트/표/메타데이터를 추출하고, 페이지를 병합/분할/회전/워터마크/스탬프 처리하고, 페이지 이미지를 내보내고, 메타데이터와 첨부 파일을 관리하며, 암호화/복호화를 수행합니다(pypdf, reportlab, pdfplumber 사용). 두 가지 추가 기능은 references/에 있으며, 해당 작업을 수행하기 전에 관련 파일을 읽어야 합니다:
- 스캔된/이미지 전용 PDF 및 OCR(pymupdf 고속 경로, marker-pdf 고품질 경로, scripts/extract_pymupdf.py + scripts/extract_marker.py):
references/ocr-extraction.md - 자연어 프롬프트로 기존 PDF의 텍스트 편집(nano-pdf CLI):
references/nano-pdf-editing.md
사용 시기
- 보고서, 청구서 또는 여러 페이지 문서를 PDF로 생성합니다.
- JSON 명세로 채울 수 있는 AcroForm(텍스트/체크박스/라디오/드롭다운)을 만들고, 먼저 레이아웃을 린트합니다.
- PDF에서 텍스트, 표(JSON/CSV), 메타데이터 또는 양식 필드 값을 추출합니다.
- PDF를 병합, 분할, 회전, 페이지 하위 집합 추출, 워터마크, 좌표 위치에 텍스트/이미지 스탬프, 책갈피 추가 또는 압축합니다.
- 시각적 검토 또는 OCR 전달을 위해 페이지를 PNG로 내보내고, 문서 메타데이터를 설정/해제하며, 파일 첨부를 추가/추출합니다.
- AcroForm 양식을 채우거나 평탄화(flatten)하고, 암호로 암호화하거나 복호화합니다.
- 스캔된/이미지 전용 PDF에는 사용하지 않음(
references/ocr-extraction.md사용) 및 픽셀 완벽한 HTML-to-PDF 렌더링에는 사용하지 않음(헤드리스 브라우저 사용).
사전 요구 사항
- Python 3.10+ 및
pypdf,reportlab,pdfplumber:python -m pip install pypdf reportlab pdfplumber - 선택 사항, 페이지 래스터화(
pdf_page_image.py, 오버레이 렌더링):python -m pip install pypdfium2또는 PATH에 poppler의pdftoppm. 스크립트는 pypdfium2 → pdftoppm 순서로 대체하며, 둘 다 없으면{"rendered": false, "missing": [...]}(종료 코드 0)을 보고합니다. - 각 도우미 스크립트는 지연(lazy) 임포트를 확인하고, 종속성이 없으면 설치 힌트를 출력합니다.
실행 방법
모든 도우미는 scripts/에 있으며 argparse CLI입니다. terminal 도구로 실행하세요. 모든 도우미는 --help를 지원합니다. JSON은 UTF-8로 읽고 쓰며, JSON 결과를 stdout에 출력하고, 실패 시 0이 아닌 종료 코드를 반환합니다.
python scripts/pdf_create.py spec.json -o out.pdf # JSON 명세로 PDF 빌드
python scripts/pdf_make_form.py formspec.json -o form.pdf # JSON 명세로 채울 수 있는 AcroForm 빌드
python scripts/pdf_form_layout.py formspec.json # 양식 빌드 전 레이아웃 린트
python scripts/pdf_form_layout.py formspec.json --render-overlay boxes.png [--pdf form.pdf]
python scripts/pdf_read.py doc.pdf --text # 페이지별 텍스트 (JSON)
python scripts/pdf_read.py doc.pdf --tables --csv-dir t/ # 표를 JSON + CSV 파일로
python scripts/pdf_read.py doc.pdf --meta # 메타데이터, 페이지 크기, 암호화/스캔 플래그
python scripts/pdf_read.py form.pdf --fields # 양식 필드: 이름, 유형, 값
python scripts/pdf_merge.py a.pdf b.pdf -o merged.pdf [--bookmarks]
python scripts/pdf_split.py doc.pdf --pages 1-3,7 -o part.pdf [--rotate 90]
python scripts/pdf_fill_form.py form.pdf --fields-json values.json -o filled.pdf [--flatten]
python scripts/pdf_secure.py doc.pdf --encrypt -o enc.pdf --user-password your-password
python scripts/pdf_secure.py enc.pdf --decrypt -o dec.pdf --password your-password
python scripts/pdf_watermark.py doc.pdf --stamp mark.pdf -o stamped.pdf [--under]
python scripts/pdf_stamp.py doc.pdf -o out.pdf --text "DRAFT" --x 150 --y 400 \
--font-size 60 --rotation 45 --opacity 0.3 --color "#cc0000" [--pages 1-3]
python scripts/pdf_stamp.py doc.pdf -o out.pdf --image sig.png --x 400 --y 60 --width 120
python scripts/pdf_page_image.py doc.pdf --pages 1-3 --dpi 150 --out-dir imgs/
python scripts/pdf_meta.py doc.pdf --set-meta --title "T" --author "A" -o out.pdf
python scripts/pdf_meta.py doc.pdf --attach data.csv -o out.pdf
python scripts/pdf_meta.py doc.pdf --list-attachments | --extract-attachments dir/
빠른 참조
| 작업 | 도구 | 명령어 / API |
|---|---|---|
| 문서 생성 (제목, 표, 이미지) | reportlab platypus | pdf_create.py spec.json -o out.pdf |
| 채울 수 있는 양식 빌드 | reportlab acroForm | pdf_make_form.py formspec.json -o form.pdf |
| 양식 레이아웃 린트 / 오버레이 이미지 | 순수 python + PIL | pdf_form_layout.py formspec.json [--render-overlay o.png] |
| 페이지별 텍스트 | pdfplumber | pdf_read.py f.pdf --text |
| 표 → JSON/CSV | pdfplumber | pdf_read.py f.pdf --tables |
| 메타데이터 / 크기 / 암호화됨 / 스캔됨 | pypdf + pdfplumber | pdf_read.py f.pdf --meta |
| 병합 (+ 개요) | pypdf | pdf_merge.py a.pdf b.pdf -o m.pdf |
| 분할 / 추출 / 회전 | pypdf | pdf_split.py f.pdf --pages 2-5 --rotate 90 |
| 양식 필드 나열 / 채우기 / 평탄화 | pypdf | pdf_read.py --fields, pdf_fill_form.py |
| 암호화 / 복호화 (AES-256) | pypdf | pdf_secure.py --encrypt/--decrypt |
| 워터마크 / 스탬프 PDF 페이지 | pypdf | pdf_watermark.py f.pdf --stamp w.pdf |
| 좌표에 텍스트/이미지 스탬프 | reportlab + pypdf | pdf_stamp.py f.pdf --text "Sign here" --x 400 --y 60 |
| 페이지 → PNG (검토 / OCR 전달) | pypdfium2 또는 pdftoppm | pdf_page_image.py f.pdf --pages 1-3 --out-dir imgs/ |
| 메타데이터 설정/해제, 첨부 파일 | pypdf | pdf_meta.py --set-meta / --attach / --extract-attachments |
| 콘텐츠 스트림 압축 | pypdf | pdf_split.py f.pdf --pages 1-N --compress |
절차
- 먼저 검사합니다.
pdf_read.py file.pdf --meta를 실행합니다.encrypted(true인 경우 먼저pdf_secure.py --decrypt로 복호화) 및likely_scanned_pages를 확인합니다. 페이지가 이미지 전용인 경우pdf_page_image.py --pages <scanned> --dpi 300 --out-dir imgs/로 내보내고 PNG를references/ocr-extraction.md스킬에 전달합니다. 빈 텍스트를 "내용 없음"으로 보고하지 마십시오. - 생성합니다.
write_file로 JSON 명세를 작성합니다(요소:heading,paragraph,table,image,pagebreak; 선택적title/author메타데이터; 페이지 번호는 자동으로 추가됨). 그런 다음pdf_create.py를 실행합니다. 레이아웃이 중요한 경우 렌더링된 페이지 이미지에서vision_analyze로 시각적으로 확인합니다. - 추출합니다.
--text는 페이지별 문자열의 JSON 목록을 제공합니다.--tables는 페이지당 행 배열을 제공하고 CSV 파일을 내보낼 수도 있습니다.read_file로 결과를 읽습니다. 바이너리 PDF를 직접 보지 마십시오. - 조작합니다.
pdf_merge.py는 파일을 연결하고 소스 파일당 하나의 책갈피를 추가할 수 있습니다.pdf_split.py는 페이지 범위(1부터 시작, 예:1-3,5,9-), 90° 단위 회전 및--compress를 처리합니다. 단일 페이지 스탬프 PDF(예:pdf_create.py를 통해)를 준비하고pdf_watermark.py로 오버레이하여 워터마크를 만듭니다. 한 줄 스탬프("여기에 서명", 대각선 DRAFT, 모서리 레이블)에는pdf_stamp.py를 텍스트 또는 명시적 좌표의 이미지와 함께 사용합니다. - 양식을 만듭니다. 하나의 양식 명세 JSON을 작성하고(필드는 PDF 포인트 단위의
label_box/entry_box사용 —references/forms.md참조),pdf_form_layout.py로 린트하고 보고된 모든 문제를 수정한 후, 선택적으로--render-overlayPNG를vision_analyze로 검토하고,pdf_make_form.py로 빌드한 후pdf_read.py --fields로 확인합니다. - 양식을 채웁니다. 필드를 나열(
--fields)하여 정확한 이름과 유형을 알아내고,write_file로 UTF-8 JSON{"FieldName": "value"}를 작성합니다(체크박스는true/false허용; 라디오/선택 값은 필드의 내보내기 옵션과 일치해야 함). 그런 다음pdf_fill_form.py를 실행합니다.--fields로 다시 읽어 값이 제대로 들어갔는지 확인합니다. - 메타데이터 및 첨부 파일.
pdf_meta.py --set-meta는 Title/Author/Subject/Keywords(DocInfo)를 씁니다.--clear-meta는 이를 제거합니다.--attach/--list-attachments/--extract-attachments는 포함된 파일을 왕복 처리합니다. - 보안. 사용자 및 소유자 암호와 AES-256을 사용하여 암호화합니다. 알고 있는 암호를 제거하려면
--decrypt가 암호화되지 않은 복사본을 씁니다. - 확인합니다(아래 참조). 그런 다음 성공을 보고합니다.
주의 사항
- 스캔된 PDF: 빈
extract_text()및 페이지 이미지는 텍스트 레이어가 없음을 의미합니다.references/ocr-extraction.md로 라우팅하고 텍스트를 조작하지 마십시오. - 평탄화 제한:
pdf_fill_form.py --flatten은 pypdf의 평탄화 지원을 사용하여 위젯 모양을 페이지 콘텐츠로 변환합니다. 일반 텍스트 필드와 체크박스에는 안정적이지만, 이국적인 위젯(리치 텍스트, 사용자 정의 모양 스트림, 일부 라디오 그룹)은 삭제하거나 잘못 렌더링할 수 있습니다. 평탄화된 출력을vision_analyze로 시각적으로 확인하고, 확실한 평탄화를 위해 외부 렌더러(예: Ghostscript 또는pdftoppm+재조립)를 대체 방법으로 사용하십시오. - NeedAppearances: 채운 후, 뷰어는 모양 스트림이 있는 경우에만 값을 렌더링합니다. 채우기 스크립트는 AcroForm
NeedAppearances플래그를 설정하여 준수하는 뷰어가 다시 생성하도록 합니다. 일부 최소 뷰어는 이를 무시하므로 표시 충실도가 중요한 경우 평탄화하십시오. - 비라틴 양식 값: 값은 올바르게 저장되지만(UTF-16), 필드의 기본 글꼴에 문자가 없을 수 있어 데이터가 왕복되더라도 뷰어에 빈칸으로 표시될 수 있습니다. 시각적으로만 확인하지 말고
--fields로 확인하십시오. - 압축 기대치:
--compress는 콘텐츠 스트림만 축소합니다. 일반적인 절감 효과는 0-20%입니다. 이미지가 지배적이거나 이미 압축된 스트림이 있는 PDF에는 아무런 효과가 없습니다. 이미지 다운샘플링(Ghostscript 영역)을 대체하지 않습니다. - 권한 플래그는 강제하지 않음: 소유자 암호 권한 비트(인쇄 금지, 복사 금지)는 뷰어가 존중할 수 있는 정중한 요청일 뿐입니다. 어떤 라이브러리(pypdf 포함)라도 이를 읽고 제거할 수 있습니다. 사용자 암호만 암호화를 통해 실제로 콘텐츠를 제어합니다. 권한 플래그를 보안으로 제시하지 마십시오.
- 표 추출은 휴리스틱: pdfplumber는 눈금선/단어 정렬에서 표를 감지합니다. 테두리가 없거나 병합된 셀 표는
table_settings조정 또는 수동 정리가 필요할 수 있습니다. - 페이지 인덱싱: 도우미 CLI는 1부터 시작하는 페이지를 사용하고, pypdf API는 0부터 시작합니다. 스크립트가 변환하므로 이중 변환하지 마십시오.
- 회전된 스탬프 텍스트 추출: pdfplumber의 줄 그룹화는 회전된 글리프를 혼란스럽게 만듭니다(45° "DRAFT"는 분산된 문자로 추출됨). 회전된 스탬프는 pypdf의
extract_text()또는 렌더링된 이미지로 대신 확인하십시오. - 라디오 그룹: reportlab은 그룹당 ≥2개의
radio()위젯이 필요하고, 채우기는 슬래시가 있는 내보내기 값("/red")이 필요하며, 라디오의 평탄화 충실도가 가장 낮습니다.references/forms.md를 참조하십시오. - 메타데이터 범위:
pdf_meta.py는 클래식 DocInfo 사전만 씁니다. 포함된 XMP 메타데이터(있는 경우)는 그대로 두며 일부 뷰어에서 다른 값을 표시할 수 있습니다. - PDF/A는 범위 밖: pypdf/reportlab은 준수하는 PDF/A를 생성하거나 검증할 수 없습니다. 아카이브 적합성이 필요한 경우,
terminal도구를 통해 Ghostscript를 실행하고(예: 적절한 ICC 프로파일과 함께gs -dPDFA=2 -dPDFACompatibilityPolicy=1 -sColorConversionStrategy=UseDeviceIndependentColor -sDEVICE=pdfwrite -o out.pdf in.pdf) veraPDF로 검증하십시오. 둘 다 외부 설치이며 결과는 여전히 가정이 아닌 검증이 필요합니다. - 회전은 90의 배수여야 합니다. 암호화된 입력은 다른 작업 전에 복호화되어야 합니다.
확인
- 생성/병합/분할 후:
pdf_read.py out.pdf --meta—page_count및 회전한 경우 페이지별rotation을 확인합니다. - 추출 후: JSON이 비어 있지 않은지 확인하고 알려진 문자열이나 셀을 점검합니다.
- 양식 설계 루프:
pdf_form_layout.py spec.json이 0으로 종료되어야 합니다. 그런 다음--render-overlay boxes.png --pdf form.pdf를 실행하고 PNG를vision_analyze로 검토하여(빨간색 = 필드 이름이 있는 항목 상자, 파란색 = 레이블 상자) 중복, 잘못된 정렬 및 필드에서 분리된 레이블을 확인합니다. 명세 → 린트 → 오버레이를 깨끗해질 때까지 반복합니다. - 양식 빌드 후:
pdf_read.py form.pdf --fields는 올바른 유형과 옵션으로 모든 명세 필드를 나열합니다. - 양식 채우기 후:
pdf_read.py filled.pdf --fields를 실행하고 값(비ASCII 포함, 정확히 일치)을 비교합니다. - 스탬프 후: 텍스트를 다시 추출하거나(회전된 스탬프의 경우 pypdf 사용)
pdf_page_image.py로 페이지를 렌더링하고vision_analyze로 검사합니다. - 메타데이터/첨부 파일 편집 후:
pdf_read.py --meta/pdf_meta.py --list-attachments를 실행하고 첨부 파일을 다시 추출하여 바이트를 비교합니다. - 암호화 후:
--meta는"encrypted": true를 표시하고 암호 없이 열면 실패합니다. 복호화 후 텍스트 추출이 원본과 일치합니다. - 시각적인 모든 것(워터마크, 평탄화된 양식)에 대해 렌더링하고
vision_analyze로 검사합니다.