basegfx/source/color/bcolormodifier.cxx | 136 +++----- drawinglayer/source/primitive2d/graphicprimitive2d.cxx | 49 +-- include/basegfx/color/bcolormodifier.hxx | 64 +++- vcl/source/bitmap/BitmapEx.cxx | 268 ++++++++++------- 4 files changed, 305 insertions(+), 212 deletions(-)
New commits: commit 27829e4a6c5a4a1162599550c46b5e7f974aba91 Author: Armin Le Grand (allotropia) <armin.le.grand.ext...@allotropia.de> AuthorDate: Wed Jul 10 13:16:20 2024 +0200 Commit: Armin Le Grand <armin.le.gr...@me.com> CommitDate: Thu Jul 11 10:58:24 2024 +0200 CairoSDPR: Improve BColorModified Bitmaps There is the complete BColorModifierStack support for primitives for Bitmaps, e.g. hue/saturation, etc, but it was slow due to not being buffered, so had to be re-created often. I changed this to use the common buffering mechanism to improve this. Up to now a fallback to use the old Graphic manipulators for that purpose was in place since this was faster, but had to be done every time. I have now changed the priority to using the primitive way to handle things, but kept the fallback code - just in case. Note that the new stuff is faster, but even much faster when the bitmap is copied and appears multiple times -> the same buffered instance is used, and SDPRs then use the system-dependent data buffered at that prepared data. Also note that this change does not only speedup CairoSDPR, but all PrimitiveRenderers, including the VCL and Metafile ones. In principle everything that uses BitmapEx::ModifyBitmapEx. Had a 2nd thought: Only the content Bitmap gets changed, so for this case we do not need AssociatedAlpha and watch for it to not have changed. Removed that. Change-Id: I2ee36cc84bdc1c723aa01f872edbfd1f51e11c2d Reviewed-on: https://gerrit.libreoffice.org/c/core/+/170305 Tested-by: Jenkins Reviewed-by: Armin Le Grand <armin.le.gr...@me.com> diff --git a/basegfx/source/color/bcolormodifier.cxx b/basegfx/source/color/bcolormodifier.cxx index 04ab3757cb45..e0e0ebbd6203 100644 --- a/basegfx/source/color/bcolormodifier.cxx +++ b/basegfx/source/color/bcolormodifier.cxx @@ -33,11 +33,6 @@ namespace basegfx { } - bool BColorModifier_gray::operator==(const BColorModifier& rCompare) const - { - return dynamic_cast< const BColorModifier_gray* >(&rCompare) != nullptr; - } - ::basegfx::BColor BColorModifier_gray::getModifiedColor(const ::basegfx::BColor& aSourceColor) const { const double fLuminance(aSourceColor.luminance()); @@ -54,11 +49,6 @@ namespace basegfx { } - bool BColorModifier_invert::operator==(const BColorModifier& rCompare) const - { - return dynamic_cast< const BColorModifier_invert* >(&rCompare) != nullptr; - } - ::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()); @@ -73,11 +63,6 @@ namespace basegfx { } - bool BColorModifier_luminance_to_alpha::operator==(const BColorModifier& rCompare) const - { - return dynamic_cast< const BColorModifier_luminance_to_alpha* >(&rCompare) != nullptr; - } - ::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))); @@ -96,13 +81,10 @@ namespace basegfx bool BColorModifier_replace::operator==(const BColorModifier& rCompare) const { - const BColorModifier_replace* pCompare = dynamic_cast< const BColorModifier_replace* >(&rCompare); - - if(!pCompare) - { + if (!BColorModifier::operator==(rCompare)) return false; - } + const BColorModifier_replace* pCompare(static_cast< const BColorModifier_replace* >(&rCompare)); return getBColor() == pCompare->getBColor(); } @@ -122,13 +104,10 @@ namespace basegfx bool BColorModifier_interpolate::operator==(const BColorModifier& rCompare) const { - const BColorModifier_interpolate* pCompare = dynamic_cast< const BColorModifier_interpolate* >(&rCompare); - - if(!pCompare) - { + if (!BColorModifier::operator==(rCompare)) return false; - } + const BColorModifier_interpolate* pCompare(static_cast< const BColorModifier_interpolate* >(&rCompare)); return maBColor == pCompare->maBColor && mfValue == pCompare->mfValue; } @@ -148,13 +127,10 @@ namespace basegfx bool BColorModifier_matrix::operator==(const BColorModifier& rCompare) const { - const BColorModifier_matrix* pCompare = dynamic_cast< const BColorModifier_matrix* >(&rCompare); - - if(!pCompare) - { + if (!BColorModifier::operator==(rCompare)) return false; - } + const BColorModifier_matrix* pCompare(static_cast< const BColorModifier_matrix* >(&rCompare)); return maVector == pCompare->maVector; } @@ -198,6 +174,7 @@ namespace basegfx } 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); @@ -216,13 +193,10 @@ namespace basegfx bool BColorModifier_saturate::operator==(const BColorModifier& rCompare) const { - const BColorModifier_saturate* pCompare = dynamic_cast< const BColorModifier_saturate* >(&rCompare); - - if(!pCompare) - { + if (!BColorModifier::operator==(rCompare)) return false; - } + const BColorModifier_saturate* pCompare(static_cast< const BColorModifier_saturate* >(&rCompare)); return maSatMatrix == pCompare->maSatMatrix; } @@ -243,6 +217,7 @@ namespace basegfx } BColorModifier_hueRotate::BColorModifier_hueRotate(double fRad) + : BColorModifier(basegfx::BColorModifierType::BCMType_hueRotate) { const double fCos = cos(fRad); const double fSin = sin(fRad); @@ -264,13 +239,10 @@ namespace basegfx bool BColorModifier_hueRotate::operator==(const BColorModifier& rCompare) const { - const BColorModifier_hueRotate* pCompare = dynamic_cast< const BColorModifier_hueRotate* >(&rCompare); - - if(!pCompare) - { + if (!BColorModifier::operator==(rCompare)) return false; - } + const BColorModifier_hueRotate* pCompare(static_cast< const BColorModifier_hueRotate* >(&rCompare)); return maHueMatrix == pCompare->maHueMatrix; } @@ -299,13 +271,10 @@ namespace basegfx bool BColorModifier_black_and_white::operator==(const BColorModifier& rCompare) const { - const BColorModifier_black_and_white* pCompare = dynamic_cast< const BColorModifier_black_and_white* >(&rCompare); - - if(!pCompare) - { + if (!BColorModifier::operator==(rCompare)) return false; - } + const BColorModifier_black_and_white* pCompare(static_cast< const BColorModifier_black_and_white* >(&rCompare)); return mfValue == pCompare->mfValue; } @@ -329,9 +298,10 @@ namespace basegfx } BColorModifier_gamma::BColorModifier_gamma(double fValue) - : mfValue(fValue), - mfInvValue(fValue), - mbUseIt(!basegfx::fTools::equal(fValue, 1.0) && fValue > 0.0 && basegfx::fTools::lessOrEqual(fValue, 10.0)) + : 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) { @@ -345,14 +315,12 @@ namespace basegfx bool BColorModifier_gamma::operator==(const BColorModifier& rCompare) const { - const BColorModifier_gamma* pCompare = dynamic_cast< const BColorModifier_gamma* >(&rCompare); - - if(!pCompare) - { + if (!BColorModifier::operator==(rCompare)) return false; - } - // getValue is sufficient, mfInvValue and mbUseIt are only helper values + const BColorModifier_gamma* pCompare(static_cast< const BColorModifier_gamma* >(&rCompare)); + + // mfValue is sufficient, mfInvValue and mbUseIt are only helper values return mfValue == pCompare->mfValue; } @@ -380,16 +348,17 @@ namespace basegfx } BColorModifier_RGBLuminanceContrast::BColorModifier_RGBLuminanceContrast(double fRed, double fGreen, double fBlue, double fLuminance, double fContrast) - : 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) + : 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) @@ -426,12 +395,10 @@ namespace basegfx bool BColorModifier_RGBLuminanceContrast::operator==(const BColorModifier& rCompare) const { - const BColorModifier_RGBLuminanceContrast* pCompare = dynamic_cast< const BColorModifier_RGBLuminanceContrast* >(&rCompare); - - if(!pCompare) - { + 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 @@ -462,7 +429,8 @@ namespace basegfx } BColorModifier_randomize::BColorModifier_randomize(double fRandomPart) - : mfRandomPart(fRandomPart) + : BColorModifier(basegfx::BColorModifierType::BCMType_randomize) + , mfRandomPart(fRandomPart) { } @@ -473,13 +441,10 @@ namespace basegfx // compare operator bool BColorModifier_randomize::operator==(const BColorModifier& rCompare) const { - const BColorModifier_randomize* pCompare = dynamic_cast< const BColorModifier_randomize* >(&rCompare); - - if(!pCompare) - { + if (!BColorModifier::operator==(rCompare)) return false; - } + const BColorModifier_randomize* pCompare(static_cast< const BColorModifier_randomize* >(&rCompare)); return mfRandomPart == pCompare->mfRandomPart; } @@ -534,6 +499,27 @@ namespace basegfx 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: */ diff --git a/drawinglayer/source/primitive2d/graphicprimitive2d.cxx b/drawinglayer/source/primitive2d/graphicprimitive2d.cxx index 0f228c528a0e..2c97c809f4ff 100644 --- a/drawinglayer/source/primitive2d/graphicprimitive2d.cxx +++ b/drawinglayer/source/primitive2d/graphicprimitive2d.cxx @@ -75,28 +75,41 @@ GraphicPrimitive2D::create2DDecomposition(const geometry::ViewInformation2D&) co const GraphicObject& rGraphicObject = getGraphicObject(); Graphic aTransformedGraphic(rGraphicObject.GetGraphic()); - const bool isBitmap(GraphicType::Bitmap == aTransformedGraphic.GetType() - && !aTransformedGraphic.getVectorGraphicData()); const bool isAdjusted(getGraphicAttr().IsAdjusted()); const bool isDrawMode(GraphicDrawMode::Standard != getGraphicAttr().GetDrawMode()); - if (isBitmap && (isAdjusted || isDrawMode)) + // I have now added buffering BColorModifierStack-adapted Bitmaps, + // see BitmapEx::ModifyBitmapEx, thus the primitive case is fast now. + // It buffers the adapted bitmap and at that the SDPRs can then buffer + // the system-dependent represetation. + // I keep the code below (adding a static switch). It modifies the + // Graphic and is a reliable fallback - just in case. Remember that + // it does *not* buffer and has to modify again at each re-use... + static bool bUseOldModification(false); + + if (bUseOldModification) { - // the pure primitive solution with the color modifiers works well, too, but when - // it is a bitmap graphic the old modification currently is faster; so use it here - // instead of creating all as in create2DColorModifierEmbeddingsAsNeeded (see below). - // Still, crop, rotation, mirroring and transparency is handled by primitives already - // (see above). - // This could even be done when vector graphic, but we explicitly want to have the - // pure primitive solution for this; this will allow vector graphics to stay vector - // graphics, independent from the color filtering stuff. This will enhance e.g. - // SVG and print quality while reducing data size at the same time. - // The other way around the old modifications when only used on already bitmap objects - // will not lose any quality. - aTransformedGraphic = rGraphicObject.GetTransformedGraphic(&aSuppressGraphicAttr); - - // reset GraphicAttr after use to not apply double - aSuppressGraphicAttr = GraphicAttr(); + const bool isBitmap(GraphicType::Bitmap == aTransformedGraphic.GetType() + && !aTransformedGraphic.getVectorGraphicData()); + + if (isBitmap && (isAdjusted || isDrawMode)) + { + // the pure primitive solution with the color modifiers works well, too, but when + // it is a bitmap graphic the old modification currently is faster; so use it here + // instead of creating all as in create2DColorModifierEmbeddingsAsNeeded (see below). + // Still, crop, rotation, mirroring and transparency is handled by primitives already + // (see above). + // This could even be done when vector graphic, but we explicitly want to have the + // pure primitive solution for this; this will allow vector graphics to stay vector + // graphics, independent from the color filtering stuff. This will enhance e.g. + // SVG and print quality while reducing data size at the same time. + // The other way around the old modifications when only used on already bitmap objects + // will not lose any quality. + aTransformedGraphic = rGraphicObject.GetTransformedGraphic(&aSuppressGraphicAttr); + + // reset GraphicAttr after use to not apply double + aSuppressGraphicAttr = GraphicAttr(); + } } // create sub-content; helper takes care of correct handling of diff --git a/include/basegfx/color/bcolormodifier.hxx b/include/basegfx/color/bcolormodifier.hxx index 59f277555c30..e74d6b43726e 100644 --- a/include/basegfx/color/bcolormodifier.hxx +++ b/include/basegfx/color/bcolormodifier.hxx @@ -32,6 +32,21 @@ namespace basegfx { + enum class BColorModifierType : sal_uInt16 { + BCMType_gray, + BCMType_invert, + BCMType_luminance_to_alpha, + BCMType_replace, + BCMType_interpolate, + BCMType_saturate, + BCMType_matrix, + BCMType_hueRotate, + BCMType_black_and_white, + BCMType_gamma, + BCMType_RGBLuminanceContrast, + BCMType_randomize + }; + /** base class to define color modifications The basic idea is to have instances of color modifiers where each @@ -61,12 +76,16 @@ namespace basegfx class SAL_WARN_UNUSED BASEGFX_DLLPUBLIC BColorModifier { private: + BColorModifierType maType; BColorModifier(const BColorModifier&) = delete; BColorModifier& operator=(const BColorModifier&) = delete; protected: // no one is allowed to incarnate the abstract base class // except derivations - BColorModifier() {} + BColorModifier(BColorModifierType aType) + : maType(aType) + { + } public: // no one should directly destroy it; all incarnations should be @@ -74,9 +93,19 @@ namespace basegfx virtual ~BColorModifier(); // compare operator - virtual bool operator==(const BColorModifier& rCompare) const = 0; + virtual bool operator==(const BColorModifier& rCompare) const + { + if (maType != rCompare.maType) + return false; + + return true; + } + bool operator!=(const BColorModifier& rCompare) const { + if (maType != rCompare.maType) + return true; + return !(operator==(rCompare)); } @@ -84,6 +113,9 @@ namespace basegfx virtual ::basegfx::BColor getModifiedColor(const ::basegfx::BColor& aSourceColor) const = 0; virtual OUString getModifierName() const = 0; + + // return type + BColorModifierType getBColorModifierType() const { return maType; } }; /** convert color to gray @@ -92,14 +124,12 @@ namespace basegfx { public: BColorModifier_gray() + : BColorModifier(basegfx::BColorModifierType::BCMType_gray) { } virtual ~BColorModifier_gray() override; - // compare operator - SAL_DLLPRIVATE virtual bool operator==(const BColorModifier& rCompare) const override; - // compute modified color SAL_DLLPRIVATE virtual ::basegfx::BColor getModifiedColor(const ::basegfx::BColor& aSourceColor) const override; SAL_DLLPRIVATE virtual OUString getModifierName() const override; @@ -113,14 +143,12 @@ namespace basegfx { public: BColorModifier_invert() + : BColorModifier(basegfx::BColorModifierType::BCMType_invert) { } virtual ~BColorModifier_invert() override; - // compare operator - SAL_DLLPRIVATE virtual bool operator==(const BColorModifier& rCompare) const override; - // compute modified color SAL_DLLPRIVATE virtual ::basegfx::BColor getModifiedColor(const ::basegfx::BColor& aSourceColor) const override; SAL_DLLPRIVATE virtual OUString getModifierName() const override; @@ -138,14 +166,12 @@ namespace basegfx { public: BColorModifier_luminance_to_alpha() + : BColorModifier(basegfx::BColorModifierType::BCMType_luminance_to_alpha) { } virtual ~BColorModifier_luminance_to_alpha() override; - // compare operator - SAL_DLLPRIVATE virtual bool operator==(const BColorModifier& rCompare) const override; - // compute modified color SAL_DLLPRIVATE virtual ::basegfx::BColor getModifiedColor(const ::basegfx::BColor& aSourceColor) const override; SAL_DLLPRIVATE virtual OUString getModifierName() const override; @@ -164,7 +190,8 @@ namespace basegfx public: BColorModifier_replace(const ::basegfx::BColor& rBColor) - : maBColor(rBColor) + : BColorModifier(basegfx::BColorModifierType::BCMType_replace) + , maBColor(rBColor) { } @@ -196,8 +223,9 @@ namespace basegfx public: BColorModifier_interpolate(const ::basegfx::BColor& rBColor, double fValue) - : maBColor(rBColor), - mfValue(fValue) + : BColorModifier(basegfx::BColorModifierType::BCMType_interpolate) + , maBColor(rBColor) + , mfValue(fValue) { } @@ -250,7 +278,8 @@ namespace basegfx public: BColorModifier_matrix(std::vector<double> aVector) - : maVector(std::move(aVector)) + : BColorModifier(basegfx::BColorModifierType::BCMType_matrix) + , maVector(std::move(aVector)) { } @@ -300,7 +329,8 @@ namespace basegfx public: BColorModifier_black_and_white(double fValue) - : mfValue(fValue) + : BColorModifier(basegfx::BColorModifierType::BCMType_black_and_white) + , mfValue(fValue) { } @@ -441,6 +471,8 @@ namespace basegfx { maBColorModifiers.pop_back(); } + + bool operator==(const BColorModifierStack& rComp) const; }; } // end of namespace basegfx diff --git a/vcl/source/bitmap/BitmapEx.cxx b/vcl/source/bitmap/BitmapEx.cxx index f00eff75ab9e..3c6679df6795 100644 --- a/vcl/source/bitmap/BitmapEx.cxx +++ b/vcl/source/bitmap/BitmapEx.cxx @@ -837,148 +837,210 @@ BitmapEx BitmapEx::getTransformed( return aRetval; } +namespace +{ +class BufferedData_ModifiedBitmapEx : public basegfx::SystemDependentData +{ + Bitmap maChangedBitmap; + basegfx::BColorModifierStack maBColorModifierStack; + +public: + BufferedData_ModifiedBitmapEx( + const Bitmap& rChangedBitmap, + const basegfx::BColorModifierStack& rBColorModifierStack) + : basegfx::SystemDependentData(Application::GetSystemDependentDataManager()) + , maChangedBitmap(rChangedBitmap) + , maBColorModifierStack(rBColorModifierStack) + { + } + + const Bitmap& getChangedBitmap() const { return maChangedBitmap; } + const basegfx::BColorModifierStack& getBColorModifierStack() const { return maBColorModifierStack; } + + virtual sal_Int64 estimateUsageInBytes() const override; +}; + +sal_Int64 BufferedData_ModifiedBitmapEx::estimateUsageInBytes() const +{ + return maChangedBitmap.GetSizeBytes(); +} +} + BitmapEx BitmapEx::ModifyBitmapEx(const basegfx::BColorModifierStack& rBColorModifierStack) const { - Bitmap aChangedBitmap(GetBitmap()); - bool bDone(false); + if (0 == rBColorModifierStack.count()) + { + // no modifiers, done + return *this; + } - for(sal_uInt32 a(rBColorModifierStack.count()); a && !bDone; ) + // check for BColorModifier_replace at the top of the stack + const basegfx::BColorModifierSharedPtr& rLastModifier(rBColorModifierStack.getBColorModifier(rBColorModifierStack.count() - 1)); + const basegfx::BColorModifier_replace* pLastModifierReplace(dynamic_cast<const basegfx::BColorModifier_replace*>(rLastModifier.get())); + + if (nullptr != pLastModifierReplace && !IsAlpha()) { - const basegfx::BColorModifierSharedPtr& rModifier = rBColorModifierStack.getBColorModifier(--a); - const basegfx::BColorModifier_replace* pReplace = dynamic_cast< const basegfx::BColorModifier_replace* >(rModifier.get()); + // at the top of the stack we have a BColorModifier_replace -> no Bitmap needed, + // representation can be replaced by filled colored polygon. signal the caller + // about that by returning empty BitmapEx + return BitmapEx(); + } - if(pReplace) + const basegfx::SystemDependentDataHolder* pHolder(GetBitmap().accessSystemDependentDataHolder()); + std::shared_ptr<BufferedData_ModifiedBitmapEx> pBufferedData_ModifiedBitmapEx; + + if (nullptr != pHolder) + { + // try to access SystemDependentDataHolder and buffered data + pBufferedData_ModifiedBitmapEx = std::static_pointer_cast<BufferedData_ModifiedBitmapEx>( + pHolder->getSystemDependentData( + typeid(BufferedData_ModifiedBitmapEx).hash_code())); + + if (nullptr != pBufferedData_ModifiedBitmapEx + && !(pBufferedData_ModifiedBitmapEx->getBColorModifierStack() == rBColorModifierStack)) { - // complete replace + // BColorModifierStack is different -> data invalid + pBufferedData_ModifiedBitmapEx = nullptr; + } + + if (nullptr != pBufferedData_ModifiedBitmapEx) + { + // found existing instance of modified Bitmap, return reused/buffered result if(IsAlpha()) - { - // clear bitmap with dest color - if (vcl::isPalettePixelFormat(aChangedBitmap.getPixelFormat())) - { - // For e.g. 8bit Bitmaps, the nearest color to the given erase color is - // determined and used -> this may be different from what is wanted here. - // Better create a new bitmap with the needed color explicitly. - BitmapScopedReadAccess xReadAccess(aChangedBitmap); - OSL_ENSURE(xReadAccess, "Got no Bitmap ReadAccess ?!?"); + return BitmapEx(pBufferedData_ModifiedBitmapEx->getChangedBitmap(), GetAlphaMask()); + return BitmapEx(pBufferedData_ModifiedBitmapEx->getChangedBitmap()); + } + } - if(xReadAccess) - { - BitmapPalette aNewPalette(xReadAccess->GetPalette()); - aNewPalette[0] = BitmapColor(Color(pReplace->getBColor())); - aChangedBitmap = Bitmap( - aChangedBitmap.GetSizePixel(), - aChangedBitmap.getPixelFormat(), - &aNewPalette); - } - } - aChangedBitmap.Erase(Color(pReplace->getBColor())); - } - else + // have to create modified Bitmap + Bitmap aChangedBitmap(GetBitmap()); + + if (nullptr != pLastModifierReplace) + { + // special case -> we have BColorModifier_replace but Alpha channel + if (vcl::isPalettePixelFormat(aChangedBitmap.getPixelFormat())) + { + // For e.g. 8bit Bitmaps, the nearest color to the given erase color is + // determined and used -> this may be different from what is wanted here. + // Better create a new bitmap with the needed color explicitly. + BitmapScopedReadAccess xReadAccess(aChangedBitmap); + OSL_ENSURE(xReadAccess, "Got no Bitmap ReadAccess ?!?"); + + if(xReadAccess) { - // erase bitmap, caller will know to paint direct - aChangedBitmap.SetEmpty(); + BitmapPalette aNewPalette(xReadAccess->GetPalette()); + aNewPalette[0] = BitmapColor(Color(pLastModifierReplace->getBColor())); + aChangedBitmap = Bitmap( + aChangedBitmap.GetSizePixel(), + aChangedBitmap.getPixelFormat(), + &aNewPalette); } - - bDone = true; } else { - BitmapScopedWriteAccess xContent(aChangedBitmap); + // clear bitmap with dest color + aChangedBitmap.Erase(Color(pLastModifierReplace->getBColor())); + } + } + else + { + BitmapScopedWriteAccess xContent(aChangedBitmap); + + if(xContent) + { + const double fConvertColor(1.0 / 255.0); - if(xContent) + if(xContent->HasPalette()) { - const double fConvertColor(1.0 / 255.0); + const sal_uInt16 nCount(xContent->GetPaletteEntryCount()); - if(xContent->HasPalette()) + for(sal_uInt16 b(0); b < nCount; b++) + { + const BitmapColor& rCol = xContent->GetPaletteColor(b); + const basegfx::BColor aBSource( + rCol.GetRed() * fConvertColor, + rCol.GetGreen() * fConvertColor, + rCol.GetBlue() * fConvertColor); + const basegfx::BColor aBDest(rBColorModifierStack.getModifiedColor(aBSource)); + xContent->SetPaletteColor(b, BitmapColor(Color(aBDest))); + } + } + else if(ScanlineFormat::N24BitTcBgr == xContent->GetScanlineFormat()) + { + for(tools::Long y(0); y < xContent->Height(); y++) { - const sal_uInt16 nCount(xContent->GetPaletteEntryCount()); + Scanline pScan = xContent->GetScanline(y); - for(sal_uInt16 b(0); b < nCount; b++) + for(tools::Long x(0); x < xContent->Width(); x++) { - const BitmapColor& rCol = xContent->GetPaletteColor(b); const basegfx::BColor aBSource( - rCol.GetRed() * fConvertColor, - rCol.GetGreen() * fConvertColor, - rCol.GetBlue() * fConvertColor); - const basegfx::BColor aBDest(rModifier->getModifiedColor(aBSource)); - xContent->SetPaletteColor(b, BitmapColor(Color(aBDest))); + *(pScan + 2)* fConvertColor, + *(pScan + 1) * fConvertColor, + *pScan * fConvertColor); + const basegfx::BColor aBDest(rBColorModifierStack.getModifiedColor(aBSource)); + *pScan++ = static_cast< sal_uInt8 >(aBDest.getBlue() * 255.0); + *pScan++ = static_cast< sal_uInt8 >(aBDest.getGreen() * 255.0); + *pScan++ = static_cast< sal_uInt8 >(aBDest.getRed() * 255.0); } } - else if(ScanlineFormat::N24BitTcBgr == xContent->GetScanlineFormat()) + } + else if(ScanlineFormat::N24BitTcRgb == xContent->GetScanlineFormat()) + { + for(tools::Long y(0); y < xContent->Height(); y++) { - for(tools::Long y(0); y < xContent->Height(); y++) - { - Scanline pScan = xContent->GetScanline(y); + Scanline pScan = xContent->GetScanline(y); - for(tools::Long x(0); x < xContent->Width(); x++) - { - const basegfx::BColor aBSource( - *(pScan + 2)* fConvertColor, - *(pScan + 1) * fConvertColor, - *pScan * fConvertColor); - const basegfx::BColor aBDest(rModifier->getModifiedColor(aBSource)); - *pScan++ = static_cast< sal_uInt8 >(aBDest.getBlue() * 255.0); - *pScan++ = static_cast< sal_uInt8 >(aBDest.getGreen() * 255.0); - *pScan++ = static_cast< sal_uInt8 >(aBDest.getRed() * 255.0); - } - } - } - else if(ScanlineFormat::N24BitTcRgb == xContent->GetScanlineFormat()) - { - for(tools::Long y(0); y < xContent->Height(); y++) + for(tools::Long x(0); x < xContent->Width(); x++) { - Scanline pScan = xContent->GetScanline(y); - - for(tools::Long x(0); x < xContent->Width(); x++) - { - const basegfx::BColor aBSource( - *pScan * fConvertColor, - *(pScan + 1) * fConvertColor, - *(pScan + 2) * fConvertColor); - const basegfx::BColor aBDest(rModifier->getModifiedColor(aBSource)); - *pScan++ = static_cast< sal_uInt8 >(aBDest.getRed() * 255.0); - *pScan++ = static_cast< sal_uInt8 >(aBDest.getGreen() * 255.0); - *pScan++ = static_cast< sal_uInt8 >(aBDest.getBlue() * 255.0); - } + const basegfx::BColor aBSource( + *pScan * fConvertColor, + *(pScan + 1) * fConvertColor, + *(pScan + 2) * fConvertColor); + const basegfx::BColor aBDest(rBColorModifierStack.getModifiedColor(aBSource)); + *pScan++ = static_cast< sal_uInt8 >(aBDest.getRed() * 255.0); + *pScan++ = static_cast< sal_uInt8 >(aBDest.getGreen() * 255.0); + *pScan++ = static_cast< sal_uInt8 >(aBDest.getBlue() * 255.0); } } - else + } + else + { + for(tools::Long y(0); y < xContent->Height(); y++) { - for(tools::Long y(0); y < xContent->Height(); y++) + Scanline pScanline = xContent->GetScanline( y ); + for(tools::Long x(0); x < xContent->Width(); x++) { - Scanline pScanline = xContent->GetScanline( y ); - for(tools::Long x(0); x < xContent->Width(); x++) - { - const BitmapColor aBMCol(xContent->GetColor(y, x)); - const basegfx::BColor aBSource( - static_cast<double>(aBMCol.GetRed()) * fConvertColor, - static_cast<double>(aBMCol.GetGreen()) * fConvertColor, - static_cast<double>(aBMCol.GetBlue()) * fConvertColor); - const basegfx::BColor aBDest(rModifier->getModifiedColor(aBSource)); - - xContent->SetPixelOnData(pScanline, x, BitmapColor(Color(aBDest))); - } + const BitmapColor aBMCol(xContent->GetColor(y, x)); + const basegfx::BColor aBSource( + static_cast<double>(aBMCol.GetRed()) * fConvertColor, + static_cast<double>(aBMCol.GetGreen()) * fConvertColor, + static_cast<double>(aBMCol.GetBlue()) * fConvertColor); + const basegfx::BColor aBDest(rBColorModifierStack.getModifiedColor(aBSource)); + + xContent->SetPixelOnData(pScanline, x, BitmapColor(Color(aBDest))); } } } } } - if(aChangedBitmap.IsEmpty()) + if (nullptr != pHolder) { - return BitmapEx(); - } - else - { - if(IsAlpha()) + // create new BufferedData_ModifiedBitmapEx (should be nullptr here) + if (nullptr == pBufferedData_ModifiedBitmapEx) { - return BitmapEx(aChangedBitmap, GetAlphaMask()); - } - else - { - return BitmapEx(aChangedBitmap); + pBufferedData_ModifiedBitmapEx = std::make_shared<BufferedData_ModifiedBitmapEx>(aChangedBitmap, rBColorModifierStack); } + + // register it, evtl. it's a new one + basegfx::SystemDependentData_SharedPtr r2(pBufferedData_ModifiedBitmapEx); + const_cast<basegfx::SystemDependentDataHolder*>(pHolder)->addOrReplaceSystemDependentData(r2); } + + // return result + if(IsAlpha()) + return BitmapEx(aChangedBitmap, GetAlphaMask()); + return BitmapEx(aChangedBitmap); } BitmapEx createBlendFrame(