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
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063 #define _USE_MATH_DEFINES // for msvc
00064
00065 #include "qimageblitz.h"
00066 #include "private/blitz_p.h"
00067 #include <config-processor.h>
00068 #include "blitzcpu.h"
00069 #include "private/interpolate.h"
00070 #include "private/inlinehsv.h"
00071 #include <cmath>
00072 #ifndef M_PI
00073
00074 #include "math.h"
00075 #endif
00076 #include <string.h>
00077 #include <QVector>
00078 #include <QColor>
00079
00080 #if defined(__i386__) && ( defined(__GNUC__) || defined(__INTEL_COMPILER) )
00081 # if defined(HAVE_MMX )
00082 # define USE_MMX_INLINE_ASM
00083 # endif
00084 #endif
00085
00086 QImage& Blitz::despeckle(QImage &img)
00087 {
00088 if(img.isNull())
00089 return(img);
00090
00091 int length, x, y, j, i;
00092 QRgb *src, *dest;
00093 unsigned char *buffer, *pixels;
00094 int w = img.width();
00095 int h = img.height();
00096
00097 static const int
00098 X[4]= {0, 1, 1,-1},
00099 Y[4]= {1, 0, 1, 1};
00100
00101 length = (img.width()+2)*(img.height()+2);
00102 pixels = new unsigned char[length];
00103 buffer = new unsigned char[length];
00104
00105 if(img.depth() != 32){
00106 img = img.convertToFormat(img.hasAlphaChannel() ?
00107 QImage::Format_ARGB32 :
00108 QImage::Format_RGB32);
00109 }
00110 else if(img.format() == QImage::Format_ARGB32_Premultiplied)
00111 img = img.convertToFormat(QImage::Format_ARGB32);
00112
00113
00114
00115
00116
00117
00118 (void)memset(pixels, 0, length);
00119 j = w+2;
00120 for(y=0; y < h; ++y, ++j){
00121 src = (QRgb *)img.scanLine(y);
00122 ++j;
00123 for(x=w-1; x >= 0; --x, ++src, ++j)
00124 pixels[j] = qRed(*src);
00125 }
00126 (void)memset(buffer, 0, length);
00127 for(i=0; i < 4; ++i){
00128 BlitzPrivate::hull(X[i], Y[i], w, h, pixels, buffer, 1);
00129 BlitzPrivate::hull(-X[i], -Y[i], w, h, pixels, buffer, 1);
00130 BlitzPrivate::hull(-X[i], -Y[i], w, h, pixels, buffer, -1);
00131 BlitzPrivate::hull(X[i], Y[i], w, h, pixels, buffer, -1);
00132 }
00133 j = w+2;
00134 for(y=0; y < h; ++y, ++j){
00135 dest = (QRgb *)img.scanLine(y);
00136 ++j;
00137 for(x=w-1; x >= 0; --x, ++dest, ++j)
00138 *dest = qRgba(pixels[j], qGreen(*dest), qBlue(*dest),
00139 qAlpha(*dest));
00140 }
00141
00142
00143 (void)memset(pixels, 0, length);
00144 j = w+2;
00145 for(y=0; y < h; ++y, ++j){
00146 src = (QRgb *)img.scanLine(y);
00147 ++j;
00148 for(x=w-1; x >= 0; --x, ++src, ++j)
00149 pixels[j] = qGreen(*src);
00150 }
00151 (void)memset(buffer, 0, length);
00152 for(i=0; i < 4; ++i){
00153 BlitzPrivate::hull(X[i], Y[i], w, h, pixels, buffer, 1);
00154 BlitzPrivate::hull(-X[i], -Y[i], w, h, pixels, buffer, 1);
00155 BlitzPrivate::hull(-X[i], -Y[i], w, h, pixels, buffer, -1);
00156 BlitzPrivate::hull(X[i], Y[i], w, h, pixels, buffer, -1);
00157 }
00158 j = w+2;
00159 for(y=0; y < h; ++y, ++j){
00160 dest = (QRgb *)img.scanLine(y);
00161 ++j;
00162 for(x=w-1; x >= 0; --x, ++dest, ++j)
00163 *dest = qRgba(qRed(*dest), pixels[j], qBlue(*dest),
00164 qAlpha(*dest));
00165 }
00166
00167
00168 (void)memset(pixels, 0, length);
00169 j = w+2;
00170 for(y=0; y < h; ++y, ++j){
00171 src = (QRgb *)img.scanLine(y);
00172 ++j;
00173 for(x=w-1; x >= 0; --x, ++src, ++j)
00174 pixels[j] = qBlue(*src);
00175 }
00176 (void)memset(buffer, 0, length);
00177 for(i=0; i < 4; ++i){
00178 BlitzPrivate::hull(X[i], Y[i], w, h, pixels, buffer, 1);
00179 BlitzPrivate::hull(-X[i], -Y[i], w, h, pixels, buffer, 1);
00180 BlitzPrivate::hull(-X[i], -Y[i], w, h, pixels, buffer, -1);
00181 BlitzPrivate::hull(X[i], Y[i], w, h, pixels, buffer, -1);
00182 }
00183 j = w+2;
00184 for(y=0; y < h; ++y, ++j){
00185 dest = (QRgb *)img.scanLine(y);
00186 ++j;
00187 for(x=w-1; x >= 0; --x, ++dest, ++j)
00188 *dest = qRgba(qRed(*dest), qGreen(*dest), pixels[j],
00189 qAlpha(*dest));
00190 }
00191
00192 delete[] pixels;
00193 delete[] buffer;
00194 return(img);
00195 }
00196
00197 QImage Blitz::blur(QImage &img, int radius)
00198 {
00199 QRgb *p1, *p2;
00200 int x, y, w, h, mx, my, mw, mh, mt, xx, yy;
00201 int a, r, g, b;
00202 int *as, *rs, *gs, *bs;
00203
00204 if(radius < 1 || img.isNull() || img.width() < (radius << 1))
00205 return(img);
00206
00207 w = img.width();
00208 h = img.height();
00209
00210 if(img.depth() < 8)
00211 img = img.convertToFormat(QImage::Format_Indexed8);
00212 QImage buffer(w, h, img.hasAlphaChannel() ?
00213 QImage::Format_ARGB32 : QImage::Format_RGB32);
00214
00215 as = new int[w];
00216 rs = new int[w];
00217 gs = new int[w];
00218 bs = new int[w];
00219
00220 QVector<QRgb> colorTable;
00221 if(img.format() == QImage::Format_Indexed8)
00222 colorTable = img.colorTable();
00223
00224 for(y = 0; y < h; y++){
00225 my = y - radius;
00226 mh = (radius << 1) + 1;
00227 if(my < 0){
00228 mh += my;
00229 my = 0;
00230 }
00231 if((my + mh) > h)
00232 mh = h - my;
00233
00234 p1 = (QRgb *)buffer.scanLine(y);
00235 memset(as, 0, w * sizeof(int));
00236 memset(rs, 0, w * sizeof(int));
00237 memset(gs, 0, w * sizeof(int));
00238 memset(bs, 0, w * sizeof(int));
00239
00240 if(img.format() == QImage::Format_ARGB32_Premultiplied){
00241 QRgb pixel;
00242 for(yy = 0; yy < mh; yy++){
00243 p2 = (QRgb *)img.scanLine(yy + my);
00244 for(x = 0; x < w; x++, p2++){
00245 pixel = BlitzPrivate::convertFromPremult(*p2);
00246 as[x] += qAlpha(pixel);
00247 rs[x] += qRed(pixel);
00248 gs[x] += qGreen(pixel);
00249 bs[x] += qBlue(pixel);
00250 }
00251 }
00252 }
00253 else if(img.format() == QImage::Format_Indexed8){
00254 QRgb pixel;
00255 unsigned char *ptr;
00256 for(yy = 0; yy < mh; yy++){
00257 ptr = (unsigned char *)img.scanLine(yy + my);
00258 for(x = 0; x < w; x++, ptr++){
00259 pixel = colorTable[*ptr];
00260 as[x] += qAlpha(pixel);
00261 rs[x] += qRed(pixel);
00262 gs[x] += qGreen(pixel);
00263 bs[x] += qBlue(pixel);
00264 }
00265 }
00266 }
00267 else{
00268 for(yy = 0; yy < mh; yy++){
00269 p2 = (QRgb *)img.scanLine(yy + my);
00270 for(x = 0; x < w; x++, p2++){
00271 as[x] += qAlpha(*p2);
00272 rs[x] += qRed(*p2);
00273 gs[x] += qGreen(*p2);
00274 bs[x] += qBlue(*p2);
00275 }
00276 }
00277 }
00278
00279 for(x = 0; x < w; x++){
00280 a = r = g = b = 0;
00281 mx = x - radius;
00282 mw = (radius << 1) + 1;
00283 if(mx < 0){
00284 mw += mx;
00285 mx = 0;
00286 }
00287 if((mx + mw) > w)
00288 mw = w - mx;
00289 mt = mw * mh;
00290 for(xx = mx; xx < (mw + mx); xx++){
00291 a += as[xx];
00292 r += rs[xx];
00293 g += gs[xx];
00294 b += bs[xx];
00295 }
00296 a = a / mt;
00297 r = r / mt;
00298 g = g / mt;
00299 b = b / mt;
00300 *p1++ = qRgba(r, g, b, a);
00301 }
00302 }
00303 delete[] as;
00304 delete[] rs;
00305 delete[] gs;
00306 delete[] bs;
00307
00308 return(buffer);
00309 }
00310
00311 QImage Blitz::sharpen(QImage &img, int radius)
00312 {
00313 if(img.isNull() || radius < 1)
00314 return(img);
00315 if(img.depth() != 32){
00316 img = img.convertToFormat(img.hasAlphaChannel() ?
00317 QImage::Format_ARGB32 :
00318 QImage::Format_RGB32);
00319 }
00320 else if(img.format() == QImage::Format_ARGB32_Premultiplied)
00321 img = img.convertToFormat(QImage::Format_ARGB32);
00322
00323 QImage buffer(img.width(), img.height(), img.format());
00324 int a, r, g, b, x, y;
00325 int w = img.width();
00326 int h = img.height();
00327 QRgb *src, *dest;
00328
00329 memcpy(buffer.scanLine(0), img.scanLine(0), img.bytesPerLine());
00330 for(y=1; y < h-1; ++y){
00331 src = (QRgb *)img.scanLine(y);
00332 dest = (QRgb *)buffer.scanLine(y);
00333 *dest++ = *src++;
00334 for(x=1; x < w-1; ++x){
00335 r = qRed(*src)*5;
00336 g = qGreen(*src)*5;
00337 b = qBlue(*src)*5;
00338 a = qAlpha(*src)*5;
00339
00340 r -= qRed(*(src-1));
00341 g -= qGreen(*(src-1));
00342 b -= qBlue(*(src-1));
00343 a -= qAlpha(*(src-1));
00344 r -= qRed(*(src+1));
00345 g -= qGreen(*(src+1));
00346 b -= qBlue(*(src+1));
00347 a -= qAlpha(*(src+1));
00348
00349 r -= qRed(*(src-w));
00350 g -= qGreen(*(src-w));
00351 b -= qBlue(*(src-w));
00352 a -= qAlpha(*(src-w));
00353 r -= qRed(*(src+w));
00354 g -= qGreen(*(src+w));
00355 b -= qBlue(*(src+w));
00356 a -= qAlpha(*(src+w));
00357
00358 r = (r & ((~r) >> 16));
00359 r = ((r | ((r & 256) - ((r & 256) >> 8))));
00360 g = (g & ((~g) >> 16));
00361 g = ((g | ((g & 256) - ((g & 256) >> 8))));
00362 b = (b & ((~b) >> 16));
00363 b = ((b | ((b & 256) - ((b & 256) >> 8))));
00364 a = (a & ((~a) >> 16));
00365 a = ((a | ((a & 256) - ((a & 256) >> 8))));
00366
00367 *dest = qRgba(r, g, b, a);
00368 ++src; ++dest;
00369 }
00370 *dest++ = *src++;
00371 }
00372 memcpy(buffer.scanLine(h-1), img.scanLine(h-1), img.bytesPerLine());
00373 return(buffer);
00374 }
00375
00376
00377
00378
00379
00380
00381
00382
00383
00384
00385
00386
00387
00388
00389
00390
00391
00392
00393
00394
00395
00396 #define SOBEL(xm, ym, pixel) \
00397 xR += qRed((pixel))*(xm); xG += qGreen((pixel))*(xm); \
00398 xB += qBlue((pixel))*(xm); \
00399 yR += qRed((pixel))*(ym); yG += qGreen((pixel))*(ym); \
00400 yB += qBlue((pixel))*(ym);
00401
00402 QImage Blitz::edge(QImage &img)
00403 {
00404
00405 int x, y, w = img.width(), h = img.height();
00406 if(w < 3 || h < 3){
00407 qWarning("Blitz::edge(): Image is too small!");
00408 return(img);
00409 }
00410 if(img.isNull())
00411 return(img);
00412
00413 if(img.depth() != 32){
00414 img = img.convertToFormat(img.hasAlphaChannel() ?
00415 QImage::Format_ARGB32 :
00416 QImage::Format_RGB32);
00417 }
00418 else if(img.format() == QImage::Format_ARGB32_Premultiplied)
00419 img = img.convertToFormat(QImage::Format_ARGB32);
00420
00421 QImage buffer(w, h, QImage::Format_RGB32);
00422 QRgb *dest;
00423 QRgb *s, *scanblock[3];
00424
00425
00426 #ifdef USE_MMX_INLINE_ASM
00427 #ifdef __GNUC__
00428 #warning Using MMX sobel edge
00429 #endif
00430 if(BlitzCPUInfo::haveExtension(BlitzCPUInfo::MMX)){
00431 int xmatrix[] = {-1, 0, 1, -2, 0, 2, -1, 0, 1};
00432 int ymatrix[] = {1, 2, 1, 0, 0, 0, -1, -2, -1};
00433 int i, *xm, *ym;
00434
00435 for(y=0; y < h; ++y){
00436 scanblock[1] = (QRgb *)img.scanLine(y);
00437 dest = (QRgb *)buffer.scanLine(y);
00438 if(y == 0){
00439 scanblock[0] = (QRgb *)img.scanLine(y);
00440 scanblock[2] = (QRgb *)img.scanLine(y+1);
00441 }
00442 else if(y == h-1){
00443 scanblock[0] = (QRgb *)img.scanLine(y-1);
00444 scanblock[2] = (QRgb *)img.scanLine(y);
00445 }
00446 else{
00447 scanblock[0] = (QRgb *)img.scanLine(y-1);
00448 scanblock[2] = (QRgb *)img.scanLine(y+1);
00449 }
00450
00451
00452
00453 __asm__ __volatile__
00454 ("pxor %%mm7, %%mm7\n\t"
00455 "pxor %%mm5, %%mm5\n\t"
00456 "pxor %%mm6, %%mm6\n\t"
00457 : : );
00458 for(i=0, xm=xmatrix, ym=ymatrix; i < 3; ++i, xm+=3, ym+=3){
00459 s = scanblock[i];
00460 __asm__ __volatile__
00461 (
00462 "movd (%0), %%mm0\n\t"
00463 "punpcklbw %%mm7, %%mm0\n\t"
00464 "movq %%mm0, %%mm1\n\t"
00465 "movq %%mm0, %%mm4\n\t"
00466 "movd 0(%1), %%mm2\n\t"
00467 "punpckldq %%mm2, %%mm2\n\t"
00468 "packssdw %%mm2, %%mm2\n\t"
00469 "movd 0(%2), %%mm3\n\t"
00470 "punpckldq %%mm3, %%mm3\n\t"
00471 "packssdw %%mm3, %%mm3\n\t"
00472 "pmullw %%mm2, %%mm0\n\t"
00473 "pmullw %%mm3, %%mm1\n\t"
00474 "paddw %%mm0, %%mm5\n\t"
00475 "paddw %%mm1, %%mm6\n\t"
00476
00477 "movq %%mm4, %%mm1\n\t"
00478 "movd 4(%1), %%mm2\n\t"
00479 "punpckldq %%mm2, %%mm2\n\t"
00480 "packssdw %%mm2, %%mm2\n\t"
00481 "movd 4(%2), %%mm3\n\t"
00482 "punpckldq %%mm3, %%mm3\n\t"
00483 "packssdw %%mm3, %%mm3\n\t"
00484 "pmullw %%mm2, %%mm4\n\t"
00485 "pmullw %%mm3, %%mm1\n\t"
00486 "paddw %%mm4, %%mm5\n\t"
00487 "paddw %%mm1, %%mm6\n\t"
00488
00489 "movd 4(%0), %%mm0\n\t"
00490 "punpcklbw %%mm7, %%mm0\n\t"
00491 "movq %%mm0, %%mm1\n\t"
00492 "movd 8(%1), %%mm2\n\t"
00493 "punpckldq %%mm2, %%mm2\n\t"
00494 "packssdw %%mm2, %%mm2\n\t"
00495 "movd 8(%2), %%mm3\n\t"
00496 "punpckldq %%mm3, %%mm3\n\t"
00497 "packssdw %%mm3, %%mm3\n\t"
00498 "pmullw %%mm2, %%mm0\n\t"
00499 "pmullw %%mm3, %%mm1\n\t"
00500 "paddw %%mm0, %%mm5\n\t"
00501 "paddw %%mm1, %%mm6\n\t"
00502 : : "r"(s), "r"(xm), "r"(ym));
00503 }
00504 __asm__ __volatile__
00505 (
00506 "movq %%mm5, %%mm0\n\t"
00507 "psraw $15, %%mm0\n\t"
00508 "pxor %%mm0, %%mm5\n\t"
00509 "psubw %%mm0, %%mm5\n\t"
00510 "movq %%mm6, %%mm0\n\t"
00511 "psraw $15, %%mm0\n\t"
00512 "pxor %%mm0, %%mm6\n\t"
00513 "psubw %%mm0, %%mm6\n\t"
00514 "paddw %%mm5, %%mm6\n\t"
00515 "packuswb %%mm6, %%mm6\n\t"
00516 "movd %%mm6, (%0)\n\t"
00517 : : "r"(dest));
00518 dest++;
00519
00520
00521
00522
00523
00524 for(x=1; x < w-1; ++x){
00525 __asm__ __volatile__
00526 ("pxor %%mm5, %%mm5\n\t"
00527 "pxor %%mm6, %%mm6\n\t"
00528 : : );
00529 for(i=0, xm=xmatrix, ym=ymatrix; i < 3; ++i, xm+=3, ym+=3){
00530 s = scanblock[i];
00531 __asm__ __volatile__
00532 (
00533 "movd (%0), %%mm0\n\t"
00534 "punpcklbw %%mm7, %%mm0\n\t"
00535 "movq %%mm0, %%mm1\n\t"
00536 "movd (%1), %%mm2\n\t"
00537 "punpckldq %%mm2, %%mm2\n\t"
00538 "packssdw %%mm2, %%mm2\n\t"
00539 "movd (%2), %%mm3\n\t"
00540 "punpckldq %%mm3, %%mm3\n\t"
00541 "packssdw %%mm3, %%mm3\n\t"
00542 "pmullw %%mm2, %%mm0\n\t"
00543 "pmullw %%mm3, %%mm1\n\t"
00544 "paddw %%mm0, %%mm5\n\t"
00545 "paddw %%mm1, %%mm6\n\t"
00546
00547 "movd 4(%0), %%mm0\n\t"
00548 "punpcklbw %%mm7, %%mm0\n\t"
00549 "movq %%mm0, %%mm1\n\t"
00550 "movd 4(%1), %%mm2\n\t"
00551 "punpckldq %%mm2, %%mm2\n\t"
00552 "packssdw %%mm2, %%mm2\n\t"
00553 "movd 4(%2), %%mm3\n\t"
00554 "punpckldq %%mm3, %%mm3\n\t"
00555 "packssdw %%mm3, %%mm3\n\t"
00556 "pmullw %%mm2, %%mm0\n\t"
00557 "pmullw %%mm3, %%mm1\n\t"
00558 "paddw %%mm0, %%mm5\n\t"
00559 "paddw %%mm1, %%mm6\n\t"
00560
00561 "movd 8(%0), %%mm0\n\t"
00562 "punpcklbw %%mm7, %%mm0\n\t"
00563 "movq %%mm0, %%mm1\n\t"
00564 "movd 8(%1), %%mm2\n\t"
00565 "punpckldq %%mm2, %%mm2\n\t"
00566 "packssdw %%mm2, %%mm2\n\t"
00567 "movd 8(%2), %%mm3\n\t"
00568 "punpckldq %%mm3, %%mm3\n\t"
00569 "packssdw %%mm3, %%mm3\n\t"
00570 "pmullw %%mm2, %%mm0\n\t"
00571 "pmullw %%mm3, %%mm1\n\t"
00572 "paddw %%mm0, %%mm5\n\t"
00573 "paddw %%mm1, %%mm6\n\t"
00574 : : "r"(s), "r"(xm), "r"(ym));
00575 }
00576 __asm__ __volatile__
00577 (
00578 "movq %%mm5, %%mm0\n\t"
00579 "psraw $15, %%mm0\n\t"
00580 "pxor %%mm0, %%mm5\n\t"
00581 "psubw %%mm0, %%mm5\n\t"
00582 "movq %%mm6, %%mm0\n\t"
00583 "psraw $15, %%mm0\n\t"
00584 "pxor %%mm0, %%mm6\n\t"
00585 "psubw %%mm0, %%mm6\n\t"
00586 "paddw %%mm5, %%mm6\n\t"
00587 "packuswb %%mm6, %%mm6\n\t"
00588 "movd %%mm6, (%0)\n\t"
00589 : : "r"(dest));
00590 dest++;
00591 ++scanblock[0], ++scanblock[1], ++scanblock[2];
00592 }
00593
00594
00595
00596
00597
00598 __asm__ __volatile__
00599 ("pxor %%mm5, %%mm5\n\t"
00600 "pxor %%mm6, %%mm6\n\t"
00601 : : );
00602 for(i=0, xm=xmatrix, ym=ymatrix; i < 3; ++i, xm+=3, ym+=3){
00603 s = scanblock[i];
00604 __asm__ __volatile__
00605 (
00606 "movd (%0), %%mm0\n\t"
00607 "punpcklbw %%mm7, %%mm0\n\t"
00608 "movq %%mm0, %%mm1\n\t"
00609 "movd (%1), %%mm2\n\t"
00610 "punpckldq %%mm2, %%mm2\n\t"
00611 "packssdw %%mm2, %%mm2\n\t"
00612 "movd (%2), %%mm3\n\t"
00613 "punpckldq %%mm3, %%mm3\n\t"
00614 "packssdw %%mm3, %%mm3\n\t"
00615 "pmullw %%mm2, %%mm0\n\t"
00616 "pmullw %%mm3, %%mm1\n\t"
00617 "paddw %%mm0, %%mm5\n\t"
00618 "paddw %%mm1, %%mm6\n\t"
00619
00620 "movd 4(%0), %%mm0\n\t"
00621 "punpcklbw %%mm7, %%mm0\n\t"
00622 "movq %%mm0, %%mm1\n\t"
00623 "movd 4(%1), %%mm2\n\t"
00624 "punpckldq %%mm2, %%mm2\n\t"
00625 "packssdw %%mm2, %%mm2\n\t"
00626 "movd 4(%2), %%mm3\n\t"
00627 "punpckldq %%mm3, %%mm3\n\t"
00628 "packssdw %%mm3, %%mm3\n\t"
00629 "pmullw %%mm2, %%mm0\n\t"
00630 "pmullw %%mm3, %%mm1\n\t"
00631 "paddw %%mm0, %%mm5\n\t"
00632 "paddw %%mm1, %%mm6\n\t"
00633
00634 "movd 4(%0), %%mm0\n\t"
00635 "punpcklbw %%mm7, %%mm0\n\t"
00636 "movq %%mm0, %%mm1\n\t"
00637 "movd 8(%1), %%mm2\n\t"
00638 "punpckldq %%mm2, %%mm2\n\t"
00639 "packssdw %%mm2, %%mm2\n\t"
00640 "movd 8(%2), %%mm3\n\t"
00641 "punpckldq %%mm3, %%mm3\n\t"
00642 "packssdw %%mm3, %%mm3\n\t"
00643 "pmullw %%mm2, %%mm0\n\t"
00644 "pmullw %%mm3, %%mm1\n\t"
00645 "paddw %%mm0, %%mm5\n\t"
00646 "paddw %%mm1, %%mm6\n\t"
00647 : : "r"(s), "r"(xm), "r"(ym));
00648 }
00649 __asm__ __volatile__
00650 (
00651 "movq %%mm5, %%mm0\n\t"
00652 "psraw $15, %%mm0\n\t"
00653 "pxor %%mm0, %%mm5\n\t"
00654 "psubw %%mm0, %%mm5\n\t"
00655 "movq %%mm6, %%mm0\n\t"
00656 "psraw $15, %%mm0\n\t"
00657 "pxor %%mm0, %%mm6\n\t"
00658 "psubw %%mm0, %%mm6\n\t"
00659 "paddw %%mm5, %%mm6\n\t"
00660 "packuswb %%mm6, %%mm6\n\t"
00661 "movd %%mm6, (%0)\n\t"
00662 : : "r"(dest));
00663 dest++;
00664 }
00665 __asm__ __volatile__ ("emms\n\t" : :);
00666 }
00667 else
00668 #endif
00669 {
00670 int xR, xG, xB, yR, yG, yB;
00671 for(y=0; y < h; ++y){
00672 scanblock[1] = (QRgb *)img.scanLine(y);
00673 dest = (QRgb *)buffer.scanLine(y);
00674 if(y == 0){
00675 scanblock[0] = (QRgb *)img.scanLine(y);
00676 scanblock[2] = (QRgb *)img.scanLine(y+1);
00677 }
00678 else if(y == h-1){
00679 scanblock[0] = (QRgb *)img.scanLine(y-1);
00680 scanblock[2] = (QRgb *)img.scanLine(y);
00681 }
00682 else{
00683 scanblock[0] = (QRgb *)img.scanLine(y-1);
00684 scanblock[2] = (QRgb *)img.scanLine(y+1);
00685 }
00686
00687
00688 xR = xG = xB = yR = yG = yB = 0;
00689 s = scanblock[0];
00690 SOBEL(-1, 1, *s); SOBEL(0, 2, *s); ++s; SOBEL(1, 1, *s);
00691 s = scanblock[1];
00692 SOBEL(-2, 0, *s); SOBEL(0, 0, *s); ++s; SOBEL(2, 0, *s);
00693 s = scanblock[2];
00694 SOBEL(-1, -1, *s); SOBEL(0, -2, *s); ++s; SOBEL(1, -1, *s);
00695 xR = qAbs(xR)+qAbs(yR); xG = qAbs(xG)+qAbs(yG);
00696 xB = qAbs(xB)+qAbs(yB);
00697 *dest++ = qRgb(qMin(xR, 255), qMin(xG, 255), qMin(xB, 255));
00698
00699
00700 for(x=1; x < w-1; ++x){
00701 xR = xG = xB = yR = yG = yB = 0;
00702 s = scanblock[0];
00703 SOBEL(-1, 1, *s); ++s; SOBEL(0, 2, *s); ++s; SOBEL(1, 1, *s);
00704 s = scanblock[1];
00705 SOBEL(-2, 0, *s); ++s; SOBEL(0, 0, *s); ++s; SOBEL(2, 0, *s);
00706 s = scanblock[2];
00707 SOBEL(-1, -1, *s); ++s; SOBEL(0, -2, *s); ++s; SOBEL(1, -1, *s);
00708 ++scanblock[0]; ++scanblock[1]; ++scanblock[2];
00709 xR = qAbs(xR)+qAbs(yR); xG = qAbs(xG)+qAbs(yG);
00710 xB = qAbs(xB)+qAbs(yB);
00711 *dest++ = qRgb(qMin(xR, 255), qMin(xG, 255), qMin(xB, 255));
00712 }
00713
00714
00715 xR = xG = xB = yR = yG = yB = 0;
00716 s = scanblock[0];
00717 SOBEL(-1, 1, *s); ++s; SOBEL(0, 2, *s); SOBEL(1, 1, *s);
00718 s = scanblock[1];
00719 SOBEL(-2, 0, *s); ++s; SOBEL(0, 0, *s); SOBEL(2, 0, *s);
00720 s = scanblock[2];
00721 SOBEL(-1, -1, *s); ++s; SOBEL(0, -2, *s); SOBEL(1, -1, *s);
00722 xR = qAbs(xR)+qAbs(yR); xG = qAbs(xG)+qAbs(yG);
00723 xB = qAbs(xB)+qAbs(yB);
00724 *dest++ = qRgb(qMin(xR, 255), qMin(xG, 255), qMin(xB, 255));
00725 }
00726 }
00727 return(buffer);
00728 }
00729
00730 QImage Blitz::charcoal(QImage &img)
00731 {
00732 QImage buffer(edge(img));
00733 buffer = blur(buffer, 1);
00734 normalize(buffer);
00735 buffer.invertPixels();
00736 grayscale(buffer, true);
00737 return(buffer);
00738 }
00739
00740 QImage Blitz::swirl(QImage &img, float degrees)
00741 {
00742 float sine, cosine, distance, radius, factor;
00743 float x_center, x_distance, x_scale;
00744 float y_center, y_distance, y_scale;
00745 int x, y, w, h;
00746 QRgb *dest;
00747
00748 w = img.width();
00749 h = img.height();
00750
00751 if(img.format() == QImage::Format_ARGB32_Premultiplied)
00752 img = img.convertToFormat(QImage::Format_ARGB32);
00753 else if(img.depth() < 8)
00754 img = img.convertToFormat(QImage::Format_Indexed8);
00755
00756 QImage buffer(w, h, img.hasAlphaChannel() ?
00757 QImage::Format_ARGB32 : QImage::Format_RGB32);
00758
00759 x_center = w/2.0;
00760 y_center = h/2.0;
00761 radius = qMax(x_center, y_center);
00762 x_scale = y_scale = 1.0;
00763 if(w > h)
00764 y_scale = (float)(w/h);
00765 else if(w < h)
00766 x_scale = (float)(h/w);
00767 degrees = (M_PI*degrees)/180.0;
00768
00769 InlineInterpolate interpolate(&img, 0);
00770 if(img.depth() > 8){
00771 QRgb *src;
00772 for(y=0; y < h; ++y){
00773 src = (QRgb *)img.scanLine(y);
00774 dest = (QRgb *)buffer.scanLine(y);
00775 y_distance = y_scale*(y-y_center);
00776 for(x=0; x < w; ++x){
00777 x_distance = x_scale*(x-x_center);
00778 distance = x_distance*x_distance + y_distance*y_distance;
00779 if(distance >= (radius*radius))
00780 *dest = src[x];
00781 else{
00782 factor = 1.0-std::sqrt(distance)/radius;
00783 sine = std::sin(degrees*factor*factor);
00784 cosine = std::cos(degrees*factor*factor);
00785 *dest = interpolate.
00786 interpolate((cosine*x_distance-sine*y_distance)/
00787 x_scale+x_center,
00788 (sine*x_distance+cosine*y_distance)/
00789 y_scale+y_center);
00790 }
00791 ++dest;
00792 }
00793 }
00794 }
00795 else{
00796 QVector<QRgb> cTable(img.colorTable());
00797 unsigned char *src;
00798 for(y=0; y < h; ++y){
00799 src = img.scanLine(y);
00800 dest = (QRgb *)buffer.scanLine(y);
00801 y_distance = y_scale*(y-y_center);
00802 for(x=0; x < w; ++x){
00803 x_distance = x_scale*(x-x_center);
00804 distance = x_distance*x_distance + y_distance*y_distance;
00805 if(distance >= (radius*radius))
00806 *dest = cTable.at(src[x]);
00807 else{
00808 factor = 1.0-std::sqrt(distance)/radius;
00809 sine = std::sin(degrees*factor*factor);
00810 cosine = std::cos(degrees*factor*factor);
00811 *dest = interpolate.
00812 interpolate((cosine*x_distance-sine*y_distance)/
00813 x_scale+x_center,
00814 (sine*x_distance+cosine*y_distance)/
00815 y_scale+y_center);
00816 }
00817 ++dest;
00818 }
00819 }
00820 }
00821 return(buffer);
00822 }
00823
00824 QImage Blitz::implode(QImage &img, float amount)
00825 {
00826 float distance, radius, factor;
00827 float x_center, x_distance, x_scale;
00828 float y_center, y_distance, y_scale;
00829 int x, y, w, h;
00830 QRgb *dest;
00831
00832 w = img.width();
00833 h = img.height();
00834
00835 if(img.format() == QImage::Format_ARGB32_Premultiplied)
00836 img = img.convertToFormat(QImage::Format_ARGB32);
00837 else if(img.depth() < 8)
00838 img = img.convertToFormat(QImage::Format_Indexed8);
00839
00840 QImage buffer(w, h, img.hasAlphaChannel() ?
00841 QImage::Format_ARGB32 : QImage::Format_RGB32);
00842
00843 x_scale = y_scale = 1.0;
00844 x_center = 0.5*w;
00845 y_center = 0.5*h;
00846 radius = x_center;
00847 if(w > h)
00848 y_scale = (float)(w/h);
00849 else if(w < h){
00850 x_scale = (float)(h/w);
00851 radius = y_center;
00852 }
00853
00854 InlineInterpolate interpolate(&img, 0);
00855 if(img.depth() > 8){
00856 QRgb *src;
00857 for(y=0; y < h; ++y){
00858 src = (QRgb *)img.scanLine(y);
00859 dest = (QRgb *)buffer.scanLine(y);
00860 y_distance = y_scale*(y-y_center);
00861 for(x=0; x < w; ++x){
00862 x_distance = x_scale*(x-x_center);
00863 distance = x_distance*x_distance + y_distance*y_distance;
00864 if(distance >= (radius*radius))
00865 *dest = src[x];
00866 else{
00867 factor = 1.0;
00868 if(distance > 0.0)
00869 factor = std::pow(std::sin(((float)M_PI)*
00870 std::sqrt(distance)/
00871 radius/2), -amount);
00872 *dest = interpolate.
00873 interpolate(factor*x_distance/x_scale+x_center,
00874 factor*y_distance/y_scale+y_center);
00875 }
00876 ++dest;
00877 }
00878 }
00879 }
00880 else{
00881 QVector<QRgb> cTable(img.colorTable());
00882 unsigned char *src;
00883 for(y=0; y < h; ++y){
00884 src = img.scanLine(y);
00885 dest = (QRgb *)buffer.scanLine(y);
00886 y_distance = y_scale*(y-y_center);
00887 for(x=0; x < w; ++x){
00888 x_distance = x_scale*(x-x_center);
00889 distance = x_distance*x_distance + y_distance*y_distance;
00890 if(distance >= (radius*radius))
00891 *dest = cTable.at(src[x]);
00892 else{
00893 factor = 1.0;
00894 if(distance > 0.0)
00895 factor = std::pow(std::sin(((float)M_PI)*
00896 std::sqrt(distance)/
00897 radius/2), -amount);
00898 *dest = interpolate.
00899 interpolate(factor*x_distance/x_scale+x_center,
00900 factor*y_distance/y_scale+y_center);
00901 }
00902 ++dest;
00903 }
00904 }
00905 }
00906 return(buffer);
00907 }
00908
00909 QImage Blitz::wave(QImage &img, float amplitude, float length,
00910 unsigned int background)
00911 {
00912 int x, y, w, h;
00913 QRgb *dest;
00914 float *sine_map;
00915
00916 if(img.format() == QImage::Format_ARGB32_Premultiplied)
00917 img = img.convertToFormat(QImage::Format_ARGB32);
00918 else if(img.depth() < 8)
00919 img = img.convertToFormat(QImage::Format_Indexed8);
00920
00921 QImage buffer(img.width(), (int)(img.height()+2.0*std::abs(amplitude)),
00922 QImage::Format_RGB32);
00923 w = buffer.width();
00924 h = buffer.height();
00925
00926 sine_map = new float[w];
00927 for(x=0; x < w; ++x)
00928 sine_map[x] = std::abs(amplitude)+amplitude*std::sin((2*M_PI*x)/length);
00929
00930 InlineInterpolate interpolate(&img, background);
00931 for(y=0; y < h; ++y){
00932 dest = (QRgb *)buffer.scanLine(y);
00933 for(x=0; x < w; ++x)
00934 *dest++ = interpolate.
00935 interpolateBackground(x, y-sine_map[x]);
00936 }
00937 delete[] sine_map;
00938 return(buffer);
00939 }
00940
00941 QImage& Blitz::modulate(QImage &img, QImage &modImg, bool reverse,
00942 ModulationType type, int factor, RGBChannel channel)
00943 {
00944 if(img.isNull() || modImg.isNull())
00945 return(img);
00946
00947
00948 if(img.depth() < 32 || img.format() == QImage::Format_ARGB32_Premultiplied)
00949 img = img.convertToFormat(img.hasAlphaChannel() ?
00950 QImage::Format_ARGB32 :
00951 QImage::Format_RGB32);
00952
00953
00954 if(modImg.depth() < 8)
00955 modImg = modImg.convertToFormat(QImage::Format_Indexed8);
00956 else if(modImg.format() == QImage::Format_ARGB32_Premultiplied)
00957 modImg = modImg.convertToFormat(QImage::Format_ARGB32);
00958
00959 unsigned int x1 = img.width(), y1 = img.height();
00960 unsigned int x2 = modImg.width(), y2 = modImg.height();
00961 unsigned int x, y;
00962 unsigned int *src, *modulation_colorTable;
00963 unsigned char *modulation_src;
00964 int r, g, b, mod = 0;
00965 QRgb color1, color2;
00966 InlineHSV hsv;
00967
00968 QVector<QRgb> cTable;
00969 if(modImg.format() == QImage::Format_Indexed8){
00970 cTable = modImg.colorTable();
00971 modulation_colorTable = cTable.data();
00972 }
00973 else
00974 modulation_colorTable = NULL;
00975
00976 for(y=0; y < y1; ++y){
00977 src = (QRgb *)img.scanLine(y);
00978 modulation_src = modImg.scanLine(y%y2);
00979 x=0;
00980 while(x < x1){
00981 color2 = (!modulation_colorTable) ?
00982 *((QRgb *)modulation_src) :
00983 modulation_colorTable[*modulation_src];
00984 if(reverse){
00985 color1 = color2;
00986 color2 = *src;
00987 }
00988 else
00989 color1 = *src;
00990
00991 if(type == Intensity || type == Contrast){
00992 r = qRed(color1); g = qGreen(color1); b = qBlue(color1);
00993 if(channel != All){
00994 mod = (channel == Red) ? qRed(color2) :
00995 (channel == Green) ? qGreen(color2) :
00996 (channel == Blue) ? qBlue(color2) :
00997 (channel == Grayscale) ? qGray(color2) : 0;
00998 mod = mod*factor/50;
00999 }
01000
01001 if(type == Intensity){
01002 if(channel == All){
01003 r += r * factor/50 * qRed(color2)/256;
01004 g += g * factor/50 * qGreen(color2)/256;
01005 b += b * factor/50 * qBlue(color2)/256;
01006 }
01007 else{
01008 r += r * mod/256;
01009 g += g * mod/256;
01010 b += b * mod/256;
01011 }
01012 }
01013 else{
01014 if(channel == All){
01015 r += (r-128) * factor/50 * qRed(color2)/128;
01016 g += (g-128) * factor/50 * qGreen(color2)/128;
01017 b += (b-128) * factor/50 * qBlue(color2)/128;
01018 }
01019 else{
01020 r += (r-128) * mod/128;
01021 g += (g-128) * mod/128;
01022 b += (b-128) * mod/128;
01023 }
01024 }
01025 *src = qRgba(qBound(0, r, 255), qBound(0, g, 255),
01026 qBound(0, b, 255), qAlpha(*src));
01027 }
01028 else if(type == Saturation || type == HueShift){
01029 mod = (channel == Red) ? qRed(color2) :
01030 (channel == Green) ? qGreen(color2) :
01031 (channel == Blue) ? qBlue(color2) :
01032 (channel == Grayscale||channel == All) ? qGray(color2) : 0;
01033 mod = mod*factor/50;
01034 hsv.convertRGB2HSV(color1);
01035 if(type == Saturation)
01036 hsv.setSaturation(qBound(0, hsv.saturation()-
01037 hsv.saturation()*mod/256, 255));
01038 else{
01039 int h = hsv.hue() + mod;
01040 while(h<0) h+=360;
01041 hsv.setHue(h %= 360);
01042 }
01043 hsv.convertHSV2RGB();
01044 *src = qRgba(hsv.red(), hsv.green(), hsv.blue(), qAlpha(*src));
01045 }
01046 ++src; ++x;
01047 modulation_src += (!modulation_colorTable) ? 4 : 1;
01048
01049 if((x%x2) == 0)
01050 modulation_src -= (!modulation_colorTable) ? x2*4 : x2;
01051 }
01052 }
01053 return(img);
01054 }
01055
01056