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 <tools/poly.hxx>
21 #include <tools/helpers.hxx>
22 #include <vcl/bitmap.hxx>
23 #include <vcl/bitmapaccess.hxx>
24 #include <vcl/alpha.hxx>
26 #include <bitmapwriteaccess.hxx>
29 #include <salinst.hxx>
34 bool Bitmap::Erase(const Color
& rFillColor
)
39 BitmapScopedWriteAccess
pWriteAcc(*this);
44 const ScanlineFormat nFormat
= pWriteAcc
->GetScanlineFormat();
50 case ScanlineFormat::N1BitMsbPal
:
51 case ScanlineFormat::N1BitLsbPal
:
53 cIndex
= static_cast<sal_uInt8
>(pWriteAcc
->GetBestPaletteIndex(rFillColor
));
54 cIndex
= (cIndex
? 255 : 0);
59 case ScanlineFormat::N4BitMsnPal
:
60 case ScanlineFormat::N4BitLsnPal
:
62 cIndex
= static_cast<sal_uInt8
>(pWriteAcc
->GetBestPaletteIndex(rFillColor
));
63 cIndex
= cIndex
| (cIndex
<< 4);
68 case ScanlineFormat::N8BitPal
:
70 cIndex
= static_cast<sal_uInt8
>(pWriteAcc
->GetBestPaletteIndex(rFillColor
));
75 case ScanlineFormat::N24BitTcBgr
:
76 case ScanlineFormat::N24BitTcRgb
:
78 if (rFillColor
.GetRed() == rFillColor
.GetGreen()
79 && rFillColor
.GetRed() == rFillColor
.GetBlue())
81 cIndex
= rFillColor
.GetRed();
98 const sal_uLong nBufSize
= pWriteAcc
->GetScanlineSize() * pWriteAcc
->Height();
99 memset(pWriteAcc
->GetBuffer(), cIndex
, nBufSize
);
103 const tools::Rectangle
aRect(Point(), Size(pWriteAcc
->Width(), pWriteAcc
->Height()));
104 pWriteAcc
->SetFillColor(rFillColor
);
105 pWriteAcc
->FillRect(aRect
);
114 bool Bitmap::Invert()
116 BitmapScopedWriteAccess
pAcc(*this);
121 if (pAcc
->HasPalette())
123 BitmapPalette
aBmpPal(pAcc
->GetPalette());
124 const sal_uInt16 nCount
= aBmpPal
.GetEntryCount();
126 for (sal_uInt16 i
= 0; i
< nCount
; i
++)
131 pAcc
->SetPalette(aBmpPal
);
135 const long nWidth
= pAcc
->Width();
136 const long nHeight
= pAcc
->Height();
138 for (long nY
= 0; nY
< nHeight
; nY
++)
140 Scanline pScanline
= pAcc
->GetScanline(nY
);
141 for (long nX
= 0; nX
< nWidth
; nX
++)
143 BitmapColor aBmpColor
= pAcc
->GetPixelFromData(pScanline
, nX
);
145 pAcc
->SetPixelOnData(pScanline
, nX
, aBmpColor
);
150 mxSalBmp
->InvalidateChecksum();
158 bool Bitmap::Mirror(BmpMirrorFlags nMirrorFlags
)
160 bool bHorz(nMirrorFlags
& BmpMirrorFlags::Horizontal
);
161 bool bVert(nMirrorFlags
& BmpMirrorFlags::Vertical
);
166 BitmapScopedWriteAccess
pAcc(*this);
170 const long nWidth
= pAcc
->Width();
171 const long nHeight
= pAcc
->Height();
172 const long nWidth1
= nWidth
- 1;
173 const long nWidth_2
= nWidth
>> 1;
175 for (long nY
= 0; nY
< nHeight
; nY
++)
177 Scanline pScanline
= pAcc
->GetScanline(nY
);
178 for (long nX
= 0, nOther
= nWidth1
; nX
< nWidth_2
; nX
++, nOther
--)
180 const BitmapColor
aTemp(pAcc
->GetPixelFromData(pScanline
, nX
));
182 pAcc
->SetPixelOnData(pScanline
, nX
, pAcc
->GetPixelFromData(pScanline
, nOther
));
183 pAcc
->SetPixelOnData(pScanline
, nOther
, aTemp
);
191 else if (bVert
&& !bHorz
)
193 BitmapScopedWriteAccess
pAcc(*this);
197 const long nScanSize
= pAcc
->GetScanlineSize();
198 std::unique_ptr
<sal_uInt8
[]> pBuffer(new sal_uInt8
[nScanSize
]);
199 const long nHeight
= pAcc
->Height();
200 const long nHeight1
= nHeight
- 1;
201 const long nHeight_2
= nHeight
>> 1;
203 for (long nY
= 0, nOther
= nHeight1
; nY
< nHeight_2
; nY
++, nOther
--)
205 memcpy(pBuffer
.get(), pAcc
->GetScanline(nY
), nScanSize
);
206 memcpy(pAcc
->GetScanline(nY
), pAcc
->GetScanline(nOther
), nScanSize
);
207 memcpy(pAcc
->GetScanline(nOther
), pBuffer
.get(), nScanSize
);
214 else if (bHorz
&& bVert
)
216 BitmapScopedWriteAccess
pAcc(*this);
220 const long nWidth
= pAcc
->Width();
221 const long nWidth1
= nWidth
- 1;
222 const long nHeight
= pAcc
->Height();
223 long nHeight_2
= nHeight
>> 1;
225 for (long nY
= 0, nOtherY
= nHeight
- 1; nY
< nHeight_2
; nY
++, nOtherY
--)
227 Scanline pScanline
= pAcc
->GetScanline(nY
);
228 Scanline pScanlineOther
= pAcc
->GetScanline(nOtherY
);
229 for (long nX
= 0, nOtherX
= nWidth1
; nX
< nWidth
; nX
++, nOtherX
--)
231 const BitmapColor
aTemp(pAcc
->GetPixelFromData(pScanline
, nX
));
233 pAcc
->SetPixelOnData(pScanline
, nX
,
234 pAcc
->GetPixelFromData(pScanlineOther
, nOtherX
));
235 pAcc
->SetPixelOnData(pScanlineOther
, nOtherX
, aTemp
);
239 // if necessary, also mirror the middle line horizontally
242 Scanline pScanline
= pAcc
->GetScanline(nHeight_2
);
243 for (long nX
= 0, nOtherX
= nWidth1
, nWidth_2
= nWidth
>> 1; nX
< nWidth_2
;
246 const BitmapColor
aTemp(pAcc
->GetPixelFromData(pScanline
, nX
));
247 pAcc
->SetPixelOnData(pScanline
, nX
, pAcc
->GetPixelFromData(pScanline
, nOtherX
));
248 pAcc
->SetPixelOnData(pScanline
, nOtherX
, aTemp
);
262 bool Bitmap::Rotate(long nAngle10
, const Color
& rFillColor
)
267 nAngle10
= (nAngle10
< 0) ? (3599L + nAngle10
) : nAngle10
;
271 else if (nAngle10
== 1800)
272 bRet
= Mirror(BmpMirrorFlags::Horizontal
| BmpMirrorFlags::Vertical
);
275 ScopedReadAccess
pReadAcc(*this);
280 const Size
aSizePix(GetSizePixel());
282 if (nAngle10
== 900 || nAngle10
== 2700)
284 const Size
aNewSizePix(aSizePix
.Height(), aSizePix
.Width());
285 Bitmap
aNewBmp(aNewSizePix
, GetBitCount(), &pReadAcc
->GetPalette());
286 BitmapScopedWriteAccess
pWriteAcc(aNewBmp
);
290 const long nWidth
= aSizePix
.Width();
291 const long nWidth1
= nWidth
- 1;
292 const long nHeight
= aSizePix
.Height();
293 const long nHeight1
= nHeight
- 1;
294 const long nNewWidth
= aNewSizePix
.Width();
295 const long nNewHeight
= aNewSizePix
.Height();
299 for (long nY
= 0, nOtherX
= nWidth1
; nY
< nNewHeight
; nY
++, nOtherX
--)
301 Scanline pScanline
= pWriteAcc
->GetScanline(nY
);
302 for (long nX
= 0, nOtherY
= 0; nX
< nNewWidth
; nX
++)
304 pWriteAcc
->SetPixelOnData(pScanline
, nX
,
305 pReadAcc
->GetPixel(nOtherY
++, nOtherX
));
309 else if (nAngle10
== 2700)
311 for (long nY
= 0, nOtherX
= 0; nY
< nNewHeight
; nY
++, nOtherX
++)
313 Scanline pScanline
= pWriteAcc
->GetScanline(nY
);
314 for (long nX
= 0, nOtherY
= nHeight1
; nX
< nNewWidth
; nX
++)
316 pWriteAcc
->SetPixelOnData(pScanline
, nX
,
317 pReadAcc
->GetPixel(nOtherY
--, nOtherX
));
325 aRotatedBmp
= aNewBmp
;
330 tools::Rectangle
aTmpRectangle(aTmpPoint
, aSizePix
);
331 tools::Polygon
aPoly(aTmpRectangle
);
332 aPoly
.Rotate(aTmpPoint
, static_cast<sal_uInt16
>(nAngle10
));
334 tools::Rectangle
aNewBound(aPoly
.GetBoundRect());
335 const Size
aNewSizePix(aNewBound
.GetSize());
336 Bitmap
aNewBmp(aNewSizePix
, GetBitCount(), &pReadAcc
->GetPalette());
337 BitmapScopedWriteAccess
pWriteAcc(aNewBmp
);
341 const BitmapColor
aFillColor(pWriteAcc
->GetBestMatchingColor(rFillColor
));
342 const double fCosAngle
= cos(nAngle10
* F_PI1800
);
343 const double fSinAngle
= sin(nAngle10
* F_PI1800
);
344 const double fXMin
= aNewBound
.Left();
345 const double fYMin
= aNewBound
.Top();
346 const long nWidth
= aSizePix
.Width();
347 const long nHeight
= aSizePix
.Height();
348 const long nNewWidth
= aNewSizePix
.Width();
349 const long nNewHeight
= aNewSizePix
.Height();
354 std::unique_ptr
<long[]> pCosX(new long[nNewWidth
]);
355 std::unique_ptr
<long[]> pSinX(new long[nNewWidth
]);
356 std::unique_ptr
<long[]> pCosY(new long[nNewHeight
]);
357 std::unique_ptr
<long[]> pSinY(new long[nNewHeight
]);
359 for (nX
= 0; nX
< nNewWidth
; nX
++)
361 const double fTmp
= (fXMin
+ nX
) * 64.;
363 pCosX
[nX
] = FRound(fCosAngle
* fTmp
);
364 pSinX
[nX
] = FRound(fSinAngle
* fTmp
);
367 for (nY
= 0; nY
< nNewHeight
; nY
++)
369 const double fTmp
= (fYMin
+ nY
) * 64.;
371 pCosY
[nY
] = FRound(fCosAngle
* fTmp
);
372 pSinY
[nY
] = FRound(fSinAngle
* fTmp
);
375 for (nY
= 0; nY
< nNewHeight
; nY
++)
377 long nSinY
= pSinY
[nY
];
378 long nCosY
= pCosY
[nY
];
379 Scanline pScanline
= pWriteAcc
->GetScanline(nY
);
381 for (nX
= 0; nX
< nNewWidth
; nX
++)
383 nRotX
= (pCosX
[nX
] - nSinY
) >> 6;
384 nRotY
= (pSinX
[nX
] + nCosY
) >> 6;
386 if ((nRotX
> -1) && (nRotX
< nWidth
) && (nRotY
> -1)
387 && (nRotY
< nHeight
))
389 pWriteAcc
->SetPixelOnData(pScanline
, nX
,
390 pReadAcc
->GetPixel(nRotY
, nRotX
));
394 pWriteAcc
->SetPixelOnData(pScanline
, nX
, aFillColor
);
402 aRotatedBmp
= aNewBmp
;
408 bRet
= !!aRotatedBmp
;
410 ReassignWithSize(aRotatedBmp
);
416 Bitmap
Bitmap::CreateMask(const Color
& rTransColor
, sal_uInt8 nTol
) const
418 ScopedReadAccess
pReadAcc(const_cast<Bitmap
&>(*this));
420 if (!nTol
&& pReadAcc
421 && (pReadAcc
->GetScanlineFormat() == ScanlineFormat::N1BitLsbPal
422 || pReadAcc
->GetScanlineFormat() == ScanlineFormat::N1BitMsbPal
)
423 && pReadAcc
->GetBestMatchingColor(COL_WHITE
) == pReadAcc
->GetBestMatchingColor(rTransColor
))
425 // if we're a 1 bit pixel already, and the transcolor matches the color that would replace it
426 // already, then just return a copy
430 Bitmap
aNewBmp(GetSizePixel(), 1);
431 BitmapScopedWriteAccess
pWriteAcc(aNewBmp
);
434 if (pWriteAcc
&& pReadAcc
)
436 const long nWidth
= pReadAcc
->Width();
437 const long nHeight
= pReadAcc
->Height();
438 const BitmapColor
aBlack(pWriteAcc
->GetBestMatchingColor(COL_BLACK
));
439 const BitmapColor
aWhite(pWriteAcc
->GetBestMatchingColor(COL_WHITE
));
443 const BitmapColor
aTest(pReadAcc
->GetBestMatchingColor(rTransColor
));
445 if (pReadAcc
->GetScanlineFormat() == ScanlineFormat::N4BitMsnPal
446 || pReadAcc
->GetScanlineFormat() == ScanlineFormat::N4BitLsnPal
)
448 // optimized for 4Bit-MSN/LSN source palette
449 const sal_uInt8 cTest
= aTest
.GetIndex();
450 const long nShiftInit
451 = ((pReadAcc
->GetScanlineFormat() == ScanlineFormat::N4BitMsnPal
) ? 4 : 0);
453 if (pWriteAcc
->GetScanlineFormat() == ScanlineFormat::N1BitMsbPal
454 && aWhite
.GetIndex() == 1)
456 // optimized for 1Bit-MSB destination palette
457 for (long nY
= 0; nY
< nHeight
; ++nY
)
459 Scanline pSrc
= pReadAcc
->GetScanline(nY
);
460 Scanline pDst
= pWriteAcc
->GetScanline(nY
);
461 for (long nX
= 0, nShift
= nShiftInit
; nX
< nWidth
; nX
++, nShift
^= 4)
463 if (cTest
== ((pSrc
[nX
>> 1] >> nShift
) & 0x0f))
464 pDst
[nX
>> 3] |= 1 << (7 - (nX
& 7));
466 pDst
[nX
>> 3] &= ~(1 << (7 - (nX
& 7)));
472 for (long nY
= 0; nY
< nHeight
; ++nY
)
474 Scanline pSrc
= pReadAcc
->GetScanline(nY
);
475 Scanline pDst
= pWriteAcc
->GetScanline(nY
);
476 for (long nX
= 0, nShift
= nShiftInit
; nX
< nWidth
; nX
++, nShift
^= 4)
478 if (cTest
== ((pSrc
[nX
>> 1] >> nShift
) & 0x0f))
479 pWriteAcc
->SetPixelOnData(pDst
, nX
, aWhite
);
481 pWriteAcc
->SetPixelOnData(pDst
, nX
, aBlack
);
486 else if (pReadAcc
->GetScanlineFormat() == ScanlineFormat::N8BitPal
)
488 // optimized for 8Bit source palette
489 const sal_uInt8 cTest
= aTest
.GetIndex();
491 if (pWriteAcc
->GetScanlineFormat() == ScanlineFormat::N1BitMsbPal
492 && aWhite
.GetIndex() == 1)
494 // optimized for 1Bit-MSB destination palette
495 for (long nY
= 0; nY
< nHeight
; ++nY
)
497 Scanline pSrc
= pReadAcc
->GetScanline(nY
);
498 Scanline pDst
= pWriteAcc
->GetScanline(nY
);
499 for (long nX
= 0; nX
< nWidth
; ++nX
)
501 if (cTest
== pSrc
[nX
])
502 pDst
[nX
>> 3] |= 1 << (7 - (nX
& 7));
504 pDst
[nX
>> 3] &= ~(1 << (7 - (nX
& 7)));
510 for (long nY
= 0; nY
< nHeight
; ++nY
)
512 Scanline pSrc
= pReadAcc
->GetScanline(nY
);
513 Scanline pDst
= pWriteAcc
->GetScanline(nY
);
514 for (long nX
= 0; nX
< nWidth
; ++nX
)
516 if (cTest
== pSrc
[nX
])
517 pWriteAcc
->SetPixelOnData(pDst
, nX
, aWhite
);
519 pWriteAcc
->SetPixelOnData(pDst
, nX
, aBlack
);
524 else if (pWriteAcc
->GetScanlineFormat() == pReadAcc
->GetScanlineFormat()
525 && aWhite
.GetIndex() == 1
526 && (pReadAcc
->GetScanlineFormat() == ScanlineFormat::N1BitLsbPal
527 || pReadAcc
->GetScanlineFormat() == ScanlineFormat::N1BitMsbPal
))
529 for (long nY
= 0; nY
< nHeight
; ++nY
)
531 Scanline pSrc
= pReadAcc
->GetScanline(nY
);
532 Scanline pDst
= pWriteAcc
->GetScanline(nY
);
533 assert(pWriteAcc
->GetScanlineSize() == pReadAcc
->GetScanlineSize());
534 const long nScanlineSize
= pWriteAcc
->GetScanlineSize();
535 for (long nX
= 0; nX
< nScanlineSize
; ++nX
)
536 pDst
[nX
] = ~pSrc
[nX
];
542 for (long nY
= 0; nY
< nHeight
; ++nY
)
544 Scanline pScanline
= pWriteAcc
->GetScanline(nY
);
545 Scanline pScanlineRead
= pReadAcc
->GetScanline(nY
);
546 for (long nX
= 0; nX
< nWidth
; ++nX
)
548 if (aTest
== pReadAcc
->GetPixelFromData(pScanlineRead
, nX
))
549 pWriteAcc
->SetPixelOnData(pScanline
, nX
, aWhite
);
551 pWriteAcc
->SetPixelOnData(pScanline
, nX
, aBlack
);
560 const long nMinR
= MinMax
<long>(rTransColor
.GetRed() - nTol
, 0, 255);
561 const long nMaxR
= MinMax
<long>(rTransColor
.GetRed() + nTol
, 0, 255);
562 const long nMinG
= MinMax
<long>(rTransColor
.GetGreen() - nTol
, 0, 255);
563 const long nMaxG
= MinMax
<long>(rTransColor
.GetGreen() + nTol
, 0, 255);
564 const long nMinB
= MinMax
<long>(rTransColor
.GetBlue() - nTol
, 0, 255);
565 const long nMaxB
= MinMax
<long>(rTransColor
.GetBlue() + nTol
, 0, 255);
567 if (pReadAcc
->HasPalette())
569 for (long nY
= 0; nY
< nHeight
; nY
++)
571 Scanline pScanline
= pWriteAcc
->GetScanline(nY
);
572 Scanline pScanlineRead
= pReadAcc
->GetScanline(nY
);
573 for (long nX
= 0; nX
< nWidth
; nX
++)
575 aCol
= pReadAcc
->GetPaletteColor(
576 pReadAcc
->GetIndexFromData(pScanlineRead
, nX
));
578 nG
= aCol
.GetGreen();
581 if (nMinR
<= nR
&& nMaxR
>= nR
&& nMinG
<= nG
&& nMaxG
>= nG
&& nMinB
<= nB
584 pWriteAcc
->SetPixelOnData(pScanline
, nX
, aWhite
);
588 pWriteAcc
->SetPixelOnData(pScanline
, nX
, aBlack
);
595 for (long nY
= 0; nY
< nHeight
; nY
++)
597 Scanline pScanline
= pWriteAcc
->GetScanline(nY
);
598 Scanline pScanlineRead
= pReadAcc
->GetScanline(nY
);
599 for (long nX
= 0; nX
< nWidth
; nX
++)
601 aCol
= pReadAcc
->GetPixelFromData(pScanlineRead
, nX
);
603 nG
= aCol
.GetGreen();
606 if (nMinR
<= nR
&& nMaxR
>= nR
&& nMinG
<= nG
&& nMaxG
>= nG
&& nMinB
<= nB
609 pWriteAcc
->SetPixelOnData(pScanline
, nX
, aWhite
);
613 pWriteAcc
->SetPixelOnData(pScanline
, nX
, aBlack
);
628 aNewBmp
.maPrefSize
= maPrefSize
;
629 aNewBmp
.maPrefMapMode
= maPrefMapMode
;
637 vcl::Region
Bitmap::CreateRegion(const Color
& rColor
, const tools::Rectangle
& rRect
) const
640 tools::Rectangle
aRect(rRect
);
641 ScopedReadAccess
pReadAcc(const_cast<Bitmap
&>(*this));
643 aRect
.Intersection(tools::Rectangle(Point(), GetSizePixel()));
648 const long nLeft
= aRect
.Left();
649 const long nTop
= aRect
.Top();
650 const long nRight
= aRect
.Right();
651 const long nBottom
= aRect
.Bottom();
652 const BitmapColor
aMatch(pReadAcc
->GetBestMatchingColor(rColor
));
654 std::vector
<long> aLine
;
658 for (; nY
<= nBottom
; nY
++)
660 std::vector
<long> aNewLine
;
662 Scanline pScanlineRead
= pReadAcc
->GetScanline(nY
);
664 for (; nX
<= nRight
;)
666 while ((nX
<= nRight
) && (aMatch
!= pReadAcc
->GetPixelFromData(pScanlineRead
, nX
)))
671 aNewLine
.push_back(nX
);
673 while ((nX
<= nRight
)
674 && (aMatch
== pReadAcc
->GetPixelFromData(pScanlineRead
, nX
)))
679 aNewLine
.push_back(nX
- 1);
683 if (aNewLine
!= aLine
)
685 // need to write aLine, it's different from the next line
688 tools::Rectangle aSubRect
;
690 // enter y values and proceed ystart
691 aSubRect
.SetTop(nYStart
);
692 aSubRect
.SetBottom(nY
? nY
- 1 : 0);
694 for (size_t a(0); a
< aLine
.size();)
696 aSubRect
.SetLeft(aLine
[a
++]);
697 aSubRect
.SetRight(aLine
[a
++]);
698 aRegion
.Union(aSubRect
);
702 // copy line as new line
708 // write last line if used
711 tools::Rectangle aSubRect
;
714 aSubRect
.SetTop(nYStart
);
715 aSubRect
.SetBottom(nY
? nY
- 1 : 0);
717 for (size_t a(0); a
< aLine
.size();)
719 aSubRect
.SetLeft(aLine
[a
++]);
720 aSubRect
.SetRight(aLine
[a
++]);
721 aRegion
.Union(aSubRect
);
735 bool Bitmap::Replace(const Bitmap
& rMask
, const Color
& rReplaceColor
)
737 ScopedReadAccess
pMaskAcc(const_cast<Bitmap
&>(rMask
));
738 BitmapScopedWriteAccess
pAcc(*this);
741 if (pMaskAcc
&& pAcc
)
743 const long nWidth
= std::min(pMaskAcc
->Width(), pAcc
->Width());
744 const long nHeight
= std::min(pMaskAcc
->Height(), pAcc
->Height());
745 const BitmapColor
aMaskWhite(pMaskAcc
->GetBestMatchingColor(COL_WHITE
));
746 BitmapColor aReplace
;
748 if (pAcc
->HasPalette())
750 const sal_uInt16 nActColors
= pAcc
->GetPaletteEntryCount();
751 const sal_uInt16 nMaxColors
= 1 << pAcc
->GetBitCount();
753 // default to the nearest color
754 aReplace
= pAcc
->GetBestMatchingColor(rReplaceColor
);
756 // for paletted images without a matching palette entry
757 // look for an unused palette entry (NOTE: expensive!)
758 if (pAcc
->GetPaletteColor(aReplace
.GetIndex()) != BitmapColor(rReplaceColor
))
760 // if the palette has empty entries use the last one
761 if (nActColors
< nMaxColors
)
763 pAcc
->SetPaletteEntryCount(nActColors
+ 1);
764 pAcc
->SetPaletteColor(nActColors
, rReplaceColor
);
765 aReplace
= BitmapColor(static_cast<sal_uInt8
>(nActColors
));
769 std::unique_ptr
<bool[]> pFlags(new bool[nMaxColors
]);
771 // Set all entries to false
772 std::fill(pFlags
.get(), pFlags
.get() + nMaxColors
, false);
774 for (long nY
= 0; nY
< nHeight
; nY
++)
776 Scanline pScanline
= pAcc
->GetScanline(nY
);
777 for (long nX
= 0; nX
< nWidth
; nX
++)
778 pFlags
[pAcc
->GetIndexFromData(pScanline
, nX
)] = true;
781 for (sal_uInt16 i
= 0; i
< nMaxColors
; i
++)
783 // Hurray, we do have an unused entry
786 pAcc
->SetPaletteColor(i
, rReplaceColor
);
787 aReplace
= BitmapColor(static_cast<sal_uInt8
>(i
));
794 aReplace
= rReplaceColor
;
796 for (long nY
= 0; nY
< nHeight
; nY
++)
798 Scanline pScanline
= pAcc
->GetScanline(nY
);
799 Scanline pScanlineMask
= pMaskAcc
->GetScanline(nY
);
800 for (long nX
= 0; nX
< nWidth
; nX
++)
802 if (pMaskAcc
->GetPixelFromData(pScanlineMask
, nX
) == aMaskWhite
)
803 pAcc
->SetPixelOnData(pScanline
, nX
, aReplace
);
813 bool Bitmap::Replace(const AlphaMask
& rAlpha
, const Color
& rMergeColor
)
815 Bitmap
aNewBmp(GetSizePixel(), 24);
816 ScopedReadAccess
pAcc(*this);
817 AlphaMask::ScopedReadAccess
pAlphaAcc(const_cast<AlphaMask
&>(rAlpha
));
818 BitmapScopedWriteAccess
pNewAcc(aNewBmp
);
821 if (pAcc
&& pAlphaAcc
&& pNewAcc
)
824 const long nWidth
= std::min(pAlphaAcc
->Width(), pAcc
->Width());
825 const long nHeight
= std::min(pAlphaAcc
->Height(), pAcc
->Height());
827 for (long nY
= 0; nY
< nHeight
; nY
++)
829 Scanline pScanline
= pNewAcc
->GetScanline(nY
);
830 Scanline pScanlineAlpha
= pAlphaAcc
->GetScanline(nY
);
831 for (long nX
= 0; nX
< nWidth
; nX
++)
833 aCol
= pAcc
->GetColor(nY
, nX
);
834 aCol
.Merge(rMergeColor
, 255 - pAlphaAcc
->GetIndexFromData(pScanlineAlpha
, nX
));
835 pNewAcc
->SetPixelOnData(pScanline
, nX
, aCol
);
848 const MapMode
aMap(maPrefMapMode
);
849 const Size
aSize(maPrefSize
);
853 maPrefMapMode
= aMap
;
860 bool Bitmap::Replace(const Color
& rSearchColor
, const Color
& rReplaceColor
, sal_uInt8 nTol
)
864 // implementation specific replace
865 std::shared_ptr
<SalBitmap
> xImpBmp(ImplGetSVData()->mpDefInst
->CreateSalBitmap());
866 if (xImpBmp
->Create(*mxSalBmp
) && xImpBmp
->Replace(rSearchColor
, rReplaceColor
, nTol
))
868 ImplSetSalBitmap(xImpBmp
);
869 maPrefMapMode
= MapMode(MapUnit::MapPixel
);
870 maPrefSize
= xImpBmp
->GetSize();
875 // Bitmaps with 1 bit color depth can cause problems if they have other entries than black/white
877 if (GetBitCount() == 1)
878 Convert(BmpConversion::N4BitColors
);
880 BitmapScopedWriteAccess
pAcc(*this);
885 const long nMinR
= MinMax
<long>(rSearchColor
.GetRed() - nTol
, 0, 255);
886 const long nMaxR
= MinMax
<long>(rSearchColor
.GetRed() + nTol
, 0, 255);
887 const long nMinG
= MinMax
<long>(rSearchColor
.GetGreen() - nTol
, 0, 255);
888 const long nMaxG
= MinMax
<long>(rSearchColor
.GetGreen() + nTol
, 0, 255);
889 const long nMinB
= MinMax
<long>(rSearchColor
.GetBlue() - nTol
, 0, 255);
890 const long nMaxB
= MinMax
<long>(rSearchColor
.GetBlue() + nTol
, 0, 255);
892 if (pAcc
->HasPalette())
894 for (sal_uInt16 i
= 0, nPalCount
= pAcc
->GetPaletteEntryCount(); i
< nPalCount
; i
++)
896 const BitmapColor
& rCol
= pAcc
->GetPaletteColor(i
);
898 if (nMinR
<= rCol
.GetRed() && nMaxR
>= rCol
.GetRed() && nMinG
<= rCol
.GetGreen()
899 && nMaxG
>= rCol
.GetGreen() && nMinB
<= rCol
.GetBlue()
900 && nMaxB
>= rCol
.GetBlue())
902 pAcc
->SetPaletteColor(i
, rReplaceColor
);
909 const BitmapColor
aReplace(pAcc
->GetBestMatchingColor(rReplaceColor
));
911 for (long nY
= 0, nHeight
= pAcc
->Height(); nY
< nHeight
; nY
++)
913 Scanline pScanline
= pAcc
->GetScanline(nY
);
914 for (long nX
= 0, nWidth
= pAcc
->Width(); nX
< nWidth
; nX
++)
916 aCol
= pAcc
->GetPixelFromData(pScanline
, nX
);
918 if (nMinR
<= aCol
.GetRed() && nMaxR
>= aCol
.GetRed() && nMinG
<= aCol
.GetGreen()
919 && nMaxG
>= aCol
.GetGreen() && nMinB
<= aCol
.GetBlue()
920 && nMaxB
>= aCol
.GetBlue())
922 pAcc
->SetPixelOnData(pScanline
, nX
, aReplace
);
935 bool Bitmap::Replace(const Color
* pSearchColors
, const Color
* pReplaceColors
, sal_uLong nColorCount
,
936 sal_uInt8
const* pTols
)
938 // Bitmaps with 1 bit color depth can cause problems if they have other entries than black/white
940 if (GetBitCount() == 1)
941 Convert(BmpConversion::N4BitColors
);
943 BitmapScopedWriteAccess
pAcc(*this);
948 std::unique_ptr
<long[]> pMinR(new long[nColorCount
]);
949 std::unique_ptr
<long[]> pMaxR(new long[nColorCount
]);
950 std::unique_ptr
<long[]> pMinG(new long[nColorCount
]);
951 std::unique_ptr
<long[]> pMaxG(new long[nColorCount
]);
952 std::unique_ptr
<long[]> pMinB(new long[nColorCount
]);
953 std::unique_ptr
<long[]> pMaxB(new long[nColorCount
]);
957 for (sal_uLong i
= 0; i
< nColorCount
; i
++)
959 const Color
& rCol
= pSearchColors
[i
];
960 const sal_uInt8 nTol
= pTols
[i
];
962 pMinR
[i
] = MinMax
<long>(rCol
.GetRed() - nTol
, 0, 255);
963 pMaxR
[i
] = MinMax
<long>(rCol
.GetRed() + nTol
, 0, 255);
964 pMinG
[i
] = MinMax
<long>(rCol
.GetGreen() - nTol
, 0, 255);
965 pMaxG
[i
] = MinMax
<long>(rCol
.GetGreen() + nTol
, 0, 255);
966 pMinB
[i
] = MinMax
<long>(rCol
.GetBlue() - nTol
, 0, 255);
967 pMaxB
[i
] = MinMax
<long>(rCol
.GetBlue() + nTol
, 0, 255);
972 for (sal_uLong i
= 0; i
< nColorCount
; i
++)
974 const Color
& rCol
= pSearchColors
[i
];
976 pMinR
[i
] = rCol
.GetRed();
977 pMaxR
[i
] = rCol
.GetRed();
978 pMinG
[i
] = rCol
.GetGreen();
979 pMaxG
[i
] = rCol
.GetGreen();
980 pMinB
[i
] = rCol
.GetBlue();
981 pMaxB
[i
] = rCol
.GetBlue();
985 if (pAcc
->HasPalette())
987 for (sal_uInt16 nEntry
= 0, nPalCount
= pAcc
->GetPaletteEntryCount();
988 nEntry
< nPalCount
; nEntry
++)
990 const BitmapColor
& rCol
= pAcc
->GetPaletteColor(nEntry
);
992 for (sal_uLong i
= 0; i
< nColorCount
; i
++)
994 if (pMinR
[i
] <= rCol
.GetRed() && pMaxR
[i
] >= rCol
.GetRed()
995 && pMinG
[i
] <= rCol
.GetGreen() && pMaxG
[i
] >= rCol
.GetGreen()
996 && pMinB
[i
] <= rCol
.GetBlue() && pMaxB
[i
] >= rCol
.GetBlue())
998 pAcc
->SetPaletteColor(nEntry
, pReplaceColors
[i
]);
1007 std::unique_ptr
<BitmapColor
[]> pReplaces(new BitmapColor
[nColorCount
]);
1009 for (sal_uLong i
= 0; i
< nColorCount
; i
++)
1010 pReplaces
[i
] = pAcc
->GetBestMatchingColor(pReplaceColors
[i
]);
1012 for (long nY
= 0, nHeight
= pAcc
->Height(); nY
< nHeight
; nY
++)
1014 Scanline pScanline
= pAcc
->GetScanline(nY
);
1015 for (long nX
= 0, nWidth
= pAcc
->Width(); nX
< nWidth
; nX
++)
1017 aCol
= pAcc
->GetPixelFromData(pScanline
, nX
);
1019 for (sal_uLong i
= 0; i
< nColorCount
; i
++)
1021 if (pMinR
[i
] <= aCol
.GetRed() && pMaxR
[i
] >= aCol
.GetRed()
1022 && pMinG
[i
] <= aCol
.GetGreen() && pMaxG
[i
] >= aCol
.GetGreen()
1023 && pMinB
[i
] <= aCol
.GetBlue() && pMaxB
[i
] >= aCol
.GetBlue())
1025 pAcc
->SetPixelOnData(pScanline
, nX
, pReplaces
[i
]);
1040 bool Bitmap::CombineSimple(const Bitmap
& rMask
, BmpCombine eCombine
)
1042 ScopedReadAccess
pMaskAcc(const_cast<Bitmap
&>(rMask
));
1043 BitmapScopedWriteAccess
pAcc(*this);
1046 if (pMaskAcc
&& pAcc
)
1048 const long nWidth
= std::min(pMaskAcc
->Width(), pAcc
->Width());
1049 const long nHeight
= std::min(pMaskAcc
->Height(), pAcc
->Height());
1050 const Color
aColBlack(COL_BLACK
);
1051 const BitmapColor
aWhite(pAcc
->GetBestMatchingColor(COL_WHITE
));
1052 const BitmapColor
aBlack(pAcc
->GetBestMatchingColor(aColBlack
));
1053 const BitmapColor
aMaskBlack(pMaskAcc
->GetBestMatchingColor(aColBlack
));
1057 case BmpCombine::And
:
1059 for (long nY
= 0; nY
< nHeight
; nY
++)
1061 Scanline pScanline
= pAcc
->GetScanline(nY
);
1062 Scanline pScanlineMask
= pMaskAcc
->GetScanline(nY
);
1063 for (long nX
= 0; nX
< nWidth
; nX
++)
1065 if (pMaskAcc
->GetPixelFromData(pScanlineMask
, nX
) != aMaskBlack
1066 && pAcc
->GetPixelFromData(pScanline
, nX
) != aBlack
)
1068 pAcc
->SetPixelOnData(pScanline
, nX
, aWhite
);
1072 pAcc
->SetPixelOnData(pScanline
, nX
, aBlack
);
1079 case BmpCombine::Or
:
1081 for (long nY
= 0; nY
< nHeight
; nY
++)
1083 Scanline pScanline
= pAcc
->GetScanline(nY
);
1084 Scanline pScanlineMask
= pMaskAcc
->GetScanline(nY
);
1085 for (long nX
= 0; nX
< nWidth
; nX
++)
1087 if (pMaskAcc
->GetPixelFromData(pScanlineMask
, nX
) != aMaskBlack
1088 || pAcc
->GetPixelFromData(pScanline
, nX
) != aBlack
)
1090 pAcc
->SetPixelOnData(pScanline
, nX
, aWhite
);
1094 pAcc
->SetPixelOnData(pScanline
, nX
, aBlack
);
1108 // TODO: Have a look at OutputDevice::ImplDrawAlpha() for some
1109 // optimizations. Might even consolidate the code here and there.
1110 bool Bitmap::Blend(const AlphaMask
& rAlpha
, const Color
& rBackgroundColor
)
1112 // Convert to a truecolor bitmap, if we're a paletted one. There's room for tradeoff decision here,
1113 // maybe later for an overload (or a flag)
1114 if (GetBitCount() <= 8)
1115 Convert(BmpConversion::N24Bit
);
1117 AlphaMask::ScopedReadAccess
pAlphaAcc(const_cast<AlphaMask
&>(rAlpha
));
1119 BitmapScopedWriteAccess
pAcc(*this);
1122 if (pAlphaAcc
&& pAcc
)
1124 const long nWidth
= std::min(pAlphaAcc
->Width(), pAcc
->Width());
1125 const long nHeight
= std::min(pAlphaAcc
->Height(), pAcc
->Height());
1127 for (long nY
= 0; nY
< nHeight
; ++nY
)
1129 Scanline pScanline
= pAcc
->GetScanline(nY
);
1130 Scanline pScanlineAlpha
= pAlphaAcc
->GetScanline(nY
);
1131 for (long nX
= 0; nX
< nWidth
; ++nX
)
1133 BitmapColor aBmpColor
= pAcc
->GetPixelFromData(pScanline
, nX
);
1134 aBmpColor
.Merge(rBackgroundColor
,
1135 255 - pAlphaAcc
->GetIndexFromData(pScanlineAlpha
, nX
));
1136 pAcc
->SetPixelOnData(pScanline
, nX
, aBmpColor
);
1146 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */