use the same LUT for all color channels. Do a binary search in the LUT for
2005-03-26 Sven Neumann <sven@gimp.org> * modules/cdisplay_colorblind.c: use the same LUT for all color channels. Do a binary search in the LUT for the backward transformation.
This commit is contained in:

committed by
Sven Neumann

parent
72f7894ad8
commit
1d8471ae9b
@ -1,3 +1,9 @@
|
|||||||
|
2005-03-26 Sven Neumann <sven@gimp.org>
|
||||||
|
|
||||||
|
* modules/cdisplay_colorblind.c: use the same LUT for all color
|
||||||
|
channels. Do a binary search in the LUT for the backward
|
||||||
|
transformation.
|
||||||
|
|
||||||
2005-03-26 Sven Neumann <sven@gimp.org>
|
2005-03-26 Sven Neumann <sven@gimp.org>
|
||||||
|
|
||||||
* modules/cdisplay_colorblind.c: applied a modified version of
|
* modules/cdisplay_colorblind.c: applied a modified version of
|
||||||
|
@ -97,7 +97,7 @@ struct _CdisplayColorblind
|
|||||||
gfloat inflection;
|
gfloat inflection;
|
||||||
|
|
||||||
guint32 cache[2 * COLOR_CACHE_SIZE];
|
guint32 cache[2 * COLOR_CACHE_SIZE];
|
||||||
gfloat gamma_lut[256][3];
|
gfloat gamma_lut[256];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct _CdisplayColorblindClass
|
struct _CdisplayColorblindClass
|
||||||
@ -153,7 +153,7 @@ static void cdisplay_colorblind_set_deficiency (CdisplayColorblind *col
|
|||||||
* indistinguishabled).
|
* indistinguishabled).
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static const gfloat gammaRGB[3] = { 2.1, 2.0, 2.1 };
|
static const gfloat gammaRGB = 2.1;
|
||||||
|
|
||||||
|
|
||||||
/* For most modern Cathode-Ray Tube monitors (CRTs), the following
|
/* For most modern Cathode-Ray Tube monitors (CRTs), the following
|
||||||
@ -300,11 +300,7 @@ cdisplay_colorblind_init (CdisplayColorblind *colorblind)
|
|||||||
gint i;
|
gint i;
|
||||||
|
|
||||||
for (i = 0; i < 256; i++)
|
for (i = 0; i < 256; i++)
|
||||||
{
|
colorblind->gamma_lut[i] = pow (i, 1.0 / gammaRGB);
|
||||||
colorblind->gamma_lut[i][0] = pow (i, 1.0 / gammaRGB[0]);
|
|
||||||
colorblind->gamma_lut[i][1] = pow (i, 1.0 / gammaRGB[1]);
|
|
||||||
colorblind->gamma_lut[i][2] = pow (i, 1.0 / gammaRGB[2]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -346,6 +342,37 @@ cdisplay_colorblind_set_property (GObject *object,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This function performs a binary search in the gamma LUT. It
|
||||||
|
* assumes a monotone gamma function and it simply clips out of gamut
|
||||||
|
* values. It would be better to desaturate instead of clipping.
|
||||||
|
*/
|
||||||
|
static inline guchar
|
||||||
|
lut_lookup (gfloat value,
|
||||||
|
const gfloat *lut)
|
||||||
|
{
|
||||||
|
guchar offset = 128;
|
||||||
|
|
||||||
|
while (TRUE)
|
||||||
|
{
|
||||||
|
if (lut[offset] < value)
|
||||||
|
{
|
||||||
|
if (offset == 255 || lut[offset + 1] >= value)
|
||||||
|
return offset;
|
||||||
|
|
||||||
|
offset++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (offset == 0 || lut[offset - 1] < value)
|
||||||
|
return offset;
|
||||||
|
|
||||||
|
offset--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
cdisplay_colorblind_convert (GimpColorDisplay *display,
|
cdisplay_colorblind_convert (GimpColorDisplay *display,
|
||||||
guchar *buf,
|
guchar *buf,
|
||||||
@ -355,19 +382,22 @@ cdisplay_colorblind_convert (GimpColorDisplay *display,
|
|||||||
gint bpl)
|
gint bpl)
|
||||||
{
|
{
|
||||||
CdisplayColorblind *colorblind = CDISPLAY_COLORBLIND (display);
|
CdisplayColorblind *colorblind = CDISPLAY_COLORBLIND (display);
|
||||||
guchar *b;
|
const gfloat a1 = colorblind->a1;
|
||||||
gfloat a1, b1, c1, a2, b2, c2;
|
const gfloat b1 = colorblind->b1;
|
||||||
|
const gfloat c1 = colorblind->c1;
|
||||||
|
const gfloat a2 = colorblind->a2;
|
||||||
|
const gfloat b2 = colorblind->b2;
|
||||||
|
const gfloat c2 = colorblind->c2;
|
||||||
gfloat tmp;
|
gfloat tmp;
|
||||||
gfloat red, green, blue, redOld, greenOld;
|
gfloat red, green, blue;
|
||||||
|
gfloat redOld, greenOld;
|
||||||
|
guchar *b;
|
||||||
gint x, y;
|
gint x, y;
|
||||||
|
|
||||||
/* Require 3 bytes per pixel (assume RGB) */
|
/* Require 3 bytes per pixel (assume RGB) */
|
||||||
if (bpp != 3)
|
if (bpp != 3)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
a1 = colorblind->a1; b1 = colorblind->b1; c1 = colorblind->c1;
|
|
||||||
a2 = colorblind->a2; b2 = colorblind->b2; c2 = colorblind->c2;
|
|
||||||
|
|
||||||
for (y = 0; y < height; y++, buf += bpl)
|
for (y = 0; y < height; y++, buf += bpl)
|
||||||
for (x = 0, b = buf; x < width; x++, b += bpp)
|
for (x = 0, b = buf; x < width; x++, b += bpp)
|
||||||
{
|
{
|
||||||
@ -390,9 +420,9 @@ cdisplay_colorblind_convert (GimpColorDisplay *display,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Remove gamma to linearize RGB intensities */
|
/* Remove gamma to linearize RGB intensities */
|
||||||
red = colorblind->gamma_lut[b[0]][0];
|
red = colorblind->gamma_lut[b[0]];
|
||||||
green = colorblind->gamma_lut[b[1]][1];
|
green = colorblind->gamma_lut[b[1]];
|
||||||
blue = colorblind->gamma_lut[b[2]][2];
|
blue = colorblind->gamma_lut[b[2]];
|
||||||
|
|
||||||
/* Convert to LMS (dot product with transform matrix) */
|
/* Convert to LMS (dot product with transform matrix) */
|
||||||
redOld = red;
|
redOld = red;
|
||||||
@ -408,7 +438,7 @@ cdisplay_colorblind_convert (GimpColorDisplay *display,
|
|||||||
tmp = blue / red;
|
tmp = blue / red;
|
||||||
/* See which side of the inflection line we fall... */
|
/* See which side of the inflection line we fall... */
|
||||||
if (tmp < colorblind->inflection)
|
if (tmp < colorblind->inflection)
|
||||||
green = -(a1 * red + c1 * blue) / b1;
|
green = -(a1 * red + c1 * blue) / b1;
|
||||||
else
|
else
|
||||||
green = -(a2 * red + c2 * blue) / b2;
|
green = -(a2 * red + c2 * blue) / b2;
|
||||||
break;
|
break;
|
||||||
@ -444,15 +474,9 @@ cdisplay_colorblind_convert (GimpColorDisplay *display,
|
|||||||
blue = redOld * lms2rgb[6] + greenOld * lms2rgb[7] + blue * lms2rgb[8];
|
blue = redOld * lms2rgb[6] + greenOld * lms2rgb[7] + blue * lms2rgb[8];
|
||||||
|
|
||||||
/* Apply gamma to go back to non-linear intensities */
|
/* Apply gamma to go back to non-linear intensities */
|
||||||
red = pow (red, gammaRGB[0]);
|
b[0] = lut_lookup (red, colorblind->gamma_lut);
|
||||||
green = pow (green, gammaRGB[1]);
|
b[1] = lut_lookup (green, colorblind->gamma_lut);
|
||||||
blue = pow (blue, gammaRGB[2]);
|
b[2] = lut_lookup (blue, colorblind->gamma_lut);
|
||||||
|
|
||||||
/* Ensure that we stay within the RGB gamut */
|
|
||||||
/* *** FIXME: it would be better to desaturate than blindly clip. */
|
|
||||||
b[0] = (guchar) CLAMP (red, 0, 255);
|
|
||||||
b[1] = (guchar) CLAMP (green, 0, 255);
|
|
||||||
b[2] = (guchar) CLAMP (blue, 0, 255);
|
|
||||||
|
|
||||||
/* Put the result into our cache */
|
/* Put the result into our cache */
|
||||||
colorblind->cache[2 * index] = pixel;
|
colorblind->cache[2 * index] = pixel;
|
||||||
|
Reference in New Issue
Block a user