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