From 7507488243b356826a9cc0a3676a77dd8f699bcb Mon Sep 17 00:00:00 2001 From: Manish Singh Date: Sat, 28 Aug 1999 01:17:11 +0000 Subject: [PATCH] more work on the gamma correction stuff -Yosh --- ChangeLog | 4 + app/display/gimpdisplayshell-filter.c | 233 +++++++++++++++++++++++--- app/gdisplay_color.c | 233 +++++++++++++++++++++++--- 3 files changed, 432 insertions(+), 38 deletions(-) diff --git a/ChangeLog b/ChangeLog index 1499499e3f..e9af91e144 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +Fri Aug 27 18:15:33 PDT 1999 Manish Singh + + * app/gdisplay_color.c: more work on the gamma correction stuff + 1999-08-28 Tor Lillqvist * app/gimpbrushpipe.c: Implement the selection of brush based on diff --git a/app/display/gimpdisplayshell-filter.c b/app/display/gimpdisplayshell-filter.c index d4fa5ce614..8e7589b156 100644 --- a/app/display/gimpdisplayshell-filter.c +++ b/app/display/gimpdisplayshell-filter.c @@ -18,6 +18,9 @@ #include "gdisplay_color.h" #include "gimpimageP.h" +#include "libgimp/parasite.h" +#include "libgimp/gimpintl.h" +#include typedef struct _ColorDisplayInfo ColorDisplayInfo; @@ -29,6 +32,54 @@ struct _ColorDisplayInfo { static GHashTable *color_display_table = NULL; +typedef struct _GammaContext GammaContext; + +struct _GammaContext +{ + double gamma; + guchar *lookup; + + GtkWidget *shell; + GtkWidget *spinner; +}; + +static gpointer gamma_new (int type); +static void gamma_create_lookup_table (GammaContext *context); +static void gamma_destroy (gpointer cd_ID); +static void gamma_convert (gpointer cd_ID, + guchar *buf, + int width, + int height, + int bpp); +static void gamma_load (gpointer cd_ID, + Parasite *state); +static Parasite * gamma_save (gpointer cd_ID); +static void gamma_configure_ok_callback (GtkWidget *widget, + gpointer data); +static void gamma_configure_cancel_callback (GtkWidget *widget, + gpointer data); +static gint gamma_configure_delete_callback (GtkWidget *widget, + GdkEvent *event, + gpointer data); +static void gamma_configure (gpointer cd_ID); + +void +gdisplay_color_init (void) +{ + GimpColorDisplayMethods methods = { + NULL, + gamma_new, + gamma_convert, + gamma_destroy, + NULL, + gamma_load, + gamma_save, + gamma_configure + }; + + gimp_color_display_register ("Gamma", &methods); +} + gboolean gimp_color_display_register (const char *name, GimpColorDisplayMethods *methods) @@ -122,16 +173,10 @@ gdisplay_color_detach (GDisplay *gdisp) } } -typedef struct _GammaContext GammaContext; +/* The Gamma Color Display */ -struct _GammaContext -{ - double gamma; - guchar *lookup; -}; - -static -gpointer gamma_new (int type) +static gpointer +gamma_new (int type) { int i; GammaContext *context = NULL; @@ -139,6 +184,8 @@ gpointer gamma_new (int type) context = g_new (GammaContext, 1); context->gamma = 1.0; context->lookup = g_new (guchar, 256); + context->shell = NULL; + context->spinner = NULL; for (i = 0; i < 256; i++) context->lookup[i] = i; @@ -146,21 +193,43 @@ gpointer gamma_new (int type) return context; } -static -void gamma_destroy (gpointer cd_ID) +static void +gamma_create_lookup_table (GammaContext *context) +{ + double one_over_gamma; + double ind; + int i; + + if (context->gamma == 0.0) + context->gamma = 1.0; + + one_over_gamma = 1.0 / context->gamma; + + for (i = 0; i < 256; i++) + { + ind = (double) i / 255.0; + context->lookup[i] = (guchar) (int) (255 * pow (ind, one_over_gamma)); + } +} + +static void +gamma_destroy (gpointer cd_ID) { GammaContext *context = (GammaContext *) cd_ID; + if (context->shell) + gtk_widget_destroy (context->shell); + g_free (context->lookup); g_free (context); } -static -void gamma_convert (gpointer cd_ID, - guchar *buf, - int width, - int height, - int bpp) +static void +gamma_convert (gpointer cd_ID, + guchar *buf, + int width, + int height, + int bpp) { int i; guchar *lookup = ((GammaContext *) cd_ID)->lookup; @@ -169,7 +238,133 @@ void gamma_convert (gpointer cd_ID, *buf++ = lookup[*buf]; } -void -gdisplay_color_init (void) +static void +gamma_load (gpointer cd_ID, + Parasite *state) { + GammaContext *context = (GammaContext *) cd_ID; + +#if G_BYTE_ORDER == G_BIG_ENDIAN + memcpy (&context->gamma, parasite_data (state), sizeof (double)); +#else + guint32 buf[2], *data = parasite_data (state); + + buf[0] = g_ntohl (data[1]); + buf[1] = g_ntohl (data[0]); + + memcpy (&context->gamma, buf, sizeof (double)); +#endif + + gamma_create_lookup_table (context); +} + +static Parasite * +gamma_save (gpointer cd_ID) +{ + GammaContext *context = (GammaContext *) cd_ID; + guint32 buf[2]; + + memcpy (buf, &context->gamma, sizeof (double)); + +#if G_BYTE_ORDER == G_LITTLE_ENDIAN + { + guint32 tmp = g_htonl (buf[0]); + buf[0] = g_htonl (buf[1]); + buf[1] = tmp; + } +#endif + + return parasite_new ("Display/Gamma", PARASITE_PERSISTENT, + sizeof (double), &buf); +} + +static void +gamma_configure_ok_callback (GtkWidget *widget, + gpointer data) +{ + GammaContext *context = (GammaContext *) data; + + context->gamma = gtk_spin_button_get_value_as_float (context->spinner); + gamma_create_lookup_table (context); + + gtk_widget_hide (widget); +} + +static void +gamma_configure_cancel_callback (GtkWidget *widget, + gpointer data) +{ + gtk_widget_hide (widget); +} + +static gint +gamma_configure_delete_callback (GtkWidget *widget, + GdkEvent *event, + gpointer data) +{ + gamma_configure_cancel_callback (widget, data); + return TRUE; +} + +static void +gamma_configure (gpointer cd_ID) +{ + GammaContext *context = (GammaContext *) cd_ID; + GtkWidget *vbox; + GtkWidget *hbox; + GtkWidget *label; + GtkWidget *entry; + GtkWidget *hbbox; + GtkWidget *button; + GtkObject *adjustment; + + if (!context->shell) + { + context->shell = gtk_dialog_new (); + gtk_window_set_wmclass (GTK_WINDOW (context->shell), "gamma", "Gimp"); + gtk_window_set_title (GTK_WINDOW (context->shell), _("Gamma")); + + gtk_signal_connect (GTK_OBJECT (context->shell), "delete_event", + GTK_SIGNAL_FUNC (gamma_configure_delete_callback), + NULL); + + hbox = gtk_hbox_new (TRUE, 2); + gtk_box_pack_start (GTK_BOX (GTK_DIALOG (context->shell)->vbox), + hbox, FALSE, FALSE, 0); + + label = gtk_label_new (_("Gamma:")); + gtk_misc_set_alignment (GTK_MISC (label), 1.0, 0.5); + gtk_box_pack_start (GTK_BOX (hbox), label, TRUE, FALSE, 0); + + adjustment = gtk_adjustment_new (1.0, 0.01, 10.0, 0.01, 0.1, 0.0); + context->spinner = gtk_spin_button_new (GTK_ADJUSTMENT (adjustment), + 0.1, 3); + gtk_widget_set_usize (context->spinner, 100, 0); + gtk_box_pack_start (GTK_BOX (hbox), label, TRUE, FALSE, 0); + + gtk_widget_show_all (hbox); + + hbbox = gtk_hbutton_box_new (); + gtk_button_box_set_spacing (GTK_BUTTON_BOX (hbbox), 4); + gtk_box_pack_end (GTK_BOX (GTK_DIALOG (context->shell)->action_area), + hbbox, FALSE, FALSE, 0); + + button = gtk_button_new_with_label (_("OK")); + GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); + gtk_box_pack_start (GTK_BOX (hbbox), button, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (gamma_configure_ok_callback), + cd_ID); + + button = gtk_button_new_with_label (_("Cancel")); + GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); + gtk_box_pack_start (GTK_BOX (hbbox), button, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (gamma_configure_cancel_callback), + cd_ID); + + gtk_widget_show_all (hbbox); + } + + gtk_widget_show (context->shell); } diff --git a/app/gdisplay_color.c b/app/gdisplay_color.c index d4fa5ce614..8e7589b156 100644 --- a/app/gdisplay_color.c +++ b/app/gdisplay_color.c @@ -18,6 +18,9 @@ #include "gdisplay_color.h" #include "gimpimageP.h" +#include "libgimp/parasite.h" +#include "libgimp/gimpintl.h" +#include typedef struct _ColorDisplayInfo ColorDisplayInfo; @@ -29,6 +32,54 @@ struct _ColorDisplayInfo { static GHashTable *color_display_table = NULL; +typedef struct _GammaContext GammaContext; + +struct _GammaContext +{ + double gamma; + guchar *lookup; + + GtkWidget *shell; + GtkWidget *spinner; +}; + +static gpointer gamma_new (int type); +static void gamma_create_lookup_table (GammaContext *context); +static void gamma_destroy (gpointer cd_ID); +static void gamma_convert (gpointer cd_ID, + guchar *buf, + int width, + int height, + int bpp); +static void gamma_load (gpointer cd_ID, + Parasite *state); +static Parasite * gamma_save (gpointer cd_ID); +static void gamma_configure_ok_callback (GtkWidget *widget, + gpointer data); +static void gamma_configure_cancel_callback (GtkWidget *widget, + gpointer data); +static gint gamma_configure_delete_callback (GtkWidget *widget, + GdkEvent *event, + gpointer data); +static void gamma_configure (gpointer cd_ID); + +void +gdisplay_color_init (void) +{ + GimpColorDisplayMethods methods = { + NULL, + gamma_new, + gamma_convert, + gamma_destroy, + NULL, + gamma_load, + gamma_save, + gamma_configure + }; + + gimp_color_display_register ("Gamma", &methods); +} + gboolean gimp_color_display_register (const char *name, GimpColorDisplayMethods *methods) @@ -122,16 +173,10 @@ gdisplay_color_detach (GDisplay *gdisp) } } -typedef struct _GammaContext GammaContext; +/* The Gamma Color Display */ -struct _GammaContext -{ - double gamma; - guchar *lookup; -}; - -static -gpointer gamma_new (int type) +static gpointer +gamma_new (int type) { int i; GammaContext *context = NULL; @@ -139,6 +184,8 @@ gpointer gamma_new (int type) context = g_new (GammaContext, 1); context->gamma = 1.0; context->lookup = g_new (guchar, 256); + context->shell = NULL; + context->spinner = NULL; for (i = 0; i < 256; i++) context->lookup[i] = i; @@ -146,21 +193,43 @@ gpointer gamma_new (int type) return context; } -static -void gamma_destroy (gpointer cd_ID) +static void +gamma_create_lookup_table (GammaContext *context) +{ + double one_over_gamma; + double ind; + int i; + + if (context->gamma == 0.0) + context->gamma = 1.0; + + one_over_gamma = 1.0 / context->gamma; + + for (i = 0; i < 256; i++) + { + ind = (double) i / 255.0; + context->lookup[i] = (guchar) (int) (255 * pow (ind, one_over_gamma)); + } +} + +static void +gamma_destroy (gpointer cd_ID) { GammaContext *context = (GammaContext *) cd_ID; + if (context->shell) + gtk_widget_destroy (context->shell); + g_free (context->lookup); g_free (context); } -static -void gamma_convert (gpointer cd_ID, - guchar *buf, - int width, - int height, - int bpp) +static void +gamma_convert (gpointer cd_ID, + guchar *buf, + int width, + int height, + int bpp) { int i; guchar *lookup = ((GammaContext *) cd_ID)->lookup; @@ -169,7 +238,133 @@ void gamma_convert (gpointer cd_ID, *buf++ = lookup[*buf]; } -void -gdisplay_color_init (void) +static void +gamma_load (gpointer cd_ID, + Parasite *state) { + GammaContext *context = (GammaContext *) cd_ID; + +#if G_BYTE_ORDER == G_BIG_ENDIAN + memcpy (&context->gamma, parasite_data (state), sizeof (double)); +#else + guint32 buf[2], *data = parasite_data (state); + + buf[0] = g_ntohl (data[1]); + buf[1] = g_ntohl (data[0]); + + memcpy (&context->gamma, buf, sizeof (double)); +#endif + + gamma_create_lookup_table (context); +} + +static Parasite * +gamma_save (gpointer cd_ID) +{ + GammaContext *context = (GammaContext *) cd_ID; + guint32 buf[2]; + + memcpy (buf, &context->gamma, sizeof (double)); + +#if G_BYTE_ORDER == G_LITTLE_ENDIAN + { + guint32 tmp = g_htonl (buf[0]); + buf[0] = g_htonl (buf[1]); + buf[1] = tmp; + } +#endif + + return parasite_new ("Display/Gamma", PARASITE_PERSISTENT, + sizeof (double), &buf); +} + +static void +gamma_configure_ok_callback (GtkWidget *widget, + gpointer data) +{ + GammaContext *context = (GammaContext *) data; + + context->gamma = gtk_spin_button_get_value_as_float (context->spinner); + gamma_create_lookup_table (context); + + gtk_widget_hide (widget); +} + +static void +gamma_configure_cancel_callback (GtkWidget *widget, + gpointer data) +{ + gtk_widget_hide (widget); +} + +static gint +gamma_configure_delete_callback (GtkWidget *widget, + GdkEvent *event, + gpointer data) +{ + gamma_configure_cancel_callback (widget, data); + return TRUE; +} + +static void +gamma_configure (gpointer cd_ID) +{ + GammaContext *context = (GammaContext *) cd_ID; + GtkWidget *vbox; + GtkWidget *hbox; + GtkWidget *label; + GtkWidget *entry; + GtkWidget *hbbox; + GtkWidget *button; + GtkObject *adjustment; + + if (!context->shell) + { + context->shell = gtk_dialog_new (); + gtk_window_set_wmclass (GTK_WINDOW (context->shell), "gamma", "Gimp"); + gtk_window_set_title (GTK_WINDOW (context->shell), _("Gamma")); + + gtk_signal_connect (GTK_OBJECT (context->shell), "delete_event", + GTK_SIGNAL_FUNC (gamma_configure_delete_callback), + NULL); + + hbox = gtk_hbox_new (TRUE, 2); + gtk_box_pack_start (GTK_BOX (GTK_DIALOG (context->shell)->vbox), + hbox, FALSE, FALSE, 0); + + label = gtk_label_new (_("Gamma:")); + gtk_misc_set_alignment (GTK_MISC (label), 1.0, 0.5); + gtk_box_pack_start (GTK_BOX (hbox), label, TRUE, FALSE, 0); + + adjustment = gtk_adjustment_new (1.0, 0.01, 10.0, 0.01, 0.1, 0.0); + context->spinner = gtk_spin_button_new (GTK_ADJUSTMENT (adjustment), + 0.1, 3); + gtk_widget_set_usize (context->spinner, 100, 0); + gtk_box_pack_start (GTK_BOX (hbox), label, TRUE, FALSE, 0); + + gtk_widget_show_all (hbox); + + hbbox = gtk_hbutton_box_new (); + gtk_button_box_set_spacing (GTK_BUTTON_BOX (hbbox), 4); + gtk_box_pack_end (GTK_BOX (GTK_DIALOG (context->shell)->action_area), + hbbox, FALSE, FALSE, 0); + + button = gtk_button_new_with_label (_("OK")); + GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); + gtk_box_pack_start (GTK_BOX (hbbox), button, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (gamma_configure_ok_callback), + cd_ID); + + button = gtk_button_new_with_label (_("Cancel")); + GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); + gtk_box_pack_start (GTK_BOX (hbbox), button, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (gamma_configure_cancel_callback), + cd_ID); + + gtk_widget_show_all (hbbox); + } + + gtk_widget_show (context->shell); }