diff options
author | Xisco Fauli <xiscofauli@libreoffice.org> | 2024-04-10 18:05:00 +0200 |
---|---|---|
committer | Xisco Fauli <xiscofauli@libreoffice.org> | 2024-04-12 10:47:56 +0200 |
commit | 732ca4879b7e49b171c5930166e4dba7be451841 (patch) | |
tree | dc9b7fa7a3c65885739f988e0d1c0897d764c239 /vcl/source/bitmap/BitmapTools.cxx | |
parent | 51abf44808c6793a184e986b62c0786753e11ded (diff) |
tdf#159660: Add support for screen mode in feBlend
Change-Id: Iefe655a370cca930319290baa2a25d791371f55c
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/165958
Tested-by: Jenkins
Reviewed-by: Xisco Fauli <xiscofauli@libreoffice.org>
Diffstat (limited to 'vcl/source/bitmap/BitmapTools.cxx')
-rw-r--r-- | vcl/source/bitmap/BitmapTools.cxx | 121 |
1 files changed, 120 insertions, 1 deletions
diff --git a/vcl/source/bitmap/BitmapTools.cxx b/vcl/source/bitmap/BitmapTools.cxx index 2330483bb98b..41f8ff38992c 100644 --- a/vcl/source/bitmap/BitmapTools.cxx +++ b/vcl/source/bitmap/BitmapTools.cxx @@ -512,6 +512,126 @@ BitmapEx CanvasTransformBitmap( const BitmapEx& rBitmap, return BitmapEx(aDstBitmap, AlphaMask(aDstAlpha)); } +BitmapEx DrawBitmapInRect( const BitmapEx& rBitmap, + ::basegfx::B2DRectangle const & rBitmapRect, + ::basegfx::B2DRectangle const & rDestRect ) +{ + if( rBitmapRect.isEmpty() || rDestRect.isEmpty() ) + return BitmapEx(); + + const Size aDestBmpSize( ::basegfx::fround( rDestRect.getWidth() ), + ::basegfx::fround( rDestRect.getHeight() ) ); + + Bitmap aSrcBitmap( rBitmap.GetBitmap() ); + Bitmap aSrcAlpha; + + // differentiate mask and alpha channel (on-off + // vs. multi-level transparency) + if( rBitmap.IsAlpha() ) + { + aSrcAlpha = rBitmap.GetAlphaMask().GetBitmap(); + } + + BitmapScopedReadAccess pReadAccess( aSrcBitmap ); + BitmapScopedReadAccess pAlphaReadAccess; + if (rBitmap.IsAlpha()) + pAlphaReadAccess = aSrcAlpha; + + if( !pReadAccess || (!pAlphaReadAccess && rBitmap.IsAlpha()) ) + { + // TODO(E2): Error handling! + ENSURE_OR_THROW( false, + "DrawBitmapInRect(): could not access source bitmap" ); + } + + // mapping table, to translate pAlphaReadAccess' pixel + // values into destination alpha values (needed e.g. for + // paletted 1-bit masks). + sal_uInt8 aAlphaMap[256]; + + if( rBitmap.IsAlpha() ) + { + // source already has alpha channel - 1:1 mapping, + // i.e. aAlphaMap[0]=0,...,aAlphaMap[255]=255. + sal_uInt8 val=0; + sal_uInt8* pCur=aAlphaMap; + sal_uInt8* const pEnd=&aAlphaMap[256]; + while(pCur != pEnd) + *pCur++ = val++; + } + // else: mapping table is not used + + Bitmap aDstBitmap(aDestBmpSize, aSrcBitmap.getPixelFormat(), &pReadAccess->GetPalette()); + Bitmap aDstAlpha( AlphaMask( aDestBmpSize ).GetBitmap() ); + + { + // just to be on the safe side: let the + // ScopedAccessors get destructed before + // copy-constructing the resulting bitmap. This will + // rule out the possibility that cached accessor data + // is not yet written back. + BitmapScopedWriteAccess pWriteAccess( aDstBitmap ); + BitmapScopedWriteAccess pAlphaWriteAccess( aDstAlpha ); + + + if( pWriteAccess.get() != nullptr && + pAlphaWriteAccess.get() != nullptr) + { + // for the time being, always read as ARGB + for (tools::Long y(rDestRect.getMinY()); y < rDestRect.getMaxY(); y++) + { + // differentiate mask and alpha channel (on-off + // vs. multi-level transparency) + if( rBitmap.IsAlpha() ) + { + Scanline pScan = pWriteAccess->GetScanline( y - rDestRect.getMinY() ); + Scanline pScanAlpha = pAlphaWriteAccess->GetScanline( y - rDestRect.getMinY() ); + // Handling alpha and mask just the same... + for (tools::Long x(rDestRect.getMinX()); x < rDestRect.getMaxX(); x++) + { + if (rBitmapRect.getMinX() <= x && rBitmapRect.getMaxX() > x && rBitmapRect.getMinY() <= y + && rBitmapRect.getMaxY() > y) + { + const sal_uInt8 cAlphaIdx = pAlphaReadAccess->GetPixelIndex( x - rBitmapRect.getMinX(), y - rBitmapRect.getMinY() ); + pAlphaWriteAccess->SetPixelOnData( pScanAlpha, x - rDestRect.getMinX(), BitmapColor(aAlphaMap[ cAlphaIdx ]) ); + pWriteAccess->SetPixelOnData( pScan, x - rDestRect.getMinX(), pReadAccess->GetPixel( x - rBitmapRect.getMinX(), y - rBitmapRect.getMinY() ) ); + } + else + { + pAlphaWriteAccess->SetPixelOnData( pScanAlpha, x - rDestRect.getMinX(), BitmapColor(0) ); + } + } + } + else + { + Scanline pScan = pWriteAccess->GetScanline( y - rDestRect.getMinY() ); + Scanline pScanAlpha = pAlphaWriteAccess->GetScanline( y - rDestRect.getMinY() ); + for (tools::Long x(rDestRect.getMinX()); x < rDestRect.getMaxX(); x++) + { + if (rBitmapRect.getMinX() <= x && rBitmapRect.getMaxX() > x && rBitmapRect.getMinY() <= y + && rBitmapRect.getMaxY() > y) + { + pAlphaWriteAccess->SetPixelOnData( pScanAlpha, x - rDestRect.getMinX(), BitmapColor(255) ); + pWriteAccess->SetPixelOnData( pScan, x - rDestRect.getMinX(), pReadAccess->GetPixel( x - rBitmapRect.getMinX(), y - rBitmapRect.getMinY() ) ); + } + else + { + pAlphaWriteAccess->SetPixelOnData( pScanAlpha, x - rDestRect.getMinX(), BitmapColor(0) ); + } + } + } + } + } + else + { + // TODO(E2): Error handling! + ENSURE_OR_THROW( false, + "DrawBitmapInRect(): could not access bitmap" ); + } + } + + return BitmapEx(aDstBitmap, AlphaMask(aDstAlpha)); +} void DrawAlphaBitmapAndAlphaGradient(BitmapEx & rBitmapEx, bool bFixedTransparence, float fTransparence, AlphaMask & rNewMask) { @@ -644,7 +764,6 @@ void DrawAndClipBitmap(const Point& rPos, const Size& rSize, const BitmapEx& rBi } } - css::uno::Sequence< sal_Int8 > GetMaskDIB(BitmapEx const & aBmpEx) { if ( aBmpEx.IsAlpha() ) |