diff options
Diffstat (limited to 'contrib/groff/src/libs/libgroff/color.cc')
-rw-r--r-- | contrib/groff/src/libs/libgroff/color.cc | 363 |
1 files changed, 363 insertions, 0 deletions
diff --git a/contrib/groff/src/libs/libgroff/color.cc b/contrib/groff/src/libs/libgroff/color.cc new file mode 100644 index 0000000..68e604c --- /dev/null +++ b/contrib/groff/src/libs/libgroff/color.cc @@ -0,0 +1,363 @@ +// -*- C++ -*- + +/* <groff_src_dir>/src/libs/libgroff/color.cc + +Last update: 10 Apr 2002 + +Copyright (C) 2001, 2002 Free Software Foundation, Inc. + Written by Gaius Mulley <gaius@glam.ac.uk> + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License along +with groff; see the file COPYING. If not, write to the Free Software +Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "color.h" +#include "cset.h" +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif + +#include <assert.h> +#include <stdio.h> +#include <fcntl.h> +#include <stdlib.h> +#include "errarg.h" +#include "error.h" + +static inline unsigned int +min(const unsigned int a, const unsigned int b) +{ + if (a < b) + return a; + else + return b; +} + +color::color(const color * const c) +{ + scheme = c->scheme; + components[0] = c->components[0]; + components[1] = c->components[1]; + components[2] = c->components[2]; + components[3] = c->components[3]; +} + +int color::operator==(const color & c) const +{ + if (scheme != c.scheme) + return 0; + switch (scheme) { + case DEFAULT: + break; + case RGB: + if (Red != c.Red || Green != c.Green || Blue != c.Blue) + return 0; + break; + case CMYK: + if (Cyan != c.Cyan || Magenta != c.Magenta + || Yellow != c.Yellow || Black != c.Black) + return 0; + break; + case GRAY: + if (Gray != c.Gray) + return 0; + break; + case CMY: + if (Cyan != c.Cyan || Magenta != c.Magenta || Yellow != c.Yellow) + return 0; + break; + } + return 1; +} + +int color::operator!=(const color & c) const +{ + return !(*this == c); +} + +color_scheme color::get_components(unsigned int *c) const +{ +#if 0 + if (sizeof (c) < sizeof (unsigned int) * 4) + fatal("argument is not big enough to store 4 color components"); +#endif + c[0] = components[0]; + c[1] = components[1]; + c[2] = components[2]; + c[3] = components[3]; + return scheme; +} + +void color::set_default() +{ + scheme = DEFAULT; +} + +// (0, 0, 0) is black + +void color::set_rgb(const unsigned int r, const unsigned int g, + const unsigned int b) +{ + scheme = RGB; + Red = min(MAX_COLOR_VAL, r); + Green = min(MAX_COLOR_VAL, g); + Blue = min(MAX_COLOR_VAL, b); +} + +// (0, 0, 0) is white + +void color::set_cmy(const unsigned int c, const unsigned int m, + const unsigned int y) +{ + scheme = CMY; + Cyan = min(MAX_COLOR_VAL, c); + Magenta = min(MAX_COLOR_VAL, m); + Yellow = min(MAX_COLOR_VAL, y); +} + +// (0, 0, 0, 0) is white + +void color::set_cmyk(const unsigned int c, const unsigned int m, + const unsigned int y, const unsigned int k) +{ + scheme = CMYK; + Cyan = min(MAX_COLOR_VAL, c); + Magenta = min(MAX_COLOR_VAL, m); + Yellow = min(MAX_COLOR_VAL, y); + Black = min(MAX_COLOR_VAL, k); +} + +// (0) is black + +void color::set_gray(const unsigned int g) +{ + scheme = GRAY; + Gray = min(MAX_COLOR_VAL, g); +} + +/* + * atoh - computes the decimal value of a hexadecimal number string. + * `length' characters of `s' are read. Returns 1 if successful. + */ + +static int atoh(unsigned int *result, + const char * const s, const size_t length) +{ + size_t i = 0; + unsigned int val = 0; + while ((i < length) && csxdigit(s[i])) { + if (csdigit(s[i])) + val = val*0x10 + (s[i]-'0'); + else if (csupper(s[i])) + val = val*0x10 + (s[i]-'A') + 10; + else + val = val*0x10 + (s[i]-'a') + 10; + i++; + } + if (i != length) + return 0; + *result = val; + return 1; +} + +/* + * read_encoding - set color from a hexadecimal color string. + * + * Use color scheme `cs' to parse `n' color components from string `s'. + * Returns 1 if successful. + */ + +int color::read_encoding(const color_scheme cs, const char * const s, + const size_t n) +{ + size_t hex_length = 2; + scheme = cs; + char *p = (char *) s; + p++; + if (*p == '#') { + hex_length = 4; + p++; + } + for (size_t i = 0; i < n; i++) { + if (!atoh(&(components[i]), p, hex_length)) + return 0; + if (hex_length == 2) + components[i] *= 0x101; // scale up -- 0xff should become 0xffff + p += hex_length; + } + return 1; +} + +int color::read_rgb(const char * const s) +{ + return read_encoding(RGB, s, 3); +} + +int color::read_cmy(const char * const s) +{ + return read_encoding(CMY, s, 3); +} + +int color::read_cmyk(const char * const s) +{ + return read_encoding(CMYK, s, 4); +} + +int color::read_gray(const char * const s) +{ + return read_encoding(GRAY, s, 1); +} + +void +color::get_rgb(unsigned int *r, unsigned int *g, unsigned int *b) const +{ + switch (scheme) { + case RGB: + *r = Red; + *g = Green; + *b = Blue; + break; + case CMY: + *r = MAX_COLOR_VAL - Cyan; + *g = MAX_COLOR_VAL - Magenta; + *b = MAX_COLOR_VAL - Yellow; + break; + case CMYK: + *r = MAX_COLOR_VAL + - min(MAX_COLOR_VAL, + Cyan * (MAX_COLOR_VAL - Black) / MAX_COLOR_VAL + Black); + *g = MAX_COLOR_VAL + - min(MAX_COLOR_VAL, + Magenta * (MAX_COLOR_VAL - Black) / MAX_COLOR_VAL + Black); + *b = MAX_COLOR_VAL + - min(MAX_COLOR_VAL, + Yellow * (MAX_COLOR_VAL - Black) / MAX_COLOR_VAL + Black); + break; + case GRAY: + *r = *g = *b = Gray; + break; + default: + assert(0); + break; + } +} + +void +color::get_cmy(unsigned int *c, unsigned int *m, unsigned int *y) const +{ + switch (scheme) { + case RGB: + *c = MAX_COLOR_VAL - Red; + *m = MAX_COLOR_VAL - Green; + *y = MAX_COLOR_VAL - Blue; + break; + case CMY: + *c = Cyan; + *m = Magenta; + *y = Yellow; + break; + case CMYK: + *c = min(MAX_COLOR_VAL, + Cyan * (MAX_COLOR_VAL - Black) / MAX_COLOR_VAL + Black); + *m = min(MAX_COLOR_VAL, + Magenta * (MAX_COLOR_VAL - Black) / MAX_COLOR_VAL + Black); + *y = min(MAX_COLOR_VAL, + Yellow * (MAX_COLOR_VAL - Black) / MAX_COLOR_VAL + Black); + break; + case GRAY: + *c = *m = *y = MAX_COLOR_VAL - Gray; + break; + default: + assert(0); + break; + } +} + +void color::get_cmyk(unsigned int *c, unsigned int *m, + unsigned int *y, unsigned int *k) const +{ + switch (scheme) { + case RGB: + *k = min(MAX_COLOR_VAL - Red, + min(MAX_COLOR_VAL - Green, MAX_COLOR_VAL - Blue)); + if (MAX_COLOR_VAL == *k) { + *c = MAX_COLOR_VAL; + *m = MAX_COLOR_VAL; + *y = MAX_COLOR_VAL; + } + else { + *c = (MAX_COLOR_VAL * (MAX_COLOR_VAL - Red - *k)) + / (MAX_COLOR_VAL - *k); + *m = (MAX_COLOR_VAL * (MAX_COLOR_VAL - Green - *k)) + / (MAX_COLOR_VAL - *k); + *y = (MAX_COLOR_VAL * (MAX_COLOR_VAL - Blue - *k)) + / (MAX_COLOR_VAL - *k); + } + break; + case CMY: + *k = min(Cyan, min(Magenta, Yellow)); + if (MAX_COLOR_VAL == *k) { + *c = MAX_COLOR_VAL; + *m = MAX_COLOR_VAL; + *y = MAX_COLOR_VAL; + } + else { + *c = (MAX_COLOR_VAL * (Cyan - *k)) / (MAX_COLOR_VAL - *k); + *m = (MAX_COLOR_VAL * (Magenta - *k)) / (MAX_COLOR_VAL - *k); + *y = (MAX_COLOR_VAL * (Yellow - *k)) / (MAX_COLOR_VAL - *k); + } + break; + case CMYK: + *c = Cyan; + *m = Magenta; + *y = Yellow; + *k = Black; + break; + case GRAY: + *c = *m = *y = 0; + *k = MAX_COLOR_VAL - Gray; + break; + default: + assert(0); + break; + } +} + +// we use `0.222r + 0.707g + 0.071b' (this is the ITU standard) +// as an approximation for gray + +void color::get_gray(unsigned int *g) const +{ + switch (scheme) { + case RGB: + *g = (222*Red + 707*Green + 71*Blue) / 1000; + break; + case CMY: + *g = MAX_COLOR_VAL - (222*Cyan + 707*Magenta + 71*Yellow) / 1000; + break; + case CMYK: + *g = (MAX_COLOR_VAL - (222*Cyan + 707*Magenta + 71*Yellow) / 1000) + * (MAX_COLOR_VAL - Black); + break; + case GRAY: + *g = Gray; + break; + default: + assert(0); + break; + } +} + +color default_color; |