include/vcl/bitmap.hxx | 12 ++++++ vcl/source/bitmap/bitmappaint.cxx | 75 ++++++++++++++++++++++++++++++++++++++ vcl/source/filter/egif/egif.cxx | 6 ++- 3 files changed, 92 insertions(+), 1 deletion(-)
New commits: commit f22c23e71d4ae628e9e90ee98d22d1fc8fca1619 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: Mon Oct 2 15:38:32 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> (cherry picked from commit f76acf9bd97e65ba50303b6e5a25e5877996ebe1) Reviewed-on: https://gerrit.libreoffice.org/c/core/+/157457 Reviewed-by: Michael Stahl <michael.st...@allotropia.de> diff --git a/include/vcl/bitmap.hxx b/include/vcl/bitmap.hxx index 0c794d496342..065579de9577 100644 --- a/include/vcl/bitmap.hxx +++ b/include/vcl/bitmap.hxx @@ -399,6 +399,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/source/bitmap/bitmappaint.cxx b/vcl/source/bitmap/bitmappaint.cxx index f454aa97affa..b0933d2ba6d8 100644 --- a/vcl/source/bitmap/bitmappaint.cxx +++ b/vcl/source/bitmap/bitmappaint.cxx @@ -706,6 +706,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;