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;