Native OCR library using platform-specific frameworks (macOS Vision, Windows Runtime OCR)
Project description
natocr
natocr (native ocr) is a small Python wrapper around the OCR engines that already ship with macOS and Windows: Vision framework on macOS and Windows Runtime OCR on Windows.
These built-in engines are generally faster, more efficient, and more accurate than third-party alternatives like Tesseract. natocr makes reaching for them painless via one clean Python API instead of wrangling with Objective-C bridges or WinRT async plumbing.
Install
pip install natocr[macos] # on macOS
pip install natocr[windows] # on Windows
Quick start
from natocr import OCR
ocr = OCR() # defaults to english
result = ocr.recognize("invoice.png")
print(result.text)
Invoice #1042 Total $58.20 Thank you!
Confidence Scores and Bounding Boxes
recognize() returns an OCRResult. Beyond the flat .text, you get a
per-detection breakdown with bounding boxes and (on macOS) confidence scores:
result = ocr.recognize("receipt.png")
print(result.confidence) # average confidence, or None if unavailable
for element in result.elements:
box = element.bounds.bounds # (x, y, width, height) in pixels
print(f"{element.text!r} @ {box} conf={element.confidence}")
0.93
'Acme Coffee' @ (24.0, 18.0, 180.0, 32.0) conf=0.97
'Latte' @ (24.0, 70.0, 96.0, 28.0) conf=0.95
'$4.50' @ (220.0, 70.0, 80.0, 28.0) conf=0.88
Lines and Words
There's also convenience views for grouping results by reading order:
result.lines # ['Acme Coffee', 'Latte $4.50'] - elements grouped into lines
result.words # list of TextElement with non-empty text
Detection Language
Pick a different recognition language, and inspect what the current platform supports:
ocr = OCR(language="fr")
print(ocr.platform) # 'darwin' or 'win32'
print(ocr.supported_languages) # ['en-US', 'fr-FR', 'de-DE', ...]
The supported set is decided by the OS and queried live, so
supported_languages always reflects the current machine. On macOS it's
Vision's built-in set for your macOS version; on Windows it's whatever OCR
language packs are installed. See the Usage guide
for the full list and how to add Windows language packs.
Alternative Inputs
recognize() accepts more than file paths - hand it whatever you already have
in memory:
from PIL import Image
import numpy as np
ocr.recognize("page.png") # a file path
ocr.recognize(Image.open("page.png")) # a PIL image
ocr.recognize(np.array(image)) # a numpy array (e.g. from OpenCV)
ocr.recognize(open("page.png", "rb").read()) # raw image bytes
Supported File Types
Images are decoded with Pillow, so any raster
format Pillow can open works as an input file or byte string. HEIC/HEIF decoding
is provided by the bundled pillow-heif,
so iPhone photos work with no extra setup. JPEG XL and JPEG XR need a couple of
extra decoders - install them with pip install natocr[extras] (see
JPEG XL and JPEG XR below).
| Format | Extensions | Notes |
|---|---|---|
| PNG | .png |
recommended - lossless |
| JPEG | .jpg, .jpeg |
great for photos of documents |
| JPEG 2000 | .jp2, .j2k, .jpf, .jpx |
wavelet-based, decoded natively by Pillow |
| JPEG XL | .jxl |
modern successor to JPEG (needs natocr[extras]) |
| JPEG XR / HD Photo | .jxr, .wdp, .hdp |
Microsoft HD Photo (needs natocr[extras]) |
| TIFF | .tif, .tiff |
common for scans |
| BMP | .bmp |
uncompressed bitmap |
| GIF | .gif |
first frame is used |
| WebP | .webp |
modern lossy/lossless |
| HEIC/HEIF | .heic, .heif, .hif |
iPhone photos and screenshots |
| PPM/PGM | .ppm, .pgm |
netpbm bitmaps |
JPEG XL and JPEG XR
These two are optional because their decoders are extra dependencies. Install them with:
pip install natocr[extras]
That pulls in pillow-jxl-plugin
for .jxl and imagecodecs for
.jxr/.wdp/.hdp. Once installed they decode through the same recognize()
call as every other format - no extra code. Without the extra, the rest of the
formats above (including JPEG 2000) keep working unchanged.
In addition to file paths, recognize() accepts these in-memory types:
| Input type | Example |
|---|---|
str (file path) |
ocr.recognize("page.png") |
PIL.Image.Image |
ocr.recognize(Image.open("page.png")) |
numpy.ndarray |
ocr.recognize(np.array(image)) |
bytes (encoded image) |
ocr.recognize(data) |
[!NOTE] PDFs and other multi-page documents aren't decoded directly - rasterize a page to one of the formats above first (e.g. with
pdf2imageorpymupdf).
Testing
Install the dev dependencies (in a virtualenv), then run the suite. The tests mock the native macOS Vision and Windows Runtime backends, so they run anywhere without those frameworks installed.
python3 -m venv .venv
source .venv/bin/activate
pip install -e ".[dev]"
Run everything with coverage (coverage is wired up in pyproject.toml, so plain
pytest already reports it):
pytest
Other handy invocations:
# run a single test file
pytest tests/test_models.py
# run one test by name
pytest -k test_lines_groups_close_y_into_single_line
# verbose output
pytest -v
Coverage reports land in the terminal, in htmlcov/index.html, and in
coverage.xml.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file natocr-1.5.3.tar.gz.
File metadata
- Download URL: natocr-1.5.3.tar.gz
- Upload date:
- Size: 20.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
39282c05495a590cfa8e4699c4d6c7be791e5084b805b79d5ef9271bebeafbff
|
|
| MD5 |
f015cf64217dc3dbb4dcd28aaf1a6ea5
|
|
| BLAKE2b-256 |
005dd0d8ba04d8a564c4033743c612bd5f05880c479e0ad299d348da78cede04
|
File details
Details for the file natocr-1.5.3-py3-none-any.whl.
File metadata
- Download URL: natocr-1.5.3-py3-none-any.whl
- Upload date:
- Size: 12.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1f7b7d838ff5d1d1fe68ab9a8e1f537a96312cf24ada726194f7834559ffd114
|
|
| MD5 |
47b48b226ce7de45d752209d6d772501
|
|
| BLAKE2b-256 |
a6a1373b79e80bf4a4fc8ea98fe3710bb481ec83d60a84be2a23ed774cd24460
|