KIO
imagefilter.cpp
Go to the documentation of this file.
00001 //krazy:exclude=copyright (email of Maxim is missing) 00002 /* 00003 This file is a part of the KDE project 00004 00005 Copyright © 2006 Zack Rusin <zack@kde.org> 00006 Copyright © 2006-2007, 2008 Fredrik Höglund <fredrik@kde.org> 00007 00008 The stack blur algorithm was invented by Mario Klingemann <mario@quasimondo.com> 00009 00010 This implementation is based on the version in Anti-Grain Geometry Version 2.4, 00011 Copyright © 2002-2005 Maxim Shemanarev (http://www.antigrain.com) 00012 00013 Redistribution and use in source and binary forms, with or without 00014 modification, are permitted provided that the following conditions 00015 are met: 00016 00017 1. Redistributions of source code must retain the above copyright 00018 notice, this list of conditions and the following disclaimer. 00019 2. Redistributions in binary form must reproduce the above copyright 00020 notice, this list of conditions and the following disclaimer in the 00021 documentation and/or other materials provided with the distribution. 00022 00023 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 00024 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 00025 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 00026 IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 00027 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 00028 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 00029 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 00030 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 00031 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 00032 THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 00033 */ 00034 00035 #include "imagefilter_p.h" 00036 00037 #include <QPainter> 00038 #include <QImage> 00039 #include <QColor> 00040 #include <QDebug> 00041 00042 #include <cmath> 00043 #include <string.h> 00044 00045 using namespace KIO; 00046 00047 static const quint32 stack_blur8_mul[255] = 00048 { 00049 512,512,456,512,328,456,335,512,405,328,271,456,388,335,292,512, 00050 454,405,364,328,298,271,496,456,420,388,360,335,312,292,273,512, 00051 482,454,428,405,383,364,345,328,312,298,284,271,259,496,475,456, 00052 437,420,404,388,374,360,347,335,323,312,302,292,282,273,265,512, 00053 497,482,468,454,441,428,417,405,394,383,373,364,354,345,337,328, 00054 320,312,305,298,291,284,278,271,265,259,507,496,485,475,465,456, 00055 446,437,428,420,412,404,396,388,381,374,367,360,354,347,341,335, 00056 329,323,318,312,307,302,297,292,287,282,278,273,269,265,261,512, 00057 505,497,489,482,475,468,461,454,447,441,435,428,422,417,411,405, 00058 399,394,389,383,378,373,368,364,359,354,350,345,341,337,332,328, 00059 324,320,316,312,309,305,301,298,294,291,287,284,281,278,274,271, 00060 268,265,262,259,257,507,501,496,491,485,480,475,470,465,460,456, 00061 451,446,442,437,433,428,424,420,416,412,408,404,400,396,392,388, 00062 385,381,377,374,370,367,363,360,357,354,350,347,344,341,338,335, 00063 332,329,326,323,320,318,315,312,310,307,304,302,299,297,294,292, 00064 289,287,285,282,280,278,275,273,271,269,267,265,263,261,259 00065 }; 00066 00067 static const quint32 stack_blur8_shr[255] = 00068 { 00069 9, 11, 12, 13, 13, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 17, 00070 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 18, 19, 00071 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 20, 20, 20, 00072 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 21, 00073 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 00074 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 00075 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 00076 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 00077 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 00078 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 00079 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 00080 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 00081 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 00082 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 00083 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 00084 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24 00085 }; 00086 00087 inline static void blurHorizontal(QImage &image, unsigned int *stack, int div, int radius) 00088 { 00089 int stackindex; 00090 int stackstart; 00091 00092 quint32 * const pixels = reinterpret_cast<quint32 *>(image.bits()); 00093 quint32 pixel; 00094 00095 int w = image.width(); 00096 int h = image.height(); 00097 int wm = w - 1; 00098 00099 unsigned int mul_sum = stack_blur8_mul[radius]; 00100 unsigned int shr_sum = stack_blur8_shr[radius]; 00101 00102 unsigned int sum, sum_in, sum_out; 00103 00104 for (int y = 0; y < h; y++) 00105 { 00106 sum = 0; 00107 sum_in = 0; 00108 sum_out = 0; 00109 00110 const int yw = y * w; 00111 pixel = pixels[yw]; 00112 for (int i = 0; i <= radius; i++) 00113 { 00114 stack[i] = qAlpha(pixel); 00115 00116 sum += stack[i] * (i + 1); 00117 sum_out += stack[i]; 00118 } 00119 00120 for (int i = 1; i <= radius; i++) 00121 { 00122 pixel = pixels[yw + qMin(i, wm)]; 00123 00124 unsigned int *stackpix = &stack[i + radius]; 00125 *stackpix = qAlpha(pixel); 00126 00127 sum += *stackpix * (radius + 1 - i); 00128 sum_in += *stackpix; 00129 } 00130 00131 stackindex = radius; 00132 for (int x = 0, i = yw; x < w; x++) 00133 { 00134 pixels[i++] = (((sum * mul_sum) >> shr_sum) << 24) & 0xff000000; 00135 00136 sum -= sum_out; 00137 00138 stackstart = stackindex + div - radius; 00139 if (stackstart >= div) 00140 stackstart -= div; 00141 00142 unsigned int *stackpix = &stack[stackstart]; 00143 00144 sum_out -= *stackpix; 00145 00146 pixel = pixels[yw + qMin(x + radius + 1, wm)]; 00147 00148 *stackpix = qAlpha(pixel); 00149 00150 sum_in += *stackpix; 00151 sum += sum_in; 00152 00153 if (++stackindex >= div) 00154 stackindex = 0; 00155 00156 stackpix = &stack[stackindex]; 00157 00158 sum_out += *stackpix; 00159 sum_in -= *stackpix; 00160 } // for (x = 0, ...) 00161 } // for (y = 0, ...) 00162 } 00163 00164 inline static void blurVertical(QImage &image, unsigned int *stack, int div, int radius) 00165 { 00166 int stackindex; 00167 int stackstart; 00168 00169 quint32 * const pixels = reinterpret_cast<quint32 *>(image.bits()); 00170 quint32 pixel; 00171 00172 int w = image.width(); 00173 int h = image.height(); 00174 int hm = h - 1; 00175 00176 int mul_sum = stack_blur8_mul[radius]; 00177 int shr_sum = stack_blur8_shr[radius]; 00178 00179 unsigned int sum, sum_in, sum_out; 00180 00181 for (int x = 0; x < w; x++) 00182 { 00183 sum = 0; 00184 sum_in = 0; 00185 sum_out = 0; 00186 00187 pixel = pixels[x]; 00188 for (int i = 0; i <= radius; i++) 00189 { 00190 stack[i] = qAlpha(pixel); 00191 00192 sum += stack[i] * (i + 1); 00193 sum_out += stack[i]; 00194 } 00195 00196 for (int i = 1; i <= radius; i++) 00197 { 00198 pixel = pixels[qMin(i, hm) * w + x]; 00199 00200 unsigned int *stackpix = &stack[i + radius]; 00201 *stackpix = qAlpha(pixel); 00202 00203 sum += *stackpix * (radius + 1 - i); 00204 sum_in += *stackpix; 00205 } 00206 00207 stackindex = radius; 00208 for (int y = 0, i = x; y < h; y++, i += w) 00209 { 00210 pixels[i] = (((sum * mul_sum) >> shr_sum) << 24) & 0xff000000; 00211 00212 sum -= sum_out; 00213 00214 stackstart = stackindex + div - radius; 00215 if (stackstart >= div) 00216 stackstart -= div; 00217 00218 unsigned int *stackpix = &stack[stackstart]; 00219 00220 sum_out -= *stackpix; 00221 00222 pixel = pixels[qMin(y + radius + 1, hm) * w + x]; 00223 00224 *stackpix = qAlpha(pixel); 00225 00226 sum_in += *stackpix; 00227 sum += sum_in; 00228 00229 if (++stackindex >= div) 00230 stackindex = 0; 00231 00232 stackpix = &stack[stackindex]; 00233 00234 sum_out += *stackpix; 00235 sum_in -= *stackpix; 00236 } // for (y = 0, ...) 00237 } // for (x = 0, ...) 00238 } 00239 00240 static void stackBlur(QImage &image, float radius) 00241 { 00242 radius = qRound(radius); 00243 00244 int div = int(radius * 2) + 1; 00245 unsigned int *stack = new unsigned int[div]; 00246 00247 blurHorizontal(image, stack, div, radius); 00248 blurVertical(image, stack, div, radius); 00249 00250 delete [] stack; 00251 } 00252 00253 void ImageFilter::shadowBlur(QImage &image, float radius, const QColor &color) 00254 { 00255 if (radius < 0) 00256 return; 00257 00258 if (radius > 0) 00259 stackBlur(image, radius); 00260 00261 // Correct the color and opacity of the shadow 00262 QPainter p(&image); 00263 p.setCompositionMode(QPainter::CompositionMode_SourceIn); 00264 p.fillRect(image.rect(), color); 00265 } 00266 00267 // kate: space-indent on; indent-width 4; replace-tabs on;
KDE 4.6 API Reference