xref: /plan9/sys/src/cmd/gs/src/gshsb.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
1 /* Copyright (C) 1994, 1997, 1998 Aladdin Enterprises.  All rights reserved.
2 
3   This software is provided AS-IS with no warranty, either express or
4   implied.
5 
6   This software is distributed under license and may not be copied,
7   modified or distributed except as expressly authorized under the terms
8   of the license contained in the file LICENSE in this distribution.
9 
10   For more information about licensing, please refer to
11   http://www.ghostscript.com/licensing/. For information on
12   commercial licensing, go to http://www.artifex.com/licensing/ or
13   contact Artifex Software, Inc., 101 Lucas Valley Road #110,
14   San Rafael, CA  94903, U.S.A., +1(415)492-9861.
15 */
16 
17 /* $Id: gshsb.c,v 1.5 2002/06/16 05:48:55 lpd Exp $ */
18 /* HSB color operators for Ghostscript library */
19 #include "gx.h"
20 #include "gscolor.h"
21 #include "gshsb.h"		/* interface definition */
22 #include "gxfrac.h"
23 
24 /* Forward references */
25 private void color_hsb_to_rgb(floatp h, floatp s, floatp b, float rgb[3]);
26 private void color_rgb_to_hsb(floatp r, floatp g, floatp b, float hsb[3]);
27 
28 /* Force a parameter into the range [0.0..1.0]. */
29 #define force_unit(p) (p < 0.0 ? 0.0 : p > 1.0 ? 1.0 : p)
30 
31 /* sethsbcolor */
32 int
gs_sethsbcolor(gs_state * pgs,floatp h,floatp s,floatp b)33 gs_sethsbcolor(gs_state * pgs, floatp h, floatp s, floatp b)
34 {
35     float rgb[3];
36 
37     color_hsb_to_rgb(force_unit(h), force_unit(s), force_unit(b), rgb);
38     return gs_setrgbcolor(pgs, rgb[0], rgb[1], rgb[2]);
39 }
40 
41 /* currenthsbcolor */
42 int
gs_currenthsbcolor(const gs_state * pgs,float pr3[3])43 gs_currenthsbcolor(const gs_state * pgs, float pr3[3])
44 {
45     float rgb[3];
46 
47     gs_currentrgbcolor(pgs, rgb);
48     color_rgb_to_hsb(rgb[0], rgb[1], rgb[2], pr3);
49     return 0;
50 }
51 
52 /* ------ Internal routines ------ */
53 
54 /* Note: the color model conversion algorithms are taken from */
55 /* Rogers, Procedural Elements for Computer Graphics, pp. 401-403. */
56 
57 /* Convert RGB to HSB. */
58 private void
color_rgb_to_hsb(floatp r,floatp g,floatp b,float hsb[3])59 color_rgb_to_hsb(floatp r, floatp g, floatp b, float hsb[3])
60 {
61     frac red = float2frac(r), green = float2frac(g), blue = float2frac(b);
62 
63 #define rhue hsb[0]
64 #define rsat hsb[1]
65 #define rbri hsb[2]
66     if (red == green && green == blue) {
67 	rhue = 0;		/* arbitrary */
68 	rsat = 0;
69 	rbri = r;		/* pick any one */
70     } else {			/* Convert rgb to hsb */
71 	frac V, Temp, diff;
72 	long H;
73 
74 	V = (red > green ? red : green);
75 	if (blue > V)
76 	    V = blue;
77 	Temp = (red > green ? green : red);
78 	if (blue < Temp)
79 	    Temp = blue;
80 	diff = V - Temp;
81 	if (V == red)
82 	    H = (green - blue) * frac_1_long / diff;
83 	else if (V == green)
84 	    H = (blue - red) * frac_1_long / diff + 2 * frac_1_long;
85 	else			/* V == blue */
86 	    H = (red - green) * frac_1_long / diff + 4 * frac_1_long;
87 	if (H < 0)
88 	    H += 6 * frac_1_long;
89 	rhue = H / (frac_1 * 6.0);
90 	rsat = diff / (float)V;
91 	rbri = frac2float(V);
92     }
93 #undef rhue
94 #undef rsat
95 #undef rbri
96 }
97 
98 /* Convert HSB to RGB. */
99 private void
color_hsb_to_rgb(floatp hue,floatp saturation,floatp brightness,float rgb[3])100 color_hsb_to_rgb(floatp hue, floatp saturation, floatp brightness, float rgb[3])
101 {
102     if (saturation == 0) {
103 	rgb[0] = rgb[1] = rgb[2] = brightness;
104     } else {			/* Convert hsb to rgb. */
105 	/* We rely on the fact that the product of two */
106 	/* fracs fits into an unsigned long. */
107 	floatp h6 = hue * 6;
108 	ulong V = float2frac(brightness);	/* force arithmetic to long */
109 	frac S = float2frac(saturation);
110 	int I = (int)h6;
111 	ulong F = float2frac(h6 - I);	/* ditto */
112 
113 	/* M = V*(1-S), N = V*(1-S*F), K = V*(1-S*(1-F)) = M-N+V */
114 	frac M = V * (frac_1_long - S) / frac_1_long;
115 	frac N = V * (frac_1_long - S * F / frac_1_long) / frac_1_long;
116 	frac K = M - N + V;
117 	frac R, G, B;
118 
119 	switch (I) {
120 	    default:
121 		R = V;
122 		G = K;
123 		B = M;
124 		break;
125 	    case 1:
126 		R = N;
127 		G = V;
128 		B = M;
129 		break;
130 	    case 2:
131 		R = M;
132 		G = V;
133 		B = K;
134 		break;
135 	    case 3:
136 		R = M;
137 		G = N;
138 		B = V;
139 		break;
140 	    case 4:
141 		R = K;
142 		G = M;
143 		B = V;
144 		break;
145 	    case 5:
146 		R = V;
147 		G = M;
148 		B = N;
149 		break;
150 	}
151 	rgb[0] = frac2float(R);
152 	rgb[1] = frac2float(G);
153 	rgb[2] = frac2float(B);
154 #ifdef DEBUG
155 	if (gs_debug_c('c')) {
156 	    dlprintf7("[c]hsb(%g,%g,%g)->VSFI(%ld,%d,%ld,%d)->\n",
157 		      hue, saturation, brightness, V, S, F, I);
158 	    dlprintf6("   RGB(%d,%d,%d)->rgb(%g,%g,%g)\n",
159 		      R, G, B, rgb[0], rgb[1], rgb[2]);
160 	}
161 #endif
162     }
163 }
164