gimpimage-resize.c 111 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
/* The GIMP -- an image manipulation program
 * Copyright (C) 1995 Spencer Kimball and Peter Mattis
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (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
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */
18

19 20
#include "config.h"

21
#include <string.h>
22

Sven Neumann's avatar
Sven Neumann committed
23 24
#include <gtk/gtk.h>

25
#include "libgimpcolor/gimpcolor.h"
26
#include "libgimpmath/gimpmath.h"
27
#include "libgimpbase/gimpbase.h"
28

Michael Natterer's avatar
Michael Natterer committed
29 30
#include "core-types.h"

Michael Natterer's avatar
Michael Natterer committed
31 32 33 34
#include "base/pixel-region.h"
#include "base/temp-buf.h"
#include "base/tile-manager.h"
#include "base/tile.h"
Sven Neumann's avatar
Sven Neumann committed
35

36 37
#include "paint-funcs/paint-funcs.h"

Michael Natterer's avatar
Michael Natterer committed
38 39 40
/* FIXME: remove the Path <-> BezierSelect dependency */
#include "tools/tools-types.h"

41
#include "app_procs.h"
42 43
#include "drawable.h"
#include "floating_sel.h"
44
#include "gdisplay.h"
45
#include "gimpcontext.h"
46
#include "gimpimage.h"
Michael Natterer's avatar
Michael Natterer committed
47
#include "gimpimage-colorhash.h"
48
#include "gimpimage-mask.h"
49
#include "gimpimage-undo.h"
50
#include "gimplayer.h"
51
#include "gimplayermask.h"
52
#include "gimplist.h"
53
#include "gimpmarshal.h"
54
#include "gimprc.h"
Manish Singh's avatar
Manish Singh committed
55
#include "gimpparasite.h"
56
#include "gimpundostack.h"
57
#include "parasitelist.h"
58
#include "path.h"
59
#include "undo.h"
60

61 62
#include "libgimp/gimpintl.h"

63

64 65 66 67 68 69 70
#ifdef DEBUG
#define TRC(x) printf x
#else
#define TRC(x)
#endif


71
/*  Local function declarations  */
72 73 74 75 76
static void     gimp_image_class_init            (GimpImageClass *klass);
static void     gimp_image_init                  (GimpImage      *gimage);
static void     gimp_image_destroy               (GtkObject      *object);
static void     gimp_image_name_changed          (GimpObject     *object);
static void     gimp_image_invalidate_preview    (GimpViewable   *viewable);
77
static void     gimp_image_size_changed          (GimpViewable   *viewable);
Michael Natterer's avatar
Michael Natterer committed
78 79
static void     gimp_image_real_colormap_changed (GimpImage      *gimage,
						  gint            ncol);
80
static TempBuf *gimp_image_get_preview           (GimpViewable   *gimage,
81 82
						  gint            width,
						  gint            height);
83
static TempBuf *gimp_image_get_new_preview       (GimpViewable   *viewable,
84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109
						  gint            width, 
						  gint            height);
static void     gimp_image_free_projection       (GimpImage      *gimage);
static void     gimp_image_allocate_shadow       (GimpImage      *gimage,
						  gint            width,
						  gint            height,
						  gint            bpp);
static void     gimp_image_allocate_projection   (GimpImage      *gimage);
static void     gimp_image_construct_layers      (GimpImage      *gimage,
						  gint            x,
						  gint            y,
						  gint            w,
						  gint            h);
static void     gimp_image_construct_channels    (GimpImage      *gimage,
						  gint            x,
						  gint            y,
						  gint            w,
						  gint            h);
static void     gimp_image_initialize_projection (GimpImage      *gimage,
						  gint            x,
						  gint            y,
						  gint            w,
						  gint            h);
static void     gimp_image_get_active_channels   (GimpImage      *gimage,
						  GimpDrawable   *drawable,
						  gint           *active);
110 111

/*  projection functions  */
112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134
static void     project_intensity                (GimpImage      *gimage,
						  GimpLayer      *layer,
						  PixelRegion    *src,
						  PixelRegion    *dest,
						  PixelRegion    *mask);
static void     project_intensity_alpha          (GimpImage      *gimage,
						  GimpLayer      *layer,
						  PixelRegion    *src,
						  PixelRegion    *dest,
						  PixelRegion    *mask);
static void     project_indexed                  (GimpImage      *gimage,
						  GimpLayer      *layer,
						  PixelRegion    *src,
						  PixelRegion    *dest);
static void     project_indexed_alpha            (GimpImage      *gimage, 
						  GimpLayer      *layer,
						  PixelRegion    *src, 
						  PixelRegion    *dest,
						  PixelRegion    *mask);
static void     project_channel                  (GimpImage      *gimage,
						  GimpChannel    *channel,
						  PixelRegion    *src,
						  PixelRegion    *src2);
135 136 137 138

/*
 *  Global variables
 */
139
gint valid_combinations[][MAX_CHANNELS + 1] =
140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159
{
  /* RGB GIMAGE */
  { -1, -1, -1, COMBINE_INTEN_INTEN, COMBINE_INTEN_INTEN_A },
  /* RGBA GIMAGE */
  { -1, -1, -1, COMBINE_INTEN_A_INTEN, COMBINE_INTEN_A_INTEN_A },
  /* GRAY GIMAGE */
  { -1, COMBINE_INTEN_INTEN, COMBINE_INTEN_INTEN_A, -1, -1 },
  /* GRAYA GIMAGE */
  { -1, COMBINE_INTEN_A_INTEN, COMBINE_INTEN_A_INTEN_A, -1, -1 },
  /* INDEXED GIMAGE */
  { -1, COMBINE_INDEXED_INDEXED, COMBINE_INDEXED_INDEXED_A, -1, -1 },
  /* INDEXEDA GIMAGE */
  { -1, -1, COMBINE_INDEXED_A_INDEXED_A, -1, -1 },
};


/*
 *  Static variables
 */

160 161
enum
{
162
  MODE_CHANGED,
163
  ALPHA_CHANGED,
164
  FLOATING_SELECTION_CHANGED,
165 166
  ACTIVE_LAYER_CHANGED,
  ACTIVE_CHANNEL_CHANGED,
167 168
  COMPONENT_VISIBILITY_CHANGED,
  COMPONENT_ACTIVE_CHANGED,
169
  MASK_CHANGED,
170

171
  CLEAN,
172 173
  DIRTY,
  REPAINT,
174
  COLORMAP_CHANGED,
175
  UNDO_EVENT,
176 177
  LAST_SIGNAL
};
178

179 180
static guint gimp_image_signals[LAST_SIGNAL] = { 0 };

181
static GimpViewableClass *parent_class = NULL;
182

183 184 185
static gint        global_image_ID  = 1;
static GHashTable *gimp_image_table = NULL;

Michael Natterer's avatar
Michael Natterer committed
186 187
static guint32     next_guide_id    = 1;

188

189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213
GtkType 
gimp_image_get_type (void) 
{
  static GtkType image_type = 0;

  if (! image_type)
    {
      GtkTypeInfo image_info =
      {
        "GimpImage",
        sizeof (GimpImage),
        sizeof (GimpImageClass),
        (GtkClassInitFunc) gimp_image_class_init,
        (GtkObjectInitFunc) gimp_image_init,
        /* reserved_1 */ NULL,
        /* reserved_2 */ NULL,
        (GtkClassInitFunc) NULL,
      };

      image_type = gtk_type_unique (GIMP_TYPE_VIEWABLE, &image_info);
    }

  return image_type;
}

214 215 216
static void
gimp_image_class_init (GimpImageClass *klass)
{
217 218 219
  GtkObjectClass    *object_class;
  GimpObjectClass   *gimp_object_class;
  GimpViewableClass *viewable_class;
220

221 222
  object_class      = (GtkObjectClass *) klass;
  gimp_object_class = (GimpObjectClass *) klass;
223
  viewable_class    = (GimpViewableClass *) klass;
224

225
  parent_class = gtk_type_class (GIMP_TYPE_VIEWABLE);
226

227 228 229 230 231 232 233 234 235
  gimp_image_signals[MODE_CHANGED] =
    gtk_signal_new ("mode_changed",
                    GTK_RUN_FIRST,
                    object_class->type,
                    GTK_SIGNAL_OFFSET (GimpImageClass,
				       mode_changed),
                    gtk_signal_default_marshaller,
                    GTK_TYPE_NONE, 0);

236 237 238 239 240 241 242 243 244
  gimp_image_signals[ALPHA_CHANGED] =
    gtk_signal_new ("alpha_changed",
                    GTK_RUN_FIRST,
                    object_class->type,
                    GTK_SIGNAL_OFFSET (GimpImageClass,
				       alpha_changed),
                    gtk_signal_default_marshaller,
                    GTK_TYPE_NONE, 0);

245 246 247 248 249 250 251 252 253
  gimp_image_signals[FLOATING_SELECTION_CHANGED] =
    gtk_signal_new ("floating_selection_changed",
                    GTK_RUN_FIRST,
                    object_class->type,
                    GTK_SIGNAL_OFFSET (GimpImageClass,
				       floating_selection_changed),
                    gtk_signal_default_marshaller,
                    GTK_TYPE_NONE, 0);

254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271
  gimp_image_signals[ACTIVE_LAYER_CHANGED] =
    gtk_signal_new ("active_layer_changed",
                    GTK_RUN_FIRST,
                    object_class->type,
                    GTK_SIGNAL_OFFSET (GimpImageClass,
				       active_layer_changed),
                    gtk_signal_default_marshaller,
                    GTK_TYPE_NONE, 0);

  gimp_image_signals[ACTIVE_CHANNEL_CHANGED] =
    gtk_signal_new ("active_channel_changed",
                    GTK_RUN_FIRST,
                    object_class->type,
                    GTK_SIGNAL_OFFSET (GimpImageClass,
				       active_channel_changed),
                    gtk_signal_default_marshaller,
                    GTK_TYPE_NONE, 0);

272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291
  gimp_image_signals[COMPONENT_VISIBILITY_CHANGED] =
    gtk_signal_new ("component_visibility_changed",
                    GTK_RUN_FIRST,
                    object_class->type,
                    GTK_SIGNAL_OFFSET (GimpImageClass,
				       component_visibility_changed),
                    gtk_marshal_NONE__INT,
                    GTK_TYPE_NONE, 1,
		    GTK_TYPE_INT);

  gimp_image_signals[COMPONENT_ACTIVE_CHANGED] =
    gtk_signal_new ("component_active_changed",
                    GTK_RUN_FIRST,
                    object_class->type,
                    GTK_SIGNAL_OFFSET (GimpImageClass,
				       component_active_changed),
                    gtk_marshal_NONE__INT,
                    GTK_TYPE_NONE, 1,
		    GTK_TYPE_INT);

292 293 294 295 296 297 298 299 300
  gimp_image_signals[MASK_CHANGED] =
    gtk_signal_new ("mask_changed",
                    GTK_RUN_FIRST,
                    object_class->type,
                    GTK_SIGNAL_OFFSET (GimpImageClass,
				       mask_changed),
                    gtk_signal_default_marshaller,
                    GTK_TYPE_NONE, 0);

301
  gimp_image_signals[CLEAN] =
302 303 304 305 306 307 308 309
    gtk_signal_new ("clean",
                    GTK_RUN_FIRST,
                    object_class->type,
                    GTK_SIGNAL_OFFSET (GimpImageClass,
				       clean),
                    gtk_signal_default_marshaller,
                    GTK_TYPE_NONE, 0);

310
  gimp_image_signals[DIRTY] =
311 312 313 314 315 316 317 318
    gtk_signal_new ("dirty",
                    GTK_RUN_FIRST,
                    object_class->type,
                    GTK_SIGNAL_OFFSET (GimpImageClass,
				       dirty),
                    gtk_signal_default_marshaller,
                    GTK_TYPE_NONE, 0);

319
  gimp_image_signals[REPAINT] =
320 321 322 323 324 325 326 327 328 329 330 331
    gtk_signal_new ("repaint",
                    GTK_RUN_FIRST,
                    object_class->type,
                    GTK_SIGNAL_OFFSET (GimpImageClass,
				       repaint),
                    gimp_marshal_NONE__INT_INT_INT_INT,
                    GTK_TYPE_NONE, 4,
		    GTK_TYPE_INT,
		    GTK_TYPE_INT,
		    GTK_TYPE_INT,
		    GTK_TYPE_INT);

332
  gimp_image_signals[COLORMAP_CHANGED] =
333 334 335 336 337 338 339 340 341
    gtk_signal_new ("colormap_changed",
                    GTK_RUN_FIRST,
                    object_class->type,
                    GTK_SIGNAL_OFFSET (GimpImageClass,
				       colormap_changed),
                    gtk_marshal_NONE__INT,
                    GTK_TYPE_NONE, 1,
		    GTK_TYPE_INT);

342
  gimp_image_signals[UNDO_EVENT] = 
343 344 345 346 347 348 349 350
    gtk_signal_new ("undo_event",
                    GTK_RUN_FIRST,
                    object_class->type,
                    GTK_SIGNAL_OFFSET (GimpImageClass,
				       undo_event),
                    gtk_marshal_NONE__INT,
                    GTK_TYPE_NONE, 1,
		    GTK_TYPE_INT);
351

352
  gtk_object_class_add_signals (object_class, gimp_image_signals, LAST_SIGNAL);
353

354
  object_class->destroy               = gimp_image_destroy;
355

356
  gimp_object_class->name_changed     = gimp_image_name_changed;
357

358
  viewable_class->invalidate_preview  = gimp_image_invalidate_preview;
359
  viewable_class->size_changed        = gimp_image_size_changed;
360 361
  viewable_class->get_preview         = gimp_image_get_preview;
  viewable_class->get_new_preview     = gimp_image_get_new_preview;
362

363
  klass->mode_changed                 = NULL;
364
  klass->alpha_changed                = NULL;
365
  klass->floating_selection_changed   = NULL;
366 367 368 369
  klass->active_layer_changed         = NULL;
  klass->active_channel_changed       = NULL;
  klass->component_visibility_changed = NULL;
  klass->component_active_changed     = NULL;
370
  klass->mask_changed                 = NULL;
371

372 373 374
  klass->clean                        = NULL;
  klass->dirty                        = NULL;
  klass->repaint                      = NULL;
Michael Natterer's avatar
Michael Natterer committed
375
  klass->colormap_changed             = gimp_image_real_colormap_changed;
376 377 378
  klass->undo_event                   = NULL;
  klass->undo                         = gimp_image_undo;
  klass->redo                         = gimp_image_redo;
Michael Natterer's avatar
Michael Natterer committed
379 380

  gimp_image_color_hash_init ();
381 382 383 384 385
}


/* static functions */

Sven Neumann's avatar
Sven Neumann committed
386 387
static void 
gimp_image_init (GimpImage *gimage)
388
{
389 390
  gimage->ID                    = global_image_ID++;

391 392 393 394
  gimage->save_proc             = NULL;

  gimage->width                 = 0;
  gimage->height                = 0;
395 396 397
  gimage->xresolution           = gimprc.default_xresolution;
  gimage->yresolution           = gimprc.default_yresolution;
  gimage->unit                  = gimprc.default_units;
398 399
  gimage->base_type             = RGB;

400
  gimage->cmap                  = NULL;
401 402
  gimage->num_cols              = 0;

403
  gimage->dirty                 = 1;
404
  gimage->undo_on               = TRUE;
405 406 407 408

  gimage->instance_count        = 0;
  gimage->disp_count            = 0;

409
  gimage->tattoo_state          = 0;
410 411 412 413 414

  gimage->shadow                = NULL;

  gimage->construct_flag        = -1;
  gimage->proj_type             = RGBA_GIMAGE;
415
  gimage->projection            = NULL;
416

417
  gimage->guides                = NULL;
418

419 420 421 422
  gimage->layers                = gimp_list_new (GIMP_TYPE_LAYER, 
						 GIMP_CONTAINER_POLICY_STRONG);
  gimage->channels              = gimp_list_new (GIMP_TYPE_CHANNEL, 
						 GIMP_CONTAINER_POLICY_STRONG);
423
  gimage->layer_stack           = NULL;
424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439

  gimage->active_layer          = NULL;
  gimage->active_channel        = NULL;
  gimage->floating_sel          = NULL;
  gimage->selection_mask        = NULL;

  gimage->parasites             = parasite_list_new ();

  gimage->paths                 = NULL;

  gimage->qmask_state           = FALSE;
  gimage->qmask_color.r         = 1.0;
  gimage->qmask_color.g         = 0.0;
  gimage->qmask_color.b         = 0.0;
  gimage->qmask_color.a         = 0.5;

440 441 442 443
  gimage->undo_stack            = NULL;
  gimage->redo_stack            = NULL;
  gimage->undo_bytes            = 0;
  gimage->undo_levels           = 0;
444
  gimage->group_count           = 0;
445
  gimage->pushing_undo_group    = UNDO_NULL;
446 447
  gimage->undo_history          = NULL;

448 449 450
  gimage->new_undo_stack        = gimp_undo_stack_new (gimage);
  gimage->new_redo_stack        = gimp_undo_stack_new (gimage);

451
  gimage->comp_preview          = NULL;
452
  gimage->comp_preview_valid    = FALSE;
453 454 455 456 457 458 459

  if (gimp_image_table == NULL)
    gimp_image_table = g_hash_table_new (g_direct_hash, NULL);

  g_hash_table_insert (gimp_image_table,
		       GINT_TO_POINTER (gimage->ID),
		       (gpointer) gimage);
460 461
}

462 463
static void
gimp_image_destroy (GtkObject *object)
Sven Neumann's avatar
Sven Neumann committed
464
{
465 466 467 468 469
  GimpImage *gimage;

  gimage = GIMP_IMAGE (object);

  g_hash_table_remove (gimp_image_table, GINT_TO_POINTER (gimage->ID));
470

471 472 473 474 475
  gimp_image_free_projection (gimage);
  gimp_image_free_shadow (gimage);
  
  if (gimage->cmap)
    g_free (gimage->cmap);
476 477 478 479
  
  gtk_object_unref (GTK_OBJECT (gimage->layers));
  gtk_object_unref (GTK_OBJECT (gimage->channels));
  g_slist_free (gimage->layer_stack);
480 481

  gtk_object_unref (GTK_OBJECT (gimage->selection_mask));
482

483 484 485 486 487
  if (gimage->comp_preview)
    temp_buf_free (gimage->comp_preview);

  if (gimage->parasites)
    gtk_object_unref (GTK_OBJECT (gimage->parasites));
488

Michael Natterer's avatar
Michael Natterer committed
489 490 491
  g_list_foreach (gimage->guides, (GFunc) g_free, NULL);
  g_list_free (gimage->guides);

492 493
  gtk_object_unref (GTK_OBJECT (gimage->new_undo_stack));
  gtk_object_unref (GTK_OBJECT (gimage->new_redo_stack));
494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511
}

static void
gimp_image_name_changed (GimpObject *object)
{
  GimpImage   *gimage;
  const gchar *name;

  if (GIMP_OBJECT_CLASS (parent_class)->name_changed)
    GIMP_OBJECT_CLASS (parent_class)->name_changed (object);

  gimage = GIMP_IMAGE (object);
  name   = gimp_object_get_name (object);

  if (! (name && strlen (name)))
    {
      g_free (object->name);
      object->name = NULL;
512
    }
513
}
514

515 516 517 518 519
static void
gimp_image_invalidate_preview (GimpViewable *viewable)
{
  GimpImage *gimage;

520 521 522
  if (GIMP_VIEWABLE_CLASS (parent_class)->invalidate_preview)
    GIMP_VIEWABLE_CLASS (parent_class)->invalidate_preview (viewable);

523 524 525
  gimage = GIMP_IMAGE (viewable);

  gimage->comp_preview_valid = FALSE;
526 527
}

528 529 530 531 532 533 534 535 536 537 538 539 540 541
static void
gimp_image_size_changed (GimpViewable *viewable)
{
  GimpImage *gimage;

  if (GIMP_VIEWABLE_CLASS (parent_class)->size_changed)
    GIMP_VIEWABLE_CLASS (parent_class)->size_changed (viewable);

  gimage = GIMP_IMAGE (viewable);

  gimp_image_invalidate_layer_previews (gimage);
  gimp_image_invalidate_channel_previews (gimage);
}

Michael Natterer's avatar
Michael Natterer committed
542 543 544 545 546 547 548 549
static void 
gimp_image_real_colormap_changed (GimpImage *gimage,
				  gint       ncol)
{
  if (gimp_image_base_type (gimage) == INDEXED)
    gimp_image_color_hash_invalidate (gimage, ncol);
}

550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571
static void
gimp_image_allocate_projection (GimpImage *gimage)
{
  if (gimage->projection)
    gimp_image_free_projection (gimage);

  /*  Find the number of bytes required for the projection.
   *  This includes the intensity channels and an alpha channel
   *  if one doesn't exist.
   */
  switch (gimp_image_base_type (gimage))
    {
    case RGB:
    case INDEXED:
      gimage->proj_bytes = 4;
      gimage->proj_type = RGBA_GIMAGE;
      break;
    case GRAY:
      gimage->proj_bytes = 2;
      gimage->proj_type = GRAYA_GIMAGE;
      break;
    default:
572
      g_assert_not_reached ();
573 574 575
    }

  /*  allocate the new projection  */
576 577
  gimage->projection = tile_manager_new (gimage->width, gimage->height,
					 gimage->proj_bytes);
578
  tile_manager_set_user_data (gimage->projection, (void *) gimage);
579 580 581 582 583 584 585 586 587 588 589 590 591
  tile_manager_set_validate_proc (gimage->projection, gimp_image_validate);
}

static void
gimp_image_free_projection (GimpImage *gimage)
{
  if (gimage->projection)
    tile_manager_destroy (gimage->projection);

  gimage->projection = NULL;
}

static void
Sven Neumann's avatar
Sven Neumann committed
592
gimp_image_allocate_shadow (GimpImage *gimage, 
593 594 595
			    gint       width, 
			    gint       height, 
			    gint       bpp)
596 597 598 599 600 601 602 603 604
{
  /*  allocate the new projection  */
  gimage->shadow = tile_manager_new (width, height, bpp);
}


/* function definitions */

GimpImage *
605 606 607
gimp_image_new (gint               width,
		gint               height,
		GimpImageBaseType  base_type)
608
{
609
  GimpImage *gimage = GIMP_IMAGE (gtk_type_new (GIMP_TYPE_IMAGE));
610
  gint i;
611

612 613
  gimage->width     = width;
  gimage->height    = height;
614 615 616 617 618 619 620 621 622 623
  gimage->base_type = base_type;

  switch (base_type)
    {
    case RGB:
    case GRAY:
      break;
    case INDEXED:
      /* always allocate 256 colors for the colormap */
      gimage->num_cols = 0;
624
      gimage->cmap     = (guchar *) g_malloc0 (COLORMAP_SIZE);
625 626 627 628 629 630 631 632
      break;
    default:
      break;
    }

  /*  set all color channels visible and active  */
  for (i = 0; i < MAX_CHANNELS; i++)
    {
633 634
      gimage->visible[i] = TRUE;
      gimage->active[i]  = TRUE;
635 636 637
    }

  /* create the selection mask */
Michael Natterer's avatar
Michael Natterer committed
638 639 640
  gimage->selection_mask = gimp_channel_new_mask (gimage,
						  gimage->width,
						  gimage->height);
641 642 643 644 645


  return gimage;
}

646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664
gint
gimp_image_get_ID (GimpImage *gimage)
{
  g_return_val_if_fail (gimage != NULL, -1);
  g_return_val_if_fail (GIMP_IS_IMAGE (gimage), -1);

  return gimage->ID;
}

GimpImage *
gimp_image_get_by_ID (gint image_id)
{
  if (gimp_image_table == NULL)
    return NULL;

  return (GimpImage *) g_hash_table_lookup (gimp_image_table, 
					    GINT_TO_POINTER (image_id));
}

665
void
666 667
gimp_image_set_filename (GimpImage   *gimage,
			 const gchar *filename)
668
{
669 670
  gimp_object_set_name (GIMP_OBJECT (gimage), filename);
}
671

672
void
673
gimp_image_set_resolution (GimpImage *gimage,
674 675
			   gdouble    xresolution,
			   gdouble    yresolution)
676
{
677 678 679 680 681
  /* nothing to do if setting res to the same as before */
  if ((ABS (gimage->xresolution - xresolution) < 1e-5) &&
      (ABS (gimage->yresolution - yresolution) < 1e-5))
      return;

682 683 684
  /* don't allow to set the resolution out of bounds */
  if (xresolution < GIMP_MIN_RESOLUTION || xresolution > GIMP_MAX_RESOLUTION ||
      yresolution < GIMP_MIN_RESOLUTION || yresolution > GIMP_MAX_RESOLUTION)
685 686
    return;

687
  undo_push_resolution (gimage);
688

689 690
  gimage->xresolution = xresolution;
  gimage->yresolution = yresolution;
691 692 693

  /* really just want to recalc size and repaint */
  gdisplays_shrink_wrap (gimage);
694 695
}

696
void
697 698 699
gimp_image_get_resolution (const GimpImage *gimage,
			   gdouble         *xresolution,
			   gdouble         *yresolution)
700
{
701 702
  g_return_if_fail (xresolution && yresolution);

703 704
  *xresolution = gimage->xresolution;
  *yresolution = gimage->yresolution;
705 706
}

707 708
void
gimp_image_set_unit (GimpImage *gimage,
709
		     GimpUnit   unit)
710
{
711 712
  undo_push_resolution (gimage);

713 714 715
  gimage->unit = unit;
}

716
GimpUnit
717
gimp_image_get_unit (const GimpImage *gimage)
718 719 720 721
{
  return gimage->unit;
}

722
void
Sven Neumann's avatar
Sven Neumann committed
723 724
gimp_image_set_save_proc (GimpImage     *gimage, 
			  PlugInProcDef *proc)
725 726 727 728 729
{
  gimage->save_proc = proc;
}

PlugInProcDef *
730
gimp_image_get_save_proc (const GimpImage *gimage)
731 732 733
{
  return gimage->save_proc;
}
734

735 736 737 738 739 740 741 742 743 744 745 746
gint
gimp_image_get_width (const GimpImage *gimage)
{
  return gimage->width;
}

gint
gimp_image_get_height (const GimpImage *gimage)
{
  return gimage->height;
}

747
void
748
gimp_image_resize (GimpImage *gimage, 
749 750 751 752
		   gint       new_width, 
		   gint       new_height,
		   gint       offset_x, 
		   gint       offset_y)
753
{
Michael Natterer's avatar
Michael Natterer committed
754 755 756
  GimpChannel *channel;
  GimpLayer   *layer;
  GimpLayer   *floating_layer;
757
  GList       *list;
Michael Natterer's avatar
Michael Natterer committed
758
  GList       *guide_list;
759

760
  gimp_set_busy ();
761

762
  g_assert (new_width > 0 && new_height > 0);
763 764 765 766

  /*  Get the floating layer if one exists  */
  floating_layer = gimp_image_floating_sel (gimage);

Sven Neumann's avatar
Sven Neumann committed
767
  undo_push_group_start (gimage, IMAGE_RESIZE_UNDO);
768 769 770 771 772 773 774 775 776

  /*  Relax the floating selection  */
  if (floating_layer)
    floating_sel_relax (floating_layer, TRUE);

  /*  Push the image size to the stack  */
  undo_push_gimage_mod (gimage);

  /*  Set the new width and height  */
777
  gimage->width  = new_width;
778 779 780
  gimage->height = new_height;

  /*  Resize all channels  */
781 782 783
  for (list = GIMP_LIST (gimage->channels)->list; 
       list; 
       list = g_list_next (list))
784
    {
Michael Natterer's avatar
Michael Natterer committed
785
      channel = (GimpChannel *) list->data;
786

Michael Natterer's avatar
Michael Natterer committed
787
      gimp_channel_resize (channel, new_width, new_height, offset_x, offset_y);
788 789 790 791 792 793
    }

  /*  Reposition or remove any guides  */
  guide_list = gimage->guides;
  while (guide_list)
    {
Michael Natterer's avatar
Michael Natterer committed
794
      GimpGuide *guide;
795

Michael Natterer's avatar
Michael Natterer committed
796
      guide = (GimpGuide *) guide_list->data;
Sven Neumann's avatar
Sven Neumann committed
797
      guide_list = g_list_next (guide_list);
798 799 800

      switch (guide->orientation)
	{
801
	case ORIENTATION_HORIZONTAL:
Sven Neumann's avatar
Sven Neumann committed
802
	  undo_push_guide (gimage, guide);
803 804 805 806
	  guide->position += offset_y;
	  if (guide->position < 0 || guide->position > new_height)
	    gimp_image_delete_guide (gimage, guide);
	  break;
807

808
	case ORIENTATION_VERTICAL:
Sven Neumann's avatar
Sven Neumann committed
809
	  undo_push_guide (gimage, guide);
810 811 812 813
	  guide->position += offset_x;
	  if (guide->position < 0 || guide->position > new_width)
	    gimp_image_delete_guide (gimage, guide);
	  break;
814

815
	default:
816
	  g_error ("Unknown guide orientation\n");
817
	}
818 819 820
    }

  /*  Don't forget the selection mask!  */
Michael Natterer's avatar
Michael Natterer committed
821 822
  gimp_channel_resize (gimage->selection_mask,
		       new_width, new_height, offset_x, offset_y);
823 824 825
  gimage_mask_invalidate (gimage);

  /*  Reposition all layers  */
826 827 828
  for (list = GIMP_LIST (gimage->layers)->list; 
       list; 
       list = g_list_next (list))
829
    {
830
      layer = (GimpLayer *) list->data;
831

832
      gimp_layer_translate (layer, offset_x, offset_y);
833 834 835 836 837 838 839 840 841
    }

  /*  Make sure the projection matches the gimage size  */
  gimp_image_projection_realloc (gimage);

  /*  Rigor the floating selection  */
  if (floating_layer)
    floating_sel_rigor (floating_layer, TRUE);

842 843
  undo_push_group_end (gimage);

844
  gimp_viewable_size_changed (GIMP_VIEWABLE (gimage));
845

846
  gimp_unset_busy ();
847 848 849
}

void
850
gimp_image_scale (GimpImage *gimage, 
851 852
		  gint       new_width, 
		  gint       new_height)
853
{
Michael Natterer's avatar
Michael Natterer committed
854 855 856
  GimpChannel *channel;
  GimpLayer   *layer;
  GimpLayer   *floating_layer;
857
  GList       *list;
Michael Natterer's avatar
Michael Natterer committed
858
  GSList      *remove = NULL;
859
  GSList      *slist;
Michael Natterer's avatar
Michael Natterer committed
860
  GimpGuide   *guide;
Michael Natterer's avatar
Michael Natterer committed
861 862 863 864
  gint         old_width;
  gint         old_height;
  gdouble      img_scale_w = 1.0;
  gdouble      img_scale_h = 1.0;
865

866
  if ((new_width == 0) || (new_height == 0))
867
    {
868 869
      g_message ("%s(): Scaling to zero width or height has been rejected.",
		 G_GNUC_FUNCTION);
870 871
      return;
    }
872

873
  gimp_set_busy ();
874

875 876 877
  /*  Get the floating layer if one exists  */
  floating_layer = gimp_image_floating_sel (gimage);

Sven Neumann's avatar
Sven Neumann committed
878
  undo_push_group_start (gimage, IMAGE_SCALE_UNDO);
879 880 881 882 883 884 885 886 887

  /*  Relax the floating selection  */
  if (floating_layer)
    floating_sel_relax (floating_layer, TRUE);

  /*  Push the image size to the stack  */
  undo_push_gimage_mod (gimage);

  /*  Set the new width and height  */
888 889 890

  old_width      = gimage->width;
  old_height     = gimage->height;
891
  gimage->width  = new_width;
892
  gimage->height = new_height;
893 894
  img_scale_w    = (gdouble) new_width  / (gdouble) old_width;
  img_scale_h    = (gdouble) new_height / (gdouble) old_height;
895
 
896
  /*  Scale all channels  */
897 898 899
  for (list = GIMP_LIST (gimage->channels)->list; 
       list; 
       list = g_list_next (list))
900
    {
Michael Natterer's avatar
Michael Natterer committed
901 902 903
      channel = (GimpChannel *) list->data;

      gimp_channel_scale (channel, new_width, new_height);
904 905 906
    }

  /*  Don't forget the selection mask!  */
907
  /*  if (channel_is_empty(gimage->selection_mask))
Michael Natterer's avatar
Michael Natterer committed
908
        gimp_channel_resize(gimage->selection_mask, new_width, new_height, 0, 0)
909 910
      else
  */
Michael Natterer's avatar
Michael Natterer committed
911

Michael Natterer's avatar
Michael Natterer committed
912
  gimp_channel_scale (gimage->selection_mask, new_width, new_height);
913 914 915
  gimage_mask_invalidate (gimage);

  /*  Scale all layers  */
916 917 918
  for (list = GIMP_LIST (gimage->layers)->list; 
       list; 
       list = g_list_next (list))
919
    {
920 921
      layer = (GimpLayer *) list->data;

Michael Natterer's avatar
Michael Natterer committed
922
      if (! gimp_layer_scale_by_factors (layer, img_scale_w, img_scale_h))
923
	{
924 925 926 927 928
	  /* Since 0 < img_scale_w, img_scale_h, failure due to one or more
	   * vanishing scaled layer dimensions. Implicit delete implemented
	   * here. Upstream warning implemented in resize_check_layer_scaling()
	   * [resize.c line 1295], which offers the user the chance to bail out.
	   */
929
          remove = g_slist_append (remove, layer);
930 931
        }
    }
932

Michael Natterer's avatar
Michael Natterer committed
933 934 935
  /* We defer removing layers lost to scaling until now so as not to mix
   * the operations of iterating over and removal from gimage->layers.
   */  
936
  for (slist = remove; slist; slist = g_slist_next (slist))
937
    {
938
      layer = slist->data;
939
      gimp_image_remove_layer (gimage, layer);
940
    }
941
  g_slist_free (remove);
942

943
  /*  Scale any Guides  */
944
  for (list = gimage->guides; list; list = g_list_next (list))
945
    {
Michael Natterer's avatar
Michael Natterer committed
946
      guide = (GimpGuide *) list->data;
947 948 949

      switch (guide->orientation)
	{
950
	case ORIENTATION_HORIZONTAL:
Sven Neumann's avatar
Sven Neumann committed
951
	  undo_push_guide (gimage, guide);
952 953
	  guide->position = (guide->position * new_height) / old_height;
	  break;
954
	case ORIENTATION_VERTICAL:
Sven Neumann's avatar
Sven Neumann committed
955
	  undo_push_guide (gimage, guide);
956 957 958 959 960 961
	  guide->position = (guide->position * new_width) / old_width;
	  break;
	default:
	  g_error("Unknown guide orientation II.\n");
	}
    }
962

963 964 965 966 967 968 969
  /*  Make sure the projection matches the gimage size  */
  gimp_image_projection_realloc (gimage);

  /*  Rigor the floating selection  */
  if (floating_layer)
    floating_sel_rigor (floating_layer, TRUE);

970 971
  undo_push_group_end (gimage);

972
  gimp_viewable_size_changed (GIMP_VIEWABLE (gimage));
973

974
  gimp_unset_busy ();
975 976
}

Michael Natterer's avatar
Michael Natterer committed
977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013
/**
 * gimp_image_check_scaling:
 * @gimage:     A #GimpImage.
 * @new_width:  The new width.
 * @new_height: The new height.
 * 
 * Inventory the layer list in gimage and return #TRUE if, after
 * scaling, they all retain positive x and y pixel dimensions.
 * 
 * Return value: #TRUE if scaling the image will shrink none of it's
 *               layers completely away.
 **/
gboolean 
gimp_image_check_scaling (const GimpImage *gimage,
			  gint             new_width,
			  gint             new_height)
{
  GList *list;

  g_return_val_if_fail (gimage != NULL, FALSE);
  g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE);

  for (list = GIMP_LIST (gimage->layers)->list;
       list;
       list = g_list_next (list))
    {
      GimpLayer *layer;

      layer = (GimpLayer *) list->data;

      if (! gimp_layer_check_scaling (layer, new_width, new_height))
	return FALSE;
    }

  return TRUE;
}