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);