source: libcaca/trunk/cucul/colour.c @ 1254

Last change on this file since 1254 was 1254, checked in by Sam Hocevar, 14 years ago
  • Use the LSB of alpha and blue components to encode additional flags such as bold or underline. No higher level support for these yet, but at least everything is consistent.
  • Created cucul_set_attr_ansi() and cucul_set_attr_argb() which are bound to replace cucul_set_color() and cucul_set_truecolor().
  • Property svn:keywords set to Id
File size: 9.8 KB
Line 
1/*
2 *  libcucul      Canvas for ultrafast compositing of Unicode letters
3 *  Copyright (c) 2002-2006 Sam Hocevar <sam@zoy.org>
4 *                All Rights Reserved
5 *
6 *  $Id: colour.c 1254 2006-10-28 23:53:46Z sam $
7 *
8 *  This library is free software; you can redistribute it and/or
9 *  modify it under the terms of the Do What The Fuck You Want To
10 *  Public License, Version 2, as published by Sam Hocevar. See
11 *  http://sam.zoy.org/wtfpl/COPYING for more details.
12 */
13
14/*
15 *  This file contains functions for converting colour values between
16 *  various colourspaces.
17 */
18
19#include "config.h"
20#include "common.h"
21
22#if defined(HAVE_ERRNO_H)
23#   include <errno.h>
24#endif
25
26#include "cucul.h"
27#include "cucul_internals.h"
28
29/* RGB colours for the ANSI palette. There is no real standard, so we
30 * use the same values as gnome-terminal. The 7th colour (brown) is a bit
31 * special: 0xfa50 instead of 0xfaa0. */
32static const uint16_t ansitab[16] =
33{
34    0xf000, 0xf00a, 0xf0a0, 0xf0aa, 0xfa00, 0xfa0a, 0xfa50, 0xfaaa,
35    0xf555, 0xf55f, 0xf5f5, 0xf5ff, 0xff55, 0xff5f, 0xfff5, 0xffff,
36};
37
38/** \brief Set the default character attribute.
39 *
40 *  Set the default character attribute for drawing. Attributes define
41 *  foreground and background colour, transparency, bold, italics and
42 *  underline styles, as well as blink. String functions such as
43 *  caca_printf() and graphical primitive functions such as caca_draw_line()
44 *  will use this attribute.
45 *
46 *  The attribute value is a 32-bit integer as returned by cucul_get_attr().
47 *  For more user-friendly versions of this function, see cucul_set_attr_ansi()
48 *  and cucul_set_attr_argb().
49 *
50 *  If an error occurs, -1 is returned and \b errno is set accordingly:
51 *  - \c EINVAL The attribute value is out of the 32-bit range.
52 *
53 *  \param cv A handle to the libcucul canvas.
54 *  \param attr The requested attribute value.
55 *  \return 0 in case of success, -1 if an error occurred.
56 */
57int cucul_set_attr(cucul_canvas_t *cv, unsigned long int attr)
58{
59    if(sizeof(unsigned long int) > sizeof(uint32_t) && attr > 0xffffffff)
60    {
61#if defined(HAVE_ERRNO_H)
62        errno = EINVAL;
63#endif
64        return -1;
65    }
66
67    cv->curattr = attr;
68
69    return 0;
70}
71
72/** \brief Set the default colour pair and text style (ANSI version).
73 *
74 *  Set the default ANSI colour pair and text style for drawing. String
75 *  functions such as caca_printf() and graphical primitive functions such as
76 *  caca_draw_line() will use these attributes.
77 *
78 *  Color values are those defined in cucul.h, such as CUCUL_COLOR_RED
79 *  or CUCUL_COLOR_TRANSPARENT.
80 *
81 *  Style values are those defined in cucul.h, such as CUCUL_STYLE_UNDERLINE
82 *  or CUCUL_STYLE_BLINK. The values can be ORed to set several styles at
83 *  the same time.
84 *
85 *  If an error occurs, -1 is returned and \b errno is set accordingly:
86 *  - \c EINVAL The colour values and/or the style mask are invalid.
87 *
88 *  \param cv A handle to the libcucul canvas.
89 *  \param fg The requested foreground colour.
90 *  \param bg The requested background colour.
91 *  \param style The requested text styles.
92 *  \return 0 in case of success, -1 if an error occurred.
93 */
94int cucul_set_attr_ansi(cucul_canvas_t *cv, unsigned char fg, unsigned char bg,
95                        unsigned char style)
96{
97    uint32_t attr;
98
99    if(fg > 0x20 || bg > 0x20 || style > 0x0f)
100    {
101#if defined(HAVE_ERRNO_H)
102        errno = EINVAL;
103#endif
104        return -1;
105    }
106
107    attr = ((uint32_t)bg << 20) | ((uint32_t)fg << 4);
108
109    if(style)
110        attr |= (0x02004801 * style) & 0x10011001;
111
112    cv->curattr = attr;
113
114    return 0;
115}
116
117/* Legacy function for old programs */
118int cucul_set_color(cucul_canvas_t *cv, unsigned char fg, unsigned char bg)
119{
120    return cucul_set_attr_ansi(cv, fg, bg, 0);
121}
122
123/** \brief Set the default colour pair and text style (truecolor version).
124 *
125 *  Set the default colour pair and text style for drawing. String
126 *  functions such as caca_printf() and graphical primitive functions such as
127 *  caca_draw_line() will use these attributes.
128 *
129 *  Colors are 16-bit ARGB values, each component being coded on 4 bits. For
130 *  instance, 0xf088 is solid dark cyan (A=15 R=0 G=8 B=8), and 0x8fff is
131 *  white with 50% alpha (A=8 R=15 G=15 B=15).
132 *
133 *  Style values are those defined in cucul.h, such as CUCUL_STYLE_UNDERLINE
134 *  or CUCUL_STYLE_BLINK. The values can be ORed to set several styles at
135 *  the same time.
136 *
137 *  If an error occurs, -1 is returned and \b errno is set accordingly:
138 *  - \c EINVAL At least one of the colour values is invalid.
139 *
140 *  \param cv A handle to the libcucul canvas.
141 *  \param fg The requested foreground colour.
142 *  \param bg The requested background colour.
143 *  \param style The requested text styles.
144 *  \return 0 in case of success, -1 if an error occurred.
145 */
146int cucul_set_attr_argb(cucul_canvas_t *cv, unsigned int fg, unsigned int bg,
147                        unsigned char style)
148{
149    uint32_t attr;
150
151    if(fg > 0xffff || bg > 0xffff || style > 0x0f)
152    {
153#if defined(HAVE_ERRNO_H)
154        errno = EINVAL;
155#endif
156        return -1;
157    }
158
159    if(fg < 0x100)
160        fg += 0x100;
161
162    if(bg < 0x100)
163        bg += 0x100;
164
165    attr = (((uint32_t)bg << 16) | (uint32_t)fg) & 0xeffeeffe;
166
167    if(style)
168        attr |= (0x02004801 * style) & 0x10011001;
169
170    cv->curattr = attr;
171
172    return 0;
173}
174
175/* Legacy function for old programs */
176int cucul_set_truecolor(cucul_canvas_t *cv, unsigned int fg, unsigned int bg)
177{
178    return cucul_set_attr_argb(cv, fg, bg, 0);
179}
180
181/** \brief Get the text attribute at the given coordinates.
182 *
183 *  Get the internal \e libcucul attribute value of the character at the
184 *  given coordinates. The attribute value has 32 significant bits,
185 *  organised as follows from MSB to LSB:
186 *  - 3 bits for the background alpha
187 *  - 1 bit for the blink flag
188 *  - 4 bits for the background red component
189 *  - 4 bits for the background green component
190 *  - 3 bits for the background blue component
191 *  - 1 bit for the underline flag
192 *  - 3 bits for the foreground alpha
193 *  - 1 bit for the italics flag
194 *  - 4 bits for the foreground red component
195 *  - 4 bits for the foreground green component
196 *  - 3 bits for the foreground blue component
197 *  - 1 bit for the bold flag
198 *
199 *  If the coordinates are outside the canvas boundaries, the current
200 *  attribute is returned.
201 *
202 *  This function never fails.
203 *
204 *  \param cv A handle to the libcucul canvas.
205 *  \param x X coordinate.
206 *  \param y Y coordinate.
207 *  \return The requested attribute.
208 */
209unsigned long int cucul_get_attr(cucul_canvas_t *cv, int x, int y)
210{
211    if(x < 0 || x >= (int)cv->width || y < 0 || y >= (int)cv->height)
212        return (unsigned long int)cv->curattr;
213
214    return (unsigned long int)cv->attrs[x + y * cv->width];
215}
216
217/*
218 * XXX: the following functions are local
219 */
220
221static uint8_t nearest_ansi(uint16_t argb16, uint8_t def)
222{
223    unsigned int i, best, dist;
224
225    if(argb16 == (argb16 & 0x00f0))
226        return argb16 >> 4;
227
228    if(argb16 == (CUCUL_COLOR_DEFAULT << 4)
229       || argb16 == (CUCUL_COLOR_TRANSPARENT << 4))
230        return def;
231
232    if(argb16 < 0x6fff) /* too transparent, return default colour */
233        return def;
234
235    best = def;
236    dist = 0xffff;
237    for(i = 0; i < 16; i++)
238    {
239        unsigned int d = 0;
240        int a, b;
241
242        a = (ansitab[i] >> 8) & 0xf;
243        b = (argb16 >> 8) & 0xf;
244        d += (a - b) * (a - b);
245
246        a = (ansitab[i] >> 4) & 0xf;
247        b = (argb16 >> 4) & 0xf;
248        d += (a - b) * (a - b);
249
250        a = ansitab[i] & 0xf;
251        b = argb16 & 0xf;
252        d += (a - b) * (a - b);
253
254        if(d < dist)
255        {
256            dist = d;
257            best = i;
258        }
259    }
260
261    return best;
262}
263
264uint8_t _cucul_attr_to_ansi8(uint32_t attr)
265{
266    uint16_t fg = attr & 0xeffe;
267    uint16_t bg = (attr >> 16) & 0xeffe;
268
269    return nearest_ansi(fg, CUCUL_COLOR_LIGHTGRAY)
270            | (nearest_ansi(bg, CUCUL_COLOR_BLACK) << 4);
271}
272
273uint8_t _cucul_attr_to_ansi4fg(uint32_t attr)
274{
275    return nearest_ansi(attr & 0xeffe, CUCUL_COLOR_LIGHTGRAY);
276}
277
278uint8_t _cucul_attr_to_ansi4bg(uint32_t attr)
279{
280    return nearest_ansi((attr >> 16) & 0xeffe, CUCUL_COLOR_BLACK);
281}
282
283uint16_t _cucul_attr_to_rgb12fg(uint32_t attr)
284{
285    uint16_t fg = attr & 0xeffe;
286
287    if(fg == (fg & 0x00f0))
288        return ansitab[fg >> 4] & 0x0fff;
289
290    if(fg == (CUCUL_COLOR_DEFAULT << 4))
291        return ansitab[CUCUL_COLOR_LIGHTGRAY] & 0x0fff;
292
293    if(fg == (CUCUL_COLOR_TRANSPARENT << 4))
294        return ansitab[CUCUL_COLOR_LIGHTGRAY] & 0x0fff;
295
296    return fg & 0x0fff;
297}
298
299uint16_t _cucul_attr_to_rgb12bg(uint32_t attr)
300{
301    uint16_t bg = (attr >> 16) & 0xeffe;
302
303    if(bg == (bg & 0x00f0))
304        return ansitab[bg >> 4] & 0x0fff;
305
306    if(bg == (CUCUL_COLOR_DEFAULT << 4))
307        return ansitab[CUCUL_COLOR_BLACK] & 0x0fff;
308
309    if(bg == (CUCUL_COLOR_TRANSPARENT << 4))
310        return ansitab[CUCUL_COLOR_BLACK] & 0x0fff;
311
312    return bg & 0x0fff;
313}
314
315#define RGB12TO24(i) \
316   (((uint32_t)((i & 0xf00) >> 8) * 0x110000) \
317  | ((uint32_t)((i & 0x0f0) >> 4) * 0x001100) \
318  | ((uint32_t)(i & 0x00f) * 0x000011))
319
320uint32_t _cucul_attr_to_rgb24fg(uint32_t attr)
321{
322    return RGB12TO24(_cucul_attr_to_rgb12fg(attr));
323}
324
325uint32_t _cucul_attr_to_rgb24bg(uint32_t attr)
326{
327    return RGB12TO24(_cucul_attr_to_rgb12bg(attr));
328}
329
330void _cucul_attr_to_argb4(uint32_t attr, uint8_t argb[8])
331{
332    uint16_t fg = attr & 0xeffe;
333    uint16_t bg = (attr >> 16) & 0xeffe;
334
335    if(fg == (fg & 0x00f0))
336        fg = ansitab[fg >> 4];
337    else if(fg == (CUCUL_COLOR_DEFAULT << 4))
338        fg = ansitab[CUCUL_COLOR_LIGHTGRAY];
339    else if(fg == (CUCUL_COLOR_TRANSPARENT << 4))
340        fg = 0x0fff;
341
342    if(bg == (bg & 0x00f0))
343        bg = ansitab[bg >> 4];
344    else if(bg == (CUCUL_COLOR_DEFAULT << 4))
345        bg = ansitab[CUCUL_COLOR_BLACK];
346    else if(bg == (CUCUL_COLOR_TRANSPARENT << 4))
347        bg = 0x0fff;
348
349    argb[0] = bg >> 12;
350    argb[1] = (bg >> 8) & 0xf;
351    argb[2] = (bg >> 4) & 0xf;
352    argb[3] = bg & 0xf;
353
354    argb[4] = fg >> 12;
355    argb[5] = (fg >> 8) & 0xf;
356    argb[6] = (fg >> 4) & 0xf;
357    argb[7] = fg & 0xf;
358}
359
Note: See TracBrowser for help on using the repository browser.