summaryrefslogtreecommitdiff
path: root/vcl
diff options
context:
space:
mode:
authorChris Sherlock <chris.sherlock79@gmail.com>2018-03-01 06:07:39 +1100
committerTomaž Vajngerl <quikee@gmail.com>2018-03-06 05:08:19 +0100
commitbdd62b4c327ab894dbba00fe2e07696c1b7d9de6 (patch)
treee6da9e7783142a37b0edf190946688a8073a5a65 /vcl
parent221b17794c1cb15ce7f5a0b5a543fc79eee7085f (diff)
vcl: split painting bitmap functions to bitmappaint.cxx
Change-Id: Ib5f52e4b7b5121de15cdb205165fcbdb8b09bc8a Reviewed-on: https://gerrit.libreoffice.org/50530 Tested-by: Jenkins <ci@libreoffice.org> Reviewed-by: Tomaž Vajngerl <quikee@gmail.com>
Diffstat (limited to 'vcl')
-rw-r--r--vcl/Library_vcl.mk3
-rw-r--r--vcl/source/bitmap/bitmap.cxx1088
-rw-r--r--vcl/source/bitmap/bitmappaint.cxx1158
3 files changed, 1164 insertions, 1085 deletions
diff --git a/vcl/Library_vcl.mk b/vcl/Library_vcl.mk
index b116fd15705a..9e292916f843 100644
--- a/vcl/Library_vcl.mk
+++ b/vcl/Library_vcl.mk
@@ -300,8 +300,9 @@ $(eval $(call gb_Library_add_exception_objects,vcl,\
vcl/source/gdi/wall \
vcl/source/gdi/scrptrun \
vcl/source/gdi/CommonSalLayout \
- vcl/source/bitmap/bitmap \
+ vcl/source/bitmap/bitmap \
vcl/source/bitmap/bitmapfilter \
+ vcl/source/bitmap/bitmappaint \
vcl/source/bitmap/bitmapscalesuper \
vcl/source/bitmap/BitmapScaleConvolution \
vcl/source/bitmap/BitmapSymmetryCheck \
diff --git a/vcl/source/bitmap/bitmap.cxx b/vcl/source/bitmap/bitmap.cxx
index bf670f20ffce..b5602327f75d 100644
--- a/vcl/source/bitmap/bitmap.cxx
+++ b/vcl/source/bitmap/bitmap.cxx
@@ -17,20 +17,15 @@
* the License at http://www.apache.org/licenses/LICENSE-2.0 .
*/
-#include <algorithm>
-#include <rtl/crc.h>
-#include <tools/stream.hxx>
-#include <tools/poly.hxx>
-#include <vcl/salbtype.hxx>
+#include <osl/diagnose.h>
+#include <vcl/bitmap.hxx>
#include <vcl/bitmapaccess.hxx>
#include <vcl/outdev.hxx>
-#include <vcl/bitmap.hxx>
-#include <vcl/bitmapex.hxx>
-#include <vcl/svapp.hxx>
-#include <vcl/image.hxx>
#include <impbmp.hxx>
#include <salbmp.hxx>
+
+#include <algorithm>
#include <memory>
Bitmap::Bitmap()
@@ -377,366 +372,6 @@ void Bitmap::ReleaseAccess( BitmapInfoAccess* pBitmapAccess )
delete pBitmapAccess;
}
-bool Bitmap::Erase(const Color& rFillColor)
-{
- if (IsEmpty())
- return true;
-
- Bitmap::ScopedWriteAccess pWriteAcc(*this);
- bool bRet = false;
-
- if (pWriteAcc)
- {
- const ScanlineFormat nFormat = pWriteAcc->GetScanlineFormat();
- sal_uInt8 cIndex = 0;
- bool bFast = false;
-
- switch (nFormat)
- {
- case ScanlineFormat::N1BitMsbPal:
- case ScanlineFormat::N1BitLsbPal:
- {
- cIndex = static_cast<sal_uInt8>(pWriteAcc->GetBestPaletteIndex(rFillColor));
- cIndex = (cIndex ? 255 : 0);
- bFast = true;
- }
- break;
-
- case ScanlineFormat::N4BitMsnPal:
- case ScanlineFormat::N4BitLsnPal:
- {
- cIndex = static_cast<sal_uInt8>(pWriteAcc->GetBestPaletteIndex(rFillColor));
- cIndex = cIndex | ( cIndex << 4 );
- bFast = true;
- }
- break;
-
- case ScanlineFormat::N8BitPal:
- {
- cIndex = static_cast<sal_uInt8>(pWriteAcc->GetBestPaletteIndex(rFillColor));
- bFast = true;
- }
- break;
-
- case ScanlineFormat::N24BitTcBgr:
- case ScanlineFormat::N24BitTcRgb:
- {
- if (rFillColor.GetRed() == rFillColor.GetGreen() &&
- rFillColor.GetRed() == rFillColor.GetBlue())
- {
- cIndex = rFillColor.GetRed();
- bFast = true;
- }
- else
- bFast = false;
- }
- break;
-
- default:
- bFast = false;
- break;
- }
-
- if( bFast )
- {
- const sal_uLong nBufSize = pWriteAcc->GetScanlineSize() * pWriteAcc->Height();
- memset( pWriteAcc->GetBuffer(), cIndex, nBufSize );
- }
- else
- {
- const tools::Rectangle aRect( Point(), Size( pWriteAcc->Width(), pWriteAcc->Height() ) );
- pWriteAcc->SetFillColor( rFillColor );
- pWriteAcc->FillRect( aRect );
- }
-
- bRet = true;
- }
-
- return bRet;
-}
-
-bool Bitmap::Invert()
-{
- ScopedWriteAccess pAcc(*this);
- bool bRet = false;
-
- if( pAcc )
- {
- if( pAcc->HasPalette() )
- {
- BitmapPalette aBmpPal( pAcc->GetPalette() );
- const sal_uInt16 nCount = aBmpPal.GetEntryCount();
-
- for( sal_uInt16 i = 0; i < nCount; i++ )
- aBmpPal[ i ].Invert();
-
- pAcc->SetPalette( aBmpPal );
- }
- else
- {
- const long nWidth = pAcc->Width();
- const long nHeight = pAcc->Height();
-
- for( long nY = 0; nY < nHeight; nY++ )
- {
- Scanline pScanline = pAcc->GetScanline(nY);
- for( long nX = 0; nX < nWidth; nX++ )
- pAcc->SetPixelOnData( pScanline, nX, pAcc->GetPixelFromData( pScanline, nX ).Invert() );
- }
- }
-
- mxImpBmp->ImplInvalidateChecksum();
- pAcc.reset();
- bRet = true;
- }
-
- return bRet;
-}
-
-bool Bitmap::Mirror( BmpMirrorFlags nMirrorFlags )
-{
- bool bHorz( nMirrorFlags & BmpMirrorFlags::Horizontal );
- bool bVert( nMirrorFlags & BmpMirrorFlags::Vertical );
- bool bRet = false;
-
- if( bHorz && !bVert )
- {
- ScopedWriteAccess pAcc(*this);
-
- if( pAcc )
- {
- const long nWidth = pAcc->Width();
- const long nHeight = pAcc->Height();
- const long nWidth1 = nWidth - 1;
- const long nWidth_2 = nWidth >> 1;
-
- for( long nY = 0; nY < nHeight; nY++ )
- {
- Scanline pScanline = pAcc->GetScanline(nY);
- for( long nX = 0, nOther = nWidth1; nX < nWidth_2; nX++, nOther-- )
- {
- const BitmapColor aTemp( pAcc->GetPixelFromData( pScanline, nX ) );
-
- pAcc->SetPixelOnData( pScanline, nX, pAcc->GetPixelFromData( pScanline, nOther ) );
- pAcc->SetPixelOnData( pScanline, nOther, aTemp );
- }
- }
-
- pAcc.reset();
- bRet = true;
- }
- }
- else if( bVert && !bHorz )
- {
- ScopedWriteAccess pAcc(*this);
-
- if( pAcc )
- {
- const long nScanSize = pAcc->GetScanlineSize();
- std::unique_ptr<sal_uInt8[]> pBuffer(new sal_uInt8[ nScanSize ]);
- const long nHeight = pAcc->Height();
- const long nHeight1 = nHeight - 1;
- const long nHeight_2 = nHeight >> 1;
-
- for( long nY = 0, nOther = nHeight1; nY < nHeight_2; nY++, nOther-- )
- {
- memcpy( pBuffer.get(), pAcc->GetScanline( nY ), nScanSize );
- memcpy( pAcc->GetScanline( nY ), pAcc->GetScanline( nOther ), nScanSize );
- memcpy( pAcc->GetScanline( nOther ), pBuffer.get(), nScanSize );
- }
-
- pAcc.reset();
- bRet = true;
- }
- }
- else if( bHorz && bVert )
- {
- ScopedWriteAccess pAcc(*this);
-
- if( pAcc )
- {
- const long nWidth = pAcc->Width();
- const long nWidth1 = nWidth - 1;
- const long nHeight = pAcc->Height();
- long nHeight_2 = nHeight >> 1;
-
- for( long nY = 0, nOtherY = nHeight - 1; nY < nHeight_2; nY++, nOtherY-- )
- {
- Scanline pScanline = pAcc->GetScanline(nY);
- Scanline pScanlineOther = pAcc->GetScanline(nOtherY);
- for( long nX = 0, nOtherX = nWidth1; nX < nWidth; nX++, nOtherX-- )
- {
- const BitmapColor aTemp( pAcc->GetPixelFromData( pScanline, nX ) );
-
- pAcc->SetPixelOnData( pScanline, nX, pAcc->GetPixelFromData( pScanlineOther, nOtherX ) );
- pAcc->SetPixelOnData( pScanlineOther, nOtherX, aTemp );
- }
- }
-
- // if necessary, also mirror the middle line horizontally
- if( nHeight & 1 )
- {
- Scanline pScanline = pAcc->GetScanline(nHeight_2);
- for( long nX = 0, nOtherX = nWidth1, nWidth_2 = nWidth >> 1; nX < nWidth_2; nX++, nOtherX-- )
- {
- const BitmapColor aTemp( pAcc->GetPixelFromData( pScanline, nX ) );
- pAcc->SetPixelOnData( pScanline, nX, pAcc->GetPixelFromData( pScanline, nOtherX ) );
- pAcc->SetPixelOnData( pScanline, nOtherX, aTemp );
- }
- }
-
- pAcc.reset();
- bRet = true;
- }
- }
- else
- bRet = true;
-
- return bRet;
-}
-
-bool Bitmap::Rotate( long nAngle10, const Color& rFillColor )
-{
- bool bRet = false;
-
- nAngle10 %= 3600;
- nAngle10 = ( nAngle10 < 0 ) ? ( 3599L + nAngle10 ) : nAngle10;
-
- if( !nAngle10 )
- bRet = true;
- else if( 1800 == nAngle10 )
- bRet = Mirror( BmpMirrorFlags::Horizontal | BmpMirrorFlags::Vertical );
- else
- {
- ScopedReadAccess pReadAcc(*this);
- Bitmap aRotatedBmp;
-
- if( pReadAcc )
- {
- const Size aSizePix( GetSizePixel() );
-
- if( ( 900 == nAngle10 ) || ( 2700 == nAngle10 ) )
- {
- const Size aNewSizePix( aSizePix.Height(), aSizePix.Width() );
- Bitmap aNewBmp( aNewSizePix, GetBitCount(), &pReadAcc->GetPalette() );
- ScopedWriteAccess pWriteAcc(aNewBmp);
-
- if( pWriteAcc )
- {
- const long nWidth = aSizePix.Width();
- const long nWidth1 = nWidth - 1;
- const long nHeight = aSizePix.Height();
- const long nHeight1 = nHeight - 1;
- const long nNewWidth = aNewSizePix.Width();
- const long nNewHeight = aNewSizePix.Height();
-
- if( 900 == nAngle10 )
- {
- for( long nY = 0, nOtherX = nWidth1; nY < nNewHeight; nY++, nOtherX-- )
- {
- Scanline pScanline = pWriteAcc->GetScanline(nY);
- for( long nX = 0, nOtherY = 0; nX < nNewWidth; nX++ )
- pWriteAcc->SetPixelOnData( pScanline, nX, pReadAcc->GetPixel( nOtherY++, nOtherX ) );
- }
- }
- else if( 2700 == nAngle10 )
- {
- for( long nY = 0, nOtherX = 0; nY < nNewHeight; nY++, nOtherX++ )
- {
- Scanline pScanline = pWriteAcc->GetScanline(nY);
- for( long nX = 0, nOtherY = nHeight1; nX < nNewWidth; nX++ )
- pWriteAcc->SetPixelOnData( pScanline, nX, pReadAcc->GetPixel( nOtherY--, nOtherX ) );
- }
- }
-
- pWriteAcc.reset();
- }
-
- aRotatedBmp = aNewBmp;
- }
- else
- {
- Point aTmpPoint;
- tools::Rectangle aTmpRectangle( aTmpPoint, aSizePix );
- tools::Polygon aPoly( aTmpRectangle );
- aPoly.Rotate( aTmpPoint, static_cast<sal_uInt16>(nAngle10) );
-
- tools::Rectangle aNewBound( aPoly.GetBoundRect() );
- const Size aNewSizePix( aNewBound.GetSize() );
- Bitmap aNewBmp( aNewSizePix, GetBitCount(), &pReadAcc->GetPalette() );
- ScopedWriteAccess pWriteAcc(aNewBmp);
-
- if( pWriteAcc )
- {
- const BitmapColor aFillColor( pWriteAcc->GetBestMatchingColor( rFillColor ) );
- const double fCosAngle = cos( nAngle10 * F_PI1800 );
- const double fSinAngle = sin( nAngle10 * F_PI1800 );
- const double fXMin = aNewBound.Left();
- const double fYMin = aNewBound.Top();
- const long nWidth = aSizePix.Width();
- const long nHeight = aSizePix.Height();
- const long nNewWidth = aNewSizePix.Width();
- const long nNewHeight = aNewSizePix.Height();
- long nX;
- long nY;
- long nRotX;
- long nRotY;
- std::unique_ptr<long[]> pCosX(new long[ nNewWidth ]);
- std::unique_ptr<long[]> pSinX(new long[ nNewWidth ]);
- std::unique_ptr<long[]> pCosY(new long[ nNewHeight ]);
- std::unique_ptr<long[]> pSinY(new long[ nNewHeight ]);
-
- for ( nX = 0; nX < nNewWidth; nX++ )
- {
- const double fTmp = ( fXMin + nX ) * 64.;
-
- pCosX[ nX ] = FRound( fCosAngle * fTmp );
- pSinX[ nX ] = FRound( fSinAngle * fTmp );
- }
-
- for ( nY = 0; nY < nNewHeight; nY++ )
- {
- const double fTmp = ( fYMin + nY ) * 64.;
-
- pCosY[ nY ] = FRound( fCosAngle * fTmp );
- pSinY[ nY ] = FRound( fSinAngle * fTmp );
- }
-
- for( nY = 0; nY < nNewHeight; nY++ )
- {
- long nSinY = pSinY[ nY ];
- long nCosY = pCosY[ nY ];
- Scanline pScanline = pWriteAcc->GetScanline(nY);
-
- for( nX = 0; nX < nNewWidth; nX++ )
- {
- nRotX = ( pCosX[ nX ] - nSinY ) >> 6;
- nRotY = ( pSinX[ nX ] + nCosY ) >> 6;
-
- if ( ( nRotX > -1 ) && ( nRotX < nWidth ) && ( nRotY > -1 ) && ( nRotY < nHeight ) )
- pWriteAcc->SetPixelOnData( pScanline, nX, pReadAcc->GetPixel( nRotY, nRotX ) );
- else
- pWriteAcc->SetPixelOnData( pScanline, nX, aFillColor );
- }
- }
-
- pWriteAcc.reset();
- }
-
- aRotatedBmp = aNewBmp;
- }
-
- pReadAcc.reset();
- }
-
- bRet = !!aRotatedBmp;
- if( bRet )
- ImplAssignWithSize( aRotatedBmp );
- }
-
- return bRet;
-};
-
bool Bitmap::Crop( const tools::Rectangle& rRectPixel )
{
const Size aSizePix( GetSizePixel() );
@@ -1182,625 +817,6 @@ bool Bitmap::Expand( sal_uLong nDX, sal_uLong nDY, const Color* pInitColor )
return bRet;
}
-Bitmap Bitmap::CreateMask( const Color& rTransColor, sal_uInt8 nTol ) const
-{
- ScopedReadAccess pReadAcc(const_cast<Bitmap&>(*this));
-
- if (!nTol && pReadAcc && (pReadAcc->GetScanlineFormat() == ScanlineFormat::N1BitLsbPal || pReadAcc->GetScanlineFormat() == ScanlineFormat::N1BitMsbPal)
- && pReadAcc->GetBestMatchingColor(COL_WHITE) == 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 *this;
- }
-
- Bitmap aNewBmp(GetSizePixel(), 1);
- ScopedWriteAccess pWriteAcc(aNewBmp);
- bool bRet = false;
-
- if (pWriteAcc && pReadAcc)
- {
- const long nWidth = pReadAcc->Width();
- const long nHeight = pReadAcc->Height();
- const BitmapColor aBlack( pWriteAcc->GetBestMatchingColor( COL_BLACK ) );
- const BitmapColor aWhite( pWriteAcc->GetBestMatchingColor( COL_WHITE ) );
-
- if( !nTol )
- {
- const BitmapColor aTest( pReadAcc->GetBestMatchingColor( rTransColor ) );
-
- if( pReadAcc->GetScanlineFormat() == ScanlineFormat::N4BitMsnPal ||
- pReadAcc->GetScanlineFormat() == ScanlineFormat::N4BitLsnPal )
- {
- // optimized for 4Bit-MSN/LSN source palette
- const sal_uInt8 cTest = aTest.GetIndex();
- const long nShiftInit = ( ( pReadAcc->GetScanlineFormat() == ScanlineFormat::N4BitMsnPal ) ? 4 : 0 );
-
- if( pWriteAcc->GetScanlineFormat() == ScanlineFormat::N1BitMsbPal &&
- aWhite.GetIndex() == 1 )
- {
- // optimized for 1Bit-MSB destination palette
- for (long nY = 0; nY < nHeight; ++nY)
- {
- Scanline pSrc = pReadAcc->GetScanline( nY );
- Scanline pDst = pWriteAcc->GetScanline( nY );
- for (long nX = 0, nShift = nShiftInit; nX < nWidth; nX++, nShift ^= 4)
- {
- if( cTest == ( ( pSrc[ nX >> 1 ] >> nShift ) & 0x0f ) )
- pDst[ nX >> 3 ] |= 1 << ( 7 - ( nX & 7 ) );
- else
- pDst[ nX >> 3 ] &= ~( 1 << ( 7 - ( nX & 7 ) ) );
- }
- }
- }
- else
- {
- for (long nY = 0; nY < nHeight; ++nY)
- {
- Scanline pSrc = pReadAcc->GetScanline( nY );
- Scanline pDst = pWriteAcc->GetScanline( nY );
- for (long nX = 0, nShift = nShiftInit; nX < nWidth; nX++, nShift ^= 4)
- {
- if( cTest == ( ( pSrc[ nX >> 1 ] >> nShift ) & 0x0f ) )
- pWriteAcc->SetPixelOnData( pDst, nX, aWhite );
- else
- pWriteAcc->SetPixelOnData( pDst, nX, aBlack );
- }
- }
- }
- }
- else if( pReadAcc->GetScanlineFormat() == ScanlineFormat::N8BitPal )
- {
- // optimized for 8Bit source palette
- const sal_uInt8 cTest = aTest.GetIndex();
-
- if( pWriteAcc->GetScanlineFormat() == ScanlineFormat::N1BitMsbPal &&
- aWhite.GetIndex() == 1 )
- {
- // optimized for 1Bit-MSB destination palette
- for (long nY = 0; nY < nHeight; ++nY)
- {
- Scanline pSrc = pReadAcc->GetScanline( nY );
- Scanline pDst = pWriteAcc->GetScanline( nY );
- for (long nX = 0; nX < nWidth; ++nX)
- {
- if( cTest == pSrc[ nX ] )
- pDst[ nX >> 3 ] |= 1 << ( 7 - ( nX & 7 ) );
- else
- pDst[ nX >> 3 ] &= ~( 1 << ( 7 - ( nX & 7 ) ) );
- }
- }
- }
- else
- {
- for (long nY = 0; nY < nHeight; ++nY)
- {
- Scanline pSrc = pReadAcc->GetScanline( nY );
- Scanline pDst = pWriteAcc->GetScanline( nY );
- for (long nX = 0; nX < nWidth; ++nX)
- {
- if( cTest == pSrc[ nX ] )
- pWriteAcc->SetPixelOnData( pDst, nX, aWhite );
- else
- pWriteAcc->SetPixelOnData( pDst, nX, aBlack );
- }
- }
- }
- }
- else if (pWriteAcc->GetScanlineFormat() == pReadAcc->GetScanlineFormat() && aWhite.GetIndex() == 1 &&
- (pReadAcc->GetScanlineFormat() == ScanlineFormat::N1BitLsbPal || pReadAcc->GetScanlineFormat() == ScanlineFormat::N1BitMsbPal))
- {
- for (long nY = 0; nY < nHeight; ++nY)
- {
- Scanline pSrc = pReadAcc->GetScanline(nY);
- Scanline pDst = pWriteAcc->GetScanline(nY);
- assert(pWriteAcc->GetScanlineSize() == pReadAcc->GetScanlineSize());
- const long nScanlineSize = pWriteAcc->GetScanlineSize();
- for (long nX = 0; nX < nScanlineSize; ++nX)
- pDst[nX] = ~pSrc[nX];
- }
- }
- else
- {
- // not optimized
- for (long nY = 0; nY < nHeight; ++nY)
- {
- Scanline pScanline = pWriteAcc->GetScanline( nY );
- Scanline pScanlineRead = pReadAcc->GetScanline( nY );
- for (long nX = 0; nX < nWidth; ++nX)
- {
- if( aTest == pReadAcc->GetPixelFromData( pScanlineRead, nX ) )
- pWriteAcc->SetPixelOnData( pScanline, nX, aWhite );
- else
- pWriteAcc->SetPixelOnData( pScanline, nX, aBlack );
- }
- }
- }
- }
- else
- {
- BitmapColor aCol;
- long nR, nG, nB;
- const long nMinR = MinMax<long>(rTransColor.GetRed() - nTol, 0, 255);
- const long nMaxR = MinMax<long>(rTransColor.GetRed() + nTol, 0, 255);
- const long nMinG = MinMax<long>(rTransColor.GetGreen() - nTol, 0, 255);
- const long nMaxG = MinMax<long>(rTransColor.GetGreen() + nTol, 0, 255);
- const long nMinB = MinMax<long>(rTransColor.GetBlue() - nTol, 0, 255);
- const long nMaxB = MinMax<long>(rTransColor.GetBlue() + nTol, 0, 255);
-
- if( pReadAcc->HasPalette() )
- {
- for( long nY = 0; nY < nHeight; nY++ )
- {
- Scanline pScanline = pWriteAcc->GetScanline( nY );
- Scanline pScanlineRead = pReadAcc->GetScanline(nY);
- for( 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, aWhite );
- }
- else
- pWriteAcc->SetPixelOnData( pScanline, nX, aBlack );
- }
- }
- }
- else
- {
- for( long nY = 0; nY < nHeight; nY++ )
- {
- Scanline pScanline = pWriteAcc->GetScanline( nY );
- Scanline pScanlineRead = pReadAcc->GetScanline(nY);
- for( 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, aWhite );
- }
- else
- pWriteAcc->SetPixelOnData( pScanline, nX, aBlack );
- }
- }
- }
- }
-
- bRet = true;
- }
-
- pWriteAcc.reset();
- pReadAcc.reset();
-
- if( bRet )
- {
- aNewBmp.maPrefSize = maPrefSize;
- aNewBmp.maPrefMapMode = maPrefMapMode;
- }
- else
- aNewBmp = Bitmap();
-
- return aNewBmp;
-}
-
-vcl::Region Bitmap::CreateRegion( const Color& rColor, const tools::Rectangle& rRect ) const
-{
- vcl::Region aRegion;
- tools::Rectangle aRect( rRect );
- ScopedReadAccess pReadAcc(const_cast<Bitmap&>(*this));
-
- aRect.Intersection( tools::Rectangle( Point(), GetSizePixel() ) );
- aRect.Justify();
-
- if( pReadAcc )
- {
- //Rectangle aSubRect;
- const long nLeft = aRect.Left();
- const long nTop = aRect.Top();
- const long nRight = aRect.Right();
- const long nBottom = aRect.Bottom();
- const BitmapColor aMatch( pReadAcc->GetBestMatchingColor( rColor ) );
-
- //RectangleVector aRectangles;
- //aRegion.ImplBeginAddRect();
- std::vector< long > aLine;
- long nYStart(nTop);
- long nY(nTop);
-
- for( ; nY <= nBottom; nY++ )
- {
- //aSubRect.Top() = aSubRect.Bottom() = nY;
- std::vector< long > aNewLine;
- long nX(nLeft);
- Scanline pScanlineRead = pReadAcc->GetScanline(nY);
-
- for( ; nX <= nRight; )
- {
- while( ( nX <= nRight ) && ( aMatch != pReadAcc->GetPixelFromData( pScanlineRead, nX ) ) )
- nX++;
-
- if( nX <= nRight )
- {
- aNewLine.push_back(nX);
- //aSubRect.Left() = nX;
-
- while( ( nX <= nRight ) && ( aMatch == pReadAcc->GetPixelFromData( pScanlineRead, nX ) ) )
- nX++;
-
- //aSubRect.Right() = nX - 1;
- aNewLine.push_back(nX - 1);
-
- //aRegion.ImplAddRect( aSubRect );
- //aRectangles.push_back(aSubRect);
- //aRegion.Union(aSubRect);
- }
- }
-
- if(aNewLine != aLine)
- {
- // need to write aLine, it's different from the next line
- if(aLine.size())
- {
- tools::Rectangle aSubRect;
-
- // enter y values and proceed ystart
- aSubRect.SetTop( nYStart );
- aSubRect.SetBottom( nY ? nY - 1 : 0 );
-
- for(size_t a(0); a < aLine.size();)
- {
- aSubRect.SetLeft( aLine[a++] );
- aSubRect.SetRight( aLine[a++] );
- aRegion.Union(aSubRect);
- }
- }
-
- // copy line as new line
- aLine = aNewLine;
- nYStart = nY;
- }
- }
-
- // write last line if used
- if(aLine.size())
- {
- tools::Rectangle aSubRect;
-
- // enter y values
- aSubRect.SetTop( nYStart );
- aSubRect.SetBottom( nY ? nY - 1 : 0 );
-
- for(size_t a(0); a < aLine.size();)
- {
- aSubRect.SetLeft( aLine[a++] );
- aSubRect.SetRight( aLine[a++] );
- aRegion.Union(aSubRect);
- }
- }
-
- //aRegion.ImplEndAddRect();
- //aRegion.SetRegionRectangles(aRectangles);
-
- pReadAcc.reset();
- }
- else
- aRegion = aRect;
-
- return aRegion;
-}
-
-bool Bitmap::Replace( const Bitmap& rMask, const Color& rReplaceColor )
-{
- ScopedReadAccess pMaskAcc( const_cast<Bitmap&>(rMask) );
- ScopedWriteAccess pAcc(*this);
- bool bRet = false;
-
- if( pMaskAcc && pAcc )
- {
- const long nWidth = std::min( pMaskAcc->Width(), pAcc->Width() );
- const long nHeight = std::min( pMaskAcc->Height(), pAcc->Height() );
- const BitmapColor aMaskWhite( pMaskAcc->GetBestMatchingColor( COL_WHITE ) );
- BitmapColor aReplace;
-
- if( pAcc->HasPalette() )
- {
- const sal_uInt16 nActColors = pAcc->GetPaletteEntryCount();
- const sal_uInt16 nMaxColors = 1 << pAcc->GetBitCount();
-
- // default to the nearest color
- aReplace = pAcc->GetBestMatchingColor( rReplaceColor );
-
- // for paletted images without a matching palette entry
- // look for an unused palette entry (NOTE: expensive!)
- if( pAcc->GetPaletteColor( aReplace.GetIndex() ) != BitmapColor( rReplaceColor ) )
- {
- // if the palette has empty entries use the last one
- if( nActColors < nMaxColors )
- {
- pAcc->SetPaletteEntryCount( nActColors + 1 );
- pAcc->SetPaletteColor( nActColors, rReplaceColor );
- aReplace = BitmapColor( static_cast<sal_uInt8>(nActColors) );
- }
- else
- {
- std::unique_ptr<bool[]> pFlags(new bool[ nMaxColors ]);
-
- // Set all entries to false
- std::fill( pFlags.get(), pFlags.get()+nMaxColors, false );
-
- for( long nY = 0; nY < nHeight; nY++ )
- {
- Scanline pScanline = pAcc->GetScanline(nY);
- for( long nX = 0; nX < nWidth; nX++ )
- pFlags[ pAcc->GetIndexFromData( pScanline, nX ) ] = true;
- }
-
- for( sal_uInt16 i = 0; i < nMaxColors; i++ )
- {
- // Hurray, we do have an unused entry
- if( !pFlags[ i ] )
- {
- pAcc->SetPaletteColor( i, rReplaceColor );
- aReplace = BitmapColor( static_cast<sal_uInt8>(i) );
- }
- }
- }
- }
- }
- else
- aReplace = rReplaceColor;
-
- for( long nY = 0; nY < nHeight; nY++ )
- {
- Scanline pScanline = pAcc->GetScanline( nY );
- Scanline pScanlineMask = pMaskAcc->GetScanline( nY );
- for( long nX = 0; nX < nWidth; nX++ )
- if( pMaskAcc->GetPixelFromData( pScanlineMask, nX ) == aMaskWhite )
- pAcc->SetPixelOnData( pScanline, nX, aReplace );
- }
-
- bRet = true;
- }
-
- return bRet;
-}
-
-bool Bitmap::Replace( const AlphaMask& rAlpha, const Color& rMergeColor )
-{
- Bitmap aNewBmp( GetSizePixel(), 24 );
- ScopedReadAccess pAcc(*this);
- AlphaMask::ScopedReadAccess pAlphaAcc(const_cast<AlphaMask&>(rAlpha));
- ScopedWriteAccess pNewAcc(aNewBmp);
- bool bRet = false;
-
- if( pAcc && pAlphaAcc && pNewAcc )
- {
- BitmapColor aCol;
- const long nWidth = std::min( pAlphaAcc->Width(), pAcc->Width() );
- const long nHeight = std::min( pAlphaAcc->Height(), pAcc->Height() );
-
- for( long nY = 0; nY < nHeight; nY++ )
- {
- Scanline pScanline = pNewAcc->GetScanline( nY );
- Scanline pScanlineAlpha = pAlphaAcc->GetScanline( nY );
- for( long nX = 0; nX < nWidth; nX++ )
- {
- aCol = pAcc->GetColor( nY, nX );
- pNewAcc->SetPixelOnData( pScanline, nX, aCol.Merge( rMergeColor, 255 - pAlphaAcc->GetIndexFromData( pScanlineAlpha, nX ) ) );
- }
- }
-
- bRet = true;
- }
-
- pAcc.reset();
- pAlphaAcc.reset();
- pNewAcc.reset();
-
- if( bRet )
- {
- const MapMode aMap( maPrefMapMode );
- const Size aSize( maPrefSize );
-
- *this = aNewBmp;
-
- maPrefMapMode = aMap;
- maPrefSize = aSize;
- }
-
- return bRet;
-}
-
-bool Bitmap::Replace( const Color& rSearchColor, const Color& rReplaceColor, sal_uInt8 nTol )
-{
- if( mxImpBmp )
- {
- // implementation specific replace
- std::shared_ptr<ImpBitmap> xImpBmp(new ImpBitmap);
- if (xImpBmp->ImplCreate(*mxImpBmp) && xImpBmp->ImplReplace(rSearchColor, rReplaceColor, nTol))
- {
- ImplSetImpBitmap(xImpBmp);
- maPrefMapMode = MapMode( MapUnit::MapPixel );
- maPrefSize = xImpBmp->ImplGetSize();
- return true;
- }
- }
-
- // Bitmaps with 1 bit color depth can cause problems
- // if they have other entries than black/white in their palette
- if( 1 == GetBitCount() )
- Convert( BmpConversion::N4BitColors );
-
- ScopedWriteAccess pAcc(*this);
- bool bRet = false;
-
- if( pAcc )
- {
- const long nMinR = MinMax<long>(rSearchColor.GetRed() - nTol, 0, 255);
- const long nMaxR = MinMax<long>(rSearchColor.GetRed() + nTol, 0, 255);
- const long nMinG = MinMax<long>(rSearchColor.GetGreen() - nTol, 0, 255);
- const long nMaxG = MinMax<long>(rSearchColor.GetGreen() + nTol, 0, 255);
- const long nMinB = MinMax<long>(rSearchColor.GetBlue() - nTol, 0, 255);
- const long nMaxB = MinMax<long>(rSearchColor.GetBlue() + nTol, 0, 255);
-
- if( pAcc->HasPalette() )
- {
- for( sal_uInt16 i = 0, nPalCount = pAcc->GetPaletteEntryCount(); i < nPalCount; i++ )
- {
- const BitmapColor& rCol = pAcc->GetPaletteColor( i );
-
- if( nMinR <= rCol.GetRed() && nMaxR >= rCol.GetRed() &&
- nMinG <= rCol.GetGreen() && nMaxG >= rCol.GetGreen() &&
- nMinB <= rCol.GetBlue() && nMaxB >= rCol.GetBlue() )
- {
- pAcc->SetPaletteColor( i, rReplaceColor );
- }
- }
- }
- else
- {
- BitmapColor aCol;
- const BitmapColor aReplace( pAcc->GetBestMatchingColor( rReplaceColor ) );
-
- for( long nY = 0, nHeight = pAcc->Height(); nY < nHeight; nY++ )
- {
- Scanline pScanline = pAcc->GetScanline( nY );
- for( long nX = 0, nWidth = pAcc->Width(); nX < nWidth; nX++ )
- {
- aCol = pAcc->GetPixelFromData( pScanline, nX );
-
- if( nMinR <= aCol.GetRed() && nMaxR >= aCol.GetRed() &&
- nMinG <= aCol.GetGreen() && nMaxG >= aCol.GetGreen() &&
- nMinB <= aCol.GetBlue() && nMaxB >= aCol.GetBlue() )
- {
- pAcc->SetPixelOnData( pScanline, nX, aReplace );
- }
- }
- }
- }
-
- pAcc.reset();
- bRet = true;
- }
-
- return bRet;
-}
-
-bool Bitmap::Replace( const Color* pSearchColors, const Color* pReplaceColors,
- sal_uLong nColorCount, sal_uInt8 const * pTols )
-{
- // Bitmaps with 1 bit color depth can cause problems
- // if they have other entries than black/white in their palette
- if( 1 == GetBitCount() )
- Convert( BmpConversion::N4BitColors );
-
- ScopedWriteAccess pAcc(*this);
- bool bRet = false;
-
- if( pAcc )
- {
- std::unique_ptr<long[]> pMinR(new long[ nColorCount ]);
- std::unique_ptr<long[]> pMaxR(new long[ nColorCount ]);
- std::unique_ptr<long[]> pMinG(new long[ nColorCount ]);
- std::unique_ptr<long[]> pMaxG(new long[ nColorCount ]);
- std::unique_ptr<long[]> pMinB(new long[ nColorCount ]);
- std::unique_ptr<long[]> pMaxB(new long[ nColorCount ]);
-
- if( pTols )
- {
- for( sal_uLong i = 0; i < nColorCount; i++ )
- {
- const Color& rCol = pSearchColors[ i ];
- const sal_uInt8 nTol = pTols[ i ];
-
- pMinR[ i ] = MinMax<long>(rCol.GetRed() - nTol, 0, 255);
- pMaxR[ i ] = MinMax<long>(rCol.GetRed() + nTol, 0, 255);
- pMinG[ i ] = MinMax<long>(rCol.GetGreen() - nTol, 0, 255);
- pMaxG[ i ] = MinMax<long>(rCol.GetGreen() + nTol, 0, 255);
- pMinB[ i ] = MinMax<long>(rCol.GetBlue() - nTol, 0, 255);
- pMaxB[ i ] = MinMax<long>(rCol.GetBlue() + nTol, 0, 255);
- }
- }
- else
- {
- for( sal_uLong i = 0; i < nColorCount; i++ )
- {
- const Color& rCol = pSearchColors[ i ];
-
- pMinR[ i ] = rCol.GetRed();
- pMaxR[ i ] = rCol.GetRed();
- pMinG[ i ] = rCol.GetGreen();
- pMaxG[ i ] = rCol.GetGreen();
- pMinB[ i ] = rCol.GetBlue();
- pMaxB[ i ] = rCol.GetBlue();
- }
- }
-
- if( pAcc->HasPalette() )
- {
- for( sal_uInt16 nEntry = 0, nPalCount = pAcc->GetPaletteEntryCount(); nEntry < nPalCount; nEntry++ )
- {
- const BitmapColor& rCol = pAcc->GetPaletteColor( nEntry );
-
- for( sal_uLong i = 0; i < nColorCount; i++ )
- {
- if( pMinR[ i ] <= rCol.GetRed() && pMaxR[ i ] >= rCol.GetRed() &&
- pMinG[ i ] <= rCol.GetGreen() && pMaxG[ i ] >= rCol.GetGreen() &&
- pMinB[ i ] <= rCol.GetBlue() && pMaxB[ i ] >= rCol.GetBlue() )
- {
- pAcc->SetPaletteColor( nEntry, pReplaceColors[ i ] );
- break;
- }
- }
- }
- }
- else
- {
- BitmapColor aCol;
- std::unique_ptr<BitmapColor[]> pReplaces(new BitmapColor[ nColorCount ]);
-
- for( sal_uLong i = 0; i < nColorCount; i++ )
- pReplaces[ i ] = pAcc->GetBestMatchingColor( pReplaceColors[ i ] );
-
- for( long nY = 0, nHeight = pAcc->Height(); nY < nHeight; nY++ )
- {
- Scanline pScanline = pAcc->GetScanline( nY );
- for( long nX = 0, nWidth = pAcc->Width(); nX < nWidth; nX++ )
- {
- aCol = pAcc->GetPixelFromData( pScanline, nX );
-
- for( sal_uLong i = 0; i < nColorCount; i++ )
- {
- if( pMinR[ i ] <= aCol.GetRed() && pMaxR[ i ] >= aCol.GetRed() &&
- pMinG[ i ] <= aCol.GetGreen() && pMaxG[ i ] >= aCol.GetGreen() &&
- pMinB[ i ] <= aCol.GetBlue() && pMaxB[ i ] >= aCol.GetBlue() )
- {
- pAcc->SetPixelOnData( pScanline, nX, pReplaces[ i ] );
- break;
- }
- }
- }
- }
- }
-
- pAcc.reset();
- bRet = true;
- }
-
- return bRet;
-}
-
Bitmap Bitmap::CreateDisplayBitmap( OutputDevice* pDisplay )
{
Bitmap aDispBmp( *this );
@@ -1817,102 +833,6 @@ Bitmap Bitmap::CreateDisplayBitmap( OutputDevice* pDisplay )
return aDispBmp;
}
-bool Bitmap::CombineSimple( const Bitmap& rMask, BmpCombine eCombine )
-{
- ScopedReadAccess pMaskAcc(const_cast<Bitmap&>(rMask));
- ScopedWriteAccess pAcc(*this);
- bool bRet = false;
-
- if( pMaskAcc && pAcc )
- {
- const long nWidth = std::min( pMaskAcc->Width(), pAcc->Width() );
- const long nHeight = std::min( pMaskAcc->Height(), pAcc->Height() );
- const Color aColBlack( COL_BLACK );
- BitmapColor aPixel;
- BitmapColor aMaskPixel;
- const BitmapColor aWhite( pAcc->GetBestMatchingColor( COL_WHITE ) );
- const BitmapColor aBlack( pAcc->GetBestMatchingColor( aColBlack ) );
- const BitmapColor aMaskBlack( pMaskAcc->GetBestMatchingColor( aColBlack ) );
-
- switch( eCombine )
- {
- case BmpCombine::And:
- {
- for( long nY = 0; nY < nHeight; nY++ )
- {
- Scanline pScanline = pAcc->GetScanline( nY );
- Scanline pScanlineMask = pMaskAcc->GetScanline( nY );
- for( long nX = 0; nX < nWidth; nX++ )
- {
- if( pMaskAcc->GetPixelFromData( pScanlineMask, nX ) != aMaskBlack && pAcc->GetPixelFromData( pScanline, nX ) != aBlack )
- pAcc->SetPixelOnData( pScanline, nX, aWhite );
- else
- pAcc->SetPixelOnData( pScanline, nX, aBlack );
- }
- }
- }
- break;
-
- case BmpCombine::Or:
- {
- for( long nY = 0; nY < nHeight; nY++ )
- {
- Scanline pScanline = pAcc->GetScanline( nY );
- Scanline pScanlineMask = pMaskAcc->GetScanline( nY );
- for( long nX = 0; nX < nWidth; nX++ )
- {
- if( pMaskAcc->GetPixelFromData( pScanlineMask, nX ) != aMaskBlack || pAcc->GetPixelFromData( pScanline, nX ) != aBlack )
- pAcc->SetPixelOnData( pScanline, nX, aWhite );
- else
- pAcc->SetPixelOnData( pScanline, nX, aBlack );
- }
- }
- }
- break;
-
- }
-
- bRet = true;
- }
-
- return bRet;
-}
-
-// TODO: Have a look at OutputDevice::ImplDrawAlpha() for some
-// optimizations. Might even consolidate the code here and there.
-bool Bitmap::Blend( const AlphaMask& rAlpha, const Color& rBackgroundColor )
-{
- // Convert to a truecolor bitmap, if we're a paletted one. There's
- // room for tradeoff decision here, maybe later for an overload (or a flag)
- if( GetBitCount() <= 8 )
- Convert( BmpConversion::N24Bit );
-
- AlphaMask::ScopedReadAccess pAlphaAcc(const_cast<AlphaMask&>(rAlpha));
-
- ScopedWriteAccess pAcc(*this);
- bool bRet = false;
-
- if( pAlphaAcc && pAcc )
- {
- const long nWidth = std::min( pAlphaAcc->Width(), pAcc->Width() );
- const long nHeight = std::min( pAlphaAcc->Height(), pAcc->Height() );
-
- for( long nY = 0; nY < nHeight; ++nY )
- {
- Scanline pScanline = pAcc->GetScanline( nY );
- Scanline pScanlineAlpha = pAlphaAcc->GetScanline( nY );
- for( long nX = 0; nX < nWidth; ++nX )
- pAcc->SetPixelOnData( pScanline, nX,
- pAcc->GetPixelFromData( pScanline, nX ).Merge( rBackgroundColor,
- 255 - pAlphaAcc->GetIndexFromData( pScanlineAlpha, nX ) ) );
- }
-
- bRet = true;
- }
-
- return bRet;
-}
-
bool Bitmap::MakeMonochrome(sal_uInt8 cThreshold)
{
ScopedReadAccess pReadAcc(*this);
diff --git a/vcl/source/bitmap/bitmappaint.cxx b/vcl/source/bitmap/bitmappaint.cxx
new file mode 100644
index 000000000000..38472333a0c3
--- /dev/null
+++ b/vcl/source/bitmap/bitmappaint.cxx
@@ -0,0 +1,1158 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <tools/poly.hxx>
+#include <vcl/bitmap.hxx>
+#include <vcl/bitmapaccess.hxx>
+#include <vcl/alpha.hxx>
+
+#include <impbmp.hxx>
+
+#include <algorithm>
+#include <memory>
+
+bool Bitmap::Erase(const Color& rFillColor)
+{
+ if (IsEmpty())
+ return true;
+
+ Bitmap::ScopedWriteAccess pWriteAcc(*this);
+ bool bRet = false;
+
+ if (pWriteAcc)
+ {
+ const ScanlineFormat nFormat = pWriteAcc->GetScanlineFormat();
+ sal_uInt8 cIndex = 0;
+ bool bFast = false;
+
+ switch (nFormat)
+ {
+ case ScanlineFormat::N1BitMsbPal:
+ case ScanlineFormat::N1BitLsbPal:
+ {
+ cIndex = static_cast<sal_uInt8>(pWriteAcc->GetBestPaletteIndex(rFillColor));
+ cIndex = (cIndex ? 255 : 0);
+ bFast = true;
+ }
+ break;
+
+ case ScanlineFormat::N4BitMsnPal:
+ case ScanlineFormat::N4BitLsnPal:
+ {
+ cIndex = static_cast<sal_uInt8>(pWriteAcc->GetBestPaletteIndex(rFillColor));
+ cIndex = cIndex | (cIndex << 4);
+ bFast = true;
+ }
+ break;
+
+ case ScanlineFormat::N8BitPal:
+ {
+ cIndex = static_cast<sal_uInt8>(pWriteAcc->GetBestPaletteIndex(rFillColor));
+ bFast = true;
+ }
+ break;
+
+ case ScanlineFormat::N24BitTcBgr:
+ case ScanlineFormat::N24BitTcRgb:
+ {
+ if (rFillColor.GetRed() == rFillColor.GetGreen()
+ && rFillColor.GetRed() == rFillColor.GetBlue())
+ {
+ cIndex = rFillColor.GetRed();
+ bFast = true;
+ }
+ else
+ {
+ bFast = false;
+ }
+ }
+ break;
+
+ default:
+ bFast = false;
+ break;
+ }
+
+ if (bFast)
+ {
+ const sal_uLong nBufSize = pWriteAcc->GetScanlineSize() * pWriteAcc->Height();
+ memset(pWriteAcc->GetBuffer(), cIndex, nBufSize);
+ }
+ else
+ {
+ const tools::Rectangle aRect(Point(), Size(pWriteAcc->Width(), pWriteAcc->Height()));
+ pWriteAcc->SetFillColor(rFillColor);
+ pWriteAcc->FillRect(aRect);
+ }
+
+ bRet = true;
+ }
+
+ return bRet;
+}
+
+bool Bitmap::Invert()
+{
+ ScopedWriteAccess pAcc(*this);
+ bool bRet = false;
+
+ if (pAcc)
+ {
+ if (pAcc->HasPalette())
+ {
+ BitmapPalette aBmpPal(pAcc->GetPalette());
+ const sal_uInt16 nCount = aBmpPal.GetEntryCount();
+
+ for (sal_uInt16 i = 0; i < nCount; i++)
+ {
+ aBmpPal[i].Invert();
+ }
+
+ pAcc->SetPalette(aBmpPal);
+ }
+ else
+ {
+ const long nWidth = pAcc->Width();
+ const long nHeight = pAcc->Height();
+
+ for (long nY = 0; nY < nHeight; nY++)
+ {
+ Scanline pScanline = pAcc->GetScanline(nY);
+ for (long nX = 0; nX < nWidth; nX++)
+ {
+ pAcc->SetPixelOnData(pScanline, nX,
+ pAcc->GetPixelFromData(pScanline, nX).Invert());
+ }
+ }
+ }
+
+ mxImpBmp->ImplInvalidateChecksum();
+ pAcc.reset();
+ bRet = true;
+ }
+
+ return bRet;
+}
+
+bool Bitmap::Mirror(BmpMirrorFlags nMirrorFlags)
+{
+ bool bHorz(nMirrorFlags & BmpMirrorFlags::Horizontal);
+ bool bVert(nMirrorFlags & BmpMirrorFlags::Vertical);
+ bool bRet = false;
+
+ if (bHorz && !bVert)
+ {
+ ScopedWriteAccess pAcc(*this);
+
+ if (pAcc)
+ {
+ const long nWidth = pAcc->Width();
+ const long nHeight = pAcc->Height();
+ const long nWidth1 = nWidth - 1;
+ const long nWidth_2 = nWidth >> 1;
+
+ for (long nY = 0; nY < nHeight; nY++)
+ {
+ Scanline pScanline = pAcc->GetScanline(nY);
+ for (long nX = 0, nOther = nWidth1; nX < nWidth_2; nX++, nOther--)
+ {
+ const BitmapColor aTemp(pAcc->GetPixelFromData(pScanline, nX));
+
+ pAcc->SetPixelOnData(pScanline, nX, pAcc->GetPixelFromData(pScanline, nOther));
+ pAcc->SetPixelOnData(pScanline, nOther, aTemp);
+ }
+ }
+
+ pAcc.reset();
+ bRet = true;
+ }
+ }
+ else if (bVert && !bHorz)
+ {
+ ScopedWriteAccess pAcc(*this);
+
+ if (pAcc)
+ {
+ const long nScanSize = pAcc->GetScanlineSize();
+ std::unique_ptr<sal_uInt8[]> pBuffer(new sal_uInt8[nScanSize]);
+ const long nHeight = pAcc->Height();
+ const long nHeight1 = nHeight - 1;
+ const long nHeight_2 = nHeight >> 1;
+
+ for (long nY = 0, nOther = nHeight1; nY < nHeight_2; nY++, nOther--)
+ {
+ memcpy(pBuffer.get(), pAcc->GetScanline(nY), nScanSize);
+ memcpy(pAcc->GetScanline(nY), pAcc->GetScanline(nOther), nScanSize);
+ memcpy(pAcc->GetScanline(nOther), pBuffer.get(), nScanSize);
+ }
+
+ pAcc.reset();
+ bRet = true;
+ }
+ }
+ else if (bHorz && bVert)
+ {
+ ScopedWriteAccess pAcc(*this);
+
+ if (pAcc)
+ {
+ const long nWidth = pAcc->Width();
+ const long nWidth1 = nWidth - 1;
+ const long nHeight = pAcc->Height();
+ long nHeight_2 = nHeight >> 1;
+
+ for (long nY = 0, nOtherY = nHeight - 1; nY < nHeight_2; nY++, nOtherY--)
+ {
+ Scanline pScanline = pAcc->GetScanline(nY);
+ Scanline pScanlineOther = pAcc->GetScanline(nOtherY);
+ for (long nX = 0, nOtherX = nWidth1; nX < nWidth; nX++, nOtherX--)
+ {
+ const BitmapColor aTemp(pAcc->GetPixelFromData(pScanline, nX));
+
+ pAcc->SetPixelOnData(pScanline, nX,
+ pAcc->GetPixelFromData(pScanlineOther, nOtherX));
+ pAcc->SetPixelOnData(pScanlineOther, nOtherX, aTemp);
+ }
+ }
+
+ // if necessary, also mirror the middle line horizontally
+ if (nHeight & 1)
+ {
+ Scanline pScanline = pAcc->GetScanline(nHeight_2);
+ for (long nX = 0, nOtherX = nWidth1, nWidth_2 = nWidth >> 1; nX < nWidth_2;
+ nX++, nOtherX--)
+ {
+ const BitmapColor aTemp(pAcc->GetPixelFromData(pScanline, nX));
+ pAcc->SetPixelOnData(pScanline, nX, pAcc->GetPixelFromData(pScanline, nOtherX));
+ pAcc->SetPixelOnData(pScanline, nOtherX, aTemp);
+ }
+ }
+
+ pAcc.reset();
+ bRet = true;
+ }
+ }
+ else
+ bRet = true;
+
+ return bRet;
+}
+
+bool Bitmap::Rotate(long nAngle10, const Color& rFillColor)
+{
+ bool bRet = false;
+
+ nAngle10 %= 3600;
+ nAngle10 = (nAngle10 < 0) ? (3599L + nAngle10) : nAngle10;
+
+ if (!nAngle10)
+ bRet = true;
+ else if (nAngle10 == 1800)
+ bRet = Mirror(BmpMirrorFlags::Horizontal | BmpMirrorFlags::Vertical);
+ else
+ {
+ ScopedReadAccess pReadAcc(*this);
+ Bitmap aRotatedBmp;
+
+ if (pReadAcc)
+ {
+ const Size aSizePix(GetSizePixel());
+
+ if (nAngle10 == 900 || nAngle10 == 2700)
+ {
+ const Size aNewSizePix(aSizePix.Height(), aSizePix.Width());
+ Bitmap aNewBmp(aNewSizePix, GetBitCount(), &pReadAcc->GetPalette());
+ ScopedWriteAccess pWriteAcc(aNewBmp);
+
+ if (pWriteAcc)
+ {
+ const long nWidth = aSizePix.Width();
+ const long nWidth1 = nWidth - 1;
+ const long nHeight = aSizePix.Height();
+ const long nHeight1 = nHeight - 1;
+ const long nNewWidth = aNewSizePix.Width();
+ const long nNewHeight = aNewSizePix.Height();
+
+ if (nAngle10 == 900)
+ {
+ for (long nY = 0, nOtherX = nWidth1; nY < nNewHeight; nY++, nOtherX--)
+ {
+ Scanline pScanline = pWriteAcc->GetScanline(nY);
+ for (long nX = 0, nOtherY = 0; nX < nNewWidth; nX++)
+ {
+ pWriteAcc->SetPixelOnData(pScanline, nX,
+ pReadAcc->GetPixel(nOtherY++, nOtherX));
+ }
+ }
+ }
+ else if (nAngle10 == 2700)
+ {
+ for (long nY = 0, nOtherX = 0; nY < nNewHeight; nY++, nOtherX++)
+ {
+ Scanline pScanline = pWriteAcc->GetScanline(nY);
+ for (long nX = 0, nOtherY = nHeight1; nX < nNewWidth; nX++)
+ {
+ pWriteAcc->SetPixelOnData(pScanline, nX,
+ pReadAcc->GetPixel(nOtherY--, nOtherX));
+ }
+ }
+ }
+
+ pWriteAcc.reset();
+ }
+
+ aRotatedBmp = aNewBmp;
+ }
+ else
+ {
+ Point aTmpPoint;
+ tools::Rectangle aTmpRectangle(aTmpPoint, aSizePix);
+ tools::Polygon aPoly(aTmpRectangle);
+ aPoly.Rotate(aTmpPoint, static_cast<sal_uInt16>(nAngle10));
+
+ tools::Rectangle aNewBound(aPoly.GetBoundRect());
+ const Size aNewSizePix(aNewBound.GetSize());
+ Bitmap aNewBmp(aNewSizePix, GetBitCount(), &pReadAcc->GetPalette());
+ ScopedWriteAccess pWriteAcc(aNewBmp);
+
+ if (pWriteAcc)
+ {
+ const BitmapColor aFillColor(pWriteAcc->GetBestMatchingColor(rFillColor));
+ const double fCosAngle = cos(nAngle10 * F_PI1800);
+ const double fSinAngle = sin(nAngle10 * F_PI1800);
+ const double fXMin = aNewBound.Left();
+ const double fYMin = aNewBound.Top();
+ const long nWidth = aSizePix.Width();
+ const long nHeight = aSizePix.Height();
+ const long nNewWidth = aNewSizePix.Width();
+ const long nNewHeight = aNewSizePix.Height();
+ long nX;
+ long nY;
+ long nRotX;
+ long nRotY;
+ std::unique_ptr<long[]> pCosX(new long[nNewWidth]);
+ std::unique_ptr<long[]> pSinX(new long[nNewWidth]);
+ std::unique_ptr<long[]> pCosY(new long[nNewHeight]);
+ std::unique_ptr<long[]> pSinY(new long[nNewHeight]);
+
+ for (nX = 0; nX < nNewWidth; nX++)
+ {
+ const double fTmp = (fXMin + nX) * 64.;
+
+ pCosX[nX] = FRound(fCosAngle * fTmp);
+ pSinX[nX] = FRound(fSinAngle * fTmp);
+ }
+
+ for (nY = 0; nY < nNewHeight; nY++)
+ {
+ const double fTmp = (fYMin + nY) * 64.;
+
+ pCosY[nY] = FRound(fCosAngle * fTmp);
+ pSinY[nY] = FRound(fSinAngle * fTmp);
+ }
+
+ for (nY = 0; nY < nNewHeight; nY++)
+ {
+ long nSinY = pSinY[nY];
+ long nCosY = pCosY[nY];
+ Scanline pScanline = pWriteAcc->GetScanline(nY);
+
+ for (nX = 0; nX < nNewWidth; nX++)
+ {
+ nRotX = (pCosX[nX] - nSinY) >> 6;
+ nRotY = (pSinX[nX] + nCosY) >> 6;
+
+ if ((nRotX > -1) && (nRotX < nWidth) && (nRotY > -1)
+ && (nRotY < nHeight))
+ {
+ pWriteAcc->SetPixelOnData(pScanline, nX,
+ pReadAcc->GetPixel(nRotY, nRotX));
+ }
+ else
+ {
+ pWriteAcc->SetPixelOnData(pScanline, nX, aFillColor);
+ }
+ }
+ }
+
+ pWriteAcc.reset();
+ }
+
+ aRotatedBmp = aNewBmp;
+ }
+
+ pReadAcc.reset();
+ }
+
+ bRet = !!aRotatedBmp;
+ if (bRet)
+ ImplAssignWithSize(aRotatedBmp);
+ }
+
+ return bRet;
+};
+
+Bitmap Bitmap::CreateMask(const Color& rTransColor, sal_uInt8 nTol) const
+{
+ ScopedReadAccess pReadAcc(const_cast<Bitmap&>(*this));
+
+ if (!nTol && pReadAcc
+ && (pReadAcc->GetScanlineFormat() == ScanlineFormat::N1BitLsbPal
+ || pReadAcc->GetScanlineFormat() == ScanlineFormat::N1BitMsbPal)
+ && pReadAcc->GetBestMatchingColor(COL_WHITE) == 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 *this;
+ }
+
+ Bitmap aNewBmp(GetSizePixel(), 1);
+ ScopedWriteAccess pWriteAcc(aNewBmp);
+ bool bRet = false;
+
+ if (pWriteAcc && pReadAcc)
+ {
+ const long nWidth = pReadAcc->Width();
+ const long nHeight = pReadAcc->Height();
+ const BitmapColor aBlack(pWriteAcc->GetBestMatchingColor(COL_BLACK));
+ const BitmapColor aWhite(pWriteAcc->GetBestMatchingColor(COL_WHITE));
+
+ if (!nTol)
+ {
+ const BitmapColor aTest(pReadAcc->GetBestMatchingColor(rTransColor));
+
+ if (pReadAcc->GetScanlineFormat() == ScanlineFormat::N4BitMsnPal
+ || pReadAcc->GetScanlineFormat() == ScanlineFormat::N4BitLsnPal)
+ {
+ // optimized for 4Bit-MSN/LSN source palette
+ const sal_uInt8 cTest = aTest.GetIndex();
+ const long nShiftInit
+ = ((pReadAcc->GetScanlineFormat() == ScanlineFormat::N4BitMsnPal) ? 4 : 0);
+
+ if (pWriteAcc->GetScanlineFormat() == ScanlineFormat::N1BitMsbPal
+ && aWhite.GetIndex() == 1)
+ {
+ // optimized for 1Bit-MSB destination palette
+ for (long nY = 0; nY < nHeight; ++nY)
+ {
+ Scanline pSrc = pReadAcc->GetScanline(nY);
+ Scanline pDst = pWriteAcc->GetScanline(nY);
+ for (long nX = 0, nShift = nShiftInit; nX < nWidth; nX++, nShift ^= 4)
+ {
+ if (cTest == ((pSrc[nX >> 1] >> nShift) & 0x0f))
+ pDst[nX >> 3] |= 1 << (7 - (nX & 7));
+ else
+ pDst[nX >> 3] &= ~(1 << (7 - (nX & 7)));
+ }
+ }
+ }
+ else
+ {
+ for (long nY = 0; nY < nHeight; ++nY)
+ {
+ Scanline pSrc = pReadAcc->GetScanline(nY);
+ Scanline pDst = pWriteAcc->GetScanline(nY);
+ for (long nX = 0, nShift = nShiftInit; nX < nWidth; nX++, nShift ^= 4)
+ {
+ if (cTest == ((pSrc[nX >> 1] >> nShift) & 0x0f))
+ pWriteAcc->SetPixelOnData(pDst, nX, aWhite);
+ else
+ pWriteAcc->SetPixelOnData(pDst, nX, aBlack);
+ }
+ }
+ }
+ }
+ else if (pReadAcc->GetScanlineFormat() == ScanlineFormat::N8BitPal)
+ {
+ // optimized for 8Bit source palette
+ const sal_uInt8 cTest = aTest.GetIndex();
+
+ if (pWriteAcc->GetScanlineFormat() == ScanlineFormat::N1BitMsbPal
+ && aWhite.GetIndex() == 1)
+ {
+ // optimized for 1Bit-MSB destination palette
+ for (long nY = 0; nY < nHeight; ++nY)
+ {
+ Scanline pSrc = pReadAcc->GetScanline(nY);
+ Scanline pDst = pWriteAcc->GetScanline(nY);
+ for (long nX = 0; nX < nWidth; ++nX)
+ {
+ if (cTest == pSrc[nX])
+ pDst[nX >> 3] |= 1 << (7 - (nX & 7));
+ else
+ pDst[nX >> 3] &= ~(1 << (7 - (nX & 7)));
+ }
+ }
+ }
+ else
+ {
+ for (long nY = 0; nY < nHeight; ++nY)
+ {
+ Scanline pSrc = pReadAcc->GetScanline(nY);
+ Scanline pDst = pWriteAcc->GetScanline(nY);
+ for (long nX = 0; nX < nWidth; ++nX)
+ {
+ if (cTest == pSrc[nX])
+ pWriteAcc->SetPixelOnData(pDst, nX, aWhite);
+ else
+ pWriteAcc->SetPixelOnData(pDst, nX, aBlack);
+ }
+ }
+ }
+ }
+ else if (pWriteAcc->GetScanlineFormat() == pReadAcc->GetScanlineFormat()
+ && aWhite.GetIndex() == 1
+ && (pReadAcc->GetScanlineFormat() == ScanlineFormat::N1BitLsbPal
+ || pReadAcc->GetScanlineFormat() == ScanlineFormat::N1BitMsbPal))
+ {
+ for (long nY = 0; nY < nHeight; ++nY)
+ {
+ Scanline pSrc = pReadAcc->GetScanline(nY);
+ Scanline pDst = pWriteAcc->GetScanline(nY);
+ assert(pWriteAcc->GetScanlineSize() == pReadAcc->GetScanlineSize());
+ const long nScanlineSize = pWriteAcc->GetScanlineSize();
+ for (long nX = 0; nX < nScanlineSize; ++nX)
+ pDst[nX] = ~pSrc[nX];
+ }
+ }
+ else
+ {
+ // not optimized
+ for (long nY = 0; nY < nHeight; ++nY)
+ {
+ Scanline pScanline = pWriteAcc->GetScanline(nY);
+ Scanline pScanlineRead = pReadAcc->GetScanline(nY);
+ for (long nX = 0; nX < nWidth; ++nX)
+ {
+ if (aTest == pReadAcc->GetPixelFromData(pScanlineRead, nX))
+ pWriteAcc->SetPixelOnData(pScanline, nX, aWhite);
+ else
+ pWriteAcc->SetPixelOnData(pScanline, nX, aBlack);
+ }
+ }
+ }
+ }
+ else
+ {
+ BitmapColor aCol;
+ long nR, nG, nB;
+ const long nMinR = MinMax<long>(rTransColor.GetRed() - nTol, 0, 255);
+ const long nMaxR = MinMax<long>(rTransColor.GetRed() + nTol, 0, 255);
+ const long nMinG = MinMax<long>(rTransColor.GetGreen() - nTol, 0, 255);
+ const long nMaxG = MinMax<long>(rTransColor.GetGreen() + nTol, 0, 255);
+ const long nMinB = MinMax<long>(rTransColor.GetBlue() - nTol, 0, 255);
+ const long nMaxB = MinMax<long>(rTransColor.GetBlue() + nTol, 0, 255);
+
+ if (pReadAcc->HasPalette())
+ {
+ for (long nY = 0; nY < nHeight; nY++)
+ {
+ Scanline pScanline = pWriteAcc->GetScanline(nY);
+ Scanline pScanlineRead = pReadAcc->GetScanline(nY);
+ for (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, aWhite);
+ }
+ else
+ {
+ pWriteAcc->SetPixelOnData(pScanline, nX, aBlack);
+ }
+ }
+ }
+ }
+ else
+ {
+ for (long nY = 0; nY < nHeight; nY++)
+ {
+ Scanline pScanline = pWriteAcc->GetScanline(nY);
+ Scanline pScanlineRead = pReadAcc->GetScanline(nY);
+ for (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, aWhite);
+ }
+ else
+ {
+ pWriteAcc->SetPixelOnData(pScanline, nX, aBlack);
+ }
+ }
+ }
+ }
+ }
+
+ bRet = true;
+ }
+
+ pWriteAcc.reset();
+ pReadAcc.reset();
+
+ if (bRet)
+ {
+ aNewBmp.maPrefSize = maPrefSize;
+ aNewBmp.maPrefMapMode = maPrefMapMode;
+ }
+ else
+ aNewBmp = Bitmap();
+
+ return aNewBmp;
+}
+
+vcl::Region Bitmap::CreateRegion(const Color& rColor, const tools::Rectangle& rRect) const
+{
+ vcl::Region aRegion;
+ tools::Rectangle aRect(rRect);
+ ScopedReadAccess pReadAcc(const_cast<Bitmap&>(*this));
+
+ aRect.Intersection(tools::Rectangle(Point(), GetSizePixel()));
+ aRect.Justify();
+
+ if (pReadAcc)
+ {
+ const long nLeft = aRect.Left();
+ const long nTop = aRect.Top();
+ const long nRight = aRect.Right();
+ const long nBottom = aRect.Bottom();
+ const BitmapColor aMatch(pReadAcc->GetBestMatchingColor(rColor));
+
+ //RectangleVector aRectangles;
+ //aRegion.ImplBeginAddRect();
+ std::vector<long> aLine;
+ long nYStart(nTop);
+ long nY(nTop);
+
+ for (; nY <= nBottom; nY++)
+ {
+ //aSubRect.Top() = aSubRect.Bottom() = nY;
+ std::vector<long> aNewLine;
+ long nX(nLeft);
+ Scanline pScanlineRead = pReadAcc->GetScanline(nY);
+
+ for (; nX <= nRight;)
+ {
+ while ((nX <= nRight) && (aMatch != pReadAcc->GetPixelFromData(pScanlineRead, nX)))
+ nX++;
+
+ if (nX <= nRight)
+ {
+ aNewLine.push_back(nX);
+ //aSubRect.Left() = nX;
+
+ while ((nX <= nRight)
+ && (aMatch == pReadAcc->GetPixelFromData(pScanlineRead, nX)))
+ {
+ nX++;
+ }
+
+ //aSubRect.Right() = nX - 1;
+ aNewLine.push_back(nX - 1);
+
+ //aRegion.ImplAddRect( aSubRect );
+ //aRectangles.push_back(aSubRect);
+ //aRegion.Union(aSubRect);
+ }
+ }
+
+ if (aNewLine != aLine)
+ {
+ // need to write aLine, it's different from the next line
+ if (aLine.size())
+ {
+ tools::Rectangle aSubRect;
+
+ // enter y values and proceed ystart
+ aSubRect.SetTop(nYStart);
+ aSubRect.SetBottom(nY ? nY - 1 : 0);
+
+ for (size_t a(0); a < aLine.size();)
+ {
+ aSubRect.SetLeft(aLine[a++]);
+ aSubRect.SetRight(aLine[a++]);
+ aRegion.Union(aSubRect);
+ }
+ }
+
+ // copy line as new line
+ aLine = aNewLine;
+ nYStart = nY;
+ }
+ }
+
+ // write last line if used
+ if (aLine.size())
+ {
+ tools::Rectangle aSubRect;
+
+ // enter y values
+ aSubRect.SetTop(nYStart);
+ aSubRect.SetBottom(nY ? nY - 1 : 0);
+
+ for (size_t a(0); a < aLine.size();)
+ {
+ aSubRect.SetLeft(aLine[a++]);
+ aSubRect.SetRight(aLine[a++]);
+ aRegion.Union(aSubRect);
+ }
+ }
+
+ //aRegion.ImplEndAddRect();
+ //aRegion.SetRegionRectangles(aRectangles);
+
+ pReadAcc.reset();
+ }
+ else
+ {
+ aRegion = aRect;
+ }
+
+ return aRegion;
+}
+
+bool Bitmap::Replace(const Bitmap& rMask, const Color& rReplaceColor)
+{
+ ScopedReadAccess pMaskAcc(const_cast<Bitmap&>(rMask));
+ ScopedWriteAccess pAcc(*this);
+ bool bRet = false;
+
+ if (pMaskAcc && pAcc)
+ {
+ const long nWidth = std::min(pMaskAcc->Width(), pAcc->Width());
+ const long nHeight = std::min(pMaskAcc->Height(), pAcc->Height());
+ const BitmapColor aMaskWhite(pMaskAcc->GetBestMatchingColor(COL_WHITE));
+ BitmapColor aReplace;
+
+ if (pAcc->HasPalette())
+ {
+ const sal_uInt16 nActColors = pAcc->GetPaletteEntryCount();
+ const sal_uInt16 nMaxColors = 1 << pAcc->GetBitCount();
+
+ // default to the nearest color
+ aReplace = pAcc->GetBestMatchingColor(rReplaceColor);
+
+ // for paletted images without a matching palette entry
+ // look for an unused palette entry (NOTE: expensive!)
+ if (pAcc->GetPaletteColor(aReplace.GetIndex()) != BitmapColor(rReplaceColor))
+ {
+ // if the palette has empty entries use the last one
+ if (nActColors < nMaxColors)
+ {
+ pAcc->SetPaletteEntryCount(nActColors + 1);
+ pAcc->SetPaletteColor(nActColors, rReplaceColor);
+ aReplace = BitmapColor(static_cast<sal_uInt8>(nActColors));
+ }
+ else
+ {
+ std::unique_ptr<bool[]> pFlags(new bool[nMaxColors]);
+
+ // Set all entries to false
+ std::fill(pFlags.get(), pFlags.get() + nMaxColors, false);
+
+ for (long nY = 0; nY < nHeight; nY++)
+ {
+ Scanline pScanline = pAcc->GetScanline(nY);
+ for (long nX = 0; nX < nWidth; nX++)
+ pFlags[pAcc->GetIndexFromData(pScanline, nX)] = true;
+ }
+
+ for (sal_uInt16 i = 0; i < nMaxColors; i++)
+ {
+ // Hurray, we do have an unused entry
+ if (!pFlags[i])
+ {
+ pAcc->SetPaletteColor(i, rReplaceColor);
+ aReplace = BitmapColor(static_cast<sal_uInt8>(i));
+ }
+ }
+ }
+ }
+ }
+ else
+ aReplace = rReplaceColor;
+
+ for (long nY = 0; nY < nHeight; nY++)
+ {
+ Scanline pScanline = pAcc->GetScanline(nY);
+ Scanline pScanlineMask = pMaskAcc->GetScanline(nY);
+ for (long nX = 0; nX < nWidth; nX++)
+ {
+ if (pMaskAcc->GetPixelFromData(pScanlineMask, nX) == aMaskWhite)
+ pAcc->SetPixelOnData(pScanline, nX, aReplace);
+ }
+ }
+
+ bRet = true;
+ }
+
+ return bRet;
+}
+
+bool Bitmap::Replace(const AlphaMask& rAlpha, const Color& rMergeColor)
+{
+ Bitmap aNewBmp(GetSizePixel(), 24);
+ ScopedReadAccess pAcc(*this);
+ AlphaMask::ScopedReadAccess pAlphaAcc(const_cast<AlphaMask&>(rAlpha));
+ ScopedWriteAccess pNewAcc(aNewBmp);
+ bool bRet = false;
+
+ if (pAcc && pAlphaAcc && pNewAcc)
+ {
+ BitmapColor aCol;
+ const long nWidth = std::min(pAlphaAcc->Width(), pAcc->Width());
+ const long nHeight = std::min(pAlphaAcc->Height(), pAcc->Height());
+
+ for (long nY = 0; nY < nHeight; nY++)
+ {
+ Scanline pScanline = pNewAcc->GetScanline(nY);
+ Scanline pScanlineAlpha = pAlphaAcc->GetScanline(nY);
+ for (long nX = 0; nX < nWidth; nX++)
+ {
+ aCol = pAcc->GetColor(nY, nX);
+ pNewAcc->SetPixelOnData(
+ pScanline, nX,
+ aCol.Merge(rMergeColor, 255 - pAlphaAcc->GetIndexFromData(pScanlineAlpha, nX)));
+ }
+ }
+
+ bRet = true;
+ }
+
+ pAcc.reset();
+ pAlphaAcc.reset();
+ pNewAcc.reset();
+
+ if (bRet)
+ {
+ const MapMode aMap(maPrefMapMode);
+ const Size aSize(maPrefSize);
+
+ *this = aNewBmp;
+
+ maPrefMapMode = aMap;
+ maPrefSize = aSize;
+ }
+
+ return bRet;
+}
+
+bool Bitmap::Replace(const Color& rSearchColor, const Color& rReplaceColor, sal_uInt8 nTol)
+{
+ if (mxImpBmp)
+ {
+ // implementation specific replace
+ std::shared_ptr<ImpBitmap> xImpBmp(new ImpBitmap);
+ if (xImpBmp->ImplCreate(*mxImpBmp)
+ && xImpBmp->ImplReplace(rSearchColor, rReplaceColor, nTol))
+ {
+ ImplSetImpBitmap(xImpBmp);
+ maPrefMapMode = MapMode(MapUnit::MapPixel);
+ maPrefSize = xImpBmp->ImplGetSize();
+ return true;
+ }
+ }
+
+ // Bitmaps with 1 bit color depth can cause problems if they have other entries than black/white
+ // in their palette
+ if (GetBitCount() == 1)
+ Convert(BmpConversion::N4BitColors);
+
+ ScopedWriteAccess pAcc(*this);
+ bool bRet = false;
+
+ if (pAcc)
+ {
+ const long nMinR = MinMax<long>(rSearchColor.GetRed() - nTol, 0, 255);
+ const long nMaxR = MinMax<long>(rSearchColor.GetRed() + nTol, 0, 255);
+ const long nMinG = MinMax<long>(rSearchColor.GetGreen() - nTol, 0, 255);
+ const long nMaxG = MinMax<long>(rSearchColor.GetGreen() + nTol, 0, 255);
+ const long nMinB = MinMax<long>(rSearchColor.GetBlue() - nTol, 0, 255);
+ const long nMaxB = MinMax<long>(rSearchColor.GetBlue() + nTol, 0, 255);
+
+ if (pAcc->HasPalette())
+ {
+ for (sal_uInt16 i = 0, nPalCount = pAcc->GetPaletteEntryCount(); i < nPalCount; i++)
+ {
+ const BitmapColor& rCol = pAcc->GetPaletteColor(i);
+
+ if (nMinR <= rCol.GetRed() && nMaxR >= rCol.GetRed() && nMinG <= rCol.GetGreen()
+ && nMaxG >= rCol.GetGreen() && nMinB <= rCol.GetBlue()
+ && nMaxB >= rCol.GetBlue())
+ {
+ pAcc->SetPaletteColor(i, rReplaceColor);
+ }
+ }
+ }
+ else
+ {
+ BitmapColor aCol;
+ const BitmapColor aReplace(pAcc->GetBestMatchingColor(rReplaceColor));
+
+ for (long nY = 0, nHeight = pAcc->Height(); nY < nHeight; nY++)
+ {
+ Scanline pScanline = pAcc->GetScanline(nY);
+ for (long nX = 0, nWidth = pAcc->Width(); nX < nWidth; nX++)
+ {
+ aCol = pAcc->GetPixelFromData(pScanline, nX);
+
+ if (nMinR <= aCol.GetRed() && nMaxR >= aCol.GetRed() && nMinG <= aCol.GetGreen()
+ && nMaxG >= aCol.GetGreen() && nMinB <= aCol.GetBlue()
+ && nMaxB >= aCol.GetBlue())
+ {
+ pAcc->SetPixelOnData(pScanline, nX, aReplace);
+ }
+ }
+ }
+ }
+
+ pAcc.reset();
+ bRet = true;
+ }
+
+ return bRet;
+}
+
+bool Bitmap::Replace(const Color* pSearchColors, const Color* pReplaceColors, sal_uLong nColorCount,
+ sal_uInt8 const* pTols)
+{
+ // Bitmaps with 1 bit color depth can cause problems if they have other entries than black/white
+ // in their palette
+ if (GetBitCount() == 1)
+ Convert(BmpConversion::N4BitColors);
+
+ ScopedWriteAccess pAcc(*this);
+ bool bRet = false;
+
+ if (pAcc)
+ {
+ std::unique_ptr<long[]> pMinR(new long[nColorCount]);
+ std::unique_ptr<long[]> pMaxR(new long[nColorCount]);
+ std::unique_ptr<long[]> pMinG(new long[nColorCount]);
+ std::unique_ptr<long[]> pMaxG(new long[nColorCount]);
+ std::unique_ptr<long[]> pMinB(new long[nColorCount]);
+ std::unique_ptr<long[]> pMaxB(new long[nColorCount]);
+
+ if (pTols)
+ {
+ for (sal_uLong i = 0; i < nColorCount; i++)
+ {
+ const Color& rCol = pSearchColors[i];
+ const sal_uInt8 nTol = pTols[i];
+
+ pMinR[i] = MinMax<long>(rCol.GetRed() - nTol, 0, 255);
+ pMaxR[i] = MinMax<long>(rCol.GetRed() + nTol, 0, 255);
+ pMinG[i] = MinMax<long>(rCol.GetGreen() - nTol, 0, 255);
+ pMaxG[i] = MinMax<long>(rCol.GetGreen() + nTol, 0, 255);
+ pMinB[i] = MinMax<long>(rCol.GetBlue() - nTol, 0, 255);
+ pMaxB[i] = MinMax<long>(rCol.GetBlue() + nTol, 0, 255);
+ }
+ }
+ else
+ {
+ for (sal_uLong i = 0; i < nColorCount; i++)
+ {
+ const Color& rCol = pSearchColors[i];
+
+ pMinR[i] = rCol.GetRed();
+ pMaxR[i] = rCol.GetRed();
+ pMinG[i] = rCol.GetGreen();
+ pMaxG[i] = rCol.GetGreen();
+ pMinB[i] = rCol.GetBlue();
+ pMaxB[i] = rCol.GetBlue();
+ }
+ }
+
+ if (pAcc->HasPalette())
+ {
+ for (sal_uInt16 nEntry = 0, nPalCount = pAcc->GetPaletteEntryCount();
+ nEntry < nPalCount; nEntry++)
+ {
+ const BitmapColor& rCol = pAcc->GetPaletteColor(nEntry);
+
+ for (sal_uLong i = 0; i < nColorCount; i++)
+ {
+ if (pMinR[i] <= rCol.GetRed() && pMaxR[i] >= rCol.GetRed()
+ && pMinG[i] <= rCol.GetGreen() && pMaxG[i] >= rCol.GetGreen()
+ && pMinB[i] <= rCol.GetBlue() && pMaxB[i] >= rCol.GetBlue())
+ {
+ pAcc->SetPaletteColor(nEntry, pReplaceColors[i]);
+ break;
+ }
+ }
+ }
+ }
+ else
+ {
+ BitmapColor aCol;
+ std::unique_ptr<BitmapColor[]> pReplaces(new BitmapColor[nColorCount]);
+
+ for (sal_uLong i = 0; i < nColorCount; i++)
+ pReplaces[i] = pAcc->GetBestMatchingColor(pReplaceColors[i]);
+
+ for (long nY = 0, nHeight = pAcc->Height(); nY < nHeight; nY++)
+ {
+ Scanline pScanline = pAcc->GetScanline(nY);
+ for (long nX = 0, nWidth = pAcc->Width(); nX < nWidth; nX++)
+ {
+ aCol = pAcc->GetPixelFromData(pScanline, nX);
+
+ for (sal_uLong i = 0; i < nColorCount; i++)
+ {
+ if (pMinR[i] <= aCol.GetRed() && pMaxR[i] >= aCol.GetRed()
+ && pMinG[i] <= aCol.GetGreen() && pMaxG[i] >= aCol.GetGreen()
+ && pMinB[i] <= aCol.GetBlue() && pMaxB[i] >= aCol.GetBlue())
+ {
+ pAcc->SetPixelOnData(pScanline, nX, pReplaces[i]);
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ pAcc.reset();
+ bRet = true;
+ }
+
+ return bRet;
+}
+
+bool Bitmap::CombineSimple(const Bitmap& rMask, BmpCombine eCombine)
+{
+ ScopedReadAccess pMaskAcc(const_cast<Bitmap&>(rMask));
+ ScopedWriteAccess pAcc(*this);
+ bool bRet = false;
+
+ if (pMaskAcc && pAcc)
+ {
+ const long nWidth = std::min(pMaskAcc->Width(), pAcc->Width());
+ const long nHeight = std::min(pMaskAcc->Height(), pAcc->Height());
+ const Color aColBlack(COL_BLACK);
+ BitmapColor aPixel;
+ BitmapColor aMaskPixel;
+ const BitmapColor aWhite(pAcc->GetBestMatchingColor(COL_WHITE));
+ const BitmapColor aBlack(pAcc->GetBestMatchingColor(aColBlack));
+ const BitmapColor aMaskBlack(pMaskAcc->GetBestMatchingColor(aColBlack));
+
+ switch (eCombine)
+ {
+ case BmpCombine::And:
+ {
+ for (long nY = 0; nY < nHeight; nY++)
+ {
+ Scanline pScanline = pAcc->GetScanline(nY);
+ Scanline pScanlineMask = pMaskAcc->GetScanline(nY);
+ for (long nX = 0; nX < nWidth; nX++)
+ {
+ if (pMaskAcc->GetPixelFromData(pScanlineMask, nX) != aMaskBlack
+ && pAcc->GetPixelFromData(pScanline, nX) != aBlack)
+ {
+ pAcc->SetPixelOnData(pScanline, nX, aWhite);
+ }
+ else
+ {
+ pAcc->SetPixelOnData(pScanline, nX, aBlack);
+ }
+ }
+ }
+ }
+ break;
+
+ case BmpCombine::Or:
+ {
+ for (long nY = 0; nY < nHeight; nY++)
+ {
+ Scanline pScanline = pAcc->GetScanline(nY);
+ Scanline pScanlineMask = pMaskAcc->GetScanline(nY);
+ for (long nX = 0; nX < nWidth; nX++)
+ {
+ if (pMaskAcc->GetPixelFromData(pScanlineMask, nX) != aMaskBlack
+ || pAcc->GetPixelFromData(pScanline, nX) != aBlack)
+ {
+ pAcc->SetPixelOnData(pScanline, nX, aWhite);
+ }
+ else
+ {
+ pAcc->SetPixelOnData(pScanline, nX, aBlack);
+ }
+ }
+ }
+ }
+ break;
+ }
+
+ bRet = true;
+ }
+
+ return bRet;
+}
+
+// TODO: Have a look at OutputDevice::ImplDrawAlpha() for some
+// optimizations. Might even consolidate the code here and there.
+bool Bitmap::Blend(const AlphaMask& rAlpha, const Color& rBackgroundColor)
+{
+ // Convert to a truecolor bitmap, if we're a paletted one. There's room for tradeoff decision here,
+ // maybe later for an overload (or a flag)
+ if (GetBitCount() <= 8)
+ Convert(BmpConversion::N24Bit);
+
+ AlphaMask::ScopedReadAccess pAlphaAcc(const_cast<AlphaMask&>(rAlpha));
+
+ ScopedWriteAccess pAcc(*this);
+ bool bRet = false;
+
+ if (pAlphaAcc && pAcc)
+ {
+ const long nWidth = std::min(pAlphaAcc->Width(), pAcc->Width());
+ const long nHeight = std::min(pAlphaAcc->Height(), pAcc->Height());
+
+ for (long nY = 0; nY < nHeight; ++nY)
+ {
+ Scanline pScanline = pAcc->GetScanline(nY);
+ Scanline pScanlineAlpha = pAlphaAcc->GetScanline(nY);
+ for (long nX = 0; nX < nWidth; ++nX)
+ {
+ pAcc->SetPixelOnData(
+ pScanline, nX,
+ pAcc->GetPixelFromData(pScanline, nX)
+ .Merge(rBackgroundColor,
+ 255 - pAlphaAcc->GetIndexFromData(pScanlineAlpha, nX)));
+ }
+ }
+
+ bRet = true;
+ }
+
+ return bRet;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */