• Skip to content
  • Skip to link menu
Trinity API Reference
  • Trinity API Reference
  • tdefx
 

tdefx

  • tdefx
kimageeffect.cpp
1 /* This file is part of the KDE libraries
2  Copyright (C) 1998, 1999, 2001, 2002 Daniel M. Duley <mosfet@kde.org>
3  (C) 1998, 1999 Christian Tibirna <ctibirna@total.net>
4  (C) 1998, 1999 Dirk Mueller <mueller@kde.org>
5  (C) 1999 Geert Jansen <g.t.jansen@stud.tue.nl>
6  (C) 2000 Josef Weidendorfer <weidendo@in.tum.de>
7  (C) 2004 Zack Rusin <zack@kde.org>
8 
9 Redistribution and use in source and binary forms, with or without
10 modification, are permitted provided that the following conditions
11 are met:
12 
13 1. Redistributions of source code must retain the above copyright
14  notice, this list of conditions and the following disclaimer.
15 2. Redistributions in binary form must reproduce the above copyright
16  notice, this list of conditions and the following disclaimer in the
17  documentation and/or other materials provided with the distribution.
18 
19 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22 IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28 THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 
30 */
31 
32 // $Id$
33 
34 #include <math.h>
35 #include <assert.h>
36 
37 #include <tqimage.h>
38 #include <stdlib.h>
39 #include <iostream>
40 
41 #include "kimageeffect.h"
42 #include "kcpuinfo.h"
43 
44 #include <config.h>
45 
46 #if 0
47 //disabled until #74478 fixed.
48 
49 #if defined(__i386__) && ( defined(__GNUC__) || defined(__INTEL_COMPILER) )
50 # if defined( HAVE_X86_MMX )
51 # define USE_MMX_INLINE_ASM
52 # endif
53 # if defined( HAVE_X86_SSE2 )
54 # define USE_SSE2_INLINE_ASM
55 # endif
56 #endif
57 
58 #endif
59 //======================================================================
60 //
61 // Utility stuff for effects ported from ImageMagick to TQImage
62 //
63 //======================================================================
64 #define MaxRGB 255L
65 #define DegreesToRadians(x) ((x)*M_PI/180.0)
66 #define MagickSQ2PI 2.50662827463100024161235523934010416269302368164062
67 #define MagickEpsilon 1.0e-12
68 #define MagickPI 3.14159265358979323846264338327950288419716939937510
69 #define MOD(x, y) ((x) < 0 ? ((y) - 1 - ((y) - 1 - (x)) % (y)) : (x) % (y))
70 
76 #define FXCLAMP(x,low,high) fxClamp(x,low,high)
77 template<class T>
78 inline const T& fxClamp( const T& x, const T& low, const T& high )
79 {
80  if ( x < low ) return low;
81  else if ( x > high ) return high;
82  else return x;
83 }
84 
85 static inline unsigned int intensityValue(unsigned int color)
86 {
87  return((unsigned int)((0.299*tqRed(color) +
88  0.587*tqGreen(color) +
89  0.1140000000000001*tqBlue(color))));
90 }
91 
92 template<typename T>
93 static inline void liberateMemory(T **memory)
94 {
95  assert(memory != NULL);
96  if(*memory == NULL) return;
97  free((char*)*memory);
98  *memory=NULL;
99 }
100 
101 struct double_packet
102 {
103  double red;
104  double green;
105  double blue;
106  double alpha;
107 };
108 
109 struct short_packet
110 {
111  unsigned short int red;
112  unsigned short int green;
113  unsigned short int blue;
114  unsigned short int alpha;
115 };
116 
117 
118 //======================================================================
119 //
120 // Gradient effects
121 //
122 //======================================================================
123 
124 TQImage KImageEffect::gradient(const TQSize &size, const TQColor &ca,
125  const TQColor &cb, GradientType eff, int ncols)
126 {
127  int rDiff, gDiff, bDiff;
128  int rca, gca, bca, rcb, gcb, bcb;
129 
130  TQImage image(size, 32);
131 
132  if (size.width() == 0 || size.height() == 0) {
133 #ifndef NDEBUG
134  std::cerr << "WARNING: KImageEffect::gradient: invalid image" << std::endl;
135 #endif
136  return image;
137  }
138 
139  int x, y;
140 
141  rDiff = (rcb = cb.red()) - (rca = ca.red());
142  gDiff = (gcb = cb.green()) - (gca = ca.green());
143  bDiff = (bcb = cb.blue()) - (bca = ca.blue());
144 
145  if( eff == VerticalGradient || eff == HorizontalGradient ){
146 
147  uint *p;
148  uint rgb;
149 
150  int rl = rca << 16;
151  int gl = gca << 16;
152  int bl = bca << 16;
153 
154  if( eff == VerticalGradient ) {
155 
156  int rcdelta = ((1<<16) / size.height()) * rDiff;
157  int gcdelta = ((1<<16) / size.height()) * gDiff;
158  int bcdelta = ((1<<16) / size.height()) * bDiff;
159 
160  for ( y = 0; y < size.height(); y++ ) {
161  p = (uint *) image.scanLine(y);
162 
163  rl += rcdelta;
164  gl += gcdelta;
165  bl += bcdelta;
166 
167  rgb = tqRgb( (rl>>16), (gl>>16), (bl>>16) );
168 
169  for( x = 0; x < size.width(); x++ ) {
170  *p = rgb;
171  p++;
172  }
173  }
174 
175  }
176  else { // must be HorizontalGradient
177 
178  unsigned int *o_src = (unsigned int *)image.scanLine(0);
179  unsigned int *src = o_src;
180 
181  int rcdelta = ((1<<16) / size.width()) * rDiff;
182  int gcdelta = ((1<<16) / size.width()) * gDiff;
183  int bcdelta = ((1<<16) / size.width()) * bDiff;
184 
185  for( x = 0; x < size.width(); x++) {
186 
187  rl += rcdelta;
188  gl += gcdelta;
189  bl += bcdelta;
190 
191  *src++ = tqRgb( (rl>>16), (gl>>16), (bl>>16));
192  }
193 
194  src = o_src;
195 
196  // Believe it or not, manually copying in a for loop is faster
197  // than calling memcpy for each scanline (on the order of ms...).
198  // I think this is due to the function call overhead (mosfet).
199 
200  for (y = 1; y < size.height(); ++y) {
201 
202  p = (unsigned int *)image.scanLine(y);
203  src = o_src;
204  for(x=0; x < size.width(); ++x)
205  *p++ = *src++;
206  }
207  }
208  }
209 
210  else {
211 
212  float rfd, gfd, bfd;
213  float rd = rca, gd = gca, bd = bca;
214 
215  unsigned char *xtable[3];
216  unsigned char *ytable[3];
217 
218  unsigned int w = size.width(), h = size.height();
219  xtable[0] = new unsigned char[w];
220  xtable[1] = new unsigned char[w];
221  xtable[2] = new unsigned char[w];
222  ytable[0] = new unsigned char[h];
223  ytable[1] = new unsigned char[h];
224  ytable[2] = new unsigned char[h];
225  w*=2, h*=2;
226 
227  if ( eff == DiagonalGradient || eff == CrossDiagonalGradient) {
228  // Diagonal dgradient code inspired by BlackBox (mosfet)
229  // BlackBox dgradient is (C) Brad Hughes, <bhughes@tcac.net> and
230  // Mike Cole <mike@mydot.com>.
231 
232  rfd = (float)rDiff/w;
233  gfd = (float)gDiff/w;
234  bfd = (float)bDiff/w;
235 
236  int dir;
237  for (x = 0; x < size.width(); x++, rd+=rfd, gd+=gfd, bd+=bfd) {
238  dir = eff == DiagonalGradient? x : size.width() - x - 1;
239  xtable[0][dir] = (unsigned char) rd;
240  xtable[1][dir] = (unsigned char) gd;
241  xtable[2][dir] = (unsigned char) bd;
242  }
243  rfd = (float)rDiff/h;
244  gfd = (float)gDiff/h;
245  bfd = (float)bDiff/h;
246  rd = gd = bd = 0;
247  for (y = 0; y < size.height(); y++, rd+=rfd, gd+=gfd, bd+=bfd) {
248  ytable[0][y] = (unsigned char) rd;
249  ytable[1][y] = (unsigned char) gd;
250  ytable[2][y] = (unsigned char) bd;
251  }
252 
253  for (y = 0; y < size.height(); y++) {
254  unsigned int *scanline = (unsigned int *)image.scanLine(y);
255  for (x = 0; x < size.width(); x++) {
256  scanline[x] = tqRgb(xtable[0][x] + ytable[0][y],
257  xtable[1][x] + ytable[1][y],
258  xtable[2][x] + ytable[2][y]);
259  }
260  }
261  }
262 
263  else if (eff == RectangleGradient ||
264  eff == PyramidGradient ||
265  eff == PipeCrossGradient ||
266  eff == EllipticGradient)
267  {
268  int rSign = rDiff>0? 1: -1;
269  int gSign = gDiff>0? 1: -1;
270  int bSign = bDiff>0? 1: -1;
271 
272  rfd = (float)rDiff / size.width();
273  gfd = (float)gDiff / size.width();
274  bfd = (float)bDiff / size.width();
275 
276  rd = (float)rDiff/2;
277  gd = (float)gDiff/2;
278  bd = (float)bDiff/2;
279 
280  for (x = 0; x < size.width(); x++, rd-=rfd, gd-=gfd, bd-=bfd)
281  {
282  xtable[0][x] = (unsigned char) abs((int)rd);
283  xtable[1][x] = (unsigned char) abs((int)gd);
284  xtable[2][x] = (unsigned char) abs((int)bd);
285  }
286 
287  rfd = (float)rDiff/size.height();
288  gfd = (float)gDiff/size.height();
289  bfd = (float)bDiff/size.height();
290 
291  rd = (float)rDiff/2;
292  gd = (float)gDiff/2;
293  bd = (float)bDiff/2;
294 
295  for (y = 0; y < size.height(); y++, rd-=rfd, gd-=gfd, bd-=bfd)
296  {
297  ytable[0][y] = (unsigned char) abs((int)rd);
298  ytable[1][y] = (unsigned char) abs((int)gd);
299  ytable[2][y] = (unsigned char) abs((int)bd);
300  }
301 
302  int h = (size.height()+1)>>1;
303  for (y = 0; y < h; y++) {
304  unsigned int *sl1 = (unsigned int *)image.scanLine(y);
305  unsigned int *sl2 = (unsigned int *)image.scanLine(TQMAX(size.height()-y-1, y));
306 
307  int w = (size.width()+1)>>1;
308  int x2 = size.width()-1;
309 
310  for (x = 0; x < w; x++, x2--) {
311  unsigned int rgb = 0;
312  if (eff == PyramidGradient) {
313  rgb = tqRgb(rcb-rSign*(xtable[0][x]+ytable[0][y]),
314  gcb-gSign*(xtable[1][x]+ytable[1][y]),
315  bcb-bSign*(xtable[2][x]+ytable[2][y]));
316  }
317  if (eff == RectangleGradient) {
318  rgb = tqRgb(rcb - rSign *
319  TQMAX(xtable[0][x], ytable[0][y]) * 2,
320  gcb - gSign *
321  TQMAX(xtable[1][x], ytable[1][y]) * 2,
322  bcb - bSign *
323  TQMAX(xtable[2][x], ytable[2][y]) * 2);
324  }
325  if (eff == PipeCrossGradient) {
326  rgb = tqRgb(rcb - rSign *
327  TQMIN(xtable[0][x], ytable[0][y]) * 2,
328  gcb - gSign *
329  TQMIN(xtable[1][x], ytable[1][y]) * 2,
330  bcb - bSign *
331  TQMIN(xtable[2][x], ytable[2][y]) * 2);
332  }
333  if (eff == EllipticGradient) {
334  rgb = tqRgb(rcb - rSign *
335  (int)sqrt((xtable[0][x]*xtable[0][x] +
336  ytable[0][y]*ytable[0][y])*2.0),
337  gcb - gSign *
338  (int)sqrt((xtable[1][x]*xtable[1][x] +
339  ytable[1][y]*ytable[1][y])*2.0),
340  bcb - bSign *
341  (int)sqrt((xtable[2][x]*xtable[2][x] +
342  ytable[2][y]*ytable[2][y])*2.0));
343  }
344 
345  sl1[x] = sl2[x] = rgb;
346  sl1[x2] = sl2[x2] = rgb;
347  }
348  }
349  }
350 
351  delete [] xtable[0];
352  delete [] xtable[1];
353  delete [] xtable[2];
354  delete [] ytable[0];
355  delete [] ytable[1];
356  delete [] ytable[2];
357  }
358 
359  // dither if necessary
360  if (ncols && (TQPixmap::defaultDepth() < 15 )) {
361  if ( ncols < 2 || ncols > 256 )
362  ncols = 3;
363  TQColor *dPal = new TQColor[ncols];
364  for (int i=0; i<ncols; i++) {
365  dPal[i].setRgb ( rca + rDiff * i / ( ncols - 1 ),
366  gca + gDiff * i / ( ncols - 1 ),
367  bca + bDiff * i / ( ncols - 1 ) );
368  }
369  dither(image, dPal, ncols);
370  delete [] dPal;
371  }
372 
373  return image;
374 }
375 
376 
377 // -----------------------------------------------------------------------------
378 
379 //CT this was (before Dirk A. Mueller's speedup changes)
380 // merely the same code as in the above method, but it's supposedly
381 // way less performant since it introduces a lot of supplementary tests
382 // and simple math operations for the calculus of the balance.
383 // (surprizingly, it isn't less performant, in the contrary :-)
384 // Yes, I could have merged them, but then the excellent performance of
385 // the balanced code would suffer with no other gain than a mere
386 // source code and byte code size economy.
387 
388 TQImage KImageEffect::unbalancedGradient(const TQSize &size, const TQColor &ca,
389  const TQColor &cb, GradientType eff, int xfactor, int yfactor,
390  int ncols)
391 {
392  int dir; // general parameter used for direction switches
393 
394  bool _xanti = false , _yanti = false;
395 
396  if (xfactor < 0) _xanti = true; // negative on X direction
397  if (yfactor < 0) _yanti = true; // negative on Y direction
398 
399  xfactor = abs(xfactor);
400  yfactor = abs(yfactor);
401 
402  if (!xfactor) xfactor = 1;
403  if (!yfactor) yfactor = 1;
404 
405  if (xfactor > 200 ) xfactor = 200;
406  if (yfactor > 200 ) yfactor = 200;
407 
408 
409  // float xbal = xfactor/5000.;
410  // float ybal = yfactor/5000.;
411  float xbal = xfactor/30./size.width();
412  float ybal = yfactor/30./size.height();
413  float rat;
414 
415  int rDiff, gDiff, bDiff;
416  int rca, gca, bca, rcb, gcb, bcb;
417 
418  TQImage image(size, 32);
419 
420  if (size.width() == 0 || size.height() == 0) {
421 #ifndef NDEBUG
422  std::cerr << "WARNING: KImageEffect::unbalancedGradient : invalid image\n";
423 #endif
424  return image;
425  }
426 
427  int x, y;
428  unsigned int *scanline;
429 
430  rDiff = (rcb = cb.red()) - (rca = ca.red());
431  gDiff = (gcb = cb.green()) - (gca = ca.green());
432  bDiff = (bcb = cb.blue()) - (bca = ca.blue());
433 
434  if( eff == VerticalGradient || eff == HorizontalGradient){
435  TQColor cRow;
436 
437  uint *p;
438  uint rgbRow;
439 
440  if( eff == VerticalGradient) {
441  for ( y = 0; y < size.height(); y++ ) {
442  dir = _yanti ? y : size.height() - 1 - y;
443  p = (uint *) image.scanLine(dir);
444  rat = 1 - exp( - (float)y * ybal );
445 
446  cRow.setRgb( rcb - (int) ( rDiff * rat ),
447  gcb - (int) ( gDiff * rat ),
448  bcb - (int) ( bDiff * rat ) );
449 
450  rgbRow = cRow.rgb();
451 
452  for( x = 0; x < size.width(); x++ ) {
453  *p = rgbRow;
454  p++;
455  }
456  }
457  }
458  else {
459 
460  unsigned int *src = (unsigned int *)image.scanLine(0);
461  for(x = 0; x < size.width(); x++ )
462  {
463  dir = _xanti ? x : size.width() - 1 - x;
464  rat = 1 - exp( - (float)x * xbal );
465 
466  src[dir] = tqRgb(rcb - (int) ( rDiff * rat ),
467  gcb - (int) ( gDiff * rat ),
468  bcb - (int) ( bDiff * rat ));
469  }
470 
471  // Believe it or not, manually copying in a for loop is faster
472  // than calling memcpy for each scanline (on the order of ms...).
473  // I think this is due to the function call overhead (mosfet).
474 
475  for(y = 1; y < size.height(); ++y)
476  {
477  scanline = (unsigned int *)image.scanLine(y);
478  for(x=0; x < size.width(); ++x)
479  scanline[x] = src[x];
480  }
481  }
482  }
483 
484  else {
485  int w=size.width(), h=size.height();
486 
487  unsigned char *xtable[3];
488  unsigned char *ytable[3];
489  xtable[0] = new unsigned char[w];
490  xtable[1] = new unsigned char[w];
491  xtable[2] = new unsigned char[w];
492  ytable[0] = new unsigned char[h];
493  ytable[1] = new unsigned char[h];
494  ytable[2] = new unsigned char[h];
495 
496  if ( eff == DiagonalGradient || eff == CrossDiagonalGradient)
497  {
498  for (x = 0; x < w; x++) {
499  dir = _xanti ? x : w - 1 - x;
500  rat = 1 - exp( - (float)x * xbal );
501 
502  xtable[0][dir] = (unsigned char) ( rDiff/2 * rat );
503  xtable[1][dir] = (unsigned char) ( gDiff/2 * rat );
504  xtable[2][dir] = (unsigned char) ( bDiff/2 * rat );
505  }
506 
507  for (y = 0; y < h; y++) {
508  dir = _yanti ? y : h - 1 - y;
509  rat = 1 - exp( - (float)y * ybal );
510 
511  ytable[0][dir] = (unsigned char) ( rDiff/2 * rat );
512  ytable[1][dir] = (unsigned char) ( gDiff/2 * rat );
513  ytable[2][dir] = (unsigned char) ( bDiff/2 * rat );
514  }
515 
516  for (y = 0; y < h; y++) {
517  unsigned int *scanline = (unsigned int *)image.scanLine(y);
518  for (x = 0; x < w; x++) {
519  scanline[x] = tqRgb(rcb - (xtable[0][x] + ytable[0][y]),
520  gcb - (xtable[1][x] + ytable[1][y]),
521  bcb - (xtable[2][x] + ytable[2][y]));
522  }
523  }
524  }
525 
526  else if (eff == RectangleGradient ||
527  eff == PyramidGradient ||
528  eff == PipeCrossGradient ||
529  eff == EllipticGradient)
530  {
531  int rSign = rDiff>0? 1: -1;
532  int gSign = gDiff>0? 1: -1;
533  int bSign = bDiff>0? 1: -1;
534 
535  for (x = 0; x < w; x++)
536  {
537  dir = _xanti ? x : w - 1 - x;
538  rat = 1 - exp( - (float)x * xbal );
539 
540  xtable[0][dir] = (unsigned char) abs((int)(rDiff*(0.5-rat)));
541  xtable[1][dir] = (unsigned char) abs((int)(gDiff*(0.5-rat)));
542  xtable[2][dir] = (unsigned char) abs((int)(bDiff*(0.5-rat)));
543  }
544 
545  for (y = 0; y < h; y++)
546  {
547  dir = _yanti ? y : h - 1 - y;
548 
549  rat = 1 - exp( - (float)y * ybal );
550 
551  ytable[0][dir] = (unsigned char) abs((int)(rDiff*(0.5-rat)));
552  ytable[1][dir] = (unsigned char) abs((int)(gDiff*(0.5-rat)));
553  ytable[2][dir] = (unsigned char) abs((int)(bDiff*(0.5-rat)));
554  }
555 
556  for (y = 0; y < h; y++) {
557  unsigned int *scanline = (unsigned int *)image.scanLine(y);
558  for (x = 0; x < w; x++) {
559  if (eff == PyramidGradient)
560  {
561  scanline[x] = tqRgb(rcb-rSign*(xtable[0][x]+ytable[0][y]),
562  gcb-gSign*(xtable[1][x]+ytable[1][y]),
563  bcb-bSign*(xtable[2][x]+ytable[2][y]));
564  }
565  else if (eff == RectangleGradient)
566  {
567  scanline[x] = tqRgb(rcb - rSign *
568  TQMAX(xtable[0][x], ytable[0][y]) * 2,
569  gcb - gSign *
570  TQMAX(xtable[1][x], ytable[1][y]) * 2,
571  bcb - bSign *
572  TQMAX(xtable[2][x], ytable[2][y]) * 2);
573  }
574  else if (eff == PipeCrossGradient)
575  {
576  scanline[x] = tqRgb(rcb - rSign *
577  TQMIN(xtable[0][x], ytable[0][y]) * 2,
578  gcb - gSign *
579  TQMIN(xtable[1][x], ytable[1][y]) * 2,
580  bcb - bSign *
581  TQMIN(xtable[2][x], ytable[2][y]) * 2);
582  }
583  else if (eff == EllipticGradient)
584  {
585  scanline[x] = tqRgb(rcb - rSign *
586  (int)sqrt((xtable[0][x]*xtable[0][x] +
587  ytable[0][y]*ytable[0][y])*2.0),
588  gcb - gSign *
589  (int)sqrt((xtable[1][x]*xtable[1][x] +
590  ytable[1][y]*ytable[1][y])*2.0),
591  bcb - bSign *
592  (int)sqrt((xtable[2][x]*xtable[2][x] +
593  ytable[2][y]*ytable[2][y])*2.0));
594  }
595  }
596  }
597  }
598 
599  if (ncols && (TQPixmap::defaultDepth() < 15 )) {
600  if ( ncols < 2 || ncols > 256 )
601  ncols = 3;
602  TQColor *dPal = new TQColor[ncols];
603  for (int i=0; i<ncols; i++) {
604  dPal[i].setRgb ( rca + rDiff * i / ( ncols - 1 ),
605  gca + gDiff * i / ( ncols - 1 ),
606  bca + bDiff * i / ( ncols - 1 ) );
607  }
608  dither(image, dPal, ncols);
609  delete [] dPal;
610  }
611 
612  delete [] xtable[0];
613  delete [] xtable[1];
614  delete [] xtable[2];
615  delete [] ytable[0];
616  delete [] ytable[1];
617  delete [] ytable[2];
618 
619  }
620 
621  return image;
622 }
623 
627 namespace {
628 
629 struct KIE4Pack
630 {
631  TQ_UINT16 data[4];
632 };
633 
634 struct KIE8Pack
635 {
636  TQ_UINT16 data[8];
637 };
638 
639 }
640 
641 //======================================================================
642 //
643 // Intensity effects
644 //
645 //======================================================================
646 
647 
648 /* This builds a 256 byte unsigned char lookup table with all
649  * the possible percent values prior to applying the effect, then uses
650  * integer math for the pixels. For any image larger than 9x9 this will be
651  * less expensive than doing a float operation on the 3 color components of
652  * each pixel. (mosfet)
653  */
654 TQImage& KImageEffect::intensity(TQImage &image, float percent)
655 {
656  if (image.width() == 0 || image.height() == 0) {
657 #ifndef NDEBUG
658  std::cerr << "WARNING: KImageEffect::intensity : invalid image\n";
659 #endif
660  return image;
661  }
662 
663  int segColors = image.depth() > 8 ? 256 : image.numColors();
664  int pixels = image.depth() > 8 ? image.width()*image.height() :
665  image.numColors();
666  unsigned int *data = image.depth() > 8 ? (unsigned int *)image.bits() :
667  (unsigned int *)image.colorTable();
668 
669  bool brighten = (percent >= 0);
670  if(percent < 0)
671  percent = -percent;
672 
673 #ifdef USE_MMX_INLINE_ASM
674  bool haveMMX = KCPUInfo::haveExtension( KCPUInfo::IntelMMX );
675 
676  if(haveMMX)
677  {
678  TQ_UINT16 p = TQ_UINT16(256.0f*(percent));
679  KIE4Pack mult = {{p,p,p,0}};
680 
681  __asm__ __volatile__(
682  "pxor %%mm7, %%mm7\n\t" // zero mm7 for unpacking
683  "movq (%0), %%mm6\n\t" // copy intensity change to mm6
684  : : "r"(&mult), "m"(mult));
685 
686  unsigned int rem = pixels % 4;
687  pixels -= rem;
688  TQ_UINT32 *end = ( data + pixels );
689 
690  if (brighten)
691  {
692  while ( data != end ) {
693  __asm__ __volatile__(
694  "movq (%0), %%mm0\n\t"
695  "movq 8(%0), %%mm4\n\t" // copy 4 pixels of data to mm0 and mm4
696  "movq %%mm0, %%mm1\n\t"
697  "movq %%mm0, %%mm3\n\t"
698  "movq %%mm4, %%mm5\n\t" // copy to registers for unpacking
699  "punpcklbw %%mm7, %%mm0\n\t"
700  "punpckhbw %%mm7, %%mm1\n\t" // unpack the two pixels from mm0
701  "pmullw %%mm6, %%mm0\n\t"
702  "punpcklbw %%mm7, %%mm4\n\t"
703  "pmullw %%mm6, %%mm1\n\t" // multiply by intensity*256
704  "psrlw $8, %%mm0\n\t" // divide by 256
705  "pmullw %%mm6, %%mm4\n\t"
706  "psrlw $8, %%mm1\n\t"
707  "psrlw $8, %%mm4\n\t"
708  "packuswb %%mm1, %%mm0\n\t" // pack solution into mm0. saturates at 255
709  "movq %%mm5, %%mm1\n\t"
710 
711  "punpckhbw %%mm7, %%mm1\n\t" // unpack 4th pixel in mm1
712 
713  "pmullw %%mm6, %%mm1\n\t"
714  "paddusb %%mm3, %%mm0\n\t" // add intesity result to original of mm0
715  "psrlw $8, %%mm1\n\t"
716  "packuswb %%mm1, %%mm4\n\t" // pack upper two pixels into mm4
717 
718  "movq %%mm0, (%0)\n\t" // rewrite to memory lower two pixels
719  "paddusb %%mm5, %%mm4\n\t"
720  "movq %%mm4, 8(%0)\n\t" // rewrite upper two pixels
721  : : "r"(data) );
722  data += 4;
723  }
724 
725  end += rem;
726  while ( data != end ) {
727  __asm__ __volatile__(
728  "movd (%0), %%mm0\n\t" // repeat above but for
729  "punpcklbw %%mm7, %%mm0\n\t" // one pixel at a time
730  "movq %%mm0, %%mm3\n\t"
731  "pmullw %%mm6, %%mm0\n\t"
732  "psrlw $8, %%mm0\n\t"
733  "paddw %%mm3, %%mm0\n\t"
734  "packuswb %%mm0, %%mm0\n\t"
735  "movd %%mm0, (%0)\n\t"
736  : : "r"(data) );
737  data++;
738  }
739  }
740  else
741  {
742  while ( data != end ) {
743  __asm__ __volatile__(
744  "movq (%0), %%mm0\n\t"
745  "movq 8(%0), %%mm4\n\t"
746  "movq %%mm0, %%mm1\n\t"
747  "movq %%mm0, %%mm3\n\t"
748 
749  "movq %%mm4, %%mm5\n\t"
750 
751  "punpcklbw %%mm7, %%mm0\n\t"
752  "punpckhbw %%mm7, %%mm1\n\t"
753  "pmullw %%mm6, %%mm0\n\t"
754  "punpcklbw %%mm7, %%mm4\n\t"
755  "pmullw %%mm6, %%mm1\n\t"
756  "psrlw $8, %%mm0\n\t"
757  "pmullw %%mm6, %%mm4\n\t"
758  "psrlw $8, %%mm1\n\t"
759  "psrlw $8, %%mm4\n\t"
760  "packuswb %%mm1, %%mm0\n\t"
761  "movq %%mm5, %%mm1\n\t"
762 
763  "punpckhbw %%mm7, %%mm1\n\t"
764 
765  "pmullw %%mm6, %%mm1\n\t"
766  "psubusb %%mm0, %%mm3\n\t" // subtract darkening amount
767  "psrlw $8, %%mm1\n\t"
768  "packuswb %%mm1, %%mm4\n\t"
769 
770  "movq %%mm3, (%0)\n\t"
771  "psubusb %%mm4, %%mm5\n\t" // only change for this version is
772  "movq %%mm5, 8(%0)\n\t" // subtraction here as we are darkening image
773  : : "r"(data) );
774  data += 4;
775  }
776 
777  end += rem;
778  while ( data != end ) {
779  __asm__ __volatile__(
780  "movd (%0), %%mm0\n\t"
781  "punpcklbw %%mm7, %%mm0\n\t"
782  "movq %%mm0, %%mm3\n\t"
783  "pmullw %%mm6, %%mm0\n\t"
784  "psrlw $8, %%mm0\n\t"
785  "psubusw %%mm0, %%mm3\n\t"
786  "packuswb %%mm3, %%mm3\n\t"
787  "movd %%mm3, (%0)\n\t"
788  : : "r"(data) );
789  data++;
790  }
791  }
792  __asm__ __volatile__("emms"); // clear mmx state
793  }
794  else
795 #endif // USE_MMX_INLINE_ASM
796  {
797  unsigned char *segTbl = new unsigned char[segColors];
798  int tmp;
799  if(brighten){ // keep overflow check out of loops
800  for(int i=0; i < segColors; ++i){
801  tmp = (int)(i*percent);
802  if(tmp > 255)
803  tmp = 255;
804  segTbl[i] = tmp;
805  }
806  }
807  else{
808  for(int i=0; i < segColors; ++i){
809  tmp = (int)(i*percent);
810  if(tmp < 0)
811  tmp = 0;
812  segTbl[i] = tmp;
813  }
814  }
815 
816  if(brighten){ // same here
817  for(int i=0; i < pixels; ++i){
818  int r = tqRed(data[i]);
819  int g = tqGreen(data[i]);
820  int b = tqBlue(data[i]);
821  int a = tqAlpha(data[i]);
822  r = r + segTbl[r] > 255 ? 255 : r + segTbl[r];
823  g = g + segTbl[g] > 255 ? 255 : g + segTbl[g];
824  b = b + segTbl[b] > 255 ? 255 : b + segTbl[b];
825  data[i] = tqRgba(r, g, b,a);
826  }
827  }
828  else{
829  for(int i=0; i < pixels; ++i){
830  int r = tqRed(data[i]);
831  int g = tqGreen(data[i]);
832  int b = tqBlue(data[i]);
833  int a = tqAlpha(data[i]);
834  r = r - segTbl[r] < 0 ? 0 : r - segTbl[r];
835  g = g - segTbl[g] < 0 ? 0 : g - segTbl[g];
836  b = b - segTbl[b] < 0 ? 0 : b - segTbl[b];
837  data[i] = tqRgba(r, g, b, a);
838  }
839  }
840  delete [] segTbl;
841  }
842 
843  return image;
844 }
845 
846 TQImage& KImageEffect::channelIntensity(TQImage &image, float percent,
847  RGBComponent channel)
848 {
849  if (image.width() == 0 || image.height() == 0) {
850 #ifndef NDEBUG
851  std::cerr << "WARNING: KImageEffect::channelIntensity : invalid image\n";
852 #endif
853  return image;
854  }
855 
856  int segColors = image.depth() > 8 ? 256 : image.numColors();
857  unsigned char *segTbl = new unsigned char[segColors];
858  int pixels = image.depth() > 8 ? image.width()*image.height() :
859  image.numColors();
860  unsigned int *data = image.depth() > 8 ? (unsigned int *)image.bits() :
861  (unsigned int *)image.colorTable();
862  bool brighten = (percent >= 0);
863  if(percent < 0)
864  percent = -percent;
865 
866  if(brighten){ // keep overflow check out of loops
867  for(int i=0; i < segColors; ++i){
868  int tmp = (int)(i*percent);
869  if(tmp > 255)
870  tmp = 255;
871  segTbl[i] = tmp;
872  }
873  }
874  else{
875  for(int i=0; i < segColors; ++i){
876  int tmp = (int)(i*percent);
877  if(tmp < 0)
878  tmp = 0;
879  segTbl[i] = tmp;
880  }
881  }
882 
883  if(brighten){ // same here
884  if(channel == Red){ // and here ;-)
885  for(int i=0; i < pixels; ++i){
886  int c = tqRed(data[i]);
887  c = c + segTbl[c] > 255 ? 255 : c + segTbl[c];
888  data[i] = tqRgba(c, tqGreen(data[i]), tqBlue(data[i]), tqAlpha(data[i]));
889  }
890  }
891  else if(channel == Green){
892  for(int i=0; i < pixels; ++i){
893  int c = tqGreen(data[i]);
894  c = c + segTbl[c] > 255 ? 255 : c + segTbl[c];
895  data[i] = tqRgba(tqRed(data[i]), c, tqBlue(data[i]), tqAlpha(data[i]));
896  }
897  }
898  else{
899  for(int i=0; i < pixels; ++i){
900  int c = tqBlue(data[i]);
901  c = c + segTbl[c] > 255 ? 255 : c + segTbl[c];
902  data[i] = tqRgba(tqRed(data[i]), tqGreen(data[i]), c, tqAlpha(data[i]));
903  }
904  }
905 
906  }
907  else{
908  if(channel == Red){
909  for(int i=0; i < pixels; ++i){
910  int c = tqRed(data[i]);
911  c = c - segTbl[c] < 0 ? 0 : c - segTbl[c];
912  data[i] = tqRgba(c, tqGreen(data[i]), tqBlue(data[i]), tqAlpha(data[i]));
913  }
914  }
915  else if(channel == Green){
916  for(int i=0; i < pixels; ++i){
917  int c = tqGreen(data[i]);
918  c = c - segTbl[c] < 0 ? 0 : c - segTbl[c];
919  data[i] = tqRgba(tqRed(data[i]), c, tqBlue(data[i]), tqAlpha(data[i]));
920  }
921  }
922  else{
923  for(int i=0; i < pixels; ++i){
924  int c = tqBlue(data[i]);
925  c = c - segTbl[c] < 0 ? 0 : c - segTbl[c];
926  data[i] = tqRgba(tqRed(data[i]), tqGreen(data[i]), c, tqAlpha(data[i]));
927  }
928  }
929  }
930  delete [] segTbl;
931 
932  return image;
933 }
934 
935 // Modulate an image with an RBG channel of another image
936 //
937 TQImage& KImageEffect::modulate(TQImage &image, TQImage &modImage, bool reverse,
938  ModulationType type, int factor, RGBComponent channel)
939 {
940  if (image.width() == 0 || image.height() == 0 ||
941  modImage.width() == 0 || modImage.height() == 0) {
942 #ifndef NDEBUG
943  std::cerr << "WARNING: KImageEffect::modulate : invalid image\n";
944 #endif
945  return image;
946  }
947 
948  int r, g, b, h, s, v, a;
949  TQColor clr;
950  int mod=0;
951  unsigned int x1, x2, y1, y2;
952  int x, y;
953 
954  // for image, we handle only depth 32
955  if (image.depth()<32) image = image.convertDepth(32);
956 
957  // for modImage, we handle depth 8 and 32
958  if (modImage.depth()<8) modImage = modImage.convertDepth(8);
959 
960  unsigned int *colorTable2 = (modImage.depth()==8) ?
961  modImage.colorTable():0;
962  unsigned int *data1, *data2;
963  unsigned char *data2b;
964  unsigned int color1, color2;
965 
966  x1 = image.width(); y1 = image.height();
967  x2 = modImage.width(); y2 = modImage.height();
968 
969  for (y = 0; y < (int)y1; y++) {
970  data1 = (unsigned int *) image.scanLine(y);
971  data2 = (unsigned int *) modImage.scanLine( y%y2 );
972  data2b = (unsigned char *) modImage.scanLine( y%y2 );
973 
974  x=0;
975  while(x < (int)x1) {
976  color2 = (colorTable2) ? colorTable2[*data2b] : *data2;
977  if (reverse) {
978  color1 = color2;
979  color2 = *data1;
980  }
981  else
982  color1 = *data1;
983 
984  if (type == Intensity || type == Contrast) {
985  r = tqRed(color1);
986  g = tqGreen(color1);
987  b = tqBlue(color1);
988  if (channel != All) {
989  mod = (channel == Red) ? tqRed(color2) :
990  (channel == Green) ? tqGreen(color2) :
991  (channel == Blue) ? tqBlue(color2) :
992  (channel == Gray) ? tqGray(color2) : 0;
993  mod = mod*factor/50;
994  }
995 
996  if (type == Intensity) {
997  if (channel == All) {
998  r += r * factor/50 * tqRed(color2)/256;
999  g += g * factor/50 * tqGreen(color2)/256;
1000  b += b * factor/50 * tqBlue(color2)/256;
1001  }
1002  else {
1003  r += r * mod/256;
1004  g += g * mod/256;
1005  b += b * mod/256;
1006  }
1007  }
1008  else { // Contrast
1009  if (channel == All) {
1010  r += (r-128) * factor/50 * tqRed(color2)/128;
1011  g += (g-128) * factor/50 * tqGreen(color2)/128;
1012  b += (b-128) * factor/50 * tqBlue(color2)/128;
1013  }
1014  else {
1015  r += (r-128) * mod/128;
1016  g += (g-128) * mod/128;
1017  b += (b-128) * mod/128;
1018  }
1019  }
1020 
1021  if (r<0) r=0; if (r>255) r=255;
1022  if (g<0) g=0; if (g>255) g=255;
1023  if (b<0) b=0; if (b>255) b=255;
1024  a = tqAlpha(*data1);
1025  *data1 = tqRgba(r, g, b, a);
1026  }
1027  else if (type == Saturation || type == HueShift) {
1028  clr.setRgb(color1);
1029  clr.hsv(&h, &s, &v);
1030  mod = (channel == Red) ? tqRed(color2) :
1031  (channel == Green) ? tqGreen(color2) :
1032  (channel == Blue) ? tqBlue(color2) :
1033  (channel == Gray) ? tqGray(color2) : 0;
1034  mod = mod*factor/50;
1035 
1036  if (type == Saturation) {
1037  s -= s * mod/256;
1038  if (s<0) s=0; if (s>255) s=255;
1039  }
1040  else { // HueShift
1041  h += mod;
1042  while(h<0) h+=360;
1043  h %= 360;
1044  }
1045 
1046  clr.setHsv(h, s, v);
1047  a = tqAlpha(*data1);
1048  *data1 = clr.rgb() | ((uint)(a & 0xff) << 24);
1049  }
1050  data1++; data2++; data2b++; x++;
1051  if ( (x%x2) ==0) { data2 -= x2; data2b -= x2; }
1052  }
1053  }
1054  return image;
1055 }
1056 
1057 
1058 
1059 //======================================================================
1060 //
1061 // Blend effects
1062 //
1063 //======================================================================
1064 
1065 
1066 // Nice and fast direct pixel manipulation
1067 TQImage& KImageEffect::blend(const TQColor& clr, TQImage& dst, float opacity)
1068 {
1069  if (dst.width() <= 0 || dst.height() <= 0)
1070  return dst;
1071 
1072  if (opacity < 0.0 || opacity > 1.0) {
1073 #ifndef NDEBUG
1074  std::cerr << "WARNING: KImageEffect::blend : invalid opacity. Range [0, 1]\n";
1075 #endif
1076  return dst;
1077  }
1078 
1079  if (dst.depth() != 32)
1080  dst = dst.convertDepth(32);
1081 
1082  int pixels = dst.width() * dst.height();
1083 
1084 #ifdef USE_SSE2_INLINE_ASM
1085  if ( KCPUInfo::haveExtension( KCPUInfo::IntelSSE2 ) && pixels > 16 ) {
1086  TQ_UINT16 alpha = TQ_UINT16( ( 1.0 - opacity ) * 256.0 );
1087 
1088  KIE8Pack packedalpha = { { alpha, alpha, alpha, 256,
1089  alpha, alpha, alpha, 256 } };
1090 
1091  TQ_UINT16 red = TQ_UINT16( clr.red() * 256 * opacity );
1092  TQ_UINT16 green = TQ_UINT16( clr.green() * 256 * opacity );
1093  TQ_UINT16 blue = TQ_UINT16( clr.blue() * 256 * opacity );
1094 
1095  KIE8Pack packedcolor = { { blue, green, red, 0,
1096  blue, green, red, 0 } };
1097 
1098  // Prepare the XMM5, XMM6 and XMM7 registers for unpacking and blending
1099  __asm__ __volatile__(
1100  "pxor %%xmm7, %%xmm7\n\t" // Zero out XMM7 for unpacking
1101  "movdqu (%0), %%xmm6\n\t" // Set up (1 - alpha) * 256 in XMM6
1102  "movdqu (%1), %%xmm5\n\t" // Set up color * alpha * 256 in XMM5
1103  : : "r"(&packedalpha), "r"(&packedcolor),
1104  "m"(packedcolor), "m"(packedalpha) );
1105 
1106  TQ_UINT32 *data = reinterpret_cast<TQ_UINT32*>( dst.bits() );
1107 
1108  // Check how many pixels we need to process to achieve 16 byte alignment
1109  int offset = (16 - (TQ_UINT32( data ) & 0x0f)) / 4;
1110 
1111  // The main loop processes 8 pixels / iteration
1112  int remainder = (pixels - offset) % 8;
1113  pixels -= remainder;
1114 
1115  // Alignment loop
1116  for ( int i = 0; i < offset; i++ ) {
1117  __asm__ __volatile__(
1118  "movd (%0,%1,4), %%xmm0\n\t" // Load one pixel to XMM1
1119  "punpcklbw %%xmm7, %%xmm0\n\t" // Unpack the pixel
1120  "pmullw %%xmm6, %%xmm0\n\t" // Multiply the pixel with (1 - alpha) * 256
1121  "paddw %%xmm5, %%xmm0\n\t" // Add color * alpha * 256 to the result
1122  "psrlw $8, %%xmm0\n\t" // Divide by 256
1123  "packuswb %%xmm1, %%xmm0\n\t" // Pack the pixel to a dword
1124  "movd %%xmm0, (%0,%1,4)\n\t" // Write the pixel to the image
1125  : : "r"(data), "r"(i) );
1126  }
1127 
1128  // Main loop
1129  for ( int i = offset; i < pixels; i += 8 ) {
1130  __asm__ __volatile(
1131  // Load 8 pixels to XMM registers 1 - 4
1132  "movq (%0,%1,4), %%xmm0\n\t" // Load pixels 1 and 2 to XMM1
1133  "movq 8(%0,%1,4), %%xmm1\n\t" // Load pixels 3 and 4 to XMM2
1134  "movq 16(%0,%1,4), %%xmm2\n\t" // Load pixels 5 and 6 to XMM3
1135  "movq 24(%0,%1,4), %%xmm3\n\t" // Load pixels 7 and 8 to XMM4
1136 
1137  // Prefetch the pixels for next iteration
1138  "prefetchnta 32(%0,%1,4) \n\t"
1139 
1140  // Blend pixels 1 and 2
1141  "punpcklbw %%xmm7, %%xmm0\n\t" // Unpack the pixels
1142  "pmullw %%xmm6, %%xmm0\n\t" // Multiply the pixels with (1 - alpha) * 256
1143  "paddw %%xmm5, %%xmm0\n\t" // Add color * alpha * 256 to the result
1144  "psrlw $8, %%xmm0\n\t" // Divide by 256
1145 
1146  // Blend pixels 3 and 4
1147  "punpcklbw %%xmm7, %%xmm1\n\t" // Unpack the pixels
1148  "pmullw %%xmm6, %%xmm1\n\t" // Multiply the pixels with (1 - alpha) * 256
1149  "paddw %%xmm5, %%xmm1\n\t" // Add color * alpha * 256 to the result
1150  "psrlw $8, %%xmm1\n\t" // Divide by 256
1151 
1152  // Blend pixels 5 and 6
1153  "punpcklbw %%xmm7, %%xmm2\n\t" // Unpack the pixels
1154  "pmullw %%xmm6, %%xmm2\n\t" // Multiply the pixels with (1 - alpha) * 256
1155  "paddw %%xmm5, %%xmm2\n\t" // Add color * alpha * 256 to the result
1156  "psrlw $8, %%xmm2\n\t" // Divide by 256
1157 
1158  // Blend pixels 7 and 8
1159  "punpcklbw %%xmm7, %%xmm3\n\t" // Unpack the pixels
1160  "pmullw %%xmm6, %%xmm3\n\t" // Multiply the pixels with (1 - alpha) * 256
1161  "paddw %%xmm5, %%xmm3\n\t" // Add color * alpha * 256 to the result
1162  "psrlw $8, %%xmm3\n\t" // Divide by 256
1163 
1164  // Pack the pixels into 2 double quadwords
1165  "packuswb %%xmm1, %%xmm0\n\t" // Pack pixels 1 - 4 to a double qword
1166  "packuswb %%xmm3, %%xmm2\n\t" // Pack pixles 5 - 8 to a double qword
1167 
1168  // Write the pixels back to the image
1169  "movdqa %%xmm0, (%0,%1,4)\n\t" // Store pixels 1 - 4
1170  "movdqa %%xmm2, 16(%0,%1,4)\n\t" // Store pixels 5 - 8
1171  : : "r"(data), "r"(i) );
1172  }
1173 
1174  // Cleanup loop
1175  for ( int i = pixels; i < pixels + remainder; i++ ) {
1176  __asm__ __volatile__(
1177  "movd (%0,%1,4), %%xmm0\n\t" // Load one pixel to XMM1
1178  "punpcklbw %%xmm7, %%xmm0\n\t" // Unpack the pixel
1179  "pmullw %%xmm6, %%xmm0\n\t" // Multiply the pixel with (1 - alpha) * 256
1180  "paddw %%xmm5, %%xmm0\n\t" // Add color * alpha * 256 to the result
1181  "psrlw $8, %%xmm0\n\t" // Divide by 256
1182  "packuswb %%xmm1, %%xmm0\n\t" // Pack the pixel to a dword
1183  "movd %%xmm0, (%0,%1,4)\n\t" // Write the pixel to the image
1184  : : "r"(data), "r"(i) );
1185  }
1186  } else
1187 #endif
1188 
1189 #ifdef USE_MMX_INLINE_ASM
1190  if ( KCPUInfo::haveExtension( KCPUInfo::IntelMMX ) && pixels > 1 ) {
1191  TQ_UINT16 alpha = TQ_UINT16( ( 1.0 - opacity ) * 256.0 );
1192  KIE4Pack packedalpha = { { alpha, alpha, alpha, 256 } };
1193 
1194  TQ_UINT16 red = TQ_UINT16( clr.red() * 256 * opacity );
1195  TQ_UINT16 green = TQ_UINT16( clr.green() * 256 * opacity );
1196  TQ_UINT16 blue = TQ_UINT16( clr.blue() * 256 * opacity );
1197 
1198  KIE4Pack packedcolor = { { blue, green, red, 0 } };
1199 
1200  __asm__ __volatile__(
1201  "pxor %%mm7, %%mm7\n\t" // Zero out MM7 for unpacking
1202  "movq (%0), %%mm6\n\t" // Set up (1 - alpha) * 256 in MM6
1203  "movq (%1), %%mm5\n\t" // Set up color * alpha * 256 in MM5
1204  : : "r"(&packedalpha), "r"(&packedcolor), "m"(packedcolor), "m"(packedalpha) );
1205 
1206  TQ_UINT32 *data = reinterpret_cast<TQ_UINT32*>( dst.bits() );
1207 
1208  // The main loop processes 4 pixels / iteration
1209  int remainder = pixels % 4;
1210  pixels -= remainder;
1211 
1212  // Main loop
1213  for ( int i = 0; i < pixels; i += 4 ) {
1214  __asm__ __volatile__(
1215  // Load 4 pixels to MM registers 1 - 4
1216  "movd (%0,%1,4), %%mm0\n\t" // Load the 1st pixel to MM0
1217  "movd 4(%0,%1,4), %%mm1\n\t" // Load the 2nd pixel to MM1
1218  "movd 8(%0,%1,4), %%mm2\n\t" // Load the 3rd pixel to MM2
1219  "movd 12(%0,%1,4), %%mm3\n\t" // Load the 4th pixel to MM3
1220 
1221  // Blend the first pixel
1222  "punpcklbw %%mm7, %%mm0\n\t" // Unpack the pixel
1223  "pmullw %%mm6, %%mm0\n\t" // Multiply the pixel with (1 - alpha) * 256
1224  "paddw %%mm5, %%mm0\n\t" // Add color * alpha * 256 to the result
1225  "psrlw $8, %%mm0\n\t" // Divide by 256
1226 
1227  // Blend the second pixel
1228  "punpcklbw %%mm7, %%mm1\n\t" // Unpack the pixel
1229  "pmullw %%mm6, %%mm1\n\t" // Multiply the pixel with (1 - alpha) * 256
1230  "paddw %%mm5, %%mm1\n\t" // Add color * alpha * 256 to the result
1231  "psrlw $8, %%mm1\n\t" // Divide by 256
1232 
1233  // Blend the third pixel
1234  "punpcklbw %%mm7, %%mm2\n\t" // Unpack the pixel
1235  "pmullw %%mm6, %%mm2\n\t" // Multiply the pixel with (1 - alpha) * 256
1236  "paddw %%mm5, %%mm2\n\t" // Add color * alpha * 256 to the result
1237  "psrlw $8, %%mm2\n\t" // Divide by 256
1238 
1239  // Blend the fourth pixel
1240  "punpcklbw %%mm7, %%mm3\n\t" // Unpack the pixel
1241  "pmullw %%mm6, %%mm3\n\t" // Multiply the pixel with (1 - alpha) * 256
1242  "paddw %%mm5, %%mm3\n\t" // Add color * alpha * 256 to the result
1243  "psrlw $8, %%mm3\n\t" // Divide by 256
1244 
1245  // Pack the pixels into 2 quadwords
1246  "packuswb %%mm1, %%mm0\n\t" // Pack pixels 1 and 2 to a qword
1247  "packuswb %%mm3, %%mm2\n\t" // Pack pixels 3 and 4 to a qword
1248 
1249  // Write the pixels back to the image
1250  "movq %%mm0, (%0,%1,4)\n\t" // Store pixels 1 and 2
1251  "movq %%mm2, 8(%0,%1,4)\n\t" // Store pixels 3 and 4
1252  : : "r"(data), "r"(i) );
1253  }
1254 
1255  // Cleanup loop
1256  for ( int i = pixels; i < pixels + remainder; i++ ) {
1257  __asm__ __volatile__(
1258  "movd (%0,%1,4), %%mm0\n\t" // Load one pixel to MM1
1259  "punpcklbw %%mm7, %%mm0\n\t" // Unpack the pixel
1260  "pmullw %%mm6, %%mm0\n\t" // Multiply the pixel with 1 - alpha * 256
1261  "paddw %%mm5, %%mm0\n\t" // Add color * alpha * 256 to the result
1262  "psrlw $8, %%mm0\n\t" // Divide by 256
1263  "packuswb %%mm0, %%mm0\n\t" // Pack the pixel to a dword
1264  "movd %%mm0, (%0,%1,4)\n\t" // Write the pixel to the image
1265  : : "r"(data), "r"(i) );
1266  }
1267 
1268  // Empty the MMX state
1269  __asm__ __volatile__("emms");
1270  } else
1271 #endif // USE_MMX_INLINE_ASM
1272 
1273  {
1274  int rcol, gcol, bcol;
1275  clr.rgb(&rcol, &gcol, &bcol);
1276 
1277 #ifdef WORDS_BIGENDIAN // ARGB (skip alpha)
1278  unsigned char *data = (unsigned char *)dst.bits() + 1;
1279 #else // BGRA
1280  unsigned char *data = (unsigned char *)dst.bits();
1281 #endif
1282 
1283  for (int i=0; i<pixels; i++)
1284  {
1285 #ifdef WORDS_BIGENDIAN
1286  *data += (unsigned char)((rcol - *data) * opacity);
1287  data++;
1288  *data += (unsigned char)((gcol - *data) * opacity);
1289  data++;
1290  *data += (unsigned char)((bcol - *data) * opacity);
1291  data++;
1292 #else
1293  *data += (unsigned char)((bcol - *data) * opacity);
1294  data++;
1295  *data += (unsigned char)((gcol - *data) * opacity);
1296  data++;
1297  *data += (unsigned char)((rcol - *data) * opacity);
1298  data++;
1299 #endif
1300  data++; // skip alpha
1301  }
1302  }
1303 
1304  return dst;
1305 }
1306 
1307 // Nice and fast direct pixel manipulation
1308 TQImage& KImageEffect::blend(TQImage& src, TQImage& dst, float opacity)
1309 {
1310  if (src.width() <= 0 || src.height() <= 0)
1311  return dst;
1312  if (dst.width() <= 0 || dst.height() <= 0)
1313  return dst;
1314 
1315  if (src.width() != dst.width() || src.height() != dst.height()) {
1316 #ifndef NDEBUG
1317  std::cerr << "WARNING: KImageEffect::blend : src and destination images are not the same size\n";
1318 #endif
1319  return dst;
1320  }
1321 
1322  if (opacity < 0.0 || opacity > 1.0) {
1323 #ifndef NDEBUG
1324  std::cerr << "WARNING: KImageEffect::blend : invalid opacity. Range [0, 1]\n";
1325 #endif
1326  return dst;
1327  }
1328 
1329  if (src.depth() != 32) src = src.convertDepth(32);
1330  if (dst.depth() != 32) dst = dst.convertDepth(32);
1331 
1332  int pixels = src.width() * src.height();
1333 
1334 #ifdef USE_SSE2_INLINE_ASM
1335  if ( KCPUInfo::haveExtension( KCPUInfo::IntelSSE2 ) && pixels > 16 ) {
1336  TQ_UINT16 alpha = TQ_UINT16( opacity * 256.0 );
1337  KIE8Pack packedalpha = { { alpha, alpha, alpha, 0,
1338  alpha, alpha, alpha, 0 } };
1339 
1340  // Prepare the XMM6 and XMM7 registers for unpacking and blending
1341  __asm__ __volatile__(
1342  "pxor %%xmm7, %%xmm7\n\t" // Zero out XMM7 for unpacking
1343  "movdqu (%0), %%xmm6\n\t" // Set up alpha * 256 in XMM6
1344  : : "r"(&packedalpha), "m"(packedalpha) );
1345 
1346  TQ_UINT32 *data1 = reinterpret_cast<TQ_UINT32*>( src.bits() );
1347  TQ_UINT32 *data2 = reinterpret_cast<TQ_UINT32*>( dst.bits() );
1348 
1349  // Check how many pixels we need to process to achieve 16 byte alignment
1350  int offset = (16 - (TQ_UINT32( data2 ) & 0x0f)) / 4;
1351 
1352  // The main loop processes 4 pixels / iteration
1353  int remainder = (pixels - offset) % 4;
1354  pixels -= remainder;
1355 
1356  // Alignment loop
1357  for ( int i = 0; i < offset; i++ ) {
1358  __asm__ __volatile__(
1359  "movd (%1,%2,4), %%xmm1\n\t" // Load one dst pixel to XMM1
1360  "punpcklbw %%xmm7, %%xmm1\n\t" // Unpack the pixel
1361  "movd (%0,%2,4), %%xmm0\n\t" // Load one src pixel to XMM0
1362  "punpcklbw %%xmm7, %%xmm0\n\t" // Unpack the pixel
1363  "psubw %%xmm1, %%xmm0\n\t" // Subtract dst from src
1364  "pmullw %%xmm6, %%xmm0\n\t" // Multiply the result with alpha * 256
1365  "psllw $8, %%xmm1\n\t" // Multiply dst with 256
1366  "paddw %%xmm1, %%xmm0\n\t" // Add dst to result
1367  "psrlw $8, %%xmm0\n\t" // Divide by 256
1368  "packuswb %%xmm1, %%xmm0\n\t" // Pack the pixel to a dword
1369  "movd %%xmm0, (%1,%2,4)\n\t" // Write the pixel to the image
1370  : : "r"(data1), "r"(data2), "r"(i) );
1371  }
1372 
1373  // Main loop
1374  for ( int i = offset; i < pixels; i += 4 ) {
1375  __asm__ __volatile__(
1376  // Load 4 src pixels to XMM0 and XMM2 and 4 dst pixels to XMM1 and XMM3
1377  "movq (%0,%2,4), %%xmm0\n\t" // Load two src pixels to XMM0
1378  "movq (%1,%2,4), %%xmm1\n\t" // Load two dst pixels to XMM1
1379  "movq 8(%0,%2,4), %%xmm2\n\t" // Load two src pixels to XMM2
1380  "movq 8(%1,%2,4), %%xmm3\n\t" // Load two dst pixels to XMM3
1381 
1382  // Prefetch the pixels for the iteration after the next one
1383  "prefetchnta 32(%0,%2,4) \n\t"
1384  "prefetchnta 32(%1,%2,4) \n\t"
1385 
1386  // Blend the first two pixels
1387  "punpcklbw %%xmm7, %%xmm1\n\t" // Unpack the dst pixels
1388  "punpcklbw %%xmm7, %%xmm0\n\t" // Unpack the src pixels
1389  "psubw %%xmm1, %%xmm0\n\t" // Subtract dst from src
1390  "pmullw %%xmm6, %%xmm0\n\t" // Multiply the result with alpha * 256
1391  "psllw $8, %%xmm1\n\t" // Multiply dst with 256
1392  "paddw %%xmm1, %%xmm0\n\t" // Add dst to the result
1393  "psrlw $8, %%xmm0\n\t" // Divide by 256
1394 
1395  // Blend the next two pixels
1396  "punpcklbw %%xmm7, %%xmm3\n\t" // Unpack the dst pixels
1397  "punpcklbw %%xmm7, %%xmm2\n\t" // Unpack the src pixels
1398  "psubw %%xmm3, %%xmm2\n\t" // Subtract dst from src
1399  "pmullw %%xmm6, %%xmm2\n\t" // Multiply the result with alpha * 256
1400  "psllw $8, %%xmm3\n\t" // Multiply dst with 256
1401  "paddw %%xmm3, %%xmm2\n\t" // Add dst to the result
1402  "psrlw $8, %%xmm2\n\t" // Divide by 256
1403 
1404  // Write the pixels back to the image
1405  "packuswb %%xmm2, %%xmm0\n\t" // Pack the pixels to a double qword
1406  "movdqa %%xmm0, (%1,%2,4)\n\t" // Store the pixels
1407  : : "r"(data1), "r"(data2), "r"(i) );
1408  }
1409 
1410  // Cleanup loop
1411  for ( int i = pixels; i < pixels + remainder; i++ ) {
1412  __asm__ __volatile__(
1413  "movd (%1,%2,4), %%xmm1\n\t" // Load one dst pixel to XMM1
1414  "punpcklbw %%xmm7, %%xmm1\n\t" // Unpack the pixel
1415  "movd (%0,%2,4), %%xmm0\n\t" // Load one src pixel to XMM0
1416  "punpcklbw %%xmm7, %%xmm0\n\t" // Unpack the pixel
1417  "psubw %%xmm1, %%xmm0\n\t" // Subtract dst from src
1418  "pmullw %%xmm6, %%xmm0\n\t" // Multiply the result with alpha * 256
1419  "psllw $8, %%xmm1\n\t" // Multiply dst with 256
1420  "paddw %%xmm1, %%xmm0\n\t" // Add dst to result
1421  "psrlw $8, %%xmm0\n\t" // Divide by 256
1422  "packuswb %%xmm1, %%xmm0\n\t" // Pack the pixel to a dword
1423  "movd %%xmm0, (%1,%2,4)\n\t" // Write the pixel to the image
1424  : : "r"(data1), "r"(data2), "r"(i) );
1425  }
1426  } else
1427 #endif // USE_SSE2_INLINE_ASM
1428 
1429 #ifdef USE_MMX_INLINE_ASM
1430  if ( KCPUInfo::haveExtension( KCPUInfo::IntelMMX ) && pixels > 1 ) {
1431  TQ_UINT16 alpha = TQ_UINT16( opacity * 256.0 );
1432  KIE4Pack packedalpha = { { alpha, alpha, alpha, 0 } };
1433 
1434  // Prepare the MM6 and MM7 registers for blending and unpacking
1435  __asm__ __volatile__(
1436  "pxor %%mm7, %%mm7\n\t" // Zero out MM7 for unpacking
1437  "movq (%0), %%mm6\n\t" // Set up alpha * 256 in MM6
1438  : : "r"(&packedalpha), "m"(packedalpha) );
1439 
1440  TQ_UINT32 *data1 = reinterpret_cast<TQ_UINT32*>( src.bits() );
1441  TQ_UINT32 *data2 = reinterpret_cast<TQ_UINT32*>( dst.bits() );
1442 
1443  // The main loop processes 2 pixels / iteration
1444  int remainder = pixels % 2;
1445  pixels -= remainder;
1446 
1447  // Main loop
1448  for ( int i = 0; i < pixels; i += 2 ) {
1449  __asm__ __volatile__(
1450  // Load 2 src pixels to MM0 and MM2 and 2 dst pixels to MM1 and MM3
1451  "movd (%0,%2,4), %%mm0\n\t" // Load the 1st src pixel to MM0
1452  "movd (%1,%2,4), %%mm1\n\t" // Load the 1st dst pixel to MM1
1453  "movd 4(%0,%2,4), %%mm2\n\t" // Load the 2nd src pixel to MM2
1454  "movd 4(%1,%2,4), %%mm3\n\t" // Load the 2nd dst pixel to MM3
1455 
1456  // Blend the first pixel
1457  "punpcklbw %%mm7, %%mm0\n\t" // Unpack the src pixel
1458  "punpcklbw %%mm7, %%mm1\n\t" // Unpack the dst pixel
1459  "psubw %%mm1, %%mm0\n\t" // Subtract dst from src
1460  "pmullw %%mm6, %%mm0\n\t" // Multiply the result with alpha * 256
1461  "psllw $8, %%mm1\n\t" // Multiply dst with 256
1462  "paddw %%mm1, %%mm0\n\t" // Add dst to the result
1463  "psrlw $8, %%mm0\n\t" // Divide by 256
1464 
1465  // Blend the second pixel
1466  "punpcklbw %%mm7, %%mm2\n\t" // Unpack the src pixel
1467  "punpcklbw %%mm7, %%mm3\n\t" // Unpack the dst pixel
1468  "psubw %%mm3, %%mm2\n\t" // Subtract dst from src
1469  "pmullw %%mm6, %%mm2\n\t" // Multiply the result with alpha * 256
1470  "psllw $8, %%mm3\n\t" // Multiply dst with 256
1471  "paddw %%mm3, %%mm2\n\t" // Add dst to the result
1472  "psrlw $8, %%mm2\n\t" // Divide by 256
1473 
1474  // Write the pixels back to the image
1475  "packuswb %%mm2, %%mm0\n\t" // Pack the pixels to a qword
1476  "movq %%mm0, (%1,%2,4)\n\t" // Store the pixels
1477  : : "r"(data1), "r"(data2), "r"(i) );
1478  }
1479 
1480  // Blend the remaining pixel (if there is one)
1481  if ( remainder ) {
1482  __asm__ __volatile__(
1483  "movd (%0), %%mm0\n\t" // Load one src pixel to MM0
1484  "punpcklbw %%mm7, %%mm0\n\t" // Unpack the src pixel
1485  "movd (%1), %%mm1\n\t" // Load one dst pixel to MM1
1486  "punpcklbw %%mm7, %%mm1\n\t" // Unpack the dst pixel
1487  "psubw %%mm1, %%mm0\n\t" // Subtract dst from src
1488  "pmullw %%mm6, %%mm0\n\t" // Multiply the result with alpha * 256
1489  "psllw $8, %%mm1\n\t" // Multiply dst with 256
1490  "paddw %%mm1, %%mm0\n\t" // Add dst to result
1491  "psrlw $8, %%mm0\n\t" // Divide by 256
1492  "packuswb %%mm0, %%mm0\n\t" // Pack the pixel to a dword
1493  "movd %%mm0, (%1)\n\t" // Write the pixel to the image
1494  : : "r"(data1 + pixels), "r"(data2 + pixels) );
1495  }
1496 
1497  // Empty the MMX state
1498  __asm__ __volatile__("emms");
1499  } else
1500 #endif // USE_MMX_INLINE_ASM
1501 
1502  {
1503 #ifdef WORDS_BIGENDIAN // ARGB (skip alpha)
1504  unsigned char *data1 = (unsigned char *)dst.bits() + 1;
1505  unsigned char *data2 = (unsigned char *)src.bits() + 1;
1506 #else // BGRA
1507  unsigned char *data1 = (unsigned char *)dst.bits();
1508  unsigned char *data2 = (unsigned char *)src.bits();
1509 #endif
1510 
1511  for (int i=0; i<pixels; i++)
1512  {
1513 #ifdef WORDS_BIGENDIAN
1514  *data1 += (unsigned char)((*(data2++) - *data1) * opacity);
1515  data1++;
1516  *data1 += (unsigned char)((*(data2++) - *data1) * opacity);
1517  data1++;
1518  *data1 += (unsigned char)((*(data2++) - *data1) * opacity);
1519  data1++;
1520 #else
1521  *data1 += (unsigned char)((*(data2++) - *data1) * opacity);
1522  data1++;
1523  *data1 += (unsigned char)((*(data2++) - *data1) * opacity);
1524  data1++;
1525  *data1 += (unsigned char)((*(data2++) - *data1) * opacity);
1526  data1++;
1527 #endif
1528  data1++; // skip alpha
1529  data2++;
1530  }
1531  }
1532 
1533  return dst;
1534 }
1535 
1536 
1537 TQImage& KImageEffect::blend(TQImage &image, float initial_intensity,
1538  const TQColor &bgnd, GradientType eff,
1539  bool anti_dir)
1540 {
1541  if (image.width() == 0 || image.height() == 0 || image.depth()!=32 ) {
1542 #ifndef NDEBUG
1543  std::cerr << "WARNING: KImageEffect::blend : invalid image\n";
1544 #endif
1545  return image;
1546  }
1547 
1548  int r_bgnd = bgnd.red(), g_bgnd = bgnd.green(), b_bgnd = bgnd.blue();
1549  int r, g, b;
1550  int ind;
1551 
1552  unsigned int xi, xf, yi, yf;
1553  unsigned int a;
1554 
1555  // check the boundaries of the initial intesity param
1556  float unaffected = 1;
1557  if (initial_intensity > 1) initial_intensity = 1;
1558  if (initial_intensity < -1) initial_intensity = -1;
1559  if (initial_intensity < 0) {
1560  unaffected = 1. + initial_intensity;
1561  initial_intensity = 0;
1562  }
1563 
1564 
1565  float intensity = initial_intensity;
1566  float var = 1. - initial_intensity;
1567 
1568  if (anti_dir) {
1569  initial_intensity = intensity = 1.;
1570  var = -var;
1571  }
1572 
1573  int x, y;
1574 
1575  unsigned int *data = (unsigned int *)image.bits();
1576 
1577  int image_width = image.width(); //Those can't change
1578  int image_height = image.height();
1579 
1580 
1581  if( eff == VerticalGradient || eff == HorizontalGradient ) {
1582 
1583  // set the image domain to apply the effect to
1584  xi = 0, xf = image_width;
1585  yi = 0, yf = image_height;
1586  if (eff == VerticalGradient) {
1587  if (anti_dir) yf = (int)(image_height * unaffected);
1588  else yi = (int)(image_height * (1 - unaffected));
1589  }
1590  else {
1591  if (anti_dir) xf = (int)(image_width * unaffected);
1592  else xi = (int)(image_height * (1 - unaffected));
1593  }
1594 
1595  var /= (eff == VerticalGradient?yf-yi:xf-xi);
1596 
1597  int ind_base;
1598  for (y = yi; y < (int)yf; y++) {
1599  intensity = eff == VerticalGradient? intensity + var :
1600  initial_intensity;
1601  ind_base = image_width * y ;
1602  for (x = xi; x < (int)xf ; x++) {
1603  if (eff == HorizontalGradient) intensity += var;
1604  ind = x + ind_base;
1605  r = tqRed (data[ind]) + (int)(intensity *
1606  (r_bgnd - tqRed (data[ind])));
1607  g = tqGreen(data[ind]) + (int)(intensity *
1608  (g_bgnd - tqGreen(data[ind])));
1609  b = tqBlue (data[ind]) + (int)(intensity *
1610  (b_bgnd - tqBlue (data[ind])));
1611  if (r > 255) r = 255; if (r < 0 ) r = 0;
1612  if (g > 255) g = 255; if (g < 0 ) g = 0;
1613  if (b > 255) b = 255; if (b < 0 ) b = 0;
1614  a = tqAlpha(data[ind]);
1615  data[ind] = tqRgba(r, g, b, a);
1616  }
1617  }
1618  }
1619  else if (eff == DiagonalGradient || eff == CrossDiagonalGradient) {
1620  float xvar = var / 2 / image_width; // / unaffected;
1621  float yvar = var / 2 / image_height; // / unaffected;
1622  float tmp;
1623 
1624  for (x = 0; x < image_width ; x++) {
1625  tmp = xvar * (eff == DiagonalGradient? x : image.width()-x-1);
1626  ind = x;
1627  for (y = 0; y < image_height ; y++) {
1628  intensity = initial_intensity + tmp + yvar * y;
1629 
1630  r = tqRed (data[ind]) + (int)(intensity *
1631  (r_bgnd - tqRed (data[ind])));
1632  g = tqGreen(data[ind]) + (int)(intensity *
1633  (g_bgnd - tqGreen(data[ind])));
1634  b = tqBlue (data[ind]) + (int)(intensity *
1635  (b_bgnd - tqBlue (data[ind])));
1636  if (r > 255) r = 255; if (r < 0 ) r = 0;
1637  if (g > 255) g = 255; if (g < 0 ) g = 0;
1638  if (b > 255) b = 255; if (b < 0 ) b = 0;
1639  a = tqAlpha(data[ind]);
1640  data[ind] = tqRgba(r, g, b, a);
1641 
1642  ind += image_width;
1643  }
1644  }
1645  }
1646 
1647  else if (eff == RectangleGradient || eff == EllipticGradient) {
1648  float xvar;
1649  float yvar;
1650 
1651  for (x = 0; x < image_width / 2 + image_width % 2; x++) {
1652  xvar = var / image_width * (image_width - x*2/unaffected-1);
1653  for (y = 0; y < image_height / 2 + image_height % 2; y++) {
1654  yvar = var / image_height * (image_height - y*2/unaffected -1);
1655 
1656  if (eff == RectangleGradient)
1657  intensity = initial_intensity + TQMAX(xvar, yvar);
1658  else
1659  intensity = initial_intensity + sqrt(xvar * xvar + yvar * yvar);
1660  if (intensity > 1) intensity = 1;
1661  if (intensity < 0) intensity = 0;
1662 
1663  //NW
1664  ind = x + image_width * y ;
1665  r = tqRed (data[ind]) + (int)(intensity *
1666  (r_bgnd - tqRed (data[ind])));
1667  g = tqGreen(data[ind]) + (int)(intensity *
1668  (g_bgnd - tqGreen(data[ind])));
1669  b = tqBlue (data[ind]) + (int)(intensity *
1670  (b_bgnd - tqBlue (data[ind])));
1671  if (r > 255) r = 255; if (r < 0 ) r = 0;
1672  if (g > 255) g = 255; if (g < 0 ) g = 0;
1673  if (b > 255) b = 255; if (b < 0 ) b = 0;
1674  a = tqAlpha(data[ind]);
1675  data[ind] = tqRgba(r, g, b, a);
1676 
1677  //NE
1678  ind = image_width - x - 1 + image_width * y ;
1679  r = tqRed (data[ind]) + (int)(intensity *
1680  (r_bgnd - tqRed (data[ind])));
1681  g = tqGreen(data[ind]) + (int)(intensity *
1682  (g_bgnd - tqGreen(data[ind])));
1683  b = tqBlue (data[ind]) + (int)(intensity *
1684  (b_bgnd - tqBlue (data[ind])));
1685  if (r > 255) r = 255; if (r < 0 ) r = 0;
1686  if (g > 255) g = 255; if (g < 0 ) g = 0;
1687  if (b > 255) b = 255; if (b < 0 ) b = 0;
1688  a = tqAlpha(data[ind]);
1689  data[ind] = tqRgba(r, g, b, a);
1690  }
1691  }
1692 
1693  //CT loop is doubled because of stupid central row/column issue.
1694  // other solution?
1695  for (x = 0; x < image_width / 2; x++) {
1696  xvar = var / image_width * (image_width - x*2/unaffected-1);
1697  for (y = 0; y < image_height / 2; y++) {
1698  yvar = var / image_height * (image_height - y*2/unaffected -1);
1699 
1700  if (eff == RectangleGradient)
1701  intensity = initial_intensity + TQMAX(xvar, yvar);
1702  else
1703  intensity = initial_intensity + sqrt(xvar * xvar + yvar * yvar);
1704  if (intensity > 1) intensity = 1;
1705  if (intensity < 0) intensity = 0;
1706 
1707  //SW
1708  ind = x + image_width * (image_height - y -1) ;
1709  r = tqRed (data[ind]) + (int)(intensity *
1710  (r_bgnd - tqRed (data[ind])));
1711  g = tqGreen(data[ind]) + (int)(intensity *
1712  (g_bgnd - tqGreen(data[ind])));
1713  b = tqBlue (data[ind]) + (int)(intensity *
1714  (b_bgnd - tqBlue (data[ind])));
1715  if (r > 255) r = 255; if (r < 0 ) r = 0;
1716  if (g > 255) g = 255; if (g < 0 ) g = 0;
1717  if (b > 255) b = 255; if (b < 0 ) b = 0;
1718  a = tqAlpha(data[ind]);
1719  data[ind] = tqRgba(r, g, b, a);
1720 
1721  //SE
1722  ind = image_width-x-1 + image_width * (image_height - y - 1) ;
1723  r = tqRed (data[ind]) + (int)(intensity *
1724  (r_bgnd - tqRed (data[ind])));
1725  g = tqGreen(data[ind]) + (int)(intensity *
1726  (g_bgnd - tqGreen(data[ind])));
1727  b = tqBlue (data[ind]) + (int)(intensity *
1728  (b_bgnd - tqBlue (data[ind])));
1729  if (r > 255) r = 255; if (r < 0 ) r = 0;
1730  if (g > 255) g = 255; if (g < 0 ) g = 0;
1731  if (b > 255) b = 255; if (b < 0 ) b = 0;
1732  a = tqAlpha(data[ind]);
1733  data[ind] = tqRgba(r, g, b, a);
1734  }
1735  }
1736  }
1737 #ifndef NDEBUG
1738  else std::cerr << "KImageEffect::blend effect not implemented" << std::endl;
1739 #endif
1740  return image;
1741 }
1742 
1743 // Not very efficient as we create a third big image...
1744 //
1745 TQImage& KImageEffect::blend(TQImage &image1, TQImage &image2,
1746  GradientType gt, int xf, int yf)
1747 {
1748  if (image1.width() == 0 || image1.height() == 0 ||
1749  image2.width() == 0 || image2.height() == 0)
1750  return image1;
1751 
1752  TQImage image3;
1753 
1754  image3 = KImageEffect::unbalancedGradient(image1.size(),
1755  TQColor(0,0,0), TQColor(255,255,255),
1756  gt, xf, yf, 0);
1757 
1758  return blend(image1,image2,image3, Red); // Channel to use is arbitrary
1759 }
1760 
1761 // Blend image2 into image1, using an RBG channel of blendImage
1762 //
1763 TQImage& KImageEffect::blend(TQImage &image1, TQImage &image2,
1764  TQImage &blendImage, RGBComponent channel)
1765 {
1766  if (image1.width() == 0 || image1.height() == 0 ||
1767  image2.width() == 0 || image2.height() == 0 ||
1768  blendImage.width() == 0 || blendImage.height() == 0) {
1769 #ifndef NDEBUG
1770  std::cerr << "KImageEffect::blend effect invalid image" << std::endl;
1771 #endif
1772  return image1;
1773  }
1774 
1775  int r, g, b;
1776  int ind1, ind2, ind3;
1777 
1778  unsigned int x1, x2, x3, y1, y2, y3;
1779  unsigned int a;
1780 
1781  int x, y;
1782 
1783  // for image1 and image2, we only handle depth 32
1784  if (image1.depth()<32) image1 = image1.convertDepth(32);
1785  if (image2.depth()<32) image2 = image2.convertDepth(32);
1786 
1787  // for blendImage, we handle depth 8 and 32
1788  if (blendImage.depth()<8) blendImage = blendImage.convertDepth(8);
1789 
1790  unsigned int *colorTable3 = (blendImage.depth()==8) ?
1791  blendImage.colorTable():0;
1792 
1793  unsigned int *data1 = (unsigned int *)image1.bits();
1794  unsigned int *data2 = (unsigned int *)image2.bits();
1795  unsigned int *data3 = (unsigned int *)blendImage.bits();
1796  unsigned char *data3b = (unsigned char *)blendImage.bits();
1797  unsigned int color3;
1798 
1799  x1 = image1.width(); y1 = image1.height();
1800  x2 = image2.width(); y2 = image2.height();
1801  x3 = blendImage.width(); y3 = blendImage.height();
1802 
1803  for (y = 0; y < (int)y1; y++) {
1804  ind1 = x1*y;
1805  ind2 = x2*(y%y2);
1806  ind3 = x3*(y%y3);
1807 
1808  x=0;
1809  while(x < (int)x1) {
1810  color3 = (colorTable3) ? colorTable3[data3b[ind3]] : data3[ind3];
1811 
1812  a = (channel == Red) ? tqRed(color3) :
1813  (channel == Green) ? tqGreen(color3) :
1814  (channel == Blue) ? tqBlue(color3) : tqGray(color3);
1815 
1816  r = (a*tqRed(data1[ind1]) + (256-a)*tqRed(data2[ind2]))/256;
1817  g = (a*tqGreen(data1[ind1]) + (256-a)*tqGreen(data2[ind2]))/256;
1818  b = (a*tqBlue(data1[ind1]) + (256-a)*tqBlue(data2[ind2]))/256;
1819 
1820  a = tqAlpha(data1[ind1]);
1821  data1[ind1] = tqRgba(r, g, b, a);
1822 
1823  ind1++; ind2++; ind3++; x++;
1824  if ( (x%x2) ==0) ind2 -= x2;
1825  if ( (x%x3) ==0) ind3 -= x3;
1826  }
1827  }
1828  return image1;
1829 }
1830 
1831 
1832 //======================================================================
1833 //
1834 // Hash effects
1835 //
1836 //======================================================================
1837 
1838 unsigned int KImageEffect::lHash(unsigned int c)
1839 {
1840  unsigned char r = tqRed(c), g = tqGreen(c), b = tqBlue(c), a = tqAlpha(c);
1841  unsigned char nr, ng, nb;
1842  nr =(r >> 1) + (r >> 2); nr = nr > r ? 0 : nr;
1843  ng =(g >> 1) + (g >> 2); ng = ng > g ? 0 : ng;
1844  nb =(b >> 1) + (b >> 2); nb = nb > b ? 0 : nb;
1845 
1846  return tqRgba(nr, ng, nb, a);
1847 }
1848 
1849 
1850 // -----------------------------------------------------------------------------
1851 
1852 unsigned int KImageEffect::uHash(unsigned int c)
1853 {
1854  unsigned char r = tqRed(c), g = tqGreen(c), b = tqBlue(c), a = tqAlpha(c);
1855  unsigned char nr, ng, nb;
1856  nr = r + (r >> 3); nr = nr < r ? ~0 : nr;
1857  ng = g + (g >> 3); ng = ng < g ? ~0 : ng;
1858  nb = b + (b >> 3); nb = nb < b ? ~0 : nb;
1859 
1860  return tqRgba(nr, ng, nb, a);
1861 }
1862 
1863 
1864 // -----------------------------------------------------------------------------
1865 
1866 TQImage& KImageEffect::hash(TQImage &image, Lighting lite, unsigned int spacing)
1867 {
1868  if (image.width() == 0 || image.height() == 0) {
1869 #ifndef NDEBUG
1870  std::cerr << "KImageEffect::hash effect invalid image" << std::endl;
1871 #endif
1872  return image;
1873  }
1874 
1875  int x, y;
1876  unsigned int *data = (unsigned int *)image.bits();
1877  unsigned int ind;
1878 
1879  //CT no need to do it if not enough space
1880  if ((lite == NorthLite ||
1881  lite == SouthLite)&&
1882  (unsigned)image.height() < 2+spacing) return image;
1883  if ((lite == EastLite ||
1884  lite == WestLite)&&
1885  (unsigned)image.height() < 2+spacing) return image;
1886 
1887  if (lite == NorthLite || lite == SouthLite) {
1888  for (y = 0 ; y < image.height(); y = y + 2 + spacing) {
1889  for (x = 0; x < image.width(); x++) {
1890  ind = x + image.width() * y;
1891  data[ind] = lite==NorthLite?uHash(data[ind]):lHash(data[ind]);
1892 
1893  ind = ind + image.width();
1894  data[ind] = lite==NorthLite?lHash(data[ind]):uHash(data[ind]);
1895  }
1896  }
1897  }
1898 
1899  else if (lite == EastLite || lite == WestLite) {
1900  for (y = 0 ; y < image.height(); y++) {
1901  for (x = 0; x < image.width(); x = x + 2 + spacing) {
1902  ind = x + image.width() * y;
1903  data[ind] = lite==EastLite?uHash(data[ind]):lHash(data[ind]);
1904 
1905  ind++;
1906  data[ind] = lite==EastLite?lHash(data[ind]):uHash(data[ind]);
1907  }
1908  }
1909  }
1910 
1911  else if (lite == NWLite || lite == SELite) {
1912  for (y = 0 ; y < image.height(); y++) {
1913  for (x = 0;
1914  x < (int)(image.width() - ((y & 1)? 1 : 0) * spacing);
1915  x = x + 2 + spacing) {
1916  ind = x + image.width() * y + ((y & 1)? 1 : 0);
1917  data[ind] = lite==NWLite?uHash(data[ind]):lHash(data[ind]);
1918 
1919  ind++;
1920  data[ind] = lite==NWLite?lHash(data[ind]):uHash(data[ind]);
1921  }
1922  }
1923  }
1924 
1925  else if (lite == SWLite || lite == NELite) {
1926  for (y = 0 ; y < image.height(); y++) {
1927  for (x = 0 + ((y & 1)? 1 : 0); x < image.width(); x = x + 2 + spacing) {
1928  ind = x + image.width() * y - ((y & 1)? 1 : 0);
1929  data[ind] = lite==SWLite?uHash(data[ind]):lHash(data[ind]);
1930 
1931  ind++;
1932  data[ind] = lite==SWLite?lHash(data[ind]):uHash(data[ind]);
1933  }
1934  }
1935  }
1936 
1937  return image;
1938 }
1939 
1940 
1941 //======================================================================
1942 //
1943 // Flatten effects
1944 //
1945 //======================================================================
1946 
1947 TQImage& KImageEffect::flatten(TQImage &img, const TQColor &ca,
1948  const TQColor &cb, int ncols)
1949 {
1950  if (img.width() == 0 || img.height() == 0)
1951  return img;
1952 
1953  // a bitmap is easy...
1954  if (img.depth() == 1) {
1955  img.setColor(0, ca.rgb());
1956  img.setColor(1, cb.rgb());
1957  return img;
1958  }
1959 
1960  int r1 = ca.red(); int r2 = cb.red();
1961  int g1 = ca.green(); int g2 = cb.green();
1962  int b1 = ca.blue(); int b2 = cb.blue();
1963  int min = 0, max = 255;
1964 
1965  TQRgb col;
1966 
1967  // Get minimum and maximum greylevel.
1968  if (img.numColors()) {
1969  // pseudocolor
1970  for (int i = 0; i < img.numColors(); i++) {
1971  col = img.color(i);
1972  int mean = (tqRed(col) + tqGreen(col) + tqBlue(col)) / 3;
1973  min = TQMIN(min, mean);
1974  max = TQMAX(max, mean);
1975  }
1976  } else {
1977  // truecolor
1978  for (int y=0; y < img.height(); y++)
1979  for (int x=0; x < img.width(); x++) {
1980  col = img.pixel(x, y);
1981  int mean = (tqRed(col) + tqGreen(col) + tqBlue(col)) / 3;
1982  min = TQMIN(min, mean);
1983  max = TQMAX(max, mean);
1984  }
1985  }
1986 
1987  // Conversion factors
1988  float sr = ((float) r2 - r1) / (max - min);
1989  float sg = ((float) g2 - g1) / (max - min);
1990  float sb = ((float) b2 - b1) / (max - min);
1991 
1992 
1993  // Repaint the image
1994  if (img.numColors()) {
1995  for (int i=0; i < img.numColors(); i++) {
1996  col = img.color(i);
1997  int mean = (tqRed(col) + tqGreen(col) + tqBlue(col)) / 3;
1998  int r = (int) (sr * (mean - min) + r1 + 0.5);
1999  int g = (int) (sg * (mean - min) + g1 + 0.5);
2000  int b = (int) (sb * (mean - min) + b1 + 0.5);
2001  img.setColor(i, tqRgba(r, g, b, tqAlpha(col)));
2002  }
2003  } else {
2004  for (int y=0; y < img.height(); y++)
2005  for (int x=0; x < img.width(); x++) {
2006  col = img.pixel(x, y);
2007  int mean = (tqRed(col) + tqGreen(col) + tqBlue(col)) / 3;
2008  int r = (int) (sr * (mean - min) + r1 + 0.5);
2009  int g = (int) (sg * (mean - min) + g1 + 0.5);
2010  int b = (int) (sb * (mean - min) + b1 + 0.5);
2011  img.setPixel(x, y, tqRgba(r, g, b, tqAlpha(col)));
2012  }
2013  }
2014 
2015 
2016  // Dither if necessary
2017  if ( (ncols <= 0) || ((img.numColors() != 0) && (img.numColors() <= ncols)))
2018  return img;
2019 
2020  if (ncols == 1) ncols++;
2021  if (ncols > 256) ncols = 256;
2022 
2023  TQColor *pal = new TQColor[ncols];
2024  sr = ((float) r2 - r1) / (ncols - 1);
2025  sg = ((float) g2 - g1) / (ncols - 1);
2026  sb = ((float) b2 - b1) / (ncols - 1);
2027 
2028  for (int i=0; i<ncols; i++)
2029  pal[i] = TQColor(r1 + int(sr*i), g1 + int(sg*i), b1 + int(sb*i));
2030 
2031  dither(img, pal, ncols);
2032 
2033  delete[] pal;
2034  return img;
2035 }
2036 
2037 
2038 //======================================================================
2039 //
2040 // Fade effects
2041 //
2042 //======================================================================
2043 
2044 TQImage& KImageEffect::fade(TQImage &img, float val, const TQColor &color)
2045 {
2046  if (img.width() == 0 || img.height() == 0)
2047  return img;
2048 
2049  // We don't handle bitmaps
2050  if (img.depth() == 1)
2051  return img;
2052 
2053  unsigned char tbl[256];
2054  for (int i=0; i<256; i++)
2055  tbl[i] = (int) (val * i + 0.5);
2056 
2057  int red = color.red();
2058  int green = color.green();
2059  int blue = color.blue();
2060 
2061  TQRgb col;
2062  int r, g, b, cr, cg, cb;
2063 
2064  if (img.depth() <= 8) {
2065  // pseudo color
2066  for (int i=0; i<img.numColors(); i++) {
2067  col = img.color(i);
2068  cr = tqRed(col); cg = tqGreen(col); cb = tqBlue(col);
2069  if (cr > red)
2070  r = cr - tbl[cr - red];
2071  else
2072  r = cr + tbl[red - cr];
2073  if (cg > green)
2074  g = cg - tbl[cg - green];
2075  else
2076  g = cg + tbl[green - cg];
2077  if (cb > blue)
2078  b = cb - tbl[cb - blue];
2079  else
2080  b = cb + tbl[blue - cb];
2081  img.setColor(i, tqRgba(r, g, b, tqAlpha(col)));
2082  }
2083 
2084  } else {
2085  // truecolor
2086  for (int y=0; y<img.height(); y++) {
2087  TQRgb *data = (TQRgb *) img.scanLine(y);
2088  for (int x=0; x<img.width(); x++) {
2089  col = *data;
2090  cr = tqRed(col); cg = tqGreen(col); cb = tqBlue(col);
2091  if (cr > red)
2092  r = cr - tbl[cr - red];
2093  else
2094  r = cr + tbl[red - cr];
2095  if (cg > green)
2096  g = cg - tbl[cg - green];
2097  else
2098  g = cg + tbl[green - cg];
2099  if (cb > blue)
2100  b = cb - tbl[cb - blue];
2101  else
2102  b = cb + tbl[blue - cb];
2103  *data++ = tqRgba(r, g, b, tqAlpha(col));
2104  }
2105  }
2106  }
2107 
2108  return img;
2109 }
2110 
2111 //======================================================================
2112 //
2113 // Color effects
2114 //
2115 //======================================================================
2116 
2117 // This code is adapted from code (C) Rik Hemsley <rik@kde.org>
2118 //
2119 // The formula used (r + b + g) /3 is different from the tqGray formula
2120 // used by Qt. This is because our formula is much much faster. If,
2121 // however, it turns out that this is producing sub-optimal images,
2122 // then it will have to change (kurt)
2123 //
2124 // It does produce lower quality grayscale ;-) Use fast == true for the fast
2125 // algorithm, false for the higher quality one (mosfet).
2126 TQImage& KImageEffect::toGray(TQImage &img, bool fast)
2127 {
2128  if (img.width() == 0 || img.height() == 0)
2129  return img;
2130 
2131  if(fast){
2132  if (img.depth() == 32) {
2133  uchar * r(img.bits());
2134  uchar * g(img.bits() + 1);
2135  uchar * b(img.bits() + 2);
2136 
2137  uchar * end(img.bits() + img.numBytes());
2138 
2139  while (r != end) {
2140 
2141  *r = *g = *b = (((*r + *g) >> 1) + *b) >> 1; // (r + b + g) / 3
2142 
2143  r += 4;
2144  g += 4;
2145  b += 4;
2146  }
2147  }
2148  else
2149  {
2150  for (int i = 0; i < img.numColors(); i++)
2151  {
2152  uint r = tqRed(img.color(i));
2153  uint g = tqGreen(img.color(i));
2154  uint b = tqBlue(img.color(i));
2155 
2156  uint gray = (((r + g) >> 1) + b) >> 1;
2157  img.setColor(i, tqRgba(gray, gray, gray, tqAlpha(img.color(i))));
2158  }
2159  }
2160  }
2161  else{
2162  int pixels = img.depth() > 8 ? img.width()*img.height() :
2163  img.numColors();
2164  unsigned int *data = img.depth() > 8 ? (unsigned int *)img.bits() :
2165  (unsigned int *)img.colorTable();
2166  int val, i;
2167  for(i=0; i < pixels; ++i){
2168  val = tqGray(data[i]);
2169  data[i] = tqRgba(val, val, val, tqAlpha(data[i]));
2170  }
2171  }
2172  return img;
2173 }
2174 
2175 // CT 29Jan2000 - desaturation algorithms
2176 TQImage& KImageEffect::desaturate(TQImage &img, float desat)
2177 {
2178  if (img.width() == 0 || img.height() == 0)
2179  return img;
2180 
2181  if (desat < 0) desat = 0.;
2182  if (desat > 1) desat = 1.;
2183  int pixels = img.depth() > 8 ? img.width()*img.height() :
2184  img.numColors();
2185  unsigned int *data = img.depth() > 8 ? (unsigned int *)img.bits() :
2186  (unsigned int *)img.colorTable();
2187  int h, s, v, i;
2188  TQColor clr; // keep constructor out of loop (mosfet)
2189  for(i=0; i < pixels; ++i){
2190  clr.setRgb(data[i]);
2191  clr.hsv(&h, &s, &v);
2192  clr.setHsv(h, (int)(s * (1. - desat)), v);
2193  data[i] = clr.rgb();
2194  }
2195  return img;
2196 }
2197 
2198 // Contrast stuff (mosfet)
2199 TQImage& KImageEffect::contrast(TQImage &img, int c)
2200 {
2201  if (img.width() == 0 || img.height() == 0)
2202  return img;
2203 
2204  if(c > 255)
2205  c = 255;
2206  if(c < -255)
2207  c = -255;
2208  int pixels = img.depth() > 8 ? img.width()*img.height() :
2209  img.numColors();
2210  unsigned int *data = img.depth() > 8 ? (unsigned int *)img.bits() :
2211  (unsigned int *)img.colorTable();
2212  int i, r, g, b;
2213  for(i=0; i < pixels; ++i){
2214  r = tqRed(data[i]);
2215  g = tqGreen(data[i]);
2216  b = tqBlue(data[i]);
2217  if(tqGray(data[i]) <= 127){
2218  if(r - c > 0)
2219  r -= c;
2220  else
2221  r = 0;
2222  if(g - c > 0)
2223  g -= c;
2224  else
2225  g = 0;
2226  if(b - c > 0)
2227  b -= c;
2228  else
2229  b = 0;
2230  }
2231  else{
2232  if(r + c <= 255)
2233  r += c;
2234  else
2235  r = 255;
2236  if(g + c <= 255)
2237  g += c;
2238  else
2239  g = 255;
2240  if(b + c <= 255)
2241  b += c;
2242  else
2243  b = 255;
2244  }
2245  data[i] = tqRgba(r, g, b, tqAlpha(data[i]));
2246  }
2247  return(img);
2248 }
2249 
2250 //======================================================================
2251 //
2252 // Dithering effects
2253 //
2254 //======================================================================
2255 
2256 // adapted from kFSDither (C) 1997 Martin Jones (mjones@kde.org)
2257 //
2258 // Floyd-Steinberg dithering
2259 // Ref: Bitmapped Graphics Programming in C++
2260 // Marv Luse, Addison-Wesley Publishing, 1993.
2261 TQImage& KImageEffect::dither(TQImage &img, const TQColor *palette, int size)
2262 {
2263  if (img.width() == 0 || img.height() == 0 ||
2264  palette == 0 || img.depth() <= 8)
2265  return img;
2266 
2267  TQImage dImage( img.width(), img.height(), 8, size );
2268  int i;
2269 
2270  dImage.setNumColors( size );
2271  for ( i = 0; i < size; i++ )
2272  dImage.setColor( i, palette[ i ].rgb() );
2273 
2274  int *rerr1 = new int [ img.width() * 2 ];
2275  int *gerr1 = new int [ img.width() * 2 ];
2276  int *berr1 = new int [ img.width() * 2 ];
2277 
2278  memset( rerr1, 0, sizeof( int ) * img.width() * 2 );
2279  memset( gerr1, 0, sizeof( int ) * img.width() * 2 );
2280  memset( berr1, 0, sizeof( int ) * img.width() * 2 );
2281 
2282  int *rerr2 = rerr1 + img.width();
2283  int *gerr2 = gerr1 + img.width();
2284  int *berr2 = berr1 + img.width();
2285 
2286  for ( int j = 0; j < img.height(); j++ )
2287  {
2288  uint *ip = (uint * )img.scanLine( j );
2289  uchar *dp = dImage.scanLine( j );
2290 
2291  for ( i = 0; i < img.width(); i++ )
2292  {
2293  rerr1[i] = rerr2[i] + tqRed( *ip );
2294  rerr2[i] = 0;
2295  gerr1[i] = gerr2[i] + tqGreen( *ip );
2296  gerr2[i] = 0;
2297  berr1[i] = berr2[i] + tqBlue( *ip );
2298  berr2[i] = 0;
2299  ip++;
2300  }
2301 
2302  *dp++ = nearestColor( rerr1[0], gerr1[0], berr1[0], palette, size );
2303 
2304  for ( i = 1; i < img.width()-1; i++ )
2305  {
2306  int indx = nearestColor( rerr1[i], gerr1[i], berr1[i], palette, size );
2307  *dp = indx;
2308 
2309  int rerr = rerr1[i];
2310  rerr -= palette[indx].red();
2311  int gerr = gerr1[i];
2312  gerr -= palette[indx].green();
2313  int berr = berr1[i];
2314  berr -= palette[indx].blue();
2315 
2316  // diffuse red error
2317  rerr1[ i+1 ] += ( rerr * 7 ) >> 4;
2318  rerr2[ i-1 ] += ( rerr * 3 ) >> 4;
2319  rerr2[ i ] += ( rerr * 5 ) >> 4;
2320  rerr2[ i+1 ] += ( rerr ) >> 4;
2321 
2322  // diffuse green error
2323  gerr1[ i+1 ] += ( gerr * 7 ) >> 4;
2324  gerr2[ i-1 ] += ( gerr * 3 ) >> 4;
2325  gerr2[ i ] += ( gerr * 5 ) >> 4;
2326  gerr2[ i+1 ] += ( gerr ) >> 4;
2327 
2328  // diffuse red error
2329  berr1[ i+1 ] += ( berr * 7 ) >> 4;
2330  berr2[ i-1 ] += ( berr * 3 ) >> 4;
2331  berr2[ i ] += ( berr * 5 ) >> 4;
2332  berr2[ i+1 ] += ( berr ) >> 4;
2333 
2334  dp++;
2335  }
2336 
2337  *dp = nearestColor( rerr1[i], gerr1[i], berr1[i], palette, size );
2338  }
2339 
2340  delete [] rerr1;
2341  delete [] gerr1;
2342  delete [] berr1;
2343 
2344  img = dImage;
2345  return img;
2346 }
2347 
2348 int KImageEffect::nearestColor( int r, int g, int b, const TQColor *palette, int size )
2349 {
2350  if (palette == 0)
2351  return 0;
2352 
2353  int dr = palette[0].red() - r;
2354  int dg = palette[0].green() - g;
2355  int db = palette[0].blue() - b;
2356 
2357  int minDist = dr*dr + dg*dg + db*db;
2358  int nearest = 0;
2359 
2360  for (int i = 1; i < size; i++ )
2361  {
2362  dr = palette[i].red() - r;
2363  dg = palette[i].green() - g;
2364  db = palette[i].blue() - b;
2365 
2366  int dist = dr*dr + dg*dg + db*db;
2367 
2368  if ( dist < minDist )
2369  {
2370  minDist = dist;
2371  nearest = i;
2372  }
2373  }
2374 
2375  return nearest;
2376 }
2377 
2378 bool KImageEffect::blend(
2379  const TQImage & upper,
2380  const TQImage & lower,
2381  TQImage & output
2382 )
2383 {
2384  if (
2385  upper.width() > lower.width() ||
2386  upper.height() > lower.height() ||
2387  upper.depth() != 32 ||
2388  lower.depth() != 32
2389  )
2390  {
2391 #ifndef NDEBUG
2392  std::cerr << "KImageEffect::blend : Sizes not correct\n" ;
2393 #endif
2394  return false;
2395  }
2396 
2397  output = lower.copy();
2398 
2399  uchar *i, *o;
2400  int a;
2401  int col;
2402  int w = upper.width();
2403  int row(upper.height() - 1);
2404 
2405  do {
2406 
2407  i = const_cast<TQImage&>(upper).scanLine(row);
2408  o = const_cast<TQImage&>(output).scanLine(row);
2409 
2410  col = w << 2;
2411  --col;
2412 
2413  do {
2414 
2415  while (!(a = i[col]) && (col != 3)) {
2416  --col; --col; --col; --col;
2417  }
2418 
2419  --col;
2420  o[col] += ((i[col] - o[col]) * a) >> 8;
2421 
2422  --col;
2423  o[col] += ((i[col] - o[col]) * a) >> 8;
2424 
2425  --col;
2426  o[col] += ((i[col] - o[col]) * a) >> 8;
2427 
2428  } while (col--);
2429 
2430  } while (row--);
2431 
2432  return true;
2433 }
2434 
2435 #if 0
2436 // Not yet...
2437 bool KImageEffect::blend(
2438  const TQImage & upper,
2439  const TQImage & lower,
2440  TQImage & output,
2441  const TQRect & destRect
2442 )
2443 {
2444  output = lower.copy();
2445  return output;
2446 }
2447 
2448 #endif
2449 
2450 bool KImageEffect::blend(
2451  int &x, int &y,
2452  const TQImage & upper,
2453  const TQImage & lower,
2454  TQImage & output
2455 )
2456 {
2457  int cx=0, cy=0, cw=upper.width(), ch=upper.height();
2458 
2459  if ( upper.width() + x > lower.width() ||
2460  upper.height() + y > lower.height() ||
2461  x < 0 || y < 0 ||
2462  upper.depth() != 32 || lower.depth() != 32 )
2463  {
2464  if ( x > lower.width() || y > lower.height() ) return false;
2465  if ( upper.width()<=0 || upper.height() <= 0 ) return false;
2466  if ( lower.width()<=0 || lower.height() <= 0 ) return false;
2467 
2468  if (x<0) {cx=-x; cw+=x; x=0; };
2469  if (cw + x > lower.width()) { cw=lower.width()-x; };
2470  if (y<0) {cy=-y; ch+=y; y=0; };
2471  if (ch + y > lower.height()) { ch=lower.height()-y; };
2472 
2473  if ( cx >= upper.width() || cy >= upper.height() ) return true;
2474  if ( cw <= 0 || ch <= 0 ) return true;
2475  }
2476 
2477  output.create(cw,ch,32);
2478 // output.setAlphaBuffer(true); // I should do some benchmarks to see if
2479  // this is worth the effort
2480 
2481  TQRgb *i, *o, *b;
2482 
2483  int a;
2484  int j,k;
2485  for (j=0; j<ch; j++)
2486  {
2487  b=reinterpret_cast<TQRgb *>(&const_cast<TQImage&>(lower).scanLine(y+j) [ (x+cw) << 2 ]);
2488  i=reinterpret_cast<TQRgb *>(&const_cast<TQImage&>(upper).scanLine(cy+j)[ (cx+cw) << 2 ]);
2489  o=reinterpret_cast<TQRgb *>(&const_cast<TQImage&>(output).scanLine(j) [ cw << 2 ]);
2490 
2491  k=cw-1;
2492  --b; --i; --o;
2493  do
2494  {
2495  while ( !(a=tqAlpha(*i)) && k>0 )
2496  {
2497  i--;
2498 // *o=0;
2499  *o=*b;
2500  --o; --b;
2501  k--;
2502  };
2503 // *o=0xFF;
2504  *o = tqRgb(tqRed(*b) + (((tqRed(*i) - tqRed(*b)) * a) >> 8),
2505  tqGreen(*b) + (((tqGreen(*i) - tqGreen(*b)) * a) >> 8),
2506  tqBlue(*b) + (((tqBlue(*i) - tqBlue(*b)) * a) >> 8));
2507  --i; --o; --b;
2508  } while (k--);
2509  }
2510 
2511  return true;
2512 }
2513 
2514 bool KImageEffect::blendOnLower(
2515  int x, int y,
2516  const TQImage & upper,
2517  const TQImage & lower
2518 )
2519 {
2520  int cx=0, cy=0, cw=upper.width(), ch=upper.height();
2521 
2522  if ( upper.depth() != 32 || lower.depth() != 32 ) return false;
2523  if ( x + cw > lower.width() ||
2524  y + ch > lower.height() ||
2525  x < 0 || y < 0 )
2526  {
2527  if ( x > lower.width() || y > lower.height() ) return true;
2528  if ( upper.width()<=0 || upper.height() <= 0 ) return true;
2529  if ( lower.width()<=0 || lower.height() <= 0 ) return true;
2530 
2531  if (x<0) {cx=-x; cw+=x; x=0; };
2532  if (cw + x > lower.width()) { cw=lower.width()-x; };
2533  if (y<0) {cy=-y; ch+=y; y=0; };
2534  if (ch + y > lower.height()) { ch=lower.height()-y; };
2535 
2536  if ( cx >= upper.width() || cy >= upper.height() ) return true;
2537  if ( cw <= 0 || ch <= 0 ) return true;
2538  }
2539 
2540  uchar *i, *b;
2541  int a;
2542  int k;
2543 
2544  for (int j=0; j<ch; j++)
2545  {
2546  b=&const_cast<TQImage&>(lower).scanLine(y+j) [ (x+cw) << 2 ];
2547  i=&const_cast<TQImage&>(upper).scanLine(cy+j)[ (cx+cw) << 2 ];
2548 
2549  k=cw-1;
2550  --b; --i;
2551  do
2552  {
2553 #ifndef WORDS_BIGENDIAN
2554  while ( !(a=*i) && k>0 )
2555 #else
2556  while ( !(a=*(i-3)) && k>0 )
2557 #endif
2558  {
2559  i-=4; b-=4; k--;
2560  };
2561 
2562 #ifndef WORDS_BIGENDIAN
2563  --i; --b;
2564  *b += ( ((*i - *b) * a) >> 8 );
2565  --i; --b;
2566  *b += ( ((*i - *b) * a) >> 8 );
2567  --i; --b;
2568  *b += ( ((*i - *b) * a) >> 8 );
2569  --i; --b;
2570 #else
2571  *b += ( ((*i - *b) * a) >> 8 );
2572  --i; --b;
2573  *b += ( ((*i - *b) * a) >> 8 );
2574  --i; --b;
2575  *b += ( ((*i - *b) * a) >> 8 );
2576  i -= 2; b -= 2;
2577 #endif
2578  } while (k--);
2579  }
2580 
2581  return true;
2582 }
2583 
2584 void KImageEffect::blendOnLower(const TQImage &upper, const TQPoint &upperOffset,
2585  TQImage &lower, const TQRect &lowerRect)
2586 {
2587  // clip rect
2588  TQRect lr = lowerRect & lower.rect();
2589  lr.setWidth( TQMIN(lr.width(), upper.width()-upperOffset.x()) );
2590  lr.setHeight( TQMIN(lr.height(), upper.height()-upperOffset.y()) );
2591  if ( !lr.isValid() ) return;
2592 
2593  // blend
2594  for (int y = 0; y < lr.height(); y++) {
2595  for (int x = 0; x < lr.width(); x++) {
2596  TQRgb *b = reinterpret_cast<TQRgb*>(const_cast<TQImage&>(lower).scanLine(lr.y() + y)+ (lr.x() + x) * sizeof(TQRgb));
2597  TQRgb *d = reinterpret_cast<TQRgb*>(const_cast<TQImage&>(upper).scanLine(upperOffset.y() + y) + (upperOffset.x() + x) * sizeof(TQRgb));
2598  int a = tqAlpha(*d);
2599  *b = tqRgb(tqRed(*b) - (((tqRed(*b) - tqRed(*d)) * a) >> 8),
2600  tqGreen(*b) - (((tqGreen(*b) - tqGreen(*d)) * a) >> 8),
2601  tqBlue(*b) - (((tqBlue(*b) - tqBlue(*d)) * a) >> 8));
2602  }
2603  }
2604 }
2605 
2606 void KImageEffect::blendOnLower(const TQImage &upper, const TQPoint &upperOffset,
2607  TQImage &lower, const TQRect &lowerRect, float opacity)
2608 {
2609  // clip rect
2610  TQRect lr = lowerRect & lower.rect();
2611  lr.setWidth( TQMIN(lr.width(), upper.width()-upperOffset.x()) );
2612  lr.setHeight( TQMIN(lr.height(), upper.height()-upperOffset.y()) );
2613  if ( !lr.isValid() ) return;
2614 
2615  // blend
2616  for (int y = 0; y < lr.height(); y++) {
2617  for (int x = 0; x < lr.width(); x++) {
2618  TQRgb *b = reinterpret_cast<TQRgb*>(const_cast<TQImage&>(lower).scanLine(lr.y() + y)+ (lr.x() + x) * sizeof(TQRgb));
2619  TQRgb *d = reinterpret_cast<TQRgb*>(const_cast<TQImage&>(upper).scanLine(upperOffset.y() + y) + (upperOffset.x() + x) * sizeof(TQRgb));
2620  int a = tqRound(opacity * tqAlpha(*d));
2621  *b = tqRgb(tqRed(*b) - (((tqRed(*b) - tqRed(*d)) * a) >> 8),
2622  tqGreen(*b) - (((tqGreen(*b) - tqGreen(*d)) * a) >> 8),
2623  tqBlue(*b) - (((tqBlue(*b) - tqBlue(*d)) * a) >> 8));
2624  }
2625  }
2626 }
2627 
2628 TQRect KImageEffect::computeDestinationRect(const TQSize &lowerSize,
2629  Disposition disposition, TQImage &upper)
2630 {
2631  int w = lowerSize.width();
2632  int h = lowerSize.height();
2633  int ww = upper.width();
2634  int wh = upper.height();
2635  TQRect d;
2636 
2637  switch (disposition) {
2638  case NoImage:
2639  break;
2640  case Centered:
2641  d.setRect((w - ww) / 2, (h - wh) / 2, ww, wh);
2642  break;
2643  case Tiled:
2644  d.setRect(0, 0, w, h);
2645  break;
2646  case CenterTiled:
2647  d.setCoords(-ww + ((w - ww) / 2) % ww, -wh + ((h - wh) / 2) % wh,
2648  w-1, h-1);
2649  break;
2650  case Scaled:
2651  upper = upper.smoothScale(w, h);
2652  d.setRect(0, 0, w, h);
2653  break;
2654  case CenteredAutoFit:
2655  if( ww <= w && wh <= h ) {
2656  d.setRect((w - ww) / 2, (h - wh) / 2, ww, wh); // like Centered
2657  break;
2658  }
2659  // fall through
2660  case CenteredMaxpect: {
2661  double sx = (double) w / ww;
2662  double sy = (double) h / wh;
2663  if (sx > sy) {
2664  ww = (int)(sy * ww);
2665  wh = h;
2666  } else {
2667  wh = (int)(sx * wh);
2668  ww = w;
2669  }
2670  upper = upper.smoothScale(ww, wh);
2671  d.setRect((w - ww) / 2, (h - wh) / 2, ww, wh);
2672  break;
2673  }
2674  case TiledMaxpect: {
2675  double sx = (double) w / ww;
2676  double sy = (double) h / wh;
2677  if (sx > sy) {
2678  ww = (int)(sy * ww);
2679  wh = h;
2680  } else {
2681  wh = (int)(sx * wh);
2682  ww = w;
2683  }
2684  upper = upper.smoothScale(ww, wh);
2685  d.setRect(0, 0, w, h);
2686  break;
2687  }
2688  }
2689 
2690  return d;
2691 }
2692 
2693 void KImageEffect::blendOnLower(TQImage &upper, TQImage &lower,
2694  Disposition disposition, float opacity)
2695 {
2696  TQRect r = computeDestinationRect(lower.size(), disposition, upper);
2697  for (int y = r.top(); y<r.bottom(); y += upper.height())
2698  for (int x = r.left(); x<r.right(); x += upper.width())
2699  blendOnLower(upper, TQPoint(-TQMIN(x, 0), -TQMIN(y, 0)),
2700  lower, TQRect(x, y, upper.width(), upper.height()), opacity);
2701 }
2702 
2703 
2704 // For selected icons
2705 TQImage& KImageEffect::selectedImage( TQImage &img, const TQColor &col )
2706 {
2707  return blend( col, img, 0.5);
2708 }
2709 
2710 //
2711 // ===================================================================
2712 // Effects originally ported from ImageMagick for PixiePlus, plus a few
2713 // new ones. (mosfet 05/26/2003)
2714 // ===================================================================
2715 //
2716 /*
2717  Portions of this software are based on ImageMagick. Such portions are clearly
2718 marked as being ported from ImageMagick. ImageMagick is copyrighted under the
2719 following conditions:
2720 
2721 Copyright (C) 2003 ImageMagick Studio, a non-profit organization dedicated to
2722 making software imaging solutions freely available.
2723 
2724 Permission is hereby granted, free of charge, to any person obtaining a copy
2725 of this software and associated documentation files ("ImageMagick"), to deal
2726 in ImageMagick without restriction, including without limitation the rights
2727 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
2728 copies of ImageMagick, and to permit persons to whom the ImageMagick is
2729 furnished to do so, subject to the following conditions:
2730 
2731 The above copyright notice and this permission notice shall be included in all
2732 copies or substantial portions of ImageMagick.
2733 
2734 The software is provided "as is", without warranty of any kind, express or
2735 implied, including but not limited to the warranties of merchantability,
2736 fitness for a particular purpose and noninfringement. In no event shall
2737 ImageMagick Studio be liable for any claim, damages or other liability,
2738 whether in an action of contract, tort or otherwise, arising from, out of or
2739 in connection with ImageMagick or the use or other dealings in ImageMagick.
2740 
2741 Except as contained in this notice, the name of the ImageMagick Studio shall
2742 not be used in advertising or otherwise to promote the sale, use or other
2743 dealings in ImageMagick without prior written authorization from the
2744 ImageMagick Studio.
2745 */
2746 
2747 TQImage KImageEffect::sample(TQImage &src, int w, int h)
2748 {
2749  if(w == src.width() && h == src.height())
2750  return(src);
2751 
2752  int depth = src.depth();
2753  TQImage dest(w, h, depth, depth <= 8 ? src.numColors() : 0,
2754  depth == 1 ? TQImage::LittleEndian : TQImage::IgnoreEndian);
2755  int *x_offset = (int *)malloc(w*sizeof(int));
2756  int *y_offset = (int *)malloc(h*sizeof(int));
2757  if(!x_offset || !y_offset){
2758 #ifndef NDEBUG
2759  tqWarning("KImageEffect::sample(): Unable to allocate pixel buffer");
2760 #endif
2761  free(x_offset);
2762  free(y_offset);
2763  return(src);
2764  }
2765 
2766  // init pixel offsets
2767  for(int x=0; x < w; ++x)
2768  x_offset[x] = (int)(x*src.width()/((double)w));
2769  for(int y=0; y < h; ++y)
2770  y_offset[y] = (int)(y*src.height()/((double)h));
2771 
2772  if(depth > 8){ // DirectClass source image
2773  for(int y=0; y < h; ++y){
2774  unsigned int *destData = (unsigned int *)dest.scanLine(y);
2775  unsigned int *srcData = (unsigned int *)src.scanLine(y_offset[y]);
2776  for(int x=0; x < w; ++x)
2777  destData[x] = srcData[x_offset[x]];
2778  }
2779  }
2780  else if(depth == 1) {
2781  int r = src.bitOrder() == TQImage::LittleEndian;
2782  memcpy(dest.colorTable(), src.colorTable(), src.numColors()*sizeof(TQRgb));
2783  for(int y=0; y < h; ++y){
2784  unsigned char *destData = dest.scanLine(y);
2785  unsigned char *srcData = src.scanLine(y_offset[y]);
2786  for(int x=0; x < w; ++x){
2787  int k = x_offset[x];
2788  int l = r ? (k & 7) : (7 - (k&7));
2789  if(srcData[k >> 3] & (1 << l))
2790  destData[x >> 3] |= 1 << (x & 7);
2791  else
2792  destData[x >> 3] &= ~(1 << (x & 7));
2793  }
2794  }
2795  }
2796  else{ // PseudoClass source image
2797  memcpy(dest.colorTable(), src.colorTable(), src.numColors()*sizeof(TQRgb));
2798  for(int y=0; y < h; ++y){
2799  unsigned char *destData = dest.scanLine(y);
2800  unsigned char *srcData = src.scanLine(y_offset[y]);
2801  for(int x=0; x < w; ++x)
2802  destData[x] = srcData[x_offset[x]];
2803  }
2804  }
2805  free(x_offset);
2806  free(y_offset);
2807  return(dest);
2808 }
2809 
2810 void KImageEffect::threshold(TQImage &img, unsigned int threshold)
2811 {
2812  int i, count;
2813  unsigned int *data;
2814  if(img.depth() > 8){ // DirectClass
2815  count = img.width()*img.height();
2816  data = (unsigned int *)img.bits();
2817  }
2818  else{ // PsudeoClass
2819  count = img.numColors();
2820  data = (unsigned int *)img.colorTable();
2821  }
2822  for(i=0; i < count; ++i)
2823  data[i] = intensityValue(data[i]) < threshold ? TQColor(TQt::black).rgb() : TQColor(TQt::white).rgb();
2824 }
2825 
2826 void KImageEffect::hull(const int x_offset, const int y_offset,
2827  const int polarity, const int columns,
2828  const int rows,
2829  unsigned int *f, unsigned int *g)
2830 {
2831  int x, y;
2832 
2833  unsigned int *p, *q, *r, *s;
2834  unsigned int v;
2835  if(f == NULL || g == NULL)
2836  return;
2837  p=f+(columns+2);
2838  q=g+(columns+2);
2839  r=p+(y_offset*(columns+2)+x_offset);
2840  for (y=0; y < rows; y++){
2841  p++;
2842  q++;
2843  r++;
2844  if(polarity > 0)
2845  for (x=0; x < columns; x++){
2846  v=(*p);
2847  if (*r > v)
2848  v++;
2849  *q=v;
2850  p++;
2851  q++;
2852  r++;
2853  }
2854  else
2855  for(x=0; x < columns; x++){
2856  v=(*p);
2857  if (v > (unsigned int) (*r+1))
2858  v--;
2859  *q=v;
2860  p++;
2861  q++;
2862  r++;
2863  }
2864  p++;
2865  q++;
2866  r++;
2867  }
2868  p=f+(columns+2);
2869  q=g+(columns+2);
2870  r=q+(y_offset*(columns+2)+x_offset);
2871  s=q-(y_offset*(columns+2)+x_offset);
2872  for(y=0; y < rows; y++){
2873  p++;
2874  q++;
2875  r++;
2876  s++;
2877  if(polarity > 0)
2878  for(x=0; x < (int) columns; x++){
2879  v=(*q);
2880  if (((unsigned int) (*s+1) > v) && (*r > v))
2881  v++;
2882  *p=v;
2883  p++;
2884  q++;
2885  r++;
2886  s++;
2887  }
2888  else
2889  for (x=0; x < columns; x++){
2890  v=(*q);
2891  if (((unsigned int) (*s+1) < v) && (*r < v))
2892  v--;
2893  *p=v;
2894  p++;
2895  q++;
2896  r++;
2897  s++;
2898  }
2899  p++;
2900  q++;
2901  r++;
2902  s++;
2903  }
2904 }
2905 
2906 TQImage KImageEffect::despeckle(TQImage &src)
2907 {
2908  int i, j, x, y;
2909  unsigned int *blue_channel, *red_channel, *green_channel, *buffer,
2910  *alpha_channel;
2911  int packets;
2912  static const int
2913  X[4]= {0, 1, 1,-1},
2914  Y[4]= {1, 0, 1, 1};
2915 
2916  unsigned int *destData;
2917  TQImage dest(src.width(), src.height(), 32);
2918 
2919  packets = (src.width()+2)*(src.height()+2);
2920  red_channel = (unsigned int *)calloc(packets, sizeof(unsigned int));
2921  green_channel = (unsigned int *)calloc(packets, sizeof(unsigned int));
2922  blue_channel = (unsigned int *)calloc(packets, sizeof(unsigned int));
2923  alpha_channel = (unsigned int *)calloc(packets, sizeof(unsigned int));
2924  buffer = (unsigned int *)calloc(packets, sizeof(unsigned int));
2925  if(!red_channel || ! green_channel || ! blue_channel || ! alpha_channel ||
2926  !buffer){
2927  free(red_channel);
2928  free(green_channel);
2929  free(blue_channel);
2930  free(alpha_channel);
2931  free(buffer);
2932  return(src);
2933  }
2934 
2935  // copy image pixels to color component buffers
2936  j = src.width()+2;
2937  if(src.depth() > 8){ // DirectClass source image
2938  unsigned int *srcData;
2939  for(y=0; y < src.height(); ++y){
2940  srcData = (unsigned int *)src.scanLine(y);
2941  ++j;
2942  for(x=0; x < src.width(); ++x){
2943  red_channel[j] = tqRed(srcData[x]);
2944  green_channel[j] = tqGreen(srcData[x]);
2945  blue_channel[j] = tqBlue(srcData[x]);
2946  alpha_channel[j] = tqAlpha(srcData[x]);
2947  ++j;
2948  }
2949  ++j;
2950  }
2951  }
2952  else{ // PsudeoClass source image
2953  unsigned char *srcData;
2954  unsigned int *cTable = src.colorTable();
2955  unsigned int pixel;
2956  for(y=0; y < src.height(); ++y){
2957  srcData = (unsigned char *)src.scanLine(y);
2958  ++j;
2959  for(x=0; x < src.width(); ++x){
2960  pixel = *(cTable+srcData[x]);
2961  red_channel[j] = tqRed(pixel);
2962  green_channel[j] = tqGreen(pixel);
2963  blue_channel[j] = tqBlue(pixel);
2964  alpha_channel[j] = tqAlpha(pixel);
2965  ++j;
2966  }
2967  ++j;
2968  }
2969  }
2970  // reduce speckle in red channel
2971  for(i=0; i < 4; i++){
2972  hull(X[i],Y[i],1,src.width(),src.height(),red_channel,buffer);
2973  hull(-X[i],-Y[i],1,src.width(),src.height(),red_channel,buffer);
2974  hull(-X[i],-Y[i],-1,src.width(),src.height(),red_channel,buffer);
2975  hull(X[i],Y[i],-1,src.width(),src.height(),red_channel,buffer);
2976  }
2977  // reduce speckle in green channel
2978  for (i=0; i < packets; i++)
2979  buffer[i]=0;
2980  for (i=0; i < 4; i++){
2981  hull(X[i],Y[i],1,src.width(),src.height(),green_channel,buffer);
2982  hull(-X[i],-Y[i],1,src.width(),src.height(),green_channel,buffer);
2983  hull(-X[i],-Y[i],-1,src.width(),src.height(),green_channel,buffer);
2984  hull(X[i],Y[i],-1,src.width(),src.height(),green_channel,buffer);
2985  }
2986  // reduce speckle in blue channel
2987  for (i=0; i < packets; i++)
2988  buffer[i]=0;
2989  for (i=0; i < 4; i++){
2990  hull(X[i],Y[i],1,src.width(),src.height(),blue_channel,buffer);
2991  hull(-X[i],-Y[i],1,src.width(),src.height(),blue_channel,buffer);
2992  hull(-X[i],-Y[i],-1,src.width(),src.height(),blue_channel,buffer);
2993  hull(X[i],Y[i],-1,src.width(),src.height(),blue_channel,buffer);
2994  }
2995  // copy color component buffers to despeckled image
2996  j = dest.width()+2;
2997  for(y=0; y < dest.height(); ++y)
2998  {
2999  destData = (unsigned int *)dest.scanLine(y);
3000  ++j;
3001  for (x=0; x < dest.width(); ++x)
3002  {
3003  destData[x] = tqRgba(red_channel[j], green_channel[j],
3004  blue_channel[j], alpha_channel[j]);
3005  ++j;
3006  }
3007  ++j;
3008  }
3009  free(buffer);
3010  free(red_channel);
3011  free(green_channel);
3012  free(blue_channel);
3013  free(alpha_channel);
3014  return(dest);
3015 }
3016 
3017 unsigned int KImageEffect::generateNoise(unsigned int pixel,
3018  NoiseType noise_type)
3019 {
3020 #define NoiseEpsilon 1.0e-5
3021 #define NoiseMask 0x7fff
3022 #define SigmaUniform 4.0
3023 #define SigmaGaussian 4.0
3024 #define SigmaImpulse 0.10
3025 #define SigmaLaplacian 10.0
3026 #define SigmaMultiplicativeGaussian 0.5
3027 #define SigmaPoisson 0.05
3028 #define TauGaussian 20.0
3029 
3030  double alpha, beta, sigma, value;
3031  alpha=(double) (rand() & NoiseMask)/NoiseMask;
3032  if (alpha == 0.0)
3033  alpha=1.0;
3034  switch(noise_type){
3035  case UniformNoise:
3036  default:
3037  {
3038  value=(double) pixel+SigmaUniform*(alpha-0.5);
3039  break;
3040  }
3041  case GaussianNoise:
3042  {
3043  double tau;
3044 
3045  beta=(double) (rand() & NoiseMask)/NoiseMask;
3046  sigma=sqrt(-2.0*log(alpha))*cos(2.0*M_PI*beta);
3047  tau=sqrt(-2.0*log(alpha))*sin(2.0*M_PI*beta);
3048  value=(double) pixel+
3049  (sqrt((double) pixel)*SigmaGaussian*sigma)+(TauGaussian*tau);
3050  break;
3051  }
3052  case MultiplicativeGaussianNoise:
3053  {
3054  if (alpha <= NoiseEpsilon)
3055  sigma=MaxRGB;
3056  else
3057  sigma=sqrt(-2.0*log(alpha));
3058  beta=(rand() & NoiseMask)/NoiseMask;
3059  value=(double) pixel+
3060  pixel*SigmaMultiplicativeGaussian*sigma*cos(2.0*M_PI*beta);
3061  break;
3062  }
3063  case ImpulseNoise:
3064  {
3065  if (alpha < (SigmaImpulse/2.0))
3066  value=0;
3067  else
3068  if (alpha >= (1.0-(SigmaImpulse/2.0)))
3069  value=MaxRGB;
3070  else
3071  value=pixel;
3072  break;
3073  }
3074  case LaplacianNoise:
3075  {
3076  if (alpha <= 0.5)
3077  {
3078  if (alpha <= NoiseEpsilon)
3079  value=(double) pixel-MaxRGB;
3080  else
3081  value=(double) pixel+SigmaLaplacian*log(2.0*alpha);
3082  break;
3083  }
3084  beta=1.0-alpha;
3085  if (beta <= (0.5*NoiseEpsilon))
3086  value=(double) pixel+MaxRGB;
3087  else
3088  value=(double) pixel-SigmaLaplacian*log(2.0*beta);
3089  break;
3090  }
3091  case PoissonNoise:
3092  {
3093  int
3094  i;
3095 
3096  for (i=0; alpha > exp(-SigmaPoisson*pixel); i++)
3097  {
3098  beta=(double) (rand() & NoiseMask)/NoiseMask;
3099  alpha=alpha*beta;
3100  }
3101  value=i/SigmaPoisson;
3102  break;
3103  }
3104  }
3105  if(value < 0.0)
3106  return(0);
3107  if(value > MaxRGB)
3108  return(MaxRGB);
3109  return((unsigned int) (value+0.5));
3110 }
3111 
3112 TQImage KImageEffect::addNoise(TQImage &src, NoiseType noise_type)
3113 {
3114  int x, y;
3115  TQImage dest(src.width(), src.height(), 32);
3116  unsigned int *destData;
3117 
3118  if(src.depth() > 8){ // DirectClass source image
3119  unsigned int *srcData;
3120  for(y=0; y < src.height(); ++y){
3121  srcData = (unsigned int *)src.scanLine(y);
3122  destData = (unsigned int *)dest.scanLine(y);
3123  for(x=0; x < src.width(); ++x){
3124  destData[x] = tqRgba(generateNoise(tqRed(srcData[x]), noise_type),
3125  generateNoise(tqGreen(srcData[x]), noise_type),
3126  generateNoise(tqBlue(srcData[x]), noise_type),
3127  tqAlpha(srcData[x]));
3128  }
3129  }
3130  }
3131  else{ // PsudeoClass source image
3132  unsigned char *srcData;
3133  unsigned int *cTable = src.colorTable();
3134  unsigned int pixel;
3135  for(y=0; y < src.height(); ++y){
3136  srcData = (unsigned char *)src.scanLine(y);
3137  destData = (unsigned int *)dest.scanLine(y);
3138  for(x=0; x < src.width(); ++x){
3139  pixel = *(cTable+srcData[x]);
3140  destData[x] = tqRgba(generateNoise(tqRed(pixel), noise_type),
3141  generateNoise(tqGreen(pixel), noise_type),
3142  generateNoise(tqBlue(pixel), noise_type),
3143  tqAlpha(pixel));
3144  }
3145  }
3146 
3147  }
3148  return(dest);
3149 }
3150 
3151 unsigned int KImageEffect::interpolateColor(TQImage *image, double x_offset,
3152  double y_offset,
3153  unsigned int background)
3154 {
3155  double alpha, beta;
3156  unsigned int p, q, r, s;
3157  int x, y;
3158 
3159  x = (int)x_offset;
3160  y = (int)y_offset;
3161  if((x < -1) || (x >= image->width()) || (y < -1) || (y >= image->height()))
3162  return(background);
3163  if(image->depth() > 8){
3164  if((x >= 0) && (y >= 0) && (x < (image->width()-1)) && (y < (image->height()-1))) {
3165  unsigned int *t = (unsigned int *)image->scanLine(y);
3166  p = t[x];
3167  q = t[x+1];
3168  r = t[x+image->width()];
3169  s = t[x+image->width()+1];
3170  }
3171  else{
3172  unsigned int *t = (unsigned int *)image->scanLine(y);
3173  p = background;
3174  if((x >= 0) && (y >= 0)){
3175  p = t[x];
3176  }
3177  q = background;
3178  if(((x+1) < image->width()) && (y >= 0)){
3179  q = t[x+1];
3180  }
3181  r = background;
3182  if((x >= 0) && ((y+1) < image->height())){
3183  t = (unsigned int *)image->scanLine(y+1);
3184  r = t[x+image->width()];
3185  }
3186  s = background;
3187  if(((x+1) < image->width()) && ((y+1) < image->height())){
3188  t = (unsigned int *)image->scanLine(y+1);
3189  s = t[x+image->width()+1];
3190  }
3191 
3192  }
3193  }
3194  else{
3195  unsigned int *colorTable = (unsigned int *)image->colorTable();
3196  if((x >= 0) && (y >= 0) && (x < (image->width()-1)) && (y < (image->height()-1))) {
3197  unsigned char *t;
3198  t = (unsigned char *)image->scanLine(y);
3199  p = *(colorTable+t[x]);
3200  q = *(colorTable+t[x+1]);
3201  t = (unsigned char *)image->scanLine(y+1);
3202  r = *(colorTable+t[x]);
3203  s = *(colorTable+t[x+1]);
3204  }
3205  else{
3206  unsigned char *t;
3207  p = background;
3208  if((x >= 0) && (y >= 0)){
3209  t = (unsigned char *)image->scanLine(y);
3210  p = *(colorTable+t[x]);
3211  }
3212  q = background;
3213  if(((x+1) < image->width()) && (y >= 0)){
3214  t = (unsigned char *)image->scanLine(y);
3215  q = *(colorTable+t[x+1]);
3216  }
3217  r = background;
3218  if((x >= 0) && ((y+1) < image->height())){
3219  t = (unsigned char *)image->scanLine(y+1);
3220  r = *(colorTable+t[x]);
3221  }
3222  s = background;
3223  if(((x+1) < image->width()) && ((y+1) < image->height())){
3224  t = (unsigned char *)image->scanLine(y+1);
3225  s = *(colorTable+t[x+1]);
3226  }
3227 
3228  }
3229 
3230  }
3231  x_offset -= floor(x_offset);
3232  y_offset -= floor(y_offset);
3233  alpha = 1.0-x_offset;
3234  beta = 1.0-y_offset;
3235 
3236  return(tqRgba((unsigned char)(beta*(alpha*tqRed(p)+x_offset*tqRed(q))+y_offset*(alpha*tqRed(r)+x_offset*tqRed(s))),
3237  (unsigned char)(beta*(alpha*tqGreen(p)+x_offset*tqGreen(q))+y_offset*(alpha*tqGreen(r)+x_offset*tqGreen(s))),
3238  (unsigned char)(beta*(alpha*tqBlue(p)+x_offset*tqBlue(q))+y_offset*(alpha*tqBlue(r)+x_offset*tqBlue(s))),
3239  (unsigned char)(beta*(alpha*tqAlpha(p)+x_offset*tqAlpha(q))+y_offset*(alpha*tqAlpha(r)+x_offset*tqAlpha(s)))));
3240 }
3241 
3242 TQImage KImageEffect::implode(TQImage &src, double factor,
3243  unsigned int background)
3244 {
3245  double amount, distance, radius;
3246  double x_center, x_distance, x_scale;
3247  double y_center, y_distance, y_scale;
3248  unsigned int *destData;
3249  int x, y;
3250 
3251  TQImage dest(src.width(), src.height(), 32);
3252 
3253  // compute scaling factor
3254  x_scale = 1.0;
3255  y_scale = 1.0;
3256  x_center = (double)0.5*src.width();
3257  y_center = (double)0.5*src.height();
3258  radius=x_center;
3259  if(src.width() > src.height())
3260  y_scale = (double)src.width()/src.height();
3261  else if(src.width() < src.height()){
3262  x_scale = (double) src.height()/src.width();
3263  radius = y_center;
3264  }
3265  amount=factor/10.0;
3266  if(amount >= 0)
3267  amount/=10.0;
3268  if(src.depth() > 8){ // DirectClass source image
3269  unsigned int *srcData;
3270  for(y=0; y < src.height(); ++y){
3271  srcData = (unsigned int *)src.scanLine(y);
3272  destData = (unsigned int *)dest.scanLine(y);
3273  y_distance=y_scale*(y-y_center);
3274  for(x=0; x < src.width(); ++x){
3275  destData[x] = srcData[x];
3276  x_distance = x_scale*(x-x_center);
3277  distance= x_distance*x_distance+y_distance*y_distance;
3278  if(distance < (radius*radius)){
3279  double factor;
3280  // Implode the pixel.
3281  factor=1.0;
3282  if(distance > 0.0)
3283  factor=
3284  pow(sin(0.5000000000000001*M_PI*sqrt(distance)/radius),-amount);
3285  destData[x] = interpolateColor(&src, factor*x_distance/x_scale+x_center,
3286  factor*y_distance/y_scale+y_center,
3287  background);
3288  }
3289  }
3290  }
3291  }
3292  else{ // PsudeoClass source image
3293  unsigned char *srcData;
3294  unsigned char idx;
3295  unsigned int *cTable = src.colorTable();
3296  for(y=0; y < src.height(); ++y){
3297  srcData = (unsigned char *)src.scanLine(y);
3298  destData = (unsigned int *)dest.scanLine(y);
3299  y_distance=y_scale*(y-y_center);
3300  for(x=0; x < src.width(); ++x){
3301  idx = srcData[x];
3302  destData[x] = cTable[idx];
3303  x_distance = x_scale*(x-x_center);
3304  distance= x_distance*x_distance+y_distance*y_distance;
3305  if(distance < (radius*radius)){
3306  double factor;
3307  // Implode the pixel.
3308  factor=1.0;
3309  if(distance > 0.0)
3310  factor=
3311  pow(sin(0.5000000000000001*M_PI*sqrt(distance)/radius),-amount);
3312  destData[x] = interpolateColor(&src, factor*x_distance/x_scale+x_center,
3313  factor*y_distance/y_scale+y_center,
3314  background);
3315  }
3316  }
3317  }
3318 
3319  }
3320  return(dest);
3321 }
3322 
3323 TQImage KImageEffect::rotate(TQImage &img, RotateDirection r)
3324 {
3325  TQImage dest;
3326  int x, y;
3327  if(img.depth() > 8){
3328  unsigned int *srcData, *destData;
3329  switch(r){
3330  case Rotate90:
3331  dest.create(img.height(), img.width(), img.depth());
3332  for(y=0; y < img.height(); ++y){
3333  srcData = (unsigned int *)img.scanLine(y);
3334  for(x=0; x < img.width(); ++x){
3335  destData = (unsigned int *)dest.scanLine(x);
3336  destData[img.height()-y-1] = srcData[x];
3337  }
3338  }
3339  break;
3340  case Rotate180:
3341  dest.create(img.width(), img.height(), img.depth());
3342  for(y=0; y < img.height(); ++y){
3343  srcData = (unsigned int *)img.scanLine(y);
3344  destData = (unsigned int *)dest.scanLine(img.height()-y-1);
3345  for(x=0; x < img.width(); ++x)
3346  destData[img.width()-x-1] = srcData[x];
3347  }
3348  break;
3349  case Rotate270:
3350  dest.create(img.height(), img.width(), img.depth());
3351  for(y=0; y < img.height(); ++y){
3352  srcData = (unsigned int *)img.scanLine(y);
3353  for(x=0; x < img.width(); ++x){
3354  destData = (unsigned int *)dest.scanLine(img.width()-x-1);
3355  destData[y] = srcData[x];
3356  }
3357  }
3358  break;
3359  default:
3360  dest = img;
3361  break;
3362  }
3363  }
3364  else{
3365  unsigned char *srcData, *destData;
3366  unsigned int *srcTable, *destTable;
3367  switch(r){
3368  case Rotate90:
3369  dest.create(img.height(), img.width(), img.depth());
3370  dest.setNumColors(img.numColors());
3371  srcTable = (unsigned int *)img.colorTable();
3372  destTable = (unsigned int *)dest.colorTable();
3373  for(x=0; x < img.numColors(); ++x)
3374  destTable[x] = srcTable[x];
3375  for(y=0; y < img.height(); ++y){
3376  srcData = (unsigned char *)img.scanLine(y);
3377  for(x=0; x < img.width(); ++x){
3378  destData = (unsigned char *)dest.scanLine(x);
3379  destData[img.height()-y-1] = srcData[x];
3380  }
3381  }
3382  break;
3383  case Rotate180:
3384  dest.create(img.width(), img.height(), img.depth());
3385  dest.setNumColors(img.numColors());
3386  srcTable = (unsigned int *)img.colorTable();
3387  destTable = (unsigned int *)dest.colorTable();
3388  for(x=0; x < img.numColors(); ++x)
3389  destTable[x] = srcTable[x];
3390  for(y=0; y < img.height(); ++y){
3391  srcData = (unsigned char *)img.scanLine(y);
3392  destData = (unsigned char *)dest.scanLine(img.height()-y-1);
3393  for(x=0; x < img.width(); ++x)
3394  destData[img.width()-x-1] = srcData[x];
3395  }
3396  break;
3397  case Rotate270:
3398  dest.create(img.height(), img.width(), img.depth());
3399  dest.setNumColors(img.numColors());
3400  srcTable = (unsigned int *)img.colorTable();
3401  destTable = (unsigned int *)dest.colorTable();
3402  for(x=0; x < img.numColors(); ++x)
3403  destTable[x] = srcTable[x];
3404  for(y=0; y < img.height(); ++y){
3405  srcData = (unsigned char *)img.scanLine(y);
3406  for(x=0; x < img.width(); ++x){
3407  destData = (unsigned char *)dest.scanLine(img.width()-x-1);
3408  destData[y] = srcData[x];
3409  }
3410  }
3411  break;
3412  default:
3413  dest = img;
3414  break;
3415  }
3416 
3417  }
3418  return(dest);
3419 }
3420 
3421 void KImageEffect::solarize(TQImage &img, double factor)
3422 {
3423  int i, count;
3424  int threshold;
3425  unsigned int *data;
3426 
3427  threshold = (int)(factor*(MaxRGB+1)/100.0);
3428  if(img.depth() < 32){
3429  data = (unsigned int *)img.colorTable();
3430  count = img.numColors();
3431  }
3432  else{
3433  data = (unsigned int *)img.bits();
3434  count = img.width()*img.height();
3435  }
3436  for(i=0; i < count; ++i){
3437  data[i] = tqRgba(tqRed(data[i]) > threshold ? MaxRGB-tqRed(data[i]) : tqRed(data[i]),
3438  tqGreen(data[i]) > threshold ? MaxRGB-tqGreen(data[i]) : tqGreen(data[i]),
3439  tqBlue(data[i]) > threshold ? MaxRGB-tqBlue(data[i]) : tqBlue(data[i]),
3440  tqAlpha(data[i]));
3441  }
3442 }
3443 
3444 TQImage KImageEffect::spread(TQImage &src, unsigned int amount)
3445 {
3446  int quantum, x, y;
3447  int x_distance, y_distance;
3448  if(src.width() < 3 || src.height() < 3)
3449  return(src);
3450  TQImage dest(src);
3451  dest.detach();
3452  quantum=(amount+1) >> 1;
3453  if(src.depth() > 8){ // DirectClass source image
3454  unsigned int *p, *q;
3455  for(y=0; y < src.height(); y++){
3456  q = (unsigned int *)dest.scanLine(y);
3457  for(x=0; x < src.width(); x++){
3458  x_distance = x + ((rand() & (amount+1))-quantum);
3459  y_distance = y + ((rand() & (amount+1))-quantum);
3460  x_distance = TQMIN(x_distance, src.width()-1);
3461  y_distance = TQMIN(y_distance, src.height()-1);
3462  if(x_distance < 0)
3463  x_distance = 0;
3464  if(y_distance < 0)
3465  y_distance = 0;
3466  p = (unsigned int *)src.scanLine(y_distance);
3467  p += x_distance;
3468  *q++=(*p);
3469  }
3470  }
3471  }
3472  else{ // PsudeoClass source image
3473  // just do colortable values
3474  unsigned char *p, *q;
3475  for(y=0; y < src.height(); y++){
3476  q = (unsigned char *)dest.scanLine(y);
3477  for(x=0; x < src.width(); x++){
3478  x_distance = x + ((rand() & (amount+1))-quantum);
3479  y_distance = y + ((rand() & (amount+1))-quantum);
3480  x_distance = TQMIN(x_distance, src.width()-1);
3481  y_distance = TQMIN(y_distance, src.height()-1);
3482  if(x_distance < 0)
3483  x_distance = 0;
3484  if(y_distance < 0)
3485  y_distance = 0;
3486  p = (unsigned char *)src.scanLine(y_distance);
3487  p += x_distance;
3488  *q++=(*p);
3489  }
3490  }
3491  }
3492  return(dest);
3493 }
3494 
3495 TQImage KImageEffect::swirl(TQImage &src, double degrees,
3496  unsigned int background)
3497 {
3498  double cosine, distance, factor, radius, sine, x_center, x_distance,
3499  x_scale, y_center, y_distance, y_scale;
3500  int x, y;
3501  unsigned int *q;
3502  TQImage dest(src.width(), src.height(), 32);
3503 
3504  // compute scaling factor
3505  x_center = src.width()/2.0;
3506  y_center = src.height()/2.0;
3507  radius = TQMAX(x_center,y_center);
3508  x_scale=1.0;
3509  y_scale=1.0;
3510  if(src.width() > src.height())
3511  y_scale=(double)src.width()/src.height();
3512  else if(src.width() < src.height())
3513  x_scale=(double)src.height()/src.width();
3514  degrees=DegreesToRadians(degrees);
3515  // swirl each row
3516  if(src.depth() > 8){ // DirectClass source image
3517  unsigned int *p;
3518  for(y=0; y < src.height(); y++){
3519  p = (unsigned int *)src.scanLine(y);
3520  q = (unsigned int *)dest.scanLine(y);
3521  y_distance = y_scale*(y-y_center);
3522  for(x=0; x < src.width(); x++){
3523  // determine if the pixel is within an ellipse
3524  *q=(*p);
3525  x_distance = x_scale*(x-x_center);
3526  distance = x_distance*x_distance+y_distance*y_distance;
3527  if (distance < (radius*radius)){
3528  // swirl
3529  factor = 1.0-sqrt(distance)/radius;
3530  sine = sin(degrees*factor*factor);
3531  cosine = cos(degrees*factor*factor);
3532  *q = interpolateColor(&src,
3533  (cosine*x_distance-sine*y_distance)/x_scale+x_center,
3534  (sine*x_distance+cosine*y_distance)/y_scale+y_center,
3535  background);
3536  }
3537  p++;
3538  q++;
3539  }
3540  }
3541  }
3542  else{ // PsudeoClass source image
3543  unsigned char *p;
3544  unsigned int *cTable = (unsigned int *)src.colorTable();
3545  for(y=0; y < src.height(); y++){
3546  p = (unsigned char *)src.scanLine(y);
3547  q = (unsigned int *)dest.scanLine(y);
3548  y_distance = y_scale*(y-y_center);
3549  for(x=0; x < src.width(); x++){
3550  // determine if the pixel is within an ellipse
3551  *q = *(cTable+(*p));
3552  x_distance = x_scale*(x-x_center);
3553  distance = x_distance*x_distance+y_distance*y_distance;
3554  if (distance < (radius*radius)){
3555  // swirl
3556  factor = 1.0-sqrt(distance)/radius;
3557  sine = sin(degrees*factor*factor);
3558  cosine = cos(degrees*factor*factor);
3559  *q = interpolateColor(&src,
3560  (cosine*x_distance-sine*y_distance)/x_scale+x_center,
3561  (sine*x_distance+cosine*y_distance)/y_scale+y_center,
3562  background);
3563  }
3564  p++;
3565  q++;
3566  }
3567  }
3568 
3569  }
3570  return(dest);
3571 }
3572 
3573 TQImage KImageEffect::wave(TQImage &src, double amplitude, double wavelength,
3574  unsigned int background)
3575 {
3576  double *sine_map;
3577  int x, y;
3578  unsigned int *q;
3579 
3580  TQImage dest(src.width(), src.height() + (int)(2*fabs(amplitude)), 32);
3581  // allocate sine map
3582  sine_map = (double *)malloc(dest.width()*sizeof(double));
3583  if(!sine_map)
3584  return(src);
3585  for(x=0; x < dest.width(); ++x)
3586  sine_map[x]=fabs(amplitude)+amplitude*sin((2*M_PI*x)/wavelength);
3587  // wave image
3588  for(y=0; y < dest.height(); ++y){
3589  q = (unsigned int *)dest.scanLine(y);
3590  for (x=0; x < dest.width(); x++){
3591  *q=interpolateColor(&src, x, (int)(y-sine_map[x]), background);
3592  ++q;
3593  }
3594  }
3595  free(sine_map);
3596  return(dest);
3597 }
3598 
3599 //
3600 // The following methods work by computing a value from neighboring pixels
3601 // (mosfet 05/26/03)
3602 //
3603 
3604 // New algorithms based on ImageMagick 5.5.6 (05/26/03)
3605 
3606 TQImage KImageEffect::oilPaint(TQImage &src, int /*radius*/)
3607 {
3608  /* binary compat method - remove me when possible! */
3609  return(oilPaintConvolve(src, 0));
3610 }
3611 
3612 TQImage KImageEffect::oilPaintConvolve(TQImage &src, double radius)
3613 {
3614  unsigned long count /*,*histogram*/;
3615  unsigned long histogram[256];
3616  unsigned int k;
3617  int width;
3618  int x, y, mx, my, sx, sy;
3619  int mcx, mcy;
3620  unsigned int *s=0, *q;
3621 
3622  if(src.depth() < 32)
3623  src.convertDepth(32);
3624  TQImage dest(src);
3625  dest.detach();
3626 
3627  width = getOptimalKernelWidth(radius, 0.5);
3628  if(src.width() < width){
3629  tqWarning("KImageEffect::oilPaintConvolve(): Image is smaller than radius!");
3630  return(dest);
3631  }
3632  /*
3633  histogram = (unsigned long *)malloc(256*sizeof(unsigned long));
3634  if(!histogram){
3635  tqWarning("KImageEffect::oilPaintColvolve(): Unable to allocate memory!");
3636  return(dest);
3637  }
3638  */
3639  unsigned int **jumpTable = (unsigned int **)src.jumpTable();
3640  for(y=0; y < dest.height(); ++y){
3641  sy = y-(width/2);
3642  q = (unsigned int *)dest.scanLine(y);
3643  for(x=0; x < dest.width(); ++x){
3644  count = 0;
3645  memset(histogram, 0, 256*sizeof(unsigned long));
3646  //memset(histogram, 0, 256);
3647  sy = y-(width/2);
3648  for(mcy=0; mcy < width; ++mcy, ++sy){
3649  my = sy < 0 ? 0 : sy > src.height()-1 ?
3650  src.height()-1 : sy;
3651  sx = x+(-width/2);
3652  for(mcx=0; mcx < width; ++mcx, ++sx){
3653  mx = sx < 0 ? 0 : sx > src.width()-1 ?
3654  src.width()-1 : sx;
3655 
3656  k = intensityValue(jumpTable[my][mx]);
3657  if(k > 255){
3658  tqWarning("KImageEffect::oilPaintConvolve(): k is %d",
3659  k);
3660  k = 255;
3661  }
3662  histogram[k]++;
3663  if(histogram[k] > count){
3664  count = histogram[k];
3665  s = jumpTable[my]+mx;
3666  }
3667  }
3668  }
3669  if (s)
3670  *q++ = (*s);
3671  }
3672  }
3673  /* liberateMemory((histogram); */
3674  return(dest);
3675 }
3676 
3677 TQImage KImageEffect::charcoal(TQImage &src, double /*factor*/)
3678 {
3679  /* binary compat method - remove me when possible! */
3680  return(charcoal(src, 0, 1));
3681 }
3682 
3683 TQImage KImageEffect::charcoal(TQImage &src, double radius, double sigma)
3684 {
3685  TQImage img(edge(src, radius));
3686  img = blur(img, radius, sigma);
3687  normalize(img);
3688  img.invertPixels(false);
3689  KImageEffect::toGray(img);
3690  return(img);
3691 }
3692 
3693 void KImageEffect::normalize(TQImage &image)
3694 {
3695  struct double_packet high, low, intensity, *histogram;
3696  struct short_packet *normalize_map;
3697  TQ_INT64 number_pixels;
3698  int x, y;
3699  unsigned int *p, *q;
3700  long i;
3701  unsigned long threshold_intensity;
3702  unsigned char r, g, b, a;
3703 
3704  if(image.depth() < 32) // result will always be 32bpp
3705  image = image.convertDepth(32);
3706 
3707  histogram = (struct double_packet *)
3708  malloc(256*sizeof(struct double_packet));
3709  normalize_map = (struct short_packet *)
3710  malloc(256*sizeof(struct short_packet));
3711 
3712  if(!histogram || !normalize_map){
3713  if(histogram)
3714  liberateMemory(&histogram);
3715  if(normalize_map)
3716  liberateMemory(&normalize_map);
3717  tqWarning("KImageEffect::normalize(): Unable to allocate memory!");
3718  return;
3719  }
3720 
3721  /*
3722  Form histogram.
3723  */
3724  memset(histogram, 0, 256*sizeof(struct double_packet));
3725  for(y=0; y < image.height(); ++y){
3726  p = (unsigned int *)image.scanLine(y);
3727  for(x=0; x < image.width(); ++x){
3728  histogram[(unsigned char)(tqRed(*p))].red++;
3729  histogram[(unsigned char)(tqGreen(*p))].green++;
3730  histogram[(unsigned char)(tqBlue(*p))].blue++;
3731  histogram[(unsigned char)(tqAlpha(*p))].alpha++;
3732  p++;
3733  }
3734  }
3735 
3736  /*
3737  Find the histogram boundaries by locating the 0.1 percent levels.
3738  */
3739  number_pixels = (TQ_INT64)image.width()*image.height();
3740  threshold_intensity = number_pixels/1000;
3741 
3742  /* red */
3743  memset(&intensity, 0, sizeof(struct double_packet));
3744  memset(&high, 0, sizeof(struct double_packet));
3745  memset(&low, 0, sizeof(struct double_packet));
3746  for(high.red=255; high.red != 0; high.red--){
3747  intensity.red+=histogram[(unsigned char)high.red].red;
3748  if(intensity.red > threshold_intensity)
3749  break;
3750  }
3751  if(low.red == high.red){
3752  threshold_intensity = 0;
3753  memset(&intensity, 0, sizeof(struct double_packet));
3754  for(low.red=0; low.red < 255; low.red++){
3755  intensity.red+=histogram[(unsigned char)low.red].red;
3756  if(intensity.red > threshold_intensity)
3757  break;
3758  }
3759  memset(&intensity, 0, sizeof(struct double_packet));
3760  for(high.red=255; high.red != 0; high.red--){
3761  intensity.red+=histogram[(unsigned char)high.red].red;
3762  if(intensity.red > threshold_intensity)
3763  break;
3764  }
3765  }
3766 
3767  /* green */
3768  memset(&intensity, 0, sizeof(struct double_packet));
3769  for(high.green=255; high.green != 0; high.green--){
3770  intensity.green+=histogram[(unsigned char)high.green].green;
3771  if(intensity.green > threshold_intensity)
3772  break;
3773  }
3774  if(low.green == high.green){
3775  threshold_intensity = 0;
3776  memset(&intensity, 0, sizeof(struct double_packet));
3777  for(low.green=0; low.green < 255; low.green++){
3778  intensity.green+=histogram[(unsigned char)low.green].green;
3779  if(intensity.green > threshold_intensity)
3780  break;
3781  }
3782  memset(&intensity,0,sizeof(struct double_packet));
3783  for(high.green=255; high.green != 0; high.green--){
3784  intensity.green+=histogram[(unsigned char)high.green].green;
3785  if(intensity.green > threshold_intensity)
3786  break;
3787  }
3788  }
3789 
3790  /* blue */
3791  memset(&intensity, 0, sizeof(struct double_packet));
3792  for(high.blue=255; high.blue != 0; high.blue--){
3793  intensity.blue+=histogram[(unsigned char)high.blue].blue;
3794  if(intensity.blue > threshold_intensity)
3795  break;
3796  }
3797  if(low.blue == high.blue){
3798  threshold_intensity = 0;
3799  memset(&intensity, 0, sizeof(struct double_packet));
3800  for(low.blue=0; low.blue < 255; low.blue++){
3801  intensity.blue+=histogram[(unsigned char)low.blue].blue;
3802  if(intensity.blue > threshold_intensity)
3803  break;
3804  }
3805  memset(&intensity,0,sizeof(struct double_packet));
3806  for(high.blue=255; high.blue != 0; high.blue--){
3807  intensity.blue+=histogram[(unsigned char)high.blue].blue;
3808  if(intensity.blue > threshold_intensity)
3809  break;
3810  }
3811  }
3812 
3813  /* alpha */
3814  memset(&intensity, 0, sizeof(struct double_packet));
3815  for(high.alpha=255; high.alpha != 0; high.alpha--){
3816  intensity.alpha+=histogram[(unsigned char)high.alpha].alpha;
3817  if(intensity.alpha > threshold_intensity)
3818  break;
3819  }
3820  if(low.alpha == high.alpha){
3821  threshold_intensity = 0;
3822  memset(&intensity, 0, sizeof(struct double_packet));
3823  for(low.alpha=0; low.alpha < 255; low.alpha++){
3824  intensity.alpha+=histogram[(unsigned char)low.alpha].alpha;
3825  if(intensity.alpha > threshold_intensity)
3826  break;
3827  }
3828  memset(&intensity,0,sizeof(struct double_packet));
3829  for(high.alpha=255; high.alpha != 0; high.alpha--){
3830  intensity.alpha+=histogram[(unsigned char)high.alpha].alpha;
3831  if(intensity.alpha > threshold_intensity)
3832  break;
3833  }
3834  }
3835  liberateMemory(&histogram);
3836 
3837  /*
3838  Stretch the histogram to create the normalized image mapping.
3839  */
3840 
3841  // should the maxes be 65535?
3842  memset(normalize_map, 0 ,256*sizeof(struct short_packet));
3843  for(i=0; i <= (long) 255; i++){
3844  if(i < (long) low.red)
3845  normalize_map[i].red=0;
3846  else if (i > (long) high.red)
3847  normalize_map[i].red=65535;
3848  else if (low.red != high.red)
3849  normalize_map[i].red =
3850  (unsigned short)((65535*(i-low.red))/(high.red-low.red));
3851 
3852  if(i < (long) low.green)
3853  normalize_map[i].green=0;
3854  else if (i > (long) high.green)
3855  normalize_map[i].green=65535;
3856  else if (low.green != high.green)
3857  normalize_map[i].green =
3858  (unsigned short)((65535*(i-low.green))/(high.green-low.green));
3859 
3860  if(i < (long) low.blue)
3861  normalize_map[i].blue=0;
3862  else if (i > (long) high.blue)
3863  normalize_map[i].blue=65535;
3864  else if (low.blue != high.blue)
3865  normalize_map[i].blue =
3866  (unsigned short)((65535*(i-low.blue))/(high.blue-low.blue));
3867 
3868  if(i < (long) low.alpha)
3869  normalize_map[i].alpha=0;
3870  else if (i > (long) high.alpha)
3871  normalize_map[i].alpha=65535;
3872  else if (low.alpha != high.alpha)
3873  normalize_map[i].alpha =
3874  (unsigned short)((65535*(i-low.alpha))/(high.alpha-low.alpha));
3875 
3876  }
3877 
3878  for(y=0; y < image.height(); ++y){
3879  q = (unsigned int *)image.scanLine(y);
3880  for(x=0; x < image.width(); ++x){
3881  if(low.red != high.red)
3882  r = (normalize_map[(unsigned short)(tqRed(q[x]))].red)/257;
3883  else
3884  r = tqRed(q[x]);
3885  if(low.green != high.green)
3886  g = (normalize_map[(unsigned short)(tqGreen(q[x]))].green)/257;
3887  else
3888  g = tqGreen(q[x]);
3889  if(low.blue != high.blue)
3890  b = (normalize_map[(unsigned short)(tqBlue(q[x]))].blue)/257;
3891  else
3892  b = tqBlue(q[x]);
3893  if(low.alpha != high.alpha)
3894  a = (normalize_map[(unsigned short)(tqAlpha(q[x]))].alpha)/257;
3895  else
3896  a = tqAlpha(q[x]);
3897  q[x] = tqRgba(r, g, b, a);
3898  }
3899  }
3900  liberateMemory(&normalize_map);
3901 }
3902 
3903 void KImageEffect::equalize(TQImage &image)
3904 {
3905  struct double_packet high, low, intensity, *map, *histogram;
3906  struct short_packet *equalize_map;
3907  int x, y;
3908  unsigned int *p, *q;
3909  long i;
3910  unsigned char r, g, b, a;
3911 
3912  if(image.depth() < 32) // result will always be 32bpp
3913  image = image.convertDepth(32);
3914 
3915  histogram=(struct double_packet *) malloc(256*sizeof(struct double_packet));
3916  map=(struct double_packet *) malloc(256*sizeof(struct double_packet));
3917  equalize_map=(struct short_packet *)malloc(256*sizeof(struct short_packet));
3918  if(!histogram || !map || !equalize_map){
3919  if(histogram)
3920  liberateMemory(&histogram);
3921  if(map)
3922  liberateMemory(&map);
3923  if(equalize_map)
3924  liberateMemory(&equalize_map);
3925  tqWarning("KImageEffect::equalize(): Unable to allocate memory!");
3926  return;
3927  }
3928 
3929  /*
3930  Form histogram.
3931  */
3932  memset(histogram, 0, 256*sizeof(struct double_packet));
3933  for(y=0; y < image.height(); ++y){
3934  p = (unsigned int *)image.scanLine(y);
3935  for(x=0; x < image.width(); ++x){
3936  histogram[(unsigned char)(tqRed(*p))].red++;
3937  histogram[(unsigned char)(tqGreen(*p))].green++;
3938  histogram[(unsigned char)(tqBlue(*p))].blue++;
3939  histogram[(unsigned char)(tqAlpha(*p))].alpha++;
3940  p++;
3941  }
3942  }
3943  /*
3944  Integrate the histogram to get the equalization map.
3945  */
3946  memset(&intensity, 0 ,sizeof(struct double_packet));
3947  for(i=0; i <= 255; ++i){
3948  intensity.red += histogram[i].red;
3949  intensity.green += histogram[i].green;
3950  intensity.blue += histogram[i].blue;
3951  intensity.alpha += histogram[i].alpha;
3952  map[i]=intensity;
3953  }
3954  low=map[0];
3955  high=map[255];
3956  memset(equalize_map, 0, 256*sizeof(short_packet));
3957  for(i=0; i <= 255; ++i){
3958  if(high.red != low.red)
3959  equalize_map[i].red=(unsigned short)
3960  ((65535*(map[i].red-low.red))/(high.red-low.red));
3961  if(high.green != low.green)
3962  equalize_map[i].green=(unsigned short)
3963  ((65535*(map[i].green-low.green))/(high.green-low.green));
3964  if(high.blue != low.blue)
3965  equalize_map[i].blue=(unsigned short)
3966  ((65535*(map[i].blue-low.blue))/(high.blue-low.blue));
3967  if(high.alpha != low.alpha)
3968  equalize_map[i].alpha=(unsigned short)
3969  ((65535*(map[i].alpha-low.alpha))/(high.alpha-low.alpha));
3970  }
3971  liberateMemory(&histogram);
3972  liberateMemory(&map);
3973 
3974  /*
3975  Stretch the histogram.
3976  */
3977  for(y=0; y < image.height(); ++y){
3978  q = (unsigned int *)image.scanLine(y);
3979  for(x=0; x < image.width(); ++x){
3980  if(low.red != high.red)
3981  r = (equalize_map[(unsigned short)(tqRed(q[x]))].red/257);
3982  else
3983  r = tqRed(q[x]);
3984  if(low.green != high.green)
3985  g = (equalize_map[(unsigned short)(tqGreen(q[x]))].green/257);
3986  else
3987  g = tqGreen(q[x]);
3988  if(low.blue != high.blue)
3989  b = (equalize_map[(unsigned short)(tqBlue(q[x]))].blue/257);
3990  else
3991  b = tqBlue(q[x]);
3992  if(low.alpha != high.alpha)
3993  a = (equalize_map[(unsigned short)(tqAlpha(q[x]))].alpha/257);
3994  else
3995  a = tqAlpha(q[x]);
3996  q[x] = tqRgba(r, g, b, a);
3997  }
3998  }
3999  liberateMemory(&equalize_map);
4000 
4001 }
4002 
4003 TQImage KImageEffect::edge(TQImage &image, double radius)
4004 {
4005  double *kernel;
4006  int width;
4007  long i;
4008  TQImage dest;
4009 
4010  if(radius == 50.0){
4011  /* For binary compatability! Remove me when possible! This used to
4012  * take a different parameter, a factor, and this was the default
4013  * value */
4014  radius = 0.0;
4015  }
4016 
4017  width = getOptimalKernelWidth(radius, 0.5);
4018  if(image.width() < width || image.height() < width){
4019  tqWarning("KImageEffect::edge(): Image is smaller than radius!");
4020  return(dest);
4021  }
4022  kernel= (double *)malloc(width*width*sizeof(double));
4023  if(!kernel){
4024  tqWarning("KImageEffect::edge(): Unable to allocate memory!");
4025  return(dest);
4026  }
4027  for(i=0; i < (width*width); i++)
4028  kernel[i]=(-1.0);
4029  kernel[i/2]=width*width-1.0;
4030  convolveImage(&image, &dest, width, kernel);
4031  free(kernel);
4032  return(dest);
4033 }
4034 
4035 TQImage KImageEffect::emboss(TQImage &src)
4036 {
4037  /* binary compat method - remove me when possible! */
4038  return(emboss(src, 0, 1));
4039 }
4040 
4041 TQImage KImageEffect::emboss(TQImage &image, double radius, double sigma)
4042 {
4043  double alpha, *kernel;
4044  int j, width;
4045  long i, u, v;
4046  TQImage dest;
4047 
4048  if(sigma == 0.0){
4049  tqWarning("KImageEffect::emboss(): Zero sigma is not permitted!");
4050  return(dest);
4051  }
4052 
4053  width = getOptimalKernelWidth(radius, sigma);
4054  if(image.width() < width || image.height() < width){
4055  tqWarning("KImageEffect::emboss(): Image is smaller than radius!");
4056  return(dest);
4057  }
4058  kernel= (double *)malloc(width*width*sizeof(double));
4059  if(!kernel){
4060  tqWarning("KImageEffect::emboss(): Unable to allocate memory!");
4061  return(dest);
4062  }
4063  if(image.depth() < 32)
4064  image = image.convertDepth(32);
4065 
4066  i=0;
4067  j=width/2;
4068  for(v=(-width/2); v <= (width/2); v++){
4069  for(u=(-width/2); u <= (width/2); u++){
4070  alpha=exp(-((double) u*u+v*v)/(2.0*sigma*sigma));
4071  kernel[i]=((u < 0) || (v < 0) ? -8.0 : 8.0)*alpha/
4072  (2.0*MagickPI*sigma*sigma);
4073  if (u == j)
4074  kernel[i]=0.0;
4075  i++;
4076  }
4077  j--;
4078  }
4079  convolveImage(&image, &dest, width, kernel);
4080  liberateMemory(&kernel);
4081 
4082  equalize(dest);
4083  return(dest);
4084 }
4085 
4086 void KImageEffect::blurScanLine(double *kernel, int width,
4087  unsigned int *src, unsigned int *dest,
4088  int columns)
4089 {
4090  double *p;
4091  unsigned int *q;
4092  int x;
4093  long i;
4094  double red, green, blue, alpha;
4095  double scale = 0.0;
4096 
4097  if(width > columns){
4098  for(x=0; x < columns; ++x){
4099  scale = 0.0;
4100  red = blue = green = alpha = 0.0;
4101  p = kernel;
4102  q = src;
4103  for(i=0; i < columns; ++i){
4104  if((i >= (x-width/2)) && (i <= (x+width/2))){
4105  red += (*p)*(tqRed(*q)*257);
4106  green += (*p)*(tqGreen(*q)*257);
4107  blue += (*p)*(tqBlue(*q)*257);
4108  alpha += (*p)*(tqAlpha(*q)*257);
4109  }
4110  if(((i+width/2-x) >= 0) && ((i+width/2-x) < width))
4111  scale+=kernel[i+width/2-x];
4112  p++;
4113  q++;
4114  }
4115  scale = 1.0/scale;
4116  red = scale*(red+0.5);
4117  green = scale*(green+0.5);
4118  blue = scale*(blue+0.5);
4119  alpha = scale*(alpha+0.5);
4120 
4121  red = red < 0 ? 0 : red > 65535 ? 65535 : red;
4122  green = green < 0 ? 0 : green > 65535 ? 65535 : green;
4123  blue = blue < 0 ? 0 : blue > 65535 ? 65535 : blue;
4124  alpha = alpha < 0 ? 0 : alpha > 65535 ? 65535 : alpha;
4125 
4126  dest[x] = tqRgba((unsigned char)(red/257UL),
4127  (unsigned char)(green/257UL),
4128  (unsigned char)(blue/257UL),
4129  (unsigned char)(alpha/257UL));
4130  }
4131  return;
4132  }
4133 
4134  for(x=0; x < width/2; ++x){
4135  scale = 0.0;
4136  red = blue = green = alpha = 0.0;
4137  p = kernel+width/2-x;
4138  q = src;
4139  for(i=width/2-x; i < width; ++i){
4140  red += (*p)*(tqRed(*q)*257);
4141  green += (*p)*(tqGreen(*q)*257);
4142  blue += (*p)*(tqBlue(*q)*257);
4143  alpha += (*p)*(tqAlpha(*q)*257);
4144  scale += (*p);
4145  p++;
4146  q++;
4147  }
4148  scale=1.0/scale;
4149 
4150  red = scale*(red+0.5);
4151  green = scale*(green+0.5);
4152  blue = scale*(blue+0.5);
4153  alpha = scale*(alpha+0.5);
4154 
4155  red = red < 0 ? 0 : red > 65535 ? 65535 : red;
4156  green = green < 0 ? 0 : green > 65535 ? 65535 : green;
4157  blue = blue < 0 ? 0 : blue > 65535 ? 65535 : blue;
4158  alpha = alpha < 0 ? 0 : alpha > 65535 ? 65535 : alpha;
4159 
4160  dest[x] = tqRgba((unsigned char)(red/257UL),
4161  (unsigned char)(green/257UL),
4162  (unsigned char)(blue/257UL),
4163  (unsigned char)(alpha/257UL));
4164  }
4165 
4166  for(; x < columns-width/2; ++x){
4167  red = blue = green = alpha = 0.0;
4168  p = kernel;
4169  q = src+(x-width/2);
4170  for (i=0; i < (long) width; ++i){
4171  red += (*p)*(tqRed(*q)*257);
4172  green += (*p)*(tqGreen(*q)*257);
4173  blue += (*p)*(tqBlue(*q)*257);
4174  alpha += (*p)*(tqAlpha(*q)*257);
4175  p++;
4176  q++;
4177  }
4178  red = scale*(red+0.5);
4179  green = scale*(green+0.5);
4180  blue = scale*(blue+0.5);
4181  alpha = scale*(alpha+0.5);
4182 
4183  red = red < 0 ? 0 : red > 65535 ? 65535 : red;
4184  green = green < 0 ? 0 : green > 65535 ? 65535 : green;
4185  blue = blue < 0 ? 0 : blue > 65535 ? 65535 : blue;
4186  alpha = alpha < 0 ? 0 : alpha > 65535 ? 65535 : alpha;
4187 
4188  dest[x] = tqRgba((unsigned char)(red/257UL),
4189  (unsigned char)(green/257UL),
4190  (unsigned char)(blue/257UL),
4191  (unsigned char)(alpha/257UL));
4192  }
4193 
4194  for(; x < columns; ++x){
4195  red = blue = green = alpha = 0.0;
4196  scale=0;
4197  p = kernel;
4198  q = src+(x-width/2);
4199  for(i=0; i < columns-x+width/2; ++i){
4200  red += (*p)*(tqRed(*q)*257);
4201  green += (*p)*(tqGreen(*q)*257);
4202  blue += (*p)*(tqBlue(*q)*257);
4203  alpha += (*p)*(tqAlpha(*q)*257);
4204  scale += (*p);
4205  p++;
4206  q++;
4207  }
4208  scale=1.0/scale;
4209  red = scale*(red+0.5);
4210  green = scale*(green+0.5);
4211  blue = scale*(blue+0.5);
4212  alpha = scale*(alpha+0.5);
4213 
4214  red = red < 0 ? 0 : red > 65535 ? 65535 : red;
4215  green = green < 0 ? 0 : green > 65535 ? 65535 : green;
4216  blue = blue < 0 ? 0 : blue > 65535 ? 65535 : blue;
4217  alpha = alpha < 0 ? 0 : alpha > 65535 ? 65535 : alpha;
4218 
4219  dest[x] = tqRgba((unsigned char)(red/257UL),
4220  (unsigned char)(green/257UL),
4221  (unsigned char)(blue/257UL),
4222  (unsigned char)(alpha/257UL));
4223  }
4224 }
4225 
4226 int KImageEffect::getBlurKernel(int width, double sigma, double **kernel)
4227 {
4228 #define KernelRank 3
4229  double alpha, normalize;
4230  long i;
4231  int bias;
4232 
4233  assert(sigma != 0.0);
4234  if(width == 0)
4235  width = 3;
4236  *kernel=(double *)malloc(width*sizeof(double));
4237  if(*kernel == (double *)NULL)
4238  return(0);
4239  memset(*kernel, 0, width*sizeof(double));
4240  bias = KernelRank*width/2;
4241  for(i=(-bias); i <= bias; i++){
4242  alpha=exp(-((double) i*i)/(2.0*KernelRank*KernelRank*sigma*sigma));
4243  (*kernel)[(i+bias)/KernelRank]+=alpha/(MagickSQ2PI*sigma);
4244  }
4245  normalize=0;
4246  for(i=0; i < width; i++)
4247  normalize+=(*kernel)[i];
4248  for(i=0; i < width; i++)
4249  (*kernel)[i]/=normalize;
4250 
4251  return(width);
4252 }
4253 
4254 TQImage KImageEffect::blur(TQImage &src, double /*factor*/)
4255 {
4256  /* binary compat method - remove me when possible! */
4257  return(blur(src, 0, 1));
4258 }
4259 
4260 TQImage KImageEffect::blur(TQImage &src, double radius, double sigma)
4261 {
4262  double *kernel;
4263  TQImage dest;
4264  int width;
4265  int x, y;
4266  unsigned int *scanline, *temp;
4267  unsigned int *p, *q;
4268 
4269  if(sigma == 0.0){
4270  tqWarning("KImageEffect::blur(): Zero sigma is not permitted!");
4271  return(dest);
4272  }
4273  if(src.depth() < 32)
4274  src = src.convertDepth(32);
4275 
4276  kernel=(double *) NULL;
4277  if(radius > 0)
4278  width=getBlurKernel((int) (2*ceil(radius)+1),sigma,&kernel);
4279  else{
4280  double *last_kernel;
4281  last_kernel=(double *) NULL;
4282  width=getBlurKernel(3,sigma,&kernel);
4283 
4284  while ((long) (MaxRGB*kernel[0]) > 0){
4285  if(last_kernel != (double *)NULL){
4286  liberateMemory(&last_kernel);
4287  }
4288  last_kernel=kernel;
4289  kernel = (double *)NULL;
4290  width = getBlurKernel(width+2, sigma, &kernel);
4291  }
4292  if(last_kernel != (double *) NULL){
4293  liberateMemory(&kernel);
4294  width-=2;
4295  kernel = last_kernel;
4296  }
4297  }
4298 
4299  if(width < 3){
4300  tqWarning("KImageEffect::blur(): Kernel radius is too small!");
4301  liberateMemory(&kernel);
4302  return(dest);
4303  }
4304 
4305  dest.create(src.width(), src.height(), 32);
4306 
4307  // Horizontal convolution
4308  scanline = (unsigned int *)malloc(sizeof(unsigned int)*src.height());
4309  temp = (unsigned int *)malloc(sizeof(unsigned int)*src.height());
4310  for(y=0; y < src.height(); ++y){
4311  p = (unsigned int *)src.scanLine(y);
4312  q = (unsigned int *)dest.scanLine(y);
4313  blurScanLine(kernel, width, p, q, src.width());
4314  }
4315 
4316  TQImage partial = dest;
4317 
4318  // Vertical convolution
4319  unsigned int **srcTable = (unsigned int **)partial.jumpTable();
4320  unsigned int **destTable = (unsigned int **)dest.jumpTable();
4321  for(x=0; x < partial.width(); ++x){
4322  for(y=0; y < partial.height(); ++y){
4323  scanline[y] = srcTable[y][x];
4324  }
4325  blurScanLine(kernel, width, scanline, temp, partial.height());
4326  for(y=0; y < partial.height(); ++y){
4327  destTable[y][x] = temp[y];
4328  }
4329  }
4330  free(scanline);
4331  free(temp);
4332  free(kernel);
4333  return(dest);
4334 }
4335 
4336 bool KImageEffect::convolveImage(TQImage *image, TQImage *dest,
4337  const unsigned int order,
4338  const double *kernel)
4339 {
4340  long width;
4341  double red, green, blue, alpha;
4342  double normalize, *normal_kernel;
4343  const double *k;
4344  unsigned int *q;
4345  int x, y, mx, my, sx, sy;
4346  long i;
4347  int mcx, mcy;
4348 
4349  width = order;
4350  if((width % 2) == 0){
4351  tqWarning("KImageEffect: Kernel width must be an odd number!");
4352  return(false);
4353  }
4354  normal_kernel = (double *)malloc(width*width*sizeof(double));
4355  if(!normal_kernel){
4356  tqWarning("KImageEffect: Unable to allocate memory!");
4357  return(false);
4358  }
4359  dest->reset();
4360  dest->create(image->width(), image->height(), 32);
4361  if(image->depth() < 32)
4362  *image = image->convertDepth(32);
4363 
4364  normalize=0.0;
4365  for(i=0; i < (width*width); i++)
4366  normalize += kernel[i];
4367  if(fabs(normalize) <= MagickEpsilon)
4368  normalize=1.0;
4369  normalize=1.0/normalize;
4370  for(i=0; i < (width*width); i++)
4371  normal_kernel[i] = normalize*kernel[i];
4372 
4373  unsigned int **jumpTable = (unsigned int **)image->jumpTable();
4374  for(y=0; y < dest->height(); ++y){
4375  sy = y-(width/2);
4376  q = (unsigned int *)dest->scanLine(y);
4377  for(x=0; x < dest->width(); ++x){
4378  k = normal_kernel;
4379  red = green = blue = alpha = 0;
4380  sy = y-(width/2);
4381  for(mcy=0; mcy < width; ++mcy, ++sy){
4382  my = sy < 0 ? 0 : sy > image->height()-1 ?
4383  image->height()-1 : sy;
4384  sx = x+(-width/2);
4385  for(mcx=0; mcx < width; ++mcx, ++sx){
4386  mx = sx < 0 ? 0 : sx > image->width()-1 ?
4387  image->width()-1 : sx;
4388  red += (*k)*(tqRed(jumpTable[my][mx])*257);
4389  green += (*k)*(tqGreen(jumpTable[my][mx])*257);
4390  blue += (*k)*(tqBlue(jumpTable[my][mx])*257);
4391  alpha += (*k)*(tqAlpha(jumpTable[my][mx])*257);
4392  ++k;
4393  }
4394  }
4395 
4396  red = red < 0 ? 0 : red > 65535 ? 65535 : red+0.5;
4397  green = green < 0 ? 0 : green > 65535 ? 65535 : green+0.5;
4398  blue = blue < 0 ? 0 : blue > 65535 ? 65535 : blue+0.5;
4399  alpha = alpha < 0 ? 0 : alpha > 65535 ? 65535 : alpha+0.5;
4400 
4401  *q++ = tqRgba((unsigned char)(red/257UL),
4402  (unsigned char)(green/257UL),
4403  (unsigned char)(blue/257UL),
4404  (unsigned char)(alpha/257UL));
4405  }
4406  }
4407  free(normal_kernel);
4408  return(true);
4409 
4410 }
4411 
4412 int KImageEffect::getOptimalKernelWidth(double radius, double sigma)
4413 {
4414  double normalize, value;
4415  long width;
4416  long u;
4417 
4418  assert(sigma != 0.0);
4419  if(radius > 0.0)
4420  return((int)(2.0*ceil(radius)+1.0));
4421  for(width=5; ;){
4422  normalize=0.0;
4423  for(u=(-width/2); u <= (width/2); u++)
4424  normalize+=exp(-((double) u*u)/(2.0*sigma*sigma))/(MagickSQ2PI*sigma);
4425  u=width/2;
4426  value=exp(-((double) u*u)/(2.0*sigma*sigma))/(MagickSQ2PI*sigma)/normalize;
4427  if((long)(65535*value) <= 0)
4428  break;
4429  width+=2;
4430  }
4431  return((int)width-2);
4432 }
4433 
4434 TQImage KImageEffect::sharpen(TQImage &src, double /*factor*/)
4435 {
4436  /* binary compat method - remove me when possible! */
4437  return(sharpen(src, 0, 1));
4438 }
4439 
4440 TQImage KImageEffect::sharpen(TQImage &image, double radius, double sigma)
4441 {
4442  double alpha, normalize, *kernel;
4443  int width;
4444  long i, u, v;
4445  TQImage dest;
4446 
4447  if(sigma == 0.0){
4448  tqWarning("KImageEffect::sharpen(): Zero sigma is not permitted!");
4449  return(dest);
4450  }
4451  width = getOptimalKernelWidth(radius, sigma);
4452  if(image.width() < width){
4453  tqWarning("KImageEffect::sharpen(): Image is smaller than radius!");
4454  return(dest);
4455  }
4456  kernel = (double *)malloc(width*width*sizeof(double));
4457  if(!kernel){
4458  tqWarning("KImageEffect::sharpen(): Unable to allocate memory!");
4459  return(dest);
4460  }
4461 
4462  i = 0;
4463  normalize=0.0;
4464  for(v=(-width/2); v <= (width/2); v++){
4465  for(u=(-width/2); u <= (width/2); u++){
4466  alpha=exp(-((double) u*u+v*v)/(2.0*sigma*sigma));
4467  kernel[i]=alpha/(2.0*MagickPI*sigma*sigma);
4468  normalize+=kernel[i];
4469  i++;
4470  }
4471  }
4472  kernel[i/2]=(-2.0)*normalize;
4473  convolveImage(&image, &dest, width, kernel);
4474  free(kernel);
4475  return(dest);
4476 }
4477 
4478 // End of new algorithms
4479 
4480 TQImage KImageEffect::shade(TQImage &src, bool color_shading, double azimuth,
4481  double elevation)
4482 {
4483  struct PointInfo{
4484  double x, y, z;
4485  };
4486 
4487  double distance, normal_distance, shade;
4488  int x, y;
4489 
4490  struct PointInfo light, normal;
4491 
4492  unsigned int *q;
4493 
4494  TQImage dest(src.width(), src.height(), 32);
4495 
4496  azimuth = DegreesToRadians(azimuth);
4497  elevation = DegreesToRadians(elevation);
4498  light.x = MaxRGB*cos(azimuth)*cos(elevation);
4499  light.y = MaxRGB*sin(azimuth)*cos(elevation);
4500  light.z = MaxRGB*sin(elevation);
4501  normal.z= 2*MaxRGB; // constant Z of surface normal
4502 
4503  if(src.depth() > 8){ // DirectClass source image
4504  unsigned int *p, *s0, *s1, *s2;
4505  for(y=0; y < src.height(); ++y){
4506  p = (unsigned int *)src.scanLine(TQMIN(TQMAX(y-1,0),src.height()-3));
4507  q = (unsigned int *)dest.scanLine(y);
4508  // shade this row of pixels.
4509  *q++=(*(p+src.width()));
4510  p++;
4511  s0 = p;
4512  s1 = p + src.width();
4513  s2 = p + 2*src.width();
4514  for(x=1; x < src.width()-1; ++x){
4515  // determine the surface normal and compute shading.
4516  normal.x=intensityValue(*(s0-1))+intensityValue(*(s1-1))+intensityValue(*(s2-1))-
4517  (double) intensityValue(*(s0+1))-(double) intensityValue(*(s1+1))-
4518  (double) intensityValue(*(s2+1));
4519  normal.y=intensityValue(*(s2-1))+intensityValue(*s2)+intensityValue(*(s2+1))-
4520  (double) intensityValue(*(s0-1))-(double) intensityValue(*s0)-
4521  (double) intensityValue(*(s0+1));
4522  if((normal.x == 0) && (normal.y == 0))
4523  shade=light.z;
4524  else{
4525  shade=0.0;
4526  distance=normal.x*light.x+normal.y*light.y+normal.z*light.z;
4527  if (distance > 0.0){
4528  normal_distance=
4529  normal.x*normal.x+normal.y*normal.y+normal.z*normal.z;
4530  if(fabs(normal_distance) > 0.0000001)
4531  shade=distance/sqrt(normal_distance);
4532  }
4533  }
4534  if(!color_shading){
4535  *q = tqRgba((unsigned char)(shade),
4536  (unsigned char)(shade),
4537  (unsigned char)(shade),
4538  tqAlpha(*s1));
4539  }
4540  else{
4541  *q = tqRgba((unsigned char)((shade*tqRed(*s1))/(MaxRGB+1)),
4542  (unsigned char)((shade*tqGreen(*s1))/(MaxRGB+1)),
4543  (unsigned char)((shade*tqBlue(*s1))/(MaxRGB+1)),
4544  tqAlpha(*s1));
4545  }
4546  ++s0;
4547  ++s1;
4548  ++s2;
4549  q++;
4550  }
4551  *q++=(*s1);
4552  }
4553  }
4554  else{ // PsudeoClass source image
4555  unsigned char *p, *s0, *s1, *s2;
4556  int scanLineIdx;
4557  unsigned int *cTable = (unsigned int *)src.colorTable();
4558  for(y=0; y < src.height(); ++y){
4559  scanLineIdx = TQMIN(TQMAX(y-1,0),src.height()-3);
4560  p = (unsigned char *)src.scanLine(scanLineIdx);
4561  q = (unsigned int *)dest.scanLine(y);
4562  // shade this row of pixels.
4563  s0 = p;
4564  s1 = (unsigned char *) src.scanLine(scanLineIdx+1);
4565  s2 = (unsigned char *) src.scanLine(scanLineIdx+2);
4566  *q++=(*(cTable+(*s1)));
4567  ++p;
4568  ++s0;
4569  ++s1;
4570  ++s2;
4571  for(x=1; x < src.width()-1; ++x){
4572  // determine the surface normal and compute shading.
4573  normal.x=intensityValue(*(cTable+(*(s0-1))))+intensityValue(*(cTable+(*(s1-1))))+intensityValue(*(cTable+(*(s2-1))))-
4574  (double) intensityValue(*(cTable+(*(s0+1))))-(double) intensityValue(*(cTable+(*(s1+1))))-
4575  (double) intensityValue(*(cTable+(*(s2+1))));
4576  normal.y=intensityValue(*(cTable+(*(s2-1))))+intensityValue(*(cTable+(*s2)))+intensityValue(*(cTable+(*(s2+1))))-
4577  (double) intensityValue(*(cTable+(*(s0-1))))-(double) intensityValue(*(cTable+(*s0)))-
4578  (double) intensityValue(*(cTable+(*(s0+1))));
4579  if((normal.x == 0) && (normal.y == 0))
4580  shade=light.z;
4581  else{
4582  shade=0.0;
4583  distance=normal.x*light.x+normal.y*light.y+normal.z*light.z;
4584  if (distance > 0.0){
4585  normal_distance=
4586  normal.x*normal.x+normal.y*normal.y+normal.z*normal.z;
4587  if(fabs(normal_distance) > 0.0000001)
4588  shade=distance/sqrt(normal_distance);
4589  }
4590  }
4591  if(!color_shading){
4592  *q = tqRgba((unsigned char)(shade),
4593  (unsigned char)(shade),
4594  (unsigned char)(shade),
4595  tqAlpha(*(cTable+(*s1))));
4596  }
4597  else{
4598  *q = tqRgba((unsigned char)((shade*tqRed(*(cTable+(*s1))))/(MaxRGB+1)),
4599  (unsigned char)((shade*tqGreen(*(cTable+(*s1))))/(MaxRGB+1)),
4600  (unsigned char)((shade*tqBlue(*(cTable+(*s1))))/(MaxRGB+1)),
4601  tqAlpha(*s1));
4602  }
4603  ++s0;
4604  ++s1;
4605  ++s2;
4606  q++;
4607  }
4608  *q++=(*(cTable+(*s1)));
4609  }
4610  }
4611  return(dest);
4612 }
4613 
4614 // High quality, expensive HSV contrast. You can do a faster one by just
4615 // taking a grayscale threshold (ie: 128) and incrementing RGB color
4616 // channels above it and decrementing those below it, but this gives much
4617 // better results. (mosfet 12/28/01)
4618 void KImageEffect::contrastHSV(TQImage &img, bool sharpen)
4619 {
4620  int i, sign;
4621  unsigned int *data;
4622  int count;
4623  double brightness, scale, theta;
4624  TQColor c;
4625  int h, s, v;
4626 
4627  sign = sharpen ? 1 : -1;
4628  scale=0.5000000000000001;
4629  if(img.depth() > 8){
4630  count = img.width()*img.height();
4631  data = (unsigned int *)img.bits();
4632  }
4633  else{
4634  count = img.numColors();
4635  data = (unsigned int *)img.colorTable();
4636  }
4637  for(i=0; i < count; ++i){
4638  c.setRgb(data[i]);
4639  c.hsv(&h, &s, &v);
4640  brightness = v/255.0;
4641  theta=(brightness-0.5)*M_PI;
4642  brightness+=scale*(((scale*((sin(theta)+1.0)))-brightness)*sign);
4643  if (brightness > 1.0)
4644  brightness=1.0;
4645  else
4646  if (brightness < 0)
4647  brightness=0.0;
4648  v = (int)(brightness*255);
4649  c.setHsv(h, s, v);
4650  data[i] = tqRgba(c.red(), c.green(), c.blue(), tqAlpha(data[i]));
4651  }
4652 }
4653 
4654 
4655 struct BumpmapParams {
4656  BumpmapParams( double bm_azimuth, double bm_elevation,
4657  int bm_depth, KImageEffect::BumpmapType bm_type,
4658  bool invert ) {
4659  /* Convert to radians */
4660  double azimuth = DegreesToRadians( bm_azimuth );
4661  double elevation = DegreesToRadians( bm_elevation );
4662 
4663  /* Calculate the light vector */
4664  lx = (int)( cos(azimuth) * cos(elevation) * 255.0 );
4665  ly = (int)( sin(azimuth) * cos(elevation) * 255.0 );
4666  int lz = (int)( sin(elevation) * 255.0 );
4667 
4668  /* Calculate constant Z component of surface normal */
4669  int nz = (6 * 255) / bm_depth;
4670  nz2 = nz * nz;
4671  nzlz = nz * lz;
4672 
4673  /* Optimize for vertical normals */
4674  background = lz;
4675 
4676  /* Calculate darkness compensation factor */
4677  compensation = sin(elevation);
4678 
4679  /* Create look-up table for map type */
4680  for (int i = 0; i < 256; i++)
4681  {
4682  double n = 0;
4683  switch (bm_type)
4684  {
4685  case KImageEffect::Spherical:
4686  n = i / 255.0 - 1.0;
4687  lut[i] = (int) (255.0 * sqrt(1.0 - n * n) + 0.5);
4688  break;
4689 
4690  case KImageEffect::Sinuosidal:
4691  n = i / 255.0;
4692  lut[i] = (int) (255.0 * (sin((-M_PI / 2.0) + M_PI * n) + 1.0) /
4693  2.0 + 0.5);
4694  break;
4695 
4696  case KImageEffect::Linear:
4697  default:
4698  lut[i] = i;
4699  }
4700 
4701  if (invert)
4702  lut[i] = 255 - lut[i];
4703  }
4704  }
4705  int lx, ly;
4706  int nz2, nzlz;
4707  int background;
4708  double compensation;
4709  uchar lut[256];
4710 };
4711 
4712 
4713 static void bumpmap_convert_row( uint *row,
4714  int width,
4715  int bpp,
4716  int has_alpha,
4717  uchar *lut,
4718  int waterlevel )
4719 {
4720  uint *p;
4721 
4722  p = row;
4723 
4724  has_alpha = has_alpha ? 1 : 0;
4725 
4726  if (bpp >= 3)
4727  for (; width; width--)
4728  {
4729  if (has_alpha) {
4730  unsigned int idx = (unsigned int)(intensityValue( *row ) + 0.5);
4731  *p++ = lut[(unsigned int) ( waterlevel +
4732  ( ( idx -
4733  waterlevel) * tqBlue( *row )) / 255.0 )];
4734  } else {
4735  unsigned int idx = (unsigned int)(intensityValue( *row ) + 0.5);
4736  *p++ = lut[idx];
4737  }
4738 
4739  ++row;
4740  }
4741 }
4742 
4743 static void bumpmap_row( uint *src,
4744  uint *dest,
4745  int width,
4746  int bpp,
4747  int has_alpha,
4748  uint *bm_row1,
4749  uint *bm_row2,
4750  uint *bm_row3,
4751  int bm_width,
4752  int bm_xofs,
4753  bool tiled,
4754  bool row_in_bumpmap,
4755  int ambient,
4756  bool compensate,
4757  BumpmapParams *params )
4758 {
4759  int xofs1, xofs2, xofs3;
4760  int shade;
4761  int ndotl;
4762  int nx, ny;
4763  int x;
4764  int tmp;
4765 
4766  tmp = bm_xofs;
4767  xofs2 = MOD(tmp, bm_width);
4768 
4769  for (x = 0; x < width; x++)
4770  {
4771  /* Calculate surface normal from bump map */
4772 
4773  if (tiled || (row_in_bumpmap &&
4774  x >= - tmp && x < - tmp + bm_width)) {
4775  if (tiled) {
4776  xofs1 = MOD(xofs2 - 1, bm_width);
4777  xofs3 = MOD(xofs2 + 1, bm_width);
4778  } else {
4779  xofs1 = FXCLAMP(xofs2 - 1, 0, bm_width - 1);
4780  xofs3 = FXCLAMP(xofs2 + 1, 0, bm_width - 1);
4781  }
4782  nx = (bm_row1[xofs1] + bm_row2[xofs1] + bm_row3[xofs1] -
4783  bm_row1[xofs3] - bm_row2[xofs3] - bm_row3[xofs3]);
4784  ny = (bm_row3[xofs1] + bm_row3[xofs2] + bm_row3[xofs3] -
4785  bm_row1[xofs1] - bm_row1[xofs2] - bm_row1[xofs3]);
4786  } else {
4787  nx = ny = 0;
4788  }
4789 
4790  /* Shade */
4791 
4792  if ((nx == 0) && (ny == 0))
4793  shade = params->background;
4794  else {
4795  ndotl = nx * params->lx + ny * params->ly + params->nzlz;
4796 
4797  if (ndotl < 0)
4798  shade = (int)( params->compensation * ambient );
4799  else {
4800  shade = (int)( ndotl / sqrt(double(nx * nx + ny * ny + params->nz2)) );
4801 
4802  shade = (int)( shade + TQMAX(0.0, (255 * params->compensation - shade)) *
4803  ambient / 255 );
4804  }
4805  }
4806 
4807  /* Paint */
4808 
4813  if (compensate) {
4814  int red = (int)((tqRed( *src ) * shade) / (params->compensation * 255));
4815  int green = (int)((tqGreen( *src ) * shade) / (params->compensation * 255));
4816  int blue = (int)((tqBlue( *src ) * shade) / (params->compensation * 255));
4817  int alpha = (int)((tqAlpha( *src ) * shade) / (params->compensation * 255));
4818  ++src;
4819  *dest++ = tqRgba( red, green, blue, alpha );
4820  } else {
4821  int red = tqRed( *src ) * shade / 255;
4822  int green = tqGreen( *src ) * shade / 255;
4823  int blue = tqBlue( *src ) * shade / 255;
4824  int alpha = tqAlpha( *src ) * shade / 255;
4825  ++src;
4826  *dest++ = tqRgba( red, green, blue, alpha );
4827  }
4828 
4829  /* Next pixel */
4830 
4831  if (++xofs2 == bm_width)
4832  xofs2 = 0;
4833  }
4834 }
4835 
4855 TQImage KImageEffect::bumpmap(TQImage &img, TQImage &map, double azimuth, double elevation,
4856  int depth, int xofs, int yofs, int waterlevel,
4857  int ambient, bool compensate, bool invert,
4858  BumpmapType type, bool tiled)
4859 {
4860  TQImage dst;
4861 
4862  if ( img.depth() != 32 || img.depth() != 32 ) {
4863  tqWarning( "Bump-mapping effect works only with 32 bit images");
4864  return dst;
4865  }
4866 
4867  dst.create( img.width(), img.height(), img.depth() );
4868  int bm_width = map.width();
4869  int bm_height = map.height();
4870  int bm_bpp = map.depth();
4871  int bm_has_alpha = map.hasAlphaBuffer();
4872 
4873  int yofs1, yofs2, yofs3;
4874 
4875  if ( tiled ) {
4876  yofs2 = MOD( yofs, bm_height );
4877  yofs1 = MOD( yofs2 - 1, bm_height);
4878  yofs3 = MOD( yofs2 + 1, bm_height);
4879  } else {
4880  yofs1 = 0;
4881  yofs2 = 0;
4882  yofs3 = FXCLAMP( yofs2+1, 0, bm_height - 1 );
4883  }
4884 
4885  BumpmapParams params( azimuth, elevation, depth, type, invert );
4886 
4887  uint* bm_row1 = (unsigned int*)map.scanLine( yofs1 );
4888  uint* bm_row2 = (unsigned int*)map.scanLine( yofs2 );
4889  uint* bm_row3 = (unsigned int*)map.scanLine( yofs3 );
4890 
4891  bumpmap_convert_row( bm_row1, bm_width, bm_bpp, bm_has_alpha, params.lut, waterlevel );
4892  bumpmap_convert_row( bm_row2, bm_width, bm_bpp, bm_has_alpha, params.lut, waterlevel );
4893  bumpmap_convert_row( bm_row3, bm_width, bm_bpp, bm_has_alpha, params.lut, waterlevel );
4894 
4895  for (int y = 0; y < img.height(); ++y)
4896  {
4897  int row_in_bumpmap = (y >= - yofs && y < - yofs + bm_height);
4898 
4899  uint* src_row = (unsigned int*)img.scanLine( y );
4900  uint* dest_row = (unsigned int*)dst.scanLine( y );
4901 
4902  bumpmap_row( src_row, dest_row, img.width(), img.depth(), img.hasAlphaBuffer(),
4903  bm_row1, bm_row2, bm_row3, bm_width, xofs,
4904  tiled,
4905  row_in_bumpmap, ambient, compensate,
4906  &params );
4907 
4908  /* Next line */
4909 
4910  if (tiled || row_in_bumpmap)
4911  {
4912  uint* bm_tmprow = bm_row1;
4913  bm_row1 = bm_row2;
4914  bm_row2 = bm_row3;
4915  bm_row3 = bm_tmprow;
4916 
4917  if (++yofs2 == bm_height)
4918  yofs2 = 0;
4919 
4920  if (tiled)
4921  yofs3 = MOD(yofs2 + 1, bm_height);
4922  else
4923  yofs3 = FXCLAMP(yofs2 + 1, 0, bm_height - 1);
4924 
4925  bm_row3 = (unsigned int*)map.scanLine( yofs3 );
4926  bumpmap_convert_row( bm_row3, bm_width, bm_bpp, bm_has_alpha,
4927  params.lut, waterlevel );
4928  }
4929  }
4930  return dst;
4931 }
4932 
4941 TQImage KImageEffect::convertToPremultipliedAlpha(TQImage input) {
4942  TQImage alphaImage = input;
4943  if (!alphaImage.isNull()) alphaImage = alphaImage.convertDepth( 32 );
4944 
4945  int w = alphaImage.width();
4946  int h = alphaImage.height();
4947 
4948  int r;
4949  int g;
4950  int b;
4951  int a;
4952  float alpha_adjust;
4953  TQRgb l;
4954  TQRgb *ls;
4955  for (int y = 0; y < h; ++y) {
4956  ls = (TQRgb *)alphaImage.scanLine( y );
4957  for (int x = 0; x < w; ++x) {
4958  l = ls[x];
4959  alpha_adjust = (tqAlpha( l )/255.0);
4960  r = int( tqRed( l ) * alpha_adjust );
4961  g = int( tqGreen( l ) * alpha_adjust );
4962  b = int( tqBlue( l ) * alpha_adjust );
4963  a = int( tqAlpha( l ) * 1.0 );
4964  ls[x] = tqRgba( r, g, b, a );
4965  }
4966  }
4967  return alphaImage;
4968 }
KCPUInfo::haveExtension
static bool haveExtension(unsigned int extension)
Returns true if the processor supports extension, and false otherwise.
Definition: kcpuinfo.h:62
KCPUInfo::IntelSSE2
@ IntelSSE2
Intel's SSE2 instructions.
Definition: kcpuinfo.h:49
KCPUInfo::IntelMMX
@ IntelMMX
Intel's MMX instructions.
Definition: kcpuinfo.h:47
KImageEffect::shade
static TQImage shade(TQImage &src, bool color_shading=true, double azimuth=30.0, double elevation=30.0)
Shades the image using a distance light source.
Definition: kimageeffect.cpp:4480
KImageEffect::NoiseType
NoiseType
This enum provides a noise type specification.
Definition: kimageeffect.h:108
KImageEffect::GaussianNoise
@ GaussianNoise
Gaussian distribution.
Definition: kimageeffect.h:109
KImageEffect::MultiplicativeGaussianNoise
@ MultiplicativeGaussianNoise
Multiplicative Gaussian distribution.
Definition: kimageeffect.h:110
KImageEffect::ImpulseNoise
@ ImpulseNoise
Impulse distribution.
Definition: kimageeffect.h:111
KImageEffect::PoissonNoise
@ PoissonNoise
Poisson distribution.
Definition: kimageeffect.h:113
KImageEffect::UniformNoise
@ UniformNoise
Uniform distribution.
Definition: kimageeffect.h:108
KImageEffect::LaplacianNoise
@ LaplacianNoise
Laplacian distribution.
Definition: kimageeffect.h:112
KImageEffect::edge
static TQImage edge(TQImage &src, double radius)
Detects edges in an image using pixel neighborhoods and an edge detection mask.
Definition: kimageeffect.cpp:4003
KImageEffect::equalize
static void equalize(TQImage &img)
Performs histogram equalisation on the reference image.
Definition: kimageeffect.cpp:3903
KImageEffect::threshold
static void threshold(TQImage &img, unsigned int value=128)
Thresholds the reference image.
Definition: kimageeffect.cpp:2810
KImageEffect::dither
static TQImage & dither(TQImage &image, const TQColor *palette, int size)
Dither an image using Floyd-Steinberg dithering for low-color situations.
Definition: kimageeffect.cpp:2261
KImageEffect::computeDestinationRect
static TQRect computeDestinationRect(const TQSize &lowerSize, Disposition disposition, TQImage &upper)
Compute the destination rectangle where to draw the upper image on top of another image using the giv...
Definition: kimageeffect.cpp:2628
KImageEffect::blend
static TQImage & blend(const TQColor &clr, TQImage &dst, float opacity)
Blends a color into the destination image, using an opacity value for blending one into another.
Definition: kimageeffect.cpp:1067
KImageEffect::emboss
static TQImage emboss(TQImage &src, double radius, double sigma)
Embosses the source image.
Definition: kimageeffect.cpp:4041
KImageEffect::channelIntensity
static TQImage & channelIntensity(TQImage &image, float percent, RGBComponent channel)
Modifies the intensity of a pixmap's RGB channel component.
Definition: kimageeffect.cpp:846
KImageEffect::swirl
static TQImage swirl(TQImage &src, double degrees=50.0, unsigned int background=0xFFFFFFFF)
Swirls the image by a specified amount.
Definition: kimageeffect.cpp:3495
KImageEffect::fade
static TQImage & fade(TQImage &image, float val, const TQColor &color)
Fade an image to a certain background color.
Definition: kimageeffect.cpp:2044
KImageEffect::charcoal
static TQImage charcoal(TQImage &src, double radius, double sigma)
Produces a neat little "charcoal" effect.
Definition: kimageeffect.cpp:3683
KImageEffect::ModulationType
ModulationType
This enum provides a modulation type specification.
Definition: kimageeffect.h:98
KImageEffect::Saturation
@ Saturation
Modulate image saturation.
Definition: kimageeffect.h:99
KImageEffect::Contrast
@ Contrast
Modulate image contrast.
Definition: kimageeffect.h:101
KImageEffect::HueShift
@ HueShift
Modulate image hue.
Definition: kimageeffect.h:100
KImageEffect::Intensity
@ Intensity
Modulate image intensity.
Definition: kimageeffect.h:98
KImageEffect::GradientType
GradientType
This enum provides a gradient type specification.
Definition: kimageeffect.h:58
KImageEffect::RotateDirection
RotateDirection
This enum provides a rotation specification.
Definition: kimageeffect.h:120
KImageEffect::Rotate270
@ Rotate270
Rotate 90 degrees to the left.
Definition: kimageeffect.h:122
KImageEffect::Rotate90
@ Rotate90
Rotate 90 degrees to the right.
Definition: kimageeffect.h:120
KImageEffect::Rotate180
@ Rotate180
Rotate 180 degrees.
Definition: kimageeffect.h:121
KImageEffect::gradient
static TQImage gradient(const TQSize &size, const TQColor &ca, const TQColor &cb, GradientType type, int ncols=3)
Create a gradient from color a to color b of the specified type.
Definition: kimageeffect.cpp:124
KImageEffect::oilPaintConvolve
static TQImage oilPaintConvolve(TQImage &src, double radius)
Produces an oil painting effect.
Definition: kimageeffect.cpp:3612
KImageEffect::sample
static TQImage sample(TQImage &src, int w, int h)
Scales an image using simple pixel sampling.
Definition: kimageeffect.cpp:2747
KImageEffect::implode
static TQImage implode(TQImage &src, double factor=30.0, unsigned int background=0xFFFFFFFF)
Implodes an image by a specified percent.
Definition: kimageeffect.cpp:3242
KImageEffect::Disposition
Disposition
Disposition of a source image on top of a destination image.
Definition: kimageeffect.h:326
KImageEffect::NoImage
@ NoImage
Don't overlay.
Definition: kimageeffect.h:326
KImageEffect::CenteredAutoFit
@ CenteredAutoFit
Center and scale or scale aspect.
Definition: kimageeffect.h:333
KImageEffect::CenterTiled
@ CenterTiled
Center and tile top image on bottom image.
Definition: kimageeffect.h:329
KImageEffect::CenteredMaxpect
@ CenteredMaxpect
Center and scale aspect.
Definition: kimageeffect.h:330
KImageEffect::Scaled
@ Scaled
Scale.
Definition: kimageeffect.h:332
KImageEffect::Centered
@ Centered
Center top image on botton image.
Definition: kimageeffect.h:327
KImageEffect::TiledMaxpect
@ TiledMaxpect
Tile and scale aspect.
Definition: kimageeffect.h:331
KImageEffect::Tiled
@ Tiled
Tile top image on bottom image.
Definition: kimageeffect.h:328
KImageEffect::bumpmap
static TQImage bumpmap(TQImage &img, TQImage &map, double azimuth, double elevation, int depth, int xofs, int yofs, int waterlevel, int ambient, bool compensate, bool invert, BumpmapType type, bool tiled)
A bumpmapping algorithm.
Definition: kimageeffect.cpp:4855
KImageEffect::modulate
static TQImage & modulate(TQImage &image, TQImage &modImage, bool reverse, ModulationType type, int factor, RGBComponent channel)
Modulate the image with a color channel of another image.
Definition: kimageeffect.cpp:937
KImageEffect::desaturate
static TQImage & desaturate(TQImage &image, float desat=0.3)
Desaturate an image evenly.
Definition: kimageeffect.cpp:2176
KImageEffect::flatten
static TQImage & flatten(TQImage &image, const TQColor &ca, const TQColor &cb, int ncols=0)
This recolors a pixmap.
Definition: kimageeffect.cpp:1947
KImageEffect::Lighting
Lighting
This enum provides a lighting direction specification.
Definition: kimageeffect.h:84
KImageEffect::NELite
@ NELite
Lighting from the top right of the image.
Definition: kimageeffect.h:91
KImageEffect::NorthLite
@ NorthLite
Lighting from the top of the image.
Definition: kimageeffect.h:84
KImageEffect::SWLite
@ SWLite
Lighting from the bottom left of the image.
Definition: kimageeffect.h:87
KImageEffect::NWLite
@ NWLite
Lighting from the top left of the image.
Definition: kimageeffect.h:85
KImageEffect::EastLite
@ EastLite
Lighting from the right of the image.
Definition: kimageeffect.h:90
KImageEffect::SELite
@ SELite
Lighting from the bottom right of the image.
Definition: kimageeffect.h:89
KImageEffect::WestLite
@ WestLite
Lighting from the left of the image.
Definition: kimageeffect.h:86
KImageEffect::SouthLite
@ SouthLite
Lighting from the bottom of the image.
Definition: kimageeffect.h:88
KImageEffect::toGray
static TQImage & toGray(TQImage &image, bool fast=false)
Convert an image to grayscale.
Definition: kimageeffect.cpp:2126
KImageEffect::rotate
static TQImage rotate(TQImage &src, RotateDirection r)
Rotates the image by the specified amount.
Definition: kimageeffect.cpp:3323
KImageEffect::spread
static TQImage spread(TQImage &src, unsigned int amount=3)
Randomly displaces pixels.
Definition: kimageeffect.cpp:3444
KImageEffect::solarize
static void solarize(TQImage &img, double factor=50.0)
Produces a 'solarization' effect seen when exposing a photographic film to light during the developme...
Definition: kimageeffect.cpp:3421
KImageEffect::sharpen
static TQImage sharpen(TQImage &src, double radius, double sigma)
Sharpens the pixels in the image using pixel neighborhoods.
Definition: kimageeffect.cpp:4440
KImageEffect::convertToPremultipliedAlpha
static TQImage convertToPremultipliedAlpha(TQImage input)
Convert an image with standard alpha to premultiplied alpha.
Definition: kimageeffect.cpp:4941
KImageEffect::wave
static TQImage wave(TQImage &src, double amplitude=25.0, double frequency=150.0, unsigned int background=0xFFFFFFFF)
Modifies the pixels along a sine wave.
Definition: kimageeffect.cpp:3573
KImageEffect::oilPaint
static TQImage oilPaint(TQImage &src, int radius=3)
This is provided for binary compatability only! Use the above method instead!
Definition: kimageeffect.cpp:3606
KImageEffect::contrast
static TQImage & contrast(TQImage &image, int c)
Fast, but low quality contrast of an image.
Definition: kimageeffect.cpp:2199
KImageEffect::addNoise
static TQImage addNoise(TQImage &src, NoiseType type=GaussianNoise)
Adds noise to an image.
Definition: kimageeffect.cpp:3112
KImageEffect::BumpmapType
BumpmapType
This enum lists possible bumpmapping implementations.
Definition: kimageeffect.h:129
KImageEffect::RGBComponent
RGBComponent
This enum provides a RGB channel specification.
Definition: kimageeffect.h:73
KImageEffect::Gray
@ Gray
Grey channel.
Definition: kimageeffect.h:76
KImageEffect::All
@ All
All channels.
Definition: kimageeffect.h:77
KImageEffect::Green
@ Green
Green channel.
Definition: kimageeffect.h:74
KImageEffect::Red
@ Red
Red channel.
Definition: kimageeffect.h:73
KImageEffect::Blue
@ Blue
Blue channel.
Definition: kimageeffect.h:75
KImageEffect::selectedImage
static TQImage & selectedImage(TQImage &img, const TQColor &col)
Calculate the image for a selected image, for instance a selected icon on the desktop.
Definition: kimageeffect.cpp:2705
KImageEffect::hash
static TQImage & hash(TQImage &image, Lighting lite=NorthLite, unsigned int spacing=0)
Build a hash on any given TQImage.
Definition: kimageeffect.cpp:1866
KImageEffect::normalize
static void normalize(TQImage &img)
Normalises the pixel values to span the full range of color values.
Definition: kimageeffect.cpp:3693
KImageEffect::blur
static TQImage blur(TQImage &src, double radius, double sigma)
Blurs an image by convolving pixel neighborhoods.
Definition: kimageeffect.cpp:4260
KImageEffect::intensity
static TQImage & intensity(TQImage &image, float percent)
Either brighten or dim the image by a specified percent.
Definition: kimageeffect.cpp:654
KImageEffect::unbalancedGradient
static TQImage unbalancedGradient(const TQSize &size, const TQColor &ca, const TQColor &cb, GradientType type, int xfactor=100, int yfactor=100, int ncols=3)
Create an unbalanced gradient.
Definition: kimageeffect.cpp:388
KImageEffect::contrastHSV
static void contrastHSV(TQImage &img, bool sharpen=true)
High quality, expensive HSV contrast.
Definition: kimageeffect.cpp:4618
KImageEffect::blendOnLower
static bool blendOnLower(int x, int y, const TQImage &upper, const TQImage &lower)
Blend an image into another one, using alpha in the expected way and over coordinates x and y with re...
Definition: kimageeffect.cpp:2514
KImageEffect::despeckle
static TQImage despeckle(TQImage &src)
Minimizes speckle noise in the source image using the 8 hull algorithm.
Definition: kimageeffect.cpp:2906
endl
kndbgstream & endl(kndbgstream &s)

tdefx

Skip menu "tdefx"
  • Main Page
  • Alphabetical List
  • Class List
  • File List
  • Class Members
  • Related Pages

tdefx

Skip menu "tdefx"
  • arts
  • dcop
  • dnssd
  • interfaces
  •   kspeech
  •     interface
  •     library
  •   tdetexteditor
  • kate
  • kded
  • kdoctools
  • kimgio
  • kjs
  • libtdemid
  • libtdescreensaver
  • tdeabc
  • tdecmshell
  • tdecore
  • tdefx
  • tdehtml
  • tdeinit
  • tdeio
  •   bookmarks
  •   httpfilter
  •   kpasswdserver
  •   kssl
  •   tdefile
  •   tdeio
  •   tdeioexec
  • tdeioslave
  •   http
  • tdemdi
  •   tdemdi
  • tdenewstuff
  • tdeparts
  • tdeprint
  • tderandr
  • tderesources
  • tdespell2
  • tdesu
  • tdeui
  • tdeunittest
  • tdeutils
  • tdewallet
Generated for tdefx by doxygen 1.9.1
This website is maintained by Timothy Pearson.