Line data Source code
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 :
11 : #include <vcl/BitmapFilterStackBlur.hxx>
12 : #include <vcl/bmpacc.hxx>
13 :
14 : namespace
15 : {
16 :
17 : static const sal_Int16 constMultiplyTable[255] =
18 : {
19 : 512, 512, 456, 512, 328, 456, 335, 512, 405, 328, 271, 456, 388, 335, 292, 512,
20 : 454, 405, 364, 328, 298, 271, 496, 456, 420, 388, 360, 335, 312, 292, 273, 512,
21 : 482, 454, 428, 405, 383, 364, 345, 328, 312, 298, 284, 271, 259, 496, 475, 456,
22 : 437, 420, 404, 388, 374, 360, 347, 335, 323, 312, 302, 292, 282, 273, 265, 512,
23 : 497, 482, 468, 454, 441, 428, 417, 405, 394, 383, 373, 364, 354, 345, 337, 328,
24 : 320, 312, 305, 298, 291, 284, 278, 271, 265, 259, 507, 496, 485, 475, 465, 456,
25 : 446, 437, 428, 420, 412, 404, 396, 388, 381, 374, 367, 360, 354, 347, 341, 335,
26 : 329, 323, 318, 312, 307, 302, 297, 292, 287, 282, 278, 273, 269, 265, 261, 512,
27 : 505, 497, 489, 482, 475, 468, 461, 454, 447, 441, 435, 428, 422, 417, 411, 405,
28 : 399, 394, 389, 383, 378, 373, 368, 364, 359, 354, 350, 345, 341, 337, 332, 328,
29 : 324, 320, 316, 312, 309, 305, 301, 298, 294, 291, 287, 284, 281, 278, 274, 271,
30 : 268, 265, 262, 259, 257, 507, 501, 496, 491, 485, 480, 475, 470, 465, 460, 456,
31 : 451, 446, 442, 437, 433, 428, 424, 420, 416, 412, 408, 404, 400, 396, 392, 388,
32 : 385, 381, 377, 374, 370, 367, 363, 360, 357, 354, 350, 347, 344, 341, 338, 335,
33 : 332, 329, 326, 323, 320, 318, 315, 312, 310, 307, 304, 302, 299, 297, 294, 292,
34 : 289, 287, 285, 282, 280, 278, 275, 273, 271, 269, 267, 265, 263, 261, 259
35 : };
36 :
37 : static const sal_Int16 constShiftTable[255] =
38 : {
39 : 9, 11, 12, 13, 13, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 17,
40 : 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 18, 19,
41 : 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 20, 20, 20,
42 : 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 21,
43 : 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
44 : 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22,
45 : 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
46 : 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23,
47 : 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
48 : 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
49 : 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
50 : 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
51 : 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
52 : 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
53 : 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
54 : 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24
55 : };
56 :
57 1 : class BlurSharedData
58 : {
59 : public:
60 : long mnRadius;
61 : long mnComponentWidth;
62 : long mnColorChannels;
63 : long mnDiv;
64 : std::vector<sal_uInt8> maStackBuffer;
65 : std::vector<long> maPositionTable;
66 : std::vector<long> maWeightTable;
67 :
68 : std::vector<long> mnSumVector;
69 : std::vector<long> mnInSumVector;
70 : std::vector<long> mnOutSumVector;
71 :
72 1 : BlurSharedData(long aRadius, long nComponentWidth, long nColorChannels)
73 : : mnRadius(aRadius)
74 : , mnComponentWidth(nComponentWidth)
75 : , mnColorChannels(nColorChannels)
76 1 : , mnDiv(aRadius + aRadius + 1)
77 1 : , maStackBuffer(mnDiv * mnComponentWidth)
78 : , maPositionTable(mnDiv)
79 : , maWeightTable(mnDiv)
80 : , mnSumVector(mnColorChannels)
81 : , mnInSumVector(mnColorChannels)
82 3 : , mnOutSumVector(mnColorChannels)
83 : {
84 1 : }
85 :
86 2 : void calculateWeightAndPositions(long nLastIndex)
87 : {
88 12 : for (long i = 0; i < mnDiv; i++)
89 : {
90 10 : maPositionTable[i] = std::min(nLastIndex, std::max(0L, i - mnRadius));
91 10 : maWeightTable[i] = mnRadius + 1 - std::abs(i - mnRadius);
92 : }
93 2 : }
94 :
95 2 : long getMultiplyValue()
96 : {
97 2 : return static_cast<long>(constMultiplyTable[mnRadius]);
98 : }
99 :
100 2 : long getShiftValue()
101 : {
102 2 : return static_cast<long>(constShiftTable[mnRadius]);
103 : }
104 : };
105 :
106 : struct SumFunction24
107 : {
108 400 : static inline void add(long*& pValue1, long nConstant)
109 : {
110 400 : pValue1[0] += nConstant;
111 400 : pValue1[1] += nConstant;
112 400 : pValue1[2] += nConstant;
113 400 : }
114 :
115 240 : static inline void set(long*& pValue1, long nConstant)
116 : {
117 240 : pValue1[0] = nConstant;
118 240 : pValue1[1] = nConstant;
119 240 : pValue1[2] = nConstant;
120 240 : }
121 :
122 6700 : static inline void add(long*& pValue1, sal_uInt8*& pValue2)
123 : {
124 6700 : pValue1[0] += pValue2[0];
125 6700 : pValue1[1] += pValue2[1];
126 6700 : pValue1[2] += pValue2[2];
127 6700 : }
128 :
129 3150 : static inline void add(long*& pValue1, long*& pValue2)
130 : {
131 3150 : pValue1[0] += pValue2[0];
132 3150 : pValue1[1] += pValue2[1];
133 3150 : pValue1[2] += pValue2[2];
134 3150 : }
135 :
136 6300 : static inline void sub(long*& pValue1, sal_uInt8*& pValue2)
137 : {
138 6300 : pValue1[0] -= pValue2[0];
139 6300 : pValue1[1] -= pValue2[1];
140 6300 : pValue1[2] -= pValue2[2];
141 6300 : }
142 :
143 3150 : static inline void sub(long*& pValue1, long*& pValue2)
144 : {
145 3150 : pValue1[0] -= pValue2[0];
146 3150 : pValue1[1] -= pValue2[1];
147 3150 : pValue1[2] -= pValue2[2];
148 3150 : }
149 :
150 3550 : static inline void assignPtr(sal_uInt8*& pValue1, sal_uInt8*& pValue2)
151 : {
152 3550 : pValue1[0] = pValue2[0];
153 3550 : pValue1[1] = pValue2[1];
154 3550 : pValue1[2] = pValue2[2];
155 3550 : }
156 :
157 3150 : static inline void assignMulAndShr(sal_uInt8*& result, long*& sum, long multiply, long shift)
158 : {
159 3150 : result[0] = (multiply * sum[0]) >> shift;
160 3150 : result[1] = (multiply * sum[1]) >> shift;
161 3150 : result[2] = (multiply * sum[2]) >> shift;
162 3150 : }
163 : };
164 :
165 : struct SumFunction8
166 : {
167 0 : static inline void add(long*& pValue1, long nConstant)
168 : {
169 0 : pValue1[0] += nConstant;
170 0 : }
171 :
172 0 : static inline void set(long*& pValue1, long nConstant)
173 : {
174 0 : pValue1[0] = nConstant;
175 0 : }
176 :
177 0 : static inline void add(long*& pValue1, sal_uInt8*& pValue2)
178 : {
179 0 : pValue1[0] += pValue2[0];
180 0 : }
181 :
182 0 : static inline void add(long*& pValue1, long*& pValue2)
183 : {
184 0 : pValue1[0] += pValue2[0];
185 0 : }
186 :
187 0 : static inline void sub(long*& pValue1, sal_uInt8*& pValue2)
188 : {
189 0 : pValue1[0] -= pValue2[0];
190 0 : }
191 :
192 0 : static inline void sub(long*& pValue1, long*& pValue2)
193 : {
194 0 : pValue1[0] -= pValue2[0];
195 0 : }
196 :
197 0 : static inline void assignPtr(sal_uInt8*& pValue1, sal_uInt8*& pValue2)
198 : {
199 0 : pValue1[0] = pValue2[0];
200 0 : }
201 :
202 0 : static inline void assignMulAndShr(sal_uInt8*& result, long*& sum, long multiply, long shift)
203 : {
204 0 : result[0] = (multiply * sum[0]) >> shift;
205 0 : }
206 : };
207 :
208 : template<typename SumFunction>
209 1 : void stackBlurHorizontal(
210 : BitmapReadAccess* pReadAccess,
211 : BitmapWriteAccess* pWriteAccess,
212 : BlurSharedData& rShared)
213 : {
214 1 : long nWidth = pReadAccess->Width();
215 1 : long nHeight = pReadAccess->Height();
216 :
217 1 : sal_uInt8* pStack = rShared.maStackBuffer.data();
218 : sal_uInt8* pStackPtr;
219 :
220 1 : long nLastIndexX = nWidth - 1;
221 :
222 1 : long nMultiplyValue = rShared.getMultiplyValue();
223 1 : long nShiftValue = rShared.getShiftValue();
224 :
225 1 : long nRadius = rShared.mnRadius;
226 1 : long nComponentWidth = rShared.mnComponentWidth;
227 1 : long nDiv = rShared.mnDiv;
228 :
229 : Scanline pSourcePointer;
230 : Scanline pDestinationPointer;
231 :
232 : long nXPosition;
233 : long nStackIndex;
234 : long nStackIndexStart;
235 : long nWeight;
236 :
237 1 : long* nSum = rShared.mnSumVector.data();
238 1 : long* nInSum = rShared.mnInSumVector.data();
239 1 : long* nOutSum = rShared.mnOutSumVector.data();
240 :
241 1 : rShared.calculateWeightAndPositions(nLastIndexX);
242 1 : long* pPositionPointer = rShared.maPositionTable.data();
243 1 : long* pWeightPointer = rShared.maWeightTable.data();
244 :
245 36 : for (long y = 0; y < nHeight; y++)
246 : {
247 35 : SumFunction::set(nSum, 0L);
248 35 : SumFunction::set(nInSum, 0L);
249 35 : SumFunction::set(nOutSum, 0L);
250 :
251 210 : for (long i = 0; i < nDiv; i++)
252 : {
253 175 : pSourcePointer = pReadAccess->GetScanline(pPositionPointer[i]);
254 :
255 175 : pStackPtr = &pStack[nComponentWidth * i];
256 :
257 175 : SumFunction::assignPtr(pStackPtr, pSourcePointer);
258 :
259 175 : nWeight = pWeightPointer[i];
260 :
261 175 : SumFunction::add(nSum, pSourcePointer[0] * nWeight);
262 :
263 175 : if (i - nRadius > 0)
264 : {
265 70 : SumFunction::add(nInSum, pSourcePointer);
266 : }
267 : else
268 : {
269 105 : SumFunction::add(nOutSum, pSourcePointer);
270 : }
271 : }
272 :
273 35 : nStackIndex = nRadius;
274 35 : nXPosition = std::min(nRadius, nLastIndexX);
275 :
276 35 : pSourcePointer = pReadAccess->GetScanline(y) + nComponentWidth * nXPosition;
277 :
278 1610 : for (long x = 0; x < nWidth; x++)
279 : {
280 1575 : pDestinationPointer = pWriteAccess->GetScanline(y) + nComponentWidth * x;
281 :
282 1575 : SumFunction::assignMulAndShr(pDestinationPointer, nSum, nMultiplyValue, nShiftValue);
283 :
284 1575 : SumFunction::sub(nSum, nOutSum);
285 :
286 1575 : nStackIndexStart = nStackIndex + nDiv - nRadius;
287 1575 : if (nStackIndexStart >= nDiv)
288 : {
289 945 : nStackIndexStart -= nDiv;
290 : }
291 1575 : pStackPtr = &pStack[nComponentWidth * nStackIndexStart];
292 :
293 1575 : SumFunction::sub(nOutSum, pStackPtr);
294 :
295 1575 : if (nXPosition < nLastIndexX)
296 : {
297 1470 : nXPosition++;
298 1470 : pSourcePointer = pReadAccess->GetScanline(y) + nComponentWidth * nXPosition;
299 : }
300 :
301 1575 : SumFunction::assignPtr(pStackPtr, pSourcePointer);
302 :
303 1575 : SumFunction::add(nInSum, pSourcePointer);
304 :
305 1575 : SumFunction::add(nSum, nInSum);
306 :
307 1575 : nStackIndex++;
308 1575 : if (nStackIndex >= nDiv)
309 : {
310 315 : nStackIndex = 0;
311 : }
312 :
313 1575 : pStackPtr = &pStack[nStackIndex * nComponentWidth];
314 :
315 1575 : SumFunction::add(nOutSum, pStackPtr);
316 1575 : SumFunction::sub(nInSum, pStackPtr);
317 : }
318 : }
319 1 : }
320 :
321 : template<typename SumFunction>
322 1 : void stackBlurVertical(
323 : BitmapReadAccess* pReadAccess,
324 : BitmapWriteAccess* pWriteAccess,
325 : BlurSharedData& rShared)
326 : {
327 1 : long nWidth = pReadAccess->Width();
328 1 : long nHeight = pReadAccess->Height();
329 :
330 1 : sal_uInt8* pStack = rShared.maStackBuffer.data();
331 : sal_uInt8* pStackPtr;
332 :
333 1 : long nLastIndexY = nHeight - 1;
334 :
335 1 : long nMultiplyValue = rShared.getMultiplyValue();
336 1 : long nShiftValue = rShared.getShiftValue();
337 :
338 1 : long nRadius = rShared.mnRadius;
339 1 : long nComponentWidth = rShared.mnComponentWidth;
340 1 : long nDiv = rShared.mnDiv;
341 :
342 : Scanline pSourcePointer;
343 : Scanline pDestinationPointer;
344 :
345 : long nYPosition;
346 : long nStackIndex;
347 : long nStackIndexStart;
348 : long nWeight;
349 :
350 1 : long* nSum = rShared.mnSumVector.data();
351 1 : long* nInSum = rShared.mnInSumVector.data();
352 1 : long* nOutSum = rShared.mnOutSumVector.data();
353 :
354 1 : rShared.calculateWeightAndPositions(nLastIndexY);
355 1 : long* pPositionPointer = rShared.maPositionTable.data();
356 1 : long* pWeightPointer = rShared.maWeightTable.data();
357 :
358 46 : for (long x = 0; x < nWidth; x++)
359 : {
360 45 : SumFunction::set(nSum, 0L);
361 45 : SumFunction::set(nInSum, 0L);
362 45 : SumFunction::set(nOutSum, 0L);
363 :
364 270 : for (long i = 0; i < nDiv; i++)
365 : {
366 225 : pSourcePointer = pReadAccess->GetScanline(pPositionPointer[i]);
367 :
368 225 : pStackPtr = &pStack[nComponentWidth * i];
369 :
370 225 : SumFunction::assignPtr(pStackPtr, pSourcePointer);
371 :
372 225 : nWeight = pWeightPointer[i];
373 :
374 225 : SumFunction::add(nSum, pSourcePointer[0] * nWeight);
375 :
376 225 : if (i - nRadius > 0)
377 : {
378 90 : SumFunction::add(nInSum, pSourcePointer);
379 : }
380 : else
381 : {
382 135 : SumFunction::add(nOutSum, pSourcePointer);
383 : }
384 : }
385 :
386 45 : nStackIndex = nRadius;
387 45 : nYPosition = std::min(nRadius, nLastIndexY);
388 :
389 45 : pSourcePointer = pReadAccess->GetScanline(nYPosition) + nComponentWidth * x;
390 :
391 1620 : for (long y = 0; y < nHeight; y++)
392 : {
393 1575 : pDestinationPointer = pWriteAccess->GetScanline(y) + nComponentWidth * x;
394 :
395 1575 : SumFunction::assignMulAndShr(pDestinationPointer, nSum, nMultiplyValue, nShiftValue);
396 :
397 1575 : SumFunction::sub(nSum, nOutSum);
398 :
399 :
400 1575 : nStackIndexStart = nStackIndex + nDiv - nRadius;
401 1575 : if (nStackIndexStart >= nDiv)
402 : {
403 945 : nStackIndexStart -= nDiv;
404 : }
405 1575 : pStackPtr = &pStack[nComponentWidth * nStackIndexStart];
406 :
407 1575 : SumFunction::sub(nOutSum, pStackPtr);
408 :
409 1575 : if (nYPosition < nLastIndexY)
410 : {
411 1440 : nYPosition++;
412 1440 : pSourcePointer = pReadAccess->GetScanline(nYPosition) + nComponentWidth * x;
413 : }
414 :
415 1575 : SumFunction::assignPtr(pStackPtr, pSourcePointer);
416 :
417 1575 : SumFunction::add(nInSum, pSourcePointer);
418 :
419 1575 : SumFunction::add(nSum, nInSum);
420 :
421 1575 : nStackIndex++;
422 1575 : if (nStackIndex >= nDiv)
423 : {
424 315 : nStackIndex = 0;
425 : }
426 :
427 1575 : pStackPtr = &pStack[nStackIndex * nComponentWidth];
428 :
429 1575 : SumFunction::add(nOutSum, pStackPtr);
430 :
431 1575 : SumFunction::sub(nInSum, pStackPtr);
432 : }
433 : }
434 1 : }
435 :
436 1 : void stackBlur24(Bitmap& rBitmap, sal_Int32 nRadius, sal_Int32 nComponentWidth)
437 : {
438 : // Limit radius
439 1 : nRadius = std::min<sal_Int32>(254, std::max<sal_Int32>(2, nRadius));
440 1 : const long nColorChannels = 3; // 3 color channel
441 1 : BlurSharedData aData(nRadius, nComponentWidth, nColorChannels);
442 :
443 : {
444 1 : Bitmap::ScopedReadAccess pReadAccess(rBitmap);
445 2 : Bitmap::ScopedWriteAccess pWriteAccess(rBitmap);
446 :
447 2 : stackBlurHorizontal<SumFunction24>(pReadAccess.get(), pWriteAccess.get(), aData);
448 : }
449 :
450 : {
451 1 : Bitmap::ScopedReadAccess pReadAccess(rBitmap);
452 2 : Bitmap::ScopedWriteAccess pWriteAccess(rBitmap);
453 :
454 2 : stackBlurVertical<SumFunction24>(pReadAccess.get(), pWriteAccess.get(), aData);
455 1 : }
456 1 : }
457 :
458 0 : void stackBlur8(Bitmap& rBitmap, sal_Int32 nRadius, sal_Int32 nComponentWidth)
459 : {
460 : // Limit radius
461 0 : nRadius = std::min<sal_Int32>(254, std::max<sal_Int32>(2, nRadius));
462 0 : const long nColorChannels = 1; // 1 color channel
463 0 : BlurSharedData aData(nRadius, nComponentWidth, nColorChannels);
464 :
465 : {
466 0 : Bitmap::ScopedReadAccess pReadAccess(rBitmap);
467 0 : Bitmap::ScopedWriteAccess pWriteAccess(rBitmap);
468 :
469 0 : stackBlurHorizontal<SumFunction8>(pReadAccess.get(), pWriteAccess.get(), aData);
470 : }
471 :
472 : {
473 0 : Bitmap::ScopedReadAccess pReadAccess(rBitmap);
474 0 : Bitmap::ScopedWriteAccess pWriteAccess(rBitmap);
475 :
476 0 : stackBlurVertical<SumFunction8>(pReadAccess.get(), pWriteAccess.get(), aData);
477 0 : }
478 0 : }
479 :
480 1 : void centerExtendBitmap(Bitmap& rBitmap, sal_Int32 nExtendSize, Color aColor)
481 : {
482 1 : const Size& rSize = rBitmap.GetSizePixel();
483 1 : const Size aNewSize(rSize.Width() + nExtendSize * 2,
484 2 : rSize.Height() + nExtendSize * 2);
485 :
486 1 : Bitmap aNewBitmap(aNewSize, rBitmap.GetBitCount());
487 :
488 : {
489 1 : Bitmap::ScopedReadAccess pReadAccess(rBitmap);
490 2 : Bitmap::ScopedWriteAccess pWriteAccess(aNewBitmap);
491 :
492 1 : long nWidthBorder = nExtendSize + rSize.Width();
493 1 : long nHeightBorder = nExtendSize + rSize.Height();
494 :
495 36 : for (long y = 0; y < aNewSize.Height(); y++)
496 : {
497 1610 : for (long x = 0; x < aNewSize.Width(); x++)
498 : {
499 1575 : if (y < nExtendSize || y >= nHeightBorder
500 1395 : || x < nExtendSize || x >= nWidthBorder)
501 : {
502 304 : pWriteAccess->SetPixel(y, x, aColor);
503 : }
504 : else
505 : {
506 1271 : pWriteAccess->SetPixel(y, x, pReadAccess->GetPixel(y - nExtendSize, x - nExtendSize));
507 : }
508 : }
509 1 : }
510 : }
511 1 : rBitmap = aNewBitmap;
512 1 : }
513 :
514 : } // end anonymous namespace
515 :
516 : /**
517 : * Implementation of stack blur - a fast Gaussian blur approximation.
518 : * nRadius - blur radious, valid values are between 2 and 254
519 : * bExtend - extend the bitmap in all directions by the radius
520 : *
521 : * Stack Blur Algorithm by Mario Klingemann <mario@quasimondo.com>
522 : * (http://www.quasimondo.com/StackBlurForCanvas/StackBlurDemo.html)
523 : *
524 : * Additionally eferences and implementations:
525 : * - Blur.js by Jacob Kelley
526 : * (http://www.blurjs.com)
527 : * - BlurEffectForAndroidDesign by Nicolas Pomepuy
528 : * (https://github.com/PomepuyN/BlurEffectForAndroidDesign)
529 : * - StackBluriOS by Thomas Landspurg
530 : * (https://github.com/tomsoft1/StackBluriOS)
531 : * - stackblur.cpp by Benjamin Yates
532 : * (https://gist.github.com/benjamin9999/3809142)
533 : * - stack blur in fog 2D graphic library by Petr Kobalicek
534 : * (https://code.google.com/p/fog/)
535 : *
536 : */
537 1 : BitmapFilterStackBlur::BitmapFilterStackBlur(sal_Int32 nRadius, bool bExtend)
538 : : mnRadius(nRadius)
539 1 : , mbExtend(bExtend)
540 1 : {}
541 :
542 1 : BitmapFilterStackBlur::~BitmapFilterStackBlur()
543 1 : {}
544 :
545 1 : bool BitmapFilterStackBlur::filter(Bitmap& rBitmap)
546 : {
547 : sal_uLong nScanlineFormat;
548 : {
549 1 : Bitmap::ScopedReadAccess pReadAccess(rBitmap);
550 1 : nScanlineFormat = pReadAccess->GetScanlineFormat();
551 : }
552 :
553 1 : if (nScanlineFormat == BMP_FORMAT_24BIT_TC_RGB ||
554 1 : nScanlineFormat == BMP_FORMAT_24BIT_TC_BGR ||
555 : nScanlineFormat == BMP_FORMAT_32BIT_TC_MASK)
556 : {
557 1 : int nComponentWidth = (nScanlineFormat == BMP_FORMAT_32BIT_TC_MASK) ? 4 : 3;
558 :
559 1 : if (mbExtend)
560 : {
561 1 : centerExtendBitmap(rBitmap, mnRadius, COL_WHITE);
562 : }
563 :
564 1 : stackBlur24(rBitmap, mnRadius, nComponentWidth);
565 : }
566 0 : else if (nScanlineFormat == BMP_FORMAT_8BIT_PAL)
567 : {
568 0 : int nComponentWidth = 1;
569 :
570 0 : if (mbExtend)
571 : {
572 0 : centerExtendBitmap(rBitmap, mnRadius, COL_WHITE);
573 : }
574 :
575 0 : stackBlur8(rBitmap, mnRadius, nComponentWidth);
576 : }
577 :
578 1 : return true;
579 : }
580 :
581 0 : bool BitmapFilterStackBlur::filter(BitmapEx& rBitmapEx)
582 : {
583 0 : Bitmap aBitmap = rBitmapEx.GetBitmap();
584 0 : filter(aBitmap);
585 0 : rBitmapEx = BitmapEx(aBitmap);
586 :
587 0 : return true;
588 : }
589 :
590 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|