# Which Tools Does book-to-skill Use for PDF Extraction? A Complete Technical Breakdown

> Discover the PDF extraction tools book-to-skill uses. Explore its tiered pipeline combining system utilities, Python libraries, layout analysis, and optional ML inspection for technical PDFs.

- Repository: [Virgilio Junior/book-to-skill](https://github.com/virgiliojr94/book-to-skill)
- Tags: deep-dive
- Published: 2026-09-01

---

**`book-to-skill` uses a tiered PDF extraction pipeline that combines native system tools (`pdftotext`, `pdfinfo`), pure-Python libraries (`pypdf`, `pdfminer.six`), advanced layout-preserving extraction (`docling`), and an optional ML-powered inspector (`pdf-inspector`/`Firecrawl`) to handle everything from plain text to complex technical PDFs.**

The `virgiliojr94/book-to-skill` repository implements a robust, multi-layered approach to PDF extraction that gracefully degrades when optional dependencies are unavailable. This design ensures reliable text extraction across diverse PDF types—from simple ebooks to dense technical documents with tables, code blocks, and mathematical formulas.

## The Four-Tier PDF Extraction Architecture

`book-to-skill` organizes its PDF extraction into distinct layers, each triggered based on availability and document complexity. The core implementation lives in [`book_to_skill/parsers/pdf.py`](https://github.com/virgiliojr94/book-to-skill/blob/main/book_to_skill/parsers/pdf.py), with dependency management centralized in [`book_to_skill/dependencies.py`](https://github.com/virgiliojr94/book-to-skill/blob/main/book_to_skill/dependencies.py).

### Tier 1: Fast Native Text Extraction with `pdftotext`

The **preferred path** for text-heavy PDFs uses **`pdftotext`** from poppler-utils, invoked via subprocess:

```python

# From book_to_skill/parsers/pdf.py, lines 76-84

result = subprocess.run(
    ["pdftotext", "-layout", str(pdf_path), "-"],
    capture_output=True,
    text=True,
    timeout=30
)

```

This approach preserves layout information and runs significantly faster than pure-Python alternatives. When `pdftotext` is missing, the system automatically falls back to Tier 2.

### Tier 2: Pure-Python Fallbacks (`pypdf` and `pdfminer.six`)

Two libraries provide dependency-free extraction when native tools are unavailable.

**`pypdf`** — lightweight page-by-page extraction:

```python

# From book_to_skill/parsers/pdf.py, lines 12-21

reader = pypdf.PdfReader(pdf_path)
text_parts = []
for page in reader.pages:
    text_parts.append(page.extract_text() or "")
text = "\n".join(text_parts)

```

**`pdfminer.six`** — more sophisticated layout analysis:

```python

# From book_to_skill/parsers/pdf.py, lines 33-41

from pdfminer.high_level import extract_text
text = extract_text(
    str(pdf_path),
    page_numbers=None,  # all pages

    maxpages=0
)

```

The `pdfminer.six` extractor inserts form-feed characters (`\f`) between pages, enabling reliable page-by-page processing downstream.

### Tier 3: Technical PDF Processing with `docling`

For PDFs containing tables, code snippets, formulas, or complex multi-column layouts, **`docling`** provides structure-preserving Markdown conversion:

```python

# From book_to_skill/parsers/pdf.py, lines 45-63

from docling.datamodel.base_models import InputFormat
from docling.datamodel.document_conversion import DocumentConverter, PdfPipelineOptions

pipeline_options = PdfPipelineOptions()
pipeline_options.do_table_structure = True  # enable table detection

converter = DocumentConverter(
    format_options={
        InputFormat.PDF: PdfFormatOption(pipeline_options=pipeline_options)
    }
)
result = converter.convert(pdf_path)
markdown = result.document.export_to_markdown()

```

This Tier 3 extraction is **opt-in** via the `extraction_mode="technical"` parameter, as it requires heavier dependencies and processing time.

### Tier 4: Optional Smart Inspection with `pdf-inspector`

The [`book_to_skill/pdf_inspector_integration.py`](https://github.com/virgiliojr94/book-to-skill/blob/main/book_to_skill/pdf_inspector_integration.py) module provides an **inspector-first** path that can bypass the entire fallback chain:

```python

# From pdf_inspector_integration.py, lines 45-53

from book_to_skill.pdf_inspector_integration import inspect_pdf

markdown, metadata = inspect_pdf("document.pdf")
if markdown and metadata.get("confidence", 0) > 0.8:
    # Use inspector-provided Markdown directly

    return markdown, metadata
else:
    # Fall back to standard extraction pipeline

```

This `pdf-inspector` (Firecrawl-based) analyzes the PDF's internal structure and reports whether native text extraction will produce high-quality results. When confidence is high, it returns pre-extracted Markdown; otherwise, the standard pipeline takes over.

## Auxiliary Tool: `pdfinfo` for Page Counting

When primary extraction methods fail to report page counts, `book-to-skill` falls back to the **`pdfinfo`** system command:

```python

# From book_to_skill/parsers/pdf.py, lines 71-78

result = subprocess.run(
    ["pdfinfo", str(pdf_path)],
    capture_output=True,
    text=True
)

# Parse output for "Pages: N" line

```

This ensures accurate progress reporting and metadata even when document parsing encounters errors.

## Dependency Management and Graceful Degradation

The [`book_to_skill/dependencies.py`](https://github.com/virgiliojr94/book-to-skill/blob/main/book_to_skill/dependencies.py) module (lines 25-31) declares these tools as **optional dependency groups**:

| Dependency Group | Tools | Install Command |
|-----------------|-------|---------------|
| `pdf-text` | `pypdf`, `pdfminer.six` | `pip install book-to-skill[pdf-text]` |
| `pdf-native` | `pdftotext`, `pdfinfo` (system) | `apt-get install poppler-utils` |
| `pdf-technical` | `docling` | `pip install book-to-skill[pdf-technical]` |
| `pdf-inspector` | `pdf-inspector` (Firecrawl) | `pip install book-to-skill[pdf-inspector]` |

When tools are missing, `book-to-skill` emits targeted installation hints:

```bash
$ book-to-skill extract document.pdf
[WARNING] pdftotext not found. Install with: sudo apt-get install poppler-utils
[INFO] Falling back to pypdf extractor...

```

## Practical Usage Examples

### Basic CLI Extraction

```bash

# Default: tries pdftotext → pypdf → pdfminer.six

book-to-skill extract path/to/document.pdf

# Force technical mode for table/code extraction

book-to-skill extract --mode technical complex_tutorial.pdf

```

### Programmatic Single-File Extraction

```python
from pathlib import Path
from book_to_skill import utils

result = utils.extract_single_file(
    Path("my_book.pdf"),
    extraction_mode="text",      # or "technical"

    install_mode="ask"           # "auto", "ask", or "skip"

)

print(f"Extracted {result['pages']} pages")
print(result["text"][:2000])     # First 2000 characters

```

### Conditional Inspector Usage

```python
from book_to_skill.pdf_inspector_integration import inspect_pdf
from book_to_skill.parsers.pdf import extract_text_with_fallback

def smart_extract(pdf_path):
    # Attempt inspector shortcut

    markdown, meta = inspect_pdf(pdf_path)
    if markdown and meta.get("confidence", 0) > 0.85:
        return markdown, "inspector"
    
    # Full fallback pipeline

    return extract_text_with_fallback(pdf_path), "fallback"

```

## Key Implementation Files

| File | Lines of Interest | Purpose |
|------|-------------------|---------|
| [`book_to_skill/parsers/pdf.py`](https://github.com/virgiliojr94/book-to-skill/blob/main/book_to_skill/parsers/pdf.py) | 12-21, 33-41, 45-63, 71-84 | Core extractors for all four tiers |
| [`book_to_skill/dependencies.py`](https://github.com/virgiliojr94/book-to-skill/blob/main/book_to_skill/dependencies.py) | 25-31 | Optional dependency declarations |
| [`book_to_skill/pdf_inspector_integration.py`](https://github.com/virgiliojr94/book-to-skill/blob/main/book_to_skill/pdf_inspector_integration.py) | 45-53 | Inspector hook and confidence logic |
| [`scripts/extract.py`](https://github.com/virgiliojr94/book-to-skill/blob/main/scripts/extract.py) | — | CLI entry point wiring components |

## Summary

- **`pdftotext`** (poppler-utils) provides the fastest, layout-preserving native extraction when available
- **`pypdf`** and **`pdfminer.six`** serve as pure-Python fallbacks requiring no system dependencies
- **`docling`** handles complex technical PDFs with tables, code, and formulas via Markdown export
- **`pdf-inspector`** (Firecrawl) offers optional ML-powered pre-inspection that can bypass slower methods
- **`pdfinfo`** supplies reliable page counts as an auxiliary system command
- The dependency manager in [`dependencies.py`](https://github.com/virgiliojr94/book-to-skill/blob/main/dependencies.py) ensures graceful degradation with actionable install hints

## Frequently Asked Questions

### Is `pdftotext` required to use book-to-skill?

No. While `pdftotext` provides the best performance for text-heavy PDFs, `book-to-skill` automatically falls back to `pypdf` and `pdfminer.six` when poppler-utils is unavailable. The pure-Python fallback chain requires no system package installation.

### When should I use `extraction_mode="technical"` instead of `"text"`?

Use `"technical"` for PDFs containing structured data—tables, code blocks, mathematical notation, or multi-column academic papers. This mode activates `docling`, which preserves document structure as Markdown. For novels, articles, or other primarily textual content, `"text"` mode is faster and produces cleaner output.

### Does the `pdf-inspector` integration work offline?

No. The `pdf-inspector` (implemented via Firecrawl in [`pdf_inspector_integration.py`](https://github.com/virgiliojr94/book-to-skill/blob/main/pdf_inspector_integration.py)) requires network access to analyze PDF structure. It is purely optional; the standard four-tier extraction pipeline functions completely offline.

### How does book-to-skill handle corrupted or image-based PDFs?

For image-based PDFs without embedded text, all text extraction tiers (`pdftotext`, `pypdf`, `pdfminer.six`) will return empty or minimal text. The `docling` technical extractor may still capture visual structure, but true OCR is not currently implemented in the core pipeline. The `pdf-inspector` will typically report low confidence for such documents, triggering appropriate fallback behavior.