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