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

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