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

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