bump product version to 7.2.5.1
[LibreOffice.git] / vcl / source / bitmap / BitmapFilterStackBlur.cxx
blobc23adad0176fbc3e6590609243e1c51dfe308046
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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 */
11 #include <vcl/BitmapFilterStackBlur.hxx>
12 #include <bitmap/BitmapWriteAccess.hxx>
13 #include <sal/log.hxx>
15 #include <comphelper/threadpool.hxx>
17 namespace
19 const sal_Int16 constMultiplyTable[255]
20 = { 512, 512, 456, 512, 328, 456, 335, 512, 405, 328, 271, 456, 388, 335, 292, 512, 454,
21 405, 364, 328, 298, 271, 496, 456, 420, 388, 360, 335, 312, 292, 273, 512, 482, 454,
22 428, 405, 383, 364, 345, 328, 312, 298, 284, 271, 259, 496, 475, 456, 437, 420, 404,
23 388, 374, 360, 347, 335, 323, 312, 302, 292, 282, 273, 265, 512, 497, 482, 468, 454,
24 441, 428, 417, 405, 394, 383, 373, 364, 354, 345, 337, 328, 320, 312, 305, 298, 291,
25 284, 278, 271, 265, 259, 507, 496, 485, 475, 465, 456, 446, 437, 428, 420, 412, 404,
26 396, 388, 381, 374, 367, 360, 354, 347, 341, 335, 329, 323, 318, 312, 307, 302, 297,
27 292, 287, 282, 278, 273, 269, 265, 261, 512, 505, 497, 489, 482, 475, 468, 461, 454,
28 447, 441, 435, 428, 422, 417, 411, 405, 399, 394, 389, 383, 378, 373, 368, 364, 359,
29 354, 350, 345, 341, 337, 332, 328, 324, 320, 316, 312, 309, 305, 301, 298, 294, 291,
30 287, 284, 281, 278, 274, 271, 268, 265, 262, 259, 257, 507, 501, 496, 491, 485, 480,
31 475, 470, 465, 460, 456, 451, 446, 442, 437, 433, 428, 424, 420, 416, 412, 408, 404,
32 400, 396, 392, 388, 385, 381, 377, 374, 370, 367, 363, 360, 357, 354, 350, 347, 344,
33 341, 338, 335, 332, 329, 326, 323, 320, 318, 315, 312, 310, 307, 304, 302, 299, 297,
34 294, 292, 289, 287, 285, 282, 280, 278, 275, 273, 271, 269, 267, 265, 263, 261, 259 };
36 const sal_Int16 constShiftTable[255]
37 = { 9, 11, 12, 13, 13, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 17, 17, 17, 17, 17, 17, 17,
38 18, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
39 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 21, 21, 21,
40 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
41 21, 21, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
42 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23,
43 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 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, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
46 24, 24, 24, 24, 24, 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 };
50 struct BlurSharedData
52 BitmapReadAccess* mpReadAccess;
53 BitmapWriteAccess* mpWriteAccess;
54 tools::Long mnRadius;
55 tools::Long mnComponentWidth;
56 tools::Long mnDiv;
57 tools::Long mnColorChannels;
59 BlurSharedData(BitmapReadAccess* pReadAccess, BitmapWriteAccess* pWriteAccess,
60 tools::Long aRadius, tools::Long nComponentWidth, tools::Long nColorChannels)
61 : mpReadAccess(pReadAccess)
62 , mpWriteAccess(pWriteAccess)
63 , mnRadius(aRadius)
64 , mnComponentWidth(nComponentWidth)
65 , mnDiv(aRadius + aRadius + 1)
66 , mnColorChannels(nColorChannels)
71 struct BlurArrays
73 BlurSharedData maShared;
75 std::vector<sal_uInt8> maStackBuffer;
76 std::vector<tools::Long> maPositionTable;
77 std::vector<tools::Long> maWeightTable;
79 std::vector<tools::Long> mnSumVector;
80 std::vector<tools::Long> mnInSumVector;
81 std::vector<tools::Long> mnOutSumVector;
83 BlurArrays(BlurSharedData const& rShared)
84 : maShared(rShared)
85 , maStackBuffer(maShared.mnDiv * maShared.mnComponentWidth)
86 , maPositionTable(maShared.mnDiv)
87 , maWeightTable(maShared.mnDiv)
88 , mnSumVector(maShared.mnColorChannels)
89 , mnInSumVector(maShared.mnColorChannels)
90 , mnOutSumVector(maShared.mnColorChannels)
94 void initializeWeightAndPositions(tools::Long nLastIndex)
96 for (tools::Long i = 0; i < maShared.mnDiv; i++)
98 maPositionTable[i] = std::clamp(i - maShared.mnRadius, tools::Long(0), nLastIndex);
99 maWeightTable[i] = maShared.mnRadius + 1 - std::abs(i - maShared.mnRadius);
103 tools::Long getMultiplyValue() const
105 return static_cast<tools::Long>(constMultiplyTable[maShared.mnRadius]);
108 tools::Long getShiftValue() const
110 return static_cast<tools::Long>(constShiftTable[maShared.mnRadius]);
114 typedef void (*BlurRangeFn)(BlurSharedData const& rShared, tools::Long nStartY, tools::Long nEndY);
116 class BlurTask : public comphelper::ThreadTask
118 BlurRangeFn mpBlurFunction;
119 BlurSharedData& mrShared;
120 tools::Long mnStartY;
121 tools::Long mnEndY;
123 public:
124 explicit BlurTask(const std::shared_ptr<comphelper::ThreadTaskTag>& pTag,
125 BlurRangeFn pBlurFunction, BlurSharedData& rShared, tools::Long nStartY,
126 tools::Long nEndY)
127 : comphelper::ThreadTask(pTag)
128 , mpBlurFunction(pBlurFunction)
129 , mrShared(rShared)
130 , mnStartY(nStartY)
131 , mnEndY(nEndY)
135 virtual void doWork() override { mpBlurFunction(mrShared, mnStartY, mnEndY); }
138 struct SumFunction24
140 static inline void add(tools::Long*& pValue1, tools::Long nConstant)
142 pValue1[0] += nConstant;
143 pValue1[1] += nConstant;
144 pValue1[2] += nConstant;
147 static inline void set(tools::Long*& pValue1, tools::Long nConstant)
149 pValue1[0] = nConstant;
150 pValue1[1] = nConstant;
151 pValue1[2] = nConstant;
154 static inline void add(tools::Long*& pValue1, const sal_uInt8* pValue2)
156 pValue1[0] += pValue2[0];
157 pValue1[1] += pValue2[1];
158 pValue1[2] += pValue2[2];
161 static inline void add(tools::Long*& pValue1, const tools::Long* pValue2)
163 pValue1[0] += pValue2[0];
164 pValue1[1] += pValue2[1];
165 pValue1[2] += pValue2[2];
168 static inline void sub(tools::Long*& pValue1, const sal_uInt8* pValue2)
170 pValue1[0] -= pValue2[0];
171 pValue1[1] -= pValue2[1];
172 pValue1[2] -= pValue2[2];
175 static inline void sub(tools::Long*& pValue1, const tools::Long* pValue2)
177 pValue1[0] -= pValue2[0];
178 pValue1[1] -= pValue2[1];
179 pValue1[2] -= pValue2[2];
182 static inline void assignPtr(sal_uInt8*& pValue1, const sal_uInt8* pValue2)
184 pValue1[0] = pValue2[0];
185 pValue1[1] = pValue2[1];
186 pValue1[2] = pValue2[2];
189 static inline void assignMulAndShr(sal_uInt8*& result, const tools::Long* sum,
190 tools::Long multiply, tools::Long shift)
192 result[0] = (multiply * sum[0]) >> shift;
193 result[1] = (multiply * sum[1]) >> shift;
194 result[2] = (multiply * sum[2]) >> shift;
198 struct SumFunction8
200 static inline void add(tools::Long*& pValue1, tools::Long nConstant)
202 pValue1[0] += nConstant;
205 static inline void set(tools::Long*& pValue1, tools::Long nConstant) { pValue1[0] = nConstant; }
207 static inline void add(tools::Long*& pValue1, const sal_uInt8* pValue2)
209 pValue1[0] += pValue2[0];
212 static inline void add(tools::Long*& pValue1, const tools::Long* pValue2)
214 pValue1[0] += pValue2[0];
217 static inline void sub(tools::Long*& pValue1, const sal_uInt8* pValue2)
219 pValue1[0] -= pValue2[0];
222 static inline void sub(tools::Long*& pValue1, const tools::Long* pValue2)
224 pValue1[0] -= pValue2[0];
227 static inline void assignPtr(sal_uInt8*& pValue1, const sal_uInt8* pValue2)
229 pValue1[0] = pValue2[0];
232 static inline void assignMulAndShr(sal_uInt8*& result, const tools::Long* sum,
233 tools::Long multiply, tools::Long shift)
235 result[0] = (multiply * sum[0]) >> shift;
239 template <typename SumFunction>
240 void stackBlurHorizontal(BlurSharedData const& rShared, tools::Long nStart, tools::Long nEnd)
242 BitmapReadAccess* pReadAccess = rShared.mpReadAccess;
243 BitmapWriteAccess* pWriteAccess = rShared.mpWriteAccess;
245 BlurArrays aArrays(rShared);
247 sal_uInt8* pStack = aArrays.maStackBuffer.data();
248 sal_uInt8* pStackPtr;
250 tools::Long nWidth = pReadAccess->Width();
251 tools::Long nLastIndexX = nWidth - 1;
253 tools::Long nMultiplyValue = aArrays.getMultiplyValue();
254 tools::Long nShiftValue = aArrays.getShiftValue();
256 tools::Long nRadius = rShared.mnRadius;
257 tools::Long nComponentWidth = rShared.mnComponentWidth;
258 tools::Long nDiv = rShared.mnDiv;
260 Scanline pSourcePointer;
261 Scanline pDestinationPointer;
263 tools::Long nXPosition;
264 tools::Long nStackIndex;
265 tools::Long nStackIndexStart;
266 tools::Long nWeight;
268 aArrays.initializeWeightAndPositions(nLastIndexX);
270 tools::Long* nSum = aArrays.mnSumVector.data();
271 tools::Long* nInSum = aArrays.mnInSumVector.data();
272 tools::Long* nOutSum = aArrays.mnOutSumVector.data();
274 tools::Long* pPositionPointer = aArrays.maPositionTable.data();
275 tools::Long* pWeightPointer = aArrays.maWeightTable.data();
277 for (tools::Long y = nStart; y <= nEnd; y++)
279 SumFunction::set(nSum, 0);
280 SumFunction::set(nInSum, 0);
281 SumFunction::set(nOutSum, 0);
283 // Pre-initialize blur data for first pixel.
284 // aArrays.maPositionTable contains values like (for radius of 5): [0,0,0,0,0,0,1,2,3,4,5],
285 // which are used as pixels indices in the current row that we use to prepare information
286 // for the first pixel; aArrays.maWeightTable has [1,2,3,4,5,6,5,4,3,2,1]. Before looking at
287 // the first row pixel, we pretend to have processed fake previous pixels, as if the row was
288 // extended to the left with the same color as that of the first pixel.
289 for (tools::Long i = 0; i < nDiv; i++)
291 pSourcePointer = pReadAccess->GetScanline(y) + nComponentWidth * pPositionPointer[i];
293 pStackPtr = &pStack[nComponentWidth * i];
295 SumFunction::assignPtr(pStackPtr, pSourcePointer);
297 nWeight = pWeightPointer[i];
299 SumFunction::add(nSum, pSourcePointer[0] * nWeight);
301 if (i - nRadius > 0)
303 SumFunction::add(nInSum, pSourcePointer);
305 else
307 SumFunction::add(nOutSum, pSourcePointer);
311 nStackIndex = nRadius;
312 nXPosition = std::min(nRadius, nLastIndexX);
314 pSourcePointer = pReadAccess->GetScanline(y) + nComponentWidth * nXPosition;
316 for (tools::Long x = 0; x < nWidth; x++)
318 pDestinationPointer = pWriteAccess->GetScanline(y) + nComponentWidth * x;
320 SumFunction::assignMulAndShr(pDestinationPointer, nSum, nMultiplyValue, nShiftValue);
322 SumFunction::sub(nSum, nOutSum);
324 nStackIndexStart = nStackIndex + nDiv - nRadius;
325 if (nStackIndexStart >= nDiv)
327 nStackIndexStart -= nDiv;
329 pStackPtr = &pStack[nComponentWidth * nStackIndexStart];
331 SumFunction::sub(nOutSum, pStackPtr);
333 if (nXPosition < nLastIndexX)
335 nXPosition++;
336 pSourcePointer = pReadAccess->GetScanline(y) + nComponentWidth * nXPosition;
339 SumFunction::assignPtr(pStackPtr, pSourcePointer);
341 SumFunction::add(nInSum, pSourcePointer);
343 SumFunction::add(nSum, nInSum);
345 nStackIndex++;
346 if (nStackIndex >= nDiv)
348 nStackIndex = 0;
351 pStackPtr = &pStack[nStackIndex * nComponentWidth];
353 SumFunction::add(nOutSum, pStackPtr);
354 SumFunction::sub(nInSum, pStackPtr);
359 template <typename SumFunction>
360 void stackBlurVertical(BlurSharedData const& rShared, tools::Long nStart, tools::Long nEnd)
362 BitmapReadAccess* pReadAccess = rShared.mpReadAccess;
363 BitmapWriteAccess* pWriteAccess = rShared.mpWriteAccess;
365 BlurArrays aArrays(rShared);
367 sal_uInt8* pStack = aArrays.maStackBuffer.data();
368 sal_uInt8* pStackPtr;
370 tools::Long nHeight = pReadAccess->Height();
371 tools::Long nLastIndexY = nHeight - 1;
373 tools::Long nMultiplyValue = aArrays.getMultiplyValue();
374 tools::Long nShiftValue = aArrays.getShiftValue();
376 tools::Long nRadius = rShared.mnRadius;
377 tools::Long nComponentWidth = rShared.mnComponentWidth;
378 tools::Long nDiv = rShared.mnDiv;
380 Scanline pSourcePointer;
381 Scanline pDestinationPointer;
383 tools::Long nYPosition;
384 tools::Long nStackIndex;
385 tools::Long nStackIndexStart;
386 tools::Long nWeight;
388 aArrays.initializeWeightAndPositions(nLastIndexY);
390 tools::Long* nSum = aArrays.mnSumVector.data();
391 tools::Long* nInSum = aArrays.mnInSumVector.data();
392 tools::Long* nOutSum = aArrays.mnOutSumVector.data();
393 tools::Long* pPositionPointer = aArrays.maPositionTable.data();
394 tools::Long* pWeightPointer = aArrays.maWeightTable.data();
396 for (tools::Long x = nStart; x <= nEnd; x++)
398 SumFunction::set(nSum, 0);
399 SumFunction::set(nInSum, 0);
400 SumFunction::set(nOutSum, 0);
402 // Pre-initialize blur data for first pixel.
403 // aArrays.maPositionTable contains values like (for radius of 5): [0,0,0,0,0,0,1,2,3,4,5],
404 // which are used as pixels indices in the current column that we use to prepare information
405 // for the first pixel; aArrays.maWeightTable has [1,2,3,4,5,6,5,4,3,2,1]. Before looking at
406 // the first column pixels, we pretend to have processed fake previous pixels, as if the
407 // column was extended to the top with the same color as that of the first pixel.
408 for (tools::Long i = 0; i < nDiv; i++)
410 pSourcePointer = pReadAccess->GetScanline(pPositionPointer[i]) + nComponentWidth * x;
412 pStackPtr = &pStack[nComponentWidth * i];
414 SumFunction::assignPtr(pStackPtr, pSourcePointer);
416 nWeight = pWeightPointer[i];
418 SumFunction::add(nSum, pSourcePointer[0] * nWeight);
420 if (i - nRadius > 0)
422 SumFunction::add(nInSum, pSourcePointer);
424 else
426 SumFunction::add(nOutSum, pSourcePointer);
430 nStackIndex = nRadius;
431 nYPosition = std::min(nRadius, nLastIndexY);
433 pSourcePointer = pReadAccess->GetScanline(nYPosition) + nComponentWidth * x;
435 for (tools::Long y = 0; y < nHeight; y++)
437 pDestinationPointer = pWriteAccess->GetScanline(y) + nComponentWidth * x;
439 SumFunction::assignMulAndShr(pDestinationPointer, nSum, nMultiplyValue, nShiftValue);
441 SumFunction::sub(nSum, nOutSum);
443 nStackIndexStart = nStackIndex + nDiv - nRadius;
444 if (nStackIndexStart >= nDiv)
446 nStackIndexStart -= nDiv;
448 pStackPtr = &pStack[nComponentWidth * nStackIndexStart];
450 SumFunction::sub(nOutSum, pStackPtr);
452 if (nYPosition < nLastIndexY)
454 nYPosition++;
455 pSourcePointer = pReadAccess->GetScanline(nYPosition) + nComponentWidth * x;
458 SumFunction::assignPtr(pStackPtr, pSourcePointer);
459 SumFunction::add(nInSum, pSourcePointer);
460 SumFunction::add(nSum, nInSum);
462 nStackIndex++;
463 if (nStackIndex >= nDiv)
465 nStackIndex = 0;
468 pStackPtr = &pStack[nStackIndex * nComponentWidth];
470 SumFunction::add(nOutSum, pStackPtr);
471 SumFunction::sub(nInSum, pStackPtr);
476 constexpr tools::Long nThreadStrip = 16;
478 void runStackBlur(Bitmap& rBitmap, const tools::Long nRadius, const tools::Long nComponentWidth,
479 const tools::Long nColorChannels, BlurRangeFn pBlurHorizontalFn,
480 BlurRangeFn pBlurVerticalFn, const bool bParallel)
482 if (bParallel)
486 comphelper::ThreadPool& rShared = comphelper::ThreadPool::getSharedOptimalPool();
487 auto pTag = comphelper::ThreadPool::createThreadTaskTag();
490 Bitmap::ScopedReadAccess pReadAccess(rBitmap);
491 BitmapScopedWriteAccess pWriteAccess(rBitmap);
492 BlurSharedData aSharedData(pReadAccess.get(), pWriteAccess.get(), nRadius,
493 nComponentWidth, nColorChannels);
495 const tools::Long nFirstIndex = 0;
496 const tools::Long nLastIndex = pReadAccess->Height() - 1;
498 vcl::bitmap::generateStripRanges<nThreadStrip>(
499 nFirstIndex, nLastIndex,
500 [&](tools::Long const nStart, tools::Long const nEnd, bool const bLast) {
501 if (!bLast)
503 auto pTask(std::make_unique<BlurTask>(pTag, pBlurHorizontalFn,
504 aSharedData, nStart, nEnd));
505 rShared.pushTask(std::move(pTask));
507 else
508 pBlurHorizontalFn(aSharedData, nStart, nEnd);
510 rShared.waitUntilDone(pTag);
513 Bitmap::ScopedReadAccess pReadAccess(rBitmap);
514 BitmapScopedWriteAccess pWriteAccess(rBitmap);
515 BlurSharedData aSharedData(pReadAccess.get(), pWriteAccess.get(), nRadius,
516 nComponentWidth, nColorChannels);
518 const tools::Long nFirstIndex = 0;
519 const tools::Long nLastIndex = pReadAccess->Width() - 1;
521 vcl::bitmap::generateStripRanges<nThreadStrip>(
522 nFirstIndex, nLastIndex,
523 [&](tools::Long const nStart, tools::Long const nEnd, bool const bLast) {
524 if (!bLast)
526 auto pTask(std::make_unique<BlurTask>(pTag, pBlurVerticalFn,
527 aSharedData, nStart, nEnd));
528 rShared.pushTask(std::move(pTask));
530 else
531 pBlurVerticalFn(aSharedData, nStart, nEnd);
534 rShared.waitUntilDone(pTag);
537 catch (...)
539 SAL_WARN("vcl.gdi", "threaded bitmap blurring failed");
542 else
545 Bitmap::ScopedReadAccess pReadAccess(rBitmap);
546 BitmapScopedWriteAccess pWriteAccess(rBitmap);
547 BlurSharedData aSharedData(pReadAccess.get(), pWriteAccess.get(), nRadius,
548 nComponentWidth, nColorChannels);
549 tools::Long nFirstIndex = 0;
550 tools::Long nLastIndex = pReadAccess->Height() - 1;
551 pBlurHorizontalFn(aSharedData, nFirstIndex, nLastIndex);
554 Bitmap::ScopedReadAccess pReadAccess(rBitmap);
555 BitmapScopedWriteAccess pWriteAccess(rBitmap);
556 BlurSharedData aSharedData(pReadAccess.get(), pWriteAccess.get(), nRadius,
557 nComponentWidth, nColorChannels);
558 tools::Long nFirstIndex = 0;
559 tools::Long nLastIndex = pReadAccess->Width() - 1;
560 pBlurVerticalFn(aSharedData, nFirstIndex, nLastIndex);
565 void stackBlur24(Bitmap& rBitmap, sal_Int32 nRadius, sal_Int32 nComponentWidth)
567 const bool bParallel = true;
568 // Limit radius
569 nRadius = std::clamp<sal_Int32>(nRadius, 2, 254);
570 const tools::Long nColorChannels = 3; // 3 color channel
572 BlurRangeFn pBlurHorizontalFn = stackBlurHorizontal<SumFunction24>;
573 BlurRangeFn pBlurVerticalFn = stackBlurVertical<SumFunction24>;
575 runStackBlur(rBitmap, nRadius, nComponentWidth, nColorChannels, pBlurHorizontalFn,
576 pBlurVerticalFn, bParallel);
579 void stackBlur8(Bitmap& rBitmap, sal_Int32 nRadius, sal_Int32 nComponentWidth)
581 const bool bParallel = true;
582 // Limit radius
583 nRadius = std::clamp<sal_Int32>(nRadius, 2, 254);
584 const tools::Long nColorChannels = 1; // 1 color channel
586 BlurRangeFn pBlurHorizontalFn = stackBlurHorizontal<SumFunction8>;
587 BlurRangeFn pBlurVerticalFn = stackBlurVertical<SumFunction8>;
589 runStackBlur(rBitmap, nRadius, nComponentWidth, nColorChannels, pBlurHorizontalFn,
590 pBlurVerticalFn, bParallel);
593 } // end anonymous namespace
596 * Implementation of stack blur - a fast Gaussian blur approximation.
597 * nRadius - blur radius, valid values are between 2 and 254
598 * bExtend - extend the bitmap in all directions by the radius
600 * Stack Blur Algorithm by Mario Klingemann <mario@quasimondo.com>
601 * (http://www.quasimondo.com/StackBlurForCanvas/StackBlurDemo.html)
603 * Additionally references and implementations:
604 * - Blur.js by Jacob Kelley
605 * (http://www.blurjs.com)
606 * - BlurEffectForAndroidDesign by Nicolas Pomepuy
607 * (https://github.com/PomepuyN/BlurEffectForAndroidDesign)
608 * - StackBluriOS by Thomas Landspurg
609 * (https://github.com/tomsoft1/StackBluriOS)
610 * - stackblur.cpp by Benjamin Yates
611 * (https://gist.github.com/benjamin9999/3809142)
612 * - stack blur in fog 2D graphic library by Petr Kobalicek
613 * (https://code.google.com/p/fog/)
616 BitmapFilterStackBlur::BitmapFilterStackBlur(sal_Int32 nRadius)
617 : mnRadius(nRadius)
621 BitmapFilterStackBlur::~BitmapFilterStackBlur() {}
623 BitmapEx BitmapFilterStackBlur::execute(BitmapEx const& rBitmapEx) const
625 Bitmap aBitmap = rBitmapEx.GetBitmap();
626 Bitmap result = filter(aBitmap);
627 return BitmapEx(result, rBitmapEx.GetAlpha());
630 Bitmap BitmapFilterStackBlur::filter(Bitmap const& rBitmap) const
632 Bitmap bitmapCopy(rBitmap);
633 ScanlineFormat nScanlineFormat;
635 Bitmap::ScopedReadAccess pReadAccess(bitmapCopy);
636 nScanlineFormat = pReadAccess->GetScanlineFormat();
639 if (nScanlineFormat == ScanlineFormat::N24BitTcRgb
640 || nScanlineFormat == ScanlineFormat::N24BitTcBgr
641 || nScanlineFormat == ScanlineFormat::N32BitTcMask
642 || nScanlineFormat == ScanlineFormat::N32BitTcBgra)
644 int nComponentWidth = (nScanlineFormat == ScanlineFormat::N32BitTcMask
645 || nScanlineFormat == ScanlineFormat::N32BitTcBgra)
647 : 3;
649 stackBlur24(bitmapCopy, mnRadius, nComponentWidth);
651 else if (nScanlineFormat == ScanlineFormat::N8BitPal)
653 int nComponentWidth = 1;
655 stackBlur8(bitmapCopy, mnRadius, nComponentWidth);
658 return bitmapCopy;
661 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */