From dd80b4c263bd28e5df6316b0fb2bf2d3e6e4493d Mon Sep 17 00:00:00 2001 From: Michael Natterer Date: Tue, 4 Dec 2007 11:30:31 +0000 Subject: [PATCH] added new API gimp_drawable_estimate_memsize() and virtual function 2007-12-04 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 #329468. * app/gimp-log.[ch]: added IMAGE_SCALE log domain. * app/core/gimpimage-scale.c: use it here for debugging output. svn path=/trunk/; revision=24260 --- ChangeLog | 21 +++++++ app/core/gimpdrawable.c | 32 ++++++++-- app/core/gimpdrawable.h | 103 ++++++++++++++++++--------------- app/core/gimpimage-item-list.c | 4 +- app/core/gimpimage-item-list.h | 4 +- app/core/gimpimage-scale.c | 61 ++++++++++++++++--- app/core/gimplayer.c | 22 +++++++ app/gimp-log.c | 3 +- app/gimp-log.h | 3 +- 9 files changed, 186 insertions(+), 67 deletions(-) diff --git a/ChangeLog b/ChangeLog index e2095c46d6..0a35338611 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,24 @@ +2007-12-04 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 #329468. + + * app/gimp-log.[ch]: added IMAGE_SCALE log domain. + + * app/core/gimpimage-scale.c: use it here for debugging output. + 2007-12-04 Sven Neumann * modules/Makefile.am diff --git a/app/core/gimpdrawable.c b/app/core/gimpdrawable.c index 40fdf76ccc..22c060ebfa 100644 --- a/app/core/gimpdrawable.c +++ b/app/core/gimpdrawable.c @@ -87,7 +87,7 @@ static void gimp_drawable_scale (GimpItem *item, 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 (GimpItem *item, 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_update (GimpDrawable *drawable, 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 (GimpDrawableClass *klass) 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 *drawable, 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 (GimpDrawable *drawable, /* 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, diff --git a/app/core/gimpdrawable.h b/app/core/gimpdrawable.h index a8205fca99..10bd130aa1 100644 --- a/app/core/gimpdrawable.h +++ b/app/core/gimpdrawable.h @@ -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); + 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); + 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, diff --git a/app/core/gimpimage-item-list.c b/app/core/gimpimage-item-list.c index 2b719c5aa2..25f2a633b2 100644 --- a/app/core/gimpimage-item-list.c +++ b/app/core/gimpimage-item-list.c @@ -159,8 +159,8 @@ gimp_image_item_list_transform (GimpImage *image, * 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) { diff --git a/app/core/gimpimage-item-list.h b/app/core/gimpimage-item-list.h index d3dfd3ddc2..21990f2988 100644 --- a/app/core/gimpimage-item-list.h +++ b/app/core/gimpimage-item-list.h @@ -48,8 +48,8 @@ void gimp_image_item_list_transform (GimpImage *image, 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); diff --git a/app/core/gimpimage-scale.c b/app/core/gimpimage-scale.c index 6dd11dad6f..fea2aee811 100644 --- a/app/core/gimpimage-scale.c +++ b/app/core/gimpimage-scale.c @@ -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,9 +36,11 @@ #include "gimplayer.h" #include "gimplist.h" #include "gimpprogress.h" +#include "gimpprojection.h" #include "gimpsamplepoint.h" #include "gimpsubprogress.h" +#include "gimp-log.h" #include "gimp-intl.h" @@ -234,9 +237,11 @@ gimp_image_scale_check (const GimpImage *image, 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 +253,47 @@ gimp_image_scale_check (const GimpImage *image, 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); + + GIMP_LOG (IMAGE_SCALE, + "scalable_size = %"G_GINT64_FORMAT" scaled_size = %"G_GINT64_FORMAT, + 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 +302,12 @@ gimp_image_scale_check (const GimpImage *image, 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... */ + + GIMP_LOG (IMAGE_SCALE, + "old_size = %"G_GINT64_FORMAT" new_size = %"G_GINT64_FORMAT, + current_size - undo_size - redo_size, new_size); *new_memsize = new_size; diff --git a/app/core/gimplayer.c b/app/core/gimplayer.c index 5877850d92..fe3995da30 100644 --- a/app/core/gimplayer.c +++ b/app/core/gimplayer.c @@ -136,6 +136,10 @@ static void gimp_layer_transform (GimpItem *item, 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 *klass) 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 *item, 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) { diff --git a/app/gimp-log.c b/app/gimp-log.c index d4c6d5c579..94d623f226 100644 --- a/app/gimp-log.c +++ b/app/gimp-log.c @@ -39,7 +39,8 @@ gimp_log_init (void) { "dnd", GIMP_LOG_DND }, { "help", GIMP_LOG_HELP }, { "dialog-factory", GIMP_LOG_DIALOG_FACTORY }, - { "save-dialog", GIMP_LOG_SAVE_DIALOG } + { "save-dialog", GIMP_LOG_SAVE_DIALOG }, + { "image-scale", GIMP_LOG_IMAGE_SCALE } }; gimp_log_flags = g_parse_debug_string (env_log_val, diff --git a/app/gimp-log.h b/app/gimp-log.h index 612f09515f..dda95ea7b2 100644 --- a/app/gimp-log.h +++ b/app/gimp-log.h @@ -26,7 +26,8 @@ typedef enum GIMP_LOG_DND = 1 << 1, GIMP_LOG_HELP = 1 << 2, GIMP_LOG_DIALOG_FACTORY = 1 << 3, - GIMP_LOG_SAVE_DIALOG = 1 << 4 + GIMP_LOG_SAVE_DIALOG = 1 << 4, + GIMP_LOG_IMAGE_SCALE = 1 << 5 } GimpLogFlags;