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