How To

Use Decoded RGB Input

High-performance OCR directly from uncompressed, decoded interleaved RGB8 pixel buffers in Rust, C FFI, and language bindings.

OCR from Decoded RGB Pixels

High-throughput image processing callers (such as libvips, imagor, OpenCV, camera feeds, and GUI viewports) already maintain uncompressed, decoded pixel arrays in memory. Encoding these pixels as JPEG or PNG solely to invoke rocr_detect_text_data adds redundant codec overhead and, in the case of lossy formats like JPEG, introduces compression artifacts that degrade recognition accuracy.

RustO! provides direct, validated raw RGB input methods that bypass compression and decompression entirely while utilizing the same detection, recognition, and coordinate systems.

Key Properties

  • Input Format: Interleaved unsigned 8-bit RGB (RGB8), with no alpha channel and no EXIF auto-rotation.
  • Row Padding: Supports padded row strides (stride >= width * 3). The buffer must contain at least (height - 1) * stride + width * 3 readable bytes (the final row does not require trailing padding).
  • Fast-Path Memory Copy: When stride == width * 3 (unpadded contiguous pixels), buffers are ingested in a single vectorized memory pass.
  • Safe Memory Invariants: The caller retains ownership of the pixel buffer. RustO copies the active pixels and never retains, modifies, or frees the caller's pointer.
  • Backend Requirement: Requires the default pure-Rust image backend.

C / C++ Integration

Build RustO! with cargo build --release --features ffi. C declarations are exported in include/rusto.h.

Structured Output (rocr_detect_text_rgb)

#include "rusto.h"

/* handle is an initialized ROCRHandle*; pixels is caller-owned RGB8 buffer. */
CTextResult *results = NULL;
size_t count = 0;
int status = rocr_detect_text_rgb(
    handle,
    pixels,
    buffer_length,
    width,
    height,
    stride_bytes,
    "{}",
    &results,
    &count
);

if (status == 0) {
    for (size_t i = 0; i < count; ++i) {
        printf("Detected: %s (confidence: %.2f)\n", results[i].text, results[i].score);
    }
    rocr_free_results(results, count);
}

Spatial Output (rocr_detect_text_rgb_spatial)

#include "rusto.h"

char *spatial_json = rocr_detect_text_rgb_spatial(
    handle,
    pixels,
    buffer_length,
    width,
    height,
    stride_bytes,
    "{}"
);

if (spatial_json != NULL) {
    printf("Spatial JSON: %s\n", spatial_json);
    rocr_free_string(spatial_json);
}

Return Codes

CodeMeaning
0Success
-1NULL pointer passed for a required argument
-2Invalid dimensions, insufficient stride, or short buffer length
-3Engine or inference execution failure
-4Invalid options JSON string
-5Spatial output requested on structured API (use rocr_detect_text_rgb_spatial instead)

Native Rust API

use rusto::{InitializeConfig, OcrRunOptions, RustO};

let mut ocr = RustO::initialize(config)?;
let options = OcrRunOptions::default();

// pixels: &[u8], width: u32, height: u32, stride: usize
let result = ocr.detect_text_rgb(pixels, width, height, stride, &options)?;

Language Bindings

Go (packages/go)

results, err := engine.DetectTextRGB(pixels, width, height, stride, "{}")
if err != nil {
    log.Fatal(err)
}

Flutter & Dart (packages/flutter, packages/dart)

final results = ocr.detectTextRgb(pixelBytes, width, height, stride);

Java & JVM (packages/java)

List<TextResult> results = ocr.detectTextRGB(pixelBytes, width, height, stride, "{}");

Python (packages/python via UniFFI)

results = ocr.detect_text_rgb(pixel_bytes, width, height, stride, options)