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