Recursive AI

Getting started with OneOcr

All oneocr docs

Install OneOcr for .NET 10, read the text of an invoice image, walk the page model with its boxes and confidences, turn the page into Markdown, and set a default engine. No native binaries, no tessdata, no network.

Install

OneOcr targets net10.0, so you need the .NET 10 SDK. Every package shares one version; this guide uses 1.0.0.

Terminal
dotnet new console -o OneOcrStart
cd OneOcrStart
dotnet add package RecursiveAI.OneOcr --version 1.0.0

RecursiveAI.OneOcr brings in RecursiveAI.OneOcr.Models, which embeds the recognizer, the page detector and the two word models and checks them against their SHA-256 pins on every load. There is nothing to download and no model path to set. Pixels come from OneImage, so any OneImage.Image (PNG, JPEG, WebP, TIFF and so on) is an input. The same weights are also attached to the v1.0.0 release on GitHub for OcrEngine.Load(path) and .WithDetector(path).

The sample images

The guide and the cookbook read two images. invoice.png is a one-page A4 invoice rendered from HTML at 300 DPI (2481 × 3509 pixels), with a seller and buyer block, a table of items and totals. receipt.png is a till receipt rendered at twice screen resolution (920 × 940). Any PNG or JPEG of a flat document works the same way; the outputs below are what 1.0.0 printed for these two.

Read the text

OcrEngine.LoadBundled() loads the bundled models. An engine is immutable and thread-safe: load it once and share it. ToText returns the page in reading order, with lines separated by a newline and table cells by a tab:

C#
using OneImage;
using OneOcr;
 
OcrEngine engine = OcrEngine.LoadBundled();      // once at startup; immutable and thread-safe
 
Image image = Image.Load("invoice.png");
Console.WriteLine(image.ToText(engine));
Text
Northwind Supply Ltd
14 Harbour Street
BS1 4DJ Bristol
United Kingdom
VAT ID: GB284193752
INVOICE
Bill to
Blue Heron Bakery
88 Elm Road
OX1 2JD Oxford
United Kingdom
Invoice no.
INV-2041
Date
Due date
Order no.
14/10/2026
13/11/2026
PO-7731
Description	Qty	Unit price	VAT	Amount
Flour, 25 kg bag	4 pcs	31.50	0%	126.00
Cane sugar, 10 kg	2 pcs	18.25	0%	36.50
Baking parchment roll	6 pcs	7.40	20%	44.40
Payment terms: Payable within 30 days
Subtotal
VAT total
Total
£206.90
£8.88
£215.78
IBAN: GB33 BUKB 2020 1555 5555 55	BIC: BUKBGB22	Tel. +44 117 496 0321

The page detector found the table and the blocks; reading order goes block by block, so the labels of the meta grid and the totals come before their values.

The page model

Ocr runs the same pipeline and returns the whole OcrPage: blocks, lines, words and characters with boxes, tables, key–value pairs and diagnostics. Coordinates are pixels from the top left, y down. A word’s Confidence is the calibrated probability that it is exactly right:

C#
using OneImage;
using OneOcr;
 
OcrEngine engine = OcrEngine.LoadBundled();
OcrPage page = Image.Load("invoice.png").Ocr(engine);
 
Console.WriteLine($"{page.Width} x {page.Height}, {page.Blocks.Count} blocks, {page.Words.Count} words, {page.Tables.Count} table");
foreach (OcrWord word in page.Blocks[0].Lines[0].Words)
    Console.WriteLine($"{word.Text,-10} {word.Confidence:F3}  ({word.Box.Left:F0}, {word.Box.Top:F0}) to ({word.Box.Right:F0}, {word.Box.Bottom:F0})");
foreach (OcrDiagnostic diagnostic in page.Diagnostics)
    Console.WriteLine($"{diagnostic.Code}: {diagnostic.Message}");
Text
2481 x 3509, 19 blocks, 98 words, 1 table
Northwind  0.986  (231, 198) to (580, 247)
Supply     1.000  (614, 198) to (845, 260)
Ltd        0.974  (878, 200) to (963, 247)
OCR101: UnitsPerInch is estimated at 200 from the size of the text; pass OcrOptions.Dpi to set it.
OCR107: 1 word(s) read from specks, grain or stray marks were dropped as noise; pass OcrOptions.DropNoise = false to keep them.

Diagnostics say what the reader decided on its own. This PNG doesn’t declare a resolution, so OCR101 says it was estimated; pass new OcrOptions { Dpi = 300 } when you know it. It only sets UnitsPerInch: recognition doesn’t depend on it.

Markdown

ToMarkdown builds Markdown from the page model with no model call: headings from text size, lists, and pipe tables from detected tables, with headers, footers and page numbers dropped.

C#
using OneImage;
using OneOcr;
 
OcrEngine engine = OcrEngine.LoadBundled();
Console.WriteLine(Image.Load("invoice.png").ToMarkdown(engine));
Text
Northwind Supply Ltd 14 Harbour Street BS1 4DJ Bristol United Kingdom VAT ID: GB284193752
 
# INVOICE
 
## Bill to
 
Blue Heron Bakery 88 Elm Road
 
OX1 2JD Oxford United Kingdom
 
Invoice no.
 
INV-2041
 
Date
 
Due date
 
Order no.
 
14/10/2026
 
13/11/2026 PO-7731
 
| Description | Qty | Unit price | VAT | Amount |
| --- | --- | --- | --- | --- |
| Flour, 25 kg bag | 4 pcs | 31.50 | 0% | 126.00 |
| Cane sugar, 10 kg | 2 pcs | 18.25 | 0% | 36.50 |
| Baking parchment roll | 6 pcs | 7.40 | 20% | 44.40 |
 
Payment terms: Payable within 30 days
 
Subtotal
 
VAT total
 
Total
 
£206.90
 
£8.88
 
£215.78
 
IBAN: GB33 BUKB 2020 1555 5555 55 BIC: BUKBGB22 Tel. +44 117 496 0321

A default engine

If you’d rather not pass the engine around, set a process-wide default once. The extension methods without an engine argument then use it; until you call ConfigureDefault, OcrEngine.Default throws InvalidOperationException.

C#
using OneImage;
using OneOcr;
 
OcrEngine.ConfigureDefault();                    // the bundled models become OcrEngine.Default
Console.WriteLine($"Kernels: {OcrEngine.Default.KernelPath}");
 
string text = Image.Load("receipt.png").ToText();   // no engine argument: the default is used
Console.WriteLine(text);
Text
Kernels: Avx512
Corner Market
1402 Oak Street
78704 Austin
+1 512 555 0142
Date: 24/10/2026
Time: 14:32
Coffee beans	12.99
2x Oat milk	8.98
Bagels	5.25
Subtotal	27.22
Tax 8.25 %	2.07
TOTAL	$ 29.29
Paid by	Card **** 4821
Thank you!

KernelPath says which kernels run: Avx512, Avx2, Vector128 or Scalar. The text, boxes and confidences are the same on all four (Same bytes on every machine).

Good to know

  • Every local call takes a CancellationToken and has an Async twin (OcrAsync, ToTextAsync, ToMarkdownAsync) that returns the same result.
  • Ocr(Image) reads one page and throws ArgumentException for an image with several frames; OcrPages reads every frame of a TIFF.
  • Errors are typed: OcrFormatException for bytes that aren’t what they claim to be, OcrLimitException when an OcrLimits bound is crossed (checked before anything large is allocated), OcrModelException for a bad model file.
  • Scripts: Latin (including the EU languages, Turkish and Vietnamese), Greek and Cyrillic in one recognizer. CJK, Arabic and Indic scripts, handwriting and scene text are not supported yet.

Next