include/vcl/alpha.hxx             |    9 ++++
 vcl/qa/cppunit/BitmapExTest.cxx   |   77 ++++++++++++++++++++++++++++++++++++++
 vcl/source/bitmap/BitmapEx.cxx    |    5 --
 vcl/source/bitmap/alpha.cxx       |   31 +++++++++++++++
 vcl/source/bitmap/bitmappaint.cxx |    3 +
 5 files changed, 122 insertions(+), 3 deletions(-)

New commits:
commit dcaa66e4663111f563eab54aae7e1d73e1ae8e44
Author:     Noel Grandin <noel.gran...@collabora.co.uk>
AuthorDate: Tue Oct 17 10:25:25 2023 +0200
Commit:     Noel Grandin <noel.gran...@collabora.co.uk>
CommitDate: Tue Oct 17 19:06:38 2023 +0200

    tdf#157792 FILEOPEN: PPT: logo not displayed
    
    regression from
        commit 3622404f09448b82c095256140afe6240b522ece
        Author: Noel Grandin <noel.gran...@collabora.co.uk>
        Date:   Wed Oct 11 12:54:43 2023 +0200
        tdf#157636 FILEOPEN: PPT: Images have no background
    
    But actually from
        commit 81994cb2b8b32453a92bcb011830fcb884f22ffe
        Convert internal vcl bitmap formats transparency->alpha (II)
    
    where BitmapEx::CombineMaskOr was not properly updated.
    
    To make this stuff more obvious, add a version of CombineOr
    called AlphaCombineOr that only operates on AlphaMask objects.
    
    Change-Id: I8222bcdd7babefb748d21a71d02775c6a74bf068
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/158085
    Tested-by: Jenkins
    Reviewed-by: Noel Grandin <noel.gran...@collabora.co.uk>

diff --git a/include/vcl/alpha.hxx b/include/vcl/alpha.hxx
index d10d4dcc7f31..9c6b1070ed53 100644
--- a/include/vcl/alpha.hxx
+++ b/include/vcl/alpha.hxx
@@ -51,6 +51,15 @@ public:
     void        Erase( sal_uInt8 cTransparency );
     void        BlendWith(const AlphaMask& rOther);
 
+    /** Perform boolean OR operation with another alpha-mask
+
+        @param rMask
+        The mask bitmap in the selected combine operation
+
+        @return true, if the operation was completed successfully.
+     */
+    bool        AlphaCombineOr( const AlphaMask& rMask );
+
     // check if alpha is used, returns true if at least one pixel has 
transparence
     bool        hasAlpha() const;
 
diff --git a/vcl/qa/cppunit/BitmapExTest.cxx b/vcl/qa/cppunit/BitmapExTest.cxx
index 9e5da1c9fab6..757cc8999538 100644
--- a/vcl/qa/cppunit/BitmapExTest.cxx
+++ b/vcl/qa/cppunit/BitmapExTest.cxx
@@ -25,12 +25,16 @@ class BitmapExTest : public CppUnit::TestFixture
     void testGetPixelColor32();
     void testTransformBitmapEx();
     void testAlphaBlendWith();
+    void testCreateMask();
+    void testCombineMaskOr();
 
     CPPUNIT_TEST_SUITE(BitmapExTest);
     CPPUNIT_TEST(testGetPixelColor24_8);
     CPPUNIT_TEST(testGetPixelColor32);
     CPPUNIT_TEST(testTransformBitmapEx);
     CPPUNIT_TEST(testAlphaBlendWith);
+    CPPUNIT_TEST(testCreateMask);
+    CPPUNIT_TEST(testCombineMaskOr);
     CPPUNIT_TEST_SUITE_END();
 };
 
@@ -167,6 +171,79 @@ void BitmapExTest::testAlphaBlendWith()
                          AlphaMask::ScopedReadAccess(alpha)->GetPixelIndex(0, 
0));
 }
 
+void BitmapExTest::testCreateMask()
+{
+    Bitmap aBitmap(Size(3, 3), vcl::PixelFormat::N24_BPP);
+    {
+        BitmapScopedWriteAccess pWriteAccess(aBitmap);
+        pWriteAccess->Erase(COL_WHITE);
+        for (int i = 0; i < 3; ++i)
+            pWriteAccess->SetPixel(i, i, COL_RED);
+    }
+    aBitmap = aBitmap.CreateMask(COL_RED, 1);
+    Bitmap::ScopedReadAccess pAccess(aBitmap);
+    // the output is a greyscale palette bitmap
+    CPPUNIT_ASSERT_EQUAL(sal_uInt8(0xff), pAccess->GetPixelIndex(0, 0));
+    CPPUNIT_ASSERT_EQUAL(sal_uInt8(0x00), pAccess->GetPixelIndex(0, 1));
+    CPPUNIT_ASSERT_EQUAL(sal_uInt8(0x00), pAccess->GetPixelIndex(0, 2));
+    CPPUNIT_ASSERT_EQUAL(sal_uInt8(0x00), pAccess->GetPixelIndex(1, 0));
+    CPPUNIT_ASSERT_EQUAL(sal_uInt8(0xff), pAccess->GetPixelIndex(1, 1));
+    CPPUNIT_ASSERT_EQUAL(sal_uInt8(0x00), pAccess->GetPixelIndex(1, 2));
+    CPPUNIT_ASSERT_EQUAL(sal_uInt8(0x00), pAccess->GetPixelIndex(2, 0));
+    CPPUNIT_ASSERT_EQUAL(sal_uInt8(0x00), pAccess->GetPixelIndex(2, 1));
+    CPPUNIT_ASSERT_EQUAL(sal_uInt8(0xff), pAccess->GetPixelIndex(2, 2));
+}
+
+void BitmapExTest::testCombineMaskOr()
+{
+    Bitmap aBitmap(Size(3, 3), vcl::PixelFormat::N24_BPP);
+    {
+        BitmapScopedWriteAccess pWriteAccess(aBitmap);
+        pWriteAccess->Erase(COL_WHITE);
+        for (int i = 0; i < 3; ++i)
+            pWriteAccess->SetPixel(1, i, COL_RED);
+    }
+    AlphaMask aAlphaBitmap(Size(3, 3));
+    {
+        BitmapScopedWriteAccess pWriteAccess(aAlphaBitmap);
+        pWriteAccess->Erase(Color(0xff, 0xff, 0xff));
+        for (int i = 1; i < 3; ++i)
+        {
+            pWriteAccess->SetPixel(i, 0, Color(0x00, 0x00, 0x00));
+            pWriteAccess->SetPixel(i, 1, Color(0x80, 0x80, 0x80));
+            pWriteAccess->SetPixel(i, 0, Color(0xef, 0xef, 0xef));
+        }
+    }
+
+    {
+        AlphaMask aMask = aBitmap.CreateAlphaMask(COL_RED, 1);
+        Bitmap::ScopedReadAccess pAccess(aMask);
+        // the output is a greyscale palette bitmap
+        CPPUNIT_ASSERT_EQUAL(sal_uInt8(0xff), pAccess->GetPixelIndex(0, 0));
+        CPPUNIT_ASSERT_EQUAL(sal_uInt8(0xff), pAccess->GetPixelIndex(0, 1));
+        CPPUNIT_ASSERT_EQUAL(sal_uInt8(0xff), pAccess->GetPixelIndex(0, 2));
+        CPPUNIT_ASSERT_EQUAL(sal_uInt8(0x00), pAccess->GetPixelIndex(1, 0));
+        CPPUNIT_ASSERT_EQUAL(sal_uInt8(0x00), pAccess->GetPixelIndex(1, 1));
+        CPPUNIT_ASSERT_EQUAL(sal_uInt8(0x00), pAccess->GetPixelIndex(1, 2));
+        CPPUNIT_ASSERT_EQUAL(sal_uInt8(0xff), pAccess->GetPixelIndex(2, 0));
+        CPPUNIT_ASSERT_EQUAL(sal_uInt8(0xff), pAccess->GetPixelIndex(2, 1));
+        CPPUNIT_ASSERT_EQUAL(sal_uInt8(0xff), pAccess->GetPixelIndex(2, 2));
+    }
+
+    BitmapEx aBitmapEx(aBitmap, aAlphaBitmap);
+    aBitmapEx.CombineMaskOr(COL_RED, 1);
+
+    CPPUNIT_ASSERT_EQUAL(Color(ColorAlpha, 0xff, 0xff, 0xff, 0xff), 
aBitmapEx.GetPixelColor(0, 0));
+    CPPUNIT_ASSERT_EQUAL(Color(ColorAlpha, 0x00, 0x80, 0x00, 0x00), 
aBitmapEx.GetPixelColor(0, 1));
+    CPPUNIT_ASSERT_EQUAL(Color(ColorAlpha, 0x00, 0xff, 0xff, 0xff), 
aBitmapEx.GetPixelColor(0, 2));
+    CPPUNIT_ASSERT_EQUAL(Color(ColorAlpha, 0xff, 0xff, 0xff, 0xff), 
aBitmapEx.GetPixelColor(1, 0));
+    CPPUNIT_ASSERT_EQUAL(Color(ColorAlpha, 0x00, 0x80, 0x00, 0x00), 
aBitmapEx.GetPixelColor(1, 1));
+    CPPUNIT_ASSERT_EQUAL(Color(ColorAlpha, 0x00, 0xff, 0xff, 0xff), 
aBitmapEx.GetPixelColor(1, 2));
+    CPPUNIT_ASSERT_EQUAL(Color(ColorAlpha, 0xff, 0xff, 0xff, 0xff), 
aBitmapEx.GetPixelColor(2, 0));
+    CPPUNIT_ASSERT_EQUAL(Color(ColorAlpha, 0x00, 0x80, 0x00, 0x00), 
aBitmapEx.GetPixelColor(2, 1));
+    CPPUNIT_ASSERT_EQUAL(Color(ColorAlpha, 0xff, 0xff, 0xff, 0xff), 
aBitmapEx.GetPixelColor(2, 2));
+}
+
 } // namespace
 
 CPPUNIT_TEST_SUITE_REGISTRATION(BitmapExTest);
diff --git a/vcl/source/bitmap/BitmapEx.cxx b/vcl/source/bitmap/BitmapEx.cxx
index 7333aea90cc3..5608254e68bb 100644
--- a/vcl/source/bitmap/BitmapEx.cxx
+++ b/vcl/source/bitmap/BitmapEx.cxx
@@ -1444,10 +1444,9 @@ void BitmapEx::AdjustTransparency(sal_uInt8 cTrans)
 
 void BitmapEx::CombineMaskOr(Color maskColor, sal_uInt8 nTol)
 {
-    Bitmap aNewMask = maBitmap.CreateMask( maskColor, nTol );
+    AlphaMask aNewMask = maBitmap.CreateAlphaMask( maskColor, nTol );
     if ( IsAlpha() )
-         aNewMask.CombineOr( maAlphaMask );
-    aNewMask.Invert();
+         aNewMask.AlphaCombineOr( maAlphaMask );
     maAlphaMask = aNewMask;
 }
 
diff --git a/vcl/source/bitmap/alpha.cxx b/vcl/source/bitmap/alpha.cxx
index cb8be28664d4..005edbea20de 100644
--- a/vcl/source/bitmap/alpha.cxx
+++ b/vcl/source/bitmap/alpha.cxx
@@ -182,4 +182,35 @@ void AlphaMask::ReleaseAccess( BitmapReadAccess* pAccess )
     assert( HasGreyPalette8Bit() && "alpha bitmap should have greyscale 
palette" );
 }
 
+bool AlphaMask::AlphaCombineOr(const AlphaMask& rMask)
+{
+    ScopedReadAccess pMaskAcc(const_cast<AlphaMask&>(rMask));
+    AlphaScopedWriteAccess pAcc(*this);
+
+    if (!pMaskAcc || !pAcc)
+        return false;
+
+    assert (pMaskAcc->GetBitCount() == 8 && pAcc->GetBitCount() == 8);
+
+    const tools::Long nWidth = std::min(pMaskAcc->Width(), pAcc->Width());
+    const tools::Long nHeight = std::min(pMaskAcc->Height(), pAcc->Height());
+
+    for (tools::Long nY = 0; nY < nHeight; nY++)
+    {
+        Scanline pScanline = pAcc->GetScanline(nY);
+        ConstScanline pScanlineMask = pMaskAcc->GetScanline(nY);
+        for (tools::Long nX = 0; nX < nWidth; nX++)
+        {
+            if (*pScanlineMask != 255 || *pScanline != 255)
+                *pScanline = 0;
+            else
+                *pScanline = 255;
+            ++pScanline;
+            ++pScanlineMask;
+        }
+    }
+
+    return true;
+}
+
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/source/bitmap/bitmappaint.cxx 
b/vcl/source/bitmap/bitmappaint.cxx
index dc4fda1eedac..f3e51dd2af64 100644
--- a/vcl/source/bitmap/bitmappaint.cxx
+++ b/vcl/source/bitmap/bitmappaint.cxx
@@ -1164,6 +1164,9 @@ bool Bitmap::Replace(const Color* pSearchColors, const 
Color* pReplaceColors, si
 
 bool Bitmap::CombineOr(const Bitmap& rMask)
 {
+    assert(!dynamic_cast<AlphaMask*>(this) && "should rather be calling 
AlphaMask::AlphaCombineOr");
+    assert(!dynamic_cast<const AlphaMask*>(&rMask)
+           && "should rather be calling AlphaMask::AlphaCombineOr");
     ScopedReadAccess pMaskAcc(const_cast<Bitmap&>(rMask));
     BitmapScopedWriteAccess pAcc(*this);
 

Reply via email to