Documentation / Desktop and server
On this page
The C API in mrzscanner.h is the same in the Linux and Windows libraries (and inside every other package). No function throws; failures are reported as mrz_status.
The licence
int32_t mrz_register_license(const char *key, const char *app_id, const char *device_model, int32_t platform);
platform: 1 iOS, 2 Android, 4 desktop / server, 8 web. Returns 0 on success, -2 invalid key, -3 other app, -4 other device, -5 expired, -6 other platform. The check is offline and process-wide. Without a licence, results come back with masked fields.
A scanner
mrz_scanner *mrz_scanner_create(const char *tessdata_dir, mrz_status *status);
void mrz_scanner_destroy(mrz_scanner *scanner);
void mrz_scanner_reset(mrz_scanner *scanner);
tessdata_dir is the folder with mrz.traineddata; it must be named tessdata. A scanner is not thread-safe: use one per thread. mrz_scanner_reset starts a new camera stream on the same scanner.
Images and frames
typedef struct { const uint8_t *pixels; int32_t width, height, stride, format; } mrz_image;
mrz_status mrz_scan_image(mrz_scanner *s, const mrz_image *image, const mrz_scan_options *options, mrz_result **result);
mrz_status mrz_scan_frame(mrz_scanner *s, const mrz_image *image, const mrz_scan_options *options, mrz_result **result);
format:MRZ_PIXEL_RGBA8,BGRA8,RGB8,BGR8orGRAY8.stride: bytes per row, 0 for packed rows.mrz_scan_imagereads a still image (photo, scan) with several passes. The same image and options always give the same result.mrz_scan_framereads one camera frame. Call it on consecutive frames: a read is returned once the same MRZ came fromframe_confirmationsframes (default 2).- Both return
MRZ_OKwith a result, orMRZ_NOT_FOUND. Release a result withmrz_result_free.
Options
options may be NULL. Otherwise fill it with mrz_scan_options_init(&options) and change what you need:
| Field | Default | |
|---|---|---|
document_types |
MRZ_DOC_ALL |
MRZ_DOC_PASSPORT, MRZ_DOC_ID, MRZ_DOC_VISA (a mask) |
roi_x, roi_y, roi_width, roi_height |
0, 0, 100, 100 | region of interest in percent: only an MRZ inside it is read |
upside_down |
0 | also try the image turned 180 degrees |
rotation |
0 | degrees (0, 90, 180, 270) the image must be turned to be upright, as camera APIs report |
frame_confirmations |
2 | frames that must agree before mrz_scan_frame returns a read; 1: the first read |
validate_country_codes |
1 | issuing state and nationality must be known country codes |
Results
const char *mrz_result_text(const mrz_result *r); /* the MRZ lines, joined by '\n' */
const char *mrz_result_json(const mrz_result *r); /* the parsed fields */
int32_t mrz_result_check_digits_valid(const mrz_result *r); /* 1 if every check digit matches */
int32_t mrz_result_corners(const mrz_result *r, int32_t xy[8]);
The strings belong to the result. The corners are in image pixels, top left first, clockwise.
The MRZ as an image
mrz_status mrz_isolate_size(const int32_t corners[8], int32_t height, int32_t *width);
mrz_status mrz_isolate(const mrz_image *image, const int32_t corners[8], int32_t width, int32_t height, uint8_t *out, int32_t stride);
The MRZ alone, straightened and scaled to height pixels, in the pixel format of image.
Following the MRZ on screen
For an overlay at display rate: mrz_scanner_frame_corners gives where the last frame's MRZ is, even before it is read; a mrz_tracker (mrz_tracker_create, mrz_tracker_set, mrz_tracker_track) finds it again in later frames in a few milliseconds. mrz_scanner_document_id changes when a different document comes into view.
Version
mrz_version() returns the core's version, mrz_status_string(status) a status as text.
Updated Oct 24, 2026 ยท Questions? Ask us