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