File indexing completed on 2024-04-28 04:58:03
0001 // krazy:exclude=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.h" 0017 0018 #include <QColor> 0019 #include <QImage> 0020 #include <QPainter> 0021 0022 #include <cmath> 0023 #include <string.h> 0024 0025 static const quint32 stack_blur8_mul[255] = { 0026 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, 0027 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, 0028 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, 0029 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, 0030 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, 0031 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, 0032 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, 0033 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, 0034 310, 307, 304, 302, 299, 297, 294, 292, 289, 287, 285, 282, 280, 278, 275, 273, 271, 269, 267, 265, 263, 261, 259}; 0035 0036 static const quint32 stack_blur8_shr[255] = { 0037 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, 0038 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, 0039 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, 0040 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, 0041 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, 0042 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, 0043 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}; 0044 0045 inline static void blurHorizontal(QImage &image, unsigned int *stack, int div, int radius) 0046 { 0047 int stackindex; 0048 int stackstart; 0049 0050 quint32 *const pixels = reinterpret_cast<quint32 *>(image.bits()); 0051 quint32 pixel; 0052 0053 int w = image.width(); 0054 int h = image.height(); 0055 int wm = w - 1; 0056 0057 unsigned int mul_sum = stack_blur8_mul[radius]; 0058 unsigned int shr_sum = stack_blur8_shr[radius]; 0059 0060 unsigned int sum, sum_in, sum_out; 0061 0062 for (int y = 0; y < h; y++) { 0063 sum = 0; 0064 sum_in = 0; 0065 sum_out = 0; 0066 0067 const int yw = y * w; 0068 pixel = pixels[yw]; 0069 for (int i = 0; i <= radius; i++) { 0070 stack[i] = qAlpha(pixel); 0071 0072 sum += stack[i] * (i + 1); 0073 sum_out += stack[i]; 0074 } 0075 0076 for (int i = 1; i <= radius; i++) { 0077 pixel = pixels[yw + qMin(i, wm)]; 0078 0079 unsigned int *stackpix = &stack[i + radius]; 0080 *stackpix = qAlpha(pixel); 0081 0082 sum += *stackpix * (radius + 1 - i); 0083 sum_in += *stackpix; 0084 } 0085 0086 stackindex = radius; 0087 for (int x = 0, i = yw; x < w; x++) { 0088 pixels[i++] = (((sum * mul_sum) >> shr_sum) << 24) & 0xff000000; 0089 0090 sum -= sum_out; 0091 0092 stackstart = stackindex + div - radius; 0093 if (stackstart >= div) 0094 stackstart -= div; 0095 0096 unsigned int *stackpix = &stack[stackstart]; 0097 0098 sum_out -= *stackpix; 0099 0100 pixel = pixels[yw + qMin(x + radius + 1, wm)]; 0101 0102 *stackpix = qAlpha(pixel); 0103 0104 sum_in += *stackpix; 0105 sum += sum_in; 0106 0107 if (++stackindex >= div) 0108 stackindex = 0; 0109 0110 stackpix = &stack[stackindex]; 0111 0112 sum_out += *stackpix; 0113 sum_in -= *stackpix; 0114 } // for (x = 0, ...) 0115 } // for (y = 0, ...) 0116 } 0117 0118 inline static void blurVertical(QImage &image, unsigned int *stack, int div, int radius) 0119 { 0120 int stackindex; 0121 int stackstart; 0122 0123 quint32 *const pixels = reinterpret_cast<quint32 *>(image.bits()); 0124 quint32 pixel; 0125 0126 int w = image.width(); 0127 int h = image.height(); 0128 int hm = h - 1; 0129 0130 int mul_sum = stack_blur8_mul[radius]; 0131 int shr_sum = stack_blur8_shr[radius]; 0132 0133 unsigned int sum, sum_in, sum_out; 0134 0135 for (int x = 0; x < w; x++) { 0136 sum = 0; 0137 sum_in = 0; 0138 sum_out = 0; 0139 0140 pixel = pixels[x]; 0141 for (int i = 0; i <= radius; i++) { 0142 stack[i] = qAlpha(pixel); 0143 0144 sum += stack[i] * (i + 1); 0145 sum_out += stack[i]; 0146 } 0147 0148 for (int i = 1; i <= radius; i++) { 0149 pixel = pixels[qMin(i, hm) * w + x]; 0150 0151 unsigned int *stackpix = &stack[i + radius]; 0152 *stackpix = qAlpha(pixel); 0153 0154 sum += *stackpix * (radius + 1 - i); 0155 sum_in += *stackpix; 0156 } 0157 0158 stackindex = radius; 0159 for (int y = 0, i = x; y < h; y++, i += w) { 0160 pixels[i] = (((sum * mul_sum) >> shr_sum) << 24) & 0xff000000; 0161 0162 sum -= sum_out; 0163 0164 stackstart = stackindex + div - radius; 0165 if (stackstart >= div) 0166 stackstart -= div; 0167 0168 unsigned int *stackpix = &stack[stackstart]; 0169 0170 sum_out -= *stackpix; 0171 0172 pixel = pixels[qMin(y + radius + 1, hm) * w + x]; 0173 0174 *stackpix = qAlpha(pixel); 0175 0176 sum_in += *stackpix; 0177 sum += sum_in; 0178 0179 if (++stackindex >= div) 0180 stackindex = 0; 0181 0182 stackpix = &stack[stackindex]; 0183 0184 sum_out += *stackpix; 0185 sum_in -= *stackpix; 0186 } // for (y = 0, ...) 0187 } // for (x = 0, ...) 0188 } 0189 0190 static void stackBlur(QImage &image, float radius) 0191 { 0192 radius = qRound(radius); 0193 0194 int div = int(radius * 2) + 1; 0195 unsigned int *stack = new unsigned int[div]; 0196 0197 blurHorizontal(image, stack, div, radius); 0198 blurVertical(image, stack, div, radius); 0199 0200 delete[] stack; 0201 } 0202 0203 void ImageFilter::shadowBlur(QImage &image, float radius, const QColor &color) 0204 { 0205 if (radius < 0) 0206 return; 0207 0208 if (radius > 0) 0209 stackBlur(image, radius); 0210 0211 // Correct the color and opacity of the shadow 0212 QPainter p(&image); 0213 p.setCompositionMode(QPainter::CompositionMode_SourceIn); 0214 p.fillRect(image.rect(), color); 0215 } 0216 0217 // kate: space-indent on; indent-width 4; replace-tabs on;