Tools,

Tess4J on Mac and Linux, tested on 55 scans

2.6x

less CPU with one engine

Fix the setup

Unable to load library: install Tesseract

Ubuntu without Tesseract:

java.lang.UnsatisfiedLinkError: Unable to load library 'tesseract':
libtesseract.so: cannot open shared object file: No such file or directory

The jar carries Tesseract for Windows only. On Mac and Linux, install it, and Tess4J finds it:

System Install Found
Ubuntu 26.04.1 sudo apt-get install tesseract-ocr libtesseract.so.5
Mac, Apple Silicon brew install tesseract /opt/homebrew/lib

Then set the models folder

With Tesseract in place, the next run can fail like this:

Error opening data file ./eng.traineddata
java.lang.IllegalArgumentException: Specified language data does not exist.

Tess4J looks in TESSDATA_PREFIX, else in the folder you run from. Set the path, as in the code below. On Ubuntu it is /usr/share/tesseract-ocr/5/tessdata.

The jar also carries eng.traineddata, the same file as Homebrew's. To use it, copy it out first:

tess.setDatapath(LoadLibs.extractTessResources("tessdata").getPath());

The code, run on 55 scans

<dependency>
  <groupId>net.sourceforge.tess4j</groupId>
  <artifactId>tess4j</artifactId>
  <version>5.21.0</version>
</dependency>
import java.io.File;
import net.sourceforge.tess4j.Tesseract;

public class Ocr {
  public static void main(String[] args) throws Exception {
    Tesseract tess = new Tesseract();
    tess.setDatapath("/opt/homebrew/share/tessdata");
    tess.setLanguage("eng");
    tess.setPageSegMode(3);
    tess.setVariable("user_defined_dpi", "300");
    System.out.println(tess.doOCR(new File("scan.jpg")));
  }
}

Run as printed, it wrote the tesseract command's text on 55 of 55 scans.

Set psm 3 to match the command

Without setPageSegMode, Tesseract's own default applies: psm 6, the page as one block. The command uses psm 3, which finds the layout first.

9 of 55 scans, the command's text without it

13,839 words found, 19 fewer

My scans have one column. I did not test pages with more.

Same text, 23% more CPU

55 of 55 scans, the same text

13,858 of 14,693 words found, both

CPU seconds, Tesseract 5.5.4
Job Command Tess4J
55 full pages 147.3 s 181.7 s
259 line images 50.9 s 52.8 s

Tess4J writes each image as a PNG in memory before Tesseract reads it. In a profile run, that took 34.4 s of 191.0 s.

Many small images: keep one engine

doOCR loads the model again on every call. Keep one engine with the low-level API instead:

TessBaseAPI api = TessAPI1.TessBaseAPICreate();
TessAPI1.TessBaseAPIInit3(api, "/opt/homebrew/share/tessdata", "eng");
TessAPI1.TessBaseAPISetPageSegMode(api, 7);
TessAPI1.TessBaseAPISetVariable(api, "user_defined_dpi", "300");
for (File f : files) {
  BufferedImage img = ImageIO.read(f); // 8-bit gray
  ByteBuffer px = ImageIOHelper.convertImageData(img);
  TessAPI1.TessBaseAPISetImage(api, px, img.getWidth(), img.getHeight(), 1, img.getWidth());
  Pointer text = TessAPI1.TessBaseAPIGetUTF8Text(api);
  System.out.print(text.getString(0));
  TessAPI1.TessDeleteText(text);
}
TessAPI1.TessBaseAPIDelete(api);

20.2 s for 259 lines, not 52.8 s

All 259 lines, the command's text

This version takes 8-bit gray images, like my line crops. I did not test it on color.

PDFs work, at twice the CPU

Pass a PDF to doOCR and Tess4J renders each page at 300 dpi with PDFBox. I made a 10-page PDF from the scans.

1,878 of 1,955 words, as from the JPEGs

6.8 s of CPU a page, not 3.3 s

It deleted its temporary files.

How I tested it
  • Pages: 55 proofread Wikisource scans from 11 printed books, JPEG, 1,920 pixels wide, no dpi in the file. The same set as Tesseract in Docker.
  • Score: true words found in order, with the scorer of the tessdata test.
  • Apple Silicon Mac, OpenJDK 21, Maven 3.9.16, Tess4J 5.21.0, Homebrew Tesseract 5.5.4, tessdata_fast English.
  • Ubuntu: Docker, eclipse-temurin:21-jdk on arm64, apt-get as root with --no-install-recommends.
  • Time is CPU time of the whole process tree, JVM start included, on the Mac's efficiency cores. Pages: median of 3 rounds. Lines and PDF: 1 round.
  • Line images: the 259 PNG crops of the tesserocr test, psm 7.
What I did not test
  • Windows, Intel Macs, x86-64 Linux, and older Tess4J.
  • Threads, wall time, and color images on the one-engine code.
  • Other languages, tessdata_best, and photos.
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

Do I need libtesseract-dev?

Not on Ubuntu 26.04.1. The tesseract-ocr package brings libtesseract.so.5, and Tess4J 5.21.0 loaded it. I did not test older Ubuntu or Debian releases.

Which Tesseract does Tess4J use?

On Mac and Linux, the one you installed. Tess4J reported 5.5.4 from Homebrew and 5.5.0 from Ubuntu. The jar carries a Tesseract only for 64-bit Windows.

Does it give the same text as the command?

Yes, byte for byte on 55 of 55 scans, with the same Tesseract, the same model, psm 3 and 300 dpi on both. Every round gave the same text.