Beispiel #1
0
static GList *
file_open_get_layers (const GimpImage *image,
                      gboolean         merge_visible,
                      gint            *n_visible)
{
  GList *iter   = NULL;
  GList *layers = NULL;

  for (iter = gimp_image_get_layer_iter (image);
       iter;
       iter = g_list_next (iter))
    {
      GimpItem *item = iter->data;

      if (! merge_visible)
        layers = g_list_prepend (layers, item);

      if (gimp_item_get_visible (item))
        {
          if (n_visible)
            (*n_visible)++;

          if (! layers)
            layers = g_list_prepend (layers, item);
        }
    }

  return layers;
}
GimpLayer *
gimp_image_flatten (GimpImage    *image,
                    GimpContext  *context,
                    GError      **error)
{
  GList     *list;
  GSList    *merge_list = NULL;
  GimpLayer *layer;

  g_return_val_if_fail (GIMP_IS_IMAGE (image), NULL);
  g_return_val_if_fail (GIMP_IS_CONTEXT (context), NULL);
  g_return_val_if_fail (error == NULL || *error == NULL, NULL);

  for (list = gimp_image_get_layer_iter (image);
       list;
       list = g_list_next (list))
    {
      layer = list->data;

      if (gimp_layer_is_floating_sel (layer))
        continue;

      if (gimp_item_get_visible (GIMP_ITEM (layer)))
        merge_list = g_slist_append (merge_list, layer);
    }

  if (merge_list)
    {
      gimp_set_busy (image->gimp);

      gimp_image_undo_group_start (image,
                                   GIMP_UNDO_GROUP_IMAGE_LAYERS_MERGE,
                                   C_("undo-type", "Flatten Image"));

      /* if there's a floating selection, anchor it */
      if (gimp_image_get_floating_selection (image))
        floating_sel_anchor (gimp_image_get_floating_selection (image));

      layer = gimp_image_merge_layers (image,
                                       gimp_image_get_layers (image),
                                       merge_list, context,
                                       GIMP_FLATTEN_IMAGE);
      g_slist_free (merge_list);

      gimp_image_alpha_changed (image);

      gimp_image_undo_group_end (image);

      gimp_unset_busy (image->gimp);

      return layer;
    }

  g_set_error_literal (error, GIMP_ERROR, GIMP_FAILED,
                       _("Cannot flatten an image without any visible layer."));
  return NULL;
}
Beispiel #3
0
void
gimp_image_resize_to_layers (GimpImage    *image,
                             GimpContext  *context,
                             GimpProgress *progress)
{
  GList    *list;
  GimpItem *item;
  gint      x, y;
  gint      width, height;

  g_return_if_fail (GIMP_IS_IMAGE (image));
  g_return_if_fail (GIMP_IS_CONTEXT (context));
  g_return_if_fail (progress == NULL || GIMP_IS_PROGRESS (progress));

  list = gimp_image_get_layer_iter (image);

  if (! list)
    return;

  /* figure out starting values */
  item = list->data;

  x      = gimp_item_get_offset_x (item);
  y      = gimp_item_get_offset_y (item);
  width  = gimp_item_get_width  (item);
  height = gimp_item_get_height (item);

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

      gimp_rectangle_union (x, y,
                            width, height,
                            gimp_item_get_offset_x (item),
                            gimp_item_get_offset_y (item),
                            gimp_item_get_width  (item),
                            gimp_item_get_height (item),
                            &x, &y,
                            &width, &height);
    }

  gimp_image_resize (image, context,
                     width, height, -x, -y,
                     progress);
}
Beispiel #4
0
static GimpLayer *
gimp_image_duplicate_layers (GimpImage *image,
                             GimpImage *new_image)
{
  GimpLayer *active_layer = NULL;
  GList     *list;
  gint       count;

  for (list = gimp_image_get_layer_iter (image), count = 0;
       list;
       list = g_list_next (list))
    {
      GimpLayer *layer = list->data;
      GimpLayer *new_layer;

      if (gimp_layer_is_floating_sel (layer))
        continue;

      new_layer = GIMP_LAYER (gimp_image_duplicate_item (GIMP_ITEM (layer),
                                                         new_image));

      /*  Make sure that if the layer has a layer mask,
       *  its name isn't screwed up
       */
      if (new_layer->mask)
        gimp_object_set_name (GIMP_OBJECT (new_layer->mask),
                              gimp_object_get_name (layer->mask));

      if (gimp_image_get_active_layer (image) == layer)
        active_layer = new_layer;

      gimp_image_add_layer (new_image, new_layer,
                            NULL, count++, FALSE);
    }

  return active_layer;
}
static GimpLayer *
gimp_image_merge_layers (GimpImage     *image,
                         GimpContainer *container,
                         GSList        *merge_list,
                         GimpContext   *context,
                         GimpMergeType  merge_type)
{
  GList            *list;
  GSList           *reverse_list = NULL;
  GSList           *layers;
  GimpLayer        *merge_layer;
  GimpLayer        *layer;
  GimpLayer        *bottom_layer;
  GimpParasiteList *parasites;
  gint              count;
  gint              x1, y1, x2, y2;
  gint              off_x, off_y;
  gint              position;
  gchar            *name;
  GimpLayer        *parent;

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

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

  parent = gimp_layer_get_parent (merge_list->data);

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

      gimp_item_get_offset (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_get_width  (GIMP_ITEM (layer));
              y2 = off_y + gimp_item_get_height (GIMP_ITEM (layer));
            }
          else
            {
              if (off_x < x1)
                x1 = off_x;
              if (off_y < y1)
                y1 = off_y;
              if ((off_x + gimp_item_get_width (GIMP_ITEM (layer))) > x2)
                x2 = (off_x + gimp_item_get_width (GIMP_ITEM (layer)));
              if ((off_y + gimp_item_get_height (GIMP_ITEM (layer))) > y2)
                y2 = (off_y + gimp_item_get_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_get_width  (GIMP_ITEM (layer));
              y2 = off_y + gimp_item_get_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. */

  name = g_strdup (gimp_object_get_name (layer));

  if (merge_type == GIMP_FLATTEN_IMAGE ||
      (gimp_drawable_is_indexed (GIMP_DRAWABLE (layer)) &&
       ! gimp_drawable_has_alpha (GIMP_DRAWABLE (layer))))
    {
      GeglColor *color;
      GimpRGB    bg;

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

      gimp_item_set_offset (GIMP_ITEM (merge_layer), x1, y1);

      /*  get the background for compositing  */
      gimp_context_get_background (context, &bg);

      color = gimp_gegl_color_new (&bg);
      gegl_buffer_set_color (gimp_drawable_get_buffer (GIMP_DRAWABLE (merge_layer)),
                             GEGL_RECTANGLE(0,0,x2-x1,y2-y1), color);
      g_object_unref (color);

      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_get_format_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_set_offset (GIMP_ITEM (merge_layer), x1, y1);

      /*  clear the layer  */
      gegl_buffer_clear (gimp_drawable_get_buffer (GIMP_DRAWABLE (merge_layer)),
                         NULL);

      /*  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_get_n_children (container) -
        gimp_container_get_child_index (container, 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)));

  parasites = gimp_item_get_parasites (GIMP_ITEM (bottom_layer));
  parasites = gimp_parasite_list_copy (parasites);
  gimp_item_set_parasites (GIMP_ITEM (merge_layer), parasites);
  g_object_unref (parasites);

  for (layers = reverse_list; layers; layers = g_slist_next (layers))
    {
      GeglBuffer           *merge_buffer;
      GeglBuffer           *layer_buffer;
      GimpApplicator       *applicator;
      GimpLayerModeEffects  mode;

      layer = layers->data;

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

      /* 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;

      merge_buffer = gimp_drawable_get_buffer (GIMP_DRAWABLE (merge_layer));
      layer_buffer = gimp_drawable_get_buffer (GIMP_DRAWABLE (layer));

      applicator =
        gimp_applicator_new (NULL,
                             gimp_drawable_get_linear (GIMP_DRAWABLE (layer)),
                             FALSE, FALSE);

      if (gimp_layer_get_mask (layer) &&
          gimp_layer_get_apply_mask (layer))
        {
          GeglBuffer *mask_buffer;

          mask_buffer = gimp_drawable_get_buffer (GIMP_DRAWABLE (layer->mask));

          gimp_applicator_set_mask_buffer (applicator, mask_buffer);
          gimp_applicator_set_mask_offset (applicator,
                                           - (x1 - off_x),
                                           - (y1 - off_y));
        }

      gimp_applicator_set_src_buffer (applicator, merge_buffer);
      gimp_applicator_set_dest_buffer (applicator, merge_buffer);

      gimp_applicator_set_apply_buffer (applicator, layer_buffer);
      gimp_applicator_set_apply_offset (applicator,
                                        - (x1 - off_x),
                                        - (y1 - off_y));

      gimp_applicator_set_mode (applicator,
                                gimp_layer_get_opacity (layer),
                                mode);

      gimp_applicator_blit (applicator,
                            GEGL_RECTANGLE (0, 0,
                                            gegl_buffer_get_width  (merge_buffer),
                                            gegl_buffer_get_height (merge_buffer)));

      g_object_unref (applicator);

      gimp_image_remove_layer (image, layer, TRUE, NULL);
    }

  g_slist_free (reverse_list);

  gimp_object_take_name (GIMP_OBJECT (merge_layer), name);
  gimp_item_set_visible (GIMP_ITEM (merge_layer), TRUE, FALSE);

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

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

      gimp_image_add_layer (image, merge_layer, parent,
                            position, TRUE);
    }
  else
    {
      /*  Add the layer to the image  */

      gimp_image_add_layer (image, merge_layer, parent,
                            gimp_container_get_n_children (container) -
                            position + 1,
                            TRUE);
    }

  gimp_drawable_update (GIMP_DRAWABLE (merge_layer),
                        0, 0,
                        gimp_item_get_width  (GIMP_ITEM (merge_layer)),
                        gimp_item_get_height (GIMP_ITEM (merge_layer)));

  return merge_layer;
}
Beispiel #6
0
GimpImage *
file_open_with_proc_and_display (Gimp                *gimp,
                                 GimpContext         *context,
                                 GimpProgress        *progress,
                                 GFile               *file,
                                 GFile               *entered_file,
                                 gboolean             as_new,
                                 GimpPlugInProcedure *file_proc,
                                 GObject             *screen,
                                 gint                 monitor,
                                 GimpPDBStatusType   *status,
                                 GError             **error)
{
  GimpImage   *image;
  const gchar *mime_type = NULL;

  g_return_val_if_fail (GIMP_IS_GIMP (gimp), NULL);
  g_return_val_if_fail (GIMP_IS_CONTEXT (context), NULL);
  g_return_val_if_fail (progress == NULL || GIMP_IS_PROGRESS (progress), NULL);
  g_return_val_if_fail (G_IS_FILE (file), NULL);
  g_return_val_if_fail (G_IS_FILE (entered_file), NULL);
  g_return_val_if_fail (screen == NULL || G_IS_OBJECT (screen), NULL);
  g_return_val_if_fail (status != NULL, NULL);

  image = file_open_image (gimp, context, progress,
                           file,
                           entered_file,
                           as_new,
                           file_proc,
                           GIMP_RUN_INTERACTIVE,
                           status,
                           &mime_type,
                           error);

  if (image)
    {
      /* If the file was imported we want to set the layer name to the
       * file name. For now, assume that multi-layered imported images
       * have named the layers already, so only rename the layer of
       * single-layered imported files. Note that this will also
       * rename already named layers from e.g. single-layered PSD
       * files. To solve this properly, we would need new file plug-in
       * API.
       */
      if (! file_proc)
        file_proc = gimp_image_get_load_proc (image);

      if (file_open_file_proc_is_import (file_proc) &&
          gimp_image_get_n_layers (image) == 1)
        {
          GimpObject *layer = gimp_image_get_layer_iter (image)->data;
          gchar      *basename;

          basename = g_path_get_basename (gimp_file_get_utf8_name (file));

          gimp_item_rename (GIMP_ITEM (layer), basename, NULL);
          gimp_image_undo_free (image);
          gimp_image_clean_all (image);

          g_free (basename);
        }

      if (gimp_create_display (image->gimp, image, GIMP_UNIT_PIXEL, 1.0,
                               screen, monitor))
        {
          /*  the display owns the image now  */
          g_object_unref (image);
        }

      if (! as_new)
        {
          GimpDocumentList *documents = GIMP_DOCUMENT_LIST (gimp->documents);
          GimpImagefile    *imagefile;
          GFile            *any_file;

          imagefile = gimp_document_list_add_file (documents, file, mime_type);

          /*  can only create a thumbnail if the passed file and the
           *  resulting image's file match. Use any_file() here so we
           *  create thumbnails for both XCF and imported images.
           */
          any_file = gimp_image_get_any_file (image);

          if (any_file && g_file_equal (file, any_file))
            {
              /*  no need to save a thumbnail if there's a good one already  */
              if (! gimp_imagefile_check_thumbnail (imagefile))
                {
                  gimp_imagefile_save_thumbnail (imagefile, mime_type, image,
                                                 NULL);
                }
            }
        }

      /*  announce that we opened this image  */
      gimp_image_opened (image->gimp, file);
    }

  return image;
}
Beispiel #7
0
GimpLayer *
gimp_edit_paste (GimpImage     *image,
                 GimpDrawable  *drawable,
                 GimpObject    *paste,
                 GimpPasteType  paste_type,
                 gint           viewport_x,
                 gint           viewport_y,
                 gint           viewport_width,
                 gint           viewport_height)
{
  GimpLayer  *layer = NULL;
  const Babl *floating_format;
  gint        offset_x;
  gint        offset_y;

  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_IMAGE (paste) || GIMP_IS_BUFFER (paste), NULL);

  /*  change paste type to NEW_LAYER for cases where we can't attach a
   *  floating selection
   */
  if (! drawable                                            ||
      gimp_viewable_get_children (GIMP_VIEWABLE (drawable)) ||
      gimp_item_is_content_locked (GIMP_ITEM (drawable)))
    {
      paste_type = GIMP_PASTE_TYPE_NEW_LAYER;
    }

  /*  floating pastes always have the pasted-to drawable's format with
   *  alpha; if drawable == NULL, user is pasting into an empty image
   */
  if (drawable)
    floating_format = gimp_drawable_get_format_with_alpha (drawable);
  else
    floating_format = gimp_image_get_layer_format (image, TRUE);

  if (GIMP_IS_IMAGE (paste))
    {
      GType layer_type;

      layer = gimp_image_get_layer_iter (GIMP_IMAGE (paste))->data;

      switch (paste_type)
        {
        case GIMP_PASTE_TYPE_FLOATING:
        case GIMP_PASTE_TYPE_FLOATING_INTO:
          /*  when pasting as floating selection, force creation of a
           *  plain layer, so gimp_item_convert() will collapse a
           *  group layer
           */
          layer_type = GIMP_TYPE_LAYER;
          break;

        case GIMP_PASTE_TYPE_NEW_LAYER:
          layer_type = G_TYPE_FROM_INSTANCE (layer);
          break;

        default:
          g_return_val_if_reached (NULL);
        }

      layer = GIMP_LAYER (gimp_item_convert (GIMP_ITEM (layer),
                                             image, layer_type));

      switch (paste_type)
        {
        case GIMP_PASTE_TYPE_FLOATING:
        case GIMP_PASTE_TYPE_FLOATING_INTO:
          /*  when pasting as floating selection, get rid of the layer mask,
           *  and make sure the layer has the right format
           */
          if (gimp_layer_get_mask (layer))
            gimp_layer_apply_mask (layer, GIMP_MASK_DISCARD, FALSE);

          if (gimp_drawable_get_format (GIMP_DRAWABLE (layer)) !=
              floating_format)
            {
              gimp_drawable_convert_type (GIMP_DRAWABLE (layer), image,
                                          gimp_drawable_get_base_type (drawable),
                                          gimp_drawable_get_precision (drawable),
                                          TRUE,
                                          NULL,
                                          GEGL_DITHER_NONE, GEGL_DITHER_NONE,
                                          FALSE, NULL);
            }
          break;

        default:
          break;
        }
    }
  else if (GIMP_IS_BUFFER (paste))
    {
      layer = gimp_layer_new_from_buffer (GIMP_BUFFER (paste), image,
                                          floating_format,
                                          _("Pasted Layer"),
                                          GIMP_OPACITY_OPAQUE, GIMP_NORMAL_MODE);
    }

  if (! layer)
    return NULL;

  gimp_edit_get_paste_offset (image, drawable, GIMP_OBJECT (layer),
                              viewport_x,
                              viewport_y,
                              viewport_width,
                              viewport_height,
                              &offset_x,
                              &offset_y);
  gimp_item_set_offset (GIMP_ITEM (layer), offset_x, offset_y);

  gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_EDIT_PASTE,
                               C_("undo-type", "Paste"));

  switch (paste_type)
    {
    case GIMP_PASTE_TYPE_FLOATING:
      /*  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);

      /* fall thru */

    case GIMP_PASTE_TYPE_FLOATING_INTO:
      floating_sel_attach (layer, drawable);
      break;

    case GIMP_PASTE_TYPE_NEW_LAYER:
      {
        GimpLayer *parent   = NULL;
        gint       position = 0;

        /* always add on top of the passed layer, where we would
         * attach a floating selection
         */
        if (GIMP_IS_LAYER (drawable))
          {
            parent   = gimp_layer_get_parent (GIMP_LAYER (drawable));
            position = gimp_item_get_index (GIMP_ITEM (drawable));
          }

        gimp_image_add_layer (image, layer, parent, position, TRUE);
      }
      break;
    }

  gimp_image_undo_group_end (image);

  return layer;
}
Beispiel #8
0
void
gimp_image_resize_with_layers (GimpImage    *image,
                               GimpContext  *context,
                               gint          new_width,
                               gint          new_height,
                               gint          offset_x,
                               gint          offset_y,
                               GimpItemSet   layer_set,
                               gboolean      resize_text_layers,
                               GimpProgress *progress)
{
  GList   *list;
  GList   *resize_layers;
  gdouble  progress_max;
  gdouble  progress_current = 1.0;
  gint     old_width, old_height;

  g_return_if_fail (GIMP_IS_IMAGE (image));
  g_return_if_fail (GIMP_IS_CONTEXT (context));
  g_return_if_fail (new_width > 0 && new_height > 0);
  g_return_if_fail (progress == NULL || GIMP_IS_PROGRESS (progress));

  gimp_set_busy (image->gimp);

  g_object_freeze_notify (G_OBJECT (image));

  gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_IMAGE_RESIZE,
                               C_("undo-type", "Resize Image"));

  resize_layers = gimp_image_item_list_get_list (image, NULL,
                                                 GIMP_ITEM_TYPE_LAYERS,
                                                 layer_set);

  progress_max = (gimp_container_get_n_children (gimp_image_get_layers (image))   +
                  gimp_container_get_n_children (gimp_image_get_channels (image)) +
                  gimp_container_get_n_children (gimp_image_get_vectors (image))  +
                  g_list_length (resize_layers)                                   +
                  1 /* selection */);

  old_width  = gimp_image_get_width  (image);
  old_height = gimp_image_get_height (image);

  /*  Push the image size to the stack  */
  gimp_image_undo_push_image_size (image, NULL,
                                   -offset_x, -offset_y,
                                   new_width, new_height);

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

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

      gimp_item_resize (item, context,
                        new_width, new_height, offset_x, offset_y);

      if (progress)
        gimp_progress_set_value (progress, progress_current++ / progress_max);
    }

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

      gimp_item_resize (item, context,
                        new_width, new_height, offset_x, offset_y);

      if (progress)
        gimp_progress_set_value (progress, progress_current++ / progress_max);
    }

  /*  Don't forget the selection mask!  */
  gimp_item_resize (GIMP_ITEM (gimp_image_get_mask (image)), context,
                    new_width, new_height, offset_x, offset_y);

  if (progress)
    gimp_progress_set_value (progress, progress_current++ / progress_max);

  /*  Reposition all layers  */
  for (list = gimp_image_get_layer_iter (image);
       list;
       list = g_list_next (list))
    {
      GimpItem *item = list->data;

      gimp_item_translate (item, offset_x, offset_y, TRUE);

      if (progress)
        gimp_progress_set_value (progress, progress_current++ / progress_max);
    }

  /*  Resize all resize_layers to image size  */
  for (list = resize_layers; list; list = g_list_next (list))
    {
      GimpItem *item = list->data;
      gint      old_offset_x;
      gint      old_offset_y;

      /*  group layers can't be resized here  */
      if (gimp_viewable_get_children (GIMP_VIEWABLE (item)))
        continue;

      if (! resize_text_layers && gimp_item_is_text_layer (item))
        continue;

      gimp_item_get_offset (item, &old_offset_x, &old_offset_y);

      gimp_item_resize (item, context,
                        new_width, new_height,
                        old_offset_x, old_offset_y);

      if (progress)
        gimp_progress_set_value (progress, progress_current++ / progress_max);
    }

  g_list_free (resize_layers);

  /*  Reposition or remove all guides  */
  list = gimp_image_get_guides (image);

  while (list)
    {
      GimpGuide *guide        = list->data;
      gboolean   remove_guide = FALSE;
      gint       new_position = gimp_guide_get_position (guide);

      list = g_list_next (list);

      switch (gimp_guide_get_orientation (guide))
        {
        case GIMP_ORIENTATION_HORIZONTAL:
          new_position += offset_y;
          if (new_position < 0 || new_position > new_height)
            remove_guide = TRUE;
          break;

        case GIMP_ORIENTATION_VERTICAL:
          new_position += offset_x;
          if (new_position < 0 || new_position > new_width)
            remove_guide = TRUE;
          break;

        default:
          break;
        }

      if (remove_guide)
        gimp_image_remove_guide (image, guide, TRUE);
      else if (new_position != gimp_guide_get_position (guide))
        gimp_image_move_guide (image, guide, new_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 += offset_y;
      if ((sample_point->y < 0) || (sample_point->y > new_height))
        remove_sample_point = TRUE;

      new_x += offset_x;
      if ((sample_point->x < 0) || (sample_point->x > new_width))
        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_size_changed_detailed (image,
                                    offset_x, offset_y,
                                    old_width, old_height);

  g_object_thaw_notify (G_OBJECT (image));

  gimp_unset_busy (image->gimp);
}
Beispiel #9
0
void
gimp_image_rotate (GimpImage        *image,
                   GimpContext      *context,
                   GimpRotationType  rotate_type,
                   GimpProgress     *progress)
{
  GList    *list;
  gdouble   center_x;
  gdouble   center_y;
  gdouble   progress_max;
  gdouble   progress_current = 1.0;
  gint      new_image_width;
  gint      new_image_height;
  gint      previous_image_width;
  gint      previous_image_height;
  gint      offset_x;
  gint      offset_y;
  gboolean  size_changed;

  g_return_if_fail (GIMP_IS_IMAGE (image));
  g_return_if_fail (GIMP_IS_CONTEXT (context));
  g_return_if_fail (progress == NULL || GIMP_IS_PROGRESS (progress));

  gimp_set_busy (image->gimp);

  previous_image_width  = gimp_image_get_width  (image);
  previous_image_height = gimp_image_get_height (image);

  center_x              = previous_image_width  / 2.0;
  center_y              = previous_image_height / 2.0;

  progress_max = (gimp_container_get_n_children (gimp_image_get_channels (image)) +
                  gimp_container_get_n_children (gimp_image_get_layers (image))   +
                  gimp_container_get_n_children (gimp_image_get_vectors (image))  +
                  1 /* selection */);

  g_object_freeze_notify (G_OBJECT (image));

  gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_IMAGE_ROTATE, NULL);

  /*  Resize the image (if needed)  */
  switch (rotate_type)
    {
    case GIMP_ROTATE_90:
    case GIMP_ROTATE_270:
      new_image_width  = gimp_image_get_height (image);
      new_image_height = gimp_image_get_width  (image);
      size_changed     = TRUE;
      offset_x         = (gimp_image_get_width  (image) - new_image_width)  / 2;
      offset_y         = (gimp_image_get_height (image) - new_image_height) / 2;
      break;

    case GIMP_ROTATE_180:
      new_image_width  = gimp_image_get_width  (image);
      new_image_height = gimp_image_get_height (image);
      size_changed     = FALSE;
      offset_x         = 0;
      offset_y         = 0;
      break;

    default:
      g_assert_not_reached ();
      return;
    }

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

      gimp_item_rotate (item, context, rotate_type, center_x, center_y, FALSE);

      gimp_item_set_offset (item, 0, 0);

      if (progress)
        gimp_progress_set_value (progress, progress_current++ / progress_max);
    }

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

      gimp_item_rotate (item, context, rotate_type, center_x, center_y, FALSE);

      gimp_item_set_offset (item, 0, 0);
      gimp_item_set_size (item, new_image_width, new_image_height);

      gimp_item_translate (item,
                           (new_image_width  - gimp_image_get_width  (image)) / 2,
                           (new_image_height - gimp_image_get_height (image)) / 2,
                           FALSE);

      if (progress)
        gimp_progress_set_value (progress, progress_current++ / progress_max);
    }

  /*  Don't forget the selection mask!  */
  {
    GimpChannel *mask = gimp_image_get_mask (image);

    gimp_item_rotate (GIMP_ITEM (mask), context,
                      rotate_type, center_x, center_y, FALSE);

    gimp_item_set_offset (GIMP_ITEM (mask), 0, 0);

    if (progress)
      gimp_progress_set_value (progress, progress_current++ / progress_max);
  }

  /*  Rotate all layers  */
  for (list = gimp_image_get_layer_iter (image);
       list;
       list = g_list_next (list))
    {
      GimpItem *item = list->data;
      gint      off_x;
      gint      off_y;

      gimp_item_get_offset (item, &off_x, &off_y);

      gimp_item_rotate (item, context, rotate_type, center_x, center_y, FALSE);

      gimp_image_rotate_item_offset (image, rotate_type, item, off_x, off_y);

      if (progress)
        gimp_progress_set_value (progress, progress_current++ / progress_max);
    }

  /*  Rotate all Guides  */
  gimp_image_rotate_guides (image, rotate_type);

  /*  Rotate all sample points  */
  gimp_image_rotate_sample_points (image, rotate_type);

  /*  Resize the image (if needed)  */
  if (size_changed)
    {
      gdouble xres;
      gdouble yres;

      gimp_image_undo_push_image_size (image,
                                       NULL,
                                       offset_x,
                                       offset_y,
                                       new_image_width,
                                       new_image_height);

      g_object_set (image,
                    "width",  new_image_width,
                    "height", new_image_height,
                    NULL);

      gimp_image_get_resolution (image, &xres, &yres);

      if (xres != yres)
        gimp_image_set_resolution (image, yres, xres);
    }

  gimp_image_undo_group_end (image);

  if (size_changed)
    gimp_image_size_changed_detailed (image,
                                      -offset_x,
                                      -offset_y,
                                      previous_image_width,
                                      previous_image_height);

  g_object_thaw_notify (G_OBJECT (image));

  gimp_unset_busy (image->gimp);
}
Beispiel #10
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));
  g_return_if_fail (active_layer_only == FALSE ||
                    gimp_image_get_active_layer (image));

  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_get_offset (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
    {
      GList *list;

      g_object_freeze_notify (G_OBJECT (image));

      if (crop_layers)
        gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_IMAGE_CROP,
                                     C_("undo-type", "Crop Image"));
      else
        gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_IMAGE_RESIZE,
                                     C_("undo-type", "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_image_get_channel_iter (image);
           list;
           list = g_list_next (list))
        {
          GimpItem *item = list->data;

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

      /*  Resize all vectors  */
      for (list = gimp_image_get_vectors_iter (image);
           list;
           list = g_list_next (list))
        {
          GimpItem *item = 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_image_get_layer_iter (image);

      while (list)
        {
          GimpItem *item = 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_get_offset (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_get_width  (item) + off_x,
                           0, gimp_image_get_width (image));
              ly2 = CLAMP (gimp_item_get_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),
                                           TRUE, NULL);
                }
            }
        }

      /*  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_invalidate (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);
}