1#ifndef BLUR_CPP
2#define BLUR_CPP
3
4/*
5 * Copyright 2007 Jani Huhtanen <jani.huhtanen@tut.fi>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU Library General Public License version 2 as
9 * published by the Free Software Foundation
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details
15 *
16 * You should have received a copy of the GNU Library General Public
17 * License along with this program; if not, write to the
18 * Free Software Foundation, Inc.,
19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 */
21
22#include <cmath>
23
24#include <QImage>
25
26// Exponential blur, Jani Huhtanen, 2006
27//
28template<int aprec, int zprec>
29static inline void blurinner(unsigned char *bptr, int &zR, int &zG, int &zB, int &zA, int alpha);
30
31template<int aprec,int zprec>
32static inline void blurrow(QImage &im, int line, int alpha);
33
34template<int aprec, int zprec>
35static inline void blurcol(QImage &im, int col, int alpha);
36
37/*
38* expblur(QImage &img, int radius)
39*
40* In-place blur of image 'img' with kernel
41* of approximate radius 'radius'.
42*
43* Blurs with two sided exponential impulse
44* response.
45*
46* aprec = precision of alpha parameter
47* in fixed-point format 0.aprec
48*
49* zprec = precision of state parameters
50* zR,zG,zB and zA in fp format 8.zprec
51*/
52template<int aprec,int zprec>
53void expblur(QImage &img, int radius)
54{
55 if (radius < 1) {
56 return;
57 }
58
59 img = img.convertToFormat(QImage::Format_ARGB32_Premultiplied);
60
61 /* Calculate the alpha such that 90% of
62 the kernel is within the radius.
63 (Kernel extends to infinity)
64 */
65 int alpha = (int)((1 << aprec) * (1.0f - std::exp(-2.3f / (radius + 1.f))));
66
67 int height = img.height();
68 int width = img.width();
69 for (int row=0; row<height; row++) {
70 blurrow<aprec,zprec>(img, row, alpha);
71 }
72
73 for (int col=0; col<width; col++) {
74 blurcol<aprec,zprec>(img, col, alpha);
75 }
76 return;
77}
78
79template<int aprec, int zprec>
80static inline void blurinner(unsigned char *bptr, int &zR, int &zG, int &zB, int &zA, int alpha)
81{
82 int R, G, B, A;
83 R = *bptr;
84 G = *(bptr + 1);
85 B = *(bptr + 2);
86 A = *(bptr + 3);
87
88 zR += (alpha * ((R << zprec) - zR)) >> aprec;
89 zG += (alpha * ((G << zprec) - zG)) >> aprec;
90 zB += (alpha * ((B << zprec) - zB)) >> aprec;
91 zA += (alpha * ((A << zprec) - zA)) >> aprec;
92
93 *bptr = zR >> zprec;
94 *(bptr+1) = zG >> zprec;
95 *(bptr+2) = zB >> zprec;
96 *(bptr+3) = zA >> zprec;
97}
98
99template<int aprec,int zprec>
100static inline void blurrow(QImage &im, int line, int alpha)
101{
102 int zR, zG, zB, zA;
103
104 QRgb *ptr = (QRgb *)im.scanLine(line);
105 int width = im.width();
106
107 zR = *((unsigned char *)ptr ) << zprec;
108 zG = *((unsigned char *)ptr + 1) << zprec;
109 zB = *((unsigned char *)ptr + 2) << zprec;
110 zA = *((unsigned char *)ptr + 3) << zprec;
111
112 for (int index=1; index<width; index++) {
113 blurinner<aprec,zprec>((unsigned char *)&ptr[index],zR,zG,zB,zA,alpha);
114 }
115 for (int index=width-2; index>=0; index--) {
116 blurinner<aprec,zprec>((unsigned char *)&ptr[index],zR,zG,zB,zA,alpha);
117 }
118}
119
120template<int aprec, int zprec>
121static inline void blurcol(QImage &im, int col, int alpha)
122{
123 int zR, zG, zB, zA;
124
125 QRgb *ptr = (QRgb *)im.bits();
126 ptr += col;
127 int height = im.height();
128 int width = im.width();
129
130 zR = *((unsigned char *)ptr ) << zprec;
131 zG = *((unsigned char *)ptr + 1) << zprec;
132 zB = *((unsigned char *)ptr + 2) << zprec;
133 zA = *((unsigned char *)ptr + 3) << zprec;
134
135 for (int index=width; index<(height-1)*width; index+=width) {
136 blurinner<aprec,zprec>((unsigned char *)&ptr[index], zR, zG, zB, zA, alpha);
137 }
138
139 for (int index=(height-2)*width; index>=0; index-=width) {
140 blurinner<aprec,zprec>((unsigned char *)&ptr[index], zR, zG, zB, zA, alpha);
141 }
142}
143
144template<class T>
145inline const T &qClamp(const T &x, const T &low, const T &high)
146{
147 if (x < low) {
148 return low;
149 } else if (x > high) {
150 return high;
151 } else {
152 return x;
153 }
154}
155
156#endif
157