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

Last change on this file since 874 was 874, checked in by Sam Hocevar, 15 years ago
  • More error checking in libcucul.
  • Property svn:keywords set to Id
File size: 5.9 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 874 2006-04-25 11:05:25Z 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
29static const uint16_t ansitab[16] =
30{
31    0xf000, 0xf008, 0xf080, 0xf088, 0xf800, 0xf808, 0xf880, 0xf888,
32    0xf444, 0xf44f, 0xf4f4, 0xf4ff, 0xff44, 0xff4f, 0xfff4, 0xffff,
33};
34
35/** \brief Set the default colour pair.
36 *
37 *  This function sets the default ANSI colour pair. String functions such as
38 *  caca_printf() and graphical primitive functions such as caca_draw_line()
39 *  will use these colours.
40 *
41 *  Color values are those defined in cucul.h, such as CUCUL_COLOR_RED
42 *  or CUCUL_COLOR_TRANSPARENT.
43 *
44 *  If an error occurs, -1 is returned and \b errno is set accordingly:
45 *  - \c EINVAL At least one of the colour values is invalid.
46 *
47 *  \param cv A handle to the libcucul canvas.
48 *  \param fg The requested foreground colour.
49 *  \param bg The requested background colour.
50 *  \return 0 in case of success, -1 if an error occurred.
51 */
52int cucul_set_color(cucul_canvas_t *cv, unsigned char fg, unsigned char bg)
53{
54    if(fg > 0x20 || bg > 0x20)
55    {
56#if defined(HAVE_ERRNO_H)
57        errno = EINVAL;
58#endif
59        return -1;
60    }
61
62    cv->fgcolor = fg;
63    cv->bgcolor = bg;
64
65    return 0;
66}
67
68/** \brief Set the default colour pair (truecolor version).
69 *
70 *  This function sets the default colour pair. String functions such as
71 *  caca_printf() and graphical primitive functions such as caca_draw_line()
72 *  will use these colours.
73 *
74 *  Colors are 16-bit ARGB values, each component being coded on 4 bits. For
75 *  instance, 0xf088 is solid dark cyan (A=15 R=0 G=8 B=8), and 0x8fff is
76 *  white with 50% alpha (A=8 R=15 G=15 B=15).
77 *
78 *  If an error occurs, -1 is returned and \b errno is set accordingly:
79 *  - \c EINVAL At least one of the colour values is invalid.
80 *
81 *  \param cv A handle to the libcucul canvas.
82 *  \param fg The requested foreground colour.
83 *  \param bg The requested background colour.
84 *  \return 0 in case of success, -1 if an error occurred.
85 */
86int cucul_set_truecolor(cucul_canvas_t *cv, unsigned int fg, unsigned int bg)
87{
88    if(fg > 0xffff || bg > 0xffff)
89    {
90#if defined(HAVE_ERRNO_H)
91        errno = EINVAL;
92#endif
93        return -1;
94    }
95
96    if(fg < 0x100)
97        fg += 0x100;
98
99    if(bg < 0x100)
100        bg += 0x100;
101
102    cv->fgcolor = fg;
103    cv->bgcolor = bg;
104
105    return 0;
106}
107
108/*
109 * XXX: the following functions are local
110 */
111
112static uint8_t nearest_ansi(uint16_t argb16, uint8_t def)
113{
114    unsigned int i, best, dist;
115
116    if(argb16 < CUCUL_COLOR_DEFAULT)
117        return argb16;
118
119    if(argb16 == CUCUL_COLOR_DEFAULT || argb16 == CUCUL_COLOR_TRANSPARENT)
120        return def;
121
122    if(argb16 < 0x5fff) /* too transparent, return default colour */
123        return def;
124
125    best = def;
126    dist = 0xffff;
127    for(i = 0; i < 16; i++)
128    {
129        unsigned int d = 0;
130        int a, b;
131
132        a = (ansitab[i] >> 8) & 0xf;
133        b = (argb16 >> 8) & 0xf;
134        d += (a - b) * (a - b);
135
136        a = (ansitab[i] >> 4) & 0xf;
137        b = (argb16 >> 4) & 0xf;
138        d += (a - b) * (a - b);
139
140        a = ansitab[i] & 0xf;
141        b = argb16 & 0xf;
142        d += (a - b) * (a - b);
143
144        if(d < dist)
145        {
146            dist = d;
147            best = i;
148        }
149    }
150
151    return best;
152}
153
154uint8_t _cucul_argb32_to_ansi8(uint32_t ch)
155{
156    uint16_t fg = ch & 0xffff;
157    uint16_t bg = ch >> 16;
158
159    return nearest_ansi(fg, CUCUL_COLOR_LIGHTGRAY)
160            | (nearest_ansi(bg, CUCUL_COLOR_BLACK) << 4);
161}
162
163uint8_t _cucul_argb32_to_ansi4fg(uint32_t ch)
164{
165    return nearest_ansi(ch & 0xffff, CUCUL_COLOR_LIGHTGRAY);
166}
167
168uint8_t _cucul_argb32_to_ansi4bg(uint32_t ch)
169{
170    return nearest_ansi(ch >> 16, CUCUL_COLOR_BLACK);
171}
172
173uint16_t _cucul_argb32_to_rgb12fg(uint32_t ch)
174{
175    uint16_t fg = ch & 0xffff;
176
177    if(fg < CUCUL_COLOR_DEFAULT)
178        return ansitab[fg] & 0x0fff;
179
180    if(fg == CUCUL_COLOR_DEFAULT)
181        return ansitab[CUCUL_COLOR_LIGHTGRAY] & 0x0fff;
182
183    if(fg == CUCUL_COLOR_TRANSPARENT)
184        return 0x0fff;
185
186    return fg & 0x0fff;
187}
188
189uint16_t _cucul_argb32_to_rgb12bg(uint32_t ch)
190{
191    uint16_t bg = ch >> 16;
192
193    if(bg < CUCUL_COLOR_DEFAULT)
194        return ansitab[bg] & 0x0fff;
195
196    if(bg == CUCUL_COLOR_DEFAULT)
197        return ansitab[CUCUL_COLOR_BLACK] & 0x0fff;
198
199    if(bg == CUCUL_COLOR_TRANSPARENT)
200        return 0x0fff;
201
202    return bg & 0x0fff;
203}
204
205#define RGB12TO24(i) \
206   (((uint32_t)((i & 0xf00) >> 8) * 0x110000) \
207  | ((uint32_t)((i & 0x0f0) >> 4) * 0x001100) \
208  | ((uint32_t)(i & 0x00f) * 0x000011))
209
210uint32_t _cucul_argb32_to_rgb24fg(uint32_t ch)
211{
212    return RGB12TO24(_cucul_argb32_to_rgb12fg(ch));
213}
214
215uint32_t _cucul_argb32_to_rgb24bg(uint32_t ch)
216{
217    return RGB12TO24(_cucul_argb32_to_rgb12bg(ch));
218}
219
220void _cucul_argb32_to_argb4(uint32_t ch, uint8_t argb[8])
221{
222    uint16_t fg = ch & 0xffff;
223    uint16_t bg = ch >> 16;
224
225    if(fg < CUCUL_COLOR_DEFAULT)
226        fg = ansitab[fg];
227    else if(fg == CUCUL_COLOR_DEFAULT)
228        fg = ansitab[CUCUL_COLOR_LIGHTGRAY];
229    else if(fg == CUCUL_COLOR_TRANSPARENT)
230        fg = 0x0fff;
231
232    if(bg < CUCUL_COLOR_DEFAULT)
233        bg = ansitab[bg];
234    else if(bg == CUCUL_COLOR_DEFAULT)
235        bg = ansitab[CUCUL_COLOR_BLACK];
236    else if(bg == CUCUL_COLOR_TRANSPARENT)
237        bg = 0x0fff;
238
239    argb[0] = bg >> 12;
240    argb[1] = (bg >> 8) & 0xf;
241    argb[2] = (bg >> 4) & 0xf;
242    argb[3] = bg & 0xf;
243
244    argb[4] = fg >> 12;
245    argb[5] = (fg >> 8) & 0xf;
246    argb[6] = (fg >> 4) & 0xf;
247    argb[7] = fg & 0xf;
248}
249
Note: See TracBrowser for help on using the repository browser.