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

ogfxeffect.cpp

Go to the documentation of this file.
00001 /* This file is part of the KDE libraries
00002     Copyright (C) 1998, 1999 Christian Tibirna <ctibirna@total.net>
00003               (C) 1998, 1999 Daniel M. Duley <mosfet@kde.org>
00004               (C) 1998, 1999 Dirk A. Mueller <mueller@kde.org>
00005 
00006 */
00007 
00008 // $Id: ogfxeffect.cpp,v 1.6 2004/05/21 20:54:44 ar Exp $
00009 
00010 #include "ogfxeffect.h"
00011 
00012 /* OPIE */
00013 #include <opie2/odebug.h>
00014 #include <qpe/qmath.h>
00015 
00016 /* QT */
00017 #include <qimage.h>
00018 #include <qpainter.h>
00019 
00020 /* STD */
00021 #include <cstdlib>
00022 #include <cmath>
00023 
00024 //======================================================================
00025 //
00026 // Gradient effects
00027 //
00028 //======================================================================
00029 
00030 
00031 QPixmap& OGfxEffect::gradient(QPixmap &pixmap, const QColor &ca,
00032     const QColor &cb, GradientType eff, int ncols)
00033 {
00034     if ( !pixmap. isNull ( )) {
00035         QImage image = gradient(pixmap.size(), ca, cb, eff, ncols);
00036         pixmap.convertFromImage(image);
00037     }
00038     return pixmap;
00039 }
00040 
00041 QImage OGfxEffect::gradient(const QSize &size, const QColor &ca,
00042                             const QColor &cb, GradientType eff, int /*ncols*/)
00043 {
00044     int rDiff, gDiff, bDiff;
00045     int rca, gca, bca, rcb, gcb, bcb;
00046 
00047     QImage image(size, 32);
00048 
00049     if (size.width() == 0 || size.height() == 0) {
00050         odebug << "WARNING: OGfxEffect::gradient: invalid image" << oendl;
00051         return image;
00052     }
00053 
00054     register int x, y;
00055 
00056     rDiff = (rcb = cb.red())   - (rca = ca.red());
00057     gDiff = (gcb = cb.green()) - (gca = ca.green());
00058     bDiff = (bcb = cb.blue())  - (bca = ca.blue());
00059 
00060     if( eff == VerticalGradient || eff == HorizontalGradient ){
00061 
00062         uint *p;
00063         uint rgb;
00064 
00065         register int rl = rca << 16;
00066         register int gl = gca << 16;
00067         register int bl = bca << 16;
00068 
00069         if( eff == VerticalGradient ) {
00070 
00071             int rcdelta = ((1<<16) / size.height()) * rDiff;
00072             int gcdelta = ((1<<16) / size.height()) * gDiff;
00073             int bcdelta = ((1<<16) / size.height()) * bDiff;
00074 
00075             for ( y = 0; y < size.height(); y++ ) {
00076                 p = (uint *) image.scanLine(y);
00077 
00078                 rl += rcdelta;
00079                 gl += gcdelta;
00080                 bl += bcdelta;
00081 
00082                 rgb = qRgb( (rl>>16), (gl>>16), (bl>>16) );
00083 
00084                 for( x = 0; x < size.width(); x++ ) {
00085                     *p = rgb;
00086                     p++;
00087                 }
00088             }
00089 
00090         }
00091         else {                  // must be HorizontalGradient
00092 
00093             unsigned int *o_src = (unsigned int *)image.scanLine(0);
00094             unsigned int *src = o_src;
00095 
00096             int rcdelta = ((1<<16) / size.width()) * rDiff;
00097             int gcdelta = ((1<<16) / size.width()) * gDiff;
00098             int bcdelta = ((1<<16) / size.width()) * bDiff;
00099 
00100             for( x = 0; x < size.width(); x++) {
00101 
00102                 rl += rcdelta;
00103                 gl += gcdelta;
00104                 bl += bcdelta;
00105 
00106                 *src++ = qRgb( (rl>>16), (gl>>16), (bl>>16));
00107             }
00108 
00109             src = o_src;
00110 
00111             // Believe it or not, manually copying in a for loop is faster
00112             // than calling memcpy for each scanline (on the order of ms...).
00113             // I think this is due to the function call overhead (mosfet).
00114 
00115             for (y = 1; y < size.height(); ++y) {
00116 
00117                 p = (unsigned int *)image.scanLine(y);
00118                 src = o_src;
00119                 for(x=0; x < size.width(); ++x)
00120                     *p++ = *src++;
00121             }
00122         }
00123     }
00124 
00125     else {
00126 
00127         float rfd, gfd, bfd;
00128         float rd = rca, gd = gca, bd = bca;
00129 
00130         unsigned char *xtable[3];
00131         unsigned char *ytable[3];
00132 
00133         unsigned int w = size.width(), h = size.height();
00134         xtable[0] = new unsigned char[w];
00135         xtable[1] = new unsigned char[w];
00136         xtable[2] = new unsigned char[w];
00137         ytable[0] = new unsigned char[h];
00138         ytable[1] = new unsigned char[h];
00139         ytable[2] = new unsigned char[h];
00140         w*=2, h*=2;
00141 
00142         if ( eff == DiagonalGradient || eff == CrossDiagonalGradient) {
00143             // Diagonal dgradient code inspired by BlackBox (mosfet)
00144             // BlackBox dgradient is (C) Brad Hughes, <bhughes@tcac.net> and
00145             // Mike Cole <mike@mydot.com>.
00146 
00147             rfd = (float)rDiff/w;
00148             gfd = (float)gDiff/w;
00149             bfd = (float)bDiff/w;
00150 
00151             int dir;
00152             for (x = 0; x < size.width(); x++, rd+=rfd, gd+=gfd, bd+=bfd) {
00153                 dir = eff == DiagonalGradient? x : size.width() - x - 1;
00154                 xtable[0][dir] = (unsigned char) rd;
00155                 xtable[1][dir] = (unsigned char) gd;
00156                 xtable[2][dir] = (unsigned char) bd;
00157             }
00158             rfd = (float)rDiff/h;
00159             gfd = (float)gDiff/h;
00160             bfd = (float)bDiff/h;
00161             rd = gd = bd = 0;
00162             for (y = 0; y < size.height(); y++, rd+=rfd, gd+=gfd, bd+=bfd) {
00163                 ytable[0][y] = (unsigned char) rd;
00164                 ytable[1][y] = (unsigned char) gd;
00165                 ytable[2][y] = (unsigned char) bd;
00166             }
00167 
00168             for (y = 0; y < size.height(); y++) {
00169                 unsigned int *scanline = (unsigned int *)image.scanLine(y);
00170                 for (x = 0; x < size.width(); x++) {
00171                     scanline[x] = qRgb(xtable[0][x] + ytable[0][y],
00172                                        xtable[1][x] + ytable[1][y],
00173                                        xtable[2][x] + ytable[2][y]);
00174                 }
00175             }
00176         }
00177 
00178         else if (eff == RectangleGradient ||
00179                  eff == PyramidGradient ||
00180                  eff == PipeCrossGradient ||
00181                  eff == EllipticGradient)
00182         {
00183             int rSign = rDiff>0? 1: -1;
00184             int gSign = gDiff>0? 1: -1;
00185             int bSign = bDiff>0? 1: -1;
00186 
00187             rfd = (float)rDiff / size.width();
00188             gfd = (float)gDiff / size.width();
00189             bfd = (float)bDiff / size.width();
00190 
00191             rd = (float)rDiff/2;
00192             gd = (float)gDiff/2;
00193             bd = (float)bDiff/2;
00194 
00195             for (x = 0; x < size.width(); x++, rd-=rfd, gd-=gfd, bd-=bfd)
00196             {
00197                 xtable[0][x] = (unsigned char) abs((int)rd);
00198                 xtable[1][x] = (unsigned char) abs((int)gd);
00199                 xtable[2][x] = (unsigned char) abs((int)bd);
00200             }
00201 
00202             rfd = (float)rDiff/size.height();
00203             gfd = (float)gDiff/size.height();
00204             bfd = (float)bDiff/size.height();
00205 
00206             rd = (float)rDiff/2;
00207             gd = (float)gDiff/2;
00208             bd = (float)bDiff/2;
00209 
00210             for (y = 0; y < size.height(); y++, rd-=rfd, gd-=gfd, bd-=bfd)
00211             {
00212                 ytable[0][y] = (unsigned char) abs((int)rd);
00213                 ytable[1][y] = (unsigned char) abs((int)gd);
00214                 ytable[2][y] = (unsigned char) abs((int)bd);
00215             }
00216             unsigned int rgb;
00217             int h = (size.height()+1)>>1;
00218             for (y = 0; y < h; y++) {
00219                 unsigned int *sl1 = (unsigned int *)image.scanLine(y);
00220                 unsigned int *sl2 = (unsigned int *)image.scanLine(QMAX(size.height()-y-1, y));
00221 
00222                 int w = (size.width()+1)>>1;
00223                 int x2 = size.width()-1;
00224 
00225                 for (x = 0; x < w; x++, x2--) {
00226                     rgb = 0;
00227                     if (eff == PyramidGradient) {
00228                         rgb = qRgb(rcb-rSign*(xtable[0][x]+ytable[0][y]),
00229                                    gcb-gSign*(xtable[1][x]+ytable[1][y]),
00230                                    bcb-bSign*(xtable[2][x]+ytable[2][y]));
00231                     }
00232                     if (eff == RectangleGradient) {
00233                         rgb = qRgb(rcb - rSign *
00234                                    QMAX(xtable[0][x], ytable[0][y]) * 2,
00235                                    gcb - gSign *
00236                                    QMAX(xtable[1][x], ytable[1][y]) * 2,
00237                                    bcb - bSign *
00238                                    QMAX(xtable[2][x], ytable[2][y]) * 2);
00239                     }
00240                     if (eff == PipeCrossGradient) {
00241                         rgb = qRgb(rcb - rSign *
00242                                    QMIN(xtable[0][x], ytable[0][y]) * 2,
00243                                    gcb - gSign *
00244                                    QMIN(xtable[1][x], ytable[1][y]) * 2,
00245                                    bcb - bSign *
00246                                    QMIN(xtable[2][x], ytable[2][y]) * 2);
00247                     }
00248                     if (eff == EllipticGradient) {
00249                         rgb = qRgb(rcb - rSign *
00250                                    (int)sqrt((xtable[0][x]*xtable[0][x] +
00251                                               ytable[0][y]*ytable[0][y])*2.0),
00252                                    gcb - gSign *
00253                                    (int)sqrt((xtable[1][x]*xtable[1][x] +
00254                                               ytable[1][y]*ytable[1][y])*2.0),
00255                                    bcb - bSign *
00256                                    (int)sqrt((xtable[2][x]*xtable[2][x] +
00257                                               ytable[2][y]*ytable[2][y])*2.0));
00258                     }
00259 
00260                     sl1[x] = sl2[x] = rgb;
00261                     sl1[x2] = sl2[x2] = rgb;
00262                 }
00263             }
00264         }
00265 
00266         delete [] xtable[0];
00267         delete [] xtable[1];
00268         delete [] xtable[2];
00269         delete [] ytable[0];
00270         delete [] ytable[1];
00271         delete [] ytable[2];
00272     }
00273     return image;
00274 }
00275 
00276 
00277 //======================================================================
00278 //
00279 // Blend effects
00280 //
00281 //======================================================================
00282 
00283 
00284 QPixmap& OGfxEffect::blend(QPixmap &pixmap, float initial_intensity,
00285               const QColor &bgnd, GradientType eff,
00286               bool anti_dir, int /*ncols*/)
00287 {
00288     if ( !pixmap. isNull ( )) {
00289         QImage image = pixmap.convertToImage();
00290         OGfxEffect::blend(image, initial_intensity, bgnd, eff, anti_dir);
00291 
00292         if ( pixmap. depth ( ) <= 8 )
00293             image. convertDepth ( pixmap. depth ( ));
00294 
00295         pixmap.convertFromImage(image);
00296     }
00297     return pixmap;
00298 }
00299 
00300 
00301 QImage& OGfxEffect::blend(QImage &image, float initial_intensity,
00302                             const QColor &bgnd, GradientType eff,
00303                             bool anti_dir)
00304 {
00305     if (image.width() == 0 || image.height() == 0) {
00306       odebug << "Invalid image" << oendl;
00307       return image;
00308     }
00309 
00310     int r_bgnd = bgnd.red(), g_bgnd = bgnd.green(), b_bgnd = bgnd.blue();
00311     int r, g, b;
00312     int ind;
00313 
00314     unsigned int xi, xf, yi, yf;
00315     unsigned int a;
00316 
00317     // check the boundaries of the initial intesity param
00318     float unaffected = 1;
00319     if (initial_intensity >  1) initial_intensity =  1;
00320     if (initial_intensity < -1) initial_intensity = -1;
00321     if (initial_intensity < 0) {
00322         unaffected = 1. + initial_intensity;
00323         initial_intensity = 0;
00324     }
00325 
00326 
00327     float intensity = initial_intensity;
00328     float var = 1. - initial_intensity;
00329 
00330     if (anti_dir) {
00331         initial_intensity = intensity = 1.;
00332         var = -var;
00333     }
00334 
00335     register int x, y;
00336 
00337     unsigned int *data =  (unsigned int *)image.bits();
00338 
00339     if( eff == VerticalGradient || eff == HorizontalGradient ) {
00340 
00341         // set the image domain to apply the effect to
00342         xi = 0, xf = image.width();
00343         yi = 0, yf = image.height();
00344         if (eff == VerticalGradient) {
00345             if (anti_dir) yf = (int)(image.height() * unaffected);
00346             else yi = (int)(image.height() * (1 - unaffected));
00347         }
00348         else {
00349             if (anti_dir) xf = (int)(image.width() * unaffected);
00350             else xi = (int)(image.height() * (1 - unaffected));
00351         }
00352 
00353         var /= (eff == VerticalGradient?yf-yi:xf-xi);
00354 
00355         for (y = yi; y < (int)yf; y++) {
00356             intensity = eff == VerticalGradient? intensity + var :
00357                 initial_intensity;
00358             for (x = xi; x < (int)xf ; x++) {
00359                 if (eff == HorizontalGradient) intensity += var;
00360                 ind = x + image.width()  * y ;
00361                 r = qRed  (data[ind]) + (int)(intensity *
00362                                               (r_bgnd - qRed  (data[ind])));
00363                 g = qGreen(data[ind]) + (int)(intensity *
00364                                               (g_bgnd - qGreen(data[ind])));
00365                 b = qBlue (data[ind]) + (int)(intensity *
00366                                               (b_bgnd - qBlue (data[ind])));
00367                 if (r > 255) r = 255; if (r < 0 ) r = 0;
00368                 if (g > 255) g = 255; if (g < 0 ) g = 0;
00369                 if (b > 255) b = 255; if (b < 0 ) b = 0;
00370                 a = qAlpha(data[ind]);
00371                 data[ind] = qRgba(r, g, b, a);
00372             }
00373         }
00374     }
00375     else if (eff == DiagonalGradient  || eff == CrossDiagonalGradient) {
00376         float xvar = var / 2 / image.width();  // / unaffected;
00377         float yvar = var / 2 / image.height(); // / unaffected;
00378         float tmp;
00379 
00380         for (x = 0; x < image.width() ; x++) {
00381             tmp =  xvar * (eff == DiagonalGradient? x : image.width()-x-1);
00382             for (y = 0; y < image.height() ; y++) {
00383                 intensity = initial_intensity + tmp + yvar * y;
00384                 ind = x + image.width()  * y ;
00385                 r = qRed  (data[ind]) + (int)(intensity *
00386                                               (r_bgnd - qRed  (data[ind])));
00387                 g = qGreen(data[ind]) + (int)(intensity *
00388                                               (g_bgnd - qGreen(data[ind])));
00389                 b = qBlue (data[ind]) + (int)(intensity *
00390                                               (b_bgnd - qBlue (data[ind])));
00391                 if (r > 255) r = 255; if (r < 0 ) r = 0;
00392                 if (g > 255) g = 255; if (g < 0 ) g = 0;
00393                 if (b > 255) b = 255; if (b < 0 ) b = 0;
00394                 a = qAlpha(data[ind]);
00395                 data[ind] = qRgba(r, g, b, a);
00396             }
00397         }
00398     }
00399 
00400     else if (eff == RectangleGradient || eff == EllipticGradient) {
00401         float xvar;
00402         float yvar;
00403 
00404         for (x = 0; x < image.width() / 2 + image.width() % 2; x++) {
00405             xvar = var / image.width()  * (image.width() - x*2/unaffected-1);
00406             for (y = 0; y < image.height() / 2 + image.height() % 2; y++) {
00407                 yvar = var / image.height()   * (image.height() - y*2/unaffected -1);
00408 
00409                 if (eff == RectangleGradient)
00410                     intensity = initial_intensity + QMAX(xvar, yvar);
00411                 else
00412                     intensity = initial_intensity + qSqrt(xvar * xvar + yvar * yvar);
00413                 if (intensity > 1) intensity = 1;
00414                 if (intensity < 0) intensity = 0;
00415 
00416                 //NW
00417                 ind = x + image.width()  * y ;
00418                 r = qRed  (data[ind]) + (int)(intensity *
00419                                               (r_bgnd - qRed  (data[ind])));
00420                 g = qGreen(data[ind]) + (int)(intensity *
00421                                               (g_bgnd - qGreen(data[ind])));
00422                 b = qBlue (data[ind]) + (int)(intensity *
00423                                               (b_bgnd - qBlue (data[ind])));
00424                 if (r > 255) r = 255; if (r < 0 ) r = 0;
00425                 if (g > 255) g = 255; if (g < 0 ) g = 0;
00426                 if (b > 255) b = 255; if (b < 0 ) b = 0;
00427                 a = qAlpha(data[ind]);
00428                 data[ind] = qRgba(r, g, b, a);
00429 
00430                 //NE
00431                 ind = image.width() - x - 1 + image.width()  * y ;
00432                 r = qRed  (data[ind]) + (int)(intensity *
00433                                               (r_bgnd - qRed  (data[ind])));
00434                 g = qGreen(data[ind]) + (int)(intensity *
00435                                               (g_bgnd - qGreen(data[ind])));
00436                 b = qBlue (data[ind]) + (int)(intensity *
00437                                               (b_bgnd - qBlue (data[ind])));
00438                 if (r > 255) r = 255; if (r < 0 ) r = 0;
00439                 if (g > 255) g = 255; if (g < 0 ) g = 0;
00440                 if (b > 255) b = 255; if (b < 0 ) b = 0;
00441                 a = qAlpha(data[ind]);
00442                 data[ind] = qRgba(r, g, b, a);
00443             }
00444         }
00445 
00446         //CT  loop is doubled because of stupid central row/column issue.
00447         //    other solution?
00448         for (x = 0; x < image.width() / 2; x++) {
00449             xvar = var / image.width()  * (image.width() - x*2/unaffected-1);
00450             for (y = 0; y < image.height() / 2; y++) {
00451                 yvar = var / image.height()   * (image.height() - y*2/unaffected -1);
00452 
00453                 if (eff == RectangleGradient)
00454                     intensity = initial_intensity + QMAX(xvar, yvar);
00455                 else
00456                     intensity = initial_intensity + qSqrt(xvar * xvar + yvar * yvar);
00457                 if (intensity > 1) intensity = 1;
00458                 if (intensity < 0) intensity = 0;
00459 
00460                 //SW
00461                 ind = x + image.width()  * (image.height() - y -1) ;
00462                 r = qRed  (data[ind]) + (int)(intensity *
00463                                               (r_bgnd - qRed  (data[ind])));
00464                 g = qGreen(data[ind]) + (int)(intensity *
00465                                               (g_bgnd - qGreen(data[ind])));
00466                 b = qBlue (data[ind]) + (int)(intensity *
00467                                               (b_bgnd - qBlue (data[ind])));
00468                 if (r > 255) r = 255; if (r < 0 ) r = 0;
00469                 if (g > 255) g = 255; if (g < 0 ) g = 0;
00470                 if (b > 255) b = 255; if (b < 0 ) b = 0;
00471                 a = qAlpha(data[ind]);
00472                 data[ind] = qRgba(r, g, b, a);
00473 
00474                 //SE
00475                 ind = image.width()-x-1 + image.width() * (image.height() - y - 1) ;
00476                 r = qRed  (data[ind]) + (int)(intensity *
00477                                               (r_bgnd - qRed  (data[ind])));
00478                 g = qGreen(data[ind]) + (int)(intensity *
00479                                               (g_bgnd - qGreen(data[ind])));
00480                 b = qBlue (data[ind]) + (int)(intensity *
00481                                               (b_bgnd - qBlue (data[ind])));
00482                 if (r > 255) r = 255; if (r < 0 ) r = 0;
00483                 if (g > 255) g = 255; if (g < 0 ) g = 0;
00484                 if (b > 255) b = 255; if (b < 0 ) b = 0;
00485                 a = qAlpha(data[ind]);
00486                 data[ind] = qRgba(r, g, b, a);
00487             }
00488         }
00489     }
00490 
00491     else
00492         odebug << "not implemented" << oendl;
00493 
00494     return image;
00495 }
00496 
00497 #if 0
00498 // Not very efficient as we create a third big image...
00499 //
00500 QImage& KQGfxEffect::blend(QImage &image1, QImage &image2,
00501                 GradientType gt, int xf, int yf)
00502 {
00503   if (image1.width() == 0 || image1.height() == 0 ||
00504       image2.width() == 0 || image2.height() == 0)
00505     return image1;
00506 
00507   QImage image3;
00508 
00509   image3 = KQGfxEffect::unbalancedGradient(image1.size(),
00510                     QColor(0,0,0), QColor(255,255,255),
00511                     gt, xf, yf, 0);
00512 
00513   return blend(image1,image2,image3, Red); // Channel to use is arbitrary
00514 }
00515 #endif

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