fix tricky regression noticed by Vyacheslav Tokarev on Google Reader.
[kdelibs.git] / kio / kio / imagefilter.cpp
blob65d7dbc3b1cf9e800e027dc264d2663d5e9966ce
1 //krazy:exclude=copyright (email of Maxim is missing)
2 /*
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
15 are met:
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"
37 #include <QPainter>
38 #include <QImage>
39 #include <QColor>
40 #include <QDebug>
42 #include <cmath>
43 #include <string.h>
45 using namespace KIO;
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)
89 int stackindex;
90 int stackstart;
92 quint32 * const pixels = reinterpret_cast<quint32 *>(image.bits());
93 quint32 pixel;
95 int w = image.width();
96 int h = image.height();
97 int wm = w - 1;
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++)
106 sum = 0;
107 sum_in = 0;
108 sum_out = 0;
110 const int yw = y * w;
111 pixel = pixels[yw];
112 for (int i = 0; i <= radius; i++)
114 stack[i] = qAlpha(pixel);
116 sum += stack[i] * (i + 1);
117 sum_out += stack[i];
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);
128 sum_in += *stackpix;
131 stackindex = radius;
132 for (int x = 0, i = yw; x < w; x++)
134 pixels[i++] = (((sum * mul_sum) >> shr_sum) << 24) & 0xff000000;
136 sum -= sum_out;
138 stackstart = stackindex + div - radius;
139 if (stackstart >= div)
140 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);
150 sum_in += *stackpix;
151 sum += sum_in;
153 if (++stackindex >= div)
154 stackindex = 0;
156 stackpix = &stack[stackindex];
158 sum_out += *stackpix;
159 sum_in -= *stackpix;
160 } // for (x = 0, ...)
161 } // for (y = 0, ...)
164 inline static void blurVertical(QImage &image, unsigned int *stack, int div, int radius)
166 int stackindex;
167 int stackstart;
169 quint32 * const pixels = reinterpret_cast<quint32 *>(image.bits());
170 quint32 pixel;
172 int w = image.width();
173 int h = image.height();
174 int hm = h - 1;
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++)
183 sum = 0;
184 sum_in = 0;
185 sum_out = 0;
187 pixel = pixels[x];
188 for (int i = 0; i <= radius; i++)
190 stack[i] = qAlpha(pixel);
192 sum += stack[i] * (i + 1);
193 sum_out += stack[i];
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);
204 sum_in += *stackpix;
207 stackindex = radius;
208 for (int y = 0, i = x; y < h; y++, i += w)
210 pixels[i] = (((sum * mul_sum) >> shr_sum) << 24) & 0xff000000;
212 sum -= sum_out;
214 stackstart = stackindex + div - radius;
215 if (stackstart >= div)
216 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);
226 sum_in += *stackpix;
227 sum += sum_in;
229 if (++stackindex >= div)
230 stackindex = 0;
232 stackpix = &stack[stackindex];
234 sum_out += *stackpix;
235 sum_in -= *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);
250 delete [] stack;
253 void ImageFilter::shadowBlur(QImage &image, float radius, const QColor &color)
255 if (radius < 0)
256 return;
258 if (radius > 0)
259 stackBlur(image, radius);
261 // Correct the color and opacity of the shadow
262 QPainter p(&image);
263 p.setCompositionMode(QPainter::CompositionMode_SourceIn);
264 p.fillRect(image.rect(), color);
267 // kate: space-indent on; indent-width 4; replace-tabs on;