/************************************************************** * * 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 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * *************************************************************/ // MARKER(update_precomp.py): autogen include statement, do not remove #include "precompiled_vcl.hxx" #include #include #include #include #include #include #include #include #include #include #include #include #include // ---------- // - Bitmap - // ---------- Bitmap::Bitmap() : mpImpBmp( NULL ) { } // ------------------------------------------------------------------ Bitmap::Bitmap( const ResId& rResId ) : mpImpBmp( NULL ) { const BitmapEx aBmpEx( rResId ); if( !aBmpEx.IsEmpty() ) *this = aBmpEx.GetBitmap(); } // ------------------------------------------------------------------ Bitmap::Bitmap( const Bitmap& rBitmap ) : maPrefMapMode ( rBitmap.maPrefMapMode ), maPrefSize ( rBitmap.maPrefSize ) { mpImpBmp = rBitmap.mpImpBmp; if ( mpImpBmp ) mpImpBmp->ImplIncRefCount(); } // ------------------------------------------------------------------ Bitmap::Bitmap( SalBitmap* pSalBitmap ) { mpImpBmp = new ImpBitmap(); mpImpBmp->ImplSetSalBitmap( pSalBitmap ); maPrefMapMode = MapMode( MAP_PIXEL ); maPrefSize = mpImpBmp->ImplGetSize(); } // ------------------------------------------------------------------ Bitmap::Bitmap( const Size& rSizePixel, sal_uInt16 nBitCount, const BitmapPalette* pPal ) { if( rSizePixel.Width() && rSizePixel.Height() ) { BitmapPalette aPal; BitmapPalette* pRealPal = NULL; if( nBitCount <= 8 ) { if( !pPal ) { if( 1 == nBitCount ) { aPal.SetEntryCount( 2 ); aPal[ 0 ] = Color( COL_BLACK ); aPal[ 1 ] = Color( COL_WHITE ); } else if( ( 4 == nBitCount ) || ( 8 == nBitCount ) ) { aPal.SetEntryCount( 1 << nBitCount ); aPal[ 0 ] = Color( COL_BLACK ); aPal[ 1 ] = Color( COL_BLUE ); aPal[ 2 ] = Color( COL_GREEN ); aPal[ 3 ] = Color( COL_CYAN ); aPal[ 4 ] = Color( COL_RED ); aPal[ 5 ] = Color( COL_MAGENTA ); aPal[ 6 ] = Color( COL_BROWN ); aPal[ 7 ] = Color( COL_GRAY ); aPal[ 8 ] = Color( COL_LIGHTGRAY ); aPal[ 9 ] = Color( COL_LIGHTBLUE ); aPal[ 10 ] = Color( COL_LIGHTGREEN ); aPal[ 11 ] = Color( COL_LIGHTCYAN ); aPal[ 12 ] = Color( COL_LIGHTRED ); aPal[ 13 ] = Color( COL_LIGHTMAGENTA ); aPal[ 14 ] = Color( COL_YELLOW ); aPal[ 15 ] = Color( COL_WHITE ); // Dither-Palette erzeugen 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( (sal_uInt8) nR, (sal_uInt8) nG, (sal_uInt8) nB ); // Standard-Office-Farbe setzen aPal[ nActCol++ ] = BitmapColor( 0, 184, 255 ); } } } else pRealPal = (BitmapPalette*) pPal; } mpImpBmp = new ImpBitmap; mpImpBmp->ImplCreate( rSizePixel, nBitCount, pRealPal ? *pRealPal : aPal ); } else mpImpBmp = NULL; } // ------------------------------------------------------------------ Bitmap::~Bitmap() { ImplReleaseRef(); } // ------------------------------------------------------------------ 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, cGreyInc = 17; aGreyPalette16.SetEntryCount( 16 ); for( sal_uInt16 i = 0; i < 16; i++, cGrey = sal::static_int_cast(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( (sal_uInt8) i, (sal_uInt8) i, (sal_uInt8) i ); } return aGreyPalette256; } } else { DBG_ERROR( "Bitmap::GetGreyPalette: invalid entry count (2/4/16/256 allowed)" ); return aGreyPalette2; } } // ------------------------------------------------------------------ bool BitmapPalette::IsGreyPalette() const { // TODO: add an IsGreyPalette flag to BitmapPalette // TODO: unless this causes problems binary compatibility 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; } // TODO: is it worth to compare the entries? return false; } // ------------------------------------------------------------------ Bitmap& Bitmap::operator=( const Bitmap& rBitmap ) { maPrefSize = rBitmap.maPrefSize; maPrefMapMode = rBitmap.maPrefMapMode; if ( rBitmap.mpImpBmp ) rBitmap.mpImpBmp->ImplIncRefCount(); ImplReleaseRef(); mpImpBmp = rBitmap.mpImpBmp; return *this; } // ------------------------------------------------------------------ sal_Bool Bitmap::IsEqual( const Bitmap& rBmp ) const { return( IsSameInstance( rBmp ) || ( rBmp.GetSizePixel() == GetSizePixel() && rBmp.GetBitCount() == GetBitCount() && rBmp.GetChecksum() == GetChecksum() ) ); } // ------------------------------------------------------------------ void Bitmap::SetEmpty() { maPrefMapMode = MapMode(); maPrefSize = Size(); ImplReleaseRef(); mpImpBmp = NULL; } // ------------------------------------------------------------------ Size Bitmap::GetSizePixel() const { return( mpImpBmp ? mpImpBmp->ImplGetSize() : Size() ); } // ------------------------------------------------------------------ void Bitmap::SetSizePixel( const Size& rNewSize, sal_uInt32 nScaleFlag ) { if(GetSizePixel() != rNewSize) { Scale( rNewSize, nScaleFlag ); } } // ------------------------------------------------------------------ Size Bitmap::GetSourceSizePixel() const { return( mpImpBmp ? mpImpBmp->ImplGetSourceSize() : Size() ); } // ------------------------------------------------------------------ void Bitmap::SetSourceSizePixel( const Size& rSize) { if( mpImpBmp ) mpImpBmp->ImplSetSourceSize( rSize); } // ------------------------------------------------------------------ sal_uInt16 Bitmap::GetBitCount() const { return( mpImpBmp ? mpImpBmp->ImplGetBitCount() : 0 ); } // ------------------------------------------------------------------ sal_Bool Bitmap::HasGreyPalette() const { const sal_uInt16 nBitCount = GetBitCount(); sal_Bool bRet = sal_False; if( 1 == nBitCount ) { BitmapReadAccess* pRAcc = ( (Bitmap*) this )->AcquireReadAccess(); if( pRAcc ) { const BitmapColor& rCol0( pRAcc->GetPaletteColor( 0 ) ); const BitmapColor& rCol1( pRAcc->GetPaletteColor( 1 ) ); if( rCol0.GetRed() == rCol0.GetGreen() && rCol0.GetRed() == rCol0.GetBlue() && rCol1.GetRed() == rCol1.GetGreen() && rCol1.GetRed() == rCol1.GetBlue() ) { bRet = sal_True; } ( (Bitmap*) this )->ReleaseAccess( pRAcc ); } else bRet = sal_True; } else if( 4 == nBitCount || 8 == nBitCount ) { BitmapReadAccess* pRAcc = ( (Bitmap*) this )->AcquireReadAccess(); if( pRAcc ) { if( pRAcc->HasPalette() && ( (BitmapPalette&) pRAcc->GetPalette() == GetGreyPalette( 1 << nBitCount ) ) ) bRet = sal_True; ( (Bitmap*) this )->ReleaseAccess( pRAcc ); } } return bRet; } // ------------------------------------------------------------------ sal_uLong Bitmap::GetChecksum() const { sal_uLong nRet = 0UL; if( mpImpBmp ) { nRet = mpImpBmp->ImplGetChecksum(); if( !nRet ) { BitmapReadAccess* pRAcc = ( (Bitmap*) this )->AcquireReadAccess(); if( pRAcc && pRAcc->Width() && pRAcc->Height() ) { sal_uInt32 nCrc = 0; SVBT32 aBT32; pRAcc->ImplZeroInitUnusedBits(); UInt32ToSVBT32( pRAcc->Width(), aBT32 ); nCrc = rtl_crc32( nCrc, aBT32, 4 ); UInt32ToSVBT32( pRAcc->Height(), aBT32 ); nCrc = rtl_crc32( nCrc, aBT32, 4 ); UInt32ToSVBT32( pRAcc->GetBitCount(), aBT32 ); nCrc = rtl_crc32( nCrc, aBT32, 4 ); UInt32ToSVBT32( pRAcc->GetColorMask().GetRedMask(), aBT32 ); nCrc = rtl_crc32( nCrc, aBT32, 4 ); UInt32ToSVBT32( pRAcc->GetColorMask().GetGreenMask(), aBT32 ); nCrc = rtl_crc32( nCrc, aBT32, 4 ); UInt32ToSVBT32( pRAcc->GetColorMask().GetBlueMask(), aBT32 ); nCrc = rtl_crc32( nCrc, aBT32, 4 ); if( pRAcc->HasPalette() ) { nCrc = rtl_crc32( nCrc, pRAcc->GetPalette().ImplGetColorBuffer(), pRAcc->GetPaletteEntryCount() * sizeof( BitmapColor ) ); } nCrc = rtl_crc32( nCrc, pRAcc->GetBuffer(), pRAcc->GetScanlineSize() * pRAcc->Height() ); mpImpBmp->ImplSetChecksum( nRet = nCrc ); } if (pRAcc) ( (Bitmap*) this )->ReleaseAccess( pRAcc ); } } return nRet; } // ------------------------------------------------------------------ void Bitmap::ImplReleaseRef() { if( mpImpBmp ) { if( mpImpBmp->ImplGetRefCount() > 1UL ) mpImpBmp->ImplDecRefCount(); else { delete mpImpBmp; mpImpBmp = NULL; } } } // ------------------------------------------------------------------ void Bitmap::ImplMakeUnique() { if( mpImpBmp && mpImpBmp->ImplGetRefCount() > 1UL ) { ImpBitmap* pOldImpBmp = mpImpBmp; pOldImpBmp->ImplDecRefCount(); mpImpBmp = new ImpBitmap; mpImpBmp->ImplCreate( *pOldImpBmp ); } } // ------------------------------------------------------------------ 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.Width() = FRound( maPrefSize.Width() * aNewSizePix.Width() / aOldSizePix.Width() ); aNewPrefSize.Height() = FRound( maPrefSize.Height() * aNewSizePix.Height() / aOldSizePix.Height() ); } else aNewPrefSize = maPrefSize; *this = rBitmap; maPrefSize = aNewPrefSize; maPrefMapMode = aOldMapMode; } // ------------------------------------------------------------------ ImpBitmap* Bitmap::ImplGetImpBitmap() const { return mpImpBmp; } // ------------------------------------------------------------------ void Bitmap::ImplSetImpBitmap( ImpBitmap* pImpBmp ) { if( pImpBmp != mpImpBmp ) { ImplReleaseRef(); mpImpBmp = pImpBmp; } } // ------------------------------------------------------------------ BitmapReadAccess* Bitmap::AcquireReadAccess() { BitmapReadAccess* pReadAccess = new BitmapReadAccess( *this ); if( !*pReadAccess ) { delete pReadAccess; pReadAccess = NULL; } return pReadAccess; } // ------------------------------------------------------------------ BitmapWriteAccess* Bitmap::AcquireWriteAccess() { BitmapWriteAccess* pWriteAccess = new BitmapWriteAccess( *this ); if( !*pWriteAccess ) { delete pWriteAccess; pWriteAccess = NULL; } return pWriteAccess; } // ------------------------------------------------------------------ void Bitmap::ReleaseAccess( BitmapReadAccess* pBitmapAccess ) { delete pBitmapAccess; } // ------------------------------------------------------------------ sal_Bool Bitmap::Erase( const Color& rFillColor ) { if( !(*this) ) return sal_True; BitmapWriteAccess* pWriteAcc = AcquireWriteAccess(); sal_Bool bRet = sal_False; if( pWriteAcc ) { const sal_uLong nFormat = pWriteAcc->GetScanlineFormat(); sal_uInt8 cIndex = 0; sal_Bool bFast = sal_False; switch( nFormat ) { case( BMP_FORMAT_1BIT_MSB_PAL ): case( BMP_FORMAT_1BIT_LSB_PAL ): { cIndex = (sal_uInt8) pWriteAcc->GetBestPaletteIndex( rFillColor ); cIndex = ( cIndex ? 255 : 0 ); bFast = sal_True; } break; case( BMP_FORMAT_4BIT_MSN_PAL ): case( BMP_FORMAT_4BIT_LSN_PAL ): { cIndex = (sal_uInt8) pWriteAcc->GetBestPaletteIndex( rFillColor ); cIndex = cIndex | ( cIndex << 4 ); bFast = sal_True; } break; case( BMP_FORMAT_8BIT_PAL ): { cIndex = (sal_uInt8) pWriteAcc->GetBestPaletteIndex( rFillColor ); bFast = sal_True; } break; case( BMP_FORMAT_24BIT_TC_BGR ): case( BMP_FORMAT_24BIT_TC_RGB ): { if( ( rFillColor.GetRed() == rFillColor.GetGreen() ) && ( rFillColor.GetRed() == rFillColor.GetBlue() ) ) { cIndex = rFillColor.GetRed(); bFast = sal_True; } else bFast = sal_False; } break; default: bFast = sal_False; break; } if( bFast ) { const sal_uLong nBufSize = pWriteAcc->GetScanlineSize() * pWriteAcc->Height(); memset( pWriteAcc->GetBuffer(), cIndex, nBufSize ); } else { Point aTmpPoint; const Rectangle aRect( aTmpPoint, Size( pWriteAcc->Width(), pWriteAcc->Height() ) ); pWriteAcc->SetFillColor( rFillColor ); pWriteAcc->FillRect( aRect ); } ReleaseAccess( pWriteAcc ); bRet = sal_True; } return bRet; } // ------------------------------------------------------------------ sal_Bool Bitmap::Invert() { BitmapWriteAccess* pAcc = AcquireWriteAccess(); sal_Bool bRet = sal_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 nX = 0L; nX < nWidth; nX++ ) for( long nY = 0L; nY < nHeight; nY++ ) pAcc->SetPixel( nY, nX, pAcc->GetPixel( nY, nX ).Invert() ); } ReleaseAccess( pAcc ); bRet = sal_True; } return bRet; } // ------------------------------------------------------------------ sal_Bool Bitmap::Mirror( sal_uLong nMirrorFlags ) { sal_Bool bHorz = ( ( nMirrorFlags & BMP_MIRROR_HORZ ) == BMP_MIRROR_HORZ ); sal_Bool bVert = ( ( nMirrorFlags & BMP_MIRROR_VERT ) == BMP_MIRROR_VERT ); sal_Bool bRet = sal_False; if( bHorz && !bVert ) { BitmapWriteAccess* pAcc = AcquireWriteAccess(); if( pAcc ) { const long nWidth = pAcc->Width(); const long nHeight = pAcc->Height(); const long nWidth1 = nWidth - 1L; const long nWidth_2 = nWidth >> 1L; for( long nY = 0L; nY < nHeight; nY++ ) { for( long nX = 0L, nOther = nWidth1; nX < nWidth_2; nX++, nOther-- ) { const BitmapColor aTemp( pAcc->GetPixel( nY, nX ) ); pAcc->SetPixel( nY, nX, pAcc->GetPixel( nY, nOther ) ); pAcc->SetPixel( nY, nOther, aTemp ); } } ReleaseAccess( pAcc ); bRet = sal_True; } } else if( bVert && !bHorz ) { BitmapWriteAccess* pAcc = AcquireWriteAccess(); if( pAcc ) { const long nScanSize = pAcc->GetScanlineSize(); sal_uInt8* pBuffer = new sal_uInt8[ nScanSize ]; const long nHeight = pAcc->Height(); const long nHeight1 = nHeight - 1L; const long nHeight_2 = nHeight >> 1L; for( long nY = 0L, nOther = nHeight1; nY < nHeight_2; nY++, nOther-- ) { memcpy( pBuffer, pAcc->GetScanline( nY ), nScanSize ); memcpy( pAcc->GetScanline( nY ), pAcc->GetScanline( nOther ), nScanSize ); memcpy( pAcc->GetScanline( nOther ), pBuffer, nScanSize ); } delete[] pBuffer; ReleaseAccess( pAcc ); bRet = sal_True; } } else if( bHorz && bVert ) { BitmapWriteAccess* pAcc = AcquireWriteAccess(); if( pAcc ) { const long nWidth = pAcc->Width(); const long nWidth1 = nWidth - 1L; const long nHeight = pAcc->Height(); long nHeight_2 = nHeight >> 1; for( long nY = 0L, nOtherY = nHeight - 1L; nY < nHeight_2; nY++, nOtherY-- ) { for( long nX = 0L, nOtherX = nWidth1; nX < nWidth; nX++, nOtherX-- ) { const BitmapColor aTemp( pAcc->GetPixel( nY, nX ) ); pAcc->SetPixel( nY, nX, pAcc->GetPixel( nOtherY, nOtherX ) ); pAcc->SetPixel( nOtherY, nOtherX, aTemp ); } } // ggf. noch mittlere Zeile horizontal spiegeln if( nHeight & 1 ) { for( long nX = 0L, nOtherX = nWidth1, nWidth_2 = nWidth >> 1; nX < nWidth_2; nX++, nOtherX-- ) { const BitmapColor aTemp( pAcc->GetPixel( nHeight_2, nX ) ); pAcc->SetPixel( nHeight_2, nX, pAcc->GetPixel( nHeight_2, nOtherX ) ); pAcc->SetPixel( nHeight_2, nOtherX, aTemp ); } } ReleaseAccess( pAcc ); bRet = sal_True; } } else bRet = sal_True; return bRet; } // ------------------------------------------------------------------ sal_Bool Bitmap::Rotate( long nAngle10, const Color& rFillColor ) { sal_Bool bRet = sal_False; nAngle10 %= 3600L; nAngle10 = ( nAngle10 < 0L ) ? ( 3599L + nAngle10 ) : nAngle10; if( !nAngle10 ) bRet = sal_True; else if( 1800L == nAngle10 ) bRet = Mirror( BMP_MIRROR_HORZ | BMP_MIRROR_VERT ); else { BitmapReadAccess* pReadAcc = AcquireReadAccess(); Bitmap aRotatedBmp; if( pReadAcc ) { const Size aSizePix( GetSizePixel() ); if( ( 900L == nAngle10 ) || ( 2700L == nAngle10 ) ) { const Size aNewSizePix( aSizePix.Height(), aSizePix.Width() ); Bitmap aNewBmp( aNewSizePix, GetBitCount(), &pReadAcc->GetPalette() ); BitmapWriteAccess* pWriteAcc = aNewBmp.AcquireWriteAccess(); if( pWriteAcc ) { const long nWidth = aSizePix.Width(); const long nWidth1 = nWidth - 1L; const long nHeight = aSizePix.Height(); const long nHeight1 = nHeight - 1L; const long nNewWidth = aNewSizePix.Width(); const long nNewHeight = aNewSizePix.Height(); if( 900L == nAngle10 ) { for( long nY = 0L, nOtherX = nWidth1; nY < nNewHeight; nY++, nOtherX-- ) for( long nX = 0L, nOtherY = 0L; nX < nNewWidth; nX++ ) pWriteAcc->SetPixel( nY, nX, pReadAcc->GetPixel( nOtherY++, nOtherX ) ); } else if( 2700L == nAngle10 ) { for( long nY = 0L, nOtherX = 0L; nY < nNewHeight; nY++, nOtherX++ ) for( long nX = 0L, nOtherY = nHeight1; nX < nNewWidth; nX++ ) pWriteAcc->SetPixel( nY, nX, pReadAcc->GetPixel( nOtherY--, nOtherX ) ); } aNewBmp.ReleaseAccess( pWriteAcc ); } aRotatedBmp = aNewBmp; } else { Point aTmpPoint; Rectangle aTmpRectangle( aTmpPoint, aSizePix ); Polygon aPoly( aTmpRectangle ); aPoly.Rotate( aTmpPoint, (sal_uInt16) nAngle10 ); Rectangle aNewBound( aPoly.GetBoundRect() ); const Size aNewSizePix( aNewBound.GetSize() ); Bitmap aNewBmp( aNewSizePix, GetBitCount(), &pReadAcc->GetPalette() ); BitmapWriteAccess* pWriteAcc = aNewBmp.AcquireWriteAccess(); 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; long nSinY; long nCosY; long* pCosX = new long[ nNewWidth ]; long* pSinX = new long[ nNewWidth ]; long* pCosY = new long[ nNewHeight ]; 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 = 0L; nY < nNewHeight; nY++ ) { nSinY = pSinY[ nY ]; nCosY = pCosY[ nY ]; for( nX = 0L; nX < nNewWidth; nX++ ) { nRotX = ( pCosX[ nX ] - nSinY ) >> 6; nRotY = ( pSinX[ nX ] + nCosY ) >> 6; if ( ( nRotX > -1L ) && ( nRotX < nWidth ) && ( nRotY > -1L ) && ( nRotY < nHeight ) ) pWriteAcc->SetPixel( nY, nX, pReadAcc->GetPixel( nRotY, nRotX ) ); else pWriteAcc->SetPixel( nY, nX, aFillColor ); } } delete[] pSinX; delete[] pCosX; delete[] pSinY; delete[] pCosY; aNewBmp.ReleaseAccess( pWriteAcc ); } aRotatedBmp = aNewBmp; } ReleaseAccess( pReadAcc ); } if( ( bRet = !!aRotatedBmp ) == sal_True ) ImplAssignWithSize( aRotatedBmp ); } return bRet; }; // ------------------------------------------------------------------ sal_Bool Bitmap::Crop( const Rectangle& rRectPixel ) { const Size aSizePix( GetSizePixel() ); Rectangle aRect( rRectPixel ); sal_Bool bRet = sal_False; aRect.Intersection( Rectangle( Point(), aSizePix ) ); if( !aRect.IsEmpty() ) { BitmapReadAccess* pReadAcc = AcquireReadAccess(); if( pReadAcc ) { Point aTmpPoint; const Rectangle aNewRect( aTmpPoint, aRect.GetSize() ); Bitmap aNewBmp( aNewRect.GetSize(), GetBitCount(), &pReadAcc->GetPalette() ); BitmapWriteAccess* pWriteAcc = aNewBmp.AcquireWriteAccess(); 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++ ) for( long nX = 0, nX2 = nOldX; nX < nNewWidth; nX++, nX2++ ) pWriteAcc->SetPixel( nY, nX, pReadAcc->GetPixel( nY2, nX2 ) ); aNewBmp.ReleaseAccess( pWriteAcc ); bRet = sal_True; } ReleaseAccess( pReadAcc ); if( bRet ) ImplAssignWithSize( aNewBmp ); } } return bRet; }; // ------------------------------------------------------------------ sal_Bool Bitmap::CopyPixel( const Rectangle& rRectDst, const Rectangle& rRectSrc, const Bitmap* pBmpSrc ) { const Size aSizePix( GetSizePixel() ); Rectangle aRectDst( rRectDst ); sal_Bool bRet = sal_False; aRectDst.Intersection( Rectangle( Point(), aSizePix ) ); if( !aRectDst.IsEmpty() ) { if( pBmpSrc && ( *pBmpSrc != *this ) ) { Bitmap* pSrc = (Bitmap*) pBmpSrc; const Size aCopySizePix( pSrc->GetSizePixel() ); Rectangle aRectSrc( rRectSrc ); const sal_uInt16 nSrcBitCount = pBmpSrc->GetBitCount(); const sal_uInt16 nDstBitCount = GetBitCount(); if( nSrcBitCount > nDstBitCount ) { long nNextIndex = 0L; if( ( nSrcBitCount == 24 ) && ( nDstBitCount < 24 ) ) Convert( BMP_CONVERSION_24BIT ); else if( ( nSrcBitCount == 8 ) && ( nDstBitCount < 8 ) ) { Convert( BMP_CONVERSION_8BIT_COLORS ); nNextIndex = 16; } else if( ( nSrcBitCount == 4 ) && ( nDstBitCount < 4 ) ) { Convert( BMP_CONVERSION_4BIT_COLORS ); nNextIndex = 2; } if( nNextIndex ) { BitmapReadAccess* pSrcAcc = pSrc->AcquireReadAccess(); BitmapWriteAccess* pDstAcc = AcquireWriteAccess(); if( pSrcAcc && pDstAcc ) { const long nSrcCount = pDstAcc->GetPaletteEntryCount(); const long nDstCount = 1 << nDstBitCount; sal_Bool bFound; for( long i = 0L; ( i < nSrcCount ) && ( nNextIndex < nSrcCount ); i++ ) { const BitmapColor& rSrcCol = pSrcAcc->GetPaletteColor( (sal_uInt16) i ); bFound = sal_False; for( long j = 0L; j < nDstCount; j++ ) { if( rSrcCol == pDstAcc->GetPaletteColor( (sal_uInt16) j ) ) { bFound = sal_True; break; } } if( !bFound ) pDstAcc->SetPaletteColor( (sal_uInt16) nNextIndex++, rSrcCol ); } } if( pSrcAcc ) pSrc->ReleaseAccess( pSrcAcc ); if( pDstAcc ) ReleaseAccess( pDstAcc ); } } aRectSrc.Intersection( Rectangle( Point(), aCopySizePix ) ); if( !aRectSrc.IsEmpty() ) { BitmapReadAccess* pReadAcc = pSrc->AcquireReadAccess(); if( pReadAcc ) { BitmapWriteAccess* pWriteAcc = AcquireWriteAccess(); if( pWriteAcc ) { const long nWidth = Min( aRectSrc.GetWidth(), aRectDst.GetWidth() ); const long nHeight = 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(); sal_uInt8* pMap = new sal_uInt8[ nCount ]; // Index-Map fuer Farbtabelle // aufbauen, da das Bild ja (relativ) farbgenau // kopiert werden soll for( sal_uInt16 i = 0; i < nCount; i++ ) pMap[ i ] = (sal_uInt8) pWriteAcc->GetBestPaletteIndex( pReadAcc->GetPaletteColor( i ) ); for( long nSrcY = aRectSrc.Top(); nSrcY < nSrcEndY; nSrcY++, nDstY++ ) for( long nSrcX = aRectSrc.Left(), nDstX = aRectDst.Left(); nSrcX < nSrcEndX; nSrcX++, nDstX++ ) pWriteAcc->SetPixelIndex( nDstY, nDstX, pMap[ pReadAcc->GetPixelIndex( nSrcY, nSrcX ) ] ); delete[] pMap; } else if( pReadAcc->HasPalette() ) { for( long nSrcY = aRectSrc.Top(); nSrcY < nSrcEndY; nSrcY++, nDstY++ ) for( long nSrcX = aRectSrc.Left(), nDstX = aRectDst.Left(); nSrcX < nSrcEndX; nSrcX++, nDstX++ ) pWriteAcc->SetPixel( nDstY, nDstX, pReadAcc->GetPaletteColor( pReadAcc->GetPixelIndex( nSrcY, nSrcX ) ) ); } else for( long nSrcY = aRectSrc.Top(); nSrcY < nSrcEndY; nSrcY++, nDstY++ ) for( long nSrcX = aRectSrc.Left(), nDstX = aRectDst.Left(); nSrcX < nSrcEndX; nSrcX++, nDstX++ ) pWriteAcc->SetPixel( nDstY, nDstX, pReadAcc->GetPixel( nSrcY, nSrcX ) ); ReleaseAccess( pWriteAcc ); bRet = ( nWidth > 0L ) && ( nHeight > 0L ); } pSrc->ReleaseAccess( pReadAcc ); } } } else { Rectangle aRectSrc( rRectSrc ); aRectSrc.Intersection( Rectangle( Point(), aSizePix ) ); if( !aRectSrc.IsEmpty() && ( aRectSrc != aRectDst ) ) { BitmapWriteAccess* pWriteAcc = AcquireWriteAccess(); if( pWriteAcc ) { const long nWidth = Min( aRectSrc.GetWidth(), aRectDst.GetWidth() ); const long nHeight = Min( aRectSrc.GetHeight(), aRectDst.GetHeight() ); const long nSrcX = aRectSrc.Left(); const long nSrcY = aRectSrc.Top(); const long nSrcEndX1 = nSrcX + nWidth - 1L; const long nSrcEndY1 = nSrcY + nHeight - 1L; const long nDstX = aRectDst.Left(); const long nDstY = aRectDst.Top(); const long nDstEndX1 = nDstX + nWidth - 1L; const long nDstEndY1 = nDstY + nHeight - 1L; if( ( nDstX <= nSrcX ) && ( nDstY <= nSrcY ) ) { for( long nY = nSrcY, nYN = nDstY; nY <= nSrcEndY1; nY++, nYN++ ) for( long nX = nSrcX, nXN = nDstX; nX <= nSrcEndX1; nX++, nXN++ ) pWriteAcc->SetPixel( nYN, nXN, pWriteAcc->GetPixel( nY, nX ) ); } else if( ( nDstX <= nSrcX ) && ( nDstY >= nSrcY ) ) { for( long nY = nSrcEndY1, nYN = nDstEndY1; nY >= nSrcY; nY--, nYN-- ) for( long nX = nSrcX, nXN = nDstX; nX <= nSrcEndX1; nX++, nXN++ ) pWriteAcc->SetPixel( nYN, nXN, pWriteAcc->GetPixel( nY, nX ) ); } else if( ( nDstX >= nSrcX ) && ( nDstY <= nSrcY ) ) { for( long nY = nSrcY, nYN = nDstY; nY <= nSrcEndY1; nY++, nYN++ ) for( long nX = nSrcEndX1, nXN = nDstEndX1; nX >= nSrcX; nX--, nXN-- ) pWriteAcc->SetPixel( nYN, nXN, pWriteAcc->GetPixel( nY, nX ) ); } else { for( long nY = nSrcEndY1, nYN = nDstEndY1; nY >= nSrcY; nY--, nYN-- ) for( long nX = nSrcEndX1, nXN = nDstEndX1; nX >= nSrcX; nX--, nXN-- ) pWriteAcc->SetPixel( nYN, nXN, pWriteAcc->GetPixel( nY, nX ) ); } ReleaseAccess( pWriteAcc ); bRet = sal_True; } } } } return bRet; } // ------------------------------------------------------------------ sal_Bool Bitmap::Expand( sal_uLong nDX, sal_uLong nDY, const Color* pInitColor ) { sal_Bool bRet = sal_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 ); BitmapReadAccess* pReadAcc = AcquireReadAccess(); if( pReadAcc ) { BitmapPalette aBmpPal( pReadAcc->GetPalette() ); Bitmap aNewBmp( aNewSize, GetBitCount(), &aBmpPal ); BitmapWriteAccess* pWriteAcc = aNewBmp.AcquireWriteAccess(); 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 = 0L; nY < nHeight; nY++ ) { pWriteAcc->CopyScanline( nY, *pReadAcc ); if( pInitColor && nDX ) for( nX = nNewX; nX < nNewWidth; nX++ ) pWriteAcc->SetPixel( nY, nX, aColor ); } if( pInitColor && nDY ) for( nY = nNewY; nY < nNewHeight; nY++ ) for( nX = 0; nX < nNewWidth; nX++ ) pWriteAcc->SetPixel( nY, nX, aColor ); aNewBmp.ReleaseAccess( pWriteAcc ); bRet = sal_True; } ReleaseAccess( pReadAcc ); if( bRet ) ImplAssignWithSize( aNewBmp ); } } return bRet; } // ------------------------------------------------------------------ Bitmap Bitmap::CreateMask( const Color& rTransColor, sal_uLong nTol ) const { Bitmap aNewBmp( GetSizePixel(), 1 ); BitmapWriteAccess* pWriteAcc = aNewBmp.AcquireWriteAccess(); sal_Bool bRet = sal_False; if( pWriteAcc ) { BitmapReadAccess* pReadAcc = ( (Bitmap*) this )->AcquireReadAccess(); if( pReadAcc ) { const long nWidth = pReadAcc->Width(); const long nHeight = pReadAcc->Height(); const BitmapColor aBlack( pWriteAcc->GetBestMatchingColor( Color( COL_BLACK ) ) ); const BitmapColor aWhite( pWriteAcc->GetBestMatchingColor( Color( COL_WHITE ) ) ); if( !nTol ) { const BitmapColor aTest( pReadAcc->GetBestMatchingColor( rTransColor ) ); long nX, nY, nShift; if( pReadAcc->GetScanlineFormat() == BMP_FORMAT_4BIT_MSN_PAL || pReadAcc->GetScanlineFormat() == BMP_FORMAT_4BIT_LSN_PAL ) { // optimized for 4Bit-MSN/LSN source palette const sal_uInt8 cTest = aTest.GetIndex(); const long nShiftInit = ( ( pReadAcc->GetScanlineFormat() == BMP_FORMAT_4BIT_MSN_PAL ) ? 4 : 0 ); if( pWriteAcc->GetScanlineFormat() == BMP_FORMAT_1BIT_MSB_PAL && aWhite.GetIndex() == 1 ) { // optimized for 1Bit-MSB destination palette for( nY = 0L; nY < nHeight; nY++ ) { Scanline pSrc = pReadAcc->GetScanline( nY ); Scanline pDst = pWriteAcc->GetScanline( nY ); for( nX = 0L, 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( nY = 0L; nY < nHeight; nY++ ) { Scanline pSrc = pReadAcc->GetScanline( nY ); for( nX = 0L, nShift = nShiftInit; nX < nWidth; nX++, nShift ^= 4 ) { if( cTest == ( ( pSrc[ nX >> 1 ] >> nShift ) & 0x0f ) ) pWriteAcc->SetPixel( nY, nX, aWhite ); else pWriteAcc->SetPixel( nY, nX, aBlack ); } } } } else if( pReadAcc->GetScanlineFormat() == BMP_FORMAT_8BIT_PAL ) { // optimized for 8Bit source palette const sal_uInt8 cTest = aTest.GetIndex(); if( pWriteAcc->GetScanlineFormat() == BMP_FORMAT_1BIT_MSB_PAL && aWhite.GetIndex() == 1 ) { // optimized for 1Bit-MSB destination palette for( nY = 0L; nY < nHeight; nY++ ) { Scanline pSrc = pReadAcc->GetScanline( nY ); Scanline pDst = pWriteAcc->GetScanline( nY ); for( nX = 0L; nX < nWidth; nX++ ) { if( cTest == pSrc[ nX ] ) pDst[ nX >> 3 ] |= 1 << ( 7 - ( nX & 7 ) ); else pDst[ nX >> 3 ] &= ~( 1 << ( 7 - ( nX & 7 ) ) ); } } } else { for( nY = 0L; nY < nHeight; nY++ ) { Scanline pSrc = pReadAcc->GetScanline( nY ); for( nX = 0L; nX < nWidth; nX++ ) { if( cTest == pSrc[ nX ] ) pWriteAcc->SetPixel( nY, nX, aWhite ); else pWriteAcc->SetPixel( nY, nX, aBlack ); } } } } else { // not optimized for( nY = 0L; nY < nHeight; nY++ ) { for( nX = 0L; nX < nWidth; nX++ ) { if( aTest == pReadAcc->GetPixel( nY, nX ) ) pWriteAcc->SetPixel( nY, nX, aWhite ); else pWriteAcc->SetPixel( nY, 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 = 0L; nY < nHeight; nY++ ) { for( long nX = 0L; nX < nWidth; nX++ ) { aCol = pReadAcc->GetPaletteColor( pReadAcc->GetPixelIndex( nY, nX ) ); nR = aCol.GetRed(); nG = aCol.GetGreen(); nB = aCol.GetBlue(); if( nMinR <= nR && nMaxR >= nR && nMinG <= nG && nMaxG >= nG && nMinB <= nB && nMaxB >= nB ) { pWriteAcc->SetPixel( nY, nX, aWhite ); } else pWriteAcc->SetPixel( nY, nX, aBlack ); } } } else { for( long nY = 0L; nY < nHeight; nY++ ) { for( long nX = 0L; nX < nWidth; nX++ ) { aCol = pReadAcc->GetPixel( nY, nX ); nR = aCol.GetRed(); nG = aCol.GetGreen(); nB = aCol.GetBlue(); if( nMinR <= nR && nMaxR >= nR && nMinG <= nG && nMaxG >= nG && nMinB <= nB && nMaxB >= nB ) { pWriteAcc->SetPixel( nY, nX, aWhite ); } else pWriteAcc->SetPixel( nY, nX, aBlack ); } } } } ( (Bitmap*) this )->ReleaseAccess( pReadAcc ); bRet = sal_True; } aNewBmp.ReleaseAccess( pWriteAcc ); } if( bRet ) { aNewBmp.maPrefSize = maPrefSize; aNewBmp.maPrefMapMode = maPrefMapMode; } else aNewBmp = Bitmap(); return aNewBmp; } // ------------------------------------------------------------------ Region Bitmap::CreateRegion( const Color& rColor, const Rectangle& rRect ) const { Region aRegion; Rectangle aRect( rRect ); BitmapReadAccess* pReadAcc = ( (Bitmap*) this )->AcquireReadAccess(); aRect.Intersection( 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); for( ; nX <= nRight; ) { while( ( nX <= nRight ) && ( aMatch != pReadAcc->GetPixel( nY, nX ) ) ) nX++; if( nX <= nRight ) { aNewLine.push_back(nX); //aSubRect.Left() = nX; while( ( nX <= nRight ) && ( aMatch == pReadAcc->GetPixel( nY, nX ) ) ) nX++; //aSubRect.Right() = nX - 1L; 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()) { Rectangle aSubRect; // enter y values and proceed ystart aSubRect.Top() = nYStart; aSubRect.Bottom() = nY ? nY - 1 : 0; for(sal_uInt32 a(0); a < aLine.size();) { aSubRect.Left() = aLine[a++]; aSubRect.Right() = aLine[a++]; aRegion.Union(aSubRect); } } // copy line as new line aLine = aNewLine; nYStart = nY; } } // write last line if used if(aLine.size()) { Rectangle aSubRect; // enter y values aSubRect.Top() = nYStart; aSubRect.Bottom() = nY ? nY - 1 : 0; for(sal_uInt32 a(0); a < aLine.size();) { aSubRect.Left() = aLine[a++]; aSubRect.Right() = aLine[a++]; aRegion.Union(aSubRect); } } //aRegion.ImplEndAddRect(); //aRegion.SetRegionRectangles(aRectangles); ( (Bitmap*) this )->ReleaseAccess( pReadAcc ); } else aRegion = aRect; return aRegion; } // ------------------------------------------------------------------ sal_Bool Bitmap::Replace( const Bitmap& rMask, const Color& rReplaceColor ) { BitmapReadAccess* pMaskAcc = ( (Bitmap&) rMask ).AcquireReadAccess(); BitmapWriteAccess* pAcc = AcquireWriteAccess(); sal_Bool bRet = sal_False; if( pMaskAcc && pAcc ) { const long nWidth = Min( pMaskAcc->Width(), pAcc->Width() ); const long nHeight = Min( pMaskAcc->Height(), pAcc->Height() ); const BitmapColor aMaskWhite( pMaskAcc->GetBestMatchingColor( Color( 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( (sal_uInt8) nActColors ); } else { sal_Bool* pFlags = new sal_Bool[ nMaxColors ]; // alle Eintraege auf 0 setzen memset( pFlags, 0, nMaxColors ); for( long nY = 0L; nY < nHeight; nY++ ) for( long nX = 0L; nX < nWidth; nX++ ) pFlags[ pAcc->GetPixelIndex( nY, nX ) ] = sal_True; for( sal_uInt16 i = 0UL; i < nMaxColors; i++ ) { // Hurra, wir haben einen unbenutzten Eintrag if( !pFlags[ i ] ) { pAcc->SetPaletteColor( (sal_uInt16) i, rReplaceColor ); aReplace = BitmapColor( (sal_uInt8) i ); } } delete[] pFlags; } } } else aReplace = rReplaceColor; for( long nY = 0L; nY < nHeight; nY++ ) for( long nX = 0L; nX < nWidth; nX++ ) if( pMaskAcc->GetPixel( nY, nX ) == aMaskWhite ) pAcc->SetPixel( nY, nX, aReplace ); bRet = sal_True; } ( (Bitmap&) rMask ).ReleaseAccess( pMaskAcc ); ReleaseAccess( pAcc ); return bRet; } // ------------------------------------------------------------------ sal_Bool Bitmap::Replace( const AlphaMask& rAlpha, const Color& rMergeColor ) { Bitmap aNewBmp( GetSizePixel(), 24 ); BitmapReadAccess* pAcc = AcquireReadAccess(); BitmapReadAccess* pAlphaAcc = ( (AlphaMask&) rAlpha ).AcquireReadAccess(); BitmapWriteAccess* pNewAcc = aNewBmp.AcquireWriteAccess(); sal_Bool bRet = sal_False; if( pAcc && pAlphaAcc && pNewAcc ) { BitmapColor aCol; const long nWidth = Min( pAlphaAcc->Width(), pAcc->Width() ); const long nHeight = Min( pAlphaAcc->Height(), pAcc->Height() ); for( long nY = 0L; nY < nHeight; nY++ ) { for( long nX = 0L; nX < nWidth; nX++ ) { aCol = pAcc->GetColor( nY, nX ); pNewAcc->SetPixel( nY, nX, aCol.Merge( rMergeColor, 255 - pAlphaAcc->GetPixelIndex( nY, nX ) ) ); } } bRet = sal_True; } ReleaseAccess( pAcc ); ( (AlphaMask&) rAlpha ).ReleaseAccess( pAlphaAcc ); aNewBmp.ReleaseAccess( pNewAcc ); if( bRet ) { const MapMode aMap( maPrefMapMode ); const Size aSize( maPrefSize ); *this = aNewBmp; maPrefMapMode = aMap; maPrefSize = aSize; } return bRet; } // ------------------------------------------------------------------ sal_Bool Bitmap::Replace( const Color& rSearchColor, const Color& rReplaceColor, sal_uLong nTol ) { // Bitmaps with 1 bit color depth can cause problems // if they have other entries than black/white in their palette if( 1 == GetBitCount() ) Convert( BMP_CONVERSION_4BIT_COLORS ); BitmapWriteAccess* pAcc = AcquireWriteAccess(); sal_Bool bRet = sal_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 = 0L, nHeight = pAcc->Height(); nY < nHeight; nY++ ) { for( long nX = 0L, nWidth = pAcc->Width(); nX < nWidth; nX++ ) { aCol = pAcc->GetPixel( nY, nX ); if( nMinR <= aCol.GetRed() && nMaxR >= aCol.GetRed() && nMinG <= aCol.GetGreen() && nMaxG >= aCol.GetGreen() && nMinB <= aCol.GetBlue() && nMaxB >= aCol.GetBlue() ) { pAcc->SetPixel( nY, nX, aReplace ); } } } } ReleaseAccess( pAcc ); bRet = sal_True; } return bRet; } // ------------------------------------------------------------------ sal_Bool Bitmap::Replace( const Color* pSearchColors, const Color* pReplaceColors, sal_uLong nColorCount, sal_uLong* _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( BMP_CONVERSION_4BIT_COLORS ); BitmapWriteAccess* pAcc = AcquireWriteAccess(); sal_Bool bRet = sal_False; if( pAcc ) { long* pMinR = new long[ nColorCount ]; long* pMaxR = new long[ nColorCount ]; long* pMinG = new long[ nColorCount ]; long* pMaxG = new long[ nColorCount ]; long* pMinB = new long[ nColorCount ]; long* pMaxB = new long[ nColorCount ]; long* pTols; sal_uLong i; if( !_pTols ) { pTols = new long[ nColorCount ]; memset( pTols, 0, nColorCount * sizeof( long ) ); } else pTols = (long*) _pTols; for( i = 0UL; i < nColorCount; i++ ) { const Color& rCol = pSearchColors[ i ]; const long 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 ); } if( pAcc->HasPalette() ) { for( sal_uInt16 nEntry = 0, nPalCount = pAcc->GetPaletteEntryCount(); nEntry < nPalCount; nEntry++ ) { const BitmapColor& rCol = pAcc->GetPaletteColor( nEntry ); for( i = 0UL; 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( (sal_uInt16)nEntry, pReplaceColors[ i ] ); break; } } } } else { BitmapColor aCol; BitmapColor* pReplaces = new BitmapColor[ nColorCount ]; for( i = 0UL; i < nColorCount; i++ ) pReplaces[ i ] = pAcc->GetBestMatchingColor( pReplaceColors[ i ] ); for( long nY = 0L, nHeight = pAcc->Height(); nY < nHeight; nY++ ) { for( long nX = 0L, nWidth = pAcc->Width(); nX < nWidth; nX++ ) { aCol = pAcc->GetPixel( nY, nX ); for( i = 0UL; 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->SetPixel( nY, nX, pReplaces[ i ] ); break; } } } } delete[] pReplaces; } if( !_pTols ) delete[] pTols; delete[] pMinR; delete[] pMaxR; delete[] pMinG; delete[] pMaxG; delete[] pMinB; delete[] pMaxB; ReleaseAccess( pAcc ); bRet = sal_True; } return bRet; } // ------------------------------------------------------------------ Bitmap Bitmap::CreateDisplayBitmap( OutputDevice* pDisplay ) { Bitmap aDispBmp( *this ); if( mpImpBmp && ( pDisplay->mpGraphics || pDisplay->ImplGetGraphics() ) ) { ImpBitmap* pImpDispBmp = new ImpBitmap; if( pImpDispBmp->ImplCreate( *mpImpBmp, pDisplay->mpGraphics ) ) aDispBmp.ImplSetImpBitmap( pImpDispBmp ); else delete pImpDispBmp; } return aDispBmp; } // ------------------------------------------------------------------ Bitmap Bitmap::GetColorTransformedBitmap( BmpColorMode eColorMode ) const { Bitmap aRet; if( BMP_COLOR_HIGHCONTRAST == eColorMode ) { Color* pSrcColors = NULL; Color* pDstColors = NULL; sal_uLong nColorCount = 0; aRet = *this; Image::GetColorTransformArrays( (ImageColorTransform) eColorMode, pSrcColors, pDstColors, nColorCount ); if( nColorCount && pSrcColors && pDstColors ) aRet.Replace( pSrcColors, pDstColors, nColorCount ); delete[] pSrcColors; delete[] pDstColors; } else if( BMP_COLOR_MONOCHROME_BLACK == eColorMode || BMP_COLOR_MONOCHROME_WHITE == eColorMode ) { aRet = *this; aRet.MakeMono( BMP_COLOR_MONOCHROME_THRESHOLD ); } return aRet; } // ------------------------------------------------------------------ sal_Bool Bitmap::CombineSimple( const Bitmap& rMask, BmpCombine eCombine ) { BitmapReadAccess* pMaskAcc = ( (Bitmap&) rMask ).AcquireReadAccess(); BitmapWriteAccess* pAcc = AcquireWriteAccess(); sal_Bool bRet = sal_False; if( pMaskAcc && pAcc ) { const long nWidth = Min( pMaskAcc->Width(), pAcc->Width() ); const long nHeight = Min( pMaskAcc->Height(), pAcc->Height() ); const Color aColBlack( COL_BLACK ); BitmapColor aPixel; BitmapColor aMaskPixel; const BitmapColor aWhite( pAcc->GetBestMatchingColor( Color( COL_WHITE ) ) ); const BitmapColor aBlack( pAcc->GetBestMatchingColor( aColBlack ) ); const BitmapColor aMaskBlack( pMaskAcc->GetBestMatchingColor( aColBlack ) ); switch( eCombine ) { case( BMP_COMBINE_COPY ): { for( long nY = 0L; nY < nHeight; nY++ ) for( long nX = 0L; nX < nWidth; nX++ ) { if( pMaskAcc->GetPixel( nY, nX ) == aMaskBlack ) pAcc->SetPixel( nY, nX, aBlack ); else pAcc->SetPixel( nY, nX, aWhite ); } } break; case( BMP_COMBINE_INVERT ): { for( long nY = 0L; nY < nHeight; nY++ ) for( long nX = 0L; nX < nWidth; nX++ ) { if( pAcc->GetPixel( nY, nX ) == aBlack ) pAcc->SetPixel( nY, nX, aWhite ); else pAcc->SetPixel( nY, nX, aBlack ); } } break; case( BMP_COMBINE_AND ): { for( long nY = 0L; nY < nHeight; nY++ ) for( long nX = 0L; nX < nWidth; nX++ ) { if( pMaskAcc->GetPixel( nY, nX ) != aMaskBlack && pAcc->GetPixel( nY, nX ) != aBlack ) pAcc->SetPixel( nY, nX, aWhite ); else pAcc->SetPixel( nY, nX, aBlack ); } } break; case( BMP_COMBINE_NAND ): { for( long nY = 0L; nY < nHeight; nY++ ) for( long nX = 0L; nX < nWidth; nX++ ) { if( pMaskAcc->GetPixel( nY, nX ) != aMaskBlack && pAcc->GetPixel( nY, nX ) != aBlack ) pAcc->SetPixel( nY, nX, aBlack ); else pAcc->SetPixel( nY, nX, aWhite ); } } break; case( BMP_COMBINE_OR ): { for( long nY = 0L; nY < nHeight; nY++ ) for( long nX = 0L; nX < nWidth; nX++ ) { if( pMaskAcc->GetPixel( nY, nX ) != aMaskBlack || pAcc->GetPixel( nY, nX ) != aBlack ) pAcc->SetPixel( nY, nX, aWhite ); else pAcc->SetPixel( nY, nX, aBlack ); } } break; case( BMP_COMBINE_NOR ): { for( long nY = 0L; nY < nHeight; nY++ ) for( long nX = 0L; nX < nWidth; nX++ ) { if( pMaskAcc->GetPixel( nY, nX ) != aMaskBlack || pAcc->GetPixel( nY, nX ) != aBlack ) pAcc->SetPixel( nY, nX, aBlack ); else pAcc->SetPixel( nY, nX, aWhite ); } } break; case( BMP_COMBINE_XOR ): { for( long nY = 0L; nY < nHeight; nY++ ) for( long nX = 0L; nX < nWidth; nX++ ) { aPixel = pAcc->GetPixel( nY, nX ); aMaskPixel = pMaskAcc->GetPixel( nY, nX ); if( ( aMaskPixel != aMaskBlack && aPixel == aBlack ) || ( aMaskPixel == aMaskBlack && aPixel != aBlack ) ) { pAcc->SetPixel( nY, nX, aWhite ); } else pAcc->SetPixel( nY, nX, aBlack ); } } break; case( BMP_COMBINE_NXOR ): { for( long nY = 0L; nY < nHeight; nY++ ) for( long nX = 0L; nX < nWidth; nX++ ) { aPixel = pAcc->GetPixel( nY, nX ); aMaskPixel = pMaskAcc->GetPixel( nY, nX ); if( ( aMaskPixel != aMaskBlack && aPixel == aBlack ) || ( aMaskPixel == aMaskBlack && aPixel != aBlack ) ) { pAcc->SetPixel( nY, nX, aBlack ); } else pAcc->SetPixel( nY, nX, aWhite ); } } break; } bRet = sal_True; } ( (Bitmap&) rMask ).ReleaseAccess( pMaskAcc ); ReleaseAccess( pAcc ); return bRet; } // ------------------------------------------------------------------ sal_Bool Bitmap::Blend( const AlphaMask& rAlpha, const Color& rBackgroundColor ) { // TODO: Have a look at OutputDevice::ImplDrawAlpha() for some // optimizations. Might even consolidate the code here and there. // 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( BMP_CONVERSION_24BIT ); BitmapReadAccess* pAlphaAcc = const_cast(rAlpha).AcquireReadAccess(); BitmapWriteAccess* pAcc = AcquireWriteAccess(); sal_Bool bRet = sal_False; if( pAlphaAcc && pAcc ) { const long nWidth = Min( pAlphaAcc->Width(), pAcc->Width() ); const long nHeight = Min( pAlphaAcc->Height(), pAcc->Height() ); for( long nY = 0L; nY < nHeight; ++nY ) for( long nX = 0L; nX < nWidth; ++nX ) pAcc->SetPixel( nY, nX, pAcc->GetPixel( nY, nX ).Merge( rBackgroundColor, 255 - pAlphaAcc->GetPixelIndex( nY, nX ) ) ); bRet = sal_True; } const_cast(rAlpha).ReleaseAccess( pAlphaAcc ); ReleaseAccess( pAcc ); return bRet; } // ------------------------------------------------------------------ sal_Bool Bitmap::MakeMono( sal_uInt8 cThreshold ) { return ImplMakeMono( cThreshold ); } // ------------------------------------------------------------------ bool Bitmap::GetSystemData( BitmapSystemData& rData ) const { bool bRet = false; if( mpImpBmp ) { SalBitmap* pSalBitmap = mpImpBmp->ImplGetSalBitmap(); if( pSalBitmap ) bRet = pSalBitmap->GetSystemData( rData ); } return bRet; } /* vim: set noet sw=4 ts=4: */