blob: 0ab5cd16a66fb6beed95940931e3092a13578e09 [file] [log] [blame]
/**************************************************************
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*************************************************************/
// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_slideshow.hxx"
#include <hslcolor.hxx>
#include <rgbcolor.hxx>
#include <basegfx/numeric/ftools.hxx>
#include <cmath> // for fmod
#include <algorithm>
namespace slideshow
{
namespace internal
{
namespace
{
// helper functions
// ================
double getMagic( double nLuminance, double nSaturation )
{
if( nLuminance <= 0.5 )
return nLuminance*(1.0 + nSaturation);
else
return nLuminance + nSaturation - nLuminance*nSaturation;
}
HSLColor::HSLTriple rgb2hsl( double nRed, double nGreen, double nBlue )
{
// r,g,b in [0,1], h in [0,360] and s,l in [0,1]
HSLColor::HSLTriple aRes;
const double nMax( ::std::max(nRed,::std::max(nGreen, nBlue)) );
const double nMin( ::std::min(nRed,::std::min(nGreen, nBlue)) );
const double nDelta( nMax - nMin );
aRes.mnLuminance = (nMax + nMin) / 2.0;
if( ::basegfx::fTools::equalZero( nDelta ) )
{
aRes.mnSaturation = 0.0;
// hue undefined (achromatic case)
aRes.mnHue = 0.0;
}
else
{
aRes.mnSaturation = aRes.mnLuminance > 0.5 ?
nDelta/(2.0-nMax-nMin) :
nDelta/(nMax + nMin);
if( nRed == nMax )
aRes.mnHue = (nGreen - nBlue)/nDelta;
else if( nGreen == nMax )
aRes.mnHue = 2.0 + (nBlue - nRed)/nDelta;
else if( nBlue == nMax )
aRes.mnHue = 4.0 + (nRed - nGreen)/nDelta;
aRes.mnHue *= 60.0;
if( aRes.mnHue < 0.0 )
aRes.mnHue += 360.0;
}
return aRes;
}
double hsl2rgbHelper( double nValue1, double nValue2, double nHue )
{
// clamp hue to [0,360]
nHue = fmod( nHue, 360.0 );
// cope with wrap-arounds
if( nHue < 0.0 )
nHue += 360.0;
if( nHue < 60.0 )
return nValue1 + (nValue2 - nValue1)*nHue/60.0;
else if( nHue < 180.0 )
return nValue2;
else if( nHue < 240.0 )
return nValue1 + (nValue2 - nValue1)*(240.0 - nHue)/60.0;
else
return nValue1;
}
RGBColor::RGBTriple hsl2rgb( double nHue, double nSaturation, double nLuminance )
{
if( ::basegfx::fTools::equalZero( nSaturation ) )
return RGBColor::RGBTriple(0.0, 0.0, nLuminance );
const double nVal1( getMagic(nLuminance, nSaturation) );
const double nVal2( 2.0*nLuminance - nVal1 );
RGBColor::RGBTriple aRes;
aRes.mnRed = hsl2rgbHelper( nVal2,
nVal1,
nHue + 120.0 );
aRes.mnGreen = hsl2rgbHelper( nVal2,
nVal1,
nHue );
aRes.mnBlue = hsl2rgbHelper( nVal2,
nVal1,
nHue - 120.0 );
return aRes;
}
/// Truncate range of value to [0,1]
double truncateRangeStd( double nVal )
{
return ::std::max( 0.0,
::std::min( 1.0,
nVal ) );
}
/// Truncate range of value to [0,360]
double truncateRangeHue( double nVal )
{
return ::std::max( 0.0,
::std::min( 360.0,
nVal ) );
}
/// convert RGB color to sal_uInt8, truncate range appropriately before
sal_uInt8 colorToInt( double nCol )
{
return static_cast< sal_uInt8 >(
::basegfx::fround( truncateRangeStd( nCol ) * 255.0 ) );
}
}
// HSLColor
// ===============================================
HSLColor::HSLTriple::HSLTriple() :
mnHue(),
mnSaturation(),
mnLuminance()
{
}
HSLColor::HSLTriple::HSLTriple( double nHue, double nSaturation, double nLuminance ) :
mnHue( nHue ),
mnSaturation( nSaturation ),
mnLuminance( nLuminance )
{
}
HSLColor::HSLColor() :
maHSLTriple( 0.0, 0.0, 0.0 ),
mnMagicValue( getMagic( maHSLTriple.mnLuminance,
maHSLTriple.mnSaturation ) )
{
}
HSLColor::HSLColor( ::cppcanvas::Color::IntSRGBA nRGBColor ) :
maHSLTriple( rgb2hsl( ::cppcanvas::getRed( nRGBColor ) / 255.0,
::cppcanvas::getGreen( nRGBColor ) / 255.0,
::cppcanvas::getBlue( nRGBColor ) / 255.0 ) ),
mnMagicValue( getMagic( maHSLTriple.mnLuminance,
maHSLTriple.mnSaturation ) )
{
}
HSLColor::HSLColor( double nHue, double nSaturation, double nLuminance ) :
maHSLTriple( nHue, nSaturation, nLuminance ),
mnMagicValue( getMagic( maHSLTriple.mnLuminance,
maHSLTriple.mnSaturation ) )
{
}
HSLColor::HSLColor( const RGBColor& rColor ) :
maHSLTriple( rgb2hsl( truncateRangeStd( rColor.getRed() ),
truncateRangeStd( rColor.getGreen() ),
truncateRangeStd( rColor.getBlue() ) ) ),
mnMagicValue( getMagic( maHSLTriple.mnLuminance,
maHSLTriple.mnSaturation ) )
{
}
double HSLColor::getHue() const
{
return maHSLTriple.mnHue;
}
double HSLColor::getSaturation() const
{
return maHSLTriple.mnSaturation;
}
double HSLColor::getLuminance() const
{
return maHSLTriple.mnLuminance;
}
double HSLColor::getRed() const
{
if( ::basegfx::fTools::equalZero( getSaturation() ) )
return getLuminance();
return hsl2rgbHelper( 2.0*getLuminance() - mnMagicValue,
mnMagicValue,
getHue() + 120.0 );
}
double HSLColor::getGreen() const
{
if( ::basegfx::fTools::equalZero( getSaturation() ) )
return getLuminance();
return hsl2rgbHelper( 2.0*getLuminance() - mnMagicValue,
mnMagicValue,
getHue() );
}
double HSLColor::getBlue() const
{
if( ::basegfx::fTools::equalZero( getSaturation() ) )
return getLuminance();
return hsl2rgbHelper( 2.0*getLuminance() - mnMagicValue,
mnMagicValue,
getHue() - 120.0 );
}
RGBColor HSLColor::getRGBColor() const
{
RGBColor::RGBTriple aColor( hsl2rgb( getHue(),
getSaturation(),
getLuminance() ) );
return RGBColor( aColor.mnRed, aColor.mnGreen, aColor.mnBlue );
}
RGBColor::RGBColor(const RGBColor& rLHS)
{
maRGBTriple.mnRed = rLHS.getRed();
maRGBTriple.mnGreen = rLHS.getGreen();
maRGBTriple.mnBlue = rLHS.getBlue();
}
RGBColor& RGBColor::operator=( const RGBColor& rLHS ){
maRGBTriple.mnRed = rLHS.getRed();
maRGBTriple.mnGreen = rLHS.getGreen();
maRGBTriple.mnBlue = rLHS.getBlue();
return *this;
}
HSLColor operator+( const HSLColor& rLHS, const HSLColor& rRHS )
{
return HSLColor( rLHS.getHue() + rRHS.getHue(),
rLHS.getSaturation() + rRHS.getSaturation(),
rLHS.getLuminance() + rRHS.getLuminance() );
}
HSLColor operator*( const HSLColor& rLHS, const HSLColor& rRHS )
{
return HSLColor( rLHS.getHue() * rRHS.getHue(),
rLHS.getSaturation() * rRHS.getSaturation(),
rLHS.getLuminance() * rRHS.getLuminance() );
}
HSLColor operator*( double nFactor, const HSLColor& rRHS )
{
return HSLColor( nFactor * rRHS.getHue(),
nFactor * rRHS.getSaturation(),
nFactor * rRHS.getLuminance() );
}
HSLColor interpolate( const HSLColor& rFrom, const HSLColor& rTo, double t, bool bCCW )
{
const double nFromHue( rFrom.getHue() );
const double nToHue ( rTo.getHue() );
double nHue=0.0;
if( nFromHue <= nToHue && !bCCW )
{
// interpolate hue clockwise. That is, hue starts at
// high values and ends at low ones. Therefore, we
// must 'cross' the 360 degrees and start at low
// values again (imagine the hues to lie on the
// circle, where values above 360 degrees are mapped
// back to [0,360)).
nHue = (1.0-t)*(nFromHue + 360.0) + t*nToHue;
}
else if( nFromHue > nToHue && bCCW )
{
// interpolate hue counter-clockwise. That is, hue
// starts at high values and ends at low
// ones. Therefore, we must 'cross' the 360 degrees
// and start at low values again (imagine the hues to
// lie on the circle, where values above 360 degrees
// are mapped back to [0,360)).
nHue = (1.0-t)*nFromHue + t*(nToHue + 360.0);
}
else
{
// interpolate hue counter-clockwise. That is, hue
// starts at low values and ends at high ones (imagine
// the hue value as degrees on a circle, with
// increasing values going counter-clockwise)
nHue = (1.0-t)*nFromHue + t*nToHue;
}
return HSLColor( nHue,
(1.0-t)*rFrom.getSaturation() + t*rTo.getSaturation(),
(1.0-t)*rFrom.getLuminance() + t*rTo.getLuminance() );
}
// RGBColor
// ===============================================
RGBColor::RGBTriple::RGBTriple() :
mnRed(),
mnGreen(),
mnBlue()
{
}
RGBColor::RGBTriple::RGBTriple( double nRed, double nGreen, double nBlue ) :
mnRed( nRed ),
mnGreen( nGreen ),
mnBlue( nBlue )
{
}
RGBColor::RGBColor() :
maRGBTriple( 0.0, 0.0, 0.0 )
{
}
RGBColor::RGBColor( ::cppcanvas::Color::IntSRGBA nRGBColor ) :
maRGBTriple( ::cppcanvas::getRed( nRGBColor ) / 255.0,
::cppcanvas::getGreen( nRGBColor ) / 255.0,
::cppcanvas::getBlue( nRGBColor ) / 255.0 )
{
}
RGBColor::RGBColor( double nRed, double nGreen, double nBlue ) :
maRGBTriple( nRed, nGreen, nBlue )
{
}
RGBColor::RGBColor( const HSLColor& rColor ) :
maRGBTriple( hsl2rgb( truncateRangeHue( rColor.getHue() ),
truncateRangeStd( rColor.getSaturation() ),
truncateRangeStd( rColor.getLuminance() ) ) )
{
}
double RGBColor::getHue() const
{
return rgb2hsl( getRed(),
getGreen(),
getBlue() ).mnHue;
}
double RGBColor::getSaturation() const
{
return rgb2hsl( getRed(),
getGreen(),
getBlue() ).mnSaturation;
}
double RGBColor::getLuminance() const
{
return rgb2hsl( getRed(),
getGreen(),
getBlue() ).mnLuminance;
}
double RGBColor::getRed() const
{
return maRGBTriple.mnRed;
}
double RGBColor::getGreen() const
{
return maRGBTriple.mnGreen;
}
double RGBColor::getBlue() const
{
return maRGBTriple.mnBlue;
}
HSLColor RGBColor::getHSLColor() const
{
HSLColor::HSLTriple aColor( rgb2hsl( getRed(),
getGreen(),
getBlue() ) );
return HSLColor( aColor.mnHue, aColor.mnSaturation, aColor.mnLuminance );
}
::cppcanvas::Color::IntSRGBA RGBColor::getIntegerColor() const
{
return ::cppcanvas::makeColor( colorToInt( getRed() ),
colorToInt( getGreen() ),
colorToInt( getBlue() ),
255 );
}
RGBColor operator+( const RGBColor& rLHS, const RGBColor& rRHS )
{
return RGBColor( rLHS.getRed() + rRHS.getRed(),
rLHS.getGreen() + rRHS.getGreen(),
rLHS.getBlue() + rRHS.getBlue() );
}
RGBColor operator*( const RGBColor& rLHS, const RGBColor& rRHS )
{
return RGBColor( rLHS.getRed() * rRHS.getRed(),
rLHS.getGreen() * rRHS.getGreen(),
rLHS.getBlue() * rRHS.getBlue() );
}
RGBColor operator*( double nFactor, const RGBColor& rRHS )
{
return RGBColor( nFactor * rRHS.getRed(),
nFactor * rRHS.getGreen(),
nFactor * rRHS.getBlue() );
}
RGBColor interpolate( const RGBColor& rFrom, const RGBColor& rTo, double t )
{
return RGBColor( (1.0-t)*rFrom.getRed() + t*rTo.getRed(),
(1.0-t)*rFrom.getGreen() + t*rTo.getGreen(),
(1.0-t)*rFrom.getBlue() + t*rTo.getBlue() );
}
}
}