"Fossies" - the Fresh Open Source Software Archive 
Member "libcaca-0.99.beta20/caca/attr.c" (22 May 2018, 16837 Bytes) of package /linux/privat/libcaca-0.99.beta20.tar.bz2:
1 /*
2 * libcaca Colour ASCII-Art library
3 * Copyright © 2002—2018 Sam Hocevar <sam@hocevar.net>
4 * All Rights Reserved
5 *
6 * This library is free software. It comes without any warranty, to
7 * the extent permitted by applicable law. You can redistribute it
8 * and/or modify it under the terms of the Do What the Fuck You Want
9 * to Public License, Version 2, as published by Sam Hocevar. See
10 * http://www.wtfpl.net/ for more details.
11 */
12
13 /*
14 * This file contains functions for attribute management and colourspace
15 * conversions.
16 */
17
18 #include "config.h"
19
20 #include "caca.h"
21 #include "caca_internals.h"
22
23 static uint8_t nearest_ansi(uint16_t);
24
25 /* RGB colours for the ANSI palette. There is no real standard, so we
26 * use the same values as gnome-terminal. The 7th colour (brown) is a bit
27 * special: 0xfa50 instead of 0xfaa0. */
28 static const uint16_t ansitab16[16] =
29 {
30 0xf000, 0xf00a, 0xf0a0, 0xf0aa, 0xfa00, 0xfa0a, 0xfa50, 0xfaaa,
31 0xf555, 0xf55f, 0xf5f5, 0xf5ff, 0xff55, 0xff5f, 0xfff5, 0xffff,
32 };
33
34 /* Same table, except on 14 bits (3-4-4-3) */
35 static const uint16_t ansitab14[16] =
36 {
37 0x3800, 0x3805, 0x3850, 0x3855, 0x3d00, 0x3d05, 0x3d28, 0x3d55,
38 0x3aaa, 0x3aaf, 0x3afa, 0x3aff, 0x3faa, 0x3faf, 0x3ffa, 0x3fff,
39 };
40
41 /** \brief Get the text attribute at the given coordinates.
42 *
43 * Get the internal \e libcaca attribute value of the character at the
44 * given coordinates. The attribute value has 32 significant bits,
45 * organised as follows from MSB to LSB:
46 * - 3 bits for the background alpha
47 * - 4 bits for the background red component
48 * - 4 bits for the background green component
49 * - 3 bits for the background blue component
50 * - 3 bits for the foreground alpha
51 * - 4 bits for the foreground red component
52 * - 4 bits for the foreground green component
53 * - 3 bits for the foreground blue component
54 * - 4 bits for the bold, italics, underline and blink flags
55 *
56 * If the coordinates are outside the canvas boundaries, the current
57 * attribute is returned.
58 *
59 * This function never fails.
60 *
61 * \param cv A handle to the libcaca canvas.
62 * \param x X coordinate.
63 * \param y Y coordinate.
64 * \return The requested attribute.
65 */
66 uint32_t caca_get_attr(caca_canvas_t const *cv, int x, int y)
67 {
68 if(x < 0 || x >= (int)cv->width || y < 0 || y >= (int)cv->height)
69 return cv->curattr;
70
71 return cv->attrs[x + y * cv->width];
72 }
73
74 /** \brief Set the default character attribute.
75 *
76 * Set the default character attribute for drawing. Attributes define
77 * foreground and background colour, transparency, bold, italics and
78 * underline styles, as well as blink. String functions such as
79 * caca_printf() and graphical primitive functions such as caca_draw_line()
80 * will use this attribute.
81 *
82 * The value of \e attr is either:
83 * - a 32-bit integer as returned by caca_get_attr(), in which case it
84 * also contains colour information,
85 * - a combination (bitwise OR) of style values (\e CACA_UNDERLINE,
86 * \e CACA_BLINK, \e CACA_BOLD and \e CACA_ITALICS), in which case
87 * setting the attribute does not modify the current colour information.
88 *
89 * To retrieve the current attribute value, use caca_get_attr(-1,-1).
90 *
91 * This function never fails.
92 *
93 * \param cv A handle to the libcaca canvas.
94 * \param attr The requested attribute value.
95 * \return This function always returns 0.
96 */
97 int caca_set_attr(caca_canvas_t *cv, uint32_t attr)
98 {
99 if(attr < 0x00000010)
100 attr = (cv->curattr & 0xfffffff0) | attr;
101
102 cv->curattr = attr;
103
104 return 0;
105 }
106
107 /** \brief Unset flags in the default character attribute.
108 *
109 * Unset flags in the default character attribute for drawing. Attributes
110 * define foreground and background colour, transparency, bold, italics and
111 * underline styles, as well as blink. String functions such as
112 * caca_printf() and graphical primitive functions such as caca_draw_line()
113 * will use this attribute.
114 *
115 * The value of \e attr is a combination (bitwise OR) of style values
116 * (\e CACA_UNDERLINE, \e CACA_BLINK, \e CACA_BOLD and \e CACA_ITALICS).
117 * Unsetting these attributes does not modify the current colour information.
118 *
119 * To retrieve the current attribute value, use caca_get_attr(-1,-1).
120 *
121 * This function never fails.
122 *
123 * \param cv A handle to the libcaca canvas.
124 * \param attr The requested attribute values to unset.
125 * \return This function always returns 0.
126 */
127 int caca_unset_attr(caca_canvas_t *cv, uint32_t attr)
128 {
129 cv->curattr &= ~(attr & 0x0000000f);
130
131 return 0;
132 }
133
134 /** \brief Toggle flags in the default character attribute.
135 *
136 * Toggle flags in the default character attribute for drawing. Attributes
137 * define foreground and background colour, transparency, bold, italics and
138 * underline styles, as well as blink. String functions such as
139 * caca_printf() and graphical primitive functions such as caca_draw_line()
140 * will use this attribute.
141 *
142 * The value of \e attr is a combination (bitwise OR) of style values
143 * (\e CACA_UNDERLINE, \e CACA_BLINK, \e CACA_BOLD and \e CACA_ITALICS).
144 * Toggling these attributes does not modify the current colour information.
145 *
146 * To retrieve the current attribute value, use caca_get_attr(-1,-1).
147 *
148 * This function never fails.
149 *
150 * \param cv A handle to the libcaca canvas.
151 * \param attr The requested attribute values to toggle.
152 * \return This function always returns 0.
153 */
154 int caca_toggle_attr(caca_canvas_t *cv, uint32_t attr)
155 {
156 cv->curattr ^= attr & 0x0000000f;
157
158 return 0;
159 }
160
161 /** \brief Set the character attribute at the given coordinates.
162 *
163 * Set the character attribute, without changing the character's value. If
164 * the character at the given coordinates is a fullwidth character, both
165 * cells' attributes are replaced.
166 *
167 * The value of \e attr is either:
168 * - a 32-bit integer as returned by caca_get_attr(), in which case it
169 * also contains colour information,
170 * - a combination (bitwise OR) of style values (\e CACA_UNDERLINE,
171 * \e CACA_BLINK, \e CACA_BOLD and \e CACA_ITALICS), in which case
172 * setting the attribute does not modify the current colour information.
173 *
174 * This function never fails.
175 *
176 * \param cv A handle to the libcaca canvas.
177 * \param x X coordinate.
178 * \param y Y coordinate.
179 * \param attr The requested attribute value.
180 * \return This function always returns 0.
181 */
182 int caca_put_attr(caca_canvas_t *cv, int x, int y, uint32_t attr)
183 {
184 uint32_t *curattr, *curchar;
185 int xmin, xmax;
186
187 if(x < 0 || x >= (int)cv->width || y < 0 || y >= (int)cv->height)
188 return 0;
189
190 xmin = xmax = x;
191
192 curchar = cv->chars + x + y * cv->width;
193 curattr = cv->attrs + x + y * cv->width;
194
195 if(attr < 0x00000010)
196 curattr[0] = (curattr[0] & 0xfffffff0) | attr;
197 else
198 curattr[0] = attr;
199
200 if(x && curchar[0] == CACA_MAGIC_FULLWIDTH)
201 {
202 curattr[-1] = curattr[0];
203 xmin--;
204 }
205 else if(x + 1 < (int)cv->width && curchar[1] == CACA_MAGIC_FULLWIDTH)
206 {
207 curattr[1] = curattr[0];
208 xmax++;
209 }
210
211 if(!cv->dirty_disabled)
212 caca_add_dirty_rect(cv, xmin, y, xmax - xmin + 1, 1);
213
214 return 0;
215 }
216
217 /** \brief Set the default colour pair for text (ANSI version).
218 *
219 * Set the default ANSI colour pair for text drawing. String functions such
220 * as caca_printf() and graphical primitive functions such as caca_draw_line()
221 * will use these attributes.
222 *
223 * Color values are those defined in caca.h, such as CACA_RED
224 * or CACA_TRANSPARENT.
225 *
226 * If an error occurs, -1 is returned and \b errno is set accordingly:
227 * - \c EINVAL At least one of the colour values is invalid.
228 *
229 * \param cv A handle to the libcaca canvas.
230 * \param fg The requested ANSI foreground colour.
231 * \param bg The requested ANSI background colour.
232 * \return 0 in case of success, -1 if an error occurred.
233 */
234 int caca_set_color_ansi(caca_canvas_t *cv, uint8_t fg, uint8_t bg)
235 {
236 uint32_t attr;
237
238 if(fg > 0x20 || bg > 0x20)
239 {
240 seterrno(EINVAL);
241 return -1;
242 }
243
244 attr = ((uint32_t)(bg | 0x40) << 18) | ((uint32_t)(fg | 0x40) << 4);
245 cv->curattr = (cv->curattr & 0x0000000f) | attr;
246
247 return 0;
248 }
249
250 /** \brief Set the default colour pair for text (truecolor version).
251 *
252 * Set the default ARGB colour pair for text drawing. String functions such
253 * as caca_printf() and graphical primitive functions such as caca_draw_line()
254 * will use these attributes.
255 *
256 * Colors are 16-bit ARGB values, each component being coded on 4 bits. For
257 * instance, 0xf088 is solid dark cyan (A=15 R=0 G=8 B=8), and 0x8fff is
258 * white with 50% alpha (A=8 R=15 G=15 B=15).
259 *
260 * This function never fails.
261 *
262 * \param cv A handle to the libcaca canvas.
263 * \param fg The requested ARGB foreground colour.
264 * \param bg The requested ARGB background colour.
265 * \return This function always returns 0.
266 */
267 int caca_set_color_argb(caca_canvas_t *cv, uint16_t fg, uint16_t bg)
268 {
269 uint32_t attr;
270
271 if(fg < 0x100)
272 fg += 0x100;
273
274 if(bg < 0x100)
275 bg += 0x100;
276
277 fg = ((fg >> 1) & 0x7ff) | ((fg >> 13) << 11);
278 bg = ((bg >> 1) & 0x7ff) | ((bg >> 13) << 11);
279
280 attr = ((uint32_t)bg << 18) | ((uint32_t)fg << 4);
281 cv->curattr = (cv->curattr & 0x0000000f) | attr;
282
283 return 0;
284 }
285
286 /** \brief Get DOS ANSI information from attribute.
287 *
288 * Get the ANSI colour pair for a given attribute. The returned value is
289 * an 8-bit value whose higher 4 bits are the background colour and lower
290 * 4 bits are the foreground colour.
291 *
292 * If the attribute has ARGB colours, the nearest colour is used. Special
293 * attributes such as \e CACA_DEFAULT and \e CACA_TRANSPARENT are not
294 * handled and are both replaced with \e CACA_LIGHTGRAY for the foreground
295 * colour and \e CACA_BLACK for the background colour.
296 *
297 * This function never fails. If the attribute value is outside the expected
298 * 32-bit range, higher order bits are simply ignored.
299 *
300 * \param attr The requested attribute value.
301 * \return The corresponding DOS ANSI value.
302 */
303 uint8_t caca_attr_to_ansi(uint32_t attr)
304 {
305 uint8_t fg = nearest_ansi((attr >> 4) & 0x3fff);
306 uint8_t bg = nearest_ansi(attr >> 18);
307
308 return (fg < 0x10 ? fg : CACA_LIGHTGRAY)
309 | ((bg < 0x10 ? bg : CACA_BLACK) << 4);
310 }
311
312 /** \brief Get ANSI foreground information from attribute.
313 *
314 * Get the ANSI foreground colour value for a given attribute. The returned
315 * value is either one of the \e CACA_RED, \e CACA_BLACK etc. predefined
316 * colours, or the special value \e CACA_DEFAULT meaning the media's
317 * default foreground value, or the special value \e CACA_TRANSPARENT.
318 *
319 * If the attribute has ARGB colours, the nearest colour is returned.
320 *
321 * This function never fails. If the attribute value is outside the expected
322 * 32-bit range, higher order bits are simply ignored.
323 *
324 * \param attr The requested attribute value.
325 * \return The corresponding ANSI foreground value.
326 */
327 uint8_t caca_attr_to_ansi_fg(uint32_t attr)
328 {
329 return nearest_ansi((attr >> 4) & 0x3fff);
330 }
331
332 /** \brief Get ANSI background information from attribute.
333 *
334 * Get the ANSI background colour value for a given attribute. The returned
335 * value is either one of the \e CACA_RED, \e CACA_BLACK etc. predefined
336 * colours, or the special value \e CACA_DEFAULT meaning the media's
337 * default background value, or the special value \e CACA_TRANSPARENT.
338 *
339 * If the attribute has ARGB colours, the nearest colour is returned.
340 *
341 * This function never fails. If the attribute value is outside the expected
342 * 32-bit range, higher order bits are simply ignored.
343 *
344 * \param attr The requested attribute value.
345 * \return The corresponding ANSI background value.
346 */
347 uint8_t caca_attr_to_ansi_bg(uint32_t attr)
348 {
349 return nearest_ansi(attr >> 18);
350 }
351
352 /** \brief Get 12-bit RGB foreground information from attribute.
353 *
354 * Get the 12-bit foreground colour value for a given attribute. The returned
355 * value is a native-endian encoded integer with each red, green and blue
356 * values encoded on 8 bits in the following order:
357 * - 8-11 most significant bits: red
358 * - 4-7 most significant bits: green
359 * - least significant bits: blue
360 *
361 * This function never fails. If the attribute value is outside the expected
362 * 32-bit range, higher order bits are simply ignored.
363 *
364 * \param attr The requested attribute value.
365 * \return The corresponding 12-bit RGB foreground value.
366 */
367 uint16_t caca_attr_to_rgb12_fg(uint32_t attr)
368 {
369 uint16_t fg = (attr >> 4) & 0x3fff;
370
371 if(fg < (0x10 | 0x40))
372 return ansitab16[fg ^ 0x40] & 0x0fff;
373
374 if(fg == (CACA_DEFAULT | 0x40))
375 return ansitab16[CACA_LIGHTGRAY] & 0x0fff;
376
377 if(fg == (CACA_TRANSPARENT | 0x40))
378 return ansitab16[CACA_LIGHTGRAY] & 0x0fff;
379
380 return (fg << 1) & 0x0fff;
381 }
382
383 /** \brief Get 12-bit RGB background information from attribute.
384 *
385 * Get the 12-bit background colour value for a given attribute. The returned
386 * value is a native-endian encoded integer with each red, green and blue
387 * values encoded on 8 bits in the following order:
388 * - 8-11 most significant bits: red
389 * - 4-7 most significant bits: green
390 * - least significant bits: blue
391 *
392 * This function never fails. If the attribute value is outside the expected
393 * 32-bit range, higher order bits are simply ignored.
394 *
395 * \param attr The requested attribute value.
396 * \return The corresponding 12-bit RGB background value.
397 */
398 uint16_t caca_attr_to_rgb12_bg(uint32_t attr)
399 {
400 uint16_t bg = attr >> 18;
401
402 if(bg < (0x10 | 0x40))
403 return ansitab16[bg ^ 0x40] & 0x0fff;
404
405 if(bg == (CACA_DEFAULT | 0x40))
406 return ansitab16[CACA_BLACK] & 0x0fff;
407
408 if(bg == (CACA_TRANSPARENT | 0x40))
409 return ansitab16[CACA_BLACK] & 0x0fff;
410
411 return (bg << 1) & 0x0fff;
412 }
413
414 /** \brief Get 64-bit ARGB information from attribute.
415 *
416 * Get the 64-bit colour and alpha values for a given attribute. The values
417 * are written as 8-bit integers in the \e argb array in the following order:
418 * - \e argb[0]: background alpha value
419 * - \e argb[1]: background red value
420 * - \e argb[2]: background green value
421 * - \e argb[3]: background blue value
422 * - \e argb[4]: foreground alpha value
423 * - \e argb[5]: foreground red value
424 * - \e argb[6]: foreground green value
425 * - \e argb[7]: foreground blue value
426 *
427 * This function never fails. If the attribute value is outside the expected
428 * 32-bit range, higher order bits are simply ignored.
429 *
430 * \param attr The requested attribute value.
431 * \param argb An array of 8-bit integers.
432 */
433 void caca_attr_to_argb64(uint32_t attr, uint8_t argb[8])
434 {
435 uint16_t fg = (attr >> 4) & 0x3fff;
436 uint16_t bg = attr >> 18;
437
438 if(bg < (0x10 | 0x40))
439 bg = ansitab16[bg ^ 0x40];
440 else if(bg == (CACA_DEFAULT | 0x40))
441 bg = ansitab16[CACA_BLACK];
442 else if(bg == (CACA_TRANSPARENT | 0x40))
443 bg = 0x0fff;
444 else
445 bg = ((bg << 2) & 0xf000) | ((bg << 1) & 0x0fff);
446
447 argb[0] = bg >> 12;
448 argb[1] = (bg >> 8) & 0xf;
449 argb[2] = (bg >> 4) & 0xf;
450 argb[3] = bg & 0xf;
451
452 if(fg < (0x10 | 0x40))
453 fg = ansitab16[fg ^ 0x40];
454 else if(fg == (CACA_DEFAULT | 0x40))
455 fg = ansitab16[CACA_LIGHTGRAY];
456 else if(fg == (CACA_TRANSPARENT | 0x40))
457 fg = 0x0fff;
458 else
459 fg = ((fg << 2) & 0xf000) | ((fg << 1) & 0x0fff);
460
461 argb[4] = fg >> 12;
462 argb[5] = (fg >> 8) & 0xf;
463 argb[6] = (fg >> 4) & 0xf;
464 argb[7] = fg & 0xf;
465 }
466
467 /*
468 * XXX: the following functions are local
469 */
470
471 static uint8_t nearest_ansi(uint16_t argb14)
472 {
473 unsigned int i, best, dist;
474
475 if(argb14 < (0x10 | 0x40))
476 return argb14 ^ 0x40;
477
478 if(argb14 == (CACA_DEFAULT | 0x40) || argb14 == (CACA_TRANSPARENT | 0x40))
479 return argb14 ^ 0x40;
480
481 if(argb14 < 0x0fff) /* too transparent */
482 return CACA_TRANSPARENT;
483
484 best = CACA_DEFAULT;
485 dist = 0x3fff;
486 for(i = 0; i < 16; i++)
487 {
488 unsigned int d = 0;
489 int a, b;
490
491 a = (ansitab14[i] >> 7) & 0xf;
492 b = (argb14 >> 7) & 0xf;
493 d += (a - b) * (a - b);
494
495 a = (ansitab14[i] >> 3) & 0xf;
496 b = (argb14 >> 3) & 0xf;
497 d += (a - b) * (a - b);
498
499 a = (ansitab14[i] << 1) & 0xf;
500 b = (argb14 << 1) & 0xf;
501 d += (a - b) * (a - b);
502
503 if(d < dist)
504 {
505 dist = d;
506 best = i;
507 }
508 }
509
510 return best;
511 }
512
513 #define RGB12TO24(i) \
514 (((uint32_t)((i & 0xf00) >> 8) * 0x110000) \
515 | ((uint32_t)((i & 0x0f0) >> 4) * 0x001100) \
516 | ((uint32_t)(i & 0x00f) * 0x000011))
517
518 uint32_t _caca_attr_to_rgb24fg(uint32_t attr)
519 {
520 return RGB12TO24(caca_attr_to_rgb12_fg(attr));
521 }
522
523 uint32_t _caca_attr_to_rgb24bg(uint32_t attr)
524 {
525 return RGB12TO24(caca_attr_to_rgb12_bg(attr));
526 }
527