xref: /AOO41X/main/slideshow/source/engine/color.cxx (revision 1ecadb572e7010ff3b3382ad9bf179dbc6efadbb)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_slideshow.hxx"
30 
31 #include <hslcolor.hxx>
32 #include <rgbcolor.hxx>
33 
34 #include <basegfx/numeric/ftools.hxx>
35 
36 #include <cmath> // for fmod
37 #include <algorithm>
38 
39 
40 namespace slideshow
41 {
42     namespace internal
43     {
44         namespace
45         {
46             // helper functions
47             // ================
48 
49             double getMagic( double nLuminance, double nSaturation )
50             {
51                 if( nLuminance <= 0.5 )
52                     return nLuminance*(1.0 + nSaturation);
53                 else
54                     return nLuminance + nSaturation - nLuminance*nSaturation;
55             }
56 
57             HSLColor::HSLTriple rgb2hsl( double nRed, double nGreen, double nBlue )
58             {
59                 // r,g,b in [0,1], h in [0,360] and s,l in [0,1]
60                 HSLColor::HSLTriple aRes;
61 
62                 const double nMax( ::std::max(nRed,::std::max(nGreen, nBlue)) );
63                 const double nMin( ::std::min(nRed,::std::min(nGreen, nBlue)) );
64 
65                 const double nDelta( nMax - nMin );
66 
67                 aRes.mnLuminance = (nMax + nMin) / 2.0;
68 
69                 if( ::basegfx::fTools::equalZero( nDelta ) )
70                 {
71                     aRes.mnSaturation = 0.0;
72 
73                     // hue undefined (achromatic case)
74                     aRes.mnHue = 0.0;
75                 }
76                 else
77                 {
78                     aRes.mnSaturation = aRes.mnLuminance > 0.5 ?
79                         nDelta/(2.0-nMax-nMin) :
80                         nDelta/(nMax + nMin);
81 
82                     if( nRed == nMax )
83                         aRes.mnHue = (nGreen - nBlue)/nDelta;
84                     else if( nGreen == nMax )
85                         aRes.mnHue = 2.0 + (nBlue - nRed)/nDelta;
86                     else if( nBlue == nMax )
87                         aRes.mnHue = 4.0 + (nRed - nGreen)/nDelta;
88 
89                     aRes.mnHue *= 60.0;
90 
91                     if( aRes.mnHue < 0.0 )
92                         aRes.mnHue += 360.0;
93                 }
94 
95                 return aRes;
96             }
97 
98             double hsl2rgbHelper( double nValue1, double nValue2, double nHue )
99             {
100                 // clamp hue to [0,360]
101                 nHue = fmod( nHue, 360.0 );
102 
103                 // cope with wrap-arounds
104                 if( nHue < 0.0 )
105                     nHue += 360.0;
106 
107                 if( nHue < 60.0 )
108                     return nValue1 + (nValue2 - nValue1)*nHue/60.0;
109                 else if( nHue < 180.0 )
110                     return nValue2;
111                 else if( nHue < 240.0 )
112                     return nValue1 + (nValue2 - nValue1)*(240.0 - nHue)/60.0;
113                 else
114                     return nValue1;
115             }
116 
117             RGBColor::RGBTriple hsl2rgb( double nHue, double nSaturation, double nLuminance )
118             {
119                 if( ::basegfx::fTools::equalZero( nSaturation ) )
120                     return RGBColor::RGBTriple(0.0, 0.0, nLuminance );
121 
122                 const double nVal1( getMagic(nLuminance, nSaturation) );
123                 const double nVal2( 2.0*nLuminance - nVal1 );
124 
125                 RGBColor::RGBTriple aRes;
126 
127                 aRes.mnRed = hsl2rgbHelper( nVal2,
128                                             nVal1,
129                                             nHue + 120.0 );
130                 aRes.mnGreen = hsl2rgbHelper( nVal2,
131                                               nVal1,
132                                               nHue );
133                 aRes.mnBlue = hsl2rgbHelper( nVal2,
134                                              nVal1,
135                                              nHue - 120.0 );
136 
137                 return aRes;
138             }
139 
140             /// Truncate range of value to [0,1]
141             double truncateRangeStd( double nVal )
142             {
143                 return ::std::max( 0.0,
144                                    ::std::min( 1.0,
145                                                nVal ) );
146             }
147 
148             /// Truncate range of value to [0,360]
149             double truncateRangeHue( double nVal )
150             {
151                 return ::std::max( 0.0,
152                                    ::std::min( 360.0,
153                                                nVal ) );
154             }
155 
156             /// convert RGB color to sal_uInt8, truncate range appropriately before
157             sal_uInt8 colorToInt( double nCol )
158             {
159                 return static_cast< sal_uInt8 >(
160                     ::basegfx::fround( truncateRangeStd( nCol ) * 255.0 ) );
161             }
162         }
163 
164 
165 
166         // HSLColor
167         // ===============================================
168 
169         HSLColor::HSLTriple::HSLTriple() :
170             mnHue(),
171             mnSaturation(),
172             mnLuminance()
173         {
174         }
175 
176         HSLColor::HSLTriple::HSLTriple( double nHue, double nSaturation, double nLuminance ) :
177             mnHue( nHue ),
178             mnSaturation( nSaturation ),
179             mnLuminance( nLuminance )
180         {
181         }
182 
183         HSLColor::HSLColor() :
184             maHSLTriple( 0.0, 0.0, 0.0 ),
185             mnMagicValue( getMagic( maHSLTriple.mnLuminance,
186                                     maHSLTriple.mnSaturation ) )
187         {
188         }
189 
190         HSLColor::HSLColor( ::cppcanvas::Color::IntSRGBA nRGBColor ) :
191             maHSLTriple( rgb2hsl( ::cppcanvas::getRed( nRGBColor ) / 255.0,
192                                   ::cppcanvas::getGreen( nRGBColor ) / 255.0,
193                                   ::cppcanvas::getBlue( nRGBColor ) / 255.0 ) ),
194             mnMagicValue( getMagic( maHSLTriple.mnLuminance,
195                                     maHSLTriple.mnSaturation ) )
196         {
197         }
198 
199         HSLColor::HSLColor( double nHue, double nSaturation, double nLuminance ) :
200             maHSLTriple( nHue, nSaturation, nLuminance ),
201             mnMagicValue( getMagic( maHSLTriple.mnLuminance,
202                                     maHSLTriple.mnSaturation ) )
203         {
204         }
205 
206         HSLColor::HSLColor( const RGBColor& rColor ) :
207             maHSLTriple( rgb2hsl( truncateRangeStd( rColor.getRed() ),
208                                   truncateRangeStd( rColor.getGreen() ),
209                                   truncateRangeStd( rColor.getBlue() ) ) ),
210             mnMagicValue( getMagic( maHSLTriple.mnLuminance,
211                                     maHSLTriple.mnSaturation ) )
212         {
213         }
214 
215         double HSLColor::getHue() const
216         {
217             return maHSLTriple.mnHue;
218         }
219 
220         double HSLColor::getSaturation() const
221         {
222             return maHSLTriple.mnSaturation;
223         }
224 
225         double HSLColor::getLuminance() const
226         {
227             return maHSLTriple.mnLuminance;
228         }
229 
230         double HSLColor::getRed() const
231         {
232             if( ::basegfx::fTools::equalZero( getSaturation() ) )
233                 return getLuminance();
234 
235             return hsl2rgbHelper( 2.0*getLuminance() - mnMagicValue,
236                                   mnMagicValue,
237                                   getHue() + 120.0 );
238         }
239 
240         double HSLColor::getGreen() const
241         {
242             if( ::basegfx::fTools::equalZero( getSaturation() ) )
243                 return getLuminance();
244 
245             return hsl2rgbHelper( 2.0*getLuminance() - mnMagicValue,
246                                   mnMagicValue,
247                                   getHue() );
248         }
249 
250         double HSLColor::getBlue() const
251         {
252             if( ::basegfx::fTools::equalZero( getSaturation() ) )
253                 return getLuminance();
254 
255             return hsl2rgbHelper( 2.0*getLuminance() - mnMagicValue,
256                                   mnMagicValue,
257                                   getHue() - 120.0 );
258         }
259 
260         RGBColor HSLColor::getRGBColor() const
261         {
262             RGBColor::RGBTriple aColor( hsl2rgb( getHue(),
263                                                  getSaturation(),
264                                                  getLuminance() ) );
265             return RGBColor( aColor.mnRed, aColor.mnGreen, aColor.mnBlue );
266         }
267 
268         RGBColor::RGBColor(const RGBColor& rLHS)
269         {
270             maRGBTriple.mnRed = rLHS.getRed();
271             maRGBTriple.mnGreen = rLHS.getGreen();
272             maRGBTriple.mnBlue = rLHS.getBlue();
273         }
274 
275         RGBColor& RGBColor::operator=( const RGBColor& rLHS ){
276 
277             maRGBTriple.mnRed = rLHS.getRed();
278             maRGBTriple.mnGreen = rLHS.getGreen();
279             maRGBTriple.mnBlue = rLHS.getBlue();
280             return *this;
281         }
282 
283         HSLColor operator+( const HSLColor& rLHS, const HSLColor& rRHS )
284         {
285             return HSLColor( rLHS.getHue() + rRHS.getHue(),
286                              rLHS.getSaturation() + rRHS.getSaturation(),
287                              rLHS.getLuminance() + rRHS.getLuminance() );
288         }
289 
290         HSLColor operator*( const HSLColor& rLHS, const HSLColor& rRHS )
291         {
292             return HSLColor( rLHS.getHue() * rRHS.getHue(),
293                              rLHS.getSaturation() * rRHS.getSaturation(),
294                              rLHS.getLuminance() * rRHS.getLuminance() );
295         }
296 
297         HSLColor operator*( double nFactor, const HSLColor& rRHS )
298         {
299             return HSLColor( nFactor * rRHS.getHue(),
300                              nFactor * rRHS.getSaturation(),
301                              nFactor * rRHS.getLuminance() );
302         }
303 
304         HSLColor interpolate( const HSLColor& rFrom, const HSLColor& rTo, double t, bool bCCW )
305         {
306             const double nFromHue( rFrom.getHue() );
307             const double nToHue	 ( rTo.getHue()   );
308 
309             double nHue=0.0;
310 
311             if( nFromHue <= nToHue && !bCCW )
312             {
313                 // interpolate hue clockwise. That is, hue starts at
314                 // high values and ends at low ones. Therefore, we
315                 // must 'cross' the 360 degrees and start at low
316                 // values again (imagine the hues to lie on the
317                 // circle, where values above 360 degrees are mapped
318                 // back to [0,360)).
319                 nHue = (1.0-t)*(nFromHue + 360.0) + t*nToHue;
320             }
321             else if( nFromHue > nToHue && bCCW )
322             {
323                 // interpolate hue counter-clockwise. That is, hue
324                 // starts at high values and ends at low
325                 // ones. Therefore, we must 'cross' the 360 degrees
326                 // and start at low values again (imagine the hues to
327                 // lie on the circle, where values above 360 degrees
328                 // are mapped back to [0,360)).
329                 nHue = (1.0-t)*nFromHue + t*(nToHue + 360.0);
330             }
331             else
332             {
333                 // interpolate hue counter-clockwise. That is, hue
334                 // starts at low values and ends at high ones (imagine
335                 // the hue value as degrees on a circle, with
336                 // increasing values going counter-clockwise)
337                 nHue = (1.0-t)*nFromHue + t*nToHue;
338             }
339 
340             return HSLColor( nHue,
341                              (1.0-t)*rFrom.getSaturation() + t*rTo.getSaturation(),
342                              (1.0-t)*rFrom.getLuminance() + t*rTo.getLuminance() );
343         }
344 
345 
346 
347         // RGBColor
348         // ===============================================
349 
350 
351         RGBColor::RGBTriple::RGBTriple() :
352             mnRed(),
353             mnGreen(),
354             mnBlue()
355         {
356         }
357 
358         RGBColor::RGBTriple::RGBTriple( double nRed, double nGreen, double nBlue ) :
359             mnRed( nRed ),
360             mnGreen( nGreen ),
361             mnBlue( nBlue )
362         {
363         }
364 
365         RGBColor::RGBColor() :
366             maRGBTriple( 0.0, 0.0, 0.0 )
367         {
368         }
369 
370         RGBColor::RGBColor( ::cppcanvas::Color::IntSRGBA nRGBColor ) :
371             maRGBTriple( ::cppcanvas::getRed( nRGBColor ) / 255.0,
372                          ::cppcanvas::getGreen( nRGBColor ) / 255.0,
373                          ::cppcanvas::getBlue( nRGBColor ) / 255.0 )
374         {
375         }
376 
377         RGBColor::RGBColor( double nRed, double nGreen, double nBlue ) :
378             maRGBTriple( nRed, nGreen, nBlue )
379         {
380         }
381 
382         RGBColor::RGBColor( const HSLColor& rColor ) :
383             maRGBTriple( hsl2rgb( truncateRangeHue( rColor.getHue() ),
384                                   truncateRangeStd( rColor.getSaturation() ),
385                                   truncateRangeStd( rColor.getLuminance() ) ) )
386         {
387         }
388 
389         double RGBColor::getHue() const
390         {
391             return rgb2hsl( getRed(),
392                             getGreen(),
393                             getBlue() ).mnHue;
394         }
395 
396         double RGBColor::getSaturation() const
397         {
398             return rgb2hsl( getRed(),
399                             getGreen(),
400                             getBlue() ).mnSaturation;
401         }
402 
403         double RGBColor::getLuminance() const
404         {
405             return rgb2hsl( getRed(),
406                             getGreen(),
407                             getBlue() ).mnLuminance;
408         }
409 
410         double RGBColor::getRed() const
411         {
412             return maRGBTriple.mnRed;
413         }
414 
415         double RGBColor::getGreen() const
416         {
417             return maRGBTriple.mnGreen;
418         }
419 
420         double RGBColor::getBlue() const
421         {
422             return maRGBTriple.mnBlue;
423         }
424 
425         HSLColor RGBColor::getHSLColor() const
426         {
427             HSLColor::HSLTriple aColor( rgb2hsl( getRed(),
428                                                  getGreen(),
429                                                  getBlue() ) );
430             return HSLColor( aColor.mnHue, aColor.mnSaturation, aColor.mnLuminance );
431         }
432 
433         ::cppcanvas::Color::IntSRGBA RGBColor::getIntegerColor() const
434         {
435             return ::cppcanvas::makeColor( colorToInt( getRed() ),
436                                            colorToInt( getGreen() ),
437                                            colorToInt( getBlue() ),
438                                            255 );
439         }
440 
441         RGBColor operator+( const RGBColor& rLHS, const RGBColor& rRHS )
442         {
443             return RGBColor( rLHS.getRed() + rRHS.getRed(),
444                              rLHS.getGreen() + rRHS.getGreen(),
445                              rLHS.getBlue() + rRHS.getBlue() );
446         }
447 
448         RGBColor operator*( const RGBColor& rLHS, const RGBColor& rRHS )
449         {
450             return RGBColor( rLHS.getRed() * rRHS.getRed(),
451                              rLHS.getGreen() * rRHS.getGreen(),
452                              rLHS.getBlue() * rRHS.getBlue() );
453         }
454 
455         RGBColor operator*( double nFactor, const RGBColor& rRHS )
456         {
457             return RGBColor( nFactor * rRHS.getRed(),
458                              nFactor * rRHS.getGreen(),
459                              nFactor * rRHS.getBlue() );
460         }
461 
462         RGBColor interpolate( const RGBColor& rFrom, const RGBColor& rTo, double t )
463         {
464             return RGBColor( (1.0-t)*rFrom.getRed() + t*rTo.getRed(),
465                              (1.0-t)*rFrom.getGreen() + t*rTo.getGreen(),
466                              (1.0-t)*rFrom.getBlue() + t*rTo.getBlue() );
467         }
468     }
469 }
470