kdefx Library API Documentation

kimageeffect.cpp

00001 /* This file is part of the KDE libraries
00002     Copyright (C) 1998, 1999, 2001, 2002 Daniel M. Duley <mosfet@kde.org>
00003     (C) 1998, 1999 Christian Tibirna <ctibirna@total.net>
00004     (C) 1998, 1999 Dirk A. Mueller <mueller@kde.org>
00005     (C) 2000 Josef Weidendorfer <weidendo@in.tum.de>
00006 
00007 Redistribution and use in source and binary forms, with or without
00008 modification, are permitted provided that the following conditions
00009 are met:
00010 
00011 1. Redistributions of source code must retain the above copyright
00012    notice, this list of conditions and the following disclaimer.
00013 2. Redistributions in binary form must reproduce the above copyright
00014    notice, this list of conditions and the following disclaimer in the
00015    documentation and/or other materials provided with the distribution.
00016 
00017 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
00018 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
00019 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
00020 IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
00021 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
00022 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
00023 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
00024 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00025 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
00026 THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00027 
00028 */
00029 
00030 #include <math.h>
00031 
00032 #include <qimage.h>
00033 #include <stdlib.h>
00034 #include <iostream>
00035 
00036 #include "kimageeffect.h"
00037 
00038 #include <config.h>
00039 
00040 #define MaxRGB 255L
00041 #define DegreesToRadians(x) ((x)*M_PI/180.0)
00042 
00043 using namespace std;
00044 
00045 inline unsigned int intensityValue(unsigned int color)
00046 {
00047     return((unsigned int)((0.299*qRed(color) +
00048                            0.587*qGreen(color) +
00049                            0.1140000000000001*qBlue(color))));
00050 }
00051 
00052 //======================================================================
00053 //
00054 // Gradient effects
00055 //
00056 //======================================================================
00057 
00058 QImage KImageEffect::gradient(const QSize &size, const QColor &ca,
00059         const QColor &cb, GradientType eff, int ncols)
00060 {
00061     int rDiff, gDiff, bDiff;
00062     int rca, gca, bca, rcb, gcb, bcb;
00063 
00064     QImage image(size, 32);
00065 
00066     if (size.width() == 0 || size.height() == 0) {
00067 #ifndef NDEBUG
00068       cerr << "WARNING: KImageEffect::gradient: invalid image" << endl;
00069 #endif
00070       return image;
00071     }
00072 
00073     register int x, y;
00074 
00075     rDiff = (rcb = cb.red())   - (rca = ca.red());
00076     gDiff = (gcb = cb.green()) - (gca = ca.green());
00077     bDiff = (bcb = cb.blue())  - (bca = ca.blue());
00078 
00079     if( eff == VerticalGradient || eff == HorizontalGradient ){
00080 
00081         uint *p;
00082         uint rgb;
00083 
00084         register int rl = rca << 16;
00085         register int gl = gca << 16;
00086         register int bl = bca << 16;
00087 
00088         if( eff == VerticalGradient ) {
00089 
00090             int rcdelta = ((1<<16) / size.height()) * rDiff;
00091             int gcdelta = ((1<<16) / size.height()) * gDiff;
00092             int bcdelta = ((1<<16) / size.height()) * bDiff;
00093 
00094             for ( y = 0; y < size.height(); y++ ) {
00095                 p = (uint *) image.scanLine(y);
00096 
00097                 rl += rcdelta;
00098                 gl += gcdelta;
00099                 bl += bcdelta;
00100 
00101                 rgb = qRgb( (rl>>16), (gl>>16), (bl>>16) );
00102 
00103                 for( x = 0; x < size.width(); x++ ) {
00104                     *p = rgb;
00105                     p++;
00106                 }
00107             }
00108 
00109         }
00110         else {                  // must be HorizontalGradient
00111 
00112             unsigned int *o_src = (unsigned int *)image.scanLine(0);
00113             unsigned int *src = o_src;
00114 
00115             int rcdelta = ((1<<16) / size.width()) * rDiff;
00116             int gcdelta = ((1<<16) / size.width()) * gDiff;
00117             int bcdelta = ((1<<16) / size.width()) * bDiff;
00118 
00119             for( x = 0; x < size.width(); x++) {
00120 
00121                 rl += rcdelta;
00122                 gl += gcdelta;
00123                 bl += bcdelta;
00124 
00125                 *src++ = qRgb( (rl>>16), (gl>>16), (bl>>16));
00126             }
00127 
00128             src = o_src;
00129 
00130             // Believe it or not, manually copying in a for loop is faster
00131             // than calling memcpy for each scanline (on the order of ms...).
00132             // I think this is due to the function call overhead (mosfet).
00133 
00134             for (y = 1; y < size.height(); ++y) {
00135 
00136                 p = (unsigned int *)image.scanLine(y);
00137                 src = o_src;
00138                 for(x=0; x < size.width(); ++x)
00139                     *p++ = *src++;
00140             }
00141         }
00142     }
00143 
00144     else {
00145 
00146         float rfd, gfd, bfd;
00147         float rd = rca, gd = gca, bd = bca;
00148 
00149         unsigned char *xtable[3];
00150         unsigned char *ytable[3];
00151 
00152         unsigned int w = size.width(), h = size.height();
00153         xtable[0] = new unsigned char[w];
00154         xtable[1] = new unsigned char[w];
00155         xtable[2] = new unsigned char[w];
00156         ytable[0] = new unsigned char[h];
00157         ytable[1] = new unsigned char[h];
00158         ytable[2] = new unsigned char[h];
00159         w*=2, h*=2;
00160 
00161         if ( eff == DiagonalGradient || eff == CrossDiagonalGradient) {
00162             // Diagonal dgradient code inspired by BlackBox (mosfet)
00163             // BlackBox dgradient is (C) Brad Hughes, <bhughes@tcac.net> and
00164             // Mike Cole <mike@mydot.com>.
00165 
00166             rfd = (float)rDiff/w;
00167             gfd = (float)gDiff/w;
00168             bfd = (float)bDiff/w;
00169 
00170             int dir;
00171             for (x = 0; x < size.width(); x++, rd+=rfd, gd+=gfd, bd+=bfd) {
00172                 dir = eff == DiagonalGradient? x : size.width() - x - 1;
00173                 xtable[0][dir] = (unsigned char) rd;
00174                 xtable[1][dir] = (unsigned char) gd;
00175                 xtable[2][dir] = (unsigned char) bd;
00176             }
00177             rfd = (float)rDiff/h;
00178             gfd = (float)gDiff/h;
00179             bfd = (float)bDiff/h;
00180             rd = gd = bd = 0;
00181             for (y = 0; y < size.height(); y++, rd+=rfd, gd+=gfd, bd+=bfd) {
00182                 ytable[0][y] = (unsigned char) rd;
00183                 ytable[1][y] = (unsigned char) gd;
00184                 ytable[2][y] = (unsigned char) bd;
00185             }
00186 
00187             for (y = 0; y < size.height(); y++) {
00188                 unsigned int *scanline = (unsigned int *)image.scanLine(y);
00189                 for (x = 0; x < size.width(); x++) {
00190                     scanline[x] = qRgb(xtable[0][x] + ytable[0][y],
00191                                        xtable[1][x] + ytable[1][y],
00192                                        xtable[2][x] + ytable[2][y]);
00193                 }
00194             }
00195         }
00196 
00197         else if (eff == RectangleGradient ||
00198                  eff == PyramidGradient ||
00199                  eff == PipeCrossGradient ||
00200                  eff == EllipticGradient)
00201         {
00202             int rSign = rDiff>0? 1: -1;
00203             int gSign = gDiff>0? 1: -1;
00204             int bSign = bDiff>0? 1: -1;
00205 
00206             rfd = (float)rDiff / size.width();
00207             gfd = (float)gDiff / size.width();
00208             bfd = (float)bDiff / size.width();
00209 
00210             rd = (float)rDiff/2;
00211             gd = (float)gDiff/2;
00212             bd = (float)bDiff/2;
00213 
00214             for (x = 0; x < size.width(); x++, rd-=rfd, gd-=gfd, bd-=bfd)
00215             {
00216                 xtable[0][x] = (unsigned char) abs((int)rd);
00217                 xtable[1][x] = (unsigned char) abs((int)gd);
00218                 xtable[2][x] = (unsigned char) abs((int)bd);
00219             }
00220 
00221             rfd = (float)rDiff/size.height();
00222             gfd = (float)gDiff/size.height();
00223             bfd = (float)bDiff/size.height();
00224 
00225             rd = (float)rDiff/2;
00226             gd = (float)gDiff/2;
00227             bd = (float)bDiff/2;
00228 
00229             for (y = 0; y < size.height(); y++, rd-=rfd, gd-=gfd, bd-=bfd)
00230             {
00231                 ytable[0][y] = (unsigned char) abs((int)rd);
00232                 ytable[1][y] = (unsigned char) abs((int)gd);
00233                 ytable[2][y] = (unsigned char) abs((int)bd);
00234             }
00235             unsigned int rgb;
00236             int h = (size.height()+1)>>1;
00237             for (y = 0; y < h; y++) {
00238                 unsigned int *sl1 = (unsigned int *)image.scanLine(y);
00239                 unsigned int *sl2 = (unsigned int *)image.scanLine(QMAX(size.height()-y-1, y));
00240 
00241                 int w = (size.width()+1)>>1;
00242                 int x2 = size.width()-1;
00243 
00244                 for (x = 0; x < w; x++, x2--) {
00245                     rgb = 0;
00246                     if (eff == PyramidGradient) {
00247                         rgb = qRgb(rcb-rSign*(xtable[0][x]+ytable[0][y]),
00248                                    gcb-gSign*(xtable[1][x]+ytable[1][y]),
00249                                    bcb-bSign*(xtable[2][x]+ytable[2][y]));
00250                     }
00251                     if (eff == RectangleGradient) {
00252                         rgb = qRgb(rcb - rSign *
00253                                    QMAX(xtable[0][x], ytable[0][y]) * 2,
00254                                    gcb - gSign *
00255                                    QMAX(xtable[1][x], ytable[1][y]) * 2,
00256                                    bcb - bSign *
00257                                    QMAX(xtable[2][x], ytable[2][y]) * 2);
00258                     }
00259                     if (eff == PipeCrossGradient) {
00260                         rgb = qRgb(rcb - rSign *
00261                                    QMIN(xtable[0][x], ytable[0][y]) * 2,
00262                                    gcb - gSign *
00263                                    QMIN(xtable[1][x], ytable[1][y]) * 2,
00264                                    bcb - bSign *
00265                                    QMIN(xtable[2][x], ytable[2][y]) * 2);
00266                     }
00267                     if (eff == EllipticGradient) {
00268                         rgb = qRgb(rcb - rSign *
00269                                    (int)sqrt((xtable[0][x]*xtable[0][x] +
00270                                               ytable[0][y]*ytable[0][y])*2.0),
00271                                    gcb - gSign *
00272                                    (int)sqrt((xtable[1][x]*xtable[1][x] +
00273                                               ytable[1][y]*ytable[1][y])*2.0),
00274                                    bcb - bSign *
00275                                    (int)sqrt((xtable[2][x]*xtable[2][x] +
00276                                               ytable[2][y]*ytable[2][y])*2.0));
00277                     }
00278 
00279                     sl1[x] = sl2[x] = rgb;
00280                     sl1[x2] = sl2[x2] = rgb;
00281                 }
00282             }
00283         }
00284 
00285         delete [] xtable[0];
00286         delete [] xtable[1];
00287         delete [] xtable[2];
00288         delete [] ytable[0];
00289         delete [] ytable[1];
00290         delete [] ytable[2];
00291     }
00292 
00293     // dither if necessary
00294     if (ncols && (QPixmap::defaultDepth() < 15 )) {
00295         if ( ncols < 2 || ncols > 256 )
00296             ncols = 3;
00297         QColor *dPal = new QColor[ncols];
00298         for (int i=0; i<ncols; i++) {
00299             dPal[i].setRgb ( rca + rDiff * i / ( ncols - 1 ),
00300                              gca + gDiff * i / ( ncols - 1 ),
00301                              bca + bDiff * i / ( ncols - 1 ) );
00302         }
00303     dither(image, dPal, ncols);
00304         delete [] dPal;
00305     }
00306 
00307     return image;
00308 }
00309 
00310 
00311 // -----------------------------------------------------------------------------
00312 
00313 //CT this was (before Dirk A. Mueller's speedup changes)
00314 //   merely the same code as in the above method, but it's supposedly
00315 //   way less performant since it introduces a lot of supplementary tests
00316 //   and simple math operations for the calculus of the balance.
00317 //      (surprizingly, it isn't less performant, in the contrary :-)
00318 //   Yes, I could have merged them, but then the excellent performance of
00319 //   the balanced code would suffer with no other gain than a mere
00320 //   source code and byte code size economy.
00321 
00322 QImage KImageEffect::unbalancedGradient(const QSize &size, const QColor &ca,
00323         const QColor &cb, GradientType eff, int xfactor, int yfactor,
00324         int ncols)
00325 {
00326     int dir; // general parameter used for direction switches
00327 
00328     bool _xanti = false , _yanti = false;
00329 
00330     if (xfactor < 0) _xanti = true; // negative on X direction
00331     if (yfactor < 0) _yanti = true; // negative on Y direction
00332 
00333     xfactor = abs(xfactor);
00334     yfactor = abs(yfactor);
00335 
00336     if (!xfactor) xfactor = 1;
00337     if (!yfactor) yfactor = 1;
00338 
00339     if (xfactor > 200 ) xfactor = 200;
00340     if (yfactor > 200 ) yfactor = 200;
00341 
00342 
00343     //    float xbal = xfactor/5000.;
00344     //    float ybal = yfactor/5000.;
00345     float xbal = xfactor/30./size.width();
00346     float ybal = yfactor/30./size.height();
00347     float rat;
00348 
00349     int rDiff, gDiff, bDiff;
00350     int rca, gca, bca, rcb, gcb, bcb;
00351 
00352     QImage image(size, 32);
00353 
00354     if (size.width() == 0 || size.height() == 0) {
00355 #ifndef NDEBUG
00356       cerr << "WARNING: KImageEffect::unbalancedGradient : invalid image\n";
00357 #endif
00358       return image;
00359     }
00360 
00361     register int x, y;
00362     unsigned int *scanline;
00363 
00364     rDiff = (rcb = cb.red())   - (rca = ca.red());
00365     gDiff = (gcb = cb.green()) - (gca = ca.green());
00366     bDiff = (bcb = cb.blue())  - (bca = ca.blue());
00367 
00368     if( eff == VerticalGradient || eff == HorizontalGradient){
00369         QColor cRow;
00370 
00371         uint *p;
00372         uint rgbRow;
00373 
00374         if( eff == VerticalGradient) {
00375           for ( y = 0; y < size.height(); y++ ) {
00376             dir = _yanti ? y : size.height() - 1 - y;
00377             p = (uint *) image.scanLine(dir);
00378             rat =  1 - exp( - (float)y  * ybal );
00379 
00380             cRow.setRgb( rcb - (int) ( rDiff * rat ),
00381                          gcb - (int) ( gDiff * rat ),
00382                          bcb - (int) ( bDiff * rat ) );
00383 
00384             rgbRow = cRow.rgb();
00385 
00386             for( x = 0; x < size.width(); x++ ) {
00387               *p = rgbRow;
00388               p++;
00389             }
00390           }
00391         }
00392         else {
00393 
00394           unsigned int *src = (unsigned int *)image.scanLine(0);
00395           for(x = 0; x < size.width(); x++ )
00396             {
00397               dir = _xanti ? x : size.width() - 1 - x;
00398               rat = 1 - exp( - (float)x  * xbal );
00399 
00400               src[dir] = qRgb(rcb - (int) ( rDiff * rat ),
00401                             gcb - (int) ( gDiff * rat ),
00402                             bcb - (int) ( bDiff * rat ));
00403             }
00404 
00405           // Believe it or not, manually copying in a for loop is faster
00406           // than calling memcpy for each scanline (on the order of ms...).
00407           // I think this is due to the function call overhead (mosfet).
00408 
00409           for(y = 1; y < size.height(); ++y)
00410             {
00411               scanline = (unsigned int *)image.scanLine(y);
00412               for(x=0; x < size.width(); ++x)
00413                 scanline[x] = src[x];
00414             }
00415         }
00416     }
00417 
00418     else {
00419       int w=size.width(), h=size.height();
00420 
00421       unsigned char *xtable[3];
00422       unsigned char *ytable[3];
00423       xtable[0] = new unsigned char[w];
00424       xtable[1] = new unsigned char[w];
00425       xtable[2] = new unsigned char[w];
00426       ytable[0] = new unsigned char[h];
00427       ytable[1] = new unsigned char[h];
00428       ytable[2] = new unsigned char[h];
00429 
00430       if ( eff == DiagonalGradient || eff == CrossDiagonalGradient)
00431         {
00432           for (x = 0; x < w; x++) {
00433               dir = _xanti ? x : w - 1 - x;
00434               rat = 1 - exp( - (float)x * xbal );
00435 
00436               xtable[0][dir] = (unsigned char) ( rDiff/2 * rat );
00437               xtable[1][dir] = (unsigned char) ( gDiff/2 * rat );
00438               xtable[2][dir] = (unsigned char) ( bDiff/2 * rat );
00439           }
00440 
00441           for (y = 0; y < h; y++) {
00442               dir = _yanti ? y : h - 1 - y;
00443               rat =  1 - exp( - (float)y  * ybal );
00444 
00445               ytable[0][dir] = (unsigned char) ( rDiff/2 * rat );
00446               ytable[1][dir] = (unsigned char) ( gDiff/2 * rat );
00447               ytable[2][dir] = (unsigned char) ( bDiff/2 * rat );
00448           }
00449 
00450           for (y = 0; y < h; y++) {
00451               unsigned int *scanline = (unsigned int *)image.scanLine(y);
00452               for (x = 0; x < w; x++) {
00453                   scanline[x] = qRgb(rcb - (xtable[0][x] + ytable[0][y]),
00454                                      gcb - (xtable[1][x] + ytable[1][y]),
00455                                      bcb - (xtable[2][x] + ytable[2][y]));
00456               }
00457           }
00458         }
00459 
00460       else if (eff == RectangleGradient ||
00461                eff == PyramidGradient ||
00462                eff == PipeCrossGradient ||
00463                eff == EllipticGradient)
00464       {
00465           int rSign = rDiff>0? 1: -1;
00466           int gSign = gDiff>0? 1: -1;
00467           int bSign = bDiff>0? 1: -1;
00468 
00469           for (x = 0; x < w; x++)
00470             {
00471                 dir = _xanti ? x : w - 1 - x;
00472                 rat =  1 - exp( - (float)x * xbal );
00473 
00474                 xtable[0][dir] = (unsigned char) abs((int)(rDiff*(0.5-rat)));
00475                 xtable[1][dir] = (unsigned char) abs((int)(gDiff*(0.5-rat)));
00476                 xtable[2][dir] = (unsigned char) abs((int)(bDiff*(0.5-rat)));
00477             }
00478 
00479           for (y = 0; y < h; y++)
00480           {
00481               dir = _yanti ? y : h - 1 - y;
00482 
00483               rat =  1 - exp( - (float)y * ybal );
00484 
00485               ytable[0][dir] = (unsigned char) abs((int)(rDiff*(0.5-rat)));
00486               ytable[1][dir] = (unsigned char) abs((int)(gDiff*(0.5-rat)));
00487               ytable[2][dir] = (unsigned char) abs((int)(bDiff*(0.5-rat)));
00488           }
00489 
00490           for (y = 0; y < h; y++) {
00491               unsigned int *scanline = (unsigned int *)image.scanLine(y);
00492               for (x = 0; x < w; x++) {
00493                   if (eff == PyramidGradient)
00494                   {
00495                       scanline[x] = qRgb(rcb-rSign*(xtable[0][x]+ytable[0][y]),
00496                                          gcb-gSign*(xtable[1][x]+ytable[1][y]),
00497                                          bcb-bSign*(xtable[2][x]+ytable[2][y]));
00498                   }
00499                   if (eff == RectangleGradient)
00500                   {
00501                       scanline[x] = qRgb(rcb - rSign *
00502                                          QMAX(xtable[0][x], ytable[0][y]) * 2,
00503                                          gcb - gSign *
00504                                          QMAX(xtable[1][x], ytable[1][y]) * 2,
00505                                          bcb - bSign *
00506                                          QMAX(xtable[2][x], ytable[2][y]) * 2);
00507                   }
00508                   if (eff == PipeCrossGradient)
00509                   {
00510                       scanline[x] = qRgb(rcb - rSign *
00511                                          QMIN(xtable[0][x], ytable[0][y]) * 2,
00512                                          gcb - gSign *
00513                                          QMIN(xtable[1][x], ytable[1][y]) * 2,
00514                                          bcb - bSign *
00515                                          QMIN(xtable[2][x], ytable[2][y]) * 2);
00516                   }
00517                   if (eff == EllipticGradient)
00518                   {
00519                       scanline[x] = qRgb(rcb - rSign *
00520                                          (int)sqrt((xtable[0][x]*xtable[0][x] +
00521                                                     ytable[0][y]*ytable[0][y])*2.0),
00522                                          gcb - gSign *
00523                                          (int)sqrt((xtable[1][x]*xtable[1][x] +
00524                                                     ytable[1][y]*ytable[1][y])*2.0),
00525                                          bcb - bSign *
00526                                          (int)sqrt((xtable[2][x]*xtable[2][x] +
00527                                                     ytable[2][y]*ytable[2][y])*2.0));
00528                   }
00529               }
00530           }
00531       }
00532 
00533       if (ncols && (QPixmap::defaultDepth() < 15 )) {
00534           if ( ncols < 2 || ncols > 256 )
00535               ncols = 3;
00536           QColor *dPal = new QColor[ncols];
00537           for (int i=0; i<ncols; i++) {
00538               dPal[i].setRgb ( rca + rDiff * i / ( ncols - 1 ),
00539                                gca + gDiff * i / ( ncols - 1 ),
00540                                bca + bDiff * i / ( ncols - 1 ) );
00541           }
00542           dither(image, dPal, ncols);
00543           delete [] dPal;
00544       }
00545 
00546       delete [] xtable[0];
00547       delete [] xtable[1];
00548       delete [] xtable[2];
00549       delete [] ytable[0];
00550       delete [] ytable[1];
00551       delete [] ytable[2];
00552 
00553     }
00554 
00555     return image;
00556 }
00557 
00558 
00559 //======================================================================
00560 //
00561 // Intensity effects
00562 //
00563 //======================================================================
00564 
00565 
00566 /* This builds a 256 byte unsigned char lookup table with all
00567  * the possible percent values prior to applying the effect, then uses
00568  * integer math for the pixels. For any image larger than 9x9 this will be
00569  * less expensive than doing a float operation on the 3 color components of
00570  * each pixel. (mosfet)
00571  */
00572 
00573 QImage& KImageEffect::intensity(QImage &image, float percent)
00574 {
00575     if (image.width() == 0 || image.height() == 0) {
00576 #ifndef NDEBUG
00577       cerr << "WARNING: KImageEffect::intensity : invalid image\n";
00578 #endif
00579       return image;
00580     }
00581 
00582     int segColors = image.depth() > 8 ? 256 : image.numColors();
00583     unsigned char *segTbl = new unsigned char[segColors];
00584     int pixels = image.depth() > 8 ? image.width()*image.height() :
00585         image.numColors();
00586     unsigned int *data = image.depth() > 8 ? (unsigned int *)image.bits() :
00587         (unsigned int *)image.colorTable();
00588 
00589     bool brighten = (percent >= 0);
00590     if(percent < 0)
00591         percent = -percent;
00592 
00593     if(brighten){ // keep overflow check out of loops
00594         for(int i=0; i < segColors; ++i){
00595             int tmp = (int)(i*percent);
00596             if(tmp > 255)
00597                 tmp = 255;
00598             segTbl[i] = tmp;
00599         }
00600     }
00601     else{
00602         for(int i=0; i < segColors; ++i){
00603             int tmp = (int)(i*percent);
00604             if(tmp < 0)
00605                 tmp = 0;
00606             segTbl[i] = tmp;
00607         }
00608     }
00609 
00610     if(brighten){ // same here
00611         for(int i=0; i < pixels; ++i){
00612             int r = qRed(data[i]);
00613             int g = qGreen(data[i]);
00614             int b = qBlue(data[i]);
00615             int a = qAlpha(data[i]);
00616             r = r + segTbl[r] > 255 ? 255 : r + segTbl[r];
00617             g = g + segTbl[g] > 255 ? 255 : g + segTbl[g];
00618             b = b + segTbl[b] > 255 ? 255 : b + segTbl[b];
00619             data[i] = qRgba(r, g, b,a);
00620         }
00621     }
00622     else{
00623         for(int i=0; i < pixels; ++i){
00624             int r = qRed(data[i]);
00625             int g = qGreen(data[i]);
00626             int b = qBlue(data[i]);
00627             int a = qAlpha(data[i]);
00628             r = r - segTbl[r] < 0 ? 0 : r - segTbl[r];
00629             g = g - segTbl[g] < 0 ? 0 : g - segTbl[g];
00630             b = b - segTbl[b] < 0 ? 0 : b - segTbl[b];
00631             data[i] = qRgba(r, g, b, a);
00632         }
00633     }
00634     delete [] segTbl;
00635 
00636     return image;
00637 }
00638 
00639 QImage& KImageEffect::channelIntensity(QImage &image, float percent,
00640                                        RGBComponent channel)
00641 {
00642     if (image.width() == 0 || image.height() == 0) {
00643 #ifndef NDEBUG
00644       cerr << "WARNING: KImageEffect::channelIntensity : invalid image\n";
00645 #endif
00646       return image;
00647     }
00648 
00649     int segColors = image.depth() > 8 ? 256 : image.numColors();
00650     unsigned char *segTbl = new unsigned char[segColors];
00651     int pixels = image.depth() > 8 ? image.width()*image.height() :
00652         image.numColors();
00653     unsigned int *data = image.depth() > 8 ? (unsigned int *)image.bits() :
00654         (unsigned int *)image.colorTable();
00655     bool brighten = (percent >= 0);
00656     if(percent < 0)
00657         percent = -percent;
00658 
00659     if(brighten){ // keep overflow check out of loops
00660         for(int i=0; i < segColors; ++i){
00661             int tmp = (int)(i*percent);
00662             if(tmp > 255)
00663                 tmp = 255;
00664             segTbl[i] = tmp;
00665         }
00666     }
00667     else{
00668         for(int i=0; i < segColors; ++i){
00669             int tmp = (int)(i*percent);
00670             if(tmp < 0)
00671                 tmp = 0;
00672             segTbl[i] = tmp;
00673         }
00674     }
00675 
00676     if(brighten){ // same here
00677         if(channel == Red){ // and here ;-)
00678             for(int i=0; i < pixels; ++i){
00679                 int c = qRed(data[i]);
00680                 c = c + segTbl[c] > 255 ? 255 : c + segTbl[c];
00681                 data[i] = qRgba(c, qGreen(data[i]), qBlue(data[i]), qAlpha(data[i]));
00682             }
00683         }
00684         if(channel == Green){
00685             for(int i=0; i < pixels; ++i){
00686                 int c = qGreen(data[i]);
00687                 c = c + segTbl[c] > 255 ? 255 : c + segTbl[c];
00688                 data[i] = qRgba(qRed(data[i]), c, qBlue(data[i]), qAlpha(data[i]));
00689             }
00690         }
00691         else{
00692             for(int i=0; i < pixels; ++i){
00693                 int c = qBlue(data[i]);
00694                 c = c + segTbl[c] > 255 ? 255 : c + segTbl[c];
00695                 data[i] = qRgba(qRed(data[i]), qGreen(data[i]), c, qAlpha(data[i]));
00696             }
00697         }
00698 
00699     }
00700     else{
00701         if(channel == Red){
00702             for(int i=0; i < pixels; ++i){
00703                 int c = qRed(data[i]);
00704                 c = c - segTbl[c] < 0 ? 0 : c - segTbl[c];
00705                 data[i] = qRgba(c, qGreen(data[i]), qBlue(data[i]), qAlpha(data[i]));
00706             }
00707         }
00708         if(channel == Green){
00709             for(int i=0; i < pixels; ++i){
00710                 int c = qGreen(data[i]);
00711                 c = c - segTbl[c] < 0 ? 0 : c - segTbl[c];
00712                 data[i] = qRgba(qRed(data[i]), c, qBlue(data[i]), qAlpha(data[i]));
00713             }
00714         }
00715         else{
00716             for(int i=0; i < pixels; ++i){
00717                 int c = qBlue(data[i]);
00718                 c = c - segTbl[c] < 0 ? 0 : c - segTbl[c];
00719                 data[i] = qRgba(qRed(data[i]), qGreen(data[i]), c, qAlpha(data[i]));
00720             }
00721         }
00722     }
00723     delete [] segTbl;
00724 
00725     return image;
00726 }
00727 
00728 // Modulate an image with an RBG channel of another image
00729 //
00730 QImage& KImageEffect::modulate(QImage &image, QImage &modImage, bool reverse,
00731         ModulationType type, int factor, RGBComponent channel)
00732 {
00733     if (image.width() == 0 || image.height() == 0 ||
00734         modImage.width() == 0 || modImage.height() == 0) {
00735 #ifndef NDEBUG
00736       cerr << "WARNING: KImageEffect::modulate : invalid image\n";
00737 #endif
00738       return image;
00739     }
00740 
00741     int r, g, b, h, s, v, a;
00742     QColor clr;
00743     int mod=0;
00744     unsigned int x1, x2, y1, y2;
00745     register int x, y;
00746 
00747     // for image, we handle only depth 32
00748     if (image.depth()<32) image = image.convertDepth(32);
00749 
00750     // for modImage, we handle depth 8 and 32
00751     if (modImage.depth()<8) modImage = modImage.convertDepth(8);
00752 
00753     unsigned int *colorTable2 = (modImage.depth()==8) ?
00754                                  modImage.colorTable():0;
00755     unsigned int *data1, *data2;
00756     unsigned char *data2b;
00757     unsigned int color1, color2;
00758 
00759     x1 = image.width();    y1 = image.height();
00760     x2 = modImage.width(); y2 = modImage.height();
00761 
00762     for (y = 0; y < (int)y1; y++) {
00763         data1 =  (unsigned int *) image.scanLine(y);
00764         data2 =  (unsigned int *) modImage.scanLine( y%y2 );
00765         data2b = (unsigned char *) modImage.scanLine( y%y2 );
00766 
00767         x=0;
00768         while(x < (int)x1) {
00769           color2 = (colorTable2) ? colorTable2[*data2b] : *data2;
00770           if (reverse) {
00771               color1 = color2;
00772               color2 = *data1;
00773           }
00774           else
00775               color1 = *data1;
00776 
00777           if (type == Intensity || type == Contrast) {
00778               r = qRed(color1);
00779               g = qGreen(color1);
00780               b = qBlue(color1);
00781               if (channel != All) {
00782                 mod = (channel == Red) ? qRed(color2) :
00783                     (channel == Green) ? qGreen(color2) :
00784                     (channel == Blue) ? qBlue(color2) :
00785                     (channel == Gray) ? qGray(color2) : 0;
00786                 mod = mod*factor/50;
00787               }
00788 
00789               if (type == Intensity) {
00790                 if (channel == All) {
00791                   r += r * factor/50 * qRed(color2)/256;
00792                   g += g * factor/50 * qGreen(color2)/256;
00793                   b += b * factor/50 * qBlue(color2)/256;
00794                 }
00795                 else {
00796                   r += r * mod/256;
00797                   g += g * mod/256;
00798                   b += b * mod/256;
00799                 }
00800               }
00801               else { // Contrast
00802                 if (channel == All) {
00803                   r += (r-128) * factor/50 * qRed(color2)/128;
00804                   g += (g-128) * factor/50 * qGreen(color2)/128;
00805                   b += (b-128) * factor/50 * qBlue(color2)/128;
00806                 }
00807                 else {
00808                   r += (r-128) * mod/128;
00809                   g += (g-128) * mod/128;
00810                   b += (b-128) * mod/128;
00811                 }
00812               }
00813 
00814               if (r<0) r=0; if (r>255) r=255;
00815               if (g<0) g=0; if (g>255) g=255;
00816               if (b<0) b=0; if (b>255) b=255;
00817               a = qAlpha(*data1);
00818               *data1 = qRgba(r, g, b, a);
00819           }
00820           else if (type == Saturation || type == HueShift) {
00821               clr.setRgb(color1);
00822               clr.hsv(&h, &s, &v);
00823               mod = (channel == Red) ? qRed(color2) :
00824                     (channel == Green) ? qGreen(color2) :
00825                     (channel == Blue) ? qBlue(color2) :
00826                     (channel == Gray) ? qGray(color2) : 0;
00827               mod = mod*factor/50;
00828 
00829               if (type == Saturation) {
00830                   s -= s * mod/256;
00831                   if (s<0) s=0; if (s>255) s=255;
00832               }
00833               else { // HueShift
00834                 h += mod;
00835                 while(h<0) h+=360;
00836                 h %= 360;
00837               }
00838 
00839               clr.setHsv(h, s, v);
00840               a = qAlpha(*data1);
00841               *data1 = clr.rgb() | ((uint)(a & 0xff) << 24);
00842           }
00843           data1++; data2++; data2b++; x++;
00844           if ( (x%x2) ==0) { data2 -= x2; data2b -= x2; }
00845         }
00846     }
00847     return image;
00848 }
00849 
00850 
00851 
00852 //======================================================================
00853 //
00854 // Blend effects
00855 //
00856 //======================================================================
00857 
00858 
00859 // Nice and fast direct pixel manipulation
00860 QImage& KImageEffect::blend(const QColor& clr, QImage& dst, float opacity)
00861 {
00862     if (dst.width() <= 0 || dst.height() <= 0)
00863         return dst;
00864 
00865     if (opacity < 0.0 || opacity > 1.0) {
00866 #ifndef NDEBUG
00867         cerr << "WARNING: KImageEffect::blend : invalid opacity. Range [0, 1]\n";
00868 #endif
00869         return dst;
00870     }
00871 
00872     int depth = dst.depth();
00873     if (depth != 32)
00874         dst = dst.convertDepth(32);
00875 
00876     int pixels = dst.width() * dst.height();
00877     int rcol, gcol, bcol;
00878     clr.rgb(&rcol, &gcol, &bcol);
00879 
00880 #ifdef WORDS_BIGENDIAN   // ARGB (skip alpha)
00881     register unsigned char *data = (unsigned char *)dst.bits() + 1;
00882 #else                    // BGRA
00883     register unsigned char *data = (unsigned char *)dst.bits();
00884 #endif
00885 
00886     for (register int i=0; i<pixels; i++)
00887     {
00888 #ifdef WORDS_BIGENDIAN
00889         *(data++) += (unsigned char)((rcol - *data) * opacity);
00890         *(data++) += (unsigned char)((gcol - *data) * opacity);
00891         *(data++) += (unsigned char)((bcol - *data) * opacity);
00892 #else
00893         *(data++) += (unsigned char)((bcol - *data) * opacity);
00894         *(data++) += (unsigned char)((gcol - *data) * opacity);
00895         *(data++) += (unsigned char)((rcol - *data) * opacity);
00896 #endif
00897         data++; // skip alpha
00898     }
00899     return dst;
00900 }
00901 
00902 // Nice and fast direct pixel manipulation
00903 QImage& KImageEffect::blend(QImage& src, QImage& dst, float opacity)
00904 {
00905     if (src.width() <= 0 || src.height() <= 0)
00906         return dst;
00907     if (dst.width() <= 0 || dst.height() <= 0)
00908         return dst;
00909 
00910     if (src.width() != dst.width() || src.height() != dst.height()) {
00911 #ifndef NDEBUG
00912         cerr << "WARNING: KImageEffect::blend : src and destination images are not the same size\n";
00913 #endif
00914         return dst;
00915     }
00916 
00917     if (opacity < 0.0 || opacity > 1.0) {
00918 #ifndef NDEBUG
00919         cerr << "WARNING: KImageEffect::blend : invalid opacity. Range [0, 1]\n";
00920 #endif
00921         return dst;
00922     }
00923 
00924     if (src.depth() != 32) src = src.convertDepth(32);
00925     if (dst.depth() != 32) dst = dst.convertDepth(32);
00926 
00927     int pixels = src.width() * src.height();
00928 #ifdef WORDS_BIGENDIAN   // ARGB (skip alpha)
00929     register unsigned char *data1 = (unsigned char *)dst.bits() + 1;
00930     register unsigned char *data2 = (unsigned char *)src.bits() + 1;
00931 #else                    // BGRA
00932     register unsigned char *data1 = (unsigned char *)dst.bits();
00933     register unsigned char *data2 = (unsigned char *)src.bits();
00934 #endif
00935 
00936     for (register int i=0; i<pixels; i++)
00937     {
00938 #ifdef WORDS_BIGENDIAN
00939         *(data1++) += (unsigned char)((*(data2++) - *data1) * opacity);
00940         *(data1++) += (unsigned char)((*(data2++) - *data1) * opacity);
00941         *(data1++) += (unsigned char)((*(data2++) - *data1) * opacity);
00942 #else
00943         *(data1++) += (unsigned char)((*(data2++) - *data1) * opacity);
00944         *(data1++) += (unsigned char)((*(data2++) - *data1) * opacity);
00945         *(data1++) += (unsigned char)((*(data2++) - *data1) * opacity);
00946 #endif
00947         data1++; // skip alpha
00948         data2++;
00949     }
00950 
00951     return dst;
00952 }
00953 
00954 
00955 QImage& KImageEffect::blend(QImage &image, float initial_intensity,
00956                             const QColor &bgnd, GradientType eff,
00957                             bool anti_dir)
00958 {
00959     if (image.width() == 0 || image.height() == 0 || image.depth()!=32 ) {
00960 #ifndef NDEBUG
00961       cerr << "WARNING: KImageEffect::blend : invalid image\n";
00962 #endif
00963       return image;
00964     }
00965 
00966     int r_bgnd = bgnd.red(), g_bgnd = bgnd.green(), b_bgnd = bgnd.blue();
00967     int r, g, b;
00968     int ind;
00969 
00970     unsigned int xi, xf, yi, yf;
00971     unsigned int a;
00972 
00973     // check the boundaries of the initial intesity param
00974     float unaffected = 1;
00975     if (initial_intensity >  1) initial_intensity =  1;
00976     if (initial_intensity < -1) initial_intensity = -1;
00977     if (initial_intensity < 0) {
00978         unaffected = 1. + initial_intensity;
00979         initial_intensity = 0;
00980     }
00981 
00982 
00983     float intensity = initial_intensity;
00984     float var = 1. - initial_intensity;
00985 
00986     if (anti_dir) {
00987         initial_intensity = intensity = 1.;
00988         var = -var;
00989     }
00990 
00991     register int x, y;
00992 
00993     unsigned int *data =  (unsigned int *)image.bits();
00994 
00995     int image_width = image.width(); //Those can't change
00996     int image_height = image.height();
00997 
00998 
00999     if( eff == VerticalGradient || eff == HorizontalGradient ) {
01000 
01001         // set the image domain to apply the effect to
01002         xi = 0, xf = image_width;
01003         yi = 0, yf = image_height;
01004         if (eff == VerticalGradient) {
01005             if (anti_dir) yf = (int)(image_height * unaffected);
01006             else yi = (int)(image_height * (1 - unaffected));
01007         }
01008         else {
01009             if (anti_dir) xf = (int)(image_width * unaffected);
01010             else xi = (int)(image_height * (1 - unaffected));
01011         }
01012 
01013         var /= (eff == VerticalGradient?yf-yi:xf-xi);
01014 
01015         int ind_base;
01016         for (y = yi; y < (int)yf; y++) {
01017             intensity = eff == VerticalGradient? intensity + var :
01018                 initial_intensity;
01019             ind_base = image_width  * y ;
01020             for (x = xi; x < (int)xf ; x++) {
01021                 if (eff == HorizontalGradient) intensity += var;
01022                 ind = x + ind_base;
01023                 r = qRed  (data[ind]) + (int)(intensity *
01024                                               (r_bgnd - qRed  (data[ind])));
01025                 g = qGreen(data[ind]) + (int)(intensity *
01026                                               (g_bgnd - qGreen(data[ind])));
01027                 b = qBlue (data[ind]) + (int)(intensity *
01028                                               (b_bgnd - qBlue (data[ind])));
01029                 if (r > 255) r = 255; if (r < 0 ) r = 0;
01030                 if (g > 255) g = 255; if (g < 0 ) g = 0;
01031                 if (b > 255) b = 255; if (b < 0 ) b = 0;
01032                 a = qAlpha(data[ind]);
01033                 data[ind] = qRgba(r, g, b, a);
01034             }
01035         }
01036     }
01037     else if (eff == DiagonalGradient  || eff == CrossDiagonalGradient) {
01038         float xvar = var / 2 / image_width;  // / unaffected;
01039         float yvar = var / 2 / image_height; // / unaffected;
01040         float tmp;
01041 
01042         for (x = 0; x < image_width ; x++) {
01043             tmp =  xvar * (eff == DiagonalGradient? x : image.width()-x-1);
01044             ind = x;
01045             for (y = 0; y < image_height ; y++) {
01046                 intensity = initial_intensity + tmp + yvar * y;
01047 
01048                 r = qRed  (data[ind]) + (int)(intensity *
01049                                               (r_bgnd - qRed  (data[ind])));
01050                 g = qGreen(data[ind]) + (int)(intensity *
01051                                               (g_bgnd - qGreen(data[ind])));
01052                 b = qBlue (data[ind]) + (int)(intensity *
01053                                               (b_bgnd - qBlue (data[ind])));
01054                 if (r > 255) r = 255; if (r < 0 ) r = 0;
01055                 if (g > 255) g = 255; if (g < 0 ) g = 0;
01056                 if (b > 255) b = 255; if (b < 0 ) b = 0;
01057                 a = qAlpha(data[ind]);
01058                 data[ind] = qRgba(r, g, b, a);
01059 
01060                 ind += image_width;
01061             }
01062         }
01063     }
01064 
01065     else if (eff == RectangleGradient || eff == EllipticGradient) {
01066         float xvar;
01067         float yvar;
01068 
01069         for (x = 0; x < image_width / 2 + image_width % 2; x++) {
01070             xvar = var / image_width  * (image_width - x*2/unaffected-1);
01071             for (y = 0; y < image_height / 2 + image_height % 2; y++) {
01072                 yvar = var / image_height   * (image_height - y*2/unaffected -1);
01073 
01074                 if (eff == RectangleGradient)
01075                     intensity = initial_intensity + QMAX(xvar, yvar);
01076                 else
01077                     intensity = initial_intensity + sqrt(xvar * xvar + yvar * yvar);
01078                 if (intensity > 1) intensity = 1;
01079                 if (intensity < 0) intensity = 0;
01080 
01081                 //NW
01082                 ind = x + image_width  * y ;
01083                 r = qRed  (data[ind]) + (int)(intensity *
01084                                               (r_bgnd - qRed  (data[ind])));
01085                 g = qGreen(data[ind]) + (int)(intensity *
01086                                               (g_bgnd - qGreen(data[ind])));
01087                 b = qBlue (data[ind]) + (int)(intensity *
01088                                               (b_bgnd - qBlue (data[ind])));
01089                 if (r > 255) r = 255; if (r < 0 ) r = 0;
01090                 if (g > 255) g = 255; if (g < 0 ) g = 0;
01091                 if (b > 255) b = 255; if (b < 0 ) b = 0;
01092                 a = qAlpha(data[ind]);
01093                 data[ind] = qRgba(r, g, b, a);
01094 
01095                 //NE
01096                 ind = image_width - x - 1 + image_width  * y ;
01097                 r = qRed  (data[ind]) + (int)(intensity *
01098                                               (r_bgnd - qRed  (data[ind])));
01099                 g = qGreen(data[ind]) + (int)(intensity *
01100                                               (g_bgnd - qGreen(data[ind])));
01101                 b = qBlue (data[ind]) + (int)(intensity *
01102                                               (b_bgnd - qBlue (data[ind])));
01103                 if (r > 255) r = 255; if (r < 0 ) r = 0;
01104                 if (g > 255) g = 255; if (g < 0 ) g = 0;
01105                 if (b > 255) b = 255; if (b < 0 ) b = 0;
01106                 a = qAlpha(data[ind]);
01107                 data[ind] = qRgba(r, g, b, a);
01108             }
01109         }
01110 
01111         //CT  loop is doubled because of stupid central row/column issue.
01112         //    other solution?
01113         for (x = 0; x < image_width / 2; x++) {
01114             xvar = var / image_width  * (image_width - x*2/unaffected-1);
01115             for (y = 0; y < image_height / 2; y++) {
01116                 yvar = var / image_height   * (image_height - y*2/unaffected -1);
01117 
01118                 if (eff == RectangleGradient)
01119                     intensity = initial_intensity + QMAX(xvar, yvar);
01120                 else
01121                     intensity = initial_intensity + sqrt(xvar * xvar + yvar * yvar);
01122                 if (intensity > 1) intensity = 1;
01123                 if (intensity < 0) intensity = 0;
01124 
01125                 //SW
01126                 ind = x + image_width  * (image_height - y -1) ;
01127                 r = qRed  (data[ind]) + (int)(intensity *
01128                                               (r_bgnd - qRed  (data[ind])));
01129                 g = qGreen(data[ind]) + (int)(intensity *
01130                                               (g_bgnd - qGreen(data[ind])));
01131                 b = qBlue (data[ind]) + (int)(intensity *
01132                                               (b_bgnd - qBlue (data[ind])));
01133                 if (r > 255) r = 255; if (r < 0 ) r = 0;
01134                 if (g > 255) g = 255; if (g < 0 ) g = 0;
01135                 if (b > 255) b = 255; if (b < 0 ) b = 0;
01136                 a = qAlpha(data[ind]);
01137                 data[ind] = qRgba(r, g, b, a);
01138 
01139                 //SE
01140                 ind = image_width-x-1 + image_width * (image_height - y - 1) ;
01141                 r = qRed  (data[ind]) + (int)(intensity *
01142                                               (r_bgnd - qRed  (data[ind])));
01143                 g = qGreen(data[ind]) + (int)(intensity *
01144                                               (g_bgnd - qGreen(data[ind])));
01145                 b = qBlue (data[ind]) + (int)(intensity *
01146                                               (b_bgnd - qBlue (data[ind])));
01147                 if (r > 255) r = 255; if (r < 0 ) r = 0;
01148                 if (g > 255) g = 255; if (g < 0 ) g = 0;
01149                 if (b > 255) b = 255; if (b < 0 ) b = 0;
01150                 a = qAlpha(data[ind]);
01151                 data[ind] = qRgba(r, g, b, a);
01152             }
01153         }
01154     }
01155 #ifndef NDEBUG
01156     else cerr << "KImageEffect::blend effect not implemented" << endl;
01157 #endif
01158     return image;
01159 }
01160 
01161 // Not very efficient as we create a third big image...
01162 //
01163 QImage& KImageEffect::blend(QImage &image1, QImage &image2,
01164                             GradientType gt, int xf, int yf)
01165 {
01166   if (image1.width() == 0 || image1.height() == 0 ||
01167       image2.width() == 0 || image2.height() == 0)
01168     return image1;
01169 
01170   QImage image3;
01171 
01172   image3 = KImageEffect::unbalancedGradient(image1.size(),
01173                                     QColor(0,0,0), QColor(255,255,255),
01174                                     gt, xf, yf, 0);
01175 
01176   return blend(image1,image2,image3, Red); // Channel to use is arbitrary
01177 }
01178 
01179 // Blend image2 into image1, using an RBG channel of blendImage
01180 //
01181 QImage& KImageEffect::blend(QImage &image1, QImage &image2,
01182                             QImage &blendImage, RGBComponent channel)
01183 {
01184     if (image1.width() == 0 || image1.height() == 0 ||
01185         image2.width() == 0 || image2.height() == 0 ||
01186         blendImage.width() == 0 || blendImage.height() == 0) {
01187 #ifndef NDEBUG
01188       cerr << "KImageEffect::blend effect invalid image" << endl;
01189 #endif
01190       return image1;
01191     }
01192 
01193     int r, g, b;
01194     int ind1, ind2, ind3;
01195 
01196     unsigned int x1, x2, x3, y1, y2, y3;
01197     unsigned int a;
01198 
01199     register int x, y;
01200 
01201     // for image1 and image2, we only handle depth 32
01202     if (image1.depth()<32) image1 = image1.convertDepth(32);
01203     if (image2.depth()<32) image2 = image2.convertDepth(32);
01204 
01205     // for blendImage, we handle depth 8 and 32
01206     if (blendImage.depth()<8) blendImage = blendImage.convertDepth(8);
01207 
01208     unsigned int *colorTable3 = (blendImage.depth()==8) ?
01209                                  blendImage.colorTable():0;
01210 
01211     unsigned int *data1 =  (unsigned int *)image1.bits();
01212     unsigned int *data2 =  (unsigned int *)image2.bits();
01213     unsigned int *data3   =  (unsigned int *)blendImage.bits();
01214     unsigned char *data3b =  (unsigned char *)blendImage.bits();
01215     unsigned int color3;
01216 
01217     x1 = image1.width();     y1 = image1.height();
01218     x2 = image2.width();     y2 = image2.height();
01219     x3 = blendImage.width(); y3 = blendImage.height();
01220 
01221     for (y = 0; y < (int)y1; y++) {
01222         ind1 = x1*y;
01223         ind2 = x2*(y%y2);
01224         ind3 = x3*(y%y3);
01225 
01226         x=0;
01227         while(x < (int)x1) {
01228           color3 = (colorTable3) ? colorTable3[data3b[ind3]] : data3[ind3];
01229 
01230           a = (channel == Red) ? qRed(color3) :
01231               (channel == Green) ? qGreen(color3) :
01232               (channel == Blue) ? qBlue(color3) : qGray(color3);
01233 
01234           r = (a*qRed(data1[ind1]) + (256-a)*qRed(data2[ind2]))/256;
01235           g = (a*qGreen(data1[ind1]) + (256-a)*qGreen(data2[ind2]))/256;
01236           b = (a*qBlue(data1[ind1]) + (256-a)*qBlue(data2[ind2]))/256;
01237 
01238           a = qAlpha(data1[ind1]);
01239           data1[ind1] = qRgba(r, g, b, a);
01240 
01241           ind1++; ind2++; ind3++; x++;
01242           if ( (x%x2) ==0) ind2 -= x2;
01243           if ( (x%x3) ==0) ind3 -= x3;
01244         }
01245     }
01246     return image1;
01247 }
01248 
01249 
01250 //======================================================================
01251 //
01252 // Hash effects
01253 //
01254 //======================================================================
01255 
01256 unsigned int KImageEffect::lHash(unsigned int c)
01257 {
01258     unsigned char r = qRed(c), g = qGreen(c), b = qBlue(c), a = qAlpha(c);
01259     unsigned char nr, ng, nb;
01260     nr =(r >> 1) + (r >> 2); nr = nr > r ? 0 : nr;
01261     ng =(g >> 1) + (g >> 2); ng = ng > g ? 0 : ng;
01262     nb =(b >> 1) + (b >> 2); nb = nb > b ? 0 : nb;
01263 
01264     return qRgba(nr, ng, nb, a);
01265 }
01266 
01267 
01268 // -----------------------------------------------------------------------------
01269 
01270 unsigned int KImageEffect::uHash(unsigned int c)
01271 {
01272     unsigned char r = qRed(c), g = qGreen(c), b = qBlue(c), a = qAlpha(c);
01273     unsigned char nr, ng, nb;
01274     nr = r + (r >> 3); nr = nr < r ? ~0 : nr;
01275     ng = g + (g >> 3); ng = ng < g ? ~0 : ng;
01276     nb = b + (b >> 3); nb = nb < b ? ~0 : nb;
01277 
01278     return qRgba(nr, ng, nb, a);
01279 }
01280 
01281 
01282 // -----------------------------------------------------------------------------
01283 
01284 QImage& KImageEffect::hash(QImage &image, Lighting lite, unsigned int spacing)
01285 {
01286     if (image.width() == 0 || image.height() == 0) {
01287 #ifndef NDEBUG
01288       cerr << "KImageEffect::hash effect invalid image" << endl;
01289 #endif
01290       return image;
01291     }
01292 
01293     register int x, y;
01294     unsigned int *data =  (unsigned int *)image.bits();
01295     unsigned int ind;
01296 
01297     //CT no need to do it if not enough space
01298     if ((lite == NorthLite ||
01299          lite == SouthLite)&&
01300         (unsigned)image.height() < 2+spacing) return image;
01301     if ((lite == EastLite ||
01302          lite == WestLite)&&
01303         (unsigned)image.height() < 2+spacing) return image;
01304 
01305     if (lite == NorthLite || lite == SouthLite) {
01306         for (y = 0 ; y < image.height(); y = y + 2 + spacing) {
01307             for (x = 0; x < image.width(); x++) {
01308                 ind = x + image.width() * y;
01309                 data[ind] = lite==NorthLite?uHash(data[ind]):lHash(data[ind]);
01310 
01311                 ind = ind + image.width();
01312                 data[ind] = lite==NorthLite?lHash(data[ind]):uHash(data[ind]);
01313             }
01314         }
01315     }
01316 
01317     else if (lite == EastLite || lite == WestLite) {
01318         for (y = 0 ; y < image.height(); y++) {
01319             for (x = 0; x < image.width(); x = x + 2 + spacing) {
01320                 ind = x + image.width() * y;
01321                 data[ind] = lite==EastLite?uHash(data[ind]):lHash(data[ind]);
01322 
01323                 ind++;
01324                 data[ind] = lite==EastLite?lHash(data[ind]):uHash(data[ind]);
01325             }
01326         }
01327     }
01328 
01329     else if (lite == NWLite || lite == SELite) {
01330         for (y = 0 ; y < image.height(); y++) {
01331             for (x = 0;
01332                  x < (int)(image.width() - ((y & 1)? 1 : 0) * spacing);
01333                  x = x + 2 + spacing) {
01334                 ind = x + image.width() * y + ((y & 1)? 1 : 0);
01335                 data[ind] = lite==NWLite?uHash(data[ind]):lHash(data[ind]);
01336 
01337                 ind++;
01338                 data[ind] = lite==NWLite?lHash(data[ind]):uHash(data[ind]);
01339             }
01340         }
01341     }
01342 
01343     else if (lite == SWLite || lite == NELite) {
01344         for (y = 0 ; y < image.height(); y++) {
01345             for (x = 0  + ((y & 1)? 1 : 0); x < image.width(); x = x + 2 + spacing) {
01346                 ind = x + image.width() * y - ((y & 1)? 1 : 0);
01347                 data[ind] = lite==SWLite?uHash(data[ind]):lHash(data[ind]);
01348 
01349                 ind++;
01350                 data[ind] = lite==SWLite?lHash(data[ind]):uHash(data[ind]);
01351             }
01352         }
01353     }
01354 
01355     return image;
01356 }
01357 
01358 
01359 //======================================================================
01360 //
01361 // Flatten effects
01362 //
01363 //======================================================================
01364 
01365 QImage& KImageEffect::flatten(QImage &img, const QColor &ca,
01366                             const QColor &cb, int ncols)
01367 {
01368     if (img.width() == 0 || img.height() == 0)
01369       return img;
01370 
01371     // a bitmap is easy...
01372     if (img.depth() == 1) {
01373         img.setColor(0, ca.rgb());
01374         img.setColor(1, cb.rgb());
01375         return img;
01376     }
01377 
01378     int r1 = ca.red(); int r2 = cb.red();
01379     int g1 = ca.green(); int g2 = cb.green();
01380     int b1 = ca.blue(); int b2 = cb.blue();
01381     int min = 0, max = 255;
01382 
01383     QRgb col;
01384 
01385     // Get minimum and maximum greylevel.
01386     if (img.numColors()) {
01387         // pseudocolor
01388         for (int i = 0; i < img.numColors(); i++) {
01389             col = img.color(i);
01390             int mean = (qRed(col) + qGreen(col) + qBlue(col)) / 3;
01391             min = QMIN(min, mean);
01392             max = QMAX(max, mean);
01393         }
01394     } else {
01395         // truecolor
01396         for (int y=0; y < img.height(); y++)
01397             for (int x=0; x < img.width(); x++) {
01398                 col = img.pixel(x, y);
01399                 int mean = (qRed(col) + qGreen(col) + qBlue(col)) / 3;
01400                 min = QMIN(min, mean);
01401                 max = QMAX(max, mean);
01402             }
01403     }
01404 
01405     // Conversion factors
01406     float sr = ((float) r2 - r1) / (max - min);
01407     float sg = ((float) g2 - g1) / (max - min);
01408     float sb = ((float) b2 - b1) / (max - min);
01409 
01410 
01411     // Repaint the image
01412     if (img.numColors()) {
01413         for (int i=0; i < img.numColors(); i++) {
01414             col = img.color(i);
01415             int mean = (qRed(col) + qGreen(col) + qBlue(col)) / 3;
01416             int r = (int) (sr * (mean - min) + r1 + 0.5);
01417             int g = (int) (sg * (mean - min) + g1 + 0.5);
01418             int b = (int) (sb * (mean - min) + b1 + 0.5);
01419             img.setColor(i, qRgba(r, g, b, qAlpha(col)));
01420         }
01421     } else {
01422         for (int y=0; y < img.height(); y++)
01423             for (int x=0; x < img.width(); x++) {
01424                 col = img.pixel(x, y);
01425                 int mean = (qRed(col) + qGreen(col) + qBlue(col)) / 3;
01426                 int r = (int) (sr * (mean - min) + r1 + 0.5);
01427                 int g = (int) (sg * (mean - min) + g1 + 0.5);
01428                 int b = (int) (sb * (mean - min) + b1 + 0.5);
01429                 img.setPixel(x, y, qRgba(r, g, b, qAlpha(col)));
01430             }
01431     }
01432 
01433 
01434     // Dither if necessary
01435     if ( (ncols <= 0) || ((img.numColors() != 0) && (img.numColors() <= ncols)))
01436         return img;
01437 
01438     if (ncols == 1) ncols++;
01439     if (ncols > 256) ncols = 256;
01440 
01441     QColor *pal = new QColor[ncols];
01442     sr = ((float) r2 - r1) / (ncols - 1);
01443     sg = ((float) g2 - g1) / (ncols - 1);
01444     sb = ((float) b2 - b1) / (ncols - 1);
01445 
01446     for (int i=0; i<ncols; i++)
01447         pal[i] = QColor(r1 + int(sr*i), g1 + int(sg*i), b1 + int(sb*i));
01448 
01449     dither(img, pal, ncols);
01450 
01451     delete[] pal;
01452     return img;
01453 }
01454 
01455 
01456 //======================================================================
01457 //
01458 // Fade effects
01459 //
01460 //======================================================================
01461 
01462 QImage& KImageEffect::fade(QImage &img, float val, const QColor &color)
01463 {
01464     if (img.width() == 0 || img.height() == 0)
01465       return img;
01466 
01467     // We don't handle bitmaps
01468     if (img.depth() == 1)
01469         return img;
01470 
01471     unsigned char tbl[256];
01472     for (int i=0; i<256; i++)
01473         tbl[i] = (int) (val * i + 0.5);
01474 
01475     int red = color.red();
01476     int green = color.green();
01477     int blue = color.blue();
01478 
01479     QRgb col;
01480     int r, g, b, cr, cg, cb;
01481 
01482     if (img.depth() <= 8) {
01483         // pseudo color
01484         for (int i=0; i<img.numColors(); i++) {
01485             col = img.color(i);
01486             cr = qRed(col); cg = qGreen(col); cb = qBlue(col);
01487             if (cr > red)
01488                 r = cr - tbl[cr - red];
01489             else
01490                 r = cr + tbl[red - cr];
01491             if (cg > green)
01492                 g = cg - tbl[cg - green];
01493             else
01494                 g = cg + tbl[green - cg];
01495             if (cb > blue)
01496                 b = cb - tbl[cb - blue];
01497             else
01498                 b = cb + tbl[blue - cb];
01499             img.setColor(i, qRgba(r, g, b, qAlpha(col)));
01500         }
01501 
01502     } else {
01503         // truecolor
01504         for (int y=0; y<img.height(); y++) {
01505             QRgb *data = (QRgb *) img.scanLine(y);
01506             for (int x=0; x<img.width(); x++) {
01507                 col = *data;
01508                 cr = qRed(col); cg = qGreen(col); cb = qBlue(col);
01509                 if (cr > red)
01510                     r = cr - tbl[cr - red];
01511                 else
01512                     r = cr + tbl[red - cr];
01513                 if (cg > green)
01514                     g = cg - tbl[cg - green];
01515                 else
01516                     g = cg + tbl[green - cg];
01517                 if (cb > blue)
01518                     b = cb - tbl[cb - blue];
01519                 else
01520                     b = cb + tbl[blue - cb];
01521                 *data++ = qRgba(r, g, b, qAlpha(col));
01522             }
01523         }
01524     }
01525 
01526     return img;
01527 }
01528 
01529 //======================================================================
01530 //
01531 // Color effects
01532 //
01533 //======================================================================
01534 
01535 // This code is adapted from code (C) Rik Hemsley <rik@kde.org>
01536 //
01537 // The formula used (r + b + g) /3 is different from the qGray formula
01538 // used by Qt.  This is because our formula is much much faster.  If,
01539 // however, it turns out that this is producing sub-optimal images,
01540 // then it will have to change (kurt)
01541 //
01542 // It does produce lower quality grayscale ;-) Use fast == true for the fast
01543 // algorithm, false for the higher quality one (mosfet).
01544 QImage& KImageEffect::toGray(QImage &img, bool fast)
01545 {
01546     if (img.width() == 0 || img.height() == 0)
01547       return img;
01548 
01549     if(fast){
01550         if (img.depth() == 32) {
01551             register uchar * r(img.bits());
01552             register uchar * g(img.bits() + 1);
01553             register uchar * b(img.bits() + 2);
01554 
01555             uchar * end(img.bits() + img.numBytes());
01556 
01557             while (r != end) {
01558 
01559                 *r = *g = *b = (((*r + *g) >> 1) + *b) >> 1; // (r + b + g) / 3
01560 
01561                 r += 4;
01562                 g += 4;
01563                 b += 4;
01564             }
01565         }
01566         else
01567         {
01568             for (int i = 0; i < img.numColors(); i++)
01569             {
01570                 register uint r = qRed(img.color(i));
01571                 register uint g = qGreen(img.color(i));
01572                 register uint b = qBlue(img.color(i));
01573 
01574                 register uint gray = (((r + g) >> 1) + b) >> 1;
01575                 img.setColor(i, qRgba(gray, gray, gray, qAlpha(img.color(i))));
01576             }
01577         }
01578     }
01579     else{
01580         int pixels = img.depth() > 8 ? img.width()*img.height() :
01581             img.numColors();
01582         unsigned int *data = img.depth() > 8 ? (unsigned int *)img.bits() :
01583             (unsigned int *)img.colorTable();
01584         int val, i;
01585         for(i=0; i < pixels; ++i){
01586             val = qGray(data[i]);
01587             data[i] = qRgba(val, val, val, qAlpha(data[i]));
01588         }
01589     }
01590     return img;
01591 }
01592 
01593 // CT 29Jan2000 - desaturation algorithms
01594 QImage& KImageEffect::desaturate(QImage &img, float desat)
01595 {
01596     if (img.width() == 0 || img.height() == 0)
01597       return img;
01598 
01599     if (desat < 0) desat = 0.;
01600     if (desat > 1) desat = 1.;
01601     int pixels = img.depth() > 8 ? img.width()*img.height() :
01602         img.numColors();
01603     unsigned int *data = img.depth() > 8 ? (unsigned int *)img.bits() :
01604         (unsigned int *)img.colorTable();
01605     int h, s, v, i;
01606     QColor clr; // keep constructor out of loop (mosfet)
01607     for(i=0; i < pixels; ++i){
01608         clr.setRgb(data[i]);
01609         clr.hsv(&h, &s, &v);
01610         clr.setHsv(h, (int)(s * (1. - desat)), v);
01611         data[i] = clr.rgb();
01612     }
01613     return img;
01614 }
01615 
01616 // Contrast stuff (mosfet)
01617 QImage& KImageEffect::contrast(QImage &img, int c)
01618 {
01619     if (img.width() == 0 || img.height() == 0)
01620       return img;
01621 
01622     if(c > 255)
01623         c = 255;
01624     if(c < -255)
01625         c =  -255;
01626     int pixels = img.depth() > 8 ? img.width()*img.height() :
01627         img.numColors();
01628     unsigned int *data = img.depth() > 8 ? (unsigned int *)img.bits() :
01629         (unsigned int *)img.colorTable();
01630     int i, r, g, b;
01631     for(i=0; i < pixels; ++i){
01632         r = qRed(data[i]);
01633         g = qGreen(data[i]);
01634         b = qBlue(data[i]);
01635         if(qGray(data[i]) <= 127){
01636             if(r - c <= 255)
01637                 r -= c;
01638             if(g - c <= 255)
01639                 g -= c;
01640             if(b - c <= 255)
01641                 b -= c;
01642         }
01643         else{
01644             if(r + c <= 255)
01645                 r += c;
01646             if(g + c <= 255)
01647                 g += c;
01648             if(b + c <= 255)
01649                 b += c;
01650         }
01651         data[i] = qRgba(r, g, b, qAlpha(data[i]));
01652     }
01653     return(img);
01654 }
01655 
01656 //======================================================================
01657 //
01658 // Dithering effects
01659 //
01660 //======================================================================
01661 
01662 // adapted from kFSDither (C) 1997 Martin Jones (mjones@kde.org)
01663 //
01664 // Floyd-Steinberg dithering
01665 // Ref: Bitmapped Graphics Programming in C++
01666 //      Marv Luse, Addison-Wesley Publishing, 1993.
01667 QImage& KImageEffect::dither(QImage &img, const QColor *palette, int size)
01668 {
01669     if (img.width() == 0 || img.height() == 0 ||
01670         palette == 0 || img.depth() <= 8)
01671       return img;
01672 
01673     QImage dImage( img.width(), img.height(), 8, size );
01674     int i;
01675 
01676     dImage.setNumColors( size );
01677     for ( i = 0; i < size; i++ )
01678         dImage.setColor( i, palette[ i ].rgb() );
01679 
01680     int *rerr1 = new int [ img.width() * 2 ];
01681     int *gerr1 = new int [ img.width() * 2 ];
01682     int *berr1 = new int [ img.width() * 2 ];
01683 
01684     memset( rerr1, 0, sizeof( int ) * img.width() * 2 );
01685     memset( gerr1, 0, sizeof( int ) * img.width() * 2 );
01686     memset( berr1, 0, sizeof( int ) * img.width() * 2 );
01687 
01688     int *rerr2 = rerr1 + img.width();
01689     int *gerr2 = gerr1 + img.width();
01690     int *berr2 = berr1 + img.width();
01691 
01692     for ( int j = 0; j < img.height(); j++ )
01693     {
01694         uint *ip = (uint * )img.scanLine( j );
01695         uchar *dp = dImage.scanLine( j );
01696 
01697         for ( i = 0; i < img.width(); i++ )
01698         {
01699             rerr1[i] = rerr2[i] + qRed( *ip );
01700             rerr2[i] = 0;
01701             gerr1[i] = gerr2[i] + qGreen( *ip );
01702             gerr2[i] = 0;
01703             berr1[i] = berr2[i] + qBlue( *ip );
01704             berr2[i] = 0;
01705             ip++;
01706         }
01707 
01708         *dp++ = nearestColor( rerr1[0], gerr1[0], berr1[0], palette, size );
01709 
01710         for ( i = 1; i < img.width()-1; i++ )
01711         {
01712             int indx = nearestColor( rerr1[i], gerr1[i], berr1[i], palette, size );
01713             *dp = indx;
01714 
01715             int rerr = rerr1[i];
01716             rerr -= palette[indx].red();
01717             int gerr = gerr1[i];
01718             gerr -= palette[indx].green();
01719             int berr = berr1[i];
01720             berr -= palette[indx].blue();
01721 
01722             // diffuse red error
01723             rerr1[ i+1 ] += ( rerr * 7 ) >> 4;
01724             rerr2[ i-1 ] += ( rerr * 3 ) >> 4;
01725             rerr2[  i  ] += ( rerr * 5 ) >> 4;
01726             rerr2[ i+1 ] += ( rerr ) >> 4;
01727 
01728             // diffuse green error
01729             gerr1[ i+1 ] += ( gerr * 7 ) >> 4;
01730             gerr2[ i-1 ] += ( gerr * 3 ) >> 4;
01731             gerr2[  i  ] += ( gerr * 5 ) >> 4;
01732             gerr2[ i+1 ] += ( gerr ) >> 4;
01733 
01734             // diffuse red error
01735             berr1[ i+1 ] += ( berr * 7 ) >> 4;
01736             berr2[ i-1 ] += ( berr * 3 ) >> 4;
01737             berr2[  i  ] += ( berr * 5 ) >> 4;
01738             berr2[ i+1 ] += ( berr ) >> 4;
01739 
01740             dp++;
01741         }
01742 
01743         *dp = nearestColor( rerr1[i], gerr1[i], berr1[i], palette, size );
01744     }
01745 
01746     delete [] rerr1;
01747     delete [] gerr1;
01748     delete [] berr1;
01749 
01750     img = dImage;
01751     return img;
01752 }
01753 
01754 int KImageEffect::nearestColor( int r, int g, int b, const QColor *palette, int size )
01755 {
01756     if (palette == 0)
01757       return 0;
01758 
01759     int dr = palette[0].red() - r;
01760     int dg = palette[0].green() - g;
01761     int db = palette[0].blue() - b;
01762 
01763     int minDist =  dr*dr + dg*dg + db*db;
01764     int nearest = 0;
01765 
01766     for (int i = 1; i < size; i++ )
01767     {
01768         dr = palette[i].red() - r;
01769         dg = palette[i].green() - g;
01770         db = palette[i].blue() - b;
01771 
01772         int dist = dr*dr + dg*dg + db*db;
01773 
01774         if ( dist < minDist )
01775         {
01776             minDist = dist;
01777             nearest = i;
01778         }
01779     }
01780 
01781     return nearest;
01782 }
01783 
01784 bool KImageEffect::blend(
01785     const QImage & upper,
01786     const QImage & lower,
01787     QImage & output
01788 )
01789 {
01790   if (
01791       upper.width()  > lower.width()  ||
01792       upper.height() > lower.height() ||
01793       upper.depth() != 32             ||
01794       lower.depth() != 32
01795   )
01796   {
01797 #ifndef NDEBUG
01798     cerr << "KImageEffect::blend : Sizes not correct\n" ;
01799 #endif
01800     return false;
01801   }
01802 
01803   output = lower.copy();
01804 
01805   register uchar *i, *o;
01806   register int a;
01807   register int col;
01808   register int w = upper.width();
01809   int row(upper.height() - 1);
01810 
01811   do {
01812 
01813     i = upper.scanLine(row);
01814     o = output.scanLine(row);
01815 
01816     col = w << 2;
01817     --col;
01818 
01819     do {
01820 
01821       while (!(a = i[col]) && (col != 3)) {
01822         --col; --col; --col; --col;
01823       }
01824 
01825       --col;
01826       o[col] += ((i[col] - o[col]) * a) >> 8;
01827 
01828       --col;
01829       o[col] += ((i[col] - o[col]) * a) >> 8;
01830 
01831       --col;
01832       o[col] += ((i[col] - o[col]) * a) >> 8;
01833 
01834     } while (col--);
01835 
01836   } while (row--);
01837 
01838   return true;
01839 }
01840 
01841 #if 0
01842 // Not yet...
01843 bool KImageEffect::blend(
01844     const QImage & upper,
01845     const QImage & lower,
01846     QImage & output,
01847     const QRect & destRect
01848 )
01849 {
01850   output = lower.copy();
01851   return output;
01852 }
01853 
01854 #endif
01855 
01856 bool KImageEffect::blend(
01857     int &x, int &y,
01858     const QImage & upper,
01859     const QImage & lower,
01860     QImage & output
01861 )
01862 {
01863   int cx=0, cy=0, cw=upper.width(), ch=upper.height();
01864 
01865   if ( upper.width() + x > lower.width()  ||
01866       upper.height() + y > lower.height() ||
01867       x < 0 || y < 0 ||
01868       upper.depth() != 32 || lower.depth() != 32 )
01869   {
01870     if ( x > lower.width() || y > lower.height() ) return false;
01871     if ( upper.width()<=0 || upper.height() <= 0 ) return false;
01872     if ( lower.width()<=0 || lower.height() <= 0 ) return false;
01873 
01874     if (x<0) {cx=-x; cw+=x; x=0; };
01875     if (cw + x > lower.width()) { cw=lower.width()-x; };
01876     if (y<0) {cy=-y; ch+=y; y=0; };
01877     if (ch + y > lower.height()) { ch=lower.height()-y; };
01878 
01879     if ( cx >= upper.width() || cy >= upper.height() ) return true;
01880     if ( cw <= 0 || ch <= 0 ) return true;
01881   }
01882 
01883   output.create(cw,ch,32);
01884 //  output.setAlphaBuffer(true); // I should do some benchmarks to see if
01885         // this is worth the effort
01886 
01887   register QRgb *i, *o, *b;
01888 
01889   register int a;
01890   register int j,k;
01891   for (j=0; j<ch; j++)
01892   {
01893     b=reinterpret_cast<QRgb *>(&lower.scanLine(y+j) [ (x+cw) << 2 ]);
01894     i=reinterpret_cast<QRgb *>(&upper.scanLine(cy+j)[ (cx+cw) << 2 ]);
01895     o=reinterpret_cast<QRgb *>(&output.scanLine(j)  [ cw << 2 ]);
01896 
01897     k=cw-1;
01898     --b; --i; --o;
01899     do
01900     {
01901       while ( !(a=qAlpha(*i)) && k>0 )
01902       {
01903         i--;
01904 //      *o=0;
01905         *o=*b;
01906         --o; --b;
01907         k--;
01908       };
01909 //      *o=0xFF;
01910       *o = qRgb(qRed(*b) + (((qRed(*i) - qRed(*b)) * a) >> 8),
01911                 qGreen(*b) + (((qGreen(*i) - qGreen(*b)) * a) >> 8),
01912                 qBlue(*b) + (((qBlue(*i) - qBlue(*b)) * a) >> 8));
01913       --i; --o; --b;
01914     } while (k--);
01915   }
01916 
01917   return true;
01918 }
01919 
01920 bool KImageEffect::blendOnLower(
01921     int x, int y,
01922     const QImage & upper,
01923     const QImage & lower
01924 )
01925 {
01926   int cx=0, cy=0, cw=upper.width(), ch=upper.height();
01927 
01928   if ( upper.depth() != 32 || lower.depth() != 32 ) return false;
01929   if ( x + cw > lower.width()  ||
01930       y + ch > lower.height() ||
01931       x < 0 || y < 0 )
01932   {
01933     if ( x > lower.width() || y > lower.height() ) return true;
01934     if ( upper.width()<=0 || upper.height() <= 0 ) return true;
01935     if ( lower.width()<=0 || lower.height() <= 0 ) return true;
01936 
01937     if (x<0) {cx=-x; cw+=x; x=0; };
01938     if (cw + x > lower.width()) { cw=lower.width()-x; };
01939     if (y<0) {cy=-y; ch+=y; y=0; };
01940     if (ch + y > lower.height()) { ch=lower.height()-y; };
01941 
01942     if ( cx >= upper.width() || cy >= upper.height() ) return true;
01943     if ( cw <= 0 || ch <= 0 ) return true;
01944   }
01945 
01946   register uchar *i, *b;
01947   register int a;
01948   register int k;
01949 
01950   for (int j=0; j<ch; j++)
01951   {
01952     b=&lower.scanLine(y+j) [ (x+cw) << 2 ];
01953     i=&upper.scanLine(cy+j)[ (cx+cw) << 2 ];
01954 
01955     k=cw-1;
01956     --b; --i;
01957     do
01958     {
01959 #ifndef WORDS_BIGENDIAN
01960       while ( !(a=*i) && k>0 )
01961 #else
01962       while ( !(a=*(i-3)) && k>0 )
01963 #endif
01964       {
01965         i-=4; b-=4; k--;
01966       };
01967 
01968 #ifndef WORDS_BIGENDIAN
01969       --i; --b;
01970       *b += ( ((*i - *b) * a) >> 8 );
01971       --i; --b;
01972       *b += ( ((*i - *b) * a) >> 8 );
01973       --i; --b;
01974       *b += ( ((*i - *b) * a) >> 8 );
01975       --i; --b;
01976 #else
01977       *b += ( ((*i - *b) * a) >> 8 );
01978       --i; --b;
01979       *b += ( ((*i - *b) * a) >> 8 );
01980       --i; --b;
01981       *b += ( ((*i - *b) * a) >> 8 );
01982       i -= 2; b -= 2;
01983 #endif
01984     } while (k--);
01985   }
01986 
01987   return true;
01988 }
01989 
01990 // For selected icons
01991 QImage& KImageEffect::selectedImage( QImage &img, const QColor &col )
01992 {
01993     return blend( col, img, 0.5);
01994 }
01995 
01996 //
01997 // ===================================================================
01998 // Effects originally ported from ImageMagick for PixiePlus, plus a few
01999 // new ones. (mosfet 12/29/01)
02000 // ===================================================================
02001 //
02002 
02003 void KImageEffect::normalize(QImage &img)
02004 {
02005     int *histogram, threshold_intensity, intense;
02006     int x, y, i;
02007 
02008     unsigned int gray_value;
02009     unsigned int *normalize_map;
02010     unsigned int high, low;
02011 
02012     // allocate histogram and normalize map
02013     histogram = (int *)calloc(MaxRGB+1, sizeof(int));
02014     normalize_map = (unsigned int *)malloc((MaxRGB+1)*sizeof(unsigned int));
02015     if(!normalize_map || !histogram){
02016         qWarning("Unable to allocate normalize histogram and map");
02017         free(normalize_map);
02018         free(histogram);
02019         return;
02020     }
02021 
02022     // form histogram
02023     if(img.depth() > 8){  // DirectClass
02024         unsigned int *data;
02025         for(y=0; y < img.height(); ++y){
02026             data = (unsigned int *)img.scanLine(y);
02027             for(x=0; x < img.width(); ++x){
02028                 gray_value = intensityValue(data[x]);
02029                 histogram[gray_value]++;
02030             }
02031         }
02032     }
02033     else{ // PsudeoClass
02034         unsigned char *data;
02035         unsigned int *cTable = img.colorTable();
02036         for(y=0; y < img.height(); ++y){
02037             data = (unsigned char *)img.scanLine(y);
02038             for(x=0; x < img.width(); ++x){
02039                 gray_value = intensityValue(*(cTable+data[x]));
02040                 histogram[gray_value]++;
02041             }
02042         }
02043     }
02044 
02045     // find histogram boundaries by locating the 1 percent levels
02046     threshold_intensity = (img.width()*img.height())/100;
02047     intense = 0;
02048     for(low=0; low < MaxRGB; ++low){
02049         intense+=histogram[low];
02050         if(intense > threshold_intensity)
02051             break;
02052     }
02053     intense=0;
02054     for(high=MaxRGB; high != 0; --high){
02055         intense+=histogram[high];
02056         if(intense > threshold_intensity)
02057             break;
02058     }
02059 
02060     if (low == high){
02061         // Unreasonable contrast;  use zero threshold to determine boundaries.
02062         threshold_intensity=0;
02063         intense=0;
02064         for(low=0; low < MaxRGB; ++low){
02065             intense+=histogram[low];
02066             if(intense > threshold_intensity)
02067                 break;
02068         }
02069         intense=0;
02070         for(high=MaxRGB; high != 0; --high)
02071         {
02072             intense+=histogram[high];
02073             if(intense > threshold_intensity)
02074                 break;
02075         }
02076         if(low == high)
02077             return;  // zero span bound
02078     }
02079 
02080     // Stretch the histogram to create the normalized image mapping.
02081     for(i=0; i <= MaxRGB; i++){
02082         if (i < (int) low)
02083             normalize_map[i]=0;
02084         else{
02085             if(i > (int) high)
02086                 normalize_map[i]=MaxRGB;
02087             else
02088                 normalize_map[i]=(MaxRGB-1)*(i-low)/(high-low);
02089         }
02090     }
02091     // Normalize
02092     if(img.depth() > 8){ // DirectClass
02093         unsigned int *data;
02094         for(y=0; y < img.height(); ++y){
02095             data = (unsigned int *)img.scanLine(y);
02096             for(x=0; x < img.width(); ++x){
02097                 data[x] = qRgba(normalize_map[qRed(data[x])],
02098                                 normalize_map[qGreen(data[x])],
02099                                 normalize_map[qBlue(data[x])],
02100                                 qAlpha(data[x]));
02101             }
02102         }
02103     }
02104     else{ // PsudeoClass
02105         int colors = img.numColors();
02106         unsigned int *cTable = img.colorTable();
02107         for(i=0; i < colors; ++i){
02108             cTable[i] = qRgba(normalize_map[qRed(cTable[i])],
02109                               normalize_map[qGreen(cTable[i])],
02110                               normalize_map[qBlue(cTable[i])],
02111                               qAlpha(cTable[i]));
02112         }
02113     }
02114     free(histogram);
02115     free(normalize_map);
02116 }
02117 
02118 
02119 void KImageEffect::equalize(QImage &img)
02120 {
02121     int *histogram, *map, *equalize_map;
02122     int x, y, i, j;
02123 
02124     unsigned int high, low;
02125 
02126     // allocate histogram and maps
02127     histogram = (int *)calloc(MaxRGB+1, sizeof(int));
02128     map = (int *)malloc((MaxRGB+1)*sizeof(unsigned int));
02129     equalize_map  = (int *)malloc((MaxRGB+1)*sizeof(unsigned int));
02130 
02131     if(!histogram || !map || !equalize_map){
02132         qWarning("Unable to allocate equalize histogram and maps");
02133         free(histogram);
02134         free(map);
02135         free(equalize_map);
02136         return;
02137     }
02138     // form histogram
02139     if(img.depth() > 8){ // DirectClass
02140         unsigned int *data;
02141         for(y=0; y < img.height(); ++y){
02142             data = (unsigned int *)img.scanLine(y);
02143             for(x=0; x < img.width(); ++x){
02144                 histogram[intensityValue(data[x])]++;
02145             }
02146         }
02147     }
02148     else{ // PsudeoClass
02149         unsigned char *data;
02150         unsigned int *cTable = img.colorTable();
02151         for(y=0; y < img.height(); ++y){
02152             data = (unsigned char *)img.scanLine(y);
02153             for(x=0; x < img.width(); ++x){
02154                 histogram[intensityValue(*(cTable+data[x]))]++;
02155             }
02156         }
02157     }
02158 
02159     // integrate the histogram to get the equalization map.
02160     j=0;
02161     for(i=0; i <= MaxRGB; i++){
02162         j+=histogram[i];
02163         map[i]=j;
02164     }
02165     free(histogram);
02166     if(map[MaxRGB] == 0){
02167         free(equalize_map);
02168         free(map);
02169         return;
02170     }
02171     // equalize
02172     low=map[0];
02173     high=map[MaxRGB];
02174     for(i=0; i <= MaxRGB; i++)
02175         equalize_map[i]=(unsigned int)
02176             ((((double) (map[i]-low))*MaxRGB)/QMAX(high-low,1));
02177     free(map);
02178     // stretch the histogram
02179     if(img.depth() > 8){ // DirectClass
02180         unsigned int *data;
02181         for(y=0; y < img.height(); ++y){
02182             data = (unsigned int *)img.scanLine(y);
02183             for(x=0; x < img.width(); ++x){
02184                 data[x] = qRgba(equalize_map[qRed(data[x])],
02185                                 equalize_map[qGreen(data[x])],
02186                                 equalize_map[qBlue(data[x])],
02187                                 qAlpha(data[x]));
02188             }
02189         }
02190     }
02191     else{ // PsudeoClass
02192         int colors = img.numColors();
02193         unsigned int *cTable = img.colorTable();
02194         for(i=0; i < colors; ++i){
02195             cTable[i] = qRgba(equalize_map[qRed(cTable[i])],
02196                               equalize_map[qGreen(cTable[i])],
02197                               equalize_map[qBlue(cTable[i])],
02198                               qAlpha(cTable[i]));
02199         }
02200     }
02201     free(equalize_map);
02202 }
02203 
02204 QImage KImageEffect::sample(QImage &src, int w, int h)
02205 {
02206     if(w == src.width() && h == src.height())
02207         return(src);
02208 
02209     double *x_offset, *y_offset;
02210     int j, k, y;
02211     register int x;
02212     QImage dest(w, h, src.depth());
02213 
02214     x_offset = (double *)malloc(w*sizeof(double));
02215     y_offset = (double *)malloc(h*sizeof(double));
02216     if(!x_offset || !y_offset){
02217         qWarning("Unable to allocate pixels buffer");
02218         free(x_offset);
02219         free(y_offset);
02220         return(src);
02221     }
02222 
02223     // init pixel offsets
02224     for(x=0; x < w; ++x)
02225         x_offset[x] = x*src.width()/((double)w);
02226     for(y=0; y < h; ++y)
02227         y_offset[y] = y*src.height()/((double)h);
02228 
02229     // sample each row
02230     if(src.depth() > 8){ // DirectClass source image
02231         unsigned int *srcData, *destData;
02232         unsigned int *pixels;
02233         pixels = (unsigned int *)malloc(src.width()*sizeof(unsigned int));
02234         if(!pixels){
02235             qWarning("Unable to allocate pixels buffer");
02236             free(pixels);
02237             free(x_offset);
02238             free(y_offset);
02239             return(src);
02240         }
02241         j = (-1);
02242         for(y=0; y < h; ++y){
02243             destData = (unsigned int *)dest.scanLine(y);
02244             if(j != y_offset[y]){
02245                 // read a scan line
02246                 j = (int)(y_offset[y]);
02247                 srcData = (unsigned int *)src.scanLine(j);
02248                 (void)memcpy(pixels, srcData, src.width()*sizeof(unsigned int));
02249             }
02250             // sample each column
02251             for(x=0; x < w; ++x){
02252                 k = (int)(x_offset[x]);
02253                 destData[x] = pixels[k];
02254             }
02255         }
02256         free(pixels);
02257     }
02258     else{ // PsudeoClass source image
02259         unsigned char *srcData, *destData;
02260         unsigned char *pixels;
02261         pixels = (unsigned char *)malloc(src.width()*sizeof(unsigned char));
02262         if(!pixels){
02263             qWarning("Unable to allocate pixels buffer");
02264             free(pixels);
02265             free(x_offset);
02266             free(y_offset);
02267             return(src);
02268         }
02269         // copy colortable
02270         dest.setNumColors(src.numColors());
02271         (void)memcpy(dest.colorTable(), src.colorTable(),
02272                      src.numColors()*sizeof(unsigned int));
02273 
02274         // sample image
02275         j = (-1);
02276         for(y=0; y < h; ++y){
02277             destData = (unsigned char *)dest.scanLine(y);
02278             if(j != y_offset[y]){
02279                 // read a scan line
02280                 j = (int)(y_offset[y]);
02281                 srcData = (unsigned char *)src.scanLine(j);
02282                 (void)memcpy(pixels, srcData, src.width()*sizeof(unsigned char));
02283             }
02284             // sample each column
02285             for(x=0; x < w; ++x){
02286                 k = (int)(x_offset[x]);
02287                 destData[x] = pixels[k];
02288             }
02289         }
02290         free(pixels);
02291     }
02292     free(x_offset);
02293     free(y_offset);
02294     return(dest);
02295 }
02296 
02297 void KImageEffect::threshold(QImage &img, unsigned int threshold)
02298 {
02299     int i, count;
02300     unsigned int *data;
02301     if(img.depth() > 8){ // DirectClass
02302         count = img.width()*img.height();
02303         data = (unsigned int *)img.bits();
02304     }
02305     else{ // PsudeoClass
02306         count = img.numColors();
02307         data = (unsigned int *)img.colorTable();
02308     }
02309     for(i=0; i < count; ++i)
02310         data[i] = intensityValue(data[i]) < threshold ? Qt::black.rgb() : Qt::white.rgb();
02311 }
02312 
02313 QImage KImageEffect::charcoal(QImage &src, double factor)
02314 {
02315     QImage dest(src);
02316     dest.detach();
02317     toGray(dest);
02318     dest = edge(dest, factor);
02319     dest = blur(dest, factor);
02320     normalize(dest);
02321     dest.invertPixels(false);
02322     return(dest);
02323 }
02324 
02325 void KImageEffect::hull(const int x_offset, const int y_offset,
02326                         const int polarity, const int columns,
02327                         const int rows,
02328                         unsigned int *f, unsigned int *g)
02329 {
02330     int x, y;
02331 
02332     unsigned int *p, *q, *r, *s;
02333     unsigned int v;
02334     if(f == NULL || g == NULL)
02335         return;
02336     p=f+(columns+2);
02337     q=g+(columns+2);
02338     r=p+(y_offset*(columns+2)+x_offset);
02339     for (y=0; y < rows; y++){
02340         p++;
02341         q++;
02342         r++;
02343         if(polarity > 0)
02344             for (x=0; x < columns; x++){
02345                 v=(*p);
02346                 if (*r > v)
02347                     v++;
02348                 *q=v;
02349                 p++;
02350                 q++;
02351                 r++;
02352             }
02353         else
02354             for(x=0; x < columns; x++){
02355                 v=(*p);
02356                 if (v > (unsigned int) (*r+1))
02357                     v--;
02358                 *q=v;
02359                 p++;
02360                 q++;
02361                 r++;
02362             }
02363         p++;
02364         q++;
02365         r++;
02366     }
02367     p=f+(columns+2);
02368     q=g+(columns+2);
02369     r=q+(y_offset*(columns+2)+x_offset);
02370     s=q-(y_offset*(columns+2)+x_offset);
02371     for(y=0; y < rows; y++){
02372         p++;
02373         q++;
02374         r++;
02375         s++;
02376         if(polarity > 0)
02377             for(x=0; x < (int) columns; x++){
02378                 v=(*q);
02379                 if (((unsigned int) (*s+1) > v) && (*r > v))
02380                     v++;
02381                 *p=v;
02382                 p++;
02383                 q++;
02384                 r++;
02385                 s++;
02386             }
02387         else
02388             for (x=0; x < columns; x++){
02389                 v=(*q);
02390                 if (((unsigned int) (*s+1) < v) && (*r < v))
02391                     v--;
02392                 *p=v;
02393                 p++;
02394                 q++;
02395                 r++;
02396                 s++;
02397             }
02398         p++;
02399         q++;
02400         r++;
02401         s++;
02402     }
02403 }
02404 
02405 QImage KImageEffect::despeckle(QImage &src)
02406 {
02407     int i, j, x, y;
02408     unsigned int *blue_channel, *red_channel, *green_channel, *buffer,
02409         *alpha_channel;
02410     int packets;
02411     static const int
02412     X[4]= {0, 1, 1,-1},
02413     Y[4]= {1, 0, 1, 1};
02414 
02415     unsigned int *destData;
02416     QImage dest(src.width(), src.height(), 32);
02417 
02418     packets = (src.width()+2)*(src.height()+2);
02419     red_channel = (unsigned int *)calloc(packets, sizeof(unsigned int));
02420     green_channel = (unsigned int *)calloc(packets, sizeof(unsigned int));
02421     blue_channel = (unsigned int *)calloc(packets, sizeof(unsigned int));
02422     alpha_channel = (unsigned int *)calloc(packets, sizeof(unsigned int));
02423     buffer = (unsigned int *)calloc(packets, sizeof(unsigned int));
02424     if(!red_channel || ! green_channel || ! blue_channel || ! alpha_channel ||
02425        !buffer){
02426         free(red_channel);
02427         free(green_channel);
02428         free(blue_channel);
02429         free(alpha_channel);
02430         free(buffer);
02431         return(src);
02432     }
02433 
02434     // copy image pixels to color component buffers
02435     j = src.width()+2;
02436     if(src.depth() > 8){ // DirectClass source image
02437         unsigned int *srcData;
02438         for(y=0; y < src.height(); ++y){
02439             srcData = (unsigned int *)src.scanLine(y);
02440             ++j;
02441             for(x=0; x < src.width(); ++x){
02442                 red_channel[j] = qRed(srcData[x]);
02443                 green_channel[j] = qGreen(srcData[x]);
02444                 blue_channel[j] = qBlue(srcData[x]);
02445                 alpha_channel[j] = qAlpha(srcData[x]);
02446                 ++j;
02447             }
02448             ++j;
02449         }
02450     }
02451     else{ // PsudeoClass source image
02452         unsigned char *srcData;
02453         unsigned int *cTable = src.colorTable();
02454         unsigned int pixel;
02455         for(y=0; y < src.height(); ++y){
02456             srcData = (unsigned char *)src.scanLine(y);
02457             ++j;
02458             for(x=0; x < src.width(); ++x){
02459                 pixel = *(cTable+srcData[x]);
02460                 red_channel[j] = qRed(pixel);
02461                 green_channel[j] = qGreen(pixel);
02462                 blue_channel[j] = qBlue(pixel);
02463                 alpha_channel[j] = qAlpha(pixel);
02464                 ++j;
02465             }
02466             ++j;
02467         }
02468     }
02469     // reduce speckle in red channel
02470     for(i=0; i < 4; i++){
02471         hull(X[i],Y[i],1,src.width(),src.height(),red_channel,buffer);
02472         hull(-X[i],-Y[i],1,src.width(),src.height(),red_channel,buffer);
02473         hull(-X[i],-Y[i],-1,src.width(),src.height(),red_channel,buffer);
02474         hull(X[i],Y[i],-1,src.width(),src.height(),red_channel,buffer);
02475     }
02476     // reduce speckle in green channel
02477     for (i=0; i < packets; i++)
02478         buffer[i]=0;
02479     for (i=0; i < 4; i++){
02480         hull(X[i],Y[i],1,src.width(),src.height(),green_channel,buffer);
02481         hull(-X[i],-Y[i],1,src.width(),src.height(),green_channel,buffer);
02482         hull(-X[i],-Y[i],-1,src.width(),src.height(),green_channel,buffer);
02483         hull(X[i],Y[i],-1,src.width(),src.height(),green_channel,buffer);
02484     }
02485     // reduce speckle in blue channel
02486     for (i=0; i < packets; i++)
02487         buffer[i]=0;
02488     for (i=0; i < 4; i++){
02489         hull(X[i],Y[i],1,src.width(),src.height(),blue_channel,buffer);
02490         hull(-X[i],-Y[i],1,src.width(),src.height(),blue_channel,buffer);
02491         hull(-X[i],-Y[i],-1,src.width(),src.height(),blue_channel,buffer);
02492         hull(X[i],Y[i],-1,src.width(),src.height(),blue_channel,buffer);
02493     }
02494     // copy color component buffers to despeckled image
02495     j = dest.width()+2;
02496     for(y=0; y < dest.height(); ++y)
02497     {
02498         destData = (unsigned int *)dest.scanLine(y);
02499         ++j;
02500         for (x=0; x < dest.width(); ++x)
02501         {
02502             destData[x] = qRgba(red_channel[j], green_channel[j],
02503                                 blue_channel[j], alpha_channel[j]);
02504             ++j;
02505         }
02506         ++j;
02507     }
02508     free(buffer);
02509     free(red_channel);
02510     free(green_channel);
02511     free(blue_channel);
02512     free(alpha_channel);
02513     return(dest);
02514 }
02515 
02516 unsigned int KImageEffect::generateNoise(unsigned int pixel,
02517                                          NoiseType noise_type)
02518 {
02519 #define NoiseEpsilon  1.0e-5
02520 #define NoiseMask  0x7fff
02521 #define SigmaUniform  4.0
02522 #define SigmaGaussian  4.0
02523 #define SigmaImpulse  0.10
02524 #define SigmaLaplacian 10.0
02525 #define SigmaMultiplicativeGaussian  0.5
02526 #define SigmaPoisson  0.05
02527 #define TauGaussian  20.0
02528 
02529     double alpha, beta, sigma, value;
02530     alpha=(double) (rand() & NoiseMask)/NoiseMask;
02531     if (alpha == 0.0)
02532         alpha=1.0;
02533     switch(noise_type){
02534     case UniformNoise:
02535     default:
02536         {
02537             value=(double) pixel+SigmaUniform*(alpha-0.5);
02538             break;
02539         }
02540     case GaussianNoise:
02541         {
02542             double tau;
02543 
02544             beta=(double) (rand() & NoiseMask)/NoiseMask;
02545             sigma=sqrt(-2.0*log(alpha))*cos(2.0*M_PI*beta);
02546             tau=sqrt(-2.0*log(alpha))*sin(2.0*M_PI*beta);
02547             value=(double) pixel+
02548                 (sqrt((double) pixel)*SigmaGaussian*sigma)+(TauGaussian*tau);
02549             break;
02550         }
02551     case MultiplicativeGaussianNoise:
02552         {
02553             if (alpha <= NoiseEpsilon)
02554                 sigma=MaxRGB;
02555             else
02556                 sigma=sqrt(-2.0*log(alpha));
02557             beta=(rand() & NoiseMask)/NoiseMask;
02558             value=(double) pixel+
02559                 pixel*SigmaMultiplicativeGaussian*sigma*cos(2.0*M_PI*beta);
02560             break;
02561         }
02562     case ImpulseNoise:
02563         {
02564             if (alpha < (SigmaImpulse/2.0))
02565                 value=0;
02566             else
02567                 if (alpha >= (1.0-(SigmaImpulse/2.0)))
02568                     value=MaxRGB;
02569                 else
02570                     value=pixel;
02571             break;
02572         }
02573     case LaplacianNoise:
02574         {
02575             if (alpha <= 0.5)
02576             {
02577                 if (alpha <= NoiseEpsilon)
02578                     value=(double) pixel-MaxRGB;
02579                 else
02580                     value=(double) pixel+SigmaLaplacian*log(2.0*alpha);
02581                 break;
02582             }
02583             beta=1.0-alpha;
02584             if (beta <= (0.5*NoiseEpsilon))
02585                 value=(double) pixel+MaxRGB;
02586             else
02587                 value=(double) pixel-SigmaLaplacian*log(2.0*beta);
02588             break;
02589         }
02590     case PoissonNoise:
02591         {
02592             register int
02593                 i;
02594 
02595             for (i=0; alpha > exp(-SigmaPoisson*pixel); i++)
02596             {
02597                 beta=(double) (rand() & NoiseMask)/NoiseMask;
02598                 alpha=alpha*beta;
02599             }
02600             value=i/SigmaPoisson;
02601             break;
02602         }
02603     }
02604     if(value < 0.0)
02605         return(0);
02606     if(value > MaxRGB)
02607         return(MaxRGB);
02608     return((unsigned int) (value+0.5));
02609 }
02610 
02611 QImage KImageEffect::addNoise(QImage &src, NoiseType noise_type)
02612 {
02613     int x, y;
02614     QImage dest(src.width(), src.height(), 32);
02615     unsigned int *destData;
02616 
02617     if(src.depth() > 8){ // DirectClass source image
02618         unsigned int *srcData;
02619         for(y=0; y < src.height(); ++y){
02620             srcData = (unsigned int *)src.scanLine(y);
02621             destData = (unsigned int *)dest.scanLine(y);
02622             for(x=0; x < src.width(); ++x){
02623                 destData[x] = qRgba(generateNoise(qRed(srcData[x]), noise_type),
02624                                     generateNoise(qGreen(srcData[x]), noise_type),
02625                                     generateNoise(qBlue(srcData[x]), noise_type),
02626                                     qAlpha(srcData[x]));
02627             }
02628         }
02629     }
02630     else{ // PsudeoClass source image
02631         unsigned char *srcData;
02632         unsigned int *cTable = src.colorTable();
02633         unsigned int pixel;
02634         for(y=0; y < src.height(); ++y){
02635             srcData = (unsigned char *)src.scanLine(y);
02636             destData = (unsigned int *)dest.scanLine(y);
02637             for(x=0; x < src.width(); ++x){
02638                 pixel = *(cTable+srcData[x]);
02639                 destData[x] = qRgba(generateNoise(qRed(pixel), noise_type),
02640                                     generateNoise(qGreen(pixel), noise_type),
02641                                     generateNoise(qBlue(pixel), noise_type),
02642                                     qAlpha(pixel));
02643             }
02644         }
02645 
02646     }
02647     return(dest);
02648 }
02649 
02650 unsigned int KImageEffect::interpolateColor(QImage *image, double x_offset,
02651                                             double y_offset,
02652                                             unsigned int background)
02653 {
02654     double alpha, beta;
02655     unsigned int p, q, r, s;
02656     int x, y;
02657 
02658     x = (int)x_offset;
02659     y = (int)y_offset;
02660     if((x < -1) || (x >= image->width()) || (y < -1) || (y >= image->height()))
02661         return(background);
02662     if(image->depth() > 8){
02663         if((x >= 0) && (y >= 0) && (x < (image->width()-1)) && (y < (image->height()-1)))    {
02664             unsigned int *t = (unsigned int *)image->scanLine(y);
02665             p = t[x];
02666             q = t[x+1];
02667             r = t[x+image->width()];
02668             s = t[x+image->width()+1];
02669         }
02670         else{
02671             unsigned int *t = (unsigned int *)image->scanLine(y);
02672             p = background;
02673             if((x >= 0) && (y >= 0)){
02674                 p = t[x];
02675             }
02676             q = background;
02677             if(((x+1) < image->width()) && (y >= 0)){
02678                 q = t[x+1];
02679             }
02680             r = background;
02681             if((x >= 0) && ((y+1) < image->height())){
02682                 t = (unsigned int *)image->scanLine(y+1);
02683                 r = t[x+image->width()];
02684             }
02685             s = background;
02686             if(((x+1) < image->width()) && ((y+1) < image->height())){
02687                 t = (unsigned int *)image->scanLine(y+1);
02688                 s = t[x+image->width()+1];
02689             }
02690 
02691         }
02692     }
02693     else{
02694         unsigned int *colorTable = (unsigned int *)image->colorTable();
02695         if((x >= 0) && (y >= 0) && (x < (image->width()-1)) && (y < (image->height()-1)))    {
02696             unsigned char *t;
02697             t = (unsigned char *)image->scanLine(y);
02698             p = *(colorTable+t[x]);
02699             q = *(colorTable+t[x+1]);
02700             t = (unsigned char *)image->scanLine(y+1);
02701             r = *(colorTable+t[x]);
02702             s = *(colorTable+t[x+1]);
02703         }
02704         else{
02705             unsigned char *t;
02706             p = background;
02707             if((x >= 0) && (y >= 0)){
02708                 t = (unsigned char *)image->scanLine(y);
02709                 p = *(colorTable+t[x]);
02710             }
02711             q = background;
02712             if(((x+1) < image->width()) && (y >= 0)){
02713                 t = (unsigned char *)image->scanLine(y);
02714                 q = *(colorTable+t[x+1]);
02715             }
02716             r = background;
02717             if((x >= 0) && ((y+1) < image->height())){
02718                 t = (unsigned char *)image->scanLine(y+1);
02719                 r = *(colorTable+t[x]);
02720             }
02721             s = background;
02722             if(((x+1) < image->width()) && ((y+1) < image->height())){
02723                 t = (unsigned char *)image->scanLine(y+1);
02724                 s = *(colorTable+t[x+1]);
02725             }
02726 
02727         }
02728 
02729     }
02730     x_offset -= floor(x_offset);
02731     y_offset -= floor(y_offset);
02732     alpha = 1.0-x_offset;
02733     beta = 1.0-y_offset;
02734 
02735     return(qRgba((unsigned char)(beta*(alpha*qRed(p)+x_offset*qRed(q))+y_offset*(alpha*qRed(r)+x_offset*qRed(s))),
02736                  (unsigned char)(beta*(alpha*qGreen(p)+x_offset*qGreen(q))+y_offset*(alpha*qGreen(r)+x_offset*qGreen(s))),
02737                  (unsigned char)(beta*(alpha*qBlue(p)+x_offset*qBlue(q))+y_offset*(alpha*qBlue(r)+x_offset*qBlue(s))),
02738                  (unsigned char)(beta*(alpha*qAlpha(p)+x_offset*qAlpha(q))+y_offset*(alpha*qAlpha(r)+x_offset*qAlpha(s)))));
02739 }
02740 
02741 QImage KImageEffect::implode(QImage &src, double factor,
02742                              unsigned int background)
02743 {
02744     double amount, distance, radius;
02745     double x_center, x_distance, x_scale;
02746     double y_center, y_distance, y_scale;
02747     unsigned int *destData;
02748     int x, y;
02749 
02750     QImage dest(src.width(), src.height(), 32);
02751 
02752     // compute scaling factor
02753     x_scale = 1.0;
02754     y_scale = 1.0;
02755     x_center = (double)0.5*src.width();
02756     y_center = (double)0.5*src.height();
02757     radius=x_center;
02758     if(src.width() > src.height())
02759         y_scale = (double)src.width()/src.height();
02760     else if(src.width() < src.height()){
02761         x_scale = (double) src.height()/src.width();
02762         radius = y_center;
02763     }
02764     amount=factor/10.0;
02765     if(amount >= 0)
02766         amount/=10.0;
02767     if(src.depth() > 8){ // DirectClass source image
02768         unsigned int *srcData;
02769         for(y=0; y < src.height(); ++y){
02770             srcData = (unsigned int *)src.scanLine(y);
02771             destData = (unsigned int *)dest.scanLine(y);
02772             y_distance=y_scale*(y-y_center);
02773             for(x=0; x < src.width(); ++x){
02774                 destData[x] = srcData[x];
02775                 x_distance = x_scale*(x-x_center);
02776                 distance= x_distance*x_distance+y_distance*y_distance;
02777                 if(distance < (radius*radius)){
02778                     double factor;
02779                     // Implode the pixel.
02780                     factor=1.0;
02781                     if(distance > 0.0)
02782                         factor=
02783                             pow(sin(0.5000000000000001*M_PI*sqrt(distance)/radius),-amount);
02784                     destData[x] = interpolateColor(&src, factor*x_distance/x_scale+x_center,
02785                                                    factor*y_distance/y_scale+y_center,
02786                                                    background);
02787                 }
02788             }
02789         }
02790     }
02791     else{ // PsudeoClass source image
02792         unsigned char *srcData;
02793         unsigned char idx;
02794         unsigned int *cTable = src.colorTable();
02795         for(y=0; y < src.height(); ++y){
02796             srcData = (unsigned char *)src.scanLine(y);
02797             destData = (unsigned int *)dest.scanLine(y);
02798             y_distance=y_scale*(y-y_center);
02799             for(x=0; x < src.width(); ++x){
02800                 idx = srcData[x];
02801                 destData[x] = cTable[idx];
02802                 x_distance = x_scale*(x-x_center);
02803                 distance= x_distance*x_distance+y_distance*y_distance;
02804                 if(distance < (radius*radius)){
02805                     double factor;
02806                     // Implode the pixel.
02807                     factor=1.0;
02808                     if(distance > 0.0)
02809                         factor=
02810                             pow(sin(0.5000000000000001*M_PI*sqrt(distance)/radius),-amount);
02811                     destData[x] = interpolateColor(&src, factor*x_distance/x_scale+x_center,
02812                                                    factor*y_distance/y_scale+y_center,
02813                                                    background);
02814                 }
02815             }
02816         }
02817 
02818     }
02819     return(dest);
02820 }
02821 
02822 QImage KImageEffect::rotate(QImage &img, RotateDirection r)
02823 {
02824     QImage dest;
02825     int x, y;
02826     if(img.depth() > 8){
02827         unsigned int *srcData, *destData;
02828         switch(r){
02829         case Rotate90:
02830             dest.create(img.height(), img.width(), img.depth());
02831             for(y=0; y < img.height(); ++y){
02832                 srcData = (unsigned int *)img.scanLine(y);
02833                 for(x=0; x < img.width(); ++x){
02834                     destData = (unsigned int *)dest.scanLine(x);
02835                     destData[img.height()-y-1] = srcData[x];
02836                 }
02837             }
02838             break;
02839         case Rotate180:
02840             dest.create(img.width(), img.height(), img.depth());
02841             for(y=0; y < img.height(); ++y){
02842                 srcData = (unsigned int *)img.scanLine(y);
02843                 destData = (unsigned int *)dest.scanLine(img.height()-y-1);
02844                 for(x=0; x < img.width(); ++x)
02845                     destData[img.width()-x-1] = srcData[x];
02846             }
02847             break;
02848         case Rotate270:
02849             dest.create(img.height(), img.width(), img.depth());
02850             for(y=0; y < img.height(); ++y){
02851                 srcData = (unsigned int *)img.scanLine(y);
02852                 for(x=0; x < img.width(); ++x){
02853                     destData = (unsigned int *)dest.scanLine(img.width()-x-1);
02854                     destData[y] = srcData[x];
02855                 }
02856             }
02857             break;
02858         default:
02859             dest = img;
02860             break;
02861         }
02862     }
02863     else{
02864         unsigned char *srcData, *destData;
02865         unsigned int *srcTable, *destTable;
02866         switch(r){
02867         case Rotate90:
02868             dest.create(img.height(), img.width(), img.depth());
02869             dest.setNumColors(img.numColors());
02870             srcTable = (unsigned int *)img.colorTable();
02871             destTable = (unsigned int *)dest.colorTable();
02872             for(x=0; x < img.numColors(); ++x)
02873                 destTable[x] = srcTable[x];
02874             for(y=0; y < img.height(); ++y){
02875                 srcData = (unsigned char *)img.scanLine(y);
02876                 for(x=0; x < img.width(); ++x){
02877                     destData = (unsigned char *)dest.scanLine(x);
02878                     destData[img.height()-y-1] = srcData[x];
02879                 }
02880             }
02881             break;
02882         case Rotate180:
02883             dest.create(img.width(), img.height(), img.depth());
02884             dest.setNumColors(img.numColors());
02885             srcTable = (unsigned int *)img.colorTable();
02886             destTable = (unsigned int *)dest.colorTable();
02887             for(x=0; x < img.numColors(); ++x)
02888                 destTable[x] = srcTable[x];
02889             for(y=0; y < img.height(); ++y){
02890                 srcData = (unsigned char *)img.scanLine(y);
02891                 destData = (unsigned char *)dest.scanLine(img.height()-y-1);
02892                 for(x=0; x < img.width(); ++x)
02893                     destData[img.width()-x-1] = srcData[x];
02894             }
02895             break;
02896         case Rotate270:
02897             dest.create(img.height(), img.width(), img.depth());
02898             dest.setNumColors(img.numColors());
02899             srcTable = (unsigned int *)img.colorTable();
02900             destTable = (unsigned int *)dest.colorTable();
02901             for(x=0; x < img.numColors(); ++x)
02902                 destTable[x] = srcTable[x];
02903             for(y=0; y < img.height(); ++y){
02904                 srcData = (unsigned char *)img.scanLine(y);
02905                 for(x=0; x < img.width(); ++x){
02906                     destData = (unsigned char *)dest.scanLine(img.width()-x-1);
02907                     destData[y] = srcData[x];
02908                 }
02909             }
02910             break;
02911         default:
02912             dest = img;
02913             break;
02914         }
02915 
02916     }
02917     return(dest);
02918 }
02919 
02920 void KImageEffect::solarize(QImage &img, double factor)
02921 {
02922     int i, count;
02923     int threshold;
02924     unsigned int *data;
02925 
02926     threshold = (int)(factor*(MaxRGB+1)/100.0);
02927     if(img.depth() < 32){
02928         data = (unsigned int *)img.colorTable();
02929         count = img.numColors();
02930     }
02931     else{
02932         data = (unsigned int *)img.bits();
02933         count = img.width()*img.height();
02934     }
02935     for(i=0; i < count; ++i){
02936         data[i] = qRgba(qRed(data[i]) > threshold ? MaxRGB-qRed(data[i]) : qRed(data[i]),
02937                         qGreen(data[i]) > threshold ? MaxRGB-qGreen(data[i]) : qGreen(data[i]),
02938                         qBlue(data[i]) > threshold ? MaxRGB-qBlue(data[i]) : qBlue(data[i]),
02939                         qAlpha(data[i]));
02940     }
02941 }
02942 
02943 QImage KImageEffect::spread(QImage &src, unsigned int amount)
02944 {
02945     int quantum, x, y;
02946     int x_distance, y_distance;
02947     if(src.width() < 3 || src.height() < 3)
02948         return(src);
02949     QImage dest(src);
02950     dest.detach();
02951     quantum=(amount+1) >> 1;
02952     if(src.depth() > 8){ // DirectClass source image
02953         unsigned int *p, *q;
02954         for(y=0; y < src.height(); y++){
02955             q = (unsigned int *)dest.scanLine(y);
02956             for(x=0; x < src.width(); x++){
02957                 x_distance = x + ((rand() & (amount+1))-quantum);
02958                 y_distance = y + ((rand() & (amount+1))-quantum);
02959                 x_distance = QMIN(x_distance, src.width()-1);
02960                 y_distance = QMIN(y_distance, src.height()-1);
02961                 if(x_distance < 0)
02962                     x_distance = 0;
02963                 if(y_distance < 0)
02964                     y_distance = 0;
02965                 p = (unsigned int *)src.scanLine(y_distance);
02966                 p += x_distance;
02967                 *q++=(*p);
02968             }
02969         }
02970     }
02971     else{ // PsudeoClass source image
02972         // just do colortable values
02973         unsigned char *p, *q;
02974         for(y=0; y < src.height(); y++){
02975             q = (unsigned char *)dest.scanLine(y);
02976             for(x=0; x < src.width(); x++){
02977                 x_distance = x + ((rand() & (amount+1))-quantum);
02978                 y_distance = y + ((rand() & (amount+1))-quantum);
02979                 x_distance = QMIN(x_distance, src.width()-1);
02980                 y_distance = QMIN(y_distance, src.height()-1);
02981                 if(x_distance < 0)
02982                     x_distance = 0;
02983                 if(y_distance < 0)
02984                     y_distance = 0;
02985                 p = (unsigned char *)src.scanLine(y_distance);
02986                 p += x_distance;
02987                 *q++=(*p);
02988             }
02989         }
02990     }
02991     return(dest);
02992 }
02993 
02994 QImage KImageEffect::swirl(QImage &src, double degrees,
02995                            unsigned int background)
02996 {
02997     double cosine, distance, factor, radius, sine, x_center, x_distance,
02998         x_scale, y_center, y_distance, y_scale;
02999     int x, y;
03000     unsigned int *q;
03001     QImage dest(src.width(), src.height(), 32);
03002 
03003     // compute scaling factor
03004     x_center = src.width()/2.0;
03005     y_center = src.height()/2.0;
03006     radius = QMAX(x_center,y_center);
03007     x_scale=1.0;
03008     y_scale=1.0;
03009     if(src.width() > src.height())
03010         y_scale=(double)src.width()/src.height();
03011     else if(src.width() < src.height())
03012         x_scale=(double)src.height()/src.width();
03013     degrees=DegreesToRadians(degrees);
03014     // swirl each row
03015     if(src.depth() > 8){ // DirectClass source image
03016         unsigned int *p;
03017         for(y=0; y < src.height(); y++){
03018             p = (unsigned int *)src.scanLine(y);
03019             q = (unsigned int *)dest.scanLine(y);
03020             y_distance = y_scale*(y-y_center);
03021             for(x=0; x < src.width(); x++){
03022                 // determine if the pixel is within an ellipse
03023                 *q=(*p);
03024                 x_distance = x_scale*(x-x_center);
03025                 distance = x_distance*x_distance+y_distance*y_distance;
03026                 if (distance < (radius*radius)){
03027                     // swirl
03028                     factor = 1.0-sqrt(distance)/radius;
03029                     sine = sin(degrees*factor*factor);
03030                     cosine = cos(degrees*factor*factor);
03031                     *q = interpolateColor(&src,
03032                                           (cosine*x_distance-sine*y_distance)/x_scale+x_center,
03033                                           (sine*x_distance+cosine*y_distance)/y_scale+y_center,
03034                                           background);
03035                 }
03036                 p++;
03037                 q++;
03038             }
03039         }
03040     }
03041     else{ // PsudeoClass source image
03042         unsigned char *p;
03043         unsigned int *cTable = (unsigned int *)src.colorTable();
03044         for(y=0; y < src.height(); y++){
03045             p = (unsigned char *)src.scanLine(y);
03046             q = (unsigned int *)dest.scanLine(y);
03047             y_distance = y_scale*(y-y_center);
03048             for(x=0; x < src.width(); x++){
03049                 // determine if the pixel is within an ellipse
03050                 *q = *(cTable+(*p));
03051                 x_distance = x_scale*(x-x_center);
03052                 distance = x_distance*x_distance+y_distance*y_distance;
03053                 if (distance < (radius*radius)){
03054                     // swirl
03055                     factor = 1.0-sqrt(distance)/radius;
03056                     sine = sin(degrees*factor*factor);
03057                     cosine = cos(degrees*factor*factor);
03058                     *q = interpolateColor(&src,
03059                                           (cosine*x_distance-sine*y_distance)/x_scale+x_center,
03060                                           (sine*x_distance+cosine*y_distance)/y_scale+y_center,
03061                                           background);
03062                 }
03063                 p++;
03064                 q++;
03065             }
03066         }
03067 
03068     }
03069     return(dest);
03070 }
03071 
03072 QImage KImageEffect::wave(QImage &src, double amplitude, double wavelength,
03073                           unsigned int background)
03074 {
03075     double *sine_map;
03076     int x, y;
03077     unsigned int *q;
03078 
03079     QImage dest(src.width(), src.height() + (int)(2*fabs(amplitude)), 32);
03080     // allocate sine map
03081     sine_map = (double *)malloc(dest.width()*sizeof(double));
03082     if(!sine_map)
03083         return(src);
03084     for(x=0; x < dest.width(); ++x)
03085         sine_map[x]=fabs(amplitude)+amplitude*sin((2*M_PI*x)/wavelength);
03086     // wave image
03087     for(y=0; y < dest.height(); ++y){
03088         q = (unsigned int *)dest.scanLine(y);
03089         for (x=0; x < dest.width(); x++){
03090             *q=interpolateColor(&src, x, (int)(y-sine_map[x]), background);
03091             ++q;
03092         }
03093     }
03094     free(sine_map);
03095     return(dest);
03096 }
03097 
03098 QImage KImageEffect::oilPaint(QImage &src, int radius)
03099 {
03100     // TODO 8bpp src!
03101     if(src.depth() < 32){
03102         qWarning("Oil Paint source image < 32bpp. Convert before using!");
03103         return(src);
03104     }
03105     int j, k, i, x, y;
03106     unsigned int *histogram;
03107     unsigned int *s;
03108     unsigned int count;
03109 
03110     unsigned int *srcData, *destData;
03111 
03112     QImage dest(src);
03113     dest.detach();
03114     histogram = (unsigned int *) malloc((MaxRGB+1)*sizeof(unsigned int));
03115     if(!histogram)
03116         return(src);
03117     // paint each row
03118     k=0;
03119     for(y = radius; y < src.height(); ++y){
03120         srcData = (unsigned int *)src.scanLine(y-radius);
03121         destData = (unsigned int *)dest.scanLine(y);
03122         srcData += radius*src.width()+radius;
03123         destData += radius;
03124         for(x=radius; x < src.width()-radius; ++x){
03125             // determine most frequent color
03126             count = 0;
03127             for(i=0; i < MaxRGB+1; ++i)
03128                 histogram[i] = 0;
03129             for(i=0; i < radius; ++i){
03130                 s = srcData-(radius-1)*src.width()-i-1;
03131                 for(j =0; j < (2*i+1); ++j){
03132                     k = intensityValue(*s);
03133                     histogram[k]++;
03134                     if(histogram[k] > count){
03135                         *destData = *s;
03136                         count = histogram[k];
03137                     }
03138                     ++s;
03139                 }
03140                 s = srcData+(radius-i)*src.width()-i-1;
03141                 for(j =0; j < (2*i+1); ++j){
03142                     k = intensityValue(*s);
03143                     histogram[k]++;
03144                     if(histogram[k] > count){
03145                         *destData = *s;
03146                         count = histogram[k];
03147                     }
03148                     ++s;
03149                 }
03150             }
03151             s = srcData-radius;
03152             for(j =0; j < (2*i+1); ++j){
03153                 k = intensityValue(*s);
03154                 histogram[k]++;
03155                 if(histogram[k] > count){
03156                     *destData = *s;
03157                     count = histogram[k];
03158                 }
03159                 ++s;
03160             }
03161             ++srcData;
03162             ++destData;
03163         }
03164     }
03165     free(histogram);
03166     return(dest);
03167 }
03168 
03169 //
03170 // The following methods work by computing a value from neighboring pixels
03171 // (mosfet 12/28/01)
03172 //
03173 
03174 QImage KImageEffect::edge(QImage &src, double factor)
03175 {
03176 #define Edge(weight) \
03177     total_red+=(weight)*qRed(*s); \
03178     total_green+=(weight)*qGreen(*s); \
03179     total_blue+=(weight)*qBlue(*s); \
03180     total_opacity+=(weight)*qAlpha(*s); \
03181     s++;
03182 
03183 #define Edge256(weight) \
03184     total_red+=(weight)*qRed(*(cTable+(*s))); \
03185     total_green+=(weight)*qGreen(*(cTable+(*s))); \
03186     total_blue+=(weight)*qBlue(*(cTable+(*s))); \
03187     total_opacity+=(weight)*qAlpha(*(cTable+(*s))); \
03188     s++;
03189 
03190     if(src.width() < 3 || src.height() < 3)
03191         return(src);
03192 
03193     double total_blue, total_green, total_opacity, total_red, weight;
03194 
03195     int x, y;
03196 
03197     unsigned int *q;
03198 
03199     QImage dest(src.width(), src.height(), 32);
03200     weight=factor/8.0;
03201     if(src.depth() > 8){ // DirectClass source image
03202         unsigned int *p, *s;
03203         for(y=0; y < src.height(); ++y){
03204             p = (unsigned int *)src.scanLine(QMIN(QMAX(y-1,0),src.height()-3));
03205             q = (unsigned int *)dest.scanLine(y);
03206             // edge detect this row of pixels.
03207             *q++=(*(p+src.width()));
03208             for(x=1; x < src.width()-1; ++x){
03209                 // compute weighted average of target pixel color components.
03210                 total_red=0.0;
03211                 total_green=0.0;
03212                 total_blue=0.0;
03213                 total_opacity=0.0;
03214                 s=p;
03215                 Edge(-weight/8); Edge(-weight/8) Edge(-weight/8);
03216                 s=p+src.width();
03217                 Edge(-weight/8); Edge(weight); Edge(-weight/8);
03218                 s=p+2*src.width();
03219                 Edge(-weight/8); Edge(-weight/8); Edge(-weight/8);
03220                 *q = qRgba((unsigned char)((total_red < 0) ? 0 : (total_red > MaxRGB) ? MaxRGB : total_red),
03221                            (unsigned char)((total_green < 0) ? 0 : (total_green > MaxRGB) ? MaxRGB : total_green),
03222                            (unsigned char)((total_blue < 0) ? 0 : (total_blue > MaxRGB) ? MaxRGB : total_blue),
03223                            (unsigned char)((total_opacity < 0) ? 0 : (total_opacity > MaxRGB) ? MaxRGB : total_opacity));
03224                 p++;
03225                 q++;
03226             }
03227             p++;
03228             *q++=(*p);
03229         }
03230     }
03231     else{ // PsudeoClass source image
03232         unsigned char *p, *p2, *p3, *s;
03233         unsigned int *cTable = src.colorTable();
03234         int scanLineIdx;
03235         for(y=0; y < src.height(); ++y){
03236             scanLineIdx = QMIN(QMAX(y-1,0),src.height()-3);
03237             p = (unsigned char *)src.scanLine(scanLineIdx);
03238             p2 = (unsigned char *)src.scanLine(scanLineIdx+1);
03239             p3 = (unsigned char *)src.scanLine(scanLineIdx+2);
03240             q = (unsigned int *)dest.scanLine(y);
03241             // edge detect this row of pixels.
03242             *q++=(*(cTable+(*p2)));
03243             for(x=1; x < src.width()-1; ++x){
03244                 // compute weighted average of target pixel color components.
03245                 total_red=0.0;
03246                 total_green=0.0;
03247                 total_blue=0.0;
03248                 total_opacity=0.0;
03249                 s=p;
03250                 Edge256(-weight/8); Edge256(-weight/8) Edge256(-weight/8);
03251                 s=p2;
03252                 Edge256(-weight/8); Edge256(weight); Edge256(-weight/8);
03253                 s=p3;
03254                 Edge256(-weight/8); Edge256(-weight/8); Edge256(-weight/8);
03255                 *q = qRgba((unsigned char)((total_red < 0) ? 0 : (total_red > MaxRGB) ? MaxRGB : total_red),
03256                            (unsigned char)((total_green < 0) ? 0 : (total_green > MaxRGB) ? MaxRGB : total_green),
03257                            (unsigned char)((total_blue < 0) ? 0 : (total_blue > MaxRGB) ? MaxRGB : total_blue),
03258                            (unsigned char)((total_opacity < 0) ? 0 : (total_opacity > MaxRGB) ? MaxRGB : total_opacity));
03259                 p++;
03260                 p2++;
03261                 p3++;
03262                 q++;
03263             }
03264             p++;
03265             *q++=(*(cTable+(*p)));
03266         }
03267     }
03268     return(dest);
03269 }
03270 
03271 QImage KImageEffect::sharpen(QImage &src, double factor)
03272 {
03273 #define Sharpen(weight) \
03274     total_red+=(weight)*qRed(*s); \
03275     total_green+=(weight)*qGreen(*s); \
03276     total_blue+=(weight)*qBlue(*s); \
03277     total_opacity+=(weight)*qAlpha(*s); \
03278     s++;
03279 
03280 #define Sharpen256(weight) \
03281     total_red+=(weight)*qRed(*(cTable+(*s))); \
03282     total_green+=(weight)*qGreen(*(cTable+(*s))); \
03283     total_blue+=(weight)*qBlue(*(cTable+(*s))); \
03284     total_opacity+=(weight)*qAlpha(*(cTable+(*s))); \
03285     s++;
03286 
03287     if(src.width() < 3 || src.height() < 3)
03288         return(src);
03289 
03290     double total_blue, total_green, total_opacity, total_red;
03291     double quantum, weight;
03292     unsigned char r, g, b, a;
03293 
03294     int x, y;
03295     unsigned int *q;
03296 
03297     QImage dest(src.width(), src.height(), 32);
03298     weight = ((100.0-factor)/2.0+13.0);
03299     quantum = QMAX(weight-12.0, 1.0);
03300     if(src.depth() > 8){ // DirectClass source image
03301         unsigned int *p, *s;
03302         for(y=0; y < src.height(); ++y){
03303             p = (unsigned int *)src.scanLine(QMIN(QMAX(y-1,0),src.height()-3));
03304             q = (unsigned int *)dest.scanLine(y);
03305             // sharpen this row of pixels.
03306             *q++=(*(p+src.width()));
03307             for(x=1; x < src.width()-1; ++x){
03308                 // compute weighted average of target pixel color components.
03309                 total_red=0.0;
03310                 total_green=0.0;
03311                 total_blue=0.0;
03312                 total_opacity=0.0;
03313                 s=p;
03314                 Sharpen(-1); Sharpen(-2); Sharpen(-1);
03315                 s=p+src.width();
03316                 Sharpen(-2); Sharpen(weight); Sharpen(-2);
03317                 s=p+2*src.width();
03318                 Sharpen(-1); Sharpen(-2); Sharpen(-1);
03319                 if(total_red < 0)
03320                     r=0;
03321                 else if(total_red > (int)(MaxRGB*quantum))
03322                     r = (unsigned char)MaxRGB;
03323                 else
03324                     r = (unsigned char)((total_red+(quantum/2.0))/quantum);
03325 
03326                 if(total_green < 0)
03327                     g = 0;
03328                 else if(total_green > (int)(MaxRGB*quantum))
03329                     g = (unsigned char)MaxRGB;
03330                 else
03331                     g = (unsigned char)((total_green+(quantum/2.0))/quantum);
03332 
03333                 if(total_blue < 0)
03334                     b = 0;
03335                 else if(total_blue > (int)(MaxRGB*quantum))
03336                     b = (unsigned char)MaxRGB;
03337                 else
03338                     b = (unsigned char)((total_blue+(quantum/2.0))/quantum);
03339 
03340                 if(total_opacity < 0)
03341                     a = 0;
03342                 else if(total_opacity > (int)(MaxRGB*quantum))
03343                     a = (unsigned char)MaxRGB;
03344                 else
03345                     a= (unsigned char)((total_opacity+(quantum/2.0))/quantum);
03346 
03347                 *q = qRgba(r, g, b, a);
03348 
03349                 p++;
03350                 q++;
03351             }
03352             p++;
03353             *q++=(*p);
03354         }
03355     }
03356     else{ // PsudeoClass source image
03357         unsigned char *p, *p2, *p3, *s;
03358         unsigned int *cTable = src.colorTable();
03359         int scanLineIdx;
03360         for(y=0; y < src.height(); ++y){
03361             scanLineIdx = QMIN(QMAX(y-1,0),src.height()-3);
03362             p = (unsigned char *)src.scanLine(scanLineIdx);
03363             p2 = (unsigned char *)src.scanLine(scanLineIdx+1);
03364             p3 = (unsigned char *)src.scanLine(scanLineIdx+2);
03365             q = (unsigned int *)dest.scanLine(y);
03366             // sharpen this row of pixels.
03367             *q++=(*(cTable+(*p2)));
03368             for(x=1; x < src.width()-1; ++x){
03369                 // compute weighted average of target pixel color components.
03370                 total_red=0.0;
03371                 total_green=0.0;
03372                 total_blue=0.0;
03373                 total_opacity=0.0;
03374                 s=p;
03375                 Sharpen256(-1); Sharpen256(-2); Sharpen256(-1);
03376                 s=p2;
03377                 Sharpen256(-2); Sharpen256(weight); Sharpen256(-2);
03378                 s=p3;
03379                 Sharpen256(-1); Sharpen256(-2); Sharpen256(-1);
03380                 if(total_red < 0)
03381                     r=0;
03382                 else if(total_red > (int)(MaxRGB*quantum))
03383                     r = (unsigned char)MaxRGB;
03384                 else
03385                     r = (unsigned char)((total_red+(quantum/2.0))/quantum);
03386 
03387                 if(total_green < 0)
03388                     g = 0;
03389                 else if(total_green > (int)(MaxRGB*quantum))
03390                     g = (unsigned char)MaxRGB;
03391                 else
03392                     g = (unsigned char)((total_green+(quantum/2.0))/quantum);
03393 
03394                 if(total_blue < 0)
03395                     b = 0;
03396                 else if(total_blue > (int)(MaxRGB*quantum))
03397                     b = (unsigned char)MaxRGB;
03398                 else
03399                     b = (unsigned char)((total_blue+(quantum/2.0))/quantum);
03400 
03401                 if(total_opacity < 0)
03402                     a = 0;
03403                 else if(total_opacity > (int)(MaxRGB*quantum))
03404                     a = (unsigned char)MaxRGB;
03405                 else
03406                     a = (unsigned char)((total_opacity+(quantum/2.0))/quantum);
03407 
03408                 *q = qRgba(r, g, b, a);
03409 
03410                 p++;
03411                 p2++;
03412                 p3++;
03413                 q++;
03414             }
03415             p++;
03416             *q++=(*(cTable+(*p)));
03417         }
03418     }
03419     return(dest);
03420 }
03421 
03422 QImage KImageEffect::emboss(QImage &src)
03423 {
03424 #define Emboss(weight) \
03425     total_red+=(weight)*qRed(*s); \
03426     total_green+=(weight)*qGreen(*s); \
03427     total_blue+=(weight)*qBlue(*s); \
03428     s++;
03429 
03430 #define Emboss256(weight) \
03431     total_red+=(weight)*qRed(*(cTable+(*s))); \
03432     total_green+=(weight)*qGreen(*(cTable+(*s))); \
03433     total_blue+=(weight)*qBlue(*(cTable+(*s))); \
03434     s++;
03435 
03436     if(src.width() < 3 || src.height() < 3)
03437         return(src);
03438 
03439     double total_blue, total_green, total_red;
03440     int x, y;
03441     unsigned int *q;
03442 
03443     QImage dest(src.width(), src.height(), 32);
03444     if(src.depth() > 8){ // DirectClass source image
03445         unsigned int *p, *s;
03446         for(y=0; y < src.height(); ++y){
03447             p = (unsigned int *)src.scanLine(QMIN(QMAX(y-1,0),src.height()-3));
03448             q = (unsigned int *)dest.scanLine(y);
03449             // emboss this row of pixels.
03450             *q++=(*(p+src.width()));
03451             for(x=1; x < src.width()-1; ++x){
03452                 // compute weighted average of target pixel color components.
03453                 total_red=0.0;
03454                 total_green=0.0;
03455                 total_blue=0.0;
03456                 s=p;
03457                 Emboss(-1); Emboss(-2); Emboss( 0);
03458                 s=p+src.width();
03459                 Emboss(-2); Emboss( 0); Emboss( 2);
03460                 s=p+2*src.width();
03461                 Emboss( 0); Emboss( 2); Emboss( 1);
03462                 total_red += (MaxRGB+1)/2;
03463                 total_green += (MaxRGB+1)/2;
03464                 total_blue += (MaxRGB+1)/2;
03465                 *q = qRgba((unsigned char)((total_red < 0) ? 0 : (total_red > MaxRGB) ? MaxRGB : total_red),
03466                            (unsigned char)((total_green < 0) ? 0 : (total_green > MaxRGB) ? MaxRGB : total_green),
03467                            (unsigned char)((total_blue < 0) ? 0 : (total_blue > MaxRGB) ? MaxRGB : total_blue),
03468                            255);
03469                 p++;
03470                 q++;
03471             }
03472             p++;
03473             *q++=(*p);
03474         }
03475     }
03476     else{ // PsudeoClass source image
03477         unsigned char *p, *p2, *p3, *s;
03478         unsigned int *cTable = src.colorTable();
03479         int scanLineIdx;
03480         for(y=0; y < src.height(); ++y){
03481             scanLineIdx = QMIN(QMAX(y-1,0),src.height()-3);
03482             p = (unsigned char *)src.scanLine(scanLineIdx);
03483             p2 = (unsigned char *)src.scanLine(scanLineIdx+1);
03484             p3 = (unsigned char *)src.scanLine(scanLineIdx+2);
03485             q = (unsigned int *)dest.scanLine(y);
03486             // emboss this row of pixels.
03487             *q++=(*(cTable+(*p2)));
03488             for(x=1; x < src.width()-1; ++x){
03489                 // compute weighted average of target pixel color components.
03490                 total_red=0.0;
03491                 total_green=0.0;
03492                 total_blue=0.0;
03493                 s=p;
03494                 Emboss256(-1); Emboss256(-2); Emboss256(0);
03495                 s=p2;
03496                 Emboss256(-2); Emboss256(0); Emboss256(2);
03497                 s=p3;
03498                 Emboss256(0); Emboss256(2); Emboss256(1);
03499                 total_red += (MaxRGB+1)/2;
03500                 total_green += (MaxRGB+1)/2;
03501                 total_blue += (MaxRGB+1)/2;
03502                 *q = qRgba((unsigned char)((total_red < 0) ? 0 : (total_red > MaxRGB) ? MaxRGB : total_red),
03503                            (unsigned char)((total_green < 0) ? 0 : (total_green > MaxRGB) ? MaxRGB : total_green),
03504                            (unsigned char)((total_blue < 0) ? 0 : (total_blue > MaxRGB) ? MaxRGB : total_blue),
03505                            255);
03506                 p++;
03507                 p2++;
03508                 p3++;
03509                 q++;
03510             }
03511             p++;
03512             *q++=(*(cTable+(*p)));
03513         }
03514     }
03515     toGray(dest);
03516     normalize(dest);
03517     return(dest);
03518 }
03519 
03520 QImage KImageEffect::shade(QImage &src, bool color_shading, double azimuth,
03521              double elevation)
03522 {
03523     struct PointInfo{
03524         double x, y, z;
03525     };
03526 
03527     double distance, normal_distance, shade;
03528     int x, y;
03529 
03530     struct PointInfo light, normal;
03531 
03532     unsigned int *q;
03533 
03534     QImage dest(src.width(), src.height(), 32);
03535 
03536     azimuth = DegreesToRadians(azimuth);
03537     elevation = DegreesToRadians(elevation);
03538     light.x = MaxRGB*cos(azimuth)*cos(elevation);
03539     light.y = MaxRGB*sin(azimuth)*cos(elevation);
03540     light.z = MaxRGB*sin(elevation);
03541     normal.z= 2*MaxRGB;  // constant Z of surface normal
03542 
03543     if(src.depth() > 8){ // DirectClass source image
03544         unsigned int *p, *s0, *s1, *s2;
03545         for(y=0; y < src.height(); ++y){
03546             p = (unsigned int *)src.scanLine(QMIN(QMAX(y-1,0),src.height()-3));
03547             q = (unsigned int *)dest.scanLine(y);
03548             // shade this row of pixels.
03549             *q++=(*(p+src.width()));
03550             p++;
03551             s0 = p;
03552             s1 = p + src.width();
03553             s2 = p + 2*src.width();
03554             for(x=1; x < src.width()-1; ++x){
03555                 // determine the surface normal and compute shading.
03556                 normal.x=intensityValue(*(s0-1))+intensityValue(*(s1-1))+intensityValue(*(s2-1))-
03557                     (double) intensityValue(*(s0+1))-(double) intensityValue(*(s1+1))-
03558                     (double) intensityValue(*(s2+1));
03559                 normal.y=intensityValue(*(s2-1))+intensityValue(*s2)+intensityValue(*(s2+1))-
03560                     (double) intensityValue(*(s0-1))-(double) intensityValue(*s0)-
03561                     (double) intensityValue(*(s0+1));
03562                 if((normal.x == 0) && (normal.y == 0))
03563                     shade=light.z;
03564                 else{
03565                     shade=0.0;
03566                     distance=normal.x*light.x+normal.y*light.y+normal.z*light.z;
03567                     if (distance > 0.0){
03568                         normal_distance=
03569                             normal.x*normal.x+normal.y*normal.y+normal.z*normal.z;
03570                         if(fabs(normal_distance) > 0.0000001)
03571                             shade=distance/sqrt(normal_distance);
03572                     }
03573                 }
03574                 if(!color_shading){
03575                     *q = qRgba((unsigned char)(shade),
03576                                (unsigned char)(shade),
03577                                (unsigned char)(shade),
03578                                qAlpha(*s1));
03579                 }
03580                 else{
03581                     *q = qRgba((unsigned char)((shade*qRed(*s1))/(MaxRGB+1)),
03582                                (unsigned char)((shade*qGreen(*s1))/(MaxRGB+1)),
03583                                (unsigned char)((shade*qBlue(*s1))/(MaxRGB+1)),
03584                                qAlpha(*s1));
03585                 }
03586                 ++s0;
03587                 ++s1;
03588                 ++s2;
03589                 q++;
03590             }
03591             *q++=(*s1);
03592         }
03593     }
03594     else{ // PsudeoClass source image
03595         unsigned char *p, *s0, *s1, *s2;
03596         int scanLineIdx;
03597         unsigned int *cTable = (unsigned int *)src.colorTable();
03598         for(y=0; y < src.height(); ++y){
03599             scanLineIdx = QMIN(QMAX(y-1,0),src.height()-3);
03600             p = (unsigned char *)src.scanLine(scanLineIdx);
03601             q = (unsigned int *)dest.scanLine(y);
03602             // shade this row of pixels.
03603             s0 = p;
03604             s1 = (unsigned char *) src.scanLine(scanLineIdx+1);
03605             s2 = (unsigned char *) src.scanLine(scanLineIdx+2);
03606             *q++=(*(cTable+(*s1)));
03607             ++p;
03608             ++s0;
03609             ++s1;
03610             ++s2;
03611             for(x=1; x < src.width()-1; ++x){
03612                 // determine the surface normal and compute shading.
03613                 normal.x=intensityValue(*(cTable+(*(s0-1))))+intensityValue(*(cTable+(*(s1-1))))+intensityValue(*(cTable+(*(s2-1))))-
03614                     (double) intensityValue(*(cTable+(*(s0+1))))-(double) intensityValue(*(cTable+(*(s1+1))))-
03615                     (double) intensityValue(*(cTable+(*(s2+1))));
03616                 normal.y=intensityValue(*(cTable+(*(s2-1))))+intensityValue(*(cTable+(*s2)))+intensityValue(*(cTable+(*(s2+1))))-
03617                     (double) intensityValue(*(cTable+(*(s0-1))))-(double) intensityValue(*(cTable+(*s0)))-
03618                     (double) intensityValue(*(cTable+(*(s0+1))));
03619                 if((normal.x == 0) && (normal.y == 0))
03620                     shade=light.z;
03621                 else{
03622                     shade=0.0;
03623                     distance=normal.x*light.x+normal.y*light.y+normal.z*light.z;
03624                     if (distance > 0.0){
03625                         normal_distance=
03626                             normal.x*normal.x+normal.y*normal.y+normal.z*normal.z;
03627                         if(fabs(normal_distance) > 0.0000001)
03628                             shade=distance/sqrt(normal_distance);
03629                     }
03630                 }
03631                 if(!color_shading){
03632                     *q = qRgba((unsigned char)(shade),
03633                                (unsigned char)(shade),
03634                                (unsigned char)(shade),
03635                                qAlpha(*(cTable+(*s1))));
03636                 }
03637                 else{
03638                     *q = qRgba((unsigned char)((shade*qRed(*(cTable+(*s1))))/(MaxRGB+1)),
03639                                (unsigned char)((shade*qGreen(*(cTable+(*s1))))/(MaxRGB+1)),
03640                                (unsigned char)((shade*qBlue(*(cTable+(*s1))))/(MaxRGB+1)),
03641                                qAlpha(*s1));
03642                 }
03643                 ++s0;
03644                 ++s1;
03645                 ++s2;
03646                 q++;
03647             }
03648             *q++=(*(cTable+(*s1)));
03649         }
03650     }
03651     return(dest);
03652 }
03653 
03654 QImage KImageEffect::blur(QImage &src, double factor)
03655 {
03656 
03657 #define Blur(weight) \
03658     total_red+=(weight)*qRed(*s); \
03659     total_green+=(weight)*qGreen(*s); \
03660     total_blue+=(weight)*qBlue(*s); \
03661     total_opacity+=(weight)*qAlpha(*s); \
03662     s++;
03663 
03664 #define Blur256(weight) \
03665     total_red+=(weight)*qRed(*(cTable+(*s))); \
03666     total_green+=(weight)*qGreen(*(cTable+(*s))); \
03667     total_blue+=(weight)*qBlue(*(cTable+(*s))); \
03668     total_opacity+=(weight)*qAlpha(*(cTable+(*s))); \
03669     s++;
03670 
03671     if(src.width() < 3 || src.height() < 3)
03672         return(src);
03673 
03674     double quantum, total_blue, total_green, total_opacity, total_red, weight;
03675 
03676     int x, y;
03677     unsigned int *q;
03678 
03679     QImage dest(src.width(), src.height(), 32);
03680     weight=((100.0-factor)/2)+1;
03681     quantum = QMAX(weight+12.0, 1.0);
03682     if(src.depth() > 8){ // DirectClass source image
03683         unsigned int *p, *s;
03684         for(y=0; y < src.height(); ++y){
03685             p = (unsigned int *)src.scanLine(QMIN(QMAX(y-1,0),src.height()-3));
03686             q = (unsigned int *)dest.scanLine(y);
03687             // blur this row of pixels.
03688             *q++=(*(p+src.width()));
03689             for(x=1; x < src.width()-1; ++x){
03690                 // compute weighted average of target pixel color components.
03691                 total_red=0.0;
03692                 total_green=0.0;
03693                 total_blue=0.0;
03694                 total_opacity=0.0;
03695                 s=p;
03696                 Blur(1); Blur(2); Blur(1);
03697                 s=p+src.width();
03698                 Blur(2); Blur(weight); Blur(2);
03699                 s=p+2*src.width();
03700                 Blur(1); Blur(2); Blur(1);
03701                 *q = qRgba((unsigned char)((total_red+(quantum/2))/quantum),
03702                            (unsigned char)((total_green+(quantum/2))/quantum),
03703                            (unsigned char)((total_blue+(quantum/2))/quantum),
03704                            (unsigned char)((total_opacity+(quantum/2))/quantum));
03705                 p++;
03706                 q++;
03707             }
03708             p++;
03709             *q++=(*p);
03710         }
03711     }
03712     else{ // PsudeoClass source image
03713         unsigned char *p, *p2, *p3, *s;
03714         unsigned int *cTable = src.colorTable();
03715         int scanLineIdx;
03716         for(y=0; y < src.height(); ++y){
03717             scanLineIdx = QMIN(QMAX(y-1,0),src.height()-3);
03718             p = (unsigned char *)src.scanLine(scanLineIdx);
03719             p2 = (unsigned char *)src.scanLine(scanLineIdx+1);
03720             p3 = (unsigned char *)src.scanLine(scanLineIdx+2);
03721             q = (unsigned int *)dest.scanLine(y);
03722             // blur this row of pixels.
03723             *q++=(*(cTable+(*p2)));
03724             for(x=1; x < src.width()-1; ++x){
03725                 // compute weighted average of target pixel color components.
03726                 total_red=0.0;
03727                 total_green=0.0;
03728                 total_blue=0.0;
03729                 total_opacity=0.0;
03730                 s=p;
03731                 Blur256(1); Blur256(2); Blur256(1);
03732                 s=p2;
03733                 Blur256(2); Blur256(weight); Blur256(2);
03734                 s=p3;
03735                 Blur256(1); Blur256(2); Blur256(1);
03736                 *q = qRgba((unsigned char)((total_red+(quantum/2))/quantum),
03737                            (unsigned char)((total_green+(quantum/2))/quantum),
03738                            (unsigned char)((total_blue+(quantum/2))/quantum),
03739                            (unsigned char)((total_opacity+(quantum/2))/quantum));
03740                 p++;
03741                 p2++;
03742                 p3++;
03743                 q++;
03744             }
03745             p++;
03746             *q++=(*(cTable+(*p)));
03747         }
03748     }
03749     return(dest);
03750 }
03751 
03752 // High quality, expensive HSV contrast. You can do a faster one by just
03753 // taking a grayscale threshold (ie: 128) and incrementing RGB color
03754 // channels above it and decrementing those below it, but this gives much
03755 // better results. (mosfet 12/28/01)
03756 void KImageEffect::contrastHSV(QImage &img, bool sharpen)
03757 {
03758     int i, sign;
03759     unsigned int *data;
03760     int count;
03761     double brightness, scale, theta;
03762     QColor c;
03763     int h, s, v;
03764 
03765     sign = sharpen ? 1 : -1;
03766     scale=0.5000000000000001;
03767     if(img.depth() > 8){
03768         count = img.width()*img.height();
03769         data = (unsigned int *)img.bits();
03770     }
03771     else{
03772         count = img.numColors();
03773         data = (unsigned int *)img.colorTable();
03774     }
03775     for(i=0; i < count; ++i){
03776         c.setRgb(data[i]);
03777         c.hsv(&h, &s, &v);
03778         brightness = v/255.0;
03779         theta=(brightness-0.5)*M_PI;
03780         brightness+=scale*(((scale*((sin(theta)+1.0)))-brightness)*sign);
03781         if (brightness > 1.0)
03782             brightness=1.0;
03783         else
03784             if (brightness < 0)
03785                 brightness=0.0;
03786         v = (int)(brightness*255);
03787         c.setHsv(h, s, v);
03788         data[i] = qRgba(c.red(), c.green(), c.blue(), qAlpha(data[i]));
03789     }
03790 }
03791 
03792 
03793 
03794 
KDE Logo
This file is part of the documentation for kdelibs Version 3.1.5.
Documentation copyright © 1996-2002 the KDE developers.
Generated on Wed Jan 28 12:44:22 2004 by doxygen 1.3.4 written by Dimitri van Heesch, © 1997-2001