1 /* GIMP - The GNU Image Manipulation Program
2 * Copyright (C) 1995 Spencer Kimball and Peter Mattis
3 *
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 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * 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 #include "config.h"
19
20 #include <gdk-pixbuf/gdk-pixbuf.h>
21 #include <gegl.h>
22
23 #include "core-types.h"
24
25 #include "gimp.h"
26 #include "gimpcontext.h"
27 #include "gimpguide.h"
28 #include "gimpimage.h"
29 #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 /* public functions */
41
42 void
gimp_image_crop(GimpImage * image,GimpContext * context,GimpFillType fill_type,gint x,gint y,gint width,gint height,gboolean crop_layers)43 gimp_image_crop (GimpImage *image,
44 GimpContext *context,
45 GimpFillType fill_type,
46 gint x,
47 gint y,
48 gint width,
49 gint height,
50 gboolean crop_layers)
51 {
52 GList *list;
53 gint previous_width;
54 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 previous_height = gimp_image_get_height (image);
61
62 /* Make sure new width and height are non-zero */
63 if (width < 1 || height < 1)
64 return;
65
66 gimp_set_busy (image->gimp);
67
68 g_object_freeze_notify (G_OBJECT (image));
69
70 if (crop_layers)
71 gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_IMAGE_CROP,
72 C_("undo-type", "Crop Image"));
73 else
74 gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_IMAGE_RESIZE,
75 C_("undo-type", "Resize Image"));
76
77 /* Push the image size to the stack */
78 gimp_image_undo_push_image_size (image, NULL,
79 x, y, width, height);
80
81 /* Set the new width and height */
82 g_object_set (image,
83 "width", width,
84 "height", height,
85 NULL);
86
87 /* Resize all channels */
88 for (list = gimp_image_get_channel_iter (image);
89 list;
90 list = g_list_next (list))
91 {
92 GimpItem *item = list->data;
93
94 gimp_item_resize (item, context, GIMP_FILL_TRANSPARENT,
95 width, height, -x, -y);
96 }
97
98 /* Resize all vectors */
99 for (list = gimp_image_get_vectors_iter (image);
100 list;
101 list = g_list_next (list))
102 {
103 GimpItem *item = list->data;
104
105 gimp_item_resize (item, context, GIMP_FILL_TRANSPARENT,
106 width, height, -x, -y);
107 }
108
109 /* Don't forget the selection mask! */
110 gimp_item_resize (GIMP_ITEM (gimp_image_get_mask (image)),
111 context, GIMP_FILL_TRANSPARENT,
112 width, height, -x, -y);
113
114 /* crop all layers */
115 list = gimp_image_get_layer_iter (image);
116
117 while (list)
118 {
119 GimpItem *item = list->data;
120
121 list = g_list_next (list);
122
123 gimp_item_translate (item, -x, -y, TRUE);
124
125 if (crop_layers && ! gimp_item_is_content_locked (item))
126 {
127 gint off_x, off_y;
128 gint lx1, ly1, lx2, ly2;
129
130 gimp_item_get_offset (item, &off_x, &off_y);
131
132 lx1 = CLAMP (off_x, 0, gimp_image_get_width (image));
133 ly1 = CLAMP (off_y, 0, gimp_image_get_height (image));
134 lx2 = CLAMP (gimp_item_get_width (item) + off_x,
135 0, gimp_image_get_width (image));
136 ly2 = CLAMP (gimp_item_get_height (item) + off_y,
137 0, gimp_image_get_height (image));
138
139 width = lx2 - lx1;
140 height = ly2 - ly1;
141
142 if (width > 0 && height > 0)
143 {
144 gimp_item_resize (item, context, fill_type,
145 width, height,
146 -(lx1 - off_x),
147 -(ly1 - off_y));
148 }
149 else
150 {
151 gimp_image_remove_layer (image, GIMP_LAYER (item),
152 TRUE, NULL);
153 }
154 }
155 }
156
157 /* Reposition or remove guides */
158 list = gimp_image_get_guides (image);
159
160 while (list)
161 {
162 GimpGuide *guide = list->data;
163 gboolean remove_guide = FALSE;
164 gint position = gimp_guide_get_position (guide);
165
166 list = g_list_next (list);
167
168 switch (gimp_guide_get_orientation (guide))
169 {
170 case GIMP_ORIENTATION_HORIZONTAL:
171 position -= y;
172 if ((position < 0) || (position > height))
173 remove_guide = TRUE;
174 break;
175
176 case GIMP_ORIENTATION_VERTICAL:
177 position -= x;
178 if ((position < 0) || (position > width))
179 remove_guide = TRUE;
180 break;
181
182 default:
183 break;
184 }
185
186 if (remove_guide)
187 gimp_image_remove_guide (image, guide, TRUE);
188 else if (position != gimp_guide_get_position (guide))
189 gimp_image_move_guide (image, guide, position, TRUE);
190 }
191
192 /* Reposition or remove sample points */
193 list = gimp_image_get_sample_points (image);
194
195 while (list)
196 {
197 GimpSamplePoint *sample_point = list->data;
198 gboolean remove_sample_point = FALSE;
199 gint old_x;
200 gint old_y;
201 gint new_x;
202 gint new_y;
203
204 list = g_list_next (list);
205
206 gimp_sample_point_get_position (sample_point, &old_x, &old_y);
207 new_x = old_x;
208 new_y = old_y;
209
210 new_y -= y;
211 if ((new_y < 0) || (new_y > height))
212 remove_sample_point = TRUE;
213
214 new_x -= x;
215 if ((new_x < 0) || (new_x > width))
216 remove_sample_point = TRUE;
217
218 if (remove_sample_point)
219 gimp_image_remove_sample_point (image, sample_point, TRUE);
220 else if (new_x != old_x || new_y != old_y)
221 gimp_image_move_sample_point (image, sample_point,
222 new_x, new_y, TRUE);
223 }
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 }
235