3 /* <groff_src_dir>/src/libs/libgroff/color.cc
5 Last update: 10 Apr 2002
7 Copyright (C) 2001, 2002 Free Software Foundation, Inc.
8 Written by Gaius Mulley <gaius@glam.ac.uk>
10 This file is part of groff.
12 groff is free software; you can redistribute it and/or modify it under
13 the terms of the GNU General Public License as published by the Free
14 Software Foundation; either version 2, or (at your option) any later
17 groff is distributed in the hope that it will be useful, but WITHOUT ANY
18 WARRANTY; without even the implied warranty of MERCHANTABILITY or
19 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
22 You should have received a copy of the GNU General Public License along
23 with groff; see the file COPYING. If not, write to the Free Software
24 Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
39 static inline unsigned int
40 min(const unsigned int a, const unsigned int b)
48 color::color(const color * const c)
51 components[0] = c->components[0];
52 components[1] = c->components[1];
53 components[2] = c->components[2];
54 components[3] = c->components[3];
57 int color::operator==(const color & c) const
59 if (scheme != c.scheme)
65 if (Red != c.Red || Green != c.Green || Blue != c.Blue)
69 if (Cyan != c.Cyan || Magenta != c.Magenta
70 || Yellow != c.Yellow || Black != c.Black)
78 if (Cyan != c.Cyan || Magenta != c.Magenta || Yellow != c.Yellow)
85 int color::operator!=(const color & c) const
90 color_scheme color::get_components(unsigned int *c) const
93 if (sizeof (c) < sizeof (unsigned int) * 4)
94 fatal("argument is not big enough to store 4 color components");
103 void color::set_default()
108 // (0, 0, 0) is black
110 void color::set_rgb(const unsigned int r, const unsigned int g,
111 const unsigned int b)
114 Red = min(MAX_COLOR_VAL, r);
115 Green = min(MAX_COLOR_VAL, g);
116 Blue = min(MAX_COLOR_VAL, b);
119 // (0, 0, 0) is white
121 void color::set_cmy(const unsigned int c, const unsigned int m,
122 const unsigned int y)
125 Cyan = min(MAX_COLOR_VAL, c);
126 Magenta = min(MAX_COLOR_VAL, m);
127 Yellow = min(MAX_COLOR_VAL, y);
130 // (0, 0, 0, 0) is white
132 void color::set_cmyk(const unsigned int c, const unsigned int m,
133 const unsigned int y, const unsigned int k)
136 Cyan = min(MAX_COLOR_VAL, c);
137 Magenta = min(MAX_COLOR_VAL, m);
138 Yellow = min(MAX_COLOR_VAL, y);
139 Black = min(MAX_COLOR_VAL, k);
144 void color::set_gray(const unsigned int g)
147 Gray = min(MAX_COLOR_VAL, g);
151 * atoh - computes the decimal value of a hexadecimal number string.
152 * `length' characters of `s' are read. Returns 1 if successful.
155 static int atoh(unsigned int *result,
156 const char * const s, const size_t length)
159 unsigned int val = 0;
160 while ((i < length) && csxdigit(s[i])) {
162 val = val*0x10 + (s[i]-'0');
163 else if (csupper(s[i]))
164 val = val*0x10 + (s[i]-'A') + 10;
166 val = val*0x10 + (s[i]-'a') + 10;
176 * read_encoding - set color from a hexadecimal color string.
178 * Use color scheme `cs' to parse `n' color components from string `s'.
179 * Returns 1 if successful.
182 int color::read_encoding(const color_scheme cs, const char * const s,
185 size_t hex_length = 2;
187 char *p = (char *) s;
193 for (size_t i = 0; i < n; i++) {
194 if (!atoh(&(components[i]), p, hex_length))
197 components[i] *= 0x101; // scale up -- 0xff should become 0xffff
203 int color::read_rgb(const char * const s)
205 return read_encoding(RGB, s, 3);
208 int color::read_cmy(const char * const s)
210 return read_encoding(CMY, s, 3);
213 int color::read_cmyk(const char * const s)
215 return read_encoding(CMYK, s, 4);
218 int color::read_gray(const char * const s)
220 return read_encoding(GRAY, s, 1);
224 color::get_rgb(unsigned int *r, unsigned int *g, unsigned int *b) const
233 *r = MAX_COLOR_VAL - Cyan;
234 *g = MAX_COLOR_VAL - Magenta;
235 *b = MAX_COLOR_VAL - Yellow;
240 Cyan * (MAX_COLOR_VAL - Black) / MAX_COLOR_VAL + Black);
243 Magenta * (MAX_COLOR_VAL - Black) / MAX_COLOR_VAL + Black);
246 Yellow * (MAX_COLOR_VAL - Black) / MAX_COLOR_VAL + Black);
258 color::get_cmy(unsigned int *c, unsigned int *m, unsigned int *y) const
262 *c = MAX_COLOR_VAL - Red;
263 *m = MAX_COLOR_VAL - Green;
264 *y = MAX_COLOR_VAL - Blue;
272 *c = min(MAX_COLOR_VAL,
273 Cyan * (MAX_COLOR_VAL - Black) / MAX_COLOR_VAL + Black);
274 *m = min(MAX_COLOR_VAL,
275 Magenta * (MAX_COLOR_VAL - Black) / MAX_COLOR_VAL + Black);
276 *y = min(MAX_COLOR_VAL,
277 Yellow * (MAX_COLOR_VAL - Black) / MAX_COLOR_VAL + Black);
280 *c = *m = *y = MAX_COLOR_VAL - Gray;
288 void color::get_cmyk(unsigned int *c, unsigned int *m,
289 unsigned int *y, unsigned int *k) const
293 *k = min(MAX_COLOR_VAL - Red,
294 min(MAX_COLOR_VAL - Green, MAX_COLOR_VAL - Blue));
295 if (MAX_COLOR_VAL == *k) {
301 *c = (MAX_COLOR_VAL * (MAX_COLOR_VAL - Red - *k))
302 / (MAX_COLOR_VAL - *k);
303 *m = (MAX_COLOR_VAL * (MAX_COLOR_VAL - Green - *k))
304 / (MAX_COLOR_VAL - *k);
305 *y = (MAX_COLOR_VAL * (MAX_COLOR_VAL - Blue - *k))
306 / (MAX_COLOR_VAL - *k);
310 *k = min(Cyan, min(Magenta, Yellow));
311 if (MAX_COLOR_VAL == *k) {
317 *c = (MAX_COLOR_VAL * (Cyan - *k)) / (MAX_COLOR_VAL - *k);
318 *m = (MAX_COLOR_VAL * (Magenta - *k)) / (MAX_COLOR_VAL - *k);
319 *y = (MAX_COLOR_VAL * (Yellow - *k)) / (MAX_COLOR_VAL - *k);
330 *k = MAX_COLOR_VAL - Gray;
338 // we use `0.222r + 0.707g + 0.071b' (this is the ITU standard)
339 // as an approximation for gray
341 void color::get_gray(unsigned int *g) const
345 *g = (222*Red + 707*Green + 71*Blue) / 1000;
348 *g = MAX_COLOR_VAL - (222*Cyan + 707*Magenta + 71*Yellow) / 1000;
351 *g = (MAX_COLOR_VAL - (222*Cyan + 707*Magenta + 71*Yellow) / 1000)
352 * (MAX_COLOR_VAL - Black);