static void gimp_group_layer_undo_pop (GimpUndo *undo, GimpUndoMode undo_mode, GimpUndoAccumulator *accum) { GimpGroupLayerUndo *group_layer_undo = GIMP_GROUP_LAYER_UNDO (undo); GimpGroupLayer *group; group = GIMP_GROUP_LAYER (GIMP_ITEM_UNDO (undo)->item); GIMP_UNDO_CLASS (parent_class)->pop (undo, undo_mode, accum); switch (undo->undo_type) { case GIMP_UNDO_GROUP_LAYER_SUSPEND: case GIMP_UNDO_GROUP_LAYER_RESUME: if ((undo_mode == GIMP_UNDO_MODE_UNDO && undo->undo_type == GIMP_UNDO_GROUP_LAYER_SUSPEND) || (undo_mode == GIMP_UNDO_MODE_REDO && undo->undo_type == GIMP_UNDO_GROUP_LAYER_RESUME)) { /* resume group layer auto-resizing */ gimp_group_layer_resume_resize (group, FALSE); } else { /* suspend group layer auto-resizing */ gimp_group_layer_suspend_resize (group, FALSE); } break; case GIMP_UNDO_GROUP_LAYER_CONVERT: { GimpImageBaseType type; GimpPrecision precision; type = gimp_drawable_get_base_type (GIMP_DRAWABLE (group)); precision = gimp_drawable_get_precision (GIMP_DRAWABLE (group)); gimp_drawable_convert_type (GIMP_DRAWABLE (group), gimp_item_get_image (GIMP_ITEM (group)), group_layer_undo->prev_type, group_layer_undo->prev_precision, 0, 0, FALSE, FALSE, NULL); group_layer_undo->prev_type = type; group_layer_undo->prev_precision = precision; } break; default: g_assert_not_reached (); } }
void gimp_image_scale (GimpImage *image, gint new_width, gint new_height, GimpInterpolationType interpolation_type, GimpProgress *progress) { GimpProgress *sub_progress; GList *all_layers; GList *all_channels; GList *all_vectors; GList *list; gint old_width; gint old_height; gint offset_x; gint offset_y; gdouble img_scale_w = 1.0; gdouble img_scale_h = 1.0; gint progress_steps; gint progress_current = 0; g_return_if_fail (GIMP_IS_IMAGE (image)); g_return_if_fail (new_width > 0 && new_height > 0); g_return_if_fail (progress == NULL || GIMP_IS_PROGRESS (progress)); gimp_set_busy (image->gimp); sub_progress = gimp_sub_progress_new (progress); all_layers = gimp_image_get_layer_list (image); all_channels = gimp_image_get_channel_list (image); all_vectors = gimp_image_get_vectors_list (image); progress_steps = (g_list_length (all_layers) + g_list_length (all_channels) + g_list_length (all_vectors) + 1 /* selection */); g_object_freeze_notify (G_OBJECT (image)); gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_IMAGE_SCALE, C_("undo-type", "Scale Image")); old_width = gimp_image_get_width (image); old_height = gimp_image_get_height (image); img_scale_w = (gdouble) new_width / (gdouble) old_width; img_scale_h = (gdouble) new_height / (gdouble) old_height; offset_x = (old_width - new_width) / 2; offset_y = (old_height - new_height) / 2; /* Push the image size to the stack */ gimp_image_undo_push_image_size (image, NULL, offset_x, offset_y, new_width, new_height); /* Set the new width and height early, so below image item setters * (esp. guides and sample points) don't choke about moving stuff * out of the image */ g_object_set (image, "width", new_width, "height", new_height, NULL); /* Scale all channels */ for (list = all_channels; list; list = g_list_next (list)) { GimpItem *item = list->data; gimp_sub_progress_set_step (GIMP_SUB_PROGRESS (sub_progress), progress_current++, progress_steps); gimp_item_scale (item, new_width, new_height, 0, 0, interpolation_type, sub_progress); } /* Scale all vectors */ for (list = all_vectors; list; list = g_list_next (list)) { GimpItem *item = list->data; gimp_sub_progress_set_step (GIMP_SUB_PROGRESS (sub_progress), progress_current++, progress_steps); gimp_item_scale (item, new_width, new_height, 0, 0, interpolation_type, sub_progress); } /* Don't forget the selection mask! */ gimp_sub_progress_set_step (GIMP_SUB_PROGRESS (sub_progress), progress_current++, progress_steps); gimp_item_scale (GIMP_ITEM (gimp_image_get_mask (image)), new_width, new_height, 0, 0, interpolation_type, sub_progress); /* Scale all layers */ for (list = all_layers; list; list = g_list_next (list)) { GimpItem *item = list->data; gimp_sub_progress_set_step (GIMP_SUB_PROGRESS (sub_progress), progress_current++, progress_steps); /* group layers are updated automatically */ if (gimp_viewable_get_children (GIMP_VIEWABLE (item))) { gimp_group_layer_suspend_resize (GIMP_GROUP_LAYER (item), FALSE); continue; } if (! gimp_item_scale_by_factors (item, img_scale_w, img_scale_h, interpolation_type, sub_progress)) { /* Since 0 < img_scale_w, img_scale_h, failure due to one or more * vanishing scaled layer dimensions. Implicit delete implemented * here. Upstream warning implemented in resize_check_layer_scaling(), * which offers the user the chance to bail out. */ gimp_image_remove_layer (image, GIMP_LAYER (item), TRUE, NULL); } } for (list = all_layers; list; list = g_list_next (list)) if (gimp_viewable_get_children (list->data)) gimp_group_layer_resume_resize (list->data, FALSE); /* Scale all Guides */ for (list = gimp_image_get_guides (image); list; list = g_list_next (list)) { GimpGuide *guide = list->data; gint position = gimp_guide_get_position (guide); switch (gimp_guide_get_orientation (guide)) { case GIMP_ORIENTATION_HORIZONTAL: gimp_image_move_guide (image, guide, (position * new_height) / old_height, TRUE); break; case GIMP_ORIENTATION_VERTICAL: gimp_image_move_guide (image, guide, (position * new_width) / old_width, TRUE); break; default: break; } } /* Scale all sample points */ for (list = gimp_image_get_sample_points (image); list; list = g_list_next (list)) { GimpSamplePoint *sample_point = list->data; gimp_image_move_sample_point (image, sample_point, sample_point->x * new_width / old_width, sample_point->y * new_height / old_height, TRUE); } gimp_image_undo_group_end (image); g_list_free (all_layers); g_list_free (all_channels); g_list_free (all_vectors); g_object_unref (sub_progress); gimp_image_size_changed_detailed (image, -offset_x, -offset_y, old_width, old_height); g_object_thaw_notify (G_OBJECT (image)); gimp_unset_busy (image->gimp); }