Behaviour for packing pixels the way a panel expects them.
RasterExRatatui.Raster never builds pixels itself: it asks the format what a cell's foreground and background look like, and what an RGB pixel from a region looks like at a given position, and tiles those bytes. A format is therefore the whole colour policy of a panel, from "RGB565, little-endian" to "1-bit e-ink with tone rules and a dither".
Built in:
RasterExRatatui.PixelFormat.Mono— one gray byte per pixel for 1-bit panels (0 ink, 255 paper)RasterExRatatui.PixelFormat.RGB565— 16-bit little-endianRasterExRatatui.PixelFormat.XRGB8888— 32-bit little-endian, a common Linux framebuffer depth
Callbacks
init/1 turns the raster's format_opts: into a config term, once; every other callback receives that config, so per-pixel work does not re-read keyword lists.
cell_paints/2 returns a paint/0 for each side of a cell. Most formats return solid pixel bytes. A format that simulates a tone it cannot show (a gray on a 1-bit panel) returns {:checker, even, odd}: the pixel at panel position (x, y) takes even when x + y is even, odd otherwise, so the pattern stays aligned across cells.
rgb_pixel/6 packs one region pixel. The position is there for ordered dithering; formats that do not dither ignore it.
unpack_row/2 is optional and turns packed pixels back into RGB8, so RasterExRatatui.Raster.to_png/1 can show what the panel shows.
native_format/1 is optional and names the ExRatatui.Pixels.format/0 whose bytes match the format's rgb_pixel/6, or nil. When a format has one, the raster packs its regions natively with ExRatatui.Pixels.pack_rgb8/5: resample, clip, rotate and pack in a single pass, which is how the three built-in formats run.
rgb_row/4 is optional and packs a whole row of region pixels in one call. For a format without a native format, the raster still resamples, clips and rotates natively and then packs row by row, preferring rgb_row/4 when the format exports it, because one function call per pixel is most of a region's cost. A format that does not define it gets rgb_row/5, the per-pixel fallback.
Examples
iex> alias RasterExRatatui.PixelFormat.XRGB8888
iex> config = XRGB8888.init([])
iex> XRGB8888.bytes_per_pixel(config)
4
iex> XRGB8888.rgb_pixel(255, 128, 0, 0, 0, config)
<<0, 128, 255, 255>>
Summary
Types
Packed bytes for one pixel, or a two-pixel checkerboard.
A module implementing this behaviour.
Callbacks
The packed pixel for areas no cell or region covers (margins, skipped cells).
Bytes per packed pixel.
{foreground, background} paints for a cell, after its colours and modifiers.
Validates opts and precomputes whatever the other callbacks need.
The ExRatatui.Pixels format these bytes match, or nil.
One packed pixel for an RGB colour at panel position (x, y).
Packs a row of region pixels: row holds n RGB8 pixels (3 * n bytes) that land at panel positions (x, y) to (x + n - 1, y). Returns n packed pixels.
Unpacks a row of packed pixels back to RGB8, 3 bytes per pixel: what the panel shows, as colours.
Functions
The format's native_format/1, or nil when it does not define one.
Resolves a paint to the pixel bytes at panel position (x, y).
Packs a row of region pixels with format, through its rgb_row/4 when it has one and pixel by pixel through rgb_pixel/6 otherwise.
Types
Callbacks
The packed pixel for areas no cell or region covers (margins, skipped cells).
@callback bytes_per_pixel(config()) :: pos_integer()
Bytes per packed pixel.
@callback cell_paints(ExRatatui.CellSession.Cell.t(), config()) :: {paint(), paint()}
{foreground, background} paints for a cell, after its colours and modifiers.
Validates opts and precomputes whatever the other callbacks need.
@callback native_format(config()) :: ExRatatui.Pixels.format() | nil
The ExRatatui.Pixels format these bytes match, or nil.
Optional. A format that returns one must pack every region pixel exactly as ExRatatui.Pixels.pack_rgb8/5 does for it, at the same panel positions; its rgb_pixel/6 is then only a reference, never called for regions.
@callback rgb_pixel( r :: 0..255, g :: 0..255, b :: 0..255, x :: non_neg_integer(), y :: non_neg_integer(), config() ) :: binary()
One packed pixel for an RGB colour at panel position (x, y).
@callback rgb_row( row :: binary(), x :: non_neg_integer(), y :: non_neg_integer(), config() ) :: binary()
Packs a row of region pixels: row holds n RGB8 pixels (3 * n bytes) that land at panel positions (x, y) to (x + n - 1, y). Returns n packed pixels.
Optional. Must produce the same bytes as n calls to rgb_pixel/6.
Unpacks a row of packed pixels back to RGB8, 3 bytes per pixel: what the panel shows, as colours.
Optional. RasterExRatatui.Raster.to_png/1 needs it; nothing on the drawing path calls it.
Functions
@spec native_format(t(), config()) :: ExRatatui.Pixels.format() | nil
The format's native_format/1, or nil when it does not define one.
Examples
iex> alias RasterExRatatui.PixelFormat
iex> PixelFormat.native_format(PixelFormat.RGB565, PixelFormat.RGB565.init([]))
:rgb565
@spec resolve(paint(), non_neg_integer(), non_neg_integer()) :: binary()
Resolves a paint to the pixel bytes at panel position (x, y).
Examples
iex> RasterExRatatui.PixelFormat.resolve(<<7>>, 3, 4)
<<7>>
iex> RasterExRatatui.PixelFormat.resolve({:checker, <<0>>, <<255>>}, 1, 1)
<<0>>
iex> RasterExRatatui.PixelFormat.resolve({:checker, <<0>>, <<255>>}, 1, 2)
<<255>>
@spec rgb_row(t(), binary(), non_neg_integer(), non_neg_integer(), config()) :: binary()
Packs a row of region pixels with format, through its rgb_row/4 when it has one and pixel by pixel through rgb_pixel/6 otherwise.
Examples
iex> alias RasterExRatatui.PixelFormat
iex> PixelFormat.rgb_row(PixelFormat.RGB565, <<255, 0, 0, 0, 0, 255>>, 0, 0, PixelFormat.RGB565.init([]))
<<0, 248, 31, 0>>