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 if (s)
03670 *q++ = (*s);
03671 }
03672 }
03673
03674 return(dest);
03675 }
03676
03677 QImage KImageEffect::charcoal(QImage &src, double )
03678 {
03679
03680 return(charcoal(src, 0, 1));
03681 }
03682
03683 QImage KImageEffect::charcoal(QImage &src, double radius, double sigma)
03684 {
03685 QImage img(edge(src, radius));
03686 img = blur(img, radius, sigma);
03687 normalize(img);
03688 img.invertPixels(false);
03689 KImageEffect::toGray(img);
03690 return(img);
03691 }
03692
03693 void KImageEffect::normalize(QImage &image)
03694 {
03695 struct double_packet high, low, intensity, *histogram;
03696 struct short_packet *normalize_map;
03697 Q_INT64 number_pixels;
03698 int x, y;
03699 unsigned int *p, *q;
03700 register long i;
03701 unsigned long threshold_intensity;
03702 unsigned char r, g, b, a;
03703
03704 if(image.depth() < 32)
03705 image = image.convertDepth(32);
03706
03707 histogram = (struct double_packet *)
03708 malloc(256*sizeof(struct double_packet));
03709 normalize_map = (struct short_packet *)
03710 malloc(256*sizeof(struct short_packet));
03711
03712 if(!histogram || !normalize_map){
03713 if(histogram)
03714 liberateMemory(&histogram);
03715 if(normalize_map)
03716 liberateMemory(&normalize_map);
03717 qWarning("KImageEffect::normalize(): Unable to allocate memory!");
03718 return;
03719 }
03720
03721
03722
03723
03724 memset(histogram, 0, 256*sizeof(struct double_packet));
03725 for(y=0; y < image.height(); ++y){
03726 p = (unsigned int *)image.scanLine(y);
03727 for(x=0; x < image.width(); ++x){
03728 histogram[(unsigned char)(qRed(*p))].red++;
03729 histogram[(unsigned char)(qGreen(*p))].green++;
03730 histogram[(unsigned char)(qBlue(*p))].blue++;
03731 histogram[(unsigned char)(qAlpha(*p))].alpha++;
03732 p++;
03733 }
03734 }
03735
03736
03737
03738
03739 number_pixels = (Q_INT64)image.width()*image.height();
03740 threshold_intensity = number_pixels/1000;
03741
03742
03743 memset(&intensity, 0, sizeof(struct double_packet));
03744 memset(&high, 0, sizeof(struct double_packet));
03745 memset(&low, 0, sizeof(struct double_packet));
03746 for(high.red=255; high.red != 0; high.red--){
03747 intensity.red+=histogram[(unsigned char)high.red].red;
03748 if(intensity.red > threshold_intensity)
03749 break;
03750 }
03751 if(low.red == high.red){
03752 threshold_intensity = 0;
03753 memset(&intensity, 0, sizeof(struct double_packet));
03754 for(low.red=0; low.red < 255; low.red++){
03755 intensity.red+=histogram[(unsigned char)low.red].red;
03756 if(intensity.red > threshold_intensity)
03757 break;
03758 }
03759 memset(&intensity, 0, sizeof(struct double_packet));
03760 for(high.red=255; high.red != 0; high.red--){
03761 intensity.red+=histogram[(unsigned char)high.red].red;
03762 if(intensity.red > threshold_intensity)
03763 break;
03764 }
03765 }
03766
03767
03768 memset(&intensity, 0, sizeof(struct double_packet));
03769 for(high.green=255; high.green != 0; high.green--){
03770 intensity.green+=histogram[(unsigned char)high.green].green;
03771 if(intensity.green > threshold_intensity)
03772 break;
03773 }
03774 if(low.green == high.green){
03775 threshold_intensity = 0;
03776 memset(&intensity, 0, sizeof(struct double_packet));
03777 for(low.green=0; low.green < 255; low.green++){
03778 intensity.green+=histogram[(unsigned char)low.green].green;
03779 if(intensity.green > threshold_intensity)
03780 break;
03781 }
03782 memset(&intensity,0,sizeof(struct double_packet));
03783 for(high.green=255; high.green != 0; high.green--){
03784 intensity.green+=histogram[(unsigned char)high.green].green;
03785 if(intensity.green > threshold_intensity)
03786 break;
03787 }
03788 }
03789
03790
03791 memset(&intensity, 0, sizeof(struct double_packet));
03792 for(high.blue=255; high.blue != 0; high.blue--){
03793 intensity.blue+=histogram[(unsigned char)high.blue].blue;
03794 if(intensity.blue > threshold_intensity)
03795 break;
03796 }
03797 if(low.blue == high.blue){
03798 threshold_intensity = 0;
03799 memset(&intensity, 0, sizeof(struct double_packet));
03800 for(low.blue=0; low.blue < 255; low.blue++){
03801 intensity.blue+=histogram[(unsigned char)low.blue].blue;
03802 if(intensity.blue > threshold_intensity)
03803 break;
03804 }
03805 memset(&intensity,0,sizeof(struct double_packet));
03806 for(high.blue=255; high.blue != 0; high.blue--){
03807 intensity.blue+=histogram[(unsigned char)high.blue].blue;
03808 if(intensity.blue > threshold_intensity)
03809 break;
03810 }
03811 }
03812
03813
03814 memset(&intensity, 0, sizeof(struct double_packet));
03815 for(high.alpha=255; high.alpha != 0; high.alpha--){
03816 intensity.alpha+=histogram[(unsigned char)high.alpha].alpha;
03817 if(intensity.alpha > threshold_intensity)
03818 break;
03819 }
03820 if(low.alpha == high.alpha){
03821 threshold_intensity = 0;
03822 memset(&intensity, 0, sizeof(struct double_packet));
03823 for(low.alpha=0; low.alpha < 255; low.alpha++){
03824 intensity.alpha+=histogram[(unsigned char)low.alpha].alpha;
03825 if(intensity.alpha > threshold_intensity)
03826 break;
03827 }
03828 memset(&intensity,0,sizeof(struct double_packet));
03829 for(high.alpha=255; high.alpha != 0; high.alpha--){
03830 intensity.alpha+=histogram[(unsigned char)high.alpha].alpha;
03831 if(intensity.alpha > threshold_intensity)
03832 break;
03833 }
03834 }
03835 liberateMemory(&histogram);
03836
03837
03838
03839
03840
03841
03842 memset(normalize_map, 0 ,256*sizeof(struct short_packet));
03843 for(i=0; i <= (long) 255; i++){
03844 if(i < (long) low.red)
03845 normalize_map[i].red=0;
03846 else if (i > (long) high.red)
03847 normalize_map[i].red=65535;
03848 else if (low.red != high.red)
03849 normalize_map[i].red =
03850 (unsigned short)((65535*(i-low.red))/(high.red-low.red));
03851
03852 if(i < (long) low.green)
03853 normalize_map[i].green=0;
03854 else if (i > (long) high.green)
03855 normalize_map[i].green=65535;
03856 else if (low.green != high.green)
03857 normalize_map[i].green =
03858 (unsigned short)((65535*(i-low.green))/(high.green-low.green));
03859
03860 if(i < (long) low.blue)
03861 normalize_map[i].blue=0;
03862 else if (i > (long) high.blue)
03863 normalize_map[i].blue=65535;
03864 else if (low.blue != high.blue)
03865 normalize_map[i].blue =
03866 (unsigned short)((65535*(i-low.blue))/(high.blue-low.blue));
03867
03868 if(i < (long) low.alpha)
03869 normalize_map[i].alpha=0;
03870 else if (i > (long) high.alpha)
03871 normalize_map[i].alpha=65535;
03872 else if (low.alpha != high.alpha)
03873 normalize_map[i].alpha =
03874 (unsigned short)((65535*(i-low.alpha))/(high.alpha-low.alpha));
03875
03876 }
03877
03878 for(y=0; y < image.height(); ++y){
03879 q = (unsigned int *)image.scanLine(y);
03880 for(x=0; x < image.width(); ++x){
03881 if(low.red != high.red)
03882 r = (normalize_map[(unsigned short)(qRed(q[x]))].red)/257;
03883 else
03884 r = qRed(q[x]);
03885 if(low.green != high.green)
03886 g = (normalize_map[(unsigned short)(qGreen(q[x]))].green)/257;
03887 else
03888 g = qGreen(q[x]);
03889 if(low.blue != high.blue)
03890 b = (normalize_map[(unsigned short)(qBlue(q[x]))].blue)/257;
03891 else
03892 b = qBlue(q[x]);
03893 if(low.alpha != high.alpha)
03894 a = (normalize_map[(unsigned short)(qAlpha(q[x]))].alpha)/257;
03895 else
03896 a = qAlpha(q[x]);
03897 q[x] = qRgba(r, g, b, a);
03898 }
03899 }
03900 liberateMemory(&normalize_map);
03901 }
03902
03903 void KImageEffect::equalize(QImage &image)
03904 {
03905 struct double_packet high, low, intensity, *map, *histogram;
03906 struct short_packet *equalize_map;
03907 int x, y;
03908 unsigned int *p, *q;
03909 long i;
03910 unsigned char r, g, b, a;
03911
03912 if(image.depth() < 32)
03913 image = image.convertDepth(32);
03914
03915 histogram=(struct double_packet *) malloc(256*sizeof(struct double_packet));
03916 map=(struct double_packet *) malloc(256*sizeof(struct double_packet));
03917 equalize_map=(struct short_packet *)malloc(256*sizeof(struct short_packet));
03918 if(!histogram || !map || !equalize_map){
03919 if(histogram)
03920 liberateMemory(&histogram);
03921 if(map)
03922 liberateMemory(&map);
03923 if(equalize_map)
03924 liberateMemory(&equalize_map);
03925 qWarning("KImageEffect::equalize(): Unable to allocate memory!");
03926 return;
03927 }
03928
03929
03930
03931
03932 memset(histogram, 0, 256*sizeof(struct double_packet));
03933 for(y=0; y < image.height(); ++y){
03934 p = (unsigned int *)image.scanLine(y);
03935 for(x=0; x < image.width(); ++x){
03936 histogram[(unsigned char)(qRed(*p))].red++;
03937 histogram[(unsigned char)(qGreen(*p))].green++;
03938 histogram[(unsigned char)(qBlue(*p))].blue++;
03939 histogram[(unsigned char)(qAlpha(*p))].alpha++;
03940 p++;
03941 }
03942 }
03943
03944
03945
03946 memset(&intensity, 0 ,sizeof(struct double_packet));
03947 for(i=0; i <= 255; ++i){
03948 intensity.red += histogram[i].red;
03949 intensity.green += histogram[i].green;
03950 intensity.blue += histogram[i].blue;
03951 intensity.alpha += histogram[i].alpha;
03952 map[i]=intensity;
03953 }
03954 low=map[0];
03955 high=map[255];
03956 memset(equalize_map, 0, 256*sizeof(short_packet));
03957 for(i=0; i <= 255; ++i){
03958 if(high.red != low.red)
03959 equalize_map[i].red=(unsigned short)
03960 ((65535*(map[i].red-low.red))/(high.red-low.red));
03961 if(high.green != low.green)
03962 equalize_map[i].green=(unsigned short)
03963 ((65535*(map[i].green-low.green))/(high.green-low.green));
03964 if(high.blue != low.blue)
03965 equalize_map[i].blue=(unsigned short)
03966 ((65535*(map[i].blue-low.blue))/(high.blue-low.blue));
03967 if(high.alpha != low.alpha)
03968 equalize_map[i].alpha=(unsigned short)
03969 ((65535*(map[i].alpha-low.alpha))/(high.alpha-low.alpha));
03970 }
03971 liberateMemory(&histogram);
03972 liberateMemory(&map);
03973
03974
03975
03976
03977 for(y=0; y < image.height(); ++y){
03978 q = (unsigned int *)image.scanLine(y);
03979 for(x=0; x < image.width(); ++x){
03980 if(low.red != high.red)
03981 r = (equalize_map[(unsigned short)(qRed(q[x]))].red/257);
03982 else
03983 r = qRed(q[x]);
03984 if(low.green != high.green)
03985 g = (equalize_map[(unsigned short)(qGreen(q[x]))].green/257);
03986 else
03987 g = qGreen(q[x]);
03988 if(low.blue != high.blue)
03989 b = (equalize_map[(unsigned short)(qBlue(q[x]))].blue/257);
03990 else
03991 b = qBlue(q[x]);
03992 if(low.alpha != high.alpha)
03993 a = (equalize_map[(unsigned short)(qAlpha(q[x]))].alpha/257);
03994 else
03995 a = qAlpha(q[x]);
03996 q[x] = qRgba(r, g, b, a);
03997 }
03998 }
03999 liberateMemory(&equalize_map);
04000
04001 }
04002
04003 QImage KImageEffect::edge(QImage &image, double radius)
04004 {
04005 double *kernel;
04006 int width;
04007 register long i;
04008 QImage dest;
04009
04010 if(radius == 50.0){
04011
04012
04013
04014 radius = 0.0;
04015 }
04016
04017 width = getOptimalKernelWidth(radius, 0.5);
04018 if(image.width() < width || image.height() < width){
04019 qWarning("KImageEffect::edge(): Image is smaller than radius!");
04020 return(dest);
04021 }
04022 kernel= (double *)malloc(width*width*sizeof(double));
04023 if(!kernel){
04024 qWarning("KImageEffect::edge(): Unable to allocate memory!");
04025 return(dest);
04026 }
04027 for(i=0; i < (width*width); i++)
04028 kernel[i]=(-1.0);
04029 kernel[i/2]=width*width-1.0;
04030 convolveImage(&image, &dest, width, kernel);
04031 free(kernel);
04032 return(dest);
04033 }
04034
04035 QImage KImageEffect::emboss(QImage &src)
04036 {
04037
04038 return(emboss(src, 0, 1));
04039 }
04040
04041 QImage KImageEffect::emboss(QImage &image, double radius, double sigma)
04042 {
04043 double alpha, *kernel;
04044 int j, width;
04045 register long i, u, v;
04046 QImage dest;
04047
04048 if(sigma == 0.0){
04049 qWarning("KImageEffect::emboss(): Zero sigma is not permitted!");
04050 return(dest);
04051 }
04052
04053 width = getOptimalKernelWidth(radius, sigma);
04054 if(image.width() < width || image.height() < width){
04055 qWarning("KImageEffect::emboss(): Image is smaller than radius!");
04056 return(dest);
04057 }
04058 kernel= (double *)malloc(width*width*sizeof(double));
04059 if(!kernel){
04060 qWarning("KImageEffect::emboss(): Unable to allocate memory!");
04061 return(dest);
04062 }
04063 if(image.depth() < 32)
04064 image = image.convertDepth(32);
04065
04066 i=0;
04067 j=width/2;
04068 for(v=(-width/2); v <= (width/2); v++){
04069 for(u=(-width/2); u <= (width/2); u++){
04070 alpha=exp(-((double) u*u+v*v)/(2.0*sigma*sigma));
04071 kernel[i]=((u < 0) || (v < 0) ? -8.0 : 8.0)*alpha/
04072 (2.0*MagickPI*sigma*sigma);
04073 if (u == j)
04074 kernel[i]=0.0;
04075 i++;
04076 }
04077 j--;
04078 }
04079 convolveImage(&image, &dest, width, kernel);
04080 liberateMemory(&kernel);
04081
04082 equalize(dest);
04083 return(dest);
04084 }
04085
04086 void KImageEffect::blurScanLine(double *kernel, int width,
04087 unsigned int *src, unsigned int *dest,
04088 int columns)
04089 {
04090 register double *p;
04091 unsigned int *q;
04092 register int x;
04093 register long i;
04094 double red, green, blue, alpha;
04095 double scale = 0.0;
04096
04097 if(width > columns){
04098 for(x=0; x < columns; ++x){
04099 scale = 0.0;
04100 red = blue = green = alpha = 0.0;
04101 p = kernel;
04102 q = src;
04103 for(i=0; i < columns; ++i){
04104 if((i >= (x-width/2)) && (i <= (x+width/2))){
04105 red += (*p)*(qRed(*q)*257);
04106 green += (*p)*(qGreen(*q)*257);
04107 blue += (*p)*(qBlue(*q)*257);
04108 alpha += (*p)*(qAlpha(*q)*257);
04109 }
04110 if(((i+width/2-x) >= 0) && ((i+width/2-x) < width))
04111 scale+=kernel[i+width/2-x];
04112 p++;
04113 q++;
04114 }
04115 scale = 1.0/scale;
04116 red = scale*(red+0.5);
04117 green = scale*(green+0.5);
04118 blue = scale*(blue+0.5);
04119 alpha = scale*(alpha+0.5);
04120
04121 red = red < 0 ? 0 : red > 65535 ? 65535 : red;
04122 green = green < 0 ? 0 : green > 65535 ? 65535 : green;
04123 blue = blue < 0 ? 0 : blue > 65535 ? 65535 : blue;
04124 alpha = alpha < 0 ? 0 : alpha > 65535 ? 65535 : alpha;
04125
04126 dest[x] = qRgba((unsigned char)(red/257UL),
04127 (unsigned char)(green/257UL),
04128 (unsigned char)(blue/257UL),
04129 (unsigned char)(alpha/257UL));
04130 }
04131 return;
04132 }
04133
04134 for(x=0; x < width/2; ++x){
04135 scale = 0.0;
04136 red = blue = green = alpha = 0.0;
04137 p = kernel+width/2-x;
04138 q = src;
04139 for(i=width/2-x; i < width; ++i){
04140 red += (*p)*(qRed(*q)*257);
04141 green += (*p)*(qGreen(*q)*257);
04142 blue += (*p)*(qBlue(*q)*257);
04143 alpha += (*p)*(qAlpha(*q)*257);
04144 scale += (*p);
04145 p++;
04146 q++;
04147 }
04148 scale=1.0/scale;
04149
04150 red = scale*(red+0.5);
04151 green = scale*(green+0.5);
04152 blue = scale*(blue+0.5);
04153 alpha = scale*(alpha+0.5);
04154
04155 red = red < 0 ? 0 : red > 65535 ? 65535 : red;
04156 green = green < 0 ? 0 : green > 65535 ? 65535 : green;
04157 blue = blue < 0 ? 0 : blue > 65535 ? 65535 : blue;
04158 alpha = alpha < 0 ? 0 : alpha > 65535 ? 65535 : alpha;
04159
04160 dest[x] = qRgba((unsigned char)(red/257UL),
04161 (unsigned char)(green/257UL),
04162 (unsigned char)(blue/257UL),
04163 (unsigned char)(alpha/257UL));
04164 }
04165
04166 for(; x < columns-width/2; ++x){
04167 red = blue = green = alpha = 0.0;
04168 p = kernel;
04169 q = src+(x-width/2);
04170 for (i=0; i < (long) width; ++i){
04171 red += (*p)*(qRed(*q)*257);
04172 green += (*p)*(qGreen(*q)*257);
04173 blue += (*p)*(qBlue(*q)*257);
04174 alpha += (*p)*(qAlpha(*q)*257);
04175 p++;
04176 q++;
04177 }
04178 red = scale*(red+0.5);
04179 green = scale*(green+0.5);
04180 blue = scale*(blue+0.5);
04181 alpha = scale*(alpha+0.5);
04182
04183 red = red < 0 ? 0 : red > 65535 ? 65535 : red;
04184 green = green < 0 ? 0 : green > 65535 ? 65535 : green;
04185 blue = blue < 0 ? 0 : blue > 65535 ? 65535 : blue;
04186 alpha = alpha < 0 ? 0 : alpha > 65535 ? 65535 : alpha;
04187
04188 dest[x] = qRgba((unsigned char)(red/257UL),
04189 (unsigned char)(green/257UL),
04190 (unsigned char)(blue/257UL),
04191 (unsigned char)(alpha/257UL));
04192 }
04193
04194 for(; x < columns; ++x){
04195 red = blue = green = alpha = 0.0;
04196 scale=0;
04197 p = kernel;
04198 q = src+(x-width/2);
04199 for(i=0; i < columns-x+width/2; ++i){
04200 red += (*p)*(qRed(*q)*257);
04201 green += (*p)*(qGreen(*q)*257);
04202 blue += (*p)*(qBlue(*q)*257);
04203 alpha += (*p)*(qAlpha(*q)*257);
04204 scale += (*p);
04205 p++;
04206 q++;
04207 }
04208 scale=1.0/scale;
04209 red = scale*(red+0.5);
04210 green = scale*(green+0.5);
04211 blue = scale*(blue+0.5);
04212 alpha = scale*(alpha+0.5);
04213
04214 red = red < 0 ? 0 : red > 65535 ? 65535 : red;
04215 green = green < 0 ? 0 : green > 65535 ? 65535 : green;
04216 blue = blue < 0 ? 0 : blue > 65535 ? 65535 : blue;
04217 alpha = alpha < 0 ? 0 : alpha > 65535 ? 65535 : alpha;
04218
04219 dest[x] = qRgba((unsigned char)(red/257UL),
04220 (unsigned char)(green/257UL),
04221 (unsigned char)(blue/257UL),
04222 (unsigned char)(alpha/257UL));
04223 }
04224 }
04225
04226 int KImageEffect::getBlurKernel(int width, double sigma, double **kernel)
04227 {
04228 #define KernelRank 3
04229 double alpha, normalize;
04230 register long i;
04231 int bias;
04232
04233 assert(sigma != 0.0);
04234 if(width == 0)
04235 width = 3;
04236 *kernel=(double *)malloc(width*sizeof(double));
04237 if(*kernel == (double *)NULL)
04238 return(0);
04239 memset(*kernel, 0, width*sizeof(double));
04240 bias = KernelRank*width/2;
04241 for(i=(-bias); i <= bias; i++){
04242 alpha=exp(-((double) i*i)/(2.0*KernelRank*KernelRank*sigma*sigma));
04243 (*kernel)[(i+bias)/KernelRank]+=alpha/(MagickSQ2PI*sigma);
04244 }
04245 normalize=0;
04246 for(i=0; i < width; i++)
04247 normalize+=(*kernel)[i];
04248 for(i=0; i < width; i++)
04249 (*kernel)[i]/=normalize;
04250
04251 return(width);
04252 }
04253
04254 QImage KImageEffect::blur(QImage &src, double )
04255 {
04256
04257 return(blur(src, 0, 1));
04258 }
04259
04260 QImage KImageEffect::blur(QImage &src, double radius, double sigma)
04261 {
04262 double *kernel;
04263 QImage dest;
04264 int width;
04265 int x, y;
04266 unsigned int *scanline, *temp;
04267 unsigned int *p, *q;
04268
04269 if(sigma == 0.0){
04270 qWarning("KImageEffect::blur(): Zero sigma is not permitted!");
04271 return(dest);
04272 }
04273 if(src.depth() < 32)
04274 src = src.convertDepth(32);
04275
04276 kernel=(double *) NULL;
04277 if(radius > 0)
04278 width=getBlurKernel((int) (2*ceil(radius)+1),sigma,&kernel);
04279 else{
04280 double *last_kernel;
04281 last_kernel=(double *) NULL;
04282 width=getBlurKernel(3,sigma,&kernel);
04283
04284 while ((long) (MaxRGB*kernel[0]) > 0){
04285 if(last_kernel != (double *)NULL){
04286 liberateMemory(&last_kernel);
04287 }
04288 last_kernel=kernel;
04289 kernel = (double *)NULL;
04290 width = getBlurKernel(width+2, sigma, &kernel);
04291 }
04292 if(last_kernel != (double *) NULL){
04293 liberateMemory(&kernel);
04294 width-=2;
04295 kernel = last_kernel;
04296 }
04297 }
04298
04299 if(width < 3){
04300 qWarning("KImageEffect::blur(): Kernel radius is too small!");
04301 liberateMemory(&kernel);
04302 return(dest);
04303 }
04304
04305 dest.create(src.width(), src.height(), 32);
04306
04307 scanline = (unsigned int *)malloc(sizeof(unsigned int)*src.height());
04308 temp = (unsigned int *)malloc(sizeof(unsigned int)*src.height());
04309 for(y=0; y < src.height(); ++y){
04310 p = (unsigned int *)src.scanLine(y);
04311 q = (unsigned int *)dest.scanLine(y);
04312 blurScanLine(kernel, width, p, q, src.width());
04313 }
04314
04315 unsigned int **srcTable = (unsigned int **)src.jumpTable();
04316 unsigned int **destTable = (unsigned int **)dest.jumpTable();
04317 for(x=0; x < src.width(); ++x){
04318 for(y=0; y < src.height(); ++y){
04319 scanline[y] = srcTable[y][x];
04320 }
04321 blurScanLine(kernel, width, scanline, temp, src.height());
04322 for(y=0; y < src.height(); ++y){
04323 destTable[y][x] = temp[y];
04324 }
04325 }
04326 free(scanline);
04327 free(temp);
04328 free(kernel);
04329 return(dest);
04330 }
04331
04332 bool KImageEffect::convolveImage(QImage *image, QImage *dest,
04333 const unsigned int order,
04334 const double *kernel)
04335 {
04336 long width;
04337 double red, green, blue, alpha;
04338 double normalize, *normal_kernel;
04339 register const double *k;
04340 register unsigned int *q;
04341 int x, y, mx, my, sx, sy;
04342 long i;
04343 int mcx, mcy;
04344
04345 width = order;
04346 if((width % 2) == 0){
04347 qWarning("KImageEffect: Kernel width must be an odd number!");
04348 return(false);
04349 }
04350 normal_kernel = (double *)malloc(width*width*sizeof(double));
04351 if(!normal_kernel){
04352 qWarning("KImageEffect: Unable to allocate memory!");
04353 return(false);
04354 }
04355 dest->reset();
04356 dest->create(image->width(), image->height(), 32);
04357 if(image->depth() < 32)
04358 *image = image->convertDepth(32);
04359
04360 normalize=0.0;
04361 for(i=0; i < (width*width); i++)
04362 normalize += kernel[i];
04363 if(fabs(normalize) <= MagickEpsilon)
04364 normalize=1.0;
04365 normalize=1.0/normalize;
04366 for(i=0; i < (width*width); i++)
04367 normal_kernel[i] = normalize*kernel[i];
04368
04369 unsigned int **jumpTable = (unsigned int **)image->jumpTable();
04370 for(y=0; y < dest->height(); ++y){
04371 sy = y-(width/2);
04372 q = (unsigned int *)dest->scanLine(y);
04373 for(x=0; x < dest->width(); ++x){
04374 k = normal_kernel;
04375 red = green = blue = alpha = 0;
04376 sy = y-(width/2);
04377 for(mcy=0; mcy < width; ++mcy, ++sy){
04378 my = sy < 0 ? 0 : sy > image->height()-1 ?
04379 image->height()-1 : sy;
04380 sx = x+(-width/2);
04381 for(mcx=0; mcx < width; ++mcx, ++sx){
04382 mx = sx < 0 ? 0 : sx > image->width()-1 ?
04383 image->width()-1 : sx;
04384 red += (*k)*(qRed(jumpTable[my][mx])*257);
04385 green += (*k)*(qGreen(jumpTable[my][mx])*257);
04386 blue += (*k)*(qBlue(jumpTable[my][mx])*257);
04387 alpha += (*k)*(qAlpha(jumpTable[my][mx])*257);
04388 ++k;
04389 }
04390 }
04391
04392 red = red < 0 ? 0 : red > 65535 ? 65535 : red+0.5;
04393 green = green < 0 ? 0 : green > 65535 ? 65535 : green+0.5;
04394 blue = blue < 0 ? 0 : blue > 65535 ? 65535 : blue+0.5;
04395 alpha = alpha < 0 ? 0 : alpha > 65535 ? 65535 : alpha+0.5;
04396
04397 *q++ = qRgba((unsigned char)(red/257UL),
04398 (unsigned char)(green/257UL),
04399 (unsigned char)(blue/257UL),
04400 (unsigned char)(alpha/257UL));
04401 }
04402 }
04403 free(normal_kernel);
04404 return(true);
04405
04406 }
04407
04408 int KImageEffect::getOptimalKernelWidth(double radius, double sigma)
04409 {
04410 double normalize, value;
04411 long width;
04412 register long u;
04413
04414 assert(sigma != 0.0);
04415 if(radius > 0.0)
04416 return((int)(2.0*ceil(radius)+1.0));
04417 for(width=5; ;){
04418 normalize=0.0;
04419 for(u=(-width/2); u <= (width/2); u++)
04420 normalize+=exp(-((double) u*u)/(2.0*sigma*sigma))/(MagickSQ2PI*sigma);
04421 u=width/2;
04422 value=exp(-((double) u*u)/(2.0*sigma*sigma))/(MagickSQ2PI*sigma)/normalize;
04423 if((long)(65535*value) <= 0)
04424 break;
04425 width+=2;
04426 }
04427 return((int)width-2);
04428 }
04429
04430 QImage KImageEffect::sharpen(QImage &src, double )
04431 {
04432
04433 return(sharpen(src, 0, 1));
04434 }
04435
04436 QImage KImageEffect::sharpen(QImage &image, double radius, double sigma)
04437 {
04438 double alpha, normalize, *kernel;
04439 int width;
04440 register long i, u, v;
04441 QImage dest;
04442
04443 if(sigma == 0.0){
04444 qWarning("KImageEffect::sharpen(): Zero sigma is not permitted!");
04445 return(dest);
04446 }
04447 width = getOptimalKernelWidth(radius, sigma);
04448 if(image.width() < width){
04449 qWarning("KImageEffect::sharpen(): Image is smaller than radius!");
04450 return(dest);
04451 }
04452 kernel = (double *)malloc(width*width*sizeof(double));
04453 if(!kernel){
04454 qWarning("KImageEffect::sharpen(): Unable to allocate memory!");
04455 return(dest);
04456 }
04457
04458 i = 0;
04459 normalize=0.0;
04460 for(v=(-width/2); v <= (width/2); v++){
04461 for(u=(-width/2); u <= (width/2); u++){
04462 alpha=exp(-((double) u*u+v*v)/(2.0*sigma*sigma));
04463 kernel[i]=alpha/(2.0*MagickPI*sigma*sigma);
04464 normalize+=kernel[i];
04465 i++;
04466 }
04467 }
04468 kernel[i/2]=(-2.0)*normalize;
04469 convolveImage(&image, &dest, width, kernel);
04470 free(kernel);
04471 return(dest);
04472 }
04473
04474
04475
04476 QImage KImageEffect::shade(QImage &src, bool color_shading, double azimuth,
04477 double elevation)
04478 {
04479 struct PointInfo{
04480 double x, y, z;
04481 };
04482
04483 double distance, normal_distance, shade;
04484 int x, y;
04485
04486 struct PointInfo light, normal;
04487
04488 unsigned int *q;
04489
04490 QImage dest(src.width(), src.height(), 32);
04491
04492 azimuth = DegreesToRadians(azimuth);
04493 elevation = DegreesToRadians(elevation);
04494 light.x = MaxRGB*cos(azimuth)*cos(elevation);
04495 light.y = MaxRGB*sin(azimuth)*cos(elevation);
04496 light.z = MaxRGB*sin(elevation);
04497 normal.z= 2*MaxRGB;
04498
04499 if(src.depth() > 8){
04500 unsigned int *p, *s0, *s1, *s2;
04501 for(y=0; y < src.height(); ++y){
04502 p = (unsigned int *)src.scanLine(QMIN(QMAX(y-1,0),src.height()-3));
04503 q = (unsigned int *)dest.scanLine(y);
04504
04505 *q++=(*(p+src.width()));
04506 p++;
04507 s0 = p;
04508 s1 = p + src.width();
04509 s2 = p + 2*src.width();
04510 for(x=1; x < src.width()-1; ++x){
04511
04512 normal.x=intensityValue(*(s0-1))+intensityValue(*(s1-1))+intensityValue(*(s2-1))-
04513 (double) intensityValue(*(s0+1))-(double) intensityValue(*(s1+1))-
04514 (double) intensityValue(*(s2+1));
04515 normal.y=intensityValue(*(s2-1))+intensityValue(*s2)+intensityValue(*(s2+1))-
04516 (double) intensityValue(*(s0-1))-(double) intensityValue(*s0)-
04517 (double) intensityValue(*(s0+1));
04518 if((normal.x == 0) && (normal.y == 0))
04519 shade=light.z;
04520 else{
04521 shade=0.0;
04522 distance=normal.x*light.x+normal.y*light.y+normal.z*light.z;
04523 if (distance > 0.0){
04524 normal_distance=
04525 normal.x*normal.x+normal.y*normal.y+normal.z*normal.z;
04526 if(fabs(normal_distance) > 0.0000001)
04527 shade=distance/sqrt(normal_distance);
04528 }
04529 }
04530 if(!color_shading){
04531 *q = qRgba((unsigned char)(shade),
04532 (unsigned char)(shade),
04533 (unsigned char)(shade),
04534 qAlpha(*s1));
04535 }
04536 else{
04537 *q = qRgba((unsigned char)((shade*qRed(*s1))/(MaxRGB+1)),
04538 (unsigned char)((shade*qGreen(*s1))/(MaxRGB+1)),
04539 (unsigned char)((shade*qBlue(*s1))/(MaxRGB+1)),
04540 qAlpha(*s1));
04541 }
04542 ++s0;
04543 ++s1;
04544 ++s2;
04545 q++;
04546 }
04547 *q++=(*s1);
04548 }
04549 }
04550 else{
04551 unsigned char *p, *s0, *s1, *s2;
04552 int scanLineIdx;
04553 unsigned int *cTable = (unsigned int *)src.colorTable();
04554 for(y=0; y < src.height(); ++y){
04555 scanLineIdx = QMIN(QMAX(y-1,0),src.height()-3);
04556 p = (unsigned char *)src.scanLine(scanLineIdx);
04557 q = (unsigned int *)dest.scanLine(y);
04558
04559 s0 = p;
04560 s1 = (unsigned char *) src.scanLine(scanLineIdx+1);
04561 s2 = (unsigned char *) src.scanLine(scanLineIdx+2);
04562 *q++=(*(cTable+(*s1)));
04563 ++p;
04564 ++s0;
04565 ++s1;
04566 ++s2;
04567 for(x=1; x < src.width()-1; ++x){
04568
04569 normal.x=intensityValue(*(cTable+(*(s0-1))))+intensityValue(*(cTable+(*(s1-1))))+intensityValue(*(cTable+(*(s2-1))))-
04570 (double) intensityValue(*(cTable+(*(s0+1))))-(double) intensityValue(*(cTable+(*(s1+1))))-
04571 (double) intensityValue(*(cTable+(*(s2+1))));
04572 normal.y=intensityValue(*(cTable+(*(s2-1))))+intensityValue(*(cTable+(*s2)))+intensityValue(*(cTable+(*(s2+1))))-
04573 (double) intensityValue(*(cTable+(*(s0-1))))-(double) intensityValue(*(cTable+(*s0)))-
04574 (double) intensityValue(*(cTable+(*(s0+1))));
04575 if((normal.x == 0) && (normal.y == 0))
04576 shade=light.z;
04577 else{
04578 shade=0.0;
04579 distance=normal.x*light.x+normal.y*light.y+normal.z*light.z;
04580 if (distance > 0.0){
04581 normal_distance=
04582 normal.x*normal.x+normal.y*normal.y+normal.z*normal.z;
04583 if(fabs(normal_distance) > 0.0000001)
04584 shade=distance/sqrt(normal_distance);
04585 }
04586 }
04587 if(!color_shading){
04588 *q = qRgba((unsigned char)(shade),
04589 (unsigned char)(shade),
04590 (unsigned char)(shade),
04591 qAlpha(*(cTable+(*s1))));
04592 }
04593 else{
04594 *q = qRgba((unsigned char)((shade*qRed(*(cTable+(*s1))))/(MaxRGB+1)),
04595 (unsigned char)((shade*qGreen(*(cTable+(*s1))))/(MaxRGB+1)),
04596 (unsigned char)((shade*qBlue(*(cTable+(*s1))))/(MaxRGB+1)),
04597 qAlpha(*s1));
04598 }
04599 ++s0;
04600 ++s1;
04601 ++s2;
04602 q++;
04603 }
04604 *q++=(*(cTable+(*s1)));
04605 }
04606 }
04607 return(dest);
04608 }
04609
04610
04611
04612
04613
04614 void KImageEffect::contrastHSV(QImage &img, bool sharpen)
04615 {
04616 int i, sign;
04617 unsigned int *data;
04618 int count;
04619 double brightness, scale, theta;
04620 QColor c;
04621 int h, s, v;
04622
04623 sign = sharpen ? 1 : -1;
04624 scale=0.5000000000000001;
04625 if(img.depth() > 8){
04626 count = img.width()*img.height();
04627 data = (unsigned int *)img.bits();
04628 }
04629 else{
04630 count = img.numColors();
04631 data = (unsigned int *)img.colorTable();
04632 }
04633 for(i=0; i < count; ++i){
04634 c.setRgb(data[i]);
04635 c.hsv(&h, &s, &v);
04636 brightness = v/255.0;
04637 theta=(brightness-0.5)*M_PI;
04638 brightness+=scale*(((scale*((sin(theta)+1.0)))-brightness)*sign);
04639 if (brightness > 1.0)
04640 brightness=1.0;
04641 else
04642 if (brightness < 0)
04643 brightness=0.0;
04644 v = (int)(brightness*255);
04645 c.setHsv(h, s, v);
04646 data[i] = qRgba(c.red(), c.green(), c.blue(), qAlpha(data[i]));
04647 }
04648 }
04649
04650
04651 struct BumpmapParams {
04652 BumpmapParams( double bm_azimuth, double bm_elevation,
04653 int bm_depth, KImageEffect::BumpmapType bm_type,
04654 bool invert ) {
04655
04656 double azimuth = DegreesToRadians( bm_azimuth );
04657 double elevation = DegreesToRadians( bm_elevation );
04658
04659
04660 lx = (int)( cos(azimuth) * cos(elevation) * 255.0 );
04661 ly = (int)( sin(azimuth) * cos(elevation) * 255.0 );
04662 int lz = (int)( sin(elevation) * 255.0 );
04663
04664
04665 int nz = (6 * 255) / bm_depth;
04666 nz2 = nz * nz;
04667 nzlz = nz * lz;
04668
04669
04670 background = lz;
04671
04672
04673 compensation = sin(elevation);
04674
04675
04676 for (int i = 0; i < 256; i++)
04677 {
04678 double n = 0;
04679 switch (bm_type)
04680 {
04681 case KImageEffect::Spherical:
04682 n = i / 255.0 - 1.0;
04683 lut[i] = (int) (255.0 * sqrt(1.0 - n * n) + 0.5);
04684 break;
04685
04686 case KImageEffect::Sinuosidal:
04687 n = i / 255.0;
04688 lut[i] = (int) (255.0 * (sin((-M_PI / 2.0) + M_PI * n) + 1.0) /
04689 2.0 + 0.5);
04690 break;
04691
04692 case KImageEffect::Linear:
04693 default:
04694 lut[i] = i;
04695 }
04696
04697 if (invert)
04698 lut[i] = 255 - lut[i];
04699 }
04700 }
04701 int lx, ly;
04702 int nz2, nzlz;
04703 int background;
04704 double compensation;
04705 uchar lut[256];
04706 };
04707
04708
04709 static void bumpmap_convert_row( uint *row,
04710 int width,
04711 int bpp,
04712 int has_alpha,
04713 uchar *lut,
04714 int waterlevel )
04715 {
04716 uint *p;
04717
04718 p = row;
04719
04720 has_alpha = has_alpha ? 1 : 0;
04721
04722 if (bpp >= 3)
04723 for (; width; width--)
04724 {
04725 if (has_alpha) {
04726 unsigned int idx = (unsigned int)(intensityValue( *row ) + 0.5);
04727 *p++ = lut[(unsigned int) ( waterlevel +
04728 ( ( idx -
04729 waterlevel) * qBlue( *row )) / 255.0 )];
04730 } else {
04731 unsigned int idx = (unsigned int)(intensityValue( *row ) + 0.5);
04732 *p++ = lut[idx];
04733 }
04734
04735 ++row;
04736 }
04737 }
04738
04739 static void bumpmap_row( uint *src,
04740 uint *dest,
04741 int width,
04742 int bpp,
04743 int has_alpha,
04744 uint *bm_row1,
04745 uint *bm_row2,
04746 uint *bm_row3,
04747 int bm_width,
04748 int bm_xofs,
04749 bool tiled,
04750 bool row_in_bumpmap,
04751 int ambient,
04752 bool compensate,
04753 BumpmapParams *params )
04754 {
04755 int xofs1, xofs2, xofs3;
04756 int shade;
04757 int ndotl;
04758 int nx, ny;
04759 int x;
04760 int tmp;
04761
04762 tmp = bm_xofs;
04763 xofs2 = MOD(tmp, bm_width);
04764
04765 for (x = 0; x < width; x++)
04766 {
04767
04768
04769 if (tiled || (row_in_bumpmap &&
04770 x >= - tmp && x < - tmp + bm_width)) {
04771 if (tiled) {
04772 xofs1 = MOD(xofs2 - 1, bm_width);
04773 xofs3 = MOD(xofs2 + 1, bm_width);
04774 } else {
04775 xofs1 = FXCLAMP(xofs2 - 1, 0, bm_width - 1);
04776 xofs3 = FXCLAMP(xofs2 + 1, 0, bm_width - 1);
04777 }
04778 nx = (bm_row1[xofs1] + bm_row2[xofs1] + bm_row3[xofs1] -
04779 bm_row1[xofs3] - bm_row2[xofs3] - bm_row3[xofs3]);
04780 ny = (bm_row3[xofs1] + bm_row3[xofs2] + bm_row3[xofs3] -
04781 bm_row1[xofs1] - bm_row1[xofs2] - bm_row1[xofs3]);
04782 } else {
04783 nx = ny = 0;
04784 }
04785
04786
04787
04788 if ((nx == 0) && (ny == 0))
04789 shade = params->background;
04790 else {
04791 ndotl = nx * params->lx + ny * params->ly + params->nzlz;
04792
04793 if (ndotl < 0)
04794 shade = (int)( params->compensation * ambient );
04795 else {
04796 shade = (int)( ndotl / sqrt(double(nx * nx + ny * ny + params->nz2)) );
04797
04798 shade = (int)( shade + QMAX(0.0, (255 * params->compensation - shade)) *
04799 ambient / 255 );
04800 }
04801 }
04802
04803
04804
04809 if (compensate) {
04810 int red = (int)((qRed( *src ) * shade) / (params->compensation * 255));
04811 int green = (int)((qGreen( *src ) * shade) / (params->compensation * 255));
04812 int blue = (int)((qBlue( *src ) * shade) / (params->compensation * 255));
04813 int alpha = (int)((qAlpha( *src ) * shade) / (params->compensation * 255));
04814 ++src;
04815 *dest++ = qRgba( red, green, blue, alpha );
04816 } else {
04817 int red = qRed( *src ) * shade / 255;
04818 int green = qGreen( *src ) * shade / 255;
04819 int blue = qBlue( *src ) * shade / 255;
04820 int alpha = qAlpha( *src ) * shade / 255;
04821 ++src;
04822 *dest++ = qRgba( red, green, blue, alpha );
04823 }
04824
04825
04826
04827 if (++xofs2 == bm_width)
04828 xofs2 = 0;
04829 }
04830 }
04831
04851 QImage KImageEffect::bumpmap(QImage &img, QImage &map, double azimuth, double elevation,
04852 int depth, int xofs, int yofs, int waterlevel,
04853 int ambient, bool compensate, bool invert,
04854 BumpmapType type, bool tiled)
04855 {
04856 QImage dst;
04857
04858 if ( img.depth() != 32 || img.depth() != 32 ) {
04859 qWarning( "Bump-mapping effect works only with 32 bit images");
04860 return dst;
04861 }
04862
04863 dst.create( img.width(), img.height(), img.depth() );
04864 int bm_width = map.width();
04865 int bm_height = map.height();
04866 int bm_bpp = map.depth();
04867 int bm_has_alpha = map.hasAlphaBuffer();
04868
04869 int yofs1, yofs2, yofs3;
04870
04871 if ( tiled ) {
04872 yofs2 = MOD( yofs, bm_height );
04873 yofs1 = MOD( yofs2 - 1, bm_height);
04874 yofs3 = MOD( yofs2 + 1, bm_height);
04875 } else {
04876 yofs1 = 0;
04877 yofs2 = 0;
04878 yofs3 = FXCLAMP( yofs2+1, 0, bm_height - 1 );
04879 }
04880
04881 BumpmapParams params( azimuth, elevation, depth, type, invert );
04882
04883 uint* bm_row1 = (unsigned int*)map.scanLine( yofs1 );
04884 uint* bm_row2 = (unsigned int*)map.scanLine( yofs2 );
04885 uint* bm_row3 = (unsigned int*)map.scanLine( yofs3 );
04886
04887 bumpmap_convert_row( bm_row1, bm_width, bm_bpp, bm_has_alpha, params.lut, waterlevel );
04888 bumpmap_convert_row( bm_row2, bm_width, bm_bpp, bm_has_alpha, params.lut, waterlevel );
04889 bumpmap_convert_row( bm_row3, bm_width, bm_bpp, bm_has_alpha, params.lut, waterlevel );
04890
04891 for (int y = 0; y < img.height(); ++y)
04892 {
04893 int row_in_bumpmap = (y >= - yofs && y < - yofs + bm_height);
04894
04895 uint* src_row = (unsigned int*)img.scanLine( y );
04896 uint* dest_row = (unsigned int*)dst.scanLine( y );
04897
04898 bumpmap_row( src_row, dest_row, img.width(), img.depth(), img.hasAlphaBuffer(),
04899 bm_row1, bm_row2, bm_row3, bm_width, xofs,
04900 tiled,
04901 row_in_bumpmap, ambient, compensate,
04902 ¶ms );
04903
04904
04905
04906 if (tiled || row_in_bumpmap)
04907 {
04908 uint* bm_tmprow = bm_row1;
04909 bm_row1 = bm_row2;
04910 bm_row2 = bm_row3;
04911 bm_row3 = bm_tmprow;
04912
04913 if (++yofs2 == bm_height)
04914 yofs2 = 0;
04915
04916 if (tiled)
04917 yofs3 = MOD(yofs2 + 1, bm_height);
04918 else
04919 yofs3 = FXCLAMP(yofs2 + 1, 0, bm_height - 1);
04920
04921 bm_row3 = (unsigned int*)map.scanLine( yofs3 );
04922 bumpmap_convert_row( bm_row3, bm_width, bm_bpp, bm_has_alpha,
04923 params.lut, waterlevel );
04924 }
04925 }
04926 return dst;
04927 }