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