KHtml

imagefilter.cpp
1 /*
2  This file is a part of the KDE project
3 
4  Copyright © 2006 Zack Rusin <[email protected]>
5  Copyright © 2006-2007, 2008 Fredrik Höglund <[email protected]>
6 
7  The stack blur algorithm was invented by Mario Klingemann <[email protected]>
8 
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)
11 
12  Redistribution and use in source and binary forms, with or without
13  modification, are permitted provided that the following conditions
14  are met:
15 
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.
21 
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.
32 */
33 
34 #include <QPainter>
35 #include <QImage>
36 #include <QColor>
37 #include "khtml_debug.h"
38 
39 #include <cmath>
40 #include <string.h>
41 
42 #include "imagefilter.h"
43 
44 using namespace khtml;
45 
46 static const quint32 stack_blur8_mul[255] = {
47  512, 512, 456, 512, 328, 456, 335, 512, 405, 328, 271, 456, 388, 335, 292, 512,
48  454, 405, 364, 328, 298, 271, 496, 456, 420, 388, 360, 335, 312, 292, 273, 512,
49  482, 454, 428, 405, 383, 364, 345, 328, 312, 298, 284, 271, 259, 496, 475, 456,
50  437, 420, 404, 388, 374, 360, 347, 335, 323, 312, 302, 292, 282, 273, 265, 512,
51  497, 482, 468, 454, 441, 428, 417, 405, 394, 383, 373, 364, 354, 345, 337, 328,
52  320, 312, 305, 298, 291, 284, 278, 271, 265, 259, 507, 496, 485, 475, 465, 456,
53  446, 437, 428, 420, 412, 404, 396, 388, 381, 374, 367, 360, 354, 347, 341, 335,
54  329, 323, 318, 312, 307, 302, 297, 292, 287, 282, 278, 273, 269, 265, 261, 512,
55  505, 497, 489, 482, 475, 468, 461, 454, 447, 441, 435, 428, 422, 417, 411, 405,
56  399, 394, 389, 383, 378, 373, 368, 364, 359, 354, 350, 345, 341, 337, 332, 328,
57  324, 320, 316, 312, 309, 305, 301, 298, 294, 291, 287, 284, 281, 278, 274, 271,
58  268, 265, 262, 259, 257, 507, 501, 496, 491, 485, 480, 475, 470, 465, 460, 456,
59  451, 446, 442, 437, 433, 428, 424, 420, 416, 412, 408, 404, 400, 396, 392, 388,
60  385, 381, 377, 374, 370, 367, 363, 360, 357, 354, 350, 347, 344, 341, 338, 335,
61  332, 329, 326, 323, 320, 318, 315, 312, 310, 307, 304, 302, 299, 297, 294, 292,
62  289, 287, 285, 282, 280, 278, 275, 273, 271, 269, 267, 265, 263, 261, 259
63 };
64 
65 static const quint32 stack_blur8_shr[255] = {
66  9, 11, 12, 13, 13, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 17,
67  17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 18, 19,
68  19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 20, 20, 20,
69  20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 21,
70  21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
71  21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22,
72  22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
73  22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23,
74  23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
75  23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
76  23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
77  23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
78  24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
79  24, 24, 24, 24, 24, 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
82 };
83 
84 inline static void blurHorizontal(QImage &image, unsigned int *stack, int div, int radius)
85 {
86  int stackindex;
87  int stackstart;
88 
89  quint32 *const pixels = reinterpret_cast<quint32 *>(image.bits());
90  quint32 pixel;
91 
92  int w = image.width();
93  int h = image.height();
94  int wm = w - 1;
95 
96  unsigned int mul_sum = stack_blur8_mul[radius];
97  unsigned int shr_sum = stack_blur8_shr[radius];
98 
99  unsigned int sum, sum_in, sum_out;
100 
101  for (int y = 0; y < h; y++) {
102  sum = 0;
103  sum_in = 0;
104  sum_out = 0;
105 
106  const int yw = y * w;
107  pixel = pixels[yw];
108  for (int i = 0; i <= radius; i++) {
109  stack[i] = qAlpha(pixel);
110 
111  sum += stack[i] * (i + 1);
112  sum_out += stack[i];
113  }
114 
115  for (int i = 1; i <= radius; i++) {
116  pixel = pixels[yw + qMin(i, wm)];
117 
118  unsigned int *stackpix = &stack[i + radius];
119  *stackpix = qAlpha(pixel);
120 
121  sum += *stackpix * (radius + 1 - i);
122  sum_in += *stackpix;
123  }
124 
125  stackindex = radius;
126  for (int x = 0, i = yw; x < w; x++) {
127  pixels[i++] = (((sum * mul_sum) >> shr_sum) << 24) & 0xff000000;
128 
129  sum -= sum_out;
130 
131  stackstart = stackindex + div - radius;
132  if (stackstart >= div) {
133  stackstart -= div;
134  }
135 
136  unsigned int *stackpix = &stack[stackstart];
137 
138  sum_out -= *stackpix;
139 
140  pixel = pixels[yw + qMin(x + radius + 1, wm)];
141 
142  *stackpix = qAlpha(pixel);
143 
144  sum_in += *stackpix;
145  sum += sum_in;
146 
147  if (++stackindex >= div) {
148  stackindex = 0;
149  }
150 
151  stackpix = &stack[stackindex];
152 
153  sum_out += *stackpix;
154  sum_in -= *stackpix;
155  } // for (x = 0, ...)
156  } // for (y = 0, ...)
157 }
158 
159 inline static void blurVertical(QImage &image, unsigned int *stack, int div, int radius)
160 {
161  int stackindex;
162  int stackstart;
163 
164  quint32 *const pixels = reinterpret_cast<quint32 *>(image.bits());
165  quint32 pixel;
166 
167  int w = image.width();
168  int h = image.height();
169  int hm = h - 1;
170 
171  int mul_sum = stack_blur8_mul[radius];
172  int shr_sum = stack_blur8_shr[radius];
173 
174  unsigned int sum, sum_in, sum_out;
175 
176  for (int x = 0; x < w; x++) {
177  sum = 0;
178  sum_in = 0;
179  sum_out = 0;
180 
181  pixel = pixels[x];
182  for (int i = 0; i <= radius; i++) {
183  stack[i] = qAlpha(pixel);
184 
185  sum += stack[i] * (i + 1);
186  sum_out += stack[i];
187  }
188 
189  for (int i = 1; i <= radius; i++) {
190  pixel = pixels[qMin(i, hm) * w + x];
191 
192  unsigned int *stackpix = &stack[i + radius];
193  *stackpix = qAlpha(pixel);
194 
195  sum += *stackpix * (radius + 1 - i);
196  sum_in += *stackpix;
197  }
198 
199  stackindex = radius;
200  for (int y = 0, i = x; y < h; y++, i += w) {
201  pixels[i] = (((sum * mul_sum) >> shr_sum) << 24) & 0xff000000;
202 
203  sum -= sum_out;
204 
205  stackstart = stackindex + div - radius;
206  if (stackstart >= div) {
207  stackstart -= div;
208  }
209 
210  unsigned int *stackpix = &stack[stackstart];
211 
212  sum_out -= *stackpix;
213 
214  pixel = pixels[qMin(y + radius + 1, hm) * w + x];
215 
216  *stackpix = qAlpha(pixel);
217 
218  sum_in += *stackpix;
219  sum += sum_in;
220 
221  if (++stackindex >= div) {
222  stackindex = 0;
223  }
224 
225  stackpix = &stack[stackindex];
226 
227  sum_out += *stackpix;
228  sum_in -= *stackpix;
229  } // for (y = 0, ...)
230  } // for (x = 0, ...)
231 }
232 
233 static void stackBlur(QImage &image, float radius)
234 {
235  radius = qRound(radius);
236 
237  int div = int(radius * 2) + 1;
238  unsigned int *stack = new unsigned int[div];
239 
240  blurHorizontal(image, stack, div, radius);
241  blurVertical(image, stack, div, radius);
242 
243  delete [] stack;
244 }
245 
246 void ImageFilter::shadowBlur(QImage &image, float radius, const QColor &color)
247 {
248  if (radius < 0) {
249  return;
250  }
251 
252  if (radius > 0) {
253  stackBlur(image, radius);
254  }
255 
256  // Correct the color and opacity of the shadow
257  QPainter p(&image);
258  p.setCompositionMode(QPainter::CompositionMode_SourceIn);
259  p.fillRect(image.rect(), color);
260 }
261 
This file is part of the HTML rendering engine for KDE.
int width() const const
QRect rect() const const
CompositionMode_SourceIn
uchar * bits()
int height() const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2021 The KDE developers.
Generated on Tue Oct 26 2021 22:48:03 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.