LibreOffice Module vcl (master)  1
BitmapFilterStackBlur.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  */
10 
12 #include <vcl/bitmapaccess.hxx>
13 #include <bitmapwriteaccess.hxx>
14 #include <sal/log.hxx>
15 
17 
18 namespace
19 {
20 const sal_Int16 constMultiplyTable[255]
21  = { 512, 512, 456, 512, 328, 456, 335, 512, 405, 328, 271, 456, 388, 335, 292, 512, 454,
22  405, 364, 328, 298, 271, 496, 456, 420, 388, 360, 335, 312, 292, 273, 512, 482, 454,
23  428, 405, 383, 364, 345, 328, 312, 298, 284, 271, 259, 496, 475, 456, 437, 420, 404,
24  388, 374, 360, 347, 335, 323, 312, 302, 292, 282, 273, 265, 512, 497, 482, 468, 454,
25  441, 428, 417, 405, 394, 383, 373, 364, 354, 345, 337, 328, 320, 312, 305, 298, 291,
26  284, 278, 271, 265, 259, 507, 496, 485, 475, 465, 456, 446, 437, 428, 420, 412, 404,
27  396, 388, 381, 374, 367, 360, 354, 347, 341, 335, 329, 323, 318, 312, 307, 302, 297,
28  292, 287, 282, 278, 273, 269, 265, 261, 512, 505, 497, 489, 482, 475, 468, 461, 454,
29  447, 441, 435, 428, 422, 417, 411, 405, 399, 394, 389, 383, 378, 373, 368, 364, 359,
30  354, 350, 345, 341, 337, 332, 328, 324, 320, 316, 312, 309, 305, 301, 298, 294, 291,
31  287, 284, 281, 278, 274, 271, 268, 265, 262, 259, 257, 507, 501, 496, 491, 485, 480,
32  475, 470, 465, 460, 456, 451, 446, 442, 437, 433, 428, 424, 420, 416, 412, 408, 404,
33  400, 396, 392, 388, 385, 381, 377, 374, 370, 367, 363, 360, 357, 354, 350, 347, 344,
34  341, 338, 335, 332, 329, 326, 323, 320, 318, 315, 312, 310, 307, 304, 302, 299, 297,
35  294, 292, 289, 287, 285, 282, 280, 278, 275, 273, 271, 269, 267, 265, 263, 261, 259 };
36 
37 const sal_Int16 constShiftTable[255]
38  = { 9, 11, 12, 13, 13, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 17, 17, 17, 17, 17, 17, 17,
39  18, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
40  19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 21, 21, 21,
41  21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
42  21, 21, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
43  22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23,
44  23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
45  23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
46  23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
47  24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
48  24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
49  24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24 };
50 
51 struct BlurSharedData
52 {
53  BitmapReadAccess* mpReadAccess;
54  BitmapWriteAccess* mpWriteAccess;
55  long mnRadius;
56  long mnComponentWidth;
57  long mnDiv;
58  long mnColorChannels;
59 
60  BlurSharedData(BitmapReadAccess* pReadAccess, BitmapWriteAccess* pWriteAccess, long aRadius,
61  long nComponentWidth, long nColorChannels)
62  : mpReadAccess(pReadAccess)
63  , mpWriteAccess(pWriteAccess)
64  , mnRadius(aRadius)
65  , mnComponentWidth(nComponentWidth)
66  , mnDiv(aRadius + aRadius + 1)
67  , mnColorChannels(nColorChannels)
68  {
69  }
70 };
71 
72 struct BlurArrays
73 {
74  BlurSharedData maShared;
75 
76  std::vector<sal_uInt8> maStackBuffer;
77  std::vector<long> maPositionTable;
78  std::vector<long> maWeightTable;
79 
80  std::vector<long> mnSumVector;
81  std::vector<long> mnInSumVector;
82  std::vector<long> mnOutSumVector;
83 
84  BlurArrays(BlurSharedData const& rShared)
85  : maShared(rShared)
86  , maStackBuffer(maShared.mnDiv * maShared.mnComponentWidth)
87  , maPositionTable(maShared.mnDiv)
88  , maWeightTable(maShared.mnDiv)
89  , mnSumVector(maShared.mnColorChannels)
90  , mnInSumVector(maShared.mnColorChannels)
91  , mnOutSumVector(maShared.mnColorChannels)
92  {
93  }
94 
95  void initializeWeightAndPositions(long nLastIndex)
96  {
97  for (long i = 0; i < maShared.mnDiv; i++)
98  {
99  maPositionTable[i] = std::clamp(i - maShared.mnRadius, 0L, nLastIndex);
100  maWeightTable[i] = maShared.mnRadius + 1 - std::abs(i - maShared.mnRadius);
101  }
102  }
103 
104  long getMultiplyValue() { return static_cast<long>(constMultiplyTable[maShared.mnRadius]); }
105 
106  long getShiftValue() { return static_cast<long>(constShiftTable[maShared.mnRadius]); }
107 };
108 
109 typedef void (*BlurRangeFn)(BlurSharedData const& rShared, long nStartY, long nEndY);
110 
111 class BlurTask : public comphelper::ThreadTask
112 {
113  BlurRangeFn mpBlurFunction;
114  BlurSharedData& mrShared;
115  long mnStartY;
116  long mnEndY;
117 
118 public:
119  explicit BlurTask(const std::shared_ptr<comphelper::ThreadTaskTag>& pTag,
120  BlurRangeFn pBlurFunction, BlurSharedData& rShared, long nStartY, long nEndY)
121  : comphelper::ThreadTask(pTag)
122  , mpBlurFunction(pBlurFunction)
123  , mrShared(rShared)
124  , mnStartY(nStartY)
125  , mnEndY(nEndY)
126  {
127  }
128 
129  virtual void doWork() override { mpBlurFunction(mrShared, mnStartY, mnEndY); }
130 };
131 
132 struct SumFunction24
133 {
134  static inline void add(long*& pValue1, long nConstant)
135  {
136  pValue1[0] += nConstant;
137  pValue1[1] += nConstant;
138  pValue1[2] += nConstant;
139  }
140 
141  static inline void set(long*& pValue1, long nConstant)
142  {
143  pValue1[0] = nConstant;
144  pValue1[1] = nConstant;
145  pValue1[2] = nConstant;
146  }
147 
148  static inline void add(long*& pValue1, sal_uInt8*& pValue2)
149  {
150  pValue1[0] += pValue2[0];
151  pValue1[1] += pValue2[1];
152  pValue1[2] += pValue2[2];
153  }
154 
155  static inline void add(long*& pValue1, long*& pValue2)
156  {
157  pValue1[0] += pValue2[0];
158  pValue1[1] += pValue2[1];
159  pValue1[2] += pValue2[2];
160  }
161 
162  static inline void sub(long*& pValue1, sal_uInt8*& pValue2)
163  {
164  pValue1[0] -= pValue2[0];
165  pValue1[1] -= pValue2[1];
166  pValue1[2] -= pValue2[2];
167  }
168 
169  static inline void sub(long*& pValue1, long*& pValue2)
170  {
171  pValue1[0] -= pValue2[0];
172  pValue1[1] -= pValue2[1];
173  pValue1[2] -= pValue2[2];
174  }
175 
176  static inline void assignPtr(sal_uInt8*& pValue1, sal_uInt8*& pValue2)
177  {
178  pValue1[0] = pValue2[0];
179  pValue1[1] = pValue2[1];
180  pValue1[2] = pValue2[2];
181  }
182 
183  static inline void assignMulAndShr(sal_uInt8*& result, long*& sum, long multiply, long shift)
184  {
185  result[0] = (multiply * sum[0]) >> shift;
186  result[1] = (multiply * sum[1]) >> shift;
187  result[2] = (multiply * sum[2]) >> shift;
188  }
189 };
190 
191 struct SumFunction8
192 {
193  static inline void add(long*& pValue1, long nConstant) { pValue1[0] += nConstant; }
194 
195  static inline void set(long*& pValue1, long nConstant) { pValue1[0] = nConstant; }
196 
197  static inline void add(long*& pValue1, sal_uInt8*& pValue2) { pValue1[0] += pValue2[0]; }
198 
199  static inline void add(long*& pValue1, long*& pValue2) { pValue1[0] += pValue2[0]; }
200 
201  static inline void sub(long*& pValue1, sal_uInt8*& pValue2) { pValue1[0] -= pValue2[0]; }
202 
203  static inline void sub(long*& pValue1, long*& pValue2) { pValue1[0] -= pValue2[0]; }
204 
205  static inline void assignPtr(sal_uInt8*& pValue1, sal_uInt8*& pValue2)
206  {
207  pValue1[0] = pValue2[0];
208  }
209 
210  static inline void assignMulAndShr(sal_uInt8*& result, long*& sum, long multiply, long shift)
211  {
212  result[0] = (multiply * sum[0]) >> shift;
213  }
214 };
215 
216 template <typename SumFunction>
217 void stackBlurHorizontal(BlurSharedData const& rShared, long nStart, long nEnd)
218 {
219  BitmapReadAccess* pReadAccess = rShared.mpReadAccess;
220  BitmapWriteAccess* pWriteAccess = rShared.mpWriteAccess;
221 
222  BlurArrays aArrays(rShared);
223 
224  sal_uInt8* pStack = aArrays.maStackBuffer.data();
225  sal_uInt8* pStackPtr;
226 
227  long nWidth = pReadAccess->Width();
228  long nLastIndexX = nWidth - 1;
229 
230  long nMultiplyValue = aArrays.getMultiplyValue();
231  long nShiftValue = aArrays.getShiftValue();
232 
233  long nRadius = rShared.mnRadius;
234  long nComponentWidth = rShared.mnComponentWidth;
235  long nDiv = rShared.mnDiv;
236 
237  Scanline pSourcePointer;
238  Scanline pDestinationPointer;
239 
240  long nXPosition;
241  long nStackIndex;
242  long nStackIndexStart;
243  long nWeight;
244 
245  aArrays.initializeWeightAndPositions(nLastIndexX);
246 
247  long* nSum = aArrays.mnSumVector.data();
248  long* nInSum = aArrays.mnInSumVector.data();
249  long* nOutSum = aArrays.mnOutSumVector.data();
250 
251  long* pPositionPointer = aArrays.maPositionTable.data();
252  long* pWeightPointer = aArrays.maWeightTable.data();
253 
254  for (long y = nStart; y <= nEnd; y++)
255  {
256  SumFunction::set(nSum, 0L);
257  SumFunction::set(nInSum, 0L);
258  SumFunction::set(nOutSum, 0L);
259 
260  // Pre-initialize blur data for first pixel.
261  // aArrays.maPositionTable contains values like (for radius of 5): [0,0,0,0,0,0,1,2,3,4,5],
262  // which are used as pixels indices in the current row that we use to prepare information
263  // for the first pixel; aArrays.maWeightTable has [1,2,3,4,5,6,5,4,3,2,1]. Before looking at
264  // the first row pixel, we pretend to have processed fake previous pixels, as if the row was
265  // extended to the left with the same color as that of the first pixel.
266  for (long i = 0; i < nDiv; i++)
267  {
268  pSourcePointer = pReadAccess->GetScanline(y) + nComponentWidth * pPositionPointer[i];
269 
270  pStackPtr = &pStack[nComponentWidth * i];
271 
272  SumFunction::assignPtr(pStackPtr, pSourcePointer);
273 
274  nWeight = pWeightPointer[i];
275 
276  SumFunction::add(nSum, pSourcePointer[0] * nWeight);
277 
278  if (i - nRadius > 0)
279  {
280  SumFunction::add(nInSum, pSourcePointer);
281  }
282  else
283  {
284  SumFunction::add(nOutSum, pSourcePointer);
285  }
286  }
287 
288  nStackIndex = nRadius;
289  nXPosition = std::min(nRadius, nLastIndexX);
290 
291  pSourcePointer = pReadAccess->GetScanline(y) + nComponentWidth * nXPosition;
292 
293  for (long x = 0; x < nWidth; x++)
294  {
295  pDestinationPointer = pWriteAccess->GetScanline(y) + nComponentWidth * x;
296 
297  SumFunction::assignMulAndShr(pDestinationPointer, nSum, nMultiplyValue, nShiftValue);
298 
299  SumFunction::sub(nSum, nOutSum);
300 
301  nStackIndexStart = nStackIndex + nDiv - nRadius;
302  if (nStackIndexStart >= nDiv)
303  {
304  nStackIndexStart -= nDiv;
305  }
306  pStackPtr = &pStack[nComponentWidth * nStackIndexStart];
307 
308  SumFunction::sub(nOutSum, pStackPtr);
309 
310  if (nXPosition < nLastIndexX)
311  {
312  nXPosition++;
313  pSourcePointer = pReadAccess->GetScanline(y) + nComponentWidth * nXPosition;
314  }
315 
316  SumFunction::assignPtr(pStackPtr, pSourcePointer);
317 
318  SumFunction::add(nInSum, pSourcePointer);
319 
320  SumFunction::add(nSum, nInSum);
321 
322  nStackIndex++;
323  if (nStackIndex >= nDiv)
324  {
325  nStackIndex = 0;
326  }
327 
328  pStackPtr = &pStack[nStackIndex * nComponentWidth];
329 
330  SumFunction::add(nOutSum, pStackPtr);
331  SumFunction::sub(nInSum, pStackPtr);
332  }
333  }
334 }
335 
336 template <typename SumFunction>
337 void stackBlurVertical(BlurSharedData const& rShared, long nStart, long nEnd)
338 {
339  BitmapReadAccess* pReadAccess = rShared.mpReadAccess;
340  BitmapWriteAccess* pWriteAccess = rShared.mpWriteAccess;
341 
342  BlurArrays aArrays(rShared);
343 
344  sal_uInt8* pStack = aArrays.maStackBuffer.data();
345  sal_uInt8* pStackPtr;
346 
347  long nHeight = pReadAccess->Height();
348  long nLastIndexY = nHeight - 1;
349 
350  long nMultiplyValue = aArrays.getMultiplyValue();
351  long nShiftValue = aArrays.getShiftValue();
352 
353  long nRadius = rShared.mnRadius;
354  long nComponentWidth = rShared.mnComponentWidth;
355  long nDiv = rShared.mnDiv;
356 
357  Scanline pSourcePointer;
358  Scanline pDestinationPointer;
359 
360  long nYPosition;
361  long nStackIndex;
362  long nStackIndexStart;
363  long nWeight;
364 
365  aArrays.initializeWeightAndPositions(nLastIndexY);
366 
367  long* nSum = aArrays.mnSumVector.data();
368  long* nInSum = aArrays.mnInSumVector.data();
369  long* nOutSum = aArrays.mnOutSumVector.data();
370  long* pPositionPointer = aArrays.maPositionTable.data();
371  long* pWeightPointer = aArrays.maWeightTable.data();
372 
373  for (long x = nStart; x <= nEnd; x++)
374  {
375  SumFunction::set(nSum, 0L);
376  SumFunction::set(nInSum, 0L);
377  SumFunction::set(nOutSum, 0L);
378 
379  // Pre-initialize blur data for first pixel.
380  // aArrays.maPositionTable contains values like (for radius of 5): [0,0,0,0,0,0,1,2,3,4,5],
381  // which are used as pixels indices in the current column that we use to prepare information
382  // for the first pixel; aArrays.maWeightTable has [1,2,3,4,5,6,5,4,3,2,1]. Before looking at
383  // the first column pixels, we pretend to have processed fake previous pixels, as if the
384  // column was extended to the top with the same color as that of the first pixel.
385  for (long i = 0; i < nDiv; i++)
386  {
387  pSourcePointer = pReadAccess->GetScanline(pPositionPointer[i]) + nComponentWidth * x;
388 
389  pStackPtr = &pStack[nComponentWidth * i];
390 
391  SumFunction::assignPtr(pStackPtr, pSourcePointer);
392 
393  nWeight = pWeightPointer[i];
394 
395  SumFunction::add(nSum, pSourcePointer[0] * nWeight);
396 
397  if (i - nRadius > 0)
398  {
399  SumFunction::add(nInSum, pSourcePointer);
400  }
401  else
402  {
403  SumFunction::add(nOutSum, pSourcePointer);
404  }
405  }
406 
407  nStackIndex = nRadius;
408  nYPosition = std::min(nRadius, nLastIndexY);
409 
410  pSourcePointer = pReadAccess->GetScanline(nYPosition) + nComponentWidth * x;
411 
412  for (long y = 0; y < nHeight; y++)
413  {
414  pDestinationPointer = pWriteAccess->GetScanline(y) + nComponentWidth * x;
415 
416  SumFunction::assignMulAndShr(pDestinationPointer, nSum, nMultiplyValue, nShiftValue);
417 
418  SumFunction::sub(nSum, nOutSum);
419 
420  nStackIndexStart = nStackIndex + nDiv - nRadius;
421  if (nStackIndexStart >= nDiv)
422  {
423  nStackIndexStart -= nDiv;
424  }
425  pStackPtr = &pStack[nComponentWidth * nStackIndexStart];
426 
427  SumFunction::sub(nOutSum, pStackPtr);
428 
429  if (nYPosition < nLastIndexY)
430  {
431  nYPosition++;
432  pSourcePointer = pReadAccess->GetScanline(nYPosition) + nComponentWidth * x;
433  }
434 
435  SumFunction::assignPtr(pStackPtr, pSourcePointer);
436  SumFunction::add(nInSum, pSourcePointer);
437  SumFunction::add(nSum, nInSum);
438 
439  nStackIndex++;
440  if (nStackIndex >= nDiv)
441  {
442  nStackIndex = 0;
443  }
444 
445  pStackPtr = &pStack[nStackIndex * nComponentWidth];
446 
447  SumFunction::add(nOutSum, pStackPtr);
448  SumFunction::sub(nInSum, pStackPtr);
449  }
450  }
451 }
452 
453 constexpr long nThreadStrip = 16;
454 
455 void runStackBlur(Bitmap& rBitmap, const long nRadius, const long nComponentWidth,
456  const long nColorChannels, BlurRangeFn pBlurHorizontalFn,
457  BlurRangeFn pBlurVerticalFn, const bool bParallel)
458 {
459  if (bParallel)
460  {
461  try
462  {
465 
466  {
467  Bitmap::ScopedReadAccess pReadAccess(rBitmap);
468  BitmapScopedWriteAccess pWriteAccess(rBitmap);
469  BlurSharedData aSharedData(pReadAccess.get(), pWriteAccess.get(), nRadius,
470  nComponentWidth, nColorChannels);
471 
472  const long nFirstIndex = 0;
473  const long nLastIndex = pReadAccess->Height() - 1;
474 
475  vcl::bitmap::generateStripRanges<nThreadStrip>(
476  nFirstIndex, nLastIndex,
477  [&](long const nStart, long const nEnd, bool const bLast) {
478  if (!bLast)
479  {
480  auto pTask(std::make_unique<BlurTask>(pTag, pBlurHorizontalFn,
481  aSharedData, nStart, nEnd));
482  rShared.pushTask(std::move(pTask));
483  }
484  else
485  pBlurHorizontalFn(aSharedData, nStart, nEnd);
486  });
487  rShared.waitUntilDone(pTag);
488  }
489  {
490  Bitmap::ScopedReadAccess pReadAccess(rBitmap);
491  BitmapScopedWriteAccess pWriteAccess(rBitmap);
492  BlurSharedData aSharedData(pReadAccess.get(), pWriteAccess.get(), nRadius,
493  nComponentWidth, nColorChannels);
494 
495  const long nFirstIndex = 0;
496  const long nLastIndex = pReadAccess->Width() - 1;
497 
498  vcl::bitmap::generateStripRanges<nThreadStrip>(
499  nFirstIndex, nLastIndex,
500  [&](long const nStart, long const nEnd, bool const bLast) {
501  if (!bLast)
502  {
503  auto pTask(std::make_unique<BlurTask>(pTag, pBlurVerticalFn,
504  aSharedData, nStart, nEnd));
505  rShared.pushTask(std::move(pTask));
506  }
507  else
508  pBlurVerticalFn(aSharedData, nStart, nEnd);
509  });
510 
511  rShared.waitUntilDone(pTag);
512  }
513  }
514  catch (...)
515  {
516  SAL_WARN("vcl.gdi", "threaded bitmap blurring failed");
517  }
518  }
519  else
520  {
521  {
522  Bitmap::ScopedReadAccess pReadAccess(rBitmap);
523  BitmapScopedWriteAccess pWriteAccess(rBitmap);
524  BlurSharedData aSharedData(pReadAccess.get(), pWriteAccess.get(), nRadius,
525  nComponentWidth, nColorChannels);
526  long nFirstIndex = 0;
527  long nLastIndex = pReadAccess->Height() - 1;
528  pBlurHorizontalFn(aSharedData, nFirstIndex, nLastIndex);
529  }
530  {
531  Bitmap::ScopedReadAccess pReadAccess(rBitmap);
532  BitmapScopedWriteAccess pWriteAccess(rBitmap);
533  BlurSharedData aSharedData(pReadAccess.get(), pWriteAccess.get(), nRadius,
534  nComponentWidth, nColorChannels);
535  long nFirstIndex = 0;
536  long nLastIndex = pReadAccess->Width() - 1;
537  pBlurVerticalFn(aSharedData, nFirstIndex, nLastIndex);
538  }
539  }
540 }
541 
542 void stackBlur24(Bitmap& rBitmap, sal_Int32 nRadius, sal_Int32 nComponentWidth)
543 {
544  const bool bParallel = true;
545  // Limit radius
546  nRadius = std::clamp<sal_Int32>(nRadius, 2, 254);
547  const long nColorChannels = 3; // 3 color channel
548 
549  BlurRangeFn pBlurHorizontalFn = stackBlurHorizontal<SumFunction24>;
550  BlurRangeFn pBlurVerticalFn = stackBlurVertical<SumFunction24>;
551 
552  runStackBlur(rBitmap, nRadius, nComponentWidth, nColorChannels, pBlurHorizontalFn,
553  pBlurVerticalFn, bParallel);
554 }
555 
556 void stackBlur8(Bitmap& rBitmap, sal_Int32 nRadius, sal_Int32 nComponentWidth)
557 {
558  const bool bParallel = true;
559  // Limit radius
560  nRadius = std::clamp<sal_Int32>(nRadius, 2, 254);
561  const long nColorChannels = 1; // 1 color channel
562 
563  BlurRangeFn pBlurHorizontalFn = stackBlurHorizontal<SumFunction8>;
564  BlurRangeFn pBlurVerticalFn = stackBlurVertical<SumFunction8>;
565 
566  runStackBlur(rBitmap, nRadius, nComponentWidth, nColorChannels, pBlurHorizontalFn,
567  pBlurVerticalFn, bParallel);
568 }
569 
570 } // end anonymous namespace
571 
594  : mnRadius(nRadius)
595 {
596 }
597 
599 
601 {
602  Bitmap aBitmap = rBitmapEx.GetBitmap();
603  Bitmap result = filter(aBitmap);
604  return BitmapEx(result, rBitmapEx.GetMask());
605 }
606 
608 {
609  Bitmap bitmapCopy(rBitmap);
610  ScanlineFormat nScanlineFormat;
611  {
612  Bitmap::ScopedReadAccess pReadAccess(bitmapCopy);
613  nScanlineFormat = pReadAccess->GetScanlineFormat();
614  }
615 
616  if (nScanlineFormat == ScanlineFormat::N24BitTcRgb
617  || nScanlineFormat == ScanlineFormat::N24BitTcBgr
618  || nScanlineFormat == ScanlineFormat::N32BitTcMask
619  || nScanlineFormat == ScanlineFormat::N32BitTcBgra)
620  {
621  int nComponentWidth = (nScanlineFormat == ScanlineFormat::N32BitTcMask
622  || nScanlineFormat == ScanlineFormat::N32BitTcBgra)
623  ? 4
624  : 3;
625 
626  stackBlur24(bitmapCopy, mnRadius, nComponentWidth);
627  }
628  else if (nScanlineFormat == ScanlineFormat::N8BitPal)
629  {
630  int nComponentWidth = 1;
631 
632  stackBlur8(bitmapCopy, mnRadius, nComponentWidth);
633  }
634 
635  return bitmapCopy;
636 }
637 
638 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
Bitmap GetMask() const
Definition: bitmapex.cxx:254
Scanline GetScanline(long nY) const
void waitUntilDone(const std::shared_ptr< ThreadTaskTag > &, bool bJoinAll=true)
Bitmap filter(Bitmap const &rBitmap) const
virtual void doWork()=0
long Width() const
float x
ScanlineFormat
Definition: Scanline.hxx:28
float y
static ThreadPool & getSharedOptimalPool()
sal_uInt8 * Scanline
Definition: Scanline.hxx:25
int i
void pushTask(std::unique_ptr< ThreadTask > pTask)
ScanlineFormat GetScanlineFormat() const
BitmapFilterStackBlur(sal_Int32 nRadius)
Implementation of stack blur - a fast Gaussian blur approximation.
virtual BitmapEx execute(BitmapEx const &rBitmap) const override
Bitmap GetBitmap(Color aTransparentReplaceColor) const
Definition: bitmapex.cxx:232
long Height() const
unsigned char sal_uInt8
static std::shared_ptr< ThreadTaskTag > createThreadTaskTag()
Any result
#define SAL_WARN(area, stream)
void set(css::uno::UnoInterfaceReference const &value)
typedef void(CALLTYPE *GetFuncDataPtr)(sal_uInt16 &nNo