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