[gimp] modules: implement convert_buffer() in the color blind display filter
- From: Michael Natterer <mitch src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gimp] modules: implement convert_buffer() in the color blind display filter
- Date: Sat, 2 Nov 2013 13:44:16 +0000 (UTC)
commit e96b1db02355e5d7d1a400308f63130dda0bac37
Author: Michael Natterer <mitch gimp org>
Date: Sat Nov 2 14:43:47 2013 +0100
modules: implement convert_buffer() in the color blind display filter
modules/display-filter-color-blind.c | 253 ++++++++++++----------------------
1 files changed, 90 insertions(+), 163 deletions(-)
---
diff --git a/modules/display-filter-color-blind.c b/modules/display-filter-color-blind.c
index cbf1ef2..8a2a455 100644
--- a/modules/display-filter-color-blind.c
+++ b/modules/display-filter-color-blind.c
@@ -96,9 +96,6 @@ struct _CdisplayColorblind
gfloat a1, b1, c1;
gfloat a2, b2, c2;
gfloat inflection;
-
- guint32 cache[2 * COLOR_CACHE_SIZE];
- gfloat gamma_lut[256];
};
struct _CdisplayColorblindClass
@@ -125,8 +122,9 @@ static void cdisplay_colorblind_get_property (GObject *o
GValue *value,
GParamSpec *pspec);
-static void cdisplay_colorblind_convert_surface (GimpColorDisplay *display,
- cairo_surface_t *surface);
+static void cdisplay_colorblind_convert_buffer (GimpColorDisplay *display,
+ GeglBuffer *buffer,
+ GeglRectangle *area);
static GtkWidget * cdisplay_colorblind_configure (GimpColorDisplay *display);
static void cdisplay_colorblind_changed (GimpColorDisplay *display);
@@ -259,7 +257,7 @@ cdisplay_colorblind_class_init (CdisplayColorblindClass *klass)
display_class->help_id = "gimp-colordisplay-colorblind";
display_class->stock_id = GIMP_STOCK_DISPLAY_FILTER_COLORBLIND;
- display_class->convert_surface = cdisplay_colorblind_convert_surface;
+ display_class->convert_buffer = cdisplay_colorblind_convert_buffer;
display_class->configure = cdisplay_colorblind_configure;
display_class->changed = cdisplay_colorblind_changed;
}
@@ -272,10 +270,6 @@ cdisplay_colorblind_class_finalize (CdisplayColorblindClass *klass)
static void
cdisplay_colorblind_init (CdisplayColorblind *colorblind)
{
- gint i;
-
- for (i = 0; i < 256; i++)
- colorblind->gamma_lut[i] = pow (i, 1.0 / gammaRGB);
}
static void
@@ -319,159 +313,95 @@ 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)
+static void
+cdisplay_colorblind_convert_buffer (GimpColorDisplay *display,
+ GeglBuffer *buffer,
+ GeglRectangle *area)
{
- guchar offset = 127;
- guchar step = 64;
-
- while (step)
+ CdisplayColorblind *colorblind = CDISPLAY_COLORBLIND (display);
+ GeglBufferIterator *iter;
+ const gfloat a1 = colorblind->a1;
+ 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;
+
+ iter = gegl_buffer_iterator_new (buffer, area, 0,
+ babl_format ("RGBA float") /* linear! */,
+ GEGL_BUFFER_READWRITE, GEGL_ABYSS_NONE);
+
+ while (gegl_buffer_iterator_next (iter))
{
- if (lut[offset] > value)
- {
- offset -= step;
- }
- else
- {
- if (lut[offset + 1] > value)
- return offset;
+ gfloat *data = iter->data[0];
+ gint count = iter->length;
- offset += step;
+ while (count--)
+ {
+ gfloat tmp;
+ gfloat red, green, blue;
+ gfloat redOld, greenOld;
+
+ red = data[0];
+ green = data[1];
+ blue = data[2];
+
+ /* Convert to LMS (dot product with transform matrix) */
+ redOld = red;
+ 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 (colorblind->deficiency)
+ {
+ case COLORBLIND_DEFICIENCY_DEUTERANOPIA:
+ tmp = blue / red;
+ /* See which side of the inflection line we fall... */
+ if (tmp < colorblind->inflection)
+ green = -(a1 * red + c1 * blue) / b1;
+ else
+ green = -(a2 * red + c2 * blue) / b2;
+ break;
+
+ case COLORBLIND_DEFICIENCY_PROTANOPIA:
+ tmp = blue / green;
+ /* See which side of the inflection line we fall... */
+ if (tmp < colorblind->inflection)
+ red = -(b1 * green + c1 * blue) / a1;
+ else
+ red = -(b2 * green + c2 * blue) / a2;
+ break;
+
+ case COLORBLIND_DEFICIENCY_TRITANOPIA:
+ tmp = green / red;
+ /* See which side of the inflection line we fall... */
+ if (tmp < colorblind->inflection)
+ blue = -(a1 * red + b1 * green) / c1;
+ else
+ blue = -(a2 * red + b2 * green) / c2;
+ break;
+
+ 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];
+
+ data[0] = red;
+ data[1] = green;
+ data[2] = blue;
+
+ data += 4;
}
-
- step /= 2;
}
-
- /* the algorithm above can't reach 255 */
- if (offset == 254 && lut[255] < value)
- return 255;
-
- return offset;
-}
-
-static void
-cdisplay_colorblind_convert_surface (GimpColorDisplay *display,
- cairo_surface_t *surface)
-{
- CdisplayColorblind *colorblind = CDISPLAY_COLORBLIND (display);
- gint width = cairo_image_surface_get_width (surface);
- gint height = cairo_image_surface_get_height (surface);
- gint stride = cairo_image_surface_get_stride (surface);
- guchar *buf = cairo_image_surface_get_data (surface);
- cairo_format_t fmt = cairo_image_surface_get_format (surface);
- const gfloat a1 = colorblind->a1;
- 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 red, green, blue;
- gfloat redOld, greenOld;
- guchar r, g, b, a;
- gint x, y, skip;
-
- /* Require ARGB32 pixel format */
- if (fmt != CAIRO_FORMAT_ARGB32)
- return;
-
- skip = stride - 4 * width;
-
- for (y = 0; y < height; y++, buf += skip)
- for (x = 0; x < width; x++, buf += 4)
- {
- guint32 pixel;
- guint index;
-
- /* First check our cache */
- GIMP_CAIRO_ARGB32_GET_PIXEL (buf, r, g, b, a);
- pixel = r << 16 | g << 8 | b;
- index = pixel % COLOR_CACHE_SIZE;
-
- if (colorblind->cache[2 * index] == pixel)
- {
- pixel = colorblind->cache[2 * index + 1];
-
- b = pixel & 0xFF; pixel >>= 8;
- g = pixel & 0xFF; pixel >>= 8;
- r = pixel & 0xFF;
-
- GIMP_CAIRO_ARGB32_SET_PIXEL (buf, r, g, b, a);
-
- continue;
- }
-
- /* Remove gamma to linearize RGB intensities */
- red = colorblind->gamma_lut[r];
- green = colorblind->gamma_lut[g];
- blue = colorblind->gamma_lut[b];
-
- /* Convert to LMS (dot product with transform matrix) */
- redOld = red;
- 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 (colorblind->deficiency)
- {
- case COLORBLIND_DEFICIENCY_DEUTERANOPIA:
- tmp = blue / red;
- /* See which side of the inflection line we fall... */
- if (tmp < colorblind->inflection)
- green = -(a1 * red + c1 * blue) / b1;
- else
- green = -(a2 * red + c2 * blue) / b2;
- break;
-
- case COLORBLIND_DEFICIENCY_PROTANOPIA:
- tmp = blue / green;
- /* See which side of the inflection line we fall... */
- if (tmp < colorblind->inflection)
- red = -(b1 * green + c1 * blue) / a1;
- else
- red = -(b2 * green + c2 * blue) / a2;
- break;
-
- case COLORBLIND_DEFICIENCY_TRITANOPIA:
- tmp = green / red;
- /* See which side of the inflection line we fall... */
- if (tmp < colorblind->inflection)
- blue = -(a1 * red + b1 * green) / c1;
- else
- blue = -(a2 * red + b2 * green) / c2;
- break;
-
- 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 */
- r = lut_lookup (red, colorblind->gamma_lut);
- g = lut_lookup (green, colorblind->gamma_lut);
- b = lut_lookup (blue, colorblind->gamma_lut);
- GIMP_CAIRO_ARGB32_SET_PIXEL (buf, r, g, b, a);
-
- /* Put the result into our cache */
- colorblind->cache[2 * index] = pixel;
- colorblind->cache[2 * index + 1] = r << 16 | g << 8 | b;
- }
}
static GtkWidget *
@@ -488,8 +418,8 @@ cdisplay_colorblind_configure (GimpColorDisplay *display)
gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
gtk_widget_show (label);
- combo =
- gimp_prop_enum_combo_box_new (G_OBJECT (colorblind), "deficiency", 0, 0);
+ combo = gimp_prop_enum_combo_box_new (G_OBJECT (colorblind),
+ "deficiency", 0, 0);
gtk_box_pack_start (GTK_BOX (hbox), combo, TRUE, TRUE, 0);
gtk_widget_show (combo);
@@ -566,9 +496,6 @@ cdisplay_colorblind_changed (GimpColorDisplay *display)
colorblind->inflection = (anchor_e[1] / anchor_e[0]);
break;
}
-
- /* Invalidate the cache */
- memset (colorblind->cache, 0, sizeof (colorblind->cache));
}
static void
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]