Subversion Repositories Scribus

Compare Revisions

Ignore whitespace Rev 6550 → Rev 6549

/branches/Version13x/Scribus/scribus/plugins/colorwheel/colorblind.cpp
0,0 → 1,250
/*
For general Scribus (>=1.3.2) copyright and licensing information please refer
to the COPYING file provided with the program. Following this notice may exist
a copyright and/or license notice that predates the release of Scribus 1.3.2
for which a new license (GPL+exception) is in place.
*/
#include "colorblind.h"
#include "colorblind.moc"
 
#include <math.h>
 
//#define CLAMP(x, low, high) (((x) > (high)) ? (high) : (((x) < (low)) ? (low) : (x)))
 
 
VisionDefectColor::VisionDefectColor(int r, int g, int b)
{
red = (double)r;
green = (double)g;
blue = (double)b;
originalColor = QColor(r, g, b);
init();
}
 
VisionDefectColor::VisionDefectColor(QColor c)
{
red = (double)c.red();
green = (double)c.green();
blue = (double)c.blue();
originalColor = c;
init();
}
 
VisionDefectColor::VisionDefectColor()
{
red = 0.0;
green = 0.0;
blue = 0.0;
originalColor = QColor(0, 0, 0);
init();
}
 
void VisionDefectColor::init()
{
rgb2lms[0] = 0.05059983;
rgb2lms[1] = 0.08585369;
rgb2lms[2] = 0.00952420;
 
rgb2lms[3] = 0.01893033;
rgb2lms[4] = 0.08925308;
rgb2lms[5] = 0.01370054;
 
rgb2lms[6] = 0.00292202;
rgb2lms[7] = 0.00975732;
rgb2lms[8] = 0.07145979;
 
lms2rgb[0] = 30.830854;
lms2rgb[1] = -29.832659;
lms2rgb[2] = 1.610474;
 
lms2rgb[3] = -6.481468;
lms2rgb[4] = 17.715578;
lms2rgb[5] = -2.532642;
 
lms2rgb[6] = -0.375690;
lms2rgb[7] = -1.199062;
lms2rgb[8] = 14.273846;
 
gammaRGB[0] = 2.1;
gammaRGB[1] = 2.0;
gammaRGB[2] = 2.1;
}
 
void VisionDefectColor::convertDefect()
{
double tmp;
 
/* Remove gamma to linearize RGB intensities */
red = pow(red, 1.0 / gammaRGB[0]);
green = pow(green, 1.0 / gammaRGB[1]);
blue = pow(blue, 1.0 / gammaRGB[2]);
 
/* Convert to LMS (dot product with transform matrix) */
double redOld = red;
double greenOld = green;
 
red = redOld * rgb2lms[0] + greenOld * rgb2lms[1] + blue * rgb2lms[2];
green = redOld * rgb2lms[3] + greenOld * rgb2lms[4] + blue * rgb2lms[5];
blue = redOld * rgb2lms[6] + greenOld * rgb2lms[7] + blue * rgb2lms[8];
 
switch (deficiency)
{
case normalVision:
break;
case deuteranopeVision:
setupDefect();
tmp = blue / red;
/* See which side of the inflection line we fall... */
if (tmp < inflection)
green = -(a1 * red + c1 * blue) / b1;
else
green = -(a2 * red + c2 * blue) / b2;
break;
case protanopeVision:
setupDefect();
tmp = blue / green;
/* See which side of the inflection line we fall... */
if (tmp < inflection)
red = -(b1 * green + c1 * blue) / a1;
else
red = -(b2 * green + c2 * blue) / a2;
break;
case tritanopeVision:
setupDefect();
tmp = green / red;
/* See which side of the inflection line we fall... */
if (tmp < inflection)
blue = -(a1 * red + b1 * green) / c1;
else
blue = -(a2 * red + b2 * green) / c2;
break;
case colorBlindnessVision:
{
double gray = clamp(0.3 * originalColor.red()
+ 0.59 * originalColor.green()
+ 0.11 * originalColor.blue(), 0, 255);
red = gray;
green = gray;
blue = gray;
return; // no other transformations!
}
default:
break;
}
 
/* Convert back to RGB (cross product with transform matrix) */
redOld = red;
greenOld = green;
 
red = redOld * lms2rgb[0] + greenOld * lms2rgb[1] + blue * lms2rgb[2];
green = redOld * lms2rgb[3] + greenOld * lms2rgb[4] + blue * lms2rgb[5];
blue = redOld * lms2rgb[6] + greenOld * lms2rgb[7] + blue * lms2rgb[8];
 
/* Apply gamma to go back to non-linear intensities */
red = pow(red, gammaRGB[0]);
green = pow(green, gammaRGB[1]);
blue = pow(blue, gammaRGB[2]);
 
/* Ensure that we stay within the RGB gamut */
/* *** FIX THIS: it would be better to desaturate than blindly clip. */
red = clamp(red, 0.0, 255.0);
green = clamp(green, 0.0, 255.0);
blue = clamp(blue, 0.0, 255.0);
}
 
QColor VisionDefectColor::convertDefect(QColor c, int d)
{
red = (double)c.red();
green = (double)c.green();
blue = (double)c.blue();
originalColor = c;
init();
deficiency = d;
convertDefect();
return getColor();
}
 
void VisionDefectColor::setupDefect()
{
double anchor_e[3];
double anchor[12];
 
/*
Load the LMS anchor-point values for lambda = 475 & 485 nm (for
protans & deutans) and the LMS values for lambda = 575 & 660 nm
(for tritans)
*/
anchor[0] = 0.08008; anchor[1] = 0.1579; anchor[2] = 0.5897;
anchor[3] = 0.1284; anchor[4] = 0.2237; anchor[5] = 0.3636;
anchor[6] = 0.9856; anchor[7] = 0.7325; anchor[8] = 0.001079;
anchor[9] = 0.0914; anchor[10] = 0.007009; anchor[11] = 0.0;
 
/* We also need LMS for RGB=(1,1,1)- the equal-energy point (one of
* our anchors) (we can just peel this out of the rgb2lms transform
* matrix)
*/
anchor_e[0] = rgb2lms[0] + rgb2lms[1] + rgb2lms[2];
anchor_e[1] = rgb2lms[3] + rgb2lms[4] + rgb2lms[5];
anchor_e[2] = rgb2lms[6] + rgb2lms[7] + rgb2lms[8];
 
switch (deficiency)
{
case deuteranopeVision:
/* find a,b,c for lam=575nm and lam=475 */
a1 = anchor_e[1] * anchor[8] - anchor_e[2] * anchor[7];
b1 = anchor_e[2] * anchor[6] - anchor_e[0] * anchor[8];
c1 = anchor_e[0] * anchor[7] - anchor_e[1] * anchor[6];
a2 = anchor_e[1] * anchor[2] - anchor_e[2] * anchor[1];
b2 = anchor_e[2] * anchor[0] - anchor_e[0] * anchor[2];
c2 = anchor_e[0] * anchor[1] - anchor_e[1] * anchor[0];
inflection = (anchor_e[2] / anchor_e[0]);
break;
case protanopeVision:
/* find a,b,c for lam=575nm and lam=475 */
a1 = anchor_e[1] * anchor[8] - anchor_e[2] * anchor[7];
b1 = anchor_e[2] * anchor[6] - anchor_e[0] * anchor[8];
c1 = anchor_e[0] * anchor[7] - anchor_e[1] * anchor[6];
a2 = anchor_e[1] * anchor[2] - anchor_e[2] * anchor[1];
b2 = anchor_e[2] * anchor[0] - anchor_e[0] * anchor[2];
c2 = anchor_e[0] * anchor[1] - anchor_e[1] * anchor[0];
inflection = (anchor_e[2] / anchor_e[1]);
break;
case tritanopeVision:
/* Set 1: regions where lambda_a=575, set 2: lambda_a=475 */
a1 = anchor_e[1] * anchor[11] - anchor_e[2] * anchor[10];
b1 = anchor_e[2] * anchor[9] - anchor_e[0] * anchor[11];
c1 = anchor_e[0] * anchor[10] - anchor_e[1] * anchor[9];
a2 = anchor_e[1] * anchor[5] - anchor_e[2] * anchor[4];
b2 = anchor_e[2] * anchor[3] - anchor_e[0] * anchor[5];
c2 = anchor_e[0] * anchor[4] - anchor_e[1] * anchor[3];
inflection = (anchor_e[1] / anchor_e[0]);
break;
}
}
 
uint VisionDefectColor::getRed()
{
return (uint)red;
}
 
uint VisionDefectColor::getGreen()
{
return (uint)green;
}
 
uint VisionDefectColor::getBlue()
{
return (uint)blue;
}
 
QColor VisionDefectColor::getColor()
{
return QColor(getRed(), getGreen(), getBlue());
}
 
double VisionDefectColor::clamp(double x, double low, double high)
{
double ret;
(x > high) ? ret = high : ((x < low) ? ret = low : ret = x);
return ret;
}
Property changes:
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+Author Date Id Revision
\ No newline at end of property
Index: Scribus/scribus/plugins/colorwheel/colorblind.h
===================================================================
--- Scribus/scribus/plugins/colorwheel/colorblind.h (nonexistent)
+++ Scribus/scribus/plugins/colorwheel/colorblind.h (revision 6549)
@@ -0,0 +1,161 @@
+/*
+For general Scribus (>=1.3.2) copyright and licensing information please refer
+to the COPYING file provided with the program. Following this notice may exist
+a copyright and/or license notice that predates the release of Scribus 1.3.2
+for which a new license (GPL+exception) is in place.
+*/
+#ifndef COLORBLIND_H
+#define COLORBLIND_H
+
+#include <qvariant.h>
+#include <qcolor.h>
+#include <qobject.h>
+
+/*! \brief This code is an implementation of an algorithm described by Hans Brettel,
+Francoise Vienot and John Mollon in the Journal of the Optical Society of
+America V14(10), pg 2647. (See http://vischeck.com/ for more info.).
+
+Based on the GIMP's cdisplay_colorblind.c
+by Michael Natterer <mitch@gimp.org>, Sven Neumann <sven@gimp.org>,
+Robert Dougherty <bob@vischeck.com> and Alex Wade <alex@vischeck.com>.
+
+This code is written using "Scribus coding standard" as a part of the
+Scribus project (www.scribus.net).
+
+\author Petr Vanek <petr@scribus.info>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+class VisionDefectColor : public QObject, public QColor
+{
+ Q_OBJECT
+public:
+ /*! \brief Enumerate Vision Defects for readable ComboBox access */
+ enum defectMode {
+ normalVision = 0,
+ protanopeVision = 1,
+ deuteranopeVision = 2,
+ tritanopeVision = 3,
+ colorBlindnessVision = 4
+ };
+
+ /*! \brief QColor like constructors. Setup the RGB parts, then init().
+ \param r red part of the color
+ \param g green part of the color
+ \param b blue part of the color
+ */
+ VisionDefectColor(int r, int g, int b);
+ /*! \brief QColor like constructors. Setup the RGB parts, then init().
+ \param c QColor object
+ */
+ VisionDefectColor(QColor c);
+
+ /*! \brief Default constructors. Setup the RGB parts to default values, then init().
+ */
+ VisionDefectColor();
+
+ /*! \brief Actual defect type. One of the 'defectMode' */
+ int deficiency;
+
+ /*! \brief Perform conversion itself.
+ Gama removing, RGB2LSM, matrix operation for selected deficiency,
+ LSM2RGB, gama applying. */
+ void convertDefect();
+
+ /*! \brief Perform conversion itself. Confidence overload to perform the conversion in one step;
+ \param c QColor object
+ \param d defect type
+ \retval QColor converted color
+ Gama removing, RGB2LSM, matrix operation for selected deficiency,
+ LSM2RGB, gama applying. */
+ QColor convertDefect(QColor c, int d);
+
+ /*! \brief Return the color parts
+ \retval uint red part
+ */
+ uint getRed();
+ /*! \brief Return the color parts
+ \retval uint green part
+ */
+ uint getGreen();
+ /*! \brief Return the color parts
+ \retval uint blue part
+ */
+ uint getBlue();
+ /*! \brief Return QColor
+ \retval QColor new QColor
+ */
+ QColor getColor();
+
+private:
+ /*! \brief Convert matrix */
+ double rgb2lms[9];
+ /*! \brief Convert matrix */
+ double lms2rgb[9];
+ /*! \brief Gamma matrix */
+ double gammaRGB[3];
+
+ /*! \brief cross products with transform matrixes for actual defect */
+ double a1, b1, c1;
+ /*! \brief cross products with transform matrixes for actual defect */
+ double a2, b2, c2;
+ /*! \brief Inflection border line */
+ double inflection;
+
+ /*! \brief Internal RGB color parts */
+ double red, green, blue;
+
+ /*! \brief original color */
+ QColor originalColor;
+
+ /*! \brief Initialization of the internal values. rgb2lms, lms2rgb etc.
+ For most modern Cathode-Ray Tube monitors (CRTs), the following
+ are good estimates of the RGB->LMS and LMS->RGB transform
+ matrices. They are based on spectra measured on a typical CRT
+ with a PhotoResearch PR650 spectral photometer and the Stockman
+ human cone fundamentals. NOTE: these estimates will NOT work well
+ for LCDs!
+ The RGB<->LMS transforms are computed from the human cone
+ photo-pigment absorption spectra and the monitor phosphor
+ emission spectra. These parameters are fairly constant for most
+ humans and most montiors (at least for modern CRTs). However,
+ gamma will vary quite a bit, as it is a property of the monitor
+ (eg. amplifier gain), the video card, and even the
+ software. Further, users can adjust their gammas (either via
+ adjusting the monitor amp gains or in software). That said, the
+ following are the gamma estimates that we have used in the
+ Vischeck code. Many colorblind users have viewed our simulations
+ and told us that they "work" (simulated and original images are
+ indistinguishabled).
+ */
+ void init();
+
+ /*! \brief This function performs initialisations that are dependant
+ on the type of color deficiency (see defectMode). */
+ void setupDefect();
+
+ /*! \brief Ensures that x is between the limits set by low and high.
+ Glib CLAMP() macro replacement for C++ speedup optimalization.
+ \param x value itself
+ \param low low border
+ \param high high border
+ \retval double value from interval
+ */
+ double clamp(double x, double low, double high);
+
+};
+
+#endif
/Scribus/scribus/plugins/colorwheel/colorblind.h
Property changes:
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+Author Date Id Revision
\ No newline at end of property
Index: Scribus/scribus/plugins/colorwheel/CMakeLists.txt
===================================================================
--- Scribus/scribus/plugins/colorwheel/CMakeLists.txt (revision 6550)
+++ Scribus/scribus/plugins/colorwheel/CMakeLists.txt (revision 6549)
@@ -8,6 +8,7 @@
)
SET(COLORWHEEL_PLUGIN_MOC_CLASSES
+colorblind.h
colorwheel.h
colorwheelwidget.h
cwdialog.h
@@ -14,6 +15,7 @@
)
SET(COLORWHEEL_PLUGIN_SOURCES
+colorblind.cpp
colorwheel.cpp
colorwheelwidget.cpp
cwdialog.cpp
/branches/Version13x/Scribus/scribus/plugins/colorwheel/Makefile.am
6,9 → 6,9
 
libcolorwheel_la_LDFLAGS = -version-info 0:0:0
libcolorwheel_la_METASOURCES = AUTO
libcolorwheel_la_SOURCES = cwdialogbase.ui colorwheel.cpp colorwheelwidget.cpp cwdialog.cpp
libcolorwheel_la_SOURCES = cwdialogbase.ui colorwheel.cpp colorwheelwidget.cpp cwdialog.cpp colorblind.cpp
 
EXTRA_DIST = cwdialogbase.ui colorwheel.cpp colorwheel.h colorwheelwidget.cpp colorwheelwidget.h cwdialog.cpp cwdialog.h
EXTRA_DIST = cwdialogbase.ui colorwheel.cpp colorwheel.h colorwheelwidget.cpp colorwheelwidget.h cwdialog.cpp cwdialog.h colorblind.cpp colorblind.h
 
KDE_OPTIONS = qtonly
AM_LDFLAGS = $(LIBFREETYPE_LIBS) $(MODULE_LINK_FLAGS)