ExRatatui.CellSession.Region (ExRatatui v0.18.0)

Copy Markdown View Source

A bitmap that a pixel-mode widget handed to an ExRatatui.CellSession created with a :font_size, covering a rect of cells.

Terminal graphics protocols smuggle their bytes through one cell's symbol, which a cell diff cannot carry. A surface with real pixels does not need the escape at all: it wants the bitmap and the rect it covers. So on a session that knows its cell pixel size, ExRatatui.Widgets.Viewport3D and ExRatatui.Widgets.Image in a pixel mode rasterize into a region, and the cells they cover arrive as plain blank cells.

Fields

  • :x, :y, :width, :height — the covered rect, in cells
  • :pixel_width, :pixel_height — the bitmap's size in pixels. Usually width * font_width by height * font_height; the longest side is capped (1280 px), so a very large rect gets a smaller bitmap to scale up
  • :format — :rgb8: row-major, three bytes per pixel, no padding
  • :data — the pixel bytes, pixel_width * pixel_height * 3 long

Contract

ExRatatui.CellSession.Snapshot and ExRatatui.CellSession.Diff carry the complete list of regions on screen for that frame, never a delta. A region that is not listed is gone. Paint the cells first, then blit every region over its rect, scaling if the bitmap is smaller than the rect.

Examples

iex> ExRatatui.CellSession.Region.from_native(%{
...>   x: 2, y: 1, width: 2, height: 1,
...>   pixel_width: 2, pixel_height: 1, format: :rgb8,
...>   data: <<255, 0, 0, 0, 0, 255>>
...> })
%ExRatatui.CellSession.Region{
  x: 2, y: 1, width: 2, height: 1,
  pixel_width: 2, pixel_height: 1, format: :rgb8,
  data: <<255, 0, 0, 0, 0, 255>>
}

Summary

Functions

Builds a t/0 from the raw map the NIF returns for one region.

Rotates the region's bitmap clockwise by angle degrees.

Encodes the region's bitmap as a PNG binary.

Types

t()

@type t() :: %ExRatatui.CellSession.Region{
  data: binary(),
  format: :rgb8,
  height: non_neg_integer(),
  pixel_height: non_neg_integer(),
  pixel_width: non_neg_integer(),
  width: non_neg_integer(),
  x: non_neg_integer(),
  y: non_neg_integer()
}

Functions

from_native(map)

@spec from_native(map()) :: t()

Builds a t/0 from the raw map the NIF returns for one region.

rotate(region, angle)

@spec rotate(t(), ExRatatui.Pixels.angle()) :: t()

Rotates the region's bitmap clockwise by angle degrees.

Returns the region with :data, :pixel_width and :pixel_height updated; at 90 and 270 the two dimensions are swapped. For a surface whose panel is mounted on its side, this turns the bitmap once so the rest of the paint stays a flat row-by-row copy.

The cell rect is left alone. :x, :y, :width and :height are the app's cell coordinates, and turning them needs the size of the grid they sit in, which a region does not carry. A consumer that rotates its whole screen already knows that size and computes the turned rect itself — raster_ex_ratatui does exactly that, in its physical_rect/2.

Raises ArgumentError on a bitmap whose byte count is not pixel_width * pixel_height * 3, or on an unsupported angle. See ExRatatui.Pixels.rotate_rgb8/4 for the corner mapping.

Examples

iex> region = %ExRatatui.CellSession.Region{
...>   x: 4, y: 2, width: 2, height: 1,
...>   pixel_width: 2, pixel_height: 1,
...>   data: <<255, 0, 0, 0, 0, 255>>
...> }
iex> ExRatatui.CellSession.Region.rotate(region, 90)
%ExRatatui.CellSession.Region{
  x: 4, y: 2, width: 2, height: 1,
  pixel_width: 1, pixel_height: 2, format: :rgb8,
  data: <<255, 0, 0, 0, 0, 255>>
}

to_png(region)

@spec to_png(t()) :: binary()

Encodes the region's bitmap as a PNG binary.

For consumers that ship regions over a text channel (a LiveView push, a JSON API), where raw RGB would be several times heavier. The PNG has the region's pixel_width × pixel_height.

Raises ArgumentError when data does not hold exactly pixel_width * pixel_height * 3 bytes.