# `Etcher.Raster`
[🔗](https://github.com/alexdont/etcher/blob/v0.9.0/lib/etcher/raster.ex#L1)

Server-side, dependency-free rendering of Etcher annotations to static output.

Etcher renders shapes live (SVG) on the Fresco canvas in the browser. This
module is the *server* counterpart: it turns the same annotation geometry into
either **ImageMagick `convert -draw` arguments** (to bake shapes into a raster
— e.g. an annotated thumbnail) or a standalone **SVG string** (to overlay
shapes on an image without JS).

It is the single source of truth for "Etcher geometry → drawn shape" on the
server, mirroring the wire format documented in the README. Pure functions, no
system dependencies — the caller owns rasterization (running `convert`,
embedding the SVG, …).

## Input

A list of annotation maps as they travel in `etcher:annotations-changed` /
the `extensions.etcher` blob — `%{"kind" => ..., "geometry" => ..., "style" =>
...}` (string keys; atom keys are also accepted). Unknown or malformed shapes
are skipped, so one bad row never breaks a render.

## Examples

    iex> rect = [%{"kind" => "rectangle", "geometry" => %{"x" => 10, "y" => 20, "w" => 30, "h" => 40}}]
    iex> Etcher.Raster.to_draw_args(rect, stroke_width: 4)
    ["-fill", "none", "-stroke", "#ef4444", "-strokewidth", "4", "-draw", "rectangle 10,20 40,60"]

    iex> rect = [%{"kind" => "rectangle", "geometry" => %{"x" => 10, "y" => 20, "w" => 30, "h" => 40}}]
    iex> Etcher.Raster.to_svg(rect, width: 100, height: 100)
    ~s(<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" preserveAspectRatio="xMidYMid slice" fill="none"><rect x="10" y="20" width="30" height="40" stroke="#ef4444" stroke-width="2"/></svg>)

# `annotation`

```elixir
@type annotation() :: map()
```

# `opts`

```elixir
@type opts() :: keyword()
```

# `primitives`

```elixir
@spec primitives([annotation()]) :: [{tuple(), String.t() | nil}]
```

Normalises annotations into drawing primitives + colour.

Each entry is `{primitive, color}` where `primitive` is one of:
`{:rect, x, y, w, h}`, `{:circle, cx, cy, r}`, `{:polygon, points}`,
`{:polyline, points}`, `{:line, x1, y1, x2, y2}` (coords are numbers, `points`
is a list of `{x, y}`). Exposed so callers can add their own backend.

# `to_draw_args`

```elixir
@spec to_draw_args([annotation()], opts()) :: [String.t()]
```

Builds ImageMagick `convert` arguments that draw the annotations' outlines.

Returns a flat arg list to splice into a `convert` invocation *before* any
resize/crop, so shapes are drawn in the source image's pixel space (Etcher
geometry is in canvas/image pixels) and scale with the image.

Returns `[]` when there is nothing drawable.

## Options

  * `:stroke_width` — outline width in source pixels (default `2`)
  * `:default_color` — colour for shapes without a `style` colour (default `#ef4444`)

# `to_svg`

```elixir
@spec to_svg([annotation()], opts()) :: String.t()
```

Renders the annotations as a standalone `<svg>` string (outlines only).

Suitable as an absolutely-positioned overlay on an image. With
`preserveAspectRatio="xMidYMid slice"` the SVG crops identically to CSS
`object-cover`, so shapes line up with a cover-fit thumbnail.

Returns `""` when there is nothing drawable.

## Options

  * `:width` / `:height` — the source image dimensions for the `viewBox`
    (required for correct positioning; default `100`)
  * `:stroke_width` — outline width in viewBox units (default `2`)
  * `:default_color` — colour fallback (default `#ef4444`)
  * `:class` — extra class on the `<svg>` element

---

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