Index: ChangeLog =================================================================== --- ChangeLog (revision 24258) +++ ChangeLog (working copy) @@ -1,5 +1,22 @@ 2007-12-03 Michael Natterer + * app/core/gimpdrawable.[ch]: added new API + gimp_drawable_estimate_memsize() and virtual function + GimpDrawable::estimate_memsize() which estimate the memsize of a + drawable after scaling/resizing. + + * app/core/gimplayer.c: implement the virtual function and take + the layer mask into account. + + * app/core/gimpimage-item-list.[ch] (gimp_image_item_list_get_list): + added const qualifiers. + + * app/core/gimpimage-scale.c (gimp_image_scale_check): use the new + function to correctly estimate the new size instead of scaling the + drawables' memsizes including all constant parts. Fixes bug #501318. + +2007-12-03 Michael Natterer + * tools/pdbgen/pdb/fileops.pdb: pass the new error down to all file functions which take GError arguments. Index: app/core/gimpdrawable.c =================================================================== --- app/core/gimpdrawable.c (revision 24258) +++ app/core/gimpdrawable.c (working copy) @@ -87,7 +87,7 @@ static void gimp_drawable_scale gint new_offset_x, gint new_offset_y, GimpInterpolationType interp_type, - GimpProgress *progress); + GimpProgress *progress); static void gimp_drawable_resize (GimpItem *item, GimpContext *context, gint new_width, @@ -108,10 +108,10 @@ static void gimp_drawable_rotate static void gimp_drawable_transform (GimpItem *item, GimpContext *context, const GimpMatrix3 *matrix, - GimpTransformDirection direction, - GimpInterpolationType interpolation_type, + GimpTransformDirection direction, + GimpInterpolationType interpolation_type, gint recursion_level, - GimpTransformResize clip_result, + GimpTransformResize clip_result, GimpProgress *progress); static gboolean gimp_drawable_get_pixel_at (GimpPickable *pickable, @@ -124,6 +124,10 @@ static void gimp_drawable_real_upd gint width, gint height); +static gint64 gimp_drawable_real_estimate_memsize (const GimpDrawable *drawable, + gint width, + gint height); + static void gimp_drawable_real_set_tiles (GimpDrawable *drawable, gboolean push_undo, const gchar *undo_desc, @@ -206,6 +210,7 @@ gimp_drawable_class_init (GimpDrawableCl klass->update = gimp_drawable_real_update; klass->alpha_changed = NULL; + klass->estimate_memsize = gimp_drawable_real_estimate_memsize; klass->invalidate_boundary = NULL; klass->get_active_components = NULL; klass->apply_region = gimp_drawable_real_apply_region; @@ -612,6 +617,14 @@ gimp_drawable_real_update (GimpDrawable gimp_viewable_invalidate_preview (GIMP_VIEWABLE (drawable)); } +static gint64 +gimp_drawable_real_estimate_memsize (const GimpDrawable *drawable, + gint width, + gint height) +{ + return (gint64) gimp_drawable_bytes (drawable) * width * height; +} + static void gimp_drawable_real_set_tiles (GimpDrawable *drawable, gboolean push_undo, @@ -758,6 +771,17 @@ gimp_drawable_real_swap_pixels (GimpDraw /* public functions */ +gint64 +gimp_drawable_estimate_memsize (const GimpDrawable *drawable, + gint width, + gint height) +{ + g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), 0); + + return GIMP_DRAWABLE_GET_CLASS (drawable)->estimate_memsize (drawable, + width, height); +} + void gimp_drawable_configure (GimpDrawable *drawable, GimpImage *image, Index: app/core/gimpdrawable.h =================================================================== --- app/core/gimpdrawable.h (revision 24258) +++ app/core/gimpdrawable.h (working copy) @@ -53,62 +53,69 @@ struct _GimpDrawableClass GimpItemClass parent_class; /* signals */ - void (* update) (GimpDrawable *drawable, - gint x, - gint y, - gint width, - gint height); - void (* alpha_changed) (GimpDrawable *drawable); + void (* update) (GimpDrawable *drawable, + gint x, + gint y, + gint width, + gint height); + void (* alpha_changed) (GimpDrawable *drawable); /* virtual functions */ - void (* invalidate_boundary) (GimpDrawable *drawable); - void (* get_active_components) (const GimpDrawable *drawable, - gboolean *active); - void (* apply_region) (GimpDrawable *drawable, - PixelRegion *src2PR, - gboolean push_undo, - const gchar *undo_desc, - gdouble opacity, - GimpLayerModeEffects mode, - TileManager *src1_tiles, - gint x, - gint y); - void (* replace_region) (GimpDrawable *drawable, - PixelRegion *src2PR, - gboolean push_undo, - const gchar *undo_desc, - gdouble opacity, - PixelRegion *maskPR, - gint x, - gint y); - void (* set_tiles) (GimpDrawable *drawable, - gboolean push_undo, - const gchar *undo_desc, - TileManager *tiles, - GimpImageType type, - gint offset_x, - gint offset_y); - - void (* push_undo) (GimpDrawable *drawable, - const gchar *undo_desc, - TileManager *tiles, - gboolean sparse, - gint x, - gint y, - gint width, - gint height); - void (* swap_pixels) (GimpDrawable *drawable, - TileManager *tiles, - gboolean sparse, - gint x, - gint y, - gint width, - gint height); + gint64 (* estimate_memsize) (const GimpDrawable *drawable, + gint width, + gint height); + void (* invalidate_boundary) (GimpDrawable *drawable); + void (* get_active_components) (const GimpDrawable *drawable, + gboolean *active); + void (* apply_region) (GimpDrawable *drawable, + PixelRegion *src2PR, + gboolean push_undo, + const gchar *undo_desc, + gdouble opacity, + GimpLayerModeEffects mode, + TileManager *src1_tiles, + gint x, + gint y); + void (* replace_region) (GimpDrawable *drawable, + PixelRegion *src2PR, + gboolean push_undo, + const gchar *undo_desc, + gdouble opacity, + PixelRegion *maskPR, + gint x, + gint y); + void (* set_tiles) (GimpDrawable *drawable, + gboolean push_undo, + const gchar *undo_desc, + TileManager *tiles, + GimpImageType type, + gint offset_x, + gint offset_y); + + void (* push_undo) (GimpDrawable *drawable, + const gchar *undo_desc, + TileManager *tiles, + gboolean sparse, + gint x, + gint y, + gint width, + gint height); + void (* swap_pixels) (GimpDrawable *drawable, + TileManager *tiles, + gboolean sparse, + gint x, + gint y, + gint width, + gint height); }; GType gimp_drawable_get_type (void) G_GNUC_CONST; +gint64 gimp_drawable_estimate_memsize (const GimpDrawable *drawable, + gint width, + gint height); + void gimp_drawable_configure (GimpDrawable *drawable, GimpImage *image, gint offset_x, Index: app/core/gimplayer.c =================================================================== --- app/core/gimplayer.c (revision 24258) +++ app/core/gimplayer.c (working copy) @@ -136,6 +136,10 @@ static void gimp_layer_transform gint recursion_level, GimpTransformResize clip_result, GimpProgress *progress); + +static gint64 gimp_layer_estimate_memsize (const GimpDrawable *drawable, + gint width, + gint height); static void gimp_layer_invalidate_boundary (GimpDrawable *drawable); static void gimp_layer_get_active_components (const GimpDrawable *drawable, gboolean *active); @@ -250,6 +254,7 @@ gimp_layer_class_init (GimpLayerClass *k item_class->rotate_desc = _("Rotate Layer"); item_class->transform_desc = _("Transform Layer"); + drawable_class->estimate_memsize = gimp_layer_estimate_memsize; drawable_class->invalidate_boundary = gimp_layer_invalidate_boundary; drawable_class->get_active_components = gimp_layer_get_active_components; drawable_class->set_tiles = gimp_layer_set_tiles; @@ -798,6 +803,23 @@ gimp_layer_transform (GimpItem clip_result, progress); } +static gint64 +gimp_layer_estimate_memsize (const GimpDrawable *drawable, + gint width, + gint height) +{ + GimpLayer *layer = GIMP_LAYER (drawable); + gint64 memsize = 0; + + if (layer->mask) + memsize += gimp_drawable_estimate_memsize (GIMP_DRAWABLE (layer->mask), + width, height); + + return memsize + GIMP_DRAWABLE_CLASS (parent_class)->estimate_memsize (drawable, + width, + height); +} + static void gimp_layer_invalidate_boundary (GimpDrawable *drawable) { Index: app/core/gimpimage-item-list.c =================================================================== --- app/core/gimpimage-item-list.c (revision 24258) +++ app/core/gimpimage-item-list.c (working copy) @@ -159,8 +159,8 @@ gimp_image_item_list_transform (GimpImag * Return value: The list of items, excluding @exclude. **/ GList * -gimp_image_item_list_get_list (GimpImage *image, - GimpItem *exclude, +gimp_image_item_list_get_list (const GimpImage *image, + const GimpItem *exclude, GimpItemTypeMask type, GimpItemSet set) { Index: app/core/gimpimage-item-list.h =================================================================== --- app/core/gimpimage-item-list.h (revision 24258) +++ app/core/gimpimage-item-list.h (working copy) @@ -48,8 +48,8 @@ void gimp_image_item_list_transform ( GimpTransformResize clip_result, GimpProgress *progress); -GList * gimp_image_item_list_get_list (GimpImage *image, - GimpItem *exclude, +GList * gimp_image_item_list_get_list (const GimpImage *image, + const GimpItem *exclude, GimpItemTypeMask type, GimpItemSet set); Index: app/core/gimpimage-scale.c =================================================================== --- app/core/gimpimage-scale.c (revision 24258) +++ app/core/gimpimage-scale.c (working copy) @@ -28,6 +28,7 @@ #include "gimpguide.h" #include "gimpimage.h" #include "gimpimage-guides.h" +#include "gimpimage-item-list.h" #include "gimpimage-sample-points.h" #include "gimpimage-scale.h" #include "gimpimage-undo.h" @@ -35,6 +36,7 @@ #include "gimplayer.h" #include "gimplist.h" #include "gimpprogress.h" +#include "gimpprojection.h" #include "gimpsamplepoint.h" #include "gimpsubprogress.h" @@ -234,9 +236,11 @@ gimp_image_scale_check (const GimpImage gint64 max_memsize, gint64 *new_memsize) { + GList *drawables; GList *list; gint64 current_size; gint64 scalable_size; + gint64 scaled_size; gint64 undo_size; gint64 redo_size; gint64 fixed_size; @@ -248,11 +252,46 @@ gimp_image_scale_check (const GimpImage current_size = gimp_object_get_memsize (GIMP_OBJECT (image), NULL); /* the part of the image's memsize that scales linearly with the image */ - scalable_size = - gimp_object_get_memsize (GIMP_OBJECT (image->layers), NULL) + - gimp_object_get_memsize (GIMP_OBJECT (image->channels), NULL) + - gimp_object_get_memsize (GIMP_OBJECT (image->selection_mask), NULL) + - gimp_object_get_memsize (GIMP_OBJECT (image->projection), NULL); + drawables = gimp_image_item_list_get_list (image, NULL, + GIMP_ITEM_TYPE_LAYERS | + GIMP_ITEM_TYPE_CHANNELS, + GIMP_ITEM_SET_ALL); + drawables = g_list_prepend (drawables, image->selection_mask); + + scalable_size = 0; + scaled_size = 0; + + for (list = drawables; list; list = g_list_next (list)) + { + GimpDrawable *drawable = list->data; + gdouble width = gimp_item_width (GIMP_ITEM (drawable)); + gdouble height = gimp_item_height (GIMP_ITEM (drawable)); + + scalable_size += + gimp_drawable_estimate_memsize (drawable, + width, height); + + scaled_size += + gimp_drawable_estimate_memsize (drawable, + width * new_width / + gimp_image_get_width (image), + height * new_height / + gimp_image_get_height (image)); + } + + g_list_free (drawables); + + scalable_size += + gimp_projection_estimate_memsize (gimp_image_base_type (image), + gimp_image_get_width (image), + gimp_image_get_height (image)); + + scaled_size += + gimp_projection_estimate_memsize (gimp_image_base_type (image), + new_width, new_height); + + g_printerr ("%s: scalable_size = %"G_GINT64_FORMAT" scaled_size = %"G_GINT64_FORMAT"\n", + G_STRFUNC, scalable_size, scaled_size); undo_size = gimp_object_get_memsize (GIMP_OBJECT (image->undo_stack), NULL); redo_size = gimp_object_get_memsize (GIMP_OBJECT (image->redo_stack), NULL); @@ -261,10 +300,11 @@ gimp_image_scale_check (const GimpImage fixed_size = current_size - undo_size - redo_size - scalable_size; /* calculate the new size, which is: */ - new_size = (fixed_size + /* the fixed part */ - scalable_size * /* plus the part that scales... */ - ((gdouble) new_width / gimp_image_get_width (image)) * - ((gdouble) new_height / gimp_image_get_height (image))); + new_size = (fixed_size + /* the fixed part */ + scaled_size); /* plus the part that scales... */ + + g_printerr ("%s: old_size = %"G_GINT64_FORMAT" new_size = %"G_GINT64_FORMAT"\n", + G_STRFUNC, current_size - undo_size - redo_size, new_size); *new_memsize = new_size;