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 .
22 #include <tools/stream.hxx>
23 #include <tools/poly.hxx>
24 #include <vcl/salbtype.hxx>
25 #include <vcl/bitmapaccess.hxx>
26 #include <vcl/outdev.hxx>
27 #include <vcl/bitmap.hxx>
28 #include <vcl/bitmapex.hxx>
29 #include <vcl/svapp.hxx>
30 #include <vcl/image.hxx>
40 Bitmap::Bitmap(const Bitmap
& rBitmap
)
41 : mxImpBmp(rBitmap
.mxImpBmp
)
42 , maPrefMapMode(rBitmap
.maPrefMapMode
)
43 , maPrefSize(rBitmap
.maPrefSize
)
47 Bitmap::Bitmap(SalBitmap
* pSalBitmap
)
48 : mxImpBmp(new ImpBitmap(pSalBitmap
))
49 , maPrefMapMode(MapMode(MapUnit::MapPixel
))
50 , maPrefSize(mxImpBmp
->ImplGetSize())
54 Bitmap::Bitmap( const Size
& rSizePixel
, sal_uInt16 nBitCount
, const BitmapPalette
* pPal
)
56 if (rSizePixel
.Width() && rSizePixel
.Height())
59 BitmapPalette
* pRealPal
= nullptr;
67 aPal
.SetEntryCount( 2 );
68 aPal
[ 0 ] = Color( COL_BLACK
);
69 aPal
[ 1 ] = Color( COL_WHITE
);
71 else if( ( 4 == nBitCount
) || ( 8 == nBitCount
) )
73 aPal
.SetEntryCount( 1 << nBitCount
);
74 aPal
[ 0 ] = Color( COL_BLACK
);
75 aPal
[ 1 ] = Color( COL_BLUE
);
76 aPal
[ 2 ] = Color( COL_GREEN
);
77 aPal
[ 3 ] = Color( COL_CYAN
);
78 aPal
[ 4 ] = Color( COL_RED
);
79 aPal
[ 5 ] = Color( COL_MAGENTA
);
80 aPal
[ 6 ] = Color( COL_BROWN
);
81 aPal
[ 7 ] = Color( COL_GRAY
);
82 aPal
[ 8 ] = Color( COL_LIGHTGRAY
);
83 aPal
[ 9 ] = Color( COL_LIGHTBLUE
);
84 aPal
[ 10 ] = Color( COL_LIGHTGREEN
);
85 aPal
[ 11 ] = Color( COL_LIGHTCYAN
);
86 aPal
[ 12 ] = Color( COL_LIGHTRED
);
87 aPal
[ 13 ] = Color( COL_LIGHTMAGENTA
);
88 aPal
[ 14 ] = Color( COL_YELLOW
);
89 aPal
[ 15 ] = Color( COL_WHITE
);
91 // Create dither palette
94 sal_uInt16 nActCol
= 16;
96 for( sal_uInt16 nB
= 0; nB
< 256; nB
+= 51 )
97 for( sal_uInt16 nG
= 0; nG
< 256; nG
+= 51 )
98 for( sal_uInt16 nR
= 0; nR
< 256; nR
+= 51 )
99 aPal
[ nActCol
++ ] = BitmapColor( (sal_uInt8
) nR
, (sal_uInt8
) nG
, (sal_uInt8
) nB
);
101 // Set standard Office colors
102 aPal
[ nActCol
++ ] = BitmapColor( 0, 184, 255 );
107 pRealPal
= const_cast<BitmapPalette
*>(pPal
);
110 mxImpBmp
.reset(new ImpBitmap
);
111 mxImpBmp
->ImplCreate( rSizePixel
, nBitCount
, pRealPal
? *pRealPal
: aPal
);
119 const BitmapPalette
& Bitmap::GetGreyPalette( int nEntries
)
121 static BitmapPalette aGreyPalette2
;
122 static BitmapPalette aGreyPalette4
;
123 static BitmapPalette aGreyPalette16
;
124 static BitmapPalette aGreyPalette256
;
126 // Create greyscale palette with 2, 4, 16 or 256 entries
127 if( 2 == nEntries
|| 4 == nEntries
|| 16 == nEntries
|| 256 == nEntries
)
131 if( !aGreyPalette2
.GetEntryCount() )
133 aGreyPalette2
.SetEntryCount( 2 );
134 aGreyPalette2
[ 0 ] = BitmapColor( 0, 0, 0 );
135 aGreyPalette2
[ 1 ] = BitmapColor( 255, 255, 255 );
138 return aGreyPalette2
;
140 else if( 4 == nEntries
)
142 if( !aGreyPalette4
.GetEntryCount() )
144 aGreyPalette4
.SetEntryCount( 4 );
145 aGreyPalette4
[ 0 ] = BitmapColor( 0, 0, 0 );
146 aGreyPalette4
[ 1 ] = BitmapColor( 85, 85, 85 );
147 aGreyPalette4
[ 2 ] = BitmapColor( 170, 170, 170 );
148 aGreyPalette4
[ 3 ] = BitmapColor( 255, 255, 255 );
151 return aGreyPalette4
;
153 else if( 16 == nEntries
)
155 if( !aGreyPalette16
.GetEntryCount() )
157 sal_uInt8 cGrey
= 0, cGreyInc
= 17;
159 aGreyPalette16
.SetEntryCount( 16 );
161 for( sal_uInt16 i
= 0; i
< 16; i
++, cGrey
= sal::static_int_cast
<sal_uInt8
>(cGrey
+ cGreyInc
) )
162 aGreyPalette16
[ i
] = BitmapColor( cGrey
, cGrey
, cGrey
);
165 return aGreyPalette16
;
169 if( !aGreyPalette256
.GetEntryCount() )
171 aGreyPalette256
.SetEntryCount( 256 );
173 for( sal_uInt16 i
= 0; i
< 256; i
++ )
174 aGreyPalette256
[ i
] = BitmapColor( (sal_uInt8
) i
, (sal_uInt8
) i
, (sal_uInt8
) i
);
177 return aGreyPalette256
;
182 OSL_FAIL( "Bitmap::GetGreyPalette: invalid entry count (2/4/16/256 allowed)" );
183 return aGreyPalette2
;
187 bool BitmapPalette::IsGreyPalette() const
189 const int nEntryCount
= GetEntryCount();
190 if( !nEntryCount
) // NOTE: an empty palette means 1:1 mapping
192 // See above: only certain entry values will result in a valid call to GetGreyPalette
193 if( nEntryCount
== 2 || nEntryCount
== 4 || nEntryCount
== 16 || nEntryCount
== 256 )
195 const BitmapPalette
& rGreyPalette
= Bitmap::GetGreyPalette( nEntryCount
);
196 if( rGreyPalette
== *this )
201 // TODO: is it worth to compare the entries for the general case?
202 if (nEntryCount
== 2)
204 const BitmapColor
& rCol0(maBitmapColor
[0]);
205 const BitmapColor
& rCol1(maBitmapColor
[1]);
206 bRet
= rCol0
.GetRed() == rCol0
.GetGreen() && rCol0
.GetRed() == rCol0
.GetBlue() &&
207 rCol1
.GetRed() == rCol1
.GetGreen() && rCol1
.GetRed() == rCol1
.GetBlue();
212 Bitmap
& Bitmap::operator=( const Bitmap
& rBitmap
)
214 if (this == &rBitmap
)
217 maPrefSize
= rBitmap
.maPrefSize
;
218 maPrefMapMode
= rBitmap
.maPrefMapMode
;
219 mxImpBmp
= rBitmap
.mxImpBmp
;
224 Bitmap
& Bitmap::operator=( Bitmap
&& rBitmap
)
226 maPrefSize
= std::move(rBitmap
.maPrefSize
);
227 maPrefMapMode
= std::move(rBitmap
.maPrefMapMode
);
228 mxImpBmp
= std::move(rBitmap
.mxImpBmp
);
233 bool Bitmap::IsEqual( const Bitmap
& rBmp
) const
235 return rBmp
.mxImpBmp
== mxImpBmp
|| // Includes both are nullptr
236 (rBmp
.mxImpBmp
&& mxImpBmp
&& mxImpBmp
->ImplIsEqual(*rBmp
.mxImpBmp
));
239 void Bitmap::SetEmpty()
241 maPrefMapMode
= MapMode();
246 Size
Bitmap::GetSizePixel() const
248 return( mxImpBmp
? mxImpBmp
->ImplGetSize() : Size() );
251 sal_uInt16
Bitmap::GetBitCount() const
253 return( mxImpBmp
? mxImpBmp
->ImplGetBitCount() : 0 );
256 bool Bitmap::HasGreyPalette() const
258 const sal_uInt16 nBitCount
= GetBitCount();
259 bool bRet
= nBitCount
== 1;
261 ScopedInfoAccess
pIAcc(const_cast<Bitmap
&>(*this));
265 bRet
= pIAcc
->HasPalette() && pIAcc
->GetPalette().IsGreyPalette();
271 BitmapChecksum
Bitmap::GetChecksum() const
273 BitmapChecksum nRet
= 0;
277 nRet
= mxImpBmp
->ImplGetChecksum();
281 // nRet == 0 => probably, we were not able to acquire
282 // the buffer in SalBitmap::updateChecksum;
283 // so, we need to update the imp bitmap for this bitmap instance
284 // as we do in BitmapInfoAccess::ImplCreate
285 std::shared_ptr
<ImpBitmap
> xNewImpBmp(new ImpBitmap
);
286 if (xNewImpBmp
->ImplCreate(*mxImpBmp
, GetBitCount()))
288 Bitmap
* pThis
= const_cast<Bitmap
*>(this);
289 pThis
->mxImpBmp
= xNewImpBmp
;
290 nRet
= mxImpBmp
->ImplGetChecksum();
298 void Bitmap::ImplMakeUnique()
300 if (mxImpBmp
&& !mxImpBmp
.unique())
302 std::shared_ptr
<ImpBitmap
> xOldImpBmp
= mxImpBmp
;
303 mxImpBmp
.reset(new ImpBitmap
);
304 mxImpBmp
->ImplCreate(*xOldImpBmp
);
308 void Bitmap::ImplAssignWithSize( const Bitmap
& rBitmap
)
310 const Size
aOldSizePix( GetSizePixel() );
311 const Size
aNewSizePix( rBitmap
.GetSizePixel() );
312 const MapMode
aOldMapMode( maPrefMapMode
);
315 if( ( aOldSizePix
!= aNewSizePix
) && aOldSizePix
.Width() && aOldSizePix
.Height() )
317 aNewPrefSize
.Width() = FRound( maPrefSize
.Width() * aNewSizePix
.Width() / aOldSizePix
.Width() );
318 aNewPrefSize
.Height() = FRound( maPrefSize
.Height() * aNewSizePix
.Height() / aOldSizePix
.Height() );
321 aNewPrefSize
= maPrefSize
;
325 maPrefSize
= aNewPrefSize
;
326 maPrefMapMode
= aOldMapMode
;
330 void Bitmap::ImplSetImpBitmap(const std::shared_ptr
<ImpBitmap
>& xImpBmp
)
335 BitmapInfoAccess
* Bitmap::AcquireInfoAccess()
337 BitmapInfoAccess
* pInfoAccess
= new BitmapInfoAccess( *this );
342 pInfoAccess
= nullptr;
348 BitmapReadAccess
* Bitmap::AcquireReadAccess()
350 BitmapReadAccess
* pReadAccess
= new BitmapReadAccess( *this );
355 pReadAccess
= nullptr;
361 BitmapWriteAccess
* Bitmap::AcquireWriteAccess()
363 BitmapWriteAccess
* pWriteAccess
= new BitmapWriteAccess( *this );
368 pWriteAccess
= nullptr;
374 void Bitmap::ReleaseAccess( BitmapInfoAccess
* pBitmapAccess
)
376 delete pBitmapAccess
;
379 bool Bitmap::Erase(const Color
& rFillColor
)
384 Bitmap::ScopedWriteAccess
pWriteAcc(*this);
389 const ScanlineFormat nFormat
= pWriteAcc
->GetScanlineFormat();
390 sal_uInt8 cIndex
= 0;
395 case ScanlineFormat::N1BitMsbPal
:
396 case ScanlineFormat::N1BitLsbPal
:
398 cIndex
= static_cast<sal_uInt8
>(pWriteAcc
->GetBestPaletteIndex(rFillColor
));
399 cIndex
= (cIndex
? 255 : 0);
404 case ScanlineFormat::N4BitMsnPal
:
405 case ScanlineFormat::N4BitLsnPal
:
407 cIndex
= static_cast<sal_uInt8
>(pWriteAcc
->GetBestPaletteIndex(rFillColor
));
408 cIndex
= cIndex
| ( cIndex
<< 4 );
413 case ScanlineFormat::N8BitPal
:
415 cIndex
= static_cast<sal_uInt8
>(pWriteAcc
->GetBestPaletteIndex(rFillColor
));
420 case ScanlineFormat::N24BitTcBgr
:
421 case ScanlineFormat::N24BitTcRgb
:
423 if (rFillColor
.GetRed() == rFillColor
.GetGreen() &&
424 rFillColor
.GetRed() == rFillColor
.GetBlue())
426 cIndex
= rFillColor
.GetRed();
441 const sal_uLong nBufSize
= pWriteAcc
->GetScanlineSize() * pWriteAcc
->Height();
442 memset( pWriteAcc
->GetBuffer(), cIndex
, nBufSize
);
447 const tools::Rectangle
aRect( aTmpPoint
, Size( pWriteAcc
->Width(), pWriteAcc
->Height() ) );
448 pWriteAcc
->SetFillColor( rFillColor
);
449 pWriteAcc
->FillRect( aRect
);
458 bool Bitmap::Invert()
460 ScopedWriteAccess
pAcc(*this);
465 if( pAcc
->HasPalette() )
467 BitmapPalette
aBmpPal( pAcc
->GetPalette() );
468 const sal_uInt16 nCount
= aBmpPal
.GetEntryCount();
470 for( sal_uInt16 i
= 0; i
< nCount
; i
++ )
471 aBmpPal
[ i
].Invert();
473 pAcc
->SetPalette( aBmpPal
);
477 const long nWidth
= pAcc
->Width();
478 const long nHeight
= pAcc
->Height();
480 for( long nX
= 0L; nX
< nWidth
; nX
++ )
481 for( long nY
= 0L; nY
< nHeight
; nY
++ )
482 pAcc
->SetPixel( nY
, nX
, pAcc
->GetPixel( nY
, nX
).Invert() );
485 mxImpBmp
->ImplInvalidateChecksum();
493 bool Bitmap::Mirror( BmpMirrorFlags nMirrorFlags
)
495 bool bHorz( nMirrorFlags
& BmpMirrorFlags::Horizontal
);
496 bool bVert( nMirrorFlags
& BmpMirrorFlags::Vertical
);
499 if( bHorz
&& !bVert
)
501 ScopedWriteAccess
pAcc(*this);
505 const long nWidth
= pAcc
->Width();
506 const long nHeight
= pAcc
->Height();
507 const long nWidth1
= nWidth
- 1L;
508 const long nWidth_2
= nWidth
>> 1L;
510 for( long nY
= 0L; nY
< nHeight
; nY
++ )
512 for( long nX
= 0L, nOther
= nWidth1
; nX
< nWidth_2
; nX
++, nOther
-- )
514 const BitmapColor
aTemp( pAcc
->GetPixel( nY
, nX
) );
516 pAcc
->SetPixel( nY
, nX
, pAcc
->GetPixel( nY
, nOther
) );
517 pAcc
->SetPixel( nY
, nOther
, aTemp
);
525 else if( bVert
&& !bHorz
)
527 ScopedWriteAccess
pAcc(*this);
531 const long nScanSize
= pAcc
->GetScanlineSize();
532 std::unique_ptr
<sal_uInt8
[]> pBuffer(new sal_uInt8
[ nScanSize
]);
533 const long nHeight
= pAcc
->Height();
534 const long nHeight1
= nHeight
- 1L;
535 const long nHeight_2
= nHeight
>> 1L;
537 for( long nY
= 0L, nOther
= nHeight1
; nY
< nHeight_2
; nY
++, nOther
-- )
539 memcpy( pBuffer
.get(), pAcc
->GetScanline( nY
), nScanSize
);
540 memcpy( pAcc
->GetScanline( nY
), pAcc
->GetScanline( nOther
), nScanSize
);
541 memcpy( pAcc
->GetScanline( nOther
), pBuffer
.get(), nScanSize
);
548 else if( bHorz
&& bVert
)
550 ScopedWriteAccess
pAcc(*this);
554 const long nWidth
= pAcc
->Width();
555 const long nWidth1
= nWidth
- 1L;
556 const long nHeight
= pAcc
->Height();
557 long nHeight_2
= nHeight
>> 1;
559 for( long nY
= 0L, nOtherY
= nHeight
- 1L; nY
< nHeight_2
; nY
++, nOtherY
-- )
561 for( long nX
= 0L, nOtherX
= nWidth1
; nX
< nWidth
; nX
++, nOtherX
-- )
563 const BitmapColor
aTemp( pAcc
->GetPixel( nY
, nX
) );
565 pAcc
->SetPixel( nY
, nX
, pAcc
->GetPixel( nOtherY
, nOtherX
) );
566 pAcc
->SetPixel( nOtherY
, nOtherX
, aTemp
);
570 // ggf. noch mittlere Zeile horizontal spiegeln
573 for( long nX
= 0L, nOtherX
= nWidth1
, nWidth_2
= nWidth
>> 1; nX
< nWidth_2
; nX
++, nOtherX
-- )
575 const BitmapColor
aTemp( pAcc
->GetPixel( nHeight_2
, nX
) );
576 pAcc
->SetPixel( nHeight_2
, nX
, pAcc
->GetPixel( nHeight_2
, nOtherX
) );
577 pAcc
->SetPixel( nHeight_2
, nOtherX
, aTemp
);
591 bool Bitmap::Rotate( long nAngle10
, const Color
& rFillColor
)
596 nAngle10
= ( nAngle10
< 0L ) ? ( 3599L + nAngle10
) : nAngle10
;
600 else if( 1800L == nAngle10
)
601 bRet
= Mirror( BmpMirrorFlags::Horizontal
| BmpMirrorFlags::Vertical
);
604 ScopedReadAccess
pReadAcc(*this);
609 const Size
aSizePix( GetSizePixel() );
611 if( ( 900L == nAngle10
) || ( 2700L == nAngle10
) )
613 const Size
aNewSizePix( aSizePix
.Height(), aSizePix
.Width() );
614 Bitmap
aNewBmp( aNewSizePix
, GetBitCount(), &pReadAcc
->GetPalette() );
615 ScopedWriteAccess
pWriteAcc(aNewBmp
);
619 const long nWidth
= aSizePix
.Width();
620 const long nWidth1
= nWidth
- 1L;
621 const long nHeight
= aSizePix
.Height();
622 const long nHeight1
= nHeight
- 1L;
623 const long nNewWidth
= aNewSizePix
.Width();
624 const long nNewHeight
= aNewSizePix
.Height();
626 if( 900L == nAngle10
)
628 for( long nY
= 0L, nOtherX
= nWidth1
; nY
< nNewHeight
; nY
++, nOtherX
-- )
629 for( long nX
= 0L, nOtherY
= 0L; nX
< nNewWidth
; nX
++ )
630 pWriteAcc
->SetPixel( nY
, nX
, pReadAcc
->GetPixel( nOtherY
++, nOtherX
) );
632 else if( 2700L == nAngle10
)
634 for( long nY
= 0L, nOtherX
= 0L; nY
< nNewHeight
; nY
++, nOtherX
++ )
635 for( long nX
= 0L, nOtherY
= nHeight1
; nX
< nNewWidth
; nX
++ )
636 pWriteAcc
->SetPixel( nY
, nX
, pReadAcc
->GetPixel( nOtherY
--, nOtherX
) );
642 aRotatedBmp
= aNewBmp
;
647 tools::Rectangle
aTmpRectangle( aTmpPoint
, aSizePix
);
648 tools::Polygon
aPoly( aTmpRectangle
);
649 aPoly
.Rotate( aTmpPoint
, (sal_uInt16
) nAngle10
);
651 tools::Rectangle
aNewBound( aPoly
.GetBoundRect() );
652 const Size
aNewSizePix( aNewBound
.GetSize() );
653 Bitmap
aNewBmp( aNewSizePix
, GetBitCount(), &pReadAcc
->GetPalette() );
654 ScopedWriteAccess
pWriteAcc(aNewBmp
);
658 const BitmapColor
aFillColor( pWriteAcc
->GetBestMatchingColor( rFillColor
) );
659 const double fCosAngle
= cos( nAngle10
* F_PI1800
);
660 const double fSinAngle
= sin( nAngle10
* F_PI1800
);
661 const double fXMin
= aNewBound
.Left();
662 const double fYMin
= aNewBound
.Top();
663 const long nWidth
= aSizePix
.Width();
664 const long nHeight
= aSizePix
.Height();
665 const long nNewWidth
= aNewSizePix
.Width();
666 const long nNewHeight
= aNewSizePix
.Height();
671 std::unique_ptr
<long[]> pCosX(new long[ nNewWidth
]);
672 std::unique_ptr
<long[]> pSinX(new long[ nNewWidth
]);
673 std::unique_ptr
<long[]> pCosY(new long[ nNewHeight
]);
674 std::unique_ptr
<long[]> pSinY(new long[ nNewHeight
]);
676 for ( nX
= 0; nX
< nNewWidth
; nX
++ )
678 const double fTmp
= ( fXMin
+ nX
) * 64.;
680 pCosX
[ nX
] = FRound( fCosAngle
* fTmp
);
681 pSinX
[ nX
] = FRound( fSinAngle
* fTmp
);
684 for ( nY
= 0; nY
< nNewHeight
; nY
++ )
686 const double fTmp
= ( fYMin
+ nY
) * 64.;
688 pCosY
[ nY
] = FRound( fCosAngle
* fTmp
);
689 pSinY
[ nY
] = FRound( fSinAngle
* fTmp
);
692 for( nY
= 0L; nY
< nNewHeight
; nY
++ )
694 long nSinY
= pSinY
[ nY
];
695 long nCosY
= pCosY
[ nY
];
697 for( nX
= 0L; nX
< nNewWidth
; nX
++ )
699 nRotX
= ( pCosX
[ nX
] - nSinY
) >> 6;
700 nRotY
= ( pSinX
[ nX
] + nCosY
) >> 6;
702 if ( ( nRotX
> -1L ) && ( nRotX
< nWidth
) && ( nRotY
> -1L ) && ( nRotY
< nHeight
) )
703 pWriteAcc
->SetPixel( nY
, nX
, pReadAcc
->GetPixel( nRotY
, nRotX
) );
705 pWriteAcc
->SetPixel( nY
, nX
, aFillColor
);
712 aRotatedBmp
= aNewBmp
;
718 bRet
= !!aRotatedBmp
;
720 ImplAssignWithSize( aRotatedBmp
);
726 bool Bitmap::Crop( const tools::Rectangle
& rRectPixel
)
728 const Size
aSizePix( GetSizePixel() );
729 tools::Rectangle
aRect( rRectPixel
);
732 aRect
.Intersection( tools::Rectangle( Point(), aSizePix
) );
734 if( !aRect
.IsEmpty() && aSizePix
!= aRect
.GetSize())
736 ScopedReadAccess
pReadAcc(*this);
741 const tools::Rectangle
aNewRect( aTmpPoint
, aRect
.GetSize() );
742 Bitmap
aNewBmp( aNewRect
.GetSize(), GetBitCount(), &pReadAcc
->GetPalette() );
743 ScopedWriteAccess
pWriteAcc(aNewBmp
);
747 const long nOldX
= aRect
.Left();
748 const long nOldY
= aRect
.Top();
749 const long nNewWidth
= aNewRect
.GetWidth();
750 const long nNewHeight
= aNewRect
.GetHeight();
752 for( long nY
= 0, nY2
= nOldY
; nY
< nNewHeight
; nY
++, nY2
++ )
753 for( long nX
= 0, nX2
= nOldX
; nX
< nNewWidth
; nX
++, nX2
++ )
754 pWriteAcc
->SetPixel( nY
, nX
, pReadAcc
->GetPixel( nY2
, nX2
) );
763 ImplAssignWithSize( aNewBmp
);
770 bool Bitmap::CopyPixel( const tools::Rectangle
& rRectDst
,
771 const tools::Rectangle
& rRectSrc
, const Bitmap
* pBmpSrc
)
773 const Size
aSizePix( GetSizePixel() );
774 tools::Rectangle
aRectDst( rRectDst
);
777 aRectDst
.Intersection( tools::Rectangle( Point(), aSizePix
) );
779 if( !aRectDst
.IsEmpty() )
781 if( pBmpSrc
&& ( *pBmpSrc
!= *this ) )
783 Bitmap
* pSrc
= const_cast<Bitmap
*>(pBmpSrc
);
784 const Size
aCopySizePix( pSrc
->GetSizePixel() );
785 tools::Rectangle
aRectSrc( rRectSrc
);
786 const sal_uInt16 nSrcBitCount
= pBmpSrc
->GetBitCount();
787 const sal_uInt16 nDstBitCount
= GetBitCount();
789 if( nSrcBitCount
> nDstBitCount
)
793 if( ( nSrcBitCount
== 24 ) && ( nDstBitCount
< 24 ) )
794 Convert( BmpConversion::N24Bit
);
795 else if( ( nSrcBitCount
== 8 ) && ( nDstBitCount
< 8 ) )
797 Convert( BmpConversion::N8BitColors
);
800 else if( ( nSrcBitCount
== 4 ) && ( nDstBitCount
< 4 ) )
802 Convert( BmpConversion::N4BitColors
);
808 ScopedReadAccess
pSrcAcc(*pSrc
);
809 ScopedWriteAccess
pDstAcc(*this);
811 if( pSrcAcc
&& pDstAcc
)
813 const int nSrcCount
= pDstAcc
->GetPaletteEntryCount();
814 const int nDstCount
= 1 << nDstBitCount
;
816 for (int i
= 0; ( i
< nSrcCount
) && ( nNextIndex
< nSrcCount
); ++i
)
818 const BitmapColor
& rSrcCol
= pSrcAcc
->GetPaletteColor( (sal_uInt16
) i
);
822 for (int j
= 0; j
< nDstCount
; ++j
)
824 if( rSrcCol
== pDstAcc
->GetPaletteColor( (sal_uInt16
) j
) )
832 pDstAcc
->SetPaletteColor( (sal_uInt16
) nNextIndex
++, rSrcCol
);
838 aRectSrc
.Intersection( tools::Rectangle( Point(), aCopySizePix
) );
840 if( !aRectSrc
.IsEmpty() )
842 ScopedReadAccess
pReadAcc(*pSrc
);
846 ScopedWriteAccess
pWriteAcc(*this);
850 const long nWidth
= std::min( aRectSrc
.GetWidth(), aRectDst
.GetWidth() );
851 const long nHeight
= std::min( aRectSrc
.GetHeight(), aRectDst
.GetHeight() );
852 const long nSrcEndX
= aRectSrc
.Left() + nWidth
;
853 const long nSrcEndY
= aRectSrc
.Top() + nHeight
;
854 long nDstY
= aRectDst
.Top();
856 if( pReadAcc
->HasPalette() && pWriteAcc
->HasPalette() )
858 const sal_uInt16 nCount
= pReadAcc
->GetPaletteEntryCount();
859 std::unique_ptr
<sal_uInt8
[]> pMap(new sal_uInt8
[ nCount
]);
861 // Create index map for the color table, as the bitmap should be copied
862 // retaining it's color information relatively well
863 for( sal_uInt16 i
= 0; i
< nCount
; i
++ )
864 pMap
[ i
] = (sal_uInt8
) pWriteAcc
->GetBestPaletteIndex( pReadAcc
->GetPaletteColor( i
) );
866 for( long nSrcY
= aRectSrc
.Top(); nSrcY
< nSrcEndY
; nSrcY
++, nDstY
++ )
867 for( long nSrcX
= aRectSrc
.Left(), nDstX
= aRectDst
.Left(); nSrcX
< nSrcEndX
; nSrcX
++, nDstX
++ )
868 pWriteAcc
->SetPixelIndex( nDstY
, nDstX
, pMap
[ pReadAcc
->GetPixelIndex( nSrcY
, nSrcX
) ] );
870 else if( pReadAcc
->HasPalette() )
872 for( long nSrcY
= aRectSrc
.Top(); nSrcY
< nSrcEndY
; nSrcY
++, nDstY
++ )
873 for( long nSrcX
= aRectSrc
.Left(), nDstX
= aRectDst
.Left(); nSrcX
< nSrcEndX
; nSrcX
++, nDstX
++ )
874 pWriteAcc
->SetPixel( nDstY
, nDstX
, pReadAcc
->GetPaletteColor( pReadAcc
->GetPixelIndex( nSrcY
, nSrcX
) ) );
877 for( long nSrcY
= aRectSrc
.Top(); nSrcY
< nSrcEndY
; nSrcY
++, nDstY
++ )
878 for( long nSrcX
= aRectSrc
.Left(), nDstX
= aRectDst
.Left(); nSrcX
< nSrcEndX
; nSrcX
++, nDstX
++ )
879 pWriteAcc
->SetPixel( nDstY
, nDstX
, pReadAcc
->GetPixel( nSrcY
, nSrcX
) );
882 bRet
= ( nWidth
> 0L ) && ( nHeight
> 0L );
891 tools::Rectangle
aRectSrc( rRectSrc
);
893 aRectSrc
.Intersection( tools::Rectangle( Point(), aSizePix
) );
895 if( !aRectSrc
.IsEmpty() && ( aRectSrc
!= aRectDst
) )
897 ScopedWriteAccess
pWriteAcc(*this);
901 const long nWidth
= std::min( aRectSrc
.GetWidth(), aRectDst
.GetWidth() );
902 const long nHeight
= std::min( aRectSrc
.GetHeight(), aRectDst
.GetHeight() );
903 const long nSrcX
= aRectSrc
.Left();
904 const long nSrcY
= aRectSrc
.Top();
905 const long nSrcEndX1
= nSrcX
+ nWidth
- 1L;
906 const long nSrcEndY1
= nSrcY
+ nHeight
- 1L;
907 const long nDstX
= aRectDst
.Left();
908 const long nDstY
= aRectDst
.Top();
909 const long nDstEndX1
= nDstX
+ nWidth
- 1L;
910 const long nDstEndY1
= nDstY
+ nHeight
- 1L;
912 if( ( nDstX
<= nSrcX
) && ( nDstY
<= nSrcY
) )
914 for( long nY
= nSrcY
, nYN
= nDstY
; nY
<= nSrcEndY1
; nY
++, nYN
++ )
915 for( long nX
= nSrcX
, nXN
= nDstX
; nX
<= nSrcEndX1
; nX
++, nXN
++ )
916 pWriteAcc
->SetPixel( nYN
, nXN
, pWriteAcc
->GetPixel( nY
, nX
) );
918 else if( ( nDstX
<= nSrcX
) && ( nDstY
>= nSrcY
) )
920 for( long nY
= nSrcEndY1
, nYN
= nDstEndY1
; nY
>= nSrcY
; nY
--, nYN
-- )
921 for( long nX
= nSrcX
, nXN
= nDstX
; nX
<= nSrcEndX1
; nX
++, nXN
++ )
922 pWriteAcc
->SetPixel( nYN
, nXN
, pWriteAcc
->GetPixel( nY
, nX
) );
924 else if( ( nDstX
>= nSrcX
) && ( nDstY
<= nSrcY
) )
926 for( long nY
= nSrcY
, nYN
= nDstY
; nY
<= nSrcEndY1
; nY
++, nYN
++ )
927 for( long nX
= nSrcEndX1
, nXN
= nDstEndX1
; nX
>= nSrcX
; nX
--, nXN
-- )
928 pWriteAcc
->SetPixel( nYN
, nXN
, pWriteAcc
->GetPixel( nY
, nX
) );
932 for( long nY
= nSrcEndY1
, nYN
= nDstEndY1
; nY
>= nSrcY
; nY
--, nYN
-- )
933 for( long nX
= nSrcEndX1
, nXN
= nDstEndX1
; nX
>= nSrcX
; nX
--, nXN
-- )
934 pWriteAcc
->SetPixel( nYN
, nXN
, pWriteAcc
->GetPixel( nY
, nX
) );
947 bool Bitmap::CopyPixel_AlphaOptimized( const tools::Rectangle
& rRectDst
, const tools::Rectangle
& rRectSrc
,
948 const Bitmap
* pBmpSrc
)
950 // Note: this code is copied from Bitmap::CopyPixel but avoids any palette lookups
951 // This optimization is possible because the palettes of AlphaMasks are always identical (8bit GreyPalette, see ctor)
952 const Size
aSizePix( GetSizePixel() );
953 tools::Rectangle
aRectDst( rRectDst
);
956 aRectDst
.Intersection( tools::Rectangle( Point(), aSizePix
) );
958 if( !aRectDst
.IsEmpty() )
960 if( pBmpSrc
&& ( *pBmpSrc
!= *this ) )
962 Bitmap
* pSrc
= const_cast<Bitmap
*>(pBmpSrc
);
963 const Size
aCopySizePix( pSrc
->GetSizePixel() );
964 tools::Rectangle
aRectSrc( rRectSrc
);
966 aRectSrc
.Intersection( tools::Rectangle( Point(), aCopySizePix
) );
968 if( !aRectSrc
.IsEmpty() )
970 ScopedReadAccess
pReadAcc(*pSrc
);
974 ScopedWriteAccess
pWriteAcc(*this);
978 const long nWidth
= std::min( aRectSrc
.GetWidth(), aRectDst
.GetWidth() );
979 const long nHeight
= std::min( aRectSrc
.GetHeight(), aRectDst
.GetHeight() );
980 const long nSrcEndX
= aRectSrc
.Left() + nWidth
;
981 const long nSrcEndY
= aRectSrc
.Top() + nHeight
;
982 long nDstY
= aRectDst
.Top();
984 for( long nSrcY
= aRectSrc
.Top(); nSrcY
< nSrcEndY
; nSrcY
++, nDstY
++ )
985 for( long nSrcX
= aRectSrc
.Left(), nDstX
= aRectDst
.Left(); nSrcX
< nSrcEndX
; nSrcX
++, nDstX
++ )
986 pWriteAcc
->SetPixel( nDstY
, nDstX
, pReadAcc
->GetPixel( nSrcY
, nSrcX
) );
989 bRet
= ( nWidth
> 0L ) && ( nHeight
> 0L );
998 tools::Rectangle
aRectSrc( rRectSrc
);
1000 aRectSrc
.Intersection( tools::Rectangle( Point(), aSizePix
) );
1002 if( !aRectSrc
.IsEmpty() && ( aRectSrc
!= aRectDst
) )
1004 ScopedWriteAccess
pWriteAcc(*this);
1008 const long nWidth
= std::min( aRectSrc
.GetWidth(), aRectDst
.GetWidth() );
1009 const long nHeight
= std::min( aRectSrc
.GetHeight(), aRectDst
.GetHeight() );
1010 const long nSrcX
= aRectSrc
.Left();
1011 const long nSrcY
= aRectSrc
.Top();
1012 const long nSrcEndX1
= nSrcX
+ nWidth
- 1L;
1013 const long nSrcEndY1
= nSrcY
+ nHeight
- 1L;
1014 const long nDstX
= aRectDst
.Left();
1015 const long nDstY
= aRectDst
.Top();
1016 const long nDstEndX1
= nDstX
+ nWidth
- 1L;
1017 const long nDstEndY1
= nDstY
+ nHeight
- 1L;
1019 if( ( nDstX
<= nSrcX
) && ( nDstY
<= nSrcY
) )
1021 for( long nY
= nSrcY
, nYN
= nDstY
; nY
<= nSrcEndY1
; nY
++, nYN
++ )
1022 for( long nX
= nSrcX
, nXN
= nDstX
; nX
<= nSrcEndX1
; nX
++, nXN
++ )
1023 pWriteAcc
->SetPixel( nYN
, nXN
, pWriteAcc
->GetPixel( nY
, nX
) );
1025 else if( ( nDstX
<= nSrcX
) && ( nDstY
>= nSrcY
) )
1027 for( long nY
= nSrcEndY1
, nYN
= nDstEndY1
; nY
>= nSrcY
; nY
--, nYN
-- )
1028 for( long nX
= nSrcX
, nXN
= nDstX
; nX
<= nSrcEndX1
; nX
++, nXN
++ )
1029 pWriteAcc
->SetPixel( nYN
, nXN
, pWriteAcc
->GetPixel( nY
, nX
) );
1031 else if( ( nDstX
>= nSrcX
) && ( nDstY
<= nSrcY
) )
1033 for( long nY
= nSrcY
, nYN
= nDstY
; nY
<= nSrcEndY1
; nY
++, nYN
++ )
1034 for( long nX
= nSrcEndX1
, nXN
= nDstEndX1
; nX
>= nSrcX
; nX
--, nXN
-- )
1035 pWriteAcc
->SetPixel( nYN
, nXN
, pWriteAcc
->GetPixel( nY
, nX
) );
1039 for( long nY
= nSrcEndY1
, nYN
= nDstEndY1
; nY
>= nSrcY
; nY
--, nYN
-- )
1040 for( long nX
= nSrcEndX1
, nXN
= nDstEndX1
; nX
>= nSrcX
; nX
--, nXN
-- )
1041 pWriteAcc
->SetPixel( nYN
, nXN
, pWriteAcc
->GetPixel( nY
, nX
) );
1055 bool Bitmap::Expand( sal_uLong nDX
, sal_uLong nDY
, const Color
* pInitColor
)
1061 const Size
aSizePixel( GetSizePixel() );
1062 const long nWidth
= aSizePixel
.Width();
1063 const long nHeight
= aSizePixel
.Height();
1064 const Size
aNewSize( nWidth
+ nDX
, nHeight
+ nDY
);
1065 ScopedReadAccess
pReadAcc(*this);
1069 BitmapPalette
aBmpPal( pReadAcc
->GetPalette() );
1070 Bitmap
aNewBmp( aNewSize
, GetBitCount(), &aBmpPal
);
1071 ScopedWriteAccess
pWriteAcc(aNewBmp
);
1076 const long nNewX
= nWidth
;
1077 const long nNewY
= nHeight
;
1078 const long nNewWidth
= pWriteAcc
->Width();
1079 const long nNewHeight
= pWriteAcc
->Height();
1084 aColor
= pWriteAcc
->GetBestMatchingColor( *pInitColor
);
1086 for( nY
= 0L; nY
< nHeight
; nY
++ )
1088 pWriteAcc
->CopyScanline( nY
, *pReadAcc
);
1090 if( pInitColor
&& nDX
)
1091 for( nX
= nNewX
; nX
< nNewWidth
; nX
++ )
1092 pWriteAcc
->SetPixel( nY
, nX
, aColor
);
1095 if( pInitColor
&& nDY
)
1096 for( nY
= nNewY
; nY
< nNewHeight
; nY
++ )
1097 for( nX
= 0; nX
< nNewWidth
; nX
++ )
1098 pWriteAcc
->SetPixel( nY
, nX
, aColor
);
1107 ImplAssignWithSize( aNewBmp
);
1114 Bitmap
Bitmap::CreateMask( const Color
& rTransColor
, sal_uLong nTol
) const
1116 ScopedReadAccess
pReadAcc(const_cast<Bitmap
&>(*this));
1118 if (!nTol
&& pReadAcc
&& (pReadAcc
->GetScanlineFormat() == ScanlineFormat::N1BitLsbPal
|| pReadAcc
->GetScanlineFormat() == ScanlineFormat::N1BitMsbPal
)
1119 && pReadAcc
->GetBestMatchingColor(Color(COL_WHITE
)) == pReadAcc
->GetBestMatchingColor(rTransColor
))
1121 //if we're a 1 bit pixel already, and the transcolor matches the color that would replace it already already, then just return a copy
1125 Bitmap
aNewBmp(GetSizePixel(), 1);
1126 ScopedWriteAccess
pWriteAcc(aNewBmp
);
1129 if (pWriteAcc
&& pReadAcc
)
1131 const long nWidth
= pReadAcc
->Width();
1132 const long nHeight
= pReadAcc
->Height();
1133 const BitmapColor
aBlack( pWriteAcc
->GetBestMatchingColor( Color( COL_BLACK
) ) );
1134 const BitmapColor
aWhite( pWriteAcc
->GetBestMatchingColor( Color( COL_WHITE
) ) );
1138 const BitmapColor
aTest( pReadAcc
->GetBestMatchingColor( rTransColor
) );
1141 if( pReadAcc
->GetScanlineFormat() == ScanlineFormat::N4BitMsnPal
||
1142 pReadAcc
->GetScanlineFormat() == ScanlineFormat::N4BitLsnPal
)
1144 // optimized for 4Bit-MSN/LSN source palette
1145 const sal_uInt8 cTest
= aTest
.GetIndex();
1146 const long nShiftInit
= ( ( pReadAcc
->GetScanlineFormat() == ScanlineFormat::N4BitMsnPal
) ? 4 : 0 );
1148 if( pWriteAcc
->GetScanlineFormat() == ScanlineFormat::N1BitMsbPal
&&
1149 aWhite
.GetIndex() == 1 )
1151 // optimized for 1Bit-MSB destination palette
1152 for( nY
= 0L; nY
< nHeight
; nY
++ )
1154 Scanline pSrc
= pReadAcc
->GetScanline( nY
);
1155 Scanline pDst
= pWriteAcc
->GetScanline( nY
);
1157 for( nX
= 0L, nShift
= nShiftInit
; nX
< nWidth
; nX
++, nShift
^= 4 )
1159 if( cTest
== ( ( pSrc
[ nX
>> 1 ] >> nShift
) & 0x0f ) )
1160 pDst
[ nX
>> 3 ] |= 1 << ( 7 - ( nX
& 7 ) );
1162 pDst
[ nX
>> 3 ] &= ~( 1 << ( 7 - ( nX
& 7 ) ) );
1168 for( nY
= 0L; nY
< nHeight
; nY
++ )
1170 Scanline pSrc
= pReadAcc
->GetScanline( nY
);
1172 for( nX
= 0L, nShift
= nShiftInit
; nX
< nWidth
; nX
++, nShift
^= 4 )
1174 if( cTest
== ( ( pSrc
[ nX
>> 1 ] >> nShift
) & 0x0f ) )
1175 pWriteAcc
->SetPixel( nY
, nX
, aWhite
);
1177 pWriteAcc
->SetPixel( nY
, nX
, aBlack
);
1182 else if( pReadAcc
->GetScanlineFormat() == ScanlineFormat::N8BitPal
)
1184 // optimized for 8Bit source palette
1185 const sal_uInt8 cTest
= aTest
.GetIndex();
1187 if( pWriteAcc
->GetScanlineFormat() == ScanlineFormat::N1BitMsbPal
&&
1188 aWhite
.GetIndex() == 1 )
1190 // optimized for 1Bit-MSB destination palette
1191 for( nY
= 0L; nY
< nHeight
; nY
++ )
1193 Scanline pSrc
= pReadAcc
->GetScanline( nY
);
1194 Scanline pDst
= pWriteAcc
->GetScanline( nY
);
1195 for( nX
= 0L; nX
< nWidth
; nX
++ )
1197 if( cTest
== pSrc
[ nX
] )
1198 pDst
[ nX
>> 3 ] |= 1 << ( 7 - ( nX
& 7 ) );
1200 pDst
[ nX
>> 3 ] &= ~( 1 << ( 7 - ( nX
& 7 ) ) );
1206 for( nY
= 0L; nY
< nHeight
; nY
++ )
1208 Scanline pSrc
= pReadAcc
->GetScanline( nY
);
1209 for( nX
= 0L; nX
< nWidth
; nX
++ )
1211 if( cTest
== pSrc
[ nX
] )
1212 pWriteAcc
->SetPixel( nY
, nX
, aWhite
);
1214 pWriteAcc
->SetPixel( nY
, nX
, aBlack
);
1222 for( nY
= 0L; nY
< nHeight
; nY
++ )
1224 for( nX
= 0L; nX
< nWidth
; nX
++ )
1226 if( aTest
== pReadAcc
->GetPixel( nY
, nX
) )
1227 pWriteAcc
->SetPixel( nY
, nX
, aWhite
);
1229 pWriteAcc
->SetPixel( nY
, nX
, aBlack
);
1238 const long nMinR
= MinMax
<long>(rTransColor
.GetRed() - nTol
, 0, 255);
1239 const long nMaxR
= MinMax
<long>(rTransColor
.GetRed() + nTol
, 0, 255);
1240 const long nMinG
= MinMax
<long>(rTransColor
.GetGreen() - nTol
, 0, 255);
1241 const long nMaxG
= MinMax
<long>(rTransColor
.GetGreen() + nTol
, 0, 255);
1242 const long nMinB
= MinMax
<long>(rTransColor
.GetBlue() - nTol
, 0, 255);
1243 const long nMaxB
= MinMax
<long>(rTransColor
.GetBlue() + nTol
, 0, 255);
1245 if( pReadAcc
->HasPalette() )
1247 for( long nY
= 0L; nY
< nHeight
; nY
++ )
1249 for( long nX
= 0L; nX
< nWidth
; nX
++ )
1251 aCol
= pReadAcc
->GetPaletteColor( pReadAcc
->GetPixelIndex( nY
, nX
) );
1253 nG
= aCol
.GetGreen();
1254 nB
= aCol
.GetBlue();
1256 if( nMinR
<= nR
&& nMaxR
>= nR
&&
1257 nMinG
<= nG
&& nMaxG
>= nG
&&
1258 nMinB
<= nB
&& nMaxB
>= nB
)
1260 pWriteAcc
->SetPixel( nY
, nX
, aWhite
);
1263 pWriteAcc
->SetPixel( nY
, nX
, aBlack
);
1269 for( long nY
= 0L; nY
< nHeight
; nY
++ )
1271 for( long nX
= 0L; nX
< nWidth
; nX
++ )
1273 aCol
= pReadAcc
->GetPixel( nY
, nX
);
1275 nG
= aCol
.GetGreen();
1276 nB
= aCol
.GetBlue();
1278 if( nMinR
<= nR
&& nMaxR
>= nR
&&
1279 nMinG
<= nG
&& nMaxG
>= nG
&&
1280 nMinB
<= nB
&& nMaxB
>= nB
)
1282 pWriteAcc
->SetPixel( nY
, nX
, aWhite
);
1285 pWriteAcc
->SetPixel( nY
, nX
, aBlack
);
1299 aNewBmp
.maPrefSize
= maPrefSize
;
1300 aNewBmp
.maPrefMapMode
= maPrefMapMode
;
1308 vcl::Region
Bitmap::CreateRegion( const Color
& rColor
, const tools::Rectangle
& rRect
) const
1310 vcl::Region aRegion
;
1311 tools::Rectangle
aRect( rRect
);
1312 ScopedReadAccess
pReadAcc(const_cast<Bitmap
&>(*this));
1314 aRect
.Intersection( tools::Rectangle( Point(), GetSizePixel() ) );
1319 //Rectangle aSubRect;
1320 const long nLeft
= aRect
.Left();
1321 const long nTop
= aRect
.Top();
1322 const long nRight
= aRect
.Right();
1323 const long nBottom
= aRect
.Bottom();
1324 const BitmapColor
aMatch( pReadAcc
->GetBestMatchingColor( rColor
) );
1326 //RectangleVector aRectangles;
1327 //aRegion.ImplBeginAddRect();
1328 std::vector
< long > aLine
;
1332 for( ; nY
<= nBottom
; nY
++ )
1334 //aSubRect.Top() = aSubRect.Bottom() = nY;
1335 std::vector
< long > aNewLine
;
1338 for( ; nX
<= nRight
; )
1340 while( ( nX
<= nRight
) && ( aMatch
!= pReadAcc
->GetPixel( nY
, nX
) ) )
1345 aNewLine
.push_back(nX
);
1346 //aSubRect.Left() = nX;
1348 while( ( nX
<= nRight
) && ( aMatch
== pReadAcc
->GetPixel( nY
, nX
) ) )
1351 //aSubRect.Right() = nX - 1L;
1352 aNewLine
.push_back(nX
- 1);
1354 //aRegion.ImplAddRect( aSubRect );
1355 //aRectangles.push_back(aSubRect);
1356 //aRegion.Union(aSubRect);
1360 if(aNewLine
!= aLine
)
1362 // need to write aLine, it's different from the next line
1365 tools::Rectangle aSubRect
;
1367 // enter y values and proceed ystart
1368 aSubRect
.Top() = nYStart
;
1369 aSubRect
.Bottom() = nY
? nY
- 1 : 0;
1371 for(size_t a(0); a
< aLine
.size();)
1373 aSubRect
.Left() = aLine
[a
++];
1374 aSubRect
.Right() = aLine
[a
++];
1375 aRegion
.Union(aSubRect
);
1379 // copy line as new line
1385 // write last line if used
1388 tools::Rectangle aSubRect
;
1391 aSubRect
.Top() = nYStart
;
1392 aSubRect
.Bottom() = nY
? nY
- 1 : 0;
1394 for(size_t a(0); a
< aLine
.size();)
1396 aSubRect
.Left() = aLine
[a
++];
1397 aSubRect
.Right() = aLine
[a
++];
1398 aRegion
.Union(aSubRect
);
1402 //aRegion.ImplEndAddRect();
1403 //aRegion.SetRegionRectangles(aRectangles);
1413 bool Bitmap::Replace( const Bitmap
& rMask
, const Color
& rReplaceColor
)
1415 ScopedReadAccess
pMaskAcc( const_cast<Bitmap
&>(rMask
) );
1416 ScopedWriteAccess
pAcc(*this);
1419 if( pMaskAcc
&& pAcc
)
1421 const long nWidth
= std::min( pMaskAcc
->Width(), pAcc
->Width() );
1422 const long nHeight
= std::min( pMaskAcc
->Height(), pAcc
->Height() );
1423 const BitmapColor
aMaskWhite( pMaskAcc
->GetBestMatchingColor( Color( COL_WHITE
) ) );
1424 BitmapColor aReplace
;
1426 if( pAcc
->HasPalette() )
1428 const sal_uInt16 nActColors
= pAcc
->GetPaletteEntryCount();
1429 const sal_uInt16 nMaxColors
= 1 << pAcc
->GetBitCount();
1431 // default to the nearest color
1432 aReplace
= pAcc
->GetBestMatchingColor( rReplaceColor
);
1434 // for paletted images without a matching palette entry
1435 // look for an unused palette entry (NOTE: expensive!)
1436 if( pAcc
->GetPaletteColor( aReplace
.GetIndex() ) != BitmapColor( rReplaceColor
) )
1438 // if the palette has empty entries use the last one
1439 if( nActColors
< nMaxColors
)
1441 pAcc
->SetPaletteEntryCount( nActColors
+ 1 );
1442 pAcc
->SetPaletteColor( nActColors
, rReplaceColor
);
1443 aReplace
= BitmapColor( (sal_uInt8
) nActColors
);
1447 std::unique_ptr
<bool[]> pFlags(new bool[ nMaxColors
]);
1449 // Set all entries to false
1450 std::fill( pFlags
.get(), pFlags
.get()+nMaxColors
, false );
1452 for( long nY
= 0L; nY
< nHeight
; nY
++ )
1453 for( long nX
= 0L; nX
< nWidth
; nX
++ )
1454 pFlags
[ pAcc
->GetPixelIndex( nY
, nX
) ] = true;
1456 for( sal_uInt16 i
= 0UL; i
< nMaxColors
; i
++ )
1458 // Hurray, we do have an unused entry
1461 pAcc
->SetPaletteColor( i
, rReplaceColor
);
1462 aReplace
= BitmapColor( (sal_uInt8
) i
);
1469 aReplace
= rReplaceColor
;
1471 for( long nY
= 0L; nY
< nHeight
; nY
++ )
1472 for( long nX
= 0L; nX
< nWidth
; nX
++ )
1473 if( pMaskAcc
->GetPixel( nY
, nX
) == aMaskWhite
)
1474 pAcc
->SetPixel( nY
, nX
, aReplace
);
1482 bool Bitmap::Replace( const AlphaMask
& rAlpha
, const Color
& rMergeColor
)
1484 Bitmap
aNewBmp( GetSizePixel(), 24 );
1485 ScopedReadAccess
pAcc(*this);
1486 AlphaMask::ScopedReadAccess
pAlphaAcc(const_cast<AlphaMask
&>(rAlpha
));
1487 ScopedWriteAccess
pNewAcc(aNewBmp
);
1490 if( pAcc
&& pAlphaAcc
&& pNewAcc
)
1493 const long nWidth
= std::min( pAlphaAcc
->Width(), pAcc
->Width() );
1494 const long nHeight
= std::min( pAlphaAcc
->Height(), pAcc
->Height() );
1496 for( long nY
= 0L; nY
< nHeight
; nY
++ )
1498 for( long nX
= 0L; nX
< nWidth
; nX
++ )
1500 aCol
= pAcc
->GetColor( nY
, nX
);
1501 pNewAcc
->SetPixel( nY
, nX
, aCol
.Merge( rMergeColor
, 255 - pAlphaAcc
->GetPixelIndex( nY
, nX
) ) );
1514 const MapMode
aMap( maPrefMapMode
);
1515 const Size
aSize( maPrefSize
);
1519 maPrefMapMode
= aMap
;
1526 bool Bitmap::Replace( const Color
& rSearchColor
, const Color
& rReplaceColor
, sal_uLong nTol
)
1530 // implementation specific replace
1531 std::shared_ptr
<ImpBitmap
> xImpBmp(new ImpBitmap
);
1532 if (xImpBmp
->ImplCreate(*mxImpBmp
) && xImpBmp
->ImplReplace(rSearchColor
, rReplaceColor
, nTol
))
1534 ImplSetImpBitmap(xImpBmp
);
1535 maPrefMapMode
= MapMode( MapUnit::MapPixel
);
1536 maPrefSize
= xImpBmp
->ImplGetSize();
1541 // Bitmaps with 1 bit color depth can cause problems
1542 // if they have other entries than black/white in their palette
1543 if( 1 == GetBitCount() )
1544 Convert( BmpConversion::N4BitColors
);
1546 ScopedWriteAccess
pAcc(*this);
1551 const long nMinR
= MinMax
<long>(rSearchColor
.GetRed() - nTol
, 0, 255);
1552 const long nMaxR
= MinMax
<long>(rSearchColor
.GetRed() + nTol
, 0, 255);
1553 const long nMinG
= MinMax
<long>(rSearchColor
.GetGreen() - nTol
, 0, 255);
1554 const long nMaxG
= MinMax
<long>(rSearchColor
.GetGreen() + nTol
, 0, 255);
1555 const long nMinB
= MinMax
<long>(rSearchColor
.GetBlue() - nTol
, 0, 255);
1556 const long nMaxB
= MinMax
<long>(rSearchColor
.GetBlue() + nTol
, 0, 255);
1558 if( pAcc
->HasPalette() )
1560 for( sal_uInt16 i
= 0, nPalCount
= pAcc
->GetPaletteEntryCount(); i
< nPalCount
; i
++ )
1562 const BitmapColor
& rCol
= pAcc
->GetPaletteColor( i
);
1564 if( nMinR
<= rCol
.GetRed() && nMaxR
>= rCol
.GetRed() &&
1565 nMinG
<= rCol
.GetGreen() && nMaxG
>= rCol
.GetGreen() &&
1566 nMinB
<= rCol
.GetBlue() && nMaxB
>= rCol
.GetBlue() )
1568 pAcc
->SetPaletteColor( i
, rReplaceColor
);
1575 const BitmapColor
aReplace( pAcc
->GetBestMatchingColor( rReplaceColor
) );
1577 for( long nY
= 0L, nHeight
= pAcc
->Height(); nY
< nHeight
; nY
++ )
1579 for( long nX
= 0L, nWidth
= pAcc
->Width(); nX
< nWidth
; nX
++ )
1581 aCol
= pAcc
->GetPixel( nY
, nX
);
1583 if( nMinR
<= aCol
.GetRed() && nMaxR
>= aCol
.GetRed() &&
1584 nMinG
<= aCol
.GetGreen() && nMaxG
>= aCol
.GetGreen() &&
1585 nMinB
<= aCol
.GetBlue() && nMaxB
>= aCol
.GetBlue() )
1587 pAcc
->SetPixel( nY
, nX
, aReplace
);
1600 bool Bitmap::Replace( const Color
* pSearchColors
, const Color
* pReplaceColors
,
1601 sal_uLong nColorCount
, sal_uLong
* _pTols
)
1603 // Bitmaps with 1 bit color depth can cause problems
1604 // if they have other entries than black/white in their palette
1605 if( 1 == GetBitCount() )
1606 Convert( BmpConversion::N4BitColors
);
1608 ScopedWriteAccess
pAcc(*this);
1613 std::unique_ptr
<long[]> pMinR(new long[ nColorCount
]);
1614 std::unique_ptr
<long[]> pMaxR(new long[ nColorCount
]);
1615 std::unique_ptr
<long[]> pMinG(new long[ nColorCount
]);
1616 std::unique_ptr
<long[]> pMaxG(new long[ nColorCount
]);
1617 std::unique_ptr
<long[]> pMinB(new long[ nColorCount
]);
1618 std::unique_ptr
<long[]> pMaxB(new long[ nColorCount
]);
1624 pTols
= new long[ nColorCount
];
1625 memset( pTols
, 0, nColorCount
* sizeof( long ) );
1628 pTols
= reinterpret_cast<long*>(_pTols
);
1630 for( i
= 0UL; i
< nColorCount
; i
++ )
1632 const Color
& rCol
= pSearchColors
[ i
];
1633 const long nTol
= pTols
[ i
];
1635 pMinR
[ i
] = MinMax
<long>(rCol
.GetRed() - nTol
, 0, 255);
1636 pMaxR
[ i
] = MinMax
<long>(rCol
.GetRed() + nTol
, 0, 255);
1637 pMinG
[ i
] = MinMax
<long>(rCol
.GetGreen() - nTol
, 0, 255);
1638 pMaxG
[ i
] = MinMax
<long>(rCol
.GetGreen() + nTol
, 0, 255);
1639 pMinB
[ i
] = MinMax
<long>(rCol
.GetBlue() - nTol
, 0, 255);
1640 pMaxB
[ i
] = MinMax
<long>(rCol
.GetBlue() + nTol
, 0, 255);
1643 if( pAcc
->HasPalette() )
1645 for( sal_uInt16 nEntry
= 0, nPalCount
= pAcc
->GetPaletteEntryCount(); nEntry
< nPalCount
; nEntry
++ )
1647 const BitmapColor
& rCol
= pAcc
->GetPaletteColor( nEntry
);
1649 for( i
= 0UL; i
< nColorCount
; i
++ )
1651 if( pMinR
[ i
] <= rCol
.GetRed() && pMaxR
[ i
] >= rCol
.GetRed() &&
1652 pMinG
[ i
] <= rCol
.GetGreen() && pMaxG
[ i
] >= rCol
.GetGreen() &&
1653 pMinB
[ i
] <= rCol
.GetBlue() && pMaxB
[ i
] >= rCol
.GetBlue() )
1655 pAcc
->SetPaletteColor( nEntry
, pReplaceColors
[ i
] );
1664 std::unique_ptr
<BitmapColor
[]> pReplaces(new BitmapColor
[ nColorCount
]);
1666 for( i
= 0UL; i
< nColorCount
; i
++ )
1667 pReplaces
[ i
] = pAcc
->GetBestMatchingColor( pReplaceColors
[ i
] );
1669 for( long nY
= 0L, nHeight
= pAcc
->Height(); nY
< nHeight
; nY
++ )
1671 for( long nX
= 0L, nWidth
= pAcc
->Width(); nX
< nWidth
; nX
++ )
1673 aCol
= pAcc
->GetPixel( nY
, nX
);
1675 for( i
= 0UL; i
< nColorCount
; i
++ )
1677 if( pMinR
[ i
] <= aCol
.GetRed() && pMaxR
[ i
] >= aCol
.GetRed() &&
1678 pMinG
[ i
] <= aCol
.GetGreen() && pMaxG
[ i
] >= aCol
.GetGreen() &&
1679 pMinB
[ i
] <= aCol
.GetBlue() && pMaxB
[ i
] >= aCol
.GetBlue() )
1681 pAcc
->SetPixel( nY
, nX
, pReplaces
[ i
] );
1699 Bitmap
Bitmap::CreateDisplayBitmap( OutputDevice
* pDisplay
)
1701 Bitmap
aDispBmp( *this );
1703 SalGraphics
* pDispGraphics
= pDisplay
->GetGraphics();
1705 if( mxImpBmp
&& pDispGraphics
)
1707 std::shared_ptr
<ImpBitmap
> xImpDispBmp(new ImpBitmap
);
1708 if (xImpDispBmp
->ImplCreate(*mxImpBmp
, pDispGraphics
))
1709 aDispBmp
.ImplSetImpBitmap(xImpDispBmp
);
1715 bool Bitmap::CombineSimple( const Bitmap
& rMask
, BmpCombine eCombine
)
1717 ScopedReadAccess
pMaskAcc(const_cast<Bitmap
&>(rMask
));
1718 ScopedWriteAccess
pAcc(*this);
1721 if( pMaskAcc
&& pAcc
)
1723 const long nWidth
= std::min( pMaskAcc
->Width(), pAcc
->Width() );
1724 const long nHeight
= std::min( pMaskAcc
->Height(), pAcc
->Height() );
1725 const Color
aColBlack( COL_BLACK
);
1727 BitmapColor aMaskPixel
;
1728 const BitmapColor
aWhite( pAcc
->GetBestMatchingColor( Color( COL_WHITE
) ) );
1729 const BitmapColor
aBlack( pAcc
->GetBestMatchingColor( aColBlack
) );
1730 const BitmapColor
aMaskBlack( pMaskAcc
->GetBestMatchingColor( aColBlack
) );
1734 case BmpCombine::And
:
1736 for( long nY
= 0L; nY
< nHeight
; nY
++ ) for( long nX
= 0L; nX
< nWidth
; nX
++ )
1738 if( pMaskAcc
->GetPixel( nY
, nX
) != aMaskBlack
&& pAcc
->GetPixel( nY
, nX
) != aBlack
)
1739 pAcc
->SetPixel( nY
, nX
, aWhite
);
1741 pAcc
->SetPixel( nY
, nX
, aBlack
);
1746 case BmpCombine::Or
:
1748 for( long nY
= 0L; nY
< nHeight
; nY
++ ) for( long nX
= 0L; nX
< nWidth
; nX
++ )
1750 if( pMaskAcc
->GetPixel( nY
, nX
) != aMaskBlack
|| pAcc
->GetPixel( nY
, nX
) != aBlack
)
1751 pAcc
->SetPixel( nY
, nX
, aWhite
);
1753 pAcc
->SetPixel( nY
, nX
, aBlack
);
1766 // TODO: Have a look at OutputDevice::ImplDrawAlpha() for some
1767 // optimizations. Might even consolidate the code here and there.
1768 bool Bitmap::Blend( const AlphaMask
& rAlpha
, const Color
& rBackgroundColor
)
1770 // Convert to a truecolor bitmap, if we're a paletted one. There's
1771 // room for tradeoff decision here, maybe later for an overload (or a flag)
1772 if( GetBitCount() <= 8 )
1773 Convert( BmpConversion::N24Bit
);
1775 AlphaMask::ScopedReadAccess
pAlphaAcc(const_cast<AlphaMask
&>(rAlpha
));
1777 ScopedWriteAccess
pAcc(*this);
1780 if( pAlphaAcc
&& pAcc
)
1782 const long nWidth
= std::min( pAlphaAcc
->Width(), pAcc
->Width() );
1783 const long nHeight
= std::min( pAlphaAcc
->Height(), pAcc
->Height() );
1785 for( long nY
= 0L; nY
< nHeight
; ++nY
)
1786 for( long nX
= 0L; nX
< nWidth
; ++nX
)
1787 pAcc
->SetPixel( nY
, nX
,
1788 pAcc
->GetPixel( nY
, nX
).Merge( rBackgroundColor
,
1789 255 - pAlphaAcc
->GetPixelIndex( nY
, nX
) ) );
1797 bool Bitmap::MakeMono( sal_uInt8 cThreshold
)
1799 return ImplMakeMono( cThreshold
);
1802 bool Bitmap::GetSystemData( BitmapSystemData
& rData
) const
1807 SalBitmap
* pSalBitmap
= mxImpBmp
->ImplGetSalBitmap();
1809 bRet
= pSalBitmap
->GetSystemData( rData
);
1815 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */