app/commands.c app/gimpimage.c app/layer.c app/layer.h app/resize.c

2000-02-26 Garry R. Osgood <gosgood@idt.net>
* app/commands.c
* app/gimpimage.c
* app/layer.c
* app/layer.h
* app/resize.c
* app/resize.h

Aliasing artifacts that changed relative positions
of layers under scaling, giving rise to #5271, are
minimized by a new layer.c function,
layer_scale_by_factors(). Closes #5271. See
http://idt.net/~gosgood/gimp-patch/patch07.html for
further detail. See also usage documentation for
layer_scale() and layer_scale_by_factors() in
layer.c.

Provided logic for the Scale Image dialog box to
pre-check an image's layers for the possibility that
a particular scaling, s: 0 < s < 1, reduces a layer
dimension to zero. Should this case prevail, a
boolean dialog box warns the user of the
possibility. The user may (1) Cancel, returning
focus to Scale Image and the possibility of
corrective adjustment, or (2) OK the scaling. The
layers that will vanish upon the new scaling are
culled from the GimpImage::layers list first.
This commit is contained in:
Garry R. Osgood 2000-02-26 18:46:08 +00:00 committed by Garry R. Osgood
parent 882c240a38
commit 8769bbb456
27 changed files with 1513 additions and 610 deletions

View File

@ -1,3 +1,36 @@
2000-02-26 Garry R. Osgood <gosgood@idt.net>
* app/commands.c
* app/gimpimage.c
* app/layer.c
* app/layer.h
* app/resize.c
* app/resize.h
* help/C/dialogs/Makefile.am
* help/C/dialogs/scale_layer_warn.html (new: placeholder)
Aliasing artifacts that changed relative positions
of layers under scaling, giving rise to #5271, are
minimized by a new layer.c function,
layer_scale_by_factors(). Closes #5271. See
http://idt.net/~gosgood/gimp-patch/patch07.html
for further detail. See also usage documentation
for layer_scale() and layer_scale_by_factors()
in layer.c.
Provided logic for the Scale Image dialog box
<Image->Scale Image...>
to pre-check an image's layers for the possibility
that a particular scaling, s: 0 < s < 1, reduces
a layer dimension to zero. Should this case prevail,
a boolean dialog box warns the user of the possibility.
The user may (1) Cancel, returning focus to Scale
Image and the possibility of corrective adjustment, or
(2) OK the scaling. The layers that will vanish upon
the new scaling are culled from the GimpImage::layers
list first. >>Please Test This!<< I've tested it
fairly thoroughly, but my physician reports that I
suffer from hubris. ;)
2000-02-26 Michael Natterer <mitch@gimp.org>
* libgimp/gimphelpui.[ch]

View File

@ -65,27 +65,21 @@
gdisp = gdisplay_active (); \
if (!gdisp) return
typedef struct
{
Resize *resize;
GimpImage *gimage;
} ImageResize;
/* external functions */
extern void layers_dialog_layer_merge_query (GImage *, gboolean);
/* local functions */
static void image_resize_callback (GtkWidget *, gpointer);
static void image_scale_callback (GtkWidget *, gpointer);
static void image_cancel_callback (GtkWidget *, gpointer);
static void gimage_mask_feather_callback (GtkWidget *, gdouble, GimpUnit,
gpointer);
static void gimage_mask_border_callback (GtkWidget *, gdouble, GimpUnit,
gpointer);
static void gimage_mask_grow_callback (GtkWidget *, gdouble, GimpUnit,
gpointer);
static void gimage_mask_shrink_callback (GtkWidget *, gdouble, GimpUnit,
gpointer);
static void image_resize_callback (GtkWidget *, gpointer);
static void image_scale_callback (GtkWidget *, gpointer);
static void image_cancel_callback (GtkWidget *, gpointer);
static void gimage_mask_feather_callback (GtkWidget *, gdouble, GimpUnit,
gpointer);
static void gimage_mask_border_callback (GtkWidget *, gdouble, GimpUnit,
gpointer);
static void gimage_mask_grow_callback (GtkWidget *, gdouble, GimpUnit,
gpointer);
static void gimage_mask_shrink_callback (GtkWidget *, gdouble, GimpUnit,
gpointer);
/* local variables */
static gdouble selection_feather_radius = 5.0;
@ -1318,94 +1312,29 @@ static void
image_scale_callback (GtkWidget *widget,
gpointer client_data)
{
ImageResize *image_scale;
GImage *gimage;
gboolean rulers_flush = FALSE;
gboolean display_flush = FALSE; /* this is a bit ugly:
we hijack the flush variable
to check if an undo_group was
already started */
ImageResize *image_scale = NULL;
image_scale = (ImageResize *) client_data;
if ((gimage = image_scale->gimage) != NULL)
g_assert((image_scale = (ImageResize *) client_data) != NULL);
g_assert(image_scale->gimage != NULL);
if(TRUE == resize_check_layer_scaling(image_scale))
{
if (image_scale->resize->resolution_x != gimage->xresolution ||
image_scale->resize->resolution_y != gimage->yresolution)
{
undo_push_group_start (gimage, IMAGE_SCALE_UNDO);
gimage_set_resolution (gimage,
image_scale->resize->resolution_x,
image_scale->resize->resolution_y);
rulers_flush = TRUE;
display_flush = TRUE;
}
if (image_scale->resize->unit != gimage->unit)
{
if (!display_flush)
undo_push_group_start (gimage, IMAGE_SCALE_UNDO);
gimage_set_unit (gimage, image_scale->resize->unit);
gdisplays_setup_scale (gimage);
gdisplays_resize_cursor_label (gimage);
rulers_flush = TRUE;
display_flush = TRUE;
}
if (image_scale->resize->width != gimage->width ||
image_scale->resize->height != gimage->height)
{
if (image_scale->resize->width > 0 &&
image_scale->resize->height > 0)
{
if (!display_flush)
undo_push_group_start (gimage, IMAGE_SCALE_UNDO);
gimage_scale (gimage,
image_scale->resize->width,
image_scale->resize->height);
display_flush = TRUE;
}
else
{
g_message (_("Scale Error: Both width and height must be "
"greater than zero."));
return;
}
}
if (rulers_flush)
{
gdisplays_setup_scale (gimage);
gdisplays_resize_cursor_label (gimage);
}
if (display_flush)
{
undo_push_group_end (gimage);
gdisplays_flush ();
}
resize_scale_implement(image_scale);
resize_widget_free (image_scale->resize);
g_free (image_scale);
}
resize_widget_free (image_scale->resize);
g_free (image_scale);
}
static void
image_cancel_callback (GtkWidget *widget,
gpointer client_data)
{
ImageResize *image_resize;
ImageResize *image_scale;
image_resize = (ImageResize *) client_data;
image_scale = (ImageResize *) client_data;
resize_widget_free (image_resize->resize);
g_free (image_resize);
resize_widget_free (image_scale->resize);
g_free (image_scale);
}
static void

View File

@ -65,27 +65,21 @@
gdisp = gdisplay_active (); \
if (!gdisp) return
typedef struct
{
Resize *resize;
GimpImage *gimage;
} ImageResize;
/* external functions */
extern void layers_dialog_layer_merge_query (GImage *, gboolean);
/* local functions */
static void image_resize_callback (GtkWidget *, gpointer);
static void image_scale_callback (GtkWidget *, gpointer);
static void image_cancel_callback (GtkWidget *, gpointer);
static void gimage_mask_feather_callback (GtkWidget *, gdouble, GimpUnit,
gpointer);
static void gimage_mask_border_callback (GtkWidget *, gdouble, GimpUnit,
gpointer);
static void gimage_mask_grow_callback (GtkWidget *, gdouble, GimpUnit,
gpointer);
static void gimage_mask_shrink_callback (GtkWidget *, gdouble, GimpUnit,
gpointer);
static void image_resize_callback (GtkWidget *, gpointer);
static void image_scale_callback (GtkWidget *, gpointer);
static void image_cancel_callback (GtkWidget *, gpointer);
static void gimage_mask_feather_callback (GtkWidget *, gdouble, GimpUnit,
gpointer);
static void gimage_mask_border_callback (GtkWidget *, gdouble, GimpUnit,
gpointer);
static void gimage_mask_grow_callback (GtkWidget *, gdouble, GimpUnit,
gpointer);
static void gimage_mask_shrink_callback (GtkWidget *, gdouble, GimpUnit,
gpointer);
/* local variables */
static gdouble selection_feather_radius = 5.0;
@ -1318,94 +1312,29 @@ static void
image_scale_callback (GtkWidget *widget,
gpointer client_data)
{
ImageResize *image_scale;
GImage *gimage;
gboolean rulers_flush = FALSE;
gboolean display_flush = FALSE; /* this is a bit ugly:
we hijack the flush variable
to check if an undo_group was
already started */
ImageResize *image_scale = NULL;
image_scale = (ImageResize *) client_data;
if ((gimage = image_scale->gimage) != NULL)
g_assert((image_scale = (ImageResize *) client_data) != NULL);
g_assert(image_scale->gimage != NULL);
if(TRUE == resize_check_layer_scaling(image_scale))
{
if (image_scale->resize->resolution_x != gimage->xresolution ||
image_scale->resize->resolution_y != gimage->yresolution)
{
undo_push_group_start (gimage, IMAGE_SCALE_UNDO);
gimage_set_resolution (gimage,
image_scale->resize->resolution_x,
image_scale->resize->resolution_y);
rulers_flush = TRUE;
display_flush = TRUE;
}
if (image_scale->resize->unit != gimage->unit)
{
if (!display_flush)
undo_push_group_start (gimage, IMAGE_SCALE_UNDO);
gimage_set_unit (gimage, image_scale->resize->unit);
gdisplays_setup_scale (gimage);
gdisplays_resize_cursor_label (gimage);
rulers_flush = TRUE;
display_flush = TRUE;
}
if (image_scale->resize->width != gimage->width ||
image_scale->resize->height != gimage->height)
{
if (image_scale->resize->width > 0 &&
image_scale->resize->height > 0)
{
if (!display_flush)
undo_push_group_start (gimage, IMAGE_SCALE_UNDO);
gimage_scale (gimage,
image_scale->resize->width,
image_scale->resize->height);
display_flush = TRUE;
}
else
{
g_message (_("Scale Error: Both width and height must be "
"greater than zero."));
return;
}
}
if (rulers_flush)
{
gdisplays_setup_scale (gimage);
gdisplays_resize_cursor_label (gimage);
}
if (display_flush)
{
undo_push_group_end (gimage);
gdisplays_flush ();
}
resize_scale_implement(image_scale);
resize_widget_free (image_scale->resize);
g_free (image_scale);
}
resize_widget_free (image_scale->resize);
g_free (image_scale);
}
static void
image_cancel_callback (GtkWidget *widget,
gpointer client_data)
{
ImageResize *image_resize;
ImageResize *image_scale;
image_resize = (ImageResize *) client_data;
image_scale = (ImageResize *) client_data;
resize_widget_free (image_resize->resize);
g_free (image_resize);
resize_widget_free (image_scale->resize);
g_free (image_scale);
}
static void

View File

@ -532,10 +532,20 @@ gimp_image_scale (GimpImage *gimage,
Layer *layer;
Layer *floating_layer;
GSList *list;
GSList *marklist = NULL;
GList *glist;
Guide *guide;
gint old_width, old_height;
gint layer_width, layer_height;
gint old_width, old_height;
gint old_offset_x, old_offset_y;
gint layer_width, layer_height;
gdouble img_scale_w = 1.0;
gdouble img_scale_h = 1.0;
if((new_width == 0) || (new_height == 0))
{
g_message(_("gimp_image_scale: Layer with zero width or height has been rejected."));
return;
}
gimp_add_busy_cursors ();
@ -552,11 +562,14 @@ gimp_image_scale (GimpImage *gimage,
undo_push_gimage_mod (gimage);
/* Set the new width and height */
old_width = gimage->width;
old_height = gimage->height;
old_width = gimage->width;
old_height = gimage->height;
gimage->width = new_width;
gimage->height = new_height;
img_scale_w = (gdouble)new_width/(gdouble)old_width;
img_scale_h = (gdouble)new_height/(gdouble)old_height;
/* Scale all channels */
list = gimage->channels;
while (list)
@ -574,14 +587,30 @@ gimp_image_scale (GimpImage *gimage,
list = gimage->layers;
while (list)
{
layer = (Layer *) list->data;
layer = (Layer *) list->data;
if(FALSE == layer_scale_by_factors(layer, img_scale_w, img_scale_h))
{
/* 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() */
/* [resize.c line 1295], which offers the user the chance to bail out.*/
layer_width = (new_width *
drawable_width (GIMP_DRAWABLE(layer))) / old_width;
layer_height = (new_height *
drawable_height (GIMP_DRAWABLE(layer))) / old_height;
layer_scale (layer, layer_width, layer_height, FALSE);
list = g_slist_next (list);
marklist = g_list_append(marklist, layer);
}
list = g_slist_next (list);
}
/* We defer removing layers lost to scaling until now */
/* so as not to mix the operations of iterating over and removal */
/* from gimage->layers. */
if(marklist != NULL)
{
while(marklist)
{
layer = marklist->data;
gimage_remove_layer(gimage, layer);
marklist = g_slist_remove(marklist, layer);
}
}
/* Scale any Guides */

View File

@ -532,10 +532,20 @@ gimp_image_scale (GimpImage *gimage,
Layer *layer;
Layer *floating_layer;
GSList *list;
GSList *marklist = NULL;
GList *glist;
Guide *guide;
gint old_width, old_height;
gint layer_width, layer_height;
gint old_width, old_height;
gint old_offset_x, old_offset_y;
gint layer_width, layer_height;
gdouble img_scale_w = 1.0;
gdouble img_scale_h = 1.0;
if((new_width == 0) || (new_height == 0))
{
g_message(_("gimp_image_scale: Layer with zero width or height has been rejected."));
return;
}
gimp_add_busy_cursors ();
@ -552,11 +562,14 @@ gimp_image_scale (GimpImage *gimage,
undo_push_gimage_mod (gimage);
/* Set the new width and height */
old_width = gimage->width;
old_height = gimage->height;
old_width = gimage->width;
old_height = gimage->height;
gimage->width = new_width;
gimage->height = new_height;
img_scale_w = (gdouble)new_width/(gdouble)old_width;
img_scale_h = (gdouble)new_height/(gdouble)old_height;
/* Scale all channels */
list = gimage->channels;
while (list)
@ -574,14 +587,30 @@ gimp_image_scale (GimpImage *gimage,
list = gimage->layers;
while (list)
{
layer = (Layer *) list->data;
layer = (Layer *) list->data;
if(FALSE == layer_scale_by_factors(layer, img_scale_w, img_scale_h))
{
/* 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() */
/* [resize.c line 1295], which offers the user the chance to bail out.*/
layer_width = (new_width *
drawable_width (GIMP_DRAWABLE(layer))) / old_width;
layer_height = (new_height *
drawable_height (GIMP_DRAWABLE(layer))) / old_height;
layer_scale (layer, layer_width, layer_height, FALSE);
list = g_slist_next (list);
marklist = g_list_append(marklist, layer);
}
list = g_slist_next (list);
}
/* We defer removing layers lost to scaling until now */
/* so as not to mix the operations of iterating over and removal */
/* from gimage->layers. */
if(marklist != NULL)
{
while(marklist)
{
layer = marklist->data;
gimage_remove_layer(gimage, layer);
marklist = g_slist_remove(marklist, layer);
}
}
/* Scale any Guides */

View File

@ -532,10 +532,20 @@ gimp_image_scale (GimpImage *gimage,
Layer *layer;
Layer *floating_layer;
GSList *list;
GSList *marklist = NULL;
GList *glist;
Guide *guide;
gint old_width, old_height;
gint layer_width, layer_height;
gint old_width, old_height;
gint old_offset_x, old_offset_y;
gint layer_width, layer_height;
gdouble img_scale_w = 1.0;
gdouble img_scale_h = 1.0;
if((new_width == 0) || (new_height == 0))
{
g_message(_("gimp_image_scale: Layer with zero width or height has been rejected."));
return;
}
gimp_add_busy_cursors ();
@ -552,11 +562,14 @@ gimp_image_scale (GimpImage *gimage,
undo_push_gimage_mod (gimage);
/* Set the new width and height */
old_width = gimage->width;
old_height = gimage->height;
old_width = gimage->width;
old_height = gimage->height;
gimage->width = new_width;
gimage->height = new_height;
img_scale_w = (gdouble)new_width/(gdouble)old_width;
img_scale_h = (gdouble)new_height/(gdouble)old_height;
/* Scale all channels */
list = gimage->channels;
while (list)
@ -574,14 +587,30 @@ gimp_image_scale (GimpImage *gimage,
list = gimage->layers;
while (list)
{
layer = (Layer *) list->data;
layer = (Layer *) list->data;
if(FALSE == layer_scale_by_factors(layer, img_scale_w, img_scale_h))
{
/* 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() */
/* [resize.c line 1295], which offers the user the chance to bail out.*/
layer_width = (new_width *
drawable_width (GIMP_DRAWABLE(layer))) / old_width;
layer_height = (new_height *
drawable_height (GIMP_DRAWABLE(layer))) / old_height;
layer_scale (layer, layer_width, layer_height, FALSE);
list = g_slist_next (list);
marklist = g_list_append(marklist, layer);
}
list = g_slist_next (list);
}
/* We defer removing layers lost to scaling until now */
/* so as not to mix the operations of iterating over and removal */
/* from gimage->layers. */
if(marklist != NULL)
{
while(marklist)
{
layer = marklist->data;
gimage_remove_layer(gimage, layer);
marklist = g_slist_remove(marklist, layer);
}
}
/* Scale any Guides */

View File

@ -532,10 +532,20 @@ gimp_image_scale (GimpImage *gimage,
Layer *layer;
Layer *floating_layer;
GSList *list;
GSList *marklist = NULL;
GList *glist;
Guide *guide;
gint old_width, old_height;
gint layer_width, layer_height;
gint old_width, old_height;
gint old_offset_x, old_offset_y;
gint layer_width, layer_height;
gdouble img_scale_w = 1.0;
gdouble img_scale_h = 1.0;
if((new_width == 0) || (new_height == 0))
{
g_message(_("gimp_image_scale: Layer with zero width or height has been rejected."));
return;
}
gimp_add_busy_cursors ();
@ -552,11 +562,14 @@ gimp_image_scale (GimpImage *gimage,
undo_push_gimage_mod (gimage);
/* Set the new width and height */
old_width = gimage->width;
old_height = gimage->height;
old_width = gimage->width;
old_height = gimage->height;
gimage->width = new_width;
gimage->height = new_height;
img_scale_w = (gdouble)new_width/(gdouble)old_width;
img_scale_h = (gdouble)new_height/(gdouble)old_height;
/* Scale all channels */
list = gimage->channels;
while (list)
@ -574,14 +587,30 @@ gimp_image_scale (GimpImage *gimage,
list = gimage->layers;
while (list)
{
layer = (Layer *) list->data;
layer = (Layer *) list->data;
if(FALSE == layer_scale_by_factors(layer, img_scale_w, img_scale_h))
{
/* 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() */
/* [resize.c line 1295], which offers the user the chance to bail out.*/
layer_width = (new_width *
drawable_width (GIMP_DRAWABLE(layer))) / old_width;
layer_height = (new_height *
drawable_height (GIMP_DRAWABLE(layer))) / old_height;
layer_scale (layer, layer_width, layer_height, FALSE);
list = g_slist_next (list);
marklist = g_list_append(marklist, layer);
}
list = g_slist_next (list);
}
/* We defer removing layers lost to scaling until now */
/* so as not to mix the operations of iterating over and removal */
/* from gimage->layers. */
if(marklist != NULL)
{
while(marklist)
{
layer = marklist->data;
gimage_remove_layer(gimage, layer);
marklist = g_slist_remove(marklist, layer);
}
}
/* Scale any Guides */

View File

@ -532,10 +532,20 @@ gimp_image_scale (GimpImage *gimage,
Layer *layer;
Layer *floating_layer;
GSList *list;
GSList *marklist = NULL;
GList *glist;
Guide *guide;
gint old_width, old_height;
gint layer_width, layer_height;
gint old_width, old_height;
gint old_offset_x, old_offset_y;
gint layer_width, layer_height;
gdouble img_scale_w = 1.0;
gdouble img_scale_h = 1.0;
if((new_width == 0) || (new_height == 0))
{
g_message(_("gimp_image_scale: Layer with zero width or height has been rejected."));
return;
}
gimp_add_busy_cursors ();
@ -552,11 +562,14 @@ gimp_image_scale (GimpImage *gimage,
undo_push_gimage_mod (gimage);
/* Set the new width and height */
old_width = gimage->width;
old_height = gimage->height;
old_width = gimage->width;
old_height = gimage->height;
gimage->width = new_width;
gimage->height = new_height;
img_scale_w = (gdouble)new_width/(gdouble)old_width;
img_scale_h = (gdouble)new_height/(gdouble)old_height;
/* Scale all channels */
list = gimage->channels;
while (list)
@ -574,14 +587,30 @@ gimp_image_scale (GimpImage *gimage,
list = gimage->layers;
while (list)
{
layer = (Layer *) list->data;
layer = (Layer *) list->data;
if(FALSE == layer_scale_by_factors(layer, img_scale_w, img_scale_h))
{
/* 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() */
/* [resize.c line 1295], which offers the user the chance to bail out.*/
layer_width = (new_width *
drawable_width (GIMP_DRAWABLE(layer))) / old_width;
layer_height = (new_height *
drawable_height (GIMP_DRAWABLE(layer))) / old_height;
layer_scale (layer, layer_width, layer_height, FALSE);
list = g_slist_next (list);
marklist = g_list_append(marklist, layer);
}
list = g_slist_next (list);
}
/* We defer removing layers lost to scaling until now */
/* so as not to mix the operations of iterating over and removal */
/* from gimage->layers. */
if(marklist != NULL)
{
while(marklist)
{
layer = marklist->data;
gimage_remove_layer(gimage, layer);
marklist = g_slist_remove(marklist, layer);
}
}
/* Scale any Guides */

View File

@ -532,10 +532,20 @@ gimp_image_scale (GimpImage *gimage,
Layer *layer;
Layer *floating_layer;
GSList *list;
GSList *marklist = NULL;
GList *glist;
Guide *guide;
gint old_width, old_height;
gint layer_width, layer_height;
gint old_width, old_height;
gint old_offset_x, old_offset_y;
gint layer_width, layer_height;
gdouble img_scale_w = 1.0;
gdouble img_scale_h = 1.0;
if((new_width == 0) || (new_height == 0))
{
g_message(_("gimp_image_scale: Layer with zero width or height has been rejected."));
return;
}
gimp_add_busy_cursors ();
@ -552,11 +562,14 @@ gimp_image_scale (GimpImage *gimage,
undo_push_gimage_mod (gimage);
/* Set the new width and height */
old_width = gimage->width;
old_height = gimage->height;
old_width = gimage->width;
old_height = gimage->height;
gimage->width = new_width;
gimage->height = new_height;
img_scale_w = (gdouble)new_width/(gdouble)old_width;
img_scale_h = (gdouble)new_height/(gdouble)old_height;
/* Scale all channels */
list = gimage->channels;
while (list)
@ -574,14 +587,30 @@ gimp_image_scale (GimpImage *gimage,
list = gimage->layers;
while (list)
{
layer = (Layer *) list->data;
layer = (Layer *) list->data;
if(FALSE == layer_scale_by_factors(layer, img_scale_w, img_scale_h))
{
/* 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() */
/* [resize.c line 1295], which offers the user the chance to bail out.*/
layer_width = (new_width *
drawable_width (GIMP_DRAWABLE(layer))) / old_width;
layer_height = (new_height *
drawable_height (GIMP_DRAWABLE(layer))) / old_height;
layer_scale (layer, layer_width, layer_height, FALSE);
list = g_slist_next (list);
marklist = g_list_append(marklist, layer);
}
list = g_slist_next (list);
}
/* We defer removing layers lost to scaling until now */
/* so as not to mix the operations of iterating over and removal */
/* from gimage->layers. */
if(marklist != NULL)
{
while(marklist)
{
layer = marklist->data;
gimage_remove_layer(gimage, layer);
marklist = g_slist_remove(marklist, layer);
}
}
/* Scale any Guides */

View File

@ -346,7 +346,7 @@ layer_copy (Layer *layer,
new_type, layer_name, layer->opacity, layer->mode);
if (!new_layer)
{
g_message ("layer_copy: could not allocate new layer");
g_message (_("layer_copy: could not allocate new layer"));
goto cleanup;
}
@ -421,7 +421,7 @@ layer_new_from_tiles (GimpImage *gimage,
if (!new_layer)
{
g_message ("layer_new_from_tiles: could not allocate new layer");
g_message (_("layer_new_from_tiles: could not allocate new layer"));
return NULL;
}
@ -723,18 +723,16 @@ layer_add_alpha (Layer *layer)
"restructure");
}
void
layer_scale (Layer *layer,
gint new_width,
gint new_height,
gint local_origin)
static void
layer_scale_lowlevel(Layer *layer,
gint new_width,
gint new_height,
gint new_offset_x,
gint new_offset_y)
{
PixelRegion srcPR, destPR;
TileManager *new_tiles;
if (new_width == 0 || new_height == 0)
return;
/* Update the old layer position */
drawable_update (GIMP_DRAWABLE(layer),
0, 0,
@ -761,29 +759,12 @@ layer_scale (Layer *layer,
undo_push_layer_mod (GIMP_DRAWABLE(layer)->gimage, layer);
/* Configure the new layer */
if (local_origin)
{
int cx, cy;
cx = GIMP_DRAWABLE(layer)->offset_x + GIMP_DRAWABLE(layer)->width / 2;
cy = GIMP_DRAWABLE(layer)->offset_y + GIMP_DRAWABLE(layer)->height / 2;
GIMP_DRAWABLE(layer)->offset_x = cx - (new_width / 2);
GIMP_DRAWABLE(layer)->offset_y = cy - (new_height / 2);
}
else
{
double xrat, yrat;
xrat = (double) new_width / (double) GIMP_DRAWABLE(layer)->width;
yrat = (double) new_height / (double) GIMP_DRAWABLE(layer)->height;
GIMP_DRAWABLE(layer)->offset_x = (int) (xrat * GIMP_DRAWABLE(layer)->offset_x);
GIMP_DRAWABLE(layer)->offset_y = (int) (yrat * GIMP_DRAWABLE(layer)->offset_y);
}
GIMP_DRAWABLE(layer)->tiles = new_tiles;
GIMP_DRAWABLE(layer)->width = new_width;
GIMP_DRAWABLE(layer)->height = new_height;
GIMP_DRAWABLE(layer)->offset_x = new_offset_x;
GIMP_DRAWABLE(layer)->offset_y = new_offset_y;
GIMP_DRAWABLE(layer)->tiles = new_tiles;
GIMP_DRAWABLE(layer)->width = new_width;
GIMP_DRAWABLE(layer)->height = new_height;
/* If there is a layer mask, make sure it gets scaled also */
if (layer->mask)
@ -794,11 +775,146 @@ layer_scale (Layer *layer,
}
/* Update the new layer position */
drawable_update (GIMP_DRAWABLE(layer),
0, 0,
GIMP_DRAWABLE(layer)->width, GIMP_DRAWABLE(layer)->height);
}
/**
* layer_check_scaling:
* @layer: Layer to check
* @new_width: proposed width of layer, in pixels
* @new_height: proposed height of layer, in pixels
* Scales layer dimensions, then snaps them to pixel centers
* Returns FALSE if any dimension reduces to zero as a result
* of this; otherwise, returns TRUE.
*/
gboolean layer_check_scaling (Layer *layer,
gint new_width,
gint new_height)
{
GImage *gimage = GIMP_DRAWABLE(layer)->gimage;
gdouble img_scale_w = (gdouble)new_width/(gdouble)gimage->width;
gdouble img_scale_h = (gdouble)new_height/(gdouble)gimage->height;
gint new_layer_width = (gint)(0.5 + img_scale_w * (gdouble)GIMP_DRAWABLE(layer)->width);
gint new_layer_height = (gint)(0.5 + img_scale_h * (gdouble)GIMP_DRAWABLE(layer)->height);
return (new_layer_width != 0 && new_layer_height != 0);
}
/**
* layer_scale_by_factors:
* @layer: Layer to be transformed by explicit width and height factors.
* @w_factor: scale factor to apply to width and horizontal offset
* @h_factor: scale factor to apply to height and vertical offset
*
* Scales layer dimensions and offsets by uniform width and
* height factors.
*
* Use layer_scale_by_factors() in circumstances when the
* same width and height scaling factors are to be uniformly
* applied to a set of layers. In this context, the layer's
* dimensions and offsets from the sides of the containing
* image all change by these predetermined factors. By fiat,
* the fixed point of the transform is the upper left hand
* corner of the image. Returns gboolean FALSE if a requested
* scale factor is zero or if a scaling zero's out a layer
* dimension; returns TRUE otherwise.
*
* Use layer_scale() in circumstances where new layer width
* and height dimensions are predetermined instead.
*
* #Returns: TRUE, if the scaled layer has positive dimensions
* FALSE if the scaled layer has at least one zero dimension
*
* #Side effects: undo set created for layer.
* Old layer imagery scaled
* & painted to new layer tiles
*/
gboolean
layer_scale_by_factors(Layer *layer,
gdouble w_factor,
gdouble h_factor)
{
gint new_width, new_height, new_offset_x, new_offset_y;
if (w_factor == 0.0 || h_factor == 0.0)
{
g_message(_("layer_scale_by_factors: Error. Requested width or height scale equals zero."));
return FALSE;
}
new_offset_x = (gint)(0.5 + w_factor * (gdouble)GIMP_DRAWABLE(layer)->offset_x);
new_offset_y = (gint)(0.5 + h_factor * (gdouble)GIMP_DRAWABLE(layer)->offset_y);
new_width = (gint)(0.5 + w_factor * (gdouble)GIMP_DRAWABLE(layer)->width);
new_height = (gint)(0.5 + h_factor * (gdouble)GIMP_DRAWABLE(layer)->height);
if(new_width != 0 && new_height != 0)
{
layer_scale_lowlevel(layer, new_width, new_height, new_offset_x, new_offset_y);
return TRUE;
}
else
return FALSE;
}
/**
* layer_scale:
* @layer: The layer to be transformed by width & height scale factors
* @new_width: The width that layer will acquire
* @new_height: The height that the layer will acquire
* @local_origin: sets fixed point of the scaling transform. See below.
*
* Sets layer dimensions to new_width and
* new_height. Derives vertical and horizontal scaling
* transforms from new width and height. If local_origin is
* TRUE, the fixed point of the scaling transform coincides
* with the layer's center point. Otherwise, the fixed
* point is taken to be [-GIMP_DRAWABLE(layer)->offset_x,
* -GIMP_DRAWABLE(layer)->offset_y].
*
* Since this function derives scale factors from new and
* current layer dimensions, these factors will vary from
* layer to layer because of aliasing artifacts; factor
* variations among layers can be quite large where layer
* dimensions approach pixel dimensions. Use
* layer_scale_by_factors where constant scales are to
* be uniformly applied to a number of layers.
*
* Side effects: undo set created for layer.
* Old layer imagery scaled
* & painted to new layer tiles
*/
void
layer_scale (Layer *layer,
gint new_width,
gint new_height,
gboolean local_origin)
{
gint new_offset_x, new_offset_y;
if (new_width == 0 || new_height == 0)
{
g_message(_("layer_scale: Error. Requested width or height equals zero."));
return;
}
if (local_origin)
{
new_offset_x = GIMP_DRAWABLE(layer)->offset_x + ((GIMP_DRAWABLE(layer)->width - new_width)/2.0);
new_offset_y = GIMP_DRAWABLE(layer)->offset_y + ((GIMP_DRAWABLE(layer)->height - new_height)/2.0);
}
else
{
new_offset_x = (gint)(((gdouble) new_width * GIMP_DRAWABLE(layer)->offset_x/(gdouble) GIMP_DRAWABLE(layer)->width));
new_offset_y = (gint)(((gdouble) new_height * GIMP_DRAWABLE(layer)->offset_y/(gdouble) GIMP_DRAWABLE(layer)->height));
}
layer_scale_lowlevel(layer, new_width, new_height, new_offset_x, new_offset_y);
}
void
layer_resize (Layer *layer,
gint new_width,

View File

@ -82,6 +82,7 @@ void layer_unref (Layer *);
Layer * layer_new_from_tiles (GimpImage *, GimpImageType, TileManager *,
gchar *, gint, LayerModeEffects);
LayerMask * layer_add_mask (Layer *, LayerMask *);
gboolean layer_check_scaling (Layer *, gint, gint);
LayerMask * layer_create_mask (Layer *, AddMaskType);
Layer * layer_get_ID (gint);
void layer_delete (Layer *);
@ -90,7 +91,8 @@ void layer_apply_mask (Layer *, MaskApplyMode);
void layer_temporarily_translate (Layer *, gint, gint);
void layer_translate (Layer *, gint, gint);
void layer_add_alpha (Layer *);
void layer_scale (Layer *, gint, gint, gint);
gboolean layer_scale_by_factors (Layer *, gdouble, gdouble);
void layer_scale (Layer *, gint, gint, gboolean);
void layer_resize (Layer *, gint, gint, gint, gint);
void layer_resize_to_image (Layer *);
BoundSeg * layer_boundary (Layer *, gint *);

View File

@ -532,10 +532,20 @@ gimp_image_scale (GimpImage *gimage,
Layer *layer;
Layer *floating_layer;
GSList *list;
GSList *marklist = NULL;
GList *glist;
Guide *guide;
gint old_width, old_height;
gint layer_width, layer_height;
gint old_width, old_height;
gint old_offset_x, old_offset_y;
gint layer_width, layer_height;
gdouble img_scale_w = 1.0;
gdouble img_scale_h = 1.0;
if((new_width == 0) || (new_height == 0))
{
g_message(_("gimp_image_scale: Layer with zero width or height has been rejected."));
return;
}
gimp_add_busy_cursors ();
@ -552,11 +562,14 @@ gimp_image_scale (GimpImage *gimage,
undo_push_gimage_mod (gimage);
/* Set the new width and height */
old_width = gimage->width;
old_height = gimage->height;
old_width = gimage->width;
old_height = gimage->height;
gimage->width = new_width;
gimage->height = new_height;
img_scale_w = (gdouble)new_width/(gdouble)old_width;
img_scale_h = (gdouble)new_height/(gdouble)old_height;
/* Scale all channels */
list = gimage->channels;
while (list)
@ -574,14 +587,30 @@ gimp_image_scale (GimpImage *gimage,
list = gimage->layers;
while (list)
{
layer = (Layer *) list->data;
layer = (Layer *) list->data;
if(FALSE == layer_scale_by_factors(layer, img_scale_w, img_scale_h))
{
/* 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() */
/* [resize.c line 1295], which offers the user the chance to bail out.*/
layer_width = (new_width *
drawable_width (GIMP_DRAWABLE(layer))) / old_width;
layer_height = (new_height *
drawable_height (GIMP_DRAWABLE(layer))) / old_height;
layer_scale (layer, layer_width, layer_height, FALSE);
list = g_slist_next (list);
marklist = g_list_append(marklist, layer);
}
list = g_slist_next (list);
}
/* We defer removing layers lost to scaling until now */
/* so as not to mix the operations of iterating over and removal */
/* from gimage->layers. */
if(marklist != NULL)
{
while(marklist)
{
layer = marklist->data;
gimage_remove_layer(gimage, layer);
marklist = g_slist_remove(marklist, layer);
}
}
/* Scale any Guides */

View File

@ -65,19 +65,19 @@ struct _ResizePrivate
gint orig_x, orig_y;
};
static void resize_draw (Resize *);
static void unit_update (GtkWidget *, gpointer);
static gint resize_bound_off_x (Resize *, gint);
static gint resize_bound_off_y (Resize *, gint);
static void orig_labels_update (GtkWidget *, gpointer);
static void size_callback (GtkWidget *, gpointer);
static void ratio_callback (GtkWidget *, gpointer);
static void size_update (Resize *, gdouble, gdouble, gdouble, gdouble);
static void offset_update (GtkWidget *, gpointer);
static gint resize_events (GtkWidget *, GdkEvent *);
static void printsize_update (GtkWidget *, gpointer);
static void resolution_update (GtkWidget *, gpointer);
static void resize_draw (Resize *);
static void unit_update (GtkWidget *, gpointer);
static gint resize_bound_off_x (Resize *, gint);
static gint resize_bound_off_y (Resize *, gint);
static void orig_labels_update (GtkWidget *, gpointer);
static void size_callback (GtkWidget *, gpointer);
static void ratio_callback (GtkWidget *, gpointer);
static void size_update (Resize *, gdouble, gdouble, gdouble, gdouble);
static void offset_update (GtkWidget *, gpointer);
static gint resize_events (GtkWidget *, GdkEvent *);
static void printsize_update (GtkWidget *, gpointer);
static void resolution_update (GtkWidget *, gpointer);
static void resize_scale_warn_callback (GtkWidget *, gboolean, gpointer);
Resize *
resize_widget_new (ResizeType type,
@ -1191,3 +1191,164 @@ resize_events (GtkWidget *widget,
return FALSE;
}
/*** Resize sanity checks ***/
void resize_scale_implement (ImageResize *image_scale)
{
GImage *gimage = NULL;
gboolean rulers_flush = FALSE;
gboolean display_flush = FALSE; /* this is a bit ugly:
we hijack the flush variable
to check if an undo_group was
already started */
g_assert(image_scale != NULL);
gimage = image_scale->gimage;
g_assert(gimage != NULL);
if (image_scale->resize->resolution_x != gimage->xresolution ||
image_scale->resize->resolution_y != gimage->yresolution)
{
undo_push_group_start (gimage, IMAGE_SCALE_UNDO);
gimage_set_resolution (gimage,
image_scale->resize->resolution_x,
image_scale->resize->resolution_y);
rulers_flush = TRUE;
display_flush = TRUE;
}
if (image_scale->resize->unit != gimage->unit)
{
if (!display_flush)
undo_push_group_start (gimage, IMAGE_SCALE_UNDO);
gimage_set_unit (gimage, image_scale->resize->unit);
gdisplays_setup_scale (gimage);
gdisplays_resize_cursor_label (gimage);
rulers_flush = TRUE;
display_flush = TRUE;
}
if (image_scale->resize->width != gimage->width ||
image_scale->resize->height != gimage->height)
{
if (image_scale->resize->width > 0 &&
image_scale->resize->height > 0)
{
if (!display_flush)
undo_push_group_start (gimage, IMAGE_SCALE_UNDO);
gimage_scale (gimage,
image_scale->resize->width,
image_scale->resize->height);
display_flush = TRUE;
}
else
{
g_message (_("Scale Error: Both width and height must be "
"greater than zero."));
return;
}
}
if (rulers_flush)
{
gdisplays_setup_scale (gimage);
gdisplays_resize_cursor_label (gimage);
}
if (display_flush)
{
undo_push_group_end (gimage);
gdisplays_flush ();
}
}
static
void resize_scale_warn_callback (GtkWidget *widget,
gboolean do_scale,
gpointer client_data)
{
ImageResize *image_scale = NULL;
GImage *gimage = NULL;
g_assert(client_data != NULL);
image_scale = (ImageResize *) client_data;
gimage = image_scale->gimage;
g_assert(gimage != NULL);
if(do_scale == TRUE) /* User doesn't mind losing layers... */
{
resize_scale_implement(image_scale);
resize_widget_free (image_scale->resize);
g_free (image_scale);
}
else
gtk_widget_set_sensitive (image_scale->resize->resize_shell, TRUE);
}
gboolean
resize_check_layer_scaling (ImageResize *image_scale)
{
/* Inventory the layer list in gimage and return TRUE if, after
* scaling, they all retain positive x and y pixel dimensions.
* Otherwise, put up a modal boolean dialog box and ask the user if
* she wishes to proceed. Return FALSE in the dialog case; the dialog box
* callback will complete the job if the user really wants to
* proceed. <02/22/2000 gosgood@idt.net>
*/
gboolean success = FALSE;
GImage *gimage = NULL;
GSList *list = NULL;
Layer *layer = NULL;
GtkWidget *dialog = NULL;
gchar *str = NULL;
g_assert(image_scale != NULL);
if(NULL != (gimage = image_scale->gimage))
{
/* Step through layers; test scaled dimensions. */
success = TRUE;
list = gimage->layers;
while(list && success == TRUE)
{
layer = (Layer *)list->data;
success = layer_check_scaling (layer,
image_scale->resize->width,
image_scale->resize->height);
list = g_slist_next (list);
}
/* Warn user on failure */
if(success == FALSE)
{
gtk_widget_set_sensitive (image_scale->resize->resize_shell, FALSE);
str = g_strdup (_("The chosen image size will shrink\n"
"some layers completely away.\nIs this what you want?"));
dialog =
gimp_query_boolean_box (_("Layer Too Small"),
gimp_standard_help_func,
"dialogs/scale_layer_warn.html",
FALSE,
str,
_("OK"), _("Cancel"),
NULL, NULL,
resize_scale_warn_callback,
image_scale);
g_free (str);
gtk_widget_show (dialog);
}
}
return success;
}

View File

@ -19,6 +19,7 @@
#define __RESIZE_H__
#include "libgimp/gimpunit.h"
#include "gimage.h"
typedef enum
{
@ -59,9 +60,16 @@ struct _Resize
void * private_part;
};
typedef struct
{
Resize *resize;
GimpImage *gimage;
} ImageResize;
/* If resolution_x is zero, then don't show resolution modification
* parts of the dialog. If object is non-NULL, then attach the cancel
* callback to its destroy signal. */
Resize * resize_widget_new (ResizeType type,
ResizeTarget target,
GtkObject * object,
@ -76,4 +84,9 @@ Resize * resize_widget_new (ResizeType type,
gpointer user_data);
void resize_widget_free (Resize * resize);
/* Layer scaling sanity check and warning dialogs */
gboolean resize_check_layer_scaling (ImageResize *);
void resize_scale_implement (ImageResize *);
#endif /* __RESIZE_H__ */

View File

@ -532,10 +532,20 @@ gimp_image_scale (GimpImage *gimage,
Layer *layer;
Layer *floating_layer;
GSList *list;
GSList *marklist = NULL;
GList *glist;
Guide *guide;
gint old_width, old_height;
gint layer_width, layer_height;
gint old_width, old_height;
gint old_offset_x, old_offset_y;
gint layer_width, layer_height;
gdouble img_scale_w = 1.0;
gdouble img_scale_h = 1.0;
if((new_width == 0) || (new_height == 0))
{
g_message(_("gimp_image_scale: Layer with zero width or height has been rejected."));
return;
}
gimp_add_busy_cursors ();
@ -552,11 +562,14 @@ gimp_image_scale (GimpImage *gimage,
undo_push_gimage_mod (gimage);
/* Set the new width and height */
old_width = gimage->width;
old_height = gimage->height;
old_width = gimage->width;
old_height = gimage->height;
gimage->width = new_width;
gimage->height = new_height;
img_scale_w = (gdouble)new_width/(gdouble)old_width;
img_scale_h = (gdouble)new_height/(gdouble)old_height;
/* Scale all channels */
list = gimage->channels;
while (list)
@ -574,14 +587,30 @@ gimp_image_scale (GimpImage *gimage,
list = gimage->layers;
while (list)
{
layer = (Layer *) list->data;
layer = (Layer *) list->data;
if(FALSE == layer_scale_by_factors(layer, img_scale_w, img_scale_h))
{
/* 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() */
/* [resize.c line 1295], which offers the user the chance to bail out.*/
layer_width = (new_width *
drawable_width (GIMP_DRAWABLE(layer))) / old_width;
layer_height = (new_height *
drawable_height (GIMP_DRAWABLE(layer))) / old_height;
layer_scale (layer, layer_width, layer_height, FALSE);
list = g_slist_next (list);
marklist = g_list_append(marklist, layer);
}
list = g_slist_next (list);
}
/* We defer removing layers lost to scaling until now */
/* so as not to mix the operations of iterating over and removal */
/* from gimage->layers. */
if(marklist != NULL)
{
while(marklist)
{
layer = marklist->data;
gimage_remove_layer(gimage, layer);
marklist = g_slist_remove(marklist, layer);
}
}
/* Scale any Guides */

View File

@ -346,7 +346,7 @@ layer_copy (Layer *layer,
new_type, layer_name, layer->opacity, layer->mode);
if (!new_layer)
{
g_message ("layer_copy: could not allocate new layer");
g_message (_("layer_copy: could not allocate new layer"));
goto cleanup;
}
@ -421,7 +421,7 @@ layer_new_from_tiles (GimpImage *gimage,
if (!new_layer)
{
g_message ("layer_new_from_tiles: could not allocate new layer");
g_message (_("layer_new_from_tiles: could not allocate new layer"));
return NULL;
}
@ -723,18 +723,16 @@ layer_add_alpha (Layer *layer)
"restructure");
}
void
layer_scale (Layer *layer,
gint new_width,
gint new_height,
gint local_origin)
static void
layer_scale_lowlevel(Layer *layer,
gint new_width,
gint new_height,
gint new_offset_x,
gint new_offset_y)
{
PixelRegion srcPR, destPR;
TileManager *new_tiles;
if (new_width == 0 || new_height == 0)
return;
/* Update the old layer position */
drawable_update (GIMP_DRAWABLE(layer),
0, 0,
@ -761,29 +759,12 @@ layer_scale (Layer *layer,
undo_push_layer_mod (GIMP_DRAWABLE(layer)->gimage, layer);
/* Configure the new layer */
if (local_origin)
{
int cx, cy;
cx = GIMP_DRAWABLE(layer)->offset_x + GIMP_DRAWABLE(layer)->width / 2;
cy = GIMP_DRAWABLE(layer)->offset_y + GIMP_DRAWABLE(layer)->height / 2;
GIMP_DRAWABLE(layer)->offset_x = cx - (new_width / 2);
GIMP_DRAWABLE(layer)->offset_y = cy - (new_height / 2);
}
else
{
double xrat, yrat;
xrat = (double) new_width / (double) GIMP_DRAWABLE(layer)->width;
yrat = (double) new_height / (double) GIMP_DRAWABLE(layer)->height;
GIMP_DRAWABLE(layer)->offset_x = (int) (xrat * GIMP_DRAWABLE(layer)->offset_x);
GIMP_DRAWABLE(layer)->offset_y = (int) (yrat * GIMP_DRAWABLE(layer)->offset_y);
}
GIMP_DRAWABLE(layer)->tiles = new_tiles;
GIMP_DRAWABLE(layer)->width = new_width;
GIMP_DRAWABLE(layer)->height = new_height;
GIMP_DRAWABLE(layer)->offset_x = new_offset_x;
GIMP_DRAWABLE(layer)->offset_y = new_offset_y;
GIMP_DRAWABLE(layer)->tiles = new_tiles;
GIMP_DRAWABLE(layer)->width = new_width;
GIMP_DRAWABLE(layer)->height = new_height;
/* If there is a layer mask, make sure it gets scaled also */
if (layer->mask)
@ -794,11 +775,146 @@ layer_scale (Layer *layer,
}
/* Update the new layer position */
drawable_update (GIMP_DRAWABLE(layer),
0, 0,
GIMP_DRAWABLE(layer)->width, GIMP_DRAWABLE(layer)->height);
}
/**
* layer_check_scaling:
* @layer: Layer to check
* @new_width: proposed width of layer, in pixels
* @new_height: proposed height of layer, in pixels
* Scales layer dimensions, then snaps them to pixel centers
* Returns FALSE if any dimension reduces to zero as a result
* of this; otherwise, returns TRUE.
*/
gboolean layer_check_scaling (Layer *layer,
gint new_width,
gint new_height)
{
GImage *gimage = GIMP_DRAWABLE(layer)->gimage;
gdouble img_scale_w = (gdouble)new_width/(gdouble)gimage->width;
gdouble img_scale_h = (gdouble)new_height/(gdouble)gimage->height;
gint new_layer_width = (gint)(0.5 + img_scale_w * (gdouble)GIMP_DRAWABLE(layer)->width);
gint new_layer_height = (gint)(0.5 + img_scale_h * (gdouble)GIMP_DRAWABLE(layer)->height);
return (new_layer_width != 0 && new_layer_height != 0);
}
/**
* layer_scale_by_factors:
* @layer: Layer to be transformed by explicit width and height factors.
* @w_factor: scale factor to apply to width and horizontal offset
* @h_factor: scale factor to apply to height and vertical offset
*
* Scales layer dimensions and offsets by uniform width and
* height factors.
*
* Use layer_scale_by_factors() in circumstances when the
* same width and height scaling factors are to be uniformly
* applied to a set of layers. In this context, the layer's
* dimensions and offsets from the sides of the containing
* image all change by these predetermined factors. By fiat,
* the fixed point of the transform is the upper left hand
* corner of the image. Returns gboolean FALSE if a requested
* scale factor is zero or if a scaling zero's out a layer
* dimension; returns TRUE otherwise.
*
* Use layer_scale() in circumstances where new layer width
* and height dimensions are predetermined instead.
*
* #Returns: TRUE, if the scaled layer has positive dimensions
* FALSE if the scaled layer has at least one zero dimension
*
* #Side effects: undo set created for layer.
* Old layer imagery scaled
* & painted to new layer tiles
*/
gboolean
layer_scale_by_factors(Layer *layer,
gdouble w_factor,
gdouble h_factor)
{
gint new_width, new_height, new_offset_x, new_offset_y;
if (w_factor == 0.0 || h_factor == 0.0)
{
g_message(_("layer_scale_by_factors: Error. Requested width or height scale equals zero."));
return FALSE;
}
new_offset_x = (gint)(0.5 + w_factor * (gdouble)GIMP_DRAWABLE(layer)->offset_x);
new_offset_y = (gint)(0.5 + h_factor * (gdouble)GIMP_DRAWABLE(layer)->offset_y);
new_width = (gint)(0.5 + w_factor * (gdouble)GIMP_DRAWABLE(layer)->width);
new_height = (gint)(0.5 + h_factor * (gdouble)GIMP_DRAWABLE(layer)->height);
if(new_width != 0 && new_height != 0)
{
layer_scale_lowlevel(layer, new_width, new_height, new_offset_x, new_offset_y);
return TRUE;
}
else
return FALSE;
}
/**
* layer_scale:
* @layer: The layer to be transformed by width & height scale factors
* @new_width: The width that layer will acquire
* @new_height: The height that the layer will acquire
* @local_origin: sets fixed point of the scaling transform. See below.
*
* Sets layer dimensions to new_width and
* new_height. Derives vertical and horizontal scaling
* transforms from new width and height. If local_origin is
* TRUE, the fixed point of the scaling transform coincides
* with the layer's center point. Otherwise, the fixed
* point is taken to be [-GIMP_DRAWABLE(layer)->offset_x,
* -GIMP_DRAWABLE(layer)->offset_y].
*
* Since this function derives scale factors from new and
* current layer dimensions, these factors will vary from
* layer to layer because of aliasing artifacts; factor
* variations among layers can be quite large where layer
* dimensions approach pixel dimensions. Use
* layer_scale_by_factors where constant scales are to
* be uniformly applied to a number of layers.
*
* Side effects: undo set created for layer.
* Old layer imagery scaled
* & painted to new layer tiles
*/
void
layer_scale (Layer *layer,
gint new_width,
gint new_height,
gboolean local_origin)
{
gint new_offset_x, new_offset_y;
if (new_width == 0 || new_height == 0)
{
g_message(_("layer_scale: Error. Requested width or height equals zero."));
return;
}
if (local_origin)
{
new_offset_x = GIMP_DRAWABLE(layer)->offset_x + ((GIMP_DRAWABLE(layer)->width - new_width)/2.0);
new_offset_y = GIMP_DRAWABLE(layer)->offset_y + ((GIMP_DRAWABLE(layer)->height - new_height)/2.0);
}
else
{
new_offset_x = (gint)(((gdouble) new_width * GIMP_DRAWABLE(layer)->offset_x/(gdouble) GIMP_DRAWABLE(layer)->width));
new_offset_y = (gint)(((gdouble) new_height * GIMP_DRAWABLE(layer)->offset_y/(gdouble) GIMP_DRAWABLE(layer)->height));
}
layer_scale_lowlevel(layer, new_width, new_height, new_offset_x, new_offset_y);
}
void
layer_resize (Layer *layer,
gint new_width,

View File

@ -82,6 +82,7 @@ void layer_unref (Layer *);
Layer * layer_new_from_tiles (GimpImage *, GimpImageType, TileManager *,
gchar *, gint, LayerModeEffects);
LayerMask * layer_add_mask (Layer *, LayerMask *);
gboolean layer_check_scaling (Layer *, gint, gint);
LayerMask * layer_create_mask (Layer *, AddMaskType);
Layer * layer_get_ID (gint);
void layer_delete (Layer *);
@ -90,7 +91,8 @@ void layer_apply_mask (Layer *, MaskApplyMode);
void layer_temporarily_translate (Layer *, gint, gint);
void layer_translate (Layer *, gint, gint);
void layer_add_alpha (Layer *);
void layer_scale (Layer *, gint, gint, gint);
gboolean layer_scale_by_factors (Layer *, gdouble, gdouble);
void layer_scale (Layer *, gint, gint, gboolean);
void layer_resize (Layer *, gint, gint, gint, gint);
void layer_resize_to_image (Layer *);
BoundSeg * layer_boundary (Layer *, gint *);

View File

@ -65,27 +65,21 @@
gdisp = gdisplay_active (); \
if (!gdisp) return
typedef struct
{
Resize *resize;
GimpImage *gimage;
} ImageResize;
/* external functions */
extern void layers_dialog_layer_merge_query (GImage *, gboolean);
/* local functions */
static void image_resize_callback (GtkWidget *, gpointer);
static void image_scale_callback (GtkWidget *, gpointer);
static void image_cancel_callback (GtkWidget *, gpointer);
static void gimage_mask_feather_callback (GtkWidget *, gdouble, GimpUnit,
gpointer);
static void gimage_mask_border_callback (GtkWidget *, gdouble, GimpUnit,
gpointer);
static void gimage_mask_grow_callback (GtkWidget *, gdouble, GimpUnit,
gpointer);
static void gimage_mask_shrink_callback (GtkWidget *, gdouble, GimpUnit,
gpointer);
static void image_resize_callback (GtkWidget *, gpointer);
static void image_scale_callback (GtkWidget *, gpointer);
static void image_cancel_callback (GtkWidget *, gpointer);
static void gimage_mask_feather_callback (GtkWidget *, gdouble, GimpUnit,
gpointer);
static void gimage_mask_border_callback (GtkWidget *, gdouble, GimpUnit,
gpointer);
static void gimage_mask_grow_callback (GtkWidget *, gdouble, GimpUnit,
gpointer);
static void gimage_mask_shrink_callback (GtkWidget *, gdouble, GimpUnit,
gpointer);
/* local variables */
static gdouble selection_feather_radius = 5.0;
@ -1318,94 +1312,29 @@ static void
image_scale_callback (GtkWidget *widget,
gpointer client_data)
{
ImageResize *image_scale;
GImage *gimage;
gboolean rulers_flush = FALSE;
gboolean display_flush = FALSE; /* this is a bit ugly:
we hijack the flush variable
to check if an undo_group was
already started */
ImageResize *image_scale = NULL;
image_scale = (ImageResize *) client_data;
if ((gimage = image_scale->gimage) != NULL)
g_assert((image_scale = (ImageResize *) client_data) != NULL);
g_assert(image_scale->gimage != NULL);
if(TRUE == resize_check_layer_scaling(image_scale))
{
if (image_scale->resize->resolution_x != gimage->xresolution ||
image_scale->resize->resolution_y != gimage->yresolution)
{
undo_push_group_start (gimage, IMAGE_SCALE_UNDO);
gimage_set_resolution (gimage,
image_scale->resize->resolution_x,
image_scale->resize->resolution_y);
rulers_flush = TRUE;
display_flush = TRUE;
}
if (image_scale->resize->unit != gimage->unit)
{
if (!display_flush)
undo_push_group_start (gimage, IMAGE_SCALE_UNDO);
gimage_set_unit (gimage, image_scale->resize->unit);
gdisplays_setup_scale (gimage);
gdisplays_resize_cursor_label (gimage);
rulers_flush = TRUE;
display_flush = TRUE;
}
if (image_scale->resize->width != gimage->width ||
image_scale->resize->height != gimage->height)
{
if (image_scale->resize->width > 0 &&
image_scale->resize->height > 0)
{
if (!display_flush)
undo_push_group_start (gimage, IMAGE_SCALE_UNDO);
gimage_scale (gimage,
image_scale->resize->width,
image_scale->resize->height);
display_flush = TRUE;
}
else
{
g_message (_("Scale Error: Both width and height must be "
"greater than zero."));
return;
}
}
if (rulers_flush)
{
gdisplays_setup_scale (gimage);
gdisplays_resize_cursor_label (gimage);
}
if (display_flush)
{
undo_push_group_end (gimage);
gdisplays_flush ();
}
resize_scale_implement(image_scale);
resize_widget_free (image_scale->resize);
g_free (image_scale);
}
resize_widget_free (image_scale->resize);
g_free (image_scale);
}
static void
image_cancel_callback (GtkWidget *widget,
gpointer client_data)
{
ImageResize *image_resize;
ImageResize *image_scale;
image_resize = (ImageResize *) client_data;
image_scale = (ImageResize *) client_data;
resize_widget_free (image_resize->resize);
g_free (image_resize);
resize_widget_free (image_scale->resize);
g_free (image_scale);
}
static void

View File

@ -65,27 +65,21 @@
gdisp = gdisplay_active (); \
if (!gdisp) return
typedef struct
{
Resize *resize;
GimpImage *gimage;
} ImageResize;
/* external functions */
extern void layers_dialog_layer_merge_query (GImage *, gboolean);
/* local functions */
static void image_resize_callback (GtkWidget *, gpointer);
static void image_scale_callback (GtkWidget *, gpointer);
static void image_cancel_callback (GtkWidget *, gpointer);
static void gimage_mask_feather_callback (GtkWidget *, gdouble, GimpUnit,
gpointer);
static void gimage_mask_border_callback (GtkWidget *, gdouble, GimpUnit,
gpointer);
static void gimage_mask_grow_callback (GtkWidget *, gdouble, GimpUnit,
gpointer);
static void gimage_mask_shrink_callback (GtkWidget *, gdouble, GimpUnit,
gpointer);
static void image_resize_callback (GtkWidget *, gpointer);
static void image_scale_callback (GtkWidget *, gpointer);
static void image_cancel_callback (GtkWidget *, gpointer);
static void gimage_mask_feather_callback (GtkWidget *, gdouble, GimpUnit,
gpointer);
static void gimage_mask_border_callback (GtkWidget *, gdouble, GimpUnit,
gpointer);
static void gimage_mask_grow_callback (GtkWidget *, gdouble, GimpUnit,
gpointer);
static void gimage_mask_shrink_callback (GtkWidget *, gdouble, GimpUnit,
gpointer);
/* local variables */
static gdouble selection_feather_radius = 5.0;
@ -1318,94 +1312,29 @@ static void
image_scale_callback (GtkWidget *widget,
gpointer client_data)
{
ImageResize *image_scale;
GImage *gimage;
gboolean rulers_flush = FALSE;
gboolean display_flush = FALSE; /* this is a bit ugly:
we hijack the flush variable
to check if an undo_group was
already started */
ImageResize *image_scale = NULL;
image_scale = (ImageResize *) client_data;
if ((gimage = image_scale->gimage) != NULL)
g_assert((image_scale = (ImageResize *) client_data) != NULL);
g_assert(image_scale->gimage != NULL);
if(TRUE == resize_check_layer_scaling(image_scale))
{
if (image_scale->resize->resolution_x != gimage->xresolution ||
image_scale->resize->resolution_y != gimage->yresolution)
{
undo_push_group_start (gimage, IMAGE_SCALE_UNDO);
gimage_set_resolution (gimage,
image_scale->resize->resolution_x,
image_scale->resize->resolution_y);
rulers_flush = TRUE;
display_flush = TRUE;
}
if (image_scale->resize->unit != gimage->unit)
{
if (!display_flush)
undo_push_group_start (gimage, IMAGE_SCALE_UNDO);
gimage_set_unit (gimage, image_scale->resize->unit);
gdisplays_setup_scale (gimage);
gdisplays_resize_cursor_label (gimage);
rulers_flush = TRUE;
display_flush = TRUE;
}
if (image_scale->resize->width != gimage->width ||
image_scale->resize->height != gimage->height)
{
if (image_scale->resize->width > 0 &&
image_scale->resize->height > 0)
{
if (!display_flush)
undo_push_group_start (gimage, IMAGE_SCALE_UNDO);
gimage_scale (gimage,
image_scale->resize->width,
image_scale->resize->height);
display_flush = TRUE;
}
else
{
g_message (_("Scale Error: Both width and height must be "
"greater than zero."));
return;
}
}
if (rulers_flush)
{
gdisplays_setup_scale (gimage);
gdisplays_resize_cursor_label (gimage);
}
if (display_flush)
{
undo_push_group_end (gimage);
gdisplays_flush ();
}
resize_scale_implement(image_scale);
resize_widget_free (image_scale->resize);
g_free (image_scale);
}
resize_widget_free (image_scale->resize);
g_free (image_scale);
}
static void
image_cancel_callback (GtkWidget *widget,
gpointer client_data)
{
ImageResize *image_resize;
ImageResize *image_scale;
image_resize = (ImageResize *) client_data;
image_scale = (ImageResize *) client_data;
resize_widget_free (image_resize->resize);
g_free (image_resize);
resize_widget_free (image_scale->resize);
g_free (image_scale);
}
static void

View File

@ -65,19 +65,19 @@ struct _ResizePrivate
gint orig_x, orig_y;
};
static void resize_draw (Resize *);
static void unit_update (GtkWidget *, gpointer);
static gint resize_bound_off_x (Resize *, gint);
static gint resize_bound_off_y (Resize *, gint);
static void orig_labels_update (GtkWidget *, gpointer);
static void size_callback (GtkWidget *, gpointer);
static void ratio_callback (GtkWidget *, gpointer);
static void size_update (Resize *, gdouble, gdouble, gdouble, gdouble);
static void offset_update (GtkWidget *, gpointer);
static gint resize_events (GtkWidget *, GdkEvent *);
static void printsize_update (GtkWidget *, gpointer);
static void resolution_update (GtkWidget *, gpointer);
static void resize_draw (Resize *);
static void unit_update (GtkWidget *, gpointer);
static gint resize_bound_off_x (Resize *, gint);
static gint resize_bound_off_y (Resize *, gint);
static void orig_labels_update (GtkWidget *, gpointer);
static void size_callback (GtkWidget *, gpointer);
static void ratio_callback (GtkWidget *, gpointer);
static void size_update (Resize *, gdouble, gdouble, gdouble, gdouble);
static void offset_update (GtkWidget *, gpointer);
static gint resize_events (GtkWidget *, GdkEvent *);
static void printsize_update (GtkWidget *, gpointer);
static void resolution_update (GtkWidget *, gpointer);
static void resize_scale_warn_callback (GtkWidget *, gboolean, gpointer);
Resize *
resize_widget_new (ResizeType type,
@ -1191,3 +1191,164 @@ resize_events (GtkWidget *widget,
return FALSE;
}
/*** Resize sanity checks ***/
void resize_scale_implement (ImageResize *image_scale)
{
GImage *gimage = NULL;
gboolean rulers_flush = FALSE;
gboolean display_flush = FALSE; /* this is a bit ugly:
we hijack the flush variable
to check if an undo_group was
already started */
g_assert(image_scale != NULL);
gimage = image_scale->gimage;
g_assert(gimage != NULL);
if (image_scale->resize->resolution_x != gimage->xresolution ||
image_scale->resize->resolution_y != gimage->yresolution)
{
undo_push_group_start (gimage, IMAGE_SCALE_UNDO);
gimage_set_resolution (gimage,
image_scale->resize->resolution_x,
image_scale->resize->resolution_y);
rulers_flush = TRUE;
display_flush = TRUE;
}
if (image_scale->resize->unit != gimage->unit)
{
if (!display_flush)
undo_push_group_start (gimage, IMAGE_SCALE_UNDO);
gimage_set_unit (gimage, image_scale->resize->unit);
gdisplays_setup_scale (gimage);
gdisplays_resize_cursor_label (gimage);
rulers_flush = TRUE;
display_flush = TRUE;
}
if (image_scale->resize->width != gimage->width ||
image_scale->resize->height != gimage->height)
{
if (image_scale->resize->width > 0 &&
image_scale->resize->height > 0)
{
if (!display_flush)
undo_push_group_start (gimage, IMAGE_SCALE_UNDO);
gimage_scale (gimage,
image_scale->resize->width,
image_scale->resize->height);
display_flush = TRUE;
}
else
{
g_message (_("Scale Error: Both width and height must be "
"greater than zero."));
return;
}
}
if (rulers_flush)
{
gdisplays_setup_scale (gimage);
gdisplays_resize_cursor_label (gimage);
}
if (display_flush)
{
undo_push_group_end (gimage);
gdisplays_flush ();
}
}
static
void resize_scale_warn_callback (GtkWidget *widget,
gboolean do_scale,
gpointer client_data)
{
ImageResize *image_scale = NULL;
GImage *gimage = NULL;
g_assert(client_data != NULL);
image_scale = (ImageResize *) client_data;
gimage = image_scale->gimage;
g_assert(gimage != NULL);
if(do_scale == TRUE) /* User doesn't mind losing layers... */
{
resize_scale_implement(image_scale);
resize_widget_free (image_scale->resize);
g_free (image_scale);
}
else
gtk_widget_set_sensitive (image_scale->resize->resize_shell, TRUE);
}
gboolean
resize_check_layer_scaling (ImageResize *image_scale)
{
/* Inventory the layer list in gimage and return TRUE if, after
* scaling, they all retain positive x and y pixel dimensions.
* Otherwise, put up a modal boolean dialog box and ask the user if
* she wishes to proceed. Return FALSE in the dialog case; the dialog box
* callback will complete the job if the user really wants to
* proceed. <02/22/2000 gosgood@idt.net>
*/
gboolean success = FALSE;
GImage *gimage = NULL;
GSList *list = NULL;
Layer *layer = NULL;
GtkWidget *dialog = NULL;
gchar *str = NULL;
g_assert(image_scale != NULL);
if(NULL != (gimage = image_scale->gimage))
{
/* Step through layers; test scaled dimensions. */
success = TRUE;
list = gimage->layers;
while(list && success == TRUE)
{
layer = (Layer *)list->data;
success = layer_check_scaling (layer,
image_scale->resize->width,
image_scale->resize->height);
list = g_slist_next (list);
}
/* Warn user on failure */
if(success == FALSE)
{
gtk_widget_set_sensitive (image_scale->resize->resize_shell, FALSE);
str = g_strdup (_("The chosen image size will shrink\n"
"some layers completely away.\nIs this what you want?"));
dialog =
gimp_query_boolean_box (_("Layer Too Small"),
gimp_standard_help_func,
"dialogs/scale_layer_warn.html",
FALSE,
str,
_("OK"), _("Cancel"),
NULL, NULL,
resize_scale_warn_callback,
image_scale);
g_free (str);
gtk_widget_show (dialog);
}
}
return success;
}

View File

@ -19,6 +19,7 @@
#define __RESIZE_H__
#include "libgimp/gimpunit.h"
#include "gimage.h"
typedef enum
{
@ -59,9 +60,16 @@ struct _Resize
void * private_part;
};
typedef struct
{
Resize *resize;
GimpImage *gimage;
} ImageResize;
/* If resolution_x is zero, then don't show resolution modification
* parts of the dialog. If object is non-NULL, then attach the cancel
* callback to its destroy signal. */
Resize * resize_widget_new (ResizeType type,
ResizeTarget target,
GtkObject * object,
@ -76,4 +84,9 @@ Resize * resize_widget_new (ResizeType type,
gpointer user_data);
void resize_widget_free (Resize * resize);
/* Layer scaling sanity check and warning dialogs */
gboolean resize_check_layer_scaling (ImageResize *);
void resize_scale_implement (ImageResize *);
#endif /* __RESIZE_H__ */

View File

@ -346,7 +346,7 @@ layer_copy (Layer *layer,
new_type, layer_name, layer->opacity, layer->mode);
if (!new_layer)
{
g_message ("layer_copy: could not allocate new layer");
g_message (_("layer_copy: could not allocate new layer"));
goto cleanup;
}
@ -421,7 +421,7 @@ layer_new_from_tiles (GimpImage *gimage,
if (!new_layer)
{
g_message ("layer_new_from_tiles: could not allocate new layer");
g_message (_("layer_new_from_tiles: could not allocate new layer"));
return NULL;
}
@ -723,18 +723,16 @@ layer_add_alpha (Layer *layer)
"restructure");
}
void
layer_scale (Layer *layer,
gint new_width,
gint new_height,
gint local_origin)
static void
layer_scale_lowlevel(Layer *layer,
gint new_width,
gint new_height,
gint new_offset_x,
gint new_offset_y)
{
PixelRegion srcPR, destPR;
TileManager *new_tiles;
if (new_width == 0 || new_height == 0)
return;
/* Update the old layer position */
drawable_update (GIMP_DRAWABLE(layer),
0, 0,
@ -761,29 +759,12 @@ layer_scale (Layer *layer,
undo_push_layer_mod (GIMP_DRAWABLE(layer)->gimage, layer);
/* Configure the new layer */
if (local_origin)
{
int cx, cy;
cx = GIMP_DRAWABLE(layer)->offset_x + GIMP_DRAWABLE(layer)->width / 2;
cy = GIMP_DRAWABLE(layer)->offset_y + GIMP_DRAWABLE(layer)->height / 2;
GIMP_DRAWABLE(layer)->offset_x = cx - (new_width / 2);
GIMP_DRAWABLE(layer)->offset_y = cy - (new_height / 2);
}
else
{
double xrat, yrat;
xrat = (double) new_width / (double) GIMP_DRAWABLE(layer)->width;
yrat = (double) new_height / (double) GIMP_DRAWABLE(layer)->height;
GIMP_DRAWABLE(layer)->offset_x = (int) (xrat * GIMP_DRAWABLE(layer)->offset_x);
GIMP_DRAWABLE(layer)->offset_y = (int) (yrat * GIMP_DRAWABLE(layer)->offset_y);
}
GIMP_DRAWABLE(layer)->tiles = new_tiles;
GIMP_DRAWABLE(layer)->width = new_width;
GIMP_DRAWABLE(layer)->height = new_height;
GIMP_DRAWABLE(layer)->offset_x = new_offset_x;
GIMP_DRAWABLE(layer)->offset_y = new_offset_y;
GIMP_DRAWABLE(layer)->tiles = new_tiles;
GIMP_DRAWABLE(layer)->width = new_width;
GIMP_DRAWABLE(layer)->height = new_height;
/* If there is a layer mask, make sure it gets scaled also */
if (layer->mask)
@ -794,11 +775,146 @@ layer_scale (Layer *layer,
}
/* Update the new layer position */
drawable_update (GIMP_DRAWABLE(layer),
0, 0,
GIMP_DRAWABLE(layer)->width, GIMP_DRAWABLE(layer)->height);
}
/**
* layer_check_scaling:
* @layer: Layer to check
* @new_width: proposed width of layer, in pixels
* @new_height: proposed height of layer, in pixels
* Scales layer dimensions, then snaps them to pixel centers
* Returns FALSE if any dimension reduces to zero as a result
* of this; otherwise, returns TRUE.
*/
gboolean layer_check_scaling (Layer *layer,
gint new_width,
gint new_height)
{
GImage *gimage = GIMP_DRAWABLE(layer)->gimage;
gdouble img_scale_w = (gdouble)new_width/(gdouble)gimage->width;
gdouble img_scale_h = (gdouble)new_height/(gdouble)gimage->height;
gint new_layer_width = (gint)(0.5 + img_scale_w * (gdouble)GIMP_DRAWABLE(layer)->width);
gint new_layer_height = (gint)(0.5 + img_scale_h * (gdouble)GIMP_DRAWABLE(layer)->height);
return (new_layer_width != 0 && new_layer_height != 0);
}
/**
* layer_scale_by_factors:
* @layer: Layer to be transformed by explicit width and height factors.
* @w_factor: scale factor to apply to width and horizontal offset
* @h_factor: scale factor to apply to height and vertical offset
*
* Scales layer dimensions and offsets by uniform width and
* height factors.
*
* Use layer_scale_by_factors() in circumstances when the
* same width and height scaling factors are to be uniformly
* applied to a set of layers. In this context, the layer's
* dimensions and offsets from the sides of the containing
* image all change by these predetermined factors. By fiat,
* the fixed point of the transform is the upper left hand
* corner of the image. Returns gboolean FALSE if a requested
* scale factor is zero or if a scaling zero's out a layer
* dimension; returns TRUE otherwise.
*
* Use layer_scale() in circumstances where new layer width
* and height dimensions are predetermined instead.
*
* #Returns: TRUE, if the scaled layer has positive dimensions
* FALSE if the scaled layer has at least one zero dimension
*
* #Side effects: undo set created for layer.
* Old layer imagery scaled
* & painted to new layer tiles
*/
gboolean
layer_scale_by_factors(Layer *layer,
gdouble w_factor,
gdouble h_factor)
{
gint new_width, new_height, new_offset_x, new_offset_y;
if (w_factor == 0.0 || h_factor == 0.0)
{
g_message(_("layer_scale_by_factors: Error. Requested width or height scale equals zero."));
return FALSE;
}
new_offset_x = (gint)(0.5 + w_factor * (gdouble)GIMP_DRAWABLE(layer)->offset_x);
new_offset_y = (gint)(0.5 + h_factor * (gdouble)GIMP_DRAWABLE(layer)->offset_y);
new_width = (gint)(0.5 + w_factor * (gdouble)GIMP_DRAWABLE(layer)->width);
new_height = (gint)(0.5 + h_factor * (gdouble)GIMP_DRAWABLE(layer)->height);
if(new_width != 0 && new_height != 0)
{
layer_scale_lowlevel(layer, new_width, new_height, new_offset_x, new_offset_y);
return TRUE;
}
else
return FALSE;
}
/**
* layer_scale:
* @layer: The layer to be transformed by width & height scale factors
* @new_width: The width that layer will acquire
* @new_height: The height that the layer will acquire
* @local_origin: sets fixed point of the scaling transform. See below.
*
* Sets layer dimensions to new_width and
* new_height. Derives vertical and horizontal scaling
* transforms from new width and height. If local_origin is
* TRUE, the fixed point of the scaling transform coincides
* with the layer's center point. Otherwise, the fixed
* point is taken to be [-GIMP_DRAWABLE(layer)->offset_x,
* -GIMP_DRAWABLE(layer)->offset_y].
*
* Since this function derives scale factors from new and
* current layer dimensions, these factors will vary from
* layer to layer because of aliasing artifacts; factor
* variations among layers can be quite large where layer
* dimensions approach pixel dimensions. Use
* layer_scale_by_factors where constant scales are to
* be uniformly applied to a number of layers.
*
* Side effects: undo set created for layer.
* Old layer imagery scaled
* & painted to new layer tiles
*/
void
layer_scale (Layer *layer,
gint new_width,
gint new_height,
gboolean local_origin)
{
gint new_offset_x, new_offset_y;
if (new_width == 0 || new_height == 0)
{
g_message(_("layer_scale: Error. Requested width or height equals zero."));
return;
}
if (local_origin)
{
new_offset_x = GIMP_DRAWABLE(layer)->offset_x + ((GIMP_DRAWABLE(layer)->width - new_width)/2.0);
new_offset_y = GIMP_DRAWABLE(layer)->offset_y + ((GIMP_DRAWABLE(layer)->height - new_height)/2.0);
}
else
{
new_offset_x = (gint)(((gdouble) new_width * GIMP_DRAWABLE(layer)->offset_x/(gdouble) GIMP_DRAWABLE(layer)->width));
new_offset_y = (gint)(((gdouble) new_height * GIMP_DRAWABLE(layer)->offset_y/(gdouble) GIMP_DRAWABLE(layer)->height));
}
layer_scale_lowlevel(layer, new_width, new_height, new_offset_x, new_offset_y);
}
void
layer_resize (Layer *layer,
gint new_width,

View File

@ -82,6 +82,7 @@ void layer_unref (Layer *);
Layer * layer_new_from_tiles (GimpImage *, GimpImageType, TileManager *,
gchar *, gint, LayerModeEffects);
LayerMask * layer_add_mask (Layer *, LayerMask *);
gboolean layer_check_scaling (Layer *, gint, gint);
LayerMask * layer_create_mask (Layer *, AddMaskType);
Layer * layer_get_ID (gint);
void layer_delete (Layer *);
@ -90,7 +91,8 @@ void layer_apply_mask (Layer *, MaskApplyMode);
void layer_temporarily_translate (Layer *, gint, gint);
void layer_translate (Layer *, gint, gint);
void layer_add_alpha (Layer *);
void layer_scale (Layer *, gint, gint, gint);
gboolean layer_scale_by_factors (Layer *, gdouble, gdouble);
void layer_scale (Layer *, gint, gint, gboolean);
void layer_resize (Layer *, gint, gint, gint, gint);
void layer_resize_to_image (Layer *);
BoundSeg * layer_boundary (Layer *, gint *);

View File

@ -65,19 +65,19 @@ struct _ResizePrivate
gint orig_x, orig_y;
};
static void resize_draw (Resize *);
static void unit_update (GtkWidget *, gpointer);
static gint resize_bound_off_x (Resize *, gint);
static gint resize_bound_off_y (Resize *, gint);
static void orig_labels_update (GtkWidget *, gpointer);
static void size_callback (GtkWidget *, gpointer);
static void ratio_callback (GtkWidget *, gpointer);
static void size_update (Resize *, gdouble, gdouble, gdouble, gdouble);
static void offset_update (GtkWidget *, gpointer);
static gint resize_events (GtkWidget *, GdkEvent *);
static void printsize_update (GtkWidget *, gpointer);
static void resolution_update (GtkWidget *, gpointer);
static void resize_draw (Resize *);
static void unit_update (GtkWidget *, gpointer);
static gint resize_bound_off_x (Resize *, gint);
static gint resize_bound_off_y (Resize *, gint);
static void orig_labels_update (GtkWidget *, gpointer);
static void size_callback (GtkWidget *, gpointer);
static void ratio_callback (GtkWidget *, gpointer);
static void size_update (Resize *, gdouble, gdouble, gdouble, gdouble);
static void offset_update (GtkWidget *, gpointer);
static gint resize_events (GtkWidget *, GdkEvent *);
static void printsize_update (GtkWidget *, gpointer);
static void resolution_update (GtkWidget *, gpointer);
static void resize_scale_warn_callback (GtkWidget *, gboolean, gpointer);
Resize *
resize_widget_new (ResizeType type,
@ -1191,3 +1191,164 @@ resize_events (GtkWidget *widget,
return FALSE;
}
/*** Resize sanity checks ***/
void resize_scale_implement (ImageResize *image_scale)
{
GImage *gimage = NULL;
gboolean rulers_flush = FALSE;
gboolean display_flush = FALSE; /* this is a bit ugly:
we hijack the flush variable
to check if an undo_group was
already started */
g_assert(image_scale != NULL);
gimage = image_scale->gimage;
g_assert(gimage != NULL);
if (image_scale->resize->resolution_x != gimage->xresolution ||
image_scale->resize->resolution_y != gimage->yresolution)
{
undo_push_group_start (gimage, IMAGE_SCALE_UNDO);
gimage_set_resolution (gimage,
image_scale->resize->resolution_x,
image_scale->resize->resolution_y);
rulers_flush = TRUE;
display_flush = TRUE;
}
if (image_scale->resize->unit != gimage->unit)
{
if (!display_flush)
undo_push_group_start (gimage, IMAGE_SCALE_UNDO);
gimage_set_unit (gimage, image_scale->resize->unit);
gdisplays_setup_scale (gimage);
gdisplays_resize_cursor_label (gimage);
rulers_flush = TRUE;
display_flush = TRUE;
}
if (image_scale->resize->width != gimage->width ||
image_scale->resize->height != gimage->height)
{
if (image_scale->resize->width > 0 &&
image_scale->resize->height > 0)
{
if (!display_flush)
undo_push_group_start (gimage, IMAGE_SCALE_UNDO);
gimage_scale (gimage,
image_scale->resize->width,
image_scale->resize->height);
display_flush = TRUE;
}
else
{
g_message (_("Scale Error: Both width and height must be "
"greater than zero."));
return;
}
}
if (rulers_flush)
{
gdisplays_setup_scale (gimage);
gdisplays_resize_cursor_label (gimage);
}
if (display_flush)
{
undo_push_group_end (gimage);
gdisplays_flush ();
}
}
static
void resize_scale_warn_callback (GtkWidget *widget,
gboolean do_scale,
gpointer client_data)
{
ImageResize *image_scale = NULL;
GImage *gimage = NULL;
g_assert(client_data != NULL);
image_scale = (ImageResize *) client_data;
gimage = image_scale->gimage;
g_assert(gimage != NULL);
if(do_scale == TRUE) /* User doesn't mind losing layers... */
{
resize_scale_implement(image_scale);
resize_widget_free (image_scale->resize);
g_free (image_scale);
}
else
gtk_widget_set_sensitive (image_scale->resize->resize_shell, TRUE);
}
gboolean
resize_check_layer_scaling (ImageResize *image_scale)
{
/* Inventory the layer list in gimage and return TRUE if, after
* scaling, they all retain positive x and y pixel dimensions.
* Otherwise, put up a modal boolean dialog box and ask the user if
* she wishes to proceed. Return FALSE in the dialog case; the dialog box
* callback will complete the job if the user really wants to
* proceed. <02/22/2000 gosgood@idt.net>
*/
gboolean success = FALSE;
GImage *gimage = NULL;
GSList *list = NULL;
Layer *layer = NULL;
GtkWidget *dialog = NULL;
gchar *str = NULL;
g_assert(image_scale != NULL);
if(NULL != (gimage = image_scale->gimage))
{
/* Step through layers; test scaled dimensions. */
success = TRUE;
list = gimage->layers;
while(list && success == TRUE)
{
layer = (Layer *)list->data;
success = layer_check_scaling (layer,
image_scale->resize->width,
image_scale->resize->height);
list = g_slist_next (list);
}
/* Warn user on failure */
if(success == FALSE)
{
gtk_widget_set_sensitive (image_scale->resize->resize_shell, FALSE);
str = g_strdup (_("The chosen image size will shrink\n"
"some layers completely away.\nIs this what you want?"));
dialog =
gimp_query_boolean_box (_("Layer Too Small"),
gimp_standard_help_func,
"dialogs/scale_layer_warn.html",
FALSE,
str,
_("OK"), _("Cancel"),
NULL, NULL,
resize_scale_warn_callback,
image_scale);
g_free (str);
gtk_widget_show (dialog);
}
}
return success;
}

View File

@ -19,6 +19,7 @@
#define __RESIZE_H__
#include "libgimp/gimpunit.h"
#include "gimage.h"
typedef enum
{
@ -59,9 +60,16 @@ struct _Resize
void * private_part;
};
typedef struct
{
Resize *resize;
GimpImage *gimage;
} ImageResize;
/* If resolution_x is zero, then don't show resolution modification
* parts of the dialog. If object is non-NULL, then attach the cancel
* callback to its destroy signal. */
Resize * resize_widget_new (ResizeType type,
ResizeTarget target,
GtkObject * object,
@ -76,4 +84,9 @@ Resize * resize_widget_new (ResizeType type,
gpointer user_data);
void resize_widget_free (Resize * resize);
/* Layer scaling sanity check and warning dialogs */
gboolean resize_check_layer_scaling (ImageResize *);
void resize_scale_implement (ImageResize *);
#endif /* __RESIZE_H__ */

View File

@ -37,6 +37,7 @@ helpdata_DATA = \
really_close.html \
really_quit.html \
scale_image.html \
scale_layer_warn.html \
set_canvas_size.html \
shrink_selection.html \
tip_of_the_day.html \

View File

@ -0,0 +1,45 @@
<!doctype html public "-//w3c//dtd html 4.0 transitional//en">
<HTML>
<HEAD>
<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
<TITLE>Scale Image</TITLE>
</HEAD>
<BODY text="#000000" bgcolor="#FFFFFF" link="#0000FF" vlink="#FF0000" alink="#000088">
<TABLE width="100%" cellspacing="1" cellpadding="1">
<TR bgcolor="black">
<TD width="100%" align="center"><FONT size="+2" color="white">Layer Too Small</FONT></TD>
</TR>
<TR bgcolor="white" >
<TD width="100%" align="left">
<P>
[Placeholder: Documentation to come]
</P>
<H3>
Additional Information
</H3>
<P>
For further information see The Gimp User's Manual page XXXX and the Gimp
User's Tutorial page YYYY
<P>
Shortcut Key
<P>
Modifier
<P>
Drag and Drop
<P>
Xinput
<P>
----DEV----
<P>
<A href="index.html">Index</A>
<P>
(/dialogs/scale_layer_warn.html)
<P>
Sorry but the help file for scale_layer_warn is not yet done.
<P>
/Karin &amp; Olof
<P>
</TD>
</TR>
</TABLE>
</BODY></HTML>