rxing decodes barcodes from image binaries using a source-built Rustler NIF
powered by the Rust rxing crate.
Installation
def deps do
[
{:rxing, "~> 0.1.0"}
]
endrxing compiles its native library from source when the dependency is
compiled. Install Rust 1.91 or newer (rustc and cargo) before running
mix compile.
Immediate Example (binary input)
image = File.read!("path/to/barcode.png")
{:ok, [%Rxing.Result{format: :qr_code} | _results]} =
Rxing.decode(image, formats: [:qr_code])Public APIs
Rxing exposes three decoding entry points:
Rxing.decode/2decodes every supported barcode in an image binary.Rxing.decode_one/2decodes the first supported barcode or returns{:error, :not_found}.Rxing.decode_file/2reads an image from a path and decodes it.
All APIs share the same option vocabulary and stable error vocabulary.
Decoding Binaries, One Result, and Files
image = File.read!("path/to/barcodes.png")
# Decode every result up to the configured bound.
{:ok, results} =
Rxing.decode(image, formats: [:qr_code, :data_matrix], max_results: 32)
# Decode only the first result.
{:ok, first} = Rxing.decode_one(image, formats: [:qr_code, :data_matrix])
%Rxing.Result{} = first
# Let Rxing read a regular file after applying the input-size pre-check.
{:ok, file_results} =
Rxing.decode_file("path/to/barcodes.png", formats: [:qr_code, :data_matrix])results and file_results are lists of %Rxing.Result{} values in upstream
detection order. When no barcode is recognized, decoding returns {:ok, []}.
Supported Barcode Formats
Rxing.formats/0 returns the guaranteed format set in stable order:
:qr_code:data_matrix:code_128:ean_13
Supported Image Encodings
The binary API accepts these content-detectable formats from image 0.25:
- BMP
- DDS
- OpenEXR
- farbfeld
- GIF
- HDR
- ICO
- JPEG
- PNG
- PNM
- QOI
- TIFF
- WebP
Committed integration fixtures guarantee representative decoding coverage for PNG, JPEG, GIF, BMP, and WebP. Other enabled encodings use the same content-based classification and decoding pipeline.
AVIF and TGA are not accepted by the current binary-only pipeline: AVIF decoding
requires the separate image/avif-native feature, while image::guess_format
cannot identify TGA without a filename extension.
Options, Filtering, and Defaults
Public options:
:formats(default:[:qr_code, :data_matrix, :code_128, :ean_13]):try_harder(default:false):try_inverted(default:false):max_results(default:32, allowed range1..256):max_input_bytes(default:20 * 1024 * 1024):max_width(default:10_000):max_height(default:10_000):max_pixels(default:40_000_000):max_alloc_bytes(default:256 * 1024 * 1024)
Filtering examples:
- Restrict formats:
formats: [:qr_code] - Enable rotated scan retries:
try_harder: true - Enable inverted scan retries:
try_inverted: true - Raise result bound for dense images:
max_results: 64
Stable Errors
Decode operations return:
{:error, :invalid_image}{:error, :internal_error}{:error, {:unsupported_format, format}}{:error, {:invalid_option, key}}{:error, {:limit_exceeded, limit}}{:error, {:file, reason}}(decode_file/2){:error, :not_found}(decode_one/2)
Result Payload, Raw Bytes, and Metadata
Every successful decode returns %Rxing.Result{} values:
:format- one of the supported barcode format atoms.:text- decoded UTF-8 text when available, elsenil.:raw_bytes- raw decoded bytes when available, elsenil.:points- list of%{x: float(), y: float()}result points.:metadata- decoder metadata map. Supported keys include::orientation,:byte_segments,:error_correction_level,:structured_append_sequence,:structured_append_parity,:symbology_identifier,:is_inverted, and:is_mirrored.
Runtime and Concurrency Notes
- Native decoding runs on dirty CPU schedulers to avoid monopolizing normal BEAM schedulers.
- Callers remain responsible for choosing safe request-level concurrency and backpressure limits.
Source Build Requirements and Platforms
- Elixir:
~> 1.15. - Tested runtime pairs: Elixir 1.15.8 / OTP 26 and Elixir 1.20 / OTP 29.
- Rust toolchain:
rustc/cargo1.91 or newer. - The native crate is built from source during dependency compilation.
- Supported CI platforms: Linux and macOS.
Benchmarks
From a repository checkout with development dependencies installed, run:
mix run bench/rxing_bench.exs
The non-gating Benchee report includes throughput, median, p95, and p99 latency, BEAM memory, scheduler counts, run-queue snapshots, and heartbeat observations. It covers the guaranteed barcode formats, clean/rotated/inverted/damaged/multiple and no-code scenarios, an image-size sweep, and concurrency levels 1 through 32.
Treat the output as a baseline for comparisons made on the same host and toolchain. It deliberately contains no pass/fail latency thresholds or portable speed claims.
Non-goals (0.1.0)
- Barcode encoding/generation APIs.
- Precompiled NIF artifacts in Hex packages.
- Alternative native backends beyond Rust
rxing.
License
MIT. See LICENSE.