xref: /AOO41X/main/vcl/source/gdi/bitmapex.cxx (revision 7b6b9ddb4b63a97ea0214b9472b5270bbf674949)
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(!rMask)
135     {
136         OSL_ENSURE(false, "Empty mask given (!)");
137     }
138     else if(rBmp.GetSizePixel() != rMask.GetSizePixel())
139     {
140         OSL_ENSURE(false, "Mask size differs from Bitmap size, corrected Mask (!)");
141         aMask.Scale(rBmp.GetSizePixel());
142     }
143 
144     // #105489# Ensure a mask is exactly one bit deep
145     if( !!aMask && aMask.GetBitCount() != 1 )
146     {
147         OSL_TRACE("BitmapEx: forced mask to monochrome");
148         aMask.ImplMakeMono( 255 );
149     }
150 }
151 
152 // ------------------------------------------------------------------
153 
154 BitmapEx::BitmapEx( const Bitmap& rBmp, const AlphaMask& rAlphaMask ) :
155         aBitmap         ( rBmp ),
156         aMask           ( rAlphaMask.ImplGetBitmap() ),
157         aBitmapSize     ( aBitmap.GetSizePixel() ),
158         eTransparent    ( !rAlphaMask ? TRANSPARENT_NONE : TRANSPARENT_BITMAP ),
159         bAlpha          ( !rAlphaMask ? sal_False : sal_True )
160 {
161     if(!rAlphaMask)
162     {
163         OSL_ENSURE(false, "Empty alpha given (!)");
164     }
165     else if(rBmp.GetSizePixel() != rAlphaMask.GetSizePixel())
166     {
167         OSL_ENSURE(false, "Alpha size differs from Bitmap size, corrected Mask (!)");
168         aMask.Scale(rBmp.GetSizePixel());
169     }
170 
171     // #i75531# the workaround below can go when
172     // X11SalGraphics::drawAlphaBitmap()'s render acceleration
173     // can handle the bitmap depth mismatch directly
174     if( aBitmap.GetBitCount() < aMask.GetBitCount() )
175         aBitmap.Convert( BMP_CONVERSION_24BIT );
176 }
177 
178 // ------------------------------------------------------------------
179 
180 BitmapEx::BitmapEx( const Bitmap& rBmp, const Color& rTransparentColor ) :
181         aBitmap             ( rBmp ),
182         aBitmapSize         ( aBitmap.GetSizePixel() ),
183         aTransparentColor   ( rTransparentColor ),
184         eTransparent        ( TRANSPARENT_BITMAP ),
185         bAlpha              ( sal_False )
186 {
187     aMask = aBitmap.CreateMask( aTransparentColor );
188 
189     DBG_ASSERT( rBmp.GetSizePixel() == aMask.GetSizePixel(),
190                 "BitmapEx::BitmapEx(): size mismatch for bitmap and alpha mask." );
191 }
192 
193 // ------------------------------------------------------------------
194 
195 BitmapEx::~BitmapEx()
196 {
197 }
198 
199 // ------------------------------------------------------------------
200 
201 // ------------------------------------------------------------------
202 
203 BitmapEx& BitmapEx::operator=( const BitmapEx& rBitmapEx )
204 {
205     if( &rBitmapEx != this )
206     {
207         aBitmap = rBitmapEx.aBitmap;
208         aMask = rBitmapEx.aMask;
209         aBitmapSize = rBitmapEx.aBitmapSize;
210         aTransparentColor = rBitmapEx.aTransparentColor;
211         eTransparent = rBitmapEx.eTransparent;
212         bAlpha = rBitmapEx.bAlpha;
213     }
214 
215     return *this;
216 }
217 
218 // ------------------------------------------------------------------
219 
220 sal_Bool BitmapEx::operator==( const BitmapEx& rBitmapEx ) const
221 {
222     if( eTransparent != rBitmapEx.eTransparent )
223         return sal_False;
224 
225     if( aBitmap != rBitmapEx.aBitmap )
226         return sal_False;
227 
228     if( aBitmapSize != rBitmapEx.aBitmapSize )
229         return sal_False;
230 
231     if( eTransparent == TRANSPARENT_NONE )
232         return sal_True;
233 
234     if( eTransparent == TRANSPARENT_COLOR )
235         return aTransparentColor == rBitmapEx.aTransparentColor;
236 
237     return( ( aMask == rBitmapEx.aMask ) && ( bAlpha == rBitmapEx.bAlpha ) );
238 }
239 
240 // ------------------------------------------------------------------
241 
242 sal_Bool BitmapEx::IsEqual( const BitmapEx& rBmpEx ) const
243 {
244     return( rBmpEx.eTransparent == eTransparent &&
245             rBmpEx.bAlpha == bAlpha &&
246             rBmpEx.aBitmap.IsEqual( aBitmap ) &&
247             rBmpEx.aMask.IsEqual( aMask ) );
248 }
249 
250 // ------------------------------------------------------------------
251 
252 sal_Bool BitmapEx::IsEmpty() const
253 {
254     return( aBitmap.IsEmpty() && aMask.IsEmpty() );
255 }
256 
257 // ------------------------------------------------------------------
258 
259 void BitmapEx::SetEmpty()
260 {
261     aBitmap.SetEmpty();
262     aMask.SetEmpty();
263     eTransparent = TRANSPARENT_NONE;
264     bAlpha = sal_False;
265 }
266 
267 // ------------------------------------------------------------------
268 
269 void BitmapEx::Clear()
270 {
271     SetEmpty();
272 }
273 
274 // ------------------------------------------------------------------
275 
276 sal_Bool BitmapEx::IsTransparent() const
277 {
278     return( eTransparent != TRANSPARENT_NONE );
279 }
280 
281 // ------------------------------------------------------------------
282 
283 sal_Bool BitmapEx::IsAlpha() const
284 {
285     return( IsTransparent() && bAlpha );
286 }
287 
288 // ------------------------------------------------------------------
289 
290 Bitmap BitmapEx::GetBitmap( const Color* pTransReplaceColor ) const
291 {
292     Bitmap aRetBmp( aBitmap );
293 
294     if( pTransReplaceColor && ( eTransparent != TRANSPARENT_NONE ) )
295     {
296         Bitmap aTempMask;
297 
298         if( eTransparent == TRANSPARENT_COLOR )
299             aTempMask = aBitmap.CreateMask( aTransparentColor );
300         else
301             aTempMask = aMask;
302 
303         if( !IsAlpha() )
304             aRetBmp.Replace( aTempMask, *pTransReplaceColor );
305         else
306             aRetBmp.Replace( GetAlpha(), *pTransReplaceColor );
307     }
308 
309     return aRetBmp;
310 }
311 
312 // ------------------------------------------------------------------
313 
314 BitmapEx BitmapEx::GetColorTransformedBitmapEx( BmpColorMode eColorMode ) const
315 {
316     BitmapEx aRet;
317 
318     if( BMP_COLOR_HIGHCONTRAST == eColorMode )
319     {
320         aRet = *this;
321         aRet.aBitmap = aBitmap.GetColorTransformedBitmap( eColorMode );
322     }
323     else if( BMP_COLOR_MONOCHROME_BLACK == eColorMode ||
324              BMP_COLOR_MONOCHROME_WHITE == eColorMode )
325     {
326         aRet = *this;
327         aRet.aBitmap = aRet.aBitmap.GetColorTransformedBitmap( eColorMode );
328 
329         if( !aRet.aMask.IsEmpty() )
330         {
331             aRet.aMask.CombineSimple( aRet.aBitmap, BMP_COMBINE_OR );
332             aRet.aBitmap.Erase( ( BMP_COLOR_MONOCHROME_BLACK == eColorMode ) ? COL_BLACK : COL_WHITE );
333 
334             DBG_ASSERT( aRet.aBitmap.GetSizePixel() == aRet.aMask.GetSizePixel(),
335                         "BitmapEx::GetColorTransformedBitmapEx(): size mismatch for bitmap and alpha mask." );
336         }
337     }
338 
339     return aRet;
340 }
341 
342 // ------------------------------------------------------------------
343 
344 Bitmap BitmapEx::GetMask() const
345 {
346     Bitmap aRet( aMask );
347 
348     if( IsAlpha() )
349         aRet.ImplMakeMono( 255 );
350 
351     return aRet;
352 }
353 
354 // ------------------------------------------------------------------
355 
356 AlphaMask BitmapEx::GetAlpha() const
357 {
358     AlphaMask aAlpha;
359 
360     if( IsAlpha() )
361         aAlpha.ImplSetBitmap( aMask );
362     else
363         aAlpha = aMask;
364 
365     return aAlpha;
366 }
367 
368 // ------------------------------------------------------------------
369 
370 sal_uLong BitmapEx::GetSizeBytes() const
371 {
372     sal_uLong nSizeBytes = aBitmap.GetSizeBytes();
373 
374     if( eTransparent == TRANSPARENT_BITMAP )
375         nSizeBytes += aMask.GetSizeBytes();
376 
377     return nSizeBytes;
378 }
379 
380 // ------------------------------------------------------------------
381 
382 sal_uLong BitmapEx::GetChecksum() const
383 {
384     sal_uInt32  nCrc = aBitmap.GetChecksum();
385     SVBT32      aBT32;
386 
387     UInt32ToSVBT32( (long) eTransparent, aBT32 );
388     nCrc = rtl_crc32( nCrc, aBT32, 4 );
389 
390     UInt32ToSVBT32( (long) bAlpha, aBT32 );
391     nCrc = rtl_crc32( nCrc, aBT32, 4 );
392 
393     if( ( TRANSPARENT_BITMAP == eTransparent ) && !aMask.IsEmpty() )
394     {
395         UInt32ToSVBT32( aMask.GetChecksum(), aBT32 );
396         nCrc = rtl_crc32( nCrc, aBT32, 4 );
397     }
398 
399     return nCrc;
400 }
401 
402 // ------------------------------------------------------------------
403 
404 void BitmapEx::SetSizePixel( const Size& rNewSize )
405 {
406     Scale( rNewSize );
407 }
408 
409 // ------------------------------------------------------------------
410 
411 sal_Bool BitmapEx::Invert()
412 {
413     sal_Bool bRet = sal_False;
414 
415     if( !!aBitmap )
416     {
417         bRet = aBitmap.Invert();
418 
419         if( bRet && ( eTransparent == TRANSPARENT_COLOR ) )
420             aTransparentColor = BitmapColor( aTransparentColor ).Invert();
421     }
422 
423     return bRet;
424 }
425 
426 // ------------------------------------------------------------------
427 
428 sal_Bool BitmapEx::Mirror( sal_uLong nMirrorFlags )
429 {
430     sal_Bool bRet = sal_False;
431 
432     if( !!aBitmap )
433     {
434         bRet = aBitmap.Mirror( nMirrorFlags );
435 
436         if( bRet && ( eTransparent == TRANSPARENT_BITMAP ) && !!aMask )
437             aMask.Mirror( nMirrorFlags );
438     }
439 
440     return bRet;
441 }
442 
443 // ------------------------------------------------------------------
444 
445 sal_Bool BitmapEx::Scale( const double& rScaleX, const double& rScaleY, sal_uLong nScaleFlag )
446 {
447     sal_Bool bRet = sal_False;
448 
449     if( !!aBitmap )
450     {
451         bRet = aBitmap.Scale( rScaleX, rScaleY, nScaleFlag );
452 
453         if( bRet && ( eTransparent == TRANSPARENT_BITMAP ) && !!aMask )
454             aMask.Scale( rScaleX, rScaleY, BMP_SCALE_FAST );
455 
456         aBitmapSize = aBitmap.GetSizePixel();
457 
458         DBG_ASSERT( !aMask || aBitmap.GetSizePixel() == aMask.GetSizePixel(),
459                     "BitmapEx::Scale(): size mismatch for bitmap and alpha mask." );
460     }
461 
462     return bRet;
463 }
464 
465 // ------------------------------------------------------------------------
466 
467 sal_Bool BitmapEx::Scale( const Size& rNewSize, sal_uLong nScaleFlag )
468 {
469     sal_Bool bRet;
470 
471     if( aBitmapSize.Width() && aBitmapSize.Height() )
472     {
473         bRet = Scale( (double) rNewSize.Width() / aBitmapSize.Width(),
474                       (double) rNewSize.Height() / aBitmapSize.Height(),
475                       nScaleFlag );
476     }
477     else
478         bRet = sal_True;
479 
480     return bRet;
481 }
482 
483 // ------------------------------------------------------------------
484 
485 sal_Bool BitmapEx::Rotate( long nAngle10, const Color& rFillColor )
486 {
487     sal_Bool bRet = sal_False;
488 
489     if( !!aBitmap )
490     {
491         const sal_Bool bTransRotate = ( Color( COL_TRANSPARENT ) == rFillColor );
492 
493         if( bTransRotate )
494         {
495             if( eTransparent == TRANSPARENT_COLOR )
496                 bRet = aBitmap.Rotate( nAngle10, aTransparentColor );
497             else
498             {
499                 bRet = aBitmap.Rotate( nAngle10, COL_BLACK );
500 
501                 if( eTransparent == TRANSPARENT_NONE )
502                 {
503                     aMask = Bitmap( aBitmapSize, 1 );
504                     aMask.Erase( COL_BLACK );
505                     eTransparent = TRANSPARENT_BITMAP;
506                 }
507 
508                 if( bRet && !!aMask )
509                     aMask.Rotate( nAngle10, COL_WHITE );
510             }
511         }
512         else
513         {
514             bRet = aBitmap.Rotate( nAngle10, rFillColor );
515 
516             if( bRet && ( eTransparent == TRANSPARENT_BITMAP ) && !!aMask )
517                 aMask.Rotate( nAngle10, COL_WHITE );
518         }
519 
520         aBitmapSize = aBitmap.GetSizePixel();
521 
522         DBG_ASSERT( !aMask || aBitmap.GetSizePixel() == aMask.GetSizePixel(),
523                     "BitmapEx::Rotate(): size mismatch for bitmap and alpha mask." );
524     }
525 
526     return bRet;
527 }
528 
529 // ------------------------------------------------------------------
530 
531 sal_Bool BitmapEx::Crop( const Rectangle& rRectPixel )
532 {
533     sal_Bool bRet = sal_False;
534 
535     if( !!aBitmap )
536     {
537         bRet = aBitmap.Crop( rRectPixel );
538 
539         if( bRet && ( eTransparent == TRANSPARENT_BITMAP ) && !!aMask )
540             aMask.Crop( rRectPixel );
541 
542         aBitmapSize = aBitmap.GetSizePixel();
543 
544         DBG_ASSERT( !aMask || aBitmap.GetSizePixel() == aMask.GetSizePixel(),
545                     "BitmapEx::Crop(): size mismatch for bitmap and alpha mask." );
546     }
547 
548     return bRet;
549 }
550 
551 // ------------------------------------------------------------------
552 
553 sal_Bool BitmapEx::Convert( BmpConversion eConversion )
554 {
555     return( !!aBitmap ? aBitmap.Convert( eConversion ) : sal_False );
556 }
557 
558 // ------------------------------------------------------------------
559 
560 sal_Bool BitmapEx::ReduceColors( sal_uInt16 nNewColorCount, BmpReduce eReduce )
561 {
562     return( !!aBitmap ? aBitmap.ReduceColors( nNewColorCount, eReduce ) : sal_False );
563 }
564 
565 // ------------------------------------------------------------------
566 
567 sal_Bool BitmapEx::Expand( sal_uLong nDX, sal_uLong nDY, const Color* pInitColor, sal_Bool bExpandTransparent )
568 {
569     sal_Bool bRet = sal_False;
570 
571     if( !!aBitmap )
572     {
573         bRet = aBitmap.Expand( nDX, nDY, pInitColor );
574 
575         if( bRet && ( eTransparent == TRANSPARENT_BITMAP ) && !!aMask )
576         {
577             Color aColor( bExpandTransparent ? COL_WHITE : COL_BLACK );
578             aMask.Expand( nDX, nDY, &aColor );
579         }
580 
581         aBitmapSize = aBitmap.GetSizePixel();
582 
583         DBG_ASSERT( !aMask || aBitmap.GetSizePixel() == aMask.GetSizePixel(),
584                     "BitmapEx::Expand(): size mismatch for bitmap and alpha mask." );
585     }
586 
587     return bRet;
588 }
589 
590 // ------------------------------------------------------------------
591 
592 sal_Bool BitmapEx::CopyPixel( const Rectangle& rRectDst, const Rectangle& rRectSrc,
593                           const BitmapEx* pBmpExSrc )
594 {
595     sal_Bool bRet = sal_False;
596 
597     if( !pBmpExSrc || pBmpExSrc->IsEmpty() )
598     {
599         if( !aBitmap.IsEmpty() )
600         {
601             bRet = aBitmap.CopyPixel( rRectDst, rRectSrc );
602 
603             if( bRet && ( eTransparent == TRANSPARENT_BITMAP ) && !!aMask )
604                 aMask.CopyPixel( rRectDst, rRectSrc );
605         }
606     }
607     else
608     {
609         if( !aBitmap.IsEmpty() )
610         {
611             bRet = aBitmap.CopyPixel( rRectDst, rRectSrc, &pBmpExSrc->aBitmap );
612 
613             if( bRet )
614             {
615                 if( pBmpExSrc->IsAlpha() )
616                 {
617                     if( IsAlpha() )
618                         // cast to use the optimized AlphaMask::CopyPixel
619                         ((AlphaMask*) &aMask)->CopyPixel( rRectDst, rRectSrc, (AlphaMask*)&pBmpExSrc->aMask );
620                     else if( IsTransparent() )
621                     {
622                         AlphaMask* pAlpha = new AlphaMask( aMask );
623 
624                         aMask = pAlpha->ImplGetBitmap();
625                         delete pAlpha;
626                         bAlpha = sal_True;
627                         aMask.CopyPixel( rRectDst, rRectSrc, &pBmpExSrc->aMask );
628                     }
629                     else
630                     {
631                         sal_uInt8   cBlack = 0;
632                         AlphaMask*  pAlpha = new AlphaMask( GetSizePixel(), &cBlack );
633 
634                         aMask = pAlpha->ImplGetBitmap();
635                         delete pAlpha;
636                         eTransparent = TRANSPARENT_BITMAP;
637                         bAlpha = sal_True;
638                         aMask.CopyPixel( rRectDst, rRectSrc, &pBmpExSrc->aMask );
639                     }
640                 }
641                 else if( pBmpExSrc->IsTransparent() )
642                 {
643                     if( IsAlpha() )
644                     {
645                         AlphaMask aAlpha( pBmpExSrc->aMask );
646                         aMask.CopyPixel( rRectDst, rRectSrc, &aAlpha.ImplGetBitmap() );
647                     }
648                     else if( IsTransparent() )
649                         aMask.CopyPixel( rRectDst, rRectSrc, &pBmpExSrc->aMask );
650                     else
651                     {
652                         aMask = Bitmap( GetSizePixel(), 1 );
653                         aMask.Erase( Color( COL_BLACK ) );
654                         eTransparent = TRANSPARENT_BITMAP;
655                         aMask.CopyPixel( rRectDst, rRectSrc, &pBmpExSrc->aMask );
656                     }
657                 }
658                 else if( IsAlpha() )
659                 {
660                     sal_uInt8         cBlack = 0;
661                     const AlphaMask   aAlphaSrc( pBmpExSrc->GetSizePixel(), &cBlack );
662 
663                     aMask.CopyPixel( rRectDst, rRectSrc, &aAlphaSrc.ImplGetBitmap() );
664                 }
665                 else if( IsTransparent() )
666                 {
667                     Bitmap aMaskSrc( pBmpExSrc->GetSizePixel(), 1 );
668 
669                     aMaskSrc.Erase( Color( COL_BLACK ) );
670                     aMask.CopyPixel( rRectDst, rRectSrc, &aMaskSrc );
671                 }
672             }
673         }
674     }
675 
676     return bRet;
677 }
678 
679 // ------------------------------------------------------------------
680 
681 sal_Bool BitmapEx::Erase( const Color& rFillColor )
682 {
683     sal_Bool bRet = sal_False;
684 
685     if( !!aBitmap )
686     {
687         bRet = aBitmap.Erase( rFillColor );
688 
689         if( bRet && ( eTransparent == TRANSPARENT_BITMAP ) && !!aMask )
690         {
691             // #104416# Respect transparency on fill color
692             if( rFillColor.GetTransparency() )
693             {
694                 const Color aFill( rFillColor.GetTransparency(), rFillColor.GetTransparency(), rFillColor.GetTransparency() );
695                 aMask.Erase( aFill );
696             }
697             else
698             {
699                 const Color aBlack( COL_BLACK );
700                 aMask.Erase( aBlack );
701             }
702         }
703     }
704 
705     return bRet;
706 }
707 
708 // ------------------------------------------------------------------
709 
710 sal_Bool BitmapEx::Dither( sal_uLong nDitherFlags )
711 {
712     return( !!aBitmap ? aBitmap.Dither( nDitherFlags ) : sal_False );
713 }
714 
715 // ------------------------------------------------------------------
716 
717 sal_Bool BitmapEx::Replace( const Color& rSearchColor, const Color& rReplaceColor, sal_uLong nTol )
718 {
719     return( !!aBitmap ? aBitmap.Replace( rSearchColor, rReplaceColor, nTol ) : sal_False );
720 }
721 
722 // ------------------------------------------------------------------
723 
724 sal_Bool BitmapEx::Replace( const Color* pSearchColors, const Color* pReplaceColors, sal_uLong nColorCount, const sal_uLong* pTols )
725 {
726     return( !!aBitmap ? aBitmap.Replace( pSearchColors, pReplaceColors, nColorCount, (sal_uLong*) pTols ) : sal_False );
727 }
728 
729 // ------------------------------------------------------------------
730 
731 sal_Bool BitmapEx::Adjust( short nLuminancePercent, short nContrastPercent,
732                        short nChannelRPercent, short nChannelGPercent, short nChannelBPercent,
733                        double fGamma, sal_Bool bInvert )
734 {
735     return( !!aBitmap ? aBitmap.Adjust( nLuminancePercent, nContrastPercent,
736                                         nChannelRPercent, nChannelGPercent, nChannelBPercent,
737                                         fGamma, bInvert ) : sal_False );
738 }
739 
740 // ------------------------------------------------------------------
741 
742 sal_Bool BitmapEx::Filter( BmpFilter eFilter, const BmpFilterParam* pFilterParam, const Link* pProgress )
743 {
744     return( !!aBitmap ? aBitmap.Filter( eFilter, pFilterParam, pProgress ) : sal_False );
745 }
746 
747 // ------------------------------------------------------------------
748 
749 void BitmapEx::Draw( OutputDevice* pOutDev, const Point& rDestPt ) const
750 {
751     pOutDev->DrawBitmapEx( rDestPt, *this );
752 }
753 
754 // ------------------------------------------------------------------
755 
756 void BitmapEx::Draw( OutputDevice* pOutDev,
757                      const Point& rDestPt, const Size& rDestSize ) const
758 {
759     pOutDev->DrawBitmapEx( rDestPt, rDestSize, *this );
760 }
761 
762 // ------------------------------------------------------------------
763 
764 void BitmapEx::Draw( OutputDevice* pOutDev,
765                      const Point& rDestPt, const Size& rDestSize,
766                      const Point& rSrcPtPixel, const Size& rSrcSizePixel ) const
767 {
768     pOutDev->DrawBitmapEx( rDestPt, rDestSize, rSrcPtPixel, rSrcSizePixel, *this );
769 }
770 
771 // ------------------------------------------------------------------
772 
773 sal_uInt8 BitmapEx::GetTransparency(sal_Int32 nX, sal_Int32 nY) const
774 {
775     sal_uInt8 nTransparency(0xff);
776 
777     if(!aBitmap.IsEmpty())
778     {
779         if(nX >= 0 && nX < aBitmapSize.Width() && nY >= 0 && nY < aBitmapSize.Height())
780         {
781             switch(eTransparent)
782             {
783                 case TRANSPARENT_NONE:
784                 {
785                     // not transparent, ergo all covered
786                     nTransparency = 0x00;
787                     break;
788                 }
789                 case TRANSPARENT_COLOR:
790                 {
791                     Bitmap aTestBitmap(aBitmap);
792                     BitmapReadAccess* pRead = aTestBitmap.AcquireReadAccess();
793 
794                     if(pRead)
795                     {
796                         const Color aColor = pRead->GetColor(nY, nX);
797 
798                         // if color is not equal to TransparentColor, we are not transparent
799                         if(aColor != aTransparentColor)
800                         {
801                             nTransparency = 0x00;
802                         }
803 
804                         aTestBitmap.ReleaseAccess(pRead);
805                     }
806                     break;
807                 }
808                 case TRANSPARENT_BITMAP:
809                 {
810                     if(!aMask.IsEmpty())
811                     {
812                         Bitmap aTestBitmap(aMask);
813                         BitmapReadAccess* pRead = aTestBitmap.AcquireReadAccess();
814 
815                         if(pRead)
816                         {
817                             const BitmapColor aBitmapColor(pRead->GetPixel(nY, nX));
818 
819                             if(bAlpha)
820                             {
821                                 nTransparency = aBitmapColor.GetIndex();
822                             }
823                             else
824                             {
825                                 if(0x00 == aBitmapColor.GetIndex())
826                                 {
827                                     nTransparency = 0x00;
828                                 }
829                             }
830 
831                             aTestBitmap.ReleaseAccess(pRead);
832                         }
833                     }
834                     break;
835                 }
836             }
837         }
838     }
839 
840     return nTransparency;
841 }
842 
843 // ------------------------------------------------------------------
844 
845 SvStream& operator<<( SvStream& rOStm, const BitmapEx& rBitmapEx )
846 {
847     rBitmapEx.aBitmap.Write( rOStm );
848 
849     rOStm << (sal_uInt32) 0x25091962;
850     rOStm << (sal_uInt32) 0xACB20201;
851     rOStm << (sal_uInt8) rBitmapEx.eTransparent;
852 
853     if( rBitmapEx.eTransparent == TRANSPARENT_BITMAP )
854         rBitmapEx.aMask.Write( rOStm );
855     else if( rBitmapEx.eTransparent == TRANSPARENT_COLOR )
856         rOStm << rBitmapEx.aTransparentColor;
857 
858     return rOStm;
859 }
860 
861 // ------------------------------------------------------------------
862 
863 SvStream& operator>>( SvStream& rIStm, BitmapEx& rBitmapEx )
864 {
865     Bitmap aBmp;
866 
867     rIStm >> aBmp;
868 
869     if( !rIStm.GetError() )
870     {
871         const sal_uLong nStmPos = rIStm.Tell();
872         sal_uInt32      nMagic1 = 0;
873         sal_uInt32      nMagic2 = 0;
874 
875         rIStm >> nMagic1 >> nMagic2;
876 
877         if( ( nMagic1 != 0x25091962 ) || ( nMagic2 != 0xACB20201 ) || rIStm.GetError() )
878         {
879             rIStm.ResetError();
880             rIStm.Seek( nStmPos );
881             rBitmapEx = aBmp;
882         }
883         else
884         {
885             sal_uInt8 bTransparent = false;
886 
887             rIStm >> bTransparent;
888 
889             if( bTransparent == (sal_uInt8) TRANSPARENT_BITMAP )
890             {
891                 Bitmap aMask;
892 
893                 rIStm >> aMask;
894 
895                 if( !!aMask)
896                 {
897                     // do we have an alpha mask?
898                     if( ( 8 == aMask.GetBitCount() ) && aMask.HasGreyPalette() )
899                     {
900                         AlphaMask aAlpha;
901 
902                         // create alpha mask quickly (without greyscale conversion)
903                         aAlpha.ImplSetBitmap( aMask );
904                         rBitmapEx = BitmapEx( aBmp, aAlpha );
905                     }
906                     else
907                         rBitmapEx = BitmapEx( aBmp, aMask );
908                 }
909                 else
910                     rBitmapEx = aBmp;
911             }
912             else if( bTransparent == (sal_uInt8) TRANSPARENT_COLOR )
913             {
914                 Color aTransparentColor;
915 
916                 rIStm >> aTransparentColor;
917                 rBitmapEx = BitmapEx( aBmp, aTransparentColor );
918             }
919             else
920                 rBitmapEx = aBmp;
921         }
922     }
923 
924     return rIStm;
925 }
926