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/implimagetree.hxx>
28 #include <vcl/salbtype.hxx>
29 #include <vcl/outdev.hxx>
30 #include <vcl/alpha.hxx>
31 #include <vcl/bitmapex.hxx>
32 #include <vcl/dibtools.hxx>
33 #include <vcl/pngread.hxx>
34 #include <vcl/svapp.hxx>
35 #include <vcl/bmpacc.hxx>
36 #include <vcl/virdev.hxx>
37 #include <vcl/settings.hxx>
40 #include <basegfx/matrix/b2dhommatrixtools.hxx>
44 #include <salinst.hxx>
46 #include <com/sun/star/beans/XFastPropertySet.hpp>
49 using namespace ::com::sun::star
;
51 BitmapEx::BitmapEx() :
52 eTransparent( TRANSPARENT_NONE
),
57 BitmapEx::BitmapEx( const BitmapEx
& rBitmapEx
) :
58 aBitmap ( rBitmapEx
.aBitmap
),
59 aMask ( rBitmapEx
.aMask
),
60 aBitmapSize ( rBitmapEx
.aBitmapSize
),
61 aTransparentColor ( rBitmapEx
.aTransparentColor
),
62 eTransparent ( rBitmapEx
.eTransparent
),
63 bAlpha ( rBitmapEx
.bAlpha
)
67 BitmapEx::BitmapEx( const BitmapEx
& rBitmapEx
, Point aSrc
, Size aSize
) :
68 eTransparent( TRANSPARENT_NONE
),
71 if( rBitmapEx
.IsEmpty() )
74 aBitmap
= Bitmap( aSize
, rBitmapEx
.aBitmap
.GetBitCount() );
76 if( rBitmapEx
.IsAlpha() )
79 aMask
= AlphaMask( aSize
).ImplGetBitmap();
81 else if( rBitmapEx
.IsTransparent() )
82 aMask
= Bitmap( aSize
, rBitmapEx
.aMask
.GetBitCount() );
84 Rectangle
aDestRect( Point( 0, 0 ), aSize
);
85 Rectangle
aSrcRect( aSrc
, aSize
);
86 CopyPixel( aDestRect
, aSrcRect
, &rBitmapEx
);
89 BitmapEx::BitmapEx( const OUString
& rIconName
)
91 loadFromIconTheme( rIconName
);
94 BitmapEx::BitmapEx( const ResId
& rResId
) :
95 eTransparent( TRANSPARENT_NONE
),
98 ResMgr
* pResMgr
= NULL
;
100 ResMgr::GetResourceSkipHeader( rResId
.SetRT( RSC_BITMAP
), &pResMgr
);
104 const OUString
aFileName( pResMgr
->ReadString() );
105 loadFromIconTheme( aFileName
);
108 void BitmapEx::loadFromIconTheme( const OUString
& rIconName
)
110 OUString aIconTheme
= Application::GetSettings().GetStyleSettings().DetermineIconTheme();
112 if( !ImplImageTree::get().loadImage( rIconName
, aIconTheme
, *this, true ) )
115 OStringBuffer
aErrorStr(
116 "BitmapEx::BitmapEx(): could not load image <");
117 aErrorStr
.append(OUStringToOString(rIconName
, RTL_TEXTENCODING_ASCII_US
)).append("> via icon theme ");
118 aErrorStr
.append(OUStringToOString(aIconTheme
, RTL_TEXTENCODING_ASCII_US
)).append('.');
119 OSL_FAIL(aErrorStr
.getStr());
124 BitmapEx::BitmapEx( const Bitmap
& rBmp
) :
126 aBitmapSize ( aBitmap
.GetSizePixel() ),
127 eTransparent( TRANSPARENT_NONE
),
132 BitmapEx::BitmapEx( const Bitmap
& rBmp
, const Bitmap
& rMask
) :
135 aBitmapSize ( aBitmap
.GetSizePixel() ),
136 eTransparent ( !rMask
? TRANSPARENT_NONE
: TRANSPARENT_BITMAP
),
139 if(!!aBitmap
&& !!aMask
&& aBitmap
.GetSizePixel() != aMask
.GetSizePixel())
141 OSL_ENSURE(false, "Mask size differs from Bitmap size, corrected Mask (!)");
142 aMask
.Scale(aBitmap
.GetSizePixel());
145 // Ensure a mask is exactly one bit deep
146 if( !!aMask
&& aMask
.GetBitCount() != 1 )
148 OSL_TRACE("BitmapEx: forced mask to monochrome");
149 aMask
.ImplMakeMono( 255 );
153 BitmapEx::BitmapEx( const Bitmap
& rBmp
, const AlphaMask
& rAlphaMask
) :
155 aMask ( rAlphaMask
.ImplGetBitmap() ),
156 aBitmapSize ( aBitmap
.GetSizePixel() ),
157 eTransparent ( !rAlphaMask
? TRANSPARENT_NONE
: TRANSPARENT_BITMAP
),
158 bAlpha ( !rAlphaMask
.IsEmpty() )
160 if(!!aBitmap
&& !!aMask
&& aBitmap
.GetSizePixel() != aMask
.GetSizePixel())
162 OSL_ENSURE(false, "Alpha size differs from Bitmap size, corrected Mask (!)");
163 aMask
.Scale(rBmp
.GetSizePixel());
166 // #i75531# the workaround below can go when
167 // X11SalGraphics::drawAlphaBitmap()'s render acceleration
168 // can handle the bitmap depth mismatch directly
169 if( aBitmap
.GetBitCount() < aMask
.GetBitCount() )
170 aBitmap
.Convert( BMP_CONVERSION_24BIT
);
173 BitmapEx::BitmapEx( const Bitmap
& rBmp
, const Color
& rTransparentColor
) :
175 aBitmapSize ( aBitmap
.GetSizePixel() ),
176 aTransparentColor ( rTransparentColor
),
177 eTransparent ( TRANSPARENT_BITMAP
),
180 aMask
= aBitmap
.CreateMask( aTransparentColor
);
182 DBG_ASSERT( rBmp
.GetSizePixel() == aMask
.GetSizePixel(),
183 "BitmapEx::BitmapEx(): size mismatch for bitmap and alpha mask." );
186 BitmapEx::~BitmapEx()
190 BitmapEx
& BitmapEx::operator=( const BitmapEx
& rBitmapEx
)
192 if( &rBitmapEx
!= this )
194 aBitmap
= rBitmapEx
.aBitmap
;
195 aMask
= rBitmapEx
.aMask
;
196 aBitmapSize
= rBitmapEx
.aBitmapSize
;
197 aTransparentColor
= rBitmapEx
.aTransparentColor
;
198 eTransparent
= rBitmapEx
.eTransparent
;
199 bAlpha
= rBitmapEx
.bAlpha
;
205 bool BitmapEx::operator==( const BitmapEx
& rBitmapEx
) const
207 if( eTransparent
!= rBitmapEx
.eTransparent
)
210 if( aBitmap
!= rBitmapEx
.aBitmap
)
213 if( aBitmapSize
!= rBitmapEx
.aBitmapSize
)
216 if( eTransparent
== TRANSPARENT_NONE
)
219 if( eTransparent
== TRANSPARENT_COLOR
)
220 return aTransparentColor
== rBitmapEx
.aTransparentColor
;
222 return( ( aMask
== rBitmapEx
.aMask
) && ( bAlpha
== rBitmapEx
.bAlpha
) );
225 bool BitmapEx::IsEqual( const BitmapEx
& rBmpEx
) const
227 return( rBmpEx
.eTransparent
== eTransparent
&&
228 rBmpEx
.bAlpha
== bAlpha
&&
229 rBmpEx
.aBitmap
.IsEqual( aBitmap
) &&
230 rBmpEx
.aMask
.IsEqual( aMask
) );
233 bool BitmapEx::IsEmpty() const
235 return( aBitmap
.IsEmpty() && aMask
.IsEmpty() );
238 void BitmapEx::SetEmpty()
242 eTransparent
= TRANSPARENT_NONE
;
246 void BitmapEx::Clear()
251 bool BitmapEx::IsTransparent() const
253 return( eTransparent
!= TRANSPARENT_NONE
);
256 bool BitmapEx::IsAlpha() const
258 return( IsTransparent() && bAlpha
);
261 Bitmap
BitmapEx::GetBitmap( const Color
* pTransReplaceColor
) const
263 Bitmap
aRetBmp( aBitmap
);
265 if( pTransReplaceColor
&& ( eTransparent
!= TRANSPARENT_NONE
) )
269 if( eTransparent
== TRANSPARENT_COLOR
)
270 aTempMask
= aBitmap
.CreateMask( aTransparentColor
);
275 aRetBmp
.Replace( aTempMask
, *pTransReplaceColor
);
277 aRetBmp
.Replace( GetAlpha(), *pTransReplaceColor
);
283 Bitmap
BitmapEx::GetMask() const
285 Bitmap
aRet( aMask
);
288 aRet
.ImplMakeMono( 255 );
293 AlphaMask
BitmapEx::GetAlpha() const
298 aAlpha
.ImplSetBitmap( aMask
);
307 sal_uLong
BitmapEx::GetSizeBytes() const
309 sal_uLong nSizeBytes
= aBitmap
.GetSizeBytes();
311 if( eTransparent
== TRANSPARENT_BITMAP
)
312 nSizeBytes
+= aMask
.GetSizeBytes();
317 BitmapChecksum
BitmapEx::GetChecksum() const
319 BitmapChecksum nCrc
= aBitmap
.GetChecksum();
321 BitmapChecksumOctetArray aBCOA
;
323 UInt32ToSVBT32( (long) eTransparent
, aBT32
);
324 nCrc
= vcl_get_checksum( nCrc
, aBT32
, 4 );
326 UInt32ToSVBT32( (long) bAlpha
, aBT32
);
327 nCrc
= vcl_get_checksum( nCrc
, aBT32
, 4 );
329 if( ( TRANSPARENT_BITMAP
== eTransparent
) && !aMask
.IsEmpty() )
331 BCToBCOA( aMask
.GetChecksum(), aBCOA
);
332 nCrc
= vcl_get_checksum( nCrc
, aBCOA
, BITMAP_CHECKSUM_SIZE
);
338 void BitmapEx::SetSizePixel( const Size
& rNewSize
, BmpScaleFlag nScaleFlag
)
340 if(GetSizePixel() != rNewSize
)
342 Scale( rNewSize
, nScaleFlag
);
346 bool BitmapEx::Invert()
352 bRet
= aBitmap
.Invert();
354 if( bRet
&& ( eTransparent
== TRANSPARENT_COLOR
) )
355 aTransparentColor
= BitmapColor( aTransparentColor
).Invert();
361 bool BitmapEx::Mirror( BmpMirrorFlags nMirrorFlags
)
367 bRet
= aBitmap
.Mirror( nMirrorFlags
);
369 if( bRet
&& ( eTransparent
== TRANSPARENT_BITMAP
) && !!aMask
)
370 aMask
.Mirror( nMirrorFlags
);
376 bool BitmapEx::Scale( const double& rScaleX
, const double& rScaleY
, BmpScaleFlag nScaleFlag
)
382 bRet
= aBitmap
.Scale( rScaleX
, rScaleY
, nScaleFlag
);
384 if( bRet
&& ( eTransparent
== TRANSPARENT_BITMAP
) && !!aMask
)
386 aMask
.Scale( rScaleX
, rScaleY
, nScaleFlag
);
389 aBitmapSize
= aBitmap
.GetSizePixel();
391 DBG_ASSERT( !aMask
|| aBitmap
.GetSizePixel() == aMask
.GetSizePixel(),
392 "BitmapEx::Scale(): size mismatch for bitmap and alpha mask." );
398 bool BitmapEx::Scale( const Size
& rNewSize
, BmpScaleFlag nScaleFlag
)
402 if( aBitmapSize
.Width() && aBitmapSize
.Height() &&
403 ( rNewSize
.Width() != aBitmapSize
.Width() ||
404 rNewSize
.Height() != aBitmapSize
.Height() ) )
406 bRet
= Scale( (double) rNewSize
.Width() / aBitmapSize
.Width(),
407 (double) rNewSize
.Height() / aBitmapSize
.Height(),
416 bool BitmapEx::Rotate( long nAngle10
, const Color
& rFillColor
)
422 const bool bTransRotate
= ( Color( COL_TRANSPARENT
) == rFillColor
);
426 if( eTransparent
== TRANSPARENT_COLOR
)
427 bRet
= aBitmap
.Rotate( nAngle10
, aTransparentColor
);
430 bRet
= aBitmap
.Rotate( nAngle10
, COL_BLACK
);
432 if( eTransparent
== TRANSPARENT_NONE
)
434 aMask
= Bitmap( aBitmapSize
, 1 );
435 aMask
.Erase( COL_BLACK
);
436 eTransparent
= TRANSPARENT_BITMAP
;
439 if( bRet
&& !!aMask
)
440 aMask
.Rotate( nAngle10
, COL_WHITE
);
445 bRet
= aBitmap
.Rotate( nAngle10
, rFillColor
);
447 if( bRet
&& ( eTransparent
== TRANSPARENT_BITMAP
) && !!aMask
)
448 aMask
.Rotate( nAngle10
, COL_WHITE
);
451 aBitmapSize
= aBitmap
.GetSizePixel();
453 DBG_ASSERT( !aMask
|| aBitmap
.GetSizePixel() == aMask
.GetSizePixel(),
454 "BitmapEx::Rotate(): size mismatch for bitmap and alpha mask." );
460 bool BitmapEx::Crop( const Rectangle
& rRectPixel
)
466 bRet
= aBitmap
.Crop( rRectPixel
);
468 if( bRet
&& ( eTransparent
== TRANSPARENT_BITMAP
) && !!aMask
)
469 aMask
.Crop( rRectPixel
);
471 aBitmapSize
= aBitmap
.GetSizePixel();
473 DBG_ASSERT( !aMask
|| aBitmap
.GetSizePixel() == aMask
.GetSizePixel(),
474 "BitmapEx::Crop(): size mismatch for bitmap and alpha mask." );
480 bool BitmapEx::Convert( BmpConversion eConversion
)
482 return !!aBitmap
&& aBitmap
.Convert( eConversion
);
485 bool BitmapEx::ReduceColors( sal_uInt16 nNewColorCount
, BmpReduce eReduce
)
487 return !!aBitmap
&& aBitmap
.ReduceColors( nNewColorCount
, eReduce
);
490 bool BitmapEx::Expand( sal_uLong nDX
, sal_uLong nDY
, const Color
* pInitColor
, bool bExpandTransparent
)
496 bRet
= aBitmap
.Expand( nDX
, nDY
, pInitColor
);
498 if( bRet
&& ( eTransparent
== TRANSPARENT_BITMAP
) && !!aMask
)
500 Color
aColor( bExpandTransparent
? COL_WHITE
: COL_BLACK
);
501 aMask
.Expand( nDX
, nDY
, &aColor
);
504 aBitmapSize
= aBitmap
.GetSizePixel();
506 DBG_ASSERT( !aMask
|| aBitmap
.GetSizePixel() == aMask
.GetSizePixel(),
507 "BitmapEx::Expand(): size mismatch for bitmap and alpha mask." );
513 bool BitmapEx::CopyPixel( const Rectangle
& rRectDst
, const Rectangle
& rRectSrc
,
514 const BitmapEx
* pBmpExSrc
)
518 if( !pBmpExSrc
|| pBmpExSrc
->IsEmpty() )
520 if( !aBitmap
.IsEmpty() )
522 bRet
= aBitmap
.CopyPixel( rRectDst
, rRectSrc
);
524 if( bRet
&& ( eTransparent
== TRANSPARENT_BITMAP
) && !!aMask
)
525 aMask
.CopyPixel( rRectDst
, rRectSrc
);
530 if( !aBitmap
.IsEmpty() )
532 bRet
= aBitmap
.CopyPixel( rRectDst
, rRectSrc
, &pBmpExSrc
->aBitmap
);
536 if( pBmpExSrc
->IsAlpha() )
539 // cast to use the optimized AlphaMask::CopyPixel
540 aMask
.CopyPixel_AlphaOptimized( rRectDst
, rRectSrc
, &pBmpExSrc
->aMask
);
541 else if( IsTransparent() )
543 AlphaMask
* pAlpha
= new AlphaMask( aMask
);
545 aMask
= pAlpha
->ImplGetBitmap();
548 aMask
.CopyPixel( rRectDst
, rRectSrc
, &pBmpExSrc
->aMask
);
552 sal_uInt8 cBlack
= 0;
553 AlphaMask
* pAlpha
= new AlphaMask( GetSizePixel(), &cBlack
);
555 aMask
= pAlpha
->ImplGetBitmap();
557 eTransparent
= TRANSPARENT_BITMAP
;
559 aMask
.CopyPixel( rRectDst
, rRectSrc
, &pBmpExSrc
->aMask
);
562 else if( pBmpExSrc
->IsTransparent() )
566 AlphaMask
aAlpha( pBmpExSrc
->aMask
);
567 aMask
.CopyPixel( rRectDst
, rRectSrc
, &aAlpha
.ImplGetBitmap() );
569 else if( IsTransparent() )
570 aMask
.CopyPixel( rRectDst
, rRectSrc
, &pBmpExSrc
->aMask
);
573 aMask
= Bitmap( GetSizePixel(), 1 );
574 aMask
.Erase( Color( COL_BLACK
) );
575 eTransparent
= TRANSPARENT_BITMAP
;
576 aMask
.CopyPixel( rRectDst
, rRectSrc
, &pBmpExSrc
->aMask
);
581 sal_uInt8 cBlack
= 0;
582 const AlphaMask
aAlphaSrc( pBmpExSrc
->GetSizePixel(), &cBlack
);
584 aMask
.CopyPixel( rRectDst
, rRectSrc
, &aAlphaSrc
.ImplGetBitmap() );
586 else if( IsTransparent() )
588 Bitmap
aMaskSrc( pBmpExSrc
->GetSizePixel(), 1 );
590 aMaskSrc
.Erase( Color( COL_BLACK
) );
591 aMask
.CopyPixel( rRectDst
, rRectSrc
, &aMaskSrc
);
600 bool BitmapEx::Erase( const Color
& rFillColor
)
606 bRet
= aBitmap
.Erase( rFillColor
);
608 if( bRet
&& ( eTransparent
== TRANSPARENT_BITMAP
) && !!aMask
)
610 // Respect transparency on fill color
611 if( rFillColor
.GetTransparency() )
613 const Color
aFill( rFillColor
.GetTransparency(), rFillColor
.GetTransparency(), rFillColor
.GetTransparency() );
614 aMask
.Erase( aFill
);
618 const Color
aBlack( COL_BLACK
);
619 aMask
.Erase( aBlack
);
627 bool BitmapEx::Dither( BmpDitherFlags nDitherFlags
)
629 return !!aBitmap
&& aBitmap
.Dither( nDitherFlags
);
632 bool BitmapEx::Replace( const Color
& rSearchColor
, const Color
& rReplaceColor
, sal_uLong nTol
)
634 return !!aBitmap
&& aBitmap
.Replace( rSearchColor
, rReplaceColor
, nTol
);
637 bool BitmapEx::Replace( const Color
* pSearchColors
, const Color
* pReplaceColors
, sal_uLong nColorCount
, const sal_uLong
* pTols
)
639 return !!aBitmap
&& aBitmap
.Replace( pSearchColors
, pReplaceColors
, nColorCount
, const_cast<sal_uLong
*>(pTols
) );
642 bool BitmapEx::Adjust( short nLuminancePercent
, short nContrastPercent
,
643 short nChannelRPercent
, short nChannelGPercent
, short nChannelBPercent
,
644 double fGamma
, bool bInvert
, bool msoBrightness
)
646 return !!aBitmap
&& aBitmap
.Adjust( nLuminancePercent
, nContrastPercent
,
647 nChannelRPercent
, nChannelGPercent
, nChannelBPercent
,
648 fGamma
, bInvert
, msoBrightness
);
651 bool BitmapEx::Filter( BmpFilter eFilter
, const BmpFilterParam
* pFilterParam
, const Link
<>* pProgress
)
653 return !!aBitmap
&& aBitmap
.Filter( eFilter
, pFilterParam
, pProgress
);
656 void BitmapEx::Draw( OutputDevice
* pOutDev
, const Point
& rDestPt
) const
658 pOutDev
->DrawBitmapEx( rDestPt
, *this );
661 void BitmapEx::Draw( OutputDevice
* pOutDev
,
662 const Point
& rDestPt
, const Size
& rDestSize
) const
664 pOutDev
->DrawBitmapEx( rDestPt
, rDestSize
, *this );
667 BitmapEx
BitmapEx:: AutoScaleBitmap(BitmapEx
& aBitmap
, const long aStandardSize
)
669 Point
aEmptyPoint(0,0);
672 BitmapEx aRet
= aBitmap
;
673 double imgOldWidth
= aRet
.GetSizePixel().Width();
674 double imgOldHeight
=aRet
.GetSizePixel().Height();
677 if (imgOldWidth
>= aStandardSize
|| imgOldHeight
>= aStandardSize
)
679 sal_Int32 imgNewWidth
= 0;
680 sal_Int32 imgNewHeight
= 0;
681 if (imgOldWidth
>= imgOldHeight
)
683 imgNewWidth
= aStandardSize
;
684 imgNewHeight
= sal_Int32(imgOldHeight
/ (imgOldWidth
/ aStandardSize
) + 0.5);
686 imgposY
= (aStandardSize
- (imgOldHeight
/ (imgOldWidth
/ aStandardSize
) + 0.5)) / 2 + 0.5;
690 imgNewHeight
= aStandardSize
;
691 imgNewWidth
= sal_Int32(imgOldWidth
/ (imgOldHeight
/ aStandardSize
) + 0.5);
693 imgposX
= (aStandardSize
- (imgOldWidth
/ (imgOldHeight
/ aStandardSize
) + 0.5)) / 2 + 0.5;
696 aScaledSize
= Size( imgNewWidth
, imgNewHeight
);
697 aRet
.Scale( aScaledSize
, BmpScaleFlag::BestQuality
);
701 imgposX
= (aStandardSize
- imgOldWidth
) / 2 + 0.5;
702 imgposY
= (aStandardSize
- imgOldHeight
) / 2 + 0.5;
705 Size
aStdSize( aStandardSize
, aStandardSize
);
706 Rectangle
aRect(aEmptyPoint
, aStdSize
);
708 ScopedVclPtrInstance
< VirtualDevice
> aVirDevice( *Application::GetDefaultDevice(), 0, 1 );
709 aVirDevice
->SetOutputSizePixel( aStdSize
);
710 aVirDevice
->SetFillColor( COL_TRANSPARENT
);
711 aVirDevice
->SetLineColor( COL_TRANSPARENT
);
713 // Draw a rect into virDevice
714 aVirDevice
->DrawRect( aRect
);
715 Point
aPointPixel( (long)imgposX
, (long)imgposY
);
716 aVirDevice
->DrawBitmapEx( aPointPixel
, aRet
);
717 aRet
= aVirDevice
->GetBitmapEx( aEmptyPoint
, aStdSize
);
722 sal_uInt8
BitmapEx::GetTransparency(sal_Int32 nX
, sal_Int32 nY
) const
724 sal_uInt8
nTransparency(0xff);
726 if(!aBitmap
.IsEmpty())
728 if(nX
>= 0 && nX
< aBitmapSize
.Width() && nY
>= 0 && nY
< aBitmapSize
.Height())
732 case TRANSPARENT_NONE
:
734 // Not transparent, ergo all covered
735 nTransparency
= 0x00;
738 case TRANSPARENT_COLOR
:
740 Bitmap
aTestBitmap(aBitmap
);
741 BitmapReadAccess
* pRead
= aTestBitmap
.AcquireReadAccess();
745 const Color aColor
= pRead
->GetColor(nY
, nX
);
747 // If color is not equal to TransparentColor, we are not transparent
748 if(aColor
!= aTransparentColor
)
750 nTransparency
= 0x00;
753 Bitmap::ReleaseAccess(pRead
);
757 case TRANSPARENT_BITMAP
:
761 Bitmap
aTestBitmap(aMask
);
762 BitmapReadAccess
* pRead
= aTestBitmap
.AcquireReadAccess();
766 const BitmapColor
aBitmapColor(pRead
->GetPixel(nY
, nX
));
770 nTransparency
= aBitmapColor
.GetIndex();
774 if(0x00 == aBitmapColor
.GetIndex())
776 nTransparency
= 0x00;
780 Bitmap::ReleaseAccess(pRead
);
789 return nTransparency
;
792 // Shift alpha transparent pixels between cppcanvas/ implementations
793 // and vcl in a generally grotesque and under-performing fashion
794 bool BitmapEx::Create( const ::com::sun::star::uno::Reference
<
795 ::com::sun::star::rendering::XBitmapCanvas
> &xBitmapCanvas
,
798 uno::Reference
< beans::XFastPropertySet
> xFastPropertySet( xBitmapCanvas
, uno::UNO_QUERY
);
799 if( xFastPropertySet
.get() )
801 // 0 means get BitmapEx
802 uno::Any aAny
= xFastPropertySet
->getFastPropertyValue( 0 );
803 std::unique_ptr
<BitmapEx
> xBitmapEx(reinterpret_cast<BitmapEx
*>( *static_cast<const sal_Int64
*>(aAny
.getValue())));
811 SalBitmap
* pSalBmp
, *pSalMask
;
813 pSalBmp
= ImplGetSVData()->mpDefInst
->CreateSalBitmap();
814 pSalMask
= ImplGetSVData()->mpDefInst
->CreateSalBitmap();
816 Size
aLocalSize(rSize
);
817 if( pSalBmp
->Create( xBitmapCanvas
, aLocalSize
) )
819 if ( pSalMask
->Create( xBitmapCanvas
, aLocalSize
, true ) )
821 *this = BitmapEx(Bitmap(pSalBmp
), Bitmap(pSalMask
) );
826 *this = BitmapEx(Bitmap(pSalBmp
));
839 Bitmap
impTransformBitmap(
840 const Bitmap
& rSource
,
841 const Size
& rDestinationSize
,
842 const basegfx::B2DHomMatrix
& rTransform
,
845 Bitmap
aDestination(rDestinationSize
, 24);
846 std::unique_ptr
<BitmapWriteAccess
> xWrite(aDestination
.AcquireWriteAccess());
850 std::unique_ptr
<BitmapReadAccess
> xRead((const_cast< Bitmap
& >(rSource
)).AcquireReadAccess());
854 const Size
aDestinationSizePixel(aDestination
.GetSizePixel());
855 const BitmapColor
aOutside(BitmapColor(0xff, 0xff, 0xff));
857 for(sal_Int32
y(0L); y
< aDestinationSizePixel
.getHeight(); y
++)
859 for(sal_Int32
x(0L); x
< aDestinationSizePixel
.getWidth(); x
++)
861 const basegfx::B2DPoint
aSourceCoor(rTransform
* basegfx::B2DPoint(x
, y
));
868 xRead
->GetInterpolatedColorWithFallback(
875 // this version does the correct <= 0.0 checks, so no need
876 // to do the static_cast< sal_Int32 > self and make an error
880 xRead
->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 BitmapEx
BitmapEx::getTransformed(
928 const basegfx::B2DHomMatrix
& rTransformation
,
929 const basegfx::B2DRange
& rVisibleRange
,
938 const sal_uInt32
nSourceWidth(GetSizePixel().Width());
939 const sal_uInt32
nSourceHeight(GetSizePixel().Height());
941 if(!nSourceWidth
|| !nSourceHeight
)
945 basegfx::B2DRange
aOutlineRange(0.0, 0.0, 1.0, 1.0);
947 aOutlineRange
.transform(rTransformation
);
949 // create visible range from it by moving from relative to absolute
950 basegfx::B2DRange
aVisibleRange(rVisibleRange
);
952 aVisibleRange
.transform(
953 basegfx::tools::createScaleTranslateB2DHomMatrix(
954 aOutlineRange
.getRange(),
955 aOutlineRange
.getMinimum()));
957 // get target size (which is visible range's size)
958 double fWidth(aVisibleRange
.getWidth());
959 double fHeight(aVisibleRange
.getHeight());
961 if(fWidth
< 1.0 || fHeight
< 1.0)
966 // test if discrete size (pixel) maybe too big and limit it
967 const double fArea(fWidth
* fHeight
);
968 const bool bNeedToReduce(basegfx::fTools::more(fArea
, fMaximumArea
));
969 double fReduceFactor(1.0);
973 fReduceFactor
= sqrt(fMaximumArea
/ fArea
);
974 fWidth
*= fReduceFactor
;
975 fHeight
*= fReduceFactor
;
978 // Build complete transform from source pixels to target pixels.
979 // Start by scaling from source pixel size to unit coordinates
980 basegfx::B2DHomMatrix
aTransform(
981 basegfx::tools::createScaleB2DHomMatrix(
983 1.0 / nSourceHeight
));
985 // multiply with given transform which leads from unit coordinates inside
987 aTransform
= rTransformation
* aTransform
;
989 // subtract top-left of absolute VisibleRange
990 aTransform
.translate(
991 -aVisibleRange
.getMinX(),
992 -aVisibleRange
.getMinY());
994 // scale to target pixels (if needed)
997 aTransform
.scale(fReduceFactor
, fReduceFactor
);
1000 // invert to get transformation from target pixel coordiates to source pixels
1001 aTransform
.invert();
1003 // create bitmap using source, destination and linear back-transformation
1004 aRetval
= TransformBitmapEx(fWidth
, fHeight
, aTransform
, bSmooth
);
1009 BitmapEx
BitmapEx::ModifyBitmapEx(const basegfx::BColorModifierStack
& rBColorModifierStack
) const
1011 Bitmap
aChangedBitmap(GetBitmap());
1014 for(sal_uInt32
a(rBColorModifierStack
.count()); a
&& !bDone
; )
1016 const basegfx::BColorModifierSharedPtr
& rModifier
= rBColorModifierStack
.getBColorModifier(--a
);
1017 const basegfx::BColorModifier_replace
* pReplace
= dynamic_cast< const basegfx::BColorModifier_replace
* >(rModifier
.get());
1024 // clear bitmap with dest color
1025 if(aChangedBitmap
.GetBitCount() <= 8)
1027 // do NOT use erase; for e.g. 8bit Bitmaps, the nearest color to the given
1028 // erase color is determined and used -> this may be different from what is
1029 // wanted here. Better create a new bitmap with the needed color explicitely
1030 std::unique_ptr
<BitmapReadAccess
> xReadAccess(aChangedBitmap
.AcquireReadAccess());
1031 OSL_ENSURE(xReadAccess
, "Got no Bitmap ReadAccess ?!?");
1035 BitmapPalette
aNewPalette(xReadAccess
->GetPalette());
1036 aNewPalette
[0] = BitmapColor(Color(pReplace
->getBColor()));
1037 aChangedBitmap
= Bitmap(
1038 aChangedBitmap
.GetSizePixel(),
1039 aChangedBitmap
.GetBitCount(),
1045 aChangedBitmap
.Erase(Color(pReplace
->getBColor()));
1050 // erase bitmap, caller will know to paint direct
1051 aChangedBitmap
.SetEmpty();
1058 std::unique_ptr
<BitmapWriteAccess
> xContent(aChangedBitmap
.AcquireWriteAccess());
1062 const double fConvertColor(1.0 / 255.0);
1064 if(xContent
->HasPalette())
1066 const sal_uInt16
nCount(xContent
->GetPaletteEntryCount());
1068 for(sal_uInt16
b(0); b
< nCount
; b
++)
1070 const BitmapColor
& rCol
= xContent
->GetPaletteColor(b
);
1071 const basegfx::BColor
aBSource(
1072 rCol
.GetRed() * fConvertColor
,
1073 rCol
.GetGreen() * fConvertColor
,
1074 rCol
.GetBlue() * fConvertColor
);
1075 const basegfx::BColor
aBDest(rModifier
->getModifiedColor(aBSource
));
1076 xContent
->SetPaletteColor(b
, BitmapColor(Color(aBDest
)));
1079 else if(BMP_FORMAT_24BIT_TC_BGR
== xContent
->GetScanlineFormat())
1081 for(sal_uInt32
y(0L); y
< (sal_uInt32
)xContent
->Height(); y
++)
1083 Scanline pScan
= xContent
->GetScanline(y
);
1085 for(sal_uInt32
x(0L); x
< (sal_uInt32
)xContent
->Width(); x
++)
1087 const basegfx::BColor
aBSource(
1088 *(pScan
+ 2)* fConvertColor
,
1089 *(pScan
+ 1) * fConvertColor
,
1090 *pScan
* fConvertColor
);
1091 const basegfx::BColor
aBDest(rModifier
->getModifiedColor(aBSource
));
1092 *pScan
++ = static_cast< sal_uInt8
>(aBDest
.getBlue() * 255.0);
1093 *pScan
++ = static_cast< sal_uInt8
>(aBDest
.getGreen() * 255.0);
1094 *pScan
++ = static_cast< sal_uInt8
>(aBDest
.getRed() * 255.0);
1098 else if(BMP_FORMAT_24BIT_TC_RGB
== xContent
->GetScanlineFormat())
1100 for(sal_uInt32
y(0L); y
< (sal_uInt32
)xContent
->Height(); y
++)
1102 Scanline pScan
= xContent
->GetScanline(y
);
1104 for(sal_uInt32
x(0L); x
< (sal_uInt32
)xContent
->Width(); x
++)
1106 const basegfx::BColor
aBSource(
1107 *pScan
* fConvertColor
,
1108 *(pScan
+ 1) * fConvertColor
,
1109 *(pScan
+ 2) * fConvertColor
);
1110 const basegfx::BColor
aBDest(rModifier
->getModifiedColor(aBSource
));
1111 *pScan
++ = static_cast< sal_uInt8
>(aBDest
.getRed() * 255.0);
1112 *pScan
++ = static_cast< sal_uInt8
>(aBDest
.getGreen() * 255.0);
1113 *pScan
++ = static_cast< sal_uInt8
>(aBDest
.getBlue() * 255.0);
1119 for(sal_uInt32
y(0L); y
< (sal_uInt32
)xContent
->Height(); y
++)
1121 for(sal_uInt32
x(0L); x
< (sal_uInt32
)xContent
->Width(); x
++)
1123 const BitmapColor
aBMCol(xContent
->GetColor(y
, x
));
1124 const basegfx::BColor
aBSource(
1125 (double)aBMCol
.GetRed() * fConvertColor
,
1126 (double)aBMCol
.GetGreen() * fConvertColor
,
1127 (double)aBMCol
.GetBlue() * fConvertColor
);
1128 const basegfx::BColor
aBDest(rModifier
->getModifiedColor(aBSource
));
1130 xContent
->SetPixel(y
, x
, BitmapColor(Color(aBDest
)));
1138 if(aChangedBitmap
.IsEmpty())
1148 return BitmapEx(aChangedBitmap
, GetAlpha());
1152 return BitmapEx(aChangedBitmap
, GetMask());
1157 return BitmapEx(aChangedBitmap
);
1162 BitmapEx
createBlendFrame(
1165 Color aColorTopLeft
,
1166 Color aColorBottomRight
)
1168 const sal_uInt32
nW(rSize
.Width());
1169 const sal_uInt32
nH(rSize
.Height());
1173 Color
aColTopRight(aColorTopLeft
);
1174 Color
aColBottomLeft(aColorTopLeft
);
1175 const sal_uInt32
nDE(nW
+ nH
);
1177 aColTopRight
.Merge(aColorBottomRight
, 255 - sal_uInt8((nW
* 255) / nDE
));
1178 aColBottomLeft
.Merge(aColorBottomRight
, 255 - sal_uInt8((nH
* 255) / nDE
));
1180 return createBlendFrame(rSize
, nAlpha
, aColorTopLeft
, aColTopRight
, aColorBottomRight
, aColBottomLeft
);
1186 BitmapEx
createBlendFrame(
1189 Color aColorTopLeft
,
1190 Color aColorTopRight
,
1191 Color aColorBottomRight
,
1192 Color aColorBottomLeft
)
1194 BlendFrameCache
* pBlendFrameCache
= ImplGetBlendFrameCache();
1196 if(pBlendFrameCache
->m_aLastSize
== rSize
1197 && pBlendFrameCache
->m_nLastAlpha
== nAlpha
1198 && pBlendFrameCache
->m_aLastColorTopLeft
== aColorTopLeft
1199 && pBlendFrameCache
->m_aLastColorTopRight
== aColorTopRight
1200 && pBlendFrameCache
->m_aLastColorBottomRight
== aColorBottomRight
1201 && pBlendFrameCache
->m_aLastColorBottomLeft
== aColorBottomLeft
)
1203 return pBlendFrameCache
->m_aLastResult
;
1206 pBlendFrameCache
->m_aLastSize
= rSize
;
1207 pBlendFrameCache
->m_nLastAlpha
= nAlpha
;
1208 pBlendFrameCache
->m_aLastColorTopLeft
= aColorTopLeft
;
1209 pBlendFrameCache
->m_aLastColorTopRight
= aColorTopRight
;
1210 pBlendFrameCache
->m_aLastColorBottomRight
= aColorBottomRight
;
1211 pBlendFrameCache
->m_aLastColorBottomLeft
= aColorBottomLeft
;
1212 pBlendFrameCache
->m_aLastResult
.Clear();
1214 const long nW(rSize
.Width());
1215 const long nH(rSize
.Height());
1217 if(nW
> 1 && nH
> 1)
1219 sal_uInt8
aEraseTrans(0xff);
1220 Bitmap
aContent(rSize
, 24);
1221 AlphaMask
aAlpha(rSize
, &aEraseTrans
);
1223 aContent
.Erase(COL_BLACK
);
1225 BitmapWriteAccess
* xContent
= aContent
.AcquireWriteAccess();
1226 BitmapWriteAccess
* pAlpha
= aAlpha
.AcquireWriteAccess();
1228 if(xContent
&& pAlpha
)
1233 // x == 0, y == 0, top-left corner
1234 xContent
->SetPixel(0, 0, aColorTopLeft
);
1235 pAlpha
->SetPixelIndex(0, 0, nAlpha
);
1237 // y == 0, top line left to right
1238 for(x
= 1; x
< nW
- 1; x
++)
1240 Color
aMix(aColorTopLeft
);
1242 aMix
.Merge(aColorTopRight
, 255 - sal_uInt8((x
* 255) / nW
));
1243 xContent
->SetPixel(0, x
, aMix
);
1244 pAlpha
->SetPixelIndex(0, x
, nAlpha
);
1247 // x == nW - 1, y == 0, top-right corner
1248 // #i123690# Caution! When nW is 1, x == nW is possible (!)
1251 xContent
->SetPixel(0, x
, aColorTopRight
);
1252 pAlpha
->SetPixelIndex(0, x
, nAlpha
);
1255 // x == 0 and nW - 1, left and right line top-down
1256 for(y
= 1; y
< nH
- 1; y
++)
1258 Color
aMixA(aColorTopLeft
);
1260 aMixA
.Merge(aColorBottomLeft
, 255 - sal_uInt8((y
* 255) / nH
));
1261 xContent
->SetPixel(y
, 0, aMixA
);
1262 pAlpha
->SetPixelIndex(y
, 0, nAlpha
);
1264 // #i123690# Caution! When nW is 1, x == nW is possible (!)
1267 Color
aMixB(aColorTopRight
);
1269 aMixB
.Merge(aColorBottomRight
, 255 - sal_uInt8((y
* 255) / nH
));
1270 xContent
->SetPixel(y
, x
, aMixB
);
1271 pAlpha
->SetPixelIndex(y
, x
, nAlpha
);
1275 // #i123690# Caution! When nH is 1, y == nH is possible (!)
1278 // x == 0, y == nH - 1, bottom-left corner
1279 xContent
->SetPixel(y
, 0, aColorBottomLeft
);
1280 pAlpha
->SetPixelIndex(y
, 0, nAlpha
);
1282 // y == nH - 1, bottom line left to right
1283 for(x
= 1; x
< nW
- 1; x
++)
1285 Color
aMix(aColorBottomLeft
);
1287 aMix
.Merge(aColorBottomRight
, 255 - sal_uInt8(((x
- 0)* 255) / nW
));
1288 xContent
->SetPixel(y
, x
, aMix
);
1289 pAlpha
->SetPixelIndex(y
, x
, nAlpha
);
1292 // x == nW - 1, y == nH - 1, bottom-right corner
1293 // #i123690# Caution! When nW is 1, x == nW is possible (!)
1296 xContent
->SetPixel(y
, x
, aColorBottomRight
);
1297 pAlpha
->SetPixelIndex(y
, x
, nAlpha
);
1301 Bitmap::ReleaseAccess(xContent
);
1302 Bitmap::ReleaseAccess(pAlpha
);
1304 pBlendFrameCache
->m_aLastResult
= BitmapEx(aContent
, aAlpha
);
1310 Bitmap::ReleaseAccess(xContent
);
1315 Bitmap::ReleaseAccess(pAlpha
);
1320 return pBlendFrameCache
->m_aLastResult
;
1323 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */