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