2 Copyright (c) 2006 Maurizio Monge <maurizio.monge@kdemail.net>
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 Part of the code been contributed by Jani Huhtanen.
10 Copyright (c) 2006 Jani Huhtanen.
17 #include "imageeffects.h"
19 template<int aprec
, int zprec
>
20 static inline void blurinner(unsigned char *bptr
, int &zR
,
21 int &zG
, int &zB
, int &zA
, int alpha
);
23 template<int aprec
,int zprec
>
24 static inline void blurrow(QImage
& im
, int line
, int alpha
);
26 template<int aprec
, int zprec
>
27 static inline void blurcol(QImage
& im
, int col
, int alpha
);
30 * expblur(QImage &img, int radius)
32 * In-place blur of image 'img' with kernel
33 * of approximate radius 'radius'.
35 * Blurs with two sided exponential impulse
38 * aprec = precision of alpha parameter
39 * in fixed-point format 0.aprec
41 * zprec = precision of state parameters
42 * zR,zG,zB and zA in fp format 8.zprec
44 template<int aprec
,int zprec
>
45 static void expblur(QImage
&img
, int radius
)
50 /* Calculate the alpha such that 90% of
51 the kernel is within the radius.
52 (Kernel extends to infinity)
54 int alpha
= (int)((1<<aprec
)*(1.0f
-expf(-2.3f
/(radius
+1.f
))));
56 for(int row
=0;row
<img
.height();row
++) {
57 blurrow
<aprec
,zprec
>(img
,row
,alpha
);
60 for(int col
=0;col
<img
.width();col
++) {
61 blurcol
<aprec
,zprec
>(img
,col
,alpha
);
66 template<int aprec
, int zprec
>
67 static inline void blurinner(unsigned char *bptr
,
68 int &zR
, int &zG
, int &zB
, int &zA
, int alpha
)
76 zR
+= (alpha
* ((R
<<zprec
)-zR
))>>aprec
;
77 zG
+= (alpha
* ((G
<<zprec
)-zG
))>>aprec
;
78 zB
+= (alpha
* ((B
<<zprec
)-zB
))>>aprec
;
79 zA
+= (alpha
* ((A
<<zprec
)-zA
))>>aprec
;
82 *(bptr
+1) = zG
>>zprec
;
83 *(bptr
+2) = zB
>>zprec
;
84 *(bptr
+3) = zA
>>zprec
;
87 template<int aprec
,int zprec
>
88 static inline void blurrow( QImage
& im
, int line
, int alpha
)
92 QRgb
*ptr
= (QRgb
*)im
.scanLine(line
);
94 zR
= *((unsigned char *)ptr
)<<zprec
;
95 zG
= *((unsigned char *)ptr
+ 1)<<zprec
;
96 zB
= *((unsigned char *)ptr
+ 2)<<zprec
;
97 zA
= *((unsigned char *)ptr
+ 3)<<zprec
;
99 for(int index
=1; index
<im
.width(); index
++) {
100 blurinner
<aprec
,zprec
>((unsigned char *)&ptr
[index
],
101 zR
, zG
, zB
, zA
, alpha
);
103 for(int index
=im
.width()-2; index
>=0; index
--) {
104 blurinner
<aprec
,zprec
>((unsigned char *)&ptr
[index
],
105 zR
, zG
, zB
, zA
, alpha
);
111 template<int aprec
, int zprec
>
112 static inline void blurcol(QImage
& im
, int col
, int alpha
)
116 QRgb
*ptr
= (QRgb
*)im
.bits();
119 zR
= *((unsigned char *)ptr
)<<zprec
;
120 zG
= *((unsigned char *)ptr
+ 1)<<zprec
;
121 zB
= *((unsigned char *)ptr
+ 2)<<zprec
;
122 zA
= *((unsigned char *)ptr
+ 3)<<zprec
;
124 for(int index
=im
.width(); index
<(im
.height()-1)*im
.width();
126 blurinner
<aprec
,zprec
>((unsigned char *)&ptr
[index
],
127 zR
, zG
, zB
, zA
, alpha
);
130 for(int index
=(im
.height()-2)*im
.width(); index
>=0;
132 blurinner
<aprec
,zprec
>((unsigned char *)&ptr
[index
],
133 zR
, zG
, zB
, zA
, alpha
);
138 namespace ImageEffects
{
142 void expblur_sse( QImage
&img
, int radius
);
143 #endif //HAVE_X86_SSE2
147 void expblur_mmx( QImage
&img
, int radius
);
148 #endif //HAVE_X86_MMX
152 void expBlur(QImage
& img
, int radius
) {
154 //KCPUInfo:: returns false on x86_64, and x86_64 always have sse/mmx
157 if(BlitzCPUInfo::haveExtension( BlitzCPUInfo::SSE2
) )
159 return expblur_sse(img
, radius
);
160 #endif //HAVE_X86_SSE2
164 if(BlitzCPUInfo::haveExtension( BlitzCPUInfo::MMX
) )
166 return expblur_mmx(img
, radius
);
167 #endif //HAVE_X86_MMX
169 return expblur
<15,7>(img
, radius
);
172 QImage
addShadow(const QImage
& image
, int r
, QColor color
,
173 int offx
, int offy
, int growx
, int growy
) {
175 QImage
retv(image
.width()+growx
, image
.height()+growy
, QImage::Format_ARGB32_Premultiplied
);
176 int dx
= (growx
-offx
)/2, dy
= (growy
-offy
)/2;
179 p
.setCompositionMode(QPainter::CompositionMode_Source
);
180 p
.fillRect(0,0,retv
.width(), retv
.height(), QColor(0,0,0,0));
181 p
.fillRect(dx
+offx
, dy
+offy
, image
.width(), image
.height(), color
);
182 p
.setCompositionMode(QPainter::CompositionMode_DestinationAtop
);
183 p
.drawImage(dx
+offx
, dy
+offy
, image
);
189 p
.drawImage(dx
, dy
, image
);
195 QImage
growBorder(const QImage
& image
) {
196 int w
= image
.width();
197 int h
= image
.height();
199 QImage
retv(w
+2, h
+2, QImage::Format_ARGB32_Premultiplied
);
202 p
.setCompositionMode(QPainter::CompositionMode_Source
);
203 p
.drawImage(0, 0, image
, 0, 0, 1, 1);
204 p
.drawImage(w
+1, 0, image
, w
-1, 0, 1, 1);
205 p
.drawImage(0, h
+1, image
, 0, h
-1, 1, 1);
206 p
.drawImage(w
+1, h
+1, image
, w
-1, h
-1, 1, 1);
207 p
.drawImage(1, 0, image
, 0, 0, w
, 1);
208 p
.drawImage(1, h
+1, image
, 0, h
-1, w
, 1);
209 p
.drawImage(0, 1, image
, 0, 0, 1, h
);
210 p
.drawImage(w
+1, 1, image
, w
-1, 0, 1, h
);
211 p
.drawImage(1, 1, image
);
220 Line(int _y
, int _x1
, int _x2
)
221 : y(_y
), x1(_x1
), x2(_x2
) {}
224 void floodFill(QImage
& image
, QPoint point
, QColor color
,
225 bool invade_border
, std::vector
<QPoint
>* border
) {
227 int* ptr
= (int*)image
.bits();
228 int h
= image
.height();
229 int w
= image
.width();
230 int newcol
= color
.rgba();
231 int oldcol
= ptr
[point
.x()+point
.y()*w
];
232 std::vector
<Line
> lines
;
235 Line
l(point
.y(), point
.x(), point
.x()+1);
236 int *scanline
= ptr
+point
.y()*w
;
237 scanline
[l
.x1
] = newcol
;
238 while(l
.x1
> 0 && scanline
[l
.x1
-1] == oldcol
)
239 scanline
[--l
.x1
] = newcol
;
240 while(l
.x2
< w
&& scanline
[l
.x2
] == oldcol
)
241 scanline
[l
.x2
++] = newcol
;
245 while(!lines
.empty()) {
246 Line ll
= lines
.back();
251 ptr
[ll
.y
*w
+ ll
.x1
- 1] = newcol
;
253 border
->push_back(QPoint(ll
.x1
-1, ll
.y
));
257 ptr
[ll
.y
*w
+ ll
.x2
] = newcol
;
259 border
->push_back(QPoint(ll
.x2
, ll
.y
));
262 for(int d
=-1; d
<=1; d
+=2)
263 if( (d
== -1) ? (ll
.y
> 0) : (ll
.y
< h
-1) ) {
264 int *scanline
= ptr
+ (ll
.y
+d
)*w
;
266 for(int i
=ll
.x1
;i
<ll
.x2
;i
++){
267 if(scanline
[i
]==oldcol
) {
268 Line
l(ll
.y
+d
, i
, i
+1);
270 scanline
[l
.x1
] = newcol
;
271 while(l
.x1
> 0 && scanline
[l
.x1
-1] == oldcol
)
272 scanline
[--l
.x1
] = newcol
;
273 while(l
.x2
< w
&& scanline
[l
.x2
] == oldcol
)
274 scanline
[l
.x2
++] = newcol
;
278 if(i
<ll
.x2
&& scanline
[i
]!=newcol
) {
282 border
->push_back(QPoint(i
, ll
.y
+d
));
289 void floodFillBlueThreshold(QImage
& image
, QPoint point
, QColor color
, unsigned int thresh
,
290 bool invade_border
, std::vector
<QPoint
>* border
) {
292 unsigned int* ptr
= (unsigned int*)image
.bits();
293 int h
= image
.height();
294 int w
= image
.width();
295 unsigned int newcol
= color
.rgba();
296 std::vector
<Line
> lines
;
298 #define TEST(x) ((((x) & 0xff) < thresh) && ((x) != newcol))
300 Line
l(point
.y(), point
.x(), point
.x()+1);
301 unsigned int *scanline
= ptr
+point
.y()*w
;
302 scanline
[l
.x1
] = newcol
;
303 while(l
.x1
> 0 && TEST(scanline
[l
.x1
-1]))
304 scanline
[--l
.x1
] = newcol
;
305 while(l
.x2
< w
&& TEST(scanline
[l
.x2
]))
306 scanline
[l
.x2
++] = newcol
;
310 while(!lines
.empty()) {
311 Line ll
= lines
.back();
316 ptr
[ll
.y
*w
+ ll
.x1
- 1] = newcol
;
318 border
->push_back(QPoint(ll
.x1
-1, ll
.y
));
322 ptr
[ll
.y
*w
+ ll
.x2
] = newcol
;
324 border
->push_back(QPoint(ll
.x2
, ll
.y
));
327 for(int d
=-1; d
<=1; d
+=2)
328 if( (d
== -1) ? (ll
.y
> 0) : (ll
.y
< h
-1) ) {
329 unsigned int *scanline
= ptr
+ (ll
.y
+d
)*w
;
331 for(int i
=ll
.x1
;i
<ll
.x2
;i
++){
332 if(TEST(scanline
[i
])) {
333 Line
l(ll
.y
+d
, i
, i
+1);
335 scanline
[l
.x1
] = newcol
;
336 while(l
.x1
> 0 && TEST(scanline
[l
.x1
-1]))
337 scanline
[--l
.x1
] = newcol
;
338 while(l
.x2
< w
&& TEST(scanline
[l
.x2
]))
339 scanline
[l
.x2
++] = newcol
;
343 if(i
<ll
.x2
&& scanline
[i
]!=newcol
) {
347 border
->push_back(QPoint(i
, ll
.y
+d
));