• Skip to content
  • Skip to link menu
KDE 4.4 API Reference
  • KDE API Reference
  • KDE Support
  • Sitemap
  • Contact Us
 

qimageblitz

colors.cpp

Go to the documentation of this file.
00001 /*
00002  Copyright (C) 1998, 1999, 2001, 2002, 2004, 2005, 2007
00003       Daniel M. Duley <daniel.duley@verizon.net>
00004  (C) 2000 Josef Weidendorfer <weidendo@in.tum.de>
00005  (C) 1999 Geert Jansen <g.t.jansen@stud.tue.nl>
00006 
00007 Redistribution and use in source and binary forms, with or without
00008 modification, are permitted provided that the following conditions
00009 are met:
00010 
00011 1. Redistributions of source code must retain the above copyright
00012    notice, this list of conditions and the following disclaimer.
00013 2. Redistributions in binary form must reproduce the above copyright
00014    notice, this list of conditions and the following disclaimer in the
00015    documentation and/or other materials provided with the distribution.
00016 
00017 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
00018 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
00019 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
00020 IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
00021 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
00022 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
00023 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
00024 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00025 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
00026 THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
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" // load pixel
00110                          "punpcklbw %%mm7, %%mm0\n\t" // upgrade to quad
00111                          "pand %%mm6, %%mm0\n\t" // zero alpha so we can use pmaddwd
00112 
00113                          "pmaddwd %%mm4, %%mm0\n\t" // 2 multiplies and sum BG, RA
00114                          "pshufw $0xE4, %%mm0, %%mm1\n\t"
00115                          "punpckhwd %%mm7, %%mm1\n\t" // sum R
00116                          "paddw %%mm1, %%mm0\n\t"
00117                          "psrlw $0x05, %%mm0\n\t" // divide by 32
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             // 8bpp or 32bpp w/ no conversion
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" // load pixel
00149                      "punpcklbw %%mm7, %%mm0\n\t" // upgrade to quad
00150                      "pshufw $0xE4, %%mm0, %%mm2\n\t" // copy for alpha later
00151                      "pand %%mm6, %%mm0\n\t" // zero alpha so we can use pmaddwd
00152 
00153                      "pmaddwd %%mm4, %%mm0\n\t" // 2 multiplies and sum BG, RA
00154                      "pshufw $0xE4, %%mm0, %%mm1\n\t"
00155                      "punpckhwd %%mm7, %%mm1\n\t" // sum R
00156                      "paddw %%mm1, %%mm0\n\t"
00157                      "psrlw $0x05, %%mm0\n\t" // divide by 32
00158 
00159                      "pshufw $0x00, %%mm0, %%mm0\n\t" // copy to all pixels
00160                      "pand %%mm6, %%mm0\n\t" // reset original alpha
00161                      "pand %%mm5, %%mm2\n\t"
00162                      "por %%mm2, %%mm0\n\t"
00163 
00164                      "packuswb %%mm0, %%mm0\n\t" // pack and write
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         // Non MMX version
00178         if(reduceDepth && img.format() ==  QImage::Format_RGB32){
00179             // 32bpp w/ conversion to palette
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             // 8bpp or 32bpp w/ no conversion
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"                // zero mm7 for unpacking
00407         "movq  (%0), %%mm6\n\t"                // copy intensity change to mm6
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"   // copy 4 pixels of data to mm0 and mm4
00415                 "movq      %%mm0, %%mm1\n\t"
00416                 "movq      %%mm0, %%mm3\n\t"
00417                 "movq      %%mm4, %%mm5\n\t"   // copy to registers for unpacking
00418                 "punpcklbw %%mm7, %%mm0\n\t"
00419                 "punpckhbw %%mm7, %%mm1\n\t"   // unpack the two pixels from mm0
00420                 "pmullw    %%mm6, %%mm0\n\t"
00421                 "punpcklbw %%mm7, %%mm4\n\t"
00422                 "pmullw    %%mm6, %%mm1\n\t"   // multiply by intensity*256
00423                 "psrlw        $8, %%mm0\n\t"   // divide by 256
00424                 "pmullw    %%mm6, %%mm4\n\t"
00425                 "psrlw        $8, %%mm1\n\t"
00426                 "psrlw        $8, %%mm4\n\t"
00427                 "packuswb  %%mm1, %%mm0\n\t"   // pack solution into mm0. saturates at 255
00428                 "movq      %%mm5, %%mm1\n\t"
00429 
00430                 "punpckhbw %%mm7, %%mm1\n\t"   // unpack 4th pixel in mm1
00431 
00432                 "pmullw    %%mm6, %%mm1\n\t"
00433                 "paddusb   %%mm3, %%mm0\n\t"   // add intesity result to original of mm0
00434                 "psrlw        $8, %%mm1\n\t"
00435                 "packuswb  %%mm1, %%mm4\n\t"   // pack upper two pixels into mm4
00436 
00437                 "movq      %%mm0, (%0)\n\t"    // rewrite to memory lower two pixels
00438                 "paddusb   %%mm5, %%mm4\n\t"
00439                 "movq      %%mm4, 8(%0)\n\t"   // rewrite upper two pixels
00440                 : : "r"(data) );
00441                 data += 4;
00442             }
00443 
00444             end += rem;
00445             while ( data != end ) {
00446                 __asm__ __volatile__(
00447                 "movd       (%0), %%mm0\n\t"   // repeat above but for
00448                 "punpcklbw %%mm7, %%mm0\n\t"   // one pixel at a time
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"   // subtract darkening amount
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"   // only change for this version is
00491                 "movq      %%mm5, 8(%0)\n\t"   // subtraction here as we are darkening image
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");          // clear mmx state
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){ // and here ;-)
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         // would be quicker to just threshold the color table, but we return
00837         // images w/ only 2 colors for easy conversion to bitmap
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     // get minimum and maximum graylevel
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     // conversion factors
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 

qimageblitz

Skip menu "qimageblitz"
  • Main Page
  • Namespace List
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members

KDE Support

Skip menu "KDE Support"
  • akonadi
  • Decibel
  • grantlee
  • kdewin
  • phonon
  •     Backend
  • polkit-qt
  • qca
  • qimageblitz
  • soprano
  • strigi
  •     searchclient
  •     streamanalyzer
  •     streams
Generated for KDE Support by doxygen 1.5.9-20090814
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal