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