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