Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

oimageeffect.cpp

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

Generated on Sat Nov 5 16:16:26 2005 for OPIE by  doxygen 1.4.2