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