agentsclimarketplace

Pdf

Skill Dannykkh/skill-olympus/skills/pdf

Twelve Greek gods. One command. A working SaaS. 98 skills + 49 agents + 13 hooks for Claude Code + Codex CLI + Gemini CLI. Cross-CLI persistent memory, zero-interaction full pipeline (design → build → inspect → test → ship).

Install
npx -y skills add Dannykkh/skill-olympus --skill pdf

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

2 things to look at

  • no licenseNo license file was found in the repository. Code published without one is not open source by default, so using it at work is a question for whoever answers licensing questions where you are.
  • 3 stars3 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

What its author says it does

Copied from the file, not written here

Read, create, edit, split, merge, rotate, watermark, fill, encrypt/decrypt, OCR, or extract text/tables/images from PDF files; use whenever .pdf is mentioned or requested.

The file declares its own license as Proprietary. LICENSE.txt has complete terms. That is the author’s claim about this one file, and it is not the same thing as the license GitHub reports for the repository, which is listed with the other numbers below.

SKILL.md

12.8 KB, ~3.9k tokens by cl100k_base, as published. Nobody here has run it

PDF Processing Guide

Overview

This guide covers essential PDF processing operations using Python libraries and command-line tools. For advanced features, JavaScript libraries, and detailed examples, see reference.md. If you need to fill out a PDF form, read forms.md and follow its instructions.

Quick Start

from pypdf import PdfReader, PdfWriter

# Read a PDF
reader = PdfReader("document.pdf")
print(f"Pages: {len(reader.pages)}")

# Extract text
text = ""
for page in reader.pages:
    text += page.extract_text()

Python Libraries

pypdf - Basic Operations

Merge PDFs

from pypdf import PdfWriter, PdfReader

writer = PdfWriter()
for pdf_file in ["doc1.pdf", "doc2.pdf", "doc3.pdf"]:
    reader = PdfReader(pdf_file)
    for page in reader.pages:
        writer.add_page(page)

with open("merged.pdf", "wb") as output:
    writer.write(output)

Split PDF

reader = PdfReader("input.pdf")
for i, page in enumerate(reader.pages):
    writer = PdfWriter()
    writer.add_page(page)
    with open(f"page_{i+1}.pdf", "wb") as output:
        writer.write(output)

Extract Metadata

reader = PdfReader("document.pdf")
meta = reader.metadata
print(f"Title: {meta.title}")
print(f"Author: {meta.author}")
print(f"Subject: {meta.subject}")
print(f"Creator: {meta.creator}")

Rotate Pages

reader = PdfReader("input.pdf")
writer = PdfWriter()

page = reader.pages[0]
page.rotate(90)  # Rotate 90 degrees clockwise
writer.add_page(page)

with open("rotated.pdf", "wb") as output:
    writer.write(output)

pdfplumber - Text and Table Extraction

Extract Text with Layout

import pdfplumber

with pdfplumber.open("document.pdf") as pdf:
    for page in pdf.pages:
        text = page.extract_text()
        print(text)

Extract Tables

with pdfplumber.open("document.pdf") as pdf:
    for i, page in enumerate(pdf.pages):
        tables = page.extract_tables()
        for j, table in enumerate(tables):
            print(f"Table {j+1} on page {i+1}:")
            for row in table:
                print(row)

Advanced Table Extraction

import pandas as pd

with pdfplumber.open("document.pdf") as pdf:
    all_tables = []
    for page in pdf.pages:
        tables = page.extract_tables()
        for table in tables:
            if table:  # Check if table is not empty
                df = pd.DataFrame(table[1:], columns=table[0])
                all_tables.append(df)

# Combine all tables
if all_tables:
    combined_df = pd.concat(all_tables, ignore_index=True)
    combined_df.to_excel("extracted_tables.xlsx", index=False)

reportlab - Create PDFs

Basic PDF Creation

from reportlab.lib.pagesizes import letter
from reportlab.pdfgen import canvas

c = canvas.Canvas("hello.pdf", pagesize=letter)
width, height = letter

# Add text
c.drawString(100, height - 100, "Hello World!")
c.drawString(100, height - 120, "This is a PDF created with reportlab")

# Add a line
c.line(100, height - 140, 400, height - 140)

# Save
c.save()

Create PDF with Multiple Pages

from reportlab.lib.pagesizes import letter
from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer, PageBreak
from reportlab.lib.styles import getSampleStyleSheet

doc = SimpleDocTemplate("report.pdf", pagesize=letter)
styles = getSampleStyleSheet()
story = []

# Add content
title = Paragraph("Report Title", styles['Title'])
story.append(title)
story.append(Spacer(1, 12))

body = Paragraph("This is the body of the report. " * 20, styles['Normal'])
story.append(body)
story.append(PageBreak())

# Page 2
story.append(Paragraph("Page 2", styles['Heading1']))
story.append(Paragraph("Content for page 2", styles['Normal']))

# Build PDF
doc.build(story)

Subscripts and Superscripts

IMPORTANT: Never use Unicode subscript/superscript characters (₀₁₂₃₄₅₆₇₈₉, ⁰¹²³⁴⁵⁶⁷⁸⁹) in ReportLab PDFs. The built-in fonts do not include these glyphs, causing them to render as solid black boxes.

Instead, use ReportLab's XML markup tags in Paragraph objects:

from reportlab.platypus import Paragraph
from reportlab.lib.styles import getSampleStyleSheet

styles = getSampleStyleSheet()

# Subscripts: use <sub> tag
chemical = Paragraph("H<sub>2</sub>O", styles['Normal'])

# Superscripts: use <super> tag
squared = Paragraph("x<super>2</super> + y<super>2</super>", styles['Normal'])

For canvas-drawn text (not Paragraph objects), manually adjust font the size and position rather than using Unicode subscripts/superscripts.

Command-Line Tools

pdftotext (poppler-utils)

# Extract text
pdftotext input.pdf output.txt

# Extract text preserving layout
pdftotext -layout input.pdf output.txt

# Extract specific pages
pdftotext -f 1 -l 5 input.pdf output.txt  # Pages 1-5

qpdf

# Merge PDFs
qpdf --empty --pages file1.pdf file2.pdf -- merged.pdf

# Split pages
qpdf input.pdf --pages . 1-5 -- pages1-5.pdf
qpdf input.pdf --pages . 6-10 -- pages6-10.pdf

# Rotate pages
qpdf input.pdf output.pdf --rotate=+90:1  # Rotate page 1 by 90 degrees

# Remove password
qpdf --password=mypassword --decrypt encrypted.pdf decrypted.pdf

pdftk (if available)

# Merge
pdftk file1.pdf file2.pdf cat output merged.pdf

# Split
pdftk input.pdf burst

# Rotate
pdftk input.pdf rotate 1east output rotated.pdf

Common Tasks

Extract Text from Scanned PDFs

# Requires: pip install pytesseract pdf2image
import pytesseract
from pdf2image import convert_from_path

# Convert PDF to images
images = convert_from_path('scanned.pdf')

# OCR each page
text = ""
for i, image in enumerate(images):
    text += f"Page {i+1}:\n"
    text += pytesseract.image_to_string(image)
    text += "\n\n"

print(text)

Add Watermark

from pypdf import PdfReader, PdfWriter

# Create watermark (or load existing)
watermark = PdfReader("watermark.pdf").pages[0]

# Apply to all pages
reader = PdfReader("document.pdf")
writer = PdfWriter()

for page in reader.pages:
    page.merge_page(watermark)
    writer.add_page(page)

with open("watermarked.pdf", "wb") as output:
    writer.write(output)

Extract Images

# Using pdfimages (poppler-utils)
pdfimages -j input.pdf output_prefix

# This extracts all images as output_prefix-000.jpg, output_prefix-001.jpg, etc.

Password Protection

from pypdf import PdfReader, PdfWriter

reader = PdfReader("input.pdf")
writer = PdfWriter()

for page in reader.pages:
    writer.add_page(page)

# Add password
writer.encrypt("userpassword", "ownerpassword")

with open("encrypted.pdf", "wb") as output:
    writer.write(output)

Quick Reference

TaskBest ToolCommand/Code
Merge PDFspypdfwriter.add_page(page)
Split PDFspypdfOne page per file
Extract textpdfplumberpage.extract_text()
Extract tablespdfplumberpage.extract_tables()
Create PDFsreportlabCanvas or Platypus
Command line mergeqpdfqpdf --empty --pages ...
OCR scanned PDFspytesseractConvert to image first
Fill PDF formspdf-lib or pypdf (see forms.md)See forms.md
Markdown → 출판품질 PDFscripts/markdown_to_pdf.py아래 섹션 참조

Markdown → 출판품질 PDF (한국 기본값)

scripts/markdown_to_pdf.py는 playwright(Chromium) 기반 마크다운 → 출판품질 PDF 변환기입니다. 한국 환경에 맞게 A4/25mm 마진/Pretendard 폰트를 기본으로 사용합니다.

한국 기본값

항목기본값비고
페이지A4 (210×297mm)한국/유럽 표준
마진25mm한국 출판 표준
본문 폰트Pretendard → Noto Sans KR → 시스템 sans자동 다운로드 (SIL OFL 1.1)
코드 폰트D2Coding → JetBrains Mono → monospace자동 다운로드 (SIL OFL 1.1)
페이지번호하단 중앙 "N / M"
날짜 형식YYYY년 M월 D일
외부 이미지 fetch허용 (networkidle까지 대기)Chromium이 외부 리소스를 로드 — 트래커 차단 아님

사용법

# 80% 케이스 — 무플래그
python skills/pdf/scripts/markdown_to_pdf.py generate spec.md
# → spec.pdf 생성, stdout에 경로 한 줄

# 출력 경로 지정
python ... markdown_to_pdf.py generate spec.md docs/spec.pdf

# 표지 + TOC 포함 (출판 모드)
python ... markdown_to_pdf.py generate \
  --cover --toc \
  --title "프로젝트 명세서" \
  --author "팀 이름" \
  --org "회사명" \
  spec.md

# 워터마크 (한글/영문 모두 지원)
python ... markdown_to_pdf.py generate --watermark "초안" memo.md
python ... markdown_to_pdf.py generate --watermark "DRAFT" memo.md
python ... markdown_to_pdf.py generate --watermark "대외비" memo.md

# 프리뷰 (HTML 렌더 후 브라우저 자동 오픈, PDF 라운드트립 회피)
python ... markdown_to_pdf.py preview spec.md

# 폰트 미리 다운로드 + 의존성 점검
python ... markdown_to_pdf.py setup

페이지 구성 옵션 (현재 CLI의 질문 방식 권장)

마크다운을 PDF로 만들 때, 다음을 사용자에게 물어보고 적용하세요:

Q1: 표지 페이지를 추가할까요?

  • A) 추가 (외부 공유용) → --cover --title "..." --author "..."
  • B) 추가 안 함 (내부 메모) → 옵션 없음

Q2: 목차(TOC)를 포함할까요?

  • A) 포함 (10페이지 이상이면 추천) → --toc
  • B) 포함 안 함 (짧은 문서)

Q3: 워터마크가 필요한가요?

  • A) DRAFT/초안 (작업 중) → --watermark "초안"
  • B) 대외비/CONFIDENTIAL → --watermark "대외비" --confidential
  • C) 없음 (최종본)

Q4: H1마다 새 페이지로 시작?

  • A) 예 (장 단위 문서) → 기본값 (옵션 불필요)
  • B) 아니오 (메모/단편) → --no-chapter-breaks

옵션 레퍼런스

옵션설명
--title TEXT문서 제목 (생략 시 첫 H1)
--subtitle TEXT부제
--author TEXT저자 (표지 표기)
--org TEXT조직/팀명 (표지 표기)
--date TEXT날짜 (생략 시 오늘, 한국식)
--cover표지 페이지 추가
--toc목차 추가
--watermark TEXT대각선 워터마크
--confidential좌측하단 CONFIDENTIAL 푸터 (페이지번호는 우측)
--no-chapter-breaksH1마다 페이지 분할 안 함
--skip-fonts폰트 자동 다운로드 건너뜀
--quiet진행상황 출력 끔

Output Contract

스크립트 자동화/체이닝을 위한 명확한 출력 규약:

stdout: <output-path>           ← 한 줄, 경로만 (성공 시)
stderr: 진행상황 메시지         ← --quiet로 끔
exit:
  0 = 성공
  1 = 인자 오류 (입력파일 없음/.md 아님)
  2 = 렌더링 실패
  3 = 의존성 누락 (playwright/markdown 미설치)
  4 = 네트워크 실패 (정의됨, 현재 미사용 — 폰트 다운로드 실패는 fallback 처리)

캡처 예시:

PDF=$(python markdown_to_pdf.py generate spec.md 2>/dev/null) && open "$PDF"

의존성 설치

pip install playwright markdown pygments
playwright install chromium     # 첫 실행 시 1회만

왜 playwright? 우리 /minos 스킬이 이미 playwright + Chromium을 사용하므로 의존성이 중복되지 않습니다. Windows/Mac/Linux 모두 동일한 렌더링 결과를 보장하고, GTK 같은 시스템 라이브러리 의존성이 없습니다.

셋업 한 방에:

python skills/pdf/scripts/markdown_to_pdf.py setup
# → 의존성 점검 + Chromium 다운로드 + 한글 폰트 다운로드

폰트는 첫 실행 시 ~/.cache/agent-customizations/fonts/에 자동 다운로드됩니다 (SIL OFL 1.1 라이선스). 오프라인 환경이면 --skip-fonts로 시스템 폰트만 사용 가능합니다.

Clio 통합

/clio 스킬의 Phase 3에서 산출물(PRD/TECHNICAL/USER-MANUAL)을 PDF로 자동 출력할 때 사용됩니다. Clio가 호출하는 명령:

# USER-MANUAL은 표지 + TOC 포함 (외부 공유 빈도 높음)
python markdown_to_pdf.py generate \
  --cover --toc \
  --title "{프로젝트명} 사용자 매뉴얼" \
  USER-MANUAL.md

# PRD/TECHNICAL은 TOC만 (내부 문서)
python markdown_to_pdf.py generate --toc PRD.md
python markdown_to_pdf.py generate --toc TECHNICAL.md

Next Steps

  • For advanced pypdfium2 usage, see reference.md
  • For JavaScript libraries (pdf-lib), see reference.md
  • If you need to fill out a PDF form, follow the instructions in forms.md
  • For troubleshooting guides, see reference.md
  • Markdown → 출판 PDF: 위 섹션 참조 (한국 기본값: A4 + Pretendard)

Keep looking

Skills are one crate of 328,083. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.