LibreOffice Module slideshow (master) 1
color.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
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/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
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 .
18 */
19
20
21#include <hslcolor.hxx>
22#include <rgbcolor.hxx>
23
25#include <rtl/math.hxx>
26
27#include <cmath>
28#include <algorithm>
29
30
31namespace slideshow::internal
32{
33 namespace
34 {
35 // helper functions
36 // ================
37
38 double getMagic( double nLuminance, double nSaturation )
39 {
40 if( nLuminance <= 0.5 )
41 return nLuminance*(1.0 + nSaturation);
42 else
43 return nLuminance + nSaturation - nLuminance*nSaturation;
44 }
45
46 HSLColor::HSLTriple rgb2hsl( double nRed, double nGreen, double nBlue )
47 {
48 // r,g,b in [0,1], h in [0,360] and s,l in [0,1]
49 HSLColor::HSLTriple aRes;
50
51 const double nMax( ::std::max(nRed,::std::max(nGreen, nBlue)) );
52 const double nMin( ::std::min(nRed,::std::min(nGreen, nBlue)) );
53
54 const double nDelta( nMax - nMin );
55
56 aRes.mnLuminance = (nMax + nMin) / 2.0;
57
58 if( ::basegfx::fTools::equalZero( nDelta ) )
59 {
60 aRes.mnSaturation = 0.0;
61
62 // hue undefined (achromatic case)
63 aRes.mnHue = 0.0;
64 }
65 else
66 {
67 aRes.mnSaturation = aRes.mnLuminance > 0.5 ?
68 nDelta/(2.0-nMax-nMin) :
69 nDelta/(nMax + nMin);
70
71 if( rtl::math::approxEqual(nRed, nMax) )
72 aRes.mnHue = (nGreen - nBlue)/nDelta;
73 else if( rtl::math::approxEqual(nGreen, nMax) )
74 aRes.mnHue = 2.0 + (nBlue - nRed)/nDelta;
75 else if( rtl::math::approxEqual(nBlue, nMax) )
76 aRes.mnHue = 4.0 + (nRed - nGreen)/nDelta;
77
78 aRes.mnHue *= 60.0;
79
80 if( aRes.mnHue < 0.0 )
81 aRes.mnHue += 360.0;
82 }
83
84 return aRes;
85 }
86
87 double hsl2rgbHelper( double nValue1, double nValue2, double nHue )
88 {
89 // clamp hue to [0,360]
90 nHue = fmod( nHue, 360.0 );
91
92 // cope with wrap-arounds
93 if( nHue < 0.0 )
94 nHue += 360.0;
95
96 if( nHue < 60.0 )
97 return nValue1 + (nValue2 - nValue1)*nHue/60.0;
98 else if( nHue < 180.0 )
99 return nValue2;
100 else if( nHue < 240.0 )
101 return nValue1 + (nValue2 - nValue1)*(240.0 - nHue)/60.0;
102 else
103 return nValue1;
104 }
105
106 RGBColor::RGBTriple hsl2rgb( double nHue, double nSaturation, double nLuminance )
107 {
108 if( ::basegfx::fTools::equalZero( nSaturation ) )
109 return RGBColor::RGBTriple(0.0, 0.0, nLuminance );
110
111 const double nVal1( getMagic(nLuminance, nSaturation) );
112 const double nVal2( 2.0*nLuminance - nVal1 );
113
114 RGBColor::RGBTriple aRes;
115
116 aRes.mnRed = hsl2rgbHelper( nVal2,
117 nVal1,
118 nHue + 120.0 );
119 aRes.mnGreen = hsl2rgbHelper( nVal2,
120 nVal1,
121 nHue );
122 aRes.mnBlue = hsl2rgbHelper( nVal2,
123 nVal1,
124 nHue - 120.0 );
125
126 return aRes;
127 }
128
130 double truncateRangeStd( double nVal )
131 {
132 return ::std::max( 0.0,
133 ::std::min( 1.0,
134 nVal ) );
135 }
136
138 double truncateRangeHue( double nVal )
139 {
140 return ::std::max( 0.0,
141 ::std::min( 360.0,
142 nVal ) );
143 }
144
146 sal_uInt8 colorToInt( double nCol )
147 {
148 return static_cast< sal_uInt8 >(
149 ::basegfx::fround( truncateRangeStd( nCol ) * 255.0 ) );
150 }
151 }
152
153
154 // HSLColor
155
156
158 mnHue(),
159 mnSaturation(),
160 mnLuminance()
161 {
162 }
163
164 HSLColor::HSLTriple::HSLTriple( double nHue, double nSaturation, double nLuminance ) :
165 mnHue( nHue ),
166 mnSaturation( nSaturation ),
167 mnLuminance( nLuminance )
168 {
169 }
170
172 maHSLTriple( 0.0, 0.0, 0.0 )
173 {
174 }
175
176 HSLColor::HSLColor( double nHue, double nSaturation, double nLuminance ) :
177 maHSLTriple( nHue, nSaturation, nLuminance )
178 {
179 }
180
181 HSLColor::HSLColor( const RGBColor& rColor ) :
182 maHSLTriple( rgb2hsl( truncateRangeStd( rColor.getRed() ),
183 truncateRangeStd( rColor.getGreen() ),
184 truncateRangeStd( rColor.getBlue() ) ) )
185 {
186 }
187
188
189 bool operator==( const HSLColor& rLHS, const HSLColor& rRHS )
190 {
191 return ( rLHS.getHue() == rRHS.getHue() &&
192 rLHS.getSaturation() == rRHS.getSaturation() &&
193 rLHS.getLuminance() == rRHS.getLuminance() );
194 }
195
196 bool operator!=( const HSLColor& rLHS, const HSLColor& rRHS )
197 {
198 return !( rLHS == rRHS );
199 }
200
201 HSLColor operator+( const HSLColor& rLHS, const HSLColor& rRHS )
202 {
203 return HSLColor( rLHS.getHue() + rRHS.getHue(),
204 rLHS.getSaturation() + rRHS.getSaturation(),
205 rLHS.getLuminance() + rRHS.getLuminance() );
206 }
207
208 HSLColor operator*( double nFactor, const HSLColor& rRHS )
209 {
210 return HSLColor( nFactor * rRHS.getHue(),
211 nFactor * rRHS.getSaturation(),
212 nFactor * rRHS.getLuminance() );
213 }
214
215 HSLColor interpolate( const HSLColor& rFrom, const HSLColor& rTo, double t, bool bCCW )
216 {
217 const double nFromHue( rFrom.getHue() );
218 const double nToHue ( rTo.getHue() );
219
220 double nHue=0.0;
221
222 if( nFromHue <= nToHue && !bCCW )
223 {
224 // interpolate hue clockwise. That is, hue starts at
225 // high values and ends at low ones. Therefore, we
226 // must 'cross' the 360 degrees and start at low
227 // values again (imagine the hues to lie on the
228 // circle, where values above 360 degrees are mapped
229 // back to [0,360)).
230 nHue = (1.0-t)*(nFromHue + 360.0) + t*nToHue;
231 }
232 else if( nFromHue > nToHue && bCCW )
233 {
234 // interpolate hue counter-clockwise. That is, hue
235 // starts at high values and ends at low
236 // ones. Therefore, we must 'cross' the 360 degrees
237 // and start at low values again (imagine the hues to
238 // lie on the circle, where values above 360 degrees
239 // are mapped back to [0,360)).
240 nHue = (1.0-t)*nFromHue + t*(nToHue + 360.0);
241 }
242 else
243 {
244 // interpolate hue counter-clockwise. That is, hue
245 // starts at low values and ends at high ones (imagine
246 // the hue value as degrees on a circle, with
247 // increasing values going counter-clockwise)
248 nHue = (1.0-t)*nFromHue + t*nToHue;
249 }
250
251 return HSLColor( nHue,
252 (1.0-t)*rFrom.getSaturation() + t*rTo.getSaturation(),
253 (1.0-t)*rFrom.getLuminance() + t*rTo.getLuminance() );
254 }
255
256
257 // RGBColor
258
259
261 mnRed(),
262 mnGreen(),
263 mnBlue()
264 {
265 }
266
267 RGBColor::RGBTriple::RGBTriple( double nRed, double nGreen, double nBlue ) :
268 mnRed( nRed ),
269 mnGreen( nGreen ),
270 mnBlue( nBlue )
271 {
272 }
273
275 maRGBTriple( 0.0, 0.0, 0.0 )
276 {
277 }
278
280 maRGBTriple( ::cppcanvas::getRed( nRGBColor ) / 255.0,
281 ::cppcanvas::getGreen( nRGBColor ) / 255.0,
282 ::cppcanvas::getBlue( nRGBColor ) / 255.0 )
283 {
284 }
285
286 RGBColor::RGBColor( double nRed, double nGreen, double nBlue ) :
287 maRGBTriple( nRed, nGreen, nBlue )
288 {
289 }
290
291 RGBColor::RGBColor( const HSLColor& rColor ) :
292 maRGBTriple( hsl2rgb( truncateRangeHue( rColor.getHue() ),
293 truncateRangeStd( rColor.getSaturation() ),
294 truncateRangeStd( rColor.getLuminance() ) ) )
295 {
296 }
297
298
300 {
301 return ::cppcanvas::makeColor( colorToInt( getRed() ),
302 colorToInt( getGreen() ),
303 colorToInt( getBlue() ),
304 255 );
305 }
306
307 bool operator==( const RGBColor& rLHS, const RGBColor& rRHS )
308 {
309 return ( rLHS.getRed() == rRHS.getRed() &&
310 rLHS.getGreen() == rRHS.getGreen() &&
311 rLHS.getBlue() == rRHS.getBlue() );
312 }
313
314 bool operator!=( const RGBColor& rLHS, const RGBColor& rRHS )
315 {
316 return !( rLHS == rRHS );
317 }
318
319 RGBColor operator+( const RGBColor& rLHS, const RGBColor& rRHS )
320 {
321 return RGBColor( rLHS.getRed() + rRHS.getRed(),
322 rLHS.getGreen() + rRHS.getGreen(),
323 rLHS.getBlue() + rRHS.getBlue() );
324 }
325
326 RGBColor operator*( const RGBColor& rLHS, const RGBColor& rRHS )
327 {
328 return RGBColor( rLHS.getRed() * rRHS.getRed(),
329 rLHS.getGreen() * rRHS.getGreen(),
330 rLHS.getBlue() * rRHS.getBlue() );
331 }
332
333 RGBColor operator*( double nFactor, const RGBColor& rRHS )
334 {
335 return RGBColor( nFactor * rRHS.getRed(),
336 nFactor * rRHS.getGreen(),
337 nFactor * rRHS.getBlue() );
338 }
339
340 RGBColor interpolate( const RGBColor& rFrom, const RGBColor& rTo, double t )
341 {
342 return RGBColor( (1.0-t)*rFrom.getRed() + t*rTo.getRed(),
343 (1.0-t)*rFrom.getGreen() + t*rTo.getGreen(),
344 (1.0-t)*rFrom.getBlue() + t*rTo.getBlue() );
345 }
346}
347
348/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
XPropertyListType t
HSL color space class.
Definition: hslcolor.hxx:33
double getHue() const
Hue of the color.
Definition: hslcolor.hxx:43
double getLuminance() const
Luminance of the color.
Definition: hslcolor.hxx:55
double getSaturation() const
Saturation of the color.
Definition: hslcolor.hxx:49
RGB color space class.
Definition: rgbcolor.hxx:35
::cppcanvas::IntSRGBA getIntegerColor() const
Create an integer sRGBA color.
Definition: color.cxx:299
double getRed() const
Get the RGB red value.
Definition: rgbcolor.hxx:44
double getGreen() const
Get the RGB green value.
Definition: rgbcolor.hxx:48
double getBlue() const
Get the RGB blue value.
Definition: rgbcolor.hxx:52
BColor rgb2hsl(const BColor &rRGBColor)
BColor hsl2rgb(const BColor &rHSLColor)
sal_uInt8 getRed(IntSRGBA nCol)
sal_uInt32 IntSRGBA
sal_uInt8 getBlue(IntSRGBA nCol)
sal_uInt8 getGreen(IntSRGBA nCol)
bool operator==(const HSLColor &rLHS, const HSLColor &rRHS)
Definition: color.cxx:189
HSLColor operator+(const HSLColor &rLHS, const HSLColor &rRHS)
Definition: color.cxx:201
bool operator!=(const HSLColor &rLHS, const HSLColor &rRHS)
Definition: color.cxx:196
HSLColor operator*(double nFactor, const HSLColor &rRHS)
Definition: color.cxx:208
HSLColor interpolate(const HSLColor &rFrom, const HSLColor &rTo, double t, bool bCCW)
HSL color linear interpolator.
Definition: color.cxx:215
unsigned char sal_uInt8