1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_basegfx.hxx"
26 
27 #include <basegfx/numeric/ftools.hxx>
28 #include <basegfx/color/bcolor.hxx>
29 #include <basegfx/color/bcolortools.hxx>
30 
31 //////////////////////////////////////////////////////////////////////////////
32 
33 namespace basegfx { namespace tools
34 {
rgb2hsl(const BColor & rRGBColor)35     BColor rgb2hsl(const BColor& rRGBColor)
36     {
37         const double r=rRGBColor.getRed(), g=rRGBColor.getGreen(), b=rRGBColor.getBlue();
38         const double minVal = ::std::min( ::std::min( r, g ), b );
39         const double maxVal = ::std::max( ::std::max( r, g ), b );
40         const double d = maxVal - minVal;
41 
42         double h=0, s=0, l=0;
43 
44         l = (maxVal + minVal) / 2.0;
45 
46         if( ::basegfx::fTools::equalZero(d) )
47         {
48             s = h = 0; // hue undefined (achromatic case)
49         }
50         else
51         {
52             s = l > 0.5 ? d/(2.0-maxVal-minVal) :
53                 d/(maxVal + minVal);
54 
55             if( r == maxVal )
56                 h = (g - b)/d;
57             else if( g == maxVal )
58                 h = 2.0 + (b - r)/d;
59             else
60                 h = 4.0 + (r - g)/d;
61 
62             h *= 60.0;
63 
64             if( h < 0.0 )
65                 h += 360.0;
66         }
67 
68         return BColor(h,s,l);
69     }
70 
hsl2rgbHelper(double nValue1,double nValue2,double nHue)71     static inline double hsl2rgbHelper( double nValue1, double nValue2, double nHue )
72     {
73         // clamp hue to [0,360]
74         nHue = fmod( nHue, 360.0 );
75 
76         // cope with wrap-arounds
77         if( nHue < 0.0 )
78             nHue += 360.0;
79 
80         if( nHue < 60.0 )
81             return nValue1 + (nValue2 - nValue1)*nHue/60.0;
82         else if( nHue < 180.0 )
83             return nValue2;
84         else if( nHue < 240.0 )
85             return nValue1 + (nValue2 - nValue1)*(240.0 - nHue)/60.0;
86         else
87             return nValue1;
88     }
89 
hsl2rgb(const BColor & rHSLColor)90     BColor hsl2rgb(const BColor& rHSLColor)
91     {
92         const double h=rHSLColor.getRed(), s=rHSLColor.getGreen(), l=rHSLColor.getBlue();
93 
94         if( fTools::equalZero(s) )
95             return BColor(l, l, l ); // achromatic case
96 
97         const double nVal1( l <= 0.5 ? l*(1.0 + s) : l + s - l*s );
98         const double nVal2( 2.0*l - nVal1 );
99 
100         return BColor(
101             hsl2rgbHelper(nVal2,
102                           nVal1,
103                           h + 120.0),
104             hsl2rgbHelper(nVal2,
105                           nVal1,
106                           h),
107             hsl2rgbHelper(nVal2,
108                           nVal1,
109                           h - 120.0) );
110     }
111 
rgb2hsv(const BColor & rRGBColor)112     BColor rgb2hsv(const BColor& rRGBColor)
113     {
114         const double r=rRGBColor.getRed(), g=rRGBColor.getGreen(), b=rRGBColor.getBlue();
115         const double maxVal = std::max(std::max(r,g),b);
116         const double minVal = std::min(std::min(r,g),b);
117         const double delta = maxVal-minVal;
118 
119         double h=0, s=0, v=0;
120 
121         v = maxVal;
122         if( fTools::equalZero(v) )
123             s = 0;
124         else
125             s = delta / v;
126 
127         if( !fTools::equalZero(s) )
128         {
129             if( maxVal == r )
130             {
131                 h = (g - b) / delta;
132             }
133             else if( maxVal == g )
134             {
135                 h = 2.0 + (b - r) / delta;
136             }
137             else
138             {
139                 h = 4.0 + (r - g) / delta;
140             }
141 
142             h *= 60.0;
143 
144             if( h < 0 )
145                 h += 360;
146         }
147 
148         return BColor(h,s,v);
149     }
150 
hsv2rgb(const BColor & rHSVColor)151     BColor hsv2rgb(const BColor& rHSVColor)
152     {
153         double h=rHSVColor.getRed();
154         const double s=rHSVColor.getGreen(), v=rHSVColor.getBlue();
155 
156         if( fTools::equalZero(s) )
157         {
158             // achromatic case: no hue.
159             return BColor(v,v,v);
160         }
161         else
162         {
163             if( fTools::equal(h,360) )
164                 h = 0; // 360 degrees is equivalent to 0 degrees
165 
166             h /= 60.0;
167 			const sal_Int32 intval = static_cast< sal_Int32 >( h );
168             const double f = h - intval;
169             const double p = v*(1.0-s);
170             const double q = v*(1.0-(s*f));
171             const double t = v*(1.0-(s*(1.0-f)));
172 
173             /* which hue area? */
174             switch( intval )
175             {
176                 case 0:
177                     return BColor(v,t,p);
178 
179                 case 1:
180                     return BColor(q,v,p);
181 
182                 case 2:
183                     return BColor(p,v,t);
184 
185                 case 3:
186                     return BColor(p,q,v);
187 
188                 case 4:
189                     return BColor(t,p,v);
190 
191                 case 5:
192                     return BColor(v,p,q);
193 
194                 default:
195                     // hue overflow
196                     return BColor();
197             }
198         }
199     }
200 
rgb2yiq(const BColor & rRGBColor)201     BColor rgb2yiq(const BColor& rRGBColor)
202     {
203         // from Foley, van Dam, Computer Graphics
204         const double r=rRGBColor.getRed(), g=rRGBColor.getGreen(), b=rRGBColor.getBlue();
205         return BColor(
206             0.299*r + 0.587*g + 0.114*b,
207             0.596*r - 0.274*g - 0.322*b,
208             0.211*r - 0.522*g + 0.311*b);
209     }
210 
yiq2rgb(const BColor & rYIQColor)211     BColor yiq2rgb(const BColor& rYIQColor)
212     {
213         // from Foley, van Dam, Computer Graphics
214         const double y=rYIQColor.getRed(), i=rYIQColor.getGreen(), q=rYIQColor.getBlue();
215         return BColor(
216             y + 0.956*i + 0.623*q,
217             y - 0.272*i - 0.648*q,
218             y - 1.105*i + 1.705*q );
219     }
220 
ciexyz2rgb(const BColor & rXYZColor)221     BColor ciexyz2rgb( const BColor& rXYZColor )
222     {
223         // from Poynton color faq, and SMPTE RP 177-1993, Derivation
224         // of Basic Television Color Equations
225         const double x=rXYZColor.getRed(), y=rXYZColor.getGreen(), z=rXYZColor.getBlue();
226         return BColor(
227             3.240479*x - 1.53715*y  - 0.498535*z,
228             -0.969256*x + 1.875991*y + 0.041556*z,
229             0.055648*x - 0.204043*y + 1.057311*z );
230     }
231 
rgb2ciexyz(const BColor & rRGBColor)232     BColor rgb2ciexyz( const BColor& rRGBColor )
233     {
234         // from Poynton color faq, and SMPTE RP 177-1993, Derivation
235         // of Basic Television Color Equations
236         const double r=rRGBColor.getRed(), g=rRGBColor.getGreen(), b=rRGBColor.getBlue();
237         return BColor(
238             0.412453*r + 0.35758*g  + 0.180423*b,
239             0.212671*r + 0.71516*g  + 0.072169*b,
240             0.019334*r + 0.119193*g + 0.950227*b);
241     }
242 
rgb2ypbpr(const BColor & rRGBColor)243     BColor rgb2ypbpr(const BColor& rRGBColor)
244     {
245         const double r=rRGBColor.getRed(), g=rRGBColor.getGreen(), b=rRGBColor.getBlue();
246         return BColor(
247              0.299*r    + 0.587*g    + 0.114*b,
248             -0.168736*r - 0.331264*g + 0.5*b,
249              0.5*r      - 0.418688*g - 0.081312*b);
250     }
251 
ypbpr2rgb(const BColor & rYPbPrColor)252     BColor ypbpr2rgb(const BColor& rYPbPrColor)
253     {
254         const double y=rYPbPrColor.getRed(), pb=rYPbPrColor.getGreen(), pr=rYPbPrColor.getBlue();
255         return BColor(
256             1.*y +       0.*pb +    1.402*pr,
257             1.*y - 0.344136*pb - 0.714136*pr,
258             1.*y +    1.772*pb +       0.*pr);
259     }
260 
261 } } // end of namespace basegfx
262 
263 //////////////////////////////////////////////////////////////////////////////
264 // eof
265