386BSD 0.1 development
[unix-history] / usr / othersrc / public / ghostscript-2.4.1 / gxcolor.c
CommitLineData
0c52bae1
WJ
1/* Copyright (C) 1989, 1992 Aladdin Enterprises. All rights reserved.
2 Distributed by Free Software Foundation, Inc.
3
4This file is part of Ghostscript.
5
6Ghostscript is distributed in the hope that it will be useful, but
7WITHOUT ANY WARRANTY. No author or distributor accepts responsibility
8to anyone for the consequences of using it or for whether it serves any
9particular purpose or works at all, unless he says so in writing. Refer
10to the Ghostscript General Public License for full details.
11
12Everyone is granted permission to copy, modify and redistribute
13Ghostscript, but only under the conditions described in the Ghostscript
14General Public License. A copy of this license is supposed to have been
15given to you along with Ghostscript so you can know your rights and
16responsibilities. It should be in a file named COPYING. Among other
17things, the copyright notice and this notice must be preserved on all
18copies. */
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 */
33void gx_color_render(P3(gs_color *, gx_device_color *, gs_state *));
34
35/* Forward declarations */
36void gx_color_from_rgb(P1(gs_color *));
37
38/* ------ Color setup routines ------ */
39
40/* Set up black for writing into the character cache. */
41void
42gx_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. */
53void
54gx_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. */
64void
65gx_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. */
74void
75gx_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. */
89color_param
90gx_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. */
100color_param
101gx_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. */
122void gx_render_color(P2(gs_color *, gs_state *));
123int
124gx_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}
144void
145gx_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. */
155color_param
156gx_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 */
170void
171gx_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 */
211void
212gx_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. */
255void
256gx_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}