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
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
unsigned int 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
else 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
else 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
else 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
else 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
else 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
if (dst.depth() != 32)
01079 dst = dst.convertDepth(32);
01080
01081
int pixels = dst.width() * dst.height();
01082
01083
#ifdef USE_SSE2_INLINE_ASM
01084
if ( KCPUInfo::haveExtension( KCPUInfo::IntelSSE2 ) && pixels > 16 ) {
01085 Q_UINT16 alpha = Q_UINT16( ( 1.0 - opacity ) * 256.0 );
01086
01087 KIE8Pack packedalpha = { { alpha, alpha, alpha, 256,
01088 alpha, alpha, alpha, 256 } };
01089
01090 Q_UINT16 red = Q_UINT16( clr.red() * 256 * opacity );
01091 Q_UINT16 green = Q_UINT16( clr.green() * 256 * opacity );
01092 Q_UINT16 blue = Q_UINT16( clr.blue() * 256 * opacity );
01093
01094 KIE8Pack packedcolor = { { blue, green, red, 0,
01095 blue, green, red, 0 } };
01096
01097
01098 __asm__ __volatile__(
01099
"pxor %%xmm7, %%xmm7\n\t"
01100
"movdqu (%0), %%xmm6\n\t"
01101
"movdqu (%1), %%xmm5\n\t"
01102 : :
"r"(&packedalpha),
"r"(&packedcolor),
01103
"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 Q_INT64 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 = (Q_INT64)image.width()*image.height();
03768 threshold_intensity = number_pixels/1000;
03769
03770
03771 memset(&intensity, 0,
sizeof(
struct double_packet));
03772 memset(&high, 0,
sizeof(
struct double_packet));
03773 memset(&low, 0,
sizeof(
struct double_packet));
03774
for(high.red=255; high.red != 0; high.red--){
03775 intensity.red+=histogram[(
unsigned char)high.red].red;
03776
if(intensity.red > threshold_intensity)
03777
break;
03778 }
03779
if(low.red == high.red){
03780 threshold_intensity = 0;
03781 memset(&intensity, 0,
sizeof(
struct double_packet));
03782
for(low.red=0; low.red < 255; low.red++){
03783 intensity.red+=histogram[(
unsigned char)low.red].red;
03784
if(intensity.red > threshold_intensity)
03785
break;
03786 }
03787 memset(&intensity, 0,
sizeof(
struct double_packet));
03788
for(high.red=255; high.red != 0; high.red--){
03789 intensity.red+=histogram[(
unsigned char)high.red].red;
03790
if(intensity.red > threshold_intensity)
03791
break;
03792 }
03793 }
03794
03795
03796 memset(&intensity, 0,
sizeof(
struct double_packet));
03797
for(high.green=255; high.green != 0; high.green--){
03798 intensity.green+=histogram[(
unsigned char)high.green].green;
03799
if(intensity.green > threshold_intensity)
03800
break;
03801 }
03802
if(low.green == high.green){
03803 threshold_intensity = 0;
03804 memset(&intensity, 0,
sizeof(
struct double_packet));
03805
for(low.green=0; low.green < 255; low.green++){
03806 intensity.green+=histogram[(
unsigned char)low.green].green;
03807
if(intensity.green > threshold_intensity)
03808
break;
03809 }
03810 memset(&intensity,0,
sizeof(
struct double_packet));
03811
for(high.green=255; high.green != 0; high.green--){
03812 intensity.green+=histogram[(
unsigned char)high.green].green;
03813
if(intensity.green > threshold_intensity)
03814
break;
03815 }
03816 }
03817
03818
03819 memset(&intensity, 0,
sizeof(
struct double_packet));
03820
for(high.blue=255; high.blue != 0; high.blue--){
03821 intensity.blue+=histogram[(
unsigned char)high.blue].blue;
03822
if(intensity.blue > threshold_intensity)
03823
break;
03824 }
03825
if(low.blue == high.blue){
03826 threshold_intensity = 0;
03827 memset(&intensity, 0,
sizeof(
struct double_packet));
03828
for(low.blue=0; low.blue < 255; low.blue++){
03829 intensity.blue+=histogram[(
unsigned char)low.blue].blue;
03830
if(intensity.blue > threshold_intensity)
03831
break;
03832 }
03833 memset(&intensity,0,
sizeof(
struct double_packet));
03834
for(high.blue=255; high.blue != 0; high.blue--){
03835 intensity.blue+=histogram[(
unsigned char)high.blue].blue;
03836
if(intensity.blue > threshold_intensity)
03837
break;
03838 }
03839 }
03840
03841
03842 memset(&intensity, 0,
sizeof(
struct double_packet));
03843
for(high.alpha=255; high.alpha != 0; high.alpha--){
03844 intensity.alpha+=histogram[(
unsigned char)high.alpha].alpha;
03845
if(intensity.alpha > threshold_intensity)
03846
break;
03847 }
03848
if(low.alpha == high.alpha){
03849 threshold_intensity = 0;
03850 memset(&intensity, 0,
sizeof(
struct double_packet));
03851
for(low.alpha=0; low.alpha < 255; low.alpha++){
03852 intensity.alpha+=histogram[(
unsigned char)low.alpha].alpha;
03853
if(intensity.alpha > threshold_intensity)
03854
break;
03855 }
03856 memset(&intensity,0,
sizeof(
struct double_packet));
03857
for(high.alpha=255; high.alpha != 0; high.alpha--){
03858 intensity.alpha+=histogram[(
unsigned char)high.alpha].alpha;
03859
if(intensity.alpha > threshold_intensity)
03860
break;
03861 }
03862 }
03863 liberateMemory((
void **) &histogram);
03864
03865
03866
03867
03868
03869
03870 memset(normalize_map, 0 ,256*
sizeof(
struct short_packet));
03871
for(i=0; i <= (
long) 255; i++){
03872
if(i < (
long) low.red)
03873 normalize_map[i].red=0;
03874
else if (i > (
long) high.red)
03875 normalize_map[i].red=65535;
03876
else if (low.red != high.red)
03877 normalize_map[i].red =
03878 (
unsigned short)((65535*(i-low.red))/(high.red-low.red));
03879
03880
if(i < (
long) low.green)
03881 normalize_map[i].green=0;
03882
else if (i > (
long) high.green)
03883 normalize_map[i].green=65535;
03884
else if (low.green != high.green)
03885 normalize_map[i].green =
03886 (
unsigned short)((65535*(i-low.green))/(high.green-low.green));
03887
03888
if(i < (
long) low.blue)
03889 normalize_map[i].blue=0;
03890
else if (i > (
long) high.blue)
03891 normalize_map[i].blue=65535;
03892
else if (low.blue != high.blue)
03893 normalize_map[i].blue =
03894 (
unsigned short)((65535*(i-low.blue))/(high.blue-low.blue));
03895
03896
if(i < (
long) low.alpha)
03897 normalize_map[i].alpha=0;
03898
else if (i > (
long) high.alpha)
03899 normalize_map[i].alpha=65535;
03900
else if (low.alpha != high.alpha)
03901 normalize_map[i].alpha =
03902 (
unsigned short)((65535*(i-low.alpha))/(high.alpha-low.alpha));
03903
03904 }
03905
03906
for(y=0; y < image.height(); ++y){
03907 q = (
unsigned int *)image.scanLine(y);
03908
for(x=0; x < image.width(); ++x){
03909
if(low.red != high.red)
03910 r = (normalize_map[(
unsigned short)(qRed(q[x]))].red)/257;
03911
else
03912 r = qRed(q[x]);
03913
if(low.green != high.green)
03914 g = (normalize_map[(
unsigned short)(qGreen(q[x]))].green)/257;
03915
else
03916 g = qGreen(q[x]);
03917
if(low.blue != high.blue)
03918 b = (normalize_map[(
unsigned short)(qBlue(q[x]))].blue)/257;
03919
else
03920 b = qBlue(q[x]);
03921
if(low.alpha != high.alpha)
03922 a = (normalize_map[(
unsigned short)(qAlpha(q[x]))].alpha)/257;
03923
else
03924 a = qAlpha(q[x]);
03925 q[x] = qRgba(r, g, b, a);
03926 }
03927 }
03928 liberateMemory((
void **) &normalize_map);
03929 }
03930
03931 void KImageEffect::equalize(
QImage &image)
03932 {
03933
struct double_packet high, low, intensity, *map, *histogram;
03934
struct short_packet *equalize_map;
03935
int x, y;
03936
unsigned int *p, *q;
03937
long i;
03938
unsigned char r, g, b, a;
03939
03940
if(image.depth() < 32)
03941 image = image.convertDepth(32);
03942
03943 histogram=(
struct double_packet *) malloc(256*
sizeof(
struct double_packet));
03944 map=(
struct double_packet *) malloc(256*
sizeof(
struct double_packet));
03945 equalize_map=(
struct short_packet *)malloc(256*
sizeof(
struct short_packet));
03946
if(!histogram || !map || !equalize_map){
03947
if(histogram)
03948 liberateMemory((
void **) &histogram);
03949
if(map)
03950 liberateMemory((
void **) &map);
03951
if(equalize_map)
03952 liberateMemory((
void **) &equalize_map);
03953 qWarning(
"KImageEffect::equalize(): Unable to allocate memory!");
03954
return;
03955 }
03956
03957
03958
03959
03960 memset(histogram, 0, 256*
sizeof(
struct double_packet));
03961
for(y=0; y < image.height(); ++y){
03962 p = (
unsigned int *)image.scanLine(y);
03963
for(x=0; x < image.width(); ++x){
03964 histogram[(
unsigned char)(qRed(*p))].red++;
03965 histogram[(
unsigned char)(qGreen(*p))].green++;
03966 histogram[(
unsigned char)(qBlue(*p))].blue++;
03967 histogram[(
unsigned char)(qAlpha(*p))].alpha++;
03968 p++;
03969 }
03970 }
03971
03972
03973
03974 memset(&intensity, 0 ,
sizeof(
struct double_packet));
03975
for(i=0; i <= 255; ++i){
03976 intensity.red += histogram[i].red;
03977 intensity.green += histogram[i].green;
03978 intensity.blue += histogram[i].blue;
03979 intensity.alpha += histogram[i].alpha;
03980 map[i]=intensity;
03981 }
03982 low=map[0];
03983 high=map[255];
03984 memset(equalize_map, 0, 256*
sizeof(short_packet));
03985
for(i=0; i <= 255; ++i){
03986
if(high.red != low.red)
03987 equalize_map[i].red=(
unsigned short)
03988 ((65535*(map[i].red-low.red))/(high.red-low.red));
03989
if(high.green != low.green)
03990 equalize_map[i].green=(
unsigned short)
03991 ((65535*(map[i].green-low.green))/(high.green-low.green));
03992
if(high.blue != low.blue)
03993 equalize_map[i].blue=(
unsigned short)
03994 ((65535*(map[i].blue-low.blue))/(high.blue-low.blue));
03995
if(high.alpha != low.alpha)
03996 equalize_map[i].alpha=(
unsigned short)
03997 ((65535*(map[i].alpha-low.alpha))/(high.alpha-low.alpha));
03998 }
03999 liberateMemory((
void **) &histogram);
04000 liberateMemory((
void **) &map);
04001
04002
04003
04004
04005
for(y=0; y < image.height(); ++y){
04006 q = (
unsigned int *)image.scanLine(y);
04007
for(x=0; x < image.width(); ++x){
04008
if(low.red != high.red)
04009 r = (equalize_map[(
unsigned short)(qRed(q[x]))].red/257);
04010
else
04011 r = qRed(q[x]);
04012
if(low.green != high.green)
04013 g = (equalize_map[(
unsigned short)(qGreen(q[x]))].green/257);
04014
else
04015 g = qGreen(q[x]);
04016
if(low.blue != high.blue)
04017 b = (equalize_map[(
unsigned short)(qBlue(q[x]))].blue/257);
04018
else
04019 b = qBlue(q[x]);
04020
if(low.alpha != high.alpha)
04021 a = (equalize_map[(
unsigned short)(qAlpha(q[x]))].alpha/257);
04022
else
04023 a = qAlpha(q[x]);
04024 q[x] = qRgba(r, g, b, a);
04025 }
04026 }
04027 liberateMemory((
void **) &equalize_map);
04028
04029 }
04030
04031 QImage KImageEffect::edge(
QImage &image,
double radius)
04032 {
04033
double *kernel;
04034
int width;
04035
register long i;
04036
QImage dest;
04037
04038
if(radius == 50.0){
04039
04040
04041
04042 radius = 0.0;
04043 }
04044
04045 width = getOptimalKernelWidth(radius, 0.5);
04046
if(image.width() < width || image.height() < width){
04047 qWarning(
"KImageEffect::edge(): Image is smaller than radius!");
04048
return(dest);
04049 }
04050 kernel= (
double *)malloc(width*width*
sizeof(
double));
04051
if(!kernel){
04052 qWarning(
"KImageEffect::edge(): Unable to allocate memory!");
04053
return(dest);
04054 }
04055
for(i=0; i < (width*width); i++)
04056 kernel[i]=(-1.0);
04057 kernel[i/2]=width*width-1.0;
04058 convolveImage(&image, &dest, width, kernel);
04059 liberateMemory((
void **)&kernel);
04060
return(dest);
04061 }
04062
04063 QImage KImageEffect::emboss(
QImage &src)
04064 {
04065
04066
return(
emboss(src, 0, 1));
04067 }
04068
04069 QImage KImageEffect::emboss(
QImage &image,
double radius,
double sigma)
04070 {
04071
double alpha, *kernel;
04072
int j, width;
04073
register long i, u, v;
04074
QImage dest;
04075
04076
if(sigma == 0.0){
04077 qWarning(
"KImageEffect::emboss(): Zero sigma is not permitted!");
04078
return(dest);
04079 }
04080
04081 width = getOptimalKernelWidth(radius, sigma);
04082
if(image.width() < width || image.height() < width){
04083 qWarning(
"KImageEffect::emboss(): Image is smaller than radius!");
04084
return(dest);
04085 }
04086 kernel= (
double *)malloc(width*width*
sizeof(
double));
04087
if(!kernel){
04088 qWarning(
"KImageEffect::emboss(): Unable to allocate memory!");
04089
return(dest);
04090 }
04091
if(image.depth() < 32)
04092 image = image.convertDepth(32);
04093
04094 i=0;
04095 j=width/2;
04096
for(v=(-width/2); v <= (width/2); v++){
04097
for(u=(-width/2); u <= (width/2); u++){
04098 alpha=exp(-((
double) u*u+v*v)/(2.0*sigma*sigma));
04099 kernel[i]=((u < 0) || (v < 0) ? -8.0 : 8.0)*alpha/
04100 (2.0*MagickPI*sigma*sigma);
04101
if (u == j)
04102 kernel[i]=0.0;
04103 i++;
04104 }
04105 j--;
04106 }
04107 convolveImage(&image, &dest, width, kernel);
04108 liberateMemory((
void **)&kernel);
04109
04110
equalize(dest);
04111
return(dest);
04112 }
04113
04114
void KImageEffect::blurScanLine(
double *kernel,
int width,
04115
unsigned int *src,
unsigned int *dest,
04116
int columns)
04117 {
04118
register double *p;
04119
unsigned int *q;
04120
register int x;
04121
register long i;
04122
double red, green, blue, alpha;
04123
double scale = 0.0;
04124
04125
if(width > columns){
04126
for(x=0; x < columns; ++x){
04127 scale = 0.0;
04128 red = blue = green = alpha = 0.0;
04129 p = kernel;
04130 q = src;
04131
for(i=0; i < columns; ++i){
04132
if((i >= (x-width/2)) && (i <= (x+width/2))){
04133 red += (*p)*(qRed(*q)*257);
04134 green += (*p)*(qGreen(*q)*257);
04135 blue += (*p)*(qBlue(*q)*257);
04136 alpha += (*p)*(qAlpha(*q)*257);
04137 }
04138
if(((i+width/2-x) >= 0) && ((i+width/2-x) < width))
04139 scale+=kernel[i+width/2-x];
04140 p++;
04141 q++;
04142 }
04143 scale = 1.0/scale;
04144 red = scale*(red+0.5);
04145 green = scale*(green+0.5);
04146 blue = scale*(blue+0.5);
04147 alpha = scale*(alpha+0.5);
04148
04149 red = red < 0 ? 0 : red > 65535 ? 65535 : red;
04150 green = green < 0 ? 0 : green > 65535 ? 65535 : green;
04151 blue = blue < 0 ? 0 : blue > 65535 ? 65535 : blue;
04152 alpha = alpha < 0 ? 0 : alpha > 65535 ? 65535 : alpha;
04153
04154 dest[x] = qRgba((
unsigned char)(red/257UL),
04155 (
unsigned char)(green/257UL),
04156 (
unsigned char)(blue/257UL),
04157 (
unsigned char)(alpha/257UL));
04158 }
04159
return;
04160 }
04161
04162
for(x=0; x < width/2; ++x){
04163 scale = 0.0;
04164 red = blue = green = alpha = 0.0;
04165 p = kernel+width/2-x;
04166 q = src;
04167
for(i=width/2-x; i < width; ++i){
04168 red += (*p)*(qRed(*q)*257);
04169 green += (*p)*(qGreen(*q)*257);
04170 blue += (*p)*(qBlue(*q)*257);
04171 alpha += (*p)*(qAlpha(*q)*257);
04172 scale += (*p);
04173 p++;
04174 q++;
04175 }
04176 scale=1.0/scale;
04177
04178 red = scale*(red+0.5);
04179 green = scale*(green+0.5);
04180 blue = scale*(blue+0.5);
04181 alpha = scale*(alpha+0.5);
04182
04183 red = red < 0 ? 0 : red > 65535 ? 65535 : red;
04184 green = green < 0 ? 0 : green > 65535 ? 65535 : green;
04185 blue = blue < 0 ? 0 : blue > 65535 ? 65535 : blue;
04186 alpha = alpha < 0 ? 0 : alpha > 65535 ? 65535 : alpha;
04187
04188 dest[x] = qRgba((
unsigned char)(red/257UL),
04189 (
unsigned char)(green/257UL),
04190 (
unsigned char)(blue/257UL),
04191 (
unsigned char)(alpha/257UL));
04192 }
04193
04194
for(; x < columns-width/2; ++x){
04195 red = blue = green = alpha = 0.0;
04196 p = kernel;
04197 q = src+(x-width/2);
04198
for (i=0; i < (
long) width; ++i){
04199 red += (*p)*(qRed(*q)*257);
04200 green += (*p)*(qGreen(*q)*257);
04201 blue += (*p)*(qBlue(*q)*257);
04202 alpha += (*p)*(qAlpha(*q)*257);
04203 p++;
04204 q++;
04205 }
04206 red = scale*(red+0.5);
04207 green = scale*(green+0.5);
04208 blue = scale*(blue+0.5);
04209 alpha = scale*(alpha+0.5);
04210
04211 red = red < 0 ? 0 : red > 65535 ? 65535 : red;
04212 green = green < 0 ? 0 : green > 65535 ? 65535 : green;
04213 blue = blue < 0 ? 0 : blue > 65535 ? 65535 : blue;
04214 alpha = alpha < 0 ? 0 : alpha > 65535 ? 65535 : alpha;
04215
04216 dest[x] = qRgba((
unsigned char)(red/257UL),
04217 (
unsigned char)(green/257UL),
04218 (
unsigned char)(blue/257UL),
04219 (
unsigned char)(alpha/257UL));
04220 }
04221
04222
for(; x < columns; ++x){
04223 red = blue = green = alpha = 0.0;
04224 scale=0;
04225 p = kernel;
04226 q = src+(x-width/2);
04227
for(i=0; i < columns-x+width/2; ++i){
04228 red += (*p)*(qRed(*q)*257);
04229 green += (*p)*(qGreen(*q)*257);
04230 blue += (*p)*(qBlue(*q)*257);
04231 alpha += (*p)*(qAlpha(*q)*257);
04232 scale += (*p);
04233 p++;
04234 q++;
04235 }
04236 scale=1.0/scale;
04237 red = scale*(red+0.5);
04238 green = scale*(green+0.5);
04239 blue = scale*(blue+0.5);
04240 alpha = scale*(alpha+0.5);
04241
04242 red = red < 0 ? 0 : red > 65535 ? 65535 : red;
04243 green = green < 0 ? 0 : green > 65535 ? 65535 : green;
04244 blue = blue < 0 ? 0 : blue > 65535 ? 65535 : blue;
04245 alpha = alpha < 0 ? 0 : alpha > 65535 ? 65535 : alpha;
04246
04247 dest[x] = qRgba((
unsigned char)(red/257UL),
04248 (
unsigned char)(green/257UL),
04249 (
unsigned char)(blue/257UL),
04250 (
unsigned char)(alpha/257UL));
04251 }
04252 }
04253
04254
int KImageEffect::getBlurKernel(
int width,
double sigma,
double **kernel)
04255 {
04256
#define KernelRank 3
04257
double alpha,
normalize;
04258
register long i;
04259
int bias;
04260
04261 assert(sigma != 0.0);
04262
if(width == 0)
04263 width = 3;
04264 *kernel=(
double *)malloc(width*
sizeof(
double));
04265
if(*kernel == (
double *)NULL)
04266
return(0);
04267 memset(*kernel, 0, width*
sizeof(
double));
04268 bias = KernelRank*width/2;
04269
for(i=(-bias); i <= bias; i++){
04270 alpha=exp(-((
double) i*i)/(2.0*KernelRank*KernelRank*sigma*sigma));
04271 (*kernel)[(i+bias)/KernelRank]+=alpha/(MagickSQ2PI*sigma);
04272 }
04273 normalize=0;
04274
for(i=0; i < width; i++)
04275 normalize+=(*kernel)[i];
04276
for(i=0; i < width; i++)
04277 (*kernel)[i]/=normalize;
04278
04279
return(width);
04280 }
04281
04282 QImage KImageEffect::blur(
QImage &src,
double )
04283 {
04284
04285
return(
blur(src, 0, 1));
04286 }
04287
04288 QImage KImageEffect::blur(
QImage &src,
double radius,
double sigma)
04289 {
04290
double *kernel;
04291
QImage dest;
04292
int width;
04293
int x, y;
04294
unsigned int *scanline, *temp;
04295
unsigned int *p, *q;
04296
04297
if(sigma == 0.0){
04298 qWarning(
"KImageEffect::blur(): Zero sigma is not permitted!");
04299
return(dest);
04300 }
04301
if(src.depth() < 32)
04302 src = src.convertDepth(32);
04303
04304 kernel=(
double *) NULL;
04305
if(radius > 0)
04306 width=getBlurKernel((
int) (2*ceil(radius)+1),sigma,&kernel);
04307
else{
04308
double *last_kernel;
04309 last_kernel=(
double *) NULL;
04310 width=getBlurKernel(3,sigma,&kernel);
04311
04312
while ((
long) (MaxRGB*kernel[0]) > 0){
04313
if(last_kernel != (
double *)NULL){
04314 liberateMemory((
void **) &last_kernel);
04315 }
04316 last_kernel=kernel;
04317 kernel = (
double *)NULL;
04318 width = getBlurKernel(width+2, sigma, &kernel);
04319 }
04320
if(last_kernel != (
double *) NULL){
04321 liberateMemory((
void **) &kernel);
04322 width-=2;
04323 kernel = last_kernel;
04324 }
04325 }
04326
04327
if(width < 3){
04328 qWarning(
"KImageEffect::blur(): Kernel radius is too small!");
04329 liberateMemory((
void **) &kernel);
04330
return(dest);
04331 }
04332
04333 dest.create(src.width(), src.height(), 32);
04334
04335 scanline = (
unsigned int *)malloc(
sizeof(
unsigned int)*src.height());
04336 temp = (
unsigned int *)malloc(
sizeof(
unsigned int)*src.height());
04337
for(y=0; y < src.height(); ++y){
04338 p = (
unsigned int *)src.scanLine(y);
04339 q = (
unsigned int *)dest.scanLine(y);
04340 blurScanLine(kernel, width, p, q, src.width());
04341 }
04342
04343
unsigned int **srcTable = (
unsigned int **)src.jumpTable();
04344
unsigned int **destTable = (
unsigned int **)dest.jumpTable();
04345
for(x=0; x < src.width(); ++x){
04346
for(y=0; y < src.height(); ++y){
04347 scanline[y] = srcTable[y][x];
04348 }
04349 blurScanLine(kernel, width, scanline, temp, src.height());
04350
for(y=0; y < src.height(); ++y){
04351 destTable[y][x] = temp[y];
04352 }
04353 }
04354 liberateMemory((
void **) &scanline);
04355 liberateMemory((
void **) &temp);
04356 liberateMemory((
void **) &kernel);
04357
return(dest);
04358 }
04359
04360
bool KImageEffect::convolveImage(
QImage *image,
QImage *dest,
04361
const unsigned int order,
04362
const double *kernel)
04363 {
04364
long width;
04365
double red, green, blue, alpha;
04366
double normalize, *normal_kernel;
04367
register const double *k;
04368
register unsigned int *q;
04369
int x, y, mx, my, sx, sy;
04370
long i;
04371
int mcx, mcy;
04372
04373 width = order;
04374
if((width % 2) == 0){
04375 qWarning(
"KImageEffect: Kernel width must be an odd number!");
04376
return(
false);
04377 }
04378 normal_kernel = (
double *)malloc(width*width*
sizeof(
double));
04379
if(!normal_kernel){
04380 qWarning(
"KImageEffect: Unable to allocate memory!");
04381
return(
false);
04382 }
04383 dest->reset();
04384 dest->create(image->width(), image->height(), 32);
04385
if(image->depth() < 32)
04386 *image = image->convertDepth(32);
04387
04388 normalize=0.0;
04389
for(i=0; i < (width*width); i++)
04390 normalize += kernel[i];
04391
if(fabs(normalize) <= MagickEpsilon)
04392 normalize=1.0;
04393 normalize=1.0/normalize;
04394
for(i=0; i < (width*width); i++)
04395 normal_kernel[i] = normalize*kernel[i];
04396
04397
unsigned int **jumpTable = (
unsigned int **)image->jumpTable();
04398
for(y=0; y < dest->height(); ++y){
04399 sy = y-(width/2);
04400 q = (
unsigned int *)dest->scanLine(y);
04401
for(x=0; x < dest->width(); ++x){
04402 k = normal_kernel;
04403 red = green = blue = alpha = 0;
04404 sy = y-(width/2);
04405
for(mcy=0; mcy < width; ++mcy, ++sy){
04406 my = sy < 0 ? 0 : sy > image->height()-1 ?
04407 image->height()-1 : sy;
04408 sx = x+(-width/2);
04409
for(mcx=0; mcx < width; ++mcx, ++sx){
04410 mx = sx < 0 ? 0 : sx > image->width()-1 ?
04411 image->width()-1 : sx;
04412 red += (*k)*(qRed(jumpTable[my][mx])*257);
04413 green += (*k)*(qGreen(jumpTable[my][mx])*257);
04414 blue += (*k)*(qBlue(jumpTable[my][mx])*257);
04415 alpha += (*k)*(qAlpha(jumpTable[my][mx])*257);
04416 ++k;
04417 }
04418 }
04419
04420 red = red < 0 ? 0 : red > 65535 ? 65535 : red+0.5;
04421 green = green < 0 ? 0 : green > 65535 ? 65535 : green+0.5;
04422 blue = blue < 0 ? 0 : blue > 65535 ? 65535 : blue+0.5;
04423 alpha = alpha < 0 ? 0 : alpha > 65535 ? 65535 : alpha+0.5;
04424
04425 *q++ = qRgba((
unsigned char)(red/257UL),
04426 (
unsigned char)(green/257UL),
04427 (
unsigned char)(blue/257UL),
04428 (
unsigned char)(alpha/257UL));
04429 }
04430 }
04431 free(normal_kernel);
04432
return(
true);
04433
04434 }
04435
04436
int KImageEffect::getOptimalKernelWidth(
double radius,
double sigma)
04437 {
04438
double normalize, value;
04439
long width;
04440
register long u;
04441
04442 assert(sigma != 0.0);
04443
if(radius > 0.0)
04444
return((
int)(2.0*ceil(radius)+1.0));
04445
for(width=5; ;){
04446 normalize=0.0;
04447
for(u=(-width/2); u <= (width/2); u++)
04448 normalize+=exp(-((
double) u*u)/(2.0*sigma*sigma))/(MagickSQ2PI*sigma);
04449 u=width/2;
04450 value=exp(-((
double) u*u)/(2.0*sigma*sigma))/(MagickSQ2PI*sigma)/normalize;
04451
if((
long)(65535*value) <= 0)
04452
break;
04453 width+=2;
04454 }
04455
return((
int)width-2);
04456 }
04457
04458 QImage KImageEffect::sharpen(
QImage &src,
double )
04459 {
04460
04461
return(
sharpen(src, 0, 1));
04462 }
04463
04464 QImage KImageEffect::sharpen(
QImage &image,
double radius,
double sigma)
04465 {
04466
double alpha, normalize, *kernel;
04467
int width;
04468
register long i, u, v;
04469
QImage dest;
04470
04471
if(sigma == 0.0){
04472 qWarning(
"KImageEffect::sharpen(): Zero sigma is not permitted!");
04473
return(dest);
04474 }
04475 width = getOptimalKernelWidth(radius, sigma);
04476
if(image.width() < width){
04477 qWarning(
"KImageEffect::sharpen(): Image is smaller than radius!");
04478
return(dest);
04479 }
04480 kernel = (
double *)malloc(width*width*
sizeof(
double));
04481
if(!kernel){
04482 qWarning(
"KImageEffect::sharpen(): Unable to allocate memory!");
04483
return(dest);
04484 }
04485
04486 i = 0;
04487 normalize=0.0;
04488
for(v=(-width/2); v <= (width/2); v++){
04489
for(u=(-width/2); u <= (width/2); u++){
04490 alpha=exp(-((
double) u*u+v*v)/(2.0*sigma*sigma));
04491 kernel[i]=alpha/(2.0*MagickPI*sigma*sigma);
04492 normalize+=kernel[i];
04493 i++;
04494 }
04495 }
04496 kernel[i/2]=(-2.0)*normalize;
04497 convolveImage(&image, &dest, width, kernel);
04498 liberateMemory((
void **) &kernel);
04499
return(dest);
04500 }
04501
04502
04503
04504 QImage KImageEffect::shade(
QImage &src,
bool color_shading,
double azimuth,
04505
double elevation)
04506 {
04507
struct PointInfo{
04508
double x, y, z;
04509 };
04510
04511
double distance, normal_distance,
shade;
04512
int x, y;
04513
04514
struct PointInfo light, normal;
04515
04516
unsigned int *q;
04517
04518
QImage dest(src.width(), src.height(), 32);
04519
04520 azimuth = DegreesToRadians(azimuth);
04521 elevation = DegreesToRadians(elevation);
04522 light.x = MaxRGB*cos(azimuth)*cos(elevation);
04523 light.y = MaxRGB*sin(azimuth)*cos(elevation);
04524 light.z = MaxRGB*sin(elevation);
04525 normal.z= 2*MaxRGB;
04526
04527
if(src.depth() > 8){
04528
unsigned int *p, *s0, *s1, *s2;
04529
for(y=0; y < src.height(); ++y){
04530 p = (
unsigned int *)src.scanLine(QMIN(QMAX(y-1,0),src.height()-3));
04531 q = (
unsigned int *)dest.scanLine(y);
04532
04533 *q++=(*(p+src.width()));
04534 p++;
04535 s0 = p;
04536 s1 = p + src.width();
04537 s2 = p + 2*src.width();
04538
for(x=1; x < src.width()-1; ++x){
04539
04540 normal.x=intensityValue(*(s0-1))+intensityValue(*(s1-1))+intensityValue(*(s2-1))-
04541 (
double) intensityValue(*(s0+1))-(
double) intensityValue(*(s1+1))-
04542 (
double) intensityValue(*(s2+1));
04543 normal.y=intensityValue(*(s2-1))+intensityValue(*s2)+intensityValue(*(s2+1))-
04544 (
double) intensityValue(*(s0-1))-(
double) intensityValue(*s0)-
04545 (
double) intensityValue(*(s0+1));
04546
if((normal.x == 0) && (normal.y == 0))
04547 shade=light.z;
04548
else{
04549 shade=0.0;
04550 distance=normal.x*light.x+normal.y*light.y+normal.z*light.z;
04551
if (distance > 0.0){
04552 normal_distance=
04553 normal.x*normal.x+normal.y*normal.y+normal.z*normal.z;
04554
if(fabs(normal_distance) > 0.0000001)
04555 shade=distance/sqrt(normal_distance);
04556 }
04557 }
04558
if(!color_shading){
04559 *q = qRgba((
unsigned char)(shade),
04560 (
unsigned char)(shade),
04561 (
unsigned char)(shade),
04562 qAlpha(*s1));
04563 }
04564
else{
04565 *q = qRgba((
unsigned char)((shade*qRed(*s1))/(MaxRGB+1)),
04566 (
unsigned char)((shade*qGreen(*s1))/(MaxRGB+1)),
04567 (
unsigned char)((shade*qBlue(*s1))/(MaxRGB+1)),
04568 qAlpha(*s1));
04569 }
04570 ++s0;
04571 ++s1;
04572 ++s2;
04573 q++;
04574 }
04575 *q++=(*s1);
04576 }
04577 }
04578
else{
04579
unsigned char *p, *s0, *s1, *s2;
04580
int scanLineIdx;
04581
unsigned int *cTable = (
unsigned int *)src.colorTable();
04582
for(y=0; y < src.height(); ++y){
04583 scanLineIdx = QMIN(QMAX(y-1,0),src.height()-3);
04584 p = (
unsigned char *)src.scanLine(scanLineIdx);
04585 q = (
unsigned int *)dest.scanLine(y);
04586
04587 s0 = p;
04588 s1 = (
unsigned char *) src.scanLine(scanLineIdx+1);
04589 s2 = (
unsigned char *) src.scanLine(scanLineIdx+2);
04590 *q++=(*(cTable+(*s1)));
04591 ++p;
04592 ++s0;
04593 ++s1;
04594 ++s2;
04595
for(x=1; x < src.width()-1; ++x){
04596
04597 normal.x=intensityValue(*(cTable+(*(s0-1))))+intensityValue(*(cTable+(*(s1-1))))+intensityValue(*(cTable+(*(s2-1))))-
04598 (
double) intensityValue(*(cTable+(*(s0+1))))-(
double) intensityValue(*(cTable+(*(s1+1))))-
04599 (
double) intensityValue(*(cTable+(*(s2+1))));
04600 normal.y=intensityValue(*(cTable+(*(s2-1))))+intensityValue(*(cTable+(*s2)))+intensityValue(*(cTable+(*(s2+1))))-
04601 (
double) intensityValue(*(cTable+(*(s0-1))))-(
double) intensityValue(*(cTable+(*s0)))-
04602 (
double) intensityValue(*(cTable+(*(s0+1))));
04603
if((normal.x == 0) && (normal.y == 0))
04604 shade=light.z;
04605
else{
04606 shade=0.0;
04607 distance=normal.x*light.x+normal.y*light.y+normal.z*light.z;
04608
if (distance > 0.0){
04609 normal_distance=
04610 normal.x*normal.x+normal.y*normal.y+normal.z*normal.z;
04611
if(fabs(normal_distance) > 0.0000001)
04612 shade=distance/sqrt(normal_distance);
04613 }
04614 }
04615
if(!color_shading){
04616 *q = qRgba((
unsigned char)(shade),
04617 (
unsigned char)(shade),
04618 (
unsigned char)(shade),
04619 qAlpha(*(cTable+(*s1))));
04620 }
04621
else{
04622 *q = qRgba((
unsigned char)((shade*qRed(*(cTable+(*s1))))/(MaxRGB+1)),
04623 (
unsigned char)((shade*qGreen(*(cTable+(*s1))))/(MaxRGB+1)),
04624 (
unsigned char)((shade*qBlue(*(cTable+(*s1))))/(MaxRGB+1)),
04625 qAlpha(*s1));
04626 }
04627 ++s0;
04628 ++s1;
04629 ++s2;
04630 q++;
04631 }
04632 *q++=(*(cTable+(*s1)));
04633 }
04634 }
04635
return(dest);
04636 }
04637
04638
04639
04640
04641
04642 void KImageEffect::contrastHSV(
QImage &img,
bool sharpen)
04643 {
04644
int i, sign;
04645
unsigned int *data;
04646
int count;
04647
double brightness, scale, theta;
04648
QColor c;
04649
int h, s, v;
04650
04651 sign = sharpen ? 1 : -1;
04652 scale=0.5000000000000001;
04653
if(img.depth() > 8){
04654 count = img.width()*img.height();
04655 data = (
unsigned int *)img.bits();
04656 }
04657
else{
04658 count = img.numColors();
04659 data = (
unsigned int *)img.colorTable();
04660 }
04661
for(i=0; i < count; ++i){
04662 c.setRgb(data[i]);
04663 c.hsv(&h, &s, &v);
04664 brightness = v/255.0;
04665 theta=(brightness-0.5)*M_PI;
04666 brightness+=scale*(((scale*((sin(theta)+1.0)))-brightness)*sign);
04667
if (brightness > 1.0)
04668 brightness=1.0;
04669
else
04670
if (brightness < 0)
04671 brightness=0.0;
04672 v = (
int)(brightness*255);
04673 c.setHsv(h, s, v);
04674 data[i] = qRgba(c.red(), c.green(), c.blue(), qAlpha(data[i]));
04675 }
04676 }
04677
04678
04679
struct BumpmapParams {
04680 BumpmapParams(
double bm_azimuth,
double bm_elevation,
04681
int bm_depth, KImageEffect::BumpmapType bm_type,
04682
bool invert ) {
04683
04684
double azimuth = DegreesToRadians( bm_azimuth );
04685
double elevation = DegreesToRadians( bm_elevation );
04686
04687
04688 lx = (
int)( cos(azimuth) * cos(elevation) * 255.0 );
04689 ly = (
int)( sin(azimuth) * cos(elevation) * 255.0 );
04690
int lz = (
int)( sin(elevation) * 255.0 );
04691
04692
04693
int nz = (6 * 255) / bm_depth;
04694 nz2 = nz * nz;
04695 nzlz = nz * lz;
04696
04697
04698 background = lz;
04699
04700
04701 compensation = sin(elevation);
04702
04703
04704
for (
int i = 0; i < 256; i++)
04705 {
04706
double n = 0;
04707
switch (bm_type)
04708 {
04709
case KImageEffect::Spherical:
04710 n = i / 255.0 - 1.0;
04711 lut[i] = (
int) (255.0 * sqrt(1.0 - n * n) + 0.5);
04712
break;
04713
04714
case KImageEffect::Sinuosidal:
04715 n = i / 255.0;
04716 lut[i] = (
int) (255.0 * (sin((-M_PI / 2.0) + M_PI * n) + 1.0) /
04717 2.0 + 0.5);
04718
break;
04719
04720
case KImageEffect::Linear:
04721
default:
04722 lut[i] = i;
04723 }
04724
04725
if (invert)
04726 lut[i] = 255 - lut[i];
04727 }
04728 }
04729
int lx, ly;
04730
int nz2, nzlz;
04731
int background;
04732
double compensation;
04733 uchar lut[256];
04734 };
04735
04736
04737
static void bumpmap_convert_row( uint *row,
04738
int width,
04739
int bpp,
04740
int has_alpha,
04741 uchar *lut,
04742
int waterlevel )
04743 {
04744 uint *p;
04745
04746 p = row;
04747
04748 has_alpha = has_alpha ? 1 : 0;
04749
04750
if (bpp >= 3)
04751
for (; width; width--)
04752 {
04753
if (has_alpha) {
04754
unsigned int idx = (
unsigned int)(intensityValue( *row ) + 0.5);
04755 *p++ = lut[(
unsigned int) ( waterlevel +
04756 ( ( idx -
04757 waterlevel) * qBlue( *row )) / 255.0 )];
04758 }
else {
04759
unsigned int idx = (
unsigned int)(intensityValue( *row ) + 0.5);
04760 *p++ = lut[idx];
04761 }
04762
04763 ++row;
04764 }
04765 }
04766
04767
static void bumpmap_row( uint *src,
04768 uint *dest,
04769
int width,
04770
int bpp,
04771
int has_alpha,
04772 uint *bm_row1,
04773 uint *bm_row2,
04774 uint *bm_row3,
04775
int bm_width,
04776
int bm_xofs,
04777
bool tiled,
04778
bool row_in_bumpmap,
04779
int ambient,
04780
bool compensate,
04781 BumpmapParams *params )
04782 {
04783
int xofs1, xofs2, xofs3;
04784
int shade;
04785
int ndotl;
04786
int nx, ny;
04787
int x;
04788
int pbpp;
04789
int tmp;
04790
04791
if (has_alpha)
04792 pbpp = bpp - 1;
04793
else
04794 pbpp = bpp;
04795
04796 tmp = bm_xofs;
04797 xofs2 = MOD(tmp, bm_width);
04798
04799
for (x = 0; x < width; x++)
04800 {
04801
04802
04803
if (tiled || (row_in_bumpmap &&
04804 x >= - tmp && x < - tmp + bm_width)) {
04805
if (tiled) {
04806 xofs1 = MOD(xofs2 - 1, bm_width);
04807 xofs3 = MOD(xofs2 + 1, bm_width);
04808 }
else {
04809 xofs1 = FXCLAMP(xofs2 - 1, 0, bm_width - 1);
04810 xofs3 = FXCLAMP(xofs2 + 1, 0, bm_width - 1);
04811 }
04812 nx = (bm_row1[xofs1] + bm_row2[xofs1] + bm_row3[xofs1] -
04813 bm_row1[xofs3] - bm_row2[xofs3] - bm_row3[xofs3]);
04814 ny = (bm_row3[xofs1] + bm_row3[xofs2] + bm_row3[xofs3] -
04815 bm_row1[xofs1] - bm_row1[xofs2] - bm_row1[xofs3]);
04816 }
else {
04817 nx = ny = 0;
04818 }
04819
04820
04821
04822
if ((nx == 0) && (ny == 0))
04823 shade = params->background;
04824
else {
04825 ndotl = nx * params->lx + ny * params->ly + params->nzlz;
04826
04827
if (ndotl < 0)
04828 shade = (
int)( params->compensation * ambient );
04829
else {
04830 shade = (
int)( ndotl / sqrt(
double(nx * nx + ny * ny + params->nz2)) );
04831
04832 shade = (
int)( shade + QMAX(0.0, (255 * params->compensation - shade)) *
04833 ambient / 255 );
04834 }
04835 }
04836
04837
04838
04843
if (compensate) {
04844
int red = (
int)((qRed( *src ) * shade) / (params->compensation * 255));
04845
int green = (
int)((qGreen( *src ) * shade) / (params->compensation * 255));
04846
int blue = (
int)((qBlue( *src ) * shade) / (params->compensation * 255));
04847
int alpha = (
int)((qAlpha( *src ) * shade) / (params->compensation * 255));
04848 ++src;
04849 *dest++ = qRgba( red, green, blue, alpha );
04850 }
else {
04851
int red = qRed( *src ) * shade / 255;
04852
int green = qGreen( *src ) * shade / 255;
04853
int blue = qBlue( *src ) * shade / 255;
04854
int alpha = qAlpha( *src ) * shade / 255;
04855 ++src;
04856 *dest++ = qRgba( red, green, blue, alpha );
04857 }
04858
04859
04860
04861
if (++xofs2 == bm_width)
04862 xofs2 = 0;
04863 }
04864 }
04865
04885 QImage KImageEffect::bumpmap(
QImage &img,
QImage &map,
double azimuth,
double elevation,
04886
int depth,
int xofs,
int yofs,
int waterlevel,
04887
int ambient,
bool compensate,
bool invert,
04888 BumpmapType type,
bool tiled)
04889 {
04890
QImage dst;
04891
04892
if ( img.depth() != 32 || img.depth() != 32 ) {
04893 qWarning(
"Bump-mapping effect works only with 32 bit images");
04894
return dst;
04895 }
04896
04897 dst.create( img.width(), img.height(), img.depth() );
04898
int bm_width = map.width();
04899
int bm_height = map.height();
04900
int bm_bpp = map.depth();
04901
int bm_has_alpha = map.hasAlphaBuffer();
04902
04903
int yofs1, yofs2, yofs3;
04904
04905
if ( tiled ) {
04906 yofs2 = MOD( yofs, bm_height );
04907 yofs1 = MOD( yofs2 - 1, bm_height);
04908 yofs3 = MOD( yofs2 + 1, bm_height);
04909 }
else {
04910 yofs1 = 0;
04911 yofs2 = 0;
04912 yofs3 = FXCLAMP( yofs2+1, 0, bm_height - 1 );
04913 }
04914
04915 BumpmapParams params( azimuth, elevation, depth, type, invert );
04916
04917 uint* bm_row1 = (
unsigned int*)map.scanLine( yofs1 );
04918 uint* bm_row2 = (
unsigned int*)map.scanLine( yofs2 );
04919 uint* bm_row3 = (
unsigned int*)map.scanLine( yofs3 );
04920
04921 bumpmap_convert_row( bm_row1, bm_width, bm_bpp, bm_has_alpha, params.lut, waterlevel );
04922 bumpmap_convert_row( bm_row2, bm_width, bm_bpp, bm_has_alpha, params.lut, waterlevel );
04923 bumpmap_convert_row( bm_row3, bm_width, bm_bpp, bm_has_alpha, params.lut, waterlevel );
04924
04925
for (
int y = 0; y < img.height(); ++y)
04926 {
04927
int row_in_bumpmap = (y >= - yofs && y < - yofs + bm_height);
04928
04929 uint* src_row = (
unsigned int*)img.scanLine( y );
04930 uint* dest_row = (
unsigned int*)dst.scanLine( y );
04931
04932 bumpmap_row( src_row, dest_row, img.width(), img.depth(), img.hasAlphaBuffer(),
04933 bm_row1, bm_row2, bm_row3, bm_width, xofs,
04934 tiled,
04935 row_in_bumpmap, ambient, compensate,
04936 ¶ms );
04937
04938
04939
04940
if (tiled || row_in_bumpmap)
04941 {
04942 uint* bm_tmprow = bm_row1;
04943 bm_row1 = bm_row2;
04944 bm_row2 = bm_row3;
04945 bm_row3 = bm_tmprow;
04946
04947
if (++yofs2 == bm_height)
04948 yofs2 = 0;
04949
04950
if (tiled)
04951 yofs3 = MOD(yofs2 + 1, bm_height);
04952
else
04953 yofs3 = FXCLAMP(yofs2 + 1, 0, bm_height - 1);
04954
04955 bm_row3 = (
unsigned int*)map.scanLine( yofs3 );
04956 bumpmap_convert_row( bm_row3, bm_width, bm_bpp, bm_has_alpha,
04957 params.lut, waterlevel );
04958 }
04959 }
04960
return dst;
04961 }