3 /* <groff_src_dir>/src/libs/libgroff/color.cpp
5 Copyright (C) 2001-2018 Free Software Foundation, Inc.
6 Written by Gaius Mulley <gaius@glam.ac.uk>
8 This file is part of groff.
10 groff is free software; you can redistribute it and/or modify it under
11 the terms of the GNU General Public License as published by the Free
12 Software Foundation, either version 3 of the License, or
13 (at your option) any later version.
15 groff is distributed in the hope that it will be useful, but WITHOUT ANY
16 WARRANTY; without even the implied warranty of MERCHANTABILITY or
17 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
20 You should have received a copy of the GNU General Public License
21 along with this program. If not, see <http://www.gnu.org/licenses/>. */
37 static inline unsigned int
38 min(const unsigned int a, const unsigned int b)
47 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];
61 int color::operator==(const color & c) const
63 if (scheme != c.scheme)
69 if (Red != c.Red || Green != c.Green || Blue != c.Blue)
73 if (Cyan != c.Cyan || Magenta != c.Magenta
74 || Yellow != c.Yellow || Black != c.Black)
82 if (Cyan != c.Cyan || Magenta != c.Magenta || Yellow != c.Yellow)
89 int color::operator!=(const color & c) const
94 color_scheme color::get_components(unsigned int *c) const
97 if (sizeof (c) < sizeof (unsigned int) * 4)
98 fatal("argument is not big enough to store 4 color components");
100 c[0] = components[0];
101 c[1] = components[1];
102 c[2] = components[2];
103 c[3] = components[3];
107 void color::set_default()
112 // (0, 0, 0) is black
114 void color::set_rgb(const unsigned int r, const unsigned int g,
115 const unsigned int b)
118 Red = min(MAX_COLOR_VAL, r);
119 Green = min(MAX_COLOR_VAL, g);
120 Blue = min(MAX_COLOR_VAL, b);
123 // (0, 0, 0) is white
125 void color::set_cmy(const unsigned int c, const unsigned int m,
126 const unsigned int y)
129 Cyan = min(MAX_COLOR_VAL, c);
130 Magenta = min(MAX_COLOR_VAL, m);
131 Yellow = min(MAX_COLOR_VAL, y);
134 // (0, 0, 0, 0) is white
136 void color::set_cmyk(const unsigned int c, const unsigned int m,
137 const unsigned int y, const unsigned int k)
140 Cyan = min(MAX_COLOR_VAL, c);
141 Magenta = min(MAX_COLOR_VAL, m);
142 Yellow = min(MAX_COLOR_VAL, y);
143 Black = min(MAX_COLOR_VAL, k);
148 void color::set_gray(const unsigned int g)
151 Gray = min(MAX_COLOR_VAL, g);
155 * atoh - computes the decimal value of a hexadecimal number string.
156 * 'length' characters of 's' are read. Returns 1 if successful.
159 static int atoh(unsigned int *result,
160 const char * const s, const size_t length)
163 unsigned int val = 0;
164 while ((i < length) && csxdigit(s[i])) {
166 val = val*0x10 + (s[i]-'0');
167 else if (csupper(s[i]))
168 val = val*0x10 + (s[i]-'A') + 10;
170 val = val*0x10 + (s[i]-'a') + 10;
180 * read_encoding - set color from a hexadecimal color string.
182 * Use color scheme 'cs' to parse 'n' color components from string 's'.
183 * Returns 1 if successful.
186 int color::read_encoding(const color_scheme cs, const char * const s,
189 size_t hex_length = 2;
191 char *p = (char *) s;
197 for (size_t i = 0; i < n; i++) {
198 if (!atoh(&(components[i]), p, hex_length))
201 components[i] *= 0x101; // scale up -- 0xff should become 0xffff
207 int color::read_rgb(const char * const s)
209 return read_encoding(RGB, s, 3);
212 int color::read_cmy(const char * const s)
214 return read_encoding(CMY, s, 3);
217 int color::read_cmyk(const char * const s)
219 return read_encoding(CMYK, s, 4);
222 int color::read_gray(const char * const s)
224 return read_encoding(GRAY, s, 1);
228 color::get_rgb(unsigned int *r, unsigned int *g, unsigned int *b) const
237 *r = MAX_COLOR_VAL - Cyan;
238 *g = MAX_COLOR_VAL - Magenta;
239 *b = MAX_COLOR_VAL - Yellow;
244 Cyan * (MAX_COLOR_VAL - Black) / MAX_COLOR_VAL + Black);
247 Magenta * (MAX_COLOR_VAL - Black) / MAX_COLOR_VAL + Black);
250 Yellow * (MAX_COLOR_VAL - Black) / MAX_COLOR_VAL + Black);
262 color::get_cmy(unsigned int *c, unsigned int *m, unsigned int *y) const
266 *c = MAX_COLOR_VAL - Red;
267 *m = MAX_COLOR_VAL - Green;
268 *y = MAX_COLOR_VAL - Blue;
276 *c = min(MAX_COLOR_VAL,
277 Cyan * (MAX_COLOR_VAL - Black) / MAX_COLOR_VAL + Black);
278 *m = min(MAX_COLOR_VAL,
279 Magenta * (MAX_COLOR_VAL - Black) / MAX_COLOR_VAL + Black);
280 *y = min(MAX_COLOR_VAL,
281 Yellow * (MAX_COLOR_VAL - Black) / MAX_COLOR_VAL + Black);
284 *c = *m = *y = MAX_COLOR_VAL - Gray;
292 void color::get_cmyk(unsigned int *c, unsigned int *m,
293 unsigned int *y, unsigned int *k) const
297 *k = min(MAX_COLOR_VAL - Red,
298 min(MAX_COLOR_VAL - Green, MAX_COLOR_VAL - Blue));
299 if (MAX_COLOR_VAL == *k) {
305 *c = (MAX_COLOR_VAL * (MAX_COLOR_VAL - Red - *k))
306 / (MAX_COLOR_VAL - *k);
307 *m = (MAX_COLOR_VAL * (MAX_COLOR_VAL - Green - *k))
308 / (MAX_COLOR_VAL - *k);
309 *y = (MAX_COLOR_VAL * (MAX_COLOR_VAL - Blue - *k))
310 / (MAX_COLOR_VAL - *k);
314 *k = min(Cyan, min(Magenta, Yellow));
315 if (MAX_COLOR_VAL == *k) {
321 *c = (MAX_COLOR_VAL * (Cyan - *k)) / (MAX_COLOR_VAL - *k);
322 *m = (MAX_COLOR_VAL * (Magenta - *k)) / (MAX_COLOR_VAL - *k);
323 *y = (MAX_COLOR_VAL * (Yellow - *k)) / (MAX_COLOR_VAL - *k);
334 *k = MAX_COLOR_VAL - Gray;
342 // we use '0.222r + 0.707g + 0.071b' (this is the ITU standard)
343 // as an approximation for gray
345 void color::get_gray(unsigned int *g) const
349 *g = (222*Red + 707*Green + 71*Blue) / 1000;
352 *g = MAX_COLOR_VAL - (222*Cyan + 707*Magenta + 71*Yellow) / 1000;
355 *g = (MAX_COLOR_VAL - (222*Cyan + 707*Magenta + 71*Yellow) / 1000)
356 * (MAX_COLOR_VAL - Black);
367 char *color::print_color()
369 char *s = new char[30];
372 sprintf(s, "default");
375 sprintf(s, "rgb %.2ff %.2ff %.2ff",
376 double(Red) / MAX_COLOR_VAL,
377 double(Green) / MAX_COLOR_VAL,
378 double(Blue) / MAX_COLOR_VAL);
381 sprintf(s, "cmy %.2ff %.2ff %.2ff",
382 double(Cyan) / MAX_COLOR_VAL,
383 double(Magenta) / MAX_COLOR_VAL,
384 double(Yellow) / MAX_COLOR_VAL);
387 sprintf(s, "cmyk %.2ff %.2ff %.2ff %.2ff",
388 double(Cyan) / MAX_COLOR_VAL,
389 double(Magenta) / MAX_COLOR_VAL,
390 double(Yellow) / MAX_COLOR_VAL,
391 double(Black) / MAX_COLOR_VAL);
394 sprintf(s, "gray %.2ff",
395 double(Gray) / MAX_COLOR_VAL);