From 7f33bccce7be3e71dbbad07a7c2c04abd0b1647c Mon Sep 17 00:00:00 2001 From: Noel Grandin Date: Sun, 4 May 2025 23:18:39 +0200 Subject: [PATCH] improve the bitmap->alpha conversion MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit we do not need to go via this complex luminance calculation, we just want the red channel of the RGB data. This is also what the skia backends do, ever since commit 2fcfbd73768b69ba58607a054e7f851be2942992 Author: Luboš Luňák Date: Fri Apr 3 22:50:12 2020 +0200 no gray conversion needed for VCL alpha hacks Change-Id: Ie4a7adcc7c488d241ec58e64a130da544c3d39d0 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/184944 Reviewed-by: Noel Grandin Tested-by: Jenkins --- include/vcl/bitmap.hxx | 1 + vcl/source/bitmap/bitmap.cxx | 110 ++++++++++++++++++++++++++++++++++- 2 files changed, 109 insertions(+), 2 deletions(-) diff --git a/include/vcl/bitmap.hxx b/include/vcl/bitmap.hxx index ca13e2cc1a69..cfb2c1a95caa 100644 --- a/include/vcl/bitmap.hxx +++ b/include/vcl/bitmap.hxx @@ -580,6 +580,7 @@ public: SAL_DLLPRIVATE void ImplSetSalBitmap( const std::shared_ptr& xImpBmp ); SAL_DLLPRIVATE bool ImplMakeGreyscales(); + SAL_DLLPRIVATE bool ImplMake8BitNoConversion(); private: SAL_DLLPRIVATE bool ImplConvertUp(vcl::PixelFormat ePixelFormat, Color const* pExtColor = nullptr); diff --git a/vcl/source/bitmap/bitmap.cxx b/vcl/source/bitmap/bitmap.cxx index 8d38e3b889c0..cca49e45b3ea 100644 --- a/vcl/source/bitmap/bitmap.cxx +++ b/vcl/source/bitmap/bitmap.cxx @@ -861,10 +861,13 @@ bool Bitmap::Convert( BmpConversion eConversion ) break; case BmpConversion::N8BitGreys: - case BmpConversion::N8BitNoConversion: bRet = ImplMakeGreyscales(); break; + case BmpConversion::N8BitNoConversion: + bRet = ImplMake8BitNoConversion(); + break; + case BmpConversion::N8BitColors: { if( nBitCount < 8 ) @@ -1016,7 +1019,110 @@ bool Bitmap::ImplMakeGreyscales() return true; } -bool Bitmap::ImplConvertUp(vcl::PixelFormat ePixelFormat, Color const * pExtColor) +// Used for the bitmap->alpha layer conversion, just takes the red channel +bool Bitmap::ImplMake8BitNoConversion() +{ + BitmapScopedReadAccess pReadAcc(*this); + if (!pReadAcc) + return false; + + const BitmapPalette& rPal = GetGreyPalette(256); + bool bPalDiffers + = !pReadAcc->HasPalette() || (rPal.GetEntryCount() != pReadAcc->GetPaletteEntryCount()); + + if (!bPalDiffers) + bPalDiffers = (rPal != pReadAcc->GetPalette()); + if (!bPalDiffers) + return true; + + const auto ePixelFormat = vcl::PixelFormat::N8_BPP; + Bitmap aNewBmp(GetSizePixel(), ePixelFormat, &rPal); + BitmapScopedWriteAccess pWriteAcc(aNewBmp); + if (!pWriteAcc) + return false; + + const tools::Long nWidth = pWriteAcc->Width(); + const tools::Long nHeight = pWriteAcc->Height(); + + if (pReadAcc->HasPalette()) + { + for (tools::Long nY = 0; nY < nHeight; nY++) + { + Scanline pScanline = pWriteAcc->GetScanline(nY); + Scanline pScanlineRead = pReadAcc->GetScanline(nY); + for (tools::Long nX = 0; nX < nWidth; nX++) + { + const sal_uInt8 cIndex = pReadAcc->GetIndexFromData(pScanlineRead, nX); + pWriteAcc->SetPixelOnData( + pScanline, nX, + BitmapColor(pReadAcc->GetPaletteColor(cIndex).GetRed())); + } + } + } + else if (pReadAcc->GetScanlineFormat() == ScanlineFormat::N24BitTcBgr + && pWriteAcc->GetScanlineFormat() == ScanlineFormat::N8BitPal) + { + for (tools::Long nY = 0; nY < nHeight; nY++) + { + Scanline pReadScan = pReadAcc->GetScanline(nY); + Scanline pWriteScan = pWriteAcc->GetScanline(nY); + + for (tools::Long nX = 0; nX < nWidth; nX++) + { + pReadScan++; + pReadScan++; + const sal_uLong nR = *pReadScan++; + + *pWriteScan++ = static_cast(nR); + } + } + } + else if (pReadAcc->GetScanlineFormat() == ScanlineFormat::N24BitTcRgb + && pWriteAcc->GetScanlineFormat() == ScanlineFormat::N8BitPal) + { + for (tools::Long nY = 0; nY < nHeight; nY++) + { + Scanline pReadScan = pReadAcc->GetScanline(nY); + Scanline pWriteScan = pWriteAcc->GetScanline(nY); + + for (tools::Long nX = 0; nX < nWidth; nX++) + { + const sal_uLong nR = *pReadScan++; + pReadScan++; + pReadScan++; + + *pWriteScan++ = static_cast(nR); + } + } + } + else + { + for (tools::Long nY = 0; nY < nHeight; nY++) + { + Scanline pScanline = pWriteAcc->GetScanline(nY); + Scanline pScanlineRead = pReadAcc->GetScanline(nY); + for (tools::Long nX = 0; nX < nWidth; nX++) + pWriteAcc->SetPixelOnData( + pScanline, nX, + BitmapColor(pReadAcc->GetPixelFromData(pScanlineRead, nX).GetRed())); + } + } + + pWriteAcc.reset(); + pReadAcc.reset(); + + const MapMode aMap(maPrefMapMode); + const Size aSize(maPrefSize); + + *this = std::move(aNewBmp); + + maPrefMapMode = aMap; + maPrefSize = aSize; + + return true; +} + +bool Bitmap::ImplConvertUp(vcl::PixelFormat ePixelFormat, Color const* pExtColor) { SAL_WARN_IF(ePixelFormat <= getPixelFormat(), "vcl", "New pixel format must be greater!" );