nss: upgrade to release 3.73
[LibreOffice.git] / vcl / source / bitmap / BitmapFilterStackBlur.cxx
blobd3e1ddea93105877468b27b16ca9c88be2d69826
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 <vcl/bitmapaccess.hxx>
13 #include <bitmapwriteaccess.hxx>
14 #include <sal/log.hxx>
16 #include <comphelper/threadpool.hxx>
18 namespace
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 };
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 };
51 struct BlurSharedData
53 BitmapReadAccess* mpReadAccess;
54 BitmapWriteAccess* mpWriteAccess;
55 tools::Long mnRadius;
56 tools::Long mnComponentWidth;
57 tools::Long mnDiv;
58 tools::Long mnColorChannels;
60 BlurSharedData(BitmapReadAccess* pReadAccess, BitmapWriteAccess* pWriteAccess,
61 tools::Long aRadius, tools::Long nComponentWidth, tools::Long nColorChannels)
62 : mpReadAccess(pReadAccess)
63 , mpWriteAccess(pWriteAccess)
64 , mnRadius(aRadius)
65 , mnComponentWidth(nComponentWidth)
66 , mnDiv(aRadius + aRadius + 1)
67 , mnColorChannels(nColorChannels)
72 struct BlurArrays
74 BlurSharedData maShared;
76 std::vector<sal_uInt8> maStackBuffer;
77 std::vector<tools::Long> maPositionTable;
78 std::vector<tools::Long> maWeightTable;
80 std::vector<tools::Long> mnSumVector;
81 std::vector<tools::Long> mnInSumVector;
82 std::vector<tools::Long> mnOutSumVector;
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)
95 void initializeWeightAndPositions(tools::Long nLastIndex)
97 for (tools::Long i = 0; i < maShared.mnDiv; i++)
99 maPositionTable[i] = std::clamp(i - maShared.mnRadius, tools::Long(0), nLastIndex);
100 maWeightTable[i] = maShared.mnRadius + 1 - std::abs(i - maShared.mnRadius);
104 tools::Long getMultiplyValue() const
106 return static_cast<tools::Long>(constMultiplyTable[maShared.mnRadius]);
109 tools::Long getShiftValue() const
111 return static_cast<tools::Long>(constShiftTable[maShared.mnRadius]);
115 typedef void (*BlurRangeFn)(BlurSharedData const& rShared, tools::Long nStartY, tools::Long nEndY);
117 class BlurTask : public comphelper::ThreadTask
119 BlurRangeFn mpBlurFunction;
120 BlurSharedData& mrShared;
121 tools::Long mnStartY;
122 tools::Long mnEndY;
124 public:
125 explicit BlurTask(const std::shared_ptr<comphelper::ThreadTaskTag>& pTag,
126 BlurRangeFn pBlurFunction, BlurSharedData& rShared, tools::Long nStartY,
127 tools::Long nEndY)
128 : comphelper::ThreadTask(pTag)
129 , mpBlurFunction(pBlurFunction)
130 , mrShared(rShared)
131 , mnStartY(nStartY)
132 , mnEndY(nEndY)
136 virtual void doWork() override { mpBlurFunction(mrShared, mnStartY, mnEndY); }
139 struct SumFunction24
141 static inline void add(tools::Long*& pValue1, tools::Long nConstant)
143 pValue1[0] += nConstant;
144 pValue1[1] += nConstant;
145 pValue1[2] += nConstant;
148 static inline void set(tools::Long*& pValue1, tools::Long nConstant)
150 pValue1[0] = nConstant;
151 pValue1[1] = nConstant;
152 pValue1[2] = nConstant;
155 static inline void add(tools::Long*& pValue1, const sal_uInt8* pValue2)
157 pValue1[0] += pValue2[0];
158 pValue1[1] += pValue2[1];
159 pValue1[2] += pValue2[2];
162 static inline void add(tools::Long*& pValue1, const tools::Long* pValue2)
164 pValue1[0] += pValue2[0];
165 pValue1[1] += pValue2[1];
166 pValue1[2] += pValue2[2];
169 static inline void sub(tools::Long*& pValue1, const sal_uInt8* pValue2)
171 pValue1[0] -= pValue2[0];
172 pValue1[1] -= pValue2[1];
173 pValue1[2] -= pValue2[2];
176 static inline void sub(tools::Long*& pValue1, const tools::Long* pValue2)
178 pValue1[0] -= pValue2[0];
179 pValue1[1] -= pValue2[1];
180 pValue1[2] -= pValue2[2];
183 static inline void assignPtr(sal_uInt8*& pValue1, const sal_uInt8* pValue2)
185 pValue1[0] = pValue2[0];
186 pValue1[1] = pValue2[1];
187 pValue1[2] = pValue2[2];
190 static inline void assignMulAndShr(sal_uInt8*& result, const tools::Long* sum,
191 tools::Long multiply, tools::Long shift)
193 result[0] = (multiply * sum[0]) >> shift;
194 result[1] = (multiply * sum[1]) >> shift;
195 result[2] = (multiply * sum[2]) >> shift;
199 struct SumFunction8
201 static inline void add(tools::Long*& pValue1, tools::Long nConstant)
203 pValue1[0] += nConstant;
206 static inline void set(tools::Long*& pValue1, tools::Long nConstant) { pValue1[0] = nConstant; }
208 static inline void add(tools::Long*& pValue1, const sal_uInt8* pValue2)
210 pValue1[0] += pValue2[0];
213 static inline void add(tools::Long*& pValue1, const tools::Long* pValue2)
215 pValue1[0] += pValue2[0];
218 static inline void sub(tools::Long*& pValue1, const sal_uInt8* pValue2)
220 pValue1[0] -= pValue2[0];
223 static inline void sub(tools::Long*& pValue1, const tools::Long* pValue2)
225 pValue1[0] -= pValue2[0];
228 static inline void assignPtr(sal_uInt8*& pValue1, const sal_uInt8* pValue2)
230 pValue1[0] = pValue2[0];
233 static inline void assignMulAndShr(sal_uInt8*& result, const tools::Long* sum,
234 tools::Long multiply, tools::Long shift)
236 result[0] = (multiply * sum[0]) >> shift;
240 template <typename SumFunction>
241 void stackBlurHorizontal(BlurSharedData const& rShared, tools::Long nStart, tools::Long nEnd)
243 BitmapReadAccess* pReadAccess = rShared.mpReadAccess;
244 BitmapWriteAccess* pWriteAccess = rShared.mpWriteAccess;
246 BlurArrays aArrays(rShared);
248 sal_uInt8* pStack = aArrays.maStackBuffer.data();
249 sal_uInt8* pStackPtr;
251 tools::Long nWidth = pReadAccess->Width();
252 tools::Long nLastIndexX = nWidth - 1;
254 tools::Long nMultiplyValue = aArrays.getMultiplyValue();
255 tools::Long nShiftValue = aArrays.getShiftValue();
257 tools::Long nRadius = rShared.mnRadius;
258 tools::Long nComponentWidth = rShared.mnComponentWidth;
259 tools::Long nDiv = rShared.mnDiv;
261 Scanline pSourcePointer;
262 Scanline pDestinationPointer;
264 tools::Long nXPosition;
265 tools::Long nStackIndex;
266 tools::Long nStackIndexStart;
267 tools::Long nWeight;
269 aArrays.initializeWeightAndPositions(nLastIndexX);
271 tools::Long* nSum = aArrays.mnSumVector.data();
272 tools::Long* nInSum = aArrays.mnInSumVector.data();
273 tools::Long* nOutSum = aArrays.mnOutSumVector.data();
275 tools::Long* pPositionPointer = aArrays.maPositionTable.data();
276 tools::Long* pWeightPointer = aArrays.maWeightTable.data();
278 for (tools::Long y = nStart; y <= nEnd; y++)
280 SumFunction::set(nSum, 0L);
281 SumFunction::set(nInSum, 0L);
282 SumFunction::set(nOutSum, 0L);
284 // Pre-initialize blur data for first pixel.
285 // aArrays.maPositionTable contains values like (for radius of 5): [0,0,0,0,0,0,1,2,3,4,5],
286 // which are used as pixels indices in the current row that we use to prepare information
287 // for the first pixel; aArrays.maWeightTable has [1,2,3,4,5,6,5,4,3,2,1]. Before looking at
288 // the first row pixel, we pretend to have processed fake previous pixels, as if the row was
289 // extended to the left with the same color as that of the first pixel.
290 for (tools::Long i = 0; i < nDiv; i++)
292 pSourcePointer = pReadAccess->GetScanline(y) + nComponentWidth * pPositionPointer[i];
294 pStackPtr = &pStack[nComponentWidth * i];
296 SumFunction::assignPtr(pStackPtr, pSourcePointer);
298 nWeight = pWeightPointer[i];
300 SumFunction::add(nSum, pSourcePointer[0] * nWeight);
302 if (i - nRadius > 0)
304 SumFunction::add(nInSum, pSourcePointer);
306 else
308 SumFunction::add(nOutSum, pSourcePointer);
312 nStackIndex = nRadius;
313 nXPosition = std::min(nRadius, nLastIndexX);
315 pSourcePointer = pReadAccess->GetScanline(y) + nComponentWidth * nXPosition;
317 for (tools::Long x = 0; x < nWidth; x++)
319 pDestinationPointer = pWriteAccess->GetScanline(y) + nComponentWidth * x;
321 SumFunction::assignMulAndShr(pDestinationPointer, nSum, nMultiplyValue, nShiftValue);
323 SumFunction::sub(nSum, nOutSum);
325 nStackIndexStart = nStackIndex + nDiv - nRadius;
326 if (nStackIndexStart >= nDiv)
328 nStackIndexStart -= nDiv;
330 pStackPtr = &pStack[nComponentWidth * nStackIndexStart];
332 SumFunction::sub(nOutSum, pStackPtr);
334 if (nXPosition < nLastIndexX)
336 nXPosition++;
337 pSourcePointer = pReadAccess->GetScanline(y) + nComponentWidth * nXPosition;
340 SumFunction::assignPtr(pStackPtr, pSourcePointer);
342 SumFunction::add(nInSum, pSourcePointer);
344 SumFunction::add(nSum, nInSum);
346 nStackIndex++;
347 if (nStackIndex >= nDiv)
349 nStackIndex = 0;
352 pStackPtr = &pStack[nStackIndex * nComponentWidth];
354 SumFunction::add(nOutSum, pStackPtr);
355 SumFunction::sub(nInSum, pStackPtr);
360 template <typename SumFunction>
361 void stackBlurVertical(BlurSharedData const& rShared, tools::Long nStart, tools::Long nEnd)
363 BitmapReadAccess* pReadAccess = rShared.mpReadAccess;
364 BitmapWriteAccess* pWriteAccess = rShared.mpWriteAccess;
366 BlurArrays aArrays(rShared);
368 sal_uInt8* pStack = aArrays.maStackBuffer.data();
369 sal_uInt8* pStackPtr;
371 tools::Long nHeight = pReadAccess->Height();
372 tools::Long nLastIndexY = nHeight - 1;
374 tools::Long nMultiplyValue = aArrays.getMultiplyValue();
375 tools::Long nShiftValue = aArrays.getShiftValue();
377 tools::Long nRadius = rShared.mnRadius;
378 tools::Long nComponentWidth = rShared.mnComponentWidth;
379 tools::Long nDiv = rShared.mnDiv;
381 Scanline pSourcePointer;
382 Scanline pDestinationPointer;
384 tools::Long nYPosition;
385 tools::Long nStackIndex;
386 tools::Long nStackIndexStart;
387 tools::Long nWeight;
389 aArrays.initializeWeightAndPositions(nLastIndexY);
391 tools::Long* nSum = aArrays.mnSumVector.data();
392 tools::Long* nInSum = aArrays.mnInSumVector.data();
393 tools::Long* nOutSum = aArrays.mnOutSumVector.data();
394 tools::Long* pPositionPointer = aArrays.maPositionTable.data();
395 tools::Long* pWeightPointer = aArrays.maWeightTable.data();
397 for (tools::Long x = nStart; x <= nEnd; x++)
399 SumFunction::set(nSum, 0L);
400 SumFunction::set(nInSum, 0L);
401 SumFunction::set(nOutSum, 0L);
403 // Pre-initialize blur data for first pixel.
404 // aArrays.maPositionTable contains values like (for radius of 5): [0,0,0,0,0,0,1,2,3,4,5],
405 // which are used as pixels indices in the current column that we use to prepare information
406 // for the first pixel; aArrays.maWeightTable has [1,2,3,4,5,6,5,4,3,2,1]. Before looking at
407 // the first column pixels, we pretend to have processed fake previous pixels, as if the
408 // column was extended to the top with the same color as that of the first pixel.
409 for (tools::Long i = 0; i < nDiv; i++)
411 pSourcePointer = pReadAccess->GetScanline(pPositionPointer[i]) + nComponentWidth * x;
413 pStackPtr = &pStack[nComponentWidth * i];
415 SumFunction::assignPtr(pStackPtr, pSourcePointer);
417 nWeight = pWeightPointer[i];
419 SumFunction::add(nSum, pSourcePointer[0] * nWeight);
421 if (i - nRadius > 0)
423 SumFunction::add(nInSum, pSourcePointer);
425 else
427 SumFunction::add(nOutSum, pSourcePointer);
431 nStackIndex = nRadius;
432 nYPosition = std::min(nRadius, nLastIndexY);
434 pSourcePointer = pReadAccess->GetScanline(nYPosition) + nComponentWidth * x;
436 for (tools::Long y = 0; y < nHeight; y++)
438 pDestinationPointer = pWriteAccess->GetScanline(y) + nComponentWidth * x;
440 SumFunction::assignMulAndShr(pDestinationPointer, nSum, nMultiplyValue, nShiftValue);
442 SumFunction::sub(nSum, nOutSum);
444 nStackIndexStart = nStackIndex + nDiv - nRadius;
445 if (nStackIndexStart >= nDiv)
447 nStackIndexStart -= nDiv;
449 pStackPtr = &pStack[nComponentWidth * nStackIndexStart];
451 SumFunction::sub(nOutSum, pStackPtr);
453 if (nYPosition < nLastIndexY)
455 nYPosition++;
456 pSourcePointer = pReadAccess->GetScanline(nYPosition) + nComponentWidth * x;
459 SumFunction::assignPtr(pStackPtr, pSourcePointer);
460 SumFunction::add(nInSum, pSourcePointer);
461 SumFunction::add(nSum, nInSum);
463 nStackIndex++;
464 if (nStackIndex >= nDiv)
466 nStackIndex = 0;
469 pStackPtr = &pStack[nStackIndex * nComponentWidth];
471 SumFunction::add(nOutSum, pStackPtr);
472 SumFunction::sub(nInSum, pStackPtr);
477 constexpr tools::Long nThreadStrip = 16;
479 void runStackBlur(Bitmap& rBitmap, const tools::Long nRadius, const tools::Long nComponentWidth,
480 const tools::Long nColorChannels, BlurRangeFn pBlurHorizontalFn,
481 BlurRangeFn pBlurVerticalFn, const bool bParallel)
483 if (bParallel)
487 comphelper::ThreadPool& rShared = comphelper::ThreadPool::getSharedOptimalPool();
488 auto pTag = comphelper::ThreadPool::createThreadTaskTag();
491 Bitmap::ScopedReadAccess pReadAccess(rBitmap);
492 BitmapScopedWriteAccess pWriteAccess(rBitmap);
493 BlurSharedData aSharedData(pReadAccess.get(), pWriteAccess.get(), nRadius,
494 nComponentWidth, nColorChannels);
496 const tools::Long nFirstIndex = 0;
497 const tools::Long nLastIndex = pReadAccess->Height() - 1;
499 vcl::bitmap::generateStripRanges<nThreadStrip>(
500 nFirstIndex, nLastIndex,
501 [&](tools::Long const nStart, tools::Long const nEnd, bool const bLast) {
502 if (!bLast)
504 auto pTask(std::make_unique<BlurTask>(pTag, pBlurHorizontalFn,
505 aSharedData, nStart, nEnd));
506 rShared.pushTask(std::move(pTask));
508 else
509 pBlurHorizontalFn(aSharedData, nStart, nEnd);
511 rShared.waitUntilDone(pTag);
514 Bitmap::ScopedReadAccess pReadAccess(rBitmap);
515 BitmapScopedWriteAccess pWriteAccess(rBitmap);
516 BlurSharedData aSharedData(pReadAccess.get(), pWriteAccess.get(), nRadius,
517 nComponentWidth, nColorChannels);
519 const tools::Long nFirstIndex = 0;
520 const tools::Long nLastIndex = pReadAccess->Width() - 1;
522 vcl::bitmap::generateStripRanges<nThreadStrip>(
523 nFirstIndex, nLastIndex,
524 [&](tools::Long const nStart, tools::Long const nEnd, bool const bLast) {
525 if (!bLast)
527 auto pTask(std::make_unique<BlurTask>(pTag, pBlurVerticalFn,
528 aSharedData, nStart, nEnd));
529 rShared.pushTask(std::move(pTask));
531 else
532 pBlurVerticalFn(aSharedData, nStart, nEnd);
535 rShared.waitUntilDone(pTag);
538 catch (...)
540 SAL_WARN("vcl.gdi", "threaded bitmap blurring failed");
543 else
546 Bitmap::ScopedReadAccess pReadAccess(rBitmap);
547 BitmapScopedWriteAccess pWriteAccess(rBitmap);
548 BlurSharedData aSharedData(pReadAccess.get(), pWriteAccess.get(), nRadius,
549 nComponentWidth, nColorChannels);
550 tools::Long nFirstIndex = 0;
551 tools::Long nLastIndex = pReadAccess->Height() - 1;
552 pBlurHorizontalFn(aSharedData, nFirstIndex, nLastIndex);
555 Bitmap::ScopedReadAccess pReadAccess(rBitmap);
556 BitmapScopedWriteAccess pWriteAccess(rBitmap);
557 BlurSharedData aSharedData(pReadAccess.get(), pWriteAccess.get(), nRadius,
558 nComponentWidth, nColorChannels);
559 tools::Long nFirstIndex = 0;
560 tools::Long nLastIndex = pReadAccess->Width() - 1;
561 pBlurVerticalFn(aSharedData, nFirstIndex, nLastIndex);
566 void stackBlur24(Bitmap& rBitmap, sal_Int32 nRadius, sal_Int32 nComponentWidth)
568 const bool bParallel = true;
569 // Limit radius
570 nRadius = std::clamp<sal_Int32>(nRadius, 2, 254);
571 const tools::Long nColorChannels = 3; // 3 color channel
573 BlurRangeFn pBlurHorizontalFn = stackBlurHorizontal<SumFunction24>;
574 BlurRangeFn pBlurVerticalFn = stackBlurVertical<SumFunction24>;
576 runStackBlur(rBitmap, nRadius, nComponentWidth, nColorChannels, pBlurHorizontalFn,
577 pBlurVerticalFn, bParallel);
580 void stackBlur8(Bitmap& rBitmap, sal_Int32 nRadius, sal_Int32 nComponentWidth)
582 const bool bParallel = true;
583 // Limit radius
584 nRadius = std::clamp<sal_Int32>(nRadius, 2, 254);
585 const tools::Long nColorChannels = 1; // 1 color channel
587 BlurRangeFn pBlurHorizontalFn = stackBlurHorizontal<SumFunction8>;
588 BlurRangeFn pBlurVerticalFn = stackBlurVertical<SumFunction8>;
590 runStackBlur(rBitmap, nRadius, nComponentWidth, nColorChannels, pBlurHorizontalFn,
591 pBlurVerticalFn, bParallel);
594 } // end anonymous namespace
597 * Implementation of stack blur - a fast Gaussian blur approximation.
598 * nRadius - blur radius, valid values are between 2 and 254
599 * bExtend - extend the bitmap in all directions by the radius
601 * Stack Blur Algorithm by Mario Klingemann <mario@quasimondo.com>
602 * (http://www.quasimondo.com/StackBlurForCanvas/StackBlurDemo.html)
604 * Additionally references and implementations:
605 * - Blur.js by Jacob Kelley
606 * (http://www.blurjs.com)
607 * - BlurEffectForAndroidDesign by Nicolas Pomepuy
608 * (https://github.com/PomepuyN/BlurEffectForAndroidDesign)
609 * - StackBluriOS by Thomas Landspurg
610 * (https://github.com/tomsoft1/StackBluriOS)
611 * - stackblur.cpp by Benjamin Yates
612 * (https://gist.github.com/benjamin9999/3809142)
613 * - stack blur in fog 2D graphic library by Petr Kobalicek
614 * (https://code.google.com/p/fog/)
617 BitmapFilterStackBlur::BitmapFilterStackBlur(sal_Int32 nRadius)
618 : mnRadius(nRadius)
622 BitmapFilterStackBlur::~BitmapFilterStackBlur() {}
624 BitmapEx BitmapFilterStackBlur::execute(BitmapEx const& rBitmapEx) const
626 Bitmap aBitmap = rBitmapEx.GetBitmap();
627 Bitmap result = filter(aBitmap);
628 return BitmapEx(result, rBitmapEx.GetMask());
631 Bitmap BitmapFilterStackBlur::filter(Bitmap const& rBitmap) const
633 Bitmap bitmapCopy(rBitmap);
634 ScanlineFormat nScanlineFormat;
636 Bitmap::ScopedReadAccess pReadAccess(bitmapCopy);
637 nScanlineFormat = pReadAccess->GetScanlineFormat();
640 if (nScanlineFormat == ScanlineFormat::N24BitTcRgb
641 || nScanlineFormat == ScanlineFormat::N24BitTcBgr
642 || nScanlineFormat == ScanlineFormat::N32BitTcMask
643 || nScanlineFormat == ScanlineFormat::N32BitTcBgra)
645 int nComponentWidth = (nScanlineFormat == ScanlineFormat::N32BitTcMask
646 || nScanlineFormat == ScanlineFormat::N32BitTcBgra)
648 : 3;
650 stackBlur24(bitmapCopy, mnRadius, nComponentWidth);
652 else if (nScanlineFormat == ScanlineFormat::N8BitPal)
654 int nComponentWidth = 1;
656 stackBlur8(bitmapCopy, mnRadius, nComponentWidth);
659 return bitmapCopy;
662 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */