include/vcl/bitmap.hxx         |    4 -
 include/vcl/bitmapex.hxx       |    3 -
 vcl/source/bitmap/BitmapEx.cxx |   17 ------
 vcl/source/bitmap/bitmap.cxx   |  102 ++++++++++++++++++++++++++++++-----------
 4 files changed, 77 insertions(+), 49 deletions(-)

New commits:
commit a65a224c2b1b9b5fcccfb04ca14d37a8d615b85e
Author:     Noel Grandin <[email protected]>
AuthorDate: Fri Sep 5 11:01:20 2025 +0200
Commit:     Noel Grandin <[email protected]>
CommitDate: Fri Sep 5 16:55:12 2025 +0200

    use less BitmapEx in Bitmap
    
    we want Bitmap to be independant of BitmapEx
    
    Change-Id: I47dc1e62f5575a75fd2e9e78085146b079c49187
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/190616
    Reviewed-by: Noel Grandin <[email protected]>
    Tested-by: Jenkins

diff --git a/include/vcl/bitmap.hxx b/include/vcl/bitmap.hxx
index 3cb18150a00d..2005bfeab669 100644
--- a/include/vcl/bitmap.hxx
+++ b/include/vcl/bitmap.hxx
@@ -38,7 +38,6 @@
 #include <memory>
 
 class AlphaMask;
-class BitmapEx;
 namespace basegfx { class BColorModifierStack; }
 namespace com::sun::star::rendering {
     class XBitmapCanvas;
@@ -119,7 +118,6 @@ public:
     explicit                Bitmap( const OUString& rIconName );
                             Bitmap( const Bitmap& rBitmap );
                             Bitmap( const Bitmap& rBitmap, Point aSrc, Size 
aSize );
-    explicit                Bitmap( const BitmapEx& rBitmapEx );
                             Bitmap( const Size& rSizePixel, vcl::PixelFormat 
ePixelFormat, const BitmapPalette* pPal = nullptr );
                             Bitmap( const Bitmap& rBmp, const Bitmap& rMask );
                             Bitmap( const Bitmap& rBmp, const AlphaMask& 
rAlphaMask );
@@ -658,7 +656,7 @@ public:
 
     /** Remove existing blending against COL_WHITE based on given AlphaMask
 
-        Inside convertToBitmapEx the content gets rendered to RGB target (no 
'A'),
+        Inside convertToBitmap the content gets rendered to RGB target (no 
'A'),
         so it gets blended against the start condition of the target device 
which
         is blank (usually white background, but others may be used).
         Usually rendering to RGB is sufficient (e.g. EditViews), but for 
conversion
diff --git a/include/vcl/bitmapex.hxx b/include/vcl/bitmapex.hxx
index 0b1a14e77fff..b319071bce85 100644
--- a/include/vcl/bitmapex.hxx
+++ b/include/vcl/bitmapex.hxx
@@ -439,9 +439,6 @@ public:
 
     SAL_DLLPRIVATE std::shared_ptr<SalBitmap> const & ImplGetBitmapSalBitmap() 
const { return maBitmap.ImplGetSalBitmap(); }
 
-    /// Dumps the pixels as PNG in bitmap.png.
-    void DumpAsPng(const char* pFileName = nullptr) const;
-
 private:
     friend class ImpGraphic;
     friend class OutputDevice;
diff --git a/vcl/source/bitmap/BitmapEx.cxx b/vcl/source/bitmap/BitmapEx.cxx
index 61f7db99a63b..8a853d2bdbd9 100644
--- a/vcl/source/bitmap/BitmapEx.cxx
+++ b/vcl/source/bitmap/BitmapEx.cxx
@@ -1311,21 +1311,4 @@ void  BitmapEx::GetColorModel(css::uno::Sequence< 
sal_Int32 >& rRGBPalette,
     rnBitCount = pReadAccess->GetBitCount();
 }
 
-void BitmapEx::DumpAsPng(const char* pFileName) const
-{
-    OUString sPath(u"file:///tmp/bitmap.png"_ustr);
-    if (pFileName)
-    {
-        sPath = OUString::fromUtf8(pFileName);
-    }
-    else if (OUString env = o3tl::getEnvironment(u"VCL_DUMP_BMP_PATH"_ustr); 
!env.isEmpty())
-    {
-        sPath = env;
-    }
-    SvFileStream aStream(sPath, StreamMode::STD_READWRITE | StreamMode::TRUNC);
-    assert(aStream.good());
-    vcl::PngImageWriter aWriter(aStream);
-    aWriter.write(Bitmap(*this));
-}
-
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/source/bitmap/bitmap.cxx b/vcl/source/bitmap/bitmap.cxx
index e38b0236daa3..db842d55090c 100644
--- a/vcl/source/bitmap/bitmap.cxx
+++ b/vcl/source/bitmap/bitmap.cxx
@@ -26,7 +26,6 @@
 
 #include <utility>
 #include <vcl/bitmap.hxx>
-#include <vcl/bitmapex.hxx>
 #include <vcl/outdev.hxx>
 
 #include <svdata.hxx>
@@ -141,26 +140,25 @@ Bitmap::Bitmap( const Size& rSizePixel, vcl::PixelFormat 
ePixelFormat, const Bit
     mxSalBmp->Create(rSizePixel, ePixelFormat, *pPal);
 }
 
-Bitmap::Bitmap(const BitmapEx& rBitmapEx)
-    : maPrefMapMode(rBitmapEx.GetPrefMapMode())
-    , maPrefSize(rBitmapEx.GetPrefSize())
+static Bitmap createBitmapFromColorAndAlpha(const Bitmap& rColorBitmap, const 
Bitmap& rAlphaBitmap)
 {
-    if (!rBitmapEx.IsAlpha())
-        mxSalBmp = rBitmapEx.GetBitmap().mxSalBmp;
+    if (rAlphaBitmap.IsEmpty())
+        return rColorBitmap;
     else
     {
-        Size aSize = rBitmapEx.GetSizePixel();
+        Size aSize = rColorBitmap.GetSizePixel();
         static const BitmapPalette aPalEmpty;
-        mxSalBmp = ImplGetSVData()->mpDefInst->CreateSalBitmap();
-        const bool bSuccess = mxSalBmp->Create(aSize, 
vcl::PixelFormat::N32_BPP, aPalEmpty);
+        std::shared_ptr<SalBitmap> xSalBmp = 
ImplGetSVData()->mpDefInst->CreateSalBitmap();
+        const bool bSuccess = xSalBmp->Create(aSize, 
vcl::PixelFormat::N32_BPP, aPalEmpty);
         if (!bSuccess)
         {
             SAL_WARN("vcl", "Bitmap::Bitmap(): could not create image");
-            return;
+            return Bitmap(xSalBmp);
         }
-        BitmapScopedReadAccess pReadColorAcc(rBitmapEx.GetBitmap());
-        BitmapScopedReadAccess pReadAlphaAcc(rBitmapEx.GetAlphaMask());
-        BitmapScopedWriteAccess pWriteAcc(*this);
+        Bitmap aRetBmp(xSalBmp);
+        BitmapScopedReadAccess pReadColorAcc(rColorBitmap);
+        BitmapScopedReadAccess pReadAlphaAcc(rAlphaBitmap);
+        BitmapScopedWriteAccess pWriteAcc(aRetBmp);
         auto nHeight = pReadColorAcc->Height();
         auto nWidth = pReadColorAcc->Width();
         bool bPalette = pReadColorAcc->HasPalette();
@@ -182,6 +180,7 @@ Bitmap::Bitmap(const BitmapEx& rBitmapEx)
                 pWriteAcc->SetPixelOnData(pScanlineWrite, nX, aCol);
             }
         }
+        return aRetBmp;
 
 // So.... in theory the following code should work, and be much more 
efficient. In practice, the gen/cairo
 // code is doing something weird involving masks that results in alpha not 
doing the same thing as on the other
@@ -227,23 +226,73 @@ void Bitmap::loadFromIconTheme( const OUString& rIconName 
)
         bSuccess = false;
     }
 
-    SAL_WARN_IF( !bSuccess, "vcl", "BitmapEx::BitmapEx(): could not load image 
" << rIconName << " via icon theme " << aIconTheme);
+    SAL_WARN_IF( !bSuccess, "vcl", "Bitmap::Bitmap(): could not load image " 
<< rIconName << " via icon theme " << aIconTheme);
 }
 
 Bitmap::Bitmap( const Bitmap& rBmp, const Bitmap& rMask )
 {
-    *this = Bitmap(BitmapEx(rBmp, rMask));
+    if (rMask.IsEmpty())
+    {
+        *this = rBmp;
+        return;
+    }
+
+    assert(typeid(rMask) != typeid(AlphaMask)
+        && "If this mask is actually an AlphaMask, then it will be inverted 
unnecessarily "
+           "and the alpha channel will be wrong");
+
+    AlphaMask aAlphaMask;
+    if( rMask.getPixelFormat() == vcl::PixelFormat::N8_BPP && 
rMask.HasGreyPalette8Bit() )
+    {
+        aAlphaMask = rMask;
+        aAlphaMask.Invert();
+    }
+    else if( rMask.getPixelFormat() == vcl::PixelFormat::N8_BPP )
+    {
+        Bitmap aMask(rMask);
+        BitmapFilter::Filter(aMask, BitmapMonochromeFilter(255));
+        aMask.Invert();
+        aAlphaMask = aMask;
+    }
+    else
+    {
+        // convert to alpha bitmap
+        SAL_WARN("vcl", "Bitmap: forced mask to monochrome");
+        Bitmap aMask(rMask);
+        BitmapFilter::Filter(aMask, BitmapMonochromeFilter(255));
+        aMask.Invert();
+        aAlphaMask = aMask;
+    }
+
+    if (!rBmp.IsEmpty() && rBmp.GetSizePixel() != aAlphaMask.GetSizePixel())
+    {
+        SAL_WARN("vcl", "Mask size differs from Bitmap size, corrected Mask 
(!)");
+        aAlphaMask.Scale(rBmp.GetSizePixel(), BmpScaleFlag::Fast);
+    }
+    *this = createBitmapFromColorAndAlpha(rBmp, aAlphaMask.GetBitmap());
 }
 
 Bitmap::Bitmap( const Bitmap& rBmp, const AlphaMask& rAlphaMask )
 {
-    *this = Bitmap(BitmapEx(rBmp, rAlphaMask));
+    if (!rBmp.IsEmpty() && !rAlphaMask.IsEmpty() && rBmp.GetSizePixel() != 
rAlphaMask.GetSizePixel())
+    {
+        SAL_WARN("vcl", "Alpha size differs from Bitmap size, corrected Mask 
(!)");
+        AlphaMask aNewMask = rAlphaMask;
+        aNewMask.Scale(rBmp.GetSizePixel(), BmpScaleFlag::Fast);
+        *this = createBitmapFromColorAndAlpha(rBmp, aNewMask.GetBitmap());
+    }
+    else
+        *this = createBitmapFromColorAndAlpha(rBmp, rAlphaMask.GetBitmap());
 }
 
 
 Bitmap::Bitmap( const Bitmap& rBmp, const Color& rTransparentColor )
 {
-    *this = Bitmap(BitmapEx(rBmp, rTransparentColor));
+    AlphaMask aAlphaMask = rBmp.CreateAlphaMask( rTransparentColor );
+
+    SAL_WARN_IF(rBmp.GetSizePixel() != aAlphaMask.GetSizePixel(), "vcl",
+                "Bitmap::Bitmap(): size mismatch for bitmap and alpha mask.");
+    *this = createBitmapFromColorAndAlpha(rBmp, aAlphaMask.GetBitmap());
 }
 
 
@@ -2051,7 +2100,7 @@ Bitmap Bitmap::Modify(const basegfx::BColorModifierStack& 
rBColorModifierStack)
     {
         // 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
+        // about that by returning empty Bitmap
         return Bitmap();
     }
 
@@ -2109,7 +2158,7 @@ Bitmap Bitmap::Modify(const basegfx::BColorModifierStack& 
rBColorModifierStack)
             AlphaMask aAlphaMask(CreateAlphaMask());
             Bitmap aTmpBitmap(CreateColorBitmap());
             aTmpBitmap.Erase(Color(pLastModifierReplace->getBColor()));
-            aChangedBitmap = Bitmap(BitmapEx(aTmpBitmap, aAlphaMask));
+            aChangedBitmap = createBitmapFromColorAndAlpha(aTmpBitmap, 
aAlphaMask.GetBitmap());
         }
         else
         {
@@ -2205,7 +2254,7 @@ Bitmap Bitmap::Modify(const basegfx::BColorModifierStack& 
rBColorModifierStack)
 
     if (nullptr != pHolder)
     {
-        // create new BufferedData_ModifiedBitmapEx (should be nullptr here)
+        // create new BufferedData_ModifiedBitmap (should be nullptr here)
         if (nullptr == pBufferedData_ModifiedBitmap)
         {
             pBufferedData_ModifiedBitmap = 
std::make_shared<BufferedData_ModifiedBitmap>(aChangedBitmap, 
rBColorModifierStack);
@@ -2236,14 +2285,16 @@ AlphaMask Bitmap::CreateAlphaMask() const
     assert(HasAlpha());
     if (!HasAlpha())
         return AlphaMask();
-    return BitmapEx(*this).GetAlphaMask();
+    std::pair<Bitmap, AlphaMask> aPair = SplitIntoColorAndAlpha();
+    return aPair.second;
 }
 
 Bitmap Bitmap::CreateColorBitmap() const
 {
     if (!HasAlpha())
         return *this;
-    return BitmapEx(*this).GetBitmap();
+    std::pair<Bitmap, AlphaMask> aPair = SplitIntoColorAndAlpha();
+    return aPair.first;
 }
 
 void Bitmap::ChangeColorAlpha( sal_uInt8 cIndexFrom, sal_Int8 nAlphaTo )
@@ -2278,8 +2329,7 @@ void Bitmap::AdjustTransparency(sal_uInt8 cTrans)
     if (!HasAlpha())
     {
         AlphaMask aAlpha(GetSizePixel(), &cTrans);
-        BitmapEx aNew( *this, aAlpha );
-        *this = Bitmap(aNew);
+        *this = createBitmapFromColorAndAlpha(*this, aAlpha.GetBitmap());
     }
     else
     {
@@ -2344,7 +2394,7 @@ void Bitmap::BlendAlpha(sal_uInt8 nAlpha)
     if (!HasAlpha())
     {
         sal_uInt8 cTrans = 255 - nAlpha;
-        *this = Bitmap(BitmapEx( *this, AlphaMask(GetSizePixel(), &cTrans) ));
+        *this = createBitmapFromColorAndAlpha( *this, 
AlphaMask(GetSizePixel(), &cTrans).GetBitmap() );
     }
     else
     {
@@ -2474,7 +2524,7 @@ void Bitmap::CombineMaskOr(Color rTransColor, sal_uInt8 
nTol)
     const MapMode aMap( maPrefMapMode );
     const Size aSize( maPrefSize );
 
-    *this = Bitmap(BitmapEx(aColBmp, aNewMask));
+    *this = createBitmapFromColorAndAlpha(aColBmp, aNewMask.GetBitmap());
 
     maPrefMapMode = aMap;
     maPrefSize = aSize;

Reply via email to