Version 6.4.0.0.beta1, tag libreoffice-6.4.0.0.beta1
[LibreOffice.git] / vcl / source / bitmap / bitmap.cxx
bloba24fddf31023b7f30566782cd25fc410133e6a1f
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 <osl/diagnose.h>
21 #include <tools/helpers.hxx>
22 #include <vcl/bitmap.hxx>
23 #include <vcl/bitmapaccess.hxx>
24 #include <vcl/outdev.hxx>
26 #include <svdata.hxx>
27 #include <salinst.hxx>
28 #include <salbmp.hxx>
29 #include <bitmapwriteaccess.hxx>
31 #include <algorithm>
32 #include <memory>
34 Bitmap::Bitmap()
38 Bitmap::Bitmap(const Bitmap& rBitmap)
39 : mxSalBmp(rBitmap.mxSalBmp)
40 , maPrefMapMode(rBitmap.maPrefMapMode)
41 , maPrefSize(rBitmap.maPrefSize)
45 Bitmap::Bitmap(std::shared_ptr<SalBitmap> const & pSalBitmap)
46 : mxSalBmp(pSalBitmap)
47 , maPrefMapMode(MapMode(MapUnit::MapPixel))
48 , maPrefSize(mxSalBmp->GetSize())
52 Bitmap::Bitmap( const Size& rSizePixel, sal_uInt16 nBitCount, const BitmapPalette* pPal )
54 if (rSizePixel.Width() && rSizePixel.Height())
56 BitmapPalette aPal;
57 BitmapPalette* pRealPal = nullptr;
59 if( nBitCount <= 8 )
61 if( !pPal )
63 if( 1 == nBitCount )
65 aPal.SetEntryCount( 2 );
66 aPal[ 0 ] = COL_BLACK;
67 aPal[ 1 ] = COL_WHITE;
69 else if( ( 4 == nBitCount ) || ( 8 == nBitCount ) )
71 aPal.SetEntryCount( 1 << nBitCount );
72 aPal[ 0 ] = COL_BLACK;
73 aPal[ 1 ] = COL_BLUE;
74 aPal[ 2 ] = COL_GREEN;
75 aPal[ 3 ] = COL_CYAN;
76 aPal[ 4 ] = COL_RED;
77 aPal[ 5 ] = COL_MAGENTA;
78 aPal[ 6 ] = COL_BROWN;
79 aPal[ 7 ] = COL_GRAY;
80 aPal[ 8 ] = COL_LIGHTGRAY;
81 aPal[ 9 ] = COL_LIGHTBLUE;
82 aPal[ 10 ] = COL_LIGHTGREEN;
83 aPal[ 11 ] = COL_LIGHTCYAN;
84 aPal[ 12 ] = COL_LIGHTRED;
85 aPal[ 13 ] = COL_LIGHTMAGENTA;
86 aPal[ 14 ] = COL_YELLOW;
87 aPal[ 15 ] = COL_WHITE;
89 // Create dither palette
90 if( 8 == nBitCount )
92 sal_uInt16 nActCol = 16;
94 for( sal_uInt16 nB = 0; nB < 256; nB += 51 )
95 for( sal_uInt16 nG = 0; nG < 256; nG += 51 )
96 for( sal_uInt16 nR = 0; nR < 256; nR += 51 )
97 aPal[ nActCol++ ] = BitmapColor( static_cast<sal_uInt8>(nR), static_cast<sal_uInt8>(nG), static_cast<sal_uInt8>(nB) );
99 // Set standard Office colors
100 aPal[ nActCol++ ] = BitmapColor( 0, 184, 255 );
104 else
105 pRealPal = const_cast<BitmapPalette*>(pPal);
108 mxSalBmp = ImplGetSVData()->mpDefInst->CreateSalBitmap();
109 mxSalBmp->Create( rSizePixel, nBitCount, pRealPal ? *pRealPal : aPal );
113 Bitmap::~Bitmap()
117 const BitmapPalette& Bitmap::GetGreyPalette( int nEntries )
119 static BitmapPalette aGreyPalette2;
120 static BitmapPalette aGreyPalette4;
121 static BitmapPalette aGreyPalette16;
122 static BitmapPalette aGreyPalette256;
124 // Create greyscale palette with 2, 4, 16 or 256 entries
125 if( 2 == nEntries || 4 == nEntries || 16 == nEntries || 256 == nEntries )
127 if( 2 == nEntries )
129 if( !aGreyPalette2.GetEntryCount() )
131 aGreyPalette2.SetEntryCount( 2 );
132 aGreyPalette2[ 0 ] = BitmapColor( 0, 0, 0 );
133 aGreyPalette2[ 1 ] = BitmapColor( 255, 255, 255 );
136 return aGreyPalette2;
138 else if( 4 == nEntries )
140 if( !aGreyPalette4.GetEntryCount() )
142 aGreyPalette4.SetEntryCount( 4 );
143 aGreyPalette4[ 0 ] = BitmapColor( 0, 0, 0 );
144 aGreyPalette4[ 1 ] = BitmapColor( 85, 85, 85 );
145 aGreyPalette4[ 2 ] = BitmapColor( 170, 170, 170 );
146 aGreyPalette4[ 3 ] = BitmapColor( 255, 255, 255 );
149 return aGreyPalette4;
151 else if( 16 == nEntries )
153 if( !aGreyPalette16.GetEntryCount() )
155 sal_uInt8 cGrey = 0;
156 sal_uInt8 const cGreyInc = 17;
158 aGreyPalette16.SetEntryCount( 16 );
160 for( sal_uInt16 i = 0; i < 16; i++, cGrey = sal::static_int_cast<sal_uInt8>(cGrey + cGreyInc) )
161 aGreyPalette16[ i ] = BitmapColor( cGrey, cGrey, cGrey );
164 return aGreyPalette16;
166 else
168 if( !aGreyPalette256.GetEntryCount() )
170 aGreyPalette256.SetEntryCount( 256 );
172 for( sal_uInt16 i = 0; i < 256; i++ )
173 aGreyPalette256[ i ] = BitmapColor( static_cast<sal_uInt8>(i), static_cast<sal_uInt8>(i), static_cast<sal_uInt8>(i) );
176 return aGreyPalette256;
179 else
181 OSL_FAIL( "Bitmap::GetGreyPalette: invalid entry count (2/4/16/256 allowed)" );
182 return aGreyPalette2;
186 bool BitmapPalette::IsGreyPalette() const
188 const int nEntryCount = GetEntryCount();
189 if( !nEntryCount ) // NOTE: an empty palette means 1:1 mapping
190 return true;
191 // See above: only certain entry values will result in a valid call to GetGreyPalette
192 if( nEntryCount == 2 || nEntryCount == 4 || nEntryCount == 16 || nEntryCount == 256 )
194 const BitmapPalette& rGreyPalette = Bitmap::GetGreyPalette( nEntryCount );
195 if( rGreyPalette == *this )
196 return true;
199 bool bRet = false;
200 // TODO: is it worth to compare the entries for the general case?
201 if (nEntryCount == 2)
203 const BitmapColor& rCol0(maBitmapColor[0]);
204 const BitmapColor& rCol1(maBitmapColor[1]);
205 bRet = rCol0.GetRed() == rCol0.GetGreen() && rCol0.GetRed() == rCol0.GetBlue() &&
206 rCol1.GetRed() == rCol1.GetGreen() && rCol1.GetRed() == rCol1.GetBlue();
208 return bRet;
211 Bitmap& Bitmap::operator=( const Bitmap& rBitmap )
213 if (this == &rBitmap)
214 return *this;
216 maPrefSize = rBitmap.maPrefSize;
217 maPrefMapMode = rBitmap.maPrefMapMode;
218 mxSalBmp = rBitmap.mxSalBmp;
220 return *this;
223 Bitmap& Bitmap::operator=( Bitmap&& rBitmap ) noexcept
225 maPrefSize = std::move(rBitmap.maPrefSize);
226 maPrefMapMode = std::move(rBitmap.maPrefMapMode);
227 mxSalBmp = std::move(rBitmap.mxSalBmp);
229 return *this;
232 bool Bitmap::operator==( const Bitmap& rBmp ) const
234 if (rBmp.mxSalBmp == mxSalBmp) // Includes both are nullptr
235 return true;
236 if (!rBmp.mxSalBmp || !mxSalBmp)
237 return false;
238 if (rBmp.mxSalBmp->GetSize() != mxSalBmp->GetSize() ||
239 rBmp.mxSalBmp->GetBitCount() != mxSalBmp->GetBitCount())
240 return false;
241 BitmapChecksum aChecksum1, aChecksum2;
242 rBmp.mxSalBmp->GetChecksum(aChecksum1);
243 mxSalBmp->GetChecksum(aChecksum2);
244 // If the bitmaps can't calculate a checksum, best to regard them as different.
245 if (aChecksum1 == 0 || aChecksum2 == 0)
246 return false;
247 return aChecksum1 == aChecksum2;
250 void Bitmap::SetEmpty()
252 maPrefMapMode = MapMode();
253 maPrefSize = Size();
254 mxSalBmp.reset();
257 Size Bitmap::GetSizePixel() const
259 return( mxSalBmp ? mxSalBmp->GetSize() : Size() );
262 sal_uInt16 Bitmap::GetBitCount() const
264 if (!mxSalBmp)
265 return 0;
267 sal_uInt16 nBitCount = mxSalBmp->GetBitCount();
268 if (nBitCount <= 1)
269 return 1;
270 if (nBitCount <= 4)
271 return 4;
272 if (nBitCount <= 8)
273 return 8;
274 if (nBitCount <= 24)
275 return 24;
276 if (nBitCount <= 32)
277 return 32;
278 return 0;
281 bool Bitmap::HasGreyPalette() const
283 const sal_uInt16 nBitCount = GetBitCount();
284 bool bRet = nBitCount == 1;
286 ScopedInfoAccess pIAcc(const_cast<Bitmap&>(*this));
288 if( pIAcc )
290 bRet = pIAcc->HasPalette() && pIAcc->GetPalette().IsGreyPalette();
293 return bRet;
296 BitmapChecksum Bitmap::GetChecksum() const
298 BitmapChecksum nRet = 0;
300 if( mxSalBmp )
302 mxSalBmp->GetChecksum(nRet);
304 if (!nRet)
306 // nRet == 0 => probably, we were not able to acquire
307 // the buffer in SalBitmap::updateChecksum;
308 // so, we need to update the imp bitmap for this bitmap instance
309 // as we do in BitmapInfoAccess::ImplCreate
310 std::shared_ptr<SalBitmap> xNewImpBmp(ImplGetSVData()->mpDefInst->CreateSalBitmap());
311 if (xNewImpBmp->Create(*mxSalBmp, GetBitCount()))
313 Bitmap* pThis = const_cast<Bitmap*>(this);
314 pThis->mxSalBmp = xNewImpBmp;
315 mxSalBmp->GetChecksum(nRet);
320 return nRet;
323 void Bitmap::ImplMakeUnique()
325 if (mxSalBmp && mxSalBmp.use_count() > 1)
327 std::shared_ptr<SalBitmap> xOldImpBmp = mxSalBmp;
328 mxSalBmp = ImplGetSVData()->mpDefInst->CreateSalBitmap();
329 mxSalBmp->Create(*xOldImpBmp);
333 void Bitmap::ReassignWithSize(const Bitmap& rBitmap)
335 const Size aOldSizePix(GetSizePixel());
336 const Size aNewSizePix(rBitmap.GetSizePixel());
337 const MapMode aOldMapMode(maPrefMapMode);
338 Size aNewPrefSize;
340 if ((aOldSizePix != aNewSizePix) && aOldSizePix.Width() && aOldSizePix.Height())
342 aNewPrefSize.setWidth(FRound(maPrefSize.Width() * aNewSizePix.Width() / aOldSizePix.Width()));
343 aNewPrefSize.setHeight(FRound(maPrefSize.Height() * aNewSizePix.Height() / aOldSizePix.Height()));
345 else
347 aNewPrefSize = maPrefSize;
350 *this = rBitmap;
352 maPrefSize = aNewPrefSize;
353 maPrefMapMode = aOldMapMode;
357 void Bitmap::ImplSetSalBitmap(const std::shared_ptr<SalBitmap>& xImpBmp)
359 mxSalBmp = xImpBmp;
362 BitmapInfoAccess* Bitmap::AcquireInfoAccess()
364 std::unique_ptr<BitmapInfoAccess> pInfoAccess(new BitmapInfoAccess( *this ));
366 if( !*pInfoAccess )
368 return nullptr;
371 return pInfoAccess.release();
374 BitmapReadAccess* Bitmap::AcquireReadAccess()
376 std::unique_ptr<BitmapReadAccess> pReadAccess(new BitmapReadAccess( *this ));
378 if( !*pReadAccess )
380 return nullptr;
383 return pReadAccess.release();
386 BitmapWriteAccess* Bitmap::AcquireWriteAccess()
388 std::unique_ptr<BitmapWriteAccess> pWriteAccess(new BitmapWriteAccess( *this ));
390 if( !*pWriteAccess )
392 return nullptr;
395 return pWriteAccess.release();
398 void Bitmap::ReleaseAccess( BitmapInfoAccess* pBitmapAccess )
400 delete pBitmapAccess;
403 bool Bitmap::Crop( const tools::Rectangle& rRectPixel )
405 const Size aSizePix( GetSizePixel() );
406 tools::Rectangle aRect( rRectPixel );
407 bool bRet = false;
409 aRect.Intersection( tools::Rectangle( Point(), aSizePix ) );
411 if( !aRect.IsEmpty() && aSizePix != aRect.GetSize())
413 ScopedReadAccess pReadAcc(*this);
415 if( pReadAcc )
417 const tools::Rectangle aNewRect( Point(), aRect.GetSize() );
418 Bitmap aNewBmp( aNewRect.GetSize(), GetBitCount(), &pReadAcc->GetPalette() );
419 BitmapScopedWriteAccess pWriteAcc(aNewBmp);
421 if( pWriteAcc )
423 const long nOldX = aRect.Left();
424 const long nOldY = aRect.Top();
425 const long nNewWidth = aNewRect.GetWidth();
426 const long nNewHeight = aNewRect.GetHeight();
428 for( long nY = 0, nY2 = nOldY; nY < nNewHeight; nY++, nY2++ )
430 Scanline pScanline = pWriteAcc->GetScanline(nY);
431 Scanline pScanlineRead = pReadAcc->GetScanline(nY2);
432 for( long nX = 0, nX2 = nOldX; nX < nNewWidth; nX++, nX2++ )
433 pWriteAcc->SetPixelOnData( pScanline, nX, pReadAcc->GetPixelFromData( pScanlineRead, nX2 ) );
436 pWriteAcc.reset();
437 bRet = true;
440 pReadAcc.reset();
442 if( bRet )
443 ReassignWithSize( aNewBmp );
447 return bRet;
450 bool Bitmap::CopyPixel( const tools::Rectangle& rRectDst,
451 const tools::Rectangle& rRectSrc, const Bitmap* pBmpSrc )
453 const Size aSizePix( GetSizePixel() );
454 tools::Rectangle aRectDst( rRectDst );
455 bool bRet = false;
457 aRectDst.Intersection( tools::Rectangle( Point(), aSizePix ) );
459 if( !aRectDst.IsEmpty() )
461 if( pBmpSrc && ( pBmpSrc->mxSalBmp != mxSalBmp ) )
463 Bitmap* pSrc = const_cast<Bitmap*>(pBmpSrc);
464 const Size aCopySizePix( pSrc->GetSizePixel() );
465 tools::Rectangle aRectSrc( rRectSrc );
466 const sal_uInt16 nSrcBitCount = pBmpSrc->GetBitCount();
467 const sal_uInt16 nDstBitCount = GetBitCount();
469 if( nSrcBitCount > nDstBitCount )
471 int nNextIndex = 0;
473 if (nSrcBitCount == 24)
474 Convert( BmpConversion::N24Bit );
475 else if (nSrcBitCount == 8)
477 Convert( BmpConversion::N8BitColors );
478 nNextIndex = 16;
480 else if (nSrcBitCount == 4)
482 Convert( BmpConversion::N4BitColors );
483 nNextIndex = 2;
486 if( nNextIndex )
488 ScopedReadAccess pSrcAcc(*pSrc);
489 BitmapScopedWriteAccess pDstAcc(*this);
491 if( pSrcAcc && pDstAcc )
493 const int nSrcCount = pDstAcc->GetPaletteEntryCount();
494 const int nDstCount = 1 << nDstBitCount;
496 for (int i = 0; ( i < nSrcCount ) && ( nNextIndex < nSrcCount ); ++i)
498 const BitmapColor& rSrcCol = pSrcAcc->GetPaletteColor( static_cast<sal_uInt16>(i) );
500 bool bFound = false;
502 for (int j = 0; j < nDstCount; ++j)
504 if( rSrcCol == pDstAcc->GetPaletteColor( static_cast<sal_uInt16>(j) ) )
506 bFound = true;
507 break;
511 if( !bFound )
512 pDstAcc->SetPaletteColor( static_cast<sal_uInt16>(nNextIndex++), rSrcCol );
518 aRectSrc.Intersection( tools::Rectangle( Point(), aCopySizePix ) );
520 if( !aRectSrc.IsEmpty() )
522 ScopedReadAccess pReadAcc(*pSrc);
524 if( pReadAcc )
526 BitmapScopedWriteAccess pWriteAcc(*this);
528 if( pWriteAcc )
530 const long nWidth = std::min( aRectSrc.GetWidth(), aRectDst.GetWidth() );
531 const long nHeight = std::min( aRectSrc.GetHeight(), aRectDst.GetHeight() );
532 const long nSrcEndX = aRectSrc.Left() + nWidth;
533 const long nSrcEndY = aRectSrc.Top() + nHeight;
534 long nDstY = aRectDst.Top();
536 if( pReadAcc->HasPalette() && pWriteAcc->HasPalette() )
538 const sal_uInt16 nCount = pReadAcc->GetPaletteEntryCount();
539 std::unique_ptr<sal_uInt8[]> pMap(new sal_uInt8[ nCount ]);
541 // Create index map for the color table, as the bitmap should be copied
542 // retaining it's color information relatively well
543 for( sal_uInt16 i = 0; i < nCount; i++ )
544 pMap[ i ] = static_cast<sal_uInt8>(pWriteAcc->GetBestPaletteIndex( pReadAcc->GetPaletteColor( i ) ));
546 for( long nSrcY = aRectSrc.Top(); nSrcY < nSrcEndY; nSrcY++, nDstY++ )
548 Scanline pScanline = pWriteAcc->GetScanline(nDstY);
549 Scanline pScanlineRead = pReadAcc->GetScanline(nSrcY);
550 for( long nSrcX = aRectSrc.Left(), nDstX = aRectDst.Left(); nSrcX < nSrcEndX; nSrcX++, nDstX++ )
551 pWriteAcc->SetPixelOnData( pScanline, nDstX, BitmapColor( pMap[ pReadAcc->GetIndexFromData( pScanlineRead, nSrcX ) ] ));
554 else if( pReadAcc->HasPalette() )
556 for( long nSrcY = aRectSrc.Top(); nSrcY < nSrcEndY; nSrcY++, nDstY++ )
558 Scanline pScanline = pWriteAcc->GetScanline(nDstY);
559 Scanline pScanlineRead = pReadAcc->GetScanline(nSrcY);
560 for( long nSrcX = aRectSrc.Left(), nDstX = aRectDst.Left(); nSrcX < nSrcEndX; nSrcX++, nDstX++ )
561 pWriteAcc->SetPixelOnData( pScanline, nDstX, pReadAcc->GetPaletteColor( pReadAcc->GetIndexFromData( pScanlineRead, nSrcX ) ) );
564 else
565 for( long nSrcY = aRectSrc.Top(); nSrcY < nSrcEndY; nSrcY++, nDstY++ )
567 Scanline pScanline = pWriteAcc->GetScanline(nDstY);
568 Scanline pScanlineRead = pReadAcc->GetScanline(nSrcY);
569 for( long nSrcX = aRectSrc.Left(), nDstX = aRectDst.Left(); nSrcX < nSrcEndX; nSrcX++, nDstX++ )
570 pWriteAcc->SetPixelOnData( pScanline, nDstX, pReadAcc->GetPixelFromData( pScanlineRead, nSrcX ) );
573 pWriteAcc.reset();
574 bRet = ( nWidth > 0 ) && ( nHeight > 0 );
577 pReadAcc.reset();
581 else
583 tools::Rectangle aRectSrc( rRectSrc );
585 aRectSrc.Intersection( tools::Rectangle( Point(), aSizePix ) );
587 if( !aRectSrc.IsEmpty() && ( aRectSrc != aRectDst ) )
589 BitmapScopedWriteAccess pWriteAcc(*this);
591 if( pWriteAcc )
593 const long nWidth = std::min( aRectSrc.GetWidth(), aRectDst.GetWidth() );
594 const long nHeight = std::min( aRectSrc.GetHeight(), aRectDst.GetHeight() );
595 const long nSrcX = aRectSrc.Left();
596 const long nSrcY = aRectSrc.Top();
597 const long nSrcEndX1 = nSrcX + nWidth - 1;
598 const long nSrcEndY1 = nSrcY + nHeight - 1;
599 const long nDstX = aRectDst.Left();
600 const long nDstY = aRectDst.Top();
601 const long nDstEndX1 = nDstX + nWidth - 1;
602 const long nDstEndY1 = nDstY + nHeight - 1;
604 if( ( nDstX <= nSrcX ) && ( nDstY <= nSrcY ) )
606 for( long nY = nSrcY, nYN = nDstY; nY <= nSrcEndY1; nY++, nYN++ )
608 Scanline pScanline = pWriteAcc->GetScanline(nYN);
609 Scanline pScanlineSrc = pWriteAcc->GetScanline(nY);
610 for( long nX = nSrcX, nXN = nDstX; nX <= nSrcEndX1; nX++, nXN++ )
611 pWriteAcc->SetPixelOnData( pScanline, nXN, pWriteAcc->GetPixelFromData( pScanlineSrc, nX ) );
614 else if( ( nDstX <= nSrcX ) && ( nDstY >= nSrcY ) )
616 for( long nY = nSrcEndY1, nYN = nDstEndY1; nY >= nSrcY; nY--, nYN-- )
618 Scanline pScanline = pWriteAcc->GetScanline(nYN);
619 Scanline pScanlineSrc = pWriteAcc->GetScanline(nY);
620 for( long nX = nSrcX, nXN = nDstX; nX <= nSrcEndX1; nX++, nXN++ )
621 pWriteAcc->SetPixelOnData( pScanline, nXN, pWriteAcc->GetPixelFromData( pScanlineSrc, nX ) );
624 else if( ( nDstX >= nSrcX ) && ( nDstY <= nSrcY ) )
626 for( long nY = nSrcY, nYN = nDstY; nY <= nSrcEndY1; nY++, nYN++ )
628 Scanline pScanline = pWriteAcc->GetScanline(nYN);
629 Scanline pScanlineSrc = pWriteAcc->GetScanline(nY);
630 for( long nX = nSrcEndX1, nXN = nDstEndX1; nX >= nSrcX; nX--, nXN-- )
631 pWriteAcc->SetPixelOnData( pScanline, nXN, pWriteAcc->GetPixelFromData( pScanlineSrc, nX ) );
634 else
636 for( long nY = nSrcEndY1, nYN = nDstEndY1; nY >= nSrcY; nY--, nYN-- )
638 Scanline pScanline = pWriteAcc->GetScanline(nYN);
639 Scanline pScanlineSrc = pWriteAcc->GetScanline(nY);
640 for( long nX = nSrcEndX1, nXN = nDstEndX1; nX >= nSrcX; nX--, nXN-- )
641 pWriteAcc->SetPixelOnData( pScanline, nXN, pWriteAcc->GetPixelFromData( pScanlineSrc, nX ) );
645 pWriteAcc.reset();
646 bRet = true;
652 return bRet;
655 bool Bitmap::CopyPixel_AlphaOptimized( const tools::Rectangle& rRectDst, const tools::Rectangle& rRectSrc,
656 const Bitmap* pBmpSrc )
658 // Note: this code is copied from Bitmap::CopyPixel but avoids any palette lookups
659 // This optimization is possible because the palettes of AlphaMasks are always identical (8bit GreyPalette, see ctor)
660 const Size aSizePix( GetSizePixel() );
661 tools::Rectangle aRectDst( rRectDst );
662 bool bRet = false;
664 aRectDst.Intersection( tools::Rectangle( Point(), aSizePix ) );
666 if( !aRectDst.IsEmpty() )
668 if( pBmpSrc && ( pBmpSrc->mxSalBmp != mxSalBmp ) )
670 Bitmap* pSrc = const_cast<Bitmap*>(pBmpSrc);
671 const Size aCopySizePix( pSrc->GetSizePixel() );
672 tools::Rectangle aRectSrc( rRectSrc );
674 aRectSrc.Intersection( tools::Rectangle( Point(), aCopySizePix ) );
676 if( !aRectSrc.IsEmpty() )
678 ScopedReadAccess pReadAcc(*pSrc);
680 if( pReadAcc )
682 BitmapScopedWriteAccess pWriteAcc(*this);
684 if( pWriteAcc )
686 const long nWidth = std::min( aRectSrc.GetWidth(), aRectDst.GetWidth() );
687 const long nHeight = std::min( aRectSrc.GetHeight(), aRectDst.GetHeight() );
688 const long nSrcEndX = aRectSrc.Left() + nWidth;
689 const long nSrcEndY = aRectSrc.Top() + nHeight;
690 long nDstY = aRectDst.Top();
692 for( long nSrcY = aRectSrc.Top(); nSrcY < nSrcEndY; nSrcY++, nDstY++)
694 Scanline pScanline = pWriteAcc->GetScanline(nDstY);
695 Scanline pScanlineRead = pReadAcc->GetScanline(nSrcY);
696 for( long nSrcX = aRectSrc.Left(), nDstX = aRectDst.Left(); nSrcX < nSrcEndX; nSrcX++, nDstX++ )
697 pWriteAcc->SetPixelOnData( pScanline, nDstX, pReadAcc->GetPixelFromData( pScanlineRead, nSrcX ) );
700 pWriteAcc.reset();
701 bRet = ( nWidth > 0 ) && ( nHeight > 0 );
704 pReadAcc.reset();
708 else
710 tools::Rectangle aRectSrc( rRectSrc );
712 aRectSrc.Intersection( tools::Rectangle( Point(), aSizePix ) );
714 if( !aRectSrc.IsEmpty() && ( aRectSrc != aRectDst ) )
716 BitmapScopedWriteAccess pWriteAcc(*this);
718 if( pWriteAcc )
720 const long nWidth = std::min( aRectSrc.GetWidth(), aRectDst.GetWidth() );
721 const long nHeight = std::min( aRectSrc.GetHeight(), aRectDst.GetHeight() );
722 const long nSrcX = aRectSrc.Left();
723 const long nSrcY = aRectSrc.Top();
724 const long nSrcEndX1 = nSrcX + nWidth - 1;
725 const long nSrcEndY1 = nSrcY + nHeight - 1;
726 const long nDstX = aRectDst.Left();
727 const long nDstY = aRectDst.Top();
728 const long nDstEndX1 = nDstX + nWidth - 1;
729 const long nDstEndY1 = nDstY + nHeight - 1;
731 if( ( nDstX <= nSrcX ) && ( nDstY <= nSrcY ) )
733 for( long nY = nSrcY, nYN = nDstY; nY <= nSrcEndY1; nY++, nYN++ )
735 Scanline pScanline = pWriteAcc->GetScanline(nYN);
736 Scanline pScanlineSrc = pWriteAcc->GetScanline(nY);
737 for( long nX = nSrcX, nXN = nDstX; nX <= nSrcEndX1; nX++, nXN++ )
738 pWriteAcc->SetPixelOnData( pScanline, nXN, pWriteAcc->GetPixelFromData( pScanlineSrc, nX ) );
741 else if( ( nDstX <= nSrcX ) && ( nDstY >= nSrcY ) )
743 for( long nY = nSrcEndY1, nYN = nDstEndY1; nY >= nSrcY; nY--, nYN-- )
745 Scanline pScanline = pWriteAcc->GetScanline(nYN);
746 Scanline pScanlineSrc = pWriteAcc->GetScanline(nY);
747 for( long nX = nSrcX, nXN = nDstX; nX <= nSrcEndX1; nX++, nXN++ )
748 pWriteAcc->SetPixelOnData( pScanline, nXN, pWriteAcc->GetPixelFromData( pScanlineSrc, nX ) );
751 else if( ( nDstX >= nSrcX ) && ( nDstY <= nSrcY ) )
753 for( long nY = nSrcY, nYN = nDstY; nY <= nSrcEndY1; nY++, nYN++ )
755 Scanline pScanline = pWriteAcc->GetScanline(nYN);
756 Scanline pScanlineSrc = pWriteAcc->GetScanline(nY);
757 for( long nX = nSrcEndX1, nXN = nDstEndX1; nX >= nSrcX; nX--, nXN-- )
758 pWriteAcc->SetPixelOnData( pScanline, nXN, pWriteAcc->GetPixelFromData( pScanlineSrc, nX ) );
761 else
763 for( long nY = nSrcEndY1, nYN = nDstEndY1; nY >= nSrcY; nY--, nYN-- )
765 Scanline pScanline = pWriteAcc->GetScanline(nYN);
766 Scanline pScanlineSrc = pWriteAcc->GetScanline(nY);
767 for( long nX = nSrcEndX1, nXN = nDstEndX1; nX >= nSrcX; nX--, nXN-- )
768 pWriteAcc->SetPixelOnData( pScanline, nXN, pWriteAcc->GetPixelFromData( pScanlineSrc, nX ) );
772 pWriteAcc.reset();
773 bRet = true;
779 return bRet;
783 bool Bitmap::Expand( sal_uLong nDX, sal_uLong nDY, const Color* pInitColor )
785 bool bRet = false;
787 if( nDX || nDY )
789 const Size aSizePixel( GetSizePixel() );
790 const long nWidth = aSizePixel.Width();
791 const long nHeight = aSizePixel.Height();
792 const Size aNewSize( nWidth + nDX, nHeight + nDY );
793 ScopedReadAccess pReadAcc(*this);
795 if( pReadAcc )
797 BitmapPalette aBmpPal( pReadAcc->GetPalette() );
798 Bitmap aNewBmp( aNewSize, GetBitCount(), &aBmpPal );
799 BitmapScopedWriteAccess pWriteAcc(aNewBmp);
801 if( pWriteAcc )
803 BitmapColor aColor;
804 const long nNewX = nWidth;
805 const long nNewY = nHeight;
806 const long nNewWidth = pWriteAcc->Width();
807 const long nNewHeight = pWriteAcc->Height();
808 long nX;
809 long nY;
811 if( pInitColor )
812 aColor = pWriteAcc->GetBestMatchingColor( *pInitColor );
814 for( nY = 0; nY < nHeight; nY++ )
816 pWriteAcc->CopyScanline( nY, *pReadAcc );
818 if( pInitColor && nDX )
820 Scanline pScanline = pWriteAcc->GetScanline(nY);
821 for( nX = nNewX; nX < nNewWidth; nX++ )
822 pWriteAcc->SetPixelOnData( pScanline, nX, aColor );
826 if( pInitColor && nDY )
827 for( nY = nNewY; nY < nNewHeight; nY++ )
829 Scanline pScanline = pWriteAcc->GetScanline(nY);
830 for( nX = 0; nX < nNewWidth; nX++ )
831 pWriteAcc->SetPixelOnData( pScanline, nX, aColor );
834 pWriteAcc.reset();
835 bRet = true;
838 pReadAcc.reset();
840 if (bRet)
841 ReassignWithSize(aNewBmp);
845 return bRet;
848 Bitmap Bitmap::CreateDisplayBitmap( OutputDevice* pDisplay )
850 Bitmap aDispBmp( *this );
852 SalGraphics* pDispGraphics = pDisplay->GetGraphics();
854 if( mxSalBmp && pDispGraphics )
856 std::shared_ptr<SalBitmap> xImpDispBmp(ImplGetSVData()->mpDefInst->CreateSalBitmap());
857 if (xImpDispBmp->Create(*mxSalBmp, pDispGraphics))
858 aDispBmp.ImplSetSalBitmap(xImpDispBmp);
861 return aDispBmp;
864 bool Bitmap::GetSystemData( BitmapSystemData& rData ) const
866 return mxSalBmp && mxSalBmp->GetSystemData(rData);
869 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */