summaryrefslogtreecommitdiff
authormickeyl <mickeyl>2003-09-16 13:07:56 (UTC)
committer mickeyl <mickeyl>2003-09-16 13:07:56 (UTC)
commit9cd1a5708fa9f10e391bd18cbf1f5800cdc76851 (patch) (unidiff)
tree65404702ea418b9270158a941b408870d981eca4
parent81171716bb686e709f27fbbc0931740aa9d9462a (diff)
downloadopie-9cd1a5708fa9f10e391bd18cbf1f5800cdc76851.zip
opie-9cd1a5708fa9f10e391bd18cbf1f5800cdc76851.tar.gz
opie-9cd1a5708fa9f10e391bd18cbf1f5800cdc76851.tar.bz2
remove unneccessary #include
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--libopie2/opieui/oimageeffect.cpp1
1 files changed, 0 insertions, 1 deletions
diff --git a/libopie2/opieui/oimageeffect.cpp b/libopie2/opieui/oimageeffect.cpp
index 2855da6..01e7c6f 100644
--- a/libopie2/opieui/oimageeffect.cpp
+++ b/libopie2/opieui/oimageeffect.cpp
@@ -1,3768 +1,3767 @@
1/* This file is part of the KDE libraries 1/* This file is part of the KDE libraries
2 Copyright (C) 1998, 1999, 2001, 2002 Daniel M. Duley <mosfet@kde.org> 2 Copyright (C) 1998, 1999, 2001, 2002 Daniel M. Duley <mosfet@kde.org>
3 (C) 1998, 1999 Christian Tibirna <ctibirna@total.net> 3 (C) 1998, 1999 Christian Tibirna <ctibirna@total.net>
4 (C) 1998, 1999 Dirk A. Mueller <mueller@kde.org> 4 (C) 1998, 1999 Dirk A. Mueller <mueller@kde.org>
5 (C) 2000 Josef Weidendorfer <weidendo@in.tum.de> 5 (C) 2000 Josef Weidendorfer <weidendo@in.tum.de>
6 6
7Redistribution and use in source and binary forms, with or without 7Redistribution and use in source and binary forms, with or without
8modification, are permitted provided that the following conditions 8modification, are permitted provided that the following conditions
9are met: 9are met:
10 10
111. Redistributions of source code must retain the above copyright 111. Redistributions of source code must retain the above copyright
12 notice, this list of conditions and the following disclaimer. 12 notice, this list of conditions and the following disclaimer.
132. Redistributions in binary form must reproduce the above copyright 132. Redistributions in binary form must reproduce the above copyright
14 notice, this list of conditions and the following disclaimer in the 14 notice, this list of conditions and the following disclaimer in the
15 documentation and/or other materials provided with the distribution. 15 documentation and/or other materials provided with the distribution.
16 16
17THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 21INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 27
28*/ 28*/
29 29
30// $Id$ 30// $Id$
31 31
32#include <math.h> 32#include <math.h>
33 33
34#include <qimage.h> 34#include <qimage.h>
35#include <stdlib.h> 35#include <stdlib.h>
36#include <iostream>
37 36
38#include "oimageeffect.h" 37#include "oimageeffect.h"
39 38
40#define MaxRGB 255L 39#define MaxRGB 255L
41#define DegreesToRadians(x) ((x)*M_PI/180.0) 40#define DegreesToRadians(x) ((x)*M_PI/180.0)
42 41
43using namespace std; 42using namespace std;
44 43
45inline unsigned int intensityValue(unsigned int color) 44inline unsigned int intensityValue(unsigned int color)
46{ 45{
47 return((unsigned int)((0.299*qRed(color) + 46 return((unsigned int)((0.299*qRed(color) +
48 0.587*qGreen(color) + 47 0.587*qGreen(color) +
49 0.1140000000000001*qBlue(color)))); 48 0.1140000000000001*qBlue(color))));
50} 49}
51 50
52//====================================================================== 51//======================================================================
53// 52//
54// Gradient effects 53// Gradient effects
55// 54//
56//====================================================================== 55//======================================================================
57 56
58QImage OImageEffect::gradient(const QSize &size, const QColor &ca, 57QImage OImageEffect::gradient(const QSize &size, const QColor &ca,
59 const QColor &cb, GradientType eff, int ncols) 58 const QColor &cb, GradientType eff, int ncols)
60{ 59{
61 int rDiff, gDiff, bDiff; 60 int rDiff, gDiff, bDiff;
62 int rca, gca, bca, rcb, gcb, bcb; 61 int rca, gca, bca, rcb, gcb, bcb;
63 62
64 QImage image(size, 32); 63 QImage image(size, 32);
65 64
66 if (size.width() == 0 || size.height() == 0) { 65 if (size.width() == 0 || size.height() == 0) {
67 qDebug( "WARNING: OImageEffect::gradient: invalid image" ); 66 qDebug( "WARNING: OImageEffect::gradient: invalid image" );
68 return image; 67 return image;
69 } 68 }
70 69
71 register int x, y; 70 register int x, y;
72 71
73 rDiff = (rcb = cb.red()) - (rca = ca.red()); 72 rDiff = (rcb = cb.red()) - (rca = ca.red());
74 gDiff = (gcb = cb.green()) - (gca = ca.green()); 73 gDiff = (gcb = cb.green()) - (gca = ca.green());
75 bDiff = (bcb = cb.blue()) - (bca = ca.blue()); 74 bDiff = (bcb = cb.blue()) - (bca = ca.blue());
76 75
77 if( eff == VerticalGradient || eff == HorizontalGradient ){ 76 if( eff == VerticalGradient || eff == HorizontalGradient ){
78 77
79 uint *p; 78 uint *p;
80 uint rgb; 79 uint rgb;
81 80
82 register int rl = rca << 16; 81 register int rl = rca << 16;
83 register int gl = gca << 16; 82 register int gl = gca << 16;
84 register int bl = bca << 16; 83 register int bl = bca << 16;
85 84
86 if( eff == VerticalGradient ) { 85 if( eff == VerticalGradient ) {
87 86
88 int rcdelta = ((1<<16) / size.height()) * rDiff; 87 int rcdelta = ((1<<16) / size.height()) * rDiff;
89 int gcdelta = ((1<<16) / size.height()) * gDiff; 88 int gcdelta = ((1<<16) / size.height()) * gDiff;
90 int bcdelta = ((1<<16) / size.height()) * bDiff; 89 int bcdelta = ((1<<16) / size.height()) * bDiff;
91 90
92 for ( y = 0; y < size.height(); y++ ) { 91 for ( y = 0; y < size.height(); y++ ) {
93 p = (uint *) image.scanLine(y); 92 p = (uint *) image.scanLine(y);
94 93
95 rl += rcdelta; 94 rl += rcdelta;
96 gl += gcdelta; 95 gl += gcdelta;
97 bl += bcdelta; 96 bl += bcdelta;
98 97
99 rgb = qRgb( (rl>>16), (gl>>16), (bl>>16) ); 98 rgb = qRgb( (rl>>16), (gl>>16), (bl>>16) );
100 99
101 for( x = 0; x < size.width(); x++ ) { 100 for( x = 0; x < size.width(); x++ ) {
102 *p = rgb; 101 *p = rgb;
103 p++; 102 p++;
104 } 103 }
105 } 104 }
106 105
107 } 106 }
108 else { // must be HorizontalGradient 107 else { // must be HorizontalGradient
109 108
110 unsigned int *o_src = (unsigned int *)image.scanLine(0); 109 unsigned int *o_src = (unsigned int *)image.scanLine(0);
111 unsigned int *src = o_src; 110 unsigned int *src = o_src;
112 111
113 int rcdelta = ((1<<16) / size.width()) * rDiff; 112 int rcdelta = ((1<<16) / size.width()) * rDiff;
114 int gcdelta = ((1<<16) / size.width()) * gDiff; 113 int gcdelta = ((1<<16) / size.width()) * gDiff;
115 int bcdelta = ((1<<16) / size.width()) * bDiff; 114 int bcdelta = ((1<<16) / size.width()) * bDiff;
116 115
117 for( x = 0; x < size.width(); x++) { 116 for( x = 0; x < size.width(); x++) {
118 117
119 rl += rcdelta; 118 rl += rcdelta;
120 gl += gcdelta; 119 gl += gcdelta;
121 bl += bcdelta; 120 bl += bcdelta;
122 121
123 *src++ = qRgb( (rl>>16), (gl>>16), (bl>>16)); 122 *src++ = qRgb( (rl>>16), (gl>>16), (bl>>16));
124 } 123 }
125 124
126 src = o_src; 125 src = o_src;
127 126
128 // Believe it or not, manually copying in a for loop is faster 127 // Believe it or not, manually copying in a for loop is faster
129 // than calling memcpy for each scanline (on the order of ms...). 128 // than calling memcpy for each scanline (on the order of ms...).
130 // I think this is due to the function call overhead (mosfet). 129 // I think this is due to the function call overhead (mosfet).
131 130
132 for (y = 1; y < size.height(); ++y) { 131 for (y = 1; y < size.height(); ++y) {
133 132
134 p = (unsigned int *)image.scanLine(y); 133 p = (unsigned int *)image.scanLine(y);
135 src = o_src; 134 src = o_src;
136 for(x=0; x < size.width(); ++x) 135 for(x=0; x < size.width(); ++x)
137 *p++ = *src++; 136 *p++ = *src++;
138 } 137 }
139 } 138 }
140 } 139 }
141 140
142 else { 141 else {
143 142
144 float rfd, gfd, bfd; 143 float rfd, gfd, bfd;
145 float rd = rca, gd = gca, bd = bca; 144 float rd = rca, gd = gca, bd = bca;
146 145
147 unsigned char *xtable[3]; 146 unsigned char *xtable[3];
148 unsigned char *ytable[3]; 147 unsigned char *ytable[3];
149 148
150 unsigned int w = size.width(), h = size.height(); 149 unsigned int w = size.width(), h = size.height();
151 xtable[0] = new unsigned char[w]; 150 xtable[0] = new unsigned char[w];
152 xtable[1] = new unsigned char[w]; 151 xtable[1] = new unsigned char[w];
153 xtable[2] = new unsigned char[w]; 152 xtable[2] = new unsigned char[w];
154 ytable[0] = new unsigned char[h]; 153 ytable[0] = new unsigned char[h];
155 ytable[1] = new unsigned char[h]; 154 ytable[1] = new unsigned char[h];
156 ytable[2] = new unsigned char[h]; 155 ytable[2] = new unsigned char[h];
157 w*=2, h*=2; 156 w*=2, h*=2;
158 157
159 if ( eff == DiagonalGradient || eff == CrossDiagonalGradient) { 158 if ( eff == DiagonalGradient || eff == CrossDiagonalGradient) {
160 // Diagonal dgradient code inspired by BlackBox (mosfet) 159 // Diagonal dgradient code inspired by BlackBox (mosfet)
161 // BlackBox dgradient is (C) Brad Hughes, <bhughes@tcac.net> and 160 // BlackBox dgradient is (C) Brad Hughes, <bhughes@tcac.net> and
162 // Mike Cole <mike@mydot.com>. 161 // Mike Cole <mike@mydot.com>.
163 162
164 rfd = (float)rDiff/w; 163 rfd = (float)rDiff/w;
165 gfd = (float)gDiff/w; 164 gfd = (float)gDiff/w;
166 bfd = (float)bDiff/w; 165 bfd = (float)bDiff/w;
167 166
168 int dir; 167 int dir;
169 for (x = 0; x < size.width(); x++, rd+=rfd, gd+=gfd, bd+=bfd) { 168 for (x = 0; x < size.width(); x++, rd+=rfd, gd+=gfd, bd+=bfd) {
170 dir = eff == DiagonalGradient? x : size.width() - x - 1; 169 dir = eff == DiagonalGradient? x : size.width() - x - 1;
171 xtable[0][dir] = (unsigned char) rd; 170 xtable[0][dir] = (unsigned char) rd;
172 xtable[1][dir] = (unsigned char) gd; 171 xtable[1][dir] = (unsigned char) gd;
173 xtable[2][dir] = (unsigned char) bd; 172 xtable[2][dir] = (unsigned char) bd;
174 } 173 }
175 rfd = (float)rDiff/h; 174 rfd = (float)rDiff/h;
176 gfd = (float)gDiff/h; 175 gfd = (float)gDiff/h;
177 bfd = (float)bDiff/h; 176 bfd = (float)bDiff/h;
178 rd = gd = bd = 0; 177 rd = gd = bd = 0;
179 for (y = 0; y < size.height(); y++, rd+=rfd, gd+=gfd, bd+=bfd) { 178 for (y = 0; y < size.height(); y++, rd+=rfd, gd+=gfd, bd+=bfd) {
180 ytable[0][y] = (unsigned char) rd; 179 ytable[0][y] = (unsigned char) rd;
181 ytable[1][y] = (unsigned char) gd; 180 ytable[1][y] = (unsigned char) gd;
182 ytable[2][y] = (unsigned char) bd; 181 ytable[2][y] = (unsigned char) bd;
183 } 182 }
184 183
185 for (y = 0; y < size.height(); y++) { 184 for (y = 0; y < size.height(); y++) {
186 unsigned int *scanline = (unsigned int *)image.scanLine(y); 185 unsigned int *scanline = (unsigned int *)image.scanLine(y);
187 for (x = 0; x < size.width(); x++) { 186 for (x = 0; x < size.width(); x++) {
188 scanline[x] = qRgb(xtable[0][x] + ytable[0][y], 187 scanline[x] = qRgb(xtable[0][x] + ytable[0][y],
189 xtable[1][x] + ytable[1][y], 188 xtable[1][x] + ytable[1][y],
190 xtable[2][x] + ytable[2][y]); 189 xtable[2][x] + ytable[2][y]);
191 } 190 }
192 } 191 }
193 } 192 }
194 193
195 else if (eff == RectangleGradient || 194 else if (eff == RectangleGradient ||
196 eff == PyramidGradient || 195 eff == PyramidGradient ||
197 eff == PipeCrossGradient || 196 eff == PipeCrossGradient ||
198 eff == EllipticGradient) 197 eff == EllipticGradient)
199 { 198 {
200 int rSign = rDiff>0? 1: -1; 199 int rSign = rDiff>0? 1: -1;
201 int gSign = gDiff>0? 1: -1; 200 int gSign = gDiff>0? 1: -1;
202 int bSign = bDiff>0? 1: -1; 201 int bSign = bDiff>0? 1: -1;
203 202
204 rfd = (float)rDiff / size.width(); 203 rfd = (float)rDiff / size.width();
205 gfd = (float)gDiff / size.width(); 204 gfd = (float)gDiff / size.width();
206 bfd = (float)bDiff / size.width(); 205 bfd = (float)bDiff / size.width();
207 206
208 rd = (float)rDiff/2; 207 rd = (float)rDiff/2;
209 gd = (float)gDiff/2; 208 gd = (float)gDiff/2;
210 bd = (float)bDiff/2; 209 bd = (float)bDiff/2;
211 210
212 for (x = 0; x < size.width(); x++, rd-=rfd, gd-=gfd, bd-=bfd) 211 for (x = 0; x < size.width(); x++, rd-=rfd, gd-=gfd, bd-=bfd)
213 { 212 {
214 xtable[0][x] = (unsigned char) abs((int)rd); 213 xtable[0][x] = (unsigned char) abs((int)rd);
215 xtable[1][x] = (unsigned char) abs((int)gd); 214 xtable[1][x] = (unsigned char) abs((int)gd);
216 xtable[2][x] = (unsigned char) abs((int)bd); 215 xtable[2][x] = (unsigned char) abs((int)bd);
217 } 216 }
218 217
219 rfd = (float)rDiff/size.height(); 218 rfd = (float)rDiff/size.height();
220 gfd = (float)gDiff/size.height(); 219 gfd = (float)gDiff/size.height();
221 bfd = (float)bDiff/size.height(); 220 bfd = (float)bDiff/size.height();
222 221
223 rd = (float)rDiff/2; 222 rd = (float)rDiff/2;
224 gd = (float)gDiff/2; 223 gd = (float)gDiff/2;
225 bd = (float)bDiff/2; 224 bd = (float)bDiff/2;
226 225
227 for (y = 0; y < size.height(); y++, rd-=rfd, gd-=gfd, bd-=bfd) 226 for (y = 0; y < size.height(); y++, rd-=rfd, gd-=gfd, bd-=bfd)
228 { 227 {
229 ytable[0][y] = (unsigned char) abs((int)rd); 228 ytable[0][y] = (unsigned char) abs((int)rd);
230 ytable[1][y] = (unsigned char) abs((int)gd); 229 ytable[1][y] = (unsigned char) abs((int)gd);
231 ytable[2][y] = (unsigned char) abs((int)bd); 230 ytable[2][y] = (unsigned char) abs((int)bd);
232 } 231 }
233 unsigned int rgb; 232 unsigned int rgb;
234 int h = (size.height()+1)>>1; 233 int h = (size.height()+1)>>1;
235 for (y = 0; y < h; y++) { 234 for (y = 0; y < h; y++) {
236 unsigned int *sl1 = (unsigned int *)image.scanLine(y); 235 unsigned int *sl1 = (unsigned int *)image.scanLine(y);
237 unsigned int *sl2 = (unsigned int *)image.scanLine(QMAX(size.height()-y-1, y)); 236 unsigned int *sl2 = (unsigned int *)image.scanLine(QMAX(size.height()-y-1, y));
238 237
239 int w = (size.width()+1)>>1; 238 int w = (size.width()+1)>>1;
240 int x2 = size.width()-1; 239 int x2 = size.width()-1;
241 240
242 for (x = 0; x < w; x++, x2--) { 241 for (x = 0; x < w; x++, x2--) {
243 rgb = 0; 242 rgb = 0;
244 if (eff == PyramidGradient) { 243 if (eff == PyramidGradient) {
245 rgb = qRgb(rcb-rSign*(xtable[0][x]+ytable[0][y]), 244 rgb = qRgb(rcb-rSign*(xtable[0][x]+ytable[0][y]),
246 gcb-gSign*(xtable[1][x]+ytable[1][y]), 245 gcb-gSign*(xtable[1][x]+ytable[1][y]),
247 bcb-bSign*(xtable[2][x]+ytable[2][y])); 246 bcb-bSign*(xtable[2][x]+ytable[2][y]));
248 } 247 }
249 if (eff == RectangleGradient) { 248 if (eff == RectangleGradient) {
250 rgb = qRgb(rcb - rSign * 249 rgb = qRgb(rcb - rSign *
251 QMAX(xtable[0][x], ytable[0][y]) * 2, 250 QMAX(xtable[0][x], ytable[0][y]) * 2,
252 gcb - gSign * 251 gcb - gSign *
253 QMAX(xtable[1][x], ytable[1][y]) * 2, 252 QMAX(xtable[1][x], ytable[1][y]) * 2,
254 bcb - bSign * 253 bcb - bSign *
255 QMAX(xtable[2][x], ytable[2][y]) * 2); 254 QMAX(xtable[2][x], ytable[2][y]) * 2);
256 } 255 }
257 if (eff == PipeCrossGradient) { 256 if (eff == PipeCrossGradient) {
258 rgb = qRgb(rcb - rSign * 257 rgb = qRgb(rcb - rSign *
259 QMIN(xtable[0][x], ytable[0][y]) * 2, 258 QMIN(xtable[0][x], ytable[0][y]) * 2,
260 gcb - gSign * 259 gcb - gSign *
261 QMIN(xtable[1][x], ytable[1][y]) * 2, 260 QMIN(xtable[1][x], ytable[1][y]) * 2,
262 bcb - bSign * 261 bcb - bSign *
263 QMIN(xtable[2][x], ytable[2][y]) * 2); 262 QMIN(xtable[2][x], ytable[2][y]) * 2);
264 } 263 }
265 if (eff == EllipticGradient) { 264 if (eff == EllipticGradient) {
266 rgb = qRgb(rcb - rSign * 265 rgb = qRgb(rcb - rSign *
267 (int)sqrt((xtable[0][x]*xtable[0][x] + 266 (int)sqrt((xtable[0][x]*xtable[0][x] +
268 ytable[0][y]*ytable[0][y])*2.0), 267 ytable[0][y]*ytable[0][y])*2.0),
269 gcb - gSign * 268 gcb - gSign *
270 (int)sqrt((xtable[1][x]*xtable[1][x] + 269 (int)sqrt((xtable[1][x]*xtable[1][x] +
271 ytable[1][y]*ytable[1][y])*2.0), 270 ytable[1][y]*ytable[1][y])*2.0),
272 bcb - bSign * 271 bcb - bSign *
273 (int)sqrt((xtable[2][x]*xtable[2][x] + 272 (int)sqrt((xtable[2][x]*xtable[2][x] +
274 ytable[2][y]*ytable[2][y])*2.0)); 273 ytable[2][y]*ytable[2][y])*2.0));
275 } 274 }
276 275
277 sl1[x] = sl2[x] = rgb; 276 sl1[x] = sl2[x] = rgb;
278 sl1[x2] = sl2[x2] = rgb; 277 sl1[x2] = sl2[x2] = rgb;
279 } 278 }
280 } 279 }
281 } 280 }
282 281
283 delete [] xtable[0]; 282 delete [] xtable[0];
284 delete [] xtable[1]; 283 delete [] xtable[1];
285 delete [] xtable[2]; 284 delete [] xtable[2];
286 delete [] ytable[0]; 285 delete [] ytable[0];
287 delete [] ytable[1]; 286 delete [] ytable[1];
288 delete [] ytable[2]; 287 delete [] ytable[2];
289 } 288 }
290 289
291 // dither if necessary 290 // dither if necessary
292 if (ncols && (QPixmap::defaultDepth() < 15 )) { 291 if (ncols && (QPixmap::defaultDepth() < 15 )) {
293 if ( ncols < 2 || ncols > 256 ) 292 if ( ncols < 2 || ncols > 256 )
294 ncols = 3; 293 ncols = 3;
295 QColor *dPal = new QColor[ncols]; 294 QColor *dPal = new QColor[ncols];
296 for (int i=0; i<ncols; i++) { 295 for (int i=0; i<ncols; i++) {
297 dPal[i].setRgb ( rca + rDiff * i / ( ncols - 1 ), 296 dPal[i].setRgb ( rca + rDiff * i / ( ncols - 1 ),
298 gca + gDiff * i / ( ncols - 1 ), 297 gca + gDiff * i / ( ncols - 1 ),
299 bca + bDiff * i / ( ncols - 1 ) ); 298 bca + bDiff * i / ( ncols - 1 ) );
300 } 299 }
301 dither(image, dPal, ncols); 300 dither(image, dPal, ncols);
302 delete [] dPal; 301 delete [] dPal;
303 } 302 }
304 303
305 return image; 304 return image;
306} 305}
307 306
308 307
309// ----------------------------------------------------------------------------- 308// -----------------------------------------------------------------------------
310 309
311//CT this was (before Dirk A. Mueller's speedup changes) 310//CT this was (before Dirk A. Mueller's speedup changes)
312// merely the same code as in the above method, but it's supposedly 311// merely the same code as in the above method, but it's supposedly
313// way less performant since it introduces a lot of supplementary tests 312// way less performant since it introduces a lot of supplementary tests
314// and simple math operations for the calculus of the balance. 313// and simple math operations for the calculus of the balance.
315// (surprizingly, it isn't less performant, in the contrary :-) 314// (surprizingly, it isn't less performant, in the contrary :-)
316// Yes, I could have merged them, but then the excellent performance of 315// Yes, I could have merged them, but then the excellent performance of
317// the balanced code would suffer with no other gain than a mere 316// the balanced code would suffer with no other gain than a mere
318// source code and byte code size economy. 317// source code and byte code size economy.
319 318
320QImage OImageEffect::unbalancedGradient(const QSize &size, const QColor &ca, 319QImage OImageEffect::unbalancedGradient(const QSize &size, const QColor &ca,
321 const QColor &cb, GradientType eff, int xfactor, int yfactor, 320 const QColor &cb, GradientType eff, int xfactor, int yfactor,
322 int ncols) 321 int ncols)
323{ 322{
324 int dir; // general parameter used for direction switches 323 int dir; // general parameter used for direction switches
325 324
326 bool _xanti = false , _yanti = false; 325 bool _xanti = false , _yanti = false;
327 326
328 if (xfactor < 0) _xanti = true; // negative on X direction 327 if (xfactor < 0) _xanti = true; // negative on X direction
329 if (yfactor < 0) _yanti = true; // negative on Y direction 328 if (yfactor < 0) _yanti = true; // negative on Y direction
330 329
331 xfactor = abs(xfactor); 330 xfactor = abs(xfactor);
332 yfactor = abs(yfactor); 331 yfactor = abs(yfactor);
333 332
334 if (!xfactor) xfactor = 1; 333 if (!xfactor) xfactor = 1;
335 if (!yfactor) yfactor = 1; 334 if (!yfactor) yfactor = 1;
336 335
337 if (xfactor > 200 ) xfactor = 200; 336 if (xfactor > 200 ) xfactor = 200;
338 if (yfactor > 200 ) yfactor = 200; 337 if (yfactor > 200 ) yfactor = 200;
339 338
340 339
341 // float xbal = xfactor/5000.; 340 // float xbal = xfactor/5000.;
342 // float ybal = yfactor/5000.; 341 // float ybal = yfactor/5000.;
343 float xbal = xfactor/30./size.width(); 342 float xbal = xfactor/30./size.width();
344 float ybal = yfactor/30./size.height(); 343 float ybal = yfactor/30./size.height();
345 float rat; 344 float rat;
346 345
347 int rDiff, gDiff, bDiff; 346 int rDiff, gDiff, bDiff;
348 int rca, gca, bca, rcb, gcb, bcb; 347 int rca, gca, bca, rcb, gcb, bcb;
349 348
350 QImage image(size, 32); 349 QImage image(size, 32);
351 350
352 if (size.width() == 0 || size.height() == 0) { 351 if (size.width() == 0 || size.height() == 0) {
353 qDebug( "WARNING: OImageEffect::unbalancedGradient : invalid image" ); 352 qDebug( "WARNING: OImageEffect::unbalancedGradient : invalid image" );
354 return image; 353 return image;
355 } 354 }
356 355
357 register int x, y; 356 register int x, y;
358 unsigned int *scanline; 357 unsigned int *scanline;
359 358
360 rDiff = (rcb = cb.red()) - (rca = ca.red()); 359 rDiff = (rcb = cb.red()) - (rca = ca.red());
361 gDiff = (gcb = cb.green()) - (gca = ca.green()); 360 gDiff = (gcb = cb.green()) - (gca = ca.green());
362 bDiff = (bcb = cb.blue()) - (bca = ca.blue()); 361 bDiff = (bcb = cb.blue()) - (bca = ca.blue());
363 362
364 if( eff == VerticalGradient || eff == HorizontalGradient){ 363 if( eff == VerticalGradient || eff == HorizontalGradient){
365 QColor cRow; 364 QColor cRow;
366 365
367 uint *p; 366 uint *p;
368 uint rgbRow; 367 uint rgbRow;
369 368
370 if( eff == VerticalGradient) { 369 if( eff == VerticalGradient) {
371 for ( y = 0; y < size.height(); y++ ) { 370 for ( y = 0; y < size.height(); y++ ) {
372 dir = _yanti ? y : size.height() - 1 - y; 371 dir = _yanti ? y : size.height() - 1 - y;
373 p = (uint *) image.scanLine(dir); 372 p = (uint *) image.scanLine(dir);
374 rat = 1 - exp( - (float)y * ybal ); 373 rat = 1 - exp( - (float)y * ybal );
375 374
376 cRow.setRgb( rcb - (int) ( rDiff * rat ), 375 cRow.setRgb( rcb - (int) ( rDiff * rat ),
377 gcb - (int) ( gDiff * rat ), 376 gcb - (int) ( gDiff * rat ),
378 bcb - (int) ( bDiff * rat ) ); 377 bcb - (int) ( bDiff * rat ) );
379 378
380 rgbRow = cRow.rgb(); 379 rgbRow = cRow.rgb();
381 380
382 for( x = 0; x < size.width(); x++ ) { 381 for( x = 0; x < size.width(); x++ ) {
383 *p = rgbRow; 382 *p = rgbRow;
384 p++; 383 p++;
385 } 384 }
386 } 385 }
387 } 386 }
388 else { 387 else {
389 388
390 unsigned int *src = (unsigned int *)image.scanLine(0); 389 unsigned int *src = (unsigned int *)image.scanLine(0);
391 for(x = 0; x < size.width(); x++ ) 390 for(x = 0; x < size.width(); x++ )
392 { 391 {
393 dir = _xanti ? x : size.width() - 1 - x; 392 dir = _xanti ? x : size.width() - 1 - x;
394 rat = 1 - exp( - (float)x * xbal ); 393 rat = 1 - exp( - (float)x * xbal );
395 394
396 src[dir] = qRgb(rcb - (int) ( rDiff * rat ), 395 src[dir] = qRgb(rcb - (int) ( rDiff * rat ),
397 gcb - (int) ( gDiff * rat ), 396 gcb - (int) ( gDiff * rat ),
398 bcb - (int) ( bDiff * rat )); 397 bcb - (int) ( bDiff * rat ));
399 } 398 }
400 399
401 // Believe it or not, manually copying in a for loop is faster 400 // Believe it or not, manually copying in a for loop is faster
402 // than calling memcpy for each scanline (on the order of ms...). 401 // than calling memcpy for each scanline (on the order of ms...).
403 // I think this is due to the function call overhead (mosfet). 402 // I think this is due to the function call overhead (mosfet).
404 403
405 for(y = 1; y < size.height(); ++y) 404 for(y = 1; y < size.height(); ++y)
406 { 405 {
407 scanline = (unsigned int *)image.scanLine(y); 406 scanline = (unsigned int *)image.scanLine(y);
408 for(x=0; x < size.width(); ++x) 407 for(x=0; x < size.width(); ++x)
409 scanline[x] = src[x]; 408 scanline[x] = src[x];
410 } 409 }
411 } 410 }
412 } 411 }
413 412
414 else { 413 else {
415 int w=size.width(), h=size.height(); 414 int w=size.width(), h=size.height();
416 415
417 unsigned char *xtable[3]; 416 unsigned char *xtable[3];
418 unsigned char *ytable[3]; 417 unsigned char *ytable[3];
419 xtable[0] = new unsigned char[w]; 418 xtable[0] = new unsigned char[w];
420 xtable[1] = new unsigned char[w]; 419 xtable[1] = new unsigned char[w];
421 xtable[2] = new unsigned char[w]; 420 xtable[2] = new unsigned char[w];
422 ytable[0] = new unsigned char[h]; 421 ytable[0] = new unsigned char[h];
423 ytable[1] = new unsigned char[h]; 422 ytable[1] = new unsigned char[h];
424 ytable[2] = new unsigned char[h]; 423 ytable[2] = new unsigned char[h];
425 424
426 if ( eff == DiagonalGradient || eff == CrossDiagonalGradient) 425 if ( eff == DiagonalGradient || eff == CrossDiagonalGradient)
427 { 426 {
428 for (x = 0; x < w; x++) { 427 for (x = 0; x < w; x++) {
429 dir = _xanti ? x : w - 1 - x; 428 dir = _xanti ? x : w - 1 - x;
430 rat = 1 - exp( - (float)x * xbal ); 429 rat = 1 - exp( - (float)x * xbal );
431 430
432 xtable[0][dir] = (unsigned char) ( rDiff/2 * rat ); 431 xtable[0][dir] = (unsigned char) ( rDiff/2 * rat );
433 xtable[1][dir] = (unsigned char) ( gDiff/2 * rat ); 432 xtable[1][dir] = (unsigned char) ( gDiff/2 * rat );
434 xtable[2][dir] = (unsigned char) ( bDiff/2 * rat ); 433 xtable[2][dir] = (unsigned char) ( bDiff/2 * rat );
435 } 434 }
436 435
437 for (y = 0; y < h; y++) { 436 for (y = 0; y < h; y++) {
438 dir = _yanti ? y : h - 1 - y; 437 dir = _yanti ? y : h - 1 - y;
439 rat = 1 - exp( - (float)y * ybal ); 438 rat = 1 - exp( - (float)y * ybal );
440 439
441 ytable[0][dir] = (unsigned char) ( rDiff/2 * rat ); 440 ytable[0][dir] = (unsigned char) ( rDiff/2 * rat );
442 ytable[1][dir] = (unsigned char) ( gDiff/2 * rat ); 441 ytable[1][dir] = (unsigned char) ( gDiff/2 * rat );
443 ytable[2][dir] = (unsigned char) ( bDiff/2 * rat ); 442 ytable[2][dir] = (unsigned char) ( bDiff/2 * rat );
444 } 443 }
445 444
446 for (y = 0; y < h; y++) { 445 for (y = 0; y < h; y++) {
447 unsigned int *scanline = (unsigned int *)image.scanLine(y); 446 unsigned int *scanline = (unsigned int *)image.scanLine(y);
448 for (x = 0; x < w; x++) { 447 for (x = 0; x < w; x++) {
449 scanline[x] = qRgb(rcb - (xtable[0][x] + ytable[0][y]), 448 scanline[x] = qRgb(rcb - (xtable[0][x] + ytable[0][y]),
450 gcb - (xtable[1][x] + ytable[1][y]), 449 gcb - (xtable[1][x] + ytable[1][y]),
451 bcb - (xtable[2][x] + ytable[2][y])); 450 bcb - (xtable[2][x] + ytable[2][y]));
452 } 451 }
453 } 452 }
454 } 453 }
455 454
456 else if (eff == RectangleGradient || 455 else if (eff == RectangleGradient ||
457 eff == PyramidGradient || 456 eff == PyramidGradient ||
458 eff == PipeCrossGradient || 457 eff == PipeCrossGradient ||
459 eff == EllipticGradient) 458 eff == EllipticGradient)
460 { 459 {
461 int rSign = rDiff>0? 1: -1; 460 int rSign = rDiff>0? 1: -1;
462 int gSign = gDiff>0? 1: -1; 461 int gSign = gDiff>0? 1: -1;
463 int bSign = bDiff>0? 1: -1; 462 int bSign = bDiff>0? 1: -1;
464 463
465 for (x = 0; x < w; x++) 464 for (x = 0; x < w; x++)
466 { 465 {
467 dir = _xanti ? x : w - 1 - x; 466 dir = _xanti ? x : w - 1 - x;
468 rat = 1 - exp( - (float)x * xbal ); 467 rat = 1 - exp( - (float)x * xbal );
469 468
470 xtable[0][dir] = (unsigned char) abs((int)(rDiff*(0.5-rat))); 469 xtable[0][dir] = (unsigned char) abs((int)(rDiff*(0.5-rat)));
471 xtable[1][dir] = (unsigned char) abs((int)(gDiff*(0.5-rat))); 470 xtable[1][dir] = (unsigned char) abs((int)(gDiff*(0.5-rat)));
472 xtable[2][dir] = (unsigned char) abs((int)(bDiff*(0.5-rat))); 471 xtable[2][dir] = (unsigned char) abs((int)(bDiff*(0.5-rat)));
473 } 472 }
474 473
475 for (y = 0; y < h; y++) 474 for (y = 0; y < h; y++)
476 { 475 {
477 dir = _yanti ? y : h - 1 - y; 476 dir = _yanti ? y : h - 1 - y;
478 477
479 rat = 1 - exp( - (float)y * ybal ); 478 rat = 1 - exp( - (float)y * ybal );
480 479
481 ytable[0][dir] = (unsigned char) abs((int)(rDiff*(0.5-rat))); 480 ytable[0][dir] = (unsigned char) abs((int)(rDiff*(0.5-rat)));
482 ytable[1][dir] = (unsigned char) abs((int)(gDiff*(0.5-rat))); 481 ytable[1][dir] = (unsigned char) abs((int)(gDiff*(0.5-rat)));
483 ytable[2][dir] = (unsigned char) abs((int)(bDiff*(0.5-rat))); 482 ytable[2][dir] = (unsigned char) abs((int)(bDiff*(0.5-rat)));
484 } 483 }
485 484
486 for (y = 0; y < h; y++) { 485 for (y = 0; y < h; y++) {
487 unsigned int *scanline = (unsigned int *)image.scanLine(y); 486 unsigned int *scanline = (unsigned int *)image.scanLine(y);
488 for (x = 0; x < w; x++) { 487 for (x = 0; x < w; x++) {
489 if (eff == PyramidGradient) 488 if (eff == PyramidGradient)
490 { 489 {
491 scanline[x] = qRgb(rcb-rSign*(xtable[0][x]+ytable[0][y]), 490 scanline[x] = qRgb(rcb-rSign*(xtable[0][x]+ytable[0][y]),
492 gcb-gSign*(xtable[1][x]+ytable[1][y]), 491 gcb-gSign*(xtable[1][x]+ytable[1][y]),
493 bcb-bSign*(xtable[2][x]+ytable[2][y])); 492 bcb-bSign*(xtable[2][x]+ytable[2][y]));
494 } 493 }
495 if (eff == RectangleGradient) 494 if (eff == RectangleGradient)
496 { 495 {
497 scanline[x] = qRgb(rcb - rSign * 496 scanline[x] = qRgb(rcb - rSign *
498 QMAX(xtable[0][x], ytable[0][y]) * 2, 497 QMAX(xtable[0][x], ytable[0][y]) * 2,
499 gcb - gSign * 498 gcb - gSign *
500 QMAX(xtable[1][x], ytable[1][y]) * 2, 499 QMAX(xtable[1][x], ytable[1][y]) * 2,
501 bcb - bSign * 500 bcb - bSign *
502 QMAX(xtable[2][x], ytable[2][y]) * 2); 501 QMAX(xtable[2][x], ytable[2][y]) * 2);
503 } 502 }
504 if (eff == PipeCrossGradient) 503 if (eff == PipeCrossGradient)
505 { 504 {
506 scanline[x] = qRgb(rcb - rSign * 505 scanline[x] = qRgb(rcb - rSign *
507 QMIN(xtable[0][x], ytable[0][y]) * 2, 506 QMIN(xtable[0][x], ytable[0][y]) * 2,
508 gcb - gSign * 507 gcb - gSign *
509 QMIN(xtable[1][x], ytable[1][y]) * 2, 508 QMIN(xtable[1][x], ytable[1][y]) * 2,
510 bcb - bSign * 509 bcb - bSign *
511 QMIN(xtable[2][x], ytable[2][y]) * 2); 510 QMIN(xtable[2][x], ytable[2][y]) * 2);
512 } 511 }
513 if (eff == EllipticGradient) 512 if (eff == EllipticGradient)
514 { 513 {
515 scanline[x] = qRgb(rcb - rSign * 514 scanline[x] = qRgb(rcb - rSign *
516 (int)sqrt((xtable[0][x]*xtable[0][x] + 515 (int)sqrt((xtable[0][x]*xtable[0][x] +
517 ytable[0][y]*ytable[0][y])*2.0), 516 ytable[0][y]*ytable[0][y])*2.0),
518 gcb - gSign * 517 gcb - gSign *
519 (int)sqrt((xtable[1][x]*xtable[1][x] + 518 (int)sqrt((xtable[1][x]*xtable[1][x] +
520 ytable[1][y]*ytable[1][y])*2.0), 519 ytable[1][y]*ytable[1][y])*2.0),
521 bcb - bSign * 520 bcb - bSign *
522 (int)sqrt((xtable[2][x]*xtable[2][x] + 521 (int)sqrt((xtable[2][x]*xtable[2][x] +
523 ytable[2][y]*ytable[2][y])*2.0)); 522 ytable[2][y]*ytable[2][y])*2.0));
524 } 523 }
525 } 524 }
526 } 525 }
527 } 526 }
528 527
529 if (ncols && (QPixmap::defaultDepth() < 15 )) { 528 if (ncols && (QPixmap::defaultDepth() < 15 )) {
530 if ( ncols < 2 || ncols > 256 ) 529 if ( ncols < 2 || ncols > 256 )
531 ncols = 3; 530 ncols = 3;
532 QColor *dPal = new QColor[ncols]; 531 QColor *dPal = new QColor[ncols];
533 for (int i=0; i<ncols; i++) { 532 for (int i=0; i<ncols; i++) {
534 dPal[i].setRgb ( rca + rDiff * i / ( ncols - 1 ), 533 dPal[i].setRgb ( rca + rDiff * i / ( ncols - 1 ),
535 gca + gDiff * i / ( ncols - 1 ), 534 gca + gDiff * i / ( ncols - 1 ),
536 bca + bDiff * i / ( ncols - 1 ) ); 535 bca + bDiff * i / ( ncols - 1 ) );
537 } 536 }
538 dither(image, dPal, ncols); 537 dither(image, dPal, ncols);
539 delete [] dPal; 538 delete [] dPal;
540 } 539 }
541 540
542 delete [] xtable[0]; 541 delete [] xtable[0];
543 delete [] xtable[1]; 542 delete [] xtable[1];
544 delete [] xtable[2]; 543 delete [] xtable[2];
545 delete [] ytable[0]; 544 delete [] ytable[0];
546 delete [] ytable[1]; 545 delete [] ytable[1];
547 delete [] ytable[2]; 546 delete [] ytable[2];
548 547
549 } 548 }
550 549
551 return image; 550 return image;
552} 551}
553 552
554 553
555//====================================================================== 554//======================================================================
556// 555//
557// Intensity effects 556// Intensity effects
558// 557//
559//====================================================================== 558//======================================================================
560 559
561 560
562/* This builds a 256 byte unsigned char lookup table with all 561/* This builds a 256 byte unsigned char lookup table with all
563 * the possible percent values prior to applying the effect, then uses 562 * the possible percent values prior to applying the effect, then uses
564 * integer math for the pixels. For any image larger than 9x9 this will be 563 * integer math for the pixels. For any image larger than 9x9 this will be
565 * less expensive than doing a float operation on the 3 color components of 564 * less expensive than doing a float operation on the 3 color components of
566 * each pixel. (mosfet) 565 * each pixel. (mosfet)
567 */ 566 */
568 567
569QImage& OImageEffect::intensity(QImage &image, float percent) 568QImage& OImageEffect::intensity(QImage &image, float percent)
570{ 569{
571 if (image.width() == 0 || image.height() == 0) { 570 if (image.width() == 0 || image.height() == 0) {
572 qDebug( "WARNING: OImageEffect::intensity : invalid image" ); 571 qDebug( "WARNING: OImageEffect::intensity : invalid image" );
573 return image; 572 return image;
574 } 573 }
575 574
576 int segColors = image.depth() > 8 ? 256 : image.numColors(); 575 int segColors = image.depth() > 8 ? 256 : image.numColors();
577 unsigned char *segTbl = new unsigned char[segColors]; 576 unsigned char *segTbl = new unsigned char[segColors];
578 int pixels = image.depth() > 8 ? image.width()*image.height() : 577 int pixels = image.depth() > 8 ? image.width()*image.height() :
579 image.numColors(); 578 image.numColors();
580 unsigned int *data = image.depth() > 8 ? (unsigned int *)image.bits() : 579 unsigned int *data = image.depth() > 8 ? (unsigned int *)image.bits() :
581 (unsigned int *)image.colorTable(); 580 (unsigned int *)image.colorTable();
582 581
583 bool brighten = (percent >= 0); 582 bool brighten = (percent >= 0);
584 if(percent < 0) 583 if(percent < 0)
585 percent = -percent; 584 percent = -percent;
586 585
587 if(brighten){ // keep overflow check out of loops 586 if(brighten){ // keep overflow check out of loops
588 for(int i=0; i < segColors; ++i){ 587 for(int i=0; i < segColors; ++i){
589 int tmp = (int)(i*percent); 588 int tmp = (int)(i*percent);
590 if(tmp > 255) 589 if(tmp > 255)
591 tmp = 255; 590 tmp = 255;
592 segTbl[i] = tmp; 591 segTbl[i] = tmp;
593 } 592 }
594 } 593 }
595 else{ 594 else{
596 for(int i=0; i < segColors; ++i){ 595 for(int i=0; i < segColors; ++i){
597 int tmp = (int)(i*percent); 596 int tmp = (int)(i*percent);
598 if(tmp < 0) 597 if(tmp < 0)
599 tmp = 0; 598 tmp = 0;
600 segTbl[i] = tmp; 599 segTbl[i] = tmp;
601 } 600 }
602 } 601 }
603 602
604 if(brighten){ // same here 603 if(brighten){ // same here
605 for(int i=0; i < pixels; ++i){ 604 for(int i=0; i < pixels; ++i){
606 int r = qRed(data[i]); 605 int r = qRed(data[i]);
607 int g = qGreen(data[i]); 606 int g = qGreen(data[i]);
608 int b = qBlue(data[i]); 607 int b = qBlue(data[i]);
609 int a = qAlpha(data[i]); 608 int a = qAlpha(data[i]);
610 r = r + segTbl[r] > 255 ? 255 : r + segTbl[r]; 609 r = r + segTbl[r] > 255 ? 255 : r + segTbl[r];
611 g = g + segTbl[g] > 255 ? 255 : g + segTbl[g]; 610 g = g + segTbl[g] > 255 ? 255 : g + segTbl[g];
612 b = b + segTbl[b] > 255 ? 255 : b + segTbl[b]; 611 b = b + segTbl[b] > 255 ? 255 : b + segTbl[b];
613 data[i] = qRgba(r, g, b,a); 612 data[i] = qRgba(r, g, b,a);
614 } 613 }
615 } 614 }
616 else{ 615 else{
617 for(int i=0; i < pixels; ++i){ 616 for(int i=0; i < pixels; ++i){
618 int r = qRed(data[i]); 617 int r = qRed(data[i]);
619 int g = qGreen(data[i]); 618 int g = qGreen(data[i]);
620 int b = qBlue(data[i]); 619 int b = qBlue(data[i]);
621 int a = qAlpha(data[i]); 620 int a = qAlpha(data[i]);
622 r = r - segTbl[r] < 0 ? 0 : r - segTbl[r]; 621 r = r - segTbl[r] < 0 ? 0 : r - segTbl[r];
623 g = g - segTbl[g] < 0 ? 0 : g - segTbl[g]; 622 g = g - segTbl[g] < 0 ? 0 : g - segTbl[g];
624 b = b - segTbl[b] < 0 ? 0 : b - segTbl[b]; 623 b = b - segTbl[b] < 0 ? 0 : b - segTbl[b];
625 data[i] = qRgba(r, g, b, a); 624 data[i] = qRgba(r, g, b, a);
626 } 625 }
627 } 626 }
628 delete [] segTbl; 627 delete [] segTbl;
629 628
630 return image; 629 return image;
631} 630}
632 631
633QImage& OImageEffect::channelIntensity(QImage &image, float percent, 632QImage& OImageEffect::channelIntensity(QImage &image, float percent,
634 RGBComponent channel) 633 RGBComponent channel)
635{ 634{
636 if (image.width() == 0 || image.height() == 0) { 635 if (image.width() == 0 || image.height() == 0) {
637 qDebug( "WARNING: OImageEffect::channelIntensity : invalid image" ); 636 qDebug( "WARNING: OImageEffect::channelIntensity : invalid image" );
638 return image; 637 return image;
639 } 638 }
640 639
641 int segColors = image.depth() > 8 ? 256 : image.numColors(); 640 int segColors = image.depth() > 8 ? 256 : image.numColors();
642 unsigned char *segTbl = new unsigned char[segColors]; 641 unsigned char *segTbl = new unsigned char[segColors];
643 int pixels = image.depth() > 8 ? image.width()*image.height() : 642 int pixels = image.depth() > 8 ? image.width()*image.height() :
644 image.numColors(); 643 image.numColors();
645 unsigned int *data = image.depth() > 8 ? (unsigned int *)image.bits() : 644 unsigned int *data = image.depth() > 8 ? (unsigned int *)image.bits() :
646 (unsigned int *)image.colorTable(); 645 (unsigned int *)image.colorTable();
647 bool brighten = (percent >= 0); 646 bool brighten = (percent >= 0);
648 if(percent < 0) 647 if(percent < 0)
649 percent = -percent; 648 percent = -percent;
650 649
651 if(brighten){ // keep overflow check out of loops 650 if(brighten){ // keep overflow check out of loops
652 for(int i=0; i < segColors; ++i){ 651 for(int i=0; i < segColors; ++i){
653 int tmp = (int)(i*percent); 652 int tmp = (int)(i*percent);
654 if(tmp > 255) 653 if(tmp > 255)
655 tmp = 255; 654 tmp = 255;
656 segTbl[i] = tmp; 655 segTbl[i] = tmp;
657 } 656 }
658 } 657 }
659 else{ 658 else{
660 for(int i=0; i < segColors; ++i){ 659 for(int i=0; i < segColors; ++i){
661 int tmp = (int)(i*percent); 660 int tmp = (int)(i*percent);
662 if(tmp < 0) 661 if(tmp < 0)
663 tmp = 0; 662 tmp = 0;
664 segTbl[i] = tmp; 663 segTbl[i] = tmp;
665 } 664 }
666 } 665 }
667 666
668 if(brighten){ // same here 667 if(brighten){ // same here
669 if(channel == Red){ // and here ;-) 668 if(channel == Red){ // and here ;-)
670 for(int i=0; i < pixels; ++i){ 669 for(int i=0; i < pixels; ++i){
671 int c = qRed(data[i]); 670 int c = qRed(data[i]);
672 c = c + segTbl[c] > 255 ? 255 : c + segTbl[c]; 671 c = c + segTbl[c] > 255 ? 255 : c + segTbl[c];
673 data[i] = qRgba(c, qGreen(data[i]), qBlue(data[i]), qAlpha(data[i])); 672 data[i] = qRgba(c, qGreen(data[i]), qBlue(data[i]), qAlpha(data[i]));
674 } 673 }
675 } 674 }
676 if(channel == Green){ 675 if(channel == Green){
677 for(int i=0; i < pixels; ++i){ 676 for(int i=0; i < pixels; ++i){
678 int c = qGreen(data[i]); 677 int c = qGreen(data[i]);
679 c = c + segTbl[c] > 255 ? 255 : c + segTbl[c]; 678 c = c + segTbl[c] > 255 ? 255 : c + segTbl[c];
680 data[i] = qRgba(qRed(data[i]), c, qBlue(data[i]), qAlpha(data[i])); 679 data[i] = qRgba(qRed(data[i]), c, qBlue(data[i]), qAlpha(data[i]));
681 } 680 }
682 } 681 }
683 else{ 682 else{
684 for(int i=0; i < pixels; ++i){ 683 for(int i=0; i < pixels; ++i){
685 int c = qBlue(data[i]); 684 int c = qBlue(data[i]);
686 c = c + segTbl[c] > 255 ? 255 : c + segTbl[c]; 685 c = c + segTbl[c] > 255 ? 255 : c + segTbl[c];
687 data[i] = qRgba(qRed(data[i]), qGreen(data[i]), c, qAlpha(data[i])); 686 data[i] = qRgba(qRed(data[i]), qGreen(data[i]), c, qAlpha(data[i]));
688 } 687 }
689 } 688 }
690 689
691 } 690 }
692 else{ 691 else{
693 if(channel == Red){ 692 if(channel == Red){
694 for(int i=0; i < pixels; ++i){ 693 for(int i=0; i < pixels; ++i){
695 int c = qRed(data[i]); 694 int c = qRed(data[i]);
696 c = c - segTbl[c] < 0 ? 0 : c - segTbl[c]; 695 c = c - segTbl[c] < 0 ? 0 : c - segTbl[c];
697 data[i] = qRgba(c, qGreen(data[i]), qBlue(data[i]), qAlpha(data[i])); 696 data[i] = qRgba(c, qGreen(data[i]), qBlue(data[i]), qAlpha(data[i]));
698 } 697 }
699 } 698 }
700 if(channel == Green){ 699 if(channel == Green){
701 for(int i=0; i < pixels; ++i){ 700 for(int i=0; i < pixels; ++i){
702 int c = qGreen(data[i]); 701 int c = qGreen(data[i]);
703 c = c - segTbl[c] < 0 ? 0 : c - segTbl[c]; 702 c = c - segTbl[c] < 0 ? 0 : c - segTbl[c];
704 data[i] = qRgba(qRed(data[i]), c, qBlue(data[i]), qAlpha(data[i])); 703 data[i] = qRgba(qRed(data[i]), c, qBlue(data[i]), qAlpha(data[i]));
705 } 704 }
706 } 705 }
707 else{ 706 else{
708 for(int i=0; i < pixels; ++i){ 707 for(int i=0; i < pixels; ++i){
709 int c = qBlue(data[i]); 708 int c = qBlue(data[i]);
710 c = c - segTbl[c] < 0 ? 0 : c - segTbl[c]; 709 c = c - segTbl[c] < 0 ? 0 : c - segTbl[c];
711 data[i] = qRgba(qRed(data[i]), qGreen(data[i]), c, qAlpha(data[i])); 710 data[i] = qRgba(qRed(data[i]), qGreen(data[i]), c, qAlpha(data[i]));
712 } 711 }
713 } 712 }
714 } 713 }
715 delete [] segTbl; 714 delete [] segTbl;
716 715
717 return image; 716 return image;
718} 717}
719 718
720// Modulate an image with an RBG channel of another image 719// Modulate an image with an RBG channel of another image
721// 720//
722QImage& OImageEffect::modulate(QImage &image, QImage &modImage, bool reverse, 721QImage& OImageEffect::modulate(QImage &image, QImage &modImage, bool reverse,
723 ModulationType type, int factor, RGBComponent channel) 722 ModulationType type, int factor, RGBComponent channel)
724{ 723{
725 if (image.width() == 0 || image.height() == 0 || 724 if (image.width() == 0 || image.height() == 0 ||
726 modImage.width() == 0 || modImage.height() == 0) { 725 modImage.width() == 0 || modImage.height() == 0) {
727 qDebug( "WARNING: OImageEffect::modulate : invalid image" ); 726 qDebug( "WARNING: OImageEffect::modulate : invalid image" );
728 return image; 727 return image;
729 } 728 }
730 729
731 int r, g, b, h, s, v, a; 730 int r, g, b, h, s, v, a;
732 QColor clr; 731 QColor clr;
733 int mod=0; 732 int mod=0;
734 unsigned int x1, x2, y1, y2; 733 unsigned int x1, x2, y1, y2;
735 register int x, y; 734 register int x, y;
736 735
737 // for image, we handle only depth 32 736 // for image, we handle only depth 32
738 if (image.depth()<32) image = image.convertDepth(32); 737 if (image.depth()<32) image = image.convertDepth(32);
739 738
740 // for modImage, we handle depth 8 and 32 739 // for modImage, we handle depth 8 and 32
741 if (modImage.depth()<8) modImage = modImage.convertDepth(8); 740 if (modImage.depth()<8) modImage = modImage.convertDepth(8);
742 741
743 unsigned int *colorTable2 = (modImage.depth()==8) ? 742 unsigned int *colorTable2 = (modImage.depth()==8) ?
744 modImage.colorTable():0; 743 modImage.colorTable():0;
745 unsigned int *data1, *data2; 744 unsigned int *data1, *data2;
746 unsigned char *data2b; 745 unsigned char *data2b;
747 unsigned int color1, color2; 746 unsigned int color1, color2;
748 747
749 x1 = image.width(); y1 = image.height(); 748 x1 = image.width(); y1 = image.height();
750 x2 = modImage.width(); y2 = modImage.height(); 749 x2 = modImage.width(); y2 = modImage.height();
751 750
752 for (y = 0; y < (int)y1; y++) { 751 for (y = 0; y < (int)y1; y++) {
753 data1 = (unsigned int *) image.scanLine(y); 752 data1 = (unsigned int *) image.scanLine(y);
754 data2 = (unsigned int *) modImage.scanLine( y%y2 ); 753 data2 = (unsigned int *) modImage.scanLine( y%y2 );
755 data2b = (unsigned char *) modImage.scanLine( y%y2 ); 754 data2b = (unsigned char *) modImage.scanLine( y%y2 );
756 755
757 x=0; 756 x=0;
758 while(x < (int)x1) { 757 while(x < (int)x1) {
759 color2 = (colorTable2) ? colorTable2[*data2b] : *data2; 758 color2 = (colorTable2) ? colorTable2[*data2b] : *data2;
760 if (reverse) { 759 if (reverse) {
761 color1 = color2; 760 color1 = color2;
762 color2 = *data1; 761 color2 = *data1;
763 } 762 }
764 else 763 else
765 color1 = *data1; 764 color1 = *data1;
766 765
767 if (type == Intensity || type == Contrast) { 766 if (type == Intensity || type == Contrast) {
768 r = qRed(color1); 767 r = qRed(color1);
769 g = qGreen(color1); 768 g = qGreen(color1);
770 b = qBlue(color1); 769 b = qBlue(color1);
771 if (channel != All) { 770 if (channel != All) {
772 mod = (channel == Red) ? qRed(color2) : 771 mod = (channel == Red) ? qRed(color2) :
773 (channel == Green) ? qGreen(color2) : 772 (channel == Green) ? qGreen(color2) :
774 (channel == Blue) ? qBlue(color2) : 773 (channel == Blue) ? qBlue(color2) :
775 (channel == Gray) ? qGray(color2) : 0; 774 (channel == Gray) ? qGray(color2) : 0;
776 mod = mod*factor/50; 775 mod = mod*factor/50;
777 } 776 }
778 777
779 if (type == Intensity) { 778 if (type == Intensity) {
780 if (channel == All) { 779 if (channel == All) {
781 r += r * factor/50 * qRed(color2)/256; 780 r += r * factor/50 * qRed(color2)/256;
782 g += g * factor/50 * qGreen(color2)/256; 781 g += g * factor/50 * qGreen(color2)/256;
783 b += b * factor/50 * qBlue(color2)/256; 782 b += b * factor/50 * qBlue(color2)/256;
784 } 783 }
785 else { 784 else {
786 r += r * mod/256; 785 r += r * mod/256;
787 g += g * mod/256; 786 g += g * mod/256;
788 b += b * mod/256; 787 b += b * mod/256;
789 } 788 }
790 } 789 }
791 else { // Contrast 790 else { // Contrast
792 if (channel == All) { 791 if (channel == All) {
793 r += (r-128) * factor/50 * qRed(color2)/128; 792 r += (r-128) * factor/50 * qRed(color2)/128;
794 g += (g-128) * factor/50 * qGreen(color2)/128; 793 g += (g-128) * factor/50 * qGreen(color2)/128;
795 b += (b-128) * factor/50 * qBlue(color2)/128; 794 b += (b-128) * factor/50 * qBlue(color2)/128;
796 } 795 }
797 else { 796 else {
798 r += (r-128) * mod/128; 797 r += (r-128) * mod/128;
799 g += (g-128) * mod/128; 798 g += (g-128) * mod/128;
800 b += (b-128) * mod/128; 799 b += (b-128) * mod/128;
801 } 800 }
802 } 801 }
803 802
804 if (r<0) r=0; if (r>255) r=255; 803 if (r<0) r=0; if (r>255) r=255;
805 if (g<0) g=0; if (g>255) g=255; 804 if (g<0) g=0; if (g>255) g=255;
806 if (b<0) b=0; if (b>255) b=255; 805 if (b<0) b=0; if (b>255) b=255;
807 a = qAlpha(*data1); 806 a = qAlpha(*data1);
808 *data1 = qRgba(r, g, b, a); 807 *data1 = qRgba(r, g, b, a);
809 } 808 }
810 else if (type == Saturation || type == HueShift) { 809 else if (type == Saturation || type == HueShift) {
811 clr.setRgb(color1); 810 clr.setRgb(color1);
812 clr.hsv(&h, &s, &v); 811 clr.hsv(&h, &s, &v);
813 mod = (channel == Red) ? qRed(color2) : 812 mod = (channel == Red) ? qRed(color2) :
814 (channel == Green) ? qGreen(color2) : 813 (channel == Green) ? qGreen(color2) :
815 (channel == Blue) ? qBlue(color2) : 814 (channel == Blue) ? qBlue(color2) :
816 (channel == Gray) ? qGray(color2) : 0; 815 (channel == Gray) ? qGray(color2) : 0;
817 mod = mod*factor/50; 816 mod = mod*factor/50;
818 817
819 if (type == Saturation) { 818 if (type == Saturation) {
820 s -= s * mod/256; 819 s -= s * mod/256;
821 if (s<0) s=0; if (s>255) s=255; 820 if (s<0) s=0; if (s>255) s=255;
822 } 821 }
823 else { // HueShift 822 else { // HueShift
824 h += mod; 823 h += mod;
825 while(h<0) h+=360; 824 while(h<0) h+=360;
826 h %= 360; 825 h %= 360;
827 } 826 }
828 827
829 clr.setHsv(h, s, v); 828 clr.setHsv(h, s, v);
830 a = qAlpha(*data1); 829 a = qAlpha(*data1);
831 *data1 = clr.rgb() | ((uint)(a & 0xff) << 24); 830 *data1 = clr.rgb() | ((uint)(a & 0xff) << 24);
832 } 831 }
833 data1++; data2++; data2b++; x++; 832 data1++; data2++; data2b++; x++;
834 if ( (x%x2) ==0) { data2 -= x2; data2b -= x2; } 833 if ( (x%x2) ==0) { data2 -= x2; data2b -= x2; }
835 } 834 }
836 } 835 }
837 return image; 836 return image;
838} 837}
839 838
840 839
841 840
842//====================================================================== 841//======================================================================
843// 842//
844// Blend effects 843// Blend effects
845// 844//
846//====================================================================== 845//======================================================================
847 846
848 847
849// Nice and fast direct pixel manipulation 848// Nice and fast direct pixel manipulation
850QImage& OImageEffect::blend(const QColor& clr, QImage& dst, float opacity) 849QImage& OImageEffect::blend(const QColor& clr, QImage& dst, float opacity)
851{ 850{
852 if (dst.width() <= 0 || dst.height() <= 0) 851 if (dst.width() <= 0 || dst.height() <= 0)
853 return dst; 852 return dst;
854 853
855 if (opacity < 0.0 || opacity > 1.0) { 854 if (opacity < 0.0 || opacity > 1.0) {
856 qDebug( "WARNING: OImageEffect::blend : invalid opacity. Range [0, 1] "); 855 qDebug( "WARNING: OImageEffect::blend : invalid opacity. Range [0, 1] ");
857 return dst; 856 return dst;
858 } 857 }
859 858
860 int depth = dst.depth(); 859 int depth = dst.depth();
861 if (depth != 32) 860 if (depth != 32)
862 dst = dst.convertDepth(32); 861 dst = dst.convertDepth(32);
863 862
864 int pixels = dst.width() * dst.height(); 863 int pixels = dst.width() * dst.height();
865 int rcol, gcol, bcol; 864 int rcol, gcol, bcol;
866 clr.rgb(&rcol, &gcol, &bcol); 865 clr.rgb(&rcol, &gcol, &bcol);
867 866
868#ifdef WORDS_BIGENDIAN // ARGB (skip alpha) 867#ifdef WORDS_BIGENDIAN // ARGB (skip alpha)
869 register unsigned char *data = (unsigned char *)dst.bits() + 1; 868 register unsigned char *data = (unsigned char *)dst.bits() + 1;
870#else // BGRA 869#else // BGRA
871 register unsigned char *data = (unsigned char *)dst.bits(); 870 register unsigned char *data = (unsigned char *)dst.bits();
872#endif 871#endif
873 872
874 for (register int i=0; i<pixels; i++) 873 for (register int i=0; i<pixels; i++)
875 { 874 {
876#ifdef WORDS_BIGENDIAN 875#ifdef WORDS_BIGENDIAN
877 *(data++) += (unsigned char)((rcol - *data) * opacity); 876 *(data++) += (unsigned char)((rcol - *data) * opacity);
878 *(data++) += (unsigned char)((gcol - *data) * opacity); 877 *(data++) += (unsigned char)((gcol - *data) * opacity);
879 *(data++) += (unsigned char)((bcol - *data) * opacity); 878 *(data++) += (unsigned char)((bcol - *data) * opacity);
880#else 879#else
881 *(data++) += (unsigned char)((bcol - *data) * opacity); 880 *(data++) += (unsigned char)((bcol - *data) * opacity);
882 *(data++) += (unsigned char)((gcol - *data) * opacity); 881 *(data++) += (unsigned char)((gcol - *data) * opacity);
883 *(data++) += (unsigned char)((rcol - *data) * opacity); 882 *(data++) += (unsigned char)((rcol - *data) * opacity);
884#endif 883#endif
885 data++; // skip alpha 884 data++; // skip alpha
886 } 885 }
887 return dst; 886 return dst;
888} 887}
889 888
890// Nice and fast direct pixel manipulation 889// Nice and fast direct pixel manipulation
891QImage& OImageEffect::blend(QImage& src, QImage& dst, float opacity) 890QImage& OImageEffect::blend(QImage& src, QImage& dst, float opacity)
892{ 891{
893 if (src.width() <= 0 || src.height() <= 0) 892 if (src.width() <= 0 || src.height() <= 0)
894 return dst; 893 return dst;
895 if (dst.width() <= 0 || dst.height() <= 0) 894 if (dst.width() <= 0 || dst.height() <= 0)
896 return dst; 895 return dst;
897 896
898 if (src.width() != dst.width() || src.height() != dst.height()) { 897 if (src.width() != dst.width() || src.height() != dst.height()) {
899 qDebug( "WARNING: OImageEffect::blend : src and destination images are not the same size" ); 898 qDebug( "WARNING: OImageEffect::blend : src and destination images are not the same size" );
900 return dst; 899 return dst;
901 } 900 }
902 901
903 if (opacity < 0.0 || opacity > 1.0) { 902 if (opacity < 0.0 || opacity > 1.0) {
904 qDebug( "WARNING: OImageEffect::blend : invalid opacity. Range [0, 1]" ); 903 qDebug( "WARNING: OImageEffect::blend : invalid opacity. Range [0, 1]" );
905 return dst; 904 return dst;
906 } 905 }
907 906
908 if (src.depth() != 32) src = src.convertDepth(32); 907 if (src.depth() != 32) src = src.convertDepth(32);
909 if (dst.depth() != 32) dst = dst.convertDepth(32); 908 if (dst.depth() != 32) dst = dst.convertDepth(32);
910 909
911 int pixels = src.width() * src.height(); 910 int pixels = src.width() * src.height();
912#ifdef WORDS_BIGENDIAN // ARGB (skip alpha) 911#ifdef WORDS_BIGENDIAN // ARGB (skip alpha)
913 register unsigned char *data1 = (unsigned char *)dst.bits() + 1; 912 register unsigned char *data1 = (unsigned char *)dst.bits() + 1;
914 register unsigned char *data2 = (unsigned char *)src.bits() + 1; 913 register unsigned char *data2 = (unsigned char *)src.bits() + 1;
915#else // BGRA 914#else // BGRA
916 register unsigned char *data1 = (unsigned char *)dst.bits(); 915 register unsigned char *data1 = (unsigned char *)dst.bits();
917 register unsigned char *data2 = (unsigned char *)src.bits(); 916 register unsigned char *data2 = (unsigned char *)src.bits();
918#endif 917#endif
919 918
920 for (register int i=0; i<pixels; i++) 919 for (register int i=0; i<pixels; i++)
921 { 920 {
922#ifdef WORDS_BIGENDIAN 921#ifdef WORDS_BIGENDIAN
923 *(data1++) += (unsigned char)((*(data2++) - *data1) * opacity); 922 *(data1++) += (unsigned char)((*(data2++) - *data1) * opacity);
924 *(data1++) += (unsigned char)((*(data2++) - *data1) * opacity); 923 *(data1++) += (unsigned char)((*(data2++) - *data1) * opacity);
925 *(data1++) += (unsigned char)((*(data2++) - *data1) * opacity); 924 *(data1++) += (unsigned char)((*(data2++) - *data1) * opacity);
926#else 925#else
927 *(data1++) += (unsigned char)((*(data2++) - *data1) * opacity); 926 *(data1++) += (unsigned char)((*(data2++) - *data1) * opacity);
928 *(data1++) += (unsigned char)((*(data2++) - *data1) * opacity); 927 *(data1++) += (unsigned char)((*(data2++) - *data1) * opacity);
929 *(data1++) += (unsigned char)((*(data2++) - *data1) * opacity); 928 *(data1++) += (unsigned char)((*(data2++) - *data1) * opacity);
930#endif 929#endif
931 data1++; // skip alpha 930 data1++; // skip alpha
932 data2++; 931 data2++;
933 } 932 }
934 933
935 return dst; 934 return dst;
936} 935}
937 936
938 937
939QImage& OImageEffect::blend(QImage &image, float initial_intensity, 938QImage& OImageEffect::blend(QImage &image, float initial_intensity,
940 const QColor &bgnd, GradientType eff, 939 const QColor &bgnd, GradientType eff,
941 bool anti_dir) 940 bool anti_dir)
942{ 941{
943 if (image.width() == 0 || image.height() == 0 || image.depth()!=32 ) { 942 if (image.width() == 0 || image.height() == 0 || image.depth()!=32 ) {
944 qDebug( "WARNING: OImageEffect::blend : invalid image" ); 943 qDebug( "WARNING: OImageEffect::blend : invalid image" );
945 return image; 944 return image;
946 } 945 }
947 946
948 int r_bgnd = bgnd.red(), g_bgnd = bgnd.green(), b_bgnd = bgnd.blue(); 947 int r_bgnd = bgnd.red(), g_bgnd = bgnd.green(), b_bgnd = bgnd.blue();
949 int r, g, b; 948 int r, g, b;
950 int ind; 949 int ind;
951 950
952 unsigned int xi, xf, yi, yf; 951 unsigned int xi, xf, yi, yf;
953 unsigned int a; 952 unsigned int a;
954 953
955 // check the boundaries of the initial intesity param 954 // check the boundaries of the initial intesity param
956 float unaffected = 1; 955 float unaffected = 1;
957 if (initial_intensity > 1) initial_intensity = 1; 956 if (initial_intensity > 1) initial_intensity = 1;
958 if (initial_intensity < -1) initial_intensity = -1; 957 if (initial_intensity < -1) initial_intensity = -1;
959 if (initial_intensity < 0) { 958 if (initial_intensity < 0) {
960 unaffected = 1. + initial_intensity; 959 unaffected = 1. + initial_intensity;
961 initial_intensity = 0; 960 initial_intensity = 0;
962 } 961 }
963 962
964 963
965 float intensity = initial_intensity; 964 float intensity = initial_intensity;
966 float var = 1. - initial_intensity; 965 float var = 1. - initial_intensity;
967 966
968 if (anti_dir) { 967 if (anti_dir) {
969 initial_intensity = intensity = 1.; 968 initial_intensity = intensity = 1.;
970 var = -var; 969 var = -var;
971 } 970 }
972 971
973 register int x, y; 972 register int x, y;
974 973
975 unsigned int *data = (unsigned int *)image.bits(); 974 unsigned int *data = (unsigned int *)image.bits();
976 975
977 int image_width = image.width(); //Those can't change 976 int image_width = image.width(); //Those can't change
978 int image_height = image.height(); 977 int image_height = image.height();
979 978
980 979
981 if( eff == VerticalGradient || eff == HorizontalGradient ) { 980 if( eff == VerticalGradient || eff == HorizontalGradient ) {
982 981
983 // set the image domain to apply the effect to 982 // set the image domain to apply the effect to
984 xi = 0, xf = image_width; 983 xi = 0, xf = image_width;
985 yi = 0, yf = image_height; 984 yi = 0, yf = image_height;
986 if (eff == VerticalGradient) { 985 if (eff == VerticalGradient) {
987 if (anti_dir) yf = (int)(image_height * unaffected); 986 if (anti_dir) yf = (int)(image_height * unaffected);
988 else yi = (int)(image_height * (1 - unaffected)); 987 else yi = (int)(image_height * (1 - unaffected));
989 } 988 }
990 else { 989 else {
991 if (anti_dir) xf = (int)(image_width * unaffected); 990 if (anti_dir) xf = (int)(image_width * unaffected);
992 else xi = (int)(image_height * (1 - unaffected)); 991 else xi = (int)(image_height * (1 - unaffected));
993 } 992 }
994 993
995 var /= (eff == VerticalGradient?yf-yi:xf-xi); 994 var /= (eff == VerticalGradient?yf-yi:xf-xi);
996 995
997 int ind_base; 996 int ind_base;
998 for (y = yi; y < (int)yf; y++) { 997 for (y = yi; y < (int)yf; y++) {
999 intensity = eff == VerticalGradient? intensity + var : 998 intensity = eff == VerticalGradient? intensity + var :
1000 initial_intensity; 999 initial_intensity;
1001 ind_base = image_width * y ; 1000 ind_base = image_width * y ;
1002 for (x = xi; x < (int)xf ; x++) { 1001 for (x = xi; x < (int)xf ; x++) {
1003 if (eff == HorizontalGradient) intensity += var; 1002 if (eff == HorizontalGradient) intensity += var;
1004 ind = x + ind_base; 1003 ind = x + ind_base;
1005 r = qRed (data[ind]) + (int)(intensity * 1004 r = qRed (data[ind]) + (int)(intensity *
1006 (r_bgnd - qRed (data[ind]))); 1005 (r_bgnd - qRed (data[ind])));
1007 g = qGreen(data[ind]) + (int)(intensity * 1006 g = qGreen(data[ind]) + (int)(intensity *
1008 (g_bgnd - qGreen(data[ind]))); 1007 (g_bgnd - qGreen(data[ind])));
1009 b = qBlue (data[ind]) + (int)(intensity * 1008 b = qBlue (data[ind]) + (int)(intensity *
1010 (b_bgnd - qBlue (data[ind]))); 1009 (b_bgnd - qBlue (data[ind])));
1011 if (r > 255) r = 255; if (r < 0 ) r = 0; 1010 if (r > 255) r = 255; if (r < 0 ) r = 0;
1012 if (g > 255) g = 255; if (g < 0 ) g = 0; 1011 if (g > 255) g = 255; if (g < 0 ) g = 0;
1013 if (b > 255) b = 255; if (b < 0 ) b = 0; 1012 if (b > 255) b = 255; if (b < 0 ) b = 0;
1014 a = qAlpha(data[ind]); 1013 a = qAlpha(data[ind]);
1015 data[ind] = qRgba(r, g, b, a); 1014 data[ind] = qRgba(r, g, b, a);
1016 } 1015 }
1017 } 1016 }
1018 } 1017 }
1019 else if (eff == DiagonalGradient || eff == CrossDiagonalGradient) { 1018 else if (eff == DiagonalGradient || eff == CrossDiagonalGradient) {
1020 float xvar = var / 2 / image_width; // / unaffected; 1019 float xvar = var / 2 / image_width; // / unaffected;
1021 float yvar = var / 2 / image_height; // / unaffected; 1020 float yvar = var / 2 / image_height; // / unaffected;
1022 float tmp; 1021 float tmp;
1023 1022
1024 for (x = 0; x < image_width ; x++) { 1023 for (x = 0; x < image_width ; x++) {
1025 tmp = xvar * (eff == DiagonalGradient? x : image.width()-x-1); 1024 tmp = xvar * (eff == DiagonalGradient? x : image.width()-x-1);
1026 ind = x; 1025 ind = x;
1027 for (y = 0; y < image_height ; y++) { 1026 for (y = 0; y < image_height ; y++) {
1028 intensity = initial_intensity + tmp + yvar * y; 1027 intensity = initial_intensity + tmp + yvar * y;
1029 1028
1030 r = qRed (data[ind]) + (int)(intensity * 1029 r = qRed (data[ind]) + (int)(intensity *
1031 (r_bgnd - qRed (data[ind]))); 1030 (r_bgnd - qRed (data[ind])));
1032 g = qGreen(data[ind]) + (int)(intensity * 1031 g = qGreen(data[ind]) + (int)(intensity *
1033 (g_bgnd - qGreen(data[ind]))); 1032 (g_bgnd - qGreen(data[ind])));
1034 b = qBlue (data[ind]) + (int)(intensity * 1033 b = qBlue (data[ind]) + (int)(intensity *
1035 (b_bgnd - qBlue (data[ind]))); 1034 (b_bgnd - qBlue (data[ind])));
1036 if (r > 255) r = 255; if (r < 0 ) r = 0; 1035 if (r > 255) r = 255; if (r < 0 ) r = 0;
1037 if (g > 255) g = 255; if (g < 0 ) g = 0; 1036 if (g > 255) g = 255; if (g < 0 ) g = 0;
1038 if (b > 255) b = 255; if (b < 0 ) b = 0; 1037 if (b > 255) b = 255; if (b < 0 ) b = 0;
1039 a = qAlpha(data[ind]); 1038 a = qAlpha(data[ind]);
1040 data[ind] = qRgba(r, g, b, a); 1039 data[ind] = qRgba(r, g, b, a);
1041 1040
1042 ind += image_width; 1041 ind += image_width;
1043 } 1042 }
1044 } 1043 }
1045 } 1044 }
1046 1045
1047 else if (eff == RectangleGradient || eff == EllipticGradient) { 1046 else if (eff == RectangleGradient || eff == EllipticGradient) {
1048 float xvar; 1047 float xvar;
1049 float yvar; 1048 float yvar;
1050 1049
1051 for (x = 0; x < image_width / 2 + image_width % 2; x++) { 1050 for (x = 0; x < image_width / 2 + image_width % 2; x++) {
1052 xvar = var / image_width * (image_width - x*2/unaffected-1); 1051 xvar = var / image_width * (image_width - x*2/unaffected-1);
1053 for (y = 0; y < image_height / 2 + image_height % 2; y++) { 1052 for (y = 0; y < image_height / 2 + image_height % 2; y++) {
1054 yvar = var / image_height * (image_height - y*2/unaffected -1); 1053 yvar = var / image_height * (image_height - y*2/unaffected -1);
1055 1054
1056 if (eff == RectangleGradient) 1055 if (eff == RectangleGradient)
1057 intensity = initial_intensity + QMAX(xvar, yvar); 1056 intensity = initial_intensity + QMAX(xvar, yvar);
1058 else 1057 else
1059 intensity = initial_intensity + sqrt(xvar * xvar + yvar * yvar); 1058 intensity = initial_intensity + sqrt(xvar * xvar + yvar * yvar);
1060 if (intensity > 1) intensity = 1; 1059 if (intensity > 1) intensity = 1;
1061 if (intensity < 0) intensity = 0; 1060 if (intensity < 0) intensity = 0;
1062 1061
1063 //NW 1062 //NW
1064 ind = x + image_width * y ; 1063 ind = x + image_width * y ;
1065 r = qRed (data[ind]) + (int)(intensity * 1064 r = qRed (data[ind]) + (int)(intensity *
1066 (r_bgnd - qRed (data[ind]))); 1065 (r_bgnd - qRed (data[ind])));
1067 g = qGreen(data[ind]) + (int)(intensity * 1066 g = qGreen(data[ind]) + (int)(intensity *
1068 (g_bgnd - qGreen(data[ind]))); 1067 (g_bgnd - qGreen(data[ind])));
1069 b = qBlue (data[ind]) + (int)(intensity * 1068 b = qBlue (data[ind]) + (int)(intensity *
1070 (b_bgnd - qBlue (data[ind]))); 1069 (b_bgnd - qBlue (data[ind])));
1071 if (r > 255) r = 255; if (r < 0 ) r = 0; 1070 if (r > 255) r = 255; if (r < 0 ) r = 0;
1072 if (g > 255) g = 255; if (g < 0 ) g = 0; 1071 if (g > 255) g = 255; if (g < 0 ) g = 0;
1073 if (b > 255) b = 255; if (b < 0 ) b = 0; 1072 if (b > 255) b = 255; if (b < 0 ) b = 0;
1074 a = qAlpha(data[ind]); 1073 a = qAlpha(data[ind]);
1075 data[ind] = qRgba(r, g, b, a); 1074 data[ind] = qRgba(r, g, b, a);
1076 1075
1077 //NE 1076 //NE
1078 ind = image_width - x - 1 + image_width * y ; 1077 ind = image_width - x - 1 + image_width * y ;
1079 r = qRed (data[ind]) + (int)(intensity * 1078 r = qRed (data[ind]) + (int)(intensity *
1080 (r_bgnd - qRed (data[ind]))); 1079 (r_bgnd - qRed (data[ind])));
1081 g = qGreen(data[ind]) + (int)(intensity * 1080 g = qGreen(data[ind]) + (int)(intensity *
1082 (g_bgnd - qGreen(data[ind]))); 1081 (g_bgnd - qGreen(data[ind])));
1083 b = qBlue (data[ind]) + (int)(intensity * 1082 b = qBlue (data[ind]) + (int)(intensity *
1084 (b_bgnd - qBlue (data[ind]))); 1083 (b_bgnd - qBlue (data[ind])));
1085 if (r > 255) r = 255; if (r < 0 ) r = 0; 1084 if (r > 255) r = 255; if (r < 0 ) r = 0;
1086 if (g > 255) g = 255; if (g < 0 ) g = 0; 1085 if (g > 255) g = 255; if (g < 0 ) g = 0;
1087 if (b > 255) b = 255; if (b < 0 ) b = 0; 1086 if (b > 255) b = 255; if (b < 0 ) b = 0;
1088 a = qAlpha(data[ind]); 1087 a = qAlpha(data[ind]);
1089 data[ind] = qRgba(r, g, b, a); 1088 data[ind] = qRgba(r, g, b, a);
1090 } 1089 }
1091 } 1090 }
1092 1091
1093 //CT loop is doubled because of stupid central row/column issue. 1092 //CT loop is doubled because of stupid central row/column issue.
1094 // other solution? 1093 // other solution?
1095 for (x = 0; x < image_width / 2; x++) { 1094 for (x = 0; x < image_width / 2; x++) {
1096 xvar = var / image_width * (image_width - x*2/unaffected-1); 1095 xvar = var / image_width * (image_width - x*2/unaffected-1);
1097 for (y = 0; y < image_height / 2; y++) { 1096 for (y = 0; y < image_height / 2; y++) {
1098 yvar = var / image_height * (image_height - y*2/unaffected -1); 1097 yvar = var / image_height * (image_height - y*2/unaffected -1);
1099 1098
1100 if (eff == RectangleGradient) 1099 if (eff == RectangleGradient)
1101 intensity = initial_intensity + QMAX(xvar, yvar); 1100 intensity = initial_intensity + QMAX(xvar, yvar);
1102 else 1101 else
1103 intensity = initial_intensity + sqrt(xvar * xvar + yvar * yvar); 1102 intensity = initial_intensity + sqrt(xvar * xvar + yvar * yvar);
1104 if (intensity > 1) intensity = 1; 1103 if (intensity > 1) intensity = 1;
1105 if (intensity < 0) intensity = 0; 1104 if (intensity < 0) intensity = 0;
1106 1105
1107 //SW 1106 //SW
1108 ind = x + image_width * (image_height - y -1) ; 1107 ind = x + image_width * (image_height - y -1) ;
1109 r = qRed (data[ind]) + (int)(intensity * 1108 r = qRed (data[ind]) + (int)(intensity *
1110 (r_bgnd - qRed (data[ind]))); 1109 (r_bgnd - qRed (data[ind])));
1111 g = qGreen(data[ind]) + (int)(intensity * 1110 g = qGreen(data[ind]) + (int)(intensity *
1112 (g_bgnd - qGreen(data[ind]))); 1111 (g_bgnd - qGreen(data[ind])));
1113 b = qBlue (data[ind]) + (int)(intensity * 1112 b = qBlue (data[ind]) + (int)(intensity *
1114 (b_bgnd - qBlue (data[ind]))); 1113 (b_bgnd - qBlue (data[ind])));
1115 if (r > 255) r = 255; if (r < 0 ) r = 0; 1114 if (r > 255) r = 255; if (r < 0 ) r = 0;
1116 if (g > 255) g = 255; if (g < 0 ) g = 0; 1115 if (g > 255) g = 255; if (g < 0 ) g = 0;
1117 if (b > 255) b = 255; if (b < 0 ) b = 0; 1116 if (b > 255) b = 255; if (b < 0 ) b = 0;
1118 a = qAlpha(data[ind]); 1117 a = qAlpha(data[ind]);
1119 data[ind] = qRgba(r, g, b, a); 1118 data[ind] = qRgba(r, g, b, a);
1120 1119
1121 //SE 1120 //SE
1122 ind = image_width-x-1 + image_width * (image_height - y - 1) ; 1121 ind = image_width-x-1 + image_width * (image_height - y - 1) ;
1123 r = qRed (data[ind]) + (int)(intensity * 1122 r = qRed (data[ind]) + (int)(intensity *
1124 (r_bgnd - qRed (data[ind]))); 1123 (r_bgnd - qRed (data[ind])));
1125 g = qGreen(data[ind]) + (int)(intensity * 1124 g = qGreen(data[ind]) + (int)(intensity *
1126 (g_bgnd - qGreen(data[ind]))); 1125 (g_bgnd - qGreen(data[ind])));
1127 b = qBlue (data[ind]) + (int)(intensity * 1126 b = qBlue (data[ind]) + (int)(intensity *
1128 (b_bgnd - qBlue (data[ind]))); 1127 (b_bgnd - qBlue (data[ind])));
1129 if (r > 255) r = 255; if (r < 0 ) r = 0; 1128 if (r > 255) r = 255; if (r < 0 ) r = 0;
1130 if (g > 255) g = 255; if (g < 0 ) g = 0; 1129 if (g > 255) g = 255; if (g < 0 ) g = 0;
1131 if (b > 255) b = 255; if (b < 0 ) b = 0; 1130 if (b > 255) b = 255; if (b < 0 ) b = 0;
1132 a = qAlpha(data[ind]); 1131 a = qAlpha(data[ind]);
1133 data[ind] = qRgba(r, g, b, a); 1132 data[ind] = qRgba(r, g, b, a);
1134 } 1133 }
1135 } 1134 }
1136 } 1135 }
1137 else qDebug( "OImageEffect::blend effect not implemented" ); 1136 else qDebug( "OImageEffect::blend effect not implemented" );
1138 return image; 1137 return image;
1139} 1138}
1140 1139
1141// Not very efficient as we create a third big image... 1140// Not very efficient as we create a third big image...
1142// 1141//
1143QImage& OImageEffect::blend(QImage &image1, QImage &image2, 1142QImage& OImageEffect::blend(QImage &image1, QImage &image2,
1144 GradientType gt, int xf, int yf) 1143 GradientType gt, int xf, int yf)
1145{ 1144{
1146 if (image1.width() == 0 || image1.height() == 0 || 1145 if (image1.width() == 0 || image1.height() == 0 ||
1147 image2.width() == 0 || image2.height() == 0) 1146 image2.width() == 0 || image2.height() == 0)
1148 return image1; 1147 return image1;
1149 1148
1150 QImage image3; 1149 QImage image3;
1151 1150
1152 image3 = OImageEffect::unbalancedGradient(image1.size(), 1151 image3 = OImageEffect::unbalancedGradient(image1.size(),
1153 QColor(0,0,0), QColor(255,255,255), 1152 QColor(0,0,0), QColor(255,255,255),
1154 gt, xf, yf, 0); 1153 gt, xf, yf, 0);
1155 1154
1156 return blend(image1,image2,image3, Red); // Channel to use is arbitrary 1155 return blend(image1,image2,image3, Red); // Channel to use is arbitrary
1157} 1156}
1158 1157
1159// Blend image2 into image1, using an RBG channel of blendImage 1158// Blend image2 into image1, using an RBG channel of blendImage
1160// 1159//
1161QImage& OImageEffect::blend(QImage &image1, QImage &image2, 1160QImage& OImageEffect::blend(QImage &image1, QImage &image2,
1162 QImage &blendImage, RGBComponent channel) 1161 QImage &blendImage, RGBComponent channel)
1163{ 1162{
1164 if (image1.width() == 0 || image1.height() == 0 || 1163 if (image1.width() == 0 || image1.height() == 0 ||
1165 image2.width() == 0 || image2.height() == 0 || 1164 image2.width() == 0 || image2.height() == 0 ||
1166 blendImage.width() == 0 || blendImage.height() == 0) { 1165 blendImage.width() == 0 || blendImage.height() == 0) {
1167 qDebug( "OImageEffect::blend effect invalid image" ); 1166 qDebug( "OImageEffect::blend effect invalid image" );
1168 return image1; 1167 return image1;
1169 } 1168 }
1170 1169
1171 int r, g, b; 1170 int r, g, b;
1172 int ind1, ind2, ind3; 1171 int ind1, ind2, ind3;
1173 1172
1174 unsigned int x1, x2, x3, y1, y2, y3; 1173 unsigned int x1, x2, x3, y1, y2, y3;
1175 unsigned int a; 1174 unsigned int a;
1176 1175
1177 register int x, y; 1176 register int x, y;
1178 1177
1179 // for image1 and image2, we only handle depth 32 1178 // for image1 and image2, we only handle depth 32
1180 if (image1.depth()<32) image1 = image1.convertDepth(32); 1179 if (image1.depth()<32) image1 = image1.convertDepth(32);
1181 if (image2.depth()<32) image2 = image2.convertDepth(32); 1180 if (image2.depth()<32) image2 = image2.convertDepth(32);
1182 1181
1183 // for blendImage, we handle depth 8 and 32 1182 // for blendImage, we handle depth 8 and 32
1184 if (blendImage.depth()<8) blendImage = blendImage.convertDepth(8); 1183 if (blendImage.depth()<8) blendImage = blendImage.convertDepth(8);
1185 1184
1186 unsigned int *colorTable3 = (blendImage.depth()==8) ? 1185 unsigned int *colorTable3 = (blendImage.depth()==8) ?
1187 blendImage.colorTable():0; 1186 blendImage.colorTable():0;
1188 1187
1189 unsigned int *data1 = (unsigned int *)image1.bits(); 1188 unsigned int *data1 = (unsigned int *)image1.bits();
1190 unsigned int *data2 = (unsigned int *)image2.bits(); 1189 unsigned int *data2 = (unsigned int *)image2.bits();
1191 unsigned int *data3 = (unsigned int *)blendImage.bits(); 1190 unsigned int *data3 = (unsigned int *)blendImage.bits();
1192 unsigned char *data3b = (unsigned char *)blendImage.bits(); 1191 unsigned char *data3b = (unsigned char *)blendImage.bits();
1193 unsigned int color3; 1192 unsigned int color3;
1194 1193
1195 x1 = image1.width(); y1 = image1.height(); 1194 x1 = image1.width(); y1 = image1.height();
1196 x2 = image2.width(); y2 = image2.height(); 1195 x2 = image2.width(); y2 = image2.height();
1197 x3 = blendImage.width(); y3 = blendImage.height(); 1196 x3 = blendImage.width(); y3 = blendImage.height();
1198 1197
1199 for (y = 0; y < (int)y1; y++) { 1198 for (y = 0; y < (int)y1; y++) {
1200 ind1 = x1*y; 1199 ind1 = x1*y;
1201 ind2 = x2*(y%y2); 1200 ind2 = x2*(y%y2);
1202 ind3 = x3*(y%y3); 1201 ind3 = x3*(y%y3);
1203 1202
1204 x=0; 1203 x=0;
1205 while(x < (int)x1) { 1204 while(x < (int)x1) {
1206 color3 = (colorTable3) ? colorTable3[data3b[ind3]] : data3[ind3]; 1205 color3 = (colorTable3) ? colorTable3[data3b[ind3]] : data3[ind3];
1207 1206
1208 a = (channel == Red) ? qRed(color3) : 1207 a = (channel == Red) ? qRed(color3) :
1209 (channel == Green) ? qGreen(color3) : 1208 (channel == Green) ? qGreen(color3) :
1210 (channel == Blue) ? qBlue(color3) : qGray(color3); 1209 (channel == Blue) ? qBlue(color3) : qGray(color3);
1211 1210
1212 r = (a*qRed(data1[ind1]) + (256-a)*qRed(data2[ind2]))/256; 1211 r = (a*qRed(data1[ind1]) + (256-a)*qRed(data2[ind2]))/256;
1213 g = (a*qGreen(data1[ind1]) + (256-a)*qGreen(data2[ind2]))/256; 1212 g = (a*qGreen(data1[ind1]) + (256-a)*qGreen(data2[ind2]))/256;
1214 b = (a*qBlue(data1[ind1]) + (256-a)*qBlue(data2[ind2]))/256; 1213 b = (a*qBlue(data1[ind1]) + (256-a)*qBlue(data2[ind2]))/256;
1215 1214
1216 a = qAlpha(data1[ind1]); 1215 a = qAlpha(data1[ind1]);
1217 data1[ind1] = qRgba(r, g, b, a); 1216 data1[ind1] = qRgba(r, g, b, a);
1218 1217
1219 ind1++; ind2++; ind3++; x++; 1218 ind1++; ind2++; ind3++; x++;
1220 if ( (x%x2) ==0) ind2 -= x2; 1219 if ( (x%x2) ==0) ind2 -= x2;
1221 if ( (x%x3) ==0) ind3 -= x3; 1220 if ( (x%x3) ==0) ind3 -= x3;
1222 } 1221 }
1223 } 1222 }
1224 return image1; 1223 return image1;
1225} 1224}
1226 1225
1227 1226
1228//====================================================================== 1227//======================================================================
1229// 1228//
1230// Hash effects 1229// Hash effects
1231// 1230//
1232//====================================================================== 1231//======================================================================
1233 1232
1234unsigned int OImageEffect::lHash(unsigned int c) 1233unsigned int OImageEffect::lHash(unsigned int c)
1235{ 1234{
1236 unsigned char r = qRed(c), g = qGreen(c), b = qBlue(c), a = qAlpha(c); 1235 unsigned char r = qRed(c), g = qGreen(c), b = qBlue(c), a = qAlpha(c);
1237 unsigned char nr, ng, nb; 1236 unsigned char nr, ng, nb;
1238 nr =(r >> 1) + (r >> 2); nr = nr > r ? 0 : nr; 1237 nr =(r >> 1) + (r >> 2); nr = nr > r ? 0 : nr;
1239 ng =(g >> 1) + (g >> 2); ng = ng > g ? 0 : ng; 1238 ng =(g >> 1) + (g >> 2); ng = ng > g ? 0 : ng;
1240 nb =(b >> 1) + (b >> 2); nb = nb > b ? 0 : nb; 1239 nb =(b >> 1) + (b >> 2); nb = nb > b ? 0 : nb;
1241 1240
1242 return qRgba(nr, ng, nb, a); 1241 return qRgba(nr, ng, nb, a);
1243} 1242}
1244 1243
1245 1244
1246// ----------------------------------------------------------------------------- 1245// -----------------------------------------------------------------------------
1247 1246
1248unsigned int OImageEffect::uHash(unsigned int c) 1247unsigned int OImageEffect::uHash(unsigned int c)
1249{ 1248{
1250 unsigned char r = qRed(c), g = qGreen(c), b = qBlue(c), a = qAlpha(c); 1249 unsigned char r = qRed(c), g = qGreen(c), b = qBlue(c), a = qAlpha(c);
1251 unsigned char nr, ng, nb; 1250 unsigned char nr, ng, nb;
1252 nr = r + (r >> 3); nr = nr < r ? ~0 : nr; 1251 nr = r + (r >> 3); nr = nr < r ? ~0 : nr;
1253 ng = g + (g >> 3); ng = ng < g ? ~0 : ng; 1252 ng = g + (g >> 3); ng = ng < g ? ~0 : ng;
1254 nb = b + (b >> 3); nb = nb < b ? ~0 : nb; 1253 nb = b + (b >> 3); nb = nb < b ? ~0 : nb;
1255 1254
1256 return qRgba(nr, ng, nb, a); 1255 return qRgba(nr, ng, nb, a);
1257} 1256}
1258 1257
1259 1258
1260// ----------------------------------------------------------------------------- 1259// -----------------------------------------------------------------------------
1261 1260
1262QImage& OImageEffect::hash(QImage &image, Lighting lite, unsigned int spacing) 1261QImage& OImageEffect::hash(QImage &image, Lighting lite, unsigned int spacing)
1263{ 1262{
1264 if (image.width() == 0 || image.height() == 0) { 1263 if (image.width() == 0 || image.height() == 0) {
1265 qDebug( "OImageEffect::hash effect invalid image" ); 1264 qDebug( "OImageEffect::hash effect invalid image" );
1266 return image; 1265 return image;
1267 } 1266 }
1268 1267
1269 register int x, y; 1268 register int x, y;
1270 unsigned int *data = (unsigned int *)image.bits(); 1269 unsigned int *data = (unsigned int *)image.bits();
1271 unsigned int ind; 1270 unsigned int ind;
1272 1271
1273 //CT no need to do it if not enough space 1272 //CT no need to do it if not enough space
1274 if ((lite == NorthLite || 1273 if ((lite == NorthLite ||
1275 lite == SouthLite)&& 1274 lite == SouthLite)&&
1276 (unsigned)image.height() < 2+spacing) return image; 1275 (unsigned)image.height() < 2+spacing) return image;
1277 if ((lite == EastLite || 1276 if ((lite == EastLite ||
1278 lite == WestLite)&& 1277 lite == WestLite)&&
1279 (unsigned)image.height() < 2+spacing) return image; 1278 (unsigned)image.height() < 2+spacing) return image;
1280 1279
1281 if (lite == NorthLite || lite == SouthLite) { 1280 if (lite == NorthLite || lite == SouthLite) {
1282 for (y = 0 ; y < image.height(); y = y + 2 + spacing) { 1281 for (y = 0 ; y < image.height(); y = y + 2 + spacing) {
1283 for (x = 0; x < image.width(); x++) { 1282 for (x = 0; x < image.width(); x++) {
1284 ind = x + image.width() * y; 1283 ind = x + image.width() * y;
1285 data[ind] = lite==NorthLite?uHash(data[ind]):lHash(data[ind]); 1284 data[ind] = lite==NorthLite?uHash(data[ind]):lHash(data[ind]);
1286 1285
1287 ind = ind + image.width(); 1286 ind = ind + image.width();
1288 data[ind] = lite==NorthLite?lHash(data[ind]):uHash(data[ind]); 1287 data[ind] = lite==NorthLite?lHash(data[ind]):uHash(data[ind]);
1289 } 1288 }
1290 } 1289 }
1291 } 1290 }
1292 1291
1293 else if (lite == EastLite || lite == WestLite) { 1292 else if (lite == EastLite || lite == WestLite) {
1294 for (y = 0 ; y < image.height(); y++) { 1293 for (y = 0 ; y < image.height(); y++) {
1295 for (x = 0; x < image.width(); x = x + 2 + spacing) { 1294 for (x = 0; x < image.width(); x = x + 2 + spacing) {
1296 ind = x + image.width() * y; 1295 ind = x + image.width() * y;
1297 data[ind] = lite==EastLite?uHash(data[ind]):lHash(data[ind]); 1296 data[ind] = lite==EastLite?uHash(data[ind]):lHash(data[ind]);
1298 1297
1299 ind++; 1298 ind++;
1300 data[ind] = lite==EastLite?lHash(data[ind]):uHash(data[ind]); 1299 data[ind] = lite==EastLite?lHash(data[ind]):uHash(data[ind]);
1301 } 1300 }
1302 } 1301 }
1303 } 1302 }
1304 1303
1305 else if (lite == NWLite || lite == SELite) { 1304 else if (lite == NWLite || lite == SELite) {
1306 for (y = 0 ; y < image.height(); y++) { 1305 for (y = 0 ; y < image.height(); y++) {
1307 for (x = 0; 1306 for (x = 0;
1308 x < (int)(image.width() - ((y & 1)? 1 : 0) * spacing); 1307 x < (int)(image.width() - ((y & 1)? 1 : 0) * spacing);
1309 x = x + 2 + spacing) { 1308 x = x + 2 + spacing) {
1310 ind = x + image.width() * y + ((y & 1)? 1 : 0); 1309 ind = x + image.width() * y + ((y & 1)? 1 : 0);
1311 data[ind] = lite==NWLite?uHash(data[ind]):lHash(data[ind]); 1310 data[ind] = lite==NWLite?uHash(data[ind]):lHash(data[ind]);
1312 1311
1313 ind++; 1312 ind++;
1314 data[ind] = lite==NWLite?lHash(data[ind]):uHash(data[ind]); 1313 data[ind] = lite==NWLite?lHash(data[ind]):uHash(data[ind]);
1315 } 1314 }
1316 } 1315 }
1317 } 1316 }
1318 1317
1319 else if (lite == SWLite || lite == NELite) { 1318 else if (lite == SWLite || lite == NELite) {
1320 for (y = 0 ; y < image.height(); y++) { 1319 for (y = 0 ; y < image.height(); y++) {
1321 for (x = 0 + ((y & 1)? 1 : 0); x < image.width(); x = x + 2 + spacing) { 1320 for (x = 0 + ((y & 1)? 1 : 0); x < image.width(); x = x + 2 + spacing) {
1322 ind = x + image.width() * y - ((y & 1)? 1 : 0); 1321 ind = x + image.width() * y - ((y & 1)? 1 : 0);
1323 data[ind] = lite==SWLite?uHash(data[ind]):lHash(data[ind]); 1322 data[ind] = lite==SWLite?uHash(data[ind]):lHash(data[ind]);
1324 1323
1325 ind++; 1324 ind++;
1326 data[ind] = lite==SWLite?lHash(data[ind]):uHash(data[ind]); 1325 data[ind] = lite==SWLite?lHash(data[ind]):uHash(data[ind]);
1327 } 1326 }
1328 } 1327 }
1329 } 1328 }
1330 1329
1331 return image; 1330 return image;
1332} 1331}
1333 1332
1334 1333
1335//====================================================================== 1334//======================================================================
1336// 1335//
1337// Flatten effects 1336// Flatten effects
1338// 1337//
1339//====================================================================== 1338//======================================================================
1340 1339
1341QImage& OImageEffect::flatten(QImage &img, const QColor &ca, 1340QImage& OImageEffect::flatten(QImage &img, const QColor &ca,
1342 const QColor &cb, int ncols) 1341 const QColor &cb, int ncols)
1343{ 1342{
1344 if (img.width() == 0 || img.height() == 0) 1343 if (img.width() == 0 || img.height() == 0)
1345 return img; 1344 return img;
1346 1345
1347 // a bitmap is easy... 1346 // a bitmap is easy...
1348 if (img.depth() == 1) { 1347 if (img.depth() == 1) {
1349 img.setColor(0, ca.rgb()); 1348 img.setColor(0, ca.rgb());
1350 img.setColor(1, cb.rgb()); 1349 img.setColor(1, cb.rgb());
1351 return img; 1350 return img;
1352 } 1351 }
1353 1352
1354 int r1 = ca.red(); int r2 = cb.red(); 1353 int r1 = ca.red(); int r2 = cb.red();
1355 int g1 = ca.green(); int g2 = cb.green(); 1354 int g1 = ca.green(); int g2 = cb.green();
1356 int b1 = ca.blue(); int b2 = cb.blue(); 1355 int b1 = ca.blue(); int b2 = cb.blue();
1357 int min = 0, max = 255; 1356 int min = 0, max = 255;
1358 1357
1359 QRgb col; 1358 QRgb col;
1360 1359
1361 // Get minimum and maximum greylevel. 1360 // Get minimum and maximum greylevel.
1362 if (img.numColors()) { 1361 if (img.numColors()) {
1363 // pseudocolor 1362 // pseudocolor
1364 for (int i = 0; i < img.numColors(); i++) { 1363 for (int i = 0; i < img.numColors(); i++) {
1365 col = img.color(i); 1364 col = img.color(i);
1366 int mean = (qRed(col) + qGreen(col) + qBlue(col)) / 3; 1365 int mean = (qRed(col) + qGreen(col) + qBlue(col)) / 3;
1367 min = QMIN(min, mean); 1366 min = QMIN(min, mean);
1368 max = QMAX(max, mean); 1367 max = QMAX(max, mean);
1369 } 1368 }
1370 } else { 1369 } else {
1371 // truecolor 1370 // truecolor
1372 for (int y=0; y < img.height(); y++) 1371 for (int y=0; y < img.height(); y++)
1373 for (int x=0; x < img.width(); x++) { 1372 for (int x=0; x < img.width(); x++) {
1374 col = img.pixel(x, y); 1373 col = img.pixel(x, y);
1375 int mean = (qRed(col) + qGreen(col) + qBlue(col)) / 3; 1374 int mean = (qRed(col) + qGreen(col) + qBlue(col)) / 3;
1376 min = QMIN(min, mean); 1375 min = QMIN(min, mean);
1377 max = QMAX(max, mean); 1376 max = QMAX(max, mean);
1378 } 1377 }
1379 } 1378 }
1380 1379
1381 // Conversion factors 1380 // Conversion factors
1382 float sr = ((float) r2 - r1) / (max - min); 1381 float sr = ((float) r2 - r1) / (max - min);
1383 float sg = ((float) g2 - g1) / (max - min); 1382 float sg = ((float) g2 - g1) / (max - min);
1384 float sb = ((float) b2 - b1) / (max - min); 1383 float sb = ((float) b2 - b1) / (max - min);
1385 1384
1386 1385
1387 // Repaint the image 1386 // Repaint the image
1388 if (img.numColors()) { 1387 if (img.numColors()) {
1389 for (int i=0; i < img.numColors(); i++) { 1388 for (int i=0; i < img.numColors(); i++) {
1390 col = img.color(i); 1389 col = img.color(i);
1391 int mean = (qRed(col) + qGreen(col) + qBlue(col)) / 3; 1390 int mean = (qRed(col) + qGreen(col) + qBlue(col)) / 3;
1392 int r = (int) (sr * (mean - min) + r1 + 0.5); 1391 int r = (int) (sr * (mean - min) + r1 + 0.5);
1393 int g = (int) (sg * (mean - min) + g1 + 0.5); 1392 int g = (int) (sg * (mean - min) + g1 + 0.5);
1394 int b = (int) (sb * (mean - min) + b1 + 0.5); 1393 int b = (int) (sb * (mean - min) + b1 + 0.5);
1395 img.setColor(i, qRgba(r, g, b, qAlpha(col))); 1394 img.setColor(i, qRgba(r, g, b, qAlpha(col)));
1396 } 1395 }
1397 } else { 1396 } else {
1398 for (int y=0; y < img.height(); y++) 1397 for (int y=0; y < img.height(); y++)
1399 for (int x=0; x < img.width(); x++) { 1398 for (int x=0; x < img.width(); x++) {
1400 col = img.pixel(x, y); 1399 col = img.pixel(x, y);
1401 int mean = (qRed(col) + qGreen(col) + qBlue(col)) / 3; 1400 int mean = (qRed(col) + qGreen(col) + qBlue(col)) / 3;
1402 int r = (int) (sr * (mean - min) + r1 + 0.5); 1401 int r = (int) (sr * (mean - min) + r1 + 0.5);
1403 int g = (int) (sg * (mean - min) + g1 + 0.5); 1402 int g = (int) (sg * (mean - min) + g1 + 0.5);
1404 int b = (int) (sb * (mean - min) + b1 + 0.5); 1403 int b = (int) (sb * (mean - min) + b1 + 0.5);
1405 img.setPixel(x, y, qRgba(r, g, b, qAlpha(col))); 1404 img.setPixel(x, y, qRgba(r, g, b, qAlpha(col)));
1406 } 1405 }
1407 } 1406 }
1408 1407
1409 1408
1410 // Dither if necessary 1409 // Dither if necessary
1411 if ( (ncols <= 0) || ((img.numColors() != 0) && (img.numColors() <= ncols))) 1410 if ( (ncols <= 0) || ((img.numColors() != 0) && (img.numColors() <= ncols)))
1412 return img; 1411 return img;
1413 1412
1414 if (ncols == 1) ncols++; 1413 if (ncols == 1) ncols++;
1415 if (ncols > 256) ncols = 256; 1414 if (ncols > 256) ncols = 256;
1416 1415
1417 QColor *pal = new QColor[ncols]; 1416 QColor *pal = new QColor[ncols];
1418 sr = ((float) r2 - r1) / (ncols - 1); 1417 sr = ((float) r2 - r1) / (ncols - 1);
1419 sg = ((float) g2 - g1) / (ncols - 1); 1418 sg = ((float) g2 - g1) / (ncols - 1);
1420 sb = ((float) b2 - b1) / (ncols - 1); 1419 sb = ((float) b2 - b1) / (ncols - 1);
1421 1420
1422 for (int i=0; i<ncols; i++) 1421 for (int i=0; i<ncols; i++)
1423 pal[i] = QColor(r1 + int(sr*i), g1 + int(sg*i), b1 + int(sb*i)); 1422 pal[i] = QColor(r1 + int(sr*i), g1 + int(sg*i), b1 + int(sb*i));
1424 1423
1425 dither(img, pal, ncols); 1424 dither(img, pal, ncols);
1426 1425
1427 delete[] pal; 1426 delete[] pal;
1428 return img; 1427 return img;
1429} 1428}
1430 1429
1431 1430
1432//====================================================================== 1431//======================================================================
1433// 1432//
1434// Fade effects 1433// Fade effects
1435// 1434//
1436//====================================================================== 1435//======================================================================
1437 1436
1438QImage& OImageEffect::fade(QImage &img, float val, const QColor &color) 1437QImage& OImageEffect::fade(QImage &img, float val, const QColor &color)
1439{ 1438{
1440 if (img.width() == 0 || img.height() == 0) 1439 if (img.width() == 0 || img.height() == 0)
1441 return img; 1440 return img;
1442 1441
1443 // We don't handle bitmaps 1442 // We don't handle bitmaps
1444 if (img.depth() == 1) 1443 if (img.depth() == 1)
1445 return img; 1444 return img;
1446 1445
1447 unsigned char tbl[256]; 1446 unsigned char tbl[256];
1448 for (int i=0; i<256; i++) 1447 for (int i=0; i<256; i++)
1449 tbl[i] = (int) (val * i + 0.5); 1448 tbl[i] = (int) (val * i + 0.5);
1450 1449
1451 int red = color.red(); 1450 int red = color.red();
1452 int green = color.green(); 1451 int green = color.green();
1453 int blue = color.blue(); 1452 int blue = color.blue();
1454 1453
1455 QRgb col; 1454 QRgb col;
1456 int r, g, b, cr, cg, cb; 1455 int r, g, b, cr, cg, cb;
1457 1456
1458 if (img.depth() <= 8) { 1457 if (img.depth() <= 8) {
1459 // pseudo color 1458 // pseudo color
1460 for (int i=0; i<img.numColors(); i++) { 1459 for (int i=0; i<img.numColors(); i++) {
1461 col = img.color(i); 1460 col = img.color(i);
1462 cr = qRed(col); cg = qGreen(col); cb = qBlue(col); 1461 cr = qRed(col); cg = qGreen(col); cb = qBlue(col);
1463 if (cr > red) 1462 if (cr > red)
1464 r = cr - tbl[cr - red]; 1463 r = cr - tbl[cr - red];
1465 else 1464 else
1466 r = cr + tbl[red - cr]; 1465 r = cr + tbl[red - cr];
1467 if (cg > green) 1466 if (cg > green)
1468 g = cg - tbl[cg - green]; 1467 g = cg - tbl[cg - green];
1469 else 1468 else
1470 g = cg + tbl[green - cg]; 1469 g = cg + tbl[green - cg];
1471 if (cb > blue) 1470 if (cb > blue)
1472 b = cb - tbl[cb - blue]; 1471 b = cb - tbl[cb - blue];
1473 else 1472 else
1474 b = cb + tbl[blue - cb]; 1473 b = cb + tbl[blue - cb];
1475 img.setColor(i, qRgba(r, g, b, qAlpha(col))); 1474 img.setColor(i, qRgba(r, g, b, qAlpha(col)));
1476 } 1475 }
1477 1476
1478 } else { 1477 } else {
1479 // truecolor 1478 // truecolor
1480 for (int y=0; y<img.height(); y++) { 1479 for (int y=0; y<img.height(); y++) {
1481 QRgb *data = (QRgb *) img.scanLine(y); 1480 QRgb *data = (QRgb *) img.scanLine(y);
1482 for (int x=0; x<img.width(); x++) { 1481 for (int x=0; x<img.width(); x++) {
1483 col = *data; 1482 col = *data;
1484 cr = qRed(col); cg = qGreen(col); cb = qBlue(col); 1483 cr = qRed(col); cg = qGreen(col); cb = qBlue(col);
1485 if (cr > red) 1484 if (cr > red)
1486 r = cr - tbl[cr - red]; 1485 r = cr - tbl[cr - red];
1487 else 1486 else
1488 r = cr + tbl[red - cr]; 1487 r = cr + tbl[red - cr];
1489 if (cg > green) 1488 if (cg > green)
1490 g = cg - tbl[cg - green]; 1489 g = cg - tbl[cg - green];
1491 else 1490 else
1492 g = cg + tbl[green - cg]; 1491 g = cg + tbl[green - cg];
1493 if (cb > blue) 1492 if (cb > blue)
1494 b = cb - tbl[cb - blue]; 1493 b = cb - tbl[cb - blue];
1495 else 1494 else
1496 b = cb + tbl[blue - cb]; 1495 b = cb + tbl[blue - cb];
1497 *data++ = qRgba(r, g, b, qAlpha(col)); 1496 *data++ = qRgba(r, g, b, qAlpha(col));
1498 } 1497 }
1499 } 1498 }
1500 } 1499 }
1501 1500
1502 return img; 1501 return img;
1503} 1502}
1504 1503
1505//====================================================================== 1504//======================================================================
1506// 1505//
1507// Color effects 1506// Color effects
1508// 1507//
1509//====================================================================== 1508//======================================================================
1510 1509
1511// This code is adapted from code (C) Rik Hemsley <rik@kde.org> 1510// This code is adapted from code (C) Rik Hemsley <rik@kde.org>
1512// 1511//
1513// The formula used (r + b + g) /3 is different from the qGray formula 1512// The formula used (r + b + g) /3 is different from the qGray formula
1514// used by Qt. This is because our formula is much much faster. If, 1513// used by Qt. This is because our formula is much much faster. If,
1515// however, it turns out that this is producing sub-optimal images, 1514// however, it turns out that this is producing sub-optimal images,
1516// then it will have to change (kurt) 1515// then it will have to change (kurt)
1517// 1516//
1518// It does produce lower quality grayscale ;-) Use fast == true for the fast 1517// It does produce lower quality grayscale ;-) Use fast == true for the fast
1519// algorithm, false for the higher quality one (mosfet). 1518// algorithm, false for the higher quality one (mosfet).
1520QImage& OImageEffect::toGray(QImage &img, bool fast) 1519QImage& OImageEffect::toGray(QImage &img, bool fast)
1521{ 1520{
1522 if (img.width() == 0 || img.height() == 0) 1521 if (img.width() == 0 || img.height() == 0)
1523 return img; 1522 return img;
1524 1523
1525 if(fast){ 1524 if(fast){
1526 if (img.depth() == 32) { 1525 if (img.depth() == 32) {
1527 register uchar * r(img.bits()); 1526 register uchar * r(img.bits());
1528 register uchar * g(img.bits() + 1); 1527 register uchar * g(img.bits() + 1);
1529 register uchar * b(img.bits() + 2); 1528 register uchar * b(img.bits() + 2);
1530 1529
1531 uchar * end(img.bits() + img.numBytes()); 1530 uchar * end(img.bits() + img.numBytes());
1532 1531
1533 while (r != end) { 1532 while (r != end) {
1534 1533
1535 *r = *g = *b = (((*r + *g) >> 1) + *b) >> 1; // (r + b + g) / 3 1534 *r = *g = *b = (((*r + *g) >> 1) + *b) >> 1; // (r + b + g) / 3
1536 1535
1537 r += 4; 1536 r += 4;
1538 g += 4; 1537 g += 4;
1539 b += 4; 1538 b += 4;
1540 } 1539 }
1541 } 1540 }
1542 else 1541 else
1543 { 1542 {
1544 for (int i = 0; i < img.numColors(); i++) 1543 for (int i = 0; i < img.numColors(); i++)
1545 { 1544 {
1546 register uint r = qRed(img.color(i)); 1545 register uint r = qRed(img.color(i));
1547 register uint g = qGreen(img.color(i)); 1546 register uint g = qGreen(img.color(i));
1548 register uint b = qBlue(img.color(i)); 1547 register uint b = qBlue(img.color(i));
1549 1548
1550 register uint gray = (((r + g) >> 1) + b) >> 1; 1549 register uint gray = (((r + g) >> 1) + b) >> 1;
1551 img.setColor(i, qRgba(gray, gray, gray, qAlpha(img.color(i)))); 1550 img.setColor(i, qRgba(gray, gray, gray, qAlpha(img.color(i))));
1552 } 1551 }
1553 } 1552 }
1554 } 1553 }
1555 else{ 1554 else{
1556 int pixels = img.depth() > 8 ? img.width()*img.height() : 1555 int pixels = img.depth() > 8 ? img.width()*img.height() :
1557 img.numColors(); 1556 img.numColors();
1558 unsigned int *data = img.depth() > 8 ? (unsigned int *)img.bits() : 1557 unsigned int *data = img.depth() > 8 ? (unsigned int *)img.bits() :
1559 (unsigned int *)img.colorTable(); 1558 (unsigned int *)img.colorTable();
1560 int val, i; 1559 int val, i;
1561 for(i=0; i < pixels; ++i){ 1560 for(i=0; i < pixels; ++i){
1562 val = qGray(data[i]); 1561 val = qGray(data[i]);
1563 data[i] = qRgba(val, val, val, qAlpha(data[i])); 1562 data[i] = qRgba(val, val, val, qAlpha(data[i]));
1564 } 1563 }
1565 } 1564 }
1566 return img; 1565 return img;
1567} 1566}
1568 1567
1569// CT 29Jan2000 - desaturation algorithms 1568// CT 29Jan2000 - desaturation algorithms
1570QImage& OImageEffect::desaturate(QImage &img, float desat) 1569QImage& OImageEffect::desaturate(QImage &img, float desat)
1571{ 1570{
1572 if (img.width() == 0 || img.height() == 0) 1571 if (img.width() == 0 || img.height() == 0)
1573 return img; 1572 return img;
1574 1573
1575 if (desat < 0) desat = 0.; 1574 if (desat < 0) desat = 0.;
1576 if (desat > 1) desat = 1.; 1575 if (desat > 1) desat = 1.;
1577 int pixels = img.depth() > 8 ? img.width()*img.height() : 1576 int pixels = img.depth() > 8 ? img.width()*img.height() :
1578 img.numColors(); 1577 img.numColors();
1579 unsigned int *data = img.depth() > 8 ? (unsigned int *)img.bits() : 1578 unsigned int *data = img.depth() > 8 ? (unsigned int *)img.bits() :
1580 (unsigned int *)img.colorTable(); 1579 (unsigned int *)img.colorTable();
1581 int h, s, v, i; 1580 int h, s, v, i;
1582 QColor clr; // keep constructor out of loop (mosfet) 1581 QColor clr; // keep constructor out of loop (mosfet)
1583 for(i=0; i < pixels; ++i){ 1582 for(i=0; i < pixels; ++i){
1584 clr.setRgb(data[i]); 1583 clr.setRgb(data[i]);
1585 clr.hsv(&h, &s, &v); 1584 clr.hsv(&h, &s, &v);
1586 clr.setHsv(h, (int)(s * (1. - desat)), v); 1585 clr.setHsv(h, (int)(s * (1. - desat)), v);
1587 data[i] = clr.rgb(); 1586 data[i] = clr.rgb();
1588 } 1587 }
1589 return img; 1588 return img;
1590} 1589}
1591 1590
1592// Contrast stuff (mosfet) 1591// Contrast stuff (mosfet)
1593QImage& OImageEffect::contrast(QImage &img, int c) 1592QImage& OImageEffect::contrast(QImage &img, int c)
1594{ 1593{
1595 if (img.width() == 0 || img.height() == 0) 1594 if (img.width() == 0 || img.height() == 0)
1596 return img; 1595 return img;
1597 1596
1598 if(c > 255) 1597 if(c > 255)
1599 c = 255; 1598 c = 255;
1600 if(c < -255) 1599 if(c < -255)
1601 c = -255; 1600 c = -255;
1602 int pixels = img.depth() > 8 ? img.width()*img.height() : 1601 int pixels = img.depth() > 8 ? img.width()*img.height() :
1603 img.numColors(); 1602 img.numColors();
1604 unsigned int *data = img.depth() > 8 ? (unsigned int *)img.bits() : 1603 unsigned int *data = img.depth() > 8 ? (unsigned int *)img.bits() :
1605 (unsigned int *)img.colorTable(); 1604 (unsigned int *)img.colorTable();
1606 int i, r, g, b; 1605 int i, r, g, b;
1607 for(i=0; i < pixels; ++i){ 1606 for(i=0; i < pixels; ++i){
1608 r = qRed(data[i]); 1607 r = qRed(data[i]);
1609 g = qGreen(data[i]); 1608 g = qGreen(data[i]);
1610 b = qBlue(data[i]); 1609 b = qBlue(data[i]);
1611 if(qGray(data[i]) <= 127){ 1610 if(qGray(data[i]) <= 127){
1612 if(r - c <= 255) 1611 if(r - c <= 255)
1613 r -= c; 1612 r -= c;
1614 if(g - c <= 255) 1613 if(g - c <= 255)
1615 g -= c; 1614 g -= c;
1616 if(b - c <= 255) 1615 if(b - c <= 255)
1617 b -= c; 1616 b -= c;
1618 } 1617 }
1619 else{ 1618 else{
1620 if(r + c <= 255) 1619 if(r + c <= 255)
1621 r += c; 1620 r += c;
1622 if(g + c <= 255) 1621 if(g + c <= 255)
1623 g += c; 1622 g += c;
1624 if(b + c <= 255) 1623 if(b + c <= 255)
1625 b += c; 1624 b += c;
1626 } 1625 }
1627 data[i] = qRgba(r, g, b, qAlpha(data[i])); 1626 data[i] = qRgba(r, g, b, qAlpha(data[i]));
1628 } 1627 }
1629 return(img); 1628 return(img);
1630} 1629}
1631 1630
1632//====================================================================== 1631//======================================================================
1633// 1632//
1634// Dithering effects 1633// Dithering effects
1635// 1634//
1636//====================================================================== 1635//======================================================================
1637 1636
1638// adapted from kFSDither (C) 1997 Martin Jones (mjones@kde.org) 1637// adapted from kFSDither (C) 1997 Martin Jones (mjones@kde.org)
1639// 1638//
1640// Floyd-Steinberg dithering 1639// Floyd-Steinberg dithering
1641// Ref: Bitmapped Graphics Programming in C++ 1640// Ref: Bitmapped Graphics Programming in C++
1642// Marv Luse, Addison-Wesley Publishing, 1993. 1641// Marv Luse, Addison-Wesley Publishing, 1993.
1643QImage& OImageEffect::dither(QImage &img, const QColor *palette, int size) 1642QImage& OImageEffect::dither(QImage &img, const QColor *palette, int size)
1644{ 1643{
1645 if (img.width() == 0 || img.height() == 0 || 1644 if (img.width() == 0 || img.height() == 0 ||
1646 palette == 0 || img.depth() <= 8) 1645 palette == 0 || img.depth() <= 8)
1647 return img; 1646 return img;
1648 1647
1649 QImage dImage( img.width(), img.height(), 8, size ); 1648 QImage dImage( img.width(), img.height(), 8, size );
1650 int i; 1649 int i;
1651 1650
1652 dImage.setNumColors( size ); 1651 dImage.setNumColors( size );
1653 for ( i = 0; i < size; i++ ) 1652 for ( i = 0; i < size; i++ )
1654 dImage.setColor( i, palette[ i ].rgb() ); 1653 dImage.setColor( i, palette[ i ].rgb() );
1655 1654
1656 int *rerr1 = new int [ img.width() * 2 ]; 1655 int *rerr1 = new int [ img.width() * 2 ];
1657 int *gerr1 = new int [ img.width() * 2 ]; 1656 int *gerr1 = new int [ img.width() * 2 ];
1658 int *berr1 = new int [ img.width() * 2 ]; 1657 int *berr1 = new int [ img.width() * 2 ];
1659 1658
1660 memset( rerr1, 0, sizeof( int ) * img.width() * 2 ); 1659 memset( rerr1, 0, sizeof( int ) * img.width() * 2 );
1661 memset( gerr1, 0, sizeof( int ) * img.width() * 2 ); 1660 memset( gerr1, 0, sizeof( int ) * img.width() * 2 );
1662 memset( berr1, 0, sizeof( int ) * img.width() * 2 ); 1661 memset( berr1, 0, sizeof( int ) * img.width() * 2 );
1663 1662
1664 int *rerr2 = rerr1 + img.width(); 1663 int *rerr2 = rerr1 + img.width();
1665 int *gerr2 = gerr1 + img.width(); 1664 int *gerr2 = gerr1 + img.width();
1666 int *berr2 = berr1 + img.width(); 1665 int *berr2 = berr1 + img.width();
1667 1666
1668 for ( int j = 0; j < img.height(); j++ ) 1667 for ( int j = 0; j < img.height(); j++ )
1669 { 1668 {
1670 uint *ip = (uint * )img.scanLine( j ); 1669 uint *ip = (uint * )img.scanLine( j );
1671 uchar *dp = dImage.scanLine( j ); 1670 uchar *dp = dImage.scanLine( j );
1672 1671
1673 for ( i = 0; i < img.width(); i++ ) 1672 for ( i = 0; i < img.width(); i++ )
1674 { 1673 {
1675 rerr1[i] = rerr2[i] + qRed( *ip ); 1674 rerr1[i] = rerr2[i] + qRed( *ip );
1676 rerr2[i] = 0; 1675 rerr2[i] = 0;
1677 gerr1[i] = gerr2[i] + qGreen( *ip ); 1676 gerr1[i] = gerr2[i] + qGreen( *ip );
1678 gerr2[i] = 0; 1677 gerr2[i] = 0;
1679 berr1[i] = berr2[i] + qBlue( *ip ); 1678 berr1[i] = berr2[i] + qBlue( *ip );
1680 berr2[i] = 0; 1679 berr2[i] = 0;
1681 ip++; 1680 ip++;
1682 } 1681 }
1683 1682
1684 *dp++ = nearestColor( rerr1[0], gerr1[0], berr1[0], palette, size ); 1683 *dp++ = nearestColor( rerr1[0], gerr1[0], berr1[0], palette, size );
1685 1684
1686 for ( i = 1; i < img.width()-1; i++ ) 1685 for ( i = 1; i < img.width()-1; i++ )
1687 { 1686 {
1688 int indx = nearestColor( rerr1[i], gerr1[i], berr1[i], palette, size ); 1687 int indx = nearestColor( rerr1[i], gerr1[i], berr1[i], palette, size );
1689 *dp = indx; 1688 *dp = indx;
1690 1689
1691 int rerr = rerr1[i]; 1690 int rerr = rerr1[i];
1692 rerr -= palette[indx].red(); 1691 rerr -= palette[indx].red();
1693 int gerr = gerr1[i]; 1692 int gerr = gerr1[i];
1694 gerr -= palette[indx].green(); 1693 gerr -= palette[indx].green();
1695 int berr = berr1[i]; 1694 int berr = berr1[i];
1696 berr -= palette[indx].blue(); 1695 berr -= palette[indx].blue();
1697 1696
1698 // diffuse red error 1697 // diffuse red error
1699 rerr1[ i+1 ] += ( rerr * 7 ) >> 4; 1698 rerr1[ i+1 ] += ( rerr * 7 ) >> 4;
1700 rerr2[ i-1 ] += ( rerr * 3 ) >> 4; 1699 rerr2[ i-1 ] += ( rerr * 3 ) >> 4;
1701 rerr2[ i ] += ( rerr * 5 ) >> 4; 1700 rerr2[ i ] += ( rerr * 5 ) >> 4;
1702 rerr2[ i+1 ] += ( rerr ) >> 4; 1701 rerr2[ i+1 ] += ( rerr ) >> 4;
1703 1702
1704 // diffuse green error 1703 // diffuse green error
1705 gerr1[ i+1 ] += ( gerr * 7 ) >> 4; 1704 gerr1[ i+1 ] += ( gerr * 7 ) >> 4;
1706 gerr2[ i-1 ] += ( gerr * 3 ) >> 4; 1705 gerr2[ i-1 ] += ( gerr * 3 ) >> 4;
1707 gerr2[ i ] += ( gerr * 5 ) >> 4; 1706 gerr2[ i ] += ( gerr * 5 ) >> 4;
1708 gerr2[ i+1 ] += ( gerr ) >> 4; 1707 gerr2[ i+1 ] += ( gerr ) >> 4;
1709 1708
1710 // diffuse red error 1709 // diffuse red error
1711 berr1[ i+1 ] += ( berr * 7 ) >> 4; 1710 berr1[ i+1 ] += ( berr * 7 ) >> 4;
1712 berr2[ i-1 ] += ( berr * 3 ) >> 4; 1711 berr2[ i-1 ] += ( berr * 3 ) >> 4;
1713 berr2[ i ] += ( berr * 5 ) >> 4; 1712 berr2[ i ] += ( berr * 5 ) >> 4;
1714 berr2[ i+1 ] += ( berr ) >> 4; 1713 berr2[ i+1 ] += ( berr ) >> 4;
1715 1714
1716 dp++; 1715 dp++;
1717 } 1716 }
1718 1717
1719 *dp = nearestColor( rerr1[i], gerr1[i], berr1[i], palette, size ); 1718 *dp = nearestColor( rerr1[i], gerr1[i], berr1[i], palette, size );
1720 } 1719 }
1721 1720
1722 delete [] rerr1; 1721 delete [] rerr1;
1723 delete [] gerr1; 1722 delete [] gerr1;
1724 delete [] berr1; 1723 delete [] berr1;
1725 1724
1726 img = dImage; 1725 img = dImage;
1727 return img; 1726 return img;
1728} 1727}
1729 1728
1730int OImageEffect::nearestColor( int r, int g, int b, const QColor *palette, int size ) 1729int OImageEffect::nearestColor( int r, int g, int b, const QColor *palette, int size )
1731{ 1730{
1732 if (palette == 0) 1731 if (palette == 0)
1733 return 0; 1732 return 0;
1734 1733
1735 int dr = palette[0].red() - r; 1734 int dr = palette[0].red() - r;
1736 int dg = palette[0].green() - g; 1735 int dg = palette[0].green() - g;
1737 int db = palette[0].blue() - b; 1736 int db = palette[0].blue() - b;
1738 1737
1739 int minDist = dr*dr + dg*dg + db*db; 1738 int minDist = dr*dr + dg*dg + db*db;
1740 int nearest = 0; 1739 int nearest = 0;
1741 1740
1742 for (int i = 1; i < size; i++ ) 1741 for (int i = 1; i < size; i++ )
1743 { 1742 {
1744 dr = palette[i].red() - r; 1743 dr = palette[i].red() - r;
1745 dg = palette[i].green() - g; 1744 dg = palette[i].green() - g;
1746 db = palette[i].blue() - b; 1745 db = palette[i].blue() - b;
1747 1746
1748 int dist = dr*dr + dg*dg + db*db; 1747 int dist = dr*dr + dg*dg + db*db;
1749 1748
1750 if ( dist < minDist ) 1749 if ( dist < minDist )
1751 { 1750 {
1752 minDist = dist; 1751 minDist = dist;
1753 nearest = i; 1752 nearest = i;
1754 } 1753 }
1755 } 1754 }
1756 1755
1757 return nearest; 1756 return nearest;
1758} 1757}
1759 1758
1760bool OImageEffect::blend( 1759bool OImageEffect::blend(
1761 const QImage & upper, 1760 const QImage & upper,
1762 const QImage & lower, 1761 const QImage & lower,
1763 QImage & output 1762 QImage & output
1764) 1763)
1765{ 1764{
1766 if ( 1765 if (
1767 upper.width() > lower.width() || 1766 upper.width() > lower.width() ||
1768 upper.height() > lower.height() || 1767 upper.height() > lower.height() ||
1769 upper.depth() != 32 || 1768 upper.depth() != 32 ||
1770 lower.depth() != 32 1769 lower.depth() != 32
1771 ) 1770 )
1772 { 1771 {
1773 qDebug( "OImageEffect::blend : Sizes not correct" ); 1772 qDebug( "OImageEffect::blend : Sizes not correct" );
1774 return false; 1773 return false;
1775 } 1774 }
1776 1775
1777 output = lower.copy(); 1776 output = lower.copy();
1778 1777
1779 register uchar *i, *o; 1778 register uchar *i, *o;
1780 register int a; 1779 register int a;
1781 register int col; 1780 register int col;
1782 register int w = upper.width(); 1781 register int w = upper.width();
1783 int row(upper.height() - 1); 1782 int row(upper.height() - 1);
1784 1783
1785 do { 1784 do {
1786 1785
1787 i = upper.scanLine(row); 1786 i = upper.scanLine(row);
1788 o = output.scanLine(row); 1787 o = output.scanLine(row);
1789 1788
1790 col = w << 2; 1789 col = w << 2;
1791 --col; 1790 --col;
1792 1791
1793 do { 1792 do {
1794 1793
1795 while (!(a = i[col]) && (col != 3)) { 1794 while (!(a = i[col]) && (col != 3)) {
1796 --col; --col; --col; --col; 1795 --col; --col; --col; --col;
1797 } 1796 }
1798 1797
1799 --col; 1798 --col;
1800 o[col] += ((i[col] - o[col]) * a) >> 8; 1799 o[col] += ((i[col] - o[col]) * a) >> 8;
1801 1800
1802 --col; 1801 --col;
1803 o[col] += ((i[col] - o[col]) * a) >> 8; 1802 o[col] += ((i[col] - o[col]) * a) >> 8;
1804 1803
1805 --col; 1804 --col;
1806 o[col] += ((i[col] - o[col]) * a) >> 8; 1805 o[col] += ((i[col] - o[col]) * a) >> 8;
1807 1806
1808 } while (col--); 1807 } while (col--);
1809 1808
1810 } while (row--); 1809 } while (row--);
1811 1810
1812 return true; 1811 return true;
1813} 1812}
1814 1813
1815#if 0 1814#if 0
1816// Not yet... 1815// Not yet...
1817bool OImageEffect::blend( 1816bool OImageEffect::blend(
1818 const QImage & upper, 1817 const QImage & upper,
1819 const QImage & lower, 1818 const QImage & lower,
1820 QImage & output, 1819 QImage & output,
1821 const QRect & destRect 1820 const QRect & destRect
1822) 1821)
1823{ 1822{
1824 output = lower.copy(); 1823 output = lower.copy();
1825 return output; 1824 return output;
1826} 1825}
1827 1826
1828#endif 1827#endif
1829 1828
1830bool OImageEffect::blend( 1829bool OImageEffect::blend(
1831 int &x, int &y, 1830 int &x, int &y,
1832 const QImage & upper, 1831 const QImage & upper,
1833 const QImage & lower, 1832 const QImage & lower,
1834 QImage & output 1833 QImage & output
1835) 1834)
1836{ 1835{
1837 int cx=0, cy=0, cw=upper.width(), ch=upper.height(); 1836 int cx=0, cy=0, cw=upper.width(), ch=upper.height();
1838 1837
1839 if ( upper.width() + x > lower.width() || 1838 if ( upper.width() + x > lower.width() ||
1840 upper.height() + y > lower.height() || 1839 upper.height() + y > lower.height() ||
1841 x < 0 || y < 0 || 1840 x < 0 || y < 0 ||
1842 upper.depth() != 32 || lower.depth() != 32 ) 1841 upper.depth() != 32 || lower.depth() != 32 )
1843 { 1842 {
1844 if ( x > lower.width() || y > lower.height() ) return false; 1843 if ( x > lower.width() || y > lower.height() ) return false;
1845 if ( upper.width()<=0 || upper.height() <= 0 ) return false; 1844 if ( upper.width()<=0 || upper.height() <= 0 ) return false;
1846 if ( lower.width()<=0 || lower.height() <= 0 ) return false; 1845 if ( lower.width()<=0 || lower.height() <= 0 ) return false;
1847 1846
1848 if (x<0) {cx=-x; cw+=x; x=0; }; 1847 if (x<0) {cx=-x; cw+=x; x=0; };
1849 if (cw + x > lower.width()) { cw=lower.width()-x; }; 1848 if (cw + x > lower.width()) { cw=lower.width()-x; };
1850 if (y<0) {cy=-y; ch+=y; y=0; }; 1849 if (y<0) {cy=-y; ch+=y; y=0; };
1851 if (ch + y > lower.height()) { ch=lower.height()-y; }; 1850 if (ch + y > lower.height()) { ch=lower.height()-y; };
1852 1851
1853 if ( cx >= upper.width() || cy >= upper.height() ) return true; 1852 if ( cx >= upper.width() || cy >= upper.height() ) return true;
1854 if ( cw <= 0 || ch <= 0 ) return true; 1853 if ( cw <= 0 || ch <= 0 ) return true;
1855 } 1854 }
1856 1855
1857 output.create(cw,ch,32); 1856 output.create(cw,ch,32);
1858// output.setAlphaBuffer(true); // I should do some benchmarks to see if 1857// output.setAlphaBuffer(true); // I should do some benchmarks to see if
1859 // this is worth the effort 1858 // this is worth the effort
1860 1859
1861 register QRgb *i, *o, *b; 1860 register QRgb *i, *o, *b;
1862 1861
1863 register int a; 1862 register int a;
1864 register int j,k; 1863 register int j,k;
1865 for (j=0; j<ch; j++) 1864 for (j=0; j<ch; j++)
1866 { 1865 {
1867 b=reinterpret_cast<QRgb *>(&lower.scanLine(y+j) [ (x+cw) << 2 ]); 1866 b=reinterpret_cast<QRgb *>(&lower.scanLine(y+j) [ (x+cw) << 2 ]);
1868 i=reinterpret_cast<QRgb *>(&upper.scanLine(cy+j)[ (cx+cw) << 2 ]); 1867 i=reinterpret_cast<QRgb *>(&upper.scanLine(cy+j)[ (cx+cw) << 2 ]);
1869 o=reinterpret_cast<QRgb *>(&output.scanLine(j) [ cw << 2 ]); 1868 o=reinterpret_cast<QRgb *>(&output.scanLine(j) [ cw << 2 ]);
1870 1869
1871 k=cw-1; 1870 k=cw-1;
1872 --b; --i; --o; 1871 --b; --i; --o;
1873 do 1872 do
1874 { 1873 {
1875 while ( !(a=qAlpha(*i)) && k>0 ) 1874 while ( !(a=qAlpha(*i)) && k>0 )
1876 { 1875 {
1877 i--; 1876 i--;
1878 //*o=0; 1877 //*o=0;
1879 *o=*b; 1878 *o=*b;
1880 --o; --b; 1879 --o; --b;
1881 k--; 1880 k--;
1882 }; 1881 };
1883// *o=0xFF; 1882// *o=0xFF;
1884 *o = qRgb(qRed(*b) + (((qRed(*i) - qRed(*b)) * a) >> 8), 1883 *o = qRgb(qRed(*b) + (((qRed(*i) - qRed(*b)) * a) >> 8),
1885 qGreen(*b) + (((qGreen(*i) - qGreen(*b)) * a) >> 8), 1884 qGreen(*b) + (((qGreen(*i) - qGreen(*b)) * a) >> 8),
1886 qBlue(*b) + (((qBlue(*i) - qBlue(*b)) * a) >> 8)); 1885 qBlue(*b) + (((qBlue(*i) - qBlue(*b)) * a) >> 8));
1887 --i; --o; --b; 1886 --i; --o; --b;
1888 } while (k--); 1887 } while (k--);
1889 } 1888 }
1890 1889
1891 return true; 1890 return true;
1892} 1891}
1893 1892
1894bool OImageEffect::blendOnLower( 1893bool OImageEffect::blendOnLower(
1895 int x, int y, 1894 int x, int y,
1896 const QImage & upper, 1895 const QImage & upper,
1897 const QImage & lower 1896 const QImage & lower
1898) 1897)
1899{ 1898{
1900 int cx=0, cy=0, cw=upper.width(), ch=upper.height(); 1899 int cx=0, cy=0, cw=upper.width(), ch=upper.height();
1901 1900
1902 if ( upper.depth() != 32 || lower.depth() != 32 ) return false; 1901 if ( upper.depth() != 32 || lower.depth() != 32 ) return false;
1903 if ( x + cw > lower.width() || 1902 if ( x + cw > lower.width() ||
1904 y + ch > lower.height() || 1903 y + ch > lower.height() ||
1905 x < 0 || y < 0 ) 1904 x < 0 || y < 0 )
1906 { 1905 {
1907 if ( x > lower.width() || y > lower.height() ) return true; 1906 if ( x > lower.width() || y > lower.height() ) return true;
1908 if ( upper.width()<=0 || upper.height() <= 0 ) return true; 1907 if ( upper.width()<=0 || upper.height() <= 0 ) return true;
1909 if ( lower.width()<=0 || lower.height() <= 0 ) return true; 1908 if ( lower.width()<=0 || lower.height() <= 0 ) return true;
1910 1909
1911 if (x<0) {cx=-x; cw+=x; x=0; }; 1910 if (x<0) {cx=-x; cw+=x; x=0; };
1912 if (cw + x > lower.width()) { cw=lower.width()-x; }; 1911 if (cw + x > lower.width()) { cw=lower.width()-x; };
1913 if (y<0) {cy=-y; ch+=y; y=0; }; 1912 if (y<0) {cy=-y; ch+=y; y=0; };
1914 if (ch + y > lower.height()) { ch=lower.height()-y; }; 1913 if (ch + y > lower.height()) { ch=lower.height()-y; };
1915 1914
1916 if ( cx >= upper.width() || cy >= upper.height() ) return true; 1915 if ( cx >= upper.width() || cy >= upper.height() ) return true;
1917 if ( cw <= 0 || ch <= 0 ) return true; 1916 if ( cw <= 0 || ch <= 0 ) return true;
1918 } 1917 }
1919 1918
1920 register uchar *i, *b; 1919 register uchar *i, *b;
1921 register int a; 1920 register int a;
1922 register int k; 1921 register int k;
1923 1922
1924 for (int j=0; j<ch; j++) 1923 for (int j=0; j<ch; j++)
1925 { 1924 {
1926 b=&lower.scanLine(y+j) [ (x+cw) << 2 ]; 1925 b=&lower.scanLine(y+j) [ (x+cw) << 2 ];
1927 i=&upper.scanLine(cy+j)[ (cx+cw) << 2 ]; 1926 i=&upper.scanLine(cy+j)[ (cx+cw) << 2 ];
1928 1927
1929 k=cw-1; 1928 k=cw-1;
1930 --b; --i; 1929 --b; --i;
1931 do 1930 do
1932 { 1931 {
1933#ifndef WORDS_BIGENDIAN 1932#ifndef WORDS_BIGENDIAN
1934 while ( !(a=*i) && k>0 ) 1933 while ( !(a=*i) && k>0 )
1935#else 1934#else
1936 while ( !(a=*(i-3)) && k>0 ) 1935 while ( !(a=*(i-3)) && k>0 )
1937#endif 1936#endif
1938 { 1937 {
1939 i-=4; b-=4; k--; 1938 i-=4; b-=4; k--;
1940 }; 1939 };
1941 1940
1942#ifndef WORDS_BIGENDIAN 1941#ifndef WORDS_BIGENDIAN
1943 --i; --b; 1942 --i; --b;
1944 *b += ( ((*i - *b) * a) >> 8 ); 1943 *b += ( ((*i - *b) * a) >> 8 );
1945 --i; --b; 1944 --i; --b;
1946 *b += ( ((*i - *b) * a) >> 8 ); 1945 *b += ( ((*i - *b) * a) >> 8 );
1947 --i; --b; 1946 --i; --b;
1948 *b += ( ((*i - *b) * a) >> 8 ); 1947 *b += ( ((*i - *b) * a) >> 8 );
1949 --i; --b; 1948 --i; --b;
1950#else 1949#else
1951 *b += ( ((*i - *b) * a) >> 8 ); 1950 *b += ( ((*i - *b) * a) >> 8 );
1952 --i; --b; 1951 --i; --b;
1953 *b += ( ((*i - *b) * a) >> 8 ); 1952 *b += ( ((*i - *b) * a) >> 8 );
1954 --i; --b; 1953 --i; --b;
1955 *b += ( ((*i - *b) * a) >> 8 ); 1954 *b += ( ((*i - *b) * a) >> 8 );
1956 i -= 2; b -= 2; 1955 i -= 2; b -= 2;
1957#endif 1956#endif
1958 } while (k--); 1957 } while (k--);
1959 } 1958 }
1960 1959
1961 return true; 1960 return true;
1962} 1961}
1963 1962
1964// For selected icons 1963// For selected icons
1965QImage& OImageEffect::selectedImage( QImage &img, const QColor &col ) 1964QImage& OImageEffect::selectedImage( QImage &img, const QColor &col )
1966{ 1965{
1967 return blend( col, img, 0.5); 1966 return blend( col, img, 0.5);
1968} 1967}
1969 1968
1970// 1969//
1971// =================================================================== 1970// ===================================================================
1972// Effects originally ported from ImageMagick for PixiePlus, plus a few 1971// Effects originally ported from ImageMagick for PixiePlus, plus a few
1973// new ones. (mosfet 12/29/01) 1972// new ones. (mosfet 12/29/01)
1974// =================================================================== 1973// ===================================================================
1975// 1974//
1976 1975
1977void OImageEffect::normalize(QImage &img) 1976void OImageEffect::normalize(QImage &img)
1978{ 1977{
1979 int *histogram, threshold_intensity, intense; 1978 int *histogram, threshold_intensity, intense;
1980 int x, y, i; 1979 int x, y, i;
1981 1980
1982 unsigned int gray_value; 1981 unsigned int gray_value;
1983 unsigned int *normalize_map; 1982 unsigned int *normalize_map;
1984 unsigned int high, low; 1983 unsigned int high, low;
1985 1984
1986 // allocate histogram and normalize map 1985 // allocate histogram and normalize map
1987 histogram = (int *)calloc(MaxRGB+1, sizeof(int)); 1986 histogram = (int *)calloc(MaxRGB+1, sizeof(int));
1988 normalize_map = (unsigned int *)malloc((MaxRGB+1)*sizeof(unsigned int)); 1987 normalize_map = (unsigned int *)malloc((MaxRGB+1)*sizeof(unsigned int));
1989 if(!normalize_map || !histogram){ 1988 if(!normalize_map || !histogram){
1990 qWarning("Unable to allocate normalize histogram and map"); 1989 qWarning("Unable to allocate normalize histogram and map");
1991 free(normalize_map); 1990 free(normalize_map);
1992 free(histogram); 1991 free(histogram);
1993 return; 1992 return;
1994 } 1993 }
1995 1994
1996 // form histogram 1995 // form histogram
1997 if(img.depth() > 8){ // DirectClass 1996 if(img.depth() > 8){ // DirectClass
1998 unsigned int *data; 1997 unsigned int *data;
1999 for(y=0; y < img.height(); ++y){ 1998 for(y=0; y < img.height(); ++y){
2000 data = (unsigned int *)img.scanLine(y); 1999 data = (unsigned int *)img.scanLine(y);
2001 for(x=0; x < img.width(); ++x){ 2000 for(x=0; x < img.width(); ++x){
2002 gray_value = intensityValue(data[x]); 2001 gray_value = intensityValue(data[x]);
2003 histogram[gray_value]++; 2002 histogram[gray_value]++;
2004 } 2003 }
2005 } 2004 }
2006 } 2005 }
2007 else{ // PsudeoClass 2006 else{ // PsudeoClass
2008 unsigned char *data; 2007 unsigned char *data;
2009 unsigned int *cTable = img.colorTable(); 2008 unsigned int *cTable = img.colorTable();
2010 for(y=0; y < img.height(); ++y){ 2009 for(y=0; y < img.height(); ++y){
2011 data = (unsigned char *)img.scanLine(y); 2010 data = (unsigned char *)img.scanLine(y);
2012 for(x=0; x < img.width(); ++x){ 2011 for(x=0; x < img.width(); ++x){
2013 gray_value = intensityValue(*(cTable+data[x])); 2012 gray_value = intensityValue(*(cTable+data[x]));
2014 histogram[gray_value]++; 2013 histogram[gray_value]++;
2015 } 2014 }
2016 } 2015 }
2017 } 2016 }
2018 2017
2019 // find histogram boundaries by locating the 1 percent levels 2018 // find histogram boundaries by locating the 1 percent levels
2020 threshold_intensity = (img.width()*img.height())/100; 2019 threshold_intensity = (img.width()*img.height())/100;
2021 intense = 0; 2020 intense = 0;
2022 for(low=0; low < MaxRGB; ++low){ 2021 for(low=0; low < MaxRGB; ++low){
2023 intense+=histogram[low]; 2022 intense+=histogram[low];
2024 if(intense > threshold_intensity) 2023 if(intense > threshold_intensity)
2025 break; 2024 break;
2026 } 2025 }
2027 intense=0; 2026 intense=0;
2028 for(high=MaxRGB; high != 0; --high){ 2027 for(high=MaxRGB; high != 0; --high){
2029 intense+=histogram[high]; 2028 intense+=histogram[high];
2030 if(intense > threshold_intensity) 2029 if(intense > threshold_intensity)
2031 break; 2030 break;
2032 } 2031 }
2033 2032
2034 if (low == high){ 2033 if (low == high){
2035 // Unreasonable contrast; use zero threshold to determine boundaries. 2034 // Unreasonable contrast; use zero threshold to determine boundaries.
2036 threshold_intensity=0; 2035 threshold_intensity=0;
2037 intense=0; 2036 intense=0;
2038 for(low=0; low < MaxRGB; ++low){ 2037 for(low=0; low < MaxRGB; ++low){
2039 intense+=histogram[low]; 2038 intense+=histogram[low];
2040 if(intense > threshold_intensity) 2039 if(intense > threshold_intensity)
2041 break; 2040 break;
2042 } 2041 }
2043 intense=0; 2042 intense=0;
2044 for(high=MaxRGB; high != 0; --high) 2043 for(high=MaxRGB; high != 0; --high)
2045 { 2044 {
2046 intense+=histogram[high]; 2045 intense+=histogram[high];
2047 if(intense > threshold_intensity) 2046 if(intense > threshold_intensity)
2048 break; 2047 break;
2049 } 2048 }
2050 if(low == high) 2049 if(low == high)
2051 return; // zero span bound 2050 return; // zero span bound
2052 } 2051 }
2053 2052
2054 // Stretch the histogram to create the normalized image mapping. 2053 // Stretch the histogram to create the normalized image mapping.
2055 for(i=0; i <= MaxRGB; i++){ 2054 for(i=0; i <= MaxRGB; i++){
2056 if (i < (int) low) 2055 if (i < (int) low)
2057 normalize_map[i]=0; 2056 normalize_map[i]=0;
2058 else{ 2057 else{
2059 if(i > (int) high) 2058 if(i > (int) high)
2060 normalize_map[i]=MaxRGB; 2059 normalize_map[i]=MaxRGB;
2061 else 2060 else
2062 normalize_map[i]=(MaxRGB-1)*(i-low)/(high-low); 2061 normalize_map[i]=(MaxRGB-1)*(i-low)/(high-low);
2063 } 2062 }
2064 } 2063 }
2065 // Normalize 2064 // Normalize
2066 if(img.depth() > 8){ // DirectClass 2065 if(img.depth() > 8){ // DirectClass
2067 unsigned int *data; 2066 unsigned int *data;
2068 for(y=0; y < img.height(); ++y){ 2067 for(y=0; y < img.height(); ++y){
2069 data = (unsigned int *)img.scanLine(y); 2068 data = (unsigned int *)img.scanLine(y);
2070 for(x=0; x < img.width(); ++x){ 2069 for(x=0; x < img.width(); ++x){
2071 data[x] = qRgba(normalize_map[qRed(data[x])], 2070 data[x] = qRgba(normalize_map[qRed(data[x])],
2072 normalize_map[qGreen(data[x])], 2071 normalize_map[qGreen(data[x])],
2073 normalize_map[qBlue(data[x])], 2072 normalize_map[qBlue(data[x])],
2074 qAlpha(data[x])); 2073 qAlpha(data[x]));
2075 } 2074 }
2076 } 2075 }
2077 } 2076 }
2078 else{ // PsudeoClass 2077 else{ // PsudeoClass
2079 int colors = img.numColors(); 2078 int colors = img.numColors();
2080 unsigned int *cTable = img.colorTable(); 2079 unsigned int *cTable = img.colorTable();
2081 for(i=0; i < colors; ++i){ 2080 for(i=0; i < colors; ++i){
2082 cTable[i] = qRgba(normalize_map[qRed(cTable[i])], 2081 cTable[i] = qRgba(normalize_map[qRed(cTable[i])],
2083 normalize_map[qGreen(cTable[i])], 2082 normalize_map[qGreen(cTable[i])],
2084 normalize_map[qBlue(cTable[i])], 2083 normalize_map[qBlue(cTable[i])],
2085 qAlpha(cTable[i])); 2084 qAlpha(cTable[i]));
2086 } 2085 }
2087 } 2086 }
2088 free(histogram); 2087 free(histogram);
2089 free(normalize_map); 2088 free(normalize_map);
2090} 2089}
2091 2090
2092 2091
2093void OImageEffect::equalize(QImage &img) 2092void OImageEffect::equalize(QImage &img)
2094{ 2093{
2095 int *histogram, *map, *equalize_map; 2094 int *histogram, *map, *equalize_map;
2096 int x, y, i, j; 2095 int x, y, i, j;
2097 2096
2098 unsigned int high, low; 2097 unsigned int high, low;
2099 2098
2100 // allocate histogram and maps 2099 // allocate histogram and maps
2101 histogram = (int *)calloc(MaxRGB+1, sizeof(int)); 2100 histogram = (int *)calloc(MaxRGB+1, sizeof(int));
2102 map = (int *)malloc((MaxRGB+1)*sizeof(unsigned int)); 2101 map = (int *)malloc((MaxRGB+1)*sizeof(unsigned int));
2103 equalize_map = (int *)malloc((MaxRGB+1)*sizeof(unsigned int)); 2102 equalize_map = (int *)malloc((MaxRGB+1)*sizeof(unsigned int));
2104 2103
2105 if(!histogram || !map || !equalize_map){ 2104 if(!histogram || !map || !equalize_map){
2106 qWarning("Unable to allocate equalize histogram and maps"); 2105 qWarning("Unable to allocate equalize histogram and maps");
2107 free(histogram); 2106 free(histogram);
2108 free(map); 2107 free(map);
2109 free(equalize_map); 2108 free(equalize_map);
2110 return; 2109 return;
2111 } 2110 }
2112 // form histogram 2111 // form histogram
2113 if(img.depth() > 8){ // DirectClass 2112 if(img.depth() > 8){ // DirectClass
2114 unsigned int *data; 2113 unsigned int *data;
2115 for(y=0; y < img.height(); ++y){ 2114 for(y=0; y < img.height(); ++y){
2116 data = (unsigned int *)img.scanLine(y); 2115 data = (unsigned int *)img.scanLine(y);
2117 for(x=0; x < img.width(); ++x){ 2116 for(x=0; x < img.width(); ++x){
2118 histogram[intensityValue(data[x])]++; 2117 histogram[intensityValue(data[x])]++;
2119 } 2118 }
2120 } 2119 }
2121 } 2120 }
2122 else{ // PsudeoClass 2121 else{ // PsudeoClass
2123 unsigned char *data; 2122 unsigned char *data;
2124 unsigned int *cTable = img.colorTable(); 2123 unsigned int *cTable = img.colorTable();
2125 for(y=0; y < img.height(); ++y){ 2124 for(y=0; y < img.height(); ++y){
2126 data = (unsigned char *)img.scanLine(y); 2125 data = (unsigned char *)img.scanLine(y);
2127 for(x=0; x < img.width(); ++x){ 2126 for(x=0; x < img.width(); ++x){
2128 histogram[intensityValue(*(cTable+data[x]))]++; 2127 histogram[intensityValue(*(cTable+data[x]))]++;
2129 } 2128 }
2130 } 2129 }
2131 } 2130 }
2132 2131
2133 // integrate the histogram to get the equalization map. 2132 // integrate the histogram to get the equalization map.
2134 j=0; 2133 j=0;
2135 for(i=0; i <= MaxRGB; i++){ 2134 for(i=0; i <= MaxRGB; i++){
2136 j+=histogram[i]; 2135 j+=histogram[i];
2137 map[i]=j; 2136 map[i]=j;
2138 } 2137 }
2139 free(histogram); 2138 free(histogram);
2140 if(map[MaxRGB] == 0){ 2139 if(map[MaxRGB] == 0){
2141 free(equalize_map); 2140 free(equalize_map);
2142 free(map); 2141 free(map);
2143 return; 2142 return;
2144 } 2143 }
2145 // equalize 2144 // equalize
2146 low=map[0]; 2145 low=map[0];
2147 high=map[MaxRGB]; 2146 high=map[MaxRGB];
2148 for(i=0; i <= MaxRGB; i++) 2147 for(i=0; i <= MaxRGB; i++)
2149 equalize_map[i]=(unsigned int) 2148 equalize_map[i]=(unsigned int)
2150 ((((double) (map[i]-low))*MaxRGB)/QMAX(high-low,1)); 2149 ((((double) (map[i]-low))*MaxRGB)/QMAX(high-low,1));
2151 free(map); 2150 free(map);
2152 // stretch the histogram 2151 // stretch the histogram
2153 if(img.depth() > 8){ // DirectClass 2152 if(img.depth() > 8){ // DirectClass
2154 unsigned int *data; 2153 unsigned int *data;
2155 for(y=0; y < img.height(); ++y){ 2154 for(y=0; y < img.height(); ++y){
2156 data = (unsigned int *)img.scanLine(y); 2155 data = (unsigned int *)img.scanLine(y);
2157 for(x=0; x < img.width(); ++x){ 2156 for(x=0; x < img.width(); ++x){
2158 data[x] = qRgba(equalize_map[qRed(data[x])], 2157 data[x] = qRgba(equalize_map[qRed(data[x])],
2159 equalize_map[qGreen(data[x])], 2158 equalize_map[qGreen(data[x])],
2160 equalize_map[qBlue(data[x])], 2159 equalize_map[qBlue(data[x])],
2161 qAlpha(data[x])); 2160 qAlpha(data[x]));
2162 } 2161 }
2163 } 2162 }
2164 } 2163 }
2165 else{ // PsudeoClass 2164 else{ // PsudeoClass
2166 int colors = img.numColors(); 2165 int colors = img.numColors();
2167 unsigned int *cTable = img.colorTable(); 2166 unsigned int *cTable = img.colorTable();
2168 for(i=0; i < colors; ++i){ 2167 for(i=0; i < colors; ++i){
2169 cTable[i] = qRgba(equalize_map[qRed(cTable[i])], 2168 cTable[i] = qRgba(equalize_map[qRed(cTable[i])],
2170 equalize_map[qGreen(cTable[i])], 2169 equalize_map[qGreen(cTable[i])],
2171 equalize_map[qBlue(cTable[i])], 2170 equalize_map[qBlue(cTable[i])],
2172 qAlpha(cTable[i])); 2171 qAlpha(cTable[i]));
2173 } 2172 }
2174 } 2173 }
2175 free(equalize_map); 2174 free(equalize_map);
2176} 2175}
2177 2176
2178QImage OImageEffect::sample(QImage &src, int w, int h) 2177QImage OImageEffect::sample(QImage &src, int w, int h)
2179{ 2178{
2180 if(w == src.width() && h == src.height()) 2179 if(w == src.width() && h == src.height())
2181 return(src); 2180 return(src);
2182 2181
2183 double *x_offset, *y_offset; 2182 double *x_offset, *y_offset;
2184 int j, k, y; 2183 int j, k, y;
2185 register int x; 2184 register int x;
2186 QImage dest(w, h, src.depth()); 2185 QImage dest(w, h, src.depth());
2187 2186
2188 x_offset = (double *)malloc(w*sizeof(double)); 2187 x_offset = (double *)malloc(w*sizeof(double));
2189 y_offset = (double *)malloc(h*sizeof(double)); 2188 y_offset = (double *)malloc(h*sizeof(double));
2190 if(!x_offset || !y_offset){ 2189 if(!x_offset || !y_offset){
2191 qWarning("Unable to allocate pixels buffer"); 2190 qWarning("Unable to allocate pixels buffer");
2192 free(x_offset); 2191 free(x_offset);
2193 free(y_offset); 2192 free(y_offset);
2194 return(src); 2193 return(src);
2195 } 2194 }
2196 2195
2197 // init pixel offsets 2196 // init pixel offsets
2198 for(x=0; x < w; ++x) 2197 for(x=0; x < w; ++x)
2199 x_offset[x] = x*src.width()/((double)w); 2198 x_offset[x] = x*src.width()/((double)w);
2200 for(y=0; y < h; ++y) 2199 for(y=0; y < h; ++y)
2201 y_offset[y] = y*src.height()/((double)h); 2200 y_offset[y] = y*src.height()/((double)h);
2202 2201
2203 // sample each row 2202 // sample each row
2204 if(src.depth() > 8){ // DirectClass source image 2203 if(src.depth() > 8){ // DirectClass source image
2205 unsigned int *srcData, *destData; 2204 unsigned int *srcData, *destData;
2206 unsigned int *pixels; 2205 unsigned int *pixels;
2207 pixels = (unsigned int *)malloc(src.width()*sizeof(unsigned int)); 2206 pixels = (unsigned int *)malloc(src.width()*sizeof(unsigned int));
2208 if(!pixels){ 2207 if(!pixels){
2209 qWarning("Unable to allocate pixels buffer"); 2208 qWarning("Unable to allocate pixels buffer");
2210 free(pixels); 2209 free(pixels);
2211 free(x_offset); 2210 free(x_offset);
2212 free(y_offset); 2211 free(y_offset);
2213 return(src); 2212 return(src);
2214 } 2213 }
2215 j = (-1); 2214 j = (-1);
2216 for(y=0; y < h; ++y){ 2215 for(y=0; y < h; ++y){
2217 destData = (unsigned int *)dest.scanLine(y); 2216 destData = (unsigned int *)dest.scanLine(y);
2218 if(j != y_offset[y]){ 2217 if(j != y_offset[y]){
2219 // read a scan line 2218 // read a scan line
2220 j = (int)(y_offset[y]); 2219 j = (int)(y_offset[y]);
2221 srcData = (unsigned int *)src.scanLine(j); 2220 srcData = (unsigned int *)src.scanLine(j);
2222 (void)memcpy(pixels, srcData, src.width()*sizeof(unsigned int)); 2221 (void)memcpy(pixels, srcData, src.width()*sizeof(unsigned int));
2223 } 2222 }
2224 // sample each column 2223 // sample each column
2225 for(x=0; x < w; ++x){ 2224 for(x=0; x < w; ++x){
2226 k = (int)(x_offset[x]); 2225 k = (int)(x_offset[x]);
2227 destData[x] = pixels[k]; 2226 destData[x] = pixels[k];
2228 } 2227 }
2229 } 2228 }
2230 free(pixels); 2229 free(pixels);
2231 } 2230 }
2232 else{ // PsudeoClass source image 2231 else{ // PsudeoClass source image
2233 unsigned char *srcData, *destData; 2232 unsigned char *srcData, *destData;
2234 unsigned char *pixels; 2233 unsigned char *pixels;
2235 pixels = (unsigned char *)malloc(src.width()*sizeof(unsigned char)); 2234 pixels = (unsigned char *)malloc(src.width()*sizeof(unsigned char));
2236 if(!pixels){ 2235 if(!pixels){
2237 qWarning("Unable to allocate pixels buffer"); 2236 qWarning("Unable to allocate pixels buffer");
2238 free(pixels); 2237 free(pixels);
2239 free(x_offset); 2238 free(x_offset);
2240 free(y_offset); 2239 free(y_offset);
2241 return(src); 2240 return(src);
2242 } 2241 }
2243 // copy colortable 2242 // copy colortable
2244 dest.setNumColors(src.numColors()); 2243 dest.setNumColors(src.numColors());
2245 (void)memcpy(dest.colorTable(), src.colorTable(), 2244 (void)memcpy(dest.colorTable(), src.colorTable(),
2246 src.numColors()*sizeof(unsigned int)); 2245 src.numColors()*sizeof(unsigned int));
2247 2246
2248 // sample image 2247 // sample image
2249 j = (-1); 2248 j = (-1);
2250 for(y=0; y < h; ++y){ 2249 for(y=0; y < h; ++y){
2251 destData = (unsigned char *)dest.scanLine(y); 2250 destData = (unsigned char *)dest.scanLine(y);
2252 if(j != y_offset[y]){ 2251 if(j != y_offset[y]){
2253 // read a scan line 2252 // read a scan line
2254 j = (int)(y_offset[y]); 2253 j = (int)(y_offset[y]);
2255 srcData = (unsigned char *)src.scanLine(j); 2254 srcData = (unsigned char *)src.scanLine(j);
2256 (void)memcpy(pixels, srcData, src.width()*sizeof(unsigned char)); 2255 (void)memcpy(pixels, srcData, src.width()*sizeof(unsigned char));
2257 } 2256 }
2258 // sample each column 2257 // sample each column
2259 for(x=0; x < w; ++x){ 2258 for(x=0; x < w; ++x){
2260 k = (int)(x_offset[x]); 2259 k = (int)(x_offset[x]);
2261 destData[x] = pixels[k]; 2260 destData[x] = pixels[k];
2262 } 2261 }
2263 } 2262 }
2264 free(pixels); 2263 free(pixels);
2265 } 2264 }
2266 free(x_offset); 2265 free(x_offset);
2267 free(y_offset); 2266 free(y_offset);
2268 return(dest); 2267 return(dest);
2269} 2268}
2270 2269
2271void OImageEffect::threshold(QImage &img, unsigned int threshold) 2270void OImageEffect::threshold(QImage &img, unsigned int threshold)
2272{ 2271{
2273 int i, count; 2272 int i, count;
2274 unsigned int *data; 2273 unsigned int *data;
2275 if(img.depth() > 8){ // DirectClass 2274 if(img.depth() > 8){ // DirectClass
2276 count = img.width()*img.height(); 2275 count = img.width()*img.height();
2277 data = (unsigned int *)img.bits(); 2276 data = (unsigned int *)img.bits();
2278 } 2277 }
2279 else{ // PsudeoClass 2278 else{ // PsudeoClass
2280 count = img.numColors(); 2279 count = img.numColors();
2281 data = (unsigned int *)img.colorTable(); 2280 data = (unsigned int *)img.colorTable();
2282 } 2281 }
2283 for(i=0; i < count; ++i) 2282 for(i=0; i < count; ++i)
2284 data[i] = intensityValue(data[i]) < threshold ? Qt::black.rgb() : Qt::white.rgb(); 2283 data[i] = intensityValue(data[i]) < threshold ? Qt::black.rgb() : Qt::white.rgb();
2285} 2284}
2286 2285
2287QImage OImageEffect::charcoal(QImage &src, double factor) 2286QImage OImageEffect::charcoal(QImage &src, double factor)
2288{ 2287{
2289 QImage dest(src); 2288 QImage dest(src);
2290 dest.detach(); 2289 dest.detach();
2291 toGray(dest); 2290 toGray(dest);
2292 dest = edge(dest, factor); 2291 dest = edge(dest, factor);
2293 dest = blur(dest, factor); 2292 dest = blur(dest, factor);
2294 normalize(dest); 2293 normalize(dest);
2295 dest.invertPixels(false); 2294 dest.invertPixels(false);
2296 return(dest); 2295 return(dest);
2297} 2296}
2298 2297
2299void OImageEffect::hull(const int x_offset, const int y_offset, 2298void OImageEffect::hull(const int x_offset, const int y_offset,
2300 const int polarity, const int columns, 2299 const int polarity, const int columns,
2301 const int rows, 2300 const int rows,
2302 unsigned int *f, unsigned int *g) 2301 unsigned int *f, unsigned int *g)
2303{ 2302{
2304 int x, y; 2303 int x, y;
2305 2304
2306 unsigned int *p, *q, *r, *s; 2305 unsigned int *p, *q, *r, *s;
2307 unsigned int v; 2306 unsigned int v;
2308 if(f == NULL || g == NULL) 2307 if(f == NULL || g == NULL)
2309 return; 2308 return;
2310 p=f+(columns+2); 2309 p=f+(columns+2);
2311 q=g+(columns+2); 2310 q=g+(columns+2);
2312 r=p+(y_offset*(columns+2)+x_offset); 2311 r=p+(y_offset*(columns+2)+x_offset);
2313 for (y=0; y < rows; y++){ 2312 for (y=0; y < rows; y++){
2314 p++; 2313 p++;
2315 q++; 2314 q++;
2316 r++; 2315 r++;
2317 if(polarity > 0) 2316 if(polarity > 0)
2318 for (x=0; x < columns; x++){ 2317 for (x=0; x < columns; x++){
2319 v=(*p); 2318 v=(*p);
2320 if (*r > v) 2319 if (*r > v)
2321 v++; 2320 v++;
2322 *q=v; 2321 *q=v;
2323 p++; 2322 p++;
2324 q++; 2323 q++;
2325 r++; 2324 r++;
2326 } 2325 }
2327 else 2326 else
2328 for(x=0; x < columns; x++){ 2327 for(x=0; x < columns; x++){
2329 v=(*p); 2328 v=(*p);
2330 if (v > (unsigned int) (*r+1)) 2329 if (v > (unsigned int) (*r+1))
2331 v--; 2330 v--;
2332 *q=v; 2331 *q=v;
2333 p++; 2332 p++;
2334 q++; 2333 q++;
2335 r++; 2334 r++;
2336 } 2335 }
2337 p++; 2336 p++;
2338 q++; 2337 q++;
2339 r++; 2338 r++;
2340 } 2339 }
2341 p=f+(columns+2); 2340 p=f+(columns+2);
2342 q=g+(columns+2); 2341 q=g+(columns+2);
2343 r=q+(y_offset*(columns+2)+x_offset); 2342 r=q+(y_offset*(columns+2)+x_offset);
2344 s=q-(y_offset*(columns+2)+x_offset); 2343 s=q-(y_offset*(columns+2)+x_offset);
2345 for(y=0; y < rows; y++){ 2344 for(y=0; y < rows; y++){
2346 p++; 2345 p++;
2347 q++; 2346 q++;
2348 r++; 2347 r++;
2349 s++; 2348 s++;
2350 if(polarity > 0) 2349 if(polarity > 0)
2351 for(x=0; x < (int) columns; x++){ 2350 for(x=0; x < (int) columns; x++){
2352 v=(*q); 2351 v=(*q);
2353 if (((unsigned int) (*s+1) > v) && (*r > v)) 2352 if (((unsigned int) (*s+1) > v) && (*r > v))
2354 v++; 2353 v++;
2355 *p=v; 2354 *p=v;
2356 p++; 2355 p++;
2357 q++; 2356 q++;
2358 r++; 2357 r++;
2359 s++; 2358 s++;
2360 } 2359 }
2361 else 2360 else
2362 for (x=0; x < columns; x++){ 2361 for (x=0; x < columns; x++){
2363 v=(*q); 2362 v=(*q);
2364 if (((unsigned int) (*s+1) < v) && (*r < v)) 2363 if (((unsigned int) (*s+1) < v) && (*r < v))
2365 v--; 2364 v--;
2366 *p=v; 2365 *p=v;
2367 p++; 2366 p++;
2368 q++; 2367 q++;
2369 r++; 2368 r++;
2370 s++; 2369 s++;
2371 } 2370 }
2372 p++; 2371 p++;
2373 q++; 2372 q++;
2374 r++; 2373 r++;
2375 s++; 2374 s++;
2376 } 2375 }
2377} 2376}
2378 2377
2379QImage OImageEffect::despeckle(QImage &src) 2378QImage OImageEffect::despeckle(QImage &src)
2380{ 2379{
2381 int i, j, x, y; 2380 int i, j, x, y;
2382 unsigned int *blue_channel, *red_channel, *green_channel, *buffer, 2381 unsigned int *blue_channel, *red_channel, *green_channel, *buffer,
2383 *alpha_channel; 2382 *alpha_channel;
2384 int packets; 2383 int packets;
2385 static const int 2384 static const int
2386 X[4]= {0, 1, 1,-1}, 2385 X[4]= {0, 1, 1,-1},
2387 Y[4]= {1, 0, 1, 1}; 2386 Y[4]= {1, 0, 1, 1};
2388 2387
2389 unsigned int *destData; 2388 unsigned int *destData;
2390 QImage dest(src.width(), src.height(), 32); 2389 QImage dest(src.width(), src.height(), 32);
2391 2390
2392 packets = (src.width()+2)*(src.height()+2); 2391 packets = (src.width()+2)*(src.height()+2);
2393 red_channel = (unsigned int *)calloc(packets, sizeof(unsigned int)); 2392 red_channel = (unsigned int *)calloc(packets, sizeof(unsigned int));
2394 green_channel = (unsigned int *)calloc(packets, sizeof(unsigned int)); 2393 green_channel = (unsigned int *)calloc(packets, sizeof(unsigned int));
2395 blue_channel = (unsigned int *)calloc(packets, sizeof(unsigned int)); 2394 blue_channel = (unsigned int *)calloc(packets, sizeof(unsigned int));
2396 alpha_channel = (unsigned int *)calloc(packets, sizeof(unsigned int)); 2395 alpha_channel = (unsigned int *)calloc(packets, sizeof(unsigned int));
2397 buffer = (unsigned int *)calloc(packets, sizeof(unsigned int)); 2396 buffer = (unsigned int *)calloc(packets, sizeof(unsigned int));
2398 if(!red_channel || ! green_channel || ! blue_channel || ! alpha_channel || 2397 if(!red_channel || ! green_channel || ! blue_channel || ! alpha_channel ||
2399 !buffer){ 2398 !buffer){
2400 free(red_channel); 2399 free(red_channel);
2401 free(green_channel); 2400 free(green_channel);
2402 free(blue_channel); 2401 free(blue_channel);
2403 free(alpha_channel); 2402 free(alpha_channel);
2404 free(buffer); 2403 free(buffer);
2405 return(src); 2404 return(src);
2406 } 2405 }
2407 2406
2408 // copy image pixels to color component buffers 2407 // copy image pixels to color component buffers
2409 j = src.width()+2; 2408 j = src.width()+2;
2410 if(src.depth() > 8){ // DirectClass source image 2409 if(src.depth() > 8){ // DirectClass source image
2411 unsigned int *srcData; 2410 unsigned int *srcData;
2412 for(y=0; y < src.height(); ++y){ 2411 for(y=0; y < src.height(); ++y){
2413 srcData = (unsigned int *)src.scanLine(y); 2412 srcData = (unsigned int *)src.scanLine(y);
2414 ++j; 2413 ++j;
2415 for(x=0; x < src.width(); ++x){ 2414 for(x=0; x < src.width(); ++x){
2416 red_channel[j] = qRed(srcData[x]); 2415 red_channel[j] = qRed(srcData[x]);
2417 green_channel[j] = qGreen(srcData[x]); 2416 green_channel[j] = qGreen(srcData[x]);
2418 blue_channel[j] = qBlue(srcData[x]); 2417 blue_channel[j] = qBlue(srcData[x]);
2419 alpha_channel[j] = qAlpha(srcData[x]); 2418 alpha_channel[j] = qAlpha(srcData[x]);
2420 ++j; 2419 ++j;
2421 } 2420 }
2422 ++j; 2421 ++j;
2423 } 2422 }
2424 } 2423 }
2425 else{ // PsudeoClass source image 2424 else{ // PsudeoClass source image
2426 unsigned char *srcData; 2425 unsigned char *srcData;
2427 unsigned int *cTable = src.colorTable(); 2426 unsigned int *cTable = src.colorTable();
2428 unsigned int pixel; 2427 unsigned int pixel;
2429 for(y=0; y < src.height(); ++y){ 2428 for(y=0; y < src.height(); ++y){
2430 srcData = (unsigned char *)src.scanLine(y); 2429 srcData = (unsigned char *)src.scanLine(y);
2431 ++j; 2430 ++j;
2432 for(x=0; x < src.width(); ++x){ 2431 for(x=0; x < src.width(); ++x){
2433 pixel = *(cTable+srcData[x]); 2432 pixel = *(cTable+srcData[x]);
2434 red_channel[j] = qRed(pixel); 2433 red_channel[j] = qRed(pixel);
2435 green_channel[j] = qGreen(pixel); 2434 green_channel[j] = qGreen(pixel);
2436 blue_channel[j] = qBlue(pixel); 2435 blue_channel[j] = qBlue(pixel);
2437 alpha_channel[j] = qAlpha(pixel); 2436 alpha_channel[j] = qAlpha(pixel);
2438 ++j; 2437 ++j;
2439 } 2438 }
2440 ++j; 2439 ++j;
2441 } 2440 }
2442 } 2441 }
2443 // reduce speckle in red channel 2442 // reduce speckle in red channel
2444 for(i=0; i < 4; i++){ 2443 for(i=0; i < 4; i++){
2445 hull(X[i],Y[i],1,src.width(),src.height(),red_channel,buffer); 2444 hull(X[i],Y[i],1,src.width(),src.height(),red_channel,buffer);
2446 hull(-X[i],-Y[i],1,src.width(),src.height(),red_channel,buffer); 2445 hull(-X[i],-Y[i],1,src.width(),src.height(),red_channel,buffer);
2447 hull(-X[i],-Y[i],-1,src.width(),src.height(),red_channel,buffer); 2446 hull(-X[i],-Y[i],-1,src.width(),src.height(),red_channel,buffer);
2448 hull(X[i],Y[i],-1,src.width(),src.height(),red_channel,buffer); 2447 hull(X[i],Y[i],-1,src.width(),src.height(),red_channel,buffer);
2449 } 2448 }
2450 // reduce speckle in green channel 2449 // reduce speckle in green channel
2451 for (i=0; i < packets; i++) 2450 for (i=0; i < packets; i++)
2452 buffer[i]=0; 2451 buffer[i]=0;
2453 for (i=0; i < 4; i++){ 2452 for (i=0; i < 4; i++){
2454 hull(X[i],Y[i],1,src.width(),src.height(),green_channel,buffer); 2453 hull(X[i],Y[i],1,src.width(),src.height(),green_channel,buffer);
2455 hull(-X[i],-Y[i],1,src.width(),src.height(),green_channel,buffer); 2454 hull(-X[i],-Y[i],1,src.width(),src.height(),green_channel,buffer);
2456 hull(-X[i],-Y[i],-1,src.width(),src.height(),green_channel,buffer); 2455 hull(-X[i],-Y[i],-1,src.width(),src.height(),green_channel,buffer);
2457 hull(X[i],Y[i],-1,src.width(),src.height(),green_channel,buffer); 2456 hull(X[i],Y[i],-1,src.width(),src.height(),green_channel,buffer);
2458 } 2457 }
2459 // reduce speckle in blue channel 2458 // reduce speckle in blue channel
2460 for (i=0; i < packets; i++) 2459 for (i=0; i < packets; i++)
2461 buffer[i]=0; 2460 buffer[i]=0;
2462 for (i=0; i < 4; i++){ 2461 for (i=0; i < 4; i++){
2463 hull(X[i],Y[i],1,src.width(),src.height(),blue_channel,buffer); 2462 hull(X[i],Y[i],1,src.width(),src.height(),blue_channel,buffer);
2464 hull(-X[i],-Y[i],1,src.width(),src.height(),blue_channel,buffer); 2463 hull(-X[i],-Y[i],1,src.width(),src.height(),blue_channel,buffer);
2465 hull(-X[i],-Y[i],-1,src.width(),src.height(),blue_channel,buffer); 2464 hull(-X[i],-Y[i],-1,src.width(),src.height(),blue_channel,buffer);
2466 hull(X[i],Y[i],-1,src.width(),src.height(),blue_channel,buffer); 2465 hull(X[i],Y[i],-1,src.width(),src.height(),blue_channel,buffer);
2467 } 2466 }
2468 // copy color component buffers to despeckled image 2467 // copy color component buffers to despeckled image
2469 j = dest.width()+2; 2468 j = dest.width()+2;
2470 for(y=0; y < dest.height(); ++y) 2469 for(y=0; y < dest.height(); ++y)
2471 { 2470 {
2472 destData = (unsigned int *)dest.scanLine(y); 2471 destData = (unsigned int *)dest.scanLine(y);
2473 ++j; 2472 ++j;
2474 for (x=0; x < dest.width(); ++x) 2473 for (x=0; x < dest.width(); ++x)
2475 { 2474 {
2476 destData[x] = qRgba(red_channel[j], green_channel[j], 2475 destData[x] = qRgba(red_channel[j], green_channel[j],
2477 blue_channel[j], alpha_channel[j]); 2476 blue_channel[j], alpha_channel[j]);
2478 ++j; 2477 ++j;
2479 } 2478 }
2480 ++j; 2479 ++j;
2481 } 2480 }
2482 free(buffer); 2481 free(buffer);
2483 free(red_channel); 2482 free(red_channel);
2484 free(green_channel); 2483 free(green_channel);
2485 free(blue_channel); 2484 free(blue_channel);
2486 free(alpha_channel); 2485 free(alpha_channel);
2487 return(dest); 2486 return(dest);
2488} 2487}
2489 2488
2490unsigned int OImageEffect::generateNoise(unsigned int pixel, 2489unsigned int OImageEffect::generateNoise(unsigned int pixel,
2491 NoiseType noise_type) 2490 NoiseType noise_type)
2492{ 2491{
2493#define NoiseEpsilon 1.0e-5 2492#define NoiseEpsilon 1.0e-5
2494#define NoiseMask 0x7fff 2493#define NoiseMask 0x7fff
2495#define SigmaUniform 4.0 2494#define SigmaUniform 4.0
2496#define SigmaGaussian 4.0 2495#define SigmaGaussian 4.0
2497#define SigmaImpulse 0.10 2496#define SigmaImpulse 0.10
2498#define SigmaLaplacian 10.0 2497#define SigmaLaplacian 10.0
2499#define SigmaMultiplicativeGaussian 0.5 2498#define SigmaMultiplicativeGaussian 0.5
2500#define SigmaPoisson 0.05 2499#define SigmaPoisson 0.05
2501#define TauGaussian 20.0 2500#define TauGaussian 20.0
2502 2501
2503 double alpha, beta, sigma, value; 2502 double alpha, beta, sigma, value;
2504 alpha=(double) (rand() & NoiseMask)/NoiseMask; 2503 alpha=(double) (rand() & NoiseMask)/NoiseMask;
2505 if (alpha == 0.0) 2504 if (alpha == 0.0)
2506 alpha=1.0; 2505 alpha=1.0;
2507 switch(noise_type){ 2506 switch(noise_type){
2508 case UniformNoise: 2507 case UniformNoise:
2509 default: 2508 default:
2510 { 2509 {
2511 value=(double) pixel+SigmaUniform*(alpha-0.5); 2510 value=(double) pixel+SigmaUniform*(alpha-0.5);
2512 break; 2511 break;
2513 } 2512 }
2514 case GaussianNoise: 2513 case GaussianNoise:
2515 { 2514 {
2516 double tau; 2515 double tau;
2517 2516
2518 beta=(double) (rand() & NoiseMask)/NoiseMask; 2517 beta=(double) (rand() & NoiseMask)/NoiseMask;
2519 sigma=sqrt(-2.0*log(alpha))*cos(2.0*M_PI*beta); 2518 sigma=sqrt(-2.0*log(alpha))*cos(2.0*M_PI*beta);
2520 tau=sqrt(-2.0*log(alpha))*sin(2.0*M_PI*beta); 2519 tau=sqrt(-2.0*log(alpha))*sin(2.0*M_PI*beta);
2521 value=(double) pixel+ 2520 value=(double) pixel+
2522 (sqrt((double) pixel)*SigmaGaussian*sigma)+(TauGaussian*tau); 2521 (sqrt((double) pixel)*SigmaGaussian*sigma)+(TauGaussian*tau);
2523 break; 2522 break;
2524 } 2523 }
2525 case MultiplicativeGaussianNoise: 2524 case MultiplicativeGaussianNoise:
2526 { 2525 {
2527 if (alpha <= NoiseEpsilon) 2526 if (alpha <= NoiseEpsilon)
2528 sigma=MaxRGB; 2527 sigma=MaxRGB;
2529 else 2528 else
2530 sigma=sqrt(-2.0*log(alpha)); 2529 sigma=sqrt(-2.0*log(alpha));
2531 beta=(rand() & NoiseMask)/NoiseMask; 2530 beta=(rand() & NoiseMask)/NoiseMask;
2532 value=(double) pixel+ 2531 value=(double) pixel+
2533 pixel*SigmaMultiplicativeGaussian*sigma*cos(2.0*M_PI*beta); 2532 pixel*SigmaMultiplicativeGaussian*sigma*cos(2.0*M_PI*beta);
2534 break; 2533 break;
2535 } 2534 }
2536 case ImpulseNoise: 2535 case ImpulseNoise:
2537 { 2536 {
2538 if (alpha < (SigmaImpulse/2.0)) 2537 if (alpha < (SigmaImpulse/2.0))
2539 value=0; 2538 value=0;
2540 else 2539 else
2541 if (alpha >= (1.0-(SigmaImpulse/2.0))) 2540 if (alpha >= (1.0-(SigmaImpulse/2.0)))
2542 value=MaxRGB; 2541 value=MaxRGB;
2543 else 2542 else
2544 value=pixel; 2543 value=pixel;
2545 break; 2544 break;
2546 } 2545 }
2547 case LaplacianNoise: 2546 case LaplacianNoise:
2548 { 2547 {
2549 if (alpha <= 0.5) 2548 if (alpha <= 0.5)
2550 { 2549 {
2551 if (alpha <= NoiseEpsilon) 2550 if (alpha <= NoiseEpsilon)
2552 value=(double) pixel-MaxRGB; 2551 value=(double) pixel-MaxRGB;
2553 else 2552 else
2554 value=(double) pixel+SigmaLaplacian*log(2.0*alpha); 2553 value=(double) pixel+SigmaLaplacian*log(2.0*alpha);
2555 break; 2554 break;
2556 } 2555 }
2557 beta=1.0-alpha; 2556 beta=1.0-alpha;
2558 if (beta <= (0.5*NoiseEpsilon)) 2557 if (beta <= (0.5*NoiseEpsilon))
2559 value=(double) pixel+MaxRGB; 2558 value=(double) pixel+MaxRGB;
2560 else 2559 else
2561 value=(double) pixel-SigmaLaplacian*log(2.0*beta); 2560 value=(double) pixel-SigmaLaplacian*log(2.0*beta);
2562 break; 2561 break;
2563 } 2562 }
2564 case PoissonNoise: 2563 case PoissonNoise:
2565 { 2564 {
2566 register int 2565 register int
2567 i; 2566 i;
2568 2567
2569 for (i=0; alpha > exp(-SigmaPoisson*pixel); i++) 2568 for (i=0; alpha > exp(-SigmaPoisson*pixel); i++)
2570 { 2569 {
2571 beta=(double) (rand() & NoiseMask)/NoiseMask; 2570 beta=(double) (rand() & NoiseMask)/NoiseMask;
2572 alpha=alpha*beta; 2571 alpha=alpha*beta;
2573 } 2572 }
2574 value=i/SigmaPoisson; 2573 value=i/SigmaPoisson;
2575 break; 2574 break;
2576 } 2575 }
2577 } 2576 }
2578 if(value < 0.0) 2577 if(value < 0.0)
2579 return(0); 2578 return(0);
2580 if(value > MaxRGB) 2579 if(value > MaxRGB)
2581 return(MaxRGB); 2580 return(MaxRGB);
2582 return((unsigned int) (value+0.5)); 2581 return((unsigned int) (value+0.5));
2583} 2582}
2584 2583
2585QImage OImageEffect::addNoise(QImage &src, NoiseType noise_type) 2584QImage OImageEffect::addNoise(QImage &src, NoiseType noise_type)
2586{ 2585{
2587 int x, y; 2586 int x, y;
2588 QImage dest(src.width(), src.height(), 32); 2587 QImage dest(src.width(), src.height(), 32);
2589 unsigned int *destData; 2588 unsigned int *destData;
2590 2589
2591 if(src.depth() > 8){ // DirectClass source image 2590 if(src.depth() > 8){ // DirectClass source image
2592 unsigned int *srcData; 2591 unsigned int *srcData;
2593 for(y=0; y < src.height(); ++y){ 2592 for(y=0; y < src.height(); ++y){
2594 srcData = (unsigned int *)src.scanLine(y); 2593 srcData = (unsigned int *)src.scanLine(y);
2595 destData = (unsigned int *)dest.scanLine(y); 2594 destData = (unsigned int *)dest.scanLine(y);
2596 for(x=0; x < src.width(); ++x){ 2595 for(x=0; x < src.width(); ++x){
2597 destData[x] = qRgba(generateNoise(qRed(srcData[x]), noise_type), 2596 destData[x] = qRgba(generateNoise(qRed(srcData[x]), noise_type),
2598 generateNoise(qGreen(srcData[x]), noise_type), 2597 generateNoise(qGreen(srcData[x]), noise_type),
2599 generateNoise(qBlue(srcData[x]), noise_type), 2598 generateNoise(qBlue(srcData[x]), noise_type),
2600 qAlpha(srcData[x])); 2599 qAlpha(srcData[x]));
2601 } 2600 }
2602 } 2601 }
2603 } 2602 }
2604 else{ // PsudeoClass source image 2603 else{ // PsudeoClass source image
2605 unsigned char *srcData; 2604 unsigned char *srcData;
2606 unsigned int *cTable = src.colorTable(); 2605 unsigned int *cTable = src.colorTable();
2607 unsigned int pixel; 2606 unsigned int pixel;
2608 for(y=0; y < src.height(); ++y){ 2607 for(y=0; y < src.height(); ++y){
2609 srcData = (unsigned char *)src.scanLine(y); 2608 srcData = (unsigned char *)src.scanLine(y);
2610 destData = (unsigned int *)dest.scanLine(y); 2609 destData = (unsigned int *)dest.scanLine(y);
2611 for(x=0; x < src.width(); ++x){ 2610 for(x=0; x < src.width(); ++x){
2612 pixel = *(cTable+srcData[x]); 2611 pixel = *(cTable+srcData[x]);
2613 destData[x] = qRgba(generateNoise(qRed(pixel), noise_type), 2612 destData[x] = qRgba(generateNoise(qRed(pixel), noise_type),
2614 generateNoise(qGreen(pixel), noise_type), 2613 generateNoise(qGreen(pixel), noise_type),
2615 generateNoise(qBlue(pixel), noise_type), 2614 generateNoise(qBlue(pixel), noise_type),
2616 qAlpha(pixel)); 2615 qAlpha(pixel));
2617 } 2616 }
2618 } 2617 }
2619 2618
2620 } 2619 }
2621 return(dest); 2620 return(dest);
2622} 2621}
2623 2622
2624unsigned int OImageEffect::interpolateColor(QImage *image, double x_offset, 2623unsigned int OImageEffect::interpolateColor(QImage *image, double x_offset,
2625 double y_offset, 2624 double y_offset,
2626 unsigned int background) 2625 unsigned int background)
2627{ 2626{
2628 double alpha, beta; 2627 double alpha, beta;
2629 unsigned int p, q, r, s; 2628 unsigned int p, q, r, s;
2630 int x, y; 2629 int x, y;
2631 2630
2632 x = (int)x_offset; 2631 x = (int)x_offset;
2633 y = (int)y_offset; 2632 y = (int)y_offset;
2634 if((x < -1) || (x >= image->width()) || (y < -1) || (y >= image->height())) 2633 if((x < -1) || (x >= image->width()) || (y < -1) || (y >= image->height()))
2635 return(background); 2634 return(background);
2636 if(image->depth() > 8){ 2635 if(image->depth() > 8){
2637 if((x >= 0) && (y >= 0) && (x < (image->width()-1)) && (y < (image->height()-1))) { 2636 if((x >= 0) && (y >= 0) && (x < (image->width()-1)) && (y < (image->height()-1))) {
2638 unsigned int *t = (unsigned int *)image->scanLine(y); 2637 unsigned int *t = (unsigned int *)image->scanLine(y);
2639 p = t[x]; 2638 p = t[x];
2640 q = t[x+1]; 2639 q = t[x+1];
2641 r = t[x+image->width()]; 2640 r = t[x+image->width()];
2642 s = t[x+image->width()+1]; 2641 s = t[x+image->width()+1];
2643 } 2642 }
2644 else{ 2643 else{
2645 unsigned int *t = (unsigned int *)image->scanLine(y); 2644 unsigned int *t = (unsigned int *)image->scanLine(y);
2646 p = background; 2645 p = background;
2647 if((x >= 0) && (y >= 0)){ 2646 if((x >= 0) && (y >= 0)){
2648 p = t[x]; 2647 p = t[x];
2649 } 2648 }
2650 q = background; 2649 q = background;
2651 if(((x+1) < image->width()) && (y >= 0)){ 2650 if(((x+1) < image->width()) && (y >= 0)){
2652 q = t[x+1]; 2651 q = t[x+1];
2653 } 2652 }
2654 r = background; 2653 r = background;
2655 if((x >= 0) && ((y+1) < image->height())){ 2654 if((x >= 0) && ((y+1) < image->height())){
2656 t = (unsigned int *)image->scanLine(y+1); 2655 t = (unsigned int *)image->scanLine(y+1);
2657 r = t[x+image->width()]; 2656 r = t[x+image->width()];
2658 } 2657 }
2659 s = background; 2658 s = background;
2660 if(((x+1) < image->width()) && ((y+1) < image->height())){ 2659 if(((x+1) < image->width()) && ((y+1) < image->height())){
2661 t = (unsigned int *)image->scanLine(y+1); 2660 t = (unsigned int *)image->scanLine(y+1);
2662 s = t[x+image->width()+1]; 2661 s = t[x+image->width()+1];
2663 } 2662 }
2664 2663
2665 } 2664 }
2666 } 2665 }
2667 else{ 2666 else{
2668 unsigned int *colorTable = (unsigned int *)image->colorTable(); 2667 unsigned int *colorTable = (unsigned int *)image->colorTable();
2669 if((x >= 0) && (y >= 0) && (x < (image->width()-1)) && (y < (image->height()-1))) { 2668 if((x >= 0) && (y >= 0) && (x < (image->width()-1)) && (y < (image->height()-1))) {
2670 unsigned char *t; 2669 unsigned char *t;
2671 t = (unsigned char *)image->scanLine(y); 2670 t = (unsigned char *)image->scanLine(y);
2672 p = *(colorTable+t[x]); 2671 p = *(colorTable+t[x]);
2673 q = *(colorTable+t[x+1]); 2672 q = *(colorTable+t[x+1]);
2674 t = (unsigned char *)image->scanLine(y+1); 2673 t = (unsigned char *)image->scanLine(y+1);
2675 r = *(colorTable+t[x]); 2674 r = *(colorTable+t[x]);
2676 s = *(colorTable+t[x+1]); 2675 s = *(colorTable+t[x+1]);
2677 } 2676 }
2678 else{ 2677 else{
2679 unsigned char *t; 2678 unsigned char *t;
2680 p = background; 2679 p = background;
2681 if((x >= 0) && (y >= 0)){ 2680 if((x >= 0) && (y >= 0)){
2682 t = (unsigned char *)image->scanLine(y); 2681 t = (unsigned char *)image->scanLine(y);
2683 p = *(colorTable+t[x]); 2682 p = *(colorTable+t[x]);
2684 } 2683 }
2685 q = background; 2684 q = background;
2686 if(((x+1) < image->width()) && (y >= 0)){ 2685 if(((x+1) < image->width()) && (y >= 0)){
2687 t = (unsigned char *)image->scanLine(y); 2686 t = (unsigned char *)image->scanLine(y);
2688 q = *(colorTable+t[x+1]); 2687 q = *(colorTable+t[x+1]);
2689 } 2688 }
2690 r = background; 2689 r = background;
2691 if((x >= 0) && ((y+1) < image->height())){ 2690 if((x >= 0) && ((y+1) < image->height())){
2692 t = (unsigned char *)image->scanLine(y+1); 2691 t = (unsigned char *)image->scanLine(y+1);
2693 r = *(colorTable+t[x]); 2692 r = *(colorTable+t[x]);
2694 } 2693 }
2695 s = background; 2694 s = background;
2696 if(((x+1) < image->width()) && ((y+1) < image->height())){ 2695 if(((x+1) < image->width()) && ((y+1) < image->height())){
2697 t = (unsigned char *)image->scanLine(y+1); 2696 t = (unsigned char *)image->scanLine(y+1);
2698 s = *(colorTable+t[x+1]); 2697 s = *(colorTable+t[x+1]);
2699 } 2698 }
2700 2699
2701 } 2700 }
2702 2701
2703 } 2702 }
2704 x_offset -= floor(x_offset); 2703 x_offset -= floor(x_offset);
2705 y_offset -= floor(y_offset); 2704 y_offset -= floor(y_offset);
2706 alpha = 1.0-x_offset; 2705 alpha = 1.0-x_offset;
2707 beta = 1.0-y_offset; 2706 beta = 1.0-y_offset;
2708 2707
2709 return(qRgba((unsigned char)(beta*(alpha*qRed(p)+x_offset*qRed(q))+y_offset*(alpha*qRed(r)+x_offset*qRed(s))), 2708 return(qRgba((unsigned char)(beta*(alpha*qRed(p)+x_offset*qRed(q))+y_offset*(alpha*qRed(r)+x_offset*qRed(s))),
2710 (unsigned char)(beta*(alpha*qGreen(p)+x_offset*qGreen(q))+y_offset*(alpha*qGreen(r)+x_offset*qGreen(s))), 2709 (unsigned char)(beta*(alpha*qGreen(p)+x_offset*qGreen(q))+y_offset*(alpha*qGreen(r)+x_offset*qGreen(s))),
2711 (unsigned char)(beta*(alpha*qBlue(p)+x_offset*qBlue(q))+y_offset*(alpha*qBlue(r)+x_offset*qBlue(s))), 2710 (unsigned char)(beta*(alpha*qBlue(p)+x_offset*qBlue(q))+y_offset*(alpha*qBlue(r)+x_offset*qBlue(s))),
2712 (unsigned char)(beta*(alpha*qAlpha(p)+x_offset*qAlpha(q))+y_offset*(alpha*qAlpha(r)+x_offset*qAlpha(s))))); 2711 (unsigned char)(beta*(alpha*qAlpha(p)+x_offset*qAlpha(q))+y_offset*(alpha*qAlpha(r)+x_offset*qAlpha(s)))));
2713} 2712}
2714 2713
2715QImage OImageEffect::implode(QImage &src, double factor, 2714QImage OImageEffect::implode(QImage &src, double factor,
2716 unsigned int background) 2715 unsigned int background)
2717{ 2716{
2718 double amount, distance, radius; 2717 double amount, distance, radius;
2719 double x_center, x_distance, x_scale; 2718 double x_center, x_distance, x_scale;
2720 double y_center, y_distance, y_scale; 2719 double y_center, y_distance, y_scale;
2721 unsigned int *destData; 2720 unsigned int *destData;
2722 int x, y; 2721 int x, y;
2723 2722
2724 QImage dest(src.width(), src.height(), 32); 2723 QImage dest(src.width(), src.height(), 32);
2725 2724
2726 // compute scaling factor 2725 // compute scaling factor
2727 x_scale = 1.0; 2726 x_scale = 1.0;
2728 y_scale = 1.0; 2727 y_scale = 1.0;
2729 x_center = (double)0.5*src.width(); 2728 x_center = (double)0.5*src.width();
2730 y_center = (double)0.5*src.height(); 2729 y_center = (double)0.5*src.height();
2731 radius=x_center; 2730 radius=x_center;
2732 if(src.width() > src.height()) 2731 if(src.width() > src.height())
2733 y_scale = (double)src.width()/src.height(); 2732 y_scale = (double)src.width()/src.height();
2734 else if(src.width() < src.height()){ 2733 else if(src.width() < src.height()){
2735 x_scale = (double) src.height()/src.width(); 2734 x_scale = (double) src.height()/src.width();
2736 radius = y_center; 2735 radius = y_center;
2737 } 2736 }
2738 amount=factor/10.0; 2737 amount=factor/10.0;
2739 if(amount >= 0) 2738 if(amount >= 0)
2740 amount/=10.0; 2739 amount/=10.0;
2741 if(src.depth() > 8){ // DirectClass source image 2740 if(src.depth() > 8){ // DirectClass source image
2742 unsigned int *srcData; 2741 unsigned int *srcData;
2743 for(y=0; y < src.height(); ++y){ 2742 for(y=0; y < src.height(); ++y){
2744 srcData = (unsigned int *)src.scanLine(y); 2743 srcData = (unsigned int *)src.scanLine(y);
2745 destData = (unsigned int *)dest.scanLine(y); 2744 destData = (unsigned int *)dest.scanLine(y);
2746 y_distance=y_scale*(y-y_center); 2745 y_distance=y_scale*(y-y_center);
2747 for(x=0; x < src.width(); ++x){ 2746 for(x=0; x < src.width(); ++x){
2748 destData[x] = srcData[x]; 2747 destData[x] = srcData[x];
2749 x_distance = x_scale*(x-x_center); 2748 x_distance = x_scale*(x-x_center);
2750 distance= x_distance*x_distance+y_distance*y_distance; 2749 distance= x_distance*x_distance+y_distance*y_distance;
2751 if(distance < (radius*radius)){ 2750 if(distance < (radius*radius)){
2752 double factor; 2751 double factor;
2753 // Implode the pixel. 2752 // Implode the pixel.
2754 factor=1.0; 2753 factor=1.0;
2755 if(distance > 0.0) 2754 if(distance > 0.0)
2756 factor= 2755 factor=
2757 pow(sin(0.5000000000000001*M_PI*sqrt(distance)/radius),-amount); 2756 pow(sin(0.5000000000000001*M_PI*sqrt(distance)/radius),-amount);
2758 destData[x] = interpolateColor(&src, factor*x_distance/x_scale+x_center, 2757 destData[x] = interpolateColor(&src, factor*x_distance/x_scale+x_center,
2759 factor*y_distance/y_scale+y_center, 2758 factor*y_distance/y_scale+y_center,
2760 background); 2759 background);
2761 } 2760 }
2762 } 2761 }
2763 } 2762 }
2764 } 2763 }
2765 else{ // PsudeoClass source image 2764 else{ // PsudeoClass source image
2766 unsigned char *srcData; 2765 unsigned char *srcData;
2767 unsigned char idx; 2766 unsigned char idx;
2768 unsigned int *cTable = src.colorTable(); 2767 unsigned int *cTable = src.colorTable();
2769 for(y=0; y < src.height(); ++y){ 2768 for(y=0; y < src.height(); ++y){
2770 srcData = (unsigned char *)src.scanLine(y); 2769 srcData = (unsigned char *)src.scanLine(y);
2771 destData = (unsigned int *)dest.scanLine(y); 2770 destData = (unsigned int *)dest.scanLine(y);
2772 y_distance=y_scale*(y-y_center); 2771 y_distance=y_scale*(y-y_center);
2773 for(x=0; x < src.width(); ++x){ 2772 for(x=0; x < src.width(); ++x){
2774 idx = srcData[x]; 2773 idx = srcData[x];
2775 destData[x] = cTable[idx]; 2774 destData[x] = cTable[idx];
2776 x_distance = x_scale*(x-x_center); 2775 x_distance = x_scale*(x-x_center);
2777 distance= x_distance*x_distance+y_distance*y_distance; 2776 distance= x_distance*x_distance+y_distance*y_distance;
2778 if(distance < (radius*radius)){ 2777 if(distance < (radius*radius)){
2779 double factor; 2778 double factor;
2780 // Implode the pixel. 2779 // Implode the pixel.
2781 factor=1.0; 2780 factor=1.0;
2782 if(distance > 0.0) 2781 if(distance > 0.0)
2783 factor= 2782 factor=
2784 pow(sin(0.5000000000000001*M_PI*sqrt(distance)/radius),-amount); 2783 pow(sin(0.5000000000000001*M_PI*sqrt(distance)/radius),-amount);
2785 destData[x] = interpolateColor(&src, factor*x_distance/x_scale+x_center, 2784 destData[x] = interpolateColor(&src, factor*x_distance/x_scale+x_center,
2786 factor*y_distance/y_scale+y_center, 2785 factor*y_distance/y_scale+y_center,
2787 background); 2786 background);
2788 } 2787 }
2789 } 2788 }
2790 } 2789 }
2791 2790
2792 } 2791 }
2793 return(dest); 2792 return(dest);
2794} 2793}
2795 2794
2796QImage OImageEffect::rotate(QImage &img, RotateDirection r) 2795QImage OImageEffect::rotate(QImage &img, RotateDirection r)
2797{ 2796{
2798 QImage dest; 2797 QImage dest;
2799 int x, y; 2798 int x, y;
2800 if(img.depth() > 8){ 2799 if(img.depth() > 8){
2801 unsigned int *srcData, *destData; 2800 unsigned int *srcData, *destData;
2802 switch(r){ 2801 switch(r){
2803 case Rotate90: 2802 case Rotate90:
2804 dest.create(img.height(), img.width(), img.depth()); 2803 dest.create(img.height(), img.width(), img.depth());
2805 for(y=0; y < img.height(); ++y){ 2804 for(y=0; y < img.height(); ++y){
2806 srcData = (unsigned int *)img.scanLine(y); 2805 srcData = (unsigned int *)img.scanLine(y);
2807 for(x=0; x < img.width(); ++x){ 2806 for(x=0; x < img.width(); ++x){
2808 destData = (unsigned int *)dest.scanLine(x); 2807 destData = (unsigned int *)dest.scanLine(x);
2809 destData[img.height()-y-1] = srcData[x]; 2808 destData[img.height()-y-1] = srcData[x];
2810 } 2809 }
2811 } 2810 }
2812 break; 2811 break;
2813 case Rotate180: 2812 case Rotate180:
2814 dest.create(img.width(), img.height(), img.depth()); 2813 dest.create(img.width(), img.height(), img.depth());
2815 for(y=0; y < img.height(); ++y){ 2814 for(y=0; y < img.height(); ++y){
2816 srcData = (unsigned int *)img.scanLine(y); 2815 srcData = (unsigned int *)img.scanLine(y);
2817 destData = (unsigned int *)dest.scanLine(img.height()-y-1); 2816 destData = (unsigned int *)dest.scanLine(img.height()-y-1);
2818 for(x=0; x < img.width(); ++x) 2817 for(x=0; x < img.width(); ++x)
2819 destData[img.width()-x-1] = srcData[x]; 2818 destData[img.width()-x-1] = srcData[x];
2820 } 2819 }
2821 break; 2820 break;
2822 case Rotate270: 2821 case Rotate270:
2823 dest.create(img.height(), img.width(), img.depth()); 2822 dest.create(img.height(), img.width(), img.depth());
2824 for(y=0; y < img.height(); ++y){ 2823 for(y=0; y < img.height(); ++y){
2825 srcData = (unsigned int *)img.scanLine(y); 2824 srcData = (unsigned int *)img.scanLine(y);
2826 for(x=0; x < img.width(); ++x){ 2825 for(x=0; x < img.width(); ++x){
2827 destData = (unsigned int *)dest.scanLine(img.width()-x-1); 2826 destData = (unsigned int *)dest.scanLine(img.width()-x-1);
2828 destData[y] = srcData[x]; 2827 destData[y] = srcData[x];
2829 } 2828 }
2830 } 2829 }
2831 break; 2830 break;
2832 default: 2831 default:
2833 dest = img; 2832 dest = img;
2834 break; 2833 break;
2835 } 2834 }
2836 } 2835 }
2837 else{ 2836 else{
2838 unsigned char *srcData, *destData; 2837 unsigned char *srcData, *destData;
2839 unsigned int *srcTable, *destTable; 2838 unsigned int *srcTable, *destTable;
2840 switch(r){ 2839 switch(r){
2841 case Rotate90: 2840 case Rotate90:
2842 dest.create(img.height(), img.width(), img.depth()); 2841 dest.create(img.height(), img.width(), img.depth());
2843 dest.setNumColors(img.numColors()); 2842 dest.setNumColors(img.numColors());
2844 srcTable = (unsigned int *)img.colorTable(); 2843 srcTable = (unsigned int *)img.colorTable();
2845 destTable = (unsigned int *)dest.colorTable(); 2844 destTable = (unsigned int *)dest.colorTable();
2846 for(x=0; x < img.numColors(); ++x) 2845 for(x=0; x < img.numColors(); ++x)
2847 destTable[x] = srcTable[x]; 2846 destTable[x] = srcTable[x];
2848 for(y=0; y < img.height(); ++y){ 2847 for(y=0; y < img.height(); ++y){
2849 srcData = (unsigned char *)img.scanLine(y); 2848 srcData = (unsigned char *)img.scanLine(y);
2850 for(x=0; x < img.width(); ++x){ 2849 for(x=0; x < img.width(); ++x){
2851 destData = (unsigned char *)dest.scanLine(x); 2850 destData = (unsigned char *)dest.scanLine(x);
2852 destData[img.height()-y-1] = srcData[x]; 2851 destData[img.height()-y-1] = srcData[x];
2853 } 2852 }
2854 } 2853 }
2855 break; 2854 break;
2856 case Rotate180: 2855 case Rotate180:
2857 dest.create(img.width(), img.height(), img.depth()); 2856 dest.create(img.width(), img.height(), img.depth());
2858 dest.setNumColors(img.numColors()); 2857 dest.setNumColors(img.numColors());
2859 srcTable = (unsigned int *)img.colorTable(); 2858 srcTable = (unsigned int *)img.colorTable();
2860 destTable = (unsigned int *)dest.colorTable(); 2859 destTable = (unsigned int *)dest.colorTable();
2861 for(x=0; x < img.numColors(); ++x) 2860 for(x=0; x < img.numColors(); ++x)
2862 destTable[x] = srcTable[x]; 2861 destTable[x] = srcTable[x];
2863 for(y=0; y < img.height(); ++y){ 2862 for(y=0; y < img.height(); ++y){
2864 srcData = (unsigned char *)img.scanLine(y); 2863 srcData = (unsigned char *)img.scanLine(y);
2865 destData = (unsigned char *)dest.scanLine(img.height()-y-1); 2864 destData = (unsigned char *)dest.scanLine(img.height()-y-1);
2866 for(x=0; x < img.width(); ++x) 2865 for(x=0; x < img.width(); ++x)
2867 destData[img.width()-x-1] = srcData[x]; 2866 destData[img.width()-x-1] = srcData[x];
2868 } 2867 }
2869 break; 2868 break;
2870 case Rotate270: 2869 case Rotate270:
2871 dest.create(img.height(), img.width(), img.depth()); 2870 dest.create(img.height(), img.width(), img.depth());
2872 dest.setNumColors(img.numColors()); 2871 dest.setNumColors(img.numColors());
2873 srcTable = (unsigned int *)img.colorTable(); 2872 srcTable = (unsigned int *)img.colorTable();
2874 destTable = (unsigned int *)dest.colorTable(); 2873 destTable = (unsigned int *)dest.colorTable();
2875 for(x=0; x < img.numColors(); ++x) 2874 for(x=0; x < img.numColors(); ++x)
2876 destTable[x] = srcTable[x]; 2875 destTable[x] = srcTable[x];
2877 for(y=0; y < img.height(); ++y){ 2876 for(y=0; y < img.height(); ++y){
2878 srcData = (unsigned char *)img.scanLine(y); 2877 srcData = (unsigned char *)img.scanLine(y);
2879 for(x=0; x < img.width(); ++x){ 2878 for(x=0; x < img.width(); ++x){
2880 destData = (unsigned char *)dest.scanLine(img.width()-x-1); 2879 destData = (unsigned char *)dest.scanLine(img.width()-x-1);
2881 destData[y] = srcData[x]; 2880 destData[y] = srcData[x];
2882 } 2881 }
2883 } 2882 }
2884 break; 2883 break;
2885 default: 2884 default:
2886 dest = img; 2885 dest = img;
2887 break; 2886 break;
2888 } 2887 }
2889 2888
2890 } 2889 }
2891 return(dest); 2890 return(dest);
2892} 2891}
2893 2892
2894void OImageEffect::solarize(QImage &img, double factor) 2893void OImageEffect::solarize(QImage &img, double factor)
2895{ 2894{
2896 int i, count; 2895 int i, count;
2897 int threshold; 2896 int threshold;
2898 unsigned int *data; 2897 unsigned int *data;
2899 2898
2900 threshold = (int)(factor*(MaxRGB+1)/100.0); 2899 threshold = (int)(factor*(MaxRGB+1)/100.0);
2901 if(img.depth() < 32){ 2900 if(img.depth() < 32){
2902 data = (unsigned int *)img.colorTable(); 2901 data = (unsigned int *)img.colorTable();
2903 count = img.numColors(); 2902 count = img.numColors();
2904 } 2903 }
2905 else{ 2904 else{
2906 data = (unsigned int *)img.bits(); 2905 data = (unsigned int *)img.bits();
2907 count = img.width()*img.height(); 2906 count = img.width()*img.height();
2908 } 2907 }
2909 for(i=0; i < count; ++i){ 2908 for(i=0; i < count; ++i){
2910 data[i] = qRgba(qRed(data[i]) > threshold ? MaxRGB-qRed(data[i]) : qRed(data[i]), 2909 data[i] = qRgba(qRed(data[i]) > threshold ? MaxRGB-qRed(data[i]) : qRed(data[i]),
2911 qGreen(data[i]) > threshold ? MaxRGB-qGreen(data[i]) : qGreen(data[i]), 2910 qGreen(data[i]) > threshold ? MaxRGB-qGreen(data[i]) : qGreen(data[i]),
2912 qBlue(data[i]) > threshold ? MaxRGB-qBlue(data[i]) : qBlue(data[i]), 2911 qBlue(data[i]) > threshold ? MaxRGB-qBlue(data[i]) : qBlue(data[i]),
2913 qAlpha(data[i])); 2912 qAlpha(data[i]));
2914 } 2913 }
2915} 2914}
2916 2915
2917QImage OImageEffect::spread(QImage &src, unsigned int amount) 2916QImage OImageEffect::spread(QImage &src, unsigned int amount)
2918{ 2917{
2919 int quantum, x, y; 2918 int quantum, x, y;
2920 int x_distance, y_distance; 2919 int x_distance, y_distance;
2921 if(src.width() < 3 || src.height() < 3) 2920 if(src.width() < 3 || src.height() < 3)
2922 return(src); 2921 return(src);
2923 QImage dest(src); 2922 QImage dest(src);
2924 dest.detach(); 2923 dest.detach();
2925 quantum=(amount+1) >> 1; 2924 quantum=(amount+1) >> 1;
2926 if(src.depth() > 8){ // DirectClass source image 2925 if(src.depth() > 8){ // DirectClass source image
2927 unsigned int *p, *q; 2926 unsigned int *p, *q;
2928 for(y=0; y < src.height(); y++){ 2927 for(y=0; y < src.height(); y++){
2929 q = (unsigned int *)dest.scanLine(y); 2928 q = (unsigned int *)dest.scanLine(y);
2930 for(x=0; x < src.width(); x++){ 2929 for(x=0; x < src.width(); x++){
2931 x_distance = x + ((rand() & (amount+1))-quantum); 2930 x_distance = x + ((rand() & (amount+1))-quantum);
2932 y_distance = y + ((rand() & (amount+1))-quantum); 2931 y_distance = y + ((rand() & (amount+1))-quantum);
2933 x_distance = QMIN(x_distance, src.width()-1); 2932 x_distance = QMIN(x_distance, src.width()-1);
2934 y_distance = QMIN(y_distance, src.height()-1); 2933 y_distance = QMIN(y_distance, src.height()-1);
2935 if(x_distance < 0) 2934 if(x_distance < 0)
2936 x_distance = 0; 2935 x_distance = 0;
2937 if(y_distance < 0) 2936 if(y_distance < 0)
2938 y_distance = 0; 2937 y_distance = 0;
2939 p = (unsigned int *)src.scanLine(y_distance); 2938 p = (unsigned int *)src.scanLine(y_distance);
2940 p += x_distance; 2939 p += x_distance;
2941 *q++=(*p); 2940 *q++=(*p);
2942 } 2941 }
2943 } 2942 }
2944 } 2943 }
2945 else{ // PsudeoClass source image 2944 else{ // PsudeoClass source image
2946 // just do colortable values 2945 // just do colortable values
2947 unsigned char *p, *q; 2946 unsigned char *p, *q;
2948 for(y=0; y < src.height(); y++){ 2947 for(y=0; y < src.height(); y++){
2949 q = (unsigned char *)dest.scanLine(y); 2948 q = (unsigned char *)dest.scanLine(y);
2950 for(x=0; x < src.width(); x++){ 2949 for(x=0; x < src.width(); x++){
2951 x_distance = x + ((rand() & (amount+1))-quantum); 2950 x_distance = x + ((rand() & (amount+1))-quantum);
2952 y_distance = y + ((rand() & (amount+1))-quantum); 2951 y_distance = y + ((rand() & (amount+1))-quantum);
2953 x_distance = QMIN(x_distance, src.width()-1); 2952 x_distance = QMIN(x_distance, src.width()-1);
2954 y_distance = QMIN(y_distance, src.height()-1); 2953 y_distance = QMIN(y_distance, src.height()-1);
2955 if(x_distance < 0) 2954 if(x_distance < 0)
2956 x_distance = 0; 2955 x_distance = 0;
2957 if(y_distance < 0) 2956 if(y_distance < 0)
2958 y_distance = 0; 2957 y_distance = 0;
2959 p = (unsigned char *)src.scanLine(y_distance); 2958 p = (unsigned char *)src.scanLine(y_distance);
2960 p += x_distance; 2959 p += x_distance;
2961 *q++=(*p); 2960 *q++=(*p);
2962 } 2961 }
2963 } 2962 }
2964 } 2963 }
2965 return(dest); 2964 return(dest);
2966} 2965}
2967 2966
2968QImage OImageEffect::swirl(QImage &src, double degrees, 2967QImage OImageEffect::swirl(QImage &src, double degrees,
2969 unsigned int background) 2968 unsigned int background)
2970{ 2969{
2971 double cosine, distance, factor, radius, sine, x_center, x_distance, 2970 double cosine, distance, factor, radius, sine, x_center, x_distance,
2972 x_scale, y_center, y_distance, y_scale; 2971 x_scale, y_center, y_distance, y_scale;
2973 int x, y; 2972 int x, y;
2974 unsigned int *q; 2973 unsigned int *q;
2975 QImage dest(src.width(), src.height(), 32); 2974 QImage dest(src.width(), src.height(), 32);
2976 2975
2977 // compute scaling factor 2976 // compute scaling factor
2978 x_center = src.width()/2.0; 2977 x_center = src.width()/2.0;
2979 y_center = src.height()/2.0; 2978 y_center = src.height()/2.0;
2980 radius = QMAX(x_center,y_center); 2979 radius = QMAX(x_center,y_center);
2981 x_scale=1.0; 2980 x_scale=1.0;
2982 y_scale=1.0; 2981 y_scale=1.0;
2983 if(src.width() > src.height()) 2982 if(src.width() > src.height())
2984 y_scale=(double)src.width()/src.height(); 2983 y_scale=(double)src.width()/src.height();
2985 else if(src.width() < src.height()) 2984 else if(src.width() < src.height())
2986 x_scale=(double)src.height()/src.width(); 2985 x_scale=(double)src.height()/src.width();
2987 degrees=DegreesToRadians(degrees); 2986 degrees=DegreesToRadians(degrees);
2988 // swirl each row 2987 // swirl each row
2989 if(src.depth() > 8){ // DirectClass source image 2988 if(src.depth() > 8){ // DirectClass source image
2990 unsigned int *p; 2989 unsigned int *p;
2991 for(y=0; y < src.height(); y++){ 2990 for(y=0; y < src.height(); y++){
2992 p = (unsigned int *)src.scanLine(y); 2991 p = (unsigned int *)src.scanLine(y);
2993 q = (unsigned int *)dest.scanLine(y); 2992 q = (unsigned int *)dest.scanLine(y);
2994 y_distance = y_scale*(y-y_center); 2993 y_distance = y_scale*(y-y_center);
2995 for(x=0; x < src.width(); x++){ 2994 for(x=0; x < src.width(); x++){
2996 // determine if the pixel is within an ellipse 2995 // determine if the pixel is within an ellipse
2997 *q=(*p); 2996 *q=(*p);
2998 x_distance = x_scale*(x-x_center); 2997 x_distance = x_scale*(x-x_center);
2999 distance = x_distance*x_distance+y_distance*y_distance; 2998 distance = x_distance*x_distance+y_distance*y_distance;
3000 if (distance < (radius*radius)){ 2999 if (distance < (radius*radius)){
3001 // swirl 3000 // swirl
3002 factor = 1.0-sqrt(distance)/radius; 3001 factor = 1.0-sqrt(distance)/radius;
3003 sine = sin(degrees*factor*factor); 3002 sine = sin(degrees*factor*factor);
3004 cosine = cos(degrees*factor*factor); 3003 cosine = cos(degrees*factor*factor);
3005 *q = interpolateColor(&src, 3004 *q = interpolateColor(&src,
3006 (cosine*x_distance-sine*y_distance)/x_scale+x_center, 3005 (cosine*x_distance-sine*y_distance)/x_scale+x_center,
3007 (sine*x_distance+cosine*y_distance)/y_scale+y_center, 3006 (sine*x_distance+cosine*y_distance)/y_scale+y_center,
3008 background); 3007 background);
3009 } 3008 }
3010 p++; 3009 p++;
3011 q++; 3010 q++;
3012 } 3011 }
3013 } 3012 }
3014 } 3013 }
3015 else{ // PsudeoClass source image 3014 else{ // PsudeoClass source image
3016 unsigned char *p; 3015 unsigned char *p;
3017 unsigned int *cTable = (unsigned int *)src.colorTable(); 3016 unsigned int *cTable = (unsigned int *)src.colorTable();
3018 for(y=0; y < src.height(); y++){ 3017 for(y=0; y < src.height(); y++){
3019 p = (unsigned char *)src.scanLine(y); 3018 p = (unsigned char *)src.scanLine(y);
3020 q = (unsigned int *)dest.scanLine(y); 3019 q = (unsigned int *)dest.scanLine(y);
3021 y_distance = y_scale*(y-y_center); 3020 y_distance = y_scale*(y-y_center);
3022 for(x=0; x < src.width(); x++){ 3021 for(x=0; x < src.width(); x++){
3023 // determine if the pixel is within an ellipse 3022 // determine if the pixel is within an ellipse
3024 *q = *(cTable+(*p)); 3023 *q = *(cTable+(*p));
3025 x_distance = x_scale*(x-x_center); 3024 x_distance = x_scale*(x-x_center);
3026 distance = x_distance*x_distance+y_distance*y_distance; 3025 distance = x_distance*x_distance+y_distance*y_distance;
3027 if (distance < (radius*radius)){ 3026 if (distance < (radius*radius)){
3028 // swirl 3027 // swirl
3029 factor = 1.0-sqrt(distance)/radius; 3028 factor = 1.0-sqrt(distance)/radius;
3030 sine = sin(degrees*factor*factor); 3029 sine = sin(degrees*factor*factor);
3031 cosine = cos(degrees*factor*factor); 3030 cosine = cos(degrees*factor*factor);
3032 *q = interpolateColor(&src, 3031 *q = interpolateColor(&src,
3033 (cosine*x_distance-sine*y_distance)/x_scale+x_center, 3032 (cosine*x_distance-sine*y_distance)/x_scale+x_center,
3034 (sine*x_distance+cosine*y_distance)/y_scale+y_center, 3033 (sine*x_distance+cosine*y_distance)/y_scale+y_center,
3035 background); 3034 background);
3036 } 3035 }
3037 p++; 3036 p++;
3038 q++; 3037 q++;
3039 } 3038 }
3040 } 3039 }
3041 3040
3042 } 3041 }
3043 return(dest); 3042 return(dest);
3044} 3043}
3045 3044
3046QImage OImageEffect::wave(QImage &src, double amplitude, double wavelength, 3045QImage OImageEffect::wave(QImage &src, double amplitude, double wavelength,
3047 unsigned int background) 3046 unsigned int background)
3048{ 3047{
3049 double *sine_map; 3048 double *sine_map;
3050 int x, y; 3049 int x, y;
3051 unsigned int *q; 3050 unsigned int *q;
3052 3051
3053 QImage dest(src.width(), src.height() + (int)(2*fabs(amplitude)), 32); 3052 QImage dest(src.width(), src.height() + (int)(2*fabs(amplitude)), 32);
3054 // allocate sine map 3053 // allocate sine map
3055 sine_map = (double *)malloc(dest.width()*sizeof(double)); 3054 sine_map = (double *)malloc(dest.width()*sizeof(double));
3056 if(!sine_map) 3055 if(!sine_map)
3057 return(src); 3056 return(src);
3058 for(x=0; x < dest.width(); ++x) 3057 for(x=0; x < dest.width(); ++x)
3059 sine_map[x]=fabs(amplitude)+amplitude*sin((2*M_PI*x)/wavelength); 3058 sine_map[x]=fabs(amplitude)+amplitude*sin((2*M_PI*x)/wavelength);
3060 // wave image 3059 // wave image
3061 for(y=0; y < dest.height(); ++y){ 3060 for(y=0; y < dest.height(); ++y){
3062 q = (unsigned int *)dest.scanLine(y); 3061 q = (unsigned int *)dest.scanLine(y);
3063 for (x=0; x < dest.width(); x++){ 3062 for (x=0; x < dest.width(); x++){
3064 *q=interpolateColor(&src, x, (int)(y-sine_map[x]), background); 3063 *q=interpolateColor(&src, x, (int)(y-sine_map[x]), background);
3065 ++q; 3064 ++q;
3066 } 3065 }
3067 } 3066 }
3068 free(sine_map); 3067 free(sine_map);
3069 return(dest); 3068 return(dest);
3070} 3069}
3071 3070
3072QImage OImageEffect::oilPaint(QImage &src, int radius) 3071QImage OImageEffect::oilPaint(QImage &src, int radius)
3073{ 3072{
3074 // TODO 8bpp src! 3073 // TODO 8bpp src!
3075 if(src.depth() < 32){ 3074 if(src.depth() < 32){
3076 qWarning("Oil Paint source image < 32bpp. Convert before using!"); 3075 qWarning("Oil Paint source image < 32bpp. Convert before using!");
3077 return(src); 3076 return(src);
3078 } 3077 }
3079 int j, k, i, x, y; 3078 int j, k, i, x, y;
3080 unsigned int *histogram; 3079 unsigned int *histogram;
3081 unsigned int *s; 3080 unsigned int *s;
3082 unsigned int count; 3081 unsigned int count;
3083 3082
3084 unsigned int *srcData, *destData; 3083 unsigned int *srcData, *destData;
3085 3084
3086 QImage dest(src); 3085 QImage dest(src);
3087 dest.detach(); 3086 dest.detach();
3088 histogram = (unsigned int *) malloc((MaxRGB+1)*sizeof(unsigned int)); 3087 histogram = (unsigned int *) malloc((MaxRGB+1)*sizeof(unsigned int));
3089 if(!histogram) 3088 if(!histogram)
3090 return(src); 3089 return(src);
3091 // paint each row 3090 // paint each row
3092 k=0; 3091 k=0;
3093 for(y = radius; y < src.height(); ++y){ 3092 for(y = radius; y < src.height(); ++y){
3094 srcData = (unsigned int *)src.scanLine(y-radius); 3093 srcData = (unsigned int *)src.scanLine(y-radius);
3095 destData = (unsigned int *)dest.scanLine(y); 3094 destData = (unsigned int *)dest.scanLine(y);
3096 srcData += radius*src.width()+radius; 3095 srcData += radius*src.width()+radius;
3097 destData += radius; 3096 destData += radius;
3098 for(x=radius; x < src.width()-radius; ++x){ 3097 for(x=radius; x < src.width()-radius; ++x){
3099 // determine most frequent color 3098 // determine most frequent color
3100 count = 0; 3099 count = 0;
3101 for(i=0; i < MaxRGB+1; ++i) 3100 for(i=0; i < MaxRGB+1; ++i)
3102 histogram[i] = 0; 3101 histogram[i] = 0;
3103 for(i=0; i < radius; ++i){ 3102 for(i=0; i < radius; ++i){
3104 s = srcData-(radius-1)*src.width()-i-1; 3103 s = srcData-(radius-1)*src.width()-i-1;
3105 for(j =0; j < (2*i+1); ++j){ 3104 for(j =0; j < (2*i+1); ++j){
3106 k = intensityValue(*s); 3105 k = intensityValue(*s);
3107 histogram[k]++; 3106 histogram[k]++;
3108 if(histogram[k] > count){ 3107 if(histogram[k] > count){
3109 *destData = *s; 3108 *destData = *s;
3110 count = histogram[k]; 3109 count = histogram[k];
3111 } 3110 }
3112 ++s; 3111 ++s;
3113 } 3112 }
3114 s = srcData+(radius-i)*src.width()-i-1; 3113 s = srcData+(radius-i)*src.width()-i-1;
3115 for(j =0; j < (2*i+1); ++j){ 3114 for(j =0; j < (2*i+1); ++j){
3116 k = intensityValue(*s); 3115 k = intensityValue(*s);
3117 histogram[k]++; 3116 histogram[k]++;
3118 if(histogram[k] > count){ 3117 if(histogram[k] > count){
3119 *destData = *s; 3118 *destData = *s;
3120 count = histogram[k]; 3119 count = histogram[k];
3121 } 3120 }
3122 ++s; 3121 ++s;
3123 } 3122 }
3124 } 3123 }
3125 s = srcData-radius; 3124 s = srcData-radius;
3126 for(j =0; j < (2*i+1); ++j){ 3125 for(j =0; j < (2*i+1); ++j){
3127 k = intensityValue(*s); 3126 k = intensityValue(*s);
3128 histogram[k]++; 3127 histogram[k]++;
3129 if(histogram[k] > count){ 3128 if(histogram[k] > count){
3130 *destData = *s; 3129 *destData = *s;
3131 count = histogram[k]; 3130 count = histogram[k];
3132 } 3131 }
3133 ++s; 3132 ++s;
3134 } 3133 }
3135 ++srcData; 3134 ++srcData;
3136 ++destData; 3135 ++destData;
3137 } 3136 }
3138 } 3137 }
3139 free(histogram); 3138 free(histogram);
3140 return(dest); 3139 return(dest);
3141} 3140}
3142 3141
3143// 3142//
3144// The following methods work by computing a value from neighboring pixels 3143// The following methods work by computing a value from neighboring pixels
3145// (mosfet 12/28/01) 3144// (mosfet 12/28/01)
3146// 3145//
3147 3146
3148QImage OImageEffect::edge(QImage &src, double factor) 3147QImage OImageEffect::edge(QImage &src, double factor)
3149{ 3148{
3150#define Edge(weight) \ 3149#define Edge(weight) \
3151 total_red+=(weight)*qRed(*s); \ 3150 total_red+=(weight)*qRed(*s); \
3152 total_green+=(weight)*qGreen(*s); \ 3151 total_green+=(weight)*qGreen(*s); \
3153 total_blue+=(weight)*qBlue(*s); \ 3152 total_blue+=(weight)*qBlue(*s); \
3154 total_opacity+=(weight)*qAlpha(*s); \ 3153 total_opacity+=(weight)*qAlpha(*s); \
3155 s++; 3154 s++;
3156 3155
3157#define Edge256(weight) \ 3156#define Edge256(weight) \
3158 total_red+=(weight)*qRed(*(cTable+(*s))); \ 3157 total_red+=(weight)*qRed(*(cTable+(*s))); \
3159 total_green+=(weight)*qGreen(*(cTable+(*s))); \ 3158 total_green+=(weight)*qGreen(*(cTable+(*s))); \
3160 total_blue+=(weight)*qBlue(*(cTable+(*s))); \ 3159 total_blue+=(weight)*qBlue(*(cTable+(*s))); \
3161 total_opacity+=(weight)*qAlpha(*(cTable+(*s))); \ 3160 total_opacity+=(weight)*qAlpha(*(cTable+(*s))); \
3162 s++; 3161 s++;
3163 3162
3164 if(src.width() < 3 || src.height() < 3) 3163 if(src.width() < 3 || src.height() < 3)
3165 return(src); 3164 return(src);
3166 3165
3167 double total_blue, total_green, total_opacity, total_red, weight; 3166 double total_blue, total_green, total_opacity, total_red, weight;
3168 3167
3169 int x, y; 3168 int x, y;
3170 3169
3171 unsigned int *q; 3170 unsigned int *q;
3172 3171
3173 QImage dest(src.width(), src.height(), 32); 3172 QImage dest(src.width(), src.height(), 32);
3174 weight=factor/8.0; 3173 weight=factor/8.0;
3175 if(src.depth() > 8){ // DirectClass source image 3174 if(src.depth() > 8){ // DirectClass source image
3176 unsigned int *p, *s; 3175 unsigned int *p, *s;
3177 for(y=0; y < src.height(); ++y){ 3176 for(y=0; y < src.height(); ++y){
3178 p = (unsigned int *)src.scanLine(QMIN(QMAX(y-1,0),src.height()-3)); 3177 p = (unsigned int *)src.scanLine(QMIN(QMAX(y-1,0),src.height()-3));
3179 q = (unsigned int *)dest.scanLine(y); 3178 q = (unsigned int *)dest.scanLine(y);
3180 // edge detect this row of pixels. 3179 // edge detect this row of pixels.
3181 *q++=(*(p+src.width())); 3180 *q++=(*(p+src.width()));
3182 for(x=1; x < src.width()-1; ++x){ 3181 for(x=1; x < src.width()-1; ++x){
3183 // compute weighted average of target pixel color components. 3182 // compute weighted average of target pixel color components.
3184 total_red=0.0; 3183 total_red=0.0;
3185 total_green=0.0; 3184 total_green=0.0;
3186 total_blue=0.0; 3185 total_blue=0.0;
3187 total_opacity=0.0; 3186 total_opacity=0.0;
3188 s=p; 3187 s=p;
3189 Edge(-weight/8); Edge(-weight/8) Edge(-weight/8); 3188 Edge(-weight/8); Edge(-weight/8) Edge(-weight/8);
3190 s=p+src.width(); 3189 s=p+src.width();
3191 Edge(-weight/8); Edge(weight); Edge(-weight/8); 3190 Edge(-weight/8); Edge(weight); Edge(-weight/8);
3192 s=p+2*src.width(); 3191 s=p+2*src.width();
3193 Edge(-weight/8); Edge(-weight/8); Edge(-weight/8); 3192 Edge(-weight/8); Edge(-weight/8); Edge(-weight/8);
3194 *q = qRgba((unsigned char)((total_red < 0) ? 0 : (total_red > MaxRGB) ? MaxRGB : total_red), 3193 *q = qRgba((unsigned char)((total_red < 0) ? 0 : (total_red > MaxRGB) ? MaxRGB : total_red),
3195 (unsigned char)((total_green < 0) ? 0 : (total_green > MaxRGB) ? MaxRGB : total_green), 3194 (unsigned char)((total_green < 0) ? 0 : (total_green > MaxRGB) ? MaxRGB : total_green),
3196 (unsigned char)((total_blue < 0) ? 0 : (total_blue > MaxRGB) ? MaxRGB : total_blue), 3195 (unsigned char)((total_blue < 0) ? 0 : (total_blue > MaxRGB) ? MaxRGB : total_blue),
3197 (unsigned char)((total_opacity < 0) ? 0 : (total_opacity > MaxRGB) ? MaxRGB : total_opacity)); 3196 (unsigned char)((total_opacity < 0) ? 0 : (total_opacity > MaxRGB) ? MaxRGB : total_opacity));
3198 p++; 3197 p++;
3199 q++; 3198 q++;
3200 } 3199 }
3201 p++; 3200 p++;
3202 *q++=(*p); 3201 *q++=(*p);
3203 } 3202 }
3204 } 3203 }
3205 else{ // PsudeoClass source image 3204 else{ // PsudeoClass source image
3206 unsigned char *p, *p2, *p3, *s; 3205 unsigned char *p, *p2, *p3, *s;
3207 unsigned int *cTable = src.colorTable(); 3206 unsigned int *cTable = src.colorTable();
3208 int scanLineIdx; 3207 int scanLineIdx;
3209 for(y=0; y < src.height(); ++y){ 3208 for(y=0; y < src.height(); ++y){
3210 scanLineIdx = QMIN(QMAX(y-1,0),src.height()-3); 3209 scanLineIdx = QMIN(QMAX(y-1,0),src.height()-3);
3211 p = (unsigned char *)src.scanLine(scanLineIdx); 3210 p = (unsigned char *)src.scanLine(scanLineIdx);
3212 p2 = (unsigned char *)src.scanLine(scanLineIdx+1); 3211 p2 = (unsigned char *)src.scanLine(scanLineIdx+1);
3213 p3 = (unsigned char *)src.scanLine(scanLineIdx+2); 3212 p3 = (unsigned char *)src.scanLine(scanLineIdx+2);
3214 q = (unsigned int *)dest.scanLine(y); 3213 q = (unsigned int *)dest.scanLine(y);
3215 // edge detect this row of pixels. 3214 // edge detect this row of pixels.
3216 *q++=(*(cTable+(*p2))); 3215 *q++=(*(cTable+(*p2)));
3217 for(x=1; x < src.width()-1; ++x){ 3216 for(x=1; x < src.width()-1; ++x){
3218 // compute weighted average of target pixel color components. 3217 // compute weighted average of target pixel color components.
3219 total_red=0.0; 3218 total_red=0.0;
3220 total_green=0.0; 3219 total_green=0.0;
3221 total_blue=0.0; 3220 total_blue=0.0;
3222 total_opacity=0.0; 3221 total_opacity=0.0;
3223 s=p; 3222 s=p;
3224 Edge256(-weight/8); Edge256(-weight/8) Edge256(-weight/8); 3223 Edge256(-weight/8); Edge256(-weight/8) Edge256(-weight/8);
3225 s=p2; 3224 s=p2;
3226 Edge256(-weight/8); Edge256(weight); Edge256(-weight/8); 3225 Edge256(-weight/8); Edge256(weight); Edge256(-weight/8);
3227 s=p3; 3226 s=p3;
3228 Edge256(-weight/8); Edge256(-weight/8); Edge256(-weight/8); 3227 Edge256(-weight/8); Edge256(-weight/8); Edge256(-weight/8);
3229 *q = qRgba((unsigned char)((total_red < 0) ? 0 : (total_red > MaxRGB) ? MaxRGB : total_red), 3228 *q = qRgba((unsigned char)((total_red < 0) ? 0 : (total_red > MaxRGB) ? MaxRGB : total_red),
3230 (unsigned char)((total_green < 0) ? 0 : (total_green > MaxRGB) ? MaxRGB : total_green), 3229 (unsigned char)((total_green < 0) ? 0 : (total_green > MaxRGB) ? MaxRGB : total_green),
3231 (unsigned char)((total_blue < 0) ? 0 : (total_blue > MaxRGB) ? MaxRGB : total_blue), 3230 (unsigned char)((total_blue < 0) ? 0 : (total_blue > MaxRGB) ? MaxRGB : total_blue),
3232 (unsigned char)((total_opacity < 0) ? 0 : (total_opacity > MaxRGB) ? MaxRGB : total_opacity)); 3231 (unsigned char)((total_opacity < 0) ? 0 : (total_opacity > MaxRGB) ? MaxRGB : total_opacity));
3233 p++; 3232 p++;
3234 p2++; 3233 p2++;
3235 p3++; 3234 p3++;
3236 q++; 3235 q++;
3237 } 3236 }
3238 p++; 3237 p++;
3239 *q++=(*(cTable+(*p))); 3238 *q++=(*(cTable+(*p)));
3240 } 3239 }
3241 } 3240 }
3242 return(dest); 3241 return(dest);
3243} 3242}
3244 3243
3245QImage OImageEffect::sharpen(QImage &src, double factor) 3244QImage OImageEffect::sharpen(QImage &src, double factor)
3246{ 3245{
3247#define Sharpen(weight) \ 3246#define Sharpen(weight) \
3248 total_red+=(weight)*qRed(*s); \ 3247 total_red+=(weight)*qRed(*s); \
3249 total_green+=(weight)*qGreen(*s); \ 3248 total_green+=(weight)*qGreen(*s); \
3250 total_blue+=(weight)*qBlue(*s); \ 3249 total_blue+=(weight)*qBlue(*s); \
3251 total_opacity+=(weight)*qAlpha(*s); \ 3250 total_opacity+=(weight)*qAlpha(*s); \
3252 s++; 3251 s++;
3253 3252
3254#define Sharpen256(weight) \ 3253#define Sharpen256(weight) \
3255 total_red+=(weight)*qRed(*(cTable+(*s))); \ 3254 total_red+=(weight)*qRed(*(cTable+(*s))); \
3256 total_green+=(weight)*qGreen(*(cTable+(*s))); \ 3255 total_green+=(weight)*qGreen(*(cTable+(*s))); \
3257 total_blue+=(weight)*qBlue(*(cTable+(*s))); \ 3256 total_blue+=(weight)*qBlue(*(cTable+(*s))); \
3258 total_opacity+=(weight)*qAlpha(*(cTable+(*s))); \ 3257 total_opacity+=(weight)*qAlpha(*(cTable+(*s))); \
3259 s++; 3258 s++;
3260 3259
3261 if(src.width() < 3 || src.height() < 3) 3260 if(src.width() < 3 || src.height() < 3)
3262 return(src); 3261 return(src);
3263 3262
3264 double total_blue, total_green, total_opacity, total_red; 3263 double total_blue, total_green, total_opacity, total_red;
3265 double quantum, weight; 3264 double quantum, weight;
3266 unsigned char r, g, b, a; 3265 unsigned char r, g, b, a;
3267 3266
3268 int x, y; 3267 int x, y;
3269 unsigned int *q; 3268 unsigned int *q;
3270 3269
3271 QImage dest(src.width(), src.height(), 32); 3270 QImage dest(src.width(), src.height(), 32);
3272 weight = ((100.0-factor)/2.0+13.0); 3271 weight = ((100.0-factor)/2.0+13.0);
3273 quantum = QMAX(weight-12.0, 1.0); 3272 quantum = QMAX(weight-12.0, 1.0);
3274 if(src.depth() > 8){ // DirectClass source image 3273 if(src.depth() > 8){ // DirectClass source image
3275 unsigned int *p, *s; 3274 unsigned int *p, *s;
3276 for(y=0; y < src.height(); ++y){ 3275 for(y=0; y < src.height(); ++y){
3277 p = (unsigned int *)src.scanLine(QMIN(QMAX(y-1,0),src.height()-3)); 3276 p = (unsigned int *)src.scanLine(QMIN(QMAX(y-1,0),src.height()-3));
3278 q = (unsigned int *)dest.scanLine(y); 3277 q = (unsigned int *)dest.scanLine(y);
3279 // sharpen this row of pixels. 3278 // sharpen this row of pixels.
3280 *q++=(*(p+src.width())); 3279 *q++=(*(p+src.width()));
3281 for(x=1; x < src.width()-1; ++x){ 3280 for(x=1; x < src.width()-1; ++x){
3282 // compute weighted average of target pixel color components. 3281 // compute weighted average of target pixel color components.
3283 total_red=0.0; 3282 total_red=0.0;
3284 total_green=0.0; 3283 total_green=0.0;
3285 total_blue=0.0; 3284 total_blue=0.0;
3286 total_opacity=0.0; 3285 total_opacity=0.0;
3287 s=p; 3286 s=p;
3288 Sharpen(-1); Sharpen(-2); Sharpen(-1); 3287 Sharpen(-1); Sharpen(-2); Sharpen(-1);
3289 s=p+src.width(); 3288 s=p+src.width();
3290 Sharpen(-2); Sharpen(weight); Sharpen(-2); 3289 Sharpen(-2); Sharpen(weight); Sharpen(-2);
3291 s=p+2*src.width(); 3290 s=p+2*src.width();
3292 Sharpen(-1); Sharpen(-2); Sharpen(-1); 3291 Sharpen(-1); Sharpen(-2); Sharpen(-1);
3293 if(total_red < 0) 3292 if(total_red < 0)
3294 r=0; 3293 r=0;
3295 else if(total_red > (int)(MaxRGB*quantum)) 3294 else if(total_red > (int)(MaxRGB*quantum))
3296 r = (unsigned char)MaxRGB; 3295 r = (unsigned char)MaxRGB;
3297 else 3296 else
3298 r = (unsigned char)((total_red+(quantum/2.0))/quantum); 3297 r = (unsigned char)((total_red+(quantum/2.0))/quantum);
3299 3298
3300 if(total_green < 0) 3299 if(total_green < 0)
3301 g = 0; 3300 g = 0;
3302 else if(total_green > (int)(MaxRGB*quantum)) 3301 else if(total_green > (int)(MaxRGB*quantum))
3303 g = (unsigned char)MaxRGB; 3302 g = (unsigned char)MaxRGB;
3304 else 3303 else
3305 g = (unsigned char)((total_green+(quantum/2.0))/quantum); 3304 g = (unsigned char)((total_green+(quantum/2.0))/quantum);
3306 3305
3307 if(total_blue < 0) 3306 if(total_blue < 0)
3308 b = 0; 3307 b = 0;
3309 else if(total_blue > (int)(MaxRGB*quantum)) 3308 else if(total_blue > (int)(MaxRGB*quantum))
3310 b = (unsigned char)MaxRGB; 3309 b = (unsigned char)MaxRGB;
3311 else 3310 else
3312 b = (unsigned char)((total_blue+(quantum/2.0))/quantum); 3311 b = (unsigned char)((total_blue+(quantum/2.0))/quantum);
3313 3312
3314 if(total_opacity < 0) 3313 if(total_opacity < 0)
3315 a = 0; 3314 a = 0;
3316 else if(total_opacity > (int)(MaxRGB*quantum)) 3315 else if(total_opacity > (int)(MaxRGB*quantum))
3317 a = (unsigned char)MaxRGB; 3316 a = (unsigned char)MaxRGB;
3318 else 3317 else
3319 a= (unsigned char)((total_opacity+(quantum/2.0))/quantum); 3318 a= (unsigned char)((total_opacity+(quantum/2.0))/quantum);
3320 3319
3321 *q = qRgba(r, g, b, a); 3320 *q = qRgba(r, g, b, a);
3322 3321
3323 p++; 3322 p++;
3324 q++; 3323 q++;
3325 } 3324 }
3326 p++; 3325 p++;
3327 *q++=(*p); 3326 *q++=(*p);
3328 } 3327 }
3329 } 3328 }
3330 else{ // PsudeoClass source image 3329 else{ // PsudeoClass source image
3331 unsigned char *p, *p2, *p3, *s; 3330 unsigned char *p, *p2, *p3, *s;
3332 unsigned int *cTable = src.colorTable(); 3331 unsigned int *cTable = src.colorTable();
3333 int scanLineIdx; 3332 int scanLineIdx;
3334 for(y=0; y < src.height(); ++y){ 3333 for(y=0; y < src.height(); ++y){
3335 scanLineIdx = QMIN(QMAX(y-1,0),src.height()-3); 3334 scanLineIdx = QMIN(QMAX(y-1,0),src.height()-3);
3336 p = (unsigned char *)src.scanLine(scanLineIdx); 3335 p = (unsigned char *)src.scanLine(scanLineIdx);
3337 p2 = (unsigned char *)src.scanLine(scanLineIdx+1); 3336 p2 = (unsigned char *)src.scanLine(scanLineIdx+1);
3338 p3 = (unsigned char *)src.scanLine(scanLineIdx+2); 3337 p3 = (unsigned char *)src.scanLine(scanLineIdx+2);
3339 q = (unsigned int *)dest.scanLine(y); 3338 q = (unsigned int *)dest.scanLine(y);
3340 // sharpen this row of pixels. 3339 // sharpen this row of pixels.
3341 *q++=(*(cTable+(*p2))); 3340 *q++=(*(cTable+(*p2)));
3342 for(x=1; x < src.width()-1; ++x){ 3341 for(x=1; x < src.width()-1; ++x){
3343 // compute weighted average of target pixel color components. 3342 // compute weighted average of target pixel color components.
3344 total_red=0.0; 3343 total_red=0.0;
3345 total_green=0.0; 3344 total_green=0.0;
3346 total_blue=0.0; 3345 total_blue=0.0;
3347 total_opacity=0.0; 3346 total_opacity=0.0;
3348 s=p; 3347 s=p;
3349 Sharpen256(-1); Sharpen256(-2); Sharpen256(-1); 3348 Sharpen256(-1); Sharpen256(-2); Sharpen256(-1);
3350 s=p2; 3349 s=p2;
3351 Sharpen256(-2); Sharpen256(weight); Sharpen256(-2); 3350 Sharpen256(-2); Sharpen256(weight); Sharpen256(-2);
3352 s=p3; 3351 s=p3;
3353 Sharpen256(-1); Sharpen256(-2); Sharpen256(-1); 3352 Sharpen256(-1); Sharpen256(-2); Sharpen256(-1);
3354 if(total_red < 0) 3353 if(total_red < 0)
3355 r=0; 3354 r=0;
3356 else if(total_red > (int)(MaxRGB*quantum)) 3355 else if(total_red > (int)(MaxRGB*quantum))
3357 r = (unsigned char)MaxRGB; 3356 r = (unsigned char)MaxRGB;
3358 else 3357 else
3359 r = (unsigned char)((total_red+(quantum/2.0))/quantum); 3358 r = (unsigned char)((total_red+(quantum/2.0))/quantum);
3360 3359
3361 if(total_green < 0) 3360 if(total_green < 0)
3362 g = 0; 3361 g = 0;
3363 else if(total_green > (int)(MaxRGB*quantum)) 3362 else if(total_green > (int)(MaxRGB*quantum))
3364 g = (unsigned char)MaxRGB; 3363 g = (unsigned char)MaxRGB;
3365 else 3364 else
3366 g = (unsigned char)((total_green+(quantum/2.0))/quantum); 3365 g = (unsigned char)((total_green+(quantum/2.0))/quantum);
3367 3366
3368 if(total_blue < 0) 3367 if(total_blue < 0)
3369 b = 0; 3368 b = 0;
3370 else if(total_blue > (int)(MaxRGB*quantum)) 3369 else if(total_blue > (int)(MaxRGB*quantum))
3371 b = (unsigned char)MaxRGB; 3370 b = (unsigned char)MaxRGB;
3372 else 3371 else
3373 b = (unsigned char)((total_blue+(quantum/2.0))/quantum); 3372 b = (unsigned char)((total_blue+(quantum/2.0))/quantum);
3374 3373
3375 if(total_opacity < 0) 3374 if(total_opacity < 0)
3376 a = 0; 3375 a = 0;
3377 else if(total_opacity > (int)(MaxRGB*quantum)) 3376 else if(total_opacity > (int)(MaxRGB*quantum))
3378 a = (unsigned char)MaxRGB; 3377 a = (unsigned char)MaxRGB;
3379 else 3378 else
3380 a = (unsigned char)((total_opacity+(quantum/2.0))/quantum); 3379 a = (unsigned char)((total_opacity+(quantum/2.0))/quantum);
3381 3380
3382 *q = qRgba(r, g, b, a); 3381 *q = qRgba(r, g, b, a);
3383 3382
3384 p++; 3383 p++;
3385 p2++; 3384 p2++;
3386 p3++; 3385 p3++;
3387 q++; 3386 q++;
3388 } 3387 }
3389 p++; 3388 p++;
3390 *q++=(*(cTable+(*p))); 3389 *q++=(*(cTable+(*p)));
3391 } 3390 }
3392 } 3391 }
3393 return(dest); 3392 return(dest);
3394} 3393}
3395 3394
3396QImage OImageEffect::emboss(QImage &src) 3395QImage OImageEffect::emboss(QImage &src)
3397{ 3396{
3398#define Emboss(weight) \ 3397#define Emboss(weight) \
3399 total_red+=(weight)*qRed(*s); \ 3398 total_red+=(weight)*qRed(*s); \
3400 total_green+=(weight)*qGreen(*s); \ 3399 total_green+=(weight)*qGreen(*s); \
3401 total_blue+=(weight)*qBlue(*s); \ 3400 total_blue+=(weight)*qBlue(*s); \
3402 s++; 3401 s++;
3403 3402
3404#define Emboss256(weight) \ 3403#define Emboss256(weight) \
3405 total_red+=(weight)*qRed(*(cTable+(*s))); \ 3404 total_red+=(weight)*qRed(*(cTable+(*s))); \
3406 total_green+=(weight)*qGreen(*(cTable+(*s))); \ 3405 total_green+=(weight)*qGreen(*(cTable+(*s))); \
3407 total_blue+=(weight)*qBlue(*(cTable+(*s))); \ 3406 total_blue+=(weight)*qBlue(*(cTable+(*s))); \
3408 s++; 3407 s++;
3409 3408
3410 if(src.width() < 3 || src.height() < 3) 3409 if(src.width() < 3 || src.height() < 3)
3411 return(src); 3410 return(src);
3412 3411
3413 double total_blue, total_green, total_red; 3412 double total_blue, total_green, total_red;
3414 int x, y; 3413 int x, y;
3415 unsigned int *q; 3414 unsigned int *q;
3416 3415
3417 QImage dest(src.width(), src.height(), 32); 3416 QImage dest(src.width(), src.height(), 32);
3418 if(src.depth() > 8){ // DirectClass source image 3417 if(src.depth() > 8){ // DirectClass source image
3419 unsigned int *p, *s; 3418 unsigned int *p, *s;
3420 for(y=0; y < src.height(); ++y){ 3419 for(y=0; y < src.height(); ++y){
3421 p = (unsigned int *)src.scanLine(QMIN(QMAX(y-1,0),src.height()-3)); 3420 p = (unsigned int *)src.scanLine(QMIN(QMAX(y-1,0),src.height()-3));
3422 q = (unsigned int *)dest.scanLine(y); 3421 q = (unsigned int *)dest.scanLine(y);
3423 // emboss this row of pixels. 3422 // emboss this row of pixels.
3424 *q++=(*(p+src.width())); 3423 *q++=(*(p+src.width()));
3425 for(x=1; x < src.width()-1; ++x){ 3424 for(x=1; x < src.width()-1; ++x){
3426 // compute weighted average of target pixel color components. 3425 // compute weighted average of target pixel color components.
3427 total_red=0.0; 3426 total_red=0.0;
3428 total_green=0.0; 3427 total_green=0.0;
3429 total_blue=0.0; 3428 total_blue=0.0;
3430 s=p; 3429 s=p;
3431 Emboss(-1); Emboss(-2); Emboss( 0); 3430 Emboss(-1); Emboss(-2); Emboss( 0);
3432 s=p+src.width(); 3431 s=p+src.width();
3433 Emboss(-2); Emboss( 0); Emboss( 2); 3432 Emboss(-2); Emboss( 0); Emboss( 2);
3434 s=p+2*src.width(); 3433 s=p+2*src.width();
3435 Emboss( 0); Emboss( 2); Emboss( 1); 3434 Emboss( 0); Emboss( 2); Emboss( 1);
3436 total_red += (MaxRGB+1)/2; 3435 total_red += (MaxRGB+1)/2;
3437 total_green += (MaxRGB+1)/2; 3436 total_green += (MaxRGB+1)/2;
3438 total_blue += (MaxRGB+1)/2; 3437 total_blue += (MaxRGB+1)/2;
3439 *q = qRgba((unsigned char)((total_red < 0) ? 0 : (total_red > MaxRGB) ? MaxRGB : total_red), 3438 *q = qRgba((unsigned char)((total_red < 0) ? 0 : (total_red > MaxRGB) ? MaxRGB : total_red),
3440 (unsigned char)((total_green < 0) ? 0 : (total_green > MaxRGB) ? MaxRGB : total_green), 3439 (unsigned char)((total_green < 0) ? 0 : (total_green > MaxRGB) ? MaxRGB : total_green),
3441 (unsigned char)((total_blue < 0) ? 0 : (total_blue > MaxRGB) ? MaxRGB : total_blue), 3440 (unsigned char)((total_blue < 0) ? 0 : (total_blue > MaxRGB) ? MaxRGB : total_blue),
3442 255); 3441 255);
3443 p++; 3442 p++;
3444 q++; 3443 q++;
3445 } 3444 }
3446 p++; 3445 p++;
3447 *q++=(*p); 3446 *q++=(*p);
3448 } 3447 }
3449 } 3448 }
3450 else{ // PsudeoClass source image 3449 else{ // PsudeoClass source image
3451 unsigned char *p, *p2, *p3, *s; 3450 unsigned char *p, *p2, *p3, *s;
3452 unsigned int *cTable = src.colorTable(); 3451 unsigned int *cTable = src.colorTable();
3453 int scanLineIdx; 3452 int scanLineIdx;
3454 for(y=0; y < src.height(); ++y){ 3453 for(y=0; y < src.height(); ++y){
3455 scanLineIdx = QMIN(QMAX(y-1,0),src.height()-3); 3454 scanLineIdx = QMIN(QMAX(y-1,0),src.height()-3);
3456 p = (unsigned char *)src.scanLine(scanLineIdx); 3455 p = (unsigned char *)src.scanLine(scanLineIdx);
3457 p2 = (unsigned char *)src.scanLine(scanLineIdx+1); 3456 p2 = (unsigned char *)src.scanLine(scanLineIdx+1);
3458 p3 = (unsigned char *)src.scanLine(scanLineIdx+2); 3457 p3 = (unsigned char *)src.scanLine(scanLineIdx+2);
3459 q = (unsigned int *)dest.scanLine(y); 3458 q = (unsigned int *)dest.scanLine(y);
3460 // emboss this row of pixels. 3459 // emboss this row of pixels.
3461 *q++=(*(cTable+(*p2))); 3460 *q++=(*(cTable+(*p2)));
3462 for(x=1; x < src.width()-1; ++x){ 3461 for(x=1; x < src.width()-1; ++x){
3463 // compute weighted average of target pixel color components. 3462 // compute weighted average of target pixel color components.
3464 total_red=0.0; 3463 total_red=0.0;
3465 total_green=0.0; 3464 total_green=0.0;
3466 total_blue=0.0; 3465 total_blue=0.0;
3467 s=p; 3466 s=p;
3468 Emboss256(-1); Emboss256(-2); Emboss256(0); 3467 Emboss256(-1); Emboss256(-2); Emboss256(0);
3469 s=p2; 3468 s=p2;
3470 Emboss256(-2); Emboss256(0); Emboss256(2); 3469 Emboss256(-2); Emboss256(0); Emboss256(2);
3471 s=p3; 3470 s=p3;
3472 Emboss256(0); Emboss256(2); Emboss256(1); 3471 Emboss256(0); Emboss256(2); Emboss256(1);
3473 total_red += (MaxRGB+1)/2; 3472 total_red += (MaxRGB+1)/2;
3474 total_green += (MaxRGB+1)/2; 3473 total_green += (MaxRGB+1)/2;
3475 total_blue += (MaxRGB+1)/2; 3474 total_blue += (MaxRGB+1)/2;
3476 *q = qRgba((unsigned char)((total_red < 0) ? 0 : (total_red > MaxRGB) ? MaxRGB : total_red), 3475 *q = qRgba((unsigned char)((total_red < 0) ? 0 : (total_red > MaxRGB) ? MaxRGB : total_red),
3477 (unsigned char)((total_green < 0) ? 0 : (total_green > MaxRGB) ? MaxRGB : total_green), 3476 (unsigned char)((total_green < 0) ? 0 : (total_green > MaxRGB) ? MaxRGB : total_green),
3478 (unsigned char)((total_blue < 0) ? 0 : (total_blue > MaxRGB) ? MaxRGB : total_blue), 3477 (unsigned char)((total_blue < 0) ? 0 : (total_blue > MaxRGB) ? MaxRGB : total_blue),
3479 255); 3478 255);
3480 p++; 3479 p++;
3481 p2++; 3480 p2++;
3482 p3++; 3481 p3++;
3483 q++; 3482 q++;
3484 } 3483 }
3485 p++; 3484 p++;
3486 *q++=(*(cTable+(*p))); 3485 *q++=(*(cTable+(*p)));
3487 } 3486 }
3488 } 3487 }
3489 toGray(dest); 3488 toGray(dest);
3490 normalize(dest); 3489 normalize(dest);
3491 return(dest); 3490 return(dest);
3492} 3491}
3493 3492
3494QImage OImageEffect::shade(QImage &src, bool color_shading, double azimuth, 3493QImage OImageEffect::shade(QImage &src, bool color_shading, double azimuth,
3495 double elevation) 3494 double elevation)
3496{ 3495{
3497 struct PointInfo{ 3496 struct PointInfo{
3498 double x, y, z; 3497 double x, y, z;
3499 }; 3498 };
3500 3499
3501 double distance, normal_distance, shade; 3500 double distance, normal_distance, shade;
3502 int x, y; 3501 int x, y;
3503 3502
3504 struct PointInfo light, normal; 3503 struct PointInfo light, normal;
3505 3504
3506 unsigned int *q; 3505 unsigned int *q;
3507 3506
3508 QImage dest(src.width(), src.height(), 32); 3507 QImage dest(src.width(), src.height(), 32);
3509 3508
3510 azimuth = DegreesToRadians(azimuth); 3509 azimuth = DegreesToRadians(azimuth);
3511 elevation = DegreesToRadians(elevation); 3510 elevation = DegreesToRadians(elevation);
3512 light.x = MaxRGB*cos(azimuth)*cos(elevation); 3511 light.x = MaxRGB*cos(azimuth)*cos(elevation);
3513 light.y = MaxRGB*sin(azimuth)*cos(elevation); 3512 light.y = MaxRGB*sin(azimuth)*cos(elevation);
3514 light.z = MaxRGB*sin(elevation); 3513 light.z = MaxRGB*sin(elevation);
3515 normal.z= 2*MaxRGB; // constant Z of surface normal 3514 normal.z= 2*MaxRGB; // constant Z of surface normal
3516 3515
3517 if(src.depth() > 8){ // DirectClass source image 3516 if(src.depth() > 8){ // DirectClass source image
3518 unsigned int *p, *s0, *s1, *s2; 3517 unsigned int *p, *s0, *s1, *s2;
3519 for(y=0; y < src.height(); ++y){ 3518 for(y=0; y < src.height(); ++y){
3520 p = (unsigned int *)src.scanLine(QMIN(QMAX(y-1,0),src.height()-3)); 3519 p = (unsigned int *)src.scanLine(QMIN(QMAX(y-1,0),src.height()-3));
3521 q = (unsigned int *)dest.scanLine(y); 3520 q = (unsigned int *)dest.scanLine(y);
3522 // shade this row of pixels. 3521 // shade this row of pixels.
3523 *q++=(*(p+src.width())); 3522 *q++=(*(p+src.width()));
3524 p++; 3523 p++;
3525 s0 = p; 3524 s0 = p;
3526 s1 = p + src.width(); 3525 s1 = p + src.width();
3527 s2 = p + 2*src.width(); 3526 s2 = p + 2*src.width();
3528 for(x=1; x < src.width()-1; ++x){ 3527 for(x=1; x < src.width()-1; ++x){
3529 // determine the surface normal and compute shading. 3528 // determine the surface normal and compute shading.
3530 normal.x=intensityValue(*(s0-1))+intensityValue(*(s1-1))+intensityValue(*(s2-1))- 3529 normal.x=intensityValue(*(s0-1))+intensityValue(*(s1-1))+intensityValue(*(s2-1))-
3531 (double) intensityValue(*(s0+1))-(double) intensityValue(*(s1+1))- 3530 (double) intensityValue(*(s0+1))-(double) intensityValue(*(s1+1))-
3532 (double) intensityValue(*(s2+1)); 3531 (double) intensityValue(*(s2+1));
3533 normal.y=intensityValue(*(s2-1))+intensityValue(*s2)+intensityValue(*(s2+1))- 3532 normal.y=intensityValue(*(s2-1))+intensityValue(*s2)+intensityValue(*(s2+1))-
3534 (double) intensityValue(*(s0-1))-(double) intensityValue(*s0)- 3533 (double) intensityValue(*(s0-1))-(double) intensityValue(*s0)-
3535 (double) intensityValue(*(s0+1)); 3534 (double) intensityValue(*(s0+1));
3536 if((normal.x == 0) && (normal.y == 0)) 3535 if((normal.x == 0) && (normal.y == 0))
3537 shade=light.z; 3536 shade=light.z;
3538 else{ 3537 else{
3539 shade=0.0; 3538 shade=0.0;
3540 distance=normal.x*light.x+normal.y*light.y+normal.z*light.z; 3539 distance=normal.x*light.x+normal.y*light.y+normal.z*light.z;
3541 if (distance > 0.0){ 3540 if (distance > 0.0){
3542 normal_distance= 3541 normal_distance=
3543 normal.x*normal.x+normal.y*normal.y+normal.z*normal.z; 3542 normal.x*normal.x+normal.y*normal.y+normal.z*normal.z;
3544 if(fabs(normal_distance) > 0.0000001) 3543 if(fabs(normal_distance) > 0.0000001)
3545 shade=distance/sqrt(normal_distance); 3544 shade=distance/sqrt(normal_distance);
3546 } 3545 }
3547 } 3546 }
3548 if(!color_shading){ 3547 if(!color_shading){
3549 *q = qRgba((unsigned char)(shade), 3548 *q = qRgba((unsigned char)(shade),
3550 (unsigned char)(shade), 3549 (unsigned char)(shade),
3551 (unsigned char)(shade), 3550 (unsigned char)(shade),
3552 qAlpha(*s1)); 3551 qAlpha(*s1));
3553 } 3552 }
3554 else{ 3553 else{
3555 *q = qRgba((unsigned char)((shade*qRed(*s1))/(MaxRGB+1)), 3554 *q = qRgba((unsigned char)((shade*qRed(*s1))/(MaxRGB+1)),
3556 (unsigned char)((shade*qGreen(*s1))/(MaxRGB+1)), 3555 (unsigned char)((shade*qGreen(*s1))/(MaxRGB+1)),
3557 (unsigned char)((shade*qBlue(*s1))/(MaxRGB+1)), 3556 (unsigned char)((shade*qBlue(*s1))/(MaxRGB+1)),
3558 qAlpha(*s1)); 3557 qAlpha(*s1));
3559 } 3558 }
3560 ++s0; 3559 ++s0;
3561 ++s1; 3560 ++s1;
3562 ++s2; 3561 ++s2;
3563 q++; 3562 q++;
3564 } 3563 }
3565 *q++=(*s1); 3564 *q++=(*s1);
3566 } 3565 }
3567 } 3566 }
3568 else{ // PsudeoClass source image 3567 else{ // PsudeoClass source image
3569 unsigned char *p, *s0, *s1, *s2; 3568 unsigned char *p, *s0, *s1, *s2;
3570 int scanLineIdx; 3569 int scanLineIdx;
3571 unsigned int *cTable = (unsigned int *)src.colorTable(); 3570 unsigned int *cTable = (unsigned int *)src.colorTable();
3572 for(y=0; y < src.height(); ++y){ 3571 for(y=0; y < src.height(); ++y){
3573 scanLineIdx = QMIN(QMAX(y-1,0),src.height()-3); 3572 scanLineIdx = QMIN(QMAX(y-1,0),src.height()-3);
3574 p = (unsigned char *)src.scanLine(scanLineIdx); 3573 p = (unsigned char *)src.scanLine(scanLineIdx);
3575 q = (unsigned int *)dest.scanLine(y); 3574 q = (unsigned int *)dest.scanLine(y);
3576 // shade this row of pixels. 3575 // shade this row of pixels.
3577 s0 = p; 3576 s0 = p;
3578 s1 = (unsigned char *) src.scanLine(scanLineIdx+1); 3577 s1 = (unsigned char *) src.scanLine(scanLineIdx+1);
3579 s2 = (unsigned char *) src.scanLine(scanLineIdx+2); 3578 s2 = (unsigned char *) src.scanLine(scanLineIdx+2);
3580 *q++=(*(cTable+(*s1))); 3579 *q++=(*(cTable+(*s1)));
3581 ++p; 3580 ++p;
3582 ++s0; 3581 ++s0;
3583 ++s1; 3582 ++s1;
3584 ++s2; 3583 ++s2;
3585 for(x=1; x < src.width()-1; ++x){ 3584 for(x=1; x < src.width()-1; ++x){
3586 // determine the surface normal and compute shading. 3585 // determine the surface normal and compute shading.
3587 normal.x=intensityValue(*(cTable+(*(s0-1))))+intensityValue(*(cTable+(*(s1-1))))+intensityValue(*(cTable+(*(s2-1))))- 3586 normal.x=intensityValue(*(cTable+(*(s0-1))))+intensityValue(*(cTable+(*(s1-1))))+intensityValue(*(cTable+(*(s2-1))))-
3588 (double) intensityValue(*(cTable+(*(s0+1))))-(double) intensityValue(*(cTable+(*(s1+1))))- 3587 (double) intensityValue(*(cTable+(*(s0+1))))-(double) intensityValue(*(cTable+(*(s1+1))))-
3589 (double) intensityValue(*(cTable+(*(s2+1)))); 3588 (double) intensityValue(*(cTable+(*(s2+1))));
3590 normal.y=intensityValue(*(cTable+(*(s2-1))))+intensityValue(*(cTable+(*s2)))+intensityValue(*(cTable+(*(s2+1))))- 3589 normal.y=intensityValue(*(cTable+(*(s2-1))))+intensityValue(*(cTable+(*s2)))+intensityValue(*(cTable+(*(s2+1))))-
3591 (double) intensityValue(*(cTable+(*(s0-1))))-(double) intensityValue(*(cTable+(*s0)))- 3590 (double) intensityValue(*(cTable+(*(s0-1))))-(double) intensityValue(*(cTable+(*s0)))-
3592 (double) intensityValue(*(cTable+(*(s0+1)))); 3591 (double) intensityValue(*(cTable+(*(s0+1))));
3593 if((normal.x == 0) && (normal.y == 0)) 3592 if((normal.x == 0) && (normal.y == 0))
3594 shade=light.z; 3593 shade=light.z;
3595 else{ 3594 else{
3596 shade=0.0; 3595 shade=0.0;
3597 distance=normal.x*light.x+normal.y*light.y+normal.z*light.z; 3596 distance=normal.x*light.x+normal.y*light.y+normal.z*light.z;
3598 if (distance > 0.0){ 3597 if (distance > 0.0){
3599 normal_distance= 3598 normal_distance=
3600 normal.x*normal.x+normal.y*normal.y+normal.z*normal.z; 3599 normal.x*normal.x+normal.y*normal.y+normal.z*normal.z;
3601 if(fabs(normal_distance) > 0.0000001) 3600 if(fabs(normal_distance) > 0.0000001)
3602 shade=distance/sqrt(normal_distance); 3601 shade=distance/sqrt(normal_distance);
3603 } 3602 }
3604 } 3603 }
3605 if(!color_shading){ 3604 if(!color_shading){
3606 *q = qRgba((unsigned char)(shade), 3605 *q = qRgba((unsigned char)(shade),
3607 (unsigned char)(shade), 3606 (unsigned char)(shade),
3608 (unsigned char)(shade), 3607 (unsigned char)(shade),
3609 qAlpha(*(cTable+(*s1)))); 3608 qAlpha(*(cTable+(*s1))));
3610 } 3609 }
3611 else{ 3610 else{
3612 *q = qRgba((unsigned char)((shade*qRed(*(cTable+(*s1))))/(MaxRGB+1)), 3611 *q = qRgba((unsigned char)((shade*qRed(*(cTable+(*s1))))/(MaxRGB+1)),
3613 (unsigned char)((shade*qGreen(*(cTable+(*s1))))/(MaxRGB+1)), 3612 (unsigned char)((shade*qGreen(*(cTable+(*s1))))/(MaxRGB+1)),
3614 (unsigned char)((shade*qBlue(*(cTable+(*s1))))/(MaxRGB+1)), 3613 (unsigned char)((shade*qBlue(*(cTable+(*s1))))/(MaxRGB+1)),
3615 qAlpha(*s1)); 3614 qAlpha(*s1));
3616 } 3615 }
3617 ++s0; 3616 ++s0;
3618 ++s1; 3617 ++s1;
3619 ++s2; 3618 ++s2;
3620 q++; 3619 q++;
3621 } 3620 }
3622 *q++=(*(cTable+(*s1))); 3621 *q++=(*(cTable+(*s1)));
3623 } 3622 }
3624 } 3623 }
3625 return(dest); 3624 return(dest);
3626} 3625}
3627 3626
3628QImage OImageEffect::blur(QImage &src, double factor) 3627QImage OImageEffect::blur(QImage &src, double factor)
3629{ 3628{
3630 3629
3631#define Blur(weight) \ 3630#define Blur(weight) \
3632 total_red+=(weight)*qRed(*s); \ 3631 total_red+=(weight)*qRed(*s); \
3633 total_green+=(weight)*qGreen(*s); \ 3632 total_green+=(weight)*qGreen(*s); \
3634 total_blue+=(weight)*qBlue(*s); \ 3633 total_blue+=(weight)*qBlue(*s); \
3635 total_opacity+=(weight)*qAlpha(*s); \ 3634 total_opacity+=(weight)*qAlpha(*s); \
3636 s++; 3635 s++;
3637 3636
3638#define Blur256(weight) \ 3637#define Blur256(weight) \
3639 total_red+=(weight)*qRed(*(cTable+(*s))); \ 3638 total_red+=(weight)*qRed(*(cTable+(*s))); \
3640 total_green+=(weight)*qGreen(*(cTable+(*s))); \ 3639 total_green+=(weight)*qGreen(*(cTable+(*s))); \
3641 total_blue+=(weight)*qBlue(*(cTable+(*s))); \ 3640 total_blue+=(weight)*qBlue(*(cTable+(*s))); \
3642 total_opacity+=(weight)*qAlpha(*(cTable+(*s))); \ 3641 total_opacity+=(weight)*qAlpha(*(cTable+(*s))); \
3643 s++; 3642 s++;
3644 3643
3645 if(src.width() < 3 || src.height() < 3) 3644 if(src.width() < 3 || src.height() < 3)
3646 return(src); 3645 return(src);
3647 3646
3648 double quantum, total_blue, total_green, total_opacity, total_red, weight; 3647 double quantum, total_blue, total_green, total_opacity, total_red, weight;
3649 3648
3650 int x, y; 3649 int x, y;
3651 unsigned int *q; 3650 unsigned int *q;
3652 3651
3653 QImage dest(src.width(), src.height(), 32); 3652 QImage dest(src.width(), src.height(), 32);
3654 weight=((100.0-factor)/2)+1; 3653 weight=((100.0-factor)/2)+1;
3655 quantum = QMAX(weight+12.0, 1.0); 3654 quantum = QMAX(weight+12.0, 1.0);
3656 if(src.depth() > 8){ // DirectClass source image 3655 if(src.depth() > 8){ // DirectClass source image
3657 unsigned int *p, *s; 3656 unsigned int *p, *s;
3658 for(y=0; y < src.height(); ++y){ 3657 for(y=0; y < src.height(); ++y){
3659 p = (unsigned int *)src.scanLine(QMIN(QMAX(y-1,0),src.height()-3)); 3658 p = (unsigned int *)src.scanLine(QMIN(QMAX(y-1,0),src.height()-3));
3660 q = (unsigned int *)dest.scanLine(y); 3659 q = (unsigned int *)dest.scanLine(y);
3661 // blur this row of pixels. 3660 // blur this row of pixels.
3662 *q++=(*(p+src.width())); 3661 *q++=(*(p+src.width()));
3663 for(x=1; x < src.width()-1; ++x){ 3662 for(x=1; x < src.width()-1; ++x){
3664 // compute weighted average of target pixel color components. 3663 // compute weighted average of target pixel color components.
3665 total_red=0.0; 3664 total_red=0.0;
3666 total_green=0.0; 3665 total_green=0.0;
3667 total_blue=0.0; 3666 total_blue=0.0;
3668 total_opacity=0.0; 3667 total_opacity=0.0;
3669 s=p; 3668 s=p;
3670 Blur(1); Blur(2); Blur(1); 3669 Blur(1); Blur(2); Blur(1);
3671 s=p+src.width(); 3670 s=p+src.width();
3672 Blur(2); Blur(weight); Blur(2); 3671 Blur(2); Blur(weight); Blur(2);
3673 s=p+2*src.width(); 3672 s=p+2*src.width();
3674 Blur(1); Blur(2); Blur(1); 3673 Blur(1); Blur(2); Blur(1);
3675 *q = qRgba((unsigned char)((total_red+(quantum/2))/quantum), 3674 *q = qRgba((unsigned char)((total_red+(quantum/2))/quantum),
3676 (unsigned char)((total_green+(quantum/2))/quantum), 3675 (unsigned char)((total_green+(quantum/2))/quantum),
3677 (unsigned char)((total_blue+(quantum/2))/quantum), 3676 (unsigned char)((total_blue+(quantum/2))/quantum),
3678 (unsigned char)((total_opacity+(quantum/2))/quantum)); 3677 (unsigned char)((total_opacity+(quantum/2))/quantum));
3679 p++; 3678 p++;
3680 q++; 3679 q++;
3681 } 3680 }
3682 p++; 3681 p++;
3683 *q++=(*p); 3682 *q++=(*p);
3684 } 3683 }
3685 } 3684 }
3686 else{ // PsudeoClass source image 3685 else{ // PsudeoClass source image
3687 unsigned char *p, *p2, *p3, *s; 3686 unsigned char *p, *p2, *p3, *s;
3688 unsigned int *cTable = src.colorTable(); 3687 unsigned int *cTable = src.colorTable();
3689 int scanLineIdx; 3688 int scanLineIdx;
3690 for(y=0; y < src.height(); ++y){ 3689 for(y=0; y < src.height(); ++y){
3691 scanLineIdx = QMIN(QMAX(y-1,0),src.height()-3); 3690 scanLineIdx = QMIN(QMAX(y-1,0),src.height()-3);
3692 p = (unsigned char *)src.scanLine(scanLineIdx); 3691 p = (unsigned char *)src.scanLine(scanLineIdx);
3693 p2 = (unsigned char *)src.scanLine(scanLineIdx+1); 3692 p2 = (unsigned char *)src.scanLine(scanLineIdx+1);
3694 p3 = (unsigned char *)src.scanLine(scanLineIdx+2); 3693 p3 = (unsigned char *)src.scanLine(scanLineIdx+2);
3695 q = (unsigned int *)dest.scanLine(y); 3694 q = (unsigned int *)dest.scanLine(y);
3696 // blur this row of pixels. 3695 // blur this row of pixels.
3697 *q++=(*(cTable+(*p2))); 3696 *q++=(*(cTable+(*p2)));
3698 for(x=1; x < src.width()-1; ++x){ 3697 for(x=1; x < src.width()-1; ++x){
3699 // compute weighted average of target pixel color components. 3698 // compute weighted average of target pixel color components.
3700 total_red=0.0; 3699 total_red=0.0;
3701 total_green=0.0; 3700 total_green=0.0;
3702 total_blue=0.0; 3701 total_blue=0.0;
3703 total_opacity=0.0; 3702 total_opacity=0.0;
3704 s=p; 3703 s=p;
3705 Blur256(1); Blur256(2); Blur256(1); 3704 Blur256(1); Blur256(2); Blur256(1);
3706 s=p2; 3705 s=p2;
3707 Blur256(2); Blur256(weight); Blur256(2); 3706 Blur256(2); Blur256(weight); Blur256(2);
3708 s=p3; 3707 s=p3;
3709 Blur256(1); Blur256(2); Blur256(1); 3708 Blur256(1); Blur256(2); Blur256(1);
3710 *q = qRgba((unsigned char)((total_red+(quantum/2))/quantum), 3709 *q = qRgba((unsigned char)((total_red+(quantum/2))/quantum),
3711 (unsigned char)((total_green+(quantum/2))/quantum), 3710 (unsigned char)((total_green+(quantum/2))/quantum),
3712 (unsigned char)((total_blue+(quantum/2))/quantum), 3711 (unsigned char)((total_blue+(quantum/2))/quantum),
3713 (unsigned char)((total_opacity+(quantum/2))/quantum)); 3712 (unsigned char)((total_opacity+(quantum/2))/quantum));
3714 p++; 3713 p++;
3715 p2++; 3714 p2++;
3716 p3++; 3715 p3++;
3717 q++; 3716 q++;
3718 } 3717 }
3719 p++; 3718 p++;
3720 *q++=(*(cTable+(*p))); 3719 *q++=(*(cTable+(*p)));
3721 } 3720 }
3722 } 3721 }
3723 return(dest); 3722 return(dest);
3724} 3723}
3725 3724
3726// High quality, expensive HSV contrast. You can do a faster one by just 3725// High quality, expensive HSV contrast. You can do a faster one by just
3727// taking a grayscale threshold (ie: 128) and incrementing RGB color 3726// taking a grayscale threshold (ie: 128) and incrementing RGB color
3728// channels above it and decrementing those below it, but this gives much 3727// channels above it and decrementing those below it, but this gives much
3729// better results. (mosfet 12/28/01) 3728// better results. (mosfet 12/28/01)
3730void OImageEffect::contrastHSV(QImage &img, bool sharpen) 3729void OImageEffect::contrastHSV(QImage &img, bool sharpen)
3731{ 3730{
3732 int i, sign; 3731 int i, sign;
3733 unsigned int *data; 3732 unsigned int *data;
3734 int count; 3733 int count;
3735 double brightness, scale, theta; 3734 double brightness, scale, theta;
3736 QColor c; 3735 QColor c;
3737 int h, s, v; 3736 int h, s, v;
3738 3737
3739 sign = sharpen ? 1 : -1; 3738 sign = sharpen ? 1 : -1;
3740 scale=0.5000000000000001; 3739 scale=0.5000000000000001;
3741 if(img.depth() > 8){ 3740 if(img.depth() > 8){
3742 count = img.width()*img.height(); 3741 count = img.width()*img.height();
3743 data = (unsigned int *)img.bits(); 3742 data = (unsigned int *)img.bits();
3744 } 3743 }
3745 else{ 3744 else{
3746 count = img.numColors(); 3745 count = img.numColors();
3747 data = (unsigned int *)img.colorTable(); 3746 data = (unsigned int *)img.colorTable();
3748 } 3747 }
3749 for(i=0; i < count; ++i){ 3748 for(i=0; i < count; ++i){
3750 c.setRgb(data[i]); 3749 c.setRgb(data[i]);
3751 c.hsv(&h, &s, &v); 3750 c.hsv(&h, &s, &v);
3752 brightness = v/255.0; 3751 brightness = v/255.0;
3753 theta=(brightness-0.5)*M_PI; 3752 theta=(brightness-0.5)*M_PI;
3754 brightness+=scale*(((scale*((sin(theta)+1.0)))-brightness)*sign); 3753 brightness+=scale*(((scale*((sin(theta)+1.0)))-brightness)*sign);
3755 if (brightness > 1.0) 3754 if (brightness > 1.0)
3756 brightness=1.0; 3755 brightness=1.0;
3757 else 3756 else
3758 if (brightness < 0) 3757 if (brightness < 0)
3759 brightness=0.0; 3758 brightness=0.0;
3760 v = (int)(brightness*255); 3759 v = (int)(brightness*255);
3761 c.setHsv(h, s, v); 3760 c.setHsv(h, s, v);
3762 data[i] = qRgba(c.red(), c.green(), c.blue(), qAlpha(data[i])); 3761 data[i] = qRgba(c.red(), c.green(), c.blue(), qAlpha(data[i]));
3763 } 3762 }
3764} 3763}
3765 3764
3766 3765
3767 3766
3768 3767