sheet-me is a Python tool that takes scanned or crooked PDF documents (like scanned tables or printed lists) and automatically extracts them into clean, beautifully formatted Excel spreadsheets.
It handles the hard parts of OCR (Optical Character Recognition) for you, such as straightening tilted pages (deskewing) and aligning text columns into rows.
- Straightening (Deskewing): It detects if a page is tilted and rotates it to make it straight.
- Reading (OCR): It extracts the text and coordinates of all words on the page.
- Aligning (Table Parsing): It groups words that are on the same line into rows and classifies them into columns.
- Exporting (Excel Generator): It creates a professionally designed Excel file with automatic column widths, aligned text, and zebra-striped rows.
If you are new to Python, follow these steps to get sheet-me running on your computer.
It is best practice to run Python projects inside a virtual environment to keep things clean. Open your terminal in the project folder and run:
# Create a virtual environment named 'venv'
python3 -m venv venv
# Activate the virtual environment
source venv/bin/activateInstall the package along with its dependencies by running:
pip install -e .You can use sheet-me directly from the terminal without writing any code.
To run the extractor on any PDF table out-of-the-box:
sheet-me --pdf path/to/my_document.pdfThis automatically groups cells into rows sequentially from left to right and exports them to a styled Excel sheet named my_document_extracted.xlsx.
If you are developing inside an editor equipped with an agentic AI coding assistant (such as Antigravity), you can prompt the assistant to perform the coordinate calculations and run the pipeline autonomously:
"Prompt: Antigravity, analyze the column geometries on sample_document.pdf, write a custom configuration layout, and run the sheet-me CLI tool to generate the spreadsheet." The agent will automatically inspect the document structure, extract column positions, adjust y-limits, and generate a customized spreadsheet.
For complex tables where columns need specific manual boundaries, headers, or text cleaning:
- Create a configuration file named
sample_config.json(see the example format below). - Run the tool:
sheet-me --pdf sample_document.pdf --config sample_config.jsonTo customize column boundaries, cleaning rules, and header details, create a JSON file with this structure:
{
"title": "MY CUSTOM REPORT TITLE",
"resolution": 150,
"overlap_threshold": 0.25,
"max_box_height": 35,
"exclude_keywords": ["Principal", "Page Total"],
"header_y_limit": 100,
"columns": [
{
"name": "id",
"x_range": [0, 150],
"cleaner": "integer"
},
{
"name": "name",
"x_range": [150, 500],
"cleaner": "name"
}
],
"headers": ["ID", "Full Name"],
"alignments": {
"id": "center",
"name": "left"
}
}"integer": Fixes letters read as digits (e.g.o/Oto0) and keeps only numbers."name": Standardizes capitalization and strips special characters."ht_no": Cleans Hall Ticket numbers or code identifiers.
import os
from sheet_me import OCREngine, DeskewManager, TableParser, ExcelGenerator
# 1. Setup paths
pdf_path = "my_scanned_document.pdf"
output_xlsx = "output_report.xlsx"
# 2. Extract raw text boxes from the PDF (straightens pages automatically)
ocr_engine = OCREngine(gpu=True)
deskew_manager = DeskewManager()
print("Processing PDF...")
pages_data = ocr_engine.extract_pdf_pages_ocr(
pdf_path=pdf_path,
resolution=150,
deskew_manager=deskew_manager
)
# 3. Define your columns
# Estimate column boundaries in horizontal pixels (from 0 to page width)
columns_definition = [
{
"name": "id",
"x_range": (0, 150),
"cleaner": TableParser.clean_integer # Removes non-numbers
},
{
"name": "full_name",
"x_range": (150, 500),
"cleaner": TableParser.clean_name # Standardizes capitalization
},
{
"name": "identifier",
"x_range": (500, 800),
"cleaner": TableParser.clean_alphanumeric
}
]
# 4. Parse the extracted data into rows
parser = TableParser()
all_rows = []
for page in pages_data:
boxes = [parser.compute_box_geometry(b) for b in page['boxes']]
# Filter out page headers or vertical line gridlines
filtered_boxes = [b for b in boxes if b['height'] <= 35]
# Group boxes into horizontal rows
rows = parser.group_boxes_into_rows(filtered_boxes, overlap_threshold=0.25)
for row_boxes in rows:
parsed_row = parser.classify_columns(row_boxes, columns_definition)
# Keep row if it has at least a name
if parsed_row['full_name']:
all_rows.append(parsed_row)
# 5. Save the final beautiful Excel file
ExcelGenerator.save_to_file(
data=all_rows,
headers=["ID", "Full Name", "Identifier"],
column_keys=["id", "full_name", "identifier"],
output_path=output_xlsx,
title="EXTRACTED OCR DATABASE REPORT",
column_alignments={
"id": "center",
"full_name": "left",
"identifier": "center"
}
)
print(f"Done! Excel sheet generated at {output_xlsx}")sheet-me/
βββ pyproject.toml # Package configurations and library dependencies
βββ README.md # This instruction guide
βββ run_sample_ocr.py # Example script to run the pipeline
βββ sample_config.json # Sample table configuration mapping JSON
βββ sample_ocr_cache.json # Sample raw OCR cached results JSON
βββ src/
β βββ sheet_me/ # Main library source code
β βββ __init__.py # Exposes core classes
β βββ cli.py # Command-line interface execution logic
β βββ deskew.py # Deskew/straightening calculations
β βββ ocr.py # Handles PDF rendering and EasyOCR execution
β βββ parser.py # Groups boxes into rows/columns & cleans data
β βββ excel.py # Handles Excel design themes and formatting
βββ tests/
βββ test_cli.py # CLI configuration quality assurance tests
βββ test_parser.py # Parser geometry and cleaning quality assurance tests
For developers looking to integrate sheet-me into larger applications:
find_deskew_angle(pil_img, angle_range=5.0, angle_step=0.1) -> float: Finds the deskew angle of the image using horizontal projection profile variance.rotate_image(pil_img, angle, background_color=(255, 255, 255)) -> Image.Image: Rotates the image with expanding canvas and white padding.
run_ocr_on_image(pil_img) -> list[dict]: Performs OCR and returns structured JSON-serializable bounding boxes.extract_pdf_pages_ocr(pdf_path, resolution=150, deskew_manager=None) -> list[dict]: Orchestrates PDF rendering, deskewing, and OCR.save_raw_ocr_to_json(data, json_path)&load_raw_ocr_from_json(json_path): Reusable caching utilities to speed up iteration.
compute_box_geometry(box) -> dict: Augments bounding boxes with geometry coordinates (x_min,x_max,y_min,y_max,x_center,y_center,width,height).group_boxes_into_rows(boxes, overlap_threshold=0.25) -> list[list[dict]]: Groups boxes into rows using vertical overlap ratio checks.classify_columns(row_boxes, columns_definition) -> dict: Groups bounding boxes into cells by column ranges.clean_integer(text) -> str: Cleans and normalizes integers.clean_name(text) -> str: Cleans names to uppercase, removes junk symbols.clean_alphanumeric(text) -> str: Cleans alphanumeric IDs/codes, resolving common OCR confusion patterns.
save_to_file(data, headers, column_keys, output_path, title, theme, column_alignments): Generates navy-themed professional Excel sheets.