Use when extracting a page range or chapter from a scanned/OCR'd book PDF (ABBYY FineReader 등) into text, markdown, or study notes (정리) — triggers include "PDF 텍스트 발췌", "스캔본 PDF 추출", "책 챕터 정리", "정리본 만들기", "PDF to markdown", "표가 깨져서 안 나와", "pdftotext", "pymupdf4llm", "marker", "OCR 깨짐", "scanned book extraction", "extract chapter from PDF", "make study notes from PDF". Use whenever a book PDF must become text/notes and tables, code, or precise values need to survive.
Scanned 9/3/2026
Install to Claude Code
npx -y skills add toongri/oh-my-toong-playground --skill scan-pdf-to-notes --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Scan Pdf To Notes?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/toongri-scan-pdf-to-notes)More formats (shields.io, HTML) on the badges page.
---
name: scan-pdf-to-notes
description: Use when extracting a page range or chapter from a scanned/OCR'd book PDF (ABBYY FineReader 등) into text, markdown, or study notes (정리) — triggers include "PDF 텍스트 발췌", "스캔본 PDF 추출", "책 챕터 정리", "정리본 만들기", "PDF to markdown", "표가 깨져서 안 나와", "pdftotext", "pymupdf4llm", "marker", "OCR 깨짐", "scanned book extraction", "extract chapter from PDF", "make study notes from PDF". Use whenever a book PDF must become text/notes and tables, code, or precise values need to survive.
---
# Scan PDF to Notes
## Overview
A scanned book PDF (Producer is `ABBYY FineReader` or another OCR engine) is **page images + an OCR text layer**. The OCR layer's accuracy is the **quality ceiling** — no text extractor beats it for body text, and tables/figures/precise values (hashes, numbers, formulas) are the first things OCR mangles.
**Core principle:** one job yields **two artifacts and keeps both**:
- **Raw extraction (추출 원문)** — 1:1 with the book, OCR noise included. The *verifiable source*. Never delete it.
- **Study notes (정리)** — a re-narrated, condensed rewrite of the raw extraction. The *thing you read and study*.
Full flow = **Part A extract → quality check → Part B notes**. Doing only one half leaves the job half done.
## When to Use / NOT
**Use:** extracting a page range (chapter) of a scanned/OCR PDF book into text, markdown, or notes. When tables/code collapse into a single mangled line. When `pdftotext`/`get_text` alone loses structure and tables.
**NOT for:** native (text-based) PDFs — `pymupdf4llm`/`pdftotext` alone suffice (but confirm this in step 1 first). If only raw OCR text is needed and no notes, stop after Part A.
## Full Flow
```dot
digraph flow {
rankdir=LR; node [shape=box];
"1 detect PDF type" -> "2 verify page mapping" -> "3 split range" -> "4 Tier1 extract";
"4 Tier1 extract" -> "5 tables?";
"5 tables?" [shape=diamond];
"5 tables?" -> "6 Tier2 marker" [label="yes"];
"5 tables?" -> "7 quality check" [label="no"];
"6 Tier2 marker" -> "7 quality check" -> "8 write notes" -> "9 OCR fix + verify";
}
```
---
# Part A — Extraction
### 1. Detect PDF type
`pdfinfo file.pdf | grep -iE 'producer|pages'`. If Producer is `ABBYY` or a scanner name, it is scanned+OCR → **OCR is the quality ceiling**. Pull one page with `pdftotext -f N -l N file.pdf -` to confirm a text layer exists.
### 2. Verify page mapping
Printed page ≠ PDF index (front-matter offset, blank divider pages between chapters). **Sample-extract the chapter boundary pages** to confirm start/end and any blank pages. Skipping this extracts the wrong pages (e.g. an empty p200 is the 6↔7 chapter divider). Also: pymupdf indices are **0-based**, while printed pages and `convert-range.sh` args are **1-based** — don't confuse the conversion. If the mapping is unclear, find the chapter-title page first via a `get_text()` keyword search.
### 3. Split the range
`convert-range.sh <SRC.pdf> <START> <END>` — pymupdf `insert_pdf` (the script handles the 0-indexed conversion) cuts out only the target pages. Name it `<book>_p<a>-<b>`.
### 4. Tier 1 (always)
`convert-range.sh` produces these in one pass:
- `pymupdf4llm.to_markdown(..., table_strategy="lines_strict")` → markdown with headers and structure. **Never use `fitz.get_text("text")` alone** (it loses structure and tables).
- `pdftotext -layout` → spatially-aligned text (cross-check for tables, columns, log output).
### 5–6. Tier 2 — recover tables/code blocks (conditionally required)
**If there are real grid tables, or code/logs where alignment matters,** run `marker-chunked.sh <SPLIT.pdf>`. marker re-OCRs + analyzes layout to restore **tables as real markdown tables (`|`)**. On Apple Silicon, the MPS bug forces **8-page chunking** (the script splits and recombines automatically).
- INFO output, key:value dumps, and diagrams "look like tables" but are not grids → marker is unnecessary; `pdftotext -layout` is enough.
- Cost: model is several GB and runs for minutes. The value often concentrates in 1–2 tables, so judge by ROI.
### 7. Quality check
`quality-check.sh <files...>` compares broken-char (`�`), header, and table-row counts per tool to pick a **per-region canonical source**. Body prose is usually pymupdf4llm; table/precise-value regions are pdftotext-layout or marker. **Never trust a single tool blindly.**
---
# Part B — Study Notes (정리)
The raw extraction is a "transcript" with OCR noise. The notes are the "study notebook" you write from it.
### 8. Writing the notes
- **Re-narrate and condense** — rewrite in your own words; do not copy book sentences verbatim (not a transcription).
- **Reorganize into numbered thematic sections.**
- **If a series exists, match its style, density, and file naming** — e.g. if `<book>_6장_정리.md` exists, write `<book>_7장_정리.md` at the same tone and section depth. (Series consistency is the core value of the notes.)
- **Prose comparisons → markdown tables.**
- **Reconstruct OCR-broken code/RESP/logs to spec** — don't paste broken tokens; fix them to the protocol format (`*N`/`$N`).
- **"Easy-to-confuse points" recap section** at the chapter's end. **The recap is conceptual, never autobiographical** — even if the series example is first-person ("I found this confusing"), keep the section but state the conceptual difficulty objectively (the no-fabrication rule wins).
- **Header note** at the top: state that it is a re-narrated summary + the source page range.
### 9. OCR fix + verification (while moving raw → notes)
- **Korean body text**: context-based correction is fine. Common patterns:
| Pattern | OCR → fix |
|---------|-----------|
| mangled English abbreviation/parens | `AOFAppend 0nly` → `AOF(Append Only File)`, `RDBRedisDataBase` → `RDB(Redis DataBase)` |
| digit↔letter confusion | `keyl`→`key1`, `co니nter`→`counter`, `slave©`→`slave0` (`l↔1`, `O↔0`) |
| broken abbreviation glyphs | `QOM`→`OOM`, `[inf이`→`[info]`, `사wck`→`check` |
| broken Korean | `人수용`→`사용`, `기준0.루`→`기준으로` |
| superscript/footnote noise | `<sup>…</sup>`, `프로토콜*3P`, footnote digits — remove |
- **Precise values (hashes, offsets, ports, formulas, versions, identifiers): no context guessing.** Render the page to an image and **verify by eye**: `pymupdf.open(p)[idx].get_pixmap(matrix=pymupdf.Matrix(2.4,2.4)).save("v.png")` → read → delete the temp PNG. Use scale 2.2–2.6; **raise it for small fonts/logs/tables** (2.2 can be blurry).
- **Figures don't extract as text.** Fold their content into prose via caption + body description, or render to image if truly needed.
### No fabrication (strict)
- **Do not invent personal study context** — study week numbers, PR numbers, first-person reflections ("I was confused at first") are unknown to you, so **leave them blank for the user**. Even if the series example contains them, do not imitate and invent.
- **Environment-dependent values** (absolute maxmemory figures, etc.) → annotate as "reference values".
- **Do not fill gaps with inference** not present in the raw extraction.
## Tool Selection
| Tool | Output | Strength | Limit |
|---|---|---|---|
| `pymupdf4llm` | `.md` | header/structure markdown, fast | inherits OCR errors, misses scanned tables |
| `pdftotext -layout` | `.txt` | preserves spatial layout/logs, fast | no markdown structure, inherits OCR |
| `marker_single` | `.md` | re-OCR, **restores tables/code** | slow, multi-GB model, 8p chunks on MPS |
| `get_pixmap()` | `.png` | **eye-verify** precise values/figures | not text, manual check only |
| ❌ `fitz.get_text("text")` | `.txt` | — | loses all structure/tables — **do not use** |
## Common Mistakes
| Mistake | Fix |
|---|---|
| extracting plain text with `get_text("text")` | use pymupdf4llm to preserve structure |
| dropping tables when they break | recover real tables with marker Tier 2 |
| wasting marker on non-table INFO output | marker only for grid tables; pdftotext-layout for the rest |
| trusting one tool's output | compare with `quality-check.sh`, pick per-region canonical |
| context-guessing OCR precise values | eye-verify hashes/formulas/ports via image render |
| deleting the raw extraction (intermediate) | it is the verification source → keep, separate from notes |
| pasting broken code/RESP verbatim | reconstruct to protocol format |
| free-styling style/naming in a series | match the existing notes' tone, density, filename |
| fabricating personal study context | leave blank for the user |
| starting without checking it's scanned | run `pdfinfo` Producer first |
## Reference (scripts)
- `convert-range.sh <SRC.pdf> <START> <END> [STEM]` — split + Tier 1
- `marker-chunked.sh <SPLIT.pdf> [CHUNK=8]` — Tier 2, auto chunk + merge
- `quality-check.sh <files...>` — compare broken-char/structure metrics
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!