Support for native 32bit Bitmap in VCL and SVP (cairo) backend
This adds basic support for 32bit bitmaps for the SVP backend. For
other backends the support is disabled for now as we need to add it for
each backend separately and enable support.
When this patch is applied it is possible to a Bitmap with bit count
32, but currently no input filter uses this with the exception of the
new PngImageReader(libpng based), which is used only for the icons.
For a general support more things need to be implemented and tested:
- conversion back and fourth between 32-bit and 24-bit + 8bit alpha (or
other supported pairs)
- 'raw' export of the bitmap needs to be handeled properly (like in
SVM import/export) so it creates the correct image.
- input filters need to be checked and converted if this is necessary
- look for possible bugs when drawing transparent bitmaps
- check of UNO API
Change-Id: I7a7be0e6134dfdd9a7aeaef897131bb6e710ae7e
Reviewed-on: https://gerrit.libreoffice.org/69289
Reviewed-by: Tomaž Vajngerl <quikee@gmail.com>
Tested-by: Tomaž Vajngerl <quikee@gmail.com>
diff --git a/include/vcl/BitmapTools.hxx b/include/vcl/BitmapTools.hxx
index ff43178..0099358 100644
--- a/include/vcl/BitmapTools.hxx
+++ b/include/vcl/BitmapTools.hxx
@@ -33,6 +33,9 @@ typedef sal_uInt8 (*lookup_table)[256];
lookup_table VCL_DLLPUBLIC get_premultiply_table();
lookup_table VCL_DLLPUBLIC get_unpremultiply_table();
VCL_DLLPUBLIC sal_uInt8 unpremultiply(sal_uInt8 c, sal_uInt8 a);
VCL_DLLPUBLIC sal_uInt8 premultiply(sal_uInt8 c, sal_uInt8 a);
/**
* Intended to be used to feed into CreateFromData to create a BitmapEx. RGB data format.
*/
@@ -124,6 +127,8 @@ VCL_DLLPUBLIC css::uno::Sequence< sal_Int8 > CanvasExtractBitmapData(BitmapEx co
BitmapEx VCL_DLLPUBLIC createHistorical8x8FromArray(std::array<sal_uInt8,64> const & pArray, Color aColorPix, Color aColorBack);
bool VCL_DLLPUBLIC isHistorical8x8(const BitmapEx& rBitmapEx, BitmapColor& o_rBack, BitmapColor& o_rFront);
VCL_DLLPUBLIC bool convertBitmap32To24Plus8(BitmapEx const & rInput, BitmapEx & rResult);
}} // end vcl::bitmap
#endif // INCLUDED_VCL_BITMAP_TOOLS_HXX
diff --git a/vcl/headless/svpgdi.cxx b/vcl/headless/svpgdi.cxx
index 08cb2bf..3ec663c 100644
--- a/vcl/headless/svpgdi.cxx
+++ b/vcl/headless/svpgdi.cxx
@@ -1624,7 +1624,7 @@ void SvpSalGraphics::drawBitmap(const SalTwoRect& rTR, const SalBitmap& rSourceB
{
SourceHelper aSurface(rSourceBitmap);
cairo_surface_t* source = aSurface.getSurface();
copySource(rTR, source);
copyWithOperator(rTR, source, CAIRO_OPERATOR_OVER);
}
void SvpSalGraphics::drawBitmap(const SalTwoRect& rTR, const BitmapBuffer* pBuffer, cairo_operator_t eOp)
@@ -1749,11 +1749,10 @@ std::shared_ptr<SalBitmap> SvpSalGraphics::getBitmap( long nX, long nY, long nWi
Color SvpSalGraphics::getPixel( long nX, long nY )
{
#if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1, 12, 0)
cairo_surface_t *target = cairo_surface_create_similar_image(m_pSurface,
cairo_surface_t *target = cairo_surface_create_similar_image(m_pSurface, CAIRO_FORMAT_ARGB32, 1, 1);
#else
cairo_surface_t *target = cairo_image_surface_create(
cairo_surface_t *target = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 1, 1);
#endif
CAIRO_FORMAT_ARGB32, 1, 1);
cairo_t* cr = cairo_create(target);
@@ -1769,11 +1768,10 @@ Color SvpSalGraphics::getPixel( long nX, long nY )
sal_uInt8 b = unpremultiply_table[a][data[SVP_CAIRO_BLUE]];
sal_uInt8 g = unpremultiply_table[a][data[SVP_CAIRO_GREEN]];
sal_uInt8 r = unpremultiply_table[a][data[SVP_CAIRO_RED]];
Color nRet = Color(r, g, b);
Color aColor(0xFF - a, r, g, b);
cairo_surface_destroy(target);
return nRet;
return aColor;
}
namespace
diff --git a/vcl/headless/svpinst.cxx b/vcl/headless/svpinst.cxx
index 49a64c7..324d976 100644
--- a/vcl/headless/svpinst.cxx
+++ b/vcl/headless/svpinst.cxx
@@ -537,6 +537,13 @@ void SvpSalInstance::AddToRecentDocumentList(const OUString&, const OUString&, c
{
}
std::shared_ptr<vcl::BackendCapabilities> SvpSalInstance::GetBackendCapabilities()
{
auto pBackendCapabilities = SalInstance::GetBackendCapabilities();
pBackendCapabilities->mbSupportsBitmap32 = true;
return pBackendCapabilities;
}
//obviously doesn't actually do anything, it's just a nonfunctional stub
#ifdef LIBO_HEADLESS
diff --git a/vcl/inc/backend/BackendCapabilities.hxx b/vcl/inc/backend/BackendCapabilities.hxx
new file mode 100644
index 0000000..89879ee
--- /dev/null
+++ b/vcl/inc/backend/BackendCapabilities.hxx
@@ -0,0 +1,28 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* This file is part of the LibreOffice project.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
*/
#ifndef INCLUDED_VCL_INC_BACKENDCAPABILITIES_HXX
#define INCLUDED_VCL_INC_BACKENDCAPABILITIES_HXX
namespace vcl
{
struct BackendCapabilities
{
bool mbSupportsBitmap32;
BackendCapabilities()
: mbSupportsBitmap32(false)
{
}
};
}
#endif // INCLUDED_VCL_INC_BACKENDCAPABILITIES_HXX
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/inc/headless/svpinst.hxx b/vcl/inc/headless/svpinst.hxx
index 684abde..dcdd29f 100644
--- a/vcl/inc/headless/svpinst.hxx
+++ b/vcl/inc/headless/svpinst.hxx
@@ -167,6 +167,8 @@ public:
// SalBitmap
virtual std::shared_ptr<SalBitmap> CreateSalBitmap() override;
std::shared_ptr<vcl::BackendCapabilities> GetBackendCapabilities() override;
// wait next event and dispatch
// must returned by UserEvent (SalFrame::PostEvent)
// and timer
diff --git a/vcl/inc/salinst.hxx b/vcl/inc/salinst.hxx
index e35cd78..4acb031 100644
--- a/vcl/inc/salinst.hxx
+++ b/vcl/inc/salinst.hxx
@@ -28,6 +28,8 @@
#include <osl/thread.hxx>
#include <vcl/vclenum.hxx>
#include "backend/BackendCapabilities.hxx"
#include "displayconnectiondispatch.hxx"
#include <com/sun/star/uno/XComponentContext.hpp>
@@ -134,6 +136,11 @@ public:
virtual SalSystem* CreateSalSystem() = 0;
// SalBitmap
virtual std::shared_ptr<SalBitmap> CreateSalBitmap() = 0;
// BackendCapabilities
virtual std::shared_ptr<vcl::BackendCapabilities> GetBackendCapabilities()
{
return std::make_shared<vcl::BackendCapabilities>();
}
// YieldMutex
comphelper::SolarMutex* GetYieldMutex();
diff --git a/vcl/qa/cppunit/BitmapTest.cxx b/vcl/qa/cppunit/BitmapTest.cxx
index 986ce35..11cfea3 100644
--- a/vcl/qa/cppunit/BitmapTest.cxx
+++ b/vcl/qa/cppunit/BitmapTest.cxx
@@ -30,6 +30,9 @@
#include <BitmapSymmetryCheck.hxx>
#include <bitmapwriteaccess.hxx>
#include <svdata.hxx>
#include <salinst.hxx>
namespace
{
class BitmapTest : public CppUnit::TestFixture
@@ -44,6 +47,8 @@ class BitmapTest : public CppUnit::TestFixture
void testCRC();
void testGreyPalette();
void testCustom8BitPalette();
void testErase();
void testBitmap32();
CPPUNIT_TEST_SUITE(BitmapTest);
CPPUNIT_TEST(testCreation);
@@ -56,6 +61,8 @@ class BitmapTest : public CppUnit::TestFixture
CPPUNIT_TEST(testCRC);
CPPUNIT_TEST(testGreyPalette);
CPPUNIT_TEST(testCustom8BitPalette);
CPPUNIT_TEST(testErase);
CPPUNIT_TEST(testBitmap32);
CPPUNIT_TEST_SUITE_END();
};
@@ -151,6 +158,10 @@ void BitmapTest::testCreation()
aBmp.GetSizeBytes());
}
// Check backend capabilities and return from the test successfully
// if the backend doesn't support 32-bit bitmap
auto pBackendCapabilities = ImplGetSVData()->mpDefInst->GetBackendCapabilities();
if (pBackendCapabilities->mbSupportsBitmap32)
{
Bitmap aBmp(Size(10, 10), 32);
Size aSize = aBmp.GetSizePixel();
@@ -158,12 +169,11 @@ void BitmapTest::testCreation()
CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong height", static_cast<long>(10), aSize.Height());
CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong pref size", Size(), aBmp.GetPrefSize());
CPPUNIT_ASSERT_MESSAGE("Empty bitmap", !aBmp.IsEmpty());
CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong bit count", static_cast<sal_uInt16>(24),
aBmp.GetBitCount());
CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong color count", static_cast<sal_uLong>(16777216),
aBmp.GetColorCount());
CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong byte size", static_cast<sal_uLong>(300),
aBmp.GetSizeBytes());
CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong bit count", sal_uInt16(32), aBmp.GetBitCount());
CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong color count", sal_Int64(4294967296U),
sal_Int64(aBmp.GetColorCount()));
CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong byte size", sal_uLong(400), aBmp.GetSizeBytes());
}
}
@@ -599,6 +609,48 @@ void BitmapTest::testCustom8BitPalette()
}
}
void BitmapTest::testErase()
{
Bitmap aBitmap(Size(3, 3), 24);
{
BitmapScopedWriteAccess pWriteAccess(aBitmap);
pWriteAccess->Erase(Color(0x11, 0x22, 0x33));
}
{
Bitmap::ScopedReadAccess pReadAccess(aBitmap);
BitmapColor aColor(pReadAccess->GetPixel(0, 0));
CPPUNIT_ASSERT_EQUAL(BitmapColor(0x11, 0x22, 0x33, 0x00), aColor);
}
}
void BitmapTest::testBitmap32()
{
// Check backend capabilities and return from the test successfully
// if the backend doesn't support 32-bit bitmap
auto pBackendCapabilities = ImplGetSVData()->mpDefInst->GetBackendCapabilities();
if (!pBackendCapabilities->mbSupportsBitmap32)
return;
Bitmap aBitmap(Size(3, 3), 32);
{
BitmapScopedWriteAccess pWriteAccess(aBitmap);
pWriteAccess->Erase(Color(0xFF, 0x11, 0x22, 0x33));
pWriteAccess->SetPixel(1, 1, BitmapColor(0x44, 0xFF, 0xBB, 0x00));
pWriteAccess->SetPixel(2, 2, BitmapColor(0x99, 0x77, 0x66, 0x55));
}
{
Bitmap::ScopedReadAccess pReadAccess(aBitmap);
BitmapColor aColor = pReadAccess->GetPixel(0, 0);
CPPUNIT_ASSERT_EQUAL(BitmapColor(0x00, 0x00, 0x00, 0xFF), aColor);
aColor = pReadAccess->GetPixel(1, 1);
CPPUNIT_ASSERT_EQUAL(BitmapColor(0x44, 0xFF, 0xBB, 0x00), aColor);
aColor = pReadAccess->GetPixel(2, 2);
CPPUNIT_ASSERT_EQUAL(BitmapColor(0x99, 0x77, 0x66, 0x55), aColor);
}
}
} // namespace
CPPUNIT_TEST_SUITE_REGISTRATION(BitmapTest);
diff --git a/vcl/qa/cppunit/png/PngFilterTest.cxx b/vcl/qa/cppunit/png/PngFilterTest.cxx
index 1a9dd0a..fdb61f97 100644
--- a/vcl/qa/cppunit/png/PngFilterTest.cxx
+++ b/vcl/qa/cppunit/png/PngFilterTest.cxx
@@ -60,19 +60,25 @@ void PngFilterTest::testPng()
Bitmap aBitmap = aBitmapEx.GetBitmap();
{
Bitmap::ScopedReadAccess pAccess(aBitmap);
CPPUNIT_ASSERT_EQUAL(sal_uInt16(24), pAccess->GetBitCount());
CPPUNIT_ASSERT_EQUAL(4L, pAccess->Width());
CPPUNIT_ASSERT_EQUAL(4L, pAccess->Height());
CPPUNIT_ASSERT_EQUAL(BitmapColor(0xFF, 0xFF, 0xFF, 0x00), pAccess->GetPixel(0, 0));
CPPUNIT_ASSERT_EQUAL(BitmapColor(0xFF, 0xFF, 0xFF, 0x00), pAccess->GetPixel(3, 3));
CPPUNIT_ASSERT_EQUAL(BitmapColor(0xFF, 0xFF, 0xFF, 0x00), pAccess->GetPixel(3, 0));
CPPUNIT_ASSERT_EQUAL(BitmapColor(0xFF, 0xFF, 0xFF, 0x00), pAccess->GetPixel(0, 3));
if (pAccess->GetBitCount() == 24 || pAccess->GetBitCount() == 32)
{
CPPUNIT_ASSERT_EQUAL(BitmapColor(0xFF, 0xFF, 0xFF, 0x00), pAccess->GetPixel(0, 0));
CPPUNIT_ASSERT_EQUAL(BitmapColor(0xFF, 0xFF, 0xFF, 0x00), pAccess->GetPixel(3, 3));
CPPUNIT_ASSERT_EQUAL(BitmapColor(0xFF, 0xFF, 0xFF, 0x00), pAccess->GetPixel(3, 0));
CPPUNIT_ASSERT_EQUAL(BitmapColor(0xFF, 0xFF, 0xFF, 0x00), pAccess->GetPixel(0, 3));
CPPUNIT_ASSERT_EQUAL(BitmapColor(0x00, 0x00, 0x00, 0x00), pAccess->GetPixel(1, 1));
CPPUNIT_ASSERT_EQUAL(BitmapColor(0x00, 0x00, 0x00, 0x00), pAccess->GetPixel(1, 2));
CPPUNIT_ASSERT_EQUAL(BitmapColor(0x00, 0x00, 0x00, 0x00), pAccess->GetPixel(2, 1));
CPPUNIT_ASSERT_EQUAL(BitmapColor(0x00, 0x00, 0x00, 0x00), pAccess->GetPixel(2, 2));
CPPUNIT_ASSERT_EQUAL(BitmapColor(0x00, 0x00, 0x00, 0x00), pAccess->GetPixel(1, 1));
CPPUNIT_ASSERT_EQUAL(BitmapColor(0x00, 0x00, 0x00, 0x00), pAccess->GetPixel(1, 2));
CPPUNIT_ASSERT_EQUAL(BitmapColor(0x00, 0x00, 0x00, 0x00), pAccess->GetPixel(2, 1));
CPPUNIT_ASSERT_EQUAL(BitmapColor(0x00, 0x00, 0x00, 0x00), pAccess->GetPixel(2, 2));
}
else
{
CPPUNIT_ASSERT_MESSAGE("Bitmap is not 24 or 32 bit.", false);
}
}
}
for (const OUString& aFileName :
@@ -87,19 +93,24 @@ void PngFilterTest::testPng()
Bitmap aBitmap = aBitmapEx.GetBitmap();
{
Bitmap::ScopedReadAccess pAccess(aBitmap);
CPPUNIT_ASSERT_EQUAL(sal_uInt16(24), pAccess->GetBitCount());
CPPUNIT_ASSERT_EQUAL(4L, pAccess->Width());
CPPUNIT_ASSERT_EQUAL(4L, pAccess->Height());
if (pAccess->GetBitCount() == 24 || pAccess->GetBitCount() == 32)
{
CPPUNIT_ASSERT_EQUAL(BitmapColor(0xFF, 0xFF, 0xFF, 0x00), pAccess->GetPixel(0, 0));
CPPUNIT_ASSERT_EQUAL(BitmapColor(0xFF, 0xFF, 0xFF, 0x00), pAccess->GetPixel(3, 3));
CPPUNIT_ASSERT_EQUAL(BitmapColor(0xFF, 0xFF, 0xFF, 0x00), pAccess->GetPixel(3, 0));
CPPUNIT_ASSERT_EQUAL(BitmapColor(0xFF, 0xFF, 0xFF, 0x00), pAccess->GetPixel(0, 3));
CPPUNIT_ASSERT_EQUAL(BitmapColor(0xFF, 0xFF, 0xFF, 0x00), pAccess->GetPixel(0, 0));
CPPUNIT_ASSERT_EQUAL(BitmapColor(0xFF, 0xFF, 0xFF, 0x00), pAccess->GetPixel(3, 3));
CPPUNIT_ASSERT_EQUAL(BitmapColor(0xFF, 0xFF, 0xFF, 0x00), pAccess->GetPixel(3, 0));
CPPUNIT_ASSERT_EQUAL(BitmapColor(0xFF, 0xFF, 0xFF, 0x00), pAccess->GetPixel(0, 3));
CPPUNIT_ASSERT_EQUAL(BitmapColor(0xFF, 0x00, 0x00, 0x00), pAccess->GetPixel(1, 1));
CPPUNIT_ASSERT_EQUAL(BitmapColor(0x00, 0xFF, 0x00, 0x00), pAccess->GetPixel(1, 2));
CPPUNIT_ASSERT_EQUAL(BitmapColor(0x00, 0x00, 0xFF, 0x00), pAccess->GetPixel(2, 1));
CPPUNIT_ASSERT_EQUAL(BitmapColor(0xFF, 0xFF, 0x00, 0x00), pAccess->GetPixel(2, 2));
CPPUNIT_ASSERT_EQUAL(BitmapColor(0xFF, 0x00, 0x00, 0x00), pAccess->GetPixel(1, 1));
CPPUNIT_ASSERT_EQUAL(BitmapColor(0x00, 0xFF, 0x00, 0x00), pAccess->GetPixel(1, 2));
CPPUNIT_ASSERT_EQUAL(BitmapColor(0x00, 0x00, 0xFF, 0x00), pAccess->GetPixel(2, 1));
CPPUNIT_ASSERT_EQUAL(BitmapColor(0xFF, 0xFF, 0x00, 0x00), pAccess->GetPixel(2, 2));
}
else
{
CPPUNIT_ASSERT_MESSAGE("Bitmap is not 24 or 32 bit.", false);
}
}
}
for (const OUString& aFileName : { OUString("alpha-rect-8bit-RGBA.png") })
@@ -113,39 +124,65 @@ void PngFilterTest::testPng()
Bitmap aBitmap = aBitmapEx.GetBitmap();
{
Bitmap::ScopedReadAccess pAccess(aBitmap);
CPPUNIT_ASSERT_EQUAL(sal_uInt16(24), pAccess->GetBitCount());
CPPUNIT_ASSERT_EQUAL(4L, pAccess->Width());
CPPUNIT_ASSERT_EQUAL(4L, pAccess->Height());
CPPUNIT_ASSERT_EQUAL(BitmapColor(0xFF, 0xFF, 0xFF, 0x00), pAccess->GetPixel(0, 0));
CPPUNIT_ASSERT_EQUAL(BitmapColor(0xFF, 0xFF, 0xFF, 0x00), pAccess->GetPixel(3, 3));
CPPUNIT_ASSERT_EQUAL(BitmapColor(0xFF, 0xFF, 0xFF, 0x00), pAccess->GetPixel(3, 0));
CPPUNIT_ASSERT_EQUAL(BitmapColor(0xFF, 0xFF, 0xFF, 0x00), pAccess->GetPixel(0, 3));
if (pAccess->GetBitCount() == 24)
{
CPPUNIT_ASSERT_EQUAL(BitmapColor(0xFF, 0xFF, 0xFF, 0x00), pAccess->GetPixel(0, 0));
CPPUNIT_ASSERT_EQUAL(BitmapColor(0xFF, 0xFF, 0xFF, 0x00), pAccess->GetPixel(3, 3));
CPPUNIT_ASSERT_EQUAL(BitmapColor(0xFF, 0xFF, 0xFF, 0x00), pAccess->GetPixel(3, 0));
CPPUNIT_ASSERT_EQUAL(BitmapColor(0xFF, 0xFF, 0xFF, 0x00), pAccess->GetPixel(0, 3));
CPPUNIT_ASSERT_EQUAL(BitmapColor(0xFF, 0x00, 0x00, 0x00), pAccess->GetPixel(1, 1));
CPPUNIT_ASSERT_EQUAL(BitmapColor(0x00, 0xFF, 0x00, 0x00), pAccess->GetPixel(1, 2));
CPPUNIT_ASSERT_EQUAL(BitmapColor(0x00, 0x00, 0xFF, 0x00), pAccess->GetPixel(2, 1));
CPPUNIT_ASSERT_EQUAL(BitmapColor(0xFF, 0xFF, 0x00, 0x00), pAccess->GetPixel(2, 2));
}
AlphaMask aAlpha = aBitmapEx.GetAlpha();
{
AlphaMask::ScopedReadAccess pAccess(aAlpha);
CPPUNIT_ASSERT_EQUAL(sal_uInt16(8), pAccess->GetBitCount());
CPPUNIT_ASSERT_EQUAL(4L, pAccess->Width());
CPPUNIT_ASSERT_EQUAL(4L, pAccess->Height());
CPPUNIT_ASSERT_EQUAL(BitmapColor(0xFF, 0x00, 0x00, 0x00), pAccess->GetPixel(1, 1));
CPPUNIT_ASSERT_EQUAL(BitmapColor(0x00, 0xFF, 0x00, 0x00), pAccess->GetPixel(1, 2));
CPPUNIT_ASSERT_EQUAL(BitmapColor(0x00, 0x00, 0xFF, 0x00), pAccess->GetPixel(2, 1));
CPPUNIT_ASSERT_EQUAL(BitmapColor(0xFF, 0xFF, 0x00, 0x00), pAccess->GetPixel(2, 2));
CPPUNIT_ASSERT_EQUAL(BitmapColor(0x00, 0x00, 0x80, 0x00), pAccess->GetPixel(0, 0));
CPPUNIT_ASSERT_EQUAL(BitmapColor(0x00, 0x00, 0x80, 0x00), pAccess->GetPixel(3, 3));
CPPUNIT_ASSERT_EQUAL(BitmapColor(0x00, 0x00, 0x80, 0x00), pAccess->GetPixel(3, 0));
CPPUNIT_ASSERT_EQUAL(BitmapColor(0x00, 0x00, 0x80, 0x00), pAccess->GetPixel(0, 3));
AlphaMask aAlpha = aBitmapEx.GetAlpha();
{
AlphaMask::ScopedReadAccess pAlphaAccess(aAlpha);
CPPUNIT_ASSERT_EQUAL(sal_uInt16(8), pAlphaAccess->GetBitCount());
CPPUNIT_ASSERT_EQUAL(4L, pAlphaAccess->Width());
CPPUNIT_ASSERT_EQUAL(4L, pAlphaAccess->Height());
CPPUNIT_ASSERT_EQUAL(BitmapColor(0x00, 0x00, 0x40, 0x00), pAccess->GetPixel(1, 1));
CPPUNIT_ASSERT_EQUAL(BitmapColor(0x00, 0x00, 0xC0, 0x00), pAccess->GetPixel(1, 2));
CPPUNIT_ASSERT_EQUAL(BitmapColor(0x00, 0x00, 0xC0, 0x00), pAccess->GetPixel(2, 1));
CPPUNIT_ASSERT_EQUAL(BitmapColor(0x00, 0x00, 0x40, 0x00), pAccess->GetPixel(2, 2));
CPPUNIT_ASSERT_EQUAL(BitmapColor(0x00, 0x00, 0x80, 0x00),
pAlphaAccess->GetPixel(0, 0));
CPPUNIT_ASSERT_EQUAL(BitmapColor(0x00, 0x00, 0x80, 0x00),
pAlphaAccess->GetPixel(3, 3));
CPPUNIT_ASSERT_EQUAL(BitmapColor(0x00, 0x00, 0x80, 0x00),
pAlphaAccess->GetPixel(3, 0));
CPPUNIT_ASSERT_EQUAL(BitmapColor(0x00, 0x00, 0x80, 0x00),
pAlphaAccess->GetPixel(0, 3));
CPPUNIT_ASSERT_EQUAL(BitmapColor(0x00, 0x00, 0x40, 0x00),
pAlphaAccess->GetPixel(1, 1));
CPPUNIT_ASSERT_EQUAL(BitmapColor(0x00, 0x00, 0xC0, 0x00),
pAlphaAccess->GetPixel(1, 2));
CPPUNIT_ASSERT_EQUAL(BitmapColor(0x00, 0x00, 0xC0, 0x00),
pAlphaAccess->GetPixel(2, 1));
CPPUNIT_ASSERT_EQUAL(BitmapColor(0x00, 0x00, 0x40, 0x00),
pAlphaAccess->GetPixel(2, 2));
}
}
else if (pAccess->GetBitCount() == 32)
{
CPPUNIT_ASSERT_EQUAL(BitmapColor(0xFF, 0xFF, 0xFF, 0x80), pAccess->GetPixel(0, 0));
CPPUNIT_ASSERT_EQUAL(BitmapColor(0xFF, 0xFF, 0xFF, 0x80), pAccess->GetPixel(3, 3));
CPPUNIT_ASSERT_EQUAL(BitmapColor(0xFF, 0xFF, 0xFF, 0x80), pAccess->GetPixel(3, 0));
CPPUNIT_ASSERT_EQUAL(BitmapColor(0xFF, 0xFF, 0xFF, 0x80), pAccess->GetPixel(0, 3));
CPPUNIT_ASSERT_EQUAL(BitmapColor(0xFF, 0x00, 0x00, 0x40), pAccess->GetPixel(1, 1));
CPPUNIT_ASSERT_EQUAL(BitmapColor(0x00, 0xFF, 0x00, 0xC0), pAccess->GetPixel(1, 2));
CPPUNIT_ASSERT_EQUAL(BitmapColor(0x00, 0x00, 0xFF, 0xC0), pAccess->GetPixel(2, 1));
CPPUNIT_ASSERT_EQUAL(BitmapColor(0xFF, 0xFF, 0x00, 0x40), pAccess->GetPixel(2, 2));
}
else
{
CPPUNIT_ASSERT_MESSAGE("Bitmap is not 24 or 32 bit.", false);
}
}
}
// CPPUNIT_ASSERT(false);
}
CPPUNIT_TEST_SUITE_REGISTRATION(PngFilterTest);
diff --git a/vcl/source/bitmap/BitmapDisabledImageFilter.cxx b/vcl/source/bitmap/BitmapDisabledImageFilter.cxx
index 56f46b3..6c13e61 100644
--- a/vcl/source/bitmap/BitmapDisabledImageFilter.cxx
+++ b/vcl/source/bitmap/BitmapDisabledImageFilter.cxx
@@ -44,7 +44,7 @@ BitmapEx BitmapDisabledImageFilter::execute(BitmapEx const& rBitmapEx) const
// Get the luminance from RGB color and remap the value from 0-255 to 160-224
const BitmapColor aColor = pRead->GetPixelFromData(pReadScan, nX);
sal_uInt8 nLum(aColor.GetLuminance() / 4 + 160);
BitmapColor aGreyValue(nLum, nLum, nLum);
BitmapColor aGreyValue(nLum, nLum, nLum, aColor.GetAlpha());
pGrey->SetPixelOnData(pGreyScan, nX, aGreyValue);
}
}
diff --git a/vcl/source/bitmap/BitmapTools.cxx b/vcl/source/bitmap/BitmapTools.cxx
index 9762c27..6f14c35 100644
--- a/vcl/source/bitmap/BitmapTools.cxx
+++ b/vcl/source/bitmap/BitmapTools.cxx
@@ -1041,12 +1041,12 @@ void CanvasCairoExtractBitmapData( BitmapEx const & aBmpEx, Bitmap & aBitmap, un
return bRet;
}
static sal_uInt8 unpremultiply(sal_uInt8 c, sal_uInt8 a)
sal_uInt8 unpremultiply(sal_uInt8 c, sal_uInt8 a)
{
return (a == 0) ? 0 : (c * 255 + a / 2) / a;
}
static sal_uInt8 premultiply(sal_uInt8 c, sal_uInt8 a)
sal_uInt8 premultiply(sal_uInt8 c, sal_uInt8 a)
{
return (c * a + 127) / 255;
}
@@ -1083,6 +1083,45 @@ void CanvasCairoExtractBitmapData( BitmapEx const & aBmpEx, Bitmap & aBitmap, un
return premultiply_table;
}
bool convertBitmap32To24Plus8(BitmapEx const & rInput, BitmapEx & rResult)
{
Bitmap aBitmap(rInput.GetBitmap());
if (aBitmap.GetBitCount() != 32)
return false;
Size aSize = aBitmap.GetSizePixel();
Bitmap aResultBitmap(aSize, 24);
AlphaMask aResultAlpha(aSize);
{
BitmapScopedWriteAccess pResultBitmapAccess(aResultBitmap);
AlphaScopedWriteAccess pResultAlphaAccess(aResultAlpha);
Bitmap::ScopedReadAccess pReadAccess(aBitmap);
for (long nY = 0; nY < aSize.Height(); ++nY)
{
Scanline aResultScan = pResultBitmapAccess->GetScanline(nY);
Scanline aResultScanAlpha = pResultAlphaAccess->GetScanline(nY);
Scanline aReadScan = pReadAccess->GetScanline(nY);
for (long nX = 0; nX < aSize.Width(); ++nX)
{
const BitmapColor aColor = pReadAccess->GetPixelFromData(aReadScan, nX);
BitmapColor aResultColor(aColor.GetRed(), aColor.GetGreen(), aColor.GetBlue());
BitmapColor aResultColorAlpha(aColor.GetAlpha(), aColor.GetAlpha(), aColor.GetAlpha());
pResultBitmapAccess->SetPixelOnData(aResultScan, nX, aResultColor);
pResultAlphaAccess->SetPixelOnData(aResultScanAlpha, nX, aResultColorAlpha);
}
}
}
if (rInput.IsTransparent())
rResult = BitmapEx(aResultBitmap, rInput.GetAlpha());
else
rResult = BitmapEx(aResultBitmap, aResultAlpha);
return true;
}
}} // end vcl::bitmap
diff --git a/vcl/source/bitmap/bitmap.cxx b/vcl/source/bitmap/bitmap.cxx
index c26cf89..bf391f3 100644
--- a/vcl/source/bitmap/bitmap.cxx
+++ b/vcl/source/bitmap/bitmap.cxx
@@ -260,9 +260,19 @@ sal_uInt16 Bitmap::GetBitCount() const
{
if (!mxSalBmp)
return 0;
sal_uInt16 nBitCount = mxSalBmp->GetBitCount();
return ( nBitCount <= 4 ) ? ( ( nBitCount <= 1 ) ? 1 : 4 ):
( ( nBitCount <= 8 ) ? 8 : 24);
if (nBitCount <= 1)
return 1;
if (nBitCount <= 4)
return 4;
if (nBitCount <= 8)
return 8;
if (nBitCount <= 24)
return 24;
if (nBitCount <= 32)
return 32;
return 0;
}
bool Bitmap::HasGreyPalette() const
diff --git a/vcl/source/filter/png/PngImageReader.cxx b/vcl/source/filter/png/PngImageReader.cxx
index 2c83f89..be50687 100644
--- a/vcl/source/filter/png/PngImageReader.cxx
+++ b/vcl/source/filter/png/PngImageReader.cxx
@@ -14,6 +14,9 @@
#include <bitmapwriteaccess.hxx>
#include <vcl/bitmap.hxx>
#include <vcl/alpha.hxx>
#include <vcl/BitmapTools.hxx>
#include <svdata.hxx>
#include <salinst.hxx>
namespace
{
@@ -32,13 +35,14 @@ void lclReadStream(png_structp pPng, png_bytep pOutBytes, png_size_t nBytesToRea
png_error(pPng, "Error reading");
}
bool reader(SvStream& rStream, BitmapEx& rBitmapEx)
bool reader(SvStream& rStream, BitmapEx& rBitmapEx, bool bUseBitmap32)
{
enum
{
PNG_SIGNATURE_SIZE = 8
};
// Check signature bytes
sal_uInt8 aHeader[PNG_SIGNATURE_SIZE];
rStream.ReadBytes(aHeader, PNG_SIGNATURE_SIZE);
@@ -62,9 +66,11 @@ bool reader(SvStream& rStream, BitmapEx& rBitmapEx)
return false;
}
png_set_option(pPng, PNG_MAXIMUM_INFLATE_WINDOW, PNG_OPTION_ON);
png_set_read_fn(pPng, &rStream, lclReadStream);
png_set_crc_action(pPng, PNG_CRC_WARN_USE, PNG_CRC_WARN_DISCARD);
png_set_crc_action(pPng, PNG_CRC_ERROR_QUIT, PNG_CRC_WARN_DISCARD);
png_set_sig_bytes(pPng, PNG_SIGNATURE_SIZE);
@@ -85,9 +91,6 @@ bool reader(SvStream& rStream, BitmapEx& rBitmapEx)
return false;
}
Bitmap aBitmap(Size(width, height), 24);
AlphaMask aBitmapAlpha(Size(width, height), nullptr);
if (colorType == PNG_COLOR_TYPE_PALETTE)
png_set_palette_to_rgb(pPng);
@@ -135,61 +138,114 @@ bool reader(SvStream& rStream, BitmapEx& rBitmapEx)
{
size_t aRowSizeBytes = png_get_rowbytes(pPng, pInfo);
BitmapScopedWriteAccess pWriteAccess(aBitmap);
ScanlineFormat eFormat = pWriteAccess->GetScanlineFormat();
if (eFormat == ScanlineFormat::N24BitTcBgr)
png_set_bgr(pPng);
std::vector<png_byte> aRow(aRowSizeBytes, 0);
for (int pass = 0; pass < nNumberOfPasses; pass++)
Bitmap aBitmap(Size(width, height), 24);
{
for (png_uint_32 y = 0; y < height; y++)
BitmapScopedWriteAccess pWriteAccess(aBitmap);
ScanlineFormat eFormat = pWriteAccess->GetScanlineFormat();
if (eFormat == ScanlineFormat::N24BitTcBgr)
png_set_bgr(pPng);
std::vector<std::vector<png_byte>> aRows(height);
for (auto& rRow : aRows)
rRow.resize(aRowSizeBytes, 0);
for (int pass = 0; pass < nNumberOfPasses; pass++)
{
Scanline pScanline = pWriteAccess->GetScanline(y);
png_bytep pRow = aRow.data();
png_read_rows(pPng, &pRow, nullptr, 1);
size_t iColor = 0;
for (size_t i = 0; i < aRowSizeBytes; i += 3)
for (png_uint_32 y = 0; y < height; y++)
{
pScanline[iColor++] = pRow[i + 0];
pScanline[iColor++] = pRow[i + 1];
pScanline[iColor++] = pRow[i + 2];
Scanline pScanline = pWriteAccess->GetScanline(y);
png_bytep pRow = aRows[y].data();
png_read_row(pPng, pRow, nullptr);
size_t iColor = 0;
for (size_t i = 0; i < aRowSizeBytes; i += 3)
{
pScanline[iColor++] = pRow[i + 0];
pScanline[iColor++] = pRow[i + 1];
pScanline[iColor++] = pRow[i + 2];
}
}
}
}
rBitmapEx = BitmapEx(aBitmap);
}
else if (colorType == PNG_COLOR_TYPE_RGB_ALPHA)
{
size_t aRowSizeBytes = png_get_rowbytes(pPng, pInfo);
BitmapScopedWriteAccess pWriteAccess(aBitmap);
AlphaScopedWriteAccess pWriteAccessAlpha(aBitmapAlpha);
ScanlineFormat eFormat = pWriteAccess->GetScanlineFormat();
if (eFormat == ScanlineFormat::N24BitTcBgr)
png_set_bgr(pPng);
std::vector<png_byte> aRow(aRowSizeBytes, 0);
for (int pass = 0; pass < nNumberOfPasses; pass++)
if (bUseBitmap32)
{
for (png_uint_32 y = 0; y < height; y++)
Bitmap aBitmap(Size(width, height), 32);
{
Scanline pScanAlpha = pWriteAccessAlpha->GetScanline(y);
Scanline pScanline = pWriteAccess->GetScanline(y);
png_bytep pRow = aRow.data();
png_read_rows(pPng, &pRow, nullptr, 1);
size_t iAlpha = 0;
size_t iColor = 0;
for (size_t i = 0; i < aRowSizeBytes; i += 4)
BitmapScopedWriteAccess pWriteAccess(aBitmap);
ScanlineFormat eFormat = pWriteAccess->GetScanlineFormat();
if (eFormat == ScanlineFormat::N32BitTcAbgr
|| eFormat == ScanlineFormat::N32BitTcBgra)
{
pScanline[iColor++] = pRow[i + 0];
pScanline[iColor++] = pRow[i + 1];
pScanline[iColor++] = pRow[i + 2];
pScanAlpha[iAlpha++] = 0xFF - pRow[i + 3];
png_set_bgr(pPng);
}
std::vector<std::vector<png_byte>> aRows(height);
for (auto& rRow : aRows)
rRow.resize(aRowSizeBytes, 0);
for (int pass = 0; pass < nNumberOfPasses; pass++)
{
for (png_uint_32 y = 0; y < height; y++)
{
Scanline pScanline = pWriteAccess->GetScanline(y);
png_bytep pRow = aRows[y].data();
png_read_row(pPng, pRow, nullptr);
size_t iColor = 0;
for (size_t i = 0; i < aRowSizeBytes; i += 4)
{
sal_Int8 alpha = pRow[i + 3];
pScanline[iColor++] = vcl::bitmap::premultiply(pRow[i + 0], alpha);
pScanline[iColor++] = vcl::bitmap::premultiply(pRow[i + 1], alpha);
pScanline[iColor++] = vcl::bitmap::premultiply(pRow[i + 2], alpha);
pScanline[iColor++] = alpha;
}
}
}
}
rBitmapEx = BitmapEx(aBitmap);
}
else
{
Bitmap aBitmap(Size(width, height), 24);
AlphaMask aBitmapAlpha(Size(width, height), nullptr);
{
BitmapScopedWriteAccess pWriteAccess(aBitmap);
ScanlineFormat eFormat = pWriteAccess->GetScanlineFormat();
if (eFormat == ScanlineFormat::N24BitTcBgr)
png_set_bgr(pPng);
AlphaScopedWriteAccess pWriteAccessAlpha(aBitmapAlpha);
std::vector<std::vector<png_byte>> aRows(height);
for (auto& rRow : aRows)
rRow.resize(aRowSizeBytes, 0);
for (int pass = 0; pass < nNumberOfPasses; pass++)
{
for (png_uint_32 y = 0; y < height; y++)
{
Scanline pScanline = pWriteAccess->GetScanline(y);
Scanline pScanAlpha = pWriteAccessAlpha->GetScanline(y);
png_bytep pRow = aRows[y].data();
png_read_row(pPng, pRow, nullptr);
size_t iAlpha = 0;
size_t iColor = 0;
for (size_t i = 0; i < aRowSizeBytes; i += 4)
{
pScanline[iColor++] = pRow[i + 0];
pScanline[iColor++] = pRow[i + 1];
pScanline[iColor++] = pRow[i + 2];
pScanAlpha[iAlpha++] = 0xFF - pRow[i + 3];
}
}
}
}
rBitmapEx = BitmapEx(aBitmap, aBitmapAlpha);
}
}
}
@@ -198,8 +254,6 @@ bool reader(SvStream& rStream, BitmapEx& rBitmapEx)
png_destroy_read_struct(&pPng, &pInfo, nullptr);
rBitmapEx = BitmapEx(aBitmap, aBitmapAlpha);
return true;
}
@@ -212,7 +266,13 @@ PngImageReader::PngImageReader(SvStream& rStream)
{
}
bool PngImageReader::read(BitmapEx& rBitmapEx) { return reader(mrStream, rBitmapEx); }
bool PngImageReader::read(BitmapEx& rBitmapEx)
{
auto pBackendCapabilities = ImplGetSVData()->mpDefInst->GetBackendCapabilities();
bool bSupportsBitmap32 = pBackendCapabilities->mbSupportsBitmap32;
return reader(mrStream, rBitmapEx, bSupportsBitmap32);
}
} // namespace vcl
diff --git a/vcl/source/filter/png/pngwrite.cxx b/vcl/source/filter/png/pngwrite.cxx
index 98dc91c33..38e7617 100644
--- a/vcl/source/filter/png/pngwrite.cxx
+++ b/vcl/source/filter/png/pngwrite.cxx
@@ -34,6 +34,7 @@
#include <vcl/alpha.hxx>
#include <osl/endian.h>
#include <memory>
#include <vcl/BitmapTools.hxx>
#define PNG_DEF_COMPRESSION 6
@@ -100,7 +101,7 @@ private:
void ImplWriteChunk(unsigned char const * pSource, sal_uInt32 nDatSize);
};
PNGWriterImpl::PNGWriterImpl( const BitmapEx& rBmpEx,
PNGWriterImpl::PNGWriterImpl( const BitmapEx& rBitmapEx,
const css::uno::Sequence<css::beans::PropertyValue>* pFilterData )
: mnCompLevel(PNG_DEF_COMPRESSION)
, mnInterlaced(0)
@@ -116,9 +117,21 @@ PNGWriterImpl::PNGWriterImpl( const BitmapEx& rBmpEx,
, mbTrueAlpha(false)
, mnCRC(0)
{
if (!rBmpEx.IsEmpty())
if (!rBitmapEx.IsEmpty())
{
Bitmap aBmp(rBmpEx.GetBitmap());
BitmapEx aBitmapEx;
if (rBitmapEx.GetBitmap().GetBitCount() == 32)
{
if (!vcl::bitmap::convertBitmap32To24Plus8(rBitmapEx, aBitmapEx))
return;
}
else
{
aBitmapEx = rBitmapEx;
}
Bitmap aBmp(aBitmapEx.GetBitmap());
mnMaxChunkSize = std::numeric_limits<sal_uInt32>::max();
@@ -141,9 +154,9 @@ PNGWriterImpl::PNGWriterImpl( const BitmapEx& rBmpEx,
}
mnBitsPerPixel = static_cast<sal_uInt8>(aBmp.GetBitCount());
if (rBmpEx.IsTransparent())
if (aBitmapEx.IsTransparent())
{
if (mnBitsPerPixel <= 8 && rBmpEx.IsAlpha())
if (mnBitsPerPixel <= 8 && aBitmapEx.IsAlpha())
{
aBmp.Convert( BmpConversion::N24Bit );
mnBitsPerPixel = 24;
@@ -152,14 +165,14 @@ PNGWriterImpl::PNGWriterImpl( const BitmapEx& rBmpEx,
if (mnBitsPerPixel <= 8) // transparent palette
{
aBmp.Convert(BmpConversion::N8BitTrans);
aBmp.Replace(rBmpEx.GetMask(), BMP_COL_TRANS);
aBmp.Replace(aBitmapEx.GetMask(), BMP_COL_TRANS);
mnBitsPerPixel = 8;
mpAccess = Bitmap::ScopedReadAccess(aBmp);
if (mpAccess)
{
if (ImplWriteHeader())
{
ImplWritepHYs(rBmpEx);
ImplWritepHYs(aBitmapEx);
ImplWritePalette();
ImplWriteTransparent();
ImplWriteIDAT();
@@ -176,16 +189,16 @@ PNGWriterImpl::PNGWriterImpl( const BitmapEx& rBmpEx,
mpAccess = Bitmap::ScopedReadAccess(aBmp); // true RGB with alphachannel
if (mpAccess)
{
mbTrueAlpha = rBmpEx.IsAlpha();
mbTrueAlpha = aBitmapEx.IsAlpha();
if (mbTrueAlpha)
{
AlphaMask aMask(rBmpEx.GetAlpha());
AlphaMask aMask(aBitmapEx.GetAlpha());
mpMaskAccess = aMask.AcquireReadAccess();
if (mpMaskAccess)
{
if (ImplWriteHeader())
{
ImplWritepHYs(rBmpEx);
ImplWritepHYs(aBitmapEx);
ImplWriteIDAT();
}
aMask.ReleaseAccess(mpMaskAccess);
@@ -198,13 +211,13 @@ PNGWriterImpl::PNGWriterImpl( const BitmapEx& rBmpEx,
}
else
{
Bitmap aMask(rBmpEx.GetMask());
Bitmap aMask(aBitmapEx.GetMask());
mpMaskAccess = aMask.AcquireReadAccess();
if (mpMaskAccess)
{
if (ImplWriteHeader())
{
ImplWritepHYs(rBmpEx);
ImplWritepHYs(aBitmapEx);
ImplWriteIDAT();
}
Bitmap::ReleaseAccess(mpMaskAccess);
@@ -230,7 +243,7 @@ PNGWriterImpl::PNGWriterImpl( const BitmapEx& rBmpEx,
{
if (ImplWriteHeader())
{
ImplWritepHYs(rBmpEx);
ImplWritepHYs(aBitmapEx);
if (mpAccess->HasPalette())
ImplWritePalette();
diff --git a/vcl/source/gdi/bmpacc2.cxx b/vcl/source/gdi/bmpacc2.cxx
index 8386511..1b03e85 100644
--- a/vcl/source/gdi/bmpacc2.cxx
+++ b/vcl/source/gdi/bmpacc2.cxx
@@ -19,6 +19,7 @@
#include <vcl/salbtype.hxx>
#include <vcl/bitmapaccess.hxx>
#include <vcl/BitmapTools.hxx>
BitmapColor BitmapReadAccess::GetPixelForN1BitMsbPal(ConstScanline pScanline, long nX, const ColorMask&)
{
@@ -181,86 +182,110 @@ void BitmapReadAccess::SetPixelForN24BitTcRgb(Scanline pScanline, long nX, const
BitmapColor BitmapReadAccess::GetPixelForN32BitTcAbgr(ConstScanline pScanline, long nX, const ColorMask&)
{
BitmapColor aBitmapColor;
pScanline = pScanline + nX * 4;
pScanline = pScanline + ( nX << 2 ) + 1;
aBitmapColor.SetBlue( *pScanline++ );
aBitmapColor.SetGreen( *pScanline++ );
aBitmapColor.SetRed( *pScanline );
sal_uInt8 a = *pScanline++;
sal_uInt8 b = *pScanline++;
sal_uInt8 g = *pScanline++;
sal_uInt8 r = *pScanline;
return aBitmapColor;
return BitmapColor(
vcl::bitmap::unpremultiply(r, a),
vcl::bitmap::unpremultiply(g, a),
vcl::bitmap::unpremultiply(b, a),
0xFF - a);
}
void BitmapReadAccess::SetPixelForN32BitTcAbgr(Scanline pScanline, long nX, const BitmapColor& rBitmapColor, const ColorMask&)
{
pScanline = pScanline + ( nX << 2 );
*pScanline++ = 0xFF;
*pScanline++ = rBitmapColor.GetBlue();
*pScanline++ = rBitmapColor.GetGreen();
*pScanline = rBitmapColor.GetRed();
pScanline = pScanline + nX * 4;
sal_uInt8 alpha = 0xFF - rBitmapColor.GetAlpha();
*pScanline++ = alpha;
*pScanline++ = vcl::bitmap::premultiply(rBitmapColor.GetBlue(), alpha);
*pScanline++ = vcl::bitmap::premultiply(rBitmapColor.GetGreen(), alpha);
*pScanline = vcl::bitmap::premultiply(rBitmapColor.GetRed(), alpha);
}
BitmapColor BitmapReadAccess::GetPixelForN32BitTcArgb(ConstScanline pScanline, long nX, const ColorMask&)
{
BitmapColor aBitmapColor;
pScanline = pScanline + nX * 4;
pScanline = pScanline + ( nX << 2 ) + 1;
aBitmapColor.SetRed( *pScanline++ );
aBitmapColor.SetGreen( *pScanline++ );
aBitmapColor.SetBlue( *pScanline );
sal_uInt8 a = *pScanline++;
sal_uInt8 r = *pScanline++;
sal_uInt8 g = *pScanline++;
sal_uInt8 b = *pScanline;
return aBitmapColor;
return BitmapColor(
vcl::bitmap::unpremultiply(r, a),
vcl::bitmap::unpremultiply(g, a),
vcl::bitmap::unpremultiply(b, a),
0xFF - a);
}
void BitmapReadAccess::SetPixelForN32BitTcArgb(Scanline pScanline, long nX, const BitmapColor& rBitmapColor, const ColorMask&)
{
pScanline = pScanline + ( nX << 2 );
*pScanline++ = 0xFF;
*pScanline++ = rBitmapColor.GetRed();
*pScanline++ = rBitmapColor.GetGreen();
*pScanline = rBitmapColor.GetBlue();
pScanline = pScanline + nX * 4;
sal_uInt8 alpha = 0xFF - rBitmapColor.GetAlpha();
*pScanline++ = alpha;
*pScanline++ = vcl::bitmap::premultiply(rBitmapColor.GetRed(), alpha);
*pScanline++ = vcl::bitmap::premultiply(rBitmapColor.GetGreen(), alpha);
*pScanline = vcl::bitmap::premultiply(rBitmapColor.GetBlue(), alpha);
}
BitmapColor BitmapReadAccess::GetPixelForN32BitTcBgra(ConstScanline pScanline, long nX, const ColorMask&)
{
BitmapColor aBitmapColor;
pScanline = pScanline + nX * 4;
pScanline = pScanline + ( nX << 2 );
aBitmapColor.SetBlue( *pScanline++ );
aBitmapColor.SetGreen( *pScanline++ );
aBitmapColor.SetRed( *pScanline );
sal_uInt8 b = *pScanline++;
sal_uInt8 g = *pScanline++;
sal_uInt8 r = *pScanline++;
sal_uInt8 a = *pScanline;
return aBitmapColor;
return BitmapColor(
vcl::bitmap::unpremultiply(r, a),
vcl::bitmap::unpremultiply(g, a),
vcl::bitmap::unpremultiply(b, a),
0xFF - a);
}
void BitmapReadAccess::SetPixelForN32BitTcBgra(Scanline pScanline, long nX, const BitmapColor& rBitmapColor, const ColorMask&)
{
pScanline = pScanline + ( nX << 2 );
*pScanline++ = rBitmapColor.GetBlue();
*pScanline++ = rBitmapColor.GetGreen();
*pScanline++ = rBitmapColor.GetRed();
*pScanline = 0xFF;
pScanline = pScanline + nX * 4;
sal_uInt8 alpha = 0xFF - rBitmapColor.GetAlpha();
*pScanline++ = vcl::bitmap::premultiply(rBitmapColor.GetBlue(), alpha);
*pScanline++ = vcl::bitmap::premultiply(rBitmapColor.GetGreen(), alpha);
*pScanline++ = vcl::bitmap::premultiply(rBitmapColor.GetRed(), alpha);
*pScanline = alpha;
}
BitmapColor BitmapReadAccess::GetPixelForN32BitTcRgba(ConstScanline pScanline, long nX, const ColorMask&)
{
BitmapColor aBitmapColor;
pScanline = pScanline + nX * 4;
pScanline = pScanline + ( nX << 2 );
aBitmapColor.SetRed( *pScanline++ );
aBitmapColor.SetGreen( *pScanline++ );
aBitmapColor.SetBlue( *pScanline );
sal_uInt8 r = *pScanline++;
sal_uInt8 g = *pScanline++;
sal_uInt8 b = *pScanline++;
sal_uInt8 a = *pScanline;
return aBitmapColor;
return BitmapColor(
vcl::bitmap::unpremultiply(r, a),
vcl::bitmap::unpremultiply(g, a),
vcl::bitmap::unpremultiply(b, a),
0xFF - a);
}
void BitmapReadAccess::SetPixelForN32BitTcRgba(Scanline pScanline, long nX, const BitmapColor& rBitmapColor, const ColorMask&)
{
pScanline = pScanline + ( nX << 2 );
*pScanline++ = rBitmapColor.GetRed();
*pScanline++ = rBitmapColor.GetGreen();
*pScanline++ = rBitmapColor.GetBlue();
*pScanline = 0xFF;
pScanline = pScanline + nX * 4;
sal_uInt8 alpha = 0xFF - rBitmapColor.GetAlpha();
*pScanline++ = vcl::bitmap::premultiply(rBitmapColor.GetRed(), alpha);
*pScanline++ = vcl::bitmap::premultiply(rBitmapColor.GetGreen(), alpha);
*pScanline++ = vcl::bitmap::premultiply(rBitmapColor.GetBlue(), alpha);
*pScanline = alpha;
}
BitmapColor BitmapReadAccess::GetPixelForN32BitTcMask(ConstScanline pScanline, long nX, const ColorMask& rMask)