# `SSCMEx.Image`

Image structure used by camera capture and model inference.

This is a zero-copy wrapper over an Elixir binary. The `data` field holds a
reference to the original binary.

## Supported Formats

Raw (fixed bytes-per-pixel):
- `:rgb888`
- `:rgb888_planar`
- `:rgb565`
- `:yuv422`
- `:gray`

Encoded (variable size):
- `:jpeg`
- `:h264`
- `:h265`

## Example

    # Create image from camera frame (zero-copy)
    frame = capture_camera_frame()  # Returns binary
    image = SSCMEx.Image.new(640, 480, :rgb888, frame)

    # Run inference
    {:ok, results} = SSCMEx.Model.run(model, image)

# `convert_format`

```elixir
@type convert_format() :: :rgb888 | :rgb565 | :yuv422 | :gray | :jpeg | :webp
```

Supported pixel formats for convert operations.
Note: YUV422 can only be used as input (YUV422→RGB/Grayscale),
not as output (RGB→YUV422 is not supported by OpenCV 3.2.0).

# `encoded_format`

```elixir
@type encoded_format() :: :jpeg | :h264 | :h265
```

# `format`

```elixir
@type format() :: raw_format() | encoded_format()
```

# `interpolation`

```elixir
@type interpolation() :: :nearest | :bilinear | :bicubic | :area | :lanczos4
```

Interpolation methods for resize operations.

# `raw_format`

```elixir
@type raw_format() :: :rgb888 | :rgb888_planar | :rgb565 | :yuv422 | :gray
```

# `t`

```elixir
@type t() :: %SSCMEx.Image{
  data: binary(),
  format: format(),
  height: non_neg_integer(),
  key: boolean() | nil,
  size: non_neg_integer() | nil,
  timestamp: integer() | nil,
  width: non_neg_integer()
}
```

# `convert`

```elixir
@spec convert(t(), convert_format(), keyword()) :: {:ok, t()} | {:error, atom()}
```

Convert image to a different format.

## Supported conversions

Raw formats (RGB888, RGB565, YUV422, Grayscale):
- RGB888 ↔ Grayscale
- RGB888 ↔ RGB565
- YUV422 → RGB888/Grayscale (note: reverse not supported)

Compressed formats:
- Any raw format → JPEG
- Any raw format → WebP (requires libwebp support in SDK)

## Options

  * `:quality` - JPEG/WebP quality 0-100 (default: 85)

## Examples

    {:ok, webp} = SSCMEx.Image.convert(image, :webp, quality: 90)
    {:ok, gray} = SSCMEx.Image.convert(image, :gray)
    {:ok, rgb} = SSCMEx.Image.convert(yuv_image, :rgb888)

# `data_size`

```elixir
@spec data_size(t()) :: non_neg_integer()
```

Returns the expected byte size for the image data based on dimensions and format.

## Example

    iex> SSCMEx.Image.data_size(%SSCMEx.Image{width: 640, height: 480, format: :rgb888, data: <<>>})
    921600

# `new`

```elixir
@spec new(non_neg_integer(), non_neg_integer(), format(), binary()) :: t()
```

Create a new image struct.

This is zero-copy - `data` binary is referenced, not copied.

## Parameters

- `width` - Image width in pixels
- `height` - Image height in pixels
- `format` - Pixel format
- `data` - Binary image data (not copied)

## Example

    image = SSCMEx.Image.new(640, 480, :rgb888, frame_data)

# `resize`

```elixir
@spec resize(t(), {pos_integer(), pos_integer()}, keyword()) ::
  {:ok, t()} | {:error, atom()}
```

Resize image to new dimensions.

## Options

  * `:interpolation` - `:nearest`, `:bilinear` (default), `:bicubic`, `:area`, `:lanczos4`

## Examples

    {:ok, small} = SSCMEx.Image.resize(image, {320, 240})
    {:ok, thumb} = SSCMEx.Image.resize(image, {160, 120}, interpolation: :lanczos4)

# `valid?`

```elixir
@spec valid?(t()) :: boolean()
```

Validates that the image data size matches the expected size for the given dimensions and format.

## Example

    iex> image = SSCMEx.Image.new(2, 2, :rgb888, <<255, 0, 0, 0, 255, 0, 0, 0, 255, 255, 255, 255>>)
    iex> SSCMEx.Image.valid?(image)
    true

---

*Consult [api-reference.md](api-reference.md) for complete listing*
