2 This file is a part of the KDE project
4 Copyright © 2006 Zack Rusin <zack@kde.org>
5 Copyright © 2006-2007, 2008 Fredrik Höglund <fredrik@kde.org>
7 The stack blur algorithm was invented by Mario Klingemann <mario@quasimondo.com>
9 This implementation is based on the version in Anti-Grain Geometry Version 2.4,
10 Copyright © 2002-2005 Maxim Shemanarev (http://www.antigrain.com)
12 Redistribution and use in source and binary forms, with or without
13 modification, are permitted provided that the following conditions
16 1. Redistributions of source code must retain the above copyright
17 notice, this list of conditions and the following disclaimer.
18 2. Redistributions in binary form must reproduce the above copyright
19 notice, this list of conditions and the following disclaimer in the
20 documentation and/or other materials provided with the distribution.
22 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
23 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25 IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
26 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
27 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
31 THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
42 #include "imagefilter.h"
44 using namespace khtml
;
46 static const quint32 stack_blur8_mul
[255] =
48 512,512,456,512,328,456,335,512,405,328,271,456,388,335,292,512,
49 454,405,364,328,298,271,496,456,420,388,360,335,312,292,273,512,
50 482,454,428,405,383,364,345,328,312,298,284,271,259,496,475,456,
51 437,420,404,388,374,360,347,335,323,312,302,292,282,273,265,512,
52 497,482,468,454,441,428,417,405,394,383,373,364,354,345,337,328,
53 320,312,305,298,291,284,278,271,265,259,507,496,485,475,465,456,
54 446,437,428,420,412,404,396,388,381,374,367,360,354,347,341,335,
55 329,323,318,312,307,302,297,292,287,282,278,273,269,265,261,512,
56 505,497,489,482,475,468,461,454,447,441,435,428,422,417,411,405,
57 399,394,389,383,378,373,368,364,359,354,350,345,341,337,332,328,
58 324,320,316,312,309,305,301,298,294,291,287,284,281,278,274,271,
59 268,265,262,259,257,507,501,496,491,485,480,475,470,465,460,456,
60 451,446,442,437,433,428,424,420,416,412,408,404,400,396,392,388,
61 385,381,377,374,370,367,363,360,357,354,350,347,344,341,338,335,
62 332,329,326,323,320,318,315,312,310,307,304,302,299,297,294,292,
63 289,287,285,282,280,278,275,273,271,269,267,265,263,261,259
66 static const quint32 stack_blur8_shr
[255] =
68 9, 11, 12, 13, 13, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 17,
69 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 18, 19,
70 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 20, 20, 20,
71 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 21,
72 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
73 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22,
74 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
75 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23,
76 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 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, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
80 24, 24, 24, 24, 24, 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
86 inline static void blurHorizontal(QImage
&image
, unsigned int *stack
, int div
, int radius
)
91 quint32
* const pixels
= reinterpret_cast<quint32
*>(image
.bits());
94 int w
= image
.width();
95 int h
= image
.height();
98 unsigned int mul_sum
= stack_blur8_mul
[radius
];
99 unsigned int shr_sum
= stack_blur8_shr
[radius
];
101 unsigned int sum
, sum_in
, sum_out
;
103 for (int y
= 0; y
< h
; y
++)
109 const int yw
= y
* w
;
111 for (int i
= 0; i
<= radius
; i
++)
113 stack
[i
] = qAlpha(pixel
);
115 sum
+= stack
[i
] * (i
+ 1);
119 for (int i
= 1; i
<= radius
; i
++)
121 pixel
= pixels
[yw
+ qMin(i
, wm
)];
123 unsigned int *stackpix
= &stack
[i
+ radius
];
124 *stackpix
= qAlpha(pixel
);
126 sum
+= *stackpix
* (radius
+ 1 - i
);
131 for (int x
= 0, i
= yw
; x
< w
; x
++)
133 pixels
[i
++] = (((sum
* mul_sum
) >> shr_sum
) << 24) & 0xff000000;
137 stackstart
= stackindex
+ div
- radius
;
138 if (stackstart
>= div
)
141 unsigned int *stackpix
= &stack
[stackstart
];
143 sum_out
-= *stackpix
;
145 pixel
= pixels
[yw
+ qMin(x
+ radius
+ 1, wm
)];
147 *stackpix
= qAlpha(pixel
);
152 if (++stackindex
>= div
)
155 stackpix
= &stack
[stackindex
];
157 sum_out
+= *stackpix
;
159 } // for (x = 0, ...)
160 } // for (y = 0, ...)
163 inline static void blurVertical(QImage
&image
, unsigned int *stack
, int div
, int radius
)
168 quint32
* const pixels
= reinterpret_cast<quint32
*>(image
.bits());
171 int w
= image
.width();
172 int h
= image
.height();
175 int mul_sum
= stack_blur8_mul
[radius
];
176 int shr_sum
= stack_blur8_shr
[radius
];
178 unsigned int sum
, sum_in
, sum_out
;
180 for (int x
= 0; x
< w
; x
++)
187 for (int i
= 0; i
<= radius
; i
++)
189 stack
[i
] = qAlpha(pixel
);
191 sum
+= stack
[i
] * (i
+ 1);
195 for (int i
= 1; i
<= radius
; i
++)
197 pixel
= pixels
[qMin(i
, hm
) * w
+ x
];
199 unsigned int *stackpix
= &stack
[i
+ radius
];
200 *stackpix
= qAlpha(pixel
);
202 sum
+= *stackpix
* (radius
+ 1 - i
);
207 for (int y
= 0, i
= x
; y
< h
; y
++, i
+= w
)
209 pixels
[i
] = (((sum
* mul_sum
) >> shr_sum
) << 24) & 0xff000000;
213 stackstart
= stackindex
+ div
- radius
;
214 if (stackstart
>= div
)
217 unsigned int *stackpix
= &stack
[stackstart
];
219 sum_out
-= *stackpix
;
221 pixel
= pixels
[qMin(y
+ radius
+ 1, hm
) * w
+ x
];
223 *stackpix
= qAlpha(pixel
);
228 if (++stackindex
>= div
)
231 stackpix
= &stack
[stackindex
];
233 sum_out
+= *stackpix
;
235 } // for (y = 0, ...)
236 } // for (x = 0, ...)
239 static void stackBlur(QImage
&image
, float radius
)
241 radius
= qRound(radius
);
243 int div
= int(radius
* 2) + 1;
244 unsigned int *stack
= new unsigned int[div
];
246 blurHorizontal(image
, stack
, div
, radius
);
247 blurVertical(image
, stack
, div
, radius
);
252 void ImageFilter::shadowBlur(QImage
&image
, float radius
, const QColor
&color
)
258 stackBlur(image
, radius
);
260 // Correct the color and opacity of the shadow
262 p
.setCompositionMode(QPainter::CompositionMode_SourceIn
);
263 p
.fillRect(image
.rect(), color
);
266 // kate: space-indent on; indent-width 4; replace-tabs on;