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 .
20 #include <sal/log.hxx>
21 #include <o3tl/underlyingenumvalue.hxx>
22 #include <osl/diagnose.h>
23 #include <basegfx/matrix/b2dhommatrixtools.hxx>
24 #include <basegfx/color/bcolormodifier.hxx>
26 #include <vcl/ImageTree.hxx>
27 #include <vcl/outdev.hxx>
28 #include <vcl/alpha.hxx>
29 #include <vcl/bitmapex.hxx>
30 #include <vcl/svapp.hxx>
31 #include <vcl/bitmapaccess.hxx>
32 #include <vcl/virdev.hxx>
33 #include <vcl/settings.hxx>
34 #include <vcl/BitmapMonochromeFilter.hxx>
38 #include <salinst.hxx>
40 #include <bitmapwriteaccess.hxx>
42 #include <o3tl/any.hxx>
44 #include <com/sun/star/beans/XFastPropertySet.hpp>
48 using namespace ::com::sun::star
;
51 : meTransparent(TransparentType::NONE
)
56 BitmapEx::BitmapEx( const BitmapEx
& ) = default;
58 BitmapEx::BitmapEx( const BitmapEx
& rBitmapEx
, Point aSrc
, Size aSize
)
59 : meTransparent(TransparentType::NONE
)
62 if( rBitmapEx
.IsEmpty() )
65 maBitmap
= Bitmap( aSize
, rBitmapEx
.maBitmap
.GetBitCount() );
67 if( rBitmapEx
.IsAlpha() )
70 maMask
= AlphaMask( aSize
).ImplGetBitmap();
72 else if( rBitmapEx
.IsTransparent() )
73 maMask
= Bitmap( aSize
, rBitmapEx
.maMask
.GetBitCount() );
75 tools::Rectangle
aDestRect( Point( 0, 0 ), aSize
);
76 tools::Rectangle
aSrcRect( aSrc
, aSize
);
77 CopyPixel( aDestRect
, aSrcRect
, &rBitmapEx
);
80 BitmapEx::BitmapEx( Size aSize
, sal_uInt16 nBitCount
)
81 : meTransparent(TransparentType::NONE
)
84 maBitmap
= Bitmap( aSize
, nBitCount
);
88 BitmapEx::BitmapEx( const OUString
& rIconName
)
89 : meTransparent(TransparentType::NONE
)
92 loadFromIconTheme( rIconName
);
95 void BitmapEx::loadFromIconTheme( const OUString
& rIconName
)
102 aIconTheme
= Application::GetSettings().GetStyleSettings().DetermineIconTheme();
103 bSuccess
= ImageTree::get().loadImage(rIconName
, aIconTheme
, *this, true);
110 SAL_WARN_IF( !bSuccess
, "vcl", "BitmapEx::BitmapEx(): could not load image " << rIconName
<< " via icon theme " << aIconTheme
);
113 BitmapEx::BitmapEx( const Bitmap
& rBmp
) :
115 maBitmapSize ( maBitmap
.GetSizePixel() ),
116 meTransparent( TransparentType::NONE
),
121 BitmapEx::BitmapEx( const Bitmap
& rBmp
, const Bitmap
& rMask
) :
124 maBitmapSize ( maBitmap
.GetSizePixel() ),
125 meTransparent ( !rMask
? TransparentType::NONE
: TransparentType::Bitmap
),
128 // Ensure a mask is exactly one bit deep
129 if( !!maMask
&& maMask
.GetBitCount() != 1 )
131 SAL_WARN( "vcl", "BitmapEx: forced mask to monochrome");
132 BitmapEx
aMaskEx(maMask
);
133 BitmapFilter::Filter(aMaskEx
, BitmapMonochromeFilter(255));
134 maMask
= aMaskEx
.GetBitmap();
137 if (!!maBitmap
&& !!maMask
&& maBitmap
.GetSizePixel() != maMask
.GetSizePixel())
139 OSL_ENSURE(false, "Mask size differs from Bitmap size, corrected Mask (!)");
140 maMask
.Scale(maBitmap
.GetSizePixel());
144 BitmapEx::BitmapEx( const Bitmap
& rBmp
, const AlphaMask
& rAlphaMask
) :
146 maMask ( rAlphaMask
.ImplGetBitmap() ),
147 maBitmapSize ( maBitmap
.GetSizePixel() ),
148 meTransparent ( !rAlphaMask
? TransparentType::NONE
: TransparentType::Bitmap
),
149 mbAlpha ( !rAlphaMask
.IsEmpty() )
151 if (!!maBitmap
&& !!maMask
&& maBitmap
.GetSizePixel() != maMask
.GetSizePixel())
153 OSL_ENSURE(false, "Alpha size differs from Bitmap size, corrected Mask (!)");
154 maMask
.Scale(rBmp
.GetSizePixel());
157 // #i75531# the workaround below can go when
158 // X11SalGraphics::drawAlphaBitmap()'s render acceleration
159 // can handle the bitmap depth mismatch directly
160 if( maBitmap
.GetBitCount() < maMask
.GetBitCount() )
161 maBitmap
.Convert( BmpConversion::N24Bit
);
164 BitmapEx::BitmapEx( const Bitmap
& rBmp
, const Color
& rTransparentColor
) :
166 maBitmapSize ( maBitmap
.GetSizePixel() ),
167 maTransparentColor ( rTransparentColor
),
168 meTransparent ( TransparentType::Bitmap
),
171 maMask
= maBitmap
.CreateMask( maTransparentColor
);
173 SAL_WARN_IF(rBmp
.GetSizePixel() != maMask
.GetSizePixel(), "vcl",
174 "BitmapEx::BitmapEx(): size mismatch for bitmap and alpha mask.");
177 BitmapEx
& BitmapEx::operator=( const BitmapEx
& ) = default;
179 bool BitmapEx::operator==( const BitmapEx
& rBitmapEx
) const
181 if (meTransparent
!= rBitmapEx
.meTransparent
)
184 if (GetSizePixel() != rBitmapEx
.GetSizePixel())
187 if (meTransparent
!= rBitmapEx
.meTransparent
)
190 if (meTransparent
== TransparentType::Color
191 && maTransparentColor
!= rBitmapEx
.maTransparentColor
)
194 if (mbAlpha
!= rBitmapEx
.mbAlpha
)
197 if (maBitmap
!= rBitmapEx
.maBitmap
)
200 return maMask
== rBitmapEx
.maMask
;
203 bool BitmapEx::IsEmpty() const
205 return( maBitmap
.IsEmpty() && maMask
.IsEmpty() );
208 void BitmapEx::SetEmpty()
212 meTransparent
= TransparentType::NONE
;
216 void BitmapEx::Clear()
221 bool BitmapEx::IsTransparent() const
223 return( meTransparent
!= TransparentType::NONE
);
226 bool BitmapEx::IsAlpha() const
228 return( IsTransparent() && mbAlpha
);
231 const Bitmap
& BitmapEx::GetBitmapRef() const
236 Bitmap
BitmapEx::GetBitmap( const Color
* pTransReplaceColor
) const
238 Bitmap
aRetBmp( maBitmap
);
240 if( pTransReplaceColor
&& ( meTransparent
!= TransparentType::NONE
) )
244 if( meTransparent
== TransparentType::Color
)
245 aTempMask
= maBitmap
.CreateMask( maTransparentColor
);
250 aRetBmp
.Replace( aTempMask
, *pTransReplaceColor
);
252 aRetBmp
.Replace( GetAlpha(), *pTransReplaceColor
);
258 Bitmap
BitmapEx::GetMask() const
263 BitmapEx
aMaskEx(maMask
);
264 BitmapFilter::Filter(aMaskEx
, BitmapMonochromeFilter(255));
265 return aMaskEx
.GetBitmap();
268 AlphaMask
BitmapEx::GetAlpha() const
273 aAlpha
.ImplSetBitmap( maMask
);
278 return AlphaMask(maMask
);
282 sal_uLong
BitmapEx::GetSizeBytes() const
284 sal_uLong nSizeBytes
= maBitmap
.GetSizeBytes();
286 if( meTransparent
== TransparentType::Bitmap
)
287 nSizeBytes
+= maMask
.GetSizeBytes();
292 BitmapChecksum
BitmapEx::GetChecksum() const
294 BitmapChecksum nCrc
= maBitmap
.GetChecksum();
296 BitmapChecksumOctetArray aBCOA
;
298 UInt32ToSVBT32( o3tl::underlyingEnumValue(meTransparent
), aBT32
);
299 nCrc
= vcl_get_checksum( nCrc
, aBT32
, 4 );
301 UInt32ToSVBT32( sal_uInt32(mbAlpha
), aBT32
);
302 nCrc
= vcl_get_checksum( nCrc
, aBT32
, 4 );
304 if( ( TransparentType::Bitmap
== meTransparent
) && !maMask
.IsEmpty() )
306 BCToBCOA( maMask
.GetChecksum(), aBCOA
);
307 nCrc
= vcl_get_checksum( nCrc
, aBCOA
, BITMAP_CHECKSUM_SIZE
);
313 void BitmapEx::SetSizePixel(const Size
& rNewSize
)
315 maBitmapSize
= rNewSize
;
318 bool BitmapEx::Invert()
324 bRet
= maBitmap
.Invert();
326 if (bRet
&& (meTransparent
== TransparentType::Color
))
327 maTransparentColor
.Invert();
333 bool BitmapEx::Mirror( BmpMirrorFlags nMirrorFlags
)
339 bRet
= maBitmap
.Mirror( nMirrorFlags
);
341 if( bRet
&& ( meTransparent
== TransparentType::Bitmap
) && !!maMask
)
342 maMask
.Mirror( nMirrorFlags
);
348 bool BitmapEx::Scale( const double& rScaleX
, const double& rScaleY
, BmpScaleFlag nScaleFlag
)
354 bRet
= maBitmap
.Scale( rScaleX
, rScaleY
, nScaleFlag
);
356 if( bRet
&& ( meTransparent
== TransparentType::Bitmap
) && !!maMask
)
358 maMask
.Scale( rScaleX
, rScaleY
, nScaleFlag
);
361 SetSizePixel(maBitmap
.GetSizePixel());
363 SAL_WARN_IF( !!maMask
&& maBitmap
.GetSizePixel() != maMask
.GetSizePixel(), "vcl",
364 "BitmapEx::Scale(): size mismatch for bitmap and alpha mask." );
370 bool BitmapEx::Scale( const Size
& rNewSize
, BmpScaleFlag nScaleFlag
)
374 if (GetSizePixel().Width() && GetSizePixel().Height()
375 && (rNewSize
.Width() != GetSizePixel().Width()
376 || rNewSize
.Height() != GetSizePixel().Height() ) )
378 bRet
= Scale( static_cast<double>(rNewSize
.Width()) / GetSizePixel().Width(),
379 static_cast<double>(rNewSize
.Height()) / GetSizePixel().Height(),
390 bool BitmapEx::Rotate( long nAngle10
, const Color
& rFillColor
)
396 const bool bTransRotate
= ( COL_TRANSPARENT
== rFillColor
);
400 if( meTransparent
== TransparentType::Color
)
401 bRet
= maBitmap
.Rotate( nAngle10
, maTransparentColor
);
404 bRet
= maBitmap
.Rotate( nAngle10
, COL_BLACK
);
406 if( meTransparent
== TransparentType::NONE
)
408 maMask
= Bitmap(GetSizePixel(), 1);
409 maMask
.Erase( COL_BLACK
);
410 meTransparent
= TransparentType::Bitmap
;
413 if( bRet
&& !!maMask
)
414 maMask
.Rotate( nAngle10
, COL_WHITE
);
419 bRet
= maBitmap
.Rotate( nAngle10
, rFillColor
);
421 if( bRet
&& ( meTransparent
== TransparentType::Bitmap
) && !!maMask
)
422 maMask
.Rotate( nAngle10
, COL_WHITE
);
425 SetSizePixel(maBitmap
.GetSizePixel());
427 SAL_WARN_IF(!!maMask
&& maBitmap
.GetSizePixel() != maMask
.GetSizePixel(), "vcl",
428 "BitmapEx::Rotate(): size mismatch for bitmap and alpha mask.");
434 bool BitmapEx::Crop( const tools::Rectangle
& rRectPixel
)
440 bRet
= maBitmap
.Crop( rRectPixel
);
442 if( bRet
&& ( meTransparent
== TransparentType::Bitmap
) && !!maMask
)
443 maMask
.Crop( rRectPixel
);
445 SetSizePixel(maBitmap
.GetSizePixel());
447 SAL_WARN_IF(!!maMask
&& maBitmap
.GetSizePixel() != maMask
.GetSizePixel(), "vcl",
448 "BitmapEx::Crop(): size mismatch for bitmap and alpha mask.");
454 bool BitmapEx::Convert( BmpConversion eConversion
)
456 return !!maBitmap
&& maBitmap
.Convert( eConversion
);
459 void BitmapEx::Expand( sal_uLong nDX
, sal_uLong nDY
, bool bExpandTransparent
)
465 bRet
= maBitmap
.Expand( nDX
, nDY
);
467 if( bRet
&& ( meTransparent
== TransparentType::Bitmap
) && !!maMask
)
469 Color
aColor( bExpandTransparent
? COL_WHITE
: COL_BLACK
);
470 maMask
.Expand( nDX
, nDY
, &aColor
);
473 SetSizePixel(maBitmap
.GetSizePixel());
475 SAL_WARN_IF(!!maMask
&& maBitmap
.GetSizePixel() != maMask
.GetSizePixel(), "vcl",
476 "BitmapEx::Expand(): size mismatch for bitmap and alpha mask.");
480 bool BitmapEx::CopyPixel( const tools::Rectangle
& rRectDst
, const tools::Rectangle
& rRectSrc
,
481 const BitmapEx
* pBmpExSrc
)
485 if( !pBmpExSrc
|| pBmpExSrc
->IsEmpty() )
487 if( !maBitmap
.IsEmpty() )
489 bRet
= maBitmap
.CopyPixel( rRectDst
, rRectSrc
);
491 if( bRet
&& ( meTransparent
== TransparentType::Bitmap
) && !!maMask
)
492 maMask
.CopyPixel( rRectDst
, rRectSrc
);
497 if( !maBitmap
.IsEmpty() )
499 bRet
= maBitmap
.CopyPixel( rRectDst
, rRectSrc
, &pBmpExSrc
->maBitmap
);
503 if( pBmpExSrc
->IsAlpha() )
506 // cast to use the optimized AlphaMask::CopyPixel
507 maMask
.CopyPixel_AlphaOptimized( rRectDst
, rRectSrc
, &pBmpExSrc
->maMask
);
508 else if( IsTransparent() )
510 std::unique_ptr
<AlphaMask
> pAlpha(new AlphaMask( maMask
));
512 maMask
= pAlpha
->ImplGetBitmap();
515 maMask
.CopyPixel( rRectDst
, rRectSrc
, &pBmpExSrc
->maMask
);
519 sal_uInt8 cBlack
= 0;
520 std::unique_ptr
<AlphaMask
> pAlpha(new AlphaMask(GetSizePixel(), &cBlack
));
522 maMask
= pAlpha
->ImplGetBitmap();
524 meTransparent
= TransparentType::Bitmap
;
526 maMask
.CopyPixel( rRectDst
, rRectSrc
, &pBmpExSrc
->maMask
);
529 else if( pBmpExSrc
->IsTransparent() )
533 AlphaMask
aAlpha( pBmpExSrc
->maMask
);
534 maMask
.CopyPixel( rRectDst
, rRectSrc
, &aAlpha
.ImplGetBitmap() );
536 else if (IsTransparent())
538 maMask
.CopyPixel( rRectDst
, rRectSrc
, &pBmpExSrc
->maMask
);
542 maMask
= Bitmap(GetSizePixel(), 1);
543 maMask
.Erase(COL_BLACK
);
544 meTransparent
= TransparentType::Bitmap
;
545 maMask
.CopyPixel( rRectDst
, rRectSrc
, &pBmpExSrc
->maMask
);
550 sal_uInt8 cBlack
= 0;
551 const AlphaMask
aAlphaSrc(pBmpExSrc
->GetSizePixel(), &cBlack
);
553 maMask
.CopyPixel( rRectDst
, rRectSrc
, &aAlphaSrc
.ImplGetBitmap() );
555 else if (IsTransparent())
557 Bitmap
aMaskSrc(pBmpExSrc
->GetSizePixel(), 1);
559 aMaskSrc
.Erase( COL_BLACK
);
560 maMask
.CopyPixel( rRectDst
, rRectSrc
, &aMaskSrc
);
569 bool BitmapEx::Erase( const Color
& rFillColor
)
575 bRet
= maBitmap
.Erase( rFillColor
);
577 if( bRet
&& ( meTransparent
== TransparentType::Bitmap
) && !!maMask
)
579 // Respect transparency on fill color
580 if( rFillColor
.GetTransparency() )
582 const Color
aFill( rFillColor
.GetTransparency(), rFillColor
.GetTransparency(), rFillColor
.GetTransparency() );
583 maMask
.Erase( aFill
);
587 const Color
aBlack( COL_BLACK
);
588 maMask
.Erase( aBlack
);
596 void BitmapEx::Replace( const Color
& rSearchColor
, const Color
& rReplaceColor
)
599 maBitmap
.Replace( rSearchColor
, rReplaceColor
);
602 void BitmapEx::Replace( const Color
* pSearchColors
, const Color
* pReplaceColors
, sal_uLong nColorCount
)
605 maBitmap
.Replace( pSearchColors
, pReplaceColors
, nColorCount
, /*pTols*/nullptr );
608 bool BitmapEx::Adjust( short nLuminancePercent
, short nContrastPercent
,
609 short nChannelRPercent
, short nChannelGPercent
, short nChannelBPercent
,
610 double fGamma
, bool bInvert
, bool msoBrightness
)
612 return !!maBitmap
&& maBitmap
.Adjust( nLuminancePercent
, nContrastPercent
,
613 nChannelRPercent
, nChannelGPercent
, nChannelBPercent
,
614 fGamma
, bInvert
, msoBrightness
);
617 void BitmapEx::Draw( OutputDevice
* pOutDev
, const Point
& rDestPt
) const
619 pOutDev
->DrawBitmapEx( rDestPt
, *this );
622 void BitmapEx::Draw( OutputDevice
* pOutDev
,
623 const Point
& rDestPt
, const Size
& rDestSize
) const
625 pOutDev
->DrawBitmapEx( rDestPt
, rDestSize
, *this );
628 BitmapEx
BitmapEx:: AutoScaleBitmap(BitmapEx
const & aBitmap
, const long aStandardSize
)
630 Point
aEmptyPoint(0,0);
633 BitmapEx aRet
= aBitmap
;
634 double imgOldWidth
= aRet
.GetSizePixel().Width();
635 double imgOldHeight
= aRet
.GetSizePixel().Height();
638 if (imgOldWidth
>= aStandardSize
|| imgOldHeight
>= aStandardSize
)
640 sal_Int32 imgNewWidth
= 0;
641 sal_Int32 imgNewHeight
= 0;
642 if (imgOldWidth
>= imgOldHeight
)
644 imgNewWidth
= aStandardSize
;
645 imgNewHeight
= sal_Int32(imgOldHeight
/ (imgOldWidth
/ aStandardSize
) + 0.5);
647 imgposY
= (aStandardSize
- (imgOldHeight
/ (imgOldWidth
/ aStandardSize
) + 0.5)) / 2 + 0.5;
651 imgNewHeight
= aStandardSize
;
652 imgNewWidth
= sal_Int32(imgOldWidth
/ (imgOldHeight
/ aStandardSize
) + 0.5);
654 imgposX
= (aStandardSize
- (imgOldWidth
/ (imgOldHeight
/ aStandardSize
) + 0.5)) / 2 + 0.5;
657 aScaledSize
= Size( imgNewWidth
, imgNewHeight
);
658 aRet
.Scale( aScaledSize
, BmpScaleFlag::BestQuality
);
662 imgposX
= (aStandardSize
- imgOldWidth
) / 2 + 0.5;
663 imgposY
= (aStandardSize
- imgOldHeight
) / 2 + 0.5;
666 Size
aStdSize( aStandardSize
, aStandardSize
);
667 tools::Rectangle
aRect(aEmptyPoint
, aStdSize
);
669 ScopedVclPtrInstance
< VirtualDevice
> aVirDevice(*Application::GetDefaultDevice(),
670 DeviceFormat::DEFAULT
, DeviceFormat::BITMASK
);
671 aVirDevice
->SetOutputSizePixel( aStdSize
);
672 aVirDevice
->SetFillColor( COL_TRANSPARENT
);
673 aVirDevice
->SetLineColor( COL_TRANSPARENT
);
675 // Draw a rect into virDevice
676 aVirDevice
->DrawRect( aRect
);
677 Point
aPointPixel( static_cast<long>(imgposX
), static_cast<long>(imgposY
) );
678 aVirDevice
->DrawBitmapEx( aPointPixel
, aRet
);
679 aRet
= aVirDevice
->GetBitmapEx( aEmptyPoint
, aStdSize
);
684 sal_uInt8
BitmapEx::GetTransparency(sal_Int32 nX
, sal_Int32 nY
) const
686 sal_uInt8
nTransparency(0xff);
688 if(!maBitmap
.IsEmpty())
690 if (nX
>= 0 && nX
< GetSizePixel().Width() && nY
>= 0 && nY
< GetSizePixel().Height())
692 switch(meTransparent
)
694 case TransparentType::NONE
:
696 // Not transparent, ergo all covered
697 nTransparency
= 0x00;
700 case TransparentType::Color
:
702 Bitmap
aTestBitmap(maBitmap
);
703 Bitmap::ScopedReadAccess
pRead(aTestBitmap
);
707 const BitmapColor aBmpColor
= pRead
->GetColor(nY
, nX
);
709 // If color is not equal to TransparentColor, we are not transparent
710 if (aBmpColor
!= maTransparentColor
)
711 nTransparency
= 0x00;
716 case TransparentType::Bitmap
:
718 if(!maMask
.IsEmpty())
720 Bitmap
aTestBitmap(maMask
);
721 Bitmap::ScopedReadAccess
pRead(aTestBitmap
);
725 const BitmapColor
aBitmapColor(pRead
->GetPixel(nY
, nX
));
729 nTransparency
= aBitmapColor
.GetIndex();
733 if(0x00 == aBitmapColor
.GetIndex())
735 nTransparency
= 0x00;
746 return nTransparency
;
750 Color
BitmapEx::GetPixelColor(sal_Int32 nX
, sal_Int32 nY
) const
752 Bitmap::ScopedReadAccess
pReadAccess( const_cast<Bitmap
&>(maBitmap
) );
755 BitmapColor aColor
= pReadAccess
->GetColor(nY
, nX
);
759 AlphaMask aAlpha
= GetAlpha();
760 AlphaMask::ScopedReadAccess
pAlphaReadAccess(aAlpha
);
761 aColor
.SetTransparency(pAlphaReadAccess
->GetPixel(nY
, nX
).GetIndex());
763 else if (maBitmap
.GetBitCount() != 32)
765 aColor
.SetTransparency(0);
770 // Shift alpha transparent pixels between cppcanvas/ implementations
771 // and vcl in a generally grotesque and under-performing fashion
772 bool BitmapEx::Create( const css::uno::Reference
< css::rendering::XBitmapCanvas
> &xBitmapCanvas
,
775 uno::Reference
< beans::XFastPropertySet
> xFastPropertySet( xBitmapCanvas
, uno::UNO_QUERY
);
776 if( xFastPropertySet
.get() )
778 // 0 means get BitmapEx
779 uno::Any aAny
= xFastPropertySet
->getFastPropertyValue( 0 );
780 std::unique_ptr
<BitmapEx
> xBitmapEx(reinterpret_cast<BitmapEx
*>(*o3tl::doAccess
<sal_Int64
>(aAny
)));
788 std::shared_ptr
<SalBitmap
> pSalBmp
;
789 std::shared_ptr
<SalBitmap
> pSalMask
;
791 pSalBmp
= ImplGetSVData()->mpDefInst
->CreateSalBitmap();
793 Size
aLocalSize(rSize
);
794 if( pSalBmp
->Create( xBitmapCanvas
, aLocalSize
) )
796 pSalMask
= ImplGetSVData()->mpDefInst
->CreateSalBitmap();
797 if ( pSalMask
->Create( xBitmapCanvas
, aLocalSize
, true ) )
799 *this = BitmapEx(Bitmap(pSalBmp
), Bitmap(pSalMask
) );
804 *this = BitmapEx(Bitmap(pSalBmp
));
814 Bitmap
impTransformBitmap(
815 const Bitmap
& rSource
,
816 const Size
& rDestinationSize
,
817 const basegfx::B2DHomMatrix
& rTransform
,
820 Bitmap
aDestination(rDestinationSize
, 24);
821 BitmapScopedWriteAccess
xWrite(aDestination
);
825 Bitmap::ScopedReadAccess
xRead(const_cast< Bitmap
& >(rSource
));
829 const Size
aDestinationSizePixel(aDestination
.GetSizePixel());
830 const BitmapColor
aOutside(BitmapColor(0xff, 0xff, 0xff));
832 for(long y(0); y
< aDestinationSizePixel
.getHeight(); y
++)
834 Scanline pScanline
= xWrite
->GetScanline( y
);
835 for(long x(0); x
< aDestinationSizePixel
.getWidth(); x
++)
837 const basegfx::B2DPoint
aSourceCoor(rTransform
* basegfx::B2DPoint(x
, y
));
841 xWrite
->SetPixelOnData(
844 xRead
->GetInterpolatedColorWithFallback(
851 // this version does the correct <= 0.0 checks, so no need
852 // to do the static_cast< sal_Int32 > self and make an error
853 xWrite
->SetPixelOnData(
856 xRead
->GetColorWithFallback(
866 rSource
.AdaptBitCount(aDestination
);
871 /// Decides if rTransformation needs smoothing or not (e.g. 180 deg rotation doesn't need it).
872 bool implTransformNeedsSmooth(const basegfx::B2DHomMatrix
& rTransformation
)
874 basegfx::B2DVector aScale
, aTranslate
;
875 double fRotate
, fShearX
;
876 rTransformation
.decompose(aScale
, aTranslate
, fRotate
, fShearX
);
877 if (aScale
!= basegfx::B2DVector(1, 1))
882 fRotate
= fmod( fRotate
, F_2PI
);
887 if (!rtl::math::approxEqual(fRotate
, 0)
888 && !rtl::math::approxEqual(fRotate
, F_PI2
)
889 && !rtl::math::approxEqual(fRotate
, F_PI
)
890 && !rtl::math::approxEqual(fRotate
, 3 * F_PI2
))
895 if (!rtl::math::approxEqual(fShearX
, 0))
902 } // end of anonymous namespace
904 BitmapEx
BitmapEx::TransformBitmapEx(
907 const basegfx::B2DHomMatrix
& rTransformation
) const
909 if(fWidth
<= 1 || fHeight
<= 1)
912 // force destination to 24 bit, we want to smooth output
913 const Size
aDestinationSize(basegfx::fround(fWidth
), basegfx::fround(fHeight
));
914 bool bSmooth
= implTransformNeedsSmooth(rTransformation
);
915 const Bitmap
aDestination(impTransformBitmap(GetBitmapRef(), aDestinationSize
, rTransformation
, bSmooth
));
922 const Bitmap
aAlpha(impTransformBitmap(GetAlpha().GetBitmap(), aDestinationSize
, rTransformation
, bSmooth
));
923 return BitmapEx(aDestination
, AlphaMask(aAlpha
));
927 const Bitmap
aLclMask(impTransformBitmap(GetMask(), aDestinationSize
, rTransformation
, false));
928 return BitmapEx(aDestination
, aLclMask
);
932 return BitmapEx(aDestination
);
935 BitmapEx
BitmapEx::getTransformed(
936 const basegfx::B2DHomMatrix
& rTransformation
,
937 const basegfx::B2DRange
& rVisibleRange
,
938 double fMaximumArea
) const
945 const sal_uInt32
nSourceWidth(GetSizePixel().Width());
946 const sal_uInt32
nSourceHeight(GetSizePixel().Height());
948 if(!nSourceWidth
|| !nSourceHeight
)
952 basegfx::B2DRange
aOutlineRange(0.0, 0.0, 1.0, 1.0);
954 aOutlineRange
.transform(rTransformation
);
956 // create visible range from it by moving from relative to absolute
957 basegfx::B2DRange
aVisibleRange(rVisibleRange
);
959 aVisibleRange
.transform(
960 basegfx::utils::createScaleTranslateB2DHomMatrix(
961 aOutlineRange
.getRange(),
962 aOutlineRange
.getMinimum()));
964 // get target size (which is visible range's size)
965 double fWidth(aVisibleRange
.getWidth());
966 double fHeight(aVisibleRange
.getHeight());
968 if(fWidth
< 1.0 || fHeight
< 1.0)
973 // test if discrete size (pixel) maybe too big and limit it
974 const double fArea(fWidth
* fHeight
);
975 const bool bNeedToReduce(basegfx::fTools::more(fArea
, fMaximumArea
));
976 double fReduceFactor(1.0);
980 fReduceFactor
= sqrt(fMaximumArea
/ fArea
);
981 fWidth
*= fReduceFactor
;
982 fHeight
*= fReduceFactor
;
985 // Build complete transform from source pixels to target pixels.
986 // Start by scaling from source pixel size to unit coordinates
987 basegfx::B2DHomMatrix
aTransform(
988 basegfx::utils::createScaleB2DHomMatrix(
990 1.0 / nSourceHeight
));
992 // multiply with given transform which leads from unit coordinates inside
994 aTransform
= rTransformation
* aTransform
;
996 // subtract top-left of absolute VisibleRange
997 aTransform
.translate(
998 -aVisibleRange
.getMinX(),
999 -aVisibleRange
.getMinY());
1001 // scale to target pixels (if needed)
1004 aTransform
.scale(fReduceFactor
, fReduceFactor
);
1007 // invert to get transformation from target pixel coordinates to source pixels
1008 aTransform
.invert();
1010 // create bitmap using source, destination and linear back-transformation
1011 aRetval
= TransformBitmapEx(fWidth
, fHeight
, aTransform
);
1016 BitmapEx
BitmapEx::ModifyBitmapEx(const basegfx::BColorModifierStack
& rBColorModifierStack
) const
1018 Bitmap
aChangedBitmap(GetBitmapRef());
1021 for(sal_uInt32
a(rBColorModifierStack
.count()); a
&& !bDone
; )
1023 const basegfx::BColorModifierSharedPtr
& rModifier
= rBColorModifierStack
.getBColorModifier(--a
);
1024 const basegfx::BColorModifier_replace
* pReplace
= dynamic_cast< const basegfx::BColorModifier_replace
* >(rModifier
.get());
1031 // clear bitmap with dest color
1032 if(aChangedBitmap
.GetBitCount() <= 8)
1034 // do NOT use erase; for e.g. 8bit Bitmaps, the nearest color to the given
1035 // erase color is determined and used -> this may be different from what is
1036 // wanted here. Better create a new bitmap with the needed color explicitly
1037 Bitmap::ScopedReadAccess
xReadAccess(aChangedBitmap
);
1038 OSL_ENSURE(xReadAccess
, "Got no Bitmap ReadAccess ?!?");
1042 BitmapPalette
aNewPalette(xReadAccess
->GetPalette());
1043 aNewPalette
[0] = BitmapColor(Color(pReplace
->getBColor()));
1044 aChangedBitmap
= Bitmap(
1045 aChangedBitmap
.GetSizePixel(),
1046 aChangedBitmap
.GetBitCount(),
1052 aChangedBitmap
.Erase(Color(pReplace
->getBColor()));
1057 // erase bitmap, caller will know to paint direct
1058 aChangedBitmap
.SetEmpty();
1065 BitmapScopedWriteAccess
xContent(aChangedBitmap
);
1069 const double fConvertColor(1.0 / 255.0);
1071 if(xContent
->HasPalette())
1073 const sal_uInt16
nCount(xContent
->GetPaletteEntryCount());
1075 for(sal_uInt16
b(0); b
< nCount
; b
++)
1077 const BitmapColor
& rCol
= xContent
->GetPaletteColor(b
);
1078 const basegfx::BColor
aBSource(
1079 rCol
.GetRed() * fConvertColor
,
1080 rCol
.GetGreen() * fConvertColor
,
1081 rCol
.GetBlue() * fConvertColor
);
1082 const basegfx::BColor
aBDest(rModifier
->getModifiedColor(aBSource
));
1083 xContent
->SetPaletteColor(b
, BitmapColor(Color(aBDest
)));
1086 else if(ScanlineFormat::N24BitTcBgr
== xContent
->GetScanlineFormat())
1088 for(sal_uInt32
y(0); y
< static_cast<sal_uInt32
>(xContent
->Height()); y
++)
1090 Scanline pScan
= xContent
->GetScanline(y
);
1092 for(sal_uInt32
x(0); x
< static_cast<sal_uInt32
>(xContent
->Width()); x
++)
1094 const basegfx::BColor
aBSource(
1095 *(pScan
+ 2)* fConvertColor
,
1096 *(pScan
+ 1) * fConvertColor
,
1097 *pScan
* fConvertColor
);
1098 const basegfx::BColor
aBDest(rModifier
->getModifiedColor(aBSource
));
1099 *pScan
++ = static_cast< sal_uInt8
>(aBDest
.getBlue() * 255.0);
1100 *pScan
++ = static_cast< sal_uInt8
>(aBDest
.getGreen() * 255.0);
1101 *pScan
++ = static_cast< sal_uInt8
>(aBDest
.getRed() * 255.0);
1105 else if(ScanlineFormat::N24BitTcRgb
== xContent
->GetScanlineFormat())
1107 for(sal_uInt32
y(0); y
< static_cast<sal_uInt32
>(xContent
->Height()); y
++)
1109 Scanline pScan
= xContent
->GetScanline(y
);
1111 for(sal_uInt32
x(0); x
< static_cast<sal_uInt32
>(xContent
->Width()); x
++)
1113 const basegfx::BColor
aBSource(
1114 *pScan
* fConvertColor
,
1115 *(pScan
+ 1) * fConvertColor
,
1116 *(pScan
+ 2) * fConvertColor
);
1117 const basegfx::BColor
aBDest(rModifier
->getModifiedColor(aBSource
));
1118 *pScan
++ = static_cast< sal_uInt8
>(aBDest
.getRed() * 255.0);
1119 *pScan
++ = static_cast< sal_uInt8
>(aBDest
.getGreen() * 255.0);
1120 *pScan
++ = static_cast< sal_uInt8
>(aBDest
.getBlue() * 255.0);
1126 for(sal_uInt32
y(0); y
< static_cast<sal_uInt32
>(xContent
->Height()); y
++)
1128 Scanline pScanline
= xContent
->GetScanline( y
);
1129 for(sal_uInt32
x(0); x
< static_cast<sal_uInt32
>(xContent
->Width()); x
++)
1131 const BitmapColor
aBMCol(xContent
->GetColor(y
, x
));
1132 const basegfx::BColor
aBSource(
1133 static_cast<double>(aBMCol
.GetRed()) * fConvertColor
,
1134 static_cast<double>(aBMCol
.GetGreen()) * fConvertColor
,
1135 static_cast<double>(aBMCol
.GetBlue()) * fConvertColor
);
1136 const basegfx::BColor
aBDest(rModifier
->getModifiedColor(aBSource
));
1138 xContent
->SetPixelOnData(pScanline
, x
, BitmapColor(Color(aBDest
)));
1146 if(aChangedBitmap
.IsEmpty())
1156 return BitmapEx(aChangedBitmap
, GetAlpha());
1160 return BitmapEx(aChangedBitmap
, GetMask());
1165 return BitmapEx(aChangedBitmap
);
1170 BitmapEx
createBlendFrame(
1173 Color aColorTopLeft
,
1174 Color aColorBottomRight
)
1176 const sal_uInt32
nW(rSize
.Width());
1177 const sal_uInt32
nH(rSize
.Height());
1181 Color
aColTopRight(aColorTopLeft
);
1182 Color
aColBottomLeft(aColorTopLeft
);
1183 const sal_uInt32
nDE(nW
+ nH
);
1185 aColTopRight
.Merge(aColorBottomRight
, 255 - sal_uInt8((nW
* 255) / nDE
));
1186 aColBottomLeft
.Merge(aColorBottomRight
, 255 - sal_uInt8((nH
* 255) / nDE
));
1188 return createBlendFrame(rSize
, nAlpha
, aColorTopLeft
, aColTopRight
, aColorBottomRight
, aColBottomLeft
);
1194 BitmapEx
createBlendFrame(
1197 Color aColorTopLeft
,
1198 Color aColorTopRight
,
1199 Color aColorBottomRight
,
1200 Color aColorBottomLeft
)
1202 BlendFrameCache
* pBlendFrameCache
= ImplGetBlendFrameCache();
1204 if(pBlendFrameCache
->m_aLastSize
== rSize
1205 && pBlendFrameCache
->m_nLastAlpha
== nAlpha
1206 && pBlendFrameCache
->m_aLastColorTopLeft
== aColorTopLeft
1207 && pBlendFrameCache
->m_aLastColorTopRight
== aColorTopRight
1208 && pBlendFrameCache
->m_aLastColorBottomRight
== aColorBottomRight
1209 && pBlendFrameCache
->m_aLastColorBottomLeft
== aColorBottomLeft
)
1211 return pBlendFrameCache
->m_aLastResult
;
1214 pBlendFrameCache
->m_aLastSize
= rSize
;
1215 pBlendFrameCache
->m_nLastAlpha
= nAlpha
;
1216 pBlendFrameCache
->m_aLastColorTopLeft
= aColorTopLeft
;
1217 pBlendFrameCache
->m_aLastColorTopRight
= aColorTopRight
;
1218 pBlendFrameCache
->m_aLastColorBottomRight
= aColorBottomRight
;
1219 pBlendFrameCache
->m_aLastColorBottomLeft
= aColorBottomLeft
;
1220 pBlendFrameCache
->m_aLastResult
.Clear();
1222 const long nW(rSize
.Width());
1223 const long nH(rSize
.Height());
1225 if(nW
> 1 && nH
> 1)
1227 sal_uInt8
aEraseTrans(0xff);
1228 Bitmap
aContent(rSize
, 24);
1229 AlphaMask
aAlpha(rSize
, &aEraseTrans
);
1231 aContent
.Erase(COL_BLACK
);
1233 BitmapScopedWriteAccess
pContent(aContent
);
1234 AlphaScopedWriteAccess
pAlpha(aAlpha
);
1236 if(pContent
&& pAlpha
)
1240 Scanline pScanContent
= pContent
->GetScanline( 0 );
1241 Scanline pScanAlpha
= pContent
->GetScanline( 0 );
1243 // x == 0, y == 0, top-left corner
1244 pContent
->SetPixelOnData(pScanContent
, 0, aColorTopLeft
);
1245 pAlpha
->SetPixelOnData(pScanAlpha
, 0, BitmapColor(nAlpha
));
1247 // y == 0, top line left to right
1248 for(x
= 1; x
< nW
- 1; x
++)
1250 Color
aMix(aColorTopLeft
);
1252 aMix
.Merge(aColorTopRight
, 255 - sal_uInt8((x
* 255) / nW
));
1253 pContent
->SetPixelOnData(pScanContent
, x
, aMix
);
1254 pAlpha
->SetPixelOnData(pScanAlpha
, x
, BitmapColor(nAlpha
));
1257 // x == nW - 1, y == 0, top-right corner
1258 // #i123690# Caution! When nW is 1, x == nW is possible (!)
1261 pContent
->SetPixelOnData(pScanContent
, x
, aColorTopRight
);
1262 pAlpha
->SetPixelOnData(pScanAlpha
, x
, BitmapColor(nAlpha
));
1265 // x == 0 and nW - 1, left and right line top-down
1266 for(y
= 1; y
< nH
- 1; y
++)
1268 pScanContent
= pContent
->GetScanline( y
);
1269 pScanAlpha
= pContent
->GetScanline( y
);
1270 Color
aMixA(aColorTopLeft
);
1272 aMixA
.Merge(aColorBottomLeft
, 255 - sal_uInt8((y
* 255) / nH
));
1273 pContent
->SetPixelOnData(pScanContent
, 0, aMixA
);
1274 pAlpha
->SetPixelOnData(pScanAlpha
, 0, BitmapColor(nAlpha
));
1276 // #i123690# Caution! When nW is 1, x == nW is possible (!)
1279 Color
aMixB(aColorTopRight
);
1281 aMixB
.Merge(aColorBottomRight
, 255 - sal_uInt8((y
* 255) / nH
));
1282 pContent
->SetPixelOnData(pScanContent
, x
, aMixB
);
1283 pAlpha
->SetPixelOnData(pScanAlpha
, x
, BitmapColor(nAlpha
));
1287 // #i123690# Caution! When nH is 1, y == nH is possible (!)
1290 // x == 0, y == nH - 1, bottom-left corner
1291 pContent
->SetPixelOnData(pScanContent
, 0, aColorBottomLeft
);
1292 pAlpha
->SetPixelOnData(pScanAlpha
, 0, BitmapColor(nAlpha
));
1294 // y == nH - 1, bottom line left to right
1295 for(x
= 1; x
< nW
- 1; x
++)
1297 Color
aMix(aColorBottomLeft
);
1299 aMix
.Merge(aColorBottomRight
, 255 - sal_uInt8(((x
- 0)* 255) / nW
));
1300 pContent
->SetPixelOnData(pScanContent
, x
, aMix
);
1301 pAlpha
->SetPixelOnData(pScanAlpha
, x
, BitmapColor(nAlpha
));
1304 // x == nW - 1, y == nH - 1, bottom-right corner
1305 // #i123690# Caution! When nW is 1, x == nW is possible (!)
1308 pContent
->SetPixelOnData(pScanContent
, x
, aColorBottomRight
);
1309 pAlpha
->SetPixelOnData(pScanAlpha
, x
, BitmapColor(nAlpha
));
1316 pBlendFrameCache
->m_aLastResult
= BitmapEx(aContent
, aAlpha
);
1320 return pBlendFrameCache
->m_aLastResult
;
1323 void BitmapEx::Replace(const Color
& rSearchColor
,
1324 const Color
& rReplaceColor
,
1325 sal_uInt8 nTolerance
)
1327 maBitmap
.Replace(rSearchColor
, rReplaceColor
, nTolerance
);
1330 void BitmapEx::Replace( const Color
* pSearchColors
,
1331 const Color
* pReplaceColors
,
1332 sal_uLong nColorCount
,
1333 sal_uInt8
const * pTols
)
1335 maBitmap
.Replace( pSearchColors
, pReplaceColors
, nColorCount
, pTols
);
1338 void BitmapEx::ReplaceTransparency(const Color
& rColor
)
1340 if( IsTransparent() )
1342 maBitmap
.Replace( GetMask(), rColor
);
1344 maBitmapSize
= maBitmap
.GetSizePixel();
1345 maTransparentColor
= Color();
1346 meTransparent
= TransparentType::NONE
;
1351 static Bitmap
DetectEdges( const Bitmap
& rBmp
)
1353 constexpr sal_uInt8 cEdgeDetectThreshold
= 128;
1354 const Size
aSize( rBmp
.GetSizePixel() );
1357 if( ( aSize
.Width() > 2 ) && ( aSize
.Height() > 2 ) )
1359 Bitmap
aWorkBmp( rBmp
);
1361 if( aWorkBmp
.Convert( BmpConversion::N8BitGreys
) )
1365 ScopedVclPtr
<VirtualDevice
> pVirDev(VclPtr
<VirtualDevice
>::Create());
1366 pVirDev
->SetOutputSizePixel(aSize
);
1367 Bitmap::ScopedReadAccess
pReadAcc(aWorkBmp
);
1371 const long nWidth
= aSize
.Width();
1372 const long nWidth2
= nWidth
- 2;
1373 const long nHeight
= aSize
.Height();
1374 const long nHeight2
= nHeight
- 2;
1375 const long lThres2
= static_cast<long>(cEdgeDetectThreshold
) * cEdgeDetectThreshold
;
1380 // initialize border with white pixels
1381 pVirDev
->SetLineColor( COL_WHITE
);
1382 pVirDev
->DrawLine( Point(), Point( nWidth
- 1, 0L ) );
1383 pVirDev
->DrawLine( Point( nWidth
- 1, 0L ), Point( nWidth
- 1, nHeight
- 1 ) );
1384 pVirDev
->DrawLine( Point( nWidth
- 1, nHeight
- 1 ), Point( 0L, nHeight
- 1 ) );
1385 pVirDev
->DrawLine( Point( 0, nHeight
- 1 ), Point() );
1387 for( long nY
= 0, nY1
= 1, nY2
= 2; nY
< nHeight2
; nY
++, nY1
++, nY2
++ )
1389 Scanline pScanlineRead
= pReadAcc
->GetScanline( nY
);
1390 Scanline pScanlineRead1
= pReadAcc
->GetScanline( nY1
);
1391 Scanline pScanlineRead2
= pReadAcc
->GetScanline( nY2
);
1392 for( long nX
= 0, nXDst
= 1, nXTmp
; nX
< nWidth2
; nX
++, nXDst
++ )
1396 nSum2
= lGray
= pReadAcc
->GetIndexFromData( pScanlineRead
, nXTmp
++ );
1398 nSum2
+= static_cast<long>(pReadAcc
->GetIndexFromData( pScanlineRead
, nXTmp
++ )) << 1;
1399 lGray
= pReadAcc
->GetIndexFromData( pScanlineRead
, nXTmp
);
1403 nSum1
+= static_cast<long>(pReadAcc
->GetIndexFromData( pScanlineRead1
, nXTmp
)) << 1;
1405 nSum1
-= static_cast<long>(pReadAcc
->GetIndexFromData( pScanlineRead1
, nXTmp
)) << 1;
1407 lGray
= -static_cast<long>(pReadAcc
->GetIndexFromData( pScanlineRead2
, nXTmp
++ ));
1410 nSum2
-= static_cast<long>(pReadAcc
->GetIndexFromData( pScanlineRead2
, nXTmp
++ )) << 1;
1411 lGray
= static_cast<long>(pReadAcc
->GetIndexFromData( pScanlineRead2
, nXTmp
));
1415 if( ( nSum1
* nSum1
+ nSum2
* nSum2
) < lThres2
)
1416 pVirDev
->DrawPixel( Point(nXDst
, nY
), COL_WHITE
);
1418 pVirDev
->DrawPixel( Point(nXDst
, nY
), COL_BLACK
);
1428 aRetBmp
= pVirDev
->GetBitmap(Point(0,0), aSize
);
1436 aRetBmp
.SetPrefMapMode( rBmp
.GetPrefMapMode() );
1437 aRetBmp
.SetPrefSize( rBmp
.GetPrefSize() );
1443 /** Get contours in image */
1444 tools::Polygon
BitmapEx::GetContour( bool bContourEdgeDetect
,
1445 const tools::Rectangle
* pWorkRectPixel
)
1448 tools::Polygon aRetPoly
;
1449 tools::Rectangle
aWorkRect( Point(), maBitmap
.GetSizePixel() );
1451 if( pWorkRectPixel
)
1452 aWorkRect
.Intersection( *pWorkRectPixel
);
1454 aWorkRect
.Justify();
1456 if( ( aWorkRect
.GetWidth() > 4 ) && ( aWorkRect
.GetHeight() > 4 ) )
1458 // if the flag is set, we need to detect edges
1459 if( bContourEdgeDetect
)
1460 aWorkBmp
= DetectEdges( maBitmap
);
1462 aWorkBmp
= maBitmap
;
1464 BitmapReadAccess
* pAcc
= aWorkBmp
.AcquireReadAccess();
1466 const long nWidth
= pAcc
? pAcc
->Width() : 0;
1467 const long nHeight
= pAcc
? pAcc
->Height() : 0;
1469 if (pAcc
&& nWidth
&& nHeight
)
1471 const Size
& rPrefSize
= aWorkBmp
.GetPrefSize();
1472 const double fFactorX
= static_cast<double>(rPrefSize
.Width()) / nWidth
;
1473 const double fFactorY
= static_cast<double>(rPrefSize
.Height()) / nHeight
;
1474 const long nStartX1
= aWorkRect
.Left() + 1;
1475 const long nEndX1
= aWorkRect
.Right();
1476 const long nStartX2
= nEndX1
- 1;
1477 const long nStartY1
= aWorkRect
.Top() + 1;
1478 const long nEndY1
= aWorkRect
.Bottom();
1479 std::unique_ptr
<Point
[]> pPoints1
;
1480 std::unique_ptr
<Point
[]> pPoints2
;
1482 sal_uInt16 nPolyPos
= 0;
1483 const BitmapColor aBlack
= pAcc
->GetBestMatchingColor( COL_BLACK
);
1485 pPoints1
.reset(new Point
[ nHeight
]);
1486 pPoints2
.reset(new Point
[ nHeight
]);
1488 for ( nY
= nStartY1
; nY
< nEndY1
; nY
++ )
1491 Scanline pScanline
= pAcc
->GetScanline( nY
);
1493 // scan row from left to right
1494 while( nX
< nEndX1
)
1496 if( aBlack
== pAcc
->GetPixelFromData( pScanline
, nX
) )
1498 pPoints1
[ nPolyPos
] = Point( nX
, nY
);
1501 // this loop always breaks eventually as there is at least one pixel
1504 if( aBlack
== pAcc
->GetPixelFromData( pScanline
, nX
) )
1506 pPoints2
[ nPolyPos
] = Point( nX
, nY
);
1521 const sal_uInt16 nNewSize1
= nPolyPos
<< 1;
1523 aRetPoly
= tools::Polygon( nPolyPos
, pPoints1
.get() );
1524 aRetPoly
.SetSize( nNewSize1
+ 1 );
1525 aRetPoly
[ nNewSize1
] = aRetPoly
[ 0 ];
1527 for( sal_uInt16 j
= nPolyPos
; nPolyPos
< nNewSize1
; )
1528 aRetPoly
[ nPolyPos
++ ] = pPoints2
[ --j
];
1530 if( ( fFactorX
!= 0. ) && ( fFactorY
!= 0. ) )
1531 aRetPoly
.Scale( fFactorX
, fFactorY
);
1534 Bitmap::ReleaseAccess(pAcc
);
1540 void BitmapEx::setAlphaFrom( sal_uInt8 cIndexFrom
, sal_Int8 nAlphaTo
)
1542 AlphaMask
aAlphaMask(GetAlpha());
1543 BitmapScopedWriteAccess
pWriteAccess(aAlphaMask
);
1544 Bitmap::ScopedReadAccess
pReadAccess(maBitmap
);
1545 assert( pReadAccess
.get() && pWriteAccess
.get() );
1546 if ( pReadAccess
.get() && pWriteAccess
.get() )
1548 for ( long nY
= 0; nY
< pReadAccess
->Height(); nY
++ )
1550 Scanline pScanline
= pWriteAccess
->GetScanline( nY
);
1551 Scanline pScanlineRead
= pReadAccess
->GetScanline( nY
);
1552 for ( long nX
= 0; nX
< pReadAccess
->Width(); nX
++ )
1554 const sal_uInt8 cIndex
= pReadAccess
->GetPixelFromData( pScanlineRead
, nX
).GetIndex();
1555 if ( cIndex
== cIndexFrom
)
1556 pWriteAccess
->SetPixelOnData( pScanline
, nX
, BitmapColor(nAlphaTo
) );
1562 void BitmapEx::AdjustTransparency(sal_uInt8 cTrans
)
1566 if (!IsTransparent())
1568 aAlpha
= AlphaMask(GetSizePixel(), &cTrans
);
1570 else if( !IsAlpha() )
1573 aAlpha
.Replace( 0, cTrans
);
1577 aAlpha
= GetAlpha();
1578 BitmapScopedWriteAccess
pA(aAlpha
);
1584 sal_uLong nTrans
= cTrans
, nNewTrans
;
1585 const long nWidth
= pA
->Width(), nHeight
= pA
->Height();
1587 if( pA
->GetScanlineFormat() == ScanlineFormat::N8BitPal
)
1589 for( long nY
= 0; nY
< nHeight
; nY
++ )
1591 Scanline pAScan
= pA
->GetScanline( nY
);
1593 for( long nX
= 0; nX
< nWidth
; nX
++ )
1595 nNewTrans
= nTrans
+ *pAScan
;
1596 *pAScan
++ = static_cast<sal_uInt8
>( ( nNewTrans
& 0xffffff00 ) ? 255 : nNewTrans
);
1602 BitmapColor
aAlphaValue( 0 );
1604 for( long nY
= 0; nY
< nHeight
; nY
++ )
1606 Scanline pScanline
= pA
->GetScanline( nY
);
1607 for( long nX
= 0; nX
< nWidth
; nX
++ )
1609 nNewTrans
= nTrans
+ pA
->GetIndexFromData( pScanline
, nX
);
1610 aAlphaValue
.SetIndex( static_cast<sal_uInt8
>( ( nNewTrans
& 0xffffff00 ) ? 255 : nNewTrans
) );
1611 pA
->SetPixelOnData( pScanline
, nX
, aAlphaValue
);
1616 *this = BitmapEx( GetBitmapRef(), aAlpha
);
1619 // AS: Because JPEGs require the alpha channel provided separately (JPEG does not
1620 // natively support alpha channel, but SWF lets you provide it separately), we
1621 // extract the alpha channel into a separate array here.
1622 void BitmapEx::GetSplitData( std::vector
<sal_uInt8
>& rvColorData
, std::vector
<sal_uInt8
>& rvAlphaData
) const
1627 Bitmap::ScopedReadAccess
pRAcc(const_cast<Bitmap
&>(maBitmap
));
1632 sal_uInt32 nWidth
= pRAcc
->Width();
1633 sal_uInt32 nHeight
= pRAcc
->Height();
1634 rvColorData
.resize(nWidth
*nHeight
*4);
1635 rvAlphaData
.resize(nWidth
*nHeight
);
1636 sal_uInt8
* p
= rvColorData
.data(), *pAlpha
= rvAlphaData
.data();
1641 aAlpha
= GetAlpha();
1643 else if (IsTransparent())
1649 sal_uInt8 cAlphaVal
= 0;
1650 aAlpha
= AlphaMask(maBitmap
.GetSizePixel(), &cAlphaVal
);
1653 AlphaMask::ScopedReadAccess
pAAcc(aAlpha
);
1657 for( sal_uInt32 nY
= 0; nY
< nHeight
; nY
++ )
1659 Scanline pScanlineAA
= pAAcc
->GetScanline( nY
);
1660 for( sal_uInt32 nX
= 0; nX
< nWidth
; nX
++ )
1662 const sal_uInt8 nAlpha
= pAAcc
->GetIndexFromData( pScanlineAA
, nX
);
1663 const BitmapColor
aPixelColor( pRAcc
->GetColor( nY
, nX
) );
1665 if( nAlpha
== 0xff )
1675 *p
++ = aPixelColor
.GetRed();
1676 *p
++ = aPixelColor
.GetGreen();
1677 *p
++ = aPixelColor
.GetBlue();
1679 *pAlpha
++ = 0xff - nAlpha
;
1684 void BitmapEx::CombineMaskOr(Color maskColor
, sal_uInt8 nTol
)
1686 Bitmap aNewMask
= maBitmap
.CreateMask( maskColor
, nTol
);
1687 if ( IsTransparent() )
1688 aNewMask
.CombineSimple( maMask
, BmpCombine::Or
);
1690 meTransparent
= TransparentType::Bitmap
;
1694 * Retrieves the color model data we need for the XImageConsumer stuff.
1696 void BitmapEx::GetColorModel(css::uno::Sequence
< sal_Int32
>& rRGBPalette
,
1697 sal_uInt32
& rnRedMask
, sal_uInt32
& rnGreenMask
, sal_uInt32
& rnBlueMask
, sal_uInt32
& rnAlphaMask
, sal_uInt32
& rnTransparencyIndex
,
1698 sal_uInt32
& rnWidth
, sal_uInt32
& rnHeight
, sal_uInt8
& rnBitCount
)
1700 Bitmap::ScopedReadAccess
pReadAccess( maBitmap
);
1701 assert( pReadAccess
);
1703 if( pReadAccess
->HasPalette() )
1705 sal_uInt16 nPalCount
= pReadAccess
->GetPaletteEntryCount();
1709 rRGBPalette
= css::uno::Sequence
< sal_Int32
>( nPalCount
+ 1 );
1711 sal_Int32
* pTmp
= rRGBPalette
.getArray();
1713 for( sal_uInt32 i
= 0; i
< nPalCount
; i
++, pTmp
++ )
1715 const BitmapColor
& rCol
= pReadAccess
->GetPaletteColor( static_cast<sal_uInt16
>(i
) );
1717 *pTmp
= static_cast<sal_Int32
>(rCol
.GetRed()) << sal_Int32(24);
1718 *pTmp
|= static_cast<sal_Int32
>(rCol
.GetGreen()) << sal_Int32(16);
1719 *pTmp
|= static_cast<sal_Int32
>(rCol
.GetBlue()) << sal_Int32(8);
1720 *pTmp
|= sal_Int32(0x000000ffL
);
1723 if( IsTransparent() )
1725 // append transparent entry
1726 *pTmp
= sal_Int32(0xffffff00L
);
1727 rnTransparencyIndex
= nPalCount
;
1731 rnTransparencyIndex
= 0;
1736 rnRedMask
= 0xff000000UL
;
1737 rnGreenMask
= 0x00ff0000UL
;
1738 rnBlueMask
= 0x0000ff00UL
;
1739 rnAlphaMask
= 0x000000ffUL
;
1740 rnTransparencyIndex
= 0;
1743 rnWidth
= pReadAccess
->Width();
1744 rnHeight
= pReadAccess
->Height();
1745 rnBitCount
= pReadAccess
->GetBitCount();
1748 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */