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