1 /* Copyright (C) 2008-2012 by George Williams */
2 /*
3  * Redistribution and use in source and binary forms, with or without
4  * modification, are permitted provided that the following conditions are met:
5 
6  * Redistributions of source code must retain the above copyright notice, this
7  * list of conditions and the following disclaimer.
8 
9  * Redistributions in binary form must reproduce the above copyright notice,
10  * this list of conditions and the following disclaimer in the documentation
11  * and/or other materials provided with the distribution.
12 
13  * The name of the author may not be used to endorse or promote products
14  * derived from this software without specific prior written permission.
15 
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19  * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27 
28 #include <fontforge-config.h>
29 
30 #include "gimage.h"
31 
32 #include <math.h>
33 #include <string.h>
34 
gRGB2HSL(struct hslrgb * col)35 void gRGB2HSL(struct hslrgb *col) {
36     double mx, mn;
37 
38     /* Algorithm from http://en.wikipedia.org/wiki/HSL_color_space */
39     if ( col->r>col->g ) {
40 	mx = ( col->r>col->b ) ? col->r : col->b;
41 	mn = ( col->g<col->b ) ? col->g : col->b;
42     } else {
43 	mx = ( col->g>col->b ) ? col->g : col->b;
44 	mn = ( col->r<col->b ) ? col->r : col->b;
45     }
46     if ( mx==mn )
47 	col->h = 0;
48     else if ( mx==col->r ) {
49 	col->h = fmod(60*(col->g-col->b)/(mx-mn),360);
50     } else if ( mx==col->g ) {
51 	col->h = 60*(col->b-col->r)/(mx-mn) + 120;
52     } else {
53 	col->h = 60*(col->r-col->g)/(mx-mn) + 240;
54     }
55     col->l = (mx+mn)/2;
56     if ( mx==mn )
57 	col->s = 0;
58     else if ( col->l<=.5 )
59 	col->s = (mx-mn)/(mx+mn);
60     else
61 	col->s = (mx-mn)/(2-(mx+mn));
62     col->hsl = true; col->hsv = false;
63 }
64 
gHSL2RGB(struct hslrgb * col)65 void gHSL2RGB(struct hslrgb *col) {
66     double q,p,hk, ts[3], cs[3];
67     int i;
68 
69     /* Algorithm from http://en.wikipedia.org/wiki/HSL_color_space */
70     if ( col->l<.5 )
71 	q = col->l*(1 + col->s);
72     else
73 	q = col->l+col->s - (col->l*col->s);
74     p = 2*col->l - q;
75     hk = fmod(col->h,360)/360;
76     if ( hk<0 ) hk += 1.0;
77     ts[0] = hk + 1./3.;
78     ts[1] = hk;
79     ts[2] = hk - 1./3.;
80 
81     for ( i=0; i<3; ++i ) {
82 	if ( ts[i]<0 ) ts[i] += 1.0;
83 	else if ( ts[i]>1 ) ts[i] -= 1.0;
84 	if ( ts[i]<1./6. )
85 	    cs[i] = p + ((q-p)*6*ts[i]);
86 	else if ( ts[i]<.5 )
87 	    cs[i] = q;
88 	else if ( ts[i]<2./3. )
89 	    cs[i] = p + ((q-p)*6*(2./3.-ts[i]));
90 	else
91 	    cs[i] = p;
92     }
93     col->r = cs[0];
94     col->g = cs[1];
95     col->b = cs[2];
96     col->rgb = true;
97 }
98 
gRGB2HSV(struct hslrgb * col)99 void gRGB2HSV(struct hslrgb *col) {
100     double mx, mn;
101 
102     /* Algorithm from http://en.wikipedia.org/wiki/HSL_color_space */
103     if ( col->r>col->g ) {
104 	mx = ( col->r>col->b ) ? col->r : col->b;
105 	mn = ( col->g<col->b ) ? col->g : col->b;
106     } else {
107 	mx = ( col->g>col->b ) ? col->g : col->b;
108 	mn = ( col->r<col->b ) ? col->r : col->b;
109     }
110     if ( mx==mn )
111 	col->h = 0;
112     else if ( mx==col->r ) {
113 	col->h = fmod(60*(col->g-col->b)/(mx-mn),360);
114     } else if ( mx==col->g ) {
115 	col->h = 60*(col->b-col->r)/(mx-mn) + 120;
116     } else {
117 	col->h = 60*(col->r-col->g)/(mx-mn) + 240;
118     }
119     col->v = mx;
120     if ( mx==0 )
121 	col->s = 0;
122     else
123 	col->s = (mx-mn)/mx;
124     col->hsv = true; col->hsl = false;
125 }
126 
gHSV2RGB(struct hslrgb * col)127 void gHSV2RGB(struct hslrgb *col) {
128     double q,p,t,f;
129     int h;
130 
131     /* Algorithm from http://en.wikipedia.org/wiki/HSL_color_space */
132     h = ((int) floor(col->h/60)) % 6;
133     if ( h<0 ) h+=6;
134     f = col->h/60 - floor(col->h/60);
135 
136     p = col->v*(1-col->s);
137     q = col->v*(1-f*col->s);
138     t = col->v*(1-(1-f)*col->s);
139 
140     if ( h==0 ) {
141 	col->r = col->v; col->g = t; col->b = p;
142     } else if ( h==1 ) {
143 	col->r = q; col->g = col->v; col->b = p;
144     } else if ( h==2 ) {
145 	col->r = p; col->g = col->v; col->b = t;
146     } else if ( h==3 ) {
147 	col->r = p; col->g = q; col->b = col->v;
148     } else if ( h==4 ) {
149 	col->r = t; col->g = p; col->b = col->v;
150     } else if ( h==5 ) {
151 	col->r = col->v; col->g = p; col->b = q;
152     }
153     col->rgb = true;
154 }
155 
gHslrgb2Color(struct hslrgb * col)156 Color gHslrgb2Color(struct hslrgb *col) {
157     if ( !col->rgb ) {
158 	if ( col->hsv )
159 	    gHSV2RGB(col);
160 	else if ( col->hsl )
161 	    gHSL2RGB(col);
162 	else
163 	    return( COLOR_UNKNOWN );
164     }
165     return( (((int) rint(255.*col->r))<<16 ) | \
166 	    (((int) rint(255.*col->g))<<8 )  | \
167 	    (((int) rint(255.*col->b)) ) );
168 }
169 
gHslrgba2Color(struct hslrgba * col)170 Color gHslrgba2Color(struct hslrgba *col) {
171     if ( !col->rgb ) {
172 	if ( col->hsv )
173 	    gHSV2RGB((struct hslrgb *) col);
174 	else if ( col->hsl )
175 	    gHSL2RGB((struct hslrgb *) col);
176 	else
177 	    return( COLOR_UNKNOWN );
178     }
179     if ( !col->has_alpha || col->alpha==1.0 )
180 	return( (((int) rint(255.*col->r))<<16 ) | \
181 		(((int) rint(255.*col->g))<<8 )  | \
182 		(((int) rint(255.*col->b)) ) );
183     else if ( col->alpha==0.0 )
184 	return( COLOR_TRANSPARENT );
185     else
186 	return( (((int) rint(255.*col->alpha))<<24 ) | \
187 		(((int) rint(255.*col->r))<<16) | \
188 		(((int) rint(255.*col->g))<<8 ) | \
189 		(((int) rint(255.*col->b)) ) );
190 }
191 
gColor2Hslrgb(struct hslrgb * col,Color from)192 void gColor2Hslrgb(struct hslrgb *col,Color from) {
193     col->rgb = true;
194     col->r = ((from>>16)&0xff)/255.0;
195     col->g = ((from>>8 )&0xff)/255.0;
196     col->b = ((from    )&0xff)/255.0;
197     col->hsl = col->hsv = false;
198 }
199 
gColor2Hslrgba(struct hslrgba * col,Color from)200 void gColor2Hslrgba(struct hslrgba *col,Color from) {
201     if ( from == COLOR_TRANSPARENT ) {
202 	memset(col,0,sizeof(*col));
203 	col->has_alpha = 1;
204     } else {
205 	col->alpha = ((from>>24)&0xff)/255.0;
206 	col->r = ((from>>16)&0xff)/255.0;
207 	col->g = ((from>>8 )&0xff)/255.0;
208 	col->b = ((from    )&0xff)/255.0;
209 	col->hsl = col->hsv = false;
210 	col->has_alpha = col->alpha!=0;
211 	if ( !col->has_alpha )
212 	    col->alpha = 1.0;
213     }
214     col->rgb = true;
215 }
216