xref: /AOO41X/main/vcl/source/gdi/bitmapex.cxx (revision 2b3b47da7571c20365210c2262e7e4e861cb17b5)
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 // MARKER(update_precomp.py): autogen include statement, do not remove
23 #include "precompiled_vcl.hxx"
24 
25 #include <ctype.h>
26 #include <rtl/crc.h>
27 #include <tools/stream.hxx>
28 #include <tools/debug.hxx>
29 #include <tools/rc.h>
30 #include <vcl/salbtype.hxx>
31 #include <vcl/outdev.hxx>
32 #include <vcl/alpha.hxx>
33 #include <vcl/bitmapex.hxx>
34 #include <vcl/pngread.hxx>
35 #include <vcl/svapp.hxx>
36 #include <vcl/bmpacc.hxx>
37 #include <vcl/dibtools.hxx>
38 #include <image.h>
39 #include <impimagetree.hxx>
40 #include <basegfx/matrix/b2dhommatrixtools.hxx>
41 
42 // ------------
43 // - BitmapEx -
44 // ------------
45 
BitmapEx()46 BitmapEx::BitmapEx() :
47         eTransparent( TRANSPARENT_NONE ),
48         bAlpha      ( sal_False )
49 {
50 }
51 
52 // ------------------------------------------------------------------
53 
BitmapEx(const BitmapEx & rBitmapEx)54 BitmapEx::BitmapEx( const BitmapEx& rBitmapEx ) :
55         aBitmap             ( rBitmapEx.aBitmap ),
56         aMask               ( rBitmapEx.aMask ),
57         aBitmapSize         ( rBitmapEx.aBitmapSize ),
58         aTransparentColor   ( rBitmapEx.aTransparentColor ),
59         eTransparent        ( rBitmapEx.eTransparent ),
60         bAlpha              ( rBitmapEx.bAlpha )
61 {
62 }
63 
BitmapEx(const BitmapEx & rBitmapEx,Point aSrc,Size aSize)64 BitmapEx::BitmapEx( const BitmapEx& rBitmapEx, Point aSrc, Size aSize ) :
65         eTransparent( TRANSPARENT_NONE ),
66         bAlpha      ( sal_False )
67 {
68     if( rBitmapEx.IsEmpty() )
69         return;
70 
71     aBitmap = Bitmap( aSize, rBitmapEx.aBitmap.GetBitCount() );
72     aBitmapSize = aSize;
73     if( rBitmapEx.IsAlpha() )
74     {
75         bAlpha = sal_True;
76         aMask = AlphaMask( aSize ).ImplGetBitmap();
77     }
78     else if( rBitmapEx.IsTransparent() )
79         aMask = Bitmap( aSize, rBitmapEx.aMask.GetBitCount() );
80 
81     Rectangle aDestRect( Point( 0, 0 ), aSize );
82     Rectangle aSrcRect( aSrc, aSize );
83     CopyPixel( aDestRect, aSrcRect, &rBitmapEx );
84 }
85 
86 // ------------------------------------------------------------------
87 
BitmapEx(const ResId & rResId)88 BitmapEx::BitmapEx( const ResId& rResId ) :
89         eTransparent( TRANSPARENT_NONE ),
90         bAlpha      ( sal_False )
91 {
92     static ImplImageTreeSingletonRef    aImageTree;
93     ResMgr*                             pResMgr = NULL;
94 
95     ResMgr::GetResourceSkipHeader( rResId.SetRT( RSC_BITMAP ), &pResMgr );
96     pResMgr->ReadLong();
97     pResMgr->ReadLong();
98 
99     const String aFileName( pResMgr->ReadString() );
100     ::rtl::OUString aCurrentSymbolsStyle = Application::GetSettings().GetStyleSettings().GetCurrentSymbolsStyleName();
101 
102     if( !aImageTree->loadImage( aFileName, aCurrentSymbolsStyle, *this ) )
103     {
104 #ifdef DBG_UTIL
105         ByteString aErrorStr( "BitmapEx::BitmapEx( const ResId& rResId ): could not load image <" );
106         DBG_ERROR( ( ( aErrorStr += ByteString( aFileName, RTL_TEXTENCODING_ASCII_US ) ) += '>' ).GetBuffer() );
107 #endif
108     }
109 }
110 
111 // ------------------------------------------------------------------
112 
BitmapEx(const Bitmap & rBmp)113 BitmapEx::BitmapEx( const Bitmap& rBmp ) :
114         aBitmap     ( rBmp ),
115         aBitmapSize ( aBitmap.GetSizePixel() ),
116         eTransparent( TRANSPARENT_NONE ),
117         bAlpha      ( sal_False )
118 {
119 }
120 
121 // ------------------------------------------------------------------
122 
BitmapEx(const Bitmap & rBmp,const Bitmap & rMask)123 BitmapEx::BitmapEx( const Bitmap& rBmp, const Bitmap& rMask ) :
124         aBitmap         ( rBmp ),
125         aMask           ( rMask ),
126         aBitmapSize     ( aBitmap.GetSizePixel() ),
127         eTransparent    ( !rMask ? TRANSPARENT_NONE : TRANSPARENT_BITMAP ),
128         bAlpha          ( sal_False )
129 {
130     if(!!aBitmap && !!aMask && aBitmap.GetSizePixel() != aMask.GetSizePixel())
131     {
132         OSL_ENSURE(false, "Mask size differs from Bitmap size, corrected Mask (!)");
133         aMask.Scale(aBitmap.GetSizePixel());
134     }
135 
136     // #105489# Ensure a mask is exactly one bit deep
137     if( !!aMask && aMask.GetBitCount() != 1 )
138     {
139         OSL_TRACE("BitmapEx: forced mask to monochrome");
140         aMask.ImplMakeMono( 255 );
141     }
142 }
143 
144 // ------------------------------------------------------------------
145 
BitmapEx(const Bitmap & rBmp,const AlphaMask & rAlphaMask)146 BitmapEx::BitmapEx( const Bitmap& rBmp, const AlphaMask& rAlphaMask ) :
147         aBitmap         ( rBmp ),
148         aMask           ( rAlphaMask.ImplGetBitmap() ),
149         aBitmapSize     ( aBitmap.GetSizePixel() ),
150         eTransparent    ( !rAlphaMask ? TRANSPARENT_NONE : TRANSPARENT_BITMAP ),
151         bAlpha          ( !rAlphaMask ? sal_False : sal_True )
152 {
153     if(!!aBitmap && !!aMask && aBitmap.GetSizePixel() != aMask.GetSizePixel())
154     {
155         OSL_ENSURE(false, "Alpha size differs from Bitmap size, corrected Mask (!)");
156         aMask.Scale(rBmp.GetSizePixel());
157     }
158 
159     // #i75531# the workaround below can go when
160     // X11SalGraphics::drawAlphaBitmap()'s render acceleration
161     // can handle the bitmap depth mismatch directly
162     if( aBitmap.GetBitCount() < aMask.GetBitCount() )
163         aBitmap.Convert( BMP_CONVERSION_24BIT );
164 }
165 
166 // ------------------------------------------------------------------
167 
BitmapEx(const Bitmap & rBmp,const Color & rTransparentColor)168 BitmapEx::BitmapEx( const Bitmap& rBmp, const Color& rTransparentColor ) :
169         aBitmap             ( rBmp ),
170         aBitmapSize         ( aBitmap.GetSizePixel() ),
171         aTransparentColor   ( rTransparentColor ),
172         eTransparent        ( TRANSPARENT_BITMAP ),
173         bAlpha              ( sal_False )
174 {
175     aMask = aBitmap.CreateMask( aTransparentColor );
176 
177     DBG_ASSERT( rBmp.GetSizePixel() == aMask.GetSizePixel(),
178                 "BitmapEx::BitmapEx(): size mismatch for bitmap and alpha mask." );
179 }
180 
181 // ------------------------------------------------------------------
182 
~BitmapEx()183 BitmapEx::~BitmapEx()
184 {
185 }
186 
187 // ------------------------------------------------------------------
188 
189 // ------------------------------------------------------------------
190 
operator =(const BitmapEx & rBitmapEx)191 BitmapEx& BitmapEx::operator=( const BitmapEx& rBitmapEx )
192 {
193     if( &rBitmapEx != this )
194     {
195         aBitmap = rBitmapEx.aBitmap;
196         aMask = rBitmapEx.aMask;
197         aBitmapSize = rBitmapEx.aBitmapSize;
198         aTransparentColor = rBitmapEx.aTransparentColor;
199         eTransparent = rBitmapEx.eTransparent;
200         bAlpha = rBitmapEx.bAlpha;
201     }
202 
203     return *this;
204 }
205 
206 // ------------------------------------------------------------------
207 
operator ==(const BitmapEx & rBitmapEx) const208 sal_Bool BitmapEx::operator==( const BitmapEx& rBitmapEx ) const
209 {
210     if( eTransparent != rBitmapEx.eTransparent )
211         return sal_False;
212 
213     if( aBitmap != rBitmapEx.aBitmap )
214         return sal_False;
215 
216     if( aBitmapSize != rBitmapEx.aBitmapSize )
217         return sal_False;
218 
219     if( eTransparent == TRANSPARENT_NONE )
220         return sal_True;
221 
222     if( eTransparent == TRANSPARENT_COLOR )
223         return aTransparentColor == rBitmapEx.aTransparentColor;
224 
225     return( ( aMask == rBitmapEx.aMask ) && ( bAlpha == rBitmapEx.bAlpha ) );
226 }
227 
228 // ------------------------------------------------------------------
229 
IsEqual(const BitmapEx & rBmpEx) const230 sal_Bool BitmapEx::IsEqual( const BitmapEx& rBmpEx ) const
231 {
232     return( rBmpEx.eTransparent == eTransparent &&
233             rBmpEx.bAlpha == bAlpha &&
234             rBmpEx.aBitmap.IsEqual( aBitmap ) &&
235             rBmpEx.aMask.IsEqual( aMask ) );
236 }
237 
238 // ------------------------------------------------------------------
239 
IsEmpty() const240 sal_Bool BitmapEx::IsEmpty() const
241 {
242     return( aBitmap.IsEmpty() && aMask.IsEmpty() );
243 }
244 
245 // ------------------------------------------------------------------
246 
SetEmpty()247 void BitmapEx::SetEmpty()
248 {
249     aBitmap.SetEmpty();
250     aMask.SetEmpty();
251     eTransparent = TRANSPARENT_NONE;
252     bAlpha = sal_False;
253 }
254 
255 // ------------------------------------------------------------------
256 
Clear()257 void BitmapEx::Clear()
258 {
259     SetEmpty();
260 }
261 
262 // ------------------------------------------------------------------
263 
IsTransparent() const264 sal_Bool BitmapEx::IsTransparent() const
265 {
266     return( eTransparent != TRANSPARENT_NONE );
267 }
268 
269 // ------------------------------------------------------------------
270 
IsAlpha() const271 sal_Bool BitmapEx::IsAlpha() const
272 {
273     return( IsTransparent() && bAlpha );
274 }
275 
276 // ------------------------------------------------------------------
277 
GetBitmap(const Color * pTransReplaceColor) const278 Bitmap BitmapEx::GetBitmap( const Color* pTransReplaceColor ) const
279 {
280     Bitmap aRetBmp( aBitmap );
281 
282     if( pTransReplaceColor && ( eTransparent != TRANSPARENT_NONE ) )
283     {
284         Bitmap aTempMask;
285 
286         if( eTransparent == TRANSPARENT_COLOR )
287             aTempMask = aBitmap.CreateMask( aTransparentColor );
288         else
289             aTempMask = aMask;
290 
291         if( !IsAlpha() )
292             aRetBmp.Replace( aTempMask, *pTransReplaceColor );
293         else
294             aRetBmp.Replace( GetAlpha(), *pTransReplaceColor );
295     }
296 
297     return aRetBmp;
298 }
299 
300 // ------------------------------------------------------------------
301 
GetColorTransformedBitmapEx(BmpColorMode eColorMode) const302 BitmapEx BitmapEx::GetColorTransformedBitmapEx( BmpColorMode eColorMode ) const
303 {
304     BitmapEx aRet;
305 
306     if( BMP_COLOR_HIGHCONTRAST == eColorMode )
307     {
308         aRet = *this;
309         aRet.aBitmap = aBitmap.GetColorTransformedBitmap( eColorMode );
310     }
311     else if( BMP_COLOR_MONOCHROME_BLACK == eColorMode ||
312              BMP_COLOR_MONOCHROME_WHITE == eColorMode )
313     {
314         aRet = *this;
315         aRet.aBitmap = aRet.aBitmap.GetColorTransformedBitmap( eColorMode );
316 
317         if( !aRet.aMask.IsEmpty() )
318         {
319             aRet.aMask.CombineSimple( aRet.aBitmap, BMP_COMBINE_OR );
320             aRet.aBitmap.Erase( ( BMP_COLOR_MONOCHROME_BLACK == eColorMode ) ? COL_BLACK : COL_WHITE );
321 
322             DBG_ASSERT( aRet.aBitmap.GetSizePixel() == aRet.aMask.GetSizePixel(),
323                         "BitmapEx::GetColorTransformedBitmapEx(): size mismatch for bitmap and alpha mask." );
324         }
325     }
326 
327     return aRet;
328 }
329 
330 // ------------------------------------------------------------------
331 
GetMask() const332 Bitmap BitmapEx::GetMask() const
333 {
334     Bitmap aRet( aMask );
335 
336     if( IsAlpha() )
337         aRet.ImplMakeMono( 255 );
338 
339     return aRet;
340 }
341 
342 // ------------------------------------------------------------------
343 
GetAlpha() const344 AlphaMask BitmapEx::GetAlpha() const
345 {
346     AlphaMask aAlpha;
347 
348     if( IsAlpha() )
349         aAlpha.ImplSetBitmap( aMask );
350     else
351         aAlpha = aMask;
352 
353     return aAlpha;
354 }
355 
356 // ------------------------------------------------------------------
357 
GetSizeBytes() const358 sal_uLong BitmapEx::GetSizeBytes() const
359 {
360     sal_uLong nSizeBytes = aBitmap.GetSizeBytes();
361 
362     if( eTransparent == TRANSPARENT_BITMAP )
363         nSizeBytes += aMask.GetSizeBytes();
364 
365     return nSizeBytes;
366 }
367 
368 // ------------------------------------------------------------------
369 
GetChecksum() const370 sal_uLong BitmapEx::GetChecksum() const
371 {
372     sal_uInt32  nCrc = aBitmap.GetChecksum();
373     SVBT32      aBT32;
374 
375     UInt32ToSVBT32( (long) eTransparent, aBT32 );
376     nCrc = rtl_crc32( nCrc, aBT32, 4 );
377 
378     UInt32ToSVBT32( (long) bAlpha, aBT32 );
379     nCrc = rtl_crc32( nCrc, aBT32, 4 );
380 
381     if( ( TRANSPARENT_BITMAP == eTransparent ) && !aMask.IsEmpty() )
382     {
383         UInt32ToSVBT32( aMask.GetChecksum(), aBT32 );
384         nCrc = rtl_crc32( nCrc, aBT32, 4 );
385     }
386 
387     return nCrc;
388 }
389 
390 // ------------------------------------------------------------------
391 
SetSizePixel(const Size & rNewSize,sal_uInt32 nScaleFlag)392 void BitmapEx::SetSizePixel( const Size& rNewSize, sal_uInt32 nScaleFlag )
393 {
394     if(GetSizePixel() != rNewSize)
395     {
396         Scale( rNewSize, nScaleFlag );
397     }
398 }
399 
400 // ------------------------------------------------------------------
401 
Invert()402 sal_Bool BitmapEx::Invert()
403 {
404     sal_Bool bRet = sal_False;
405 
406     if( !!aBitmap )
407     {
408         bRet = aBitmap.Invert();
409 
410         if( bRet && ( eTransparent == TRANSPARENT_COLOR ) )
411             aTransparentColor = BitmapColor( aTransparentColor ).Invert();
412     }
413 
414     return bRet;
415 }
416 
417 // ------------------------------------------------------------------
418 
Mirror(sal_uLong nMirrorFlags)419 sal_Bool BitmapEx::Mirror( sal_uLong nMirrorFlags )
420 {
421     sal_Bool bRet = sal_False;
422 
423     if( !!aBitmap )
424     {
425         bRet = aBitmap.Mirror( nMirrorFlags );
426 
427         if( bRet && ( eTransparent == TRANSPARENT_BITMAP ) && !!aMask )
428             aMask.Mirror( nMirrorFlags );
429     }
430 
431     return bRet;
432 }
433 
434 // ------------------------------------------------------------------
435 
Scale(const double & rScaleX,const double & rScaleY,sal_uInt32 nScaleFlag)436 sal_Bool BitmapEx::Scale( const double& rScaleX, const double& rScaleY, sal_uInt32 nScaleFlag )
437 {
438     sal_Bool bRet = sal_False;
439 
440     if( !!aBitmap )
441     {
442         bRet = aBitmap.Scale( rScaleX, rScaleY, nScaleFlag );
443 
444         if( bRet && ( eTransparent == TRANSPARENT_BITMAP ) && !!aMask )
445         {
446             aMask.Scale( rScaleX, rScaleY, nScaleFlag );
447         }
448 
449         aBitmapSize = aBitmap.GetSizePixel();
450 
451         DBG_ASSERT( !aMask || aBitmap.GetSizePixel() == aMask.GetSizePixel(),
452                     "BitmapEx::Scale(): size mismatch for bitmap and alpha mask." );
453     }
454 
455     return bRet;
456 }
457 
458 // ------------------------------------------------------------------------
459 
Scale(const Size & rNewSize,sal_uInt32 nScaleFlag)460 sal_Bool BitmapEx::Scale( const Size& rNewSize, sal_uInt32 nScaleFlag )
461 {
462     sal_Bool bRet;
463 
464     if( aBitmapSize.Width() && aBitmapSize.Height() )
465     {
466         bRet = Scale( (double) rNewSize.Width() / aBitmapSize.Width(),
467                       (double) rNewSize.Height() / aBitmapSize.Height(),
468                       nScaleFlag );
469     }
470     else
471         bRet = sal_True;
472 
473     return bRet;
474 }
475 
476 // ------------------------------------------------------------------
477 
Rotate(long nAngle10,const Color & rFillColor)478 sal_Bool BitmapEx::Rotate( long nAngle10, const Color& rFillColor )
479 {
480     sal_Bool bRet = sal_False;
481 
482     if( !!aBitmap )
483     {
484         const sal_Bool bTransRotate = ( Color( COL_TRANSPARENT ) == rFillColor );
485 
486         if( bTransRotate )
487         {
488             if( eTransparent == TRANSPARENT_COLOR )
489                 bRet = aBitmap.Rotate( nAngle10, aTransparentColor );
490             else
491             {
492                 bRet = aBitmap.Rotate( nAngle10, COL_BLACK );
493 
494                 if( eTransparent == TRANSPARENT_NONE )
495                 {
496                     aMask = Bitmap( aBitmapSize, 1 );
497                     aMask.Erase( COL_BLACK );
498                     eTransparent = TRANSPARENT_BITMAP;
499                 }
500 
501                 if( bRet && !!aMask )
502                     aMask.Rotate( nAngle10, COL_WHITE );
503             }
504         }
505         else
506         {
507             bRet = aBitmap.Rotate( nAngle10, rFillColor );
508 
509             if( bRet && ( eTransparent == TRANSPARENT_BITMAP ) && !!aMask )
510                 aMask.Rotate( nAngle10, COL_WHITE );
511         }
512 
513         aBitmapSize = aBitmap.GetSizePixel();
514 
515         DBG_ASSERT( !aMask || aBitmap.GetSizePixel() == aMask.GetSizePixel(),
516                     "BitmapEx::Rotate(): size mismatch for bitmap and alpha mask." );
517     }
518 
519     return bRet;
520 }
521 
522 // ------------------------------------------------------------------
523 
Crop(const Rectangle & rRectPixel)524 sal_Bool BitmapEx::Crop( const Rectangle& rRectPixel )
525 {
526     sal_Bool bRet = sal_False;
527 
528     if( !!aBitmap )
529     {
530         bRet = aBitmap.Crop( rRectPixel );
531 
532         if( bRet && ( eTransparent == TRANSPARENT_BITMAP ) && !!aMask )
533             aMask.Crop( rRectPixel );
534 
535         aBitmapSize = aBitmap.GetSizePixel();
536 
537         DBG_ASSERT( !aMask || aBitmap.GetSizePixel() == aMask.GetSizePixel(),
538                     "BitmapEx::Crop(): size mismatch for bitmap and alpha mask." );
539     }
540 
541     return bRet;
542 }
543 
544 // ------------------------------------------------------------------
545 
Convert(BmpConversion eConversion)546 sal_Bool BitmapEx::Convert( BmpConversion eConversion )
547 {
548     return( !!aBitmap ? aBitmap.Convert( eConversion ) : sal_False );
549 }
550 
551 // ------------------------------------------------------------------
552 
ReduceColors(sal_uInt16 nNewColorCount,BmpReduce eReduce)553 sal_Bool BitmapEx::ReduceColors( sal_uInt16 nNewColorCount, BmpReduce eReduce )
554 {
555     return( !!aBitmap ? aBitmap.ReduceColors( nNewColorCount, eReduce ) : sal_False );
556 }
557 
558 // ------------------------------------------------------------------
559 
Expand(sal_uLong nDX,sal_uLong nDY,const Color * pInitColor,sal_Bool bExpandTransparent)560 sal_Bool BitmapEx::Expand( sal_uLong nDX, sal_uLong nDY, const Color* pInitColor, sal_Bool bExpandTransparent )
561 {
562     sal_Bool bRet = sal_False;
563 
564     if( !!aBitmap )
565     {
566         bRet = aBitmap.Expand( nDX, nDY, pInitColor );
567 
568         if( bRet && ( eTransparent == TRANSPARENT_BITMAP ) && !!aMask )
569         {
570             Color aColor( bExpandTransparent ? COL_WHITE : COL_BLACK );
571             aMask.Expand( nDX, nDY, &aColor );
572         }
573 
574         aBitmapSize = aBitmap.GetSizePixel();
575 
576         DBG_ASSERT( !aMask || aBitmap.GetSizePixel() == aMask.GetSizePixel(),
577                     "BitmapEx::Expand(): size mismatch for bitmap and alpha mask." );
578     }
579 
580     return bRet;
581 }
582 
583 // ------------------------------------------------------------------
584 
CopyPixel(const Rectangle & rRectDst,const Rectangle & rRectSrc,const BitmapEx * pBmpExSrc)585 sal_Bool BitmapEx::CopyPixel( const Rectangle& rRectDst, const Rectangle& rRectSrc,
586                           const BitmapEx* pBmpExSrc )
587 {
588     sal_Bool bRet = sal_False;
589 
590     if( !pBmpExSrc || pBmpExSrc->IsEmpty() )
591     {
592         if( !aBitmap.IsEmpty() )
593         {
594             bRet = aBitmap.CopyPixel( rRectDst, rRectSrc );
595 
596             if( bRet && ( eTransparent == TRANSPARENT_BITMAP ) && !!aMask )
597                 aMask.CopyPixel( rRectDst, rRectSrc );
598         }
599     }
600     else
601     {
602         if( !aBitmap.IsEmpty() )
603         {
604             bRet = aBitmap.CopyPixel( rRectDst, rRectSrc, &pBmpExSrc->aBitmap );
605 
606             if( bRet )
607             {
608                 if( pBmpExSrc->IsAlpha() )
609                 {
610                     if( IsAlpha() )
611                         // cast to use the optimized AlphaMask::CopyPixel
612                         ((AlphaMask*) &aMask)->CopyPixel( rRectDst, rRectSrc, (AlphaMask*)&pBmpExSrc->aMask );
613                     else if( IsTransparent() )
614                     {
615                         AlphaMask* pAlpha = new AlphaMask( aMask );
616 
617                         aMask = pAlpha->ImplGetBitmap();
618                         delete pAlpha;
619                         bAlpha = sal_True;
620                         aMask.CopyPixel( rRectDst, rRectSrc, &pBmpExSrc->aMask );
621                     }
622                     else
623                     {
624                         sal_uInt8   cBlack = 0;
625                         AlphaMask*  pAlpha = new AlphaMask( GetSizePixel(), &cBlack );
626 
627                         aMask = pAlpha->ImplGetBitmap();
628                         delete pAlpha;
629                         eTransparent = TRANSPARENT_BITMAP;
630                         bAlpha = sal_True;
631                         aMask.CopyPixel( rRectDst, rRectSrc, &pBmpExSrc->aMask );
632                     }
633                 }
634                 else if( pBmpExSrc->IsTransparent() )
635                 {
636                     if( IsAlpha() )
637                     {
638                         AlphaMask aAlpha( pBmpExSrc->aMask );
639                         aMask.CopyPixel( rRectDst, rRectSrc, &aAlpha.ImplGetBitmap() );
640                     }
641                     else if( IsTransparent() )
642                         aMask.CopyPixel( rRectDst, rRectSrc, &pBmpExSrc->aMask );
643                     else
644                     {
645                         aMask = Bitmap( GetSizePixel(), 1 );
646                         aMask.Erase( Color( COL_BLACK ) );
647                         eTransparent = TRANSPARENT_BITMAP;
648                         aMask.CopyPixel( rRectDst, rRectSrc, &pBmpExSrc->aMask );
649                     }
650                 }
651                 else if( IsAlpha() )
652                 {
653                     sal_uInt8         cBlack = 0;
654                     const AlphaMask   aAlphaSrc( pBmpExSrc->GetSizePixel(), &cBlack );
655 
656                     aMask.CopyPixel( rRectDst, rRectSrc, &aAlphaSrc.ImplGetBitmap() );
657                 }
658                 else if( IsTransparent() )
659                 {
660                     Bitmap aMaskSrc( pBmpExSrc->GetSizePixel(), 1 );
661 
662                     aMaskSrc.Erase( Color( COL_BLACK ) );
663                     aMask.CopyPixel( rRectDst, rRectSrc, &aMaskSrc );
664                 }
665             }
666         }
667     }
668 
669     return bRet;
670 }
671 
672 // ------------------------------------------------------------------
673 
Erase(const Color & rFillColor)674 sal_Bool BitmapEx::Erase( const Color& rFillColor )
675 {
676     sal_Bool bRet = sal_False;
677 
678     if( !!aBitmap )
679     {
680         bRet = aBitmap.Erase( rFillColor );
681 
682         if( bRet && ( eTransparent == TRANSPARENT_BITMAP ) && !!aMask )
683         {
684             // #104416# Respect transparency on fill color
685             if( rFillColor.GetTransparency() )
686             {
687                 const Color aFill( rFillColor.GetTransparency(), rFillColor.GetTransparency(), rFillColor.GetTransparency() );
688                 aMask.Erase( aFill );
689             }
690             else
691             {
692                 const Color aBlack( COL_BLACK );
693                 aMask.Erase( aBlack );
694             }
695         }
696     }
697 
698     return bRet;
699 }
700 
701 // ------------------------------------------------------------------
702 
Dither(sal_uLong nDitherFlags)703 sal_Bool BitmapEx::Dither( sal_uLong nDitherFlags )
704 {
705     return( !!aBitmap ? aBitmap.Dither( nDitherFlags ) : sal_False );
706 }
707 
708 // ------------------------------------------------------------------
709 
Replace(const Color & rSearchColor,const Color & rReplaceColor,sal_uLong nTol)710 sal_Bool BitmapEx::Replace( const Color& rSearchColor, const Color& rReplaceColor, sal_uLong nTol )
711 {
712     return( !!aBitmap ? aBitmap.Replace( rSearchColor, rReplaceColor, nTol ) : sal_False );
713 }
714 
715 // ------------------------------------------------------------------
716 
Replace(const Color * pSearchColors,const Color * pReplaceColors,sal_uLong nColorCount,const sal_uLong * pTols)717 sal_Bool BitmapEx::Replace( const Color* pSearchColors, const Color* pReplaceColors, sal_uLong nColorCount, const sal_uLong* pTols )
718 {
719     return( !!aBitmap ? aBitmap.Replace( pSearchColors, pReplaceColors, nColorCount, (sal_uLong*) pTols ) : sal_False );
720 }
721 
722 // ------------------------------------------------------------------
723 
Adjust(short nLuminancePercent,short nContrastPercent,short nChannelRPercent,short nChannelGPercent,short nChannelBPercent,double fGamma,sal_Bool bInvert)724 sal_Bool BitmapEx::Adjust( short nLuminancePercent, short nContrastPercent,
725                        short nChannelRPercent, short nChannelGPercent, short nChannelBPercent,
726                        double fGamma, sal_Bool bInvert )
727 {
728     return( !!aBitmap ? aBitmap.Adjust( nLuminancePercent, nContrastPercent,
729                                         nChannelRPercent, nChannelGPercent, nChannelBPercent,
730                                         fGamma, bInvert ) : sal_False );
731 }
732 
733 // ------------------------------------------------------------------
734 
Filter(BmpFilter eFilter,const BmpFilterParam * pFilterParam,const Link * pProgress)735 sal_Bool BitmapEx::Filter( BmpFilter eFilter, const BmpFilterParam* pFilterParam, const Link* pProgress )
736 {
737     return( !!aBitmap ? aBitmap.Filter( eFilter, pFilterParam, pProgress ) : sal_False );
738 }
739 
740 // ------------------------------------------------------------------
741 
Draw(OutputDevice * pOutDev,const Point & rDestPt) const742 void BitmapEx::Draw( OutputDevice* pOutDev, const Point& rDestPt ) const
743 {
744     pOutDev->DrawBitmapEx( rDestPt, *this );
745 }
746 
747 // ------------------------------------------------------------------
748 
Draw(OutputDevice * pOutDev,const Point & rDestPt,const Size & rDestSize) const749 void BitmapEx::Draw( OutputDevice* pOutDev,
750                      const Point& rDestPt, const Size& rDestSize ) const
751 {
752     pOutDev->DrawBitmapEx( rDestPt, rDestSize, *this );
753 }
754 
755 // ------------------------------------------------------------------
756 
Draw(OutputDevice * pOutDev,const Point & rDestPt,const Size & rDestSize,const Point & rSrcPtPixel,const Size & rSrcSizePixel) const757 void BitmapEx::Draw( OutputDevice* pOutDev,
758                      const Point& rDestPt, const Size& rDestSize,
759                      const Point& rSrcPtPixel, const Size& rSrcSizePixel ) const
760 {
761     pOutDev->DrawBitmapEx( rDestPt, rDestSize, rSrcPtPixel, rSrcSizePixel, *this );
762 }
763 
764 // ------------------------------------------------------------------
765 
GetTransparency(sal_Int32 nX,sal_Int32 nY) const766 sal_uInt8 BitmapEx::GetTransparency(sal_Int32 nX, sal_Int32 nY) const
767 {
768     sal_uInt8 nTransparency(0xff);
769 
770     if(!aBitmap.IsEmpty())
771     {
772         if(nX >= 0 && nX < aBitmapSize.Width() && nY >= 0 && nY < aBitmapSize.Height())
773         {
774             switch(eTransparent)
775             {
776                 case TRANSPARENT_NONE:
777                 {
778                     // not transparent, ergo all covered
779                     nTransparency = 0x00;
780                     break;
781                 }
782                 case TRANSPARENT_COLOR:
783                 {
784                     Bitmap aTestBitmap(aBitmap);
785                     BitmapReadAccess* pRead = aTestBitmap.AcquireReadAccess();
786 
787                     if(pRead)
788                     {
789                         const Color aColor = pRead->GetColor(nY, nX);
790 
791                         // if color is not equal to TransparentColor, we are not transparent
792                         if(aColor != aTransparentColor)
793                         {
794                             nTransparency = 0x00;
795                         }
796 
797                         aTestBitmap.ReleaseAccess(pRead);
798                     }
799                     break;
800                 }
801                 case TRANSPARENT_BITMAP:
802                 {
803                     if(!aMask.IsEmpty())
804                     {
805                         Bitmap aTestBitmap(aMask);
806                         BitmapReadAccess* pRead = aTestBitmap.AcquireReadAccess();
807 
808                         if(pRead)
809                         {
810                             const BitmapColor aBitmapColor(pRead->GetPixel(nY, nX));
811 
812                             if(bAlpha)
813                             {
814                                 nTransparency = aBitmapColor.GetIndex();
815                             }
816                             else
817                             {
818                                 if(0x00 == aBitmapColor.GetIndex())
819                                 {
820                                     nTransparency = 0x00;
821                                 }
822                             }
823 
824                             aTestBitmap.ReleaseAccess(pRead);
825                         }
826                     }
827                     break;
828                 }
829             }
830         }
831     }
832 
833     return nTransparency;
834 }
835 
836 // ------------------------------------------------------------------
837 
838 namespace
839 {
impTransformBitmap(const Bitmap & rSource,const Size aDestinationSize,const basegfx::B2DHomMatrix & rTransform,bool bSmooth)840     Bitmap impTransformBitmap(
841         const Bitmap& rSource,
842         const Size aDestinationSize,
843         const basegfx::B2DHomMatrix& rTransform,
844         bool bSmooth)
845     {
846         Bitmap aDestination(aDestinationSize, 24);
847         BitmapWriteAccess* pWrite = aDestination.AcquireWriteAccess();
848 
849         if(pWrite)
850         {
851             //const Size aContentSizePixel(rSource.GetSizePixel());
852             BitmapReadAccess* pRead = (const_cast< Bitmap& >(rSource)).AcquireReadAccess();
853 
854             if(pRead)
855             {
856                 const Size aDestinationSizePixel(aDestination.GetSizePixel());
857                 const BitmapColor aOutside(BitmapColor(0xff, 0xff, 0xff));
858 
859                 for(sal_Int32 y(0L); y < aDestinationSizePixel.getHeight(); y++)
860                 {
861                     for(sal_Int32 x(0L); x < aDestinationSizePixel.getWidth(); x++)
862                     {
863                         const basegfx::B2DPoint aSourceCoor(rTransform * basegfx::B2DPoint(x, y));
864 
865                         if(bSmooth)
866                         {
867                             pWrite->SetPixel(
868                                 y,
869                                 x,
870                                 pRead->GetInterpolatedColorWithFallback(
871                                     aSourceCoor.getY(),
872                                     aSourceCoor.getX(),
873                                     aOutside));
874                         }
875                         else
876                         {
877                             // this version does the correct <= 0.0 checks, so no need
878                             // to do the static_cast< sal_Int32 > self and make an error
879                             pWrite->SetPixel(
880                                 y,
881                                 x,
882                                 pRead->GetColorWithFallback(
883                                     aSourceCoor.getY(),
884                                     aSourceCoor.getX(),
885                                     aOutside));
886                         }
887                     }
888                 }
889 
890                 delete pRead;
891             }
892 
893             delete pWrite;
894         }
895 
896         rSource.AdaptBitCount(aDestination);
897 
898         return aDestination;
899     }
900 } // end of anonymous namespace
901 
TransformBitmapEx(double fWidth,double fHeight,const basegfx::B2DHomMatrix & rTransformation,bool bSmooth) const902 BitmapEx BitmapEx::TransformBitmapEx(
903     double fWidth,
904     double fHeight,
905     const basegfx::B2DHomMatrix& rTransformation,
906     bool bSmooth) const
907 {
908     if(fWidth <= 1 || fHeight <= 1)
909         return BitmapEx();
910 
911     // force destination to 24 bit, we want to smooth output
912     const Size aDestinationSize(basegfx::fround(fWidth), basegfx::fround(fHeight));
913     const Bitmap aDestination(impTransformBitmap(GetBitmap(), aDestinationSize, rTransformation, bSmooth));
914 
915     // create mask
916     if(IsTransparent())
917     {
918         if(IsAlpha())
919         {
920             const Bitmap aAlpha(impTransformBitmap(GetAlpha().GetBitmap(), aDestinationSize, rTransformation, bSmooth));
921             return BitmapEx(aDestination, AlphaMask(aAlpha));
922         }
923         else
924         {
925             const Bitmap aMask(impTransformBitmap(GetMask(), aDestinationSize, rTransformation, false));
926             return BitmapEx(aDestination, aMask);
927         }
928     }
929 
930     return BitmapEx(aDestination);
931 }
932 
933 // ------------------------------------------------------------------
934 
getTransformed(const basegfx::B2DHomMatrix & rTransformation,const basegfx::B2DRange & rVisibleRange,double fMaximumArea,bool bSmooth) const935 BitmapEx BitmapEx::getTransformed(
936     const basegfx::B2DHomMatrix& rTransformation,
937     const basegfx::B2DRange& rVisibleRange,
938     double fMaximumArea,
939     bool bSmooth) const
940 {
941     BitmapEx aRetval;
942 
943     if(IsEmpty())
944         return aRetval;
945 
946     const sal_uInt32 nSourceWidth(GetSizePixel().Width());
947     const sal_uInt32 nSourceHeight(GetSizePixel().Height());
948 
949     if(!nSourceWidth || !nSourceHeight)
950         return aRetval;
951 
952     // Get aOutlineRange
953     basegfx::B2DRange aOutlineRange(0.0, 0.0, 1.0, 1.0);
954 
955     aOutlineRange.transform(rTransformation);
956 
957     // create visible range from it by moving from relative to absolute
958     basegfx::B2DRange aVisibleRange(rVisibleRange);
959 
960     aVisibleRange.transform(
961         basegfx::tools::createScaleTranslateB2DHomMatrix(
962             aOutlineRange.getRange(),
963             aOutlineRange.getMinimum()));
964 
965     // get target size (which is visible range's size)
966     double fWidth(aVisibleRange.getWidth());
967     double fHeight(aVisibleRange.getHeight());
968 
969     if(fWidth < 1.0 || fHeight < 1.0)
970     {
971         return aRetval;
972     }
973 
974     // test if discrete size (pixel) maybe too big and limit it
975     const double fArea(fWidth * fHeight);
976     const bool bNeedToReduce(basegfx::fTools::more(fArea, fMaximumArea));
977     double fReduceFactor(1.0);
978 
979     if(bNeedToReduce)
980     {
981         fReduceFactor = sqrt(fMaximumArea / fArea);
982         fWidth *= fReduceFactor;
983         fHeight *= fReduceFactor;
984     }
985 
986     // Build complete transform from source pixels to target pixels.
987     // Start by scaling from source pixel size to unit coordinates
988     basegfx::B2DHomMatrix aTransform(
989         basegfx::tools::createScaleB2DHomMatrix(
990             1.0 / nSourceWidth,
991             1.0 / nSourceHeight));
992 
993     // multiply with given transform which leads from unit coordinates inside
994     // aOutlineRange
995     aTransform = rTransformation * aTransform;
996 
997     // substract top-left of absolute VisibleRange
998     aTransform.translate(
999         -aVisibleRange.getMinX(),
1000         -aVisibleRange.getMinY());
1001 
1002     // scale to target pixels (if needed)
1003     if(bNeedToReduce)
1004     {
1005         aTransform.scale(fReduceFactor, fReduceFactor);
1006     }
1007 
1008     // invert to get transformation from target pixel coordiates to source pixels
1009     aTransform.invert();
1010 
1011     // create bitmap using source, destination and linear back-transformation
1012     aRetval = TransformBitmapEx(fWidth, fHeight, aTransform, bSmooth);
1013 
1014     return aRetval;
1015 }
1016 
1017 // ------------------------------------------------------------------
1018 
ModifyBitmapEx(const basegfx::BColorModifierStack & rBColorModifierStack) const1019 BitmapEx BitmapEx::ModifyBitmapEx(const basegfx::BColorModifierStack& rBColorModifierStack) const
1020 {
1021     Bitmap aChangedBitmap(GetBitmap());
1022     bool bDone(false);
1023 
1024     for(sal_uInt32 a(rBColorModifierStack.count()); a && !bDone; )
1025     {
1026         const basegfx::BColorModifierSharedPtr& rModifier = rBColorModifierStack.getBColorModifier(--a);
1027         const basegfx::BColorModifier_replace* pReplace = dynamic_cast< const basegfx::BColorModifier_replace* >(rModifier.get());
1028 
1029         if(pReplace)
1030         {
1031             // complete replace
1032             if(IsTransparent())
1033             {
1034                 // clear bitmap with dest color
1035                 if(aChangedBitmap.GetBitCount() <= 8)
1036                 {
1037                     // do NOT use erase; for e.g. 8bit Bitmaps, the nearest color to the given
1038                     // erase color is determined and used -> this may be different from what is
1039                     // wanted here. Better create a new bitmap with the needed color explicitely
1040                     BitmapReadAccess* pReadAccess = aChangedBitmap.AcquireReadAccess();
1041                     OSL_ENSURE(pReadAccess, "Got no Bitmap ReadAccess ?!?");
1042 
1043                     if(pReadAccess)
1044                     {
1045                         BitmapPalette aNewPalette(pReadAccess->GetPalette());
1046                         aNewPalette[0] = BitmapColor(Color(pReplace->getBColor()));
1047                         aChangedBitmap = Bitmap(
1048                             aChangedBitmap.GetSizePixel(),
1049                             aChangedBitmap.GetBitCount(),
1050                             &aNewPalette);
1051                         delete pReadAccess;
1052                     }
1053                 }
1054                 else
1055                 {
1056                     aChangedBitmap.Erase(Color(pReplace->getBColor()));
1057                 }
1058             }
1059             else
1060             {
1061                 // erase bitmap, caller will know to paint direct
1062                 aChangedBitmap.SetEmpty();
1063             }
1064 
1065             bDone = true;
1066         }
1067         else
1068         {
1069             BitmapWriteAccess* pContent = aChangedBitmap.AcquireWriteAccess();
1070 
1071             if(pContent)
1072             {
1073                 const double fConvertColor(1.0 / 255.0);
1074 
1075                 if(pContent->HasPalette())
1076                 {
1077                     const sal_uInt16 nCount(pContent->GetPaletteEntryCount());
1078 
1079                     for(sal_uInt16 a(0); a < nCount; a++)
1080                     {
1081                         const BitmapColor& rCol = pContent->GetPaletteColor(a);
1082                         const basegfx::BColor aBSource(
1083                             rCol.GetRed() * fConvertColor,
1084                             rCol.GetGreen() * fConvertColor,
1085                             rCol.GetBlue() * fConvertColor);
1086                         const basegfx::BColor aBDest(rModifier->getModifiedColor(aBSource));
1087                         pContent->SetPaletteColor(a, BitmapColor(Color(aBDest)));
1088                     }
1089                 }
1090                 else if(BMP_FORMAT_24BIT_TC_BGR == pContent->GetScanlineFormat())
1091                 {
1092                     for(sal_uInt32 y(0L); y < (sal_uInt32)pContent->Height(); y++)
1093                     {
1094                         Scanline pScan = pContent->GetScanline(y);
1095 
1096                         for(sal_uInt32 x(0L); x < (sal_uInt32)pContent->Width(); x++)
1097                         {
1098                             const basegfx::BColor aBSource(
1099                                 *(pScan + 2)* fConvertColor,
1100                                 *(pScan + 1) * fConvertColor,
1101                                 *pScan * fConvertColor);
1102                             const basegfx::BColor aBDest(rModifier->getModifiedColor(aBSource));
1103                             *pScan++ = static_cast< sal_uInt8 >(aBDest.getBlue() * 255.0);
1104                             *pScan++ = static_cast< sal_uInt8 >(aBDest.getGreen() * 255.0);
1105                             *pScan++ = static_cast< sal_uInt8 >(aBDest.getRed() * 255.0);
1106                         }
1107                     }
1108                 }
1109                 else if(BMP_FORMAT_24BIT_TC_RGB == pContent->GetScanlineFormat())
1110                 {
1111                     for(sal_uInt32 y(0L); y < (sal_uInt32)pContent->Height(); y++)
1112                     {
1113                         Scanline pScan = pContent->GetScanline(y);
1114 
1115                         for(sal_uInt32 x(0L); x < (sal_uInt32)pContent->Width(); x++)
1116                         {
1117                             const basegfx::BColor aBSource(
1118                                 *pScan * fConvertColor,
1119                                 *(pScan + 1) * fConvertColor,
1120                                 *(pScan + 2) * fConvertColor);
1121                             const basegfx::BColor aBDest(rModifier->getModifiedColor(aBSource));
1122                             *pScan++ = static_cast< sal_uInt8 >(aBDest.getRed() * 255.0);
1123                             *pScan++ = static_cast< sal_uInt8 >(aBDest.getGreen() * 255.0);
1124                             *pScan++ = static_cast< sal_uInt8 >(aBDest.getBlue() * 255.0);
1125                         }
1126                     }
1127                 }
1128                 else
1129                 {
1130                     for(sal_uInt32 y(0L); y < (sal_uInt32)pContent->Height(); y++)
1131                     {
1132                         for(sal_uInt32 x(0L); x < (sal_uInt32)pContent->Width(); x++)
1133                         {
1134                             const BitmapColor aBMCol(pContent->GetColor(y, x));
1135                             const basegfx::BColor aBSource(
1136                                 (double)aBMCol.GetRed() * fConvertColor,
1137                                 (double)aBMCol.GetGreen() * fConvertColor,
1138                                 (double)aBMCol.GetBlue() * fConvertColor);
1139                             const basegfx::BColor aBDest(rModifier->getModifiedColor(aBSource));
1140 
1141                             pContent->SetPixel(y, x, BitmapColor(Color(aBDest)));
1142                         }
1143                     }
1144                 }
1145 
1146                 delete pContent;
1147             }
1148         }
1149     }
1150 
1151     if(aChangedBitmap.IsEmpty())
1152     {
1153         return BitmapEx();
1154     }
1155     else
1156     {
1157         if(IsTransparent())
1158         {
1159             if(IsAlpha())
1160             {
1161                 return BitmapEx(aChangedBitmap, GetAlpha());
1162             }
1163             else
1164             {
1165                 return BitmapEx(aChangedBitmap, GetMask());
1166             }
1167         }
1168         else
1169         {
1170             return BitmapEx(aChangedBitmap);
1171         }
1172     }
1173 }
1174 
1175 // -----------------------------------------------------------------------------
1176 
createBlendFrame(const Size & rSize,sal_uInt8 nAlpha,Color aColorTopLeft,Color aColorBottomRight)1177 BitmapEx VCL_DLLPUBLIC createBlendFrame(
1178     const Size& rSize,
1179     sal_uInt8 nAlpha,
1180     Color aColorTopLeft,
1181     Color aColorBottomRight)
1182 {
1183     const sal_uInt32 nW(rSize.Width());
1184     const sal_uInt32 nH(rSize.Height());
1185 
1186     if(nW || nH)
1187     {
1188         Color aColTopRight(aColorTopLeft);
1189         Color aColBottomLeft(aColorTopLeft);
1190         const sal_uInt32 nDE(nW + nH);
1191 
1192         aColTopRight.Merge(aColorBottomRight, 255 - sal_uInt8((nW * 255) / nDE));
1193         aColBottomLeft.Merge(aColorBottomRight, 255 - sal_uInt8((nH * 255) / nDE));
1194 
1195         return createBlendFrame(rSize, nAlpha, aColorTopLeft, aColTopRight, aColorBottomRight, aColBottomLeft);
1196     }
1197 
1198     return BitmapEx();
1199 }
1200 
createBlendFrame(const Size & rSize,sal_uInt8 nAlpha,Color aColorTopLeft,Color aColorTopRight,Color aColorBottomRight,Color aColorBottomLeft)1201 BitmapEx VCL_DLLPUBLIC createBlendFrame(
1202     const Size& rSize,
1203     sal_uInt8 nAlpha,
1204     Color aColorTopLeft,
1205     Color aColorTopRight,
1206     Color aColorBottomRight,
1207     Color aColorBottomLeft)
1208 {
1209     static Size aLastSize(0, 0);
1210     static sal_uInt8 nLastAlpha(0);
1211     static Color aLastColorTopLeft(COL_BLACK);
1212     static Color aLastColorTopRight(COL_BLACK);
1213     static Color aLastColorBottomRight(COL_BLACK);
1214     static Color aLastColorBottomLeft(COL_BLACK);
1215     static BitmapEx aLastResult;
1216 
1217     if(aLastSize == rSize
1218         && nLastAlpha == nAlpha
1219         && aLastColorTopLeft == aColorTopLeft
1220         && aLastColorTopRight == aColorTopRight
1221         && aLastColorBottomRight == aColorBottomRight
1222         && aLastColorBottomLeft == aColorBottomLeft)
1223     {
1224         return aLastResult;
1225     }
1226 
1227     aLastSize = rSize;
1228     nLastAlpha = nAlpha;
1229     aLastColorTopLeft = aColorTopLeft;
1230     aLastColorTopRight = aColorTopRight;
1231     aLastColorBottomRight = aColorBottomRight;
1232     aLastColorBottomLeft = aColorBottomLeft;
1233     aLastResult.Clear();
1234 
1235     const long nW(rSize.Width());
1236     const long nH(rSize.Height());
1237 
1238     if(nW && nH)
1239     {
1240         sal_uInt8 aEraseTrans(0xff);
1241         Bitmap aContent(rSize, 24);
1242         AlphaMask aAlpha(rSize, &aEraseTrans);
1243 
1244         aContent.Erase(COL_BLACK);
1245 
1246         BitmapWriteAccess* pContent = aContent.AcquireWriteAccess();
1247         BitmapWriteAccess* pAlpha = aAlpha.AcquireWriteAccess();
1248 
1249         if(pContent && pAlpha)
1250         {
1251             long x(0);
1252             long y(0);
1253 
1254             // x == 0, y == 0, top-left corner
1255             pContent->SetPixel(0, 0, aColorTopLeft);
1256             pAlpha->SetPixelIndex(0, 0, nAlpha);
1257 
1258             // y == 0, top line left to right
1259             for(x = 1; x < nW - 1; x++)
1260             {
1261                 Color aMix(aColorTopLeft);
1262 
1263                 aMix.Merge(aColorTopRight, 255 - sal_uInt8((x * 255) / nW));
1264                 pContent->SetPixel(0, x, aMix);
1265                 pAlpha->SetPixelIndex(0, x, nAlpha);
1266             }
1267 
1268             // x == nW - 1, y == 0, top-right corner
1269             // #123690# Caution! When nW is 1, x == nW is possible (!)
1270             if(x < nW)
1271             {
1272                 pContent->SetPixel(0, x, aColorTopRight);
1273                 pAlpha->SetPixelIndex(0, x, nAlpha);
1274             }
1275 
1276             // x == 0 and nW - 1, left and right line top-down
1277             for(y = 1; y < nH - 1; y++)
1278             {
1279                 Color aMixA(aColorTopLeft);
1280 
1281                 aMixA.Merge(aColorBottomLeft, 255 - sal_uInt8((y * 255) / nH));
1282                 pContent->SetPixel(y, 0, aMixA);
1283                 pAlpha->SetPixelIndex(y, 0, nAlpha);
1284 
1285                 // #123690# Caution! When nW is 1, x == nW is possible (!)
1286                 if(x < nW)
1287                 {
1288                     Color aMixB(aColorTopRight);
1289 
1290                     aMixB.Merge(aColorBottomRight, 255 - sal_uInt8((y * 255) / nH));
1291                     pContent->SetPixel(y, x, aMixB);
1292                     pAlpha->SetPixelIndex(y, x, nAlpha);
1293                 }
1294             }
1295 
1296             // #123690# Caution! When nH is 1, y == nH is possible (!)
1297             if(y < nH)
1298             {
1299                 // x == 0, y == nH - 1, bottom-left corner
1300                 pContent->SetPixel(y, 0, aColorBottomLeft);
1301                 pAlpha->SetPixelIndex(y, 0, nAlpha);
1302 
1303                 // y == nH - 1, bottom line left to right
1304                 for(x = 1; x < nW - 1; x++)
1305                 {
1306                     Color aMix(aColorBottomLeft);
1307 
1308                     aMix.Merge(aColorBottomRight, 255 - sal_uInt8(((x - 0)* 255) / nW));
1309                     pContent->SetPixel(y, x, aMix);
1310                     pAlpha->SetPixelIndex(y, x, nAlpha);
1311                 }
1312 
1313                 // x == nW - 1, y == nH - 1, bottom-right corner
1314                 // #123690# Caution! When nW is 1, x == nW is possible (!)
1315                 if(x < nW)
1316                 {
1317                     pContent->SetPixel(y, x, aColorBottomRight);
1318                     pAlpha->SetPixelIndex(y, x, nAlpha);
1319                 }
1320             }
1321 
1322             aContent.ReleaseAccess(pContent);
1323             aAlpha.ReleaseAccess(pAlpha);
1324 
1325             aLastResult = BitmapEx(aContent, aAlpha);
1326         }
1327         else
1328         {
1329             if(pContent)
1330             {
1331                 aContent.ReleaseAccess(pContent);
1332             }
1333 
1334             if(pAlpha)
1335             {
1336                 aAlpha.ReleaseAccess(pAlpha);
1337             }
1338         }
1339     }
1340 
1341     return aLastResult;
1342 }
1343 
1344 // ------------------------------------------------------------------
1345 // eof
1346