diff --git a/ChangeLog b/ChangeLog index 61c4c01673..d62abad7be 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,14 @@ +2008-01-18 Michael Natterer + + * app/gegl/gimplevelsconfig.[ch]: ported the stretch and pick + functions from base/levels.c. + + * app/tools/gimplevelstool.[ch]: use them instead of the old + stuff. Also switch to GimpLevelsConfig as primary storage for all + settings and fill the old Levels struct only when needed in map(). + Remove all hackish fiddling with levels_tool->channel because it + is now always what is set in the menu. + 2008-01-18 Michael Natterer * app/gegl/gimpoperationtilesink.c (class_init) diff --git a/app/gegl/gimplevelsconfig.c b/app/gegl/gimplevelsconfig.c index 7074604123..eedbda8be3 100644 --- a/app/gegl/gimplevelsconfig.c +++ b/app/gegl/gimplevelsconfig.c @@ -28,6 +28,8 @@ #include "gegl-types.h" +#include "base/gimphistogram.h" + #include "gimplevelsconfig.h" @@ -206,31 +208,204 @@ gimp_levels_config_set_property (GObject *object, /* public functions */ void -gimp_levels_config_reset (GimpLevelsConfig *self) +gimp_levels_config_reset (GimpLevelsConfig *config) { GimpHistogramChannel channel; - g_return_if_fail (GIMP_IS_LEVELS_CONFIG (self)); + g_return_if_fail (GIMP_IS_LEVELS_CONFIG (config)); - self->channel = GIMP_HISTOGRAM_VALUE; + config->channel = GIMP_HISTOGRAM_VALUE; for (channel = GIMP_HISTOGRAM_VALUE; channel <= GIMP_HISTOGRAM_ALPHA; channel++) { - gimp_levels_config_reset_channel (self, channel); + gimp_levels_config_reset_channel (config, channel); } } void -gimp_levels_config_reset_channel (GimpLevelsConfig *self, +gimp_levels_config_reset_channel (GimpLevelsConfig *config, GimpHistogramChannel channel) { - g_return_if_fail (GIMP_IS_LEVELS_CONFIG (self)); + g_return_if_fail (GIMP_IS_LEVELS_CONFIG (config)); - self->gamma[channel] = 1.0; - self->low_input[channel] = 0.0; - self->high_input[channel] = 1.0; - self->low_output[channel] = 0.0; - self->high_output[channel] = 1.0; + config->gamma[channel] = 1.0; + config->low_input[channel] = 0.0; + config->high_input[channel] = 1.0; + config->low_output[channel] = 0.0; + config->high_output[channel] = 1.0; +} + +void +gimp_levels_config_stretch (GimpLevelsConfig *config, + GimpHistogram *histogram, + gboolean is_color) +{ + g_return_if_fail (GIMP_IS_LEVELS_CONFIG (config)); + g_return_if_fail (histogram != NULL); + + if (is_color) + { + GimpHistogramChannel channel; + + /* Set the overall value to defaults */ + gimp_levels_config_reset_channel (config, GIMP_HISTOGRAM_VALUE); + + for (channel = GIMP_HISTOGRAM_RED; + channel <= GIMP_HISTOGRAM_BLUE; + channel++) + gimp_levels_config_stretch_channel (config, histogram, channel); + } + else + { + gimp_levels_config_stretch_channel (config, histogram, + GIMP_HISTOGRAM_VALUE); + } +} + +void +gimp_levels_config_stretch_channel (GimpLevelsConfig *config, + GimpHistogram *histogram, + GimpHistogramChannel channel) +{ + gdouble count; + gint i; + + g_return_if_fail (GIMP_IS_LEVELS_CONFIG (config)); + g_return_if_fail (histogram != NULL); + + config->gamma[channel] = 1.0; + config->low_output[channel] = 0.0; + config->high_output[channel] = 1.0; + + count = gimp_histogram_get_count (histogram, channel, 0, 255); + + if (count == 0.0) + { + config->low_input[channel] = 0.0; + config->high_input[channel] = 0.0; + } + else + { + gdouble new_count; + gdouble percentage; + gdouble next_percentage; + + /* Set the low input */ + new_count = 0.0; + + for (i = 0; i < 255; i++) + { + new_count += gimp_histogram_get_value (histogram, channel, i); + percentage = new_count / count; + next_percentage = (new_count + + gimp_histogram_get_value (histogram, + channel, + i + 1)) / count; + + if (fabs (percentage - 0.006) < fabs (next_percentage - 0.006)) + { + config->low_input[channel] = (gdouble) (i + 1) / 255.0; + break; + } + } + + /* Set the high input */ + new_count = 0.0; + + for (i = 255; i > 0; i--) + { + new_count += gimp_histogram_get_value (histogram, channel, i); + percentage = new_count / count; + next_percentage = (new_count + + gimp_histogram_get_value (histogram, + channel, + i - 1)) / count; + + if (fabs (percentage - 0.006) < fabs (next_percentage - 0.006)) + { + config->high_input[channel] = (gdouble) (i - 1) / 255.0; + break; + } + } + } +} + +static gdouble +gimp_levels_config_input_from_color (GimpHistogramChannel channel, + const GimpRGB *color) +{ + switch (channel) + { + case GIMP_HISTOGRAM_VALUE: + return MAX (MAX (color->r, color->g), color->b); + + case GIMP_HISTOGRAM_RED: + return color->r; + + case GIMP_HISTOGRAM_GREEN: + return color->g; + + case GIMP_HISTOGRAM_BLUE: + return color->b; + + case GIMP_HISTOGRAM_ALPHA: + return color->a; + + case GIMP_HISTOGRAM_RGB: + return MIN (MIN (color->r, color->g), color->b); + } + + return 0.0; +} + +void +gimp_levels_config_adjust_by_colors (GimpLevelsConfig *config, + GimpHistogramChannel channel, + const GimpRGB *black, + const GimpRGB *gray, + const GimpRGB *white) +{ + g_return_if_fail (GIMP_IS_LEVELS_CONFIG (config)); + + if (black) + config->low_input[channel] = gimp_levels_config_input_from_color (channel, + black); + + if (white) + config->high_input[channel] = gimp_levels_config_input_from_color (channel, + white); + + if (gray) + { + gdouble input; + gdouble range; + gdouble inten; + gdouble out_light; + gdouble lightness; + + /* Calculate lightness value */ + lightness = GIMP_RGB_LUMINANCE (gray->r, gray->g, gray->b); + + input = gimp_levels_config_input_from_color (channel, gray); + + range = config->high_input[channel] - config->low_input[channel]; + if (range <= 0) + return; + + input -= config->low_input[channel]; + if (input < 0) + return; + + /* Normalize input and lightness */ + inten = input / range; + out_light = lightness/ range; + + if (out_light <= 0) + return; + + /* Map selected color to corresponding lightness */ + config->gamma[channel] = log (inten) / log (out_light); + } } diff --git a/app/gegl/gimplevelsconfig.h b/app/gegl/gimplevelsconfig.h index 012f56cf44..a2ba8be86e 100644 --- a/app/gegl/gimplevelsconfig.h +++ b/app/gegl/gimplevelsconfig.h @@ -54,11 +54,24 @@ struct _GimpLevelsConfigClass }; -GType gimp_levels_config_get_type (void) G_GNUC_CONST; +GType gimp_levels_config_get_type (void) G_GNUC_CONST; + +void gimp_levels_config_reset (GimpLevelsConfig *config); +void gimp_levels_config_reset_channel (GimpLevelsConfig *config, + GimpHistogramChannel channel); + +void gimp_levels_config_stretch (GimpLevelsConfig *config, + GimpHistogram *histogram, + gboolean is_color); +void gimp_levels_config_stretch_channel (GimpLevelsConfig *config, + GimpHistogram *histogram, + GimpHistogramChannel channel); +void gimp_levels_config_adjust_by_colors (GimpLevelsConfig *config, + GimpHistogramChannel channel, + const GimpRGB *black, + const GimpRGB *gray, + const GimpRGB *white); -void gimp_levels_config_reset (GimpLevelsConfig *self); -void gimp_levels_config_reset_channel (GimpLevelsConfig *self, - GimpHistogramChannel channel); #endif /* __GIMP_LEVELS_CONFIG_H__ */ diff --git a/app/tools/gimplevelstool.c b/app/tools/gimplevelstool.c index 6d982c88c1..5f546f6a13 100644 --- a/app/tools/gimplevelstool.c +++ b/app/tools/gimplevelstool.c @@ -38,7 +38,6 @@ #include "base/levels.h" #include "gegl/gimplevelsconfig.h" -#include "gegl/gimpoperationlevels.h" #include "core/gimpdrawable.h" #include "core/gimpdrawable-histogram.h" @@ -238,9 +237,7 @@ gimp_levels_tool_initialize (GimpTool *tool, gimp_levels_config_reset (l_tool->config); - levels_init (l_tool->levels); - - l_tool->channel = GIMP_HISTOGRAM_VALUE; + l_tool->channel = l_tool->config->channel; l_tool->color = gimp_drawable_is_rgb (drawable); l_tool->alpha = gimp_drawable_has_alpha (drawable); @@ -256,10 +253,6 @@ gimp_levels_tool_initialize (GimpTool *tool, gimp_int_combo_box_set_active (GIMP_INT_COMBO_BOX (l_tool->channel_menu), l_tool->channel); - /* FIXME: hack */ - if (! l_tool->color) - l_tool->channel = (l_tool->channel == GIMP_HISTOGRAM_ALPHA) ? 1 : 0; - levels_update_adjustments (l_tool); gimp_drawable_calculate_histogram (drawable, l_tool->hist); @@ -291,39 +284,35 @@ gimp_levels_tool_get_operation (GimpImageMapTool *im_tool) static void gimp_levels_tool_map (GimpImageMapTool *image_map_tool) { - GimpLevelsTool *tool = GIMP_LEVELS_TOOL (image_map_tool); + GimpLevelsTool *tool = GIMP_LEVELS_TOOL (image_map_tool); + GimpLevelsConfig *config = tool->config; + Levels *levels = tool->levels; GimpHistogramChannel channel; for (channel = GIMP_HISTOGRAM_VALUE; channel <= GIMP_HISTOGRAM_ALPHA; channel++) { - /* FIXME: hack */ - if (! tool->color && channel == 1) - g_object_set (tool->config, - "channel", GIMP_HISTOGRAM_ALPHA, - NULL); - else - g_object_set (tool->config, - "channel", channel, - NULL); + levels->gamma[channel] = config->gamma[channel]; + levels->low_input[channel] = config->low_input[channel] * 255.999; + levels->high_input[channel] = config->high_input[channel] * 255.999; + levels->low_output[channel] = config->low_output[channel] * 255.999; + levels->high_output[channel] = config->high_output[channel] * 255.999; + } - g_object_set (tool->config, - "gamma", tool->levels->gamma[channel], - "low-input", tool->levels->low_input[channel] / 255.0, - "high-input", tool->levels->high_input[channel] / 255.0, - "low-output", tool->levels->low_output[channel] / 255.0, - "high-output", tool->levels->high_output[channel] / 255.0, - NULL); - - /* FIXME: hack */ - if (! tool->color && channel == 1) - break; + /* FIXME: hack */ + if (! tool->color) + { + levels->gamma[1] = levels->gamma[GIMP_HISTOGRAM_ALPHA]; + levels->low_input[1] = levels->low_input[GIMP_HISTOGRAM_ALPHA]; + levels->high_input[1] = levels->high_input[GIMP_HISTOGRAM_ALPHA]; + levels->low_output[1] = levels->low_output[GIMP_HISTOGRAM_ALPHA]; + levels->high_output[1] = levels->high_output[GIMP_HISTOGRAM_ALPHA]; } gimp_lut_setup (tool->lut, (GimpLutFunc) levels_lut_func, - tool->levels, + levels, gimp_drawable_bytes (image_map_tool->drawable)); } @@ -727,8 +716,6 @@ gimp_levels_tool_reset (GimpImageMapTool *image_map_tool) GimpLevelsTool *tool = GIMP_LEVELS_TOOL (image_map_tool); gimp_levels_config_reset (tool->config); - - levels_init (tool->levels); levels_update_adjustments (tool); } @@ -778,13 +765,23 @@ gimp_levels_tool_settings_load (GimpImageMapTool *image_map_tool, for (i = 0; i < 5; i++) { - tool->levels->low_input[i] = low_input[i]; - tool->levels->high_input[i] = high_input[i]; - tool->levels->low_output[i] = low_output[i]; - tool->levels->high_output[i] = high_output[i]; - tool->levels->gamma[i] = gamma[i]; + g_object_set (tool->config, + "channel", i, + NULL); + + g_object_set (tool->config, + "low-input", low_input[i] / 255.0, + "high-input", high_input[i] / 255.0, + "low-output", low_output[i] / 255.0, + "high-output", high_output[i] / 255.0, + "gamma", gamma[i], + NULL); } + g_object_set (tool->config, + "channel", tool->channel, + NULL); + levels_update_adjustments (tool); return TRUE; @@ -810,12 +807,12 @@ gimp_levels_tool_settings_save (GimpImageMapTool *image_map_tool, gchar buf[G_ASCII_DTOSTR_BUF_SIZE]; fprintf (file, "%d %d %d %d %s\n", - tool->levels->low_input[i], - tool->levels->high_input[i], - tool->levels->low_output[i], - tool->levels->high_output[i], + (gint) (tool->config->low_input[i] * 255.999), + (gint) (tool->config->high_input[i] * 255.999), + (gint) (tool->config->low_output[i] * 255.999), + (gint) (tool->config->high_output[i] * 255.999), g_ascii_formatd (buf, G_ASCII_DTOSTR_BUF_SIZE, "%f", - tool->levels->gamma[i])); + tool->config->gamma[i])); } return TRUE; @@ -830,11 +827,11 @@ levels_update_adjustments (GimpLevelsTool *tool) tool->gamma_linear->upper = 255; gtk_adjustment_set_value (tool->low_input, - tool->levels->low_input[tool->channel]); + tool->config->low_input[tool->channel] * 255.0); gtk_adjustment_set_value (tool->gamma, - tool->levels->gamma[tool->channel]); + tool->config->gamma[tool->channel]); gtk_adjustment_set_value (tool->high_input, - tool->levels->high_input[tool->channel]); + tool->config->high_input[tool->channel] * 255.0); tool->low_input->upper = tool->high_input->value; tool->high_input->lower = tool->low_input->value; @@ -845,9 +842,9 @@ levels_update_adjustments (GimpLevelsTool *tool) gtk_adjustment_changed (tool->gamma_linear); gtk_adjustment_set_value (tool->low_output, - tool->levels->low_output[tool->channel]); + tool->config->low_output[tool->channel] * 255.0); gtk_adjustment_set_value (tool->high_output, - tool->levels->high_output[tool->channel]); + tool->config->high_output[tool->channel] * 255.0); levels_update_input_bar (tool); } @@ -855,16 +852,10 @@ levels_update_adjustments (GimpLevelsTool *tool) static void levels_update_input_bar (GimpLevelsTool *tool) { - GimpHistogramChannel channel = tool->channel; - - /* FIXME: hack */ - if (! tool->color && channel == 1) - channel = GIMP_HISTOGRAM_ALPHA; - /* Recalculate the transfer arrays */ levels_calculate_transfers (tool->levels); - switch (channel) + switch (tool->channel) { case GIMP_HISTOGRAM_VALUE: case GIMP_HISTOGRAM_ALPHA: @@ -895,15 +886,16 @@ levels_channel_callback (GtkWidget *widget, if (gimp_int_combo_box_get_active (GIMP_INT_COMBO_BOX (widget), &value)) { tool->channel = value; + + g_object_set (tool->config, + "channel", tool->channel, + NULL); + gimp_histogram_view_set_channel (GIMP_HISTOGRAM_VIEW (tool->hist_view), tool->channel); gimp_color_bar_set_channel (GIMP_COLOR_BAR (tool->output_bar), tool->channel); - /* FIXME: hack */ - if (! tool->color) - tool->channel = (tool->channel == GIMP_HISTOGRAM_ALPHA) ? 1 : 0; - levels_update_adjustments (tool); } } @@ -912,15 +904,7 @@ static void levels_channel_reset_callback (GtkWidget *widget, GimpLevelsTool *tool) { - GimpHistogramChannel channel = tool->channel; - - /* FIXME: hack */ - if (! tool->color && channel == 1) - channel = GIMP_HISTOGRAM_ALPHA; - - gimp_levels_config_reset_channel (tool->config, channel); - - levels_channel_reset (tool->levels, tool->channel); + gimp_levels_config_reset_channel (tool->config, tool->channel); levels_update_adjustments (tool); gimp_image_map_tool_preview (GIMP_IMAGE_MAP_TOOL (tool)); @@ -957,7 +941,7 @@ static void levels_stretch_callback (GtkWidget *widget, GimpLevelsTool *tool) { - levels_stretch (tool->levels, tool->hist, tool->color); + gimp_levels_config_stretch (tool->config, tool->hist, tool->color); levels_update_adjustments (tool); gimp_image_map_tool_preview (GIMP_IMAGE_MAP_TOOL (tool)); @@ -970,7 +954,7 @@ levels_linear_gamma_update (GimpLevelsTool *tool) delta = (tool->high_input->value - tool->low_input->value) / 2.0; mid = tool->low_input->value + delta; - tmp = log10 (1.0 / tool->levels->gamma[tool->channel]); + tmp = log10 (1.0 / tool->config->gamma[tool->channel]); value = mid + delta * tmp; gtk_adjustment_set_value (tool->gamma_linear, value); @@ -1008,9 +992,11 @@ levels_low_input_changed (GtkAdjustment *adjustment, gtk_adjustment_changed (tool->high_input); gtk_adjustment_changed (tool->gamma_linear); - if (tool->levels->low_input[tool->channel] != value) + if (tool->config->low_input[tool->channel] != value / 255.0) { - tool->levels->low_input[tool->channel] = value; + g_object_set (tool->config, + "low-input", value / 255.0, + NULL); levels_update_input_bar (tool); gimp_image_map_tool_preview (GIMP_IMAGE_MAP_TOOL (tool)); @@ -1023,9 +1009,11 @@ static void levels_gamma_changed (GtkAdjustment *adjustment, GimpLevelsTool *tool) { - if (tool->levels->gamma[tool->channel] != adjustment->value) + if (tool->config->gamma[tool->channel] != adjustment->value) { - tool->levels->gamma[tool->channel] = adjustment->value; + g_object_set (tool->config, + "gamma", adjustment->value, + NULL); levels_update_input_bar (tool); gimp_image_map_tool_preview (GIMP_IMAGE_MAP_TOOL (tool)); @@ -1045,9 +1033,11 @@ levels_high_input_changed (GtkAdjustment *adjustment, gtk_adjustment_changed (tool->low_input); gtk_adjustment_changed (tool->gamma_linear); - if (tool->levels->high_input[tool->channel] != value) + if (tool->config->high_input[tool->channel] != value / 255.0) { - tool->levels->high_input[tool->channel] = value; + g_object_set (tool->config, + "high-input", value / 255.0, + NULL); levels_update_input_bar (tool); gimp_image_map_tool_preview (GIMP_IMAGE_MAP_TOOL (tool)); @@ -1062,9 +1052,11 @@ levels_low_output_changed (GtkAdjustment *adjustment, { gint value = ROUND (adjustment->value); - if (tool->levels->low_output[tool->channel] != value) + if (tool->config->low_output[tool->channel] != value / 255.0) { - tool->levels->low_output[tool->channel] = value; + g_object_set (tool->config, + "low-output", value / 255.0, + NULL); gimp_image_map_tool_preview (GIMP_IMAGE_MAP_TOOL (tool)); } @@ -1076,9 +1068,11 @@ levels_high_output_changed (GtkAdjustment *adjustment, { gint value = ROUND (adjustment->value); - if (tool->levels->high_output[tool->channel] != value) + if (tool->config->high_output[tool->channel] != value / 255.0) { - tool->levels->high_output[tool->channel] = value; + g_object_set (tool->config, + "high-output", value / 255.0, + NULL); gimp_image_map_tool_preview (GIMP_IMAGE_MAP_TOOL (tool)); } @@ -1110,21 +1104,21 @@ levels_input_picker_toggled (GtkWidget *widget, } static void -levels_input_adjust_by_color (Levels *levels, +levels_input_adjust_by_color (GimpLevelsConfig *config, guint value, GimpHistogramChannel channel, - guchar *color) + const GimpRGB *color) { switch (value & 0xF) { case PICK_LOW_INPUT: - levels_adjust_by_colors (levels, channel, color, NULL, NULL); + gimp_levels_config_adjust_by_colors (config, channel, color, NULL, NULL); break; case PICK_GAMMA: - levels_adjust_by_colors (levels, channel, NULL, color, NULL); + gimp_levels_config_adjust_by_colors (config, channel, NULL, color, NULL); break; case PICK_HIGH_INPUT: - levels_adjust_by_colors (levels, channel, NULL, NULL, color); + gimp_levels_config_adjust_by_colors (config, channel, NULL, NULL, color); break; default: break; @@ -1139,15 +1133,8 @@ gimp_levels_tool_color_picked (GimpColorTool *color_tool, gint color_index) { GimpLevelsTool *tool = GIMP_LEVELS_TOOL (color_tool); - guchar col[5]; guint value; - gimp_rgba_get_uchar (color, - col + RED_PIX, - col + GREEN_PIX, - col + BLUE_PIX, - col + ALPHA_PIX); - value = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (tool->active_picker), "pick-value")); @@ -1159,13 +1146,13 @@ gimp_levels_tool_color_picked (GimpColorTool *color_tool, switch (value & 0xF) { case PICK_LOW_INPUT: - tool->levels->low_input[GIMP_HISTOGRAM_VALUE] = 0; + tool->config->low_input[GIMP_HISTOGRAM_VALUE] = 0.0; break; case PICK_GAMMA: - tool->levels->gamma[GIMP_HISTOGRAM_VALUE] = 1.0; + tool->config->gamma[GIMP_HISTOGRAM_VALUE] = 1.0; break; case PICK_HIGH_INPUT: - tool->levels->high_input[GIMP_HISTOGRAM_VALUE] = 255; + tool->config->high_input[GIMP_HISTOGRAM_VALUE] = 1.0; break; default: break; @@ -1176,14 +1163,14 @@ gimp_levels_tool_color_picked (GimpColorTool *color_tool, channel <= GIMP_HISTOGRAM_BLUE; channel++) { - levels_input_adjust_by_color (tool->levels, - value, channel, col); + levels_input_adjust_by_color (tool->config, + value, channel, color); } } else { - levels_input_adjust_by_color (tool->levels, - value, tool->channel, col); + levels_input_adjust_by_color (tool->config, + value, tool->channel, color); } levels_update_adjustments (tool); diff --git a/app/tools/gimplevelstool.h b/app/tools/gimplevelstool.h index da0cc536ba..fcf0693881 100644 --- a/app/tools/gimplevelstool.h +++ b/app/tools/gimplevelstool.h @@ -38,9 +38,9 @@ struct _GimpLevelsTool { GimpImageMapTool parent_instance; + GimpLevelsConfig *config; GimpLut *lut; Levels *levels; - GimpLevelsConfig *config; /* dialog */ gboolean color;