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