00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034 #include <math.h>
00035 #include <assert.h>
00036
00037 #include <qimage.h>
00038 #include <stdlib.h>
00039 #include <iostream>
00040
00041 #include "kimageeffect.h"
00042 #include "kcpuinfo.h"
00043
00044 #include <config.h>
00045
00046 #if 0
00047
00048
00049 #if defined(__i386__) && ( defined(__GNUC__) || defined(__INTEL_COMPILER) )
00050 # if defined( HAVE_X86_MMX )
00051 # define USE_MMX_INLINE_ASM
00052 # endif
00053 # if defined( HAVE_X86_SSE2 )
00054 # define USE_SSE2_INLINE_ASM
00055 # endif
00056 #endif
00057
00058 #endif
00059
00060
00061
00062
00063
00064 #define MaxRGB 255L
00065 #define DegreesToRadians(x) ((x)*M_PI/180.0)
00066 #define MagickSQ2PI 2.50662827463100024161235523934010416269302368164062
00067 #define MagickEpsilon 1.0e-12
00068 #define MagickPI 3.14159265358979323846264338327950288419716939937510
00069 #define MOD(x, y) ((x) < 0 ? ((y) - 1 - ((y) - 1 - (x)) % (y)) : (x) % (y))
00070
00076 #define FXCLAMP(x,low,high) fxClamp(x,low,high)
00077 template<class T>
00078 inline const T& fxClamp( const T& x, const T& low, const T& high )
00079 {
00080 if ( x < low ) return low;
00081 else if ( x > high ) return high;
00082 else return x;
00083 }
00084
00085 static inline unsigned int intensityValue(unsigned int color)
00086 {
00087 return((unsigned int)((0.299*qRed(color) +
00088 0.587*qGreen(color) +
00089 0.1140000000000001*qBlue(color))));
00090 }
00091
00092 template<typename T>
00093 static inline void liberateMemory(T **memory)
00094 {
00095 assert(memory != NULL);
00096 if(*memory == NULL) return;
00097 free((char*)*memory);
00098 *memory=NULL;
00099 }
00100
00101 struct double_packet
00102 {
00103 double red;
00104 double green;
00105 double blue;
00106 double alpha;
00107 };
00108
00109 struct short_packet
00110 {
00111 unsigned short int red;
00112 unsigned short int green;
00113 unsigned short int blue;
00114 unsigned short int alpha;
00115 };
00116
00117
00118
00119
00120
00121
00122
00123
00124 QImage KImageEffect::gradient(const QSize &size, const QColor &ca,
00125 const QColor &cb, GradientType eff, int ncols)
00126 {
00127 int rDiff, gDiff, bDiff;
00128 int rca, gca, bca, rcb, gcb, bcb;
00129
00130 QImage image(size, 32);
00131
00132 if (size.width() == 0 || size.height() == 0) {
00133 #ifndef NDEBUG
00134 std::cerr << "WARNING: KImageEffect::gradient: invalid image" << std::endl;
00135 #endif
00136 return image;
00137 }
00138
00139 register int x, y;
00140
00141 rDiff = (rcb = cb.red()) - (rca = ca.red());
00142 gDiff = (gcb = cb.green()) - (gca = ca.green());
00143 bDiff = (bcb = cb.blue()) - (bca = ca.blue());
00144
00145 if( eff == VerticalGradient || eff == HorizontalGradient ){
00146
00147 uint *p;
00148 uint rgb;
00149
00150 register int rl = rca << 16;
00151 register int gl = gca << 16;
00152 register int bl = bca << 16;
00153
00154 if( eff == VerticalGradient ) {
00155
00156 int rcdelta = ((1<<16) / size.height()) * rDiff;
00157 int gcdelta = ((1<<16) / size.height()) * gDiff;
00158 int bcdelta = ((1<<16) / size.height()) * bDiff;
00159
00160 for ( y = 0; y < size.height(); y++ ) {
00161 p = (uint *) image.scanLine(y);
00162
00163 rl += rcdelta;
00164 gl += gcdelta;
00165 bl += bcdelta;
00166
00167 rgb = qRgb( (rl>>16), (gl>>16), (bl>>16) );
00168
00169 for( x = 0; x < size.width(); x++ ) {
00170 *p = rgb;
00171 p++;
00172 }
00173 }
00174
00175 }
00176 else {
00177
00178 unsigned int *o_src = (unsigned int *)image.scanLine(0);
00179 unsigned int *src = o_src;
00180
00181 int rcdelta = ((1<<16) / size.width()) * rDiff;
00182 int gcdelta = ((1<<16) / size.width()) * gDiff;
00183 int bcdelta = ((1<<16) / size.width()) * bDiff;
00184
00185 for( x = 0; x < size.width(); x++) {
00186
00187 rl += rcdelta;
00188 gl += gcdelta;
00189 bl += bcdelta;
00190
00191 *src++ = qRgb( (rl>>16), (gl>>16), (bl>>16));
00192 }
00193
00194 src = o_src;
00195
00196
00197
00198
00199
00200 for (y = 1; y < size.height(); ++y) {
00201
00202 p = (unsigned int *)image.scanLine(y);
00203 src = o_src;
00204 for(x=0; x < size.width(); ++x)
00205 *p++ = *src++;
00206 }
00207 }
00208 }
00209
00210 else {
00211
00212 float rfd, gfd, bfd;
00213 float rd = rca, gd = gca, bd = bca;
00214
00215 unsigned char *xtable[3];
00216 unsigned char *ytable[3];
00217
00218 unsigned int w = size.width(), h = size.height();
00219 xtable[0] = new unsigned char[w];
00220 xtable[1] = new unsigned char[w];
00221 xtable[2] = new unsigned char[w];
00222 ytable[0] = new unsigned char[h];
00223 ytable[1] = new unsigned char[h];
00224 ytable[2] = new unsigned char[h];
00225 w*=2, h*=2;
00226
00227 if ( eff == DiagonalGradient || eff == CrossDiagonalGradient) {
00228
00229
00230
00231
00232 rfd = (float)rDiff/w;
00233 gfd = (float)gDiff/w;
00234 bfd = (float)bDiff/w;
00235
00236 int dir;
00237 for (x = 0; x < size.width(); x++, rd+=rfd, gd+=gfd, bd+=bfd) {
00238 dir = eff == DiagonalGradient? x : size.width() - x - 1;
00239 xtable[0][dir] = (unsigned char) rd;
00240 xtable[1][dir] = (unsigned char) gd;
00241 xtable[2][dir] = (unsigned char) bd;
00242 }
00243 rfd = (float)rDiff/h;
00244 gfd = (float)gDiff/h;
00245 bfd = (float)bDiff/h;
00246 rd = gd = bd = 0;
00247 for (y = 0; y < size.height(); y++, rd+=rfd, gd+=gfd, bd+=bfd) {
00248 ytable[0][y] = (unsigned char) rd;
00249 ytable[1][y] = (unsigned char) gd;
00250 ytable[2][y] = (unsigned char) bd;
00251 }
00252
00253 for (y = 0; y < size.height(); y++) {
00254 unsigned int *scanline = (unsigned int *)image.scanLine(y);
00255 for (x = 0; x < size.width(); x++) {
00256 scanline[x] = qRgb(xtable[0][x] + ytable[0][y],
00257 xtable[1][x] + ytable[1][y],
00258 xtable[2][x] + ytable[2][y]);
00259 }
00260 }
00261 }
00262
00263 else if (eff == RectangleGradient ||
00264 eff == PyramidGradient ||
00265 eff == PipeCrossGradient ||
00266 eff == EllipticGradient)
00267 {
00268 int rSign = rDiff>0? 1: -1;
00269 int gSign = gDiff>0? 1: -1;
00270 int bSign = bDiff>0? 1: -1;
00271
00272 rfd = (float)rDiff / size.width();
00273 gfd = (float)gDiff / size.width();
00274 bfd = (float)bDiff / size.width();
00275
00276 rd = (float)rDiff/2;
00277 gd = (float)gDiff/2;
00278 bd = (float)bDiff/2;
00279
00280 for (x = 0; x < size.width(); x++, rd-=rfd, gd-=gfd, bd-=bfd)
00281 {
00282 xtable[0][x] = (unsigned char) abs((int)rd);
00283 xtable[1][x] = (unsigned char) abs((int)gd);
00284 xtable[2][x] = (unsigned char) abs((int)bd);
00285 }
00286
00287 rfd = (float)rDiff/size.height();
00288 gfd = (float)gDiff/size.height();
00289 bfd = (float)bDiff/size.height();
00290
00291 rd = (float)rDiff/2;
00292 gd = (float)gDiff/2;
00293 bd = (float)bDiff/2;
00294
00295 for (y = 0; y < size.height(); y++, rd-=rfd, gd-=gfd, bd-=bfd)
00296 {
00297 ytable[0][y] = (unsigned char) abs((int)rd);
00298 ytable[1][y] = (unsigned char) abs((int)gd);
00299 ytable[2][y] = (unsigned char) abs((int)bd);
00300 }
00301
00302 int h = (size.height()+1)>>1;
00303 for (y = 0; y < h; y++) {
00304 unsigned int *sl1 = (unsigned int *)image.scanLine(y);
00305 unsigned int *sl2 = (unsigned int *)image.scanLine(QMAX(size.height()-y-1, y));
00306
00307 int w = (size.width()+1)>>1;
00308 int x2 = size.width()-1;
00309
00310 for (x = 0; x < w; x++, x2--) {
00311 unsigned int rgb = 0;
00312 if (eff == PyramidGradient) {
00313 rgb = qRgb(rcb-rSign*(xtable[0][x]+ytable[0][y]),
00314 gcb-gSign*(xtable[1][x]+ytable[1][y]),
00315 bcb-bSign*(xtable[2][x]+ytable[2][y]));
00316 }
00317 if (eff == RectangleGradient) {
00318 rgb = qRgb(rcb - rSign *
00319 QMAX(xtable[0][x], ytable[0][y]) * 2,
00320 gcb - gSign *
00321 QMAX(xtable[1][x], ytable[1][y]) * 2,
00322 bcb - bSign *
00323 QMAX(xtable[2][x], ytable[2][y]) * 2);
00324 }
00325 if (eff == PipeCrossGradient) {
00326 rgb = qRgb(rcb - rSign *
00327 QMIN(xtable[0][x], ytable[0][y]) * 2,
00328 gcb - gSign *
00329 QMIN(xtable[1][x], ytable[1][y]) * 2,
00330 bcb - bSign *
00331 QMIN(xtable[2][x], ytable[2][y]) * 2);
00332 }
00333 if (eff == EllipticGradient) {
00334 rgb = qRgb(rcb - rSign *
00335 (int)sqrt((xtable[0][x]*xtable[0][x] +
00336 ytable[0][y]*ytable[0][y])*2.0),
00337 gcb - gSign *
00338 (int)sqrt((xtable[1][x]*xtable[1][x] +
00339 ytable[1][y]*ytable[1][y])*2.0),
00340 bcb - bSign *
00341 (int)sqrt((xtable[2][x]*xtable[2][x] +
00342 ytable[2][y]*ytable[2][y])*2.0));
00343 }
00344
00345 sl1[x] = sl2[x] = rgb;
00346 sl1[x2] = sl2[x2] = rgb;
00347 }
00348 }
00349 }
00350
00351 delete [] xtable[0];
00352 delete [] xtable[1];
00353 delete [] xtable[2];
00354 delete [] ytable[0];
00355 delete [] ytable[1];
00356 delete [] ytable[2];
00357 }
00358
00359
00360 if (ncols && (QPixmap::defaultDepth() < 15 )) {
00361 if ( ncols < 2 || ncols > 256 )
00362 ncols = 3;
00363 QColor *dPal = new QColor[ncols];
00364 for (int i=0; i<ncols; i++) {
00365 dPal[i].setRgb ( rca + rDiff * i / ( ncols - 1 ),
00366 gca + gDiff * i / ( ncols - 1 ),
00367 bca + bDiff * i / ( ncols - 1 ) );
00368 }
00369 dither(image, dPal, ncols);
00370 delete [] dPal;
00371 }
00372
00373 return image;
00374 }
00375
00376
00377
00378
00379
00380
00381
00382
00383
00384
00385
00386
00387
00388 QImage KImageEffect::unbalancedGradient(const QSize &size, const QColor &ca,
00389 const QColor &cb, GradientType eff, int xfactor, int yfactor,
00390 int ncols)
00391 {
00392 int dir;
00393
00394 bool _xanti = false , _yanti = false;
00395
00396 if (xfactor < 0) _xanti = true;
00397 if (yfactor < 0) _yanti = true;
00398
00399 xfactor = abs(xfactor);
00400 yfactor = abs(yfactor);
00401
00402 if (!xfactor) xfactor = 1;
00403 if (!yfactor) yfactor = 1;
00404
00405 if (xfactor > 200 ) xfactor = 200;
00406 if (yfactor > 200 ) yfactor = 200;
00407
00408
00409
00410
00411 float xbal = xfactor/30./size.width();
00412 float ybal = yfactor/30./size.height();
00413 float rat;
00414
00415 int rDiff, gDiff, bDiff;
00416 int rca, gca, bca, rcb, gcb, bcb;
00417
00418 QImage image(size, 32);
00419
00420 if (size.width() == 0 || size.height() == 0) {
00421 #ifndef NDEBUG
00422 std::cerr << "WARNING: KImageEffect::unbalancedGradient : invalid image\n";
00423 #endif
00424 return image;
00425 }
00426
00427 register int x, y;
00428 unsigned int *scanline;
00429
00430 rDiff = (rcb = cb.red()) - (rca = ca.red());
00431 gDiff = (gcb = cb.green()) - (gca = ca.green());
00432 bDiff = (bcb = cb.blue()) - (bca = ca.blue());
00433
00434 if( eff == VerticalGradient || eff == HorizontalGradient){
00435 QColor cRow;
00436
00437 uint *p;
00438 uint rgbRow;
00439
00440 if( eff == VerticalGradient) {
00441 for ( y = 0; y < size.height(); y++ ) {
00442 dir = _yanti ? y : size.height() - 1 - y;
00443 p = (uint *) image.scanLine(dir);
00444 rat = 1 - exp( - (float)y * ybal );
00445
00446 cRow.setRgb( rcb - (int) ( rDiff * rat ),
00447 gcb - (int) ( gDiff * rat ),
00448 bcb - (int) ( bDiff * rat ) );
00449
00450 rgbRow = cRow.rgb();
00451
00452 for( x = 0; x < size.width(); x++ ) {
00453 *p = rgbRow;
00454 p++;
00455 }
00456 }
00457 }
00458 else {
00459
00460 unsigned int *src = (unsigned int *)image.scanLine(0);
00461 for(x = 0; x < size.width(); x++ )
00462 {
00463 dir = _xanti ? x : size.width() - 1 - x;
00464 rat = 1 - exp( - (float)x * xbal );
00465
00466 src[dir] = qRgb(rcb - (int) ( rDiff * rat ),
00467 gcb - (int) ( gDiff * rat ),
00468 bcb - (int) ( bDiff * rat ));
00469 }
00470
00471
00472
00473
00474
00475 for(y = 1; y < size.height(); ++y)
00476 {
00477 scanline = (unsigned int *)image.scanLine(y);
00478 for(x=0; x < size.width(); ++x)
00479 scanline[x] = src[x];
00480 }
00481 }
00482 }
00483
00484 else {
00485 int w=size.width(), h=size.height();
00486
00487 unsigned char *xtable[3];
00488 unsigned char *ytable[3];
00489 xtable[0] = new unsigned char[w];
00490 xtable[1] = new unsigned char[w];
00491 xtable[2] = new unsigned char[w];
00492 ytable[0] = new unsigned char[h];
00493 ytable[1] = new unsigned char[h];
00494 ytable[2] = new unsigned char[h];
00495
00496 if ( eff == DiagonalGradient || eff == CrossDiagonalGradient)
00497 {
00498 for (x = 0; x < w; x++) {
00499 dir = _xanti ? x : w - 1 - x;
00500 rat = 1 - exp( - (float)x * xbal );
00501
00502 xtable[0][dir] = (unsigned char) ( rDiff/2 * rat );
00503 xtable[1][dir] = (unsigned char) ( gDiff/2 * rat );
00504 xtable[2][dir] = (unsigned char) ( bDiff/2 * rat );
00505 }
00506
00507 for (y = 0; y < h; y++) {
00508 dir = _yanti ? y : h - 1 - y;
00509 rat = 1 - exp( - (float)y * ybal );
00510
00511 ytable[0][dir] = (unsigned char) ( rDiff/2 * rat );
00512 ytable[1][dir] = (unsigned char) ( gDiff/2 * rat );
00513 ytable[2][dir] = (unsigned char) ( bDiff/2 * rat );
00514 }
00515
00516 for (y = 0; y < h; y++) {
00517 unsigned int *scanline = (unsigned int *)image.scanLine(y);
00518 for (x = 0; x < w; x++) {
00519 scanline[x] = qRgb(rcb - (xtable[0][x] + ytable[0][y]),
00520 gcb - (xtable[1][x] + ytable[1][y]),
00521 bcb - (xtable[2][x] + ytable[2][y]));
00522 }
00523 }
00524 }
00525
00526 else if (eff == RectangleGradient ||
00527 eff == PyramidGradient ||
00528 eff == PipeCrossGradient ||
00529 eff == EllipticGradient)
00530 {
00531 int rSign = rDiff>0? 1: -1;
00532 int gSign = gDiff>0? 1: -1;
00533 int bSign = bDiff>0? 1: -1;
00534
00535 for (x = 0; x < w; x++)
00536 {
00537 dir = _xanti ? x : w - 1 - x;
00538 rat = 1 - exp( - (float)x * xbal );
00539
00540 xtable[0][dir] = (unsigned char) abs((int)(rDiff*(0.5-rat)));
00541 xtable[1][dir] = (unsigned char) abs((int)(gDiff*(0.5-rat)));
00542 xtable[2][dir] = (unsigned char) abs((int)(bDiff*(0.5-rat)));
00543 }
00544
00545 for (y = 0; y < h; y++)
00546 {
00547 dir = _yanti ? y : h - 1 - y;
00548
00549 rat = 1 - exp( - (float)y * ybal );
00550
00551 ytable[0][dir] = (unsigned char) abs((int)(rDiff*(0.5-rat)));
00552 ytable[1][dir] = (unsigned char) abs((int)(gDiff*(0.5-rat)));
00553 ytable[2][dir] = (unsigned char) abs((int)(bDiff*(0.5-rat)));
00554 }
00555
00556 for (y = 0; y < h; y++) {
00557 unsigned int *scanline = (unsigned int *)image.scanLine(y);
00558 for (x = 0; x < w; x++) {
00559 if (eff == PyramidGradient)
00560 {
00561 scanline[x] = qRgb(rcb-rSign*(xtable[0][x]+ytable[0][y]),
00562 gcb-gSign*(xtable[1][x]+ytable[1][y]),
00563 bcb-bSign*(xtable[2][x]+ytable[2][y]));
00564 }
00565 else if (eff == RectangleGradient)
00566 {
00567 scanline[x] = qRgb(rcb - rSign *
00568 QMAX(xtable[0][x], ytable[0][y]) * 2,
00569 gcb - gSign *
00570 QMAX(xtable[1][x], ytable[1][y]) * 2,
00571 bcb - bSign *
00572 QMAX(xtable[2][x], ytable[2][y]) * 2);
00573 }
00574 else if (eff == PipeCrossGradient)
00575 {
00576 scanline[x] = qRgb(rcb - rSign *
00577 QMIN(xtable[0][x], ytable[0][y]) * 2,
00578 gcb - gSign *
00579 QMIN(xtable[1][x], ytable[1][y]) * 2,
00580 bcb - bSign *
00581 QMIN(xtable[2][x], ytable[2][y]) * 2);
00582 }
00583 else if (eff == EllipticGradient)
00584 {
00585 scanline[x] = qRgb(rcb - rSign *
00586 (int)sqrt((xtable[0][x]*xtable[0][x] +
00587 ytable[0][y]*ytable[0][y])*2.0),
00588 gcb - gSign *
00589 (int)sqrt((xtable[1][x]*xtable[1][x] +
00590 ytable[1][y]*ytable[1][y])*2.0),
00591 bcb - bSign *
00592 (int)sqrt((xtable[2][x]*xtable[2][x] +
00593 ytable[2][y]*ytable[2][y])*2.0));
00594 }
00595 }
00596 }
00597 }
00598
00599 if (ncols && (QPixmap::defaultDepth() < 15 )) {
00600 if ( ncols < 2 || ncols > 256 )
00601 ncols = 3;
00602 QColor *dPal = new QColor[ncols];
00603 for (int i=0; i<ncols; i++) {
00604 dPal[i].setRgb ( rca + rDiff * i / ( ncols - 1 ),
00605 gca + gDiff * i / ( ncols - 1 ),
00606 bca + bDiff * i / ( ncols - 1 ) );
00607 }
00608 dither(image, dPal, ncols);
00609 delete [] dPal;
00610 }
00611
00612 delete [] xtable[0];
00613 delete [] xtable[1];
00614 delete [] xtable[2];
00615 delete [] ytable[0];
00616 delete [] ytable[1];
00617 delete [] ytable[2];
00618
00619 }
00620
00621 return image;
00622 }
00623
00627 namespace {
00628
00629 struct KIE4Pack
00630 {
00631 Q_UINT16 data[4];
00632 };
00633
00634 struct KIE8Pack
00635 {
00636 Q_UINT16 data[8];
00637 };
00638
00639 }
00640
00641
00642
00643
00644
00645
00646
00647
00648
00649
00650
00651
00652
00653
00654 QImage& KImageEffect::intensity(QImage &image, float percent)
00655 {
00656 if (image.width() == 0 || image.height() == 0) {
00657 #ifndef NDEBUG
00658 std::cerr << "WARNING: KImageEffect::intensity : invalid image\n";
00659 #endif
00660 return image;
00661 }
00662
00663 int segColors = image.depth() > 8 ? 256 : image.numColors();
00664 int pixels = image.depth() > 8 ? image.width()*image.height() :
00665 image.numColors();
00666 unsigned int *data = image.depth() > 8 ? (unsigned int *)image.bits() :
00667 (unsigned int *)image.colorTable();
00668
00669 bool brighten = (percent >= 0);
00670 if(percent < 0)
00671 percent = -percent;
00672
00673 #ifdef USE_MMX_INLINE_ASM
00674 bool haveMMX = KCPUInfo::haveExtension( KCPUInfo::IntelMMX );
00675
00676 if(haveMMX)
00677 {
00678 Q_UINT16 p = Q_UINT16(256.0f*(percent));
00679 KIE4Pack mult = {{p,p,p,0}};
00680
00681 __asm__ __volatile__(
00682 "pxor %%mm7, %%mm7\n\t"
00683 "movq (%0), %%mm6\n\t"
00684 : : "r"(&mult), "m"(mult));
00685
00686 unsigned int rem = pixels % 4;
00687 pixels -= rem;
00688 Q_UINT32 *end = ( data + pixels );
00689
00690 if (brighten)
00691 {
00692 while ( data != end ) {
00693 __asm__ __volatile__(
00694 "movq (%0), %%mm0\n\t"
00695 "movq 8(%0), %%mm4\n\t"
00696 "movq %%mm0, %%mm1\n\t"
00697 "movq %%mm0, %%mm3\n\t"
00698 "movq %%mm4, %%mm5\n\t"
00699 "punpcklbw %%mm7, %%mm0\n\t"
00700 "punpckhbw %%mm7, %%mm1\n\t"
00701 "pmullw %%mm6, %%mm0\n\t"
00702 "punpcklbw %%mm7, %%mm4\n\t"
00703 "pmullw %%mm6, %%mm1\n\t"
00704 "psrlw $8, %%mm0\n\t"
00705 "pmullw %%mm6, %%mm4\n\t"
00706 "psrlw $8, %%mm1\n\t"
00707 "psrlw $8, %%mm4\n\t"
00708 "packuswb %%mm1, %%mm0\n\t"
00709 "movq %%mm5, %%mm1\n\t"
00710
00711 "punpckhbw %%mm7, %%mm1\n\t"
00712
00713 "pmullw %%mm6, %%mm1\n\t"
00714 "paddusb %%mm3, %%mm0\n\t"
00715 "psrlw $8, %%mm1\n\t"
00716 "packuswb %%mm1, %%mm4\n\t"
00717
00718 "movq %%mm0, (%0)\n\t"
00719 "paddusb %%mm5, %%mm4\n\t"
00720 "movq %%mm4, 8(%0)\n\t"
00721 : : "r"(data) );
00722 data += 4;
00723 }
00724
00725 end += rem;
00726 while ( data != end ) {
00727 __asm__ __volatile__(
00728 "movd (%0), %%mm0\n\t"
00729 "punpcklbw %%mm7, %%mm0\n\t"
00730 "movq %%mm0, %%mm3\n\t"
00731 "pmullw %%mm6, %%mm0\n\t"
00732 "psrlw $8, %%mm0\n\t"
00733 "paddw %%mm3, %%mm0\n\t"
00734 "packuswb %%mm0, %%mm0\n\t"
00735 "movd %%mm0, (%0)\n\t"
00736 : : "r"(data) );
00737 data++;
00738 }
00739 }
00740 else
00741 {
00742 while ( data != end ) {
00743 __asm__ __volatile__(
00744 "movq (%0), %%mm0\n\t"
00745 "movq 8(%0), %%mm4\n\t"
00746 "movq %%mm0, %%mm1\n\t"
00747 "movq %%mm0, %%mm3\n\t"
00748
00749 "movq %%mm4, %%mm5\n\t"
00750
00751 "punpcklbw %%mm7, %%mm0\n\t"
00752 "punpckhbw %%mm7, %%mm1\n\t"
00753 "pmullw %%mm6, %%mm0\n\t"
00754 "punpcklbw %%mm7, %%mm4\n\t"
00755 "pmullw %%mm6, %%mm1\n\t"
00756 "psrlw $8, %%mm0\n\t"
00757 "pmullw %%mm6, %%mm4\n\t"
00758 "psrlw $8, %%mm1\n\t"
00759 "psrlw $8, %%mm4\n\t"
00760 "packuswb %%mm1, %%mm0\n\t"
00761 "movq %%mm5, %%mm1\n\t"
00762
00763 "punpckhbw %%mm7, %%mm1\n\t"
00764
00765 "pmullw %%mm6, %%mm1\n\t"
00766 "psubusb %%mm0, %%mm3\n\t"
00767 "psrlw $8, %%mm1\n\t"
00768 "packuswb %%mm1, %%mm4\n\t"
00769
00770 "movq %%mm3, (%0)\n\t"
00771 "psubusb %%mm4, %%mm5\n\t"
00772 "movq %%mm5, 8(%0)\n\t"
00773 : : "r"(data) );
00774 data += 4;
00775 }
00776
00777 end += rem;
00778 while ( data != end ) {
00779 __asm__ __volatile__(
00780 "movd (%0), %%mm0\n\t"
00781 "punpcklbw %%mm7, %%mm0\n\t"
00782 "movq %%mm0, %%mm3\n\t"
00783 "pmullw %%mm6, %%mm0\n\t"
00784 "psrlw $8, %%mm0\n\t"
00785 "psubusw %%mm0, %%mm3\n\t"
00786 "packuswb %%mm3, %%mm3\n\t"
00787 "movd %%mm3, (%0)\n\t"
00788 : : "r"(data) );
00789 data++;
00790 }
00791 }
00792 __asm__ __volatile__("emms");
00793 }
00794 else
00795 #endif // USE_MMX_INLINE_ASM
00796 {
00797 unsigned char *segTbl = new unsigned char[segColors];
00798 int tmp;
00799 if(brighten){
00800 for(int i=0; i < segColors; ++i){
00801 tmp = (int)(i*percent);
00802 if(tmp > 255)
00803 tmp = 255;
00804 segTbl[i] = tmp;
00805 }
00806 }
00807 else{
00808 for(int i=0; i < segColors; ++i){
00809 tmp = (int)(i*percent);
00810 if(tmp < 0)
00811 tmp = 0;
00812 segTbl[i] = tmp;
00813 }
00814 }
00815
00816 if(brighten){
00817 for(int i=0; i < pixels; ++i){
00818 int r = qRed(data[i]);
00819 int g = qGreen(data[i]);
00820 int b = qBlue(data[i]);
00821 int a = qAlpha(data[i]);
00822 r = r + segTbl[r] > 255 ? 255 : r + segTbl[r];
00823 g = g + segTbl[g] > 255 ? 255 : g + segTbl[g];
00824 b = b + segTbl[b] > 255 ? 255 : b + segTbl[b];
00825 data[i] = qRgba(r, g, b,a);
00826 }
00827 }
00828 else{
00829 for(int i=0; i < pixels; ++i){
00830 int r = qRed(data[i]);
00831 int g = qGreen(data[i]);
00832 int b = qBlue(data[i]);
00833 int a = qAlpha(data[i]);
00834 r = r - segTbl[r] < 0 ? 0 : r - segTbl[r];
00835 g = g - segTbl[g] < 0 ? 0 : g - segTbl[g];
00836 b = b - segTbl[b] < 0 ? 0 : b - segTbl[b];
00837 data[i] = qRgba(r, g, b, a);
00838 }
00839 }
00840 delete [] segTbl;
00841 }
00842
00843 return image;
00844 }
00845
00846 QImage& KImageEffect::channelIntensity(QImage &image, float percent,
00847 RGBComponent channel)
00848 {
00849 if (image.width() == 0 || image.height() == 0) {
00850 #ifndef NDEBUG
00851 std::cerr << "WARNING: KImageEffect::channelIntensity : invalid image\n";
00852 #endif
00853 return image;
00854 }
00855
00856 int segColors = image.depth() > 8 ? 256 : image.numColors();
00857 unsigned char *segTbl = new unsigned char[segColors];
00858 int pixels = image.depth() > 8 ? image.width()*image.height() :
00859 image.numColors();
00860 unsigned int *data = image.depth() > 8 ? (unsigned int *)image.bits() :
00861 (unsigned int *)image.colorTable();
00862 bool brighten = (percent >= 0);
00863 if(percent < 0)
00864 percent = -percent;
00865
00866 if(brighten){
00867 for(int i=0; i < segColors; ++i){
00868 int tmp = (int)(i*percent);
00869 if(tmp > 255)
00870 tmp = 255;
00871 segTbl[i] = tmp;
00872 }
00873 }
00874 else{
00875 for(int i=0; i < segColors; ++i){
00876 int tmp = (int)(i*percent);
00877 if(tmp < 0)
00878 tmp = 0;
00879 segTbl[i] = tmp;
00880 }
00881 }
00882
00883 if(brighten){
00884 if(channel == Red){
00885 for(int i=0; i < pixels; ++i){
00886 int c = qRed(data[i]);
00887 c = c + segTbl[c] > 255 ? 255 : c + segTbl[c];
00888 data[i] = qRgba(c, qGreen(data[i]), qBlue(data[i]), qAlpha(data[i]));
00889 }
00890 }
00891 else if(channel == Green){
00892 for(int i=0; i < pixels; ++i){
00893 int c = qGreen(data[i]);
00894 c = c + segTbl[c] > 255 ? 255 : c + segTbl[c];
00895 data[i] = qRgba(qRed(data[i]), c, qBlue(data[i]), qAlpha(data[i]));
00896 }
00897 }
00898 else{
00899 for(int i=0; i < pixels; ++i){
00900 int c = qBlue(data[i]);
00901 c = c + segTbl[c] > 255 ? 255 : c + segTbl[c];
00902 data[i] = qRgba(qRed(data[i]), qGreen(data[i]), c, qAlpha(data[i]));
00903 }
00904 }
00905
00906 }
00907 else{
00908 if(channel == Red){
00909 for(int i=0; i < pixels; ++i){
00910 int c = qRed(data[i]);
00911 c = c - segTbl[c] < 0 ? 0 : c - segTbl[c];
00912 data[i] = qRgba(c, qGreen(data[i]), qBlue(data[i]), qAlpha(data[i]));
00913 }
00914 }
00915 else if(channel == Green){
00916 for(int i=0; i < pixels; ++i){
00917 int c = qGreen(data[i]);
00918 c = c - segTbl[c] < 0 ? 0 : c - segTbl[c];
00919 data[i] = qRgba(qRed(data[i]), c, qBlue(data[i]), qAlpha(data[i]));
00920 }
00921 }
00922 else{
00923 for(int i=0; i < pixels; ++i){
00924 int c = qBlue(data[i]);
00925 c = c - segTbl[c] < 0 ? 0 : c - segTbl[c];
00926 data[i] = qRgba(qRed(data[i]), qGreen(data[i]), c, qAlpha(data[i]));
00927 }
00928 }
00929 }
00930 delete [] segTbl;
00931
00932 return image;
00933 }
00934
00935
00936
00937 QImage& KImageEffect::modulate(QImage &image, QImage &modImage, bool reverse,
00938 ModulationType type, int factor, RGBComponent channel)
00939 {
00940 if (image.width() == 0 || image.height() == 0 ||
00941 modImage.width() == 0 || modImage.height() == 0) {
00942 #ifndef NDEBUG
00943 std::cerr << "WARNING: KImageEffect::modulate : invalid image\n";
00944 #endif
00945 return image;
00946 }
00947
00948 int r, g, b, h, s, v, a;
00949 QColor clr;
00950 int mod=0;
00951 unsigned int x1, x2, y1, y2;
00952 register int x, y;
00953
00954
00955 if (image.depth()<32) image = image.convertDepth(32);
00956
00957
00958 if (modImage.depth()<8) modImage = modImage.convertDepth(8);
00959
00960 unsigned int *colorTable2 = (modImage.depth()==8) ?
00961 modImage.colorTable():0;
00962 unsigned int *data1, *data2;
00963 unsigned char *data2b;
00964 unsigned int color1, color2;
00965
00966 x1 = image.width(); y1 = image.height();
00967 x2 = modImage.width(); y2 = modImage.height();
00968
00969 for (y = 0; y < (int)y1; y++) {
00970 data1 = (unsigned int *) image.scanLine(y);
00971 data2 = (unsigned int *) modImage.scanLine( y%y2 );
00972 data2b = (unsigned char *) modImage.scanLine( y%y2 );
00973
00974 x=0;
00975 while(x < (int)x1) {
00976 color2 = (colorTable2) ? colorTable2[*data2b] : *data2;
00977 if (reverse) {
00978 color1 = color2;
00979 color2 = *data1;
00980 }
00981 else
00982 color1 = *data1;
00983
00984 if (type == Intensity || type == Contrast) {
00985 r = qRed(color1);
00986 g = qGreen(color1);
00987 b = qBlue(color1);
00988 if (channel != All) {
00989 mod = (channel == Red) ? qRed(color2) :
00990 (channel == Green) ? qGreen(color2) :
00991 (channel == Blue) ? qBlue(color2) :
00992 (channel == Gray) ? qGray(color2) : 0;
00993 mod = mod*factor/50;
00994 }
00995
00996 if (type == Intensity) {
00997 if (channel == All) {
00998 r += r * factor/50 * qRed(color2)/256;
00999 g += g * factor/50 * qGreen(color2)/256;
01000 b += b * factor/50 * qBlue(color2)/256;
01001 }
01002 else {
01003 r += r * mod/256;
01004 g += g * mod/256;
01005 b += b * mod/256;
01006 }
01007 }
01008 else {
01009 if (channel == All) {
01010 r += (r-128) * factor/50 * qRed(color2)/128;
01011 g += (g-128) * factor/50 * qGreen(color2)/128;
01012 b += (b-128) * factor/50 * qBlue(color2)/128;
01013 }
01014 else {
01015 r += (r-128) * mod/128;
01016 g += (g-128) * mod/128;
01017 b += (b-128) * mod/128;
01018 }
01019 }
01020
01021 if (r<0) r=0; if (r>255) r=255;
01022 if (g<0) g=0; if (g>255) g=255;
01023 if (b<0) b=0; if (b>255) b=255;
01024 a = qAlpha(*data1);
01025 *data1 = qRgba(r, g, b, a);
01026 }
01027 else if (type == Saturation || type == HueShift) {
01028 clr.setRgb(color1);
01029 clr.hsv(&h, &s, &v);
01030 mod = (channel == Red) ? qRed(color2) :
01031 (channel == Green) ? qGreen(color2) :
01032 (channel == Blue) ? qBlue(color2) :
01033 (channel == Gray) ? qGray(color2) : 0;
01034 mod = mod*factor/50;
01035
01036 if (type == Saturation) {
01037 s -= s * mod/256;
01038 if (s<0) s=0; if (s>255) s=255;
01039 }
01040 else {
01041 h += mod;
01042 while(h<0) h+=360;
01043 h %= 360;
01044 }
01045
01046 clr.setHsv(h, s, v);
01047 a = qAlpha(*data1);
01048 *data1 = clr.rgb() | ((uint)(a & 0xff) << 24);
01049 }
01050 data1++; data2++; data2b++; x++;
01051 if ( (x%x2) ==0) { data2 -= x2; data2b -= x2; }
01052 }
01053 }
01054 return image;
01055 }
01056
01057
01058
01059
01060
01061
01062
01063
01064
01065
01066
01067 QImage& KImageEffect::blend(const QColor& clr, QImage& dst, float opacity)
01068 {
01069 if (dst.width() <= 0 || dst.height() <= 0)
01070 return dst;
01071
01072 if (opacity < 0.0 || opacity > 1.0) {
01073 #ifndef NDEBUG
01074 std::cerr << "WARNING: KImageEffect::blend : invalid opacity. Range [0, 1]\n";
01075 #endif
01076 return dst;
01077 }
01078
01079 if (dst.depth() != 32)
01080 dst = dst.convertDepth(32);
01081
01082 int pixels = dst.width() * dst.height();
01083
01084 #ifdef USE_SSE2_INLINE_ASM
01085 if ( KCPUInfo::haveExtension( KCPUInfo::IntelSSE2 ) && pixels > 16 ) {
01086 Q_UINT16 alpha = Q_UINT16( ( 1.0 - opacity ) * 256.0 );
01087
01088 KIE8Pack packedalpha = { { alpha, alpha, alpha, 256,
01089 alpha, alpha, alpha, 256 } };
01090
01091 Q_UINT16 red = Q_UINT16( clr.red() * 256 * opacity );
01092 Q_UINT16 green = Q_UINT16( clr.green() * 256 * opacity );
01093 Q_UINT16 blue = Q_UINT16( clr.blue() * 256 * opacity );
01094
01095 KIE8Pack packedcolor = { { blue, green, red, 0,
01096 blue, green, red, 0 } };
01097
01098
01099 __asm__ __volatile__(
01100 "pxor %%xmm7, %%xmm7\n\t"
01101 "movdqu (%0), %%xmm6\n\t"
01102 "movdqu (%1), %%xmm5\n\t"
01103 : : "r"(&packedalpha), "r"(&packedcolor),
01104 "m"(packedcolor), "m"(packedalpha) );
01105
01106 Q_UINT32 *data = reinterpret_cast<Q_UINT32*>( dst.bits() );
01107
01108
01109 int offset = (16 - (Q_UINT32( data ) & 0x0f)) / 4;
01110
01111
01112 int remainder = (pixels - offset) % 8;
01113 pixels -= remainder;
01114
01115
01116 for ( int i = 0; i < offset; i++ ) {
01117 __asm__ __volatile__(
01118 "movd (%0,%1,4), %%xmm0\n\t"
01119 "punpcklbw %%xmm7, %%xmm0\n\t"
01120 "pmullw %%xmm6, %%xmm0\n\t"
01121 "paddw %%xmm5, %%xmm0\n\t"
01122 "psrlw $8, %%xmm0\n\t"
01123 "packuswb %%xmm1, %%xmm0\n\t"
01124 "movd %%xmm0, (%0,%1,4)\n\t"
01125 : : "r"(data), "r"(i) );
01126 }
01127
01128
01129 for ( int i = offset; i < pixels; i += 8 ) {
01130 __asm__ __volatile(
01131
01132 "movq (%0,%1,4), %%xmm0\n\t"
01133 "movq 8(%0,%1,4), %%xmm1\n\t"
01134 "movq 16(%0,%1,4), %%xmm2\n\t"
01135 "movq 24(%0,%1,4), %%xmm3\n\t"
01136
01137
01138 "prefetchnta 32(%0,%1,4) \n\t"
01139
01140
01141 "punpcklbw %%xmm7, %%xmm0\n\t"
01142 "pmullw %%xmm6, %%xmm0\n\t"
01143 "paddw %%xmm5, %%xmm0\n\t"
01144 "psrlw $8, %%xmm0\n\t"
01145
01146
01147 "punpcklbw %%xmm7, %%xmm1\n\t"
01148 "pmullw %%xmm6, %%xmm1\n\t"
01149 "paddw %%xmm5, %%xmm1\n\t"
01150 "psrlw $8, %%xmm1\n\t"
01151
01152
01153 "punpcklbw %%xmm7, %%xmm2\n\t"
01154 "pmullw %%xmm6, %%xmm2\n\t"
01155 "paddw %%xmm5, %%xmm2\n\t"
01156 "psrlw $8, %%xmm2\n\t"
01157
01158
01159 "punpcklbw %%xmm7, %%xmm3\n\t"
01160 "pmullw %%xmm6, %%xmm3\n\t"
01161 "paddw %%xmm5, %%xmm3\n\t"
01162 "psrlw $8, %%xmm3\n\t"
01163
01164
01165 "packuswb %%xmm1, %%xmm0\n\t"
01166 "packuswb %%xmm3, %%xmm2\n\t"
01167
01168
01169 "movdqa %%xmm0, (%0,%1,4)\n\t"
01170 "movdqa %%xmm2, 16(%0,%1,4)\n\t"
01171 : : "r"(data), "r"(i) );
01172 }
01173
01174
01175 for ( int i = pixels; i < pixels + remainder; i++ ) {
01176 __asm__ __volatile__(
01177 "movd (%0,%1,4), %%xmm0\n\t"
01178 "punpcklbw %%xmm7, %%xmm0\n\t"
01179 "pmullw %%xmm6, %%xmm0\n\t"
01180 "paddw %%xmm5, %%xmm0\n\t"
01181 "psrlw $8, %%xmm0\n\t"
01182 "packuswb %%xmm1, %%xmm0\n\t"
01183 "movd %%xmm0, (%0,%1,4)\n\t"
01184 : : "r"(data), "r"(i) );
01185 }
01186 } else
01187 #endif
01188
01189 #ifdef USE_MMX_INLINE_ASM
01190 if ( KCPUInfo::haveExtension( KCPUInfo::IntelMMX ) && pixels > 1 ) {
01191 Q_UINT16 alpha = Q_UINT16( ( 1.0 - opacity ) * 256.0 );
01192 KIE4Pack packedalpha = { { alpha, alpha, alpha, 256 } };
01193
01194 Q_UINT16 red = Q_UINT16( clr.red() * 256 * opacity );
01195 Q_UINT16 green = Q_UINT16( clr.green() * 256 * opacity );
01196 Q_UINT16 blue = Q_UINT16( clr.blue() * 256 * opacity );
01197
01198 KIE4Pack packedcolor = { { blue, green, red, 0 } };
01199
01200 __asm__ __volatile__(
01201 "pxor %%mm7, %%mm7\n\t"
01202 "movq (%0), %%mm6\n\t"
01203 "movq (%1), %%mm5\n\t"
01204 : : "r"(&packedalpha), "r"(&packedcolor), "m"(packedcolor), "m"(packedalpha) );
01205
01206 Q_UINT32 *data = reinterpret_cast<Q_UINT32*>( dst.bits() );
01207
01208
01209 int remainder = pixels % 4;
01210 pixels -= remainder;
01211
01212
01213 for ( int i = 0; i < pixels; i += 4 ) {
01214 __asm__ __volatile__(
01215
01216 "movd (%0,%1,4), %%mm0\n\t"
01217 "movd 4(%0,%1,4), %%mm1\n\t"
01218 "movd 8(%0,%1,4), %%mm2\n\t"
01219 "movd 12(%0,%1,4), %%mm3\n\t"
01220
01221
01222 "punpcklbw %%mm7, %%mm0\n\t"
01223 "pmullw %%mm6, %%mm0\n\t"
01224 "paddw %%mm5, %%mm0\n\t"
01225 "psrlw $8, %%mm0\n\t"
01226
01227
01228 "punpcklbw %%mm7, %%mm1\n\t"
01229 "pmullw %%mm6, %%mm1\n\t"
01230 "paddw %%mm5, %%mm1\n\t"
01231 "psrlw $8, %%mm1\n\t"
01232
01233
01234 "punpcklbw %%mm7, %%mm2\n\t"
01235 "pmullw %%mm6, %%mm2\n\t"
01236 "paddw %%mm5, %%mm2\n\t"
01237 "psrlw $8, %%mm2\n\t"
01238
01239
01240 "punpcklbw %%mm7, %%mm3\n\t"
01241 "pmullw %%mm6, %%mm3\n\t"
01242 "paddw %%mm5, %%mm3\n\t"
01243 "psrlw $8, %%mm3\n\t"
01244
01245
01246 "packuswb %%mm1, %%mm0\n\t"
01247 "packuswb %%mm3, %%mm2\n\t"
01248
01249
01250 "movq %%mm0, (%0,%1,4)\n\t"
01251 "movq %%mm2, 8(%0,%1,4)\n\t"
01252 : : "r"(data), "r"(i) );
01253 }
01254
01255
01256 for ( int i = pixels; i < pixels + remainder; i++ ) {
01257 __asm__ __volatile__(
01258 "movd (%0,%1,4), %%mm0\n\t"
01259 "punpcklbw %%mm7, %%mm0\n\t"
01260 "pmullw %%mm6, %%mm0\n\t"
01261 "paddw %%mm5, %%mm0\n\t"
01262 "psrlw $8, %%mm0\n\t"
01263 "packuswb %%mm0, %%mm0\n\t"
01264 "movd %%mm0, (%0,%1,4)\n\t"
01265 : : "r"(data), "r"(i) );
01266 }
01267
01268
01269 __asm__ __volatile__("emms");
01270 } else
01271 #endif // USE_MMX_INLINE_ASM
01272
01273 {
01274 int rcol, gcol, bcol;
01275 clr.rgb(&rcol, &gcol, &bcol);
01276
01277 #ifdef WORDS_BIGENDIAN // ARGB (skip alpha)
01278 register unsigned char *data = (unsigned char *)dst.bits() + 1;
01279 #else // BGRA
01280 register unsigned char *data = (unsigned char *)dst.bits();
01281 #endif
01282
01283 for (register int i=0; i<pixels; i++)
01284 {
01285 #ifdef WORDS_BIGENDIAN
01286 *data += (unsigned char)((rcol - *data) * opacity);
01287 data++;
01288 *data += (unsigned char)((gcol - *data) * opacity);
01289 data++;
01290 *data += (unsigned char)((bcol - *data) * opacity);
01291 data++;
01292 #else
01293 *data += (unsigned char)((bcol - *data) * opacity);
01294 data++;
01295 *data += (unsigned char)((gcol - *data) * opacity);
01296 data++;
01297 *data += (unsigned char)((rcol - *data) * opacity);
01298 data++;
01299 #endif
01300 data++;
01301 }
01302 }
01303
01304 return dst;
01305 }
01306
01307
01308 QImage& KImageEffect::blend(QImage& src, QImage& dst, float opacity)
01309 {
01310 if (src.width() <= 0 || src.height() <= 0)
01311 return dst;
01312 if (dst.width() <= 0 || dst.height() <= 0)
01313 return dst;
01314
01315 if (src.width() != dst.width() || src.height() != dst.height()) {
01316 #ifndef NDEBUG
01317 std::cerr << "WARNING: KImageEffect::blend : src and destination images are not the same size\n";
01318 #endif
01319 return dst;
01320 }
01321
01322 if (opacity < 0.0 || opacity > 1.0) {
01323 #ifndef NDEBUG
01324 std::cerr << "WARNING: KImageEffect::blend : invalid opacity. Range [0, 1]\n";
01325 #endif
01326 return dst;
01327 }
01328
01329 if (src.depth() != 32) src = src.convertDepth(32);
01330 if (dst.depth() != 32) dst = dst.convertDepth(32);
01331
01332 int pixels = src.width() * src.height();
01333
01334 #ifdef USE_SSE2_INLINE_ASM
01335 if ( KCPUInfo::haveExtension( KCPUInfo::IntelSSE2 ) && pixels > 16 ) {
01336 Q_UINT16 alpha = Q_UINT16( opacity * 256.0 );
01337 KIE8Pack packedalpha = { { alpha, alpha, alpha, 0,
01338 alpha, alpha, alpha, 0 } };
01339
01340
01341 __asm__ __volatile__(
01342 "pxor %%xmm7, %%xmm7\n\t"
01343 "movdqu (%0), %%xmm6\n\t"
01344 : : "r"(&packedalpha), "m"(packedalpha) );
01345
01346 Q_UINT32 *data1 = reinterpret_cast<Q_UINT32*>( src.bits() );
01347 Q_UINT32 *data2 = reinterpret_cast<Q_UINT32*>( dst.bits() );
01348
01349
01350 int offset = (16 - (Q_UINT32( data2 ) & 0x0f)) / 4;
01351
01352
01353 int remainder = (pixels - offset) % 4;
01354 pixels -= remainder;
01355
01356
01357 for ( int i = 0; i < offset; i++ ) {
01358 __asm__ __volatile__(
01359 "movd (%1,%2,4), %%xmm1\n\t"
01360 "punpcklbw %%xmm7, %%xmm1\n\t"
01361 "movd (%0,%2,4), %%xmm0\n\t"
01362 "punpcklbw %%xmm7, %%xmm0\n\t"
01363 "psubw %%xmm1, %%xmm0\n\t"
01364 "pmullw %%xmm6, %%xmm0\n\t"
01365 "psllw $8, %%xmm1\n\t"
01366 "paddw %%xmm1, %%xmm0\n\t"
01367 "psrlw $8, %%xmm0\n\t"
01368 "packuswb %%xmm1, %%xmm0\n\t"
01369 "movd %%xmm0, (%1,%2,4)\n\t"
01370 : : "r"(data1), "r"(data2), "r"(i) );
01371 }
01372
01373
01374 for ( int i = offset; i < pixels; i += 4 ) {
01375 __asm__ __volatile__(
01376
01377 "movq (%0,%2,4), %%xmm0\n\t"
01378 "movq (%1,%2,4), %%xmm1\n\t"
01379 "movq 8(%0,%2,4), %%xmm2\n\t"
01380 "movq 8(%1,%2,4), %%xmm3\n\t"
01381
01382
01383 "prefetchnta 32(%0,%2,4) \n\t"
01384 "prefetchnta 32(%1,%2,4) \n\t"
01385
01386
01387 "punpcklbw %%xmm7, %%xmm1\n\t"
01388 "punpcklbw %%xmm7, %%xmm0\n\t"
01389 "psubw %%xmm1, %%xmm0\n\t"
01390 "pmullw %%xmm6, %%xmm0\n\t"
01391 "psllw $8, %%xmm1\n\t"
01392 "paddw %%xmm1, %%xmm0\n\t"
01393 "psrlw $8, %%xmm0\n\t"
01394
01395
01396 "punpcklbw %%xmm7, %%xmm3\n\t"
01397 "punpcklbw %%xmm7, %%xmm2\n\t"
01398 "psubw %%xmm3, %%xmm2\n\t"
01399 "pmullw %%xmm6, %%xmm2\n\t"
01400 "psllw $8, %%xmm3\n\t"
01401 "paddw %%xmm3, %%xmm2\n\t"
01402 "psrlw $8, %%xmm2\n\t"
01403
01404
01405 "packuswb %%xmm2, %%xmm0\n\t"
01406 "movdqa %%xmm0, (%1,%2,4)\n\t"
01407 : : "r"(data1), "r"(data2), "r"(i) );
01408 }
01409
01410
01411 for ( int i = pixels; i < pixels + remainder; i++ ) {
01412 __asm__ __volatile__(
01413 "movd (%1,%2,4), %%xmm1\n\t"
01414 "punpcklbw %%xmm7, %%xmm1\n\t"
01415 "movd (%0,%2,4), %%xmm0\n\t"
01416 "punpcklbw %%xmm7, %%xmm0\n\t"
01417 "psubw %%xmm1, %%xmm0\n\t"
01418 "pmullw %%xmm6, %%xmm0\n\t"
01419 "psllw $8, %%xmm1\n\t"
01420 "paddw %%xmm1, %%xmm0\n\t"
01421 "psrlw $8, %%xmm0\n\t"
01422 "packuswb %%xmm1, %%xmm0\n\t"
01423 "movd %%xmm0, (%1,%2,4)\n\t"
01424 : : "r"(data1), "r"(data2), "r"(i) );
01425 }
01426 } else
01427 #endif // USE_SSE2_INLINE_ASM
01428
01429 #ifdef USE_MMX_INLINE_ASM
01430 if ( KCPUInfo::haveExtension( KCPUInfo::IntelMMX ) && pixels > 1 ) {
01431 Q_UINT16 alpha = Q_UINT16( opacity * 256.0 );
01432 KIE4Pack packedalpha = { { alpha, alpha, alpha, 0 } };
01433
01434
01435 __asm__ __volatile__(
01436 "pxor %%mm7, %%mm7\n\t"
01437 "movq (%0), %%mm6\n\t"
01438 : : "r"(&packedalpha), "m"(packedalpha) );
01439
01440 Q_UINT32 *data1 = reinterpret_cast<Q_UINT32*>( src.bits() );
01441 Q_UINT32 *data2 = reinterpret_cast<Q_UINT32*>( dst.bits() );
01442
01443
01444 int remainder = pixels % 2;
01445 pixels -= remainder;
01446
01447
01448 for ( int i = 0; i < pixels; i += 2 ) {
01449 __asm__ __volatile__(
01450
01451 "movd (%0,%2,4), %%mm0\n\t"
01452 "movd (%1,%2,4), %%mm1\n\t"
01453 "movd 4(%0,%2,4), %%mm2\n\t"
01454 "movd 4(%1,%2,4), %%mm3\n\t"
01455
01456
01457 "punpcklbw %%mm7, %%mm0\n\t"
01458 "punpcklbw %%mm7, %%mm1\n\t"
01459 "psubw %%mm1, %%mm0\n\t"
01460 "pmullw %%mm6, %%mm0\n\t"
01461 "psllw $8, %%mm1\n\t"
01462 "paddw %%mm1, %%mm0\n\t"
01463 "psrlw $8, %%mm0\n\t"
01464
01465
01466 "punpcklbw %%mm7, %%mm2\n\t"
01467 "punpcklbw %%mm7, %%mm3\n\t"
01468 "psubw %%mm3, %%mm2\n\t"
01469 "pmullw %%mm6, %%mm2\n\t"
01470 "psllw $8, %%mm3\n\t"
01471 "paddw %%mm3, %%mm2\n\t"
01472 "psrlw $8, %%mm2\n\t"
01473
01474
01475 "packuswb %%mm2, %%mm0\n\t"
01476 "movq %%mm0, (%1,%2,4)\n\t"
01477 : : "r"(data1), "r"(data2), "r"(i) );
01478 }
01479
01480
01481 if ( remainder ) {
01482 __asm__ __volatile__(
01483 "movd (%0), %%mm0\n\t"
01484 "punpcklbw %%mm7, %%mm0\n\t"
01485 "movd (%1), %%mm1\n\t"
01486 "punpcklbw %%mm7, %%mm1\n\t"
01487 "psubw %%mm1, %%mm0\n\t"
01488 "pmullw %%mm6, %%mm0\n\t"
01489 "psllw $8, %%mm1\n\t"
01490 "paddw %%mm1, %%mm0\n\t"
01491 "psrlw $8, %%mm0\n\t"
01492 "packuswb %%mm0, %%mm0\n\t"
01493 "movd %%mm0, (%1)\n\t"
01494 : : "r"(data1 + pixels), "r"(data2 + pixels) );
01495 }
01496
01497
01498 __asm__ __volatile__("emms");
01499 } else
01500 #endif // USE_MMX_INLINE_ASM
01501
01502 {
01503 #ifdef WORDS_BIGENDIAN // ARGB (skip alpha)
01504 register unsigned char *data1 = (unsigned char *)dst.bits() + 1;
01505 register unsigned char *data2 = (unsigned char *)src.bits() + 1;
01506 #else // BGRA
01507 register unsigned char *data1 = (unsigned char *)dst.bits();
01508 register unsigned char *data2 = (unsigned char *)src.bits();
01509 #endif
01510
01511 for (register int i=0; i<pixels; i++)
01512 {
01513 #ifdef WORDS_BIGENDIAN
01514 *data1 += (unsigned char)((*(data2++) - *data1) * opacity);
01515 data1++;
01516 *data1 += (unsigned char)((*(data2++) - *data1) * opacity);
01517 data1++;
01518 *data1 += (unsigned char)((*(data2++) - *data1) * opacity);
01519 data1++;
01520 #else
01521 *data1 += (unsigned char)((*(data2++) - *data1) * opacity);
01522 data1++;
01523 *data1 += (unsigned char)((*(data2++) - *data1) * opacity);
01524 data1++;
01525 *data1 += (unsigned char)((*(data2++) - *data1) * opacity);
01526 data1++;
01527 #endif
01528 data1++;
01529 data2++;
01530 }
01531 }
01532
01533 return dst;
01534 }
01535
01536
01537 QImage& KImageEffect::blend(QImage &image, float initial_intensity,
01538 const QColor &bgnd, GradientType eff,
01539 bool anti_dir)
01540 {
01541 if (image.width() == 0 || image.height() == 0 || image.depth()!=32 ) {
01542 #ifndef NDEBUG
01543 std::cerr << "WARNING: KImageEffect::blend : invalid image\n";
01544 #endif
01545 return image;
01546 }
01547
01548 int r_bgnd = bgnd.red(), g_bgnd = bgnd.green(), b_bgnd = bgnd.blue();
01549 int r, g, b;
01550 int ind;
01551
01552 unsigned int xi, xf, yi, yf;
01553 unsigned int a;
01554
01555
01556 float unaffected = 1;
01557 if (initial_intensity > 1) initial_intensity = 1;
01558 if (initial_intensity < -1) initial_intensity = -1;
01559 if (initial_intensity < 0) {
01560 unaffected = 1. + initial_intensity;
01561 initial_intensity = 0;
01562 }
01563
01564
01565 float intensity = initial_intensity;
01566 float var = 1. - initial_intensity;
01567
01568 if (anti_dir) {
01569 initial_intensity = intensity = 1.;
01570 var = -var;
01571 }
01572
01573 register int x, y;
01574
01575 unsigned int *data = (unsigned int *)image.bits();
01576
01577 int image_width = image.width();
01578 int image_height = image.height();
01579
01580
01581 if( eff == VerticalGradient || eff == HorizontalGradient ) {
01582
01583
01584 xi = 0, xf = image_width;
01585 yi = 0, yf = image_height;
01586 if (eff == VerticalGradient) {
01587 if (anti_dir) yf = (int)(image_height * unaffected);
01588 else yi = (int)(image_height * (1 - unaffected));
01589 }
01590 else {
01591 if (anti_dir) xf = (int)(image_width * unaffected);
01592 else xi = (int)(image_height * (1 - unaffected));
01593 }
01594
01595 var /= (eff == VerticalGradient?yf-yi:xf-xi);
01596
01597 int ind_base;
01598 for (y = yi; y < (int)yf; y++) {
01599 intensity = eff == VerticalGradient? intensity + var :
01600 initial_intensity;
01601 ind_base = image_width * y ;
01602 for (x = xi; x < (int)xf ; x++) {
01603 if (eff == HorizontalGradient) intensity += var;
01604 ind = x + ind_base;
01605 r = qRed (data[ind]) + (int)(intensity *
01606 (r_bgnd - qRed (data[ind])));
01607 g = qGreen(data[ind]) + (int)(intensity *
01608 (g_bgnd - qGreen(data[ind])));
01609 b = qBlue (data[ind]) + (int)(intensity *
01610 (b_bgnd - qBlue (data[ind])));
01611 if (r > 255) r = 255; if (r < 0 ) r = 0;
01612 if (g > 255) g = 255; if (g < 0 ) g = 0;
01613 if (b > 255) b = 255; if (b < 0 ) b = 0;
01614 a = qAlpha(data[ind]);
01615 data[ind] = qRgba(r, g, b, a);
01616 }
01617 }
01618 }
01619 else if (eff == DiagonalGradient || eff == CrossDiagonalGradient) {
01620 float xvar = var / 2 / image_width;
01621 float yvar = var / 2 / image_height;
01622 float tmp;
01623
01624 for (x = 0; x < image_width ; x++) {
01625 tmp = xvar * (eff == DiagonalGradient? x : image.width()-x-1);
01626 ind = x;
01627 for (y = 0; y < image_height ; y++) {
01628 intensity = initial_intensity + tmp + yvar * y;
01629
01630 r = qRed (data[ind]) + (int)(intensity *
01631 (r_bgnd - qRed (data[ind])));
01632 g = qGreen(data[ind]) + (int)(intensity *
01633 (g_bgnd - qGreen(data[ind])));
01634 b = qBlue (data[ind]) + (int)(intensity *
01635 (b_bgnd - qBlue (data[ind])));
01636 if (r > 255) r = 255; if (r < 0 ) r = 0;
01637 if (g > 255) g = 255; if (g < 0 ) g = 0;
01638 if (b > 255) b = 255; if (b < 0 ) b = 0;
01639 a = qAlpha(data[ind]);
01640 data[ind] = qRgba(r, g, b, a);
01641
01642 ind += image_width;
01643 }
01644 }
01645 }
01646
01647 else if (eff == RectangleGradient || eff == EllipticGradient) {
01648 float xvar;
01649 float yvar;
01650
01651 for (x = 0; x < image_width / 2 + image_width % 2; x++) {
01652 xvar = var / image_width * (image_width - x*2/unaffected-1);
01653 for (y = 0; y < image_height / 2 + image_height % 2; y++) {
01654 yvar = var / image_height * (image_height - y*2/unaffected -1);
01655
01656 if (eff == RectangleGradient)
01657 intensity = initial_intensity + QMAX(xvar, yvar);
01658 else
01659 intensity = initial_intensity + sqrt(xvar * xvar + yvar * yvar);
01660 if (intensity > 1) intensity = 1;
01661 if (intensity < 0) intensity = 0;
01662
01663
01664 ind = x + image_width * y ;
01665 r = qRed (data[ind]) + (int)(intensity *
01666 (r_bgnd - qRed (data[ind])));
01667 g = qGreen(data[ind]) + (int)(intensity *
01668 (g_bgnd - qGreen(data[ind])));
01669 b = qBlue (data[ind]) + (int)(intensity *
01670 (b_bgnd - qBlue (data[ind])));
01671 if (r > 255) r = 255; if (r < 0 ) r = 0;
01672 if (g > 255) g = 255; if (g < 0 ) g = 0;
01673 if (b > 255) b = 255; if (b < 0 ) b = 0;
01674 a = qAlpha(data[ind]);
01675 data[ind] = qRgba(r, g, b, a);
01676
01677
01678 ind = image_width - x - 1 + image_width * y ;
01679 r = qRed (data[ind]) + (int)(intensity *
01680 (r_bgnd - qRed (data[ind])));
01681 g = qGreen(data[ind]) + (int)(intensity *
01682 (g_bgnd - qGreen(data[ind])));
01683 b = qBlue (data[ind]) + (int)(intensity *
01684 (b_bgnd - qBlue (data[ind])));
01685 if (r > 255) r = 255; if (r < 0 ) r = 0;
01686 if (g > 255) g = 255; if (g < 0 ) g = 0;
01687 if (b > 255) b = 255; if (b < 0 ) b = 0;
01688 a = qAlpha(data[ind]);
01689 data[ind] = qRgba(r, g, b, a);
01690 }
01691 }
01692
01693
01694
01695 for (x = 0; x < image_width / 2; x++) {
01696 xvar = var / image_width * (image_width - x*2/unaffected-1);
01697 for (y = 0; y < image_height / 2; y++) {
01698 yvar = var / image_height * (image_height - y*2/unaffected -1);
01699
01700 if (eff == RectangleGradient)
01701 intensity = initial_intensity + QMAX(xvar, yvar);
01702 else
01703 intensity = initial_intensity + sqrt(xvar * xvar + yvar * yvar);
01704 if (intensity > 1) intensity = 1;
01705 if (intensity < 0) intensity = 0;
01706
01707
01708 ind = x + image_width * (image_height - y -1) ;
01709 r = qRed (data[ind]) + (int)(intensity *
01710 (r_bgnd - qRed (data[ind])));
01711 g = qGreen(data[ind]) + (int)(intensity *
01712 (g_bgnd - qGreen(data[ind])));
01713 b = qBlue (data[ind]) + (int)(intensity *
01714 (b_bgnd - qBlue (data[ind])));
01715 if (r > 255) r = 255; if (r < 0 ) r = 0;
01716 if (g > 255) g = 255; if (g < 0 ) g = 0;
01717 if (b > 255) b = 255; if (b < 0 ) b = 0;
01718 a = qAlpha(data[ind]);
01719 data[ind] = qRgba(r, g, b, a);
01720
01721
01722 ind = image_width-x-1 + image_width * (image_height - y - 1) ;
01723 r = qRed (data[ind]) + (int)(intensity *
01724 (r_bgnd - qRed (data[ind])));
01725 g = qGreen(data[ind]) + (int)(intensity *
01726 (g_bgnd - qGreen(data[ind])));
01727 b = qBlue (data[ind]) + (int)(intensity *
01728 (b_bgnd - qBlue (data[ind])));
01729 if (r > 255) r = 255; if (r < 0 ) r = 0;
01730 if (g > 255) g = 255; if (g < 0 ) g = 0;
01731 if (b > 255) b = 255; if (b < 0 ) b = 0;
01732 a = qAlpha(data[ind]);
01733 data[ind] = qRgba(r, g, b, a);
01734 }
01735 }
01736 }
01737 #ifndef NDEBUG
01738 else std::cerr << "KImageEffect::blend effect not implemented" << std::endl;
01739 #endif
01740 return image;
01741 }
01742
01743
01744
01745 QImage& KImageEffect::blend(QImage &image1, QImage &image2,
01746 GradientType gt, int xf, int yf)
01747 {
01748 if (image1.width() == 0 || image1.height() == 0 ||
01749 image2.width() == 0 || image2.height() == 0)
01750 return image1;
01751
01752 QImage image3;
01753
01754 image3 = KImageEffect::unbalancedGradient(image1.size(),
01755 QColor(0,0,0), QColor(255,255,255),
01756 gt, xf, yf, 0);
01757
01758 return blend(image1,image2,image3, Red);
01759 }
01760
01761
01762
01763 QImage& KImageEffect::blend(QImage &image1, QImage &image2,
01764 QImage &blendImage, RGBComponent channel)
01765 {
01766 if (image1.width() == 0 || image1.height() == 0 ||
01767 image2.width() == 0 || image2.height() == 0 ||
01768 blendImage.width() == 0 || blendImage.height() == 0) {
01769 #ifndef NDEBUG
01770 std::cerr << "KImageEffect::blend effect invalid image" << std::endl;
01771 #endif
01772 return image1;
01773 }
01774
01775 int r, g, b;
01776 int ind1, ind2, ind3;
01777
01778 unsigned int x1, x2, x3, y1, y2, y3;
01779 unsigned int a;
01780
01781 register int x, y;
01782
01783
01784 if (image1.depth()<32) image1 = image1.convertDepth(32);
01785 if (image2.depth()<32) image2 = image2.convertDepth(32);
01786
01787
01788 if (blendImage.depth()<8) blendImage = blendImage.convertDepth(8);
01789
01790 unsigned int *colorTable3 = (blendImage.depth()==8) ?
01791 blendImage.colorTable():0;
01792
01793 unsigned int *data1 = (unsigned int *)image1.bits();
01794 unsigned int *data2 = (unsigned int *)image2.bits();
01795 unsigned int *data3 = (unsigned int *)blendImage.bits();
01796 unsigned char *data3b = (unsigned char *)blendImage.bits();
01797 unsigned int color3;
01798
01799 x1 = image1.width(); y1 = image1.height();
01800 x2 = image2.width(); y2 = image2.height();
01801 x3 = blendImage.width(); y3 = blendImage.height();
01802
01803 for (y = 0; y < (int)y1; y++) {
01804 ind1 = x1*y;
01805 ind2 = x2*(y%y2);
01806 ind3 = x3*(y%y3);
01807
01808 x=0;
01809 while(x < (int)x1) {
01810 color3 = (colorTable3) ? colorTable3[data3b[ind3]] : data3[ind3];
01811
01812 a = (channel == Red) ? qRed(color3) :
01813 (channel == Green) ? qGreen(color3) :
01814 (channel == Blue) ? qBlue(color3) : qGray(color3);
01815
01816 r = (a*qRed(data1[ind1]) + (256-a)*qRed(data2[ind2]))/256;
01817 g = (a*qGreen(data1[ind1]) + (256-a)*qGreen(data2[ind2]))/256;
01818 b = (a*qBlue(data1[ind1]) + (256-a)*qBlue(data2[ind2]))/256;
01819
01820 a = qAlpha(data1[ind1]);
01821 data1[ind1] = qRgba(r, g, b, a);
01822
01823 ind1++; ind2++; ind3++; x++;
01824 if ( (x%x2) ==0) ind2 -= x2;
01825 if ( (x%x3) ==0) ind3 -= x3;
01826 }
01827 }
01828 return image1;
01829 }
01830
01831
01832
01833
01834
01835
01836
01837
01838 unsigned int KImageEffect::lHash(unsigned int c)
01839 {
01840 unsigned char r = qRed(c), g = qGreen(c), b = qBlue(c), a = qAlpha(c);
01841 unsigned char nr, ng, nb;
01842 nr =(r >> 1) + (r >> 2); nr = nr > r ? 0 : nr;
01843 ng =(g >> 1) + (g >> 2); ng = ng > g ? 0 : ng;
01844 nb =(b >> 1) + (b >> 2); nb = nb > b ? 0 : nb;
01845
01846 return qRgba(nr, ng, nb, a);
01847 }
01848
01849
01850
01851
01852 unsigned int KImageEffect::uHash(unsigned int c)
01853 {
01854 unsigned char r = qRed(c), g = qGreen(c), b = qBlue(c), a = qAlpha(c);
01855 unsigned char nr, ng, nb;
01856 nr = r + (r >> 3); nr = nr < r ? ~0 : nr;
01857 ng = g + (g >> 3); ng = ng < g ? ~0 : ng;
01858 nb = b + (b >> 3); nb = nb < b ? ~0 : nb;
01859
01860 return qRgba(nr, ng, nb, a);
01861 }
01862
01863
01864
01865
01866 QImage& KImageEffect::hash(QImage &image, Lighting lite, unsigned int spacing)
01867 {
01868 if (image.width() == 0 || image.height() == 0) {
01869 #ifndef NDEBUG
01870 std::cerr << "KImageEffect::hash effect invalid image" << std::endl;
01871 #endif
01872 return image;
01873 }
01874
01875 register int x, y;
01876 unsigned int *data = (unsigned int *)image.bits();
01877 unsigned int ind;
01878
01879
01880 if ((lite == NorthLite ||
01881 lite == SouthLite)&&
01882 (unsigned)image.height() < 2+spacing) return image;
01883 if ((lite == EastLite ||
01884 lite == WestLite)&&
01885 (unsigned)image.height() < 2+spacing) return image;
01886
01887 if (lite == NorthLite || lite == SouthLite) {
01888 for (y = 0 ; y < image.height(); y = y + 2 + spacing) {
01889 for (x = 0; x < image.width(); x++) {
01890 ind = x + image.width() * y;
01891 data[ind] = lite==NorthLite?uHash(data[ind]):lHash(data[ind]);
01892
01893 ind = ind + image.width();
01894 data[ind] = lite==NorthLite?lHash(data[ind]):uHash(data[ind]);
01895 }
01896 }
01897 }
01898
01899 else if (lite == EastLite || lite == WestLite) {
01900 for (y = 0 ; y < image.height(); y++) {
01901 for (x = 0; x < image.width(); x = x + 2 + spacing) {
01902 ind = x + image.width() * y;
01903 data[ind] = lite==EastLite?uHash(data[ind]):lHash(data[ind]);
01904
01905 ind++;
01906 data[ind] = lite==EastLite?lHash(data[ind]):uHash(data[ind]);
01907 }
01908 }
01909 }
01910
01911 else if (lite == NWLite || lite == SELite) {
01912 for (y = 0 ; y < image.height(); y++) {
01913 for (x = 0;
01914 x < (int)(image.width() - ((y & 1)? 1 : 0) * spacing);
01915 x = x + 2 + spacing) {
01916 ind = x + image.width() * y + ((y & 1)? 1 : 0);
01917 data[ind] = lite==NWLite?uHash(data[ind]):lHash(data[ind]);
01918
01919 ind++;
01920 data[ind] = lite==NWLite?lHash(data[ind]):uHash(data[ind]);
01921 }
01922 }
01923 }
01924
01925 else if (lite == SWLite || lite == NELite) {
01926 for (y = 0 ; y < image.height(); y++) {
01927 for (x = 0 + ((y & 1)? 1 : 0); x < image.width(); x = x + 2 + spacing) {
01928 ind = x + image.width() * y - ((y & 1)? 1 : 0);
01929 data[ind] = lite==SWLite?uHash(data[ind]):lHash(data[ind]);
01930
01931 ind++;
01932 data[ind] = lite==SWLite?lHash(data[ind]):uHash(data[ind]);
01933 }
01934 }
01935 }
01936
01937 return image;
01938 }
01939
01940
01941
01942
01943
01944
01945
01946
01947 QImage& KImageEffect::flatten(QImage &img, const QColor &ca,
01948 const QColor &cb, int ncols)
01949 {
01950 if (img.width() == 0 || img.height() == 0)
01951 return img;
01952
01953
01954 if (img.depth() == 1) {
01955 img.setColor(0, ca.rgb());
01956 img.setColor(1, cb.rgb());
01957 return img;
01958 }
01959
01960 int r1 = ca.red(); int r2 = cb.red();
01961 int g1 = ca.green(); int g2 = cb.green();
01962 int b1 = ca.blue(); int b2 = cb.blue();
01963 int min = 0, max = 255;
01964
01965 QRgb col;
01966
01967
01968 if (img.numColors()) {
01969
01970 for (int i = 0; i < img.numColors(); i++) {
01971 col = img.color(i);
01972 int mean = (qRed(col) + qGreen(col) + qBlue(col)) / 3;
01973 min = QMIN(min, mean);
01974 max = QMAX(max, mean);
01975 }
01976 } else {
01977
01978 for (int y=0; y < img.height(); y++)
01979 for (int x=0; x < img.width(); x++) {
01980 col = img.pixel(x, y);
01981 int mean = (qRed(col) + qGreen(col) + qBlue(col)) / 3;
01982 min = QMIN(min, mean);
01983 max = QMAX(max, mean);
01984 }
01985 }
01986
01987
01988 float sr = ((float) r2 - r1) / (max - min);
01989 float sg = ((float) g2 - g1) / (max - min);
01990 float sb = ((float) b2 - b1) / (max - min);
01991
01992
01993
01994 if (img.numColors()) {
01995 for (int i=0; i < img.numColors(); i++) {
01996 col = img.color(i);
01997 int mean = (qRed(col) + qGreen(col) + qBlue(col)) / 3;
01998 int r = (int) (sr * (mean - min) + r1 + 0.5);
01999 int g = (int) (sg * (mean - min) + g1 + 0.5);
02000 int b = (int) (sb * (mean - min) + b1 + 0.5);
02001 img.setColor(i, qRgba(r, g, b, qAlpha(col)));
02002 }
02003 } else {
02004 for (int y=0; y < img.height(); y++)
02005 for (int x=0; x < img.width(); x++) {
02006 col = img.pixel(x, y);
02007 int mean = (qRed(col) + qGreen(col) + qBlue(col)) / 3;
02008 int r = (int) (sr * (mean - min) + r1 + 0.5);
02009 int g = (int) (sg * (mean - min) + g1 + 0.5);
02010 int b = (int) (sb * (mean - min) + b1 + 0.5);
02011 img.setPixel(x, y, qRgba(r, g, b, qAlpha(col)));
02012 }
02013 }
02014
02015
02016
02017 if ( (ncols <= 0) || ((img.numColors() != 0) && (img.numColors() <= ncols)))
02018 return img;
02019
02020 if (ncols == 1) ncols++;
02021 if (ncols > 256) ncols = 256;
02022
02023 QColor *pal = new QColor[ncols];
02024 sr = ((float) r2 - r1) / (ncols - 1);
02025 sg = ((float) g2 - g1) / (ncols - 1);
02026 sb = ((float) b2 - b1) / (ncols - 1);
02027
02028 for (int i=0; i<ncols; i++)
02029 pal[i] = QColor(r1 + int(sr*i), g1 + int(sg*i), b1 + int(sb*i));
02030
02031 dither(img, pal, ncols);
02032
02033 delete[] pal;
02034 return img;
02035 }
02036
02037
02038
02039
02040
02041
02042
02043
02044 QImage& KImageEffect::fade(QImage &img, float val, const QColor &color)
02045 {
02046 if (img.width() == 0 || img.height() == 0)
02047 return img;
02048
02049
02050 if (img.depth() == 1)
02051 return img;
02052
02053 unsigned char tbl[256];
02054 for (int i=0; i<256; i++)
02055 tbl[i] = (int) (val * i + 0.5);
02056
02057 int red = color.red();
02058 int green = color.green();
02059 int blue = color.blue();
02060
02061 QRgb col;
02062 int r, g, b, cr, cg, cb;
02063
02064 if (img.depth() <= 8) {
02065
02066 for (int i=0; i<img.numColors(); i++) {
02067 col = img.color(i);
02068 cr = qRed(col); cg = qGreen(col); cb = qBlue(col);
02069 if (cr > red)
02070 r = cr - tbl[cr - red];
02071 else
02072 r = cr + tbl[red - cr];
02073 if (cg > green)
02074 g = cg - tbl[cg - green];
02075 else
02076 g = cg + tbl[green - cg];
02077 if (cb > blue)
02078 b = cb - tbl[cb - blue];
02079 else
02080 b = cb + tbl[blue - cb];
02081 img.setColor(i, qRgba(r, g, b, qAlpha(col)));
02082 }
02083
02084 } else {
02085
02086 for (int y=0; y<img.height(); y++) {
02087 QRgb *data = (QRgb *) img.scanLine(y);
02088 for (int x=0; x<img.width(); x++) {
02089 col = *data;
02090 cr = qRed(col); cg = qGreen(col); cb = qBlue(col);
02091 if (cr > red)
02092 r = cr - tbl[cr - red];
02093 else
02094 r = cr + tbl[red - cr];
02095 if (cg > green)
02096 g = cg - tbl[cg - green];
02097 else
02098 g = cg + tbl[green - cg];
02099 if (cb > blue)
02100 b = cb - tbl[cb - blue];
02101 else
02102 b = cb + tbl[blue - cb];
02103 *data++ = qRgba(r, g, b, qAlpha(col));
02104 }
02105 }
02106 }
02107
02108 return img;
02109 }
02110
02111
02112
02113
02114
02115
02116
02117
02118
02119
02120
02121
02122
02123
02124
02125
02126 QImage& KImageEffect::toGray(QImage &img, bool fast)
02127 {
02128 if (img.width() == 0 || img.height() == 0)
02129 return img;
02130
02131 if(fast){
02132 if (img.depth() == 32) {
02133 register uchar * r(img.bits());
02134 register uchar * g(img.bits() + 1);
02135 register uchar * b(img.bits() + 2);
02136
02137 uchar * end(img.bits() + img.numBytes());
02138
02139 while (r != end) {
02140
02141 *r = *g = *b = (((*r + *g) >> 1) + *b) >> 1;
02142
02143 r += 4;
02144 g += 4;
02145 b += 4;
02146 }
02147 }
02148 else
02149 {
02150 for (int i = 0; i < img.numColors(); i++)
02151 {
02152 register uint r = qRed(img.color(i));
02153 register uint g = qGreen(img.color(i));
02154 register uint b = qBlue(img.color(i));
02155
02156 register uint gray = (((r + g) >> 1) + b) >> 1;
02157 img.setColor(i, qRgba(gray, gray, gray, qAlpha(img.color(i))));
02158 }
02159 }
02160 }
02161 else{
02162 int pixels = img.depth() > 8 ? img.width()*img.height() :
02163 img.numColors();
02164 unsigned int *data = img.depth() > 8 ? (unsigned int *)img.bits() :
02165 (unsigned int *)img.colorTable();
02166 int val, i;
02167 for(i=0; i < pixels; ++i){
02168 val = qGray(data[i]);
02169 data[i] = qRgba(val, val, val, qAlpha(data[i]));
02170 }
02171 }
02172 return img;
02173 }
02174
02175
02176 QImage& KImageEffect::desaturate(QImage &img, float desat)
02177 {
02178 if (img.width() == 0 || img.height() == 0)
02179 return img;
02180
02181 if (desat < 0) desat = 0.;
02182 if (desat > 1) desat = 1.;
02183 int pixels = img.depth() > 8 ? img.width()*img.height() :
02184 img.numColors();
02185 unsigned int *data = img.depth() > 8 ? (unsigned int *)img.bits() :
02186 (unsigned int *)img.colorTable();
02187 int h, s, v, i;
02188 QColor clr;
02189 for(i=0; i < pixels; ++i){
02190 clr.setRgb(data[i]);
02191 clr.hsv(&h, &s, &v);
02192 clr.setHsv(h, (int)(s * (1. - desat)), v);
02193 data[i] = clr.rgb();
02194 }
02195 return img;
02196 }
02197
02198
02199 QImage& KImageEffect::contrast(QImage &img, int c)
02200 {
02201 if (img.width() == 0 || img.height() == 0)
02202 return img;
02203
02204 if(c > 255)
02205 c = 255;
02206 if(c < -255)
02207 c = -255;
02208 int pixels = img.depth() > 8 ? img.width()*img.height() :
02209 img.numColors();
02210 unsigned int *data = img.depth() > 8 ? (unsigned int *)img.bits() :
02211 (unsigned int *)img.colorTable();
02212 int i, r, g, b;
02213 for(i=0; i < pixels; ++i){
02214 r = qRed(data[i]);
02215 g = qGreen(data[i]);
02216 b = qBlue(data[i]);
02217 if(qGray(data[i]) <= 127){
02218 if(r - c > 0)
02219 r -= c;
02220 else
02221 r = 0;
02222 if(g - c > 0)
02223 g -= c;
02224 else
02225 g = 0;
02226 if(b - c > 0)
02227 b -= c;
02228 else
02229 b = 0;
02230 }
02231 else{
02232 if(r + c <= 255)
02233 r += c;
02234 else
02235 r = 255;
02236 if(g + c <= 255)
02237 g += c;
02238 else
02239 g = 255;
02240 if(b + c <= 255)
02241 b += c;
02242 else
02243 b = 255;
02244 }
02245 data[i] = qRgba(r, g, b, qAlpha(data[i]));
02246 }
02247 return(img);
02248 }
02249
02250
02251
02252
02253
02254
02255
02256
02257
02258
02259
02260
02261 QImage& KImageEffect::dither(QImage &img, const QColor *palette, int size)
02262 {
02263 if (img.width() == 0 || img.height() == 0 ||
02264 palette == 0 || img.depth() <= 8)
02265 return img;
02266
02267 QImage dImage( img.width(), img.height(), 8, size );
02268 int i;
02269
02270 dImage.setNumColors( size );
02271 for ( i = 0; i < size; i++ )
02272 dImage.setColor( i, palette[ i ].rgb() );
02273
02274 int *rerr1 = new int [ img.width() * 2 ];
02275 int *gerr1 = new int [ img.width() * 2 ];
02276 int *berr1 = new int [ img.width() * 2 ];
02277
02278 memset( rerr1, 0, sizeof( int ) * img.width() * 2 );
02279 memset( gerr1, 0, sizeof( int ) * img.width() * 2 );
02280 memset( berr1, 0, sizeof( int ) * img.width() * 2 );
02281
02282 int *rerr2 = rerr1 + img.width();
02283 int *gerr2 = gerr1 + img.width();
02284 int *berr2 = berr1 + img.width();
02285
02286 for ( int j = 0; j < img.height(); j++ )
02287 {
02288 uint *ip = (uint * )img.scanLine( j );
02289 uchar *dp = dImage.scanLine( j );
02290
02291 for ( i = 0; i < img.width(); i++ )
02292 {
02293 rerr1[i] = rerr2[i] + qRed( *ip );
02294 rerr2[i] = 0;
02295 gerr1[i] = gerr2[i] + qGreen( *ip );
02296 gerr2[i] = 0;
02297 berr1[i] = berr2[i] + qBlue( *ip );
02298 berr2[i] = 0;
02299 ip++;
02300 }
02301
02302 *dp++ = nearestColor( rerr1[0], gerr1[0], berr1[0], palette, size );
02303
02304 for ( i = 1; i < img.width()-1; i++ )
02305 {
02306 int indx = nearestColor( rerr1[i], gerr1[i], berr1[i], palette, size );
02307 *dp = indx;
02308
02309 int rerr = rerr1[i];
02310 rerr -= palette[indx].red();
02311 int gerr = gerr1[i];
02312 gerr -= palette[indx].green();
02313 int berr = berr1[i];
02314 berr -= palette[indx].blue();
02315
02316
02317 rerr1[ i+1 ] += ( rerr * 7 ) >> 4;
02318 rerr2[ i-1 ] += ( rerr * 3 ) >> 4;
02319 rerr2[ i ] += ( rerr * 5 ) >> 4;
02320 rerr2[ i+1 ] += ( rerr ) >> 4;
02321
02322
02323 gerr1[ i+1 ] += ( gerr * 7 ) >> 4;
02324 gerr2[ i-1 ] += ( gerr * 3 ) >> 4;
02325 gerr2[ i ] += ( gerr * 5 ) >> 4;
02326 gerr2[ i+1 ] += ( gerr ) >> 4;
02327
02328
02329 berr1[ i+1 ] += ( berr * 7 ) >> 4;
02330 berr2[ i-1 ] += ( berr * 3 ) >> 4;
02331 berr2[ i ] += ( berr * 5 ) >> 4;
02332 berr2[ i+1 ] += ( berr ) >> 4;
02333
02334 dp++;
02335 }
02336
02337 *dp = nearestColor( rerr1[i], gerr1[i], berr1[i], palette, size );
02338 }
02339
02340 delete [] rerr1;
02341 delete [] gerr1;
02342 delete [] berr1;
02343
02344 img = dImage;
02345 return img;
02346 }
02347
02348 int KImageEffect::nearestColor( int r, int g, int b, const QColor *palette, int size )
02349 {
02350 if (palette == 0)
02351 return 0;
02352
02353 int dr = palette[0].red() - r;
02354 int dg = palette[0].green() - g;
02355 int db = palette[0].blue() - b;
02356
02357 int minDist = dr*dr + dg*dg + db*db;
02358 int nearest = 0;
02359
02360 for (int i = 1; i < size; i++ )
02361 {
02362 dr = palette[i].red() - r;
02363 dg = palette[i].green() - g;
02364 db = palette[i].blue() - b;
02365
02366 int dist = dr*dr + dg*dg + db*db;
02367
02368 if ( dist < minDist )
02369 {
02370 minDist = dist;
02371 nearest = i;
02372 }
02373 }
02374
02375 return nearest;
02376 }
02377
02378 bool KImageEffect::blend(
02379 const QImage & upper,
02380 const QImage & lower,
02381 QImage & output
02382 )
02383 {
02384 if (
02385 upper.width() > lower.width() ||
02386 upper.height() > lower.height() ||
02387 upper.depth() != 32 ||
02388 lower.depth() != 32
02389 )
02390 {
02391 #ifndef NDEBUG
02392 std::cerr << "KImageEffect::blend : Sizes not correct\n" ;
02393 #endif
02394 return false;
02395 }
02396
02397 output = lower.copy();
02398
02399 register uchar *i, *o;
02400 register int a;
02401 register int col;
02402 register int w = upper.width();
02403 int row(upper.height() - 1);
02404
02405 do {
02406
02407 i = upper.scanLine(row);
02408 o = output.scanLine(row);
02409
02410 col = w << 2;
02411 --col;
02412
02413 do {
02414
02415 while (!(a = i[col]) && (col != 3)) {
02416 --col; --col; --col; --col;
02417 }
02418
02419 --col;
02420 o[col] += ((i[col] - o[col]) * a) >> 8;
02421
02422 --col;
02423 o[col] += ((i[col] - o[col]) * a) >> 8;
02424
02425 --col;
02426 o[col] += ((i[col] - o[col]) * a) >> 8;
02427
02428 } while (col--);
02429
02430 } while (row--);
02431
02432 return true;
02433 }
02434
02435 #if 0
02436
02437 bool KImageEffect::blend(
02438 const QImage & upper,
02439 const QImage & lower,
02440 QImage & output,
02441 const QRect & destRect
02442 )
02443 {
02444 output = lower.copy();
02445 return output;
02446 }
02447
02448 #endif
02449
02450 bool KImageEffect::blend(
02451 int &x, int &y,
02452 const QImage & upper,
02453 const QImage & lower,
02454 QImage & output
02455 )
02456 {
02457 int cx=0, cy=0, cw=upper.width(), ch=upper.height();
02458
02459 if ( upper.width() + x > lower.width() ||
02460 upper.height() + y > lower.height() ||
02461 x < 0 || y < 0 ||
02462 upper.depth() != 32 || lower.depth() != 32 )
02463 {
02464 if ( x > lower.width() || y > lower.height() ) return false;
02465 if ( upper.width()<=0 || upper.height() <= 0 ) return false;
02466 if ( lower.width()<=0 || lower.height() <= 0 ) return false;
02467
02468 if (x<0) {cx=-x; cw+=x; x=0; };
02469 if (cw + x > lower.width()) { cw=lower.width()-x; };
02470 if (y<0) {cy=-y; ch+=y; y=0; };
02471 if (ch + y > lower.height()) { ch=lower.height()-y; };
02472
02473 if ( cx >= upper.width() || cy >= upper.height() ) return true;
02474 if ( cw <= 0 || ch <= 0 ) return true;
02475 }
02476
02477 output.create(cw,ch,32);
02478
02479
02480
02481 register QRgb *i, *o, *b;
02482
02483 register int a;
02484 register int j,k;
02485 for (j=0; j<ch; j++)
02486 {
02487 b=reinterpret_cast<QRgb *>(&lower.scanLine(y+j) [ (x+cw) << 2 ]);
02488 i=reinterpret_cast<QRgb *>(&upper.scanLine(cy+j)[ (cx+cw) << 2 ]);
02489 o=reinterpret_cast<QRgb *>(&output.scanLine(j) [ cw << 2 ]);
02490
02491 k=cw-1;
02492 --b; --i; --o;
02493 do
02494 {
02495 while ( !(a=qAlpha(*i)) && k>0 )
02496 {
02497 i--;
02498
02499 *o=*b;
02500 --o; --b;
02501 k--;
02502 };
02503
02504 *o = qRgb(qRed(*b) + (((qRed(*i) - qRed(*b)) * a) >> 8),
02505 qGreen(*b) + (((qGreen(*i) - qGreen(*b)) * a) >> 8),
02506 qBlue(*b) + (((qBlue(*i) - qBlue(*b)) * a) >> 8));
02507 --i; --o; --b;
02508 } while (k--);
02509 }
02510
02511 return true;
02512 }
02513
02514 bool KImageEffect::blendOnLower(
02515 int x, int y,
02516 const QImage & upper,
02517 const QImage & lower
02518 )
02519 {
02520 int cx=0, cy=0, cw=upper.width(), ch=upper.height();
02521
02522 if ( upper.depth() != 32 || lower.depth() != 32 ) return false;
02523 if ( x + cw > lower.width() ||
02524 y + ch > lower.height() ||
02525 x < 0 || y < 0 )
02526 {
02527 if ( x > lower.width() || y > lower.height() ) return true;
02528 if ( upper.width()<=0 || upper.height() <= 0 ) return true;
02529 if ( lower.width()<=0 || lower.height() <= 0 ) return true;
02530
02531 if (x<0) {cx=-x; cw+=x; x=0; };
02532 if (cw + x > lower.width()) { cw=lower.width()-x; };
02533 if (y<0) {cy=-y; ch+=y; y=0; };
02534 if (ch + y > lower.height()) { ch=lower.height()-y; };
02535
02536 if ( cx >= upper.width() || cy >= upper.height() ) return true;
02537 if ( cw <= 0 || ch <= 0 ) return true;
02538 }
02539
02540 register uchar *i, *b;
02541 register int a;
02542 register int k;
02543
02544 for (int j=0; j<ch; j++)
02545 {
02546 b=&lower.scanLine(y+j) [ (x+cw) << 2 ];
02547 i=&upper.scanLine(cy+j)[ (cx+cw) << 2 ];
02548
02549 k=cw-1;
02550 --b; --i;
02551 do
02552 {
02553 #ifndef WORDS_BIGENDIAN
02554 while ( !(a=*i) && k>0 )
02555 #else
02556 while ( !(a=*(i-3)) && k>0 )
02557 #endif
02558 {
02559 i-=4; b-=4; k--;
02560 };
02561
02562 #ifndef WORDS_BIGENDIAN
02563 --i; --b;
02564 *b += ( ((*i - *b) * a) >> 8 );
02565 --i; --b;
02566 *b += ( ((*i - *b) * a) >> 8 );
02567 --i; --b;
02568 *b += ( ((*i - *b) * a) >> 8 );
02569 --i; --b;
02570 #else
02571 *b += ( ((*i - *b) * a) >> 8 );
02572 --i; --b;
02573 *b += ( ((*i - *b) * a) >> 8 );
02574 --i; --b;
02575 *b += ( ((*i - *b) * a) >> 8 );
02576 i -= 2; b -= 2;
02577 #endif
02578 } while (k--);
02579 }
02580
02581 return true;
02582 }
02583
02584 void KImageEffect::blendOnLower(const QImage &upper, const QPoint &upperOffset,
02585 QImage &lower, const QRect &lowerRect)
02586 {
02587
02588 QRect lr = lowerRect & lower.rect();
02589 lr.setWidth( QMIN(lr.width(), upper.width()-upperOffset.x()) );
02590 lr.setHeight( QMIN(lr.height(), upper.height()-upperOffset.y()) );
02591 if ( !lr.isValid() ) return;
02592
02593
02594 for (int y = 0; y < lr.height(); y++) {
02595 for (int x = 0; x < lr.width(); x++) {
02596 QRgb *b = reinterpret_cast<QRgb*>(lower.scanLine(lr.y() + y)+ (lr.x() + x) * sizeof(QRgb));
02597 QRgb *d = reinterpret_cast<QRgb*>(upper.scanLine(upperOffset.y() + y) + (upperOffset.x() + x) * sizeof(QRgb));
02598 int a = qAlpha(*d);
02599 *b = qRgb(qRed(*b) - (((qRed(*b) - qRed(*d)) * a) >> 8),
02600 qGreen(*b) - (((qGreen(*b) - qGreen(*d)) * a) >> 8),
02601 qBlue(*b) - (((qBlue(*b) - qBlue(*d)) * a) >> 8));
02602 }
02603 }
02604 }
02605
02606 void KImageEffect::blendOnLower(const QImage &upper, const QPoint &upperOffset,
02607 QImage &lower, const QRect &lowerRect, float opacity)
02608 {
02609
02610 QRect lr = lowerRect & lower.rect();
02611 lr.setWidth( QMIN(lr.width(), upper.width()-upperOffset.x()) );
02612 lr.setHeight( QMIN(lr.height(), upper.height()-upperOffset.y()) );
02613 if ( !lr.isValid() ) return;
02614
02615
02616 for (int y = 0; y < lr.height(); y++) {
02617 for (int x = 0; x < lr.width(); x++) {
02618 QRgb *b = reinterpret_cast<QRgb*>(lower.scanLine(lr.y() + y)+ (lr.x() + x) * sizeof(QRgb));
02619 QRgb *d = reinterpret_cast<QRgb*>(upper.scanLine(upperOffset.y() + y) + (upperOffset.x() + x) * sizeof(QRgb));
02620 int a = qRound(opacity * qAlpha(*d));
02621 *b = qRgb(qRed(*b) - (((qRed(*b) - qRed(*d)) * a) >> 8),
02622 qGreen(*b) - (((qGreen(*b) - qGreen(*d)) * a) >> 8),
02623 qBlue(*b) - (((qBlue(*b) - qBlue(*d)) * a) >> 8));
02624 }
02625 }
02626 }
02627
02628 QRect KImageEffect::computeDestinationRect(const QSize &lowerSize,
02629 Disposition disposition, QImage &upper)
02630 {
02631 int w = lowerSize.width();
02632 int h = lowerSize.height();
02633 int ww = upper.width();
02634 int wh = upper.height();
02635 QRect d;
02636
02637 switch (disposition) {
02638 case NoImage:
02639 break;
02640 case Centered:
02641 d.setRect((w - ww) / 2, (h - wh) / 2, ww, wh);
02642 break;
02643 case Tiled:
02644 d.setRect(0, 0, w, h);
02645 break;
02646 case CenterTiled:
02647 d.setCoords(-ww + ((w - ww) / 2) % ww, -wh + ((h - wh) / 2) % wh,
02648 w-1, h-1);
02649 break;
02650 case Scaled:
02651 upper = upper.smoothScale(w, h);
02652 d.setRect(0, 0, w, h);
02653 break;
02654 case CenteredAutoFit:
02655 if( ww <= w && wh <= h ) {
02656 d.setRect((w - ww) / 2, (h - wh) / 2, ww, wh);
02657 break;
02658 }
02659
02660 case CenteredMaxpect: {
02661 double sx = (double) w / ww;
02662 double sy = (double) h / wh;
02663 if (sx > sy) {
02664 ww = (int)(sy * ww);
02665 wh = h;
02666 } else {
02667 wh = (int)(sx * wh);
02668 ww = w;
02669 }
02670 upper = upper.smoothScale(ww, wh);
02671 d.setRect((w - ww) / 2, (h - wh) / 2, ww, wh);
02672 break;
02673 }
02674 case TiledMaxpect: {
02675 double sx = (double) w / ww;
02676 double sy = (double) h / wh;
02677 if (sx > sy) {
02678 ww = (int)(sy * ww);
02679 wh = h;
02680 } else {
02681 wh = (int)(sx * wh);
02682 ww = w;
02683 }
02684 upper = upper.smoothScale(ww, wh);
02685 d.setRect(0, 0, w, h);
02686 break;
02687 }
02688 }
02689
02690 return d;
02691 }
02692
02693 void KImageEffect::blendOnLower(QImage &upper, QImage &lower,
02694 Disposition disposition, float opacity)
02695 {
02696 QRect r = computeDestinationRect(lower.size(), disposition, upper);
02697 for (int y = r.top(); y<r.bottom(); y += upper.height())
02698 for (int x = r.left(); x<r.right(); x += upper.width())
02699 blendOnLower(upper, QPoint(-QMIN(x, 0), -QMIN(y, 0)),
02700 lower, QRect(x, y, upper.width(), upper.height()), opacity);
02701 }
02702
02703
02704
02705 QImage& KImageEffect::selectedImage( QImage &img, const QColor &col )
02706 {
02707 return blend( col, img, 0.5);
02708 }
02709
02710
02711
02712
02713
02714
02715
02716
02717
02718
02719
02720
02721
02722
02723
02724
02725
02726
02727
02728
02729
02730
02731
02732
02733
02734
02735
02736
02737
02738
02739
02740
02741
02742
02743
02744
02745
02746
02747 QImage KImageEffect::sample(QImage &src, int w, int h)
02748 {
02749 if(w == src.width() && h == src.height())
02750 return(src);
02751
02752 int depth = src.depth();
02753 QImage dest(w, h, depth, depth <= 8 ? src.numColors() : 0,
02754 depth == 1 ? QImage::LittleEndian : QImage::IgnoreEndian);
02755 int *x_offset = (int *)malloc(w*sizeof(int));
02756 int *y_offset = (int *)malloc(h*sizeof(int));
02757 if(!x_offset || !y_offset){
02758 #ifndef NDEBUG
02759 qWarning("KImageEffect::sample(): Unable to allocate pixel buffer");
02760 #endif
02761 free(x_offset);
02762 free(y_offset);
02763 return(src);
02764 }
02765
02766
02767 for(int x=0; x < w; ++x)
02768 x_offset[x] = (int)(x*src.width()/((double)w));
02769 for(int y=0; y < h; ++y)
02770 y_offset[y] = (int)(y*src.height()/((double)h));
02771
02772 if(depth > 8){
02773 for(int y=0; y < h; ++y){
02774 unsigned int *destData = (unsigned int *)dest.scanLine(y);
02775 unsigned int *srcData = (unsigned int *)src.scanLine(y_offset[y]);
02776 for(int x=0; x < w; ++x)
02777 destData[x] = srcData[x_offset[x]];
02778 }
02779 }
02780 else if(depth == 1) {
02781 int r = src.bitOrder() == QImage::LittleEndian;
02782 memcpy(dest.colorTable(), src.colorTable(), src.numColors()*sizeof(QRgb));
02783 for(int y=0; y < h; ++y){
02784 unsigned char *destData = dest.scanLine(y);
02785 unsigned char *srcData = src.scanLine(y_offset[y]);
02786 for(int x=0; x < w; ++x){
02787 int k = x_offset[x];
02788 int l = r ? (k & 7) : (7 - (k&7));
02789 if(srcData[k >> 3] & (1 << l))
02790 destData[x >> 3] |= 1 << (x & 7);
02791 else
02792 destData[x >> 3] &= ~(1 << (x & 7));
02793 }
02794 }
02795 }
02796 else{
02797 memcpy(dest.colorTable(), src.colorTable(), src.numColors()*sizeof(QRgb));
02798 for(int y=0; y < h; ++y){
02799 unsigned char *destData = dest.scanLine(y);
02800 unsigned char *srcData = src.scanLine(y_offset[y]);
02801 for(int x=0; x < w; ++x)
02802 destData[x] = srcData[x_offset[x]];
02803 }
02804 }
02805 free(x_offset);
02806 free(y_offset);
02807 return(dest);
02808 }
02809
02810 void KImageEffect::threshold(QImage &img, unsigned int threshold)
02811 {
02812 int i, count;
02813 unsigned int *data;
02814 if(img.depth() > 8){
02815 count = img.width()*img.height();
02816 data = (unsigned int *)img.bits();
02817 }
02818 else{
02819 count = img.numColors();
02820 data = (unsigned int *)img.colorTable();
02821 }
02822 for(i=0; i < count; ++i)
02823 data[i] = intensityValue(data[i]) < threshold ? Qt::black.rgb() : Qt::white.rgb();
02824 }
02825
02826 void KImageEffect::hull(const int x_offset, const int y_offset,
02827 const int polarity, const int columns,
02828 const int rows,
02829 unsigned int *f, unsigned int *g)
02830 {
02831 int x, y;
02832
02833 unsigned int *p, *q, *r, *s;
02834 unsigned int v;
02835 if(f == NULL || g == NULL)
02836 return;
02837 p=f+(columns+2);
02838 q=g+(columns+2);
02839 r=p+(y_offset*(columns+2)+x_offset);
02840 for (y=0; y < rows; y++){
02841 p++;
02842 q++;
02843 r++;
02844 if(polarity > 0)
02845 for (x=0; x < columns; x++){
02846 v=(*p);
02847 if (*r > v)
02848 v++;
02849 *q=v;
02850 p++;
02851 q++;
02852 r++;
02853 }
02854 else
02855 for(x=0; x < columns; x++){
02856 v=(*p);
02857 if (v > (unsigned int) (*r+1))
02858 v--;
02859 *q=v;
02860 p++;
02861 q++;
02862 r++;
02863 }
02864 p++;
02865 q++;
02866 r++;
02867 }
02868 p=f+(columns+2);
02869 q=g+(columns+2);
02870 r=q+(y_offset*(columns+2)+x_offset);
02871 s=q-(y_offset*(columns+2)+x_offset);
02872 for(y=0; y < rows; y++){
02873 p++;
02874 q++;
02875 r++;
02876 s++;
02877 if(polarity > 0)
02878 for(x=0; x < (int) columns; x++){
02879 v=(*q);
02880 if (((unsigned int) (*s+1) > v) && (*r > v))
02881 v++;
02882 *p=v;
02883 p++;
02884 q++;
02885 r++;
02886 s++;
02887 }
02888 else
02889 for (x=0; x < columns; x++){
02890 v=(*q);
02891 if (((unsigned int) (*s+1) < v) && (*r < v))
02892 v--;
02893 *p=v;
02894 p++;
02895 q++;
02896 r++;
02897 s++;
02898 }
02899 p++;
02900 q++;
02901 r++;
02902 s++;
02903 }
02904 }
02905
02906 QImage KImageEffect::despeckle(QImage &src)
02907 {
02908 int i, j, x, y;
02909 unsigned int *blue_channel, *red_channel, *green_channel, *buffer,
02910 *alpha_channel;
02911 int packets;
02912 static const int
02913 X[4]= {0, 1, 1,-1},
02914 Y[4]= {1, 0, 1, 1};
02915
02916 unsigned int *destData;
02917 QImage dest(src.width(), src.height(), 32);
02918
02919 packets = (src.width()+2)*(src.height()+2);
02920 red_channel = (unsigned int *)calloc(packets, sizeof(unsigned int));
02921 green_channel = (unsigned int *)calloc(packets, sizeof(unsigned int));
02922 blue_channel = (unsigned int *)calloc(packets, sizeof(unsigned int));
02923 alpha_channel = (unsigned int *)calloc(packets, sizeof(unsigned int));
02924 buffer = (unsigned int *)calloc(packets, sizeof(unsigned int));
02925 if(!red_channel || ! green_channel || ! blue_channel || ! alpha_channel ||
02926 !buffer){
02927 free(red_channel);
02928 free(green_channel);
02929 free(blue_channel);
02930 free(alpha_channel);
02931 free(buffer);
02932 return(src);
02933 }
02934
02935
02936 j = src.width()+2;
02937 if(src.depth() > 8){
02938 unsigned int *srcData;
02939 for(y=0; y < src.height(); ++y){
02940 srcData = (unsigned int *)src.scanLine(y);
02941 ++j;
02942 for(x=0; x < src.width(); ++x){
02943 red_channel[j] = qRed(srcData[x]);
02944 green_channel[j] = qGreen(srcData[x]);
02945 blue_channel[j] = qBlue(srcData[x]);
02946 alpha_channel[j] = qAlpha(srcData[x]);
02947 ++j;
02948 }
02949 ++j;
02950 }
02951 }
02952 else{
02953 unsigned char *srcData;
02954 unsigned int *cTable = src.colorTable();
02955 unsigned int pixel;
02956 for(y=0; y < src.height(); ++y){
02957 srcData = (unsigned char *)src.scanLine(y);
02958 ++j;
02959 for(x=0; x < src.width(); ++x){
02960 pixel = *(cTable+srcData[x]);
02961 red_channel[j] = qRed(pixel);
02962 green_channel[j] = qGreen(pixel);
02963 blue_channel[j] = qBlue(pixel);
02964 alpha_channel[j] = qAlpha(pixel);
02965 ++j;
02966 }
02967 ++j;
02968 }
02969 }
02970
02971 for(i=0; i < 4; i++){
02972 hull(X[i],Y[i],1,src.width(),src.height(),red_channel,buffer);
02973 hull(-X[i],-Y[i],1,src.width(),src.height(),red_channel,buffer);
02974 hull(-X[i],-Y[i],-1,src.width(),src.height(),red_channel,buffer);
02975 hull(X[i],Y[i],-1,src.width(),src.height(),red_channel,buffer);
02976 }
02977
02978 for (i=0; i < packets; i++)
02979 buffer[i]=0;
02980 for (i=0; i < 4; i++){
02981 hull(X[i],Y[i],1,src.width(),src.height(),green_channel,buffer);
02982 hull(-X[i],-Y[i],1,src.width(),src.height(),green_channel,buffer);
02983 hull(-X[i],-Y[i],-1,src.width(),src.height(),green_channel,buffer);
02984 hull(X[i],Y[i],-1,src.width(),src.height(),green_channel,buffer);
02985 }
02986
02987 for (i=0; i < packets; i++)
02988 buffer[i]=0;
02989 for (i=0; i < 4; i++){
02990 hull(X[i],Y[i],1,src.width(),src.height(),blue_channel,buffer);
02991 hull(-X[i],-Y[i],1,src.width(),src.height(),blue_channel,buffer);
02992 hull(-X[i],-Y[i],-1,src.width(),src.height(),blue_channel,buffer);
02993 hull(X[i],Y[i],-1,src.width(),src.height(),blue_channel,buffer);
02994 }
02995
02996 j = dest.width()+2;
02997 for(y=0; y < dest.height(); ++y)
02998 {
02999 destData = (unsigned int *)dest.scanLine(y);
03000 ++j;
03001 for (x=0; x < dest.width(); ++x)
03002 {
03003 destData[x] = qRgba(red_channel[j], green_channel[j],
03004 blue_channel[j], alpha_channel[j]);
03005 ++j;
03006 }
03007 ++j;
03008 }
03009 free(buffer);
03010 free(red_channel);
03011 free(green_channel);
03012 free(blue_channel);
03013 free(alpha_channel);
03014 return(dest);
03015 }
03016
03017 unsigned int KImageEffect::generateNoise(unsigned int pixel,
03018 NoiseType noise_type)
03019 {
03020 #define NoiseEpsilon 1.0e-5
03021 #define NoiseMask 0x7fff
03022 #define SigmaUniform 4.0
03023 #define SigmaGaussian 4.0
03024 #define SigmaImpulse 0.10
03025 #define SigmaLaplacian 10.0
03026 #define SigmaMultiplicativeGaussian 0.5
03027 #define SigmaPoisson 0.05
03028 #define TauGaussian 20.0
03029
03030 double alpha, beta, sigma, value;
03031 alpha=(double) (rand() & NoiseMask)/NoiseMask;
03032 if (alpha == 0.0)
03033 alpha=1.0;
03034 switch(noise_type){
03035 case UniformNoise:
03036 default:
03037 {
03038 value=(double) pixel+SigmaUniform*(alpha-0.5);
03039 break;
03040 }
03041 case GaussianNoise:
03042 {
03043 double tau;
03044
03045 beta=(double) (rand() & NoiseMask)/NoiseMask;
03046 sigma=sqrt(-2.0*log(alpha))*cos(2.0*M_PI*beta);
03047 tau=sqrt(-2.0*log(alpha))*sin(2.0*M_PI*beta);
03048 value=(double) pixel+
03049 (sqrt((double) pixel)*SigmaGaussian*sigma)+(TauGaussian*tau);
03050 break;
03051 }
03052 case MultiplicativeGaussianNoise:
03053 {
03054 if (alpha <= NoiseEpsilon)
03055 sigma=MaxRGB;
03056 else
03057 sigma=sqrt(-2.0*log(alpha));
03058 beta=(rand() & NoiseMask)/NoiseMask;
03059 value=(double) pixel+
03060 pixel*SigmaMultiplicativeGaussian*sigma*cos(2.0*M_PI*beta);
03061 break;
03062 }
03063 case ImpulseNoise:
03064 {
03065 if (alpha < (SigmaImpulse/2.0))
03066 value=0;
03067 else
03068 if (alpha >= (1.0-(SigmaImpulse/2.0)))
03069 value=MaxRGB;
03070 else
03071 value=pixel;
03072 break;
03073 }
03074 case LaplacianNoise:
03075 {
03076 if (alpha <= 0.5)
03077 {
03078 if (alpha <= NoiseEpsilon)
03079 value=(double) pixel-MaxRGB;
03080 else
03081 value=(double) pixel+SigmaLaplacian*log(2.0*alpha);
03082 break;
03083 }
03084 beta=1.0-alpha;
03085 if (beta <= (0.5*NoiseEpsilon))
03086 value=(double) pixel+MaxRGB;
03087 else
03088 value=(double) pixel-SigmaLaplacian*log(2.0*beta);
03089 break;
03090 }
03091 case PoissonNoise:
03092 {
03093 register int
03094 i;
03095
03096 for (i=0; alpha > exp(-SigmaPoisson*pixel); i++)
03097 {
03098 beta=(double) (rand() & NoiseMask)/NoiseMask;
03099 alpha=alpha*beta;
03100 }
03101 value=i/SigmaPoisson;
03102 break;
03103 }
03104 }
03105 if(value < 0.0)
03106 return(0);
03107 if(value > MaxRGB)
03108 return(MaxRGB);
03109 return((unsigned int) (value+0.5));
03110 }
03111
03112 QImage KImageEffect::addNoise(QImage &src, NoiseType noise_type)
03113 {
03114 int x, y;
03115 QImage dest(src.width(), src.height(), 32);
03116 unsigned int *destData;
03117
03118 if(src.depth() > 8){
03119 unsigned int *srcData;
03120 for(y=0; y < src.height(); ++y){
03121 srcData = (unsigned int *)src.scanLine(y);
03122 destData = (unsigned int *)dest.scanLine(y);
03123 for(x=0; x < src.width(); ++x){
03124 destData[x] = qRgba(generateNoise(qRed(srcData[x]), noise_type),
03125 generateNoise(qGreen(srcData[x]), noise_type),
03126 generateNoise(qBlue(srcData[x]), noise_type),
03127 qAlpha(srcData[x]));
03128 }
03129 }
03130 }
03131 else{
03132 unsigned char *srcData;
03133 unsigned int *cTable = src.colorTable();
03134 unsigned int pixel;
03135 for(y=0; y < src.height(); ++y){
03136 srcData = (unsigned char *)src.scanLine(y);
03137 destData = (unsigned int *)dest.scanLine(y);
03138 for(x=0; x < src.width(); ++x){
03139 pixel = *(cTable+srcData[x]);
03140 destData[x] = qRgba(generateNoise(qRed(pixel), noise_type),
03141 generateNoise(qGreen(pixel), noise_type),
03142 generateNoise(qBlue(pixel), noise_type),
03143 qAlpha(pixel));
03144 }
03145 }
03146
03147 }
03148 return(dest);
03149 }
03150
03151 unsigned int KImageEffect::interpolateColor(QImage *image, double x_offset,
03152 double y_offset,
03153 unsigned int background)
03154 {
03155 double alpha, beta;
03156 unsigned int p, q, r, s;
03157 int x, y;
03158
03159 x = (int)x_offset;
03160 y = (int)y_offset;
03161 if((x < -1) || (x >= image->width()) || (y < -1) || (y >= image->height()))
03162 return(background);
03163 if(image->depth() > 8){
03164 if((x >= 0) && (y >= 0) && (x < (image->width()-1)) && (y < (image->height()-1))) {
03165 unsigned int *t = (unsigned int *)image->scanLine(y);
03166 p = t[x];
03167 q = t[x+1];
03168 r = t[x+image->width()];
03169 s = t[x+image->width()+1];
03170 }
03171 else{
03172 unsigned int *t = (unsigned int *)image->scanLine(y);
03173 p = background;
03174 if((x >= 0) && (y >= 0)){
03175 p = t[x];
03176 }
03177 q = background;
03178 if(((x+1) < image->width()) && (y >= 0)){
03179 q = t[x+1];
03180 }
03181 r = background;
03182 if((x >= 0) && ((y+1) < image->height())){
03183 t = (unsigned int *)image->scanLine(y+1);
03184 r = t[x+image->width()];
03185 }
03186 s = background;
03187 if(((x+1) < image->width()) && ((y+1) < image->height())){
03188 t = (unsigned int *)image->scanLine(y+1);
03189 s = t[x+image->width()+1];
03190 }
03191
03192 }
03193 }
03194 else{
03195 unsigned int *colorTable = (unsigned int *)image->colorTable();
03196 if((x >= 0) && (y >= 0) && (x < (image->width()-1)) && (y < (image->height()-1))) {
03197 unsigned char *t;
03198 t = (unsigned char *)image->scanLine(y);
03199 p = *(colorTable+t[x]);
03200 q = *(colorTable+t[x+1]);
03201 t = (unsigned char *)image->scanLine(y+1);
03202 r = *(colorTable+t[x]);
03203 s = *(colorTable+t[x+1]);
03204 }
03205 else{
03206 unsigned char *t;
03207 p = background;
03208 if((x >= 0) && (y >= 0)){
03209 t = (unsigned char *)image->scanLine(y);
03210 p = *(colorTable+t[x]);
03211 }
03212 q = background;
03213 if(((x+1) < image->width()) && (y >= 0)){
03214 t = (unsigned char *)image->scanLine(y);
03215 q = *(colorTable+t[x+1]);
03216 }
03217 r = background;
03218 if((x >= 0) && ((y+1) < image->height())){
03219 t = (unsigned char *)image->scanLine(y+1);
03220 r = *(colorTable+t[x]);
03221 }
03222 s = background;
03223 if(((x+1) < image->width()) && ((y+1) < image->height())){
03224 t = (unsigned char *)image->scanLine(y+1);
03225 s = *(colorTable+t[x+1]);
03226 }
03227
03228 }
03229
03230 }
03231 x_offset -= floor(x_offset);
03232 y_offset -= floor(y_offset);
03233 alpha = 1.0-x_offset;
03234 beta = 1.0-y_offset;
03235
03236 return(qRgba((unsigned char)(beta*(alpha*qRed(p)+x_offset*qRed(q))+y_offset*(alpha*qRed(r)+x_offset*qRed(s))),
03237 (unsigned char)(beta*(alpha*qGreen(p)+x_offset*qGreen(q))+y_offset*(alpha*qGreen(r)+x_offset*qGreen(s))),
03238 (unsigned char)(beta*(alpha*qBlue(p)+x_offset*qBlue(q))+y_offset*(alpha*qBlue(r)+x_offset*qBlue(s))),
03239 (unsigned char)(beta*(alpha*qAlpha(p)+x_offset*qAlpha(q))+y_offset*(alpha*qAlpha(r)+x_offset*qAlpha(s)))));
03240 }
03241
03242 QImage KImageEffect::implode(QImage &src, double factor,
03243 unsigned int background)
03244 {
03245 double amount, distance, radius;
03246 double x_center, x_distance, x_scale;
03247 double y_center, y_distance, y_scale;
03248 unsigned int *destData;
03249 int x, y;
03250
03251 QImage dest(src.width(), src.height(), 32);
03252
03253
03254 x_scale = 1.0;
03255 y_scale = 1.0;
03256 x_center = (double)0.5*src.width();
03257 y_center = (double)0.5*src.height();
03258 radius=x_center;
03259 if(src.width() > src.height())
03260 y_scale = (double)src.width()/src.height();
03261 else if(src.width() < src.height()){
03262 x_scale = (double) src.height()/src.width();
03263 radius = y_center;
03264 }
03265 amount=factor/10.0;
03266 if(amount >= 0)
03267 amount/=10.0;
03268 if(src.depth() > 8){
03269 unsigned int *srcData;
03270 for(y=0; y < src.height(); ++y){
03271 srcData = (unsigned int *)src.scanLine(y);
03272 destData = (unsigned int *)dest.scanLine(y);
03273 y_distance=y_scale*(y-y_center);
03274 for(x=0; x < src.width(); ++x){
03275 destData[x] = srcData[x];
03276 x_distance = x_scale*(x-x_center);
03277 distance= x_distance*x_distance+y_distance*y_distance;
03278 if(distance < (radius*radius)){
03279 double factor;
03280
03281 factor=1.0;
03282 if(distance > 0.0)
03283 factor=
03284 pow(sin(0.5000000000000001*M_PI*sqrt(distance)/radius),-amount);
03285 destData[x] = interpolateColor(&src, factor*x_distance/x_scale+x_center,
03286 factor*y_distance/y_scale+y_center,
03287 background);
03288 }
03289 }
03290 }
03291 }
03292 else{
03293 unsigned char *srcData;
03294 unsigned char idx;
03295 unsigned int *cTable = src.colorTable();
03296 for(y=0; y < src.height(); ++y){
03297 srcData = (unsigned char *)src.scanLine(y);
03298 destData = (unsigned int *)dest.scanLine(y);
03299 y_distance=y_scale*(y-y_center);
03300 for(x=0; x < src.width(); ++x){
03301 idx = srcData[x];
03302 destData[x] = cTable[idx];
03303 x_distance = x_scale*(x-x_center);
03304 distance= x_distance*x_distance+y_distance*y_distance;
03305 if(distance < (radius*radius)){
03306 double factor;
03307
03308 factor=1.0;
03309 if(distance > 0.0)
03310 factor=
03311 pow(sin(0.5000000000000001*M_PI*sqrt(distance)/radius),-amount);
03312 destData[x] = interpolateColor(&src, factor*x_distance/x_scale+x_center,
03313 factor*y_distance/y_scale+y_center,
03314 background);
03315 }
03316 }
03317 }
03318
03319 }
03320 return(dest);
03321 }
03322
03323 QImage KImageEffect::rotate(QImage &img, RotateDirection r)
03324 {
03325 QImage dest;
03326 int x, y;
03327 if(img.depth() > 8){
03328 unsigned int *srcData, *destData;
03329 switch(r){
03330 case Rotate90:
03331 dest.create(img.height(), img.width(), img.depth());
03332 for(y=0; y < img.height(); ++y){
03333 srcData = (unsigned int *)img.scanLine(y);
03334 for(x=0; x < img.width(); ++x){
03335 destData = (unsigned int *)dest.scanLine(x);
03336 destData[img.height()-y-1] = srcData[x];
03337 }
03338 }
03339 break;
03340 case Rotate180:
03341 dest.create(img.width(), img.height(), img.depth());
03342 for(y=0; y < img.height(); ++y){
03343 srcData = (unsigned int *)img.scanLine(y);
03344 destData = (unsigned int *)dest.scanLine(img.height()-y-1);
03345 for(x=0; x < img.width(); ++x)
03346 destData[img.width()-x-1] = srcData[x];
03347 }
03348 break;
03349 case Rotate270:
03350 dest.create(img.height(), img.width(), img.depth());
03351 for(y=0; y < img.height(); ++y){
03352 srcData = (unsigned int *)img.scanLine(y);
03353 for(x=0; x < img.width(); ++x){
03354 destData = (unsigned int *)dest.scanLine(img.width()-x-1);
03355 destData[y] = srcData[x];
03356 }
03357 }
03358 break;
03359 default:
03360 dest = img;
03361 break;
03362 }
03363 }
03364 else{
03365 unsigned char *srcData, *destData;
03366 unsigned int *srcTable, *destTable;
03367 switch(r){
03368 case Rotate90:
03369 dest.create(img.height(), img.width(), img.depth());
03370 dest.setNumColors(img.numColors());
03371 srcTable = (unsigned int *)img.colorTable();
03372 destTable = (unsigned int *)dest.colorTable();
03373 for(x=0; x < img.numColors(); ++x)
03374 destTable[x] = srcTable[x];
03375 for(y=0; y < img.height(); ++y){
03376 srcData = (unsigned char *)img.scanLine(y);
03377 for(x=0; x < img.width(); ++x){
03378 destData = (unsigned char *)dest.scanLine(x);
03379 destData[img.height()-y-1] = srcData[x];
03380 }
03381 }
03382 break;
03383 case Rotate180:
03384 dest.create(img.width(), img.height(), img.depth());
03385 dest.setNumColors(img.numColors());
03386 srcTable = (unsigned int *)img.colorTable();
03387 destTable = (unsigned int *)dest.colorTable();
03388 for(x=0; x < img.numColors(); ++x)
03389 destTable[x] = srcTable[x];
03390 for(y=0; y < img.height(); ++y){
03391 srcData = (unsigned char *)img.scanLine(y);
03392 destData = (unsigned char *)dest.scanLine(img.height()-y-1);
03393 for(x=0; x < img.width(); ++x)
03394 destData[img.width()-x-1] = srcData[x];
03395 }
03396 break;
03397 case Rotate270:
03398 dest.create(img.height(), img.width(), img.depth());
03399 dest.setNumColors(img.numColors());
03400 srcTable = (unsigned int *)img.colorTable();
03401 destTable = (unsigned int *)dest.colorTable();
03402 for(x=0; x < img.numColors(); ++x)
03403 destTable[x] = srcTable[x];
03404 for(y=0; y < img.height(); ++y){
03405 srcData = (unsigned char *)img.scanLine(y);
03406 for(x=0; x < img.width(); ++x){
03407 destData = (unsigned char *)dest.scanLine(img.width()-x-1);
03408 destData[y] = srcData[x];
03409 }
03410 }
03411 break;
03412 default:
03413 dest = img;
03414 break;
03415 }
03416
03417 }
03418 return(dest);
03419 }
03420
03421 void KImageEffect::solarize(QImage &img, double factor)
03422 {
03423 int i, count;
03424 int threshold;
03425 unsigned int *data;
03426
03427 threshold = (int)(factor*(MaxRGB+1)/100.0);
03428 if(img.depth() < 32){
03429 data = (unsigned int *)img.colorTable();
03430 count = img.numColors();
03431 }
03432 else{
03433 data = (unsigned int *)img.bits();
03434 count = img.width()*img.height();
03435 }
03436 for(i=0; i < count; ++i){
03437 data[i] = qRgba(qRed(data[i]) > threshold ? MaxRGB-qRed(data[i]) : qRed(data[i]),
03438 qGreen(data[i]) > threshold ? MaxRGB-qGreen(data[i]) : qGreen(data[i]),
03439 qBlue(data[i]) > threshold ? MaxRGB-qBlue(data[i]) : qBlue(data[i]),
03440 qAlpha(data[i]));
03441 }
03442 }
03443
03444 QImage KImageEffect::spread(QImage &src, unsigned int amount)
03445 {
03446 int quantum, x, y;
03447 int x_distance, y_distance;
03448 if(src.width() < 3 || src.height() < 3)
03449 return(src);
03450 QImage dest(src);
03451 dest.detach();
03452 quantum=(amount+1) >> 1;
03453 if(src.depth() > 8){
03454 unsigned int *p, *q;
03455 for(y=0; y < src.height(); y++){
03456 q = (unsigned int *)dest.scanLine(y);
03457 for(x=0; x < src.width(); x++){
03458 x_distance = x + ((rand() & (amount+1))-quantum);
03459 y_distance = y + ((rand() & (amount+1))-quantum);
03460 x_distance = QMIN(x_distance, src.width()-1);
03461 y_distance = QMIN(y_distance, src.height()-1);
03462 if(x_distance < 0)
03463 x_distance = 0;
03464 if(y_distance < 0)
03465 y_distance = 0;
03466 p = (unsigned int *)src.scanLine(y_distance);
03467 p += x_distance;
03468 *q++=(*p);
03469 }
03470 }
03471 }
03472 else{
03473
03474 unsigned char *p, *q;
03475 for(y=0; y < src.height(); y++){
03476 q = (unsigned char *)dest.scanLine(y);
03477 for(x=0; x < src.width(); x++){
03478 x_distance = x + ((rand() & (amount+1))-quantum);
03479 y_distance = y + ((rand() & (amount+1))-quantum);
03480 x_distance = QMIN(x_distance, src.width()-1);
03481 y_distance = QMIN(y_distance, src.height()-1);
03482 if(x_distance < 0)
03483 x_distance = 0;
03484 if(y_distance < 0)
03485 y_distance = 0;
03486 p = (unsigned char *)src.scanLine(y_distance);
03487 p += x_distance;
03488 *q++=(*p);
03489 }
03490 }
03491 }
03492 return(dest);
03493 }
03494
03495 QImage KImageEffect::swirl(QImage &src, double degrees,
03496 unsigned int background)
03497 {
03498 double cosine, distance, factor, radius, sine, x_center, x_distance,
03499 x_scale, y_center, y_distance, y_scale;
03500 int x, y;
03501 unsigned int *q;
03502 QImage dest(src.width(), src.height(), 32);
03503
03504
03505 x_center = src.width()/2.0;
03506 y_center = src.height()/2.0;
03507 radius = QMAX(x_center,y_center);
03508 x_scale=1.0;
03509 y_scale=1.0;
03510 if(src.width() > src.height())
03511 y_scale=(double)src.width()/src.height();
03512 else if(src.width() < src.height())
03513 x_scale=(double)src.height()/src.width();
03514 degrees=DegreesToRadians(degrees);
03515
03516 if(src.depth() > 8){
03517 unsigned int *p;
03518 for(y=0; y < src.height(); y++){
03519 p = (unsigned int *)src.scanLine(y);
03520 q = (unsigned int *)dest.scanLine(y);
03521 y_distance = y_scale*(y-y_center);
03522 for(x=0; x < src.width(); x++){
03523
03524 *q=(*p);
03525 x_distance = x_scale*(x-x_center);
03526 distance = x_distance*x_distance+y_distance*y_distance;
03527 if (distance < (radius*radius)){
03528
03529 factor = 1.0-sqrt(distance)/radius;
03530 sine = sin(degrees*factor*factor);
03531 cosine = cos(degrees*factor*factor);
03532 *q = interpolateColor(&src,
03533 (cosine*x_distance-sine*y_distance)/x_scale+x_center,
03534 (sine*x_distance+cosine*y_distance)/y_scale+y_center,
03535 background);
03536 }
03537 p++;
03538 q++;
03539 }
03540 }
03541 }
03542 else{
03543 unsigned char *p;
03544 unsigned int *cTable = (unsigned int *)src.colorTable();
03545 for(y=0; y < src.height(); y++){
03546 p = (unsigned char *)src.scanLine(y);
03547 q = (unsigned int *)dest.scanLine(y);
03548 y_distance = y_scale*(y-y_center);
03549 for(x=0; x < src.width(); x++){
03550
03551 *q = *(cTable+(*p));
03552 x_distance = x_scale*(x-x_center);
03553 distance = x_distance*x_distance+y_distance*y_distance;
03554 if (distance < (radius*radius)){
03555
03556 factor = 1.0-sqrt(distance)/radius;
03557 sine = sin(degrees*factor*factor);
03558 cosine = cos(degrees*factor*factor);
03559 *q = interpolateColor(&src,
03560 (cosine*x_distance-sine*y_distance)/x_scale+x_center,
03561 (sine*x_distance+cosine*y_distance)/y_scale+y_center,
03562 background);
03563 }
03564 p++;
03565 q++;
03566 }
03567 }
03568
03569 }
03570 return(dest);
03571 }
03572
03573 QImage KImageEffect::wave(QImage &src, double amplitude, double wavelength,
03574 unsigned int background)
03575 {
03576 double *sine_map;
03577 int x, y;
03578 unsigned int *q;
03579
03580 QImage dest(src.width(), src.height() + (int)(2*fabs(amplitude)), 32);
03581
03582 sine_map = (double *)malloc(dest.width()*sizeof(double));
03583 if(!sine_map)
03584 return(src);
03585 for(x=0; x < dest.width(); ++x)
03586 sine_map[x]=fabs(amplitude)+amplitude*sin((2*M_PI*x)/wavelength);
03587
03588 for(y=0; y < dest.height(); ++y){
03589 q = (unsigned int *)dest.scanLine(y);
03590 for (x=0; x < dest.width(); x++){
03591 *q=interpolateColor(&src, x, (int)(y-sine_map[x]), background);
03592 ++q;
03593 }
03594 }
03595 free(sine_map);
03596 return(dest);
03597 }
03598
03599
03600
03601
03602
03603
03604
03605
03606 QImage KImageEffect::oilPaint(QImage &src, int )
03607 {
03608
03609 return(oilPaintConvolve(src, 0));
03610 }
03611
03612 QImage KImageEffect::oilPaintConvolve(QImage &src, double radius)
03613 {
03614 unsigned long count ;
03615 unsigned long histogram[256];
03616 unsigned int k;
03617 int width;
03618 int x, y, mx, my, sx, sy;
03619 int mcx, mcy;
03620 unsigned int *s=0, *q;
03621
03622 if(src.depth() < 32)
03623 src.convertDepth(32);
03624 QImage dest(src);
03625 dest.detach();
03626
03627 width = getOptimalKernelWidth(radius, 0.5);
03628 if(src.width() < width){
03629 qWarning("KImageEffect::oilPaintConvolve(): Image is smaller than radius!");
03630 return(dest);
03631 }
03632
03633
03634
03635
03636
03637
03638
03639 unsigned int **jumpTable = (unsigned int **)src.jumpTable();
03640 for(y=0; y < dest.height(); ++y){
03641 sy = y-(width/2);
03642 q = (unsigned int *)dest.scanLine(y);
03643 for(x=0; x < dest.width(); ++x){
03644 count = 0;
03645 memset(histogram, 0, 256*sizeof(unsigned long));
03646
03647 sy = y-(width/2);
03648 for(mcy=0; mcy < width; ++mcy, ++sy){
03649 my = sy < 0 ? 0 : sy > src.height()-1 ?
03650 src.height()-1 : sy;
03651 sx = x+(-width/2);
03652 for(mcx=0; mcx < width; ++mcx, ++sx){
03653 mx = sx < 0 ? 0 : sx > src.width()-1 ?
03654 src.width()-1 : sx;
03655
03656 k = intensityValue(jumpTable[my][mx]);
03657 if(k > 255){
03658 qWarning("KImageEffect::oilPaintConvolve(): k is %d",
03659 k);
03660 k = 255;
03661 }
03662 histogram[k]++;
03663 if(histogram[k] > count){
03664 count = histogram[k];
03665 s = jumpTable[my]+mx;
03666 }
03667 }
03668 }
03669 *q++ = (*s);
03670 }
03671 }
03672
03673 return(dest);
03674 }
03675
03676 QImage KImageEffect::charcoal(QImage &src, double )
03677 {
03678
03679 return(charcoal(src, 0, 1));
03680 }
03681
03682 QImage KImageEffect::charcoal(QImage &src, double radius, double sigma)
03683 {
03684 QImage img(edge(src, radius));
03685 img = blur(img, radius, sigma);
03686 normalize(img);
03687 img.invertPixels(false);
03688 KImageEffect::toGray(img);
03689 return(img);
03690 }
03691
03692 void KImageEffect::normalize(QImage &image)
03693 {
03694 struct double_packet high, low, intensity, *histogram;
03695 struct short_packet *normalize_map;
03696 Q_INT64 number_pixels;
03697 int x, y;
03698 unsigned int *p, *q;
03699 register long i;
03700 unsigned long threshold_intensity;
03701 unsigned char r, g, b, a;
03702
03703 if(image.depth() < 32)
03704 image = image.convertDepth(32);
03705
03706 histogram = (struct double_packet *)
03707 malloc(256*sizeof(struct double_packet));
03708 normalize_map = (struct short_packet *)
03709 malloc(256*sizeof(struct short_packet));
03710
03711 if(!histogram || !normalize_map){
03712 if(histogram)
03713 liberateMemory(&histogram);
03714 if(normalize_map)
03715 liberateMemory(&normalize_map);
03716 qWarning("KImageEffect::normalize(): Unable to allocate memory!");
03717 return;
03718 }
03719
03720
03721
03722
03723 memset(histogram, 0, 256*sizeof(struct double_packet));
03724 for(y=0; y < image.height(); ++y){
03725 p = (unsigned int *)image.scanLine(y);
03726 for(x=0; x < image.width(); ++x){
03727 histogram[(unsigned char)(qRed(*p))].red++;
03728 histogram[(unsigned char)(qGreen(*p))].green++;
03729 histogram[(unsigned char)(qBlue(*p))].blue++;
03730 histogram[(unsigned char)(qAlpha(*p))].alpha++;
03731 p++;
03732 }
03733 }
03734
03735
03736
03737
03738 number_pixels = (Q_INT64)image.width()*image.height();
03739 threshold_intensity = number_pixels/1000;
03740
03741
03742 memset(&intensity, 0, sizeof(struct double_packet));
03743 memset(&high, 0, sizeof(struct double_packet));
03744 memset(&low, 0, sizeof(struct double_packet));
03745 for(high.red=255; high.red != 0; high.red--){
03746 intensity.red+=histogram[(unsigned char)high.red].red;
03747 if(intensity.red > threshold_intensity)
03748 break;
03749 }
03750 if(low.red == high.red){
03751 threshold_intensity = 0;
03752 memset(&intensity, 0, sizeof(struct double_packet));
03753 for(low.red=0; low.red < 255; low.red++){
03754 intensity.red+=histogram[(unsigned char)low.red].red;
03755 if(intensity.red > threshold_intensity)
03756 break;
03757 }
03758 memset(&intensity, 0, sizeof(struct double_packet));
03759 for(high.red=255; high.red != 0; high.red--){
03760 intensity.red+=histogram[(unsigned char)high.red].red;
03761 if(intensity.red > threshold_intensity)
03762 break;
03763 }
03764 }
03765
03766
03767 memset(&intensity, 0, sizeof(struct double_packet));
03768 for(high.green=255; high.green != 0; high.green--){
03769 intensity.green+=histogram[(unsigned char)high.green].green;
03770 if(intensity.green > threshold_intensity)
03771 break;
03772 }
03773 if(low.green == high.green){
03774 threshold_intensity = 0;
03775 memset(&intensity, 0, sizeof(struct double_packet));
03776 for(low.green=0; low.green < 255; low.green++){
03777 intensity.green+=histogram[(unsigned char)low.green].green;
03778 if(intensity.green > threshold_intensity)
03779 break;
03780 }
03781 memset(&intensity,0,sizeof(struct double_packet));
03782 for(high.green=255; high.green != 0; high.green--){
03783 intensity.green+=histogram[(unsigned char)high.green].green;
03784 if(intensity.green > threshold_intensity)
03785 break;
03786 }
03787 }
03788
03789
03790 memset(&intensity, 0, sizeof(struct double_packet));
03791 for(high.blue=255; high.blue != 0; high.blue--){
03792 intensity.blue+=histogram[(unsigned char)high.blue].blue;
03793 if(intensity.blue > threshold_intensity)
03794 break;
03795 }
03796 if(low.blue == high.blue){
03797 threshold_intensity = 0;
03798 memset(&intensity, 0, sizeof(struct double_packet));
03799 for(low.blue=0; low.blue < 255; low.blue++){
03800 intensity.blue+=histogram[(unsigned char)low.blue].blue;
03801 if(intensity.blue > threshold_intensity)
03802 break;
03803 }
03804 memset(&intensity,0,sizeof(struct double_packet));
03805 for(high.blue=255; high.blue != 0; high.blue--){
03806 intensity.blue+=histogram[(unsigned char)high.blue].blue;
03807 if(intensity.blue > threshold_intensity)
03808 break;
03809 }
03810 }
03811
03812
03813 memset(&intensity, 0, sizeof(struct double_packet));
03814 for(high.alpha=255; high.alpha != 0; high.alpha--){
03815 intensity.alpha+=histogram[(unsigned char)high.alpha].alpha;
03816 if(intensity.alpha > threshold_intensity)
03817 break;
03818 }
03819 if(low.alpha == high.alpha){
03820 threshold_intensity = 0;
03821 memset(&intensity, 0, sizeof(struct double_packet));
03822 for(low.alpha=0; low.alpha < 255; low.alpha++){
03823 intensity.alpha+=histogram[(unsigned char)low.alpha].alpha;
03824 if(intensity.alpha > threshold_intensity)
03825 break;
03826 }
03827 memset(&intensity,0,sizeof(struct double_packet));
03828 for(high.alpha=255; high.alpha != 0; high.alpha--){
03829 intensity.alpha+=histogram[(unsigned char)high.alpha].alpha;
03830 if(intensity.alpha > threshold_intensity)
03831 break;
03832 }
03833 }
03834 liberateMemory(&histogram);
03835
03836
03837
03838
03839
03840
03841 memset(normalize_map, 0 ,256*sizeof(struct short_packet));
03842 for(i=0; i <= (long) 255; i++){
03843 if(i < (long) low.red)
03844 normalize_map[i].red=0;
03845 else if (i > (long) high.red)
03846 normalize_map[i].red=65535;
03847 else if (low.red != high.red)
03848 normalize_map[i].red =
03849 (unsigned short)((65535*(i-low.red))/(high.red-low.red));
03850
03851 if(i < (long) low.green)
03852 normalize_map[i].green=0;
03853 else if (i > (long) high.green)
03854 normalize_map[i].green=65535;
03855 else if (low.green != high.green)
03856 normalize_map[i].green =
03857 (unsigned short)((65535*(i-low.green))/(high.green-low.green));
03858
03859 if(i < (long) low.blue)
03860 normalize_map[i].blue=0;
03861 else if (i > (long) high.blue)
03862 normalize_map[i].blue=65535;
03863 else if (low.blue != high.blue)
03864 normalize_map[i].blue =
03865 (unsigned short)((65535*(i-low.blue))/(high.blue-low.blue));
03866
03867 if(i < (long) low.alpha)
03868 normalize_map[i].alpha=0;
03869 else if (i > (long) high.alpha)
03870 normalize_map[i].alpha=65535;
03871 else if (low.alpha != high.alpha)
03872 normalize_map[i].alpha =
03873 (unsigned short)((65535*(i-low.alpha))/(high.alpha-low.alpha));
03874
03875 }
03876
03877 for(y=0; y < image.height(); ++y){
03878 q = (unsigned int *)image.scanLine(y);
03879 for(x=0; x < image.width(); ++x){
03880 if(low.red != high.red)
03881 r = (normalize_map[(unsigned short)(qRed(q[x]))].red)/257;
03882 else
03883 r = qRed(q[x]);
03884 if(low.green != high.green)
03885 g = (normalize_map[(unsigned short)(qGreen(q[x]))].green)/257;
03886 else
03887 g = qGreen(q[x]);
03888 if(low.blue != high.blue)
03889 b = (normalize_map[(unsigned short)(qBlue(q[x]))].blue)/257;
03890 else
03891 b = qBlue(q[x]);
03892 if(low.alpha != high.alpha)
03893 a = (normalize_map[(unsigned short)(qAlpha(q[x]))].alpha)/257;
03894 else
03895 a = qAlpha(q[x]);
03896 q[x] = qRgba(r, g, b, a);
03897 }
03898 }
03899 liberateMemory(&normalize_map);
03900 }
03901
03902 void KImageEffect::equalize(QImage &image)
03903 {
03904 struct double_packet high, low, intensity, *map, *histogram;
03905 struct short_packet *equalize_map;
03906 int x, y;
03907 unsigned int *p, *q;
03908 long i;
03909 unsigned char r, g, b, a;
03910
03911 if(image.depth() < 32)
03912 image = image.convertDepth(32);
03913
03914 histogram=(struct double_packet *) malloc(256*sizeof(struct double_packet));
03915 map=(struct double_packet *) malloc(256*sizeof(struct double_packet));
03916 equalize_map=(struct short_packet *)malloc(256*sizeof(struct short_packet));
03917 if(!histogram || !map || !equalize_map){
03918 if(histogram)
03919 liberateMemory(&histogram);
03920 if(map)
03921 liberateMemory(&map);
03922 if(equalize_map)
03923 liberateMemory(&equalize_map);
03924 qWarning("KImageEffect::equalize(): Unable to allocate memory!");
03925 return;
03926 }
03927
03928
03929
03930
03931 memset(histogram, 0, 256*sizeof(struct double_packet));
03932 for(y=0; y < image.height(); ++y){
03933 p = (unsigned int *)image.scanLine(y);
03934 for(x=0; x < image.width(); ++x){
03935 histogram[(unsigned char)(qRed(*p))].red++;
03936 histogram[(unsigned char)(qGreen(*p))].green++;
03937 histogram[(unsigned char)(qBlue(*p))].blue++;
03938 histogram[(unsigned char)(qAlpha(*p))].alpha++;
03939 p++;
03940 }
03941 }
03942
03943
03944
03945 memset(&intensity, 0 ,sizeof(struct double_packet));
03946 for(i=0; i <= 255; ++i){
03947 intensity.red += histogram[i].red;
03948 intensity.green += histogram[i].green;
03949 intensity.blue += histogram[i].blue;
03950 intensity.alpha += histogram[i].alpha;
03951 map[i]=intensity;
03952 }
03953 low=map[0];
03954 high=map[255];
03955 memset(equalize_map, 0, 256*sizeof(short_packet));
03956 for(i=0; i <= 255; ++i){
03957 if(high.red != low.red)
03958 equalize_map[i].red=(unsigned short)
03959 ((65535*(map[i].red-low.red))/(high.red-low.red));
03960 if(high.green != low.green)
03961 equalize_map[i].green=(unsigned short)
03962 ((65535*(map[i].green-low.green))/(high.green-low.green));
03963 if(high.blue != low.blue)
03964 equalize_map[i].blue=(unsigned short)
03965 ((65535*(map[i].blue-low.blue))/(high.blue-low.blue));
03966 if(high.alpha != low.alpha)
03967 equalize_map[i].alpha=(unsigned short)
03968 ((65535*(map[i].alpha-low.alpha))/(high.alpha-low.alpha));
03969 }
03970 liberateMemory(&histogram);
03971 liberateMemory(&map);
03972
03973
03974
03975
03976 for(y=0; y < image.height(); ++y){
03977 q = (unsigned int *)image.scanLine(y);
03978 for(x=0; x < image.width(); ++x){
03979 if(low.red != high.red)
03980 r = (equalize_map[(unsigned short)(qRed(q[x]))].red/257);
03981 else
03982 r = qRed(q[x]);
03983 if(low.green != high.green)
03984 g = (equalize_map[(unsigned short)(qGreen(q[x]))].green/257);
03985 else
03986 g = qGreen(q[x]);
03987 if(low.blue != high.blue)
03988 b = (equalize_map[(unsigned short)(qBlue(q[x]))].blue/257);
03989 else
03990 b = qBlue(q[x]);
03991 if(low.alpha != high.alpha)
03992 a = (equalize_map[(unsigned short)(qAlpha(q[x]))].alpha/257);
03993 else
03994 a = qAlpha(q[x]);
03995 q[x] = qRgba(r, g, b, a);
03996 }
03997 }
03998 liberateMemory(&equalize_map);
03999
04000 }
04001
04002 QImage KImageEffect::edge(QImage &image, double radius)
04003 {
04004 double *kernel;
04005 int width;
04006 register long i;
04007 QImage dest;
04008
04009 if(radius == 50.0){
04010
04011
04012
04013 radius = 0.0;
04014 }
04015
04016 width = getOptimalKernelWidth(radius, 0.5);
04017 if(image.width() < width || image.height() < width){
04018 qWarning("KImageEffect::edge(): Image is smaller than radius!");
04019 return(dest);
04020 }
04021 kernel= (double *)malloc(width*width*sizeof(double));
04022 if(!kernel){
04023 qWarning("KImageEffect::edge(): Unable to allocate memory!");
04024 return(dest);
04025 }
04026 for(i=0; i < (width*width); i++)
04027 kernel[i]=(-1.0);
04028 kernel[i/2]=width*width-1.0;
04029 convolveImage(&image, &dest, width, kernel);
04030 free(kernel);
04031 return(dest);
04032 }
04033
04034 QImage KImageEffect::emboss(QImage &src)
04035 {
04036
04037 return(emboss(src, 0, 1));
04038 }
04039
04040 QImage KImageEffect::emboss(QImage &image, double radius, double sigma)
04041 {
04042 double alpha, *kernel;
04043 int j, width;
04044 register long i, u, v;
04045 QImage dest;
04046
04047 if(sigma == 0.0){
04048 qWarning("KImageEffect::emboss(): Zero sigma is not permitted!");
04049 return(dest);
04050 }
04051
04052 width = getOptimalKernelWidth(radius, sigma);
04053 if(image.width() < width || image.height() < width){
04054 qWarning("KImageEffect::emboss(): Image is smaller than radius!");
04055 return(dest);
04056 }
04057 kernel= (double *)malloc(width*width*sizeof(double));
04058 if(!kernel){
04059 qWarning("KImageEffect::emboss(): Unable to allocate memory!");
04060 return(dest);
04061 }
04062 if(image.depth() < 32)
04063 image = image.convertDepth(32);
04064
04065 i=0;
04066 j=width/2;
04067 for(v=(-width/2); v <= (width/2); v++){
04068 for(u=(-width/2); u <= (width/2); u++){
04069 alpha=exp(-((double) u*u+v*v)/(2.0*sigma*sigma));
04070 kernel[i]=((u < 0) || (v < 0) ? -8.0 : 8.0)*alpha/
04071 (2.0*MagickPI*sigma*sigma);
04072 if (u == j)
04073 kernel[i]=0.0;
04074 i++;
04075 }
04076 j--;
04077 }
04078 convolveImage(&image, &dest, width, kernel);
04079 liberateMemory(&kernel);
04080
04081 equalize(dest);
04082 return(dest);
04083 }
04084
04085 void KImageEffect::blurScanLine(double *kernel, int width,
04086 unsigned int *src, unsigned int *dest,
04087 int columns)
04088 {
04089 register double *p;
04090 unsigned int *q;
04091 register int x;
04092 register long i;
04093 double red, green, blue, alpha;
04094 double scale = 0.0;
04095
04096 if(width > columns){
04097 for(x=0; x < columns; ++x){
04098 scale = 0.0;
04099 red = blue = green = alpha = 0.0;
04100 p = kernel;
04101 q = src;
04102 for(i=0; i < columns; ++i){
04103 if((i >= (x-width/2)) && (i <= (x+width/2))){
04104 red += (*p)*(qRed(*q)*257);
04105 green += (*p)*(qGreen(*q)*257);
04106 blue += (*p)*(qBlue(*q)*257);
04107 alpha += (*p)*(qAlpha(*q)*257);
04108 }
04109 if(((i+width/2-x) >= 0) && ((i+width/2-x) < width))
04110 scale+=kernel[i+width/2-x];
04111 p++;
04112 q++;
04113 }
04114 scale = 1.0/scale;
04115 red = scale*(red+0.5);
04116 green = scale*(green+0.5);
04117 blue = scale*(blue+0.5);
04118 alpha = scale*(alpha+0.5);
04119
04120 red = red < 0 ? 0 : red > 65535 ? 65535 : red;
04121 green = green < 0 ? 0 : green > 65535 ? 65535 : green;
04122 blue = blue < 0 ? 0 : blue > 65535 ? 65535 : blue;
04123 alpha = alpha < 0 ? 0 : alpha > 65535 ? 65535 : alpha;
04124
04125 dest[x] = qRgba((unsigned char)(red/257UL),
04126 (unsigned char)(green/257UL),
04127 (unsigned char)(blue/257UL),
04128 (unsigned char)(alpha/257UL));
04129 }
04130 return;
04131 }
04132
04133 for(x=0; x < width/2; ++x){
04134 scale = 0.0;
04135 red = blue = green = alpha = 0.0;
04136 p = kernel+width/2-x;
04137 q = src;
04138 for(i=width/2-x; i < width; ++i){
04139 red += (*p)*(qRed(*q)*257);
04140 green += (*p)*(qGreen(*q)*257);
04141 blue += (*p)*(qBlue(*q)*257);
04142 alpha += (*p)*(qAlpha(*q)*257);
04143 scale += (*p);
04144 p++;
04145 q++;
04146 }
04147 scale=1.0/scale;
04148
04149 red = scale*(red+0.5);
04150 green = scale*(green+0.5);
04151 blue = scale*(blue+0.5);
04152 alpha = scale*(alpha+0.5);
04153
04154 red = red < 0 ? 0 : red > 65535 ? 65535 : red;
04155 green = green < 0 ? 0 : green > 65535 ? 65535 : green;
04156 blue = blue < 0 ? 0 : blue > 65535 ? 65535 : blue;
04157 alpha = alpha < 0 ? 0 : alpha > 65535 ? 65535 : alpha;
04158
04159 dest[x] = qRgba((unsigned char)(red/257UL),
04160 (unsigned char)(green/257UL),
04161 (unsigned char)(blue/257UL),
04162 (unsigned char)(alpha/257UL));
04163 }
04164
04165 for(; x < columns-width/2; ++x){
04166 red = blue = green = alpha = 0.0;
04167 p = kernel;
04168 q = src+(x-width/2);
04169 for (i=0; i < (long) width; ++i){
04170 red += (*p)*(qRed(*q)*257);
04171 green += (*p)*(qGreen(*q)*257);
04172 blue += (*p)*(qBlue(*q)*257);
04173 alpha += (*p)*(qAlpha(*q)*257);
04174 p++;
04175 q++;
04176 }
04177 red = scale*(red+0.5);
04178 green = scale*(green+0.5);
04179 blue = scale*(blue+0.5);
04180 alpha = scale*(alpha+0.5);
04181
04182 red = red < 0 ? 0 : red > 65535 ? 65535 : red;
04183 green = green < 0 ? 0 : green > 65535 ? 65535 : green;
04184 blue = blue < 0 ? 0 : blue > 65535 ? 65535 : blue;
04185 alpha = alpha < 0 ? 0 : alpha > 65535 ? 65535 : alpha;
04186
04187 dest[x] = qRgba((unsigned char)(red/257UL),
04188 (unsigned char)(green/257UL),
04189 (unsigned char)(blue/257UL),
04190 (unsigned char)(alpha/257UL));
04191 }
04192
04193 for(; x < columns; ++x){
04194 red = blue = green = alpha = 0.0;
04195 scale=0;
04196 p = kernel;
04197 q = src+(x-width/2);
04198 for(i=0; i < columns-x+width/2; ++i){
04199 red += (*p)*(qRed(*q)*257);
04200 green += (*p)*(qGreen(*q)*257);
04201 blue += (*p)*(qBlue(*q)*257);
04202 alpha += (*p)*(qAlpha(*q)*257);
04203 scale += (*p);
04204 p++;
04205 q++;
04206 }
04207 scale=1.0/scale;
04208 red = scale*(red+0.5);
04209 green = scale*(green+0.5);
04210 blue = scale*(blue+0.5);
04211 alpha = scale*(alpha+0.5);
04212
04213 red = red < 0 ? 0 : red > 65535 ? 65535 : red;
04214 green = green < 0 ? 0 : green > 65535 ? 65535 : green;
04215 blue = blue < 0 ? 0 : blue > 65535 ? 65535 : blue;
04216 alpha = alpha < 0 ? 0 : alpha > 65535 ? 65535 : alpha;
04217
04218 dest[x] = qRgba((unsigned char)(red/257UL),
04219 (unsigned char)(green/257UL),
04220 (unsigned char)(blue/257UL),
04221 (unsigned char)(alpha/257UL));
04222 }
04223 }
04224
04225 int KImageEffect::getBlurKernel(int width, double sigma, double **kernel)
04226 {
04227 #define KernelRank 3
04228 double alpha, normalize;
04229 register long i;
04230 int bias;
04231
04232 assert(sigma != 0.0);
04233 if(width == 0)
04234 width = 3;
04235 *kernel=(double *)malloc(width*sizeof(double));
04236 if(*kernel == (double *)NULL)
04237 return(0);
04238 memset(*kernel, 0, width*sizeof(double));
04239 bias = KernelRank*width/2;
04240 for(i=(-bias); i <= bias; i++){
04241 alpha=exp(-((double) i*i)/(2.0*KernelRank*KernelRank*sigma*sigma));
04242 (*kernel)[(i+bias)/KernelRank]+=alpha/(MagickSQ2PI*sigma);
04243 }
04244 normalize=0;
04245 for(i=0; i < width; i++)
04246 normalize+=(*kernel)[i];
04247 for(i=0; i < width; i++)
04248 (*kernel)[i]/=normalize;
04249
04250 return(width);
04251 }
04252
04253 QImage KImageEffect::blur(QImage &src, double )
04254 {
04255
04256 return(blur(src, 0, 1));
04257 }
04258
04259 QImage KImageEffect::blur(QImage &src, double radius, double sigma)
04260 {
04261 double *kernel;
04262 QImage dest;
04263 int width;
04264 int x, y;
04265 unsigned int *scanline, *temp;
04266 unsigned int *p, *q;
04267
04268 if(sigma == 0.0){
04269 qWarning("KImageEffect::blur(): Zero sigma is not permitted!");
04270 return(dest);
04271 }
04272 if(src.depth() < 32)
04273 src = src.convertDepth(32);
04274
04275 kernel=(double *) NULL;
04276 if(radius > 0)
04277 width=getBlurKernel((int) (2*ceil(radius)+1),sigma,&kernel);
04278 else{
04279 double *last_kernel;
04280 last_kernel=(double *) NULL;
04281 width=getBlurKernel(3,sigma,&kernel);
04282
04283 while ((long) (MaxRGB*kernel[0]) > 0){
04284 if(last_kernel != (double *)NULL){
04285 liberateMemory(&last_kernel);
04286 }
04287 last_kernel=kernel;
04288 kernel = (double *)NULL;
04289 width = getBlurKernel(width+2, sigma, &kernel);
04290 }
04291 if(last_kernel != (double *) NULL){
04292 liberateMemory(&kernel);
04293 width-=2;
04294 kernel = last_kernel;
04295 }
04296 }
04297
04298 if(width < 3){
04299 qWarning("KImageEffect::blur(): Kernel radius is too small!");
04300 liberateMemory(&kernel);
04301 return(dest);
04302 }
04303
04304 dest.create(src.width(), src.height(), 32);
04305
04306 scanline = (unsigned int *)malloc(sizeof(unsigned int)*src.height());
04307 temp = (unsigned int *)malloc(sizeof(unsigned int)*src.height());
04308 for(y=0; y < src.height(); ++y){
04309 p = (unsigned int *)src.scanLine(y);
04310 q = (unsigned int *)dest.scanLine(y);
04311 blurScanLine(kernel, width, p, q, src.width());
04312 }
04313
04314 unsigned int **srcTable = (unsigned int **)src.jumpTable();
04315 unsigned int **destTable = (unsigned int **)dest.jumpTable();
04316 for(x=0; x < src.width(); ++x){
04317 for(y=0; y < src.height(); ++y){
04318 scanline[y] = srcTable[y][x];
04319 }
04320 blurScanLine(kernel, width, scanline, temp, src.height());
04321 for(y=0; y < src.height(); ++y){
04322 destTable[y][x] = temp[y];
04323 }
04324 }
04325 free(scanline);
04326 free(temp);
04327 free(kernel);
04328 return(dest);
04329 }
04330
04331 bool KImageEffect::convolveImage(QImage *image, QImage *dest,
04332 const unsigned int order,
04333 const double *kernel)
04334 {
04335 long width;
04336 double red, green, blue, alpha;
04337 double normalize, *normal_kernel;
04338 register const double *k;
04339 register unsigned int *q;
04340 int x, y, mx, my, sx, sy;
04341 long i;
04342 int mcx, mcy;
04343
04344 width = order;
04345 if((width % 2) == 0){
04346 qWarning("KImageEffect: Kernel width must be an odd number!");
04347 return(false);
04348 }
04349 normal_kernel = (double *)malloc(width*width*sizeof(double));
04350 if(!normal_kernel){
04351 qWarning("KImageEffect: Unable to allocate memory!");
04352 return(false);
04353 }
04354 dest->reset();
04355 dest->create(image->width(), image->height(), 32);
04356 if(image->depth() < 32)
04357 *image = image->convertDepth(32);
04358
04359 normalize=0.0;
04360 for(i=0; i < (width*width); i++)
04361 normalize += kernel[i];
04362 if(fabs(normalize) <= MagickEpsilon)
04363 normalize=1.0;
04364 normalize=1.0/normalize;
04365 for(i=0; i < (width*width); i++)
04366 normal_kernel[i] = normalize*kernel[i];
04367
04368 unsigned int **jumpTable = (unsigned int **)image->jumpTable();
04369 for(y=0; y < dest->height(); ++y){
04370 sy = y-(width/2);
04371 q = (unsigned int *)dest->scanLine(y);
04372 for(x=0; x < dest->width(); ++x){
04373 k = normal_kernel;
04374 red = green = blue = alpha = 0;
04375 sy = y-(width/2);
04376 for(mcy=0; mcy < width; ++mcy, ++sy){
04377 my = sy < 0 ? 0 : sy > image->height()-1 ?
04378 image->height()-1 : sy;
04379 sx = x+(-width/2);
04380 for(mcx=0; mcx < width; ++mcx, ++sx){
04381 mx = sx < 0 ? 0 : sx > image->width()-1 ?
04382 image->width()-1 : sx;
04383 red += (*k)*(qRed(jumpTable[my][mx])*257);
04384 green += (*k)*(qGreen(jumpTable[my][mx])*257);
04385 blue += (*k)*(qBlue(jumpTable[my][mx])*257);
04386 alpha += (*k)*(qAlpha(jumpTable[my][mx])*257);
04387 ++k;
04388 }
04389 }
04390
04391 red = red < 0 ? 0 : red > 65535 ? 65535 : red+0.5;
04392 green = green < 0 ? 0 : green > 65535 ? 65535 : green+0.5;
04393 blue = blue < 0 ? 0 : blue > 65535 ? 65535 : blue+0.5;
04394 alpha = alpha < 0 ? 0 : alpha > 65535 ? 65535 : alpha+0.5;
04395
04396 *q++ = qRgba((unsigned char)(red/257UL),
04397 (unsigned char)(green/257UL),
04398 (unsigned char)(blue/257UL),
04399 (unsigned char)(alpha/257UL));
04400 }
04401 }
04402 free(normal_kernel);
04403 return(true);
04404
04405 }
04406
04407 int KImageEffect::getOptimalKernelWidth(double radius, double sigma)
04408 {
04409 double normalize, value;
04410 long width;
04411 register long u;
04412
04413 assert(sigma != 0.0);
04414 if(radius > 0.0)
04415 return((int)(2.0*ceil(radius)+1.0));
04416 for(width=5; ;){
04417 normalize=0.0;
04418 for(u=(-width/2); u <= (width/2); u++)
04419 normalize+=exp(-((double) u*u)/(2.0*sigma*sigma))/(MagickSQ2PI*sigma);
04420 u=width/2;
04421 value=exp(-((double) u*u)/(2.0*sigma*sigma))/(MagickSQ2PI*sigma)/normalize;
04422 if((long)(65535*value) <= 0)
04423 break;
04424 width+=2;
04425 }
04426 return((int)width-2);
04427 }
04428
04429 QImage KImageEffect::sharpen(QImage &src, double )
04430 {
04431
04432 return(sharpen(src, 0, 1));
04433 }
04434
04435 QImage KImageEffect::sharpen(QImage &image, double radius, double sigma)
04436 {
04437 double alpha, normalize, *kernel;
04438 int width;
04439 register long i, u, v;
04440 QImage dest;
04441
04442 if(sigma == 0.0){
04443 qWarning("KImageEffect::sharpen(): Zero sigma is not permitted!");
04444 return(dest);
04445 }
04446 width = getOptimalKernelWidth(radius, sigma);
04447 if(image.width() < width){
04448 qWarning("KImageEffect::sharpen(): Image is smaller than radius!");
04449 return(dest);
04450 }
04451 kernel = (double *)malloc(width*width*sizeof(double));
04452 if(!kernel){
04453 qWarning("KImageEffect::sharpen(): Unable to allocate memory!");
04454 return(dest);
04455 }
04456
04457 i = 0;
04458 normalize=0.0;
04459 for(v=(-width/2); v <= (width/2); v++){
04460 for(u=(-width/2); u <= (width/2); u++){
04461 alpha=exp(-((double) u*u+v*v)/(2.0*sigma*sigma));
04462 kernel[i]=alpha/(2.0*MagickPI*sigma*sigma);
04463 normalize+=kernel[i];
04464 i++;
04465 }
04466 }
04467 kernel[i/2]=(-2.0)*normalize;
04468 convolveImage(&image, &dest, width, kernel);
04469 free(kernel);
04470 return(dest);
04471 }
04472
04473
04474
04475 QImage KImageEffect::shade(QImage &src, bool color_shading, double azimuth,
04476 double elevation)
04477 {
04478 struct PointInfo{
04479 double x, y, z;
04480 };
04481
04482 double distance, normal_distance, shade;
04483 int x, y;
04484
04485 struct PointInfo light, normal;
04486
04487 unsigned int *q;
04488
04489 QImage dest(src.width(), src.height(), 32);
04490
04491 azimuth = DegreesToRadians(azimuth);
04492 elevation = DegreesToRadians(elevation);
04493 light.x = MaxRGB*cos(azimuth)*cos(elevation);
04494 light.y = MaxRGB*sin(azimuth)*cos(elevation);
04495 light.z = MaxRGB*sin(elevation);
04496 normal.z= 2*MaxRGB;
04497
04498 if(src.depth() > 8){
04499 unsigned int *p, *s0, *s1, *s2;
04500 for(y=0; y < src.height(); ++y){
04501 p = (unsigned int *)src.scanLine(QMIN(QMAX(y-1,0),src.height()-3));
04502 q = (unsigned int *)dest.scanLine(y);
04503
04504 *q++=(*(p+src.width()));
04505 p++;
04506 s0 = p;
04507 s1 = p + src.width();
04508 s2 = p + 2*src.width();
04509 for(x=1; x < src.width()-1; ++x){
04510
04511 normal.x=intensityValue(*(s0-1))+intensityValue(*(s1-1))+intensityValue(*(s2-1))-
04512 (double) intensityValue(*(s0+1))-(double) intensityValue(*(s1+1))-
04513 (double) intensityValue(*(s2+1));
04514 normal.y=intensityValue(*(s2-1))+intensityValue(*s2)+intensityValue(*(s2+1))-
04515 (double) intensityValue(*(s0-1))-(double) intensityValue(*s0)-
04516 (double) intensityValue(*(s0+1));
04517 if((normal.x == 0) && (normal.y == 0))
04518 shade=light.z;
04519 else{
04520 shade=0.0;
04521 distance=normal.x*light.x+normal.y*light.y+normal.z*light.z;
04522 if (distance > 0.0){
04523 normal_distance=
04524 normal.x*normal.x+normal.y*normal.y+normal.z*normal.z;
04525 if(fabs(normal_distance) > 0.0000001)
04526 shade=distance/sqrt(normal_distance);
04527 }
04528 }
04529 if(!color_shading){
04530 *q = qRgba((unsigned char)(shade),
04531 (unsigned char)(shade),
04532 (unsigned char)(shade),
04533 qAlpha(*s1));
04534 }
04535 else{
04536 *q = qRgba((unsigned char)((shade*qRed(*s1))/(MaxRGB+1)),
04537 (unsigned char)((shade*qGreen(*s1))/(MaxRGB+1)),
04538 (unsigned char)((shade*qBlue(*s1))/(MaxRGB+1)),
04539 qAlpha(*s1));
04540 }
04541 ++s0;
04542 ++s1;
04543 ++s2;
04544 q++;
04545 }
04546 *q++=(*s1);
04547 }
04548 }
04549 else{
04550 unsigned char *p, *s0, *s1, *s2;
04551 int scanLineIdx;
04552 unsigned int *cTable = (unsigned int *)src.colorTable();
04553 for(y=0; y < src.height(); ++y){
04554 scanLineIdx = QMIN(QMAX(y-1,0),src.height()-3);
04555 p = (unsigned char *)src.scanLine(scanLineIdx);
04556 q = (unsigned int *)dest.scanLine(y);
04557
04558 s0 = p;
04559 s1 = (unsigned char *) src.scanLine(scanLineIdx+1);
04560 s2 = (unsigned char *) src.scanLine(scanLineIdx+2);
04561 *q++=(*(cTable+(*s1)));
04562 ++p;
04563 ++s0;
04564 ++s1;
04565 ++s2;
04566 for(x=1; x < src.width()-1; ++x){
04567
04568 normal.x=intensityValue(*(cTable+(*(s0-1))))+intensityValue(*(cTable+(*(s1-1))))+intensityValue(*(cTable+(*(s2-1))))-
04569 (double) intensityValue(*(cTable+(*(s0+1))))-(double) intensityValue(*(cTable+(*(s1+1))))-
04570 (double) intensityValue(*(cTable+(*(s2+1))));
04571 normal.y=intensityValue(*(cTable+(*(s2-1))))+intensityValue(*(cTable+(*s2)))+intensityValue(*(cTable+(*(s2+1))))-
04572 (double) intensityValue(*(cTable+(*(s0-1))))-(double) intensityValue(*(cTable+(*s0)))-
04573 (double) intensityValue(*(cTable+(*(s0+1))));
04574 if((normal.x == 0) && (normal.y == 0))
04575 shade=light.z;
04576 else{
04577 shade=0.0;
04578 distance=normal.x*light.x+normal.y*light.y+normal.z*light.z;
04579 if (distance > 0.0){
04580 normal_distance=
04581 normal.x*normal.x+normal.y*normal.y+normal.z*normal.z;
04582 if(fabs(normal_distance) > 0.0000001)
04583 shade=distance/sqrt(normal_distance);
04584 }
04585 }
04586 if(!color_shading){
04587 *q = qRgba((unsigned char)(shade),
04588 (unsigned char)(shade),
04589 (unsigned char)(shade),
04590 qAlpha(*(cTable+(*s1))));
04591 }
04592 else{
04593 *q = qRgba((unsigned char)((shade*qRed(*(cTable+(*s1))))/(MaxRGB+1)),
04594 (unsigned char)((shade*qGreen(*(cTable+(*s1))))/(MaxRGB+1)),
04595 (unsigned char)((shade*qBlue(*(cTable+(*s1))))/(MaxRGB+1)),
04596 qAlpha(*s1));
04597 }
04598 ++s0;
04599 ++s1;
04600 ++s2;
04601 q++;
04602 }
04603 *q++=(*(cTable+(*s1)));
04604 }
04605 }
04606 return(dest);
04607 }
04608
04609
04610
04611
04612
04613 void KImageEffect::contrastHSV(QImage &img, bool sharpen)
04614 {
04615 int i, sign;
04616 unsigned int *data;
04617 int count;
04618 double brightness, scale, theta;
04619 QColor c;
04620 int h, s, v;
04621
04622 sign = sharpen ? 1 : -1;
04623 scale=0.5000000000000001;
04624 if(img.depth() > 8){
04625 count = img.width()*img.height();
04626 data = (unsigned int *)img.bits();
04627 }
04628 else{
04629 count = img.numColors();
04630 data = (unsigned int *)img.colorTable();
04631 }
04632 for(i=0; i < count; ++i){
04633 c.setRgb(data[i]);
04634 c.hsv(&h, &s, &v);
04635 brightness = v/255.0;
04636 theta=(brightness-0.5)*M_PI;
04637 brightness+=scale*(((scale*((sin(theta)+1.0)))-brightness)*sign);
04638 if (brightness > 1.0)
04639 brightness=1.0;
04640 else
04641 if (brightness < 0)
04642 brightness=0.0;
04643 v = (int)(brightness*255);
04644 c.setHsv(h, s, v);
04645 data[i] = qRgba(c.red(), c.green(), c.blue(), qAlpha(data[i]));
04646 }
04647 }
04648
04649
04650 struct BumpmapParams {
04651 BumpmapParams( double bm_azimuth, double bm_elevation,
04652 int bm_depth, KImageEffect::BumpmapType bm_type,
04653 bool invert ) {
04654
04655 double azimuth = DegreesToRadians( bm_azimuth );
04656 double elevation = DegreesToRadians( bm_elevation );
04657
04658
04659 lx = (int)( cos(azimuth) * cos(elevation) * 255.0 );
04660 ly = (int)( sin(azimuth) * cos(elevation) * 255.0 );
04661 int lz = (int)( sin(elevation) * 255.0 );
04662
04663
04664 int nz = (6 * 255) / bm_depth;
04665 nz2 = nz * nz;
04666 nzlz = nz * lz;
04667
04668
04669 background = lz;
04670
04671
04672 compensation = sin(elevation);
04673
04674
04675 for (int i = 0; i < 256; i++)
04676 {
04677 double n = 0;
04678 switch (bm_type)
04679 {
04680 case KImageEffect::Spherical:
04681 n = i / 255.0 - 1.0;
04682 lut[i] = (int) (255.0 * sqrt(1.0 - n * n) + 0.5);
04683 break;
04684
04685 case KImageEffect::Sinuosidal:
04686 n = i / 255.0;
04687 lut[i] = (int) (255.0 * (sin((-M_PI / 2.0) + M_PI * n) + 1.0) /
04688 2.0 + 0.5);
04689 break;
04690
04691 case KImageEffect::Linear:
04692 default:
04693 lut[i] = i;
04694 }
04695
04696 if (invert)
04697 lut[i] = 255 - lut[i];
04698 }
04699 }
04700 int lx, ly;
04701 int nz2, nzlz;
04702 int background;
04703 double compensation;
04704 uchar lut[256];
04705 };
04706
04707
04708 static void bumpmap_convert_row( uint *row,
04709 int width,
04710 int bpp,
04711 int has_alpha,
04712 uchar *lut,
04713 int waterlevel )
04714 {
04715 uint *p;
04716
04717 p = row;
04718
04719 has_alpha = has_alpha ? 1 : 0;
04720
04721 if (bpp >= 3)
04722 for (; width; width--)
04723 {
04724 if (has_alpha) {
04725 unsigned int idx = (unsigned int)(intensityValue( *row ) + 0.5);
04726 *p++ = lut[(unsigned int) ( waterlevel +
04727 ( ( idx -
04728 waterlevel) * qBlue( *row )) / 255.0 )];
04729 } else {
04730 unsigned int idx = (unsigned int)(intensityValue( *row ) + 0.5);
04731 *p++ = lut[idx];
04732 }
04733
04734 ++row;
04735 }
04736 }
04737
04738 static void bumpmap_row( uint *src,
04739 uint *dest,
04740 int width,
04741 int bpp,
04742 int has_alpha,
04743 uint *bm_row1,
04744 uint *bm_row2,
04745 uint *bm_row3,
04746 int bm_width,
04747 int bm_xofs,
04748 bool tiled,
04749 bool row_in_bumpmap,
04750 int ambient,
04751 bool compensate,
04752 BumpmapParams *params )
04753 {
04754 int xofs1, xofs2, xofs3;
04755 int shade;
04756 int ndotl;
04757 int nx, ny;
04758 int x;
04759 int tmp;
04760
04761 tmp = bm_xofs;
04762 xofs2 = MOD(tmp, bm_width);
04763
04764 for (x = 0; x < width; x++)
04765 {
04766
04767
04768 if (tiled || (row_in_bumpmap &&
04769 x >= - tmp && x < - tmp + bm_width)) {
04770 if (tiled) {
04771 xofs1 = MOD(xofs2 - 1, bm_width);
04772 xofs3 = MOD(xofs2 + 1, bm_width);
04773 } else {
04774 xofs1 = FXCLAMP(xofs2 - 1, 0, bm_width - 1);
04775 xofs3 = FXCLAMP(xofs2 + 1, 0, bm_width - 1);
04776 }
04777 nx = (bm_row1[xofs1] + bm_row2[xofs1] + bm_row3[xofs1] -
04778 bm_row1[xofs3] - bm_row2[xofs3] - bm_row3[xofs3]);
04779 ny = (bm_row3[xofs1] + bm_row3[xofs2] + bm_row3[xofs3] -
04780 bm_row1[xofs1] - bm_row1[xofs2] - bm_row1[xofs3]);
04781 } else {
04782 nx = ny = 0;
04783 }
04784
04785
04786
04787 if ((nx == 0) && (ny == 0))
04788 shade = params->background;
04789 else {
04790 ndotl = nx * params->lx + ny * params->ly + params->nzlz;
04791
04792 if (ndotl < 0)
04793 shade = (int)( params->compensation * ambient );
04794 else {
04795 shade = (int)( ndotl / sqrt(double(nx * nx + ny * ny + params->nz2)) );
04796
04797 shade = (int)( shade + QMAX(0.0, (255 * params->compensation - shade)) *
04798 ambient / 255 );
04799 }
04800 }
04801
04802
04803
04808 if (compensate) {
04809 int red = (int)((qRed( *src ) * shade) / (params->compensation * 255));
04810 int green = (int)((qGreen( *src ) * shade) / (params->compensation * 255));
04811 int blue = (int)((qBlue( *src ) * shade) / (params->compensation * 255));
04812 int alpha = (int)((qAlpha( *src ) * shade) / (params->compensation * 255));
04813 ++src;
04814 *dest++ = qRgba( red, green, blue, alpha );
04815 } else {
04816 int red = qRed( *src ) * shade / 255;
04817 int green = qGreen( *src ) * shade / 255;
04818 int blue = qBlue( *src ) * shade / 255;
04819 int alpha = qAlpha( *src ) * shade / 255;
04820 ++src;
04821 *dest++ = qRgba( red, green, blue, alpha );
04822 }
04823
04824
04825
04826 if (++xofs2 == bm_width)
04827 xofs2 = 0;
04828 }
04829 }
04830
04850 QImage KImageEffect::bumpmap(QImage &img, QImage &map, double azimuth, double elevation,
04851 int depth, int xofs, int yofs, int waterlevel,
04852 int ambient, bool compensate, bool invert,
04853 BumpmapType type, bool tiled)
04854 {
04855 QImage dst;
04856
04857 if ( img.depth() != 32 || img.depth() != 32 ) {
04858 qWarning( "Bump-mapping effect works only with 32 bit images");
04859 return dst;
04860 }
04861
04862 dst.create( img.width(), img.height(), img.depth() );
04863 int bm_width = map.width();
04864 int bm_height = map.height();
04865 int bm_bpp = map.depth();
04866 int bm_has_alpha = map.hasAlphaBuffer();
04867
04868 int yofs1, yofs2, yofs3;
04869
04870 if ( tiled ) {
04871 yofs2 = MOD( yofs, bm_height );
04872 yofs1 = MOD( yofs2 - 1, bm_height);
04873 yofs3 = MOD( yofs2 + 1, bm_height);
04874 } else {
04875 yofs1 = 0;
04876 yofs2 = 0;
04877 yofs3 = FXCLAMP( yofs2+1, 0, bm_height - 1 );
04878 }
04879
04880 BumpmapParams params( azimuth, elevation, depth, type, invert );
04881
04882 uint* bm_row1 = (unsigned int*)map.scanLine( yofs1 );
04883 uint* bm_row2 = (unsigned int*)map.scanLine( yofs2 );
04884 uint* bm_row3 = (unsigned int*)map.scanLine( yofs3 );
04885
04886 bumpmap_convert_row( bm_row1, bm_width, bm_bpp, bm_has_alpha, params.lut, waterlevel );
04887 bumpmap_convert_row( bm_row2, bm_width, bm_bpp, bm_has_alpha, params.lut, waterlevel );
04888 bumpmap_convert_row( bm_row3, bm_width, bm_bpp, bm_has_alpha, params.lut, waterlevel );
04889
04890 for (int y = 0; y < img.height(); ++y)
04891 {
04892 int row_in_bumpmap = (y >= - yofs && y < - yofs + bm_height);
04893
04894 uint* src_row = (unsigned int*)img.scanLine( y );
04895 uint* dest_row = (unsigned int*)dst.scanLine( y );
04896
04897 bumpmap_row( src_row, dest_row, img.width(), img.depth(), img.hasAlphaBuffer(),
04898 bm_row1, bm_row2, bm_row3, bm_width, xofs,
04899 tiled,
04900 row_in_bumpmap, ambient, compensate,
04901 ¶ms );
04902
04903
04904
04905 if (tiled || row_in_bumpmap)
04906 {
04907 uint* bm_tmprow = bm_row1;
04908 bm_row1 = bm_row2;
04909 bm_row2 = bm_row3;
04910 bm_row3 = bm_tmprow;
04911
04912 if (++yofs2 == bm_height)
04913 yofs2 = 0;
04914
04915 if (tiled)
04916 yofs3 = MOD(yofs2 + 1, bm_height);
04917 else
04918 yofs3 = FXCLAMP(yofs2 + 1, 0, bm_height - 1);
04919
04920 bm_row3 = (unsigned int*)map.scanLine( yofs3 );
04921 bumpmap_convert_row( bm_row3, bm_width, bm_bpp, bm_has_alpha,
04922 params.lut, waterlevel );
04923 }
04924 }
04925 return dst;
04926 }