p_color.c 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233
  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 computation routines. They are
  16. called by various PSPlotter methods, before drawing objects. They set
  17. the appropriate PSPlotter-specific fields in the drawing state. */
  18. #include "sys-defines.h"
  19. #include "extern.h"
  20. /* forward references */
  21. static int _idraw_pseudocolor (int red, int green, int blue);
  22. /* We call this routine to evaluate _plotter->drawstate->ps_fgcolor lazily,
  23. i.e. only when needed (just before an object is written to the output
  24. buffer). It finds the best match from among idraw's "foreground
  25. colors", i.e., pen colors. See p_color2.c for the list of colors. */
  26. void
  27. _pl_p_set_pen_color(S___(Plotter *_plotter))
  28. {
  29. _plotter->drawstate->ps_fgcolor_red =
  30. ((double)((_plotter->drawstate->fgcolor).red))/0xFFFF;
  31. _plotter->drawstate->ps_fgcolor_green =
  32. ((double)((_plotter->drawstate->fgcolor).green))/0xFFFF;
  33. _plotter->drawstate->ps_fgcolor_blue =
  34. ((double)((_plotter->drawstate->fgcolor).blue))/0xFFFF;
  35. /* quantize for idraw */
  36. _plotter->drawstate->ps_idraw_fgcolor =
  37. _idraw_pseudocolor ((_plotter->drawstate->fgcolor).red,
  38. (_plotter->drawstate->fgcolor).green,
  39. (_plotter->drawstate->fgcolor).blue);
  40. return;
  41. }
  42. /* We call this routine to evaluate _plotter->drawstate->ps_fillcolor
  43. lazily, i.e. only when needed (just before an object is written to the
  44. output buffer). It finds the best match from among the possible idraw
  45. colors. In idraw, the fill color is always an interpolation between a
  46. "foreground color" and a "background color", both of which are selected
  47. from a fixed set. See p_color2.c. */
  48. void
  49. _pl_p_set_fill_color(S___(Plotter *_plotter))
  50. {
  51. double red, green, blue;
  52. if (_plotter->drawstate->fill_type == 0)
  53. /* don't do anything, fill color will be ignored when writing objects*/
  54. return;
  55. red = ((double)((_plotter->drawstate->fillcolor).red))/0xFFFF;
  56. green = ((double)((_plotter->drawstate->fillcolor).green))/0xFFFF;
  57. blue = ((double)((_plotter->drawstate->fillcolor).blue))/0xFFFF;
  58. _plotter->drawstate->ps_fillcolor_red = red;
  59. _plotter->drawstate->ps_fillcolor_green = green;
  60. _plotter->drawstate->ps_fillcolor_blue = blue;
  61. /* next subroutine needs fields that this will fill in... */
  62. _pl_p_set_pen_color (S___(_plotter));
  63. /* Quantize for idraw, in a complicated way; we can choose from among a
  64. finite discrete set of values for ps_idraw_bgcolor and
  65. ps_idraw_shading, to approximate the fill color. We also adjust
  66. ps_fillcolor_* because the PS interpreter will use the
  67. ps_idraw_shading variable to interpolate between fgcolor and bgcolor,
  68. i.e. fgcolor and fillcolor. */
  69. _pl_p_compute_idraw_bgcolor (S___(_plotter));
  70. return;
  71. }
  72. /* Find, within the RGB color cube, the idraw pen color ("foreground
  73. color") that is closest to a specified color (our pen color). Euclidean
  74. distance is our metric. Our convention: no non-white color should be
  75. mapped to white. */
  76. static int
  77. _idraw_pseudocolor (int red, int green, int blue)
  78. {
  79. double difference;
  80. int i;
  81. int best = 0;
  82. difference = DBL_MAX;
  83. for (i = 0; i < PS_NUM_IDRAW_STD_COLORS; i++)
  84. {
  85. double newdifference;
  86. if (_pl_p_idraw_stdcolors[i].red == 0xffff
  87. && _pl_p_idraw_stdcolors[i].green == 0xffff
  88. && _pl_p_idraw_stdcolors[i].blue == 0xffff)
  89. /* white is a possible quantization only for white itself (our
  90. convention) */
  91. {
  92. if (red == 0xffff && green == 0xffff && blue == 0xffff)
  93. {
  94. difference = 0.0;
  95. best = i;
  96. }
  97. continue;
  98. }
  99. newdifference = ((double)(_pl_p_idraw_stdcolors[i].red - red)
  100. * (double)(_pl_p_idraw_stdcolors[i].red - red))
  101. + ((double)(_pl_p_idraw_stdcolors[i].green - green)
  102. * (double)(_pl_p_idraw_stdcolors[i].green - green))
  103. + ((double)(_pl_p_idraw_stdcolors[i].blue - blue)
  104. * (double)(_pl_p_idraw_stdcolors[i].blue - blue));
  105. if (newdifference < difference)
  106. {
  107. difference = newdifference;
  108. best = i;
  109. }
  110. }
  111. return best;
  112. }
  113. /* Once the idraw foreground color (i.e. quantized pen color) has been
  114. determined, this routine computes the idraw background color and idraw
  115. shading (0.0, 0.25, 0.5, 0.75, or 1.0) that will most closely match the
  116. user-specified fill color. It is called only when the elements
  117. ps_fillcolor_*, ps_idraw_fgcolor_* of the drawing state have been filled in.
  118. At the end of this function we adjust ps_fillcolor_* so that the output
  119. file will produce similar colors when parsed both by idraw and the PS
  120. interpreter. In fact we can persuade the PS interpreter to produce
  121. exactly the fill color specified by the user, except when the idraw
  122. shading is 0.0. In that case the fill color must be the same as the pen
  123. color. That situation will occur only if the user-specified fill color
  124. is very close to the user-specified pen color. */
  125. void
  126. _pl_p_compute_idraw_bgcolor(S___(Plotter *_plotter))
  127. {
  128. double truered, truegreen, trueblue;
  129. double fgred, fggreen, fgblue;
  130. double difference = DBL_MAX;
  131. int i, j;
  132. int best_bgcolor = 0, best_shading = 0;
  133. double best_shade = 0.0;
  134. truered = 0xFFFF * _plotter->drawstate->ps_fillcolor_red;
  135. truegreen = 0xFFFF * _plotter->drawstate->ps_fillcolor_green;
  136. trueblue = 0xFFFF * _plotter->drawstate->ps_fillcolor_blue;
  137. fgred = (double)(_pl_p_idraw_stdcolors[_plotter->drawstate->ps_idraw_fgcolor].red);
  138. fggreen = (double)(_pl_p_idraw_stdcolors[_plotter->drawstate->ps_idraw_fgcolor].green);
  139. fgblue = (double)(_pl_p_idraw_stdcolors[_plotter->drawstate->ps_idraw_fgcolor].blue);
  140. for (i = 0; i < PS_NUM_IDRAW_STD_COLORS; i++)
  141. {
  142. double bgred, bggreen, bgblue;
  143. bgred = (double)(_pl_p_idraw_stdcolors[i].red);
  144. bggreen = (double)(_pl_p_idraw_stdcolors[i].green);
  145. bgblue = (double)(_pl_p_idraw_stdcolors[i].blue);
  146. for (j = 0; j < PS_NUM_IDRAW_STD_SHADINGS; j++)
  147. {
  148. double approxred, approxgreen, approxblue;
  149. double shade, newdifference;
  150. shade = _pl_p_idraw_stdshadings[j];
  151. approxred = shade * bgred + (1.0 - shade) * fgred;
  152. approxgreen = shade * bggreen + (1.0 - shade) * fggreen;
  153. approxblue = shade * bgblue + (1.0 - shade) * fgblue;
  154. newdifference = (truered - approxred) * (truered - approxred)
  155. + (truegreen - approxgreen) * (truegreen - approxgreen)
  156. + (trueblue - approxblue) * (trueblue - approxblue);
  157. if (newdifference < difference)
  158. {
  159. difference = newdifference;
  160. best_bgcolor = i;
  161. best_shading = j;
  162. best_shade = shade;
  163. }
  164. }
  165. }
  166. _plotter->drawstate->ps_idraw_bgcolor = best_bgcolor;
  167. _plotter->drawstate->ps_idraw_shading = best_shading;
  168. /* now adjust ps_fillcolor_* fields so that interpolation between
  169. ps_fgcolor_* and ps_fillcolor_*, as specified by the shade, will yield
  170. the user-specified fill color. According to the PS prologue, the PS
  171. interpreter will compute a fill color thus:
  172. true_FILLCOLOR = shade * PS_FILLCOLOR + (1-shade) * PS_FGCOLOR
  173. we can compute an adjusted fillcolor thus:
  174. PS_FILLCOLOR = (true_FILLCOLOR - (1-shade) * PS_FGCOLOR) / shade.
  175. This is possible unless shade=0.0, in which case both idraw and the PS
  176. interpreter will use the pen color as the fill color. */
  177. if (best_shade != 0.0)
  178. {
  179. _plotter->drawstate->ps_fillcolor_red
  180. = (_plotter->drawstate->ps_fillcolor_red
  181. - (1.0 - best_shade) * _plotter->drawstate->ps_fgcolor_red) / best_shade;
  182. _plotter->drawstate->ps_fillcolor_green
  183. = (_plotter->drawstate->ps_fillcolor_green
  184. - (1.0 - best_shade) * _plotter->drawstate->ps_fgcolor_green) / best_shade;
  185. _plotter->drawstate->ps_fillcolor_blue
  186. = (_plotter->drawstate->ps_fillcolor_blue
  187. - (1.0 - best_shade) * _plotter->drawstate->ps_fgcolor_blue) / best_shade;
  188. }
  189. }