1
/* GIMP - The GNU Image Manipulation Program
2
* Copyright (C) 1995-2001 Spencer Kimball, Peter Mattis, and others
4
* This program is free software; you can redistribute it and/or modify
5
* it under the terms of the GNU General Public License as published by
6
* the Free Software Foundation; either version 2 of the License, or
7
* (at your option) any later version.
9
* This program is distributed in the hope that it will be useful,
10
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
* GNU General Public License for more details.
14
* You should have received a copy of the GNU General Public License
15
* along with this program; if not, write to the Free Software
16
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21
#include <glib-object.h>
23
#include "libgimpmath/gimpmath.h"
25
#include "core-types.h"
27
#include "gimp-transform-resize.h"
30
#if defined (HAVE_FINITE)
31
#define FINITE(x) finite(x)
32
#elif defined (HAVE_ISFINITE)
33
#define FINITE(x) isfinite(x)
34
#elif defined (G_OS_WIN32)
35
#define FINITE(x) _finite(x)
37
#error "no FINITE() implementation available?!"
40
#define MIN4(a,b,c,d) MIN(MIN((a),(b)),MIN((c),(d)))
41
#define MAX4(a,b,c,d) MAX(MAX((a),(b)),MAX((c),(d)))
53
gdouble m, b; /* y = mx + b */
59
static void gimp_transform_resize_adjust (gdouble dx1,
71
static void gimp_transform_resize_crop (gdouble dx1,
87
* This function wants to be passed the inverse transformation matrix!!
90
gimp_transform_resize_boundary (const GimpMatrix3 *inv,
91
GimpTransformResize resize,
101
gdouble dx1, dx2, dx3, dx4;
102
gdouble dy1, dy2, dy3, dy4;
104
g_return_if_fail (inv != NULL);
106
/* initialize with the original boundary */
112
if (resize == GIMP_TRANSFORM_RESIZE_CLIP)
115
gimp_matrix3_transform_point (inv, u1, v1, &dx1, &dy1);
116
gimp_matrix3_transform_point (inv, u2, v1, &dx2, &dy2);
117
gimp_matrix3_transform_point (inv, u1, v2, &dx3, &dy3);
118
gimp_matrix3_transform_point (inv, u2, v2, &dx4, &dy4);
120
/* check if the transformation matrix is valid at all */
121
if (! FINITE (dx1) || ! FINITE (dy1) ||
122
! FINITE (dx2) || ! FINITE (dy2) ||
123
! FINITE (dx3) || ! FINITE (dy3) ||
124
! FINITE (dx4) || ! FINITE (dy4))
126
g_warning ("invalid transform matrix");
127
resize = GIMP_TRANSFORM_RESIZE_CLIP;
132
case GIMP_TRANSFORM_RESIZE_ADJUST:
133
gimp_transform_resize_adjust (dx1, dy1, dx2, dy2, dx3, dy3, dx4, dy4,
137
case GIMP_TRANSFORM_RESIZE_CLIP:
138
/* we are all done already */
141
case GIMP_TRANSFORM_RESIZE_CROP:
142
gimp_transform_resize_crop (dx1, dy1, dx2, dy2, dx3, dy3, dx4, dy4,
147
case GIMP_TRANSFORM_RESIZE_CROP_WITH_ASPECT:
148
gimp_transform_resize_crop (dx1, dy1, dx2, dy2, dx3, dy3, dx4, dy4,
149
((gdouble) u2 - u1) / (v2 - v1),
162
gimp_transform_resize_adjust (gdouble dx1,
175
*x1 = (gint) floor (MIN4 (dx1, dx2, dx3, dx4));
176
*y1 = (gint) floor (MIN4 (dy1, dy2, dy3, dy4));
178
*x2 = (gint) ceil (MAX4 (dx1, dx2, dx3, dx4));
179
*y2 = (gint) ceil (MAX4 (dy1, dy2, dy3, dy4));
183
edge_init (Edge *edge,
189
edge->xmin = MIN ((p->x), (q->x));
190
edge->xmax = MAX ((p->x), (q->x));
192
edge->ymin = MIN ((p->y), (q->y));
193
edge->ymax = MAX ((p->y), (q->y));
195
edge->top = p->x > q->x;
196
edge->right = p->y > q->y;
203
edge->m = ((gdouble) q->y - p->y) / den;
204
edge->b = p->y - edge->m * p->x;
208
find_edge (const Edge *edges,
212
const Edge *emax = edges;
213
const Edge *e = edges;
216
for (i = 0; i < 4; i++)
218
if ((e->xmin == x) && (e->xmax != e->xmin) &&
219
((e->top && top) || (!e->top && !top)))
228
/* find largest pixel completely inside;
229
* look through all edges for intersection
232
intersect_x (const Edge *edges,
239
for (i = 0; i < 4; i++)
240
if (edges[i].right && edges[i].ymin <= y && edges[i].ymax >= y)
242
x0 = (y + 0.5 - edges[i].b) / edges[i].m;
243
x1 = (y - 0.5 - edges[i].b) / edges[i].m;
246
return (gint) floor (MIN (x0, x1));
250
intersect_y (const Edge *edge,
253
gdouble yfirst = edge->m * (xi - 0.5) + edge->b;
254
gdouble ylast = edge->m * (xi + 0.5) + edge->b;
256
return (gint) (edge->top ?
257
ceil (MAX (yfirst, ylast)) : floor (MIN (yfirst, ylast)));
261
gimp_transform_resize_crop (gdouble dx1,
294
/* fill in the points array */
295
points[0].x = floor (dx1);
296
points[0].y = floor (dy1);
297
points[1].x = floor (dx2);
298
points[1].y = floor (dy2);
299
points[2].x = floor (dx3);
300
points[2].y = floor (dy3);
301
points[3].x = floor (dx4);
302
points[3].y = floor (dy4);
304
/* first, translate the vertices into the first quadrant */
309
for (i = 0; i < 4; i++)
311
if (points[i].x < ax)
313
if (points[i].y < ay)
317
for (i = 0; i < 4; i++)
319
points[i].x += (-ax) * 2;
320
points[i].y += (-ay) * 2;
323
/* find the convex hull using Jarvis's March as the points are passed
324
* in different orders due to gimp_matrix3_transform_point()
328
for (i = 0; i < 4; i++)
330
if (points[i].y < points[min].y)
337
points[0].x = points[min].x;
338
points[0].y = points[min].y;
343
for (i = 1; i < 4; i++)
345
gdouble theta, theta_m = 2 * G_PI;
351
for (j = i; j < 4; j++)
353
gdouble sy = points[j].y - points[i - 1].y;
354
gdouble sx = points[j].x - points[i - 1].x;
355
theta = atan2 (sy, sx);
357
if ((theta < theta_m) &&
358
((theta > theta_v) || ((theta == theta_v) && (sx > 0))))
370
points[i].x = points[min].x;
371
points[i].y = points[min].y;
377
/* reverse the order of points */
379
tx = points[0].x; ty = points[0].y;
380
points[0].x = points[3].x; points[0].y = points[3].y;
381
points[3].x = tx; points[3].y = ty;
383
tx = points[1].x; ty = points[1].y;
384
points[1].x = points[2].x; points[1].y = points[2].y;
385
points[2].x = tx; points[2].y = ty;
388
/* now, find the largest rectangle using the method described in
389
* "Computing the Largest Inscribed Isothetic Rectangle" by
390
* D. Hsu, J. Snoeyink, et al.
393
/* first create an array of edges */
395
cxmin = cxmax = points[3].x;
396
cymin = cymax = points[3].y;
398
for (i = 0, a = points + 3, b = points; i < 4; i++, a = b, b++)
400
if (G_UNLIKELY (i == 0))
402
cxmin = cxmax = a->x;
403
cymin = cymax = a->y;
420
edge_init (edges + i, a, b);
423
xint = g_new (Point, cymax);
425
for (i = 0; i < cymax; i++)
427
xint[i].x = intersect_x (edges, i);
431
top = find_edge (edges, cxmin, TRUE);
432
bottom = find_edge (edges, cxmin, FALSE);
434
for (xi = cxmin; xi < cxmax; xi++)
438
ymin = intersect_y (top, xi);
439
ymax = intersect_y (bottom, xi);
441
for (ylo = ymax; ylo > ymin; ylo--)
443
for (yhi = ymin; yhi < ymax; yhi++)
449
gint height, width, fixed_width;
455
xright = MIN (xlo, xhi);
462
fixed_width = (gint) ceil ((gdouble) height * aspect);
464
if (fixed_width <= width)
470
area = width * height;
486
top = find_edge (edges, xi, TRUE);
488
if (xi == bottom->xmax)
489
bottom = find_edge (edges, xi, FALSE);
494
/* translate back the vertices */
496
*x1 = *x1 - ((-ax) * 2);
497
*y1 = *y1 - ((-ay) * 2);
498
*x2 = *x2 - ((-ax) * 2);
499
*y2 = *y2 - ((-ay) * 2);