app: port the foreground select tool to the GEGL matting ops

This is work in progress and needs the fixed GEGL ops too.
This commit is contained in:
Miroslav Talasek 2013-05-08 00:00:48 +02:00 committed by Michael Natterer
parent b893993e7b
commit 1cd1541b2d
4 changed files with 566 additions and 511 deletions

View File

@ -26,10 +26,9 @@
#include "tools-types.h" #include "tools-types.h"
#if 0 #include "widgets/gimppropwidgets.h"
#include "base/siox.h" #include "widgets/gimpspinscale.h"
#endif #include "widgets/gimpwidgets-constructors.h"
#include "widgets/gimpwidgets-utils.h" #include "widgets/gimpwidgets-utils.h"
#include "gimpforegroundselectoptions.h" #include "gimpforegroundselectoptions.h"
@ -38,22 +37,26 @@
#include "gimp-intl.h" #include "gimp-intl.h"
/*
* for matting-global: iterations int
* for matting-levin: levels int, active levels int
*/
enum enum
{ {
PROP_0, PROP_0,
PROP_ANTIALIAS, PROP_DRAW_MODE,
PROP_CONTIGUOUS,
PROP_BACKGROUND,
PROP_STROKE_WIDTH, PROP_STROKE_WIDTH,
PROP_SMOOTHNESS,
PROP_MASK_COLOR, PROP_MASK_COLOR,
PROP_EXPANDED, PROP_ENGINE,
PROP_SENSITIVITY_L, PROP_ITERATIONS,
PROP_SENSITIVITY_A, PROP_LEVELS,
PROP_SENSITIVITY_B PROP_ACTIVE_LEVELS
}; };
static void gimp_foreground_select_options_set_property (GObject *object, static void gimp_foreground_select_options_set_property (GObject *object,
guint property_id, guint property_id,
const GValue *value, const GValue *value,
@ -63,6 +66,14 @@ static void gimp_foreground_select_options_get_property (GObject *object,
GValue *value, GValue *value,
GParamSpec *pspec); GParamSpec *pspec);
static void gimp_foreground_select_options_gui_reset_stroke_width (GtkWidget *button,
GimpToolOptions *tool_options);
static void gimp_foreground_select_notify_engine (GimpToolOptions *tool_options,
GParamSpec *pspec,
GtkWidget *table);
G_DEFINE_TYPE (GimpForegroundSelectOptions, gimp_foreground_select_options, G_DEFINE_TYPE (GimpForegroundSelectOptions, gimp_foreground_select_options,
GIMP_TYPE_SELECTION_OPTIONS) GIMP_TYPE_SELECTION_OPTIONS)
@ -77,41 +88,28 @@ gimp_foreground_select_options_class_init (GimpForegroundSelectOptionsClass *kla
object_class->get_property = gimp_foreground_select_options_get_property; object_class->get_property = gimp_foreground_select_options_get_property;
/* override the antialias default value from GimpSelectionOptions */ /* override the antialias default value from GimpSelectionOptions */
GIMP_CONFIG_INSTALL_PROP_BOOLEAN (object_class, PROP_ANTIALIAS,
"antialias",
N_("Smooth edges"),
FALSE,
GIMP_PARAM_STATIC_STRINGS);
GIMP_CONFIG_INSTALL_PROP_BOOLEAN (object_class, PROP_CONTIGUOUS, GIMP_CONFIG_INSTALL_PROP_ENUM (object_class, PROP_DRAW_MODE,
"contiguous", "draw-mode",
N_("Select a single contiguous area"),
TRUE,
GIMP_PARAM_STATIC_STRINGS);
GIMP_CONFIG_INSTALL_PROP_BOOLEAN (object_class, PROP_BACKGROUND,
"background",
N_("Paint over areas to mark color values for " N_("Paint over areas to mark color values for "
"inclusion or exclusion from selection"), "inclusion or exclusion from selection"),
FALSE, GIMP_TYPE_MATTING_DRAW_MODE,
GIMP_MATTING_DRAW_MODE_FOREGROUND,
GIMP_PARAM_STATIC_STRINGS);
GIMP_CONFIG_INSTALL_PROP_ENUM (object_class, PROP_ENGINE,
"engine",
N_("Matting engine to use"),
GIMP_TYPE_MATTING_ENGINE,
GIMP_MATTING_ENGINE_MATTING_GLOBAL,
GIMP_PARAM_STATIC_STRINGS); GIMP_PARAM_STATIC_STRINGS);
GIMP_CONFIG_INSTALL_PROP_INT (object_class, PROP_STROKE_WIDTH, GIMP_CONFIG_INSTALL_PROP_INT (object_class, PROP_STROKE_WIDTH,
"stroke-width", "stroke-width",
N_("Size of the brush used for refinements"), N_("Size of the brush used for refinements"),
1, 80, 18, 1, 6000, 10,
GIMP_PARAM_STATIC_STRINGS); GIMP_PARAM_STATIC_STRINGS);
#if 0
GIMP_CONFIG_INSTALL_PROP_INT (object_class, PROP_SMOOTHNESS,
"smoothness",
N_("Smaller values give a more accurate "
"selection border but may introduce holes "
"in the selection"),
0, 8, SIOX_DEFAULT_SMOOTHNESS,
GIMP_PARAM_STATIC_STRINGS);
#endif
GIMP_CONFIG_INSTALL_PROP_ENUM (object_class, PROP_MASK_COLOR, GIMP_CONFIG_INSTALL_PROP_ENUM (object_class, PROP_MASK_COLOR,
"mask-color", "mask-color",
N_("Color of selection preview mask"), N_("Color of selection preview mask"),
@ -119,30 +117,21 @@ gimp_foreground_select_options_class_init (GimpForegroundSelectOptionsClass *kla
GIMP_BLUE_CHANNEL, GIMP_BLUE_CHANNEL,
GIMP_PARAM_STATIC_STRINGS); GIMP_PARAM_STATIC_STRINGS);
GIMP_CONFIG_INSTALL_PROP_BOOLEAN (object_class, PROP_EXPANDED, GIMP_CONFIG_INSTALL_PROP_INT (object_class, PROP_LEVELS,
"expanded", NULL, "levels",
FALSE, N_("Parameter for matting-levin"),
0); 1, 10, 2,
#if 0
GIMP_CONFIG_INSTALL_PROP_DOUBLE (object_class, PROP_SENSITIVITY_L,
"sensitivity-l",
N_("Sensitivity for brightness component"),
0.0, 10.0, SIOX_DEFAULT_SENSITIVITY_L,
GIMP_PARAM_STATIC_STRINGS); GIMP_PARAM_STATIC_STRINGS);
GIMP_CONFIG_INSTALL_PROP_INT (object_class, PROP_ACTIVE_LEVELS,
GIMP_CONFIG_INSTALL_PROP_DOUBLE (object_class, PROP_SENSITIVITY_A, "active-levels",
"sensitivity-a", N_("Parameter for matting-levin"),
N_("Sensitivity for red/green component"), 1, 10, 2,
0.0, 10.0, SIOX_DEFAULT_SENSITIVITY_A,
GIMP_PARAM_STATIC_STRINGS); GIMP_PARAM_STATIC_STRINGS);
GIMP_CONFIG_INSTALL_PROP_INT (object_class, PROP_ITERATIONS,
GIMP_CONFIG_INSTALL_PROP_DOUBLE (object_class, PROP_SENSITIVITY_B, "iterations",
"sensitivity-b", N_("Parameter for matting-global"),
N_("Sensitivity for yellow/blue component"), 1, 10, 2,
0.0, 10.0, SIOX_DEFAULT_SENSITIVITY_B,
GIMP_PARAM_STATIC_STRINGS); GIMP_PARAM_STATIC_STRINGS);
#endif
} }
static void static void
@ -160,44 +149,32 @@ gimp_foreground_select_options_set_property (GObject *object,
switch (property_id) switch (property_id)
{ {
case PROP_ANTIALIAS: case PROP_DRAW_MODE:
GIMP_SELECTION_OPTIONS (object)->antialias = g_value_get_boolean (value); options->draw_mode = g_value_get_enum (value);
break; break;
case PROP_CONTIGUOUS: case PROP_ENGINE:
options->contiguous = g_value_get_boolean (value); options->engine = g_value_get_enum (value);
break;
case PROP_BACKGROUND:
options->background = g_value_get_boolean (value);
break; break;
case PROP_STROKE_WIDTH: case PROP_STROKE_WIDTH:
options->stroke_width = g_value_get_int (value); options->stroke_width = g_value_get_int (value);
break; break;
case PROP_SMOOTHNESS:
options->smoothness = g_value_get_int (value);
break;
case PROP_MASK_COLOR: case PROP_MASK_COLOR:
options->mask_color = g_value_get_enum (value); options->mask_color = g_value_get_enum (value);
break; break;
case PROP_EXPANDED: case PROP_LEVELS:
options->expanded = g_value_get_boolean (value); options->levels = g_value_get_int (value);
break; break;
case PROP_SENSITIVITY_L: case PROP_ACTIVE_LEVELS:
options->sensitivity[0] = g_value_get_double (value); options->active_levels = g_value_get_int (value);
break; break;
case PROP_SENSITIVITY_A: case PROP_ITERATIONS:
options->sensitivity[1] = g_value_get_double (value); options->iterations = g_value_get_int (value);
break;
case PROP_SENSITIVITY_B:
options->sensitivity[2] = g_value_get_double (value);
break; break;
default: default:
@ -216,44 +193,33 @@ gimp_foreground_select_options_get_property (GObject *object,
switch (property_id) switch (property_id)
{ {
case PROP_ANTIALIAS:
g_value_set_boolean (value, GIMP_SELECTION_OPTIONS (object)->antialias); case PROP_DRAW_MODE:
g_value_set_enum (value, options->draw_mode);
break; break;
case PROP_CONTIGUOUS: case PROP_ENGINE:
g_value_set_boolean (value, options->contiguous); g_value_set_enum (value, options->engine);
break;
case PROP_BACKGROUND:
g_value_set_boolean (value, options->background);
break; break;
case PROP_STROKE_WIDTH: case PROP_STROKE_WIDTH:
g_value_set_int (value, options->stroke_width); g_value_set_int (value, options->stroke_width);
break; break;
case PROP_SMOOTHNESS:
g_value_set_int (value, options->smoothness);
break;
case PROP_MASK_COLOR: case PROP_MASK_COLOR:
g_value_set_enum (value, options->mask_color); g_value_set_enum (value, options->mask_color);
break; break;
case PROP_EXPANDED: case PROP_LEVELS:
g_value_set_boolean (value, options->expanded); g_value_set_int (value, options->levels);
break; break;
case PROP_SENSITIVITY_L: case PROP_ACTIVE_LEVELS:
g_value_set_double (value, options->sensitivity[0]); g_value_set_int (value, options->active_levels);
break; break;
case PROP_SENSITIVITY_A: case PROP_ITERATIONS:
g_value_set_double (value, options->sensitivity[1]); g_value_set_int (value, options->iterations);
break;
case PROP_SENSITIVITY_B:
g_value_set_double (value, options->sensitivity[2]);
break; break;
default: default:
@ -271,116 +237,175 @@ gimp_foreground_select_options_gui (GimpToolOptions *tool_options)
GtkWidget *button; GtkWidget *button;
GtkWidget *frame; GtkWidget *frame;
GtkWidget *scale; GtkWidget *scale;
GtkWidget *label; GtkWidget *combo;
GtkWidget *menu;
GtkWidget *inner_frame;
GtkWidget *table; GtkWidget *table;
gchar *title;
gint row = 0; gint row = 0;
GdkModifierType toggle_mask; GimpForegroundSelectOptions *options = GIMP_FOREGROUND_SELECT_OPTIONS (config);
toggle_mask = gimp_get_toggle_behavior_mask ();
gtk_widget_set_sensitive (GIMP_SELECTION_OPTIONS (tool_options)->antialias_toggle,
FALSE);
/* single / multiple objects */
button = gimp_prop_check_button_new (config, "contiguous", _("Contiguous"));
gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
gtk_widget_show (button);
/* foreground / background */
title = g_strdup_printf (_("Interactive refinement (%s)"),
gimp_get_mod_string (toggle_mask));
frame = gimp_prop_boolean_radio_frame_new (config, "background", title,
_("Mark background"),
_("Mark foreground"));
g_free (title);
frame = gimp_prop_enum_radio_frame_new (config, "draw-mode", _("Draw Mode"),
0,0);
gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0); gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
gtk_widget_show (frame); gtk_widget_show (frame);
/* stroke width */ hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 2);
inner_frame = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
gtk_box_pack_start (GTK_BOX (gtk_bin_get_child (GTK_BIN (frame))),
inner_frame, FALSE, FALSE, 2);
gtk_widget_show (inner_frame);
hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
gtk_box_pack_start (GTK_BOX (inner_frame), hbox, FALSE, FALSE, 0);
gtk_widget_show (hbox); gtk_widget_show (hbox);
label = gtk_label_new (_("Small brush")); /* stroke width */
gimp_label_set_attributes (GTK_LABEL (label), scale = gimp_prop_spin_scale_new (config, "stroke-width",
PANGO_ATTR_STYLE, PANGO_STYLE_ITALIC, _("Stroke width"),
PANGO_ATTR_SCALE, PANGO_SCALE_SMALL, 1.0, 10.0, 2);
-1); gimp_spin_scale_set_scale_limits (GIMP_SPIN_SCALE (scale), 1.0, 1000.0);
gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0); gimp_spin_scale_set_gamma (GIMP_SPIN_SCALE (scale), 1.7);
gtk_widget_show (label); gtk_box_pack_start (GTK_BOX (hbox), scale, TRUE, TRUE, 0);
label = gtk_label_new (_("Large brush"));
gimp_label_set_attributes (GTK_LABEL (label),
PANGO_ATTR_STYLE, PANGO_STYLE_ITALIC,
PANGO_ATTR_SCALE, PANGO_SCALE_SMALL,
-1);
gtk_box_pack_end (GTK_BOX (hbox), label, FALSE, FALSE, 0);
gtk_widget_show (label);
scale = gimp_prop_hscale_new (config, "stroke-width", 1.0, 5.0, 0);
gtk_scale_set_draw_value (GTK_SCALE (scale), FALSE);
gtk_box_pack_start (GTK_BOX (inner_frame), scale, FALSE, FALSE, 0);
gtk_widget_show (scale); gtk_widget_show (scale);
/* smoothness */ button = gimp_stock_button_new (GIMP_STOCK_RESET, NULL);
table = gtk_table_new (2, 3, FALSE); gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE);
gtk_table_set_row_spacings (GTK_TABLE (table), 2); gtk_image_set_from_stock (GTK_IMAGE (gtk_bin_get_child (GTK_BIN (button))),
gtk_table_set_col_spacings (GTK_TABLE (table), 2); GIMP_STOCK_RESET, GTK_ICON_SIZE_MENU);
gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, FALSE, 0); gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0);
gtk_widget_show (table); gtk_widget_show (button);
#if 0 g_signal_connect (button, "clicked",
scale = gimp_prop_hscale_new (config, "smoothness", 0.1, 1.0, 0); G_CALLBACK (gimp_foreground_select_options_gui_reset_stroke_width),
gtk_scale_set_value_pos (GTK_SCALE (scale), GTK_POS_RIGHT); tool_options);
gimp_table_attach_aligned (GTK_TABLE (table), 0, 0,
_("Smoothing:"), 0.0, 0.5, scale, 2, FALSE); gimp_help_set_help_data (button,
#endif _("Reset stroke width native size"), NULL);
/* mask color */ /* mask color */
menu = gimp_prop_enum_combo_box_new (config, "mask-color", frame = gimp_frame_new (_("Preview color:"));
GIMP_RED_CHANNEL, GIMP_BLUE_CHANNEL);
gimp_table_attach_aligned (GTK_TABLE (table), 0, 1,
_("Preview color:"), 0.0, 0.5, menu, 2, FALSE);
#if 0
/* granularity */
frame = gimp_prop_expander_new (config, "expanded", _("Color Sensitivity"));
gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0); gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
gtk_widget_show (frame); gtk_widget_show (frame);
inner_frame = gimp_frame_new ("<expander>"); combo = gimp_prop_enum_combo_box_new (config, "mask-color",
gtk_container_add (GTK_CONTAINER (frame), inner_frame); GIMP_RED_CHANNEL, GIMP_GRAY_CHANNEL);
gtk_widget_show (inner_frame); gtk_container_add (GTK_CONTAINER (frame), combo);
gtk_widget_show (combo);
/* engine */
frame = gimp_frame_new (_("Engine:"));
gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
gtk_widget_show (frame);
combo = gimp_prop_enum_combo_box_new (config, "engine", 0, 0);
gtk_container_add (GTK_CONTAINER (frame), combo);
gtk_widget_show (combo);
/* parameters */
table = gtk_table_new (3, 3, FALSE); table = gtk_table_new (3, 3, FALSE);
gtk_table_set_col_spacings (GTK_TABLE (table), 2); gtk_table_set_col_spacings (GTK_TABLE (table), 2);
gtk_table_set_row_spacings (GTK_TABLE (table), 2); gtk_table_set_row_spacings (GTK_TABLE (table), 2);
gtk_container_add (GTK_CONTAINER (inner_frame), table); gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, FALSE, 0);
gtk_widget_show (table); gtk_widget_show (table);
gimp_prop_opacity_entry_new (config, "sensitivity-l", options->dynamic_widgets.levels = (GObject *)
GTK_TABLE (table), 0, row++, "L"); gimp_prop_scale_entry_new (config, "levels",
GTK_TABLE (table), 0, row++,
"Levels", 1, 1, 0, FALSE, 0, 0);
gimp_prop_opacity_entry_new (config, "sensitivity-a", options->dynamic_widgets.active_levels = (GObject *)
GTK_TABLE (table), 0, row++, "a"); gimp_prop_scale_entry_new (config, "active-levels",
GTK_TABLE (table), 0, row++,
"Act. Levels", 1, 1, 0, FALSE, 0, 0);
gimp_prop_opacity_entry_new (config, "sensitivity-b", options->dynamic_widgets.iterations = (GObject *)
GTK_TABLE (table), 0, row++, "b"); gimp_prop_scale_entry_new (config, "iterations",
#endif GTK_TABLE (table), 0, row++,
"Iterations", 1, 1, 0, FALSE, 0, 0);
g_signal_connect_object (config, "notify::engine",
G_CALLBACK (gimp_foreground_select_notify_engine),
NULL, 0);
gimp_foreground_select_notify_engine (tool_options, NULL, NULL);
return vbox; return vbox;
} }
static void
gimp_foreground_select_options_gui_reset_stroke_width (GtkWidget *button,
GimpToolOptions *tool_options)
{
g_object_set (tool_options, "stroke-width", 10, NULL);
}
static void
gimp_foreground_select_show_scale (GObject *object)
{
GtkWidget *spin;
GtkWidget *label;
GtkWidget *scale;
label = g_object_get_data (object, "label");
spin = g_object_get_data (object, "spinbutton");
scale = g_object_get_data (object, "scale");
gtk_widget_show (label);
gtk_widget_show (spin);
gtk_widget_show (scale);
}
static void
gimp_foreground_select_hide_scale (GObject *object)
{
GtkWidget *spin;
GtkWidget *label;
GtkWidget *scale;
label = g_object_get_data (object, "label");
spin = g_object_get_data (object, "spinbutton");
scale = g_object_get_data (object, "scale");
gtk_widget_hide (label);
gtk_widget_hide (spin);
gtk_widget_hide (scale);
}
static void
gimp_foreground_select_notify_engine (GimpToolOptions *tool_options,
GParamSpec *pspec,
GtkWidget *widget)
{
GimpForegroundSelectOptions *options = GIMP_FOREGROUND_SELECT_OPTIONS (tool_options);
switch (options->engine)
{
case GIMP_MATTING_ENGINE_MATTING_GLOBAL:
gimp_foreground_select_show_scale (options->dynamic_widgets.iterations);
gimp_foreground_select_hide_scale (options->dynamic_widgets.levels);
gimp_foreground_select_hide_scale (options->dynamic_widgets.active_levels);
break;
case GIMP_MATTING_ENGINE_MATTING_LEVIN:
gimp_foreground_select_hide_scale (options->dynamic_widgets.iterations);
gimp_foreground_select_show_scale (options->dynamic_widgets.levels);
gimp_foreground_select_show_scale (options->dynamic_widgets.active_levels);
break;
}
}
gdouble
gimp_foreground_select_options_get_opacity (GimpForegroundSelectOptions *options)
{
g_return_val_if_fail (GIMP_IS_FOREGROUND_SELECT_OPTIONS (options), 0.0);
switch (options->draw_mode)
{
case GIMP_MATTING_DRAW_MODE_FOREGROUND:
return 1.0;
case GIMP_MATTING_DRAW_MODE_BACKGROUND:
return 0.0;
case GIMP_MATTING_DRAW_MODE_UNKNOWN:
default:
return 0.5;
}
}
void void
gimp_foreground_select_options_get_mask_color (GimpForegroundSelectOptions *options, gimp_foreground_select_options_get_mask_color (GimpForegroundSelectOptions *options,
GimpRGB *color) GimpRGB *color)
@ -391,15 +416,19 @@ gimp_foreground_select_options_get_mask_color (GimpForegroundSelectOptions *opti
switch (options->mask_color) switch (options->mask_color)
{ {
case GIMP_RED_CHANNEL: case GIMP_RED_CHANNEL:
gimp_rgba_set (color, 1, 0, 0, 0.5); gimp_rgba_set (color, 1, 0, 0, 0.7);
break; break;
case GIMP_GREEN_CHANNEL: case GIMP_GREEN_CHANNEL:
gimp_rgba_set (color, 0, 1, 0, 0.5); gimp_rgba_set (color, 0, 1, 0, 0.7);
break; break;
case GIMP_BLUE_CHANNEL: case GIMP_BLUE_CHANNEL:
gimp_rgba_set (color, 0, 0, 1, 0.5); gimp_rgba_set (color, 0, 0, 1, 0.7);
break;
case GIMP_GRAY_CHANNEL:
gimp_rgba_set (color, 1, 1, 1, 0.7);
break; break;
default: default:

View File

@ -15,6 +15,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#ifndef __GIMP_FOREGROUND_SELECT_OPTIONS_H__ #ifndef __GIMP_FOREGROUND_SELECT_OPTIONS_H__
#define __GIMP_FOREGROUND_SELECT_OPTIONS_H__ #define __GIMP_FOREGROUND_SELECT_OPTIONS_H__
@ -31,19 +32,34 @@
typedef struct _GimpForegroundSelectOptions GimpForegroundSelectOptions; typedef struct _GimpForegroundSelectOptions GimpForegroundSelectOptions;
typedef GimpSelectionOptionsClass GimpForegroundSelectOptionsClass; typedef struct _GimpForegroundSelectOptionsClass GimpForegroundSelectOptionsClass;
typedef struct _GimpMattingDynamicWidgets GimpMattingDynamicWidgets;
struct _GimpMattingDynamicWidgets
{
GObject *levels;
GObject *active_levels;
GObject *iterations;
};
struct _GimpForegroundSelectOptions struct _GimpForegroundSelectOptions
{ {
GimpSelectionOptions parent_instance; GimpSelectionOptions parent_instance;
gboolean contiguous; GimpMattingDrawMode draw_mode;
gboolean background;
gint stroke_width; gint stroke_width;
gint smoothness;
GimpChannelType mask_color; GimpChannelType mask_color;
gboolean expanded; GimpMattingEngine engine;
gdouble sensitivity[3]; gint levels;
gint active_levels;
gint iterations;
GimpMattingDynamicWidgets dynamic_widgets;
};
struct _GimpForegroundSelectOptionsClass
{
GimpSelectionOptionsClass parent_class;
}; };
@ -53,6 +69,8 @@ GtkWidget * gimp_foreground_select_options_gui (GimpToolOptions
void gimp_foreground_select_options_get_mask_color (GimpForegroundSelectOptions *options, void gimp_foreground_select_options_get_mask_color (GimpForegroundSelectOptions *options,
GimpRGB *color); GimpRGB *color);
gdouble gimp_foreground_select_options_get_opacity (GimpForegroundSelectOptions *options);
#endif /* __GIMP_FOREGROUND_SELECT_OPTIONS_H__ */ #endif /* __GIMP_FOREGROUND_SELECT_OPTIONS_H__ */

View File

@ -27,16 +27,18 @@
#include <gdk/gdkkeysyms.h> #include <gdk/gdkkeysyms.h>
#include "libgimpmath/gimpmath.h" #include "libgimpmath/gimpmath.h"
#include "libgimpcolor/gimpcolor.h"
#include "libgimpwidgets/gimpwidgets.h" #include "libgimpwidgets/gimpwidgets.h"
#include "tools-types.h" #include "tools-types.h"
#include "core/gimp.h" #include "core/gimp.h"
#include "core/gimpchannel.h"
#include "core/gimpchannel-combine.h" #include "core/gimpchannel-combine.h"
#include "core/gimpchannel-select.h" #include "core/gimpchannel-select.h"
#include "core/gimpdrawable-foreground-extract.h" #include "core/gimpdrawable-foreground-extract.h"
#include "core/gimpimage.h" #include "core/gimpimage.h"
#include "core/gimplayer.h"
#include "core/gimplayermask.h"
#include "core/gimpprogress.h" #include "core/gimpprogress.h"
#include "core/gimpscanconvert.h" #include "core/gimpscanconvert.h"
@ -108,23 +110,26 @@ static void gimp_foreground_select_tool_draw (GimpDrawTool *draw
static void gimp_foreground_select_tool_select (GimpFreeSelectTool *free_sel, static void gimp_foreground_select_tool_select (GimpFreeSelectTool *free_sel,
GimpDisplay *display); GimpDisplay *display);
static void gimp_foreground_select_tool_set_mask (GimpForegroundSelectTool *fg_select, static void gimp_foreground_select_tool_set_trimap (GimpForegroundSelectTool *fg_select,
GimpDisplay *display, GimpDisplay *display);
GimpChannel *mask); static void gimp_foreground_select_tool_set_preview (GimpForegroundSelectTool *fg_select,
static void gimp_foreground_select_tool_apply (GimpForegroundSelectTool *fg_select, GimpDisplay *display);
static void gimp_foreground_select_tool_drop_masks (GimpForegroundSelectTool *fg_select,
GimpDisplay *display); GimpDisplay *display);
static void gimp_foreground_select_tool_stroke (GimpChannel *mask, static void gimp_foreground_select_tool_apply (GimpForegroundSelectTool *fg_select,
FgSelectStroke *stroke); GimpDisplay *display);
static void gimp_foreground_select_tool_preview (GimpForegroundSelectTool *fg_select,
static void gimp_foreground_select_tool_push_stroke (GimpForegroundSelectTool *fg_select, GimpDisplay *display);
GimpDisplay *display,
GimpForegroundSelectOptions *options);
static void gimp_foreground_select_options_notify (GimpForegroundSelectOptions *options, static void gimp_foreground_select_options_notify (GimpForegroundSelectOptions *options,
GParamSpec *pspec, GParamSpec *pspec,
GimpForegroundSelectTool *fg_select); GimpForegroundSelectTool *fg_select);
static void gimp_foreground_select_tool_stroke_paint (GimpForegroundSelectTool *fg_select,
GimpDisplay *display,
GimpForegroundSelectOptions *options);
G_DEFINE_TYPE (GimpForegroundSelectTool, gimp_foreground_select_tool, G_DEFINE_TYPE (GimpForegroundSelectTool, gimp_foreground_select_tool,
GIMP_TYPE_FREE_SELECT_TOOL) GIMP_TYPE_FREE_SELECT_TOOL)
@ -194,10 +199,10 @@ gimp_foreground_select_tool_init (GimpForegroundSelectTool *fg_select)
gimp_tool_control_set_action_value_2 (tool->control, gimp_tool_control_set_action_value_2 (tool->control,
"tools/tools-foreground-select-brush-size-set"); "tools/tools-foreground-select-brush-size-set");
fg_select->idle_id = 0;
fg_select->stroke = NULL; fg_select->stroke = NULL;
fg_select->strokes = NULL;
fg_select->mask = NULL; fg_select->mask = NULL;
fg_select->trimap = NULL;
fg_select->state = MATTING_STATE_FREE_SELECT;
} }
static void static void
@ -220,17 +225,12 @@ gimp_foreground_select_tool_finalize (GObject *object)
if (fg_select->stroke) if (fg_select->stroke)
g_warning ("%s: stroke should be NULL at this point", G_STRLOC); g_warning ("%s: stroke should be NULL at this point", G_STRLOC);
if (fg_select->strokes)
g_warning ("%s: strokes should be NULL at this point", G_STRLOC);
#if 0
if (fg_select->state)
g_warning ("%s: state should be NULL at this point", G_STRLOC);
#endif
if (fg_select->mask) if (fg_select->mask)
g_warning ("%s: mask should be NULL at this point", G_STRLOC); g_warning ("%s: mask should be NULL at this point", G_STRLOC);
if (fg_select->trimap)
g_warning ("%s: mask should be NULL at this point", G_STRLOC);
G_OBJECT_CLASS (parent_class)->finalize (object); G_OBJECT_CLASS (parent_class)->finalize (object);
} }
@ -249,29 +249,7 @@ gimp_foreground_select_tool_control (GimpTool *tool,
case GIMP_TOOL_ACTION_HALT: case GIMP_TOOL_ACTION_HALT:
{ {
GList *list; gimp_foreground_select_tool_drop_masks (fg_select, display);
gimp_foreground_select_tool_set_mask (fg_select, display, NULL);
for (list = fg_select->strokes; list; list = list->next)
{
FgSelectStroke *stroke = list->data;
g_free (stroke->points);
g_slice_free (FgSelectStroke, stroke);
}
g_list_free (fg_select->strokes);
fg_select->strokes = NULL;
#if 0
if (fg_select->state)
{
gimp_drawable_foreground_extract_siox_done (fg_select->state);
fg_select->state = NULL;
}
#endif
tool->display = NULL; tool->display = NULL;
} }
break; break;
@ -293,7 +271,7 @@ gimp_foreground_select_tool_oper_update (GimpTool *tool,
GIMP_TOOL_CLASS (parent_class)->oper_update (tool, coords, state, proximity, GIMP_TOOL_CLASS (parent_class)->oper_update (tool, coords, state, proximity,
display); display);
if (fg_select->mask && display == tool->display) if (fg_select->state == MATTING_STATE_PAINT_TRIMAP && display == tool->display)
{ {
GimpDrawTool *draw_tool = GIMP_DRAW_TOOL (tool); GimpDrawTool *draw_tool = GIMP_DRAW_TOOL (tool);
@ -302,17 +280,17 @@ gimp_foreground_select_tool_oper_update (GimpTool *tool,
fg_select->last_coords = *coords; fg_select->last_coords = *coords;
gimp_draw_tool_resume (draw_tool); gimp_draw_tool_resume (draw_tool);
status = _("Paint trimap, (background, foreground and unknown) or press Enter to preview");
if (fg_select->strokes)
status = _("Add more strokes or press Enter to accept the selection");
else
status = _("Mark foreground by painting on the object to extract");
} }
else else if (fg_select->state == MATTING_STATE_FREE_SELECT)
{ {
if (GIMP_SELECTION_TOOL (tool)->function == SELECTION_SELECT) if (GIMP_SELECTION_TOOL (tool)->function == SELECTION_SELECT)
status = _("Roughly outline the object to extract"); status = _("Roughly outline the object to extract");
} }
else
{
status = _("Press escape for return to trimap or Enter to apply");
}
if (proximity && status) if (proximity && status)
gimp_tool_replace_status (tool, display, "%s", status); gimp_tool_replace_status (tool, display, "%s", status);
@ -325,6 +303,7 @@ gimp_foreground_select_tool_modifier_key (GimpTool *tool,
GdkModifierType state, GdkModifierType state,
GimpDisplay *display) GimpDisplay *display)
{ {
#if 0
if (key == gimp_get_toggle_behavior_mask ()) if (key == gimp_get_toggle_behavior_mask ())
{ {
GimpForegroundSelectOptions *options; GimpForegroundSelectOptions *options;
@ -335,6 +314,7 @@ gimp_foreground_select_tool_modifier_key (GimpTool *tool,
"background", ! options->background, "background", ! options->background,
NULL); NULL);
} }
#endif
} }
static void static void
@ -345,14 +325,8 @@ gimp_foreground_select_tool_cursor_update (GimpTool *tool,
{ {
GimpForegroundSelectTool *fg_select = GIMP_FOREGROUND_SELECT_TOOL (tool); GimpForegroundSelectTool *fg_select = GIMP_FOREGROUND_SELECT_TOOL (tool);
if (fg_select->mask) if (fg_select->state == MATTING_STATE_PAINT_TRIMAP)
{ {
GimpForegroundSelectOptions *options;
options = GIMP_FOREGROUND_SELECT_TOOL_GET_OPTIONS (tool);
gimp_tool_control_set_toggled (tool->control, options->background);
switch (GIMP_SELECTION_TOOL (tool)->function) switch (GIMP_SELECTION_TOOL (tool)->function)
{ {
case SELECTION_MOVE_MASK: case SELECTION_MOVE_MASK:
@ -378,10 +352,25 @@ gimp_foreground_select_tool_key_press (GimpTool *tool,
if (display != tool->display) if (display != tool->display)
return FALSE; return FALSE;
#if 0 if (fg_select->state == MATTING_STATE_PAINT_TRIMAP)
if (fg_select->state) {
#endif switch (kevent->keyval)
if (fg_select->mask) /* dunno if that's the right condition */ {
case GDK_KEY_Return:
case GDK_KEY_KP_Enter:
case GDK_KEY_ISO_Enter:
gimp_foreground_select_tool_preview (fg_select, display);
return TRUE;
case GDK_KEY_Escape:
gimp_tool_control (tool, GIMP_TOOL_ACTION_HALT, display);
return TRUE;
default:
return FALSE;
}
}
else if (fg_select->state == MATTING_STATE_PREVIEW_MASK)
{ {
switch (kevent->keyval) switch (kevent->keyval)
{ {
@ -392,7 +381,7 @@ gimp_foreground_select_tool_key_press (GimpTool *tool,
return TRUE; return TRUE;
case GDK_KEY_Escape: case GDK_KEY_Escape:
gimp_tool_control (tool, GIMP_TOOL_ACTION_HALT, display); gimp_foreground_select_tool_set_trimap (fg_select, display);
return TRUE; return TRUE;
default: default:
@ -418,7 +407,7 @@ gimp_foreground_select_tool_button_press (GimpTool *tool,
GimpForegroundSelectTool *fg_select = GIMP_FOREGROUND_SELECT_TOOL (tool); GimpForegroundSelectTool *fg_select = GIMP_FOREGROUND_SELECT_TOOL (tool);
GimpDrawTool *draw_tool = GIMP_DRAW_TOOL (tool); GimpDrawTool *draw_tool = GIMP_DRAW_TOOL (tool);
if (fg_select->mask) if (fg_select->state == MATTING_STATE_PAINT_TRIMAP)
{ {
GimpVector2 point = gimp_vector2_new (coords->x, coords->y); GimpVector2 point = gimp_vector2_new (coords->x, coords->y);
@ -436,12 +425,12 @@ gimp_foreground_select_tool_button_press (GimpTool *tool,
g_array_append_val (fg_select->stroke, point); g_array_append_val (fg_select->stroke, point);
if (! gimp_draw_tool_is_active (draw_tool)) if (!gimp_draw_tool_is_active (draw_tool))
gimp_draw_tool_start (draw_tool, display); gimp_draw_tool_start (draw_tool, display);
gimp_draw_tool_resume (draw_tool); gimp_draw_tool_resume (draw_tool);
} }
else else if (fg_select->state == MATTING_STATE_FREE_SELECT)
{ {
GIMP_TOOL_CLASS (parent_class)->button_press (tool, coords, time, state, GIMP_TOOL_CLASS (parent_class)->button_press (tool, coords, time, state,
press_type, display); press_type, display);
@ -458,7 +447,7 @@ gimp_foreground_select_tool_button_release (GimpTool *tool,
{ {
GimpForegroundSelectTool *fg_select = GIMP_FOREGROUND_SELECT_TOOL (tool); GimpForegroundSelectTool *fg_select = GIMP_FOREGROUND_SELECT_TOOL (tool);
if (fg_select->mask) if (fg_select->state == MATTING_STATE_PAINT_TRIMAP)
{ {
GimpForegroundSelectOptions *options; GimpForegroundSelectOptions *options;
@ -468,13 +457,15 @@ gimp_foreground_select_tool_button_release (GimpTool *tool,
gimp_tool_control_halt (tool->control); gimp_tool_control_halt (tool->control);
gimp_foreground_select_tool_push_stroke (fg_select, display, options); gimp_foreground_select_tool_stroke_paint (fg_select, display, options);
gimp_foreground_select_tool_set_trimap (fg_select, display);
gimp_free_select_tool_select (GIMP_FREE_SELECT_TOOL (tool), display); gimp_free_select_tool_select (GIMP_FREE_SELECT_TOOL (tool), display);
gimp_draw_tool_resume (GIMP_DRAW_TOOL (tool)); gimp_draw_tool_resume (GIMP_DRAW_TOOL (tool));
} }
else else if (fg_select->state == MATTING_STATE_FREE_SELECT)
{ {
GIMP_TOOL_CLASS (parent_class)->button_release (tool, GIMP_TOOL_CLASS (parent_class)->button_release (tool,
coords, time, state, coords, time, state,
@ -492,7 +483,7 @@ gimp_foreground_select_tool_motion (GimpTool *tool,
{ {
GimpForegroundSelectTool *fg_select = GIMP_FOREGROUND_SELECT_TOOL (tool); GimpForegroundSelectTool *fg_select = GIMP_FOREGROUND_SELECT_TOOL (tool);
if (fg_select->mask) if (fg_select->state == MATTING_STATE_PAINT_TRIMAP)
{ {
GimpVector2 *last = &g_array_index (fg_select->stroke, GimpVector2 *last = &g_array_index (fg_select->stroke,
GimpVector2, GimpVector2,
@ -511,7 +502,7 @@ gimp_foreground_select_tool_motion (GimpTool *tool,
gimp_draw_tool_resume (GIMP_DRAW_TOOL (tool)); gimp_draw_tool_resume (GIMP_DRAW_TOOL (tool));
} }
else else if (fg_select->state == MATTING_STATE_FREE_SELECT)
{ {
GIMP_TOOL_CLASS (parent_class)->motion (tool, GIMP_TOOL_CLASS (parent_class)->motion (tool,
coords, time, state, display); coords, time, state, display);
@ -550,24 +541,23 @@ gimp_foreground_select_tool_draw (GimpDrawTool *draw_tool)
if (fg_select->stroke) if (fg_select->stroke)
{ {
GimpDisplayShell *shell = gimp_display_get_shell (draw_tool->display);
gimp_draw_tool_add_pen (draw_tool, gimp_draw_tool_add_pen (draw_tool,
(const GimpVector2 *) fg_select->stroke->data, (const GimpVector2 *) fg_select->stroke->data,
fg_select->stroke->len, fg_select->stroke->len,
GIMP_CONTEXT (options), GIMP_CONTEXT (options),
(options->background ? GIMP_ACTIVE_COLOR_FOREGROUND,
GIMP_ACTIVE_COLOR_BACKGROUND : options->stroke_width * shell->scale_y);
GIMP_ACTIVE_COLOR_FOREGROUND),
options->stroke_width);
} }
if (fg_select->mask) if (fg_select->state == MATTING_STATE_PAINT_TRIMAP)
{ {
GimpDisplayShell *shell = gimp_display_get_shell (draw_tool->display);
gint x = fg_select->last_coords.x; gint x = fg_select->last_coords.x;
gint y = fg_select->last_coords.y; gint y = fg_select->last_coords.y;
gdouble radius; gdouble radius;
radius = (options->stroke_width / shell->scale_y) / 2; radius = options->stroke_width / 2;
/* warn if the user is drawing outside of the working area */ /* warn if the user is drawing outside of the working area */
if (FALSE) if (FALSE)
@ -592,7 +582,7 @@ gimp_foreground_select_tool_draw (GimpDrawTool *draw_tool)
2 * radius, 2 * radius, 2 * radius, 2 * radius,
0.0, 2.0 * G_PI); 0.0, 2.0 * G_PI);
} }
else else if (fg_select->state == MATTING_STATE_FREE_SELECT)
{ {
GIMP_DRAW_TOOL_CLASS (parent_class)->draw (draw_tool); GIMP_DRAW_TOOL_CLASS (parent_class)->draw (draw_tool);
} }
@ -603,27 +593,20 @@ gimp_foreground_select_tool_select (GimpFreeSelectTool *free_sel,
GimpDisplay *display) GimpDisplay *display)
{ {
GimpForegroundSelectTool *fg_select; GimpForegroundSelectTool *fg_select;
GimpForegroundSelectOptions *options;
GimpImage *image = gimp_display_get_image (display); GimpImage *image = gimp_display_get_image (display);
GimpDrawable *drawable; GimpDrawable *drawable;
GimpScanConvert *scan_convert; GimpScanConvert *scan_convert;
GimpChannel *mask;
const GimpVector2 *points; const GimpVector2 *points;
gint n_points; gint n_points;
drawable = gimp_image_get_active_drawable (image); drawable = gimp_image_get_active_drawable (image);
fg_select = GIMP_FOREGROUND_SELECT_TOOL (free_sel); fg_select = GIMP_FOREGROUND_SELECT_TOOL (free_sel);
options = GIMP_FOREGROUND_SELECT_TOOL_GET_OPTIONS (free_sel);
if (fg_select->idle_id)
{
g_source_remove (fg_select->idle_id);
fg_select->idle_id = 0;
}
if (! drawable) if (! drawable)
return; return;
if (fg_select->state == MATTING_STATE_FREE_SELECT)
{
scan_convert = gimp_scan_convert_new (); scan_convert = gimp_scan_convert_new ();
gimp_free_select_tool_get_points (free_sel, gimp_free_select_tool_get_points (free_sel,
@ -635,77 +618,85 @@ gimp_foreground_select_tool_select (GimpFreeSelectTool *free_sel,
points, points,
TRUE); TRUE);
mask = gimp_channel_new (image, fg_select->trimap = gimp_channel_new (image,
gimp_image_get_width (image), gimp_image_get_width (image),
gimp_image_get_height (image), gimp_image_get_height (image),
"foreground-extraction", NULL); "foreground-extraction",NULL);
gimp_scan_convert_render_value (scan_convert, gimp_scan_convert_render_value (scan_convert,
gimp_drawable_get_buffer (GIMP_DRAWABLE (mask)), gimp_drawable_get_buffer (GIMP_DRAWABLE (fg_select->trimap)),
0, 0, 0.5); 0, 0, 1.0);
gimp_scan_convert_free (scan_convert); gimp_scan_convert_free (scan_convert);
if (fg_select->strokes) gimp_foreground_select_tool_set_trimap (fg_select, display);
{
GList *list;
gimp_set_busy (image->gimp);
/* apply foreground and background markers */
for (list = fg_select->strokes; list; list = list->next)
gimp_foreground_select_tool_stroke (mask, list->data);
#if 0
if (fg_select->state)
gimp_drawable_foreground_extract_siox (GIMP_DRAWABLE (mask),
fg_select->state,
fg_select->refinement,
options->smoothness,
options->sensitivity,
! options->contiguous,
GIMP_PROGRESS (fg_select));
#endif
fg_select->refinement = SIOX_REFINEMENT_NO_CHANGE;
gimp_unset_busy (image->gimp);
} }
else
{
gint x1, y1;
gint x2, y2;
g_object_set (options, "background", FALSE, NULL);
gimp_foreground_select_tool_get_area (mask, &x1, &y1, &x2, &y2);
#if 0
if (fg_select->state)
g_warning ("state should be NULL here");
fg_select->state =
gimp_drawable_foreground_extract_siox_init (drawable,
x1, y1, x2 - x1, y2 - y1);
#endif
}
gimp_foreground_select_tool_set_mask (fg_select, display, mask);
g_object_unref (mask);
} }
static void static void
gimp_foreground_select_tool_set_mask (GimpForegroundSelectTool *fg_select, gimp_foreground_select_tool_set_trimap (GimpForegroundSelectTool *fg_select,
GimpDisplay *display, GimpDisplay *display)
GimpChannel *mask)
{ {
GimpTool *tool = GIMP_TOOL (fg_select); GimpTool *tool = GIMP_TOOL (fg_select);
GimpForegroundSelectOptions *options; GimpForegroundSelectOptions *options;
GimpRGB color;
g_return_if_fail (fg_select->trimap != NULL);
options = GIMP_FOREGROUND_SELECT_TOOL_GET_OPTIONS (tool); options = GIMP_FOREGROUND_SELECT_TOOL_GET_OPTIONS (tool);
if (fg_select->mask == mask) gimp_foreground_select_options_get_mask_color (options, &color);
return; gimp_display_shell_set_mask (gimp_display_get_shell (display),
GIMP_DRAWABLE (fg_select->trimap), &color);
gimp_tool_control_set_tool_cursor (tool->control,
GIMP_TOOL_CURSOR_PAINTBRUSH);
gimp_tool_control_set_toggle_tool_cursor (tool->control,
GIMP_TOOL_CURSOR_PAINTBRUSH);
gimp_tool_control_set_toggled (tool->control, FALSE);
fg_select->state = MATTING_STATE_PAINT_TRIMAP;
}
static void
gimp_foreground_select_tool_set_preview (GimpForegroundSelectTool *fg_select,
GimpDisplay *display)
{
GimpTool *tool = GIMP_TOOL (fg_select);
GimpForegroundSelectOptions *options;
GimpRGB color;
g_return_if_fail (fg_select->mask != NULL);
options = GIMP_FOREGROUND_SELECT_TOOL_GET_OPTIONS (tool);
gimp_foreground_select_options_get_mask_color (options, &color);
gimp_rgb_set_alpha (&color, 1.0);
gimp_display_shell_set_mask (gimp_display_get_shell (display),
GIMP_DRAWABLE (fg_select->mask), &color);
gimp_tool_control_set_tool_cursor (tool->control,
GIMP_TOOL_CURSOR_PAINTBRUSH);
gimp_tool_control_set_toggle_tool_cursor (tool->control,
GIMP_TOOL_CURSOR_PAINTBRUSH);
gimp_tool_control_set_toggled (tool->control, FALSE);
fg_select->state = MATTING_STATE_PREVIEW_MASK;
}
static void
gimp_foreground_select_tool_drop_masks (GimpForegroundSelectTool *fg_select,
GimpDisplay *display)
{
GimpTool *tool = GIMP_TOOL (fg_select);
if (fg_select->trimap)
{
g_object_unref (fg_select->trimap);
fg_select->trimap = NULL;
}
if (fg_select->mask) if (fg_select->mask)
{ {
@ -713,40 +704,115 @@ gimp_foreground_select_tool_set_mask (GimpForegroundSelectTool *fg_select,
fg_select->mask = NULL; fg_select->mask = NULL;
} }
if (mask) if (GIMP_IS_DISPLAY (display))
{
GimpRGB color;
fg_select->mask = g_object_ref (mask);
gimp_foreground_select_options_get_mask_color (options, &color);
gimp_display_shell_set_mask (gimp_display_get_shell (display),
GIMP_DRAWABLE (mask), &color);
}
else
{ {
gimp_display_shell_set_mask (gimp_display_get_shell (display), gimp_display_shell_set_mask (gimp_display_get_shell (display),
NULL, NULL); NULL, NULL);
} }
if (mask)
{
gimp_tool_control_set_tool_cursor (tool->control,
GIMP_TOOL_CURSOR_PAINTBRUSH);
gimp_tool_control_set_toggle_tool_cursor (tool->control,
GIMP_TOOL_CURSOR_ERASER);
gimp_tool_control_set_toggled (tool->control, options->background);
}
else
{
gimp_tool_control_set_tool_cursor (tool->control, gimp_tool_control_set_tool_cursor (tool->control,
GIMP_TOOL_CURSOR_FREE_SELECT); GIMP_TOOL_CURSOR_FREE_SELECT);
gimp_tool_control_set_toggle_tool_cursor (tool->control, gimp_tool_control_set_toggle_tool_cursor (tool->control,
GIMP_TOOL_CURSOR_FREE_SELECT); GIMP_TOOL_CURSOR_FREE_SELECT);
gimp_tool_control_set_toggled (tool->control, FALSE); gimp_tool_control_set_toggled (tool->control, FALSE);
fg_select->state = MATTING_STATE_FREE_SELECT;
}
static void
gimp_foreground_select_tool_preview (GimpForegroundSelectTool *fg_select,
GimpDisplay *display)
{
GimpTool *tool = GIMP_TOOL (fg_select);
GimpForegroundSelectOptions *options = GIMP_FOREGROUND_SELECT_TOOL_GET_OPTIONS (tool);
GimpImage *image = gimp_display_get_image (display);
GimpDrawable *drawable = gimp_image_get_active_drawable (image);
GeglBuffer *trimap_buffer;
GeglBuffer *drawable_buffer;
GeglNode *gegl;
GeglNode *matting_node;
GeglNode *input_image;
GeglNode *input_trimap;
GeglNode *output_mask;
GeglBuffer *buffer;
GimpProgress *progress;
GeglProcessor *processor;
gdouble value;
if (fg_select->mask)
{
g_object_unref (fg_select->mask);
fg_select->mask = NULL;
} }
progress = gimp_progress_start (GIMP_PROGRESS (fg_select),
_("Computing alpha of unknown pixels"),
FALSE);
trimap_buffer = gimp_drawable_get_buffer (GIMP_DRAWABLE (fg_select->trimap));
drawable_buffer = gimp_drawable_get_buffer (drawable);
gegl = gegl_node_new ();
input_trimap = gegl_node_new_child (gegl,
"operation", "gegl:buffer-source",
"buffer", trimap_buffer,
NULL);
input_image = gegl_node_new_child (gegl,
"operation", "gegl:buffer-source",
"buffer", drawable_buffer,
NULL);
output_mask = gegl_node_new_child (gegl,
"operation", "gegl:buffer-sink",
"buffer", &buffer,
"format", NULL,
NULL);
if (options->engine == GIMP_MATTING_ENGINE_MATTING_GLOBAL)
{
matting_node = gegl_node_new_child (gegl,
"operation", "gegl:matting-global",
"iterations", options->iterations,
NULL);
}
else
{
matting_node = gegl_node_new_child (gegl,
"operation", "gegl:matting-levin",
"levels", options->levels,
"active_levels", options->active_levels,
NULL);
}
gegl_node_connect_to (input_image, "output",
matting_node, "input");
gegl_node_connect_to (input_trimap, "output",
matting_node, "aux");
gegl_node_connect_to (matting_node, "output",
output_mask, "input");
processor = gegl_node_new_processor (output_mask, NULL);
while (gegl_processor_work (processor, &value))
{
if (progress)
gimp_progress_set_value (progress, value);
}
if (progress)
gimp_progress_end (progress);
g_object_unref (processor);
fg_select->mask = gimp_channel_new_from_buffer (buffer, image,
"preview-mask", NULL);
gimp_foreground_select_tool_set_preview (fg_select, display);
g_object_unref (gegl);
if (buffer)
g_object_unref (buffer);
} }
static void static void
@ -754,18 +820,20 @@ gimp_foreground_select_tool_apply (GimpForegroundSelectTool *fg_select,
GimpDisplay *display) GimpDisplay *display)
{ {
GimpTool *tool = GIMP_TOOL (fg_select); GimpTool *tool = GIMP_TOOL (fg_select);
GimpSelectionOptions *options = GIMP_SELECTION_TOOL_GET_OPTIONS (tool);
GimpImage *image = gimp_display_get_image (display); GimpImage *image = gimp_display_get_image (display);
GimpLayer *layer = gimp_image_get_active_layer (image);
GeglBuffer *buffer;
GimpLayerMask *layer_mask;
GimpRGB color = { 0.0, 0.0, 0.0, GIMP_OPACITY_OPAQUE };
g_return_if_fail (fg_select->mask != NULL); g_return_if_fail (fg_select->mask != NULL);
gimp_channel_select_channel (gimp_image_get_mask (image), buffer = gimp_drawable_get_buffer (GIMP_DRAWABLE (fg_select->mask));
C_("command", "Foreground Select"),
fg_select->mask, 0, 0, layer_mask = gimp_layer_mask_new_from_buffer (buffer, image,
options->operation, "mask", &color);
options->feather,
options->feather_radius, gimp_layer_add_mask (layer, layer_mask, TRUE, NULL);
options->feather_radius);
gimp_tool_control (tool, GIMP_TOOL_ACTION_HALT, display); gimp_tool_control (tool, GIMP_TOOL_ACTION_HALT, display);
@ -773,16 +841,22 @@ gimp_foreground_select_tool_apply (GimpForegroundSelectTool *fg_select,
} }
static void static void
gimp_foreground_select_tool_stroke (GimpChannel *mask, gimp_foreground_select_tool_stroke_paint (GimpForegroundSelectTool *fg_select,
FgSelectStroke *stroke) GimpDisplay *display,
GimpForegroundSelectOptions *options)
{ {
GimpScanConvert *scan_convert = gimp_scan_convert_new (); GimpScanConvert *scan_convert;
gint width;
if (stroke->num_points == 1) g_return_if_fail (fg_select->stroke != NULL);
scan_convert = gimp_scan_convert_new ();
if (fg_select->stroke->len == 1)
{ {
GimpVector2 points[2]; GimpVector2 points[2];
points[0] = points[1] = stroke->points[0]; points[0] = points[1] = ((GimpVector2 *) fg_select->stroke->data)[0];
points[1].x += 0.01; points[1].x += 0.01;
points[1].y += 0.01; points[1].y += 0.01;
@ -792,111 +866,50 @@ gimp_foreground_select_tool_stroke (GimpChannel *mask,
else else
{ {
gimp_scan_convert_add_polyline (scan_convert, gimp_scan_convert_add_polyline (scan_convert,
stroke->num_points, stroke->points, fg_select->stroke->len,
(GimpVector2 *) fg_select->stroke->data,
FALSE); FALSE);
} }
width = ROUND ((gdouble) options->stroke_width);
gimp_scan_convert_stroke (scan_convert, gimp_scan_convert_stroke (scan_convert,
stroke->width, width,
GIMP_JOIN_ROUND, GIMP_CAP_ROUND, 10.0, GIMP_JOIN_ROUND, GIMP_CAP_ROUND, 10.0,
0.0, NULL); 0.0, NULL);
gimp_scan_convert_compose_value (scan_convert, gimp_scan_convert_compose_value (scan_convert,
gimp_drawable_get_buffer (GIMP_DRAWABLE (mask)), gimp_drawable_get_buffer (GIMP_DRAWABLE (fg_select->trimap)),
0, 0, stroke->background ? 0.0 : 1.0); 0, 0,
gimp_foreground_select_options_get_opacity (options));
gimp_scan_convert_free (scan_convert); gimp_scan_convert_free (scan_convert);
}
static void
gimp_foreground_select_tool_push_stroke (GimpForegroundSelectTool *fg_select,
GimpDisplay *display,
GimpForegroundSelectOptions *options)
{
GimpDisplayShell *shell = gimp_display_get_shell (display);
FgSelectStroke *stroke;
g_return_if_fail (fg_select->stroke != NULL);
stroke = g_slice_new (FgSelectStroke);
stroke->background = options->background;
stroke->width = ROUND ((gdouble) options->stroke_width / shell->scale_y);
stroke->num_points = fg_select->stroke->len;
stroke->points = (GimpVector2 *) g_array_free (fg_select->stroke, FALSE);
g_array_free (fg_select->stroke, TRUE);
fg_select->stroke = NULL; fg_select->stroke = NULL;
fg_select->strokes = g_list_append (fg_select->strokes, stroke);
fg_select->refinement |= (stroke->background ?
SIOX_REFINEMENT_ADD_BACKGROUND :
SIOX_REFINEMENT_ADD_FOREGROUND);
} }
static gboolean
gimp_foreground_select_tool_idle_select (GimpForegroundSelectTool *fg_select)
{
GimpTool *tool = GIMP_TOOL (fg_select);
fg_select->idle_id = 0;
if (tool->display)
gimp_free_select_tool_select (GIMP_FREE_SELECT_TOOL (tool), tool->display);
return FALSE;
}
/* To compress close notify signals, the process is delayed by */
#define MINIMUM_DELAY 300
static void static void
gimp_foreground_select_options_notify (GimpForegroundSelectOptions *options, gimp_foreground_select_options_notify (GimpForegroundSelectOptions *options,
GParamSpec *pspec, GParamSpec *pspec,
GimpForegroundSelectTool *fg_select) GimpForegroundSelectTool *fg_select)
{ {
SioxRefinementType refinement = 0;
if (! fg_select->mask)
return;
#if 0
if (strcmp (pspec->name, "smoothness") == 0)
{
refinement = SIOX_REFINEMENT_CHANGE_SMOOTHNESS;
}
else if (strcmp (pspec->name, "contiguous") == 0)
{
refinement = SIOX_REFINEMENT_CHANGE_MULTIBLOB;
}
else if (g_str_has_prefix (pspec->name, "sensitivity"))
{
refinement = SIOX_REFINEMENT_CHANGE_SENSITIVITY;
}
#endif
if (refinement && fg_select->strokes)
{
fg_select->refinement |= refinement;
if (fg_select->idle_id)
g_source_remove (fg_select->idle_id);
fg_select->idle_id =
g_timeout_add_full (G_PRIORITY_LOW, MINIMUM_DELAY,
(GSourceFunc) gimp_foreground_select_tool_idle_select,
fg_select, NULL);
}
if (g_str_has_prefix (pspec->name, "mask-color")) if (g_str_has_prefix (pspec->name, "mask-color"))
{ {
GimpTool *tool = GIMP_TOOL (fg_select); GimpTool *tool = GIMP_TOOL (fg_select);
if (tool->display && fg_select->mask) if (tool->display)
{ {
GimpRGB color; if (fg_select->state == MATTING_STATE_PAINT_TRIMAP)
{
gimp_foreground_select_tool_set_trimap (fg_select, tool->display);
}
gimp_foreground_select_options_get_mask_color (options, &color); if (fg_select->state == MATTING_STATE_PREVIEW_MASK)
gimp_display_shell_set_mask (gimp_display_get_shell (tool->display), {
GIMP_DRAWABLE (fg_select->mask), &color); gimp_foreground_select_tool_set_preview (fg_select, tool->display);
}
} }
} }
} }

View File

@ -22,13 +22,12 @@
#include "gimpfreeselecttool.h" #include "gimpfreeselecttool.h"
typedef enum /*< pdb-skip, skip >*/ typedef enum
{ {
SIOX_REFINEMENT_NO_CHANGE = 0, MATTING_STATE_FREE_SELECT = 0,
SIOX_REFINEMENT_ADD_FOREGROUND = (1 << 0), MATTING_STATE_PAINT_TRIMAP,
SIOX_REFINEMENT_ADD_BACKGROUND = (1 << 1), MATTING_STATE_PREVIEW_MASK,
SIOX_REFINEMENT_RECALCULATE = 0xFF } MattingState;
} SioxRefinementType;
#define GIMP_TYPE_FOREGROUND_SELECT_TOOL (gimp_foreground_select_tool_get_type ()) #define GIMP_TYPE_FOREGROUND_SELECT_TOOL (gimp_foreground_select_tool_get_type ())
@ -49,14 +48,10 @@ struct _GimpForegroundSelectTool
GimpFreeSelectTool parent_instance; GimpFreeSelectTool parent_instance;
GimpCoords last_coords; GimpCoords last_coords;
guint idle_id;
GArray *stroke; GArray *stroke;
GList *strokes; GimpChannel *trimap;
GimpChannel *mask; GimpChannel *mask;
#if 0 MattingState state;
SioxState *state;
#endif
SioxRefinementType refinement;
}; };
struct _GimpForegroundSelectToolClass struct _GimpForegroundSelectToolClass