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 assert(typeid(rMask
) != typeid(AlphaMask
)
117 && "If this mask is actually an AlphaMask, then it will be inverted unnecessarily "
118 "and the alpha channel will be wrong");
120 if( rMask
.getPixelFormat() == vcl::PixelFormat::N8_BPP
&& rMask
.HasGreyPalette8Bit() )
123 maAlphaMask
.Invert();
125 else if( rMask
.getPixelFormat() == vcl::PixelFormat::N8_BPP
)
127 BitmapEx
aMaskEx(rMask
);
128 BitmapFilter::Filter(aMaskEx
, BitmapMonochromeFilter(255));
130 maAlphaMask
= aMaskEx
.GetBitmap();
134 // convert to alpha bitmap
135 SAL_WARN( "vcl", "BitmapEx: forced mask to monochrome");
136 BitmapEx
aMaskEx(rMask
);
137 BitmapFilter::Filter(aMaskEx
, BitmapMonochromeFilter(255));
139 maAlphaMask
= aMaskEx
.GetBitmap();
142 if (!maBitmap
.IsEmpty() && maBitmap
.GetSizePixel() != maAlphaMask
.GetSizePixel())
144 OSL_ENSURE(false, "Mask size differs from Bitmap size, corrected Mask (!)");
145 maAlphaMask
.Scale(maBitmap
.GetSizePixel(), BmpScaleFlag::Fast
);
149 BitmapEx::BitmapEx( const Bitmap
& rBmp
, const AlphaMask
& rAlphaMask
) :
151 maAlphaMask ( rAlphaMask
.ImplGetBitmap() ),
152 maBitmapSize ( maBitmap
.GetSizePixel() )
154 if (!maBitmap
.IsEmpty() && !maAlphaMask
.IsEmpty() && maBitmap
.GetSizePixel() != maAlphaMask
.GetSizePixel())
156 OSL_ENSURE(false, "Alpha size differs from Bitmap size, corrected Mask (!)");
157 maAlphaMask
.Scale(rBmp
.GetSizePixel(), BmpScaleFlag::Fast
);
162 BitmapEx::BitmapEx( const Bitmap
& rBmp
, const Color
& rTransparentColor
) :
164 maBitmapSize ( maBitmap
.GetSizePixel() )
166 maAlphaMask
= maBitmap
.CreateAlphaMask( rTransparentColor
);
168 SAL_WARN_IF(rBmp
.GetSizePixel() != maAlphaMask
.GetSizePixel(), "vcl",
169 "BitmapEx::BitmapEx(): size mismatch for bitmap and alpha mask.");
173 BitmapEx
& BitmapEx::operator=( const BitmapEx
& ) = default;
175 bool BitmapEx::operator==( const BitmapEx
& rBitmapEx
) const
177 if (GetSizePixel() != rBitmapEx
.GetSizePixel())
180 if (maBitmap
!= rBitmapEx
.maBitmap
)
183 return maAlphaMask
== rBitmapEx
.maAlphaMask
;
186 bool BitmapEx::IsEmpty() const
188 return( maBitmap
.IsEmpty() && maAlphaMask
.IsEmpty() );
191 void BitmapEx::SetEmpty()
194 maAlphaMask
.SetEmpty();
197 void BitmapEx::Clear()
202 void BitmapEx::ClearAlpha()
204 maAlphaMask
.SetEmpty();
207 bool BitmapEx::IsAlpha() const
209 return !maAlphaMask
.IsEmpty();
212 const Bitmap
& BitmapEx::GetBitmap() const
217 Bitmap
BitmapEx::GetBitmap( Color aTransparentReplaceColor
) const
219 Bitmap
aRetBmp( maBitmap
);
221 if( !maAlphaMask
.IsEmpty() )
223 aRetBmp
.Replace( maAlphaMask
, aTransparentReplaceColor
);
229 sal_Int64
BitmapEx::GetSizeBytes() const
231 sal_Int64 nSizeBytes
= maBitmap
.GetSizeBytes();
233 if( !maAlphaMask
.IsEmpty() )
234 nSizeBytes
+= maAlphaMask
.GetSizeBytes();
239 BitmapChecksum
BitmapEx::GetChecksum() const
241 BitmapChecksum nCrc
= maBitmap
.GetChecksum();
243 if( !maAlphaMask
.IsEmpty() )
245 BitmapChecksumOctetArray aBCOA
;
246 BCToBCOA( maAlphaMask
.GetChecksum(), aBCOA
);
247 nCrc
= vcl_get_checksum( nCrc
, aBCOA
, BITMAP_CHECKSUM_SIZE
);
253 void BitmapEx::SetSizePixel(const Size
& rNewSize
)
255 maBitmapSize
= rNewSize
;
258 bool BitmapEx::Invert()
262 if (!maBitmap
.IsEmpty())
263 bRet
= maBitmap
.Invert();
268 bool BitmapEx::Mirror( BmpMirrorFlags nMirrorFlags
)
272 if( !maBitmap
.IsEmpty() )
274 bRet
= maBitmap
.Mirror( nMirrorFlags
);
276 if( bRet
&& !maAlphaMask
.IsEmpty() )
277 maAlphaMask
.Mirror( nMirrorFlags
);
283 bool BitmapEx::Scale( const double& rScaleX
, const double& rScaleY
, BmpScaleFlag nScaleFlag
)
287 if( !maBitmap
.IsEmpty() )
289 bRet
= maBitmap
.Scale( rScaleX
, rScaleY
, nScaleFlag
);
291 if( bRet
&& !maAlphaMask
.IsEmpty() )
293 maAlphaMask
.Scale( rScaleX
, rScaleY
, nScaleFlag
);
296 SetSizePixel(maBitmap
.GetSizePixel());
298 SAL_WARN_IF( !maAlphaMask
.IsEmpty() && maBitmap
.GetSizePixel() != maAlphaMask
.GetSizePixel(), "vcl",
299 "BitmapEx::Scale(): size mismatch for bitmap and alpha mask." );
305 bool BitmapEx::Scale( const Size
& rNewSize
, BmpScaleFlag nScaleFlag
)
309 if (GetSizePixel().Width() && GetSizePixel().Height()
310 && (rNewSize
.Width() != GetSizePixel().Width()
311 || rNewSize
.Height() != GetSizePixel().Height() ) )
313 bRet
= Scale( static_cast<double>(rNewSize
.Width()) / GetSizePixel().Width(),
314 static_cast<double>(rNewSize
.Height()) / GetSizePixel().Height(),
325 bool BitmapEx::Rotate( Degree10 nAngle10
, const Color
& rFillColor
)
329 if( !maBitmap
.IsEmpty() )
331 const bool bTransRotate
= ( COL_TRANSPARENT
== rFillColor
);
335 bRet
= maBitmap
.Rotate( nAngle10
, COL_BLACK
);
337 if( maAlphaMask
.IsEmpty() )
339 maAlphaMask
= Bitmap(GetSizePixel(), vcl::PixelFormat::N8_BPP
, &Bitmap::GetGreyPalette(256));
340 maAlphaMask
.Erase( 0 );
343 if( bRet
&& !maAlphaMask
.IsEmpty() )
344 maAlphaMask
.Rotate( nAngle10
, COL_ALPHA_TRANSPARENT
);
348 bRet
= maBitmap
.Rotate( nAngle10
, rFillColor
);
350 if( bRet
&& !maAlphaMask
.IsEmpty() )
351 maAlphaMask
.Rotate( nAngle10
, COL_ALPHA_TRANSPARENT
);
354 SetSizePixel(maBitmap
.GetSizePixel());
356 SAL_WARN_IF(!maAlphaMask
.IsEmpty() && maBitmap
.GetSizePixel() != maAlphaMask
.GetSizePixel(), "vcl",
357 "BitmapEx::Rotate(): size mismatch for bitmap and alpha mask.");
363 bool BitmapEx::Crop( const tools::Rectangle
& rRectPixel
)
367 if( !maBitmap
.IsEmpty() )
369 bRet
= maBitmap
.Crop( rRectPixel
);
371 if( bRet
&& !maAlphaMask
.IsEmpty() )
372 maAlphaMask
.Crop( rRectPixel
);
374 SetSizePixel(maBitmap
.GetSizePixel());
376 SAL_WARN_IF(!maAlphaMask
.IsEmpty() && maBitmap
.GetSizePixel() != maAlphaMask
.GetSizePixel(), "vcl",
377 "BitmapEx::Crop(): size mismatch for bitmap and alpha mask.");
383 bool BitmapEx::Convert( BmpConversion eConversion
)
385 return !maBitmap
.IsEmpty() && maBitmap
.Convert( eConversion
);
388 void BitmapEx::Expand( sal_Int32 nDX
, sal_Int32 nDY
, bool bExpandTransparent
)
392 if( maBitmap
.IsEmpty() )
395 bRet
= maBitmap
.Expand( nDX
, nDY
);
397 if( bRet
&& !maAlphaMask
.IsEmpty() )
399 Color
aColor( bExpandTransparent
? COL_ALPHA_TRANSPARENT
: COL_ALPHA_OPAQUE
);
400 maAlphaMask
.Expand( nDX
, nDY
, &aColor
);
403 SetSizePixel(maBitmap
.GetSizePixel());
405 SAL_WARN_IF(!maAlphaMask
.IsEmpty() && maBitmap
.GetSizePixel() != maAlphaMask
.GetSizePixel(), "vcl",
406 "BitmapEx::Expand(): size mismatch for bitmap and alpha mask.");
409 bool BitmapEx::CopyPixel( const tools::Rectangle
& rRectDst
, const tools::Rectangle
& rRectSrc
,
410 const BitmapEx
* pBmpExSrc
)
414 if( !pBmpExSrc
|| pBmpExSrc
->IsEmpty() )
416 if( !maBitmap
.IsEmpty() )
418 bRet
= maBitmap
.CopyPixel( rRectDst
, rRectSrc
);
420 if( bRet
&& !maAlphaMask
.IsEmpty() )
421 maAlphaMask
.CopyPixel( rRectDst
, rRectSrc
);
426 if( !maBitmap
.IsEmpty() )
428 bRet
= maBitmap
.CopyPixel( rRectDst
, rRectSrc
, &pBmpExSrc
->maBitmap
);
432 if( pBmpExSrc
->IsAlpha() )
435 // cast to use the optimized AlphaMask::CopyPixel
436 maAlphaMask
.CopyPixel_AlphaOptimized( rRectDst
, rRectSrc
, &pBmpExSrc
->maAlphaMask
);
439 sal_uInt8 nTransparencyOpaque
= 0;
440 std::optional
<AlphaMask
> pAlpha(std::in_place
, GetSizePixel(), &nTransparencyOpaque
);
442 maAlphaMask
= pAlpha
->ImplGetBitmap();
444 maAlphaMask
.CopyPixel( rRectDst
, rRectSrc
, &pBmpExSrc
->maAlphaMask
);
449 sal_uInt8 nTransparencyOpaque
= 0;
450 const AlphaMask
aAlphaSrc(pBmpExSrc
->GetSizePixel(), &nTransparencyOpaque
);
452 maAlphaMask
.CopyPixel( rRectDst
, rRectSrc
, &aAlphaSrc
.ImplGetBitmap() );
461 bool BitmapEx::Erase( const Color
& rFillColor
)
465 if( !maBitmap
.IsEmpty() )
467 bRet
= maBitmap
.Erase( rFillColor
);
469 if( bRet
&& !maAlphaMask
.IsEmpty() )
471 // Respect transparency on fill color
472 if( rFillColor
.IsTransparent() )
473 maAlphaMask
.Erase( 255 - rFillColor
.GetAlpha() );
475 maAlphaMask
.Erase( 0 );
482 void BitmapEx::Replace( const Color
& rSearchColor
, const Color
& rReplaceColor
)
484 if (!maBitmap
.IsEmpty())
485 maBitmap
.Replace( rSearchColor
, rReplaceColor
);
488 void BitmapEx::Replace( const Color
* pSearchColors
, const Color
* pReplaceColors
, size_t nColorCount
)
490 if (!maBitmap
.IsEmpty())
491 maBitmap
.Replace( pSearchColors
, pReplaceColors
, nColorCount
, /*pTols*/nullptr );
494 bool BitmapEx::Adjust( short nLuminancePercent
, short nContrastPercent
,
495 short nChannelRPercent
, short nChannelGPercent
, short nChannelBPercent
,
496 double fGamma
, bool bInvert
, bool msoBrightness
)
498 return !maBitmap
.IsEmpty() && maBitmap
.Adjust( nLuminancePercent
, nContrastPercent
,
499 nChannelRPercent
, nChannelGPercent
, nChannelBPercent
,
500 fGamma
, bInvert
, msoBrightness
);
503 void BitmapEx::Draw( OutputDevice
* pOutDev
, const Point
& rDestPt
) const
505 pOutDev
->DrawBitmapEx( rDestPt
, *this );
508 void BitmapEx::Draw( OutputDevice
* pOutDev
,
509 const Point
& rDestPt
, const Size
& rDestSize
) const
511 pOutDev
->DrawBitmapEx( rDestPt
, rDestSize
, *this );
514 BitmapEx
BitmapEx:: AutoScaleBitmap(BitmapEx
const & aBitmap
, const tools::Long aStandardSize
)
516 Point
aEmptyPoint(0,0);
519 BitmapEx aRet
= aBitmap
;
520 double imgOldWidth
= aRet
.GetSizePixel().Width();
521 double imgOldHeight
= aRet
.GetSizePixel().Height();
523 if (imgOldWidth
>= aStandardSize
|| imgOldHeight
>= aStandardSize
)
525 sal_Int32 imgNewWidth
= 0;
526 sal_Int32 imgNewHeight
= 0;
527 if (imgOldWidth
>= imgOldHeight
)
529 imgNewWidth
= aStandardSize
;
530 imgNewHeight
= sal_Int32(imgOldHeight
/ (imgOldWidth
/ aStandardSize
) + 0.5);
532 imgposY
= (aStandardSize
- (imgOldHeight
/ (imgOldWidth
/ aStandardSize
) + 0.5)) / 2 + 0.5;
536 imgNewHeight
= aStandardSize
;
537 imgNewWidth
= sal_Int32(imgOldWidth
/ (imgOldHeight
/ aStandardSize
) + 0.5);
539 imgposX
= (aStandardSize
- (imgOldWidth
/ (imgOldHeight
/ aStandardSize
) + 0.5)) / 2 + 0.5;
542 Size
aScaledSize( imgNewWidth
, imgNewHeight
);
543 aRet
.Scale( aScaledSize
, BmpScaleFlag::BestQuality
);
547 imgposX
= (aStandardSize
- imgOldWidth
) / 2 + 0.5;
548 imgposY
= (aStandardSize
- imgOldHeight
) / 2 + 0.5;
551 Size
aStdSize( aStandardSize
, aStandardSize
);
552 tools::Rectangle
aRect(aEmptyPoint
, aStdSize
);
554 ScopedVclPtrInstance
< VirtualDevice
> aVirDevice(*Application::GetDefaultDevice());
555 aVirDevice
->SetOutputSizePixel( aStdSize
);
556 aVirDevice
->SetFillColor( COL_TRANSPARENT
);
557 aVirDevice
->SetLineColor( COL_TRANSPARENT
);
559 // Draw a rect into virDevice
560 aVirDevice
->DrawRect( aRect
);
561 Point
aPointPixel( static_cast<tools::Long
>(imgposX
), static_cast<tools::Long
>(imgposY
) );
562 aVirDevice
->DrawBitmapEx( aPointPixel
, aRet
);
563 aRet
= aVirDevice
->GetBitmapEx( aEmptyPoint
, aStdSize
);
568 sal_uInt8
BitmapEx::GetAlpha(sal_Int32 nX
, sal_Int32 nY
) const
570 if(maBitmap
.IsEmpty())
573 if (nX
< 0 || nX
>= GetSizePixel().Width() || nY
< 0 || nY
>= GetSizePixel().Height())
576 if (maBitmap
.getPixelFormat() == vcl::PixelFormat::N32_BPP
)
577 return GetPixelColor(nX
, nY
).GetAlpha();
580 if (maAlphaMask
.IsEmpty())
582 // Not transparent, ergo all covered
587 Bitmap
aTestBitmap(maAlphaMask
);
588 Bitmap::ScopedReadAccess
pRead(aTestBitmap
);
592 const BitmapColor
aBitmapColor(pRead
->GetPixel(nY
, nX
));
593 nAlpha
= aBitmapColor
.GetIndex();
600 Color
BitmapEx::GetPixelColor(sal_Int32 nX
, sal_Int32 nY
) const
602 Bitmap::ScopedReadAccess
pReadAccess( const_cast<Bitmap
&>(maBitmap
) );
605 BitmapColor aColor
= pReadAccess
->GetColor(nY
, nX
);
609 AlphaMask aAlpha
= GetAlphaMask();
610 AlphaMask::ScopedReadAccess
pAlphaReadAccess(aAlpha
);
611 aColor
.SetAlpha(pAlphaReadAccess
->GetPixel(nY
, nX
).GetIndex());
613 else if (maBitmap
.getPixelFormat() != vcl::PixelFormat::N32_BPP
)
615 aColor
.SetAlpha(255);
620 // Shift alpha transparent pixels between cppcanvas/ implementations
621 // and vcl in a generally grotesque and under-performing fashion
622 bool BitmapEx::Create( const css::uno::Reference
< css::rendering::XBitmapCanvas
> &xBitmapCanvas
,
625 uno::Reference
< beans::XFastPropertySet
> xFastPropertySet( xBitmapCanvas
, uno::UNO_QUERY
);
626 if( xFastPropertySet
)
628 // 0 means get BitmapEx
629 uno::Any aAny
= xFastPropertySet
->getFastPropertyValue( 0 );
630 std::unique_ptr
<BitmapEx
> xBitmapEx(reinterpret_cast<BitmapEx
*>(*o3tl::doAccess
<sal_Int64
>(aAny
)));
638 std::shared_ptr
<SalBitmap
> pSalBmp
;
639 std::shared_ptr
<SalBitmap
> pSalMask
;
641 pSalBmp
= ImplGetSVData()->mpDefInst
->CreateSalBitmap();
643 Size
aLocalSize(rSize
);
644 if( pSalBmp
->Create( xBitmapCanvas
, aLocalSize
) )
646 pSalMask
= ImplGetSVData()->mpDefInst
->CreateSalBitmap();
647 if ( pSalMask
->Create( xBitmapCanvas
, aLocalSize
, true ) )
649 *this = BitmapEx(Bitmap(pSalBmp
), Bitmap(pSalMask
) );
654 *this = BitmapEx(Bitmap(pSalBmp
));
664 Bitmap
impTransformBitmap(
665 const Bitmap
& rSource
,
666 const Size
& rDestinationSize
,
667 const basegfx::B2DHomMatrix
& rTransform
,
670 Bitmap
aDestination(rDestinationSize
, vcl::PixelFormat::N24_BPP
);
671 BitmapScopedWriteAccess
xWrite(aDestination
);
675 Bitmap::ScopedReadAccess
xRead(const_cast< Bitmap
& >(rSource
));
679 const Size
aDestinationSizePixel(aDestination
.GetSizePixel());
681 // tdf#157795 set color to black outside of of bitmap bounds
682 // Due to commit 81994cb2b8b32453a92bcb011830fcb884f22ff3,
683 // transparent areas are now black instead of white.
684 const BitmapColor
aOutside(0x0, 0x0, 0x0);
686 for(tools::Long
y(0); y
< aDestinationSizePixel
.getHeight(); y
++)
688 Scanline pScanline
= xWrite
->GetScanline( y
);
689 for(tools::Long
x(0); x
< aDestinationSizePixel
.getWidth(); x
++)
691 const basegfx::B2DPoint
aSourceCoor(rTransform
* basegfx::B2DPoint(x
, y
));
695 xWrite
->SetPixelOnData(
698 xRead
->GetInterpolatedColorWithFallback(
705 // this version does the correct <= 0.0 checks, so no need
706 // to do the static_cast< sal_Int32 > self and make an error
707 xWrite
->SetPixelOnData(
710 xRead
->GetColorWithFallback(
721 rSource
.AdaptBitCount(aDestination
);
726 /// Decides if rTransformation needs smoothing or not (e.g. 180 deg rotation doesn't need it).
727 bool implTransformNeedsSmooth(const basegfx::B2DHomMatrix
& rTransformation
)
729 basegfx::B2DVector aScale
, aTranslate
;
730 double fRotate
, fShearX
;
731 rTransformation
.decompose(aScale
, aTranslate
, fRotate
, fShearX
);
732 if (aScale
!= basegfx::B2DVector(1, 1))
737 fRotate
= fmod( fRotate
, 2 * M_PI
);
742 if (!rtl::math::approxEqual(fRotate
, 0)
743 && !rtl::math::approxEqual(fRotate
, M_PI_2
)
744 && !rtl::math::approxEqual(fRotate
, M_PI
)
745 && !rtl::math::approxEqual(fRotate
, 3 * M_PI_2
))
750 if (!rtl::math::approxEqual(fShearX
, 0))
757 } // end of anonymous namespace
759 BitmapEx
BitmapEx::TransformBitmapEx(
762 const basegfx::B2DHomMatrix
& rTransformation
) const
764 if(fWidth
<= 1 || fHeight
<= 1)
767 // force destination to 24 bit, we want to smooth output
768 const Size
aDestinationSize(basegfx::fround(fWidth
), basegfx::fround(fHeight
));
769 bool bSmooth
= implTransformNeedsSmooth(rTransformation
);
770 const Bitmap
aDestination(impTransformBitmap(GetBitmap(), aDestinationSize
, rTransformation
, bSmooth
));
775 const Bitmap
aAlpha(impTransformBitmap(GetAlphaMask().GetBitmap(), aDestinationSize
, rTransformation
, bSmooth
));
776 return BitmapEx(aDestination
, AlphaMask(aAlpha
));
779 return BitmapEx(aDestination
);
782 BitmapEx
BitmapEx::getTransformed(
783 const basegfx::B2DHomMatrix
& rTransformation
,
784 const basegfx::B2DRange
& rVisibleRange
,
785 double fMaximumArea
) const
792 const sal_uInt32
nSourceWidth(GetSizePixel().Width());
793 const sal_uInt32
nSourceHeight(GetSizePixel().Height());
795 if(!nSourceWidth
|| !nSourceHeight
)
799 basegfx::B2DRange
aOutlineRange(0.0, 0.0, 1.0, 1.0);
801 aOutlineRange
.transform(rTransformation
);
803 // create visible range from it by moving from relative to absolute
804 basegfx::B2DRange
aVisibleRange(rVisibleRange
);
806 aVisibleRange
.transform(
807 basegfx::utils::createScaleTranslateB2DHomMatrix(
808 aOutlineRange
.getRange(),
809 aOutlineRange
.getMinimum()));
811 // get target size (which is visible range's size)
812 double fWidth(aVisibleRange
.getWidth());
813 double fHeight(aVisibleRange
.getHeight());
815 if(fWidth
< 1.0 || fHeight
< 1.0)
820 // test if discrete size (pixel) maybe too big and limit it
821 const double fArea(fWidth
* fHeight
);
822 const bool bNeedToReduce(basegfx::fTools::more(fArea
, fMaximumArea
));
823 double fReduceFactor(1.0);
827 fReduceFactor
= sqrt(fMaximumArea
/ fArea
);
828 fWidth
*= fReduceFactor
;
829 fHeight
*= fReduceFactor
;
832 // Build complete transform from source pixels to target pixels.
833 // Start by scaling from source pixel size to unit coordinates
834 basegfx::B2DHomMatrix
aTransform(
835 basegfx::utils::createScaleB2DHomMatrix(
837 1.0 / nSourceHeight
));
839 // multiply with given transform which leads from unit coordinates inside
841 aTransform
= rTransformation
* aTransform
;
843 // subtract top-left of absolute VisibleRange
844 aTransform
.translate(
845 -aVisibleRange
.getMinX(),
846 -aVisibleRange
.getMinY());
848 // scale to target pixels (if needed)
851 aTransform
.scale(fReduceFactor
, fReduceFactor
);
854 // invert to get transformation from target pixel coordinates to source pixels
857 // create bitmap using source, destination and linear back-transformation
858 aRetval
= TransformBitmapEx(fWidth
, fHeight
, aTransform
);
863 BitmapEx
BitmapEx::ModifyBitmapEx(const basegfx::BColorModifierStack
& rBColorModifierStack
) const
865 Bitmap
aChangedBitmap(GetBitmap());
868 for(sal_uInt32
a(rBColorModifierStack
.count()); a
&& !bDone
; )
870 const basegfx::BColorModifierSharedPtr
& rModifier
= rBColorModifierStack
.getBColorModifier(--a
);
871 const basegfx::BColorModifier_replace
* pReplace
= dynamic_cast< const basegfx::BColorModifier_replace
* >(rModifier
.get());
878 // clear bitmap with dest color
879 if (vcl::isPalettePixelFormat(aChangedBitmap
.getPixelFormat()))
881 // For e.g. 8bit Bitmaps, the nearest color to the given erase color is
882 // determined and used -> this may be different from what is wanted here.
883 // Better create a new bitmap with the needed color explicitly.
884 Bitmap::ScopedReadAccess
xReadAccess(aChangedBitmap
);
885 OSL_ENSURE(xReadAccess
, "Got no Bitmap ReadAccess ?!?");
889 BitmapPalette
aNewPalette(xReadAccess
->GetPalette());
890 aNewPalette
[0] = BitmapColor(Color(pReplace
->getBColor()));
891 aChangedBitmap
= Bitmap(
892 aChangedBitmap
.GetSizePixel(),
893 aChangedBitmap
.getPixelFormat(),
897 aChangedBitmap
.Erase(Color(pReplace
->getBColor()));
901 // erase bitmap, caller will know to paint direct
902 aChangedBitmap
.SetEmpty();
909 BitmapScopedWriteAccess
xContent(aChangedBitmap
);
913 const double fConvertColor(1.0 / 255.0);
915 if(xContent
->HasPalette())
917 const sal_uInt16
nCount(xContent
->GetPaletteEntryCount());
919 for(sal_uInt16
b(0); b
< nCount
; b
++)
921 const BitmapColor
& rCol
= xContent
->GetPaletteColor(b
);
922 const basegfx::BColor
aBSource(
923 rCol
.GetRed() * fConvertColor
,
924 rCol
.GetGreen() * fConvertColor
,
925 rCol
.GetBlue() * fConvertColor
);
926 const basegfx::BColor
aBDest(rModifier
->getModifiedColor(aBSource
));
927 xContent
->SetPaletteColor(b
, BitmapColor(Color(aBDest
)));
930 else if(ScanlineFormat::N24BitTcBgr
== xContent
->GetScanlineFormat())
932 for(tools::Long
y(0); y
< xContent
->Height(); y
++)
934 Scanline pScan
= xContent
->GetScanline(y
);
936 for(tools::Long
x(0); x
< xContent
->Width(); x
++)
938 const basegfx::BColor
aBSource(
939 *(pScan
+ 2)* fConvertColor
,
940 *(pScan
+ 1) * fConvertColor
,
941 *pScan
* fConvertColor
);
942 const basegfx::BColor
aBDest(rModifier
->getModifiedColor(aBSource
));
943 *pScan
++ = static_cast< sal_uInt8
>(aBDest
.getBlue() * 255.0);
944 *pScan
++ = static_cast< sal_uInt8
>(aBDest
.getGreen() * 255.0);
945 *pScan
++ = static_cast< sal_uInt8
>(aBDest
.getRed() * 255.0);
949 else if(ScanlineFormat::N24BitTcRgb
== xContent
->GetScanlineFormat())
951 for(tools::Long
y(0); y
< xContent
->Height(); y
++)
953 Scanline pScan
= xContent
->GetScanline(y
);
955 for(tools::Long
x(0); x
< xContent
->Width(); x
++)
957 const basegfx::BColor
aBSource(
958 *pScan
* fConvertColor
,
959 *(pScan
+ 1) * fConvertColor
,
960 *(pScan
+ 2) * fConvertColor
);
961 const basegfx::BColor
aBDest(rModifier
->getModifiedColor(aBSource
));
962 *pScan
++ = static_cast< sal_uInt8
>(aBDest
.getRed() * 255.0);
963 *pScan
++ = static_cast< sal_uInt8
>(aBDest
.getGreen() * 255.0);
964 *pScan
++ = static_cast< sal_uInt8
>(aBDest
.getBlue() * 255.0);
970 for(tools::Long
y(0); y
< xContent
->Height(); y
++)
972 Scanline pScanline
= xContent
->GetScanline( y
);
973 for(tools::Long
x(0); x
< xContent
->Width(); x
++)
975 const BitmapColor
aBMCol(xContent
->GetColor(y
, x
));
976 const basegfx::BColor
aBSource(
977 static_cast<double>(aBMCol
.GetRed()) * fConvertColor
,
978 static_cast<double>(aBMCol
.GetGreen()) * fConvertColor
,
979 static_cast<double>(aBMCol
.GetBlue()) * fConvertColor
);
980 const basegfx::BColor
aBDest(rModifier
->getModifiedColor(aBSource
));
982 xContent
->SetPixelOnData(pScanline
, x
, BitmapColor(Color(aBDest
)));
990 if(aChangedBitmap
.IsEmpty())
998 return BitmapEx(aChangedBitmap
, GetAlphaMask());
1002 return BitmapEx(aChangedBitmap
);
1007 BitmapEx
createBlendFrame(
1010 Color aColorTopLeft
,
1011 Color aColorBottomRight
)
1013 const sal_uInt32
nW(rSize
.Width());
1014 const sal_uInt32
nH(rSize
.Height());
1018 Color
aColTopRight(aColorTopLeft
);
1019 Color
aColBottomLeft(aColorTopLeft
);
1020 const sal_uInt32
nDE(nW
+ nH
);
1022 aColTopRight
.Merge(aColorBottomRight
, 255 - sal_uInt8((nW
* 255) / nDE
));
1023 aColBottomLeft
.Merge(aColorBottomRight
, 255 - sal_uInt8((nH
* 255) / nDE
));
1025 return createBlendFrame(rSize
, nAlpha
, aColorTopLeft
, aColTopRight
, aColorBottomRight
, aColBottomLeft
);
1031 BitmapEx
createBlendFrame(
1034 Color aColorTopLeft
,
1035 Color aColorTopRight
,
1036 Color aColorBottomRight
,
1037 Color aColorBottomLeft
)
1039 // FIXME the call sites are actually passing in transparency
1040 nAlpha
= 255 - nAlpha
;
1041 BlendFrameCache
* pBlendFrameCache
= ImplGetBlendFrameCache();
1043 if(pBlendFrameCache
->m_aLastSize
== rSize
1044 && pBlendFrameCache
->m_nLastAlpha
== nAlpha
1045 && pBlendFrameCache
->m_aLastColorTopLeft
== aColorTopLeft
1046 && pBlendFrameCache
->m_aLastColorTopRight
== aColorTopRight
1047 && pBlendFrameCache
->m_aLastColorBottomRight
== aColorBottomRight
1048 && pBlendFrameCache
->m_aLastColorBottomLeft
== aColorBottomLeft
)
1050 return pBlendFrameCache
->m_aLastResult
;
1053 pBlendFrameCache
->m_aLastSize
= rSize
;
1054 pBlendFrameCache
->m_nLastAlpha
= nAlpha
;
1055 pBlendFrameCache
->m_aLastColorTopLeft
= aColorTopLeft
;
1056 pBlendFrameCache
->m_aLastColorTopRight
= aColorTopRight
;
1057 pBlendFrameCache
->m_aLastColorBottomRight
= aColorBottomRight
;
1058 pBlendFrameCache
->m_aLastColorBottomLeft
= aColorBottomLeft
;
1059 pBlendFrameCache
->m_aLastResult
.Clear();
1061 const tools::Long
nW(rSize
.Width());
1062 const tools::Long
nH(rSize
.Height());
1064 if(nW
> 1 && nH
> 1)
1066 sal_uInt8
aEraseTrans(0xff);
1067 Bitmap
aContent(rSize
, vcl::PixelFormat::N24_BPP
);
1068 AlphaMask
aAlpha(rSize
, &aEraseTrans
);
1070 aContent
.Erase(COL_BLACK
);
1072 BitmapScopedWriteAccess
pContent(aContent
);
1073 AlphaScopedWriteAccess
pAlpha(aAlpha
);
1075 if(pContent
&& pAlpha
)
1079 Scanline pScanContent
= pContent
->GetScanline( 0 );
1080 Scanline pScanAlpha
= pContent
->GetScanline( 0 );
1082 // x == 0, y == 0, top-left corner
1083 pContent
->SetPixelOnData(pScanContent
, 0, aColorTopLeft
);
1084 pAlpha
->SetPixelOnData(pScanAlpha
, 0, BitmapColor(nAlpha
));
1086 // y == 0, top line left to right
1087 for(x
= 1; x
< nW
- 1; x
++)
1089 Color
aMix(aColorTopLeft
);
1091 aMix
.Merge(aColorTopRight
, 255 - sal_uInt8((x
* 255) / nW
));
1092 pContent
->SetPixelOnData(pScanContent
, x
, aMix
);
1093 pAlpha
->SetPixelOnData(pScanAlpha
, x
, BitmapColor(nAlpha
));
1096 // x == nW - 1, y == 0, top-right corner
1097 // #i123690# Caution! When nW is 1, x == nW is possible (!)
1100 pContent
->SetPixelOnData(pScanContent
, x
, aColorTopRight
);
1101 pAlpha
->SetPixelOnData(pScanAlpha
, x
, BitmapColor(nAlpha
));
1104 // x == 0 and nW - 1, left and right line top-down
1105 for(y
= 1; y
< nH
- 1; y
++)
1107 pScanContent
= pContent
->GetScanline( y
);
1108 pScanAlpha
= pContent
->GetScanline( y
);
1109 Color
aMixA(aColorTopLeft
);
1111 aMixA
.Merge(aColorBottomLeft
, 255 - sal_uInt8((y
* 255) / nH
));
1112 pContent
->SetPixelOnData(pScanContent
, 0, aMixA
);
1113 pAlpha
->SetPixelOnData(pScanAlpha
, 0, BitmapColor(nAlpha
));
1115 // #i123690# Caution! When nW is 1, x == nW is possible (!)
1118 Color
aMixB(aColorTopRight
);
1120 aMixB
.Merge(aColorBottomRight
, 255 - sal_uInt8((y
* 255) / nH
));
1121 pContent
->SetPixelOnData(pScanContent
, x
, aMixB
);
1122 pAlpha
->SetPixelOnData(pScanAlpha
, x
, BitmapColor(nAlpha
));
1126 // #i123690# Caution! When nH is 1, y == nH is possible (!)
1129 // x == 0, y == nH - 1, bottom-left corner
1130 pContent
->SetPixelOnData(pScanContent
, 0, aColorBottomLeft
);
1131 pAlpha
->SetPixelOnData(pScanAlpha
, 0, BitmapColor(nAlpha
));
1133 // y == nH - 1, bottom line left to right
1134 for(x
= 1; x
< nW
- 1; x
++)
1136 Color
aMix(aColorBottomLeft
);
1138 aMix
.Merge(aColorBottomRight
, 255 - sal_uInt8(((x
- 0)* 255) / nW
));
1139 pContent
->SetPixelOnData(pScanContent
, x
, aMix
);
1140 pAlpha
->SetPixelOnData(pScanAlpha
, x
, BitmapColor(nAlpha
));
1143 // x == nW - 1, y == nH - 1, bottom-right corner
1144 // #i123690# Caution! When nW is 1, x == nW is possible (!)
1147 pContent
->SetPixelOnData(pScanContent
, x
, aColorBottomRight
);
1148 pAlpha
->SetPixelOnData(pScanAlpha
, x
, BitmapColor(nAlpha
));
1155 pBlendFrameCache
->m_aLastResult
= BitmapEx(aContent
, aAlpha
);
1159 return pBlendFrameCache
->m_aLastResult
;
1162 void BitmapEx::Replace(const Color
& rSearchColor
,
1163 const Color
& rReplaceColor
,
1164 sal_uInt8 nTolerance
)
1166 maBitmap
.Replace(rSearchColor
, rReplaceColor
, nTolerance
);
1169 void BitmapEx::Replace( const Color
* pSearchColors
,
1170 const Color
* pReplaceColors
,
1172 sal_uInt8
const * pTols
)
1174 maBitmap
.Replace( pSearchColors
, pReplaceColors
, nColorCount
, pTols
);
1177 void BitmapEx::ReplaceTransparency(const Color
& rColor
)
1181 maBitmap
.Replace( GetAlphaMask(), rColor
);
1182 maAlphaMask
= Bitmap();
1183 maBitmapSize
= maBitmap
.GetSizePixel();
1187 static Bitmap
DetectEdges( const Bitmap
& rBmp
)
1189 constexpr sal_uInt8 cEdgeDetectThreshold
= 128;
1190 const Size
aSize( rBmp
.GetSizePixel() );
1192 if( ( aSize
.Width() <= 2 ) || ( aSize
.Height() <= 2 ) )
1195 Bitmap
aWorkBmp( rBmp
);
1197 if( !aWorkBmp
.Convert( BmpConversion::N8BitGreys
) )
1200 ScopedVclPtr
<VirtualDevice
> pVirDev(VclPtr
<VirtualDevice
>::Create());
1201 pVirDev
->SetOutputSizePixel(aSize
);
1202 Bitmap::ScopedReadAccess
pReadAcc(aWorkBmp
);
1206 const tools::Long nWidth
= aSize
.Width();
1207 const tools::Long nWidth2
= nWidth
- 2;
1208 const tools::Long nHeight
= aSize
.Height();
1209 const tools::Long nHeight2
= nHeight
- 2;
1210 const tools::Long lThres2
= static_cast<tools::Long
>(cEdgeDetectThreshold
) * cEdgeDetectThreshold
;
1215 // initialize border with white pixels
1216 pVirDev
->SetLineColor( COL_WHITE
);
1217 pVirDev
->DrawLine( Point(), Point( nWidth
- 1, 0L ) );
1218 pVirDev
->DrawLine( Point( nWidth
- 1, 0L ), Point( nWidth
- 1, nHeight
- 1 ) );
1219 pVirDev
->DrawLine( Point( nWidth
- 1, nHeight
- 1 ), Point( 0L, nHeight
- 1 ) );
1220 pVirDev
->DrawLine( Point( 0, nHeight
- 1 ), Point() );
1222 for( tools::Long nY
= 0, nY1
= 1, nY2
= 2; nY
< nHeight2
; nY
++, nY1
++, nY2
++ )
1224 Scanline pScanlineRead
= pReadAcc
->GetScanline( nY
);
1225 Scanline pScanlineRead1
= pReadAcc
->GetScanline( nY1
);
1226 Scanline pScanlineRead2
= pReadAcc
->GetScanline( nY2
);
1227 for( tools::Long nX
= 0, nXDst
= 1, nXTmp
; nX
< nWidth2
; nX
++, nXDst
++ )
1231 nSum2
= pReadAcc
->GetIndexFromData( pScanlineRead
, nXTmp
++ );
1233 nSum2
+= static_cast<tools::Long
>(pReadAcc
->GetIndexFromData( pScanlineRead
, nXTmp
++ )) << 1;
1234 lGray
= pReadAcc
->GetIndexFromData( pScanlineRead
, nXTmp
);
1238 nSum1
+= static_cast<tools::Long
>(pReadAcc
->GetIndexFromData( pScanlineRead1
, nXTmp
)) << 1;
1240 nSum1
-= static_cast<tools::Long
>(pReadAcc
->GetIndexFromData( pScanlineRead1
, nXTmp
)) << 1;
1242 lGray
= -static_cast<tools::Long
>(pReadAcc
->GetIndexFromData( pScanlineRead2
, nXTmp
++ ));
1245 nSum2
-= static_cast<tools::Long
>(pReadAcc
->GetIndexFromData( pScanlineRead2
, nXTmp
++ )) << 1;
1246 lGray
= static_cast<tools::Long
>(pReadAcc
->GetIndexFromData( pScanlineRead2
, nXTmp
));
1250 if( ( nSum1
* nSum1
+ nSum2
* nSum2
) < lThres2
)
1251 pVirDev
->DrawPixel( Point(nXDst
, nY
), COL_WHITE
);
1253 pVirDev
->DrawPixel( Point(nXDst
, nY
), COL_BLACK
);
1259 Bitmap aRetBmp
= pVirDev
->GetBitmap(Point(0,0), aSize
);
1261 if( aRetBmp
.IsEmpty() )
1265 aRetBmp
.SetPrefMapMode( rBmp
.GetPrefMapMode() );
1266 aRetBmp
.SetPrefSize( rBmp
.GetPrefSize() );
1272 /** Get contours in image */
1273 tools::Polygon
BitmapEx::GetContour( bool bContourEdgeDetect
,
1274 const tools::Rectangle
* pWorkRectPixel
)
1277 tools::Polygon aRetPoly
;
1278 tools::Rectangle
aWorkRect( Point(), maBitmap
.GetSizePixel() );
1280 if( pWorkRectPixel
)
1281 aWorkRect
.Intersection( *pWorkRectPixel
);
1283 aWorkRect
.Normalize();
1285 if( ( aWorkRect
.GetWidth() > 4 ) && ( aWorkRect
.GetHeight() > 4 ) )
1287 // if the flag is set, we need to detect edges
1288 if( bContourEdgeDetect
)
1289 aWorkBmp
= DetectEdges( maBitmap
);
1291 aWorkBmp
= maBitmap
;
1293 BitmapReadAccess
* pAcc
= aWorkBmp
.AcquireReadAccess();
1295 const tools::Long nWidth
= pAcc
? pAcc
->Width() : 0;
1296 const tools::Long nHeight
= pAcc
? pAcc
->Height() : 0;
1298 if (pAcc
&& nWidth
&& nHeight
)
1300 const Size
& rPrefSize
= aWorkBmp
.GetPrefSize();
1301 const double fFactorX
= static_cast<double>(rPrefSize
.Width()) / nWidth
;
1302 const double fFactorY
= static_cast<double>(rPrefSize
.Height()) / nHeight
;
1303 const tools::Long nStartX1
= aWorkRect
.Left() + 1;
1304 const tools::Long nEndX1
= aWorkRect
.Right();
1305 const tools::Long nStartX2
= nEndX1
- 1;
1306 const tools::Long nStartY1
= aWorkRect
.Top() + 1;
1307 const tools::Long nEndY1
= aWorkRect
.Bottom();
1308 std::unique_ptr
<Point
[]> pPoints1
;
1309 std::unique_ptr
<Point
[]> pPoints2
;
1311 sal_uInt16 nPolyPos
= 0;
1312 const BitmapColor aBlack
= pAcc
->GetBestMatchingColor( COL_BLACK
);
1314 pPoints1
.reset(new Point
[ nHeight
]);
1315 pPoints2
.reset(new Point
[ nHeight
]);
1317 for ( nY
= nStartY1
; nY
< nEndY1
; nY
++ )
1320 Scanline pScanline
= pAcc
->GetScanline( nY
);
1322 // scan row from left to right
1323 while( nX
< nEndX1
)
1325 if( aBlack
== pAcc
->GetPixelFromData( pScanline
, nX
) )
1327 pPoints1
[ nPolyPos
] = Point( nX
, nY
);
1330 // this loop always breaks eventually as there is at least one pixel
1333 if( aBlack
== pAcc
->GetPixelFromData( pScanline
, nX
) )
1335 pPoints2
[ nPolyPos
] = Point( nX
, nY
);
1350 const sal_uInt16 nNewSize1
= nPolyPos
<< 1;
1352 aRetPoly
= tools::Polygon( nPolyPos
, pPoints1
.get() );
1353 aRetPoly
.SetSize( nNewSize1
+ 1 );
1354 aRetPoly
[ nNewSize1
] = aRetPoly
[ 0 ];
1356 for( sal_uInt16 j
= nPolyPos
; nPolyPos
< nNewSize1
; )
1357 aRetPoly
[ nPolyPos
++ ] = pPoints2
[ --j
];
1359 if( ( fFactorX
!= 0. ) && ( fFactorY
!= 0. ) )
1360 aRetPoly
.Scale( fFactorX
, fFactorY
);
1363 Bitmap::ReleaseAccess(pAcc
);
1369 void BitmapEx::ChangeColorAlpha( sal_uInt8 cIndexFrom
, sal_Int8 nAlphaTo
)
1371 AlphaMask
aAlphaMask(GetAlphaMask());
1372 BitmapScopedWriteAccess
pAlphaWriteAccess(aAlphaMask
);
1373 Bitmap::ScopedReadAccess
pReadAccess(maBitmap
);
1374 assert( pReadAccess
.get() && pAlphaWriteAccess
.get() );
1375 if ( !(pReadAccess
.get() && pAlphaWriteAccess
.get()) )
1378 for ( tools::Long nY
= 0; nY
< pReadAccess
->Height(); nY
++ )
1380 Scanline pScanline
= pAlphaWriteAccess
->GetScanline( nY
);
1381 Scanline pScanlineRead
= pReadAccess
->GetScanline( nY
);
1382 for ( tools::Long nX
= 0; nX
< pReadAccess
->Width(); nX
++ )
1384 const sal_uInt8 cIndex
= pReadAccess
->GetPixelFromData( pScanlineRead
, nX
).GetIndex();
1385 if ( cIndex
== cIndexFrom
)
1386 pAlphaWriteAccess
->SetPixelOnData( pScanline
, nX
, BitmapColor(nAlphaTo
) );
1389 *this = BitmapEx( GetBitmap(), aAlphaMask
);
1392 void BitmapEx::AdjustTransparency(sal_uInt8 cTrans
)
1398 aAlpha
= AlphaMask(GetSizePixel(), &cTrans
);
1402 aAlpha
= GetAlphaMask();
1403 BitmapScopedWriteAccess
pA(aAlpha
);
1409 sal_uLong nTrans
= cTrans
;
1410 const tools::Long nWidth
= pA
->Width(), nHeight
= pA
->Height();
1412 if( pA
->GetScanlineFormat() == ScanlineFormat::N8BitPal
)
1414 for( tools::Long nY
= 0; nY
< nHeight
; nY
++ )
1416 Scanline pAScan
= pA
->GetScanline( nY
);
1418 for( tools::Long nX
= 0; nX
< nWidth
; nX
++ )
1420 sal_uLong nNewTrans
= nTrans
+ (255 - *pAScan
);
1422 nNewTrans
= ( nNewTrans
& 0xffffff00 ) ? 255 : nNewTrans
;
1423 *pAScan
++ = static_cast<sal_uInt8
>( 255 - nNewTrans
);
1429 BitmapColor
aAlphaValue( 0 );
1431 for( tools::Long nY
= 0; nY
< nHeight
; nY
++ )
1433 Scanline pScanline
= pA
->GetScanline( nY
);
1434 for( tools::Long nX
= 0; nX
< nWidth
; nX
++ )
1436 sal_uLong nNewTrans
= nTrans
+ (255 - pA
->GetIndexFromData( pScanline
, nX
));
1438 nNewTrans
= ( nNewTrans
& 0xffffff00 ) ? 255 : nNewTrans
;
1439 // convert back to alpha
1440 aAlphaValue
.SetIndex( static_cast<sal_uInt8
>(255 - nNewTrans
) );
1441 pA
->SetPixelOnData( pScanline
, nX
, aAlphaValue
);
1446 *this = BitmapEx( GetBitmap(), aAlpha
);
1449 void BitmapEx::CombineMaskOr(Color maskColor
, sal_uInt8 nTol
)
1451 AlphaMask aNewMask
= maBitmap
.CreateAlphaMask( maskColor
, nTol
);
1453 aNewMask
.AlphaCombineOr( maAlphaMask
);
1454 maAlphaMask
= aNewMask
;
1458 * Retrieves the color model data we need for the XImageConsumer stuff.
1460 void BitmapEx::GetColorModel(css::uno::Sequence
< sal_Int32
>& rRGBPalette
,
1461 sal_uInt32
& rnRedMask
, sal_uInt32
& rnGreenMask
, sal_uInt32
& rnBlueMask
, sal_uInt32
& rnAlphaMask
, sal_uInt32
& rnTransparencyIndex
,
1462 sal_uInt32
& rnWidth
, sal_uInt32
& rnHeight
, sal_uInt8
& rnBitCount
)
1464 Bitmap::ScopedReadAccess
pReadAccess( maBitmap
);
1465 assert( pReadAccess
);
1467 if( pReadAccess
->HasPalette() )
1469 sal_uInt16 nPalCount
= pReadAccess
->GetPaletteEntryCount();
1473 rRGBPalette
= css::uno::Sequence
< sal_Int32
>( nPalCount
+ 1 );
1475 sal_Int32
* pTmp
= rRGBPalette
.getArray();
1477 for( sal_uInt32 i
= 0; i
< nPalCount
; i
++, pTmp
++ )
1479 const BitmapColor
& rCol
= pReadAccess
->GetPaletteColor( static_cast<sal_uInt16
>(i
) );
1481 *pTmp
= static_cast<sal_Int32
>(rCol
.GetRed()) << sal_Int32(24);
1482 *pTmp
|= static_cast<sal_Int32
>(rCol
.GetGreen()) << sal_Int32(16);
1483 *pTmp
|= static_cast<sal_Int32
>(rCol
.GetBlue()) << sal_Int32(8);
1484 *pTmp
|= sal_Int32(0x000000ffL
);
1489 // append transparent entry
1490 *pTmp
= sal_Int32(0xffffff00L
);
1491 rnTransparencyIndex
= nPalCount
;
1495 rnTransparencyIndex
= 0;
1500 rnRedMask
= 0xff000000UL
;
1501 rnGreenMask
= 0x00ff0000UL
;
1502 rnBlueMask
= 0x0000ff00UL
;
1503 rnAlphaMask
= 0x000000ffUL
;
1504 rnTransparencyIndex
= 0;
1507 rnWidth
= pReadAccess
->Width();
1508 rnHeight
= pReadAccess
->Height();
1509 rnBitCount
= pReadAccess
->GetBitCount();
1512 void BitmapEx::DumpAsPng(const char* pFileName
) const
1517 sPath
= OUString::fromUtf8(pFileName
);
1519 else if (const char* pEnv
= std::getenv("VCL_DUMP_BMP_PATH"))
1521 sPath
= OUString::fromUtf8(pEnv
);
1525 sPath
= "file:///tmp/bitmap.png";
1527 SvFileStream
aStream(sPath
, StreamMode::STD_READWRITE
| StreamMode::TRUNC
);
1528 assert(aStream
.good());
1529 vcl::PngImageWriter
aWriter(aStream
);
1530 aWriter
.write(*this);
1533 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */