blob: fa7596e6cc355df1230781151216c66527dc69df [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_basegfx.hxx"
#include <basegfx/numeric/ftools.hxx>
#include <basegfx/color/bcolor.hxx>
#include <basegfx/color/bcolortools.hxx>
//////////////////////////////////////////////////////////////////////////////
namespace basegfx { namespace tools
{
BColor rgb2hsl(const BColor& rRGBColor)
{
const double r=rRGBColor.getRed(), g=rRGBColor.getGreen(), b=rRGBColor.getBlue();
const double minVal = ::std::min( ::std::min( r, g ), b );
const double maxVal = ::std::max( ::std::max( r, g ), b );
const double d = maxVal - minVal;
double h=0, s=0, l=0;
l = (maxVal + minVal) / 2.0;
if( ::basegfx::fTools::equalZero(d) )
{
s = h = 0; // hue undefined (achromatic case)
}
else
{
s = l > 0.5 ? d/(2.0-maxVal-minVal) :
d/(maxVal + minVal);
if( r == maxVal )
h = (g - b)/d;
else if( g == maxVal )
h = 2.0 + (b - r)/d;
else
h = 4.0 + (r - g)/d;
h *= 60.0;
if( h < 0.0 )
h += 360.0;
}
return BColor(h,s,l);
}
static inline 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;
}
BColor hsl2rgb(const BColor& rHSLColor)
{
const double h=rHSLColor.getRed(), s=rHSLColor.getGreen(), l=rHSLColor.getBlue();
if( fTools::equalZero(s) )
return BColor(l, l, l ); // achromatic case
const double nVal1( l <= 0.5 ? l*(1.0 + s) : l + s - l*s );
const double nVal2( 2.0*l - nVal1 );
return BColor(
hsl2rgbHelper(nVal2,
nVal1,
h + 120.0),
hsl2rgbHelper(nVal2,
nVal1,
h),
hsl2rgbHelper(nVal2,
nVal1,
h - 120.0) );
}
BColor rgb2hsv(const BColor& rRGBColor)
{
const double r=rRGBColor.getRed(), g=rRGBColor.getGreen(), b=rRGBColor.getBlue();
const double maxVal = std::max(std::max(r,g),b);
const double minVal = std::min(std::min(r,g),b);
const double delta = maxVal-minVal;
double h=0, s=0, v=0;
v = maxVal;
if( fTools::equalZero(v) )
s = 0;
else
s = delta / v;
if( !fTools::equalZero(s) )
{
if( maxVal == r )
{
h = (g - b) / delta;
}
else if( maxVal == g )
{
h = 2.0 + (b - r) / delta;
}
else
{
h = 4.0 + (r - g) / delta;
}
h *= 60.0;
if( h < 0 )
h += 360;
}
return BColor(h,s,v);
}
BColor hsv2rgb(const BColor& rHSVColor)
{
double h=rHSVColor.getRed();
const double s=rHSVColor.getGreen(), v=rHSVColor.getBlue();
if( fTools::equalZero(s) )
{
// achromatic case: no hue.
return BColor(v,v,v);
}
else
{
if( fTools::equal(h,360) )
h = 0; // 360 degrees is equivalent to 0 degrees
h /= 60.0;
const sal_Int32 intval = static_cast< sal_Int32 >( h );
const double f = h - intval;
const double p = v*(1.0-s);
const double q = v*(1.0-(s*f));
const double t = v*(1.0-(s*(1.0-f)));
/* which hue area? */
switch( intval )
{
case 0:
return BColor(v,t,p);
case 1:
return BColor(q,v,p);
case 2:
return BColor(p,v,t);
case 3:
return BColor(p,q,v);
case 4:
return BColor(t,p,v);
case 5:
return BColor(v,p,q);
default:
// hue overflow
return BColor();
}
}
}
BColor rgb2yiq(const BColor& rRGBColor)
{
// from Foley, van Dam, Computer Graphics
const double r=rRGBColor.getRed(), g=rRGBColor.getGreen(), b=rRGBColor.getBlue();
return BColor(
0.299*r + 0.587*g + 0.114*b,
0.596*r - 0.274*g - 0.322*b,
0.211*r - 0.522*g + 0.311*b);
}
BColor yiq2rgb(const BColor& rYIQColor)
{
// from Foley, van Dam, Computer Graphics
const double y=rYIQColor.getRed(), i=rYIQColor.getGreen(), q=rYIQColor.getBlue();
return BColor(
y + 0.956*i + 0.623*q,
y - 0.272*i - 0.648*q,
y - 1.105*i + 1.705*q );
}
BColor ciexyz2rgb( const BColor& rXYZColor )
{
// from Poynton color faq, and SMPTE RP 177-1993, Derivation
// of Basic Television Color Equations
const double x=rXYZColor.getRed(), y=rXYZColor.getGreen(), z=rXYZColor.getBlue();
return BColor(
3.240479*x - 1.53715*y - 0.498535*z,
-0.969256*x + 1.875991*y + 0.041556*z,
0.055648*x - 0.204043*y + 1.057311*z );
}
BColor rgb2ciexyz( const BColor& rRGBColor )
{
// from Poynton color faq, and SMPTE RP 177-1993, Derivation
// of Basic Television Color Equations
const double r=rRGBColor.getRed(), g=rRGBColor.getGreen(), b=rRGBColor.getBlue();
return BColor(
0.412453*r + 0.35758*g + 0.180423*b,
0.212671*r + 0.71516*g + 0.072169*b,
0.019334*r + 0.119193*g + 0.950227*b);
}
BColor rgb2ypbpr(const BColor& rRGBColor)
{
const double r=rRGBColor.getRed(), g=rRGBColor.getGreen(), b=rRGBColor.getBlue();
return BColor(
0.299*r + 0.587*g + 0.114*b,
-0.168736*r - 0.331264*g + 0.5*b,
0.5*r - 0.418688*g - 0.081312*b);
}
BColor ypbpr2rgb(const BColor& rYPbPrColor)
{
const double y=rYPbPrColor.getRed(), pb=rYPbPrColor.getGreen(), pr=rYPbPrColor.getBlue();
return BColor(
1.*y + 0.*pb + 1.402*pr,
1.*y - 0.344136*pb - 0.714136*pr,
1.*y + 1.772*pb + 0.*pr);
}
} } // end of namespace basegfx
//////////////////////////////////////////////////////////////////////////////
// eof