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