LibreOffice Module vcl (master) 1
bitmappaint.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
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/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
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 .
18 */
19
20#include <tools/poly.hxx>
21#include <tools/helpers.hxx>
22
23#include <vcl/bitmap.hxx>
24#include <vcl/alpha.hxx>
25
27#include <salbmp.hxx>
28#include <svdata.hxx>
29#include <salinst.hxx>
30
31#include <algorithm>
32#include <memory>
33
34bool Bitmap::Erase(const Color& rFillColor)
35{
36 if (IsEmpty())
37 return true;
38
39 // implementation specific replace
40 std::shared_ptr<SalBitmap> xImpBmp(ImplGetSVData()->mpDefInst->CreateSalBitmap());
41 if (xImpBmp->Create(*mxSalBmp) && xImpBmp->Erase(rFillColor))
42 {
43 ImplSetSalBitmap(xImpBmp);
44 maPrefMapMode = MapMode(MapUnit::MapPixel);
45 maPrefSize = xImpBmp->GetSize();
46 return true;
47 }
48
49 BitmapScopedWriteAccess pWriteAcc(*this);
50 bool bRet = false;
51
52 if (pWriteAcc)
53 {
54 pWriteAcc->Erase(rFillColor);
55 bRet = true;
56 }
57
58 return bRet;
59}
60
62{
63 if (!mxSalBmp)
64 return false;
65
66 // For alpha masks, we need to actually invert the underlying data
67 // or the optimisations elsewhere do not work right.
68 if (typeid(*this) != typeid(AlphaMask))
69 {
70 // We want to avoid using ScopedReadAccess until we really need
71 // it, because on Skia it triggers a GPU->RAM copy, which is very slow.
72 ScopedReadAccess pReadAcc(*this);
73 if (!pReadAcc)
74 return false;
75 if (pReadAcc->HasPalette())
76 {
77 BitmapScopedWriteAccess pWriteAcc(*this);
78 BitmapPalette aBmpPal(pWriteAcc->GetPalette());
79 const sal_uInt16 nCount = aBmpPal.GetEntryCount();
80
81 for (sal_uInt16 i = 0; i < nCount; i++)
82 {
83 aBmpPal[i].Invert();
84 }
85
86 pWriteAcc->SetPalette(aBmpPal);
87 mxSalBmp->InvalidateChecksum();
88 return true;
89 }
90 }
91
92 // try optimised call, much faster on Skia
93 if (mxSalBmp->Invert())
94 {
95 mxSalBmp->InvalidateChecksum();
96 return true;
97 }
98
99 BitmapScopedWriteAccess pWriteAcc(*this);
100 const tools::Long nWidth = pWriteAcc->Width();
101 const tools::Long nHeight = pWriteAcc->Height();
102
103 for (tools::Long nY = 0; nY < nHeight; nY++)
104 {
105 Scanline pScanline = pWriteAcc->GetScanline(nY);
106 for (tools::Long nX = 0; nX < nWidth; nX++)
107 {
108 BitmapColor aBmpColor = pWriteAcc->GetPixelFromData(pScanline, nX);
109 aBmpColor.Invert();
110 pWriteAcc->SetPixelOnData(pScanline, nX, aBmpColor);
111 }
112 }
113
114 mxSalBmp->InvalidateChecksum();
115
116 return true;
117}
118
119namespace
120{
121// Put each scanline's content horizontally mirrored into the other one.
122// (optimized version accessing pixel values directly).
123template <int bitCount>
124void mirrorScanlines(Scanline scanline1, Scanline scanline2, tools::Long nWidth)
125{
126 constexpr int byteCount = bitCount / 8;
127 Scanline pos1 = scanline1;
128 Scanline pos2 = scanline2 + (nWidth - 1) * byteCount; // last in second scanline
129 sal_uInt8 tmp[byteCount];
130 for (tools::Long i = 0; i < nWidth; ++i)
131 {
132 memcpy(tmp, pos1, byteCount);
133 memcpy(pos1, pos2, byteCount);
134 memcpy(pos2, tmp, byteCount);
135 pos1 += byteCount;
136 pos2 -= byteCount;
137 }
138}
139}
140
142{
143 bool bHorz(nMirrorFlags & BmpMirrorFlags::Horizontal);
144 bool bVert(nMirrorFlags & BmpMirrorFlags::Vertical);
145 bool bRet = false;
146
147 if (bHorz && !bVert)
148 {
149 BitmapScopedWriteAccess pAcc(*this);
150
151 if (pAcc)
152 {
153 const tools::Long nWidth = pAcc->Width();
154 const tools::Long nHeight = pAcc->Height();
155 const tools::Long nWidth1 = nWidth - 1;
156 const tools::Long nWidth_2 = nWidth / 2;
157 const tools::Long nSecondHalf = nWidth - nWidth_2;
158
159 switch (pAcc->GetBitCount())
160 {
161 // Special-case these, swap the halves of scanlines while mirroring them.
162 case 32:
163 for (tools::Long nY = 0; nY < nHeight; nY++)
164 mirrorScanlines<32>(pAcc->GetScanline(nY),
165 pAcc->GetScanline(nY) + 4 * nSecondHalf, nWidth_2);
166 break;
167 case 24:
168 for (tools::Long nY = 0; nY < nHeight; nY++)
169 mirrorScanlines<24>(pAcc->GetScanline(nY),
170 pAcc->GetScanline(nY) + 3 * nSecondHalf, nWidth_2);
171 break;
172 case 8:
173 for (tools::Long nY = 0; nY < nHeight; nY++)
174 mirrorScanlines<8>(pAcc->GetScanline(nY),
175 pAcc->GetScanline(nY) + nSecondHalf, nWidth_2);
176 break;
177 default:
178 for (tools::Long nY = 0; nY < nHeight; nY++)
179 {
180 Scanline pScanline = pAcc->GetScanline(nY);
181 for (tools::Long nX = 0, nOther = nWidth1; nX < nWidth_2; nX++, nOther--)
182 {
183 const BitmapColor aTemp(pAcc->GetPixelFromData(pScanline, nX));
184
185 pAcc->SetPixelOnData(pScanline, nX,
186 pAcc->GetPixelFromData(pScanline, nOther));
187 pAcc->SetPixelOnData(pScanline, nOther, aTemp);
188 }
189 }
190 }
191
192 pAcc.reset();
193 bRet = true;
194 }
195 }
196 else if (bVert && !bHorz)
197 {
198 BitmapScopedWriteAccess pAcc(*this);
199
200 if (pAcc)
201 {
202 const tools::Long nScanSize = pAcc->GetScanlineSize();
203 std::unique_ptr<sal_uInt8[]> pBuffer(new sal_uInt8[nScanSize]);
204 const tools::Long nHeight = pAcc->Height();
205 const tools::Long nHeight1 = nHeight - 1;
206 const tools::Long nHeight_2 = nHeight >> 1;
207
208 for (tools::Long nY = 0, nOther = nHeight1; nY < nHeight_2; nY++, nOther--)
209 {
210 memcpy(pBuffer.get(), pAcc->GetScanline(nY), nScanSize);
211 memcpy(pAcc->GetScanline(nY), pAcc->GetScanline(nOther), nScanSize);
212 memcpy(pAcc->GetScanline(nOther), pBuffer.get(), nScanSize);
213 }
214
215 pAcc.reset();
216 bRet = true;
217 }
218 }
219 else if (bHorz && bVert)
220 {
221 BitmapScopedWriteAccess pAcc(*this);
222
223 if (pAcc)
224 {
225 const tools::Long nWidth = pAcc->Width();
226 const tools::Long nWidth1 = nWidth - 1;
227 const tools::Long nHeight = pAcc->Height();
228 tools::Long nHeight_2 = nHeight / 2;
229 const tools::Long nWidth_2 = nWidth / 2;
230 const tools::Long nSecondHalf = nWidth - nWidth_2;
231
232 switch (pAcc->GetBitCount())
233 {
234 case 32:
235 for (tools::Long nY = 0, nOtherY = nHeight - 1; nY < nHeight_2; nY++, nOtherY--)
236 mirrorScanlines<32>(pAcc->GetScanline(nY), pAcc->GetScanline(nOtherY),
237 nWidth);
238 if (nHeight & 1)
239 mirrorScanlines<32>(pAcc->GetScanline(nHeight_2),
240 pAcc->GetScanline(nHeight_2) + 4 * nSecondHalf,
241 nWidth_2);
242 break;
243 case 24:
244 for (tools::Long nY = 0, nOtherY = nHeight - 1; nY < nHeight_2; nY++, nOtherY--)
245 mirrorScanlines<24>(pAcc->GetScanline(nY), pAcc->GetScanline(nOtherY),
246 nWidth);
247 if (nHeight & 1)
248 mirrorScanlines<24>(pAcc->GetScanline(nHeight_2),
249 pAcc->GetScanline(nHeight_2) + 3 * nSecondHalf,
250 nWidth_2);
251 break;
252 case 8:
253 for (tools::Long nY = 0, nOtherY = nHeight - 1; nY < nHeight_2; nY++, nOtherY--)
254 mirrorScanlines<8>(pAcc->GetScanline(nY), pAcc->GetScanline(nOtherY),
255 nWidth);
256 if (nHeight & 1)
257 mirrorScanlines<8>(pAcc->GetScanline(nHeight_2),
258 pAcc->GetScanline(nHeight_2) + nSecondHalf, nWidth_2);
259 break;
260 default:
261 for (tools::Long nY = 0, nOtherY = nHeight - 1; nY < nHeight_2; nY++, nOtherY--)
262 {
263 Scanline pScanline = pAcc->GetScanline(nY);
264 Scanline pScanlineOther = pAcc->GetScanline(nOtherY);
265 for (tools::Long nX = 0, nOtherX = nWidth1; nX < nWidth; nX++, nOtherX--)
266 {
267 const BitmapColor aTemp(pAcc->GetPixelFromData(pScanline, nX));
268
269 pAcc->SetPixelOnData(pScanline, nX,
270 pAcc->GetPixelFromData(pScanlineOther, nOtherX));
271 pAcc->SetPixelOnData(pScanlineOther, nOtherX, aTemp);
272 }
273 }
274
275 // if necessary, also mirror the middle line horizontally
276 if (nHeight & 1)
277 {
278 Scanline pScanline = pAcc->GetScanline(nHeight_2);
279 for (tools::Long nX = 0, nOtherX = nWidth1; nX < nWidth_2; nX++, nOtherX--)
280 {
281 const BitmapColor aTemp(pAcc->GetPixelFromData(pScanline, nX));
282 pAcc->SetPixelOnData(pScanline, nX,
283 pAcc->GetPixelFromData(pScanline, nOtherX));
284 pAcc->SetPixelOnData(pScanline, nOtherX, aTemp);
285 }
286 }
287 }
288
289 pAcc.reset();
290 bRet = true;
291 }
292 }
293 else
294 bRet = true;
295
296 return bRet;
297}
298
299bool Bitmap::Rotate(Degree10 nAngle10, const Color& rFillColor)
300{
301 nAngle10 %= 3600_deg10;
302 nAngle10 = (nAngle10 < 0_deg10) ? (Degree10(3599) + nAngle10) : nAngle10;
303
304 if (!nAngle10)
305 return true;
306 if (nAngle10 == 1800_deg10)
308
309 ScopedReadAccess pReadAcc(*this);
310 if (!pReadAcc)
311 return false;
312
313 Bitmap aRotatedBmp;
314 bool bRet = false;
315 const Size aSizePix(GetSizePixel());
316
317 if (nAngle10 == 900_deg10 || nAngle10 == 2700_deg10)
318 {
319 const Size aNewSizePix(aSizePix.Height(), aSizePix.Width());
320 Bitmap aNewBmp(aNewSizePix, getPixelFormat(), &pReadAcc->GetPalette());
321 BitmapScopedWriteAccess pWriteAcc(aNewBmp);
322
323 if (pWriteAcc)
324 {
325 const tools::Long nWidth = aSizePix.Width();
326 const tools::Long nWidth1 = nWidth - 1;
327 const tools::Long nHeight = aSizePix.Height();
328 const tools::Long nHeight1 = nHeight - 1;
329 const tools::Long nNewWidth = aNewSizePix.Width();
330 const tools::Long nNewHeight = aNewSizePix.Height();
331
332 if (nAngle10 == 900_deg10)
333 {
334 for (tools::Long nY = 0, nOtherX = nWidth1; nY < nNewHeight; nY++, nOtherX--)
335 {
336 Scanline pScanline = pWriteAcc->GetScanline(nY);
337 for (tools::Long nX = 0, nOtherY = 0; nX < nNewWidth; nX++)
338 {
339 pWriteAcc->SetPixelOnData(pScanline, nX,
340 pReadAcc->GetPixel(nOtherY++, nOtherX));
341 }
342 }
343 }
344 else if (nAngle10 == 2700_deg10)
345 {
346 for (tools::Long nY = 0, nOtherX = 0; nY < nNewHeight; nY++, nOtherX++)
347 {
348 Scanline pScanline = pWriteAcc->GetScanline(nY);
349 for (tools::Long nX = 0, nOtherY = nHeight1; nX < nNewWidth; nX++)
350 {
351 pWriteAcc->SetPixelOnData(pScanline, nX,
352 pReadAcc->GetPixel(nOtherY--, nOtherX));
353 }
354 }
355 }
356
357 pWriteAcc.reset();
358 }
359
360 aRotatedBmp = aNewBmp;
361 }
362 else
363 {
364 Point aTmpPoint;
365 tools::Rectangle aTmpRectangle(aTmpPoint, aSizePix);
366 tools::Polygon aPoly(aTmpRectangle);
367 aPoly.Rotate(aTmpPoint, nAngle10);
368
369 tools::Rectangle aNewBound(aPoly.GetBoundRect());
370 const Size aNewSizePix(aNewBound.GetSize());
371 Bitmap aNewBmp(aNewSizePix, getPixelFormat(), &pReadAcc->GetPalette());
372 BitmapScopedWriteAccess pWriteAcc(aNewBmp);
373
374 if (pWriteAcc)
375 {
376 const BitmapColor aFillColor(pWriteAcc->GetBestMatchingColor(rFillColor));
377 const double fCosAngle = cos(toRadians(nAngle10));
378 const double fSinAngle = sin(toRadians(nAngle10));
379 const double fXMin = aNewBound.Left();
380 const double fYMin = aNewBound.Top();
381 const sal_Int32 nWidth = aSizePix.Width();
382 const sal_Int32 nHeight = aSizePix.Height();
383 const sal_Int32 nNewWidth = aNewSizePix.Width();
384 const sal_Int32 nNewHeight = aNewSizePix.Height();
385 // we store alternating values of cos/sin. We do this instead of
386 // separate arrays to improve cache hit.
387 std::unique_ptr<sal_Int32[]> pCosSinX(new sal_Int32[nNewWidth * 2]);
388 std::unique_ptr<sal_Int32[]> pCosSinY(new sal_Int32[nNewHeight * 2]);
389
390 for (sal_Int32 nIdx = 0, nX = 0; nX < nNewWidth; nX++)
391 {
392 const double fTmp = (fXMin + nX) * 64;
393
394 pCosSinX[nIdx++] = std::round(fCosAngle * fTmp);
395 pCosSinX[nIdx++] = std::round(fSinAngle * fTmp);
396 }
397
398 for (sal_Int32 nIdx = 0, nY = 0; nY < nNewHeight; nY++)
399 {
400 const double fTmp = (fYMin + nY) * 64;
401
402 pCosSinY[nIdx++] = std::round(fCosAngle * fTmp);
403 pCosSinY[nIdx++] = std::round(fSinAngle * fTmp);
404 }
405
406 for (sal_Int32 nCosSinYIdx = 0, nY = 0; nY < nNewHeight; nY++)
407 {
408 sal_Int32 nCosY = pCosSinY[nCosSinYIdx++];
409 sal_Int32 nSinY = pCosSinY[nCosSinYIdx++];
410 Scanline pScanline = pWriteAcc->GetScanline(nY);
411
412 for (sal_Int32 nCosSinXIdx = 0, nX = 0; nX < nNewWidth; nX++)
413 {
414 sal_Int32 nRotX = (pCosSinX[nCosSinXIdx++] - nSinY) >> 6;
415 sal_Int32 nRotY = (pCosSinX[nCosSinXIdx++] + nCosY) >> 6;
416
417 if ((nRotX > -1) && (nRotX < nWidth) && (nRotY > -1) && (nRotY < nHeight))
418 {
419 pWriteAcc->SetPixelOnData(pScanline, nX, pReadAcc->GetPixel(nRotY, nRotX));
420 }
421 else
422 {
423 pWriteAcc->SetPixelOnData(pScanline, nX, aFillColor);
424 }
425 }
426 }
427
428 pWriteAcc.reset();
429 }
430
431 aRotatedBmp = aNewBmp;
432 }
433
434 pReadAcc.reset();
435
436 bRet = !aRotatedBmp.IsEmpty();
437 if (bRet)
438 ReassignWithSize(aRotatedBmp);
439
440 return bRet;
441};
442
443Bitmap Bitmap::CreateMask(const Color& rTransColor) const
444{
445 ScopedReadAccess pReadAcc(const_cast<Bitmap&>(*this));
446 if (!pReadAcc)
447 return Bitmap();
448
449 // Historically LO used 1bpp masks, but 8bpp masks are much faster,
450 // better supported by hardware, and the memory savings are not worth
451 // it anymore.
452 // TODO: Possibly remove the 1bpp code later.
453
455 && pReadAcc->GetBestMatchingColor(COL_WHITE) == pReadAcc->GetBestMatchingColor(rTransColor))
456 {
457 // if we're a 1 bit pixel already, and the transcolor matches the color that would replace it
458 // already, then just return a copy
459 return *this;
460 }
461
462 auto ePixelFormat = vcl::PixelFormat::N8_BPP;
463 Bitmap aNewBmp(GetSizePixel(), ePixelFormat, &Bitmap::GetGreyPalette(256));
464 BitmapScopedWriteAccess pWriteAcc(aNewBmp);
465 if (!pWriteAcc)
466 return Bitmap();
467
468 const tools::Long nWidth = pReadAcc->Width();
469 const tools::Long nHeight = pReadAcc->Height();
470 const BitmapColor aBlack(pWriteAcc->GetBestMatchingColor(COL_BLACK));
471 const BitmapColor aWhite(pWriteAcc->GetBestMatchingColor(COL_WHITE));
472
473 const BitmapColor aTest(pReadAcc->GetBestMatchingColor(rTransColor));
474
475 if (pWriteAcc->GetScanlineFormat() == pReadAcc->GetScanlineFormat() && aWhite.GetIndex() == 1
477 {
478 for (tools::Long nY = 0; nY < nHeight; ++nY)
479 {
480 Scanline pSrc = pReadAcc->GetScanline(nY);
481 Scanline pDst = pWriteAcc->GetScanline(nY);
482 assert(pWriteAcc->GetScanlineSize() == pReadAcc->GetScanlineSize());
483 const tools::Long nScanlineSize = pWriteAcc->GetScanlineSize();
484 for (tools::Long nX = 0; nX < nScanlineSize; ++nX)
485 pDst[nX] = ~pSrc[nX];
486 }
487 }
488 else if (pReadAcc->GetScanlineFormat() == ScanlineFormat::N8BitPal)
489 {
490 // optimized for 8Bit source palette
491 const sal_uInt8 cTest = aTest.GetIndex();
492
493 for (tools::Long nY = 0; nY < nHeight; ++nY)
494 {
495 Scanline pSrc = pReadAcc->GetScanline(nY);
496 Scanline pDst = pWriteAcc->GetScanline(nY);
497 for (tools::Long nX = 0; nX < nWidth; ++nX)
498 {
499 if (cTest == pSrc[nX])
500 pDst[nX] = aWhite.GetIndex();
501 else
502 pDst[nX] = aBlack.GetIndex();
503 }
504 }
505 }
506 else
507 {
508 // not optimized
509 for (tools::Long nY = 0; nY < nHeight; ++nY)
510 {
511 Scanline pScanline = pWriteAcc->GetScanline(nY);
512 Scanline pScanlineRead = pReadAcc->GetScanline(nY);
513 for (tools::Long nX = 0; nX < nWidth; ++nX)
514 {
515 if (aTest == pReadAcc->GetPixelFromData(pScanlineRead, nX))
516 pWriteAcc->SetPixelOnData(pScanline, nX, aWhite);
517 else
518 pWriteAcc->SetPixelOnData(pScanline, nX, aBlack);
519 }
520 }
521 }
522
523 pWriteAcc.reset();
524 pReadAcc.reset();
525
526 aNewBmp.maPrefSize = maPrefSize;
528
529 return aNewBmp;
530}
531
532Bitmap Bitmap::CreateMask(const Color& rTransColor, sal_uInt8 nTol) const
533{
534 if (nTol == 0)
535 return CreateMask(rTransColor);
536
537 ScopedReadAccess pReadAcc(const_cast<Bitmap&>(*this));
538 if (!pReadAcc)
539 return Bitmap();
540
541 // Historically LO used 1bpp masks, but 8bpp masks are much faster,
542 // better supported by hardware, and the memory savings are not worth
543 // it anymore.
544 // TODO: Possibly remove the 1bpp code later.
545
546 auto ePixelFormat = vcl::PixelFormat::N8_BPP;
547 Bitmap aNewBmp(GetSizePixel(), ePixelFormat, &Bitmap::GetGreyPalette(256));
548 BitmapScopedWriteAccess pWriteAcc(aNewBmp);
549 if (!pWriteAcc)
550 return Bitmap();
551
552 const tools::Long nWidth = pReadAcc->Width();
553 const tools::Long nHeight = pReadAcc->Height();
554 const BitmapColor aBlack(pWriteAcc->GetBestMatchingColor(COL_BLACK));
555 const BitmapColor aWhite(pWriteAcc->GetBestMatchingColor(COL_WHITE));
556
557 BitmapColor aCol;
558 tools::Long nR, nG, nB;
559 const tools::Long nMinR = MinMax<tools::Long>(rTransColor.GetRed() - nTol, 0, 255);
560 const tools::Long nMaxR = MinMax<tools::Long>(rTransColor.GetRed() + nTol, 0, 255);
561 const tools::Long nMinG = MinMax<tools::Long>(rTransColor.GetGreen() - nTol, 0, 255);
562 const tools::Long nMaxG = MinMax<tools::Long>(rTransColor.GetGreen() + nTol, 0, 255);
563 const tools::Long nMinB = MinMax<tools::Long>(rTransColor.GetBlue() - nTol, 0, 255);
564 const tools::Long nMaxB = MinMax<tools::Long>(rTransColor.GetBlue() + nTol, 0, 255);
565
566 if (pReadAcc->HasPalette())
567 {
568 for (tools::Long nY = 0; nY < nHeight; nY++)
569 {
570 Scanline pScanline = pWriteAcc->GetScanline(nY);
571 Scanline pScanlineRead = pReadAcc->GetScanline(nY);
572 for (tools::Long nX = 0; nX < nWidth; nX++)
573 {
574 aCol = pReadAcc->GetPaletteColor(pReadAcc->GetIndexFromData(pScanlineRead, nX));
575 nR = aCol.GetRed();
576 nG = aCol.GetGreen();
577 nB = aCol.GetBlue();
578
579 if (nMinR <= nR && nMaxR >= nR && nMinG <= nG && nMaxG >= nG && nMinB <= nB
580 && nMaxB >= nB)
581 {
582 pWriteAcc->SetPixelOnData(pScanline, nX, aWhite);
583 }
584 else
585 {
586 pWriteAcc->SetPixelOnData(pScanline, nX, aBlack);
587 }
588 }
589 }
590 }
591 else
592 {
593 for (tools::Long nY = 0; nY < nHeight; nY++)
594 {
595 Scanline pScanline = pWriteAcc->GetScanline(nY);
596 Scanline pScanlineRead = pReadAcc->GetScanline(nY);
597 for (tools::Long nX = 0; nX < nWidth; nX++)
598 {
599 aCol = pReadAcc->GetPixelFromData(pScanlineRead, nX);
600 nR = aCol.GetRed();
601 nG = aCol.GetGreen();
602 nB = aCol.GetBlue();
603
604 if (nMinR <= nR && nMaxR >= nR && nMinG <= nG && nMaxG >= nG && nMinB <= nB
605 && nMaxB >= nB)
606 {
607 pWriteAcc->SetPixelOnData(pScanline, nX, aWhite);
608 }
609 else
610 {
611 pWriteAcc->SetPixelOnData(pScanline, nX, aBlack);
612 }
613 }
614 }
615 }
616
617 pWriteAcc.reset();
618 pReadAcc.reset();
619
620 aNewBmp.maPrefSize = maPrefSize;
622
623 return aNewBmp;
624}
625
626AlphaMask Bitmap::CreateAlphaMask(const Color& rTransColor) const
627{
628 ScopedReadAccess pReadAcc(const_cast<Bitmap&>(*this));
629 if (!pReadAcc)
630 return AlphaMask();
631
632 // Historically LO used 1bpp masks, but 8bpp masks are much faster,
633 // better supported by hardware, and the memory savings are not worth
634 // it anymore.
635
638 == pReadAcc->GetBestMatchingColor(rTransColor))
639 {
640 // if we're a 1 bit pixel already, and the transcolor matches the color that would replace it
641 // already, then just return a copy
642 return AlphaMask(*this);
643 }
644
645 AlphaMask aNewBmp(GetSizePixel());
646 BitmapScopedWriteAccess pWriteAcc(aNewBmp);
647 if (!pWriteAcc)
648 return AlphaMask();
649
650 const tools::Long nWidth = pReadAcc->Width();
651 const tools::Long nHeight = pReadAcc->Height();
652 const BitmapColor aOpaqueColor(pWriteAcc->GetBestMatchingColor(COL_ALPHA_OPAQUE));
653 const BitmapColor aTransparentColor(pWriteAcc->GetBestMatchingColor(COL_ALPHA_TRANSPARENT));
654
655 const BitmapColor aTest(pReadAcc->GetBestMatchingColor(rTransColor));
656
658 {
659 // optimized for 8Bit source palette
660 const sal_uInt8 cTest = aTest.GetIndex();
661
662 for (tools::Long nY = 0; nY < nHeight; ++nY)
663 {
664 Scanline pSrc = pReadAcc->GetScanline(nY);
665 Scanline pDst = pWriteAcc->GetScanline(nY);
666 for (tools::Long nX = 0; nX < nWidth; ++nX)
667 {
668 if (cTest == pSrc[nX])
669 pDst[nX] = aTransparentColor.GetIndex();
670 else
671 pDst[nX] = aOpaqueColor.GetIndex();
672 }
673 }
674 }
675 else
676 {
677 // not optimized
678 for (tools::Long nY = 0; nY < nHeight; ++nY)
679 {
680 Scanline pScanline = pWriteAcc->GetScanline(nY);
681 Scanline pScanlineRead = pReadAcc->GetScanline(nY);
682 for (tools::Long nX = 0; nX < nWidth; ++nX)
683 {
684 if (aTest == pReadAcc->GetPixelFromData(pScanlineRead, nX))
685 pWriteAcc->SetPixelOnData(pScanline, nX, aTransparentColor);
686 else
687 pWriteAcc->SetPixelOnData(pScanline, nX, aOpaqueColor);
688 }
689 }
690 }
691
692 pWriteAcc.reset();
693 pReadAcc.reset();
694
695 aNewBmp.maPrefSize = maPrefSize;
697
698 return aNewBmp;
699}
700
701AlphaMask Bitmap::CreateAlphaMask(const Color& rTransColor, sal_uInt8 nTol) const
702{
703 if (nTol == 0)
704 return CreateAlphaMask(rTransColor);
705
706 ScopedReadAccess pReadAcc(const_cast<Bitmap&>(*this));
707 if (!pReadAcc)
708 return AlphaMask();
709
710 // Historically LO used 1bpp masks, but 8bpp masks are much faster,
711 // better supported by hardware, and the memory savings are not worth
712 // it anymore.
713 // TODO: Possibly remove the 1bpp code later.
714
715 AlphaMask aNewBmp(GetSizePixel());
716 BitmapScopedWriteAccess pWriteAcc(aNewBmp);
717 if (!pWriteAcc)
718 return AlphaMask();
719
720 const tools::Long nWidth = pReadAcc->Width();
721 const tools::Long nHeight = pReadAcc->Height();
722 const BitmapColor aOpaqueColor(pWriteAcc->GetBestMatchingColor(COL_ALPHA_OPAQUE));
723 const BitmapColor aTransparentColor(pWriteAcc->GetBestMatchingColor(COL_ALPHA_TRANSPARENT));
724
725 BitmapColor aCol;
726 tools::Long nR, nG, nB;
727 const tools::Long nMinR = MinMax<tools::Long>(rTransColor.GetRed() - nTol, 0, 255);
728 const tools::Long nMaxR = MinMax<tools::Long>(rTransColor.GetRed() + nTol, 0, 255);
729 const tools::Long nMinG = MinMax<tools::Long>(rTransColor.GetGreen() - nTol, 0, 255);
730 const tools::Long nMaxG = MinMax<tools::Long>(rTransColor.GetGreen() + nTol, 0, 255);
731 const tools::Long nMinB = MinMax<tools::Long>(rTransColor.GetBlue() - nTol, 0, 255);
732 const tools::Long nMaxB = MinMax<tools::Long>(rTransColor.GetBlue() + nTol, 0, 255);
733
734 if (pReadAcc->HasPalette())
735 {
736 for (tools::Long nY = 0; nY < nHeight; nY++)
737 {
738 Scanline pScanline = pWriteAcc->GetScanline(nY);
739 Scanline pScanlineRead = pReadAcc->GetScanline(nY);
740 for (tools::Long nX = 0; nX < nWidth; nX++)
741 {
742 aCol = pReadAcc->GetPaletteColor(pReadAcc->GetIndexFromData(pScanlineRead, nX));
743 nR = aCol.GetRed();
744 nG = aCol.GetGreen();
745 nB = aCol.GetBlue();
746
747 if (nMinR <= nR && nMaxR >= nR && nMinG <= nG && nMaxG >= nG && nMinB <= nB
748 && nMaxB >= nB)
749 {
750 pWriteAcc->SetPixelOnData(pScanline, nX, aTransparentColor);
751 }
752 else
753 {
754 pWriteAcc->SetPixelOnData(pScanline, nX, aOpaqueColor);
755 }
756 }
757 }
758 }
759 else
760 {
761 for (tools::Long nY = 0; nY < nHeight; nY++)
762 {
763 Scanline pScanline = pWriteAcc->GetScanline(nY);
764 Scanline pScanlineRead = pReadAcc->GetScanline(nY);
765 for (tools::Long nX = 0; nX < nWidth; nX++)
766 {
767 aCol = pReadAcc->GetPixelFromData(pScanlineRead, nX);
768 nR = aCol.GetRed();
769 nG = aCol.GetGreen();
770 nB = aCol.GetBlue();
771
772 if (nMinR <= nR && nMaxR >= nR && nMinG <= nG && nMaxG >= nG && nMinB <= nB
773 && nMaxB >= nB)
774 {
775 pWriteAcc->SetPixelOnData(pScanline, nX, aTransparentColor);
776 }
777 else
778 {
779 pWriteAcc->SetPixelOnData(pScanline, nX, aOpaqueColor);
780 }
781 }
782 }
783 }
784
785 pWriteAcc.reset();
786 pReadAcc.reset();
787
788 aNewBmp.maPrefSize = maPrefSize;
790
791 return aNewBmp;
792}
793
794vcl::Region Bitmap::CreateRegion(const Color& rColor, const tools::Rectangle& rRect) const
795{
796 tools::Rectangle aRect(rRect);
797 ScopedReadAccess pReadAcc(const_cast<Bitmap&>(*this));
798
800 aRect.Normalize();
801
802 if (!pReadAcc)
803 return vcl::Region(aRect);
804
805 vcl::Region aRegion;
806 const tools::Long nLeft = aRect.Left();
807 const tools::Long nTop = aRect.Top();
808 const tools::Long nRight = aRect.Right();
809 const tools::Long nBottom = aRect.Bottom();
810 const BitmapColor aMatch(pReadAcc->GetBestMatchingColor(rColor));
811
812 std::vector<tools::Long> aLine;
813 tools::Long nYStart(nTop);
814 tools::Long nY(nTop);
815
816 for (; nY <= nBottom; nY++)
817 {
818 std::vector<tools::Long> aNewLine;
819 tools::Long nX(nLeft);
820 Scanline pScanlineRead = pReadAcc->GetScanline(nY);
821
822 for (; nX <= nRight;)
823 {
824 while ((nX <= nRight) && (aMatch != pReadAcc->GetPixelFromData(pScanlineRead, nX)))
825 nX++;
826
827 if (nX <= nRight)
828 {
829 aNewLine.push_back(nX);
830
831 while ((nX <= nRight) && (aMatch == pReadAcc->GetPixelFromData(pScanlineRead, nX)))
832 {
833 nX++;
834 }
835
836 aNewLine.push_back(nX - 1);
837 }
838 }
839
840 if (aNewLine != aLine)
841 {
842 // need to write aLine, it's different from the next line
843 if (!aLine.empty())
844 {
845 tools::Rectangle aSubRect;
846
847 // enter y values and proceed ystart
848 aSubRect.SetTop(nYStart);
849 aSubRect.SetBottom(nY ? nY - 1 : 0);
850
851 for (size_t a(0); a < aLine.size();)
852 {
853 aSubRect.SetLeft(aLine[a++]);
854 aSubRect.SetRight(aLine[a++]);
855 aRegion.Union(aSubRect);
856 }
857 }
858
859 // copy line as new line
860 aLine = aNewLine;
861 nYStart = nY;
862 }
863 }
864
865 // write last line if used
866 if (!aLine.empty())
867 {
868 tools::Rectangle aSubRect;
869
870 // enter y values
871 aSubRect.SetTop(nYStart);
872 aSubRect.SetBottom(nY ? nY - 1 : 0);
873
874 for (size_t a(0); a < aLine.size();)
875 {
876 aSubRect.SetLeft(aLine[a++]);
877 aSubRect.SetRight(aLine[a++]);
878 aRegion.Union(aSubRect);
879 }
880 }
881
882 pReadAcc.reset();
883
884 return aRegion;
885}
886
887bool Bitmap::Replace(const AlphaMask& rAlpha, const Color& rMergeColor)
888{
890 ScopedReadAccess pAcc(*this);
891 AlphaMask::ScopedReadAccess pAlphaAcc(const_cast<AlphaMask&>(rAlpha));
892 BitmapScopedWriteAccess pNewAcc(aNewBmp);
893
894 if (!pAcc || !pAlphaAcc || !pNewAcc)
895 return false;
896
897 BitmapColor aCol;
898 const tools::Long nWidth = std::min(pAlphaAcc->Width(), pAcc->Width());
899 const tools::Long nHeight = std::min(pAlphaAcc->Height(), pAcc->Height());
900
901 for (tools::Long nY = 0; nY < nHeight; nY++)
902 {
903 Scanline pScanline = pNewAcc->GetScanline(nY);
904 Scanline pScanlineAlpha = pAlphaAcc->GetScanline(nY);
905 for (tools::Long nX = 0; nX < nWidth; nX++)
906 {
907 aCol = pAcc->GetColor(nY, nX);
908 aCol.Merge(rMergeColor, pAlphaAcc->GetIndexFromData(pScanlineAlpha, nX));
909 pNewAcc->SetPixelOnData(pScanline, nX, aCol);
910 }
911 }
912
913 pAcc.reset();
914 pAlphaAcc.reset();
915 pNewAcc.reset();
916
918 const Size aSize(maPrefSize);
919
920 *this = aNewBmp;
921
923 maPrefSize = aSize;
924
925 return true;
926}
927
928bool Bitmap::Replace(const Color& rSearchColor, const Color& rReplaceColor, sal_uInt8 nTol)
929{
930 if (mxSalBmp)
931 {
932 // implementation specific replace
933 std::shared_ptr<SalBitmap> xImpBmp(ImplGetSVData()->mpDefInst->CreateSalBitmap());
934 if (xImpBmp->Create(*mxSalBmp) && xImpBmp->Replace(rSearchColor, rReplaceColor, nTol))
935 {
936 ImplSetSalBitmap(xImpBmp);
937 maPrefMapMode = MapMode(MapUnit::MapPixel);
938 maPrefSize = xImpBmp->GetSize();
939 return true;
940 }
941 }
942
943 BitmapScopedWriteAccess pAcc(*this);
944 if (!pAcc)
945 return false;
946
947 const tools::Long nMinR = MinMax<tools::Long>(rSearchColor.GetRed() - nTol, 0, 255);
948 const tools::Long nMaxR = MinMax<tools::Long>(rSearchColor.GetRed() + nTol, 0, 255);
949 const tools::Long nMinG = MinMax<tools::Long>(rSearchColor.GetGreen() - nTol, 0, 255);
950 const tools::Long nMaxG = MinMax<tools::Long>(rSearchColor.GetGreen() + nTol, 0, 255);
951 const tools::Long nMinB = MinMax<tools::Long>(rSearchColor.GetBlue() - nTol, 0, 255);
952 const tools::Long nMaxB = MinMax<tools::Long>(rSearchColor.GetBlue() + nTol, 0, 255);
953
954 if (pAcc->HasPalette())
955 {
956 for (sal_uInt16 i = 0, nPalCount = pAcc->GetPaletteEntryCount(); i < nPalCount; i++)
957 {
958 const BitmapColor& rCol = pAcc->GetPaletteColor(i);
959
960 if (nMinR <= rCol.GetRed() && nMaxR >= rCol.GetRed() && nMinG <= rCol.GetGreen()
961 && nMaxG >= rCol.GetGreen() && nMinB <= rCol.GetBlue() && nMaxB >= rCol.GetBlue())
962 {
963 pAcc->SetPaletteColor(i, rReplaceColor);
964 }
965 }
966 }
967 else
968 {
969 BitmapColor aCol;
970 const BitmapColor aReplace(pAcc->GetBestMatchingColor(rReplaceColor));
971
972 for (tools::Long nY = 0, nHeight = pAcc->Height(); nY < nHeight; nY++)
973 {
974 Scanline pScanline = pAcc->GetScanline(nY);
975 for (tools::Long nX = 0, nWidth = pAcc->Width(); nX < nWidth; nX++)
976 {
977 aCol = pAcc->GetPixelFromData(pScanline, nX);
978
979 if (nMinR <= aCol.GetRed() && nMaxR >= aCol.GetRed() && nMinG <= aCol.GetGreen()
980 && nMaxG >= aCol.GetGreen() && nMinB <= aCol.GetBlue()
981 && nMaxB >= aCol.GetBlue())
982 {
983 pAcc->SetPixelOnData(pScanline, nX, aReplace);
984 }
985 }
986 }
987 }
988
989 pAcc.reset();
990
991 return true;
992}
993
994bool Bitmap::Replace(const Color* pSearchColors, const Color* pReplaceColors, size_t nColorCount,
995 sal_uInt8 const* pTols)
996{
997 BitmapScopedWriteAccess pAcc(*this);
998 if (!pAcc)
999 return false;
1000
1001 std::vector<sal_uInt8> aMinR(nColorCount);
1002 std::vector<sal_uInt8> aMaxR(nColorCount);
1003 std::vector<sal_uInt8> aMinG(nColorCount);
1004 std::vector<sal_uInt8> aMaxG(nColorCount);
1005 std::vector<sal_uInt8> aMinB(nColorCount);
1006 std::vector<sal_uInt8> aMaxB(nColorCount);
1007
1008 if (pTols)
1009 {
1010 for (size_t i = 0; i < nColorCount; ++i)
1011 {
1012 const Color& rCol = pSearchColors[i];
1013 const sal_uInt8 nTol = pTols[i];
1014
1015 aMinR[i] = std::clamp(rCol.GetRed() - nTol, 0, 255);
1016 aMaxR[i] = std::clamp(rCol.GetRed() + nTol, 0, 255);
1017 aMinG[i] = std::clamp(rCol.GetGreen() - nTol, 0, 255);
1018 aMaxG[i] = std::clamp(rCol.GetGreen() + nTol, 0, 255);
1019 aMinB[i] = std::clamp(rCol.GetBlue() - nTol, 0, 255);
1020 aMaxB[i] = std::clamp(rCol.GetBlue() + nTol, 0, 255);
1021 }
1022 }
1023 else
1024 {
1025 for (size_t i = 0; i < nColorCount; ++i)
1026 {
1027 const Color& rCol = pSearchColors[i];
1028
1029 aMinR[i] = rCol.GetRed();
1030 aMaxR[i] = rCol.GetRed();
1031 aMinG[i] = rCol.GetGreen();
1032 aMaxG[i] = rCol.GetGreen();
1033 aMinB[i] = rCol.GetBlue();
1034 aMaxB[i] = rCol.GetBlue();
1035 }
1036 }
1037
1038 if (pAcc->HasPalette())
1039 {
1040 for (sal_uInt16 nEntry = 0, nPalCount = pAcc->GetPaletteEntryCount(); nEntry < nPalCount;
1041 nEntry++)
1042 {
1043 const BitmapColor& rCol = pAcc->GetPaletteColor(nEntry);
1044
1045 for (size_t i = 0; i < nColorCount; ++i)
1046 {
1047 if (aMinR[i] <= rCol.GetRed() && aMaxR[i] >= rCol.GetRed()
1048 && aMinG[i] <= rCol.GetGreen() && aMaxG[i] >= rCol.GetGreen()
1049 && aMinB[i] <= rCol.GetBlue() && aMaxB[i] >= rCol.GetBlue())
1050 {
1051 pAcc->SetPaletteColor(nEntry, pReplaceColors[i]);
1052 break;
1053 }
1054 }
1055 }
1056 }
1057 else
1058 {
1059 std::vector<BitmapColor> aReplaces(nColorCount);
1060
1061 for (size_t i = 0; i < nColorCount; ++i)
1062 aReplaces[i] = pAcc->GetBestMatchingColor(pReplaceColors[i]);
1063
1064 for (tools::Long nY = 0, nHeight = pAcc->Height(); nY < nHeight; nY++)
1065 {
1066 Scanline pScanline = pAcc->GetScanline(nY);
1067 for (tools::Long nX = 0, nWidth = pAcc->Width(); nX < nWidth; nX++)
1068 {
1069 BitmapColor aCol = pAcc->GetPixelFromData(pScanline, nX);
1070
1071 for (size_t i = 0; i < nColorCount; ++i)
1072 {
1073 if (aMinR[i] <= aCol.GetRed() && aMaxR[i] >= aCol.GetRed()
1074 && aMinG[i] <= aCol.GetGreen() && aMaxG[i] >= aCol.GetGreen()
1075 && aMinB[i] <= aCol.GetBlue() && aMaxB[i] >= aCol.GetBlue())
1076 {
1077 pAcc->SetPixelOnData(pScanline, nX, aReplaces[i]);
1078 break;
1079 }
1080 }
1081 }
1082 }
1083 }
1084
1085 pAcc.reset();
1086
1087 return true;
1088}
1089
1090bool Bitmap::CombineOr(const Bitmap& rMask)
1091{
1092 ScopedReadAccess pMaskAcc(const_cast<Bitmap&>(rMask));
1093 BitmapScopedWriteAccess pAcc(*this);
1094
1095 if (!pMaskAcc || !pAcc)
1096 return false;
1097
1098 const tools::Long nWidth = std::min(pMaskAcc->Width(), pAcc->Width());
1099 const tools::Long nHeight = std::min(pMaskAcc->Height(), pAcc->Height());
1100 const Color aColBlack(COL_BLACK);
1101 const BitmapColor aWhite(pAcc->GetBestMatchingColor(COL_WHITE));
1102 const BitmapColor aBlack(pAcc->GetBestMatchingColor(aColBlack));
1103 const BitmapColor aMaskBlack(pMaskAcc->GetBestMatchingColor(aColBlack));
1104
1105 for (tools::Long nY = 0; nY < nHeight; nY++)
1106 {
1107 Scanline pScanline = pAcc->GetScanline(nY);
1108 Scanline pScanlineMask = pMaskAcc->GetScanline(nY);
1109 for (tools::Long nX = 0; nX < nWidth; nX++)
1110 {
1111 if (pMaskAcc->GetPixelFromData(pScanlineMask, nX) != aMaskBlack
1112 || pAcc->GetPixelFromData(pScanline, nX) != aBlack)
1113 {
1114 pAcc->SetPixelOnData(pScanline, nX, aWhite);
1115 }
1116 else
1117 {
1118 pAcc->SetPixelOnData(pScanline, nX, aBlack);
1119 }
1120 }
1121 }
1122
1123 return true;
1124}
1125
1126// TODO: Have a look at OutputDevice::ImplDrawAlpha() for some
1127// optimizations. Might even consolidate the code here and there.
1128bool Bitmap::Blend(const AlphaMask& rAlpha, const Color& rBackgroundColor)
1129{
1130 // Convert to a truecolor bitmap, if we're a paletted one. There's room for tradeoff decision here,
1131 // maybe later for an overload (or a flag)
1134
1135 AlphaMask::ScopedReadAccess pAlphaAcc(const_cast<AlphaMask&>(rAlpha));
1136
1137 BitmapScopedWriteAccess pAcc(*this);
1138
1139 if (!pAlphaAcc || !pAcc)
1140 return false;
1141
1142 const tools::Long nWidth = std::min(pAlphaAcc->Width(), pAcc->Width());
1143 const tools::Long nHeight = std::min(pAlphaAcc->Height(), pAcc->Height());
1144
1145 for (tools::Long nY = 0; nY < nHeight; ++nY)
1146 {
1147 Scanline pScanline = pAcc->GetScanline(nY);
1148 Scanline pScanlineAlpha = pAlphaAcc->GetScanline(nY);
1149 for (tools::Long nX = 0; nX < nWidth; ++nX)
1150 {
1151 BitmapColor aBmpColor = pAcc->GetPixelFromData(pScanline, nX);
1152 aBmpColor.Merge(rBackgroundColor, pAlphaAcc->GetIndexFromData(pScanlineAlpha, nX));
1153 pAcc->SetPixelOnData(pScanline, nX, aBmpColor);
1154 }
1155 }
1156
1157 return true;
1158}
1159
1160/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
sal_uInt8 * Scanline
Definition: Scanline.hxx:26
sal_uInt8 GetIndex() const
Definition: BitmapColor.hxx:70
tools::Long Height() const
tools::Long Width() const
const BitmapPalette & GetPalette() const
BitmapColor GetBestMatchingColor(const BitmapColor &rBitmapColor) const
bool HasPalette() const
ScanlineFormat GetScanlineFormat() const
const BitmapColor & GetPaletteColor(sal_uInt16 nColor) const
sal_uInt32 GetScanlineSize() const
sal_uInt16 GetEntryCount() const
BitmapColor GetPixel(tools::Long nY, tools::Long nX) const
BitmapColor GetColor(tools::Long nY, tools::Long nX) const
BitmapColor GetPixelFromData(const sal_uInt8 *pData, tools::Long nX) const
sal_uInt8 GetIndexFromData(const sal_uInt8 *pData, tools::Long nX) const
Scanline GetScanline(tools::Long nY) const
bool CombineOr(const Bitmap &rMask)
Perform boolean OR operation with another bitmap.
bool Blend(const AlphaMask &rAlpha, const Color &rBackgroundColor)
Alpha-blend the given bitmap against a specified uniform background color.
bool Rotate(Degree10 nAngle10, const Color &rFillColor)
Rotate bitmap by the specified angle.
SAL_DLLPRIVATE void ImplSetSalBitmap(const std::shared_ptr< SalBitmap > &xImpBmp)
Bitmap CreateMask(const Color &rTransColor) const
Create on-off mask from bitmap.
bool Convert(BmpConversion eConversion)
Convert bitmap format.
static const BitmapPalette & GetGreyPalette(int nEntries)
SAL_DLLPRIVATE void ReassignWithSize(const Bitmap &rBitmap)
ReassignWithSize and recalculate bitmap.
bool Replace(const AlphaMask &rAlpha, const Color &rMergeColor)
Merge bitmap with given background color according to specified alpha mask.
Size GetSizePixel() const
bool IsEmpty() const
bool Invert()
Perform the Invert operation on every pixel.
Definition: bitmappaint.cxx:61
vcl::Region CreateRegion(const Color &rColor, const tools::Rectangle &rRect) const
Create region of similar colors in a given rectangle.
bool Erase(const Color &rFillColor)
Fill the entire bitmap with the given color.
Definition: bitmappaint.cxx:34
MapMode maPrefMapMode
vcl::PixelFormat getPixelFormat() const
AlphaMask CreateAlphaMask(const Color &rTransColor) const
Create on-off alpha mask from bitmap.
std::shared_ptr< SalBitmap > mxSalBmp
bool Mirror(BmpMirrorFlags nMirrorFlags)
Mirror the bitmap.
sal_uInt8 GetBlue() const
void Merge(const Color &rMergeColor, sal_uInt8 cTransparency)
void Invert()
sal_uInt8 GetRed() const
sal_uInt8 GetGreen() const
constexpr tools::Long Height() const
constexpr tools::Long Width() const
tools::Rectangle GetBoundRect() const
void Rotate(const Point &rCenter, double fSin, double fCos)
constexpr void SetLeft(tools::Long v)
constexpr void SetTop(tools::Long v)
constexpr tools::Long Top() const
constexpr void SetRight(tools::Long v)
constexpr Size GetSize() const
constexpr tools::Long Right() const
constexpr void SetBottom(tools::Long v)
tools::Rectangle & Intersection(const tools::Rectangle &rRect)
constexpr tools::Long Left() const
constexpr tools::Long Bottom() const
void Union(const tools::Rectangle &rRegion)
Definition: region.cxx:507
This template handles BitmapAccess the RAII way.
constexpr ::Color COL_WHITE(0xFF, 0xFF, 0xFF)
constexpr ::Color COL_ALPHA_OPAQUE(0xff, 0xff, 0xff)
constexpr ::Color COL_ALPHA_TRANSPARENT(0x00, 0x00, 0x00)
constexpr ::Color COL_BLACK(0x00, 0x00, 0x00)
int nCount
double toRadians(D x)
BmpMirrorFlags
uno_Any a
int i
long Long
constexpr bool isPalettePixelFormat(PixelFormat ePixelFormat)
Is it a pixel format that forces creation of a palette.
Definition: BitmapTypes.hxx:28
HashMap_OWString_Interface aMap
ImplSVData * ImplGetSVData()
Definition: svdata.cxx:77
unsigned char sal_uInt8