LibRaw (LibRaw v0.2.0)

Copy Markdown View Source

Native camera RAW decoding for the BEAM via a Rustler NIF wrapping libraw.

Prerequisites

libraw must be installed on the system:

# macOS
brew install libraw

# Debian / Ubuntu
apt install libraw-dev

Examples

{:ok, image} = LibRaw.decode("/path/to/photo.CR3")
# => %{pixels: <<...>>, width: 6000, height: 4000, colors: 3, bps: 8}

{:ok, meta} = LibRaw.metadata("/path/to/photo.CR3")
# => %{camera_make: "Canon", camera_model: "EOS R5", iso: 400.0, ...}

Summary

Functions

Decode a RAW image file, returning processed pixel data.

Read EXIF metadata from a RAW image file without running the full decode pipeline.

Types

decode_opts()

@type decode_opts() :: [
  use_camera_wb: boolean(),
  no_auto_bright: boolean(),
  output_bps: 8 | 16,
  gamma: :srgb | :linear | {number(), number()}
]

image()

@type image() :: %{
  pixels: binary(),
  width: non_neg_integer(),
  height: non_neg_integer(),
  colors: non_neg_integer(),
  bps: non_neg_integer()
}

metadata()

@type metadata() :: %{
  camera_make: String.t(),
  camera_model: String.t(),
  captured_at: DateTime.t() | nil,
  iso: float(),
  shutter: float(),
  aperture: float(),
  orientation: integer()
}

Functions

decode(path, opts \\ [])

@spec decode(Path.t(), decode_opts()) :: {:ok, image()} | {:error, term()}

Decode a RAW image file, returning processed pixel data.

Runs the full libraw pipeline: open → unpack → dcraw_process → in-memory bitmap. The NIF call is dispatched to a Dirty CPU scheduler because decoding typically takes 100–500 ms.

Parameters

  • pathPath.t(). Filesystem path to a camera RAW file. Passed to libraw verbatim; non-ASCII paths work because the NIF takes a UTF-8 binary, not a charlist.
  • opts — keyword list. See Options below.

Options

  • :use_camera_wb — use the white balance stored in the file (default: true).
  • :no_auto_bright — disable libraw's automatic brightening (default: false).
  • :output_bps — bits per sample, either 8 or 16 (default: 8). Other values return {:error, {:invalid_output_bps, n}} without touching the NIF.
  • :gamma — gamma curve: :srgb, :linear, or a {g0, g1} tuple of numbers (default: :srgb). Anything else returns {:error, {:invalid_gamma, term}}.

Returns

  • {:ok, image}image is a map with the keys:
    • :pixels — raw pixel bytes as a binary, row-major, interleaved per channel.
    • :width / :height — pixel dimensions.
    • :colors — channel count (typically 3 for RGB).
    • :bps — bits per sample, matches :output_bps.
  • {:error, reason} — option-validation failures (see Options), a libraw error string for unsupported / corrupted files, or "invalid path: contains null byte" for paths containing \0.

metadata(path)

@spec metadata(Path.t()) :: {:ok, metadata()} | {:error, term()}

Read EXIF metadata from a RAW image file without running the full decode pipeline.

Only libraw_open_file is called, so this is dramatically cheaper than decode/2 — typically single-digit milliseconds. Still scheduled on a Dirty CPU scheduler because the open touches disk.

Parameters

  • pathPath.t(). Filesystem path to a camera RAW file.

Returns

  • {:ok, metadata}metadata is a map with the keys:
    • :camera_make — manufacturer name (e.g. "Canon").
    • :camera_model — model name (e.g. "EOS R5").
    • :captured_atDateTime in UTC, or nil if libraw reports no shooting timestamp (returns 0 from libraw).
    • :iso — ISO speed as a float.
    • :shutter — shutter speed in seconds as a float (e.g. 0.004 for 1/250s).
    • :aperture — f-number as a float.
    • :orientation — EXIF orientation / flip code as an integer.
  • {:error, reason} — a libraw error string for unsupported / corrupted files, or "invalid path: contains null byte".