Get the style color and number just once
[LibreOffice.git] / basegfx / source / color / bcolormodifier.cxx
blobe0e0ebbd6203a55c07749160882eb0cbe4c8dee8
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <sal/config.h>
21 #include <algorithm>
22 #include <float.h>
23 #include <basegfx/color/bcolormodifier.hxx>
24 #include <comphelper/random.hxx>
26 namespace basegfx
28 BColorModifier::~BColorModifier()
32 BColorModifier_gray::~BColorModifier_gray()
36 ::basegfx::BColor BColorModifier_gray::getModifiedColor(const ::basegfx::BColor& aSourceColor) const
38 const double fLuminance(aSourceColor.luminance());
40 return ::basegfx::BColor(fLuminance, fLuminance, fLuminance);
43 OUString BColorModifier_gray::getModifierName() const
45 return u"gray"_ustr;
48 BColorModifier_invert::~BColorModifier_invert()
52 ::basegfx::BColor BColorModifier_invert::getModifiedColor(const ::basegfx::BColor& aSourceColor) const
54 return ::basegfx::BColor(1.0 - aSourceColor.getRed(), 1.0 - aSourceColor.getGreen(), 1.0 - aSourceColor.getBlue());
57 OUString BColorModifier_invert::getModifierName() const
59 return u"invert"_ustr;
62 BColorModifier_luminance_to_alpha::~BColorModifier_luminance_to_alpha()
66 ::basegfx::BColor BColorModifier_luminance_to_alpha::getModifiedColor(const ::basegfx::BColor& aSourceColor) const
68 const double fAlpha(1.0 - ((aSourceColor.getRed() * 0.2125) + (aSourceColor.getGreen() * 0.7154) + (aSourceColor.getBlue() * 0.0721)));
70 return ::basegfx::BColor(fAlpha, fAlpha, fAlpha);
73 OUString BColorModifier_luminance_to_alpha::getModifierName() const
75 return u"luminance_to_alpha"_ustr;
78 BColorModifier_replace::~BColorModifier_replace()
82 bool BColorModifier_replace::operator==(const BColorModifier& rCompare) const
84 if (!BColorModifier::operator==(rCompare))
85 return false;
87 const BColorModifier_replace* pCompare(static_cast< const BColorModifier_replace* >(&rCompare));
88 return getBColor() == pCompare->getBColor();
91 ::basegfx::BColor BColorModifier_replace::getModifiedColor(const ::basegfx::BColor& /*aSourceColor*/) const
93 return maBColor;
96 OUString BColorModifier_replace::getModifierName() const
98 return u"replace"_ustr;
101 BColorModifier_interpolate::~BColorModifier_interpolate()
105 bool BColorModifier_interpolate::operator==(const BColorModifier& rCompare) const
107 if (!BColorModifier::operator==(rCompare))
108 return false;
110 const BColorModifier_interpolate* pCompare(static_cast< const BColorModifier_interpolate* >(&rCompare));
111 return maBColor == pCompare->maBColor && mfValue == pCompare->mfValue;
114 ::basegfx::BColor BColorModifier_interpolate::getModifiedColor(const ::basegfx::BColor& aSourceColor) const
116 return interpolate(maBColor, aSourceColor, mfValue);
119 OUString BColorModifier_interpolate::getModifierName() const
121 return u"interpolate"_ustr;
124 BColorModifier_matrix::~BColorModifier_matrix()
128 bool BColorModifier_matrix::operator==(const BColorModifier& rCompare) const
130 if (!BColorModifier::operator==(rCompare))
131 return false;
133 const BColorModifier_matrix* pCompare(static_cast< const BColorModifier_matrix* >(&rCompare));
134 return maVector == pCompare->maVector;
137 ::basegfx::BColor BColorModifier_matrix::getModifiedColor(const ::basegfx::BColor& aSourceColor) const
139 if (maVector.size() != 20)
140 return aSourceColor;
142 const double aRed = maVector[0] * aSourceColor.getRed()
143 + maVector[1] * aSourceColor.getGreen()
144 + maVector[2] * aSourceColor.getBlue()
145 + maVector[3] * 1.0
146 + maVector[4];
147 const double aGreen = maVector[5] * aSourceColor.getRed()
148 + maVector[6] * aSourceColor.getGreen()
149 + maVector[7] * aSourceColor.getBlue()
150 + maVector[8] * 1.0
151 + maVector[9];
152 const double aBlue = maVector[10] * aSourceColor.getRed()
153 + maVector[11] * aSourceColor.getGreen()
154 + maVector[12] * aSourceColor.getBlue()
155 + maVector[13] * 1.0
156 + maVector[14];
157 /*TODO: add support for alpha
158 const double aAlpha = maVector[15] * aSourceColor.getRed()
159 + maVector[16] * aSourceColor.getGreen()
160 + maVector[17] * aSourceColor.getBlue()
161 + maVector[18] * 1.0
162 + maVector[19]);
165 return ::basegfx::BColor(
166 std::clamp(aRed, 0.0, 1.0),
167 std::clamp(aGreen, 0.0, 1.0),
168 std::clamp(aBlue, 0.0, 1.0));
171 OUString BColorModifier_matrix::getModifierName() const
173 return u"matrix"_ustr;
176 BColorModifier_saturate::BColorModifier_saturate(double fValue)
177 : BColorModifier(basegfx::BColorModifierType::BCMType_saturate)
179 maSatMatrix.set(0, 0, 0.213 + 0.787 * fValue);
180 maSatMatrix.set(0, 1, 0.715 - 0.715 * fValue);
181 maSatMatrix.set(0, 2, 0.072 - 0.072 * fValue);
182 maSatMatrix.set(1, 0, 0.213 - 0.213 * fValue);
183 maSatMatrix.set(1, 1, 0.715 + 0.285 * fValue);
184 maSatMatrix.set(1, 2, 0.072 - 0.072 * fValue);
185 maSatMatrix.set(2, 0, 0.213 - 0.213 * fValue);
186 maSatMatrix.set(2, 1, 0.715 - 0.715 * fValue);
187 maSatMatrix.set(2, 2, 0.072 + 0.928 * fValue);
190 BColorModifier_saturate::~BColorModifier_saturate()
194 bool BColorModifier_saturate::operator==(const BColorModifier& rCompare) const
196 if (!BColorModifier::operator==(rCompare))
197 return false;
199 const BColorModifier_saturate* pCompare(static_cast< const BColorModifier_saturate* >(&rCompare));
200 return maSatMatrix == pCompare->maSatMatrix;
203 ::basegfx::BColor BColorModifier_saturate::getModifiedColor(const ::basegfx::BColor& aSourceColor) const
205 basegfx::B3DHomMatrix aColorMatrix;
206 aColorMatrix.set(0, 0, aSourceColor.getRed());
207 aColorMatrix.set(1, 0, aSourceColor.getGreen());
208 aColorMatrix.set(2, 0, aSourceColor.getBlue());
210 aColorMatrix = maSatMatrix * aColorMatrix;
211 return ::basegfx::BColor(aColorMatrix.get(0, 0), aColorMatrix.get(1, 0), aColorMatrix.get(2, 0));
214 OUString BColorModifier_saturate::getModifierName() const
216 return u"saturate"_ustr;
219 BColorModifier_hueRotate::BColorModifier_hueRotate(double fRad)
220 : BColorModifier(basegfx::BColorModifierType::BCMType_hueRotate)
222 const double fCos = cos(fRad);
223 const double fSin = sin(fRad);
225 maHueMatrix.set(0, 0, 0.213 + fCos * 0.787 - fSin * 0.213);
226 maHueMatrix.set(0, 1, 0.715 - fCos * 0.715 - fSin * 0.715);
227 maHueMatrix.set(0, 2, 0.072 - fCos * 0.072 + fSin * 0.928);
228 maHueMatrix.set(1, 0, 0.213 - fCos * 0.213 + fSin * 0.143);
229 maHueMatrix.set(1, 1, 0.715 + fCos * 0.285 + fSin * 0.140);
230 maHueMatrix.set(1, 2, 0.072 - fCos * 0.072 - fSin * 0.283);
231 maHueMatrix.set(2, 0, 0.213 - fCos * 0.213 - fSin * 0.787);
232 maHueMatrix.set(2, 1, 0.715 - fCos * 0.715 + fSin * 0.715);
233 maHueMatrix.set(2, 2, 0.072 + fCos * 0.928 + fSin * 0.072);
236 BColorModifier_hueRotate::~BColorModifier_hueRotate()
240 bool BColorModifier_hueRotate::operator==(const BColorModifier& rCompare) const
242 if (!BColorModifier::operator==(rCompare))
243 return false;
245 const BColorModifier_hueRotate* pCompare(static_cast< const BColorModifier_hueRotate* >(&rCompare));
246 return maHueMatrix == pCompare->maHueMatrix;
249 ::basegfx::BColor BColorModifier_hueRotate::getModifiedColor(const ::basegfx::BColor& aSourceColor) const
251 basegfx::B3DHomMatrix aColorMatrix;
252 aColorMatrix.set(0, 0, aSourceColor.getRed());
253 aColorMatrix.set(1, 0, aSourceColor.getGreen());
254 aColorMatrix.set(2, 0, aSourceColor.getBlue());
256 aColorMatrix = maHueMatrix * aColorMatrix;
257 return ::basegfx::BColor(
258 std::clamp(aColorMatrix.get(0, 0), 0.0, 1.0),
259 std::clamp(aColorMatrix.get(1, 0), 0.0, 1.0),
260 std::clamp(aColorMatrix.get(2, 0), 0.0, 1.0));
263 OUString BColorModifier_hueRotate::getModifierName() const
265 return u"hueRotate"_ustr;
268 BColorModifier_black_and_white::~BColorModifier_black_and_white()
272 bool BColorModifier_black_and_white::operator==(const BColorModifier& rCompare) const
274 if (!BColorModifier::operator==(rCompare))
275 return false;
277 const BColorModifier_black_and_white* pCompare(static_cast< const BColorModifier_black_and_white* >(&rCompare));
278 return mfValue == pCompare->mfValue;
281 ::basegfx::BColor BColorModifier_black_and_white::getModifiedColor(const ::basegfx::BColor& aSourceColor) const
283 const double fLuminance(aSourceColor.luminance());
285 if(fLuminance < mfValue)
287 return ::basegfx::BColor::getEmptyBColor();
289 else
291 return ::basegfx::BColor(1.0, 1.0, 1.0);
295 OUString BColorModifier_black_and_white::getModifierName() const
297 return u"black_and_white"_ustr;
300 BColorModifier_gamma::BColorModifier_gamma(double fValue)
301 : BColorModifier(basegfx::BColorModifierType::BCMType_gamma)
302 , mfValue(fValue)
303 , mfInvValue(fValue)
304 , mbUseIt(!basegfx::fTools::equal(fValue, 1.0) && fValue > 0.0 && basegfx::fTools::lessOrEqual(fValue, 10.0))
306 if(mbUseIt)
308 mfInvValue = 1.0 / mfValue;
312 BColorModifier_gamma::~BColorModifier_gamma()
316 bool BColorModifier_gamma::operator==(const BColorModifier& rCompare) const
318 if (!BColorModifier::operator==(rCompare))
319 return false;
321 const BColorModifier_gamma* pCompare(static_cast< const BColorModifier_gamma* >(&rCompare));
323 // mfValue is sufficient, mfInvValue and mbUseIt are only helper values
324 return mfValue == pCompare->mfValue;
327 ::basegfx::BColor BColorModifier_gamma::getModifiedColor(const ::basegfx::BColor& aSourceColor) const
329 if(mbUseIt)
331 ::basegfx::BColor aRetval(
332 pow(aSourceColor.getRed(), mfInvValue),
333 pow(aSourceColor.getGreen(), mfInvValue),
334 pow(aSourceColor.getBlue(), mfInvValue));
336 aRetval.clamp();
337 return aRetval;
339 else
341 return aSourceColor;
345 OUString BColorModifier_gamma::getModifierName() const
347 return u"gamma"_ustr;
350 BColorModifier_RGBLuminanceContrast::BColorModifier_RGBLuminanceContrast(double fRed, double fGreen, double fBlue, double fLuminance, double fContrast)
351 : BColorModifier(basegfx::BColorModifierType::BCMType_RGBLuminanceContrast)
352 , mfRed(std::clamp(fRed, -1.0, 1.0))
353 , mfGreen(std::clamp(fGreen, -1.0, 1.0))
354 , mfBlue(std::clamp(fBlue, -1.0, 1.0))
355 , mfLuminance(std::clamp(fLuminance, -1.0, 1.0))
356 , mfContrast(std::clamp(fContrast, -1.0, 1.0))
357 , mfContrastOff(1.0)
358 , mfRedOff(0.0)
359 , mfGreenOff(0.0)
360 , mfBlueOff(0.0)
361 , mbUseIt(false)
363 if(basegfx::fTools::equalZero(mfRed)
364 && basegfx::fTools::equalZero(mfGreen)
365 && basegfx::fTools::equalZero(mfBlue)
366 && basegfx::fTools::equalZero(mfLuminance)
367 && basegfx::fTools::equalZero(mfContrast))
368 return;
370 // calculate slope
371 if(mfContrast >= 0.0)
373 mfContrastOff = 128.0 / (128.0 - (mfContrast * 127.0));
375 else
377 mfContrastOff = ( 128.0 + (mfContrast * 127.0)) / 128.0;
380 // calculate unified contrast offset
381 const double fPreparedContrastOff((128.0 - mfContrastOff * 128.0) / 255.0);
382 const double fCombinedOffset(mfLuminance + fPreparedContrastOff);
384 // set full offsets
385 mfRedOff = mfRed + fCombinedOffset;
386 mfGreenOff = mfGreen + fCombinedOffset;
387 mfBlueOff = mfBlue + fCombinedOffset;
389 mbUseIt = true;
392 BColorModifier_RGBLuminanceContrast::~BColorModifier_RGBLuminanceContrast()
396 bool BColorModifier_RGBLuminanceContrast::operator==(const BColorModifier& rCompare) const
398 if (!BColorModifier::operator==(rCompare))
399 return false;
401 const BColorModifier_RGBLuminanceContrast* pCompare(static_cast< const BColorModifier_RGBLuminanceContrast* >(&rCompare));
403 // no need to compare other values, these are just helpers
404 return mfRed == pCompare->mfRed
405 && mfGreen == pCompare->mfGreen
406 && mfBlue == pCompare->mfBlue
407 && mfLuminance == pCompare->mfLuminance
408 && mfContrast == pCompare->mfContrast;
411 ::basegfx::BColor BColorModifier_RGBLuminanceContrast::getModifiedColor(const ::basegfx::BColor& aSourceColor) const
413 if(mbUseIt)
415 return basegfx::BColor(
416 std::clamp(aSourceColor.getRed() * mfContrastOff + mfRedOff, 0.0, 1.0),
417 std::clamp(aSourceColor.getGreen() * mfContrastOff + mfGreenOff, 0.0, 1.0),
418 std::clamp(aSourceColor.getBlue() * mfContrastOff + mfBlueOff, 0.0, 1.0));
420 else
422 return aSourceColor;
426 OUString BColorModifier_RGBLuminanceContrast::getModifierName() const
428 return u"RGBLuminanceContrast"_ustr;
431 BColorModifier_randomize::BColorModifier_randomize(double fRandomPart)
432 : BColorModifier(basegfx::BColorModifierType::BCMType_randomize)
433 , mfRandomPart(fRandomPart)
437 BColorModifier_randomize::~BColorModifier_randomize()
441 // compare operator
442 bool BColorModifier_randomize::operator==(const BColorModifier& rCompare) const
444 if (!BColorModifier::operator==(rCompare))
445 return false;
447 const BColorModifier_randomize* pCompare(static_cast< const BColorModifier_randomize* >(&rCompare));
448 return mfRandomPart == pCompare->mfRandomPart;
451 // compute modified color
452 ::basegfx::BColor BColorModifier_randomize::getModifiedColor(const ::basegfx::BColor& aSourceColor) const
454 if(0.0 >= mfRandomPart)
456 // no randomizing, use orig color
457 return aSourceColor;
460 if(1.0 <= mfRandomPart)
462 // full randomized color
463 return basegfx::BColor(
464 comphelper::rng::uniform_real_distribution(0.0, nextafter(1.0, DBL_MAX)),
465 comphelper::rng::uniform_real_distribution(0.0, nextafter(1.0, DBL_MAX)),
466 comphelper::rng::uniform_real_distribution(0.0, nextafter(1.0, DBL_MAX)));
469 // mixed color
470 const double fMulA(1.0 - mfRandomPart);
471 return basegfx::BColor(
472 aSourceColor.getRed() * fMulA +
473 comphelper::rng::uniform_real_distribution(0.0, nextafter(mfRandomPart, DBL_MAX)),
474 aSourceColor.getGreen() * fMulA +
475 comphelper::rng::uniform_real_distribution(0.0, nextafter(mfRandomPart, DBL_MAX)),
476 aSourceColor.getBlue() * fMulA +
477 comphelper::rng::uniform_real_distribution(0.0, nextafter(mfRandomPart, DBL_MAX)));
480 OUString BColorModifier_randomize::getModifierName() const
482 return u"randomize"_ustr;
485 ::basegfx::BColor BColorModifierStack::getModifiedColor(const ::basegfx::BColor& rSource) const
487 if(maBColorModifiers.empty())
489 return rSource;
492 ::basegfx::BColor aRetval(rSource);
494 for(sal_uInt32 a(maBColorModifiers.size()); a;)
496 a--;
497 aRetval = maBColorModifiers[a]->getModifiedColor(aRetval);
500 return aRetval;
503 bool BColorModifierStack::operator==(const BColorModifierStack& rComp) const
505 if (count() != rComp.count())
506 return false;
508 if (0 == count())
509 return true;
511 for (sal_uInt32 a(0); a < count(); a++)
513 // nullptrs are not allowed/expected
514 assert(maBColorModifiers[a] != nullptr);
515 assert(rComp.maBColorModifiers[a] != nullptr);
517 if (!(*maBColorModifiers[a] == *rComp.maBColorModifiers[a]))
518 return false;
521 return true;
523 } // end of namespace basegfx
525 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */