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