xref: /trunk/main/vcl/source/gdi/bitmapex.cxx (revision 5f27b83c)
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 // MARKER(update_precomp.py): autogen include statement, do not remove
23 #include "precompiled_vcl.hxx"
24 
25 #include <ctype.h>
26 #include <rtl/crc.h>
27 #include <tools/stream.hxx>
28 #include <tools/debug.hxx>
29 #include <tools/rc.h>
30 #include <vcl/salbtype.hxx>
31 #include <vcl/outdev.hxx>
32 #include <vcl/alpha.hxx>
33 #include <vcl/bitmapex.hxx>
34 #include <vcl/pngread.hxx>
35 #include <vcl/svapp.hxx>
36 #include <vcl/bmpacc.hxx>
37 #include <vcl/dibtools.hxx>
38 #include <image.h>
39 #include <impimagetree.hxx>
40 #include <basegfx/matrix/b2dhommatrixtools.hxx>
41 
42 // ------------
43 // - BitmapEx -
44 // ------------
45 
46 BitmapEx::BitmapEx() :
47 		eTransparent( TRANSPARENT_NONE ),
48 		bAlpha		( sal_False )
49 {
50 }
51 
52 // ------------------------------------------------------------------
53 
54 BitmapEx::BitmapEx( const BitmapEx& rBitmapEx ) :
55 		aBitmap				( rBitmapEx.aBitmap ),
56 		aMask				( rBitmapEx.aMask ),
57 		aBitmapSize			( rBitmapEx.aBitmapSize ),
58 		aTransparentColor	( rBitmapEx.aTransparentColor ),
59 		eTransparent		( rBitmapEx.eTransparent ),
60 		bAlpha				( rBitmapEx.bAlpha )
61 {
62 }
63 
64 BitmapEx::BitmapEx( const BitmapEx& rBitmapEx, Point aSrc, Size aSize ) :
65 		eTransparent( TRANSPARENT_NONE ),
66 		bAlpha		( sal_False )
67 {
68 	if( rBitmapEx.IsEmpty() )
69 		return;
70 
71 	aBitmap = Bitmap( aSize, rBitmapEx.aBitmap.GetBitCount() );
72 	aBitmapSize = aSize;
73 	if( rBitmapEx.IsAlpha() )
74 	{
75 		bAlpha = sal_True;
76 		aMask = AlphaMask( aSize ).ImplGetBitmap();
77 	}
78 	else if( rBitmapEx.IsTransparent() )
79 		aMask = Bitmap( aSize, rBitmapEx.aMask.GetBitCount() );
80 
81 	Rectangle aDestRect( Point( 0, 0 ), aSize );
82 	Rectangle aSrcRect( aSrc, aSize );
83 	CopyPixel( aDestRect, aSrcRect, &rBitmapEx );
84 }
85 
86 // ------------------------------------------------------------------
87 
88 BitmapEx::BitmapEx( const ResId& rResId ) :
89 		eTransparent( TRANSPARENT_NONE ),
90 		bAlpha		( sal_False )
91 {
92 	static ImplImageTreeSingletonRef	aImageTree;
93 	ResMgr* 							pResMgr = NULL;
94 
95 	ResMgr::GetResourceSkipHeader( rResId.SetRT( RSC_BITMAP ), &pResMgr );
96 	pResMgr->ReadLong();
97 	pResMgr->ReadLong();
98 
99 	const String aFileName( pResMgr->ReadString() );
100 	::rtl::OUString aCurrentSymbolsStyle = Application::GetSettings().GetStyleSettings().GetCurrentSymbolsStyleName();
101 
102 	if( !aImageTree->loadImage( aFileName, aCurrentSymbolsStyle, *this ) )
103 	{
104 #ifdef DBG_UTIL
105 		ByteString aErrorStr( "BitmapEx::BitmapEx( const ResId& rResId ): could not load image <" );
106 		DBG_ERROR( ( ( aErrorStr += ByteString( aFileName, RTL_TEXTENCODING_ASCII_US ) ) += '>' ).GetBuffer() );
107 #endif
108 	}
109 }
110 
111 // ------------------------------------------------------------------
112 
113 BitmapEx::BitmapEx( const Bitmap& rBmp ) :
114 		aBitmap		( rBmp ),
115 		aBitmapSize	( aBitmap.GetSizePixel() ),
116 		eTransparent( TRANSPARENT_NONE ),
117 		bAlpha		( sal_False )
118 {
119 }
120 
121 // ------------------------------------------------------------------
122 
123 BitmapEx::BitmapEx( const Bitmap& rBmp, const Bitmap& rMask ) :
124 		aBitmap			( rBmp ),
125 		aMask			( rMask ),
126 		aBitmapSize		( aBitmap.GetSizePixel() ),
127 		eTransparent	( !rMask ? TRANSPARENT_NONE : TRANSPARENT_BITMAP ),
128 		bAlpha			( sal_False )
129 {
130     if(!!aBitmap && !!aMask && aBitmap.GetSizePixel() != aMask.GetSizePixel())
131     {
132         OSL_ENSURE(false, "Mask size differs from Bitmap size, corrected Mask (!)");
133         aMask.Scale(aBitmap.GetSizePixel());
134     }
135 
136     // #105489# Ensure a mask is exactly one bit deep
137     if( !!aMask && aMask.GetBitCount() != 1 )
138     {
139         OSL_TRACE("BitmapEx: forced mask to monochrome");
140         aMask.ImplMakeMono( 255 );
141     }
142 }
143 
144 // ------------------------------------------------------------------
145 
146 BitmapEx::BitmapEx( const Bitmap& rBmp, const AlphaMask& rAlphaMask ) :
147 		aBitmap			( rBmp ),
148 		aMask			( rAlphaMask.ImplGetBitmap() ),
149 		aBitmapSize		( aBitmap.GetSizePixel() ),
150 		eTransparent	( !rAlphaMask ? TRANSPARENT_NONE : TRANSPARENT_BITMAP ),
151 		bAlpha			( !rAlphaMask ? sal_False : sal_True )
152 {
153     if(!!aBitmap && !!aMask && aBitmap.GetSizePixel() != aMask.GetSizePixel())
154     {
155         OSL_ENSURE(false, "Alpha size differs from Bitmap size, corrected Mask (!)");
156         aMask.Scale(rBmp.GetSizePixel());
157     }
158 
159     // #i75531# the workaround below can go when
160     // X11SalGraphics::drawAlphaBitmap()'s render acceleration
161     // can handle the bitmap depth mismatch directly
162     if( aBitmap.GetBitCount() < aMask.GetBitCount() )
163         aBitmap.Convert( BMP_CONVERSION_24BIT );
164 }
165 
166 // ------------------------------------------------------------------
167 
168 BitmapEx::BitmapEx( const Bitmap& rBmp, const Color& rTransparentColor ) :
169 		aBitmap				( rBmp ),
170 		aBitmapSize			( aBitmap.GetSizePixel() ),
171 		aTransparentColor	( rTransparentColor ),
172 		eTransparent		( TRANSPARENT_BITMAP ),
173 		bAlpha				( sal_False )
174 {
175 	aMask = aBitmap.CreateMask( aTransparentColor );
176 
177     DBG_ASSERT( rBmp.GetSizePixel() == aMask.GetSizePixel(),
178                 "BitmapEx::BitmapEx(): size mismatch for bitmap and alpha mask." );
179 }
180 
181 // ------------------------------------------------------------------
182 
183 BitmapEx::~BitmapEx()
184 {
185 }
186 
187 // ------------------------------------------------------------------
188 
189 // ------------------------------------------------------------------
190 
191 BitmapEx& BitmapEx::operator=( const BitmapEx& rBitmapEx )
192 {
193 	if( &rBitmapEx != this )
194 	{
195 		aBitmap = rBitmapEx.aBitmap;
196 		aMask = rBitmapEx.aMask;
197 		aBitmapSize = rBitmapEx.aBitmapSize;
198 		aTransparentColor = rBitmapEx.aTransparentColor;
199 		eTransparent = rBitmapEx.eTransparent;
200 		bAlpha = rBitmapEx.bAlpha;
201 	}
202 
203 	return *this;
204 }
205 
206 // ------------------------------------------------------------------
207 
208 sal_Bool BitmapEx::operator==( const BitmapEx& rBitmapEx ) const
209 {
210 	if( eTransparent != rBitmapEx.eTransparent )
211 		return sal_False;
212 
213 	if( aBitmap != rBitmapEx.aBitmap )
214 		return sal_False;
215 
216 	if( aBitmapSize != rBitmapEx.aBitmapSize )
217 		return sal_False;
218 
219 	if( eTransparent == TRANSPARENT_NONE )
220 		return sal_True;
221 
222 	if( eTransparent == TRANSPARENT_COLOR )
223 		return aTransparentColor == rBitmapEx.aTransparentColor;
224 
225 	return( ( aMask == rBitmapEx.aMask ) && ( bAlpha == rBitmapEx.bAlpha ) );
226 }
227 
228 // ------------------------------------------------------------------
229 
230 sal_Bool BitmapEx::IsEqual( const BitmapEx& rBmpEx ) const
231 {
232 	return( rBmpEx.eTransparent == eTransparent &&
233 			rBmpEx.bAlpha == bAlpha &&
234 			rBmpEx.aBitmap.IsEqual( aBitmap ) &&
235 			rBmpEx.aMask.IsEqual( aMask ) );
236 }
237 
238 // ------------------------------------------------------------------
239 
240 sal_Bool BitmapEx::IsEmpty() const
241 {
242 	return( aBitmap.IsEmpty() && aMask.IsEmpty() );
243 }
244 
245 // ------------------------------------------------------------------
246 
247 void BitmapEx::SetEmpty()
248 {
249 	aBitmap.SetEmpty();
250 	aMask.SetEmpty();
251 	eTransparent = TRANSPARENT_NONE;
252 	bAlpha = sal_False;
253 }
254 
255 // ------------------------------------------------------------------
256 
257 void BitmapEx::Clear()
258 {
259 	SetEmpty();
260 }
261 
262 // ------------------------------------------------------------------
263 
264 sal_Bool BitmapEx::IsTransparent() const
265 {
266 	return( eTransparent != TRANSPARENT_NONE );
267 }
268 
269 // ------------------------------------------------------------------
270 
271 sal_Bool BitmapEx::IsAlpha() const
272 {
273 	return( IsTransparent() && bAlpha );
274 }
275 
276 // ------------------------------------------------------------------
277 
278 Bitmap BitmapEx::GetBitmap( const Color* pTransReplaceColor ) const
279 {
280 	Bitmap aRetBmp( aBitmap );
281 
282 	if( pTransReplaceColor && ( eTransparent != TRANSPARENT_NONE ) )
283 	{
284 		Bitmap aTempMask;
285 
286 		if( eTransparent == TRANSPARENT_COLOR )
287 			aTempMask = aBitmap.CreateMask( aTransparentColor );
288 		else
289 			aTempMask = aMask;
290 
291 		if( !IsAlpha() )
292 			aRetBmp.Replace( aTempMask, *pTransReplaceColor );
293 		else
294 			aRetBmp.Replace( GetAlpha(), *pTransReplaceColor );
295 	}
296 
297 	return aRetBmp;
298 }
299 
300 // ------------------------------------------------------------------
301 
302 BitmapEx BitmapEx::GetColorTransformedBitmapEx( BmpColorMode eColorMode ) const
303 {
304 	BitmapEx aRet;
305 
306 	if( BMP_COLOR_HIGHCONTRAST == eColorMode )
307 	{
308 		aRet = *this;
309 		aRet.aBitmap = aBitmap.GetColorTransformedBitmap( eColorMode );
310 	}
311 	else if( BMP_COLOR_MONOCHROME_BLACK == eColorMode ||
312 			 BMP_COLOR_MONOCHROME_WHITE == eColorMode )
313 	{
314 		aRet = *this;
315 		aRet.aBitmap = aRet.aBitmap.GetColorTransformedBitmap( eColorMode );
316 
317 		if( !aRet.aMask.IsEmpty() )
318 		{
319 			aRet.aMask.CombineSimple( aRet.aBitmap, BMP_COMBINE_OR );
320 			aRet.aBitmap.Erase( ( BMP_COLOR_MONOCHROME_BLACK == eColorMode ) ? COL_BLACK : COL_WHITE );
321 
322             DBG_ASSERT( aRet.aBitmap.GetSizePixel() == aRet.aMask.GetSizePixel(),
323                         "BitmapEx::GetColorTransformedBitmapEx(): size mismatch for bitmap and alpha mask." );
324 		}
325 	}
326 
327 	return aRet;
328 }
329 
330 // ------------------------------------------------------------------
331 
332 Bitmap BitmapEx::GetMask() const
333 {
334 	Bitmap aRet( aMask );
335 
336 	if( IsAlpha() )
337 		aRet.ImplMakeMono( 255 );
338 
339 	return aRet;
340 }
341 
342 // ------------------------------------------------------------------
343 
344 AlphaMask BitmapEx::GetAlpha() const
345 {
346 	AlphaMask aAlpha;
347 
348 	if( IsAlpha() )
349 		aAlpha.ImplSetBitmap( aMask );
350 	else
351 		aAlpha = aMask;
352 
353 	return aAlpha;
354 }
355 
356 // ------------------------------------------------------------------
357 
358 sal_uLong BitmapEx::GetSizeBytes() const
359 {
360 	sal_uLong nSizeBytes = aBitmap.GetSizeBytes();
361 
362 	if( eTransparent == TRANSPARENT_BITMAP )
363 		nSizeBytes += aMask.GetSizeBytes();
364 
365 	return nSizeBytes;
366 }
367 
368 // ------------------------------------------------------------------
369 
370 sal_uLong BitmapEx::GetChecksum() const
371 {
372 	sal_uInt32	nCrc = aBitmap.GetChecksum();
373 	SVBT32		aBT32;
374 
375 	UInt32ToSVBT32( (long) eTransparent, aBT32 );
376 	nCrc = rtl_crc32( nCrc, aBT32, 4 );
377 
378 	UInt32ToSVBT32( (long) bAlpha, aBT32 );
379 	nCrc = rtl_crc32( nCrc, aBT32, 4 );
380 
381 	if( ( TRANSPARENT_BITMAP == eTransparent ) && !aMask.IsEmpty() )
382 	{
383 		UInt32ToSVBT32( aMask.GetChecksum(), aBT32 );
384 		nCrc = rtl_crc32( nCrc, aBT32, 4 );
385 	}
386 
387 	return nCrc;
388 }
389 
390 // ------------------------------------------------------------------
391 
392 void BitmapEx::SetSizePixel( const Size& rNewSize, sal_uInt32 nScaleFlag )
393 {
394     if(GetSizePixel() != rNewSize)
395     {
396         Scale( rNewSize, nScaleFlag );
397     }
398 }
399 
400 // ------------------------------------------------------------------
401 
402 sal_Bool BitmapEx::Invert()
403 {
404 	sal_Bool bRet = sal_False;
405 
406 	if( !!aBitmap )
407 	{
408 		bRet = aBitmap.Invert();
409 
410 		if( bRet && ( eTransparent == TRANSPARENT_COLOR ) )
411 			aTransparentColor = BitmapColor( aTransparentColor ).Invert();
412 	}
413 
414 	return bRet;
415 }
416 
417 // ------------------------------------------------------------------
418 
419 sal_Bool BitmapEx::Mirror( sal_uLong nMirrorFlags )
420 {
421 	sal_Bool bRet = sal_False;
422 
423 	if( !!aBitmap )
424 	{
425 		bRet = aBitmap.Mirror( nMirrorFlags );
426 
427 		if( bRet && ( eTransparent == TRANSPARENT_BITMAP ) && !!aMask )
428 			aMask.Mirror( nMirrorFlags );
429 	}
430 
431 	return bRet;
432 }
433 
434 // ------------------------------------------------------------------
435 
436 sal_Bool BitmapEx::Scale( const double& rScaleX, const double& rScaleY, sal_uInt32 nScaleFlag )
437 {
438 	sal_Bool bRet = sal_False;
439 
440 	if( !!aBitmap )
441 	{
442 		bRet = aBitmap.Scale( rScaleX, rScaleY, nScaleFlag );
443 
444 		if( bRet && ( eTransparent == TRANSPARENT_BITMAP ) && !!aMask )
445         {
446 			aMask.Scale( rScaleX, rScaleY, nScaleFlag );
447         }
448 
449 		aBitmapSize = aBitmap.GetSizePixel();
450 
451         DBG_ASSERT( !aMask || aBitmap.GetSizePixel() == aMask.GetSizePixel(),
452                     "BitmapEx::Scale(): size mismatch for bitmap and alpha mask." );
453 	}
454 
455 	return bRet;
456 }
457 
458 // ------------------------------------------------------------------------
459 
460 sal_Bool BitmapEx::Scale( const Size& rNewSize, sal_uInt32 nScaleFlag )
461 {
462 	sal_Bool bRet;
463 
464 	if( aBitmapSize.Width() && aBitmapSize.Height() )
465 	{
466 		bRet = Scale( (double) rNewSize.Width() / aBitmapSize.Width(),
467 					  (double) rNewSize.Height() / aBitmapSize.Height(),
468 					  nScaleFlag );
469 	}
470 	else
471 		bRet = sal_True;
472 
473 	return bRet;
474 }
475 
476 // ------------------------------------------------------------------
477 
478 sal_Bool BitmapEx::Rotate( long nAngle10, const Color& rFillColor )
479 {
480 	sal_Bool bRet = sal_False;
481 
482 	if( !!aBitmap )
483 	{
484 		const sal_Bool bTransRotate = ( Color( COL_TRANSPARENT ) == rFillColor );
485 
486 		if( bTransRotate )
487 		{
488 			if( eTransparent == TRANSPARENT_COLOR )
489 				bRet = aBitmap.Rotate( nAngle10, aTransparentColor );
490 			else
491 			{
492 				bRet = aBitmap.Rotate( nAngle10, COL_BLACK );
493 
494 				if( eTransparent == TRANSPARENT_NONE )
495 				{
496 					aMask = Bitmap( aBitmapSize, 1 );
497 					aMask.Erase( COL_BLACK );
498 					eTransparent = TRANSPARENT_BITMAP;
499 				}
500 
501 				if( bRet && !!aMask )
502 					aMask.Rotate( nAngle10, COL_WHITE );
503 			}
504 		}
505 		else
506 		{
507 			bRet = aBitmap.Rotate( nAngle10, rFillColor );
508 
509 			if( bRet && ( eTransparent == TRANSPARENT_BITMAP ) && !!aMask )
510 				aMask.Rotate( nAngle10, COL_WHITE );
511 		}
512 
513 		aBitmapSize = aBitmap.GetSizePixel();
514 
515         DBG_ASSERT( !aMask || aBitmap.GetSizePixel() == aMask.GetSizePixel(),
516                     "BitmapEx::Rotate(): size mismatch for bitmap and alpha mask." );
517 	}
518 
519 	return bRet;
520 }
521 
522 // ------------------------------------------------------------------
523 
524 sal_Bool BitmapEx::Crop( const Rectangle& rRectPixel )
525 {
526 	sal_Bool bRet = sal_False;
527 
528 	if( !!aBitmap )
529 	{
530 		bRet = aBitmap.Crop( rRectPixel );
531 
532 		if( bRet && ( eTransparent == TRANSPARENT_BITMAP ) && !!aMask )
533 			aMask.Crop( rRectPixel );
534 
535 		aBitmapSize = aBitmap.GetSizePixel();
536 
537         DBG_ASSERT( !aMask || aBitmap.GetSizePixel() == aMask.GetSizePixel(),
538                     "BitmapEx::Crop(): size mismatch for bitmap and alpha mask." );
539 	}
540 
541 	return bRet;
542 }
543 
544 // ------------------------------------------------------------------
545 
546 sal_Bool BitmapEx::Convert( BmpConversion eConversion )
547 {
548 	return( !!aBitmap ? aBitmap.Convert( eConversion ) : sal_False );
549 }
550 
551 // ------------------------------------------------------------------
552 
553 sal_Bool BitmapEx::ReduceColors( sal_uInt16 nNewColorCount, BmpReduce eReduce )
554 {
555 	return( !!aBitmap ? aBitmap.ReduceColors( nNewColorCount, eReduce ) : sal_False );
556 }
557 
558 // ------------------------------------------------------------------
559 
560 sal_Bool BitmapEx::Expand( sal_uLong nDX, sal_uLong nDY, const Color* pInitColor, sal_Bool bExpandTransparent )
561 {
562 	sal_Bool bRet = sal_False;
563 
564 	if( !!aBitmap )
565 	{
566 		bRet = aBitmap.Expand( nDX, nDY, pInitColor );
567 
568 		if( bRet && ( eTransparent == TRANSPARENT_BITMAP ) && !!aMask )
569 		{
570 			Color aColor( bExpandTransparent ? COL_WHITE : COL_BLACK );
571 			aMask.Expand( nDX, nDY, &aColor );
572 		}
573 
574 		aBitmapSize = aBitmap.GetSizePixel();
575 
576         DBG_ASSERT( !aMask || aBitmap.GetSizePixel() == aMask.GetSizePixel(),
577                     "BitmapEx::Expand(): size mismatch for bitmap and alpha mask." );
578 	}
579 
580 	return bRet;
581 }
582 
583 // ------------------------------------------------------------------
584 
585 sal_Bool BitmapEx::CopyPixel( const Rectangle& rRectDst, const Rectangle& rRectSrc,
586 						  const BitmapEx* pBmpExSrc )
587 {
588 	sal_Bool bRet = sal_False;
589 
590 	if( !pBmpExSrc || pBmpExSrc->IsEmpty() )
591 	{
592 		if( !aBitmap.IsEmpty() )
593 		{
594 			bRet = aBitmap.CopyPixel( rRectDst, rRectSrc );
595 
596 			if( bRet && ( eTransparent == TRANSPARENT_BITMAP ) && !!aMask )
597 				aMask.CopyPixel( rRectDst, rRectSrc );
598 		}
599 	}
600 	else
601 	{
602 		if( !aBitmap.IsEmpty() )
603 		{
604 			bRet = aBitmap.CopyPixel( rRectDst, rRectSrc, &pBmpExSrc->aBitmap );
605 
606 			if( bRet )
607 			{
608 				if( pBmpExSrc->IsAlpha() )
609 				{
610 					if( IsAlpha() )
611                         // cast to use the optimized AlphaMask::CopyPixel
612 						((AlphaMask*) &aMask)->CopyPixel( rRectDst, rRectSrc, (AlphaMask*)&pBmpExSrc->aMask );
613 					else if( IsTransparent() )
614 					{
615 						AlphaMask* pAlpha = new AlphaMask( aMask );
616 
617 						aMask = pAlpha->ImplGetBitmap();
618 						delete pAlpha;
619 						bAlpha = sal_True;
620 						aMask.CopyPixel( rRectDst, rRectSrc, &pBmpExSrc->aMask );
621 					}
622 					else
623 					{
624 						sal_uInt8	cBlack = 0;
625 						AlphaMask*	pAlpha = new AlphaMask( GetSizePixel(), &cBlack );
626 
627 						aMask = pAlpha->ImplGetBitmap();
628 						delete pAlpha;
629 						eTransparent = TRANSPARENT_BITMAP;
630 						bAlpha = sal_True;
631 						aMask.CopyPixel( rRectDst, rRectSrc, &pBmpExSrc->aMask );
632 					}
633 				}
634 				else if( pBmpExSrc->IsTransparent() )
635 				{
636 					if( IsAlpha() )
637 					{
638 						AlphaMask aAlpha( pBmpExSrc->aMask );
639 						aMask.CopyPixel( rRectDst, rRectSrc, &aAlpha.ImplGetBitmap() );
640 					}
641 					else if( IsTransparent() )
642 						aMask.CopyPixel( rRectDst, rRectSrc, &pBmpExSrc->aMask );
643 					else
644 					{
645 						aMask = Bitmap( GetSizePixel(), 1 );
646 						aMask.Erase( Color( COL_BLACK ) );
647 						eTransparent = TRANSPARENT_BITMAP;
648 						aMask.CopyPixel( rRectDst, rRectSrc, &pBmpExSrc->aMask );
649 					}
650 				}
651                 else if( IsAlpha() )
652                 {
653                     sal_uInt8	      cBlack = 0;
654                     const AlphaMask   aAlphaSrc( pBmpExSrc->GetSizePixel(), &cBlack );
655 
656                     aMask.CopyPixel( rRectDst, rRectSrc, &aAlphaSrc.ImplGetBitmap() );
657                 }
658                 else if( IsTransparent() )
659                 {
660                     Bitmap aMaskSrc( pBmpExSrc->GetSizePixel(), 1 );
661 
662                     aMaskSrc.Erase( Color( COL_BLACK ) );
663                     aMask.CopyPixel( rRectDst, rRectSrc, &aMaskSrc );
664                 }
665 			}
666 		}
667 	}
668 
669 	return bRet;
670 }
671 
672 // ------------------------------------------------------------------
673 
674 sal_Bool BitmapEx::Erase( const Color& rFillColor )
675 {
676 	sal_Bool bRet = sal_False;
677 
678 	if( !!aBitmap )
679 	{
680 		bRet = aBitmap.Erase( rFillColor );
681 
682 		if( bRet && ( eTransparent == TRANSPARENT_BITMAP ) && !!aMask )
683 		{
684             // #104416# Respect transparency on fill color
685             if( rFillColor.GetTransparency() )
686             {
687                 const Color aFill( rFillColor.GetTransparency(), rFillColor.GetTransparency(), rFillColor.GetTransparency() );
688                 aMask.Erase( aFill );
689             }
690             else
691             {
692                 const Color aBlack( COL_BLACK );
693                 aMask.Erase( aBlack );
694             }
695 		}
696 	}
697 
698 	return bRet;
699 }
700 
701 // ------------------------------------------------------------------
702 
703 sal_Bool BitmapEx::Dither( sal_uLong nDitherFlags )
704 {
705 	return( !!aBitmap ? aBitmap.Dither( nDitherFlags ) : sal_False );
706 }
707 
708 // ------------------------------------------------------------------
709 
710 sal_Bool BitmapEx::Replace( const Color& rSearchColor, const Color& rReplaceColor, sal_uLong nTol )
711 {
712 	return( !!aBitmap ? aBitmap.Replace( rSearchColor, rReplaceColor, nTol ) : sal_False );
713 }
714 
715 // ------------------------------------------------------------------
716 
717 sal_Bool BitmapEx::Replace( const Color* pSearchColors, const Color* pReplaceColors, sal_uLong nColorCount, const sal_uLong* pTols )
718 {
719 	return( !!aBitmap ? aBitmap.Replace( pSearchColors, pReplaceColors, nColorCount, (sal_uLong*) pTols ) : sal_False );
720 }
721 
722 // ------------------------------------------------------------------
723 
724 sal_Bool BitmapEx::Adjust( short nLuminancePercent, short nContrastPercent,
725 					   short nChannelRPercent, short nChannelGPercent, short nChannelBPercent,
726 					   double fGamma, sal_Bool bInvert )
727 {
728 	return( !!aBitmap ? aBitmap.Adjust( nLuminancePercent, nContrastPercent,
729 										nChannelRPercent, nChannelGPercent, nChannelBPercent,
730 										fGamma, bInvert ) : sal_False );
731 }
732 
733 // ------------------------------------------------------------------
734 
735 sal_Bool BitmapEx::Filter( BmpFilter eFilter, const BmpFilterParam* pFilterParam, const Link* pProgress )
736 {
737 	return( !!aBitmap ? aBitmap.Filter( eFilter, pFilterParam, pProgress ) : sal_False );
738 }
739 
740 // ------------------------------------------------------------------
741 
742 void BitmapEx::Draw( OutputDevice* pOutDev, const Point& rDestPt ) const
743 {
744 	pOutDev->DrawBitmapEx( rDestPt, *this );
745 }
746 
747 // ------------------------------------------------------------------
748 
749 void BitmapEx::Draw( OutputDevice* pOutDev,
750 					 const Point& rDestPt, const Size& rDestSize ) const
751 {
752 	pOutDev->DrawBitmapEx( rDestPt, rDestSize, *this );
753 }
754 
755 // ------------------------------------------------------------------
756 
757 void BitmapEx::Draw( OutputDevice* pOutDev,
758 					 const Point& rDestPt, const Size& rDestSize,
759 					 const Point& rSrcPtPixel, const Size& rSrcSizePixel ) const
760 {
761 	pOutDev->DrawBitmapEx( rDestPt, rDestSize, rSrcPtPixel, rSrcSizePixel, *this );
762 }
763 
764 // ------------------------------------------------------------------
765 
766 sal_uInt8 BitmapEx::GetTransparency(sal_Int32 nX, sal_Int32 nY) const
767 {
768     sal_uInt8 nTransparency(0xff);
769 
770     if(!aBitmap.IsEmpty())
771     {
772         if(nX >= 0 && nX < aBitmapSize.Width() && nY >= 0 && nY < aBitmapSize.Height())
773         {
774             switch(eTransparent)
775             {
776                 case TRANSPARENT_NONE:
777                 {
778                     // not transparent, ergo all covered
779                     nTransparency = 0x00;
780                     break;
781                 }
782                 case TRANSPARENT_COLOR:
783                 {
784                     Bitmap aTestBitmap(aBitmap);
785                     BitmapReadAccess* pRead = aTestBitmap.AcquireReadAccess();
786 
787                     if(pRead)
788                     {
789                         const Color aColor = pRead->GetColor(nY, nX);
790 
791                         // if color is not equal to TransparentColor, we are not transparent
792                         if(aColor != aTransparentColor)
793                         {
794                             nTransparency = 0x00;
795                         }
796 
797                         aTestBitmap.ReleaseAccess(pRead);
798                     }
799                     break;
800                 }
801                 case TRANSPARENT_BITMAP:
802                 {
803                     if(!aMask.IsEmpty())
804                     {
805                         Bitmap aTestBitmap(aMask);
806                         BitmapReadAccess* pRead = aTestBitmap.AcquireReadAccess();
807 
808                         if(pRead)
809                         {
810                             const BitmapColor aBitmapColor(pRead->GetPixel(nY, nX));
811 
812                             if(bAlpha)
813                             {
814                                 nTransparency = aBitmapColor.GetIndex();
815                             }
816                             else
817                             {
818                                 if(0x00 == aBitmapColor.GetIndex())
819                                 {
820                                     nTransparency = 0x00;
821                                 }
822                             }
823 
824                             aTestBitmap.ReleaseAccess(pRead);
825                         }
826                     }
827                     break;
828                 }
829             }
830         }
831     }
832 
833     return nTransparency;
834 }
835 
836 // ------------------------------------------------------------------
837 
838 namespace
839 {
840 	void impSmoothPoint(BitmapColor& rValue, const basegfx::B2DPoint& rSource, sal_Int32 nIntX, sal_Int32 nIntY, BitmapReadAccess& rRead)
841 	{
842 		double fDeltaX(rSource.getX() - nIntX);
843 		double fDeltaY(rSource.getY() - nIntY);
844 		sal_Int32 nIndX(0L);
845 		sal_Int32 nIndY(0L);
846 
847 		if(fDeltaX > 0.0 && nIntX + 1L < rRead.Width())
848 		{
849 			nIndX++;
850 		}
851 		else if(fDeltaX < 0.0 && nIntX >= 1L)
852 		{
853 			fDeltaX = -fDeltaX;
854 			nIndX--;
855 		}
856 
857 		if(fDeltaY > 0.0 && nIntY + 1L < rRead.Height())
858 		{
859 			nIndY++;
860 		}
861 		else if(fDeltaY < 0.0 && nIntY >= 1L)
862 		{
863 			fDeltaY = -fDeltaY;
864 			nIndY--;
865 		}
866 
867 		if(nIndX || nIndY)
868 		{
869 			const double fColorToReal(1.0 / 255.0);
870 			double fR(rValue.GetRed() * fColorToReal);
871 			double fG(rValue.GetGreen() * fColorToReal);
872 			double fB(rValue.GetBlue() * fColorToReal);
873 			double fRBottom(0.0), fGBottom(0.0), fBBottom(0.0);
874 
875 			if(nIndX)
876 			{
877 				const double fMulA(fDeltaX * fColorToReal);
878 				double fMulB(1.0 - fDeltaX);
879 				const BitmapColor aTopPartner(rRead.GetColor(nIntY, nIntX + nIndX));
880 
881 				fR = (fR * fMulB) + (aTopPartner.GetRed() * fMulA);
882 				fG = (fG * fMulB) + (aTopPartner.GetGreen() * fMulA);
883 				fB = (fB * fMulB) + (aTopPartner.GetBlue() * fMulA);
884 
885 				if(nIndY)
886 				{
887 					fMulB *= fColorToReal;
888 					const BitmapColor aBottom(rRead.GetColor(nIntY + nIndY, nIntX));
889 					const BitmapColor aBottomPartner(rRead.GetColor(nIntY + nIndY, nIntX + nIndX));
890 
891 					fRBottom = (aBottom.GetRed() * fMulB) + (aBottomPartner.GetRed() * fMulA);
892 					fGBottom = (aBottom.GetGreen() * fMulB) + (aBottomPartner.GetGreen() * fMulA);
893 					fBBottom = (aBottom.GetBlue() * fMulB) + (aBottomPartner.GetBlue() * fMulA);
894 				}
895 			}
896 
897 			if(nIndY)
898 			{
899 				if(!nIndX)
900 				{
901 					const BitmapColor aBottom(rRead.GetColor(nIntY + nIndY, nIntX));
902 
903 					fRBottom = aBottom.GetRed() * fColorToReal;
904 					fGBottom = aBottom.GetGreen() * fColorToReal;
905 					fBBottom = aBottom.GetBlue() * fColorToReal;
906 				}
907 
908 				const double fMulB(1.0 - fDeltaY);
909 
910 				fR = (fR * fMulB) + (fRBottom * fDeltaY);
911 				fG = (fG * fMulB) + (fGBottom * fDeltaY);
912 				fB = (fB * fMulB) + (fBBottom * fDeltaY);
913 			}
914 
915 			rValue.SetRed((sal_uInt8)(fR * 255.0));
916 			rValue.SetGreen((sal_uInt8)(fG * 255.0));
917 			rValue.SetBlue((sal_uInt8)(fB * 255.0));
918 		}
919 	}
920 
921 	Bitmap impTransformBitmap(
922         const Bitmap& rSource,
923         const Size aDestinationSize,
924         const basegfx::B2DHomMatrix& rTransform,
925         bool bSmooth)
926 	{
927         Bitmap aDestination(aDestinationSize, 24);
928         BitmapWriteAccess* pWrite = aDestination.AcquireWriteAccess();
929 
930 		if(pWrite)
931 		{
932 			const Size aContentSizePixel(rSource.GetSizePixel());
933 			BitmapReadAccess* pRead = (const_cast< Bitmap& >(rSource)).AcquireReadAccess();
934 
935 			if(pRead)
936 			{
937 				const Size aDestinationSizePixel(aDestination.GetSizePixel());
938 				bool bWorkWithIndex(rSource.GetBitCount() <= 8);
939 				BitmapColor aOutside(BitmapColor(0xff, 0xff, 0xff));
940 
941 				for(sal_Int32 y(0L); y < aDestinationSizePixel.getHeight(); y++)
942 				{
943 					for(sal_Int32 x(0L); x < aDestinationSizePixel.getWidth(); x++)
944 					{
945 						const basegfx::B2DPoint aSourceCoor(rTransform * basegfx::B2DPoint(x, y));
946 						const sal_Int32 nIntX(basegfx::fround(aSourceCoor.getX()));
947 
948 						if(nIntX >= 0L && nIntX < aContentSizePixel.getWidth())
949 						{
950 							const sal_Int32 nIntY(basegfx::fround(aSourceCoor.getY()));
951 
952 							if(nIntY >= 0L && nIntY < aContentSizePixel.getHeight())
953 							{
954                                 // inside pixel
955                                 BitmapColor aValue;
956 
957                                 if(bWorkWithIndex)
958                                 {
959                                     aValue = pRead->GetPaletteColor(pRead->GetPixelIndex(nIntY, nIntX));
960                                 }
961                                 else
962                                 {
963                                     aValue = pRead->GetPixel(nIntY, nIntX);
964                                 }
965 
966                                 if(bSmooth)
967                                 {
968                                     impSmoothPoint(aValue, aSourceCoor, nIntX, nIntY, *pRead);
969                                 }
970 
971                                 pWrite->SetPixel(y, x, aValue);
972                                 continue;
973 							}
974 						}
975 
976 						// here are outside pixels. Complete mask
977 						if(bWorkWithIndex)
978 						{
979 							pWrite->SetPixel(y, x, aOutside);
980 						}
981 					}
982 				}
983 
984 				delete pRead;
985 			}
986 
987 			delete pWrite;
988 		}
989 
990         rSource.AdaptBitCount(aDestination);
991 
992         return aDestination;
993 	}
994 } // end of anonymous namespace
995 BitmapEx BitmapEx::TransformBitmapEx(
996     double fWidth,
997     double fHeight,
998     const basegfx::B2DHomMatrix& rTransformation) const
999 {
1000     if(fWidth <= 1 || fHeight <= 1)
1001         return BitmapEx();
1002 
1003     // force destination to 24 bit, we want to smooth output
1004     const Size aDestinationSize(basegfx::fround(fWidth), basegfx::fround(fHeight));
1005     static bool bDoSmoothAtAll(true);
1006     const Bitmap aDestination(impTransformBitmap(GetBitmap(), aDestinationSize, rTransformation, bDoSmoothAtAll));
1007 
1008     // create mask
1009     if(IsTransparent())
1010     {
1011         if(IsAlpha())
1012         {
1013             const Bitmap aAlpha(impTransformBitmap(GetAlpha().GetBitmap(), aDestinationSize, rTransformation, bDoSmoothAtAll));
1014             return BitmapEx(aDestination, AlphaMask(aAlpha));
1015         }
1016         else
1017         {
1018             const Bitmap aMask(impTransformBitmap(GetMask(), aDestinationSize, rTransformation, false));
1019             return BitmapEx(aDestination, aMask);
1020         }
1021     }
1022 
1023     return BitmapEx(aDestination);
1024 }
1025 
1026 // ------------------------------------------------------------------
1027 
1028 BitmapEx BitmapEx::getTransformed(
1029     const basegfx::B2DHomMatrix& rTransformation,
1030     double fMaximumArea) const
1031 {
1032     BitmapEx aRetval;
1033 
1034     if(IsEmpty())
1035         return aRetval;
1036 
1037     const sal_uInt32 nSourceWidth(GetSizePixel().Width());
1038     const sal_uInt32 nSourceHeight(GetSizePixel().Height());
1039 
1040     if(!nSourceWidth || !nSourceHeight)
1041         return aRetval;
1042 
1043     // Get dest range
1044     basegfx::B2DRange aOutlineRange(0.0, 0.0, 1.0, 1.0);
1045     aOutlineRange.transform(rTransformation);
1046 
1047     // get target size
1048     double fWidth(aOutlineRange.getWidth());
1049     double fHeight(aOutlineRange.getHeight());
1050 
1051     if(fWidth < 1.0 || fHeight < 1.0)
1052         return aRetval;
1053 
1054     // test if discrete size (pixel) maybe too big and limit it
1055     const double fArea(fWidth * fHeight);
1056     const bool bNeedToReduce(fArea > fMaximumArea);
1057     double fReduceFactor(1.0);
1058 
1059     if(bNeedToReduce)
1060     {
1061         fReduceFactor = sqrt(fMaximumArea / fArea);
1062         fWidth *= fReduceFactor;
1063         fHeight *= fReduceFactor;
1064     }
1065 
1066     // Build complete transform from source pixels to target pixels.
1067     // Start by scaling from source pixel size to unit coordinates
1068     basegfx::B2DHomMatrix aTransform(
1069         basegfx::tools::createScaleB2DHomMatrix(
1070             1.0 / nSourceWidth,
1071             1.0 / nSourceHeight));
1072 
1073     // multiply with given transform which leads from unit coordinates inside
1074     // aOutlineRange
1075     aTransform = rTransformation * aTransform;
1076 
1077     // substract top-left of aOutlineRange
1078     aTransform.translate(-aOutlineRange.getMinX(), -aOutlineRange.getMinY());
1079 
1080     // scale to target pixels (if needed)
1081     if(bNeedToReduce)
1082     {
1083         aTransform.scale(fReduceFactor, fReduceFactor);
1084     }
1085 
1086     // invert to get transformation from target pixel coordiates to source pixels
1087     aTransform.invert();
1088 
1089     // create bitmap using source, destination and linear back-transformation
1090     aRetval = TransformBitmapEx(fWidth, fHeight, aTransform);
1091 
1092     return aRetval;
1093 }
1094 
1095 // ------------------------------------------------------------------
1096 
1097 BitmapEx BitmapEx::ModifyBitmapEx(const basegfx::BColorModifierStack& rBColorModifierStack) const
1098 {
1099 	Bitmap aChangedBitmap(GetBitmap());
1100 	bool bDone(false);
1101 
1102 	for(sal_uInt32 a(rBColorModifierStack.count()); a && !bDone; )
1103 	{
1104 		const basegfx::BColorModifier& rModifier = rBColorModifierStack.getBColorModifier(--a);
1105 
1106 		switch(rModifier.getMode())
1107 		{
1108 			case basegfx::BCOLORMODIFYMODE_REPLACE :
1109 			{
1110 				// complete replace
1111 				if(IsTransparent())
1112 				{
1113 					// clear bitmap with dest color
1114 				    if(aChangedBitmap.GetBitCount() <= 8)
1115 				    {
1116                         // do NOT use erase; for e.g. 8bit Bitmaps, the nearest color to the given
1117                         // erase color is determined and used -> this may be different from what is
1118                         // wanted here. Better create a new bitmap with the needed color explicitely
1119                 		BitmapReadAccess* pReadAccess = aChangedBitmap.AcquireReadAccess();
1120                         OSL_ENSURE(pReadAccess, "Got no Bitmap ReadAccess ?!?");
1121 
1122                         if(pReadAccess)
1123                         {
1124     					    BitmapPalette aNewPalette(pReadAccess->GetPalette());
1125                             aNewPalette[0] = BitmapColor(Color(rModifier.getBColor()));
1126 	    				    aChangedBitmap = Bitmap(
1127                                 aChangedBitmap.GetSizePixel(),
1128                                 aChangedBitmap.GetBitCount(),
1129                                 &aNewPalette);
1130                             delete pReadAccess;
1131                         }
1132 				    }
1133 				    else
1134 				    {
1135 						aChangedBitmap.Erase(Color(rModifier.getBColor()));
1136                     }
1137 				}
1138 				else
1139 				{
1140 					// erase bitmap, caller will know to paint direct
1141 					aChangedBitmap.SetEmpty();
1142 				}
1143 
1144 				bDone = true;
1145 				break;
1146 			}
1147 
1148 			default : // BCOLORMODIFYMODE_INTERPOLATE, BCOLORMODIFYMODE_GRAY, BCOLORMODIFYMODE_BLACKANDWHITE
1149 			{
1150 				BitmapWriteAccess* pContent = aChangedBitmap.AcquireWriteAccess();
1151 
1152 				if(pContent)
1153 				{
1154 					const double fConvertColor(1.0 / 255.0);
1155 
1156 					for(sal_uInt32 y(0L); y < (sal_uInt32)pContent->Height(); y++)
1157 					{
1158 						for(sal_uInt32 x(0L); x < (sal_uInt32)pContent->Width(); x++)
1159 						{
1160 							const BitmapColor aBMCol(pContent->GetColor(y, x));
1161 							const basegfx::BColor aBSource(
1162 								(double)aBMCol.GetRed() * fConvertColor,
1163 								(double)aBMCol.GetGreen() * fConvertColor,
1164 								(double)aBMCol.GetBlue() * fConvertColor);
1165 							const basegfx::BColor aBDest(rModifier.getModifiedColor(aBSource));
1166 
1167 							pContent->SetPixel(y, x, BitmapColor(Color(aBDest)));
1168 						}
1169 					}
1170 
1171 					delete pContent;
1172 				}
1173 
1174 				break;
1175 			}
1176 		}
1177 	}
1178 
1179 	if(aChangedBitmap.IsEmpty())
1180 	{
1181 		return BitmapEx();
1182 	}
1183 	else
1184 	{
1185 		if(IsTransparent())
1186 		{
1187 			if(IsAlpha())
1188 			{
1189 				return BitmapEx(aChangedBitmap, GetAlpha());
1190 			}
1191 			else
1192 			{
1193 				return BitmapEx(aChangedBitmap, GetMask());
1194 			}
1195 		}
1196 		else
1197 		{
1198 			return BitmapEx(aChangedBitmap);
1199 		}
1200 	}
1201 }
1202 
1203 // ------------------------------------------------------------------
1204 // eof
1205