File indexing completed on 2024-10-06 09:37:32
0001 /* 0002 This file is a part of the KDE project 0003 0004 Copyright © 2006 Zack Rusin <zack@kde.org> 0005 Copyright © 2006-2007, 2008 Fredrik Höglund <fredrik@kde.org> 0006 0007 The stack blur algorithm was invented by Mario Klingemann <mario@quasimondo.com> 0008 0009 This implementation is based on the version in Anti-Grain Geometry Version 2.4, 0010 Copyright © 2002-2005 Maxim Shemanarev (http://www.antigrain.com) 0011 0012 Redistribution and use in source and binary forms, with or without 0013 modification, are permitted provided that the following conditions 0014 are met: 0015 0016 1. Redistributions of source code must retain the above copyright 0017 notice, this list of conditions and the following disclaimer. 0018 2. Redistributions in binary form must reproduce the above copyright 0019 notice, this list of conditions and the following disclaimer in the 0020 documentation and/or other materials provided with the distribution. 0021 0022 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 0023 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 0024 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 0025 IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 0026 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 0027 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 0028 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 0029 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 0030 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 0031 THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 0032 */ 0033 0034 #include <QPainter> 0035 #include <QImage> 0036 #include <QColor> 0037 #include "khtml_debug.h" 0038 0039 #include <cmath> 0040 #include <string.h> 0041 0042 #include "imagefilter.h" 0043 0044 using namespace khtml; 0045 0046 static const quint32 stack_blur8_mul[255] = { 0047 512, 512, 456, 512, 328, 456, 335, 512, 405, 328, 271, 456, 388, 335, 292, 512, 0048 454, 405, 364, 328, 298, 271, 496, 456, 420, 388, 360, 335, 312, 292, 273, 512, 0049 482, 454, 428, 405, 383, 364, 345, 328, 312, 298, 284, 271, 259, 496, 475, 456, 0050 437, 420, 404, 388, 374, 360, 347, 335, 323, 312, 302, 292, 282, 273, 265, 512, 0051 497, 482, 468, 454, 441, 428, 417, 405, 394, 383, 373, 364, 354, 345, 337, 328, 0052 320, 312, 305, 298, 291, 284, 278, 271, 265, 259, 507, 496, 485, 475, 465, 456, 0053 446, 437, 428, 420, 412, 404, 396, 388, 381, 374, 367, 360, 354, 347, 341, 335, 0054 329, 323, 318, 312, 307, 302, 297, 292, 287, 282, 278, 273, 269, 265, 261, 512, 0055 505, 497, 489, 482, 475, 468, 461, 454, 447, 441, 435, 428, 422, 417, 411, 405, 0056 399, 394, 389, 383, 378, 373, 368, 364, 359, 354, 350, 345, 341, 337, 332, 328, 0057 324, 320, 316, 312, 309, 305, 301, 298, 294, 291, 287, 284, 281, 278, 274, 271, 0058 268, 265, 262, 259, 257, 507, 501, 496, 491, 485, 480, 475, 470, 465, 460, 456, 0059 451, 446, 442, 437, 433, 428, 424, 420, 416, 412, 408, 404, 400, 396, 392, 388, 0060 385, 381, 377, 374, 370, 367, 363, 360, 357, 354, 350, 347, 344, 341, 338, 335, 0061 332, 329, 326, 323, 320, 318, 315, 312, 310, 307, 304, 302, 299, 297, 294, 292, 0062 289, 287, 285, 282, 280, 278, 275, 273, 271, 269, 267, 265, 263, 261, 259 0063 }; 0064 0065 static const quint32 stack_blur8_shr[255] = { 0066 9, 11, 12, 13, 13, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 17, 0067 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 18, 19, 0068 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 20, 20, 20, 0069 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 21, 0070 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 0071 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 0072 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 0073 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 0074 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 0075 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 0076 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 0077 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 0078 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 0079 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 0080 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 0081 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24 0082 }; 0083 0084 inline static void blurHorizontal(QImage &image, unsigned int *stack, int div, int radius) 0085 { 0086 int stackindex; 0087 int stackstart; 0088 0089 quint32 *const pixels = reinterpret_cast<quint32 *>(image.bits()); 0090 quint32 pixel; 0091 0092 int w = image.width(); 0093 int h = image.height(); 0094 int wm = w - 1; 0095 0096 unsigned int mul_sum = stack_blur8_mul[radius]; 0097 unsigned int shr_sum = stack_blur8_shr[radius]; 0098 0099 unsigned int sum, sum_in, sum_out; 0100 0101 for (int y = 0; y < h; y++) { 0102 sum = 0; 0103 sum_in = 0; 0104 sum_out = 0; 0105 0106 const int yw = y * w; 0107 pixel = pixels[yw]; 0108 for (int i = 0; i <= radius; i++) { 0109 stack[i] = qAlpha(pixel); 0110 0111 sum += stack[i] * (i + 1); 0112 sum_out += stack[i]; 0113 } 0114 0115 for (int i = 1; i <= radius; i++) { 0116 pixel = pixels[yw + qMin(i, wm)]; 0117 0118 unsigned int *stackpix = &stack[i + radius]; 0119 *stackpix = qAlpha(pixel); 0120 0121 sum += *stackpix * (radius + 1 - i); 0122 sum_in += *stackpix; 0123 } 0124 0125 stackindex = radius; 0126 for (int x = 0, i = yw; x < w; x++) { 0127 pixels[i++] = (((sum * mul_sum) >> shr_sum) << 24) & 0xff000000; 0128 0129 sum -= sum_out; 0130 0131 stackstart = stackindex + div - radius; 0132 if (stackstart >= div) { 0133 stackstart -= div; 0134 } 0135 0136 unsigned int *stackpix = &stack[stackstart]; 0137 0138 sum_out -= *stackpix; 0139 0140 pixel = pixels[yw + qMin(x + radius + 1, wm)]; 0141 0142 *stackpix = qAlpha(pixel); 0143 0144 sum_in += *stackpix; 0145 sum += sum_in; 0146 0147 if (++stackindex >= div) { 0148 stackindex = 0; 0149 } 0150 0151 stackpix = &stack[stackindex]; 0152 0153 sum_out += *stackpix; 0154 sum_in -= *stackpix; 0155 } // for (x = 0, ...) 0156 } // for (y = 0, ...) 0157 } 0158 0159 inline static void blurVertical(QImage &image, unsigned int *stack, int div, int radius) 0160 { 0161 int stackindex; 0162 int stackstart; 0163 0164 quint32 *const pixels = reinterpret_cast<quint32 *>(image.bits()); 0165 quint32 pixel; 0166 0167 int w = image.width(); 0168 int h = image.height(); 0169 int hm = h - 1; 0170 0171 int mul_sum = stack_blur8_mul[radius]; 0172 int shr_sum = stack_blur8_shr[radius]; 0173 0174 unsigned int sum, sum_in, sum_out; 0175 0176 for (int x = 0; x < w; x++) { 0177 sum = 0; 0178 sum_in = 0; 0179 sum_out = 0; 0180 0181 pixel = pixels[x]; 0182 for (int i = 0; i <= radius; i++) { 0183 stack[i] = qAlpha(pixel); 0184 0185 sum += stack[i] * (i + 1); 0186 sum_out += stack[i]; 0187 } 0188 0189 for (int i = 1; i <= radius; i++) { 0190 pixel = pixels[qMin(i, hm) * w + x]; 0191 0192 unsigned int *stackpix = &stack[i + radius]; 0193 *stackpix = qAlpha(pixel); 0194 0195 sum += *stackpix * (radius + 1 - i); 0196 sum_in += *stackpix; 0197 } 0198 0199 stackindex = radius; 0200 for (int y = 0, i = x; y < h; y++, i += w) { 0201 pixels[i] = (((sum * mul_sum) >> shr_sum) << 24) & 0xff000000; 0202 0203 sum -= sum_out; 0204 0205 stackstart = stackindex + div - radius; 0206 if (stackstart >= div) { 0207 stackstart -= div; 0208 } 0209 0210 unsigned int *stackpix = &stack[stackstart]; 0211 0212 sum_out -= *stackpix; 0213 0214 pixel = pixels[qMin(y + radius + 1, hm) * w + x]; 0215 0216 *stackpix = qAlpha(pixel); 0217 0218 sum_in += *stackpix; 0219 sum += sum_in; 0220 0221 if (++stackindex >= div) { 0222 stackindex = 0; 0223 } 0224 0225 stackpix = &stack[stackindex]; 0226 0227 sum_out += *stackpix; 0228 sum_in -= *stackpix; 0229 } // for (y = 0, ...) 0230 } // for (x = 0, ...) 0231 } 0232 0233 static void stackBlur(QImage &image, float radius) 0234 { 0235 radius = qRound(radius); 0236 0237 int div = int(radius * 2) + 1; 0238 unsigned int *stack = new unsigned int[div]; 0239 0240 blurHorizontal(image, stack, div, radius); 0241 blurVertical(image, stack, div, radius); 0242 0243 delete [] stack; 0244 } 0245 0246 void ImageFilter::shadowBlur(QImage &image, float radius, const QColor &color) 0247 { 0248 if (radius < 0) { 0249 return; 0250 } 0251 0252 if (radius > 0) { 0253 stackBlur(image, radius); 0254 } 0255 0256 // Correct the color and opacity of the shadow 0257 QPainter p(&image); 0258 p.setCompositionMode(QPainter::CompositionMode_SourceIn); 0259 p.fillRect(image.rect(), color); 0260 } 0261