# `Cauldron2D.Projection.Canvas`
[🔗](https://github.com/jaman/cauldron/blob/v0.2.2/cauldron_2d/lib/cauldron_2d/projection/canvas.ex#L1)

A framebuffer of RGBA rows that stamps are painted onto, and the stamps themselves.

A canvas is a map from row index to that row's pixels, `width * 4` bytes each. A stamp
is an image reduced to its opaque runs, `%{width, height, runs: [{y, x, pixels}]}`,
so painting it copies whole runs and skips transparent pixels. `paint/4` clips to the
canvas.

    canvas = Canvas.new(64, 32, {6, 7, 11})
    stamp = Canvas.stamp(%{width: 8, height: 8, rgba: rgba})
    canvas |> Canvas.paint(stamp, {10, 4}) |> Canvas.to_raster()

# `image`

```elixir
@type image() :: %{width: pos_integer(), height: pos_integer(), rgba: binary()}
```

# `stamp`

```elixir
@type stamp() :: %{
  width: pos_integer(),
  height: pos_integer(),
  runs: [{integer(), integer(), binary()}]
}
```

# `t`

```elixir
@type t() :: %{
  width: pos_integer(),
  height: pos_integer(),
  rows: %{required(non_neg_integer()) =&gt; binary()}
}
```

# `blank`

```elixir
@spec blank(pos_integer(), pos_integer()) :: t()
```

A fully transparent canvas of `width` by `height`, to build a stamp on.

# `crop`

```elixir
@spec crop(
  t(),
  {non_neg_integer(), non_neg_integer()},
  {pos_integer(), pos_integer()}
) :: t()
```

The `width` by `height` window of the canvas whose top-left corner is at `{x, y}`.

# `flip`

```elixir
@spec flip(image()) :: image()
```

The image mirrored left to right.

# `map_pixels`

```elixir
@spec map_pixels(image(), (binary() -&gt; binary())) :: image()
```

The image with `fun` applied to every pixel's four bytes.

# `memo`

```elixir
@spec memo(atom(), term(), (-&gt; term())) :: term()
```

The value under `key` in the ETS `table`, built by `build` and kept when absent.

# `new`

```elixir
@spec new(pos_integer(), pos_integer(), {byte(), byte(), byte()}) :: t()
```

A canvas of `width` by `height` filled with `colour`.

# `paint`

```elixir
@spec paint(t(), stamp(), {integer(), integer()}) :: t()
```

Paint `stamp` with its top-left corner at `{x, y}`, clipped to the canvas.

# `quad`

```elixir
@spec quad(
  t(),
  {number(), number()},
  {number(), number()},
  {number(), number()},
  (float(), float() -&gt;
     binary() | nil)
) ::
  t()
```

Paints the parallelogram `origin + u * across + v * down`, `u` and `v` running `0..1`,
taking each pixel from `texel.(u, v)`; a pixel the function answers `nil` for is left
alone, as is one outside the canvas.

The two edge vectors must not be parallel.

# `shade`

```elixir
@spec shade(binary(), number(), {byte(), byte(), byte()}, number()) :: binary()
```

`pixel` mixed towards `fog` by `mix` in `0.0..1.0` after its colour is multiplied by
`factor`; a transparent pixel is left alone.

# `shrink`

```elixir
@spec shrink(image(), pos_integer()) :: image()
```

The image at `1 / factor` of its size, sampling every `factor`th pixel.

# `stamp`

```elixir
@spec stamp(image()) :: stamp()
```

An image reduced to its opaque runs. A pixel is opaque from alpha 128.

# `texel`

```elixir
@spec texel(binary(), pos_integer(), number(), number()) :: binary()
```

The pixel of a square `size` texture at `u`, `v` in `0.0..1.0`.

# `to_image`

```elixir
@spec to_image(t()) :: image()
```

The canvas as an image, for `stamp/1`.

# `to_raster`

```elixir
@spec to_raster(t()) :: FrenchCurve.Raster.t()
```

The canvas as a raster.

---

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