/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* This file is part of the LibreOffice project.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* This file incorporates work covered by the following license notice:
*
* 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 .
*/
#include <sal/config.h>
#include <algorithm>
#include <float.h>
#include <basegfx/color/bcolormodifier.hxx>
#include <comphelper/random.hxx>
namespace basegfx
{
BColorModifier::~BColorModifier()
{
}
BColorModifier_gray::~BColorModifier_gray()
{
}
::basegfx::BColor BColorModifier_gray::getModifiedColor(const ::basegfx::BColor& aSourceColor) const
{
const double fLuminance(aSourceColor.luminance());
return ::basegfx::BColor(fLuminance, fLuminance, fLuminance);
}
OUString BColorModifier_gray::getModifierName() const
{
return u"gray"_ustr;
}
BColorModifier_invert::~BColorModifier_invert()
{
}
::basegfx::BColor BColorModifier_invert::getModifiedColor(const ::basegfx::BColor& aSourceColor) const
{
return ::basegfx::BColor(1.0 - aSourceColor.getRed(), 1.0 - aSourceColor.getGreen(), 1.0 - aSourceColor.getBlue());
}
OUString BColorModifier_invert::getModifierName() const
{
return u"invert"_ustr;
}
BColorModifier_luminance_to_alpha::~BColorModifier_luminance_to_alpha()
{
}
::basegfx::BColor BColorModifier_luminance_to_alpha::getModifiedColor(const ::basegfx::BColor& aSourceColor) const
{
const double fAlpha(1.0 - ((aSourceColor.getRed() * 0.2125) + (aSourceColor.getGreen() * 0.7154) + (aSourceColor.getBlue() * 0.0721)));
return ::basegfx::BColor(fAlpha, fAlpha, fAlpha);
}
OUString BColorModifier_luminance_to_alpha::getModifierName() const
{
return u"luminance_to_alpha"_ustr;
}
BColorModifier_replace::~BColorModifier_replace()
{
}
bool BColorModifier_replace::operator==(const BColorModifier& rCompare) const
{
if (!BColorModifier::operator==(rCompare))
return false;
const BColorModifier_replace* pCompare(static_cast< const BColorModifier_replace* >(&rCompare));
return getBColor() == pCompare->getBColor();
}
::basegfx::BColor BColorModifier_replace::getModifiedColor(const ::basegfx::BColor& /*aSourceColor*/) const
{
return maBColor;
}
OUString BColorModifier_replace::getModifierName() const
{
return u"replace"_ustr;
}
BColorModifier_interpolate::~BColorModifier_interpolate()
{
}
bool BColorModifier_interpolate::operator==(const BColorModifier& rCompare) const
{
if (!BColorModifier::operator==(rCompare))
return false;
const BColorModifier_interpolate* pCompare(static_cast< const BColorModifier_interpolate* >(&rCompare));
return maBColor == pCompare->maBColor && mfValue == pCompare->mfValue;
}
::basegfx::BColor BColorModifier_interpolate::getModifiedColor(const ::basegfx::BColor& aSourceColor) const
{
return interpolate(maBColor, aSourceColor, mfValue);
}
OUString BColorModifier_interpolate::getModifierName() const
{
return u"interpolate"_ustr;
}
BColorModifier_matrix::~BColorModifier_matrix()
{
}
bool BColorModifier_matrix::operator==(const BColorModifier& rCompare) const
{
if (!BColorModifier::operator==(rCompare))
return false;
const BColorModifier_matrix* pCompare(static_cast< const BColorModifier_matrix* >(&rCompare));
return maVector == pCompare->maVector;
}
::basegfx::BColor BColorModifier_matrix::getModifiedColor(const ::basegfx::BColor& aSourceColor) const
{
if (maVector.size() != 20)
return aSourceColor;
const double aRed = maVector[0] * aSourceColor.getRed()
+ maVector[1] * aSourceColor.getGreen()
+ maVector[2] * aSourceColor.getBlue()
+ maVector[3] * 1.0
+ maVector[4];
const double aGreen = maVector[5] * aSourceColor.getRed()
+ maVector[6] * aSourceColor.getGreen()
+ maVector[7] * aSourceColor.getBlue()
+ maVector[8] * 1.0
+ maVector[9];
const double aBlue = maVector[10] * aSourceColor.getRed()
+ maVector[11] * aSourceColor.getGreen()
+ maVector[12] * aSourceColor.getBlue()
+ maVector[13] * 1.0
+ maVector[14];
/*TODO: add support for alpha
const double aAlpha = maVector[15] * aSourceColor.getRed()
+ maVector[16] * aSourceColor.getGreen()
+ maVector[17] * aSourceColor.getBlue()
+ maVector[18] * 1.0
+ maVector[19]);
*/
return ::basegfx::BColor(
std::clamp(aRed, 0.0, 1.0),
std::clamp(aGreen, 0.0, 1.0),
std::clamp(aBlue, 0.0, 1.0));
}
OUString BColorModifier_matrix::getModifierName() const
{
return u"matrix"_ustr;
}
BColorModifier_saturate::BColorModifier_saturate(double fValue)
: BColorModifier(basegfx::BColorModifierType::BCMType_saturate)
{
maSatMatrix.set(0, 0, 0.213 + 0.787 * fValue);
maSatMatrix.set(0, 1, 0.715 - 0.715 * fValue);
maSatMatrix.set(0, 2, 0.072 - 0.072 * fValue);
maSatMatrix.set(1, 0, 0.213 - 0.213 * fValue);
maSatMatrix.set(1, 1, 0.715 + 0.285 * fValue);
maSatMatrix.set(1, 2, 0.072 - 0.072 * fValue);
maSatMatrix.set(2, 0, 0.213 - 0.213 * fValue);
maSatMatrix.set(2, 1, 0.715 - 0.715 * fValue);
maSatMatrix.set(2, 2, 0.072 + 0.928 * fValue);
}
BColorModifier_saturate::~BColorModifier_saturate()
{
}
bool BColorModifier_saturate::operator==(const BColorModifier& rCompare) const
{
if (!BColorModifier::operator==(rCompare))
return false;
const BColorModifier_saturate* pCompare(static_cast< const BColorModifier_saturate* >(&rCompare));
return maSatMatrix == pCompare->maSatMatrix;
}
::basegfx::BColor BColorModifier_saturate::getModifiedColor(const ::basegfx::BColor& aSourceColor) const
{
basegfx::B3DHomMatrix aColorMatrix;
aColorMatrix.set(0, 0, aSourceColor.getRed());
aColorMatrix.set(1, 0, aSourceColor.getGreen());
aColorMatrix.set(2, 0, aSourceColor.getBlue());
aColorMatrix = maSatMatrix * aColorMatrix;
return ::basegfx::BColor(aColorMatrix.get(0, 0), aColorMatrix.get(1, 0), aColorMatrix.get(2, 0));
}
OUString BColorModifier_saturate::getModifierName() const
{
return u"saturate"_ustr;
}
BColorModifier_hueRotate::BColorModifier_hueRotate(double fRad)
: BColorModifier(basegfx::BColorModifierType::BCMType_hueRotate)
{
const double fCos = cos(fRad);
const double fSin = sin(fRad);
maHueMatrix.set(0, 0, 0.213 + fCos * 0.787 - fSin * 0.213);
maHueMatrix.set(0, 1, 0.715 - fCos * 0.715 - fSin * 0.715);
maHueMatrix.set(0, 2, 0.072 - fCos * 0.072 + fSin * 0.928);
maHueMatrix.set(1, 0, 0.213 - fCos * 0.213 + fSin * 0.143);
maHueMatrix.set(1, 1, 0.715 + fCos * 0.285 + fSin * 0.140);
maHueMatrix.set(1, 2, 0.072 - fCos * 0.072 - fSin * 0.283);
maHueMatrix.set(2, 0, 0.213 - fCos * 0.213 - fSin * 0.787);
maHueMatrix.set(2, 1, 0.715 - fCos * 0.715 + fSin * 0.715);
maHueMatrix.set(2, 2, 0.072 + fCos * 0.928 + fSin * 0.072);
}
BColorModifier_hueRotate::~BColorModifier_hueRotate()
{
}
bool BColorModifier_hueRotate::operator==(const BColorModifier& rCompare) const
{
if (!BColorModifier::operator==(rCompare))
return false;
const BColorModifier_hueRotate* pCompare(static_cast< const BColorModifier_hueRotate* >(&rCompare));
return maHueMatrix == pCompare->maHueMatrix;
}
::basegfx::BColor BColorModifier_hueRotate::getModifiedColor(const ::basegfx::BColor& aSourceColor) const
{
basegfx::B3DHomMatrix aColorMatrix;
aColorMatrix.set(0, 0, aSourceColor.getRed());
aColorMatrix.set(1, 0, aSourceColor.getGreen());
aColorMatrix.set(2, 0, aSourceColor.getBlue());
aColorMatrix = maHueMatrix * aColorMatrix;
return ::basegfx::BColor(
std::clamp(aColorMatrix.get(0, 0), 0.0, 1.0),
std::clamp(aColorMatrix.get(1, 0), 0.0, 1.0),
std::clamp(aColorMatrix.get(2, 0), 0.0, 1.0));
}
OUString BColorModifier_hueRotate::getModifierName() const
{
return u"hueRotate"_ustr;
}
BColorModifier_black_and_white::~BColorModifier_black_and_white()
{
}
bool BColorModifier_black_and_white::operator==(const BColorModifier& rCompare) const
{
if (!BColorModifier::operator==(rCompare))
return false;
const BColorModifier_black_and_white* pCompare(static_cast< const BColorModifier_black_and_white* >(&rCompare));
return mfValue == pCompare->mfValue;
}
::basegfx::BColor BColorModifier_black_and_white::getModifiedColor(const ::basegfx::BColor& aSourceColor) const
{
const double fLuminance(aSourceColor.luminance());
if(fLuminance < mfValue)
{
return ::basegfx::BColor::getEmptyBColor();
}
else
{
return ::basegfx::BColor(1.0, 1.0, 1.0);
}
}
OUString BColorModifier_black_and_white::getModifierName() const
{
return u"black_and_white"_ustr;
}
BColorModifier_gamma::BColorModifier_gamma(double fValue)
: BColorModifier(basegfx::BColorModifierType::BCMType_gamma)
, mfValue(fValue)
, mfInvValue(fValue)
, mbUseIt(!basegfx::fTools::equal(fValue, 1.0) && fValue > 0.0 && basegfx::fTools::lessOrEqual(fValue, 10.0))
{
if(mbUseIt)
{
mfInvValue = 1.0 / mfValue;
}
}
BColorModifier_gamma::~BColorModifier_gamma()
{
}
bool BColorModifier_gamma::operator==(const BColorModifier& rCompare) const
{
if (!BColorModifier::operator==(rCompare))
return false;
const BColorModifier_gamma* pCompare(static_cast< const BColorModifier_gamma* >(&rCompare));
// mfValue is sufficient, mfInvValue and mbUseIt are only helper values
return mfValue == pCompare->mfValue;
}
::basegfx::BColor BColorModifier_gamma::getModifiedColor(const ::basegfx::BColor& aSourceColor) const
{
if(mbUseIt)
{
::basegfx::BColor aRetval(
pow(aSourceColor.getRed(), mfInvValue),
pow(aSourceColor.getGreen(), mfInvValue),
pow(aSourceColor.getBlue(), mfInvValue));
aRetval.clamp();
return aRetval;
}
else
{
return aSourceColor;
}
}
OUString BColorModifier_gamma::getModifierName() const
{
return u"gamma"_ustr;
}
BColorModifier_RGBLuminanceContrast::BColorModifier_RGBLuminanceContrast(double fRed, double fGreen, double fBlue, double fLuminance, double fContrast)
: BColorModifier(basegfx::BColorModifierType::BCMType_RGBLuminanceContrast)
, mfRed(std::clamp(fRed, -1.0, 1.0))
, mfGreen(std::clamp(fGreen, -1.0, 1.0))
, mfBlue(std::clamp(fBlue, -1.0, 1.0))
, mfLuminance(std::clamp(fLuminance, -1.0, 1.0))
, mfContrast(std::clamp(fContrast, -1.0, 1.0))
, mfContrastOff(1.0)
, mfRedOff(0.0)
, mfGreenOff(0.0)
, mfBlueOff(0.0)
, mbUseIt(false)
{
if(basegfx::fTools::equalZero(mfRed)
&& basegfx::fTools::equalZero(mfGreen)
&& basegfx::fTools::equalZero(mfBlue)
&& basegfx::fTools::equalZero(mfLuminance)
&& basegfx::fTools::equalZero(mfContrast))
return;
// calculate slope
if(mfContrast >= 0.0)
{
mfContrastOff = 128.0 / (128.0 - (mfContrast * 127.0));
}
else
{
mfContrastOff = ( 128.0 + (mfContrast * 127.0)) / 128.0;
}
// calculate unified contrast offset
const double fPreparedContrastOff((128.0 - mfContrastOff * 128.0) / 255.0);
const double fCombinedOffset(mfLuminance + fPreparedContrastOff);
// set full offsets
mfRedOff = mfRed + fCombinedOffset;
mfGreenOff = mfGreen + fCombinedOffset;
mfBlueOff = mfBlue + fCombinedOffset;
mbUseIt = true;
}
BColorModifier_RGBLuminanceContrast::~BColorModifier_RGBLuminanceContrast()
{
}
bool BColorModifier_RGBLuminanceContrast::operator==(const BColorModifier& rCompare) const
{
if (!BColorModifier::operator==(rCompare))
return false;
const BColorModifier_RGBLuminanceContrast* pCompare(static_cast< const BColorModifier_RGBLuminanceContrast* >(&rCompare));
// no need to compare other values, these are just helpers
return mfRed == pCompare->mfRed
&& mfGreen == pCompare->mfGreen
&& mfBlue == pCompare->mfBlue
&& mfLuminance == pCompare->mfLuminance
&& mfContrast == pCompare->mfContrast;
}
::basegfx::BColor BColorModifier_RGBLuminanceContrast::getModifiedColor(const ::basegfx::BColor& aSourceColor) const
{
if(mbUseIt)
{
return basegfx::BColor(
std::clamp(aSourceColor.getRed() * mfContrastOff + mfRedOff, 0.0, 1.0),
std::clamp(aSourceColor.getGreen() * mfContrastOff + mfGreenOff, 0.0, 1.0),
std::clamp(aSourceColor.getBlue() * mfContrastOff + mfBlueOff, 0.0, 1.0));
}
else
{
return aSourceColor;
}
}
OUString BColorModifier_RGBLuminanceContrast::getModifierName() const
{
return u"RGBLuminanceContrast"_ustr;
}
BColorModifier_randomize::BColorModifier_randomize(double fRandomPart)
: BColorModifier(basegfx::BColorModifierType::BCMType_randomize)
, mfRandomPart(fRandomPart)
{
}
BColorModifier_randomize::~BColorModifier_randomize()
{
}
// compare operator
bool BColorModifier_randomize::operator==(const BColorModifier& rCompare) const
{
if (!BColorModifier::operator==(rCompare))
return false;
const BColorModifier_randomize* pCompare(static_cast< const BColorModifier_randomize* >(&rCompare));
return mfRandomPart == pCompare->mfRandomPart;
}
// compute modified color
::basegfx::BColor BColorModifier_randomize::getModifiedColor(const ::basegfx::BColor& aSourceColor) const
{
if(0.0 >= mfRandomPart)
{
// no randomizing, use orig color
return aSourceColor;
}
if(1.0 <= mfRandomPart)
{
// full randomized color
return basegfx::BColor(
comphelper::rng::uniform_real_distribution(0.0, nextafter(1.0, DBL_MAX)),
comphelper::rng::uniform_real_distribution(0.0, nextafter(1.0, DBL_MAX)),
comphelper::rng::uniform_real_distribution(0.0, nextafter(1.0, DBL_MAX)));
}
// mixed color
const double fMulA(1.0 - mfRandomPart);
return basegfx::BColor(
aSourceColor.getRed() * fMulA +
comphelper::rng::uniform_real_distribution(0.0, nextafter(mfRandomPart, DBL_MAX)),
aSourceColor.getGreen() * fMulA +
comphelper::rng::uniform_real_distribution(0.0, nextafter(mfRandomPart, DBL_MAX)),
aSourceColor.getBlue() * fMulA +
comphelper::rng::uniform_real_distribution(0.0, nextafter(mfRandomPart, DBL_MAX)));
}
OUString BColorModifier_randomize::getModifierName() const
{
return u"randomize"_ustr;
}
::basegfx::BColor BColorModifierStack::getModifiedColor(const ::basegfx::BColor& rSource) const
{
if(maBColorModifiers.empty())
{
return rSource;
}
::basegfx::BColor aRetval(rSource);
for(sal_uInt32 a(maBColorModifiers.size()); a;)
{
a--;
aRetval = maBColorModifiers[a]->getModifiedColor(aRetval);
}
return aRetval;
}
bool BColorModifierStack::operator==(const BColorModifierStack& rComp) const
{
if (count() != rComp.count())
return false;
if (0 == count())
return true;
for (sal_uInt32 a(0); a < count(); a++)
{
// nullptrs are not allowed/expected
assert(maBColorModifiers[a] != nullptr);
assert(rComp.maBColorModifiers[a] != nullptr);
if (!(*maBColorModifiers[a] == *rComp.maBColorModifiers[a]))
return false;
}
return true;
}
} // end of namespace basegfx
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
↑ V530 The return value of function 'clamp' is required to be utilized.
↑ V681 The language standard does not define an order in which the 'nextafter' functions will be called during evaluation of arguments.
↑ V681 The language standard does not define an order in which the 'nextafter' functions will be called during evaluation of arguments.