f_color.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299
  1. /* This file is part of the GNU plotutils package. Copyright (C) 1995,
  2. 1996, 1997, 1998, 1999, 2000, 2005, 2008, Free Software Foundation, Inc.
  3. The GNU plotutils package is free software. You may redistribute it
  4. and/or modify it under the terms of the GNU General Public License as
  5. published by the Free Software foundation; either version 2, or (at your
  6. option) any later version.
  7. The GNU plotutils package is distributed in the hope that it will be
  8. useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  10. General Public License for more details.
  11. You should have received a copy of the GNU General Public License along
  12. with the GNU plotutils package; see the file COPYING. If not, write to
  13. the Free Software Foundation, Inc., 51 Franklin St., Fifth Floor,
  14. Boston, MA 02110-1301, USA. */
  15. /* This file contains device-specific color database access routines. They
  16. are called by various FigPlotter methods, before drawing objects. They
  17. set the appropriate FigPlotter-specific fields in the drawing state. */
  18. #include "sys-defines.h"
  19. #include "extern.h"
  20. #define ONEBYTE 0xff
  21. /* by setting this undocumented variable, user may request quantization of
  22. colors (no user-defined colors, only native xfig ones). */
  23. #ifdef SUPPORT_FIG_COLOR_QUANTIZATION
  24. int _libplotfig_use_pseudocolor = 0;
  25. #endif
  26. /* FIG_COLOR returns the index of the Fig color corresponding to specified
  27. a 48-bit RGB value. This has (or may have) a side effect. If the Fig
  28. color is not standard, it will be added to the database of user-defined
  29. colors, and a Fig `color pseudo-object' will be output later.
  30. Note: according to Fig documentation, xfig should support as many as
  31. FIG_NUM_USER_COLORS (i.e., 512) user-defined colors. However, I have
  32. observed that on at least one platform, it pops up a warning message
  33. unless the number is 511 or less. That's why FIG_NUM_USER_COLORS - 1
  34. appears in the code below.
  35. We do not call this function whenever the user calls pencolor() or
  36. fillcolor(), since we don't want to fill up the database with colors
  37. that the user may not actually use. Instead, we call it just before we
  38. write a colored object to the output buffer (lazy evaluation), by
  39. evaluating the f_set_pen_color() and f_set_fill_color() functions below.
  40. If the external variable _libplotfig_use_pseudocolor is nonzero, we
  41. don't actually maintain a database of user-defined colors. Instead we
  42. just quantize to one of xfig's native 32 colors. (They provide a
  43. [rather strange] partition of the color cube; see f_color2.c.) */
  44. /* forward references */
  45. static int _fig_pseudocolor (int red, int green, int blue, const long int *fig_usercolors, int fig_num_usercolors);
  46. int
  47. _pl_f_fig_color(R___(Plotter *_plotter) int red, int green, int blue)
  48. {
  49. int fig_fgcolor_red, fig_fgcolor_green, fig_fgcolor_blue;
  50. long int fig_fgcolor_rgb;
  51. int i;
  52. /* xfig supports only 24-bit color, so extract 8 bits for each of R,G,B */
  53. fig_fgcolor_red = (red >> 8) & ONEBYTE;
  54. fig_fgcolor_green = (green >> 8) & ONEBYTE;
  55. fig_fgcolor_blue = (blue >> 8) & ONEBYTE;
  56. #ifdef SUPPORT_FIG_COLOR_QUANTIZATION
  57. if (_libplotfig_use_pseudocolor)
  58. /* always quantize: approximate by closest standard color, and don't
  59. create user-defined colors at all */
  60. return _fig_pseudocolor (fig_fgcolor_red, fig_fgcolor_green,
  61. fig_fgcolor_blue,
  62. (const long int *)NULL, 0);
  63. #endif
  64. /* search list of standard colors */
  65. for (i = 0; i < FIG_NUM_STD_COLORS; i++)
  66. {
  67. if ((_pl_f_fig_stdcolors[i].red == fig_fgcolor_red)
  68. && (_pl_f_fig_stdcolors[i].green == fig_fgcolor_green)
  69. && (_pl_f_fig_stdcolors[i].blue == fig_fgcolor_blue))
  70. /* perfect match, return it */
  71. return i;
  72. }
  73. /* This is the 24-bit (i.e. 3-byte) integer used internally by xfig, and
  74. also by us when we stored user-defined colors. We assume long ints
  75. are wide enough to handle 3 bytes. */
  76. fig_fgcolor_rgb = (fig_fgcolor_red << 16) + (fig_fgcolor_green << 8)
  77. + (fig_fgcolor_blue);
  78. /* search list of user-defined colors */
  79. for (i = 0; i < _plotter->fig_num_usercolors; i++)
  80. {
  81. if (_plotter->fig_usercolors[i] == fig_fgcolor_rgb)
  82. /* perfect match, return it */
  83. return FIG_USER_COLOR_MIN + i;
  84. }
  85. /* color wasn't found in either list */
  86. if (_plotter->fig_num_usercolors == FIG_MAX_NUM_USER_COLORS - 1)
  87. /* can't add new color to user-defined list, must approximate */
  88. {
  89. if (_plotter->fig_colormap_warning_issued == false)
  90. {
  91. _plotter->warning (R___(_plotter)
  92. "supply of user-defined colors is exhausted");
  93. _plotter->fig_colormap_warning_issued = true;
  94. }
  95. return _fig_pseudocolor (fig_fgcolor_red, fig_fgcolor_green,
  96. fig_fgcolor_blue,
  97. _plotter->fig_usercolors,
  98. FIG_MAX_NUM_USER_COLORS - 1);
  99. }
  100. else
  101. /* create new user-defined color, will emit it to the .fig file */
  102. {
  103. _plotter->fig_usercolors[_plotter->fig_num_usercolors] = fig_fgcolor_rgb;
  104. _plotter->fig_num_usercolors++;
  105. return FIG_USER_COLOR_MIN + _plotter->fig_num_usercolors - 1;
  106. }
  107. }
  108. /* Find closest known point to a specified 24-bit color within the RGB
  109. color cube, using Euclidean distance as our metric. We search both
  110. Fig's standard colors and a specified number of user-defined colors,
  111. which are stored in an array, a pointer to which is passed. Return
  112. value is Fig color index. Standard Fig colors are located in
  113. 0..FIG_NUM_STD_COLORS-1, and user-defined colors beginning at
  114. FIG_USER_COLOR_MIN, which is equal to FIG_NUM_STD_COLORS. */
  115. static int
  116. _fig_pseudocolor (int red, int green, int blue, const long int *fig_usercolors, int fig_num_usercolors)
  117. {
  118. unsigned long int difference = INT_MAX;
  119. int i;
  120. int best = 0;
  121. for (i = 0; i < FIG_NUM_STD_COLORS; i++)
  122. {
  123. unsigned long int newdifference;
  124. if (_pl_f_fig_stdcolors[i].red == 0xff
  125. && _pl_f_fig_stdcolors[i].green == 0xff
  126. && _pl_f_fig_stdcolors[i].blue == 0xff)
  127. /* white is a possible quantization only for white itself (our
  128. convention) */
  129. {
  130. if (red == 0xff && green == 0xff && blue == 0xff)
  131. {
  132. difference = 0;
  133. best = i;
  134. }
  135. continue;
  136. }
  137. newdifference = (((_pl_f_fig_stdcolors[i].red - red)
  138. * (_pl_f_fig_stdcolors[i].red - red))
  139. + ((_pl_f_fig_stdcolors[i].green - green)
  140. * (_pl_f_fig_stdcolors[i].green - green))
  141. + ((_pl_f_fig_stdcolors[i].blue - blue)
  142. * (_pl_f_fig_stdcolors[i].blue - blue)));
  143. if (newdifference < difference)
  144. {
  145. difference = newdifference;
  146. best = i; /* save Fig color index */
  147. }
  148. }
  149. /* search through passed array of user-defined colors too */
  150. for (i = 0; i < fig_num_usercolors; i++)
  151. {
  152. unsigned long int newdifference;
  153. plColor usercolor;
  154. /* extract 3 RGB octets from 24-byte Fig-style color */
  155. usercolor.red = (fig_usercolors[i] >> 16) & ONEBYTE;
  156. usercolor.green = (fig_usercolors[i] >> 8) & ONEBYTE;
  157. usercolor.blue = (fig_usercolors[i] >> 0) & ONEBYTE;
  158. newdifference = ((usercolor.red - red) * (usercolor.red - red)
  159. + (usercolor.green - green) * (usercolor.green - green)
  160. + (usercolor.blue - blue) * (usercolor.blue - blue));
  161. if (newdifference < difference)
  162. {
  163. difference = newdifference;
  164. best = i + FIG_USER_COLOR_MIN; /* save Fig color index */
  165. }
  166. }
  167. return best;
  168. }
  169. /* we call this routine to evaluate _plotter->drawstate->fig_fgcolor
  170. lazily, i.e. only when needed (just before an object is written to the
  171. output buffer) */
  172. void
  173. _pl_f_set_pen_color(S___(Plotter *_plotter))
  174. {
  175. /* OOB switches to default color */
  176. if (((_plotter->drawstate->fgcolor).red > 0xffff)
  177. || ((_plotter->drawstate->fgcolor).green > 0xffff)
  178. || ((_plotter->drawstate->fgcolor).blue > 0xffff))
  179. _plotter->drawstate->fig_fgcolor = _default_drawstate.fig_fgcolor;
  180. else
  181. _plotter->drawstate->fig_fgcolor =
  182. _pl_f_fig_color (R___(_plotter)
  183. (_plotter->drawstate->fgcolor).red,
  184. (_plotter->drawstate->fgcolor).green,
  185. (_plotter->drawstate->fgcolor).blue);
  186. return;
  187. }
  188. /* we call this routine to evaluate _plotter->drawstate->fig_fillcolor and
  189. _plotter->drawstate->fig_fill_level lazily, i.e. only when needed (just
  190. before an object is written to the output buffer) */
  191. void
  192. _pl_f_set_fill_color(S___(Plotter *_plotter))
  193. {
  194. double fill_level;
  195. /* OOB switches to default color */
  196. if (_plotter->drawstate->fillcolor_base.red > 0xffff
  197. || _plotter->drawstate->fillcolor_base.green > 0xffff
  198. || _plotter->drawstate->fillcolor_base.blue > 0xffff)
  199. _plotter->drawstate->fig_fillcolor = _default_drawstate.fig_fillcolor;
  200. else
  201. _plotter->drawstate->fig_fillcolor =
  202. _pl_f_fig_color (R___(_plotter)
  203. _plotter->drawstate->fillcolor_base.red,
  204. _plotter->drawstate->fillcolor_base.green,
  205. _plotter->drawstate->fillcolor_base.blue);
  206. /* Now that we know drawstate->fig_fillcolor, we can compute the fig fill
  207. level that will match the user's requested fill level. Fig fill level
  208. is interpreted in a color dependent way, as follows. The value -1 is
  209. special; means no fill at all (objects will be transparent). For
  210. other values, this is the interpretation:
  211. Color = black or default:
  212. fill = 0 -> white
  213. fill = 1 -> very light grey
  214. .
  215. .
  216. fill = 19 -> very dark grey
  217. fill = 20 -> black
  218. Color = all colors other than black or default, including white
  219. fill = 0 -> black
  220. fill = 1 -> color, very faint intensity
  221. .
  222. .
  223. fill = 19 -> color, very bright intensity
  224. fill = 20 -> color, full intensity
  225. So 1->20 give increasingly intense "shades" of the color, with 20
  226. giving the color itself. Values 20->40 are increasingly desaturated
  227. "tints" of the color, ranging from the color itself (20) to white
  228. (40). A tint is defined as the color mixed with white. (Values
  229. 21->40 are not used when the color is black or default, or white
  230. itself.) */
  231. fill_level = ((double)_plotter->drawstate->fill_type - 1.)/0xFFFE;
  232. /* OOB sets fill level to a non-OOB default value */
  233. if (fill_level > 1.)
  234. fill_level = ((double)_default_drawstate.fill_type - 1.)/0xFFFE;
  235. /* level = 0 turns off filling (objects will be transparent) */
  236. else if (fill_level < 0.)
  237. fill_level = -1.0;
  238. if (fill_level == -1.0)
  239. _plotter->drawstate->fig_fill_level = -1;
  240. else
  241. {
  242. switch (_plotter->drawstate->fig_fillcolor)
  243. {
  244. case FIG_C_WHITE: /* can't desaturate white */
  245. _plotter->drawstate->fig_fill_level = 20;
  246. break;
  247. case FIG_C_BLACK:
  248. _plotter->drawstate->fig_fill_level = IROUND(20.0 - 20.0 * fill_level);
  249. break;
  250. default: /* interpret fill level as a saturation */
  251. _plotter->drawstate->fig_fill_level = IROUND(20.0 + 20.0 * fill_level);
  252. break;
  253. }
  254. }
  255. return;
  256. }