[gimp] app: confirm transforms that result in very large items
- From: Ell <ell src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gimp] app: confirm transforms that result in very large items
- Date: Sun, 23 Sep 2018 16:59:27 +0000 (UTC)
commit 20a6a3583b435b237cfaf36c178419db3ce9296d
Author: Ell <ell_se yahoo com>
Date: Sun Sep 23 12:24:50 2018 -0400
app: confirm transforms that result in very large items
In GimpTransformTools, precalculate the resulting size of the
transformed item(s), and request confirmation if the size grows to
over 10 times the size of the image (in either dimension). This
protects against transformations that can result in suprprisingly
large items, such as inverted transformations, and, specifically,
perspective-correction transformations performed using the measure
tool, which will be added in the following commits.
app/tools/gimptransformtool.c | 181 ++++++++++++++++++++++++++++++++++++++++++
1 file changed, 181 insertions(+)
---
diff --git a/app/tools/gimptransformtool.c b/app/tools/gimptransformtool.c
index 832f96b7a9..7d84ebb5ec 100644
--- a/app/tools/gimptransformtool.c
+++ b/app/tools/gimptransformtool.c
@@ -21,6 +21,7 @@
#include <gtk/gtk.h>
#include "libgimpmath/gimpmath.h"
+#include "libgimpwidgets/gimpwidgets.h"
#include "tools-types.h"
@@ -28,16 +29,21 @@
#include "core/gimpdrawable-transform.h"
#include "core/gimperror.h"
#include "core/gimpimage.h"
+#include "core/gimpimage-item-list.h"
#include "core/gimpimage-undo.h"
#include "core/gimpitem-linked.h"
#include "core/gimplayer.h"
#include "core/gimplayermask.h"
#include "core/gimpprogress.h"
+#include "core/gimp-transform-resize.h"
#include "vectors/gimpvectors.h"
#include "display/gimpdisplay.h"
+#include "widgets/gimpmessagedialog.h"
+#include "widgets/gimpmessagebox.h"
+
#include "gimptoolcontrol.h"
#include "gimptransformoptions.h"
#include "gimptransformtool.h"
@@ -45,6 +51,14 @@
#include "gimp-intl.h"
+/* the minimal ratio between the transformed item size and the image size,
+ * above which confirmation is required.
+ */
+#define MIN_CONFIRMATION_RATIO 10
+
+
+/* local function prototypes */
+
static GeglBuffer * gimp_transform_tool_real_transform (GimpTransformTool *tr_tool,
GimpItem *item,
GeglBuffer *orig_buffer,
@@ -54,12 +68,18 @@ static GeglBuffer * gimp_transform_tool_real_transform (GimpTransformTool *tr_t
gint *new_offset_x,
gint *new_offset_y);
+static gboolean gimp_transform_tool_confirm (GimpTransformTool *tr_tool,
+ GimpDisplay *display);
+
G_DEFINE_TYPE (GimpTransformTool, gimp_transform_tool, GIMP_TYPE_DRAW_TOOL)
#define parent_class gimp_transform_tool_parent_class
+/* private functions */
+
+
static void
gimp_transform_tool_class_init (GimpTransformToolClass *klass)
{
@@ -163,6 +183,164 @@ gimp_transform_tool_real_transform (GimpTransformTool *tr_tool,
return ret;
}
+static gboolean
+gimp_transform_tool_confirm (GimpTransformTool *tr_tool,
+ GimpDisplay *display)
+{
+ GimpTransformOptions *options = GIMP_TRANSFORM_TOOL_GET_OPTIONS (tr_tool);
+ GimpDisplayShell *shell = gimp_display_get_shell (display);
+ GimpImage *image = gimp_display_get_image (display);
+ GimpItem *active_item;
+ gdouble max_ratio = 0.0;
+
+ active_item = gimp_transform_tool_get_active_item (tr_tool, display);
+
+ if (GIMP_TRANSFORM_TOOL_GET_CLASS (tr_tool)->recalc_matrix)
+ {
+ GimpMatrix3 transform;
+ GeglRectangle selection_bounds;
+ gboolean selection_empty = TRUE;
+ GList *items;
+ GList *iter;
+
+ transform = tr_tool->transform;
+
+ if (options->direction == GIMP_TRANSFORM_BACKWARD)
+ gimp_matrix3_invert (&transform);
+
+ if (options->type == GIMP_TRANSFORM_TYPE_LAYER &&
+ ! gimp_viewable_get_children (GIMP_VIEWABLE (active_item)))
+ {
+ selection_empty = ! gimp_item_bounds (
+ GIMP_ITEM (gimp_image_get_mask (image)),
+ &selection_bounds.x, &selection_bounds.y,
+ &selection_bounds.width, &selection_bounds.height);
+ }
+
+ if (selection_empty && gimp_item_get_linked (active_item))
+ {
+ items = gimp_image_item_list_get_list (image,
+ GIMP_ITEM_TYPE_ALL,
+ GIMP_ITEM_SET_LINKED);
+ }
+ else
+ {
+ items = g_list_append (NULL, active_item);
+ }
+
+ for (iter = items; iter; iter = g_list_next (iter))
+ {
+ GimpItem *item = iter->data;
+ GimpTransformResize clip = options->clip;
+ GeglRectangle orig_bounds;
+ GeglRectangle new_bounds;
+
+ if (GIMP_IS_DRAWABLE (item))
+ {
+ if (selection_empty)
+ {
+ gimp_item_get_offset (item, &orig_bounds.x, &orig_bounds.y);
+
+ orig_bounds.width = gimp_item_get_width (item);
+ orig_bounds.height = gimp_item_get_height (item);
+ }
+ else
+ {
+ orig_bounds = selection_bounds;
+ }
+
+ clip = gimp_drawable_transform_get_effective_clip (
+ GIMP_DRAWABLE (item), NULL, clip);
+ }
+ else
+ {
+ gimp_item_bounds (item,
+ &orig_bounds.x, &orig_bounds.y,
+ &orig_bounds.width, &orig_bounds.height);
+
+ clip = GIMP_TRANSFORM_RESIZE_ADJUST;
+ }
+
+ gimp_transform_resize_boundary (&transform, clip,
+
+ orig_bounds.x,
+ orig_bounds.y,
+ orig_bounds.x + orig_bounds.width,
+ orig_bounds.y + orig_bounds.height,
+
+ &new_bounds.x,
+ &new_bounds.y,
+ &new_bounds.width,
+ &new_bounds.height);
+
+ new_bounds.width -= new_bounds.x;
+ new_bounds.height -= new_bounds.y;
+
+ if (new_bounds.width > orig_bounds.width)
+ {
+ max_ratio = MAX (max_ratio,
+ (gdouble) new_bounds.width /
+ (gdouble) gimp_image_get_width (image));
+ }
+
+ if (new_bounds.height > orig_bounds.height)
+ {
+ max_ratio = MAX (max_ratio,
+ (gdouble) new_bounds.height /
+ (gdouble) gimp_image_get_height (image));
+ }
+ }
+
+ g_list_free (items);
+ }
+
+ if (max_ratio > MIN_CONFIRMATION_RATIO)
+ {
+ GtkWidget *dialog;
+ gint response;
+
+ dialog = gimp_message_dialog_new (_("Confirm Transformation"),
+ GIMP_ICON_DIALOG_WARNING,
+ GTK_WIDGET (shell),
+ GTK_DIALOG_MODAL |
+ GTK_DIALOG_DESTROY_WITH_PARENT,
+ gimp_standard_help_func, NULL,
+
+ _("_Cancel"), GTK_RESPONSE_CANCEL,
+ _("_Transform"), GTK_RESPONSE_OK,
+
+ NULL);
+
+ gtk_dialog_set_alternative_button_order (GTK_DIALOG (dialog),
+ GTK_RESPONSE_OK,
+ GTK_RESPONSE_CANCEL,
+ -1);
+
+ gimp_message_box_set_primary_text (GIMP_MESSAGE_DIALOG (dialog)->box,
+ _("Transformation creates "
+ "a very large item."));
+
+ gimp_message_box_set_text (GIMP_MESSAGE_DIALOG (dialog)->box,
+ _("Applying the transformation will result "
+ "in an item that is over %g times larger "
+ "than the image."),
+ floor (max_ratio));
+
+ response = gtk_dialog_run (GTK_DIALOG (dialog));
+
+ gtk_widget_destroy (dialog);
+
+ if (response != GTK_RESPONSE_OK)
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+/* public functions */
+
+
gboolean
gimp_transform_tool_bounds (GimpTransformTool *tr_tool,
GimpDisplay *display)
@@ -450,6 +628,9 @@ gimp_transform_tool_transform (GimpTransformTool *tr_tool,
return TRUE;
}
+ if (! gimp_transform_tool_confirm (tr_tool, display))
+ return FALSE;
+
gimp_set_busy (display->gimp);
/* We're going to dirty this image, but we want to keep the tool around */
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]