Encodes a widget's picture into the bytes and region Drafter.Compositor.put_image/4
takes.
A widget exporting image_raster/2 returns a t/0: a FrenchCurve.Raster covering a box
of cells, the protocol to draw it with, and where the box sits in the widget. The
widget server encodes it with encode/3.
On a kitty terminal that keeps images under an id, the whole raster is stored once and
the region carries :crop. The compositor then moves the image and shows any part of
it with placements alone, so neither a move nor a scroll re-encodes it.
Every other protocol sends the pixels themselves. Only the part of the box inside the
visible window is encoded, and the region is reduced to that part, so a change of
window needs a new encoding. window_dependent?/1 says which case a picture is in.
picture = %{raster: raster, protocol: :kitty, dx: 0, dy: 0, cols: 40, rows: 6}
{paint, clear, region} = Drafter.Render.Picture.encode(picture, :my_chart, nil)Two optional keys change how a stored kitty image is sent, each on its own:
format: :pngsends it as a PNG — a palette one when it has at most 256 colours — instead of deflated raw pixels (FrenchCurve.Backend.Kitty.encode/2), usually far smaller for flat-coloured picturesswap: truekeeps it under two image ids, a new frame stored under the one not on screen, placed, and only then the old one deleted, the whole sent as one synchronized update, so the terminal never shows the region empty between frames
Summary
Types
The stored kitty image a region shows: its kitty image id and its size in pixels. A
picture sent with swap: true also has a spare id and its encoded pixels, which the
compositor stores under whichever of the two is not on screen, after the region's own
bytes.
A widget's picture: raster drawn with protocol into the cols by rows cell box
whose top left is dx, dy cells from the widget's top left.
A rectangle of cells, relative to the widget's top left.
Functions
Encodes picture for the image region id, showing the part inside window.
The pixel rectangle {x, y, width, height} of a width by height pixel image drawn
into cols by rows cells that covers the cells {col, row, visible_cols, visible_rows}, counted from the image's top left cell.
The cells of picture's box inside window, as {col, row, cols, rows} counted from
the box's top left, or nil when none are. A nil window is the whole box.
Whether the encoding of picture depends on the visible window.
Types
@type crop() :: %{ :image => pos_integer(), :width => pos_integer(), :height => pos_integer(), optional(:spare) => pos_integer(), optional(:encoded) => FrenchCurve.Backend.Kitty.encoded() }
The stored kitty image a region shows: its kitty image id and its size in pixels. A
picture sent with swap: true also has a spare id and its encoded pixels, which the
compositor stores under whichever of the two is not on screen, after the region's own
bytes.
@type t() :: %{ :raster => FrenchCurve.Raster.t(), :protocol => atom(), :dx => non_neg_integer(), :dy => non_neg_integer(), :cols => pos_integer(), :rows => pos_integer(), optional(:format) => :rgba | :png, optional(:swap) => boolean() }
A widget's picture: raster drawn with protocol into the cols by rows cell box
whose top left is dx, dy cells from the widget's top left.
@type window() :: %{ x: integer(), y: integer(), width: non_neg_integer(), height: non_neg_integer() }
A rectangle of cells, relative to the widget's top left.
Functions
Encodes picture for the image region id, showing the part inside window.
window is the widget's visible cells relative to its top left, or nil when all of
it is visible. It is ignored when the terminal keeps kitty images under an id.
Returns {paint, clear, region}, or nil when no part of the picture is inside
window or the protocol cannot draw it. With :crop in region, paint stores the
image without drawing it, and the compositor places it.
@spec source( {pos_integer(), pos_integer()}, {pos_integer(), pos_integer()}, {non_neg_integer(), non_neg_integer(), pos_integer(), pos_integer()} ) :: {non_neg_integer(), non_neg_integer(), pos_integer(), pos_integer()}
The pixel rectangle {x, y, width, height} of a width by height pixel image drawn
into cols by rows cells that covers the cells {col, row, visible_cols, visible_rows}, counted from the image's top left cell.
Cell edges are mapped to pixels by rounding down, so adjacent cell ranges share their boundary pixel row and column exactly.
iex> Drafter.Render.Picture.source({160, 48}, {40, 6}, {0, 2, 40, 3})
{0, 16, 160, 24}
@spec visible_cells(map(), window() | nil) :: {non_neg_integer(), non_neg_integer(), pos_integer(), pos_integer()} | nil
The cells of picture's box inside window, as {col, row, cols, rows} counted from
the box's top left, or nil when none are. A nil window is the whole box.
iex> picture = %{dx: 0, dy: 1, cols: 10, rows: 6}
iex> Drafter.Render.Picture.visible_cells(picture, %{x: 0, y: 3, width: 10, height: 20})
{0, 2, 10, 4}
Whether the encoding of picture depends on the visible window.
False when the terminal keeps kitty images under an id, where the compositor crops the stored image; true for every other protocol.