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

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