1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
21 #include <hslcolor.hxx>
22 #include <rgbcolor.hxx>
24 #include <basegfx/numeric/ftools.hxx>
39 double getMagic( double nLuminance
, double nSaturation
)
41 if( nLuminance
<= 0.5 )
42 return nLuminance
*(1.0 + nSaturation
);
44 return nLuminance
+ nSaturation
- nLuminance
*nSaturation
;
47 HSLColor::HSLTriple
rgb2hsl( double nRed
, double nGreen
, double nBlue
)
49 // r,g,b in [0,1], h in [0,360] and s,l in [0,1]
50 HSLColor::HSLTriple aRes
;
52 const double nMax( ::std::max(nRed
,::std::max(nGreen
, nBlue
)) );
53 const double nMin( ::std::min(nRed
,::std::min(nGreen
, nBlue
)) );
55 const double nDelta( nMax
- nMin
);
57 aRes
.mnLuminance
= (nMax
+ nMin
) / 2.0;
59 if( ::basegfx::fTools::equalZero( nDelta
) )
61 aRes
.mnSaturation
= 0.0;
63 // hue undefined (achromatic case)
68 aRes
.mnSaturation
= aRes
.mnLuminance
> 0.5 ?
69 nDelta
/(2.0-nMax
-nMin
) :
73 aRes
.mnHue
= (nGreen
- nBlue
)/nDelta
;
74 else if( nGreen
== nMax
)
75 aRes
.mnHue
= 2.0 + (nBlue
- nRed
)/nDelta
;
76 else if( nBlue
== nMax
)
77 aRes
.mnHue
= 4.0 + (nRed
- nGreen
)/nDelta
;
81 if( aRes
.mnHue
< 0.0 )
88 double hsl2rgbHelper( double nValue1
, double nValue2
, double nHue
)
90 // clamp hue to [0,360]
91 nHue
= fmod( nHue
, 360.0 );
93 // cope with wrap-arounds
98 return nValue1
+ (nValue2
- nValue1
)*nHue
/60.0;
99 else if( nHue
< 180.0 )
101 else if( nHue
< 240.0 )
102 return nValue1
+ (nValue2
- nValue1
)*(240.0 - nHue
)/60.0;
107 RGBColor::RGBTriple
hsl2rgb( double nHue
, double nSaturation
, double nLuminance
)
109 if( ::basegfx::fTools::equalZero( nSaturation
) )
110 return RGBColor::RGBTriple(0.0, 0.0, nLuminance
);
112 const double nVal1( getMagic(nLuminance
, nSaturation
) );
113 const double nVal2( 2.0*nLuminance
- nVal1
);
115 RGBColor::RGBTriple aRes
;
117 aRes
.mnRed
= hsl2rgbHelper( nVal2
,
120 aRes
.mnGreen
= hsl2rgbHelper( nVal2
,
123 aRes
.mnBlue
= hsl2rgbHelper( nVal2
,
130 /// Truncate range of value to [0,1]
131 double truncateRangeStd( double nVal
)
133 return ::std::max( 0.0,
138 /// Truncate range of value to [0,360]
139 double truncateRangeHue( double nVal
)
141 return ::std::max( 0.0,
146 /// convert RGB color to sal_uInt8, truncate range appropriately before
147 sal_uInt8
colorToInt( double nCol
)
149 return static_cast< sal_uInt8
>(
150 ::basegfx::fround( truncateRangeStd( nCol
) * 255.0 ) );
159 HSLColor::HSLTriple::HSLTriple() :
166 HSLColor::HSLTriple::HSLTriple( double nHue
, double nSaturation
, double nLuminance
) :
168 mnSaturation( nSaturation
),
169 mnLuminance( nLuminance
)
173 HSLColor::HSLColor() :
174 maHSLTriple( 0.0, 0.0, 0.0 ),
175 mnMagicValue( getMagic( maHSLTriple
.mnLuminance
,
176 maHSLTriple
.mnSaturation
) )
180 HSLColor::HSLColor( double nHue
, double nSaturation
, double nLuminance
) :
181 maHSLTriple( nHue
, nSaturation
, nLuminance
),
182 mnMagicValue( getMagic( maHSLTriple
.mnLuminance
,
183 maHSLTriple
.mnSaturation
) )
187 HSLColor::HSLColor( const RGBColor
& rColor
) :
188 maHSLTriple( rgb2hsl( truncateRangeStd( rColor
.getRed() ),
189 truncateRangeStd( rColor
.getGreen() ),
190 truncateRangeStd( rColor
.getBlue() ) ) ),
191 mnMagicValue( getMagic( maHSLTriple
.mnLuminance
,
192 maHSLTriple
.mnSaturation
) )
200 bool operator==( const HSLColor
& rLHS
, const HSLColor
& rRHS
)
202 return ( rLHS
.getHue() == rRHS
.getHue() &&
203 rLHS
.getSaturation() == rRHS
.getSaturation() &&
204 rLHS
.getLuminance() == rRHS
.getLuminance() );
207 bool operator!=( const HSLColor
& rLHS
, const HSLColor
& rRHS
)
209 return !( rLHS
== rRHS
);
212 HSLColor
operator+( const HSLColor
& rLHS
, const HSLColor
& rRHS
)
214 return HSLColor( rLHS
.getHue() + rRHS
.getHue(),
215 rLHS
.getSaturation() + rRHS
.getSaturation(),
216 rLHS
.getLuminance() + rRHS
.getLuminance() );
219 HSLColor
operator*( const HSLColor
& rLHS
, const HSLColor
& rRHS
)
221 return HSLColor( rLHS
.getHue() * rRHS
.getHue(),
222 rLHS
.getSaturation() * rRHS
.getSaturation(),
223 rLHS
.getLuminance() * rRHS
.getLuminance() );
226 HSLColor
operator*( double nFactor
, const HSLColor
& rRHS
)
228 return HSLColor( nFactor
* rRHS
.getHue(),
229 nFactor
* rRHS
.getSaturation(),
230 nFactor
* rRHS
.getLuminance() );
233 HSLColor
interpolate( const HSLColor
& rFrom
, const HSLColor
& rTo
, double t
, bool bCCW
)
235 const double nFromHue( rFrom
.getHue() );
236 const double nToHue ( rTo
.getHue() );
240 if( nFromHue
<= nToHue
&& !bCCW
)
242 // interpolate hue clockwise. That is, hue starts at
243 // high values and ends at low ones. Therefore, we
244 // must 'cross' the 360 degrees and start at low
245 // values again (imagine the hues to lie on the
246 // circle, where values above 360 degrees are mapped
248 nHue
= (1.0-t
)*(nFromHue
+ 360.0) + t
*nToHue
;
250 else if( nFromHue
> nToHue
&& bCCW
)
252 // interpolate hue counter-clockwise. That is, hue
253 // starts at high values and ends at low
254 // ones. Therefore, we must 'cross' the 360 degrees
255 // and start at low values again (imagine the hues to
256 // lie on the circle, where values above 360 degrees
257 // are mapped back to [0,360)).
258 nHue
= (1.0-t
)*nFromHue
+ t
*(nToHue
+ 360.0);
262 // interpolate hue counter-clockwise. That is, hue
263 // starts at low values and ends at high ones (imagine
264 // the hue value as degrees on a circle, with
265 // increasing values going counter-clockwise)
266 nHue
= (1.0-t
)*nFromHue
+ t
*nToHue
;
269 return HSLColor( nHue
,
270 (1.0-t
)*rFrom
.getSaturation() + t
*rTo
.getSaturation(),
271 (1.0-t
)*rFrom
.getLuminance() + t
*rTo
.getLuminance() );
280 RGBColor::RGBTriple::RGBTriple() :
287 RGBColor::RGBTriple::RGBTriple( double nRed
, double nGreen
, double nBlue
) :
294 RGBColor::RGBColor() :
295 maRGBTriple( 0.0, 0.0, 0.0 )
299 RGBColor::RGBColor( ::cppcanvas::Color::IntSRGBA nRGBColor
) :
300 maRGBTriple( ::cppcanvas::getRed( nRGBColor
) / 255.0,
301 ::cppcanvas::getGreen( nRGBColor
) / 255.0,
302 ::cppcanvas::getBlue( nRGBColor
) / 255.0 )
306 RGBColor::RGBColor( double nRed
, double nGreen
, double nBlue
) :
307 maRGBTriple( nRed
, nGreen
, nBlue
)
311 RGBColor::RGBColor( const HSLColor
& rColor
) :
312 maRGBTriple( hsl2rgb( truncateRangeHue( rColor
.getHue() ),
313 truncateRangeStd( rColor
.getSaturation() ),
314 truncateRangeStd( rColor
.getLuminance() ) ) )
321 ::cppcanvas::Color::IntSRGBA
RGBColor::getIntegerColor() const
323 return ::cppcanvas::makeColor( colorToInt( getRed() ),
324 colorToInt( getGreen() ),
325 colorToInt( getBlue() ),
329 bool operator==( const RGBColor
& rLHS
, const RGBColor
& rRHS
)
331 return ( rLHS
.getRed() == rRHS
.getRed() &&
332 rLHS
.getGreen() == rRHS
.getGreen() &&
333 rLHS
.getBlue() == rRHS
.getBlue() );
336 bool operator!=( const RGBColor
& rLHS
, const RGBColor
& rRHS
)
338 return !( rLHS
== rRHS
);
341 RGBColor
operator+( const RGBColor
& rLHS
, const RGBColor
& rRHS
)
343 return RGBColor( rLHS
.getRed() + rRHS
.getRed(),
344 rLHS
.getGreen() + rRHS
.getGreen(),
345 rLHS
.getBlue() + rRHS
.getBlue() );
348 RGBColor
operator*( const RGBColor
& rLHS
, const RGBColor
& rRHS
)
350 return RGBColor( rLHS
.getRed() * rRHS
.getRed(),
351 rLHS
.getGreen() * rRHS
.getGreen(),
352 rLHS
.getBlue() * rRHS
.getBlue() );
355 RGBColor
operator*( double nFactor
, const RGBColor
& rRHS
)
357 return RGBColor( nFactor
* rRHS
.getRed(),
358 nFactor
* rRHS
.getGreen(),
359 nFactor
* rRHS
.getBlue() );
362 RGBColor
interpolate( const RGBColor
& rFrom
, const RGBColor
& rTo
, double t
)
364 return RGBColor( (1.0-t
)*rFrom
.getRed() + t
*rTo
.getRed(),
365 (1.0-t
)*rFrom
.getGreen() + t
*rTo
.getGreen(),
366 (1.0-t
)*rFrom
.getBlue() + t
*rTo
.getBlue() );
371 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */