include/vcl/bitmap.hxx               |   12 +++++
 vcl/inc/bitmap/BitmapWriteAccess.hxx |    7 +++
 vcl/source/bitmap/bitmappaint.cxx    |   75 +++++++++++++++++++++++++++++++++++
 vcl/source/filter/egif/egif.cxx      |    6 ++
 4 files changed, 99 insertions(+), 1 deletion(-)

New commits:
commit f76acf9bd97e65ba50303b6e5a25e5877996ebe1
Author:     Noel Grandin <noel.gran...@collabora.co.uk>
AuthorDate: Wed Aug 2 15:26:06 2023 +0200
Commit:     Noel Grandin <noel.gran...@collabora.co.uk>
CommitDate: Wed Aug 2 18:22:28 2023 +0200

    tdf#156525 Save as > HTML loses drawing object as invalid gif
    
    regression from
        commit 1c7cbd685633d44eac554629572f3401c450f855
        Author: Noel Grandin <noel.gran...@collabora.co.uk>
        Date:   Sun May 7 16:56:21 2023 +0200
        use AlphaMask for variables when calling GetAlphaMask
    
    where after my change, the code is now calling
        Bitmap::Replace(AlphaMask,...)
    instead of
        Bitmap::Replace(Bitmap,...)
    and those two methods do quite different things.
    
    However, we have to
    (*) restore Bitmap::Replace(Bitmap,...) which was removed in
        commit 8270eb5d5600cc84dbf5f0e339f90c4519ef88bb
        Author: Noel Grandin <noel.gran...@collabora.co.uk>
        Date:   Fri May 19 13:35:31 2023 +0200
        loplugin:unusedmethods
    (*) restore BitmapWriteAccess::SetPaletteEntryCount which was removed in
        commit 74cd0d0b281f8df75612bfb600df2eae62c4d21d
        Author: Noel Grandin <noel.gran...@collabora.co.uk>
        Date:   Thu Jun 29 13:53:30 2023 +0200
        loplugin:unusedmethods
    (*) Invert the mask/alpha layer, since after
        commit 81994cb2b8b32453a92bcb011830fcb884f22ff3
        Author: Noel Grandin <noelgran...@gmail.com>
        Date:   Fri Apr 16 20:33:10 2021 +0200
        Convert internal vcl bitmap formats transparency->alpha (II)
    we are dealing with real alpha, and not transparency.
    
    Also add an assert in GIFWriter::WriteAccess, since it is a logic error
    to get here and have the image in the wrong format.
    
    Change-Id: I0e09b3ca82af0bd5b58d80e0a6eac4c7bdf7c48e
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/155254
    Tested-by: Jenkins
    Reviewed-by: Noel Grandin <noel.gran...@collabora.co.uk>

diff --git a/include/vcl/bitmap.hxx b/include/vcl/bitmap.hxx
index bc0d628179ca..1c5f7bcc7ec6 100644
--- a/include/vcl/bitmap.hxx
+++ b/include/vcl/bitmap.hxx
@@ -430,6 +430,18 @@ public:
      */
     bool                    Replace( const AlphaMask& rAlpha, const Color& 
rMergeColor );
 
+    /** Replace all pixel where the given mask/alpha layer is on with the 
specified color
+
+        @param rMask
+        Mask specifying which pixel should be replaced
+
+        @param rReplaceColor
+        Color to be placed in all changed pixel
+
+        @return true, if the operation was completed successfully.
+     */
+    bool                    ReplaceMask( const AlphaMask& rMask, const Color& 
rReplaceColor );
+
     /** Replace all pixel having the search color with the specified color
 
         @param rSearchColor
diff --git a/vcl/inc/bitmap/BitmapWriteAccess.hxx 
b/vcl/inc/bitmap/BitmapWriteAccess.hxx
index 216eb16806e4..bc903769d679 100644
--- a/vcl/inc/bitmap/BitmapWriteAccess.hxx
+++ b/vcl/inc/bitmap/BitmapWriteAccess.hxx
@@ -39,6 +39,13 @@ public:
         mpBuffer->maPalette = rPalette;
     }
 
+    void SetPaletteEntryCount(sal_uInt16 nCount)
+    {
+        assert(mpBuffer && "Access is not valid!");
+
+        mpBuffer->maPalette.SetEntryCount(nCount);
+    }
+
     void SetPaletteColor(sal_uInt16 nColor, const BitmapColor& rBitmapColor)
     {
         assert(mpBuffer && "Access is not valid!");
diff --git a/vcl/source/bitmap/bitmappaint.cxx 
b/vcl/source/bitmap/bitmappaint.cxx
index 487e6d1a6ad6..91a43b951748 100644
--- a/vcl/source/bitmap/bitmappaint.cxx
+++ b/vcl/source/bitmap/bitmappaint.cxx
@@ -884,6 +884,81 @@ vcl::Region Bitmap::CreateRegion(const Color& rColor, 
const tools::Rectangle& rR
     return aRegion;
 }
 
+bool Bitmap::ReplaceMask(const AlphaMask& rMask, const Color& rReplaceColor)
+{
+    ScopedReadAccess pMaskAcc(const_cast<AlphaMask&>(rMask));
+    BitmapScopedWriteAccess pAcc(*this);
+
+    if (!pMaskAcc || !pAcc)
+        return false;
+
+    const tools::Long nWidth = std::min(pMaskAcc->Width(), pAcc->Width());
+    const tools::Long nHeight = std::min(pMaskAcc->Height(), pAcc->Height());
+    const BitmapColor aMaskWhite(pMaskAcc->GetBestMatchingColor(COL_WHITE));
+    BitmapColor aReplace;
+
+    if (pAcc->HasPalette())
+    {
+        const sal_uInt16 nActColors = pAcc->GetPaletteEntryCount();
+        const sal_uInt16 nMaxColors = 1 << pAcc->GetBitCount();
+
+        // default to the nearest color
+        aReplace = pAcc->GetBestMatchingColor(rReplaceColor);
+
+        // for paletted images without a matching palette entry
+        // look for an unused palette entry (NOTE: expensive!)
+        if (pAcc->GetPaletteColor(aReplace.GetIndex()) != 
BitmapColor(rReplaceColor))
+        {
+            // if the palette has empty entries use the last one
+            if (nActColors < nMaxColors)
+            {
+                pAcc->SetPaletteEntryCount(nActColors + 1);
+                pAcc->SetPaletteColor(nActColors, rReplaceColor);
+                aReplace = BitmapColor(static_cast<sal_uInt8>(nActColors));
+            }
+            else
+            {
+                std::unique_ptr<bool[]> pFlags(new bool[nMaxColors]);
+
+                // Set all entries to false
+                std::fill(pFlags.get(), pFlags.get() + nMaxColors, false);
+
+                for (tools::Long nY = 0; nY < nHeight; nY++)
+                {
+                    Scanline pScanline = pAcc->GetScanline(nY);
+                    for (tools::Long nX = 0; nX < nWidth; nX++)
+                        pFlags[pAcc->GetIndexFromData(pScanline, nX)] = true;
+                }
+
+                for (sal_uInt16 i = 0; i < nMaxColors; i++)
+                {
+                    // Hurray, we do have an unused entry
+                    if (!pFlags[i])
+                    {
+                        pAcc->SetPaletteColor(i, rReplaceColor);
+                        aReplace = BitmapColor(static_cast<sal_uInt8>(i));
+                    }
+                }
+            }
+        }
+    }
+    else
+        aReplace = rReplaceColor;
+
+    for (tools::Long nY = 0; nY < nHeight; nY++)
+    {
+        Scanline pScanline = pAcc->GetScanline(nY);
+        Scanline pScanlineMask = pMaskAcc->GetScanline(nY);
+        for (tools::Long nX = 0; nX < nWidth; nX++)
+        {
+            if (pMaskAcc->GetPixelFromData(pScanlineMask, nX) == aMaskWhite)
+                pAcc->SetPixelOnData(pScanline, nX, aReplace);
+        }
+    }
+
+    return true;
+}
+
 bool Bitmap::Replace(const AlphaMask& rAlpha, const Color& rMergeColor)
 {
     Bitmap aNewBmp(GetSizePixel(), vcl::PixelFormat::N24_BPP);
diff --git a/vcl/source/filter/egif/egif.cxx b/vcl/source/filter/egif/egif.cxx
index 8da427a86c19..d213c7777178 100644
--- a/vcl/source/filter/egif/egif.cxx
+++ b/vcl/source/filter/egif/egif.cxx
@@ -252,7 +252,8 @@ bool GIFWriter::CreateAccess( const BitmapEx& rBmpEx )
             if( aAccBmp.Convert( BmpConversion::N8BitTrans ) )
             {
                 aMask.Convert( BmpConversion::N1BitThreshold );
-                aAccBmp.Replace( aMask, BMP_COL_TRANS );
+                aMask.Invert();
+                aAccBmp.ReplaceMask( aMask, BMP_COL_TRANS );
                 bTransparent = true;
             }
             else
@@ -467,6 +468,9 @@ void GIFWriter::WriteAccess()
     if( !bNative )
         pBuffer.reset(new sal_uInt8[ nWidth ]);
 
+    assert(bStatus && "should not calling here if status is bad");
+    assert( 8 == m_pAcc->GetBitCount() && m_pAcc->HasPalette()
+            && "by the time we get here, the image should be in palette 
format");
     if( !(bStatus && ( 8 == m_pAcc->GetBitCount() ) && m_pAcc->HasPalette()) )
         return;
 

Reply via email to