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