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