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.
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
| Format | Contents |
|---|---|
pdf (default) | Original image as background, invisible text layer overlaid per word. |
txt | Recognized text, one output line per Tesseract text line. |
json | See schema below. |
tsv | Flat, 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. |
hocr | Minimal hOCR document (ocr_page / ocr_line / ocrx_word), a standard other OCR tooling can consume. |
JSON schema
{
"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.
--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.
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.