update credits
[LibreOffice.git] / vcl / source / gdi / bitmap.cxx
blobbf5398df2f2871cfabef0ec657b3fc8ca1342271
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
21 #include <rtl/crc.h>
22 #include <tools/stream.hxx>
23 #include <tools/poly.hxx>
24 #include <tools/rc.h>
25 #include <vcl/salbtype.hxx>
26 #include <vcl/bmpacc.hxx>
27 #include <vcl/outdev.hxx>
28 #include <vcl/bitmap.hxx>
29 #include <vcl/bitmapex.hxx>
30 #include <vcl/svapp.hxx>
31 #include <vcl/image.hxx>
33 #include <impbmp.hxx>
34 #include <salbmp.hxx>
36 Bitmap::Bitmap() :
37 mpImpBmp( NULL )
41 Bitmap::Bitmap( const ResId& rResId ) :
42 mpImpBmp( NULL )
44 const BitmapEx aBmpEx( rResId );
46 if( !aBmpEx.IsEmpty() )
47 *this = aBmpEx.GetBitmap();
50 Bitmap::Bitmap( const Bitmap& rBitmap ) :
51 maPrefMapMode ( rBitmap.maPrefMapMode ),
52 maPrefSize ( rBitmap.maPrefSize )
54 mpImpBmp = rBitmap.mpImpBmp;
56 if ( mpImpBmp )
57 mpImpBmp->ImplIncRefCount();
60 Bitmap::Bitmap( SalBitmap* pSalBitmap )
62 mpImpBmp = new ImpBitmap();
63 mpImpBmp->ImplSetSalBitmap( pSalBitmap );
64 maPrefMapMode = MapMode( MAP_PIXEL );
65 maPrefSize = mpImpBmp->ImplGetSize();
68 Bitmap::Bitmap( const Size& rSizePixel, sal_uInt16 nBitCount, const BitmapPalette* pPal )
70 if( rSizePixel.Width() && rSizePixel.Height() )
72 BitmapPalette aPal;
73 BitmapPalette* pRealPal = NULL;
75 if( nBitCount <= 8 )
77 if( !pPal )
79 if( 1 == nBitCount )
81 aPal.SetEntryCount( 2 );
82 aPal[ 0 ] = Color( COL_BLACK );
83 aPal[ 1 ] = Color( COL_WHITE );
85 else if( ( 4 == nBitCount ) || ( 8 == nBitCount ) )
87 aPal.SetEntryCount( 1 << nBitCount );
88 aPal[ 0 ] = Color( COL_BLACK );
89 aPal[ 1 ] = Color( COL_BLUE );
90 aPal[ 2 ] = Color( COL_GREEN );
91 aPal[ 3 ] = Color( COL_CYAN );
92 aPal[ 4 ] = Color( COL_RED );
93 aPal[ 5 ] = Color( COL_MAGENTA );
94 aPal[ 6 ] = Color( COL_BROWN );
95 aPal[ 7 ] = Color( COL_GRAY );
96 aPal[ 8 ] = Color( COL_LIGHTGRAY );
97 aPal[ 9 ] = Color( COL_LIGHTBLUE );
98 aPal[ 10 ] = Color( COL_LIGHTGREEN );
99 aPal[ 11 ] = Color( COL_LIGHTCYAN );
100 aPal[ 12 ] = Color( COL_LIGHTRED );
101 aPal[ 13 ] = Color( COL_LIGHTMAGENTA );
102 aPal[ 14 ] = Color( COL_YELLOW );
103 aPal[ 15 ] = Color( COL_WHITE );
105 // Create dither palette
106 if( 8 == nBitCount )
108 sal_uInt16 nActCol = 16;
110 for( sal_uInt16 nB = 0; nB < 256; nB += 51 )
111 for( sal_uInt16 nG = 0; nG < 256; nG += 51 )
112 for( sal_uInt16 nR = 0; nR < 256; nR += 51 )
113 aPal[ nActCol++ ] = BitmapColor( (sal_uInt8) nR, (sal_uInt8) nG, (sal_uInt8) nB );
115 // Set standard Office colors
116 aPal[ nActCol++ ] = BitmapColor( 0, 184, 255 );
120 else
121 pRealPal = (BitmapPalette*) pPal;
124 mpImpBmp = new ImpBitmap;
125 mpImpBmp->ImplCreate( rSizePixel, nBitCount, pRealPal ? *pRealPal : aPal );
127 else
128 mpImpBmp = NULL;
131 Bitmap::~Bitmap()
133 ImplReleaseRef();
136 const BitmapPalette& Bitmap::GetGreyPalette( int nEntries )
138 static BitmapPalette aGreyPalette2;
139 static BitmapPalette aGreyPalette4;
140 static BitmapPalette aGreyPalette16;
141 static BitmapPalette aGreyPalette256;
143 // Create greyscale palette with 2, 4, 16 or 256 entries
144 if( 2 == nEntries || 4 == nEntries || 16 == nEntries || 256 == nEntries )
146 if( 2 == nEntries )
148 if( !aGreyPalette2.GetEntryCount() )
150 aGreyPalette2.SetEntryCount( 2 );
151 aGreyPalette2[ 0 ] = BitmapColor( 0, 0, 0 );
152 aGreyPalette2[ 1 ] = BitmapColor( 255, 255, 255 );
155 return aGreyPalette2;
157 else if( 4 == nEntries )
159 if( !aGreyPalette4.GetEntryCount() )
161 aGreyPalette4.SetEntryCount( 4 );
162 aGreyPalette4[ 0 ] = BitmapColor( 0, 0, 0 );
163 aGreyPalette4[ 1 ] = BitmapColor( 85, 85, 85 );
164 aGreyPalette4[ 2 ] = BitmapColor( 170, 170, 170 );
165 aGreyPalette4[ 3 ] = BitmapColor( 255, 255, 255 );
168 return aGreyPalette4;
170 else if( 16 == nEntries )
172 if( !aGreyPalette16.GetEntryCount() )
174 sal_uInt8 cGrey = 0, cGreyInc = 17;
176 aGreyPalette16.SetEntryCount( 16 );
178 for( sal_uInt16 i = 0; i < 16; i++, cGrey = sal::static_int_cast<sal_uInt8>(cGrey + cGreyInc) )
179 aGreyPalette16[ i ] = BitmapColor( cGrey, cGrey, cGrey );
182 return aGreyPalette16;
184 else
186 if( !aGreyPalette256.GetEntryCount() )
188 aGreyPalette256.SetEntryCount( 256 );
190 for( sal_uInt16 i = 0; i < 256; i++ )
191 aGreyPalette256[ i ] = BitmapColor( (sal_uInt8) i, (sal_uInt8) i, (sal_uInt8) i );
194 return aGreyPalette256;
197 else
199 OSL_FAIL( "Bitmap::GetGreyPalette: invalid entry count (2/4/16/256 allowed)" );
200 return aGreyPalette2;
204 bool BitmapPalette::IsGreyPalette() const
206 const int nEntryCount = GetEntryCount();
207 if( !nEntryCount ) // NOTE: an empty palette means 1:1 mapping
208 return true;
209 // See above: only certain entry values will result in a valid call to GetGreyPalette
210 if( nEntryCount == 2 || nEntryCount == 4 || nEntryCount == 16 || nEntryCount == 256 )
212 const BitmapPalette& rGreyPalette = Bitmap::GetGreyPalette( nEntryCount );
213 if( rGreyPalette == *this )
214 return true;
217 bool bRet = false;
218 // TODO: is it worth to compare the entries for the general case?
219 if (nEntryCount == 2)
221 const BitmapColor& rCol0(mpBitmapColor[0]);
222 const BitmapColor& rCol1(mpBitmapColor[1]);
223 bRet = rCol0.GetRed() == rCol0.GetGreen() && rCol0.GetRed() == rCol0.GetBlue() &&
224 rCol1.GetRed() == rCol1.GetGreen() && rCol1.GetRed() == rCol1.GetBlue();
226 return bRet;
229 Bitmap& Bitmap::operator=( const Bitmap& rBitmap )
231 maPrefSize = rBitmap.maPrefSize;
232 maPrefMapMode = rBitmap.maPrefMapMode;
234 if ( rBitmap.mpImpBmp )
235 rBitmap.mpImpBmp->ImplIncRefCount();
237 ImplReleaseRef();
238 mpImpBmp = rBitmap.mpImpBmp;
240 return *this;
243 sal_Bool Bitmap::IsEqual( const Bitmap& rBmp ) const
245 return( IsSameInstance( rBmp ) ||
246 ( rBmp.GetSizePixel() == GetSizePixel() &&
247 rBmp.GetBitCount() == GetBitCount() &&
248 rBmp.GetChecksum() == GetChecksum() ) );
251 void Bitmap::SetEmpty()
253 maPrefMapMode = MapMode();
254 maPrefSize = Size();
256 ImplReleaseRef();
257 mpImpBmp = NULL;
260 Size Bitmap::GetSizePixel() const
262 return( mpImpBmp ? mpImpBmp->ImplGetSize() : Size() );
265 void Bitmap::SetSourceSizePixel( const Size& rSize)
267 if( mpImpBmp )
268 mpImpBmp->ImplSetSourceSize( rSize);
271 sal_uInt16 Bitmap::GetBitCount() const
273 return( mpImpBmp ? mpImpBmp->ImplGetBitCount() : 0 );
276 sal_Bool Bitmap::HasGreyPalette() const
278 const sal_uInt16 nBitCount = GetBitCount();
279 sal_Bool bRet = nBitCount == 1 ? sal_True : sal_False;
281 BitmapReadAccess* pRAcc = ( (Bitmap*) this )->AcquireReadAccess();
283 if( pRAcc )
285 bRet = pRAcc->HasPalette() && pRAcc->GetPalette().IsGreyPalette();
286 ( (Bitmap*) this )->ReleaseAccess( pRAcc );
289 return bRet;
292 sal_uLong Bitmap::GetChecksum() const
294 sal_uLong nRet = 0UL;
296 if( mpImpBmp )
298 nRet = mpImpBmp->ImplGetChecksum();
300 if( !nRet )
302 BitmapReadAccess* pRAcc = ( (Bitmap*) this )->AcquireReadAccess();
304 if( pRAcc && pRAcc->Width() && pRAcc->Height() )
306 sal_uInt32 nCrc = 0;
307 SVBT32 aBT32;
309 pRAcc->ImplZeroInitUnusedBits();
311 UInt32ToSVBT32( pRAcc->Width(), aBT32 );
312 nCrc = rtl_crc32( nCrc, aBT32, 4 );
314 UInt32ToSVBT32( pRAcc->Height(), aBT32 );
315 nCrc = rtl_crc32( nCrc, aBT32, 4 );
317 UInt32ToSVBT32( pRAcc->GetBitCount(), aBT32 );
318 nCrc = rtl_crc32( nCrc, aBT32, 4 );
320 UInt32ToSVBT32( pRAcc->GetColorMask().GetRedMask(), aBT32 );
321 nCrc = rtl_crc32( nCrc, aBT32, 4 );
323 UInt32ToSVBT32( pRAcc->GetColorMask().GetGreenMask(), aBT32 );
324 nCrc = rtl_crc32( nCrc, aBT32, 4 );
326 UInt32ToSVBT32( pRAcc->GetColorMask().GetBlueMask(), aBT32 );
327 nCrc = rtl_crc32( nCrc, aBT32, 4 );
329 if( pRAcc->HasPalette() )
331 nCrc = rtl_crc32( nCrc, pRAcc->GetPalette().ImplGetColorBuffer(),
332 pRAcc->GetPaletteEntryCount() * sizeof( BitmapColor ) );
335 nCrc = rtl_crc32( nCrc, pRAcc->GetBuffer(), pRAcc->GetScanlineSize() * pRAcc->Height() );
337 mpImpBmp->ImplSetChecksum( nRet = nCrc );
340 if (pRAcc) ( (Bitmap*) this )->ReleaseAccess( pRAcc );
344 return nRet;
347 void Bitmap::ImplReleaseRef()
349 if( mpImpBmp )
351 if( mpImpBmp->ImplGetRefCount() > 1UL )
352 mpImpBmp->ImplDecRefCount();
353 else
355 delete mpImpBmp;
356 mpImpBmp = NULL;
361 void Bitmap::ImplMakeUnique()
363 if( mpImpBmp && mpImpBmp->ImplGetRefCount() > 1UL )
365 ImpBitmap* pOldImpBmp = mpImpBmp;
367 pOldImpBmp->ImplDecRefCount();
369 mpImpBmp = new ImpBitmap;
370 mpImpBmp->ImplCreate( *pOldImpBmp );
374 void Bitmap::ImplAssignWithSize( const Bitmap& rBitmap )
376 const Size aOldSizePix( GetSizePixel() );
377 const Size aNewSizePix( rBitmap.GetSizePixel() );
378 const MapMode aOldMapMode( maPrefMapMode );
379 Size aNewPrefSize;
381 if( ( aOldSizePix != aNewSizePix ) && aOldSizePix.Width() && aOldSizePix.Height() )
383 aNewPrefSize.Width() = FRound( maPrefSize.Width() * aNewSizePix.Width() / aOldSizePix.Width() );
384 aNewPrefSize.Height() = FRound( maPrefSize.Height() * aNewSizePix.Height() / aOldSizePix.Height() );
386 else
387 aNewPrefSize = maPrefSize;
389 *this = rBitmap;
391 maPrefSize = aNewPrefSize;
392 maPrefMapMode = aOldMapMode;
395 ImpBitmap* Bitmap::ImplGetImpBitmap() const
397 return mpImpBmp;
400 void Bitmap::ImplSetImpBitmap( ImpBitmap* pImpBmp )
402 if( pImpBmp != mpImpBmp )
404 ImplReleaseRef();
405 mpImpBmp = pImpBmp;
409 BitmapReadAccess* Bitmap::AcquireReadAccess()
411 BitmapReadAccess* pReadAccess = new BitmapReadAccess( *this );
413 if( !*pReadAccess )
415 delete pReadAccess;
416 pReadAccess = NULL;
419 return pReadAccess;
422 BitmapWriteAccess* Bitmap::AcquireWriteAccess()
424 BitmapWriteAccess* pWriteAccess = new BitmapWriteAccess( *this );
426 if( !*pWriteAccess )
428 delete pWriteAccess;
429 pWriteAccess = NULL;
432 return pWriteAccess;
435 void Bitmap::ReleaseAccess( BitmapReadAccess* pBitmapAccess )
437 delete pBitmapAccess;
440 sal_Bool Bitmap::Erase( const Color& rFillColor )
442 if( !(*this) )
443 return sal_True;
445 BitmapWriteAccess* pWriteAcc = AcquireWriteAccess();
446 sal_Bool bRet = sal_False;
448 if( pWriteAcc )
450 const sal_uLong nFormat = pWriteAcc->GetScanlineFormat();
451 sal_uInt8 cIndex = 0;
452 sal_Bool bFast = sal_False;
454 switch( nFormat )
456 case( BMP_FORMAT_1BIT_MSB_PAL ):
457 case( BMP_FORMAT_1BIT_LSB_PAL ):
459 cIndex = (sal_uInt8) pWriteAcc->GetBestPaletteIndex( rFillColor );
460 cIndex = ( cIndex ? 255 : 0 );
461 bFast = sal_True;
463 break;
465 case( BMP_FORMAT_4BIT_MSN_PAL ):
466 case( BMP_FORMAT_4BIT_LSN_PAL ):
468 cIndex = (sal_uInt8) pWriteAcc->GetBestPaletteIndex( rFillColor );
469 cIndex = cIndex | ( cIndex << 4 );
470 bFast = sal_True;
472 break;
474 case( BMP_FORMAT_8BIT_PAL ):
476 cIndex = (sal_uInt8) pWriteAcc->GetBestPaletteIndex( rFillColor );
477 bFast = sal_True;
479 break;
481 case( BMP_FORMAT_24BIT_TC_BGR ):
482 case( BMP_FORMAT_24BIT_TC_RGB ):
484 if( ( rFillColor.GetRed() == rFillColor.GetGreen() ) &&
485 ( rFillColor.GetRed() == rFillColor.GetBlue() ) )
487 cIndex = rFillColor.GetRed();
488 bFast = sal_True;
490 else
491 bFast = sal_False;
493 break;
495 default:
496 bFast = sal_False;
497 break;
500 if( bFast )
502 const sal_uLong nBufSize = pWriteAcc->GetScanlineSize() * pWriteAcc->Height();
503 memset( pWriteAcc->GetBuffer(), cIndex, nBufSize );
505 else
507 Point aTmpPoint;
508 const Rectangle aRect( aTmpPoint, Size( pWriteAcc->Width(), pWriteAcc->Height() ) );
509 pWriteAcc->SetFillColor( rFillColor );
510 pWriteAcc->FillRect( aRect );
513 ReleaseAccess( pWriteAcc );
514 bRet = sal_True;
517 return bRet;
520 sal_Bool Bitmap::Invert()
522 BitmapWriteAccess* pAcc = AcquireWriteAccess();
523 sal_Bool bRet = sal_False;
525 if( pAcc )
527 if( pAcc->HasPalette() )
529 BitmapPalette aBmpPal( pAcc->GetPalette() );
530 const sal_uInt16 nCount = aBmpPal.GetEntryCount();
532 for( sal_uInt16 i = 0; i < nCount; i++ )
533 aBmpPal[ i ].Invert();
535 pAcc->SetPalette( aBmpPal );
537 else
539 const long nWidth = pAcc->Width();
540 const long nHeight = pAcc->Height();
542 for( long nX = 0L; nX < nWidth; nX++ )
543 for( long nY = 0L; nY < nHeight; nY++ )
544 pAcc->SetPixel( nY, nX, pAcc->GetPixel( nY, nX ).Invert() );
547 ReleaseAccess( pAcc );
548 bRet = sal_True;
551 return bRet;
554 sal_Bool Bitmap::Mirror( sal_uLong nMirrorFlags )
556 sal_Bool bHorz = ( ( nMirrorFlags & BMP_MIRROR_HORZ ) == BMP_MIRROR_HORZ );
557 sal_Bool bVert = ( ( nMirrorFlags & BMP_MIRROR_VERT ) == BMP_MIRROR_VERT );
558 sal_Bool bRet = sal_False;
560 if( bHorz && !bVert )
562 BitmapWriteAccess* pAcc = AcquireWriteAccess();
564 if( pAcc )
566 const long nWidth = pAcc->Width();
567 const long nHeight = pAcc->Height();
568 const long nWidth1 = nWidth - 1L;
569 const long nWidth_2 = nWidth >> 1L;
571 for( long nY = 0L; nY < nHeight; nY++ )
573 for( long nX = 0L, nOther = nWidth1; nX < nWidth_2; nX++, nOther-- )
575 const BitmapColor aTemp( pAcc->GetPixel( nY, nX ) );
577 pAcc->SetPixel( nY, nX, pAcc->GetPixel( nY, nOther ) );
578 pAcc->SetPixel( nY, nOther, aTemp );
582 ReleaseAccess( pAcc );
583 bRet = sal_True;
586 else if( bVert && !bHorz )
588 BitmapWriteAccess* pAcc = AcquireWriteAccess();
590 if( pAcc )
592 const long nScanSize = pAcc->GetScanlineSize();
593 sal_uInt8* pBuffer = new sal_uInt8[ nScanSize ];
594 const long nHeight = pAcc->Height();
595 const long nHeight1 = nHeight - 1L;
596 const long nHeight_2 = nHeight >> 1L;
598 for( long nY = 0L, nOther = nHeight1; nY < nHeight_2; nY++, nOther-- )
600 memcpy( pBuffer, pAcc->GetScanline( nY ), nScanSize );
601 memcpy( pAcc->GetScanline( nY ), pAcc->GetScanline( nOther ), nScanSize );
602 memcpy( pAcc->GetScanline( nOther ), pBuffer, nScanSize );
605 delete[] pBuffer;
606 ReleaseAccess( pAcc );
607 bRet = sal_True;
610 else if( bHorz && bVert )
612 BitmapWriteAccess* pAcc = AcquireWriteAccess();
614 if( pAcc )
616 const long nWidth = pAcc->Width();
617 const long nWidth1 = nWidth - 1L;
618 const long nHeight = pAcc->Height();
619 long nHeight_2 = nHeight >> 1;
621 for( long nY = 0L, nOtherY = nHeight - 1L; nY < nHeight_2; nY++, nOtherY-- )
623 for( long nX = 0L, nOtherX = nWidth1; nX < nWidth; nX++, nOtherX-- )
625 const BitmapColor aTemp( pAcc->GetPixel( nY, nX ) );
627 pAcc->SetPixel( nY, nX, pAcc->GetPixel( nOtherY, nOtherX ) );
628 pAcc->SetPixel( nOtherY, nOtherX, aTemp );
632 // ggf. noch mittlere Zeile horizontal spiegeln
633 if( nHeight & 1 )
635 for( long nX = 0L, nOtherX = nWidth1, nWidth_2 = nWidth >> 1; nX < nWidth_2; nX++, nOtherX-- )
637 const BitmapColor aTemp( pAcc->GetPixel( nHeight_2, nX ) );
638 pAcc->SetPixel( nHeight_2, nX, pAcc->GetPixel( nHeight_2, nOtherX ) );
639 pAcc->SetPixel( nHeight_2, nOtherX, aTemp );
643 ReleaseAccess( pAcc );
644 bRet = sal_True;
647 else
648 bRet = sal_True;
650 return bRet;
653 sal_Bool Bitmap::Rotate( long nAngle10, const Color& rFillColor )
655 sal_Bool bRet = sal_False;
657 nAngle10 %= 3600L;
658 nAngle10 = ( nAngle10 < 0L ) ? ( 3599L + nAngle10 ) : nAngle10;
660 if( !nAngle10 )
661 bRet = sal_True;
662 else if( 1800L == nAngle10 )
663 bRet = Mirror( BMP_MIRROR_HORZ | BMP_MIRROR_VERT );
664 else
666 BitmapReadAccess* pReadAcc = AcquireReadAccess();
667 Bitmap aRotatedBmp;
669 if( pReadAcc )
671 const Size aSizePix( GetSizePixel() );
673 if( ( 900L == nAngle10 ) || ( 2700L == nAngle10 ) )
675 const Size aNewSizePix( aSizePix.Height(), aSizePix.Width() );
676 Bitmap aNewBmp( aNewSizePix, GetBitCount(), &pReadAcc->GetPalette() );
677 BitmapWriteAccess* pWriteAcc = aNewBmp.AcquireWriteAccess();
679 if( pWriteAcc )
681 const long nWidth = aSizePix.Width();
682 const long nWidth1 = nWidth - 1L;
683 const long nHeight = aSizePix.Height();
684 const long nHeight1 = nHeight - 1L;
685 const long nNewWidth = aNewSizePix.Width();
686 const long nNewHeight = aNewSizePix.Height();
688 if( 900L == nAngle10 )
690 for( long nY = 0L, nOtherX = nWidth1; nY < nNewHeight; nY++, nOtherX-- )
691 for( long nX = 0L, nOtherY = 0L; nX < nNewWidth; nX++ )
692 pWriteAcc->SetPixel( nY, nX, pReadAcc->GetPixel( nOtherY++, nOtherX ) );
694 else if( 2700L == nAngle10 )
696 for( long nY = 0L, nOtherX = 0L; nY < nNewHeight; nY++, nOtherX++ )
697 for( long nX = 0L, nOtherY = nHeight1; nX < nNewWidth; nX++ )
698 pWriteAcc->SetPixel( nY, nX, pReadAcc->GetPixel( nOtherY--, nOtherX ) );
701 aNewBmp.ReleaseAccess( pWriteAcc );
704 aRotatedBmp = aNewBmp;
706 else
708 Point aTmpPoint;
709 Rectangle aTmpRectangle( aTmpPoint, aSizePix );
710 Polygon aPoly( aTmpRectangle );
711 aPoly.Rotate( aTmpPoint, (sal_uInt16) nAngle10 );
713 Rectangle aNewBound( aPoly.GetBoundRect() );
714 const Size aNewSizePix( aNewBound.GetSize() );
715 Bitmap aNewBmp( aNewSizePix, GetBitCount(), &pReadAcc->GetPalette() );
716 BitmapWriteAccess* pWriteAcc = aNewBmp.AcquireWriteAccess();
718 if( pWriteAcc )
720 const BitmapColor aFillColor( pWriteAcc->GetBestMatchingColor( rFillColor ) );
721 const double fCosAngle = cos( nAngle10 * F_PI1800 );
722 const double fSinAngle = sin( nAngle10 * F_PI1800 );
723 const double fXMin = aNewBound.Left();
724 const double fYMin = aNewBound.Top();
725 const long nWidth = aSizePix.Width();
726 const long nHeight = aSizePix.Height();
727 const long nNewWidth = aNewSizePix.Width();
728 const long nNewHeight = aNewSizePix.Height();
729 long nX;
730 long nY;
731 long nRotX;
732 long nRotY;
733 long nSinY;
734 long nCosY;
735 long* pCosX = new long[ nNewWidth ];
736 long* pSinX = new long[ nNewWidth ];
737 long* pCosY = new long[ nNewHeight ];
738 long* pSinY = new long[ nNewHeight ];
740 for ( nX = 0; nX < nNewWidth; nX++ )
742 const double fTmp = ( fXMin + nX ) * 64.;
744 pCosX[ nX ] = FRound( fCosAngle * fTmp );
745 pSinX[ nX ] = FRound( fSinAngle * fTmp );
748 for ( nY = 0; nY < nNewHeight; nY++ )
750 const double fTmp = ( fYMin + nY ) * 64.;
752 pCosY[ nY ] = FRound( fCosAngle * fTmp );
753 pSinY[ nY ] = FRound( fSinAngle * fTmp );
756 for( nY = 0L; nY < nNewHeight; nY++ )
758 nSinY = pSinY[ nY ];
759 nCosY = pCosY[ nY ];
761 for( nX = 0L; nX < nNewWidth; nX++ )
763 nRotX = ( pCosX[ nX ] - nSinY ) >> 6;
764 nRotY = ( pSinX[ nX ] + nCosY ) >> 6;
766 if ( ( nRotX > -1L ) && ( nRotX < nWidth ) && ( nRotY > -1L ) && ( nRotY < nHeight ) )
767 pWriteAcc->SetPixel( nY, nX, pReadAcc->GetPixel( nRotY, nRotX ) );
768 else
769 pWriteAcc->SetPixel( nY, nX, aFillColor );
773 delete[] pSinX;
774 delete[] pCosX;
775 delete[] pSinY;
776 delete[] pCosY;
778 aNewBmp.ReleaseAccess( pWriteAcc );
781 aRotatedBmp = aNewBmp;
784 ReleaseAccess( pReadAcc );
787 if( ( bRet = !!aRotatedBmp ) == sal_True )
788 ImplAssignWithSize( aRotatedBmp );
791 return bRet;
794 sal_Bool Bitmap::Crop( const Rectangle& rRectPixel )
796 const Size aSizePix( GetSizePixel() );
797 Rectangle aRect( rRectPixel );
798 sal_Bool bRet = sal_False;
800 aRect.Intersection( Rectangle( Point(), aSizePix ) );
802 if( !aRect.IsEmpty() )
804 BitmapReadAccess* pReadAcc = AcquireReadAccess();
806 if( pReadAcc )
808 Point aTmpPoint;
809 const Rectangle aNewRect( aTmpPoint, aRect.GetSize() );
810 Bitmap aNewBmp( aNewRect.GetSize(), GetBitCount(), &pReadAcc->GetPalette() );
811 BitmapWriteAccess* pWriteAcc = aNewBmp.AcquireWriteAccess();
813 if( pWriteAcc )
815 const long nOldX = aRect.Left();
816 const long nOldY = aRect.Top();
817 const long nNewWidth = aNewRect.GetWidth();
818 const long nNewHeight = aNewRect.GetHeight();
820 for( long nY = 0, nY2 = nOldY; nY < nNewHeight; nY++, nY2++ )
821 for( long nX = 0, nX2 = nOldX; nX < nNewWidth; nX++, nX2++ )
822 pWriteAcc->SetPixel( nY, nX, pReadAcc->GetPixel( nY2, nX2 ) );
824 aNewBmp.ReleaseAccess( pWriteAcc );
825 bRet = sal_True;
828 ReleaseAccess( pReadAcc );
830 if( bRet )
831 ImplAssignWithSize( aNewBmp );
835 return bRet;
838 sal_Bool Bitmap::CopyPixel( const Rectangle& rRectDst,
839 const Rectangle& rRectSrc, const Bitmap* pBmpSrc )
841 const Size aSizePix( GetSizePixel() );
842 Rectangle aRectDst( rRectDst );
843 sal_Bool bRet = sal_False;
845 aRectDst.Intersection( Rectangle( Point(), aSizePix ) );
847 if( !aRectDst.IsEmpty() )
849 if( pBmpSrc && ( *pBmpSrc != *this ) )
851 Bitmap* pSrc = (Bitmap*) pBmpSrc;
852 const Size aCopySizePix( pSrc->GetSizePixel() );
853 Rectangle aRectSrc( rRectSrc );
854 const sal_uInt16 nSrcBitCount = pBmpSrc->GetBitCount();
855 const sal_uInt16 nDstBitCount = GetBitCount();
857 if( nSrcBitCount > nDstBitCount )
859 long nNextIndex = 0L;
861 if( ( nSrcBitCount == 24 ) && ( nDstBitCount < 24 ) )
862 Convert( BMP_CONVERSION_24BIT );
863 else if( ( nSrcBitCount == 8 ) && ( nDstBitCount < 8 ) )
865 Convert( BMP_CONVERSION_8BIT_COLORS );
866 nNextIndex = 16;
868 else if( ( nSrcBitCount == 4 ) && ( nDstBitCount < 4 ) )
870 Convert( BMP_CONVERSION_4BIT_COLORS );
871 nNextIndex = 2;
874 if( nNextIndex )
876 BitmapReadAccess* pSrcAcc = pSrc->AcquireReadAccess();
877 BitmapWriteAccess* pDstAcc = AcquireWriteAccess();
879 if( pSrcAcc && pDstAcc )
881 const long nSrcCount = pDstAcc->GetPaletteEntryCount();
882 const long nDstCount = 1 << nDstBitCount;
883 sal_Bool bFound;
885 for( long i = 0L; ( i < nSrcCount ) && ( nNextIndex < nSrcCount ); i++ )
887 const BitmapColor& rSrcCol = pSrcAcc->GetPaletteColor( (sal_uInt16) i );
889 bFound = sal_False;
891 for( long j = 0L; j < nDstCount; j++ )
893 if( rSrcCol == pDstAcc->GetPaletteColor( (sal_uInt16) j ) )
895 bFound = sal_True;
896 break;
900 if( !bFound )
901 pDstAcc->SetPaletteColor( (sal_uInt16) nNextIndex++, rSrcCol );
905 if( pSrcAcc )
906 pSrc->ReleaseAccess( pSrcAcc );
908 if( pDstAcc )
909 ReleaseAccess( pDstAcc );
913 aRectSrc.Intersection( Rectangle( Point(), aCopySizePix ) );
915 if( !aRectSrc.IsEmpty() )
917 BitmapReadAccess* pReadAcc = pSrc->AcquireReadAccess();
919 if( pReadAcc )
921 BitmapWriteAccess* pWriteAcc = AcquireWriteAccess();
923 if( pWriteAcc )
925 const long nWidth = std::min( aRectSrc.GetWidth(), aRectDst.GetWidth() );
926 const long nHeight = std::min( aRectSrc.GetHeight(), aRectDst.GetHeight() );
927 const long nSrcEndX = aRectSrc.Left() + nWidth;
928 const long nSrcEndY = aRectSrc.Top() + nHeight;
929 long nDstY = aRectDst.Top();
931 if( pReadAcc->HasPalette() && pWriteAcc->HasPalette() )
933 const sal_uInt16 nCount = pReadAcc->GetPaletteEntryCount();
934 sal_uInt8* pMap = new sal_uInt8[ nCount ];
936 // Create index map for the color table, as the bitmap should be copied
937 // retaining it's color information relatively well
938 for( sal_uInt16 i = 0; i < nCount; i++ )
939 pMap[ i ] = (sal_uInt8) pWriteAcc->GetBestPaletteIndex( pReadAcc->GetPaletteColor( i ) );
941 for( long nSrcY = aRectSrc.Top(); nSrcY < nSrcEndY; nSrcY++, nDstY++ )
942 for( long nSrcX = aRectSrc.Left(), nDstX = aRectDst.Left(); nSrcX < nSrcEndX; nSrcX++, nDstX++ )
943 pWriteAcc->SetPixelIndex( nDstY, nDstX, pMap[ pReadAcc->GetPixelIndex( nSrcY, nSrcX ) ] );
945 delete[] pMap;
947 else if( pReadAcc->HasPalette() )
949 for( long nSrcY = aRectSrc.Top(); nSrcY < nSrcEndY; nSrcY++, nDstY++ )
950 for( long nSrcX = aRectSrc.Left(), nDstX = aRectDst.Left(); nSrcX < nSrcEndX; nSrcX++, nDstX++ )
951 pWriteAcc->SetPixel( nDstY, nDstX, pReadAcc->GetPaletteColor( pReadAcc->GetPixelIndex( nSrcY, nSrcX ) ) );
953 else
954 for( long nSrcY = aRectSrc.Top(); nSrcY < nSrcEndY; nSrcY++, nDstY++ )
955 for( long nSrcX = aRectSrc.Left(), nDstX = aRectDst.Left(); nSrcX < nSrcEndX; nSrcX++, nDstX++ )
956 pWriteAcc->SetPixel( nDstY, nDstX, pReadAcc->GetPixel( nSrcY, nSrcX ) );
958 ReleaseAccess( pWriteAcc );
959 bRet = ( nWidth > 0L ) && ( nHeight > 0L );
962 pSrc->ReleaseAccess( pReadAcc );
966 else
968 Rectangle aRectSrc( rRectSrc );
970 aRectSrc.Intersection( Rectangle( Point(), aSizePix ) );
972 if( !aRectSrc.IsEmpty() && ( aRectSrc != aRectDst ) )
974 BitmapWriteAccess* pWriteAcc = AcquireWriteAccess();
976 if( pWriteAcc )
978 const long nWidth = std::min( aRectSrc.GetWidth(), aRectDst.GetWidth() );
979 const long nHeight = std::min( aRectSrc.GetHeight(), aRectDst.GetHeight() );
980 const long nSrcX = aRectSrc.Left();
981 const long nSrcY = aRectSrc.Top();
982 const long nSrcEndX1 = nSrcX + nWidth - 1L;
983 const long nSrcEndY1 = nSrcY + nHeight - 1L;
984 const long nDstX = aRectDst.Left();
985 const long nDstY = aRectDst.Top();
986 const long nDstEndX1 = nDstX + nWidth - 1L;
987 const long nDstEndY1 = nDstY + nHeight - 1L;
989 if( ( nDstX <= nSrcX ) && ( nDstY <= nSrcY ) )
991 for( long nY = nSrcY, nYN = nDstY; nY <= nSrcEndY1; nY++, nYN++ )
992 for( long nX = nSrcX, nXN = nDstX; nX <= nSrcEndX1; nX++, nXN++ )
993 pWriteAcc->SetPixel( nYN, nXN, pWriteAcc->GetPixel( nY, nX ) );
995 else if( ( nDstX <= nSrcX ) && ( nDstY >= nSrcY ) )
997 for( long nY = nSrcEndY1, nYN = nDstEndY1; nY >= nSrcY; nY--, nYN-- )
998 for( long nX = nSrcX, nXN = nDstX; nX <= nSrcEndX1; nX++, nXN++ )
999 pWriteAcc->SetPixel( nYN, nXN, pWriteAcc->GetPixel( nY, nX ) );
1001 else if( ( nDstX >= nSrcX ) && ( nDstY <= nSrcY ) )
1003 for( long nY = nSrcY, nYN = nDstY; nY <= nSrcEndY1; nY++, nYN++ )
1004 for( long nX = nSrcEndX1, nXN = nDstEndX1; nX >= nSrcX; nX--, nXN-- )
1005 pWriteAcc->SetPixel( nYN, nXN, pWriteAcc->GetPixel( nY, nX ) );
1007 else
1009 for( long nY = nSrcEndY1, nYN = nDstEndY1; nY >= nSrcY; nY--, nYN-- )
1010 for( long nX = nSrcEndX1, nXN = nDstEndX1; nX >= nSrcX; nX--, nXN-- )
1011 pWriteAcc->SetPixel( nYN, nXN, pWriteAcc->GetPixel( nY, nX ) );
1014 ReleaseAccess( pWriteAcc );
1015 bRet = sal_True;
1021 return bRet;
1024 sal_Bool Bitmap::Expand( sal_uLong nDX, sal_uLong nDY, const Color* pInitColor )
1026 sal_Bool bRet = sal_False;
1028 if( nDX || nDY )
1030 const Size aSizePixel( GetSizePixel() );
1031 const long nWidth = aSizePixel.Width();
1032 const long nHeight = aSizePixel.Height();
1033 const Size aNewSize( nWidth + nDX, nHeight + nDY );
1034 BitmapReadAccess* pReadAcc = AcquireReadAccess();
1036 if( pReadAcc )
1038 BitmapPalette aBmpPal( pReadAcc->GetPalette() );
1039 Bitmap aNewBmp( aNewSize, GetBitCount(), &aBmpPal );
1040 BitmapWriteAccess* pWriteAcc = aNewBmp.AcquireWriteAccess();
1042 if( pWriteAcc )
1044 BitmapColor aColor;
1045 const long nNewX = nWidth;
1046 const long nNewY = nHeight;
1047 const long nNewWidth = pWriteAcc->Width();
1048 const long nNewHeight = pWriteAcc->Height();
1049 long nX;
1050 long nY;
1052 if( pInitColor )
1053 aColor = pWriteAcc->GetBestMatchingColor( *pInitColor );
1055 for( nY = 0L; nY < nHeight; nY++ )
1057 pWriteAcc->CopyScanline( nY, *pReadAcc );
1059 if( pInitColor && nDX )
1060 for( nX = nNewX; nX < nNewWidth; nX++ )
1061 pWriteAcc->SetPixel( nY, nX, aColor );
1064 if( pInitColor && nDY )
1065 for( nY = nNewY; nY < nNewHeight; nY++ )
1066 for( nX = 0; nX < nNewWidth; nX++ )
1067 pWriteAcc->SetPixel( nY, nX, aColor );
1069 aNewBmp.ReleaseAccess( pWriteAcc );
1070 bRet = sal_True;
1073 ReleaseAccess( pReadAcc );
1075 if( bRet )
1076 ImplAssignWithSize( aNewBmp );
1080 return bRet;
1083 Bitmap Bitmap::CreateMask( const Color& rTransColor, sal_uLong nTol ) const
1085 Bitmap aNewBmp( GetSizePixel(), 1 );
1086 BitmapWriteAccess* pWriteAcc = aNewBmp.AcquireWriteAccess();
1087 sal_Bool bRet = sal_False;
1089 if( pWriteAcc )
1091 BitmapReadAccess* pReadAcc = ( (Bitmap*) this )->AcquireReadAccess();
1093 if( pReadAcc )
1095 const long nWidth = pReadAcc->Width();
1096 const long nHeight = pReadAcc->Height();
1097 const BitmapColor aBlack( pWriteAcc->GetBestMatchingColor( Color( COL_BLACK ) ) );
1098 const BitmapColor aWhite( pWriteAcc->GetBestMatchingColor( Color( COL_WHITE ) ) );
1100 if( !nTol )
1102 const BitmapColor aTest( pReadAcc->GetBestMatchingColor( rTransColor ) );
1103 long nX, nY;
1105 if( pReadAcc->GetScanlineFormat() == BMP_FORMAT_4BIT_MSN_PAL ||
1106 pReadAcc->GetScanlineFormat() == BMP_FORMAT_4BIT_LSN_PAL )
1108 // optimized for 4Bit-MSN/LSN source palette
1109 const sal_uInt8 cTest = aTest.GetIndex();
1110 const long nShiftInit = ( ( pReadAcc->GetScanlineFormat() == BMP_FORMAT_4BIT_MSN_PAL ) ? 4 : 0 );
1112 if( pWriteAcc->GetScanlineFormat() == BMP_FORMAT_1BIT_MSB_PAL &&
1113 aWhite.GetIndex() == 1 )
1115 // optimized for 1Bit-MSB destination palette
1116 for( nY = 0L; nY < nHeight; nY++ )
1118 Scanline pSrc = pReadAcc->GetScanline( nY );
1119 Scanline pDst = pWriteAcc->GetScanline( nY );
1120 long nShift = 0;
1121 for( nX = 0L, nShift = nShiftInit; nX < nWidth; nX++, nShift ^= 4 )
1123 if( cTest == ( ( pSrc[ nX >> 1 ] >> nShift ) & 0x0f ) )
1124 pDst[ nX >> 3 ] |= 1 << ( 7 - ( nX & 7 ) );
1125 else
1126 pDst[ nX >> 3 ] &= ~( 1 << ( 7 - ( nX & 7 ) ) );
1130 else
1132 for( nY = 0L; nY < nHeight; nY++ )
1134 Scanline pSrc = pReadAcc->GetScanline( nY );
1135 long nShift = 0;
1136 for( nX = 0L, nShift = nShiftInit; nX < nWidth; nX++, nShift ^= 4 )
1138 if( cTest == ( ( pSrc[ nX >> 1 ] >> nShift ) & 0x0f ) )
1139 pWriteAcc->SetPixel( nY, nX, aWhite );
1140 else
1141 pWriteAcc->SetPixel( nY, nX, aBlack );
1146 else if( pReadAcc->GetScanlineFormat() == BMP_FORMAT_8BIT_PAL )
1148 // optimized for 8Bit source palette
1149 const sal_uInt8 cTest = aTest.GetIndex();
1151 if( pWriteAcc->GetScanlineFormat() == BMP_FORMAT_1BIT_MSB_PAL &&
1152 aWhite.GetIndex() == 1 )
1154 // optimized for 1Bit-MSB destination palette
1155 for( nY = 0L; nY < nHeight; nY++ )
1157 Scanline pSrc = pReadAcc->GetScanline( nY );
1158 Scanline pDst = pWriteAcc->GetScanline( nY );
1159 for( nX = 0L; nX < nWidth; nX++ )
1161 if( cTest == pSrc[ nX ] )
1162 pDst[ nX >> 3 ] |= 1 << ( 7 - ( nX & 7 ) );
1163 else
1164 pDst[ nX >> 3 ] &= ~( 1 << ( 7 - ( nX & 7 ) ) );
1168 else
1170 for( nY = 0L; nY < nHeight; nY++ )
1172 Scanline pSrc = pReadAcc->GetScanline( nY );
1173 for( nX = 0L; nX < nWidth; nX++ )
1175 if( cTest == pSrc[ nX ] )
1176 pWriteAcc->SetPixel( nY, nX, aWhite );
1177 else
1178 pWriteAcc->SetPixel( nY, nX, aBlack );
1183 else
1185 // not optimized
1186 for( nY = 0L; nY < nHeight; nY++ )
1188 for( nX = 0L; nX < nWidth; nX++ )
1190 if( aTest == pReadAcc->GetPixel( nY, nX ) )
1191 pWriteAcc->SetPixel( nY, nX, aWhite );
1192 else
1193 pWriteAcc->SetPixel( nY, nX, aBlack );
1198 else
1200 BitmapColor aCol;
1201 long nR, nG, nB;
1202 const long nMinR = MinMax( (long) rTransColor.GetRed() - nTol, 0, 255 );
1203 const long nMaxR = MinMax( (long) rTransColor.GetRed() + nTol, 0, 255 );
1204 const long nMinG = MinMax( (long) rTransColor.GetGreen() - nTol, 0, 255 );
1205 const long nMaxG = MinMax( (long) rTransColor.GetGreen() + nTol, 0, 255 );
1206 const long nMinB = MinMax( (long) rTransColor.GetBlue() - nTol, 0, 255 );
1207 const long nMaxB = MinMax( (long) rTransColor.GetBlue() + nTol, 0, 255 );
1209 if( pReadAcc->HasPalette() )
1211 for( long nY = 0L; nY < nHeight; nY++ )
1213 for( long nX = 0L; nX < nWidth; nX++ )
1215 aCol = pReadAcc->GetPaletteColor( pReadAcc->GetPixelIndex( nY, nX ) );
1216 nR = aCol.GetRed();
1217 nG = aCol.GetGreen();
1218 nB = aCol.GetBlue();
1220 if( nMinR <= nR && nMaxR >= nR &&
1221 nMinG <= nG && nMaxG >= nG &&
1222 nMinB <= nB && nMaxB >= nB )
1224 pWriteAcc->SetPixel( nY, nX, aWhite );
1226 else
1227 pWriteAcc->SetPixel( nY, nX, aBlack );
1231 else
1233 for( long nY = 0L; nY < nHeight; nY++ )
1235 for( long nX = 0L; nX < nWidth; nX++ )
1237 aCol = pReadAcc->GetPixel( nY, nX );
1238 nR = aCol.GetRed();
1239 nG = aCol.GetGreen();
1240 nB = aCol.GetBlue();
1242 if( nMinR <= nR && nMaxR >= nR &&
1243 nMinG <= nG && nMaxG >= nG &&
1244 nMinB <= nB && nMaxB >= nB )
1246 pWriteAcc->SetPixel( nY, nX, aWhite );
1248 else
1249 pWriteAcc->SetPixel( nY, nX, aBlack );
1255 ( (Bitmap*) this )->ReleaseAccess( pReadAcc );
1256 bRet = sal_True;
1259 aNewBmp.ReleaseAccess( pWriteAcc );
1262 if( bRet )
1264 aNewBmp.maPrefSize = maPrefSize;
1265 aNewBmp.maPrefMapMode = maPrefMapMode;
1267 else
1268 aNewBmp = Bitmap();
1270 return aNewBmp;
1273 Region Bitmap::CreateRegion( const Color& rColor, const Rectangle& rRect ) const
1275 Region aRegion;
1276 Rectangle aRect( rRect );
1277 BitmapReadAccess* pReadAcc = ( (Bitmap*) this )->AcquireReadAccess();
1279 aRect.Intersection( Rectangle( Point(), GetSizePixel() ) );
1280 aRect.Justify();
1282 if( pReadAcc )
1284 Rectangle aSubRect;
1285 const long nLeft = aRect.Left();
1286 const long nTop = aRect.Top();
1287 const long nRight = aRect.Right();
1288 const long nBottom = aRect.Bottom();
1289 const BitmapColor aMatch( pReadAcc->GetBestMatchingColor( rColor ) );
1291 aRegion.ImplBeginAddRect();
1293 for( long nY = nTop; nY <= nBottom; nY++ )
1295 aSubRect.Top() = aSubRect.Bottom() = nY;
1297 for( long nX = nLeft; nX <= nRight; )
1299 while( ( nX <= nRight ) && ( aMatch != pReadAcc->GetPixel( nY, nX ) ) )
1300 nX++;
1302 if( nX <= nRight )
1304 aSubRect.Left() = nX;
1306 while( ( nX <= nRight ) && ( aMatch == pReadAcc->GetPixel( nY, nX ) ) )
1307 nX++;
1309 aSubRect.Right() = nX - 1L;
1310 aRegion.ImplAddRect( aSubRect );
1315 aRegion.ImplEndAddRect();
1316 ( (Bitmap*) this )->ReleaseAccess( pReadAcc );
1318 else
1319 aRegion = aRect;
1321 return aRegion;
1324 sal_Bool Bitmap::Replace( const Bitmap& rMask, const Color& rReplaceColor )
1326 BitmapReadAccess* pMaskAcc = ( (Bitmap&) rMask ).AcquireReadAccess();
1327 BitmapWriteAccess* pAcc = AcquireWriteAccess();
1328 sal_Bool bRet = sal_False;
1330 if( pMaskAcc && pAcc )
1332 const long nWidth = std::min( pMaskAcc->Width(), pAcc->Width() );
1333 const long nHeight = std::min( pMaskAcc->Height(), pAcc->Height() );
1334 const BitmapColor aMaskWhite( pMaskAcc->GetBestMatchingColor( Color( COL_WHITE ) ) );
1335 BitmapColor aReplace;
1337 if( pAcc->HasPalette() )
1339 const sal_uInt16 nActColors = pAcc->GetPaletteEntryCount();
1340 const sal_uInt16 nMaxColors = 1 << pAcc->GetBitCount();
1342 // default to the nearest color
1343 aReplace = pAcc->GetBestMatchingColor( rReplaceColor );
1345 // for paletted images without a matching palette entry
1346 // look for an unused palette entry (NOTE: expensive!)
1347 if( pAcc->GetPaletteColor( aReplace.GetIndex() ) != BitmapColor( rReplaceColor ) )
1349 // if the palette has empty entries use the last one
1350 if( nActColors < nMaxColors )
1352 pAcc->SetPaletteEntryCount( nActColors + 1 );
1353 pAcc->SetPaletteColor( nActColors, rReplaceColor );
1354 aReplace = BitmapColor( (sal_uInt8) nActColors );
1356 else
1358 sal_Bool* pFlags = new sal_Bool[ nMaxColors ];
1360 // Set all entries to 0
1361 memset( pFlags, 0, nMaxColors );
1363 for( long nY = 0L; nY < nHeight; nY++ )
1364 for( long nX = 0L; nX < nWidth; nX++ )
1365 pFlags[ pAcc->GetPixelIndex( nY, nX ) ] = sal_True;
1367 for( sal_uInt16 i = 0UL; i < nMaxColors; i++ )
1369 // Hurray, we do have an unsused entry
1370 if( !pFlags[ i ] )
1372 pAcc->SetPaletteColor( (sal_uInt16) i, rReplaceColor );
1373 aReplace = BitmapColor( (sal_uInt8) i );
1377 delete[] pFlags;
1381 else
1382 aReplace = rReplaceColor;
1384 for( long nY = 0L; nY < nHeight; nY++ )
1385 for( long nX = 0L; nX < nWidth; nX++ )
1386 if( pMaskAcc->GetPixel( nY, nX ) == aMaskWhite )
1387 pAcc->SetPixel( nY, nX, aReplace );
1389 bRet = sal_True;
1392 ( (Bitmap&) rMask ).ReleaseAccess( pMaskAcc );
1393 ReleaseAccess( pAcc );
1395 return bRet;
1398 sal_Bool Bitmap::Replace( const AlphaMask& rAlpha, const Color& rMergeColor )
1400 Bitmap aNewBmp( GetSizePixel(), 24 );
1401 BitmapReadAccess* pAcc = AcquireReadAccess();
1402 BitmapReadAccess* pAlphaAcc = ( (AlphaMask&) rAlpha ).AcquireReadAccess();
1403 BitmapWriteAccess* pNewAcc = aNewBmp.AcquireWriteAccess();
1404 sal_Bool bRet = sal_False;
1406 if( pAcc && pAlphaAcc && pNewAcc )
1408 BitmapColor aCol;
1409 const long nWidth = std::min( pAlphaAcc->Width(), pAcc->Width() );
1410 const long nHeight = std::min( pAlphaAcc->Height(), pAcc->Height() );
1412 for( long nY = 0L; nY < nHeight; nY++ )
1414 for( long nX = 0L; nX < nWidth; nX++ )
1416 aCol = pAcc->GetColor( nY, nX );
1417 pNewAcc->SetPixel( nY, nX, aCol.Merge( rMergeColor, 255 - pAlphaAcc->GetPixelIndex( nY, nX ) ) );
1421 bRet = sal_True;
1424 ReleaseAccess( pAcc );
1425 ( (AlphaMask&) rAlpha ).ReleaseAccess( pAlphaAcc );
1426 aNewBmp.ReleaseAccess( pNewAcc );
1428 if( bRet )
1430 const MapMode aMap( maPrefMapMode );
1431 const Size aSize( maPrefSize );
1433 *this = aNewBmp;
1435 maPrefMapMode = aMap;
1436 maPrefSize = aSize;
1439 return bRet;
1442 sal_Bool Bitmap::Replace( const Color& rSearchColor, const Color& rReplaceColor, sal_uLong nTol )
1444 // Bitmaps with 1 bit color depth can cause problems
1445 // if they have other entries than black/white in their palette
1446 if( 1 == GetBitCount() )
1447 Convert( BMP_CONVERSION_4BIT_COLORS );
1449 BitmapWriteAccess* pAcc = AcquireWriteAccess();
1450 sal_Bool bRet = sal_False;
1452 if( pAcc )
1454 const long nMinR = MinMax( (long) rSearchColor.GetRed() - nTol, 0, 255 );
1455 const long nMaxR = MinMax( (long) rSearchColor.GetRed() + nTol, 0, 255 );
1456 const long nMinG = MinMax( (long) rSearchColor.GetGreen() - nTol, 0, 255 );
1457 const long nMaxG = MinMax( (long) rSearchColor.GetGreen() + nTol, 0, 255 );
1458 const long nMinB = MinMax( (long) rSearchColor.GetBlue() - nTol, 0, 255 );
1459 const long nMaxB = MinMax( (long) rSearchColor.GetBlue() + nTol, 0, 255 );
1461 if( pAcc->HasPalette() )
1463 for( sal_uInt16 i = 0, nPalCount = pAcc->GetPaletteEntryCount(); i < nPalCount; i++ )
1465 const BitmapColor& rCol = pAcc->GetPaletteColor( i );
1467 if( nMinR <= rCol.GetRed() && nMaxR >= rCol.GetRed() &&
1468 nMinG <= rCol.GetGreen() && nMaxG >= rCol.GetGreen() &&
1469 nMinB <= rCol.GetBlue() && nMaxB >= rCol.GetBlue() )
1471 pAcc->SetPaletteColor( i, rReplaceColor );
1475 else
1477 BitmapColor aCol;
1478 const BitmapColor aReplace( pAcc->GetBestMatchingColor( rReplaceColor ) );
1480 for( long nY = 0L, nHeight = pAcc->Height(); nY < nHeight; nY++ )
1482 for( long nX = 0L, nWidth = pAcc->Width(); nX < nWidth; nX++ )
1484 aCol = pAcc->GetPixel( nY, nX );
1486 if( nMinR <= aCol.GetRed() && nMaxR >= aCol.GetRed() &&
1487 nMinG <= aCol.GetGreen() && nMaxG >= aCol.GetGreen() &&
1488 nMinB <= aCol.GetBlue() && nMaxB >= aCol.GetBlue() )
1490 pAcc->SetPixel( nY, nX, aReplace );
1496 ReleaseAccess( pAcc );
1497 bRet = sal_True;
1500 return bRet;
1503 sal_Bool Bitmap::Replace( const Color* pSearchColors, const Color* pReplaceColors,
1504 sal_uLong nColorCount, sal_uLong* _pTols )
1506 // Bitmaps with 1 bit color depth can cause problems
1507 // if they have other entries than black/white in their palette
1508 if( 1 == GetBitCount() )
1509 Convert( BMP_CONVERSION_4BIT_COLORS );
1511 BitmapWriteAccess* pAcc = AcquireWriteAccess();
1512 sal_Bool bRet = sal_False;
1514 if( pAcc )
1516 long* pMinR = new long[ nColorCount ];
1517 long* pMaxR = new long[ nColorCount ];
1518 long* pMinG = new long[ nColorCount ];
1519 long* pMaxG = new long[ nColorCount ];
1520 long* pMinB = new long[ nColorCount ];
1521 long* pMaxB = new long[ nColorCount ];
1522 long* pTols;
1523 sal_uLong i;
1525 if( !_pTols )
1527 pTols = new long[ nColorCount ];
1528 memset( pTols, 0, nColorCount * sizeof( long ) );
1530 else
1531 pTols = (long*) _pTols;
1533 for( i = 0UL; i < nColorCount; i++ )
1535 const Color& rCol = pSearchColors[ i ];
1536 const long nTol = pTols[ i ];
1538 pMinR[ i ] = MinMax( (long) rCol.GetRed() - nTol, 0, 255 );
1539 pMaxR[ i ] = MinMax( (long) rCol.GetRed() + nTol, 0, 255 );
1540 pMinG[ i ] = MinMax( (long) rCol.GetGreen() - nTol, 0, 255 );
1541 pMaxG[ i ] = MinMax( (long) rCol.GetGreen() + nTol, 0, 255 );
1542 pMinB[ i ] = MinMax( (long) rCol.GetBlue() - nTol, 0, 255 );
1543 pMaxB[ i ] = MinMax( (long) rCol.GetBlue() + nTol, 0, 255 );
1546 if( pAcc->HasPalette() )
1548 for( sal_uInt16 nEntry = 0, nPalCount = pAcc->GetPaletteEntryCount(); nEntry < nPalCount; nEntry++ )
1550 const BitmapColor& rCol = pAcc->GetPaletteColor( nEntry );
1552 for( i = 0UL; i < nColorCount; i++ )
1554 if( pMinR[ i ] <= rCol.GetRed() && pMaxR[ i ] >= rCol.GetRed() &&
1555 pMinG[ i ] <= rCol.GetGreen() && pMaxG[ i ] >= rCol.GetGreen() &&
1556 pMinB[ i ] <= rCol.GetBlue() && pMaxB[ i ] >= rCol.GetBlue() )
1558 pAcc->SetPaletteColor( (sal_uInt16)nEntry, pReplaceColors[ i ] );
1559 break;
1564 else
1566 BitmapColor aCol;
1567 BitmapColor* pReplaces = new BitmapColor[ nColorCount ];
1569 for( i = 0UL; i < nColorCount; i++ )
1570 pReplaces[ i ] = pAcc->GetBestMatchingColor( pReplaceColors[ i ] );
1572 for( long nY = 0L, nHeight = pAcc->Height(); nY < nHeight; nY++ )
1574 for( long nX = 0L, nWidth = pAcc->Width(); nX < nWidth; nX++ )
1576 aCol = pAcc->GetPixel( nY, nX );
1578 for( i = 0UL; i < nColorCount; i++ )
1580 if( pMinR[ i ] <= aCol.GetRed() && pMaxR[ i ] >= aCol.GetRed() &&
1581 pMinG[ i ] <= aCol.GetGreen() && pMaxG[ i ] >= aCol.GetGreen() &&
1582 pMinB[ i ] <= aCol.GetBlue() && pMaxB[ i ] >= aCol.GetBlue() )
1584 pAcc->SetPixel( nY, nX, pReplaces[ i ] );
1585 break;
1591 delete[] pReplaces;
1594 if( !_pTols )
1595 delete[] pTols;
1597 delete[] pMinR;
1598 delete[] pMaxR;
1599 delete[] pMinG;
1600 delete[] pMaxG;
1601 delete[] pMinB;
1602 delete[] pMaxB;
1603 ReleaseAccess( pAcc );
1604 bRet = sal_True;
1607 return bRet;
1610 Bitmap Bitmap::CreateDisplayBitmap( OutputDevice* pDisplay )
1612 Bitmap aDispBmp( *this );
1614 if( mpImpBmp && ( pDisplay->mpGraphics || pDisplay->ImplGetGraphics() ) )
1616 ImpBitmap* pImpDispBmp = new ImpBitmap;
1618 if( pImpDispBmp->ImplCreate( *mpImpBmp, pDisplay->mpGraphics ) )
1619 aDispBmp.ImplSetImpBitmap( pImpDispBmp );
1620 else
1621 delete pImpDispBmp;
1624 return aDispBmp;
1627 sal_Bool Bitmap::CombineSimple( const Bitmap& rMask, BmpCombine eCombine )
1629 BitmapReadAccess* pMaskAcc = ( (Bitmap&) rMask ).AcquireReadAccess();
1630 BitmapWriteAccess* pAcc = AcquireWriteAccess();
1631 sal_Bool bRet = sal_False;
1633 if( pMaskAcc && pAcc )
1635 const long nWidth = std::min( pMaskAcc->Width(), pAcc->Width() );
1636 const long nHeight = std::min( pMaskAcc->Height(), pAcc->Height() );
1637 const Color aColBlack( COL_BLACK );
1638 BitmapColor aPixel;
1639 BitmapColor aMaskPixel;
1640 const BitmapColor aWhite( pAcc->GetBestMatchingColor( Color( COL_WHITE ) ) );
1641 const BitmapColor aBlack( pAcc->GetBestMatchingColor( aColBlack ) );
1642 const BitmapColor aMaskBlack( pMaskAcc->GetBestMatchingColor( aColBlack ) );
1644 switch( eCombine )
1646 case( BMP_COMBINE_COPY ):
1648 for( long nY = 0L; nY < nHeight; nY++ ) for( long nX = 0L; nX < nWidth; nX++ )
1650 if( pMaskAcc->GetPixel( nY, nX ) == aMaskBlack )
1651 pAcc->SetPixel( nY, nX, aBlack );
1652 else
1653 pAcc->SetPixel( nY, nX, aWhite );
1656 break;
1658 case( BMP_COMBINE_INVERT ):
1660 for( long nY = 0L; nY < nHeight; nY++ ) for( long nX = 0L; nX < nWidth; nX++ )
1662 if( pAcc->GetPixel( nY, nX ) == aBlack )
1663 pAcc->SetPixel( nY, nX, aWhite );
1664 else
1665 pAcc->SetPixel( nY, nX, aBlack );
1668 break;
1670 case( BMP_COMBINE_AND ):
1672 for( long nY = 0L; nY < nHeight; nY++ ) for( long nX = 0L; nX < nWidth; nX++ )
1674 if( pMaskAcc->GetPixel( nY, nX ) != aMaskBlack && pAcc->GetPixel( nY, nX ) != aBlack )
1675 pAcc->SetPixel( nY, nX, aWhite );
1676 else
1677 pAcc->SetPixel( nY, nX, aBlack );
1680 break;
1682 case( BMP_COMBINE_NAND ):
1684 for( long nY = 0L; nY < nHeight; nY++ ) for( long nX = 0L; nX < nWidth; nX++ )
1686 if( pMaskAcc->GetPixel( nY, nX ) != aMaskBlack && pAcc->GetPixel( nY, nX ) != aBlack )
1687 pAcc->SetPixel( nY, nX, aBlack );
1688 else
1689 pAcc->SetPixel( nY, nX, aWhite );
1692 break;
1694 case( BMP_COMBINE_OR ):
1696 for( long nY = 0L; nY < nHeight; nY++ ) for( long nX = 0L; nX < nWidth; nX++ )
1698 if( pMaskAcc->GetPixel( nY, nX ) != aMaskBlack || pAcc->GetPixel( nY, nX ) != aBlack )
1699 pAcc->SetPixel( nY, nX, aWhite );
1700 else
1701 pAcc->SetPixel( nY, nX, aBlack );
1704 break;
1706 case( BMP_COMBINE_NOR ):
1708 for( long nY = 0L; nY < nHeight; nY++ ) for( long nX = 0L; nX < nWidth; nX++ )
1710 if( pMaskAcc->GetPixel( nY, nX ) != aMaskBlack || pAcc->GetPixel( nY, nX ) != aBlack )
1711 pAcc->SetPixel( nY, nX, aBlack );
1712 else
1713 pAcc->SetPixel( nY, nX, aWhite );
1716 break;
1718 case( BMP_COMBINE_XOR ):
1720 for( long nY = 0L; nY < nHeight; nY++ ) for( long nX = 0L; nX < nWidth; nX++ )
1722 aPixel = pAcc->GetPixel( nY, nX );
1723 aMaskPixel = pMaskAcc->GetPixel( nY, nX );
1725 if( ( aMaskPixel != aMaskBlack && aPixel == aBlack ) ||
1726 ( aMaskPixel == aMaskBlack && aPixel != aBlack ) )
1728 pAcc->SetPixel( nY, nX, aWhite );
1730 else
1731 pAcc->SetPixel( nY, nX, aBlack );
1734 break;
1736 case( BMP_COMBINE_NXOR ):
1738 for( long nY = 0L; nY < nHeight; nY++ ) for( long nX = 0L; nX < nWidth; nX++ )
1740 aPixel = pAcc->GetPixel( nY, nX );
1741 aMaskPixel = pMaskAcc->GetPixel( nY, nX );
1743 if( ( aMaskPixel != aMaskBlack && aPixel == aBlack ) ||
1744 ( aMaskPixel == aMaskBlack && aPixel != aBlack ) )
1746 pAcc->SetPixel( nY, nX, aBlack );
1748 else
1749 pAcc->SetPixel( nY, nX, aWhite );
1752 break;
1755 bRet = sal_True;
1758 ( (Bitmap&) rMask ).ReleaseAccess( pMaskAcc );
1759 ReleaseAccess( pAcc );
1761 return bRet;
1764 // TODO: Have a look at OutputDevice::ImplDrawAlpha() for some
1765 // optimizations. Might even consolidate the code here and there.
1766 sal_Bool Bitmap::Blend( const AlphaMask& rAlpha, const Color& rBackgroundColor )
1768 // Convert to a truecolor bitmap, if we're a paletted one. There's
1769 // room for tradeoff decision here, maybe later for an overload (or a flag)
1770 if( GetBitCount() <= 8 )
1771 Convert( BMP_CONVERSION_24BIT );
1773 BitmapReadAccess* pAlphaAcc = const_cast<AlphaMask&>(rAlpha).AcquireReadAccess();
1774 BitmapWriteAccess* pAcc = AcquireWriteAccess();
1775 sal_Bool bRet = sal_False;
1777 if( pAlphaAcc && pAcc )
1779 const long nWidth = std::min( pAlphaAcc->Width(), pAcc->Width() );
1780 const long nHeight = std::min( pAlphaAcc->Height(), pAcc->Height() );
1782 for( long nY = 0L; nY < nHeight; ++nY )
1783 for( long nX = 0L; nX < nWidth; ++nX )
1784 pAcc->SetPixel( nY, nX,
1785 pAcc->GetPixel( nY, nX ).Merge( rBackgroundColor,
1786 255 - pAlphaAcc->GetPixelIndex( nY, nX ) ) );
1788 bRet = sal_True;
1791 const_cast<AlphaMask&>(rAlpha).ReleaseAccess( pAlphaAcc );
1792 ReleaseAccess( pAcc );
1794 return bRet;
1797 sal_Bool Bitmap::MakeMono( sal_uInt8 cThreshold )
1799 return ImplMakeMono( cThreshold );
1802 bool Bitmap::GetSystemData( BitmapSystemData& rData ) const
1804 bool bRet = false;
1805 if( mpImpBmp )
1807 SalBitmap* pSalBitmap = mpImpBmp->ImplGetSalBitmap();
1808 if( pSalBitmap )
1809 bRet = pSalBitmap->GetSystemData( rData );
1812 return bRet;
1815 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */