defmodule Image.Plug.Pipeline do
@moduledoc """
The canonical, provider-neutral image-processing pipeline.
A pipeline is an ordered list of typed operation structs (under
`Image.Plug.Pipeline.Ops.*`) plus pipeline-wide settings: the
output format, an error policy, and a debug breadcrumb identifying
the provider that produced it.
Pipelines are pure data. Behaviour lives in
`Image.Plug.Pipeline.Interpreter` (executes ops),
`Image.Plug.Pipeline.Encoder` (serialises the result), and
`Image.Plug.Pipeline.Normaliser` (reorders, folds, validates).
"""
alias Image.Plug.Pipeline.Ops
@type op ::
Ops.Rotate.t()
| Ops.Trim.t()
| Ops.Flip.t()
| Ops.Resize.t()
| Ops.Background.t()
| Ops.Adjust.t()
| Ops.Sharpen.t()
| Ops.Blur.t()
| Ops.Border.t()
| Ops.Draw.t()
| Ops.Segment.t()
@type on_error ::
:auto | :render_error_image | :fallback_to_source | :raise | {:status, 100..599}
@type t :: %__MODULE__{
ops: [op()],
output: Ops.Format.t(),
on_error: on_error(),
provider: nil | module()
}
defstruct ops: [],
output: %Ops.Format{},
on_error: :auto,
provider: nil
@doc """
Builds a new, empty pipeline.
### Options
* `:output` is an `Image.Plug.Pipeline.Ops.Format` struct describing
the encoder configuration. Defaults to `%Ops.Format{}` (auto format,
quality 85, copyright-only metadata).
* `:on_error` is the error policy. Defaults to `:auto` — see
`Image.Plug` for selection semantics.
* `:provider` is an optional debug breadcrumb identifying the provider
module that produced the pipeline.
### Returns
* An empty `Image.Plug.Pipeline` struct.
### Examples
iex> p = Image.Plug.Pipeline.new()
iex> p.ops
[]
iex> p.output.type
:auto
"""
@spec new(keyword()) :: t()
def new(options \\ []) when is_list(options) do
%__MODULE__{
ops: [],
output: Keyword.get(options, :output, %Ops.Format{}),
on_error: Keyword.get(options, :on_error, :auto),
provider: Keyword.get(options, :provider)
}
end
@doc """
Appends an operation to a pipeline.
### Arguments
* `pipeline` is an `Image.Plug.Pipeline` struct.
* `op` is any operation struct under `Image.Plug.Pipeline.Ops.*`.
### Returns
* The pipeline with `op` appended to `:ops`.
### Examples
iex> alias Image.Plug.Pipeline
iex> alias Image.Plug.Pipeline.Ops.Rotate
iex> p = Pipeline.append(Pipeline.new(), %Rotate{angle: 90})
iex> length(p.ops)
1
"""
@spec append(t(), op()) :: t()
def append(%__MODULE__{} = pipeline, op) when is_struct(op) do
%{pipeline | ops: pipeline.ops ++ [op]}
end
@doc """
Replaces the pipeline's output (`Ops.Format`) struct.
### Arguments
* `pipeline` is an `Image.Plug.Pipeline` struct.
* `format` is an `Image.Plug.Pipeline.Ops.Format` struct.
### Returns
* The pipeline with `:output` replaced.
### Examples
iex> alias Image.Plug.Pipeline
iex> alias Image.Plug.Pipeline.Ops.Format
iex> p = Pipeline.put_output(Pipeline.new(), %Format{type: :webp, quality: 80})
iex> p.output.type
:webp
"""
@spec put_output(t(), Ops.Format.t()) :: t()
def put_output(%__MODULE__{} = pipeline, %Ops.Format{} = format) do
%{pipeline | output: format}
end
end