2006-12-10 05:33:38 +08:00
|
|
|
/* GIMP - The GNU Image Manipulation Program
|
2003-04-04 19:19:57 +08:00
|
|
|
* Copyright (C) 1995-2003 Spencer Kimball, Peter Mattis, and others
|
2001-03-01 14:56:57 +08:00
|
|
|
*
|
2009-01-18 06:28:01 +08:00
|
|
|
* This program is free software: you can redistribute it and/or modify
|
2001-03-01 14:56:57 +08:00
|
|
|
* it under the terms of the GNU General Public License as published by
|
2009-01-18 06:28:01 +08:00
|
|
|
* the Free Software Foundation; either version 3 of the License, or
|
2001-03-01 14:56:57 +08:00
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
2009-01-18 06:28:01 +08:00
|
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
2001-03-01 14:56:57 +08:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include "config.h"
|
|
|
|
|
2003-04-04 21:33:08 +08:00
|
|
|
#include <stdlib.h>
|
2008-05-23 22:09:55 +08:00
|
|
|
#include <string.h>
|
2003-04-04 21:33:08 +08:00
|
|
|
|
2012-03-20 02:57:55 +08:00
|
|
|
#include <cairo.h>
|
2008-10-10 04:24:04 +08:00
|
|
|
#include <gegl.h>
|
2012-05-03 09:36:22 +08:00
|
|
|
#include <gdk-pixbuf/gdk-pixbuf.h>
|
2001-03-01 14:56:57 +08:00
|
|
|
|
2006-08-29 22:46:32 +08:00
|
|
|
#include "libgimpbase/gimpbase.h"
|
2012-03-20 02:57:55 +08:00
|
|
|
#include "libgimpcolor/gimpcolor.h"
|
2001-03-01 14:56:57 +08:00
|
|
|
#include "libgimpmath/gimpmath.h"
|
|
|
|
|
2001-11-20 02:23:43 +08:00
|
|
|
#include "core-types.h"
|
2001-03-01 14:56:57 +08:00
|
|
|
|
2012-03-31 22:18:13 +08:00
|
|
|
#include "gegl/gimp-gegl-nodes.h"
|
2012-03-20 02:57:55 +08:00
|
|
|
#include "gegl/gimp-gegl-utils.h"
|
2001-04-07 23:58:26 +08:00
|
|
|
|
2001-11-20 02:23:43 +08:00
|
|
|
#include "gimp.h"
|
2012-03-20 07:00:01 +08:00
|
|
|
#include "gimp-apply-operation.h"
|
2006-12-25 00:48:08 +08:00
|
|
|
#include "gimp-transform-resize.h"
|
2001-11-20 02:23:43 +08:00
|
|
|
#include "gimpchannel.h"
|
|
|
|
#include "gimpcontext.h"
|
|
|
|
#include "gimpdrawable-transform.h"
|
|
|
|
#include "gimpimage.h"
|
2003-02-13 19:23:50 +08:00
|
|
|
#include "gimpimage-undo.h"
|
2003-02-14 22:14:29 +08:00
|
|
|
#include "gimpimage-undo-push.h"
|
2001-11-20 02:23:43 +08:00
|
|
|
#include "gimplayer.h"
|
2002-02-22 06:19:45 +08:00
|
|
|
#include "gimplayer-floating-sel.h"
|
2006-10-26 17:17:24 +08:00
|
|
|
#include "gimppickable.h"
|
2004-08-11 02:47:21 +08:00
|
|
|
#include "gimpprogress.h"
|
2003-10-06 20:17:11 +08:00
|
|
|
#include "gimpselection.h"
|
2001-11-20 02:23:43 +08:00
|
|
|
|
2003-03-26 00:38:19 +08:00
|
|
|
#include "gimp-intl.h"
|
2001-03-01 14:56:57 +08:00
|
|
|
|
2001-04-18 05:43:29 +08:00
|
|
|
|
2004-03-31 20:40:23 +08:00
|
|
|
#if defined (HAVE_FINITE)
|
|
|
|
#define FINITE(x) finite(x)
|
|
|
|
#elif defined (HAVE_ISFINITE)
|
|
|
|
#define FINITE(x) isfinite(x)
|
|
|
|
#elif defined (G_OS_WIN32)
|
|
|
|
#define FINITE(x) _finite(x)
|
|
|
|
#else
|
|
|
|
#error "no FINITE() implementation available?!"
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
2001-11-20 02:23:43 +08:00
|
|
|
/* public functions */
|
2001-03-01 14:56:57 +08:00
|
|
|
|
2012-03-21 21:30:47 +08:00
|
|
|
GeglBuffer *
|
|
|
|
gimp_drawable_transform_buffer_affine (GimpDrawable *drawable,
|
|
|
|
GimpContext *context,
|
|
|
|
GeglBuffer *orig_buffer,
|
|
|
|
gint orig_offset_x,
|
|
|
|
gint orig_offset_y,
|
|
|
|
const GimpMatrix3 *matrix,
|
|
|
|
GimpTransformDirection direction,
|
|
|
|
GimpInterpolationType interpolation_type,
|
|
|
|
gint recursion_level,
|
|
|
|
GimpTransformResize clip_result,
|
|
|
|
gint *new_offset_x,
|
|
|
|
gint *new_offset_y,
|
|
|
|
GimpProgress *progress)
|
2001-03-01 14:56:57 +08:00
|
|
|
{
|
2012-03-21 21:30:47 +08:00
|
|
|
GeglBuffer *new_buffer;
|
2006-10-26 17:17:24 +08:00
|
|
|
GimpMatrix3 m;
|
|
|
|
GimpMatrix3 inv;
|
|
|
|
gint u1, v1, u2, v2; /* source bounding box */
|
|
|
|
gint x1, y1, x2, y2; /* target bounding box */
|
2012-03-30 01:36:49 +08:00
|
|
|
GeglNode *affine;
|
|
|
|
GimpMatrix3 gegl_matrix;
|
2003-04-04 19:19:57 +08:00
|
|
|
|
2001-11-20 02:23:43 +08:00
|
|
|
g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), NULL);
|
2004-11-16 21:41:55 +08:00
|
|
|
g_return_val_if_fail (gimp_item_is_attached (GIMP_ITEM (drawable)), NULL);
|
2004-04-15 07:37:34 +08:00
|
|
|
g_return_val_if_fail (GIMP_IS_CONTEXT (context), NULL);
|
2012-03-21 21:30:47 +08:00
|
|
|
g_return_val_if_fail (GEGL_IS_BUFFER (orig_buffer), NULL);
|
2003-05-12 23:56:36 +08:00
|
|
|
g_return_val_if_fail (matrix != NULL, NULL);
|
2011-03-26 15:30:15 +08:00
|
|
|
g_return_val_if_fail (new_offset_x != NULL, NULL);
|
|
|
|
g_return_val_if_fail (new_offset_y != NULL, NULL);
|
2004-08-11 02:47:21 +08:00
|
|
|
g_return_val_if_fail (progress == NULL || GIMP_IS_PROGRESS (progress), NULL);
|
2001-11-20 02:23:43 +08:00
|
|
|
|
2004-03-14 01:45:58 +08:00
|
|
|
m = *matrix;
|
|
|
|
inv = *matrix;
|
|
|
|
|
2001-11-20 02:23:43 +08:00
|
|
|
if (direction == GIMP_TRANSFORM_BACKWARD)
|
2001-03-01 14:56:57 +08:00
|
|
|
{
|
|
|
|
/* keep the original matrix here, so we dont need to recalculate
|
2001-11-20 02:23:43 +08:00
|
|
|
* the inverse later
|
|
|
|
*/
|
2003-07-07 21:50:48 +08:00
|
|
|
gimp_matrix3_invert (&inv);
|
2001-03-01 14:56:57 +08:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Find the inverse of the transformation matrix */
|
2003-07-07 21:50:48 +08:00
|
|
|
gimp_matrix3_invert (&m);
|
2001-03-01 14:56:57 +08:00
|
|
|
}
|
|
|
|
|
2011-03-26 15:30:15 +08:00
|
|
|
u1 = orig_offset_x;
|
|
|
|
v1 = orig_offset_y;
|
2012-03-21 21:30:47 +08:00
|
|
|
u2 = u1 + gegl_buffer_get_width (orig_buffer);
|
|
|
|
v2 = v1 + gegl_buffer_get_height (orig_buffer);
|
2001-03-01 14:56:57 +08:00
|
|
|
|
2012-03-21 21:30:47 +08:00
|
|
|
/* Always clip unfloated buffers since they must keep their size */
|
2006-10-26 17:17:24 +08:00
|
|
|
if (G_TYPE_FROM_INSTANCE (drawable) == GIMP_TYPE_CHANNEL &&
|
2012-04-22 21:15:22 +08:00
|
|
|
! babl_format_has_alpha (gegl_buffer_get_format (orig_buffer)))
|
2006-12-25 00:48:08 +08:00
|
|
|
clip_result = GIMP_TRANSFORM_RESIZE_CLIP;
|
2003-05-13 21:57:11 +08:00
|
|
|
|
2003-04-04 19:19:57 +08:00
|
|
|
/* Find the bounding coordinates of target */
|
2007-09-04 17:38:55 +08:00
|
|
|
gimp_transform_resize_boundary (&inv, clip_result,
|
|
|
|
u1, v1, u2, v2,
|
|
|
|
&x1, &y1, &x2, &y2);
|
|
|
|
|
2001-03-01 14:56:57 +08:00
|
|
|
/* Get the new temporary buffer for the transformed result */
|
2012-06-21 03:44:09 +08:00
|
|
|
new_buffer = gegl_buffer_new (GEGL_RECTANGLE (0, 0, x2 - x1, y2 - y1),
|
|
|
|
gegl_buffer_get_format (orig_buffer));
|
2012-03-20 07:00:01 +08:00
|
|
|
|
2012-03-30 01:36:49 +08:00
|
|
|
gimp_matrix3_identity (&gegl_matrix);
|
|
|
|
gimp_matrix3_translate (&gegl_matrix, u1, v1);
|
|
|
|
gimp_matrix3_mult (&inv, &gegl_matrix);
|
|
|
|
gimp_matrix3_translate (&gegl_matrix, -x1, -y1);
|
|
|
|
|
|
|
|
affine = gegl_node_new_child (NULL,
|
|
|
|
"operation", "gegl:transform",
|
|
|
|
"filter", gimp_interpolation_to_gegl_filter (interpolation_type),
|
|
|
|
"hard-edges", TRUE,
|
|
|
|
NULL);
|
2012-03-31 22:18:13 +08:00
|
|
|
|
|
|
|
gimp_gegl_node_set_matrix (affine, &gegl_matrix);
|
2012-03-30 01:36:49 +08:00
|
|
|
|
|
|
|
gimp_apply_operation (orig_buffer, progress, NULL,
|
|
|
|
affine,
|
|
|
|
new_buffer, NULL);
|
|
|
|
|
|
|
|
g_object_unref (affine);
|
2006-10-26 17:17:24 +08:00
|
|
|
|
2011-03-26 15:30:15 +08:00
|
|
|
*new_offset_x = x1;
|
|
|
|
*new_offset_y = y1;
|
|
|
|
|
2012-03-21 21:30:47 +08:00
|
|
|
return new_buffer;
|
2006-10-26 17:17:24 +08:00
|
|
|
}
|
|
|
|
|
2012-03-21 21:30:47 +08:00
|
|
|
GeglBuffer *
|
|
|
|
gimp_drawable_transform_buffer_flip (GimpDrawable *drawable,
|
|
|
|
GimpContext *context,
|
|
|
|
GeglBuffer *orig_buffer,
|
|
|
|
gint orig_offset_x,
|
|
|
|
gint orig_offset_y,
|
|
|
|
GimpOrientationType flip_type,
|
|
|
|
gdouble axis,
|
|
|
|
gboolean clip_result,
|
|
|
|
gint *new_offset_x,
|
|
|
|
gint *new_offset_y)
|
2001-03-01 14:56:57 +08:00
|
|
|
{
|
2012-03-21 21:30:47 +08:00
|
|
|
GeglBuffer *new_buffer;
|
2012-03-20 02:57:55 +08:00
|
|
|
GeglRectangle src_rect;
|
|
|
|
GeglRectangle dest_rect;
|
|
|
|
gint orig_x, orig_y;
|
|
|
|
gint orig_width, orig_height;
|
|
|
|
gint new_x, new_y;
|
|
|
|
gint new_width, new_height;
|
|
|
|
gint i;
|
2001-11-20 02:23:43 +08:00
|
|
|
|
|
|
|
g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), NULL);
|
2004-11-16 21:41:55 +08:00
|
|
|
g_return_val_if_fail (gimp_item_is_attached (GIMP_ITEM (drawable)), NULL);
|
2004-04-15 07:37:34 +08:00
|
|
|
g_return_val_if_fail (GIMP_IS_CONTEXT (context), NULL);
|
2012-03-21 21:30:47 +08:00
|
|
|
g_return_val_if_fail (GEGL_IS_BUFFER (orig_buffer), NULL);
|
2001-11-20 02:23:43 +08:00
|
|
|
|
2011-03-26 15:30:15 +08:00
|
|
|
orig_x = orig_offset_x;
|
|
|
|
orig_y = orig_offset_y;
|
2012-03-21 21:30:47 +08:00
|
|
|
orig_width = gegl_buffer_get_width (orig_buffer);
|
|
|
|
orig_height = gegl_buffer_get_height (orig_buffer);
|
2007-11-28 16:09:31 +08:00
|
|
|
|
2003-05-14 18:51:14 +08:00
|
|
|
new_x = orig_x;
|
|
|
|
new_y = orig_y;
|
|
|
|
new_width = orig_width;
|
|
|
|
new_height = orig_height;
|
2003-05-12 23:56:36 +08:00
|
|
|
|
|
|
|
switch (flip_type)
|
|
|
|
{
|
|
|
|
case GIMP_ORIENTATION_HORIZONTAL:
|
2004-01-21 23:02:02 +08:00
|
|
|
new_x = RINT (-((gdouble) orig_x +
|
|
|
|
(gdouble) orig_width - axis) + axis);
|
2003-05-12 23:56:36 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
case GIMP_ORIENTATION_VERTICAL:
|
2004-01-21 23:02:02 +08:00
|
|
|
new_y = RINT (-((gdouble) orig_y +
|
|
|
|
(gdouble) orig_height - axis) + axis);
|
2003-05-12 23:56:36 +08:00
|
|
|
break;
|
|
|
|
|
2007-11-28 16:09:31 +08:00
|
|
|
case GIMP_ORIENTATION_UNKNOWN:
|
|
|
|
g_return_val_if_reached (NULL);
|
2003-05-12 23:56:36 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2012-06-21 03:44:09 +08:00
|
|
|
new_buffer = gegl_buffer_new (GEGL_RECTANGLE (0, 0,
|
|
|
|
new_width, new_height),
|
|
|
|
gegl_buffer_get_format (orig_buffer));
|
2003-05-14 18:51:14 +08:00
|
|
|
|
2007-11-28 16:09:31 +08:00
|
|
|
if (clip_result && (new_x != orig_x || new_y != orig_y))
|
2003-05-14 18:51:14 +08:00
|
|
|
{
|
2012-03-20 02:57:55 +08:00
|
|
|
GimpRGB bg;
|
|
|
|
GeglColor *color;
|
|
|
|
gint clip_x, clip_y;
|
|
|
|
gint clip_width, clip_height;
|
2003-05-14 18:51:14 +08:00
|
|
|
|
2011-03-26 15:30:15 +08:00
|
|
|
*new_offset_x = orig_x;
|
|
|
|
*new_offset_y = orig_y;
|
2003-05-14 18:51:14 +08:00
|
|
|
|
|
|
|
/* "Outside" a channel is transparency, not the bg color */
|
|
|
|
if (GIMP_IS_CHANNEL (drawable))
|
2012-03-20 02:57:55 +08:00
|
|
|
gimp_rgba_set (&bg, 0.0, 0.0, 0.0, 0.0);
|
|
|
|
else
|
|
|
|
gimp_context_get_background (context, &bg);
|
|
|
|
|
2012-03-20 17:27:28 +08:00
|
|
|
color = gimp_gegl_color_new (&bg);
|
2012-03-21 21:30:47 +08:00
|
|
|
gegl_buffer_set_color (new_buffer, NULL, color);
|
2012-03-20 02:57:55 +08:00
|
|
|
g_object_unref (color);
|
2003-05-14 18:51:14 +08:00
|
|
|
|
|
|
|
if (gimp_rectangle_intersect (orig_x, orig_y, orig_width, orig_height,
|
|
|
|
new_x, new_y, new_width, new_height,
|
|
|
|
&clip_x, &clip_y,
|
|
|
|
&clip_width, &clip_height))
|
|
|
|
{
|
|
|
|
orig_x = new_x = clip_x - orig_x;
|
|
|
|
orig_y = new_y = clip_y - orig_y;
|
|
|
|
}
|
|
|
|
|
|
|
|
orig_width = new_width = clip_width;
|
|
|
|
orig_height = new_height = clip_height;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2011-03-26 15:30:15 +08:00
|
|
|
*new_offset_x = new_x;
|
|
|
|
*new_offset_y = new_y;
|
2003-05-14 18:51:14 +08:00
|
|
|
|
|
|
|
orig_x = 0;
|
|
|
|
orig_y = 0;
|
|
|
|
new_x = 0;
|
|
|
|
new_y = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (new_width == 0 && new_height == 0)
|
2012-03-21 21:30:47 +08:00
|
|
|
return new_buffer;
|
2001-11-20 02:23:43 +08:00
|
|
|
|
2007-11-28 16:09:31 +08:00
|
|
|
switch (flip_type)
|
2001-11-20 02:23:43 +08:00
|
|
|
{
|
2007-11-28 16:09:31 +08:00
|
|
|
case GIMP_ORIENTATION_HORIZONTAL:
|
2012-03-20 02:57:55 +08:00
|
|
|
src_rect.x = orig_x;
|
|
|
|
src_rect.y = orig_y;
|
|
|
|
src_rect.width = 1;
|
|
|
|
src_rect.height = orig_height;
|
|
|
|
|
|
|
|
dest_rect.x = new_x + new_width - 1;
|
|
|
|
dest_rect.y = new_y;
|
|
|
|
dest_rect.width = 1;
|
|
|
|
dest_rect.height = new_height;
|
|
|
|
|
2001-11-20 02:23:43 +08:00
|
|
|
for (i = 0; i < orig_width; i++)
|
|
|
|
{
|
2012-03-20 02:57:55 +08:00
|
|
|
src_rect.x = i + orig_x;
|
|
|
|
dest_rect.x = new_x + new_width - i - 1;
|
|
|
|
|
2012-03-21 21:30:47 +08:00
|
|
|
gegl_buffer_copy (orig_buffer, &src_rect,
|
|
|
|
new_buffer, &dest_rect);
|
2001-11-20 02:23:43 +08:00
|
|
|
}
|
2007-11-28 16:09:31 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
case GIMP_ORIENTATION_VERTICAL:
|
2012-03-20 02:57:55 +08:00
|
|
|
src_rect.x = orig_x;
|
|
|
|
src_rect.y = orig_y;
|
|
|
|
src_rect.width = orig_width;
|
|
|
|
src_rect.height = 1;
|
|
|
|
|
|
|
|
dest_rect.x = new_x;
|
|
|
|
dest_rect.y = new_y + new_height - 1;
|
|
|
|
dest_rect.width = new_width;
|
|
|
|
dest_rect.height = 1;
|
|
|
|
|
2001-11-20 02:23:43 +08:00
|
|
|
for (i = 0; i < orig_height; i++)
|
|
|
|
{
|
2012-03-20 02:57:55 +08:00
|
|
|
src_rect.y = i + orig_y;
|
|
|
|
dest_rect.y = new_y + new_height - i - 1;
|
|
|
|
|
2012-03-21 21:30:47 +08:00
|
|
|
gegl_buffer_copy (orig_buffer, &src_rect,
|
|
|
|
new_buffer, &dest_rect);
|
2001-11-20 02:23:43 +08:00
|
|
|
}
|
2007-11-28 16:09:31 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
case GIMP_ORIENTATION_UNKNOWN:
|
|
|
|
break;
|
2001-11-20 02:23:43 +08:00
|
|
|
}
|
|
|
|
|
2012-03-21 21:30:47 +08:00
|
|
|
return new_buffer;
|
2001-11-20 02:23:43 +08:00
|
|
|
}
|
|
|
|
|
2003-05-21 02:13:07 +08:00
|
|
|
static void
|
|
|
|
gimp_drawable_transform_rotate_point (gint x,
|
|
|
|
gint y,
|
|
|
|
GimpRotationType rotate_type,
|
|
|
|
gdouble center_x,
|
|
|
|
gdouble center_y,
|
|
|
|
gint *new_x,
|
|
|
|
gint *new_y)
|
|
|
|
{
|
|
|
|
g_return_if_fail (new_x != NULL);
|
|
|
|
g_return_if_fail (new_y != NULL);
|
|
|
|
|
|
|
|
switch (rotate_type)
|
|
|
|
{
|
|
|
|
case GIMP_ROTATE_90:
|
2004-01-21 23:02:02 +08:00
|
|
|
*new_x = RINT (center_x - (gdouble) y + center_y);
|
|
|
|
*new_y = RINT (center_y + (gdouble) x - center_x);
|
2003-05-21 02:13:07 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
case GIMP_ROTATE_180:
|
2004-01-21 23:02:02 +08:00
|
|
|
*new_x = RINT (center_x - ((gdouble) x - center_x));
|
|
|
|
*new_y = RINT (center_y - ((gdouble) y - center_y));
|
2003-05-21 02:13:07 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
case GIMP_ROTATE_270:
|
2004-01-21 23:02:02 +08:00
|
|
|
*new_x = RINT (center_x + (gdouble) y - center_y);
|
|
|
|
*new_y = RINT (center_y - (gdouble) x + center_x);
|
2003-05-21 02:13:07 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
g_assert_not_reached ();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-03-21 21:30:47 +08:00
|
|
|
GeglBuffer *
|
|
|
|
gimp_drawable_transform_buffer_rotate (GimpDrawable *drawable,
|
|
|
|
GimpContext *context,
|
|
|
|
GeglBuffer *orig_buffer,
|
|
|
|
gint orig_offset_x,
|
|
|
|
gint orig_offset_y,
|
|
|
|
GimpRotationType rotate_type,
|
|
|
|
gdouble center_x,
|
|
|
|
gdouble center_y,
|
|
|
|
gboolean clip_result,
|
|
|
|
gint *new_offset_x,
|
|
|
|
gint *new_offset_y)
|
2003-05-20 18:36:29 +08:00
|
|
|
{
|
2012-03-21 21:30:47 +08:00
|
|
|
GeglBuffer *new_buffer;
|
2012-03-20 02:57:55 +08:00
|
|
|
GeglRectangle src_rect;
|
|
|
|
GeglRectangle dest_rect;
|
|
|
|
gint orig_x, orig_y;
|
|
|
|
gint orig_width, orig_height;
|
|
|
|
gint orig_bpp;
|
|
|
|
gint new_x, new_y;
|
|
|
|
gint new_width, new_height;
|
2003-05-20 18:36:29 +08:00
|
|
|
|
|
|
|
g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), NULL);
|
2004-11-16 21:41:55 +08:00
|
|
|
g_return_val_if_fail (gimp_item_is_attached (GIMP_ITEM (drawable)), NULL);
|
2004-04-15 07:37:34 +08:00
|
|
|
g_return_val_if_fail (GIMP_IS_CONTEXT (context), NULL);
|
2012-03-21 21:30:47 +08:00
|
|
|
g_return_val_if_fail (GEGL_IS_BUFFER (orig_buffer), NULL);
|
2003-05-20 18:36:29 +08:00
|
|
|
|
2011-03-26 15:30:15 +08:00
|
|
|
orig_x = orig_offset_x;
|
|
|
|
orig_y = orig_offset_y;
|
2012-03-21 21:30:47 +08:00
|
|
|
orig_width = gegl_buffer_get_width (orig_buffer);
|
|
|
|
orig_height = gegl_buffer_get_height (orig_buffer);
|
|
|
|
orig_bpp = babl_format_get_bytes_per_pixel (gegl_buffer_get_format (orig_buffer));
|
2007-11-28 16:09:31 +08:00
|
|
|
|
2003-05-20 18:36:29 +08:00
|
|
|
switch (rotate_type)
|
|
|
|
{
|
|
|
|
case GIMP_ROTATE_90:
|
2003-05-21 02:13:07 +08:00
|
|
|
gimp_drawable_transform_rotate_point (orig_x,
|
|
|
|
orig_y + orig_height,
|
|
|
|
rotate_type, center_x, center_y,
|
|
|
|
&new_x, &new_y);
|
2003-05-20 18:36:29 +08:00
|
|
|
new_width = orig_height;
|
|
|
|
new_height = orig_width;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case GIMP_ROTATE_180:
|
2003-05-21 02:13:07 +08:00
|
|
|
gimp_drawable_transform_rotate_point (orig_x + orig_width,
|
|
|
|
orig_y + orig_height,
|
|
|
|
rotate_type, center_x, center_y,
|
|
|
|
&new_x, &new_y);
|
2003-05-20 18:36:29 +08:00
|
|
|
new_width = orig_width;
|
|
|
|
new_height = orig_height;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case GIMP_ROTATE_270:
|
2003-05-21 02:13:07 +08:00
|
|
|
gimp_drawable_transform_rotate_point (orig_x + orig_width,
|
|
|
|
orig_y,
|
|
|
|
rotate_type, center_x, center_y,
|
|
|
|
&new_x, &new_y);
|
2003-05-20 18:36:29 +08:00
|
|
|
new_width = orig_height;
|
|
|
|
new_height = orig_width;
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
2007-11-28 16:09:31 +08:00
|
|
|
g_return_val_if_reached (NULL);
|
|
|
|
break;
|
2003-05-20 18:36:29 +08:00
|
|
|
}
|
|
|
|
|
2003-05-21 02:13:07 +08:00
|
|
|
if (clip_result && (new_x != orig_x || new_y != orig_y ||
|
|
|
|
new_width != orig_width || new_height != orig_height))
|
2003-10-06 20:17:11 +08:00
|
|
|
|
2003-05-20 18:36:29 +08:00
|
|
|
{
|
2012-03-20 02:57:55 +08:00
|
|
|
GimpRGB bg;
|
|
|
|
GeglColor *color;
|
|
|
|
gint clip_x, clip_y;
|
|
|
|
gint clip_width, clip_height;
|
2003-05-20 18:36:29 +08:00
|
|
|
|
2012-06-21 03:44:09 +08:00
|
|
|
new_buffer = gegl_buffer_new (GEGL_RECTANGLE (0, 0,
|
|
|
|
orig_width, orig_height),
|
|
|
|
gegl_buffer_get_format (orig_buffer));
|
2003-05-21 02:13:07 +08:00
|
|
|
|
2011-03-26 15:30:15 +08:00
|
|
|
*new_offset_x = orig_x;
|
|
|
|
*new_offset_y = orig_y;
|
2003-05-20 18:36:29 +08:00
|
|
|
|
|
|
|
/* "Outside" a channel is transparency, not the bg color */
|
|
|
|
if (GIMP_IS_CHANNEL (drawable))
|
2012-03-20 02:57:55 +08:00
|
|
|
gimp_rgba_set (&bg, 0.0, 0.0, 0.0, 0.0);
|
|
|
|
else
|
|
|
|
gimp_context_get_background (context, &bg);
|
2003-05-20 18:36:29 +08:00
|
|
|
|
2012-03-20 17:27:28 +08:00
|
|
|
color = gimp_gegl_color_new (&bg);
|
2012-03-21 21:30:47 +08:00
|
|
|
gegl_buffer_set_color (new_buffer, NULL, color);
|
2012-03-20 02:57:55 +08:00
|
|
|
g_object_unref (color);
|
2003-05-20 18:36:29 +08:00
|
|
|
|
|
|
|
if (gimp_rectangle_intersect (orig_x, orig_y, orig_width, orig_height,
|
|
|
|
new_x, new_y, new_width, new_height,
|
|
|
|
&clip_x, &clip_y,
|
|
|
|
&clip_width, &clip_height))
|
|
|
|
{
|
2003-05-21 02:13:07 +08:00
|
|
|
gint saved_orig_x = orig_x;
|
|
|
|
gint saved_orig_y = orig_y;
|
|
|
|
|
|
|
|
new_x = clip_x - orig_x;
|
|
|
|
new_y = clip_y - orig_y;
|
|
|
|
|
|
|
|
switch (rotate_type)
|
|
|
|
{
|
|
|
|
case GIMP_ROTATE_90:
|
|
|
|
gimp_drawable_transform_rotate_point (clip_x + clip_width,
|
|
|
|
clip_y,
|
|
|
|
GIMP_ROTATE_270,
|
|
|
|
center_x,
|
|
|
|
center_y,
|
|
|
|
&orig_x,
|
|
|
|
&orig_y);
|
|
|
|
orig_x -= saved_orig_x;
|
|
|
|
orig_y -= saved_orig_y;
|
|
|
|
orig_width = clip_height;
|
|
|
|
orig_height = clip_width;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case GIMP_ROTATE_180:
|
|
|
|
orig_x = clip_x - orig_x;
|
|
|
|
orig_y = clip_y - orig_y;
|
|
|
|
orig_width = clip_width;
|
|
|
|
orig_height = clip_height;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case GIMP_ROTATE_270:
|
|
|
|
gimp_drawable_transform_rotate_point (clip_x,
|
|
|
|
clip_y + clip_height,
|
|
|
|
GIMP_ROTATE_90,
|
|
|
|
center_x,
|
|
|
|
center_y,
|
|
|
|
&orig_x,
|
|
|
|
&orig_y);
|
|
|
|
orig_x -= saved_orig_x;
|
|
|
|
orig_y -= saved_orig_y;
|
|
|
|
orig_width = clip_height;
|
|
|
|
orig_height = clip_width;
|
|
|
|
break;
|
|
|
|
}
|
2003-05-20 18:36:29 +08:00
|
|
|
|
2011-03-18 07:51:05 +08:00
|
|
|
new_width = clip_width;
|
|
|
|
new_height = clip_height;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
new_width = 0;
|
|
|
|
new_height = 0;
|
|
|
|
}
|
2003-05-20 18:36:29 +08:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2012-06-21 03:44:09 +08:00
|
|
|
new_buffer = gegl_buffer_new (GEGL_RECTANGLE (0, 0,
|
|
|
|
new_width, new_height),
|
|
|
|
gegl_buffer_get_format (orig_buffer));
|
2003-05-21 02:13:07 +08:00
|
|
|
|
2011-03-26 15:30:15 +08:00
|
|
|
*new_offset_x = new_x;
|
|
|
|
*new_offset_y = new_y;
|
2003-05-20 18:36:29 +08:00
|
|
|
|
|
|
|
orig_x = 0;
|
|
|
|
orig_y = 0;
|
|
|
|
new_x = 0;
|
|
|
|
new_y = 0;
|
|
|
|
}
|
|
|
|
|
2011-03-18 07:51:05 +08:00
|
|
|
if (new_width < 1 || new_height < 1)
|
2012-03-21 21:30:47 +08:00
|
|
|
return new_buffer;
|
2012-03-20 02:57:55 +08:00
|
|
|
|
|
|
|
src_rect.x = orig_x;
|
|
|
|
src_rect.y = orig_y;
|
|
|
|
src_rect.width = orig_width;
|
|
|
|
src_rect.height = orig_height;
|
|
|
|
|
|
|
|
dest_rect.x = new_x;
|
|
|
|
dest_rect.y = new_y;
|
|
|
|
dest_rect.width = new_width;
|
|
|
|
dest_rect.height = new_height;
|
2003-05-20 18:36:29 +08:00
|
|
|
|
|
|
|
switch (rotate_type)
|
|
|
|
{
|
|
|
|
case GIMP_ROTATE_90:
|
2012-03-20 02:57:55 +08:00
|
|
|
{
|
|
|
|
guchar *buf = g_new (guchar, new_height * orig_bpp);
|
|
|
|
gint i;
|
2003-05-20 18:36:29 +08:00
|
|
|
|
2012-03-20 02:57:55 +08:00
|
|
|
g_assert (new_height == orig_width);
|
|
|
|
|
|
|
|
src_rect.y = orig_y + orig_height - 1;
|
|
|
|
src_rect.height = 1;
|
|
|
|
|
|
|
|
dest_rect.x = new_x;
|
|
|
|
dest_rect.width = 1;
|
|
|
|
|
|
|
|
for (i = 0; i < orig_height; i++)
|
|
|
|
{
|
|
|
|
src_rect.y = orig_y + orig_height - 1 - i;
|
|
|
|
dest_rect.x = new_x + i;
|
|
|
|
|
2012-03-25 11:51:55 +08:00
|
|
|
gegl_buffer_get (orig_buffer, &src_rect, 1.0, NULL, buf,
|
2012-03-26 08:17:24 +08:00
|
|
|
GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE);
|
2012-03-25 11:51:55 +08:00
|
|
|
gegl_buffer_set (new_buffer, &dest_rect, 0, NULL, buf,
|
2012-03-20 02:57:55 +08:00
|
|
|
GEGL_AUTO_ROWSTRIDE);
|
|
|
|
}
|
|
|
|
|
|
|
|
g_free (buf);
|
|
|
|
}
|
2003-05-20 18:36:29 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
case GIMP_ROTATE_180:
|
2012-03-20 02:57:55 +08:00
|
|
|
{
|
|
|
|
guchar *buf = g_new (guchar, new_width * orig_bpp);
|
|
|
|
gint i, j, k;
|
2003-05-20 18:36:29 +08:00
|
|
|
|
2012-03-20 02:57:55 +08:00
|
|
|
g_assert (new_width == orig_width);
|
2003-10-06 20:17:11 +08:00
|
|
|
|
2012-03-20 02:57:55 +08:00
|
|
|
src_rect.y = orig_y + orig_height - 1;
|
|
|
|
src_rect.height = 1;
|
2003-05-20 18:36:29 +08:00
|
|
|
|
2012-03-20 02:57:55 +08:00
|
|
|
dest_rect.y = new_y;
|
|
|
|
dest_rect.height = 1;
|
|
|
|
|
|
|
|
for (i = 0; i < orig_height; i++)
|
|
|
|
{
|
|
|
|
src_rect.y = orig_y + orig_height - 1 - i;
|
|
|
|
dest_rect.y = new_y + i;
|
|
|
|
|
2012-03-25 11:51:55 +08:00
|
|
|
gegl_buffer_get (orig_buffer, &src_rect, 1.0, NULL, buf,
|
2012-03-26 08:17:24 +08:00
|
|
|
GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE);
|
2012-03-20 02:57:55 +08:00
|
|
|
|
|
|
|
for (j = 0; j < orig_width / 2; j++)
|
|
|
|
{
|
|
|
|
guchar *left = buf + j * orig_bpp;
|
|
|
|
guchar *right = buf + (orig_width - 1 - j) * orig_bpp;
|
|
|
|
|
|
|
|
for (k = 0; k < orig_bpp; k++)
|
|
|
|
{
|
|
|
|
guchar tmp = left[k];
|
|
|
|
left[k] = right[k];
|
|
|
|
right[k] = tmp;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-03-25 11:51:55 +08:00
|
|
|
gegl_buffer_set (new_buffer, &dest_rect, 0, NULL, buf,
|
2012-03-20 02:57:55 +08:00
|
|
|
GEGL_AUTO_ROWSTRIDE);
|
|
|
|
}
|
|
|
|
|
|
|
|
g_free (buf);
|
|
|
|
}
|
2003-05-20 18:36:29 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
case GIMP_ROTATE_270:
|
2012-03-20 02:57:55 +08:00
|
|
|
{
|
|
|
|
guchar *buf = g_new (guchar, new_width * orig_bpp);
|
|
|
|
gint i;
|
2003-05-20 18:36:29 +08:00
|
|
|
|
2012-03-20 02:57:55 +08:00
|
|
|
g_assert (new_width == orig_height);
|
|
|
|
|
|
|
|
src_rect.x = orig_x + orig_width - 1;
|
|
|
|
src_rect.width = 1;
|
|
|
|
|
|
|
|
dest_rect.y = new_y;
|
|
|
|
dest_rect.height = 1;
|
|
|
|
|
|
|
|
for (i = 0; i < orig_width; i++)
|
|
|
|
{
|
|
|
|
src_rect.x = orig_x + orig_width - 1 - i;
|
|
|
|
dest_rect.y = new_y + i;
|
|
|
|
|
2012-03-25 11:51:55 +08:00
|
|
|
gegl_buffer_get (orig_buffer, &src_rect, 1.0, NULL, buf,
|
2012-03-26 08:17:24 +08:00
|
|
|
GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE);
|
2012-03-25 11:51:55 +08:00
|
|
|
gegl_buffer_set (new_buffer, &dest_rect, 0, NULL, buf,
|
2012-03-20 02:57:55 +08:00
|
|
|
GEGL_AUTO_ROWSTRIDE);
|
|
|
|
}
|
|
|
|
|
|
|
|
g_free (buf);
|
|
|
|
}
|
2003-05-20 18:36:29 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2012-03-21 21:30:47 +08:00
|
|
|
return new_buffer;
|
2003-05-20 18:36:29 +08:00
|
|
|
}
|
|
|
|
|
2010-09-16 06:36:03 +08:00
|
|
|
GimpDrawable *
|
2001-11-20 02:23:43 +08:00
|
|
|
gimp_drawable_transform_affine (GimpDrawable *drawable,
|
2004-04-15 07:37:34 +08:00
|
|
|
GimpContext *context,
|
2003-07-07 21:50:48 +08:00
|
|
|
const GimpMatrix3 *matrix,
|
2003-05-12 23:56:36 +08:00
|
|
|
GimpTransformDirection direction,
|
|
|
|
GimpInterpolationType interpolation_type,
|
2004-03-14 01:45:58 +08:00
|
|
|
gint recursion_level,
|
2006-12-25 00:48:08 +08:00
|
|
|
GimpTransformResize clip_result,
|
2004-08-31 22:17:33 +08:00
|
|
|
GimpProgress *progress)
|
2001-11-20 02:23:43 +08:00
|
|
|
{
|
2010-09-16 06:36:03 +08:00
|
|
|
GimpImage *image;
|
2012-03-21 21:30:47 +08:00
|
|
|
GeglBuffer *orig_buffer;
|
2011-03-27 01:37:34 +08:00
|
|
|
gint orig_offset_x;
|
|
|
|
gint orig_offset_y;
|
2010-09-16 06:36:03 +08:00
|
|
|
gboolean new_layer;
|
|
|
|
GimpDrawable *result = NULL;
|
2001-11-20 02:23:43 +08:00
|
|
|
|
2010-09-16 06:36:03 +08:00
|
|
|
g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), NULL);
|
|
|
|
g_return_val_if_fail (gimp_item_is_attached (GIMP_ITEM (drawable)), NULL);
|
|
|
|
g_return_val_if_fail (GIMP_IS_CONTEXT (context), NULL);
|
|
|
|
g_return_val_if_fail (matrix != NULL, NULL);
|
|
|
|
g_return_val_if_fail (progress == NULL || GIMP_IS_PROGRESS (progress), NULL);
|
2001-11-20 02:23:43 +08:00
|
|
|
|
2006-03-29 01:08:36 +08:00
|
|
|
image = gimp_item_get_image (GIMP_ITEM (drawable));
|
2001-11-20 02:23:43 +08:00
|
|
|
|
|
|
|
/* Start a transform undo group */
|
2006-03-29 01:08:36 +08:00
|
|
|
gimp_image_undo_group_start (image,
|
2010-09-16 06:36:03 +08:00
|
|
|
GIMP_UNDO_GROUP_TRANSFORM,
|
|
|
|
C_("undo-type", "Transform"));
|
2001-11-20 02:23:43 +08:00
|
|
|
|
|
|
|
/* Cut/Copy from the specified drawable */
|
2012-03-21 21:30:47 +08:00
|
|
|
orig_buffer = gimp_drawable_transform_cut (drawable, context,
|
|
|
|
&orig_offset_x, &orig_offset_y,
|
|
|
|
&new_layer);
|
2001-11-20 02:23:43 +08:00
|
|
|
|
2012-03-21 21:30:47 +08:00
|
|
|
if (orig_buffer)
|
2001-11-20 02:23:43 +08:00
|
|
|
{
|
2012-03-21 21:30:47 +08:00
|
|
|
GeglBuffer *new_buffer;
|
|
|
|
gint new_offset_x;
|
|
|
|
gint new_offset_y;
|
2001-11-20 02:23:43 +08:00
|
|
|
|
2012-03-21 21:30:47 +08:00
|
|
|
/* always clip unfloated buffers so they keep their size */
|
|
|
|
if (GIMP_IS_CHANNEL (drawable) &&
|
2012-04-22 21:15:22 +08:00
|
|
|
! babl_format_has_alpha (gegl_buffer_get_format (orig_buffer)))
|
2006-12-25 00:48:08 +08:00
|
|
|
clip_result = GIMP_TRANSFORM_RESIZE_CLIP;
|
2003-05-13 21:57:11 +08:00
|
|
|
|
2009-06-18 03:14:32 +08:00
|
|
|
/* also transform the mask if we are transforming an entire layer */
|
|
|
|
if (GIMP_IS_LAYER (drawable) &&
|
|
|
|
gimp_layer_get_mask (GIMP_LAYER (drawable)) &&
|
|
|
|
gimp_channel_is_empty (gimp_image_get_mask (image)))
|
|
|
|
{
|
|
|
|
GimpLayerMask *mask = gimp_layer_get_mask (GIMP_LAYER (drawable));
|
|
|
|
|
|
|
|
gimp_item_transform (GIMP_ITEM (mask), context,
|
|
|
|
matrix,
|
|
|
|
direction,
|
|
|
|
interpolation_type,
|
|
|
|
recursion_level,
|
|
|
|
clip_result,
|
|
|
|
progress);
|
|
|
|
}
|
|
|
|
|
2001-11-20 02:23:43 +08:00
|
|
|
/* transform the buffer */
|
2012-03-21 21:30:47 +08:00
|
|
|
new_buffer = gimp_drawable_transform_buffer_affine (drawable, context,
|
|
|
|
orig_buffer,
|
|
|
|
orig_offset_x,
|
|
|
|
orig_offset_y,
|
|
|
|
matrix,
|
|
|
|
direction,
|
|
|
|
interpolation_type,
|
|
|
|
recursion_level,
|
|
|
|
clip_result,
|
|
|
|
&new_offset_x,
|
|
|
|
&new_offset_y,
|
|
|
|
progress);
|
2001-11-20 02:23:43 +08:00
|
|
|
|
|
|
|
/* Free the cut/copied buffer */
|
2012-03-21 21:30:47 +08:00
|
|
|
g_object_unref (orig_buffer);
|
2001-11-20 02:23:43 +08:00
|
|
|
|
2012-03-21 21:30:47 +08:00
|
|
|
if (new_buffer)
|
2003-05-27 01:02:06 +08:00
|
|
|
{
|
2012-03-21 21:30:47 +08:00
|
|
|
result = gimp_drawable_transform_paste (drawable, new_buffer,
|
2011-03-26 15:30:15 +08:00
|
|
|
new_offset_x, new_offset_y,
|
2010-09-16 06:36:03 +08:00
|
|
|
new_layer);
|
2012-03-21 21:30:47 +08:00
|
|
|
g_object_unref (new_buffer);
|
2003-05-27 01:02:06 +08:00
|
|
|
}
|
2001-11-20 02:23:43 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/* push the undo group end */
|
2006-03-29 01:08:36 +08:00
|
|
|
gimp_image_undo_group_end (image);
|
2001-11-20 02:23:43 +08:00
|
|
|
|
2010-09-16 06:36:03 +08:00
|
|
|
return result;
|
2001-11-20 02:23:43 +08:00
|
|
|
}
|
|
|
|
|
2010-09-16 06:36:03 +08:00
|
|
|
GimpDrawable *
|
2003-02-08 01:12:21 +08:00
|
|
|
gimp_drawable_transform_flip (GimpDrawable *drawable,
|
2004-04-15 07:37:34 +08:00
|
|
|
GimpContext *context,
|
2004-10-27 01:50:52 +08:00
|
|
|
GimpOrientationType flip_type,
|
|
|
|
gdouble axis,
|
|
|
|
gboolean clip_result)
|
2001-11-20 02:23:43 +08:00
|
|
|
{
|
2010-09-16 06:36:03 +08:00
|
|
|
GimpImage *image;
|
2012-03-21 21:30:47 +08:00
|
|
|
GeglBuffer *orig_buffer;
|
2011-03-27 01:37:34 +08:00
|
|
|
gint orig_offset_x;
|
|
|
|
gint orig_offset_y;
|
2010-09-16 06:36:03 +08:00
|
|
|
gboolean new_layer;
|
|
|
|
GimpDrawable *result = NULL;
|
2001-11-20 02:23:43 +08:00
|
|
|
|
2010-09-16 06:36:03 +08:00
|
|
|
g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), NULL);
|
|
|
|
g_return_val_if_fail (gimp_item_is_attached (GIMP_ITEM (drawable)), NULL);
|
|
|
|
g_return_val_if_fail (GIMP_IS_CONTEXT (context), NULL);
|
2001-11-20 02:23:43 +08:00
|
|
|
|
2006-03-29 01:08:36 +08:00
|
|
|
image = gimp_item_get_image (GIMP_ITEM (drawable));
|
2001-11-20 02:23:43 +08:00
|
|
|
|
|
|
|
/* Start a transform undo group */
|
2007-11-28 16:09:31 +08:00
|
|
|
gimp_image_undo_group_start (image,
|
2008-05-23 22:09:55 +08:00
|
|
|
GIMP_UNDO_GROUP_TRANSFORM,
|
2010-06-08 19:24:11 +08:00
|
|
|
C_("undo-type", "Flip"));
|
2001-11-20 02:23:43 +08:00
|
|
|
|
|
|
|
/* Cut/Copy from the specified drawable */
|
2012-03-21 21:30:47 +08:00
|
|
|
orig_buffer = gimp_drawable_transform_cut (drawable, context,
|
|
|
|
&orig_offset_x, &orig_offset_y,
|
|
|
|
&new_layer);
|
2001-11-20 02:23:43 +08:00
|
|
|
|
2012-03-21 21:30:47 +08:00
|
|
|
if (orig_buffer)
|
2001-11-20 02:23:43 +08:00
|
|
|
{
|
2012-03-21 21:30:47 +08:00
|
|
|
GeglBuffer *new_buffer = NULL;
|
|
|
|
gint new_offset_x;
|
|
|
|
gint new_offset_y;
|
2003-05-12 23:56:36 +08:00
|
|
|
|
2012-04-22 21:15:22 +08:00
|
|
|
/* always clip unfloated buffers so they keep their size */
|
2012-03-21 21:30:47 +08:00
|
|
|
if (GIMP_IS_CHANNEL (drawable) &&
|
2012-04-22 21:15:22 +08:00
|
|
|
! babl_format_has_alpha (gegl_buffer_get_format (orig_buffer)))
|
2004-11-02 01:21:55 +08:00
|
|
|
clip_result = TRUE;
|
|
|
|
|
2009-06-18 03:14:32 +08:00
|
|
|
/* also transform the mask if we are transforming an entire layer */
|
|
|
|
if (GIMP_IS_LAYER (drawable) &&
|
|
|
|
gimp_layer_get_mask (GIMP_LAYER (drawable)) &&
|
|
|
|
gimp_channel_is_empty (gimp_image_get_mask (image)))
|
|
|
|
{
|
|
|
|
GimpLayerMask *mask = gimp_layer_get_mask (GIMP_LAYER (drawable));
|
|
|
|
|
|
|
|
gimp_item_flip (GIMP_ITEM (mask), context,
|
|
|
|
flip_type,
|
|
|
|
axis,
|
|
|
|
clip_result);
|
|
|
|
}
|
|
|
|
|
2001-11-20 02:23:43 +08:00
|
|
|
/* transform the buffer */
|
2012-03-21 21:30:47 +08:00
|
|
|
if (orig_buffer)
|
2005-03-22 06:47:06 +08:00
|
|
|
{
|
2012-03-21 21:30:47 +08:00
|
|
|
new_buffer = gimp_drawable_transform_buffer_flip (drawable, context,
|
|
|
|
orig_buffer,
|
|
|
|
orig_offset_x,
|
|
|
|
orig_offset_y,
|
|
|
|
flip_type, axis,
|
|
|
|
clip_result,
|
|
|
|
&new_offset_x,
|
|
|
|
&new_offset_y);
|
2001-11-20 02:23:43 +08:00
|
|
|
|
2005-03-22 06:47:06 +08:00
|
|
|
/* Free the cut/copied buffer */
|
2012-03-21 21:30:47 +08:00
|
|
|
g_object_unref (orig_buffer);
|
2005-03-22 06:47:06 +08:00
|
|
|
}
|
2001-11-20 02:23:43 +08:00
|
|
|
|
2012-03-21 21:30:47 +08:00
|
|
|
if (new_buffer)
|
2003-05-27 01:02:06 +08:00
|
|
|
{
|
2012-03-21 21:30:47 +08:00
|
|
|
result = gimp_drawable_transform_paste (drawable, new_buffer,
|
2011-03-26 15:30:15 +08:00
|
|
|
new_offset_x, new_offset_y,
|
2010-09-16 06:36:03 +08:00
|
|
|
new_layer);
|
2012-03-21 21:30:47 +08:00
|
|
|
g_object_unref (new_buffer);
|
2003-05-27 01:02:06 +08:00
|
|
|
}
|
2001-11-20 02:23:43 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/* push the undo group end */
|
2006-03-29 01:08:36 +08:00
|
|
|
gimp_image_undo_group_end (image);
|
2001-11-20 02:23:43 +08:00
|
|
|
|
2010-09-16 06:36:03 +08:00
|
|
|
return result;
|
2001-11-20 02:23:43 +08:00
|
|
|
}
|
|
|
|
|
2010-09-16 06:36:03 +08:00
|
|
|
GimpDrawable *
|
2003-05-20 18:36:29 +08:00
|
|
|
gimp_drawable_transform_rotate (GimpDrawable *drawable,
|
2004-04-15 07:37:34 +08:00
|
|
|
GimpContext *context,
|
2004-11-02 01:21:55 +08:00
|
|
|
GimpRotationType rotate_type,
|
|
|
|
gdouble center_x,
|
|
|
|
gdouble center_y,
|
|
|
|
gboolean clip_result)
|
2003-05-20 18:36:29 +08:00
|
|
|
{
|
2010-09-16 06:36:03 +08:00
|
|
|
GimpImage *image;
|
2012-03-21 21:30:47 +08:00
|
|
|
GeglBuffer *orig_buffer;
|
2011-03-27 01:37:34 +08:00
|
|
|
gint orig_offset_x;
|
|
|
|
gint orig_offset_y;
|
2010-09-16 06:36:03 +08:00
|
|
|
gboolean new_layer;
|
|
|
|
GimpDrawable *result = NULL;
|
2003-05-20 18:36:29 +08:00
|
|
|
|
2010-09-16 06:36:03 +08:00
|
|
|
g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), NULL);
|
|
|
|
g_return_val_if_fail (gimp_item_is_attached (GIMP_ITEM (drawable)), NULL);
|
|
|
|
g_return_val_if_fail (GIMP_IS_CONTEXT (context), NULL);
|
2003-05-20 18:36:29 +08:00
|
|
|
|
2006-03-29 01:08:36 +08:00
|
|
|
image = gimp_item_get_image (GIMP_ITEM (drawable));
|
2003-05-20 18:36:29 +08:00
|
|
|
|
|
|
|
/* Start a transform undo group */
|
2007-11-28 16:09:31 +08:00
|
|
|
gimp_image_undo_group_start (image,
|
2008-05-23 22:09:55 +08:00
|
|
|
GIMP_UNDO_GROUP_TRANSFORM,
|
2010-06-08 19:24:11 +08:00
|
|
|
C_("undo-type", "Rotate"));
|
2003-05-20 18:36:29 +08:00
|
|
|
|
|
|
|
/* Cut/Copy from the specified drawable */
|
2012-03-21 21:30:47 +08:00
|
|
|
orig_buffer = gimp_drawable_transform_cut (drawable, context,
|
|
|
|
&orig_offset_x, &orig_offset_y,
|
|
|
|
&new_layer);
|
2003-05-20 18:36:29 +08:00
|
|
|
|
2012-03-21 21:30:47 +08:00
|
|
|
if (orig_buffer)
|
2003-05-20 18:36:29 +08:00
|
|
|
{
|
2012-03-21 21:30:47 +08:00
|
|
|
GeglBuffer *new_buffer;
|
|
|
|
gint new_offset_x;
|
|
|
|
gint new_offset_y;
|
2003-05-20 18:36:29 +08:00
|
|
|
|
2012-04-22 21:15:22 +08:00
|
|
|
/* always clip unfloated buffers so they keep their size */
|
2012-03-21 21:30:47 +08:00
|
|
|
if (GIMP_IS_CHANNEL (drawable) &&
|
2012-04-22 21:15:22 +08:00
|
|
|
! babl_format_has_alpha (gegl_buffer_get_format (orig_buffer)))
|
2004-11-02 01:21:55 +08:00
|
|
|
clip_result = TRUE;
|
2003-05-20 18:36:29 +08:00
|
|
|
|
2009-06-18 03:14:32 +08:00
|
|
|
/* also transform the mask if we are transforming an entire layer */
|
|
|
|
if (GIMP_IS_LAYER (drawable) &&
|
|
|
|
gimp_layer_get_mask (GIMP_LAYER (drawable)) &&
|
|
|
|
gimp_channel_is_empty (gimp_image_get_mask (image)))
|
|
|
|
{
|
|
|
|
GimpLayerMask *mask = gimp_layer_get_mask (GIMP_LAYER (drawable));
|
|
|
|
|
|
|
|
gimp_item_rotate (GIMP_ITEM (mask), context,
|
|
|
|
rotate_type,
|
|
|
|
center_x,
|
|
|
|
center_y,
|
|
|
|
clip_result);
|
|
|
|
}
|
|
|
|
|
2003-05-20 18:36:29 +08:00
|
|
|
/* transform the buffer */
|
2012-03-21 21:30:47 +08:00
|
|
|
new_buffer = gimp_drawable_transform_buffer_rotate (drawable, context,
|
|
|
|
orig_buffer,
|
|
|
|
orig_offset_x,
|
|
|
|
orig_offset_y,
|
|
|
|
rotate_type,
|
|
|
|
center_x, center_y,
|
|
|
|
clip_result,
|
|
|
|
&new_offset_x,
|
|
|
|
&new_offset_y);
|
2003-05-20 18:36:29 +08:00
|
|
|
|
|
|
|
/* Free the cut/copied buffer */
|
2012-03-21 21:30:47 +08:00
|
|
|
g_object_unref (orig_buffer);
|
2003-05-20 18:36:29 +08:00
|
|
|
|
2012-03-21 21:30:47 +08:00
|
|
|
if (new_buffer)
|
2003-05-27 01:02:06 +08:00
|
|
|
{
|
2012-03-21 21:30:47 +08:00
|
|
|
result = gimp_drawable_transform_paste (drawable, new_buffer,
|
2011-03-26 15:30:15 +08:00
|
|
|
new_offset_x, new_offset_y,
|
2010-09-16 06:36:03 +08:00
|
|
|
new_layer);
|
2012-03-21 21:30:47 +08:00
|
|
|
g_object_unref (new_buffer);
|
2003-05-27 01:02:06 +08:00
|
|
|
}
|
2003-05-20 18:36:29 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/* push the undo group end */
|
2006-03-29 01:08:36 +08:00
|
|
|
gimp_image_undo_group_end (image);
|
2003-05-20 18:36:29 +08:00
|
|
|
|
2010-09-16 06:36:03 +08:00
|
|
|
return result;
|
2003-05-20 18:36:29 +08:00
|
|
|
}
|
|
|
|
|
2012-03-21 21:30:47 +08:00
|
|
|
GeglBuffer *
|
2001-11-20 02:23:43 +08:00
|
|
|
gimp_drawable_transform_cut (GimpDrawable *drawable,
|
2004-04-15 07:37:34 +08:00
|
|
|
GimpContext *context,
|
2011-03-26 15:30:15 +08:00
|
|
|
gint *offset_x,
|
|
|
|
gint *offset_y,
|
2001-11-20 02:23:43 +08:00
|
|
|
gboolean *new_layer)
|
|
|
|
{
|
2012-03-21 21:30:47 +08:00
|
|
|
GimpImage *image;
|
|
|
|
GeglBuffer *buffer;
|
2001-03-01 14:56:57 +08:00
|
|
|
|
2001-11-20 02:23:43 +08:00
|
|
|
g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), NULL);
|
2004-11-16 21:41:55 +08:00
|
|
|
g_return_val_if_fail (gimp_item_is_attached (GIMP_ITEM (drawable)), NULL);
|
2004-04-15 07:37:34 +08:00
|
|
|
g_return_val_if_fail (GIMP_IS_CONTEXT (context), NULL);
|
2011-03-26 15:30:15 +08:00
|
|
|
g_return_val_if_fail (offset_x != NULL, NULL);
|
|
|
|
g_return_val_if_fail (offset_y != NULL, NULL);
|
2001-11-20 02:23:43 +08:00
|
|
|
g_return_val_if_fail (new_layer != NULL, NULL);
|
|
|
|
|
2006-03-29 01:08:36 +08:00
|
|
|
image = gimp_item_get_image (GIMP_ITEM (drawable));
|
2001-11-20 02:23:43 +08:00
|
|
|
|
2001-03-01 14:56:57 +08:00
|
|
|
/* extract the selected mask if there is a selection */
|
2006-03-29 01:08:36 +08:00
|
|
|
if (! gimp_channel_is_empty (gimp_image_get_mask (image)))
|
2001-03-01 14:56:57 +08:00
|
|
|
{
|
2005-03-22 06:47:06 +08:00
|
|
|
gint x, y, w, h;
|
|
|
|
|
2001-03-01 14:56:57 +08:00
|
|
|
/* set the keep_indexed flag to FALSE here, since we use
|
2012-04-22 21:15:22 +08:00
|
|
|
* gimp_layer_new_from_buffer() later which assumes that the buffer
|
2001-11-20 02:23:43 +08:00
|
|
|
* are either RGB or GRAY. Eeek!!! (Sven)
|
2001-03-01 14:56:57 +08:00
|
|
|
*/
|
2010-09-08 03:28:00 +08:00
|
|
|
if (gimp_item_mask_intersect (GIMP_ITEM (drawable), &x, &y, &w, &h))
|
2005-03-22 06:47:06 +08:00
|
|
|
{
|
2012-03-21 21:43:38 +08:00
|
|
|
buffer = gimp_selection_extract (GIMP_SELECTION (gimp_image_get_mask (image)),
|
|
|
|
GIMP_PICKABLE (drawable),
|
|
|
|
context,
|
|
|
|
TRUE, FALSE, TRUE,
|
|
|
|
offset_x, offset_y,
|
|
|
|
NULL);
|
2008-03-05 05:25:32 +08:00
|
|
|
/* clear the selection */
|
|
|
|
gimp_channel_clear (gimp_image_get_mask (image), NULL, TRUE);
|
2001-11-20 02:23:43 +08:00
|
|
|
|
2005-03-22 06:47:06 +08:00
|
|
|
*new_layer = TRUE;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2012-03-21 21:30:47 +08:00
|
|
|
buffer = NULL;
|
2005-03-22 06:47:06 +08:00
|
|
|
*new_layer = FALSE;
|
|
|
|
}
|
2001-03-01 14:56:57 +08:00
|
|
|
}
|
2003-05-14 18:51:14 +08:00
|
|
|
else /* otherwise, just copy the layer */
|
2001-03-01 14:56:57 +08:00
|
|
|
{
|
2012-03-21 21:43:38 +08:00
|
|
|
buffer = gimp_selection_extract (GIMP_SELECTION (gimp_image_get_mask (image)),
|
|
|
|
GIMP_PICKABLE (drawable),
|
|
|
|
context,
|
|
|
|
FALSE, TRUE, GIMP_IS_LAYER (drawable),
|
|
|
|
offset_x, offset_y,
|
|
|
|
NULL);
|
2001-11-20 02:23:43 +08:00
|
|
|
|
2001-03-01 14:56:57 +08:00
|
|
|
*new_layer = FALSE;
|
|
|
|
}
|
|
|
|
|
2012-03-21 21:30:47 +08:00
|
|
|
return buffer;
|
2001-03-01 14:56:57 +08:00
|
|
|
}
|
|
|
|
|
2010-09-16 06:36:03 +08:00
|
|
|
GimpDrawable *
|
2001-11-20 02:23:43 +08:00
|
|
|
gimp_drawable_transform_paste (GimpDrawable *drawable,
|
2012-03-21 21:30:47 +08:00
|
|
|
GeglBuffer *buffer,
|
2011-03-26 15:30:15 +08:00
|
|
|
gint offset_x,
|
|
|
|
gint offset_y,
|
2001-11-20 02:23:43 +08:00
|
|
|
gboolean new_layer)
|
2001-03-01 14:56:57 +08:00
|
|
|
{
|
2006-03-29 01:08:36 +08:00
|
|
|
GimpImage *image;
|
2004-03-17 23:06:06 +08:00
|
|
|
GimpLayer *layer = NULL;
|
|
|
|
const gchar *undo_desc = NULL;
|
2001-03-01 14:56:57 +08:00
|
|
|
|
2010-09-16 06:36:03 +08:00
|
|
|
g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), NULL);
|
|
|
|
g_return_val_if_fail (gimp_item_is_attached (GIMP_ITEM (drawable)), NULL);
|
2012-03-21 21:30:47 +08:00
|
|
|
g_return_val_if_fail (GEGL_IS_BUFFER (buffer), NULL);
|
2001-11-20 02:23:43 +08:00
|
|
|
|
2006-03-29 01:08:36 +08:00
|
|
|
image = gimp_item_get_image (GIMP_ITEM (drawable));
|
2001-11-20 02:23:43 +08:00
|
|
|
|
2004-03-17 23:06:06 +08:00
|
|
|
if (GIMP_IS_LAYER (drawable))
|
2010-06-08 19:24:11 +08:00
|
|
|
undo_desc = C_("undo-type", "Transform Layer");
|
2004-03-17 23:06:06 +08:00
|
|
|
else if (GIMP_IS_CHANNEL (drawable))
|
2010-06-08 19:24:11 +08:00
|
|
|
undo_desc = C_("undo-type", "Transform Channel");
|
2004-03-17 23:06:06 +08:00
|
|
|
else
|
2010-09-16 06:36:03 +08:00
|
|
|
return NULL;
|
2004-03-17 23:06:06 +08:00
|
|
|
|
2006-03-29 01:08:36 +08:00
|
|
|
gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_EDIT_PASTE, undo_desc);
|
2004-03-17 23:06:06 +08:00
|
|
|
|
2001-03-01 14:56:57 +08:00
|
|
|
if (new_layer)
|
|
|
|
{
|
|
|
|
layer =
|
2012-03-21 21:30:47 +08:00
|
|
|
gimp_layer_new_from_buffer (buffer, image,
|
2012-03-22 03:21:11 +08:00
|
|
|
gimp_drawable_get_format_with_alpha (drawable),
|
2012-03-21 21:30:47 +08:00
|
|
|
_("Transformation"),
|
|
|
|
GIMP_OPACITY_OPAQUE, GIMP_NORMAL_MODE);
|
2001-03-01 14:56:57 +08:00
|
|
|
|
2008-11-04 05:17:50 +08:00
|
|
|
gimp_item_set_offset (GIMP_ITEM (layer), offset_x, offset_y);
|
2001-03-01 14:56:57 +08:00
|
|
|
|
|
|
|
floating_sel_attach (layer, drawable);
|
2010-09-16 06:36:03 +08:00
|
|
|
|
|
|
|
drawable = GIMP_DRAWABLE (layer);
|
2001-03-01 14:56:57 +08:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2012-03-21 21:30:47 +08:00
|
|
|
gimp_drawable_set_buffer_full (drawable, TRUE, NULL,
|
2012-03-22 06:37:16 +08:00
|
|
|
buffer,
|
2012-03-21 21:30:47 +08:00
|
|
|
offset_x, offset_y);
|
2001-03-01 14:56:57 +08:00
|
|
|
}
|
2004-01-21 19:38:53 +08:00
|
|
|
|
2006-03-29 01:08:36 +08:00
|
|
|
gimp_image_undo_group_end (image);
|
2004-03-17 23:06:06 +08:00
|
|
|
|
2010-09-16 06:36:03 +08:00
|
|
|
return drawable;
|
2001-03-01 14:56:57 +08:00
|
|
|
}
|