File indexing completed on 2024-11-17 04:17:25

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