xref: /trunk/main/slideshow/source/engine/color.cxx (revision 70f497fb)
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_slideshow.hxx"
26 
27 #include <hslcolor.hxx>
28 #include <rgbcolor.hxx>
29 
30 #include <basegfx/numeric/ftools.hxx>
31 
32 #include <cmath> // for fmod
33 #include <algorithm>
34 
35 
36 namespace slideshow
37 {
38     namespace internal
39     {
40         namespace
41         {
42             // helper functions
43             // ================
44 
getMagic(double nLuminance,double nSaturation)45             double getMagic( double nLuminance, double nSaturation )
46             {
47                 if( nLuminance <= 0.5 )
48                     return nLuminance*(1.0 + nSaturation);
49                 else
50                     return nLuminance + nSaturation - nLuminance*nSaturation;
51             }
52 
rgb2hsl(double nRed,double nGreen,double nBlue)53             HSLColor::HSLTriple rgb2hsl( double nRed, double nGreen, double nBlue )
54             {
55                 // r,g,b in [0,1], h in [0,360] and s,l in [0,1]
56                 HSLColor::HSLTriple aRes;
57 
58                 const double nMax( ::std::max(nRed,::std::max(nGreen, nBlue)) );
59                 const double nMin( ::std::min(nRed,::std::min(nGreen, nBlue)) );
60 
61                 const double nDelta( nMax - nMin );
62 
63                 aRes.mnLuminance = (nMax + nMin) / 2.0;
64 
65                 if( ::basegfx::fTools::equalZero( nDelta ) )
66                 {
67                     aRes.mnSaturation = 0.0;
68 
69                     // hue undefined (achromatic case)
70                     aRes.mnHue = 0.0;
71                 }
72                 else
73                 {
74                     aRes.mnSaturation = aRes.mnLuminance > 0.5 ?
75                         nDelta/(2.0-nMax-nMin) :
76                         nDelta/(nMax + nMin);
77 
78                     if( nRed == nMax )
79                         aRes.mnHue = (nGreen - nBlue)/nDelta;
80                     else if( nGreen == nMax )
81                         aRes.mnHue = 2.0 + (nBlue - nRed)/nDelta;
82                     else if( nBlue == nMax )
83                         aRes.mnHue = 4.0 + (nRed - nGreen)/nDelta;
84 
85                     aRes.mnHue *= 60.0;
86 
87                     if( aRes.mnHue < 0.0 )
88                         aRes.mnHue += 360.0;
89                 }
90 
91                 return aRes;
92             }
93 
hsl2rgbHelper(double nValue1,double nValue2,double nHue)94             double hsl2rgbHelper( double nValue1, double nValue2, double nHue )
95             {
96                 // clamp hue to [0,360]
97                 nHue = fmod( nHue, 360.0 );
98 
99                 // cope with wrap-arounds
100                 if( nHue < 0.0 )
101                     nHue += 360.0;
102 
103                 if( nHue < 60.0 )
104                     return nValue1 + (nValue2 - nValue1)*nHue/60.0;
105                 else if( nHue < 180.0 )
106                     return nValue2;
107                 else if( nHue < 240.0 )
108                     return nValue1 + (nValue2 - nValue1)*(240.0 - nHue)/60.0;
109                 else
110                     return nValue1;
111             }
112 
hsl2rgb(double nHue,double nSaturation,double nLuminance)113             RGBColor::RGBTriple hsl2rgb( double nHue, double nSaturation, double nLuminance )
114             {
115                 if( ::basegfx::fTools::equalZero( nSaturation ) )
116                     return RGBColor::RGBTriple(0.0, 0.0, nLuminance );
117 
118                 const double nVal1( getMagic(nLuminance, nSaturation) );
119                 const double nVal2( 2.0*nLuminance - nVal1 );
120 
121                 RGBColor::RGBTriple aRes;
122 
123                 aRes.mnRed = hsl2rgbHelper( nVal2,
124                                             nVal1,
125                                             nHue + 120.0 );
126                 aRes.mnGreen = hsl2rgbHelper( nVal2,
127                                               nVal1,
128                                               nHue );
129                 aRes.mnBlue = hsl2rgbHelper( nVal2,
130                                              nVal1,
131                                              nHue - 120.0 );
132 
133                 return aRes;
134             }
135 
136             /// Truncate range of value to [0,1]
truncateRangeStd(double nVal)137             double truncateRangeStd( double nVal )
138             {
139                 return ::std::max( 0.0,
140                                    ::std::min( 1.0,
141                                                nVal ) );
142             }
143 
144             /// Truncate range of value to [0,360]
truncateRangeHue(double nVal)145             double truncateRangeHue( double nVal )
146             {
147                 return ::std::max( 0.0,
148                                    ::std::min( 360.0,
149                                                nVal ) );
150             }
151 
152             /// convert RGB color to sal_uInt8, truncate range appropriately before
colorToInt(double nCol)153             sal_uInt8 colorToInt( double nCol )
154             {
155                 return static_cast< sal_uInt8 >(
156                     ::basegfx::fround( truncateRangeStd( nCol ) * 255.0 ) );
157             }
158         }
159 
160 
161 
162         // HSLColor
163         // ===============================================
164 
HSLTriple()165         HSLColor::HSLTriple::HSLTriple() :
166             mnHue(),
167             mnSaturation(),
168             mnLuminance()
169         {
170         }
171 
HSLTriple(double nHue,double nSaturation,double nLuminance)172         HSLColor::HSLTriple::HSLTriple( double nHue, double nSaturation, double nLuminance ) :
173             mnHue( nHue ),
174             mnSaturation( nSaturation ),
175             mnLuminance( nLuminance )
176         {
177         }
178 
HSLColor()179         HSLColor::HSLColor() :
180             maHSLTriple( 0.0, 0.0, 0.0 ),
181             mnMagicValue( getMagic( maHSLTriple.mnLuminance,
182                                     maHSLTriple.mnSaturation ) )
183         {
184         }
185 
HSLColor(::cppcanvas::Color::IntSRGBA nRGBColor)186         HSLColor::HSLColor( ::cppcanvas::Color::IntSRGBA nRGBColor ) :
187             maHSLTriple( rgb2hsl( ::cppcanvas::getRed( nRGBColor ) / 255.0,
188                                   ::cppcanvas::getGreen( nRGBColor ) / 255.0,
189                                   ::cppcanvas::getBlue( nRGBColor ) / 255.0 ) ),
190             mnMagicValue( getMagic( maHSLTriple.mnLuminance,
191                                     maHSLTriple.mnSaturation ) )
192         {
193         }
194 
HSLColor(double nHue,double nSaturation,double nLuminance)195         HSLColor::HSLColor( double nHue, double nSaturation, double nLuminance ) :
196             maHSLTriple( nHue, nSaturation, nLuminance ),
197             mnMagicValue( getMagic( maHSLTriple.mnLuminance,
198                                     maHSLTriple.mnSaturation ) )
199         {
200         }
201 
HSLColor(const RGBColor & rColor)202         HSLColor::HSLColor( const RGBColor& rColor ) :
203             maHSLTriple( rgb2hsl( truncateRangeStd( rColor.getRed() ),
204                                   truncateRangeStd( rColor.getGreen() ),
205                                   truncateRangeStd( rColor.getBlue() ) ) ),
206             mnMagicValue( getMagic( maHSLTriple.mnLuminance,
207                                     maHSLTriple.mnSaturation ) )
208         {
209         }
210 
getHue() const211         double HSLColor::getHue() const
212         {
213             return maHSLTriple.mnHue;
214         }
215 
getSaturation() const216         double HSLColor::getSaturation() const
217         {
218             return maHSLTriple.mnSaturation;
219         }
220 
getLuminance() const221         double HSLColor::getLuminance() const
222         {
223             return maHSLTriple.mnLuminance;
224         }
225 
getRed() const226         double HSLColor::getRed() const
227         {
228             if( ::basegfx::fTools::equalZero( getSaturation() ) )
229                 return getLuminance();
230 
231             return hsl2rgbHelper( 2.0*getLuminance() - mnMagicValue,
232                                   mnMagicValue,
233                                   getHue() + 120.0 );
234         }
235 
getGreen() const236         double HSLColor::getGreen() const
237         {
238             if( ::basegfx::fTools::equalZero( getSaturation() ) )
239                 return getLuminance();
240 
241             return hsl2rgbHelper( 2.0*getLuminance() - mnMagicValue,
242                                   mnMagicValue,
243                                   getHue() );
244         }
245 
getBlue() const246         double HSLColor::getBlue() const
247         {
248             if( ::basegfx::fTools::equalZero( getSaturation() ) )
249                 return getLuminance();
250 
251             return hsl2rgbHelper( 2.0*getLuminance() - mnMagicValue,
252                                   mnMagicValue,
253                                   getHue() - 120.0 );
254         }
255 
getRGBColor() const256         RGBColor HSLColor::getRGBColor() const
257         {
258             RGBColor::RGBTriple aColor( hsl2rgb( getHue(),
259                                                  getSaturation(),
260                                                  getLuminance() ) );
261             return RGBColor( aColor.mnRed, aColor.mnGreen, aColor.mnBlue );
262         }
263 
RGBColor(const RGBColor & rLHS)264         RGBColor::RGBColor(const RGBColor& rLHS)
265         {
266             maRGBTriple.mnRed = rLHS.getRed();
267             maRGBTriple.mnGreen = rLHS.getGreen();
268             maRGBTriple.mnBlue = rLHS.getBlue();
269         }
270 
operator =(const RGBColor & rLHS)271         RGBColor& RGBColor::operator=( const RGBColor& rLHS ){
272 
273             maRGBTriple.mnRed = rLHS.getRed();
274             maRGBTriple.mnGreen = rLHS.getGreen();
275             maRGBTriple.mnBlue = rLHS.getBlue();
276             return *this;
277         }
278 
operator +(const HSLColor & rLHS,const HSLColor & rRHS)279         HSLColor operator+( const HSLColor& rLHS, const HSLColor& rRHS )
280         {
281             return HSLColor( rLHS.getHue() + rRHS.getHue(),
282                              rLHS.getSaturation() + rRHS.getSaturation(),
283                              rLHS.getLuminance() + rRHS.getLuminance() );
284         }
285 
operator *(const HSLColor & rLHS,const HSLColor & rRHS)286         HSLColor operator*( const HSLColor& rLHS, const HSLColor& rRHS )
287         {
288             return HSLColor( rLHS.getHue() * rRHS.getHue(),
289                              rLHS.getSaturation() * rRHS.getSaturation(),
290                              rLHS.getLuminance() * rRHS.getLuminance() );
291         }
292 
operator *(double nFactor,const HSLColor & rRHS)293         HSLColor operator*( double nFactor, const HSLColor& rRHS )
294         {
295             return HSLColor( nFactor * rRHS.getHue(),
296                              nFactor * rRHS.getSaturation(),
297                              nFactor * rRHS.getLuminance() );
298         }
299 
interpolate(const HSLColor & rFrom,const HSLColor & rTo,double t,bool bCCW)300         HSLColor interpolate( const HSLColor& rFrom, const HSLColor& rTo, double t, bool bCCW )
301         {
302             const double nFromHue( rFrom.getHue() );
303             const double nToHue	 ( rTo.getHue()   );
304 
305             double nHue=0.0;
306 
307             if( nFromHue <= nToHue && !bCCW )
308             {
309                 // interpolate hue clockwise. That is, hue starts at
310                 // high values and ends at low ones. Therefore, we
311                 // must 'cross' the 360 degrees and start at low
312                 // values again (imagine the hues to lie on the
313                 // circle, where values above 360 degrees are mapped
314                 // back to [0,360)).
315                 nHue = (1.0-t)*(nFromHue + 360.0) + t*nToHue;
316             }
317             else if( nFromHue > nToHue && bCCW )
318             {
319                 // interpolate hue counter-clockwise. That is, hue
320                 // starts at high values and ends at low
321                 // ones. Therefore, we must 'cross' the 360 degrees
322                 // and start at low values again (imagine the hues to
323                 // lie on the circle, where values above 360 degrees
324                 // are mapped back to [0,360)).
325                 nHue = (1.0-t)*nFromHue + t*(nToHue + 360.0);
326             }
327             else
328             {
329                 // interpolate hue counter-clockwise. That is, hue
330                 // starts at low values and ends at high ones (imagine
331                 // the hue value as degrees on a circle, with
332                 // increasing values going counter-clockwise)
333                 nHue = (1.0-t)*nFromHue + t*nToHue;
334             }
335 
336             return HSLColor( nHue,
337                              (1.0-t)*rFrom.getSaturation() + t*rTo.getSaturation(),
338                              (1.0-t)*rFrom.getLuminance() + t*rTo.getLuminance() );
339         }
340 
341 
342 
343         // RGBColor
344         // ===============================================
345 
346 
RGBTriple()347         RGBColor::RGBTriple::RGBTriple() :
348             mnRed(),
349             mnGreen(),
350             mnBlue()
351         {
352         }
353 
RGBTriple(double nRed,double nGreen,double nBlue)354         RGBColor::RGBTriple::RGBTriple( double nRed, double nGreen, double nBlue ) :
355             mnRed( nRed ),
356             mnGreen( nGreen ),
357             mnBlue( nBlue )
358         {
359         }
360 
RGBColor()361         RGBColor::RGBColor() :
362             maRGBTriple( 0.0, 0.0, 0.0 )
363         {
364         }
365 
RGBColor(::cppcanvas::Color::IntSRGBA nRGBColor)366         RGBColor::RGBColor( ::cppcanvas::Color::IntSRGBA nRGBColor ) :
367             maRGBTriple( ::cppcanvas::getRed( nRGBColor ) / 255.0,
368                          ::cppcanvas::getGreen( nRGBColor ) / 255.0,
369                          ::cppcanvas::getBlue( nRGBColor ) / 255.0 )
370         {
371         }
372 
RGBColor(double nRed,double nGreen,double nBlue)373         RGBColor::RGBColor( double nRed, double nGreen, double nBlue ) :
374             maRGBTriple( nRed, nGreen, nBlue )
375         {
376         }
377 
RGBColor(const HSLColor & rColor)378         RGBColor::RGBColor( const HSLColor& rColor ) :
379             maRGBTriple( hsl2rgb( truncateRangeHue( rColor.getHue() ),
380                                   truncateRangeStd( rColor.getSaturation() ),
381                                   truncateRangeStd( rColor.getLuminance() ) ) )
382         {
383         }
384 
getHue() const385         double RGBColor::getHue() const
386         {
387             return rgb2hsl( getRed(),
388                             getGreen(),
389                             getBlue() ).mnHue;
390         }
391 
getSaturation() const392         double RGBColor::getSaturation() const
393         {
394             return rgb2hsl( getRed(),
395                             getGreen(),
396                             getBlue() ).mnSaturation;
397         }
398 
getLuminance() const399         double RGBColor::getLuminance() const
400         {
401             return rgb2hsl( getRed(),
402                             getGreen(),
403                             getBlue() ).mnLuminance;
404         }
405 
getRed() const406         double RGBColor::getRed() const
407         {
408             return maRGBTriple.mnRed;
409         }
410 
getGreen() const411         double RGBColor::getGreen() const
412         {
413             return maRGBTriple.mnGreen;
414         }
415 
getBlue() const416         double RGBColor::getBlue() const
417         {
418             return maRGBTriple.mnBlue;
419         }
420 
getHSLColor() const421         HSLColor RGBColor::getHSLColor() const
422         {
423             HSLColor::HSLTriple aColor( rgb2hsl( getRed(),
424                                                  getGreen(),
425                                                  getBlue() ) );
426             return HSLColor( aColor.mnHue, aColor.mnSaturation, aColor.mnLuminance );
427         }
428 
getIntegerColor() const429         ::cppcanvas::Color::IntSRGBA RGBColor::getIntegerColor() const
430         {
431             return ::cppcanvas::makeColor( colorToInt( getRed() ),
432                                            colorToInt( getGreen() ),
433                                            colorToInt( getBlue() ),
434                                            255 );
435         }
436 
operator +(const RGBColor & rLHS,const RGBColor & rRHS)437         RGBColor operator+( const RGBColor& rLHS, const RGBColor& rRHS )
438         {
439             return RGBColor( rLHS.getRed() + rRHS.getRed(),
440                              rLHS.getGreen() + rRHS.getGreen(),
441                              rLHS.getBlue() + rRHS.getBlue() );
442         }
443 
operator *(const RGBColor & rLHS,const RGBColor & rRHS)444         RGBColor operator*( const RGBColor& rLHS, const RGBColor& rRHS )
445         {
446             return RGBColor( rLHS.getRed() * rRHS.getRed(),
447                              rLHS.getGreen() * rRHS.getGreen(),
448                              rLHS.getBlue() * rRHS.getBlue() );
449         }
450 
operator *(double nFactor,const RGBColor & rRHS)451         RGBColor operator*( double nFactor, const RGBColor& rRHS )
452         {
453             return RGBColor( nFactor * rRHS.getRed(),
454                              nFactor * rRHS.getGreen(),
455                              nFactor * rRHS.getBlue() );
456         }
457 
interpolate(const RGBColor & rFrom,const RGBColor & rTo,double t)458         RGBColor interpolate( const RGBColor& rFrom, const RGBColor& rTo, double t )
459         {
460             return RGBColor( (1.0-t)*rFrom.getRed() + t*rTo.getRed(),
461                              (1.0-t)*rFrom.getGreen() + t*rTo.getGreen(),
462                              (1.0-t)*rFrom.getBlue() + t*rTo.getBlue() );
463         }
464     }
465 }
466