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