Commit | Line | Data |
---|---|---|
0c52bae1 WJ |
1 | /* Copyright (C) 1989, 1992 Aladdin Enterprises. All rights reserved. |
2 | Distributed by Free Software Foundation, Inc. | |
3 | ||
4 | This file is part of Ghostscript. | |
5 | ||
6 | Ghostscript is distributed in the hope that it will be useful, but | |
7 | WITHOUT ANY WARRANTY. No author or distributor accepts responsibility | |
8 | to anyone for the consequences of using it or for whether it serves any | |
9 | particular purpose or works at all, unless he says so in writing. Refer | |
10 | to the Ghostscript General Public License for full details. | |
11 | ||
12 | Everyone is granted permission to copy, modify and redistribute | |
13 | Ghostscript, but only under the conditions described in the Ghostscript | |
14 | General Public License. A copy of this license is supposed to have been | |
15 | given to you along with Ghostscript so you can know your rights and | |
16 | responsibilities. It should be in a file named COPYING. Among other | |
17 | things, the copyright notice and this notice must be preserved on all | |
18 | copies. */ | |
19 | ||
20 | /* gxcolor.c */ | |
21 | /* Private color procedures for Ghostscript library */ | |
22 | #include "gx.h" | |
23 | #include "gserrors.h" | |
24 | #include "gxfixed.h" /* for gxmatrix.h */ | |
25 | #include "gxlum.h" | |
26 | #include "gxmatrix.h" | |
27 | #include "gxdevice.h" /* for gx_color_index */ | |
28 | #include "gzcolor.h" | |
29 | #include "gzht.h" | |
30 | #include "gzstate.h" | |
31 | ||
32 | /* Imported procedures */ | |
33 | void gx_color_render(P3(gs_color *, gx_device_color *, gs_state *)); | |
34 | ||
35 | /* Forward declarations */ | |
36 | void gx_color_from_rgb(P1(gs_color *)); | |
37 | ||
38 | /* ------ Color setup routines ------ */ | |
39 | ||
40 | /* Set up black for writing into the character cache. */ | |
41 | void | |
42 | gx_set_black(gs_state *pgs) | |
43 | { register gs_color *pcolor = pgs->color; | |
44 | pcolor->red = pcolor->green = pcolor->blue = pcolor->luminance = 0; | |
45 | pcolor->luminance_set = 1; | |
46 | pcolor->is_gray = 1; | |
47 | pcolor->space = (byte)gs_color_space_DeviceGray; | |
48 | gx_color_render(pcolor, pgs->dev_color, pgs); | |
49 | } | |
50 | ||
51 | /* Set up a gray color. This is an internal routine */ | |
52 | /* for use by initialization and gx_remap_color. */ | |
53 | void | |
54 | gx_set_gray_only(register gs_color *pcolor, color_param gray) | |
55 | { pcolor->red = pcolor->green = pcolor->blue = | |
56 | pcolor->luminance = gray; | |
57 | pcolor->luminance_set = 1; | |
58 | pcolor->is_gray = 1; | |
59 | pcolor->space = (byte)gs_color_space_DeviceGray; | |
60 | } | |
61 | ||
62 | /* Set up an RGB color. This is an internal routine */ | |
63 | /* for use by gx_remap_color. */ | |
64 | void | |
65 | gx_set_rgb_only(register gs_color *pcolor, | |
66 | color_param r, color_param g, color_param b) | |
67 | { pcolor->red = r; | |
68 | pcolor->green = g; | |
69 | pcolor->blue = b; | |
70 | gx_color_from_rgb(pcolor); | |
71 | } | |
72 | ||
73 | /* Set up an RGB color. */ | |
74 | void | |
75 | gx_color_from_rgb(register gs_color *pcolor) | |
76 | { if ( pcolor->red == pcolor->green && pcolor->green == pcolor->blue ) | |
77 | { pcolor->luminance = pcolor->red; /* pick any one */ | |
78 | pcolor->is_gray = pcolor->luminance_set = 1; | |
79 | } | |
80 | else | |
81 | { /* Compute luminance later */ | |
82 | pcolor->is_gray = pcolor->luminance_set = 0; | |
83 | } | |
84 | pcolor->space = (byte)gs_color_space_DeviceRGB; | |
85 | } | |
86 | ||
87 | /* Force a parameter into the range [0..1], */ | |
88 | /* and convert to a color_param. */ | |
89 | color_param | |
90 | gx_color_unit_param(floatp fval) | |
91 | { if ( fval <= 0.0 ) | |
92 | return 0; | |
93 | else if ( fval >= 1.0 ) | |
94 | return max_color_param; | |
95 | else | |
96 | return (color_param)(fval * max_color_param_float); | |
97 | } | |
98 | ||
99 | /* Map a color_param through a transfer map. */ | |
100 | color_param | |
101 | gx_color_param_map(color_param cv, color_param *values) | |
102 | { | |
103 | #define cp_frac_bits (color_param_bits - log2_transfer_map_size) | |
104 | int cmi = cv >> cp_frac_bits; | |
105 | color_param mv = values[cmi]; | |
106 | int rem, mdv; | |
107 | /* Interpolate between two adjacent values if needed. */ | |
108 | rem = (cv & ((1 << cp_frac_bits) - 1)) - (cv >> (color_param_bits - cp_frac_bits)); | |
109 | if ( rem == 0 ) return mv; | |
110 | else if ( rem > 0 ) mdv = values[cmi + 1] - mv; | |
111 | else mdv = mv - values[cmi - 1]; | |
112 | #if arch_ints_are_short | |
113 | /* Only use long multiplication if necessary. */ | |
114 | if ( mdv > 1 << (16 - cp_frac_bits) ) | |
115 | return mv + (uint)(((ulong)rem * mdv) >> cp_frac_bits); | |
116 | #endif | |
117 | return mv + ((rem * mdv) >> cp_frac_bits); | |
118 | #undef cp_frac_bits | |
119 | } | |
120 | ||
121 | /* Remap the color in the graphics state. */ | |
122 | void gx_render_color(P2(gs_color *, gs_state *)); | |
123 | int | |
124 | gx_remap_color(gs_state *pgs) | |
125 | { gs_color *pcolor = pgs->color; | |
126 | gs_color mcolor; /* color mapped by transfer procs */ | |
127 | #define mapcp(p,c) gx_map_color_param(pgs, pcolor->c, p) | |
128 | switch ( (gs_color_space)pcolor->space ) | |
129 | { | |
130 | case gs_color_space_DeviceGray: | |
131 | gx_set_gray_only(&mcolor, mapcp(gray, red)); /* any one */ | |
132 | break; | |
133 | case gs_color_space_DeviceRGB: | |
134 | gx_set_rgb_only(&mcolor, mapcp(red, red), | |
135 | mapcp(green, green), mapcp(blue, blue)); | |
136 | break; | |
137 | default: | |
138 | return_error(gs_error_undefined); | |
139 | } | |
140 | #undef mapcp | |
141 | gx_render_color(&mcolor, pgs); | |
142 | return 0; | |
143 | } | |
144 | void | |
145 | gx_render_color(gs_color *pmcolor, gs_state *pgs) | |
146 | { gx_color_render(pmcolor, pgs->dev_color, pgs); | |
147 | } | |
148 | ||
149 | /* ------ Color conversion routines ------ */ | |
150 | ||
151 | /* Note: the color model conversion algorithms are taken from */ | |
152 | /* Rogers, Procedural Elements for Computer Graphics, pp. 401-403. */ | |
153 | ||
154 | /* Compute (if necessary) and return the luminance of a color. */ | |
155 | color_param | |
156 | gx_color_luminance(register gs_color *pcolor) | |
157 | { if ( !pcolor->luminance_set ) | |
158 | { pcolor->luminance = | |
159 | (pcolor->red * (unsigned long)lum_red_weight + | |
160 | pcolor->green * (unsigned long)lum_green_weight + | |
161 | pcolor->blue * (unsigned long)lum_blue_weight + | |
162 | (lum_all_weights / 2)) | |
163 | / lum_all_weights; | |
164 | pcolor->luminance_set = 1; | |
165 | } | |
166 | return pcolor->luminance; | |
167 | } | |
168 | ||
169 | /* Convert RGB to HSB */ | |
170 | void | |
171 | gx_color_to_hsb(register gs_color *pcolor, color_param hsb[3]) | |
172 | { | |
173 | #define rhue hsb[0] | |
174 | #define rsat hsb[1] | |
175 | #define rbri hsb[2] | |
176 | if ( pcolor->is_gray ) | |
177 | { rhue = 0; /* arbitrary */ | |
178 | rsat = 0; | |
179 | rbri = pcolor->red; /* pick any one */ | |
180 | } | |
181 | else | |
182 | { /* Convert rgb to hsb */ | |
183 | gs_color c; | |
184 | color_param V, Temp; | |
185 | long diff, H; | |
186 | c.red = pcolor->red; | |
187 | c.green = pcolor->green; | |
188 | c.blue = pcolor->blue; | |
189 | V = (c.red > c.green ? c.red : c.green); | |
190 | if ( c.blue > V ) V = c.blue; | |
191 | Temp = (c.red > c.green ? c.green : c.red); | |
192 | if ( c.blue < Temp ) Temp = c.blue; | |
193 | diff = V - Temp; | |
194 | if ( V == c.red ) | |
195 | H = (c.green - c.blue) * max_color_param_long / diff; | |
196 | else if ( V == c.green ) | |
197 | H = (c.blue - c.red) * max_color_param_long / diff + 2 * max_color_param_long; | |
198 | else /* V == c.blue */ | |
199 | H = (c.red - c.green) * max_color_param_long / diff + 4 * max_color_param_long; | |
200 | if ( H < 0 ) H += 6 * max_color_param_long; | |
201 | rhue = H / 6; | |
202 | rsat = diff * max_color_param_long / V; | |
203 | rbri = V; | |
204 | } | |
205 | #undef rhue | |
206 | #undef rsat | |
207 | #undef rbri | |
208 | } | |
209 | ||
210 | /* Complete color specified by hsb */ | |
211 | void | |
212 | gx_color_from_hsb(register gs_color *pcolor, | |
213 | color_param hue, color_param saturation, color_param brightness) | |
214 | { if ( saturation == 0 ) | |
215 | { pcolor->red = pcolor->green = pcolor->blue = brightness; | |
216 | } | |
217 | else | |
218 | { /* Convert hsb to rgb. */ | |
219 | /* We rely on the fact that the product of two */ | |
220 | /* color_params fits into an unsigned long. */ | |
221 | ulong V = brightness; /* force arithmetic to long */ | |
222 | color_param S = saturation; | |
223 | #define mcp max_color_param | |
224 | #define mcpl max_color_param_long | |
225 | #define mcp6 (mcp / 6 + 1) | |
226 | ulong F = (hue % mcp6) * 6; /* ditto */ | |
227 | int I = hue / mcp6; | |
228 | color_param M = V * (mcpl - S) / mcpl; | |
229 | color_param N = V * (mcpl - S * F / mcpl) / mcpl; | |
230 | color_param K = V * (mcpl - S * (mcpl - F) / mcpl) / mcpl; | |
231 | #undef mcp6 | |
232 | #undef mcpl | |
233 | #undef mcp | |
234 | color_param R, G, B; | |
235 | switch ( I ) | |
236 | { | |
237 | default: R = V; G = K; B = M; break; | |
238 | case 1: R = N; G = V; B = M; break; | |
239 | case 2: R = M; G = V; B = K; break; | |
240 | case 3: R = M; G = N; B = V; break; | |
241 | case 4: R = K; G = M; B = V; break; | |
242 | case 5: R = V; G = M; B = N; break; | |
243 | } | |
244 | pcolor->red = R; | |
245 | pcolor->green = G; | |
246 | pcolor->blue = B; | |
247 | } | |
248 | gx_color_from_rgb(pcolor); /* compute luminance */ | |
249 | } | |
250 | ||
251 | /* ------ Internal routines ------ */ | |
252 | ||
253 | /* Heapsort (algorithm 5.2.3H, Knuth vol. 2, p. 146), */ | |
254 | /* modified for 0-origin indexing. */ | |
255 | void | |
256 | gx_sort_ht_order(ht_bit *recs, uint N) | |
257 | { uint l = N >> 1; | |
258 | uint r = N - 1; | |
259 | uint j; | |
260 | ht_bit R; | |
261 | if ( N <= 1 ) return; | |
262 | #define key(m) recs[m].mask | |
263 | #define K R.mask | |
264 | while ( 1 ) | |
265 | { if ( l > 0 ) | |
266 | R = recs[--l]; | |
267 | else | |
268 | { R = recs[r]; | |
269 | recs[r] = recs[0]; | |
270 | if ( --r == 0 ) | |
271 | { recs[0] = R; | |
272 | break; | |
273 | } | |
274 | } | |
275 | j = l; | |
276 | while ( 1 ) | |
277 | { uint i = j; | |
278 | j = j + j + 1; | |
279 | if ( j < r ) | |
280 | if ( key(j) < key(j + 1) ) j++; | |
281 | if ( j > r || K >= key(j) ) | |
282 | { recs[i] = R; | |
283 | break; /* to outer loop */ | |
284 | } | |
285 | recs[i] = recs[j]; | |
286 | } | |
287 | } | |
288 | } |