OCR_Tools / ocr_engine.py
Claude
Add OCR notification/data extractor Gradio app for Hugging Face Spaces
2a9e166 unverified
Raw
History Blame Contribute Delete
2.29 kB
"""PDF/image loading and OCR.
Native (embedded) text is pulled straight out of the PDF when present;
pages without a usable text layer (scanned documents) are rendered to an
image and run through Tesseract instead.
"""
import os
import fitz # PyMuPDF
import pytesseract
from PIL import Image
MIN_EMBEDDED_TEXT_LEN = 20
RENDER_DPI = 300
IMAGE_EXTENSIONS = {".png", ".jpg", ".jpeg", ".tif", ".tiff", ".bmp"}
def _ocr_image(img):
data = pytesseract.image_to_data(img, output_type=pytesseract.Output.DICT)
confidences = [int(c) for c in data.get("conf", []) if str(c).isdigit() and int(c) >= 0]
mean_conf = round(sum(confidences) / len(confidences), 1) if confidences else None
text = pytesseract.image_to_string(img)
return text, mean_conf
def _process_pdf(file_path):
pages = []
doc = fitz.open(file_path)
try:
for page_num, page in enumerate(doc, start=1):
embedded_text = page.get_text().strip()
if len(embedded_text) >= MIN_EMBEDDED_TEXT_LEN:
pages.append({
"page": page_num,
"text": embedded_text,
"source": "embedded",
"ocr_confidence": None,
})
continue
pix = page.get_pixmap(dpi=RENDER_DPI)
img = Image.frombytes("RGB", [pix.width, pix.height], pix.samples)
ocr_text, mean_conf = _ocr_image(img)
pages.append({
"page": page_num,
"text": ocr_text.strip(),
"source": "ocr",
"ocr_confidence": mean_conf,
})
finally:
doc.close()
return pages
def _process_image(file_path):
img = Image.open(file_path).convert("RGB")
text, mean_conf = _ocr_image(img)
return [{
"page": 1,
"text": text.strip(),
"source": "ocr",
"ocr_confidence": mean_conf,
}]
def extract_pages(file_path):
"""Return a list of {page, text, source, ocr_confidence} dicts for a file."""
ext = os.path.splitext(file_path)[1].lower()
if ext == ".pdf":
return _process_pdf(file_path)
if ext in IMAGE_EXTENSIONS:
return _process_image(file_path)
raise ValueError(f"Unsupported file type: {ext}")