diff options
author | Noel Grandin <noel.grandin@collabora.co.uk> | 2018-03-16 14:58:59 +0200 |
---|---|---|
committer | Noel Grandin <noel.grandin@collabora.co.uk> | 2018-03-16 19:25:48 +0100 |
commit | 5b75a1697250d8b2b6003c37067f39270a5ad828 (patch) | |
tree | 14d1fddc6f14707c64c220ee738e25567037de18 /vcl | |
parent | 92dc87cbac74c1be260534b5e38088c44515a47b (diff) |
move cairo extract bitmap code from canvas to vcl
part of making GetMask/GetAlpha an internal detail of vcl
Change-Id: I45c2e9fdae08d7f444a64e8e04a6f65bb525cbd1
Reviewed-on: https://gerrit.libreoffice.org/51417
Tested-by: Jenkins <ci@libreoffice.org>
Reviewed-by: Noel Grandin <noel.grandin@collabora.co.uk>
Diffstat (limited to 'vcl')
-rw-r--r-- | vcl/source/bitmap/BitmapTools.cxx | 291 |
1 files changed, 291 insertions, 0 deletions
diff --git a/vcl/source/bitmap/BitmapTools.cxx b/vcl/source/bitmap/BitmapTools.cxx index 3abd1ca537b9..816bad119e13 100644 --- a/vcl/source/bitmap/BitmapTools.cxx +++ b/vcl/source/bitmap/BitmapTools.cxx @@ -648,6 +648,297 @@ css::uno::Sequence< sal_Int8 > GetMaskDIB(BitmapEx const & aBmpEx) return css::uno::Sequence< sal_Int8 >(); } +static sal_uInt8 lcl_GetColor(BitmapColor const& rColor) +{ + sal_uInt8 nTemp(0); + if (rColor.IsIndex()) + { + nTemp = rColor.GetIndex(); + } + else + { + nTemp = rColor.GetBlue(); + // greyscale expected here, or what would non-grey colors mean? + assert(rColor.GetRed() == nTemp && rColor.GetGreen() == nTemp); + } + return nTemp; +} + + +static bool readAlpha( BitmapReadAccess const * pAlphaReadAcc, long nY, const long nWidth, unsigned char* data, long nOff ) +{ + bool bIsAlpha = false; + long nX; + int nAlpha; + Scanline pReadScan; + + nOff += 3; + + switch( pAlphaReadAcc->GetScanlineFormat() ) + { + case ScanlineFormat::N8BitTcMask: + pReadScan = pAlphaReadAcc->GetScanline( nY ); + for( nX = 0; nX < nWidth; nX++ ) + { + nAlpha = data[ nOff ] = 255 - ( *pReadScan++ ); + if( nAlpha != 255 ) + bIsAlpha = true; + nOff += 4; + } + break; + case ScanlineFormat::N8BitPal: + pReadScan = pAlphaReadAcc->GetScanline( nY ); + for( nX = 0; nX < nWidth; nX++ ) + { + BitmapColor const& rColor( + pAlphaReadAcc->GetPaletteColor(*pReadScan)); + pReadScan++; + nAlpha = data[ nOff ] = 255 - lcl_GetColor(rColor); + if( nAlpha != 255 ) + bIsAlpha = true; + nOff += 4; + } + break; + default: + 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(); + if( nAlpha != 255 ) + bIsAlpha = true; + nOff += 4; + } + } + + return bIsAlpha; +} + + + +/** + * @param data will be filled with alpha data, if xBitmap is alpha/transparent image + * @param bHasAlpha will be set to true if resulting surface has alpha + **/ +void CanvasCairoExtractBitmapData( BitmapEx & aBmpEx, Bitmap & aBitmap, unsigned char*& data, bool& bHasAlpha ) +{ + AlphaMask aAlpha = aBmpEx.GetAlpha(); + + ::BitmapReadAccess* pBitmapReadAcc = aBitmap.AcquireReadAccess(); + ::BitmapReadAccess* pAlphaReadAcc = nullptr; + const long nWidth = pBitmapReadAcc->Width(); + const long nHeight = pBitmapReadAcc->Height(); + long nX, nY; + bool bIsAlpha = false; + + if( aBmpEx.IsTransparent() || aBmpEx.IsAlpha() ) + pAlphaReadAcc = aAlpha.AcquireReadAccess(); + + data = static_cast<unsigned char*>(malloc( nWidth*nHeight*4 )); + + long nOff = 0; + ::Color aColor; + unsigned int nAlpha = 255; + + for( nY = 0; nY < nHeight; nY++ ) + { + ::Scanline pReadScan; + + switch( pBitmapReadAcc->GetScanlineFormat() ) + { + case ScanlineFormat::N8BitPal: + pReadScan = pBitmapReadAcc->GetScanline( nY ); + if( pAlphaReadAcc ) + if( readAlpha( pAlphaReadAcc, nY, nWidth, data, nOff ) ) + bIsAlpha = true; + + for( nX = 0; nX < nWidth; nX++ ) + { +#ifdef OSL_BIGENDIAN + if( pAlphaReadAcc ) + nAlpha = data[ nOff++ ]; + else + nAlpha = data[ nOff++ ] = 255; +#else + if( pAlphaReadAcc ) + nAlpha = data[ nOff + 3 ]; + else + nAlpha = data[ nOff + 3 ] = 255; +#endif + aColor = pBitmapReadAcc->GetPaletteColor(*pReadScan++).GetColor(); + +#ifdef OSL_BIGENDIAN + data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*( aColor.GetRed() ) )/255 ); + data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*( aColor.GetGreen() ) )/255 ); + data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*( aColor.GetBlue() ) )/255 ); +#else + data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*( aColor.GetBlue() ) )/255 ); + data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*( aColor.GetGreen() ) )/255 ); + data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*( aColor.GetRed() ) )/255 ); + nOff++; +#endif + } + break; + case ScanlineFormat::N24BitTcBgr: + pReadScan = pBitmapReadAcc->GetScanline( nY ); + if( pAlphaReadAcc ) + if( readAlpha( pAlphaReadAcc, nY, nWidth, data, nOff ) ) + bIsAlpha = true; + + for( nX = 0; nX < nWidth; nX++ ) + { +#ifdef OSL_BIGENDIAN + if( pAlphaReadAcc ) + nAlpha = data[ nOff ]; + else + nAlpha = data[ nOff ] = 255; + data[ nOff + 3 ] = sal::static_int_cast<unsigned char>(( nAlpha*( *pReadScan++ ) )/255 ); + data[ nOff + 2 ] = sal::static_int_cast<unsigned char>(( nAlpha*( *pReadScan++ ) )/255 ); + data[ nOff + 1 ] = sal::static_int_cast<unsigned char>(( nAlpha*( *pReadScan++ ) )/255 ); + nOff += 4; +#else + if( pAlphaReadAcc ) + nAlpha = data[ nOff + 3 ]; + else + nAlpha = data[ nOff + 3 ] = 255; + data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*( *pReadScan++ ) )/255 ); + data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*( *pReadScan++ ) )/255 ); + data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*( *pReadScan++ ) )/255 ); + nOff++; +#endif + } + break; + case ScanlineFormat::N24BitTcRgb: + pReadScan = pBitmapReadAcc->GetScanline( nY ); + if( pAlphaReadAcc ) + if( readAlpha( pAlphaReadAcc, nY, nWidth, data, nOff ) ) + bIsAlpha = true; + + for( nX = 0; nX < nWidth; nX++ ) + { +#ifdef OSL_BIGENDIAN + if( pAlphaReadAcc ) + nAlpha = data[ nOff++ ]; + else + nAlpha = data[ nOff++ ] = 255; + data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*( *pReadScan++ ) )/255 ); + data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*( *pReadScan++ ) )/255 ); + data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*( *pReadScan++ ) )/255 ); +#else + if( pAlphaReadAcc ) + nAlpha = data[ nOff + 3 ]; + else + nAlpha = data[ nOff + 3 ] = 255; + data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*( pReadScan[ 2 ] ) )/255 ); + data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*( pReadScan[ 1 ] ) )/255 ); + data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*( pReadScan[ 0 ] ) )/255 ); + pReadScan += 3; + nOff++; +#endif + } + break; + case ScanlineFormat::N32BitTcBgra: + pReadScan = pBitmapReadAcc->GetScanline( nY ); + if( pAlphaReadAcc ) + if( readAlpha( pAlphaReadAcc, nY, nWidth, data, nOff ) ) + bIsAlpha = true; + + for( nX = 0; nX < nWidth; nX++ ) + { +#ifdef OSL_BIGENDIAN + if( pAlphaReadAcc ) + nAlpha = data[ nOff++ ]; + else + nAlpha = data[ nOff++ ] = 255; + data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*( pReadScan[ 2 ] ) )/255 ); + data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*( pReadScan[ 1 ] ) )/255 ); + data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*( pReadScan[ 0 ] ) )/255 ); + pReadScan += 4; +#else + if( pAlphaReadAcc ) + nAlpha = data[ nOff + 3 ]; + else + nAlpha = data[ nOff + 3 ] = 255; + data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*( *pReadScan++ ) )/255 ); + data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*( *pReadScan++ ) )/255 ); + data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*( *pReadScan++ ) )/255 ); + pReadScan++; + nOff++; +#endif + } + break; + case ScanlineFormat::N32BitTcRgba: + pReadScan = pBitmapReadAcc->GetScanline( nY ); + if( pAlphaReadAcc ) + if( readAlpha( pAlphaReadAcc, nY, nWidth, data, nOff ) ) + bIsAlpha = true; + + for( nX = 0; nX < nWidth; nX++ ) + { +#ifdef OSL_BIGENDIAN + if( pAlphaReadAcc ) + nAlpha = data[ nOff ++ ]; + else + nAlpha = data[ nOff ++ ] = 255; + data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*( *pReadScan++ ) )/255 ); + data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*( *pReadScan++ ) )/255 ); + data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*( *pReadScan++ ) )/255 ); + pReadScan++; +#else + if( pAlphaReadAcc ) + nAlpha = data[ nOff + 3 ]; + else + nAlpha = data[ nOff + 3 ] = 255; + data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*( pReadScan[ 2 ] ) )/255 ); + data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*( pReadScan[ 1 ] ) )/255 ); + data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*( pReadScan[ 0 ] ) )/255 ); + pReadScan += 4; + nOff++; +#endif + } + break; + default: + SAL_INFO( "canvas.cairo", "fallback to GetColor - slow, format: " << static_cast<int>(pBitmapReadAcc->GetScanlineFormat()) ); + + if( pAlphaReadAcc ) + if( readAlpha( pAlphaReadAcc, nY, nWidth, data, nOff ) ) + bIsAlpha = true; + + for( nX = 0; nX < nWidth; nX++ ) + { + aColor = pBitmapReadAcc->GetColor( nY, nX ).GetColor(); + + // cairo need premultiplied color values + // TODO(rodo) handle endianness +#ifdef OSL_BIGENDIAN + if( pAlphaReadAcc ) + nAlpha = data[ nOff++ ]; + else + nAlpha = data[ nOff++ ] = 255; + data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*aColor.GetRed() )/255 ); + data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*aColor.GetGreen() )/255 ); + data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*aColor.GetBlue() )/255 ); +#else + if( pAlphaReadAcc ) + nAlpha = data[ nOff + 3 ]; + else + nAlpha = data[ nOff + 3 ] = 255; + data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*aColor.GetBlue() )/255 ); + data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*aColor.GetGreen() )/255 ); + data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*aColor.GetRed() )/255 ); + nOff ++; +#endif + } + } + } + + ::Bitmap::ReleaseAccess( pBitmapReadAcc ); + if( pAlphaReadAcc ) + aAlpha.ReleaseAccess( pAlphaReadAcc ); + + bHasAlpha = bIsAlpha; + +} + }} // end vcl::bitmap /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |