merge the formfield patch from ooo-build
[ooovba.git] / vcl / source / gdi / bitmap.cxx
blobcd1d54205e5452f9c6f77bcb8d820d1722577b90
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: bitmap.cxx,v $
10 * $Revision: 1.23 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_vcl.hxx"
33 #include <rtl/crc.h>
34 #include <vcl/salbtype.hxx>
35 #include <tools/stream.hxx>
36 #include <vcl/bmpacc.hxx>
37 #include <tools/poly.hxx>
38 #include <vcl/outdev.hxx>
39 #include <vcl/impbmp.hxx>
40 #include <vcl/salbmp.hxx>
41 #ifndef _SV_RC_H
42 #include <tools/rc.h>
43 #endif
44 #include <vcl/bitmap.hxx>
45 #include <vcl/bitmapex.hxx>
46 #include <vcl/svapp.hxx>
47 #include <vcl/image.hxx>
49 // ----------
50 // - Bitmap -
51 // ----------
53 Bitmap::Bitmap() :
54 mpImpBmp( NULL )
58 // ------------------------------------------------------------------
60 Bitmap::Bitmap( const ResId& rResId ) :
61 mpImpBmp( NULL )
63 const BitmapEx aBmpEx( rResId );
65 if( !aBmpEx.IsEmpty() )
66 *this = aBmpEx.GetBitmap();
69 // ------------------------------------------------------------------
71 Bitmap::Bitmap( const Bitmap& rBitmap ) :
72 maPrefMapMode ( rBitmap.maPrefMapMode ),
73 maPrefSize ( rBitmap.maPrefSize )
75 mpImpBmp = rBitmap.mpImpBmp;
77 if ( mpImpBmp )
78 mpImpBmp->ImplIncRefCount();
81 // ------------------------------------------------------------------
83 Bitmap::Bitmap( SalBitmap* pSalBitmap )
85 mpImpBmp = new ImpBitmap();
86 mpImpBmp->ImplSetSalBitmap( pSalBitmap );
87 maPrefMapMode = MapMode( MAP_PIXEL );
88 maPrefSize = mpImpBmp->ImplGetSize();
91 // ------------------------------------------------------------------
93 Bitmap::Bitmap( const Size& rSizePixel, USHORT nBitCount, const BitmapPalette* pPal )
95 if( rSizePixel.Width() && rSizePixel.Height() )
97 BitmapPalette aPal;
98 BitmapPalette* pRealPal = NULL;
100 if( nBitCount <= 8 )
102 if( !pPal )
104 if( 1 == nBitCount )
106 aPal.SetEntryCount( 2 );
107 aPal[ 0 ] = Color( COL_BLACK );
108 aPal[ 1 ] = Color( COL_WHITE );
110 else if( ( 4 == nBitCount ) || ( 8 == nBitCount ) )
112 aPal.SetEntryCount( 1 << nBitCount );
113 aPal[ 0 ] = Color( COL_BLACK );
114 aPal[ 1 ] = Color( COL_BLUE );
115 aPal[ 2 ] = Color( COL_GREEN );
116 aPal[ 3 ] = Color( COL_CYAN );
117 aPal[ 4 ] = Color( COL_RED );
118 aPal[ 5 ] = Color( COL_MAGENTA );
119 aPal[ 6 ] = Color( COL_BROWN );
120 aPal[ 7 ] = Color( COL_GRAY );
121 aPal[ 8 ] = Color( COL_LIGHTGRAY );
122 aPal[ 9 ] = Color( COL_LIGHTBLUE );
123 aPal[ 10 ] = Color( COL_LIGHTGREEN );
124 aPal[ 11 ] = Color( COL_LIGHTCYAN );
125 aPal[ 12 ] = Color( COL_LIGHTRED );
126 aPal[ 13 ] = Color( COL_LIGHTMAGENTA );
127 aPal[ 14 ] = Color( COL_YELLOW );
128 aPal[ 15 ] = Color( COL_WHITE );
130 // Dither-Palette erzeugen
131 if( 8 == nBitCount )
133 USHORT nActCol = 16;
135 for( USHORT nB = 0; nB < 256; nB += 51 )
136 for( USHORT nG = 0; nG < 256; nG += 51 )
137 for( USHORT nR = 0; nR < 256; nR += 51 )
138 aPal[ nActCol++ ] = BitmapColor( (BYTE) nR, (BYTE) nG, (BYTE) nB );
140 // Standard-Office-Farbe setzen
141 aPal[ nActCol++ ] = BitmapColor( 0, 184, 255 );
145 else
146 pRealPal = (BitmapPalette*) pPal;
149 mpImpBmp = new ImpBitmap;
150 mpImpBmp->ImplCreate( rSizePixel, nBitCount, pRealPal ? *pRealPal : aPal );
152 else
153 mpImpBmp = NULL;
156 // ------------------------------------------------------------------
158 Bitmap::~Bitmap()
160 ImplReleaseRef();
163 // ------------------------------------------------------------------
165 const BitmapPalette& Bitmap::GetGreyPalette( int nEntries )
167 static BitmapPalette aGreyPalette2;
168 static BitmapPalette aGreyPalette4;
169 static BitmapPalette aGreyPalette16;
170 static BitmapPalette aGreyPalette256;
172 // create greyscale palette with 2, 4, 16 or 256 entries
173 if( 2 == nEntries || 4 == nEntries || 16 == nEntries || 256 == nEntries )
175 if( 2 == nEntries )
177 if( !aGreyPalette2.GetEntryCount() )
179 aGreyPalette2.SetEntryCount( 2 );
180 aGreyPalette2[ 0 ] = BitmapColor( 0, 0, 0 );
181 aGreyPalette2[ 1 ] = BitmapColor( 255, 255, 255 );
184 return aGreyPalette2;
186 else if( 4 == nEntries )
188 if( !aGreyPalette4.GetEntryCount() )
190 aGreyPalette4.SetEntryCount( 4 );
191 aGreyPalette4[ 0 ] = BitmapColor( 0, 0, 0 );
192 aGreyPalette4[ 1 ] = BitmapColor( 85, 85, 85 );
193 aGreyPalette4[ 2 ] = BitmapColor( 170, 170, 170 );
194 aGreyPalette4[ 3 ] = BitmapColor( 255, 255, 255 );
197 return aGreyPalette4;
199 else if( 16 == nEntries )
201 if( !aGreyPalette16.GetEntryCount() )
203 BYTE cGrey = 0, cGreyInc = 17;
205 aGreyPalette16.SetEntryCount( 16 );
207 for( USHORT i = 0; i < 16; i++, cGrey = sal::static_int_cast<BYTE>(cGrey + cGreyInc) )
208 aGreyPalette16[ i ] = BitmapColor( cGrey, cGrey, cGrey );
211 return aGreyPalette16;
213 else
215 if( !aGreyPalette256.GetEntryCount() )
217 aGreyPalette256.SetEntryCount( 256 );
219 for( USHORT i = 0; i < 256; i++ )
220 aGreyPalette256[ i ] = BitmapColor( (BYTE) i, (BYTE) i, (BYTE) i );
223 return aGreyPalette256;
226 else
228 DBG_ERROR( "Bitmap::GetGreyPalette: invalid entry count (2/4/16/256 allowed)" );
229 return aGreyPalette2;
233 // ------------------------------------------------------------------
235 bool BitmapPalette::IsGreyPalette() const
237 // TODO: add an IsGreyPalette flag to BitmapPalette
238 // TODO: unless this causes problems binary compatibility
239 const int nEntryCount = GetEntryCount();
240 if( !nEntryCount ) // NOTE: an empty palette means 1:1 mapping
241 return true;
242 const BitmapPalette& rGreyPalette = Bitmap::GetGreyPalette( nEntryCount );
243 if( rGreyPalette == *this )
244 return true;
245 // TODO: is it worth to compare the entries?
246 return false;
249 // ------------------------------------------------------------------
251 Bitmap& Bitmap::operator=( const Bitmap& rBitmap )
253 maPrefSize = rBitmap.maPrefSize;
254 maPrefMapMode = rBitmap.maPrefMapMode;
256 if ( rBitmap.mpImpBmp )
257 rBitmap.mpImpBmp->ImplIncRefCount();
259 ImplReleaseRef();
260 mpImpBmp = rBitmap.mpImpBmp;
262 return *this;
265 // ------------------------------------------------------------------
267 BOOL Bitmap::IsEqual( const Bitmap& rBmp ) const
269 return( IsSameInstance( rBmp ) ||
270 ( rBmp.GetSizePixel() == GetSizePixel() &&
271 rBmp.GetBitCount() == GetBitCount() &&
272 rBmp.GetChecksum() == GetChecksum() ) );
275 // ------------------------------------------------------------------
277 void Bitmap::SetEmpty()
279 maPrefMapMode = MapMode();
280 maPrefSize = Size();
282 ImplReleaseRef();
283 mpImpBmp = NULL;
286 // ------------------------------------------------------------------
288 Size Bitmap::GetSizePixel() const
290 return( mpImpBmp ? mpImpBmp->ImplGetSize() : Size() );
292 // ------------------------------------------------------------------
294 void Bitmap::SetSizePixel( const Size& rNewSize )
296 Scale( rNewSize );
299 // ------------------------------------------------------------------
301 Size Bitmap::GetSourceSizePixel() const
303 return( mpImpBmp ? mpImpBmp->ImplGetSourceSize() : Size() );
306 // ------------------------------------------------------------------
308 void Bitmap::SetSourceSizePixel( const Size& rSize)
310 if( mpImpBmp )
311 mpImpBmp->ImplSetSourceSize( rSize);
314 // ------------------------------------------------------------------
316 USHORT Bitmap::GetBitCount() const
318 return( mpImpBmp ? mpImpBmp->ImplGetBitCount() : 0 );
321 // ------------------------------------------------------------------
323 BOOL Bitmap::HasGreyPalette() const
325 const USHORT nBitCount = GetBitCount();
326 BOOL bRet = FALSE;
328 if( 1 == nBitCount )
329 bRet = TRUE;
330 else if( 4 == nBitCount || 8 == nBitCount )
332 BitmapReadAccess* pRAcc = ( (Bitmap*) this )->AcquireReadAccess();
334 if( pRAcc )
336 if( pRAcc->HasPalette() && ( (BitmapPalette&) pRAcc->GetPalette() == GetGreyPalette( 1 << nBitCount ) ) )
337 bRet = TRUE;
339 ( (Bitmap*) this )->ReleaseAccess( pRAcc );
343 return bRet;
346 // ------------------------------------------------------------------
348 ULONG Bitmap::GetChecksum() const
350 ULONG nRet = 0UL;
352 if( mpImpBmp )
354 nRet = mpImpBmp->ImplGetChecksum();
356 if( !nRet )
358 BitmapReadAccess* pRAcc = ( (Bitmap*) this )->AcquireReadAccess();
360 if( pRAcc && pRAcc->Width() && pRAcc->Height() )
362 sal_uInt32 nCrc = 0;
363 SVBT32 aBT32;
365 pRAcc->ImplZeroInitUnusedBits();
367 UInt32ToSVBT32( pRAcc->Width(), aBT32 );
368 nCrc = rtl_crc32( nCrc, aBT32, 4 );
370 UInt32ToSVBT32( pRAcc->Height(), aBT32 );
371 nCrc = rtl_crc32( nCrc, aBT32, 4 );
373 UInt32ToSVBT32( pRAcc->GetBitCount(), aBT32 );
374 nCrc = rtl_crc32( nCrc, aBT32, 4 );
376 UInt32ToSVBT32( pRAcc->GetColorMask().GetRedMask(), aBT32 );
377 nCrc = rtl_crc32( nCrc, aBT32, 4 );
379 UInt32ToSVBT32( pRAcc->GetColorMask().GetGreenMask(), aBT32 );
380 nCrc = rtl_crc32( nCrc, aBT32, 4 );
382 UInt32ToSVBT32( pRAcc->GetColorMask().GetBlueMask(), aBT32 );
383 nCrc = rtl_crc32( nCrc, aBT32, 4 );
385 if( pRAcc->HasPalette() )
387 nCrc = rtl_crc32( nCrc, pRAcc->GetPalette().ImplGetColorBuffer(),
388 pRAcc->GetPaletteEntryCount() * sizeof( BitmapColor ) );
391 nCrc = rtl_crc32( nCrc, pRAcc->GetBuffer(), pRAcc->GetScanlineSize() * pRAcc->Height() );
393 mpImpBmp->ImplSetChecksum( nRet = nCrc );
396 if (pRAcc) ( (Bitmap*) this )->ReleaseAccess( pRAcc );
400 return nRet;
403 // ------------------------------------------------------------------
405 void Bitmap::ImplReleaseRef()
407 if( mpImpBmp )
409 if( mpImpBmp->ImplGetRefCount() > 1UL )
410 mpImpBmp->ImplDecRefCount();
411 else
413 delete mpImpBmp;
414 mpImpBmp = NULL;
419 // ------------------------------------------------------------------
421 void Bitmap::ImplMakeUnique()
423 if( mpImpBmp && mpImpBmp->ImplGetRefCount() > 1UL )
425 ImpBitmap* pOldImpBmp = mpImpBmp;
427 pOldImpBmp->ImplDecRefCount();
429 mpImpBmp = new ImpBitmap;
430 mpImpBmp->ImplCreate( *pOldImpBmp );
434 // ------------------------------------------------------------------
436 void Bitmap::ImplAssignWithSize( const Bitmap& rBitmap )
438 const Size aOldSizePix( GetSizePixel() );
439 const Size aNewSizePix( rBitmap.GetSizePixel() );
440 const MapMode aOldMapMode( maPrefMapMode );
441 Size aNewPrefSize;
443 if( ( aOldSizePix != aNewSizePix ) && aOldSizePix.Width() && aOldSizePix.Height() )
445 aNewPrefSize.Width() = FRound( maPrefSize.Width() * aNewSizePix.Width() / aOldSizePix.Width() );
446 aNewPrefSize.Height() = FRound( maPrefSize.Height() * aNewSizePix.Height() / aOldSizePix.Height() );
448 else
449 aNewPrefSize = maPrefSize;
451 *this = rBitmap;
453 maPrefSize = aNewPrefSize;
454 maPrefMapMode = aOldMapMode;
457 // ------------------------------------------------------------------
459 ImpBitmap* Bitmap::ImplGetImpBitmap() const
461 return mpImpBmp;
464 // ------------------------------------------------------------------
466 void Bitmap::ImplSetImpBitmap( ImpBitmap* pImpBmp )
468 if( pImpBmp != mpImpBmp )
470 ImplReleaseRef();
471 mpImpBmp = pImpBmp;
475 // ------------------------------------------------------------------
477 BitmapReadAccess* Bitmap::AcquireReadAccess()
479 BitmapReadAccess* pReadAccess = new BitmapReadAccess( *this );
481 if( !*pReadAccess )
483 delete pReadAccess;
484 pReadAccess = NULL;
487 return pReadAccess;
490 // ------------------------------------------------------------------
492 BitmapWriteAccess* Bitmap::AcquireWriteAccess()
494 BitmapWriteAccess* pWriteAccess = new BitmapWriteAccess( *this );
496 if( !*pWriteAccess )
498 delete pWriteAccess;
499 pWriteAccess = NULL;
502 return pWriteAccess;
505 // ------------------------------------------------------------------
507 void Bitmap::ReleaseAccess( BitmapReadAccess* pBitmapAccess )
509 delete pBitmapAccess;
512 // ------------------------------------------------------------------
514 BOOL Bitmap::Erase( const Color& rFillColor )
516 if( !(*this) )
517 return TRUE;
519 BitmapWriteAccess* pWriteAcc = AcquireWriteAccess();
520 BOOL bRet = FALSE;
522 if( pWriteAcc )
524 const ULONG nFormat = pWriteAcc->GetScanlineFormat();
525 BYTE cIndex = 0;
526 BOOL bFast = FALSE;
528 switch( nFormat )
530 case( BMP_FORMAT_1BIT_MSB_PAL ):
531 case( BMP_FORMAT_1BIT_LSB_PAL ):
533 cIndex = (BYTE) pWriteAcc->GetBestPaletteIndex( rFillColor );
534 cIndex = ( cIndex ? 255 : 0 );
535 bFast = TRUE;
537 break;
539 case( BMP_FORMAT_4BIT_MSN_PAL ):
540 case( BMP_FORMAT_4BIT_LSN_PAL ):
542 cIndex = (BYTE) pWriteAcc->GetBestPaletteIndex( rFillColor );
543 cIndex = cIndex | ( cIndex << 4 );
544 bFast = TRUE;
546 break;
548 case( BMP_FORMAT_8BIT_PAL ):
550 cIndex = (BYTE) pWriteAcc->GetBestPaletteIndex( rFillColor );
551 bFast = TRUE;
553 break;
555 case( BMP_FORMAT_24BIT_TC_BGR ):
556 case( BMP_FORMAT_24BIT_TC_RGB ):
558 if( ( rFillColor.GetRed() == rFillColor.GetGreen() ) &&
559 ( rFillColor.GetRed() == rFillColor.GetBlue() ) )
561 cIndex = rFillColor.GetRed();
562 bFast = TRUE;
564 else
565 bFast = FALSE;
567 break;
569 default:
570 bFast = FALSE;
571 break;
574 if( bFast )
576 const ULONG nBufSize = pWriteAcc->GetScanlineSize() * pWriteAcc->Height();
577 memset( pWriteAcc->GetBuffer(), cIndex, nBufSize );
579 else
581 Point aTmpPoint;
582 const Rectangle aRect( aTmpPoint, Size( pWriteAcc->Width(), pWriteAcc->Height() ) );
583 pWriteAcc->SetFillColor( rFillColor );
584 pWriteAcc->FillRect( aRect );
587 ReleaseAccess( pWriteAcc );
588 bRet = TRUE;
591 return bRet;
594 // ------------------------------------------------------------------
596 BOOL Bitmap::Invert()
598 BitmapWriteAccess* pAcc = AcquireWriteAccess();
599 BOOL bRet = FALSE;
601 if( pAcc )
603 if( pAcc->HasPalette() )
605 BitmapPalette aBmpPal( pAcc->GetPalette() );
606 const USHORT nCount = aBmpPal.GetEntryCount();
608 for( USHORT i = 0; i < nCount; i++ )
609 aBmpPal[ i ].Invert();
611 pAcc->SetPalette( aBmpPal );
613 else
615 const long nWidth = pAcc->Width();
616 const long nHeight = pAcc->Height();
618 for( long nX = 0L; nX < nWidth; nX++ )
619 for( long nY = 0L; nY < nHeight; nY++ )
620 pAcc->SetPixel( nY, nX, pAcc->GetPixel( nY, nX ).Invert() );
623 ReleaseAccess( pAcc );
624 bRet = TRUE;
627 return bRet;
630 // ------------------------------------------------------------------
632 BOOL Bitmap::Mirror( ULONG nMirrorFlags )
634 BOOL bHorz = ( ( nMirrorFlags & BMP_MIRROR_HORZ ) == BMP_MIRROR_HORZ );
635 BOOL bVert = ( ( nMirrorFlags & BMP_MIRROR_VERT ) == BMP_MIRROR_VERT );
636 BOOL bRet = FALSE;
638 if( bHorz && !bVert )
640 BitmapWriteAccess* pAcc = AcquireWriteAccess();
642 if( pAcc )
644 const long nWidth = pAcc->Width();
645 const long nHeight = pAcc->Height();
646 const long nWidth1 = nWidth - 1L;
647 const long nWidth_2 = nWidth >> 1L;
649 for( long nY = 0L; nY < nHeight; nY++ )
651 for( long nX = 0L, nOther = nWidth1; nX < nWidth_2; nX++, nOther-- )
653 const BitmapColor aTemp( pAcc->GetPixel( nY, nX ) );
655 pAcc->SetPixel( nY, nX, pAcc->GetPixel( nY, nOther ) );
656 pAcc->SetPixel( nY, nOther, aTemp );
660 ReleaseAccess( pAcc );
661 bRet = TRUE;
664 else if( bVert && !bHorz )
666 BitmapWriteAccess* pAcc = AcquireWriteAccess();
668 if( pAcc )
670 const long nScanSize = pAcc->GetScanlineSize();
671 BYTE* pBuffer = new BYTE[ nScanSize ];
672 const long nHeight = pAcc->Height();
673 const long nHeight1 = nHeight - 1L;
674 const long nHeight_2 = nHeight >> 1L;
676 for( long nY = 0L, nOther = nHeight1; nY < nHeight_2; nY++, nOther-- )
678 memcpy( pBuffer, pAcc->GetScanline( nY ), nScanSize );
679 memcpy( pAcc->GetScanline( nY ), pAcc->GetScanline( nOther ), nScanSize );
680 memcpy( pAcc->GetScanline( nOther ), pBuffer, nScanSize );
683 delete[] pBuffer;
684 ReleaseAccess( pAcc );
685 bRet = TRUE;
688 else if( bHorz && bVert )
690 BitmapWriteAccess* pAcc = AcquireWriteAccess();
692 if( pAcc )
694 const long nWidth = pAcc->Width();
695 const long nWidth1 = nWidth - 1L;
696 const long nHeight = pAcc->Height();
697 long nHeight_2 = nHeight >> 1;
699 for( long nY = 0L, nOtherY = nHeight - 1L; nY < nHeight_2; nY++, nOtherY-- )
701 for( long nX = 0L, nOtherX = nWidth1; nX < nWidth; nX++, nOtherX-- )
703 const BitmapColor aTemp( pAcc->GetPixel( nY, nX ) );
705 pAcc->SetPixel( nY, nX, pAcc->GetPixel( nOtherY, nOtherX ) );
706 pAcc->SetPixel( nOtherY, nOtherX, aTemp );
710 // ggf. noch mittlere Zeile horizontal spiegeln
711 if( nHeight & 1 )
713 for( long nX = 0L, nOtherX = nWidth1, nWidth_2 = nWidth >> 1; nX < nWidth_2; nX++, nOtherX-- )
715 const BitmapColor aTemp( pAcc->GetPixel( nHeight_2, nX ) );
716 pAcc->SetPixel( nHeight_2, nX, pAcc->GetPixel( nHeight_2, nOtherX ) );
717 pAcc->SetPixel( nHeight_2, nOtherX, aTemp );
721 ReleaseAccess( pAcc );
722 bRet = TRUE;
725 else
726 bRet = TRUE;
728 return bRet;
731 // ------------------------------------------------------------------
733 BOOL Bitmap::Rotate( long nAngle10, const Color& rFillColor )
735 BOOL bRet = FALSE;
737 nAngle10 %= 3600L;
738 nAngle10 = ( nAngle10 < 0L ) ? ( 3599L + nAngle10 ) : nAngle10;
740 if( !nAngle10 )
741 bRet = TRUE;
742 else if( 1800L == nAngle10 )
743 bRet = Mirror( BMP_MIRROR_HORZ | BMP_MIRROR_VERT );
744 else
746 BitmapReadAccess* pReadAcc = AcquireReadAccess();
747 Bitmap aRotatedBmp;
749 if( pReadAcc )
751 const Size aSizePix( GetSizePixel() );
753 if( ( 900L == nAngle10 ) || ( 2700L == nAngle10 ) )
755 const Size aNewSizePix( aSizePix.Height(), aSizePix.Width() );
756 Bitmap aNewBmp( aNewSizePix, GetBitCount(), &pReadAcc->GetPalette() );
757 BitmapWriteAccess* pWriteAcc = aNewBmp.AcquireWriteAccess();
759 if( pWriteAcc )
761 const long nWidth = aSizePix.Width();
762 const long nWidth1 = nWidth - 1L;
763 const long nHeight = aSizePix.Height();
764 const long nHeight1 = nHeight - 1L;
765 const long nNewWidth = aNewSizePix.Width();
766 const long nNewHeight = aNewSizePix.Height();
768 if( 900L == nAngle10 )
770 for( long nY = 0L, nOtherX = nWidth1; nY < nNewHeight; nY++, nOtherX-- )
771 for( long nX = 0L, nOtherY = 0L; nX < nNewWidth; nX++ )
772 pWriteAcc->SetPixel( nY, nX, pReadAcc->GetPixel( nOtherY++, nOtherX ) );
774 else if( 2700L == nAngle10 )
776 for( long nY = 0L, nOtherX = 0L; nY < nNewHeight; nY++, nOtherX++ )
777 for( long nX = 0L, nOtherY = nHeight1; nX < nNewWidth; nX++ )
778 pWriteAcc->SetPixel( nY, nX, pReadAcc->GetPixel( nOtherY--, nOtherX ) );
781 aNewBmp.ReleaseAccess( pWriteAcc );
784 aRotatedBmp = aNewBmp;
786 else
788 Point aTmpPoint;
789 Rectangle aTmpRectangle( aTmpPoint, aSizePix );
790 Polygon aPoly( aTmpRectangle );
791 aPoly.Rotate( aTmpPoint, (USHORT) nAngle10 );
793 Rectangle aNewBound( aPoly.GetBoundRect() );
794 const Size aNewSizePix( aNewBound.GetSize() );
795 Bitmap aNewBmp( aNewSizePix, GetBitCount(), &pReadAcc->GetPalette() );
796 BitmapWriteAccess* pWriteAcc = aNewBmp.AcquireWriteAccess();
798 if( pWriteAcc )
800 const BitmapColor aFillColor( pWriteAcc->GetBestMatchingColor( rFillColor ) );
801 const double fCosAngle = cos( nAngle10 * F_PI1800 );
802 const double fSinAngle = sin( nAngle10 * F_PI1800 );
803 const double fXMin = aNewBound.Left();
804 const double fYMin = aNewBound.Top();
805 const long nWidth = aSizePix.Width();
806 const long nHeight = aSizePix.Height();
807 const long nNewWidth = aNewSizePix.Width();
808 const long nNewHeight = aNewSizePix.Height();
809 long nX;
810 long nY;
811 long nRotX;
812 long nRotY;
813 long nSinY;
814 long nCosY;
815 long* pCosX = new long[ nNewWidth ];
816 long* pSinX = new long[ nNewWidth ];
817 long* pCosY = new long[ nNewHeight ];
818 long* pSinY = new long[ nNewHeight ];
820 for ( nX = 0; nX < nNewWidth; nX++ )
822 const double fTmp = ( fXMin + nX ) * 64.;
824 pCosX[ nX ] = FRound( fCosAngle * fTmp );
825 pSinX[ nX ] = FRound( fSinAngle * fTmp );
828 for ( nY = 0; nY < nNewHeight; nY++ )
830 const double fTmp = ( fYMin + nY ) * 64.;
832 pCosY[ nY ] = FRound( fCosAngle * fTmp );
833 pSinY[ nY ] = FRound( fSinAngle * fTmp );
836 for( nY = 0L; nY < nNewHeight; nY++ )
838 nSinY = pSinY[ nY ];
839 nCosY = pCosY[ nY ];
841 for( nX = 0L; nX < nNewWidth; nX++ )
843 nRotX = ( pCosX[ nX ] - nSinY ) >> 6;
844 nRotY = ( pSinX[ nX ] + nCosY ) >> 6;
846 if ( ( nRotX > -1L ) && ( nRotX < nWidth ) && ( nRotY > -1L ) && ( nRotY < nHeight ) )
847 pWriteAcc->SetPixel( nY, nX, pReadAcc->GetPixel( nRotY, nRotX ) );
848 else
849 pWriteAcc->SetPixel( nY, nX, aFillColor );
853 delete[] pSinX;
854 delete[] pCosX;
855 delete[] pSinY;
856 delete[] pCosY;
858 aNewBmp.ReleaseAccess( pWriteAcc );
861 aRotatedBmp = aNewBmp;
864 ReleaseAccess( pReadAcc );
867 if( ( bRet = !!aRotatedBmp ) == TRUE )
868 ImplAssignWithSize( aRotatedBmp );
871 return bRet;
874 // ------------------------------------------------------------------
876 BOOL Bitmap::Crop( const Rectangle& rRectPixel )
878 const Size aSizePix( GetSizePixel() );
879 Rectangle aRect( rRectPixel );
880 BOOL bRet = FALSE;
882 aRect.Intersection( Rectangle( Point(), aSizePix ) );
884 if( !aRect.IsEmpty() )
886 BitmapReadAccess* pReadAcc = AcquireReadAccess();
888 if( pReadAcc )
890 Point aTmpPoint;
891 const Rectangle aNewRect( aTmpPoint, aRect.GetSize() );
892 Bitmap aNewBmp( aNewRect.GetSize(), GetBitCount(), &pReadAcc->GetPalette() );
893 BitmapWriteAccess* pWriteAcc = aNewBmp.AcquireWriteAccess();
895 if( pWriteAcc )
897 const long nOldX = aRect.Left();
898 const long nOldY = aRect.Top();
899 const long nNewWidth = aNewRect.GetWidth();
900 const long nNewHeight = aNewRect.GetHeight();
902 for( long nY = 0, nY2 = nOldY; nY < nNewHeight; nY++, nY2++ )
903 for( long nX = 0, nX2 = nOldX; nX < nNewWidth; nX++, nX2++ )
904 pWriteAcc->SetPixel( nY, nX, pReadAcc->GetPixel( nY2, nX2 ) );
906 aNewBmp.ReleaseAccess( pWriteAcc );
907 bRet = TRUE;
910 ReleaseAccess( pReadAcc );
912 if( bRet )
913 ImplAssignWithSize( aNewBmp );
917 return bRet;
920 // ------------------------------------------------------------------
922 BOOL Bitmap::CopyPixel( const Rectangle& rRectDst,
923 const Rectangle& rRectSrc, const Bitmap* pBmpSrc )
925 const Size aSizePix( GetSizePixel() );
926 Rectangle aRectDst( rRectDst );
927 BOOL bRet = FALSE;
929 aRectDst.Intersection( Rectangle( Point(), aSizePix ) );
931 if( !aRectDst.IsEmpty() )
933 if( pBmpSrc && ( *pBmpSrc != *this ) )
935 Bitmap* pSrc = (Bitmap*) pBmpSrc;
936 const Size aCopySizePix( pSrc->GetSizePixel() );
937 Rectangle aRectSrc( rRectSrc );
938 const USHORT nSrcBitCount = pBmpSrc->GetBitCount();
939 const USHORT nDstBitCount = GetBitCount();
941 if( nSrcBitCount > nDstBitCount )
943 long nNextIndex = 0L;
945 if( ( nSrcBitCount == 24 ) && ( nDstBitCount < 24 ) )
946 Convert( BMP_CONVERSION_24BIT );
947 else if( ( nSrcBitCount == 8 ) && ( nDstBitCount < 8 ) )
949 Convert( BMP_CONVERSION_8BIT_COLORS );
950 nNextIndex = 16;
952 else if( ( nSrcBitCount == 4 ) && ( nDstBitCount < 4 ) )
954 Convert( BMP_CONVERSION_4BIT_COLORS );
955 nNextIndex = 2;
958 if( nNextIndex )
960 BitmapReadAccess* pSrcAcc = pSrc->AcquireReadAccess();
961 BitmapWriteAccess* pDstAcc = AcquireWriteAccess();
963 if( pSrcAcc && pDstAcc )
965 const long nSrcCount = pDstAcc->GetPaletteEntryCount();
966 const long nDstCount = 1 << nDstBitCount;
967 BOOL bFound;
969 for( long i = 0L; ( i < nSrcCount ) && ( nNextIndex < nSrcCount ); i++ )
971 const BitmapColor& rSrcCol = pSrcAcc->GetPaletteColor( (USHORT) i );
973 bFound = FALSE;
975 for( long j = 0L; j < nDstCount; j++ )
977 if( rSrcCol == pDstAcc->GetPaletteColor( (USHORT) j ) )
979 bFound = TRUE;
980 break;
984 if( !bFound )
985 pDstAcc->SetPaletteColor( (USHORT) nNextIndex++, rSrcCol );
989 if( pSrcAcc )
990 pSrc->ReleaseAccess( pSrcAcc );
992 if( pDstAcc )
993 ReleaseAccess( pDstAcc );
997 aRectSrc.Intersection( Rectangle( Point(), aCopySizePix ) );
999 if( !aRectSrc.IsEmpty() )
1001 BitmapReadAccess* pReadAcc = pSrc->AcquireReadAccess();
1003 if( pReadAcc )
1005 BitmapWriteAccess* pWriteAcc = AcquireWriteAccess();
1007 if( pWriteAcc )
1009 const long nWidth = Min( aRectSrc.GetWidth(), aRectDst.GetWidth() );
1010 const long nHeight = Min( aRectSrc.GetHeight(), aRectDst.GetHeight() );
1011 const long nSrcEndX = aRectSrc.Left() + nWidth;
1012 const long nSrcEndY = aRectSrc.Top() + nHeight;
1013 long nDstY = aRectDst.Top();
1015 if( pReadAcc->HasPalette() && pWriteAcc->HasPalette() )
1017 const USHORT nCount = pReadAcc->GetPaletteEntryCount();
1018 BYTE* pMap = new BYTE[ nCount ];
1020 // Index-Map fuer Farbtabelle
1021 // aufbauen, da das Bild ja (relativ) farbgenau
1022 // kopiert werden soll
1023 for( USHORT i = 0; i < nCount; i++ )
1024 pMap[ i ] = (BYTE) pWriteAcc->GetBestPaletteIndex( pReadAcc->GetPaletteColor( i ) );
1026 for( long nSrcY = aRectSrc.Top(); nSrcY < nSrcEndY; nSrcY++, nDstY++ )
1027 for( long nSrcX = aRectSrc.Left(), nDstX = aRectDst.Left(); nSrcX < nSrcEndX; nSrcX++, nDstX++ )
1028 pWriteAcc->SetPixel( nDstY, nDstX, pMap[ pReadAcc->GetPixel( nSrcY, nSrcX ).GetIndex() ] );
1030 delete[] pMap;
1032 else if( pReadAcc->HasPalette() )
1034 for( long nSrcY = aRectSrc.Top(); nSrcY < nSrcEndY; nSrcY++, nDstY++ )
1035 for( long nSrcX = aRectSrc.Left(), nDstX = aRectDst.Left(); nSrcX < nSrcEndX; nSrcX++, nDstX++ )
1036 pWriteAcc->SetPixel( nDstY, nDstX, pReadAcc->GetPaletteColor( pReadAcc->GetPixel( nSrcY, nSrcX ) ) );
1038 else
1039 for( long nSrcY = aRectSrc.Top(); nSrcY < nSrcEndY; nSrcY++, nDstY++ )
1040 for( long nSrcX = aRectSrc.Left(), nDstX = aRectDst.Left(); nSrcX < nSrcEndX; nSrcX++, nDstX++ )
1041 pWriteAcc->SetPixel( nDstY, nDstX, pReadAcc->GetPixel( nSrcY, nSrcX ) );
1043 ReleaseAccess( pWriteAcc );
1044 bRet = ( nWidth > 0L ) && ( nHeight > 0L );
1047 pSrc->ReleaseAccess( pReadAcc );
1051 else
1053 Rectangle aRectSrc( rRectSrc );
1055 aRectSrc.Intersection( Rectangle( Point(), aSizePix ) );
1057 if( !aRectSrc.IsEmpty() && ( aRectSrc != aRectDst ) )
1059 BitmapWriteAccess* pWriteAcc = AcquireWriteAccess();
1061 if( pWriteAcc )
1063 const long nWidth = Min( aRectSrc.GetWidth(), aRectDst.GetWidth() );
1064 const long nHeight = Min( aRectSrc.GetHeight(), aRectDst.GetHeight() );
1065 const long nSrcX = aRectSrc.Left();
1066 const long nSrcY = aRectSrc.Top();
1067 const long nSrcEndX1 = nSrcX + nWidth - 1L;
1068 const long nSrcEndY1 = nSrcY + nHeight - 1L;
1069 const long nDstX = aRectDst.Left();
1070 const long nDstY = aRectDst.Top();
1071 const long nDstEndX1 = nDstX + nWidth - 1L;
1072 const long nDstEndY1 = nDstY + nHeight - 1L;
1074 if( ( nDstX <= nSrcX ) && ( nDstY <= nSrcY ) )
1076 for( long nY = nSrcY, nYN = nDstY; nY <= nSrcEndY1; nY++, nYN++ )
1077 for( long nX = nSrcX, nXN = nDstX; nX <= nSrcEndX1; nX++, nXN++ )
1078 pWriteAcc->SetPixel( nYN, nXN, pWriteAcc->GetPixel( nY, nX ) );
1080 else if( ( nDstX <= nSrcX ) && ( nDstY >= nSrcY ) )
1082 for( long nY = nSrcEndY1, nYN = nDstEndY1; nY >= nSrcY; nY--, nYN-- )
1083 for( long nX = nSrcX, nXN = nDstX; nX <= nSrcEndX1; nX++, nXN++ )
1084 pWriteAcc->SetPixel( nYN, nXN, pWriteAcc->GetPixel( nY, nX ) );
1086 else if( ( nDstX >= nSrcX ) && ( nDstY <= nSrcY ) )
1088 for( long nY = nSrcY, nYN = nDstY; nY <= nSrcEndY1; nY++, nYN++ )
1089 for( long nX = nSrcEndX1, nXN = nDstEndX1; nX >= nSrcX; nX--, nXN-- )
1090 pWriteAcc->SetPixel( nYN, nXN, pWriteAcc->GetPixel( nY, nX ) );
1092 else
1094 for( long nY = nSrcEndY1, nYN = nDstEndY1; nY >= nSrcY; nY--, nYN-- )
1095 for( long nX = nSrcEndX1, nXN = nDstEndX1; nX >= nSrcX; nX--, nXN-- )
1096 pWriteAcc->SetPixel( nYN, nXN, pWriteAcc->GetPixel( nY, nX ) );
1099 ReleaseAccess( pWriteAcc );
1100 bRet = TRUE;
1106 return bRet;
1109 // ------------------------------------------------------------------
1111 BOOL Bitmap::Expand( ULONG nDX, ULONG nDY, const Color* pInitColor )
1113 BOOL bRet = FALSE;
1115 if( nDX || nDY )
1117 const Size aSizePixel( GetSizePixel() );
1118 const long nWidth = aSizePixel.Width();
1119 const long nHeight = aSizePixel.Height();
1120 const Size aNewSize( nWidth + nDX, nHeight + nDY );
1121 BitmapReadAccess* pReadAcc = AcquireReadAccess();
1123 if( pReadAcc )
1125 BitmapPalette aBmpPal( pReadAcc->GetPalette() );
1126 Bitmap aNewBmp( aNewSize, GetBitCount(), &aBmpPal );
1127 BitmapWriteAccess* pWriteAcc = aNewBmp.AcquireWriteAccess();
1129 if( pWriteAcc )
1131 BitmapColor aColor;
1132 const long nNewX = nWidth;
1133 const long nNewY = nHeight;
1134 const long nNewWidth = pWriteAcc->Width();
1135 const long nNewHeight = pWriteAcc->Height();
1136 long nX;
1137 long nY;
1139 if( pInitColor )
1140 aColor = pWriteAcc->GetBestMatchingColor( *pInitColor );
1142 for( nY = 0L; nY < nHeight; nY++ )
1144 pWriteAcc->CopyScanline( nY, *pReadAcc );
1146 if( pInitColor && nDX )
1147 for( nX = nNewX; nX < nNewWidth; nX++ )
1148 pWriteAcc->SetPixel( nY, nX, aColor );
1151 if( pInitColor && nDY )
1152 for( nY = nNewY; nY < nNewHeight; nY++ )
1153 for( nX = 0; nX < nNewWidth; nX++ )
1154 pWriteAcc->SetPixel( nY, nX, aColor );
1156 aNewBmp.ReleaseAccess( pWriteAcc );
1157 bRet = TRUE;
1160 ReleaseAccess( pReadAcc );
1162 if( bRet )
1163 ImplAssignWithSize( aNewBmp );
1167 return bRet;
1170 // ------------------------------------------------------------------
1172 Bitmap Bitmap::CreateMask( const Color& rTransColor, ULONG nTol ) const
1174 Bitmap aNewBmp( GetSizePixel(), 1 );
1175 BitmapWriteAccess* pWriteAcc = aNewBmp.AcquireWriteAccess();
1176 BOOL bRet = FALSE;
1178 if( pWriteAcc )
1180 BitmapReadAccess* pReadAcc = ( (Bitmap*) this )->AcquireReadAccess();
1182 if( pReadAcc )
1184 const long nWidth = pReadAcc->Width();
1185 const long nHeight = pReadAcc->Height();
1186 const BitmapColor aBlack( pWriteAcc->GetBestMatchingColor( Color( COL_BLACK ) ) );
1187 const BitmapColor aWhite( pWriteAcc->GetBestMatchingColor( Color( COL_WHITE ) ) );
1189 if( !nTol )
1191 const BitmapColor aTest( pReadAcc->GetBestMatchingColor( rTransColor ) );
1192 long nX, nY, nShift;
1194 if( pReadAcc->GetScanlineFormat() == BMP_FORMAT_4BIT_MSN_PAL ||
1195 pReadAcc->GetScanlineFormat() == BMP_FORMAT_4BIT_LSN_PAL )
1197 // optimized for 4Bit-MSN/LSN source palette
1198 const BYTE cTest = aTest.GetIndex();
1199 const long nShiftInit = ( ( pReadAcc->GetScanlineFormat() == BMP_FORMAT_4BIT_MSN_PAL ) ? 4 : 0 );
1201 if( pWriteAcc->GetScanlineFormat() == BMP_FORMAT_1BIT_MSB_PAL &&
1202 aWhite.GetIndex() == 1 )
1204 // optimized for 1Bit-MSB destination palette
1205 for( nY = 0L; nY < nHeight; nY++ )
1207 Scanline pSrc = pReadAcc->GetScanline( nY );
1208 Scanline pDst = pWriteAcc->GetScanline( nY );
1209 for( nX = 0L, nShift = nShiftInit; nX < nWidth; nX++, nShift ^= 4 )
1211 if( cTest == ( ( pSrc[ nX >> 1 ] >> nShift ) & 0x0f ) )
1212 pDst[ nX >> 3 ] |= 1 << ( 7 - ( nX & 7 ) );
1213 else
1214 pDst[ nX >> 3 ] &= ~( 1 << ( 7 - ( nX & 7 ) ) );
1218 else
1220 for( nY = 0L; nY < nHeight; nY++ )
1222 Scanline pSrc = pReadAcc->GetScanline( nY );
1223 for( nX = 0L, nShift = nShiftInit; nX < nWidth; nX++, nShift ^= 4 )
1225 if( cTest == ( ( pSrc[ nX >> 1 ] >> nShift ) & 0x0f ) )
1226 pWriteAcc->SetPixel( nY, nX, aWhite );
1227 else
1228 pWriteAcc->SetPixel( nY, nX, aBlack );
1233 else if( pReadAcc->GetScanlineFormat() == BMP_FORMAT_8BIT_PAL )
1235 // optimized for 8Bit source palette
1236 const BYTE cTest = aTest.GetIndex();
1238 if( pWriteAcc->GetScanlineFormat() == BMP_FORMAT_1BIT_MSB_PAL &&
1239 aWhite.GetIndex() == 1 )
1241 // optimized for 1Bit-MSB destination palette
1242 for( nY = 0L; nY < nHeight; nY++ )
1244 Scanline pSrc = pReadAcc->GetScanline( nY );
1245 Scanline pDst = pWriteAcc->GetScanline( nY );
1246 for( nX = 0L; nX < nWidth; nX++ )
1248 if( cTest == pSrc[ nX ] )
1249 pDst[ nX >> 3 ] |= 1 << ( 7 - ( nX & 7 ) );
1250 else
1251 pDst[ nX >> 3 ] &= ~( 1 << ( 7 - ( nX & 7 ) ) );
1255 else
1257 for( nY = 0L; nY < nHeight; nY++ )
1259 Scanline pSrc = pReadAcc->GetScanline( nY );
1260 for( nX = 0L; nX < nWidth; nX++ )
1262 if( cTest == pSrc[ nX ] )
1263 pWriteAcc->SetPixel( nY, nX, aWhite );
1264 else
1265 pWriteAcc->SetPixel( nY, nX, aBlack );
1270 else
1272 // not optimized
1273 for( nY = 0L; nY < nHeight; nY++ )
1275 for( nX = 0L; nX < nWidth; nX++ )
1277 if( aTest == pReadAcc->GetPixel( nY, nX ) )
1278 pWriteAcc->SetPixel( nY, nX, aWhite );
1279 else
1280 pWriteAcc->SetPixel( nY, nX, aBlack );
1285 else
1287 BitmapColor aCol;
1288 long nR, nG, nB;
1289 const long nMinR = MinMax( (long) rTransColor.GetRed() - nTol, 0, 255 );
1290 const long nMaxR = MinMax( (long) rTransColor.GetRed() + nTol, 0, 255 );
1291 const long nMinG = MinMax( (long) rTransColor.GetGreen() - nTol, 0, 255 );
1292 const long nMaxG = MinMax( (long) rTransColor.GetGreen() + nTol, 0, 255 );
1293 const long nMinB = MinMax( (long) rTransColor.GetBlue() - nTol, 0, 255 );
1294 const long nMaxB = MinMax( (long) rTransColor.GetBlue() + nTol, 0, 255 );
1296 if( pReadAcc->HasPalette() )
1298 for( long nY = 0L; nY < nHeight; nY++ )
1300 for( long nX = 0L; nX < nWidth; nX++ )
1302 aCol = pReadAcc->GetPaletteColor( pReadAcc->GetPixel( nY, nX ) );
1303 nR = aCol.GetRed();
1304 nG = aCol.GetGreen();
1305 nB = aCol.GetBlue();
1307 if( nMinR <= nR && nMaxR >= nR &&
1308 nMinG <= nG && nMaxG >= nG &&
1309 nMinB <= nB && nMaxB >= nB )
1311 pWriteAcc->SetPixel( nY, nX, aWhite );
1313 else
1314 pWriteAcc->SetPixel( nY, nX, aBlack );
1318 else
1320 for( long nY = 0L; nY < nHeight; nY++ )
1322 for( long nX = 0L; nX < nWidth; nX++ )
1324 aCol = pReadAcc->GetPixel( nY, nX );
1325 nR = aCol.GetRed();
1326 nG = aCol.GetGreen();
1327 nB = aCol.GetBlue();
1329 if( nMinR <= nR && nMaxR >= nR &&
1330 nMinG <= nG && nMaxG >= nG &&
1331 nMinB <= nB && nMaxB >= nB )
1333 pWriteAcc->SetPixel( nY, nX, aWhite );
1335 else
1336 pWriteAcc->SetPixel( nY, nX, aBlack );
1342 ( (Bitmap*) this )->ReleaseAccess( pReadAcc );
1343 bRet = TRUE;
1346 aNewBmp.ReleaseAccess( pWriteAcc );
1349 if( bRet )
1351 aNewBmp.maPrefSize = maPrefSize;
1352 aNewBmp.maPrefMapMode = maPrefMapMode;
1354 else
1355 aNewBmp = Bitmap();
1357 return aNewBmp;
1360 // ------------------------------------------------------------------
1362 Region Bitmap::CreateRegion( const Color& rColor, const Rectangle& rRect ) const
1364 Region aRegion;
1365 Rectangle aRect( rRect );
1366 BitmapReadAccess* pReadAcc = ( (Bitmap*) this )->AcquireReadAccess();
1368 aRect.Intersection( Rectangle( Point(), GetSizePixel() ) );
1369 aRect.Justify();
1371 if( pReadAcc )
1373 Rectangle aSubRect;
1374 const long nLeft = aRect.Left();
1375 const long nTop = aRect.Top();
1376 const long nRight = aRect.Right();
1377 const long nBottom = aRect.Bottom();
1378 const BitmapColor aMatch( pReadAcc->GetBestMatchingColor( rColor ) );
1380 aRegion.ImplBeginAddRect();
1382 for( long nY = nTop; nY <= nBottom; nY++ )
1384 aSubRect.Top() = aSubRect.Bottom() = nY;
1386 for( long nX = nLeft; nX <= nRight; )
1388 while( ( nX <= nRight ) && ( aMatch != pReadAcc->GetPixel( nY, nX ) ) )
1389 nX++;
1391 if( nX <= nRight )
1393 aSubRect.Left() = nX;
1395 while( ( nX <= nRight ) && ( aMatch == pReadAcc->GetPixel( nY, nX ) ) )
1396 nX++;
1398 aSubRect.Right() = nX - 1L;
1399 aRegion.ImplAddRect( aSubRect );
1404 aRegion.ImplEndAddRect();
1405 ( (Bitmap*) this )->ReleaseAccess( pReadAcc );
1407 else
1408 aRegion = aRect;
1410 return aRegion;
1413 // ------------------------------------------------------------------
1415 BOOL Bitmap::Replace( const Bitmap& rMask, const Color& rReplaceColor )
1417 BitmapReadAccess* pMaskAcc = ( (Bitmap&) rMask ).AcquireReadAccess();
1418 BitmapWriteAccess* pAcc = AcquireWriteAccess();
1419 BOOL bRet = FALSE;
1421 if( pMaskAcc && pAcc )
1423 const long nWidth = Min( pMaskAcc->Width(), pAcc->Width() );
1424 const long nHeight = Min( pMaskAcc->Height(), pAcc->Height() );
1425 const BitmapColor aMaskWhite( pMaskAcc->GetBestMatchingColor( Color( COL_WHITE ) ) );
1426 BitmapColor aReplace;
1428 if( pAcc->HasPalette() )
1430 const USHORT nActColors = pAcc->GetPaletteEntryCount();
1431 const USHORT nMaxColors = 1 << pAcc->GetBitCount();
1433 // erst einmal naechste Farbe nehmen
1434 aReplace = pAcc->GetBestMatchingColor( rReplaceColor );
1436 // falls Palettenbild, und die zu setzende Farbe ist nicht
1437 // in der Palette, suchen wir nach freien Eintraegen (teuer)
1438 if( pAcc->GetPaletteColor( (BYTE) aReplace ) != BitmapColor( rReplaceColor ) )
1440 // erst einmal nachsehen, ob wir unsere ReplaceColor
1441 // nicht auf einen freien Platz am Ende der Palette
1442 // setzen koennen
1443 if( nActColors < nMaxColors )
1445 pAcc->SetPaletteEntryCount( nActColors + 1 );
1446 pAcc->SetPaletteColor( nActColors, rReplaceColor );
1447 aReplace = BitmapColor( (BYTE) nActColors );
1449 else
1451 BOOL* pFlags = new BOOL[ nMaxColors ];
1453 // alle Eintraege auf 0 setzen
1454 memset( pFlags, 0, nMaxColors );
1456 for( long nY = 0L; nY < nHeight; nY++ )
1457 for( long nX = 0L; nX < nWidth; nX++ )
1458 pFlags[ (BYTE) pAcc->GetPixel( nY, nX ) ] = TRUE;
1460 for( USHORT i = 0UL; i < nMaxColors; i++ )
1462 // Hurra, wir haben einen unbenutzten Eintrag
1463 if( !pFlags[ i ] )
1465 pAcc->SetPaletteColor( (USHORT) i, rReplaceColor );
1466 aReplace = BitmapColor( (BYTE) i );
1470 delete[] pFlags;
1474 else
1475 aReplace = rReplaceColor;
1477 for( long nY = 0L; nY < nHeight; nY++ )
1478 for( long nX = 0L; nX < nWidth; nX++ )
1479 if( pMaskAcc->GetPixel( nY, nX ) == aMaskWhite )
1480 pAcc->SetPixel( nY, nX, aReplace );
1482 bRet = TRUE;
1485 ( (Bitmap&) rMask ).ReleaseAccess( pMaskAcc );
1486 ReleaseAccess( pAcc );
1488 return bRet;
1491 // ------------------------------------------------------------------
1493 BOOL Bitmap::Replace( const AlphaMask& rAlpha, const Color& rMergeColor )
1495 Bitmap aNewBmp( GetSizePixel(), 24 );
1496 BitmapReadAccess* pAcc = AcquireReadAccess();
1497 BitmapReadAccess* pAlphaAcc = ( (AlphaMask&) rAlpha ).AcquireReadAccess();
1498 BitmapWriteAccess* pNewAcc = aNewBmp.AcquireWriteAccess();
1499 BOOL bRet = FALSE;
1501 if( pAcc && pAlphaAcc && pNewAcc )
1503 BitmapColor aCol;
1504 const long nWidth = Min( pAlphaAcc->Width(), pAcc->Width() );
1505 const long nHeight = Min( pAlphaAcc->Height(), pAcc->Height() );
1507 for( long nY = 0L; nY < nHeight; nY++ )
1509 for( long nX = 0L; nX < nWidth; nX++ )
1511 aCol = pAcc->GetColor( nY, nX );
1512 pNewAcc->SetPixel( nY, nX, aCol.Merge( rMergeColor, 255 - (BYTE) pAlphaAcc->GetPixel( nY, nX ) ) );
1516 bRet = TRUE;
1519 ReleaseAccess( pAcc );
1520 ( (AlphaMask&) rAlpha ).ReleaseAccess( pAlphaAcc );
1521 aNewBmp.ReleaseAccess( pNewAcc );
1523 if( bRet )
1525 const MapMode aMap( maPrefMapMode );
1526 const Size aSize( maPrefSize );
1528 *this = aNewBmp;
1530 maPrefMapMode = aMap;
1531 maPrefSize = aSize;
1534 return bRet;
1537 // ------------------------------------------------------------------
1539 BOOL Bitmap::Replace( const Color& rSearchColor, const Color& rReplaceColor, ULONG nTol )
1541 // Bitmaps with 1 bit color depth can cause problems
1542 // if they have other entries than black/white in their palette
1543 if( 1 == GetBitCount() )
1544 Convert( BMP_CONVERSION_4BIT_COLORS );
1546 BitmapWriteAccess* pAcc = AcquireWriteAccess();
1547 BOOL bRet = FALSE;
1549 if( pAcc )
1551 const long nMinR = MinMax( (long) rSearchColor.GetRed() - nTol, 0, 255 );
1552 const long nMaxR = MinMax( (long) rSearchColor.GetRed() + nTol, 0, 255 );
1553 const long nMinG = MinMax( (long) rSearchColor.GetGreen() - nTol, 0, 255 );
1554 const long nMaxG = MinMax( (long) rSearchColor.GetGreen() + nTol, 0, 255 );
1555 const long nMinB = MinMax( (long) rSearchColor.GetBlue() - nTol, 0, 255 );
1556 const long nMaxB = MinMax( (long) rSearchColor.GetBlue() + nTol, 0, 255 );
1558 if( pAcc->HasPalette() )
1560 for( USHORT i = 0, nPalCount = pAcc->GetPaletteEntryCount(); i < nPalCount; i++ )
1562 const BitmapColor& rCol = pAcc->GetPaletteColor( i );
1564 if( nMinR <= rCol.GetRed() && nMaxR >= rCol.GetRed() &&
1565 nMinG <= rCol.GetGreen() && nMaxG >= rCol.GetGreen() &&
1566 nMinB <= rCol.GetBlue() && nMaxB >= rCol.GetBlue() )
1568 pAcc->SetPaletteColor( i, rReplaceColor );
1572 else
1574 BitmapColor aCol;
1575 const BitmapColor aReplace( pAcc->GetBestMatchingColor( rReplaceColor ) );
1577 for( long nY = 0L, nHeight = pAcc->Height(); nY < nHeight; nY++ )
1579 for( long nX = 0L, nWidth = pAcc->Width(); nX < nWidth; nX++ )
1581 aCol = pAcc->GetPixel( nY, nX );
1583 if( nMinR <= aCol.GetRed() && nMaxR >= aCol.GetRed() &&
1584 nMinG <= aCol.GetGreen() && nMaxG >= aCol.GetGreen() &&
1585 nMinB <= aCol.GetBlue() && nMaxB >= aCol.GetBlue() )
1587 pAcc->SetPixel( nY, nX, aReplace );
1593 ReleaseAccess( pAcc );
1594 bRet = TRUE;
1597 return bRet;
1600 // ------------------------------------------------------------------
1602 BOOL Bitmap::Replace( const Color* pSearchColors, const Color* pReplaceColors,
1603 ULONG nColorCount, ULONG* _pTols )
1605 // Bitmaps with 1 bit color depth can cause problems
1606 // if they have other entries than black/white in their palette
1607 if( 1 == GetBitCount() )
1608 Convert( BMP_CONVERSION_4BIT_COLORS );
1610 BitmapWriteAccess* pAcc = AcquireWriteAccess();
1611 BOOL bRet = FALSE;
1613 if( pAcc )
1615 long* pMinR = new long[ nColorCount ];
1616 long* pMaxR = new long[ nColorCount ];
1617 long* pMinG = new long[ nColorCount ];
1618 long* pMaxG = new long[ nColorCount ];
1619 long* pMinB = new long[ nColorCount ];
1620 long* pMaxB = new long[ nColorCount ];
1621 long* pTols;
1622 ULONG i;
1624 if( !_pTols )
1626 pTols = new long[ nColorCount ];
1627 memset( pTols, 0, nColorCount * sizeof( long ) );
1629 else
1630 pTols = (long*) _pTols;
1632 for( i = 0UL; i < nColorCount; i++ )
1634 const Color& rCol = pSearchColors[ i ];
1635 const long nTol = pTols[ i ];
1637 pMinR[ i ] = MinMax( (long) rCol.GetRed() - nTol, 0, 255 );
1638 pMaxR[ i ] = MinMax( (long) rCol.GetRed() + nTol, 0, 255 );
1639 pMinG[ i ] = MinMax( (long) rCol.GetGreen() - nTol, 0, 255 );
1640 pMaxG[ i ] = MinMax( (long) rCol.GetGreen() + nTol, 0, 255 );
1641 pMinB[ i ] = MinMax( (long) rCol.GetBlue() - nTol, 0, 255 );
1642 pMaxB[ i ] = MinMax( (long) rCol.GetBlue() + nTol, 0, 255 );
1645 if( pAcc->HasPalette() )
1647 for( USHORT nEntry = 0, nPalCount = pAcc->GetPaletteEntryCount(); nEntry < nPalCount; nEntry++ )
1649 const BitmapColor& rCol = pAcc->GetPaletteColor( nEntry );
1651 for( i = 0UL; i < nColorCount; i++ )
1653 if( pMinR[ i ] <= rCol.GetRed() && pMaxR[ i ] >= rCol.GetRed() &&
1654 pMinG[ i ] <= rCol.GetGreen() && pMaxG[ i ] >= rCol.GetGreen() &&
1655 pMinB[ i ] <= rCol.GetBlue() && pMaxB[ i ] >= rCol.GetBlue() )
1657 pAcc->SetPaletteColor( (USHORT)nEntry, pReplaceColors[ i ] );
1658 break;
1663 else
1665 BitmapColor aCol;
1666 BitmapColor* pReplaces = new BitmapColor[ nColorCount ];
1668 for( i = 0UL; i < nColorCount; i++ )
1669 pReplaces[ i ] = pAcc->GetBestMatchingColor( pReplaceColors[ i ] );
1671 for( long nY = 0L, nHeight = pAcc->Height(); nY < nHeight; nY++ )
1673 for( long nX = 0L, nWidth = pAcc->Width(); nX < nWidth; nX++ )
1675 aCol = pAcc->GetPixel( nY, nX );
1677 for( i = 0UL; i < nColorCount; i++ )
1679 if( pMinR[ i ] <= aCol.GetRed() && pMaxR[ i ] >= aCol.GetRed() &&
1680 pMinG[ i ] <= aCol.GetGreen() && pMaxG[ i ] >= aCol.GetGreen() &&
1681 pMinB[ i ] <= aCol.GetBlue() && pMaxB[ i ] >= aCol.GetBlue() )
1683 pAcc->SetPixel( nY, nX, pReplaces[ i ] );
1684 break;
1690 delete[] pReplaces;
1693 if( !_pTols )
1694 delete[] pTols;
1696 delete[] pMinR;
1697 delete[] pMaxR;
1698 delete[] pMinG;
1699 delete[] pMaxG;
1700 delete[] pMinB;
1701 delete[] pMaxB;
1702 ReleaseAccess( pAcc );
1703 bRet = TRUE;
1706 return bRet;
1709 // ------------------------------------------------------------------
1711 Bitmap Bitmap::CreateDisplayBitmap( OutputDevice* pDisplay )
1713 Bitmap aDispBmp( *this );
1715 if( mpImpBmp && ( pDisplay->mpGraphics || pDisplay->ImplGetGraphics() ) )
1717 ImpBitmap* pImpDispBmp = new ImpBitmap;
1719 if( pImpDispBmp->ImplCreate( *mpImpBmp, pDisplay->mpGraphics ) )
1720 aDispBmp.ImplSetImpBitmap( pImpDispBmp );
1721 else
1722 delete pImpDispBmp;
1725 return aDispBmp;
1728 // ------------------------------------------------------------------
1730 Bitmap Bitmap::GetColorTransformedBitmap( BmpColorMode eColorMode ) const
1732 Bitmap aRet;
1734 if( BMP_COLOR_HIGHCONTRAST == eColorMode )
1736 Color* pSrcColors = NULL;
1737 Color* pDstColors = NULL;
1738 ULONG nColorCount = 0;
1740 aRet = *this;
1742 Image::GetColorTransformArrays( (ImageColorTransform) eColorMode, pSrcColors, pDstColors, nColorCount );
1744 if( nColorCount && pSrcColors && pDstColors )
1745 aRet.Replace( pSrcColors, pDstColors, nColorCount );
1747 delete[] pSrcColors;
1748 delete[] pDstColors;
1750 else if( BMP_COLOR_MONOCHROME_BLACK == eColorMode ||
1751 BMP_COLOR_MONOCHROME_WHITE == eColorMode )
1753 aRet = *this;
1754 aRet.MakeMono( BMP_COLOR_MONOCHROME_THRESHOLD );
1757 return aRet;
1760 // ------------------------------------------------------------------
1762 BOOL Bitmap::CombineSimple( const Bitmap& rMask, BmpCombine eCombine )
1764 BitmapReadAccess* pMaskAcc = ( (Bitmap&) rMask ).AcquireReadAccess();
1765 BitmapWriteAccess* pAcc = AcquireWriteAccess();
1766 BOOL bRet = FALSE;
1768 if( pMaskAcc && pAcc )
1770 const long nWidth = Min( pMaskAcc->Width(), pAcc->Width() );
1771 const long nHeight = Min( pMaskAcc->Height(), pAcc->Height() );
1772 const Color aColBlack( COL_BLACK );
1773 BitmapColor aPixel;
1774 BitmapColor aMaskPixel;
1775 const BitmapColor aWhite( pAcc->GetBestMatchingColor( Color( COL_WHITE ) ) );
1776 const BitmapColor aBlack( pAcc->GetBestMatchingColor( aColBlack ) );
1777 const BitmapColor aMaskBlack( pMaskAcc->GetBestMatchingColor( aColBlack ) );
1779 switch( eCombine )
1781 case( BMP_COMBINE_COPY ):
1783 for( long nY = 0L; nY < nHeight; nY++ ) for( long nX = 0L; nX < nWidth; nX++ )
1785 if( pMaskAcc->GetPixel( nY, nX ) == aMaskBlack )
1786 pAcc->SetPixel( nY, nX, aBlack );
1787 else
1788 pAcc->SetPixel( nY, nX, aWhite );
1791 break;
1793 case( BMP_COMBINE_INVERT ):
1795 for( long nY = 0L; nY < nHeight; nY++ ) for( long nX = 0L; nX < nWidth; nX++ )
1797 if( pAcc->GetPixel( nY, nX ) == aBlack )
1798 pAcc->SetPixel( nY, nX, aWhite );
1799 else
1800 pAcc->SetPixel( nY, nX, aBlack );
1803 break;
1805 case( BMP_COMBINE_AND ):
1807 for( long nY = 0L; nY < nHeight; nY++ ) for( long nX = 0L; nX < nWidth; nX++ )
1809 if( pMaskAcc->GetPixel( nY, nX ) != aMaskBlack && pAcc->GetPixel( nY, nX ) != aBlack )
1810 pAcc->SetPixel( nY, nX, aWhite );
1811 else
1812 pAcc->SetPixel( nY, nX, aBlack );
1815 break;
1817 case( BMP_COMBINE_NAND ):
1819 for( long nY = 0L; nY < nHeight; nY++ ) for( long nX = 0L; nX < nWidth; nX++ )
1821 if( pMaskAcc->GetPixel( nY, nX ) != aMaskBlack && pAcc->GetPixel( nY, nX ) != aBlack )
1822 pAcc->SetPixel( nY, nX, aBlack );
1823 else
1824 pAcc->SetPixel( nY, nX, aWhite );
1827 break;
1829 case( BMP_COMBINE_OR ):
1831 for( long nY = 0L; nY < nHeight; nY++ ) for( long nX = 0L; nX < nWidth; nX++ )
1833 if( pMaskAcc->GetPixel( nY, nX ) != aMaskBlack || pAcc->GetPixel( nY, nX ) != aBlack )
1834 pAcc->SetPixel( nY, nX, aWhite );
1835 else
1836 pAcc->SetPixel( nY, nX, aBlack );
1839 break;
1841 case( BMP_COMBINE_NOR ):
1843 for( long nY = 0L; nY < nHeight; nY++ ) for( long nX = 0L; nX < nWidth; nX++ )
1845 if( pMaskAcc->GetPixel( nY, nX ) != aMaskBlack || pAcc->GetPixel( nY, nX ) != aBlack )
1846 pAcc->SetPixel( nY, nX, aBlack );
1847 else
1848 pAcc->SetPixel( nY, nX, aWhite );
1851 break;
1853 case( BMP_COMBINE_XOR ):
1855 for( long nY = 0L; nY < nHeight; nY++ ) for( long nX = 0L; nX < nWidth; nX++ )
1857 aPixel = pAcc->GetPixel( nY, nX );
1858 aMaskPixel = pMaskAcc->GetPixel( nY, nX );
1860 if( ( aMaskPixel != aMaskBlack && aPixel == aBlack ) ||
1861 ( aMaskPixel == aMaskBlack && aPixel != aBlack ) )
1863 pAcc->SetPixel( nY, nX, aWhite );
1865 else
1866 pAcc->SetPixel( nY, nX, aBlack );
1869 break;
1871 case( BMP_COMBINE_NXOR ):
1873 for( long nY = 0L; nY < nHeight; nY++ ) for( long nX = 0L; nX < nWidth; nX++ )
1875 aPixel = pAcc->GetPixel( nY, nX );
1876 aMaskPixel = pMaskAcc->GetPixel( nY, nX );
1878 if( ( aMaskPixel != aMaskBlack && aPixel == aBlack ) ||
1879 ( aMaskPixel == aMaskBlack && aPixel != aBlack ) )
1881 pAcc->SetPixel( nY, nX, aBlack );
1883 else
1884 pAcc->SetPixel( nY, nX, aWhite );
1887 break;
1890 bRet = TRUE;
1893 ( (Bitmap&) rMask ).ReleaseAccess( pMaskAcc );
1894 ReleaseAccess( pAcc );
1896 return bRet;
1899 // ------------------------------------------------------------------
1901 BOOL Bitmap::Blend( const AlphaMask& rAlpha, const Color& rBackgroundColor )
1903 // TODO: Have a look at OutputDevice::ImplDrawAlpha() for some
1904 // optimizations. Might even consolidate the code here and there.
1906 // convert to a truecolor bitmap, if we're a paletted one. There's
1907 // room for tradeoff decision here, maybe later for an overload (or a flag)
1908 if( GetBitCount() <= 8 )
1909 Convert( BMP_CONVERSION_24BIT );
1911 BitmapReadAccess* pAlphaAcc = const_cast<AlphaMask&>(rAlpha).AcquireReadAccess();
1912 BitmapWriteAccess* pAcc = AcquireWriteAccess();
1913 BOOL bRet = FALSE;
1915 if( pAlphaAcc && pAcc )
1917 const long nWidth = Min( pAlphaAcc->Width(), pAcc->Width() );
1918 const long nHeight = Min( pAlphaAcc->Height(), pAcc->Height() );
1920 for( long nY = 0L; nY < nHeight; ++nY )
1921 for( long nX = 0L; nX < nWidth; ++nX )
1922 pAcc->SetPixel( nY, nX,
1923 pAcc->GetPixel( nY, nX ).Merge( rBackgroundColor,
1924 255 - pAlphaAcc->GetPixel( nY, nX ) ) );
1926 bRet = TRUE;
1929 const_cast<AlphaMask&>(rAlpha).ReleaseAccess( pAlphaAcc );
1930 ReleaseAccess( pAcc );
1932 return bRet;
1935 // ------------------------------------------------------------------
1937 BOOL Bitmap::MakeMono( BYTE cThreshold )
1939 return ImplMakeMono( cThreshold );
1942 // ------------------------------------------------------------------
1944 bool Bitmap::GetSystemData( BitmapSystemData& rData ) const
1946 bool bRet = false;
1947 if( mpImpBmp )
1949 SalBitmap* pSalBitmap = mpImpBmp->ImplGetSalBitmap();
1950 if( pSalBitmap )
1951 bRet = pSalBitmap->GetSystemData( rData );
1954 return bRet;