1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: color.cxx,v $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_slideshow.hxx"
34 #include <hslcolor.hxx>
35 #include <rgbcolor.hxx>
37 #include <basegfx/numeric/ftools.hxx>
39 #include <cmath> // for fmod
52 double getMagic( double nLuminance
, double nSaturation
)
54 if( nLuminance
<= 0.5 )
55 return nLuminance
*(1.0 + nSaturation
);
57 return nLuminance
+ nSaturation
- nLuminance
*nSaturation
;
60 HSLColor::HSLTriple
rgb2hsl( double nRed
, double nGreen
, double nBlue
)
62 // r,g,b in [0,1], h in [0,360] and s,l in [0,1]
63 HSLColor::HSLTriple aRes
;
65 const double nMax( ::std::max(nRed
,::std::max(nGreen
, nBlue
)) );
66 const double nMin( ::std::min(nRed
,::std::min(nGreen
, nBlue
)) );
68 const double nDelta( nMax
- nMin
);
70 aRes
.mnLuminance
= (nMax
+ nMin
) / 2.0;
72 if( ::basegfx::fTools::equalZero( nDelta
) )
74 aRes
.mnSaturation
= 0.0;
76 // hue undefined (achromatic case)
81 aRes
.mnSaturation
= aRes
.mnLuminance
> 0.5 ?
82 nDelta
/(2.0-nMax
-nMin
) :
86 aRes
.mnHue
= (nGreen
- nBlue
)/nDelta
;
87 else if( nGreen
== nMax
)
88 aRes
.mnHue
= 2.0 + (nBlue
- nRed
)/nDelta
;
89 else if( nBlue
== nMax
)
90 aRes
.mnHue
= 4.0 + (nRed
- nGreen
)/nDelta
;
94 if( aRes
.mnHue
< 0.0 )
101 double hsl2rgbHelper( double nValue1
, double nValue2
, double nHue
)
103 // clamp hue to [0,360]
104 nHue
= fmod( nHue
, 360.0 );
106 // cope with wrap-arounds
111 return nValue1
+ (nValue2
- nValue1
)*nHue
/60.0;
112 else if( nHue
< 180.0 )
114 else if( nHue
< 240.0 )
115 return nValue1
+ (nValue2
- nValue1
)*(240.0 - nHue
)/60.0;
120 RGBColor::RGBTriple
hsl2rgb( double nHue
, double nSaturation
, double nLuminance
)
122 if( ::basegfx::fTools::equalZero( nSaturation
) )
123 return RGBColor::RGBTriple(0.0, 0.0, nLuminance
);
125 const double nVal1( getMagic(nLuminance
, nSaturation
) );
126 const double nVal2( 2.0*nLuminance
- nVal1
);
128 RGBColor::RGBTriple aRes
;
130 aRes
.mnRed
= hsl2rgbHelper( nVal2
,
133 aRes
.mnGreen
= hsl2rgbHelper( nVal2
,
136 aRes
.mnBlue
= hsl2rgbHelper( nVal2
,
143 /// Truncate range of value to [0,1]
144 double truncateRangeStd( double nVal
)
146 return ::std::max( 0.0,
151 /// Truncate range of value to [0,360]
152 double truncateRangeHue( double nVal
)
154 return ::std::max( 0.0,
159 /// convert RGB color to sal_uInt8, truncate range appropriately before
160 sal_uInt8
colorToInt( double nCol
)
162 return static_cast< sal_uInt8
>(
163 ::basegfx::fround( truncateRangeStd( nCol
) * 255.0 ) );
170 // ===============================================
172 HSLColor::HSLTriple::HSLTriple() :
179 HSLColor::HSLTriple::HSLTriple( double nHue
, double nSaturation
, double nLuminance
) :
181 mnSaturation( nSaturation
),
182 mnLuminance( nLuminance
)
186 HSLColor::HSLColor() :
187 maHSLTriple( 0.0, 0.0, 0.0 ),
188 mnMagicValue( getMagic( maHSLTriple
.mnLuminance
,
189 maHSLTriple
.mnSaturation
) )
193 HSLColor::HSLColor( ::cppcanvas::Color::IntSRGBA nRGBColor
) :
194 maHSLTriple( rgb2hsl( ::cppcanvas::getRed( nRGBColor
) / 255.0,
195 ::cppcanvas::getGreen( nRGBColor
) / 255.0,
196 ::cppcanvas::getBlue( nRGBColor
) / 255.0 ) ),
197 mnMagicValue( getMagic( maHSLTriple
.mnLuminance
,
198 maHSLTriple
.mnSaturation
) )
202 HSLColor::HSLColor( double nHue
, double nSaturation
, double nLuminance
) :
203 maHSLTriple( nHue
, nSaturation
, nLuminance
),
204 mnMagicValue( getMagic( maHSLTriple
.mnLuminance
,
205 maHSLTriple
.mnSaturation
) )
209 HSLColor::HSLColor( const RGBColor
& rColor
) :
210 maHSLTriple( rgb2hsl( truncateRangeStd( rColor
.getRed() ),
211 truncateRangeStd( rColor
.getGreen() ),
212 truncateRangeStd( rColor
.getBlue() ) ) ),
213 mnMagicValue( getMagic( maHSLTriple
.mnLuminance
,
214 maHSLTriple
.mnSaturation
) )
218 double HSLColor::getHue() const
220 return maHSLTriple
.mnHue
;
223 double HSLColor::getSaturation() const
225 return maHSLTriple
.mnSaturation
;
228 double HSLColor::getLuminance() const
230 return maHSLTriple
.mnLuminance
;
233 double HSLColor::getRed() const
235 if( ::basegfx::fTools::equalZero( getSaturation() ) )
236 return getLuminance();
238 return hsl2rgbHelper( 2.0*getLuminance() - mnMagicValue
,
243 double HSLColor::getGreen() const
245 if( ::basegfx::fTools::equalZero( getSaturation() ) )
246 return getLuminance();
248 return hsl2rgbHelper( 2.0*getLuminance() - mnMagicValue
,
253 double HSLColor::getBlue() const
255 if( ::basegfx::fTools::equalZero( getSaturation() ) )
256 return getLuminance();
258 return hsl2rgbHelper( 2.0*getLuminance() - mnMagicValue
,
263 RGBColor
HSLColor::getRGBColor() const
265 RGBColor::RGBTriple
aColor( hsl2rgb( getHue(),
268 return RGBColor( aColor
.mnRed
, aColor
.mnGreen
, aColor
.mnBlue
);
271 HSLColor
operator+( const HSLColor
& rLHS
, const HSLColor
& rRHS
)
273 return HSLColor( rLHS
.getHue() + rRHS
.getHue(),
274 rLHS
.getSaturation() + rRHS
.getSaturation(),
275 rLHS
.getLuminance() + rRHS
.getLuminance() );
278 HSLColor
operator*( const HSLColor
& rLHS
, const HSLColor
& rRHS
)
280 return HSLColor( rLHS
.getHue() * rRHS
.getHue(),
281 rLHS
.getSaturation() * rRHS
.getSaturation(),
282 rLHS
.getLuminance() * rRHS
.getLuminance() );
285 HSLColor
operator*( double nFactor
, const HSLColor
& rRHS
)
287 return HSLColor( nFactor
* rRHS
.getHue(),
288 nFactor
* rRHS
.getSaturation(),
289 nFactor
* rRHS
.getLuminance() );
292 HSLColor
interpolate( const HSLColor
& rFrom
, const HSLColor
& rTo
, double t
, bool bCCW
)
294 const double nFromHue( rFrom
.getHue() );
295 const double nToHue ( rTo
.getHue() );
299 if( nFromHue
<= nToHue
&& !bCCW
)
301 // interpolate hue clockwise. That is, hue starts at
302 // high values and ends at low ones. Therefore, we
303 // must 'cross' the 360 degrees and start at low
304 // values again (imagine the hues to lie on the
305 // circle, where values above 360 degrees are mapped
307 nHue
= (1.0-t
)*(nFromHue
+ 360.0) + t
*nToHue
;
309 else if( nFromHue
> nToHue
&& bCCW
)
311 // interpolate hue counter-clockwise. That is, hue
312 // starts at high values and ends at low
313 // ones. Therefore, we must 'cross' the 360 degrees
314 // and start at low values again (imagine the hues to
315 // lie on the circle, where values above 360 degrees
316 // are mapped back to [0,360)).
317 nHue
= (1.0-t
)*nFromHue
+ t
*(nToHue
+ 360.0);
321 // interpolate hue counter-clockwise. That is, hue
322 // starts at low values and ends at high ones (imagine
323 // the hue value as degrees on a circle, with
324 // increasing values going counter-clockwise)
325 nHue
= (1.0-t
)*nFromHue
+ t
*nToHue
;
328 return HSLColor( nHue
,
329 (1.0-t
)*rFrom
.getSaturation() + t
*rTo
.getSaturation(),
330 (1.0-t
)*rFrom
.getLuminance() + t
*rTo
.getLuminance() );
336 // ===============================================
339 RGBColor::RGBTriple::RGBTriple() :
346 RGBColor::RGBTriple::RGBTriple( double nRed
, double nGreen
, double nBlue
) :
353 RGBColor::RGBColor() :
354 maRGBTriple( 0.0, 0.0, 0.0 )
358 RGBColor::RGBColor( ::cppcanvas::Color::IntSRGBA nRGBColor
) :
359 maRGBTriple( ::cppcanvas::getRed( nRGBColor
) / 255.0,
360 ::cppcanvas::getGreen( nRGBColor
) / 255.0,
361 ::cppcanvas::getBlue( nRGBColor
) / 255.0 )
365 RGBColor::RGBColor( double nRed
, double nGreen
, double nBlue
) :
366 maRGBTriple( nRed
, nGreen
, nBlue
)
370 RGBColor::RGBColor( const HSLColor
& rColor
) :
371 maRGBTriple( hsl2rgb( truncateRangeHue( rColor
.getHue() ),
372 truncateRangeStd( rColor
.getSaturation() ),
373 truncateRangeStd( rColor
.getLuminance() ) ) )
377 double RGBColor::getHue() const
379 return rgb2hsl( getRed(),
384 double RGBColor::getSaturation() const
386 return rgb2hsl( getRed(),
388 getBlue() ).mnSaturation
;
391 double RGBColor::getLuminance() const
393 return rgb2hsl( getRed(),
395 getBlue() ).mnLuminance
;
398 double RGBColor::getRed() const
400 return maRGBTriple
.mnRed
;
403 double RGBColor::getGreen() const
405 return maRGBTriple
.mnGreen
;
408 double RGBColor::getBlue() const
410 return maRGBTriple
.mnBlue
;
413 HSLColor
RGBColor::getHSLColor() const
415 HSLColor::HSLTriple
aColor( rgb2hsl( getRed(),
418 return HSLColor( aColor
.mnHue
, aColor
.mnSaturation
, aColor
.mnLuminance
);
421 ::cppcanvas::Color::IntSRGBA
RGBColor::getIntegerColor() const
423 return ::cppcanvas::makeColor( colorToInt( getRed() ),
424 colorToInt( getGreen() ),
425 colorToInt( getBlue() ),
429 RGBColor
operator+( const RGBColor
& rLHS
, const RGBColor
& rRHS
)
431 return RGBColor( rLHS
.getRed() + rRHS
.getRed(),
432 rLHS
.getGreen() + rRHS
.getGreen(),
433 rLHS
.getBlue() + rRHS
.getBlue() );
436 RGBColor
operator*( const RGBColor
& rLHS
, const RGBColor
& rRHS
)
438 return RGBColor( rLHS
.getRed() * rRHS
.getRed(),
439 rLHS
.getGreen() * rRHS
.getGreen(),
440 rLHS
.getBlue() * rRHS
.getBlue() );
443 RGBColor
operator*( double nFactor
, const RGBColor
& rRHS
)
445 return RGBColor( nFactor
* rRHS
.getRed(),
446 nFactor
* rRHS
.getGreen(),
447 nFactor
* rRHS
.getBlue() );
450 RGBColor
interpolate( const RGBColor
& rFrom
, const RGBColor
& rTo
, double t
)
452 return RGBColor( (1.0-t
)*rFrom
.getRed() + t
*rTo
.getRed(),
453 (1.0-t
)*rFrom
.getGreen() + t
*rTo
.getGreen(),
454 (1.0-t
)*rFrom
.getBlue() + t
*rTo
.getBlue() );