gimpdrawable-transform.c 35 KB
Newer Older
1
/* GIMP - The GNU Image Manipulation Program
2
 * Copyright (C) 1995-2003 Spencer Kimball, Peter Mattis, and others
3
 *
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 3 of the License, or
7 8 9 10 11 12 13 14
 * (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
15
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
16 17 18 19
 */

#include "config.h"

20
#include <stdlib.h>
21
#include <string.h>
22

23
#include <cairo.h>
24
#include <gegl.h>
25
#include <gdk-pixbuf/gdk-pixbuf.h>
26

27
#include "libgimpbase/gimpbase.h"
28
#include "libgimpcolor/gimpcolor.h"
29 30
#include "libgimpmath/gimpmath.h"

31
#include "core-types.h"
32

33
#include "gegl/gimp-gegl-apply-operation.h"
34
#include "gegl/gimp-gegl-utils.h"
35

36
#include "gimp.h"
37
#include "gimp-transform-resize.h"
38 39 40 41
#include "gimpchannel.h"
#include "gimpcontext.h"
#include "gimpdrawable-transform.h"
#include "gimpimage.h"
42
#include "gimpimage-undo.h"
43
#include "gimpimage-undo-push.h"
44
#include "gimplayer.h"
45
#include "gimplayer-floating-selection.h"
46
#include "gimplayer-new.h"
47
#include "gimppickable.h"
48
#include "gimpprogress.h"
49
#include "gimpselection.h"
50

51
#include "gimp-intl.h"
52

53

54 55 56 57 58 59 60 61 62 63 64
#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


65
/*  public functions  */
66

67 68 69 70 71 72 73 74 75 76
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,
                                       GimpTransformResize     clip_result,
77
                                       GimpColorProfile      **buffer_profile,
78 79 80
                                       gint                   *new_offset_x,
                                       gint                   *new_offset_y,
                                       GimpProgress           *progress)
81
{
82
  GeglBuffer  *new_buffer;
83 84 85
  GimpMatrix3  m;
  gint         u1, v1, u2, v2;  /* source bounding box */
  gint         x1, y1, x2, y2;  /* target bounding box */
86
  GimpMatrix3  gegl_matrix;
87

88
  g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), NULL);
89
  g_return_val_if_fail (gimp_item_is_attached (GIMP_ITEM (drawable)), NULL);
90
  g_return_val_if_fail (GIMP_IS_CONTEXT (context), NULL);
91
  g_return_val_if_fail (GEGL_IS_BUFFER (orig_buffer), NULL);
92
  g_return_val_if_fail (matrix != NULL, NULL);
93
  g_return_val_if_fail (buffer_profile != NULL, NULL);
94 95
  g_return_val_if_fail (new_offset_x != NULL, NULL);
  g_return_val_if_fail (new_offset_y != NULL, NULL);
96
  g_return_val_if_fail (progress == NULL || GIMP_IS_PROGRESS (progress), NULL);
97

98 99 100
  *buffer_profile =
    gimp_color_managed_get_color_profile (GIMP_COLOR_MANAGED (drawable));

101
  m = *matrix;
102

103
  if (direction == GIMP_TRANSFORM_BACKWARD)
104 105
    {
      /*  Find the inverse of the transformation matrix  */
106
      gimp_matrix3_invert (&m);
107 108
    }

109 110
  u1 = orig_offset_x;
  v1 = orig_offset_y;
111 112
  u2 = u1 + gegl_buffer_get_width  (orig_buffer);
  v2 = v1 + gegl_buffer_get_height (orig_buffer);
113

114
  /*  Always clip unfloated buffers since they must keep their size  */
115
  if (G_TYPE_FROM_INSTANCE (drawable) == GIMP_TYPE_CHANNEL &&
116
      ! babl_format_has_alpha (gegl_buffer_get_format (orig_buffer)))
117
    clip_result = GIMP_TRANSFORM_RESIZE_CLIP;
118

119 120 121
  if (gimp_matrix3_will_explode (&m, u1, v1, u2, v2))
    clip_result = GIMP_TRANSFORM_RESIZE_CLIP;

122
  /*  Find the bounding coordinates of target */
123
  gimp_transform_resize_boundary (&m, clip_result,
124 125 126
                                  u1, v1, u2, v2,
                                  &x1, &y1, &x2, &y2);

127
  /*  Get the new temporary buffer for the transformed result  */
128 129
  new_buffer = gegl_buffer_new (GEGL_RECTANGLE (0, 0, x2 - x1, y2 - y1),
                                gegl_buffer_get_format (orig_buffer));
130

131 132
  gimp_matrix3_identity (&gegl_matrix);
  gimp_matrix3_translate (&gegl_matrix, u1, v1);
133
  gimp_matrix3_mult (&m, &gegl_matrix);
134 135
  gimp_matrix3_translate (&gegl_matrix, -x1, -y1);

136 137 138
  gimp_gegl_apply_transform (orig_buffer, progress, NULL,
                             new_buffer,
                             interpolation_type,
139
                             clip_result,
140
                             &gegl_matrix);
141

142 143 144
  *new_offset_x = x1;
  *new_offset_y = y1;

145
  return new_buffer;
146 147
}

148 149 150 151 152 153 154 155 156
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,
157
                                     GimpColorProfile   **buffer_profile,
158 159
                                     gint                *new_offset_x,
                                     gint                *new_offset_y)
160
{
161
  GeglBuffer    *new_buffer;
162 163 164 165 166 167 168
  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;
169 170

  g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), NULL);
171
  g_return_val_if_fail (gimp_item_is_attached (GIMP_ITEM (drawable)), NULL);
172
  g_return_val_if_fail (GIMP_IS_CONTEXT (context), NULL);
173
  g_return_val_if_fail (GEGL_IS_BUFFER (orig_buffer), NULL);
174 175 176 177 178 179
  g_return_val_if_fail (buffer_profile != NULL, NULL);
  g_return_val_if_fail (new_offset_x != NULL, NULL);
  g_return_val_if_fail (new_offset_y != NULL, NULL);

  *buffer_profile =
    gimp_color_managed_get_color_profile (GIMP_COLOR_MANAGED (drawable));
180

181 182
  orig_x      = orig_offset_x;
  orig_y      = orig_offset_y;
183 184
  orig_width  = gegl_buffer_get_width (orig_buffer);
  orig_height = gegl_buffer_get_height (orig_buffer);
185

186 187 188 189
  new_x      = orig_x;
  new_y      = orig_y;
  new_width  = orig_width;
  new_height = orig_height;
190 191 192 193

  switch (flip_type)
    {
    case GIMP_ORIENTATION_HORIZONTAL:
194 195
      new_x = RINT (-((gdouble) orig_x +
                      (gdouble) orig_width - axis) + axis);
196 197 198
      break;

    case GIMP_ORIENTATION_VERTICAL:
199 200
      new_y = RINT (-((gdouble) orig_y +
                      (gdouble) orig_height - axis) + axis);
201 202
      break;

203 204
    case GIMP_ORIENTATION_UNKNOWN:
      g_return_val_if_reached (NULL);
205 206 207
      break;
    }

208 209 210
  new_buffer = gegl_buffer_new (GEGL_RECTANGLE (0, 0,
                                                new_width, new_height),
                                gegl_buffer_get_format (orig_buffer));
211

212
  if (clip_result && (new_x != orig_x || new_y != orig_y))
213
    {
214 215 216 217
      GimpRGB    bg;
      GeglColor *color;
      gint       clip_x, clip_y;
      gint       clip_width, clip_height;
218

219 220
      *new_offset_x = orig_x;
      *new_offset_y = orig_y;
221 222 223

      /*  "Outside" a channel is transparency, not the bg color  */
      if (GIMP_IS_CHANNEL (drawable))
224 225 226
        {
          gimp_rgba_set (&bg, 0.0, 0.0, 0.0, 0.0);
        }
227
      else
228 229 230 231 232
        {
          gimp_context_get_background (context, &bg);
          gimp_pickable_srgb_to_image_color (GIMP_PICKABLE (drawable),
                                             &bg, &bg);
        }
233

234
      color = gimp_gegl_color_new (&bg);
235
      gegl_buffer_set_color (new_buffer, NULL, color);
236
      g_object_unref (color);
237 238 239 240 241 242 243 244 245 246 247 248 249 250 251

      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
    {
252 253
      *new_offset_x = new_x;
      *new_offset_y = new_y;
254 255 256 257 258 259 260 261

      orig_x = 0;
      orig_y = 0;
      new_x  = 0;
      new_y  = 0;
    }

  if (new_width == 0 && new_height == 0)
262
    return new_buffer;
263

264
  switch (flip_type)
265
    {
266
    case GIMP_ORIENTATION_HORIZONTAL:
267 268 269 270 271 272 273 274 275 276
      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;

277 278
      for (i = 0; i < orig_width; i++)
        {
279 280 281
          src_rect.x  = i + orig_x;
          dest_rect.x = new_x + new_width - i - 1;

282
          gegl_buffer_copy (orig_buffer, &src_rect, GEGL_ABYSS_NONE,
283
                            new_buffer, &dest_rect);
284
        }
285 286 287
      break;

    case GIMP_ORIENTATION_VERTICAL:
288 289 290 291 292 293 294 295 296 297
      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;

298 299
      for (i = 0; i < orig_height; i++)
        {
300 301 302
          src_rect.y  = i + orig_y;
          dest_rect.y = new_y + new_height - i - 1;

303
          gegl_buffer_copy (orig_buffer, &src_rect, GEGL_ABYSS_NONE,
304
                            new_buffer, &dest_rect);
305
        }
306 307 308 309
      break;

    case GIMP_ORIENTATION_UNKNOWN:
      break;
310 311
    }

312
  return new_buffer;
313 314
}

315 316 317 318 319 320 321 322 323 324 325 326 327 328 329
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:
330 331
      *new_x = RINT (center_x - (gdouble) y + center_y);
      *new_y = RINT (center_y + (gdouble) x - center_x);
332 333 334
      break;

    case GIMP_ROTATE_180:
335 336
      *new_x = RINT (center_x - ((gdouble) x - center_x));
      *new_y = RINT (center_y - ((gdouble) y - center_y));
337 338 339
      break;

    case GIMP_ROTATE_270:
340 341
      *new_x = RINT (center_x + (gdouble) y - center_y);
      *new_y = RINT (center_y - (gdouble) x + center_x);
342 343 344 345 346 347 348
      break;

    default:
      g_assert_not_reached ();
    }
}

349
GeglBuffer *
350 351 352 353 354 355 356 357 358 359 360 361
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,
                                       GimpColorProfile **buffer_profile,
                                       gint              *new_offset_x,
                                       gint              *new_offset_y)
362
{
363
  GeglBuffer    *new_buffer;
364 365 366 367 368 369 370
  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;
371 372

  g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), NULL);
373
  g_return_val_if_fail (gimp_item_is_attached (GIMP_ITEM (drawable)), NULL);
374
  g_return_val_if_fail (GIMP_IS_CONTEXT (context), NULL);
375
  g_return_val_if_fail (GEGL_IS_BUFFER (orig_buffer), NULL);
376 377 378 379 380 381
  g_return_val_if_fail (buffer_profile != NULL, NULL);
  g_return_val_if_fail (new_offset_x != NULL, NULL);
  g_return_val_if_fail (new_offset_y != NULL, NULL);

  *buffer_profile =
    gimp_color_managed_get_color_profile (GIMP_COLOR_MANAGED (drawable));
382

383 384
  orig_x      = orig_offset_x;
  orig_y      = orig_offset_y;
385 386 387
  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));
388

389 390 391
  switch (rotate_type)
    {
    case GIMP_ROTATE_90:
392 393 394 395
      gimp_drawable_transform_rotate_point (orig_x,
                                            orig_y + orig_height,
                                            rotate_type, center_x, center_y,
                                            &new_x, &new_y);
396 397 398 399 400
      new_width  = orig_height;
      new_height = orig_width;
      break;

    case GIMP_ROTATE_180:
401 402 403 404
      gimp_drawable_transform_rotate_point (orig_x + orig_width,
                                            orig_y + orig_height,
                                            rotate_type, center_x, center_y,
                                            &new_x, &new_y);
405 406 407 408 409
      new_width  = orig_width;
      new_height = orig_height;
      break;

    case GIMP_ROTATE_270:
410 411 412 413
      gimp_drawable_transform_rotate_point (orig_x + orig_width,
                                            orig_y,
                                            rotate_type, center_x, center_y,
                                            &new_x, &new_y);
414 415 416 417 418
      new_width  = orig_height;
      new_height = orig_width;
      break;

    default:
419 420
      g_return_val_if_reached (NULL);
      break;
421 422
    }

423 424
  if (clip_result && (new_x != orig_x || new_y != orig_y ||
                      new_width != orig_width || new_height != orig_height))
425

426
    {
427 428 429 430
      GimpRGB    bg;
      GeglColor *color;
      gint       clip_x, clip_y;
      gint       clip_width, clip_height;
431

432 433 434
      new_buffer = gegl_buffer_new (GEGL_RECTANGLE (0, 0,
                                                    orig_width, orig_height),
                                    gegl_buffer_get_format (orig_buffer));
435

436 437
      *new_offset_x = orig_x;
      *new_offset_y = orig_y;
438 439 440

      /*  "Outside" a channel is transparency, not the bg color  */
      if (GIMP_IS_CHANNEL (drawable))
441 442 443
        {
          gimp_rgba_set (&bg, 0.0, 0.0, 0.0, 0.0);
        }
444
      else
445 446 447 448 449
        {
          gimp_context_get_background (context, &bg);
          gimp_pickable_srgb_to_image_color (GIMP_PICKABLE (drawable),
                                             &bg, &bg);
        }
450

451
      color = gimp_gegl_color_new (&bg);
452
      gegl_buffer_set_color (new_buffer, NULL, color);
453
      g_object_unref (color);
454 455 456 457 458 459

      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))
        {
460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502
          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;
            }
503

504 505 506 507 508 509 510 511
          new_width  = clip_width;
          new_height = clip_height;
        }
      else
        {
          new_width  = 0;
          new_height = 0;
        }
512 513 514
    }
  else
    {
515 516 517
      new_buffer = gegl_buffer_new (GEGL_RECTANGLE (0, 0,
                                                    new_width, new_height),
                                    gegl_buffer_get_format (orig_buffer));
518

519 520
      *new_offset_x = new_x;
      *new_offset_y = new_y;
521 522 523 524 525 526 527

      orig_x = 0;
      orig_y = 0;
      new_x  = 0;
      new_y  = 0;
    }

528
  if (new_width < 1 || new_height < 1)
529
    return new_buffer;
530 531 532 533 534 535 536 537 538 539

  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;
540 541 542 543

  switch (rotate_type)
    {
    case GIMP_ROTATE_90:
544 545 546
      {
        guchar *buf = g_new (guchar, new_height * orig_bpp);
        gint    i;
547

548 549 550 551 552 553 554 555 556 557 558 559 560
        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;

561
            gegl_buffer_get (orig_buffer, &src_rect, 1.0, NULL, buf,
562
                             GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE);
563
            gegl_buffer_set (new_buffer, &dest_rect, 0, NULL, buf,
564 565 566 567 568
                             GEGL_AUTO_ROWSTRIDE);
          }

        g_free (buf);
      }
569 570 571
      break;

    case GIMP_ROTATE_180:
572 573 574
      {
        guchar *buf = g_new (guchar, new_width * orig_bpp);
        gint    i, j, k;
575

576
        g_assert (new_width == orig_width);
577

578 579
        src_rect.y      = orig_y + orig_height - 1;
        src_rect.height = 1;
580

581 582 583 584 585 586 587 588
        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;

589
            gegl_buffer_get (orig_buffer, &src_rect, 1.0, NULL, buf,
590
                             GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE);
591 592 593 594 595 596 597 598 599 600 601 602 603 604

            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;
                  }
              }

605
            gegl_buffer_set (new_buffer, &dest_rect, 0, NULL, buf,
606 607 608 609 610
                             GEGL_AUTO_ROWSTRIDE);
          }

        g_free (buf);
      }
611 612 613
      break;

    case GIMP_ROTATE_270:
614 615 616
      {
        guchar *buf = g_new (guchar, new_width * orig_bpp);
        gint    i;
617

618 619 620 621 622 623 624 625 626 627 628 629 630
        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;

631
            gegl_buffer_get (orig_buffer, &src_rect, 1.0, NULL, buf,
632
                             GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE);
633
            gegl_buffer_set (new_buffer, &dest_rect, 0, NULL, buf,
634 635 636 637 638
                             GEGL_AUTO_ROWSTRIDE);
          }

        g_free (buf);
      }
639 640 641
      break;
    }

642
  return new_buffer;
643 644
}

645
GimpDrawable *
646
gimp_drawable_transform_affine (GimpDrawable           *drawable,
647
                                GimpContext            *context,
648
                                const GimpMatrix3      *matrix,
649 650
                                GimpTransformDirection  direction,
                                GimpInterpolationType   interpolation_type,
651
                                GimpTransformResize     clip_result,
652
                                GimpProgress           *progress)
653
{
654
  GimpImage    *image;
655
  GeglBuffer   *orig_buffer;
656 657
  gint          orig_offset_x;
  gint          orig_offset_y;
658 659
  gboolean      new_layer;
  GimpDrawable *result = NULL;
660

661 662 663 664 665
  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);
666

667
  image = gimp_item_get_image (GIMP_ITEM (drawable));
668 669

  /* Start a transform undo group */
670
  gimp_image_undo_group_start (image,
671 672
                               GIMP_UNDO_GROUP_TRANSFORM,
                               C_("undo-type", "Transform"));
673 674

  /* Cut/Copy from the specified drawable */
675 676 677
  orig_buffer = gimp_drawable_transform_cut (drawable, context,
                                             &orig_offset_x, &orig_offset_y,
                                             &new_layer);
678

679
  if (orig_buffer)
680
    {
681 682 683 684
      GeglBuffer       *new_buffer;
      gint              new_offset_x;
      gint              new_offset_y;
      GimpColorProfile *profile;
685

686 687
      /*  always clip unfloated buffers so they keep their size  */
      if (GIMP_IS_CHANNEL (drawable) &&
688
          ! babl_format_has_alpha (gegl_buffer_get_format (orig_buffer)))
689
        clip_result = GIMP_TRANSFORM_RESIZE_CLIP;
690

691 692 693 694 695 696 697 698 699 700 701 702 703 704 705
      /*  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,
                               clip_result,
                               progress);
        }

706
      /* transform the buffer */
707 708 709 710 711 712 713 714
      new_buffer = gimp_drawable_transform_buffer_affine (drawable, context,
                                                          orig_buffer,
                                                          orig_offset_x,
                                                          orig_offset_y,
                                                          matrix,
                                                          direction,
                                                          interpolation_type,
                                                          clip_result,
715
                                                          &profile,
716 717 718
                                                          &new_offset_x,
                                                          &new_offset_y,
                                                          progress);
719 720

      /* Free the cut/copied buffer */
721
      g_object_unref (orig_buffer);
722

723
      if (new_buffer)
724
        {
725
          result = gimp_drawable_transform_paste (drawable, new_buffer, profile,
726
                                                  new_offset_x, new_offset_y,
727
                                                  new_layer);
728
          g_object_unref (new_buffer);
729
        }
730 731 732
    }

  /*  push the undo group end  */
733
  gimp_image_undo_group_end (image);
734

735
  return result;
736 737
}

738
GimpDrawable *
739
gimp_drawable_transform_flip (GimpDrawable        *drawable,
740
                              GimpContext         *context,
741 742 743
                              GimpOrientationType  flip_type,
                              gdouble              axis,
                              gboolean             clip_result)
744
{
745
  GimpImage    *image;
746
  GeglBuffer   *orig_buffer;
747 748
  gint          orig_offset_x;
  gint          orig_offset_y;
749 750
  gboolean      new_layer;
  GimpDrawable *result = NULL;
751

752 753 754
  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);
755

756
  image = gimp_item_get_image (GIMP_ITEM (drawable));
757 758

  /* Start a transform undo group */
759
  gimp_image_undo_group_start (image,
760
                               GIMP_UNDO_GROUP_TRANSFORM,
761
                               C_("undo-type", "Flip"));
762 763

  /* Cut/Copy from the specified drawable */
764 765 766
  orig_buffer = gimp_drawable_transform_cut (drawable, context,
                                             &orig_offset_x, &orig_offset_y,
                                             &new_layer);
767

768
  if (orig_buffer)
769
    {
770 771 772 773
      GeglBuffer       *new_buffer;
      gint              new_offset_x;
      gint              new_offset_y;
      GimpColorProfile *profile;
774

775
      /*  always clip unfloated buffers so they keep their size  */
776
      if (GIMP_IS_CHANNEL (drawable) &&
777
          ! babl_format_has_alpha (gegl_buffer_get_format (orig_buffer)))
778 779
        clip_result = TRUE;

780 781 782 783 784 785 786 787 788 789 790 791 792
      /*  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);
        }

793
      /* transform the buffer */
794 795 796 797 798 799 800 801 802 803 804 805
      new_buffer = gimp_drawable_transform_buffer_flip (drawable, context,
                                                        orig_buffer,
                                                        orig_offset_x,
                                                        orig_offset_y,
                                                        flip_type, axis,
                                                        clip_result,
                                                        &profile,
                                                        &new_offset_x,
                                                        &new_offset_y);

      /* Free the cut/copied buffer */
      g_object_unref (orig_buffer);
806

807
      if (new_buffer)
808
        {
809
          result = gimp_drawable_transform_paste (drawable, new_buffer, profile,
810
                                                  new_offset_x, new_offset_y,
811
                                                  new_layer);
812
          g_object_unref (new_buffer);
813
        }
814 815 816
    }

  /*  push the undo group end  */
817
  gimp_image_undo_group_end (image);
818

819
  return result;
820 821
}

822
GimpDrawable *
823
gimp_drawable_transform_rotate (GimpDrawable     *drawable,
824
                                GimpContext      *context,
825 826 827 828
                                GimpRotationType  rotate_type,
                                gdouble           center_x,
                                gdouble           center_y,
                                gboolean          clip_result)
829
{
830
  GimpImage    *image;
831
  GeglBuffer   *orig_buffer;
832 833
  gint          orig_offset_x;
  gint          orig_offset_y;
834 835
  gboolean      new_layer;
  GimpDrawable *result = NULL;
836

837 838 839
  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);
840

841
  image = gimp_item_get_image (GIMP_ITEM (drawable));
842 843

  /* Start a transform undo group */
844
  gimp_image_undo_group_start (image,
845
                               GIMP_UNDO_GROUP_TRANSFORM,
846
                               C_("undo-type", "Rotate"));
847 848

  /* Cut/Copy from the specified drawable */
849 850 851
  orig_buffer = gimp_drawable_transform_cut (drawable, context,
                                             &orig_offset_x, &orig_offset_y,
                                             &new_layer);
852

853
  if (orig_buffer)
854
    {
855 856 857 858
      GeglBuffer       *new_buffer;
      gint              new_offset_x;
      gint              new_offset_y;
      GimpColorProfile *profile;
859

860
      /*  always clip unfloated buffers so they keep their size  */
861
      if (GIMP_IS_CHANNEL (drawable) &&
862
          ! babl_format_has_alpha (gegl_buffer_get_format (orig_buffer)))
863
        clip_result = TRUE;
864

865 866 867 868 869 870 871 872 873 874 875 876 877 878
      /*  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);
        }

879
      /* transform the buffer */
880 881 882 883 884 885 886
      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,
887
                                                          &profile,
888 889
                                                          &new_offset_x,
                                                          &new_offset_y);
890 891

      /* Free the cut/copied buffer */
892
      g_object_unref (orig_buffer);
893

894
      if (new_buffer)
895
        {
896
          result = gimp_drawable_transform_paste (drawable, new_buffer, profile,
897
                                                  new_offset_x, new_offset_y,
898
                                                  new_layer);
899
          g_object_unref (new_buffer);
900
        }
901 902 903
    }

  /*  push the undo group end  */
904
  gimp_image_undo_group_end (image);
905

906
  return result;
907 908
}

909
GeglBuffer *
910
gimp_drawable_transform_cut (GimpDrawable *drawable,
911
                             GimpContext  *context,
912 913
                             gint         *offset_x,
                             gint         *offset_y,
914 915
                             gboolean     *new_layer)
{
916 917
  GimpImage  *image;
  GeglBuffer *buffer;
918

919
  g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), NULL);
920
  g_return_val_if_fail (gimp_item_is_attached (GIMP_ITEM (drawable)), NULL);
921
  g_return_val_if_fail (GIMP_IS_CONTEXT (context), NULL);
922 923
  g_return_val_if_fail (offset_x != NULL, NULL);
  g_return_val_if_fail (offset_y != NULL, NULL);
924 925
  g_return_val_if_fail (new_layer != NULL, NULL);

926
  image = gimp_item_get_image (GIMP_ITEM (drawable));
927

928
  /*  extract the selected mask if there is a selection  */
929
  if (! gimp_channel_is_empty (gimp_image_get_mask (image)))
930
    {
931 932
      gint x, y, w, h;

933
      /* set the keep_indexed flag to FALSE here, since we use
934 935
       * gimp_layer_new_from_gegl_buffer() later which assumes that
       * the buffer are either RGB or GRAY.  Eeek!!!  (Sven)
936
       */
937
      if (gimp_item_mask_intersect (GIMP_ITEM (drawable), &x, &y, &w, &h))
938
        {
939 940 941 942 943 944
          buffer = gimp_selection_extract (GIMP_SELECTION (gimp_image_get_mask (image)),
                                           GIMP_PICKABLE (drawable),
                                           context,
                                           TRUE, FALSE, TRUE,
                                           offset_x, offset_y,
                                           NULL);
945 946
          /*  clear the selection  */
          gimp_channel_clear (gimp_image_get_mask (image), NULL, TRUE);
947

948 949 950 951
          *new_layer = TRUE;
        }
      else
        {
952
          buffer = NULL;
953 954
          *new_layer = FALSE;
        }
955
    }
956
  else  /*  otherwise, just copy the layer  */
957
    {
958 959 960 961 962 963
      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);
964

965 966 967
      *new_layer = FALSE;
    }

968
  return buffer;
969 970
}

971
GimpDrawable *
972 973 974 975 976 977
gimp_drawable_transform_paste (GimpDrawable     *drawable,
                               GeglBuffer       *buffer,
                               GimpColorProfile *buffer_profile,
                               gint              offset_x,
                               gint              offset_y,
                               gboolean          new_layer)
978
{
979
  GimpImage   *image;
980 981
  GimpLayer   *layer     = NULL;
  const gchar *undo_desc = NULL;
982

983 984
  g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), NULL);
  g_return_val_if_fail (gimp_item_is_attached (GIMP_ITEM (drawable)), NULL);
985
  g_return_val_if_fail (GEGL_IS_BUFFER (buffer), NULL);
986
  g_return_val_if_fail (GIMP_IS_COLOR_PROFILE (buffer_profile), NULL);
987

988
  image = gimp_item_get_image (GIMP_ITEM (drawable));
989

990
  if (GIMP_IS_LAYER (drawable))
991
    undo_desc = C_("undo-type", "Transform Layer");
992
  else if (GIMP_IS_CHANNEL (drawable))
993
    undo_desc = C_("undo-type", "Transform Channel");
994
  else
995
    return NULL;
996

997
  gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_EDIT_PASTE, undo_desc);
998

999 1000 1001
  if (new_layer)
    {
      layer =
1002 1003 1004
        gimp_layer_new_from_gegl_buffer (buffer, image,
                                         gimp_drawable_get_format_with_alpha (drawable),
                                         _("Transformation"),
1005
                                         GIMP_OPACITY_OPAQUE, GIMP_NORMAL_MODE,
1006
                                         buffer_profile);
1007

1008
      gimp_item_set_offset (GIMP_ITEM (layer), offset_x, offset_y);
1009 1010

      floating_sel_attach (layer, drawable);
1011 1012

      drawable = GIMP_DRAWABLE (layer);
1013 1014 1015
    }
  else
    {
1016
      gimp_drawable_set_buffer_full (drawable, TRUE, NULL,
1017
                                     buffer,
1018
                                     offset_x, offset_y);
1019
    }
1020

1021
  gimp_image_undo_group_end (image);
1022

1023
  return drawable;
1024
}