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

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