Description
Renders the result of a query as a PNG image. This is useful as a built-in visualization tool. The size of the output image is fixed by the settingsoutput_format_image_width and
output_format_image_height
(both default to 1024). Pixels that are not covered by the result are filled with black
(in RGB and grayscale modes) or with transparent black (in RGBA mode).
The color mode is determined automatically from the column names and types of the result:
Column names are matched case-insensitively. If the color mode cannot be unambiguously
determined (e.g. unknown column names, mixed
v with r/g/b/a, or one of r/g/b missing),
the query throws an exception.
For pixel channels, integer values are clamped to [0, 255] and floating-point values
are clamped to [0, 1] and then scaled to [0, 255].
The position of each record in the image is determined by one of two modes:
- Implicit (the default — when neither
xnoryis present). Each record corresponds to a single pixel; pixels are filled in scanline order: left to right, top to bottom. - Explicit (when
xandycolumns are present, both of integer types). Thexandycolumns give the pixel coordinates. Records with coordinates outside the image are silently ignored. In case of multiple records with the same coordinates, the last one wins (painter’s algorithm).
Example usage
Implicit coordinates (row-per-pixel), RGB
Explicit coordinates, grayscale
Animation
If the result has at column of an integer type, the format produces an animated PNG (APNG) instead of a
still image. Records are grouped into frames by the value of t, which is the relative time offset of the
frame. Every frame is an independent image: the canvas is empty at the start of each frame, and in the
implicit coordinate mode the cursor restarts from the top-left corner. The t column can be combined with
either coordinate mode.
The unit of t is given by
output_format_image_time_multiplier_seconds
and
output_format_image_time_divisor_seconds:
one unit of t is output_format_image_time_multiplier_seconds / output_format_image_time_divisor_seconds
seconds. With the default values (1 and 60) one unit of t is 1/60 of a second.
A frame is displayed until the next frame begins, so its duration is the difference between two consecutive
values of t. The last frame is displayed for as long as the frame before it. The animation loops forever.
Streaming the frames
By default all frames are collected in memory and written out at the end of the query, which keeps one image buffer per distinct value oft and lets t arrive in any order.
The setting
output_format_image_streaming_animation
writes each frame out as soon as the next value of t is seen. Only one image buffer is kept in memory, and
frames reach the output while the query is still running, so a viewer can display them as they are produced.
In exchange:
tmust be non-decreasing; the query throws an exception otherwise. AddORDER BY tif needed.- The number of frames is not known when the header has to be written, so the
acTLchunk declares an upper bound instead of the exact count. Browsers play such a file, but decoders that trust the declared count (for example,Pillowand some command-lineAPNGtools) report an error after the last real frame. An animation of a single frame is the exception: the whole result has been read by the time that frame is written, so the count is declared exactly and the output conforms to the specification.
iterm terminal mode. The sixel protocol cannot represent an
animation at all, and the Kitty graphics protocol animates only through a separate flow of per-frame commands,
not through an animated datastream, so it would display just the first frame; both modes reject a result with
a t column.
Displaying images in the terminal
By default, thePNG format writes the raw image bytes. The setting
output_format_image_terminal_mode
makes the format render the image directly to the terminal using an inline image protocol instead: