xref: /trunk/main/vcl/source/gdi/bitmapex.cxx (revision 37ab0f2d)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_vcl.hxx"
26 
27 #include <ctype.h>
28 
29 #include <rtl/crc.h>
30 
31 #include <tools/stream.hxx>
32 #include <tools/debug.hxx>
33 #include <tools/rc.h>
34 
35 #include <vcl/salbtype.hxx>
36 #include <vcl/outdev.hxx>
37 #include <vcl/alpha.hxx>
38 #include <vcl/bitmapex.hxx>
39 #include <vcl/pngread.hxx>
40 #include <vcl/svapp.hxx>
41 #include <vcl/bmpacc.hxx>
42 
43 #include <image.h>
44 #include <impimagetree.hxx>
45 
46 // ------------
47 // - BitmapEx -
48 // ------------
49 
50 BitmapEx::BitmapEx() :
51 		eTransparent( TRANSPARENT_NONE ),
52 		bAlpha		( sal_False )
53 {
54 }
55 
56 // ------------------------------------------------------------------
57 
58 BitmapEx::BitmapEx( const BitmapEx& rBitmapEx ) :
59 		aBitmap				( rBitmapEx.aBitmap ),
60 		aMask				( rBitmapEx.aMask ),
61 		aBitmapSize			( rBitmapEx.aBitmapSize ),
62 		aTransparentColor	( rBitmapEx.aTransparentColor ),
63 		eTransparent		( rBitmapEx.eTransparent ),
64 		bAlpha				( rBitmapEx.bAlpha )
65 {
66 }
67 
68 BitmapEx::BitmapEx( const BitmapEx& rBitmapEx, Point aSrc, Size aSize ) :
69 		eTransparent( TRANSPARENT_NONE ),
70 		bAlpha		( sal_False )
71 {
72 	if( rBitmapEx.IsEmpty() )
73 		return;
74 
75 	aBitmap = Bitmap( aSize, rBitmapEx.aBitmap.GetBitCount() );
76 	aBitmapSize = aSize;
77 	if( rBitmapEx.IsAlpha() )
78 	{
79 		bAlpha = sal_True;
80 		aMask = AlphaMask( aSize ).ImplGetBitmap();
81 	}
82 	else if( rBitmapEx.IsTransparent() )
83 		aMask = Bitmap( aSize, rBitmapEx.aMask.GetBitCount() );
84 
85 	Rectangle aDestRect( Point( 0, 0 ), aSize );
86 	Rectangle aSrcRect( aSrc, aSize );
87 	CopyPixel( aDestRect, aSrcRect, &rBitmapEx );
88 }
89 
90 // ------------------------------------------------------------------
91 
92 BitmapEx::BitmapEx( const ResId& rResId ) :
93 		eTransparent( TRANSPARENT_NONE ),
94 		bAlpha		( sal_False )
95 {
96 	static ImplImageTreeSingletonRef	aImageTree;
97 	ResMgr* 							pResMgr = NULL;
98 
99 	ResMgr::GetResourceSkipHeader( rResId.SetRT( RSC_BITMAP ), &pResMgr );
100 	pResMgr->ReadLong();
101 	pResMgr->ReadLong();
102 
103 	const String aFileName( pResMgr->ReadString() );
104 	::rtl::OUString aCurrentSymbolsStyle = Application::GetSettings().GetStyleSettings().GetCurrentSymbolsStyleName();
105 
106 	if( !aImageTree->loadImage( aFileName, aCurrentSymbolsStyle, *this ) )
107 	{
108 #ifdef DBG_UTIL
109 		ByteString aErrorStr( "BitmapEx::BitmapEx( const ResId& rResId ): could not load image <" );
110 		DBG_ERROR( ( ( aErrorStr += ByteString( aFileName, RTL_TEXTENCODING_ASCII_US ) ) += '>' ).GetBuffer() );
111 #endif
112 	}
113 }
114 
115 // ------------------------------------------------------------------
116 
117 BitmapEx::BitmapEx( const Bitmap& rBmp ) :
118 		aBitmap		( rBmp ),
119 		aBitmapSize	( aBitmap.GetSizePixel() ),
120 		eTransparent( TRANSPARENT_NONE ),
121 		bAlpha		( sal_False )
122 {
123 }
124 
125 // ------------------------------------------------------------------
126 
127 BitmapEx::BitmapEx( const Bitmap& rBmp, const Bitmap& rMask ) :
128 		aBitmap			( rBmp ),
129 		aMask			( rMask ),
130 		aBitmapSize		( aBitmap.GetSizePixel() ),
131 		eTransparent	( !rMask ? TRANSPARENT_NONE : TRANSPARENT_BITMAP ),
132 		bAlpha			( sal_False )
133 {
134     if(!!aBitmap && !!aMask && aBitmap.GetSizePixel() != aMask.GetSizePixel())
135     {
136         OSL_ENSURE(false, "Mask size differs from Bitmap size, corrected Mask (!)");
137         aMask.Scale(aBitmap.GetSizePixel());
138     }
139 
140     // #105489# Ensure a mask is exactly one bit deep
141     if( !!aMask && aMask.GetBitCount() != 1 )
142     {
143         OSL_TRACE("BitmapEx: forced mask to monochrome");
144         aMask.ImplMakeMono( 255 );
145     }
146 }
147 
148 // ------------------------------------------------------------------
149 
150 BitmapEx::BitmapEx( const Bitmap& rBmp, const AlphaMask& rAlphaMask ) :
151 		aBitmap			( rBmp ),
152 		aMask			( rAlphaMask.ImplGetBitmap() ),
153 		aBitmapSize		( aBitmap.GetSizePixel() ),
154 		eTransparent	( !rAlphaMask ? TRANSPARENT_NONE : TRANSPARENT_BITMAP ),
155 		bAlpha			( !rAlphaMask ? sal_False : sal_True )
156 {
157     if(!!aBitmap && !!aMask && aBitmap.GetSizePixel() != aMask.GetSizePixel())
158     {
159         OSL_ENSURE(false, "Alpha size differs from Bitmap size, corrected Mask (!)");
160         aMask.Scale(rBmp.GetSizePixel());
161     }
162 
163     // #i75531# the workaround below can go when
164     // X11SalGraphics::drawAlphaBitmap()'s render acceleration
165     // can handle the bitmap depth mismatch directly
166     if( aBitmap.GetBitCount() < aMask.GetBitCount() )
167         aBitmap.Convert( BMP_CONVERSION_24BIT );
168 }
169 
170 // ------------------------------------------------------------------
171 
172 BitmapEx::BitmapEx( const Bitmap& rBmp, const Color& rTransparentColor ) :
173 		aBitmap				( rBmp ),
174 		aBitmapSize			( aBitmap.GetSizePixel() ),
175 		aTransparentColor	( rTransparentColor ),
176 		eTransparent		( TRANSPARENT_BITMAP ),
177 		bAlpha				( sal_False )
178 {
179 	aMask = aBitmap.CreateMask( aTransparentColor );
180 
181     DBG_ASSERT( rBmp.GetSizePixel() == aMask.GetSizePixel(),
182                 "BitmapEx::BitmapEx(): size mismatch for bitmap and alpha mask." );
183 }
184 
185 // ------------------------------------------------------------------
186 
187 BitmapEx::~BitmapEx()
188 {
189 }
190 
191 // ------------------------------------------------------------------
192 
193 // ------------------------------------------------------------------
194 
195 BitmapEx& BitmapEx::operator=( const BitmapEx& rBitmapEx )
196 {
197 	if( &rBitmapEx != this )
198 	{
199 		aBitmap = rBitmapEx.aBitmap;
200 		aMask = rBitmapEx.aMask;
201 		aBitmapSize = rBitmapEx.aBitmapSize;
202 		aTransparentColor = rBitmapEx.aTransparentColor;
203 		eTransparent = rBitmapEx.eTransparent;
204 		bAlpha = rBitmapEx.bAlpha;
205 	}
206 
207 	return *this;
208 }
209 
210 // ------------------------------------------------------------------
211 
212 sal_Bool BitmapEx::operator==( const BitmapEx& rBitmapEx ) const
213 {
214 	if( eTransparent != rBitmapEx.eTransparent )
215 		return sal_False;
216 
217 	if( aBitmap != rBitmapEx.aBitmap )
218 		return sal_False;
219 
220 	if( aBitmapSize != rBitmapEx.aBitmapSize )
221 		return sal_False;
222 
223 	if( eTransparent == TRANSPARENT_NONE )
224 		return sal_True;
225 
226 	if( eTransparent == TRANSPARENT_COLOR )
227 		return aTransparentColor == rBitmapEx.aTransparentColor;
228 
229 	return( ( aMask == rBitmapEx.aMask ) && ( bAlpha == rBitmapEx.bAlpha ) );
230 }
231 
232 // ------------------------------------------------------------------
233 
234 sal_Bool BitmapEx::IsEqual( const BitmapEx& rBmpEx ) const
235 {
236 	return( rBmpEx.eTransparent == eTransparent &&
237 			rBmpEx.bAlpha == bAlpha &&
238 			rBmpEx.aBitmap.IsEqual( aBitmap ) &&
239 			rBmpEx.aMask.IsEqual( aMask ) );
240 }
241 
242 // ------------------------------------------------------------------
243 
244 sal_Bool BitmapEx::IsEmpty() const
245 {
246 	return( aBitmap.IsEmpty() && aMask.IsEmpty() );
247 }
248 
249 // ------------------------------------------------------------------
250 
251 void BitmapEx::SetEmpty()
252 {
253 	aBitmap.SetEmpty();
254 	aMask.SetEmpty();
255 	eTransparent = TRANSPARENT_NONE;
256 	bAlpha = sal_False;
257 }
258 
259 // ------------------------------------------------------------------
260 
261 void BitmapEx::Clear()
262 {
263 	SetEmpty();
264 }
265 
266 // ------------------------------------------------------------------
267 
268 sal_Bool BitmapEx::IsTransparent() const
269 {
270 	return( eTransparent != TRANSPARENT_NONE );
271 }
272 
273 // ------------------------------------------------------------------
274 
275 sal_Bool BitmapEx::IsAlpha() const
276 {
277 	return( IsTransparent() && bAlpha );
278 }
279 
280 // ------------------------------------------------------------------
281 
282 Bitmap BitmapEx::GetBitmap( const Color* pTransReplaceColor ) const
283 {
284 	Bitmap aRetBmp( aBitmap );
285 
286 	if( pTransReplaceColor && ( eTransparent != TRANSPARENT_NONE ) )
287 	{
288 		Bitmap aTempMask;
289 
290 		if( eTransparent == TRANSPARENT_COLOR )
291 			aTempMask = aBitmap.CreateMask( aTransparentColor );
292 		else
293 			aTempMask = aMask;
294 
295 		if( !IsAlpha() )
296 			aRetBmp.Replace( aTempMask, *pTransReplaceColor );
297 		else
298 			aRetBmp.Replace( GetAlpha(), *pTransReplaceColor );
299 	}
300 
301 	return aRetBmp;
302 }
303 
304 // ------------------------------------------------------------------
305 
306 BitmapEx BitmapEx::GetColorTransformedBitmapEx( BmpColorMode eColorMode ) const
307 {
308 	BitmapEx aRet;
309 
310 	if( BMP_COLOR_HIGHCONTRAST == eColorMode )
311 	{
312 		aRet = *this;
313 		aRet.aBitmap = aBitmap.GetColorTransformedBitmap( eColorMode );
314 	}
315 	else if( BMP_COLOR_MONOCHROME_BLACK == eColorMode ||
316 			 BMP_COLOR_MONOCHROME_WHITE == eColorMode )
317 	{
318 		aRet = *this;
319 		aRet.aBitmap = aRet.aBitmap.GetColorTransformedBitmap( eColorMode );
320 
321 		if( !aRet.aMask.IsEmpty() )
322 		{
323 			aRet.aMask.CombineSimple( aRet.aBitmap, BMP_COMBINE_OR );
324 			aRet.aBitmap.Erase( ( BMP_COLOR_MONOCHROME_BLACK == eColorMode ) ? COL_BLACK : COL_WHITE );
325 
326             DBG_ASSERT( aRet.aBitmap.GetSizePixel() == aRet.aMask.GetSizePixel(),
327                         "BitmapEx::GetColorTransformedBitmapEx(): size mismatch for bitmap and alpha mask." );
328 		}
329 	}
330 
331 	return aRet;
332 }
333 
334 // ------------------------------------------------------------------
335 
336 Bitmap BitmapEx::GetMask() const
337 {
338 	Bitmap aRet( aMask );
339 
340 	if( IsAlpha() )
341 		aRet.ImplMakeMono( 255 );
342 
343 	return aRet;
344 }
345 
346 // ------------------------------------------------------------------
347 
348 AlphaMask BitmapEx::GetAlpha() const
349 {
350 	AlphaMask aAlpha;
351 
352 	if( IsAlpha() )
353 		aAlpha.ImplSetBitmap( aMask );
354 	else
355 		aAlpha = aMask;
356 
357 	return aAlpha;
358 }
359 
360 // ------------------------------------------------------------------
361 
362 sal_uLong BitmapEx::GetSizeBytes() const
363 {
364 	sal_uLong nSizeBytes = aBitmap.GetSizeBytes();
365 
366 	if( eTransparent == TRANSPARENT_BITMAP )
367 		nSizeBytes += aMask.GetSizeBytes();
368 
369 	return nSizeBytes;
370 }
371 
372 // ------------------------------------------------------------------
373 
374 sal_uLong BitmapEx::GetChecksum() const
375 {
376 	sal_uInt32	nCrc = aBitmap.GetChecksum();
377 	SVBT32		aBT32;
378 
379 	UInt32ToSVBT32( (long) eTransparent, aBT32 );
380 	nCrc = rtl_crc32( nCrc, aBT32, 4 );
381 
382 	UInt32ToSVBT32( (long) bAlpha, aBT32 );
383 	nCrc = rtl_crc32( nCrc, aBT32, 4 );
384 
385 	if( ( TRANSPARENT_BITMAP == eTransparent ) && !aMask.IsEmpty() )
386 	{
387 		UInt32ToSVBT32( aMask.GetChecksum(), aBT32 );
388 		nCrc = rtl_crc32( nCrc, aBT32, 4 );
389 	}
390 
391 	return nCrc;
392 }
393 
394 // ------------------------------------------------------------------
395 
396 void BitmapEx::SetSizePixel( const Size& rNewSize )
397 {
398 	Scale( rNewSize );
399 }
400 
401 // ------------------------------------------------------------------
402 
403 sal_Bool BitmapEx::Invert()
404 {
405 	sal_Bool bRet = sal_False;
406 
407 	if( !!aBitmap )
408 	{
409 		bRet = aBitmap.Invert();
410 
411 		if( bRet && ( eTransparent == TRANSPARENT_COLOR ) )
412 			aTransparentColor = BitmapColor( aTransparentColor ).Invert();
413 	}
414 
415 	return bRet;
416 }
417 
418 // ------------------------------------------------------------------
419 
420 sal_Bool BitmapEx::Mirror( sal_uLong nMirrorFlags )
421 {
422 	sal_Bool bRet = sal_False;
423 
424 	if( !!aBitmap )
425 	{
426 		bRet = aBitmap.Mirror( nMirrorFlags );
427 
428 		if( bRet && ( eTransparent == TRANSPARENT_BITMAP ) && !!aMask )
429 			aMask.Mirror( nMirrorFlags );
430 	}
431 
432 	return bRet;
433 }
434 
435 // ------------------------------------------------------------------
436 
437 sal_Bool BitmapEx::Scale( const double& rScaleX, const double& rScaleY, sal_uLong nScaleFlag )
438 {
439 	sal_Bool bRet = sal_False;
440 
441 	if( !!aBitmap )
442 	{
443 		bRet = aBitmap.Scale( rScaleX, rScaleY, nScaleFlag );
444 
445 		if( bRet && ( eTransparent == TRANSPARENT_BITMAP ) && !!aMask )
446         {
447 			aMask.Scale( rScaleX, rScaleY, nScaleFlag );
448         }
449 
450 		aBitmapSize = aBitmap.GetSizePixel();
451 
452         DBG_ASSERT( !aMask || aBitmap.GetSizePixel() == aMask.GetSizePixel(),
453                     "BitmapEx::Scale(): size mismatch for bitmap and alpha mask." );
454 	}
455 
456 	return bRet;
457 }
458 
459 // ------------------------------------------------------------------------
460 
461 sal_Bool BitmapEx::Scale( const Size& rNewSize, sal_uLong nScaleFlag )
462 {
463 	sal_Bool bRet;
464 
465 	if( aBitmapSize.Width() && aBitmapSize.Height() )
466 	{
467 		bRet = Scale( (double) rNewSize.Width() / aBitmapSize.Width(),
468 					  (double) rNewSize.Height() / aBitmapSize.Height(),
469 					  nScaleFlag );
470 	}
471 	else
472 		bRet = sal_True;
473 
474 	return bRet;
475 }
476 
477 // ------------------------------------------------------------------
478 
479 sal_Bool BitmapEx::Rotate( long nAngle10, const Color& rFillColor )
480 {
481 	sal_Bool bRet = sal_False;
482 
483 	if( !!aBitmap )
484 	{
485 		const sal_Bool bTransRotate = ( Color( COL_TRANSPARENT ) == rFillColor );
486 
487 		if( bTransRotate )
488 		{
489 			if( eTransparent == TRANSPARENT_COLOR )
490 				bRet = aBitmap.Rotate( nAngle10, aTransparentColor );
491 			else
492 			{
493 				bRet = aBitmap.Rotate( nAngle10, COL_BLACK );
494 
495 				if( eTransparent == TRANSPARENT_NONE )
496 				{
497 					aMask = Bitmap( aBitmapSize, 1 );
498 					aMask.Erase( COL_BLACK );
499 					eTransparent = TRANSPARENT_BITMAP;
500 				}
501 
502 				if( bRet && !!aMask )
503 					aMask.Rotate( nAngle10, COL_WHITE );
504 			}
505 		}
506 		else
507 		{
508 			bRet = aBitmap.Rotate( nAngle10, rFillColor );
509 
510 			if( bRet && ( eTransparent == TRANSPARENT_BITMAP ) && !!aMask )
511 				aMask.Rotate( nAngle10, COL_WHITE );
512 		}
513 
514 		aBitmapSize = aBitmap.GetSizePixel();
515 
516         DBG_ASSERT( !aMask || aBitmap.GetSizePixel() == aMask.GetSizePixel(),
517                     "BitmapEx::Rotate(): size mismatch for bitmap and alpha mask." );
518 	}
519 
520 	return bRet;
521 }
522 
523 // ------------------------------------------------------------------
524 
525 sal_Bool BitmapEx::Crop( const Rectangle& rRectPixel )
526 {
527 	sal_Bool bRet = sal_False;
528 
529 	if( !!aBitmap )
530 	{
531 		bRet = aBitmap.Crop( rRectPixel );
532 
533 		if( bRet && ( eTransparent == TRANSPARENT_BITMAP ) && !!aMask )
534 			aMask.Crop( rRectPixel );
535 
536 		aBitmapSize = aBitmap.GetSizePixel();
537 
538         DBG_ASSERT( !aMask || aBitmap.GetSizePixel() == aMask.GetSizePixel(),
539                     "BitmapEx::Crop(): size mismatch for bitmap and alpha mask." );
540 	}
541 
542 	return bRet;
543 }
544 
545 // ------------------------------------------------------------------
546 
547 sal_Bool BitmapEx::Convert( BmpConversion eConversion )
548 {
549 	return( !!aBitmap ? aBitmap.Convert( eConversion ) : sal_False );
550 }
551 
552 // ------------------------------------------------------------------
553 
554 sal_Bool BitmapEx::ReduceColors( sal_uInt16 nNewColorCount, BmpReduce eReduce )
555 {
556 	return( !!aBitmap ? aBitmap.ReduceColors( nNewColorCount, eReduce ) : sal_False );
557 }
558 
559 // ------------------------------------------------------------------
560 
561 sal_Bool BitmapEx::Expand( sal_uLong nDX, sal_uLong nDY, const Color* pInitColor, sal_Bool bExpandTransparent )
562 {
563 	sal_Bool bRet = sal_False;
564 
565 	if( !!aBitmap )
566 	{
567 		bRet = aBitmap.Expand( nDX, nDY, pInitColor );
568 
569 		if( bRet && ( eTransparent == TRANSPARENT_BITMAP ) && !!aMask )
570 		{
571 			Color aColor( bExpandTransparent ? COL_WHITE : COL_BLACK );
572 			aMask.Expand( nDX, nDY, &aColor );
573 		}
574 
575 		aBitmapSize = aBitmap.GetSizePixel();
576 
577         DBG_ASSERT( !aMask || aBitmap.GetSizePixel() == aMask.GetSizePixel(),
578                     "BitmapEx::Expand(): size mismatch for bitmap and alpha mask." );
579 	}
580 
581 	return bRet;
582 }
583 
584 // ------------------------------------------------------------------
585 
586 sal_Bool BitmapEx::CopyPixel( const Rectangle& rRectDst, const Rectangle& rRectSrc,
587 						  const BitmapEx* pBmpExSrc )
588 {
589 	sal_Bool bRet = sal_False;
590 
591 	if( !pBmpExSrc || pBmpExSrc->IsEmpty() )
592 	{
593 		if( !aBitmap.IsEmpty() )
594 		{
595 			bRet = aBitmap.CopyPixel( rRectDst, rRectSrc );
596 
597 			if( bRet && ( eTransparent == TRANSPARENT_BITMAP ) && !!aMask )
598 				aMask.CopyPixel( rRectDst, rRectSrc );
599 		}
600 	}
601 	else
602 	{
603 		if( !aBitmap.IsEmpty() )
604 		{
605 			bRet = aBitmap.CopyPixel( rRectDst, rRectSrc, &pBmpExSrc->aBitmap );
606 
607 			if( bRet )
608 			{
609 				if( pBmpExSrc->IsAlpha() )
610 				{
611 					if( IsAlpha() )
612                         // cast to use the optimized AlphaMask::CopyPixel
613 						((AlphaMask*) &aMask)->CopyPixel( rRectDst, rRectSrc, (AlphaMask*)&pBmpExSrc->aMask );
614 					else if( IsTransparent() )
615 					{
616 						AlphaMask* pAlpha = new AlphaMask( aMask );
617 
618 						aMask = pAlpha->ImplGetBitmap();
619 						delete pAlpha;
620 						bAlpha = sal_True;
621 						aMask.CopyPixel( rRectDst, rRectSrc, &pBmpExSrc->aMask );
622 					}
623 					else
624 					{
625 						sal_uInt8	cBlack = 0;
626 						AlphaMask*	pAlpha = new AlphaMask( GetSizePixel(), &cBlack );
627 
628 						aMask = pAlpha->ImplGetBitmap();
629 						delete pAlpha;
630 						eTransparent = TRANSPARENT_BITMAP;
631 						bAlpha = sal_True;
632 						aMask.CopyPixel( rRectDst, rRectSrc, &pBmpExSrc->aMask );
633 					}
634 				}
635 				else if( pBmpExSrc->IsTransparent() )
636 				{
637 					if( IsAlpha() )
638 					{
639 						AlphaMask aAlpha( pBmpExSrc->aMask );
640 						aMask.CopyPixel( rRectDst, rRectSrc, &aAlpha.ImplGetBitmap() );
641 					}
642 					else if( IsTransparent() )
643 						aMask.CopyPixel( rRectDst, rRectSrc, &pBmpExSrc->aMask );
644 					else
645 					{
646 						aMask = Bitmap( GetSizePixel(), 1 );
647 						aMask.Erase( Color( COL_BLACK ) );
648 						eTransparent = TRANSPARENT_BITMAP;
649 						aMask.CopyPixel( rRectDst, rRectSrc, &pBmpExSrc->aMask );
650 					}
651 				}
652                 else if( IsAlpha() )
653                 {
654                     sal_uInt8	      cBlack = 0;
655                     const AlphaMask   aAlphaSrc( pBmpExSrc->GetSizePixel(), &cBlack );
656 
657                     aMask.CopyPixel( rRectDst, rRectSrc, &aAlphaSrc.ImplGetBitmap() );
658                 }
659                 else if( IsTransparent() )
660                 {
661                     Bitmap aMaskSrc( pBmpExSrc->GetSizePixel(), 1 );
662 
663                     aMaskSrc.Erase( Color( COL_BLACK ) );
664                     aMask.CopyPixel( rRectDst, rRectSrc, &aMaskSrc );
665                 }
666 			}
667 		}
668 	}
669 
670 	return bRet;
671 }
672 
673 // ------------------------------------------------------------------
674 
675 sal_Bool BitmapEx::Erase( const Color& rFillColor )
676 {
677 	sal_Bool bRet = sal_False;
678 
679 	if( !!aBitmap )
680 	{
681 		bRet = aBitmap.Erase( rFillColor );
682 
683 		if( bRet && ( eTransparent == TRANSPARENT_BITMAP ) && !!aMask )
684 		{
685             // #104416# Respect transparency on fill color
686             if( rFillColor.GetTransparency() )
687             {
688                 const Color aFill( rFillColor.GetTransparency(), rFillColor.GetTransparency(), rFillColor.GetTransparency() );
689                 aMask.Erase( aFill );
690             }
691             else
692             {
693                 const Color aBlack( COL_BLACK );
694                 aMask.Erase( aBlack );
695             }
696 		}
697 	}
698 
699 	return bRet;
700 }
701 
702 // ------------------------------------------------------------------
703 
704 sal_Bool BitmapEx::Dither( sal_uLong nDitherFlags )
705 {
706 	return( !!aBitmap ? aBitmap.Dither( nDitherFlags ) : sal_False );
707 }
708 
709 // ------------------------------------------------------------------
710 
711 sal_Bool BitmapEx::Replace( const Color& rSearchColor, const Color& rReplaceColor, sal_uLong nTol )
712 {
713 	return( !!aBitmap ? aBitmap.Replace( rSearchColor, rReplaceColor, nTol ) : sal_False );
714 }
715 
716 // ------------------------------------------------------------------
717 
718 sal_Bool BitmapEx::Replace( const Color* pSearchColors, const Color* pReplaceColors, sal_uLong nColorCount, const sal_uLong* pTols )
719 {
720 	return( !!aBitmap ? aBitmap.Replace( pSearchColors, pReplaceColors, nColorCount, (sal_uLong*) pTols ) : sal_False );
721 }
722 
723 // ------------------------------------------------------------------
724 
725 sal_Bool BitmapEx::Adjust( short nLuminancePercent, short nContrastPercent,
726 					   short nChannelRPercent, short nChannelGPercent, short nChannelBPercent,
727 					   double fGamma, sal_Bool bInvert )
728 {
729 	return( !!aBitmap ? aBitmap.Adjust( nLuminancePercent, nContrastPercent,
730 										nChannelRPercent, nChannelGPercent, nChannelBPercent,
731 										fGamma, bInvert ) : sal_False );
732 }
733 
734 // ------------------------------------------------------------------
735 
736 sal_Bool BitmapEx::Filter( BmpFilter eFilter, const BmpFilterParam* pFilterParam, const Link* pProgress )
737 {
738 	return( !!aBitmap ? aBitmap.Filter( eFilter, pFilterParam, pProgress ) : sal_False );
739 }
740 
741 // ------------------------------------------------------------------
742 
743 void BitmapEx::Draw( OutputDevice* pOutDev, const Point& rDestPt ) const
744 {
745 	pOutDev->DrawBitmapEx( rDestPt, *this );
746 }
747 
748 // ------------------------------------------------------------------
749 
750 void BitmapEx::Draw( OutputDevice* pOutDev,
751 					 const Point& rDestPt, const Size& rDestSize ) const
752 {
753 	pOutDev->DrawBitmapEx( rDestPt, rDestSize, *this );
754 }
755 
756 // ------------------------------------------------------------------
757 
758 void BitmapEx::Draw( OutputDevice* pOutDev,
759 					 const Point& rDestPt, const Size& rDestSize,
760 					 const Point& rSrcPtPixel, const Size& rSrcSizePixel ) const
761 {
762 	pOutDev->DrawBitmapEx( rDestPt, rDestSize, rSrcPtPixel, rSrcSizePixel, *this );
763 }
764 
765 // ------------------------------------------------------------------
766 
767 sal_uInt8 BitmapEx::GetTransparency(sal_Int32 nX, sal_Int32 nY) const
768 {
769     sal_uInt8 nTransparency(0xff);
770 
771     if(!aBitmap.IsEmpty())
772     {
773         if(nX >= 0 && nX < aBitmapSize.Width() && nY >= 0 && nY < aBitmapSize.Height())
774         {
775             switch(eTransparent)
776             {
777                 case TRANSPARENT_NONE:
778                 {
779                     // not transparent, ergo all covered
780                     nTransparency = 0x00;
781                     break;
782                 }
783                 case TRANSPARENT_COLOR:
784                 {
785                     Bitmap aTestBitmap(aBitmap);
786                     BitmapReadAccess* pRead = aTestBitmap.AcquireReadAccess();
787 
788                     if(pRead)
789                     {
790                         const Color aColor = pRead->GetColor(nY, nX);
791 
792                         // if color is not equal to TransparentColor, we are not transparent
793                         if(aColor != aTransparentColor)
794                         {
795                             nTransparency = 0x00;
796                         }
797 
798                         aTestBitmap.ReleaseAccess(pRead);
799                     }
800                     break;
801                 }
802                 case TRANSPARENT_BITMAP:
803                 {
804                     if(!aMask.IsEmpty())
805                     {
806                         Bitmap aTestBitmap(aMask);
807                         BitmapReadAccess* pRead = aTestBitmap.AcquireReadAccess();
808 
809                         if(pRead)
810                         {
811                             const BitmapColor aBitmapColor(pRead->GetPixel(nY, nX));
812 
813                             if(bAlpha)
814                             {
815                                 nTransparency = aBitmapColor.GetIndex();
816                             }
817                             else
818                             {
819                                 if(0x00 == aBitmapColor.GetIndex())
820                                 {
821                                     nTransparency = 0x00;
822                                 }
823                             }
824 
825                             aTestBitmap.ReleaseAccess(pRead);
826                         }
827                     }
828                     break;
829                 }
830             }
831         }
832     }
833 
834     return nTransparency;
835 }
836 
837 // ------------------------------------------------------------------
838 
839 SvStream& operator<<( SvStream& rOStm, const BitmapEx& rBitmapEx )
840 {
841 	rBitmapEx.aBitmap.Write( rOStm );
842 
843 	rOStm << (sal_uInt32) 0x25091962;
844 	rOStm << (sal_uInt32) 0xACB20201;
845 	rOStm << (sal_uInt8) rBitmapEx.eTransparent;
846 
847 	if( rBitmapEx.eTransparent == TRANSPARENT_BITMAP )
848 		rBitmapEx.aMask.Write( rOStm );
849 	else if( rBitmapEx.eTransparent == TRANSPARENT_COLOR )
850 		rOStm << rBitmapEx.aTransparentColor;
851 
852 	return rOStm;
853 }
854 
855 // ------------------------------------------------------------------
856 
857 SvStream& operator>>( SvStream& rIStm, BitmapEx& rBitmapEx )
858 {
859 	Bitmap aBmp;
860 
861 	rIStm >> aBmp;
862 
863 	if( !rIStm.GetError() )
864 	{
865 		const sal_uLong nStmPos = rIStm.Tell();
866 		sal_uInt32		nMagic1 = 0;
867 		sal_uInt32		nMagic2 = 0;
868 
869 		rIStm >> nMagic1 >> nMagic2;
870 
871 		if( ( nMagic1 != 0x25091962 ) || ( nMagic2 != 0xACB20201 ) || rIStm.GetError() )
872 		{
873 			rIStm.ResetError();
874 			rIStm.Seek( nStmPos );
875 			rBitmapEx = aBmp;
876 		}
877 		else
878 		{
879 			sal_uInt8 bTransparent = false;
880 
881 			rIStm >> bTransparent;
882 
883 			if( bTransparent == (sal_uInt8) TRANSPARENT_BITMAP )
884 			{
885 				Bitmap aMask;
886 
887 				rIStm >> aMask;
888 
889 				if( !!aMask)
890 				{
891 					// do we have an alpha mask?
892 					if( ( 8 == aMask.GetBitCount() ) && aMask.HasGreyPalette() )
893 					{
894 						AlphaMask aAlpha;
895 
896 						// create alpha mask quickly (without greyscale conversion)
897 						aAlpha.ImplSetBitmap( aMask );
898 						rBitmapEx = BitmapEx( aBmp, aAlpha );
899 					}
900 					else
901 						rBitmapEx = BitmapEx( aBmp, aMask );
902 				}
903 				else
904 					rBitmapEx = aBmp;
905 			}
906 			else if( bTransparent == (sal_uInt8) TRANSPARENT_COLOR )
907 			{
908 				Color aTransparentColor;
909 
910 				rIStm >> aTransparentColor;
911 				rBitmapEx = BitmapEx( aBmp, aTransparentColor );
912 			}
913 			else
914 				rBitmapEx = aBmp;
915 		}
916 	}
917 
918 	return rIStm;
919 }
920