Esempio n. 1
0
static GdkSegment *
gimp_region_select_tool_calculate (GimpRegionSelectTool *region_sel,
                                   GimpDisplay          *display,
                                   gint                 *num_segs)
{
  GimpTool                *tool    = GIMP_TOOL (region_sel);
  GimpRegionSelectOptions *options = GIMP_REGION_SELECT_TOOL_GET_OPTIONS (tool);
  GimpDisplayShell        *shell   = GIMP_DISPLAY_SHELL (display->shell);
  GimpDrawable            *drawable;
  GdkSegment              *segs;
  BoundSeg                *bsegs;
  PixelRegion              maskPR;

  drawable = gimp_image_get_active_drawable (display->image);

  gimp_display_shell_set_override_cursor (shell, GDK_WATCH);

  if (region_sel->region_mask)
    g_object_unref (region_sel->region_mask);

  region_sel->region_mask =
    GIMP_REGION_SELECT_TOOL_GET_CLASS (region_sel)->get_mask (region_sel,
                                                              display);

  if (! region_sel->region_mask)
    {
      gimp_display_shell_unset_override_cursor (shell);

      *num_segs = 0;
      return NULL;
    }

  /*  calculate and allocate a new segment array which represents the
   *  boundary of the contiguous region
   */
  pixel_region_init (&maskPR,
                     gimp_drawable_get_tiles (GIMP_DRAWABLE (region_sel->region_mask)),
                     0, 0,
                     gimp_item_width  (GIMP_ITEM (region_sel->region_mask)),
                     gimp_item_height (GIMP_ITEM (region_sel->region_mask)),
                     FALSE);

  bsegs = boundary_find (&maskPR, BOUNDARY_WITHIN_BOUNDS,
                         0, 0,
                         gimp_item_width  (GIMP_ITEM (region_sel->region_mask)),
                         gimp_item_height (GIMP_ITEM (region_sel->region_mask)),
                         BOUNDARY_HALF_WAY,
                         num_segs);

  segs = g_new (GdkSegment, *num_segs);

  gimp_display_shell_transform_segments (shell, bsegs, segs, *num_segs,
                                         ! options->sample_merged);
  g_free (bsegs);

  gimp_display_shell_unset_override_cursor (shell);

  return segs;
}
Esempio n. 2
0
void
gimp_layer_mask_set_show (GimpLayerMask *layer_mask,
                          gboolean       show,
                          gboolean       push_undo)
{
  g_return_if_fail (GIMP_IS_LAYER_MASK (layer_mask));

  if (layer_mask->show_mask != show)
    {
      GimpImage *image = GIMP_ITEM (layer_mask)->image;

      if (push_undo)
        gimp_image_undo_push_layer_mask_show (image, _("Show Layer Mask"),
                                              layer_mask);

      layer_mask->show_mask = show ? TRUE : FALSE;

      if (layer_mask->layer)
        {
          GimpDrawable *drawable = GIMP_DRAWABLE (layer_mask->layer);

          gimp_drawable_update (drawable,
                                0, 0,
                                gimp_item_width  (GIMP_ITEM (drawable)),
                                gimp_item_height (GIMP_ITEM (drawable)));
        }

      g_signal_emit (layer_mask, layer_mask_signals[SHOW_CHANGED], 0);
    }
}
Esempio n. 3
0
static void
gimp_image_map_tool_map (GimpImageMapTool *tool)
{
  GimpDisplayShell *shell = GIMP_DISPLAY_SHELL (GIMP_TOOL (tool)->display->shell);
  GimpItem         *item  = GIMP_ITEM (tool->drawable);
  gint              x, y;
  gint              w, h;
  gint              off_x, off_y;
  GeglRectangle     visible;

  GIMP_IMAGE_MAP_TOOL_GET_CLASS (tool)->map (tool);

  gimp_display_shell_untransform_viewport (shell, &x, &y, &w, &h);

  gimp_item_offsets (item, &off_x, &off_y);

  gimp_rectangle_intersect (x, y, w, h,
                            off_x,
                            off_y,
                            gimp_item_width  (item),
                            gimp_item_height (item),
                            &visible.x,
                            &visible.y,
                            &visible.width,
                            &visible.height);

  visible.x -= off_x;
  visible.y -= off_y;

  gimp_image_map_apply (tool->image_map, &visible);
}
Esempio n. 4
0
gboolean
gimp_item_is_in_set (GimpItem    *item,
                     GimpItemSet  set)
{
  g_return_val_if_fail (GIMP_IS_ITEM (item), FALSE);

  switch (set)
    {
    case GIMP_ITEM_SET_NONE:
      return FALSE;

    case GIMP_ITEM_SET_ALL:
      return TRUE;

    case GIMP_ITEM_SET_IMAGE_SIZED:
      return (gimp_item_width  (item) == gimp_image_get_width  (item->image) &&
              gimp_item_height (item) == gimp_image_get_height (item->image));

    case GIMP_ITEM_SET_VISIBLE:
      return gimp_item_get_visible (item);

    case GIMP_ITEM_SET_LINKED:
      return gimp_item_get_linked (item);
    }

  return FALSE;
}
Esempio n. 5
0
static GimpLayer *
select_layer_by_coords (GimpImage *image,
                        gint       x,
                        gint       y)
{
  GList *list;

  g_return_val_if_fail (GIMP_IS_IMAGE (image), NULL);

  for (list = GIMP_LIST (image->layers)->list;
       list;
       list = g_list_next (list))
    {
      GimpLayer *layer = list->data;
      gint       off_x, off_y;
      gint       width, height;

      if (! gimp_item_get_visible (GIMP_ITEM (layer)))
        continue;

      gimp_item_offsets (GIMP_ITEM (layer), &off_x, &off_y);
      width = gimp_item_width (GIMP_ITEM (layer));
      height = gimp_item_height (GIMP_ITEM (layer));

      if (off_x <= x &&
          off_y <= y &&
          x < off_x + width &&
          y < off_y + height)
        {
          return layer;
        }
    }

  return NULL;
}
Esempio n. 6
0
static TempBuf *
gimp_drawable_preview_private (GimpDrawable *drawable,
                               gint          width,
                               gint          height)
{
  TempBuf *ret_buf;

  if (! drawable->preview_valid ||
      ! (ret_buf = gimp_preview_cache_get (&drawable->preview_cache,
                                           width, height)))
    {
      GimpItem *item = GIMP_ITEM (drawable);

      ret_buf = gimp_drawable_get_sub_preview (drawable,
                                               0, 0,
                                               gimp_item_width (item),
                                               gimp_item_height (item),
                                               width,
                                               height);

      if (! drawable->preview_valid)
        gimp_preview_cache_invalidate (&drawable->preview_cache);

      drawable->preview_valid = TRUE;

      gimp_preview_cache_add (&drawable->preview_cache, ret_buf);
    }

  return ret_buf;
}
Esempio n. 7
0
/**
 * gimp_item_scale_by_factors:
 * @item:     Item to be transformed by explicit width and height factors.
 * @w_factor: scale factor to apply to width and horizontal offset
 * @h_factor: scale factor to apply to height and vertical offset
 * @interpolation:
 * @progress:
 *
 * Scales item dimensions and offsets by uniform width and
 * height factors.
 *
 * Use gimp_item_scale_by_factors() in circumstances when the same
 * width and height scaling factors are to be uniformly applied to a
 * set of items. In this context, the item's dimensions and offsets
 * from the sides of the containing image all change by these
 * predetermined factors. By fiat, the fixed point of the transform is
 * the upper left hand corner of the image. Returns #FALSE if a
 * requested scale factor is zero or if a scaling zero's out a item
 * dimension; returns #TRUE otherwise.
 *
 * Use gimp_item_scale() in circumstances where new item width
 * and height dimensions are predetermined instead.
 *
 * Side effects: Undo set created for item. Old item imagery
 *               scaled & painted to new item tiles.
 *
 * Returns: #TRUE, if the scaled item has positive dimensions
 *          #FALSE if the scaled item has at least one zero dimension
 **/
gboolean
gimp_item_scale_by_factors (GimpItem              *item,
                            gdouble                w_factor,
                            gdouble                h_factor,
                            GimpInterpolationType  interpolation,
                            GimpProgress          *progress)
{
  gint new_width, new_height;
  gint new_offset_x, new_offset_y;

  g_return_val_if_fail (GIMP_IS_ITEM (item), FALSE);
  g_return_val_if_fail (progress == NULL || GIMP_IS_PROGRESS (progress), FALSE);

  if (w_factor == 0.0 || h_factor == 0.0)
    {
      g_warning ("%s: requested width or height scale equals zero", G_STRFUNC);
      return FALSE;
    }

  new_offset_x = ROUND (w_factor * (gdouble) item->offset_x);
  new_offset_y = ROUND (h_factor * (gdouble) item->offset_y);
  new_width    = ROUND (w_factor * (gdouble) gimp_item_width  (item));
  new_height   = ROUND (h_factor * (gdouble) gimp_item_height (item));

  if (new_width != 0 && new_height != 0)
    {
      gimp_item_scale (item,
                       new_width, new_height,
                       new_offset_x, new_offset_y,
                       interpolation, progress);
      return TRUE;
    }

  return FALSE;
}
Esempio n. 8
0
void
gimp_layer_mask_set_apply (GimpLayerMask *layer_mask,
                           gboolean       apply,
                           gboolean       push_undo)
{
  g_return_if_fail (GIMP_IS_LAYER_MASK (layer_mask));

  if (layer_mask->apply_mask != apply)
    {
      GimpImage *image = GIMP_ITEM (layer_mask)->image;

      if (push_undo)
        gimp_image_undo_push_layer_mask_apply (image, _("Apply Layer Mask"),
                                               layer_mask);

      layer_mask->apply_mask = apply ? TRUE : FALSE;

      if (layer_mask->layer)
        {
          GimpDrawable *drawable = GIMP_DRAWABLE (layer_mask->layer);

          gimp_drawable_update (drawable,
                                0, 0,
                                gimp_item_width  (GIMP_ITEM (drawable)),
                                gimp_item_height (GIMP_ITEM (drawable)));
        }

      g_signal_emit (layer_mask, layer_mask_signals[APPLY_CHANGED], 0);
    }
}
Esempio n. 9
0
gboolean
gimp_item_get_popup_size (GimpViewable *viewable,
                          gint          width,
                          gint          height,
                          gboolean      dot_for_dot,
                          gint         *popup_width,
                          gint         *popup_height)
{
    GimpItem  *item  = GIMP_ITEM (viewable);
    GimpImage *image = gimp_item_get_image (item);

    if (image && ! image->gimp->config->layer_previews)
        return FALSE;

    if (gimp_item_width  (item) > width ||
            gimp_item_height (item) > height)
    {
        gboolean scaling_up;
        gdouble  xres = 1.0;
        gdouble  yres = 1.0;

        if (image)
            gimp_image_get_resolution (image, &xres, &yres);

        gimp_viewable_calc_preview_size (gimp_item_width  (item),
                                         gimp_item_height (item),
                                         width  * 2,
                                         height * 2,
                                         dot_for_dot,
                                         xres,
                                         yres,
                                         popup_width,
                                         popup_height,
                                         &scaling_up);

        if (scaling_up)
        {
            *popup_width = gimp_item_width  (item);
            *popup_width = gimp_item_height (item);
        }

        return TRUE;
    }

    return FALSE;
}
Esempio n. 10
0
static GimpItem *
gimp_item_real_duplicate (GimpItem *item,
                          GType     new_type)
{
  GimpItem *new_item;
  gchar    *new_name;

  g_return_val_if_fail (GIMP_IS_ITEM (item), NULL);
  g_return_val_if_fail (GIMP_IS_IMAGE (item->image), NULL);
  g_return_val_if_fail (g_type_is_a (new_type, GIMP_TYPE_ITEM), NULL);

  /*  formulate the new name  */
  {
    const gchar *name;
    gchar       *ext;
    gint         number;
    gint         len;

    name = gimp_object_get_name (GIMP_OBJECT (item));

    g_return_val_if_fail (name != NULL, NULL);

    ext = strrchr (name, '#');
    len = strlen (_("copy"));

    if ((strlen (name) >= len &&
         strcmp (&name[strlen (name) - len], _("copy")) == 0) ||
        (ext && (number = atoi (ext + 1)) > 0 &&
         ((int)(log10 (number) + 1)) == strlen (ext + 1)))
      {
        /* don't have redundant "copy"s */
        new_name = g_strdup (name);
      }
    else
      {
        new_name = g_strdup_printf (_("%s copy"), name);
      }
  }

  new_item = g_object_new (new_type, NULL);

  gimp_item_configure (new_item, gimp_item_get_image (item),
                       item->offset_x, item->offset_y,
                       gimp_item_width  (item),
                       gimp_item_height (item),
                       new_name);

  g_free (new_name);

  g_object_unref (new_item->parasites);
  new_item->parasites = gimp_parasite_list_copy (item->parasites);

  new_item->visible = gimp_item_get_visible (item);
  new_item->linked  = gimp_item_get_linked (item);

  return new_item;
}
Esempio n. 11
0
void
gimp_channel_select_round_rect (GimpChannel         *channel,
                                gint                 x,
                                gint                 y,
                                gint                 w,
                                gint                 h,
                                gdouble              corner_radius_x,
                                gdouble              corner_radius_y,
                                GimpChannelOps       op,
                                gboolean             antialias,
                                gboolean             feather,
                                gdouble              feather_radius_x,
                                gdouble              feather_radius_y,
                                gboolean             push_undo)
{
  g_return_if_fail (GIMP_IS_CHANNEL (channel));
  g_return_if_fail (gimp_item_is_attached (GIMP_ITEM (channel)));

  if (push_undo)
    gimp_channel_push_undo (channel, Q_("command|Rounded Rectangle Select"));

  /*  if applicable, replace the current selection  */
  if (op == GIMP_CHANNEL_OP_REPLACE)
    gimp_channel_clear (channel, NULL, FALSE);

  /*  if feathering for rect, make a new mask with the
   *  rectangle and feather that with the old mask
   */
  if (feather || op == GIMP_CHANNEL_OP_INTERSECT)
    {
      GimpItem    *item = GIMP_ITEM (channel);
      GimpChannel *add_on;

      add_on = gimp_channel_new_mask (gimp_item_get_image (item),
                                      gimp_item_width (item),
                                      gimp_item_height (item));
      gimp_channel_combine_ellipse_rect (add_on, GIMP_CHANNEL_OP_ADD,
                                         x, y, w, h,
                                         corner_radius_x, corner_radius_y,
                                         antialias);

      if (feather)
        gimp_channel_feather (add_on,
                              feather_radius_x,
                              feather_radius_y,
                              FALSE /* no undo */);

      gimp_channel_combine_mask (channel, add_on, op, 0, 0);
      g_object_unref (add_on);
    }
  else
    {
      gimp_channel_combine_ellipse_rect (channel, op, x, y, w, h,
                                         corner_radius_x, corner_radius_y,
                                         antialias);
    }
}
Esempio n. 12
0
/**
 * gimp_item_scale_by_origin:
 * @item:         The item to be transformed by width & height scale factors
 * @new_width:    The width that item will acquire
 * @new_height:   The height that the item will acquire
 * @interpolation:
 * @progress:
 * @local_origin: sets fixed point of the scaling transform. See below.
 *
 * Sets item dimensions to new_width and
 * new_height. Derives vertical and horizontal scaling
 * transforms from new width and height. If local_origin is
 * #TRUE, the fixed point of the scaling transform coincides
 * with the item's center point.  Otherwise, the fixed
 * point is taken to be [-item->offset_x, -item->offset_y].
 *
 * Since this function derives scale factors from new and
 * current item dimensions, these factors will vary from
 * item to item because of aliasing artifacts; factor
 * variations among items can be quite large where item
 * dimensions approach pixel dimensions. Use
 * gimp_item_scale_by_factors() where constant scales are to
 * be uniformly applied to a number of items.
 *
 * Side effects: undo set created for item.
 *               Old item imagery scaled
 *               & painted to new item tiles
 **/
void
gimp_item_scale_by_origin (GimpItem              *item,
                           gint                   new_width,
                           gint                   new_height,
                           GimpInterpolationType  interpolation,
                           GimpProgress          *progress,
                           gboolean               local_origin)
{
  gint new_offset_x, new_offset_y;

  g_return_if_fail (GIMP_IS_ITEM (item));
  g_return_if_fail (progress == NULL || GIMP_IS_PROGRESS (progress));

  if (new_width == 0 || new_height == 0)
    {
      g_warning ("%s: requested width or height equals zero", G_STRFUNC);
      return;
    }

  if (local_origin)
    {
      new_offset_x = (item->offset_x +
                      ((gimp_item_width  (item) - new_width)  / 2.0));
      new_offset_y = (item->offset_y +
                      ((gimp_item_height (item) - new_height) / 2.0));
    }
  else
    {
      new_offset_x = (gint) (((gdouble) new_width *
                              (gdouble) item->offset_x /
                              (gdouble) gimp_item_width (item)));

      new_offset_y = (gint) (((gdouble) new_height *
                              (gdouble) item->offset_y /
                              (gdouble) gimp_item_height (item)));
    }

  gimp_item_scale (item,
                   new_width, new_height,
                   new_offset_x, new_offset_y,
                   interpolation, progress);
}
Esempio n. 13
0
void
gimp_image_resize_to_layers (GimpImage    *image,
                             GimpContext  *context,
                             GimpProgress *progress)
{
  GList    *list = GIMP_LIST (image->layers)->list;
  GimpItem *item;
  gint      min_x, max_x;
  gint      min_y, max_y;

  if (!list)
    return;

  /* figure out starting values */
  item = list->data;
  min_x = item->offset_x;
  min_y = item->offset_y;
  max_x = item->offset_x + gimp_item_width  (item);
  max_y = item->offset_y + gimp_item_height (item);

  /*  Respect all layers  */
  for (list = g_list_next (list);
       list;
       list = g_list_next (list))
    {
      item = list->data;

      min_x = MIN (min_x, item->offset_x);
      min_y = MIN (min_y, item->offset_y);
      max_x = MAX (max_x, item->offset_x + gimp_item_width  (item));
      max_y = MAX (max_y, item->offset_y + gimp_item_height (item));
    }

  gimp_image_resize (image, context,
                     max_x - min_x, max_y - min_y,
                     - min_x, - min_y,
                     progress);
}
Esempio n. 14
0
void
floating_sel_restore (GimpLayer *layer,
                      gint       x,
                      gint       y,
                      gint       w,
                      gint       h)
{
  PixelRegion srcPR, destPR;
  gint        offx, offy;
  gint        x1, y1, x2, y2;

  g_return_if_fail (GIMP_IS_LAYER (layer));
  g_return_if_fail (gimp_layer_is_floating_sel (layer));

  /*  What this function does is "uncover" the specified area in the
   *  drawable that this floating selection obscures.  We do this so
   *  that either the floating selection can be removed or it can be
   *  translated
   */

  /*  Find the minimum area we need to uncover -- in image space  */
  gimp_item_offsets (GIMP_ITEM (layer->fs.drawable), &offx, &offy);

  x1 = MAX (GIMP_ITEM (layer)->offset_x, offx);
  y1 = MAX (GIMP_ITEM (layer)->offset_y, offy);
  x2 = MIN (GIMP_ITEM (layer)->offset_x + GIMP_ITEM (layer)->width,
            offx + gimp_item_width  (GIMP_ITEM (layer->fs.drawable)));
  y2 = MIN (GIMP_ITEM(layer)->offset_y + GIMP_ITEM (layer)->height,
            offy + gimp_item_height (GIMP_ITEM (layer->fs.drawable)));

  x1 = CLAMP (x, x1, x2);
  y1 = CLAMP (y, y1, y2);
  x2 = CLAMP (x + w, x1, x2);
  y2 = CLAMP (y + h, y1, y2);

  if ((x2 - x1) > 0 && (y2 - y1) > 0)
    {
      /*  Copy the area from the backing store to the drawable  */
      pixel_region_init (&srcPR, layer->fs.backing_store,
                         (x1 - GIMP_ITEM (layer)->offset_x),
                         (y1 - GIMP_ITEM (layer)->offset_y),
                         (x2 - x1), (y2 - y1), FALSE);
      pixel_region_init (&destPR, gimp_drawable_get_tiles (layer->fs.drawable),
                         (x1 - offx), (y1 - offy), (x2 - x1), (y2 - y1), TRUE);

      copy_region (&srcPR, &destPR);
    }
}
Esempio n. 15
0
void
gimp_item_get_preview_size (GimpViewable *viewable,
                            gint          size,
                            gboolean      is_popup,
                            gboolean      dot_for_dot,
                            gint         *width,
                            gint         *height)
{
    GimpItem  *item  = GIMP_ITEM (viewable);
    GimpImage *image = gimp_item_get_image (item);

    if (image && ! image->gimp->config->layer_previews && ! is_popup)
    {
        *width  = size;
        *height = size;
        return;
    }

    if (image && ! is_popup)
    {
        gdouble xres;
        gdouble yres;

        gimp_image_get_resolution (image, &xres, &yres);

        gimp_viewable_calc_preview_size (gimp_image_get_width  (image),
                                         gimp_image_get_height (image),
                                         size,
                                         size,
                                         dot_for_dot,
                                         xres,
                                         yres,
                                         width,
                                         height,
                                         NULL);
    }
    else
    {
        gimp_viewable_calc_preview_size (gimp_item_width  (item),
                                         gimp_item_height (item),
                                         size,
                                         size,
                                         dot_for_dot, 1.0, 1.0,
                                         width,
                                         height,
                                         NULL);
    }
}
Esempio n. 16
0
void
gimp_channel_select_channel (GimpChannel    *channel,
                             const gchar    *undo_desc,
                             GimpChannel    *add_on,
                             gint            offset_x,
                             gint            offset_y,
                             GimpChannelOps  op,
                             gboolean        feather,
                             gdouble         feather_radius_x,
                             gdouble         feather_radius_y)
{
  g_return_if_fail (GIMP_IS_CHANNEL (channel));
  g_return_if_fail (gimp_item_is_attached (GIMP_ITEM (channel)));
  g_return_if_fail (undo_desc != NULL);
  g_return_if_fail (GIMP_IS_CHANNEL (add_on));

  gimp_channel_push_undo (channel, undo_desc);

  /*  if applicable, replace the current selection  */
  if (op == GIMP_CHANNEL_OP_REPLACE)
    gimp_channel_clear (channel, NULL, FALSE);

  if (feather || op == GIMP_CHANNEL_OP_INTERSECT)
    {
      GimpItem    *item = GIMP_ITEM (channel);
      GimpChannel *add_on2;

      add_on2 = gimp_channel_new_mask (gimp_item_get_image (item),
                                       gimp_item_width (item),
                                       gimp_item_height (item));

      gimp_channel_combine_mask (add_on2, add_on, GIMP_CHANNEL_OP_ADD,
                                 offset_x, offset_y);

      if (feather)
        gimp_channel_feather (add_on2,
                              feather_radius_x,
                              feather_radius_y,
                              FALSE /* no undo */);

      gimp_channel_combine_mask (channel, add_on2, op, 0, 0);
      g_object_unref (add_on2);
    }
  else
    {
      gimp_channel_combine_mask (channel, add_on, op, offset_x, offset_y);
    }
}
Esempio n. 17
0
/*
 * Position the dropped item in the middle of the viewport.
 */
static void
gimp_display_shell_dnd_position_item (GimpDisplayShell *shell,
                                      GimpItem         *item)
{
  gint x, y;
  gint width, height;
  gint off_x, off_y;

  gimp_display_shell_untransform_viewport (shell, &x, &y, &width, &height);

  gimp_item_offsets (item, &off_x, &off_y);

  off_x = x + (width  - gimp_item_width  (item)) / 2 - off_x;
  off_y = y + (height - gimp_item_height (item)) / 2 - off_y;

  gimp_item_translate (item, off_x, off_y, FALSE);
}
Esempio n. 18
0
void
gimp_channel_select_scan_convert (GimpChannel     *channel,
                                  const gchar     *undo_desc,
                                  GimpScanConvert *scan_convert,
                                  gint             offset_x,
                                  gint             offset_y,
                                  GimpChannelOps   op,
                                  gboolean         antialias,
                                  gboolean         feather,
                                  gdouble          feather_radius_x,
                                  gdouble          feather_radius_y,
                                  gboolean         push_undo)
{
  GimpItem    *item;
  GimpChannel *add_on;

  g_return_if_fail (GIMP_IS_CHANNEL (channel));
  g_return_if_fail (gimp_item_is_attached (GIMP_ITEM (channel)));
  g_return_if_fail (undo_desc != NULL);
  g_return_if_fail (scan_convert != NULL);

  if (push_undo)
    gimp_channel_push_undo (channel, undo_desc);

  /*  if applicable, replace the current selection  */
  if (op == GIMP_CHANNEL_OP_REPLACE)
    gimp_channel_clear (channel, NULL, FALSE);

  item = GIMP_ITEM (channel);

  add_on = gimp_channel_new_mask (gimp_item_get_image (item),
                                  gimp_item_width (item),
                                  gimp_item_height (item));
  gimp_scan_convert_render (scan_convert,
                            gimp_drawable_get_tiles (GIMP_DRAWABLE (add_on)),
                            offset_x, offset_y, antialias);

  if (feather)
    gimp_channel_feather (add_on,
                          feather_radius_x,
                          feather_radius_y,
                          FALSE /* no undo */);

  gimp_channel_combine_mask (channel, add_on, op, 0, 0);
  g_object_unref (add_on);
}
Esempio n. 19
0
void
gimp_channel_select_alpha (GimpChannel    *channel,
                           GimpDrawable   *drawable,
                           GimpChannelOps  op,
                           gboolean        feather,
                           gdouble         feather_radius_x,
                           gdouble         feather_radius_y)
{
  GimpItem    *item;
  GimpChannel *add_on;
  gint         off_x, off_y;

  g_return_if_fail (GIMP_IS_CHANNEL (channel));
  g_return_if_fail (gimp_item_is_attached (GIMP_ITEM (channel)));
  g_return_if_fail (GIMP_IS_DRAWABLE (drawable));

  item = GIMP_ITEM (channel);

  if (gimp_drawable_has_alpha (drawable))
    {
      add_on = gimp_channel_new_from_alpha (gimp_item_get_image (item),
                                            drawable, NULL, NULL);
    }
  else
    {
      /*  no alpha is equivalent to completely opaque alpha,
       *  so simply select the whole layer's extents.  --mitch
       */
      add_on = gimp_channel_new_mask (gimp_item_get_image (item),
                                      gimp_item_width (GIMP_ITEM (drawable)),
                                      gimp_item_height (GIMP_ITEM (drawable)));
      gimp_channel_all (add_on, FALSE);
    }

  gimp_item_offsets (GIMP_ITEM (drawable), &off_x, &off_y);

  gimp_channel_select_channel (channel, _("Alpha to Selection"), add_on,
                               off_x, off_y,
                               op, feather,
                               feather_radius_x,
                               feather_radius_y);
  g_object_unref (add_on);
}
Esempio n. 20
0
TempBuf *
gimp_drawable_get_sub_preview (GimpDrawable *drawable,
                               gint          src_x,
                               gint          src_y,
                               gint          src_width,
                               gint          src_height,
                               gint          dest_width,
                               gint          dest_height)
{
  GimpItem    *item;
  GimpImage   *image;

  g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), NULL);
  g_return_val_if_fail (src_x >= 0, NULL);
  g_return_val_if_fail (src_y >= 0, NULL);
  g_return_val_if_fail (src_width  > 0, NULL);
  g_return_val_if_fail (src_height > 0, NULL);
  g_return_val_if_fail (dest_width  > 0, NULL);
  g_return_val_if_fail (dest_height > 0, NULL);

  item = GIMP_ITEM (drawable);

  g_return_val_if_fail ((src_x + src_width)  <= gimp_item_width  (item), NULL);
  g_return_val_if_fail ((src_y + src_height) <= gimp_item_height (item), NULL);

  image = gimp_item_get_image (item);

  if (! image->gimp->config->layer_previews)
    return NULL;

  if (GIMP_IMAGE_TYPE_BASE_TYPE (gimp_drawable_type (drawable)) == GIMP_INDEXED)
    return gimp_drawable_indexed_preview (drawable,
                                          gimp_image_get_colormap (image),
                                          src_x, src_y, src_width, src_height,
                                          dest_width, dest_height);

  return tile_manager_get_sub_preview (gimp_drawable_get_tiles (drawable),
                                       src_x, src_y, src_width, src_height,
                                       dest_width, dest_height);
}
Esempio n. 21
0
/**
 * gimp_item_check_scaling:
 * @item:       Item to check
 * @new_width:  proposed width of item, in pixels
 * @new_height: proposed height of item, in pixels
 *
 * Scales item dimensions, then snaps them to pixel centers
 *
 * Returns: #FALSE if any dimension reduces to zero as a result
 *          of this; otherwise, returns #TRUE.
 **/
gboolean
gimp_item_check_scaling (const GimpItem *item,
                         gint            new_width,
                         gint            new_height)
{
  GimpImage *image;
  gdouble    img_scale_w;
  gdouble    img_scale_h;
  gint       new_item_width;
  gint       new_item_height;

  g_return_val_if_fail (GIMP_IS_ITEM (item), FALSE);

  image = gimp_item_get_image (item);

  img_scale_w     = ((gdouble) new_width /
                     (gdouble) gimp_image_get_width (image));
  img_scale_h     = ((gdouble) new_height /
                     (gdouble) gimp_image_get_height (image));
  new_item_width  = ROUND (img_scale_w * (gdouble) gimp_item_width  (item));
  new_item_height = ROUND (img_scale_h * (gdouble) gimp_item_height (item));

  return (new_item_width > 0 && new_item_height > 0);
}
Esempio n. 22
0
const BoundSeg *
floating_sel_boundary (GimpLayer *layer,
                       gint      *n_segs)
{
  PixelRegion bPR;
  gint        i;

  g_return_val_if_fail (GIMP_IS_LAYER (layer), NULL);
  g_return_val_if_fail (gimp_layer_is_floating_sel (layer), NULL);
  g_return_val_if_fail (n_segs != NULL, NULL);

  if (layer->fs.boundary_known == FALSE)
    {
      gint width, height;
      gint off_x, off_y;

      width  = gimp_item_width  (GIMP_ITEM (layer));
      height = gimp_item_height (GIMP_ITEM (layer));
      gimp_item_offsets (GIMP_ITEM (layer), &off_x, &off_y);

      if (layer->fs.segs)
        g_free (layer->fs.segs);

      if (gimp_drawable_has_alpha (GIMP_DRAWABLE (layer)))
        {
          /*  find the segments  */
          pixel_region_init (&bPR,
                             gimp_drawable_get_tiles (GIMP_DRAWABLE (layer)),
                             0, 0, width, height, FALSE);
          layer->fs.segs = boundary_find (&bPR, BOUNDARY_WITHIN_BOUNDS,
                                          0, 0, width, height,
                                          BOUNDARY_HALF_WAY,
                                          &layer->fs.num_segs);

          /*  offset the segments  */
          for (i = 0; i < layer->fs.num_segs; i++)
            {
              layer->fs.segs[i].x1 += off_x;
              layer->fs.segs[i].y1 += off_y;
              layer->fs.segs[i].x2 += off_x;
              layer->fs.segs[i].y2 += off_y;
            }
        }
      else
        {
          layer->fs.num_segs = 4;
          layer->fs.segs     = g_new0 (BoundSeg, 4);

          /* top */
          layer->fs.segs[0].x1 = off_x;
          layer->fs.segs[0].y1 = off_y;
          layer->fs.segs[0].x2 = off_x + width;
          layer->fs.segs[0].y2 = off_y;

          /* left */
          layer->fs.segs[1].x1 = off_x;
          layer->fs.segs[1].y1 = off_y;
          layer->fs.segs[1].x2 = off_x;
          layer->fs.segs[1].y2 = off_y + height;

          /* right */
          layer->fs.segs[2].x1 = off_x + width;
          layer->fs.segs[2].y1 = off_y;
          layer->fs.segs[2].x2 = off_x + width;
          layer->fs.segs[2].y2 = off_y + height;

          /* bottom */
          layer->fs.segs[3].x1 = off_x;
          layer->fs.segs[3].y1 = off_y + height;
          layer->fs.segs[3].x2 = off_x + width;
          layer->fs.segs[3].y2 = off_y + height;
        }

      layer->fs.boundary_known = TRUE;
    }

  *n_segs = layer->fs.num_segs;

  return layer->fs.segs;
}
Esempio n. 23
0
static void
gimp_display_shell_drop_drawable (GtkWidget    *widget,
                                  gint          x,
                                  gint          y,
                                  GimpViewable *viewable,
                                  gpointer      data)
{
  GimpDisplayShell *shell     = GIMP_DISPLAY_SHELL (data);
  GimpImage        *image     = shell->display->image;
  GType             new_type;
  GimpItem         *new_item;
  gboolean          new_image = FALSE;

  GIMP_LOG (DND, NULL);

  if (shell->display->gimp->busy)
    return;

  if (! image)
    {
      GimpImage         *src_image = gimp_item_get_image (GIMP_ITEM (viewable));
      GimpDrawable      *drawable  = GIMP_DRAWABLE (viewable);
      GimpImageBaseType  type;
      gdouble            xres;
      gdouble            yres;

      type = GIMP_IMAGE_TYPE_BASE_TYPE (gimp_drawable_type (drawable));

      image = gimp_create_image (shell->display->gimp,
                                 gimp_item_width (GIMP_ITEM (viewable)),
                                 gimp_item_height (GIMP_ITEM (viewable)),
                                 type, TRUE);
      gimp_image_undo_disable (image);

      if (type == GIMP_INDEXED)
        gimp_image_set_colormap (image,
                                 gimp_image_get_colormap (src_image),
                                 gimp_image_get_colormap_size (src_image),
                                 FALSE);

      gimp_image_get_resolution (src_image, &xres, &yres);
      gimp_image_set_resolution (image, xres, yres);
      gimp_image_set_unit (image, gimp_image_get_unit (src_image));

      gimp_create_display (image->gimp, image, GIMP_UNIT_PIXEL, 1.0);
      g_object_unref (image);

      new_image = TRUE;
    }

  if (GIMP_IS_LAYER (viewable))
    new_type = G_TYPE_FROM_INSTANCE (viewable);
  else
    new_type = GIMP_TYPE_LAYER;

  new_item = gimp_item_convert (GIMP_ITEM (viewable), image, new_type);

  if (new_item)
    {
      GimpLayer *new_layer = GIMP_LAYER (new_item);

      gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_EDIT_PASTE,
                                   _("Drop New Layer"));

      if (! new_image)
        gimp_display_shell_dnd_position_item (shell, new_item);

      gimp_item_set_visible (new_item, TRUE, FALSE);
      gimp_item_set_linked (new_item, FALSE, FALSE);

      gimp_image_add_layer (image, new_layer, -1);

      gimp_image_undo_group_end (image);

      gimp_display_shell_dnd_flush (shell, image);
    }

  if (new_image)
    gimp_image_undo_enable (image);
}
Esempio n. 24
0
/*
 * some rather complex logic here.  If the user clicks without modifiers,
 * then we start a new list, and use the first object in it as reference.
 * If the user clicks using Shift, or draws a rubber-band box, then
 * we add objects to the list, but do not specify which one should
 * be used as reference.
 */
static void
gimp_align_tool_button_release (GimpTool              *tool,
                                GimpCoords            *coords,
                                guint32                time,
                                GdkModifierType        state,
                                GimpButtonReleaseType  release_type,
                                GimpDisplay           *display)
{
  GimpAlignTool    *align_tool = GIMP_ALIGN_TOOL (tool);
  GimpDisplayShell *shell      = GIMP_DISPLAY_SHELL (display->shell);
  GObject          *object     = NULL;
  GimpImage        *image      = display->image;
  gint              i;

  gimp_draw_tool_pause (GIMP_DRAW_TOOL (tool));

  if (release_type == GIMP_BUTTON_RELEASE_CANCEL)
    {
      align_tool->x1 = align_tool->x0;
      align_tool->y1 = align_tool->y0;

      gimp_draw_tool_resume (GIMP_DRAW_TOOL (tool));
      return;
    }

  if (! (state & GDK_SHIFT_MASK)) /* start a new list */
    {
      clear_all_selected_objects (align_tool);
      align_tool->set_reference = FALSE;
    }

  /* if mouse has moved less than EPSILON pixels since button press, select
     the nearest thing, otherwise make a rubber-band rectangle */
  if (hypot (coords->x - align_tool->x0, coords->y - align_tool->y0) < EPSILON)
    {
      GimpVectors *vectors;
      GimpGuide   *guide;
      GimpLayer   *layer;
      gint         snap_distance;

      snap_distance =
        GIMP_DISPLAY_CONFIG (display->image->gimp->config)->snap_distance;

      if (gimp_draw_tool_on_vectors (GIMP_DRAW_TOOL (tool), display,
                                     coords, snap_distance, snap_distance,
                                     NULL, NULL, NULL, NULL, NULL,
                                     &vectors))
        {
          object = G_OBJECT (vectors);
        }
      else if (gimp_display_shell_get_show_guides (shell) &&
               (guide = gimp_image_find_guide (display->image,
                                               coords->x, coords->y,
                                               FUNSCALEX (shell, snap_distance),
                                               FUNSCALEY (shell, snap_distance))))
        {
          object = G_OBJECT (guide);
        }
      else
        {
          if ((layer = select_layer_by_coords (display->image,
                                               coords->x, coords->y)))
            {
              object = G_OBJECT (layer);
            }
        }

      if (object)
        {
          if (! g_list_find (align_tool->selected_objects, object))
            {
              align_tool->selected_objects
                = g_list_append (align_tool->selected_objects, object);
              g_signal_connect (object, "removed",
                                G_CALLBACK (clear_selected_object),
                                (gpointer) align_tool);

              /* if an object has been selected using unmodified click,
               * it should be used as the reference
               */
              if (! (state & (GDK_SHIFT_MASK | GDK_CONTROL_MASK)))
                align_tool->set_reference = TRUE;
            }
        }
    }
  else  /* FIXME: look for vectors too */
    {
      gint   X0    = MIN (coords->x, align_tool->x0);
      gint   X1    = MAX (coords->x, align_tool->x0);
      gint   Y0    = MIN (coords->y, align_tool->y0);
      gint   Y1    = MAX (coords->y, align_tool->y0);
      GList *list;

      for (list = GIMP_LIST (image->layers)->list;
           list;
           list = g_list_next (list))
        {
          GimpLayer *layer = list->data;
          gint       x0, y0, x1, y1;

          if (! gimp_item_get_visible (GIMP_ITEM (layer)))
            continue;

          gimp_item_offsets (GIMP_ITEM (layer), &x0, &y0);
          x1 = x0 + gimp_item_width (GIMP_ITEM (layer));
          y1 = y0 + gimp_item_height (GIMP_ITEM (layer));

          if (x0 < X0 || y0 < Y0 || x1 > X1 || y1 > Y1)
            continue;

          if (g_list_find (align_tool->selected_objects, layer))
            continue;

          align_tool->selected_objects
            = g_list_append (align_tool->selected_objects, layer);
          g_signal_connect (layer, "removed", G_CALLBACK (clear_selected_object),
                            (gpointer) align_tool);
        }
    }

  for (i = 0; i < ALIGN_TOOL_NUM_BUTTONS; i++)
    gtk_widget_set_sensitive (align_tool->button[i],
                              (align_tool->selected_objects != NULL));

  align_tool->x1 = align_tool->x0;
  align_tool->y1 = align_tool->y0;

  gimp_draw_tool_resume (GIMP_DRAW_TOOL (tool));
}
Esempio n. 25
0
static void
gimp_align_tool_draw (GimpDrawTool *draw_tool)
{
  GimpAlignTool *align_tool = GIMP_ALIGN_TOOL (draw_tool);
  GList         *list;
  gint           x, y, w, h;

  /* draw rubber-band rectangle */
  x = MIN (align_tool->x1, align_tool->x0);
  y = MIN (align_tool->y1, align_tool->y0);
  w = MAX (align_tool->x1, align_tool->x0) - x;
  h = MAX (align_tool->y1, align_tool->y0) - y;

  gimp_draw_tool_draw_rectangle (draw_tool,
                                 FALSE,
                                 x, y,w, h,
                                 FALSE);

  for (list = g_list_first (align_tool->selected_objects); list;
       list = g_list_next (list))
    {
      if (GIMP_IS_ITEM (list->data))
        {
          GimpItem *item = GIMP_ITEM (list->data);

          if (GIMP_IS_VECTORS (list->data))
            {
              gdouble x1_f, y1_f, x2_f, y2_f;

              gimp_vectors_bounds (GIMP_VECTORS (item),
                                   &x1_f, &y1_f,
                                   &x2_f, &y2_f);
              x = ROUND (x1_f);
              y = ROUND (y1_f);
              w = ROUND (x2_f - x1_f);
              h = ROUND (y2_f - y1_f);
            }
          else
            {
              gimp_item_offsets (item, &x, &y);

              w = gimp_item_width (item);
              h = gimp_item_height (item);
            }

          gimp_draw_tool_draw_handle (draw_tool, GIMP_HANDLE_FILLED_SQUARE,
                                      x, y, MARKER_WIDTH, MARKER_WIDTH,
                                      GTK_ANCHOR_NORTH_WEST, FALSE);
          gimp_draw_tool_draw_handle (draw_tool, GIMP_HANDLE_FILLED_SQUARE,
                                      x + w, y, MARKER_WIDTH, MARKER_WIDTH,
                                      GTK_ANCHOR_NORTH_EAST, FALSE);
          gimp_draw_tool_draw_handle (draw_tool, GIMP_HANDLE_FILLED_SQUARE,
                                      x, y + h, MARKER_WIDTH, MARKER_WIDTH,
                                      GTK_ANCHOR_SOUTH_WEST, FALSE);
          gimp_draw_tool_draw_handle (draw_tool, GIMP_HANDLE_FILLED_SQUARE,
                                      x + w, y + h, MARKER_WIDTH, MARKER_WIDTH,
                                      GTK_ANCHOR_SOUTH_EAST, FALSE);
        }
      else if (GIMP_IS_GUIDE (list->data))
        {
          GimpGuide *guide = GIMP_GUIDE (list->data);
          GimpImage *image = GIMP_TOOL (draw_tool)->display->image;
          gint       x, y;
          gint       w, h;

          switch (gimp_guide_get_orientation (guide))
            {
            case GIMP_ORIENTATION_VERTICAL:
              x = gimp_guide_get_position (guide);
              h = gimp_image_get_height (image);
              gimp_draw_tool_draw_handle (draw_tool, GIMP_HANDLE_FILLED_SQUARE,
                                          x, h, MARKER_WIDTH, MARKER_WIDTH,
                                          GTK_ANCHOR_SOUTH, FALSE);
              gimp_draw_tool_draw_handle (draw_tool, GIMP_HANDLE_FILLED_SQUARE,
                                          x, 0, MARKER_WIDTH, MARKER_WIDTH,
                                          GTK_ANCHOR_NORTH, FALSE);
              break;

            case GIMP_ORIENTATION_HORIZONTAL:
              y = gimp_guide_get_position (guide);
              w = gimp_image_get_width (image);
              gimp_draw_tool_draw_handle (draw_tool, GIMP_HANDLE_FILLED_SQUARE,
                                          w, y, MARKER_WIDTH, MARKER_WIDTH,
                                          GTK_ANCHOR_EAST, FALSE);
              gimp_draw_tool_draw_handle (draw_tool, GIMP_HANDLE_FILLED_SQUARE,
                                          0, y, MARKER_WIDTH, MARKER_WIDTH,
                                          GTK_ANCHOR_WEST, FALSE);
              break;

            default:
              break;
            }
        }
    }
}
Esempio n. 26
0
void
gimp_image_crop (GimpImage   *image,
                 GimpContext *context,
                 gint         x1,
                 gint         y1,
                 gint         x2,
                 gint         y2,
                 gboolean     active_layer_only,
                 gboolean     crop_layers)
{
  gint width, height;
  gint previous_width, previous_height;

  g_return_if_fail (GIMP_IS_IMAGE (image));
  g_return_if_fail (GIMP_IS_CONTEXT (context));

  previous_width  = gimp_image_get_width (image);
  previous_height = gimp_image_get_height (image);

  width  = x2 - x1;
  height = y2 - y1;

  /*  Make sure new width and height are non-zero  */
  if (width < 1 || height < 1)
    return;

  gimp_set_busy (image->gimp);

  if (active_layer_only)
    {
      GimpLayer *layer;
      gint       off_x, off_y;

      layer = gimp_image_get_active_layer (image);

      gimp_item_offsets (GIMP_ITEM (layer), &off_x, &off_y);

      off_x -= x1;
      off_y -= y1;

      gimp_item_resize (GIMP_ITEM (layer), context, width, height, off_x, off_y);
    }
  else
    {
      GimpItem *item;
      GList    *list;

      g_object_freeze_notify (G_OBJECT (image));

      if (crop_layers)
        gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_IMAGE_CROP,
                                     C_("command", "Crop Image"));
      else
        gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_IMAGE_RESIZE,
                                     _("Resize Image"));

      /*  Push the image size to the stack  */
      gimp_image_undo_push_image_size (image,
                                       NULL,
                                       x1,
                                       y1,
                                       width,
                                       height);

      /*  Set the new width and height  */
      g_object_set (image,
                    "width",  width,
                    "height", height,
                    NULL);

      /*  Resize all channels  */
      for (list = GIMP_LIST (image->channels)->list;
           list;
           list = g_list_next (list))
        {
          item = (GimpItem *) list->data;

          gimp_item_resize (item, context, width, height, -x1, -y1);
        }

      /*  Resize all vectors  */
      for (list = GIMP_LIST (image->vectors)->list;
           list;
           list = g_list_next (list))
        {
          item = (GimpItem *) list->data;

          gimp_item_resize (item, context, width, height, -x1, -y1);
        }

      /*  Don't forget the selection mask!  */
      gimp_item_resize (GIMP_ITEM (gimp_image_get_mask (image)), context,
                        width, height, -x1, -y1);

      /*  crop all layers  */
      list = GIMP_LIST (image->layers)->list;

      while (list)
        {
          item = (GimpItem *) list->data;

          list = g_list_next (list);

          gimp_item_translate (item, -x1, -y1, TRUE);

          if (crop_layers)
            {
              gint off_x, off_y;
              gint lx1, ly1, lx2, ly2;

              gimp_item_offsets (item, &off_x, &off_y);

              lx1 = CLAMP (off_x, 0, gimp_image_get_width  (image));
              ly1 = CLAMP (off_y, 0, gimp_image_get_height (image));
              lx2 = CLAMP (gimp_item_width  (item) + off_x,
                           0, gimp_image_get_width (image));
              ly2 = CLAMP (gimp_item_height (item) + off_y,
                           0, gimp_image_get_height (image));

              width  = lx2 - lx1;
              height = ly2 - ly1;

              if (width > 0 && height > 0)
                gimp_item_resize (item, context, width, height,
                                  -(lx1 - off_x),
                                  -(ly1 - off_y));
              else
                gimp_image_remove_layer (image, GIMP_LAYER (item));
            }
        }

      /*  Reposition or remove all guides  */
      list = gimp_image_get_guides (image);
      while (list)
        {
          GimpGuide *guide        = list->data;
          gboolean   remove_guide = FALSE;
          gint       position     = gimp_guide_get_position (guide);

          list = g_list_next (list);

          switch (gimp_guide_get_orientation (guide))
            {
            case GIMP_ORIENTATION_HORIZONTAL:
              if ((position < y1) || (position > y2))
                remove_guide = TRUE;
              else
                position -= y1;
              break;

            case GIMP_ORIENTATION_VERTICAL:
              if ((position < x1) || (position > x2))
                remove_guide = TRUE;
              else
                position -= x1;
              break;

            default:
              break;
            }

          if (remove_guide)
            gimp_image_remove_guide (image, guide, TRUE);
          else if (position != gimp_guide_get_position (guide))
            gimp_image_move_guide (image, guide, position, TRUE);
        }

      /*  Reposition or remove sample points  */
      list = gimp_image_get_sample_points (image);
      while (list)
        {
          GimpSamplePoint *sample_point        = list->data;
          gboolean         remove_sample_point = FALSE;
          gint             new_x               = sample_point->x;
          gint             new_y               = sample_point->y;

          list = g_list_next (list);

          new_y -= y1;
          if ((sample_point->y < y1) || (sample_point->y > y2))
            remove_sample_point = TRUE;

          new_x -= x1;
          if ((sample_point->x < x1) || (sample_point->x > x2))
            remove_sample_point = TRUE;

          if (remove_sample_point)
            gimp_image_remove_sample_point (image, sample_point, TRUE);
          else if (new_x != sample_point->x || new_y != sample_point->y)
            gimp_image_move_sample_point (image, sample_point,
                                          new_x, new_y, TRUE);
        }

      gimp_image_undo_group_end (image);

      gimp_image_update (image,
                         0, 0,
                         gimp_image_get_width  (image),
                         gimp_image_get_height (image));

      gimp_image_size_changed_detailed (image,
                                        -x1,
                                        -y1,
                                        previous_width,
                                        previous_height);

      g_object_thaw_notify (G_OBJECT (image));
    }

  gimp_unset_busy (image->gimp);
}
Esempio n. 27
0
static GimpLayer *
gimp_image_merge_layers (GimpImage     *image,
                         GSList        *merge_list,
                         GimpContext   *context,
                         GimpMergeType  merge_type,
                         const gchar   *undo_desc)
{
  GList           *list;
  GSList          *reverse_list = NULL;
  PixelRegion      src1PR, src2PR, maskPR;
  PixelRegion     *mask;
  GimpLayer       *merge_layer;
  GimpLayer       *layer;
  GimpLayer       *bottom_layer;
  GimpImageType    type;
  gint             count;
  gint             x1, y1, x2, y2;
  gint             x3, y3, x4, y4;
  CombinationMode  operation;
  gint             position;
  gboolean         active[MAX_CHANNELS] = { TRUE, TRUE, TRUE, TRUE };
  gint             off_x, off_y;
  gchar           *name;

  g_return_val_if_fail (GIMP_IS_IMAGE (image), NULL);
  g_return_val_if_fail (GIMP_IS_CONTEXT (context), NULL);

  layer        = NULL;
  type         = GIMP_RGBA_IMAGE;
  x1 = y1      = 0;
  x2 = y2      = 0;
  bottom_layer = NULL;

  /*  Get the layer extents  */
  count = 0;
  while (merge_list)
    {
      layer = merge_list->data;

      gimp_item_offsets (GIMP_ITEM (layer), &off_x, &off_y);

      switch (merge_type)
        {
        case GIMP_EXPAND_AS_NECESSARY:
        case GIMP_CLIP_TO_IMAGE:
          if (! count)
            {
              x1 = off_x;
              y1 = off_y;
              x2 = off_x + gimp_item_width  (GIMP_ITEM (layer));
              y2 = off_y + gimp_item_height (GIMP_ITEM (layer));
            }
          else
            {
              if (off_x < x1)
                x1 = off_x;
              if (off_y < y1)
                y1 = off_y;
              if ((off_x + gimp_item_width (GIMP_ITEM (layer))) > x2)
                x2 = (off_x + gimp_item_width (GIMP_ITEM (layer)));
              if ((off_y + gimp_item_height (GIMP_ITEM (layer))) > y2)
                y2 = (off_y + gimp_item_height (GIMP_ITEM (layer)));
            }

          if (merge_type == GIMP_CLIP_TO_IMAGE)
            {
              x1 = CLAMP (x1, 0, gimp_image_get_width  (image));
              y1 = CLAMP (y1, 0, gimp_image_get_height (image));
              x2 = CLAMP (x2, 0, gimp_image_get_width  (image));
              y2 = CLAMP (y2, 0, gimp_image_get_height (image));
            }
          break;

        case GIMP_CLIP_TO_BOTTOM_LAYER:
          if (merge_list->next == NULL)
            {
              x1 = off_x;
              y1 = off_y;
              x2 = off_x + gimp_item_width (GIMP_ITEM (layer));
              y2 = off_y + gimp_item_height (GIMP_ITEM (layer));
            }
          break;

        case GIMP_FLATTEN_IMAGE:
          if (merge_list->next == NULL)
            {
              x1 = 0;
              y1 = 0;
              x2 = gimp_image_get_width  (image);
              y2 = gimp_image_get_height (image);
            }
          break;
        }

      count ++;
      reverse_list = g_slist_prepend (reverse_list, layer);
      merge_list = g_slist_next (merge_list);
    }

  if ((x2 - x1) == 0 || (y2 - y1) == 0)
    return NULL;

  /*  Start a merge undo group. */

  gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_IMAGE_LAYERS_MERGE,
                               undo_desc);

  name = g_strdup (gimp_object_get_name (GIMP_OBJECT (layer)));

  if (merge_type == GIMP_FLATTEN_IMAGE ||
      gimp_drawable_type (GIMP_DRAWABLE (layer)) == GIMP_INDEXED_IMAGE)
    {
      guchar bg[4] = { 0, 0, 0, 0 };

      type = GIMP_IMAGE_TYPE_FROM_BASE_TYPE (gimp_image_base_type (image));

      merge_layer = gimp_layer_new (image, (x2 - x1), (y2 - y1),
                                    type,
                                    gimp_object_get_name (GIMP_OBJECT (layer)),
                                    GIMP_OPACITY_OPAQUE, GIMP_NORMAL_MODE);
      if (! merge_layer)
        {
          g_warning ("%s: could not allocate merge layer.", G_STRFUNC);
          return NULL;
        }

      GIMP_ITEM (merge_layer)->offset_x = x1;
      GIMP_ITEM (merge_layer)->offset_y = y1;

      /*  get the background for compositing  */
      gimp_image_get_background (image, context,
                                 gimp_drawable_type (GIMP_DRAWABLE (merge_layer)),
                                 bg);

      /*  init the pixel region  */
      pixel_region_init (&src1PR,
                         gimp_drawable_get_tiles (GIMP_DRAWABLE (merge_layer)),
                         0, 0, (x2 - x1), (y2 - y1),
                         TRUE);

      /*  set the region to the background color  */
      color_region (&src1PR, bg);

      position = 0;
    }
  else
    {
      /*  The final merged layer inherits the name of the bottom most layer
       *  and the resulting layer has an alpha channel whether or not the
       *  original did. Opacity is set to 100% and the MODE is set to normal.
       */

      merge_layer =
        gimp_layer_new (image, (x2 - x1), (y2 - y1),
                        gimp_drawable_type_with_alpha (GIMP_DRAWABLE (layer)),
                        "merged layer",
                        GIMP_OPACITY_OPAQUE, GIMP_NORMAL_MODE);

      if (!merge_layer)
        {
          g_warning ("%s: could not allocate merge layer", G_STRFUNC);
          return NULL;
        }

      GIMP_ITEM (merge_layer)->offset_x = x1;
      GIMP_ITEM (merge_layer)->offset_y = y1;

      /*  clear the layer  */
      pixel_region_init (&src1PR,
                         gimp_drawable_get_tiles (GIMP_DRAWABLE (merge_layer)),
                         0, 0,
                         (x2 - x1), (y2 - y1),
                         TRUE);
      clear_region (&src1PR);

      /*  Find the index in the layer list of the bottom layer--we need this
       *  in order to add the final, merged layer to the layer list correctly
       */
      layer = reverse_list->data;
      position =
        gimp_container_num_children (image->layers) -
        gimp_container_get_child_index (image->layers, GIMP_OBJECT (layer));
    }

  bottom_layer = layer;

  /* Copy the tattoo and parasites of the bottom layer to the new layer */
  gimp_item_set_tattoo (GIMP_ITEM (merge_layer),
                        gimp_item_get_tattoo (GIMP_ITEM (bottom_layer)));

  g_object_unref (GIMP_ITEM (merge_layer)->parasites);
  GIMP_ITEM (merge_layer)->parasites =
    gimp_parasite_list_copy (GIMP_ITEM (bottom_layer)->parasites);

  while (reverse_list)
    {
      GimpLayerModeEffects  mode;

      layer = reverse_list->data;

      /*  determine what sort of operation is being attempted and
       *  if it's actually legal...
       */
      operation = gimp_image_merge_layers_get_operation (merge_layer, layer);

      if (operation == -1)
        {
          gimp_layer_add_alpha (layer);

          /*  try again ...  */
          operation = gimp_image_merge_layers_get_operation (merge_layer,
                                                             layer);
        }

      if (operation == -1)
        {
          g_warning ("%s: attempting to merge incompatible layers.", G_STRFUNC);
          return NULL;
        }

      gimp_item_offsets (GIMP_ITEM (layer), &off_x, &off_y);

      x3 = CLAMP (off_x, x1, x2);
      y3 = CLAMP (off_y, y1, y2);
      x4 = CLAMP (off_x + gimp_item_width  (GIMP_ITEM (layer)), x1, x2);
      y4 = CLAMP (off_y + gimp_item_height (GIMP_ITEM (layer)), y1, y2);

      /* configure the pixel regions  */
      pixel_region_init (&src1PR,
                         gimp_drawable_get_tiles (GIMP_DRAWABLE (merge_layer)),
                         (x3 - x1), (y3 - y1), (x4 - x3), (y4 - y3),
                         TRUE);
      pixel_region_init (&src2PR,
                         gimp_drawable_get_tiles (GIMP_DRAWABLE (layer)),
                         (x3 - off_x), (y3 - off_y),
                         (x4 - x3), (y4 - y3),
                         FALSE);

      if (gimp_layer_get_mask (layer) &&
          gimp_layer_mask_get_apply (layer->mask))
        {
          TileManager *tiles;

          tiles = gimp_drawable_get_tiles (GIMP_DRAWABLE (layer->mask));

          pixel_region_init (&maskPR, tiles,
                             (x3 - off_x), (y3 - off_y), (x4 - x3), (y4 - y3),
                             FALSE);
          mask = &maskPR;
        }
      else
        {
          mask = NULL;
        }

      /* DISSOLVE_MODE is special since it is the only mode that does not
       *  work on the projection with the lower layer, but only locally on
       *  the layers alpha channel.
       */
      mode = gimp_layer_get_mode (layer);
      if (layer == bottom_layer && mode != GIMP_DISSOLVE_MODE)
        mode = GIMP_NORMAL_MODE;

      combine_regions (&src1PR, &src2PR, &src1PR, mask, NULL,
                       gimp_layer_get_opacity (layer) * 255.999,
                       mode,
                       active,
                       operation);

      gimp_image_remove_layer (image, layer);

      reverse_list = g_slist_next (reverse_list);
    }

  g_slist_free (reverse_list);

  /*  if the type is flatten, remove all the remaining layers  */
  if (merge_type == GIMP_FLATTEN_IMAGE)
    {
      list = GIMP_LIST (image->layers)->list;
      while (list)
        {
          layer = list->data;

          list = g_list_next (list);
          gimp_image_remove_layer (image, layer);
        }

      gimp_image_add_layer (image, merge_layer, position);
    }
  else
    {
      /*  Add the layer to the image  */
      gimp_image_add_layer (image, merge_layer,
         gimp_container_num_children (image->layers) - position + 1);
    }

  /* set the name after the original layers have been removed so we
   * don't end up with #2 appended to the name
   */
  gimp_object_take_name (GIMP_OBJECT (merge_layer), name);

  gimp_item_set_visible (GIMP_ITEM (merge_layer), TRUE, TRUE);

  /*  End the merge undo group  */
  gimp_image_undo_group_end (image);

  gimp_drawable_update (GIMP_DRAWABLE (merge_layer),
                        0, 0,
                        gimp_item_width  (GIMP_ITEM (merge_layer)),
                        gimp_item_height (GIMP_ITEM (merge_layer)));

  return merge_layer;
}
Esempio n. 28
0
GtkWidget *
resize_dialog_new (GimpViewable       *viewable,
                   GimpContext        *context,
                   const gchar        *title,
                   const gchar        *role,
                   GtkWidget          *parent,
                   GimpHelpFunc        help_func,
                   const gchar        *help_id,
                   GimpUnit            unit,
                   GimpResizeCallback  callback,
                   gpointer            user_data)
{
  GtkWidget    *dialog;
  GtkWidget    *main_vbox;
  GtkWidget    *vbox;
  GtkWidget    *abox;
  GtkWidget    *frame;
  GtkWidget    *button;
  GtkWidget    *spinbutton;
  GtkWidget    *entry;
  GtkObject    *adjustment;
  GdkPixbuf    *pixbuf;
  ResizeDialog *private;
  GimpImage    *image = NULL;
  const gchar  *text  = NULL;
  gint          width, height;
  gdouble       xres, yres;

  g_return_val_if_fail (GIMP_IS_VIEWABLE (viewable), NULL);
  g_return_val_if_fail (GIMP_IS_CONTEXT (context), NULL);
  g_return_val_if_fail (callback != NULL, NULL);

  if (GIMP_IS_IMAGE (viewable))
    {
      image = GIMP_IMAGE (viewable);

      width  = gimp_image_get_width (image);
      height = gimp_image_get_height (image);

      text = _("Canvas Size");
    }
  else if (GIMP_IS_ITEM (viewable))
    {
      GimpItem *item = GIMP_ITEM (viewable);

      image = gimp_item_get_image (item);

      width  = gimp_item_width (item);
      height = gimp_item_height (item);

      text = _("Layer Size");
    }
  else
    {
      g_return_val_if_reached (NULL);
    }

  dialog = gimp_viewable_dialog_new (viewable, context,
                                     title, role, GIMP_STOCK_RESIZE, title,
                                     parent,
                                     help_func, help_id,

                                     GIMP_STOCK_RESET,  RESPONSE_RESET,
                                     GTK_STOCK_CANCEL,  GTK_RESPONSE_CANCEL,
                                     GIMP_STOCK_RESIZE, GTK_RESPONSE_OK,

                                     NULL);

  gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE);

  gtk_dialog_set_alternative_button_order (GTK_DIALOG (dialog),
                                           RESPONSE_RESET,
                                           GTK_RESPONSE_OK,
                                           GTK_RESPONSE_CANCEL,
                                           -1);

  private = g_slice_new0 (ResizeDialog);
Esempio n. 29
0
static gboolean
gimp_smudge_start (GimpPaintCore    *paint_core,
                   GimpDrawable     *drawable,
                   GimpPaintOptions *paint_options)
{
  GimpSmudge  *smudge = GIMP_SMUDGE (paint_core);
  GimpImage   *image;
  TempBuf     *area;
  PixelRegion  srcPR;
  gint         bytes;
  gint         x, y, w, h;

  image = gimp_item_get_image (GIMP_ITEM (drawable));

  if (gimp_drawable_is_indexed (drawable))
    return FALSE;

  area = gimp_paint_core_get_paint_area (paint_core, drawable, paint_options);
  if (! area)
    return FALSE;

  /*  adjust the x and y coordinates to the upper left corner of the brush  */
  gimp_smudge_brush_coords (paint_core, &x, &y, &w, &h);

  /*  Allocate the accumulation buffer */
  bytes = gimp_drawable_bytes (drawable);
  smudge->accum_data = g_malloc (w * h * bytes);

  /*  If clipped, prefill the smudge buffer with the color at the
   *  brush position.
   */
  if (x != area->x || y != area->y || w != area->width || h != area->height)
    {
      guchar fill[4];

      gimp_pickable_get_pixel_at (GIMP_PICKABLE (drawable),
                                  CLAMP ((gint) paint_core->cur_coords.x,
                                         0,
                                         gimp_item_width (GIMP_ITEM (drawable)) - 1),
                                  CLAMP ((gint) paint_core->cur_coords.y,
                                         0,
                                         gimp_item_height (GIMP_ITEM (drawable)) - 1),
                                  fill);

      pixel_region_init_data (&srcPR, smudge->accum_data,
                              bytes, bytes * w,
                              0, 0, w, h);

      color_region (&srcPR, fill);
    }

  pixel_region_init (&srcPR, gimp_drawable_get_tiles (drawable),
                     area->x, area->y, area->width, area->height, FALSE);

  pixel_region_init_data (&smudge->accumPR, smudge->accum_data,
                          bytes, bytes * w,
                          area->x - x,
                          area->y - y,
                          area->width,
                          area->height);

  /* copy the region under the original painthit. */
  copy_region (&srcPR, &smudge->accumPR);

  pixel_region_init_data (&smudge->accumPR, smudge->accum_data,
                          bytes, bytes * w,
                          area->x - x,
                          area->y - y,
                          area->width,
                          area->height);

  return TRUE;
}
Esempio n. 30
0
static void
gimp_drawable_stroke_scan_convert (GimpDrawable      *drawable,
                                   GimpStrokeOptions *options,
                                   GimpScanConvert   *scan_convert)
{
  GimpContext *context = GIMP_CONTEXT (options);
  GimpImage   *image;
  gdouble      width;
  TileManager *base;
  TileManager *mask;
  gint         x, y, w, h;
  gint         bytes;
  gint         off_x, off_y;
  guchar       bg[1] = { 0, };
  PixelRegion  maskPR, basePR;

  image = gimp_item_get_image (GIMP_ITEM (drawable));

  /*  must call gimp_channel_is_empty() instead of relying on
   *  gimp_drawable_mask_intersect() because the selection pretends to
   *  be empty while it is being stroked, to prevent masking itself.
   */
  if (gimp_channel_is_empty (gimp_image_get_mask (image)))
    {
      x = 0;
      y = 0;
      w = gimp_item_width (GIMP_ITEM (drawable));
      h = gimp_item_height (GIMP_ITEM (drawable));
    }
  else if (! gimp_drawable_mask_intersect (drawable, &x, &y, &w, &h))
    {
      return;
    }

  gimp_item_offsets (GIMP_ITEM (drawable), &off_x, &off_y);

  width = options->width;

  if (options->unit != GIMP_UNIT_PIXEL)
    {
      gimp_scan_convert_set_pixel_ratio (scan_convert,
                                         image->yresolution /
                                         image->xresolution);

      width *= (image->yresolution /
                _gimp_unit_get_factor (image->gimp, options->unit));
    }

  gimp_scan_convert_stroke (scan_convert, width,
                            options->join_style,
                            options->cap_style,
                            options->miter_limit,
                            options->dash_offset,
                            options->dash_info);

  /* fill a 1-bpp Tilemanager with black, this will describe the shape
   * of the stroke.
   */
  mask = tile_manager_new (w, h, 1);
  pixel_region_init (&maskPR, mask, 0, 0, w, h, TRUE);
  color_region (&maskPR, bg);

  /* render the stroke into it */
  gimp_scan_convert_render (scan_convert, mask,
                            x + off_x, y + off_y,
                            options->antialias);

  bytes = gimp_drawable_bytes_with_alpha (drawable);

  base = tile_manager_new (w, h, bytes);
  pixel_region_init (&basePR, base, 0, 0, w, h, TRUE);
  pixel_region_init (&maskPR, mask, 0, 0, w, h, FALSE);

  switch (options->style)
    {
    case GIMP_STROKE_STYLE_SOLID:
      {
        guchar tmp_col[MAX_CHANNELS] = { 0, };
        guchar col[MAX_CHANNELS]     = { 0, };

        gimp_rgb_get_uchar (&context->foreground,
                            &tmp_col[RED_PIX],
                            &tmp_col[GREEN_PIX],
                            &tmp_col[BLUE_PIX]);

        gimp_image_transform_color (image, gimp_drawable_type (drawable), col,
                                    GIMP_RGB, tmp_col);
        col[bytes - 1] = OPAQUE_OPACITY;

        color_region_mask (&basePR, &maskPR, col);
      }
      break;

    case GIMP_STROKE_STYLE_PATTERN:
      {
        GimpPattern *pattern;
        TempBuf     *pat_buf;
        gboolean     new_buf;

        pattern = gimp_context_get_pattern (context);
        pat_buf = gimp_image_transform_temp_buf (image,
                                                 gimp_drawable_type (drawable),
                                                 pattern->mask, &new_buf);

        pattern_region (&basePR, &maskPR, pat_buf, x, y);

        if (new_buf)
          temp_buf_free (pat_buf);
      }
      break;
    }

  /* Apply to drawable */
  pixel_region_init (&basePR, base, 0, 0, w, h, FALSE);
  gimp_drawable_apply_region (drawable, &basePR,
                              TRUE, _("Render Stroke"),
                              gimp_context_get_opacity (context),
                              gimp_context_get_paint_mode (context),
                              NULL, x, y);

  tile_manager_unref (mask);
  tile_manager_unref (base);

  gimp_drawable_update (drawable, x, y, w, h);
}