Removed AlgebraicNotation from the variant API.
[tagua/yd.git] / src / imageeffects.cpp
blob9d322adb9c89d14988fb147815d5d7c2264923c7
1 /*
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.
14 #include <cmath>
15 #include <QPainter>
16 #include "imageeffects.h"
17 #include <kcpuinfo.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
37 * response.
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 )
48 if (radius < 1)
49 return;
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);
64 return;
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)
71 int R,G,B,A;
72 R = *bptr;
73 G = *(bptr+1);
74 B = *(bptr+2);
75 A = *(bptr+3);
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;
82 *bptr = zR>>zprec;
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)
91 int zR,zG,zB,zA;
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)
115 int zR,zG,zB,zA;
117 QRgb *ptr = (QRgb *)im.bits();
118 ptr+=col;
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();
126 index+=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;
132 index-=im.width()) {
133 blurinner<aprec,zprec>((unsigned char *)&ptr[index],
134 zR, zG, zB, zA, alpha);
139 namespace ImageEffects {
142 #ifdef HAVE_X86_SSE2
143 void expblur_sse( QImage &img, int radius );
144 #endif //HAVE_X86_SSE2
147 #ifdef HAVE_X86_MMX
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
156 #ifdef HAVE_X86_SSE2
157 #ifndef __x86_64__
158 if(KCPUInfo::haveExtension( KCPUInfo::IntelSSE ) )
159 #endif //__x86_64__
160 return expblur_sse(img, radius);
161 #endif //HAVE_X86_SSE2
163 #ifdef HAVE_X86_MMX
164 #ifndef __x86_64__
165 if(KCPUInfo::haveExtension( KCPUInfo::IntelMMX ) )
166 #endif //__x86_64__
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) {
175 QPainter p;
176 QImage retv(image.width()+growx, image.height()+growy, QImage::Format_ARGB32_Premultiplied);
177 int dx = (growx-offx)/2, dy = (growy-offy)/2;
179 p.begin(&retv);
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);
185 p.end();
187 expBlur(retv, r);
189 p.begin(&retv);
190 p.drawImage(dx, dy, image);
191 p.end();
193 return retv;
196 QImage growBorder(const QImage& image) {
197 int w = image.width();
198 int h = image.height();
199 QPainter p;
200 QImage retv(w+2, h+2, QImage::Format_ARGB32_Premultiplied);
202 p.begin(&retv);
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);
213 p.end();
215 return retv;
218 struct Line {
219 int y, x1, x2;
220 Line(){}
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;
243 lines.push_back(l);
246 while(!lines.empty()) {
247 Line ll = lines[lines.size()-1];
248 lines.pop_back();
250 if(ll.x1>0) {
251 if(invade_border)
252 ptr[ll.y*w + ll.x1 - 1] = newcol;
253 if(border)
254 border->push_back(QPoint(ll.x1-1, ll.y));
256 if(ll.x2<w) {
257 if(invade_border)
258 ptr[ll.y*w + ll.x2] = newcol;
259 if(border)
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;
276 lines.push_back(l);
277 i = l.x2;
279 if(i<ll.x2 && scanline[i]!=newcol) {
280 if(invade_border)
281 scanline[i]=newcol;
282 if(border)
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;
308 lines.push_back(l);
311 while(!lines.empty()) {
312 Line ll = lines[lines.size()-1];
313 lines.pop_back();
315 if(ll.x1>0) {
316 if(invade_border)
317 ptr[ll.y*w + ll.x1 - 1] = newcol;
318 if(border)
319 border->push_back(QPoint(ll.x1-1, ll.y));
321 if(ll.x2<w) {
322 if(invade_border)
323 ptr[ll.y*w + ll.x2] = newcol;
324 if(border)
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;
341 lines.push_back(l);
342 i = l.x2;
344 if(i<ll.x2 && scanline[i]!=newcol) {
345 if(invade_border)
346 scanline[i]=newcol;
347 if(border)
348 border->push_back(QPoint(i, ll.y+d));