File indexing completed on 2024-05-12 16:46:37

0001 /*
0002  Copyright (C) 1998, 1999, 2001, 2002, 2004, 2005, 2007
0003       Daniel M. Duley <daniel.duley@verizon.net>
0004  (C) 2004 Zack Rusin <zack@kde.org>
0005  (C) 2000 Josef Weidendorfer <weidendo@in.tum.de>
0006  (C) 1999 Geert Jansen <g.t.jansen@stud.tue.nl>
0007  (C) 1998, 1999 Christian Tibirna <ctibirna@total.net>
0008  (C) 1998, 1999 Dirk Mueller <mueller@kde.org>
0009 
0010 Redistribution and use in source and binary forms, with or without
0011 modification, are permitted provided that the following conditions
0012 are met:
0013 
0014 1. Redistributions of source code must retain the above copyright
0015    notice, this list of conditions and the following disclaimer.
0016 2. Redistributions in binary form must reproduce the above copyright
0017    notice, this list of conditions and the following disclaimer in the
0018    documentation and/or other materials provided with the distribution.
0019 
0020 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
0021 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
0022 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
0023 IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
0024 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
0025 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
0026 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
0027 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
0028 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
0029 THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
0030 */
0031 
0032 /*
0033  Diagonal gradient code was inspired by BlackBox. BlackBox gradients are
0034  (C) Brad Hughes, <bhughes@tcac.net> and Mike Cole <mike@mydot.com>.
0035  */
0036 
0037 #include "gradient.h"
0038 
0039 #include <QColor>
0040 #include <QVector>
0041 
0042 #include <cmath>
0043 
0044 QImage Tellico::gradient(QSize size, const QColor &ca,
0045                          const QColor &cb, Tellico::GradientType eff)
0046 {
0047     QImage image(size, QImage::Format_RGB32);
0048     if(!size.isValid())
0049         return(image);
0050 
0051     int rca, gca, bca, rcb, gcb, bcb;
0052     int rDiff = (rcb = cb.red())   - (rca = ca.red());
0053     int gDiff = (gcb = cb.green()) - (gca = ca.green());
0054     int bDiff = (bcb = cb.blue())  - (bca = ca.blue());
0055     int x, y;
0056     QRgb rgb;
0057 
0058     if(eff == VerticalGradient || eff == HorizontalGradient){
0059         int rl = rca << 16;
0060         int gl = gca << 16;
0061         int bl = bca << 16;
0062         QRgb *p;
0063         if(eff == VerticalGradient){
0064             int rcdelta = ((1<<16) / size.height()) * rDiff;
0065             int gcdelta = ((1<<16) / size.height()) * gDiff;
0066             int bcdelta = ((1<<16) / size.height()) * bDiff;
0067             for(y=0; y < size.height(); ++y){
0068                 rl += rcdelta;
0069                 gl += gcdelta;
0070                 bl += bcdelta;
0071                 rgb = qRgb( (rl>>16), (gl>>16), (bl>>16) );
0072 
0073                 p = reinterpret_cast<QRgb*>(image.scanLine(y));
0074                 for(x = 0; x < size.width(); ++x)
0075                     *p++ = rgb;
0076             }
0077         }
0078         else{                  // must be HorizontalGradient
0079             int rcdelta = ((1<<16) / size.width()) * rDiff;
0080             int gcdelta = ((1<<16) / size.width()) * gDiff;
0081             int bcdelta = ((1<<16) / size.width()) * bDiff;
0082             p = reinterpret_cast<QRgb*>(image.scanLine(0));
0083             for(x = 0; x < size.width(); ++x){
0084                 rl += rcdelta;
0085                 gl += gcdelta;
0086                 bl += bcdelta;
0087                 *p++ = qRgb((rl>>16), (gl>>16), (bl>>16));
0088             }
0089             p = reinterpret_cast<QRgb*>(image.scanLine(0));
0090             for(y = 1; y < size.height(); ++y)
0091                 memcpy(image.scanLine(y), p, size.width()*sizeof(QRgb));
0092         }
0093     }
0094     else{
0095         float rfd, gfd, bfd;
0096         float rd = rca, gd = gca, bd = bca;
0097 
0098         int w = size.width(), h = size.height();
0099         int dw = w*2, dh = h*2;
0100         unsigned char *xtable = new unsigned char[w*3];
0101         unsigned char *ytable = new unsigned char[h*3];
0102 
0103         if(eff == DiagonalGradient || eff == CrossDiagonalGradient){
0104             rfd = (float)rDiff/dw;
0105             gfd = (float)gDiff/dw;
0106             bfd = (float)bDiff/dw;
0107 
0108             int dir;
0109             for(x=0; x < w; x++, rd+=rfd, gd+=gfd, bd+=bfd) {
0110                 dir = eff == DiagonalGradient? x : w - x - 1;
0111                 xtable[dir*3] = (unsigned char) rd;
0112                 xtable[dir*3+1] = (unsigned char) gd;
0113                 xtable[dir*3+2] = (unsigned char) bd;
0114             }
0115             rfd = (float)rDiff/dh;
0116             gfd = (float)gDiff/dh;
0117             bfd = (float)bDiff/dh;
0118             rd = gd = bd = 0;
0119             for(y = 0; y < h; y++, rd+=rfd, gd+=gfd, bd+=bfd){
0120                 ytable[y*3] = (unsigned char) rd;
0121                 ytable[y*3+1] = (unsigned char) gd;
0122                 ytable[y*3+2] = (unsigned char) bd;
0123             }
0124 
0125             for(y = 0; y < h; y++){
0126                 QRgb *p = reinterpret_cast<QRgb*>(image.scanLine(y));
0127                 for(x = 0; x < w; x++){
0128                     *p++ = qRgb(xtable[x*3] + ytable[y*3],
0129                                 xtable[x*3+1] + ytable[y*3+1],
0130                                 xtable[x*3+2] + ytable[y*3+2]);
0131                 }
0132             }
0133         }
0134         else{
0135             int rSign = rDiff>0? 1: -1;
0136             int gSign = gDiff>0? 1: -1;
0137             int bSign = bDiff>0? 1: -1;
0138 
0139             rfd = (float)rDiff/w;
0140             gfd = (float)gDiff/w;
0141             bfd = (float)bDiff/w;
0142 
0143             rd = (float)rDiff/2;
0144             gd = (float)gDiff/2;
0145             bd = (float)bDiff/2;
0146 
0147             for(x=0; x < w; x++, rd-=rfd, gd-=gfd, bd-=bfd){
0148                 xtable[x*3] = (unsigned char) qAbs((int)rd);
0149                 xtable[x*3+1] = (unsigned char) qAbs((int)gd);
0150                 xtable[x*3+2] = (unsigned char) qAbs((int)bd);
0151             }
0152 
0153             rfd = (float)rDiff/h;
0154             gfd = (float)gDiff/h;
0155             bfd = (float)bDiff/h;
0156 
0157             rd = (float)rDiff/2;
0158             gd = (float)gDiff/2;
0159             bd = (float)bDiff/2;
0160 
0161             for(y=0; y < h; y++, rd-=rfd, gd-=gfd, bd-=bfd){
0162                 ytable[y*3] = (unsigned char) qAbs((int)rd);
0163                 ytable[y*3+1] = (unsigned char) qAbs((int)gd);
0164                 ytable[y*3+2] = (unsigned char) qAbs((int)bd);
0165             }
0166 
0167             dw = (w+1)>>1;
0168             dh = (h+1)>>1;
0169             int x2;
0170             QRgb *sl1, *sl2;
0171             for(y = 0; y < dh; y++){
0172                 sl1 = reinterpret_cast<QRgb*>(image.scanLine(y));
0173                 sl2 = reinterpret_cast<QRgb*>(image.scanLine(qMax(h-y-1, y)));
0174                 for(x = 0, x2 = w-1; x < dw; x++, x2--){
0175                     switch(eff){
0176                     case PyramidGradient:
0177                         rgb = qRgb(rcb-rSign*(xtable[x*3]+ytable[y*3]),
0178                                    gcb-gSign*(xtable[x*3+1]+ytable[y*3+1]),
0179                                    bcb-bSign*(xtable[x*3+2]+ytable[y*3+2]));
0180                         break;
0181                     case RectangleGradient:
0182                         rgb = qRgb(rcb - rSign *
0183                                    qMax(xtable[x*3], ytable[y*3]) * 2,
0184                                    gcb - gSign *
0185                                    qMax(xtable[x*3+1], ytable[y*3+1]) * 2,
0186                                    bcb - bSign *
0187                                    qMax(xtable[x*3+2], ytable[y*3+2]) * 2);
0188                         break;
0189                     case PipeCrossGradient:
0190                         rgb = qRgb(rcb - rSign *
0191                                    qMin(xtable[x*3], ytable[y*3]) * 2,
0192                                    gcb - gSign *
0193                                    qMin(xtable[x*3+1], ytable[y*3+1]) * 2,
0194                                    bcb - bSign *
0195                                    qMin(xtable[x*3+2], ytable[y*3+2]) * 2);
0196                         break;
0197                     case EllipticGradient:
0198                     default:
0199                         rgb = qRgb(rcb - rSign *
0200                                    (int)std::sqrt((xtable[x*3]*xtable[x*3] +
0201                                                    ytable[y*3]*ytable[y*3])*2.0f),
0202                                    gcb - gSign *
0203                                    (int)std::sqrt((xtable[x*3+1]*xtable[x*3+1] +
0204                                                    ytable[y*3+1]*ytable[y*3+1])*2.0f),
0205                                    bcb - bSign *
0206                                    (int)std::sqrt((xtable[x*3+2]*xtable[x*3+2] +
0207                                                    ytable[y*3+2]*ytable[y*3+2])*2.0f));
0208                         break;
0209                     }
0210                     sl1[x] = sl2[x] = rgb;
0211                     sl1[x2] = sl2[x2] = rgb;
0212                 }
0213             }
0214         }
0215         delete [] xtable;
0216         delete [] ytable;
0217     }
0218     return(image);
0219 }
0220 
0221 QImage Tellico::grayGradient(QSize size, unsigned char ca,
0222                              unsigned char cb, Tellico::GradientType eff)
0223 {
0224     QImage image(size, QImage::Format_Indexed8);
0225     if(!size.isValid())
0226         return(image);
0227     QVector<QRgb> colorTable(256);
0228     for(int i=0; i < 256; ++i)
0229         colorTable[i] = qRgba(i, i, i, 255);
0230     image.setColorTable(colorTable);
0231 
0232     int diff = cb - ca;
0233     int x, y;
0234     unsigned char idx;
0235 
0236     if(eff == VerticalGradient || eff == HorizontalGradient){
0237         int val = ca << 16;
0238         unsigned char *p;
0239         if(eff == VerticalGradient){
0240             int delta = ((1<<16) / size.height()) * diff;
0241             for(y=0; y < size.height(); ++y){
0242                 val += delta;
0243                 idx = val >> 16;
0244                 p = image.scanLine(y);
0245                 for(x = 0; x < size.width(); ++x)
0246                     *p++ = idx;
0247             }
0248         }
0249         else{                  // must be HorizontalGradient
0250             int delta = ((1<<16) / size.width()) * diff;
0251             p = image.scanLine(0);
0252             for(x = 0; x < size.width(); ++x){
0253                 val += delta;
0254                 *p++ = val >> 16;
0255             }
0256             p = image.scanLine(0);
0257             for(y = 1; y < size.height(); ++y)
0258                 memcpy(image.scanLine(y), p, image.bytesPerLine());
0259         }
0260     }
0261     else{
0262         float delta, val=ca;
0263 
0264         unsigned int w = size.width(), h = size.height();
0265         unsigned char *xtable = new unsigned char[w];
0266         unsigned char *ytable = new unsigned char[h];
0267         w*=2, h*=2;
0268 
0269         if(eff == DiagonalGradient || eff == CrossDiagonalGradient){
0270             delta = (float)diff/w;
0271             int dir;
0272             for(x=0; x < size.width(); x++, val+=delta){
0273                 dir = eff == DiagonalGradient? x : size.width() - x - 1;
0274                 xtable[dir] = (unsigned char) val;
0275             }
0276             delta = (float)diff/h;
0277             val = 0;
0278             for(y = 0; y < size.height(); y++, val+=delta)
0279                 ytable[y] = (unsigned char) val;
0280 
0281             for(y = 0; y < size.height(); y++){
0282                 unsigned char *p = image.scanLine(y);
0283                 for(x = 0; x < size.width(); x++)
0284                     *p++ = xtable[x] + ytable[y];
0285             }
0286         }
0287         else{
0288             int sign = diff>0? 1: -1;
0289             delta = (float)diff / size.width();
0290             val = (float)diff/2;
0291             for(x=0; x < size.width(); x++, val-=delta)
0292                 xtable[x] = (unsigned char) qAbs((int)val);
0293 
0294             delta = (float)diff/size.height();
0295             val = (float)diff/2;
0296             for(y=0; y < size.height(); y++, val-=delta)
0297                 ytable[y] = (unsigned char) qAbs((int)val);
0298 
0299             int w = (size.width()+1)>>1;
0300             int h = (size.height()+1)>>1;
0301             int x2;
0302             unsigned char *sl1, *sl2;
0303             for(y = 0; y < h; y++){
0304                 sl1 = image.scanLine(y);
0305                 sl2 = image.scanLine(qMax(size.height()-y-1, y));
0306                 for(x = 0, x2 = size.width()-1; x < w; x++, x2--){
0307                     switch(eff){
0308                     case PyramidGradient:
0309                         idx = cb-sign*(xtable[x]+ytable[y]);
0310                         break;
0311                     case RectangleGradient:
0312                         idx = cb-sign*qMax(xtable[x], ytable[y])*2;
0313                         break;
0314                     case PipeCrossGradient:
0315                         idx = cb-sign*qMin(xtable[x], ytable[y])*2;
0316                         break;
0317                     case EllipticGradient:
0318                     default:
0319                         idx = cb - sign *
0320                             (int)std::sqrt((xtable[x]*xtable[x] +
0321                                             ytable[y]*ytable[y])*2.0f);
0322                         break;
0323                     }
0324                     sl1[x] = sl2[x] = idx;
0325                     sl1[x2] = sl2[x2] = idx;
0326                 }
0327             }
0328         }
0329         delete [] xtable;
0330         delete [] ytable;
0331     }
0332     return(image);
0333 }
0334 
0335 QImage Tellico::unbalancedGradient(QSize size, const QColor &ca,
0336                                    const QColor &cb, Tellico::GradientType eff,
0337                                    int xfactor, int yfactor)
0338 {
0339     QImage image(size, QImage::Format_RGB32);
0340     if(!size.isValid())
0341         return image;
0342 
0343     int dir; // general parameter used for direction switches
0344     bool _xanti = (xfactor < 0); // negative on X direction
0345     bool _yanti = (yfactor < 0); // negative on Y direction
0346     xfactor = qBound(1, qAbs(xfactor), 200);
0347     yfactor = qBound(1, qAbs(yfactor), 200);
0348     //    float xbal = xfactor/5000.;
0349     //    float ybal = yfactor/5000.;
0350     float xbal = xfactor/30.0f/size.width();
0351     float ybal = yfactor/30.0f/size.height();
0352     float rat;
0353 
0354     int x, y;
0355     int rca, gca, bca, rcb, gcb, bcb;
0356     int rDiff = (rcb = cb.red())   - (rca = ca.red());
0357     int gDiff = (gcb = cb.green()) - (gca = ca.green());
0358     int bDiff = (bcb = cb.blue())  - (bca = ca.blue());
0359 
0360     if(eff == VerticalGradient || eff == HorizontalGradient){
0361         QRgb *p;
0362         if(eff == VerticalGradient){
0363             QRgb rgbRow;
0364             for(y=0; y < size.height(); y++){
0365                 dir = _yanti ? y : size.height() - 1 - y;
0366                 rat =  1 - std::exp( - (float)y  * ybal );
0367                 p = reinterpret_cast<QRgb*>(image.scanLine(dir));
0368                 rgbRow = qRgb(rcb - (int) ( rDiff * rat ),
0369                               gcb - (int) ( gDiff * rat ),
0370                               bcb - (int) ( bDiff * rat ));
0371                 for(x = 0; x < size.width(); x++)
0372                     *p++ = rgbRow;
0373             }
0374         }
0375     else{
0376             p = reinterpret_cast<QRgb*>(image.scanLine(0));
0377             for(x = 0; x < size.width(); x++){
0378                 dir = _xanti ? x : size.width() - 1 - x;
0379                 rat = 1 - std::exp( - (float)x  * xbal );
0380                 p[dir] = qRgb(rcb - (int) ( rDiff * rat ),
0381                               gcb - (int) ( gDiff * rat ),
0382                               bcb - (int) ( bDiff * rat ));
0383             }
0384 
0385             p = reinterpret_cast<QRgb*>(image.scanLine(0));
0386             for(y = 1; y < size.height(); ++y){
0387                 memcpy(image.scanLine(y), p,
0388                        size.width()*sizeof(QRgb));
0389             }
0390         }
0391     }
0392     else{
0393         int w=size.width(), h=size.height();
0394         unsigned char *xtable = new unsigned char[w*3];
0395         unsigned char *ytable = new unsigned char[h*3];
0396         QRgb *p;
0397 
0398         if(eff == DiagonalGradient || eff == CrossDiagonalGradient){
0399             for(x = 0; x < w; x++){
0400                 dir = _xanti ? x : w - 1 - x;
0401                 rat = 1 - std::exp( - (float)x * xbal );
0402 
0403                 xtable[dir*3] = (unsigned char) ( rDiff/2 * rat );
0404                 xtable[dir*3+1] = (unsigned char) ( gDiff/2 * rat );
0405                 xtable[dir*3+2] = (unsigned char) ( bDiff/2 * rat );
0406             }
0407 
0408             for(y = 0; y < h; y++){
0409                 dir = _yanti ? y : h - 1 - y;
0410                 rat =  1 - std::exp( - (float)y  * ybal );
0411 
0412                 ytable[dir*3] = (unsigned char) ( rDiff/2 * rat );
0413                 ytable[dir*3+1] = (unsigned char) ( gDiff/2 * rat );
0414                 ytable[dir*3+2] = (unsigned char) ( bDiff/2 * rat );
0415             }
0416 
0417             for(y = 0; y < h; y++){
0418                 p = reinterpret_cast<QRgb*>(image.scanLine(y));
0419                 for(x = 0; x < w; x++){
0420                     *p++ = qRgb(rcb - (xtable[x*3] + ytable[y*3]),
0421                                 gcb - (xtable[x*3+1] + ytable[y*3+1]),
0422                                 bcb - (xtable[x*3+2] + ytable[y*3+2]));
0423                 }
0424             }
0425         }
0426         else{
0427             int rSign = rDiff>0? 1: -1;
0428             int gSign = gDiff>0? 1: -1;
0429             int bSign = bDiff>0? 1: -1;
0430 
0431             for(x = 0; x < w; x++){
0432                 dir = _xanti ? x : w - 1 - x;
0433                 rat =  1 - std::exp( - (float)x * xbal );
0434 
0435                 xtable[dir*3] = (unsigned char) qAbs((int)(rDiff*(0.5-rat)));
0436                 xtable[dir*3+1] = (unsigned char) qAbs((int)(gDiff*(0.5-rat)));
0437                 xtable[dir*3+2] = (unsigned char) qAbs((int)(bDiff*(0.5-rat)));
0438             }
0439 
0440             for(y = 0; y < h; y++){
0441               dir = _yanti ? y : h - 1 - y;
0442               rat =  1 - std::exp( - (float)y * ybal );
0443 
0444               ytable[dir*3] = (unsigned char) qAbs((int)(rDiff*(0.5-rat)));
0445               ytable[dir*3+1] = (unsigned char) qAbs((int)(gDiff*(0.5-rat)));
0446               ytable[dir*3+2] = (unsigned char) qAbs((int)(bDiff*(0.5-rat)));
0447             }
0448 
0449             for(y = 0; y < h; y++){
0450                 p = reinterpret_cast<QRgb*>(image.scanLine(y));
0451                 for(x = 0; x < w; x++) {
0452                     if (eff == PyramidGradient){
0453                         *p++ = qRgb(rcb-rSign*(xtable[x*3]+ytable[y*3]),
0454                                     gcb-gSign*(xtable[x*3+1]+ytable[y*3+1]),
0455                                     bcb-bSign*(xtable[x*3+2]+ytable[y*3+2]));
0456                     }
0457                     else if (eff == RectangleGradient){
0458                         *p++ = qRgb(rcb - rSign *
0459                                     qMax(xtable[x*3], ytable[y*3]) * 2,
0460                                     gcb - gSign *
0461                                     qMax(xtable[x*3+1], ytable[y*3+1]) * 2,
0462                                     bcb - bSign *
0463                                     qMax(xtable[x*3+2], ytable[y*3+2]) * 2);
0464                     }
0465                     else if (eff == PipeCrossGradient){
0466                         *p++ = qRgb(rcb - rSign *
0467                                     qMin(xtable[x*3], ytable[y*3]) * 2,
0468                                     gcb - gSign *
0469                                     qMin(xtable[x*3+1], ytable[y*3+1]) * 2,
0470                                     bcb - bSign *
0471                                     qMin(xtable[x*3+2], ytable[y*3+2]) * 2);
0472                     }
0473                     else if (eff == EllipticGradient){
0474                         *p++ = qRgb(rcb - rSign *
0475                                     (int)std::sqrt((xtable[x*3]*xtable[x*3] +
0476                                                     ytable[y*3]*ytable[y*3])*2.0),
0477                                     gcb - gSign *
0478                                     (int)std::sqrt((xtable[x*3+1]*xtable[x*3+1] +
0479                                                     ytable[y*3+1]*ytable[y*3+1])*2.0),
0480                                     bcb - bSign *
0481                                     (int)std::sqrt((xtable[x*3+2]*xtable[x*3+2] +
0482                                                     ytable[y*3+2]*ytable[y*3+2])*2.0));
0483                     }
0484                 }
0485             }
0486         }
0487         delete [] xtable;
0488         delete [] ytable;
0489     }
0490     return(image);
0491 }
0492 
0493 QImage Tellico::grayUnbalancedGradient(QSize size, unsigned char ca,
0494                                        unsigned char cb, Tellico::GradientType eff,
0495                                        int xfactor, int yfactor)
0496 {
0497     QImage image(size, QImage::Format_Indexed8);
0498     if(!size.isValid())
0499         return(image);
0500     QVector<QRgb> colorTable(256);
0501     for(int i=0; i < 256; ++i)
0502         colorTable[i] = qRgba(i, i, i, 255);
0503     image.setColorTable(colorTable);
0504 
0505     int dir; // general parameter used for direction switches
0506     bool _xanti = (xfactor < 0); // negative on X direction
0507     bool _yanti = (yfactor < 0); // negative on Y direction
0508     xfactor = qBound(1, qAbs(xfactor), 200);
0509     yfactor = qBound(1, qAbs(yfactor), 200);
0510     float xbal = xfactor/30.0f/size.width();
0511     float ybal = yfactor/30.0f/size.height();
0512     float rat;
0513 
0514     int x, y;
0515     int diff = cb-ca;
0516 
0517     if(eff == VerticalGradient || eff == HorizontalGradient){
0518         unsigned char *p;
0519         if(eff == VerticalGradient){
0520             unsigned char idx;
0521             for(y=0; y < size.height(); y++){
0522                 dir = _yanti ? y : size.height() - 1 - y;
0523                 rat =  1 - std::exp( - (float)y  * ybal );
0524                 p = image.scanLine(dir);
0525                 idx = cb - (int)( diff * rat );
0526                 for(x = 0; x < size.width(); x++)
0527                     *p++ = idx;
0528             }
0529         }
0530     else{
0531             p = image.scanLine(0);
0532             for(x = 0; x < size.width(); x++){
0533                 dir = _xanti ? x : size.width() - 1 - x;
0534                 rat = 1 - std::exp( - (float)x  * xbal );
0535                 p[dir] = cb - (int)( diff * rat );
0536             }
0537 
0538             p = image.scanLine(0);
0539             for(y = 1; y < size.height(); ++y)
0540                 memcpy(image.scanLine(y), p, image.bytesPerLine());
0541         }
0542     }
0543     else{
0544         int w=size.width(), h=size.height();
0545         unsigned char *xtable = new unsigned char[w];
0546         unsigned char *ytable = new unsigned char[h];
0547         unsigned char *p;
0548 
0549         if(eff == DiagonalGradient || eff == CrossDiagonalGradient){
0550             for(x = 0; x < w; x++){
0551                 dir = _xanti ? x : w - 1 - x;
0552                 rat = 1 - std::exp( - (float)x * xbal );
0553                 xtable[dir] = (unsigned char) ( diff/2 * rat );
0554             }
0555 
0556             for(y = 0; y < h; y++){
0557                 dir = _yanti ? y : h - 1 - y;
0558                 rat =  1 - std::exp( - (float)y  * ybal );
0559                 ytable[dir] = (unsigned char) ( diff/2 * rat );
0560             }
0561 
0562             for(y = 0; y < h; y++){
0563                 p = image.scanLine(y);
0564                 for(x = 0; x < w; x++)
0565                     *p++ = cb - (xtable[x] + ytable[y]);
0566             }
0567         }
0568         else{
0569             int sign = diff>0? 1: -1;
0570             for(x = 0; x < w; x++){
0571                 dir = _xanti ? x : w - 1 - x;
0572                 rat =  1 - std::exp( - (float)x * xbal );
0573                 xtable[dir] = (unsigned char) qAbs((int)(diff*(0.5-rat)));
0574             }
0575 
0576             for(y = 0; y < h; y++){
0577                 dir = _yanti ? y : h - 1 - y;
0578                 rat =  1 - std::exp( - (float)y * ybal );
0579                 ytable[dir] = (unsigned char) qAbs((int)(diff*(0.5-rat)));
0580             }
0581 
0582             for(y = 0; y < h; y++){
0583                 p = image.scanLine(y);
0584                 for(x = 0; x < w; x++) {
0585                   if (eff == PyramidGradient)
0586                         *p++ = cb-sign*(xtable[x]+ytable[y]);
0587                     else if (eff == RectangleGradient)
0588                         *p++ = cb -sign*qMax(xtable[x], ytable[y])*2;
0589                     else if (eff == PipeCrossGradient)
0590                         *p++ = cb-sign*qMin(xtable[x], ytable[y])*2;
0591                     else if (eff == EllipticGradient)
0592                         *p++ = cb-sign * (int)std::sqrt((xtable[x]*xtable[x] +
0593                                                          ytable[y]*ytable[y])*2.0);
0594                 }
0595             }
0596         }
0597         delete [] xtable;
0598         delete [] ytable;
0599     }
0600     return(image);
0601 }