1notcurses_visual(3) notcurses_visual(3)
2
3
4
6 notcurses_visual - notcurses multimedia
7
9 #include <notcurses/notcurses.h>
10
11 typedef enum {
12 NCSCALE_NONE,
13 NCSCALE_SCALE,
14 NCSCALE_STRETCH,
15 NCSCALE_NONE_HIRES,
16 NCSCALE_SCALE_HIRES,
17 NCSCALE_INFLATE,
18 } ncscale_e;
19
20 typedef enum {
21 NCBLIT_DEFAULT, // let the ncvisual pick
22 NCBLIT_1x1, // spaces only
23 NCBLIT_2x1, // halves + 1x1
24 NCBLIT_2x2, // quadrants + 2x1
25 NCBLIT_3x2, // sextants + 1x1
26 NCBLIT_BRAILLE, // 4 rows, 2 cols (braille)
27 NCBLIT_PIXEL, // pixel graphics
28 NCBLIT_4x1, // four vertical levels, (plots)
29 NCBLIT_8x1, // eight vertical levels, (plots)
30 } ncblitter_e;
31
32 #define NCVISUAL_OPTION_NODEGRADE 0x0001
33 #define NCVISUAL_OPTION_BLEND 0x0002
34 #define NCVISUAL_OPTION_HORALIGNED 0x0004
35 #define NCVISUAL_OPTION_VERALIGNED 0x0008
36 #define NCVISUAL_OPTION_ADDALPHA 0x0010
37 #define NCVISUAL_OPTION_CHILDPLANE 0x0020
38
39 struct ncvisual_options {
40 struct ncplane* n;
41 ncscale_e scaling;
42 int y, x;
43 int begy, begx; // origin of rendered section
44 int leny, lenx; // size of rendered section
45 ncblitter_e blitter; // glyph set to use
46 uint64_t flags; // bitmask over NCVISUAL_OPTION_*
47 uint32_t transcolor; // use this color for ADDALPHA
48 };
49
50 typedef int (*streamcb)(struct notcurses*, struct ncvisual*, void*);
51
52 struct ncvisual* ncvisual_from_file(const char* file);
53
54 struct ncvisual* ncvisual_from_rgba(const void* rgba, int rows, int
55 rowstride, int cols);
56
57 struct ncvisual* ncvisual_from_bgra(const void* bgra, int rows, int
58 rowstride, int cols);
59
60 struct ncvisual* ncvisual_from_plane(struct ncplane* n, ncblitter_e
61 blit, int begy, int begx, int leny, int lenx);
62
63 int ncvisual_blitter_geom(const struct notcurses* nc, const struct
64 ncvisual* n, const struct ncvisual_options* vopts, int* y, int* x, int*
65 scaley, int* scalex, ncblitter_e* blitter);
66
67 void ncvisual_destroy(struct ncvisual* ncv);
68
69 int ncvisual_decode(struct ncvisual* ncv);
70
71 int ncvisual_decode_loop(struct ncvisual* ncv);
72
73 struct ncplane* ncvisual_render(struct notcurses* nc, struct ncvisual*
74 ncv, const struct ncvisual_options* vopts);
75
76 int ncvisual_simple_streamer(struct ncplane* n, struct ncvisual* ncv,
77 const struct timespec* disptime, void* curry);
78
79 int ncvisual_stream(struct notcurses* nc, struct ncvisual* ncv, float
80 timescale, streamcb streamer, const struct ncvisual_options* vopts,
81 void* curry);
82
83 int ncvisual_rotate(struct ncvisual* n, double rads);
84
85 int ncvisual_resize(struct ncvisual* n, int rows, int cols);
86
87 int ncvisual_inflate(struct ncvisual* n, int scale);
88
89 int ncvisual_polyfill_yx(struct ncvisual* n, int y, int x, uint32_t rg‐
90 ba);
91
92 int ncvisual_at_yx(const struct ncvisual* n, int y, int x, uint32_t*
93 pixel);
94
95 int ncvisual_set_yx(const struct ncvisual* n, int y, int x, uint32_t
96 pixel);
97
98 char* ncvisual_subtitle(const struct ncvisual* ncv);
99
100 int notcurses_lex_scalemode(const char* op, ncscale_e* scaling);
101
102 const char* notcurses_str_scalemode(ncscale_e scaling);
103
104 int notcurses_lex_blitter(const char* op, ncblitter_e* blitter);
105
106 const char* notcurses_str_blitter(ncblitter_e blitter);
107
108 ncblitter_e ncvisual_media_defblitter(const struct notcurses nc, nc‐
109 scale_e scaling);
110
111 int ncplane_qrcode(struct ncplane* n, int* ymax, int* xmax, const void*
112 data, size_t len)
113
115 An ncvisual is a virtual pixel framebuffer. They can be created from
116 RGBA/BGRA data in memory (ncvisual_from_rgba/ncvisual_from_bgra), or
117 from the content of a suitable ncplane (ncvisual_from_ncplane). If
118 Notcurses was built against a multimedia engine (FFMpeg or OpenIm‐
119 ageIO), image and video files can be loaded into visuals using ncvisu‐
120 al_from_file. ncvisual_from_file discovers the container and codecs,
121 but does not verify that the entire file is well-formed. ncvisual_de‐
122 code ought be invoked to recover subsequent frames, once per frame.
123 ncvisual_decode_loop will return to the first frame, as if ncvisual_de‐
124 code had never been called.
125
126 Once the visual is loaded, it can be transformed using ncvisual_rotate,
127 ncvisual_resize, and ncvisual_inflate. These are persistent opera‐
128 tions, unlike any scaling that takes place at render time. If a subti‐
129 tle is associated with the frame, it can be acquired with ncvisual_sub‐
130 title. ncvisual_resize uses the media layer's best scheme to enlarge
131 or shrink the original data, typically involving some interpolation.
132 ncvisual_inflate maps each pixel to scalexscale pixels square, retain‐
133 ing the original color; it is an error if scale is less than one.
134
135 ncvisual_from_rgba and ncvisual_from_bgra both require a number of
136 rows, a number of image columns cols, and a virtual row length of row‐
137 stride / 4 columns. The input data must provide 32 bits per pixel, and
138 thus must be at least rowstride * rows bytes, of which a cols * rows *
139 4-byte subset is used. It is not possible to mmap(2) an image file and
140 use it directly--decompressed, decoded data is necessary. The result‐
141 ing plane will be ceil(rows/2) rows, and cols columns. ncvisu‐
142 al_from_plane requires specification of a rectangle via begy, begx, le‐
143 ny, and lenx. The only valid characters within this region are those
144 used by the NCBLIT_2x2 blitter, though this may change in the future.
145
146 ncvisual_rotate executes a rotation of rads radians, in the clockwise
147 (positive) or counterclockwise (negative) direction.
148
149 ncvisual_subtitle will return a UTF-8-encoded subtitle corresponding to
150 the current frame if such a subtitle was decoded. Note that a subtitle
151 might be returned for multiple frames, or might not.
152
153 ncvisual_render blits the visual to an ncplane, based on the contents
154 of its struct ncvisual_options. If n is not NULL, it specifies the
155 plane on which to render, and y/x specify a location within that plane.
156 Otherwise, a new plane will be created, and placed at y/x relative to
157 the rendering area. begy/begx specify the upper left corner of a sub‐
158 section of the ncvisual to render, while leny/lenx specify the geometry
159 of same. flags is a bitfield over:
160
161 • NCVISUAL_OPTION_NODEGRADE If the specified blitter is not available,
162 fail rather than degrading.
163
164 • NCVISUAL_OPTION_BLEND: Render with CELL_ALPHA_BLEND.
165
166 • NCVISUAL_OPTION_HORALIGNED: Interpret x as an ncalign_e.
167
168 • NCVISUAL_OPTION_VERALIGNED: Interpret y as an ncalign_e.
169
170 • NCVISUAL_OPTION_ADDALPHA: Interpret the lower 24 bits of transcolor
171 as a transparent color.
172
173 • NCVISUAL_OPTION_CHILDPLANE: Make a new plane, as a child of n.
174
175 ncvisual_blitter_geom allows the caller to determine any or all of the
176 visual's pixel geometry, the blitter to be used, and that blitter's
177 scaling in both dimensions. Any but the first argument may be NULL.
178
179 ncplane_qrcode draws an ISO/IEC 18004:2015 QR Code for the len bytes of
180 data using NCBLIT_2x1 (this is the only blitter that will work with QR
181 Code scanners, due to its 1:1 aspect ratio).
182
184 begy and begx specify the upper left corner of the image to start draw‐
185 ing. leny and lenx specify the area of the subimage drawn. leny
186 and/or lenx may be specified as a negative number to draw through the
187 bottom right corner of the image.
188
189 The n field specifies the plane to use. If this is NULL, a new plane
190 will be created, having the precise geometry necessary to blit the
191 specified section of the image. This might be larger (or smaller) than
192 the visual area.
193
194 y and x have different meanings depending on whether or not n is NULL.
195 If not (drawing onto a preexisting plane), they specify where in the
196 plane to start drawing. If n was NULL (new plane), they specify the
197 origin of the new plane relative to the standard plane. If the flags
198 field contains NCVISUAL_OPTION_HORALIGNED, the x parameter is inter‐
199 preted as an ncalign_e rather than an absolute position. If the flags
200 field contains NCVISUAL_OPTION_VERALIGNED, the y parameter is inter‐
201 preted as an ncalign_e rather than an absolute position. If the flags
202 field contains NCVISUAL_OPTION_CHILDPLANE, n must be non-NULL, and the
203 x and y parameters are interpreted relative to that plane.
204
206 The different ncblitter_e values select from among available glyph
207 sets:
208
209 • NCBLIT_DEFAULT: Let the ncvisual choose its own blitter.
210
211 • NCBLIT_1x1: Spaces only. Works in ASCII, unlike most other blitters.
212
213 • NCBLIT_2x1: Adds the half blocks (▄▀) to NCBLIT_1x1.
214
215 • NCBLIT_2x2: Adds left and right half blocks (▌▐) and quadrants (▖▗▟▙)
216 to NCBLIT_2x1.
217
218 • NCBLIT_3x2: Adds sextants to NCBLIT_1x1.
219
220 • NCBLIT_BRAILLE: 4 rows and 2 columns of braille
221 (⡀⡄⡆⡇⢀⣀⣄⣆⣇⢠⣠⣤⣦⣧⢰⣰⣴⣶⣷⢸⣸⣼⣾⣿).
222
223 • NCBLIT_PIXEL: Adds pixel graphics (these also work in ASCII).
224
225 Two more blitters exist for plots, but are unsuitable for generic me‐
226 dia:
227
228 • NCBLIT_4x1: Adds ¼ and ¾ blocks (▂▆) to NCBLIT_2x1.
229
230 • NCBLIT_8x1: Adds ⅛, ⅜, ⅝, and ⅞ blocks (▇▅▃▁) to NCBLIT_4x1.
231
232 NCBLIT_4x1 and NCBLIT_8x1 are intended for use with plots, and are not
233 really applicable for general visuals. NCBLIT_BRAILLE doesn't tend to
234 work out very well for images, but (depending on the font) can be very
235 good for plots.
236
237 A string can be transformed to a blitter with notcurses_lex_blitter,
238 recognizing ascii, half, quad, sex, fourstep, braille, eightstep, and
239 pixel. Conversion in the opposite direction is performed with notcurs‐
240 es_str_blitter.
241
242 In the absence of scaling, for a given set of pixels, more rows and
243 columns in the blitter will result in a smaller output image. An image
244 rendered with NCBLIT_1x1 will be twice as tall as the same image ren‐
245 dered with NCBLIT_2x1, which will be twice as wide as the same image
246 rendered with NCBLIT_2x2. The same image rendered with NCBLIT_3x2 will
247 be one-third as tall and one-half as wide as the original NCBLIT_1x1
248 render (again, this depends on NCSCALE_NONE). If the output size is
249 held constant (using for instance NCSCALE_SCALE_HIRES and a large im‐
250 age), more rows and columns will result in more effective resolution.
251
252 A string can be transformed to a scaling mode with notcurses_lex_scale‐
253 mode, recognizing stretch, scalehi, hires, scale, inflate, and none.
254 Conversion in the opposite direction is performed with notcurs‐
255 es_str_scalemode.
256
257 Assuming a cell is twice as tall as it is wide, NCBLIT_1x1 (and indeed
258 any NxN blitter) will stretch an image by a factor of 2 in the vertical
259 dimension. NCBLIT_2x1 will not distort the image whatsoever, as it
260 maps a vector two pixels high and one pixel wide to a single cell.
261 NCBLIT_3x2 will stretch an image by a factor of 1.5.
262
263 The cell's dimension in pixels is ideally evenly divisible by the blit‐
264 ter geometry. If NCBLIT_3x2 is used together with a cell 8 pixels wide
265 and 14 pixels tall, two of the vertical segments will be 5 pixels tall,
266 while one will be 4 pixels tall. Such unequal distributions are more
267 likely with larger blitter geometries. Likewise, there are only ever
268 two colors available to us in a given cell. NCBLIT_1x1 and NCBLIT_2x2
269 can be perfectly represented with two colors per cell. Blitters of
270 higher geometry are increasingly likely to require some degree of in‐
271 terpolation. Transparency is always honored with complete fidelity.
272
273 Finally, rendering operates slightly differently when two planes have
274 both been blitted, and one lies atop the other. See notcurses_ren‐
275 der(3) for more information.
276
278 Some terminals support pixel-based output via one of a number of proto‐
279 cols. Checking for bitmap support requires interrogating the terminal
280 and reading a response. This takes time, and will never complete if
281 the terminal doesn't respond. Notcurses will not do so without an ex‐
282 plicit request from the client code. Before NCBLIT_PIXEL can be used,
283 it is thus necessary to call notcurses_check_pixel_support. If this
284 function has not successfully returned, attempts to use NCBLIT_PIXEL
285 will fall back to cell-based blitting (or fail, if NCVISUAL_OP‐
286 TION_NODEGRADE is used).
287
288 NCBLIT_PIXEL has some stringent requirements on the type of planes it
289 can be used with; it is usually best to let ncvisual_render create the
290 backing plane by providing a NULL value for n. If you must bring your
291 own plane, it must be perfectly sized for the bitmap (i.e. large
292 enough, and not more than a full cell larger in either dimension--the
293 bitmap, always placed at the origin, must at least partially cover ev‐
294 ery cell of the plane). Using NCSCALE_STRETCH means that the second
295 condition will always be met. Once a sprixel is blitted to a plane,
296 cell methods (including cell blitting) may not be used with it. Resiz‐
297 ing the plane eliminates the sprixel, as does destroying the plane. A
298 sprixelated plane may be moved in all three dimensions, duplicated, and
299 reparented. The base cell of a sprixelated plane is meaningless; if
300 the sprixel is not an even multiple of the cell geometry, any excess
301 cell material is ignored during rendering.
302
303 Only one bitmap can be blitted onto a plane at a time (but multiple
304 planes with bitmaps may be visible); blitting a second to the same
305 plane will delete the original.
306
308 ncvisual_from_file returns an ncvisual object on success, or NULL on
309 failure. Success indicates that the specified file was opened, and
310 enough data was read to make a firm codec identification. It does not
311 imply that the entire file is properly-formed.
312
313 ncvisual_decode returns 0 on success, or 1 on end of file, or -1 on
314 failure. It is only necessary for multimedia-based visuals. It ad‐
315 vances one frame for each call. ncvisual_decode_loop has the same re‐
316 turn values: when called following decoding of the last frame, it will
317 return 1, but a subsequent ncvisual_render will return the first frame.
318
319 ncvisual_from_plane returns NULL if the ncvisual cannot be created and
320 bound. This is usually due to illegal content in the source ncplane.
321
322 ncvisual_render returns NULL on error, and otherwise the plane to which
323 the visual was rendered. If opts->n is provided, this will be opts->n.
324 Otherwise, a plane will be created, perfectly sized for the visual and
325 the specified blitter.
326
327 ncvisual_blitter_geom returns non-zero if the specified blitter is in‐
328 valid.
329
330 ncvisual_media_defblitter returns the blitter selected by NCBLIT_DE‐
331 FAULT in the specified configuration. If UTF8 is not enabled, this
332 will always be NCBLIT_1x1. If scale is NCSCALE_NONE or NCSCALE_SCALE,
333 the aspect-preserving NCBLIT_2x1 will be returned. If sextants are
334 available (see notcurses_cansextant), this will be NCBLIT_3x2, or oth‐
335 erwise NCBLIT_2x2.
336
338 Multimedia decoding requires that Notcurses be built with either FFmpeg
339 or OpenImageIO support. What formats can be decoded is totally depen‐
340 dent on the linked library. OpenImageIO does not support subtitles.
341
342 Sixel documentation can be found at Dankwiki (https://nick-
343 black.com/dankwiki/index.php?title=Sixel). Kitty's graphics protocol
344 is specified in its documentation (https://sw.kovidgoyal.net/kit‐
345 ty/graphics-protocol.html).
346
347 Bad font support can ruin NCBLIT_2x2, NCBLIT_3x2, NCBLIT_4x1,
348 NCBLIT_BRAILLE, and NCBLIT_8x1. Braille glyphs ought ideally draw only
349 the raised dots, rather than drawing all eight dots with two different
350 styles. It's often best for the emulator to draw these glyphs itself.
351
352 Several emulators claim to implement Sixel, but do so in a more or less
353 broken fashion. I consider XTerm and foot to be reference Sixel imple‐
354 mentations on X.org and Wayland, respectively.
355
356 Sixels are fundamentally expressed in terms of six-line bands. If the
357 rendered bitmap is not a multiple of six rows, the necessary rows will
358 be faked via transparent rows. All sprixels have a height in rows, and
359 if this height is not a multiple of the cell height in rows, the last
360 rows will only partially obstruct a row of cells. This can lead to un‐
361 desirable redraws and flicker if the cells underneath the sprixel
362 change. A sprixel which is both a multiple of the cell height and a
363 multiple of six is the most predictable possible sprixel.
364
366 Functions which describe rendered state such as ncplane_at_yx and
367 notcurses_at_yx will return an nccell with a sprixel ID, but this
368 sprixel cannot be accessed.
369
370 ncvisual_rotate currently supports only M_PI/2 and -M_PI/2 radians for
371 rads, but this will change soon.
372
373 ncvisual_render should be able to create new planes in piles other than
374 the standard pile. This ought become a reality soon.
375
376 Sprixels interact poorly with multiple planes, and such usage is dis‐
377 couraged. This situation might improve in the future.
378
379 Multiple threads may not currently call ncvisual_render concurrently
380 using the same ncvisual, even if targeting distinct ncplanes. This
381 will likely change in the future.
382
384 notcurses(3), notcurses_capabilities(3), notcurses_plane(3), notcurs‐
385 es_render(3), utf-8(7)
386
388 nick black <nickblack@linux.com>.
389
390
391
392 v2.3.1 notcurses_visual(3)