qocr

command module
v0.0.0-...-14846cb Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 27, 2026 License: GPL-3.0 Imports: 35 Imported by: 0

README ยถ

๐Ÿ“„ qocr

logo.png

Go Report Card Go Reference

A lightweight, self-contained CLI that extracts structured text from images, multi-page PDFs, and EPUB books using either the Baidu Unlimited-OCR model (default), the GLM-OCR model, or the built-in native text-layer extractor (no inference engine needed, no GPU, no network) โ€” all selectable via flags.

[!IMPORTANT] The -native mode (PDF) and EPUB mode require no inference engine. They read text directly from the document's embedded text layer. The AI-powered modes still require an OpenAI-compatible inference engine (such as vLLM). See the Native Text Extraction and EPUB Conversion sections for details.


๐Ÿ“‹ Prerequisites

Inference Engine

The CLI sends rendered page images to a chat-completions endpoint. By default it expects the server at http://localhost:8080.

Quick start Baidu Unlimited-OCR with vLLM (recommended):

docker run --gpus all \
  --privileged --ipc=host -p 8000:8000 \
  -v ~/.cache/huggingface:/root/.cache/huggingface \
  vllm/vllm-openai:unlimited-ocr baidu/Unlimited-OCR \
  --trust-remote-code \
  --logits_processors vllm.model_executor.models.unlimited_ocr:NGramPerReqLogitsProcessor \
  --no-enable-prefix-caching \
  --mm-processor-cache-gb 0 \
  --tensor-parallel-size 1

Quick start GLM-OCR with vLLM:

vllm serve zai-org/GLM-OCR \
  --allowed-local-media-path / \
  --port 8000 \
  --gpu-memory-utilization 0.75 \
  --speculative-config '{"method": "mtp", "num_speculative_tokens": 1}'

Quick start with Ollama:

If you are using Ollama (which runs on port 11434 by default), you can run GLM-OCR locally.

[!TIP] By default, Ollama configures model instances with a small context window (num_ctx 2048) and output generation limit (num_predict 128). High-resolution images (like the default 200 DPI PDF renders) translate to a high number of visual tokens, filling up the default context window and causing Ollama to truncate its responses early.

To run with Ollama, you have two options:

  • Option A (Zero-Setup Sweetspot): Just run the CLI with a lower resolution of -dpi 75 (requires no changes to Ollama):
    ocr -endpoint http://localhost:11434 -model glm-ocr:latest -dpi 75 document.pdf
    
  • Option B (Use full 200 DPI): Create a custom model in Ollama with expanded limits:
    1. Create a text file named Modelfile containing:
      FROM glm-ocr:latest
      PARAMETER num_ctx 8192
      PARAMETER num_predict 4096
      
    2. Register the customized model version in Ollama:
      ollama create glm-ocr-large -f Modelfile
      
    3. Run the CLI targeting the new model and Ollama endpoint:
      ocr -endpoint http://localhost:11434 -model glm-ocr-large document.pdf
      

Remote server:

If the engine runs on another host, simply specify the endpoint. Images are automatically embedded and sent as base64 data-URIs:

qocr -endpoint http://10.0.0.5:8000 document.pdf

โœจ Key Features

  • ๐Ÿš€ Zero Dependencies: Built with pure Go + WebAssembly. No need for poppler, mupdf, or any system-level PDF tools.
  • ๐Ÿ“ฆ Self-Contained: PDF rendering is embedded inside the binary. Single file, works everywhere.
  • ๐Ÿ”Œ Multi-Engine Support: Powered by Baidu Unlimited-OCR by default (-engine baidu), with support for GLM-OCR (-engine glm) and the built-in native text-layer extractor (-native) โ€” same CLI flags, same output formats.
  • ๐Ÿ“‘ Robust Multi-Page PDF Support: Renders pages locally, then dispatches to the engine โ€” page-by-page by default (use -batch-size to group multiple pages per request for Baidu to leverage native multi-page reasoning), or sequentially for GLM-OCR.
  • ๐Ÿ”ค Native Text Extraction: For digitally-born PDFs, extract text, headings, and tables directly from the PDF's internal text layer with zero inference โ€” offline, instant, GPU-free.
  • ๐Ÿ“š EPUB Conversion: Convert EPUB books to Markdown, HTML, JSON, LaTeX, or plain text โ€” no AI, no OCR, no network. Auto-detected by file extension.
  • ๐ŸŽฏ Multiple Outputs: Get results in Markdown, HTML, Plain Text, JSON, or LaTeX.
  • ๐ŸŒ Cross-Platform: Compiled for Linux, macOS, and Windows (AMD64 & ARM64).

๐Ÿ› ๏ธ Build & Install

Ensure you have Go 1.25+ installed.

# Build for your current platform (default target)
make

# Cross-compile for all supported platforms (linux, darwin, windows for amd64 & arm64)
make build-all

# Install to your Go bin directory
make install

The resulting binaries will be placed in the dist/ folder. You can install the qocr binary to your system PATH using:

# After building
sudo cp dist/qocr /usr/local/bin/qocr  # Linux/macOS
# or
copy dist\qocr.exe "C:\Program Files\qocr\qocr.exe"  # Windows

The resulting binaries will be placed in the dist/ folder.


๐Ÿ“– Usage

The CLI supports flags in any position (before or after the input file). You can use either a single dash - or a double dash --.

ocr [options] <file>
Options
Flag Description Default
-endpoint API base URL http://localhost:8080
-port Override port in endpoint URL 0 (uses port from endpoint)
-model Model name baidu/Unlimited-OCR (or zai-org/GLM-OCR in glm mode)
-engine OCR engine to use: baidu, glm, native, hybrid, or epub baidu
-baidu Use Baidu engine (alias for -engine baidu) false
-glm Use GLM engine (alias for -engine glm) false
-native Extract text from PDF text layer โ€” no OCR, no AI, no network false
-hybrid Use native PDF text with Baidu table OCR false
-epub Force EPUB extraction mode (auto-detected by .epub extension) false
-prompt Instruction sent with the file Automatic prompt recipe (<image>document parsing. / <image>Multi page parsing.)
-output Write output to file instead of stdout stdout
-dpi PDF rendering resolution 200
-resume Resume previous execution if interrupted true
-markdown Output as Markdown true
-html Output as HTML document (1:1 detection indexing with inline metadata) false
-text Output as plain text (flattens tables) false
-json Output as structured JSON (includes dimensions & rotation metadata) false
-latex Output as LaTeX document fragment (tables are auto-scaled) false
-bbox Embed normalized bounding boxes as HTML comments in markdown false
-batch-size Number of pages per request (Baidu mode only, 0 = one per request) 0 (one page per request)
-max-tokens Max tokens to generate (0 means use default: 8192 for baidu, unset for glm) 0
-raw Dump raw model response (debug) false
-help Show usage information false
-version Print version and exit false

๐Ÿ’ก Examples

Basic OCR

Prints formatted Markdown to your terminal:

qocr scan.png
Multi-page PDF to File

Renders all pages and combines them into a single Markdown document. Flags can follow the filename:

qocr document.pdf -output result.md -dpi 150
Remote Server

Specify the custom endpoint when the vLLM server is on a different machine:

qocr -endpoint http://10.0.0.5 invoice.pdf
Structured Data

Extract raw JSON data for programmatic use:

qocr -json -output result.json document.pdf
Using the Baidu Alias

Use the handy -baidu flag as an alias:

qocr -baidu document.pdf -output result.txt
Using the Baidu Unlimited-OCR Engine

The Baidu engine is the default, so you can omit -engine baidu and just set a custom endpoint or model:

qocr -endpoint http://192.168.0.12:4000 -model baidu/Unlimited-OCR document.pdf -latex -output result.tex
Native PDF Extraction (No OCR)

For digitally-born PDFs โ€” reports, papers, word-processor exports โ€” extract text and tables instantly without any inference engine:

qocr -native document.pdf -output result.md
EPUB Conversion (No OCR)

Convert any EPUB book to your desired output format instantly. The .epub extension is auto-detected โ€” no flags needed:

qocr book.epub -output book.md
qocr book.epub -json -output book.json
qocr book.epub -latex -output book.tex

Both the GLM-OCR and Baidu Unlimited-OCR models require images as input. Since neither model can process raw PDF blobs directly, this CLI performs the following steps (engine-dependent behaviors are noted inline):

  1. PDF Rendering: Uses go-pdfium running on the wazero WebAssembly engine to render PDF pages into images. The default is 200 DPI, which is optimal for balance between speed and OCR quality.
  2. Sequential vs. Batched Processing: With the glm engine, pages are sent one at a time to avoid overwhelming the GPU or hitting context limits. With the baidu engine, pages are sent one at a time by default (use -batch-size to group multiple pages into a single request for native multi-page reasoning). The CLI prints a beautiful, color-coded real-time dashboard of current progress and timing.
  3. Automatic Resuming: If -resume is enabled, the CLI computes a unique SHA-256 hash representing the input file (path, size, modification time) and API parameters (including the chosen engine). Every successfully processed page is saved locally to your system cache directory (~/.cache/ocr-cli/ or equivalent). If interrupted, re-running the same command will restore all cached pages and skip API calls, resuming right where it left off. Cache files are cleaned up upon successful completion.
  4. Structured Parsing: The results are combined and parsed into the chosen format. Engine-specific output formats (GLM-OCR's JSON array of blocks, Baidu's markdown laced with <|det|> grounding tokens and <PAGE> page markers) are normalized into the requested output format. If the model returns mixed content, the CLI extracts the JSON part automatically.

๐Ÿ“ฆ Output Formats

๐Ÿ“ Markdown (Default)

Maps block labels (title, text, table, figure) to appropriate Markdown elements. Multi-page documents are separated by --- lines and include page comments.

๐ŸŒ HTML (-html)

Converts detections directly into structured, editable HTML elements (<h1>, <h2>, <p>, ocr-table, ocr-image, ocr-page-number) with data-detection-index attributes for 1:1 indexing and DOM manipulation/translation.

๐Ÿ“„ Plain Text (-text)

Strips all Markdown decoration and flattens tables for easy copy-pasting or grep-ing.

๐Ÿ”ข JSON (-json)

Returns a full structured object containing the source path, model used, a list of page metadata (width, height, DPI, rotation), and a list of all detected blocks with their coordinates (bbox_2d).

๐Ÿงฎ LaTeX (-latex)

Returns a LaTeX document fragment containing the OCRed text paragraphs and tables. Tables are dynamically measured: if a table's natural width exceeds the page's text line width, it is auto-scaled down using a native LaTeX savebox conditional wrapper to fit within the margins; narrow tables are left at their natural size to prevent ugly layout stretching.


๐Ÿค– Baidu Unlimited-OCR Engine

The CLI supports the Baidu Unlimited-OCR model via -engine baidu. Key features of this integration:

  • Recipes: Automatic instruction tuning based on page count (<image>document parsing. for single page, <image>Multi page parsing. for multi-page).
  • Logit Processor Configuration: Passes the official "custom_logit_processor": "DeepseekOCRNoRepeatNGramLogitProcessor" and "custom_params" (ngram_size and window_size) configuration parameters, preventing infinite loops and text repetition on the server.
  • Batching: Processes page-by-page sequentially by default (batch size of 1) for maximum memory stability, avoiding out-of-memory errors on large documents. You can customize the batch size using the -batch-size flag.
  • Special Tokens: Preserves grounding coordinates and page tokens returned by the server to construct layout-accurate 2D mappings.
  • Cache: Unique caching strategy that serializes the full raw document output to skip inference.

Example usage:

# Using Baidu engine with custom model and endpoint
qocr -engine baidu -model <your-vllm-model-id> -endpoint http://192.168.0.12:4000 document.pdf -latex -output result.tex

๐Ÿ”ค Native Text Extraction (No-OCR)

For digitally-born PDFs โ€” exported from Word, LaTeX, InDesign, or any PDF writer โ€” qocr can extract text, headings, and tables directly from the PDF's internal text layer with zero inference engine, zero GPU, and zero network calls.

qocr -native document.pdf -output result.md
How it works

The native mode uses a two-tier detection strategy:

Tier 1 โ€” Tagged PDFs (Word exports, InDesign, PDF/UA, accessibility-compliant docs)

Many professionally-produced PDFs embed a full logical structure tree with semantic <Table>, <TR>, <TD>, <TH>, <H1>โ€“<H6>, <P> elements. When detected, qocr reads this tree directly via PDFium's FPDF_StructTree API โ€” the document author's own structural intent, stored in the file. Table cells are extracted exactly as authored, with zero spatial guessing.

Tier 2 โ€” Untagged PDFs (LaTeX output, older tools)

For PDFs without a structure tree, qocr uses GxPDF's 4-Pass Hybrid table detection โ€” a pure-Go, MIT-licensed library with no CGO:

  • Pass 1: Gap detection (adaptive threshold)
  • Pass 2: Overlap detection (Tabula-inspired)
  • Pass 3: Alignment detection (geometric column clustering)
  • Pass 4: Multi-line cell merging
Heading detection (both tiers)

Headings are detected using actual font size metadata from the PDF's internal font tables, read via GetPageTextStructured(CollectFontInformation=true). The modal (most-frequent) font size on the page becomes the body-text baseline:

Ratio vs. body font size Markdown output
โ‰ฅ 1.6ร— ## Heading (title)
โ‰ฅ 1.25ร— ### Heading (header)
Bold at body size, short line ### Heading (header)
Otherwise Paragraph
Limitations
  • Scanned PDFs: Produces empty output. Use the default OCR mode for scanned documents.
  • Complex layouts: Multi-column or magazine-style layouts may have reading-order issues. Use OCR mode for maximum fidelity.

๐Ÿ“š EPUB Conversion (No-OCR)

For EPUB books โ€” novels, textbooks, technical documentation, Project Gutenberg titles โ€” qocr can extract text, headings, and tables directly from the embedded XHTML with zero inference engine, zero GPU, and zero network calls.

The .epub extension is auto-detected; no flag is required:

qocr book.epub -output book.md

You can also force EPUB mode explicitly with -epub or -engine epub.

[!IMPORTANT] If you pass an EPUB with an AI engine flag (e.g. -baidu book.epub), qocr will warn you and automatically switch to native EPUB extraction. EPUB files contain machine-readable XHTML text โ€” no OCR is needed or beneficial.

How it works

EPUB files are standard ZIP archives containing:

  • META-INF/container.xml โ†’ points to the OPF package file
  • An OPF file (content.opf) โ†’ lists all content items and the reading-order spine
  • XHTML chapter files referenced by the spine

qocr reads the spine in order and converts each XHTML chapter to structured blocks:

XHTML element OCRBlock label Markdown output
<h1>, <h2> title # Heading / ## Heading
<h3>โ€“<h6> header ## Heading
<p> text Paragraph
<table> table Markdown table
<figcaption> caption Italic caption
<img> image ![alt text]() placeholder
<nav>, <script>, <style> โ€” Skipped

Tables are extracted as raw HTML and passed through the same rendering pipeline as PDF tables, so they are correctly converted to Markdown, LaTeX tabular environments, JSON blocks, etc.

Limitations
  • DRM-protected EPUBs: Cannot be read (the ZIP is encrypted). Remove DRM with a compatible tool first.
  • Fixed-layout EPUBs: Comics, picture books, and heavily graphical EPUBs may produce minimal text output since their content is image-based.
  • Embedded fonts/styles: Visual formatting (bold, italic within paragraphs) is stripped; only the text content is extracted.

โš–๏ธ License

This project is licensed under the MIT License (see LICENSE).

Documentation ยถ

The Go Gopher

There is no documentation for this package.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL