Search by

mpernia / pdf-ocr

mpernia

Extensible PDF reader with native text extraction and optional OCR adapters.

Package info

github.com/mpernia/pdf-ocr

pkg:composer/mpernia/pdf-ocr

Statistics

Installs: 11

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

v1.0.0 2026-10-22 23:28 UTC

This package is auto-updated.

Last update: 2026-10-22 23:58:24 UTC


README

A small, extensible PHP package for reading PDF files as structured documents. It provides generic PDF metadata and page-level access without knowing the business meaning or schema of the document's contents.

Scope: the default reader extracts embedded/selectable text from PDFs using smalot/pdfparser. Scanned pages have no such text; for those, wire an OCR adapter (TesseractCliRecognizer) and a page renderer (PopplerPdfPageRenderer). The package never decides for you which engine runs: you inject it.

Requirements

  • PHP 8.2+
  • Composer
  • Optional, only if you use the bundled adapters: tesseract and/or pdftoppm available on PATH
  • For rendering: fonts installed in the system. pdftoppm fails with "Couldn't find a font" and writes no image on a bare container, so a slim PHP image needs at least one font package (ttf-dejavu on Alpine, fonts-dejavu-core on Debian/Ubuntu)

Install

composer require mpernia/pdf-ocr

Quick start

use Mpernia\PdfOcr\Reader\PdfParserReader;

$reader = new PdfParserReader();
$document = $reader->open('/path/to/document.pdf');

echo $document->getName();
echo $document->getSize();
echo $document->getPageCount();

foreach ($document->getPages() as $page) {
    printf("Page %d: %s\n", $page->getNumber(), $page->getText());
}

$firstPage = $document->getPage(1); // Page numbers are 1-based.

Design

  • PdfReaderInterface: opens a PDF and returns a generic document.
  • PdfDocumentInterface: generic file metadata and page access.
  • PdfPageInterface: generic page number, text, and metadata.
  • PageTextRecognizerInterface: extension point for OCR engines; returns a TextExtractionResult, so a recogniser reports its text and its own confidence.
  • PageTextExtractorInterface: decides the text of a page from its native text and, optionally, a recognizer.
  • PageTextRendererInterface: turns a PDF page into an image, the input an OCR engine needs.
  • PdfParserReader: default adapter for text already embedded in the PDF.

The package deliberately does not parse invoices, embargo notices, contracts, or any other domain-specific document. Consumers own that layer, for example:

final class InvoicePageParser
{
    public function parse(PdfPageInterface $page): InvoicePageData
    {
        // Domain-specific interpretation belongs here.
    }
}

OCR and rendering adapters

Both adapters are opt-in and small wrappers around a CLI tool. Nothing runs unless you construct them, and the arguments are passed as an array to proc_open, never through a shell.

use Mpernia\PdfOcr\Extraction\NativeTextExtractor;
use Mpernia\PdfOcr\Extraction\OcrFallbackTextExtractor;
use Mpernia\PdfOcr\Ocr\TesseractCliRecognizer;
use Mpernia\PdfOcr\Reader\PdfParserReader;
use Mpernia\PdfOcr\Renderer\PopplerPdfPageRenderer;

// Native text when the page has it; OCR only when it does not.
$reader = new PdfParserReader(
    textExtractor: new OcrFallbackTextExtractor(
        nativeExtractor: new NativeTextExtractor(),
        renderer: new PopplerPdfPageRenderer(),
        recognizer: new TesseractCliRecognizer(),
        language: 'spa',
    ),
);
  • TesseractCliRecognizer(string $binary = 'tesseract') runs tesseract <image> stdout [-l <lang>] tsv. It reads Tesseract's TSV output, so the returned TextExtractionResult carries the average confidence of the words actually recognised (0–100), or null when the page produced no text. OcrFallbackTextExtractor propagates that confidence, which makes it easy to flag low-quality recognitions.
  • PopplerPdfPageRenderer(string $binary = 'pdftoppm', ?string $temporaryDirectory = null) renders one page to a PNG (dpi 72–600) and returns its path, which the caller owns. It needs system fonts: without them pdftoppm exits with an error and the renderer throws a RuntimeException carrying its stderr.

Error handling

  • InvalidArgumentException: file does not exist or is not readable, or an adapter argument is out of range.
  • RuntimeException: the PDF cannot be parsed, the page cannot be accessed, or an external binary fails.
  • OutOfBoundsException: requested page number is outside the document.

Development

composer install
composer test   # PHPUnit
composer stan   # PHPStan level 8

The test suite includes a small PDF fixture, so the reader is exercised against a real file and not only against mocks.

License

MIT