Make Bitmap::HasAlpha() more reliable

checking for 32-bit format is not sufficient when there are 32-bit
formats which do not have actual alpha data.

Change the SalBitmap backend interface to return ScanlineFormat
rather than BitCount, to give a more reliable picture.

Change-Id: I6dde931a05415a9fbe0e8e696173b58e744b0e0c
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/190242
Tested-by: Jenkins
Reviewed-by: Noel Grandin <noel.grandin@collabora.co.uk>
This commit is contained in:
Noel Grandin
2025-08-27 07:39:21 +02:00
parent 77b3fe6e85
commit 18b488deed
14 changed files with 137 additions and 80 deletions
+1 -1
View File
@@ -142,7 +142,7 @@ public:
bool HasGreyPalette8Bit() const;
bool HasGreyPaletteAny() const;
// does this bitmap have alpha information?
inline bool HasAlpha() const { return getPixelFormat() == vcl::PixelFormat::N32_BPP; }
bool HasAlpha() const;
/** return the alpha data, copied into an AlphaMask. Will assert if this Bitmap has no alpha. */
AlphaMask CreateAlphaMask() const;
+4 -9
View File
@@ -223,16 +223,11 @@ Size SvpSalBitmap::GetSize() const
return aSize;
}
sal_uInt16 SvpSalBitmap::GetBitCount() const
ScanlineFormat SvpSalBitmap::GetScanlineFormat() const
{
sal_uInt16 nBitCount;
if (moDIB.has_value())
nBitCount = moDIB->mnBitCount;
else
nBitCount = 0;
return nBitCount;
if (!moDIB.has_value())
return ScanlineFormat::NONE;
return moDIB->meFormat;
}
BitmapBuffer* SvpSalBitmap::AcquireBuffer(BitmapAccessMode)
+1 -1
View File
@@ -55,7 +55,7 @@ public:
}
SAL_DLLPRIVATE virtual void Destroy() final override;
SAL_DLLPRIVATE virtual Size GetSize() const override;
SAL_DLLPRIVATE virtual sal_uInt16 GetBitCount() const override;
SAL_DLLPRIVATE virtual ScanlineFormat GetScanlineFormat() const override;
SAL_DLLPRIVATE virtual BitmapBuffer* AcquireBuffer( BitmapAccessMode nMode ) override;
SAL_DLLPRIVATE virtual void ReleaseBuffer( BitmapBuffer* pBuffer, BitmapAccessMode nMode ) override;
+1 -1
View File
@@ -45,7 +45,7 @@ public:
Size& rSize) override;
virtual void Destroy() final override;
virtual Size GetSize() const override;
virtual sal_uInt16 GetBitCount() const override;
virtual ScanlineFormat GetScanlineFormat() const override;
virtual BitmapBuffer* AcquireBuffer(BitmapAccessMode nMode) override;
virtual void ReleaseBuffer(BitmapBuffer* pBuffer, BitmapAccessMode nMode) override;
+1 -1
View File
@@ -66,7 +66,7 @@ public:
void Destroy() override;
Size GetSize() const override;
sal_uInt16 GetBitCount() const override;
ScanlineFormat GetScanlineFormat() const override;
BitmapBuffer *AcquireBuffer( BitmapAccessMode nMode ) override;
void ReleaseBuffer( BitmapBuffer* pBuffer, BitmapAccessMode nMode ) override;
+2 -1
View File
@@ -71,7 +71,8 @@ public:
Size& rSize ) = 0;
virtual void Destroy() = 0;
virtual Size GetSize() const = 0;
virtual sal_uInt16 GetBitCount() const = 0;
sal_uInt16 GetBitCount() const;
virtual ScanlineFormat GetScanlineFormat() const = 0;
virtual BitmapBuffer* AcquireBuffer( BitmapAccessMode nMode ) = 0;
virtual void ReleaseBuffer( BitmapBuffer* pBuffer, BitmapAccessMode nMode ) = 0;
+1 -1
View File
@@ -47,7 +47,7 @@ public:
virtual void Destroy() final override;
virtual Size GetSize() const override;
virtual sal_uInt16 GetBitCount() const override;
virtual ScanlineFormat GetScanlineFormat() const override;
virtual BitmapBuffer* AcquireBuffer(BitmapAccessMode nMode) override;
virtual void ReleaseBuffer(BitmapBuffer* pBuffer, BitmapAccessMode nMode) override;
+1 -1
View File
@@ -81,7 +81,7 @@ public:
virtual void Destroy() override;
virtual Size GetSize() const override { return maSize; }
virtual sal_uInt16 GetBitCount() const override { return mnBitCount; }
virtual ScanlineFormat GetScanlineFormat() const override;
virtual BitmapBuffer* AcquireBuffer( BitmapAccessMode nMode ) override;
virtual void ReleaseBuffer( BitmapBuffer* pBuffer, BitmapAccessMode nMode ) override;
+24 -12
View File
@@ -96,11 +96,30 @@ Size QtBitmap::GetSize() const
return Size();
}
sal_uInt16 QtBitmap::GetBitCount() const
ScanlineFormat QtBitmap::GetScanlineFormat() const
{
if (m_pImage)
return getFormatBits(m_pImage->format());
return 0;
if (!m_pImage)
return ScanlineFormat::NONE;
auto nBits = getFormatBits(m_pImage->format());
switch (nBits)
{
case 1:
return ScanlineFormat::N1BitMsbPal;
case 8:
return ScanlineFormat::N8BitPal;
case 24:
return ScanlineFormat::N24BitTcRgb;
case 32:
{
#ifdef OSL_BIGENDIAN
return ScanlineFormat::N32BitTcArgb;
#else
return ScanlineFormat::N32BitTcBgra;
#endif
}
default:
abort();
}
}
BitmapBuffer* QtBitmap::AcquireBuffer(BitmapAccessMode /*nMode*/)
@@ -118,28 +137,21 @@ BitmapBuffer* QtBitmap::AcquireBuffer(BitmapAccessMode /*nMode*/)
pBuffer->mpBits = m_pImage->bits();
pBuffer->mnScanlineSize = m_pImage->bytesPerLine();
pBuffer->meDirection = ScanlineDirection::TopDown;
pBuffer->meFormat = GetScanlineFormat();
switch (pBuffer->mnBitCount)
{
case 1:
pBuffer->meFormat = ScanlineFormat::N1BitMsbPal;
pBuffer->maPalette = m_aPalette;
break;
case 8:
pBuffer->meFormat = ScanlineFormat::N8BitPal;
pBuffer->maPalette = m_aPalette;
break;
case 24:
pBuffer->meFormat = ScanlineFormat::N24BitTcRgb;
pBuffer->maPalette = aEmptyPalette;
break;
case 32:
{
#ifdef OSL_BIGENDIAN
pBuffer->meFormat = ScanlineFormat::N32BitTcArgb;
#else
pBuffer->meFormat = ScanlineFormat::N32BitTcBgra;
#endif
pBuffer->maPalette = aEmptyPalette;
break;
}
+14 -18
View File
@@ -320,9 +320,20 @@ Size QuartzSalBitmap::GetSize() const
return Size( mnWidth, mnHeight );
}
sal_uInt16 QuartzSalBitmap::GetBitCount() const
ScanlineFormat QuartzSalBitmap::GetScanlineFormat() const
{
return mnBits;
switch( mnBits )
{
case 1:
return ScanlineFormat::N1BitMsbPal;
case 8:
return ScanlineFormat::N8BitPal;
case 24:
return ScanlineFormat::N24BitTcBgr;
case 32:
return ScanlineFormat::N32BitTcArgb;
default: abort();
}
}
namespace {
@@ -427,22 +438,7 @@ BitmapBuffer* QuartzSalBitmap::AcquireBuffer( BitmapAccessMode /*nMode*/ )
pBuffer->mnScanlineSize = mnBytesPerRow;
pBuffer->mpBits = m_pUserBuffer.get();
pBuffer->mnBitCount = mnBits;
switch( mnBits )
{
case 1:
pBuffer->meFormat = ScanlineFormat::N1BitMsbPal;
break;
case 8:
pBuffer->meFormat = ScanlineFormat::N8BitPal;
break;
case 24:
pBuffer->meFormat = ScanlineFormat::N24BitTcBgr;
break;
case 32:
pBuffer->meFormat = ScanlineFormat::N32BitTcArgb;
break;
default: assert(false);
}
pBuffer->meFormat = GetScanlineFormat();
// some BitmapBuffer users depend on a complete palette
if( (mnBits <= 8) && !maPalette )
+29 -30
View File
@@ -201,7 +201,34 @@ void SkiaSalBitmap::Destroy()
Size SkiaSalBitmap::GetSize() const { return mSize; }
sal_uInt16 SkiaSalBitmap::GetBitCount() const { return mBitCount; }
ScanlineFormat SkiaSalBitmap::GetScanlineFormat() const
{
switch (mBitCount)
{
case 1:
return ScanlineFormat::N1BitMsbPal;
case 8:
return ScanlineFormat::N8BitPal;
case 24:
// Make the RGB/BGR format match the default Skia 32bpp format, to allow
// easy conversion later.
return kN32_SkColorTypeIsBGRA ? ScanlineFormat::N24BitTcBgr
: ScanlineFormat::N24BitTcRgb;
case 32:
if (m_bWithoutAlpha)
{
return kN32_SkColorTypeIsBGRA ? ScanlineFormat::N32BitTcBgrx
: ScanlineFormat::N32BitTcRgbx;
}
else
{
return kN32_SkColorTypeIsBGRA ? ScanlineFormat::N32BitTcBgra
: ScanlineFormat::N32BitTcRgba;
}
default:
abort();
}
}
BitmapBuffer* SkiaSalBitmap::AcquireBuffer(BitmapAccessMode nMode)
{
@@ -282,35 +309,7 @@ BitmapBuffer* SkiaSalBitmap::AcquireBuffer(BitmapAccessMode nMode)
mPixelsSize = savedPixelsSize;
ComputeScanlineSize();
}
switch (mBitCount)
{
case 1:
buffer->meFormat = ScanlineFormat::N1BitMsbPal;
break;
case 8:
buffer->meFormat = ScanlineFormat::N8BitPal;
break;
case 24:
// Make the RGB/BGR format match the default Skia 32bpp format, to allow
// easy conversion later.
buffer->meFormat = kN32_SkColorTypeIsBGRA ? ScanlineFormat::N24BitTcBgr
: ScanlineFormat::N24BitTcRgb;
break;
case 32:
if (m_bWithoutAlpha)
{
buffer->meFormat = kN32_SkColorTypeIsBGRA ? ScanlineFormat::N32BitTcBgrx
: ScanlineFormat::N32BitTcRgbx;
}
else
{
buffer->meFormat = kN32_SkColorTypeIsBGRA ? ScanlineFormat::N32BitTcBgra
: ScanlineFormat::N32BitTcRgba;
}
break;
default:
abort();
}
buffer->meFormat = GetScanlineFormat();
buffer->meDirection = ScanlineDirection::TopDown;
// Refcount all read/write accesses, to catch problems with existing accesses while
// a bitmap changes, and also to detect when we can free mBuffer if wanted.
+16
View File
@@ -353,6 +353,22 @@ vcl::PixelFormat Bitmap::getPixelFormat() const
return vcl::PixelFormat::INVALID;
}
bool Bitmap::HasAlpha() const
{
if (!mxSalBmp)
return false;
switch(mxSalBmp->GetScanlineFormat())
{
case ScanlineFormat::N32BitTcAbgr:
case ScanlineFormat::N32BitTcArgb:
case ScanlineFormat::N32BitTcBgra:
case ScanlineFormat::N32BitTcRgba:
return true;
default:
return false;
}
}
bool Bitmap::HasGreyPaletteAny() const
{
bool bRet = false;
+22
View File
@@ -85,6 +85,28 @@ void SalBitmap::updateChecksum() const
}
}
sal_uInt16 SalBitmap::GetBitCount() const
{
switch (GetScanlineFormat())
{
case ScanlineFormat::NONE: return 0;
case ScanlineFormat::N1BitMsbPal: return 1;
case ScanlineFormat::N8BitPal: return 8;
case ScanlineFormat::N24BitTcBgr: return 24;
case ScanlineFormat::N24BitTcRgb: return 24;
case ScanlineFormat::N32BitTcAbgr:
case ScanlineFormat::N32BitTcXbgr:
case ScanlineFormat::N32BitTcArgb:
case ScanlineFormat::N32BitTcXrgb:
case ScanlineFormat::N32BitTcBgra:
case ScanlineFormat::N32BitTcBgrx:
case ScanlineFormat::N32BitTcRgba:
case ScanlineFormat::N32BitTcRgbx:
return 32;
default: abort();
}
}
namespace
{
+20 -4
View File
@@ -730,6 +730,25 @@ void* WinSalBitmap::ImplCopyDIB( void* pDIB, sal_Int32 nSize )
return pCopy;
}
ScanlineFormat WinSalBitmap::GetScanlineFormat() const
{
if (!mpDIB)
return ScanlineFormat::NONE;
PBITMAPINFO pBI = static_cast<PBITMAPINFO>(mpDIB);
if (!pBI)
return ScanlineFormat::NONE;
PBITMAPINFOHEADER pBIH = &pBI->bmiHeader;
if( pBIH->biPlanes != 1 )
return ScanlineFormat::NONE;
return pBIH->biBitCount == 8 ? ScanlineFormat::N8BitPal :
pBIH->biBitCount == 24 ? ScanlineFormat::N24BitTcBgr :
pBIH->biBitCount == 32 ? ScanlineFormat::N32BitTcBgra :
ScanlineFormat::NONE;
}
BitmapBuffer* WinSalBitmap::AcquireBuffer( BitmapAccessMode /*nMode*/ )
{
if (!mpDIB)
@@ -746,10 +765,7 @@ BitmapBuffer* WinSalBitmap::AcquireBuffer( BitmapAccessMode /*nMode*/ )
{
pBuffer.reset(new BitmapBuffer);
pBuffer->meFormat = pBIH->biBitCount == 8 ? ScanlineFormat::N8BitPal :
pBIH->biBitCount == 24 ? ScanlineFormat::N24BitTcBgr :
pBIH->biBitCount == 32 ? ScanlineFormat::N32BitTcBgra :
ScanlineFormat::NONE;
pBuffer->meFormat = GetScanlineFormat();
assert (pBuffer->meFormat != ScanlineFormat::NONE);
if (pBuffer->meFormat != ScanlineFormat::NONE)