nss: upgrade to release 3.73
[LibreOffice.git] / vcl / source / bitmap / bitmap.cxx
blobc7b7b9b7e70c4bffadd659e176000b656d238b75
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 #ifdef DBG_UTIL
35 #include <cstdlib>
36 #include <tools/stream.hxx>
37 #include <vcl/graphicfilter.hxx>
38 #endif
40 Bitmap::Bitmap()
44 Bitmap::Bitmap(const Bitmap& rBitmap)
45 : mxSalBmp(rBitmap.mxSalBmp)
46 , maPrefMapMode(rBitmap.maPrefMapMode)
47 , maPrefSize(rBitmap.maPrefSize)
51 Bitmap::Bitmap(std::shared_ptr<SalBitmap> const & pSalBitmap)
52 : mxSalBmp(pSalBitmap)
53 , maPrefMapMode(MapMode(MapUnit::MapPixel))
54 , maPrefSize(mxSalBmp->GetSize())
58 Bitmap::Bitmap( const Size& rSizePixel, sal_uInt16 nBitCount, const BitmapPalette* pPal )
60 if (!(rSizePixel.Width() && rSizePixel.Height()))
61 return;
63 BitmapPalette aPal;
64 BitmapPalette* pRealPal = nullptr;
66 if( nBitCount <= 8 )
68 if( !pPal )
70 if( 1 == nBitCount )
72 aPal.SetEntryCount( 2 );
73 aPal[ 0 ] = COL_BLACK;
74 aPal[ 1 ] = COL_WHITE;
76 else if( ( 4 == nBitCount ) || ( 8 == nBitCount ) )
78 aPal.SetEntryCount( 1 << nBitCount );
79 aPal[ 0 ] = COL_BLACK;
80 aPal[ 1 ] = COL_BLUE;
81 aPal[ 2 ] = COL_GREEN;
82 aPal[ 3 ] = COL_CYAN;
83 aPal[ 4 ] = COL_RED;
84 aPal[ 5 ] = COL_MAGENTA;
85 aPal[ 6 ] = COL_BROWN;
86 aPal[ 7 ] = COL_GRAY;
87 aPal[ 8 ] = COL_LIGHTGRAY;
88 aPal[ 9 ] = COL_LIGHTBLUE;
89 aPal[ 10 ] = COL_LIGHTGREEN;
90 aPal[ 11 ] = COL_LIGHTCYAN;
91 aPal[ 12 ] = COL_LIGHTRED;
92 aPal[ 13 ] = COL_LIGHTMAGENTA;
93 aPal[ 14 ] = COL_YELLOW;
94 aPal[ 15 ] = COL_WHITE;
96 // Create dither palette
97 if( 8 == nBitCount )
99 sal_uInt16 nActCol = 16;
101 for( sal_uInt16 nB = 0; nB < 256; nB += 51 )
102 for( sal_uInt16 nG = 0; nG < 256; nG += 51 )
103 for( sal_uInt16 nR = 0; nR < 256; nR += 51 )
104 aPal[ nActCol++ ] = BitmapColor( static_cast<sal_uInt8>(nR), static_cast<sal_uInt8>(nG), static_cast<sal_uInt8>(nB) );
106 // Set standard Office colors
107 aPal[ nActCol++ ] = BitmapColor( 0, 184, 255 );
111 else
112 pRealPal = const_cast<BitmapPalette*>(pPal);
115 mxSalBmp = ImplGetSVData()->mpDefInst->CreateSalBitmap();
116 mxSalBmp->Create( rSizePixel, nBitCount, pRealPal ? *pRealPal : aPal );
119 #ifdef DBG_UTIL
121 namespace
123 void savePNG(const OUString& sWhere, const Bitmap& rBmp)
125 SvFileStream aStream(sWhere, StreamMode::WRITE | StreamMode::TRUNC);
126 GraphicFilter& rFilter = GraphicFilter::GetGraphicFilter();
127 rFilter.compressAsPNG(BitmapEx(rBmp), aStream);
131 #endif
133 Bitmap::~Bitmap()
135 #ifdef DBG_UTIL
136 // VCL_DUMP_BMP_PATH should be like C:/bmpDump.png or ~/bmpDump.png
137 static const OUString sDumpPath(OUString::createFromAscii(std::getenv("VCL_DUMP_BMP_PATH")));
138 // Stepping into the dtor of a bitmap you need, and setting the volatile variable to true in
139 // debugger, would dump the bitmap in question
140 static volatile bool save(false);
141 if (!sDumpPath.isEmpty() && save)
143 save = false;
144 savePNG(sDumpPath, *this);
146 #endif
149 const BitmapPalette& Bitmap::GetGreyPalette( int nEntries )
151 // Create greyscale palette with 2, 4, 16 or 256 entries
152 switch (nEntries)
154 case 2:
156 static const BitmapPalette aGreyPalette2 = [] {
157 BitmapPalette aPalette(2);
158 aPalette[0] = BitmapColor(0, 0, 0);
159 aPalette[1] = BitmapColor(255, 255, 255);
160 return aPalette;
161 }();
163 return aGreyPalette2;
165 case 4:
167 static const BitmapPalette aGreyPalette4 = [] {
168 BitmapPalette aPalette(4);
169 aPalette[0] = BitmapColor(0, 0, 0);
170 aPalette[1] = BitmapColor(85, 85, 85);
171 aPalette[2] = BitmapColor(170, 170, 170);
172 aPalette[3] = BitmapColor(255, 255, 255);
173 return aPalette;
174 }();
176 return aGreyPalette4;
178 case 16:
180 static const BitmapPalette aGreyPalette16 = [] {
181 sal_uInt8 cGrey = 0;
182 sal_uInt8 const cGreyInc = 17;
184 BitmapPalette aPalette(16);
186 for (sal_uInt16 i = 0; i < 16; ++i, cGrey += cGreyInc)
187 aPalette[i] = BitmapColor(cGrey, cGrey, cGrey);
189 return aPalette;
190 }();
192 return aGreyPalette16;
194 case 256:
196 static const BitmapPalette aGreyPalette256 = [] {
197 BitmapPalette aPalette(256);
199 for (sal_uInt16 i = 0; i < 256; ++i)
200 aPalette[i] = BitmapColor(static_cast<sal_uInt8>(i), static_cast<sal_uInt8>(i),
201 static_cast<sal_uInt8>(i));
203 return aPalette;
204 }();
206 return aGreyPalette256;
209 OSL_FAIL("Bitmap::GetGreyPalette: invalid entry count (2/4/16/256 allowed)");
210 return GetGreyPalette(2);
213 bool BitmapPalette::IsGreyPaletteAny() const
215 const int nEntryCount = GetEntryCount();
216 if( !nEntryCount ) // NOTE: an empty palette means 1:1 mapping
217 return true;
218 // See above: only certain entry values will result in a valid call to GetGreyPalette
219 if( nEntryCount == 2 || nEntryCount == 4 || nEntryCount == 16 || nEntryCount == 256 )
221 const BitmapPalette& rGreyPalette = Bitmap::GetGreyPalette( nEntryCount );
222 if( rGreyPalette == *this )
223 return true;
226 bool bRet = false;
227 // TODO: is it worth to compare the entries for the general case?
228 if (nEntryCount == 2)
230 const BitmapColor& rCol0(maBitmapColor[0]);
231 const BitmapColor& rCol1(maBitmapColor[1]);
232 bRet = rCol0.GetRed() == rCol0.GetGreen() && rCol0.GetRed() == rCol0.GetBlue() &&
233 rCol1.GetRed() == rCol1.GetGreen() && rCol1.GetRed() == rCol1.GetBlue();
235 return bRet;
238 bool BitmapPalette::IsGreyPalette8Bit() const
240 const int nEntryCount = GetEntryCount();
241 if( !nEntryCount ) // NOTE: an empty palette means 1:1 mapping
242 return true;
243 if( nEntryCount != 256 )
244 return false;
245 for (sal_uInt16 i = 0; i < 256; ++i)
247 if( maBitmapColor[i] != BitmapColor(i, i, i))
248 return false;
250 return true;
253 Bitmap& Bitmap::operator=( const Bitmap& rBitmap )
255 if (this == &rBitmap)
256 return *this;
258 maPrefSize = rBitmap.maPrefSize;
259 maPrefMapMode = rBitmap.maPrefMapMode;
260 mxSalBmp = rBitmap.mxSalBmp;
262 return *this;
265 Bitmap& Bitmap::operator=( Bitmap&& rBitmap ) noexcept
267 maPrefSize = std::move(rBitmap.maPrefSize);
268 maPrefMapMode = std::move(rBitmap.maPrefMapMode);
269 mxSalBmp = std::move(rBitmap.mxSalBmp);
271 return *this;
274 bool Bitmap::operator==( const Bitmap& rBmp ) const
276 if (rBmp.mxSalBmp == mxSalBmp) // Includes both are nullptr
277 return true;
278 if (!rBmp.mxSalBmp || !mxSalBmp)
279 return false;
280 if (rBmp.mxSalBmp->GetSize() != mxSalBmp->GetSize() ||
281 rBmp.mxSalBmp->GetBitCount() != mxSalBmp->GetBitCount())
282 return false;
283 BitmapChecksum aChecksum1, aChecksum2;
284 rBmp.mxSalBmp->GetChecksum(aChecksum1);
285 mxSalBmp->GetChecksum(aChecksum2);
286 // If the bitmaps can't calculate a checksum, best to regard them as different.
287 if (aChecksum1 == 0 || aChecksum2 == 0)
288 return false;
289 return aChecksum1 == aChecksum2;
292 void Bitmap::SetEmpty()
294 maPrefMapMode = MapMode();
295 maPrefSize = Size();
296 mxSalBmp.reset();
299 Size Bitmap::GetSizePixel() const
301 return( mxSalBmp ? mxSalBmp->GetSize() : Size() );
304 sal_uInt16 Bitmap::GetBitCount() const
306 if (!mxSalBmp)
307 return 0;
309 sal_uInt16 nBitCount = mxSalBmp->GetBitCount();
310 if (nBitCount <= 1)
311 return 1;
312 if (nBitCount <= 4)
313 return 4;
314 if (nBitCount <= 8)
315 return 8;
316 if (nBitCount <= 24)
317 return 24;
318 if (nBitCount <= 32)
319 return 32;
320 return 0;
323 bool Bitmap::HasGreyPaletteAny() const
325 const sal_uInt16 nBitCount = GetBitCount();
326 bool bRet = nBitCount == 1;
328 ScopedInfoAccess pIAcc(const_cast<Bitmap&>(*this));
330 if( pIAcc )
332 bRet = pIAcc->HasPalette() && pIAcc->GetPalette().IsGreyPaletteAny();
335 return bRet;
338 bool Bitmap::HasGreyPalette8Bit() const
340 bool bRet = false;
341 ScopedInfoAccess pIAcc(const_cast<Bitmap&>(*this));
343 if( pIAcc )
345 bRet = pIAcc->HasPalette() && pIAcc->GetPalette().IsGreyPalette8Bit();
348 return bRet;
351 BitmapChecksum Bitmap::GetChecksum() const
353 BitmapChecksum nRet = 0;
355 if( mxSalBmp )
357 mxSalBmp->GetChecksum(nRet);
359 if (!nRet)
361 // nRet == 0 => probably, we were not able to acquire
362 // the buffer in SalBitmap::updateChecksum;
363 // so, we need to update the imp bitmap for this bitmap instance
364 // as we do in BitmapInfoAccess::ImplCreate
365 std::shared_ptr<SalBitmap> xNewImpBmp(ImplGetSVData()->mpDefInst->CreateSalBitmap());
366 if (xNewImpBmp->Create(*mxSalBmp, GetBitCount()))
368 Bitmap* pThis = const_cast<Bitmap*>(this);
369 pThis->mxSalBmp = xNewImpBmp;
370 mxSalBmp->GetChecksum(nRet);
375 return nRet;
378 void Bitmap::ImplMakeUnique()
380 if (mxSalBmp && mxSalBmp.use_count() > 1)
382 std::shared_ptr<SalBitmap> xOldImpBmp = mxSalBmp;
383 mxSalBmp = ImplGetSVData()->mpDefInst->CreateSalBitmap();
384 (void)mxSalBmp->Create(*xOldImpBmp);
388 void Bitmap::ReassignWithSize(const Bitmap& rBitmap)
390 const Size aOldSizePix(GetSizePixel());
391 const Size aNewSizePix(rBitmap.GetSizePixel());
392 const MapMode aOldMapMode(maPrefMapMode);
393 Size aNewPrefSize;
395 if ((aOldSizePix != aNewSizePix) && aOldSizePix.Width() && aOldSizePix.Height())
397 aNewPrefSize.setWidth(FRound(maPrefSize.Width() * aNewSizePix.Width() / aOldSizePix.Width()));
398 aNewPrefSize.setHeight(FRound(maPrefSize.Height() * aNewSizePix.Height() / aOldSizePix.Height()));
400 else
402 aNewPrefSize = maPrefSize;
405 *this = rBitmap;
407 maPrefSize = aNewPrefSize;
408 maPrefMapMode = aOldMapMode;
412 void Bitmap::ImplSetSalBitmap(const std::shared_ptr<SalBitmap>& xImpBmp)
414 mxSalBmp = xImpBmp;
417 BitmapInfoAccess* Bitmap::AcquireInfoAccess()
419 std::unique_ptr<BitmapInfoAccess> pInfoAccess(new BitmapInfoAccess( *this ));
421 if( !*pInfoAccess )
423 return nullptr;
426 return pInfoAccess.release();
429 BitmapReadAccess* Bitmap::AcquireReadAccess()
431 std::unique_ptr<BitmapReadAccess> pReadAccess(new BitmapReadAccess( *this ));
433 if( !*pReadAccess )
435 return nullptr;
438 return pReadAccess.release();
441 BitmapWriteAccess* Bitmap::AcquireWriteAccess()
443 std::unique_ptr<BitmapWriteAccess> pWriteAccess(new BitmapWriteAccess( *this ));
445 if( !*pWriteAccess )
447 return nullptr;
450 return pWriteAccess.release();
453 void Bitmap::ReleaseAccess( BitmapInfoAccess* pBitmapAccess )
455 delete pBitmapAccess;
458 bool Bitmap::Crop( const tools::Rectangle& rRectPixel )
460 const Size aSizePix( GetSizePixel() );
461 tools::Rectangle aRect( rRectPixel );
462 bool bRet = false;
464 aRect.Intersection( tools::Rectangle( Point(), aSizePix ) );
466 if( !aRect.IsEmpty() && aSizePix != aRect.GetSize())
468 ScopedReadAccess pReadAcc(*this);
470 if( pReadAcc )
472 const tools::Rectangle aNewRect( Point(), aRect.GetSize() );
473 Bitmap aNewBmp( aNewRect.GetSize(), GetBitCount(), &pReadAcc->GetPalette() );
474 BitmapScopedWriteAccess pWriteAcc(aNewBmp);
476 if( pWriteAcc )
478 const tools::Long nOldX = aRect.Left();
479 const tools::Long nOldY = aRect.Top();
480 const tools::Long nNewWidth = aNewRect.GetWidth();
481 const tools::Long nNewHeight = aNewRect.GetHeight();
483 for( tools::Long nY = 0, nY2 = nOldY; nY < nNewHeight; nY++, nY2++ )
485 Scanline pScanline = pWriteAcc->GetScanline(nY);
486 Scanline pScanlineRead = pReadAcc->GetScanline(nY2);
487 for( tools::Long nX = 0, nX2 = nOldX; nX < nNewWidth; nX++, nX2++ )
488 pWriteAcc->SetPixelOnData( pScanline, nX, pReadAcc->GetPixelFromData( pScanlineRead, nX2 ) );
491 pWriteAcc.reset();
492 bRet = true;
495 pReadAcc.reset();
497 if( bRet )
498 ReassignWithSize( aNewBmp );
502 return bRet;
505 bool Bitmap::CopyPixel( const tools::Rectangle& rRectDst,
506 const tools::Rectangle& rRectSrc, const Bitmap* pBmpSrc )
508 const Size aSizePix( GetSizePixel() );
509 tools::Rectangle aRectDst( rRectDst );
510 bool bRet = false;
512 aRectDst.Intersection( tools::Rectangle( Point(), aSizePix ) );
514 if( !aRectDst.IsEmpty() )
516 if( pBmpSrc && ( pBmpSrc->mxSalBmp != mxSalBmp ) )
518 Bitmap* pSrc = const_cast<Bitmap*>(pBmpSrc);
519 const Size aCopySizePix( pSrc->GetSizePixel() );
520 tools::Rectangle aRectSrc( rRectSrc );
521 const sal_uInt16 nSrcBitCount = pBmpSrc->GetBitCount();
522 const sal_uInt16 nDstBitCount = GetBitCount();
524 if( nSrcBitCount > nDstBitCount )
526 int nNextIndex = 0;
528 if (nSrcBitCount == 24)
529 Convert( BmpConversion::N24Bit );
530 else if (nSrcBitCount == 8)
532 Convert( BmpConversion::N8BitColors );
533 nNextIndex = 16;
535 else if (nSrcBitCount == 4)
537 Convert( BmpConversion::N4BitColors );
538 nNextIndex = 2;
541 if( nNextIndex )
543 ScopedReadAccess pSrcAcc(*pSrc);
544 BitmapScopedWriteAccess pDstAcc(*this);
546 if( pSrcAcc && pDstAcc )
548 const int nSrcCount = pDstAcc->GetPaletteEntryCount();
549 const int nDstCount = 1 << nDstBitCount;
551 for (int i = 0; ( i < nSrcCount ) && ( nNextIndex < nSrcCount ); ++i)
553 const BitmapColor& rSrcCol = pSrcAcc->GetPaletteColor( static_cast<sal_uInt16>(i) );
555 bool bFound = false;
557 for (int j = 0; j < nDstCount; ++j)
559 if( rSrcCol == pDstAcc->GetPaletteColor( static_cast<sal_uInt16>(j) ) )
561 bFound = true;
562 break;
566 if( !bFound )
567 pDstAcc->SetPaletteColor( static_cast<sal_uInt16>(nNextIndex++), rSrcCol );
573 aRectSrc.Intersection( tools::Rectangle( Point(), aCopySizePix ) );
575 if( !aRectSrc.IsEmpty() )
577 ScopedReadAccess pReadAcc(*pSrc);
579 if( pReadAcc )
581 BitmapScopedWriteAccess pWriteAcc(*this);
583 if( pWriteAcc )
585 const tools::Long nWidth = std::min( aRectSrc.GetWidth(), aRectDst.GetWidth() );
586 const tools::Long nHeight = std::min( aRectSrc.GetHeight(), aRectDst.GetHeight() );
587 const tools::Long nSrcEndX = aRectSrc.Left() + nWidth;
588 const tools::Long nSrcEndY = aRectSrc.Top() + nHeight;
589 tools::Long nDstY = aRectDst.Top();
591 if( pReadAcc->HasPalette() && pWriteAcc->HasPalette() )
593 const sal_uInt16 nCount = pReadAcc->GetPaletteEntryCount();
594 std::unique_ptr<sal_uInt8[]> pMap(new sal_uInt8[ nCount ]);
596 // Create index map for the color table, as the bitmap should be copied
597 // retaining it's color information relatively well
598 for( sal_uInt16 i = 0; i < nCount; i++ )
599 pMap[ i ] = static_cast<sal_uInt8>(pWriteAcc->GetBestPaletteIndex( pReadAcc->GetPaletteColor( i ) ));
601 for( tools::Long nSrcY = aRectSrc.Top(); nSrcY < nSrcEndY; nSrcY++, nDstY++ )
603 Scanline pScanline = pWriteAcc->GetScanline(nDstY);
604 Scanline pScanlineRead = pReadAcc->GetScanline(nSrcY);
605 for( tools::Long nSrcX = aRectSrc.Left(), nDstX = aRectDst.Left(); nSrcX < nSrcEndX; nSrcX++, nDstX++ )
606 pWriteAcc->SetPixelOnData( pScanline, nDstX, BitmapColor( pMap[ pReadAcc->GetIndexFromData( pScanlineRead, nSrcX ) ] ));
609 else if( pReadAcc->HasPalette() )
611 for( tools::Long nSrcY = aRectSrc.Top(); nSrcY < nSrcEndY; nSrcY++, nDstY++ )
613 Scanline pScanline = pWriteAcc->GetScanline(nDstY);
614 Scanline pScanlineRead = pReadAcc->GetScanline(nSrcY);
615 for( tools::Long nSrcX = aRectSrc.Left(), nDstX = aRectDst.Left(); nSrcX < nSrcEndX; nSrcX++, nDstX++ )
616 pWriteAcc->SetPixelOnData( pScanline, nDstX, pReadAcc->GetPaletteColor( pReadAcc->GetIndexFromData( pScanlineRead, nSrcX ) ) );
619 else
620 for( tools::Long nSrcY = aRectSrc.Top(); nSrcY < nSrcEndY; nSrcY++, nDstY++ )
622 Scanline pScanline = pWriteAcc->GetScanline(nDstY);
623 Scanline pScanlineRead = pReadAcc->GetScanline(nSrcY);
624 for( tools::Long nSrcX = aRectSrc.Left(), nDstX = aRectDst.Left(); nSrcX < nSrcEndX; nSrcX++, nDstX++ )
625 pWriteAcc->SetPixelOnData( pScanline, nDstX, pReadAcc->GetPixelFromData( pScanlineRead, nSrcX ) );
628 pWriteAcc.reset();
629 bRet = ( nWidth > 0 ) && ( nHeight > 0 );
632 pReadAcc.reset();
636 else
638 tools::Rectangle aRectSrc( rRectSrc );
640 aRectSrc.Intersection( tools::Rectangle( Point(), aSizePix ) );
642 if( !aRectSrc.IsEmpty() && ( aRectSrc != aRectDst ) )
644 BitmapScopedWriteAccess pWriteAcc(*this);
646 if( pWriteAcc )
648 const tools::Long nWidth = std::min( aRectSrc.GetWidth(), aRectDst.GetWidth() );
649 const tools::Long nHeight = std::min( aRectSrc.GetHeight(), aRectDst.GetHeight() );
650 const tools::Long nSrcX = aRectSrc.Left();
651 const tools::Long nSrcY = aRectSrc.Top();
652 const tools::Long nSrcEndX1 = nSrcX + nWidth - 1;
653 const tools::Long nSrcEndY1 = nSrcY + nHeight - 1;
654 const tools::Long nDstX = aRectDst.Left();
655 const tools::Long nDstY = aRectDst.Top();
656 const tools::Long nDstEndX1 = nDstX + nWidth - 1;
657 const tools::Long nDstEndY1 = nDstY + nHeight - 1;
659 if( ( nDstX <= nSrcX ) && ( nDstY <= nSrcY ) )
661 for( tools::Long nY = nSrcY, nYN = nDstY; nY <= nSrcEndY1; nY++, nYN++ )
663 Scanline pScanline = pWriteAcc->GetScanline(nYN);
664 Scanline pScanlineSrc = pWriteAcc->GetScanline(nY);
665 for( tools::Long nX = nSrcX, nXN = nDstX; nX <= nSrcEndX1; nX++, nXN++ )
666 pWriteAcc->SetPixelOnData( pScanline, nXN, pWriteAcc->GetPixelFromData( pScanlineSrc, nX ) );
669 else if( ( nDstX <= nSrcX ) && ( nDstY >= nSrcY ) )
671 for( tools::Long nY = nSrcEndY1, nYN = nDstEndY1; nY >= nSrcY; nY--, nYN-- )
673 Scanline pScanline = pWriteAcc->GetScanline(nYN);
674 Scanline pScanlineSrc = pWriteAcc->GetScanline(nY);
675 for( tools::Long nX = nSrcX, nXN = nDstX; nX <= nSrcEndX1; nX++, nXN++ )
676 pWriteAcc->SetPixelOnData( pScanline, nXN, pWriteAcc->GetPixelFromData( pScanlineSrc, nX ) );
679 else if( ( nDstX >= nSrcX ) && ( nDstY <= nSrcY ) )
681 for( tools::Long nY = nSrcY, nYN = nDstY; nY <= nSrcEndY1; nY++, nYN++ )
683 Scanline pScanline = pWriteAcc->GetScanline(nYN);
684 Scanline pScanlineSrc = pWriteAcc->GetScanline(nY);
685 for( tools::Long nX = nSrcEndX1, nXN = nDstEndX1; nX >= nSrcX; nX--, nXN-- )
686 pWriteAcc->SetPixelOnData( pScanline, nXN, pWriteAcc->GetPixelFromData( pScanlineSrc, nX ) );
689 else
691 for( tools::Long nY = nSrcEndY1, nYN = nDstEndY1; nY >= nSrcY; nY--, nYN-- )
693 Scanline pScanline = pWriteAcc->GetScanline(nYN);
694 Scanline pScanlineSrc = pWriteAcc->GetScanline(nY);
695 for( tools::Long nX = nSrcEndX1, nXN = nDstEndX1; nX >= nSrcX; nX--, nXN-- )
696 pWriteAcc->SetPixelOnData( pScanline, nXN, pWriteAcc->GetPixelFromData( pScanlineSrc, nX ) );
700 pWriteAcc.reset();
701 bRet = true;
707 return bRet;
710 bool Bitmap::CopyPixel_AlphaOptimized( const tools::Rectangle& rRectDst, const tools::Rectangle& rRectSrc,
711 const Bitmap* pBmpSrc )
713 // Note: this code is copied from Bitmap::CopyPixel but avoids any palette lookups
714 // This optimization is possible because the palettes of AlphaMasks are always identical (8bit GreyPalette, see ctor)
715 const Size aSizePix( GetSizePixel() );
716 tools::Rectangle aRectDst( rRectDst );
717 bool bRet = false;
719 aRectDst.Intersection( tools::Rectangle( Point(), aSizePix ) );
721 if( !aRectDst.IsEmpty() )
723 if( pBmpSrc && ( pBmpSrc->mxSalBmp != mxSalBmp ) )
725 Bitmap* pSrc = const_cast<Bitmap*>(pBmpSrc);
726 const Size aCopySizePix( pSrc->GetSizePixel() );
727 tools::Rectangle aRectSrc( rRectSrc );
729 aRectSrc.Intersection( tools::Rectangle( Point(), aCopySizePix ) );
731 if( !aRectSrc.IsEmpty() )
733 ScopedReadAccess pReadAcc(*pSrc);
735 if( pReadAcc )
737 BitmapScopedWriteAccess pWriteAcc(*this);
739 if( pWriteAcc )
741 const tools::Long nWidth = std::min( aRectSrc.GetWidth(), aRectDst.GetWidth() );
742 const tools::Long nHeight = std::min( aRectSrc.GetHeight(), aRectDst.GetHeight() );
743 const tools::Long nSrcEndX = aRectSrc.Left() + nWidth;
744 const tools::Long nSrcEndY = aRectSrc.Top() + nHeight;
745 tools::Long nDstY = aRectDst.Top();
747 for( tools::Long nSrcY = aRectSrc.Top(); nSrcY < nSrcEndY; nSrcY++, nDstY++)
749 Scanline pScanline = pWriteAcc->GetScanline(nDstY);
750 Scanline pScanlineRead = pReadAcc->GetScanline(nSrcY);
751 for( tools::Long nSrcX = aRectSrc.Left(), nDstX = aRectDst.Left(); nSrcX < nSrcEndX; nSrcX++, nDstX++ )
752 pWriteAcc->SetPixelOnData( pScanline, nDstX, pReadAcc->GetPixelFromData( pScanlineRead, nSrcX ) );
755 pWriteAcc.reset();
756 bRet = ( nWidth > 0 ) && ( nHeight > 0 );
759 pReadAcc.reset();
763 else
765 tools::Rectangle aRectSrc( rRectSrc );
767 aRectSrc.Intersection( tools::Rectangle( Point(), aSizePix ) );
769 if( !aRectSrc.IsEmpty() && ( aRectSrc != aRectDst ) )
771 BitmapScopedWriteAccess pWriteAcc(*this);
773 if( pWriteAcc )
775 const tools::Long nWidth = std::min( aRectSrc.GetWidth(), aRectDst.GetWidth() );
776 const tools::Long nHeight = std::min( aRectSrc.GetHeight(), aRectDst.GetHeight() );
777 const tools::Long nSrcX = aRectSrc.Left();
778 const tools::Long nSrcY = aRectSrc.Top();
779 const tools::Long nSrcEndX1 = nSrcX + nWidth - 1;
780 const tools::Long nSrcEndY1 = nSrcY + nHeight - 1;
781 const tools::Long nDstX = aRectDst.Left();
782 const tools::Long nDstY = aRectDst.Top();
783 const tools::Long nDstEndX1 = nDstX + nWidth - 1;
784 const tools::Long nDstEndY1 = nDstY + nHeight - 1;
786 if( ( nDstX <= nSrcX ) && ( nDstY <= nSrcY ) )
788 for( tools::Long nY = nSrcY, nYN = nDstY; nY <= nSrcEndY1; nY++, nYN++ )
790 Scanline pScanline = pWriteAcc->GetScanline(nYN);
791 Scanline pScanlineSrc = pWriteAcc->GetScanline(nY);
792 for( tools::Long nX = nSrcX, nXN = nDstX; nX <= nSrcEndX1; nX++, nXN++ )
793 pWriteAcc->SetPixelOnData( pScanline, nXN, pWriteAcc->GetPixelFromData( pScanlineSrc, nX ) );
796 else if( ( nDstX <= nSrcX ) && ( nDstY >= nSrcY ) )
798 for( tools::Long nY = nSrcEndY1, nYN = nDstEndY1; nY >= nSrcY; nY--, nYN-- )
800 Scanline pScanline = pWriteAcc->GetScanline(nYN);
801 Scanline pScanlineSrc = pWriteAcc->GetScanline(nY);
802 for( tools::Long nX = nSrcX, nXN = nDstX; nX <= nSrcEndX1; nX++, nXN++ )
803 pWriteAcc->SetPixelOnData( pScanline, nXN, pWriteAcc->GetPixelFromData( pScanlineSrc, nX ) );
806 else if( ( nDstX >= nSrcX ) && ( nDstY <= nSrcY ) )
808 for( tools::Long nY = nSrcY, nYN = nDstY; nY <= nSrcEndY1; nY++, nYN++ )
810 Scanline pScanline = pWriteAcc->GetScanline(nYN);
811 Scanline pScanlineSrc = pWriteAcc->GetScanline(nY);
812 for( tools::Long nX = nSrcEndX1, nXN = nDstEndX1; nX >= nSrcX; nX--, nXN-- )
813 pWriteAcc->SetPixelOnData( pScanline, nXN, pWriteAcc->GetPixelFromData( pScanlineSrc, nX ) );
816 else
818 for( tools::Long nY = nSrcEndY1, nYN = nDstEndY1; nY >= nSrcY; nY--, nYN-- )
820 Scanline pScanline = pWriteAcc->GetScanline(nYN);
821 Scanline pScanlineSrc = pWriteAcc->GetScanline(nY);
822 for( tools::Long nX = nSrcEndX1, nXN = nDstEndX1; nX >= nSrcX; nX--, nXN-- )
823 pWriteAcc->SetPixelOnData( pScanline, nXN, pWriteAcc->GetPixelFromData( pScanlineSrc, nX ) );
827 pWriteAcc.reset();
828 bRet = true;
834 return bRet;
838 bool Bitmap::Expand( sal_uLong nDX, sal_uLong nDY, const Color* pInitColor )
840 bool bRet = false;
842 if( nDX || nDY )
844 const Size aSizePixel( GetSizePixel() );
845 const tools::Long nWidth = aSizePixel.Width();
846 const tools::Long nHeight = aSizePixel.Height();
847 const Size aNewSize( nWidth + nDX, nHeight + nDY );
848 ScopedReadAccess pReadAcc(*this);
850 if( pReadAcc )
852 BitmapPalette aBmpPal( pReadAcc->GetPalette() );
853 Bitmap aNewBmp( aNewSize, GetBitCount(), &aBmpPal );
854 BitmapScopedWriteAccess pWriteAcc(aNewBmp);
856 if( pWriteAcc )
858 BitmapColor aColor;
859 const tools::Long nNewX = nWidth;
860 const tools::Long nNewY = nHeight;
861 const tools::Long nNewWidth = pWriteAcc->Width();
862 const tools::Long nNewHeight = pWriteAcc->Height();
863 tools::Long nX;
864 tools::Long nY;
866 if( pInitColor )
867 aColor = pWriteAcc->GetBestMatchingColor( *pInitColor );
869 for( nY = 0; nY < nHeight; nY++ )
871 pWriteAcc->CopyScanline( nY, *pReadAcc );
873 if( pInitColor && nDX )
875 Scanline pScanline = pWriteAcc->GetScanline(nY);
876 for( nX = nNewX; nX < nNewWidth; nX++ )
877 pWriteAcc->SetPixelOnData( pScanline, nX, aColor );
881 if( pInitColor && nDY )
882 for( nY = nNewY; nY < nNewHeight; nY++ )
884 Scanline pScanline = pWriteAcc->GetScanline(nY);
885 for( nX = 0; nX < nNewWidth; nX++ )
886 pWriteAcc->SetPixelOnData( pScanline, nX, aColor );
889 pWriteAcc.reset();
890 bRet = true;
893 pReadAcc.reset();
895 if (bRet)
896 ReassignWithSize(aNewBmp);
900 return bRet;
903 Bitmap Bitmap::CreateDisplayBitmap( OutputDevice* pDisplay ) const
905 Bitmap aDispBmp( *this );
907 SalGraphics* pDispGraphics = pDisplay->GetGraphics();
909 if( mxSalBmp && pDispGraphics )
911 std::shared_ptr<SalBitmap> xImpDispBmp(ImplGetSVData()->mpDefInst->CreateSalBitmap());
912 if (xImpDispBmp->Create(*mxSalBmp, pDispGraphics))
913 aDispBmp.ImplSetSalBitmap(xImpDispBmp);
916 return aDispBmp;
919 bool Bitmap::GetSystemData( BitmapSystemData& rData ) const
921 return mxSalBmp && mxSalBmp->GetSystemData(rData);
924 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */