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