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