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);
Michael Natterer's avatar
Michael Natterer committed
77 78
static void     gimp_image_real_colormap_changed (GimpImage      *gimage,
						  gint            ncol);
79
static TempBuf *gimp_image_get_preview           (GimpViewable   *gimage,
80 81
						  gint            width,
						  gint            height);
82
static TempBuf *gimp_image_get_new_preview       (GimpViewable   *viewable,
83 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
						  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);
109 110

/*  projection functions  */
111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133
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);
134 135 136 137

/*
 *  Global variables
 */
138
gint valid_combinations[][MAX_CHANNELS + 1] =
139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158
{
  /* 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
 */

159 160
enum
{
161
  MODE_CHANGED,
162
  ALPHA_CHANGED,
163
  SIZE_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[SIZE_CHANGED] =
    gtk_signal_new ("size_changed",
                    GTK_RUN_FIRST,
                    object_class->type,
                    GTK_SIGNAL_OFFSET (GimpImageClass,
				       size_changed),
                    gtk_signal_default_marshaller,
                    GTK_TYPE_NONE, 0);

254 255 256 257 258 259 260 261 262
  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);

263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280
  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);

281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300
  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);

301 302 303 304 305 306 307 308 309
  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);

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

319
  gimp_image_signals[DIRTY] =
320 321 322 323 324 325 326 327
    gtk_signal_new ("dirty",
                    GTK_RUN_FIRST,
                    object_class->type,
                    GTK_SIGNAL_OFFSET (GimpImageClass,
				       dirty),
                    gtk_signal_default_marshaller,
                    GTK_TYPE_NONE, 0);

328
  gimp_image_signals[REPAINT] =
329 330 331 332 333 334 335 336 337 338 339 340
    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);

341
  gimp_image_signals[COLORMAP_CHANGED] =
342 343 344 345 346 347 348 349 350
    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);

351
  gimp_image_signals[UNDO_EVENT] = 
352 353 354 355 356 357 358 359
    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);
360

361
  gtk_object_class_add_signals (object_class, gimp_image_signals, LAST_SIGNAL);
362

363
  object_class->destroy               = gimp_image_destroy;
364

365
  gimp_object_class->name_changed     = gimp_image_name_changed;
366

367 368 369
  viewable_class->invalidate_preview  = gimp_image_invalidate_preview;
  viewable_class->get_preview         = gimp_image_get_preview;
  viewable_class->get_new_preview     = gimp_image_get_new_preview;
370

371
  klass->mode_changed                 = NULL;
372
  klass->alpha_changed                = NULL;
373
  klass->size_changed                 = NULL;
374
  klass->floating_selection_changed   = NULL;
375 376 377 378
  klass->active_layer_changed         = NULL;
  klass->active_channel_changed       = NULL;
  klass->component_visibility_changed = NULL;
  klass->component_active_changed     = NULL;
379
  klass->mask_changed                 = NULL;
380

381 382 383
  klass->clean                        = NULL;
  klass->dirty                        = NULL;
  klass->repaint                      = NULL;
Michael Natterer's avatar
Michael Natterer committed
384
  klass->colormap_changed             = gimp_image_real_colormap_changed;
385 386 387
  klass->undo_event                   = NULL;
  klass->undo                         = gimp_image_undo;
  klass->redo                         = gimp_image_redo;
Michael Natterer's avatar
Michael Natterer committed
388 389

  gimp_image_color_hash_init ();
390 391 392 393 394
}


/* static functions */

Sven Neumann's avatar
Sven Neumann committed
395 396
static void 
gimp_image_init (GimpImage *gimage)
397
{
398 399
  gimage->ID                    = global_image_ID++;

400 401 402 403
  gimage->save_proc             = NULL;

  gimage->width                 = 0;
  gimage->height                = 0;
404 405 406
  gimage->xresolution           = gimprc.default_xresolution;
  gimage->yresolution           = gimprc.default_yresolution;
  gimage->unit                  = gimprc.default_units;
407 408
  gimage->base_type             = RGB;

409
  gimage->cmap                  = NULL;
410 411
  gimage->num_cols              = 0;

412
  gimage->dirty                 = 1;
413
  gimage->undo_on               = TRUE;
414 415 416 417

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

418
  gimage->tattoo_state          = 0;
419 420 421 422 423

  gimage->shadow                = NULL;

  gimage->construct_flag        = -1;
  gimage->proj_type             = RGBA_GIMAGE;
424
  gimage->projection            = NULL;
425

426
  gimage->guides                = NULL;
427

428 429 430 431
  gimage->layers                = gimp_list_new (GIMP_TYPE_LAYER, 
						 GIMP_CONTAINER_POLICY_STRONG);
  gimage->channels              = gimp_list_new (GIMP_TYPE_CHANNEL, 
						 GIMP_CONTAINER_POLICY_STRONG);
432
  gimage->layer_stack           = NULL;
433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448

  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;

449 450 451 452
  gimage->undo_stack            = NULL;
  gimage->redo_stack            = NULL;
  gimage->undo_bytes            = 0;
  gimage->undo_levels           = 0;
453
  gimage->group_count           = 0;
454
  gimage->pushing_undo_group    = UNDO_NULL;
455 456
  gimage->undo_history          = NULL;

457 458 459
  gimage->new_undo_stack        = gimp_undo_stack_new (gimage);
  gimage->new_redo_stack        = gimp_undo_stack_new (gimage);

460
  gimage->comp_preview          = NULL;
461
  gimage->comp_preview_valid    = FALSE;
462 463 464 465 466 467 468

  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);
469 470
}

471 472
static void
gimp_image_destroy (GtkObject *object)
Sven Neumann's avatar
Sven Neumann committed
473
{
474 475 476 477 478
  GimpImage *gimage;

  gimage = GIMP_IMAGE (object);

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

480 481 482 483 484
  gimp_image_free_projection (gimage);
  gimp_image_free_shadow (gimage);
  
  if (gimage->cmap)
    g_free (gimage->cmap);
485 486 487 488
  
  gtk_object_unref (GTK_OBJECT (gimage->layers));
  gtk_object_unref (GTK_OBJECT (gimage->channels));
  g_slist_free (gimage->layer_stack);
489 490

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

492 493 494 495 496
  if (gimage->comp_preview)
    temp_buf_free (gimage->comp_preview);

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

Michael Natterer's avatar
Michael Natterer committed
498 499 500
  g_list_foreach (gimage->guides, (GFunc) g_free, NULL);
  g_list_free (gimage->guides);

501 502
  gtk_object_unref (GTK_OBJECT (gimage->new_undo_stack));
  gtk_object_unref (GTK_OBJECT (gimage->new_redo_stack));
503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520
}

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;
521
    }
522
}
523

524 525 526 527 528 529
static void
gimp_image_invalidate_preview (GimpViewable *viewable)
{
  GimpImage *gimage;
  GimpLayer *layer;

530 531 532
  if (GIMP_VIEWABLE_CLASS (parent_class)->invalidate_preview)
    GIMP_VIEWABLE_CLASS (parent_class)->invalidate_preview (viewable);

533 534 535 536 537 538 539
  gimage = GIMP_IMAGE (viewable);

  /*  Invalidate the floating sel if it exists  */
  if ((layer = gimp_image_floating_sel (gimage)))
    floating_sel_invalidate (layer);

  gimage->comp_preview_valid = FALSE;
540 541
}

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 844
  undo_push_group_end (gimage);

  gimp_image_size_changed (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 972
  undo_push_group_end (gimage);

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

1014
TileManager *
1015
gimp_image_shadow (GimpImage *gimage, 
1016 1017