summaryrefslogtreecommitdiff
path: root/vcl/source/bitmap/bitmap.cxx
diff options
context:
space:
mode:
authorChris Sherlock <chris.sherlock79@gmail.com>2018-03-01 06:25:40 +1100
committerTomaž Vajngerl <quikee@gmail.com>2018-03-05 08:24:15 +0100
commit1b51bca4ce77bdeefd2461e3b8a8b6b38bda6d43 (patch)
tree8a88ba9cc4bc5ddad11a6d697039df2edf79f61b /vcl/source/bitmap/bitmap.cxx
parent54638c88963c21e468082573f6b4c53ce427103c (diff)
vcl: move vcl/source/gdi/bitmap.cxx to vcl/source/bitmap/bitmap.cxx
Change-Id: Ib74ac5016b6f99adef41b6ee562701b5158cffd3 Reviewed-on: https://gerrit.libreoffice.org/50532 Tested-by: Jenkins <ci@libreoffice.org> Reviewed-by: Tomaž Vajngerl <quikee@gmail.com>
Diffstat (limited to 'vcl/source/bitmap/bitmap.cxx')
-rw-r--r--vcl/source/bitmap/bitmap.cxx2005
1 files changed, 2005 insertions, 0 deletions
diff --git a/vcl/source/bitmap/bitmap.cxx b/vcl/source/bitmap/bitmap.cxx
new file mode 100644
index 000000000000..bf670f20ffce
--- /dev/null
+++ b/vcl/source/bitmap/bitmap.cxx
@@ -0,0 +1,2005 @@
+/* -*- 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 <algorithm>
+#include <rtl/crc.h>
+#include <tools/stream.hxx>
+#include <tools/poly.hxx>
+#include <vcl/salbtype.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 <memory>
+
+Bitmap::Bitmap()
+{
+}
+
+Bitmap::Bitmap(const Bitmap& rBitmap)
+ : mxImpBmp(rBitmap.mxImpBmp)
+ , maPrefMapMode(rBitmap.maPrefMapMode)
+ , maPrefSize(rBitmap.maPrefSize)
+{
+}
+
+Bitmap::Bitmap(SalBitmap* pSalBitmap)
+ : mxImpBmp(new ImpBitmap(pSalBitmap))
+ , maPrefMapMode(MapMode(MapUnit::MapPixel))
+ , maPrefSize(mxImpBmp->ImplGetSize())
+{
+}
+
+Bitmap::Bitmap( const Size& rSizePixel, sal_uInt16 nBitCount, const BitmapPalette* pPal )
+{
+ if (rSizePixel.Width() && rSizePixel.Height())
+ {
+ BitmapPalette aPal;
+ BitmapPalette* pRealPal = nullptr;
+
+ if( nBitCount <= 8 )
+ {
+ if( !pPal )
+ {
+ if( 1 == nBitCount )
+ {
+ aPal.SetEntryCount( 2 );
+ aPal[ 0 ] = COL_BLACK;
+ aPal[ 1 ] = COL_WHITE;
+ }
+ else if( ( 4 == nBitCount ) || ( 8 == nBitCount ) )
+ {
+ aPal.SetEntryCount( 1 << nBitCount );
+ aPal[ 0 ] = COL_BLACK;
+ aPal[ 1 ] = COL_BLUE;
+ aPal[ 2 ] = COL_GREEN;
+ aPal[ 3 ] = COL_CYAN;
+ aPal[ 4 ] = COL_RED;
+ aPal[ 5 ] = COL_MAGENTA;
+ aPal[ 6 ] = COL_BROWN;
+ aPal[ 7 ] = COL_GRAY;
+ aPal[ 8 ] = COL_LIGHTGRAY;
+ aPal[ 9 ] = COL_LIGHTBLUE;
+ aPal[ 10 ] = COL_LIGHTGREEN;
+ aPal[ 11 ] = COL_LIGHTCYAN;
+ aPal[ 12 ] = COL_LIGHTRED;
+ aPal[ 13 ] = COL_LIGHTMAGENTA;
+ aPal[ 14 ] = COL_YELLOW;
+ aPal[ 15 ] = COL_WHITE;
+
+ // Create dither palette
+ if( 8 == nBitCount )
+ {
+ sal_uInt16 nActCol = 16;
+
+ for( sal_uInt16 nB = 0; nB < 256; nB += 51 )
+ for( sal_uInt16 nG = 0; nG < 256; nG += 51 )
+ for( sal_uInt16 nR = 0; nR < 256; nR += 51 )
+ aPal[ nActCol++ ] = BitmapColor( static_cast<sal_uInt8>(nR), static_cast<sal_uInt8>(nG), static_cast<sal_uInt8>(nB) );
+
+ // Set standard Office colors
+ aPal[ nActCol++ ] = BitmapColor( 0, 184, 255 );
+ }
+ }
+ }
+ else
+ pRealPal = const_cast<BitmapPalette*>(pPal);
+ }
+
+ mxImpBmp.reset(new ImpBitmap);
+ mxImpBmp->ImplCreate( rSizePixel, nBitCount, pRealPal ? *pRealPal : aPal );
+ }
+}
+
+Bitmap::~Bitmap()
+{
+}
+
+const BitmapPalette& Bitmap::GetGreyPalette( int nEntries )
+{
+ static BitmapPalette aGreyPalette2;
+ static BitmapPalette aGreyPalette4;
+ static BitmapPalette aGreyPalette16;
+ static BitmapPalette aGreyPalette256;
+
+ // Create greyscale palette with 2, 4, 16 or 256 entries
+ if( 2 == nEntries || 4 == nEntries || 16 == nEntries || 256 == nEntries )
+ {
+ if( 2 == nEntries )
+ {
+ if( !aGreyPalette2.GetEntryCount() )
+ {
+ aGreyPalette2.SetEntryCount( 2 );
+ aGreyPalette2[ 0 ] = BitmapColor( 0, 0, 0 );
+ aGreyPalette2[ 1 ] = BitmapColor( 255, 255, 255 );
+ }
+
+ return aGreyPalette2;
+ }
+ else if( 4 == nEntries )
+ {
+ if( !aGreyPalette4.GetEntryCount() )
+ {
+ aGreyPalette4.SetEntryCount( 4 );
+ aGreyPalette4[ 0 ] = BitmapColor( 0, 0, 0 );
+ aGreyPalette4[ 1 ] = BitmapColor( 85, 85, 85 );
+ aGreyPalette4[ 2 ] = BitmapColor( 170, 170, 170 );
+ aGreyPalette4[ 3 ] = BitmapColor( 255, 255, 255 );
+ }
+
+ return aGreyPalette4;
+ }
+ else if( 16 == nEntries )
+ {
+ if( !aGreyPalette16.GetEntryCount() )
+ {
+ sal_uInt8 cGrey = 0;
+ sal_uInt8 const cGreyInc = 17;
+
+ aGreyPalette16.SetEntryCount( 16 );
+
+ for( sal_uInt16 i = 0; i < 16; i++, cGrey = sal::static_int_cast<sal_uInt8>(cGrey + cGreyInc) )
+ aGreyPalette16[ i ] = BitmapColor( cGrey, cGrey, cGrey );
+ }
+
+ return aGreyPalette16;
+ }
+ else
+ {
+ if( !aGreyPalette256.GetEntryCount() )
+ {
+ aGreyPalette256.SetEntryCount( 256 );
+
+ for( sal_uInt16 i = 0; i < 256; i++ )
+ aGreyPalette256[ i ] = BitmapColor( static_cast<sal_uInt8>(i), static_cast<sal_uInt8>(i), static_cast<sal_uInt8>(i) );
+ }
+
+ return aGreyPalette256;
+ }
+ }
+ else
+ {
+ OSL_FAIL( "Bitmap::GetGreyPalette: invalid entry count (2/4/16/256 allowed)" );
+ return aGreyPalette2;
+ }
+}
+
+bool BitmapPalette::IsGreyPalette() const
+{
+ const int nEntryCount = GetEntryCount();
+ if( !nEntryCount ) // NOTE: an empty palette means 1:1 mapping
+ return true;
+ // See above: only certain entry values will result in a valid call to GetGreyPalette
+ if( nEntryCount == 2 || nEntryCount == 4 || nEntryCount == 16 || nEntryCount == 256 )
+ {
+ const BitmapPalette& rGreyPalette = Bitmap::GetGreyPalette( nEntryCount );
+ if( rGreyPalette == *this )
+ return true;
+ }
+
+ bool bRet = false;
+ // TODO: is it worth to compare the entries for the general case?
+ if (nEntryCount == 2)
+ {
+ const BitmapColor& rCol0(maBitmapColor[0]);
+ const BitmapColor& rCol1(maBitmapColor[1]);
+ bRet = rCol0.GetRed() == rCol0.GetGreen() && rCol0.GetRed() == rCol0.GetBlue() &&
+ rCol1.GetRed() == rCol1.GetGreen() && rCol1.GetRed() == rCol1.GetBlue();
+ }
+ return bRet;
+}
+
+Bitmap& Bitmap::operator=( const Bitmap& rBitmap )
+{
+ if (this == &rBitmap)
+ return *this;
+
+ maPrefSize = rBitmap.maPrefSize;
+ maPrefMapMode = rBitmap.maPrefMapMode;
+ mxImpBmp = rBitmap.mxImpBmp;
+
+ return *this;
+}
+
+Bitmap& Bitmap::operator=( Bitmap&& rBitmap )
+{
+ maPrefSize = std::move(rBitmap.maPrefSize);
+ maPrefMapMode = std::move(rBitmap.maPrefMapMode);
+ mxImpBmp = std::move(rBitmap.mxImpBmp);
+
+ return *this;
+}
+
+bool Bitmap::operator==( const Bitmap& rBmp ) const
+{
+ return rBmp.mxImpBmp == mxImpBmp || // Includes both are nullptr
+ (rBmp.mxImpBmp && mxImpBmp && mxImpBmp->ImplIsEqual(*rBmp.mxImpBmp));
+}
+
+void Bitmap::SetEmpty()
+{
+ maPrefMapMode = MapMode();
+ maPrefSize = Size();
+ mxImpBmp.reset();
+}
+
+Size Bitmap::GetSizePixel() const
+{
+ return( mxImpBmp ? mxImpBmp->ImplGetSize() : Size() );
+}
+
+sal_uInt16 Bitmap::GetBitCount() const
+{
+ return( mxImpBmp ? mxImpBmp->ImplGetBitCount() : 0 );
+}
+
+bool Bitmap::HasGreyPalette() const
+{
+ const sal_uInt16 nBitCount = GetBitCount();
+ bool bRet = nBitCount == 1;
+
+ ScopedInfoAccess pIAcc(const_cast<Bitmap&>(*this));
+
+ if( pIAcc )
+ {
+ bRet = pIAcc->HasPalette() && pIAcc->GetPalette().IsGreyPalette();
+ }
+
+ return bRet;
+}
+
+BitmapChecksum Bitmap::GetChecksum() const
+{
+ BitmapChecksum nRet = 0;
+
+ if( mxImpBmp )
+ {
+ nRet = mxImpBmp->ImplGetChecksum();
+
+ if (!nRet)
+ {
+ // nRet == 0 => probably, we were not able to acquire
+ // the buffer in SalBitmap::updateChecksum;
+ // so, we need to update the imp bitmap for this bitmap instance
+ // as we do in BitmapInfoAccess::ImplCreate
+ std::shared_ptr<ImpBitmap> xNewImpBmp(new ImpBitmap);
+ if (xNewImpBmp->ImplCreate(*mxImpBmp, GetBitCount()))
+ {
+ Bitmap* pThis = const_cast<Bitmap*>(this);
+ pThis->mxImpBmp = xNewImpBmp;
+ nRet = mxImpBmp->ImplGetChecksum();
+ }
+ }
+ }
+
+ return nRet;
+}
+
+void Bitmap::ImplMakeUnique()
+{
+ if (mxImpBmp && mxImpBmp.use_count() > 1)
+ {
+ std::shared_ptr<ImpBitmap> xOldImpBmp = mxImpBmp;
+ mxImpBmp.reset(new ImpBitmap);
+ mxImpBmp->ImplCreate(*xOldImpBmp);
+ }
+}
+
+void Bitmap::ImplAssignWithSize( const Bitmap& rBitmap )
+{
+ const Size aOldSizePix( GetSizePixel() );
+ const Size aNewSizePix( rBitmap.GetSizePixel() );
+ const MapMode aOldMapMode( maPrefMapMode );
+ Size aNewPrefSize;
+
+ if( ( aOldSizePix != aNewSizePix ) && aOldSizePix.Width() && aOldSizePix.Height() )
+ {
+ aNewPrefSize.setWidth( FRound( maPrefSize.Width() * aNewSizePix.Width() / aOldSizePix.Width() ) );
+ aNewPrefSize.setHeight( FRound( maPrefSize.Height() * aNewSizePix.Height() / aOldSizePix.Height() ) );
+ }
+ else
+ aNewPrefSize = maPrefSize;
+
+ *this = rBitmap;
+
+ maPrefSize = aNewPrefSize;
+ maPrefMapMode = aOldMapMode;
+}
+
+
+void Bitmap::ImplSetImpBitmap(const std::shared_ptr<ImpBitmap>& xImpBmp)
+{
+ mxImpBmp = xImpBmp;
+}
+
+BitmapInfoAccess* Bitmap::AcquireInfoAccess()
+{
+ BitmapInfoAccess* pInfoAccess = new BitmapInfoAccess( *this );
+
+ if( !*pInfoAccess )
+ {
+ delete pInfoAccess;
+ pInfoAccess = nullptr;
+ }
+
+ return pInfoAccess;
+}
+
+BitmapReadAccess* Bitmap::AcquireReadAccess()
+{
+ BitmapReadAccess* pReadAccess = new BitmapReadAccess( *this );
+
+ if( !*pReadAccess )
+ {
+ delete pReadAccess;
+ pReadAccess = nullptr;
+ }
+
+ return pReadAccess;
+}
+
+BitmapWriteAccess* Bitmap::AcquireWriteAccess()
+{
+ BitmapWriteAccess* pWriteAccess = new BitmapWriteAccess( *this );
+
+ if( !*pWriteAccess )
+ {
+ delete pWriteAccess;
+ pWriteAccess = nullptr;
+ }
+
+ return pWriteAccess;
+}
+
+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() );
+ tools::Rectangle aRect( rRectPixel );
+ bool bRet = false;
+
+ aRect.Intersection( tools::Rectangle( Point(), aSizePix ) );
+
+ if( !aRect.IsEmpty() && aSizePix != aRect.GetSize())
+ {
+ ScopedReadAccess pReadAcc(*this);
+
+ if( pReadAcc )
+ {
+ const tools::Rectangle aNewRect( Point(), aRect.GetSize() );
+ Bitmap aNewBmp( aNewRect.GetSize(), GetBitCount(), &pReadAcc->GetPalette() );
+ ScopedWriteAccess pWriteAcc(aNewBmp);
+
+ if( pWriteAcc )
+ {
+ const long nOldX = aRect.Left();
+ const long nOldY = aRect.Top();
+ const long nNewWidth = aNewRect.GetWidth();
+ const long nNewHeight = aNewRect.GetHeight();
+
+ for( long nY = 0, nY2 = nOldY; nY < nNewHeight; nY++, nY2++ )
+ {
+ Scanline pScanline = pWriteAcc->GetScanline(nY);
+ Scanline pScanlineRead = pReadAcc->GetScanline(nY2);
+ for( long nX = 0, nX2 = nOldX; nX < nNewWidth; nX++, nX2++ )
+ pWriteAcc->SetPixelOnData( pScanline, nX, pReadAcc->GetPixelFromData( pScanlineRead, nX2 ) );
+ }
+
+ pWriteAcc.reset();
+ bRet = true;
+ }
+
+ pReadAcc.reset();
+
+ if( bRet )
+ ImplAssignWithSize( aNewBmp );
+ }
+ }
+
+ return bRet;
+};
+
+bool Bitmap::CopyPixel( const tools::Rectangle& rRectDst,
+ const tools::Rectangle& rRectSrc, const Bitmap* pBmpSrc )
+{
+ const Size aSizePix( GetSizePixel() );
+ tools::Rectangle aRectDst( rRectDst );
+ bool bRet = false;
+
+ aRectDst.Intersection( tools::Rectangle( Point(), aSizePix ) );
+
+ if( !aRectDst.IsEmpty() )
+ {
+ if( pBmpSrc && ( pBmpSrc->mxImpBmp != mxImpBmp ) )
+ {
+ Bitmap* pSrc = const_cast<Bitmap*>(pBmpSrc);
+ const Size aCopySizePix( pSrc->GetSizePixel() );
+ tools::Rectangle aRectSrc( rRectSrc );
+ const sal_uInt16 nSrcBitCount = pBmpSrc->GetBitCount();
+ const sal_uInt16 nDstBitCount = GetBitCount();
+
+ if( nSrcBitCount > nDstBitCount )
+ {
+ int nNextIndex = 0;
+
+ if( ( nSrcBitCount == 24 ) && ( nDstBitCount < 24 ) )
+ Convert( BmpConversion::N24Bit );
+ else if( ( nSrcBitCount == 8 ) && ( nDstBitCount < 8 ) )
+ {
+ Convert( BmpConversion::N8BitColors );
+ nNextIndex = 16;
+ }
+ else if( ( nSrcBitCount == 4 ) && ( nDstBitCount < 4 ) )
+ {
+ Convert( BmpConversion::N4BitColors );
+ nNextIndex = 2;
+ }
+
+ if( nNextIndex )
+ {
+ ScopedReadAccess pSrcAcc(*pSrc);
+ ScopedWriteAccess pDstAcc(*this);
+
+ if( pSrcAcc && pDstAcc )
+ {
+ const int nSrcCount = pDstAcc->GetPaletteEntryCount();
+ const int nDstCount = 1 << nDstBitCount;
+
+ for (int i = 0; ( i < nSrcCount ) && ( nNextIndex < nSrcCount ); ++i)
+ {
+ const BitmapColor& rSrcCol = pSrcAcc->GetPaletteColor( static_cast<sal_uInt16>(i) );
+
+ bool bFound = false;
+
+ for (int j = 0; j < nDstCount; ++j)
+ {
+ if( rSrcCol == pDstAcc->GetPaletteColor( static_cast<sal_uInt16>(j) ) )
+ {
+ bFound = true;
+ break;
+ }
+ }
+
+ if( !bFound )
+ pDstAcc->SetPaletteColor( static_cast<sal_uInt16>(nNextIndex++), rSrcCol );
+ }
+ }
+ }
+ }
+
+ aRectSrc.Intersection( tools::Rectangle( Point(), aCopySizePix ) );
+
+ if( !aRectSrc.IsEmpty() )
+ {
+ ScopedReadAccess pReadAcc(*pSrc);
+
+ if( pReadAcc )
+ {
+ ScopedWriteAccess pWriteAcc(*this);
+
+ if( pWriteAcc )
+ {
+ const long nWidth = std::min( aRectSrc.GetWidth(), aRectDst.GetWidth() );
+ const long nHeight = std::min( aRectSrc.GetHeight(), aRectDst.GetHeight() );
+ const long nSrcEndX = aRectSrc.Left() + nWidth;
+ const long nSrcEndY = aRectSrc.Top() + nHeight;
+ long nDstY = aRectDst.Top();
+
+ if( pReadAcc->HasPalette() && pWriteAcc->HasPalette() )
+ {
+ const sal_uInt16 nCount = pReadAcc->GetPaletteEntryCount();
+ std::unique_ptr<sal_uInt8[]> pMap(new sal_uInt8[ nCount ]);
+
+ // Create index map for the color table, as the bitmap should be copied
+ // retaining it's color information relatively well
+ for( sal_uInt16 i = 0; i < nCount; i++ )
+ pMap[ i ] = static_cast<sal_uInt8>(pWriteAcc->GetBestPaletteIndex( pReadAcc->GetPaletteColor( i ) ));
+
+ for( long nSrcY = aRectSrc.Top(); nSrcY < nSrcEndY; nSrcY++, nDstY++ )
+ {
+ Scanline pScanline = pWriteAcc->GetScanline(nDstY);
+ Scanline pScanlineRead = pReadAcc->GetScanline(nSrcY);
+ for( long nSrcX = aRectSrc.Left(), nDstX = aRectDst.Left(); nSrcX < nSrcEndX; nSrcX++, nDstX++ )
+ pWriteAcc->SetPixelOnData( pScanline, nDstX, BitmapColor( pMap[ pReadAcc->GetIndexFromData( pScanlineRead, nSrcX ) ] ));
+ }
+ }
+ else if( pReadAcc->HasPalette() )
+ {
+ for( long nSrcY = aRectSrc.Top(); nSrcY < nSrcEndY; nSrcY++, nDstY++ )
+ {
+ Scanline pScanline = pWriteAcc->GetScanline(nDstY);
+ Scanline pScanlineRead = pReadAcc->GetScanline(nSrcY);
+ for( long nSrcX = aRectSrc.Left(), nDstX = aRectDst.Left(); nSrcX < nSrcEndX; nSrcX++, nDstX++ )
+ pWriteAcc->SetPixelOnData( pScanline, nDstX, pReadAcc->GetPaletteColor( pReadAcc->GetIndexFromData( pScanlineRead, nSrcX ) ) );
+ }
+ }
+ else
+ for( long nSrcY = aRectSrc.Top(); nSrcY < nSrcEndY; nSrcY++, nDstY++ )
+ {
+ Scanline pScanline = pWriteAcc->GetScanline(nDstY);
+ Scanline pScanlineRead = pReadAcc->GetScanline(nSrcY);
+ for( long nSrcX = aRectSrc.Left(), nDstX = aRectDst.Left(); nSrcX < nSrcEndX; nSrcX++, nDstX++ )
+ pWriteAcc->SetPixelOnData( pScanline, nDstX, pReadAcc->GetPixelFromData( pScanlineRead, nSrcX ) );
+ }
+
+ pWriteAcc.reset();
+ bRet = ( nWidth > 0 ) && ( nHeight > 0 );
+ }
+
+ pReadAcc.reset();
+ }
+ }
+ }
+ else
+ {
+ tools::Rectangle aRectSrc( rRectSrc );
+
+ aRectSrc.Intersection( tools::Rectangle( Point(), aSizePix ) );
+
+ if( !aRectSrc.IsEmpty() && ( aRectSrc != aRectDst ) )
+ {
+ ScopedWriteAccess pWriteAcc(*this);
+
+ if( pWriteAcc )
+ {
+ const long nWidth = std::min( aRectSrc.GetWidth(), aRectDst.GetWidth() );
+ const long nHeight = std::min( aRectSrc.GetHeight(), aRectDst.GetHeight() );
+ const long nSrcX = aRectSrc.Left();
+ const long nSrcY = aRectSrc.Top();
+ const long nSrcEndX1 = nSrcX + nWidth - 1;
+ const long nSrcEndY1 = nSrcY + nHeight - 1;
+ const long nDstX = aRectDst.Left();
+ const long nDstY = aRectDst.Top();
+ const long nDstEndX1 = nDstX + nWidth - 1;
+ const long nDstEndY1 = nDstY + nHeight - 1;
+
+ if( ( nDstX <= nSrcX ) && ( nDstY <= nSrcY ) )
+ {
+ for( long nY = nSrcY, nYN = nDstY; nY <= nSrcEndY1; nY++, nYN++ )
+ {
+ Scanline pScanline = pWriteAcc->GetScanline(nYN);
+ Scanline pScanlineSrc = pWriteAcc->GetScanline(nY);
+ for( long nX = nSrcX, nXN = nDstX; nX <= nSrcEndX1; nX++, nXN++ )
+ pWriteAcc->SetPixelOnData( pScanline, nXN, pWriteAcc->GetPixelFromData( pScanlineSrc, nX ) );
+ }
+ }
+ else if( ( nDstX <= nSrcX ) && ( nDstY >= nSrcY ) )
+ {
+ for( long nY = nSrcEndY1, nYN = nDstEndY1; nY >= nSrcY; nY--, nYN-- )
+ {
+ Scanline pScanline = pWriteAcc->GetScanline(nYN);
+ Scanline pScanlineSrc = pWriteAcc->GetScanline(nY);
+ for( long nX = nSrcX, nXN = nDstX; nX <= nSrcEndX1; nX++, nXN++ )
+ pWriteAcc->SetPixelOnData( pScanline, nXN, pWriteAcc->GetPixelFromData( pScanlineSrc, nX ) );
+ }
+ }
+ else if( ( nDstX >= nSrcX ) && ( nDstY <= nSrcY ) )
+ {
+ for( long nY = nSrcY, nYN = nDstY; nY <= nSrcEndY1; nY++, nYN++ )
+ {
+ Scanline pScanline = pWriteAcc->GetScanline(nYN);
+ Scanline pScanlineSrc = pWriteAcc->GetScanline(nY);
+ for( long nX = nSrcEndX1, nXN = nDstEndX1; nX >= nSrcX; nX--, nXN-- )
+ pWriteAcc->SetPixelOnData( pScanline, nXN, pWriteAcc->GetPixelFromData( pScanlineSrc, nX ) );
+ }
+ }
+ else
+ {
+ for( long nY = nSrcEndY1, nYN = nDstEndY1; nY >= nSrcY; nY--, nYN-- )
+ {
+ Scanline pScanline = pWriteAcc->GetScanline(nYN);
+ Scanline pScanlineSrc = pWriteAcc->GetScanline(nY);
+ for( long nX = nSrcEndX1, nXN = nDstEndX1; nX >= nSrcX; nX--, nXN-- )
+ pWriteAcc->SetPixelOnData( pScanline, nXN, pWriteAcc->GetPixelFromData( pScanlineSrc, nX ) );
+ }
+ }
+
+ pWriteAcc.reset();
+ bRet = true;
+ }
+ }
+ }
+ }
+
+ return bRet;
+}
+
+bool Bitmap::CopyPixel_AlphaOptimized( const tools::Rectangle& rRectDst, const tools::Rectangle& rRectSrc,
+ const Bitmap* pBmpSrc )
+{
+ // Note: this code is copied from Bitmap::CopyPixel but avoids any palette lookups
+ // This optimization is possible because the palettes of AlphaMasks are always identical (8bit GreyPalette, see ctor)
+ const Size aSizePix( GetSizePixel() );
+ tools::Rectangle aRectDst( rRectDst );
+ bool bRet = false;
+
+ aRectDst.Intersection( tools::Rectangle( Point(), aSizePix ) );
+
+ if( !aRectDst.IsEmpty() )
+ {
+ if( pBmpSrc && ( pBmpSrc->mxImpBmp != mxImpBmp ) )
+ {
+ Bitmap* pSrc = const_cast<Bitmap*>(pBmpSrc);
+ const Size aCopySizePix( pSrc->GetSizePixel() );
+ tools::Rectangle aRectSrc( rRectSrc );
+
+ aRectSrc.Intersection( tools::Rectangle( Point(), aCopySizePix ) );
+
+ if( !aRectSrc.IsEmpty() )
+ {
+ ScopedReadAccess pReadAcc(*pSrc);
+
+ if( pReadAcc )
+ {
+ ScopedWriteAccess pWriteAcc(*this);
+
+ if( pWriteAcc )
+ {
+ const long nWidth = std::min( aRectSrc.GetWidth(), aRectDst.GetWidth() );
+ const long nHeight = std::min( aRectSrc.GetHeight(), aRectDst.GetHeight() );
+ const long nSrcEndX = aRectSrc.Left() + nWidth;
+ const long nSrcEndY = aRectSrc.Top() + nHeight;
+ long nDstY = aRectDst.Top();
+
+ for( long nSrcY = aRectSrc.Top(); nSrcY < nSrcEndY; nSrcY++, nDstY++)
+ {
+ Scanline pScanline = pWriteAcc->GetScanline(nDstY);
+ Scanline pScanlineRead = pReadAcc->GetScanline(nSrcY);
+ for( long nSrcX = aRectSrc.Left(), nDstX = aRectDst.Left(); nSrcX < nSrcEndX; nSrcX++, nDstX++ )
+ pWriteAcc->SetPixelOnData( pScanline, nDstX, pReadAcc->GetPixelFromData( pScanlineRead, nSrcX ) );
+ }
+
+ pWriteAcc.reset();
+ bRet = ( nWidth > 0 ) && ( nHeight > 0 );
+ }
+
+ pReadAcc.reset();
+ }
+ }
+ }
+ else
+ {
+ tools::Rectangle aRectSrc( rRectSrc );
+
+ aRectSrc.Intersection( tools::Rectangle( Point(), aSizePix ) );
+
+ if( !aRectSrc.IsEmpty() && ( aRectSrc != aRectDst ) )
+ {
+ ScopedWriteAccess pWriteAcc(*this);
+
+ if( pWriteAcc )
+ {
+ const long nWidth = std::min( aRectSrc.GetWidth(), aRectDst.GetWidth() );
+ const long nHeight = std::min( aRectSrc.GetHeight(), aRectDst.GetHeight() );
+ const long nSrcX = aRectSrc.Left();
+ const long nSrcY = aRectSrc.Top();
+ const long nSrcEndX1 = nSrcX + nWidth - 1;
+ const long nSrcEndY1 = nSrcY + nHeight - 1;
+ const long nDstX = aRectDst.Left();
+ const long nDstY = aRectDst.Top();
+ const long nDstEndX1 = nDstX + nWidth - 1;
+ const long nDstEndY1 = nDstY + nHeight - 1;
+
+ if( ( nDstX <= nSrcX ) && ( nDstY <= nSrcY ) )
+ {
+ for( long nY = nSrcY, nYN = nDstY; nY <= nSrcEndY1; nY++, nYN++ )
+ {
+ Scanline pScanline = pWriteAcc->GetScanline(nYN);
+ Scanline pScanlineSrc = pWriteAcc->GetScanline(nY);
+ for( long nX = nSrcX, nXN = nDstX; nX <= nSrcEndX1; nX++, nXN++ )
+ pWriteAcc->SetPixelOnData( pScanline, nXN, pWriteAcc->GetPixelFromData( pScanlineSrc, nX ) );
+ }
+ }
+ else if( ( nDstX <= nSrcX ) && ( nDstY >= nSrcY ) )
+ {
+ for( long nY = nSrcEndY1, nYN = nDstEndY1; nY >= nSrcY; nY--, nYN-- )
+ {
+ Scanline pScanline = pWriteAcc->GetScanline(nYN);
+ Scanline pScanlineSrc = pWriteAcc->GetScanline(nY);
+ for( long nX = nSrcX, nXN = nDstX; nX <= nSrcEndX1; nX++, nXN++ )
+ pWriteAcc->SetPixelOnData( pScanline, nXN, pWriteAcc->GetPixelFromData( pScanlineSrc, nX ) );
+ }
+ }
+ else if( ( nDstX >= nSrcX ) && ( nDstY <= nSrcY ) )
+ {
+ for( long nY = nSrcY, nYN = nDstY; nY <= nSrcEndY1; nY++, nYN++ )
+ {
+ Scanline pScanline = pWriteAcc->GetScanline(nYN);
+ Scanline pScanlineSrc = pWriteAcc->GetScanline(nY);
+ for( long nX = nSrcEndX1, nXN = nDstEndX1; nX >= nSrcX; nX--, nXN-- )
+ pWriteAcc->SetPixelOnData( pScanline, nXN, pWriteAcc->GetPixelFromData( pScanlineSrc, nX ) );
+ }
+ }
+ else
+ {
+ for( long nY = nSrcEndY1, nYN = nDstEndY1; nY >= nSrcY; nY--, nYN-- )
+ {
+ Scanline pScanline = pWriteAcc->GetScanline(nYN);
+ Scanline pScanlineSrc = pWriteAcc->GetScanline(nY);
+ for( long nX = nSrcEndX1, nXN = nDstEndX1; nX >= nSrcX; nX--, nXN-- )
+ pWriteAcc->SetPixelOnData( pScanline, nXN, pWriteAcc->GetPixelFromData( pScanlineSrc, nX ) );
+ }
+ }
+
+ pWriteAcc.reset();
+ bRet = true;
+ }
+ }
+ }
+ }
+
+ return bRet;
+
+}
+
+bool Bitmap::Expand( sal_uLong nDX, sal_uLong nDY, const Color* pInitColor )
+{
+ bool bRet = false;
+
+ if( nDX || nDY )
+ {
+ const Size aSizePixel( GetSizePixel() );
+ const long nWidth = aSizePixel.Width();
+ const long nHeight = aSizePixel.Height();
+ const Size aNewSize( nWidth + nDX, nHeight + nDY );
+ ScopedReadAccess pReadAcc(*this);
+
+ if( pReadAcc )
+ {
+ BitmapPalette aBmpPal( pReadAcc->GetPalette() );
+ Bitmap aNewBmp( aNewSize, GetBitCount(), &aBmpPal );
+ ScopedWriteAccess pWriteAcc(aNewBmp);
+
+ if( pWriteAcc )
+ {
+ BitmapColor aColor;
+ const long nNewX = nWidth;
+ const long nNewY = nHeight;
+ const long nNewWidth = pWriteAcc->Width();
+ const long nNewHeight = pWriteAcc->Height();
+ long nX;
+ long nY;
+
+ if( pInitColor )
+ aColor = pWriteAcc->GetBestMatchingColor( *pInitColor );
+
+ for( nY = 0; nY < nHeight; nY++ )
+ {
+ pWriteAcc->CopyScanline( nY, *pReadAcc );
+
+ if( pInitColor && nDX )
+ {
+ Scanline pScanline = pWriteAcc->GetScanline(nY);
+ for( nX = nNewX; nX < nNewWidth; nX++ )
+ pWriteAcc->SetPixelOnData( pScanline, nX, aColor );
+ }
+ }
+
+ if( pInitColor && nDY )
+ for( nY = nNewY; nY < nNewHeight; nY++ )
+ {
+ Scanline pScanline = pWriteAcc->GetScanline(nY);
+ for( nX = 0; nX < nNewWidth; nX++ )
+ pWriteAcc->SetPixelOnData( pScanline, nX, aColor );
+ }
+
+ pWriteAcc.reset();
+ bRet = true;
+ }
+
+ pReadAcc.reset();
+
+ if( bRet )
+ ImplAssignWithSize( aNewBmp );
+ }
+ }
+
+ 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 );
+
+ SalGraphics* pDispGraphics = pDisplay->GetGraphics();
+
+ if( mxImpBmp && pDispGraphics )
+ {
+ std::shared_ptr<ImpBitmap> xImpDispBmp(new ImpBitmap);
+ if (xImpDispBmp->ImplCreate(*mxImpBmp, pDispGraphics))
+ aDispBmp.ImplSetImpBitmap(xImpDispBmp);
+ }
+
+ 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);
+ bool bRet = false;
+
+ if( pReadAcc )
+ {
+ Bitmap aNewBmp( GetSizePixel(), 1 );
+ ScopedWriteAccess pWriteAcc(aNewBmp);
+
+ if( pWriteAcc )
+ {
+ const BitmapColor aBlack( pWriteAcc->GetBestMatchingColor( COL_BLACK ) );
+ const BitmapColor aWhite( pWriteAcc->GetBestMatchingColor( COL_WHITE ) );
+ const long nWidth = pWriteAcc->Width();
+ const long nHeight = pWriteAcc->Height();
+
+ 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++ )
+ {
+ const sal_uInt8 cIndex = pReadAcc->GetIndexFromData( pScanlineRead, nX );
+ if( pReadAcc->GetPaletteColor( cIndex ).GetLuminance() >=
+ cThreshold )
+ {
+ 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++ )
+ {
+ if( pReadAcc->GetPixelFromData( pScanlineRead, nX ).GetLuminance() >=
+ cThreshold )
+ {
+ pWriteAcc->SetPixelOnData( pScanline, nX, aWhite );
+ }
+ else
+ pWriteAcc->SetPixelOnData( pScanline, nX, aBlack );
+ }
+ }
+ }
+
+ pWriteAcc.reset();
+ bRet = true;
+ }
+
+ pReadAcc.reset();
+
+ if( bRet )
+ {
+ const MapMode aMap( maPrefMapMode );
+ const Size aSize( maPrefSize );
+
+ *this = aNewBmp;
+
+ maPrefMapMode = aMap;
+ maPrefSize = aSize;
+ }
+ }
+
+ return bRet;
+}
+
+bool Bitmap::GetSystemData( BitmapSystemData& rData ) const
+{
+ bool bRet = false;
+ if (mxImpBmp)
+ {
+ SalBitmap* pSalBitmap = mxImpBmp->ImplGetSalBitmap();
+ if( pSalBitmap )
+ bRet = pSalBitmap->GetSystemData( rData );
+ }
+
+ return bRet;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */