xref: /AOO42X/main/basegfx/source/color/bcolortools.cxx (revision 94c0c48b9b2b1aa10c89d9dab2feed9ef6974019)
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 // MARKER(update_precomp.py): autogen include statement, do not remove
23 #include "precompiled_basegfx.hxx"
24 
25 #include <basegfx/numeric/ftools.hxx>
26 #include <basegfx/color/bcolor.hxx>
27 #include <basegfx/color/bcolortools.hxx>
28 
29 namespace basegfx { namespace tools
30 {
rgb2hsl(const BColor & rRGBColor)31     BColor rgb2hsl(const BColor& rRGBColor)
32     {
33         const double r=rRGBColor.getRed(), g=rRGBColor.getGreen(), b=rRGBColor.getBlue();
34         const double minVal = ::std::min( ::std::min( r, g ), b );
35         const double maxVal = ::std::max( ::std::max( r, g ), b );
36         const double d = maxVal - minVal;
37 
38         double h=0, s=0, l=0;
39 
40         l = (maxVal + minVal) / 2.0;
41 
42         if( ::basegfx::fTools::equalZero(d) )
43         {
44             s = h = 0; // hue undefined (achromatic case)
45         }
46         else
47         {
48             s = l > 0.5 ? d/(2.0-maxVal-minVal) :
49                 d/(maxVal + minVal);
50 
51             if( r == maxVal )
52                 h = (g - b)/d;
53             else if( g == maxVal )
54                 h = 2.0 + (b - r)/d;
55             else
56                 h = 4.0 + (r - g)/d;
57 
58             h *= 60.0;
59 
60             if( h < 0.0 )
61                 h += 360.0;
62         }
63 
64         return BColor(h,s,l);
65     }
66 
hsl2rgbHelper(double nValue1,double nValue2,double nHue)67     static inline double hsl2rgbHelper( double nValue1, double nValue2, double nHue )
68     {
69         // clamp hue to [0,360]
70         nHue = fmod( nHue, 360.0 );
71 
72         // cope with wrap-arounds
73         if( nHue < 0.0 )
74             nHue += 360.0;
75 
76         if( nHue < 60.0 )
77             return nValue1 + (nValue2 - nValue1)*nHue/60.0;
78         else if( nHue < 180.0 )
79             return nValue2;
80         else if( nHue < 240.0 )
81             return nValue1 + (nValue2 - nValue1)*(240.0 - nHue)/60.0;
82         else
83             return nValue1;
84     }
85 
hsl2rgb(const BColor & rHSLColor)86     BColor hsl2rgb(const BColor& rHSLColor)
87     {
88         const double h=rHSLColor.getRed(), s=rHSLColor.getGreen(), l=rHSLColor.getBlue();
89 
90         if( fTools::equalZero(s) )
91             return BColor(l, l, l ); // achromatic case
92 
93         const double nVal1( l <= 0.5 ? l*(1.0 + s) : l + s - l*s );
94         const double nVal2( 2.0*l - nVal1 );
95 
96         return BColor(
97             hsl2rgbHelper(nVal2,
98                           nVal1,
99                           h + 120.0),
100             hsl2rgbHelper(nVal2,
101                           nVal1,
102                           h),
103             hsl2rgbHelper(nVal2,
104                           nVal1,
105                           h - 120.0) );
106     }
107 
rgb2hsv(const BColor & rRGBColor)108     BColor rgb2hsv(const BColor& rRGBColor)
109     {
110         const double r=rRGBColor.getRed(), g=rRGBColor.getGreen(), b=rRGBColor.getBlue();
111         const double maxVal = std::max(std::max(r,g),b);
112         const double minVal = std::min(std::min(r,g),b);
113         const double delta = maxVal-minVal;
114 
115         double h=0, s=0, v=0;
116 
117         v = maxVal;
118         if( fTools::equalZero(v) )
119             s = 0;
120         else
121             s = delta / v;
122 
123         if( !fTools::equalZero(s) )
124         {
125             if( maxVal == r )
126             {
127                 h = (g - b) / delta;
128             }
129             else if( maxVal == g )
130             {
131                 h = 2.0 + (b - r) / delta;
132             }
133             else
134             {
135                 h = 4.0 + (r - g) / delta;
136             }
137 
138             h *= 60.0;
139 
140             if( h < 0 )
141                 h += 360;
142         }
143 
144         return BColor(h,s,v);
145     }
146 
hsv2rgb(const BColor & rHSVColor)147     BColor hsv2rgb(const BColor& rHSVColor)
148     {
149         double h=rHSVColor.getRed();
150         const double s=rHSVColor.getGreen(), v=rHSVColor.getBlue();
151 
152         if( fTools::equalZero(s) )
153         {
154             // achromatic case: no hue.
155             return BColor(v,v,v);
156         }
157         else
158         {
159             if( fTools::equal(h,360) )
160                 h = 0; // 360 degrees is equivalent to 0 degrees
161 
162             h /= 60.0;
163             const sal_Int32 intval = static_cast< sal_Int32 >( h );
164             const double f = h - intval;
165             const double p = v*(1.0-s);
166             const double q = v*(1.0-(s*f));
167             const double t = v*(1.0-(s*(1.0-f)));
168 
169             /* which hue area? */
170             switch( intval )
171             {
172                 case 0:
173                     return BColor(v,t,p);
174 
175                 case 1:
176                     return BColor(q,v,p);
177 
178                 case 2:
179                     return BColor(p,v,t);
180 
181                 case 3:
182                     return BColor(p,q,v);
183 
184                 case 4:
185                     return BColor(t,p,v);
186 
187                 case 5:
188                     return BColor(v,p,q);
189 
190                 default:
191                     // hue overflow
192                     return BColor();
193             }
194         }
195     }
196 
rgb2yiq(const BColor & rRGBColor)197     BColor rgb2yiq(const BColor& rRGBColor)
198     {
199         // from Foley, van Dam, Computer Graphics
200         const double r=rRGBColor.getRed(), g=rRGBColor.getGreen(), b=rRGBColor.getBlue();
201         return BColor(
202             0.299*r + 0.587*g + 0.114*b,
203             0.596*r - 0.274*g - 0.322*b,
204             0.211*r - 0.522*g + 0.311*b);
205     }
206 
yiq2rgb(const BColor & rYIQColor)207     BColor yiq2rgb(const BColor& rYIQColor)
208     {
209         // from Foley, van Dam, Computer Graphics
210         const double y=rYIQColor.getRed(), i=rYIQColor.getGreen(), q=rYIQColor.getBlue();
211         return BColor(
212             y + 0.956*i + 0.623*q,
213             y - 0.272*i - 0.648*q,
214             y - 1.105*i + 1.705*q );
215     }
216 
ciexyz2rgb(const BColor & rXYZColor)217     BColor ciexyz2rgb( const BColor& rXYZColor )
218     {
219         // from Poynton color faq, and SMPTE RP 177-1993, Derivation
220         // of Basic Television Color Equations
221         const double x=rXYZColor.getRed(), y=rXYZColor.getGreen(), z=rXYZColor.getBlue();
222         return BColor(
223             3.240479*x - 1.53715*y  - 0.498535*z,
224             -0.969256*x + 1.875991*y + 0.041556*z,
225             0.055648*x - 0.204043*y + 1.057311*z );
226     }
227 
rgb2ciexyz(const BColor & rRGBColor)228     BColor rgb2ciexyz( const BColor& rRGBColor )
229     {
230         // from Poynton color faq, and SMPTE RP 177-1993, Derivation
231         // of Basic Television Color Equations
232         const double r=rRGBColor.getRed(), g=rRGBColor.getGreen(), b=rRGBColor.getBlue();
233         return BColor(
234             0.412453*r + 0.35758*g  + 0.180423*b,
235             0.212671*r + 0.71516*g  + 0.072169*b,
236             0.019334*r + 0.119193*g + 0.950227*b);
237     }
238 
rgb2ypbpr(const BColor & rRGBColor)239     BColor rgb2ypbpr(const BColor& rRGBColor)
240     {
241         const double r=rRGBColor.getRed(), g=rRGBColor.getGreen(), b=rRGBColor.getBlue();
242         return BColor(
243              0.299*r    + 0.587*g    + 0.114*b,
244             -0.168736*r - 0.331264*g + 0.5*b,
245              0.5*r      - 0.418688*g - 0.081312*b);
246     }
247 
ypbpr2rgb(const BColor & rYPbPrColor)248     BColor ypbpr2rgb(const BColor& rYPbPrColor)
249     {
250         const double y=rYPbPrColor.getRed(), pb=rYPbPrColor.getGreen(), pr=rYPbPrColor.getBlue();
251         return BColor(
252             1.*y +       0.*pb +    1.402*pr,
253             1.*y - 0.344136*pb - 0.714136*pr,
254             1.*y +    1.772*pb +       0.*pr);
255     }
256 
257 } } // end of namespace basegfx
258 
259 /* vim: set noet sw=4 ts=4: */
260