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