Bump version to 6.0-36
[LibreOffice.git] / slideshow / source / engine / color.cxx
bloba7a957e7f423ec7962f718f9b243b9492b953602
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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>
26 #include <cmath>
27 #include <algorithm>
30 namespace slideshow
32 namespace internal
34 namespace
36 // helper functions
37 // ================
39 double getMagic( double nLuminance, double nSaturation )
41 if( nLuminance <= 0.5 )
42 return nLuminance*(1.0 + nSaturation);
43 else
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)
64 aRes.mnHue = 0.0;
66 else
68 aRes.mnSaturation = aRes.mnLuminance > 0.5 ?
69 nDelta/(2.0-nMax-nMin) :
70 nDelta/(nMax + nMin);
72 if( rtl::math::approxEqual(nRed, nMax) )
73 aRes.mnHue = (nGreen - nBlue)/nDelta;
74 else if( rtl::math::approxEqual(nGreen, nMax) )
75 aRes.mnHue = 2.0 + (nBlue - nRed)/nDelta;
76 else if( rtl::math::approxEqual(nBlue, nMax) )
77 aRes.mnHue = 4.0 + (nRed - nGreen)/nDelta;
79 aRes.mnHue *= 60.0;
81 if( aRes.mnHue < 0.0 )
82 aRes.mnHue += 360.0;
85 return aRes;
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
94 if( nHue < 0.0 )
95 nHue += 360.0;
97 if( nHue < 60.0 )
98 return nValue1 + (nValue2 - nValue1)*nHue/60.0;
99 else if( nHue < 180.0 )
100 return nValue2;
101 else if( nHue < 240.0 )
102 return nValue1 + (nValue2 - nValue1)*(240.0 - nHue)/60.0;
103 else
104 return nValue1;
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,
118 nVal1,
119 nHue + 120.0 );
120 aRes.mnGreen = hsl2rgbHelper( nVal2,
121 nVal1,
122 nHue );
123 aRes.mnBlue = hsl2rgbHelper( nVal2,
124 nVal1,
125 nHue - 120.0 );
127 return aRes;
130 /// Truncate range of value to [0,1]
131 double truncateRangeStd( double nVal )
133 return ::std::max( 0.0,
134 ::std::min( 1.0,
135 nVal ) );
138 /// Truncate range of value to [0,360]
139 double truncateRangeHue( double nVal )
141 return ::std::max( 0.0,
142 ::std::min( 360.0,
143 nVal ) );
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 ) );
155 // HSLColor
158 HSLColor::HSLTriple::HSLTriple() :
159 mnHue(),
160 mnSaturation(),
161 mnLuminance()
165 HSLColor::HSLTriple::HSLTriple( double nHue, double nSaturation, double nLuminance ) :
166 mnHue( nHue ),
167 mnSaturation( nSaturation ),
168 mnLuminance( nLuminance )
172 HSLColor::HSLColor() :
173 maHSLTriple( 0.0, 0.0, 0.0 )
177 HSLColor::HSLColor( double nHue, double nSaturation, double nLuminance ) :
178 maHSLTriple( nHue, nSaturation, nLuminance )
182 HSLColor::HSLColor( const RGBColor& rColor ) :
183 maHSLTriple( rgb2hsl( truncateRangeStd( rColor.getRed() ),
184 truncateRangeStd( rColor.getGreen() ),
185 truncateRangeStd( rColor.getBlue() ) ) )
190 bool operator==( const HSLColor& rLHS, const HSLColor& rRHS )
192 return ( rLHS.getHue() == rRHS.getHue() &&
193 rLHS.getSaturation() == rRHS.getSaturation() &&
194 rLHS.getLuminance() == rRHS.getLuminance() );
197 bool operator!=( const HSLColor& rLHS, const HSLColor& rRHS )
199 return !( rLHS == rRHS );
202 HSLColor operator+( const HSLColor& rLHS, const HSLColor& rRHS )
204 return HSLColor( rLHS.getHue() + rRHS.getHue(),
205 rLHS.getSaturation() + rRHS.getSaturation(),
206 rLHS.getLuminance() + rRHS.getLuminance() );
209 HSLColor operator*( double nFactor, const HSLColor& rRHS )
211 return HSLColor( nFactor * rRHS.getHue(),
212 nFactor * rRHS.getSaturation(),
213 nFactor * rRHS.getLuminance() );
216 HSLColor interpolate( const HSLColor& rFrom, const HSLColor& rTo, double t, bool bCCW )
218 const double nFromHue( rFrom.getHue() );
219 const double nToHue ( rTo.getHue() );
221 double nHue=0.0;
223 if( nFromHue <= nToHue && !bCCW )
225 // interpolate hue clockwise. That is, hue starts at
226 // high values and ends at low ones. Therefore, we
227 // must 'cross' the 360 degrees and start at low
228 // values again (imagine the hues to lie on the
229 // circle, where values above 360 degrees are mapped
230 // back to [0,360)).
231 nHue = (1.0-t)*(nFromHue + 360.0) + t*nToHue;
233 else if( nFromHue > nToHue && bCCW )
235 // interpolate hue counter-clockwise. That is, hue
236 // starts at high values and ends at low
237 // ones. Therefore, we must 'cross' the 360 degrees
238 // and start at low values again (imagine the hues to
239 // lie on the circle, where values above 360 degrees
240 // are mapped back to [0,360)).
241 nHue = (1.0-t)*nFromHue + t*(nToHue + 360.0);
243 else
245 // interpolate hue counter-clockwise. That is, hue
246 // starts at low values and ends at high ones (imagine
247 // the hue value as degrees on a circle, with
248 // increasing values going counter-clockwise)
249 nHue = (1.0-t)*nFromHue + t*nToHue;
252 return HSLColor( nHue,
253 (1.0-t)*rFrom.getSaturation() + t*rTo.getSaturation(),
254 (1.0-t)*rFrom.getLuminance() + t*rTo.getLuminance() );
258 // RGBColor
261 RGBColor::RGBTriple::RGBTriple() :
262 mnRed(),
263 mnGreen(),
264 mnBlue()
268 RGBColor::RGBTriple::RGBTriple( double nRed, double nGreen, double nBlue ) :
269 mnRed( nRed ),
270 mnGreen( nGreen ),
271 mnBlue( nBlue )
275 RGBColor::RGBColor() :
276 maRGBTriple( 0.0, 0.0, 0.0 )
280 RGBColor::RGBColor( ::cppcanvas::IntSRGBA nRGBColor ) :
281 maRGBTriple( ::cppcanvas::getRed( nRGBColor ) / 255.0,
282 ::cppcanvas::getGreen( nRGBColor ) / 255.0,
283 ::cppcanvas::getBlue( nRGBColor ) / 255.0 )
287 RGBColor::RGBColor( double nRed, double nGreen, double nBlue ) :
288 maRGBTriple( nRed, nGreen, nBlue )
292 RGBColor::RGBColor( const HSLColor& rColor ) :
293 maRGBTriple( hsl2rgb( truncateRangeHue( rColor.getHue() ),
294 truncateRangeStd( rColor.getSaturation() ),
295 truncateRangeStd( rColor.getLuminance() ) ) )
300 ::cppcanvas::IntSRGBA RGBColor::getIntegerColor() const
302 return ::cppcanvas::makeColor( colorToInt( getRed() ),
303 colorToInt( getGreen() ),
304 colorToInt( getBlue() ),
305 255 );
308 bool operator==( const RGBColor& rLHS, const RGBColor& rRHS )
310 return ( rLHS.getRed() == rRHS.getRed() &&
311 rLHS.getGreen() == rRHS.getGreen() &&
312 rLHS.getBlue() == rRHS.getBlue() );
315 bool operator!=( const RGBColor& rLHS, const RGBColor& rRHS )
317 return !( rLHS == rRHS );
320 RGBColor operator+( const RGBColor& rLHS, const RGBColor& rRHS )
322 return RGBColor( rLHS.getRed() + rRHS.getRed(),
323 rLHS.getGreen() + rRHS.getGreen(),
324 rLHS.getBlue() + rRHS.getBlue() );
327 RGBColor operator*( const RGBColor& rLHS, const RGBColor& rRHS )
329 return RGBColor( rLHS.getRed() * rRHS.getRed(),
330 rLHS.getGreen() * rRHS.getGreen(),
331 rLHS.getBlue() * rRHS.getBlue() );
334 RGBColor operator*( double nFactor, const RGBColor& rRHS )
336 return RGBColor( nFactor * rRHS.getRed(),
337 nFactor * rRHS.getGreen(),
338 nFactor * rRHS.getBlue() );
341 RGBColor interpolate( const RGBColor& rFrom, const RGBColor& rTo, double t )
343 return RGBColor( (1.0-t)*rFrom.getRed() + t*rTo.getRed(),
344 (1.0-t)*rFrom.getGreen() + t*rTo.getGreen(),
345 (1.0-t)*rFrom.getBlue() + t*rTo.getBlue() );
350 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */