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>)
Summary
Functions
Normalises annotations into drawing primitives + colour.
Builds ImageMagick convert arguments that draw the annotations' outlines.
Renders the annotations as a standalone <svg> string (outlines only).
Types
Functions
@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.
@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 (default2):default_color— colour for shapes without astylecolour (default#ef4444)
@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 theviewBox(required for correct positioning; default100):stroke_width— outline width in viewBox units (default2):default_color— colour fallback (default#ef4444):class— extra class on the<svg>element