Back to index

scribus-ng  1.3.4.dfsg+svn20071115
colorblind.cpp
Go to the documentation of this file.
00001 /*
00002 For general Scribus (>=1.3.2) copyright and licensing information please refer
00003 to the COPYING file provided with the program. Following this notice may exist
00004 a copyright and/or license notice that predates the release of Scribus 1.3.2
00005 for which a new license (GPL+exception) is in place.
00006 */
00007 #include "colorblind.h"
00008 #include "colorblind.moc"
00009 
00010 #include <math.h>
00011 
00012 //#define CLAMP(x, low, high)  (((x) > (high)) ? (high) : (((x) < (low)) ? (low) : (x)))
00013 
00014 
00015 VisionDefectColor::VisionDefectColor(int r, int g, int b)
00016 {
00017        red = (double)r;
00018        green = (double)g;
00019        blue = (double)b;
00020        originalColor = QColor(r, g, b);
00021        init();
00022 }
00023 
00024 VisionDefectColor::VisionDefectColor(QColor c)
00025 {
00026        red = (double)c.red();
00027        green = (double)c.green();
00028        blue = (double)c.blue();
00029        originalColor = c;
00030        init();
00031 }
00032 
00033 VisionDefectColor::VisionDefectColor()
00034 {
00035        red = 0.0;
00036        green = 0.0;
00037        blue = 0.0;
00038        originalColor = QColor(0, 0, 0);
00039        init();
00040 }
00041 
00042 void VisionDefectColor::init()
00043 {
00044        rgb2lms[0] = 0.05059983;
00045        rgb2lms[1] = 0.08585369;
00046        rgb2lms[2] = 0.00952420;
00047 
00048        rgb2lms[3] = 0.01893033;
00049        rgb2lms[4] = 0.08925308;
00050        rgb2lms[5] = 0.01370054;
00051 
00052        rgb2lms[6] = 0.00292202;
00053        rgb2lms[7] = 0.00975732;
00054        rgb2lms[8] = 0.07145979;
00055 
00056        lms2rgb[0] =  30.830854;
00057        lms2rgb[1] = -29.832659;
00058        lms2rgb[2] =   1.610474;
00059 
00060        lms2rgb[3] =  -6.481468;
00061        lms2rgb[4] =  17.715578;
00062        lms2rgb[5] =  -2.532642;
00063 
00064        lms2rgb[6] =  -0.375690;
00065        lms2rgb[7] =  -1.199062;
00066        lms2rgb[8] =  14.273846;
00067 
00068        gammaRGB[0] = 2.1;
00069        gammaRGB[1] = 2.0;
00070        gammaRGB[2] = 2.1;
00071 }
00072 
00073 void VisionDefectColor::convertDefect()
00074 {
00075        double tmp;
00076 
00077        /* Remove gamma to linearize RGB intensities */
00078        red   = pow(red, 1.0 / gammaRGB[0]);
00079        green = pow(green, 1.0 / gammaRGB[1]);
00080        blue  = pow(blue, 1.0 / gammaRGB[2]);
00081 
00082        /* Convert to LMS (dot product with transform matrix) */
00083        double redOld   = red;
00084        double greenOld = green;
00085 
00086        red   = redOld * rgb2lms[0] + greenOld * rgb2lms[1] + blue * rgb2lms[2];
00087        green = redOld * rgb2lms[3] + greenOld * rgb2lms[4] + blue * rgb2lms[5];
00088        blue  = redOld * rgb2lms[6] + greenOld * rgb2lms[7] + blue * rgb2lms[8];
00089 
00090        switch (deficiency)
00091        {
00092               case normalVision:
00093                      break;
00094               case deuteranopeVision:
00095                      setupDefect();
00096                      tmp = blue / red;
00097                      /* See which side of the inflection line we fall... */
00098                      if (tmp < inflection)
00099                             green = -(a1 * red + c1 * blue) / b1;
00100                      else
00101                             green = -(a2 * red + c2 * blue) / b2;
00102                      break;
00103               case protanopeVision:
00104                      setupDefect();
00105                      tmp = blue / green;
00106                      /* See which side of the inflection line we fall... */
00107                      if (tmp < inflection)
00108                             red = -(b1 * green + c1 * blue) / a1;
00109                      else
00110                             red = -(b2 * green + c2 * blue) / a2;
00111                      break;
00112               case tritanopeVision:
00113                      setupDefect();
00114                      tmp = green / red;
00115                      /* See which side of the inflection line we fall... */
00116                      if (tmp < inflection)
00117                             blue = -(a1 * red + b1 * green) / c1;
00118                      else
00119                             blue = -(a2 * red + b2 * green) / c2;
00120                      break;
00121               case colorBlindnessVision:
00122               {
00123                      double gray = clamp(0.3 * originalColor.red()
00124                                           + 0.59 * originalColor.green()
00125                                           + 0.11 * originalColor.blue(), 0, 255);
00126                      red = gray;
00127                      green = gray;
00128                      blue = gray;
00129                      return; // no other transformations!
00130               }
00131               default:
00132                      break;
00133        }
00134 
00135        /* Convert back to RGB (cross product with transform matrix) */
00136        redOld   = red;
00137        greenOld = green;
00138 
00139        red   = redOld * lms2rgb[0] + greenOld * lms2rgb[1] + blue * lms2rgb[2];
00140        green = redOld * lms2rgb[3] + greenOld * lms2rgb[4] + blue * lms2rgb[5];
00141        blue  = redOld * lms2rgb[6] + greenOld * lms2rgb[7] + blue * lms2rgb[8];
00142 
00143        /* Apply gamma to go back to non-linear intensities */
00144        red   = pow(red, gammaRGB[0]);
00145        green = pow(green, gammaRGB[1]);
00146        blue  = pow(blue, gammaRGB[2]);
00147 
00148        /* Ensure that we stay within the RGB gamut */
00149        /* *** FIX THIS: it would be better to desaturate than blindly clip. */
00150        red   = clamp(red, 0.0, 255.0);
00151        green = clamp(green, 0.0, 255.0);
00152        blue  = clamp(blue, 0.0, 255.0);
00153 }
00154 
00155 QColor VisionDefectColor::convertDefect(QColor c, int d)
00156 {
00157        red = (double)c.red();
00158        green = (double)c.green();
00159        blue = (double)c.blue();
00160        originalColor = c;
00161        init();
00162        deficiency = d;
00163        convertDefect();
00164        return getColor();
00165 }
00166 
00167 void VisionDefectColor::setupDefect()
00168 {
00169        double anchor_e[3];
00170        double anchor[12];
00171 
00172        /*
00173        Load the LMS anchor-point values for lambda = 475 & 485 nm (for
00174        protans & deutans) and the LMS values for lambda = 575 & 660 nm
00175        (for tritans)
00176        */
00177        anchor[0] = 0.08008;  anchor[1]  = 0.1579;    anchor[2]  = 0.5897;
00178        anchor[3] = 0.1284;   anchor[4]  = 0.2237;    anchor[5]  = 0.3636;
00179        anchor[6] = 0.9856;   anchor[7]  = 0.7325;    anchor[8]  = 0.001079;
00180        anchor[9] = 0.0914;   anchor[10] = 0.007009;  anchor[11] = 0.0;
00181 
00182        /* We also need LMS for RGB=(1,1,1)- the equal-energy point (one of
00183        * our anchors) (we can just peel this out of the rgb2lms transform
00184        * matrix)
00185        */
00186        anchor_e[0] = rgb2lms[0] + rgb2lms[1] + rgb2lms[2];
00187        anchor_e[1] = rgb2lms[3] + rgb2lms[4] + rgb2lms[5];
00188        anchor_e[2] = rgb2lms[6] + rgb2lms[7] + rgb2lms[8];
00189 
00190        switch (deficiency)
00191        {
00192               case deuteranopeVision:
00193                      /* find a,b,c for lam=575nm and lam=475 */
00194                      a1 = anchor_e[1] * anchor[8] - anchor_e[2] * anchor[7];
00195                      b1 = anchor_e[2] * anchor[6] - anchor_e[0] * anchor[8];
00196                      c1 = anchor_e[0] * anchor[7] - anchor_e[1] * anchor[6];
00197                      a2 = anchor_e[1] * anchor[2] - anchor_e[2] * anchor[1];
00198                      b2 = anchor_e[2] * anchor[0] - anchor_e[0] * anchor[2];
00199                      c2 = anchor_e[0] * anchor[1] - anchor_e[1] * anchor[0];
00200                      inflection = (anchor_e[2] / anchor_e[0]);
00201                      break;
00202               case protanopeVision:
00203                      /* find a,b,c for lam=575nm and lam=475 */
00204                      a1 = anchor_e[1] * anchor[8] - anchor_e[2] * anchor[7];
00205                      b1 = anchor_e[2] * anchor[6] - anchor_e[0] * anchor[8];
00206                      c1 = anchor_e[0] * anchor[7] - anchor_e[1] * anchor[6];
00207                      a2 = anchor_e[1] * anchor[2] - anchor_e[2] * anchor[1];
00208                      b2 = anchor_e[2] * anchor[0] - anchor_e[0] * anchor[2];
00209                      c2 = anchor_e[0] * anchor[1] - anchor_e[1] * anchor[0];
00210                      inflection = (anchor_e[2] / anchor_e[1]);
00211                      break;
00212               case tritanopeVision:
00213                      /* Set 1: regions where lambda_a=575, set 2: lambda_a=475 */
00214                      a1 = anchor_e[1] * anchor[11] - anchor_e[2] * anchor[10];
00215                      b1 = anchor_e[2] * anchor[9]  - anchor_e[0] * anchor[11];
00216                      c1 = anchor_e[0] * anchor[10] - anchor_e[1] * anchor[9];
00217                      a2 = anchor_e[1] * anchor[5]  - anchor_e[2] * anchor[4];
00218                      b2 = anchor_e[2] * anchor[3]  - anchor_e[0] * anchor[5];
00219                      c2 = anchor_e[0] * anchor[4]  - anchor_e[1] * anchor[3];
00220                      inflection = (anchor_e[1] / anchor_e[0]);
00221                      break;
00222        }
00223 }
00224 
00225 uint VisionDefectColor::getRed()
00226 {
00227        return (uint)red;
00228 }
00229 
00230 uint VisionDefectColor::getGreen()
00231 {
00232        return (uint)green;
00233 }
00234 
00235 uint VisionDefectColor::getBlue()
00236 {
00237        return (uint)blue;
00238 }
00239 
00240 QColor VisionDefectColor::getColor()
00241 {
00242        return QColor(getRed(), getGreen(), getBlue());
00243 }
00244 
00245 double VisionDefectColor::clamp(double x, double low, double high)
00246 {
00247        double ret;
00248        (x > high) ? ret = high : ((x < low) ? ret = low : ret = x);
00249        return ret;
00250 }