pdf-extract

Utility

Extract text, images, and tables from PDFs with OCR fallback.

Category: Utility Tier: Useful for specific workflows Source: Newly authored Updated: 2026-07-20

What it does

The agent reads a PDF and extracts its content as structured text. For normal PDFs, it uses direct text extraction (fast). For scanned PDFs (image-only), it falls back to OCR with tesseract. It can also extract tables as structured rows and pull embedded images.

How an agent uses it

  • The user wants to extract text from a PDF.
  • The user has a scanned PDF that needs OCR.
  • The user wants to pull tables or images out of a PDF.
  • The user says "read this PDF", "extract text from PDF", or "what's in this PDF".

What you get

Install this skill and your Hermes agent can extract text, images, and tables from pdfs with ocr fallback. No manual setup, no scripts to run — the agent handles it.

Install command

hermes skills install https://raw.githubusercontent.com/THEROCKSSS/hermes-skills-portfolio/main/skills/pdf-extract/SKILL.md
View SKILL.md on GitHub
---

name: pdf-extract

description: Use when the user wants to extract text, tables, or images from a PDF file — including scanned/image-only PDFs needing OCR — or asks to "read this PDF", "extract text from PDF", "what's in this PDF", or to pull tables/images out of one.

version: 1.0.0

author: Hermes Agent

license: MIT

metadata:

  hermes:

    tags: [pdf, ocr, text-extraction, table-extraction, pymupdf, tesseract]

    related_skills: [ocr-documents, markdown-to-pdf, csv-toolkit]

---



# pdf-extract



## Overview



Extract text, images, and tables from PDF files using open-source Python libraries. The agent handles PDF parsing, OCR fallback for scanned documents, and structured output.



## When to Use



- The user wants to extract text from a PDF.

- The user has a scanned PDF that needs OCR.

- The user wants to pull tables or images out of a PDF.

- The user says "read this PDF", "extract text from PDF", or "what's in this PDF".



## Prerequisites



```bash

pip install pymupdf pdfplumber pillow

# For OCR fallback:

pip install pytesseract

# Also install tesseract-ocr system package:

# Linux: apt install tesseract-ocr

# macOS: brew install tesseract

# Windows: download from https://github.com/UB-Mannheim/tesseract/wiki

```



## Text Extraction



### Basic text extraction (pymupdf)



```python

import fitz  # pymupdf



def extract_text(pdf_path: str) -> str:

    doc = fitz.open(pdf_path)

    text = []

    for page in doc:

        text.append(page.get_text())

    return "\n".join(text)

```



### With page numbers



```python

def extract_text_with_pages(pdf_path: str) -> list[dict]:

    doc = fitz.open(pdf_path)

    pages = []

    for i, page in enumerate(doc):

        pages.append({

            "page": i + 1,

            "text": page.get_text()

        })

    return pages

```



## Table Extraction



```python

import pdfplumber



def extract_tables(pdf_path: str) -> list:

    tables = []

    with pdfplumber.open(pdf_path) as pdf:

        for i, page in enumerate(pdf.pages):

            page_tables = page.extract_tables()

            for table in page_tables:

                tables.append({"page": i + 1, "rows": table})

    return tables

```



## Image Extraction



```python

import fitz

import os



def extract_images(pdf_path: str, output_dir: str = "./extracted_images"):

    os.makedirs(output_dir, exist_ok=True)

    doc = fitz.open(pdf_path)

    images = []

    for page_num, page in enumerate(doc):

        for img_index, img in enumerate(page.get_images(full=True)):

            xref = img[0]

            base_image = doc.extract_image(xref)

            image_bytes = base_image["image"]

            ext = base_image["ext"]

            filename = f"{output_dir}/page{page_num+1}_img{img_index+1}.{ext}"

            with open(filename, "wb") as f:

                f.write(image_bytes)

            images.append(filename)

    return images

```



## OCR Fallback (for scanned PDFs)



If `get_text()` returns empty or near-empty, the PDF is likely scanned images. Use OCR:



```python

import fitz

import pytesseract

from PIL import Image

import io



def extract_with_ocr(pdf_path: str) -> str:

    doc = fitz.open(pdf_path)

    text = []

    for page in doc:

        # Render page to image at 300 DPI

        pix = page.get_pixmap(dpi=300)

        img = Image.open(io.BytesIO(pix.tobytes("png")))

        page_text = pytesseract.image_to_string(img)

        text.append(page_text)

    return "\n".join(text)

```



## Auto-detect: text vs scanned



```python

def extract_pdf(pdf_path: str) -> str:

    doc = fitz.open(pdf_path)

    # Try direct text extraction

    total_text = "".join(page.get_text() for page in doc)

    # If less than 50 chars per page on average, use OCR

    if len(total_text) / len(doc) < 50:

        return extract_with_ocr(pdf_path)

    return total_text

```



## Workflow



1. Identify the PDF file path

2. Try direct text extraction with pymupdf

3. If text is sparse (< 50 chars/page average), fall back to OCR

4. If the user needs tables, use pdfplumber

5. If the user needs images, extract with pymupdf's image API

6. Return structured output (text, tables, or image paths)



## Common Pitfalls



1. **Scanned PDFs return empty text.** `get_text()` returns `""` for image-only PDFs — always check text length and fall back to OCR.

2. **OCR is slow.** Rendering at 300 DPI and running tesseract takes 2-5 seconds per page — warn the user before running it on large PDFs.

3. **Encrypted PDFs fail to open.** `fitz.open()` raises on password-protected PDFs — call `doc.authenticate("password")` first if the password is known.

4. **Table extraction quality varies.** pdfplumber handles bordered tables well but struggles with borderless ones — check the output before trusting it.

5. **Large PDFs exhaust memory.** A 500-page PDF loaded whole with pymupdf can use significant RAM — process pages one at a time if memory is constrained.

6. **Missing Tesseract language packs.** Non-English PDFs need the matching pack (e.g. `tesseract-ocr-fra`) installed and `lang='fra'` passed to `image_to_string`, or OCR silently produces garbage text.



## Verification Checklist



- [ ] Checked average chars/page before deciding text-extraction vs. OCR

- [ ] Extracted text/table/image count is consistent with the source PDF's page count

- [ ] OCR output spot-checked for garbled text when a scanned PDF was processed

- [ ] Correct Tesseract language pack used for non-English documents

- [ ] Password-protected PDFs authenticated successfully before extraction was attempted

- [ ] Output files (images, extracted text/tables) saved where the user expects them

# pdf-extract



Extract text, tables, and images from PDF files — with OCR fallback for scanned documents.



## What it does



The agent reads a PDF and extracts its content as structured text. For normal PDFs, it uses direct text extraction (fast). For scanned PDFs (image-only), it falls back to OCR with tesseract. It can also extract tables as structured rows and pull embedded images.



## Install



```bash

hermes skills install https://raw.githubusercontent.com/THEROCKSSS/hermes-skills-portfolio/main/skills/pdf-extract/SKILL.md

```



## How to use



```

"Extract the text from report.pdf"

```



The agent:

1. Opens the PDF with pymupdf

2. Tries direct text extraction

3. If text is sparse (scanned PDF), falls back to OCR

4. Returns the extracted text



## What you get



| Output | Method | Notes |

|---|---|---|

| Text | pymupdf `get_text()` | Fast, works on text-based PDFs |

| Tables | pdfplumber `extract_tables()` | Bordered tables work best |

| Images | pymupdf `extract_image()` | Saves to disk |

| OCR text | tesseract via PIL | Fallback for scanned PDFs |



## Example



```

User: "Pull the tables out of financial_report.pdf"



Agent:

  1. Uses pdfplumber to extract tables

  2. Finds 3 tables across 5 pages

  3. Returns: [{"page": 2, "rows": [["Q1", "$1.2M"], ...]}, ...]

  4. Optionally exports to CSV

```