Eine aufbereitete Darstellung der Quelle

 
     
 
 
Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 

Benutzer

Quelle  gimppaintselecttool.c   Sprache: C

 

/* GIMP - The GNU Image Manipulation Program
 * Copyright (C) 1995 Spencer Kimball and Peter Mattis
 *
 * GimpPaintSelectTool
 * Copyright (C) 2020  Thomas Manni <thomas.manni@free.fr>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */


#include "config.h"

#include <string.h>
#include <math.h>

#include <gegl.h>
#include <gtk/gtk.h>
#include <gdk/gdkkeysyms.h>


#include "libgimpmath/gimpmath.h"
#include "libgimpbase/gimpbase.h"
#include "libgimpcolor/gimpcolor.h"
#include "libgimpwidgets/gimpwidgets.h"

#include "tools-types.h"

#include "config/gimpguiconfig.h"

#include "gegl/gimp-gegl-loops.h"
#include "gegl/gimp-gegl-mask.h"
#include "gegl/gimp-gegl-utils.h"

#include "core/gimp.h"
#include "core/gimpchannel-select.h"
#include "core/gimperror.h"
#include "core/gimpimage.h"
#include "core/gimplayer.h"
#include "core/gimplayermask.h"
#include "core/gimpprogress.h"
#include "core/gimpscanconvert.h"

#include "widgets/gimphelp-ids.h"
#include "widgets/gimpwidgets-utils.h"

#include "display/gimpdisplay.h"
#include "display/gimpdisplayshell.h"
#include "display/gimpdisplayshell-scroll.h"
#include "display/gimptoolgui.h"

#include "core/gimptooloptions.h"
#include "gimppaintselecttool.h"
#include "gimppaintselectoptions.h"
#include "gimptoolcontrol.h"

#include "gimp-intl.h"

#include "config/gimpguiconfig.h" /* playground */


static void      gimp_paint_select_tool_control                     (GimpTool             *tool,
                                                                     GimpToolAction        action,
                                                                     GimpDisplay          *display);
static void      gimp_paint_select_tool_button_press                (GimpTool             *tool,
                                                                     const GimpCoords     *coords,
                                                                     guint32               time,
                                                                     GdkModifierType       state,
                                                                     GimpButtonPressType   press_type,
                                                                     GimpDisplay           *display);
static void      gimp_paint_select_tool_button_release              (GimpTool              *tool,
                                                                     const GimpCoords      *coords,
                                                                     guint32                time,
                                                                     GdkModifierType        state,
                                                                     GimpButtonReleaseType  release_type,
                                                                     GimpDisplay           *display);
static void      gimp_paint_select_tool_motion                      (GimpTool              *tool,
                                                                     const GimpCoords      *coords,
                                                                     guint32                time,
                                                                     GdkModifierType        state,
                                                                     GimpDisplay           *display);
static gboolean  gimp_paint_select_tool_key_press                   (GimpTool              *tool,
                                                                     GdkEventKey           *kevent,
                                                                     GimpDisplay           *display);
static void      gimp_paint_select_tool_modifier_key                (GimpTool              *tool,
                                                                     GdkModifierType        key,
                                                                     gboolean               press,
                                                                     GdkModifierType        state,
                                                                     GimpDisplay           *display);
static void      gimp_paint_select_tool_oper_update                 (GimpTool              *tool,
                                                                     const GimpCoords      *coords,
                                                                     GdkModifierType        state,
                                                                     gboolean               proximity,
                                                                     GimpDisplay           *display);
static void      gimp_paint_select_tool_options_notify              (GimpTool              *tool,
                                                                     GimpToolOptions       *options,
                                                                     const GParamSpec      *pspec);
static void      gimp_paint_select_tool_cursor_update               (GimpTool              *tool,
                                                                     const GimpCoords      *coords,
                                                                     GdkModifierType        state,
                                                                     GimpDisplay           *display);
static void      gimp_paint_select_tool_draw                        (GimpDrawTool          *draw_tool);

static void      gimp_paint_select_tool_progress                    (GeglNode              *ps_node,
                                                                     gdouble                value,
                                                                     GimpProgress          *progress);

static void      gimp_paint_select_tool_halt                        (GimpPaintSelectTool   *ps_tool);

static void      gimp_paint_select_tool_update_image_mask           (GimpPaintSelectTool   *ps_tool,
                                                                     GeglBuffer            *buffer,
                                                                     gint                   offset_x,
                                                                     gint                   offset_y);
static void      gimp_paint_select_tool_init_buffers                (GimpPaintSelectTool   *ps_tool,
                                                                     GimpImage             *image,
                                                                     GimpDrawable          *drawable);
static gboolean  gimp_paint_select_tool_can_paint                   (GimpPaintSelectTool   *ps_tool,
                                                                     GimpDisplay           *display,
                                                                     gboolean               show_message);
static gboolean  gimp_paint_select_tool_start                       (GimpPaintSelectTool   *ps_tool,
                                                                     GimpDisplay           *display);
static void      gimp_paint_select_tool_init_scribble               (GimpPaintSelectTool   *ps_tool);

static void      gimp_paint_select_tool_create_graph                (GimpPaintSelectTool   *ps_tool);

static gboolean  gimp_paint_select_tool_paint_scribble              (GimpPaintSelectTool   *ps_tool);

static void      gimp_paint_select_tool_toggle_scribbles_visibility (GimpPaintSelectTool   *ps_tool);

static GeglRectangle gimp_paint_select_tool_get_local_region        (GimpPaintSelectTool   *ps_tool,
                                                                     GimpDisplay           *display);

static gfloat    euclidean_distance                                 (gint                   x1,
                                                                     gint                   y1,
                                                                     gint                   x2,
                                                                     gint                   y2);


G_DEFINE_TYPE (GimpPaintSelectTool, gimp_paint_select_tool, GIMP_TYPE_DRAW_TOOL)

#define parent_class gimp_paint_select_tool_parent_class


void
gimp_paint_select_tool_register (GimpToolRegisterCallback  callback,
                                 gpointer                  data)
{
  if (gegl_has_operation ("gegl:paint-select") &&
      GIMP_GUI_CONFIG (GIMP (data)->config)->playground_paint_select_tool)
    (* callback) (GIMP_TYPE_PAINT_SELECT_TOOL,
                  GIMP_TYPE_PAINT_SELECT_OPTIONS,
                  gimp_paint_select_options_gui,
                  0,
                  "gimp-paint-select-tool",
                  _("Paint Select"),
                  _("Paint Select Tool: Select objects by painting roughly"),
                  N_("P_aint Select"), NULL,
                  NULL, GIMP_HELP_TOOL_FOREGROUND_SELECT,
                  GIMP_ICON_TOOL_PAINT_SELECT,
                  data);
}

static void
gimp_paint_select_tool_class_init (GimpPaintSelectToolClass *klass)
{
  GimpToolClass     *tool_class      = GIMP_TOOL_CLASS (klass);
  GimpDrawToolClass *draw_tool_class = GIMP_DRAW_TOOL_CLASS (klass);

  tool_class->button_press           = gimp_paint_select_tool_button_press;
  tool_class->button_release         = gimp_paint_select_tool_button_release;
  tool_class->control                = gimp_paint_select_tool_control;
  tool_class->cursor_update          = gimp_paint_select_tool_cursor_update;
  tool_class->key_press              = gimp_paint_select_tool_key_press;
  tool_class->modifier_key           = gimp_paint_select_tool_modifier_key;
  tool_class->motion                 = gimp_paint_select_tool_motion;
  tool_class->oper_update            = gimp_paint_select_tool_oper_update;
  tool_class->options_notify         = gimp_paint_select_tool_options_notify;

  draw_tool_class->draw              = gimp_paint_select_tool_draw;
}

static void
gimp_paint_select_tool_init (GimpPaintSelectTool *ps_tool)
{
  GimpTool *tool = GIMP_TOOL (ps_tool);

  gimp_tool_control_set_motion_mode       (tool->control, GIMP_MOTION_MODE_EXACT);
  gimp_tool_control_set_scroll_lock       (tool->control, FALSE);
  gimp_tool_control_set_preserve          (tool->control, FALSE);
  gimp_tool_control_set_dirty_mask        (tool->control,
                                           GIMP_DIRTY_IMAGE           |
                                           GIMP_DIRTY_ACTIVE_DRAWABLE);
  gimp_tool_control_set_dirty_action      (tool->control,
                                           GIMP_TOOL_ACTION_HALT);
  gimp_tool_control_set_precision         (tool->control,
                                           GIMP_CURSOR_PRECISION_SUBPIXEL);
  gimp_tool_control_set_tool_cursor       (tool->control,
                                           GIMP_TOOL_CURSOR_PAINTBRUSH);
  gimp_tool_control_set_cursor_modifier   (tool->control,
                                           GIMP_CURSOR_MODIFIER_PLUS);
  gimp_tool_control_set_action_pixel_size (tool->control,
                                           "tools-paint-select-pixel-size-set");
  /* TODO: the size-set action is not implemented. */
  gimp_tool_control_set_action_size       (tool->control,
                                           "tools-paint-select-size-set");
  ps_tool->image_mask  = NULL;
  ps_tool->trimap      = NULL;
  ps_tool->drawable    = NULL;
  ps_tool->scribble    = NULL;
  ps_tool->graph       = NULL;
  ps_tool->ps_node     = NULL;
  ps_tool->render_node = NULL;
}

static void
gimp_paint_select_tool_button_press (GimpTool            *tool,
                                     const GimpCoords    *coords,
                                     guint32              time,
                                     GdkModifierType      state,
                                     GimpButtonPressType  press_type,
                                     GimpDisplay         *display)
{
  GimpPaintSelectTool    *ps_tool = GIMP_PAINT_SELECT_TOOL (tool);
  GimpPaintSelectOptions *options = GIMP_PAINT_SELECT_TOOL_GET_OPTIONS (ps_tool);
  GeglColor              *grey    = gegl_color_new ("#888");

  if (tool->display && display != tool->display)
     gimp_tool_control (tool, GIMP_TOOL_ACTION_HALT, tool->display);

  if (! tool->display)
    {
      if (! gimp_paint_select_tool_start (ps_tool, display))
        return;
    }

  g_return_if_fail (g_list_length (tool->drawables) == 1);

  ps_tool->last_pos.x = coords->x;
  ps_tool->last_pos.y = coords->y;

  /* Always reset the "scribbles" to start with a blank slate. */
  gegl_buffer_set_color (ps_tool->trimap, NULL, grey);

  if (options->operation == GIMP_CHANNEL_OP_ADD)
    {
      gegl_node_set (ps_tool->ps_node, "mode", 0, NULL);
      gegl_node_set (ps_tool->threshold_node, "value", 0.99, NULL);
    }
  else
    {
      gegl_node_set (ps_tool->ps_node, "mode", 1, NULL);
      gegl_node_set (ps_tool->threshold_node, "value", 0.01, NULL);
    }
  ps_tool->painting_op = options->operation;

  ps_tool->process = gimp_paint_select_tool_paint_scribble (ps_tool);

  gimp_tool_control_activate (tool->control);

  g_object_unref (grey);
}

static void
gimp_paint_select_tool_button_release (GimpTool              *tool,
                                       const GimpCoords      *coords,
                                       guint32                time,
                                       GdkModifierType        state,
                                       GimpButtonReleaseType  release_type,
                                       GimpDisplay           *display)
{
  GimpPaintSelectTool *ps_tool   = GIMP_PAINT_SELECT_TOOL (tool);
  GimpDrawTool        *draw_tool = GIMP_DRAW_TOOL (tool);

  gimp_draw_tool_pause (draw_tool);
  gimp_tool_control_halt (tool->control);

  if (ps_tool->process)
    {
      GTimer        *timer = g_timer_new ();
      GimpProgress  *progress;
      GeglBuffer    *result;
      GeglRectangle  local_region;

      progress = gimp_progress_start (GIMP_PROGRESS (tool), FALSE,
                                      "%s", "Selecting");

      while (g_main_context_pending (NULL))
        g_main_context_iteration (NULL, FALSE);

      local_region = gimp_paint_select_tool_get_local_region (ps_tool, display);

      if (local_region.width < ps_tool->drawable_width ||
          local_region.height < ps_tool->drawable_height)
        {
          gegl_node_set (ps_tool->ps_node,
                         "use_local_region", TRUE,
                         "region_x",         local_region.x,
                         "region_y",         local_region.y,
                         "region_width",     local_region.width,
                         "region_height",    local_region.height,
                         NULL);
        }
      else
        {
          gegl_node_set (ps_tool->ps_node,
                         "use_local_region", FALSE, NULL);
        }

      gegl_node_set (ps_tool->render_node, "buffer", &result, NULL);
      g_signal_connect (ps_tool->ps_node, "progress",
                        G_CALLBACK (gimp_paint_select_tool_progress),
                        ps_tool);
      gegl_node_process (ps_tool->render_node);
      g_signal_handlers_disconnect_by_func (ps_tool->ps_node,
                                            G_CALLBACK (gimp_paint_select_tool_progress),
                                            ps_tool);

      g_timer_stop (timer);
      g_printerr ("processing graph takes %.3f s\n\n", g_timer_elapsed (timer, NULL));
      g_timer_destroy (timer);

      gimp_paint_select_tool_update_image_mask (ps_tool,
                                                result,
                                                ps_tool->drawable_off_x,
                                                ps_tool->drawable_off_y);
      if (progress)
        gimp_progress_end (progress);
      g_object_unref (result);
    }

  gimp_draw_tool_resume (draw_tool);
}

static void
gimp_paint_select_tool_control (GimpTool       *tool,
                                GimpToolAction  action,
                                GimpDisplay    *display)
{
  GimpPaintSelectTool *paint_select = GIMP_PAINT_SELECT_TOOL (tool);

  switch (action)
    {
    case GIMP_TOOL_ACTION_PAUSE:
      break;

    case GIMP_TOOL_ACTION_RESUME:
      break;

    case GIMP_TOOL_ACTION_HALT:
      gimp_paint_select_tool_halt (paint_select);
      break;

    case GIMP_TOOL_ACTION_COMMIT:
      break;
    }

  GIMP_TOOL_CLASS (parent_class)->control (tool, action, display);
}

static void
gimp_paint_select_tool_cursor_update (GimpTool         *tool,
                                      const GimpCoords *coords,
                                      GdkModifierType   state,
                                      GimpDisplay      *display)
{
  GimpPaintSelectOptions *options  = GIMP_PAINT_SELECT_TOOL_GET_OPTIONS (tool);
  GimpCursorModifier      modifier = GIMP_CURSOR_MODIFIER_NONE;

  if (options->operation == GIMP_CHANNEL_OP_ADD)
    {
      modifier = GIMP_CURSOR_MODIFIER_PLUS;
    }
  else
    {
      modifier = GIMP_CURSOR_MODIFIER_MINUS;
    }

  gimp_tool_control_set_cursor_modifier (tool->control, modifier);

  GIMP_TOOL_CLASS (parent_class)->cursor_update (tool, coords, state, display);
}

static gboolean
gimp_paint_select_tool_can_paint (GimpPaintSelectTool *ps_tool,
                                  GimpDisplay         *display,
                                  gboolean             show_message)
{
  GimpTool      *tool      = GIMP_TOOL (ps_tool);
  GimpGuiConfig *config    = GIMP_GUI_CONFIG (display->gimp->config);
  GimpImage     *image     = gimp_display_get_image (display);
  GList         *drawables = gimp_image_get_selected_drawables (image);
  GimpDrawable  *drawable;

  if (g_list_length (drawables) != 1)
    {
      if (show_message)
        {
          if (g_list_length (drawables) > 1)
            gimp_tool_message_literal (tool, display,
                                       _("Cannot paint select on multiple layers. Select only one layer."));
          else
            gimp_tool_message_literal (tool, display,
                                       _("No active drawables."));
        }

      g_list_free (drawables);

      return FALSE;
    }

  drawable = drawables->data;
  g_list_free (drawables);

  if (gimp_viewable_get_children (GIMP_VIEWABLE (drawable)))
    {
      if (show_message)
        {
          gimp_tool_message_literal (tool, display,
                                     _("Cannot paint select on layer groups."));
        }

      return FALSE;
    }

  if (! gimp_item_is_visible (GIMP_ITEM (drawable)) &&
      ! config->edit_non_visible)
    {
      if (show_message)
        {
          gimp_tool_message_literal (tool, display,
                                     _("The active layer is not visible."));
        }

      return FALSE;
    }

  return TRUE;
}

static gboolean
gimp_paint_select_tool_start (GimpPaintSelectTool *ps_tool,
                              GimpDisplay         *display)
{
  GimpTool     *tool  = GIMP_TOOL (ps_tool);
  GimpImage    *image = gimp_display_get_image (display);
  GimpDrawable *drawable;

  if (! gimp_paint_select_tool_can_paint (ps_tool, display, TRUE))
    return FALSE;

  tool->display   = display;
  g_list_free (tool->drawables);
  tool->drawables = gimp_image_get_selected_drawables (image);

  drawable = tool->drawables->data;

  gimp_paint_select_tool_init_buffers (ps_tool, image, drawable);
  gimp_paint_select_tool_create_graph (ps_tool);

  if (! gimp_draw_tool_is_active (GIMP_DRAW_TOOL (ps_tool)))
    gimp_draw_tool_start (GIMP_DRAW_TOOL (ps_tool), display);

  return TRUE;
}

static gboolean
gimp_paint_select_tool_key_press (GimpTool    *tool,
                                  GdkEventKey *kevent,
                                  GimpDisplay *display)
{
  return GIMP_TOOL_CLASS (parent_class)->key_press (tool, kevent, display);
}

/* Based on gimp_selection_tool_modifier_key () */
static void
gimp_paint_select_tool_modifier_key (GimpTool        *tool,
                                     GdkModifierType  key,
                                     gboolean         press,
                                     GdkModifierType  state,
                                     GimpDisplay     *display)
{
  GimpPaintSelectTool    *ps_tool = GIMP_PAINT_SELECT_TOOL (tool);
  GimpPaintSelectOptions *options = GIMP_PAINT_SELECT_TOOL_GET_OPTIONS (ps_tool);
  GdkModifierType         extend_mask;
  GdkModifierType         modify_mask;

  extend_mask = gimp_get_extend_selection_mask ();
  modify_mask = gimp_get_modify_selection_mask ();

  if (key == extend_mask ||
      key == modify_mask ||
      key == GDK_MOD1_MASK)
    {
      GimpChannelOps button_op = options->operation;

      state &= extend_mask | modify_mask | GDK_MOD1_MASK;

      if (press)
        {
          if (key == state || ! state)
            ps_tool->saved_op = options->operation;
        }
      else
        {
          if (! state)
            button_op = ps_tool->saved_op;
        }

      if (state & GDK_MOD1_MASK)
        {
          button_op = ps_tool->saved_op;
        }
      else if (state & (extend_mask | modify_mask))
        {
          GimpChannelOps op = gimp_modifiers_to_channel_op (state);

          switch (op)
            {
            case GIMP_CHANNEL_OP_ADD:
              button_op = GIMP_CHANNEL_OP_ADD;
              break;

            case GIMP_CHANNEL_OP_SUBTRACT:
              button_op = GIMP_CHANNEL_OP_SUBTRACT;
              break;

            default:
              break;
            }
        }

      if (button_op != options->operation)
        g_object_set (options, "operation", button_op, NULL);
    }
}

static void
gimp_paint_select_tool_motion (GimpTool         *tool,
                               const GimpCoords *coords,
                               guint32           time,
                               GdkModifierType   state,
                               GimpDisplay      *display)
{
  GimpPaintSelectTool *ps_tool = GIMP_PAINT_SELECT_TOOL (tool);

  GIMP_TOOL_CLASS (parent_class)->motion (tool, coords, time, state, display);

  if (state & GDK_BUTTON1_MASK)
    {
      gfloat distance = euclidean_distance (coords->x,
                                            coords->y,
                                            ps_tool->last_pos.x,
                                            ps_tool->last_pos.y);

      if (distance >= 2.f)
        {
          gimp_draw_tool_pause (GIMP_DRAW_TOOL (tool));
          ps_tool->last_pos.x = coords->x;
          ps_tool->last_pos.y = coords->y;

          ps_tool->process |= gimp_paint_select_tool_paint_scribble (ps_tool);
          gimp_draw_tool_resume (GIMP_DRAW_TOOL (tool));
        }
    }
}

static void
gimp_paint_select_tool_oper_update (GimpTool         *tool,
                                    const GimpCoords *coords,
                                    GdkModifierType   state,
                                    gboolean          proximity,
                                    GimpDisplay      *display)
{
  GimpPaintSelectTool *ps        = GIMP_PAINT_SELECT_TOOL (tool);
  GimpDrawTool        *draw_tool = GIMP_DRAW_TOOL (tool);

  if (proximity)
    {
      gimp_draw_tool_pause (draw_tool);

      if (! tool->display || display == tool->display)
        {
          ps->last_pos.x = coords->x;
          ps->last_pos.y = coords->y;
        }

      if (! gimp_draw_tool_is_active (draw_tool))
        gimp_draw_tool_start (draw_tool, display);

      gimp_draw_tool_resume (draw_tool);
    }
  else if (gimp_draw_tool_is_active (draw_tool))
    {
      gimp_draw_tool_stop (draw_tool);
    }
}

static void
gimp_paint_select_tool_draw (GimpDrawTool *draw_tool)
{
  GimpPaintSelectTool    *paint_select = GIMP_PAINT_SELECT_TOOL (draw_tool);
  GimpPaintSelectOptions *options      = GIMP_PAINT_SELECT_TOOL_GET_OPTIONS (paint_select);
  gint                    size         = options->stroke_width;

  gimp_draw_tool_add_arc (draw_tool,
                          FALSE,
                          paint_select->last_pos.x - (size / 2.0),
                          paint_select->last_pos.y - (size / 2.0),
                          size, size,
                          0.0, (2.0 * G_PI));
}

static void
gimp_paint_select_tool_options_notify (GimpTool         *tool,
                                       GimpToolOptions  *options,
                                       const GParamSpec *pspec)
{
  GimpPaintSelectTool *ps_tool = GIMP_PAINT_SELECT_TOOL (tool);

  if (g_strcmp0 (pspec->name, "stroke-width") == 0)
    {
      /* This triggers a redraw of the tool pointer, especially useful
       * here when we change the pen size with on-canvas interaction.
       */

      gimp_draw_tool_pause (GIMP_DRAW_TOOL (tool));
      gimp_draw_tool_resume (GIMP_DRAW_TOOL (tool));
    }

  if (! tool->display)
    return;

  if (! strcmp (pspec->name, "stroke-width") && ps_tool->scribble)
    {
      g_object_unref (ps_tool->scribble);
      ps_tool->scribble = NULL;
    }
  else if (! strcmp (pspec->name, "show-scribbles"))
    {
      gimp_paint_select_tool_toggle_scribbles_visibility (ps_tool);
    }
}

static void
gimp_paint_select_tool_progress (GeglNode     *ps_node,
                                 gdouble       value,
                                 GimpProgress *progress)
{
  gimp_progress_set_value (progress, value);
  while (g_main_context_pending (NULL))
    g_main_context_iteration (NULL, FALSE);
}

static void
gimp_paint_select_tool_halt (GimpPaintSelectTool *ps_tool)
{
  GimpTool *tool = GIMP_TOOL (ps_tool);

  g_clear_object (&ps_tool->trimap);
  g_clear_object (&ps_tool->graph);
  g_clear_object (&ps_tool->scribble);

  ps_tool->drawable    = NULL;
  ps_tool->render_node = NULL;
  ps_tool->ps_node     = NULL;

  ps_tool->image_mask  = NULL;

  if (tool->display)
    {
      gimp_display_shell_set_mask (gimp_display_get_shell (tool->display),
                                   NULL, 0, 0, NULL, FALSE);
      gimp_image_flush (gimp_display_get_image (tool->display));
    }

  tool->display   = NULL;
  g_list_free (tool->drawables);
  tool->drawables = NULL;
}

static void
gimp_paint_select_tool_update_image_mask (GimpPaintSelectTool *ps_tool,
                                          GeglBuffer          *buffer,
                                          gint                 offset_x,
                                          gint                 offset_y)
{
  GimpTool *tool = GIMP_TOOL (ps_tool);

  if (tool->display)
    {
      GimpImage *image = gimp_display_get_image (tool->display);

      gimp_channel_select_buffer (gimp_image_get_mask (image),
                                  C_("command", "Paint Select"),
                                  buffer,
                                  offset_x,
                                  offset_y,
                                  ps_tool->painting_op,
                                  FALSE,
                                  0,
                                  0);
      gimp_image_flush (image);
    }
}

static void
gimp_paint_select_tool_init_buffers (GimpPaintSelectTool *ps_tool,
                                     GimpImage           *image,
                                     GimpDrawable        *drawable)
{
  GimpChannel *channel;
  GeglColor   *grey = gegl_color_new ("#888");

  g_return_if_fail (ps_tool->trimap == NULL);
  g_return_if_fail (ps_tool->drawable == NULL);

  gimp_item_get_offset (GIMP_ITEM (drawable),
                        &ps_tool->drawable_off_x,
                        &ps_tool->drawable_off_y);
  ps_tool->drawable_width  = gimp_item_get_width (GIMP_ITEM (drawable));
  ps_tool->drawable_height = gimp_item_get_height (GIMP_ITEM (drawable));

  ps_tool->drawable = gimp_drawable_get_buffer (drawable);

  channel = gimp_image_get_mask (image);
  ps_tool->image_mask = gimp_drawable_get_buffer (GIMP_DRAWABLE (channel));
  ps_tool->trimap = gegl_buffer_new (gegl_buffer_get_extent (ps_tool->drawable),
                                     babl_format ("Y float"));
  gegl_buffer_set_color (ps_tool->trimap, NULL, grey);

  g_object_unref (grey);
}

static void
gimp_paint_select_tool_init_scribble (GimpPaintSelectTool *ps_tool)
{
  GimpPaintSelectOptions *options = GIMP_PAINT_SELECT_TOOL_GET_OPTIONS (ps_tool);
  GimpScanConvert        *scan_convert;
  GimpVector2             points[2];
  gint                    size   = options->stroke_width;
  gint                    radius = size / 2;
  GeglRectangle           square = {0, 0, size, size};

  if (ps_tool->scribble)
    g_object_unref (ps_tool->scribble);

  ps_tool->scribble = gegl_buffer_linear_new (&square, babl_format ("Y float"));

  points[0].x = points[1].x = radius;
  points[0].y = points[1].y = radius;
  points[1].x += 0.01;
  points[1].y += 0.01;

  scan_convert = gimp_scan_convert_new ();
  gimp_scan_convert_add_polyline (scan_convert, 2, points, FALSE);
  gimp_scan_convert_stroke (scan_convert, size,
                            GIMP_JOIN_ROUND, GIMP_CAP_ROUND, 10.0,
                            0.0, NULL);
  gimp_scan_convert_compose (scan_convert, ps_tool->scribble, 0, 0);
  gimp_scan_convert_free (scan_convert);
}

static gboolean
gimp_paint_select_tool_paint_scribble (GimpPaintSelectTool *ps_tool)
{
  GimpPaintSelectOptions *options = GIMP_PAINT_SELECT_TOOL_GET_OPTIONS (ps_tool);
  gint                    size    = options->stroke_width;
  gint                    radius  = size / 2;
  GeglRectangle           trimap_area;
  GeglRectangle           mask_area;
  GeglBufferIterator     *iter;
  gfloat                  scribble_value;
  gboolean                overlap = FALSE;

  if (! ps_tool->scribble)
    {
      gimp_paint_select_tool_init_scribble (ps_tool);
    }

  /* add the scribble to the trimap buffer and check the image mask to see if
     an optimization should be triggered.
   */


  if (ps_tool->painting_op == GIMP_CHANNEL_OP_ADD)
    {
      scribble_value = 1.f;
    }
  else
    {
      scribble_value = 0.f;
    }

  iter = gegl_buffer_iterator_new (ps_tool->scribble, NULL, 0,
                                   babl_format ("Y float"),
                                   GEGL_ACCESS_READ, GEGL_ABYSS_NONE, 3);

  mask_area   = *gegl_buffer_get_extent (ps_tool->scribble);
  mask_area.x = ps_tool->last_pos.x - radius;
  mask_area.y = ps_tool->last_pos.y - radius;

  gegl_rectangle_copy (&trimap_area, &mask_area);

  trimap_area.x = mask_area.x - ps_tool->drawable_off_x;
  trimap_area.y = mask_area.y - ps_tool->drawable_off_y;

  gegl_buffer_iterator_add (iter, ps_tool->trimap, &trimap_area, 0,
                            babl_format ("Y float"),
                            GEGL_ACCESS_READWRITE, GEGL_ABYSS_NONE);

  gegl_buffer_iterator_add (iter, ps_tool->image_mask, &mask_area, 0,
                            babl_format ("Y float"),
                            GEGL_ACCESS_READ, GEGL_ABYSS_NONE);

  while (gegl_buffer_iterator_next (iter))
    {
      gfloat  *scribble_pix = iter->items[0].data;
      gfloat  *trimap_pix   = iter->items[1].data;
      gfloat  *mask_pix     = iter->items[2].data;
      gint     n_pixels     = iter->length;

      while (n_pixels--)
        {
          if (*scribble_pix)
            {
              *trimap_pix = scribble_value;

              if (*mask_pix != scribble_value)
                overlap = TRUE;
            }

          scribble_pix++;
          trimap_pix++;
          mask_pix++;
        }
    }

  gimp_paint_select_tool_toggle_scribbles_visibility (ps_tool);

  return overlap;
}

static void
gimp_paint_select_tool_create_graph (GimpPaintSelectTool  *ps_tool)
{
  GeglNode *t;         /* trimap */
  GeglNode *m;         /* mask   */
  GeglNode *d;         /* drawable */
  GeglNode *crop;
  GeglNode *translate = NULL;

  ps_tool->graph = gegl_node_new ();

  m = gegl_node_new_child (ps_tool->graph,
                           "operation", "gegl:buffer-source",
                           "buffer", ps_tool->image_mask,
                           NULL);

  crop = gegl_node_new_child (ps_tool->graph,
                              "operation", "gegl:crop",
                              "x", (gdouble) ps_tool->drawable_off_x,
                              "y", (gdouble) ps_tool->drawable_off_y,
                              "width", (gdouble) gegl_buffer_get_width (ps_tool->drawable),
                              "height", (gdouble) gegl_buffer_get_height (ps_tool->drawable),
                              NULL);

  ps_tool->threshold_node = gegl_node_new_child (ps_tool->graph,
                                                 "operation", "gegl:threshold",
                                                 NULL);

  if (ps_tool->drawable_off_x || ps_tool->drawable_off_y)
    {
      translate = gegl_node_new_child (ps_tool->graph,
                                       "operation", "gegl:translate",
                                       "x", -1.0 * ps_tool->drawable_off_x,
                                       "y", -1.0 * ps_tool->drawable_off_y,
                                       NULL);
    }

  d = gegl_node_new_child (ps_tool->graph,
                           "operation", "gegl:buffer-source",
                           "buffer", ps_tool->drawable,
                           NULL);


  t = gegl_node_new_child (ps_tool->graph,
                           "operation", "gegl:buffer-source",
                           "buffer", ps_tool->trimap,
                           NULL);

  ps_tool->ps_node = gegl_node_new_child (ps_tool->graph,
                            "operation", "gegl:paint-select",
                            NULL);

  ps_tool->render_node = gegl_node_new_child (ps_tool->graph,
                                            "operation", "gegl:buffer-sink",
                                             NULL);

  gegl_node_link_many (m, ps_tool->threshold_node, crop, NULL);

  if (translate)
    gegl_node_link_many (crop, translate, ps_tool->ps_node, ps_tool->render_node, NULL);
  else
    gegl_node_link_many (crop, ps_tool->ps_node, ps_tool->render_node, NULL);

  gegl_node_connect (d, "output", ps_tool->ps_node, "aux");
  gegl_node_connect (t, "output", ps_tool->ps_node, "aux2");
}

static void
gimp_paint_select_tool_toggle_scribbles_visibility (GimpPaintSelectTool *ps_tool)
{
  GimpTool               *tool    = GIMP_TOOL (ps_tool);
  GimpPaintSelectOptions *options = GIMP_PAINT_SELECT_TOOL_GET_OPTIONS (tool);

  if (options->show_scribbles)
    {
      GeglColor *black = gegl_color_new ("black");

      gimp_display_shell_set_mask (gimp_display_get_shell (tool->display),
                                   ps_tool->trimap,
                                   ps_tool->drawable_off_x,
                                   ps_tool->drawable_off_y,
                                   black,
                                   TRUE);
      g_object_unref (black);
    }
  else
    {
      gimp_display_shell_set_mask (gimp_display_get_shell (tool->display),
                                   NULL, 0, 0, NULL, FALSE);
    }
}

static GeglRectangle
gimp_paint_select_tool_get_local_region (GimpPaintSelectTool *ps_tool,
                                         GimpDisplay         *display)
{
  GimpPaintSelectOptions *options = GIMP_PAINT_SELECT_TOOL_GET_OPTIONS (ps_tool);
  GimpDisplayShell       *shell;
  GeglRectangle           drawable_region;
  GeglRectangle           viewport;
  GeglRectangle           local_region;
  gdouble                 x, y, w, h;
  gint                    radius = ceil (options->stroke_width / 2.0);

  shell = gimp_display_get_shell (display);
  gimp_display_shell_scroll_get_viewport (shell, &x, &y, &w, &h);

  viewport.x             = (gint) x - radius;
  viewport.y             = (gint) y - radius;
  viewport.width         = (gint) w + options->stroke_width;
  viewport.height        = (gint) h + options->stroke_width;

  drawable_region.x      = ps_tool->drawable_off_x;
  drawable_region.y      = ps_tool->drawable_off_y;
  drawable_region.width  = ps_tool->drawable_width;
  drawable_region.height = ps_tool->drawable_height;

  gegl_rectangle_intersect (&local_region, &viewport, &drawable_region);

  local_region.x -= ps_tool->drawable_off_x;
  local_region.y -= ps_tool->drawable_off_y;

  g_printerr ("local region: (%d,%d) %d x %d\n",
              local_region.x, local_region.y,
              local_region.width, local_region.height);

  return local_region;
}

static gfloat
euclidean_distance (gint x1,
                    gint y1,
                    gint x2,
                    gint y2)
{
  return sqrtf ((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2));
}

Messung
CHZG
839610093

¤ Dauer der Verarbeitung: 0.13 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover


Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Open Source Software

     Quellcodebibliothek
     Eigene Quellcodes
     Fremde Quellcodes
     Suchen

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Statistik
#Sources=1104848
#Domains=416964