update emoji autocorrect entries from po-files
[LibreOffice.git] / vcl / source / gdi / bitmap.cxx
blob45ecf09c124af224575d9c4a0373dbf41c2338a7
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 .
20 #include <algorithm>
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>
35 #include <boost/scoped_array.hpp>
37 Bitmap::Bitmap() :
38 mpImpBmp( NULL )
42 Bitmap::Bitmap( const ResId& rResId ) :
43 mpImpBmp( NULL )
45 const BitmapEx aBmpEx( rResId );
47 if( !aBmpEx.IsEmpty() )
48 *this = aBmpEx.GetBitmap();
51 Bitmap::Bitmap( const Bitmap& rBitmap ) :
52 maPrefMapMode ( rBitmap.maPrefMapMode ),
53 maPrefSize ( rBitmap.maPrefSize )
55 mpImpBmp = rBitmap.mpImpBmp;
57 if ( mpImpBmp )
58 mpImpBmp->ImplIncRefCount();
61 Bitmap::Bitmap( SalBitmap* pSalBitmap )
63 mpImpBmp = new ImpBitmap(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 = const_cast<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 if (this == &rBitmap)
232 return *this;
234 maPrefSize = rBitmap.maPrefSize;
235 maPrefMapMode = rBitmap.maPrefMapMode;
237 if ( rBitmap.mpImpBmp )
238 rBitmap.mpImpBmp->ImplIncRefCount();
240 ImplReleaseRef();
241 mpImpBmp = rBitmap.mpImpBmp;
243 return *this;
246 bool Bitmap::IsEqual( const Bitmap& rBmp ) const
248 return(IsSameInstance(rBmp) || // Includes both are nullptr
249 (rBmp.mpImpBmp && mpImpBmp && mpImpBmp->ImplIsEqual(*rBmp.mpImpBmp)));
252 void Bitmap::SetEmpty()
254 maPrefMapMode = MapMode();
255 maPrefSize = Size();
257 ImplReleaseRef();
258 mpImpBmp = NULL;
261 Size Bitmap::GetSizePixel() const
263 return( mpImpBmp ? mpImpBmp->ImplGetSize() : Size() );
266 sal_uInt16 Bitmap::GetBitCount() const
268 return( mpImpBmp ? mpImpBmp->ImplGetBitCount() : 0 );
271 bool Bitmap::HasGreyPalette() const
273 const sal_uInt16 nBitCount = GetBitCount();
274 bool bRet = nBitCount == 1;
276 BitmapInfoAccess* pIAcc = const_cast<Bitmap*>(this)->AcquireInfoAccess();
278 if( pIAcc )
280 bRet = pIAcc->HasPalette() && pIAcc->GetPalette().IsGreyPalette();
281 ReleaseAccess( pIAcc );
284 return bRet;
287 BitmapChecksum Bitmap::GetChecksum() const
289 BitmapChecksum nRet = 0;
291 if( mpImpBmp )
293 nRet = mpImpBmp->ImplGetChecksum();
296 return nRet;
299 void Bitmap::ImplReleaseRef()
301 if( mpImpBmp )
303 if( mpImpBmp->ImplGetRefCount() > 1UL )
304 mpImpBmp->ImplDecRefCount();
305 else
307 delete mpImpBmp;
308 mpImpBmp = NULL;
313 void Bitmap::ImplMakeUnique()
315 if( mpImpBmp && mpImpBmp->ImplGetRefCount() > 1UL )
317 ImpBitmap* pOldImpBmp = mpImpBmp;
319 pOldImpBmp->ImplDecRefCount();
321 mpImpBmp = new ImpBitmap;
322 mpImpBmp->ImplCreate( *pOldImpBmp );
326 void Bitmap::ImplAssignWithSize( const Bitmap& rBitmap )
328 const Size aOldSizePix( GetSizePixel() );
329 const Size aNewSizePix( rBitmap.GetSizePixel() );
330 const MapMode aOldMapMode( maPrefMapMode );
331 Size aNewPrefSize;
333 if( ( aOldSizePix != aNewSizePix ) && aOldSizePix.Width() && aOldSizePix.Height() )
335 aNewPrefSize.Width() = FRound( maPrefSize.Width() * aNewSizePix.Width() / aOldSizePix.Width() );
336 aNewPrefSize.Height() = FRound( maPrefSize.Height() * aNewSizePix.Height() / aOldSizePix.Height() );
338 else
339 aNewPrefSize = maPrefSize;
341 *this = rBitmap;
343 maPrefSize = aNewPrefSize;
344 maPrefMapMode = aOldMapMode;
348 void Bitmap::ImplSetImpBitmap( ImpBitmap* pImpBmp )
350 if( pImpBmp != mpImpBmp )
352 ImplReleaseRef();
353 mpImpBmp = pImpBmp;
357 BitmapInfoAccess* Bitmap::AcquireInfoAccess()
359 BitmapInfoAccess* pInfoAccess = new BitmapInfoAccess( *this );
361 if( !*pInfoAccess )
363 delete pInfoAccess;
364 pInfoAccess = NULL;
367 return pInfoAccess;
370 BitmapReadAccess* Bitmap::AcquireReadAccess()
372 BitmapReadAccess* pReadAccess = new BitmapReadAccess( *this );
374 if( !*pReadAccess )
376 delete pReadAccess;
377 pReadAccess = NULL;
380 return pReadAccess;
383 BitmapWriteAccess* Bitmap::AcquireWriteAccess()
385 BitmapWriteAccess* pWriteAccess = new BitmapWriteAccess( *this );
387 if( !*pWriteAccess )
389 delete pWriteAccess;
390 pWriteAccess = NULL;
393 return pWriteAccess;
396 void Bitmap::ReleaseAccess( BitmapInfoAccess* pBitmapAccess )
398 delete pBitmapAccess;
401 bool Bitmap::Erase(const Color& rFillColor)
403 if (IsEmpty())
404 return true;
406 Bitmap::ScopedWriteAccess pWriteAcc(*this);
407 bool bRet = false;
409 if (pWriteAcc)
411 const sal_uLong nFormat = pWriteAcc->GetScanlineFormat();
412 sal_uInt8 cIndex = 0;
413 bool bFast = false;
415 switch (nFormat)
417 case BMP_FORMAT_1BIT_MSB_PAL:
418 case BMP_FORMAT_1BIT_LSB_PAL:
420 cIndex = static_cast<sal_uInt8>(pWriteAcc->GetBestPaletteIndex(rFillColor));
421 cIndex = (cIndex ? 255 : 0);
422 bFast = true;
424 break;
426 case BMP_FORMAT_4BIT_MSN_PAL:
427 case BMP_FORMAT_4BIT_LSN_PAL:
429 cIndex = static_cast<sal_uInt8>(pWriteAcc->GetBestPaletteIndex(rFillColor));
430 cIndex = cIndex | ( cIndex << 4 );
431 bFast = true;
433 break;
435 case BMP_FORMAT_8BIT_PAL:
437 cIndex = static_cast<sal_uInt8>(pWriteAcc->GetBestPaletteIndex(rFillColor));
438 bFast = true;
440 break;
442 case BMP_FORMAT_24BIT_TC_BGR:
443 case BMP_FORMAT_24BIT_TC_RGB:
445 if (rFillColor.GetRed() == rFillColor.GetGreen() &&
446 rFillColor.GetRed() == rFillColor.GetBlue())
448 cIndex = rFillColor.GetRed();
449 bFast = true;
451 else
452 bFast = false;
454 break;
456 default:
457 bFast = false;
458 break;
461 if( bFast )
463 const sal_uLong nBufSize = pWriteAcc->GetScanlineSize() * pWriteAcc->Height();
464 memset( pWriteAcc->GetBuffer(), cIndex, nBufSize );
466 else
468 Point aTmpPoint;
469 const Rectangle aRect( aTmpPoint, Size( pWriteAcc->Width(), pWriteAcc->Height() ) );
470 pWriteAcc->SetFillColor( rFillColor );
471 pWriteAcc->FillRect( aRect );
474 bRet = true;
477 return bRet;
480 bool Bitmap::Invert()
482 BitmapWriteAccess* pAcc = AcquireWriteAccess();
483 bool bRet = false;
485 if( pAcc )
487 if( pAcc->HasPalette() )
489 BitmapPalette aBmpPal( pAcc->GetPalette() );
490 const sal_uInt16 nCount = aBmpPal.GetEntryCount();
492 for( sal_uInt16 i = 0; i < nCount; i++ )
493 aBmpPal[ i ].Invert();
495 pAcc->SetPalette( aBmpPal );
497 else
499 const long nWidth = pAcc->Width();
500 const long nHeight = pAcc->Height();
502 for( long nX = 0L; nX < nWidth; nX++ )
503 for( long nY = 0L; nY < nHeight; nY++ )
504 pAcc->SetPixel( nY, nX, pAcc->GetPixel( nY, nX ).Invert() );
507 mpImpBmp->ImplInvalidateChecksum();
508 ReleaseAccess( pAcc );
509 bRet = true;
512 return bRet;
515 bool Bitmap::Mirror( BmpMirrorFlags nMirrorFlags )
517 bool bHorz( nMirrorFlags & BmpMirrorFlags::Horizontal );
518 bool bVert( nMirrorFlags & BmpMirrorFlags::Vertical );
519 bool bRet = false;
521 if( bHorz && !bVert )
523 BitmapWriteAccess* pAcc = AcquireWriteAccess();
525 if( pAcc )
527 const long nWidth = pAcc->Width();
528 const long nHeight = pAcc->Height();
529 const long nWidth1 = nWidth - 1L;
530 const long nWidth_2 = nWidth >> 1L;
532 for( long nY = 0L; nY < nHeight; nY++ )
534 for( long nX = 0L, nOther = nWidth1; nX < nWidth_2; nX++, nOther-- )
536 const BitmapColor aTemp( pAcc->GetPixel( nY, nX ) );
538 pAcc->SetPixel( nY, nX, pAcc->GetPixel( nY, nOther ) );
539 pAcc->SetPixel( nY, nOther, aTemp );
543 ReleaseAccess( pAcc );
544 bRet = true;
547 else if( bVert && !bHorz )
549 BitmapWriteAccess* pAcc = AcquireWriteAccess();
551 if( pAcc )
553 const long nScanSize = pAcc->GetScanlineSize();
554 boost::scoped_array<sal_uInt8> pBuffer(new sal_uInt8[ nScanSize ]);
555 const long nHeight = pAcc->Height();
556 const long nHeight1 = nHeight - 1L;
557 const long nHeight_2 = nHeight >> 1L;
559 for( long nY = 0L, nOther = nHeight1; nY < nHeight_2; nY++, nOther-- )
561 memcpy( pBuffer.get(), pAcc->GetScanline( nY ), nScanSize );
562 memcpy( pAcc->GetScanline( nY ), pAcc->GetScanline( nOther ), nScanSize );
563 memcpy( pAcc->GetScanline( nOther ), pBuffer.get(), nScanSize );
566 ReleaseAccess( pAcc );
567 bRet = true;
570 else if( bHorz && bVert )
572 BitmapWriteAccess* pAcc = AcquireWriteAccess();
574 if( pAcc )
576 const long nWidth = pAcc->Width();
577 const long nWidth1 = nWidth - 1L;
578 const long nHeight = pAcc->Height();
579 long nHeight_2 = nHeight >> 1;
581 for( long nY = 0L, nOtherY = nHeight - 1L; nY < nHeight_2; nY++, nOtherY-- )
583 for( long nX = 0L, nOtherX = nWidth1; nX < nWidth; nX++, nOtherX-- )
585 const BitmapColor aTemp( pAcc->GetPixel( nY, nX ) );
587 pAcc->SetPixel( nY, nX, pAcc->GetPixel( nOtherY, nOtherX ) );
588 pAcc->SetPixel( nOtherY, nOtherX, aTemp );
592 // ggf. noch mittlere Zeile horizontal spiegeln
593 if( nHeight & 1 )
595 for( long nX = 0L, nOtherX = nWidth1, nWidth_2 = nWidth >> 1; nX < nWidth_2; nX++, nOtherX-- )
597 const BitmapColor aTemp( pAcc->GetPixel( nHeight_2, nX ) );
598 pAcc->SetPixel( nHeight_2, nX, pAcc->GetPixel( nHeight_2, nOtherX ) );
599 pAcc->SetPixel( nHeight_2, nOtherX, aTemp );
603 ReleaseAccess( pAcc );
604 bRet = true;
607 else
608 bRet = true;
610 return bRet;
613 bool Bitmap::Rotate( long nAngle10, const Color& rFillColor )
615 bool bRet = false;
617 nAngle10 %= 3600L;
618 nAngle10 = ( nAngle10 < 0L ) ? ( 3599L + nAngle10 ) : nAngle10;
620 if( !nAngle10 )
621 bRet = true;
622 else if( 1800L == nAngle10 )
623 bRet = Mirror( BmpMirrorFlags::Horizontal | BmpMirrorFlags::Vertical );
624 else
626 BitmapReadAccess* pReadAcc = AcquireReadAccess();
627 Bitmap aRotatedBmp;
629 if( pReadAcc )
631 const Size aSizePix( GetSizePixel() );
633 if( ( 900L == nAngle10 ) || ( 2700L == nAngle10 ) )
635 const Size aNewSizePix( aSizePix.Height(), aSizePix.Width() );
636 Bitmap aNewBmp( aNewSizePix, GetBitCount(), &pReadAcc->GetPalette() );
637 BitmapWriteAccess* pWriteAcc = aNewBmp.AcquireWriteAccess();
639 if( pWriteAcc )
641 const long nWidth = aSizePix.Width();
642 const long nWidth1 = nWidth - 1L;
643 const long nHeight = aSizePix.Height();
644 const long nHeight1 = nHeight - 1L;
645 const long nNewWidth = aNewSizePix.Width();
646 const long nNewHeight = aNewSizePix.Height();
648 if( 900L == nAngle10 )
650 for( long nY = 0L, nOtherX = nWidth1; nY < nNewHeight; nY++, nOtherX-- )
651 for( long nX = 0L, nOtherY = 0L; nX < nNewWidth; nX++ )
652 pWriteAcc->SetPixel( nY, nX, pReadAcc->GetPixel( nOtherY++, nOtherX ) );
654 else if( 2700L == nAngle10 )
656 for( long nY = 0L, nOtherX = 0L; nY < nNewHeight; nY++, nOtherX++ )
657 for( long nX = 0L, nOtherY = nHeight1; nX < nNewWidth; nX++ )
658 pWriteAcc->SetPixel( nY, nX, pReadAcc->GetPixel( nOtherY--, nOtherX ) );
661 ReleaseAccess( pWriteAcc );
664 aRotatedBmp = aNewBmp;
666 else
668 Point aTmpPoint;
669 Rectangle aTmpRectangle( aTmpPoint, aSizePix );
670 Polygon aPoly( aTmpRectangle );
671 aPoly.Rotate( aTmpPoint, (sal_uInt16) nAngle10 );
673 Rectangle aNewBound( aPoly.GetBoundRect() );
674 const Size aNewSizePix( aNewBound.GetSize() );
675 Bitmap aNewBmp( aNewSizePix, GetBitCount(), &pReadAcc->GetPalette() );
676 BitmapWriteAccess* pWriteAcc = aNewBmp.AcquireWriteAccess();
678 if( pWriteAcc )
680 const BitmapColor aFillColor( pWriteAcc->GetBestMatchingColor( rFillColor ) );
681 const double fCosAngle = cos( nAngle10 * F_PI1800 );
682 const double fSinAngle = sin( nAngle10 * F_PI1800 );
683 const double fXMin = aNewBound.Left();
684 const double fYMin = aNewBound.Top();
685 const long nWidth = aSizePix.Width();
686 const long nHeight = aSizePix.Height();
687 const long nNewWidth = aNewSizePix.Width();
688 const long nNewHeight = aNewSizePix.Height();
689 long nX;
690 long nY;
691 long nRotX;
692 long nRotY;
693 boost::scoped_array<long> pCosX(new long[ nNewWidth ]);
694 boost::scoped_array<long> pSinX(new long[ nNewWidth ]);
695 boost::scoped_array<long> pCosY(new long[ nNewHeight ]);
696 boost::scoped_array<long> pSinY(new long[ nNewHeight ]);
698 for ( nX = 0; nX < nNewWidth; nX++ )
700 const double fTmp = ( fXMin + nX ) * 64.;
702 pCosX[ nX ] = FRound( fCosAngle * fTmp );
703 pSinX[ nX ] = FRound( fSinAngle * fTmp );
706 for ( nY = 0; nY < nNewHeight; nY++ )
708 const double fTmp = ( fYMin + nY ) * 64.;
710 pCosY[ nY ] = FRound( fCosAngle * fTmp );
711 pSinY[ nY ] = FRound( fSinAngle * fTmp );
714 for( nY = 0L; nY < nNewHeight; nY++ )
716 long nSinY = pSinY[ nY ];
717 long nCosY = pCosY[ nY ];
719 for( nX = 0L; nX < nNewWidth; nX++ )
721 nRotX = ( pCosX[ nX ] - nSinY ) >> 6;
722 nRotY = ( pSinX[ nX ] + nCosY ) >> 6;
724 if ( ( nRotX > -1L ) && ( nRotX < nWidth ) && ( nRotY > -1L ) && ( nRotY < nHeight ) )
725 pWriteAcc->SetPixel( nY, nX, pReadAcc->GetPixel( nRotY, nRotX ) );
726 else
727 pWriteAcc->SetPixel( nY, nX, aFillColor );
731 ReleaseAccess( pWriteAcc );
734 aRotatedBmp = aNewBmp;
737 ReleaseAccess( pReadAcc );
740 if( ( bRet = !!aRotatedBmp ) )
741 ImplAssignWithSize( aRotatedBmp );
744 return bRet;
747 bool Bitmap::Crop( const Rectangle& rRectPixel )
749 const Size aSizePix( GetSizePixel() );
750 Rectangle aRect( rRectPixel );
751 bool bRet = false;
753 aRect.Intersection( Rectangle( Point(), aSizePix ) );
755 if( !aRect.IsEmpty() && aSizePix != aRect.GetSize())
757 BitmapReadAccess* pReadAcc = AcquireReadAccess();
759 if( pReadAcc )
761 Point aTmpPoint;
762 const Rectangle aNewRect( aTmpPoint, aRect.GetSize() );
763 Bitmap aNewBmp( aNewRect.GetSize(), GetBitCount(), &pReadAcc->GetPalette() );
764 BitmapWriteAccess* pWriteAcc = aNewBmp.AcquireWriteAccess();
766 if( pWriteAcc )
768 const long nOldX = aRect.Left();
769 const long nOldY = aRect.Top();
770 const long nNewWidth = aNewRect.GetWidth();
771 const long nNewHeight = aNewRect.GetHeight();
773 for( long nY = 0, nY2 = nOldY; nY < nNewHeight; nY++, nY2++ )
774 for( long nX = 0, nX2 = nOldX; nX < nNewWidth; nX++, nX2++ )
775 pWriteAcc->SetPixel( nY, nX, pReadAcc->GetPixel( nY2, nX2 ) );
777 ReleaseAccess( pWriteAcc );
778 bRet = true;
781 ReleaseAccess( pReadAcc );
783 if( bRet )
784 ImplAssignWithSize( aNewBmp );
788 return bRet;
791 bool Bitmap::CopyPixel( const Rectangle& rRectDst,
792 const Rectangle& rRectSrc, const Bitmap* pBmpSrc )
794 const Size aSizePix( GetSizePixel() );
795 Rectangle aRectDst( rRectDst );
796 bool bRet = false;
798 aRectDst.Intersection( Rectangle( Point(), aSizePix ) );
800 if( !aRectDst.IsEmpty() )
802 if( pBmpSrc && ( *pBmpSrc != *this ) )
804 Bitmap* pSrc = const_cast<Bitmap*>(pBmpSrc);
805 const Size aCopySizePix( pSrc->GetSizePixel() );
806 Rectangle aRectSrc( rRectSrc );
807 const sal_uInt16 nSrcBitCount = pBmpSrc->GetBitCount();
808 const sal_uInt16 nDstBitCount = GetBitCount();
810 if( nSrcBitCount > nDstBitCount )
812 long nNextIndex = 0L;
814 if( ( nSrcBitCount == 24 ) && ( nDstBitCount < 24 ) )
815 Convert( BMP_CONVERSION_24BIT );
816 else if( ( nSrcBitCount == 8 ) && ( nDstBitCount < 8 ) )
818 Convert( BMP_CONVERSION_8BIT_COLORS );
819 nNextIndex = 16;
821 else if( ( nSrcBitCount == 4 ) && ( nDstBitCount < 4 ) )
823 Convert( BMP_CONVERSION_4BIT_COLORS );
824 nNextIndex = 2;
827 if( nNextIndex )
829 BitmapReadAccess* pSrcAcc = pSrc->AcquireReadAccess();
830 BitmapWriteAccess* pDstAcc = AcquireWriteAccess();
832 if( pSrcAcc && pDstAcc )
834 const long nSrcCount = pDstAcc->GetPaletteEntryCount();
835 const long nDstCount = 1 << nDstBitCount;
837 for( long i = 0L; ( i < nSrcCount ) && ( nNextIndex < nSrcCount ); i++ )
839 const BitmapColor& rSrcCol = pSrcAcc->GetPaletteColor( (sal_uInt16) i );
841 bool bFound = false;
843 for( long j = 0L; j < nDstCount; j++ )
845 if( rSrcCol == pDstAcc->GetPaletteColor( (sal_uInt16) j ) )
847 bFound = true;
848 break;
852 if( !bFound )
853 pDstAcc->SetPaletteColor( (sal_uInt16) nNextIndex++, rSrcCol );
857 if( pSrcAcc )
858 ReleaseAccess( pSrcAcc );
860 if( pDstAcc )
861 ReleaseAccess( pDstAcc );
865 aRectSrc.Intersection( Rectangle( Point(), aCopySizePix ) );
867 if( !aRectSrc.IsEmpty() )
869 BitmapReadAccess* pReadAcc = pSrc->AcquireReadAccess();
871 if( pReadAcc )
873 BitmapWriteAccess* pWriteAcc = AcquireWriteAccess();
875 if( pWriteAcc )
877 const long nWidth = std::min( aRectSrc.GetWidth(), aRectDst.GetWidth() );
878 const long nHeight = std::min( aRectSrc.GetHeight(), aRectDst.GetHeight() );
879 const long nSrcEndX = aRectSrc.Left() + nWidth;
880 const long nSrcEndY = aRectSrc.Top() + nHeight;
881 long nDstY = aRectDst.Top();
883 if( pReadAcc->HasPalette() && pWriteAcc->HasPalette() )
885 const sal_uInt16 nCount = pReadAcc->GetPaletteEntryCount();
886 boost::scoped_array<sal_uInt8> pMap(new sal_uInt8[ nCount ]);
888 // Create index map for the color table, as the bitmap should be copied
889 // retaining it's color information relatively well
890 for( sal_uInt16 i = 0; i < nCount; i++ )
891 pMap[ i ] = (sal_uInt8) pWriteAcc->GetBestPaletteIndex( pReadAcc->GetPaletteColor( i ) );
893 for( long nSrcY = aRectSrc.Top(); nSrcY < nSrcEndY; nSrcY++, nDstY++ )
894 for( long nSrcX = aRectSrc.Left(), nDstX = aRectDst.Left(); nSrcX < nSrcEndX; nSrcX++, nDstX++ )
895 pWriteAcc->SetPixelIndex( nDstY, nDstX, pMap[ pReadAcc->GetPixelIndex( nSrcY, nSrcX ) ] );
897 else if( pReadAcc->HasPalette() )
899 for( long nSrcY = aRectSrc.Top(); nSrcY < nSrcEndY; nSrcY++, nDstY++ )
900 for( long nSrcX = aRectSrc.Left(), nDstX = aRectDst.Left(); nSrcX < nSrcEndX; nSrcX++, nDstX++ )
901 pWriteAcc->SetPixel( nDstY, nDstX, pReadAcc->GetPaletteColor( pReadAcc->GetPixelIndex( nSrcY, nSrcX ) ) );
903 else
904 for( long nSrcY = aRectSrc.Top(); nSrcY < nSrcEndY; nSrcY++, nDstY++ )
905 for( long nSrcX = aRectSrc.Left(), nDstX = aRectDst.Left(); nSrcX < nSrcEndX; nSrcX++, nDstX++ )
906 pWriteAcc->SetPixel( nDstY, nDstX, pReadAcc->GetPixel( nSrcY, nSrcX ) );
908 ReleaseAccess( pWriteAcc );
909 bRet = ( nWidth > 0L ) && ( nHeight > 0L );
912 ReleaseAccess( pReadAcc );
916 else
918 Rectangle aRectSrc( rRectSrc );
920 aRectSrc.Intersection( Rectangle( Point(), aSizePix ) );
922 if( !aRectSrc.IsEmpty() && ( aRectSrc != aRectDst ) )
924 BitmapWriteAccess* pWriteAcc = AcquireWriteAccess();
926 if( pWriteAcc )
928 const long nWidth = std::min( aRectSrc.GetWidth(), aRectDst.GetWidth() );
929 const long nHeight = std::min( aRectSrc.GetHeight(), aRectDst.GetHeight() );
930 const long nSrcX = aRectSrc.Left();
931 const long nSrcY = aRectSrc.Top();
932 const long nSrcEndX1 = nSrcX + nWidth - 1L;
933 const long nSrcEndY1 = nSrcY + nHeight - 1L;
934 const long nDstX = aRectDst.Left();
935 const long nDstY = aRectDst.Top();
936 const long nDstEndX1 = nDstX + nWidth - 1L;
937 const long nDstEndY1 = nDstY + nHeight - 1L;
939 if( ( nDstX <= nSrcX ) && ( nDstY <= nSrcY ) )
941 for( long nY = nSrcY, nYN = nDstY; nY <= nSrcEndY1; nY++, nYN++ )
942 for( long nX = nSrcX, nXN = nDstX; nX <= nSrcEndX1; nX++, nXN++ )
943 pWriteAcc->SetPixel( nYN, nXN, pWriteAcc->GetPixel( nY, nX ) );
945 else if( ( nDstX <= nSrcX ) && ( nDstY >= nSrcY ) )
947 for( long nY = nSrcEndY1, nYN = nDstEndY1; nY >= nSrcY; nY--, nYN-- )
948 for( long nX = nSrcX, nXN = nDstX; nX <= nSrcEndX1; nX++, nXN++ )
949 pWriteAcc->SetPixel( nYN, nXN, pWriteAcc->GetPixel( nY, nX ) );
951 else if( ( nDstX >= nSrcX ) && ( nDstY <= nSrcY ) )
953 for( long nY = nSrcY, nYN = nDstY; nY <= nSrcEndY1; nY++, nYN++ )
954 for( long nX = nSrcEndX1, nXN = nDstEndX1; nX >= nSrcX; nX--, nXN-- )
955 pWriteAcc->SetPixel( nYN, nXN, pWriteAcc->GetPixel( nY, nX ) );
957 else
959 for( long nY = nSrcEndY1, nYN = nDstEndY1; nY >= nSrcY; nY--, nYN-- )
960 for( long nX = nSrcEndX1, nXN = nDstEndX1; nX >= nSrcX; nX--, nXN-- )
961 pWriteAcc->SetPixel( nYN, nXN, pWriteAcc->GetPixel( nY, nX ) );
964 ReleaseAccess( pWriteAcc );
965 bRet = true;
971 return bRet;
974 bool Bitmap::CopyPixel_AlphaOptimized( const Rectangle& rRectDst, const Rectangle& rRectSrc,
975 const Bitmap* pBmpSrc )
977 // Note: this code is copied from Bitmap::CopyPixel but avoids any palette lookups
978 // This optimization is possible because the palettes of AlphaMasks are always identical (8bit GreyPalette, see ctor)
979 const Size aSizePix( GetSizePixel() );
980 Rectangle aRectDst( rRectDst );
981 bool bRet = false;
983 aRectDst.Intersection( Rectangle( Point(), aSizePix ) );
985 if( !aRectDst.IsEmpty() )
987 if( pBmpSrc && ( *pBmpSrc != *this ) )
989 Bitmap* pSrc = const_cast<Bitmap*>(pBmpSrc);
990 const Size aCopySizePix( pSrc->GetSizePixel() );
991 Rectangle aRectSrc( rRectSrc );
993 aRectSrc.Intersection( Rectangle( Point(), aCopySizePix ) );
995 if( !aRectSrc.IsEmpty() )
997 BitmapReadAccess* pReadAcc = pSrc->AcquireReadAccess();
999 if( pReadAcc )
1001 BitmapWriteAccess* pWriteAcc = AcquireWriteAccess();
1003 if( pWriteAcc )
1005 const long nWidth = std::min( aRectSrc.GetWidth(), aRectDst.GetWidth() );
1006 const long nHeight = std::min( aRectSrc.GetHeight(), aRectDst.GetHeight() );
1007 const long nSrcEndX = aRectSrc.Left() + nWidth;
1008 const long nSrcEndY = aRectSrc.Top() + nHeight;
1009 long nDstY = aRectDst.Top();
1011 for( long nSrcY = aRectSrc.Top(); nSrcY < nSrcEndY; nSrcY++, nDstY++ )
1012 for( long nSrcX = aRectSrc.Left(), nDstX = aRectDst.Left(); nSrcX < nSrcEndX; nSrcX++, nDstX++ )
1013 pWriteAcc->SetPixel( nDstY, nDstX, pReadAcc->GetPixel( nSrcY, nSrcX ) );
1015 ReleaseAccess( pWriteAcc );
1016 bRet = ( nWidth > 0L ) && ( nHeight > 0L );
1019 ReleaseAccess( pReadAcc );
1023 else
1025 Rectangle aRectSrc( rRectSrc );
1027 aRectSrc.Intersection( Rectangle( Point(), aSizePix ) );
1029 if( !aRectSrc.IsEmpty() && ( aRectSrc != aRectDst ) )
1031 BitmapWriteAccess* pWriteAcc = AcquireWriteAccess();
1033 if( pWriteAcc )
1035 const long nWidth = std::min( aRectSrc.GetWidth(), aRectDst.GetWidth() );
1036 const long nHeight = std::min( aRectSrc.GetHeight(), aRectDst.GetHeight() );
1037 const long nSrcX = aRectSrc.Left();
1038 const long nSrcY = aRectSrc.Top();
1039 const long nSrcEndX1 = nSrcX + nWidth - 1L;
1040 const long nSrcEndY1 = nSrcY + nHeight - 1L;
1041 const long nDstX = aRectDst.Left();
1042 const long nDstY = aRectDst.Top();
1043 const long nDstEndX1 = nDstX + nWidth - 1L;
1044 const long nDstEndY1 = nDstY + nHeight - 1L;
1046 if( ( nDstX <= nSrcX ) && ( nDstY <= nSrcY ) )
1048 for( long nY = nSrcY, nYN = nDstY; nY <= nSrcEndY1; nY++, nYN++ )
1049 for( long nX = nSrcX, nXN = nDstX; nX <= nSrcEndX1; nX++, nXN++ )
1050 pWriteAcc->SetPixel( nYN, nXN, pWriteAcc->GetPixel( nY, nX ) );
1052 else if( ( nDstX <= nSrcX ) && ( nDstY >= nSrcY ) )
1054 for( long nY = nSrcEndY1, nYN = nDstEndY1; nY >= nSrcY; nY--, nYN-- )
1055 for( long nX = nSrcX, nXN = nDstX; nX <= nSrcEndX1; nX++, nXN++ )
1056 pWriteAcc->SetPixel( nYN, nXN, pWriteAcc->GetPixel( nY, nX ) );
1058 else if( ( nDstX >= nSrcX ) && ( nDstY <= nSrcY ) )
1060 for( long nY = nSrcY, nYN = nDstY; nY <= nSrcEndY1; nY++, nYN++ )
1061 for( long nX = nSrcEndX1, nXN = nDstEndX1; nX >= nSrcX; nX--, nXN-- )
1062 pWriteAcc->SetPixel( nYN, nXN, pWriteAcc->GetPixel( nY, nX ) );
1064 else
1066 for( long nY = nSrcEndY1, nYN = nDstEndY1; nY >= nSrcY; nY--, nYN-- )
1067 for( long nX = nSrcEndX1, nXN = nDstEndX1; nX >= nSrcX; nX--, nXN-- )
1068 pWriteAcc->SetPixel( nYN, nXN, pWriteAcc->GetPixel( nY, nX ) );
1071 ReleaseAccess( pWriteAcc );
1072 bRet = true;
1078 return bRet;
1082 bool Bitmap::Expand( sal_uLong nDX, sal_uLong nDY, const Color* pInitColor )
1084 bool bRet = false;
1086 if( nDX || nDY )
1088 const Size aSizePixel( GetSizePixel() );
1089 const long nWidth = aSizePixel.Width();
1090 const long nHeight = aSizePixel.Height();
1091 const Size aNewSize( nWidth + nDX, nHeight + nDY );
1092 BitmapReadAccess* pReadAcc = AcquireReadAccess();
1094 if( pReadAcc )
1096 BitmapPalette aBmpPal( pReadAcc->GetPalette() );
1097 Bitmap aNewBmp( aNewSize, GetBitCount(), &aBmpPal );
1098 BitmapWriteAccess* pWriteAcc = aNewBmp.AcquireWriteAccess();
1100 if( pWriteAcc )
1102 BitmapColor aColor;
1103 const long nNewX = nWidth;
1104 const long nNewY = nHeight;
1105 const long nNewWidth = pWriteAcc->Width();
1106 const long nNewHeight = pWriteAcc->Height();
1107 long nX;
1108 long nY;
1110 if( pInitColor )
1111 aColor = pWriteAcc->GetBestMatchingColor( *pInitColor );
1113 for( nY = 0L; nY < nHeight; nY++ )
1115 pWriteAcc->CopyScanline( nY, *pReadAcc );
1117 if( pInitColor && nDX )
1118 for( nX = nNewX; nX < nNewWidth; nX++ )
1119 pWriteAcc->SetPixel( nY, nX, aColor );
1122 if( pInitColor && nDY )
1123 for( nY = nNewY; nY < nNewHeight; nY++ )
1124 for( nX = 0; nX < nNewWidth; nX++ )
1125 pWriteAcc->SetPixel( nY, nX, aColor );
1127 ReleaseAccess( pWriteAcc );
1128 bRet = true;
1131 ReleaseAccess( pReadAcc );
1133 if( bRet )
1134 ImplAssignWithSize( aNewBmp );
1138 return bRet;
1141 Bitmap Bitmap::CreateMask( const Color& rTransColor, sal_uLong nTol ) const
1143 Bitmap aNewBmp( GetSizePixel(), 1 );
1144 BitmapWriteAccess* pWriteAcc = aNewBmp.AcquireWriteAccess();
1145 bool bRet = false;
1147 if( pWriteAcc )
1149 BitmapReadAccess* pReadAcc = const_cast<Bitmap*>(this)->AcquireReadAccess();
1151 if( pReadAcc )
1153 const long nWidth = pReadAcc->Width();
1154 const long nHeight = pReadAcc->Height();
1155 const BitmapColor aBlack( pWriteAcc->GetBestMatchingColor( Color( COL_BLACK ) ) );
1156 const BitmapColor aWhite( pWriteAcc->GetBestMatchingColor( Color( COL_WHITE ) ) );
1158 if( !nTol )
1160 const BitmapColor aTest( pReadAcc->GetBestMatchingColor( rTransColor ) );
1161 long nX, nY;
1163 if( pReadAcc->GetScanlineFormat() == BMP_FORMAT_4BIT_MSN_PAL ||
1164 pReadAcc->GetScanlineFormat() == BMP_FORMAT_4BIT_LSN_PAL )
1166 // optimized for 4Bit-MSN/LSN source palette
1167 const sal_uInt8 cTest = aTest.GetIndex();
1168 const long nShiftInit = ( ( pReadAcc->GetScanlineFormat() == BMP_FORMAT_4BIT_MSN_PAL ) ? 4 : 0 );
1170 if( pWriteAcc->GetScanlineFormat() == BMP_FORMAT_1BIT_MSB_PAL &&
1171 aWhite.GetIndex() == 1 )
1173 // optimized for 1Bit-MSB destination palette
1174 for( nY = 0L; nY < nHeight; nY++ )
1176 Scanline pSrc = pReadAcc->GetScanline( nY );
1177 Scanline pDst = pWriteAcc->GetScanline( nY );
1178 long nShift = 0;
1179 for( nX = 0L, nShift = nShiftInit; nX < nWidth; nX++, nShift ^= 4 )
1181 if( cTest == ( ( pSrc[ nX >> 1 ] >> nShift ) & 0x0f ) )
1182 pDst[ nX >> 3 ] |= 1 << ( 7 - ( nX & 7 ) );
1183 else
1184 pDst[ nX >> 3 ] &= ~( 1 << ( 7 - ( nX & 7 ) ) );
1188 else
1190 for( nY = 0L; nY < nHeight; nY++ )
1192 Scanline pSrc = pReadAcc->GetScanline( nY );
1193 long nShift = 0;
1194 for( nX = 0L, nShift = nShiftInit; nX < nWidth; nX++, nShift ^= 4 )
1196 if( cTest == ( ( pSrc[ nX >> 1 ] >> nShift ) & 0x0f ) )
1197 pWriteAcc->SetPixel( nY, nX, aWhite );
1198 else
1199 pWriteAcc->SetPixel( nY, nX, aBlack );
1204 else if( pReadAcc->GetScanlineFormat() == BMP_FORMAT_8BIT_PAL )
1206 // optimized for 8Bit source palette
1207 const sal_uInt8 cTest = aTest.GetIndex();
1209 if( pWriteAcc->GetScanlineFormat() == BMP_FORMAT_1BIT_MSB_PAL &&
1210 aWhite.GetIndex() == 1 )
1212 // optimized for 1Bit-MSB destination palette
1213 for( nY = 0L; nY < nHeight; nY++ )
1215 Scanline pSrc = pReadAcc->GetScanline( nY );
1216 Scanline pDst = pWriteAcc->GetScanline( nY );
1217 for( nX = 0L; nX < nWidth; nX++ )
1219 if( cTest == pSrc[ nX ] )
1220 pDst[ nX >> 3 ] |= 1 << ( 7 - ( nX & 7 ) );
1221 else
1222 pDst[ nX >> 3 ] &= ~( 1 << ( 7 - ( nX & 7 ) ) );
1226 else
1228 for( nY = 0L; nY < nHeight; nY++ )
1230 Scanline pSrc = pReadAcc->GetScanline( nY );
1231 for( nX = 0L; nX < nWidth; nX++ )
1233 if( cTest == pSrc[ nX ] )
1234 pWriteAcc->SetPixel( nY, nX, aWhite );
1235 else
1236 pWriteAcc->SetPixel( nY, nX, aBlack );
1241 else
1243 // not optimized
1244 for( nY = 0L; nY < nHeight; nY++ )
1246 for( nX = 0L; nX < nWidth; nX++ )
1248 if( aTest == pReadAcc->GetPixel( nY, nX ) )
1249 pWriteAcc->SetPixel( nY, nX, aWhite );
1250 else
1251 pWriteAcc->SetPixel( nY, nX, aBlack );
1256 else
1258 BitmapColor aCol;
1259 long nR, nG, nB;
1260 const long nMinR = MinMax( (long) rTransColor.GetRed() - nTol, 0, 255 );
1261 const long nMaxR = MinMax( (long) rTransColor.GetRed() + nTol, 0, 255 );
1262 const long nMinG = MinMax( (long) rTransColor.GetGreen() - nTol, 0, 255 );
1263 const long nMaxG = MinMax( (long) rTransColor.GetGreen() + nTol, 0, 255 );
1264 const long nMinB = MinMax( (long) rTransColor.GetBlue() - nTol, 0, 255 );
1265 const long nMaxB = MinMax( (long) rTransColor.GetBlue() + nTol, 0, 255 );
1267 if( pReadAcc->HasPalette() )
1269 for( long nY = 0L; nY < nHeight; nY++ )
1271 for( long nX = 0L; nX < nWidth; nX++ )
1273 aCol = pReadAcc->GetPaletteColor( pReadAcc->GetPixelIndex( nY, nX ) );
1274 nR = aCol.GetRed();
1275 nG = aCol.GetGreen();
1276 nB = aCol.GetBlue();
1278 if( nMinR <= nR && nMaxR >= nR &&
1279 nMinG <= nG && nMaxG >= nG &&
1280 nMinB <= nB && nMaxB >= nB )
1282 pWriteAcc->SetPixel( nY, nX, aWhite );
1284 else
1285 pWriteAcc->SetPixel( nY, nX, aBlack );
1289 else
1291 for( long nY = 0L; nY < nHeight; nY++ )
1293 for( long nX = 0L; nX < nWidth; nX++ )
1295 aCol = pReadAcc->GetPixel( nY, nX );
1296 nR = aCol.GetRed();
1297 nG = aCol.GetGreen();
1298 nB = aCol.GetBlue();
1300 if( nMinR <= nR && nMaxR >= nR &&
1301 nMinG <= nG && nMaxG >= nG &&
1302 nMinB <= nB && nMaxB >= nB )
1304 pWriteAcc->SetPixel( nY, nX, aWhite );
1306 else
1307 pWriteAcc->SetPixel( nY, nX, aBlack );
1313 ReleaseAccess( pReadAcc );
1314 bRet = true;
1317 ReleaseAccess( pWriteAcc );
1320 if( bRet )
1322 aNewBmp.maPrefSize = maPrefSize;
1323 aNewBmp.maPrefMapMode = maPrefMapMode;
1325 else
1326 aNewBmp = Bitmap();
1328 return aNewBmp;
1331 vcl::Region Bitmap::CreateRegion( const Color& rColor, const Rectangle& rRect ) const
1333 vcl::Region aRegion;
1334 Rectangle aRect( rRect );
1335 BitmapReadAccess* pReadAcc = const_cast<Bitmap*>(this)->AcquireReadAccess();
1337 aRect.Intersection( Rectangle( Point(), GetSizePixel() ) );
1338 aRect.Justify();
1340 if( pReadAcc )
1342 //Rectangle aSubRect;
1343 const long nLeft = aRect.Left();
1344 const long nTop = aRect.Top();
1345 const long nRight = aRect.Right();
1346 const long nBottom = aRect.Bottom();
1347 const BitmapColor aMatch( pReadAcc->GetBestMatchingColor( rColor ) );
1349 //RectangleVector aRectangles;
1350 //aRegion.ImplBeginAddRect();
1351 std::vector< long > aLine;
1352 long nYStart(nTop);
1353 long nY(nTop);
1355 for( ; nY <= nBottom; nY++ )
1357 //aSubRect.Top() = aSubRect.Bottom() = nY;
1358 std::vector< long > aNewLine;
1359 long nX(nLeft);
1361 for( ; nX <= nRight; )
1363 while( ( nX <= nRight ) && ( aMatch != pReadAcc->GetPixel( nY, nX ) ) )
1364 nX++;
1366 if( nX <= nRight )
1368 aNewLine.push_back(nX);
1369 //aSubRect.Left() = nX;
1371 while( ( nX <= nRight ) && ( aMatch == pReadAcc->GetPixel( nY, nX ) ) )
1372 nX++;
1374 //aSubRect.Right() = nX - 1L;
1375 aNewLine.push_back(nX - 1);
1377 //aRegion.ImplAddRect( aSubRect );
1378 //aRectangles.push_back(aSubRect);
1379 //aRegion.Union(aSubRect);
1383 if(aNewLine != aLine)
1385 // need to write aLine, it's different from the next line
1386 if(aLine.size())
1388 Rectangle aSubRect;
1390 // enter y values and proceed ystart
1391 aSubRect.Top() = nYStart;
1392 aSubRect.Bottom() = nY ? nY - 1 : 0;
1394 for(sal_uInt32 a(0); a < aLine.size();)
1396 aSubRect.Left() = aLine[a++];
1397 aSubRect.Right() = aLine[a++];
1398 aRegion.Union(aSubRect);
1402 // copy line as new line
1403 aLine = aNewLine;
1404 nYStart = nY;
1408 // write last line if used
1409 if(aLine.size())
1411 Rectangle aSubRect;
1413 // enter y values
1414 aSubRect.Top() = nYStart;
1415 aSubRect.Bottom() = nY ? nY - 1 : 0;
1417 for(sal_uInt32 a(0); a < aLine.size();)
1419 aSubRect.Left() = aLine[a++];
1420 aSubRect.Right() = aLine[a++];
1421 aRegion.Union(aSubRect);
1425 //aRegion.ImplEndAddRect();
1426 //aRegion.SetRegionRectangles(aRectangles);
1428 ReleaseAccess( pReadAcc );
1430 else
1431 aRegion = aRect;
1433 return aRegion;
1436 bool Bitmap::Replace( const Bitmap& rMask, const Color& rReplaceColor )
1438 BitmapReadAccess* pMaskAcc = ( (Bitmap&) rMask ).AcquireReadAccess();
1439 BitmapWriteAccess* pAcc = AcquireWriteAccess();
1440 bool bRet = false;
1442 if( pMaskAcc && pAcc )
1444 const long nWidth = std::min( pMaskAcc->Width(), pAcc->Width() );
1445 const long nHeight = std::min( pMaskAcc->Height(), pAcc->Height() );
1446 const BitmapColor aMaskWhite( pMaskAcc->GetBestMatchingColor( Color( COL_WHITE ) ) );
1447 BitmapColor aReplace;
1449 if( pAcc->HasPalette() )
1451 const sal_uInt16 nActColors = pAcc->GetPaletteEntryCount();
1452 const sal_uInt16 nMaxColors = 1 << pAcc->GetBitCount();
1454 // default to the nearest color
1455 aReplace = pAcc->GetBestMatchingColor( rReplaceColor );
1457 // for paletted images without a matching palette entry
1458 // look for an unused palette entry (NOTE: expensive!)
1459 if( pAcc->GetPaletteColor( aReplace.GetIndex() ) != BitmapColor( rReplaceColor ) )
1461 // if the palette has empty entries use the last one
1462 if( nActColors < nMaxColors )
1464 pAcc->SetPaletteEntryCount( nActColors + 1 );
1465 pAcc->SetPaletteColor( nActColors, rReplaceColor );
1466 aReplace = BitmapColor( (sal_uInt8) nActColors );
1468 else
1470 boost::scoped_array<bool> pFlags(new bool[ nMaxColors ]);
1472 // Set all entries to false
1473 std::fill( pFlags.get(), pFlags.get()+nMaxColors, false );
1475 for( long nY = 0L; nY < nHeight; nY++ )
1476 for( long nX = 0L; nX < nWidth; nX++ )
1477 pFlags[ pAcc->GetPixelIndex( nY, nX ) ] = true;
1479 for( sal_uInt16 i = 0UL; i < nMaxColors; i++ )
1481 // Hurray, we do have an unsused entry
1482 if( !pFlags[ i ] )
1484 pAcc->SetPaletteColor( (sal_uInt16) i, rReplaceColor );
1485 aReplace = BitmapColor( (sal_uInt8) i );
1491 else
1492 aReplace = rReplaceColor;
1494 for( long nY = 0L; nY < nHeight; nY++ )
1495 for( long nX = 0L; nX < nWidth; nX++ )
1496 if( pMaskAcc->GetPixel( nY, nX ) == aMaskWhite )
1497 pAcc->SetPixel( nY, nX, aReplace );
1499 bRet = true;
1502 ReleaseAccess( pMaskAcc );
1503 ReleaseAccess( pAcc );
1505 return bRet;
1508 bool Bitmap::Replace( const AlphaMask& rAlpha, const Color& rMergeColor )
1510 Bitmap aNewBmp( GetSizePixel(), 24 );
1511 BitmapReadAccess* pAcc = AcquireReadAccess();
1512 BitmapReadAccess* pAlphaAcc = ( (AlphaMask&) rAlpha ).AcquireReadAccess();
1513 BitmapWriteAccess* pNewAcc = aNewBmp.AcquireWriteAccess();
1514 bool bRet = false;
1516 if( pAcc && pAlphaAcc && pNewAcc )
1518 BitmapColor aCol;
1519 const long nWidth = std::min( pAlphaAcc->Width(), pAcc->Width() );
1520 const long nHeight = std::min( pAlphaAcc->Height(), pAcc->Height() );
1522 for( long nY = 0L; nY < nHeight; nY++ )
1524 for( long nX = 0L; nX < nWidth; nX++ )
1526 aCol = pAcc->GetColor( nY, nX );
1527 pNewAcc->SetPixel( nY, nX, aCol.Merge( rMergeColor, 255 - pAlphaAcc->GetPixelIndex( nY, nX ) ) );
1531 bRet = true;
1534 ReleaseAccess( pAcc );
1535 ReleaseAccess( pAlphaAcc );
1536 ReleaseAccess( pNewAcc );
1538 if( bRet )
1540 const MapMode aMap( maPrefMapMode );
1541 const Size aSize( maPrefSize );
1543 *this = aNewBmp;
1545 maPrefMapMode = aMap;
1546 maPrefSize = aSize;
1549 return bRet;
1552 bool Bitmap::Replace( const Color& rSearchColor, const Color& rReplaceColor, sal_uLong nTol )
1554 if( mpImpBmp )
1556 // implementation specific replace
1557 ImpBitmap* pImpBmp = new ImpBitmap;
1559 if( pImpBmp->ImplCreate( *mpImpBmp ) && pImpBmp->ImplReplace( rSearchColor, rReplaceColor, nTol ) )
1561 ImplSetImpBitmap( pImpBmp );
1562 maPrefMapMode = MapMode( MAP_PIXEL );
1563 maPrefSize = pImpBmp->ImplGetSize();
1564 return true;
1566 else
1568 delete pImpBmp;
1572 // Bitmaps with 1 bit color depth can cause problems
1573 // if they have other entries than black/white in their palette
1574 if( 1 == GetBitCount() )
1575 Convert( BMP_CONVERSION_4BIT_COLORS );
1577 BitmapWriteAccess* pAcc = AcquireWriteAccess();
1578 bool bRet = false;
1580 if( pAcc )
1582 const long nMinR = MinMax( (long) rSearchColor.GetRed() - nTol, 0, 255 );
1583 const long nMaxR = MinMax( (long) rSearchColor.GetRed() + nTol, 0, 255 );
1584 const long nMinG = MinMax( (long) rSearchColor.GetGreen() - nTol, 0, 255 );
1585 const long nMaxG = MinMax( (long) rSearchColor.GetGreen() + nTol, 0, 255 );
1586 const long nMinB = MinMax( (long) rSearchColor.GetBlue() - nTol, 0, 255 );
1587 const long nMaxB = MinMax( (long) rSearchColor.GetBlue() + nTol, 0, 255 );
1589 if( pAcc->HasPalette() )
1591 for( sal_uInt16 i = 0, nPalCount = pAcc->GetPaletteEntryCount(); i < nPalCount; i++ )
1593 const BitmapColor& rCol = pAcc->GetPaletteColor( i );
1595 if( nMinR <= rCol.GetRed() && nMaxR >= rCol.GetRed() &&
1596 nMinG <= rCol.GetGreen() && nMaxG >= rCol.GetGreen() &&
1597 nMinB <= rCol.GetBlue() && nMaxB >= rCol.GetBlue() )
1599 pAcc->SetPaletteColor( i, rReplaceColor );
1603 else
1605 BitmapColor aCol;
1606 const BitmapColor aReplace( pAcc->GetBestMatchingColor( rReplaceColor ) );
1608 for( long nY = 0L, nHeight = pAcc->Height(); nY < nHeight; nY++ )
1610 for( long nX = 0L, nWidth = pAcc->Width(); nX < nWidth; nX++ )
1612 aCol = pAcc->GetPixel( nY, nX );
1614 if( nMinR <= aCol.GetRed() && nMaxR >= aCol.GetRed() &&
1615 nMinG <= aCol.GetGreen() && nMaxG >= aCol.GetGreen() &&
1616 nMinB <= aCol.GetBlue() && nMaxB >= aCol.GetBlue() )
1618 pAcc->SetPixel( nY, nX, aReplace );
1624 ReleaseAccess( pAcc );
1625 bRet = true;
1628 return bRet;
1631 bool Bitmap::Replace( const Color* pSearchColors, const Color* pReplaceColors,
1632 sal_uLong nColorCount, sal_uLong* _pTols )
1634 // Bitmaps with 1 bit color depth can cause problems
1635 // if they have other entries than black/white in their palette
1636 if( 1 == GetBitCount() )
1637 Convert( BMP_CONVERSION_4BIT_COLORS );
1639 BitmapWriteAccess* pAcc = AcquireWriteAccess();
1640 bool bRet = false;
1642 if( pAcc )
1644 boost::scoped_array<long> pMinR(new long[ nColorCount ]);
1645 boost::scoped_array<long> pMaxR(new long[ nColorCount ]);
1646 boost::scoped_array<long> pMinG(new long[ nColorCount ]);
1647 boost::scoped_array<long> pMaxG(new long[ nColorCount ]);
1648 boost::scoped_array<long> pMinB(new long[ nColorCount ]);
1649 boost::scoped_array<long> pMaxB(new long[ nColorCount ]);
1650 long* pTols;
1651 sal_uLong i;
1653 if( !_pTols )
1655 pTols = new long[ nColorCount ];
1656 memset( pTols, 0, nColorCount * sizeof( long ) );
1658 else
1659 pTols = reinterpret_cast<long*>(_pTols);
1661 for( i = 0UL; i < nColorCount; i++ )
1663 const Color& rCol = pSearchColors[ i ];
1664 const long nTol = pTols[ i ];
1666 pMinR[ i ] = MinMax( (long) rCol.GetRed() - nTol, 0, 255 );
1667 pMaxR[ i ] = MinMax( (long) rCol.GetRed() + nTol, 0, 255 );
1668 pMinG[ i ] = MinMax( (long) rCol.GetGreen() - nTol, 0, 255 );
1669 pMaxG[ i ] = MinMax( (long) rCol.GetGreen() + nTol, 0, 255 );
1670 pMinB[ i ] = MinMax( (long) rCol.GetBlue() - nTol, 0, 255 );
1671 pMaxB[ i ] = MinMax( (long) rCol.GetBlue() + nTol, 0, 255 );
1674 if( pAcc->HasPalette() )
1676 for( sal_uInt16 nEntry = 0, nPalCount = pAcc->GetPaletteEntryCount(); nEntry < nPalCount; nEntry++ )
1678 const BitmapColor& rCol = pAcc->GetPaletteColor( nEntry );
1680 for( i = 0UL; i < nColorCount; i++ )
1682 if( pMinR[ i ] <= rCol.GetRed() && pMaxR[ i ] >= rCol.GetRed() &&
1683 pMinG[ i ] <= rCol.GetGreen() && pMaxG[ i ] >= rCol.GetGreen() &&
1684 pMinB[ i ] <= rCol.GetBlue() && pMaxB[ i ] >= rCol.GetBlue() )
1686 pAcc->SetPaletteColor( (sal_uInt16)nEntry, pReplaceColors[ i ] );
1687 break;
1692 else
1694 BitmapColor aCol;
1695 boost::scoped_array<BitmapColor> pReplaces(new BitmapColor[ nColorCount ]);
1697 for( i = 0UL; i < nColorCount; i++ )
1698 pReplaces[ i ] = pAcc->GetBestMatchingColor( pReplaceColors[ i ] );
1700 for( long nY = 0L, nHeight = pAcc->Height(); nY < nHeight; nY++ )
1702 for( long nX = 0L, nWidth = pAcc->Width(); nX < nWidth; nX++ )
1704 aCol = pAcc->GetPixel( nY, nX );
1706 for( i = 0UL; i < nColorCount; i++ )
1708 if( pMinR[ i ] <= aCol.GetRed() && pMaxR[ i ] >= aCol.GetRed() &&
1709 pMinG[ i ] <= aCol.GetGreen() && pMaxG[ i ] >= aCol.GetGreen() &&
1710 pMinB[ i ] <= aCol.GetBlue() && pMaxB[ i ] >= aCol.GetBlue() )
1712 pAcc->SetPixel( nY, nX, pReplaces[ i ] );
1713 break;
1720 if( !_pTols )
1721 delete[] pTols;
1723 ReleaseAccess( pAcc );
1724 bRet = true;
1727 return bRet;
1730 Bitmap Bitmap::CreateDisplayBitmap( OutputDevice* pDisplay )
1732 Bitmap aDispBmp( *this );
1734 SalGraphics* pDispGraphics = pDisplay->GetGraphics();
1736 if( mpImpBmp && pDispGraphics )
1738 ImpBitmap* pImpDispBmp = new ImpBitmap;
1740 if( pImpDispBmp->ImplCreate( *mpImpBmp, pDispGraphics ) )
1741 aDispBmp.ImplSetImpBitmap( pImpDispBmp );
1742 else
1743 delete pImpDispBmp;
1746 return aDispBmp;
1749 bool Bitmap::CombineSimple( const Bitmap& rMask, BmpCombine eCombine )
1751 BitmapReadAccess* pMaskAcc = ( (Bitmap&) rMask ).AcquireReadAccess();
1752 BitmapWriteAccess* pAcc = AcquireWriteAccess();
1753 bool bRet = false;
1755 if( pMaskAcc && pAcc )
1757 const long nWidth = std::min( pMaskAcc->Width(), pAcc->Width() );
1758 const long nHeight = std::min( pMaskAcc->Height(), pAcc->Height() );
1759 const Color aColBlack( COL_BLACK );
1760 BitmapColor aPixel;
1761 BitmapColor aMaskPixel;
1762 const BitmapColor aWhite( pAcc->GetBestMatchingColor( Color( COL_WHITE ) ) );
1763 const BitmapColor aBlack( pAcc->GetBestMatchingColor( aColBlack ) );
1764 const BitmapColor aMaskBlack( pMaskAcc->GetBestMatchingColor( aColBlack ) );
1766 switch( eCombine )
1768 case( BMP_COMBINE_COPY ):
1770 for( long nY = 0L; nY < nHeight; nY++ ) for( long nX = 0L; nX < nWidth; nX++ )
1772 if( pMaskAcc->GetPixel( nY, nX ) == aMaskBlack )
1773 pAcc->SetPixel( nY, nX, aBlack );
1774 else
1775 pAcc->SetPixel( nY, nX, aWhite );
1778 break;
1780 case( BMP_COMBINE_INVERT ):
1782 for( long nY = 0L; nY < nHeight; nY++ ) for( long nX = 0L; nX < nWidth; nX++ )
1784 if( pAcc->GetPixel( nY, nX ) == aBlack )
1785 pAcc->SetPixel( nY, nX, aWhite );
1786 else
1787 pAcc->SetPixel( nY, nX, aBlack );
1790 break;
1792 case( BMP_COMBINE_AND ):
1794 for( long nY = 0L; nY < nHeight; nY++ ) for( long nX = 0L; nX < nWidth; nX++ )
1796 if( pMaskAcc->GetPixel( nY, nX ) != aMaskBlack && pAcc->GetPixel( nY, nX ) != aBlack )
1797 pAcc->SetPixel( nY, nX, aWhite );
1798 else
1799 pAcc->SetPixel( nY, nX, aBlack );
1802 break;
1804 case( BMP_COMBINE_NAND ):
1806 for( long nY = 0L; nY < nHeight; nY++ ) for( long nX = 0L; nX < nWidth; nX++ )
1808 if( pMaskAcc->GetPixel( nY, nX ) != aMaskBlack && pAcc->GetPixel( nY, nX ) != aBlack )
1809 pAcc->SetPixel( nY, nX, aBlack );
1810 else
1811 pAcc->SetPixel( nY, nX, aWhite );
1814 break;
1816 case( BMP_COMBINE_OR ):
1818 for( long nY = 0L; nY < nHeight; nY++ ) for( long nX = 0L; nX < nWidth; nX++ )
1820 if( pMaskAcc->GetPixel( nY, nX ) != aMaskBlack || pAcc->GetPixel( nY, nX ) != aBlack )
1821 pAcc->SetPixel( nY, nX, aWhite );
1822 else
1823 pAcc->SetPixel( nY, nX, aBlack );
1826 break;
1828 case( BMP_COMBINE_NOR ):
1830 for( long nY = 0L; nY < nHeight; nY++ ) for( long nX = 0L; nX < nWidth; nX++ )
1832 if( pMaskAcc->GetPixel( nY, nX ) != aMaskBlack || pAcc->GetPixel( nY, nX ) != aBlack )
1833 pAcc->SetPixel( nY, nX, aBlack );
1834 else
1835 pAcc->SetPixel( nY, nX, aWhite );
1838 break;
1840 case( BMP_COMBINE_XOR ):
1842 for( long nY = 0L; nY < nHeight; nY++ ) for( long nX = 0L; nX < nWidth; nX++ )
1844 aPixel = pAcc->GetPixel( nY, nX );
1845 aMaskPixel = pMaskAcc->GetPixel( nY, nX );
1847 if( ( aMaskPixel != aMaskBlack && aPixel == aBlack ) ||
1848 ( aMaskPixel == aMaskBlack && aPixel != aBlack ) )
1850 pAcc->SetPixel( nY, nX, aWhite );
1852 else
1853 pAcc->SetPixel( nY, nX, aBlack );
1856 break;
1858 case( BMP_COMBINE_NXOR ):
1860 for( long nY = 0L; nY < nHeight; nY++ ) for( long nX = 0L; nX < nWidth; nX++ )
1862 aPixel = pAcc->GetPixel( nY, nX );
1863 aMaskPixel = pMaskAcc->GetPixel( nY, nX );
1865 if( ( aMaskPixel != aMaskBlack && aPixel == aBlack ) ||
1866 ( aMaskPixel == aMaskBlack && aPixel != aBlack ) )
1868 pAcc->SetPixel( nY, nX, aBlack );
1870 else
1871 pAcc->SetPixel( nY, nX, aWhite );
1874 break;
1877 bRet = true;
1880 ReleaseAccess( pMaskAcc );
1881 ReleaseAccess( pAcc );
1883 return bRet;
1886 // TODO: Have a look at OutputDevice::ImplDrawAlpha() for some
1887 // optimizations. Might even consolidate the code here and there.
1888 bool Bitmap::Blend( const AlphaMask& rAlpha, const Color& rBackgroundColor )
1890 // Convert to a truecolor bitmap, if we're a paletted one. There's
1891 // room for tradeoff decision here, maybe later for an overload (or a flag)
1892 if( GetBitCount() <= 8 )
1893 Convert( BMP_CONVERSION_24BIT );
1895 BitmapReadAccess* pAlphaAcc = const_cast<AlphaMask&>(rAlpha).AcquireReadAccess();
1896 BitmapWriteAccess* pAcc = AcquireWriteAccess();
1897 bool bRet = false;
1899 if( pAlphaAcc && pAcc )
1901 const long nWidth = std::min( pAlphaAcc->Width(), pAcc->Width() );
1902 const long nHeight = std::min( pAlphaAcc->Height(), pAcc->Height() );
1904 for( long nY = 0L; nY < nHeight; ++nY )
1905 for( long nX = 0L; nX < nWidth; ++nX )
1906 pAcc->SetPixel( nY, nX,
1907 pAcc->GetPixel( nY, nX ).Merge( rBackgroundColor,
1908 255 - pAlphaAcc->GetPixelIndex( nY, nX ) ) );
1910 bRet = true;
1913 ReleaseAccess( pAlphaAcc );
1914 ReleaseAccess( pAcc );
1916 return bRet;
1919 bool Bitmap::MakeMono( sal_uInt8 cThreshold )
1921 return ImplMakeMono( cThreshold );
1924 bool Bitmap::GetSystemData( BitmapSystemData& rData ) const
1926 bool bRet = false;
1927 if( mpImpBmp )
1929 SalBitmap* pSalBitmap = mpImpBmp->ImplGetSalBitmap();
1930 if( pSalBitmap )
1931 bRet = pSalBitmap->GetSystemData( rData );
1934 return bRet;
1937 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */