diff --git a/app/operations/gimpoperationthreshold.c b/app/operations/gimpoperationthreshold.c index 0282af822b..ddcd517fc9 100644 --- a/app/operations/gimpoperationthreshold.c +++ b/app/operations/gimpoperationthreshold.c @@ -24,6 +24,7 @@ #include #include +#include "libgimpcolor/gimpcolor.h" #include "libgimpconfig/gimpconfig.h" #include "operations-types.h" @@ -36,6 +37,7 @@ enum { PROP_0, + PROP_CHANNEL, PROP_LOW, PROP_HIGH }; @@ -82,6 +84,14 @@ gimp_operation_threshold_class_init (GimpOperationThresholdClass *klass) "description", "GIMP Threshold operation", NULL); + GIMP_CONFIG_PROP_ENUM (object_class, PROP_CHANNEL, + "channel", + _("Channel"), + NULL, + GIMP_TYPE_HISTOGRAM_CHANNEL, + GIMP_HISTOGRAM_VALUE, + GIMP_PARAM_STATIC_STRINGS); + GIMP_CONFIG_PROP_DOUBLE (object_class, PROP_LOW, "low", _("Low threshold"), @@ -112,6 +122,10 @@ gimp_operation_threshold_get_property (GObject *object, switch (property_id) { + case PROP_CHANNEL: + g_value_set_enum (value, self->channel); + break; + case PROP_LOW: g_value_set_double (value, self->low); break; @@ -136,6 +150,10 @@ gimp_operation_threshold_set_property (GObject *object, switch (property_id) { + case PROP_CHANNEL: + self->channel = g_value_get_enum (value); + break; + case PROP_LOW: self->low = g_value_get_double (value); break; @@ -164,10 +182,40 @@ gimp_operation_threshold_process (GeglOperation *operation, while (samples--) { - gfloat value; + gfloat value = 0.0; - value = MAX (src[RED], src[GREEN]); - value = MAX (value, src[BLUE]); + switch (threshold->channel) + { + case GIMP_HISTOGRAM_VALUE: + value = MAX (src[RED], src[GREEN]); + value = MAX (value, src[BLUE]); + break; + + case GIMP_HISTOGRAM_RED: + value = src[RED]; + break; + + case GIMP_HISTOGRAM_GREEN: + value = src[GREEN]; + break; + + case GIMP_HISTOGRAM_BLUE: + value = src[BLUE]; + break; + + case GIMP_HISTOGRAM_ALPHA: + value = src[ALPHA]; + break; + + case GIMP_HISTOGRAM_RGB: + value = MIN (src[RED], src[GREEN]); + value = MIN (value, src[BLUE]); + break; + + case GIMP_HISTOGRAM_LUMINANCE: + value = GIMP_RGB_LUMINANCE (src[RED], src[GREEN], src[BLUE]); + break; + } value = (value >= threshold->low && value <= threshold->high) ? 1.0 : 0.0; diff --git a/app/operations/gimpoperationthreshold.h b/app/operations/gimpoperationthreshold.h index d4f82ee4e5..30bc165d5e 100644 --- a/app/operations/gimpoperationthreshold.h +++ b/app/operations/gimpoperationthreshold.h @@ -40,6 +40,7 @@ struct _GimpOperationThreshold { GimpOperationPointFilter parent_instance; + GimpHistogramChannel channel; gdouble low; gdouble high; }; diff --git a/app/pdb/drawable-color-cmds.c b/app/pdb/drawable-color-cmds.c index b73ee24398..d0011d7593 100644 --- a/app/pdb/drawable-color-cmds.c +++ b/app/pdb/drawable-color-cmds.c @@ -679,12 +679,14 @@ drawable_threshold_invoker (GimpProcedure *procedure, { gboolean success = TRUE; GimpDrawable *drawable; + gint32 channel; gdouble low_threshold; gdouble high_threshold; drawable = gimp_value_get_drawable (gimp_value_array_index (args, 0), gimp); - low_threshold = g_value_get_double (gimp_value_array_index (args, 1)); - high_threshold = g_value_get_double (gimp_value_array_index (args, 2)); + channel = g_value_get_enum (gimp_value_array_index (args, 1)); + low_threshold = g_value_get_double (gimp_value_array_index (args, 2)); + high_threshold = g_value_get_double (gimp_value_array_index (args, 3)); if (success) { @@ -695,6 +697,7 @@ drawable_threshold_invoker (GimpProcedure *procedure, GeglNode *node = gegl_node_new_child (NULL, "operation", "gimp:threshold", + "channel", channel, "low", low_threshold, "high", high_threshold, NULL); @@ -1264,7 +1267,7 @@ register_drawable_color_procs (GimpPDB *pdb) gimp_procedure_set_static_strings (procedure, "gimp-drawable-threshold", "Threshold the specified drawable.", - "This procedures generates a threshold map of the specified drawable. All pixels between the values of 'low_threshold' and 'high_threshold' are replaced with white, and all other pixels with black.", + "This procedures generates a threshold map of the specified drawable. All pixels between the values of 'low_threshold' and 'high_threshold', on the scale of 'channel' are replaced with white, and all other pixels with black.", "Spencer Kimball & Peter Mattis", "Spencer Kimball & Peter Mattis", "1997", @@ -1275,6 +1278,13 @@ register_drawable_color_procs (GimpPDB *pdb) "The drawable", pdb->gimp, FALSE, GIMP_PARAM_READWRITE)); + gimp_procedure_add_argument (procedure, + g_param_spec_enum ("channel", + "channel", + "The channel to base the threshold on", + GIMP_TYPE_HISTOGRAM_CHANNEL, + GIMP_HISTOGRAM_VALUE, + GIMP_PARAM_READWRITE)); gimp_procedure_add_argument (procedure, g_param_spec_double ("low-threshold", "low threshold", diff --git a/app/tools/gimpthresholdtool.c b/app/tools/gimpthresholdtool.c index 10429e4b36..da85ecea41 100644 --- a/app/tools/gimpthresholdtool.c +++ b/app/tools/gimpthresholdtool.c @@ -64,6 +64,9 @@ static void gimp_threshold_tool_config_notify (GObject *object GParamSpec *pspec, GimpThresholdTool *t_tool); +static gboolean gimp_threshold_tool_channel_sensitive + (gint value, + gpointer data); static void gimp_threshold_tool_histogram_range (GimpHistogramView *view, gint start, gint end, @@ -159,6 +162,10 @@ gimp_threshold_tool_initialize (GimpTool *tool, return FALSE; } + gimp_int_combo_box_set_sensitivity (GIMP_INT_COMBO_BOX (t_tool->channel_menu), + gimp_threshold_tool_channel_sensitive, + drawable, NULL); + gimp_drawable_calculate_histogram (drawable, t_tool->histogram); gimp_histogram_view_set_histogram (t_tool->histogram_box->view, t_tool->histogram); @@ -187,42 +194,72 @@ gimp_threshold_tool_get_operation (GimpFilterTool *filter_tool, static void gimp_threshold_tool_dialog (GimpFilterTool *filter_tool) { - GimpThresholdTool *t_tool = GIMP_THRESHOLD_TOOL (filter_tool); - GimpToolOptions *tool_options = GIMP_TOOL_GET_OPTIONS (filter_tool); - GtkWidget *main_vbox; - GtkWidget *hbox; - GtkWidget *menu; - GtkWidget *box; - GtkWidget *button; - gdouble low; - gdouble high; - gint n_bins; + GimpThresholdTool *t_tool = GIMP_THRESHOLD_TOOL (filter_tool); + GimpToolOptions *tool_options = GIMP_TOOL_GET_OPTIONS (filter_tool); + GtkWidget *main_vbox; + GtkWidget *main_frame; + GtkWidget *frame_vbox; + GtkWidget *hbox; + GtkWidget *label; + GtkWidget *hbox2; + GtkWidget *box; + GtkWidget *button; + GimpHistogramChannel channel; + gdouble low; + gdouble high; + gint n_bins; main_vbox = gimp_filter_tool_dialog_get_vbox (filter_tool); + main_frame = gimp_frame_new (NULL); + gtk_box_pack_start (GTK_BOX (main_vbox), main_frame, TRUE, TRUE, 0); + gtk_widget_show (main_frame); + hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6); - gtk_box_pack_start (GTK_BOX (main_vbox), hbox, FALSE, FALSE, 0); + gtk_frame_set_label_widget (GTK_FRAME (main_frame), hbox); gtk_widget_show (hbox); - menu = gimp_prop_enum_icon_box_new (G_OBJECT (tool_options), - "histogram-scale", "gimp-histogram", - 0, 0); - gtk_box_pack_end (GTK_BOX (hbox), menu, FALSE, FALSE, 0); - gtk_widget_show (menu); + label = gtk_label_new_with_mnemonic (_("Cha_nnel:")); + gimp_label_set_attributes (GTK_LABEL (label), + PANGO_ATTR_WEIGHT, PANGO_WEIGHT_BOLD, + -1); + gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0); + gtk_widget_show (label); + + t_tool->channel_menu = gimp_prop_enum_combo_box_new (filter_tool->config, + "channel", -1, -1); + gimp_enum_combo_box_set_icon_prefix (GIMP_ENUM_COMBO_BOX (t_tool->channel_menu), + "gimp-channel"); + gtk_box_pack_start (GTK_BOX (hbox), t_tool->channel_menu, FALSE, FALSE, 0); + gtk_widget_show (t_tool->channel_menu); + + gtk_label_set_mnemonic_widget (GTK_LABEL (label), t_tool->channel_menu); + + hbox2 = gimp_prop_enum_icon_box_new (G_OBJECT (tool_options), + "histogram-scale", "gimp-histogram", + 0, 0); + gtk_box_pack_end (GTK_BOX (hbox), hbox2, FALSE, FALSE, 0); + gtk_widget_show (hbox2); + + frame_vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 4); + gtk_container_add (GTK_CONTAINER (main_frame), frame_vbox); + gtk_widget_show (frame_vbox); box = gimp_histogram_box_new (); - gtk_box_pack_start (GTK_BOX (main_vbox), box, TRUE, TRUE, 0); + gtk_box_pack_start (GTK_BOX (frame_vbox), box, TRUE, TRUE, 0); gtk_widget_show (box); t_tool->histogram_box = GIMP_HISTOGRAM_BOX (box); g_object_get (filter_tool->config, - "low", &low, - "high", &high, + "channel", &channel, + "low", &low, + "high", &high, NULL); n_bins = gimp_histogram_n_bins (t_tool->histogram); + gimp_histogram_view_set_channel (t_tool->histogram_box->view, channel); gimp_histogram_view_set_range (t_tool->histogram_box->view, low * (n_bins - 0.0001), high * (n_bins - 0.0001)); @@ -237,7 +274,7 @@ gimp_threshold_tool_dialog (GimpFilterTool *filter_tool) G_BINDING_BIDIRECTIONAL); hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6); - gtk_box_pack_start (GTK_BOX (main_vbox), hbox, FALSE, FALSE, 0); + gtk_box_pack_start (GTK_BOX (frame_vbox), hbox, FALSE, FALSE, 0); gtk_widget_show (hbox); button = gtk_button_new_with_mnemonic (_("_Auto")); @@ -256,23 +293,68 @@ gimp_threshold_tool_config_notify (GObject *object, GParamSpec *pspec, GimpThresholdTool *t_tool) { - gdouble low; - gdouble high; - gint n_bins; - if (! t_tool->histogram_box) return; - g_object_get (object, - "low", &low, - "high", &high, - NULL); + if (! strcmp (pspec->name, "channel")) + { + GimpHistogramChannel channel; - n_bins = gimp_histogram_n_bins (t_tool->histogram); + g_object_get (object, + "channel", &channel, + NULL); - gimp_histogram_view_set_range (t_tool->histogram_box->view, - low * (n_bins - 0.0001), - high * (n_bins - 0.0001)); + gimp_histogram_view_set_channel (t_tool->histogram_box->view, + channel); + } + else if (! strcmp (pspec->name, "low") || + ! strcmp (pspec->name, "high")) + { + gdouble low; + gdouble high; + gint n_bins; + + g_object_get (object, + "low", &low, + "high", &high, + NULL); + + n_bins = gimp_histogram_n_bins (t_tool->histogram); + + gimp_histogram_view_set_range (t_tool->histogram_box->view, + low * (n_bins - 0.0001), + high * (n_bins - 0.0001)); + } +} + +static gboolean +gimp_threshold_tool_channel_sensitive (gint value, + gpointer data) +{ + GimpDrawable *drawable = GIMP_DRAWABLE (data); + GimpHistogramChannel channel = value; + + switch (channel) + { + case GIMP_HISTOGRAM_VALUE: + return TRUE; + + case GIMP_HISTOGRAM_RED: + case GIMP_HISTOGRAM_GREEN: + case GIMP_HISTOGRAM_BLUE: + return gimp_drawable_is_rgb (drawable); + + case GIMP_HISTOGRAM_ALPHA: + return gimp_drawable_has_alpha (drawable); + + case GIMP_HISTOGRAM_RGB: + return gimp_drawable_is_rgb (drawable); + + case GIMP_HISTOGRAM_LUMINANCE: + return gimp_drawable_is_rgb (drawable); + } + + return FALSE; } static void @@ -307,14 +389,18 @@ static void gimp_threshold_tool_auto_clicked (GtkWidget *button, GimpThresholdTool *t_tool) { - GimpDrawable *drawable = GIMP_FILTER_TOOL (t_tool)->drawable; - gint n_bins = gimp_histogram_n_bins (t_tool->histogram); - gdouble low; + GimpHistogramChannel channel; + gint n_bins; + gdouble low; + + g_object_get (GIMP_FILTER_TOOL (t_tool)->config, + "channel", &channel, + NULL); + + n_bins = gimp_histogram_n_bins (t_tool->histogram); low = gimp_histogram_get_threshold (t_tool->histogram, - gimp_drawable_is_rgb (drawable) ? - GIMP_HISTOGRAM_RGB : - GIMP_HISTOGRAM_VALUE, + channel, 0, n_bins - 1); gimp_histogram_view_set_range (t_tool->histogram_box->view, diff --git a/app/tools/gimpthresholdtool.h b/app/tools/gimpthresholdtool.h index 6e4f7dc2ea..4eca23a399 100644 --- a/app/tools/gimpthresholdtool.h +++ b/app/tools/gimpthresholdtool.h @@ -39,6 +39,7 @@ struct _GimpThresholdTool /* dialog */ GimpHistogram *histogram; + GtkWidget *channel_menu; GimpHistogramBox *histogram_box; }; diff --git a/libgimp/gimpdrawablecolor_pdb.c b/libgimp/gimpdrawablecolor_pdb.c index 6c6ea40325..7541d499fc 100644 --- a/libgimp/gimpdrawablecolor_pdb.c +++ b/libgimp/gimpdrawablecolor_pdb.c @@ -635,6 +635,7 @@ gimp_drawable_posterize (gint32 drawable_ID, /** * gimp_drawable_threshold: * @drawable_ID: The drawable. + * @channel: The channel to base the threshold on. * @low_threshold: The low threshold value. * @high_threshold: The high threshold value. * @@ -642,17 +643,18 @@ gimp_drawable_posterize (gint32 drawable_ID, * * This procedures generates a threshold map of the specified drawable. * All pixels between the values of 'low_threshold' and - * 'high_threshold' are replaced with white, and all other pixels with - * black. + * 'high_threshold', on the scale of 'channel' are replaced with white, + * and all other pixels with black. * * Returns: TRUE on success. * * Since: 2.10 **/ gboolean -gimp_drawable_threshold (gint32 drawable_ID, - gdouble low_threshold, - gdouble high_threshold) +gimp_drawable_threshold (gint32 drawable_ID, + GimpHistogramChannel channel, + gdouble low_threshold, + gdouble high_threshold) { GimpParam *return_vals; gint nreturn_vals; @@ -661,6 +663,7 @@ gimp_drawable_threshold (gint32 drawable_ID, return_vals = gimp_run_procedure ("gimp-drawable-threshold", &nreturn_vals, GIMP_PDB_DRAWABLE, drawable_ID, + GIMP_PDB_INT32, channel, GIMP_PDB_FLOAT, low_threshold, GIMP_PDB_FLOAT, high_threshold, GIMP_PDB_END); diff --git a/libgimp/gimpdrawablecolor_pdb.h b/libgimp/gimpdrawablecolor_pdb.h index b8e138e39e..a30f1dd9b3 100644 --- a/libgimp/gimpdrawablecolor_pdb.h +++ b/libgimp/gimpdrawablecolor_pdb.h @@ -85,6 +85,7 @@ gboolean gimp_drawable_levels_stretch (gint32 drawable_ID); gboolean gimp_drawable_posterize (gint32 drawable_ID, gint levels); gboolean gimp_drawable_threshold (gint32 drawable_ID, + GimpHistogramChannel channel, gdouble low_threshold, gdouble high_threshold); diff --git a/tools/pdbgen/pdb/drawable_color.pdb b/tools/pdbgen/pdb/drawable_color.pdb index c825b6a609..960289dfa4 100644 --- a/tools/pdbgen/pdb/drawable_color.pdb +++ b/tools/pdbgen/pdb/drawable_color.pdb @@ -742,8 +742,8 @@ sub drawable_threshold { $help = <<'HELP'; This procedures generates a threshold map of the specified drawable. All pixels between the values of 'low_threshold' and -'high_threshold' are replaced with white, and all other pixels with -black. +'high_threshold', on the scale of 'channel' are replaced with white, +and all other pixels with black. HELP &std_pdb_misc; @@ -753,6 +753,8 @@ HELP @inargs = ( { name => 'drawable', type => 'drawable', desc => 'The drawable' }, + { name => 'channel', type => 'enum GimpHistogramChannel', + desc => 'The channel to base the threshold on' }, { name => 'low_threshold', type => '0.0 <= float <= 1.0', desc => 'The low threshold value' }, { name => 'high_threshold', type => '0.0 <= float <= 1.0', @@ -769,6 +771,7 @@ HELP GeglNode *node = gegl_node_new_child (NULL, "operation", "gimp:threshold", + "channel", channel, "low", low_threshold, "high", high_threshold, NULL);