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