3efc09795c0c5b76818a1530ce182a685c8c29ff
[platform/upstream/groff.git] / src / libs / libgroff / color.cpp
1 // -*- C++ -*-
2
3 /* <groff_src_dir>/src/libs/libgroff/color.cpp
4
5 Copyright (C) 2001-2014  Free Software Foundation, Inc.
6     Written by Gaius Mulley <gaius@glam.ac.uk>
7
8 This file is part of groff.
9
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.
14
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
18 for more details.
19
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/>. */
22
23 #include "lib.h"
24 #include "color.h"
25 #include "cset.h"
26 #ifdef HAVE_UNISTD_H
27 #include <unistd.h>
28 #endif
29
30 #include <assert.h>
31 #include <stdio.h>
32 #include <fcntl.h>
33 #include <stdlib.h>
34 #include "errarg.h"
35 #include "error.h"
36
37 static inline unsigned int
38 min(const unsigned int a, const unsigned int b)
39 {
40   if (a < b)
41     return a;
42   else
43     return b;
44 }
45
46 color *color::free_list = 0;
47
48 void *color::operator new(size_t n)
49 {
50   assert(n == sizeof(color));
51   if (!free_list) {
52     const int BLOCK = 128;
53     free_list = (color *)new char[sizeof(color)*BLOCK];
54     for (int i = 0; i < BLOCK - 1; i++)
55       free_list[i].next = free_list + i + 1;
56     free_list[BLOCK-1].next = 0;
57   }
58   color *p = free_list;
59   free_list = (color *)(free_list->next);
60   p->next = 0;
61   return p;
62 }
63
64 void color::operator delete(void *p)
65 {
66   if (p) {
67     ((color *)p)->next = free_list;
68     free_list = (color *)p;
69   }
70 }
71
72 color::color(const color * const c)
73 {
74   nm = c->nm;
75   scheme = c->scheme;
76   components[0] = c->components[0];
77   components[1] = c->components[1];
78   components[2] = c->components[2];
79   components[3] = c->components[3];
80 }
81
82 color::~color()
83 {
84 }
85
86 int color::operator==(const color & c) const
87 {
88   if (scheme != c.scheme)
89     return 0;
90   switch (scheme) {
91   case DEFAULT:
92     break;
93   case RGB:
94     if (Red != c.Red || Green != c.Green || Blue != c.Blue)
95       return 0;
96     break;
97   case CMYK:
98     if (Cyan != c.Cyan || Magenta != c.Magenta
99         || Yellow != c.Yellow || Black != c.Black)
100       return 0;
101     break;
102   case GRAY:
103     if (Gray != c.Gray)
104       return 0;
105     break;
106   case CMY:
107     if (Cyan != c.Cyan || Magenta != c.Magenta || Yellow != c.Yellow)
108       return 0;
109     break;
110   }
111   return 1;
112 }
113
114 int color::operator!=(const color & c) const
115 {
116   return !(*this == c);
117 }
118
119 color_scheme color::get_components(unsigned int *c) const
120 {
121 #if 0
122   if (sizeof (c) < sizeof (unsigned int) * 4)
123     fatal("argument is not big enough to store 4 color components");
124 #endif
125   c[0] = components[0];
126   c[1] = components[1];
127   c[2] = components[2];
128   c[3] = components[3];
129   return scheme;
130 }
131
132 void color::set_default()
133 {
134   scheme = DEFAULT;
135 }
136
137 // (0, 0, 0) is black
138
139 void color::set_rgb(const unsigned int r, const unsigned int g,
140                     const unsigned int b)
141 {
142   scheme = RGB;
143   Red = min(MAX_COLOR_VAL, r);
144   Green = min(MAX_COLOR_VAL, g);
145   Blue = min(MAX_COLOR_VAL, b);
146 }
147
148 // (0, 0, 0) is white
149
150 void color::set_cmy(const unsigned int c, const unsigned int m,
151                     const unsigned int y)
152 {
153   scheme = CMY;
154   Cyan = min(MAX_COLOR_VAL, c);
155   Magenta = min(MAX_COLOR_VAL, m);
156   Yellow = min(MAX_COLOR_VAL, y);
157 }
158
159 // (0, 0, 0, 0) is white
160
161 void color::set_cmyk(const unsigned int c, const unsigned int m,
162                      const unsigned int y, const unsigned int k)
163 {
164   scheme = CMYK;
165   Cyan = min(MAX_COLOR_VAL, c);
166   Magenta = min(MAX_COLOR_VAL, m);
167   Yellow = min(MAX_COLOR_VAL, y);
168   Black = min(MAX_COLOR_VAL, k);
169 }
170
171 // (0) is black
172
173 void color::set_gray(const unsigned int g)
174 {
175   scheme = GRAY;
176   Gray = min(MAX_COLOR_VAL, g);
177 }
178
179 /*
180  *  atoh - computes the decimal value of a hexadecimal number string.
181  *         `length' characters of `s' are read.  Returns 1 if successful.
182  */
183
184 static int atoh(unsigned int *result,
185                 const char * const s, const size_t length)
186 {
187   size_t i = 0;
188   unsigned int val = 0;
189   while ((i < length) && csxdigit(s[i])) {
190     if (csdigit(s[i]))
191       val = val*0x10 + (s[i]-'0');
192     else if (csupper(s[i]))
193       val = val*0x10 + (s[i]-'A') + 10;
194     else
195       val = val*0x10 + (s[i]-'a') + 10;
196     i++;
197   }
198   if (i != length)
199     return 0;
200   *result = val;
201   return 1;
202 }
203
204 /*
205  *  read_encoding - set color from a hexadecimal color string.
206  *
207  *  Use color scheme `cs' to parse `n' color components from string `s'.
208  *  Returns 1 if successful.
209  */
210
211 int color::read_encoding(const color_scheme cs, const char * const s,
212                          const size_t n)
213 {
214   size_t hex_length = 2;
215   scheme = cs;
216   char *p = (char *) s;
217   p++;
218   if (*p == '#') {
219     hex_length = 4;
220     p++;
221   }
222   for (size_t i = 0; i < n; i++) {
223     if (!atoh(&(components[i]), p, hex_length))
224       return 0;
225     if (hex_length == 2)
226       components[i] *= 0x101;   // scale up -- 0xff should become 0xffff
227     p += hex_length;
228   }
229   return 1;
230 }
231
232 int color::read_rgb(const char * const s)
233 {
234   return read_encoding(RGB, s, 3);
235 }
236
237 int color::read_cmy(const char * const s)
238 {
239   return read_encoding(CMY, s, 3);
240 }
241
242 int color::read_cmyk(const char * const s)
243 {
244   return read_encoding(CMYK, s, 4);
245 }
246
247 int color::read_gray(const char * const s)
248 {
249   return read_encoding(GRAY, s, 1);
250 }
251
252 void
253 color::get_rgb(unsigned int *r, unsigned int *g, unsigned int *b) const
254 {
255   switch (scheme) {
256   case RGB:
257     *r = Red;
258     *g = Green;
259     *b = Blue;
260     break;
261   case CMY:
262     *r = MAX_COLOR_VAL - Cyan;
263     *g = MAX_COLOR_VAL - Magenta;
264     *b = MAX_COLOR_VAL - Yellow;
265     break;
266   case CMYK:
267     *r = MAX_COLOR_VAL
268          - min(MAX_COLOR_VAL,
269                Cyan * (MAX_COLOR_VAL - Black) / MAX_COLOR_VAL + Black);
270     *g = MAX_COLOR_VAL
271          - min(MAX_COLOR_VAL,
272                Magenta * (MAX_COLOR_VAL - Black) / MAX_COLOR_VAL + Black);
273     *b = MAX_COLOR_VAL
274          - min(MAX_COLOR_VAL,
275                Yellow * (MAX_COLOR_VAL - Black) / MAX_COLOR_VAL + Black);
276     break;
277   case GRAY:
278     *r = *g = *b = Gray;
279     break;
280   default:
281     assert(0);
282     break;
283   }
284 }
285
286 void
287 color::get_cmy(unsigned int *c, unsigned int *m, unsigned int *y) const
288 {
289   switch (scheme) {
290   case RGB:
291     *c = MAX_COLOR_VAL - Red;
292     *m = MAX_COLOR_VAL - Green;
293     *y = MAX_COLOR_VAL - Blue;
294     break;
295   case CMY:
296     *c = Cyan;
297     *m = Magenta;
298     *y = Yellow;
299     break;
300   case CMYK:
301     *c = min(MAX_COLOR_VAL,
302              Cyan * (MAX_COLOR_VAL - Black) / MAX_COLOR_VAL + Black);
303     *m = min(MAX_COLOR_VAL,
304              Magenta * (MAX_COLOR_VAL - Black) / MAX_COLOR_VAL + Black);
305     *y = min(MAX_COLOR_VAL,
306              Yellow * (MAX_COLOR_VAL - Black) / MAX_COLOR_VAL + Black);
307     break;
308   case GRAY:
309     *c = *m = *y = MAX_COLOR_VAL - Gray;
310     break;
311   default:
312     assert(0);
313     break;
314   }
315 }
316
317 void color::get_cmyk(unsigned int *c, unsigned int *m,
318                      unsigned int *y, unsigned int *k) const
319 {
320   switch (scheme) {
321   case RGB:
322     *k = min(MAX_COLOR_VAL - Red,
323              min(MAX_COLOR_VAL - Green, MAX_COLOR_VAL - Blue));
324     if (MAX_COLOR_VAL == *k) {
325       *c = MAX_COLOR_VAL;
326       *m = MAX_COLOR_VAL;
327       *y = MAX_COLOR_VAL;
328     }
329     else {
330       *c = (MAX_COLOR_VAL * (MAX_COLOR_VAL - Red - *k))
331            / (MAX_COLOR_VAL - *k);
332       *m = (MAX_COLOR_VAL * (MAX_COLOR_VAL - Green - *k))
333            / (MAX_COLOR_VAL - *k);
334       *y = (MAX_COLOR_VAL * (MAX_COLOR_VAL - Blue - *k))
335            / (MAX_COLOR_VAL - *k);
336     }
337     break;
338   case CMY:
339     *k = min(Cyan, min(Magenta, Yellow));
340     if (MAX_COLOR_VAL == *k) {
341       *c = MAX_COLOR_VAL;
342       *m = MAX_COLOR_VAL;
343       *y = MAX_COLOR_VAL;
344     }
345     else {
346       *c = (MAX_COLOR_VAL * (Cyan - *k)) / (MAX_COLOR_VAL - *k);
347       *m = (MAX_COLOR_VAL * (Magenta - *k)) / (MAX_COLOR_VAL - *k);
348       *y = (MAX_COLOR_VAL * (Yellow - *k)) / (MAX_COLOR_VAL - *k);
349     }
350     break;
351   case CMYK:
352     *c = Cyan;
353     *m = Magenta;
354     *y = Yellow;
355     *k = Black;
356     break;
357   case GRAY:
358     *c = *m = *y = 0;
359     *k = MAX_COLOR_VAL - Gray;
360     break;
361   default:
362     assert(0);
363     break;
364   }
365 }
366
367 // we use `0.222r + 0.707g + 0.071b' (this is the ITU standard)
368 // as an approximation for gray
369
370 void color::get_gray(unsigned int *g) const
371 {
372   switch (scheme) {
373   case RGB:
374     *g = (222*Red + 707*Green + 71*Blue) / 1000;
375     break;
376   case CMY:
377     *g = MAX_COLOR_VAL - (222*Cyan + 707*Magenta + 71*Yellow) / 1000;
378     break;
379   case CMYK:
380     *g = (MAX_COLOR_VAL - (222*Cyan + 707*Magenta + 71*Yellow) / 1000)
381          * (MAX_COLOR_VAL - Black);
382     break;
383   case GRAY:
384     *g = Gray;
385     break;
386   default:
387     assert(0);
388     break;
389   }
390 }
391
392 char *color::print_color()
393 {
394   char *s = new char[30];
395   switch (scheme) {
396   case DEFAULT:
397     sprintf(s, "default");
398     break;
399   case RGB:
400     sprintf(s, "rgb %.2ff %.2ff %.2ff",
401             double(Red) / MAX_COLOR_VAL,
402             double(Green) / MAX_COLOR_VAL,
403             double(Blue) / MAX_COLOR_VAL);
404     break;
405   case CMY:
406     sprintf(s, "cmy %.2ff %.2ff %.2ff",
407             double(Cyan) / MAX_COLOR_VAL,
408             double(Magenta) / MAX_COLOR_VAL,
409             double(Yellow) / MAX_COLOR_VAL);
410     break;
411   case CMYK:
412     sprintf(s, "cmyk %.2ff %.2ff %.2ff %.2ff",
413             double(Cyan) / MAX_COLOR_VAL,
414             double(Magenta) / MAX_COLOR_VAL,
415             double(Yellow) / MAX_COLOR_VAL,
416             double(Black) / MAX_COLOR_VAL);
417     break;
418   case GRAY:
419     sprintf(s, "gray %.2ff",
420             double(Gray) / MAX_COLOR_VAL);
421     break;
422   }
423   return s;
424 }
425
426 color default_color;