xref: /trunk/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