summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNoel Grandin <noelgrandin@gmail.com>2021-04-16 20:33:10 +0200
committerNoel Grandin <noel.grandin@collabora.co.uk>2023-07-25 08:38:12 +0200
commit81994cb2b8b32453a92bcb011830fcb884f22ff3 (patch)
treeae1750e92421ad2e0ec3f50351c3be6581841598
parentdabedcaf27b0af1e38a611b8d8e48444f848e01d (diff)
Convert internal vcl bitmap formats transparency->alpha (II)
(Second attempt at landing this) Image formats and graphics APIs use alpha, not transparency, so change our internal formats and data structures to work directly with alpha, so we don't need to modify data before we push it to graphics APIs. Add a couple of new Color constants to make the intention of the vcl code clearer. Notes (*) On macOS, tweaking the logic in CreateWithSalBitmapAndMask to more accurately reflect the requirements of the CGImageCreateWithMask function seems to fix some tests. (*) The vcl code does not properly support gradients with transparency. So the previous code was wrong, and this change is going to result in slightly different wrongness. Change-Id: I9e21c2e98d88ecfdc5f75db13bd1ffff7c38db98 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/114168 Tested-by: Jenkins Reviewed-by: Patrick Luby <plubius@neooffice.org> Reviewed-by: Noel Grandin <noel.grandin@collabora.co.uk>
-rw-r--r--canvas/source/directx/dx_canvasbitmap.cxx2
-rw-r--r--canvas/source/directx/dx_vcltools.cxx18
-rw-r--r--canvas/source/vcl/canvasbitmaphelper.cxx2
-rw-r--r--cppcanvas/source/mtfrenderer/transparencygroupaction.cxx2
-rw-r--r--cui/source/dialogs/about.cxx26
-rw-r--r--drawinglayer/source/primitive2d/GlowSoftEgdeShadowTools.cxx6
-rw-r--r--drawinglayer/source/primitive2d/discreteshadowprimitive2d.cxx1
-rw-r--r--drawinglayer/source/processor2d/d2dpixelprocessor2d.cxx2
-rw-r--r--drawinglayer/source/processor2d/vclhelperbufferdevice.cxx1
-rw-r--r--drawinglayer/source/tools/converters.cxx27
-rw-r--r--forms/source/component/imgprod.cxx4
-rw-r--r--include/tools/color.hxx4
-rw-r--r--include/vcl/bitmap.hxx31
-rw-r--r--include/vcl/virdev.hxx4
-rw-r--r--sd/qa/unit/PNGExportTests.cxx2
-rw-r--r--sfx2/source/dialog/infobar.cxx2
-rw-r--r--slideshow/source/engine/shapes/gdimtftools.cxx6
-rw-r--r--svx/source/svdraw/svdfmtf.cxx5
-rw-r--r--toolkit/source/helper/vclunohelper.cxx1
-rw-r--r--vcl/backendtest/outputdevice/bitmap.cxx8
-rw-r--r--vcl/headless/BitmapHelper.cxx14
-rw-r--r--vcl/headless/CairoCommon.cxx15
-rw-r--r--vcl/inc/bitmap/ScanlineTools.hxx4
-rw-r--r--vcl/inc/headless/BitmapHelper.hxx3
-rw-r--r--vcl/inc/headless/CairoCommon.hxx2
-rw-r--r--vcl/qa/cppunit/BackendTest.cxx2
-rw-r--r--vcl/qa/cppunit/BitmapExTest.cxx3
-rw-r--r--vcl/qa/cppunit/ScanlineToolsTest.cxx10
-rw-r--r--vcl/qa/cppunit/canvasbitmaptest.cxx28
-rw-r--r--vcl/qa/cppunit/png/PngFilterTest.cxx32
-rw-r--r--vcl/qa/cppunit/skia/skia.cxx6
-rw-r--r--vcl/qa/cppunit/svm/svmtest.cxx21
-rw-r--r--vcl/qt5/QtGraphics_GDI.cxx1
-rw-r--r--vcl/quartz/cgutils.mm47
-rw-r--r--vcl/skia/gdiimpl.cxx31
-rw-r--r--vcl/skia/salbmp.cxx26
-rw-r--r--vcl/source/bitmap/BitmapAlphaClampFilter.cxx4
-rw-r--r--vcl/source/bitmap/BitmapEx.cxx48
-rw-r--r--vcl/source/bitmap/BitmapMaskToAlphaFilter.cxx8
-rw-r--r--vcl/source/bitmap/BitmapTools.cxx43
-rw-r--r--vcl/source/bitmap/alpha.cxx33
-rw-r--r--vcl/source/bitmap/bitmappaint.cxx235
-rw-r--r--vcl/source/bitmap/dibtools.cxx11
-rw-r--r--vcl/source/filter/eps/eps.cxx8
-rw-r--r--vcl/source/filter/igif/gifread.cxx4
-rw-r--r--vcl/source/filter/ipdf/pdfread.cxx3
-rw-r--r--vcl/source/filter/ipsd/ipsd.cxx4
-rw-r--r--vcl/source/filter/itiff/itiff.cxx2
-rw-r--r--vcl/source/filter/jpeg/JpegReader.cxx6
-rw-r--r--vcl/source/filter/jpeg/JpegReader.hxx2
-rw-r--r--vcl/source/filter/png/PngImageReader.cxx5
-rw-r--r--vcl/source/filter/png/PngImageWriter.cxx8
-rw-r--r--vcl/source/filter/wmf/emfwr.cxx3
-rw-r--r--vcl/source/filter/wmf/wmfwr.cxx3
-rw-r--r--vcl/source/gdi/gdimtf.cxx2
-rw-r--r--vcl/source/gdi/pdfwriter_impl2.cxx89
-rw-r--r--vcl/source/gdi/virdev.cxx18
-rw-r--r--vcl/source/graphic/GraphicObject2.cxx4
-rw-r--r--vcl/source/graphic/UnoGraphic.cxx2
-rw-r--r--vcl/source/helper/canvasbitmap.cxx16
-rw-r--r--vcl/source/helper/canvastools.cxx4
-rw-r--r--vcl/source/image/ImplImage.cxx11
-rw-r--r--vcl/source/opengl/OpenGLHelper.cxx2
-rw-r--r--vcl/source/outdev/background.cxx8
-rw-r--r--vcl/source/outdev/bitmap.cxx15
-rw-r--r--vcl/source/outdev/bitmapex.cxx6
-rw-r--r--vcl/source/outdev/fill.cxx2
-rw-r--r--vcl/source/outdev/font.cxx2
-rw-r--r--vcl/source/outdev/gradient.cxx2
-rw-r--r--vcl/source/outdev/line.cxx2
-rw-r--r--vcl/source/outdev/pixel.cxx4
-rw-r--r--vcl/source/outdev/text.cxx4
-rw-r--r--vcl/source/outdev/textline.cxx4
-rw-r--r--vcl/source/outdev/transparent.cxx43
-rw-r--r--vcl/source/rendercontext/drawmode.cxx2
-rw-r--r--vcl/win/gdi/salbmp.cxx2
76 files changed, 703 insertions, 370 deletions
diff --git a/canvas/source/directx/dx_canvasbitmap.cxx b/canvas/source/directx/dx_canvasbitmap.cxx
index 33dc7859fadb..fb06288ada86 100644
--- a/canvas/source/directx/dx_canvasbitmap.cxx
+++ b/canvas/source/directx/dx_canvasbitmap.cxx
@@ -214,7 +214,7 @@ namespace dxcanvas
sal_uInt8* pOutBits=pAlphaBits.get()+y*nScanWidth;
for( sal_Int32 x=0; x<aSize.getWidth(); ++x )
{
- *pOutBits++ = 255-*pInBits;
+ *pOutBits++ = *pInBits;
pInBits += 4;
}
}
diff --git a/canvas/source/directx/dx_vcltools.cxx b/canvas/source/directx/dx_vcltools.cxx
index 456f22386dd1..fb5e5c5e93db 100644
--- a/canvas/source/directx/dx_vcltools.cxx
+++ b/canvas/source/directx/dx_vcltools.cxx
@@ -211,11 +211,7 @@ namespace dxcanvas::tools
*pCurrOutput++ = aCol.GetBlue();
*pCurrOutput++ = aCol.GetGreen();
*pCurrOutput++ = aCol.GetRed();
-
- // our notion of alpha is
- // different from the rest
- // of the world's
- *pCurrOutput++ = 255 - static_cast<BYTE>(*pAScan++);
+ *pCurrOutput++ = static_cast<BYTE>(*pAScan++);
}
}
break;
@@ -231,11 +227,7 @@ namespace dxcanvas::tools
*pCurrOutput++ = *pScan++;
*pCurrOutput++ = *pScan++;
*pCurrOutput++ = *pScan++;
-
- // our notion of alpha is
- // different from the rest
- // of the world's
- *pCurrOutput++ = 255 - static_cast<BYTE>(*pAScan++);
+ *pCurrOutput++ = static_cast<BYTE>(*pAScan++);
}
}
break;
@@ -258,11 +250,7 @@ namespace dxcanvas::tools
*pCurrOutput++ = aCol.GetBlue();
*pCurrOutput++ = aCol.GetGreen();
*pCurrOutput++ = aCol.GetRed();
-
- // our notion of alpha is
- // different from the rest
- // of the world's
- *pCurrOutput++ = 255 - static_cast<BYTE>(*pAScan++);
+ *pCurrOutput++ = static_cast<BYTE>(*pAScan++);
}
}
break;
diff --git a/canvas/source/vcl/canvasbitmaphelper.cxx b/canvas/source/vcl/canvasbitmaphelper.cxx
index cd33b266346d..99b9831cabf6 100644
--- a/canvas/source/vcl/canvasbitmaphelper.cxx
+++ b/canvas/source/vcl/canvasbitmaphelper.cxx
@@ -146,7 +146,7 @@ namespace vclcanvas
pRes[ 0 ] = aColor.GetRed();
pRes[ 1 ] = aColor.GetGreen();
pRes[ 2 ] = aColor.GetBlue();
- pRes[ 3 ] = 255 - aColor.GetAlpha();
+ pRes[ 3 ] = aColor.GetAlpha();
return aRes;
}
diff --git a/cppcanvas/source/mtfrenderer/transparencygroupaction.cxx b/cppcanvas/source/mtfrenderer/transparencygroupaction.cxx
index 35a2b45fd7bd..b8350a8f3944 100644
--- a/cppcanvas/source/mtfrenderer/transparencygroupaction.cxx
+++ b/cppcanvas/source/mtfrenderer/transparencygroupaction.cxx
@@ -229,7 +229,7 @@ namespace cppcanvas::internal
// VirtualDevice with alpha channel
ScopedVclPtrInstance<VirtualDevice> aVDev(
*::Application::GetDefaultDevice(), DeviceFormat::WITH_ALPHA );
- aVDev->SetOutputSizePixel( aBitmapSizePixel );
+ aVDev->SetOutputSizePixel( aBitmapSizePixel, true, true );
aVDev->SetMapMode();
if( rSubset.mnSubsetBegin != 0 ||
diff --git a/cui/source/dialogs/about.cxx b/cui/source/dialogs/about.cxx
index 41d17b2a06d5..ce82e418cf9e 100644
--- a/cui/source/dialogs/about.cxx
+++ b/cui/source/dialogs/about.cxx
@@ -26,9 +26,9 @@
#include <osl/process.h> //osl_getProcessLocale
#include <rtl/bootstrap.hxx>
#include <sal/log.hxx> //SAL_WARN
+#include <vcl/graph.hxx> //Graphic
#include <vcl/settings.hxx> //GetSettings
#include <vcl/svapp.hxx> //Application::
-#include <vcl/virdev.hxx> //VirtualDevice
#include <vcl/weld.hxx>
#include <unotools/resmgr.hxx> //Translate
@@ -105,20 +105,20 @@ AboutDialog::AboutDialog(weld::Window *pParent)
? "shell/logo_inverted"
: "shell/logo",
aBackgroundBitmap, nWidth * 0.8)) {
- ScopedVclPtr<VirtualDevice> m_pVirDev =
- m_pBrandImage->create_virtual_device();
- m_pVirDev->SetOutputSizePixel(aBackgroundBitmap.GetSizePixel());
- m_pVirDev->DrawBitmapEx(Point(0, 0), aBackgroundBitmap);
- m_pBrandImage->set_image(m_pVirDev.get());
- m_pVirDev.disposeAndClear();
+ // Eliminate white background when Skia is disabled by not drawing the
+ // background bitmap to a VirtualDevice. On most platforms, non-Skia
+ // VirtualDevices will be filled with a solid color when drawing
+ // the bitmap.
+ Graphic aGraphic(aBackgroundBitmap);
+ m_pBrandImage->set_image(aGraphic.GetXGraphic());
}
if (SfxApplication::loadBrandSvg("shell/about", aBackgroundBitmap, nWidth * 0.9)) {
- ScopedVclPtr<VirtualDevice> m_pVirDev =
- m_pAboutImage->create_virtual_device();
- m_pVirDev->SetOutputSizePixel(aBackgroundBitmap.GetSizePixel());
- m_pVirDev->DrawBitmapEx(Point(0, 0), aBackgroundBitmap);
- m_pAboutImage->set_image(m_pVirDev.get());
- m_pVirDev.disposeAndClear();
+ // Eliminate white background when Skia is disabled by not drawing the
+ // background bitmap to a VirtualDevice. On most platforms, non-Skia
+ // VirtualDevices will be filled with a solid color when drawing
+ // the bitmap.
+ Graphic aGraphic(aBackgroundBitmap);
+ m_pAboutImage->set_image(aGraphic.GetXGraphic());
}
// Links
diff --git a/drawinglayer/source/primitive2d/GlowSoftEgdeShadowTools.cxx b/drawinglayer/source/primitive2d/GlowSoftEgdeShadowTools.cxx
index 3c45fdd030f4..9bbdf7176935 100644
--- a/drawinglayer/source/primitive2d/GlowSoftEgdeShadowTools.cxx
+++ b/drawinglayer/source/primitive2d/GlowSoftEgdeShadowTools.cxx
@@ -58,10 +58,10 @@ AlphaMask ProcessAndBlurAlphaMask(const Bitmap& rMask, double fErodeDilateRadius
else if (fErodeDilateRadius < 0)
BitmapFilter::Filter(mask, BitmapErodeFilter(-fErodeDilateRadius, 0xFF));
- if (nTransparency)
+ if (nTransparency != 255)
{
const Color aTransparency(nTransparency, nTransparency, nTransparency);
- mask.Replace(COL_BLACK, aTransparency);
+ mask.Replace(COL_WHITE, aTransparency);
}
// We need 8-bit grey mask for blurring
@@ -72,6 +72,8 @@ AlphaMask ProcessAndBlurAlphaMask(const Bitmap& rMask, double fErodeDilateRadius
mask.Scale(rMask.GetSizePixel());
+ mask.Invert(); // convert transparency to alpha
+
return AlphaMask(mask.GetBitmap());
}
diff --git a/drawinglayer/source/primitive2d/discreteshadowprimitive2d.cxx b/drawinglayer/source/primitive2d/discreteshadowprimitive2d.cxx
index 4a64da368a2f..89c4335bb0b3 100644
--- a/drawinglayer/source/primitive2d/discreteshadowprimitive2d.cxx
+++ b/drawinglayer/source/primitive2d/discreteshadowprimitive2d.cxx
@@ -32,6 +32,7 @@ namespace drawinglayer::primitive2d
DiscreteShadow::DiscreteShadow(const BitmapEx& rBitmapEx)
: maBitmapEx(rBitmapEx)
{
+ maBitmapEx.Invert(); // convert transparency to alpha
const Size& rBitmapSize = getBitmapEx().GetSizePixel();
if(rBitmapSize.Width() != rBitmapSize.Height() || rBitmapSize.Width() < 7)
diff --git a/drawinglayer/source/processor2d/d2dpixelprocessor2d.cxx b/drawinglayer/source/processor2d/d2dpixelprocessor2d.cxx
index 783060c2be4c..7671e0c29a05 100644
--- a/drawinglayer/source/processor2d/d2dpixelprocessor2d.cxx
+++ b/drawinglayer/source/processor2d/d2dpixelprocessor2d.cxx
@@ -410,7 +410,7 @@ sal::systools::COMReference<ID2D1Bitmap> createB2DBitmap(const BitmapEx& rBitmap
{
const BitmapColor aColor(pReadAccess->GetColor(y, x));
const BitmapColor aAlpha(pAlphaReadAccess->GetColor(y, x));
- const sal_uInt16 nAlpha(255 - aAlpha.GetRed());
+ const sal_uInt16 nAlpha(aAlpha.GetRed());
*pTarget++ = sal_uInt32(BitmapColor(
ColorAlpha, sal_uInt8((sal_uInt16(aColor.GetRed()) * nAlpha) >> 8),
diff --git a/drawinglayer/source/processor2d/vclhelperbufferdevice.cxx b/drawinglayer/source/processor2d/vclhelperbufferdevice.cxx
index c76225194dd7..f90049bf8773 100644
--- a/drawinglayer/source/processor2d/vclhelperbufferdevice.cxx
+++ b/drawinglayer/source/processor2d/vclhelperbufferdevice.cxx
@@ -476,6 +476,7 @@ void impBufferDevice::paint(double fTrans)
{
mpAlpha->EnableMapMode(false);
AlphaMask aAlphaMask(mpAlpha->GetBitmap(aEmptyPoint, aSizePixel));
+ aAlphaMask.Invert(); // convert transparency to alpha
#ifdef DBG_UTIL
if (!sDumpPath.isEmpty() && bDoSaveForVisualControl)
diff --git a/drawinglayer/source/tools/converters.cxx b/drawinglayer/source/tools/converters.cxx
index 001019cd9623..80ae15a3b6a9 100644
--- a/drawinglayer/source/tools/converters.cxx
+++ b/drawinglayer/source/tools/converters.cxx
@@ -95,7 +95,7 @@ AlphaMask implcreateAlphaMask(drawinglayer::primitive2d::Primitive2DContainer& r
// prepare for mask creation
pContent->SetMapMode(MapMode(MapUnit::MapPixel));
- // set alpha to all white (fully transparent)
+ // set transparency to all white (fully transparent)
pContent->Erase();
basegfx::BColorModifierSharedPtr aBColorModifier;
@@ -107,7 +107,7 @@ AlphaMask implcreateAlphaMask(drawinglayer::primitive2d::Primitive2DContainer& r
}
else
{
- // Embed primitives to paint them black
+ // Embed primitives to paint them black (fully opaque)
aBColorModifier
= std::make_shared<basegfx::BColorModifier_replace>(basegfx::BColor(0.0, 0.0, 0.0));
}
@@ -123,7 +123,14 @@ AlphaMask implcreateAlphaMask(drawinglayer::primitive2d::Primitive2DContainer& r
// get alpha channel from vdev
pContent->EnableMapMode(false);
const Point aEmptyPoint;
- return AlphaMask(pContent->GetBitmap(aEmptyPoint, rSizePixel));
+
+ // Convert from transparency->alpha.
+ // FIXME in theory I should be able to directly construct alpha by using black as background
+ // and white as foreground, but that doesn't work for some reason.
+ Bitmap aContentBitmap = pContent->GetBitmap(aEmptyPoint, rSizePixel);
+ aContentBitmap.Invert();
+
+ return AlphaMask(aContentBitmap);
}
}
@@ -257,12 +264,16 @@ BitmapEx convertToBitmapEx(drawinglayer::primitive2d::Primitive2DContainer&& rSe
if (aAlpha.hasAlpha())
{
// Need to correct content using known alpha to get to background-free
- // RGBA result, usable e.g. in PNG export(s) or convert-to-bitmap
- aRetval.RemoveBlendedStartColor(COL_WHITE, aAlpha);
+ // RGBA result, usable e.g. in PNG export(s) or convert-to-bitmap.
+ // Now that vcl supports bitmaps with an alpha channel, only apply
+ // this correction to bitmaps without an alpha channel.
+ if (pContent->GetBitCount() < 32)
+ aRetval.RemoveBlendedStartColor(COL_WHITE, aAlpha);
+ // return combined result
+ return BitmapEx(aRetval, aAlpha);
}
-
- // return combined result
- return BitmapEx(aRetval, aAlpha);
+ else
+ return BitmapEx(aRetval);
}
BitmapEx convertPrimitive2DContainerToBitmapEx(primitive2d::Primitive2DContainer&& rSequence,
diff --git a/forms/source/component/imgprod.cxx b/forms/source/component/imgprod.cxx
index 46439682519f..3f2e6bfdee5b 100644
--- a/forms/source/component/imgprod.cxx
+++ b/forms/source/component/imgprod.cxx
@@ -379,7 +379,7 @@ void ImageProducer::ImplUpdateConsumer( const Graphic& rGraphic )
if( !pMskAcc )
{
- aMask = Bitmap(aBmp.GetSizePixel(), vcl::PixelFormat::N8_BPP, &Bitmap::GetGreyPalette(256));
+ aMask = AlphaMask(aBmp.GetSizePixel());
aMask.Erase( 0 );
pMskAcc = aMask.AcquireReadAccess();
}
@@ -389,7 +389,7 @@ void ImageProducer::ImplUpdateConsumer( const Graphic& rGraphic )
if( pBmpAcc->HasPalette() )
{
- const BitmapColor aWhite( pMskAcc->GetBestMatchingColor( COL_WHITE ) );
+ const BitmapColor aWhite( pMskAcc->GetBestMatchingColor( COL_ALPHA_TRANSPARENT ) );
if( mnTransIndex < 256 )
{
diff --git a/include/tools/color.hxx b/include/tools/color.hxx
index 41826ec2335f..c3bbb5bf0e2b 100644
--- a/include/tools/color.hxx
+++ b/include/tools/color.hxx
@@ -449,6 +449,10 @@ static_assert (sal_uInt32(Color(0x12, 0x34, 0x56)) == 0x00123456);
inline constexpr ::Color COL_TRANSPARENT ( ColorTransparency, 0xFF, 0xFF, 0xFF, 0xFF );
inline constexpr ::Color COL_AUTO ( ColorTransparency, 0xFF, 0xFF, 0xFF, 0xFF );
+// These are used when drawing to the separate alpha channel we use in vcl
+inline constexpr ::Color COL_ALPHA_TRANSPARENT ( 0x00, 0x00, 0x00 );
+inline constexpr ::Color COL_ALPHA_OPAQUE ( 0xff, 0xff, 0xff );
+
inline constexpr ::Color COL_BLACK ( 0x00, 0x00, 0x00 );
inline constexpr ::Color COL_BLUE ( 0x00, 0x00, 0x80 );
inline constexpr ::Color COL_GREEN ( 0x00, 0x80, 0x00 );
diff --git a/include/vcl/bitmap.hxx b/include/vcl/bitmap.hxx
index 0c794d496342..bc0d628179ca 100644
--- a/include/vcl/bitmap.hxx
+++ b/include/vcl/bitmap.hxx
@@ -374,6 +374,37 @@ public:
*/
Bitmap CreateMask( const Color& rTransColor, sal_uInt8 nTol ) const;
+ /** Create on-off alpha mask from bitmap
+
+ This method creates a bitmask from the bitmap, where every
+ pixel that equals rTransColor is set transparent, the rest
+ opaque.
+
+ @param rTransColor
+ Color value where the bitmask should be transparent
+
+ @return the resulting bitmask.
+ */
+ AlphaMask CreateAlphaMask( const Color& rTransColor ) const;
+
+ /** Create on-off alpha mask from bitmap
+
+ This method creates a bitmask from the bitmap, where every
+ pixel that equals rTransColor is set transparent, the rest
+ opaque.
+
+ @param rTransColor
+ Color value where the bitmask should be transparent
+
+ @param nTol
+ Tolerance value. Specifies the maximal difference between
+ rTransColor and the individual pixel values, such that the
+ corresponding pixel is still regarded as transparent.
+
+ @return the resulting bitmask.
+ */
+ AlphaMask CreateAlphaMask( const Color& rTransColor, sal_uInt8 nTol ) const;
+
/** Create region of similar colors in a given rectangle
@param rColor
diff --git a/include/vcl/virdev.hxx b/include/vcl/virdev.hxx
index 0f6ec8ee1857..40cf445f0390 100644
--- a/include/vcl/virdev.hxx
+++ b/include/vcl/virdev.hxx
@@ -58,7 +58,7 @@ private:
SAL_DLLPRIVATE bool InnerImplSetOutputSizePixel( const Size& rNewSize, bool bErase,
sal_uInt8* pBuffer );
SAL_DLLPRIVATE bool ImplSetOutputSizePixel( const Size& rNewSize, bool bErase,
- sal_uInt8* pBuffer );
+ sal_uInt8* pBuffer, bool bAlphaMaskTransparent = false );
VirtualDevice (const VirtualDevice &) = delete;
VirtualDevice & operator= (const VirtualDevice &) = delete;
@@ -124,7 +124,7 @@ public:
virtual void EnableRTL( bool bEnable = true ) override;
- bool SetOutputSizePixel( const Size& rNewSize, bool bErase = true );
+ bool SetOutputSizePixel( const Size& rNewSize, bool bErase = true, bool bAlphaMaskTransparent = false );
bool SetOutputSizePixelScaleOffsetAndLOKBuffer( const Size& rNewSize,
const Fraction& rScale,
const Point& rNewOffset,
diff --git a/sd/qa/unit/PNGExportTests.cxx b/sd/qa/unit/PNGExportTests.cxx
index 5ca65f545dc2..58ec8d6077cc 100644
--- a/sd/qa/unit/PNGExportTests.cxx
+++ b/sd/qa/unit/PNGExportTests.cxx
@@ -295,7 +295,7 @@ CPPUNIT_TEST_FIXTURE(SdPNGExportTest, testTdf147119)
// - Expected: Color: R:255 G:255 B:255 A:0
// - Actual : Color: R:0 G:0 B:0 A:0
const Color aColor = pReadAccess->GetColor(nY, nX);
- CPPUNIT_ASSERT_EQUAL(COL_WHITE, aColor);
+ CPPUNIT_ASSERT_EQUAL(COL_ALPHA_TRANSPARENT, aColor);
}
}
}
diff --git a/sfx2/source/dialog/infobar.cxx b/sfx2/source/dialog/infobar.cxx
index 81e8ffe9d864..778b5e9b140e 100644
--- a/sfx2/source/dialog/infobar.cxx
+++ b/sfx2/source/dialog/infobar.cxx
@@ -115,7 +115,7 @@ void SfxInfoBarWindow::SetCloseButtonImage()
drawinglayer::primitive2d::Primitive2DContainer aSeq(2);
// Draw backround. The right and bottom need to be extended by 1 or
- // there will be a white line on both edges when Skia is enabled.
+ // there will be a white line on both edges.
B2DPolygon aPolygon;
aPolygon.append(B2DPoint(aRect.Left(), aRect.Top()));
aPolygon.append(B2DPoint(aRect.Right() + 1, aRect.Top()));
diff --git a/slideshow/source/engine/shapes/gdimtftools.cxx b/slideshow/source/engine/shapes/gdimtftools.cxx
index 990d9d26caac..c5a215eefbc4 100644
--- a/slideshow/source/engine/shapes/gdimtftools.cxx
+++ b/slideshow/source/engine/shapes/gdimtftools.cxx
@@ -338,15 +338,15 @@ bool getAnimationFromGraphic( VectorOfMtfAnimationFrames& o_rFrames,
// extract current aVDev content into a new animation
// frame
GDIMetaFileSharedPtr pMtf = std::make_shared<GDIMetaFile>();
+ Bitmap aAlphaMask = pVDevMask->GetBitmap(aEmptyPoint, aAnimSize);
+ aAlphaMask.Invert(); // convert from transparency to alpha
pMtf->AddAction(
new MetaBmpExAction( aEmptyPoint,
BitmapEx(
pVDev->GetBitmap(
aEmptyPoint,
aAnimSize ),
- pVDevMask->GetBitmap(
- aEmptyPoint,
- aAnimSize ))));
+ aAlphaMask)));
// setup mtf dimensions and pref map mode (for
// simplicity, keep it all in pixel. the metafile
diff --git a/svx/source/svdraw/svdfmtf.cxx b/svx/source/svdraw/svdfmtf.cxx
index 839fff3bdb15..923c40a550fa 100644
--- a/svx/source/svdraw/svdfmtf.cxx
+++ b/svx/source/svdraw/svdfmtf.cxx
@@ -1564,6 +1564,7 @@ void ImpSdrGDIMetaFileImport::DoAction(MetaFloatTransparentAction const & rAct)
pVDev->DrawGradient(tools::Rectangle(Point(0, 0), pVDev->GetOutputSizePixel()), rGradient);
aNewMask = AlphaMask(pVDev->GetBitmap(Point(0, 0), pVDev->GetOutputSizePixel()));
+ aNewMask.Invert(); // convert transparency to alpha
bHasNewMask = true;
}
@@ -1577,9 +1578,9 @@ void ImpSdrGDIMetaFileImport::DoAction(MetaFloatTransparentAction const & rAct)
// no transparence yet, apply new one
if(bFixedTransparence)
{
- sal_uInt8 aAlpha(basegfx::fround(fTransparence * 255.0));
+ sal_uInt8 nTransparence(basegfx::fround(fTransparence * 255.0));
- aNewMask = AlphaMask(aBitmapEx.GetBitmap().GetSizePixel(), &aAlpha);
+ aNewMask = AlphaMask(aBitmapEx.GetBitmap().GetSizePixel(), &nTransparence);
}
aBitmapEx = BitmapEx(aBitmapEx.GetBitmap(), aNewMask);
diff --git a/toolkit/source/helper/vclunohelper.cxx b/toolkit/source/helper/vclunohelper.cxx
index 45580c37cac8..9f05ae707065 100644
--- a/toolkit/source/helper/vclunohelper.cxx
+++ b/toolkit/source/helper/vclunohelper.cxx
@@ -89,6 +89,7 @@ BitmapEx VCLUnoHelper::GetBitmap( const css::uno::Reference< css::awt::XBitmap>&
SvMemoryStream aMem( aBytes.getArray(), aBytes.getLength(), StreamMode::READ );
ReadDIB(aMask, aMem, true);
}
+ aMask.Invert(); // Convert from transparency to alpha
aBmp = BitmapEx( aDIB, aMask );
}
}
diff --git a/vcl/backendtest/outputdevice/bitmap.cxx b/vcl/backendtest/outputdevice/bitmap.cxx
index 5b491badf587..9ea1a6f08d84 100644
--- a/vcl/backendtest/outputdevice/bitmap.cxx
+++ b/vcl/backendtest/outputdevice/bitmap.cxx
@@ -105,8 +105,8 @@ Bitmap OutputDeviceTestBitmap::setupDrawBitmapExWithAlpha(vcl::PixelFormat aBitm
AlphaMask aAlpha(aBitmapSize);
{
AlphaScopedWriteAccess aWriteAccess(aAlpha);
- aWriteAccess->Erase(COL_WHITE);
- aWriteAccess->SetLineColor(Color(0x44, 0x44, 0x44));
+ aWriteAccess->Erase(COL_ALPHA_TRANSPARENT);
+ aWriteAccess->SetLineColor(Color(0xBB, 0xBB, 0xBB));
aWriteAccess->DrawRect(tools::Rectangle(0, 0, 8, 8));
aWriteAccess->DrawRect(tools::Rectangle(3, 3, 5, 5));
}
@@ -154,8 +154,8 @@ BitmapEx OutputDeviceTestBitmap::setupDrawBlend(vcl::PixelFormat aBitmapFormat)
AlphaMask aAlpha(aBitmapSize);
{
AlphaScopedWriteAccess aWriteAccess(aAlpha);
- aWriteAccess->Erase(COL_WHITE);
- aWriteAccess->SetLineColor(Color(0x44, 0x44, 0x44));
+ aWriteAccess->Erase(COL_ALPHA_TRANSPARENT);
+ aWriteAccess->SetLineColor(Color(0xBB, 0xBB, 0xBB));
aWriteAccess->DrawRect(tools::Rectangle(0, 0, 8, 8));
aWriteAccess->DrawRect(tools::Rectangle(3, 3, 5, 5));
}
diff --git a/vcl/headless/BitmapHelper.cxx b/vcl/headless/BitmapHelper.cxx
index 3eb29aa76ad3..8ed0cac09fcb 100644
--- a/vcl/headless/BitmapHelper.cxx
+++ b/vcl/headless/BitmapHelper.cxx
@@ -84,19 +84,7 @@ MaskHelper::MaskHelper(const SalBitmap& rAlphaBitmap)
const BitmapBuffer* pMaskBuf = rMask.GetBuffer();
assert(rAlphaBitmap.GetBitCount() == 8 && "we only support 8-bit masks now");
- // the alpha values need to be inverted for Cairo
- // so big stupid copy and invert here
- const int nImageSize = pMaskBuf->mnHeight * pMaskBuf->mnScanlineSize;
- pAlphaBits.reset(new unsigned char[nImageSize]);
- memcpy(pAlphaBits.get(), pMaskBuf->mpBits, nImageSize);
-
- // TODO: make upper layers use standard alpha
- sal_uInt32* pLDst = reinterpret_cast<sal_uInt32*>(pAlphaBits.get());
- for (int i = nImageSize / sizeof(sal_uInt32); --i >= 0; ++pLDst)
- *pLDst = ~*pLDst;
- assert(reinterpret_cast<unsigned char*>(pLDst) == pAlphaBits.get() + nImageSize);
-
- implSetSurface(cairo_image_surface_create_for_data(pAlphaBits.get(), CAIRO_FORMAT_A8,
+ implSetSurface(cairo_image_surface_create_for_data(pMaskBuf->mpBits, CAIRO_FORMAT_A8,
pMaskBuf->mnWidth, pMaskBuf->mnHeight,
pMaskBuf->mnScanlineSize));
}
diff --git a/vcl/headless/CairoCommon.cxx b/vcl/headless/CairoCommon.cxx
index 15b8cebfb261..d378d1477bd4 100644
--- a/vcl/headless/CairoCommon.cxx
+++ b/vcl/headless/CairoCommon.cxx
@@ -1912,8 +1912,6 @@ std::shared_ptr<SalBitmap> CairoCommon::getBitmap(tools::Long nX, tools::Long nY
cairo_destroy(cr);
cairo_surface_destroy(target);
- Toggle1BitTransparency(*pBitmap->GetBuffer());
-
return pBitmap;
}
@@ -2080,19 +2078,6 @@ std::unique_ptr<BitmapBuffer> FastConvert24BitRgbTo32BitCairo(const BitmapBuffer
return pDst;
}
-void Toggle1BitTransparency(const BitmapBuffer& rBuf)
-{
- assert(rBuf.maPalette.GetBestIndex(BitmapColor(COL_BLACK)) == 0);
- // TODO: make upper layers use standard alpha
- if (getCairoFormat(rBuf) == CAIRO_FORMAT_A1)
- {
- const int nImageSize = rBuf.mnHeight * rBuf.mnScanlineSize;
- unsigned char* pDst = rBuf.mpBits;
- for (int i = nImageSize; --i >= 0; ++pDst)
- *pDst = ~*pDst;
- }
-}
-
namespace
{
// check for env var that decides for using downscale pattern
diff --git a/vcl/inc/bitmap/ScanlineTools.hxx b/vcl/inc/bitmap/ScanlineTools.hxx
index c343cf34f61e..99ce5dc33aae 100644
--- a/vcl/inc/bitmap/ScanlineTools.hxx
+++ b/vcl/inc/bitmap/ScanlineTools.hxx
@@ -39,14 +39,14 @@ public:
virtual Color readPixel() override
{
- const Color aColor(ColorTransparency, pData[4], pData[1], pData[2], pData[3]);
+ const Color aColor(ColorAlpha, pData[4], pData[1], pData[2], pData[3]);
pData += 4;
return aColor;
}
virtual void writePixel(Color nColor) override
{
- *pData++ = 255 - nColor.GetAlpha();
+ *pData++ = nColor.GetAlpha();
*pData++ = nColor.GetRed();
*pData++ = nColor.GetGreen();
*pData++ = nColor.GetBlue();
diff --git a/vcl/inc/headless/BitmapHelper.hxx b/vcl/inc/headless/BitmapHelper.hxx
index dbd7e86675e3..2b6598464703 100644
--- a/vcl/inc/headless/BitmapHelper.hxx
+++ b/vcl/inc/headless/BitmapHelper.hxx
@@ -39,9 +39,6 @@ public:
class VCL_DLLPUBLIC MaskHelper : public SurfaceHelper
{
-private:
- std::unique_ptr<unsigned char[]> pAlphaBits;
-
public:
explicit MaskHelper(const SalBitmap& rAlphaBitmap);
};
diff --git a/vcl/inc/headless/CairoCommon.hxx b/vcl/inc/headless/CairoCommon.hxx
index ea07e798b74b..8402e38b1d59 100644
--- a/vcl/inc/headless/CairoCommon.hxx
+++ b/vcl/inc/headless/CairoCommon.hxx
@@ -111,8 +111,6 @@ VCL_DLLPUBLIC cairo_format_t getCairoFormat(const BitmapBuffer& rBuffer);
VCL_DLLPUBLIC std::unique_ptr<BitmapBuffer>
FastConvert24BitRgbTo32BitCairo(const BitmapBuffer* pSrc);
-VCL_DLLPUBLIC void Toggle1BitTransparency(const BitmapBuffer& rBuf);
-
enum class PaintMode
{
Over,
diff --git a/vcl/qa/cppunit/BackendTest.cxx b/vcl/qa/cppunit/BackendTest.cxx
index 2c85be06e66d..e5013d244335 100644
--- a/vcl/qa/cppunit/BackendTest.cxx
+++ b/vcl/qa/cppunit/BackendTest.cxx
@@ -1181,7 +1181,7 @@ public:
device->Erase();
alpha.Erase(255); // transparent
BitmapWriteAccess* alphaWrite = alpha.AcquireAlphaWriteAccess();
- alphaWrite->SetPixelIndex(0, 0, 0); // opaque
+ alphaWrite->SetPixelIndex(0, 0, 255); // opaque
alpha.ReleaseAccess(alphaWrite);
device->DrawBitmapEx(Point(2, 2), BitmapEx(bitmap, alpha));
exportDevice("blend_extended_04.png", device);
diff --git a/vcl/qa/cppunit/BitmapExTest.cxx b/vcl/qa/cppunit/BitmapExTest.cxx
index a0a6b3096f53..a8f1e5a9cda5 100644
--- a/vcl/qa/cppunit/BitmapExTest.cxx
+++ b/vcl/qa/cppunit/BitmapExTest.cxx
@@ -47,8 +47,7 @@ void BitmapExTest::testGetPixelColor24_8()
BitmapEx aBitmapEx(aBitmap, aMask);
- CPPUNIT_ASSERT_EQUAL(Color(ColorTransparency, 0xAA, 0x00, 0xFF, 0x00),
- aBitmapEx.GetPixelColor(0, 0));
+ CPPUNIT_ASSERT_EQUAL(Color(ColorAlpha, 0xAA, 0x00, 0xFF, 0x00), aBitmapEx.GetPixelColor(0, 0));
}
void BitmapExTest::testGetPixelColor32()
diff --git a/vcl/qa/cppunit/ScanlineToolsTest.cxx b/vcl/qa/cppunit/ScanlineToolsTest.cxx
index 8b8a9088a1ea..97233f2692af 100644
--- a/vcl/qa/cppunit/ScanlineToolsTest.cxx
+++ b/vcl/qa/cppunit/ScanlineToolsTest.cxx
@@ -42,9 +42,9 @@ void ScanlineToolsTest::ScanlineTransformer_32_ARGB()
pScanlineTransformer->startLine(aScanLine.data());
std::vector<Color> aColors{
- Color(ColorTransparency, 0, 10, 250, 120), Color(ColorTransparency, 50, 30, 230, 110),
- Color(ColorTransparency, 100, 50, 210, 100), Color(ColorTransparency, 150, 70, 190, 90),
- Color(ColorTransparency, 200, 90, 170, 80),
+ Color(ColorAlpha, 255, 10, 250, 120), Color(ColorAlpha, 205, 30, 230, 110),
+ Color(ColorAlpha, 155, 50, 210, 100), Color(ColorAlpha, 105, 70, 190, 90),
+ Color(ColorAlpha, 55, 90, 170, 80),
};
for (Color const& aColor : aColors)
@@ -52,8 +52,8 @@ void ScanlineToolsTest::ScanlineTransformer_32_ARGB()
pScanlineTransformer->writePixel(aColor);
}
- std::vector<sal_uInt8> aExpectedBytes{ 0, 10, 250, 120, 50, 30, 230, 110, 100, 50,
- 210, 100, 150, 70, 190, 90, 200, 90, 170, 80 };
+ std::vector<sal_uInt8> aExpectedBytes{ 255, 10, 250, 120, 205, 30, 230, 110, 155, 50,
+ 210, 100, 105, 70, 190, 90, 55, 90, 170, 80 };
for (size_t i = 0; i < aScanLine.size(); ++i)
{
diff --git a/vcl/qa/cppunit/canvasbitmaptest.cxx b/vcl/qa/cppunit/canvasbitmaptest.cxx
index 27ac06d0d9de..78eb033f90b0 100644
--- a/vcl/qa/cppunit/canvasbitmaptest.cxx
+++ b/vcl/qa/cppunit/canvasbitmaptest.cxx
@@ -672,17 +672,17 @@ void CanvasBitmapTest::runTest()
checkCanvasBitmap( xBmp, "single bitmap", nDepth );
- Bitmap aMask(Size(200,200), vcl::PixelFormat::N8_BPP, &Bitmap::GetGreyPalette(256));
- aMask.Erase(COL_WHITE);
+ AlphaMask aMask(Size(200,200));
+ aMask.Erase(255);
{
BitmapScopedWriteAccess pAcc(aMask);
if( pAcc.get() )
{
- pAcc->SetFillColor(COL_BLACK);
+ pAcc->SetFillColor(COL_ALPHA_OPAQUE);
pAcc->FillRect(tools::Rectangle(0,0,100,100));
- pAcc->SetPixel(0,0,BitmapColor(255));
- pAcc->SetPixel(0,1,BitmapColor(0));
- pAcc->SetPixel(0,2,BitmapColor(255));
+ pAcc->SetPixel(0,0,BitmapColor(0));
+ pAcc->SetPixel(0,1,BitmapColor(255));
+ pAcc->SetPixel(0,2,BitmapColor(0));
}
}
@@ -691,16 +691,16 @@ void CanvasBitmapTest::runTest()
checkCanvasBitmap( xBmp, "masked bitmap", nDepth );
AlphaMask aAlpha(Size(200,200));
- aAlpha.Erase(255);
+ aAlpha.Erase(0);
{
BitmapWriteAccess* pAcc = aAlpha.AcquireWriteAccess();
if( pAcc )
{
- pAcc->SetFillColor(COL_BLACK);
+ pAcc->SetFillColor(COL_ALPHA_OPAQUE);
pAcc->FillRect(tools::Rectangle(0,0,100,100));
- pAcc->SetPixel(0,0,BitmapColor(255));
- pAcc->SetPixel(0,1,BitmapColor(0));
- pAcc->SetPixel(0,2,BitmapColor(255));
+ pAcc->SetPixel(0,0,BitmapColor(0));
+ pAcc->SetPixel(0,1,BitmapColor(255));
+ pAcc->SetPixel(0,2,BitmapColor(0));
aAlpha.ReleaseAccess(pAcc);
}
}
@@ -762,15 +762,15 @@ void CanvasBitmapTest::runTest()
CPPUNIT_ASSERT_EQUAL_MESSAGE("(0,0) incorrect content",
BitmapColor(0,1,0), pBmpAcc->GetPixel(0,0));
CPPUNIT_ASSERT_EQUAL_MESSAGE("(0,0) incorrect alpha content",
- BitmapColor(255), pAlphaAcc->GetPixel(0,0));
+ BitmapColor(0), pAlphaAcc->GetPixel(0,0));
CPPUNIT_ASSERT_EQUAL_MESSAGE("(2,2) incorrect content",
BitmapColor(0,3,2), pBmpAcc->GetPixel(2,2));
CPPUNIT_ASSERT_EQUAL_MESSAGE("(2,2) incorrect alpha content",
- BitmapColor(253), pAlphaAcc->GetPixel(2,2));
+ BitmapColor(2), pAlphaAcc->GetPixel(2,2));
CPPUNIT_ASSERT_EQUAL_MESSAGE("(9,2) incorrect content",
BitmapColor(0,3,9), pBmpAcc->GetPixel(2,9));
CPPUNIT_ASSERT_EQUAL_MESSAGE("(9,2) correct alpha content",
- BitmapColor(253), pAlphaAcc->GetPixel(2,9));
+ BitmapColor(2), pAlphaAcc->GetPixel(2,9));
aBitmapAlpha.ReleaseAccess(pAlphaAcc);
Bitmap::ReleaseAccess(pBmpAcc);
diff --git a/vcl/qa/cppunit/png/PngFilterTest.cxx b/vcl/qa/cppunit/png/PngFilterTest.cxx
index 760e12f8b3fc..8e9c15e6dd49 100644
--- a/vcl/qa/cppunit/png/PngFilterTest.cxx
+++ b/vcl/qa/cppunit/png/PngFilterTest.cxx
@@ -325,22 +325,22 @@ void PngFilterTest::testPng()
CPPUNIT_ASSERT_EQUAL(tools::Long(4), pAlphaAccess->Width());
CPPUNIT_ASSERT_EQUAL(tools::Long(4), pAlphaAccess->Height());
- CPPUNIT_ASSERT_EQUAL(BitmapColor(ColorTransparency, 0x00, 0x00, 0x80, 0x00),
+ CPPUNIT_ASSERT_EQUAL(BitmapColor(ColorTransparency, 0x00, 0x00, 0x7F, 0x00),
pAlphaAccess->GetPixel(0, 0));
- CPPUNIT_ASSERT_EQUAL(BitmapColor(ColorTransparency, 0x00, 0x00, 0x80, 0x00),
+ CPPUNIT_ASSERT_EQUAL(BitmapColor(ColorTransparency, 0x00, 0x00, 0x7F, 0x00),
pAlphaAccess->GetPixel(3, 3));
- CPPUNIT_ASSERT_EQUAL(BitmapColor(ColorTransparency, 0x00, 0x00, 0x80, 0x00),
+ CPPUNIT_ASSERT_EQUAL(BitmapColor(ColorTransparency, 0x00, 0x00, 0x7F, 0x00),
pAlphaAccess->GetPixel(3, 0));
- CPPUNIT_ASSERT_EQUAL(BitmapColor(ColorTransparency, 0x00, 0x00, 0x80, 0x00),
+ CPPUNIT_ASSERT_EQUAL(BitmapColor(ColorTransparency, 0x00, 0x00, 0x7F, 0x00),
pAlphaAccess->GetPixel(0, 3));
- CPPUNIT_ASSERT_EQUAL(BitmapColor(ColorTransparency, 0x00, 0x00, 0x40, 0x00),
+ CPPUNIT_ASSERT_EQUAL(BitmapColor(ColorTransparency, 0x00, 0x00, 0xBF, 0x00),
pAlphaAccess->GetPixel(1, 1));
- CPPUNIT_ASSERT_EQUAL(BitmapColor(ColorTransparency, 0x00, 0x00, 0xC0, 0x00),
+ CPPUNIT_ASSERT_EQUAL(BitmapColor(ColorTransparency, 0x00, 0x00, 0x3F, 0x00),
pAlphaAccess->GetPixel(1, 2));
- CPPUNIT_ASSERT_EQUAL(BitmapColor(ColorTransparency, 0x00, 0x00, 0xC0, 0x00),
+ CPPUNIT_ASSERT_EQUAL(BitmapColor(ColorTransparency, 0x00, 0x00, 0x3F, 0x00),
pAlphaAccess->GetPixel(2, 1));
- CPPUNIT_ASSERT_EQUAL(BitmapColor(ColorTransparency, 0x00, 0x00, 0x40, 0x00),
+ CPPUNIT_ASSERT_EQUAL(BitmapColor(ColorTransparency, 0x00, 0x00, 0xBF, 0x00),
pAlphaAccess->GetPixel(2, 2));
}
}
@@ -1887,15 +1887,14 @@ void PngFilterTest::testPngRoundtrip24_8()
{
BitmapScopedWriteAccess pWriteAccessBitmap(aBitmap);
AlphaScopedWriteAccess pWriteAccessAlpha(aAlpha);
- pWriteAccessAlpha->Erase(Color(ColorTransparency, 0x00, 0xAA, 0xAA, 0xAA));
+ pWriteAccessAlpha->Erase(Color(0xAA, 0xAA, 0xAA));
pWriteAccessBitmap->Erase(COL_BLACK);
for (int i = 0; i < 8; ++i)
{
for (int j = 0; j < 8; ++j)
{
pWriteAccessBitmap->SetPixel(i, j, COL_LIGHTRED);
- pWriteAccessAlpha->SetPixel(i, j,
- Color(ColorTransparency, 0x00, 0xBB, 0xBB, 0xBB));
+ pWriteAccessAlpha->SetPixel(i, j, Color(0xBB, 0xBB, 0xBB));
}
}
for (int i = 8; i < 16; ++i)
@@ -1903,8 +1902,7 @@ void PngFilterTest::testPngRoundtrip24_8()
for (int j = 8; j < 16; ++j)
{
pWriteAccessBitmap->SetPixel(i, j, COL_LIGHTBLUE);
- pWriteAccessAlpha->SetPixel(i, j,
- Color(ColorTransparency, 0x00, 0xCC, 0xCC, 0xCC));
+ pWriteAccessAlpha->SetPixel(i, j, Color(0xCC, 0xCC, 0xCC));
}
}
}
@@ -1922,13 +1920,13 @@ void PngFilterTest::testPngRoundtrip24_8()
CPPUNIT_ASSERT_EQUAL(Size(16, 16), aBitmapEx.GetSizePixel());
- CPPUNIT_ASSERT_EQUAL(Color(ColorTransparency, 0xBB, 0xFF, 0x00, 0x00),
+ CPPUNIT_ASSERT_EQUAL(Color(ColorAlpha, 0xBB, 0xFF, 0x00, 0x00),
aBitmapEx.GetPixelColor(0, 0));
- CPPUNIT_ASSERT_EQUAL(Color(ColorTransparency, 0xCC, 0x00, 0x00, 0xFF),
+ CPPUNIT_ASSERT_EQUAL(Color(ColorAlpha, 0xCC, 0x00, 0x00, 0xFF),
aBitmapEx.GetPixelColor(15, 15));
- CPPUNIT_ASSERT_EQUAL(Color(ColorTransparency, 0xAA, 0x00, 0x00, 0x00),
+ CPPUNIT_ASSERT_EQUAL(Color(ColorAlpha, 0xAA, 0x00, 0x00, 0x00),
aBitmapEx.GetPixelColor(15, 0));
- CPPUNIT_ASSERT_EQUAL(Color(ColorTransparency, 0xAA, 0x00, 0x00, 0x00),
+ CPPUNIT_ASSERT_EQUAL(Color(ColorAlpha, 0xAA, 0x00, 0x00, 0x00),
aBitmapEx.GetPixelColor(0, 15));
}
}
diff --git a/vcl/qa/cppunit/skia/skia.cxx b/vcl/qa/cppunit/skia/skia.cxx
index 5d81e39f587a..b90b915e17ea 100644
--- a/vcl/qa/cppunit/skia/skia.cxx
+++ b/vcl/qa/cppunit/skia/skia.cxx
@@ -244,7 +244,7 @@ void SkiaTest::testAlphaBlendWith()
skiaAlpha = dynamic_cast<SkiaSalBitmap*>(alpha.ImplGetSalBitmap().get());
CPPUNIT_ASSERT(skiaAlpha->unittestHasEraseColor());
CPPUNIT_ASSERT_EQUAL(vcl::PixelFormat::N8_BPP, alpha.getPixelFormat());
- CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt8>(112),
+ CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt8>(208),
AlphaMask::ScopedReadAccess(alpha)->GetPixelIndex(0, 0));
// Test with images set.
@@ -264,7 +264,7 @@ void SkiaTest::testAlphaBlendWith()
skiaAlpha = dynamic_cast<SkiaSalBitmap*>(alpha.ImplGetSalBitmap().get());
CPPUNIT_ASSERT(skiaAlpha->unittestHasImage());
CPPUNIT_ASSERT_EQUAL(vcl::PixelFormat::N8_BPP, alpha.getPixelFormat());
- CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt8>(112),
+ CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt8>(207),
AlphaMask::ScopedReadAccess(alpha)->GetPixelIndex(0, 0));
// Test with erase color for alpha and image for other bitmap.
@@ -281,7 +281,7 @@ void SkiaTest::testAlphaBlendWith()
skiaAlpha = dynamic_cast<SkiaSalBitmap*>(alpha.ImplGetSalBitmap().get());
CPPUNIT_ASSERT(skiaAlpha->unittestHasImage());
CPPUNIT_ASSERT_EQUAL(vcl::PixelFormat::N8_BPP, alpha.getPixelFormat());
- CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt8>(112),
+ CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt8>(207),
AlphaMask::ScopedReadAccess(alpha)->GetPixelIndex(0, 0));
}
diff --git a/vcl/qa/cppunit/svm/svmtest.cxx b/vcl/qa/cppunit/svm/svmtest.cxx
index fcf863e7664a..5161f4cce960 100644
--- a/vcl/qa/cppunit/svm/svmtest.cxx
+++ b/vcl/qa/cppunit/svm/svmtest.cxx
@@ -26,6 +26,7 @@
#include <vcl/filter/SvmReader.hxx>
#include <vcl/filter/SvmWriter.hxx>
#include <salhelper/simplereferenceobject.hxx>
+#include <sal/log.hxx>
#include <bitmap/BitmapWriteAccess.hxx>
@@ -46,7 +47,7 @@ class SvmTest : public test::BootstrapFixture, public XmlTestTools
return m_directories.getURLFromSrc(maDataUrl) + sFileName;
}
- void checkRendering(ScopedVclPtrInstance<VirtualDevice> const & pVirtualDev, const GDIMetaFile& rMetaFile);
+ void checkRendering(ScopedVclPtrInstance<VirtualDevice> const & pVirtualDev, const GDIMetaFile& rMetaFile, const char * where);
// write GDI Metafile to a file in data directory
// only use this for new tests to create the svm file
@@ -268,7 +269,7 @@ static void setupBaseVirtualDevice(VirtualDevice& rDevice, GDIMetaFile& rMeta)
rDevice.Erase();
}
-void SvmTest::checkRendering(ScopedVclPtrInstance<VirtualDevice> const & pVirtualDev, const GDIMetaFile& rMetaFile)
+void SvmTest::checkRendering(ScopedVclPtrInstance<VirtualDevice> const & pVirtualDev, const GDIMetaFile& rMetaFile, const char * where)
{
BitmapEx aSourceBitmapEx = pVirtualDev->GetBitmapEx(Point(), Size(10, 10));
ScopedVclPtrInstance<VirtualDevice> pVirtualDevResult;
@@ -294,7 +295,7 @@ void SvmTest::checkRendering(ScopedVclPtrInstance<VirtualDevice> const & pVirtua
aPNGWriter.write(aResultBitmapEx);
}
}
- CPPUNIT_ASSERT_EQUAL(aSourceBitmapEx.GetChecksum(), aResultBitmapEx.GetChecksum());
+ CPPUNIT_ASSERT_EQUAL_MESSAGE(where, aSourceBitmapEx.GetChecksum(), aResultBitmapEx.GetChecksum());
}
static GDIMetaFile readMetafile(const OUString& rUrl)
@@ -989,12 +990,12 @@ void SvmTest::testBitmaps()
{
GDIMetaFile aReloadedGDIMetaFile = writeAndReadStream(aGDIMetaFile);
checkBitmaps(aReloadedGDIMetaFile);
- checkRendering(pVirtualDev, aReloadedGDIMetaFile);
+ checkRendering(pVirtualDev, aReloadedGDIMetaFile, SAL_WHERE);
}
{
GDIMetaFile aFileGDIMetaFile = readFile(u"bitmaps.svm");
checkBitmaps(aFileGDIMetaFile);
- checkRendering(pVirtualDev, aFileGDIMetaFile);
+ checkRendering(pVirtualDev, aFileGDIMetaFile, SAL_WHERE);
}
}
@@ -1005,7 +1006,7 @@ void SvmTest::checkBitmapExs(const GDIMetaFile& rMetaFile, bool bIsSvmFile)
if (SkiaHelper::isVCLSkiaEnabled())
return; // TODO SKIA using CRCs is broken (the idea of it)
- std::array<OUString, 8> aExpectedCRC
+ static const std::vector<OUString> aExpectedCRC
{
#if defined OSL_BIGENDIAN
"08feb5d3",
@@ -1028,7 +1029,7 @@ void SvmTest::checkBitmapExs(const GDIMetaFile& rMetaFile, bool bIsSvmFile)
#endif
};
- std::array<OUString, 8> aExpectedContentChecksum
+ static const std::array<OUString, 8> aExpectedContentChecksum
{
"26bdebd04e5b18d685cea04982179e273ee3b659",
"f4f52df6ef965a2f0fbccbe6aca35ba3457cf9d5",
@@ -1126,7 +1127,7 @@ void SvmTest::testBitmapExs()
pAccess->Erase(COL_MAGENTA);
AlphaScopedWriteAccess pAlphaAccess(aAlpha);
- pAlphaAccess->Erase(Color(128, 128, 128));
+ pAlphaAccess->Erase(Color(127, 127, 127));
}
pVirtualDev->DrawBitmapEx(Point(6, 6), BitmapEx(aBitmap, aAlpha));
}
@@ -1178,12 +1179,12 @@ void SvmTest::testBitmapExs()
{
GDIMetaFile aReloadedGDIMetaFile = writeAndReadStream(aGDIMetaFile);
checkBitmapExs(aReloadedGDIMetaFile, /*bIsSvmFile*/false);
- checkRendering(pVirtualDev, aReloadedGDIMetaFile);
+ checkRendering(pVirtualDev, aReloadedGDIMetaFile, SAL_WHERE);
}
{
GDIMetaFile aFileGDIMetaFile = readFile(u"bitmapexs.svm");
checkBitmapExs(aFileGDIMetaFile, /*bIsSvmFile*/true);
- checkRendering(pVirtualDev, aFileGDIMetaFile);
+ checkRendering(pVirtualDev, aFileGDIMetaFile, SAL_WHERE);
}
}
diff --git a/vcl/qt5/QtGraphics_GDI.cxx b/vcl/qt5/QtGraphics_GDI.cxx
index 28bab34a7cca..70c598c8bcd9 100644
--- a/vcl/qt5/QtGraphics_GDI.cxx
+++ b/vcl/qt5/QtGraphics_GDI.cxx
@@ -597,7 +597,6 @@ static QImage getAlphaImage(const SalBitmap& rSourceBitmap, const SalBitmap& rAl
assert(rAlphaBitmap.GetBitCount() == 8 || rAlphaBitmap.GetBitCount() == 1);
QImage aAlphaMask = *static_cast<const QtBitmap*>(&rAlphaBitmap)->GetQImage();
- aAlphaMask.invertPixels();
const QImage* pBitmap = static_cast<const QtBitmap*>(&rSourceBitmap)->GetQImage();
QImage aImage = pBitmap->convertToFormat(Qt_DefaultFormat32);
diff --git a/vcl/quartz/cgutils.mm b/vcl/quartz/cgutils.mm
index c28391c48395..c6a490d44885 100644
--- a/vcl/quartz/cgutils.mm
+++ b/vcl/quartz/cgutils.mm
@@ -41,27 +41,38 @@ CGImageRef CreateWithSalBitmapAndMask( const SalBitmap& rBitmap, const SalBitmap
if( !xMask )
return xImage;
- // CGImageCreateWithMask() only likes masks or greyscale images => convert if needed
- // TODO: isolate in an extra method?
- if( !CGImageIsMask(xMask) || rMask.GetBitCount() != 8)//(CGImageGetColorSpace(xMask) != GetSalData()->mxGraySpace) )
+ // If xMask is an image (i.e. not a mask), it must be greyscale - a requirement of the
+ // CGImageCreateWithMask() function.
+ if( !CGImageIsMask(xMask) && CGImageGetColorSpace(xMask) != GetSalData()->mxGraySpace )
{
- const CGRect xImageRect=CGRectMake( 0, 0, nWidth, nHeight );//the rect has no offset
+ CGImageRef xGrayMask = CGImageCreateCopyWithColorSpace(xMask, GetSalData()->mxGraySpace);
+ if (xGrayMask)
+ {
+ CFRelease(xMask);
+ xMask = xGrayMask;
+ }
+ else
+ {
+ // Many gallery images will fail to be converted to a grayscale
+ // colorspace so fall back to old mask creation code
+ const CGRect xImageRect=CGRectMake( 0, 0, nWidth, nHeight );//the rect has no offset
- // create the alpha mask image fitting our image
- // TODO: is caching the full mask or the subimage mask worth it?
- int nMaskBytesPerRow = ((nWidth + 3) & ~3);
- void* pMaskMem = std::malloc( nMaskBytesPerRow * nHeight );
- CGContextRef xMaskContext = CGBitmapContextCreate( pMaskMem,
- nWidth, nHeight, 8, nMaskBytesPerRow, GetSalData()->mxGraySpace, kCGImageAlphaNone );
- CGContextDrawImage( xMaskContext, xImageRect, xMask );
- CFRelease( xMask );
- CGDataProviderRef xDataProvider( CGDataProviderCreateWithData( nullptr,
- pMaskMem, nHeight * nMaskBytesPerRow, &CFRTLFree ) );
+ // create the alpha mask image fitting our image
+ // TODO: is caching the full mask or the subimage mask worth it?
+ int nMaskBytesPerRow = ((nWidth + 3) & ~3);
+ void* pMaskMem = std::malloc( nMaskBytesPerRow * nHeight );
+ CGContextRef xMaskContext = CGBitmapContextCreate( pMaskMem,
+ nWidth, nHeight, 8, nMaskBytesPerRow, GetSalData()->mxGraySpace, kCGImageAlphaNone );
+ CGContextDrawImage( xMaskContext, xImageRect, xMask );
+ CFRelease( xMask );
+ CGDataProviderRef xDataProvider( CGDataProviderCreateWithData( nullptr,
+ pMaskMem, nHeight * nMaskBytesPerRow, &CFRTLFree ) );
- static const CGFloat* pDecode = nullptr;
- xMask = CGImageMaskCreate( nWidth, nHeight, 8, 8, nMaskBytesPerRow, xDataProvider, pDecode, false );
- CFRelease( xDataProvider );
- CFRelease( xMaskContext );
+ static const CGFloat* pDecode = nullptr;
+ xMask = CGImageMaskCreate( nWidth, nHeight, 8, 8, nMaskBytesPerRow, xDataProvider, pDecode, false );
+ CFRelease( xDataProvider );
+ CFRelease( xMaskContext );
+ }
}
if( !xMask )
diff --git a/vcl/skia/gdiimpl.cxx b/vcl/skia/gdiimpl.cxx
index 40341bba85f7..e6c373c2f86b 100644
--- a/vcl/skia/gdiimpl.cxx
+++ b/vcl/skia/gdiimpl.cxx
@@ -1272,23 +1272,19 @@ bool SkiaSalGraphicsImpl::blendBitmap(const SalTwoRect& rPosAry, const SalBitmap
assert(dynamic_cast<const SkiaSalBitmap*>(&rBitmap));
const SkiaSalBitmap& rSkiaBitmap = static_cast<const SkiaSalBitmap&>(rBitmap);
- // This is used by VirtualDevice in the alpha mode for the "alpha" layer which
- // is actually one-minus-alpha (opacity). Therefore white=0xff=transparent,
- // black=0x00=opaque. So the result is transparent only if both the inputs
- // are transparent. Since for blending operations white=1.0 and black=0.0,
- // kMultiply should handle exactly that (transparent*transparent=transparent,
- // opaque*transparent=opaque). And guessing from the "floor" in TYPE_BLEND in opengl's
- // combinedTextureFragmentShader.glsl, the layer is not even alpha values but
- // simply yes-or-no mask.
+ // This is used by VirtualDevice in the alpha mode for the "alpha" layer
+ // So the result is transparent only if both the inputs
+ // are transparent. Which seems to be what SkBlendMode::kModulate does,
+ // so use that.
// See also blendAlphaBitmap().
if (rSkiaBitmap.IsFullyOpaqueAsAlpha())
{
- // Optimization. If the bitmap means fully opaque, it's all zero's. In CPU
+ // Optimization. If the bitmap means fully opaque, it's all one's. In CPU
// mode it should be faster to just copy instead of SkBlendMode::kMultiply.
drawBitmap(rPosAry, rSkiaBitmap);
}
else
- drawBitmap(rPosAry, rSkiaBitmap, SkBlendMode::kMultiply);
+ drawBitmap(rPosAry, rSkiaBitmap, SkBlendMode::kModulate);
return true;
}
@@ -1337,10 +1333,10 @@ bool SkiaSalGraphicsImpl::blendAlphaBitmap(const SalTwoRect& rPosAry,
// First do the "( 1 - alpha ) * mask"
// (no idea how to do "floor", but hopefully not needed in practice).
sk_sp<SkShader> shaderAlpha
- = SkShaders::Blend(SkBlendMode::kDstOut, rSkiaMaskBitmap.GetAlphaSkShader(samplingOptions),
+ = SkShaders::Blend(SkBlendMode::kDstIn, rSkiaMaskBitmap.GetAlphaSkShader(samplingOptions),
rSkiaAlphaBitmap.GetAlphaSkShader(samplingOptions));
// And now draw the bitmap with "1 - x", where x is the "( 1 - alpha ) * mask".
- sk_sp<SkShader> shader = SkShaders::Blend(SkBlendMode::kSrcOut, shaderAlpha,
+ sk_sp<SkShader> shader = SkShaders::Blend(SkBlendMode::kSrcIn, shaderAlpha,
rSkiaSourceBitmap.GetSkShader(samplingOptions));
drawShader(rPosAry, shader);
return true;
@@ -1368,9 +1364,12 @@ void SkiaSalGraphicsImpl::drawMask(const SalTwoRect& rPosAry, const SalBitmap& r
{
assert(dynamic_cast<const SkiaSalBitmap*>(&rSalBitmap));
const SkiaSalBitmap& skiaBitmap = static_cast<const SkiaSalBitmap&>(rSalBitmap);
+ // SkBlendMode::kDstOut must be used instead of SkBlendMode::kDstIn because
+ // the alpha channel of what is drawn appears to get inverted at some point
+ // after it is drawn
drawShader(
rPosAry,
- SkShaders::Blend(SkBlendMode::kDstOut, // VCL alpha is one-minus-alpha.
+ SkShaders::Blend(SkBlendMode::kDstOut, // VCL alpha is alpha.
SkShaders::Color(toSkColor(nMaskColor)),
skiaBitmap.GetAlphaSkShader(makeSamplingOptions(rPosAry, mScaling))));
}
@@ -1680,7 +1679,7 @@ sk_sp<SkImage> SkiaSalGraphicsImpl::mergeCacheBitmaps(const SkiaSalBitmap& bitma
{
canvas->clear(SK_ColorTRANSPARENT);
paint.setShader(
- SkShaders::Blend(SkBlendMode::kDstOut, bitmap.GetSkShader(samplingOptions, bitmapType),
+ SkShaders::Blend(SkBlendMode::kDstIn, bitmap.GetSkShader(samplingOptions, bitmapType),
alphaBitmap->GetAlphaSkShader(samplingOptions, alphaBitmapType)));
canvas->drawPaint(paint);
}
@@ -1742,7 +1741,7 @@ bool SkiaSalGraphicsImpl::drawAlphaBitmap(const SalTwoRect& rPosAry, const SalBi
else
drawShader(rPosAry,
SkShaders::Blend(
- SkBlendMode::kDstOut, // VCL alpha is one-minus-alpha.
+ SkBlendMode::kDstIn,
rSkiaSourceBitmap.GetSkShader(makeSamplingOptions(rPosAry, mScaling)),
rSkiaAlphaBitmap.GetAlphaSkShader(makeSamplingOptions(rPosAry, mScaling))));
return true;
@@ -1965,7 +1964,7 @@ bool SkiaSalGraphicsImpl::drawTransformedBitmap(const basegfx::B2DPoint& rNull,
if (pSkiaAlphaBitmap)
{
SkPaint paint = makeBitmapPaint();
- paint.setShader(SkShaders::Blend(SkBlendMode::kDstOut, // VCL alpha is one-minus-alpha.
+ paint.setShader(SkShaders::Blend(SkBlendMode::kDstIn,
rSkiaBitmap.GetSkShader(samplingOptions),
pSkiaAlphaBitmap->GetAlphaSkShader(samplingOptions)));
if (fAlpha != 1.0)
diff --git a/vcl/skia/salbmp.cxx b/vcl/skia/salbmp.cxx
index 778917b6db0e..5a514aebb05d 100644
--- a/vcl/skia/salbmp.cxx
+++ b/vcl/skia/salbmp.cxx
@@ -617,7 +617,12 @@ bool SkiaSalBitmap::AlphaBlendWith(const SalBitmap& rSalBmp)
SkPaint paint;
paint.setBlendMode(SkBlendMode::kSrc); // set as is
surface->getCanvas()->drawImage(GetSkImage(), 0, 0, SkSamplingOptions(), &paint);
- paint.setBlendMode(SkBlendMode::kScreen); // src+dest - src*dest/255 (in 0..1)
+ // in the 0..1 range that skia uses, the equation we want is:
+ // r = 1 - ((1 - src) + (1 - dest) - (1 - src) * (1 - dest))
+ // which simplifies to:
+ // r = src * dest
+ // which is SkBlendMode::kModulate
+ paint.setBlendMode(SkBlendMode::kModulate);
surface->getCanvas()->drawImage(otherBitmap->GetSkImage(), 0, 0, SkSamplingOptions(), &paint);
ResetToSkImage(makeCheckedImageSnapshot(surface));
DataChanged();
@@ -640,8 +645,10 @@ bool SkiaSalBitmap::Invert()
surface->getCanvas()->clear(SK_ColorWHITE);
SkPaint paint;
paint.setBlendMode(SkBlendMode::kDifference);
- surface->getCanvas()->drawImage(
- mImage, 0, 0, SkSamplingOptions(SkFilterMode::kLinear, SkMipmapMode::kLinear), &paint);
+ // Drawing the image does not work so create a shader from the image
+ paint.setShader(GetSkShader(SkSamplingOptions(SkSamplingOptions())));
+ surface->getCanvas()->drawRect(SkRect::MakeXYWH(0, 0, mSize.Width(), mSize.Height()),
+ paint);
ResetToSkImage(makeCheckedImageSnapshot(surface));
DataChanged();
SAL_INFO("vcl.skia.trace", "invert(" << this << ")");
@@ -746,11 +753,8 @@ SkBitmap SkiaSalBitmap::GetAsSkBitmap() const
}
// If mEraseColor is set, this is the color to use when the bitmap is used as alpha bitmap.
-// E.g. COL_BLACK actually means fully opaque and COL_WHITE means fully transparent.
+// E.g. COL_BLACK actually means fully transparent and COL_WHITE means fully opaque.
// This is because the alpha value is set as the color itself, not the alpha of the color.
-// Additionally VCL actually uses transparency and not opacity, so we should use "255 - value",
-// but we account for this by doing SkBlendMode::kDstOut when using alpha images (which
-// basically does another "255 - alpha"), so do not do it here.
static SkColor fromEraseColorToAlphaImageColor(Color color)
{
return SkColorSetARGB(color.GetBlue(), 0, 0, 0);
@@ -1053,9 +1057,7 @@ bool SkiaSalBitmap::IsFullyOpaqueAsAlpha() const
return false;
// If the erase color is set so that this bitmap used as alpha would
// mean a fully opaque alpha mask (= noop), we can skip using it.
- // Note that for alpha bitmaps we use the VCL "transparency" convention,
- // i.e. alpha 0 is opaque.
- return SkColorGetA(fromEraseColorToAlphaImageColor(mEraseColor)) == 0;
+ return SkColorGetA(fromEraseColorToAlphaImageColor(mEraseColor)) == 255;
}
SkAlphaType SkiaSalBitmap::alphaType() const
@@ -1080,7 +1082,7 @@ void SkiaSalBitmap::PerformErase()
abort();
Color fastColor = mEraseColor;
if (!!mPalette)
- fastColor = Color(ColorTransparency, mPalette.GetBestIndex(fastColor));
+ fastColor = Color(ColorAlpha, mPalette.GetBestIndex(fastColor));
if (!ImplFastEraseBitmap(*bitmapBuffer, fastColor))
{
FncSetPixel setPixel = BitmapReadAccess::SetPixelFunction(bitmapBuffer->mnFormat);
@@ -1406,7 +1408,7 @@ OString SkiaSalBitmap::GetAlphaImageKey(DirectImage direct) const
{
std::stringstream ss;
ss << std::hex << std::setfill('0') << std::setw(2)
- << static_cast<int>(255 - SkColorGetA(fromEraseColorToAlphaImageColor(mEraseColor)));
+ << static_cast<int>(SkColorGetA(fromEraseColorToAlphaImageColor(mEraseColor)));
return OString::Concat("E") + ss.str().c_str();
}
assert(direct == DirectImage::No || mAlphaImage);
diff --git a/vcl/source/bitmap/BitmapAlphaClampFilter.cxx b/vcl/source/bitmap/BitmapAlphaClampFilter.cxx
index eb3245e2347c..820bdbdde34b 100644
--- a/vcl/source/bitmap/BitmapAlphaClampFilter.cxx
+++ b/vcl/source/bitmap/BitmapAlphaClampFilter.cxx
@@ -30,9 +30,9 @@ BitmapEx BitmapAlphaClampFilter::execute(BitmapEx const& rBitmapEx) const
for (sal_Int32 nX = 0; nX < sal_Int32(aSize.Width()); ++nX)
{
BitmapColor aBitmapAlphaValue(pWriteAlpha->GetPixelFromData(pScanAlpha, nX));
- if (aBitmapAlphaValue.GetIndex() > mcThreshold)
+ if ((255 - aBitmapAlphaValue.GetIndex()) > mcThreshold)
{
- aBitmapAlphaValue.SetIndex(255);
+ aBitmapAlphaValue.SetIndex(0);
pWriteAlpha->SetPixelOnData(pScanAlpha, nX, aBitmapAlphaValue);
}
}
diff --git a/vcl/source/bitmap/BitmapEx.cxx b/vcl/source/bitmap/BitmapEx.cxx
index ad4adca6319e..c9be55521f16 100644
--- a/vcl/source/bitmap/BitmapEx.cxx
+++ b/vcl/source/bitmap/BitmapEx.cxx
@@ -113,12 +113,20 @@ BitmapEx::BitmapEx( const Bitmap& rBmp, const Bitmap& rMask ) :
if (rMask.IsEmpty())
return;
+ assert(typeid(rMask) != typeid(AlphaMask)
+ && "If this mask is actually an AlphaMask, then it will be inverted unnecessarily "
+ "and the alpha channel will be wrong");
+
if( rMask.getPixelFormat() == vcl::PixelFormat::N8_BPP && rMask.HasGreyPalette8Bit() )
+ {
maAlphaMask = rMask;
+ maAlphaMask.Invert();
+ }
else if( rMask.getPixelFormat() == vcl::PixelFormat::N8_BPP )
{
BitmapEx aMaskEx(rMask);
BitmapFilter::Filter(aMaskEx, BitmapMonochromeFilter(255));
+ aMaskEx.Invert();
maAlphaMask = aMaskEx.GetBitmap();
}
else
@@ -127,6 +135,7 @@ BitmapEx::BitmapEx( const Bitmap& rBmp, const Bitmap& rMask ) :
SAL_WARN( "vcl", "BitmapEx: forced mask to monochrome");
BitmapEx aMaskEx(rMask);
BitmapFilter::Filter(aMaskEx, BitmapMonochromeFilter(255));
+ aMaskEx.Invert();
maAlphaMask = aMaskEx.GetBitmap();
}
@@ -154,7 +163,7 @@ BitmapEx::BitmapEx( const Bitmap& rBmp, const Color& rTransparentColor ) :
maBitmap ( rBmp ),
maBitmapSize ( maBitmap.GetSizePixel() )
{
- maAlphaMask = maBitmap.CreateMask( rTransparentColor );
+ maAlphaMask = maBitmap.CreateAlphaMask( rTransparentColor );
SAL_WARN_IF(rBmp.GetSizePixel() != maAlphaMask.GetSizePixel(), "vcl",
"BitmapEx::BitmapEx(): size mismatch for bitmap and alpha mask.");
@@ -332,14 +341,14 @@ bool BitmapEx::Rotate( Degree10 nAngle10, const Color& rFillColor )
}
if( bRet && !maAlphaMask.IsEmpty() )
- maAlphaMask.Rotate( nAngle10, COL_WHITE );
+ maAlphaMask.Rotate( nAngle10, COL_ALPHA_TRANSPARENT );
}
else
{
bRet = maBitmap.Rotate( nAngle10, rFillColor );
if( bRet && !maAlphaMask.IsEmpty() )
- maAlphaMask.Rotate( nAngle10, COL_WHITE );
+ maAlphaMask.Rotate( nAngle10, COL_ALPHA_TRANSPARENT );
}
SetSizePixel(maBitmap.GetSizePixel());
@@ -387,7 +396,7 @@ void BitmapEx::Expand( sal_Int32 nDX, sal_Int32 nDY, bool bExpandTransparent )
if( bRet && !maAlphaMask.IsEmpty() )
{
- Color aColor( bExpandTransparent ? COL_WHITE : COL_BLACK );
+ Color aColor( bExpandTransparent ? COL_ALPHA_TRANSPARENT : COL_ALPHA_OPAQUE );
maAlphaMask.Expand( nDX, nDY, &aColor );
}
@@ -427,8 +436,8 @@ bool BitmapEx::CopyPixel( const tools::Rectangle& rRectDst, const tools::Rectang
maAlphaMask.CopyPixel_AlphaOptimized( rRectDst, rRectSrc, &pBmpExSrc->maAlphaMask );
else
{
- sal_uInt8 cBlack = 0;
- std::optional<AlphaMask> pAlpha(std::in_place, GetSizePixel(), &cBlack);
+ sal_uInt8 nTransparencyOpaque = 0;
+ std::optional<AlphaMask> pAlpha(std::in_place, GetSizePixel(), &nTransparencyOpaque);
maAlphaMask = pAlpha->ImplGetBitmap();
pAlpha.reset();
@@ -437,8 +446,8 @@ bool BitmapEx::CopyPixel( const tools::Rectangle& rRectDst, const tools::Rectang
}
else if (IsAlpha())
{
- sal_uInt8 cBlack = 0;
- const AlphaMask aAlphaSrc(pBmpExSrc->GetSizePixel(), &cBlack);
+ sal_uInt8 nTransparencyOpaque = 0;
+ const AlphaMask aAlphaSrc(pBmpExSrc->GetSizePixel(), &nTransparencyOpaque);
maAlphaMask.CopyPixel( rRectDst, rRectSrc, &aAlphaSrc.ImplGetBitmap() );
}
@@ -581,7 +590,7 @@ sal_uInt8 BitmapEx::GetAlpha(sal_Int32 nX, sal_Int32 nY) const
if(pRead)
{
const BitmapColor aBitmapColor(pRead->GetPixel(nY, nX));
- nAlpha = 255 - aBitmapColor.GetIndex();
+ nAlpha = aBitmapColor.GetIndex();
}
}
return nAlpha;
@@ -599,7 +608,7 @@ Color BitmapEx::GetPixelColor(sal_Int32 nX, sal_Int32 nY) const
{
AlphaMask aAlpha = GetAlphaMask();
AlphaMask::ScopedReadAccess pAlphaReadAccess(aAlpha);
- aColor.SetAlpha(255 - pAlphaReadAccess->GetPixel(nY, nX).GetIndex());
+ aColor.SetAlpha(pAlphaReadAccess->GetPixel(nY, nX).GetIndex());
}
else if (maBitmap.getPixelFormat() != vcl::PixelFormat::N32_BPP)
{
@@ -1023,6 +1032,8 @@ BitmapEx createBlendFrame(
Color aColorBottomRight,
Color aColorBottomLeft)
{
+ // FIXME the call sites are actually passing in transparency
+ nAlpha = 255 - nAlpha;
BlendFrameCache* pBlendFrameCache = ImplGetBlendFrameCache();
if(pBlendFrameCache->m_aLastSize == rSize
@@ -1368,7 +1379,7 @@ void BitmapEx::ChangeColorAlpha( sal_uInt8 cIndexFrom, sal_Int8 nAlphaTo )
{
const sal_uInt8 cIndex = pReadAccess->GetPixelFromData( pScanlineRead, nX ).GetIndex();
if ( cIndex == cIndexFrom )
- pAlphaWriteAccess->SetPixelOnData( pScanline, nX, BitmapColor(255 - nAlphaTo) );
+ pAlphaWriteAccess->SetPixelOnData( pScanline, nX, BitmapColor(nAlphaTo) );
}
}
*this = BitmapEx( GetBitmap(), aAlphaMask );
@@ -1391,7 +1402,7 @@ void BitmapEx::AdjustTransparency(sal_uInt8 cTrans)
if( !pA )
return;
- sal_uLong nTrans = cTrans, nNewTrans;
+ sal_uLong nTrans = cTrans;
const tools::Long nWidth = pA->Width(), nHeight = pA->Height();
if( pA->GetScanlineFormat() == ScanlineFormat::N8BitPal )
@@ -1402,8 +1413,10 @@ void BitmapEx::AdjustTransparency(sal_uInt8 cTrans)
for( tools::Long nX = 0; nX < nWidth; nX++ )
{
- nNewTrans = nTrans + *pAScan;
- *pAScan++ = static_cast<sal_uInt8>( ( nNewTrans & 0xffffff00 ) ? 255 : nNewTrans );
+ sal_uLong nNewTrans = nTrans + (255 - *pAScan);
+ // clamp to 255
+ nNewTrans = ( nNewTrans & 0xffffff00 ) ? 255 : nNewTrans;
+ *pAScan++ = static_cast<sal_uInt8>( 255 - nNewTrans );
}
}
}
@@ -1416,8 +1429,11 @@ void BitmapEx::AdjustTransparency(sal_uInt8 cTrans)
Scanline pScanline = pA->GetScanline( nY );
for( tools::Long nX = 0; nX < nWidth; nX++ )
{
- nNewTrans = nTrans + pA->GetIndexFromData( pScanline, nX );
- aAlphaValue.SetIndex( static_cast<sal_uInt8>( ( nNewTrans & 0xffffff00 ) ? 255 : nNewTrans ) );
+ sal_uLong nNewTrans = nTrans + (255 - pA->GetIndexFromData( pScanline, nX ));
+ // clamp to 255
+ nNewTrans = ( nNewTrans & 0xffffff00 ) ? 255 : nNewTrans;
+ // convert back to alpha
+ aAlphaValue.SetIndex( static_cast<sal_uInt8>(255 - nNewTrans) );
pA->SetPixelOnData( pScanline, nX, aAlphaValue );
}
}
diff --git a/vcl/source/bitmap/BitmapMaskToAlphaFilter.cxx b/vcl/source/bitmap/BitmapMaskToAlphaFilter.cxx
index c9ec102d933a..c5f1cda1d9cb 100644
--- a/vcl/source/bitmap/BitmapMaskToAlphaFilter.cxx
+++ b/vcl/source/bitmap/BitmapMaskToAlphaFilter.cxx
@@ -14,7 +14,7 @@
#include <bitmap/BitmapMaskToAlphaFilter.hxx>
/**
- * Convert a 1-bit mask to an alpha layer
+ * Convert a 1-bit mask to an alpha bitmap
*/
BitmapEx BitmapMaskToAlphaFilter::execute(BitmapEx const& rBitmapEx) const
{
@@ -38,11 +38,11 @@ BitmapEx BitmapMaskToAlphaFilter::execute(BitmapEx const& rBitmapEx) const
{
BitmapColor aBmpColor = pRead->GetPixelFromData(pScanlineRead, nX);
if (aBmpColor == COL_BLACK)
- aBmpColor = COL_BLACK;
+ aBmpColor = COL_ALPHA_OPAQUE;
else if (aBmpColor == COL_WHITE)
- aBmpColor = COL_WHITE;
+ aBmpColor = COL_ALPHA_TRANSPARENT;
else if (aBmpColor == Color(0, 0, 1))
- aBmpColor = COL_WHITE;
+ aBmpColor = COL_ALPHA_TRANSPARENT;
else
assert(false);
pWrite->SetPixelOnData(pScanline, nX, aBmpColor);
diff --git a/vcl/source/bitmap/BitmapTools.cxx b/vcl/source/bitmap/BitmapTools.cxx
index beec528b2f0e..7caf1f12f328 100644
--- a/vcl/source/bitmap/BitmapTools.cxx
+++ b/vcl/source/bitmap/BitmapTools.cxx
@@ -205,7 +205,8 @@ BitmapEx CreateFromData(sal_uInt8 const *pData, sal_Int32 nWidth, sal_Int32 nHei
Scanline pMaskScanLine = xMaskAcc->GetScanline(y);
for (tools::Long x = 0; x < nWidth; ++x)
{
- const sal_uInt8 nValue = bReverseAlpha ? 0xff - *p : *p;
+ // FIXME this parameter is badly named
+ const sal_uInt8 nValue = bReverseAlpha ? *p : 0xff - *p;
xMaskAcc->SetPixelOnData(pMaskScanLine, x, BitmapColor(nValue));
p += 4;
}
@@ -271,11 +272,15 @@ BitmapEx CreateFromData( RawBitmap&& rawBitmap )
Scanline pMaskScanLine = xMaskAcc->GetScanline(y);
for (tools::Long x = 0; x < nWidth; ++x)
{
- xMaskAcc->SetPixelOnData(pMaskScanLine, x, BitmapColor(255 - *p));
+ xMaskAcc->SetPixelOnData(pMaskScanLine, x, BitmapColor(*p));
p += 4;
}
}
}
+
+ xMaskAcc.reset();
+ pWrite.reset();
+
if (nBitCount == 32)
return BitmapEx(aBmp, *pAlphaMask);
else
@@ -350,7 +355,7 @@ BitmapEx* CreateFromCairoSurface(Size aSize, cairo_surface_t * pSurface)
#endif
}
pRGBWrite->SetPixel( y, x, BitmapColor( nR, nG, nB ) );
- pMaskWrite->SetPixelIndex( y, x, 255 - nAlpha );
+ pMaskWrite->SetPixelIndex( y, x, nAlpha );
pPix++;
}
}
@@ -462,7 +467,7 @@ BitmapEx CanvasTransformBitmap( const BitmapEx& rBitmap,
if( nSrcX < 0 || nSrcX >= aBmpSize.Width() ||
nSrcY < 0 || nSrcY >= aBmpSize.Height() )
{
- pAlphaWriteAccess->SetPixelOnData( pScanAlpha, x, BitmapColor(255) );
+ pAlphaWriteAccess->SetPixelOnData( pScanAlpha, x, BitmapColor(0) );
}
else
{
@@ -486,11 +491,11 @@ BitmapEx CanvasTransformBitmap( const BitmapEx& rBitmap,
if( nSrcX < 0 || nSrcX >= aBmpSize.Width() ||
nSrcY < 0 || nSrcY >= aBmpSize.Height() )
{
- pAlphaWriteAccess->SetPixelOnData( pScanAlpha, x, BitmapColor(255) );
+ pAlphaWriteAccess->SetPixelOnData( pScanAlpha, x, BitmapColor(0) );
}
else
{
- pAlphaWriteAccess->SetPixelOnData( pScanAlpha, x, BitmapColor(0) );
+ pAlphaWriteAccess->SetPixelOnData( pScanAlpha, x, BitmapColor(255) );
pWriteAccess->SetPixelOnData( pScan, x, pReadAccess->GetPixel( nSrcY,
nSrcX ) );
}
@@ -521,6 +526,7 @@ void DrawAlphaBitmapAndAlphaGradient(BitmapEx & rBitmapEx, bool bFixedTransparen
}
{
+
AlphaScopedWriteAccess pOld(aOldMask);
assert(pOld && "Got no access to old alpha mask (!)");
@@ -536,8 +542,8 @@ void DrawAlphaBitmapAndAlphaGradient(BitmapEx & rBitmapEx, bool bFixedTransparen
Scanline pScanline = pOld->GetScanline( y );
for(tools::Long x(0); x < pOld->Width(); x++)
{
- const double fOpOld(1.0 - (pOld->GetIndexFromData(pScanline, x) * fFactor));
- const sal_uInt8 aCol(basegfx::fround((1.0 - (fOpOld * fOpNew)) * 255.0));
+ const double fOpOld(pOld->GetIndexFromData(pScanline, x) * fFactor);
+ const sal_uInt8 aCol(basegfx::fround((fOpOld * fOpNew) * 255.0));
pOld->SetPixelOnData(pScanline, x, BitmapColor(aCol));
}
@@ -557,9 +563,9 @@ void DrawAlphaBitmapAndAlphaGradient(BitmapEx & rBitmapEx, bool bFixedTransparen
Scanline pScanline = pOld->GetScanline( y );
for(tools::Long x(0); x < pOld->Width(); x++)
{
- const double fOpOld(1.0 - (pOld->GetIndexFromData(pScanline, x) * fFactor));
- const double fOpNew(1.0 - (pNew->GetIndexFromData(pScanline, x) * fFactor));
- const sal_uInt8 aCol(basegfx::fround((1.0 - (fOpOld * fOpNew)) * 255.0));
+ const double fOpOld(pOld->GetIndexFromData(pScanline, x) * fFactor);
+ const double fOpNew(pNew->GetIndexFromData(pScanline, x) * fFactor);
+ const sal_uInt8 aCol(basegfx::fround((fOpOld * fOpNew) * 255.0));
pOld->SetPixelOnData(pScanline, x, BitmapColor(aCol));
}
@@ -619,10 +625,9 @@ void DrawAndClipBitmap(const Point& rPos, const Size& rSize, const BitmapEx& rBi
const sal_uInt8 nIndR(pR->GetIndexFromData(pScanlineR, nX));
const sal_uInt8 nIndW(pW->GetIndexFromData(pScanlineW, nX));
- // these values represent transparency (0 == no, 255 == fully transparent),
- // so to blend these we have to multiply the inverse (opacity)
- // and re-invert the result to transparence
- const sal_uInt8 nCombined(0x00ff - (((0x00ff - nIndR) * (0x00ff - nIndW)) >> 8));
+ // these values represent alpha (255 == no, 0 == fully transparent),
+ // so to blend these we have to multiply
+ const sal_uInt8 nCombined((nIndR * nIndW) >> 8);
pW->SetPixelOnData(pScanlineW, nX, BitmapColor(nCombined));
}
@@ -672,7 +677,7 @@ static bool readAlpha( BitmapReadAccess const * pAlphaReadAcc, tools::Long nY, c
BitmapColor const& rColor(
pAlphaReadAcc->GetPaletteColor(*pReadScan));
pReadScan++;
- nAlpha = data[ nOff ] = 255 - rColor.GetIndex();
+ nAlpha = data[ nOff ] = rColor.GetIndex();
if( nAlpha != 255 )
bIsAlpha = true;
nOff += 4;
@@ -682,7 +687,7 @@ static bool readAlpha( BitmapReadAccess const * pAlphaReadAcc, tools::Long nY, c
SAL_INFO( "canvas.cairo", "fallback to GetColor for alpha - slow, format: " << static_cast<int>(pAlphaReadAcc->GetScanlineFormat()) );
for( nX = 0; nX < nWidth; nX++ )
{
- nAlpha = data[ nOff ] = 255 - pAlphaReadAcc->GetColor( nY, nX ).GetIndex();
+ nAlpha = data[ nOff ] = pAlphaReadAcc->GetColor( nY, nX ).GetIndex();
if( nAlpha != 255 )
bIsAlpha = true;
nOff += 4;
@@ -1027,7 +1032,7 @@ void CanvasCairoExtractBitmapData( BitmapEx const & aBmpEx, Bitmap & aBitmap, un
pRes[ nCurrPos++ ] = pReadAccess->GetColor( y, x ).GetRed();
pRes[ nCurrPos++ ] = pReadAccess->GetColor( y, x ).GetGreen();
pRes[ nCurrPos++ ] = pReadAccess->GetColor( y, x ).GetBlue();
- pRes[ nCurrPos++ ] = pAlphaReadAccess->GetIndexFromData( pScanlineReadAlpha, x );
+ pRes[ nCurrPos++ ] = 255 - pAlphaReadAccess->GetIndexFromData( pScanlineReadAlpha, x );
}
}
else
@@ -1217,7 +1222,7 @@ bool convertBitmap32To24Plus8(BitmapEx const & rInput, BitmapEx & rResult)
{
const BitmapColor aColor = pReadAccess->GetPixelFromData(aReadScan, nX);
BitmapColor aResultColor(aColor.GetRed(), aColor.GetGreen(), aColor.GetBlue());
- BitmapColor aResultColorAlpha(255 - aColor.GetAlpha(), 255 - aColor.GetAlpha(), 255 - aColor.GetAlpha());
+ BitmapColor aResultColorAlpha(aColor.GetAlpha(), aColor.GetAlpha(), aColor.GetAlpha());
pResultBitmapAccess->SetPixelOnData(aResultScan, nX, aResultColor);
pResultAlphaAccess->SetPixelOnData(aResultScanAlpha, nX, aResultColorAlpha);
diff --git a/vcl/source/bitmap/alpha.cxx b/vcl/source/bitmap/alpha.cxx
index f307dda63a28..8e082c695137 100644
--- a/vcl/source/bitmap/alpha.cxx
+++ b/vcl/source/bitmap/alpha.cxx
@@ -31,8 +31,11 @@ AlphaMask::AlphaMask() = default;
AlphaMask::AlphaMask( const Bitmap& rBitmap ) :
Bitmap( rBitmap )
{
- if( !rBitmap.IsEmpty() )
+ // no need to do any conversion if it is already an AlphaMask
+ if ( typeid(rBitmap) != typeid(AlphaMask) && !rBitmap.IsEmpty() )
Convert( BmpConversion::N8BitNoConversion );
+ assert( (IsEmpty() || getPixelFormat() == vcl::PixelFormat::N8_BPP) && "alpha bitmap should be 8bpp" );
+ assert( (IsEmpty() || HasGreyPalette8Bit()) && "alpha bitmap should have greyscale palette" );
}
AlphaMask::AlphaMask( const AlphaMask& ) = default;
@@ -43,7 +46,12 @@ AlphaMask::AlphaMask( const Size& rSizePixel, const sal_uInt8* pEraseTransparenc
: Bitmap(rSizePixel, vcl::PixelFormat::N8_BPP, &Bitmap::GetGreyPalette(256))
{
if( pEraseTransparency )
- Bitmap::Erase( Color( *pEraseTransparency, *pEraseTransparency, *pEraseTransparency ) );
+ {
+ sal_uInt8 nAlpha = 255 - *pEraseTransparency;
+ Bitmap::Erase( Color( nAlpha, nAlpha, nAlpha ) );
+ }
+ else
+ Bitmap::Erase( COL_ALPHA_OPAQUE );
}
AlphaMask::~AlphaMask() = default;
@@ -55,6 +63,9 @@ AlphaMask& AlphaMask::operator=( const Bitmap& rBitmap )
if( !rBitmap.IsEmpty() )
Convert( BmpConversion::N8BitNoConversion );
+ assert( getPixelFormat() == vcl::PixelFormat::N8_BPP && "alpha bitmap should be 8bpp" );
+ assert( HasGreyPalette8Bit() && "alpha bitmap should have greyscale palette" );
+
return *this;
}
@@ -70,7 +81,8 @@ Bitmap const & AlphaMask::GetBitmap() const
void AlphaMask::Erase( sal_uInt8 cTransparency )
{
- Bitmap::Erase( Color( cTransparency, cTransparency, cTransparency ) );
+ sal_uInt8 nAlpha = 255 - cTransparency;
+ Bitmap::Erase( Color( nAlpha, nAlpha, nAlpha ) );
}
void AlphaMask::BlendWith(const AlphaMask& rOther)
@@ -79,6 +91,8 @@ void AlphaMask::BlendWith(const AlphaMask& rOther)
if (xImpBmp->Create(*ImplGetSalBitmap()) && xImpBmp->AlphaBlendWith(*rOther.ImplGetSalBitmap()))
{
ImplSetSalBitmap(xImpBmp);
+ assert( getPixelFormat() == vcl::PixelFormat::N8_BPP && "alpha bitmap should be 8bpp" );
+ assert( HasGreyPalette8Bit() && "alpha bitmap should have greyscale palette" );
return;
}
Bitmap::ScopedReadAccess pOtherAcc(const_cast<AlphaMask&>(rOther));
@@ -101,11 +115,18 @@ void AlphaMask::BlendWith(const AlphaMask& rOther)
// Use sal_uInt16 for following multiplication
const sal_uInt16 nGrey1 = *scanline;
const sal_uInt16 nGrey2 = *otherScanline;
- *scanline = static_cast<sal_uInt8>(nGrey1 + nGrey2 - nGrey1 * nGrey2 / 255);
+ // Awkward calculation because the original used transparency, and to replicate
+ // the logic we need to translate into transparency, perform the original logic,
+ // then translate back to alpha.
+ auto tmp = 255 - ((255 - nGrey1) + (255 - nGrey2) - (255 - nGrey1) * (255 - nGrey2));
+ *scanline = static_cast<sal_uInt8>(tmp / 255);
++scanline;
++otherScanline;
}
}
+ pAcc.reset();
+ assert( getPixelFormat() == vcl::PixelFormat::N8_BPP && "alpha bitmap should be 8bpp" );
+ assert( HasGreyPalette8Bit() && "alpha bitmap should have greyscale palette" );
}
bool AlphaMask::hasAlpha() const
@@ -126,7 +147,7 @@ bool AlphaMask::hasAlpha() const
{
for (tools::Long x = 0; x < nWidth; ++x)
{
- if (0 != pAcc->GetColor(y, x).GetRed())
+ if (255 != pAcc->GetColor(y, x).GetRed())
{
return true;
}
@@ -143,6 +164,8 @@ void AlphaMask::ReleaseAccess( BitmapReadAccess* pAccess )
Bitmap::ReleaseAccess( pAccess );
Convert( BmpConversion::N8BitNoConversion );
}
+ assert( getPixelFormat() == vcl::PixelFormat::N8_BPP && "alpha bitmap should be 8bpp" );
+ assert( HasGreyPalette8Bit() && "alpha bitmap should have greyscale palette" );
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/source/bitmap/bitmappaint.cxx b/vcl/source/bitmap/bitmappaint.cxx
index 0207bb813fe8..487e6d1a6ad6 100644
--- a/vcl/source/bitmap/bitmappaint.cxx
+++ b/vcl/source/bitmap/bitmappaint.cxx
@@ -60,38 +60,54 @@ bool Bitmap::Erase(const Color& rFillColor)
bool Bitmap::Invert()
{
- ScopedReadAccess pReadAcc(*this);
- if (!pReadAcc)
+ if (!mxSalBmp)
return false;
- if (pReadAcc->HasPalette())
+ // For alpha masks, we need to actually invert the underlying data
+ // or the optimisations elsewhere do not work right.
+ if (typeid(*this) != typeid(AlphaMask))
{
- BitmapScopedWriteAccess pWriteAcc(*this);
- BitmapPalette aBmpPal(pWriteAcc->GetPalette());
- const sal_uInt16 nCount = aBmpPal.GetEntryCount();
-
- for (sal_uInt16 i = 0; i < nCount; i++)
+ // We want to avoid using ScopedReadAccess until we really need
+ // it, because on Skia it triggers a GPU->RAM copy, which is very slow.
+ ScopedReadAccess pReadAcc(*this);
+ if (!pReadAcc)
+ return false;
+ if (pReadAcc->HasPalette())
{
- aBmpPal[i].Invert();
- }
+ BitmapScopedWriteAccess pWriteAcc(*this);
+ BitmapPalette aBmpPal(pWriteAcc->GetPalette());
+ const sal_uInt16 nCount = aBmpPal.GetEntryCount();
- pWriteAcc->SetPalette(aBmpPal);
+ for (sal_uInt16 i = 0; i < nCount; i++)
+ {
+ aBmpPal[i].Invert();
+ }
+
+ pWriteAcc->SetPalette(aBmpPal);
+ mxSalBmp->InvalidateChecksum();
+ return true;
+ }
}
- else if (!mxSalBmp->Invert()) // try optimised call first
+
+ // try optimised call, much faster on Skia
+ if (mxSalBmp->Invert())
{
- BitmapScopedWriteAccess pWriteAcc(*this);
- const tools::Long nWidth = pWriteAcc->Width();
- const tools::Long nHeight = pWriteAcc->Height();
+ mxSalBmp->InvalidateChecksum();
+ return true;
+ }
- for (tools::Long nY = 0; nY < nHeight; nY++)
+ BitmapScopedWriteAccess pWriteAcc(*this);
+ const tools::Long nWidth = pWriteAcc->Width();
+ const tools::Long nHeight = pWriteAcc->Height();
+
+ for (tools::Long nY = 0; nY < nHeight; nY++)
+ {
+ Scanline pScanline = pWriteAcc->GetScanline(nY);
+ for (tools::Long nX = 0; nX < nWidth; nX++)
{
- Scanline pScanline = pWriteAcc->GetScanline(nY);
- for (tools::Long nX = 0; nX < nWidth; nX++)
- {
- BitmapColor aBmpColor = pWriteAcc->GetPixelFromData(pScanline, nX);
- aBmpColor.Invert();
- pWriteAcc->SetPixelOnData(pScanline, nX, aBmpColor);
- }
+ BitmapColor aBmpColor = pWriteAcc->GetPixelFromData(pScanline, nX);
+ aBmpColor.Invert();
+ pWriteAcc->SetPixelOnData(pScanline, nX, aBmpColor);
}
}
@@ -607,6 +623,174 @@ Bitmap Bitmap::CreateMask(const Color& rTransColor, sal_uInt8 nTol) const
return aNewBmp;
}
+AlphaMask Bitmap::CreateAlphaMask(const Color& rTransColor) const
+{
+ ScopedReadAccess pReadAcc(const_cast<Bitmap&>(*this));
+ if (!pReadAcc)
+ return AlphaMask();
+
+ // Historically LO used 1bpp masks, but 8bpp masks are much faster,
+ // better supported by hardware, and the memory savings are not worth
+ // it anymore.
+
+ if ((pReadAcc->GetScanlineFormat() == ScanlineFormat::N1BitMsbPal)
+ && pReadAcc->GetBestMatchingColor(COL_ALPHA_TRANSPARENT)
+ == pReadAcc->GetBestMatchingColor(rTransColor))
+ {
+ // if we're a 1 bit pixel already, and the transcolor matches the color that would replace it
+ // already, then just return a copy
+ return AlphaMask(*this);
+ }
+
+ AlphaMask aNewBmp(GetSizePixel());
+ BitmapScopedWriteAccess pWriteAcc(aNewBmp);
+ if (!pWriteAcc)
+ return AlphaMask();
+
+ const tools::Long nWidth = pReadAcc->Width();
+ const tools::Long nHeight = pReadAcc->Height();
+ const BitmapColor aOpaqueColor(pWriteAcc->GetBestMatchingColor(COL_ALPHA_OPAQUE));
+ const BitmapColor aTransparentColor(pWriteAcc->GetBestMatchingColor(COL_ALPHA_TRANSPARENT));
+
+ const BitmapColor aTest(pReadAcc->GetBestMatchingColor(rTransColor));
+
+ if (pReadAcc->GetScanlineFormat() == ScanlineFormat::N8BitPal)
+ {
+ // optimized for 8Bit source palette
+ const sal_uInt8 cTest = aTest.GetIndex();
+
+ for (tools::Long nY = 0; nY < nHeight; ++nY)
+ {
+ Scanline pSrc = pReadAcc->GetScanline(nY);
+ Scanline pDst = pWriteAcc->GetScanline(nY);
+ for (tools::Long nX = 0; nX < nWidth; ++nX)
+ {
+ if (cTest == pSrc[nX])
+ pDst[nX] = aTransparentColor.GetIndex();
+ else
+ pDst[nX] = aOpaqueColor.GetIndex();
+ }
+ }
+ }
+ else
+ {
+ // not optimized
+ 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)
+ {
+ if (aTest == pReadAcc->GetPixelFromData(pScanlineRead, nX))
+ pWriteAcc->SetPixelOnData(pScanline, nX, aTransparentColor);
+ else
+ pWriteAcc->SetPixelOnData(pScanline, nX, aOpaqueColor);
+ }
+ }
+ }
+
+ pWriteAcc.reset();
+ pReadAcc.reset();
+
+ aNewBmp.maPrefSize = maPrefSize;
+ aNewBmp.maPrefMapMode = maPrefMapMode;
+
+ return aNewBmp;
+}
+
+AlphaMask Bitmap::CreateAlphaMask(const Color& rTransColor, sal_uInt8 nTol) const
+{
+ if (nTol == 0)
+ return CreateAlphaMask(rTransColor);
+
+ ScopedReadAccess pReadAcc(const_cast<Bitmap&>(*this));
+ if (!pReadAcc)
+ return AlphaMask();
+
+ // Historically LO used 1bpp masks, but 8bpp masks are much faster,
+ // better supported by hardware, and the memory savings are not worth
+ // it anymore.
+ // TODO: Possibly remove the 1bpp code later.
+
+ AlphaMask aNewBmp(GetSizePixel());
+ BitmapScopedWriteAccess pWriteAcc(aNewBmp);
+ if (!pWriteAcc)
+ return AlphaMask();
+
+ const tools::Long nWidth = pReadAcc->Width();
+ const tools::Long nHeight = pReadAcc->Height();
+ const BitmapColor aOpaqueColor(pWriteAcc->GetBestMatchingColor(COL_ALPHA_OPAQUE));
+ const BitmapColor aTransparentColor(pWriteAcc->GetBestMatchingColor(COL_ALPHA_TRANSPARENT));
+
+ BitmapColor aCol;
+ tools::Long nR, nG, nB;
+ const tools::Long nMinR = MinMax<tools::Long>(rTransColor.GetRed() - nTol, 0, 255);
+ const tools::Long nMaxR = MinMax<tools::Long>(rTransColor.GetRed() + nTol, 0, 255);
+ const tools::Long nMinG = MinMax<tools::Long>(rTransColor.GetGreen() - nTol, 0, 255);
+ const tools::Long nMaxG = MinMax<tools::Long>(rTransColor.GetGreen() + nTol, 0, 255);
+ const tools::Long nMinB = MinMax<tools::Long>(rTransColor.GetBlue() - nTol, 0, 255);
+ const tools::Long nMaxB = MinMax<tools::Long>(rTransColor.GetBlue() + nTol, 0, 255);
+
+ 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++)
+ {
+ aCol = pReadAcc->GetPaletteColor(pReadAcc->GetIndexFromData(pScanlineRead, nX));
+ nR = aCol.GetRed();
+ nG = aCol.GetGreen();
+ nB = aCol.GetBlue();
+
+ if (nMinR <= nR && nMaxR >= nR && nMinG <= nG && nMaxG >= nG && nMinB <= nB
+ && nMaxB >= nB)
+ {
+ pWriteAcc->SetPixelOnData(pScanline, nX, aTransparentColor);
+ }
+ else
+ {
+ pWriteAcc->SetPixelOnData(pScanline, nX, aOpaqueColor);
+ }
+ }
+ }
+ }
+ 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++)
+ {
+ aCol = pReadAcc->GetPixelFromData(pScanlineRead, nX);
+ nR = aCol.GetRed();
+ nG = aCol.GetGreen();
+ nB = aCol.GetBlue();
+
+ if (nMinR <= nR && nMaxR >= nR && nMinG <= nG && nMaxG >= nG && nMinB <= nB
+ && nMaxB >= nB)
+ {
+ pWriteAcc->SetPixelOnData(pScanline, nX, aTransparentColor);
+ }
+ else
+ {
+ pWriteAcc->SetPixelOnData(pScanline, nX, aOpaqueColor);
+ }
+ }
+ }
+ }
+
+ pWriteAcc.reset();
+ pReadAcc.reset();
+
+ aNewBmp.maPrefSize = maPrefSize;
+ aNewBmp.maPrefMapMode = maPrefMapMode;
+
+ return aNewBmp;
+}
+
vcl::Region Bitmap::CreateRegion(const Color& rColor, const tools::Rectangle& rRect) const
{
tools::Rectangle aRect(rRect);
@@ -721,7 +905,7 @@ bool Bitmap::Replace(const AlphaMask& rAlpha, const Color& rMergeColor)
for (tools::Long nX = 0; nX < nWidth; nX++)
{
aCol = pAcc->GetColor(nY, nX);
- aCol.Merge(rMergeColor, 255 - pAlphaAcc->GetIndexFromData(pScanlineAlpha, nX));
+ aCol.Merge(rMergeColor, pAlphaAcc->GetIndexFromData(pScanlineAlpha, nX));
pNewAcc->SetPixelOnData(pScanline, nX, aCol);
}
}
@@ -965,8 +1149,7 @@ bool Bitmap::Blend(const AlphaMask& rAlpha, const Color& rBackgroundColor)
for (tools::Long nX = 0; nX < nWidth; ++nX)
{
BitmapColor aBmpColor = pAcc->GetPixelFromData(pScanline, nX);
- aBmpColor.Merge(rBackgroundColor,
- 255 - pAlphaAcc->GetIndexFromData(pScanlineAlpha, nX));
+ aBmpColor.Merge(rBackgroundColor, pAlphaAcc->GetIndexFromData(pScanlineAlpha, nX));
pAcc->SetPixelOnData(pScanline, nX, aBmpColor);
}
}
diff --git a/vcl/source/bitmap/dibtools.cxx b/vcl/source/bitmap/dibtools.cxx
index d8fa61362635..d6ac43a403da 100644
--- a/vcl/source/bitmap/dibtools.cxx
+++ b/vcl/source/bitmap/dibtools.cxx
@@ -1699,7 +1699,11 @@ bool ReadDIBV5(
AlphaMask& rTargetAlpha,
SvStream& rIStm)
{
- return ImplReadDIB(rTarget, &rTargetAlpha, rIStm, true);
+ bool rv = ImplReadDIB(rTarget, &rTargetAlpha, rIStm, true);
+ // convert transparency->alpha
+ if (rv)
+ rTargetAlpha.Invert();
+ return rv;
}
bool ReadRawDIB(
@@ -1747,7 +1751,10 @@ bool WriteDIBBitmapEx(
if(rSource.IsAlpha())
{
- return ImplWriteDIB(rSource.maAlphaMask, rOStm, true, true);
+ // invert the alpha because the other routines actually want transparency
+ AlphaMask tmpAlpha = rSource.maAlphaMask;
+ tmpAlpha.Invert();
+ return ImplWriteDIB(tmpAlpha, rOStm, true, true);
}
}
diff --git a/vcl/source/filter/eps/eps.cxx b/vcl/source/filter/eps/eps.cxx
index 455e89cc543a..a107a5d400c6 100644
--- a/vcl/source/filter/eps/eps.cxx
+++ b/vcl/source/filter/eps/eps.cxx
@@ -200,7 +200,7 @@ private:
void ImplPolyLine( const tools::Polygon & rPolygon );
void ImplSetClipRegion( vcl::Region const & rRegion );
- void ImplBmp( Bitmap const *, Bitmap const *, const Point &, double nWidth, double nHeight );
+ void ImplBmp( Bitmap const *, AlphaMask const *, const Point &, double nWidth, double nHeight );
void ImplText( const OUString& rUniString, const Point& rPos, KernArraySpan pDXArry, o3tl::span<const sal_Bool> pKashidaArry, sal_Int32 nWidth, VirtualDevice const & rVDev );
void ImplSetAttrForText( const Point & rPoint );
void ImplWriteCharacter( char );
@@ -1641,7 +1641,7 @@ void PSWriter::ImplSetClipRegion( vcl::Region const & rClipRegion )
// color 1(pal), 4(pal), 8(pal), 24 Bit
//
-void PSWriter::ImplBmp( Bitmap const * pBitmap, Bitmap const * pMaskBitmap, const Point & rPoint, double nXWidth, double nYHeightOrg )
+void PSWriter::ImplBmp( Bitmap const * pBitmap, AlphaMask const * pAlphaMaskBitmap, const Point & rPoint, double nXWidth, double nYHeightOrg )
{
if ( !pBitmap )
return;
@@ -1662,7 +1662,7 @@ void PSWriter::ImplBmp( Bitmap const * pBitmap, Bitmap const * pMaskBitmap, cons
tools::Rectangle aRect;
vcl::Region aRegion;
- if ( pMaskBitmap )
+ if ( pAlphaMaskBitmap )
{
bDoTrans = true;
while (true)
@@ -1670,7 +1670,7 @@ void PSWriter::ImplBmp( Bitmap const * pBitmap, Bitmap const * pMaskBitmap, cons
if ( mnLevel == 1 && nHeight > 10 )
nHeight = 8;
aRect = tools::Rectangle( Point( 0, nHeightOrg - nHeightLeft ), Size( nWidth, nHeight ) );
- aRegion = pMaskBitmap->CreateRegion( COL_BLACK, aRect );
+ aRegion = pAlphaMaskBitmap->CreateRegion( COL_ALPHA_OPAQUE, aRect );
if( mnLevel == 1 )
{
diff --git a/vcl/source/filter/igif/gifread.cxx b/vcl/source/filter/igif/gifread.cxx
index 7cdc37710f51..818317f8baa8 100644
--- a/vcl/source/filter/igif/gifread.cxx
+++ b/vcl/source/filter/igif/gifread.cxx
@@ -661,7 +661,9 @@ void GIFReader::CreateNewBitmaps()
if( bGCTransparent )
{
pAcc1.reset();
- aAnimationFrame.maBitmapEx = BitmapEx( aBmp8, aBmp1 );
+ AlphaMask aAlphaMask(aBmp1);
+ aAlphaMask.Invert(); // convert from transparency to alpha
+ aAnimationFrame.maBitmapEx = BitmapEx( aBmp8, aAlphaMask );
}
else
aAnimationFrame.maBitmapEx = BitmapEx( aBmp8 );
diff --git a/vcl/source/filter/ipdf/pdfread.cxx b/vcl/source/filter/ipdf/pdfread.cxx
index e3d70f7c0ade..18f8c4dee95e 100644
--- a/vcl/source/filter/ipdf/pdfread.cxx
+++ b/vcl/source/filter/ipdf/pdfread.cxx
@@ -102,8 +102,7 @@ size_t RenderPDFBitmaps(const void* pBuffer, int nSize, std::vector<BitmapEx>& r
pWriteAccess->CopyScanline(nRow, pPdfLine, ScanlineFormat::N32BitTcBgra, nStride);
for (int nCol = 0; nCol < nPageWidth; ++nCol)
{
- // Invert alpha (source is alpha, target is opacity).
- aScanlineAlpha[nCol] = ~pPdfLine[3];
+ aScanlineAlpha[nCol] = pPdfLine[3];
pPdfLine += 4;
}
pMaskAccess->CopyScanline(nRow, aScanlineAlpha.data(), ScanlineFormat::N8BitPal,
diff --git a/vcl/source/filter/ipsd/ipsd.cxx b/vcl/source/filter/ipsd/ipsd.cxx
index 0ded0938efef..79ccda943dca 100644
--- a/vcl/source/filter/ipsd/ipsd.cxx
+++ b/vcl/source/filter/ipsd/ipsd.cxx
@@ -727,7 +727,7 @@ bool PSDReader::ImplReadBody()
m_rPSD.ReadUChar( nDummy );
for ( sal_uInt16 i = 0; i < ( -nRunCount + 1 ); i++ )
{
- mpBitmap->SetAlpha(nY, nX, nDat ? 0 : 255);
+ mpBitmap->SetAlpha(nY, nX, nDat ? 255 : 0);
if ( ++nX == mpFileHeader->nColumns )
{
nX = 0;
@@ -748,7 +748,7 @@ bool PSDReader::ImplReadBody()
nDat = 1;
if ( mpFileHeader->nDepth == 16 ) // 16 bit depth is to be skipped
m_rPSD.ReadUChar( nDummy );
- mpBitmap->SetAlpha(nY, nX, nDat ? 0 : 255);
+ mpBitmap->SetAlpha(nY, nX, nDat ? 255 : 0);
if ( ++nX == mpFileHeader->nColumns )
{
nX = 0;
diff --git a/vcl/source/filter/itiff/itiff.cxx b/vcl/source/filter/itiff/itiff.cxx
index 439cbd856182..bdbf0309e296 100644
--- a/vcl/source/filter/itiff/itiff.cxx
+++ b/vcl/source/filter/itiff/itiff.cxx
@@ -277,7 +277,7 @@ bool ImportTiffGraphicImport(SvStream& rTIFF, Graphic& rGraphic)
}
access->SetPixel(y, dest, Color(r, g, b));
- accessAlpha->SetPixelIndex(y, dest, 255 - a);
+ accessAlpha->SetPixelIndex(y, dest, a);
++src;
}
}
diff --git a/vcl/source/filter/jpeg/JpegReader.cxx b/vcl/source/filter/jpeg/JpegReader.cxx
index 8d190200face..186105603904 100644
--- a/vcl/source/filter/jpeg/JpegReader.cxx
+++ b/vcl/source/filter/jpeg/JpegReader.cxx
@@ -249,8 +249,8 @@ Graphic JPEGReader::CreateIntermediateGraphic(tools::Long nLines)
if (!mnLastLines)
{
- mpIncompleteAlpha.emplace(aSizePixel, vcl::PixelFormat::N8_BPP, &Bitmap::GetGreyPalette(256));
- mpIncompleteAlpha->Erase(COL_WHITE);
+ mpIncompleteAlpha.emplace(aSizePixel);
+ mpIncompleteAlpha->Erase(255);
}
if (nLines && (nLines < aSizePixel.Height()))
@@ -261,7 +261,7 @@ Graphic JPEGReader::CreateIntermediateGraphic(tools::Long nLines)
{
{
BitmapScopedWriteAccess pAccess(*mpIncompleteAlpha);
- pAccess->SetFillColor(COL_BLACK);
+ pAccess->SetFillColor(COL_ALPHA_OPAQUE);
pAccess->FillRect(tools::Rectangle(Point(0, mnLastLines), Size(pAccess->Width(), nNewLines)));
}
diff --git a/vcl/source/filter/jpeg/JpegReader.hxx b/vcl/source/filter/jpeg/JpegReader.hxx
index a4df7e212119..576027237ab8 100644
--- a/vcl/source/filter/jpeg/JpegReader.hxx
+++ b/vcl/source/filter/jpeg/JpegReader.hxx
@@ -49,7 +49,7 @@ class JPEGReader : public GraphicReader
{
SvStream& mrStream;
std::optional<Bitmap> mpBitmap;
- std::optional<Bitmap> mpIncompleteAlpha;
+ std::optional<AlphaMask> mpIncompleteAlpha;
tools::Long mnLastPos;
tools::Long mnLastLines;
diff --git a/vcl/source/filter/png/PngImageReader.cxx b/vcl/source/filter/png/PngImageReader.cxx
index e7b5c414762b..fcdcd210a157 100644
--- a/vcl/source/filter/png/PngImageReader.cxx
+++ b/vcl/source/filter/png/PngImageReader.cxx
@@ -465,6 +465,7 @@ bool reader(SvStream& rStream, Graphic& rGraphic,
{
aBitmap = Bitmap(Size(width, height), vcl::PixelFormat::N24_BPP);
aBitmapAlpha = AlphaMask(Size(width, height), nullptr);
+ aBitmapAlpha.Erase(0); // opaque
}
break;
case PNG_COLOR_TYPE_GRAY:
@@ -605,7 +606,7 @@ bool reader(SvStream& rStream, Graphic& rGraphic,
pScanline[iColor++] = pRow[i + 0];
pScanline[iColor++] = pRow[i + 1];
pScanline[iColor++] = pRow[i + 2];
- pScanAlpha[iAlpha++] = 0xFF - pRow[i + 3];
+ pScanAlpha[iAlpha++] = pRow[i + 3];
}
}
}
@@ -629,7 +630,7 @@ bool reader(SvStream& rStream, Graphic& rGraphic,
pScanline[iColor++] = pRow[i + 0];
pScanline[iColor++] = pRow[i + 1];
pScanline[iColor++] = pRow[i + 2];
- pScanAlpha[iAlpha++] = 0xFF - pRow[i + 3];
+ pScanAlpha[iAlpha++] = pRow[i + 3];
}
}
}
diff --git a/vcl/source/filter/png/PngImageWriter.cxx b/vcl/source/filter/png/PngImageWriter.cxx
index 7b0bfdc28cf1..13e23fcb2e9b 100644
--- a/vcl/source/filter/png/PngImageWriter.cxx
+++ b/vcl/source/filter/png/PngImageWriter.cxx
@@ -109,12 +109,14 @@ static bool pngWrite(SvStream& rStream, const BitmapEx& rBitmapEx, int nCompress
png_set_write_fn(pPng, &rStream, lclWriteStream, nullptr);
aBitmap = aBitmapEx.GetBitmap();
- aAlphaMask = aBitmapEx.GetAlphaMask();
+ if (bTranslucent)
+ aAlphaMask = aBitmapEx.GetAlphaMask();
{
bool bCombineChannels = false;
pAccess = Bitmap::ScopedReadAccess(aBitmap);
- pAlphaAccess = Bitmap::ScopedReadAccess(aAlphaMask);
+ if (bTranslucent)
+ pAlphaAccess = Bitmap::ScopedReadAccess(aAlphaMask);
Size aSize = aBitmapEx.GetSizePixel();
int bitDepth = -1;
@@ -251,8 +253,6 @@ static bool pngWrite(SvStream& rStream, const BitmapEx& rBitmapEx, int nCompress
combineScanlineChannels(pSourcePointer, pAlphaPointer, aCombinedChannels,
nBitmapWidth, colorType);
pFinalPointer = aCombinedChannels.data();
- // Invert alpha channel (255 - a)
- png_set_invert_alpha(pPng);
}
png_write_row(pPng, pFinalPointer);
}
diff --git a/vcl/source/filter/wmf/emfwr.cxx b/vcl/source/filter/wmf/emfwr.cxx
index 385b698636e0..8b2c7713bb11 100644
--- a/vcl/source/filter/wmf/emfwr.cxx
+++ b/vcl/source/filter/wmf/emfwr.cxx
@@ -1299,7 +1299,6 @@ void EMFWriter::ImplWrite( const GDIMetaFile& rMtf )
if( !aMsk.IsEmpty() )
{
aBmp.Replace( aMsk, COL_WHITE );
- aMsk.Invert();
ImplWriteBmpRecord( aMsk, pA->GetPoint(), maVDev->PixelToLogic( aMsk.GetSizePixel() ), WIN_SRCPAINT );
ImplWriteBmpRecord( aBmp, pA->GetPoint(), maVDev->PixelToLogic( aBmp.GetSizePixel() ), WIN_SRCAND );
}
@@ -1317,7 +1316,6 @@ void EMFWriter::ImplWrite( const GDIMetaFile& rMtf )
if( !aMsk.IsEmpty() )
{
aBmp.Replace( aMsk, COL_WHITE );
- aMsk.Invert();
ImplWriteBmpRecord( aMsk, pA->GetPoint(), pA->GetSize(), WIN_SRCPAINT );
ImplWriteBmpRecord( aBmp, pA->GetPoint(), pA->GetSize(), WIN_SRCAND );
}
@@ -1337,7 +1335,6 @@ void EMFWriter::ImplWrite( const GDIMetaFile& rMtf )
if( !aMsk.IsEmpty() )
{
aBmp.Replace( aMsk, COL_WHITE );
- aMsk.Invert();
ImplWriteBmpRecord( aMsk, pA->GetDestPoint(), pA->GetDestSize(), WIN_SRCPAINT );
ImplWriteBmpRecord( aBmp, pA->GetDestPoint(), pA->GetDestSize(), WIN_SRCAND );
}
diff --git a/vcl/source/filter/wmf/wmfwr.cxx b/vcl/source/filter/wmf/wmfwr.cxx
index 7afc3a62fa73..c6612a9bbf25 100644
--- a/vcl/source/filter/wmf/wmfwr.cxx
+++ b/vcl/source/filter/wmf/wmfwr.cxx
@@ -1250,7 +1250,6 @@ void WMFWriter::WriteRecords( const GDIMetaFile & rMTF )
if( !aMsk.IsEmpty() )
{
aBmp.Replace( aMsk, COL_WHITE );
- aMsk.Invert();
WMFRecord_StretchDIB( pA->GetPoint(), aMsk.GetSizePixel(), aBmp, W_SRCPAINT );
WMFRecord_StretchDIB( pA->GetPoint(), aBmp.GetSizePixel(), aBmp, W_SRCAND );
}
@@ -1268,7 +1267,6 @@ void WMFWriter::WriteRecords( const GDIMetaFile & rMTF )
if( !aMsk.IsEmpty() )
{
aBmp.Replace( aMsk, COL_WHITE );
- aMsk.Invert();
WMFRecord_StretchDIB( pA->GetPoint(), pA->GetSize(), aMsk, W_SRCPAINT );
WMFRecord_StretchDIB( pA->GetPoint(), pA->GetSize(), aBmp, W_SRCAND );
}
@@ -1288,7 +1286,6 @@ void WMFWriter::WriteRecords( const GDIMetaFile & rMTF )
if( !aMsk.IsEmpty() )
{
aBmp.Replace( aMsk, COL_WHITE );
- aMsk.Invert();
WMFRecord_StretchDIB( pA->GetDestPoint(), pA->GetDestSize(), aMsk, W_SRCPAINT );
WMFRecord_StretchDIB( pA->GetDestPoint(), pA->GetDestSize(), aBmp, W_SRCAND );
}
diff --git a/vcl/source/gdi/gdimtf.cxx b/vcl/source/gdi/gdimtf.cxx
index 379f222572d4..359b9f69b944 100644
--- a/vcl/source/gdi/gdimtf.cxx
+++ b/vcl/source/gdi/gdimtf.cxx
@@ -1747,7 +1747,7 @@ Color GDIMetaFile::ImplColConvertFnc( const Color& rColor, const void* pColParam
if( MtfConversion::N1BitThreshold == static_cast<const ImplColConvertParam*>(pColParam)->eConversion )
cLum = ( cLum < 128 ) ? 0 : 255;
- return Color( ColorTransparency, 255 - rColor.GetAlpha(), cLum, cLum, cLum );
+ return Color( ColorAlpha, rColor.GetAlpha(), cLum, cLum, cLum );
}
BitmapEx GDIMetaFile::ImplBmpConvertFnc( const BitmapEx& rBmpEx, const void* pBmpParam )
diff --git a/vcl/source/gdi/pdfwriter_impl2.cxx b/vcl/source/gdi/pdfwriter_impl2.cxx
index e309cc21a3b9..4e309a2ee8a3 100644
--- a/vcl/source/gdi/pdfwriter_impl2.cxx
+++ b/vcl/source/gdi/pdfwriter_impl2.cxx
@@ -45,6 +45,7 @@
#include <cppuhelper/implbase.hxx>
#include <o3tl/unit_conversion.hxx>
+#include <vcl/skia/SkiaHelper.hxx>
#include <sal/log.hxx>
#include <memory>
@@ -462,16 +463,15 @@ void PDFWriterImpl::playMetafile( const GDIMetaFile& i_rMtf, vcl::PDFExtOutDevDa
if ( nPixelX && nPixelY )
{
Size aDstSizePixel( nPixelX, nPixelY );
- ScopedVclPtrInstance<VirtualDevice> xVDev;
- if( xVDev->SetOutputSizePixel( aDstSizePixel ) )
+ ScopedVclPtrInstance<VirtualDevice> xVDev(DeviceFormat::WITH_ALPHA);
+ if( xVDev->SetOutputSizePixel( aDstSizePixel, true, true ) )
{
- Bitmap aPaint, aMask;
- AlphaMask aAlpha;
Point aPoint;
MapMode aMapMode( pDummyVDev->GetMapMode() );
aMapMode.SetOrigin( aPoint );
xVDev->SetMapMode( aMapMode );
+ const bool bVDevOldMap = xVDev->IsMapModeEnabled();
Size aDstSize( xVDev->PixelToLogic( aDstSizePixel ) );
Point aMtfOrigin( aTmpMtf.GetPrefMapMode().GetOrigin() );
@@ -487,34 +487,42 @@ void PDFWriterImpl::playMetafile( const GDIMetaFile& i_rMtf, vcl::PDFExtOutDevDa
aTmpMtf.WindStart();
aTmpMtf.Play(*xVDev, aPoint, aDstSize);
aTmpMtf.WindStart();
-
xVDev->EnableMapMode( false );
- aPaint = xVDev->GetBitmap( aPoint, aDstSizePixel );
- xVDev->EnableMapMode();
-
- // create mask bitmap
- xVDev->SetLineColor( COL_BLACK );
- xVDev->SetFillColor( COL_BLACK );
- xVDev->DrawRect( tools::Rectangle( aPoint, aDstSize ) );
- xVDev->SetDrawMode( DrawModeFlags::WhiteLine | DrawModeFlags::WhiteFill | DrawModeFlags::WhiteText |
- DrawModeFlags::WhiteBitmap | DrawModeFlags::WhiteGradient );
- aTmpMtf.WindStart();
- aTmpMtf.Play(*xVDev, aPoint, aDstSize);
- aTmpMtf.WindStart();
- xVDev->EnableMapMode( false );
- aMask = xVDev->GetBitmap( aPoint, aDstSizePixel );
- xVDev->EnableMapMode();
+ BitmapEx aPaint = xVDev->GetBitmapEx(aPoint, xVDev->GetOutputSizePixel());
+ xVDev->EnableMapMode( bVDevOldMap ); // #i35331#: MUST NOT use EnableMapMode( sal_True ) here!
// create alpha mask from gradient
xVDev->SetDrawMode( DrawModeFlags::GrayGradient );
xVDev->DrawGradient( tools::Rectangle( aPoint, aDstSize ), rTransparenceGradient );
xVDev->SetDrawMode( DrawModeFlags::Default );
xVDev->EnableMapMode( false );
- xVDev->DrawMask( aPoint, aDstSizePixel, aMask, COL_WHITE );
- aAlpha = xVDev->GetBitmap( aPoint, aDstSizePixel );
+
+ AlphaMask aAlpha(xVDev->GetBitmap(Point(), xVDev->GetOutputSizePixel()));
+ AlphaMask aPaintAlpha(aPaint.GetAlphaMask());
+#if HAVE_FEATURE_SKIA
+ // One of the alpha masks is inverted from what
+ // is expected so invert it again
+ if ( SkiaHelper::isVCLSkiaEnabled() )
+ {
+ aAlpha.Invert(); // convert to alpha
+ }
+ else
+#endif
+ {
+ aPaintAlpha.Invert(); // convert to alpha
+ }
+ aAlpha.BlendWith(aPaintAlpha);
+#if HAVE_FEATURE_SKIA
+ if ( !SkiaHelper::isVCLSkiaEnabled() )
+#endif
+ {
+ aAlpha.Invert(); // convert to alpha
+ }
+
+ xVDev.disposeAndClear();
Graphic aGraphic = i_pOutDevData ? i_pOutDevData->GetCurrentGraphic() : Graphic();
- implWriteBitmapEx( rPos, rSize, BitmapEx( aPaint, aAlpha ), aGraphic, pDummyVDev, i_rContext );
+ implWriteBitmapEx( rPos, rSize, BitmapEx( aPaint.GetBitmap(), aAlpha ), aGraphic, pDummyVDev, i_rContext );
}
}
}
@@ -758,7 +766,17 @@ void PDFWriterImpl::playMetafile( const GDIMetaFile& i_rMtf, vcl::PDFExtOutDevDa
case MetaActionType::BMPEX:
{
const MetaBmpExAction* pA = static_cast<const MetaBmpExAction*>(pAction);
- const BitmapEx& aBitmapEx( pA->GetBitmapEx() );
+
+ // When rendering an image with an alpha mask during PDF
+ // export, the alpha mask needs to be inverted
+ BitmapEx aBitmapEx( pA->GetBitmapEx() );
+ if ( aBitmapEx.IsAlpha())
+ {
+ AlphaMask aAlpha = aBitmapEx.GetAlphaMask();
+ aAlpha.Invert();
+ aBitmapEx = BitmapEx(aBitmapEx.GetBitmap(), aAlpha);
+ }
+
Size aSize( OutputDevice::LogicToLogic( aBitmapEx.GetPrefSize(),
aBitmapEx.GetPrefMapMode(), pDummyVDev->GetMapMode() ) );
Graphic aGraphic = i_pOutDevData ? i_pOutDevData->GetCurrentGraphic() : Graphic();
@@ -769,15 +787,36 @@ void PDFWriterImpl::playMetafile( const GDIMetaFile& i_rMtf, vcl::PDFExtOutDevDa
case MetaActionType::BMPEXSCALE:
{
const MetaBmpExScaleAction* pA = static_cast<const MetaBmpExScaleAction*>(pAction);
+
+ // When rendering an image with an alpha mask during PDF
+ // export, the alpha mask needs to be inverted
+ BitmapEx aBitmapEx( pA->GetBitmapEx() );
+ if ( aBitmapEx.IsAlpha())
+ {
+ AlphaMask aAlpha = aBitmapEx.GetAlphaMask();
+ aAlpha.Invert();
+ aBitmapEx = BitmapEx(aBitmapEx.GetBitmap(), aAlpha);
+ }
+
Graphic aGraphic = i_pOutDevData ? i_pOutDevData->GetCurrentGraphic() : Graphic();
- implWriteBitmapEx( pA->GetPoint(), pA->GetSize(), pA->GetBitmapEx(), aGraphic, pDummyVDev, i_rContext );
+ implWriteBitmapEx( pA->GetPoint(), pA->GetSize(), aBitmapEx, aGraphic, pDummyVDev, i_rContext );
}
break;
case MetaActionType::BMPEXSCALEPART:
{
const MetaBmpExScalePartAction* pA = static_cast<const MetaBmpExScalePartAction*>(pAction);
+
+ // When rendering an image with an alpha mask during PDF
+ // export, the alpha mask needs to be inverted
BitmapEx aBitmapEx( pA->GetBitmapEx() );
+ if ( aBitmapEx.IsAlpha())
+ {
+ AlphaMask aAlpha = aBitmapEx.GetAlphaMask();
+ aAlpha.Invert();
+ aBitmapEx = BitmapEx(aBitmapEx.GetBitmap(), aAlpha);
+ }
+
aBitmapEx.Crop( tools::Rectangle( pA->GetSrcPoint(), pA->GetSrcSize() ) );
Graphic aGraphic = i_pOutDevData ? i_pOutDevData->GetCurrentGraphic() : Graphic();
implWriteBitmapEx( pA->GetDestPoint(), pA->GetDestSize(), aBitmapEx, aGraphic, pDummyVDev, i_rContext );
diff --git a/vcl/source/gdi/virdev.cxx b/vcl/source/gdi/virdev.cxx
index 4d10f317e93c..b86c4ae49624 100644
--- a/vcl/source/gdi/virdev.cxx
+++ b/vcl/source/gdi/virdev.cxx
@@ -341,18 +341,18 @@ bool VirtualDevice::InnerImplSetOutputSizePixel( const Size& rNewSize, bool bEra
// fill/linecolor state)
void VirtualDevice::ImplFillOpaqueRectangle( const tools::Rectangle& rRect )
{
- // Set line and fill color to black (->opaque),
+ // Set line and fill color to opaque,
// fill rect with that (linecolor, too, because of
// those pesky missing pixel problems)
Push( vcl::PushFlags::LINECOLOR | vcl::PushFlags::FILLCOLOR );
- SetLineColor( COL_BLACK );
- SetFillColor( COL_BLACK );
+ SetLineColor( COL_ALPHA_OPAQUE );
+ SetFillColor( COL_ALPHA_OPAQUE );
DrawRect( rRect );
Pop();
}
bool VirtualDevice::ImplSetOutputSizePixel( const Size& rNewSize, bool bErase,
- sal_uInt8 *const pBuffer)
+ sal_uInt8 *const pBuffer, bool bAlphaMaskTransparent )
{
if( InnerImplSetOutputSizePixel(rNewSize, bErase, pBuffer) )
{
@@ -368,14 +368,16 @@ bool VirtualDevice::ImplSetOutputSizePixel( const Size& rNewSize, bool bErase,
{
mpAlphaVDev = VclPtr<VirtualDevice>::Create(*this, meFormatAndAlpha);
mpAlphaVDev->InnerImplSetOutputSizePixel(rNewSize, bErase, nullptr);
+ mpAlphaVDev->SetBackground( Wallpaper(bAlphaMaskTransparent ? COL_ALPHA_TRANSPARENT : COL_ALPHA_OPAQUE) );
+ mpAlphaVDev->Erase();
}
// TODO: copy full outdev state to new one, here. Also needed in outdev2.cxx:DrawOutDev
if( GetLineColor() != COL_TRANSPARENT )
- mpAlphaVDev->SetLineColor( COL_BLACK );
+ mpAlphaVDev->SetLineColor( COL_ALPHA_OPAQUE );
if( GetFillColor() != COL_TRANSPARENT )
- mpAlphaVDev->SetFillColor( COL_BLACK );
+ mpAlphaVDev->SetFillColor( COL_ALPHA_OPAQUE );
mpAlphaVDev->SetMapMode( GetMapMode() );
@@ -400,9 +402,9 @@ void VirtualDevice::EnableRTL( bool bEnable )
OutputDevice::EnableRTL(bEnable);
}
-bool VirtualDevice::SetOutputSizePixel( const Size& rNewSize, bool bErase )
+bool VirtualDevice::SetOutputSizePixel( const Size& rNewSize, bool bErase, bool bAlphaMaskTransparent )
{
- return ImplSetOutputSizePixel(rNewSize, bErase, nullptr);
+ return ImplSetOutputSizePixel(rNewSize, bErase, nullptr, bAlphaMaskTransparent);
}
bool VirtualDevice::SetOutputSizePixelScaleOffsetAndLOKBuffer(
diff --git a/vcl/source/graphic/GraphicObject2.cxx b/vcl/source/graphic/GraphicObject2.cxx
index e5914f2be62b..a654baeba6bf 100644
--- a/vcl/source/graphic/GraphicObject2.cxx
+++ b/vcl/source/graphic/GraphicObject2.cxx
@@ -462,8 +462,8 @@ void GraphicObject::ImplTransformBitmap( BitmapEx& rBmpEx,
else
{
// #104115# Generate mask bitmap and init to zero
- Bitmap aMask(aBmpSize, vcl::PixelFormat::N8_BPP, &Bitmap::GetGreyPalette(256));
- aMask.Erase( Color(0,0,0) );
+ AlphaMask aMask(aBmpSize);
+ aMask.Erase(255);
// #104115# Always generate transparent bitmap, we need the border transparent
aBmpEx2 = BitmapEx( rBmpEx.GetBitmap(), aMask );
diff --git a/vcl/source/graphic/UnoGraphic.cxx b/vcl/source/graphic/UnoGraphic.cxx
index d1b7fd0238df..6448765a9056 100644
--- a/vcl/source/graphic/UnoGraphic.cxx
+++ b/vcl/source/graphic/UnoGraphic.cxx
@@ -206,7 +206,7 @@ uno::Reference< graphic::XGraphic > SAL_CALL Graphic::colorChange(
if ((nAlphaTo == 0) || (nAlphaTo == sal::static_int_cast< sal_Int8 >(0xff)))
{
Bitmap aBitmap(aBitmapEx.GetBitmap());
- Bitmap aMask(aBitmap.CreateMask(aColorFrom, nTolerance));
+ AlphaMask aMask(aBitmap.CreateAlphaMask(aColorFrom, nTolerance));
aBitmap.Replace(aColorFrom, aColorTo, nTolerance);
aReturnGraphic = ::Graphic(BitmapEx(aBitmap, aMask));
}
diff --git a/vcl/source/helper/canvasbitmap.cxx b/vcl/source/helper/canvasbitmap.cxx
index 39f7e344740b..e64cd07a8940 100644
--- a/vcl/source/helper/canvasbitmap.cxx
+++ b/vcl/source/helper/canvasbitmap.cxx
@@ -436,7 +436,9 @@ uno::Sequence< sal_Int8 > SAL_CALL VclCanvasBitmap::getData( rendering::IntegerB
for( tools::Long x=aRequestedArea.Left(); x<aRequestedArea.Right(); ++x )
{
*pOutScan++ = pBmpAcc->GetPixelIndex(y,x);
- *pOutScan++ = pAlphaAcc->GetPixelIndex(y,x);
+ // vcl used to store transparency. Now it stores alpha. But we need the UNO
+ // interface to still preserve the old interface.
+ *pOutScan++ = 255 - pAlphaAcc->GetPixelIndex(y,x);
}
}
else
@@ -451,7 +453,9 @@ uno::Sequence< sal_Int8 > SAL_CALL VclCanvasBitmap::getData( rendering::IntegerB
{
for( tools::Long i=0; i<nNonAlphaBytes; ++i )
*pOutScan++ = *pScan++;
- *pOutScan++ = pAlphaAcc->GetIndexFromData( pScanlineAlpha, x );
+ // vcl used to store transparency. Now it stores alpha. But we need the UNO
+ // interface to still preserve the old interface.
+ *pOutScan++ = 255 - pAlphaAcc->GetIndexFromData( pScanlineAlpha, x );
}
}
@@ -515,7 +519,9 @@ uno::Sequence< sal_Int8 > SAL_CALL VclCanvasBitmap::getPixel( rendering::Integer
{
// input less than a byte - copy via GetPixel()
*pOutBuf++ = pBmpAcc->GetPixelIndex(pos.Y,pos.X);
- *pOutBuf = pAlphaAcc->GetPixelIndex(pos.Y,pos.X);
+ // vcl used to store transparency. Now it stores alpha. But we need the UNO
+ // interface to still preserve the old interface.
+ *pOutBuf = 255 - pAlphaAcc->GetPixelIndex(pos.Y,pos.X);
}
else
{
@@ -525,7 +531,9 @@ uno::Sequence< sal_Int8 > SAL_CALL VclCanvasBitmap::getPixel( rendering::Integer
// input integer multiple of byte - copy directly
memcpy(pOutBuf, pScan+nScanlineLeftOffset, nNonAlphaBytes );
pOutBuf += nNonAlphaBytes;
- *pOutBuf++ = pAlphaAcc->GetPixelIndex(pos.Y,pos.X);
+ // vcl used to store transparency. Now it stores alpha. But we need the UNO
+ // interface to still preserve the old interface.
+ *pOutBuf++ = 255 - pAlphaAcc->GetPixelIndex(pos.Y,pos.X);
}
}
diff --git a/vcl/source/helper/canvastools.cxx b/vcl/source/helper/canvastools.cxx
index e41417b8bdfe..c0e783f9f508 100644
--- a/vcl/source/helper/canvastools.cxx
+++ b/vcl/source/helper/canvastools.cxx
@@ -115,7 +115,7 @@ namespace vcl::unotools
toByteColor(rColor.Green),
toByteColor(rColor.Blue))))) );
rAlphaAcc->SetPixelOnData( pScanlineAlpha, x,
- BitmapColor( 255 - toByteColor(rColor.Alpha) ));
+ BitmapColor( toByteColor(rColor.Alpha) ));
}
}
else
@@ -128,7 +128,7 @@ namespace vcl::unotools
toByteColor(rColor.Green),
toByteColor(rColor.Blue) ));
rAlphaAcc->SetPixelOnData( pScanlineAlpha, x,
- BitmapColor( 255 - toByteColor(rColor.Alpha) ));
+ BitmapColor( toByteColor(rColor.Alpha) ));
}
}
}
diff --git a/vcl/source/image/ImplImage.cxx b/vcl/source/image/ImplImage.cxx
index a63dd8ccb7ce..cf70052a9fd7 100644
--- a/vcl/source/image/ImplImage.cxx
+++ b/vcl/source/image/ImplImage.cxx
@@ -26,6 +26,7 @@
#include <vcl/virdev.hxx>
#include <vcl/BitmapFilter.hxx>
#include <vcl/ImageTree.hxx>
+#include <vcl/skia/SkiaHelper.hxx>
#include <bitmap/BitmapDisabledImageFilter.hxx>
#include <comphelper/lok.hxx>
@@ -164,7 +165,15 @@ BitmapEx const & ImplImage::getBitmapExForHiDPI(bool bDisabled, SalGraphics* pGr
else // if (mxMetaFile)
{
ScopedVclPtrInstance<VirtualDevice> aVDev(DeviceFormat::WITH_ALPHA);
- aVDev->SetOutputSizePixel(aTarget);
+
+ // Fix white background in font color and font background color
+ // in the Breeze icons by setting the alpha mask to transparent
+ bool bAlphaMaskTransparent = true;
+#if HAVE_FEATURE_SKIA
+ if (SkiaHelper::isVCLSkiaEnabled() && SkiaHelper::isAlphaMaskBlendingEnabled())
+ bAlphaMaskTransparent = false;
+#endif
+ aVDev->SetOutputSizePixel(aTarget, true, bAlphaMaskTransparent);
mxMetaFile->WindStart();
mxMetaFile->Play(*aVDev, Point(), aTarget);
maBitmapEx = aVDev->GetBitmapEx(Point(), aTarget);
diff --git a/vcl/source/opengl/OpenGLHelper.cxx b/vcl/source/opengl/OpenGLHelper.cxx
index d63be4c3f9a7..223dbf87eb9c 100644
--- a/vcl/source/opengl/OpenGLHelper.cxx
+++ b/vcl/source/opengl/OpenGLHelper.cxx
@@ -588,7 +588,7 @@ BitmapEx OpenGLHelper::ConvertBufferToBitmapEx(const sal_uInt8* const pBuffer, t
*pScan++ = pBuffer[nCurPos+2];
nCurPos += 3;
- *pAlphaScan++ = static_cast<sal_uInt8>( 255 - pBuffer[nCurPos++] );
+ *pAlphaScan++ = pBuffer[nCurPos++];
}
}
}
diff --git a/vcl/source/outdev/background.cxx b/vcl/source/outdev/background.cxx
index 1f5dcd860174..118b4d4c4be4 100644
--- a/vcl/source/outdev/background.cxx
+++ b/vcl/source/outdev/background.cxx
@@ -59,17 +59,17 @@ void OutputDevice::SetBackground( const Wallpaper& rBackground )
if( bitmap.IsAlpha())
mpAlphaVDev->SetBackground( Wallpaper( BitmapEx( Bitmap( bitmap.GetAlphaMask()))));
else
- mpAlphaVDev->SetBackground( Wallpaper( COL_BLACK ));
+ mpAlphaVDev->SetBackground( Wallpaper( COL_ALPHA_OPAQUE ));
}
else if( rBackground.IsGradient())
{
- mpAlphaVDev->SetBackground( Wallpaper( COL_BLACK ));
+ mpAlphaVDev->SetBackground( Wallpaper( COL_ALPHA_OPAQUE ));
}
else
{
// Color background.
- int transparency = 255 - rBackground.GetColor().GetAlpha();
- mpAlphaVDev->SetBackground( Wallpaper( Color( transparency, transparency, transparency )));
+ int alpha = rBackground.GetColor().GetAlpha();
+ mpAlphaVDev->SetBackground( Wallpaper( Color( alpha, alpha, alpha )));
}
}
diff --git a/vcl/source/outdev/bitmap.cxx b/vcl/source/outdev/bitmap.cxx
index d77b3ddd48c2..e487ac6802af 100644
--- a/vcl/source/outdev/bitmap.cxx
+++ b/vcl/source/outdev/bitmap.cxx
@@ -767,9 +767,8 @@ namespace
aSrcCol = pP->GetColor( nMapY, nMapX );
aDstCol = pB->GetColor( nY, nX );
- // vcl stores transparency, not alpha - invert it
- const sal_uInt8 nSrcAlpha = 255 - pA->GetPixelIndex( nMapY, nMapX );
- const sal_uInt8 nDstAlpha = 255 - pAlphaW->GetPixelIndex( nY, nX );
+ const sal_uInt8 nSrcAlpha = pA->GetPixelIndex( nMapY, nMapX );
+ const sal_uInt8 nDstAlpha = pAlphaW->GetPixelIndex( nY, nX );
// Perform porter-duff compositing 'over' operation
@@ -849,9 +848,9 @@ Bitmap OutputDevice::BlendBitmapWithAlpha(
nVCLBLut[ ( nVCLLut[ aDstCol.GetBlue() ] + nD ) >> 16 ] ) );
pW->SetPixelOnData( pScanline, nX, aIndex );
- aIndex.SetIndex( static_cast<sal_uInt8>( nVCLRLut[ ( nVCLLut[ 255-nResAlpha ] + nD ) >> 16 ] +
- nVCLGLut[ ( nVCLLut[ 255-nResAlpha ] + nD ) >> 16 ] +
- nVCLBLut[ ( nVCLLut[ 255-nResAlpha ] + nD ) >> 16 ] ) );
+ aIndex.SetIndex( static_cast<sal_uInt8>( nVCLRLut[ ( nVCLLut[ nResAlpha ] + nD ) >> 16 ] +
+ nVCLGLut[ ( nVCLLut[ nResAlpha ] + nD ) >> 16 ] +
+ nVCLBLut[ ( nVCLLut[ nResAlpha ] + nD ) >> 16 ] ) );
pAlphaW->SetPixelOnData( pScanlineAlpha, nX, aIndex );
}
}
@@ -877,7 +876,7 @@ Bitmap OutputDevice::BlendBitmapWithAlpha(
aDstCol = AlphaBlend( nX, nY, nMapX, nMapY, pP, pA, pB.get(), pAlphaW.get(), nResAlpha );
pB->SetPixelOnData(pScanlineB, nX, pB->GetBestMatchingColor(aDstCol));
- pAlphaW->SetPixelOnData(pScanlineAlpha, nX, pB->GetBestMatchingColor(Color(255L-nResAlpha, 255L-nResAlpha, 255L-nResAlpha)));
+ pAlphaW->SetPixelOnData(pScanlineAlpha, nX, pB->GetBestMatchingColor(Color(nResAlpha, nResAlpha, nResAlpha)));
}
}
}
@@ -944,7 +943,7 @@ Bitmap OutputDevice::BlendBitmap(
const sal_uLong nD = nVCLDitherLut[ nModY | ( nOutX & 0x0FL ) ];
aDstCol = pB->GetColor( nY, nX );
- aDstCol.Merge( pP->GetColor( nMapY, nMapX ), pA->GetIndexFromData( pScanlineAlpha, nMapX ) );
+ aDstCol.Merge( pP->GetColor( nMapY, nMapX ), 255 - pA->GetIndexFromData( pScanlineAlpha, nMapX ) );
aIndex.SetIndex( static_cast<sal_uInt8>( nVCLRLut[ ( nVCLLut[ aDstCol.GetRed() ] + nD ) >> 16 ] +
nVCLGLut[ ( nVCLLut[ aDstCol.GetGreen() ] + nD ) >> 16 ] +
nVCLBLut[ ( nVCLLut[ aDstCol.GetBlue() ] + nD ) >> 16 ] ) );
diff --git a/vcl/source/outdev/bitmapex.cxx b/vcl/source/outdev/bitmapex.cxx
index 9935a18bdee6..e849f4b73181 100644
--- a/vcl/source/outdev/bitmapex.cxx
+++ b/vcl/source/outdev/bitmapex.cxx
@@ -314,7 +314,7 @@ bool OutputDevice::DrawTransformBitmapExDirect(
else if (mpAlphaVDev)
{
aAlphaBitmap = AlphaMask(rBitmapEx.GetSizePixel());
- aAlphaBitmap.Erase(COL_BLACK); // opaque
+ aAlphaBitmap.Erase(COL_ALPHA_OPAQUE);
}
SalBitmap* pSalAlphaBmp = aAlphaBitmap.ImplGetSalBitmap().get();
@@ -516,8 +516,8 @@ void OutputDevice::DrawTransformedBitmapEx(
}
}
// Apply the alpha manually.
- sal_uInt8 nColor( static_cast<sal_uInt8>( ::basegfx::fround( 255.0*(1.0 - fAlpha) + .5) ) );
- AlphaMask aAlpha( bitmapEx.GetSizePixel(), &nColor );
+ sal_uInt8 nTransparency( static_cast<sal_uInt8>( ::basegfx::fround( 255.0*(1.0 - fAlpha) + .5) ) );
+ AlphaMask aAlpha( bitmapEx.GetSizePixel(), &nTransparency );
if( bitmapEx.IsAlpha())
aAlpha.BlendWith( bitmapEx.GetAlphaMask());
bitmapEx = BitmapEx( bitmapEx.GetBitmap(), aAlpha );
diff --git a/vcl/source/outdev/fill.cxx b/vcl/source/outdev/fill.cxx
index bbe6270632dc..c684595fb261 100644
--- a/vcl/source/outdev/fill.cxx
+++ b/vcl/source/outdev/fill.cxx
@@ -70,7 +70,7 @@ void OutputDevice::SetFillColor( const Color& rColor )
}
if( mpAlphaVDev )
- mpAlphaVDev->SetFillColor( COL_BLACK );
+ mpAlphaVDev->SetFillColor( COL_ALPHA_OPAQUE );
}
void OutputDevice::InitFillColor()
diff --git a/vcl/source/outdev/font.cxx b/vcl/source/outdev/font.cxx
index b62c037a2db7..4198cf334a15 100644
--- a/vcl/source/outdev/font.cxx
+++ b/vcl/source/outdev/font.cxx
@@ -92,7 +92,7 @@ void OutputDevice::SetFont( const vcl::Font& rNewFont )
// with COL_BLACK)
if( aFont.GetColor() != COL_TRANSPARENT )
{
- mpAlphaVDev->SetTextColor( COL_BLACK );
+ mpAlphaVDev->SetTextColor( COL_ALPHA_OPAQUE );
aFont.SetColor( COL_TRANSPARENT );
}
diff --git a/vcl/source/outdev/gradient.cxx b/vcl/source/outdev/gradient.cxx
index bbedf0256397..53dbec354d20 100644
--- a/vcl/source/outdev/gradient.cxx
+++ b/vcl/source/outdev/gradient.cxx
@@ -147,7 +147,7 @@ void OutputDevice::DrawGradient( const tools::PolyPolygon& rPolyPoly,
if( mpAlphaVDev )
{
const Color aFillCol( mpAlphaVDev->GetFillColor() );
- mpAlphaVDev->SetFillColor( COL_BLACK );
+ mpAlphaVDev->SetFillColor( COL_ALPHA_OPAQUE );
mpAlphaVDev->DrawPolyPolygon( rPolyPoly );
mpAlphaVDev->SetFillColor( aFillCol );
}
diff --git a/vcl/source/outdev/line.cxx b/vcl/source/outdev/line.cxx
index f641c338fdfa..7a5611d71d6b 100644
--- a/vcl/source/outdev/line.cxx
+++ b/vcl/source/outdev/line.cxx
@@ -79,7 +79,7 @@ void OutputDevice::SetLineColor( const Color& rColor )
}
if( mpAlphaVDev )
- mpAlphaVDev->SetLineColor( COL_BLACK );
+ mpAlphaVDev->SetLineColor( COL_ALPHA_OPAQUE );
}
void OutputDevice::InitLineColor()
diff --git a/vcl/source/outdev/pixel.cxx b/vcl/source/outdev/pixel.cxx
index dcb86f27cab8..8c97aeb43237 100644
--- a/vcl/source/outdev/pixel.cxx
+++ b/vcl/source/outdev/pixel.cxx
@@ -44,7 +44,7 @@ Color OutputDevice::GetPixel(const Point& rPoint) const
if (mpAlphaVDev)
{
Color aAlphaColor = mpAlphaVDev->GetPixel(rPoint);
- aColor.SetAlpha(255 - aAlphaColor.GetBlue());
+ aColor.SetAlpha(aAlphaColor.GetBlue());
}
}
}
@@ -110,7 +110,7 @@ void OutputDevice::DrawPixel( const Point& rPt, const Color& rColor )
if (mpAlphaVDev)
{
- Color aAlphaColor(255 - rColor.GetAlpha(), 255 - rColor.GetAlpha(), 255 - rColor.GetAlpha());
+ Color aAlphaColor(rColor.GetAlpha(), rColor.GetAlpha(), rColor.GetAlpha());
mpAlphaVDev->DrawPixel(rPt, aAlphaColor);
}
}
diff --git a/vcl/source/outdev/text.cxx b/vcl/source/outdev/text.cxx
index 435110ab5bdd..823eecb39bfe 100644
--- a/vcl/source/outdev/text.cxx
+++ b/vcl/source/outdev/text.cxx
@@ -728,7 +728,7 @@ void OutputDevice::SetTextColor( const Color& rColor )
}
if( mpAlphaVDev )
- mpAlphaVDev->SetTextColor( COL_BLACK );
+ mpAlphaVDev->SetTextColor( COL_ALPHA_OPAQUE );
}
void OutputDevice::SetTextFillColor()
@@ -760,7 +760,7 @@ void OutputDevice::SetTextFillColor( const Color& rColor )
maFont.SetTransparent( rColor.IsTransparent() );
if( mpAlphaVDev )
- mpAlphaVDev->SetTextFillColor( COL_BLACK );
+ mpAlphaVDev->SetTextFillColor( COL_ALPHA_OPAQUE );
}
Color OutputDevice::GetTextFillColor() const
diff --git a/vcl/source/outdev/textline.cxx b/vcl/source/outdev/textline.cxx
index 98f737c62647..d9c085aa97e3 100644
--- a/vcl/source/outdev/textline.cxx
+++ b/vcl/source/outdev/textline.cxx
@@ -913,7 +913,7 @@ void OutputDevice::SetTextLineColor( const Color& rColor )
maTextLineColor = aColor;
if( mpAlphaVDev )
- mpAlphaVDev->SetTextLineColor( COL_BLACK );
+ mpAlphaVDev->SetTextLineColor( COL_ALPHA_OPAQUE );
}
void OutputDevice::SetOverlineColor()
@@ -938,7 +938,7 @@ void OutputDevice::SetOverlineColor( const Color& rColor )
maOverlineColor = aColor;
if( mpAlphaVDev )
- mpAlphaVDev->SetOverlineColor( COL_BLACK );
+ mpAlphaVDev->SetOverlineColor( COL_ALPHA_OPAQUE );
}
void OutputDevice::DrawTextLine( const Point& rPos, tools::Long nWidth,
diff --git a/vcl/source/outdev/transparent.cxx b/vcl/source/outdev/transparent.cxx
index 793b26e2e581..29404aa84f6f 100644
--- a/vcl/source/outdev/transparent.cxx
+++ b/vcl/source/outdev/transparent.cxx
@@ -30,6 +30,7 @@
#include <vcl/settings.hxx>
#include <vcl/svapp.hxx>
#include <vcl/virdev.hxx>
+#include <vcl/skia/SkiaHelper.hxx>
#include <bitmap/BitmapWriteAccess.hxx>
#include <pdf/pdfwriter_impl.hxx>
@@ -549,9 +550,8 @@ void OutputDevice::DrawTransparent( const tools::PolyPolygon& rPolyPoly,
if( mpAlphaVDev )
{
const Color aFillCol( mpAlphaVDev->GetFillColor() );
- mpAlphaVDev->SetFillColor( Color(sal::static_int_cast<sal_uInt8>(255*nTransparencePercent/100),
- sal::static_int_cast<sal_uInt8>(255*nTransparencePercent/100),
- sal::static_int_cast<sal_uInt8>(255*nTransparencePercent/100)) );
+ sal_uInt8 nAlpha = 255 - sal::static_int_cast<sal_uInt8>(255*nTransparencePercent/100);
+ mpAlphaVDev->SetFillColor( Color(nAlpha, nAlpha, nAlpha) );
mpAlphaVDev->DrawTransparent( rPolyPoly, nTransparencePercent );
@@ -602,7 +602,7 @@ void OutputDevice::DrawTransparent( const GDIMetaFile& rMtf, const Point& rPos,
xVDev->mnDPIX = mnDPIX;
xVDev->mnDPIY = mnDPIY;
- if( xVDev->SetOutputSizePixel( aDstRect.GetSize() ) )
+ if( xVDev->SetOutputSizePixel( aDstRect.GetSize(), true, true ) )
{
if(GetAntialiasing() != AntialiasingFlags::NONE)
{
@@ -641,7 +641,7 @@ void OutputDevice::DrawTransparent( const GDIMetaFile& rMtf, const Point& rPos,
// get content bitmap from buffer
xVDev->EnableMapMode(false);
- const Bitmap aPaint(xVDev->GetBitmap(aPoint, xVDev->GetOutputSizePixel()));
+ const BitmapEx aPaint(xVDev->GetBitmapEx(aPoint, xVDev->GetOutputSizePixel()));
// create alpha mask from gradient and get as Bitmap
xVDev->EnableMapMode(bBufferMapModeEnabled);
@@ -650,12 +650,26 @@ void OutputDevice::DrawTransparent( const GDIMetaFile& rMtf, const Point& rPos,
xVDev->SetDrawMode(DrawModeFlags::Default);
xVDev->EnableMapMode(false);
- const AlphaMask aAlpha(xVDev->GetBitmap(aPoint, xVDev->GetOutputSizePixel()));
+ AlphaMask aAlpha(xVDev->GetBitmap(aPoint, xVDev->GetOutputSizePixel()));
+ AlphaMask aPaintAlpha(aPaint.GetAlphaMask());
+#if HAVE_FEATURE_SKIA
+ // One of the alpha masks is inverted from what
+ // is expected so invert it again
+ if ( SkiaHelper::isVCLSkiaEnabled() )
+ {
+ aAlpha.Invert(); // convert to alpha
+ }
+ else
+#endif
+ {
+ aPaintAlpha.Invert(); // convert to alpha
+ }
+ aAlpha.BlendWith(aPaintAlpha);
xVDev.disposeAndClear();
// draw masked content to target and restore MapMode
- DrawBitmapEx(aDstRect.TopLeft(), BitmapEx(aPaint, aAlpha));
+ DrawBitmapEx(aDstRect.TopLeft(), BitmapEx(aPaint.GetBitmap(), aAlpha));
EnableMapMode(bOrigMapModeEnabled);
}
else
@@ -683,7 +697,20 @@ void OutputDevice::DrawTransparent( const GDIMetaFile& rMtf, const Point& rPos,
xVDev->EnableMapMode( false );
AlphaMask aAlpha(xVDev->GetBitmap(Point(), xVDev->GetOutputSizePixel()));
- aAlpha.BlendWith(aPaint.GetAlphaMask());
+ AlphaMask aPaintAlpha(aPaint.GetAlphaMask());
+#if HAVE_FEATURE_SKIA
+ // One of the alpha masks is inverted from what
+ // is expected so invert it again
+ if ( SkiaHelper::isVCLSkiaEnabled() )
+ {
+ aAlpha.Invert(); // convert to alpha
+ }
+ else
+#endif
+ {
+ aPaintAlpha.Invert(); // convert to alpha
+ }
+ aAlpha.BlendWith(aPaintAlpha);
xVDev.disposeAndClear();
diff --git a/vcl/source/rendercontext/drawmode.cxx b/vcl/source/rendercontext/drawmode.cxx
index 995017c1f5b1..ab3b36e0223d 100644
--- a/vcl/source/rendercontext/drawmode.cxx
+++ b/vcl/source/rendercontext/drawmode.cxx
@@ -262,7 +262,9 @@ BitmapEx GetBitmapEx(BitmapEx const& rBitmapEx, DrawModeFlags nDrawMode)
// DRAWMODE_BLACK/WHITEBITMAP requires monochrome output, having alpha-induced
// grey levels is not acceptable
BitmapEx aMaskEx(aBmpEx.GetAlphaMask().GetBitmap());
+ aMaskEx.Invert(); // convert to transparency
BitmapFilter::Filter(aMaskEx, BitmapMonochromeFilter(129));
+ aMaskEx.Invert(); // convert to alpha
aBmpEx = BitmapEx(aColorBmp, aMaskEx.GetBitmap());
}
else
diff --git a/vcl/win/gdi/salbmp.cxx b/vcl/win/gdi/salbmp.cxx
index 18997f650a92..26e3537f09eb 100644
--- a/vcl/win/gdi/salbmp.cxx
+++ b/vcl/win/gdi/salbmp.cxx
@@ -385,7 +385,7 @@ std::shared_ptr<Gdiplus::Bitmap> WinSalBitmap::ImplCreateGdiPlusBitmap(const Win
*targetPixels++ = *pSrcRGB++;
*targetPixels++ = *pSrcRGB++;
*targetPixels++ = *pSrcRGB++;
- *targetPixels++ = 0xff - *pSrcA++;
+ *targetPixels++ = *pSrcA++;
}
pSrcRGB += nExtraRGB;