跪拜 Guibai
← All articles
Python

CPU-Only Invoice OCR: 4 Post-Processing Traps Between Text Lines and Structured Data

By 李帅515 ·
Read original on juejin.cn ↗ Google Translate ↗ Alt translation

Cloud OCR APIs charge per call and require sending invoice data to a third party; this MIT-licensed pipeline runs fully offline on a 4-core CPU and matches Tencent's VatInvoiceOCR field-for-field, so teams that process sensitive or high-volume invoices can cut both cost and data-exposure risk without giving up accuracy.

Summary

Recognizing a 73-page VAT invoice PDF on a 4-core CPU, with no cloud API and no GPU, is not an OCR problem in the end. The real work is reconstructing the table layout from OCR text boxes. This project runs RapidOCR (PP-OCRv6 + ONNX Runtime) locally, then applies a set of hard-won heuristics that turn raw text lines into a structured output compatible with Tencent Cloud's VatInvoiceOCR.

The four traps: wrapped product names get split across columns by OCR; quantity and unit price often merge into one number, requiring an amount-based split; multi-page invoices have page subtotals that can be mistaken for the overall total; and artistic-font invoice headers are misread, but a 20-digit full-e-invoice number can correct them. Each solution relies on domain constraints like the arithmetic relation between unit price, quantity, and amount, or the fixed structure of the tax total row.

On the 73-page test set, all pages recognized successfully, the line-item amount and tax totals matched the printed invoice exactly (reconciliation difference 0.00), and a field-by-field comparison with Tencent's cloud API showed 128 identical fields and 0 missing. Total runtime was 275 seconds on 4 cores, about 2–4 seconds per image.

Takeaways
— All 73 pages of a PDF were recognized successfully on a 4-core CPU, with 2–4 seconds per page and a total of 275 seconds.
— Line-item amount and tax totals matched the printed invoice exactly, with a reconciliation difference of 0.00.
— A field-by-field comparison with Tencent Cloud's VatInvoiceOCR found 128 identical fields and 0 missing fields.
— Quantity must be a positive integer; this constraint helps disambiguate OCR-glued numbers when combined with the check unit price × quantity ≈ amount (tolerance 0.02).
— The unit price is kept at full original precision instead of rounding to two decimals, so downstream multiplication checks still work.
— On multi-page invoices, locating the total by searching for the first row containing "合计" is wrong; the logic must skip page subtotals and use the fixed structure of the following "价税合计" row as a reverse proof.
— A 20-digit invoice number is unique to full e-invoices, so it can correct artistic-font misreadings of the invoice header without affecting paper invoices (8/10/12 digits).
— For multi-page PDFs, the `/ocr/vatpdf` endpoint must be used instead of `EnableMultiplePage` to avoid hitting a 60-second reverse proxy read timeout.
— PyMuPDF is AGPL-3.0; closed-source redistribution requires an Artifex license or switching to pypdfium2.
— The repository is MIT licensed, builds with Docker Compose, and runs completely offline after image build.
Conclusions

The majority of effort in structured invoice extraction goes into layout reconstruction, not character recognition; OCR supplies text coordinates, and the real cost is mapping them back to rows and columns.

Using arithmetic constraints like unit price × quantity ≈ amount is a pragmatic substitute for training a model, and it works because invoices are designed to be self-consistent for auditing.

A stable identifier (the 20-digit invoice number) can reliably correct an unstable field (artistic-font header), a pattern that generalizes well to other document processing problems where one field is known to be trustworthy.

Matching Tencent Cloud's VatInvoiceOCR field-by-field without the cloud suggests that for this class of structured documents, hand-crafted post-processing can achieve parity with paid API responses.

Concepts & terms
RapidOCR
An open-source OCR engine based on PaddleOCR models (here PP-OCRv6) running on ONNX Runtime, providing text lines with bounding box coordinates without needing a GPU.
Reconciliation (勾稽)
Cross-checking that separate invoice fields obey arithmetic relations, such as unit price × quantity = amount, and total amount + total tax = grand total, to catch OCR errors.
Full e-invoice (全电发票)
A fully electronic Chinese VAT invoice format identified by a 20-digit invoice number, as opposed to paper invoices with 8/10/12-digit numbers; its header is rendered in artistic font that OCR often misreads.
Source: juejin.cn ↗ Google Translate ↗ Backup ↗