1 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 
3 /* Copyright (C) 2018-2021 Hans Petter Jansson
4  *
5  * This file is part of Chafa, a program that turns images into character art.
6  *
7  * Chafa is free software: you can redistribute it and/or modify
8  * it under the terms of the GNU Lesser General Public License as published
9  * by the Free Software Foundation, either version 3 of the License, or
10  * (at your option) any later version.
11  *
12  * Chafa is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public License
18  * along with Chafa.  If not, see <http://www.gnu.org/licenses/>. */
19 
20 #include "config.h"
21 
22 #include <string.h>  /* memset, memcpy */
23 #include "chafa.h"
24 #include "internal/chafa-private.h"
25 
26 /**
27  * SECTION:chafa-canvas-config
28  * @title: ChafaCanvasConfig
29  * @short_description: Describes a configuration for #ChafaCanvas
30  *
31  * A #ChafaCanvasConfig describes a set of parameters for #ChafaCanvas, such
32  * as its geometry, color space and other output characteristics.
33  *
34  * To create a new #ChafaCanvasConfig, use chafa_canvas_config_new (). You
35  * can then modify it using its setters, e.g. chafa_canvas_config_set_canvas_mode ()
36  * before assigning it to a new #ChafaCanvas with chafa_canvas_new ().
37  *
38  * Note that it is not possible to change a canvas' configuration after
39  * the canvas is created.
40  **/
41 
42 /**
43  * ChafaCanvasMode:
44  * @CHAFA_CANVAS_MODE_TRUECOLOR: Truecolor.
45  * @CHAFA_CANVAS_MODE_INDEXED_256: 256 colors.
46  * @CHAFA_CANVAS_MODE_INDEXED_240: 256 colors, but avoid using the lower 16 whose values vary between terminal environments.
47  * @CHAFA_CANVAS_MODE_INDEXED_16: 16 colors using the aixterm ANSI extension.
48  * @CHAFA_CANVAS_MODE_INDEXED_8: 8 colors, compatible with original ANSI X3.64.
49  * @CHAFA_CANVAS_MODE_FGBG_BGFG: Default foreground and background colors, plus inversion.
50  * @CHAFA_CANVAS_MODE_FGBG: Default foreground and background colors. No ANSI codes will be used.
51  * @CHAFA_CANVAS_MODE_MAX: Last supported canvas mode plus one.
52  **/
53 
54 /**
55  * ChafaColorExtractor:
56  * @CHAFA_COLOR_EXTRACTOR_AVERAGE: Use the average colors of each symbol's coverage area.
57  * @CHAFA_COLOR_EXTRACTOR_MEDIAN: Use the median colors of each symbol's coverage area.
58  * @CHAFA_COLOR_EXTRACTOR_MAX: Last supported color extractor plus one.
59  **/
60 
61 /**
62  * ChafaColorSpace:
63  * @CHAFA_COLOR_SPACE_RGB: RGB color space. Fast but imprecise.
64  * @CHAFA_COLOR_SPACE_DIN99D: DIN99d color space. Slower, but good perceptual color precision.
65  * @CHAFA_COLOR_SPACE_MAX: Last supported color space plus one.
66  **/
67 
68 /**
69  * ChafaDitherMode:
70  * @CHAFA_DITHER_MODE_NONE: No dithering.
71  * @CHAFA_DITHER_MODE_ORDERED: Ordered dithering (Bayer or similar).
72  * @CHAFA_DITHER_MODE_DIFFUSION: Error diffusion dithering (Floyd-Steinberg or similar).
73  * @CHAFA_DITHER_MODE_MAX: Last supported dither mode plus one.
74  **/
75 
76 /**
77  * ChafaPixelMode:
78  * @CHAFA_PIXEL_MODE_SYMBOLS: Pixel data is approximated using character symbols ("ANSI art").
79  * @CHAFA_PIXEL_MODE_SIXELS: Pixel data is encoded as sixels.
80  * @CHAFA_PIXEL_MODE_KITTY: Pixel data is encoded using the Kitty terminal protocol.
81  * @CHAFA_PIXEL_MODE_ITERM2: Pixel data is encoded using the iTerm2 terminal protocol.
82  * @CHAFA_PIXEL_MODE_MAX: Last supported pixel mode plus one.
83  **/
84 
85 /**
86  * ChafaOptimizations:
87  * @CHAFA_OPTIMIZATION_REUSE_ATTRIBUTES: Suppress redundant SGR control sequences.
88  * @CHAFA_OPTIMIZATION_SKIP_CELLS: Reserved for future use.
89  * @CHAFA_OPTIMIZATION_REPEAT_CELLS: Use REP sequence to compress repeated runs of similar cells.
90  * @CHAFA_OPTIMIZATION_NONE: All optimizations disabled.
91  * @CHAFA_OPTIMIZATION_ALL: All optimizations enabled.
92  **/
93 
94 /* Private */
95 
96 void
chafa_canvas_config_init(ChafaCanvasConfig * canvas_config)97 chafa_canvas_config_init (ChafaCanvasConfig *canvas_config)
98 {
99     g_return_if_fail (canvas_config != NULL);
100 
101     memset (canvas_config, 0, sizeof (*canvas_config));
102     canvas_config->refs = 1;
103 
104     canvas_config->canvas_mode = CHAFA_CANVAS_MODE_TRUECOLOR;
105     canvas_config->color_extractor = CHAFA_COLOR_EXTRACTOR_AVERAGE;
106     canvas_config->color_space = CHAFA_COLOR_SPACE_RGB;
107     canvas_config->pixel_mode = CHAFA_PIXEL_MODE_SYMBOLS;
108     canvas_config->width = 80;
109     canvas_config->height = 24;
110     canvas_config->cell_width = 8;
111     canvas_config->cell_height = 8;
112     canvas_config->dither_mode = CHAFA_DITHER_MODE_NONE;
113     canvas_config->dither_grain_width = 4;
114     canvas_config->dither_grain_height = 4;
115     canvas_config->dither_intensity = 1.0;
116     canvas_config->fg_color_packed_rgb = 0xffffff;
117     canvas_config->bg_color_packed_rgb = 0x000000;
118     canvas_config->alpha_threshold = 127;
119     canvas_config->work_factor = 0.5;
120     canvas_config->preprocessing_enabled = TRUE;
121     canvas_config->optimizations = CHAFA_OPTIMIZATION_ALL;
122     canvas_config->fg_only_enabled = FALSE;
123 
124     chafa_symbol_map_init (&canvas_config->symbol_map);
125     chafa_symbol_map_add_by_tags (&canvas_config->symbol_map, CHAFA_SYMBOL_TAG_BLOCK);
126     chafa_symbol_map_add_by_tags (&canvas_config->symbol_map, CHAFA_SYMBOL_TAG_BORDER);
127     chafa_symbol_map_add_by_tags (&canvas_config->symbol_map, CHAFA_SYMBOL_TAG_SPACE);
128     chafa_symbol_map_remove_by_tags (&canvas_config->symbol_map, CHAFA_SYMBOL_TAG_WIDE);
129 
130     chafa_symbol_map_init (&canvas_config->fill_symbol_map);
131 }
132 
133 void
chafa_canvas_config_deinit(ChafaCanvasConfig * canvas_config)134 chafa_canvas_config_deinit (ChafaCanvasConfig *canvas_config)
135 {
136     g_return_if_fail (canvas_config != NULL);
137 
138     chafa_symbol_map_deinit (&canvas_config->symbol_map);
139     chafa_symbol_map_deinit (&canvas_config->fill_symbol_map);
140 }
141 
142 void
chafa_canvas_config_copy_contents(ChafaCanvasConfig * dest,const ChafaCanvasConfig * src)143 chafa_canvas_config_copy_contents (ChafaCanvasConfig *dest, const ChafaCanvasConfig *src)
144 {
145     g_return_if_fail (dest != NULL);
146     g_return_if_fail (src != NULL);
147 
148     memcpy (dest, src, sizeof (*dest));
149     chafa_symbol_map_copy_contents (&dest->symbol_map, &src->symbol_map);
150     chafa_symbol_map_copy_contents (&dest->fill_symbol_map, &src->fill_symbol_map);
151     dest->refs = 1;
152 }
153 
154 /* Public */
155 
156 /**
157  * chafa_canvas_config_new:
158  *
159  * Creates a new #ChafaCanvasConfig with default settings. This
160  * object can later be used in the creation of a #ChafaCanvas.
161  *
162  * Returns: The new #ChafaCanvasConfig
163  **/
164 ChafaCanvasConfig *
chafa_canvas_config_new(void)165 chafa_canvas_config_new (void)
166 {
167     ChafaCanvasConfig *canvas_config;
168 
169     canvas_config = g_new (ChafaCanvasConfig, 1);
170     chafa_canvas_config_init (canvas_config);
171     return canvas_config;
172 }
173 
174 /**
175  * chafa_canvas_config_copy:
176  * @config: A #ChafaSymbolMap to copy.
177  *
178  * Creates a new #ChafaCanvasConfig that's a copy of @config.
179  *
180  * Returns: The new #ChafaCanvasConfig
181  **/
182 ChafaCanvasConfig *
chafa_canvas_config_copy(const ChafaCanvasConfig * config)183 chafa_canvas_config_copy (const ChafaCanvasConfig *config)
184 {
185     ChafaCanvasConfig *new_config;
186 
187     new_config = g_new (ChafaCanvasConfig, 1);
188     chafa_canvas_config_copy_contents (new_config, config);
189     return new_config;
190 }
191 
192 /**
193  * chafa_canvas_config_ref:
194  * @config: #ChafaCanvasConfig to add a reference to.
195  *
196  * Adds a reference to @config.
197  **/
198 void
chafa_canvas_config_ref(ChafaCanvasConfig * config)199 chafa_canvas_config_ref (ChafaCanvasConfig *config)
200 {
201     gint refs;
202 
203     g_return_if_fail (config != NULL);
204     refs = g_atomic_int_get (&config->refs);
205     g_return_if_fail (refs > 0);
206 
207     g_atomic_int_inc (&config->refs);
208 }
209 
210 /**
211  * chafa_canvas_config_unref:
212  * @config: #ChafaCanvasConfig to remove a reference from.
213  *
214  * Removes a reference from @config.
215  **/
216 void
chafa_canvas_config_unref(ChafaCanvasConfig * config)217 chafa_canvas_config_unref (ChafaCanvasConfig *config)
218 {
219     gint refs;
220 
221     g_return_if_fail (config != NULL);
222     refs = g_atomic_int_get (&config->refs);
223     g_return_if_fail (refs > 0);
224 
225     if (g_atomic_int_dec_and_test (&config->refs))
226     {
227         chafa_canvas_config_deinit (config);
228         g_free (config);
229     }
230 }
231 
232 /**
233  * chafa_canvas_config_get_geometry:
234  * @config: A #ChafaCanvasConfig
235  * @width_out: Location to store width in, or %NULL
236  * @height_out: Location to store height in, or %NULL
237  *
238  * Returns @config's width and height in character cells in the
239  * provided output locations.
240  **/
241 void
chafa_canvas_config_get_geometry(const ChafaCanvasConfig * config,gint * width_out,gint * height_out)242 chafa_canvas_config_get_geometry (const ChafaCanvasConfig *config, gint *width_out, gint *height_out)
243 {
244     g_return_if_fail (config != NULL);
245     g_return_if_fail (config->refs > 0);
246 
247     if (width_out)
248         *width_out = config->width;
249     if (height_out)
250         *height_out = config->height;
251 }
252 
253 /**
254  * chafa_canvas_config_set_geometry:
255  * @config: A #ChafaCanvasConfig
256  * @width: Width in character cells
257  * @height: Height in character cells
258  *
259  * Sets @config's width and height in character cells to @width x @height.
260  **/
261 void
chafa_canvas_config_set_geometry(ChafaCanvasConfig * config,gint width,gint height)262 chafa_canvas_config_set_geometry (ChafaCanvasConfig *config, gint width, gint height)
263 {
264     g_return_if_fail (config != NULL);
265     g_return_if_fail (config->refs > 0);
266     g_return_if_fail (width > 0);
267     g_return_if_fail (height > 0);
268 
269     config->width = width;
270     config->height = height;
271 }
272 
273 /**
274  * chafa_canvas_config_get_cell_geometry:
275  * @config: A #ChafaCanvasConfig
276  * @cell_width_out: Location to store cell width in, or %NULL
277  * @cell_height_out: Location to store cell height in, or %NULL
278  *
279  * Returns @config's cell width and height in pixels in the
280  * provided output locations.
281  *
282  * Since: 1.4
283  **/
284 void
chafa_canvas_config_get_cell_geometry(const ChafaCanvasConfig * config,gint * cell_width_out,gint * cell_height_out)285 chafa_canvas_config_get_cell_geometry (const ChafaCanvasConfig *config, gint *cell_width_out, gint *cell_height_out)
286 {
287     g_return_if_fail (config != NULL);
288     g_return_if_fail (config->refs > 0);
289 
290     if (cell_width_out)
291         *cell_width_out = config->cell_width;
292     if (cell_height_out)
293         *cell_height_out = config->cell_height;
294 }
295 
296 /**
297  * chafa_canvas_config_set_cell_geometry:
298  * @config: A #ChafaCanvasConfig
299  * @cell_width: Cell width in pixels
300  * @cell_height: Cell height in pixels
301  *
302  * Sets @config's cell width and height in pixels to @cell_width x @cell_height.
303  *
304  * Since: 1.4
305  **/
306 void
chafa_canvas_config_set_cell_geometry(ChafaCanvasConfig * config,gint cell_width,gint cell_height)307 chafa_canvas_config_set_cell_geometry (ChafaCanvasConfig *config, gint cell_width, gint cell_height)
308 {
309     g_return_if_fail (config != NULL);
310     g_return_if_fail (config->refs > 0);
311     g_return_if_fail (cell_width > 0);
312     g_return_if_fail (cell_height > 0);
313 
314     config->cell_width = cell_width;
315     config->cell_height = cell_height;
316 }
317 
318 /**
319  * chafa_canvas_config_get_canvas_mode:
320  * @config: A #ChafaCanvasConfig
321  *
322  * Returns @config's #ChafaCanvasMode. This determines how colors (and
323  * color control codes) are used in the output.
324  *
325  * Returns: The #ChafaCanvasMode.
326  **/
327 ChafaCanvasMode
chafa_canvas_config_get_canvas_mode(const ChafaCanvasConfig * config)328 chafa_canvas_config_get_canvas_mode (const ChafaCanvasConfig *config)
329 {
330     g_return_val_if_fail (config != NULL, CHAFA_CANVAS_MODE_TRUECOLOR);
331     g_return_val_if_fail (config->refs > 0, CHAFA_CANVAS_MODE_TRUECOLOR);
332 
333     return config->canvas_mode;
334 }
335 
336 /**
337  * chafa_canvas_config_set_canvas_mode:
338  * @config: A #ChafaCanvasConfig
339  * @mode: A #ChafaCanvasMode
340  *
341  * Sets @config's stored #ChafaCanvasMode to @mode. This determines how
342  * colors (and color control codes) are used in the output.
343  **/
344 void
chafa_canvas_config_set_canvas_mode(ChafaCanvasConfig * config,ChafaCanvasMode mode)345 chafa_canvas_config_set_canvas_mode (ChafaCanvasConfig *config, ChafaCanvasMode mode)
346 {
347     g_return_if_fail (config != NULL);
348     g_return_if_fail (config->refs > 0);
349     g_return_if_fail (mode < CHAFA_CANVAS_MODE_MAX);
350 
351     config->canvas_mode = mode;
352 }
353 
354 /**
355  * chafa_canvas_config_get_color_extractor:
356  * @config: A #ChafaCanvasConfig
357  *
358  * Returns @config's #ChafaColorExtractor. This determines how colors are
359  * approximated in character symbol output.
360  *
361  * Returns: The #ChafaColorExtractor.
362  *
363  * Since: 1.4
364  **/
365 ChafaColorExtractor
chafa_canvas_config_get_color_extractor(const ChafaCanvasConfig * config)366 chafa_canvas_config_get_color_extractor (const ChafaCanvasConfig *config)
367 {
368     g_return_val_if_fail (config != NULL, CHAFA_COLOR_EXTRACTOR_AVERAGE);
369     g_return_val_if_fail (config->refs > 0, CHAFA_COLOR_EXTRACTOR_AVERAGE);
370 
371     return config->color_extractor;
372 }
373 
374 /**
375  * chafa_canvas_config_set_color_extractor:
376  * @config: A #ChafaCanvasConfig
377  * @color_extractor: A #ChafaColorExtractor
378  *
379  * Sets @config's stored #ChafaColorExtractor to @color_extractor. This
380  * determines how colors are approximated in character symbol output.
381  *
382  * Since: 1.4
383  **/
384 void
chafa_canvas_config_set_color_extractor(ChafaCanvasConfig * config,ChafaColorExtractor color_extractor)385 chafa_canvas_config_set_color_extractor (ChafaCanvasConfig *config, ChafaColorExtractor color_extractor)
386 {
387     g_return_if_fail (config != NULL);
388     g_return_if_fail (config->refs > 0);
389     g_return_if_fail (color_extractor < CHAFA_COLOR_EXTRACTOR_MAX);
390 
391     config->color_extractor = color_extractor;
392 }
393 
394 /**
395  * chafa_canvas_config_get_color_space:
396  * @config: A #ChafaCanvasConfig
397  *
398  * Returns @config's #ChafaColorSpace.
399  *
400  * Returns: The #ChafaColorSpace.
401  **/
402 ChafaColorSpace
chafa_canvas_config_get_color_space(const ChafaCanvasConfig * config)403 chafa_canvas_config_get_color_space (const ChafaCanvasConfig *config)
404 {
405     g_return_val_if_fail (config != NULL, CHAFA_COLOR_SPACE_RGB);
406     g_return_val_if_fail (config->refs > 0, CHAFA_COLOR_SPACE_RGB);
407 
408     return config->color_space;
409 }
410 
411 /**
412  * chafa_canvas_config_set_color_space:
413  * @config: A #ChafaCanvasConfig
414  * @color_space: A #ChafaColorSpace
415  *
416  * Sets @config's stored #ChafaColorSpace to @color_space.
417  **/
418 void
chafa_canvas_config_set_color_space(ChafaCanvasConfig * config,ChafaColorSpace color_space)419 chafa_canvas_config_set_color_space (ChafaCanvasConfig *config, ChafaColorSpace color_space)
420 {
421     g_return_if_fail (config != NULL);
422     g_return_if_fail (config->refs > 0);
423     g_return_if_fail (color_space < CHAFA_COLOR_SPACE_MAX);
424 
425     config->color_space = color_space;
426 }
427 
428 /**
429  * chafa_canvas_config_peek_symbol_map:
430  * @config: A #ChafaCanvasConfig
431  *
432  * Returns a pointer to the symbol map belonging to @config.
433  * This can be inspected using the #ChafaSymbolMap getter
434  * functions, but not changed.
435  *
436  * Returns: A pointer to the config's immutable symbol map
437  **/
438 const ChafaSymbolMap *
chafa_canvas_config_peek_symbol_map(const ChafaCanvasConfig * config)439 chafa_canvas_config_peek_symbol_map (const ChafaCanvasConfig *config)
440 {
441     g_return_val_if_fail (config != NULL, NULL);
442     g_return_val_if_fail (config->refs > 0, NULL);
443 
444     return &config->symbol_map;
445 }
446 
447 /**
448  * chafa_canvas_config_set_symbol_map:
449  * @config: A #ChafaCanvasConfig
450  * @symbol_map: A #ChafaSymbolMap
451  *
452  * Assigns a copy of @symbol_map to @config.
453  **/
454 void
chafa_canvas_config_set_symbol_map(ChafaCanvasConfig * config,const ChafaSymbolMap * symbol_map)455 chafa_canvas_config_set_symbol_map (ChafaCanvasConfig *config, const ChafaSymbolMap *symbol_map)
456 {
457     g_return_if_fail (config != NULL);
458     g_return_if_fail (config->refs > 0);
459 
460     chafa_symbol_map_deinit (&config->symbol_map);
461     chafa_symbol_map_copy_contents (&config->symbol_map, symbol_map);
462 }
463 
464 /**
465  * chafa_canvas_config_peek_fill_symbol_map:
466  * @config: A #ChafaCanvasConfig
467  *
468  * Returns a pointer to the fill symbol map belonging to @config.
469  * This can be inspected using the #ChafaSymbolMap getter
470  * functions, but not changed.
471  *
472  * Fill symbols are assigned according to their overall foreground to
473  * background coverage, disregarding shape.
474  *
475  * Returns: A pointer to the config's immutable fill symbol map
476  **/
477 const ChafaSymbolMap *
chafa_canvas_config_peek_fill_symbol_map(const ChafaCanvasConfig * config)478 chafa_canvas_config_peek_fill_symbol_map (const ChafaCanvasConfig *config)
479 {
480     g_return_val_if_fail (config != NULL, NULL);
481     g_return_val_if_fail (config->refs > 0, NULL);
482 
483     return &config->fill_symbol_map;
484 }
485 
486 /**
487  * chafa_canvas_config_set_fill_symbol_map:
488  * @config: A #ChafaCanvasConfig
489  * @fill_symbol_map: A #ChafaSymbolMap
490  *
491  * Assigns a copy of @fill_symbol_map to @config.
492  **/
493 void
chafa_canvas_config_set_fill_symbol_map(ChafaCanvasConfig * config,const ChafaSymbolMap * fill_symbol_map)494 chafa_canvas_config_set_fill_symbol_map (ChafaCanvasConfig *config, const ChafaSymbolMap *fill_symbol_map)
495 {
496     g_return_if_fail (config != NULL);
497     g_return_if_fail (config->refs > 0);
498 
499     chafa_symbol_map_deinit (&config->fill_symbol_map);
500     chafa_symbol_map_copy_contents (&config->fill_symbol_map, fill_symbol_map);
501 }
502 
503 /**
504  * chafa_canvas_config_get_transparency_threshold:
505  * @config: A #ChafaCanvasConfig
506  *
507  * Returns the threshold above which full transparency will be used.
508  *
509  * Returns: The transparency threshold [0.0 - 1.0]
510  **/
511 gfloat
chafa_canvas_config_get_transparency_threshold(const ChafaCanvasConfig * config)512 chafa_canvas_config_get_transparency_threshold (const ChafaCanvasConfig *config)
513 {
514     g_return_val_if_fail (config != NULL, 0.0);
515     g_return_val_if_fail (config->refs > 0, 0.0);
516 
517     return 1.0 - (config->alpha_threshold / 256.0);
518 }
519 
520 /**
521  * chafa_canvas_config_set_transparency_threshold:
522  * @config: A #ChafaCanvasConfig
523  * @alpha_threshold: The transparency threshold [0.0 - 1.0].
524  *
525  * Sets the threshold above which full transparency will be used.
526  **/
527 void
chafa_canvas_config_set_transparency_threshold(ChafaCanvasConfig * config,gfloat alpha_threshold)528 chafa_canvas_config_set_transparency_threshold (ChafaCanvasConfig *config, gfloat alpha_threshold)
529 {
530     g_return_if_fail (config != NULL);
531     g_return_if_fail (config->refs > 0);
532     g_return_if_fail (alpha_threshold >= 0.0);
533     g_return_if_fail (alpha_threshold <= 1.0);
534 
535     /* Invert the scale; internally it's more like an opacity threshold */
536     config->alpha_threshold = 256.0 * (1.0 - alpha_threshold);
537 }
538 
539 /**
540  * chafa_canvas_config_get_fg_color:
541  * @config: A #ChafaCanvasConfig
542  *
543  * Gets the assumed foreground color of the output device. This is used to
544  * determine how to apply the foreground pen in FGBG modes.
545  *
546  * Returns: Foreground color as packed RGB triplet
547  **/
548 guint32
chafa_canvas_config_get_fg_color(const ChafaCanvasConfig * config)549 chafa_canvas_config_get_fg_color (const ChafaCanvasConfig *config)
550 {
551     g_return_val_if_fail (config != NULL, 0);
552     g_return_val_if_fail (config->refs > 0, 0);
553 
554     return config->fg_color_packed_rgb;
555 }
556 
557 /**
558  * chafa_canvas_config_set_fg_color:
559  * @config: A #ChafaCanvasConfig
560  * @fg_color_packed_rgb: Foreground color as packed RGB triplet
561  *
562  * Sets the assumed foreground color of the output device. This is used to
563  * determine how to apply the foreground pen in FGBG modes.
564  **/
565 void
chafa_canvas_config_set_fg_color(ChafaCanvasConfig * config,guint32 fg_color_packed_rgb)566 chafa_canvas_config_set_fg_color (ChafaCanvasConfig *config, guint32 fg_color_packed_rgb)
567 {
568     g_return_if_fail (config != NULL);
569     g_return_if_fail (config->refs > 0);
570 
571     config->fg_color_packed_rgb = fg_color_packed_rgb;
572 }
573 
574 /**
575  * chafa_canvas_config_get_bg_color:
576  * @config: A #ChafaCanvasConfig
577  *
578  * Gets the assumed background color of the output device. This is used to
579  * determine how to apply the background pen in FGBG modes.
580  *
581  * Returns: Background color as packed RGB triplet
582  **/
583 guint32
chafa_canvas_config_get_bg_color(const ChafaCanvasConfig * config)584 chafa_canvas_config_get_bg_color (const ChafaCanvasConfig *config)
585 {
586     g_return_val_if_fail (config != NULL, 0);
587     g_return_val_if_fail (config->refs > 0, 0);
588 
589     return config->bg_color_packed_rgb;
590 }
591 
592 /**
593  * chafa_canvas_config_set_bg_color:
594  * @config: A #ChafaCanvasConfig
595  * @bg_color_packed_rgb: Background color as packed RGB triplet
596  *
597  * Sets the assumed background color of the output device. This is used to
598  * determine how to apply the background and transparency pens in FGBG modes,
599  * and will also be substituted for partial transparency.
600  **/
601 void
chafa_canvas_config_set_bg_color(ChafaCanvasConfig * config,guint32 bg_color_packed_rgb)602 chafa_canvas_config_set_bg_color (ChafaCanvasConfig *config, guint32 bg_color_packed_rgb)
603 {
604     g_return_if_fail (config != NULL);
605     g_return_if_fail (config->refs > 0);
606 
607     config->bg_color_packed_rgb = bg_color_packed_rgb;
608 }
609 
610 /**
611  * chafa_canvas_config_get_work_factor:
612  * @config: A #ChafaCanvasConfig
613  *
614  * Gets the work/quality tradeoff factor. A higher value means more time
615  * and memory will be spent towards a higher quality output.
616  *
617  * Returns: The work factor [0.0 - 1.0]
618  **/
619 gfloat
chafa_canvas_config_get_work_factor(const ChafaCanvasConfig * config)620 chafa_canvas_config_get_work_factor (const ChafaCanvasConfig *config)
621 {
622     g_return_val_if_fail (config != NULL, 1);
623     g_return_val_if_fail (config->refs > 0, 1);
624 
625     return config->work_factor;
626 }
627 
628 /**
629  * chafa_canvas_config_set_work_factor:
630  * @config: A #ChafaCanvasConfig
631  * @work_factor: Work factor [0.0 - 1.0]
632  *
633  * Sets the work/quality tradeoff factor. A higher value means more time
634  * and memory will be spent towards a higher quality output.
635  **/
636 void
chafa_canvas_config_set_work_factor(ChafaCanvasConfig * config,gfloat work_factor)637 chafa_canvas_config_set_work_factor (ChafaCanvasConfig *config, gfloat work_factor)
638 {
639     g_return_if_fail (config != NULL);
640     g_return_if_fail (config->refs > 0);
641     g_return_if_fail (work_factor >= 0.0 && work_factor <= 1.0);
642 
643     config->work_factor = work_factor;
644 }
645 
646 /**
647  * chafa_canvas_config_get_preprocessing_enabled:
648  * @config: A #ChafaCanvasConfig
649  *
650  * Queries whether automatic image preprocessing is enabled. This allows
651  * Chafa to boost contrast and saturation in an attempt to improve
652  * legibility. The type of preprocessing applied (if any) depends on the
653  * canvas mode.
654  *
655  * Returns: Whether automatic preprocessing is enabled
656  **/
657 gboolean
chafa_canvas_config_get_preprocessing_enabled(const ChafaCanvasConfig * config)658 chafa_canvas_config_get_preprocessing_enabled (const ChafaCanvasConfig *config)
659 {
660     g_return_val_if_fail (config != NULL, FALSE);
661     g_return_val_if_fail (config->refs > 0, FALSE);
662 
663     return config->preprocessing_enabled;
664 }
665 
666 /**
667  * chafa_canvas_config_set_preprocessing_enabled:
668  * @config: A #ChafaCanvasConfig
669  * @preprocessing_enabled: Whether automatic preprocessing should be enabled
670  *
671  * Indicates whether automatic image preprocessing should be enabled. This
672  * allows Chafa to boost contrast and saturation in an attempt to improve
673  * legibility. The type of preprocessing applied (if any) depends on the
674  * canvas mode.
675  **/
676 void
chafa_canvas_config_set_preprocessing_enabled(ChafaCanvasConfig * config,gboolean preprocessing_enabled)677 chafa_canvas_config_set_preprocessing_enabled (ChafaCanvasConfig *config, gboolean preprocessing_enabled)
678 {
679     g_return_if_fail (config != NULL);
680     g_return_if_fail (config->refs > 0);
681 
682     config->preprocessing_enabled = preprocessing_enabled;
683 }
684 
685 /**
686  * chafa_canvas_config_get_dither_mode:
687  * @config: A #ChafaCanvasConfig
688  *
689  * Returns @config's #ChafaDitherMode.
690  *
691  * Returns: The #ChafaDitherMode.
692  *
693  * Since: 1.2
694  **/
695 ChafaDitherMode
chafa_canvas_config_get_dither_mode(const ChafaCanvasConfig * config)696 chafa_canvas_config_get_dither_mode (const ChafaCanvasConfig *config)
697 {
698     g_return_val_if_fail (config != NULL, CHAFA_DITHER_MODE_NONE);
699     g_return_val_if_fail (config->refs > 0, CHAFA_DITHER_MODE_NONE);
700 
701     return config->dither_mode;
702 }
703 
704 /**
705  * chafa_canvas_config_set_dither_mode:
706  * @config: A #ChafaCanvasConfig
707  * @dither_mode: A #ChafaDitherMode
708  *
709  * Sets @config's stored #ChafaDitherMode to @dither_mode.
710  *
711  * Since: 1.2
712  **/
713 void
chafa_canvas_config_set_dither_mode(ChafaCanvasConfig * config,ChafaDitherMode dither_mode)714 chafa_canvas_config_set_dither_mode (ChafaCanvasConfig *config, ChafaDitherMode dither_mode)
715 {
716     g_return_if_fail (config != NULL);
717     g_return_if_fail (config->refs > 0);
718     g_return_if_fail (dither_mode < CHAFA_DITHER_MODE_MAX);
719 
720     config->dither_mode = dither_mode;
721 }
722 
723 /**
724  * chafa_canvas_config_get_dither_grain_size:
725  * @config: A #ChafaCanvasConfig
726  * @width_out: Pointer to a location to store grain width
727  * @height_out: Pointer to a location to store grain height
728  *
729  * Returns @config's dither grain size in @width_out and @height_out.
730  *
731  * Since: 1.2
732  **/
733 void
chafa_canvas_config_get_dither_grain_size(const ChafaCanvasConfig * config,gint * width_out,gint * height_out)734 chafa_canvas_config_get_dither_grain_size (const ChafaCanvasConfig *config, gint *width_out, gint *height_out)
735 {
736     g_return_if_fail (config != NULL);
737     g_return_if_fail (config->refs > 0);
738 
739     if (width_out)
740         *width_out = config->dither_grain_width;
741     if (height_out)
742         *height_out = config->dither_grain_height;
743 }
744 
745 /**
746  * chafa_canvas_config_set_dither_grain_size:
747  * @config: A #ChafaCanvasConfig
748  * @width: The desired grain width (1, 2, 4 or 8)
749  * @height: The desired grain height (1, 2, 4 or 8)
750  *
751  * Sets @config's stored dither grain size to @width by @height pixels. These
752  * values can be 1, 2, 4 or 8. 8 corresponds to the size of an entire
753  * character cell. The default is 4 pixels by 4 pixels.
754  *
755  * Since: 1.2
756  **/
757 void
chafa_canvas_config_set_dither_grain_size(ChafaCanvasConfig * config,gint width,gint height)758 chafa_canvas_config_set_dither_grain_size (ChafaCanvasConfig *config, gint width, gint height)
759 {
760     g_return_if_fail (config != NULL);
761     g_return_if_fail (config->refs > 0);
762     g_return_if_fail (width == 1 || width == 2 || width == 4 || width == 8);
763     g_return_if_fail (height == 1 || height == 2 || height == 4 || height == 8);
764 
765     config->dither_grain_width = width;
766     config->dither_grain_height = height;
767 }
768 
769 /**
770  * chafa_canvas_config_get_dither_intensity:
771  * @config: A #ChafaCanvasConfig
772  *
773  * Returns the relative intensity of the dithering pattern applied during
774  * image conversion. 1.0 is the default, corresponding to a moderate
775  * intensity.
776  *
777  * Returns: The relative dithering intensity
778  *
779  * Since: 1.2
780  **/
781 gfloat
chafa_canvas_config_get_dither_intensity(const ChafaCanvasConfig * config)782 chafa_canvas_config_get_dither_intensity (const ChafaCanvasConfig *config)
783 {
784     g_return_val_if_fail (config != NULL, 1.0);
785     g_return_val_if_fail (config->refs > 0, 1.0);
786 
787     return config->dither_intensity;
788 }
789 
790 /**
791  * chafa_canvas_config_set_dither_intensity:
792  * @config: A #ChafaCanvasConfig
793  * @intensity: Desired relative dithering intensity
794  *
795  * Sets @config's stored relative intensity of the dithering pattern applied
796  * during image conversion. 1.0 is the default, corresponding to a moderate
797  * intensity. Possible values range from 0.0 to infinity, but in practice,
798  * values above 10.0 are rarely useful.
799  *
800  * Since: 1.2
801  **/
802 void
chafa_canvas_config_set_dither_intensity(ChafaCanvasConfig * config,gfloat intensity)803 chafa_canvas_config_set_dither_intensity (ChafaCanvasConfig *config, gfloat intensity)
804 {
805     g_return_if_fail (config != NULL);
806     g_return_if_fail (config->refs > 0);
807     g_return_if_fail (intensity >= 0.0);
808 
809     config->dither_intensity = intensity;
810 }
811 
812 /**
813  * chafa_canvas_config_get_pixel_mode:
814  * @config: A #ChafaCanvasConfig
815  *
816  * Returns @config's #ChafaPixelMode.
817  *
818  * Returns: The #ChafaPixelMode. This determines how pixel graphics are
819  * rendered in the output.
820  *
821  * Since: 1.4
822  **/
823 ChafaPixelMode
chafa_canvas_config_get_pixel_mode(const ChafaCanvasConfig * config)824 chafa_canvas_config_get_pixel_mode (const ChafaCanvasConfig *config)
825 {
826     g_return_val_if_fail (config != NULL, CHAFA_PIXEL_MODE_SYMBOLS);
827     g_return_val_if_fail (config->refs > 0, CHAFA_PIXEL_MODE_SYMBOLS);
828 
829     return config->pixel_mode;
830 }
831 
832 /**
833  * chafa_canvas_config_set_pixel_mode:
834  * @config: A #ChafaCanvasConfig
835  * @pixel_mode: A #ChafaPixelMode
836  *
837  * Sets @config's stored #ChafaPixelMode to @pixel_mode. This determines
838  * how pixel graphics are rendered in the output.
839  *
840  * Since: 1.4
841  **/
842 void
chafa_canvas_config_set_pixel_mode(ChafaCanvasConfig * config,ChafaPixelMode pixel_mode)843 chafa_canvas_config_set_pixel_mode (ChafaCanvasConfig *config, ChafaPixelMode pixel_mode)
844 {
845     g_return_if_fail (config != NULL);
846     g_return_if_fail (config->refs > 0);
847     g_return_if_fail (pixel_mode < CHAFA_PIXEL_MODE_MAX);
848 
849     config->pixel_mode = pixel_mode;
850 }
851 
852 /**
853  * chafa_canvas_config_get_optimizations:
854  * @config: A #ChafaCanvasConfig
855  *
856  * Returns @config's optimization flags. When enabled, these may produce
857  * more compact output at the cost of reduced compatibility and increased CPU
858  * use. Output quality is unaffected.
859  *
860  * Returns: The #ChafaOptimizations flags.
861  *
862  * Since: 1.6
863  **/
864 ChafaOptimizations
chafa_canvas_config_get_optimizations(const ChafaCanvasConfig * config)865 chafa_canvas_config_get_optimizations (const ChafaCanvasConfig *config)
866 {
867     g_return_val_if_fail (config != NULL, CHAFA_OPTIMIZATION_NONE);
868     g_return_val_if_fail (config->refs > 0, CHAFA_OPTIMIZATION_NONE);
869 
870     return config->optimizations;
871 }
872 
873 /**
874  * chafa_canvas_config_set_optimizations:
875  * @config: A #ChafaCanvasConfig
876  * @optimizations: A combination of #ChafaOptimizations flags
877  *
878  * Sets @config's stored optimization flags. When enabled, these may produce
879  * more compact output at the cost of reduced compatibility and increased CPU
880  * use. Output quality is unaffected.
881  *
882  * Since: 1.6
883  **/
884 void
chafa_canvas_config_set_optimizations(ChafaCanvasConfig * config,ChafaOptimizations optimizations)885 chafa_canvas_config_set_optimizations (ChafaCanvasConfig *config, ChafaOptimizations optimizations)
886 {
887     g_return_if_fail (config != NULL);
888     g_return_if_fail (config->refs > 0);
889 
890     config->optimizations = optimizations;
891 }
892 
893 /**
894  * chafa_canvas_config_get_fg_only_enabled:
895  * @config: A #ChafaCanvasConfig
896  *
897  * Queries whether to use foreground colors only, leaving the background
898  * unmodified in the canvas output. This is relevant only when the
899  * #ChafaPixelMode is set to #CHAFA_PIXEL_MODE_SYMBOLS.
900  *
901  * When this is set, the canvas will emit escape codes to set the foreground
902  * color only.
903  *
904  * Returns: %TRUE if using foreground colors only, %FALSE otherwise.
905  *
906  * Since: 1.8
907  **/
908 gboolean
chafa_canvas_config_get_fg_only_enabled(const ChafaCanvasConfig * config)909 chafa_canvas_config_get_fg_only_enabled (const ChafaCanvasConfig *config)
910 {
911     g_return_val_if_fail (config != NULL, CHAFA_OPTIMIZATION_NONE);
912     g_return_val_if_fail (config->refs > 0, CHAFA_OPTIMIZATION_NONE);
913 
914     return config->fg_only_enabled;
915 }
916 
917 /**
918  * chafa_canvas_config_set_fg_only_enabled:
919  * @config: A #ChafaCanvasConfig
920  * @fg_only_enabled: Whether to use foreground colors only
921  *
922  * Indicates whether to use foreground colors only, leaving the background
923  * unmodified in the canvas output. This is relevant only when the
924  * #ChafaPixelMode is set to #CHAFA_PIXEL_MODE_SYMBOLS.
925  *
926  * When this is set, the canvas will emit escape codes to set the foreground
927  * color only.
928  *
929  * Since: 1.8
930  **/
931 void
chafa_canvas_config_set_fg_only_enabled(ChafaCanvasConfig * config,gboolean fg_only_enabled)932 chafa_canvas_config_set_fg_only_enabled (ChafaCanvasConfig *config, gboolean fg_only_enabled)
933 {
934     g_return_if_fail (config != NULL);
935     g_return_if_fail (config->refs > 0);
936 
937     config->fg_only_enabled = fg_only_enabled;
938 }
939