gimpimage-crop.c 6.58 KB
Newer Older
1
/* GIMP - The GNU Image Manipulation Program
2 3
 * Copyright (C) 1995 Spencer Kimball and Peter Mattis
 *
4
 * This program is free software: you can redistribute it and/or modify
5
 * it under the terms of the GNU General Public License as published by
6
 * the Free Software Foundation; either version 3 of the License, or
7 8 9 10 11 12 13 14
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
15
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
16 17 18 19
 */

#include "config.h"

20
#include <gdk-pixbuf/gdk-pixbuf.h>
21
#include <gegl.h>
22 23 24

#include "core-types.h"

25
#include "gimp.h"
26
#include "gimpcontext.h"
27
#include "gimpguide.h"
28 29
#include "gimpimage.h"
#include "gimpimage-crop.h"
30
#include "gimpimage-guides.h"
31
#include "gimpimage-sample-points.h"
32
#include "gimpimage-undo.h"
33
#include "gimpimage-undo-push.h"
34
#include "gimplayer.h"
35
#include "gimpsamplepoint.h"
36

37
#include "gimp-intl.h"
38

39 40 41 42

/*  public functions  */

void
43 44 45 46 47 48 49 50
gimp_image_crop (GimpImage    *image,
                 GimpContext  *context,
                 GimpFillType  fill_type,
                 gint          x,
                 gint          y,
                 gint          width,
                 gint          height,
                 gboolean      crop_layers)
51
{
52
  GList *list;
53 54
  gint   previous_width;
  gint   previous_height;
55

56
  g_return_if_fail (GIMP_IS_IMAGE (image));
57
  g_return_if_fail (GIMP_IS_CONTEXT (context));
58

59
  previous_width  = gimp_image_get_width  (image);
60 61
  previous_height = gimp_image_get_height (image);

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

66
  gimp_set_busy (image->gimp);
67

68
  g_object_freeze_notify (G_OBJECT (image));
69

70 71 72
  if (crop_layers)
    gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_IMAGE_CROP,
                                 C_("undo-type", "Crop Image"));
73
  else
74 75 76 77 78
    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,
79
                                   x, y, width, height);
80 81 82 83 84 85 86 87 88 89 90

  /*  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))
91
    {
92
      GimpItem *item = list->data;
93

94 95
      gimp_item_resize (item, context, GIMP_FILL_TRANSPARENT,
                        width, height, -x, -y);
96
    }
97

98 99 100 101 102 103
  /*  Resize all vectors  */
  for (list = gimp_image_get_vectors_iter (image);
       list;
       list = g_list_next (list))
    {
      GimpItem *item = list->data;
104

105 106
      gimp_item_resize (item, context, GIMP_FILL_TRANSPARENT,
                        width, height, -x, -y);
107
    }
108

109
  /*  Don't forget the selection mask!  */
110 111
  gimp_item_resize (GIMP_ITEM (gimp_image_get_mask (image)),
                    context, GIMP_FILL_TRANSPARENT,
112
                    width, height, -x, -y);
113

114 115
  /*  crop all layers  */
  list = gimp_image_get_layer_iter (image);
116

117 118 119 120 121
  while (list)
    {
      GimpItem *item = list->data;

      list = g_list_next (list);
122

123
      gimp_item_translate (item, -x, -y, TRUE);
124

125
      if (crop_layers)
126
        {
127 128 129 130
          gint off_x, off_y;
          gint lx1, ly1, lx2, ly2;

          gimp_item_get_offset (item, &off_x, &off_y);
131

132 133 134 135 136 137
          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));
138

139 140
          width  = lx2 - lx1;
          height = ly2 - ly1;
141

142
          if (width > 0 && height > 0)
143
            {
144 145
              gimp_item_resize (item, context, fill_type,
                                width, height,
146 147 148 149 150 151 152
                                -(lx1 - off_x),
                                -(ly1 - off_y));
            }
          else
            {
              gimp_image_remove_layer (image, GIMP_LAYER (item),
                                       TRUE, NULL);
153 154
            }
        }
155
    }
156

157
  /*  Reposition or remove guides  */
158
  list = gimp_image_get_guides (image);
159

160 161 162 163 164
  while (list)
    {
      GimpGuide *guide        = list->data;
      gboolean   remove_guide = FALSE;
      gint       position     = gimp_guide_get_position (guide);
165

166
      list = g_list_next (list);
167

168 169 170
      switch (gimp_guide_get_orientation (guide))
        {
        case GIMP_ORIENTATION_HORIZONTAL:
171 172
          position -= y;
          if ((position < 0) || (position > height))
173 174 175 176
            remove_guide = TRUE;
          break;

        case GIMP_ORIENTATION_VERTICAL:
177 178
          position -= x;
          if ((position < 0) || (position > width))
179 180 181 182 183
            remove_guide = TRUE;
          break;

        default:
          break;
184
        }
185

186 187 188 189 190
      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);
    }
191

192 193
  /*  Reposition or remove sample points  */
  list = gimp_image_get_sample_points (image);
194

195 196 197 198
  while (list)
    {
      GimpSamplePoint *sample_point        = list->data;
      gboolean         remove_sample_point = FALSE;
199 200 201 202
      gint             old_x;
      gint             old_y;
      gint             new_x;
      gint             new_y;
203 204 205

      list = g_list_next (list);

206 207 208 209
      gimp_sample_point_get_position (sample_point, &old_x, &old_y);
      new_x = old_x;
      new_y = old_y;

210
      new_y -= y;
211 212
      if ((new_y < 0) || (new_y > height))
       remove_sample_point = TRUE;
213

214
      new_x -= x;
215
      if ((new_x < 0) || (new_x > width))
216 217 218 219
        remove_sample_point = TRUE;

      if (remove_sample_point)
        gimp_image_remove_sample_point (image, sample_point, TRUE);
220
      else if (new_x != old_x || new_y != old_y)
221 222 223
        gimp_image_move_sample_point (image, sample_point,
                                      new_x, new_y, TRUE);
    }
224

225
  gimp_image_undo_group_end (image);
226

227
  gimp_image_size_changed_detailed (image,
228
                                    -x, -y,
229
                                    previous_width, previous_height);
230 231

  g_object_thaw_notify (G_OBJECT (image));
232

233
  gimp_unset_busy (image->gimp);
234
}