Skip to content

C API for ocrs lib#257

Merged
robertknight merged 6 commits into
robertknight:mainfrom
xsawyerx:sawyer/c-api
Jun 29, 2026
Merged

C API for ocrs lib#257
robertknight merged 6 commits into
robertknight:mainfrom
xsawyerx:sawyer/c-api

Conversation

@xsawyerx

Copy link
Copy Markdown

I wanted to play with ocrs in Zig and I noticed #2, so I went ahead and implemented it.

There's:

  • The C API
  • Header generated by cbindgen
  • Build targets
  • A Zig example using it
  • Full integration tests (with models) - optional

(The name on the account, "p5p", is a bug by GitHub that I keep trying to get their support to resolve, but alas, no response. I can explain in more details if this is a concern. I would be happy if you can validate the name on the commits is "Sawyer X" after merging. Thank you.)

p5p and others added 6 commits June 28, 2026 22:26
A small, stable `extern "C"` interface.

`ocrs-capi` wraps `ocrs::OcrEngine` and builds as both a `cdylib` and a
`staticlib`. Called it `ocrs_capi` (instead of `ocrs`) to avoid a
collision with the `cdylib` from the `ocrs` crate itself.

Included a README.md that explains things, and a Zig example, and
unit tests.
Now the Rust source is the single source of truth for the C ABI header so it
can no longer drift from the `extern "C"` signatures and `#[repr(C)]` types.

Way better.

- Replace hand-written `include/ocrs.h` with a cbindgen-generated header
  and add `cbindgen.toml` describing the output (C, OCRS_H guard, C++
  extern "C" compat, `usize` to `size_t`, doc comments preserved).
- Add a `header` test that regenerates the header in memory and fails if it
  differs from the committed file, so CI catches an API change made without
  regenerating. `OCRS_UPDATE_HEADER=1` rewrites it instead of comparing. The
  comparison tolerates CRLF and trailing whitespace for Windows checkouts.
- Add a `make capi-header` target.

cbindgen is a pinned, default-features-disabled dev-dependency, so
compiled only for `cargo test`, so downstram consumers don't need it to
build the library.
Adding tests that actually try to detect, layout, recognize path, using
`ocrs_engine_get_text` and `ocrs_engine_get_text_lines` on a test image,
assert substrings and non-degenerate bounding boxes.

The model files are too big to commit, so they're `#[ignore]`d and using
`OCRS_DETECTION_MODEL` / `OCRS_RECOGNITION_MODEL` from the env instead,
skipping when unset. `make test-capi` downloads the models and runs them
in release mode.

The image is decoded with a new `image` dev-dependency. `lib` is added to
the crate-type so the integration tests can link the crate as an rlib. This
produces `libocrs_capi.rlib` and does not collide with the `ocrs` crate.
Fix warnings about safety docs reported by `make lint`. Add `# Safety` headings
and regenerate the C header.

@robertknight robertknight left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks great, thank-you very much. I was able to build and run the Zig example and run the tests via make test-capi. I pushed a couple of commits to fix warnings from make lint (add # Safety headings) and a few typos.

@robertknight robertknight merged commit ff5437b into robertknight:main Jun 29, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants