Subversion Repositories Scribus

Compare Revisions

Ignore whitespace Rev 3104 → Rev 3107

/branches/Version13x/Scribus/scribus/plugins/colorwheel/cwdialog.h
19,15 → 19,6
 
/** \brief GUI dialog for Color Wheel Plugin.
Quite everything in this class is self explanatory (except few things ;)).
Ehm... And now to the "few things". There is some magic (read strange)
stuff since it's using the Vison Defects simulations. It is based on
the matrix operations. I'm computing it this way (plain multiplication)
to prevent new library dependecy - IMHO is no need to have some matrix
library for onlu 3 or 4 transformations of the 3x3 matrix.
I've took the "Digital Video Colourmaps for Checking the Legibility
of Displays of Dichromats" article by Francoise Vienot, Hans Brettel
and John D. Mollon as the base reference. Don't forget that google is
your friend ;)
\author Petr Vanek; petr@yarpen.cz
\date April 2005
*/
53,13 → 44,6
QComboBox* defectCombo;
 
protected:
/*! Enumerate Vision Defects for readable ComboBox access */
enum defectMode {
normalVision = 0,
protanopeVision = 1,
deuteranopeVision = 2,
colorBlindnessVision = 3
};
/** It fills a colors into list view. It takes colors
from ColorWheel widget. */
void fillColorList();
79,36 → 63,7
\param c input color. QColor from sample list.
\retval QColor It returns c for normalVision. It calls transformations for other filters*/
QColor computeDefect(QColor c);
/*! Converts RGB to the LMS color space
\param rgb original color
\param l returning reference to the "L" from LMS
\param m returning reference to the "M" from LMS
\param s returning reference to the "S" from LMS
*/
void getLMSfromRGB(QColor rgb, double *l, double *m, double *s);
/*! Converts LMS color to the RGB
\param l the "L" from LMS
\param m the "M" from LMS
\param s the "S" from LMS
\retval rgb color
*/
QColor getRGBfromLMS(double l, double m, double s);
/*! Compute Protanopy filter.
It doesn't need L.
\param m M from LMS
\param s S from LMS
\retval L from LMS
*/
double getProtanopesLMS(double m, double s);
/*! Compute Deuteranopy filter.
It doesn't need M.
\param l L from LMS
\param s S from LMS
\retval M from LMS
*/
double getDeuteranopesLMS(double l, double s);
 
 
public slots:
virtual void typeCombo_activated(int);
virtual void defectCombo_activated(int);
/branches/Version13x/Scribus/scribus/plugins/colorwheel/colorblind.cpp
0,0 → 1,223
#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();
}
 
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);
}
 
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/Makefile.am
===================================================================
--- Scribus/scribus/plugins/colorwheel/Makefile.am (revision 3104)
+++ Scribus/scribus/plugins/colorwheel/Makefile.am (revision 3107)
@@ -6,9 +6,9 @@
libcolorwheel_la_LDFLAGS = -version-info 0:0:0
libcolorwheel_la_METASOURCES = AUTO
-libcolorwheel_la_SOURCES = colorwheel.cpp colorwheelwidget.cpp cwdialog.cpp
+libcolorwheel_la_SOURCES = colorwheel.cpp colorwheelwidget.cpp cwdialog.cpp colorblind.cpp
-EXTRA_DIST = colorwheel.cpp colorwheel.h colorwheelwidget.cpp colorwheelwidget.h cwdialog.cpp cwdialog.h
+EXTRA_DIST = 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)
/branches/Version13x/Scribus/scribus/plugins/colorwheel/cwdialog.cpp
16,7 → 16,9
#include "prefsmanager.h"
#include "prefsfile.h"
#include "mpalette.h"
#include "colorblind.h"
 
 
extern ScribusApp SCRIBUS_API *ScApp;
 
ColorWheelDialog::ColorWheelDialog(QWidget* parent, const char* name, bool modal, WFlags fl)
98,8 → 100,9
typeCombo->insertItem(colorWheel->getTypeDescription(colorWheel->Tetradic), colorWheel->Tetradic);
// defects
defectCombo->insertItem(tr("Normal Vision"));
defectCombo->insertItem(tr("Protanopy"));
defectCombo->insertItem(tr("Deuteranopy"));
defectCombo->insertItem(tr("Protanopia (red)"));
defectCombo->insertItem(tr("Deuteranopia (green)"));
defectCombo->insertItem(tr("Tritanopia (blue)"));
defectCombo->insertItem(tr("Full Color Blindness"));
 
// preferences
331,59 → 334,13
 
QColor ColorWheelDialog::computeDefect(QColor c)
{
int g;
if (defectCombo->currentItem() == normalVision)
if (defectCombo->currentItem() == VisionDefectColor::normalVision)
return c;
double l, m, s;
getLMSfromRGB(c, &l, &m, &s);
switch (defectCombo->currentItem())
{
case (protanopeVision):
l = getProtanopesLMS(m, s);
break;
case (deuteranopeVision):
m = getDeuteranopesLMS(l, s);
break;
case (colorBlindnessVision):
// into gray
g = QMIN(qRound(0.3*c.red() + 0.59*c.green() + 0.11*c.blue()), 255);
return QColor(g, g, g);
default:
return c;
break;
}
return getRGBfromLMS(l, m, s);
VisionDefectColor *defect = new VisionDefectColor(c);
defect->deficiency = defectCombo->currentItem();
defect->convertDefect();
QColor nc = defect->getColor();
delete defect;
return nc;
}
 
void ColorWheelDialog::getLMSfromRGB(QColor rgb, double *l, double *m, double *s)
{
/* It's common matrix multiplication. I'm doing it this
way not to use more library dependencies (petr) */
double r = (double)rgb.red();
double g = (double)rgb.green();
double b = (double)rgb.blue();
*l = 17.88240*r + 43.5161*g + 4.11935*b;
*m = 3.45525*r + 27.1554*g + 3.86714*b;
*s = 0.0299566*r + 0.184309*g + 1.46709*b;
}
 
QColor ColorWheelDialog::getRGBfromLMS(double l, double m, double s)
{
/* inverse matrix to the getLMSfromRGB */
double r = 0.080944*l -0.130504*m + 0.116721*s;
double g = -0.010249*l + 0.054019*m -0.113615*s;
double b = -0.000365*l -0.004122*m + 0.693511*s;
return QColor((int)r, (int)g, (int)b);
}
 
/* M and S components without change */
double ColorWheelDialog::getProtanopesLMS(double m, double s)
{
return 2.02344*m - 2.52581*s;
}
 
/* L and S components without change */
double ColorWheelDialog::getDeuteranopesLMS(double l, double s)
{
return 0.494207*l + 1.24827*s;
}
/branches/Version13x/Scribus/scribus/plugins/colorwheel/colorblind.h
0,0 → 1,143
#ifndef COLORBLIND_H
#define COLORBLIND_H
 
#include <qvariant.h>
#include <qcolor.h>
#include <qobject.h>
 
/*! 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@yarpen.cz>
 
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:
/*! Enumerate Vision Defects for readable ComboBox access */
enum defectMode {
normalVision = 0,
protanopeVision = 1,
deuteranopeVision = 2,
tritanopeVision = 3,
colorBlindnessVision = 4
};
 
/*! 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);
/*! QColor like constructors. Setup the RGB parts, then init().
\param c QColor object
*/
VisionDefectColor(QColor c);
 
/*! Actual defect type. One of the 'defectMode' */
int deficiency;
 
/*! Perform conversion itself.
Gama removing, RGB2LSM, matrix operation for selected deficiency,
LSM2RGB, gama applying. */
void convertDefect();
 
/*! Return the color parts
\retval uint red part
*/
uint getRed();
/*! Return the color parts
\retval uint green part
*/
uint getGreen();
/*! Return the color parts
\retval uint blue part
*/
uint getBlue();
/*! Return QColor
\retval QColor new QColor
*/
QColor getColor();
 
private:
/*! Convert matrix */
double rgb2lms[9];
/*! Convert matrix */
double lms2rgb[9];
/*! Gamma matrix */
double gammaRGB[3];
 
/*! cross products with transform matrixes for actual defect */
double a1, b1, c1;
/*! cross products with transform matrixes for actual defect */
double a2, b2, c2;
/*! Inflection border line */
double inflection;
 
/*! Internal RGB color parts */
double red, green, blue;
 
/*! original color */
QColor originalColor;
 
/*! 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();
 
/*! This function performs initialisations that are dependant
on the type of color deficiency (see defectMode). */
void setupDefect();
 
/*! 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
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