Commit f0cff0ff authored by Mukund Sivaraman's avatar Mukund Sivaraman Committed by Mukund Sivaraman
Browse files

app/core/Makefile.am app/core/gimp-transform-resize.c

2006-12-24  Mukund Sivaraman  <muks@mukund.org>

        * app/core/Makefile.am
        * app/core/gimp-transform-resize.c
        * app/core/gimpchannel.c
        * app/core/gimpdrawable-transform.c
        * app/core/gimpdrawable-transform.h
        * app/core/gimpdrawable.c
        * app/core/gimpimage-item-list.c
        * app/core/gimpimage-item-list.h
        * app/core/gimpitem-linked.c
        * app/core/gimpitem-linked.h
        * app/core/gimpitem.c
        * app/core/gimpitem.h
        * app/core/gimplayer.c
        * app/pdb/drawable_transform_cmds.c
        * app/text/gimptextlayer-transform.c
        * app/text/gimptextlayer-transform.h
        * app/tools/gimptransformoptions.c
        * app/tools/gimptransformtool.c
        * app/vectors/gimpvectors.c
        * libgimp/gimpdrawabletransform_pdb.c
        * libgimp/gimpdrawabletransform_pdb.h
        * libgimp/gimpenums.c.tail
        * libgimpbase/gimpbase.def
        * libgimpbase/gimpbaseenums.c
        * libgimpbase/gimpbaseenums.h
        * tools/pdbgen/enums.pl
        * tools/pdbgen/pdb/drawable_transform.pdb: implemented UI and PDB
        for new clipping modes for affine transforms (crop to largest
        rectangle, and crop to largest rectangle with the source's aspect
        ratio); fixed various bugs in the largest rectangle computation
        code; set padding to 6 in the transformation tool options.
parent 6dad38a5
2006-12-24 Mukund Sivaraman <muks@mukund.org>
* app/core/Makefile.am
* app/core/gimp-transform-resize.c
* app/core/gimpchannel.c
* app/core/gimpdrawable-transform.c
* app/core/gimpdrawable-transform.h
* app/core/gimpdrawable.c
* app/core/gimpimage-item-list.c
* app/core/gimpimage-item-list.h
* app/core/gimpitem-linked.c
* app/core/gimpitem-linked.h
* app/core/gimpitem.c
* app/core/gimpitem.h
* app/core/gimplayer.c
* app/pdb/drawable_transform_cmds.c
* app/text/gimptextlayer-transform.c
* app/text/gimptextlayer-transform.h
* app/tools/gimptransformoptions.c
* app/tools/gimptransformtool.c
* app/vectors/gimpvectors.c
* libgimp/gimpdrawabletransform_pdb.c
* libgimp/gimpdrawabletransform_pdb.h
* libgimp/gimpenums.c.tail
* libgimpbase/gimpbase.def
* libgimpbase/gimpbaseenums.c
* libgimpbase/gimpbaseenums.h
* tools/pdbgen/enums.pl
* tools/pdbgen/pdb/drawable_transform.pdb: implemented UI and PDB
for new clipping modes for affine transforms (crop to largest
rectangle, and crop to largest rectangle with the source's aspect
ratio); fixed various bugs in the largest rectangle computation
code; set padding to 6 in the transformation tool options.
2006-12-22 Sven Neumann <sven@gimp.org>
* data/tips/gimp-tips.xml.in: another tips change (bug #141443).
......
......@@ -39,6 +39,8 @@ libappcore_a_sources = \
gimp-templates.h \
gimp-transform-region.c \
gimp-transform-region.h \
gimp-transform-resize.c \
gimp-transform-resize.h \
gimp-transform-utils.c \
gimp-transform-utils.h \
gimp-units.c \
......
......@@ -43,7 +43,7 @@
typedef struct
{
gdouble x, y;
gint x, y;
} Point;
typedef struct
......@@ -102,14 +102,14 @@ gimp_transform_resize_boundary (const GimpMatrix3 *inv,
gdouble dy1, dy2, dy3, dy4;
g_return_if_fail (inv != NULL);
/* initialize with the original boundary */
*x1 = u1;
*y1 = v1;
*x2 = u2;
*y2 = v2;
if (resize == GIMP_TRANSFORM_SIZE_CLIP)
if (resize == GIMP_TRANSFORM_RESIZE_CLIP)
return;
gimp_matrix3_transform_point (inv, u1, v1, &dx1, &dy1);
......@@ -124,25 +124,31 @@ gimp_transform_resize_boundary (const GimpMatrix3 *inv,
! FINITE (dx4) || ! FINITE (dy4))
{
g_warning ("invalid transform matrix");
resize = GIMP_TRANSFORM_SIZE_CLIP;
resize = GIMP_TRANSFORM_RESIZE_CLIP;
}
switch (resize)
{
case GIMP_TRANSFORM_SIZE_ADJUST:
case GIMP_TRANSFORM_RESIZE_ADJUST:
gimp_transform_resize_adjust (dx1, dy1, dx2, dy2, dx3, dy3, dx4, dy4,
x1, y1, x2, y2);
break;
case GIMP_TRANSFORM_SIZE_CLIP:
case GIMP_TRANSFORM_RESIZE_CLIP:
/* we are all done already */
break;
case GIMP_TRANSFORM_SIZE_CROP:
case GIMP_TRANSFORM_RESIZE_CROP:
gimp_transform_resize_crop (dx1, dy1, dx2, dy2, dx3, dy3, dx4, dy4,
0.0,
x1, y1, x2, y2);
break;
case GIMP_TRANSFORM_RESIZE_CROP_WITH_ASPECT:
gimp_transform_resize_crop (dx1, dy1, dx2, dy2, dx3, dy3, dx4, dy4,
((gdouble) u2 - u1) / (v2 - v1),
x1, y1, x2, y2);
break;
}
if (*x1 == *x2)
......@@ -178,16 +184,23 @@ edge_init (Edge *edge,
const Point *p,
const Point *q)
{
edge->xmin = MIN (ceil (p->x), ceil (q->x));
edge->xmax = MAX (floor (p->x), floor (q->x));
gdouble den;
edge->xmin = MIN ( (p->x), (q->x));
edge->xmax = MAX ( (p->x), (q->x));
edge->ymin = MIN (ceil (p->y), ceil (q->y));
edge->ymax = MAX (floor (p->y), floor (q->y));
edge->ymin = MIN ( (p->y), (q->y));
edge->ymax = MAX ( (p->y), (q->y));
edge->top = p->x > q->x;
edge->right = p->y > q->y;
edge->m = (q->y - p->y) / (q->x - p->x);
den = q->x - p->x;
if (den == 0)
den = 0.001;
edge->m = ((gdouble) q->y - p->y) / den;
edge->b = p->y - edge->m * p->x;
}
......@@ -258,6 +271,10 @@ gimp_transform_resize_crop (gdouble dx1,
gint *y2)
{
Point points[4];
gint ax, ay;
int min;
gint tx, ty;
Edge edges[4];
const Point *a;
const Point *b;
......@@ -273,16 +290,104 @@ gimp_transform_resize_crop (gdouble dx1,
gint i;
/* fill in the points array */
points[0].x = dx1;
points[0].y = dy1;
points[1].x = dx2;
points[1].y = dy2;
points[2].x = dx3;
points[2].y = dy3;
points[3].x = dx4;
points[3].y = dy4;
/* create an array of edges */
points[0].x = floor (dx1);
points[0].y = floor (dy1);
points[1].x = floor (dx2);
points[1].y = floor (dy2);
points[2].x = floor (dx3);
points[2].y = floor (dy3);
points[3].x = floor (dx4);
points[3].y = floor (dy4);
/* first, translate the vertices into the first quadrant */
ax = 0;
ay = 0;
for (i = 0; i < 4; i++)
{
if (points[i].x < ax)
ax = points[i].x;
if (points[i].y < ay)
ay = points[i].y;
}
for (i = 0; i < 4; i++)
{
points[i].x += (-ax) * 2;
points[i].y += (-ay) * 2;
}
/* find the convex hull using Jarvis's March as the points are passed
* in different orders due to gimp_matrix3_transform_point()
*/
min = 0;
for (i = 0; i < 4; i++)
{
if (points[i].y < points[min].y)
min = i;
}
tx = points[0].x;
ty = points[0].y;
points[0].x = points[min].x;
points[0].y = points[min].y;
points[min].x = tx;
points[min].y = ty;
for (i = 1; i < 4; i++)
{
gdouble theta, theta_m = 2 * G_PI;
gdouble theta_v = 0;
gint j;
min = 3;
for (j = i; j < 4; j++)
{
gdouble sy = points[j].y - points[i - 1].y;
gdouble sx = points[j].x - points[i - 1].x;
theta = atan2 (sy, sx);
if ((theta < theta_m) && ((theta > theta_v) || ((theta == theta_v) && (sx > 0))))
{
theta_m = theta;
min = j;
}
}
theta_v = theta_m;
tx = points[i].x;
ty = points[i].y;
points[i].x = points[min].x;
points[i].y = points[min].y;
points[min].x = tx;
points[min].y = ty;
}
/* reverse the order of points */
tx = points[0].x; ty = points[0].y;
points[0].x = points[3].x; points[0].y = points[3].y;
points[3].x = tx; points[3].y = ty;
tx = points[1].x; ty = points[1].y;
points[1].x = points[2].x; points[1].y = points[2].y;
points[2].x = tx; points[2].y = ty;
/* now, find the largest rectangle using the method described in
* "Computing the Largest Inscribed Isothetic Rectangle" by
* D. Hsu, J. Snoeyink, et al.
*/
/* first create an array of edges */
cxmin = cxmax = points[3].x;
cymin = cymax = points[3].y;
......@@ -330,9 +435,9 @@ gimp_transform_resize_crop (gdouble dx1,
ymin = intersect_y (top, xi);
ymax = intersect_y (bottom, xi);
for (ylo = ymax; ylo >= ymin; ylo--)
for (ylo = ymax; ylo > ymin; ylo--)
{
for (yhi = ymin; yhi <= ymax; yhi++)
for (yhi = ymin; yhi < ymax; yhi++)
{
if (yhi > ylo)
{
......@@ -364,7 +469,7 @@ gimp_transform_resize_crop (gdouble dx1,
if (area > maxarea)
{
maxarea = area;
*x1 = xi;
*y1 = ylo;
*x2 = xi + width;
......@@ -382,4 +487,11 @@ gimp_transform_resize_crop (gdouble dx1,
}
g_free (xint);
/* translate back the vertices */
*x1 = *x1 - ((-ax) * 2);
*y1 = *y1 - ((-ay) * 2);
*x2 = *x2 - ((-ax) * 2);
*y2 = *y2 - ((-ay) * 2);
}
......@@ -116,7 +116,7 @@ static void gimp_channel_transform (GimpItem *item,
GimpInterpolationType interpolation_type,
gboolean supersample,
gint recursion_level,
gboolean clip_result,
GimpTransformResize clip_result,
GimpProgress *progress);
static gboolean gimp_channel_stroke (GimpItem *item,
GimpDrawable *drawable,
......@@ -654,7 +654,7 @@ gimp_channel_transform (GimpItem *item,
GimpInterpolationType interpolation_type,
gboolean supersample,
gint recursion_level,
gboolean clip_result,
GimpTransformResize clip_result,
GimpProgress *progress)
{
if (G_TYPE_FROM_INSTANCE (item) == GIMP_TYPE_CHANNEL)
......
......@@ -34,6 +34,7 @@
#include "gimp.h"
#include "gimp-transform-region.h"
#include "gimp-transform-resize.h"
#include "gimpchannel.h"
#include "gimpcontext.h"
#include "gimpdrawable-transform.h"
......@@ -75,7 +76,7 @@ gimp_drawable_transform_tiles_affine (GimpDrawable *drawable,
GimpInterpolationType interpolation_type,
gboolean supersample,
gint recursion_level,
gboolean clip_result,
GimpTransformResize clip_result,
GimpProgress *progress)
{
GimpImage *image;
......@@ -118,56 +119,12 @@ gimp_drawable_transform_tiles_affine (GimpDrawable *drawable,
/* Always clip unfloated tiles since they must keep their size */
if (G_TYPE_FROM_INSTANCE (drawable) == GIMP_TYPE_CHANNEL &&
tile_manager_bpp (orig_tiles) == 1)
clip_result = TRUE;
clip_result = GIMP_TRANSFORM_RESIZE_CLIP;
/* Find the bounding coordinates of target */
if (clip_result)
{
x1 = u1;
y1 = v1;
x2 = u2;
y2 = v2;
}
else
{
gdouble dx1, dy1;
gdouble dx2, dy2;
gdouble dx3, dy3;
gdouble dx4, dy4;
gimp_matrix3_transform_point (&inv, u1, v1, &dx1, &dy1);
gimp_matrix3_transform_point (&inv, u2, v1, &dx2, &dy2);
gimp_matrix3_transform_point (&inv, u1, v2, &dx3, &dy3);
gimp_matrix3_transform_point (&inv, u2, v2, &dx4, &dy4);
if (! FINITE (dx1) || ! FINITE (dy1) ||
! FINITE (dx2) || ! FINITE (dy2) ||
! FINITE (dx3) || ! FINITE (dy3) ||
! FINITE (dx4) || ! FINITE (dy4))
{
/* fallback to clip_result if the passed matrix is broken */
x1 = u1;
y1 = v1;
x2 = u2;
y2 = v2;
}
else
{
x1 = (gint) floor (MIN4 (dx1, dx2, dx3, dx4));
y1 = (gint) floor (MIN4 (dy1, dy2, dy3, dy4));
x2 = (gint) ceil (MAX4 (dx1, dx2, dx3, dx4));
y2 = (gint) ceil (MAX4 (dy1, dy2, dy3, dy4));
if (x1 == x2)
x2++;
if (y1 == y2)
y2++;
}
}
gimp_transform_resize_boundary (&inv, clip_result, u1, v1, u2, v2,
&x1, &y1, &x2, &y2);
/* Get the new temporary buffer for the transformed result */
new_tiles = tile_manager_new (x2 - x1, y2 - y1,
tile_manager_bpp (orig_tiles));
......@@ -581,7 +538,7 @@ gimp_drawable_transform_affine (GimpDrawable *drawable,
GimpInterpolationType interpolation_type,
gboolean supersample,
gint recursion_level,
gboolean clip_result,
GimpTransformResize clip_result,
GimpProgress *progress)
{
GimpImage *image;
......@@ -610,7 +567,7 @@ gimp_drawable_transform_affine (GimpDrawable *drawable,
/* always clip unfloated tiles so they keep their size */
if (GIMP_IS_CHANNEL (drawable) && tile_manager_bpp (orig_tiles) == 1)
clip_result = TRUE;
clip_result = GIMP_TRANSFORM_RESIZE_CLIP;
/* transform the buffer */
new_tiles = gimp_drawable_transform_tiles_affine (drawable, context,
......
......@@ -41,7 +41,7 @@ TileManager * gimp_drawable_transform_tiles_affine (GimpDrawable *draw
GimpInterpolationType interpolation_type,
gboolean supersample,
gint recursion_level,
gboolean clip_result,
GimpTransformResize clip_result,
GimpProgress *progress);
TileManager * gimp_drawable_transform_tiles_flip (GimpDrawable *drawable,
GimpContext *context,
......@@ -65,7 +65,7 @@ gboolean gimp_drawable_transform_affine (GimpDrawable *draw
GimpInterpolationType interpolation_type,
gboolean supersample,
gint recursion_level,
gboolean clip_result,
GimpTransformResize clip_result,
GimpProgress *progress);
gboolean gimp_drawable_transform_flip (GimpDrawable *drawable,
......
......@@ -112,7 +112,7 @@ static void gimp_drawable_transform (GimpItem *item,
GimpInterpolationType interpolation_type,
gboolean supersample,
gint recursion_level,
gboolean clip_result,
GimpTransformResize clip_result,
GimpProgress *progress);
static guchar * gimp_drawable_get_color_at (GimpPickable *pickable,
......@@ -558,7 +558,7 @@ gimp_drawable_transform (GimpItem *item,
GimpInterpolationType interpolation_type,
gboolean supersample,
gint recursion_level,
gboolean clip_result,
GimpTransformResize clip_result,
GimpProgress *progress)
{
GimpDrawable *drawable = GIMP_DRAWABLE (item);
......
......@@ -123,7 +123,7 @@ gimp_image_item_list_transform (GimpImage *image,
GimpInterpolationType interpolation_type,
gboolean supersample,
gint recursion_level,
gboolean clip_result,
GimpTransformResize clip_result,
GimpProgress *progress)
{
g_return_if_fail (GIMP_IS_IMAGE (image));
......
......@@ -46,7 +46,7 @@ void gimp_image_item_list_transform (GimpImage *image,
GimpInterpolationType interpolation_type,
gboolean supersample,
gint recursion_level,
gboolean clip_result,
GimpTransformResize clip_result,
GimpProgress *progress);
GList * gimp_image_item_list_get_list (GimpImage *image,
......
......@@ -122,7 +122,7 @@ gimp_item_linked_transform (GimpItem *item,
GimpInterpolationType interpolation_type,
gboolean supersample,
gint recursion_level,
gboolean clip_result,
GimpTransformResize clip_result,
GimpProgress *progress)
{
GList *list;
......
......@@ -42,7 +42,7 @@ void gimp_item_linked_transform (GimpItem *item,
GimpInterpolationType interpolation_type,
gboolean supersample,
gint recursion_level,
gboolean clip_result,
GimpTransformResize clip_result,
GimpProgress *progress);
......
......@@ -976,7 +976,7 @@ gimp_item_transform (GimpItem *item,
GimpInterpolationType interpolation,
gboolean supersample,
gint recursion_level,
gboolean clip_result,
GimpTransformResize clip_result,
GimpProgress *progress)
{
GimpItemClass *item_class;
......
......@@ -107,7 +107,7 @@ struct _GimpItemClass
GimpInterpolationType interpolation_type,
gboolean supersample,
gint recursion_level,
gboolean clip_result,
GimpTransformResize clip_result,
GimpProgress *progress);
gboolean (* stroke) (GimpItem *item,
GimpDrawable *drawable,
......@@ -208,7 +208,7 @@ void gimp_item_transform (GimpItem *item,
GimpInterpolationType interpolation_type,
gboolean supersample,
gint recursion_level,
gboolean clip_result,
GimpTransformResize clip_result,
GimpProgress *progress);
gboolean gimp_item_stroke (GimpItem *item,
......
......@@ -135,7 +135,7 @@ static void gimp_layer_transform (GimpItem *item,
GimpInterpolationType interpolation_type,
gboolean supersample,
gint recursion_level,
gboolean clip_result,
GimpTransformResize clip_result,
GimpProgress *progress);
static void gimp_layer_invalidate_boundary (GimpDrawable *drawable);
static void gimp_layer_get_active_components (const GimpDrawable *drawable,
......@@ -778,7 +778,7 @@ gimp_layer_transform (GimpItem *item,
GimpInterpolationType interpolation_type,
gboolean supersample,
gint recursion_level,
gboolean clip_result,
GimpTransformResize clip_result,
GimpProgress *progress)
{
GimpLayer *layer = GIMP_LAYER (item);
......
This diff is collapsed.
......@@ -143,7 +143,7 @@ gimp_text_layer_transform (GimpItem *item,
GimpInterpolationType interpolation_type,
gboolean supersample,
gint recursion_level,
gboolean clip_result,
GimpTransformResize clip_result,
GimpProgress *progress)
{
/* TODO */
......
......@@ -48,7 +48,7 @@ void gimp_text_layer_transform (GimpItem *item,
GimpInterpolationType interpolation_type,
gboolean supersample,
gint recursion_level,
gboolean clip_result,
GimpTransformResize clip_result,
GimpProgress *progress);
......
......@@ -124,10 +124,11 @@ gimp_transform_options_class_init (GimpTransformOptionsClass *klass)
GIMP_PARAM_READWRITE |
G_PARAM_CONSTRUCT));
GIMP_CONFIG_INSTALL_PROP_BOOLEAN (object_class, PROP_CLIP,
"clip", NULL,
FALSE,
GIMP_PARAM_STATIC_STRINGS);
GIMP_CONFIG_INSTALL_PROP_ENUM (object_class, PROP_CLIP,
"clip", NULL,
GIMP_TYPE_TRANSFORM_RESIZE,
GIMP_TRANSFORM_RESIZE_ADJUST,
GIMP_PARAM_STATIC_STRINGS);
GIMP_CONFIG_INSTALL_PROP_ENUM (object_class, PROP_PREVIEW_TYPE,
"preview-type", NULL,
GIMP_TYPE_TRANSFORM_PREVIEW_TYPE,
......@@ -179,7 +180,7 @@ gimp_transform_options_set_property (GObject *object,
options->recursion_level = g_value_get_int (value);
break;
case PROP_CLIP:
options->clip = g_value_get_boolean (value);
options->clip = g_value_get_enum (value);
break;
case PROP_PREVIEW_TYPE:
options->preview_type = g_value_get_enum (value);
......@@ -225,7 +226,7 @@ gimp_transform_options_get_property (GObject *object,
g_value_set_int (value, options->recursion_level);
break;
case PROP_CLIP:
g_value_set_boolean (value, options->clip);
g_value_set_enum (value, options->clip);
break;
case PROP_PREVIEW_TYPE:
g_value_set_enum (value, options->preview_type);
......@@ -289,7 +290,7 @@ gimp_transform_options_gui (GimpToolOptions *tool_options)
gtk_widget_show (frame);
/* the interpolation menu */
hbox = gtk_hbox_new (FALSE, 4);
hbox = gtk_hbox_new (FALSE, 6);
gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
gtk_widget_show (hbox);
......@@ -307,10 +308,18 @@ gimp_transform_options_gui (GimpToolOptions *tool_options)
gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
gtk_widget_show (button);
/* the clip resulting image toggle button */
button = gimp_prop_check_button_new (config, "clip", _("Clip result"));
gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
gtk_widget_show (button);
/* the clipping menu */
hbox = gtk_hbox_new (FALSE, 6);
gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);