# `Tessera.TileGenerator`
[🔗](https://github.com/alexdont/tessera/blob/v0.1.0/lib/tessera/tile_generator.ex#L1)

Generates DZI (Deep Zoom Image) output from input images by shelling out
to ImageMagick.

Three operations, all writing through a pluggable `Tessera.Storage`
adapter (defaults to `Tessera.Storage.Local`):

  * `generate/3` — full eager pyramid for one image, in one call. Use
    when you want every tile up front.
  * `generate_manifest/3` — just the XML manifest declaring image size
    and tile config. Cheap; lets a viewer point at a DZI source before
    any tiles exist.
  * `generate_tile/4` — a single tile at `{level, col, row}`. Use to
    build a pyramid lazily, on demand, as users zoom into specific
    regions.

## Requirements

ImageMagick (`magick` binary) must be on the host `PATH`.

# `generate_opts`

```elixir
@type generate_opts() :: [
  tile_size: pos_integer(),
  overlap: non_neg_integer(),
  format: :jpg | :png,
  base_name: String.t()
]
```

# `lazy_opts`

```elixir
@type lazy_opts() :: [
  image_width: pos_integer(),
  image_height: pos_integer(),
  tile_size: pos_integer(),
  overlap: non_neg_integer(),
  format: :jpg | :png,
  quality: 1..100,
  storage: module(),
  storage_opts: keyword()
]
```

# `result`

```elixir
@type result() :: %{manifest: Path.t(), tiles_dir: Path.t()}
```

# `generate`

```elixir
@spec generate(Path.t(), Path.t(), generate_opts()) ::
  {:ok, result()} | {:error, term()}
```

Generate a DZI tile pyramid for `input_path` into `output_dir`.

Eager: produces every tile in one shot. For lazy per-tile generation,
see `generate_manifest/3` + `generate_tile/4`.

Returns `{:ok, %{manifest: path, tiles_dir: path}}` on success.

## Options

  * `:tile_size` — pixels per tile edge (default `256`).
  * `:overlap` — pixel overlap between adjacent tiles (default `1`).
  * `:format` — `:jpg` or `:png` (default `:jpg`).
  * `:base_name` — manifest filename prefix; defaults to the input file's
    basename without extension.

## Errors

  * `{:error, :imagemagick_not_found}` — `magick` not on `PATH`.
  * `{:error, :invalid_input}` — `input_path` does not exist or is not readable.
  * `{:error, {:exit, status, stderr}}` — ImageMagick exited non-zero.

# `generate_manifest`

```elixir
@spec generate_manifest({pos_integer(), pos_integer()}, String.t(), keyword()) ::
  :ok | {:error, term()}
```

Generate the DZI XML manifest for an image of size `{width, height}` and
hand it off to the configured storage adapter under the key
`"<base_name>.dzi"`. No tiles are produced — see `generate_tile/4` for
that.

## Options

  * `:tile_size` (default `256`)
  * `:overlap` (default `1`)
  * `:format` (`:jpg` | `:png`, default `:jpg`)
  * `:storage` (module implementing `Tessera.Storage`, default
    `Tessera.Storage.Local`)
  * `:storage_opts` (keyword list passed to `storage.put/3`)

# `generate_tile`

```elixir
@spec generate_tile(
  Path.t(),
  {non_neg_integer(), non_neg_integer(), non_neg_integer()},
  String.t(),
  lazy_opts()
) :: :ok | {:error, term()}
```

Generate a single DZI tile at `{level, col, row}` from `input_path` and
hand it off to the configured storage adapter under the key
`"<base_name>_files/<level>/<col>_<row>.<ext>"`.

The caller must supply the source image's `:image_width` and
`:image_height` (typically read from a database column populated at
upload time) so Tessera doesn't need to re-probe the image dimensions
on every tile.

## Options

  * `:image_width` (**required**)
  * `:image_height` (**required**)
  * `:tile_size` (default `256`)
  * `:overlap` (default `1`)
  * `:format` (`:jpg` | `:png`, default `:jpg`)
  * `:quality` (1..100, default `80`) — only honored for
    `:jpg`
  * `:storage` (module implementing `Tessera.Storage`, default
    `Tessera.Storage.Local`)
  * `:storage_opts` (keyword list passed to `storage.put/3`)

## Errors

  * `{:error, :imagemagick_not_found}` — `magick` not on `PATH`.
  * `{:error, :invalid_input}` — `input_path` does not exist or is not readable.
  * `{:error, :invalid_coordinate}` — `(level, col, row)` falls outside the
    pyramid for the given image dimensions.
  * `{:error, {:exit, status, stderr}}` — ImageMagick exited non-zero.

---

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