xref: /trunk/main/vcl/source/gdi/bitmapex.cxx (revision ba5b0517)
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 			aMask.Scale( rScaleX, rScaleY, BMP_SCALE_FAST );
447 
448 		aBitmapSize = aBitmap.GetSizePixel();
449 
450         DBG_ASSERT( !aMask || aBitmap.GetSizePixel() == aMask.GetSizePixel(),
451                     "BitmapEx::Scale(): size mismatch for bitmap and alpha mask." );
452 	}
453 
454 	return bRet;
455 }
456 
457 // ------------------------------------------------------------------------
458 
459 sal_Bool BitmapEx::Scale( const Size& rNewSize, sal_uLong nScaleFlag )
460 {
461 	sal_Bool bRet;
462 
463 	if( aBitmapSize.Width() && aBitmapSize.Height() )
464 	{
465 		bRet = Scale( (double) rNewSize.Width() / aBitmapSize.Width(),
466 					  (double) rNewSize.Height() / aBitmapSize.Height(),
467 					  nScaleFlag );
468 	}
469 	else
470 		bRet = sal_True;
471 
472 	return bRet;
473 }
474 
475 // ------------------------------------------------------------------
476 
477 sal_Bool BitmapEx::Rotate( long nAngle10, const Color& rFillColor )
478 {
479 	sal_Bool bRet = sal_False;
480 
481 	if( !!aBitmap )
482 	{
483 		const sal_Bool bTransRotate = ( Color( COL_TRANSPARENT ) == rFillColor );
484 
485 		if( bTransRotate )
486 		{
487 			if( eTransparent == TRANSPARENT_COLOR )
488 				bRet = aBitmap.Rotate( nAngle10, aTransparentColor );
489 			else
490 			{
491 				bRet = aBitmap.Rotate( nAngle10, COL_BLACK );
492 
493 				if( eTransparent == TRANSPARENT_NONE )
494 				{
495 					aMask = Bitmap( aBitmapSize, 1 );
496 					aMask.Erase( COL_BLACK );
497 					eTransparent = TRANSPARENT_BITMAP;
498 				}
499 
500 				if( bRet && !!aMask )
501 					aMask.Rotate( nAngle10, COL_WHITE );
502 			}
503 		}
504 		else
505 		{
506 			bRet = aBitmap.Rotate( nAngle10, rFillColor );
507 
508 			if( bRet && ( eTransparent == TRANSPARENT_BITMAP ) && !!aMask )
509 				aMask.Rotate( nAngle10, COL_WHITE );
510 		}
511 
512 		aBitmapSize = aBitmap.GetSizePixel();
513 
514         DBG_ASSERT( !aMask || aBitmap.GetSizePixel() == aMask.GetSizePixel(),
515                     "BitmapEx::Rotate(): size mismatch for bitmap and alpha mask." );
516 	}
517 
518 	return bRet;
519 }
520 
521 // ------------------------------------------------------------------
522 
523 sal_Bool BitmapEx::Crop( const Rectangle& rRectPixel )
524 {
525 	sal_Bool bRet = sal_False;
526 
527 	if( !!aBitmap )
528 	{
529 		bRet = aBitmap.Crop( rRectPixel );
530 
531 		if( bRet && ( eTransparent == TRANSPARENT_BITMAP ) && !!aMask )
532 			aMask.Crop( rRectPixel );
533 
534 		aBitmapSize = aBitmap.GetSizePixel();
535 
536         DBG_ASSERT( !aMask || aBitmap.GetSizePixel() == aMask.GetSizePixel(),
537                     "BitmapEx::Crop(): size mismatch for bitmap and alpha mask." );
538 	}
539 
540 	return bRet;
541 }
542 
543 // ------------------------------------------------------------------
544 
545 sal_Bool BitmapEx::Convert( BmpConversion eConversion )
546 {
547 	return( !!aBitmap ? aBitmap.Convert( eConversion ) : sal_False );
548 }
549 
550 // ------------------------------------------------------------------
551 
552 sal_Bool BitmapEx::ReduceColors( sal_uInt16 nNewColorCount, BmpReduce eReduce )
553 {
554 	return( !!aBitmap ? aBitmap.ReduceColors( nNewColorCount, eReduce ) : sal_False );
555 }
556 
557 // ------------------------------------------------------------------
558 
559 sal_Bool BitmapEx::Expand( sal_uLong nDX, sal_uLong nDY, const Color* pInitColor, sal_Bool bExpandTransparent )
560 {
561 	sal_Bool bRet = sal_False;
562 
563 	if( !!aBitmap )
564 	{
565 		bRet = aBitmap.Expand( nDX, nDY, pInitColor );
566 
567 		if( bRet && ( eTransparent == TRANSPARENT_BITMAP ) && !!aMask )
568 		{
569 			Color aColor( bExpandTransparent ? COL_WHITE : COL_BLACK );
570 			aMask.Expand( nDX, nDY, &aColor );
571 		}
572 
573 		aBitmapSize = aBitmap.GetSizePixel();
574 
575         DBG_ASSERT( !aMask || aBitmap.GetSizePixel() == aMask.GetSizePixel(),
576                     "BitmapEx::Expand(): size mismatch for bitmap and alpha mask." );
577 	}
578 
579 	return bRet;
580 }
581 
582 // ------------------------------------------------------------------
583 
584 sal_Bool BitmapEx::CopyPixel( const Rectangle& rRectDst, const Rectangle& rRectSrc,
585 						  const BitmapEx* pBmpExSrc )
586 {
587 	sal_Bool bRet = sal_False;
588 
589 	if( !pBmpExSrc || pBmpExSrc->IsEmpty() )
590 	{
591 		if( !aBitmap.IsEmpty() )
592 		{
593 			bRet = aBitmap.CopyPixel( rRectDst, rRectSrc );
594 
595 			if( bRet && ( eTransparent == TRANSPARENT_BITMAP ) && !!aMask )
596 				aMask.CopyPixel( rRectDst, rRectSrc );
597 		}
598 	}
599 	else
600 	{
601 		if( !aBitmap.IsEmpty() )
602 		{
603 			bRet = aBitmap.CopyPixel( rRectDst, rRectSrc, &pBmpExSrc->aBitmap );
604 
605 			if( bRet )
606 			{
607 				if( pBmpExSrc->IsAlpha() )
608 				{
609 					if( IsAlpha() )
610                         // cast to use the optimized AlphaMask::CopyPixel
611 						((AlphaMask*) &aMask)->CopyPixel( rRectDst, rRectSrc, (AlphaMask*)&pBmpExSrc->aMask );
612 					else if( IsTransparent() )
613 					{
614 						AlphaMask* pAlpha = new AlphaMask( aMask );
615 
616 						aMask = pAlpha->ImplGetBitmap();
617 						delete pAlpha;
618 						bAlpha = sal_True;
619 						aMask.CopyPixel( rRectDst, rRectSrc, &pBmpExSrc->aMask );
620 					}
621 					else
622 					{
623 						sal_uInt8	cBlack = 0;
624 						AlphaMask*	pAlpha = new AlphaMask( GetSizePixel(), &cBlack );
625 
626 						aMask = pAlpha->ImplGetBitmap();
627 						delete pAlpha;
628 						eTransparent = TRANSPARENT_BITMAP;
629 						bAlpha = sal_True;
630 						aMask.CopyPixel( rRectDst, rRectSrc, &pBmpExSrc->aMask );
631 					}
632 				}
633 				else if( pBmpExSrc->IsTransparent() )
634 				{
635 					if( IsAlpha() )
636 					{
637 						AlphaMask aAlpha( pBmpExSrc->aMask );
638 						aMask.CopyPixel( rRectDst, rRectSrc, &aAlpha.ImplGetBitmap() );
639 					}
640 					else if( IsTransparent() )
641 						aMask.CopyPixel( rRectDst, rRectSrc, &pBmpExSrc->aMask );
642 					else
643 					{
644 						aMask = Bitmap( GetSizePixel(), 1 );
645 						aMask.Erase( Color( COL_BLACK ) );
646 						eTransparent = TRANSPARENT_BITMAP;
647 						aMask.CopyPixel( rRectDst, rRectSrc, &pBmpExSrc->aMask );
648 					}
649 				}
650                 else if( IsAlpha() )
651                 {
652                     sal_uInt8	      cBlack = 0;
653                     const AlphaMask   aAlphaSrc( pBmpExSrc->GetSizePixel(), &cBlack );
654 
655                     aMask.CopyPixel( rRectDst, rRectSrc, &aAlphaSrc.ImplGetBitmap() );
656                 }
657                 else if( IsTransparent() )
658                 {
659                     Bitmap aMaskSrc( pBmpExSrc->GetSizePixel(), 1 );
660 
661                     aMaskSrc.Erase( Color( COL_BLACK ) );
662                     aMask.CopyPixel( rRectDst, rRectSrc, &aMaskSrc );
663                 }
664 			}
665 		}
666 	}
667 
668 	return bRet;
669 }
670 
671 // ------------------------------------------------------------------
672 
673 sal_Bool BitmapEx::Erase( const Color& rFillColor )
674 {
675 	sal_Bool bRet = sal_False;
676 
677 	if( !!aBitmap )
678 	{
679 		bRet = aBitmap.Erase( rFillColor );
680 
681 		if( bRet && ( eTransparent == TRANSPARENT_BITMAP ) && !!aMask )
682 		{
683             // #104416# Respect transparency on fill color
684             if( rFillColor.GetTransparency() )
685             {
686                 const Color aFill( rFillColor.GetTransparency(), rFillColor.GetTransparency(), rFillColor.GetTransparency() );
687                 aMask.Erase( aFill );
688             }
689             else
690             {
691                 const Color aBlack( COL_BLACK );
692                 aMask.Erase( aBlack );
693             }
694 		}
695 	}
696 
697 	return bRet;
698 }
699 
700 // ------------------------------------------------------------------
701 
702 sal_Bool BitmapEx::Dither( sal_uLong nDitherFlags )
703 {
704 	return( !!aBitmap ? aBitmap.Dither( nDitherFlags ) : sal_False );
705 }
706 
707 // ------------------------------------------------------------------
708 
709 sal_Bool BitmapEx::Replace( const Color& rSearchColor, const Color& rReplaceColor, sal_uLong nTol )
710 {
711 	return( !!aBitmap ? aBitmap.Replace( rSearchColor, rReplaceColor, nTol ) : sal_False );
712 }
713 
714 // ------------------------------------------------------------------
715 
716 sal_Bool BitmapEx::Replace( const Color* pSearchColors, const Color* pReplaceColors, sal_uLong nColorCount, const sal_uLong* pTols )
717 {
718 	return( !!aBitmap ? aBitmap.Replace( pSearchColors, pReplaceColors, nColorCount, (sal_uLong*) pTols ) : sal_False );
719 }
720 
721 // ------------------------------------------------------------------
722 
723 sal_Bool BitmapEx::Adjust( short nLuminancePercent, short nContrastPercent,
724 					   short nChannelRPercent, short nChannelGPercent, short nChannelBPercent,
725 					   double fGamma, sal_Bool bInvert )
726 {
727 	return( !!aBitmap ? aBitmap.Adjust( nLuminancePercent, nContrastPercent,
728 										nChannelRPercent, nChannelGPercent, nChannelBPercent,
729 										fGamma, bInvert ) : sal_False );
730 }
731 
732 // ------------------------------------------------------------------
733 
734 sal_Bool BitmapEx::Filter( BmpFilter eFilter, const BmpFilterParam* pFilterParam, const Link* pProgress )
735 {
736 	return( !!aBitmap ? aBitmap.Filter( eFilter, pFilterParam, pProgress ) : sal_False );
737 }
738 
739 // ------------------------------------------------------------------
740 
741 void BitmapEx::Draw( OutputDevice* pOutDev, const Point& rDestPt ) const
742 {
743 	pOutDev->DrawBitmapEx( rDestPt, *this );
744 }
745 
746 // ------------------------------------------------------------------
747 
748 void BitmapEx::Draw( OutputDevice* pOutDev,
749 					 const Point& rDestPt, const Size& rDestSize ) const
750 {
751 	pOutDev->DrawBitmapEx( rDestPt, rDestSize, *this );
752 }
753 
754 // ------------------------------------------------------------------
755 
756 void BitmapEx::Draw( OutputDevice* pOutDev,
757 					 const Point& rDestPt, const Size& rDestSize,
758 					 const Point& rSrcPtPixel, const Size& rSrcSizePixel ) const
759 {
760 	pOutDev->DrawBitmapEx( rDestPt, rDestSize, rSrcPtPixel, rSrcSizePixel, *this );
761 }
762 
763 // ------------------------------------------------------------------
764 
765 sal_uInt8 BitmapEx::GetTransparency(sal_Int32 nX, sal_Int32 nY) const
766 {
767     sal_uInt8 nTransparency(0xff);
768 
769     if(!aBitmap.IsEmpty())
770     {
771         if(nX >= 0 && nX < aBitmapSize.Width() && nY >= 0 && nY < aBitmapSize.Height())
772         {
773             switch(eTransparent)
774             {
775                 case TRANSPARENT_NONE:
776                 {
777                     // not transparent, ergo all covered
778                     nTransparency = 0x00;
779                     break;
780                 }
781                 case TRANSPARENT_COLOR:
782                 {
783                     Bitmap aTestBitmap(aBitmap);
784                     BitmapReadAccess* pRead = aTestBitmap.AcquireReadAccess();
785 
786                     if(pRead)
787                     {
788                         const Color aColor = pRead->GetColor(nY, nX);
789 
790                         // if color is not equal to TransparentColor, we are not transparent
791                         if(aColor != aTransparentColor)
792                         {
793                             nTransparency = 0x00;
794                         }
795 
796                         aTestBitmap.ReleaseAccess(pRead);
797                     }
798                     break;
799                 }
800                 case TRANSPARENT_BITMAP:
801                 {
802                     if(!aMask.IsEmpty())
803                     {
804                         Bitmap aTestBitmap(aMask);
805                         BitmapReadAccess* pRead = aTestBitmap.AcquireReadAccess();
806 
807                         if(pRead)
808                         {
809                             const BitmapColor aBitmapColor(pRead->GetPixel(nY, nX));
810 
811                             if(bAlpha)
812                             {
813                                 nTransparency = aBitmapColor.GetIndex();
814                             }
815                             else
816                             {
817                                 if(0x00 == aBitmapColor.GetIndex())
818                                 {
819                                     nTransparency = 0x00;
820                                 }
821                             }
822 
823                             aTestBitmap.ReleaseAccess(pRead);
824                         }
825                     }
826                     break;
827                 }
828             }
829         }
830     }
831 
832     return nTransparency;
833 }
834 
835 // ------------------------------------------------------------------
836 
837 SvStream& operator<<( SvStream& rOStm, const BitmapEx& rBitmapEx )
838 {
839 	rBitmapEx.aBitmap.Write( rOStm );
840 
841 	rOStm << (sal_uInt32) 0x25091962;
842 	rOStm << (sal_uInt32) 0xACB20201;
843 	rOStm << (sal_uInt8) rBitmapEx.eTransparent;
844 
845 	if( rBitmapEx.eTransparent == TRANSPARENT_BITMAP )
846 		rBitmapEx.aMask.Write( rOStm );
847 	else if( rBitmapEx.eTransparent == TRANSPARENT_COLOR )
848 		rOStm << rBitmapEx.aTransparentColor;
849 
850 	return rOStm;
851 }
852 
853 // ------------------------------------------------------------------
854 
855 SvStream& operator>>( SvStream& rIStm, BitmapEx& rBitmapEx )
856 {
857 	Bitmap aBmp;
858 
859 	rIStm >> aBmp;
860 
861 	if( !rIStm.GetError() )
862 	{
863 		const sal_uLong nStmPos = rIStm.Tell();
864 		sal_uInt32		nMagic1 = 0;
865 		sal_uInt32		nMagic2 = 0;
866 
867 		rIStm >> nMagic1 >> nMagic2;
868 
869 		if( ( nMagic1 != 0x25091962 ) || ( nMagic2 != 0xACB20201 ) || rIStm.GetError() )
870 		{
871 			rIStm.ResetError();
872 			rIStm.Seek( nStmPos );
873 			rBitmapEx = aBmp;
874 		}
875 		else
876 		{
877 			sal_uInt8 bTransparent = false;
878 
879 			rIStm >> bTransparent;
880 
881 			if( bTransparent == (sal_uInt8) TRANSPARENT_BITMAP )
882 			{
883 				Bitmap aMask;
884 
885 				rIStm >> aMask;
886 
887 				if( !!aMask)
888 				{
889 					// do we have an alpha mask?
890 					if( ( 8 == aMask.GetBitCount() ) && aMask.HasGreyPalette() )
891 					{
892 						AlphaMask aAlpha;
893 
894 						// create alpha mask quickly (without greyscale conversion)
895 						aAlpha.ImplSetBitmap( aMask );
896 						rBitmapEx = BitmapEx( aBmp, aAlpha );
897 					}
898 					else
899 						rBitmapEx = BitmapEx( aBmp, aMask );
900 				}
901 				else
902 					rBitmapEx = aBmp;
903 			}
904 			else if( bTransparent == (sal_uInt8) TRANSPARENT_COLOR )
905 			{
906 				Color aTransparentColor;
907 
908 				rIStm >> aTransparentColor;
909 				rBitmapEx = BitmapEx( aBmp, aTransparentColor );
910 			}
911 			else
912 				rBitmapEx = aBmp;
913 		}
914 	}
915 
916 	return rIStm;
917 }
918