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 .
21 #include <rtl/strbuf.hxx>
23 #include <o3tl/any.hxx>
24 #include <tools/debug.hxx>
25 #include <tools/rcid.h>
26 #include <tools/resmgr.hxx>
27 #include <tools/stream.hxx>
28 #include <vcl/ImageTree.hxx>
29 #include <vcl/salbtype.hxx>
30 #include <vcl/outdev.hxx>
31 #include <vcl/alpha.hxx>
32 #include <vcl/bitmapex.hxx>
33 #include <vcl/dibtools.hxx>
34 #include <vcl/pngread.hxx>
35 #include <vcl/svapp.hxx>
36 #include <vcl/bitmapaccess.hxx>
37 #include <vcl/virdev.hxx>
38 #include <vcl/settings.hxx>
41 #include <basegfx/matrix/b2dhommatrixtools.hxx>
45 #include <salinst.hxx>
47 #include <com/sun/star/beans/XFastPropertySet.hpp>
50 using namespace ::com::sun::star
;
53 : eTransparent(TransparentType::NONE
)
58 BitmapEx::BitmapEx( const BitmapEx
& rBitmapEx
) :
59 aBitmap ( rBitmapEx
.aBitmap
),
60 aMask ( rBitmapEx
.aMask
),
61 aBitmapSize ( rBitmapEx
.aBitmapSize
),
62 aTransparentColor ( rBitmapEx
.aTransparentColor
),
63 eTransparent ( rBitmapEx
.eTransparent
),
64 bAlpha ( rBitmapEx
.bAlpha
)
68 BitmapEx::BitmapEx( const BitmapEx
& rBitmapEx
, Point aSrc
, Size aSize
)
69 : eTransparent(TransparentType::NONE
)
72 if( rBitmapEx
.IsEmpty() )
75 aBitmap
= Bitmap( aSize
, rBitmapEx
.aBitmap
.GetBitCount() );
77 if( rBitmapEx
.IsAlpha() )
80 aMask
= AlphaMask( aSize
).ImplGetBitmap();
82 else if( rBitmapEx
.IsTransparent() )
83 aMask
= Bitmap( aSize
, rBitmapEx
.aMask
.GetBitCount() );
85 tools::Rectangle
aDestRect( Point( 0, 0 ), aSize
);
86 tools::Rectangle
aSrcRect( aSrc
, aSize
);
87 CopyPixel( aDestRect
, aSrcRect
, &rBitmapEx
);
90 BitmapEx::BitmapEx( const OUString
& rIconName
)
91 : eTransparent(TransparentType::NONE
)
94 loadFromIconTheme( rIconName
);
97 void BitmapEx::loadFromIconTheme( const OUString
& rIconName
)
99 OUString aIconTheme
= Application::GetSettings().GetStyleSettings().DetermineIconTheme();
101 if (!ImageTree::get().loadImage(rIconName
, aIconTheme
, *this, true))
104 OStringBuffer
aErrorStr(
105 "BitmapEx::BitmapEx(): could not load image <");
106 aErrorStr
.append(OUStringToOString(rIconName
, RTL_TEXTENCODING_ASCII_US
)).append("> via icon theme ");
107 aErrorStr
.append(OUStringToOString(aIconTheme
, RTL_TEXTENCODING_ASCII_US
)).append('.');
108 OSL_FAIL(aErrorStr
.getStr());
113 BitmapEx::BitmapEx( const Bitmap
& rBmp
) :
115 aBitmapSize ( aBitmap
.GetSizePixel() ),
116 eTransparent( TransparentType::NONE
),
121 BitmapEx::BitmapEx( const Bitmap
& rBmp
, const Bitmap
& rMask
) :
124 aBitmapSize ( aBitmap
.GetSizePixel() ),
125 eTransparent ( !rMask
? TransparentType::NONE
: TransparentType::Bitmap
),
128 // Ensure a mask is exactly one bit deep
129 if( !!aMask
&& aMask
.GetBitCount() != 1 )
131 SAL_WARN( "vcl", "BitmapEx: forced mask to monochrome");
132 aMask
.ImplMakeMono( 255 );
135 if(!!aBitmap
&& !!aMask
&& aBitmap
.GetSizePixel() != aMask
.GetSizePixel())
137 OSL_ENSURE(false, "Mask size differs from Bitmap size, corrected Mask (!)");
138 aMask
.Scale(aBitmap
.GetSizePixel());
142 BitmapEx::BitmapEx( const Bitmap
& rBmp
, const AlphaMask
& rAlphaMask
) :
144 aMask ( rAlphaMask
.ImplGetBitmap() ),
145 aBitmapSize ( aBitmap
.GetSizePixel() ),
146 eTransparent ( !rAlphaMask
? TransparentType::NONE
: TransparentType::Bitmap
),
147 bAlpha ( !rAlphaMask
.IsEmpty() )
149 if(!!aBitmap
&& !!aMask
&& aBitmap
.GetSizePixel() != aMask
.GetSizePixel())
151 OSL_ENSURE(false, "Alpha size differs from Bitmap size, corrected Mask (!)");
152 aMask
.Scale(rBmp
.GetSizePixel());
155 // #i75531# the workaround below can go when
156 // X11SalGraphics::drawAlphaBitmap()'s render acceleration
157 // can handle the bitmap depth mismatch directly
158 if( aBitmap
.GetBitCount() < aMask
.GetBitCount() )
159 aBitmap
.Convert( BmpConversion::N24Bit
);
162 BitmapEx::BitmapEx( const Bitmap
& rBmp
, const Color
& rTransparentColor
) :
164 aBitmapSize ( aBitmap
.GetSizePixel() ),
165 aTransparentColor ( rTransparentColor
),
166 eTransparent ( TransparentType::Bitmap
),
169 aMask
= aBitmap
.CreateMask( aTransparentColor
);
171 SAL_WARN_IF( rBmp
.GetSizePixel() != aMask
.GetSizePixel(), "vcl",
172 "BitmapEx::BitmapEx(): size mismatch for bitmap and alpha mask." );
175 BitmapEx
& BitmapEx::operator=( const BitmapEx
& rBitmapEx
)
177 if( &rBitmapEx
!= this )
179 aBitmap
= rBitmapEx
.aBitmap
;
180 aMask
= rBitmapEx
.aMask
;
181 aBitmapSize
= rBitmapEx
.aBitmapSize
;
182 aTransparentColor
= rBitmapEx
.aTransparentColor
;
183 eTransparent
= rBitmapEx
.eTransparent
;
184 bAlpha
= rBitmapEx
.bAlpha
;
190 bool BitmapEx::operator==( const BitmapEx
& rBitmapEx
) const
192 if( eTransparent
!= rBitmapEx
.eTransparent
)
195 if( aBitmap
!= rBitmapEx
.aBitmap
)
198 if( aBitmapSize
!= rBitmapEx
.aBitmapSize
)
201 if( eTransparent
== TransparentType::NONE
)
204 if( eTransparent
== TransparentType::Color
)
205 return aTransparentColor
== rBitmapEx
.aTransparentColor
;
207 return( ( aMask
== rBitmapEx
.aMask
) && ( bAlpha
== rBitmapEx
.bAlpha
) );
210 bool BitmapEx::IsEmpty() const
212 return( aBitmap
.IsEmpty() && aMask
.IsEmpty() );
215 void BitmapEx::SetEmpty()
219 eTransparent
= TransparentType::NONE
;
223 void BitmapEx::Clear()
228 bool BitmapEx::IsTransparent() const
230 return( eTransparent
!= TransparentType::NONE
);
233 bool BitmapEx::IsAlpha() const
235 return( IsTransparent() && bAlpha
);
238 const Bitmap
& BitmapEx::GetBitmapRef() const
243 Bitmap
BitmapEx::GetBitmap( const Color
* pTransReplaceColor
) const
245 Bitmap
aRetBmp( aBitmap
);
247 if( pTransReplaceColor
&& ( eTransparent
!= TransparentType::NONE
) )
251 if( eTransparent
== TransparentType::Color
)
252 aTempMask
= aBitmap
.CreateMask( aTransparentColor
);
257 aRetBmp
.Replace( aTempMask
, *pTransReplaceColor
);
259 aRetBmp
.Replace( GetAlpha(), *pTransReplaceColor
);
265 Bitmap
BitmapEx::GetMask() const
267 Bitmap
aRet( aMask
);
270 aRet
.ImplMakeMono( 255 );
275 AlphaMask
BitmapEx::GetAlpha() const
280 aAlpha
.ImplSetBitmap( aMask
);
289 sal_uLong
BitmapEx::GetSizeBytes() const
291 sal_uLong nSizeBytes
= aBitmap
.GetSizeBytes();
293 if( eTransparent
== TransparentType::Bitmap
)
294 nSizeBytes
+= aMask
.GetSizeBytes();
299 BitmapChecksum
BitmapEx::GetChecksum() const
301 BitmapChecksum nCrc
= aBitmap
.GetChecksum();
303 BitmapChecksumOctetArray aBCOA
;
305 UInt32ToSVBT32( (long) eTransparent
, aBT32
);
306 nCrc
= vcl_get_checksum( nCrc
, aBT32
, 4 );
308 UInt32ToSVBT32( (long) bAlpha
, aBT32
);
309 nCrc
= vcl_get_checksum( nCrc
, aBT32
, 4 );
311 if( ( TransparentType::Bitmap
== eTransparent
) && !aMask
.IsEmpty() )
313 BCToBCOA( aMask
.GetChecksum(), aBCOA
);
314 nCrc
= vcl_get_checksum( nCrc
, aBCOA
, BITMAP_CHECKSUM_SIZE
);
320 void BitmapEx::SetSizePixel( const Size
& rNewSize
, BmpScaleFlag nScaleFlag
)
322 if(GetSizePixel() != rNewSize
)
324 Scale( rNewSize
, nScaleFlag
);
328 bool BitmapEx::Invert()
334 bRet
= aBitmap
.Invert();
336 if( bRet
&& ( eTransparent
== TransparentType::Color
) )
337 aTransparentColor
= BitmapColor( aTransparentColor
).Invert();
343 bool BitmapEx::Mirror( BmpMirrorFlags nMirrorFlags
)
349 bRet
= aBitmap
.Mirror( nMirrorFlags
);
351 if( bRet
&& ( eTransparent
== TransparentType::Bitmap
) && !!aMask
)
352 aMask
.Mirror( nMirrorFlags
);
358 bool BitmapEx::Scale( const double& rScaleX
, const double& rScaleY
, BmpScaleFlag nScaleFlag
)
364 bRet
= aBitmap
.Scale( rScaleX
, rScaleY
, nScaleFlag
);
366 if( bRet
&& ( eTransparent
== TransparentType::Bitmap
) && !!aMask
)
368 aMask
.Scale( rScaleX
, rScaleY
, nScaleFlag
);
371 aBitmapSize
= aBitmap
.GetSizePixel();
373 SAL_WARN_IF( !!aMask
&& aBitmap
.GetSizePixel() != aMask
.GetSizePixel(), "vcl",
374 "BitmapEx::Scale(): size mismatch for bitmap and alpha mask." );
380 bool BitmapEx::Scale( const Size
& rNewSize
, BmpScaleFlag nScaleFlag
)
384 if( aBitmapSize
.Width() && aBitmapSize
.Height() &&
385 ( rNewSize
.Width() != aBitmapSize
.Width() ||
386 rNewSize
.Height() != aBitmapSize
.Height() ) )
388 bRet
= Scale( (double) rNewSize
.Width() / aBitmapSize
.Width(),
389 (double) rNewSize
.Height() / aBitmapSize
.Height(),
398 bool BitmapEx::Rotate( long nAngle10
, const Color
& rFillColor
)
404 const bool bTransRotate
= ( Color( COL_TRANSPARENT
) == rFillColor
);
408 if( eTransparent
== TransparentType::Color
)
409 bRet
= aBitmap
.Rotate( nAngle10
, aTransparentColor
);
412 bRet
= aBitmap
.Rotate( nAngle10
, COL_BLACK
);
414 if( eTransparent
== TransparentType::NONE
)
416 aMask
= Bitmap( aBitmapSize
, 1 );
417 aMask
.Erase( COL_BLACK
);
418 eTransparent
= TransparentType::Bitmap
;
421 if( bRet
&& !!aMask
)
422 aMask
.Rotate( nAngle10
, COL_WHITE
);
427 bRet
= aBitmap
.Rotate( nAngle10
, rFillColor
);
429 if( bRet
&& ( eTransparent
== TransparentType::Bitmap
) && !!aMask
)
430 aMask
.Rotate( nAngle10
, COL_WHITE
);
433 aBitmapSize
= aBitmap
.GetSizePixel();
435 SAL_WARN_IF( !!aMask
&& aBitmap
.GetSizePixel() != aMask
.GetSizePixel(), "vcl",
436 "BitmapEx::Rotate(): size mismatch for bitmap and alpha mask." );
442 bool BitmapEx::Crop( const tools::Rectangle
& rRectPixel
)
448 bRet
= aBitmap
.Crop( rRectPixel
);
450 if( bRet
&& ( eTransparent
== TransparentType::Bitmap
) && !!aMask
)
451 aMask
.Crop( rRectPixel
);
453 aBitmapSize
= aBitmap
.GetSizePixel();
455 SAL_WARN_IF( !!aMask
&& aBitmap
.GetSizePixel() != aMask
.GetSizePixel(), "vcl",
456 "BitmapEx::Crop(): size mismatch for bitmap and alpha mask." );
462 bool BitmapEx::Convert( BmpConversion eConversion
)
464 return !!aBitmap
&& aBitmap
.Convert( eConversion
);
467 bool BitmapEx::ReduceColors( sal_uInt16 nNewColorCount
)
469 return !!aBitmap
&& aBitmap
.ReduceColors( nNewColorCount
, BMP_REDUCE_POPULAR
);
472 bool BitmapEx::Expand( sal_uLong nDX
, sal_uLong nDY
, bool bExpandTransparent
)
478 bRet
= aBitmap
.Expand( nDX
, nDY
);
480 if( bRet
&& ( eTransparent
== TransparentType::Bitmap
) && !!aMask
)
482 Color
aColor( bExpandTransparent
? COL_WHITE
: COL_BLACK
);
483 aMask
.Expand( nDX
, nDY
, &aColor
);
486 aBitmapSize
= aBitmap
.GetSizePixel();
488 SAL_WARN_IF( !!aMask
&& aBitmap
.GetSizePixel() != aMask
.GetSizePixel(), "vcl",
489 "BitmapEx::Expand(): size mismatch for bitmap and alpha mask." );
495 bool BitmapEx::CopyPixel( const tools::Rectangle
& rRectDst
, const tools::Rectangle
& rRectSrc
,
496 const BitmapEx
* pBmpExSrc
)
500 if( !pBmpExSrc
|| pBmpExSrc
->IsEmpty() )
502 if( !aBitmap
.IsEmpty() )
504 bRet
= aBitmap
.CopyPixel( rRectDst
, rRectSrc
);
506 if( bRet
&& ( eTransparent
== TransparentType::Bitmap
) && !!aMask
)
507 aMask
.CopyPixel( rRectDst
, rRectSrc
);
512 if( !aBitmap
.IsEmpty() )
514 bRet
= aBitmap
.CopyPixel( rRectDst
, rRectSrc
, &pBmpExSrc
->aBitmap
);
518 if( pBmpExSrc
->IsAlpha() )
521 // cast to use the optimized AlphaMask::CopyPixel
522 aMask
.CopyPixel_AlphaOptimized( rRectDst
, rRectSrc
, &pBmpExSrc
->aMask
);
523 else if( IsTransparent() )
525 AlphaMask
* pAlpha
= new AlphaMask( aMask
);
527 aMask
= pAlpha
->ImplGetBitmap();
530 aMask
.CopyPixel( rRectDst
, rRectSrc
, &pBmpExSrc
->aMask
);
534 sal_uInt8 cBlack
= 0;
535 AlphaMask
* pAlpha
= new AlphaMask( GetSizePixel(), &cBlack
);
537 aMask
= pAlpha
->ImplGetBitmap();
539 eTransparent
= TransparentType::Bitmap
;
541 aMask
.CopyPixel( rRectDst
, rRectSrc
, &pBmpExSrc
->aMask
);
544 else if( pBmpExSrc
->IsTransparent() )
548 AlphaMask
aAlpha( pBmpExSrc
->aMask
);
549 aMask
.CopyPixel( rRectDst
, rRectSrc
, &aAlpha
.ImplGetBitmap() );
551 else if( IsTransparent() )
552 aMask
.CopyPixel( rRectDst
, rRectSrc
, &pBmpExSrc
->aMask
);
555 aMask
= Bitmap( GetSizePixel(), 1 );
556 aMask
.Erase( Color( COL_BLACK
) );
557 eTransparent
= TransparentType::Bitmap
;
558 aMask
.CopyPixel( rRectDst
, rRectSrc
, &pBmpExSrc
->aMask
);
563 sal_uInt8 cBlack
= 0;
564 const AlphaMask
aAlphaSrc( pBmpExSrc
->GetSizePixel(), &cBlack
);
566 aMask
.CopyPixel( rRectDst
, rRectSrc
, &aAlphaSrc
.ImplGetBitmap() );
568 else if( IsTransparent() )
570 Bitmap
aMaskSrc( pBmpExSrc
->GetSizePixel(), 1 );
572 aMaskSrc
.Erase( Color( COL_BLACK
) );
573 aMask
.CopyPixel( rRectDst
, rRectSrc
, &aMaskSrc
);
582 bool BitmapEx::Erase( const Color
& rFillColor
)
588 bRet
= aBitmap
.Erase( rFillColor
);
590 if( bRet
&& ( eTransparent
== TransparentType::Bitmap
) && !!aMask
)
592 // Respect transparency on fill color
593 if( rFillColor
.GetTransparency() )
595 const Color
aFill( rFillColor
.GetTransparency(), rFillColor
.GetTransparency(), rFillColor
.GetTransparency() );
596 aMask
.Erase( aFill
);
600 const Color
aBlack( COL_BLACK
);
601 aMask
.Erase( aBlack
);
609 bool BitmapEx::Dither()
611 return !!aBitmap
&& aBitmap
.Dither();
614 bool BitmapEx::Replace( const Color
& rSearchColor
, const Color
& rReplaceColor
)
616 return !!aBitmap
&& aBitmap
.Replace( rSearchColor
, rReplaceColor
);
619 bool BitmapEx::Replace( const Color
* pSearchColors
, const Color
* pReplaceColors
, sal_uLong nColorCount
, const sal_uLong
* pTols
)
621 return !!aBitmap
&& aBitmap
.Replace( pSearchColors
, pReplaceColors
, nColorCount
, const_cast<sal_uLong
*>(pTols
) );
624 bool BitmapEx::Adjust( short nLuminancePercent
, short nContrastPercent
,
625 short nChannelRPercent
, short nChannelGPercent
, short nChannelBPercent
,
626 double fGamma
, bool bInvert
, bool msoBrightness
)
628 return !!aBitmap
&& aBitmap
.Adjust( nLuminancePercent
, nContrastPercent
,
629 nChannelRPercent
, nChannelGPercent
, nChannelBPercent
,
630 fGamma
, bInvert
, msoBrightness
);
633 bool BitmapEx::Filter( BmpFilter eFilter
, const BmpFilterParam
* pFilterParam
)
635 return !!aBitmap
&& aBitmap
.Filter( eFilter
, pFilterParam
);
638 void BitmapEx::Draw( OutputDevice
* pOutDev
, const Point
& rDestPt
) const
640 pOutDev
->DrawBitmapEx( rDestPt
, *this );
643 void BitmapEx::Draw( OutputDevice
* pOutDev
,
644 const Point
& rDestPt
, const Size
& rDestSize
) const
646 pOutDev
->DrawBitmapEx( rDestPt
, rDestSize
, *this );
649 BitmapEx
BitmapEx:: AutoScaleBitmap(BitmapEx
& aBitmap
, const long aStandardSize
)
651 Point
aEmptyPoint(0,0);
654 BitmapEx aRet
= aBitmap
;
655 double imgOldWidth
= aRet
.GetSizePixel().Width();
656 double imgOldHeight
=aRet
.GetSizePixel().Height();
659 if (imgOldWidth
>= aStandardSize
|| imgOldHeight
>= aStandardSize
)
661 sal_Int32 imgNewWidth
= 0;
662 sal_Int32 imgNewHeight
= 0;
663 if (imgOldWidth
>= imgOldHeight
)
665 imgNewWidth
= aStandardSize
;
666 imgNewHeight
= sal_Int32(imgOldHeight
/ (imgOldWidth
/ aStandardSize
) + 0.5);
668 imgposY
= (aStandardSize
- (imgOldHeight
/ (imgOldWidth
/ aStandardSize
) + 0.5)) / 2 + 0.5;
672 imgNewHeight
= aStandardSize
;
673 imgNewWidth
= sal_Int32(imgOldWidth
/ (imgOldHeight
/ aStandardSize
) + 0.5);
675 imgposX
= (aStandardSize
- (imgOldWidth
/ (imgOldHeight
/ aStandardSize
) + 0.5)) / 2 + 0.5;
678 aScaledSize
= Size( imgNewWidth
, imgNewHeight
);
679 aRet
.Scale( aScaledSize
, BmpScaleFlag::BestQuality
);
683 imgposX
= (aStandardSize
- imgOldWidth
) / 2 + 0.5;
684 imgposY
= (aStandardSize
- imgOldHeight
) / 2 + 0.5;
687 Size
aStdSize( aStandardSize
, aStandardSize
);
688 tools::Rectangle
aRect(aEmptyPoint
, aStdSize
);
690 ScopedVclPtrInstance
< VirtualDevice
> aVirDevice(*Application::GetDefaultDevice(),
691 DeviceFormat::DEFAULT
, DeviceFormat::BITMASK
);
692 aVirDevice
->SetOutputSizePixel( aStdSize
);
693 aVirDevice
->SetFillColor( COL_TRANSPARENT
);
694 aVirDevice
->SetLineColor( COL_TRANSPARENT
);
696 // Draw a rect into virDevice
697 aVirDevice
->DrawRect( aRect
);
698 Point
aPointPixel( (long)imgposX
, (long)imgposY
);
699 aVirDevice
->DrawBitmapEx( aPointPixel
, aRet
);
700 aRet
= aVirDevice
->GetBitmapEx( aEmptyPoint
, aStdSize
);
705 sal_uInt8
BitmapEx::GetTransparency(sal_Int32 nX
, sal_Int32 nY
) const
707 sal_uInt8
nTransparency(0xff);
709 if(!aBitmap
.IsEmpty())
711 if(nX
>= 0 && nX
< aBitmapSize
.Width() && nY
>= 0 && nY
< aBitmapSize
.Height())
715 case TransparentType::NONE
:
717 // Not transparent, ergo all covered
718 nTransparency
= 0x00;
721 case TransparentType::Color
:
723 Bitmap
aTestBitmap(aBitmap
);
724 Bitmap::ScopedReadAccess
pRead(aTestBitmap
);
728 const Color aColor
= pRead
->GetColor(nY
, nX
);
730 // If color is not equal to TransparentColor, we are not transparent
731 if(aColor
!= aTransparentColor
)
733 nTransparency
= 0x00;
739 case TransparentType::Bitmap
:
743 Bitmap
aTestBitmap(aMask
);
744 Bitmap::ScopedReadAccess
pRead(aTestBitmap
);
748 const BitmapColor
aBitmapColor(pRead
->GetPixel(nY
, nX
));
752 nTransparency
= aBitmapColor
.GetIndex();
756 if(0x00 == aBitmapColor
.GetIndex())
758 nTransparency
= 0x00;
769 return nTransparency
;
772 // Shift alpha transparent pixels between cppcanvas/ implementations
773 // and vcl in a generally grotesque and under-performing fashion
774 bool BitmapEx::Create( const css::uno::Reference
< css::rendering::XBitmapCanvas
> &xBitmapCanvas
,
777 uno::Reference
< beans::XFastPropertySet
> xFastPropertySet( xBitmapCanvas
, uno::UNO_QUERY
);
778 if( xFastPropertySet
.get() )
780 // 0 means get BitmapEx
781 uno::Any aAny
= xFastPropertySet
->getFastPropertyValue( 0 );
782 std::unique_ptr
<BitmapEx
> xBitmapEx(reinterpret_cast<BitmapEx
*>(*o3tl::doAccess
<sal_Int64
>(aAny
)));
790 SalBitmap
* pSalBmp
= nullptr;
791 SalBitmap
* pSalMask
= nullptr;
793 pSalBmp
= ImplGetSVData()->mpDefInst
->CreateSalBitmap();
795 Size
aLocalSize(rSize
);
796 if( pSalBmp
->Create( xBitmapCanvas
, aLocalSize
) )
798 pSalMask
= ImplGetSVData()->mpDefInst
->CreateSalBitmap();
799 if ( pSalMask
->Create( xBitmapCanvas
, aLocalSize
, true ) )
801 *this = BitmapEx(Bitmap(pSalBmp
), Bitmap(pSalMask
) );
807 *this = BitmapEx(Bitmap(pSalBmp
));
820 Bitmap
impTransformBitmap(
821 const Bitmap
& rSource
,
822 const Size
& rDestinationSize
,
823 const basegfx::B2DHomMatrix
& rTransform
,
826 Bitmap
aDestination(rDestinationSize
, 24);
827 Bitmap::ScopedWriteAccess
xWrite(aDestination
);
831 Bitmap::ScopedReadAccess
xRead(const_cast< Bitmap
& >(rSource
));
835 const Size
aDestinationSizePixel(aDestination
.GetSizePixel());
836 const BitmapColor
aOutside(BitmapColor(0xff, 0xff, 0xff));
838 for(long y(0); y
< aDestinationSizePixel
.getHeight(); y
++)
840 for(long x(0); x
< aDestinationSizePixel
.getWidth(); x
++)
842 const basegfx::B2DPoint
aSourceCoor(rTransform
* basegfx::B2DPoint(x
, y
));
849 xRead
->GetInterpolatedColorWithFallback(
856 // this version does the correct <= 0.0 checks, so no need
857 // to do the static_cast< sal_Int32 > self and make an error
861 xRead
->GetColorWithFallback(
871 rSource
.AdaptBitCount(aDestination
);
875 } // end of anonymous namespace
877 BitmapEx
BitmapEx::TransformBitmapEx(
880 const basegfx::B2DHomMatrix
& rTransformation
,
883 if(fWidth
<= 1 || fHeight
<= 1)
886 // force destination to 24 bit, we want to smooth output
887 const Size
aDestinationSize(basegfx::fround(fWidth
), basegfx::fround(fHeight
));
888 const Bitmap
aDestination(impTransformBitmap(GetBitmap(), aDestinationSize
, rTransformation
, bSmooth
));
895 const Bitmap
aAlpha(impTransformBitmap(GetAlpha().GetBitmap(), aDestinationSize
, rTransformation
, bSmooth
));
896 return BitmapEx(aDestination
, AlphaMask(aAlpha
));
900 const Bitmap
aLclMask(impTransformBitmap(GetMask(), aDestinationSize
, rTransformation
, false));
901 return BitmapEx(aDestination
, aLclMask
);
905 return BitmapEx(aDestination
);
908 BitmapEx
BitmapEx::getTransformed(
909 const basegfx::B2DHomMatrix
& rTransformation
,
910 const basegfx::B2DRange
& rVisibleRange
,
919 const sal_uInt32
nSourceWidth(GetSizePixel().Width());
920 const sal_uInt32
nSourceHeight(GetSizePixel().Height());
922 if(!nSourceWidth
|| !nSourceHeight
)
926 basegfx::B2DRange
aOutlineRange(0.0, 0.0, 1.0, 1.0);
928 aOutlineRange
.transform(rTransformation
);
930 // create visible range from it by moving from relative to absolute
931 basegfx::B2DRange
aVisibleRange(rVisibleRange
);
933 aVisibleRange
.transform(
934 basegfx::tools::createScaleTranslateB2DHomMatrix(
935 aOutlineRange
.getRange(),
936 aOutlineRange
.getMinimum()));
938 // get target size (which is visible range's size)
939 double fWidth(aVisibleRange
.getWidth());
940 double fHeight(aVisibleRange
.getHeight());
942 if(fWidth
< 1.0 || fHeight
< 1.0)
947 // test if discrete size (pixel) maybe too big and limit it
948 const double fArea(fWidth
* fHeight
);
949 const bool bNeedToReduce(basegfx::fTools::more(fArea
, fMaximumArea
));
950 double fReduceFactor(1.0);
954 fReduceFactor
= sqrt(fMaximumArea
/ fArea
);
955 fWidth
*= fReduceFactor
;
956 fHeight
*= fReduceFactor
;
959 // Build complete transform from source pixels to target pixels.
960 // Start by scaling from source pixel size to unit coordinates
961 basegfx::B2DHomMatrix
aTransform(
962 basegfx::tools::createScaleB2DHomMatrix(
964 1.0 / nSourceHeight
));
966 // multiply with given transform which leads from unit coordinates inside
968 aTransform
= rTransformation
* aTransform
;
970 // subtract top-left of absolute VisibleRange
971 aTransform
.translate(
972 -aVisibleRange
.getMinX(),
973 -aVisibleRange
.getMinY());
975 // scale to target pixels (if needed)
978 aTransform
.scale(fReduceFactor
, fReduceFactor
);
981 // invert to get transformation from target pixel coordinates to source pixels
984 // create bitmap using source, destination and linear back-transformation
985 aRetval
= TransformBitmapEx(fWidth
, fHeight
, aTransform
, bSmooth
);
990 BitmapEx
BitmapEx::ModifyBitmapEx(const basegfx::BColorModifierStack
& rBColorModifierStack
) const
992 Bitmap
aChangedBitmap(GetBitmap());
995 for(sal_uInt32
a(rBColorModifierStack
.count()); a
&& !bDone
; )
997 const basegfx::BColorModifierSharedPtr
& rModifier
= rBColorModifierStack
.getBColorModifier(--a
);
998 const basegfx::BColorModifier_replace
* pReplace
= dynamic_cast< const basegfx::BColorModifier_replace
* >(rModifier
.get());
1005 // clear bitmap with dest color
1006 if(aChangedBitmap
.GetBitCount() <= 8)
1008 // do NOT use erase; for e.g. 8bit Bitmaps, the nearest color to the given
1009 // erase color is determined and used -> this may be different from what is
1010 // wanted here. Better create a new bitmap with the needed color explicitly
1011 Bitmap::ScopedReadAccess
xReadAccess(aChangedBitmap
);
1012 OSL_ENSURE(xReadAccess
, "Got no Bitmap ReadAccess ?!?");
1016 BitmapPalette
aNewPalette(xReadAccess
->GetPalette());
1017 aNewPalette
[0] = BitmapColor(Color(pReplace
->getBColor()));
1018 aChangedBitmap
= Bitmap(
1019 aChangedBitmap
.GetSizePixel(),
1020 aChangedBitmap
.GetBitCount(),
1026 aChangedBitmap
.Erase(Color(pReplace
->getBColor()));
1031 // erase bitmap, caller will know to paint direct
1032 aChangedBitmap
.SetEmpty();
1039 Bitmap::ScopedWriteAccess
xContent(aChangedBitmap
);
1043 const double fConvertColor(1.0 / 255.0);
1045 if(xContent
->HasPalette())
1047 const sal_uInt16
nCount(xContent
->GetPaletteEntryCount());
1049 for(sal_uInt16
b(0); b
< nCount
; b
++)
1051 const BitmapColor
& rCol
= xContent
->GetPaletteColor(b
);
1052 const basegfx::BColor
aBSource(
1053 rCol
.GetRed() * fConvertColor
,
1054 rCol
.GetGreen() * fConvertColor
,
1055 rCol
.GetBlue() * fConvertColor
);
1056 const basegfx::BColor
aBDest(rModifier
->getModifiedColor(aBSource
));
1057 xContent
->SetPaletteColor(b
, BitmapColor(Color(aBDest
)));
1060 else if(ScanlineFormat::N24BitTcBgr
== xContent
->GetScanlineFormat())
1062 for(sal_uInt32
y(0); y
< (sal_uInt32
)xContent
->Height(); y
++)
1064 Scanline pScan
= xContent
->GetScanline(y
);
1066 for(sal_uInt32
x(0); x
< (sal_uInt32
)xContent
->Width(); x
++)
1068 const basegfx::BColor
aBSource(
1069 *(pScan
+ 2)* fConvertColor
,
1070 *(pScan
+ 1) * fConvertColor
,
1071 *pScan
* fConvertColor
);
1072 const basegfx::BColor
aBDest(rModifier
->getModifiedColor(aBSource
));
1073 *pScan
++ = static_cast< sal_uInt8
>(aBDest
.getBlue() * 255.0);
1074 *pScan
++ = static_cast< sal_uInt8
>(aBDest
.getGreen() * 255.0);
1075 *pScan
++ = static_cast< sal_uInt8
>(aBDest
.getRed() * 255.0);
1079 else if(ScanlineFormat::N24BitTcRgb
== xContent
->GetScanlineFormat())
1081 for(sal_uInt32
y(0); y
< (sal_uInt32
)xContent
->Height(); y
++)
1083 Scanline pScan
= xContent
->GetScanline(y
);
1085 for(sal_uInt32
x(0); x
< (sal_uInt32
)xContent
->Width(); x
++)
1087 const basegfx::BColor
aBSource(
1088 *pScan
* fConvertColor
,
1089 *(pScan
+ 1) * fConvertColor
,
1090 *(pScan
+ 2) * fConvertColor
);
1091 const basegfx::BColor
aBDest(rModifier
->getModifiedColor(aBSource
));
1092 *pScan
++ = static_cast< sal_uInt8
>(aBDest
.getRed() * 255.0);
1093 *pScan
++ = static_cast< sal_uInt8
>(aBDest
.getGreen() * 255.0);
1094 *pScan
++ = static_cast< sal_uInt8
>(aBDest
.getBlue() * 255.0);
1100 for(sal_uInt32
y(0); y
< (sal_uInt32
)xContent
->Height(); y
++)
1102 for(sal_uInt32
x(0); x
< (sal_uInt32
)xContent
->Width(); x
++)
1104 const BitmapColor
aBMCol(xContent
->GetColor(y
, x
));
1105 const basegfx::BColor
aBSource(
1106 (double)aBMCol
.GetRed() * fConvertColor
,
1107 (double)aBMCol
.GetGreen() * fConvertColor
,
1108 (double)aBMCol
.GetBlue() * fConvertColor
);
1109 const basegfx::BColor
aBDest(rModifier
->getModifiedColor(aBSource
));
1111 xContent
->SetPixel(y
, x
, BitmapColor(Color(aBDest
)));
1119 if(aChangedBitmap
.IsEmpty())
1129 return BitmapEx(aChangedBitmap
, GetAlpha());
1133 return BitmapEx(aChangedBitmap
, GetMask());
1138 return BitmapEx(aChangedBitmap
);
1143 BitmapEx
createBlendFrame(
1146 Color aColorTopLeft
,
1147 Color aColorBottomRight
)
1149 const sal_uInt32
nW(rSize
.Width());
1150 const sal_uInt32
nH(rSize
.Height());
1154 Color
aColTopRight(aColorTopLeft
);
1155 Color
aColBottomLeft(aColorTopLeft
);
1156 const sal_uInt32
nDE(nW
+ nH
);
1158 aColTopRight
.Merge(aColorBottomRight
, 255 - sal_uInt8((nW
* 255) / nDE
));
1159 aColBottomLeft
.Merge(aColorBottomRight
, 255 - sal_uInt8((nH
* 255) / nDE
));
1161 return createBlendFrame(rSize
, nAlpha
, aColorTopLeft
, aColTopRight
, aColorBottomRight
, aColBottomLeft
);
1167 BitmapEx
createBlendFrame(
1170 Color aColorTopLeft
,
1171 Color aColorTopRight
,
1172 Color aColorBottomRight
,
1173 Color aColorBottomLeft
)
1175 BlendFrameCache
* pBlendFrameCache
= ImplGetBlendFrameCache();
1177 if(pBlendFrameCache
->m_aLastSize
== rSize
1178 && pBlendFrameCache
->m_nLastAlpha
== nAlpha
1179 && pBlendFrameCache
->m_aLastColorTopLeft
== aColorTopLeft
1180 && pBlendFrameCache
->m_aLastColorTopRight
== aColorTopRight
1181 && pBlendFrameCache
->m_aLastColorBottomRight
== aColorBottomRight
1182 && pBlendFrameCache
->m_aLastColorBottomLeft
== aColorBottomLeft
)
1184 return pBlendFrameCache
->m_aLastResult
;
1187 pBlendFrameCache
->m_aLastSize
= rSize
;
1188 pBlendFrameCache
->m_nLastAlpha
= nAlpha
;
1189 pBlendFrameCache
->m_aLastColorTopLeft
= aColorTopLeft
;
1190 pBlendFrameCache
->m_aLastColorTopRight
= aColorTopRight
;
1191 pBlendFrameCache
->m_aLastColorBottomRight
= aColorBottomRight
;
1192 pBlendFrameCache
->m_aLastColorBottomLeft
= aColorBottomLeft
;
1193 pBlendFrameCache
->m_aLastResult
.Clear();
1195 const long nW(rSize
.Width());
1196 const long nH(rSize
.Height());
1198 if(nW
> 1 && nH
> 1)
1200 sal_uInt8
aEraseTrans(0xff);
1201 Bitmap
aContent(rSize
, 24);
1202 AlphaMask
aAlpha(rSize
, &aEraseTrans
);
1204 aContent
.Erase(COL_BLACK
);
1206 Bitmap::ScopedWriteAccess
pContent(aContent
);
1207 AlphaMask::ScopedWriteAccess
pAlpha(aAlpha
);
1209 if(pContent
&& pAlpha
)
1214 // x == 0, y == 0, top-left corner
1215 pContent
->SetPixel(0, 0, aColorTopLeft
);
1216 pAlpha
->SetPixelIndex(0, 0, nAlpha
);
1218 // y == 0, top line left to right
1219 for(x
= 1; x
< nW
- 1; x
++)
1221 Color
aMix(aColorTopLeft
);
1223 aMix
.Merge(aColorTopRight
, 255 - sal_uInt8((x
* 255) / nW
));
1224 pContent
->SetPixel(0, x
, aMix
);
1225 pAlpha
->SetPixelIndex(0, x
, nAlpha
);
1228 // x == nW - 1, y == 0, top-right corner
1229 // #i123690# Caution! When nW is 1, x == nW is possible (!)
1232 pContent
->SetPixel(0, x
, aColorTopRight
);
1233 pAlpha
->SetPixelIndex(0, x
, nAlpha
);
1236 // x == 0 and nW - 1, left and right line top-down
1237 for(y
= 1; y
< nH
- 1; y
++)
1239 Color
aMixA(aColorTopLeft
);
1241 aMixA
.Merge(aColorBottomLeft
, 255 - sal_uInt8((y
* 255) / nH
));
1242 pContent
->SetPixel(y
, 0, aMixA
);
1243 pAlpha
->SetPixelIndex(y
, 0, nAlpha
);
1245 // #i123690# Caution! When nW is 1, x == nW is possible (!)
1248 Color
aMixB(aColorTopRight
);
1250 aMixB
.Merge(aColorBottomRight
, 255 - sal_uInt8((y
* 255) / nH
));
1251 pContent
->SetPixel(y
, x
, aMixB
);
1252 pAlpha
->SetPixelIndex(y
, x
, nAlpha
);
1256 // #i123690# Caution! When nH is 1, y == nH is possible (!)
1259 // x == 0, y == nH - 1, bottom-left corner
1260 pContent
->SetPixel(y
, 0, aColorBottomLeft
);
1261 pAlpha
->SetPixelIndex(y
, 0, nAlpha
);
1263 // y == nH - 1, bottom line left to right
1264 for(x
= 1; x
< nW
- 1; x
++)
1266 Color
aMix(aColorBottomLeft
);
1268 aMix
.Merge(aColorBottomRight
, 255 - sal_uInt8(((x
- 0)* 255) / nW
));
1269 pContent
->SetPixel(y
, x
, aMix
);
1270 pAlpha
->SetPixelIndex(y
, x
, nAlpha
);
1273 // x == nW - 1, y == nH - 1, bottom-right corner
1274 // #i123690# Caution! When nW is 1, x == nW is possible (!)
1277 pContent
->SetPixel(y
, x
, aColorBottomRight
);
1278 pAlpha
->SetPixelIndex(y
, x
, nAlpha
);
1285 pBlendFrameCache
->m_aLastResult
= BitmapEx(aContent
, aAlpha
);
1289 return pBlendFrameCache
->m_aLastResult
;
1292 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */