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 
4    The GNU plotutils package is free software.  You may redistribute it
5    and/or modify it under the terms of the GNU General Public License as
6    published by the Free Software foundation; either version 2, or (at your
7    option) any later version.
8 
9    The GNU plotutils package is distributed in the hope that it will be
10    useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12    General Public License for more details.
13 
14    You should have received a copy of the GNU General Public License along
15    with the GNU plotutils package; see the file COPYING.  If not, write to
16    the Free Software Foundation, Inc., 51 Franklin St., Fifth Floor,
17    Boston, MA 02110-1301, USA. */
18 
19 /* This file contains device-specific color database access routines.
20    These routines are called by various GIFPlotter methods, before drawing
21    objects.  They set the appropriate GIFPlotter-specific fields in the
22    drawing state. */
23 
24 #include "sys-defines.h"
25 #include "extern.h"
26 
27 /* forward references */
28 static int bit_depth (int colors);
29 
30 /* we call this routine to evaluate _plotter->drawstate->i_pen_color_index
31    lazily, i.e. only when needed (just before a drawing operation) */
32 void
_pl_i_set_pen_color(S___ (Plotter * _plotter))33 _pl_i_set_pen_color(S___(Plotter *_plotter))
34 {
35   int red_long, green_long, blue_long;
36   int red, green, blue;
37 
38   /* 48-bit RGB */
39   red_long = _plotter->drawstate->fgcolor.red;
40   green_long = _plotter->drawstate->fgcolor.green;
41   blue_long = _plotter->drawstate->fgcolor.blue;
42 
43   /* 24-bit RGB (as used in GIFs) */
44   red = (((unsigned int)red_long) >> 8) & 0xff;
45   green = (((unsigned int)green_long) >> 8) & 0xff;
46   blue = (((unsigned int)blue_long) >> 8) & 0xff;
47 
48   if (!(_plotter->drawstate->i_pen_color_status
49 	&& _plotter->drawstate->i_pen_color.red == red
50 	&& _plotter->drawstate->i_pen_color.green == green
51 	&& _plotter->drawstate->i_pen_color.blue == blue))
52     /* need another color index: search table, expand if necessary */
53     {
54       unsigned char index;
55 
56       index = _pl_i_new_color_index (R___(_plotter) red, green, blue);
57 
58       /* set new 24-bit RGB and color index in the drawing state */
59       _plotter->drawstate->i_pen_color.red = red;
60       _plotter->drawstate->i_pen_color.green = green;
61       _plotter->drawstate->i_pen_color.blue = blue;
62       _plotter->drawstate->i_pen_color_index = index;
63 
64       /* flag this color index as genuine */
65       _plotter->drawstate->i_pen_color_status = true;
66     }
67 }
68 
69 /* we call this routine to evaluate _plotter->drawstate->i_fill_color_index
70    lazily, i.e. only when needed (just before a filling operation) */
71 void
_pl_i_set_fill_color(S___ (Plotter * _plotter))72 _pl_i_set_fill_color(S___(Plotter *_plotter))
73 {
74   int red_long, green_long, blue_long;
75   int red, green, blue;
76 
77   if (_plotter->drawstate->fill_type == 0)
78     /* don't do anything, fill color will be ignored when writing objects */
79     return;
80 
81   /* 48-bit RGB */
82   red_long = _plotter->drawstate->fillcolor.red;
83   green_long = _plotter->drawstate->fillcolor.green;
84   blue_long = _plotter->drawstate->fillcolor.blue;
85 
86   /* 24-bit RGB (as used in GIFs) */
87   red = (((unsigned int)red_long) >> 8) & 0xff;
88   green = (((unsigned int)green_long) >> 8) & 0xff;
89   blue = (((unsigned int)blue_long) >> 8) & 0xff;
90 
91   if (!(_plotter->drawstate->i_fill_color_status
92 	&& _plotter->drawstate->i_fill_color.red == red
93 	&& _plotter->drawstate->i_fill_color.green == green
94 	&& _plotter->drawstate->i_fill_color.blue == blue))
95     /* need another color index: search table, expand if necessary */
96     {
97       unsigned char index;
98 
99       index = _pl_i_new_color_index (R___(_plotter) red, green, blue);
100 
101       /* set new 24-bit RGB and color index in the drawing state */
102       _plotter->drawstate->i_fill_color.red = red;
103       _plotter->drawstate->i_fill_color.green = green;
104       _plotter->drawstate->i_fill_color.blue = blue;
105       _plotter->drawstate->i_fill_color_index = index;
106     }
107 }
108 
109 /* we call this routine to compute and set
110    _plotter->drawstate->i_bg_color_index, e.g. in _pl_i_new_image */
111 void
_pl_i_set_bg_color(S___ (Plotter * _plotter))112 _pl_i_set_bg_color(S___(Plotter *_plotter))
113 {
114   int red_long, green_long, blue_long;
115   int red, green, blue;
116 
117   /* 48-bit RGB */
118   red_long = _plotter->drawstate->bgcolor.red;
119   green_long = _plotter->drawstate->bgcolor.green;
120   blue_long = _plotter->drawstate->bgcolor.blue;
121 
122   /* 24-bit RGB (as used in GIFs) */
123   red = (((unsigned int)red_long) >> 8) & 0xff;
124   green = (((unsigned int)green_long) >> 8) & 0xff;
125   blue = (((unsigned int)blue_long) >> 8) & 0xff;
126 
127   if (!(_plotter->drawstate->i_bg_color_status
128 	&& _plotter->drawstate->i_bg_color.red == red
129 	&& _plotter->drawstate->i_bg_color.green == green
130 	&& _plotter->drawstate->i_bg_color.blue == blue))
131     /* need another color index: search table, expand if necessary */
132     {
133       unsigned char index;
134 
135       index = _pl_i_new_color_index (R___(_plotter) red, green, blue);
136 
137       /* set new 24-bit RGB and color index in the drawing state */
138       _plotter->drawstate->i_bg_color.red = red;
139       _plotter->drawstate->i_bg_color.green = green;
140       _plotter->drawstate->i_bg_color.blue = blue;
141       _plotter->drawstate->i_bg_color_index = index;
142 
143       /* flag this color index as genuine */
144       _plotter->drawstate->i_bg_color_status = true;
145     }
146 }
147 
148 /* Internal function, called by each of the above.  It searches for a
149    24-bit RGB in the color table.  If not found, it's added to table,
150    unless table can't be expanded, in which case index with closest RGB is
151    returned. */
152 
153 unsigned char
_pl_i_new_color_index(R___ (Plotter * _plotter)int red,int green,int blue)154 _pl_i_new_color_index (R___(Plotter *_plotter) int red, int green, int blue)
155 {
156   int i, j;
157   int sqdist;
158   bool found = false;
159 
160   for (i = 0; i < _plotter->i_num_color_indices; i++)
161     if (_plotter->i_colormap[i].red == red
162 	&& _plotter->i_colormap[i].green == green
163 	&& _plotter->i_colormap[i].blue == blue)
164       {
165 	found = true;
166 	break;
167       }
168   if (found)
169     return (unsigned char)i;
170 
171   /* not found, try to allocate new index */
172   i = _plotter->i_num_color_indices;
173   if (i < 256)
174     {
175       _plotter->i_colormap[i].red = red;
176       _plotter->i_colormap[i].green = green;
177       _plotter->i_colormap[i].blue = blue;
178       _plotter->i_num_color_indices = i + 1;
179 
180       /* New bit depth of colormap, e.g. sizes 129..256 get mapped to 8.
181 	 In effect the colormap for any of these sizes will be of size 256. */
182       _plotter->i_bit_depth = bit_depth (i + 1);
183 
184       return (unsigned char)i;
185     }
186 
187   /* table full, do our best */
188   sqdist = INT_MAX;
189   i = 0;
190   for (j = 0; j < 256; j++)
191     {
192       int new_sqdist;
193       int a_red, a_green, a_blue;
194 
195       a_red = _plotter->i_colormap[j].red;
196       a_green = _plotter->i_colormap[j].green;
197       a_blue = _plotter->i_colormap[j].blue;
198       new_sqdist = ((a_red - red) * (a_red - red)
199 		    + (a_green - green) * (a_green - green)
200 		    + (a_blue - blue) * (a_blue - blue));
201       if (new_sqdist <= sqdist)
202 	{
203 	  sqdist = new_sqdist;
204 	  i = j;		/* best to date */
205 	}
206     }
207   return (unsigned char)i;
208 }
209 
210 /* compute number of bits needed to represent all color indices
211    (when this is called, colors >= 1) */
212 static int
bit_depth(int colors)213 bit_depth (int colors)
214 {
215   int size;
216   unsigned int ucolors;
217 
218   /* subtract 1, see how many bits needed to represent result */
219   size = 0;
220   for (ucolors = colors - 1; ucolors; ucolors = ucolors >> 1)
221     size++;
222 
223   return size;
224 }
225