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.
16 #include "imageeffects.h"
20 template<int aprec
, int zprec
>
21 static inline void blurinner(unsigned char *bptr
, int &zR
,
22 int &zG
, int &zB
, int &zA
, int alpha
);
24 template<int aprec
,int zprec
>
25 static inline void blurrow(QImage
& im
, int line
, int alpha
);
27 template<int aprec
, int zprec
>
28 static inline void blurcol(QImage
& im
, int col
, int alpha
);
31 * expblur(QImage &img, int radius)
33 * In-place blur of image 'img' with kernel
34 * of approximate radius 'radius'.
36 * Blurs with two sided exponential impulse
39 * aprec = precision of alpha parameter
40 * in fixed-point format 0.aprec
42 * zprec = precision of state parameters
43 * zR,zG,zB and zA in fp format 8.zprec
45 template<int aprec
,int zprec
>
46 static void expblur(QImage
&img
, int radius
)
51 /* Calculate the alpha such that 90% of
52 the kernel is within the radius.
53 (Kernel extends to infinity)
55 int alpha
= (int)((1<<aprec
)*(1.0f
-expf(-2.3f
/(radius
+1.f
))));
57 for(int row
=0;row
<img
.height();row
++) {
58 blurrow
<aprec
,zprec
>(img
,row
,alpha
);
61 for(int col
=0;col
<img
.width();col
++) {
62 blurcol
<aprec
,zprec
>(img
,col
,alpha
);
67 template<int aprec
, int zprec
>
68 static inline void blurinner(unsigned char *bptr
,
69 int &zR
, int &zG
, int &zB
, int &zA
, int alpha
)
77 zR
+= (alpha
* ((R
<<zprec
)-zR
))>>aprec
;
78 zG
+= (alpha
* ((G
<<zprec
)-zG
))>>aprec
;
79 zB
+= (alpha
* ((B
<<zprec
)-zB
))>>aprec
;
80 zA
+= (alpha
* ((A
<<zprec
)-zA
))>>aprec
;
83 *(bptr
+1) = zG
>>zprec
;
84 *(bptr
+2) = zB
>>zprec
;
85 *(bptr
+3) = zA
>>zprec
;
88 template<int aprec
,int zprec
>
89 static inline void blurrow( QImage
& im
, int line
, int alpha
)
93 QRgb
*ptr
= (QRgb
*)im
.scanLine(line
);
95 zR
= *((unsigned char *)ptr
)<<zprec
;
96 zG
= *((unsigned char *)ptr
+ 1)<<zprec
;
97 zB
= *((unsigned char *)ptr
+ 2)<<zprec
;
98 zA
= *((unsigned char *)ptr
+ 3)<<zprec
;
100 for(int index
=1; index
<im
.width(); index
++) {
101 blurinner
<aprec
,zprec
>((unsigned char *)&ptr
[index
],
102 zR
, zG
, zB
, zA
, alpha
);
104 for(int index
=im
.width()-2; index
>=0; index
--) {
105 blurinner
<aprec
,zprec
>((unsigned char *)&ptr
[index
],
106 zR
, zG
, zB
, zA
, alpha
);
112 template<int aprec
, int zprec
>
113 static inline void blurcol(QImage
& im
, int col
, int alpha
)
117 QRgb
*ptr
= (QRgb
*)im
.bits();
120 zR
= *((unsigned char *)ptr
)<<zprec
;
121 zG
= *((unsigned char *)ptr
+ 1)<<zprec
;
122 zB
= *((unsigned char *)ptr
+ 2)<<zprec
;
123 zA
= *((unsigned char *)ptr
+ 3)<<zprec
;
125 for(int index
=im
.width(); index
<(im
.height()-1)*im
.width();
127 blurinner
<aprec
,zprec
>((unsigned char *)&ptr
[index
],
128 zR
, zG
, zB
, zA
, alpha
);
131 for(int index
=(im
.height()-2)*im
.width(); index
>=0;
133 blurinner
<aprec
,zprec
>((unsigned char *)&ptr
[index
],
134 zR
, zG
, zB
, zA
, alpha
);
139 namespace ImageEffects
{
143 void expblur_sse( QImage
&img
, int radius
);
144 #endif //HAVE_X86_SSE
148 void expblur_mmx( QImage
&img
, int radius
);
149 #endif //HAVE_X86_MMX
153 void expBlur(QImage
& img
, int radius
) {
155 //KCPUInfo:: returns false on x86_64, and x86_64 always have sse/mmx
158 if(KCPUInfo::haveExtension( KCPUInfo::IntelSSE
) )
160 return expblur_sse(img
, radius
);
161 #endif //HAVE_X86_SSE
165 if(KCPUInfo::haveExtension( KCPUInfo::IntelMMX
) )
167 return expblur_mmx(img
, radius
);
168 #endif //HAVE_X86_MMX
170 return expblur
<15,7>(img
, radius
);
173 QImage
addShadow(const QImage
& image
, int r
, QColor color
,
174 int offx
, int offy
, int growx
, int growy
) {
176 QImage
retv(image
.width()+growx
, image
.height()+growy
, QImage::Format_ARGB32_Premultiplied
);
177 int dx
= (growx
-offx
)/2, dy
= (growy
-offy
)/2;
180 p
.setCompositionMode(QPainter::CompositionMode_Source
);
181 p
.fillRect(0,0,retv
.width(), retv
.height(), QColor(0,0,0,0));
182 p
.fillRect(dx
+offx
, dy
+offy
, image
.width(), image
.height(), color
);
183 p
.setCompositionMode(QPainter::CompositionMode_DestinationAtop
);
184 p
.drawImage(dx
+offx
, dy
+offy
, image
);
190 p
.drawImage(dx
, dy
, image
);
196 QImage
growBorder(const QImage
& image
) {
197 int w
= image
.width();
198 int h
= image
.height();
200 QImage
retv(w
+2, h
+2, QImage::Format_ARGB32_Premultiplied
);
203 p
.setCompositionMode(QPainter::CompositionMode_Source
);
204 p
.drawImage(0, 0, image
, 0, 0, 1, 1);
205 p
.drawImage(w
+1, 0, image
, w
-1, 0, 1, 1);
206 p
.drawImage(0, h
+1, image
, 0, h
-1, 1, 1);
207 p
.drawImage(w
+1, h
+1, image
, w
-1, h
-1, 1, 1);
208 p
.drawImage(1, 0, image
, 0, 0, w
, 1);
209 p
.drawImage(1, h
+1, image
, 0, h
-1, w
, 1);
210 p
.drawImage(0, 1, image
, 0, 0, 1, h
);
211 p
.drawImage(w
+1, 1, image
, w
-1, 0, 1, h
);
212 p
.drawImage(1, 1, image
);
221 Line(int _y
, int _x1
, int _x2
)
222 : y(_y
), x1(_x1
), x2(_x2
) {}
225 void floodFill(QImage
& image
, QPoint point
, QColor color
,
226 bool invade_border
, std::vector
<QPoint
>* border
) {
228 int* ptr
= (int*)image
.bits();
229 int h
= image
.height();
230 int w
= image
.width();
231 int newcol
= color
.rgba();
232 int oldcol
= ptr
[point
.x()+point
.y()*w
];
233 std::vector
<Line
> lines
;
236 Line
l(point
.y(), point
.x(), point
.x()+1);
237 int *scanline
= ptr
+point
.y()*w
;
238 scanline
[l
.x1
] = newcol
;
239 while(l
.x1
> 0 && scanline
[l
.x1
-1] == oldcol
)
240 scanline
[--l
.x1
] = newcol
;
241 while(l
.x2
< w
&& scanline
[l
.x2
] == oldcol
)
242 scanline
[l
.x2
++] = newcol
;
246 while(!lines
.empty()) {
247 Line ll
= lines
[lines
.size()-1];
252 ptr
[ll
.y
*w
+ ll
.x1
- 1] = newcol
;
254 border
->push_back(QPoint(ll
.x1
-1, ll
.y
));
258 ptr
[ll
.y
*w
+ ll
.x2
] = newcol
;
260 border
->push_back(QPoint(ll
.x2
, ll
.y
));
263 for(int d
=-1; d
<=1; d
+=2)
264 if( (d
== -1) ? (ll
.y
> 0) : (ll
.y
< h
-1) ) {
265 int *scanline
= ptr
+ (ll
.y
+d
)*w
;
267 for(int i
=ll
.x1
;i
<ll
.x2
;i
++){
268 if(scanline
[i
]==oldcol
) {
269 Line
l(ll
.y
+d
, i
, i
+1);
271 scanline
[l
.x1
] = newcol
;
272 while(l
.x1
> 0 && scanline
[l
.x1
-1] == oldcol
)
273 scanline
[--l
.x1
] = newcol
;
274 while(l
.x2
< w
&& scanline
[l
.x2
] == oldcol
)
275 scanline
[l
.x2
++] = newcol
;
279 if(i
<ll
.x2
&& scanline
[i
]!=newcol
) {
283 border
->push_back(QPoint(i
, ll
.y
+d
));
290 void floodFillBlueThreshold(QImage
& image
, QPoint point
, QColor color
, unsigned int thresh
,
291 bool invade_border
, std::vector
<QPoint
>* border
) {
293 unsigned int* ptr
= (unsigned int*)image
.bits();
294 int h
= image
.height();
295 int w
= image
.width();
296 unsigned int newcol
= color
.rgba();
297 std::vector
<Line
> lines
;
299 #define TEST(x) ((((x) & 0xff) < thresh) && ((x) != newcol))
301 Line
l(point
.y(), point
.x(), point
.x()+1);
302 unsigned int *scanline
= ptr
+point
.y()*w
;
303 scanline
[l
.x1
] = newcol
;
304 while(l
.x1
> 0 && TEST(scanline
[l
.x1
-1]))
305 scanline
[--l
.x1
] = newcol
;
306 while(l
.x2
< w
&& TEST(scanline
[l
.x2
]))
307 scanline
[l
.x2
++] = newcol
;
311 while(!lines
.empty()) {
312 Line ll
= lines
[lines
.size()-1];
317 ptr
[ll
.y
*w
+ ll
.x1
- 1] = newcol
;
319 border
->push_back(QPoint(ll
.x1
-1, ll
.y
));
323 ptr
[ll
.y
*w
+ ll
.x2
] = newcol
;
325 border
->push_back(QPoint(ll
.x2
, ll
.y
));
328 for(int d
=-1; d
<=1; d
+=2)
329 if( (d
== -1) ? (ll
.y
> 0) : (ll
.y
< h
-1) ) {
330 unsigned int *scanline
= ptr
+ (ll
.y
+d
)*w
;
332 for(int i
=ll
.x1
;i
<ll
.x2
;i
++){
333 if(TEST(scanline
[i
])) {
334 Line
l(ll
.y
+d
, i
, i
+1);
336 scanline
[l
.x1
] = newcol
;
337 while(l
.x1
> 0 && TEST(scanline
[l
.x1
-1]))
338 scanline
[--l
.x1
] = newcol
;
339 while(l
.x2
< w
&& TEST(scanline
[l
.x2
]))
340 scanline
[l
.x2
++] = newcol
;
344 if(i
<ll
.x2
&& scanline
[i
]!=newcol
) {
348 border
->push_back(QPoint(i
, ll
.y
+d
));