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