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