1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <osl/diagnose.h>
21 #include <tools/helpers.hxx>
22 #include <vcl/bitmap.hxx>
23 #include <vcl/bitmapaccess.hxx>
24 #include <vcl/outdev.hxx>
27 #include <salinst.hxx>
29 #include <bitmapwriteaccess.hxx>
36 #include <tools/stream.hxx>
37 #include <vcl/graphicfilter.hxx>
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()))
64 BitmapPalette
* pRealPal
= nullptr;
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
;
81 aPal
[ 2 ] = COL_GREEN
;
84 aPal
[ 5 ] = COL_MAGENTA
;
85 aPal
[ 6 ] = COL_BROWN
;
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
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 );
112 pRealPal
= const_cast<BitmapPalette
*>(pPal
);
115 mxSalBmp
= ImplGetSVData()->mpDefInst
->CreateSalBitmap();
116 mxSalBmp
->Create( rSizePixel
, nBitCount
, pRealPal
? *pRealPal
: aPal
);
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
);
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
)
144 savePNG(sDumpPath
, *this);
149 const BitmapPalette
& Bitmap::GetGreyPalette( int nEntries
)
151 // Create greyscale palette with 2, 4, 16 or 256 entries
156 static const BitmapPalette aGreyPalette2
= [] {
157 BitmapPalette
aPalette(2);
158 aPalette
[0] = BitmapColor(0, 0, 0);
159 aPalette
[1] = BitmapColor(255, 255, 255);
163 return aGreyPalette2
;
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);
176 return aGreyPalette4
;
180 static const BitmapPalette aGreyPalette16
= [] {
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
);
192 return aGreyPalette16
;
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
));
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
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 )
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();
238 bool BitmapPalette::IsGreyPalette8Bit() const
240 const int nEntryCount
= GetEntryCount();
241 if( !nEntryCount
) // NOTE: an empty palette means 1:1 mapping
243 if( nEntryCount
!= 256 )
245 for (sal_uInt16 i
= 0; i
< 256; ++i
)
247 if( maBitmapColor
[i
] != BitmapColor(i
, i
, i
))
253 Bitmap
& Bitmap::operator=( const Bitmap
& rBitmap
)
255 if (this == &rBitmap
)
258 maPrefSize
= rBitmap
.maPrefSize
;
259 maPrefMapMode
= rBitmap
.maPrefMapMode
;
260 mxSalBmp
= rBitmap
.mxSalBmp
;
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
);
274 bool Bitmap::operator==( const Bitmap
& rBmp
) const
276 if (rBmp
.mxSalBmp
== mxSalBmp
) // Includes both are nullptr
278 if (!rBmp
.mxSalBmp
|| !mxSalBmp
)
280 if (rBmp
.mxSalBmp
->GetSize() != mxSalBmp
->GetSize() ||
281 rBmp
.mxSalBmp
->GetBitCount() != mxSalBmp
->GetBitCount())
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)
289 return aChecksum1
== aChecksum2
;
292 void Bitmap::SetEmpty()
294 maPrefMapMode
= MapMode();
299 Size
Bitmap::GetSizePixel() const
301 return( mxSalBmp
? mxSalBmp
->GetSize() : Size() );
304 sal_uInt16
Bitmap::GetBitCount() const
309 sal_uInt16 nBitCount
= mxSalBmp
->GetBitCount();
323 bool Bitmap::HasGreyPaletteAny() const
325 const sal_uInt16 nBitCount
= GetBitCount();
326 bool bRet
= nBitCount
== 1;
328 ScopedInfoAccess
pIAcc(const_cast<Bitmap
&>(*this));
332 bRet
= pIAcc
->HasPalette() && pIAcc
->GetPalette().IsGreyPaletteAny();
338 bool Bitmap::HasGreyPalette8Bit() const
341 ScopedInfoAccess
pIAcc(const_cast<Bitmap
&>(*this));
345 bRet
= pIAcc
->HasPalette() && pIAcc
->GetPalette().IsGreyPalette8Bit();
351 BitmapChecksum
Bitmap::GetChecksum() const
353 BitmapChecksum nRet
= 0;
357 mxSalBmp
->GetChecksum(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
);
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
);
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()));
402 aNewPrefSize
= maPrefSize
;
407 maPrefSize
= aNewPrefSize
;
408 maPrefMapMode
= aOldMapMode
;
412 void Bitmap::ImplSetSalBitmap(const std::shared_ptr
<SalBitmap
>& xImpBmp
)
417 BitmapInfoAccess
* Bitmap::AcquireInfoAccess()
419 std::unique_ptr
<BitmapInfoAccess
> pInfoAccess(new BitmapInfoAccess( *this ));
426 return pInfoAccess
.release();
429 BitmapReadAccess
* Bitmap::AcquireReadAccess()
431 std::unique_ptr
<BitmapReadAccess
> pReadAccess(new BitmapReadAccess( *this ));
438 return pReadAccess
.release();
441 BitmapWriteAccess
* Bitmap::AcquireWriteAccess()
443 std::unique_ptr
<BitmapWriteAccess
> pWriteAccess(new BitmapWriteAccess( *this ));
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
);
464 aRect
.Intersection( tools::Rectangle( Point(), aSizePix
) );
466 if( !aRect
.IsEmpty() && aSizePix
!= aRect
.GetSize())
468 ScopedReadAccess
pReadAcc(*this);
472 const tools::Rectangle
aNewRect( Point(), aRect
.GetSize() );
473 Bitmap
aNewBmp( aNewRect
.GetSize(), GetBitCount(), &pReadAcc
->GetPalette() );
474 BitmapScopedWriteAccess
pWriteAcc(aNewBmp
);
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
) );
498 ReassignWithSize( aNewBmp
);
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
);
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
)
528 if (nSrcBitCount
== 24)
529 Convert( BmpConversion::N24Bit
);
530 else if (nSrcBitCount
== 8)
532 Convert( BmpConversion::N8BitColors
);
535 else if (nSrcBitCount
== 4)
537 Convert( BmpConversion::N4BitColors
);
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
) );
557 for (int j
= 0; j
< nDstCount
; ++j
)
559 if( rSrcCol
== pDstAcc
->GetPaletteColor( static_cast<sal_uInt16
>(j
) ) )
567 pDstAcc
->SetPaletteColor( static_cast<sal_uInt16
>(nNextIndex
++), rSrcCol
);
573 aRectSrc
.Intersection( tools::Rectangle( Point(), aCopySizePix
) );
575 if( !aRectSrc
.IsEmpty() )
577 ScopedReadAccess
pReadAcc(*pSrc
);
581 BitmapScopedWriteAccess
pWriteAcc(*this);
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
) ) );
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
) );
629 bRet
= ( nWidth
> 0 ) && ( nHeight
> 0 );
638 tools::Rectangle
aRectSrc( rRectSrc
);
640 aRectSrc
.Intersection( tools::Rectangle( Point(), aSizePix
) );
642 if( !aRectSrc
.IsEmpty() && ( aRectSrc
!= aRectDst
) )
644 BitmapScopedWriteAccess
pWriteAcc(*this);
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
) );
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
) );
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
);
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
);
737 BitmapScopedWriteAccess
pWriteAcc(*this);
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
) );
756 bRet
= ( nWidth
> 0 ) && ( nHeight
> 0 );
765 tools::Rectangle
aRectSrc( rRectSrc
);
767 aRectSrc
.Intersection( tools::Rectangle( Point(), aSizePix
) );
769 if( !aRectSrc
.IsEmpty() && ( aRectSrc
!= aRectDst
) )
771 BitmapScopedWriteAccess
pWriteAcc(*this);
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
) );
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
) );
838 bool Bitmap::Expand( sal_uLong nDX
, sal_uLong nDY
, const Color
* pInitColor
)
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);
852 BitmapPalette
aBmpPal( pReadAcc
->GetPalette() );
853 Bitmap
aNewBmp( aNewSize
, GetBitCount(), &aBmpPal
);
854 BitmapScopedWriteAccess
pWriteAcc(aNewBmp
);
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();
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
);
896 ReassignWithSize(aNewBmp
);
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
);
919 bool Bitmap::GetSystemData( BitmapSystemData
& rData
) const
921 return mxSalBmp
&& mxSalBmp
->GetSystemData(rData
);
924 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */