~ubuntu-branches/ubuntu/hoary/gimp/hoary

« back to all changes in this revision

Viewing changes to app/core/gimpimage-scale.c

  • Committer: Bazaar Package Importer
  • Author(s): Sebastien Bacher
  • Date: 2005-04-04 14:51:23 UTC
  • Revision ID: james.westby@ubuntu.com-20050404145123-9py049eeelfymur8
Tags: upstream-2.2.2
ImportĀ upstreamĀ versionĀ 2.2.2

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* The GIMP -- an 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 2 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, write to the Free Software
 
16
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 
17
 */
 
18
 
 
19
#include "config.h"
 
20
 
 
21
#include <glib-object.h>
 
22
 
 
23
#include "core-types.h"
 
24
 
 
25
#include "base/tile-manager.h"
 
26
 
 
27
#include "gimp.h"
 
28
#include "gimpimage.h"
 
29
#include "gimpimage-guides.h"
 
30
#include "gimpimage-scale.h"
 
31
#include "gimpimage-undo.h"
 
32
#include "gimpimage-undo-push.h"
 
33
#include "gimplayer.h"
 
34
#include "gimplist.h"
 
35
#include "gimpprogress.h"
 
36
 
 
37
#include "gimp-intl.h"
 
38
 
 
39
 
 
40
void
 
41
gimp_image_scale (GimpImage             *gimage,
 
42
                  gint                   new_width,
 
43
                  gint                   new_height,
 
44
                  GimpInterpolationType  interpolation_type,
 
45
                  GimpProgress          *progress)
 
46
{
 
47
  GimpItem *item;
 
48
  GList    *list;
 
49
  GList    *remove = NULL;
 
50
  gint      old_width;
 
51
  gint      old_height;
 
52
  gdouble   img_scale_w = 1.0;
 
53
  gdouble   img_scale_h = 1.0;
 
54
  gdouble   progress_max;
 
55
  gdouble   progress_current = 1.0;
 
56
 
 
57
  g_return_if_fail (GIMP_IS_IMAGE (gimage));
 
58
  g_return_if_fail (new_width > 0 && new_height > 0);
 
59
  g_return_if_fail (progress == NULL || GIMP_IS_PROGRESS (progress));
 
60
 
 
61
  gimp_set_busy (gimage->gimp);
 
62
 
 
63
  progress_max = (gimage->channels->num_children +
 
64
                  gimage->layers->num_children   +
 
65
                  gimage->vectors->num_children  +
 
66
                  1 /* selection */);
 
67
 
 
68
  g_object_freeze_notify (G_OBJECT (gimage));
 
69
 
 
70
  gimp_image_undo_group_start (gimage, GIMP_UNDO_GROUP_IMAGE_SCALE,
 
71
                               _("Scale Image"));
 
72
 
 
73
  /*  Push the image size to the stack  */
 
74
  gimp_image_undo_push_image_size (gimage, NULL);
 
75
 
 
76
  old_width      = gimage->width;
 
77
  old_height     = gimage->height;
 
78
  img_scale_w    = (gdouble) new_width  / (gdouble) old_width;
 
79
  img_scale_h    = (gdouble) new_height / (gdouble) old_height;
 
80
 
 
81
  /*  Set the new width and height  */
 
82
  g_object_set (gimage,
 
83
                "width",  new_width,
 
84
                "height", new_height,
 
85
                NULL);
 
86
 
 
87
  /*  Scale all channels  */
 
88
  for (list = GIMP_LIST (gimage->channels)->list;
 
89
       list;
 
90
       list = g_list_next (list))
 
91
    {
 
92
      item = (GimpItem *) list->data;
 
93
 
 
94
      gimp_item_scale (item,
 
95
                       new_width, new_height, 0, 0,
 
96
                       interpolation_type, NULL);
 
97
 
 
98
      if (progress)
 
99
        gimp_progress_set_value (progress, progress_current++ / progress_max);
 
100
    }
 
101
 
 
102
  /*  Scale all vectors  */
 
103
  for (list = GIMP_LIST (gimage->vectors)->list;
 
104
       list;
 
105
       list = g_list_next (list))
 
106
    {
 
107
      item = (GimpItem *) list->data;
 
108
 
 
109
      gimp_item_scale (item,
 
110
                       new_width, new_height, 0, 0,
 
111
                       interpolation_type, NULL);
 
112
 
 
113
      if (progress)
 
114
        gimp_progress_set_value (progress, progress_current++ / progress_max);
 
115
    }
 
116
 
 
117
  /*  Don't forget the selection mask!  */
 
118
  gimp_item_scale (GIMP_ITEM (gimp_image_get_mask (gimage)),
 
119
                   new_width, new_height, 0, 0,
 
120
                   interpolation_type, NULL);
 
121
 
 
122
  if (progress)
 
123
    gimp_progress_set_value (progress, progress_current++ / progress_max);
 
124
 
 
125
  /*  Scale all layers  */
 
126
  for (list = GIMP_LIST (gimage->layers)->list;
 
127
       list;
 
128
       list = g_list_next (list))
 
129
    {
 
130
      item = (GimpItem *) list->data;
 
131
 
 
132
      if (! gimp_item_scale_by_factors (item,
 
133
                                        img_scale_w, img_scale_h,
 
134
                                        interpolation_type, NULL))
 
135
        {
 
136
          /* Since 0 < img_scale_w, img_scale_h, failure due to one or more
 
137
           * vanishing scaled layer dimensions. Implicit delete implemented
 
138
           * here. Upstream warning implemented in resize_check_layer_scaling(),
 
139
           * which offers the user the chance to bail out.
 
140
           */
 
141
          remove = g_list_prepend (remove, item);
 
142
        }
 
143
 
 
144
      if (progress)
 
145
        gimp_progress_set_value (progress, progress_current++ / progress_max);
 
146
    }
 
147
 
 
148
  /* We defer removing layers lost to scaling until now so as not to mix
 
149
   * the operations of iterating over and removal from gimage->layers.
 
150
   */
 
151
  remove = g_list_reverse (remove);
 
152
 
 
153
  for (list = remove; list; list = g_list_next (list))
 
154
    {
 
155
      GimpLayer *layer = list->data;
 
156
 
 
157
      gimp_image_remove_layer (gimage, layer);
 
158
    }
 
159
 
 
160
  g_list_free (remove);
 
161
 
 
162
  /*  Scale all Guides  */
 
163
  for (list = gimage->guides; list; list = g_list_next (list))
 
164
    {
 
165
      GimpGuide *guide = list->data;
 
166
 
 
167
      switch (guide->orientation)
 
168
        {
 
169
        case GIMP_ORIENTATION_HORIZONTAL:
 
170
          gimp_image_undo_push_image_guide (gimage, NULL, guide);
 
171
          guide->position = (guide->position * new_height) / old_height;
 
172
          break;
 
173
 
 
174
        case GIMP_ORIENTATION_VERTICAL:
 
175
          gimp_image_undo_push_image_guide (gimage, NULL, guide);
 
176
          guide->position = (guide->position * new_width) / old_width;
 
177
          break;
 
178
 
 
179
        default:
 
180
          break;
 
181
        }
 
182
    }
 
183
 
 
184
  gimp_image_undo_group_end (gimage);
 
185
 
 
186
  gimp_viewable_size_changed (GIMP_VIEWABLE (gimage));
 
187
  g_object_thaw_notify (G_OBJECT (gimage));
 
188
 
 
189
  gimp_unset_busy (gimage->gimp);
 
190
}
 
191
 
 
192
/**
 
193
 * gimp_image_scale_check:
 
194
 * @gimage:      A #GimpImage.
 
195
 * @new_width:   The new width.
 
196
 * @new_height:  The new height.
 
197
 * @max_memsize: The maximum new memory size.
 
198
 * @new_memsize: The new memory size.
 
199
 *
 
200
 * Inventory the layer list in gimage and check that it may be
 
201
 * scaled to @new_height and @new_width without problems.
 
202
 *
 
203
 * Return value: #GIMP_IMAGE_SCALE_OK if scaling the image will shrink none
 
204
 *               of its layers completely away, and the new image size
 
205
 *               is smaller than @max_memsize.
 
206
 *               #GIMP_IMAGE_SCALE_TOO_SMALL if scaling would remove some
 
207
 *               existing layers.
 
208
 *               #GIMP_IMAGE_SCALE_TOO_BIG if the new image size would
 
209
 *               exceed the maximum specified in the preferences.
 
210
 **/
 
211
GimpImageScaleCheckType
 
212
gimp_image_scale_check (const GimpImage *gimage,
 
213
                        gint             new_width,
 
214
                        gint             new_height,
 
215
                        gint64           max_memsize,
 
216
                        gint64          *new_memsize)
 
217
{
 
218
  GList  *list;
 
219
  gint64  current_size;
 
220
  gint64  scalable_size;
 
221
  gint64  undo_size;
 
222
  gint64  redo_size;
 
223
  gint64  fixed_size;
 
224
  gint64  new_size;
 
225
 
 
226
  g_return_val_if_fail (GIMP_IS_IMAGE (gimage), GIMP_IMAGE_SCALE_TOO_SMALL);
 
227
  g_return_val_if_fail (new_memsize != NULL, GIMP_IMAGE_SCALE_TOO_SMALL);
 
228
 
 
229
  current_size = gimp_object_get_memsize (GIMP_OBJECT (gimage), NULL);
 
230
 
 
231
  /*  the part of the image's memsize that scales linearly with the image  */
 
232
  scalable_size =
 
233
    gimp_object_get_memsize (GIMP_OBJECT (gimage->layers), NULL)         +
 
234
    gimp_object_get_memsize (GIMP_OBJECT (gimage->channels), NULL)       +
 
235
    gimp_object_get_memsize (GIMP_OBJECT (gimage->selection_mask), NULL) +
 
236
    gimp_object_get_memsize (GIMP_OBJECT (gimage->projection), NULL);
 
237
 
 
238
  undo_size = gimp_object_get_memsize (GIMP_OBJECT (gimage->undo_stack), NULL);
 
239
  redo_size = gimp_object_get_memsize (GIMP_OBJECT (gimage->redo_stack), NULL);
 
240
 
 
241
  /*  the fixed part of the image's memsize w/o any undo information  */
 
242
  fixed_size = current_size - undo_size - redo_size - scalable_size;
 
243
 
 
244
  /*  calculate the new size, which is:  */
 
245
  new_size = (fixed_size  +    /*  the fixed part                */
 
246
              scalable_size *  /*  plus the part that scales...  */
 
247
              ((gdouble) new_width  / gimp_image_get_width  (gimage)) *
 
248
              ((gdouble) new_height / gimp_image_get_height (gimage)));
 
249
 
 
250
  *new_memsize = new_size;
 
251
 
 
252
  if (new_size > current_size && new_size > max_memsize)
 
253
    return GIMP_IMAGE_SCALE_TOO_BIG;
 
254
 
 
255
  for (list = GIMP_LIST (gimage->layers)->list;
 
256
       list;
 
257
       list = g_list_next (list))
 
258
    {
 
259
      GimpItem *item = list->data;
 
260
 
 
261
      if (! gimp_item_check_scaling (item, new_width, new_height))
 
262
        return GIMP_IMAGE_SCALE_TOO_SMALL;
 
263
    }
 
264
 
 
265
  return GIMP_IMAGE_SCALE_OK;
 
266
}