diff options
author | Chris Sherlock <chris.sherlock79@gmail.com> | 2018-03-01 06:25:40 +1100 |
---|---|---|
committer | Tomaž Vajngerl <quikee@gmail.com> | 2018-03-05 08:24:15 +0100 |
commit | 1b51bca4ce77bdeefd2461e3b8a8b6b38bda6d43 (patch) | |
tree | 8a88ba9cc4bc5ddad11a6d697039df2edf79f61b /vcl/source/bitmap/bitmap.cxx | |
parent | 54638c88963c21e468082573f6b4c53ce427103c (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.cxx | 2005 |
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: */ |