Example #1
0
static GimpValueArray *
selection_is_empty_invoker (GimpProcedure         *procedure,
                            Gimp                  *gimp,
                            GimpContext           *context,
                            GimpProgress          *progress,
                            const GimpValueArray  *args,
                            GError               **error)
{
  gboolean success = TRUE;
  GimpValueArray *return_vals;
  GimpImage *image;
  gboolean is_empty = FALSE;

  image = gimp_value_get_image (gimp_value_array_index (args, 0), gimp);

  if (success)
    {
      is_empty = gimp_channel_is_empty (gimp_image_get_mask (image));
    }

  return_vals = gimp_procedure_get_return_values (procedure, success,
                                                  error ? *error : NULL);

  if (success)
    g_value_set_boolean (gimp_value_array_index (return_vals, 1), is_empty);

  return return_vals;
}
Example #2
0
GimpTransformResize
gimp_drawable_transform_get_effective_clip (GimpDrawable        *drawable,
                                            GeglBuffer          *orig_buffer,
                                            GimpTransformResize  clip_result)
{
  g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), clip_result);
  g_return_val_if_fail (gimp_item_is_attached (GIMP_ITEM (drawable)),
                                               clip_result);
  g_return_val_if_fail (orig_buffer == NULL || GEGL_IS_BUFFER (orig_buffer),
                        clip_result);

  /*  Always clip unfloated buffers since they must keep their size  */
  if (GIMP_IS_CHANNEL (drawable))
    {
      if (orig_buffer)
        {
          if (! babl_format_has_alpha (gegl_buffer_get_format (orig_buffer)))
            clip_result = GIMP_TRANSFORM_RESIZE_CLIP;
        }
      else
        {
          GimpImage *image = gimp_item_get_image (GIMP_ITEM (drawable));

          if (gimp_channel_is_empty (gimp_image_get_mask (image)))
            clip_result = GIMP_TRANSFORM_RESIZE_CLIP;
        }
    }

  return clip_result;
}
Example #3
0
static GimpValueArray *
flip_invoker (GimpProcedure         *procedure,
              Gimp                  *gimp,
              GimpContext           *context,
              GimpProgress          *progress,
              const GimpValueArray  *args,
              GError               **error)
{
  gboolean success = TRUE;
  GimpValueArray *return_vals;
  GimpDrawable *drawable;
  gint32 flip_type;

  drawable = gimp_value_get_drawable (gimp_value_array_index (args, 0), gimp);
  flip_type = g_value_get_enum (gimp_value_array_index (args, 1));

  if (success)
    {
      gint x, y, width, height;

      success = gimp_pdb_item_is_attached (GIMP_ITEM (drawable), NULL, TRUE, error);

      if (success &&
          gimp_item_mask_intersect (GIMP_ITEM (drawable), &x, &y, &width, &height))
        {
          gdouble axis;

          gimp_transform_get_flip_axis (x, y, width, height,
                                        flip_type, TRUE, &axis);

          if (! gimp_viewable_get_children (GIMP_VIEWABLE (drawable)) &&
              ! gimp_channel_is_empty (gimp_image_get_mask (gimp_item_get_image (GIMP_ITEM (drawable)))))
            {
              if (! gimp_drawable_transform_flip (drawable, context,
                                                  flip_type, axis, FALSE))
                {
                  success = FALSE;
                }
            }
          else
            {
              gimp_item_flip (GIMP_ITEM (drawable), context,
                              flip_type, axis, FALSE);
            }
        }
    }

  return_vals = gimp_procedure_get_return_values (procedure, success,
                                                  error ? *error : NULL);

  if (success)
    gimp_value_set_drawable (gimp_value_array_index (return_vals, 1), drawable);

  return return_vals;
}
Example #4
0
GimpObject *
gimp_edit_cut (GimpImage     *image,
               GimpDrawable  *drawable,
               GimpContext   *context,
               GError       **error)
{
  g_return_val_if_fail (GIMP_IS_IMAGE (image), NULL);
  g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), NULL);
  g_return_val_if_fail (gimp_item_is_attached (GIMP_ITEM (drawable)), NULL);
  g_return_val_if_fail (GIMP_IS_CONTEXT (context), NULL);
  g_return_val_if_fail (error == NULL || *error == NULL, NULL);

  if (GIMP_IS_LAYER (drawable) &&
      gimp_channel_is_empty (gimp_image_get_mask (image)))
    {
      GimpImage *clip_image;

      clip_image = gimp_image_new_from_drawable (image->gimp, drawable);
      gimp_container_remove (image->gimp->images, GIMP_OBJECT (clip_image));
      gimp_set_clipboard_image (image->gimp, clip_image);
      g_object_unref (clip_image);

      gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_EDIT_CUT,
                                   C_("undo-type", "Cut Layer"));

      gimp_image_remove_layer (image, GIMP_LAYER (drawable),
                               TRUE, NULL);

      gimp_image_undo_group_end (image);

      return GIMP_OBJECT (gimp_get_clipboard_image (image->gimp));
    }
  else
    {
      GimpBuffer *buffer;

      buffer = gimp_edit_extract (image, GIMP_PICKABLE (drawable),
                                  context, TRUE, error);

      if (buffer)
        {
          gimp_set_clipboard_buffer (image->gimp, buffer);
          g_object_unref (buffer);

          return GIMP_OBJECT (gimp_get_clipboard_buffer (image->gimp));
        }
    }

  return NULL;
}
Example #5
0
static gboolean
gimp_drawable_edit_can_fill_direct (GimpDrawable    *drawable,
                                    GimpFillOptions *options)
{
  GimpImage                *image;
  GimpContext              *context;
  gdouble                   opacity;
  GimpComponentMask         affect;
  GimpLayerMode             mode;
  GimpLayerCompositeMode    composite_mode;
  GimpLayerCompositeRegion  composite_region;

  image            = gimp_item_get_image (GIMP_ITEM (drawable));
  context          = GIMP_CONTEXT (options);
  opacity          = gimp_context_get_opacity (context);
  affect           = gimp_drawable_get_active_mask (drawable);
  mode             = gimp_context_get_paint_mode (context);
  composite_mode   = gimp_layer_mode_get_paint_composite_mode (mode);
  composite_region = gimp_layer_mode_get_included_region (mode, composite_mode);

  if (gimp_channel_is_empty (gimp_image_get_mask (image)) &&
      opacity == GIMP_OPACITY_OPAQUE                      &&
      affect  == GIMP_COMPONENT_MASK_ALL                  &&
      gimp_layer_mode_is_trivial (mode)                   &&
      (! gimp_layer_mode_is_subtractive (mode)            ^
       ! (composite_region & GIMP_LAYER_COMPOSITE_REGION_SOURCE)))
    {
      switch (gimp_fill_options_get_style (options))
        {
        case GIMP_FILL_STYLE_SOLID:
          return TRUE;

        case GIMP_FILL_STYLE_PATTERN:
          {
            GimpPattern *pattern;
            GimpTempBuf *mask;
            const Babl  *format;

            pattern = gimp_context_get_pattern (context);
            mask    = gimp_pattern_get_mask (pattern);
            format  = gimp_temp_buf_get_format (mask);

            return ! babl_format_has_alpha (format);
          }
        }
    }

  return FALSE;
}
Example #6
0
void
select_actions_update (GimpActionGroup *group,
                       gpointer         data)
{
  GimpImage    *image    = action_data_get_image (data);
  GimpDrawable *drawable = NULL;
  gboolean      fs       = FALSE;
  gboolean      sel      = FALSE;
  gboolean      writable = FALSE;
  gboolean      children = FALSE;

  if (image)
    {
      drawable = gimp_image_get_active_drawable (image);

      if (drawable)
        {
          writable = ! gimp_item_is_content_locked (GIMP_ITEM (drawable));

          if (gimp_viewable_get_children (GIMP_VIEWABLE (drawable)))
            children = TRUE;
        }

      fs  = (gimp_image_get_floating_selection (image) != NULL);
      sel = ! gimp_channel_is_empty (gimp_image_get_mask (image));
    }

#define SET_SENSITIVE(action,condition) \
        gimp_action_group_set_action_sensitive (group, action, (condition) != 0)

  SET_SENSITIVE ("select-all",    drawable);
  SET_SENSITIVE ("select-none",   drawable && sel);
  SET_SENSITIVE ("select-invert", drawable);
  SET_SENSITIVE ("select-float",  writable && !children && sel);

  SET_SENSITIVE ("select-feather", drawable && sel);
  SET_SENSITIVE ("select-sharpen", drawable && sel);
  SET_SENSITIVE ("select-shrink",  drawable && sel);
  SET_SENSITIVE ("select-grow",    drawable && sel);
  SET_SENSITIVE ("select-border",  drawable && sel);
  SET_SENSITIVE ("select-flood",   drawable && sel);

  SET_SENSITIVE ("select-save",               drawable && !fs);
  SET_SENSITIVE ("select-stroke",             writable && !children && sel);
  SET_SENSITIVE ("select-stroke-last-values", writable && !children && sel);

#undef SET_SENSITIVE
}
Example #7
0
void
gimp_image_resize_to_selection (GimpImage    *image,
                                GimpContext  *context,
                                GimpProgress *progress)
{
  GimpChannel *selection = gimp_image_get_mask (image);
  gint         x1, y1;
  gint         x2, y2;

  if (gimp_channel_is_empty (selection))
    return;

  gimp_channel_bounds (selection, &x1, &y1, &x2, &y2);

  gimp_image_resize (image, context,
                     x2 - x1, y2 - y1,
                     - x1, - y1,
                     progress);
}
Example #8
0
gboolean
gimp_paint_core_start (GimpPaintCore     *core,
                       GimpDrawable      *drawable,
                       GimpPaintOptions  *paint_options,
                       const GimpCoords  *coords,
                       GError           **error)
{
  GimpImage   *image;
  GimpItem    *item;
  GimpChannel *mask;

  g_return_val_if_fail (GIMP_IS_PAINT_CORE (core), FALSE);
  g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), FALSE);
  g_return_val_if_fail (gimp_item_is_attached (GIMP_ITEM (drawable)), FALSE);
  g_return_val_if_fail (GIMP_IS_PAINT_OPTIONS (paint_options), FALSE);
  g_return_val_if_fail (coords != NULL, FALSE);
  g_return_val_if_fail (error == NULL || *error == NULL, FALSE);

  item  = GIMP_ITEM (drawable);
  image = gimp_item_get_image (item);

  if (core->stroke_buffer)
    {
      g_array_free (core->stroke_buffer, TRUE);
      core->stroke_buffer = NULL;
    }

  core->stroke_buffer = g_array_sized_new (TRUE, TRUE,
                                           sizeof (GimpCoords),
                                           STROKE_BUFFER_INIT_SIZE);

  /* remember the last stroke's endpoint for later undo */
  core->start_coords = core->last_coords;

  core->cur_coords = *coords;

  if (! GIMP_PAINT_CORE_GET_CLASS (core)->start (core, drawable,
                                                 paint_options,
                                                 coords, error))
    {
      return FALSE;
    }

  /*  Allocate the undo structure  */
  if (core->undo_buffer)
    g_object_unref (core->undo_buffer);

  core->undo_buffer = gegl_buffer_dup (gimp_drawable_get_buffer (drawable));

  /*  Allocate the saved proj structure  */
  if (core->saved_proj_buffer)
    {
      g_object_unref (core->saved_proj_buffer);
      core->saved_proj_buffer = NULL;
    }

  if (core->use_saved_proj)
    {
      GeglBuffer *buffer = gimp_pickable_get_buffer (GIMP_PICKABLE (image));

      core->saved_proj_buffer = gegl_buffer_dup (buffer);
    }

  /*  Allocate the canvas blocks structure  */
  if (core->canvas_buffer)
    g_object_unref (core->canvas_buffer);

  core->canvas_buffer =
    gegl_buffer_new (GEGL_RECTANGLE (0, 0,
                                     gimp_item_get_width  (item),
                                     gimp_item_get_height (item)),
                     babl_format ("Y float"));

  /*  Get the initial undo extents  */

  core->x1 = core->x2 = core->cur_coords.x;
  core->y1 = core->y2 = core->cur_coords.y;

  core->last_paint.x = -1e6;
  core->last_paint.y = -1e6;

  mask = gimp_image_get_mask (image);

  /*  don't apply the mask to itself and don't apply an empty mask  */
  if (GIMP_DRAWABLE (mask) != drawable && ! gimp_channel_is_empty (mask))
    {
      GeglBuffer *mask_buffer;
      gint        offset_x;
      gint        offset_y;

      mask_buffer = gimp_drawable_get_buffer (GIMP_DRAWABLE (mask));
      gimp_item_get_offset (item, &offset_x, &offset_y);

      core->mask_buffer   = g_object_ref (mask_buffer);
      core->mask_x_offset = -offset_x;
      core->mask_y_offset = -offset_y;
    }
  else
    {
      core->mask_buffer = NULL;
    }

  core->linear_mode = gimp_drawable_get_linear (drawable);

  if (paint_options->use_applicator)
    {
      core->applicator = gimp_applicator_new (NULL, core->linear_mode);

      if (core->mask_buffer)
        {
          gimp_applicator_set_mask_buffer (core->applicator,
                                           core->mask_buffer);
          gimp_applicator_set_mask_offset (core->applicator,
                                           core->mask_x_offset,
                                           core->mask_y_offset);
        }

      gimp_applicator_set_affect (core->applicator,
                                  gimp_drawable_get_active_mask (drawable));
      gimp_applicator_set_dest_buffer (core->applicator,
                                       gimp_drawable_get_buffer (drawable));
    }
  else
    {
      if (core->comp_buffer)
        {
          g_object_unref (core->comp_buffer);
          core->comp_buffer = NULL;
        }

      /* Allocate the scratch buffer if there's a component mask */
      if (gimp_drawable_get_active_mask (drawable) != GIMP_COMPONENT_ALL)
        {
          const Babl *format;

          if (core->linear_mode)
            format = babl_format ("RGBA float");
          else
            format = babl_format ("R'G'B'A float");

          core->comp_buffer =
            gegl_buffer_new (GEGL_RECTANGLE (0, 0,
                                             gimp_item_get_width  (item),
                                             gimp_item_get_height (item)),
                             format);
        }
    }

  /*  Freeze the drawable preview so that it isn't constantly updated.  */
  gimp_viewable_preview_freeze (GIMP_VIEWABLE (drawable));

  return TRUE;
}
Example #9
0
void
gimp_image_set_quick_mask_state (GimpImage *image,
                                 gboolean   active)
{
  GimpChannel *selection;
  GimpChannel *mask;
  gboolean     channel_was_active;

  g_return_if_fail (GIMP_IS_IMAGE (image));

  if (active == gimp_image_get_quick_mask_state (image))
    return;

  /*  Keep track of the state so that we can make the right drawable
   *  active again when deactiviting quick mask (see bug #134371).
   */
  if (image->quick_mask_state)
    channel_was_active = (image->quick_mask_state & CHANNEL_WAS_ACTIVE) != 0;
  else
    channel_was_active = gimp_image_get_active_channel (image) != NULL;

  /*  Set image->quick_mask_state early so we can return early when
   *  being called recursively.
   */
  image->quick_mask_state = (active
                             ? TRUE | (channel_was_active ?
                                       CHANNEL_WAS_ACTIVE : 0)
                             : FALSE);

  selection = gimp_image_get_mask (image);
  mask      = gimp_image_get_quick_mask (image);

  if (active)
    {
      if (! mask)
        {
          gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_IMAGE_QUICK_MASK,
                                       _("Enable Quick Mask"));

          if (gimp_channel_is_empty (selection))
            {
              /* if no selection */

              GimpLayer *floating_sel = gimp_image_floating_sel (image);

              if (floating_sel)
                floating_sel_to_layer (floating_sel);

              mask = gimp_channel_new (image,
                                       image->width,
                                       image->height,
                                       GIMP_IMAGE_QUICK_MASK_NAME,
                                       &image->quick_mask_color);

              /* Clear the mask */
              gimp_channel_clear (mask, NULL, FALSE);
            }
          else
            {
              /* if selection */

              mask = GIMP_CHANNEL (gimp_item_duplicate (GIMP_ITEM (selection),
                                                        GIMP_TYPE_CHANNEL,
                                                        FALSE));

              /* Clear the selection */
              gimp_channel_clear (selection, NULL, TRUE);

              gimp_channel_set_color (mask, &image->quick_mask_color, FALSE);
              gimp_item_rename (GIMP_ITEM (mask), GIMP_IMAGE_QUICK_MASK_NAME);
            }

          if (image->quick_mask_inverted)
            gimp_channel_invert (mask, FALSE);

          gimp_image_add_channel (image, mask, 0);

          gimp_image_undo_group_end (image);
        }
    }
  else
    {
      if (mask)
        {
          GimpLayer *floating_sel = gimp_image_floating_sel (image);

          gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_IMAGE_QUICK_MASK,
                                       _("Disable Quick Mask"));

          if (image->quick_mask_inverted)
            gimp_channel_invert (mask, TRUE);

          if (floating_sel && floating_sel->fs.drawable == GIMP_DRAWABLE (mask))
            floating_sel_anchor (floating_sel);

          gimp_selection_load (gimp_image_get_mask (image), mask);
          gimp_image_remove_channel (image, mask);

          if (! channel_was_active)
            gimp_image_unset_active_channel (image);

          gimp_image_undo_group_end (image);
        }
    }

  gimp_image_quick_mask_changed (image);
}
Example #10
0
static void
gimp_move_tool_button_press (GimpTool            *tool,
                             const GimpCoords    *coords,
                             guint32              time,
                             GdkModifierType      state,
                             GimpButtonPressType  press_type,
                             GimpDisplay         *display)
{
  GimpMoveTool     *move    = GIMP_MOVE_TOOL (tool);
  GimpMoveOptions  *options = GIMP_MOVE_TOOL_GET_OPTIONS (tool);
  GimpDisplayShell *shell   = gimp_display_get_shell (display);
  GimpImage        *image   = gimp_display_get_image (display);

  tool->display = display;

  move->floating_layer     = NULL;
  move->guide              = NULL;
  move->moving_guide       = FALSE;
  move->old_active_layer   = NULL;
  move->old_active_vectors = NULL;

  if (! options->move_current)
    {
      if (options->move_type == GIMP_TRANSFORM_TYPE_PATH)
        {
          GimpVectors *vectors;

          if (gimp_draw_tool_on_vectors (GIMP_DRAW_TOOL (tool), display,
                                         coords, 7, 7,
                                         NULL, NULL, NULL, NULL, NULL,
                                         &vectors))
            {
              move->old_active_vectors =
                gimp_image_get_active_vectors (image);

              gimp_image_set_active_vectors (image, vectors);
            }
          else
            {
              /*  no path picked  */
              return;
            }
        }
      else if (options->move_type == GIMP_TRANSFORM_TYPE_LAYER)
        {
          GimpGuide  *guide;
          GimpLayer  *layer;
          const gint  snap_distance = display->config->snap_distance;

          if (gimp_display_shell_get_show_guides (shell) &&
              (guide = gimp_image_find_guide (image,
                                              coords->x, coords->y,
                                              FUNSCALEX (shell, snap_distance),
                                              FUNSCALEY (shell, snap_distance))))
            {
              move->guide             = guide;
              move->moving_guide      = TRUE;
              move->guide_position    = gimp_guide_get_position (guide);
              move->guide_orientation = gimp_guide_get_orientation (guide);

              gimp_tool_control_set_scroll_lock (tool->control, TRUE);
              gimp_tool_control_set_precision   (tool->control,
                                                 GIMP_CURSOR_PRECISION_PIXEL_BORDER);

              gimp_tool_control_activate (tool->control);

              gimp_display_shell_selection_pause (shell);

              gimp_draw_tool_start (GIMP_DRAW_TOOL (tool), display);

              gimp_tool_push_status_length (tool, display,
                                            _("Move Guide: "),
                                            SWAP_ORIENT (move->guide_orientation),
                                            move->guide_position,
                                            NULL);

              return;
            }
          else if ((layer = gimp_image_pick_layer (image,
                                                   coords->x,
                                                   coords->y)))
            {
              if (gimp_image_get_floating_selection (image) &&
                  ! gimp_layer_is_floating_sel (layer))
                {
                  /*  If there is a floating selection, and this aint it,
                   *  use the move tool to anchor it.
                   */
                  move->floating_layer =
                    gimp_image_get_floating_selection (image);

                  gimp_tool_control_activate (tool->control);

                  return;
                }
              else
                {
                  move->old_active_layer = gimp_image_get_active_layer (image);

                  gimp_image_set_active_layer (image, layer);
                }
            }
          else
            {
              /*  no guide and no layer picked  */

              return;
            }
        }
    }

  switch (options->move_type)
    {
    case GIMP_TRANSFORM_TYPE_PATH:
      if (gimp_image_get_active_vectors (image))
        gimp_edit_selection_tool_start (tool, display, coords,
                                        GIMP_TRANSLATE_MODE_VECTORS, TRUE);
      break;

    case GIMP_TRANSFORM_TYPE_SELECTION:
      if (! gimp_channel_is_empty (gimp_image_get_mask (image)))
        gimp_edit_selection_tool_start (tool, display, coords,
                                        GIMP_TRANSLATE_MODE_MASK, TRUE);
      break;

    case GIMP_TRANSFORM_TYPE_LAYER:
      {
        GimpDrawable *drawable = gimp_image_get_active_drawable (image);

        if (GIMP_IS_LAYER_MASK (drawable))
          gimp_edit_selection_tool_start (tool, display, coords,
                                          GIMP_TRANSLATE_MODE_LAYER_MASK, TRUE);
        else if (GIMP_IS_CHANNEL (drawable))
          gimp_edit_selection_tool_start (tool, display, coords,
                                          GIMP_TRANSLATE_MODE_CHANNEL, TRUE);
        else if (GIMP_IS_LAYER (drawable))
          gimp_edit_selection_tool_start (tool, display, coords,
                                          GIMP_TRANSLATE_MODE_LAYER, TRUE);
      }
      break;
    }
}
Example #11
0
GimpDrawable *
gimp_drawable_transform_rotate (GimpDrawable     *drawable,
                                GimpContext      *context,
                                GimpRotationType  rotate_type,
                                gdouble           center_x,
                                gdouble           center_y,
                                gboolean          clip_result)
{
  GimpImage    *image;
  GeglBuffer   *orig_buffer;
  gint          orig_offset_x;
  gint          orig_offset_y;
  gboolean      new_layer;
  GimpDrawable *result = NULL;

  g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), NULL);
  g_return_val_if_fail (gimp_item_is_attached (GIMP_ITEM (drawable)), NULL);
  g_return_val_if_fail (GIMP_IS_CONTEXT (context), NULL);

  image = gimp_item_get_image (GIMP_ITEM (drawable));

  /* Start a transform undo group */
  gimp_image_undo_group_start (image,
                               GIMP_UNDO_GROUP_TRANSFORM,
                               C_("undo-type", "Rotate"));

  /* Cut/Copy from the specified drawable */
  orig_buffer = gimp_drawable_transform_cut (drawable, context,
                                             &orig_offset_x, &orig_offset_y,
                                             &new_layer);

  if (orig_buffer)
    {
      GeglBuffer *new_buffer;
      gint        new_offset_x;
      gint        new_offset_y;

      /*  always clip unfloated buffers so they keep their size  */
      if (GIMP_IS_CHANNEL (drawable) &&
          ! babl_format_has_alpha (gegl_buffer_get_format (orig_buffer)))
        clip_result = TRUE;

      /*  also transform the mask if we are transforming an entire layer  */
      if (GIMP_IS_LAYER (drawable) &&
          gimp_layer_get_mask (GIMP_LAYER (drawable)) &&
          gimp_channel_is_empty (gimp_image_get_mask (image)))
        {
          GimpLayerMask *mask = gimp_layer_get_mask (GIMP_LAYER (drawable));

          gimp_item_rotate (GIMP_ITEM (mask), context,
                            rotate_type,
                            center_x,
                            center_y,
                            clip_result);
        }

      /* transform the buffer */
      new_buffer = gimp_drawable_transform_buffer_rotate (drawable, context,
                                                          orig_buffer,
                                                          orig_offset_x,
                                                          orig_offset_y,
                                                          rotate_type,
                                                          center_x, center_y,
                                                          clip_result,
                                                          &new_offset_x,
                                                          &new_offset_y);

      /* Free the cut/copied buffer */
      g_object_unref (orig_buffer);

      if (new_buffer)
        {
          result = gimp_drawable_transform_paste (drawable, new_buffer,
                                                  new_offset_x, new_offset_y,
                                                  new_layer);
          g_object_unref (new_buffer);
        }
    }

  /*  push the undo group end  */
  gimp_image_undo_group_end (image);

  return result;
}
Example #12
0
static void
gimp_selection_tool_oper_update (GimpTool         *tool,
                                 const GimpCoords *coords,
                                 GdkModifierType   state,
                                 gboolean          proximity,
                                 GimpDisplay      *display)
{
  GimpSelectionTool    *selection_tool = GIMP_SELECTION_TOOL (tool);
  GimpSelectionOptions *options        = GIMP_SELECTION_TOOL_GET_OPTIONS (tool);
  GimpImage            *image;
  GimpChannel          *selection;
  GimpDrawable         *drawable;
  GimpLayer            *layer;
  GimpLayer            *floating_sel;
  GdkModifierType       extend_mask;
  GdkModifierType       modify_mask;
  gboolean              move_layer        = FALSE;
  gboolean              move_floating_sel = FALSE;
  gboolean              selection_empty;

  image        = gimp_display_get_image (display);
  selection    = gimp_image_get_mask (image);
  drawable     = gimp_image_get_active_drawable (image);
  layer        = gimp_image_pick_layer (image, coords->x, coords->y);
  floating_sel = gimp_image_get_floating_selection (image);

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

  if (drawable)
    {
      if (floating_sel)
        {
          if (layer == floating_sel)
            move_floating_sel = TRUE;
        }
      else if (gimp_item_mask_intersect (GIMP_ITEM (drawable),
                                         NULL, NULL, NULL, NULL))
        {
          move_layer = TRUE;
        }
    }

  selection_empty = gimp_channel_is_empty (selection);

  selection_tool->function = SELECTION_SELECT;

  if (selection_tool->allow_move &&
      (state & GDK_MOD1_MASK) && (state & modify_mask) && move_layer)
    {
      /* move the selection */
      selection_tool->function = SELECTION_MOVE;
    }
  else if (selection_tool->allow_move &&
           (state & GDK_MOD1_MASK) && (state & extend_mask) && move_layer)
    {
      /* move a copy of the selection */
      selection_tool->function = SELECTION_MOVE_COPY;
    }
  else if (selection_tool->allow_move &&
           (state & GDK_MOD1_MASK) && ! selection_empty)
    {
      /* move the selection mask */
      selection_tool->function = SELECTION_MOVE_MASK;
    }
  else if (selection_tool->allow_move &&
           ! (state & (extend_mask | modify_mask)) &&
           move_floating_sel)
    {
      /* move the selection */
      selection_tool->function = SELECTION_MOVE;
    }
  else if ((state & modify_mask) || (state & extend_mask))
    {
      /* select */
      selection_tool->function = SELECTION_SELECT;
    }
  else if (floating_sel)
    {
      /* anchor the selection */
      selection_tool->function = SELECTION_ANCHOR;
    }

  gimp_tool_pop_status (tool, display);

  if (proximity)
    {
      const gchar     *status      = NULL;
      gboolean         free_status = FALSE;
      GdkModifierType  modifiers   = (extend_mask | modify_mask);

      if (! selection_empty)
        modifiers |= GDK_MOD1_MASK;

      switch (selection_tool->function)
        {
        case SELECTION_SELECT:
          switch (options->operation)
            {
            case GIMP_CHANNEL_OP_REPLACE:
              if (! selection_empty)
                {
                  status = gimp_suggest_modifiers (_("Click-Drag to replace the "
                                                     "current selection"),
                                                   modifiers & ~state,
                                                   NULL, NULL, NULL);
                  free_status = TRUE;
                }
              else
                {
                  status = _("Click-Drag to create a new selection");
                }
              break;

            case GIMP_CHANNEL_OP_ADD:
              status = gimp_suggest_modifiers (_("Click-Drag to add to the "
                                                 "current selection"),
                                               modifiers
                                               & ~(state | extend_mask),
                                               NULL, NULL, NULL);
              free_status = TRUE;
              break;

            case GIMP_CHANNEL_OP_SUBTRACT:
              status = gimp_suggest_modifiers (_("Click-Drag to subtract from the "
                                                 "current selection"),
                                               modifiers
                                               & ~(state | modify_mask),
                                               NULL, NULL, NULL);
              free_status = TRUE;
              break;

            case GIMP_CHANNEL_OP_INTERSECT:
              status = gimp_suggest_modifiers (_("Click-Drag to intersect with "
                                                 "the current selection"),
                                               modifiers & ~state,
                                               NULL, NULL, NULL);
              free_status = TRUE;
              break;
            }
          break;

        case SELECTION_MOVE_MASK:
          status = gimp_suggest_modifiers (_("Click-Drag to move the "
                                             "selection mask"),
                                           modifiers & ~state,
                                           NULL, NULL, NULL);
          free_status = TRUE;
          break;

        case SELECTION_MOVE:
          status = _("Click-Drag to move the selected pixels");
          break;

        case SELECTION_MOVE_COPY:
          status = _("Click-Drag to move a copy of the selected pixels");
          break;

        case SELECTION_ANCHOR:
          status = _("Click to anchor the floating selection");
          break;

        default:
          g_return_if_reached ();
        }

      if (status)
        gimp_tool_push_status (tool, display, "%s", status);

      if (free_status)
        g_free ((gchar *) status);
    }
}
Example #13
0
/**
 * gimp_drawable_get_bucket_fill_buffer:
 * @drawable: the #GimpDrawable to edit.
 * @options:
 * @fill_transparent:
 * @fill_criterion:
 * @threshold:
 * @sample_merged:
 * @diagonal_neighbors:
 * @seed_x: X coordinate to start the fill.
 * @seed_y: Y coordinate to start the fill.
 * @mask_buffer: mask of the fill in-progress when in an interactive
 *               filling process. Set to NULL if you need a one-time
 *               fill.
 * @mask_x: returned x bound of @mask_buffer.
 * @mask_y: returned x bound of @mask_buffer.
 * @mask_width: returned width bound of @mask_buffer.
 * @mask_height: returned height bound of @mask_buffer.
 *
 * Creates the fill buffer for a bucket fill operation on @drawable,
 * without actually applying it (if you want to apply it directly as a
 * one-time operation, use gimp_drawable_bucket_fill() instead). If
 * @mask_buffer is not NULL, the intermediate fill mask will also be
 * returned. This fill mask can later be reused in successive calls to
 * gimp_drawable_get_bucket_fill_buffer() for interactive filling.
 *
 * Returns: a fill buffer which can be directly applied to @drawable, or
 *          used in a drawable filter as preview.
 */
GeglBuffer *
gimp_drawable_get_bucket_fill_buffer (GimpDrawable         *drawable,
                                      GimpFillOptions      *options,
                                      gboolean              fill_transparent,
                                      GimpSelectCriterion   fill_criterion,
                                      gdouble               threshold,
                                      gboolean              sample_merged,
                                      gboolean              diagonal_neighbors,
                                      gdouble               seed_x,
                                      gdouble               seed_y,
                                      GeglBuffer          **mask_buffer,
                                      gdouble              *mask_x,
                                      gdouble              *mask_y,
                                      gint                 *mask_width,
                                      gint                 *mask_height)
{
  GimpImage    *image;
  GimpPickable *pickable;
  GeglBuffer   *buffer;
  GeglBuffer   *new_mask;
  gboolean      antialias;
  gint          x, y, width, height;
  gint          mask_offset_x = 0;
  gint          mask_offset_y = 0;
  gint          sel_x, sel_y, sel_width, sel_height;

  g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), NULL);
  g_return_val_if_fail (gimp_item_is_attached (GIMP_ITEM (drawable)), NULL);
  g_return_val_if_fail (GIMP_IS_FILL_OPTIONS (options), NULL);

  image = gimp_item_get_image (GIMP_ITEM (drawable));

  if (! gimp_item_mask_intersect (GIMP_ITEM (drawable),
                                  &sel_x, &sel_y, &sel_width, &sel_height))
    return NULL;

  if (mask_buffer && *mask_buffer && threshold == 0.0)
    {
      gfloat pixel;

      gegl_buffer_sample (*mask_buffer, seed_x, seed_y, NULL, &pixel,
                          babl_format ("Y float"),
                          GEGL_SAMPLER_NEAREST, GEGL_ABYSS_NONE);

      if (pixel != 0.0)
        /* Already selected. This seed won't change the selection. */
        return NULL;
    }

  gimp_set_busy (image->gimp);
  if (sample_merged)
    pickable = GIMP_PICKABLE (image);
  else
    pickable = GIMP_PICKABLE (drawable);

  antialias = gimp_fill_options_get_antialias (options);

  /*  Do a seed bucket fill...To do this, calculate a new
   *  contiguous region.
   */
  new_mask = gimp_pickable_contiguous_region_by_seed (pickable,
                                                      antialias,
                                                      threshold,
                                                      fill_transparent,
                                                      fill_criterion,
                                                      diagonal_neighbors,
                                                      (gint) seed_x,
                                                      (gint) seed_y);
  if (mask_buffer && *mask_buffer)
    {
      gimp_gegl_mask_combine_buffer (new_mask, *mask_buffer,
                                     GIMP_CHANNEL_OP_ADD, 0, 0);
      g_object_unref (*mask_buffer);
    }
  if (mask_buffer)
    *mask_buffer = new_mask;

  gimp_gegl_mask_bounds (new_mask, &x, &y, &width, &height);
  width  -= x;
  height -= y;

  /*  If there is a selection, intersect the region bounds
   *  with the selection bounds, to avoid processing areas
   *  that are going to be masked out anyway.  The actual
   *  intersection of the fill region with the mask data
   *  happens when combining the fill buffer, in
   *  gimp_drawable_apply_buffer().
   */
  if (! gimp_channel_is_empty (gimp_image_get_mask (image)))
    {
      gint off_x = 0;
      gint off_y = 0;

      if (sample_merged)
        gimp_item_get_offset (GIMP_ITEM (drawable), &off_x, &off_y);

      if (! gimp_rectangle_intersect (x, y, width, height,

                                      sel_x + off_x, sel_y + off_y,
                                      sel_width,     sel_height,

                                      &x, &y, &width, &height))
        {
          if (! mask_buffer)
            g_object_unref (new_mask);
          /*  The fill region and the selection are disjoint; bail.  */
          gimp_unset_busy (image->gimp);

          return NULL;
        }
    }

  /*  make sure we handle the mask correctly if it was sample-merged  */
  if (sample_merged)
    {
      GimpItem *item = GIMP_ITEM (drawable);
      gint      off_x, off_y;

      /*  Limit the channel bounds to the drawable's extents  */
      gimp_item_get_offset (item, &off_x, &off_y);

      gimp_rectangle_intersect (x, y, width, height,

                                off_x, off_y,
                                gimp_item_get_width (item),
                                gimp_item_get_height (item),

                                &x, &y, &width, &height);

      mask_offset_x = x;
      mask_offset_y = y;

     /*  translate mask bounds to drawable coords  */
      x -= off_x;
      y -= off_y;
    }
  else
    {
      mask_offset_x = x;
      mask_offset_y = y;
    }

  buffer = gimp_fill_options_create_buffer (options, drawable,
                                            GEGL_RECTANGLE (0, 0,
                                                            width, height),
                                            -x, -y);

  gimp_gegl_apply_opacity (buffer, NULL, NULL, buffer, new_mask,
                           -mask_offset_x, -mask_offset_y, 1.0);

  if (mask_x)
    *mask_x = x;
  if (mask_y)
    *mask_y = y;
  if (mask_width)
    *mask_width = width;
  if (mask_height)
    *mask_height = height;

  if (! mask_buffer)
    g_object_unref (new_mask);

  gimp_unset_busy (image->gimp);

  return buffer;
}
Example #14
0
void
gimp_drawable_real_apply_buffer (GimpDrawable         *drawable,
                                 GeglBuffer           *buffer,
                                 const GeglRectangle  *buffer_region,
                                 gboolean              push_undo,
                                 const gchar          *undo_desc,
                                 gdouble               opacity,
                                 GimpLayerModeEffects  mode,
                                 GeglBuffer           *base_buffer,
                                 gint                  base_x,
                                 gint                  base_y)
{
  GimpItem          *item        = GIMP_ITEM (drawable);
  GimpImage         *image       = gimp_item_get_image (item);
  GimpChannel       *mask        = gimp_image_get_mask (image);
  GeglBuffer        *mask_buffer = NULL;
  GeglNode          *apply;
  GimpComponentMask  affect;
  gint               x, y, width, height;
  gint               offset_x, offset_y;

  /*  don't apply the mask to itself and don't apply an empty mask  */
  if (GIMP_DRAWABLE (mask) == drawable || gimp_channel_is_empty (mask))
    mask = NULL;

  if (! base_buffer)
    base_buffer = gimp_drawable_get_buffer (drawable);

  /*  get the layer offsets  */
  gimp_item_get_offset (item, &offset_x, &offset_y);

  /*  make sure the image application coordinates are within drawable bounds  */
  gimp_rectangle_intersect (base_x, base_y,
                            buffer_region->width, buffer_region->height,
                            0, 0,
                            gimp_item_get_width  (item),
                            gimp_item_get_height (item),
                            &x, &y, &width, &height);

  if (mask)
    {
      GimpItem *mask_item = GIMP_ITEM (mask);

      /*  make sure coordinates are in mask bounds ...
       *  we need to add the layer offset to transform coords
       *  into the mask coordinate system
       */
      gimp_rectangle_intersect (x, y, width, height,
                                -offset_x, -offset_y,
                                gimp_item_get_width  (mask_item),
                                gimp_item_get_height (mask_item),
                                &x, &y, &width, &height);
    }

  if (push_undo)
    {
      GimpDrawableUndo *undo;

      gimp_drawable_push_undo (drawable, undo_desc,
                               NULL, x, y, width, height);

      undo = GIMP_DRAWABLE_UNDO (gimp_image_undo_get_fadeable (image));

      if (undo)
        {
          undo->paint_mode = mode;
          undo->opacity    = opacity;

          undo->applied_buffer =
            gegl_buffer_new (GEGL_RECTANGLE (0, 0, width, height),
                             gegl_buffer_get_format (buffer));

          gegl_buffer_copy (buffer,
                            GEGL_RECTANGLE (buffer_region->x + (x - base_x),
                                            buffer_region->y + (y - base_y),
                                            width, height),
                            undo->applied_buffer,
                            GEGL_RECTANGLE (0, 0, width, height));
        }
    }

  if (mask)
    mask_buffer = gimp_drawable_get_buffer (GIMP_DRAWABLE (mask));

  affect = gimp_drawable_get_active_mask (drawable);

  apply = gimp_gegl_create_apply_buffer_node (buffer,
                                              base_x - buffer_region->x,
                                              base_y - buffer_region->y,
                                              0,
                                              0,
                                              0,
                                              0,
                                              mask_buffer,
                                              -offset_x,
                                              -offset_y,
                                              opacity,
                                              mode,
                                              affect);

  gimp_gegl_apply_operation (base_buffer, NULL, NULL,
                             apply,
                             gimp_drawable_get_buffer (drawable),
                             GEGL_RECTANGLE (x, y, width, height));

  g_object_unref (apply);
}
Example #15
0
/*  Similar to gimp_drawable_apply_region but works in "replace" mode (i.e.
 *  transparent pixels in src2 make the result transparent rather than
 *  opaque.
 *
 * Takes an additional mask pixel region as well.
 */
void
gimp_drawable_real_replace_buffer (GimpDrawable        *drawable,
                                   GeglBuffer          *buffer,
                                   const GeglRectangle *buffer_region,
                                   gboolean             push_undo,
                                   const gchar         *undo_desc,
                                   gdouble              opacity,
                                   GeglBuffer          *mask_buffer,
                                   const GeglRectangle *mask_buffer_region,
                                   gint                 dest_x,
                                   gint                 dest_y)
{
  GimpItem        *item  = GIMP_ITEM (drawable);
  GimpImage       *image = gimp_item_get_image (item);
  GimpChannel     *mask  = gimp_image_get_mask (image);
  GeglBuffer      *drawable_buffer;
  gint             x, y, width, height;
  gint             offset_x, offset_y;
  gboolean         active_components[MAX_CHANNELS];

  /*  don't apply the mask to itself and don't apply an empty mask  */
  if (GIMP_DRAWABLE (mask) == drawable || gimp_channel_is_empty (mask))
    mask = NULL;

  /*  configure the active channel array  */
  gimp_drawable_get_active_components (drawable, active_components);

  /*  get the layer offsets  */
  gimp_item_get_offset (item, &offset_x, &offset_y);

  /*  make sure the image application coordinates are within drawable bounds  */
  gimp_rectangle_intersect (dest_x, dest_y,
                            buffer_region->width, buffer_region->height,
                            0, 0,
                            gimp_item_get_width  (item),
                            gimp_item_get_height (item),
                            &x, &y, &width, &height);

  if (mask)
    {
      GimpItem *mask_item = GIMP_ITEM (mask);

      /*  make sure coordinates are in mask bounds ...
       *  we need to add the layer offset to transform coords
       *  into the mask coordinate system
       */
      gimp_rectangle_intersect (x, y, width, height,
                                -offset_x, -offset_y,
                                gimp_item_get_width  (mask_item),
                                gimp_item_get_height (mask_item),
                                &x, &y, &width, &height);
    }

  /*  If the calling procedure specified an undo step...  */
  if (push_undo)
    gimp_drawable_push_undo (drawable, undo_desc,
                             NULL, x, y, width, height);

  drawable_buffer = gimp_drawable_get_buffer (drawable);

  if (mask)
    {
      GeglBuffer *src_buffer;
      GeglBuffer *dest_buffer;

      src_buffer = gimp_drawable_get_buffer (GIMP_DRAWABLE (mask));

      dest_buffer = gegl_buffer_new (GEGL_RECTANGLE (0, 0, width, height),
                                     gegl_buffer_get_format (src_buffer));

      gegl_buffer_copy (src_buffer,
                        GEGL_RECTANGLE (x + offset_x, y + offset_y,
                                        width, height),
                        dest_buffer,
                        GEGL_RECTANGLE (0, 0, 0, 0));

      gimp_gegl_combine_mask (mask_buffer, mask_buffer_region,
                              dest_buffer, GEGL_RECTANGLE (0, 0, width, height),
                              1.0);

      gimp_gegl_replace (buffer,          buffer_region,
                         drawable_buffer, GEGL_RECTANGLE (x, y, width, height),
                         dest_buffer,     GEGL_RECTANGLE (0, 0, width, height),
                         drawable_buffer, GEGL_RECTANGLE (x, y, width, height),
                         opacity,
                         active_components);

      g_object_unref (dest_buffer);
    }
  else
    {
      gimp_gegl_replace (buffer,          buffer_region,
                         drawable_buffer, GEGL_RECTANGLE (x, y, width, height),
                         mask_buffer,     mask_buffer_region,
                         drawable_buffer, GEGL_RECTANGLE (x, y, width, height),
                         opacity,
                         active_components);
    }
}
Example #16
0
void
gimp_drawable_bucket_fill (GimpDrawable         *drawable,
                           GimpFillOptions      *options,
                           gboolean              fill_transparent,
                           GimpSelectCriterion   fill_criterion,
                           gdouble               threshold,
                           gboolean              sample_merged,
                           gboolean              diagonal_neighbors,
                           gdouble               seed_x,
                           gdouble               seed_y)
{
    GimpImage    *image;
    GimpPickable *pickable;
    GeglBuffer   *buffer;
    GeglBuffer   *mask_buffer;
    gboolean      antialias;
    gint          x, y, width, height;
    gint          mask_offset_x = 0;
    gint          mask_offset_y = 0;
    gint          sel_x, sel_y, sel_width, sel_height;

    g_return_if_fail (GIMP_IS_DRAWABLE (drawable));
    g_return_if_fail (gimp_item_is_attached (GIMP_ITEM (drawable)));
    g_return_if_fail (GIMP_IS_FILL_OPTIONS (options));

    image = gimp_item_get_image (GIMP_ITEM (drawable));

    if (! gimp_item_mask_intersect (GIMP_ITEM (drawable),
                                    &sel_x, &sel_y, &sel_width, &sel_height))
        return;

    gimp_set_busy (image->gimp);

    if (sample_merged)
        pickable = GIMP_PICKABLE (image);
    else
        pickable = GIMP_PICKABLE (drawable);

    antialias = gimp_fill_options_get_antialias (options);

    /*  Do a seed bucket fill...To do this, calculate a new
     *  contiguous region.
     */
    mask_buffer = gimp_pickable_contiguous_region_by_seed (pickable,
                  antialias,
                  threshold,
                  fill_transparent,
                  fill_criterion,
                  diagonal_neighbors,
                  (gint) seed_x,
                  (gint) seed_y);

    gimp_gegl_mask_bounds (mask_buffer, &x, &y, &width, &height);
    width  -= x;
    height -= y;

    /*  If there is a selection, inersect the region bounds
     *  with the selection bounds, to avoid processing areas
     *  that are going to be masked out anyway.  The actual
     *  intersection of the fill region with the mask data
     *  happens when combining the fill buffer, in
     *  gimp_drawable_apply_buffer().
     */
    if (! gimp_channel_is_empty (gimp_image_get_mask (image)))
    {
        gint off_x = 0;
        gint off_y = 0;

        if (sample_merged)
            gimp_item_get_offset (GIMP_ITEM (drawable), &off_x, &off_y);

        if (! gimp_rectangle_intersect (x, y, width, height,

                                        sel_x + off_x, sel_y + off_y,
                                        sel_width,     sel_height,

                                        &x, &y, &width, &height))
        {
            /*  The fill region and the selection are disjoint; bail.  */

            g_object_unref (mask_buffer);

            gimp_unset_busy (image->gimp);

            return;
        }
    }

    /*  make sure we handle the mask correctly if it was sample-merged  */
    if (sample_merged)
    {
        GimpItem *item = GIMP_ITEM (drawable);
        gint      off_x, off_y;

        /*  Limit the channel bounds to the drawable's extents  */
        gimp_item_get_offset (item, &off_x, &off_y);

        gimp_rectangle_intersect (x, y, width, height,

                                  off_x, off_y,
                                  gimp_item_get_width (item),
                                  gimp_item_get_height (item),

                                  &x, &y, &width, &height);

        mask_offset_x = x;
        mask_offset_y = y;

        /*  translate mask bounds to drawable coords  */
        x -= off_x;
        y -= off_y;
    }
    else
    {
        mask_offset_x = x;
        mask_offset_y = y;
    }

    buffer = gimp_fill_options_create_buffer (options, drawable,
             GEGL_RECTANGLE (0, 0,
                             width, height));

    gimp_gegl_apply_opacity (buffer, NULL, NULL, buffer,
                             mask_buffer,
                             -mask_offset_x,
                             -mask_offset_y,
                             1.0);
    g_object_unref (mask_buffer);

    /*  Apply it to the image  */
    gimp_drawable_apply_buffer (drawable, buffer,
                                GEGL_RECTANGLE (0, 0, width, height),
                                TRUE, C_("undo-type", "Bucket Fill"),
                                gimp_context_get_opacity (GIMP_CONTEXT (options)),
                                gimp_context_get_paint_mode (GIMP_CONTEXT (options)),
                                NULL, x, y);

    g_object_unref (buffer);

    gimp_drawable_update (drawable, x, y, width, height);

    gimp_unset_busy (image->gimp);
}
Example #17
0
GimpLayer *
gimp_edit_paste (GimpImage    *image,
                 GimpDrawable *drawable,
                 GimpBuffer   *paste,
                 gboolean      paste_into,
                 gint          viewport_x,
                 gint          viewport_y,
                 gint          viewport_width,
                 gint          viewport_height)
{
  GimpLayer  *layer;
  const Babl *format;
  gint        image_width;
  gint        image_height;
  gint        width;
  gint        height;
  gint        offset_x;
  gint        offset_y;
  gboolean    clamp_to_image = TRUE;

  g_return_val_if_fail (GIMP_IS_IMAGE (image), NULL);
  g_return_val_if_fail (drawable == NULL || GIMP_IS_DRAWABLE (drawable), NULL);
  g_return_val_if_fail (drawable == NULL ||
                        gimp_item_is_attached (GIMP_ITEM (drawable)), NULL);
  g_return_val_if_fail (GIMP_IS_BUFFER (paste), NULL);

  /*  Make a new layer: if drawable == NULL,
   *  user is pasting into an empty image.
   */

  if (drawable)
    format = gimp_drawable_get_format_with_alpha (drawable);
  else
    format = gimp_image_get_layer_format (image, TRUE);

  layer = gimp_layer_new_from_buffer (paste, image,
                                      format,
                                      _("Pasted Layer"),
                                      GIMP_OPACITY_OPAQUE, GIMP_NORMAL_MODE);

  if (! layer)
    return NULL;

  image_width  = gimp_image_get_width  (image);
  image_height = gimp_image_get_height (image);

  width  = gimp_item_get_width  (GIMP_ITEM (layer));
  height = gimp_item_get_height (GIMP_ITEM (layer));

  if (viewport_width  == image_width &&
      viewport_height == image_height)
    {
      /* if the whole image is visible, act as if there was no viewport */

      viewport_x      = 0;
      viewport_y      = 0;
      viewport_width  = 0;
      viewport_height = 0;
    }

  if (drawable)
    {
      /*  if pasting to a drawable  */

      gint     off_x, off_y;
      gint     x1, y1, x2, y2;
      gint     paste_x, paste_y;
      gint     paste_width, paste_height;
      gboolean have_mask;

      gimp_item_get_offset (GIMP_ITEM (drawable), &off_x, &off_y);
      have_mask = gimp_item_mask_bounds (GIMP_ITEM (drawable),
                                         &x1, &y1, &x2, &y2);

      if (! have_mask         && /* if we have no mask */
          viewport_width  > 0 && /* and we have a viewport */
          viewport_height > 0 &&
          (width  < (x2 - x1) || /* and the paste is smaller than the target */
           height < (y2 - y1)) &&

          /* and the viewport intersects with the target */
          gimp_rectangle_intersect (viewport_x, viewport_y,
                                    viewport_width, viewport_height,
                                    off_x, off_y,
                                    x2 - x1, y2 - y1,
                                    &paste_x, &paste_y,
                                    &paste_width, &paste_height))
        {
          /*  center on the viewport  */

          offset_x = paste_x + (paste_width - width)  / 2;
          offset_y = paste_y + (paste_height- height) / 2;
        }
      else
        {
          /*  otherwise center on the target  */

          offset_x = off_x + ((x1 + x2) - width)  / 2;
          offset_y = off_y + ((y1 + y2) - height) / 2;

          /*  and keep it that way  */
          clamp_to_image = FALSE;
        }
    }
  else if (viewport_width  > 0 &&  /* if we have a viewport */
           viewport_height > 0 &&
           (width  < image_width || /* and the paste is       */
            height < image_height)) /* smaller than the image */
    {
      /*  center on the viewport  */

      offset_x = viewport_x + (viewport_width  - width)  / 2;
      offset_y = viewport_y + (viewport_height - height) / 2;
    }
  else
    {
      /*  otherwise center on the image  */

      offset_x = (image_width  - width)  / 2;
      offset_y = (image_height - height) / 2;

      /*  and keep it that way  */
      clamp_to_image = FALSE;
    }

  if (clamp_to_image)
    {
      /*  Ensure that the pasted layer is always within the image, if it
       *  fits and aligned at top left if it doesn't. (See bug #142944).
       */
      offset_x = MIN (offset_x, image_width  - width);
      offset_y = MIN (offset_y, image_height - height);
      offset_x = MAX (offset_x, 0);
      offset_y = MAX (offset_y, 0);
    }

  gimp_item_set_offset (GIMP_ITEM (layer), offset_x, offset_y);

  /*  Start a group undo  */
  gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_EDIT_PASTE,
                               C_("undo-type", "Paste"));

  /*  If there is a selection mask clear it--
   *  this might not always be desired, but in general,
   *  it seems like the correct behavior.
   */
  if (! gimp_channel_is_empty (gimp_image_get_mask (image)) && ! paste_into)
    gimp_channel_clear (gimp_image_get_mask (image), NULL, TRUE);

  /*  if there's a drawable, add a new floating selection  */
  if (drawable)
    floating_sel_attach (layer, drawable);
  else
    gimp_image_add_layer (image, layer, NULL, 0, TRUE);

  /*  end the group undo  */
  gimp_image_undo_group_end (image);

  return layer;
}
Example #18
0
static void
compute_offset (GObject *object,
                GimpAlignmentType  alignment)
{
  gint object_offset_x = 0;
  gint object_offset_y = 0;
  gint object_height   = 0;
  gint object_width    = 0;
  gint offset          = 0;

  if (GIMP_IS_IMAGE (object))
    {
      GimpImage *image = GIMP_IMAGE (object);

      object_offset_x = 0;
      object_offset_y = 0;
      object_height   = gimp_image_get_height (image);
      object_width    = gimp_image_get_width (image);
    }
  else if (GIMP_IS_CHANNEL (object))
    {
      /* for channels, we use the bounds of the visible area, not
         the layer bounds.  This includes the selection channel */

      GimpChannel *channel = GIMP_CHANNEL (object);

      if (gimp_channel_is_empty (channel))
        {
          /* fall back on using the offsets instead */
          GimpItem *item = GIMP_ITEM (object);

          gimp_item_get_offset (item, &object_offset_x, &object_offset_y);
          object_width  = gimp_item_get_width  (item);
          object_height = gimp_item_get_height (item);
        }
      else
        {
          gint x1, x2, y1, y2;

          gimp_channel_bounds (channel, &x1, &y1, &x2, &y2);
          object_offset_x = x1;
          object_offset_y = y1;
          object_width    = x2 - x1;
          object_height   = y2 - y1;
        }
    }
  else if (GIMP_IS_ITEM (object))
    {
      GimpItem *item = GIMP_ITEM (object);

      if (GIMP_IS_VECTORS (object))
        {
          gdouble x1_f, y1_f, x2_f, y2_f;

          gimp_vectors_bounds (GIMP_VECTORS (item),
                               &x1_f, &y1_f,
                               &x2_f, &y2_f);

          object_offset_x = ROUND (x1_f);
          object_offset_y = ROUND (y1_f);
          object_height   = ROUND (y2_f - y1_f);
          object_width    = ROUND (x2_f - x1_f);
        }
      else
        {
          gimp_item_get_offset (item, &object_offset_x, &object_offset_y);
          object_width  = gimp_item_get_width  (item);
          object_height = gimp_item_get_height (item);
        }
    }
  else if (GIMP_IS_GUIDE (object))
    {
      GimpGuide *guide = GIMP_GUIDE (object);

      switch (gimp_guide_get_orientation (guide))
        {
        case GIMP_ORIENTATION_VERTICAL:
          object_offset_x = gimp_guide_get_position (guide);
          object_width = 0;
          break;

        case GIMP_ORIENTATION_HORIZONTAL:
          object_offset_y = gimp_guide_get_position (guide);
          object_height = 0;
          break;

        default:
          break;
        }
    }
  else
    {
      g_printerr ("Alignment object is not an image, item or guide.\n");
    }

  switch (alignment)
    {
    case GIMP_ALIGN_LEFT:
    case GIMP_ARRANGE_LEFT:
      offset = object_offset_x;
      break;
    case GIMP_ALIGN_HCENTER:
    case GIMP_ARRANGE_HCENTER:
      offset = object_offset_x + object_width/2;
      break;
    case GIMP_ALIGN_RIGHT:
    case GIMP_ARRANGE_RIGHT:
      offset = object_offset_x + object_width;
      break;
    case GIMP_ALIGN_TOP:
    case GIMP_ARRANGE_TOP:
      offset = object_offset_y;
      break;
    case GIMP_ALIGN_VCENTER:
    case GIMP_ARRANGE_VCENTER:
      offset = object_offset_y + object_height/2;
      break;
    case GIMP_ALIGN_BOTTOM:
    case GIMP_ARRANGE_BOTTOM:
      offset = object_offset_y + object_height;
      break;
    default:
      g_assert_not_reached ();
    }

  g_object_set_data (object, "align-offset",
                     GINT_TO_POINTER (offset));
}
Example #19
0
/**
 * gimp_drawable_get_line_art_fill_buffer:
 * @drawable: the #GimpDrawable to edit.
 * @line_art: the #GimpLineArt computed as fill source.
 * @options: the #GimpFillOptions.
 * @sample_merged:
 * @seed_x: X coordinate to start the fill.
 * @seed_y: Y coordinate to start the fill.
 * @mask_buffer: mask of the fill in-progress when in an interactive
 *               filling process. Set to NULL if you need a one-time
 *               fill.
 * @mask_x: returned x bound of @mask_buffer.
 * @mask_y: returned x bound of @mask_buffer.
 * @mask_width: returned width bound of @mask_buffer.
 * @mask_height: returned height bound of @mask_buffer.
 *
 * Creates the fill buffer for a bucket fill operation on @drawable
 * based on @line_art and @options, without actually applying it.
 * If @mask_buffer is not NULL, the intermediate fill mask will also be
 * returned. This fill mask can later be reused in successive calls to
 * gimp_drawable_get_bucket_fill_buffer() for interactive filling.
 *
 * Returns: a fill buffer which can be directly applied to @drawable, or
 *          used in a drawable filter as preview.
 */
GeglBuffer *
gimp_drawable_get_line_art_fill_buffer (GimpDrawable     *drawable,
                                        GimpLineArt      *line_art,
                                        GimpFillOptions  *options,
                                        gboolean          sample_merged,
                                        gdouble           seed_x,
                                        gdouble           seed_y,
                                        GeglBuffer      **mask_buffer,
                                        gdouble          *mask_x,
                                        gdouble          *mask_y,
                                        gint             *mask_width,
                                        gint             *mask_height)
{
  GimpImage  *image;
  GeglBuffer *buffer;
  GeglBuffer *new_mask;
  gint        x, y, width, height;
  gint        mask_offset_x = 0;
  gint        mask_offset_y = 0;
  gint        sel_x, sel_y, sel_width, sel_height;

  g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), NULL);
  g_return_val_if_fail (gimp_item_is_attached (GIMP_ITEM (drawable)), NULL);
  g_return_val_if_fail (GIMP_IS_FILL_OPTIONS (options), NULL);

  image = gimp_item_get_image (GIMP_ITEM (drawable));

  if (! gimp_item_mask_intersect (GIMP_ITEM (drawable),
                                  &sel_x, &sel_y, &sel_width, &sel_height))
    return NULL;

  if (mask_buffer && *mask_buffer)
    {
      gfloat pixel;

      gegl_buffer_sample (*mask_buffer, seed_x, seed_y, NULL, &pixel,
                          babl_format ("Y float"),
                          GEGL_SAMPLER_NEAREST, GEGL_ABYSS_NONE);

      if (pixel != 0.0)
        /* Already selected. This seed won't change the selection. */
        return NULL;
    }

  gimp_set_busy (image->gimp);

  /*  Do a seed bucket fill...To do this, calculate a new
   *  contiguous region.
   */
  new_mask = gimp_pickable_contiguous_region_by_line_art (NULL, line_art,
                                                          (gint) seed_x,
                                                          (gint) seed_y);
  if (mask_buffer && *mask_buffer)
    {
      gimp_gegl_mask_combine_buffer (new_mask, *mask_buffer,
                                     GIMP_CHANNEL_OP_ADD, 0, 0);
      g_object_unref (*mask_buffer);
    }
  if (mask_buffer)
    *mask_buffer = new_mask;

  gimp_gegl_mask_bounds (new_mask, &x, &y, &width, &height);
  width  -= x;
  height -= y;

  /*  If there is a selection, intersect the region bounds
   *  with the selection bounds, to avoid processing areas
   *  that are going to be masked out anyway.  The actual
   *  intersection of the fill region with the mask data
   *  happens when combining the fill buffer, in
   *  gimp_drawable_apply_buffer().
   */
  if (! gimp_channel_is_empty (gimp_image_get_mask (image)))
    {
      gint off_x = 0;
      gint off_y = 0;

      if (sample_merged)
        gimp_item_get_offset (GIMP_ITEM (drawable), &off_x, &off_y);

      if (! gimp_rectangle_intersect (x, y, width, height,

                                      sel_x + off_x, sel_y + off_y,
                                      sel_width,     sel_height,

                                      &x, &y, &width, &height))
        {
          if (! mask_buffer)
            g_object_unref (new_mask);
          /*  The fill region and the selection are disjoint; bail.  */
          gimp_unset_busy (image->gimp);

          return NULL;
        }
    }

  /*  make sure we handle the mask correctly if it was sample-merged  */
  if (sample_merged)
    {
      GimpItem *item = GIMP_ITEM (drawable);
      gint      off_x, off_y;

      /*  Limit the channel bounds to the drawable's extents  */
      gimp_item_get_offset (item, &off_x, &off_y);

      gimp_rectangle_intersect (x, y, width, height,

                                off_x, off_y,
                                gimp_item_get_width (item),
                                gimp_item_get_height (item),

                                &x, &y, &width, &height);

      mask_offset_x = x;
      mask_offset_y = y;

     /*  translate mask bounds to drawable coords  */
      x -= off_x;
      y -= off_y;
    }
  else
    {
      mask_offset_x = x;
      mask_offset_y = y;
    }

  buffer = gimp_fill_options_create_buffer (options, drawable,
                                            GEGL_RECTANGLE (0, 0,
                                                            width, height),
                                            -x, -y);

  gimp_gegl_apply_opacity (buffer, NULL, NULL, buffer, new_mask,
                           -mask_offset_x, -mask_offset_y, 1.0);

  if (gimp_fill_options_get_antialias (options))
    {
      /* Antialias for the line art algorithm is not applied during mask
       * creation because it is not based on individual pixel colors.
       * Instead we just want to apply it on the borders of the mask at
       * the end (since the mask can evolve, we don't want to actually
       * touch it, but only the intermediate results).
       */
      GeglNode   *graph;
      GeglNode   *input;
      GeglNode   *op;

      graph = gegl_node_new ();
      input = gegl_node_new_child (graph,
                                   "operation", "gegl:buffer-source",
                                   "buffer", buffer,
                                   NULL);
      op  = gegl_node_new_child (graph,
                                 "operation", "gegl:gaussian-blur",
                                 "std-dev-x", 0.5,
                                 "std-dev-y", 0.5,
                                 NULL);
      gegl_node_connect_to (input, "output", op, "input");
      gegl_node_blit_buffer (op, buffer, NULL, 0,
                             GEGL_ABYSS_NONE);
      g_object_unref (graph);
    }

  if (mask_x)
    *mask_x = x;
  if (mask_y)
    *mask_y = y;
  if (mask_width)
    *mask_width = width;
  if (mask_height)
    *mask_height = height;

  if (! mask_buffer)
    g_object_unref (new_mask);

  gimp_unset_busy (image->gimp);

  return buffer;
}
void
layers_actions_update (GimpActionGroup *group,
                       gpointer         data)
{
  GimpImage     *image          = action_data_get_image (data);
  GimpLayer     *layer          = NULL;
  GimpLayerMask *mask           = NULL;     /*  layer mask             */
  gboolean       fs             = FALSE;    /*  floating sel           */
  gboolean       ac             = FALSE;    /*  active channel         */
  gboolean       sel            = FALSE;
  gboolean       alpha          = FALSE;    /*  alpha channel present  */
  gboolean       indexed        = FALSE;    /*  is indexed             */
  gboolean       lock_alpha     = FALSE;
  gboolean       can_lock_alpha = FALSE;
  gboolean       text_layer     = FALSE;
  gboolean       writable       = FALSE;
  gboolean       children       = FALSE;
  GList         *next           = NULL;
  GList         *next_visible   = NULL;
  GList         *prev           = NULL;

  if (image)
    {
      fs      = (gimp_image_get_floating_selection (image) != NULL);
      ac      = (gimp_image_get_active_channel (image) != NULL);
      sel     = ! gimp_channel_is_empty (gimp_image_get_mask (image));
      indexed = (gimp_image_base_type (image) == GIMP_INDEXED);

      layer = gimp_image_get_active_layer (image);

      if (layer)
        {
          GList *layer_list;
          GList *list;

          mask           = gimp_layer_get_mask (layer);
          lock_alpha     = gimp_layer_get_lock_alpha (layer);
          can_lock_alpha = gimp_layer_can_lock_alpha (layer);
          alpha          = gimp_drawable_has_alpha (GIMP_DRAWABLE (layer));
          writable       = ! gimp_item_is_content_locked (GIMP_ITEM (layer));

          if (gimp_viewable_get_children (GIMP_VIEWABLE (layer)))
            children = TRUE;

          layer_list = gimp_item_get_container_iter (GIMP_ITEM (layer));

          list = g_list_find (layer_list, layer);

          if (list)
            {
              prev = g_list_previous (list);
              next = g_list_next (list);

              for (next_visible = next;
                   next_visible;
                   next_visible = g_list_next (next_visible))
                {
                  if (gimp_item_get_visible (next_visible->data))
                    {
                      /*  "next_visible" is actually "next_visible" and
                       *  "writable" and "not group"
                       */
                      if (gimp_item_is_content_locked (next_visible->data) ||
                          gimp_viewable_get_children (next_visible->data))
                        next_visible = NULL;

                      break;
                    }
                }
            }

          text_layer = gimp_item_is_text_layer (GIMP_ITEM (layer));
        }
    }

#define SET_VISIBLE(action,condition) \
        gimp_action_group_set_action_visible (group, action, (condition) != 0)
#define SET_SENSITIVE(action,condition) \
        gimp_action_group_set_action_sensitive (group, action, (condition) != 0)
#define SET_ACTIVE(action,condition) \
        gimp_action_group_set_action_active (group, action, (condition) != 0)
#define SET_LABEL(action,label) \
        gimp_action_group_set_action_label (group, action, label)

  SET_VISIBLE   ("layers-text-tool",        text_layer && !ac);
  SET_SENSITIVE ("layers-edit-attributes",  layer && !fs && !ac);

  if (layer && gimp_layer_is_floating_sel (layer))
    {
      SET_LABEL ("layers-new",             C_("layers-action", "To _New Layer"));
      SET_LABEL ("layers-new-last-values", C_("layers-action", "To _New Layer"));
    }
  else
    {
      SET_LABEL ("layers-new",             C_("layers-action", "_New Layer..."));
      SET_LABEL ("layers-new-last-values", C_("layers-action", "_New Layer"));
    }

  SET_SENSITIVE ("layers-new",              image);
  SET_SENSITIVE ("layers-new-last-values",  image);
  SET_SENSITIVE ("layers-new-from-visible", image);
  SET_SENSITIVE ("layers-new-group",        image && !indexed);
  SET_SENSITIVE ("layers-duplicate",        layer && !fs && !ac);
  SET_SENSITIVE ("layers-delete",           layer && !ac);

  SET_SENSITIVE ("layers-select-top",       layer && !fs && !ac && prev);
  SET_SENSITIVE ("layers-select-bottom",    layer && !fs && !ac && next);
  SET_SENSITIVE ("layers-select-previous",  layer && !fs && !ac && prev);
  SET_SENSITIVE ("layers-select-next",      layer && !fs && !ac && next);

  SET_SENSITIVE ("layers-raise",            layer && !fs && !ac && prev);
  SET_SENSITIVE ("layers-raise-to-top",     layer && !fs && !ac && prev);
  SET_SENSITIVE ("layers-lower",            layer && !fs && !ac && next);
  SET_SENSITIVE ("layers-lower-to-bottom",  layer && !fs && !ac && next);

  SET_SENSITIVE ("layers-anchor",           layer &&  fs && !ac);
  SET_SENSITIVE ("layers-merge-down",       layer && !fs && !ac && next_visible);
  SET_VISIBLE   ("layers-merge-group",      children);
  SET_SENSITIVE ("layers-merge-group",      layer && !fs && !ac && children);
  SET_SENSITIVE ("layers-merge-layers",     layer && !fs && !ac);
  SET_SENSITIVE ("layers-flatten-image",    layer && !fs && !ac);

  SET_VISIBLE   ("layers-text-discard",             text_layer && !ac);
  SET_VISIBLE   ("layers-text-to-vectors",          text_layer && !ac);
  SET_VISIBLE   ("layers-text-along-vectors",       text_layer && !ac);

  SET_SENSITIVE ("layers-resize",          writable && !ac);
  SET_SENSITIVE ("layers-resize-to-image", writable && !ac);
  SET_SENSITIVE ("layers-scale",           writable && !ac);

  SET_SENSITIVE ("layers-crop",            writable && sel);

  SET_SENSITIVE ("layers-alpha-add",       writable && !children && !fs && !alpha);
  SET_SENSITIVE ("layers-alpha-remove",    writable && !children && !fs &&  alpha);

  SET_SENSITIVE ("layers-lock-alpha", can_lock_alpha);
  SET_ACTIVE    ("layers-lock-alpha", lock_alpha);

  SET_SENSITIVE ("layers-mask-add",    layer    && !fs && !ac && !mask && !children);
  SET_SENSITIVE ("layers-mask-apply",  writable && !fs && !ac &&  mask && !children);
  SET_SENSITIVE ("layers-mask-delete", layer    && !fs && !ac &&  mask);

  SET_SENSITIVE ("layers-mask-edit",    layer && !fs && !ac &&  mask);
  SET_SENSITIVE ("layers-mask-show",    layer && !fs && !ac &&  mask);
  SET_SENSITIVE ("layers-mask-disable", layer && !fs && !ac &&  mask);

  SET_ACTIVE ("layers-mask-edit",    mask && gimp_layer_mask_get_edit (mask));
  SET_ACTIVE ("layers-mask-show",    mask && gimp_layer_mask_get_show (mask));
  SET_ACTIVE ("layers-mask-disable", mask && !gimp_layer_mask_get_apply (mask));

  SET_SENSITIVE ("layers-mask-selection-replace",   layer && !fs && !ac && mask);
  SET_SENSITIVE ("layers-mask-selection-add",       layer && !fs && !ac && mask);
  SET_SENSITIVE ("layers-mask-selection-subtract",  layer && !fs && !ac && mask);
  SET_SENSITIVE ("layers-mask-selection-intersect", layer && !fs && !ac && mask);

  SET_SENSITIVE ("layers-alpha-selection-replace",   layer && !fs && !ac);
  SET_SENSITIVE ("layers-alpha-selection-add",       layer && !fs && !ac);
  SET_SENSITIVE ("layers-alpha-selection-subtract",  layer && !fs && !ac);
  SET_SENSITIVE ("layers-alpha-selection-intersect", layer && !fs && !ac);

#undef SET_VISIBLE
#undef SET_SENSITIVE
#undef SET_ACTIVE
#undef SET_LABEL
}
Example #21
0
GimpDrawable *
gimp_drawable_transform_affine (GimpDrawable           *drawable,
                                GimpContext            *context,
                                const GimpMatrix3      *matrix,
                                GimpTransformDirection  direction,
                                GimpInterpolationType   interpolation_type,
                                gint                    recursion_level,
                                GimpTransformResize     clip_result,
                                GimpProgress           *progress)
{
  GimpImage    *image;
  GeglBuffer   *orig_buffer;
  gint          orig_offset_x;
  gint          orig_offset_y;
  gboolean      new_layer;
  GimpDrawable *result = NULL;

  g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), NULL);
  g_return_val_if_fail (gimp_item_is_attached (GIMP_ITEM (drawable)), NULL);
  g_return_val_if_fail (GIMP_IS_CONTEXT (context), NULL);
  g_return_val_if_fail (matrix != NULL, NULL);
  g_return_val_if_fail (progress == NULL || GIMP_IS_PROGRESS (progress), NULL);

  image = gimp_item_get_image (GIMP_ITEM (drawable));

  /* Start a transform undo group */
  gimp_image_undo_group_start (image,
                               GIMP_UNDO_GROUP_TRANSFORM,
                               C_("undo-type", "Transform"));

  /* Cut/Copy from the specified drawable */
  orig_buffer = gimp_drawable_transform_cut (drawable, context,
                                             &orig_offset_x, &orig_offset_y,
                                             &new_layer);

  if (orig_buffer)
    {
      GeglBuffer *new_buffer;
      gint        new_offset_x;
      gint        new_offset_y;

      /*  always clip unfloated buffers so they keep their size  */
      if (GIMP_IS_CHANNEL (drawable) &&
          ! babl_format_has_alpha (gegl_buffer_get_format (orig_buffer)))
        clip_result = GIMP_TRANSFORM_RESIZE_CLIP;

      /*  also transform the mask if we are transforming an entire layer  */
      if (GIMP_IS_LAYER (drawable) &&
          gimp_layer_get_mask (GIMP_LAYER (drawable)) &&
          gimp_channel_is_empty (gimp_image_get_mask (image)))
        {
          GimpLayerMask *mask = gimp_layer_get_mask (GIMP_LAYER (drawable));

          gimp_item_transform (GIMP_ITEM (mask), context,
                               matrix,
                               direction,
                               interpolation_type,
                               recursion_level,
                               clip_result,
                               progress);
        }

      /* transform the buffer */
      new_buffer = gimp_drawable_transform_buffer_affine (drawable, context,
                                                          orig_buffer,
                                                          orig_offset_x,
                                                          orig_offset_y,
                                                          matrix,
                                                          direction,
                                                          interpolation_type,
                                                          recursion_level,
                                                          clip_result,
                                                          &new_offset_x,
                                                          &new_offset_y,
                                                          progress);

      /* Free the cut/copied buffer */
      g_object_unref (orig_buffer);

      if (new_buffer)
        {
          result = gimp_drawable_transform_paste (drawable, new_buffer,
                                                  new_offset_x, new_offset_y,
                                                  new_layer);
          g_object_unref (new_buffer);
        }
    }

  /*  push the undo group end  */
  gimp_image_undo_group_end (image);

  return result;
}
Example #22
0
void
layers_actions_update (GimpActionGroup *group,
                       gpointer         data)
{
  GimpImage     *image     = action_data_get_image (data);
  GimpLayer     *layer      = NULL;
  GimpLayerMask *mask       = NULL;     /*  layer mask             */
  gboolean       fs         = FALSE;    /*  floating sel           */
  gboolean       ac         = FALSE;    /*  active channel         */
  gboolean       sel        = FALSE;
  gboolean       alpha      = FALSE;    /*  alpha channel present  */
  gboolean       indexed    = FALSE;    /*  is indexed             */
  gboolean       lock_alpha = FALSE;
  gboolean       text_layer = FALSE;
  GList         *next       = NULL;
  GList         *prev       = NULL;

  if (image)
    {
      fs      = (gimp_image_floating_sel (image) != NULL);
      ac      = (gimp_image_get_active_channel (image) != NULL);
      sel     = ! gimp_channel_is_empty (gimp_image_get_mask (image));
      indexed = (gimp_image_base_type (image) == GIMP_INDEXED);

      layer = gimp_image_get_active_layer (image);

      if (layer)
        {
          GList *list;

          mask       = gimp_layer_get_mask (layer);
          lock_alpha = gimp_layer_get_lock_alpha (layer);
          alpha      = gimp_drawable_has_alpha (GIMP_DRAWABLE (layer));

          list = g_list_find (GIMP_LIST (image->layers)->list, layer);

          if (list)
            {
              prev = g_list_previous (list);
              next = g_list_next (list);
            }

          if (layer)
            text_layer = gimp_drawable_is_text_layer (GIMP_DRAWABLE (layer));
        }
    }

#define SET_VISIBLE(action,condition) \
        gimp_action_group_set_action_visible (group, action, (condition) != 0)
#define SET_SENSITIVE(action,condition) \
        gimp_action_group_set_action_sensitive (group, action, (condition) != 0)
#define SET_ACTIVE(action,condition) \
        gimp_action_group_set_action_active (group, action, (condition) != 0)

  SET_VISIBLE   ("layers-text-tool",       text_layer && !ac);
  SET_SENSITIVE ("layers-edit-attributes", layer && !fs && !ac);

  SET_SENSITIVE ("layers-new",             image);
  SET_SENSITIVE ("layers-new-last-values", image);
  SET_SENSITIVE ("layers-duplicate",       layer && !fs && !ac);
  SET_SENSITIVE ("layers-delete",          layer && !ac);

  SET_SENSITIVE ("layers-select-top",      layer && !fs && !ac && prev);
  SET_SENSITIVE ("layers-select-bottom",   layer && !fs && !ac && next);
  SET_SENSITIVE ("layers-select-previous", layer && !fs && !ac && prev);
  SET_SENSITIVE ("layers-select-next",     layer && !fs && !ac && next);

  SET_SENSITIVE ("layers-raise",           layer && !fs && !ac && prev);
  SET_SENSITIVE ("layers-raise-to-top",    layer && !fs && !ac && prev);
  SET_SENSITIVE ("layers-lower",           layer && !fs && !ac && next);
  SET_SENSITIVE ("layers-lower-to-bottom", layer && !fs && !ac && next);

  SET_SENSITIVE ("layers-anchor",          layer &&  fs && !ac);
  SET_SENSITIVE ("layers-merge-down",      layer && !fs && !ac && next);
  SET_SENSITIVE ("layers-merge-layers",    layer && !fs && !ac);
  SET_SENSITIVE ("layers-flatten-image",   layer && !fs && !ac);

  SET_VISIBLE   ("layers-text-discard",             text_layer && !ac);
  SET_VISIBLE   ("layers-text-to-vectors",          text_layer && !ac);
  SET_VISIBLE   ("layers-text-along-vectors",       text_layer && !ac);
  SET_VISIBLE   ("layers-text-selection-replace",   text_layer && !ac);
  SET_VISIBLE   ("layers-text-selection-add",       text_layer && !ac);
  SET_VISIBLE   ("layers-text-selection-subtract",  text_layer && !ac);
  SET_VISIBLE   ("layers-text-selection-intersect", text_layer && !ac);

  SET_SENSITIVE ("layers-resize",          layer && !ac);
  SET_SENSITIVE ("layers-resize-to-image", layer && !ac);
  SET_SENSITIVE ("layers-scale",           layer && !ac);

  SET_SENSITIVE ("layers-crop",            layer && sel);

  SET_SENSITIVE ("layers-alpha-add",       layer && !fs && !alpha);
  SET_SENSITIVE ("layers-alpha-remove",    layer && !fs &&  alpha);

  SET_SENSITIVE ("layers-lock-alpha", layer);
  SET_ACTIVE    ("layers-lock-alpha", lock_alpha);

  SET_SENSITIVE ("layers-mask-add",    layer && !fs && !ac && !mask);
  SET_SENSITIVE ("layers-mask-apply",  layer && !fs && !ac &&  mask);
  SET_SENSITIVE ("layers-mask-delete", layer && !fs && !ac &&  mask);

  SET_SENSITIVE ("layers-mask-edit",    layer && !fs && !ac &&  mask);
  SET_SENSITIVE ("layers-mask-show",    layer && !fs && !ac &&  mask);
  SET_SENSITIVE ("layers-mask-disable", layer && !fs && !ac &&  mask);

  SET_ACTIVE ("layers-mask-edit",    mask && gimp_layer_mask_get_edit (mask));
  SET_ACTIVE ("layers-mask-show",    mask && gimp_layer_mask_get_show (mask));
  SET_ACTIVE ("layers-mask-disable", mask && !gimp_layer_mask_get_apply (mask));

  SET_SENSITIVE ("layers-mask-selection-replace",   layer && !fs && !ac && mask);
  SET_SENSITIVE ("layers-mask-selection-add",       layer && !fs && !ac && mask);
  SET_SENSITIVE ("layers-mask-selection-subtract",  layer && !fs && !ac && mask);
  SET_SENSITIVE ("layers-mask-selection-intersect", layer && !fs && !ac && mask);

  SET_SENSITIVE ("layers-alpha-selection-replace",   layer && !fs && !ac);
  SET_SENSITIVE ("layers-alpha-selection-add",       layer && !fs && !ac);
  SET_SENSITIVE ("layers-alpha-selection-subtract",  layer && !fs && !ac);
  SET_SENSITIVE ("layers-alpha-selection-intersect", layer && !fs && !ac);

#undef SET_VISIBLE
#undef SET_SENSITIVE
#undef SET_ACTIVE
}
Example #23
0
GeglBuffer *
gimp_drawable_transform_cut (GimpDrawable *drawable,
                             GimpContext  *context,
                             gint         *offset_x,
                             gint         *offset_y,
                             gboolean     *new_layer)
{
  GimpImage  *image;
  GeglBuffer *buffer;

  g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), NULL);
  g_return_val_if_fail (gimp_item_is_attached (GIMP_ITEM (drawable)), NULL);
  g_return_val_if_fail (GIMP_IS_CONTEXT (context), NULL);
  g_return_val_if_fail (offset_x != NULL, NULL);
  g_return_val_if_fail (offset_y != NULL, NULL);
  g_return_val_if_fail (new_layer != NULL, NULL);

  image = gimp_item_get_image (GIMP_ITEM (drawable));

  /*  extract the selected mask if there is a selection  */
  if (! gimp_channel_is_empty (gimp_image_get_mask (image)))
    {
      gint x, y, w, h;

      /* set the keep_indexed flag to FALSE here, since we use
       * gimp_layer_new_from_buffer() later which assumes that the buffer
       * are either RGB or GRAY.  Eeek!!!              (Sven)
       */
      if (gimp_item_mask_intersect (GIMP_ITEM (drawable), &x, &y, &w, &h))
        {
          buffer = gimp_selection_extract (GIMP_SELECTION (gimp_image_get_mask (image)),
                                           GIMP_PICKABLE (drawable),
                                           context,
                                           TRUE, FALSE, TRUE,
                                           offset_x, offset_y,
                                           NULL);
          /*  clear the selection  */
          gimp_channel_clear (gimp_image_get_mask (image), NULL, TRUE);

          *new_layer = TRUE;
        }
      else
        {
          buffer = NULL;
          *new_layer = FALSE;
        }
    }
  else  /*  otherwise, just copy the layer  */
    {
      buffer = gimp_selection_extract (GIMP_SELECTION (gimp_image_get_mask (image)),
                                       GIMP_PICKABLE (drawable),
                                       context,
                                       FALSE, TRUE, GIMP_IS_LAYER (drawable),
                                       offset_x, offset_y,
                                       NULL);

      *new_layer = FALSE;
    }

  return buffer;
}
Example #24
0
/*  Similar to gimp_drawable_apply_region but works in "replace" mode (i.e.
 *  transparent pixels in src2 make the result transparent rather than
 *  opaque.
 *
 * Takes an additional mask pixel region as well.
 */
void
gimp_drawable_real_replace_region (GimpDrawable *drawable,
                                   PixelRegion  *src2PR,
                                   gboolean      push_undo,
                                   const gchar  *undo_desc,
                                   gdouble       opacity,
                                   PixelRegion  *maskPR,
                                   gint          x,
                                   gint          y)
{
  GimpItem        *item  = GIMP_ITEM (drawable);
  GimpImage       *image = gimp_item_get_image (item);
  GimpChannel     *mask  = gimp_image_get_mask (image);
  gint             x1, y1, x2, y2;
  gint             offset_x, offset_y;
  PixelRegion      src1PR, destPR;
  CombinationMode  operation;
  gboolean         active_components[MAX_CHANNELS];

  /*  don't apply the mask to itself and don't apply an empty mask  */
  if (GIMP_DRAWABLE (mask) == drawable || gimp_channel_is_empty (mask))
    mask = NULL;

  /*  configure the active channel array  */
  gimp_drawable_get_active_components (drawable, active_components);

  /*  determine what sort of operation is being attempted and
   *  if it's actually legal...
   */
  operation = gimp_image_get_combination_mode (gimp_drawable_type (drawable),
                                               src2PR->bytes);
  if (operation == -1)
    {
      g_warning ("%s: illegal parameters.", G_STRFUNC);
      return;
    }

  /*  get the layer offsets  */
  gimp_item_get_offset (item, &offset_x, &offset_y);

  /*  make sure the image application coordinates are within drawable bounds  */
  x1 = CLAMP (x, 0,             gimp_item_get_width  (item));
  y1 = CLAMP (y, 0,             gimp_item_get_height (item));
  x2 = CLAMP (x + src2PR->w, 0, gimp_item_get_width  (item));
  y2 = CLAMP (y + src2PR->h, 0, gimp_item_get_height (item));

  if (mask)
    {
      GimpItem *mask_item = GIMP_ITEM (mask);

      /*  make sure coordinates are in mask bounds ...
       *  we need to add the layer offset to transform coords
       *  into the mask coordinate system
       */
      x1 = CLAMP (x1, -offset_x, gimp_item_get_width  (mask_item) - offset_x);
      y1 = CLAMP (y1, -offset_y, gimp_item_get_height (mask_item) - offset_y);
      x2 = CLAMP (x2, -offset_x, gimp_item_get_width  (mask_item) - offset_x);
      y2 = CLAMP (y2, -offset_y, gimp_item_get_height (mask_item) - offset_y);
    }

  /*  If the calling procedure specified an undo step...  */
  if (push_undo)
    gimp_drawable_push_undo (drawable, undo_desc,
                             x1, y1,
                             x2 - x1, y2 - y1,
                             NULL, FALSE);

  /* configure the pixel regions */
  pixel_region_init (&src1PR, gimp_drawable_get_tiles (drawable),
                     x1, y1, x2 - x1, y2 - y1,
                     FALSE);
  pixel_region_init (&destPR, gimp_drawable_get_tiles (drawable),
                     x1, y1, x2 - x1, y2 - y1,
                     TRUE);
  pixel_region_resize (src2PR,
                       src2PR->x + (x1 - x), src2PR->y + (y1 - y),
                       x2 - x1, y2 - y1);

  if (mask)
    {
      PixelRegion  mask2PR, tempPR;
      guchar      *temp_data;

      pixel_region_init (&mask2PR,
                         gimp_drawable_get_tiles (GIMP_DRAWABLE (mask)),
                         x1 + offset_x,
                         y1 + offset_y,
                         x2 - x1, y2 - y1,
                         FALSE);

      temp_data = g_malloc ((y2 - y1) * (x2 - x1));

      pixel_region_init_data (&tempPR, temp_data, 1, x2 - x1,
                              0, 0, x2 - x1, y2 - y1);

      copy_region (&mask2PR, &tempPR);

      pixel_region_init_data (&tempPR, temp_data, 1, x2 - x1,
                              0, 0, x2 - x1, y2 - y1);

      apply_mask_to_region (&tempPR, maskPR, OPAQUE_OPACITY);

      pixel_region_init_data (&tempPR, temp_data, 1, x2 - x1,
                              0, 0, x2 - x1, y2 - y1);

      combine_regions_replace (&src1PR, src2PR, &destPR, &tempPR, NULL,
                               opacity * 255.999,
                               active_components,
                               operation);

      g_free (temp_data);
    }
  else
    {
      combine_regions_replace (&src1PR, src2PR, &destPR, maskPR, NULL,
                               opacity * 255.999,
                               active_components,
                               operation);
    }
}
Example #25
0
static void
gimp_move_tool_cursor_update (GimpTool         *tool,
                              const GimpCoords *coords,
                              GdkModifierType   state,
                              GimpDisplay      *display)
{
  GimpMoveOptions    *options     = GIMP_MOVE_TOOL_GET_OPTIONS (tool);
  GimpDisplayShell   *shell       = gimp_display_get_shell (display);
  GimpImage          *image       = gimp_display_get_image (display);
  GimpCursorType      cursor      = GIMP_CURSOR_MOUSE;
  GimpToolCursorType  tool_cursor = GIMP_TOOL_CURSOR_MOVE;
  GimpCursorModifier  modifier    = GIMP_CURSOR_MODIFIER_NONE;

  if (options->move_type == GIMP_TRANSFORM_TYPE_PATH)
    {
      tool_cursor = GIMP_TOOL_CURSOR_PATHS;
      modifier    = GIMP_CURSOR_MODIFIER_MOVE;

      if (options->move_current)
        {
          if (! gimp_image_get_active_vectors (image))
            modifier = GIMP_CURSOR_MODIFIER_BAD;
        }
      else
        {
          if (gimp_draw_tool_on_vectors (GIMP_DRAW_TOOL (tool), display,
                                         coords, 7, 7,
                                         NULL, NULL, NULL, NULL, NULL, NULL))
            {
              tool_cursor = GIMP_TOOL_CURSOR_HAND;
            }
          else
            {
              modifier = GIMP_CURSOR_MODIFIER_BAD;
            }
        }
    }
  else if (options->move_type == GIMP_TRANSFORM_TYPE_SELECTION)
    {
      tool_cursor = GIMP_TOOL_CURSOR_RECT_SELECT;
      modifier    = GIMP_CURSOR_MODIFIER_MOVE;

      if (gimp_channel_is_empty (gimp_image_get_mask (image)))
        modifier = GIMP_CURSOR_MODIFIER_BAD;
    }
  else if (options->move_current)
    {
      if (! gimp_image_get_active_drawable (image))
        modifier = GIMP_CURSOR_MODIFIER_BAD;
    }
  else
    {
      GimpGuide  *guide;
      GimpLayer  *layer;
      const gint  snap_distance = display->config->snap_distance;

      if (gimp_display_shell_get_show_guides (shell) &&
          (guide = gimp_image_find_guide (image, coords->x, coords->y,
                                          FUNSCALEX (shell, snap_distance),
                                          FUNSCALEY (shell, snap_distance))))
        {
          tool_cursor = GIMP_TOOL_CURSOR_HAND;
          modifier    = GIMP_CURSOR_MODIFIER_MOVE;
        }
      else if ((layer = gimp_image_pick_layer (image,
                                               coords->x, coords->y)))
        {
          /*  if there is a floating selection, and this aint it...  */
          if (gimp_image_get_floating_selection (image) &&
              ! gimp_layer_is_floating_sel (layer))
            {
              tool_cursor = GIMP_TOOL_CURSOR_MOVE;
              modifier    = GIMP_CURSOR_MODIFIER_ANCHOR;
            }
          else if (layer != gimp_image_get_active_layer (image))
            {
              tool_cursor = GIMP_TOOL_CURSOR_HAND;
              modifier    = GIMP_CURSOR_MODIFIER_MOVE;
            }
        }
      else
        {
          modifier = GIMP_CURSOR_MODIFIER_BAD;
        }
    }

  gimp_tool_control_set_cursor          (tool->control, cursor);
  gimp_tool_control_set_tool_cursor     (tool->control, tool_cursor);
  gimp_tool_control_set_cursor_modifier (tool->control, modifier);

  GIMP_TOOL_CLASS (parent_class)->cursor_update (tool, coords, state, display);
}
Example #26
0
void
gimp_drawable_real_apply_region (GimpDrawable         *drawable,
                                 PixelRegion          *src2PR,
                                 gboolean              push_undo,
                                 const gchar          *undo_desc,
                                 gdouble               opacity,
                                 GimpLayerModeEffects  mode,
                                 TileManager          *src1_tiles,
                                 PixelRegion          *destPR,
                                 gint                  x,
                                 gint                  y)
{
  GimpItem        *item  = GIMP_ITEM (drawable);
  GimpImage       *image = gimp_item_get_image (item);
  GimpChannel     *mask  = gimp_image_get_mask (image);
  gint             x1, y1, x2, y2;
  gint             offset_x, offset_y;
  PixelRegion      src1PR, my_destPR;
  CombinationMode  operation;
  gboolean         active_components[MAX_CHANNELS];

  /*  don't apply the mask to itself and don't apply an empty mask  */
  if (GIMP_DRAWABLE (mask) == drawable || gimp_channel_is_empty (mask))
    mask = NULL;

  /*  configure the active channel array  */
  gimp_drawable_get_active_components (drawable, active_components);

  /*  determine what sort of operation is being attempted and
   *  if it's actually legal...
   */
  operation = gimp_image_get_combination_mode (gimp_drawable_type (drawable),
                                               src2PR->bytes);
  if (operation == -1)
    {
      g_warning ("%s: illegal parameters.", G_STRFUNC);
      return;
    }

  /*  get the layer offsets  */
  gimp_item_get_offset (item, &offset_x, &offset_y);

  /*  make sure the image application coordinates are within drawable bounds  */
  x1 = CLAMP (x,             0, gimp_item_get_width  (item));
  y1 = CLAMP (y,             0, gimp_item_get_height (item));
  x2 = CLAMP (x + src2PR->w, 0, gimp_item_get_width  (item));
  y2 = CLAMP (y + src2PR->h, 0, gimp_item_get_height (item));

  if (mask)
    {
      GimpItem *mask_item = GIMP_ITEM (mask);

      /*  make sure coordinates are in mask bounds ...
       *  we need to add the layer offset to transform coords
       *  into the mask coordinate system
       */
      x1 = CLAMP (x1, -offset_x, gimp_item_get_width  (mask_item) - offset_x);
      y1 = CLAMP (y1, -offset_y, gimp_item_get_height (mask_item) - offset_y);
      x2 = CLAMP (x2, -offset_x, gimp_item_get_width  (mask_item) - offset_x);
      y2 = CLAMP (y2, -offset_y, gimp_item_get_height (mask_item) - offset_y);
    }

  /*  If the calling procedure specified an undo step...  */
  if (push_undo)
    {
      GimpDrawableUndo *undo;

      gimp_drawable_push_undo (drawable, undo_desc,
                               x1, y1,
                               x2 - x1, y2 - y1,
                               NULL, FALSE);

      undo = GIMP_DRAWABLE_UNDO (gimp_image_undo_get_fadeable (image));

      if (undo)
        {
          PixelRegion tmp_srcPR;
          PixelRegion tmp_destPR;

          undo->paint_mode = mode;
          undo->opacity    = opacity;
          undo->src2_tiles = tile_manager_new (x2 - x1, y2 - y1,
                                               src2PR->bytes);

          tmp_srcPR = *src2PR;
          pixel_region_resize (&tmp_srcPR,
                               src2PR->x + (x1 - x), src2PR->y + (y1 - y),
                               x2 - x1, y2 - y1);
          pixel_region_init (&tmp_destPR, undo->src2_tiles,
                             0, 0,
                             x2 - x1, y2 - y1, TRUE);

          copy_region (&tmp_srcPR, &tmp_destPR);
        }
    }

  /* configure the pixel regions */

  /* check if an alternative to using the drawable's data as src1 was
   * provided...
   */
  if (src1_tiles)
    {
      pixel_region_init (&src1PR, src1_tiles,
                         x1, y1, x2 - x1, y2 - y1,
                         FALSE);
    }
  else
    {
      pixel_region_init (&src1PR, gimp_drawable_get_tiles (drawable),
                         x1, y1, x2 - x1, y2 - y1,
                         FALSE);
    }

  /* check if an alternative to using the drawable's data as dest was
   * provided...
   */
  if (!destPR)
    {
      pixel_region_init (&my_destPR, gimp_drawable_get_tiles (drawable),
                         x1, y1, x2 - x1, y2 - y1,
                         TRUE);
      destPR = &my_destPR;
    }

  pixel_region_resize (src2PR,
                       src2PR->x + (x1 - x), src2PR->y + (y1 - y),
                       x2 - x1, y2 - y1);

  if (mask)
    {
      PixelRegion maskPR;

      pixel_region_init (&maskPR,
                         gimp_drawable_get_tiles (GIMP_DRAWABLE (mask)),
                         x1 + offset_x,
                         y1 + offset_y,
                         x2 - x1, y2 - y1,
                         FALSE);

      combine_regions (&src1PR, src2PR, destPR, &maskPR, NULL,
                       opacity * 255.999,
                       mode,
                       active_components,
                       operation);
    }
  else
    {
      combine_regions (&src1PR, src2PR, destPR, NULL, NULL,
                       opacity * 255.999,
                       mode,
                       active_components,
                       operation);
    }
}
Example #27
0
GimpLayer *
text_render (GimpImage    *image,
             GimpDrawable *drawable,
             GimpContext  *context,
             gint          text_x,
             gint          text_y,
             const gchar  *fontname,
             const gchar  *text,
             gint          border,
             gboolean      antialias)
{
  PangoFontDescription *desc;
  GimpText             *gtext;
  GimpLayer            *layer;
  GimpRGB               color;
  gchar                *font;
  gdouble               size;

  g_return_val_if_fail (GIMP_IS_IMAGE (image), NULL);
  g_return_val_if_fail (drawable == NULL || GIMP_IS_DRAWABLE (drawable), NULL);
  g_return_val_if_fail (drawable == NULL ||
                        gimp_item_is_attached (GIMP_ITEM (drawable)), NULL);
  g_return_val_if_fail (GIMP_IS_CONTEXT (context), NULL);
  g_return_val_if_fail (fontname != NULL, NULL);
  g_return_val_if_fail (text != NULL, NULL);

  if (border < 0)
    border = 0;

  desc = pango_font_description_from_string (fontname);
  size = PANGO_PIXELS (pango_font_description_get_size (desc));

  pango_font_description_unset_fields (desc, PANGO_FONT_MASK_SIZE);
  font = pango_font_description_to_string (desc);

  pango_font_description_free (desc);

  gimp_context_get_foreground (context, &color);

  gtext = g_object_new (GIMP_TYPE_TEXT,
                        "text",      text,
                        "font",      font,
                        "font-size", size,
                        "antialias", antialias,
                        "border",    border,
                        "color",     &color,
                        NULL);

  g_free (font);

  layer = gimp_text_layer_new (image, gtext);

  g_object_unref (gtext);

  if (!layer)
    return NULL;

  /*  Start a group undo  */
  gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_TEXT,
                               _("Add Text Layer"));

  /*  Set the layer offsets  */
  gimp_item_set_offset (GIMP_ITEM (layer), text_x, text_y);

  /*  If there is a selection mask clear it--
   *  this might not always be desired, but in general,
   *  it seems like the correct behavior.
   */
  if (! gimp_channel_is_empty (gimp_image_get_mask (image)))
    gimp_channel_clear (gimp_image_get_mask (image), NULL, TRUE);

  if (drawable == NULL)
    {
      /*  If the drawable is NULL, create a new layer  */
      gimp_image_add_layer (image, layer, NULL, -1, TRUE);
    }
  else
    {
      /*  Otherwise, instantiate the text as the new floating selection */
      floating_sel_attach (layer, drawable);
    }

  /*  end the group undo  */
  gimp_image_undo_group_end (image);

  return layer;
}
Example #28
0
gboolean
gimp_paint_core_start (GimpPaintCore     *core,
                       GimpDrawable      *drawable,
                       GimpPaintOptions  *paint_options,
                       const GimpCoords  *coords,
                       GError           **error)
{
  GimpItem *item;

  g_return_val_if_fail (GIMP_IS_PAINT_CORE (core), FALSE);
  g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), FALSE);
  g_return_val_if_fail (gimp_item_is_attached (GIMP_ITEM (drawable)), FALSE);
  g_return_val_if_fail (GIMP_IS_PAINT_OPTIONS (paint_options), FALSE);
  g_return_val_if_fail (coords != NULL, FALSE);
  g_return_val_if_fail (error == NULL || *error == NULL, FALSE);

  item = GIMP_ITEM (drawable);

  if (core->stroke_buffer)
    {
      g_array_free (core->stroke_buffer, TRUE);
      core->stroke_buffer = NULL;
    }

  core->stroke_buffer = g_array_sized_new (TRUE, TRUE,
                                           sizeof (GimpCoords),
                                           STROKE_BUFFER_INIT_SIZE);

  core->cur_coords = *coords;

  if (! GIMP_PAINT_CORE_GET_CLASS (core)->start (core, drawable,
                                                 paint_options,
                                                 coords, error))
    {
      return FALSE;
    }

  /*  Allocate the undo structure  */
  if (core->undo_buffer)
    g_object_unref (core->undo_buffer);

  core->undo_buffer = gegl_buffer_dup (gimp_drawable_get_buffer (drawable));

  /*  Allocate the saved proj structure  */
  if (core->saved_proj_buffer)
    {
      g_object_unref (core->saved_proj_buffer);
      core->saved_proj_buffer = NULL;
    }

  if (core->use_saved_proj)
    {
      GimpImage    *image    = gimp_item_get_image (item);
      GimpPickable *pickable = GIMP_PICKABLE (gimp_image_get_projection (image));
      GeglBuffer   *buffer   = gimp_pickable_get_buffer (pickable);

      core->saved_proj_buffer = gegl_buffer_dup (buffer);
    }

  /*  Allocate the canvas blocks structure  */
  if (core->canvas_buffer)
    g_object_unref (core->canvas_buffer);

  core->canvas_buffer =
    gegl_buffer_new (GEGL_RECTANGLE (0, 0,
                                     gimp_item_get_width  (item),
                                     gimp_item_get_height (item)),
                     babl_format ("Y u8"));

  /*  Get the initial undo extents  */

  core->x1 = core->x2 = core->cur_coords.x;
  core->y1 = core->y2 = core->cur_coords.y;

  core->last_paint.x = -1e6;
  core->last_paint.y = -1e6;

  {
    GimpImage   *image;
    GimpChannel *mask;
    GeglBuffer  *mask_buffer = NULL;
    gint         offset_x    = 0;
    gint         offset_y    = 0;

    image = gimp_item_get_image (item);
    mask  = gimp_image_get_mask (image);

    /*  don't apply the mask to itself and don't apply an empty mask  */
    if (GIMP_DRAWABLE (mask) == drawable || gimp_channel_is_empty (mask))
      mask = NULL;

    if (mask)
      {
        mask_buffer = gimp_drawable_get_buffer (GIMP_DRAWABLE (mask));

        gimp_item_get_offset (item, &offset_x, &offset_y);
      }

    core->applicator =
      gimp_applicator_new (gimp_drawable_get_buffer (drawable),
                           gimp_drawable_get_active_mask (drawable),
                           mask_buffer,
                           -offset_x, -offset_y);
  }

  /*  Freeze the drawable preview so that it isn't constantly updated.  */
  gimp_viewable_preview_freeze (GIMP_VIEWABLE (drawable));

  return TRUE;
}
Example #29
0
static GeglBuffer *
gradient_precalc_shapeburst (GimpImage           *image,
                             GimpDrawable        *drawable,
                             const GeglRectangle *region,
                             gdouble              dist,
                             GimpProgress        *progress)
{
  GimpChannel *mask;
  GeglBuffer  *dist_buffer;
  GeglBuffer  *temp_buffer;
  GeglNode    *shapeburst;
  gdouble      max;
  gfloat       max_iteration;

  gimp_progress_set_text (progress, _("Calculating distance map"));

  /*  allocate the distance map  */
  dist_buffer = gegl_buffer_new (GEGL_RECTANGLE (0, 0,
                                                 region->width, region->height),
                                 babl_format ("Y float"));

  /*  allocate the selection mask copy
   *  XXX: its format should be the same of gimp:shapeburst input buffer
   *       porting the op to 'float' should be reflected here as well
   */
  temp_buffer = gegl_buffer_new (GEGL_RECTANGLE (0, 0,
                                                 region->width, region->height),
                                 babl_format ("Y u8"));

  mask = gimp_image_get_mask (image);

  /*  If the image mask is not empty, use it as the shape burst source  */
  if (! gimp_channel_is_empty (mask))
    {
      gint x, y, width, height;
      gint off_x, off_y;

      gimp_item_mask_intersect (GIMP_ITEM (drawable), &x, &y, &width, &height);
      gimp_item_get_offset (GIMP_ITEM (drawable), &off_x, &off_y);

      /*  copy the mask to the temp mask  */
      gegl_buffer_copy (gimp_drawable_get_buffer (GIMP_DRAWABLE (mask)),
                        GEGL_RECTANGLE (x + off_x, y + off_y, width, height),
                        temp_buffer,
                        GEGL_RECTANGLE (0, 0, 0, 0));
    }
  else
    {
      /*  If the intended drawable has an alpha channel, use that  */
      if (gimp_drawable_has_alpha (drawable))
        {
          const Babl *component_format;

          component_format = babl_format ("A u8");

          /*  extract the aplha into the temp mask  */
          gegl_buffer_set_format (temp_buffer, component_format);
          gegl_buffer_copy (gimp_drawable_get_buffer (drawable),
                            GEGL_RECTANGLE (region->x, region->y,
                                            region->width, region->height),
                            temp_buffer,
                            GEGL_RECTANGLE (0, 0, 0, 0));
          gegl_buffer_set_format (temp_buffer, NULL);
        }
      else
        {
          GeglColor *white = gegl_color_new ("white");

          /*  Otherwise, just fill the shapeburst to white  */
          gegl_buffer_set_color (temp_buffer, NULL, white);
          g_object_unref (white);
        }
    }

  shapeburst = gegl_node_new_child (NULL,
                                    "operation", "gimp:shapeburst",
                                    NULL);

  gimp_gegl_progress_connect (shapeburst, progress, NULL);

  gimp_gegl_apply_operation (temp_buffer, NULL, NULL,
                             shapeburst,
                             dist_buffer, NULL);

  gegl_node_get (shapeburst, "max-iterations", &max, NULL);

  g_object_unref (shapeburst);

  max_iteration = max;

  g_object_unref (temp_buffer);

  /*  normalize the shapeburst with the max iteration  */
  if (max_iteration > 0)
    {
      GeglBufferIterator *iter;

      iter = gegl_buffer_iterator_new (dist_buffer, NULL, 0, NULL,
                                       GEGL_BUFFER_READWRITE, GEGL_ABYSS_NONE);

      while (gegl_buffer_iterator_next (iter))
        {
          gint    count = iter->length;
          gfloat *data  = iter->data[0];

          while (count--)
            *data++ /= max_iteration;
        }
    }

  return dist_buffer;
}
Example #30
0
void
image_actions_update (GimpActionGroup *group,
                      gpointer         data)
{
  GimpImage *image       = action_data_get_image (data);
  gboolean   is_indexed  = FALSE;
  gboolean   is_u8_gamma = FALSE;
  gboolean   aux         = FALSE;
  gboolean   lp          = FALSE;
  gboolean   sel         = FALSE;
  gboolean   groups      = FALSE;
  gboolean   profile     = FALSE;

  if (image)
    {
      GimpContainer *layers;
      const gchar   *action = NULL;

      switch (gimp_image_get_base_type (image))
        {
        case GIMP_RGB:     action = "image-convert-rgb";       break;
        case GIMP_GRAY:    action = "image-convert-grayscale"; break;
        case GIMP_INDEXED: action = "image-convert-indexed";   break;
        }

      gimp_action_group_set_action_active (group, action, TRUE);

      switch (gimp_image_get_precision (image))
        {
        case GIMP_PRECISION_U8_LINEAR:
          action = "image-convert-u8-linear";
          break;
        case GIMP_PRECISION_U8_GAMMA:
          action = "image-convert-u8-gamma";
          break;
        case GIMP_PRECISION_U16_LINEAR:
          action = "image-convert-u16-linear";
          break;
        case GIMP_PRECISION_U16_GAMMA:
          action = "image-convert-u16-gamma";
          break;
        case GIMP_PRECISION_U32_LINEAR:
          action = "image-convert-u32-linear";
          break;
        case GIMP_PRECISION_U32_GAMMA:
          action = "image-convert-u32-gamma";
          break;
        case GIMP_PRECISION_HALF_LINEAR:
          action = "image-convert-half-linear";
          break;
        case GIMP_PRECISION_HALF_GAMMA:
          action = "image-convert-half-gamma";
          break;
        case GIMP_PRECISION_FLOAT_LINEAR:
          action = "image-convert-float-linear";
          break;
        case GIMP_PRECISION_FLOAT_GAMMA:
          action = "image-convert-float-gamma";
          break;
        case GIMP_PRECISION_DOUBLE_LINEAR:
          action = "image-convert-double-linear";
          break;
        case GIMP_PRECISION_DOUBLE_GAMMA:
          action = "image-convert-double-gamma";
          break;
        }

      gimp_action_group_set_action_active (group, action, TRUE);

      is_indexed  = (gimp_image_get_base_type (image) == GIMP_INDEXED);
      is_u8_gamma = (gimp_image_get_precision (image) ==
                     GIMP_PRECISION_U8_GAMMA);
      aux         = (gimp_image_get_active_channel (image) != NULL);
      lp          = ! gimp_image_is_empty (image);
      sel         = ! gimp_channel_is_empty (gimp_image_get_mask (image));

      layers = gimp_image_get_layers (image);

      groups = ! gimp_item_stack_is_flat (GIMP_ITEM_STACK (layers));

      profile = (gimp_image_get_icc_parasite (image) != NULL);
    }

#define SET_SENSITIVE(action,condition) \
        gimp_action_group_set_action_sensitive (group, action, (condition) != 0)

  SET_SENSITIVE ("image-convert-rgb",       image);
  SET_SENSITIVE ("image-convert-grayscale", image);
  SET_SENSITIVE ("image-convert-indexed",   image && !groups && is_u8_gamma);

  SET_SENSITIVE ("image-convert-u8-gamma",      image);
  SET_SENSITIVE ("image-convert-u8-linear",     image && !is_indexed);
  SET_SENSITIVE ("image-convert-u16-gamma",     image && !is_indexed);
  SET_SENSITIVE ("image-convert-u16-linear",    image && !is_indexed);
  SET_SENSITIVE ("image-convert-u32-gamma",     image && !is_indexed);
  SET_SENSITIVE ("image-convert-u32-linear",    image && !is_indexed);
  SET_SENSITIVE ("image-convert-half-gamma",    image && !is_indexed);
  SET_SENSITIVE ("image-convert-half-linear",   image && !is_indexed);
  SET_SENSITIVE ("image-convert-float-gamma",   image && !is_indexed);
  SET_SENSITIVE ("image-convert-float-linear",  image && !is_indexed);
  SET_SENSITIVE ("image-convert-double-gamma",  image && !is_indexed);
  SET_SENSITIVE ("image-convert-double-linear", image && !is_indexed);

  SET_SENSITIVE ("image-color-profile-assign",  image);
  SET_SENSITIVE ("image-color-profile-convert", image);
  SET_SENSITIVE ("image-color-profile-discard", image && profile);

  SET_SENSITIVE ("image-flip-horizontal", image);
  SET_SENSITIVE ("image-flip-vertical",   image);
  SET_SENSITIVE ("image-rotate-90",       image);
  SET_SENSITIVE ("image-rotate-180",      image);
  SET_SENSITIVE ("image-rotate-270",      image);

  SET_SENSITIVE ("image-resize",              image);
  SET_SENSITIVE ("image-resize-to-layers",    image);
  SET_SENSITIVE ("image-resize-to-selection", image && sel);
  SET_SENSITIVE ("image-print-size",          image);
  SET_SENSITIVE ("image-scale",               image);
  SET_SENSITIVE ("image-crop-to-selection",   image && sel);
  SET_SENSITIVE ("image-crop-to-content",     image);
  SET_SENSITIVE ("image-duplicate",           image);
  SET_SENSITIVE ("image-merge-layers",        image && !aux && lp);
  SET_SENSITIVE ("image-flatten",             image && !aux && lp);
  SET_SENSITIVE ("image-configure-grid",      image);
  SET_SENSITIVE ("image-properties",          image);

#undef SET_SENSITIVE
}