drawinglayer/source/processor2d/SDPRProcessor2dTools.cxx | 30 - drawinglayer/source/processor2d/cairopixelprocessor2d.cxx | 80 +--- drawinglayer/source/processor2d/d2dpixelprocessor2d.cxx | 6 include/basegfx/utils/systemdependentdata.hxx | 1 include/drawinglayer/primitive2d/fillgraphicprimitive2d.hxx | 10 include/drawinglayer/processor2d/SDPRProcessor2dTools.hxx | 5 include/drawinglayer/processor2d/cairopixelprocessor2d.hxx | 3 include/vcl/bitmap.hxx | 9 vcl/source/bitmap/bitmap.cxx | 204 ++++++++++++ 9 files changed, 271 insertions(+), 77 deletions(-)
New commits: commit bacd1b5dc4d3d81c87803048892aa1d9c1ff0d9f Author: Noel Grandin <[email protected]> AuthorDate: Thu Aug 7 12:30:54 2025 +0200 Commit: Noel Grandin <[email protected]> CommitDate: Thu Aug 7 22:04:36 2025 +0200 BitmapEx->Bitmap in FillGraphicPrimitive2D now that Bitmap supports transparency Change-Id: I9762dadae840e8eaec37526f82068183474c7962 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/189069 Tested-by: Jenkins Reviewed-by: Noel Grandin <[email protected]> diff --git a/drawinglayer/source/processor2d/SDPRProcessor2dTools.cxx b/drawinglayer/source/processor2d/SDPRProcessor2dTools.cxx index 4116c09d6b85..12917206fa55 100644 --- a/drawinglayer/source/processor2d/SDPRProcessor2dTools.cxx +++ b/drawinglayer/source/processor2d/SDPRProcessor2dTools.cxx @@ -34,14 +34,14 @@ namespace drawinglayer::processor2d { void setOffsetXYCreatedBitmap( drawinglayer::primitive2d::FillGraphicPrimitive2D& rFillGraphicPrimitive2D, - const BitmapEx& rBitmap) + const Bitmap& rBitmap) { rFillGraphicPrimitive2D.impSetOffsetXYCreatedBitmap(rBitmap); } void takeCareOfOffsetXY( const drawinglayer::primitive2d::FillGraphicPrimitive2D& rFillGraphicPrimitive2D, - BitmapEx& rTarget, basegfx::B2DRange& rFillUnitRange) + Bitmap& rTarget, basegfx::B2DRange& rFillUnitRange) { const attribute::FillGraphicAttribute& rFillGraphicAttribute( rFillGraphicPrimitive2D.getFillGraphic()); @@ -54,20 +54,20 @@ void takeCareOfOffsetXY( { if (rFillGraphicPrimitive2D.getOffsetXYCreatedBitmap().IsEmpty()) { - const Size& rSize(rTarget.GetSizePixel()); - const tools::Long w(rSize.Width()); + const Size aSize(rTarget.GetSizePixel()); + const tools::Long w(aSize.Width()); const tools::Long a( basegfx::fround<tools::Long>(w * (1.0 - rFillGraphicAttribute.getOffsetX()))); if (0 != a && w != a) { - const tools::Long h(rSize.Height()); + const tools::Long h(aSize.Height()); const tools::Long b(w - a); - BitmapEx aTarget(Size(w, h * 2), rTarget.getPixelFormat()); + Bitmap aTarget(Size(w, h * 2), rTarget.getPixelFormat()); aTarget.SetPrefSize( Size(rTarget.GetPrefSize().Width(), rTarget.GetPrefSize().Height() * 2)); - const tools::Rectangle aSrcDst(Point(), rSize); + const tools::Rectangle aSrcDst(Point(), aSize); aTarget.CopyPixel(aSrcDst, // Dst aSrcDst, // Src rTarget); @@ -98,20 +98,20 @@ void takeCareOfOffsetXY( { if (rFillGraphicPrimitive2D.getOffsetXYCreatedBitmap().IsEmpty()) { - const Size& rSize(rTarget.GetSizePixel()); - const tools::Long h(rSize.Height()); + const Size aSize(rTarget.GetSizePixel()); + const tools::Long h(aSize.Height()); const tools::Long a( basegfx::fround<tools::Long>(h * (1.0 - rFillGraphicAttribute.getOffsetY()))); if (0 != a && h != a) { - const tools::Long w(rSize.Width()); + const tools::Long w(aSize.Width()); const tools::Long b(h - a); - BitmapEx aTarget(Size(w * 2, h), rTarget.getPixelFormat()); + Bitmap aTarget(Size(w * 2, h), rTarget.getPixelFormat()); aTarget.SetPrefSize( Size(rTarget.GetPrefSize().Width() * 2, rTarget.GetPrefSize().Height())); - const tools::Rectangle aSrcDst(Point(), rSize); + const tools::Rectangle aSrcDst(Point(), aSize); aTarget.CopyPixel(aSrcDst, // Dst aSrcDst, // Src rTarget); @@ -142,7 +142,7 @@ void takeCareOfOffsetXY( bool prepareBitmapForDirectRender( const drawinglayer::primitive2d::FillGraphicPrimitive2D& rFillGraphicPrimitive2D, - const drawinglayer::geometry::ViewInformation2D& rViewInformation2D, BitmapEx& rTarget, + const drawinglayer::geometry::ViewInformation2D& rViewInformation2D, Bitmap& rTarget, basegfx::B2DRange& rFillUnitRange, double fBigDiscreteArea) { const attribute::FillGraphicAttribute& rFillGraphicAttribute( @@ -203,7 +203,7 @@ bool prepareBitmapForDirectRender( { // bitmap graphic, always handle locally, so get bitmap data independent // if it'sie or it's discrete display size - rTarget = rGraphic.GetBitmapEx(); + rTarget = Bitmap(rGraphic.GetBitmapEx()); } else { @@ -243,7 +243,7 @@ bool prepareBitmapForDirectRender( // at BitmapEx is possible, just get the default fallback Bitmap from the // vector data to continue. Trust the existing converters for now to // do something with good quality. - rTarget = rGraphic.GetBitmapEx(); + rTarget = Bitmap(rGraphic.GetBitmapEx()); } } diff --git a/drawinglayer/source/processor2d/cairopixelprocessor2d.cxx b/drawinglayer/source/processor2d/cairopixelprocessor2d.cxx index b3bbdd36536e..0eda4ca44e52 100644 --- a/drawinglayer/source/processor2d/cairopixelprocessor2d.cxx +++ b/drawinglayer/source/processor2d/cairopixelprocessor2d.cxx @@ -426,11 +426,9 @@ class CairoSurfaceHelper mutable std::unordered_map<sal_uInt64, cairo_surface_t*> maDownscaled; // create 32bit RGBA data for given BitmapEx - void createRGBA(const BitmapEx& rBitmapEx) + void createRGBA(const Bitmap& rBitmap) { - Bitmap aSrcAlpha(rBitmapEx.GetAlphaMask().GetBitmap()); - BitmapScopedReadAccess pReadAccess(rBitmapEx.GetBitmap()); - BitmapScopedReadAccess pAlphaReadAccess(aSrcAlpha); + BitmapScopedReadAccess pReadAccess(rBitmap); const tools::Long nHeight(pReadAccess->Height()); const tools::Long nWidth(pReadAccess->Width()); mpCairoSurface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, nWidth, nHeight); @@ -450,8 +448,7 @@ class CairoSurfaceHelper for (tools::Long x(0); x < nWidth; ++x) { const BitmapColor aColor(pReadAccess->GetColor(y, x)); - const BitmapColor aAlpha(pAlphaReadAccess->GetColor(y, x)); - const sal_uInt16 nAlpha(aAlpha.GetRed()); + const sal_uInt16 nAlpha(aColor.GetAlpha()); pPixelData[SVP_CAIRO_RED] = vcl::bitmap::premultiply(aColor.GetRed(), nAlpha); pPixelData[SVP_CAIRO_GREEN] = vcl::bitmap::premultiply(aColor.GetGreen(), nAlpha); @@ -465,9 +462,9 @@ class CairoSurfaceHelper } // create 32bit RGB data for given BitmapEx - void createRGB(const BitmapEx& rBitmapEx) + void createRGB(const Bitmap& rBitmap) { - BitmapScopedReadAccess pReadAccess(rBitmapEx.GetBitmap()); + BitmapScopedReadAccess pReadAccess(rBitmap); const tools::Long nHeight(pReadAccess->Height()); const tools::Long nWidth(pReadAccess->Width()); mpCairoSurface = cairo_image_surface_create(CAIRO_FORMAT_RGB24, nWidth, nHeight); @@ -502,9 +499,9 @@ class CairoSurfaceHelper // #define TEST_RGB16 #ifdef TEST_RGB16 // experimental: create 16bit RGB data for given BitmapEx - void createRGB16(const BitmapEx& rBitmapEx) + void createRGB16(const BitmapEx& rBitmap) { - BitmapScopedReadAccess pReadAccess(rBitmapEx.GetBitmap()); + BitmapScopedReadAccess pReadAccess(rBitmap); const tools::Long nHeight(pReadAccess->Height()); const tools::Long nWidth(pReadAccess->Width()); mpCairoSurface = cairo_image_surface_create(CAIRO_FORMAT_RGB16_565, nWidth, nHeight); @@ -542,17 +539,17 @@ class CairoSurfaceHelper #endif public: - CairoSurfaceHelper(const BitmapEx& rBitmapEx) + CairoSurfaceHelper(const Bitmap& rBitmap) : mpCairoSurface(nullptr) , maDownscaled() { - if (rBitmapEx.IsAlpha()) - createRGBA(rBitmapEx); + if (rBitmap.HasAlpha()) + createRGBA(rBitmap); else #ifdef TEST_RGB16 - createRGB16(rBitmapEx); + createRGB16(rBitmap); #else - createRGB(rBitmapEx); + createRGB(rBitmap); #endif } @@ -665,19 +662,12 @@ class SystemDependentData_CairoSurface : public basegfx::SystemDependentData // the CairoSurface holder std::shared_ptr<CairoSurfaceHelper> mpCairoSurfaceHelper; - // need to remember alpha source for combined BitmapEx to detect/ - // react on that changing - std::shared_ptr<SalBitmap> maAssociatedAlpha; - public: - SystemDependentData_CairoSurface(const BitmapEx& rBitmapEx) + SystemDependentData_CairoSurface(const Bitmap& rBitmap) : basegfx::SystemDependentData(Application::GetSystemDependentDataManager(), basegfx::SDD_Type::SDDType_CairoSurface) - , mpCairoSurfaceHelper(std::make_shared<CairoSurfaceHelper>(rBitmapEx)) - , maAssociatedAlpha() + , mpCairoSurfaceHelper(std::make_shared<CairoSurfaceHelper>(rBitmap)) { - if (rBitmapEx.IsAlpha()) - maAssociatedAlpha = rBitmapEx.GetAlphaMask().GetBitmap().ImplGetSalBitmap(); } // read access @@ -685,7 +675,6 @@ public: { return mpCairoSurfaceHelper; } - const std::shared_ptr<SalBitmap>& getAssociatedAlpha() const { return maAssociatedAlpha; } virtual sal_Int64 estimateUsageInBytes() const override; }; @@ -714,10 +703,9 @@ sal_Int64 SystemDependentData_CairoSurface::estimateUsageInBytes() const return nRetval; } -std::shared_ptr<CairoSurfaceHelper> getOrCreateCairoSurfaceHelper(const BitmapEx& rBitmapEx) +std::shared_ptr<CairoSurfaceHelper> getOrCreateCairoSurfaceHelper(const Bitmap& rBitmap) { - const basegfx::SystemDependentDataHolder* pHolder( - rBitmapEx.GetBitmap().accessSystemDependentDataHolder()); + const basegfx::SystemDependentDataHolder* pHolder(rBitmap.accessSystemDependentDataHolder()); std::shared_ptr<SystemDependentData_CairoSurface> pSystemDependentData_CairoSurface; if (nullptr != pHolder) @@ -726,22 +714,13 @@ std::shared_ptr<CairoSurfaceHelper> getOrCreateCairoSurfaceHelper(const BitmapEx pSystemDependentData_CairoSurface = std::static_pointer_cast<SystemDependentData_CairoSurface>( pHolder->getSystemDependentData(basegfx::SDD_Type::SDDType_CairoSurface)); - - // check data validity for associated Alpha - if (pSystemDependentData_CairoSurface && rBitmapEx.IsAlpha() - && pSystemDependentData_CairoSurface->getAssociatedAlpha() - != rBitmapEx.GetAlphaMask().GetBitmap().ImplGetSalBitmap()) - { - // AssociatedAlpha did change, data invalid - pSystemDependentData_CairoSurface.reset(); - } } if (!pSystemDependentData_CairoSurface) { // create new SystemDependentData_CairoSurface pSystemDependentData_CairoSurface - = std::make_shared<SystemDependentData_CairoSurface>(rBitmapEx); + = std::make_shared<SystemDependentData_CairoSurface>(rBitmap); // only add if feasible if (nullptr != pHolder @@ -1301,13 +1280,13 @@ void CairoPixelProcessor2D::processBitmapPrimitive2D( } } - paintBitmapAlpha(rBitmapCandidate.getBitmap(), rBitmapCandidate.getTransform()); + paintBitmapAlpha(Bitmap(rBitmapCandidate.getBitmap()), rBitmapCandidate.getTransform()); if (bDrawModeFlagsUsed) maBColorModifierStack.pop(); } -void CairoPixelProcessor2D::paintBitmapAlpha(const BitmapEx& rBitmapEx, +void CairoPixelProcessor2D::paintBitmapAlpha(const Bitmap& rBitmap, const basegfx::B2DHomMatrix& rTransform, double fTransparency) { @@ -1335,9 +1314,9 @@ void CairoPixelProcessor2D::paintBitmapAlpha(const BitmapEx& rBitmapEx, } } - BitmapEx aBitmapEx(rBitmapEx); + Bitmap aBitmap(rBitmap); - if (aBitmapEx.IsEmpty() || aBitmapEx.GetSizePixel().IsEmpty()) + if (aBitmap.IsEmpty() || aBitmap.GetSizePixel().IsEmpty()) { // no pixel data, done return; @@ -1346,9 +1325,9 @@ void CairoPixelProcessor2D::paintBitmapAlpha(const BitmapEx& rBitmapEx, if (maBColorModifierStack.count()) { // need to apply ColorModifier to Bitmap data - aBitmapEx = aBitmapEx.ModifyBitmapEx(maBColorModifierStack); + aBitmap = aBitmap.Modify(maBColorModifierStack); - if (aBitmapEx.IsEmpty()) + if (aBitmap.IsEmpty()) { // color gets completely replaced, get it const basegfx::BColor aModifiedColor( @@ -1367,8 +1346,7 @@ void CairoPixelProcessor2D::paintBitmapAlpha(const BitmapEx& rBitmapEx, } // access or create cairo bitmap data - std::shared_ptr<CairoSurfaceHelper> aCairoSurfaceHelper( - getOrCreateCairoSurfaceHelper(aBitmapEx)); + std::shared_ptr<CairoSurfaceHelper> aCairoSurfaceHelper(getOrCreateCairoSurfaceHelper(aBitmap)); if (!aCairoSurfaceHelper) { SAL_WARN("drawinglayer", "SDPRCairo: No SurfaceHelper from BitmapEx (!)"); @@ -2161,7 +2139,7 @@ void CairoPixelProcessor2D::processMarkerArrayPrimitive2D( // access or create cairo bitmap data std::shared_ptr<CairoSurfaceHelper> aCairoSurfaceHelper( - getOrCreateCairoSurfaceHelper(aBitmapEx)); + getOrCreateCairoSurfaceHelper(Bitmap(aBitmapEx))); if (!aCairoSurfaceHelper) { SAL_WARN("drawinglayer", "SDPRCairo: No SurfaceHelper from BitmapEx (!)"); @@ -2517,7 +2495,7 @@ void CairoPixelProcessor2D::processFillGraphicPrimitive2D( return; } - BitmapEx aPreparedBitmap; + Bitmap aPreparedBitmap; basegfx::B2DRange aFillUnitRange(rFillGraphicPrimitive2D.getFillGraphic().getGraphicRange()); constexpr double fBigDiscreteArea(300.0 * 300.0); @@ -2568,7 +2546,7 @@ void CairoPixelProcessor2D::processFillGraphicPrimitive2D( if (!aPreparedBitmap.IsEmpty() && maBColorModifierStack.count()) { // apply ColorModifier to Bitmap data - aPreparedBitmap = aPreparedBitmap.ModifyBitmapEx(maBColorModifierStack); + aPreparedBitmap = aPreparedBitmap.Modify(maBColorModifierStack); if (aPreparedBitmap.IsEmpty()) { @@ -3625,13 +3603,13 @@ void CairoPixelProcessor2D::processBitmapAlphaPrimitive2D( if (!rBitmapAlphaPrimitive2D.hasTransparency()) { // do what CairoPixelProcessor2D::processPolyPolygonColorPrimitive2D does - paintBitmapAlpha(rBitmapAlphaPrimitive2D.getBitmap(), + paintBitmapAlpha(Bitmap(rBitmapAlphaPrimitive2D.getBitmap()), rBitmapAlphaPrimitive2D.getTransform()); } else { // draw with alpha directly - paintBitmapAlpha(rBitmapAlphaPrimitive2D.getBitmap(), + paintBitmapAlpha(Bitmap(rBitmapAlphaPrimitive2D.getBitmap()), rBitmapAlphaPrimitive2D.getTransform(), rBitmapAlphaPrimitive2D.getTransparency()); } diff --git a/drawinglayer/source/processor2d/d2dpixelprocessor2d.cxx b/drawinglayer/source/processor2d/d2dpixelprocessor2d.cxx index 412fbaa92a59..16e116b2bd37 100644 --- a/drawinglayer/source/processor2d/d2dpixelprocessor2d.cxx +++ b/drawinglayer/source/processor2d/d2dpixelprocessor2d.cxx @@ -1817,7 +1817,7 @@ void D2DPixelProcessor2D::processFillGraphicPrimitive2D( return; } - BitmapEx aPreparedBitmap; + Bitmap aPreparedBitmap; basegfx::B2DRange aFillUnitRange(rFillGraphicPrimitive2D.getFillGraphic().getGraphicRange()); constexpr double fBigDiscreteArea(300.0 * 300.0); @@ -1842,7 +1842,7 @@ void D2DPixelProcessor2D::processFillGraphicPrimitive2D( if (maBColorModifierStack.count()) { // need to apply ColorModifier to Bitmap data - aPreparedBitmap = aPreparedBitmap.ModifyBitmapEx(maBColorModifierStack); + aPreparedBitmap = aPreparedBitmap.Modify(maBColorModifierStack); if (aPreparedBitmap.IsEmpty()) { @@ -1871,7 +1871,7 @@ void D2DPixelProcessor2D::processFillGraphicPrimitive2D( bool bDone(false); sal::systools::COMReference<ID2D1Bitmap> pD2DBitmap( - getOrCreateB2DBitmap(getRenderTarget(), aPreparedBitmap)); + getOrCreateB2DBitmap(getRenderTarget(), BitmapEx(aPreparedBitmap))); if (pD2DBitmap) { diff --git a/include/basegfx/utils/systemdependentdata.hxx b/include/basegfx/utils/systemdependentdata.hxx index b07ae267e662..2d174f21f548 100644 --- a/include/basegfx/utils/systemdependentdata.hxx +++ b/include/basegfx/utils/systemdependentdata.hxx @@ -51,6 +51,7 @@ namespace basegfx SDDType_MaskHelper, SDDType_CairoPath, SDDType_ModifiedBitmapEx, + SDDType_ModifiedBitmap, SDDType_GraphicsPath, SDDType_GdiPlusBitmap }; diff --git a/include/drawinglayer/primitive2d/fillgraphicprimitive2d.hxx b/include/drawinglayer/primitive2d/fillgraphicprimitive2d.hxx index 4688d3dacdf8..2f8e660b4397 100644 --- a/include/drawinglayer/primitive2d/fillgraphicprimitive2d.hxx +++ b/include/drawinglayer/primitive2d/fillgraphicprimitive2d.hxx @@ -38,7 +38,7 @@ namespace drawinglayer::processor2d // from there void setOffsetXYCreatedBitmap( drawinglayer::primitive2d::FillGraphicPrimitive2D&, - const BitmapEx&); + const Bitmap&); } // FillbitmapPrimitive2D class @@ -73,7 +73,7 @@ namespace drawinglayer::primitive2d attribute::FillGraphicAttribute maFillGraphic; /// the evtl. buffered OffsetXYCreatedBitmap - BitmapEx maOffsetXYCreatedBitmap; + Bitmap maOffsetXYCreatedBitmap; /// the transparency in range [0.0 .. 1.0] double mfTransparency; @@ -84,10 +84,10 @@ namespace drawinglayer::primitive2d // allow this single accessor to change it to set buggered data friend void drawinglayer::processor2d::setOffsetXYCreatedBitmap( drawinglayer::primitive2d::FillGraphicPrimitive2D&, - const BitmapEx&); + const Bitmap&); // private tooling method to be called by setOffsetXYCreatedBitmap - void impSetOffsetXYCreatedBitmap(const BitmapEx& rBitmap) + void impSetOffsetXYCreatedBitmap(const Bitmap& rBitmap) { maOffsetXYCreatedBitmap = rBitmap; } @@ -102,7 +102,7 @@ namespace drawinglayer::primitive2d /// data read access const basegfx::B2DHomMatrix& getTransformation() const { return maTransformation; } const attribute::FillGraphicAttribute& getFillGraphic() const { return maFillGraphic; } - const BitmapEx& getOffsetXYCreatedBitmap() const { return maOffsetXYCreatedBitmap; } + const Bitmap& getOffsetXYCreatedBitmap() const { return maOffsetXYCreatedBitmap; } double getTransparency() const { return mfTransparency; } bool hasTransparency() const { return !basegfx::fTools::equalZero(mfTransparency); } diff --git a/include/drawinglayer/processor2d/SDPRProcessor2dTools.hxx b/include/drawinglayer/processor2d/SDPRProcessor2dTools.hxx index 0dd81f594fa5..c26dc296cffe 100644 --- a/include/drawinglayer/processor2d/SDPRProcessor2dTools.hxx +++ b/include/drawinglayer/processor2d/SDPRProcessor2dTools.hxx @@ -36,6 +36,7 @@ namespace basegfx class B2DRange; } +class Bitmap; class BitmapEx; namespace drawinglayer::processor2d @@ -82,7 +83,7 @@ namespace drawinglayer::processor2d */ bool prepareBitmapForDirectRender( const drawinglayer::primitive2d::FillGraphicPrimitive2D& rFillGraphicPrimitive2D, - const drawinglayer::geometry::ViewInformation2D& rViewInformation2D, BitmapEx& rTarget, + const drawinglayer::geometry::ViewInformation2D& rViewInformation2D, Bitmap& rTarget, basegfx::B2DRange& rFillUnitRange, double fBigDiscreteArea = 300.0 * 300.0); /** helper to react/process if OffsetX/OffsetY of the FillGraphicAttribute is used. @@ -98,7 +99,7 @@ bool prepareBitmapForDirectRender( */ void takeCareOfOffsetXY( const drawinglayer::primitive2d::FillGraphicPrimitive2D& rFillGraphicPrimitive2D, - BitmapEx& rTarget, basegfx::B2DRange& rFillUnitRange); + Bitmap& rTarget, basegfx::B2DRange& rFillUnitRange); /** helper to calculate a discrete visible range based on a given logic range and a current ViewInformation2D. This is used for pixel renderers. diff --git a/include/drawinglayer/processor2d/cairopixelprocessor2d.hxx b/include/drawinglayer/processor2d/cairopixelprocessor2d.hxx index 3e5ecff28965..af3a1d63a710 100644 --- a/include/drawinglayer/processor2d/cairopixelprocessor2d.hxx +++ b/include/drawinglayer/processor2d/cairopixelprocessor2d.hxx @@ -61,6 +61,7 @@ namespace basegfx::utils class B2DHomMatrixBufferedOnDemandDecompose; } +class Bitmap; class BitmapEx; class OutputDevice; class SalLayout; @@ -134,7 +135,7 @@ class UNLESS_MERGELIBS(DRAWINGLAYER_DLLPUBLIC) CairoPixelProcessor2D final : pub void processPolyPolygonAlphaGradientPrimitive2D( const primitive2d::PolyPolygonAlphaGradientPrimitive2D& rPolyPolygonAlphaGradientPrimitive2D); - void paintBitmapAlpha(const BitmapEx& rBitmapEx, const basegfx::B2DHomMatrix& rTransform, + void paintBitmapAlpha(const Bitmap& rBitmap, const basegfx::B2DHomMatrix& rTransform, double fTransparency = 0.0); void processBitmapAlphaPrimitive2D( const primitive2d::BitmapAlphaPrimitive2D& rBitmapAlphaPrimitive2D); diff --git a/include/vcl/bitmap.hxx b/include/vcl/bitmap.hxx index 32d529d393fb..c0f2851b6889 100644 --- a/include/vcl/bitmap.hxx +++ b/include/vcl/bitmap.hxx @@ -37,6 +37,7 @@ #include <memory> class BitmapEx; +namespace basegfx { class BColorModifierStack; } inline sal_uInt8 GAMMA(double _def_cVal, double _def_InvGamma) { @@ -598,6 +599,14 @@ public: */ std::pair<Bitmap, AlphaMask> SplitIntoColorAndAlpha() const; + /** Create ColorStack-modified version of this BitmapEx + + @param rBColorModifierStack + A ColrModifierStack which defines how each pixel has to be modified + */ + [[nodiscard]] + Bitmap Modify( const basegfx::BColorModifierStack& rBColorModifierStack) const; + public: /** ReassignWithSize and recalculate bitmap. diff --git a/vcl/source/bitmap/bitmap.cxx b/vcl/source/bitmap/bitmap.cxx index 7471778967f7..72a84373d14f 100644 --- a/vcl/source/bitmap/bitmap.cxx +++ b/vcl/source/bitmap/bitmap.cxx @@ -37,6 +37,8 @@ #include <vcl/bitmap/BitmapMonochromeFilter.hxx> #include <vcl/ImageTree.hxx> +#include <basegfx/matrix/b2dhommatrixtools.hxx> +#include <basegfx/color/bcolormodifier.hxx> #include <bitmap/BitmapScaleSuperFilter.hxx> #include <bitmap/BitmapScaleConvolutionFilter.hxx> #include <bitmap/BitmapFastScaleFilter.hxx> @@ -1863,5 +1865,207 @@ void Bitmap::Expand(sal_Int32 nDX, sal_Int32 nDY, bool bExpandTransparent) operator=(Bitmap(aTmpEx)); } +namespace +{ +class BufferedData_ModifiedBitmap : public basegfx::SystemDependentData +{ + Bitmap maChangedBitmap; + basegfx::BColorModifierStack maBColorModifierStack; + +public: + BufferedData_ModifiedBitmap( + const Bitmap& rChangedBitmap, + const basegfx::BColorModifierStack& rBColorModifierStack) + : basegfx::SystemDependentData( + Application::GetSystemDependentDataManager(), + basegfx::SDD_Type::SDDType_ModifiedBitmap) + , 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_ModifiedBitmap::estimateUsageInBytes() const +{ + return maChangedBitmap.GetSizeBytes(); +} +} + +Bitmap Bitmap::Modify(const basegfx::BColorModifierStack& rBColorModifierStack) const +{ + if (0 == rBColorModifierStack.count()) + { + // no modifiers, done + return *this; + } + + // 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 && !HasAlpha()) + { + // 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 Bitmap(); + } + + const basegfx::SystemDependentDataHolder* pHolder(accessSystemDependentDataHolder()); + std::shared_ptr<BufferedData_ModifiedBitmap> pBufferedData_ModifiedBitmap; + + if (nullptr != pHolder) + { + // try to access SystemDependentDataHolder and buffered data + pBufferedData_ModifiedBitmap = std::static_pointer_cast<BufferedData_ModifiedBitmap>( + pHolder->getSystemDependentData(basegfx::SDD_Type::SDDType_ModifiedBitmap)); + + if (nullptr != pBufferedData_ModifiedBitmap + && !(pBufferedData_ModifiedBitmap->getBColorModifierStack() == rBColorModifierStack)) + { + // BColorModifierStack is different -> data invalid + pBufferedData_ModifiedBitmap = nullptr; + } + + if (nullptr != pBufferedData_ModifiedBitmap) + { + // found existing instance of modified Bitmap, return reused/buffered result + return pBufferedData_ModifiedBitmap->getChangedBitmap(); + } + } + + // have to create modified Bitmap + Bitmap aChangedBitmap(*this); + + 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); + SAL_WARN_IF(!xReadAccess, "vcl", "Got no Bitmap ReadAccess ?!?"); + + if(xReadAccess) + { + BitmapPalette aNewPalette(xReadAccess->GetPalette()); + aNewPalette[0] = BitmapColor(Color(pLastModifierReplace->getBColor())); + aChangedBitmap = Bitmap( + aChangedBitmap.GetSizePixel(), + aChangedBitmap.getPixelFormat(), + &aNewPalette); + } + } + else + { + // 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->HasPalette()) + { + const sal_uInt16 nCount(xContent->GetPaletteEntryCount()); + + 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), nHeight(xContent->Height()); y < nHeight; y++) + { + Scanline pScan = xContent->GetScanline(y); + + for(tools::Long x(0), nWidth(xContent->Width()); x < nWidth; x++) + { + const basegfx::BColor aBSource( + *(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::N24BitTcRgb == xContent->GetScanlineFormat()) + { + for(tools::Long y(0), nHeight(xContent->Height()); y < nHeight; y++) + { + Scanline pScan = xContent->GetScanline(y); + + for(tools::Long x(0), nWidth(xContent->Width()); x < nWidth; x++) + { + 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 + { + for(tools::Long y(0), nHeight(xContent->Height()); y < nHeight; y++) + { + Scanline pScanline = xContent->GetScanline( y ); + for(tools::Long x(0), nWidth(xContent->Width()); x < nWidth; 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(rBColorModifierStack.getModifiedColor(aBSource)); + + xContent->SetPixelOnData(pScanline, x, BitmapColor(Color(aBDest))); + } + } + } + } + } + + if (nullptr != pHolder) + { + // create new BufferedData_ModifiedBitmapEx (should be nullptr here) + if (nullptr == pBufferedData_ModifiedBitmap) + { + pBufferedData_ModifiedBitmap = std::make_shared<BufferedData_ModifiedBitmap>(aChangedBitmap, rBColorModifierStack); + } + + // register it, evtl. it's a new one + basegfx::SystemDependentData_SharedPtr r2(pBufferedData_ModifiedBitmap); + const_cast<basegfx::SystemDependentDataHolder*>(pHolder)->addOrReplaceSystemDependentData(r2); + } + + // return result + return aChangedBitmap; +} /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
