FrenchCurve.Raster (FrenchCurve v0.1.3)

Copy Markdown View Source

A fixed-size RGBA pixel buffer, the value every drawing and backend function operates on.

A raster has a width, a height, a background colour returned for any pixel never written, and two interchangeable representations of its contents:

  • pixels — a sparse map of {x, y} to colour, cheap to draw into
  • rgba — a dense row-major width * height * 4 byte buffer, what the backends send

get_pixel/3 reads from whichever is populated, so the representation is not something a caller has to track. finalize/1 caches the dense buffer on a raster that is about to be sent repeatedly; drawing into a finalized raster discards the cache.

Coordinates are zero-based with {0, 0} at the top left. Writes outside the bounds are dropped rather than raising.

FrenchCurve.Raster.new(4, 2, background: {0, 0, 0, 255})
|> FrenchCurve.Raster.put_pixel(1, 0, {255, 0, 0, 255})
|> FrenchCurve.Raster.to_rgba_binary()

Summary

Functions

Returns the raster's {width, height} in pixels.

Returns raster with its dense RGBA buffer computed and cached in the rgba field.

Builds a raster from an existing dense RGBA buffer.

Returns the color/0 at {x, y}.

Returns whether {x, y} falls inside the raster.

Builds an empty raster width by height pixels.

Returns raster with the pixel at {x, y} set to color.

Returns every pixel as height lists of width colours, top row first.

Returns the raster as a dense row-major RGBA buffer.

Types

channel()

@type channel() :: 0..255

color()

@type color() :: {channel(), channel(), channel(), channel()}

color_rgb()

@type color_rgb() :: {channel(), channel(), channel()}

point()

@type point() :: {non_neg_integer(), non_neg_integer()}

t()

@type t() :: %FrenchCurve.Raster{
  background: color(),
  height: pos_integer(),
  pixels: %{optional(point()) => color()},
  rgba: binary() | nil,
  width: pos_integer()
}

Functions

dimensions(raster)

@spec dimensions(t()) :: {pos_integer(), pos_integer()}

Returns the raster's {width, height} in pixels.

finalize(raster)

@spec finalize(t()) :: t()

Returns raster with its dense RGBA buffer computed and cached in the rgba field.

Pixel values are unchanged. Call this on a raster that will be sent to a backend more than once; a raster that already carries a cache is returned as is. put_pixel/4 after finalize/1 drops the cache, so finalize last.

from_rgba(width, height, binary, opts \\ [])

@spec from_rgba(pos_integer(), pos_integer(), binary(), keyword()) :: t()

Builds a raster from an existing dense RGBA buffer.

binary must be exactly width * height * 4 bytes, four bytes per pixel in red, green, blue, alpha order and rows top to bottom; a mismatched size raises FunctionClauseError. The buffer is kept as the raster's cache rather than expanded, so this is the cheap way to load pixels produced elsewhere.

Options

  • :background — the color/0 returned for out-of-bounds reads, default {0, 0, 0, 0}

get_pixel(raster, x, y)

@spec get_pixel(t(), integer(), integer()) :: color()

Returns the color/0 at {x, y}.

Reads a written pixel first, then the cached dense buffer, and falls back to the raster's background. Out-of-bounds coordinates return the background rather than raising.

in_bounds?(raster, x, y)

@spec in_bounds?(t(), integer(), integer()) :: boolean()

Returns whether {x, y} falls inside the raster.

True when x and y are both non-negative and below width and height respectively.

new(width, height, opts \\ [])

@spec new(pos_integer(), pos_integer(), keyword()) :: t()

Builds an empty raster width by height pixels.

Both dimensions must be positive integers; anything else raises FunctionClauseError.

Options

  • :background — the color/0 get_pixel/3 returns for unwritten pixels, default {0, 0, 0, 0} (transparent black)

put_pixel(raster, x, y, color)

@spec put_pixel(t(), integer(), integer(), color()) :: t()

Returns raster with the pixel at {x, y} set to color.

color is an {r, g, b, a} tuple of bytes and replaces whatever was there; there is no alpha blending. Coordinates outside the bounds are ignored and the raster is returned unchanged. A raster holding a cached dense buffer loses that cache here.

rows(raster)

@spec rows(t()) :: [[color()]]

Returns every pixel as height lists of width colours, top row first.

Each element is a color/0; unwritten positions come back as the background.

to_rgba_binary(raster)

@spec to_rgba_binary(t()) :: binary()

Returns the raster as a dense row-major RGBA buffer.

The result is exactly width * height * 4 bytes, four bytes per pixel in red, green, blue, alpha order, rows top to bottom. Returns the cached buffer when one is present.