diff --git a/ChangeLog b/ChangeLog index 40b395fb22..35c72c02fe 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,12 @@ +2002-12-16 Michael Natterer + + * modules/Makefile.am + * modules/cdisplay_colorblind.c: added a display filter which will + simulate the vision of people with color-deficiency to address + bug #101256. Didn't know any scientific name or any correct formula, + so I just added the framework plus the approximation formula from + the bug report. Will need some more work to become usable. + 2002-12-16 Sven Neumann * plug-ins/common/noisify.c (noisify_func): sorry, you can only diff --git a/modules/Makefile.am b/modules/Makefile.am index 6ae9d31589..442b9f2906 100644 --- a/modules/Makefile.am +++ b/modules/Makefile.am @@ -16,9 +16,11 @@ EXTRA_DIST = \ lib_LTLIBRARIES = \ libcolorsel_triangle.la \ + libcolorsel_water.la \ + \ + libcdisplay_colorblind.la \ libcdisplay_gamma.la \ - libcdisplay_highcontrast.la \ - libcolorsel_water.la + libcdisplay_highcontrast.la EXTRA_LTLIBRARIES = @@ -30,6 +32,10 @@ libcolorsel_water_la_SOURCES = colorsel_water.c libcolorsel_water_la_LDFLAGS = -avoid-version -module libcolorsel_water_la_LIBADD = $(GTK_LIBS) +libcdisplay_colorblind_la_SOURCES = cdisplay_colorblind.c +libcdisplay_colorblind_la_LDFLAGS = -avoid-version -module +libcdisplay_colorblind_la_LIBADD = $(GTK_LIBS) + libcdisplay_gamma_la_SOURCES = cdisplay_gamma.c libcdisplay_gamma_la_LDFLAGS = -avoid-version -module libcdisplay_gamma_la_LIBADD = $(GTK_LIBS) diff --git a/modules/cdisplay_colorblind.c b/modules/cdisplay_colorblind.c new file mode 100644 index 0000000000..a4eb7530a2 --- /dev/null +++ b/modules/cdisplay_colorblind.c @@ -0,0 +1,380 @@ +/* The GIMP -- an image manipulation program + * Copyright (C) 1995-1997 Spencer Kimball and Peter Mattis + * + * cdisplay_colorblind.c + * Copyright (C) 2002 Michael Natterer + * + * 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. + */ + +#include "config.h" + +#include +#include + +#include + +#include "libgimpbase/gimpbase.h" +#include "libgimpmodule/gimpmodule.h" +#include "libgimpwidgets/gimpwidgets.h" + +#include "libgimp/libgimp-intl.h" + + +typedef enum +{ + COLORBLIND_DEFICIENCY_FOO, + COLORBLIND_DEFICIENCY_BAR +} ColorblindDeficiency; + + +#define DEFAULT_DEFICIENCY COLORBLIND_DEFICIENCY_FOO + + +#define CDISPLAY_TYPE_COLORBLIND (cdisplay_colorblind_type) +#define CDISPLAY_COLORBLIND(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CDISPLAY_TYPE_COLORBLIND, CdisplayColorblind)) +#define CDISPLAY_COLORBLIND_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CDISPLAY_TYPE_COLORBLIND, CdisplayColorblindClass)) +#define CDISPLAY_IS_COLORBLIND(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CDISPLAY_TYPE_COLORBLIND)) +#define CDISPLAY_IS_COLORBLIND_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CDISPLAY_TYPE_COLORBLIND)) + + +typedef struct _CdisplayColorblind CdisplayColorblind; +typedef struct _CdisplayColorblindClass CdisplayColorblindClass; + +struct _CdisplayColorblind +{ + GimpColorDisplay parent_instance; + + ColorblindDeficiency deficiency; + + GtkWidget *hbox; + GtkWidget *optionmenu; +}; + +struct _CdisplayColorblindClass +{ + GimpColorDisplayClass parent_instance; +}; + + +static GType cdisplay_colorblind_get_type (GTypeModule *module); +static void cdisplay_colorblind_class_init (CdisplayColorblindClass *klass); +static void cdisplay_colorblind_init (CdisplayColorblind *colorblind); + +static void cdisplay_colorblind_finalize (GObject *object); + +static GimpColorDisplay * cdisplay_colorblind_clone (GimpColorDisplay *display); +static void cdisplay_colorblind_convert (GimpColorDisplay *display, + guchar *buf, + gint w, + gint h, + gint bpp, + gint bpl); +static void cdisplay_colorblind_load_state (GimpColorDisplay *display, + GimpParasite *state); +static GimpParasite * cdisplay_colorblind_save_state (GimpColorDisplay *display); +static GtkWidget * cdisplay_colorblind_configure (GimpColorDisplay *display); +static void cdisplay_colorblind_configure_reset (GimpColorDisplay *display); + +static void colorblind_deficiency_callback (GtkWidget *widget, + CdisplayColorblind *colorblind); + + +static const GimpModuleInfo cdisplay_colorblind_info = +{ + N_("Colorblind display filter"), + "Michael Natterer ", + "v0.1", + "(c) 2001, released under the GPL", + "December 16, 2002" +}; + +static GType cdisplay_colorblind_type = 0; +static GimpColorDisplayClass *parent_class = NULL; + + +G_MODULE_EXPORT const GimpModuleInfo * +gimp_module_query (GTypeModule *module) +{ + return &cdisplay_colorblind_info; +} + +G_MODULE_EXPORT gboolean +gimp_module_register (GTypeModule *module) +{ + cdisplay_colorblind_get_type (module); + + return TRUE; +} + +static GType +cdisplay_colorblind_get_type (GTypeModule *module) +{ + if (! cdisplay_colorblind_type) + { + static const GTypeInfo select_info = + { + sizeof (CdisplayColorblindClass), + (GBaseInitFunc) NULL, + (GBaseFinalizeFunc) NULL, + (GClassInitFunc) cdisplay_colorblind_class_init, + NULL, /* class_finalize */ + NULL, /* class_data */ + sizeof (CdisplayColorblind), + 0, /* n_preallocs */ + (GInstanceInitFunc) cdisplay_colorblind_init, + }; + + cdisplay_colorblind_type = + g_type_module_register_type (module, + GIMP_TYPE_COLOR_DISPLAY, + "CdisplayColorblind", + &select_info, 0); + } + + return cdisplay_colorblind_type; +} + +static void +cdisplay_colorblind_class_init (CdisplayColorblindClass *klass) +{ + GObjectClass *object_class; + GimpColorDisplayClass *display_class; + + object_class = G_OBJECT_CLASS (klass); + display_class = GIMP_COLOR_DISPLAY_CLASS (klass); + + parent_class = g_type_class_peek_parent (klass); + + object_class->finalize = cdisplay_colorblind_finalize; + + display_class->name = _("Colorblind"); + display_class->help_page = "modules/colorblind.html"; + display_class->clone = cdisplay_colorblind_clone; + display_class->convert = cdisplay_colorblind_convert; + display_class->load_state = cdisplay_colorblind_load_state; + display_class->save_state = cdisplay_colorblind_save_state; + display_class->configure = cdisplay_colorblind_configure; + display_class->configure_reset = cdisplay_colorblind_configure_reset; +} + +static void +cdisplay_colorblind_init (CdisplayColorblind *colorblind) +{ + colorblind->deficiency = DEFAULT_DEFICIENCY; +} + +static void +cdisplay_colorblind_finalize (GObject *object) +{ + CdisplayColorblind *colorblind; + + colorblind = CDISPLAY_COLORBLIND (object); + + if (colorblind->hbox) + gtk_widget_destroy (colorblind->hbox); + + G_OBJECT_CLASS (parent_class)->finalize (object); +} + + +static GimpColorDisplay * +cdisplay_colorblind_clone (GimpColorDisplay *display) +{ + CdisplayColorblind *colorblind; + CdisplayColorblind *copy; + + colorblind = CDISPLAY_COLORBLIND (display); + + copy = CDISPLAY_COLORBLIND (gimp_color_display_new (G_TYPE_FROM_INSTANCE (colorblind))); + + copy->deficiency = colorblind->deficiency; + + return GIMP_COLOR_DISPLAY (copy); +} + +static void +cdisplay_colorblind_convert (GimpColorDisplay *display, + guchar *buf, + gint width, + gint height, + gint bpp, + gint bpl) +{ + CdisplayColorblind *colorblind; + gint i, j; + guchar *b; + guchar red, green, blue; + + colorblind = CDISPLAY_COLORBLIND (display); + + if (bpp != 3) + return; + + j = height; + + while (j--) + { + i = width; + b = buf; + + switch (colorblind->deficiency) + { + case COLORBLIND_DEFICIENCY_FOO: + while (i--) + { + red = b[0] >> 1; + green = b[1] >> 1; + + b[0] = red + green; + b[1] = red + green; + /* b[2] = b[2]; */ + + b += bpp; + } + break; + + case COLORBLIND_DEFICIENCY_BAR: + while (i--) + { + red = b[0]; + green = b[1]; + blue = b[2]; + + b[0] = green; + b[1] = blue; + b[2] = red; + + b += bpp; + } + break; + + default: + break; + } + + buf += bpl; + } +} + +static void +cdisplay_colorblind_load_state (GimpColorDisplay *display, + GimpParasite *state) +{ + CdisplayColorblind *colorblind; + gchar *str; + + colorblind = CDISPLAY_COLORBLIND (display); + + str = gimp_parasite_data (state); + + if (str[gimp_parasite_data_size (state) - 1] == '\0') + { + gint deficiency; + + if (sscanf (str, "%d", &deficiency) == 1) + { + if (deficiency >= COLORBLIND_DEFICIENCY_FOO && + deficiency <= COLORBLIND_DEFICIENCY_BAR) + { + colorblind->deficiency = deficiency; + + gimp_color_display_changed (GIMP_COLOR_DISPLAY (colorblind)); + } + } + } +} + +static GimpParasite * +cdisplay_colorblind_save_state (GimpColorDisplay *display) +{ + CdisplayColorblind *colorblind; + gchar buf[32]; + + colorblind = CDISPLAY_COLORBLIND (display); + + g_snprintf (buf, sizeof (buf), "%d", colorblind->deficiency); + + return gimp_parasite_new ("Display/Colorblind", GIMP_PARASITE_PERSISTENT, + strlen (buf) + 1, buf); +} + +static GtkWidget * +cdisplay_colorblind_configure (GimpColorDisplay *display) +{ + CdisplayColorblind *colorblind; + GtkWidget *label; + + colorblind = CDISPLAY_COLORBLIND (display); + + if (colorblind->hbox) + gtk_widget_destroy (colorblind->hbox); + + colorblind->hbox = gtk_hbox_new (FALSE, 2); + g_object_add_weak_pointer (G_OBJECT (colorblind->hbox), + (gpointer) &colorblind->hbox); + + label = gtk_label_new ( _("Color Deficiency Type:")); + gtk_box_pack_start (GTK_BOX (colorblind->hbox), label, FALSE, FALSE, 0); + gtk_widget_show (label); + + colorblind->optionmenu = + gimp_option_menu_new2 (FALSE, + G_CALLBACK (colorblind_deficiency_callback), + colorblind, + GINT_TO_POINTER (colorblind->deficiency), + + "FIXME: formula from bug #101256", + GINT_TO_POINTER (COLORBLIND_DEFICIENCY_FOO), + NULL, + + "FIXME: random test formula", + GINT_TO_POINTER (COLORBLIND_DEFICIENCY_BAR), + NULL, + + NULL); + + gtk_box_pack_start (GTK_BOX (colorblind->hbox), colorblind->optionmenu, + FALSE, FALSE, 0); + gtk_widget_show (colorblind->optionmenu); + + return colorblind->hbox; +} + +static void +cdisplay_colorblind_configure_reset (GimpColorDisplay *display) +{ + CdisplayColorblind *colorblind; + + colorblind = CDISPLAY_COLORBLIND (display); + + if (colorblind->optionmenu) + { + gimp_option_menu_set_history (GTK_OPTION_MENU (colorblind->optionmenu), + GINT_TO_POINTER (DEFAULT_DEFICIENCY)); + colorblind->deficiency = DEFAULT_DEFICIENCY; + + gimp_color_display_changed (GIMP_COLOR_DISPLAY (colorblind)); + } +} + +static void +colorblind_deficiency_callback (GtkWidget *widget, + CdisplayColorblind *colorblind) +{ + gimp_menu_item_update (widget, &colorblind->deficiency); + + gimp_color_display_changed (GIMP_COLOR_DISPLAY (colorblind)); +}