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"

38
#include "gimp.h"
39
#include "gimpcontext.h"
Michael Natterer's avatar
Michael Natterer committed
40
#include "gimpcoreconfig.h"
41
#include "gimpimage.h"
Michael Natterer's avatar
Michael Natterer committed
42
#include "gimpimage-colorhash.h"
43
#include "gimpimage-mask.h"
44
#include "gimpimage-undo.h"
45
#include "gimplayer.h"
46
#include "gimplayermask.h"
47
#include "gimplist.h"
48
#include "gimpmarshal.h"
Manish Singh's avatar
Manish Singh committed
49
#include "gimpparasite.h"
50
#include "gimpparasitelist.h"
51
#include "gimpundostack.h"
52
53
54

#include "floating_sel.h"
#include "gdisplay.h"
55
#include "path.h"
56
#include "undo.h"
57

58
59
#include "libgimp/gimpintl.h"

60

61
62
63
64
65
66
67
#ifdef DEBUG
#define TRC(x) printf x
#else
#define TRC(x)
#endif


68
/*  Local function declarations  */
69
70
71
72
73
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);
74
static void     gimp_image_size_changed          (GimpViewable   *viewable);
Michael Natterer's avatar
Michael Natterer committed
75
76
static void     gimp_image_real_colormap_changed (GimpImage      *gimage,
						  gint            ncol);
77
static TempBuf *gimp_image_get_preview           (GimpViewable   *gimage,
78
79
						  gint            width,
						  gint            height);
80
static TempBuf *gimp_image_get_new_preview       (GimpViewable   *viewable,
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
						  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);
107
108
109
110
111
static void     gimp_image_construct             (GimpImage      *gimage,
						  gint            x,
						  gint            y,
						  gint            w,
						  gint            h);
112
113

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

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

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

173
  CLEAN,
174
  DIRTY,
Michael Natterer's avatar
Michael Natterer committed
175
  UPDATE,
176
  COLORMAP_CHANGED,
177
  UNDO_EVENT,
178
179
  LAST_SIGNAL
};
180

181

182
183
static guint gimp_image_signals[LAST_SIGNAL] = { 0 };

184
static GimpViewableClass *parent_class = NULL;
185

186

187
GType 
188
189
gimp_image_get_type (void) 
{
190
  static GType image_type = 0;
191
192
193

  if (! image_type)
    {
194
      static const GTypeInfo image_info =
195
196
      {
        sizeof (GimpImageClass),
197
198
199
200
201
202
203
204
        NULL,           /* base_init */
        NULL,           /* base_finalize */
        (GClassInitFunc) gimp_image_class_init,
        NULL,           /* class_finalize */
        NULL,           /* class_data */
        sizeof (GimpImage),
        0,              /* n_preallocs */
        (GInstanceInitFunc) gimp_image_init,
205
206
      };

207
208
209
      image_type = g_type_register_static (GIMP_TYPE_VIEWABLE,
					   "GimpImage",
					   &image_info, 0);
210
211
212
213
214
    }

  return image_type;
}

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

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

226
  parent_class = g_type_class_peek_parent (klass);
227

228
  gimp_image_signals[MODE_CHANGED] =
229
230
231
232
233
234
235
    g_signal_new ("mode_changed",
		  G_TYPE_FROM_CLASS (klass),
		  G_SIGNAL_RUN_FIRST,
		  G_STRUCT_OFFSET (GimpImageClass, mode_changed),
		  NULL, NULL,
		  g_cclosure_marshal_VOID__VOID,
		  G_TYPE_NONE, 0);
236

237
  gimp_image_signals[ALPHA_CHANGED] =
238
239
240
241
242
243
244
    g_signal_new ("alpha_changed",
		  G_TYPE_FROM_CLASS (klass),
		  G_SIGNAL_RUN_FIRST,
		  G_STRUCT_OFFSET (GimpImageClass, alpha_changed),
		  NULL, NULL,
		  g_cclosure_marshal_VOID__VOID,
		  G_TYPE_NONE, 0);
245

246
  gimp_image_signals[FLOATING_SELECTION_CHANGED] =
247
248
249
250
251
252
253
    g_signal_new ("floating_selection_changed",
		  G_TYPE_FROM_CLASS (klass),
		  G_SIGNAL_RUN_FIRST,
		  G_STRUCT_OFFSET (GimpImageClass, floating_selection_changed),
		  NULL, NULL,
		  g_cclosure_marshal_VOID__VOID,
		  G_TYPE_NONE, 0);
254

255
  gimp_image_signals[ACTIVE_LAYER_CHANGED] =
256
257
258
259
260
261
262
    g_signal_new ("active_layer_changed",
		  G_TYPE_FROM_CLASS (klass),
		  G_SIGNAL_RUN_FIRST,
		  G_STRUCT_OFFSET (GimpImageClass, active_layer_changed),
		  NULL, NULL,
		  g_cclosure_marshal_VOID__VOID,
		  G_TYPE_NONE, 0);
263
264

  gimp_image_signals[ACTIVE_CHANNEL_CHANGED] =
265
266
267
268
269
270
271
    g_signal_new ("active_channel_changed",
		  G_TYPE_FROM_CLASS (klass),
		  G_SIGNAL_RUN_FIRST,
		  G_STRUCT_OFFSET (GimpImageClass, active_channel_changed),
		  NULL, NULL,
		  g_cclosure_marshal_VOID__VOID,
		  G_TYPE_NONE, 0);
272

273
  gimp_image_signals[COMPONENT_VISIBILITY_CHANGED] =
274
275
276
277
278
279
280
281
    g_signal_new ("component_visibility_changed",
		  G_TYPE_FROM_CLASS (klass),
		  G_SIGNAL_RUN_FIRST,
		  G_STRUCT_OFFSET (GimpImageClass, component_visibility_changed),
		  NULL, NULL,
		  g_cclosure_marshal_VOID__INT,
		  G_TYPE_NONE, 1,
		  G_TYPE_INT);
282
283

  gimp_image_signals[COMPONENT_ACTIVE_CHANGED] =
284
285
286
287
288
289
290
291
    g_signal_new ("component_active_changed",
		  G_TYPE_FROM_CLASS (klass),
		  G_SIGNAL_RUN_FIRST,
		  G_STRUCT_OFFSET (GimpImageClass, component_active_changed),
		  NULL, NULL,
		  g_cclosure_marshal_VOID__INT,
		  G_TYPE_NONE, 1,
		  G_TYPE_INT);
292

293
  gimp_image_signals[MASK_CHANGED] =
294
295
296
297
298
299
300
    g_signal_new ("mask_changed",
		  G_TYPE_FROM_CLASS (klass),
		  G_SIGNAL_RUN_FIRST,
		  G_STRUCT_OFFSET (GimpImageClass, mask_changed),
		  NULL, NULL,
		  g_cclosure_marshal_VOID__VOID,
		  G_TYPE_NONE, 0);
301

302
  gimp_image_signals[CLEAN] =
303
304
305
306
307
308
309
    g_signal_new ("clean",
		  G_TYPE_FROM_CLASS (klass),
		  G_SIGNAL_RUN_FIRST,
		  G_STRUCT_OFFSET (GimpImageClass, clean),
		  NULL, NULL,
		  g_cclosure_marshal_VOID__VOID,
		  G_TYPE_NONE, 0);
310

311
  gimp_image_signals[DIRTY] =
312
313
314
315
316
317
318
    g_signal_new ("dirty",
		  G_TYPE_FROM_CLASS (klass),
		  G_SIGNAL_RUN_FIRST,
		  G_STRUCT_OFFSET (GimpImageClass, dirty),
		  NULL, NULL,
		  g_cclosure_marshal_VOID__VOID,
		  G_TYPE_NONE, 0);
319

Michael Natterer's avatar
Michael Natterer committed
320
  gimp_image_signals[UPDATE] =
321
322
323
324
325
326
327
328
329
330
331
    g_signal_new ("update",
		  G_TYPE_FROM_CLASS (klass),
		  G_SIGNAL_RUN_FIRST,
		  G_STRUCT_OFFSET (GimpImageClass, update),
		  NULL, NULL,
		  gimp_cclosure_marshal_VOID__INT_INT_INT_INT,
		  G_TYPE_NONE, 4,
		  G_TYPE_INT,
		  G_TYPE_INT,
		  G_TYPE_INT,
		  G_TYPE_INT);
332

333
  gimp_image_signals[COLORMAP_CHANGED] =
334
335
336
337
338
339
340
341
    g_signal_new ("colormap_changed",
		  G_TYPE_FROM_CLASS (klass),
		  G_SIGNAL_RUN_FIRST,
		  G_STRUCT_OFFSET (GimpImageClass, colormap_changed),
		  NULL, NULL,
		  g_cclosure_marshal_VOID__INT,
		  G_TYPE_NONE, 1,
		  G_TYPE_INT);
342

343
  gimp_image_signals[UNDO_EVENT] = 
344
345
346
347
348
349
350
351
    g_signal_new ("undo_event",
		  G_TYPE_FROM_CLASS (klass),
		  G_SIGNAL_RUN_FIRST,
		  G_STRUCT_OFFSET (GimpImageClass, undo_event),
		  NULL, NULL,
		  g_cclosure_marshal_VOID__INT,
		  G_TYPE_NONE, 1,
		  G_TYPE_INT);
352

353
  object_class->destroy               = gimp_image_destroy;
354

355
  gimp_object_class->name_changed     = gimp_image_name_changed;
356

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

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

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

  gimp_image_color_hash_init ();
380
381
382
383
384
}


/* static functions */

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

390
391
392
393
  gimage->save_proc             = NULL;

  gimage->width                 = 0;
  gimage->height                = 0;
394
395
396
  gimage->xresolution           = 1.0;
  gimage->yresolution           = 1.0;
  gimage->unit                  = GIMP_UNIT_INCH;
397
398
  gimage->base_type             = RGB;

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

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

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

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

  gimage->shadow                = NULL;

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

416
  gimage->guides                = NULL;
417

418
419
420
421
  gimage->layers                = gimp_list_new (GIMP_TYPE_LAYER, 
						 GIMP_CONTAINER_POLICY_STRONG);
  gimage->channels              = gimp_list_new (GIMP_TYPE_CHANNEL, 
						 GIMP_CONTAINER_POLICY_STRONG);
422
  gimage->layer_stack           = NULL;
423
424
425
426
427
428

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

429
  gimage->parasites             = gimp_parasite_list_new ();
430
431
432
433
434
435
436
437
438

  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;

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

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

450
  gimage->comp_preview          = NULL;
451
  gimage->comp_preview_valid    = FALSE;
452
453
}

454
455
static void
gimp_image_destroy (GtkObject *object)
Sven Neumann's avatar
Sven Neumann committed
456
{
457
458
459
460
  GimpImage *gimage;

  gimage = GIMP_IMAGE (object);

461
462
  g_hash_table_remove (gimage->gimp->image_table,
		       GINT_TO_POINTER (gimage->ID));
463

464
465
466
467
468
  gimp_image_free_projection (gimage);
  gimp_image_free_shadow (gimage);
  
  if (gimage->cmap)
    g_free (gimage->cmap);
469
  
470
471
  g_object_unref (G_OBJECT (gimage->layers));
  g_object_unref (G_OBJECT (gimage->channels));
472
  g_slist_free (gimage->layer_stack);
473

474
  g_object_unref (G_OBJECT (gimage->selection_mask));
475

476
477
478
479
  if (gimage->comp_preview)
    temp_buf_free (gimage->comp_preview);

  if (gimage->parasites)
480
    g_object_unref (G_OBJECT (gimage->parasites));
481

Michael Natterer's avatar
Michael Natterer committed
482
483
484
  g_list_foreach (gimage->guides, (GFunc) g_free, NULL);
  g_list_free (gimage->guides);

485
486
  undo_free (gimage);

487
488
  g_object_unref (G_OBJECT (gimage->new_undo_stack));
  g_object_unref (G_OBJECT (gimage->new_redo_stack));
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
}

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;
507
    }
508
}
509

510
511
512
513
514
static void
gimp_image_invalidate_preview (GimpViewable *viewable)
{
  GimpImage *gimage;

515
516
517
  if (GIMP_VIEWABLE_CLASS (parent_class)->invalidate_preview)
    GIMP_VIEWABLE_CLASS (parent_class)->invalidate_preview (viewable);

518
519
520
  gimage = GIMP_IMAGE (viewable);

  gimage->comp_preview_valid = FALSE;
521
522
}

523
524
525
526
527
528
529
530
531
532
533
534
535
536
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
537
538
539
540
541
542
543
544
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);
}

545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
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:
567
      g_assert_not_reached ();
568
569
570
    }

  /*  allocate the new projection  */
571
572
  gimage->projection = tile_manager_new (gimage->width, gimage->height,
					 gimage->proj_bytes);
573
  tile_manager_set_user_data (gimage->projection, (void *) gimage);
574
575
576
577
578
579
580
581
582
583
584
585
586
  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
587
gimp_image_allocate_shadow (GimpImage *gimage, 
588
589
590
			    gint       width, 
			    gint       height, 
			    gint       bpp)
591
592
593
594
595
596
597
598
599
{
  /*  allocate the new projection  */
  gimage->shadow = tile_manager_new (width, height, bpp);
}


/* function definitions */

GimpImage *
600
601
gimp_image_new (Gimp              *gimp,
		gint               width,
602
603
		gint               height,
		GimpImageBaseType  base_type)
604
{
605
606
607
608
609
610
611
  GimpImage *gimage;
  gint       i;

  g_return_val_if_fail (gimp != NULL, NULL);
  g_return_val_if_fail (GIMP_IS_GIMP (gimp), NULL);

  gimage = GIMP_IMAGE (gtk_type_new (GIMP_TYPE_IMAGE));
612

613
614
615
616
617
618
619
620
621
622
623
624
625
626
  gimage->gimp        = gimp;
  gimage->ID          = gimp->next_image_ID++;

  g_hash_table_insert (gimp->image_table,
		       GINT_TO_POINTER (gimage->ID),
		       (gpointer) gimage);

  gimage->width       = width;
  gimage->height      = height;
  gimage->base_type   = base_type;

  gimage->xresolution = gimp->config->default_xresolution;
  gimage->yresolution = gimp->config->default_yresolution;
  gimage->unit        = gimp->config->default_units;
627
628
629
630
631
632
633
634
635

  switch (base_type)
    {
    case RGB:
    case GRAY:
      break;
    case INDEXED:
      /* always allocate 256 colors for the colormap */
      gimage->num_cols = 0;
636
      gimage->cmap     = (guchar *) g_malloc0 (COLORMAP_SIZE);
637
638
639
640
641
642
643
644
      break;
    default:
      break;
    }

  /*  set all color channels visible and active  */
  for (i = 0; i < MAX_CHANNELS; i++)
    {
645
646
      gimage->visible[i] = TRUE;
      gimage->active[i]  = TRUE;
647
648
649
    }

  /* create the selection mask */
Michael Natterer's avatar
Michael Natterer committed
650
651
652
  gimage->selection_mask = gimp_channel_new_mask (gimage,
						  gimage->width,
						  gimage->height);
653
654
655
656
657


  return gimage;
}

658
659
660
661
662
663
664
665
666
667
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 *
668
669
gimp_image_get_by_ID (Gimp *gimp,
		      gint  image_id)
670
{
671
672
673
674
  g_return_val_if_fail (gimp != NULL, NULL);
  g_return_val_if_fail (GIMP_IS_GIMP (gimp), NULL);

  if (gimp->image_table == NULL)
675
676
    return NULL;

677
  return (GimpImage *) g_hash_table_lookup (gimp->image_table, 
678
679
680
					    GINT_TO_POINTER (image_id));
}

681
void
682
683
gimp_image_set_filename (GimpImage   *gimage,
			 const gchar *filename)
684
{
685
686
  gimp_object_set_name (GIMP_OBJECT (gimage), filename);
}
687

688
void
689
gimp_image_set_resolution (GimpImage *gimage,
690
691
			   gdouble    xresolution,
			   gdouble    yresolution)
692
{
693
694
695
696
697
  /* 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;

698
699
700
  /* 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)
701
702
    return;

703
  undo_push_resolution (gimage);
704

705
706
  gimage->xresolution = xresolution;
  gimage->yresolution = yresolution;
707
708
709

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

712
void
713
714
715
gimp_image_get_resolution (const GimpImage *gimage,
			   gdouble         *xresolution,
			   gdouble         *yresolution)
716
{
717
718
  g_return_if_fail (xresolution && yresolution);

719
720
  *xresolution = gimage->xresolution;
  *yresolution = gimage->yresolution;
721
722
}

723
724
void
gimp_image_set_unit (GimpImage *gimage,
725
		     GimpUnit   unit)
726
{
727
728
  undo_push_resolution (gimage);

729
730
731
  gimage->unit = unit;
}

732
GimpUnit
733
gimp_image_get_unit (const GimpImage *gimage)
734
735
736
737
{
  return gimage->unit;
}

738
void
Sven Neumann's avatar
Sven Neumann committed
739
740
gimp_image_set_save_proc (GimpImage     *gimage, 
			  PlugInProcDef *proc)
741
742
743
744
745
{
  gimage->save_proc = proc;
}

PlugInProcDef *
746
gimp_image_get_save_proc (const GimpImage *gimage)
747
748
749
{
  return gimage->save_proc;
}
750

751
752
753
754
755
756
757
758
759
760
761
762
gint
gimp_image_get_width (const GimpImage *gimage)
{
  return gimage->width;
}

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

763
void
764
gimp_image_resize (GimpImage *gimage, 
765
766
767
768
		   gint       new_width, 
		   gint       new_height,
		   gint       offset_x, 
		   gint       offset_y)
769
{
Michael Natterer's avatar
Michael Natterer committed
770
771
772
  GimpChannel *channel;
  GimpLayer   *layer;
  GimpLayer   *floating_layer;
773
  GList       *list;
Michael Natterer's avatar
Michael Natterer committed
774
  GList       *guide_list;
775

776
  gimp_set_busy (gimage->gimp);
777

778
  g_assert (new_width > 0 && new_height > 0);
779
780
781
782

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

Sven Neumann's avatar
Sven Neumann committed
783
  undo_push_group_start (gimage, IMAGE_RESIZE_UNDO);
784
785
786
787
788
789
790
791
792

  /*  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  */
793
  gimage->width  = new_width;
794
795
796
  gimage->height = new_height;

  /*  Resize all channels  */
797
798
799
  for (list = GIMP_LIST (gimage->channels)->list; 
       list; 
       list = g_list_next (list))
800
    {
Michael Natterer's avatar
Michael Natterer committed
801
      channel = (GimpChannel *) list->data;
802

Michael Natterer's avatar
Michael Natterer committed
803
      gimp_channel_resize (channel, new_width, new_height, offset_x, offset_y);
804
805
806
807
808
809
    }

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

Michael Natterer's avatar
Michael Natterer committed
812
      guide = (GimpGuide *) guide_list->data;
Sven Neumann's avatar
Sven Neumann committed
813
      guide_list = g_list_next (guide_list);
814
815
816

      switch (guide->orientation)
	{
817
	case ORIENTATION_HORIZONTAL:
Sven Neumann's avatar
Sven Neumann committed
818
	  undo_push_guide (gimage, guide);
819
820
821
822
	  guide->position += offset_y;
	  if (guide->position < 0 || guide->position > new_height)
	    gimp_image_delete_guide (gimage, guide);
	  break;
823

824
	case ORIENTATION_VERTICAL:
Sven Neumann's avatar
Sven Neumann committed
825
	  undo_push_guide (gimage, guide);
826
827
828
829
	  guide->position += offset_x;
	  if (guide->position < 0 || guide->position > new_width)
	    gimp_image_delete_guide (gimage, guide);
	  break;
830

831
	default:
832
	  g_error ("Unknown guide orientation\n");
833
	}
834
835
836
    }

  /*  Don't forget the selection mask!  */
Michael Natterer's avatar
Michael Natterer committed
837
838
  gimp_channel_resize (gimage->selection_mask,
		       new_width, new_height, offset_x, offset_y);
839
840
841
  gimage_mask_invalidate (gimage);

  /*  Reposition all layers  */
842
843
844
  for (list = GIMP_LIST (gimage->layers)->list; 
       list; 
       list = g_list_next (list))
845
    {
846
      layer = (GimpLayer *) list->data;
847

848
      gimp_layer_translate (layer, offset_x, offset_y);
849
850
851
852
853
854
855
856
857
    }

  /*  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);

858
859
  undo_push_group_end (gimage);

860
  gimp_viewable_size_changed (GIMP_VIEWABLE (gimage));
861

862
  gimp_unset_busy (gimage->gimp);
863
864
865
}

void
866
gimp_image_scale (GimpImage *gimage, 
867
868
		  gint       new_width, 
		  gint       new_height)
869
{
Michael Natterer's avatar
Michael Natterer committed
870
871
872
  GimpChannel *channel;
  GimpLayer   *layer;
  GimpLayer   *floating_layer;
873
  GList       *list;
Michael Natterer's avatar
Michael Natterer committed
874
  GSList      *remove = NULL;
875
  GSList      *slist;
Michael Natterer's avatar
Michael Natterer committed
876
  GimpGuide   *guide;
Michael Natterer's avatar
Michael Natterer committed
877
878
879
880
  gint         old_width;
  gint         old_height;
  gdouble      img_scale_w = 1.0;
  gdouble      img_scale_h = 1.0;
881

882
  if ((new_width == 0) || (new_height == 0))
883
    {
884
885
      g_message ("%s(): Scaling to zero width or height has been rejected.",
		 G_GNUC_FUNCTION);
886
887
      return;
    }
888

889
  gimp_set_busy (gimage->gimp);
890

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

Sven Neumann's avatar
Sven Neumann committed
894
  undo_push_group_start (gimage, IMAGE_SCALE_UNDO);
895
896
897
898
899
900
901
902
903

  /*  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  */
904
905
906

  old_width      = gimage->width;
  old_height     = gimage->height;
907
  gimage->width  = new_width;
908
  gimage->height = new_height;
909
910
  img_scale_w    = (gdouble) new_width  / (gdouble) old_width;
  img_scale_h    = (gdouble) new_height / (gdouble) old_height;
911
 
912
  /*  Scale all channels  */
913
914
915
  for (list = GIMP_LIST (gimage->channels)->list; 
       list; 
       list = g_list_next (list))
916
    {
Michael Natterer's avatar
Michael Natterer committed
917
918
919
      channel = (GimpChannel *) list->data;

      gimp_channel_scale (channel, new_width, new_height);
920
921
922
    }

  /*  Don't forget the selection mask!  */
923
  /*  if (channel_is_empty(gimage->selection_mask))
Michael Natterer's avatar
Michael Natterer committed
924
        gimp_channel_resize(gimage->selection_mask, new_width, new_height, 0, 0)
925
926
      else
  */
Michael Natterer's avatar
Michael Natterer committed
927

Michael Natterer's avatar
Michael Natterer committed
928
  gimp_channel_scale (gimage->selection_mask, new_width, new_height);
929
930
931
  gimage_mask_invalidate (gimage);

  /*  Scale all layers  */
932
933
934
  for (list = GIMP_LIST (gimage->layers)->list; 
       list; 
       list = g_list_next (list))
935
    {
936
937
      layer = (GimpLayer *) list->data;

Michael Natterer's avatar
Michael Natterer committed
938
      if (! gimp_layer_scale_by_factors (layer, img_scale_w, img_scale_h))
939
	{
940
941
942
943
944
	  /* 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.
	   */
945
          remove = g_slist_append (remove, layer);
946
947
        }
    }
948

Michael Natterer's avatar
Michael Natterer committed
949
950
951
  /* We defer removing layers lost to scaling until now so as not to mix
   * the operations of iterating over and removal from gimage->layers.
   */  
952
  for (slist = remove; slist; slist = g_slist_next (slist))
953
    {
954
      layer = slist->data;
955
      gimp_image_remove_layer (gimage, layer);
956
    }
957
  g_slist_free (remove);
958

959
  /*  Scale any Guides  */
960
  for (list = gimage->guides; list; list = g_list_next (list))
961
    {
Michael Natterer's avatar
Michael Natterer committed
962
      guide = (GimpGuide *) list->data;
963
964
965

      switch (guide->orientation)
	{
966
	case ORIENTATION_HORIZONTAL:
Sven Neumann's avatar
Sven Neumann committed
967
	  undo_push_guide (gimage, guide);
968
969
	  guide->position = (guide->position * new_height) / old_height;
	  break;
970
	case ORIENTATION_VERTICAL:
Sven Neumann's avatar
Sven Neumann committed
971
	  undo_push_guide (gimage, guide);
972
973
974
975
976
977
	  guide->position = (guide->position * new_width) / old_width;
	  break;
	default:
	  g_error("Unknown guide orientation II.\n");
	}
    }
978

979
980
981
982
983
984
985
  /*  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);

986
987
  undo_push_group_end (gimage);

988
  gimp_viewable_size_changed (GIMP_VIEWABLE (gimage));
989

990
  gimp_unset_busy (gimage->gimp);
991
992
}

Michael Natterer's avatar
Michael Natterer committed
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
/**
 * 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;
}

1030
TileManager *
1031
gimp_image_shadow (GimpImage *gimage, 
1032
1033
1034
		   gint       width, 
		   gint       height, 
		   gint       bpp)
1035
1036
{
  if (gimage->shadow &&
1037
1038
1039
      ((width != tile_manager_width (gimage->shadow)) ||
       (height != tile_manager_height (gimage->shadow)) ||
       (bpp != tile_manager_bpp (gimage->shadow))))
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
    gimp_image_free_shadow (gimage);
  else if (gimage->shadow)
    return gimage->shadow;

  gimp_image_allocate_shadow (gimage, width, height, bpp);

  return gimage->shadow;
}

void
gimp_image_free_shadow (GimpImage *gimage)
{
  /*  Free the shadow buffer from the specified gimage if it exists  */
  if (gimage->shadow)
    tile_manager_destroy (gimage->shadow);

  gimage->shadow = NULL;
}

void
Michael Natterer's avatar