KDEUI
kiconeffect.cpp
Go to the documentation of this file.
00001 /* vi: ts=8 sts=4 sw=4 00002 * 00003 * This file is part of the KDE project, module kdecore. 00004 * Copyright (C) 2000 Geert Jansen <jansen@kde.org> 00005 * (C) 2007 Daniel M. Duley <daniel.duley@verizon.net> 00006 * with minor additions and based on ideas from 00007 * Torsten Rahn <torsten@kde.org> 00008 * 00009 * This library is free software; you can redistribute it and/or 00010 * modify it under the terms of the GNU Library General Public 00011 * License version 2 as published by the Free Software Foundation. 00012 * 00013 * This library is distributed in the hope that it will be useful, 00014 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00016 * Library General Public License for more details. 00017 * 00018 * You should have received a copy of the GNU Library General Public License 00019 * along with this library; see the file COPYING.LIB. If not, write to 00020 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 00021 * Boston, MA 02110-1301, USA. 00022 */ 00023 00024 #include "kiconeffect.h" 00025 00026 #include <config.h> 00027 #include <unistd.h> 00028 #include <math.h> 00029 00030 #include <QtCore/QSysInfo> 00031 #include <QtGui/QApplication> 00032 #include <QtGui/QPaintEngine> 00033 #include <QtGui/QDesktopWidget> 00034 #include <QtCore/QCharRef> 00035 #include <QtCore/QMutableStringListIterator> 00036 #include <QtGui/QBitmap> 00037 #include <QtGui/QPixmap> 00038 #include <QtGui/QImage> 00039 #include <QtGui/QColor> 00040 #include <QtGui/QWidget> 00041 #include <QtGui/QPainter> 00042 #include <QtGui/QPen> 00043 00044 #include <kdebug.h> 00045 #include <kglobal.h> 00046 #include <ksharedconfig.h> 00047 #include <kglobalsettings.h> 00048 #include <kcolorscheme.h> 00049 #include <kicontheme.h> 00050 #include <kconfiggroup.h> 00051 00052 00053 class KIconEffectPrivate 00054 { 00055 public: 00056 int effect[6][3]; 00057 float value[6][3]; 00058 QColor color[6][3]; 00059 bool trans[6][3]; 00060 QString key[6][3]; 00061 QColor color2[6][3]; 00062 }; 00063 00064 KIconEffect::KIconEffect() 00065 :d(new KIconEffectPrivate) 00066 { 00067 init(); 00068 } 00069 00070 KIconEffect::~KIconEffect() 00071 { 00072 delete d; 00073 } 00074 00075 void KIconEffect::init() 00076 { 00077 KSharedConfig::Ptr config = KGlobal::config(); 00078 00079 int i, j, effect=-1; 00080 //FIXME: this really should be using KIconLoader::metaObject() to guarantee synchronization 00081 // performance wise it's also practically guaranteed to be faster 00082 QStringList groups; 00083 groups += "Desktop"; 00084 groups += "Toolbar"; 00085 groups += "MainToolbar"; 00086 groups += "Small"; 00087 groups += "Panel"; 00088 groups += "Dialog"; 00089 00090 QStringList states; 00091 states += "Default"; 00092 states += "Active"; 00093 states += "Disabled"; 00094 00095 QStringList::ConstIterator it, it2; 00096 QString _togray("togray"); 00097 QString _colorize("colorize"); 00098 QString _desaturate("desaturate"); 00099 QString _togamma("togamma"); 00100 QString _none("none"); 00101 QString _tomonochrome("tomonochrome"); 00102 00103 for (it=groups.constBegin(), i=0; it!=groups.constEnd(); ++it, ++i) 00104 { 00105 // Default effects 00106 d->effect[i][0] = NoEffect; 00107 d->effect[i][1] = ((i==0)||(i==4)) ? ToGamma : NoEffect; 00108 d->effect[i][2] = ToGray; 00109 00110 d->trans[i][0] = false; 00111 d->trans[i][1] = false; 00112 d->trans[i][2] = true; 00113 d->value[i][0] = 1.0; 00114 d->value[i][1] = ((i==0)||(i==4)) ? 0.7 : 1.0; 00115 d->value[i][2] = 1.0; 00116 d->color[i][0] = QColor(144,128,248); 00117 d->color[i][1] = QColor(169,156,255); 00118 d->color[i][2] = QColor(34,202,0); 00119 d->color2[i][0] = QColor(0,0,0); 00120 d->color2[i][1] = QColor(0,0,0); 00121 d->color2[i][2] = QColor(0,0,0); 00122 00123 KConfigGroup cg(config, *it + "Icons"); 00124 for (it2=states.constBegin(), j=0; it2!=states.constEnd(); ++it2, ++j) 00125 { 00126 QString tmp = cg.readEntry(*it2 + "Effect", QString()); 00127 if (tmp == _togray) 00128 effect = ToGray; 00129 else if (tmp == _colorize) 00130 effect = Colorize; 00131 else if (tmp == _desaturate) 00132 effect = DeSaturate; 00133 else if (tmp == _togamma) 00134 effect = ToGamma; 00135 else if (tmp == _tomonochrome) 00136 effect = ToMonochrome; 00137 else if (tmp == _none) 00138 effect = NoEffect; 00139 else 00140 continue; 00141 if(effect != -1) 00142 d->effect[i][j] = effect; 00143 d->value[i][j] = cg.readEntry(*it2 + "Value", 0.0); 00144 d->color[i][j] = cg.readEntry(*it2 + "Color", QColor()); 00145 d->color2[i][j] = cg.readEntry(*it2 + "Color2", QColor()); 00146 d->trans[i][j] = cg.readEntry(*it2 + "SemiTransparent", false); 00147 00148 } 00149 } 00150 } 00151 00152 bool KIconEffect::hasEffect(int group, int state) const 00153 { 00154 if (group < 0 || group >= KIconLoader::LastGroup || 00155 state < 0 || state >= KIconLoader::LastState) { 00156 return false; 00157 } 00158 00159 return d->effect[group][state] != NoEffect; 00160 } 00161 00162 QString KIconEffect::fingerprint(int group, int state) const 00163 { 00164 if (group < 0 || group >= KIconLoader::LastGroup || 00165 state < 0 || state >= KIconLoader::LastState) { 00166 return QString(); 00167 } 00168 00169 QString cached = d->key[group][state]; 00170 if (cached.isEmpty()) 00171 { 00172 QString tmp; 00173 cached = tmp.setNum(d->effect[group][state]); 00174 cached += ':'; 00175 cached += tmp.setNum(d->value[group][state]); 00176 cached += ':'; 00177 cached += d->trans[group][state] ? QLatin1String("trans") 00178 : QLatin1String("notrans"); 00179 if (d->effect[group][state] == Colorize || d->effect[group][state] == ToMonochrome) 00180 { 00181 cached += ':'; 00182 cached += d->color[group][state].name(); 00183 } 00184 if (d->effect[group][state] == ToMonochrome) 00185 { 00186 cached += ':'; 00187 cached += d->color2[group][state].name(); 00188 } 00189 00190 d->key[group][state] = cached; 00191 } 00192 00193 return cached; 00194 } 00195 00196 QImage KIconEffect::apply(const QImage &image, int group, int state) const 00197 { 00198 if (state >= KIconLoader::LastState) 00199 { 00200 kDebug(265) << "Illegal icon state: " << state << "\n"; 00201 return image; 00202 } 00203 if (group >= KIconLoader::LastGroup) 00204 { 00205 kDebug(265) << "Illegal icon group: " << group << "\n"; 00206 return image; 00207 } 00208 return apply(image, d->effect[group][state], d->value[group][state], 00209 d->color[group][state], d->color2[group][state], d->trans[group][state]); 00210 } 00211 00212 QImage KIconEffect::apply(const QImage &image, int effect, float value, 00213 const QColor &col, bool trans) const 00214 { 00215 return apply(image, effect, value, col, 00216 KColorScheme(QPalette::Active, KColorScheme::View).background().color(), trans); 00217 } 00218 00219 QImage KIconEffect::apply(const QImage &img, int effect, float value, 00220 const QColor &col, const QColor &col2, bool trans) const 00221 { 00222 QImage image = img; 00223 if (effect >= LastEffect ) 00224 { 00225 kDebug(265) << "Illegal icon effect: " << effect << "\n"; 00226 return image; 00227 } 00228 if (value > 1.0) 00229 value = 1.0; 00230 else if (value < 0.0) 00231 value = 0.0; 00232 switch (effect) 00233 { 00234 case ToGray: 00235 toGray(image, value); 00236 break; 00237 case DeSaturate: 00238 deSaturate(image, value); 00239 break; 00240 case Colorize: 00241 colorize(image, col, value); 00242 break; 00243 case ToGamma: 00244 toGamma(image, value); 00245 break; 00246 case ToMonochrome: 00247 toMonochrome(image, col, col2, value); 00248 break; 00249 } 00250 if (trans == true) 00251 { 00252 semiTransparent(image); 00253 } 00254 return image; 00255 } 00256 00257 QPixmap KIconEffect::apply(const QPixmap &pixmap, int group, int state) const 00258 { 00259 if (state >= KIconLoader::LastState) 00260 { 00261 kDebug(265) << "Illegal icon state: " << state << "\n"; 00262 return pixmap; 00263 } 00264 if (group >= KIconLoader::LastGroup) 00265 { 00266 kDebug(265) << "Illegal icon group: " << group << "\n"; 00267 return pixmap; 00268 } 00269 return apply(pixmap, d->effect[group][state], d->value[group][state], 00270 d->color[group][state], d->color2[group][state], d->trans[group][state]); 00271 } 00272 00273 QPixmap KIconEffect::apply(const QPixmap &pixmap, int effect, float value, 00274 const QColor &col, bool trans) const 00275 { 00276 return apply(pixmap, effect, value, col, 00277 KColorScheme(QPalette::Active, KColorScheme::View).background().color(), trans); 00278 } 00279 00280 QPixmap KIconEffect::apply(const QPixmap &pixmap, int effect, float value, 00281 const QColor &col, const QColor &col2, bool trans) const 00282 { 00283 QPixmap result; 00284 00285 if (effect >= LastEffect ) 00286 { 00287 kDebug(265) << "Illegal icon effect: " << effect << "\n"; 00288 return result; 00289 } 00290 00291 if ((trans == true) && (effect == NoEffect)) 00292 { 00293 result = pixmap; 00294 semiTransparent(result); 00295 } 00296 else if ( effect != NoEffect ) 00297 { 00298 QImage tmpImg = pixmap.toImage(); 00299 tmpImg = apply(tmpImg, effect, value, col, col2, trans); 00300 result = QPixmap::fromImage(tmpImg); 00301 } 00302 else 00303 result = pixmap; 00304 00305 return result; 00306 } 00307 00308 struct KIEImgEdit 00309 { 00310 QImage& img; 00311 QVector <QRgb> colors; 00312 unsigned int* data; 00313 unsigned int pixels; 00314 00315 KIEImgEdit(QImage& _img):img(_img) 00316 { 00317 if (img.depth() > 8) 00318 { 00319 //Code using data and pixels assumes that the pixels are stored 00320 //in 32bit values and that the image is not premultiplied 00321 if ((img.format() != QImage::Format_ARGB32) && 00322 (img.format() != QImage::Format_RGB32)) 00323 { 00324 img = img.convertToFormat(QImage::Format_ARGB32); 00325 } 00326 data = (unsigned int*)img.bits(); 00327 pixels = img.width()*img.height(); 00328 } 00329 else 00330 { 00331 pixels = img.numColors(); 00332 colors = img.colorTable(); 00333 data = (unsigned int*)colors.data(); 00334 } 00335 } 00336 00337 ~KIEImgEdit() 00338 { 00339 if (img.depth() <= 8) 00340 img.setColorTable(colors); 00341 } 00342 }; 00343 00344 static bool painterSupportsAntialiasing() 00345 { 00346 #ifdef Q_WS_WIN 00347 // apparently QApplication::desktop()->paintEngine() is null on windows 00348 // but we can assume the paint engine supports antialiasing there, right? 00349 return true; 00350 #else 00351 QPaintEngine* const pe = QApplication::desktop()->paintEngine(); 00352 return pe && pe->hasFeature(QPaintEngine::Antialiasing); 00353 #endif 00354 } 00355 00356 // Taken from KImageEffect. We don't want to link kdecore to kdeui! As long 00357 // as this code is not too big, it doesn't seem much of a problem to me. 00358 00359 void KIconEffect::toGray(QImage &img, float value) 00360 { 00361 if(value == 0.0) 00362 return; 00363 00364 KIEImgEdit ii(img); 00365 QRgb *data = ii.data; 00366 QRgb *end = data + ii.pixels; 00367 00368 unsigned char gray; 00369 if(value == 1.0){ 00370 while(data != end){ 00371 gray = qGray(*data); 00372 *data = qRgba(gray, gray, gray, qAlpha(*data)); 00373 ++data; 00374 } 00375 } 00376 else{ 00377 unsigned char val = (unsigned char)(255.0*value); 00378 while(data != end){ 00379 gray = qGray(*data); 00380 *data = qRgba((val*gray+(0xFF-val)*qRed(*data)) >> 8, 00381 (val*gray+(0xFF-val)*qGreen(*data)) >> 8, 00382 (val*gray+(0xFF-val)*qBlue(*data)) >> 8, 00383 qAlpha(*data)); 00384 ++data; 00385 } 00386 } 00387 } 00388 00389 void KIconEffect::colorize(QImage &img, const QColor &col, float value) 00390 { 00391 if(value == 0.0) 00392 return; 00393 00394 KIEImgEdit ii(img); 00395 QRgb *data = ii.data; 00396 QRgb *end = data + ii.pixels; 00397 00398 float rcol = col.red(), gcol = col.green(), bcol = col.blue(); 00399 unsigned char red, green, blue, gray; 00400 unsigned char val = (unsigned char)(255.0*value); 00401 while(data != end){ 00402 gray = qGray(*data); 00403 if(gray < 128){ 00404 red = static_cast<unsigned char>(rcol/128*gray); 00405 green = static_cast<unsigned char>(gcol/128*gray); 00406 blue = static_cast<unsigned char>(bcol/128*gray); 00407 } 00408 else if(gray > 128){ 00409 red = static_cast<unsigned char>((gray-128)*(2-rcol/128)+rcol-1); 00410 green = static_cast<unsigned char>((gray-128)*(2-gcol/128)+gcol-1); 00411 blue = static_cast<unsigned char>((gray-128)*(2-bcol/128)+bcol-1); 00412 } 00413 else{ 00414 red = static_cast<unsigned char>(rcol); 00415 green = static_cast<unsigned char>(gcol); 00416 blue = static_cast<unsigned char>(bcol); 00417 } 00418 00419 *data = qRgba((val*red+(0xFF-val)*qRed(*data)) >> 8, 00420 (val*green+(0xFF-val)*qGreen(*data)) >> 8, 00421 (val*blue+(0xFF-val)*qBlue(*data)) >> 8, 00422 qAlpha(*data)); 00423 ++data; 00424 } 00425 } 00426 00427 void KIconEffect::toMonochrome(QImage &img, const QColor &black, 00428 const QColor &white, float value) 00429 { 00430 if(value == 0.0) 00431 return; 00432 00433 KIEImgEdit ii(img); 00434 QRgb *data = ii.data; 00435 QRgb *end = data + ii.pixels; 00436 00437 // Step 1: determine the average brightness 00438 double values = 0.0, sum = 0.0; 00439 bool grayscale = true; 00440 while(data != end){ 00441 sum += qGray(*data)*qAlpha(*data) + 255*(255-qAlpha(*data)); 00442 values += 255; 00443 if((qRed(*data) != qGreen(*data) ) || (qGreen(*data) != qBlue(*data))) 00444 grayscale = false; 00445 ++data; 00446 } 00447 double medium = sum/values; 00448 00449 // Step 2: Modify the image 00450 unsigned char val = (unsigned char)(255.0*value); 00451 int rw = white.red(), gw = white.green(), bw = white.blue(); 00452 int rb = black.red(), gb = black.green(), bb = black.blue(); 00453 data = ii.data; 00454 00455 if(grayscale){ 00456 while(data != end){ 00457 if(qRed(*data) <= medium) 00458 *data = qRgba((val*rb+(0xFF-val)*qRed(*data)) >> 8, 00459 (val*gb+(0xFF-val)*qGreen(*data)) >> 8, 00460 (val*bb+(0xFF-val)*qBlue(*data)) >> 8, 00461 qAlpha(*data)); 00462 else 00463 *data = qRgba((val*rw+(0xFF-val)*qRed(*data)) >> 8, 00464 (val*gw+(0xFF-val)*qGreen(*data)) >> 8, 00465 (val*bw+(0xFF-val)*qBlue(*data)) >> 8, 00466 qAlpha(*data)); 00467 ++data; 00468 } 00469 } 00470 else{ 00471 while(data != end){ 00472 if(qGray(*data) <= medium) 00473 *data = qRgba((val*rb+(0xFF-val)*qRed(*data)) >> 8, 00474 (val*gb+(0xFF-val)*qGreen(*data)) >> 8, 00475 (val*bb+(0xFF-val)*qBlue(*data)) >> 8, 00476 qAlpha(*data)); 00477 else 00478 *data = qRgba((val*rw+(0xFF-val)*qRed(*data)) >> 8, 00479 (val*gw+(0xFF-val)*qGreen(*data)) >> 8, 00480 (val*bw+(0xFF-val)*qBlue(*data)) >> 8, 00481 qAlpha(*data)); 00482 ++data; 00483 } 00484 } 00485 } 00486 00487 void KIconEffect::deSaturate(QImage &img, float value) 00488 { 00489 if(value == 0.0) 00490 return; 00491 00492 KIEImgEdit ii(img); 00493 QRgb *data = ii.data; 00494 QRgb *end = data + ii.pixels; 00495 00496 QColor color; 00497 int h, s, v; 00498 while(data != end){ 00499 color.setRgb(*data); 00500 color.getHsv(&h, &s, &v); 00501 color.setHsv(h, (int) (s * (1.0 - value) + 0.5), v); 00502 *data = qRgba(color.red(), color.green(), color.blue(), 00503 qAlpha(*data)); 00504 ++data; 00505 } 00506 } 00507 00508 void KIconEffect::toGamma(QImage &img, float value) 00509 { 00510 KIEImgEdit ii(img); 00511 QRgb *data = ii.data; 00512 QRgb *end = data + ii.pixels; 00513 00514 float gamma = 1/(2*value+0.5); 00515 while(data != end){ 00516 *data = qRgba(static_cast<unsigned char> 00517 (pow(static_cast<float>(qRed(*data))/255 , gamma)*255), 00518 static_cast<unsigned char> 00519 (pow(static_cast<float>(qGreen(*data))/255 , gamma)*255), 00520 static_cast<unsigned char> 00521 (pow(static_cast<float>(qBlue(*data))/255 , gamma)*255), 00522 qAlpha(*data)); 00523 ++data; 00524 } 00525 } 00526 00527 void KIconEffect::semiTransparent(QImage &img) 00528 { 00529 int x, y; 00530 if(img.depth() == 32){ 00531 if(img.format() == QImage::Format_ARGB32_Premultiplied) 00532 img = img.convertToFormat(QImage::Format_ARGB32); 00533 int width = img.width(); 00534 int height = img.height(); 00535 00536 if(painterSupportsAntialiasing()){ 00537 unsigned char *line; 00538 for(y=0; y<height; ++y){ 00539 if(QSysInfo::ByteOrder == QSysInfo::BigEndian) 00540 line = img.scanLine(y); 00541 else 00542 line = img.scanLine(y) + 3; 00543 for(x=0; x<width; ++x){ 00544 *line >>= 1; 00545 line += 4; 00546 } 00547 } 00548 } 00549 else{ 00550 for(y=0; y<height; ++y){ 00551 QRgb* line = (QRgb*)img.scanLine(y); 00552 for(x=(y%2); x<width; x+=2) 00553 line[x] &= 0x00ffffff; 00554 } 00555 } 00556 } 00557 else{ 00558 if (img.depth() == 8) { 00559 if (painterSupportsAntialiasing()) { 00560 // not running on 8 bit, we can safely install a new colorTable 00561 QVector<QRgb> colorTable = img.colorTable(); 00562 for (int i = 0; i < colorTable.size(); ++i) { 00563 colorTable[i] = (colorTable[i] & 0x00ffffff) | ((colorTable[i] & 0xfe000000) >> 1); 00564 } 00565 img.setColorTable(colorTable); 00566 return; 00567 } 00568 } 00569 // Insert transparent pixel into the clut. 00570 int transColor = -1; 00571 00572 // search for a color that is already transparent 00573 for(x=0; x<img.numColors(); ++x){ 00574 // try to find already transparent pixel 00575 if(qAlpha(img.color(x)) < 127){ 00576 transColor = x; 00577 break; 00578 } 00579 } 00580 00581 // FIXME: image must have transparency 00582 if(transColor < 0 || transColor >= img.numColors()) 00583 return; 00584 00585 img.setColor(transColor, 0); 00586 unsigned char *line; 00587 if(img.depth() == 8){ 00588 for(y=0; y<img.height(); ++y){ 00589 line = img.scanLine(y); 00590 for(x=(y%2); x<img.width(); x+=2) 00591 line[x] = transColor; 00592 } 00593 } 00594 else{ 00595 bool setOn = (transColor != 0); 00596 if(img.format() == QImage::Format_MonoLSB){ 00597 for(y=0; y<img.height(); ++y){ 00598 line = img.scanLine(y); 00599 for(x=(y%2); x<img.width(); x+=2){ 00600 if(!setOn) 00601 *(line + (x >> 3)) &= ~(1 << (x & 7)); 00602 else 00603 *(line + (x >> 3)) |= (1 << (x & 7)); 00604 } 00605 } 00606 } 00607 else{ 00608 for(y=0; y<img.height(); ++y){ 00609 line = img.scanLine(y); 00610 for(x=(y%2); x<img.width(); x+=2){ 00611 if(!setOn) 00612 *(line + (x >> 3)) &= ~(1 << (7-(x & 7))); 00613 else 00614 *(line + (x >> 3)) |= (1 << (7-(x & 7))); 00615 } 00616 } 00617 } 00618 } 00619 } 00620 } 00621 00622 void KIconEffect::semiTransparent(QPixmap &pix) 00623 { 00624 if (painterSupportsAntialiasing()) { 00625 QImage img=pix.toImage(); 00626 semiTransparent(img); 00627 pix = QPixmap::fromImage(img); 00628 return; 00629 } 00630 00631 QImage img; 00632 if (!pix.mask().isNull()) 00633 img = pix.mask().toImage(); 00634 else 00635 { 00636 img = QImage(pix.size(), QImage::Format_Mono); 00637 img.fill(1); 00638 } 00639 00640 for (int y=0; y<img.height(); y++) 00641 { 00642 QRgb* line = (QRgb*)img.scanLine(y); 00643 QRgb pattern = (y % 2) ? 0x55555555 : 0xaaaaaaaa; 00644 for (int x=0; x<(img.width()+31)/32; x++) 00645 line[x] &= pattern; 00646 } 00647 QBitmap mask; 00648 mask = QBitmap::fromImage(img); 00649 pix.setMask(mask); 00650 } 00651 00652 QImage KIconEffect::doublePixels(const QImage &src) const 00653 { 00654 int w = src.width(); 00655 int h = src.height(); 00656 00657 QImage dst( w*2, h*2, src.format() ); 00658 00659 if (src.depth() == 1) 00660 { 00661 kDebug(265) << "image depth 1 not supported\n"; 00662 return QImage(); 00663 } 00664 00665 int x, y; 00666 if (src.depth() == 32) 00667 { 00668 QRgb* l1, *l2; 00669 for (y=0; y<h; ++y) 00670 { 00671 l1 = (QRgb*)src.scanLine(y); 00672 l2 = (QRgb*)dst.scanLine(y*2); 00673 for (x=0; x<w; ++x) 00674 { 00675 l2[x*2] = l2[x*2+1] = l1[x]; 00676 } 00677 memcpy(dst.scanLine(y*2+1), l2, dst.bytesPerLine()); 00678 } 00679 } else 00680 { 00681 for (x=0; x<src.numColors(); ++x) 00682 dst.setColor(x, src.color(x)); 00683 00684 const unsigned char *l1; 00685 unsigned char *l2; 00686 for (y=0; y<h; ++y) 00687 { 00688 l1 = src.scanLine(y); 00689 l2 = dst.scanLine(y*2); 00690 for (x=0; x<w; ++x) 00691 { 00692 l2[x*2] = l1[x]; 00693 l2[x*2+1] = l1[x]; 00694 } 00695 memcpy(dst.scanLine(y*2+1), l2, dst.bytesPerLine()); 00696 } 00697 } 00698 return dst; 00699 } 00700 00701 void KIconEffect::overlay(QImage &src, QImage &overlay) 00702 { 00703 if (src.depth() != overlay.depth()) 00704 { 00705 kDebug(265) << "Image depth src (" << src.depth() << ") != overlay " << "(" << overlay.depth() << ")!\n"; 00706 return; 00707 } 00708 if (src.size() != overlay.size()) 00709 { 00710 kDebug(265) << "Image size src != overlay\n"; 00711 return; 00712 } 00713 if (src.format() == QImage::Format_ARGB32_Premultiplied) 00714 src = src.convertToFormat(QImage::Format_ARGB32); 00715 00716 if (overlay.format() == QImage::Format_RGB32) 00717 { 00718 kDebug(265) << "Overlay doesn't have alpha buffer!\n"; 00719 return; 00720 } 00721 else if (overlay.format() == QImage::Format_ARGB32_Premultiplied) 00722 overlay = overlay.convertToFormat(QImage::Format_ARGB32); 00723 00724 int i, j; 00725 00726 // We don't do 1 bpp 00727 00728 if (src.depth() == 1) 00729 { 00730 kDebug(265) << "1bpp not supported!\n"; 00731 return; 00732 } 00733 00734 // Overlay at 8 bpp doesn't use alpha blending 00735 00736 if (src.depth() == 8) 00737 { 00738 if (src.numColors() + overlay.numColors() > 255) 00739 { 00740 kDebug(265) << "Too many colors in src + overlay!\n"; 00741 return; 00742 } 00743 00744 // Find transparent pixel in overlay 00745 int trans; 00746 for (trans=0; trans<overlay.numColors(); trans++) 00747 { 00748 if (qAlpha(overlay.color(trans)) == 0) 00749 { 00750 kDebug(265) << "transparent pixel found at " << trans << "\n"; 00751 break; 00752 } 00753 } 00754 if (trans == overlay.numColors()) 00755 { 00756 kDebug(265) << "transparent pixel not found!\n"; 00757 return; 00758 } 00759 00760 // Merge color tables 00761 int nc = src.numColors(); 00762 src.setNumColors(nc + overlay.numColors()); 00763 for (i=0; i<overlay.numColors(); ++i) 00764 { 00765 src.setColor(nc+i, overlay.color(i)); 00766 } 00767 00768 // Overwrite nontransparent pixels. 00769 unsigned char *oline, *sline; 00770 for (i=0; i<src.height(); ++i) 00771 { 00772 oline = overlay.scanLine(i); 00773 sline = src.scanLine(i); 00774 for (j=0; j<src.width(); ++j) 00775 { 00776 if (oline[j] != trans) 00777 sline[j] = oline[j]+nc; 00778 } 00779 } 00780 } 00781 00782 // Overlay at 32 bpp does use alpha blending 00783 00784 if (src.depth() == 32) 00785 { 00786 QRgb* oline, *sline; 00787 int r1, g1, b1, a1; 00788 int r2, g2, b2, a2; 00789 00790 for (i=0; i<src.height(); ++i) 00791 { 00792 oline = (QRgb*)overlay.scanLine(i); 00793 sline = (QRgb*)src.scanLine(i); 00794 00795 for (j=0; j<src.width(); ++j) 00796 { 00797 r1 = qRed(oline[j]); 00798 g1 = qGreen(oline[j]); 00799 b1 = qBlue(oline[j]); 00800 a1 = qAlpha(oline[j]); 00801 00802 r2 = qRed(sline[j]); 00803 g2 = qGreen(sline[j]); 00804 b2 = qBlue(sline[j]); 00805 a2 = qAlpha(sline[j]); 00806 00807 r2 = (a1 * r1 + (0xff - a1) * r2) >> 8; 00808 g2 = (a1 * g1 + (0xff - a1) * g2) >> 8; 00809 b2 = (a1 * b1 + (0xff - a1) * b2) >> 8; 00810 a2 = qMax(a1, a2); 00811 00812 sline[j] = qRgba(r2, g2, b2, a2); 00813 } 00814 } 00815 } 00816 00817 return; 00818 } 00819
KDE 4.6 API Reference