RasterExRatatui.PixelFormat.Mono (RasterExRatatui v0.4.0)

Copy Markdown View Source

One gray byte per pixel for 1-bit panels: 0 is ink, 255 is paper.

A 1-bit panel cannot show colour, so every colour collapses to a tone: ink, paper, or gray (a pixel checkerboard). The bytes are gray8 so they can be thresholded, PNG-encoded, or bit-packed by the driver; every pixel is exactly 0 or 255.

Cells

The glyph's set bits take the foreground tone and the rest of the cell the background tone, which keeps half-block cells honest: ▀ with a dark fg and a light bg inks only its top half, which is what Canvas's :half_block marker emits.

Colouras fgas bg
:blackinkink
:reset, other named, indexedink on a paper bg, paper on an ink bgpaper
{:rgb, r, g, b}by luma: ink / gray / papersame

:reversed short-circuits all of that and always paints a paper glyph on an ink cell: screens stack it with a bg: :black fill to invert a whole frame. Named colours keep terminal legibility: a red or white label is ink on paper and paper on an ink fill, and bg: :white (which Canvas emits for shape cells) is plain paper. RGB colours are treated as intent: dark is ink, light is paper, and the band between :ink_max and :paper_min (Rec. 601 luma) is gray, so lit and shadowed faces read as three tones. Other modifiers are ignored.

Regions

Region pixels go through a Bayer 4×4 ordered dither on luma. The tile repeats across the panel, so the texture is stable between frames and under partial refresh, without the crawling noise error diffusion shows.

Options

  • :ink_max — RGB colours with luma at or below this are ink (default 76, 30%)
  • :paper_min — RGB colours with luma at or above this are paper (default 178, 70%)

Examples

iex> alias ExRatatui.CellSession.Cell
iex> alias RasterExRatatui.PixelFormat.Mono
iex> config = Mono.init([])
iex> Mono.cell_paints(%Cell{fg: :red, bg: :reset}, config)
{<<0>>, <<255>>}
iex> Mono.cell_paints(%Cell{fg: :red, bg: :black}, config)
{<<255>>, <<0>>}
iex> Mono.cell_paints(%Cell{fg: {:rgb, 128, 128, 128}, bg: :reset}, config)
{{:checker, <<0>>, <<255>>}, <<255>>}

Summary

Functions

Paper.

One byte per pixel.

Foreground and background tones for a cell; see the moduledoc table.

Reads :ink_max and :paper_min.

:mono_bayer4: regions are dithered natively by ExRatatui.Pixels.pack_rgb8/5, with the same luma, matrix and panel anchoring as rgb_pixel/6. Cells keep the tone rules.

Dithers an RGB pixel to ink or paper against the Bayer 4×4 threshold at (x, y).

Dithers a row of RGB pixels against the Bayer row for y, walking the tile from x.

Each gray byte as an RGB8 pixel of that level.

Functions

blank(config)

@spec blank(term()) :: binary()

Paper.

Examples

iex> RasterExRatatui.PixelFormat.Mono.blank(%{})
<<255>>

bytes_per_pixel(config)

@spec bytes_per_pixel(term()) :: 1

One byte per pixel.

Examples

iex> RasterExRatatui.PixelFormat.Mono.bytes_per_pixel(%{})
1

cell_paints(cell, config)

Foreground and background tones for a cell; see the moduledoc table.

Examples

iex> alias ExRatatui.CellSession.Cell
iex> RasterExRatatui.PixelFormat.Mono.cell_paints(%Cell{bg: :blue, modifiers: [:reversed]}, RasterExRatatui.PixelFormat.Mono.init([]))
{<<255>>, <<0>>}

init(opts)

@spec init(keyword()) :: %{ink_max: 0..255, paper_min: 0..255}

Reads :ink_max and :paper_min.

Examples

iex> RasterExRatatui.PixelFormat.Mono.init(ink_max: 50)
%{ink_max: 50, paper_min: 178}

native_format(config)

@spec native_format(term()) :: :mono_bayer4

:mono_bayer4: regions are dithered natively by ExRatatui.Pixels.pack_rgb8/5, with the same luma, matrix and panel anchoring as rgb_pixel/6. Cells keep the tone rules.

Examples

iex> RasterExRatatui.PixelFormat.Mono.native_format(%{})
:mono_bayer4

rgb_pixel(r, g, b, x, y, config)

@spec rgb_pixel(0..255, 0..255, 0..255, non_neg_integer(), non_neg_integer(), term()) ::
  binary()

Dithers an RGB pixel to ink or paper against the Bayer 4×4 threshold at (x, y).

Examples

iex> alias RasterExRatatui.PixelFormat.Mono
iex> Mono.rgb_pixel(255, 255, 255, 0, 0, %{})
<<255>>
iex> Mono.rgb_pixel(0, 0, 0, 3, 3, %{})
<<0>>
iex> for x <- 0..3, y <- 0..3, into: <<>>, do: Mono.rgb_pixel(128, 128, 128, x, y, %{})
<<255, 0, 255, 0, 0, 255, 0, 255, 255, 0, 255, 0, 0, 255, 0, 255>>

rgb_row(row, x, y, config)

@spec rgb_row(binary(), non_neg_integer(), non_neg_integer(), term()) :: binary()

Dithers a row of RGB pixels against the Bayer row for y, walking the tile from x.

Examples

iex> alias RasterExRatatui.PixelFormat.Mono
iex> Mono.rgb_row(:binary.copy(<<128, 128, 128>>, 4), 0, 1, %{})
<<0, 255, 0, 255>>
iex> Mono.rgb_row(:binary.copy(<<128, 128, 128>>, 4), 1, 1, %{})
<<255, 0, 255, 0>>

unpack_row(row, config)

@spec unpack_row(binary(), term()) :: binary()

Each gray byte as an RGB8 pixel of that level.

Examples

iex> RasterExRatatui.PixelFormat.Mono.unpack_row(<<0, 255>>, %{})
<<0, 0, 0, 255, 255, 255>>