README.md

# Image.QRCode

QR code encoding and decoding for the [Image](https://hex.pm/packages/image)
library, implemented as a NIF over two small, well-regarded C libraries:

* **Encoding** — [nayuki/QR-Code-generator](https://github.com/nayuki/QR-Code-generator) (MIT).
* **Decoding** — [dlbeer/quirc](https://github.com/dlbeer/quirc) (ISC).

Both libraries are vendored under `c_src/` and statically linked into the
NIF, so the package has no system-library dependencies beyond a C compiler
on platforms where a precompiled artefact is not available.

The standard image type for both input and output is `t:Vix.Vips.Image.t/0`.
Conversion to and from the raw module / grayscale buffers required by the
underlying C libraries is performed implicitly.

## Installation

Add `:image_qrcode` to your `mix.exs` dependencies:

```elixir
def deps do
  [
    {:image_qrcode, "~> 0.1"}
  ]
end
```

### Toolchain

Both `image_qrcode` and its `:vix` dependency ship as precompiled NIFs on the
common targets, so no C toolchain is required on:

* macOS (x86_64, arm64)
* Linux x86_64, aarch64 (gnu and musl), armv7-gnu
* Windows x86_64 (MSVC)

On any other target, or if the precompiled artefact download fails, `mix
deps.compile` falls back to building from the vendored sources. In that case
a C11 compiler and `make` are required. (`:vix` bundles its own copy of
`libvips` as part of its precompile, so installing libvips system-wide is
not necessary either.)

## Usage

### Encoding

`Image.QRCode.encode/2` takes a string and returns a single-band 8-bit
`t:Vix.Vips.Image.t/0` rendering of the QR code:

```elixir
{:ok, image} = Image.QRCode.encode("https://example.com")
:ok = Vix.Vips.Image.write_to_file(image, "qr.png")
```

Common options:

* `:ecc` — `:low | :medium | :quartile | :high` (default `:medium`).
* `:scale` — pixels per QR module (default `4`).
* `:quiet` — quiet-zone width in modules (default `4`, the QR spec minimum).
* `:version_min` / `:version_max` — bounds for the QR version (1..40).
* `:mask` — `:auto` (default) or an integer `0..7`.
* `:boost_ecc` — let the encoder upgrade ECC if the chosen version has spare capacity (default `true`).

### Decoding

`Image.QRCode.decode/1` takes any `t:Vix.Vips.Image.t/0` and returns a list of
decoded QR codes. The image is implicitly converted to grayscale, so RGB,
RGBA, float-format and multi-band inputs are all accepted:

```elixir
{:ok, image} = Vix.Vips.Image.new_from_file("qr.png")
{:ok, [%{payload: payload, version: version, corners: corners}]} =
  Image.QRCode.decode(image)
```

Each decoded entry is a map with `:payload`, `:version`, `:ecc_level`,
`:mask`, `:data_type`, `:eci` and `:corners` (the four corners of the code
in image coordinates, top-left clockwise).

## Concurrency

Both encoder and decoder hold no shared mutable state — each call allocates
its own scratch buffers — and the NIF is scheduled on dirty CPU schedulers,
so concurrent invocation from many processes is safe and parallelised.
A stress harness (`test/concurrency_test.exs`, tagged `:concurrency`)
verifies this property by running 500 round-trips at high concurrency.

## License

This library is released under the Apache-2.0 license. The vendored
encoder is MIT-licensed (Nayuki) and the vendored decoder is ISC-licensed
(Daniel Beer); their license headers are retained in the source tree under
`c_src/nayuki` and `c_src/quirc`.