Skip to main content
Pre-release

This release is a pre-release and may not be stable for production use.

obliq-OCR

High-performance, page-aware OCR and document-parsing pipeline combining PyMuPDF and RapidOCR (PP-OCR / ONNX Runtime), built for automated tax-compliance document processing at OBLIQ.


Table of Contents

  1. How it works
  2. Requirements
  3. Installation
  4. Quick start
  5. CLI usage
  6. Output schema
  7. Model details
  8. Testing
  9. Known limitations
  10. Project structure

How it works

The pipeline processes documents page by page:

Step Action
Triage Is there a usable text layer? Is it garbled? Is the page a full-page image? Is it blank?
Digital page Extract text directly from the PDF text layer via PyMuPDF (~milliseconds).
Scanned page Rasterise the page at 200 DPI and run PP-OCR models via RapidOCR on ONNX Runtime.
Layout rebuild Word-level boxes are regrouped into visual reading-order lines; wide gaps become | so table rows remain intact.
Output Per-page text + method + confidence + timing, returned as a DocResult and optionally saved as JSON + TXT.

Mixed files (some pages digital, some scanned) are handled naturally because the decision is made on a per-page basis.


Requirements

Dependency Minimum version Notes
Python 3.10 Tested on 3.10 – 3.13
PyMuPDF 1.24.0 PDF rendering and text extraction
rapidocr-onnxruntime 1.3.18 OCR engine with bundled PP-OCR ONNX models
onnxruntime 1.17.0 CPU inference runtime
Pillow 10.0.0 Image preprocessing
NumPy 1.24.0 Array operations

For GPU (CUDA) inference, install the [gpu] extra (see below).


Installation

From source (development)

# 1. Clone the repository and switch to the feature branch
git clone https://github.com/rahulkate173/obliq-OCR.git
cd obliq-OCR
git switch feat/initial-ocr-pipeline

# 2. Create and activate a virtual environment
python -m venv .venv
# Windows
.venv\Scripts\activate
# macOS / Linux
source .venv/bin/activate

# 3. Install the package in editable mode with dev dependencies
pip install -e ".[dev]"

GPU (CUDA) support

If you have an NVIDIA GPU with CUDA:

# Uninstall the CPU onnxruntime first (the two builds conflict)
pip uninstall onnxruntime -y
pip install "obliq-ocr[gpu]"

Set OBLIQ_OCR_DEVICE=cuda or pass force_device="cuda" to use it.


Quick start

from obliq_ocr import parse_document

# Works with PDFs (digital, scanned, or mixed) and images (JPEG, PNG, TIFF, …)
result = parse_document("invoice.pdf")

# Print all pages
print(result.full_text())

# Access structured per-page data
for page in result.pages:
    print(f"Page {page.page}: method={page.method}, chars={page.n_chars}, conf={page.confidence}")

# Save JSON + TXT to disk
from obliq_ocr import save_result

save_result(result, out_dir="outputs/")

Force device

result = parse_document("scan.pdf", force_device="cpu")  # always CPU
result = parse_document("scan.pdf", force_device="cuda")  # require GPU
# or via environment variable:
# OBLIQ_OCR_DEVICE=cuda python my_script.py

CLI usage

# Basic usage
obliq-ocr invoice.pdf

# Specify output directory and device
obliq-ocr scan.pdf --output-dir results/ --device cpu

# Suppress per-page progress
obliq-ocr document.pdf --quiet

# Or invoke as a module
python -m obliq_ocr invoice.pdf

Output schema

parse_document() returns a DocResult. Calling .to_dict() gives:

{
  "source": "invoice.pdf",
  "device": "CPU",
  "pages": [
    {
      "page": 1,
      "method": "ocr",
      "reason": "only 3 text chars",
      "text": "Invoice Number: 12345 | Amount: ₹50,000",
      "n_chars": 38,
      "confidence": 0.87,
      "seconds": 2.65
    },
    {
      "page": 2,
      "method": "text_layer",
      "reason": "412 chars, image cover 0%",
      "text": "Terms and conditions ...",
      "n_chars": 412,
      "confidence": null,
      "seconds": 0.003
    }
  ]
}

Field reference

Field Type Description
page int 1-indexed page number
method str "text_layer", "ocr", or "blank"
reason str Why that method was chosen
text str Extracted text; column gaps → |
n_chars int Character count of text
confidence float | null Mean PP-OCR score [0, 1]; null for text-layer pages
seconds float Wall-clock processing time for this page

Coordinate system (elements): Bounding boxes are [x0, y0, x1, y1]. For digital pages, units are PDF points (1/72 inch), origin at the top-left corner. For scanned pages, units are pixels at the configured render DPI (default 200). Page numbering is 1-indexed.


Model details

Sub-model File Size Source License
PP-OCRv4 Detection ch_PP-OCRv4_det_infer.onnx ~4 MB RapidOCR releases Apache 2.0
PP-OCRv4 Classification ch_ppocr_mobile_v2.0_cls_infer.onnx ~1 MB RapidOCR releases Apache 2.0
PP-OCRv4 Recognition ch_PP-OCRv4_rec_infer.onnx ~12 MB RapidOCR releases Apache 2.0

All three models are bundled inside the rapidocr_onnxruntime package and are downloaded automatically by pip install rapidocr_onnxruntime. No manual model download is required. Total additional disk size: ~17 MB. No model files > 50 MB are committed to this repository.


Testing

# Run all tests (some fixture-based tests are skipped on a clean clone)
pytest

# Run with coverage report
pytest --cov=obliq_ocr --cov-report=term-missing

# Run only the fast smoke + unit tests
pytest tests/test_pipeline.py -k "Imports or Unit or Blank or Digital"

Adding real fixture PDFs

Place anonymised or synthetic PDF files in tests/fixtures/:

File What it tests
digital.pdf Text extraction from native PDF text layer
scanned.pdf OCR on rasterised page images
mixed.pdf Handling of pages with both methods
rotated.pdf Text extraction on rotated pages

See tests/fixtures/README.md for rules. No real client documents or PII.

Test results (Kaggle CPU, Oct 2026)

Tested on an 8-page scanned invoice PDF (Mix of LR No., E-Way Bill, Tax Invoice, Delivery Challan):

Metric Value
Pages 8
OCR pages 8
Total time 29 s (CPU)
Mean confidence 0.83
Hardware Kaggle CPU notebook (2 vCPU, no GPU)

No formal CER/WER benchmark has been run yet. Visual inspection of output showed high accuracy on printed documents; handwriting and low-DPI scans are not supported.


Known limitations

  • Handwriting is not supported. PP-OCR is trained on printed text.
  • Low-DPI scans (< 100 DPI) may produce poor results. Increase OCR_DPI in parser.py if needed.
  • Rotated pages – PyMuPDF handles page rotation metadata automatically, but extreme skew (not multiples of 90°) will reduce OCR accuracy.
  • Complex layouts (multi-column magazines, tables with merged cells) are approximated by the | column separator.
  • Right-to-left scripts (Arabic, Hebrew) are not explicitly handled.
  • Password-protected PDFs raise a ValueError.
  • GPU support requires manually swapping onnxruntime for onnxruntime-gpu.

Project structure

obliq-OCR/
├── .gitignore
├── README.md
├── pyproject.toml
├── src/
│   └── obliq_ocr/
│       ├── __init__.py      # Public API + version
│       ├── __main__.py      # python -m obliq_ocr
│       ├── cli.py           # obliq-ocr console script
│       ├── core.py          # Main pipeline (DocResult, extract_document, save_result)
│       ├── engine.py        # OCR engine init & device detection
│       ├── parser.py        # Per-page triage, text extraction, OCR
│       ├── schemas.py       # Typed output schema (DocumentOutput, PageOutput, …)
│       └── utils.py         # words_to_lines, garbage_ratio, image helpers
├── tests/
│   ├── __init__.py
│   ├── conftest.py          # Shared fixtures (synthetic + file-based)
│   ├── test_pipeline.py     # All tests
│   └── fixtures/            # Anonymised / synthetic PDFs (not committed)
│       ├── README.md
│       ├── digital.pdf      # ← add before full test run
│       ├── scanned.pdf      # ← add before full test run
│       ├── mixed.pdf        # ← add before full test run
│       └── rotated.pdf      # ← add before full test run
└── docs/                    # (planned) benchmarks and additional docs

License

MIT © 2026 Rahul Kate / OBLIQ

Metadata

Release files for obliq-ocr-test-abhiraj 0.1.0rc2

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for obliq-ocr-test-abhiraj 0.1.0rc2
File Size Uploaded Provenance Actions
obliq_ocr_test_abhiraj-0.1.0rc2.tar.gz 31.9 kB Without provenance Details for obliq_ocr_test_abhiraj-0.1.0rc2.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for obliq-ocr-test-abhiraj 0.1.0rc2
File Interpreter ABI Platform Actions
obliq_ocr_test_abhiraj-0.1.0rc2-py3-none-any.whl Python 3 none any Details for obliq_ocr_test_abhiraj-0.1.0rc2-py3-none-any.whl

Total release size: 51.6 kB

Release files / obliq_ocr_test_abhiraj-0.1.0rc2.tar.gz

Download URL obliq_ocr_test_abhiraj-0.1.0rc2.tar.gz
Size 31.9 kB
Tags Source
SHA-256 checksum
How to use checksums
488a25b6efd5bff0d278524d2558e36e3e970c680f0a32ef3ee54268753ec3db
BLAKE2b-256 checksum
How to use checksums
137e493dd2591034a6d4f8d79ff4d7b3f4c9bfc5b115766db77a3ed8aa97c81b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.16

Release files / obliq_ocr_test_abhiraj-0.1.0rc2-py3-none-any.whl

Download URL obliq_ocr_test_abhiraj-0.1.0rc2-py3-none-any.whl
Size 19.7 kB
Tags Python 3
SHA-256 checksum
How to use checksums
591f3af7e63c50b6f85ecdbe47a2a371a92c49dae445371b26c66974b4813323
BLAKE2b-256 checksum
How to use checksums
fb63af8fc1a54c726f12a1140b61e940027d6ae3e1c71b0a3d80ea177043850c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.16

Security for obliq-ocr-test-abhiraj 0.1.0rc2

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release
Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page