xref: /AOO41X/main/vcl/source/gdi/bitmapex.cxx (revision dd517d763d1590106211e60c61ad7d6551aa7b11)
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