scanlayer
Docs / Guides

Output Formats

By default scanlayer builds a searchable PDF, but the same OCR result (text, per-word confidence, bounding boxes) can be exported directly with --format / output_format=, without building a PDF at all.

bash
scanlayer invoice.jpg -o invoice.txt --format txt
scanlayer invoice.jpg -o invoice.json --format json
scanlayer invoice.jpg -o invoice.tsv --format tsv
scanlayer invoice.jpg -o invoice.hocr --format hocr

The four formats

FormatContents
pdf (default)Original image as background, invisible text layer overlaid per word.
txtRecognized text, one output line per Tesseract text line.
jsonSee schema below.
tsvFlat, tab-separated word list: text, confidence, x, y, width, height, line_id. A simple custom schema (not Tesseract\u2019s own TSV layout), chosen to load easily into a spreadsheet or pandas.
hocrMinimal hOCR document (ocr_page / ocr_line / ocrx_word), a standard other OCR tooling can consume.

JSON schema

jsoninvoice.json
{
  "text": "INVOICE #2024-118\nBill to: Nautilus Fittings Ltd.\n...",
  "mean_confidence": 91.2,
  "best_psm": 6,
  "language": "fra+eng",
  "image_width": 2480,
  "image_height": 3508,
  "words": [
    {"text": "INVOICE", "confidence": 96.4, "bbox": [180, 92, 410, 130]},
    {"text": "#2024-118", "confidence": 93.1, "bbox": [420, 92, 610, 130]}
  ]
}

bbox is [x0, y0, x1, y1] in pixels, in the coordinate space of the (orientation-corrected) source image.

Reading order

Word order and line grouping in every exported format follow the pipeline's reading order, which is Tesseract's own block/paragraph/line numbering, corrected for genuine multi-column pages by the same geometric reordering step the PDF builder uses (see multi-column layout reconstruction). This is correct for single-column pages, correctly-reordered multi-column prose, and most simple layouts.

Table-like layouts are not reordered Multi-column detection deliberately does not target tables: a table\u2019s narrow, per-row gutters do not look like a page-wide column break. A wide invoice table can still read out of order in the export if it is dense enough to resemble a column layout to the detector; verify with --debug-image if a table-heavy document looks wrong. See Troubleshooting.

PDF text layer construction

pdf/builder.py draws the original image as the page background, then overlays each recognized word as invisible text (PDF render mode 3), stretched to match its detected bounding box. Compression is adaptive: PNG for near-binary text pages, JPEG otherwise, with automatic grayscale encoding when the source is not in color.

Calling the exporter directly

Useful when you already have a Word list from scanlayer.ocr.engine.extract_words() and want to skip the CLI, or convert(), entirely.

python
from scanlayer.ocr.export import export_words

content = export_words(
    "json", words, mean_confidence=91.2, best_psm=6,
    language_used="eng", image_width=2480, image_height=3508,
    source_name="invoice.jpg",
)

See Library API → Low-level API for the individual to_text/to_json/to_tsv/to_hocr functions this dispatches to, and the important caveat about reading order when you call those directly on raw extract_words() output.