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 <rtl/math.hxx>
22 #include <o3tl/underlyingenumvalue.hxx>
23 #include <osl/diagnose.h>
24 #include <basegfx/matrix/b2dhommatrixtools.hxx>
25 #include <basegfx/color/bcolormodifier.hxx>
27 #include <vcl/ImageTree.hxx>
28 #include <vcl/outdev.hxx>
29 #include <vcl/alpha.hxx>
30 #include <vcl/bitmapex.hxx>
31 #include <vcl/svapp.hxx>
32 #include <vcl/virdev.hxx>
33 #include <vcl/settings.hxx>
34 #include <vcl/BitmapMonochromeFilter.hxx>
38 #include <salinst.hxx>
40 #include <bitmap/BitmapWriteAccess.hxx>
41 #include <bitmap/BitmapMaskToAlphaFilter.hxx>
43 #include <o3tl/any.hxx>
44 #include <tools/stream.hxx>
45 #include <vcl/filter/PngImageWriter.hxx>
47 #include <com/sun/star/beans/XFastPropertySet.hpp>
51 using namespace ::com::sun::star
;
57 BitmapEx::BitmapEx( const BitmapEx
& ) = default;
59 BitmapEx::BitmapEx( const BitmapEx
& rBitmapEx
, Point aSrc
, Size aSize
)
61 if( rBitmapEx
.IsEmpty() || aSize
.IsEmpty() )
64 maBitmap
= Bitmap(aSize
, rBitmapEx
.maBitmap
.getPixelFormat());
66 if( rBitmapEx
.IsAlpha() )
67 maAlphaMask
= AlphaMask( aSize
).ImplGetBitmap();
69 tools::Rectangle
aDestRect( Point( 0, 0 ), aSize
);
70 tools::Rectangle
aSrcRect( aSrc
, aSize
);
71 CopyPixel( aDestRect
, aSrcRect
, &rBitmapEx
);
74 BitmapEx::BitmapEx(Size aSize
, vcl::PixelFormat ePixelFormat
)
76 maBitmap
= Bitmap(aSize
, ePixelFormat
);
80 BitmapEx::BitmapEx( const OUString
& rIconName
)
82 loadFromIconTheme( rIconName
);
85 void BitmapEx::loadFromIconTheme( const OUString
& rIconName
)
92 aIconTheme
= Application::GetSettings().GetStyleSettings().DetermineIconTheme();
93 bSuccess
= ImageTree::get().loadImage(rIconName
, aIconTheme
, *this, true);
100 SAL_WARN_IF( !bSuccess
, "vcl", "BitmapEx::BitmapEx(): could not load image " << rIconName
<< " via icon theme " << aIconTheme
);
103 BitmapEx::BitmapEx( const Bitmap
& rBmp
) :
105 maBitmapSize ( maBitmap
.GetSizePixel() )
109 BitmapEx::BitmapEx( const Bitmap
& rBmp
, const Bitmap
& rMask
) :
111 maBitmapSize ( maBitmap
.GetSizePixel() )
116 if( rMask
.getPixelFormat() == vcl::PixelFormat::N8_BPP
&& rMask
.HasGreyPalette8Bit() )
118 else if( rMask
.getPixelFormat() == vcl::PixelFormat::N8_BPP
)
120 BitmapEx
aMaskEx(rMask
);
121 BitmapFilter::Filter(aMaskEx
, BitmapMonochromeFilter(255));
122 maAlphaMask
= aMaskEx
.GetBitmap();
126 // convert to alpha bitmap
127 SAL_WARN( "vcl", "BitmapEx: forced mask to monochrome");
128 BitmapEx
aMaskEx(rMask
);
129 BitmapFilter::Filter(aMaskEx
, BitmapMonochromeFilter(255));
130 maAlphaMask
= aMaskEx
.GetBitmap();
133 if (!maBitmap
.IsEmpty() && maBitmap
.GetSizePixel() != maAlphaMask
.GetSizePixel())
135 OSL_ENSURE(false, "Mask size differs from Bitmap size, corrected Mask (!)");
136 maAlphaMask
.Scale(maBitmap
.GetSizePixel(), BmpScaleFlag::Fast
);
140 BitmapEx::BitmapEx( const Bitmap
& rBmp
, const AlphaMask
& rAlphaMask
) :
142 maAlphaMask ( rAlphaMask
.ImplGetBitmap() ),
143 maBitmapSize ( maBitmap
.GetSizePixel() )
145 if (!maBitmap
.IsEmpty() && !maAlphaMask
.IsEmpty() && maBitmap
.GetSizePixel() != maAlphaMask
.GetSizePixel())
147 OSL_ENSURE(false, "Alpha size differs from Bitmap size, corrected Mask (!)");
148 maAlphaMask
.Scale(rBmp
.GetSizePixel(), BmpScaleFlag::Fast
);
153 BitmapEx::BitmapEx( const Bitmap
& rBmp
, const Color
& rTransparentColor
) :
155 maBitmapSize ( maBitmap
.GetSizePixel() )
157 maAlphaMask
= maBitmap
.CreateMask( rTransparentColor
);
159 SAL_WARN_IF(rBmp
.GetSizePixel() != maAlphaMask
.GetSizePixel(), "vcl",
160 "BitmapEx::BitmapEx(): size mismatch for bitmap and alpha mask.");
164 BitmapEx
& BitmapEx::operator=( const BitmapEx
& ) = default;
166 bool BitmapEx::operator==( const BitmapEx
& rBitmapEx
) const
168 if (GetSizePixel() != rBitmapEx
.GetSizePixel())
171 if (maBitmap
!= rBitmapEx
.maBitmap
)
174 return maAlphaMask
== rBitmapEx
.maAlphaMask
;
177 bool BitmapEx::IsEmpty() const
179 return( maBitmap
.IsEmpty() && maAlphaMask
.IsEmpty() );
182 void BitmapEx::SetEmpty()
185 maAlphaMask
.SetEmpty();
188 void BitmapEx::Clear()
193 void BitmapEx::ClearAlpha()
195 maAlphaMask
.SetEmpty();
198 bool BitmapEx::IsAlpha() const
200 return !maAlphaMask
.IsEmpty();
203 const Bitmap
& BitmapEx::GetBitmap() const
208 Bitmap
BitmapEx::GetBitmap( Color aTransparentReplaceColor
) const
210 Bitmap
aRetBmp( maBitmap
);
212 if( !maAlphaMask
.IsEmpty() )
214 aRetBmp
.Replace( maAlphaMask
, aTransparentReplaceColor
);
220 sal_Int64
BitmapEx::GetSizeBytes() const
222 sal_Int64 nSizeBytes
= maBitmap
.GetSizeBytes();
224 if( !maAlphaMask
.IsEmpty() )
225 nSizeBytes
+= maAlphaMask
.GetSizeBytes();
230 BitmapChecksum
BitmapEx::GetChecksum() const
232 BitmapChecksum nCrc
= maBitmap
.GetChecksum();
234 if( !maAlphaMask
.IsEmpty() )
236 BitmapChecksumOctetArray aBCOA
;
237 BCToBCOA( maAlphaMask
.GetChecksum(), aBCOA
);
238 nCrc
= vcl_get_checksum( nCrc
, aBCOA
, BITMAP_CHECKSUM_SIZE
);
244 void BitmapEx::SetSizePixel(const Size
& rNewSize
)
246 maBitmapSize
= rNewSize
;
249 bool BitmapEx::Invert()
253 if (!maBitmap
.IsEmpty())
254 bRet
= maBitmap
.Invert();
259 bool BitmapEx::Mirror( BmpMirrorFlags nMirrorFlags
)
263 if( !maBitmap
.IsEmpty() )
265 bRet
= maBitmap
.Mirror( nMirrorFlags
);
267 if( bRet
&& !maAlphaMask
.IsEmpty() )
268 maAlphaMask
.Mirror( nMirrorFlags
);
274 bool BitmapEx::Scale( const double& rScaleX
, const double& rScaleY
, BmpScaleFlag nScaleFlag
)
278 if( !maBitmap
.IsEmpty() )
280 bRet
= maBitmap
.Scale( rScaleX
, rScaleY
, nScaleFlag
);
282 if( bRet
&& !maAlphaMask
.IsEmpty() )
284 maAlphaMask
.Scale( rScaleX
, rScaleY
, nScaleFlag
);
287 SetSizePixel(maBitmap
.GetSizePixel());
289 SAL_WARN_IF( !maAlphaMask
.IsEmpty() && maBitmap
.GetSizePixel() != maAlphaMask
.GetSizePixel(), "vcl",
290 "BitmapEx::Scale(): size mismatch for bitmap and alpha mask." );
296 bool BitmapEx::Scale( const Size
& rNewSize
, BmpScaleFlag nScaleFlag
)
300 if (GetSizePixel().Width() && GetSizePixel().Height()
301 && (rNewSize
.Width() != GetSizePixel().Width()
302 || rNewSize
.Height() != GetSizePixel().Height() ) )
304 bRet
= Scale( static_cast<double>(rNewSize
.Width()) / GetSizePixel().Width(),
305 static_cast<double>(rNewSize
.Height()) / GetSizePixel().Height(),
316 bool BitmapEx::Rotate( Degree10 nAngle10
, const Color
& rFillColor
)
320 if( !maBitmap
.IsEmpty() )
322 const bool bTransRotate
= ( COL_TRANSPARENT
== rFillColor
);
326 bRet
= maBitmap
.Rotate( nAngle10
, COL_BLACK
);
328 if( maAlphaMask
.IsEmpty() )
330 maAlphaMask
= Bitmap(GetSizePixel(), vcl::PixelFormat::N8_BPP
, &Bitmap::GetGreyPalette(256));
331 maAlphaMask
.Erase( 0 );
334 if( bRet
&& !maAlphaMask
.IsEmpty() )
335 maAlphaMask
.Rotate( nAngle10
, COL_WHITE
);
339 bRet
= maBitmap
.Rotate( nAngle10
, rFillColor
);
341 if( bRet
&& !maAlphaMask
.IsEmpty() )
342 maAlphaMask
.Rotate( nAngle10
, COL_WHITE
);
345 SetSizePixel(maBitmap
.GetSizePixel());
347 SAL_WARN_IF(!maAlphaMask
.IsEmpty() && maBitmap
.GetSizePixel() != maAlphaMask
.GetSizePixel(), "vcl",
348 "BitmapEx::Rotate(): size mismatch for bitmap and alpha mask.");
354 bool BitmapEx::Crop( const tools::Rectangle
& rRectPixel
)
358 if( !maBitmap
.IsEmpty() )
360 bRet
= maBitmap
.Crop( rRectPixel
);
362 if( bRet
&& !maAlphaMask
.IsEmpty() )
363 maAlphaMask
.Crop( rRectPixel
);
365 SetSizePixel(maBitmap
.GetSizePixel());
367 SAL_WARN_IF(!maAlphaMask
.IsEmpty() && maBitmap
.GetSizePixel() != maAlphaMask
.GetSizePixel(), "vcl",
368 "BitmapEx::Crop(): size mismatch for bitmap and alpha mask.");
374 bool BitmapEx::Convert( BmpConversion eConversion
)
376 return !maBitmap
.IsEmpty() && maBitmap
.Convert( eConversion
);
379 void BitmapEx::Expand( sal_Int32 nDX
, sal_Int32 nDY
, bool bExpandTransparent
)
383 if( maBitmap
.IsEmpty() )
386 bRet
= maBitmap
.Expand( nDX
, nDY
);
388 if( bRet
&& !maAlphaMask
.IsEmpty() )
390 Color
aColor( bExpandTransparent
? COL_WHITE
: COL_BLACK
);
391 maAlphaMask
.Expand( nDX
, nDY
, &aColor
);
394 SetSizePixel(maBitmap
.GetSizePixel());
396 SAL_WARN_IF(!maAlphaMask
.IsEmpty() && maBitmap
.GetSizePixel() != maAlphaMask
.GetSizePixel(), "vcl",
397 "BitmapEx::Expand(): size mismatch for bitmap and alpha mask.");
400 bool BitmapEx::CopyPixel( const tools::Rectangle
& rRectDst
, const tools::Rectangle
& rRectSrc
,
401 const BitmapEx
* pBmpExSrc
)
405 if( !pBmpExSrc
|| pBmpExSrc
->IsEmpty() )
407 if( !maBitmap
.IsEmpty() )
409 bRet
= maBitmap
.CopyPixel( rRectDst
, rRectSrc
);
411 if( bRet
&& !maAlphaMask
.IsEmpty() )
412 maAlphaMask
.CopyPixel( rRectDst
, rRectSrc
);
417 if( !maBitmap
.IsEmpty() )
419 bRet
= maBitmap
.CopyPixel( rRectDst
, rRectSrc
, &pBmpExSrc
->maBitmap
);
423 if( pBmpExSrc
->IsAlpha() )
426 // cast to use the optimized AlphaMask::CopyPixel
427 maAlphaMask
.CopyPixel_AlphaOptimized( rRectDst
, rRectSrc
, &pBmpExSrc
->maAlphaMask
);
430 sal_uInt8 cBlack
= 0;
431 std::optional
<AlphaMask
> pAlpha(std::in_place
, GetSizePixel(), &cBlack
);
433 maAlphaMask
= pAlpha
->ImplGetBitmap();
435 maAlphaMask
.CopyPixel( rRectDst
, rRectSrc
, &pBmpExSrc
->maAlphaMask
);
440 sal_uInt8 cBlack
= 0;
441 const AlphaMask
aAlphaSrc(pBmpExSrc
->GetSizePixel(), &cBlack
);
443 maAlphaMask
.CopyPixel( rRectDst
, rRectSrc
, &aAlphaSrc
.ImplGetBitmap() );
452 bool BitmapEx::Erase( const Color
& rFillColor
)
456 if( !maBitmap
.IsEmpty() )
458 bRet
= maBitmap
.Erase( rFillColor
);
460 if( bRet
&& !maAlphaMask
.IsEmpty() )
462 // Respect transparency on fill color
463 if( rFillColor
.IsTransparent() )
464 maAlphaMask
.Erase( 255 - rFillColor
.GetAlpha() );
466 maAlphaMask
.Erase( 0 );
473 void BitmapEx::Replace( const Color
& rSearchColor
, const Color
& rReplaceColor
)
475 if (!maBitmap
.IsEmpty())
476 maBitmap
.Replace( rSearchColor
, rReplaceColor
);
479 void BitmapEx::Replace( const Color
* pSearchColors
, const Color
* pReplaceColors
, size_t nColorCount
)
481 if (!maBitmap
.IsEmpty())
482 maBitmap
.Replace( pSearchColors
, pReplaceColors
, nColorCount
, /*pTols*/nullptr );
485 bool BitmapEx::Adjust( short nLuminancePercent
, short nContrastPercent
,
486 short nChannelRPercent
, short nChannelGPercent
, short nChannelBPercent
,
487 double fGamma
, bool bInvert
, bool msoBrightness
)
489 return !maBitmap
.IsEmpty() && maBitmap
.Adjust( nLuminancePercent
, nContrastPercent
,
490 nChannelRPercent
, nChannelGPercent
, nChannelBPercent
,
491 fGamma
, bInvert
, msoBrightness
);
494 void BitmapEx::Draw( OutputDevice
* pOutDev
, const Point
& rDestPt
) const
496 pOutDev
->DrawBitmapEx( rDestPt
, *this );
499 void BitmapEx::Draw( OutputDevice
* pOutDev
,
500 const Point
& rDestPt
, const Size
& rDestSize
) const
502 pOutDev
->DrawBitmapEx( rDestPt
, rDestSize
, *this );
505 BitmapEx
BitmapEx:: AutoScaleBitmap(BitmapEx
const & aBitmap
, const tools::Long aStandardSize
)
507 Point
aEmptyPoint(0,0);
510 BitmapEx aRet
= aBitmap
;
511 double imgOldWidth
= aRet
.GetSizePixel().Width();
512 double imgOldHeight
= aRet
.GetSizePixel().Height();
514 if (imgOldWidth
>= aStandardSize
|| imgOldHeight
>= aStandardSize
)
516 sal_Int32 imgNewWidth
= 0;
517 sal_Int32 imgNewHeight
= 0;
518 if (imgOldWidth
>= imgOldHeight
)
520 imgNewWidth
= aStandardSize
;
521 imgNewHeight
= sal_Int32(imgOldHeight
/ (imgOldWidth
/ aStandardSize
) + 0.5);
523 imgposY
= (aStandardSize
- (imgOldHeight
/ (imgOldWidth
/ aStandardSize
) + 0.5)) / 2 + 0.5;
527 imgNewHeight
= aStandardSize
;
528 imgNewWidth
= sal_Int32(imgOldWidth
/ (imgOldHeight
/ aStandardSize
) + 0.5);
530 imgposX
= (aStandardSize
- (imgOldWidth
/ (imgOldHeight
/ aStandardSize
) + 0.5)) / 2 + 0.5;
533 Size
aScaledSize( imgNewWidth
, imgNewHeight
);
534 aRet
.Scale( aScaledSize
, BmpScaleFlag::BestQuality
);
538 imgposX
= (aStandardSize
- imgOldWidth
) / 2 + 0.5;
539 imgposY
= (aStandardSize
- imgOldHeight
) / 2 + 0.5;
542 Size
aStdSize( aStandardSize
, aStandardSize
);
543 tools::Rectangle
aRect(aEmptyPoint
, aStdSize
);
545 ScopedVclPtrInstance
< VirtualDevice
> aVirDevice(*Application::GetDefaultDevice());
546 aVirDevice
->SetOutputSizePixel( aStdSize
);
547 aVirDevice
->SetFillColor( COL_TRANSPARENT
);
548 aVirDevice
->SetLineColor( COL_TRANSPARENT
);
550 // Draw a rect into virDevice
551 aVirDevice
->DrawRect( aRect
);
552 Point
aPointPixel( static_cast<tools::Long
>(imgposX
), static_cast<tools::Long
>(imgposY
) );
553 aVirDevice
->DrawBitmapEx( aPointPixel
, aRet
);
554 aRet
= aVirDevice
->GetBitmapEx( aEmptyPoint
, aStdSize
);
559 sal_uInt8
BitmapEx::GetAlpha(sal_Int32 nX
, sal_Int32 nY
) const
561 if(maBitmap
.IsEmpty())
564 if (nX
< 0 || nX
>= GetSizePixel().Width() || nY
< 0 || nY
>= GetSizePixel().Height())
567 if (maBitmap
.getPixelFormat() == vcl::PixelFormat::N32_BPP
)
568 return GetPixelColor(nX
, nY
).GetAlpha();
571 if (maAlphaMask
.IsEmpty())
573 // Not transparent, ergo all covered
578 Bitmap
aTestBitmap(maAlphaMask
);
579 Bitmap::ScopedReadAccess
pRead(aTestBitmap
);
583 const BitmapColor
aBitmapColor(pRead
->GetPixel(nY
, nX
));
584 nAlpha
= 255 - aBitmapColor
.GetIndex();
591 Color
BitmapEx::GetPixelColor(sal_Int32 nX
, sal_Int32 nY
) const
593 Bitmap::ScopedReadAccess
pReadAccess( const_cast<Bitmap
&>(maBitmap
) );
596 BitmapColor aColor
= pReadAccess
->GetColor(nY
, nX
);
600 AlphaMask aAlpha
= GetAlphaMask();
601 AlphaMask::ScopedReadAccess
pAlphaReadAccess(aAlpha
);
602 aColor
.SetAlpha(255 - pAlphaReadAccess
->GetPixel(nY
, nX
).GetIndex());
604 else if (maBitmap
.getPixelFormat() != vcl::PixelFormat::N32_BPP
)
606 aColor
.SetAlpha(255);
611 // Shift alpha transparent pixels between cppcanvas/ implementations
612 // and vcl in a generally grotesque and under-performing fashion
613 bool BitmapEx::Create( const css::uno::Reference
< css::rendering::XBitmapCanvas
> &xBitmapCanvas
,
616 uno::Reference
< beans::XFastPropertySet
> xFastPropertySet( xBitmapCanvas
, uno::UNO_QUERY
);
617 if( xFastPropertySet
)
619 // 0 means get BitmapEx
620 uno::Any aAny
= xFastPropertySet
->getFastPropertyValue( 0 );
621 std::unique_ptr
<BitmapEx
> xBitmapEx(reinterpret_cast<BitmapEx
*>(*o3tl::doAccess
<sal_Int64
>(aAny
)));
629 std::shared_ptr
<SalBitmap
> pSalBmp
;
630 std::shared_ptr
<SalBitmap
> pSalMask
;
632 pSalBmp
= ImplGetSVData()->mpDefInst
->CreateSalBitmap();
634 Size
aLocalSize(rSize
);
635 if( pSalBmp
->Create( xBitmapCanvas
, aLocalSize
) )
637 pSalMask
= ImplGetSVData()->mpDefInst
->CreateSalBitmap();
638 if ( pSalMask
->Create( xBitmapCanvas
, aLocalSize
, true ) )
640 *this = BitmapEx(Bitmap(pSalBmp
), Bitmap(pSalMask
) );
645 *this = BitmapEx(Bitmap(pSalBmp
));
655 Bitmap
impTransformBitmap(
656 const Bitmap
& rSource
,
657 const Size
& rDestinationSize
,
658 const basegfx::B2DHomMatrix
& rTransform
,
661 Bitmap
aDestination(rDestinationSize
, vcl::PixelFormat::N24_BPP
);
662 BitmapScopedWriteAccess
xWrite(aDestination
);
666 Bitmap::ScopedReadAccess
xRead(const_cast< Bitmap
& >(rSource
));
670 const Size
aDestinationSizePixel(aDestination
.GetSizePixel());
671 const BitmapColor
aOutside(BitmapColor(0xff, 0xff, 0xff));
673 for(tools::Long
y(0); y
< aDestinationSizePixel
.getHeight(); y
++)
675 Scanline pScanline
= xWrite
->GetScanline( y
);
676 for(tools::Long
x(0); x
< aDestinationSizePixel
.getWidth(); x
++)
678 const basegfx::B2DPoint
aSourceCoor(rTransform
* basegfx::B2DPoint(x
, y
));
682 xWrite
->SetPixelOnData(
685 xRead
->GetInterpolatedColorWithFallback(
692 // this version does the correct <= 0.0 checks, so no need
693 // to do the static_cast< sal_Int32 > self and make an error
694 xWrite
->SetPixelOnData(
697 xRead
->GetColorWithFallback(
708 rSource
.AdaptBitCount(aDestination
);
713 /// Decides if rTransformation needs smoothing or not (e.g. 180 deg rotation doesn't need it).
714 bool implTransformNeedsSmooth(const basegfx::B2DHomMatrix
& rTransformation
)
716 basegfx::B2DVector aScale
, aTranslate
;
717 double fRotate
, fShearX
;
718 rTransformation
.decompose(aScale
, aTranslate
, fRotate
, fShearX
);
719 if (aScale
!= basegfx::B2DVector(1, 1))
724 fRotate
= fmod( fRotate
, 2 * M_PI
);
729 if (!rtl::math::approxEqual(fRotate
, 0)
730 && !rtl::math::approxEqual(fRotate
, M_PI_2
)
731 && !rtl::math::approxEqual(fRotate
, M_PI
)
732 && !rtl::math::approxEqual(fRotate
, 3 * M_PI_2
))
737 if (!rtl::math::approxEqual(fShearX
, 0))
744 } // end of anonymous namespace
746 BitmapEx
BitmapEx::TransformBitmapEx(
749 const basegfx::B2DHomMatrix
& rTransformation
) const
751 if(fWidth
<= 1 || fHeight
<= 1)
754 // force destination to 24 bit, we want to smooth output
755 const Size
aDestinationSize(basegfx::fround(fWidth
), basegfx::fround(fHeight
));
756 bool bSmooth
= implTransformNeedsSmooth(rTransformation
);
757 const Bitmap
aDestination(impTransformBitmap(GetBitmap(), aDestinationSize
, rTransformation
, bSmooth
));
762 const Bitmap
aAlpha(impTransformBitmap(GetAlphaMask().GetBitmap(), aDestinationSize
, rTransformation
, bSmooth
));
763 return BitmapEx(aDestination
, AlphaMask(aAlpha
));
766 return BitmapEx(aDestination
);
769 BitmapEx
BitmapEx::getTransformed(
770 const basegfx::B2DHomMatrix
& rTransformation
,
771 const basegfx::B2DRange
& rVisibleRange
,
772 double fMaximumArea
) const
779 const sal_uInt32
nSourceWidth(GetSizePixel().Width());
780 const sal_uInt32
nSourceHeight(GetSizePixel().Height());
782 if(!nSourceWidth
|| !nSourceHeight
)
786 basegfx::B2DRange
aOutlineRange(0.0, 0.0, 1.0, 1.0);
788 aOutlineRange
.transform(rTransformation
);
790 // create visible range from it by moving from relative to absolute
791 basegfx::B2DRange
aVisibleRange(rVisibleRange
);
793 aVisibleRange
.transform(
794 basegfx::utils::createScaleTranslateB2DHomMatrix(
795 aOutlineRange
.getRange(),
796 aOutlineRange
.getMinimum()));
798 // get target size (which is visible range's size)
799 double fWidth(aVisibleRange
.getWidth());
800 double fHeight(aVisibleRange
.getHeight());
802 if(fWidth
< 1.0 || fHeight
< 1.0)
807 // test if discrete size (pixel) maybe too big and limit it
808 const double fArea(fWidth
* fHeight
);
809 const bool bNeedToReduce(basegfx::fTools::more(fArea
, fMaximumArea
));
810 double fReduceFactor(1.0);
814 fReduceFactor
= sqrt(fMaximumArea
/ fArea
);
815 fWidth
*= fReduceFactor
;
816 fHeight
*= fReduceFactor
;
819 // Build complete transform from source pixels to target pixels.
820 // Start by scaling from source pixel size to unit coordinates
821 basegfx::B2DHomMatrix
aTransform(
822 basegfx::utils::createScaleB2DHomMatrix(
824 1.0 / nSourceHeight
));
826 // multiply with given transform which leads from unit coordinates inside
828 aTransform
= rTransformation
* aTransform
;
830 // subtract top-left of absolute VisibleRange
831 aTransform
.translate(
832 -aVisibleRange
.getMinX(),
833 -aVisibleRange
.getMinY());
835 // scale to target pixels (if needed)
838 aTransform
.scale(fReduceFactor
, fReduceFactor
);
841 // invert to get transformation from target pixel coordinates to source pixels
844 // create bitmap using source, destination and linear back-transformation
845 aRetval
= TransformBitmapEx(fWidth
, fHeight
, aTransform
);
850 BitmapEx
BitmapEx::ModifyBitmapEx(const basegfx::BColorModifierStack
& rBColorModifierStack
) const
852 Bitmap
aChangedBitmap(GetBitmap());
855 for(sal_uInt32
a(rBColorModifierStack
.count()); a
&& !bDone
; )
857 const basegfx::BColorModifierSharedPtr
& rModifier
= rBColorModifierStack
.getBColorModifier(--a
);
858 const basegfx::BColorModifier_replace
* pReplace
= dynamic_cast< const basegfx::BColorModifier_replace
* >(rModifier
.get());
865 // clear bitmap with dest color
866 if (vcl::isPalettePixelFormat(aChangedBitmap
.getPixelFormat()))
868 // For e.g. 8bit Bitmaps, the nearest color to the given erase color is
869 // determined and used -> this may be different from what is wanted here.
870 // Better create a new bitmap with the needed color explicitly.
871 Bitmap::ScopedReadAccess
xReadAccess(aChangedBitmap
);
872 OSL_ENSURE(xReadAccess
, "Got no Bitmap ReadAccess ?!?");
876 BitmapPalette
aNewPalette(xReadAccess
->GetPalette());
877 aNewPalette
[0] = BitmapColor(Color(pReplace
->getBColor()));
878 aChangedBitmap
= Bitmap(
879 aChangedBitmap
.GetSizePixel(),
880 aChangedBitmap
.getPixelFormat(),
884 aChangedBitmap
.Erase(Color(pReplace
->getBColor()));
888 // erase bitmap, caller will know to paint direct
889 aChangedBitmap
.SetEmpty();
896 BitmapScopedWriteAccess
xContent(aChangedBitmap
);
900 const double fConvertColor(1.0 / 255.0);
902 if(xContent
->HasPalette())
904 const sal_uInt16
nCount(xContent
->GetPaletteEntryCount());
906 for(sal_uInt16
b(0); b
< nCount
; b
++)
908 const BitmapColor
& rCol
= xContent
->GetPaletteColor(b
);
909 const basegfx::BColor
aBSource(
910 rCol
.GetRed() * fConvertColor
,
911 rCol
.GetGreen() * fConvertColor
,
912 rCol
.GetBlue() * fConvertColor
);
913 const basegfx::BColor
aBDest(rModifier
->getModifiedColor(aBSource
));
914 xContent
->SetPaletteColor(b
, BitmapColor(Color(aBDest
)));
917 else if(ScanlineFormat::N24BitTcBgr
== xContent
->GetScanlineFormat())
919 for(tools::Long
y(0); y
< xContent
->Height(); y
++)
921 Scanline pScan
= xContent
->GetScanline(y
);
923 for(tools::Long
x(0); x
< xContent
->Width(); x
++)
925 const basegfx::BColor
aBSource(
926 *(pScan
+ 2)* fConvertColor
,
927 *(pScan
+ 1) * fConvertColor
,
928 *pScan
* fConvertColor
);
929 const basegfx::BColor
aBDest(rModifier
->getModifiedColor(aBSource
));
930 *pScan
++ = static_cast< sal_uInt8
>(aBDest
.getBlue() * 255.0);
931 *pScan
++ = static_cast< sal_uInt8
>(aBDest
.getGreen() * 255.0);
932 *pScan
++ = static_cast< sal_uInt8
>(aBDest
.getRed() * 255.0);
936 else if(ScanlineFormat::N24BitTcRgb
== xContent
->GetScanlineFormat())
938 for(tools::Long
y(0); y
< xContent
->Height(); y
++)
940 Scanline pScan
= xContent
->GetScanline(y
);
942 for(tools::Long
x(0); x
< xContent
->Width(); x
++)
944 const basegfx::BColor
aBSource(
945 *pScan
* fConvertColor
,
946 *(pScan
+ 1) * fConvertColor
,
947 *(pScan
+ 2) * fConvertColor
);
948 const basegfx::BColor
aBDest(rModifier
->getModifiedColor(aBSource
));
949 *pScan
++ = static_cast< sal_uInt8
>(aBDest
.getRed() * 255.0);
950 *pScan
++ = static_cast< sal_uInt8
>(aBDest
.getGreen() * 255.0);
951 *pScan
++ = static_cast< sal_uInt8
>(aBDest
.getBlue() * 255.0);
957 for(tools::Long
y(0); y
< xContent
->Height(); y
++)
959 Scanline pScanline
= xContent
->GetScanline( y
);
960 for(tools::Long
x(0); x
< xContent
->Width(); x
++)
962 const BitmapColor
aBMCol(xContent
->GetColor(y
, x
));
963 const basegfx::BColor
aBSource(
964 static_cast<double>(aBMCol
.GetRed()) * fConvertColor
,
965 static_cast<double>(aBMCol
.GetGreen()) * fConvertColor
,
966 static_cast<double>(aBMCol
.GetBlue()) * fConvertColor
);
967 const basegfx::BColor
aBDest(rModifier
->getModifiedColor(aBSource
));
969 xContent
->SetPixelOnData(pScanline
, x
, BitmapColor(Color(aBDest
)));
977 if(aChangedBitmap
.IsEmpty())
985 return BitmapEx(aChangedBitmap
, GetAlphaMask());
989 return BitmapEx(aChangedBitmap
);
994 BitmapEx
createBlendFrame(
998 Color aColorBottomRight
)
1000 const sal_uInt32
nW(rSize
.Width());
1001 const sal_uInt32
nH(rSize
.Height());
1005 Color
aColTopRight(aColorTopLeft
);
1006 Color
aColBottomLeft(aColorTopLeft
);
1007 const sal_uInt32
nDE(nW
+ nH
);
1009 aColTopRight
.Merge(aColorBottomRight
, 255 - sal_uInt8((nW
* 255) / nDE
));
1010 aColBottomLeft
.Merge(aColorBottomRight
, 255 - sal_uInt8((nH
* 255) / nDE
));
1012 return createBlendFrame(rSize
, nAlpha
, aColorTopLeft
, aColTopRight
, aColorBottomRight
, aColBottomLeft
);
1018 BitmapEx
createBlendFrame(
1021 Color aColorTopLeft
,
1022 Color aColorTopRight
,
1023 Color aColorBottomRight
,
1024 Color aColorBottomLeft
)
1026 BlendFrameCache
* pBlendFrameCache
= ImplGetBlendFrameCache();
1028 if(pBlendFrameCache
->m_aLastSize
== rSize
1029 && pBlendFrameCache
->m_nLastAlpha
== nAlpha
1030 && pBlendFrameCache
->m_aLastColorTopLeft
== aColorTopLeft
1031 && pBlendFrameCache
->m_aLastColorTopRight
== aColorTopRight
1032 && pBlendFrameCache
->m_aLastColorBottomRight
== aColorBottomRight
1033 && pBlendFrameCache
->m_aLastColorBottomLeft
== aColorBottomLeft
)
1035 return pBlendFrameCache
->m_aLastResult
;
1038 pBlendFrameCache
->m_aLastSize
= rSize
;
1039 pBlendFrameCache
->m_nLastAlpha
= nAlpha
;
1040 pBlendFrameCache
->m_aLastColorTopLeft
= aColorTopLeft
;
1041 pBlendFrameCache
->m_aLastColorTopRight
= aColorTopRight
;
1042 pBlendFrameCache
->m_aLastColorBottomRight
= aColorBottomRight
;
1043 pBlendFrameCache
->m_aLastColorBottomLeft
= aColorBottomLeft
;
1044 pBlendFrameCache
->m_aLastResult
.Clear();
1046 const tools::Long
nW(rSize
.Width());
1047 const tools::Long
nH(rSize
.Height());
1049 if(nW
> 1 && nH
> 1)
1051 sal_uInt8
aEraseTrans(0xff);
1052 Bitmap
aContent(rSize
, vcl::PixelFormat::N24_BPP
);
1053 AlphaMask
aAlpha(rSize
, &aEraseTrans
);
1055 aContent
.Erase(COL_BLACK
);
1057 BitmapScopedWriteAccess
pContent(aContent
);
1058 AlphaScopedWriteAccess
pAlpha(aAlpha
);
1060 if(pContent
&& pAlpha
)
1064 Scanline pScanContent
= pContent
->GetScanline( 0 );
1065 Scanline pScanAlpha
= pContent
->GetScanline( 0 );
1067 // x == 0, y == 0, top-left corner
1068 pContent
->SetPixelOnData(pScanContent
, 0, aColorTopLeft
);
1069 pAlpha
->SetPixelOnData(pScanAlpha
, 0, BitmapColor(nAlpha
));
1071 // y == 0, top line left to right
1072 for(x
= 1; x
< nW
- 1; x
++)
1074 Color
aMix(aColorTopLeft
);
1076 aMix
.Merge(aColorTopRight
, 255 - sal_uInt8((x
* 255) / nW
));
1077 pContent
->SetPixelOnData(pScanContent
, x
, aMix
);
1078 pAlpha
->SetPixelOnData(pScanAlpha
, x
, BitmapColor(nAlpha
));
1081 // x == nW - 1, y == 0, top-right corner
1082 // #i123690# Caution! When nW is 1, x == nW is possible (!)
1085 pContent
->SetPixelOnData(pScanContent
, x
, aColorTopRight
);
1086 pAlpha
->SetPixelOnData(pScanAlpha
, x
, BitmapColor(nAlpha
));
1089 // x == 0 and nW - 1, left and right line top-down
1090 for(y
= 1; y
< nH
- 1; y
++)
1092 pScanContent
= pContent
->GetScanline( y
);
1093 pScanAlpha
= pContent
->GetScanline( y
);
1094 Color
aMixA(aColorTopLeft
);
1096 aMixA
.Merge(aColorBottomLeft
, 255 - sal_uInt8((y
* 255) / nH
));
1097 pContent
->SetPixelOnData(pScanContent
, 0, aMixA
);
1098 pAlpha
->SetPixelOnData(pScanAlpha
, 0, BitmapColor(nAlpha
));
1100 // #i123690# Caution! When nW is 1, x == nW is possible (!)
1103 Color
aMixB(aColorTopRight
);
1105 aMixB
.Merge(aColorBottomRight
, 255 - sal_uInt8((y
* 255) / nH
));
1106 pContent
->SetPixelOnData(pScanContent
, x
, aMixB
);
1107 pAlpha
->SetPixelOnData(pScanAlpha
, x
, BitmapColor(nAlpha
));
1111 // #i123690# Caution! When nH is 1, y == nH is possible (!)
1114 // x == 0, y == nH - 1, bottom-left corner
1115 pContent
->SetPixelOnData(pScanContent
, 0, aColorBottomLeft
);
1116 pAlpha
->SetPixelOnData(pScanAlpha
, 0, BitmapColor(nAlpha
));
1118 // y == nH - 1, bottom line left to right
1119 for(x
= 1; x
< nW
- 1; x
++)
1121 Color
aMix(aColorBottomLeft
);
1123 aMix
.Merge(aColorBottomRight
, 255 - sal_uInt8(((x
- 0)* 255) / nW
));
1124 pContent
->SetPixelOnData(pScanContent
, x
, aMix
);
1125 pAlpha
->SetPixelOnData(pScanAlpha
, x
, BitmapColor(nAlpha
));
1128 // x == nW - 1, y == nH - 1, bottom-right corner
1129 // #i123690# Caution! When nW is 1, x == nW is possible (!)
1132 pContent
->SetPixelOnData(pScanContent
, x
, aColorBottomRight
);
1133 pAlpha
->SetPixelOnData(pScanAlpha
, x
, BitmapColor(nAlpha
));
1140 pBlendFrameCache
->m_aLastResult
= BitmapEx(aContent
, aAlpha
);
1144 return pBlendFrameCache
->m_aLastResult
;
1147 void BitmapEx::Replace(const Color
& rSearchColor
,
1148 const Color
& rReplaceColor
,
1149 sal_uInt8 nTolerance
)
1151 maBitmap
.Replace(rSearchColor
, rReplaceColor
, nTolerance
);
1154 void BitmapEx::Replace( const Color
* pSearchColors
,
1155 const Color
* pReplaceColors
,
1157 sal_uInt8
const * pTols
)
1159 maBitmap
.Replace( pSearchColors
, pReplaceColors
, nColorCount
, pTols
);
1162 void BitmapEx::ReplaceTransparency(const Color
& rColor
)
1166 maBitmap
.Replace( GetAlphaMask(), rColor
);
1167 maAlphaMask
= Bitmap();
1168 maBitmapSize
= maBitmap
.GetSizePixel();
1172 static Bitmap
DetectEdges( const Bitmap
& rBmp
)
1174 constexpr sal_uInt8 cEdgeDetectThreshold
= 128;
1175 const Size
aSize( rBmp
.GetSizePixel() );
1177 if( ( aSize
.Width() <= 2 ) || ( aSize
.Height() <= 2 ) )
1180 Bitmap
aWorkBmp( rBmp
);
1182 if( !aWorkBmp
.Convert( BmpConversion::N8BitGreys
) )
1185 ScopedVclPtr
<VirtualDevice
> pVirDev(VclPtr
<VirtualDevice
>::Create());
1186 pVirDev
->SetOutputSizePixel(aSize
);
1187 Bitmap::ScopedReadAccess
pReadAcc(aWorkBmp
);
1191 const tools::Long nWidth
= aSize
.Width();
1192 const tools::Long nWidth2
= nWidth
- 2;
1193 const tools::Long nHeight
= aSize
.Height();
1194 const tools::Long nHeight2
= nHeight
- 2;
1195 const tools::Long lThres2
= static_cast<tools::Long
>(cEdgeDetectThreshold
) * cEdgeDetectThreshold
;
1200 // initialize border with white pixels
1201 pVirDev
->SetLineColor( COL_WHITE
);
1202 pVirDev
->DrawLine( Point(), Point( nWidth
- 1, 0L ) );
1203 pVirDev
->DrawLine( Point( nWidth
- 1, 0L ), Point( nWidth
- 1, nHeight
- 1 ) );
1204 pVirDev
->DrawLine( Point( nWidth
- 1, nHeight
- 1 ), Point( 0L, nHeight
- 1 ) );
1205 pVirDev
->DrawLine( Point( 0, nHeight
- 1 ), Point() );
1207 for( tools::Long nY
= 0, nY1
= 1, nY2
= 2; nY
< nHeight2
; nY
++, nY1
++, nY2
++ )
1209 Scanline pScanlineRead
= pReadAcc
->GetScanline( nY
);
1210 Scanline pScanlineRead1
= pReadAcc
->GetScanline( nY1
);
1211 Scanline pScanlineRead2
= pReadAcc
->GetScanline( nY2
);
1212 for( tools::Long nX
= 0, nXDst
= 1, nXTmp
; nX
< nWidth2
; nX
++, nXDst
++ )
1216 nSum2
= pReadAcc
->GetIndexFromData( pScanlineRead
, nXTmp
++ );
1218 nSum2
+= static_cast<tools::Long
>(pReadAcc
->GetIndexFromData( pScanlineRead
, nXTmp
++ )) << 1;
1219 lGray
= pReadAcc
->GetIndexFromData( pScanlineRead
, nXTmp
);
1223 nSum1
+= static_cast<tools::Long
>(pReadAcc
->GetIndexFromData( pScanlineRead1
, nXTmp
)) << 1;
1225 nSum1
-= static_cast<tools::Long
>(pReadAcc
->GetIndexFromData( pScanlineRead1
, nXTmp
)) << 1;
1227 lGray
= -static_cast<tools::Long
>(pReadAcc
->GetIndexFromData( pScanlineRead2
, nXTmp
++ ));
1230 nSum2
-= static_cast<tools::Long
>(pReadAcc
->GetIndexFromData( pScanlineRead2
, nXTmp
++ )) << 1;
1231 lGray
= static_cast<tools::Long
>(pReadAcc
->GetIndexFromData( pScanlineRead2
, nXTmp
));
1235 if( ( nSum1
* nSum1
+ nSum2
* nSum2
) < lThres2
)
1236 pVirDev
->DrawPixel( Point(nXDst
, nY
), COL_WHITE
);
1238 pVirDev
->DrawPixel( Point(nXDst
, nY
), COL_BLACK
);
1244 Bitmap aRetBmp
= pVirDev
->GetBitmap(Point(0,0), aSize
);
1246 if( aRetBmp
.IsEmpty() )
1250 aRetBmp
.SetPrefMapMode( rBmp
.GetPrefMapMode() );
1251 aRetBmp
.SetPrefSize( rBmp
.GetPrefSize() );
1257 /** Get contours in image */
1258 tools::Polygon
BitmapEx::GetContour( bool bContourEdgeDetect
,
1259 const tools::Rectangle
* pWorkRectPixel
)
1262 tools::Polygon aRetPoly
;
1263 tools::Rectangle
aWorkRect( Point(), maBitmap
.GetSizePixel() );
1265 if( pWorkRectPixel
)
1266 aWorkRect
.Intersection( *pWorkRectPixel
);
1268 aWorkRect
.Normalize();
1270 if( ( aWorkRect
.GetWidth() > 4 ) && ( aWorkRect
.GetHeight() > 4 ) )
1272 // if the flag is set, we need to detect edges
1273 if( bContourEdgeDetect
)
1274 aWorkBmp
= DetectEdges( maBitmap
);
1276 aWorkBmp
= maBitmap
;
1278 BitmapReadAccess
* pAcc
= aWorkBmp
.AcquireReadAccess();
1280 const tools::Long nWidth
= pAcc
? pAcc
->Width() : 0;
1281 const tools::Long nHeight
= pAcc
? pAcc
->Height() : 0;
1283 if (pAcc
&& nWidth
&& nHeight
)
1285 const Size
& rPrefSize
= aWorkBmp
.GetPrefSize();
1286 const double fFactorX
= static_cast<double>(rPrefSize
.Width()) / nWidth
;
1287 const double fFactorY
= static_cast<double>(rPrefSize
.Height()) / nHeight
;
1288 const tools::Long nStartX1
= aWorkRect
.Left() + 1;
1289 const tools::Long nEndX1
= aWorkRect
.Right();
1290 const tools::Long nStartX2
= nEndX1
- 1;
1291 const tools::Long nStartY1
= aWorkRect
.Top() + 1;
1292 const tools::Long nEndY1
= aWorkRect
.Bottom();
1293 std::unique_ptr
<Point
[]> pPoints1
;
1294 std::unique_ptr
<Point
[]> pPoints2
;
1296 sal_uInt16 nPolyPos
= 0;
1297 const BitmapColor aBlack
= pAcc
->GetBestMatchingColor( COL_BLACK
);
1299 pPoints1
.reset(new Point
[ nHeight
]);
1300 pPoints2
.reset(new Point
[ nHeight
]);
1302 for ( nY
= nStartY1
; nY
< nEndY1
; nY
++ )
1305 Scanline pScanline
= pAcc
->GetScanline( nY
);
1307 // scan row from left to right
1308 while( nX
< nEndX1
)
1310 if( aBlack
== pAcc
->GetPixelFromData( pScanline
, nX
) )
1312 pPoints1
[ nPolyPos
] = Point( nX
, nY
);
1315 // this loop always breaks eventually as there is at least one pixel
1318 if( aBlack
== pAcc
->GetPixelFromData( pScanline
, nX
) )
1320 pPoints2
[ nPolyPos
] = Point( nX
, nY
);
1335 const sal_uInt16 nNewSize1
= nPolyPos
<< 1;
1337 aRetPoly
= tools::Polygon( nPolyPos
, pPoints1
.get() );
1338 aRetPoly
.SetSize( nNewSize1
+ 1 );
1339 aRetPoly
[ nNewSize1
] = aRetPoly
[ 0 ];
1341 for( sal_uInt16 j
= nPolyPos
; nPolyPos
< nNewSize1
; )
1342 aRetPoly
[ nPolyPos
++ ] = pPoints2
[ --j
];
1344 if( ( fFactorX
!= 0. ) && ( fFactorY
!= 0. ) )
1345 aRetPoly
.Scale( fFactorX
, fFactorY
);
1348 Bitmap::ReleaseAccess(pAcc
);
1354 void BitmapEx::ChangeColorAlpha( sal_uInt8 cIndexFrom
, sal_Int8 nAlphaTo
)
1356 AlphaMask
aAlphaMask(GetAlphaMask());
1357 BitmapScopedWriteAccess
pAlphaWriteAccess(aAlphaMask
);
1358 Bitmap::ScopedReadAccess
pReadAccess(maBitmap
);
1359 assert( pReadAccess
.get() && pAlphaWriteAccess
.get() );
1360 if ( !(pReadAccess
.get() && pAlphaWriteAccess
.get()) )
1363 for ( tools::Long nY
= 0; nY
< pReadAccess
->Height(); nY
++ )
1365 Scanline pScanline
= pAlphaWriteAccess
->GetScanline( nY
);
1366 Scanline pScanlineRead
= pReadAccess
->GetScanline( nY
);
1367 for ( tools::Long nX
= 0; nX
< pReadAccess
->Width(); nX
++ )
1369 const sal_uInt8 cIndex
= pReadAccess
->GetPixelFromData( pScanlineRead
, nX
).GetIndex();
1370 if ( cIndex
== cIndexFrom
)
1371 pAlphaWriteAccess
->SetPixelOnData( pScanline
, nX
, BitmapColor(255 - nAlphaTo
) );
1374 *this = BitmapEx( GetBitmap(), aAlphaMask
);
1377 void BitmapEx::AdjustTransparency(sal_uInt8 cTrans
)
1383 aAlpha
= AlphaMask(GetSizePixel(), &cTrans
);
1387 aAlpha
= GetAlphaMask();
1388 BitmapScopedWriteAccess
pA(aAlpha
);
1394 sal_uLong nTrans
= cTrans
, nNewTrans
;
1395 const tools::Long nWidth
= pA
->Width(), nHeight
= pA
->Height();
1397 if( pA
->GetScanlineFormat() == ScanlineFormat::N8BitPal
)
1399 for( tools::Long nY
= 0; nY
< nHeight
; nY
++ )
1401 Scanline pAScan
= pA
->GetScanline( nY
);
1403 for( tools::Long nX
= 0; nX
< nWidth
; nX
++ )
1405 nNewTrans
= nTrans
+ *pAScan
;
1406 *pAScan
++ = static_cast<sal_uInt8
>( ( nNewTrans
& 0xffffff00 ) ? 255 : nNewTrans
);
1412 BitmapColor
aAlphaValue( 0 );
1414 for( tools::Long nY
= 0; nY
< nHeight
; nY
++ )
1416 Scanline pScanline
= pA
->GetScanline( nY
);
1417 for( tools::Long nX
= 0; nX
< nWidth
; nX
++ )
1419 nNewTrans
= nTrans
+ pA
->GetIndexFromData( pScanline
, nX
);
1420 aAlphaValue
.SetIndex( static_cast<sal_uInt8
>( ( nNewTrans
& 0xffffff00 ) ? 255 : nNewTrans
) );
1421 pA
->SetPixelOnData( pScanline
, nX
, aAlphaValue
);
1426 *this = BitmapEx( GetBitmap(), aAlpha
);
1429 void BitmapEx::CombineMaskOr(Color maskColor
, sal_uInt8 nTol
)
1431 Bitmap aNewMask
= maBitmap
.CreateMask( maskColor
, nTol
);
1433 aNewMask
.CombineOr( maAlphaMask
);
1434 maAlphaMask
= aNewMask
;
1438 * Retrieves the color model data we need for the XImageConsumer stuff.
1440 void BitmapEx::GetColorModel(css::uno::Sequence
< sal_Int32
>& rRGBPalette
,
1441 sal_uInt32
& rnRedMask
, sal_uInt32
& rnGreenMask
, sal_uInt32
& rnBlueMask
, sal_uInt32
& rnAlphaMask
, sal_uInt32
& rnTransparencyIndex
,
1442 sal_uInt32
& rnWidth
, sal_uInt32
& rnHeight
, sal_uInt8
& rnBitCount
)
1444 Bitmap::ScopedReadAccess
pReadAccess( maBitmap
);
1445 assert( pReadAccess
);
1447 if( pReadAccess
->HasPalette() )
1449 sal_uInt16 nPalCount
= pReadAccess
->GetPaletteEntryCount();
1453 rRGBPalette
= css::uno::Sequence
< sal_Int32
>( nPalCount
+ 1 );
1455 sal_Int32
* pTmp
= rRGBPalette
.getArray();
1457 for( sal_uInt32 i
= 0; i
< nPalCount
; i
++, pTmp
++ )
1459 const BitmapColor
& rCol
= pReadAccess
->GetPaletteColor( static_cast<sal_uInt16
>(i
) );
1461 *pTmp
= static_cast<sal_Int32
>(rCol
.GetRed()) << sal_Int32(24);
1462 *pTmp
|= static_cast<sal_Int32
>(rCol
.GetGreen()) << sal_Int32(16);
1463 *pTmp
|= static_cast<sal_Int32
>(rCol
.GetBlue()) << sal_Int32(8);
1464 *pTmp
|= sal_Int32(0x000000ffL
);
1469 // append transparent entry
1470 *pTmp
= sal_Int32(0xffffff00L
);
1471 rnTransparencyIndex
= nPalCount
;
1475 rnTransparencyIndex
= 0;
1480 rnRedMask
= 0xff000000UL
;
1481 rnGreenMask
= 0x00ff0000UL
;
1482 rnBlueMask
= 0x0000ff00UL
;
1483 rnAlphaMask
= 0x000000ffUL
;
1484 rnTransparencyIndex
= 0;
1487 rnWidth
= pReadAccess
->Width();
1488 rnHeight
= pReadAccess
->Height();
1489 rnBitCount
= pReadAccess
->GetBitCount();
1492 void BitmapEx::DumpAsPng(const char* pFileName
) const
1497 sPath
= OUString::fromUtf8(pFileName
);
1499 else if (const char* pEnv
= std::getenv("VCL_DUMP_BMP_PATH"))
1501 sPath
= OUString::fromUtf8(pEnv
);
1505 sPath
= "file:///tmp/bitmap.png";
1507 SvFileStream
aStream(sPath
, StreamMode::STD_READWRITE
| StreamMode::TRUNC
);
1508 assert(aStream
.good());
1509 vcl::PngImageWriter
aWriter(aStream
);
1510 aWriter
.write(*this);
1513 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */