lib Library API Documentation

koColor.cc

00001 /* This file is part of the KDE project
00002   Copyright (c) 1999 Matthias Elter (me@kde.org)
00003   Copyright (c) 2001-2002 Igor Jansen (rm@kde.org)
00004 
00005    This library is free software; you can redistribute it and/or
00006    modify it under the terms of the GNU Library General Public
00007    License as published by the Free Software Foundation; either
00008    version 2 of the License, or (at your option) any later version.
00009 
00010    This library is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY; without even the implied warranty of
00012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013    Library General Public License for more details.
00014 
00015    You should have received a copy of the GNU Library General Public License
00016    along with this library; see the file COPYING.LIB.  If not, write to
00017    the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
00018    Boston, MA 02111-1307, USA.
00019 */
00020 
00021 #include "koColor.h"
00022 #include "kdebug.h"
00023 #include <cmath>
00024 
00025 KoColor::KoColor()
00026 {
00027   // initialise to black
00028   mNative = csRGB;
00029   // RGB
00030   mR = 0;
00031   mG = 0;
00032   mB = 0;
00033   // HSV
00034   mH =  mV = 0;
00035   mS = 100;
00036   // CMYK
00037   mC = 0;
00038   mY = 0;
00039   mM = 0;
00040   mK = 0;
00041   // Lab
00042   mL = 0;
00043   ma = 0;
00044   mB = 0;
00045   rgbChanged();
00046 }
00047 
00048 KoColor::KoColor(int a, int b, int c, cSpace m)
00049 {
00050   switch(m)
00051   {
00052   case csRGB:
00053     mR = a;
00054     mG = b;
00055     mB = c;
00056     mNative = csRGB;
00057     rgbChanged();
00058     break;
00059   case csHSV:
00060     mH = a;
00061     mS = b;
00062     mV = c;
00063     mNative = csHSV;
00064     hsvChanged();
00065     break;
00066   case csLab:
00067     mL = a;
00068     ma = b;
00069     mB = c;
00070     mNative = csLab;
00071     labChanged();
00072     break;
00073   default:
00074     mR = 0;
00075     mG = 0;
00076     mB = 0;
00077     mNative = csRGB;
00078     rgbChanged();
00079   }
00080 }
00081 
00082 KoColor::KoColor(int c, int m, int y, int k)
00083 {
00084   mC = c;
00085   mM = m;
00086   mY = y;
00087   mK = k;
00088   mNative = csCMYK;
00089   cmykChanged();
00090 }
00091 
00092 KoColor::KoColor(const QColor &c)
00093 {
00094   mR = c.red();
00095   mG = c.green();
00096   mB = c.blue();
00097   mNative = csRGB;
00098   rgbChanged();
00099 }
00100 
00101 KoColor::KoColor(const QString &name)
00102 {
00103   setNamedColor(name);
00104 }
00105 
00106 int KoColor::R() const
00107 {
00108   if(!mRGBvalid)
00109     calcRGB();
00110   return mR;
00111 }
00112 
00113 int KoColor::G() const
00114 {
00115   if(!mRGBvalid)
00116     calcRGB();
00117   return mG;
00118 }
00119 
00120 int KoColor::B() const
00121 {
00122   if(!mRGBvalid)
00123     calcRGB();
00124   return mB;
00125 }
00126 
00127 int KoColor::H() const
00128 {
00129   if(!mHSVvalid)
00130     calcHSV();
00131   return mH;
00132 }
00133 
00134 int KoColor::S() const
00135 {
00136   if(!mHSVvalid)
00137     calcHSV();
00138   return mS;
00139 }
00140 
00141 int KoColor::V() const
00142 {
00143   if(!mHSVvalid)
00144     calcHSV();
00145   return mV;
00146 }
00147 
00148 int KoColor::C() const
00149 {
00150   if(!mCMYKvalid)
00151     calcCMYK();
00152   return mC;
00153 }
00154 
00155 int KoColor::M() const
00156 {
00157   if(!mCMYKvalid)
00158     calcCMYK();
00159   return mM;
00160 }
00161 
00162 int KoColor::Y() const
00163 {
00164   if(!mCMYKvalid)
00165     calcCMYK();
00166   return mY;
00167 }
00168 
00169 int KoColor::K() const
00170 {
00171   if(!mCMYKvalid)
00172     calcCMYK();
00173   return mK;
00174 }
00175 
00176 int KoColor::L() const
00177 {
00178   if(!mLABvalid)
00179     calcLAB();
00180   return mL;
00181 }
00182 
00183 int KoColor::a() const
00184 {
00185   if(!mLABvalid)
00186     calcLAB();
00187   return ma;
00188 }
00189 
00190 int KoColor::b() const
00191 {
00192   if(!mLABvalid)
00193     calcLAB();
00194   return mB;
00195 }
00196 
00197 void KoColor::rgb(int *R, int *G, int *B) const
00198 {
00199   if(!mRGBvalid)
00200     calcRGB();
00201   *R = mR;
00202   *G = mG;
00203   *B = mB;
00204 }
00205 
00206 void KoColor::hsv(int *H, int *S, int *V) const
00207 {
00208   if(!mHSVvalid)
00209     calcHSV();
00210   *H = mH;
00211   *S = mS;
00212   *V = mV;
00213 }
00214 
00215 void KoColor::lab(int *L, int *a, int *b) const
00216 {
00217   if(!mLABvalid)
00218     calcLAB();
00219   *L = mL;
00220   *a = ma;
00221   *b = mB;
00222 }
00223 
00224 void KoColor::cmyk(int *C, int *M, int *Y, int *K) const
00225 {
00226   if(!mCMYKvalid)
00227     calcCMYK();
00228   *C = mC;
00229   *M = mM;
00230   *Y = mY;
00231   *K = mK;
00232 }
00233 
00234 QString KoColor::name() const
00235 {
00236   QString s;
00237   switch(mNative)
00238   {
00239   case csRGB:
00240     s.sprintf("#%02x%02x%02x", R(), G(), B());
00241     break;
00242   case csHSV:
00243     s.sprintf("$%02x%02x%02x", H(), S(), V());
00244     break;
00245   case csCMYK:
00246     s.sprintf("@%02x%02x%02x%02x", C(), M(), Y(), K());
00247     break;
00248   case csLab:
00249     s.sprintf("*%02x%02x%02x", L(), a(), b());
00250     break;
00251   default:
00252     s.sprintf("#%02x%02x%02x", R(), G(), B());
00253   }
00254   return s;
00255 }
00256 
00257 QColor KoColor::color() const
00258 {
00259   if(!mRGBvalid)
00260     calcRGB();
00261   return QColor(mR, mG, mB);
00262 }
00263 
00264 void KoColor::setRGB(int R, int G, int B)
00265 {
00266   mR = R;
00267   mG = G;
00268   mB = B;
00269   mNative = csRGB;
00270   rgbChanged();
00271 }
00272 
00273 void KoColor::setHSV(int H, int S, int V)
00274 {
00275   mH = H;
00276   mS = S;
00277   mV = V;
00278   mNative = csHSV;
00279   hsvChanged();
00280 }
00281 
00282 void KoColor::setLab(int L, int a, int b)
00283 {
00284   mL = L;
00285   ma = a;
00286   mB = b;
00287   mNative = csLab;
00288   labChanged();
00289 }
00290 
00291 void KoColor::setCMYK(int C, int M, int Y, int K)
00292 {
00293   mC = C;
00294   mM = M;
00295   mY = Y;
00296   mK = K;
00297   mNative = csCMYK;
00298   cmykChanged();
00299 }
00300 
00301 void KoColor::setNamedColor(const QString &name)
00302 {
00303   switch(name[0])
00304   {
00305   case '#':
00306     mR = (hex2int(name[1]) << 4) + hex2int(name[2]);
00307     mG = (hex2int(name[3]) << 4) + hex2int(name[4]);
00308     mB = (hex2int(name[5]) << 4) + hex2int(name[6]);
00309     mNative = csRGB;
00310     rgbChanged();
00311     break;
00312   case '$':
00313     mH = (hex2int(name[1]) << 4) + hex2int(name[2]);
00314     mS = (hex2int(name[3]) << 4) + hex2int(name[4]);
00315     mV = (hex2int(name[5]) << 4) + hex2int(name[6]);
00316     mNative = csHSV;
00317     hsvChanged();
00318     break;
00319   case '@':
00320     mC = (hex2int(name[1]) << 4) + hex2int(name[2]);
00321     mM = (hex2int(name[3]) << 4) + hex2int(name[4]);
00322     mY = (hex2int(name[5]) << 4) + hex2int(name[6]);
00323     mK = (hex2int(name[7]) << 4) + hex2int(name[8]);
00324     mNative = csCMYK;
00325     cmykChanged();
00326     break;
00327   case '*':
00328     mL = (hex2int(name[1]) << 4) + hex2int(name[2]);
00329     ma = (hex2int(name[3]) << 4) + hex2int(name[4]);
00330     mb = (hex2int(name[5]) << 4) + hex2int(name[6]);
00331     mNative = csLab;
00332     labChanged();
00333     break;
00334   default:
00335     mR = 0;
00336     mG = 0;
00337     mB = 0;
00338     mNative = csRGB;
00339     rgbChanged();
00340   }
00341 }
00342 
00343 void KoColor::setColor(const QColor &c)
00344 {
00345   mR = c.red();
00346   mG = c.green();
00347   mB = c.blue();
00348   mNative = csRGB;
00349   rgbChanged();
00350 }
00351 
00352 void KoColor::RGBtoHSV(int R, int G, int B, int *H, int *S, int *V)
00353 {
00354   unsigned int max = R;
00355   unsigned int min = R;
00356   unsigned char maxValue = 0; // r = 0, g = 1, b = 2
00357 
00358   // find maximum and minimum RGB values
00359   if(static_cast<unsigned int>(G) > max)
00360   {
00361     max = G;
00362     maxValue = 1;
00363   }
00364   if(static_cast<unsigned int>(B) > max)
00365   {
00366     max = B;
00367     maxValue = 2;
00368   }
00369 
00370   if(static_cast<unsigned int>(G) < min)
00371     min = G;
00372   if(static_cast<unsigned int>(B) < min )
00373     min = B;
00374 
00375   int delta = max - min;
00376   *V = max; // value
00377   *S = max ? (510 * delta + max) / ( 2 * max) : 0; // saturation
00378 
00379   // calc hue
00380   if(*S == 0)
00381     *H = -1; // undefined hue
00382   else
00383   {
00384     switch(maxValue)
00385     {
00386     case 0:  // red
00387       if(G >= B)
00388         *H = (120 * (G - B) + delta) / (2 * delta);
00389       else
00390         *H = (120 * (G - B + delta) + delta) / (2 * delta) + 300;
00391       break;
00392     case 1:  // green
00393       if(B > R)
00394         *H = 120 + (120 * (B - R) + delta) / (2 * delta);
00395       else
00396         *H = 60 + (120 * (B - R + delta) + delta) / (2 * delta);
00397       break;
00398     case 2:  // blue
00399       if(R > G)
00400         *H = 240 + (120 * (R - G) + delta) / (2 * delta);
00401       else
00402         *H = 180 + (120 * (R - G + delta) + delta) / (2 * delta);
00403       break;
00404     }
00405   }
00406 }
00407 
00408 void KoColor::RGBtoLAB(int R, int G, int B, int *L, int *a, int *b)
00409 {
00410   // Convert between RGB and CIE-Lab color spaces
00411   // Uses ITU-R recommendation BT.709 with D65 as reference white.
00412   // algorithm contributed by "Mark A. Ruzon" <ruzon@CS.Stanford.EDU>
00413 
00414   double X, Y, Z, fX, fY, fZ;
00415 
00416   X = 0.412453 * R + 0.357580 * G + 0.180423 * B;
00417   Y = 0.212671 * R + 0.715160 * G + 0.072169 * B;
00418   Z = 0.019334 * R + 0.119193 * G + 0.950227 * B;
00419 
00420   X /= (255 * 0.950456);
00421   Y /=  255;
00422   Z /= (255 * 1.088754);
00423 
00424   if(Y > 0.008856)
00425   {
00426     fY = pow(Y, 1.0 / 3.0);
00427     *L = static_cast<int>(116.0 * fY - 16.0 + 0.5);
00428   }
00429   else
00430   {
00431     fY = 7.787 * Y + 16.0 / 116.0;
00432     *L = static_cast<int>(903.3 * Y + 0.5);
00433   }
00434 
00435   if(X > 0.008856)
00436     fX = pow(X, 1.0 / 3.0);
00437   else
00438     fX = 7.787 * X + 16.0 / 116.0;
00439 
00440   if(Z > 0.008856)
00441     fZ = pow(Z, 1.0 / 3.0);
00442   else
00443     fZ = 7.787 * Z + 16.0 / 116.0;
00444 
00445   *a = static_cast<int>(500.0 * (fX - fY) + 0.5);
00446   *b = static_cast<int>(200.0 * (fY - fZ) + 0.5);
00447 }
00448 
00449 void KoColor::RGBtoCMYK(int R, int G, int B, int *C, int *M, int *Y, int *K)
00450 {
00451     // XXX: these algorithms aren't the best. See www.littlecms.com
00452     // for a suitable library, or the posting by Leo Rosenthol for
00453     // a better, but slower algorithm at
00454     // http://lists.kde.org/?l=koffice-devel&m=106698241227054&w=2
00455 
00456     *C = 255 - R;
00457     *M = 255 - G;
00458     *Y = 255 - B;
00459 
00460     int min = (*C < *M) ? *C : *M;
00461     *K = (min < *Y) ? min : *Y;
00462 
00463     *C -= *K;
00464     *M -= *K;
00465     *Y -= *K;
00466 
00467 }
00468 
00469 
00470 void KoColor::HSVtoRGB(int H, int S, int V, int *R, int *G, int *B)
00471 {
00472   *R = *G = *B = V;
00473 
00474   if(S != 0 && H != -1) // chromatic
00475   {
00476     if(H >= 360) // angle > 360
00477       H %= 360;
00478 
00479     unsigned int f = H % 60;
00480     H /= 60;
00481     unsigned int p = static_cast<unsigned int>(2*V*(255-S)+255)/510;
00482     unsigned int q, t;
00483 
00484     if(H & 1)
00485     {
00486       q = static_cast<unsigned int>(2 * V * (15300 - S * f) + 15300) / 30600;
00487       switch(H)
00488       {
00489       case 1:
00490         *R = static_cast<int>(q);
00491     *G = static_cast<int>(V);
00492     *B = static_cast<int>(p);
00493     break;
00494       case 3:
00495         *R = static_cast<int>(p);
00496     *G = static_cast<int>(q);
00497     *B = static_cast<int>(V);
00498     break;
00499       case 5:
00500         *R = static_cast<int>(V);
00501     *G = static_cast<int>(p);
00502     *B = static_cast<int>(q);
00503     break;
00504       }
00505     }
00506     else
00507     {
00508       t = static_cast<unsigned int>(2 * V * (15300 - (S * (60 - f))) + 15300) / 30600;
00509       switch(H)
00510       {
00511       case 0:
00512         *R = static_cast<int>(V);
00513         *G = static_cast<int>(t);
00514         *B = static_cast<int>(p);
00515         break;
00516       case 2:
00517         *R = static_cast<int>(p);
00518         *G = static_cast<int>(V);
00519         *B = static_cast<int>(t);
00520         break;
00521       case 4:
00522         *R = static_cast<int>(t);
00523         *G = static_cast<int>(p);
00524         *B = static_cast<int>(V);
00525         break;
00526       }
00527     }
00528   }
00529 }
00530 
00531 void KoColor::HSVtoLAB(int H, int S, int V, int *L, int *a, int *b)
00532 {
00533   int R, G, B;
00534   HSVtoRGB(H, S, V, &R, &G, &B);
00535   RGBtoLAB(R, G, B, L, a, b);
00536 }
00537 
00538 void KoColor::HSVtoCMYK(int H, int S, int V, int *C, int *M, int *Y, int*K)
00539 {
00540   int R, G, B;
00541   HSVtoRGB(H, S, V, &R, &G, &B);
00542   RGBtoCMYK(R, G, B, C, M, Y, K);
00543 }
00544 
00545 void KoColor::LABtoRGB(int L, int a, int b, int *R, int *G, int *B)
00546 {
00547   // Convert between RGB and CIE-Lab color spaces
00548   // Uses ITU-R recommendation BT.709 with D65 as reference white.
00549   // algorithm contributed by "Mark A. Ruzon" <ruzon@CS.Stanford.EDU>
00550 
00551   double X, Y, Z, fX, fY, fZ;
00552   int RR, GG, BB;
00553 
00554   fY = pow((L + 16.0) / 116.0, 3.0);
00555   if(fY < 0.008856)
00556     fY = L / 903.3;
00557   Y = fY;
00558 
00559   if(fY > 0.008856)
00560     fY = pow(fY, 1.0 / 3.0);
00561   else
00562     fY = 7.787 * fY + 16.0 / 116.0;
00563 
00564   fX = a / 500.0 + fY;
00565   if(fX > 0.206893)
00566     X = pow(fX, 3.0);
00567   else
00568     X = (fX - 16.0 / 116.0) / 7.787;
00569 
00570   fZ = fY - b / 200.0;
00571   if(fZ > 0.206893)
00572     Z = pow(fZ, 3.0);
00573   else
00574     Z = (fZ - 16.0/116.0) / 7.787;
00575 
00576   X *= 0.950456 * 255;
00577   Y *= 255;
00578   Z *= 1.088754 * 255;
00579 
00580   RR = static_cast<int>(3.240479 * X - 1.537150 * Y - 0.498535 * Z + 0.5);
00581   GG = static_cast<int>(-0.969256 * X + 1.875992 * Y + 0.041556 * Z + 0.5);
00582   BB = static_cast<int>(0.055648 * X - 0.204043 * Y + 1.057311 * Z + 0.5);
00583 
00584   *R = RR < 0 ? 0 : RR > 255 ? 255 : RR;
00585   *G = GG < 0 ? 0 : GG > 255 ? 255 : GG;
00586   *B = BB < 0 ? 0 : BB > 255 ? 255 : BB;
00587 }
00588 
00589 void KoColor::LABtoHSV(int L, int a, int b, int *H, int *S, int *V)
00590 {
00591   int R, G, B;
00592   LABtoRGB(L, a, b, &R, &G, &B);
00593   RGBtoHSV(R, G, B, H, S, V);
00594 }
00595 
00596 void KoColor::LABtoCMYK(int L, int a, int b, int *C, int *M, int *Y, int*K)
00597 {
00598   int R, G, B;
00599   LABtoRGB(L, a, b, &R, &G, &B);
00600   RGBtoCMYK(R, G, B, C, M, Y, K);
00601 }
00602 
00603 void KoColor::CMYKtoRGB(int C, int M, int Y, int K, int *R, int *G, int *B)
00604 {
00605   *R = 255 - (C + K);
00606   *G = 255 - (M + K);
00607   *B = 255 - (Y + K);
00608 }
00609 
00610 void KoColor::CMYKtoHSV(int C, int M, int Y, int K, int *H, int *S, int *V)
00611 {
00612   int R, G, B;
00613   CMYKtoRGB(C, M, Y, K, &R, &G, &B);
00614   RGBtoHSV(R, G, B, H, S, V);
00615 }
00616 
00617 void KoColor::CMYKtoLAB(int C, int M, int Y, int K, int *L, int *a, int *b)
00618 {
00619   int R, G, B;
00620   CMYKtoRGB(C, M, Y, K, &R, &G, &B);
00621   RGBtoLAB(R, G, B, L, a, b);
00622 }
00623 
00624 int KoColor::hex2int(QChar c)
00625 {
00626   if(c.isDigit())
00627     return c.digitValue();
00628   else if('A' <= c && c <= 'F')
00629     return c - 'A' + 10;
00630   else if('a' <= c && c <= 'f')
00631     return c - 'a' + 10;
00632   else
00633     return 0;
00634 }
00635 
00636 void KoColor::calcRGB() const
00637 {
00638   switch(mNative)
00639   {
00640   case csHSV:
00641     HSVtoRGB(mH, mS, mV, &mR, &mG, &mB);
00642     break;
00643   case csLab:
00644     LABtoRGB(mL, ma, mB, &mR, &mG, &mB);
00645     break;
00646   case csCMYK:
00647     CMYKtoRGB(mC, mM, mY, mK, &mR, &mG, &mB);
00648     break;
00649   default:
00650     break;
00651   }
00652   mRGBvalid = true;
00653 }
00654 
00655 void KoColor::calcHSV() const
00656 {
00657   switch(mNative)
00658   {
00659   case csRGB:
00660     RGBtoHSV(mR, mG, mB, &mH, &mS, &mV);
00661     break;
00662   case csLab:
00663     LABtoHSV(mL, ma, mB, &mH, &mS, &mV);
00664     break;
00665   case csCMYK:
00666     CMYKtoHSV(mC, mM, mY, mK, &mH, &mS, &mV);
00667     break;
00668   default:
00669     break;
00670   }
00671   mHSVvalid = true;
00672 }
00673 
00674 void KoColor::calcCMYK() const
00675 {
00676   switch(mNative)
00677   {
00678   case csRGB:
00679     RGBtoCMYK(mR, mG, mB, &mC, &mM, &mY, &mK);
00680     break;
00681   case csLab:
00682     LABtoCMYK(mL, ma, mB, &mC, &mM, &mY, &mK);
00683     break;
00684   case csHSV:
00685     HSVtoCMYK(mH, mS, mV, &mC, &mM, &mY, &mK);
00686     break;
00687   default:
00688     break;
00689   }
00690   mCMYKvalid = true;
00691 }
00692 
00693 void KoColor::calcLAB() const
00694 {
00695   switch(mNative)
00696   {
00697   case csRGB:
00698     RGBtoLAB(mR, mG, mB, &mL, &ma, &mB);
00699     break;
00700   case csHSV:
00701     HSVtoLAB(mH, mS, mV, &mL, &ma, &mB);
00702     break;
00703   case csCMYK:
00704     CMYKtoLAB(mC, mM, mY, mK, &mL, &ma, &mB);
00705     break;
00706   default:
00707     break;
00708   }
00709   mLABvalid = true;
00710 }
00711 
00712 void KoColor::rgbChanged() const
00713 {
00714   mRGBvalid = true;
00715   mHSVvalid = false;
00716   mCMYKvalid = false;
00717   mLABvalid = false;
00718 }
00719 
00720 void KoColor::hsvChanged() const
00721 {
00722   mRGBvalid = false;
00723   mHSVvalid = true;
00724   mCMYKvalid = false;
00725   mLABvalid = false;
00726 }
00727 
00728 void KoColor::cmykChanged() const
00729 {
00730   mRGBvalid = false;
00731   mHSVvalid = false;
00732   mCMYKvalid = true;
00733   mLABvalid = false;
00734 }
00735 
00736 void KoColor::labChanged() const
00737 {
00738   mRGBvalid = false;
00739   mHSVvalid = false;
00740   mCMYKvalid = false;
00741   mLABvalid = true;
00742 }
KDE Logo
This file is part of the documentation for lib Library Version 1.4.2.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Mon Feb 13 09:39:59 2006 by doxygen 1.4.2 written by Dimitri van Heesch, © 1997-2003