1 /************************************************************************* 2 * 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * Copyright 2000, 2010 Oracle and/or its affiliates. 6 * 7 * OpenOffice.org - a multi-platform office productivity suite 8 * 9 * This file is part of OpenOffice.org. 10 * 11 * OpenOffice.org is free software: you can redistribute it and/or modify 12 * it under the terms of the GNU Lesser General Public License version 3 13 * only, as published by the Free Software Foundation. 14 * 15 * OpenOffice.org is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU Lesser General Public License version 3 for more details 19 * (a copy is included in the LICENSE file that accompanied this code). 20 * 21 * You should have received a copy of the GNU Lesser General Public License 22 * version 3 along with OpenOffice.org. If not, see 23 * <http://www.openoffice.org/license.html> 24 * for a copy of the LGPLv3 License. 25 * 26 ************************************************************************/ 27 28 // MARKER(update_precomp.py): autogen include statement, do not remove 29 #include "precompiled_slideshow.hxx" 30 31 #include <hslcolor.hxx> 32 #include <rgbcolor.hxx> 33 34 #include <basegfx/numeric/ftools.hxx> 35 36 #include <cmath> // for fmod 37 #include <algorithm> 38 39 40 namespace slideshow 41 { 42 namespace internal 43 { 44 namespace 45 { 46 // helper functions 47 // ================ 48 49 double getMagic( double nLuminance, double nSaturation ) 50 { 51 if( nLuminance <= 0.5 ) 52 return nLuminance*(1.0 + nSaturation); 53 else 54 return nLuminance + nSaturation - nLuminance*nSaturation; 55 } 56 57 HSLColor::HSLTriple rgb2hsl( double nRed, double nGreen, double nBlue ) 58 { 59 // r,g,b in [0,1], h in [0,360] and s,l in [0,1] 60 HSLColor::HSLTriple aRes; 61 62 const double nMax( ::std::max(nRed,::std::max(nGreen, nBlue)) ); 63 const double nMin( ::std::min(nRed,::std::min(nGreen, nBlue)) ); 64 65 const double nDelta( nMax - nMin ); 66 67 aRes.mnLuminance = (nMax + nMin) / 2.0; 68 69 if( ::basegfx::fTools::equalZero( nDelta ) ) 70 { 71 aRes.mnSaturation = 0.0; 72 73 // hue undefined (achromatic case) 74 aRes.mnHue = 0.0; 75 } 76 else 77 { 78 aRes.mnSaturation = aRes.mnLuminance > 0.5 ? 79 nDelta/(2.0-nMax-nMin) : 80 nDelta/(nMax + nMin); 81 82 if( nRed == nMax ) 83 aRes.mnHue = (nGreen - nBlue)/nDelta; 84 else if( nGreen == nMax ) 85 aRes.mnHue = 2.0 + (nBlue - nRed)/nDelta; 86 else if( nBlue == nMax ) 87 aRes.mnHue = 4.0 + (nRed - nGreen)/nDelta; 88 89 aRes.mnHue *= 60.0; 90 91 if( aRes.mnHue < 0.0 ) 92 aRes.mnHue += 360.0; 93 } 94 95 return aRes; 96 } 97 98 double hsl2rgbHelper( double nValue1, double nValue2, double nHue ) 99 { 100 // clamp hue to [0,360] 101 nHue = fmod( nHue, 360.0 ); 102 103 // cope with wrap-arounds 104 if( nHue < 0.0 ) 105 nHue += 360.0; 106 107 if( nHue < 60.0 ) 108 return nValue1 + (nValue2 - nValue1)*nHue/60.0; 109 else if( nHue < 180.0 ) 110 return nValue2; 111 else if( nHue < 240.0 ) 112 return nValue1 + (nValue2 - nValue1)*(240.0 - nHue)/60.0; 113 else 114 return nValue1; 115 } 116 117 RGBColor::RGBTriple hsl2rgb( double nHue, double nSaturation, double nLuminance ) 118 { 119 if( ::basegfx::fTools::equalZero( nSaturation ) ) 120 return RGBColor::RGBTriple(0.0, 0.0, nLuminance ); 121 122 const double nVal1( getMagic(nLuminance, nSaturation) ); 123 const double nVal2( 2.0*nLuminance - nVal1 ); 124 125 RGBColor::RGBTriple aRes; 126 127 aRes.mnRed = hsl2rgbHelper( nVal2, 128 nVal1, 129 nHue + 120.0 ); 130 aRes.mnGreen = hsl2rgbHelper( nVal2, 131 nVal1, 132 nHue ); 133 aRes.mnBlue = hsl2rgbHelper( nVal2, 134 nVal1, 135 nHue - 120.0 ); 136 137 return aRes; 138 } 139 140 /// Truncate range of value to [0,1] 141 double truncateRangeStd( double nVal ) 142 { 143 return ::std::max( 0.0, 144 ::std::min( 1.0, 145 nVal ) ); 146 } 147 148 /// Truncate range of value to [0,360] 149 double truncateRangeHue( double nVal ) 150 { 151 return ::std::max( 0.0, 152 ::std::min( 360.0, 153 nVal ) ); 154 } 155 156 /// convert RGB color to sal_uInt8, truncate range appropriately before 157 sal_uInt8 colorToInt( double nCol ) 158 { 159 return static_cast< sal_uInt8 >( 160 ::basegfx::fround( truncateRangeStd( nCol ) * 255.0 ) ); 161 } 162 } 163 164 165 166 // HSLColor 167 // =============================================== 168 169 HSLColor::HSLTriple::HSLTriple() : 170 mnHue(), 171 mnSaturation(), 172 mnLuminance() 173 { 174 } 175 176 HSLColor::HSLTriple::HSLTriple( double nHue, double nSaturation, double nLuminance ) : 177 mnHue( nHue ), 178 mnSaturation( nSaturation ), 179 mnLuminance( nLuminance ) 180 { 181 } 182 183 HSLColor::HSLColor() : 184 maHSLTriple( 0.0, 0.0, 0.0 ), 185 mnMagicValue( getMagic( maHSLTriple.mnLuminance, 186 maHSLTriple.mnSaturation ) ) 187 { 188 } 189 190 HSLColor::HSLColor( ::cppcanvas::Color::IntSRGBA nRGBColor ) : 191 maHSLTriple( rgb2hsl( ::cppcanvas::getRed( nRGBColor ) / 255.0, 192 ::cppcanvas::getGreen( nRGBColor ) / 255.0, 193 ::cppcanvas::getBlue( nRGBColor ) / 255.0 ) ), 194 mnMagicValue( getMagic( maHSLTriple.mnLuminance, 195 maHSLTriple.mnSaturation ) ) 196 { 197 } 198 199 HSLColor::HSLColor( double nHue, double nSaturation, double nLuminance ) : 200 maHSLTriple( nHue, nSaturation, nLuminance ), 201 mnMagicValue( getMagic( maHSLTriple.mnLuminance, 202 maHSLTriple.mnSaturation ) ) 203 { 204 } 205 206 HSLColor::HSLColor( const RGBColor& rColor ) : 207 maHSLTriple( rgb2hsl( truncateRangeStd( rColor.getRed() ), 208 truncateRangeStd( rColor.getGreen() ), 209 truncateRangeStd( rColor.getBlue() ) ) ), 210 mnMagicValue( getMagic( maHSLTriple.mnLuminance, 211 maHSLTriple.mnSaturation ) ) 212 { 213 } 214 215 double HSLColor::getHue() const 216 { 217 return maHSLTriple.mnHue; 218 } 219 220 double HSLColor::getSaturation() const 221 { 222 return maHSLTriple.mnSaturation; 223 } 224 225 double HSLColor::getLuminance() const 226 { 227 return maHSLTriple.mnLuminance; 228 } 229 230 double HSLColor::getRed() const 231 { 232 if( ::basegfx::fTools::equalZero( getSaturation() ) ) 233 return getLuminance(); 234 235 return hsl2rgbHelper( 2.0*getLuminance() - mnMagicValue, 236 mnMagicValue, 237 getHue() + 120.0 ); 238 } 239 240 double HSLColor::getGreen() const 241 { 242 if( ::basegfx::fTools::equalZero( getSaturation() ) ) 243 return getLuminance(); 244 245 return hsl2rgbHelper( 2.0*getLuminance() - mnMagicValue, 246 mnMagicValue, 247 getHue() ); 248 } 249 250 double HSLColor::getBlue() const 251 { 252 if( ::basegfx::fTools::equalZero( getSaturation() ) ) 253 return getLuminance(); 254 255 return hsl2rgbHelper( 2.0*getLuminance() - mnMagicValue, 256 mnMagicValue, 257 getHue() - 120.0 ); 258 } 259 260 RGBColor HSLColor::getRGBColor() const 261 { 262 RGBColor::RGBTriple aColor( hsl2rgb( getHue(), 263 getSaturation(), 264 getLuminance() ) ); 265 return RGBColor( aColor.mnRed, aColor.mnGreen, aColor.mnBlue ); 266 } 267 268 RGBColor::RGBColor(const RGBColor& rLHS) 269 { 270 maRGBTriple.mnRed = rLHS.getRed(); 271 maRGBTriple.mnGreen = rLHS.getGreen(); 272 maRGBTriple.mnBlue = rLHS.getBlue(); 273 } 274 275 RGBColor& RGBColor::operator=( const RGBColor& rLHS ){ 276 277 maRGBTriple.mnRed = rLHS.getRed(); 278 maRGBTriple.mnGreen = rLHS.getGreen(); 279 maRGBTriple.mnBlue = rLHS.getBlue(); 280 return *this; 281 } 282 283 HSLColor operator+( const HSLColor& rLHS, const HSLColor& rRHS ) 284 { 285 return HSLColor( rLHS.getHue() + rRHS.getHue(), 286 rLHS.getSaturation() + rRHS.getSaturation(), 287 rLHS.getLuminance() + rRHS.getLuminance() ); 288 } 289 290 HSLColor operator*( const HSLColor& rLHS, const HSLColor& rRHS ) 291 { 292 return HSLColor( rLHS.getHue() * rRHS.getHue(), 293 rLHS.getSaturation() * rRHS.getSaturation(), 294 rLHS.getLuminance() * rRHS.getLuminance() ); 295 } 296 297 HSLColor operator*( double nFactor, const HSLColor& rRHS ) 298 { 299 return HSLColor( nFactor * rRHS.getHue(), 300 nFactor * rRHS.getSaturation(), 301 nFactor * rRHS.getLuminance() ); 302 } 303 304 HSLColor interpolate( const HSLColor& rFrom, const HSLColor& rTo, double t, bool bCCW ) 305 { 306 const double nFromHue( rFrom.getHue() ); 307 const double nToHue ( rTo.getHue() ); 308 309 double nHue=0.0; 310 311 if( nFromHue <= nToHue && !bCCW ) 312 { 313 // interpolate hue clockwise. That is, hue starts at 314 // high values and ends at low ones. Therefore, we 315 // must 'cross' the 360 degrees and start at low 316 // values again (imagine the hues to lie on the 317 // circle, where values above 360 degrees are mapped 318 // back to [0,360)). 319 nHue = (1.0-t)*(nFromHue + 360.0) + t*nToHue; 320 } 321 else if( nFromHue > nToHue && bCCW ) 322 { 323 // interpolate hue counter-clockwise. That is, hue 324 // starts at high values and ends at low 325 // ones. Therefore, we must 'cross' the 360 degrees 326 // and start at low values again (imagine the hues to 327 // lie on the circle, where values above 360 degrees 328 // are mapped back to [0,360)). 329 nHue = (1.0-t)*nFromHue + t*(nToHue + 360.0); 330 } 331 else 332 { 333 // interpolate hue counter-clockwise. That is, hue 334 // starts at low values and ends at high ones (imagine 335 // the hue value as degrees on a circle, with 336 // increasing values going counter-clockwise) 337 nHue = (1.0-t)*nFromHue + t*nToHue; 338 } 339 340 return HSLColor( nHue, 341 (1.0-t)*rFrom.getSaturation() + t*rTo.getSaturation(), 342 (1.0-t)*rFrom.getLuminance() + t*rTo.getLuminance() ); 343 } 344 345 346 347 // RGBColor 348 // =============================================== 349 350 351 RGBColor::RGBTriple::RGBTriple() : 352 mnRed(), 353 mnGreen(), 354 mnBlue() 355 { 356 } 357 358 RGBColor::RGBTriple::RGBTriple( double nRed, double nGreen, double nBlue ) : 359 mnRed( nRed ), 360 mnGreen( nGreen ), 361 mnBlue( nBlue ) 362 { 363 } 364 365 RGBColor::RGBColor() : 366 maRGBTriple( 0.0, 0.0, 0.0 ) 367 { 368 } 369 370 RGBColor::RGBColor( ::cppcanvas::Color::IntSRGBA nRGBColor ) : 371 maRGBTriple( ::cppcanvas::getRed( nRGBColor ) / 255.0, 372 ::cppcanvas::getGreen( nRGBColor ) / 255.0, 373 ::cppcanvas::getBlue( nRGBColor ) / 255.0 ) 374 { 375 } 376 377 RGBColor::RGBColor( double nRed, double nGreen, double nBlue ) : 378 maRGBTriple( nRed, nGreen, nBlue ) 379 { 380 } 381 382 RGBColor::RGBColor( const HSLColor& rColor ) : 383 maRGBTriple( hsl2rgb( truncateRangeHue( rColor.getHue() ), 384 truncateRangeStd( rColor.getSaturation() ), 385 truncateRangeStd( rColor.getLuminance() ) ) ) 386 { 387 } 388 389 double RGBColor::getHue() const 390 { 391 return rgb2hsl( getRed(), 392 getGreen(), 393 getBlue() ).mnHue; 394 } 395 396 double RGBColor::getSaturation() const 397 { 398 return rgb2hsl( getRed(), 399 getGreen(), 400 getBlue() ).mnSaturation; 401 } 402 403 double RGBColor::getLuminance() const 404 { 405 return rgb2hsl( getRed(), 406 getGreen(), 407 getBlue() ).mnLuminance; 408 } 409 410 double RGBColor::getRed() const 411 { 412 return maRGBTriple.mnRed; 413 } 414 415 double RGBColor::getGreen() const 416 { 417 return maRGBTriple.mnGreen; 418 } 419 420 double RGBColor::getBlue() const 421 { 422 return maRGBTriple.mnBlue; 423 } 424 425 HSLColor RGBColor::getHSLColor() const 426 { 427 HSLColor::HSLTriple aColor( rgb2hsl( getRed(), 428 getGreen(), 429 getBlue() ) ); 430 return HSLColor( aColor.mnHue, aColor.mnSaturation, aColor.mnLuminance ); 431 } 432 433 ::cppcanvas::Color::IntSRGBA RGBColor::getIntegerColor() const 434 { 435 return ::cppcanvas::makeColor( colorToInt( getRed() ), 436 colorToInt( getGreen() ), 437 colorToInt( getBlue() ), 438 255 ); 439 } 440 441 RGBColor operator+( const RGBColor& rLHS, const RGBColor& rRHS ) 442 { 443 return RGBColor( rLHS.getRed() + rRHS.getRed(), 444 rLHS.getGreen() + rRHS.getGreen(), 445 rLHS.getBlue() + rRHS.getBlue() ); 446 } 447 448 RGBColor operator*( const RGBColor& rLHS, const RGBColor& rRHS ) 449 { 450 return RGBColor( rLHS.getRed() * rRHS.getRed(), 451 rLHS.getGreen() * rRHS.getGreen(), 452 rLHS.getBlue() * rRHS.getBlue() ); 453 } 454 455 RGBColor operator*( double nFactor, const RGBColor& rRHS ) 456 { 457 return RGBColor( nFactor * rRHS.getRed(), 458 nFactor * rRHS.getGreen(), 459 nFactor * rRHS.getBlue() ); 460 } 461 462 RGBColor interpolate( const RGBColor& rFrom, const RGBColor& rTo, double t ) 463 { 464 return RGBColor( (1.0-t)*rFrom.getRed() + t*rTo.getRed(), 465 (1.0-t)*rFrom.getGreen() + t*rTo.getGreen(), 466 (1.0-t)*rFrom.getBlue() + t*rTo.getBlue() ); 467 } 468 } 469 } 470