1 //krazy:exclude=copyright (email of Maxim is missing)
3 This file is a part of the KDE project
5 Copyright © 2006 Zack Rusin <zack@kde.org>
6 Copyright © 2006-2007, 2008 Fredrik Höglund <fredrik@kde.org>
8 The stack blur algorithm was invented by Mario Klingemann <mario@quasimondo.com>
10 This implementation is based on the version in Anti-Grain Geometry Version 2.4,
11 Copyright © 2002-2005 Maxim Shemanarev (http://www.antigrain.com)
13 Redistribution and use in source and binary forms, with or without
14 modification, are permitted provided that the following conditions
17 1. Redistributions of source code must retain the above copyright
18 notice, this list of conditions and the following disclaimer.
19 2. Redistributions in binary form must reproduce the above copyright
20 notice, this list of conditions and the following disclaimer in the
21 documentation and/or other materials provided with the distribution.
23 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
24 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
25 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
26 IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
27 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
28 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
30 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
32 THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35 #include "imagefilter_p.h"
47 static const quint32 stack_blur8_mul
[255] =
49 512,512,456,512,328,456,335,512,405,328,271,456,388,335,292,512,
50 454,405,364,328,298,271,496,456,420,388,360,335,312,292,273,512,
51 482,454,428,405,383,364,345,328,312,298,284,271,259,496,475,456,
52 437,420,404,388,374,360,347,335,323,312,302,292,282,273,265,512,
53 497,482,468,454,441,428,417,405,394,383,373,364,354,345,337,328,
54 320,312,305,298,291,284,278,271,265,259,507,496,485,475,465,456,
55 446,437,428,420,412,404,396,388,381,374,367,360,354,347,341,335,
56 329,323,318,312,307,302,297,292,287,282,278,273,269,265,261,512,
57 505,497,489,482,475,468,461,454,447,441,435,428,422,417,411,405,
58 399,394,389,383,378,373,368,364,359,354,350,345,341,337,332,328,
59 324,320,316,312,309,305,301,298,294,291,287,284,281,278,274,271,
60 268,265,262,259,257,507,501,496,491,485,480,475,470,465,460,456,
61 451,446,442,437,433,428,424,420,416,412,408,404,400,396,392,388,
62 385,381,377,374,370,367,363,360,357,354,350,347,344,341,338,335,
63 332,329,326,323,320,318,315,312,310,307,304,302,299,297,294,292,
64 289,287,285,282,280,278,275,273,271,269,267,265,263,261,259
67 static const quint32 stack_blur8_shr
[255] =
69 9, 11, 12, 13, 13, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 17,
70 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 18, 19,
71 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 20, 20, 20,
72 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 21,
73 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
74 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22,
75 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
76 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23,
77 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
78 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
79 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
80 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
81 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
82 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
83 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
84 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24
87 inline static void blurHorizontal(QImage
&image
, unsigned int *stack
, int div
, int radius
)
92 quint32
* const pixels
= reinterpret_cast<quint32
*>(image
.bits());
95 int w
= image
.width();
96 int h
= image
.height();
99 unsigned int mul_sum
= stack_blur8_mul
[radius
];
100 unsigned int shr_sum
= stack_blur8_shr
[radius
];
102 unsigned int sum
, sum_in
, sum_out
;
104 for (int y
= 0; y
< h
; y
++)
110 const int yw
= y
* w
;
112 for (int i
= 0; i
<= radius
; i
++)
114 stack
[i
] = qAlpha(pixel
);
116 sum
+= stack
[i
] * (i
+ 1);
120 for (int i
= 1; i
<= radius
; i
++)
122 pixel
= pixels
[yw
+ qMin(i
, wm
)];
124 unsigned int *stackpix
= &stack
[i
+ radius
];
125 *stackpix
= qAlpha(pixel
);
127 sum
+= *stackpix
* (radius
+ 1 - i
);
132 for (int x
= 0, i
= yw
; x
< w
; x
++)
134 pixels
[i
++] = (((sum
* mul_sum
) >> shr_sum
) << 24) & 0xff000000;
138 stackstart
= stackindex
+ div
- radius
;
139 if (stackstart
>= div
)
142 unsigned int *stackpix
= &stack
[stackstart
];
144 sum_out
-= *stackpix
;
146 pixel
= pixels
[yw
+ qMin(x
+ radius
+ 1, wm
)];
148 *stackpix
= qAlpha(pixel
);
153 if (++stackindex
>= div
)
156 stackpix
= &stack
[stackindex
];
158 sum_out
+= *stackpix
;
160 } // for (x = 0, ...)
161 } // for (y = 0, ...)
164 inline static void blurVertical(QImage
&image
, unsigned int *stack
, int div
, int radius
)
169 quint32
* const pixels
= reinterpret_cast<quint32
*>(image
.bits());
172 int w
= image
.width();
173 int h
= image
.height();
176 int mul_sum
= stack_blur8_mul
[radius
];
177 int shr_sum
= stack_blur8_shr
[radius
];
179 unsigned int sum
, sum_in
, sum_out
;
181 for (int x
= 0; x
< w
; x
++)
188 for (int i
= 0; i
<= radius
; i
++)
190 stack
[i
] = qAlpha(pixel
);
192 sum
+= stack
[i
] * (i
+ 1);
196 for (int i
= 1; i
<= radius
; i
++)
198 pixel
= pixels
[qMin(i
, hm
) * w
+ x
];
200 unsigned int *stackpix
= &stack
[i
+ radius
];
201 *stackpix
= qAlpha(pixel
);
203 sum
+= *stackpix
* (radius
+ 1 - i
);
208 for (int y
= 0, i
= x
; y
< h
; y
++, i
+= w
)
210 pixels
[i
] = (((sum
* mul_sum
) >> shr_sum
) << 24) & 0xff000000;
214 stackstart
= stackindex
+ div
- radius
;
215 if (stackstart
>= div
)
218 unsigned int *stackpix
= &stack
[stackstart
];
220 sum_out
-= *stackpix
;
222 pixel
= pixels
[qMin(y
+ radius
+ 1, hm
) * w
+ x
];
224 *stackpix
= qAlpha(pixel
);
229 if (++stackindex
>= div
)
232 stackpix
= &stack
[stackindex
];
234 sum_out
+= *stackpix
;
236 } // for (y = 0, ...)
237 } // for (x = 0, ...)
240 static void stackBlur(QImage
&image
, float radius
)
242 radius
= qRound(radius
);
244 int div
= int(radius
* 2) + 1;
245 unsigned int *stack
= new unsigned int[div
];
247 blurHorizontal(image
, stack
, div
, radius
);
248 blurVertical(image
, stack
, div
, radius
);
253 void ImageFilter::shadowBlur(QImage
&image
, float radius
, const QColor
&color
)
259 stackBlur(image
, radius
);
261 // Correct the color and opacity of the shadow
263 p
.setCompositionMode(QPainter::CompositionMode_SourceIn
);
264 p
.fillRect(image
.rect(), color
);
267 // kate: space-indent on; indent-width 4; replace-tabs on;