Tools,

TrOCR on 100 real handwritten notes, tested

57%

of handwritten words found, with RapidOCR lines

Get the script

Find the lines, then read them

2.2 s a note, Mac GPU

1.3 GB model download

  1. Run pip install torch transformers pillow rapidocr onnxruntime.
  2. Save trocr.py below. Run python trocr.py note.jpg.
  3. It prints one line of text for each box that RapidOCR finds.
trocr.py
# pip install torch transformers pillow rapidocr onnxruntime
# Run: python trocr.py note.jpg
import sys

import torch
from PIL import Image, ImageOps
from rapidocr import RapidOCR
from transformers import TrOCRProcessor, VisionEncoderDecoderModel

M = "microsoft/trocr-base-handwritten"
dev = "mps" if torch.backends.mps.is_available() else "cpu"
proc = TrOCRProcessor.from_pretrained(M)
model = VisionEncoderDecoderModel.from_pretrained(M).to(dev).eval()
find = RapidOCR(params={"Global.use_cls": False})

# Turn the photo upright first: phones store many notes sideways.
img = ImageOps.exif_transpose(Image.open(sys.argv[1])).convert("RGB")
w, h = img.size

# TrOCR reads one line at a time, so RapidOCR finds the text boxes.
quads = find(img, use_cls=False, use_rec=False).boxes
boxes = []
for q in [] if quads is None else quads.tolist():
    xs, ys = [p[0] for p in q], [p[1] for p in q]
    boxes.append([round(min(xs)), round(min(ys)), round(max(xs)), round(max(ys))])

for x0, y0, x1, y1 in sorted(boxes, key=lambda b: (b[1], b[0])):
    pad = max(4, round(0.1 * (y1 - y0)))
    box = (max(0, x0 - pad), max(0, y0 - pad), min(w, x1 + pad), min(h, y1 + pad))
    px = proc(images=img.crop(box), return_tensors="pt").pixel_values.to(dev)
    with torch.no_grad():
        ids = model.generate(px, max_new_tokens=64)
    print(proc.batch_decode(ids, skip_special_tokens=True)[0])

On load, transformers prints that the encoder.pooler weights are missing. TrOCR does not use them. Every score here came with that message.

The line finder sets the score

Words found, of 5,473 on 100 notes
TrOCR, true line boxes
60%
TrOCR, RapidOCR boxes
57%
RapidOCR alone
56%
TrOCR, Tesseract lines
39%

The true boxes come with the notes, so no line finder can beat them. Tesseract lines were from --psm 6. With the default --psm 3, TrOCR found 32%.

On a Mac, keep Tesseract's input out of /tmp. It failed with:

Leptonica Error in findFileFormat: image file not found: /tmp/note.jpg

The same file under /private/tmp worked.

A whole page gets two words

Given each whole note as one image, TrOCR wrote 2 words at the median. It found 41 of 5,473 words.

Turn sideways photos first

Phones often save a photo sideways, with an EXIF tag that says how to turn it. 19 of the 100 notes have one. Image.open() does not turn them.

19 turned notes, words found of 1,183
Photo Words
exif_transpose first 656
As stored 51

The other 81 notes gave the same total both ways.

Wrong words that look right

A handwritten note in blue ink on lined paper, about a court's power to make orders pending an appeal
From GNHK by Lee, Chung and Lee (GoodNotes), CC BY 4.0. Resized. The totals above are the fair numbers.

TrOCR with true line boxes wrote:

Order of rule 6 -
The Court has the power to make orders
the way of injunctions and such necessary
Order's rights protection of property
person spending the destruction of
for even though no such application was
made in the Court below .

TrOCR with RapidOCR boxes wrote:

Order of rule 6 -
the court has the power to remember
0 0 0
Members for the
0 0
to have been
made in the fourth bottom .

"Pending the determination" became "spending the destruction". No spell check catches that.

No better than RapidOCR alone

Same 100 notes, same scorer
Engine Found Right
PaddleOCR 62% 69%
TrOCR, RapidOCR boxes 57% 56%
RapidOCR alone 56% 59%
Our Actor 53% 58%
Tesseract 9% 19%

Found is the share of true words. Right is the share of output words that are true. TrOCR took 2.2 s a note on the GPU. RapidOCR alone took 0.36 s on the CPU.

MIT, for the base model

I read the licenses before the download. trocr-base-handwritten has the MIT tag, and Microsoft's unilm repository is MIT. The small and large handwritten models had no license tag, so I did not run them.

Our Actor reads print, and some handwriting

Since November 5, our Actor has RapidOCR read English pages that Tesseract reads badly. On these notes it found 53%. Check its output by eye. Our service reads print only.

How I tested it
  • Notes: the 100 GNHK test notes of Tesseract handwriting, phone photos and scans, 5,473 true words.
  • Score: true words found in any order, with the scorer of that page. Right: true words over all output words.
  • microsoft/trocr-base-handwritten revision eaacaf4, transformers 5.22.2, torch 2.15.0, on an Apple Silicon Mac GPU, at the lowest priority, 2 CPU threads, one note at a time.
  • Lines: RapidOCR 3.10.0 boxes (detection only), Tesseract 5.5.4 TSV lines, or the GNHK word boxes joined per line. Each box gets a margin of 10% of its height, at least 4 px.
  • Up to 64 new tokens a line. The model's own settings found 1 word less with the true boxes.
  • Time: the median per note, with the model loaded and line finding included. One run.
  • The other engines: the same notes and scorer, on November 4, CPU only. The Actor row is build 0.1.43 code, run on this Mac.
What I did not test
  • trocr-large-handwritten and trocr-small-handwritten.
  • The TrOCR models for printed text.
  • CPU speed, and training on your own writing.
  • Other line finders, for example PaddleOCR boxes.
Sources

Two ways to skip the work

Run it yourself. Our Apify Actor turns scanned PDFs into Markdown, tables included.

Try the Actor

Or send us the scan. Tack, our AI, does the job for $29, up to 50 pages. First page free.

Get one page free

Questions people ask

Can TrOCR read a full page?

Not by itself. It reads one line per image. Given whole notes, it found 41 of 5,473 words. Cut the page into lines first, for example with RapidOCR.

Is TrOCR better than PaddleOCR for handwriting?

Not on these 100 notes. PaddleOCR found 62% of the words. TrOCR with RapidOCR lines found 57%.

What license does TrOCR have?

trocr-base-handwritten has the MIT tag on Hugging Face, and Microsoft's unilm repository is MIT. The small and large handwritten models had no license tag on November 13, 2026.