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