File indexing completed on 2024-12-08 03:40:43
0001 // krazy:excludeall=copyright (email of Maxim is missing) 0002 /* 0003 This file is a part of the KDE project 0004 0005 SPDX-FileCopyrightText: 2006 Zack Rusin <zack@kde.org> 0006 SPDX-FileCopyrightText: 2006-2007, 2008 Fredrik Höglund <fredrik@kde.org> 0007 0008 The stack blur algorithm was invented by Mario Klingemann <mario@quasimondo.com> 0009 0010 This implementation is based on the version in Anti-Grain Geometry Version 2.4, 0011 SPDX-FileCopyrightText: 2002-2005 Maxim Shemanarev <http://www.antigrain.com> 0012 0013 SPDX-License-Identifier: BSD-2-Clause 0014 */ 0015 0016 #include "imagefilter_p.h" 0017 0018 #include <QColor> 0019 #include <QImage> 0020 #include <QPainter> 0021 0022 #include <cmath> 0023 #include <string.h> 0024 0025 using namespace KIO; 0026 0027 static const quint32 stack_blur8_mul[255] = { 0028 512, 512, 456, 512, 328, 456, 335, 512, 405, 328, 271, 456, 388, 335, 292, 512, 454, 405, 364, 328, 298, 271, 496, 456, 420, 388, 360, 335, 312, 0029 292, 273, 512, 482, 454, 428, 405, 383, 364, 345, 328, 312, 298, 284, 271, 259, 496, 475, 456, 437, 420, 404, 388, 374, 360, 347, 335, 323, 312, 0030 302, 292, 282, 273, 265, 512, 497, 482, 468, 454, 441, 428, 417, 405, 394, 383, 373, 364, 354, 345, 337, 328, 320, 312, 305, 298, 291, 284, 278, 0031 271, 265, 259, 507, 496, 485, 475, 465, 456, 446, 437, 428, 420, 412, 404, 396, 388, 381, 374, 367, 360, 354, 347, 341, 335, 329, 323, 318, 312, 0032 307, 302, 297, 292, 287, 282, 278, 273, 269, 265, 261, 512, 505, 497, 489, 482, 475, 468, 461, 454, 447, 441, 435, 428, 422, 417, 411, 405, 399, 0033 394, 389, 383, 378, 373, 368, 364, 359, 354, 350, 345, 341, 337, 332, 328, 324, 320, 316, 312, 309, 305, 301, 298, 294, 291, 287, 284, 281, 278, 0034 274, 271, 268, 265, 262, 259, 257, 507, 501, 496, 491, 485, 480, 475, 470, 465, 460, 456, 451, 446, 442, 437, 433, 428, 424, 420, 416, 412, 408, 0035 404, 400, 396, 392, 388, 385, 381, 377, 374, 370, 367, 363, 360, 357, 354, 350, 347, 344, 341, 338, 335, 332, 329, 326, 323, 320, 318, 315, 312, 0036 310, 307, 304, 302, 299, 297, 294, 292, 289, 287, 285, 282, 280, 278, 275, 273, 271, 269, 267, 265, 263, 261, 259}; 0037 0038 static const quint32 stack_blur8_shr[255] = { 0039 9, 11, 12, 13, 13, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, 19, 19, 0040 19, 19, 19, 19, 19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 0041 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 0042 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 0043 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 0044 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 0045 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24}; 0046 0047 inline static void blurHorizontal(QImage &image, unsigned int *stack, int div, int radius) 0048 { 0049 quint32 *const pixels = reinterpret_cast<quint32 *>(image.bits()); 0050 quint32 pixel = 0; 0051 0052 const int width = image.width(); 0053 const int height = image.height(); 0054 const int wm = width - 1; 0055 0056 const unsigned int mul_sum = stack_blur8_mul[radius]; 0057 const unsigned int shr_sum = stack_blur8_shr[radius]; 0058 0059 for (int y = 0; y < height; y++) { 0060 unsigned int sum = 0; 0061 unsigned int sum_in = 0; 0062 unsigned int sum_out = 0; 0063 0064 const int yw = y * width; 0065 pixel = pixels[yw]; 0066 for (int i = 0; i <= radius; i++) { 0067 stack[i] = qAlpha(pixel); 0068 0069 sum += stack[i] * (i + 1); 0070 sum_out += stack[i]; 0071 } 0072 0073 for (int i = 1; i <= radius; i++) { 0074 pixel = pixels[yw + qMin(i, wm)]; 0075 0076 unsigned int *stackpix = &stack[i + radius]; 0077 *stackpix = qAlpha(pixel); 0078 0079 sum += *stackpix * (radius + 1 - i); 0080 sum_in += *stackpix; 0081 } 0082 0083 int stackindex = radius; 0084 for (int x = 0, i = yw; x < width; x++) { 0085 pixels[i++] = (((sum * mul_sum) >> shr_sum) << 24) & 0xff000000; 0086 0087 sum -= sum_out; 0088 0089 int stackstart = stackindex + div - radius; 0090 if (stackstart >= div) { 0091 stackstart -= div; 0092 } 0093 0094 unsigned int *stackpix = &stack[stackstart]; 0095 0096 sum_out -= *stackpix; 0097 0098 pixel = pixels[yw + qMin(x + radius + 1, wm)]; 0099 0100 *stackpix = qAlpha(pixel); 0101 0102 sum_in += *stackpix; 0103 sum += sum_in; 0104 0105 if (++stackindex >= div) { 0106 stackindex = 0; 0107 } 0108 0109 stackpix = &stack[stackindex]; 0110 0111 sum_out += *stackpix; 0112 sum_in -= *stackpix; 0113 } // for (x = 0, ...) 0114 } // for (y = 0, ...) 0115 } 0116 0117 inline static void blurVertical(QImage &image, unsigned int *stack, int div, int radius) 0118 { 0119 int stackindex; 0120 int stackstart; 0121 0122 quint32 *const pixels = reinterpret_cast<quint32 *>(image.bits()); 0123 quint32 pixel; 0124 0125 int w = image.width(); 0126 int h = image.height(); 0127 int hm = h - 1; 0128 0129 int mul_sum = stack_blur8_mul[radius]; 0130 int shr_sum = stack_blur8_shr[radius]; 0131 0132 unsigned int sum; 0133 unsigned int sum_in; 0134 unsigned int sum_out; 0135 0136 for (int x = 0; x < w; x++) { 0137 sum = 0; 0138 sum_in = 0; 0139 sum_out = 0; 0140 0141 pixel = pixels[x]; 0142 for (int i = 0; i <= radius; i++) { 0143 stack[i] = qAlpha(pixel); 0144 0145 sum += stack[i] * (i + 1); 0146 sum_out += stack[i]; 0147 } 0148 0149 for (int i = 1; i <= radius; i++) { 0150 pixel = pixels[qMin(i, hm) * w + x]; 0151 0152 unsigned int *stackpix = &stack[i + radius]; 0153 *stackpix = qAlpha(pixel); 0154 0155 sum += *stackpix * (radius + 1 - i); 0156 sum_in += *stackpix; 0157 } 0158 0159 stackindex = radius; 0160 for (int y = 0, i = x; y < h; y++, i += w) { 0161 pixels[i] = (((sum * mul_sum) >> shr_sum) << 24) & 0xff000000; 0162 0163 sum -= sum_out; 0164 0165 stackstart = stackindex + div - radius; 0166 if (stackstart >= div) { 0167 stackstart -= div; 0168 } 0169 0170 unsigned int *stackpix = &stack[stackstart]; 0171 0172 sum_out -= *stackpix; 0173 0174 pixel = pixels[qMin(y + radius + 1, hm) * w + x]; 0175 0176 *stackpix = qAlpha(pixel); 0177 0178 sum_in += *stackpix; 0179 sum += sum_in; 0180 0181 if (++stackindex >= div) { 0182 stackindex = 0; 0183 } 0184 0185 stackpix = &stack[stackindex]; 0186 0187 sum_out += *stackpix; 0188 sum_in -= *stackpix; 0189 } // for (y = 0, ...) 0190 } // for (x = 0, ...) 0191 } 0192 0193 static void stackBlur(QImage &image, float radius) 0194 { 0195 radius = qRound(radius); 0196 0197 int div = int(radius * 2) + 1; 0198 unsigned int *stack = new unsigned int[div]; 0199 0200 blurHorizontal(image, stack, div, radius); 0201 blurVertical(image, stack, div, radius); 0202 0203 delete[] stack; 0204 } 0205 0206 void ImageFilter::shadowBlur(QImage &image, float radius, const QColor &color) 0207 { 0208 if (radius < 0) { 0209 return; 0210 } 0211 0212 if (radius > 0) { 0213 stackBlur(image, radius); 0214 } 0215 0216 // Correct the color and opacity of the shadow 0217 QPainter p(&image); 0218 p.setCompositionMode(QPainter::CompositionMode_SourceIn); 0219 p.fillRect(image.rect(), color); 0220 }