1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
22 #include <rtl/strbuf.hxx>
24 #include <tools/stream.hxx>
25 #include <tools/debug.hxx>
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>
38 #include <impimagetree.hxx>
39 #include <basegfx/matrix/b2dhommatrixtools.hxx>
43 #include <salinst.hxx>
45 #include <com/sun/star/beans/XFastPropertySet.hpp>
46 using namespace ::com::sun::star
;
48 BitmapEx::BitmapEx() :
49 eTransparent( TRANSPARENT_NONE
),
54 BitmapEx::BitmapEx( const BitmapEx
& rBitmapEx
) :
55 aBitmap ( rBitmapEx
.aBitmap
),
56 aMask ( rBitmapEx
.aMask
),
57 aBitmapSize ( rBitmapEx
.aBitmapSize
),
58 aTransparentColor ( rBitmapEx
.aTransparentColor
),
59 eTransparent ( rBitmapEx
.eTransparent
),
60 bAlpha ( rBitmapEx
.bAlpha
)
64 BitmapEx::BitmapEx( const BitmapEx
& rBitmapEx
, Point aSrc
, Size aSize
) :
65 eTransparent( TRANSPARENT_NONE
),
68 if( rBitmapEx
.IsEmpty() )
71 aBitmap
= Bitmap( aSize
, rBitmapEx
.aBitmap
.GetBitCount() );
73 if( rBitmapEx
.IsAlpha() )
76 aMask
= AlphaMask( aSize
).ImplGetBitmap();
78 else if( rBitmapEx
.IsTransparent() )
79 aMask
= Bitmap( aSize
, rBitmapEx
.aMask
.GetBitCount() );
81 Rectangle
aDestRect( Point( 0, 0 ), aSize
);
82 Rectangle
aSrcRect( aSrc
, aSize
);
83 CopyPixel( aDestRect
, aSrcRect
, &rBitmapEx
);
86 BitmapEx::BitmapEx( const ResId
& rResId
) :
87 eTransparent( TRANSPARENT_NONE
),
90 static ImplImageTreeSingletonRef aImageTree
;
91 ResMgr
* pResMgr
= NULL
;
93 ResMgr::GetResourceSkipHeader( rResId
.SetRT( RSC_BITMAP
), &pResMgr
);
97 const OUString
aFileName( pResMgr
->ReadString() );
98 OUString aCurrentSymbolsStyle
= Application::GetSettings().GetStyleSettings().GetCurrentSymbolsStyleName();
100 if( !aImageTree
->loadImage( aFileName
, aCurrentSymbolsStyle
, *this, true ) )
103 OStringBuffer
aErrorStr(
104 "BitmapEx::BitmapEx( const ResId& rResId ): could not load image <");
105 aErrorStr
.append(OUStringToOString(aFileName
, RTL_TEXTENCODING_ASCII_US
)).append('>');
106 OSL_FAIL(aErrorStr
.getStr());
111 BitmapEx::BitmapEx( const Bitmap
& rBmp
) :
113 aBitmapSize ( aBitmap
.GetSizePixel() ),
114 eTransparent( TRANSPARENT_NONE
),
119 BitmapEx::BitmapEx( const Bitmap
& rBmp
, const Bitmap
& rMask
) :
122 aBitmapSize ( aBitmap
.GetSizePixel() ),
123 eTransparent ( !rMask
? TRANSPARENT_NONE
: TRANSPARENT_BITMAP
),
126 if(!!aBitmap
&& !!aMask
&& aBitmap
.GetSizePixel() != aMask
.GetSizePixel())
128 OSL_ENSURE(false, "Mask size differs from Bitmap size, corrected Mask (!)");
129 aMask
.Scale(aBitmap
.GetSizePixel());
132 // Ensure a mask is exactly one bit deep
133 if( !!aMask
&& aMask
.GetBitCount() != 1 )
135 OSL_TRACE("BitmapEx: forced mask to monochrome");
136 aMask
.ImplMakeMono( 255 );
140 BitmapEx::BitmapEx( const Bitmap
& rBmp
, const AlphaMask
& rAlphaMask
) :
142 aMask ( rAlphaMask
.ImplGetBitmap() ),
143 aBitmapSize ( aBitmap
.GetSizePixel() ),
144 eTransparent ( !rAlphaMask
? TRANSPARENT_NONE
: TRANSPARENT_BITMAP
),
145 bAlpha ( !rAlphaMask
? sal_False
: sal_True
)
147 if(!!aBitmap
&& !!aMask
&& aBitmap
.GetSizePixel() != aMask
.GetSizePixel())
149 OSL_ENSURE(false, "Alpha size differs from Bitmap size, corrected Mask (!)");
150 aMask
.Scale(rBmp
.GetSizePixel());
153 // #i75531# the workaround below can go when
154 // X11SalGraphics::drawAlphaBitmap()'s render acceleration
155 // can handle the bitmap depth mismatch directly
156 if( aBitmap
.GetBitCount() < aMask
.GetBitCount() )
157 aBitmap
.Convert( BMP_CONVERSION_24BIT
);
160 BitmapEx::BitmapEx( const Bitmap
& rBmp
, const Color
& rTransparentColor
) :
162 aBitmapSize ( aBitmap
.GetSizePixel() ),
163 aTransparentColor ( rTransparentColor
),
164 eTransparent ( TRANSPARENT_BITMAP
),
167 aMask
= aBitmap
.CreateMask( aTransparentColor
);
169 DBG_ASSERT( rBmp
.GetSizePixel() == aMask
.GetSizePixel(),
170 "BitmapEx::BitmapEx(): size mismatch for bitmap and alpha mask." );
173 BitmapEx::~BitmapEx()
177 BitmapEx
& BitmapEx::operator=( const BitmapEx
& rBitmapEx
)
179 if( &rBitmapEx
!= this )
181 aBitmap
= rBitmapEx
.aBitmap
;
182 aMask
= rBitmapEx
.aMask
;
183 aBitmapSize
= rBitmapEx
.aBitmapSize
;
184 aTransparentColor
= rBitmapEx
.aTransparentColor
;
185 eTransparent
= rBitmapEx
.eTransparent
;
186 bAlpha
= rBitmapEx
.bAlpha
;
192 sal_Bool
BitmapEx::operator==( const BitmapEx
& rBitmapEx
) const
194 if( eTransparent
!= rBitmapEx
.eTransparent
)
197 if( aBitmap
!= rBitmapEx
.aBitmap
)
200 if( aBitmapSize
!= rBitmapEx
.aBitmapSize
)
203 if( eTransparent
== TRANSPARENT_NONE
)
206 if( eTransparent
== TRANSPARENT_COLOR
)
207 return aTransparentColor
== rBitmapEx
.aTransparentColor
;
209 return( ( aMask
== rBitmapEx
.aMask
) && ( bAlpha
== rBitmapEx
.bAlpha
) );
212 sal_Bool
BitmapEx::IsEqual( const BitmapEx
& rBmpEx
) const
214 return( rBmpEx
.eTransparent
== eTransparent
&&
215 rBmpEx
.bAlpha
== bAlpha
&&
216 rBmpEx
.aBitmap
.IsEqual( aBitmap
) &&
217 rBmpEx
.aMask
.IsEqual( aMask
) );
220 sal_Bool
BitmapEx::IsEmpty() const
222 return( aBitmap
.IsEmpty() && aMask
.IsEmpty() );
225 void BitmapEx::SetEmpty()
229 eTransparent
= TRANSPARENT_NONE
;
233 void BitmapEx::Clear()
238 sal_Bool
BitmapEx::IsTransparent() const
240 return( eTransparent
!= TRANSPARENT_NONE
);
243 sal_Bool
BitmapEx::IsAlpha() const
245 return( IsTransparent() && bAlpha
);
248 Bitmap
BitmapEx::GetBitmap( const Color
* pTransReplaceColor
) const
250 Bitmap
aRetBmp( aBitmap
);
252 if( pTransReplaceColor
&& ( eTransparent
!= TRANSPARENT_NONE
) )
256 if( eTransparent
== TRANSPARENT_COLOR
)
257 aTempMask
= aBitmap
.CreateMask( aTransparentColor
);
262 aRetBmp
.Replace( aTempMask
, *pTransReplaceColor
);
264 aRetBmp
.Replace( GetAlpha(), *pTransReplaceColor
);
270 Bitmap
BitmapEx::GetMask() const
272 Bitmap
aRet( aMask
);
275 aRet
.ImplMakeMono( 255 );
280 AlphaMask
BitmapEx::GetAlpha() const
285 aAlpha
.ImplSetBitmap( aMask
);
294 sal_uLong
BitmapEx::GetSizeBytes() const
296 sal_uLong nSizeBytes
= aBitmap
.GetSizeBytes();
298 if( eTransparent
== TRANSPARENT_BITMAP
)
299 nSizeBytes
+= aMask
.GetSizeBytes();
304 sal_uLong
BitmapEx::GetChecksum() const
306 sal_uInt32 nCrc
= aBitmap
.GetChecksum();
309 UInt32ToSVBT32( (long) eTransparent
, aBT32
);
310 nCrc
= rtl_crc32( nCrc
, aBT32
, 4 );
312 UInt32ToSVBT32( (long) bAlpha
, aBT32
);
313 nCrc
= rtl_crc32( nCrc
, aBT32
, 4 );
315 if( ( TRANSPARENT_BITMAP
== eTransparent
) && !aMask
.IsEmpty() )
317 UInt32ToSVBT32( aMask
.GetChecksum(), aBT32
);
318 nCrc
= rtl_crc32( nCrc
, aBT32
, 4 );
324 // ------------------------------------------------------------------
326 void BitmapEx::SetSizePixel( const Size
& rNewSize
, sal_uInt32 nScaleFlag
)
328 if(GetSizePixel() != rNewSize
)
330 Scale( rNewSize
, nScaleFlag
);
334 sal_Bool
BitmapEx::Invert()
336 sal_Bool bRet
= sal_False
;
340 bRet
= aBitmap
.Invert();
342 if( bRet
&& ( eTransparent
== TRANSPARENT_COLOR
) )
343 aTransparentColor
= BitmapColor( aTransparentColor
).Invert();
349 sal_Bool
BitmapEx::Mirror( sal_uLong nMirrorFlags
)
351 sal_Bool bRet
= sal_False
;
355 bRet
= aBitmap
.Mirror( nMirrorFlags
);
357 if( bRet
&& ( eTransparent
== TRANSPARENT_BITMAP
) && !!aMask
)
358 aMask
.Mirror( nMirrorFlags
);
364 // ------------------------------------------------------------------
366 sal_Bool
BitmapEx::Scale( const double& rScaleX
, const double& rScaleY
, sal_uInt32 nScaleFlag
)
368 sal_Bool bRet
= sal_False
;
372 bRet
= aBitmap
.Scale( rScaleX
, rScaleY
, nScaleFlag
);
374 if( bRet
&& ( eTransparent
== TRANSPARENT_BITMAP
) && !!aMask
)
376 aMask
.Scale( rScaleX
, rScaleY
, nScaleFlag
);
379 aBitmapSize
= aBitmap
.GetSizePixel();
381 DBG_ASSERT( !aMask
|| aBitmap
.GetSizePixel() == aMask
.GetSizePixel(),
382 "BitmapEx::Scale(): size mismatch for bitmap and alpha mask." );
388 // ------------------------------------------------------------------------
390 sal_Bool
BitmapEx::Scale( const Size
& rNewSize
, sal_uInt32 nScaleFlag
)
394 if( aBitmapSize
.Width() && aBitmapSize
.Height() &&
395 ( rNewSize
.Width() != aBitmapSize
.Width() ||
396 rNewSize
.Height() != aBitmapSize
.Height() ) )
398 bRet
= Scale( (double) rNewSize
.Width() / aBitmapSize
.Width(),
399 (double) rNewSize
.Height() / aBitmapSize
.Height(),
408 sal_Bool
BitmapEx::Rotate( long nAngle10
, const Color
& rFillColor
)
410 sal_Bool bRet
= sal_False
;
414 const bool bTransRotate
= ( Color( COL_TRANSPARENT
) == rFillColor
);
418 if( eTransparent
== TRANSPARENT_COLOR
)
419 bRet
= aBitmap
.Rotate( nAngle10
, aTransparentColor
);
422 bRet
= aBitmap
.Rotate( nAngle10
, COL_BLACK
);
424 if( eTransparent
== TRANSPARENT_NONE
)
426 aMask
= Bitmap( aBitmapSize
, 1 );
427 aMask
.Erase( COL_BLACK
);
428 eTransparent
= TRANSPARENT_BITMAP
;
431 if( bRet
&& !!aMask
)
432 aMask
.Rotate( nAngle10
, COL_WHITE
);
437 bRet
= aBitmap
.Rotate( nAngle10
, rFillColor
);
439 if( bRet
&& ( eTransparent
== TRANSPARENT_BITMAP
) && !!aMask
)
440 aMask
.Rotate( nAngle10
, COL_WHITE
);
443 aBitmapSize
= aBitmap
.GetSizePixel();
445 DBG_ASSERT( !aMask
|| aBitmap
.GetSizePixel() == aMask
.GetSizePixel(),
446 "BitmapEx::Rotate(): size mismatch for bitmap and alpha mask." );
452 sal_Bool
BitmapEx::Crop( const Rectangle
& rRectPixel
)
454 sal_Bool bRet
= sal_False
;
458 bRet
= aBitmap
.Crop( rRectPixel
);
460 if( bRet
&& ( eTransparent
== TRANSPARENT_BITMAP
) && !!aMask
)
461 aMask
.Crop( rRectPixel
);
463 aBitmapSize
= aBitmap
.GetSizePixel();
465 DBG_ASSERT( !aMask
|| aBitmap
.GetSizePixel() == aMask
.GetSizePixel(),
466 "BitmapEx::Crop(): size mismatch for bitmap and alpha mask." );
472 sal_Bool
BitmapEx::Convert( BmpConversion eConversion
)
474 return( !!aBitmap
? aBitmap
.Convert( eConversion
) : sal_False
);
477 sal_Bool
BitmapEx::ReduceColors( sal_uInt16 nNewColorCount
, BmpReduce eReduce
)
479 return( !!aBitmap
? aBitmap
.ReduceColors( nNewColorCount
, eReduce
) : sal_False
);
482 sal_Bool
BitmapEx::Expand( sal_uLong nDX
, sal_uLong nDY
, const Color
* pInitColor
, sal_Bool bExpandTransparent
)
484 sal_Bool bRet
= sal_False
;
488 bRet
= aBitmap
.Expand( nDX
, nDY
, pInitColor
);
490 if( bRet
&& ( eTransparent
== TRANSPARENT_BITMAP
) && !!aMask
)
492 Color
aColor( bExpandTransparent
? COL_WHITE
: COL_BLACK
);
493 aMask
.Expand( nDX
, nDY
, &aColor
);
496 aBitmapSize
= aBitmap
.GetSizePixel();
498 DBG_ASSERT( !aMask
|| aBitmap
.GetSizePixel() == aMask
.GetSizePixel(),
499 "BitmapEx::Expand(): size mismatch for bitmap and alpha mask." );
505 sal_Bool
BitmapEx::CopyPixel( const Rectangle
& rRectDst
, const Rectangle
& rRectSrc
,
506 const BitmapEx
* pBmpExSrc
)
508 sal_Bool bRet
= sal_False
;
510 if( !pBmpExSrc
|| pBmpExSrc
->IsEmpty() )
512 if( !aBitmap
.IsEmpty() )
514 bRet
= aBitmap
.CopyPixel( rRectDst
, rRectSrc
);
516 if( bRet
&& ( eTransparent
== TRANSPARENT_BITMAP
) && !!aMask
)
517 aMask
.CopyPixel( rRectDst
, rRectSrc
);
522 if( !aBitmap
.IsEmpty() )
524 bRet
= aBitmap
.CopyPixel( rRectDst
, rRectSrc
, &pBmpExSrc
->aBitmap
);
528 if( pBmpExSrc
->IsAlpha() )
531 // cast to use the optimized AlphaMask::CopyPixel
532 ((AlphaMask
*) &aMask
)->CopyPixel( rRectDst
, rRectSrc
, (AlphaMask
*)&pBmpExSrc
->aMask
);
533 else if( IsTransparent() )
535 AlphaMask
* pAlpha
= new AlphaMask( aMask
);
537 aMask
= pAlpha
->ImplGetBitmap();
540 aMask
.CopyPixel( rRectDst
, rRectSrc
, &pBmpExSrc
->aMask
);
544 sal_uInt8 cBlack
= 0;
545 AlphaMask
* pAlpha
= new AlphaMask( GetSizePixel(), &cBlack
);
547 aMask
= pAlpha
->ImplGetBitmap();
549 eTransparent
= TRANSPARENT_BITMAP
;
551 aMask
.CopyPixel( rRectDst
, rRectSrc
, &pBmpExSrc
->aMask
);
554 else if( pBmpExSrc
->IsTransparent() )
558 AlphaMask
aAlpha( pBmpExSrc
->aMask
);
559 aMask
.CopyPixel( rRectDst
, rRectSrc
, &aAlpha
.ImplGetBitmap() );
561 else if( IsTransparent() )
562 aMask
.CopyPixel( rRectDst
, rRectSrc
, &pBmpExSrc
->aMask
);
565 aMask
= Bitmap( GetSizePixel(), 1 );
566 aMask
.Erase( Color( COL_BLACK
) );
567 eTransparent
= TRANSPARENT_BITMAP
;
568 aMask
.CopyPixel( rRectDst
, rRectSrc
, &pBmpExSrc
->aMask
);
573 sal_uInt8 cBlack
= 0;
574 const AlphaMask
aAlphaSrc( pBmpExSrc
->GetSizePixel(), &cBlack
);
576 aMask
.CopyPixel( rRectDst
, rRectSrc
, &aAlphaSrc
.ImplGetBitmap() );
578 else if( IsTransparent() )
580 Bitmap
aMaskSrc( pBmpExSrc
->GetSizePixel(), 1 );
582 aMaskSrc
.Erase( Color( COL_BLACK
) );
583 aMask
.CopyPixel( rRectDst
, rRectSrc
, &aMaskSrc
);
592 sal_Bool
BitmapEx::Erase( const Color
& rFillColor
)
594 sal_Bool bRet
= sal_False
;
598 bRet
= aBitmap
.Erase( rFillColor
);
600 if( bRet
&& ( eTransparent
== TRANSPARENT_BITMAP
) && !!aMask
)
602 // Respect transparency on fill color
603 if( rFillColor
.GetTransparency() )
605 const Color
aFill( rFillColor
.GetTransparency(), rFillColor
.GetTransparency(), rFillColor
.GetTransparency() );
606 aMask
.Erase( aFill
);
610 const Color
aBlack( COL_BLACK
);
611 aMask
.Erase( aBlack
);
619 sal_Bool
BitmapEx::Dither( sal_uLong nDitherFlags
)
621 return( !!aBitmap
? aBitmap
.Dither( nDitherFlags
) : sal_False
);
624 sal_Bool
BitmapEx::Replace( const Color
& rSearchColor
, const Color
& rReplaceColor
, sal_uLong nTol
)
626 return( !!aBitmap
? aBitmap
.Replace( rSearchColor
, rReplaceColor
, nTol
) : sal_False
);
629 sal_Bool
BitmapEx::Replace( const Color
* pSearchColors
, const Color
* pReplaceColors
, sal_uLong nColorCount
, const sal_uLong
* pTols
)
631 return( !!aBitmap
? aBitmap
.Replace( pSearchColors
, pReplaceColors
, nColorCount
, (sal_uLong
*) pTols
) : sal_False
);
634 sal_Bool
BitmapEx::Adjust( short nLuminancePercent
, short nContrastPercent
,
635 short nChannelRPercent
, short nChannelGPercent
, short nChannelBPercent
,
636 double fGamma
, sal_Bool bInvert
)
638 return( !!aBitmap
? aBitmap
.Adjust( nLuminancePercent
, nContrastPercent
,
639 nChannelRPercent
, nChannelGPercent
, nChannelBPercent
,
640 fGamma
, bInvert
) : sal_False
);
643 sal_Bool
BitmapEx::Filter( BmpFilter eFilter
, const BmpFilterParam
* pFilterParam
, const Link
* pProgress
)
645 return( !!aBitmap
? aBitmap
.Filter( eFilter
, pFilterParam
, pProgress
) : sal_False
);
648 void BitmapEx::Draw( OutputDevice
* pOutDev
, const Point
& rDestPt
) const
650 pOutDev
->DrawBitmapEx( rDestPt
, *this );
653 void BitmapEx::Draw( OutputDevice
* pOutDev
,
654 const Point
& rDestPt
, const Size
& rDestSize
) const
656 pOutDev
->DrawBitmapEx( rDestPt
, rDestSize
, *this );
659 BitmapEx
BitmapEx:: AutoScaleBitmap(BitmapEx
& aBitmap
, const long aStandardSize
)
661 Point
aEmptyPoint(0,0);
664 BitmapEx aRet
= aBitmap
;
665 double imgOldWidth
= aRet
.GetSizePixel().Width();
666 double imgOldHeight
=aRet
.GetSizePixel().Height();
669 if (imgOldWidth
>= aStandardSize
|| imgOldHeight
>= aStandardSize
)
671 sal_Int32 imgNewWidth
= 0;
672 sal_Int32 imgNewHeight
= 0;
673 if (imgOldWidth
>= imgOldHeight
)
675 imgNewWidth
= aStandardSize
;
676 imgNewHeight
= sal_Int32(imgOldHeight
/ (imgOldWidth
/ aStandardSize
) + 0.5);
678 imgposY
= (aStandardSize
- (imgOldHeight
/ (imgOldWidth
/ aStandardSize
) + 0.5)) / 2 + 0.5;
682 imgNewHeight
= aStandardSize
;
683 imgNewWidth
= sal_Int32(imgOldWidth
/ (imgOldHeight
/ aStandardSize
) + 0.5);
685 imgposX
= (aStandardSize
- (imgOldWidth
/ (imgOldHeight
/ aStandardSize
) + 0.5)) / 2 + 0.5;
688 aScaledSize
= Size( imgNewWidth
, imgNewHeight
);
689 aRet
.Scale( aScaledSize
, BMP_SCALE_BESTQUALITY
);
693 imgposX
= (aStandardSize
- imgOldWidth
) / 2 + 0.5;
694 imgposY
= (aStandardSize
- imgOldHeight
) / 2 + 0.5;
697 Size
aStdSize( aStandardSize
, aStandardSize
);
698 Rectangle
aRect(aEmptyPoint
, aStdSize
);
700 VirtualDevice
aVirDevice( *Application::GetDefaultDevice(), 0, 1 );
701 aVirDevice
.SetOutputSizePixel( aStdSize
);
702 aVirDevice
.SetFillColor( COL_TRANSPARENT
);
703 aVirDevice
.SetLineColor( COL_TRANSPARENT
);
705 // Draw a rect into virDevice
706 aVirDevice
.DrawRect( aRect
);
707 Point
aPointPixel( (long)imgposX
, (long)imgposY
);
708 aVirDevice
.DrawBitmapEx( aPointPixel
, aRet
);
709 aRet
= aVirDevice
.GetBitmapEx( aEmptyPoint
, aStdSize
);
714 sal_uInt8
BitmapEx::GetTransparency(sal_Int32 nX
, sal_Int32 nY
) const
716 sal_uInt8
nTransparency(0xff);
718 if(!aBitmap
.IsEmpty())
720 if(nX
>= 0 && nX
< aBitmapSize
.Width() && nY
>= 0 && nY
< aBitmapSize
.Height())
724 case TRANSPARENT_NONE
:
726 // Not transparent, ergo all covered
727 nTransparency
= 0x00;
730 case TRANSPARENT_COLOR
:
732 Bitmap
aTestBitmap(aBitmap
);
733 BitmapReadAccess
* pRead
= aTestBitmap
.AcquireReadAccess();
737 const Color aColor
= pRead
->GetColor(nY
, nX
);
739 // If color is not equal to TransparentColor, we are not transparent
740 if(aColor
!= aTransparentColor
)
742 nTransparency
= 0x00;
745 aTestBitmap
.ReleaseAccess(pRead
);
749 case TRANSPARENT_BITMAP
:
753 Bitmap
aTestBitmap(aMask
);
754 BitmapReadAccess
* pRead
= aTestBitmap
.AcquireReadAccess();
758 const BitmapColor
aBitmapColor(pRead
->GetPixel(nY
, nX
));
762 nTransparency
= aBitmapColor
.GetIndex();
766 if(0x00 == aBitmapColor
.GetIndex())
768 nTransparency
= 0x00;
772 aTestBitmap
.ReleaseAccess(pRead
);
781 return nTransparency
;
784 // Shift alpha transparent pixels between cppcanvas/ implementations
785 // and vcl in a generally grotesque and under-performing fashion
786 bool BitmapEx::Create( const ::com::sun::star::uno::Reference
<
787 ::com::sun::star::rendering::XBitmapCanvas
> &xBitmapCanvas
,
790 uno::Reference
< beans::XFastPropertySet
> xFastPropertySet( xBitmapCanvas
, uno::UNO_QUERY
);
791 if( xFastPropertySet
.get() )
793 // 0 means get BitmapEx
794 uno::Any aAny
= xFastPropertySet
->getFastPropertyValue( 0 );
795 BitmapEx
* pBitmapEx
= (BitmapEx
*) *reinterpret_cast<const sal_Int64
*>(aAny
.getValue());
804 SalBitmap
* pSalBmp
, *pSalMask
;
806 pSalBmp
= ImplGetSVData()->mpDefInst
->CreateSalBitmap();
807 pSalMask
= ImplGetSVData()->mpDefInst
->CreateSalBitmap();
809 Size
aLocalSize(rSize
);
810 if( pSalBmp
->Create( xBitmapCanvas
, aLocalSize
) )
812 if ( pSalMask
->Create( xBitmapCanvas
, aLocalSize
, true ) )
814 *this = BitmapEx(Bitmap(pSalBmp
), Bitmap(pSalMask
) );
819 *this = BitmapEx(Bitmap(pSalBmp
));
830 // ------------------------------------------------------------------
834 Bitmap
impTransformBitmap(
835 const Bitmap
& rSource
,
836 const Size aDestinationSize
,
837 const basegfx::B2DHomMatrix
& rTransform
,
840 Bitmap
aDestination(aDestinationSize
, 24);
841 BitmapWriteAccess
* pWrite
= aDestination
.AcquireWriteAccess();
845 //const Size aContentSizePixel(rSource.GetSizePixel());
846 BitmapReadAccess
* pRead
= (const_cast< Bitmap
& >(rSource
)).AcquireReadAccess();
850 const Size
aDestinationSizePixel(aDestination
.GetSizePixel());
851 const BitmapColor
aOutside(BitmapColor(0xff, 0xff, 0xff));
853 for(sal_Int32
y(0L); y
< aDestinationSizePixel
.getHeight(); y
++)
855 for(sal_Int32
x(0L); x
< aDestinationSizePixel
.getWidth(); x
++)
857 const basegfx::B2DPoint
aSourceCoor(rTransform
* basegfx::B2DPoint(x
, y
));
864 pRead
->GetInterpolatedColorWithFallback(
871 // this version does the correct <= 0.0 checks, so no need
872 // to do the static_cast< sal_Int32 > self and make an error
876 pRead
->GetColorWithFallback(
890 rSource
.AdaptBitCount(aDestination
);
894 } // end of anonymous namespace
896 BitmapEx
BitmapEx::TransformBitmapEx(
899 const basegfx::B2DHomMatrix
& rTransformation
,
902 if(fWidth
<= 1 || fHeight
<= 1)
905 // force destination to 24 bit, we want to smooth output
906 const Size
aDestinationSize(basegfx::fround(fWidth
), basegfx::fround(fHeight
));
907 const Bitmap
aDestination(impTransformBitmap(GetBitmap(), aDestinationSize
, rTransformation
, bSmooth
));
914 const Bitmap
aAlpha(impTransformBitmap(GetAlpha().GetBitmap(), aDestinationSize
, rTransformation
, bSmooth
));
915 return BitmapEx(aDestination
, AlphaMask(aAlpha
));
919 const Bitmap
aLclMask(impTransformBitmap(GetMask(), aDestinationSize
, rTransformation
, false));
920 return BitmapEx(aDestination
, aLclMask
);
924 return BitmapEx(aDestination
);
927 // ------------------------------------------------------------------
929 BitmapEx
BitmapEx::getTransformed(
930 const basegfx::B2DHomMatrix
& rTransformation
,
931 const basegfx::B2DRange
& rVisibleRange
,
940 const sal_uInt32
nSourceWidth(GetSizePixel().Width());
941 const sal_uInt32
nSourceHeight(GetSizePixel().Height());
943 if(!nSourceWidth
|| !nSourceHeight
)
947 basegfx::B2DRange
aOutlineRange(0.0, 0.0, 1.0, 1.0);
949 aOutlineRange
.transform(rTransformation
);
951 // create visible range from it by moving from relative to absolute
952 basegfx::B2DRange
aVisibleRange(rVisibleRange
);
954 aVisibleRange
.transform(
955 basegfx::tools::createScaleTranslateB2DHomMatrix(
956 aOutlineRange
.getRange(),
957 aOutlineRange
.getMinimum()));
959 // get target size (which is visible range's size)
960 double fWidth(aVisibleRange
.getWidth());
961 double fHeight(aVisibleRange
.getHeight());
963 if(fWidth
< 1.0 || fHeight
< 1.0)
968 // test if discrete size (pixel) maybe too big and limit it
969 const double fArea(fWidth
* fHeight
);
970 const bool bNeedToReduce(basegfx::fTools::more(fArea
, fMaximumArea
));
971 double fReduceFactor(1.0);
975 fReduceFactor
= sqrt(fMaximumArea
/ fArea
);
976 fWidth
*= fReduceFactor
;
977 fHeight
*= fReduceFactor
;
980 // Build complete transform from source pixels to target pixels.
981 // Start by scaling from source pixel size to unit coordinates
982 basegfx::B2DHomMatrix
aTransform(
983 basegfx::tools::createScaleB2DHomMatrix(
985 1.0 / nSourceHeight
));
987 // multiply with given transform which leads from unit coordinates inside
989 aTransform
= rTransformation
* aTransform
;
991 // substract top-left of absolute VisibleRange
992 aTransform
.translate(
993 -aVisibleRange
.getMinX(),
994 -aVisibleRange
.getMinY());
996 // scale to target pixels (if needed)
999 aTransform
.scale(fReduceFactor
, fReduceFactor
);
1002 // invert to get transformation from target pixel coordiates to source pixels
1003 aTransform
.invert();
1005 // create bitmap using source, destination and linear back-transformation
1006 aRetval
= TransformBitmapEx(fWidth
, fHeight
, aTransform
, bSmooth
);
1011 // ------------------------------------------------------------------
1013 BitmapEx
BitmapEx::ModifyBitmapEx(const basegfx::BColorModifierStack
& rBColorModifierStack
) const
1015 Bitmap
aChangedBitmap(GetBitmap());
1018 for(sal_uInt32
a(rBColorModifierStack
.count()); a
&& !bDone
; )
1020 const basegfx::BColorModifierSharedPtr
& rModifier
= rBColorModifierStack
.getBColorModifier(--a
);
1021 const basegfx::BColorModifier_replace
* pReplace
= dynamic_cast< const basegfx::BColorModifier_replace
* >(rModifier
.get());
1028 // clear bitmap with dest color
1029 if(aChangedBitmap
.GetBitCount() <= 8)
1031 // do NOT use erase; for e.g. 8bit Bitmaps, the nearest color to the given
1032 // erase color is determined and used -> this may be different from what is
1033 // wanted here. Better create a new bitmap with the needed color explicitely
1034 BitmapReadAccess
* pReadAccess
= aChangedBitmap
.AcquireReadAccess();
1035 OSL_ENSURE(pReadAccess
, "Got no Bitmap ReadAccess ?!?");
1039 BitmapPalette
aNewPalette(pReadAccess
->GetPalette());
1040 aNewPalette
[0] = BitmapColor(Color(pReplace
->getBColor()));
1041 aChangedBitmap
= Bitmap(
1042 aChangedBitmap
.GetSizePixel(),
1043 aChangedBitmap
.GetBitCount(),
1050 aChangedBitmap
.Erase(Color(pReplace
->getBColor()));
1055 // erase bitmap, caller will know to paint direct
1056 aChangedBitmap
.SetEmpty();
1063 BitmapWriteAccess
* pContent
= aChangedBitmap
.AcquireWriteAccess();
1067 const double fConvertColor(1.0 / 255.0);
1069 if(pContent
->HasPalette())
1071 const sal_uInt16
nCount(pContent
->GetPaletteEntryCount());
1073 for(sal_uInt16
b(0); b
< nCount
; b
++)
1075 const BitmapColor
& rCol
= pContent
->GetPaletteColor(b
);
1076 const basegfx::BColor
aBSource(
1077 rCol
.GetRed() * fConvertColor
,
1078 rCol
.GetGreen() * fConvertColor
,
1079 rCol
.GetBlue() * fConvertColor
);
1080 const basegfx::BColor
aBDest(rModifier
->getModifiedColor(aBSource
));
1081 pContent
->SetPaletteColor(b
, BitmapColor(Color(aBDest
)));
1084 else if(BMP_FORMAT_24BIT_TC_BGR
== pContent
->GetScanlineFormat())
1086 for(sal_uInt32
y(0L); y
< (sal_uInt32
)pContent
->Height(); y
++)
1088 Scanline pScan
= pContent
->GetScanline(y
);
1090 for(sal_uInt32
x(0L); x
< (sal_uInt32
)pContent
->Width(); x
++)
1092 const basegfx::BColor
aBSource(
1093 *(pScan
+ 2)* fConvertColor
,
1094 *(pScan
+ 1) * fConvertColor
,
1095 *pScan
* fConvertColor
);
1096 const basegfx::BColor
aBDest(rModifier
->getModifiedColor(aBSource
));
1097 *pScan
++ = static_cast< sal_uInt8
>(aBDest
.getBlue() * 255.0);
1098 *pScan
++ = static_cast< sal_uInt8
>(aBDest
.getGreen() * 255.0);
1099 *pScan
++ = static_cast< sal_uInt8
>(aBDest
.getRed() * 255.0);
1103 else if(BMP_FORMAT_24BIT_TC_RGB
== pContent
->GetScanlineFormat())
1105 for(sal_uInt32
y(0L); y
< (sal_uInt32
)pContent
->Height(); y
++)
1107 Scanline pScan
= pContent
->GetScanline(y
);
1109 for(sal_uInt32
x(0L); x
< (sal_uInt32
)pContent
->Width(); x
++)
1111 const basegfx::BColor
aBSource(
1112 *pScan
* fConvertColor
,
1113 *(pScan
+ 1) * fConvertColor
,
1114 *(pScan
+ 2) * fConvertColor
);
1115 const basegfx::BColor
aBDest(rModifier
->getModifiedColor(aBSource
));
1116 *pScan
++ = static_cast< sal_uInt8
>(aBDest
.getRed() * 255.0);
1117 *pScan
++ = static_cast< sal_uInt8
>(aBDest
.getGreen() * 255.0);
1118 *pScan
++ = static_cast< sal_uInt8
>(aBDest
.getBlue() * 255.0);
1124 for(sal_uInt32
y(0L); y
< (sal_uInt32
)pContent
->Height(); y
++)
1126 for(sal_uInt32
x(0L); x
< (sal_uInt32
)pContent
->Width(); x
++)
1128 const BitmapColor
aBMCol(pContent
->GetColor(y
, x
));
1129 const basegfx::BColor
aBSource(
1130 (double)aBMCol
.GetRed() * fConvertColor
,
1131 (double)aBMCol
.GetGreen() * fConvertColor
,
1132 (double)aBMCol
.GetBlue() * fConvertColor
);
1133 const basegfx::BColor
aBDest(rModifier
->getModifiedColor(aBSource
));
1135 pContent
->SetPixel(y
, x
, BitmapColor(Color(aBDest
)));
1145 if(aChangedBitmap
.IsEmpty())
1155 return BitmapEx(aChangedBitmap
, GetAlpha());
1159 return BitmapEx(aChangedBitmap
, GetMask());
1164 return BitmapEx(aChangedBitmap
);
1169 // -----------------------------------------------------------------------------
1171 BitmapEx VCL_DLLPUBLIC
createBlendFrame(
1174 Color aColorTopLeft
,
1175 Color aColorBottomRight
)
1177 const sal_uInt32
nW(rSize
.Width());
1178 const sal_uInt32
nH(rSize
.Height());
1182 Color
aColTopRight(aColorTopLeft
);
1183 Color
aColBottomLeft(aColorTopLeft
);
1184 const sal_uInt32
nDE(nW
+ nH
);
1186 aColTopRight
.Merge(aColorBottomRight
, 255 - sal_uInt8((nW
* 255) / nDE
));
1187 aColBottomLeft
.Merge(aColorBottomRight
, 255 - sal_uInt8((nH
* 255) / nDE
));
1189 return createBlendFrame(rSize
, nAlpha
, aColorTopLeft
, aColTopRight
, aColorBottomRight
, aColBottomLeft
);
1195 BitmapEx VCL_DLLPUBLIC
createBlendFrame(
1198 Color aColorTopLeft
,
1199 Color aColorTopRight
,
1200 Color aColorBottomRight
,
1201 Color aColorBottomLeft
)
1203 BlendFrameCache
* pBlendFrameCache
= ImplGetBlendFrameCache();
1205 if(pBlendFrameCache
->m_aLastSize
== rSize
1206 && pBlendFrameCache
->m_nLastAlpha
== nAlpha
1207 && pBlendFrameCache
->m_aLastColorTopLeft
== aColorTopLeft
1208 && pBlendFrameCache
->m_aLastColorTopRight
== aColorTopRight
1209 && pBlendFrameCache
->m_aLastColorBottomRight
== aColorBottomRight
1210 && pBlendFrameCache
->m_aLastColorBottomLeft
== aColorBottomLeft
)
1212 return pBlendFrameCache
->m_aLastResult
;
1215 pBlendFrameCache
->m_aLastSize
= rSize
;
1216 pBlendFrameCache
->m_nLastAlpha
= nAlpha
;
1217 pBlendFrameCache
->m_aLastColorTopLeft
= aColorTopLeft
;
1218 pBlendFrameCache
->m_aLastColorTopRight
= aColorTopRight
;
1219 pBlendFrameCache
->m_aLastColorBottomRight
= aColorBottomRight
;
1220 pBlendFrameCache
->m_aLastColorBottomLeft
= aColorBottomLeft
;
1221 pBlendFrameCache
->m_aLastResult
.Clear();
1223 const long nW(rSize
.Width());
1224 const long nH(rSize
.Height());
1226 if(nW
> 1 && nH
> 1)
1228 sal_uInt8
aEraseTrans(0xff);
1229 Bitmap
aContent(rSize
, 24);
1230 AlphaMask
aAlpha(rSize
, &aEraseTrans
);
1232 aContent
.Erase(COL_BLACK
);
1234 BitmapWriteAccess
* pContent
= aContent
.AcquireWriteAccess();
1235 BitmapWriteAccess
* pAlpha
= aAlpha
.AcquireWriteAccess();
1237 if(pContent
&& pAlpha
)
1243 pContent
->SetPixel(y
, x
, aColorTopLeft
);
1244 pAlpha
->SetPixelIndex(y
, x
, nAlpha
);
1246 for(x
= 1; x
< nW
- 1; x
++) // y == 0
1248 Color
aMix(aColorTopLeft
);
1250 aMix
.Merge(aColorTopRight
, 255 - sal_uInt8((x
* 255) / nW
));
1251 pContent
->SetPixel(y
, x
, aMix
);
1252 pAlpha
->SetPixelIndex(y
, x
, nAlpha
);
1255 // x == nW - 1, y == 0
1256 pContent
->SetPixel(y
, x
, aColorTopRight
);
1257 pAlpha
->SetPixelIndex(y
, x
, nAlpha
);
1259 for(y
= 1; y
< nH
- 1; y
++) // x == 0 and nW - 1
1261 Color
aMixA(aColorTopLeft
);
1262 Color
aMixB(aColorTopRight
);
1264 aMixA
.Merge(aColorBottomLeft
, 255 - sal_uInt8((y
* 255) / nH
));
1265 pContent
->SetPixel(y
, 0, aMixA
);
1266 pAlpha
->SetPixelIndex(y
, 0, nAlpha
);
1268 aMixB
.Merge(aColorBottomRight
, 255 - sal_uInt8((y
* 255) / nH
));
1269 pContent
->SetPixel(y
, nW
- 1, aMixB
);
1270 pAlpha
->SetPixelIndex(y
, nW
- 1, nAlpha
);
1273 x
= 0; // x == 0, y == nH - 1
1274 pContent
->SetPixel(y
, x
, aColorBottomLeft
);
1275 pAlpha
->SetPixelIndex(y
, x
, nAlpha
);
1277 for(x
= 1; x
< nW
- 1; x
++) // y == nH - 1
1279 Color
aMix(aColorBottomLeft
);
1281 aMix
.Merge(aColorBottomRight
, 255 - sal_uInt8(((x
- 0)* 255) / nW
));
1282 pContent
->SetPixel(y
, x
, aMix
);
1283 pAlpha
->SetPixelIndex(y
, x
, nAlpha
);
1286 // x == nW - 1, y == nH - 1
1287 pContent
->SetPixel(y
, x
, aColorBottomRight
);
1288 pAlpha
->SetPixelIndex(y
, x
, nAlpha
);
1290 aContent
.ReleaseAccess(pContent
);
1291 aAlpha
.ReleaseAccess(pAlpha
);
1293 pBlendFrameCache
->m_aLastResult
= BitmapEx(aContent
, aAlpha
);
1299 aContent
.ReleaseAccess(pContent
);
1304 aAlpha
.ReleaseAccess(pAlpha
);
1309 return pBlendFrameCache
->m_aLastResult
;
1312 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */