film.c 44.3 KB
Newer Older
Elliot Lee's avatar
Elliot Lee committed
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
 * Film plug-in (C) 1997 Peter Kirchgessner
 * e-mail: pkirchg@aol.com, WWW: http://members.aol.com/pkirchg
 *
 * 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
18
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
Elliot Lee's avatar
Elliot Lee committed
19 20 21 22 23 24
 */

/*
 * This plug-in generates a film roll with several images
 */

25
static char ident[] = "@(#) GIMP Film plug-in v1.04 1999-10-08";
Elliot Lee's avatar
Elliot Lee committed
26

27 28
#include "config.h"

Elliot Lee's avatar
Elliot Lee committed
29 30 31
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
32

33
#include <gtk/gtk.h>
34

35 36
#include <libgimp/gimp.h>
#include <libgimp/gimpui.h>
Elliot Lee's avatar
Elliot Lee committed
37

38
#include "libgimp/stdplugins-intl.h"
Elliot Lee's avatar
Elliot Lee committed
39

40

41 42 43 44
/* Maximum number of pictures per film */
#define MAX_FILM_PICTURES   64
#define COLOR_BUTTON_WIDTH  50
#define COLOR_BUTTON_HEIGHT 20
Elliot Lee's avatar
Elliot Lee committed
45

46 47
#define FONT_LEN            256

Elliot Lee's avatar
Elliot Lee committed
48 49
/* Define how the plug-in works. Values marked (r) are with regard */
/* to film_height (i.e. it should be a value from 0.0 to 1.0) */
50 51 52
typedef struct
{
  gint     film_height;           /* height of the film */
Sven Neumann's avatar
Sven Neumann committed
53
  GimpRGB  film_color;            /* color of film */
54 55 56 57 58 59 60 61
  gdouble  picture_height;        /* height of picture (r) */
  gdouble  picture_space;         /* space between pictures (r) */
  gdouble  hole_offset;           /* distance from hole to edge of film (r) */
  gdouble  hole_width;            /* width of hole (r) */
  gdouble  hole_height;           /* height of holes (r) */
  gdouble  hole_space;            /* distance of holes (r) */
  gdouble  number_height;         /* height of picture numbering (r) */
  gint     number_start;          /* number for first picture */
Sven Neumann's avatar
Sven Neumann committed
62
  GimpRGB  number_color;          /* color of number */
63
  gchar    number_font[FONT_LEN]; /* font family to use for numbering */
64 65 66 67
  gint     number_pos[2];         /* flags where to draw numbers (top/bottom) */
  gint     keep_height;           /* flag if to keep max. image height */
  gint     num_images;            /* number of images */
  gint32   image[MAX_FILM_PICTURES]; /* list of image IDs */
Elliot Lee's avatar
Elliot Lee committed
68 69 70 71 72
} FilmVals;

/* Data to use for the dialog */
typedef struct
{
73 74 75
  GtkObject    *advanced_adj[7];
  GtkTreeModel *image_list_all;
  GtkTreeModel *image_list_film;
Elliot Lee's avatar
Elliot Lee committed
76 77 78
} FilmInterface;


79 80 81
/* Declare local functions
 */
static void      query  (void);
82 83 84 85 86
static void      run    (const gchar      *name,
			 gint              nparams,
			 const GimpParam  *param,
			 gint             *nreturn_vals,
			 GimpParam       **return_vals);
87

Elliot Lee's avatar
Elliot Lee committed
88

89
static gint32    create_new_image   (const gchar    *filename,
90 91
				     guint           width,
				     guint           height,
Sven Neumann's avatar
Sven Neumann committed
92
				     GimpImageType   gdtype,
93
				     gint32         *layer_ID,
94 95
				     GimpDrawable  **drawable,
				     GimpPixelRgn   *pixel_rgn);
Elliot Lee's avatar
Elliot Lee committed
96

97
static gchar   * compose_image_name (gint32          image_ID);
Elliot Lee's avatar
Elliot Lee committed
98

99
static gint32    film               (void);
Elliot Lee's avatar
Elliot Lee committed
100

101
static gboolean  check_filmvals     (void);
Elliot Lee's avatar
Elliot Lee committed
102

103
static void      convert_to_rgb     (GimpDrawable   *srcdrawable,
104 105 106
				     gint            numpix,
				     guchar         *src,
				     guchar         *dst);
Elliot Lee's avatar
Elliot Lee committed
107

108 109
static void      set_pixels         (gint            numpix,
				     guchar         *dst,
Sven Neumann's avatar
Sven Neumann committed
110
				     GimpRGB        *color);
Elliot Lee's avatar
Elliot Lee committed
111

112
static gboolean  scale_layer        (gint32          src_layer,
113 114 115 116 117 118 119 120 121
				     gint            src_x0,
				     gint            src_y0,
				     gint            src_width,
				     gint            src_height,
				     gint32          dst_layer,
				     gint            dst_x0,
				     gint            dst_y0,
				     gint            dst_width,
				     gint            dst_height);
Elliot Lee's avatar
Elliot Lee committed
122

123 124
static guchar  * create_hole_rgb    (gint            width,
				     gint            height);
Elliot Lee's avatar
Elliot Lee committed
125

126
static void      draw_hole_rgb      (GimpDrawable   *drw,
127 128 129 130 131
				     gint            x,
				     gint            y,
				     gint            width,
				     gint            height,
				     guchar         *hole);
Elliot Lee's avatar
Elliot Lee committed
132

133 134 135 136 137
static void      draw_number        (gint32          layer_ID,
				     gint            num,
				     gint            x,
				     gint            y,
				     gint            height);
Elliot Lee's avatar
Elliot Lee committed
138 139


140 141 142 143
static void        add_list_item_callback (GtkWidget        *widget,
					   GtkTreeSelection *sel);
static void        del_list_item_callback (GtkWidget        *widget,
					   GtkTreeSelection *sel);
Elliot Lee's avatar
Elliot Lee committed
144

145 146 147 148
static GtkTreeModel * add_image_list      (gboolean        add_box_flag,
					   gint            n,
					   gint32         *image_id,
					   GtkWidget      *hbox);
Elliot Lee's avatar
Elliot Lee committed
149

150 151 152 153 154 155
static gboolean    film_dialog               (gint32       image_ID);
static void        film_reset_callback       (GtkWidget   *widget,
                                              gpointer     data);
static void        film_font_select_callback (const gchar *name,
                                              gboolean     closing,
                                              gpointer     data);
Elliot Lee's avatar
Elliot Lee committed
156 157


Sven Neumann's avatar
Sven Neumann committed
158
GimpPlugInInfo PLUG_IN_INFO =
Elliot Lee's avatar
Elliot Lee committed
159
{
160 161 162 163 164 165 166 167 168 169 170 171 172 173
  NULL,  /* init_proc  */
  NULL,  /* quit_proc  */
  query, /* query_proc */
  run,   /* run_proc   */
};

static gdouble advanced_defaults[] =
{
  0.695,           /* Picture height */
  0.040,           /* Picture spacing */
  0.058,           /* Hole offset to edge of film */
  0.052,           /* Hole width */
  0.081,           /* Hole height */
  0.081,           /* Hole distance */
Michael Natterer's avatar
Michael Natterer committed
174
  0.052            /* Image number height */
Elliot Lee's avatar
Elliot Lee committed
175 176 177 178
};

static FilmVals filmvals =
{
179
  256,             /* Height of film */
Sven Neumann's avatar
Sven Neumann committed
180
  { 0.0, 0.0, 0.0, 1.0 }, /* Color of film */
181 182 183 184 185 186 187 188
  0.695,           /* Picture height */
  0.040,           /* Picture spacing */
  0.058,           /* Hole offset to edge of film */
  0.052,           /* Hole width */
  0.081,           /* Hole height */
  0.081,           /* Hole distance */
  0.052,           /* Image number height */
  1,               /* Start index of numbering */
Sven Neumann's avatar
Sven Neumann committed
189
  { 0.93, 0.61, 0.0, 1.0 }, /* Color of number */
190
  "Monospace",     /* Font family for numbering */
191 192 193 194
  { TRUE, TRUE },  /* Numbering on top and bottom */
  0,               /* Dont keep max. image height */
  0,               /* Number of images */
  { 0 }            /* Input image list */
Elliot Lee's avatar
Elliot Lee committed
195 196 197 198 199
};


static FilmInterface filmint =
{
200
  { NULL },   /* advanced adjustments */
201
  NULL, NULL  /* image list widgets */
Elliot Lee's avatar
Elliot Lee committed
202 203 204
};


205
static GimpRunMode run_mode;
Elliot Lee's avatar
Elliot Lee committed
206 207 208 209 210


MAIN ()

static void
211
query (void)
Elliot Lee's avatar
Elliot Lee committed
212
{
Sven Neumann's avatar
Sven Neumann committed
213
  static GimpParamDef args[] =
Elliot Lee's avatar
Elliot Lee committed
214
  {
Sven Neumann's avatar
Sven Neumann committed
215 216 217 218 219 220
    { GIMP_PDB_INT32, "run_mode", "Interactive, non-interactive" },
    { GIMP_PDB_IMAGE, "image", "Input image (only used as default image in interactive mode)" },
    { GIMP_PDB_DRAWABLE, "drawable", "Input drawable (not used)" },
    { GIMP_PDB_INT32, "film_height", "Height of film (0: fit to images)" },
    { GIMP_PDB_COLOR, "film_color", "Color of the film" },
    { GIMP_PDB_INT32, "number_start", "Start index for numbering" },
221
    { GIMP_PDB_STRING, "number_font", "Font for drawing numbers" },
Sven Neumann's avatar
Sven Neumann committed
222 223 224 225 226
    { GIMP_PDB_COLOR, "number_color", "Color for numbers" },
    { GIMP_PDB_INT32, "at_top", "Flag for drawing numbers at top of film" },
    { GIMP_PDB_INT32, "at_bottom", "Flag for drawing numbers at bottom of film" },
    { GIMP_PDB_INT32, "num_images", "Number of images to be used for film" },
    { GIMP_PDB_INT32ARRAY, "image_ids", "num_images image IDs to be used for film"}
Elliot Lee's avatar
Elliot Lee committed
227
  };
228

Sven Neumann's avatar
Sven Neumann committed
229
  static GimpParamDef return_vals[] =
Elliot Lee's avatar
Elliot Lee committed
230
  {
Sven Neumann's avatar
Sven Neumann committed
231
    { GIMP_PDB_IMAGE, "new_image", "Output image" }
Elliot Lee's avatar
Elliot Lee committed
232 233 234
  };

  gimp_install_procedure ("plug_in_film",
Marc Lehmann's avatar
Marc Lehmann committed
235 236
			  "Compose several images to a roll film",
			  "Compose several images to a roll film",
Elliot Lee's avatar
Elliot Lee committed
237
			  "Peter Kirchgessner",
238
			  "Peter Kirchgessner (peter@kirchgessner.net)",
Elliot Lee's avatar
Elliot Lee committed
239
			  "1997",
240
			  N_("_Film..."),
Elliot Lee's avatar
Elliot Lee committed
241
			  "INDEXED*, GRAY*, RGB*",
Sven Neumann's avatar
Sven Neumann committed
242
			  GIMP_PLUGIN,
243 244
			  G_N_ELEMENTS (args),
                          G_N_ELEMENTS (return_vals),
Elliot Lee's avatar
Elliot Lee committed
245
			  args, return_vals);
246 247 248

  gimp_plugin_menu_register ("plug_in_film",
                             N_("<Image>/Filters/Combine"));
Elliot Lee's avatar
Elliot Lee committed
249 250 251
}

static void
252 253 254 255 256
run (const gchar      *name,
     gint              nparams,
     const GimpParam  *param,
     gint             *nreturn_vals,
     GimpParam       **return_vals)
Elliot Lee's avatar
Elliot Lee committed
257
{
258
  static GimpParam  values[2];
Sven Neumann's avatar
Sven Neumann committed
259
  GimpPDBStatusType status = GIMP_PDB_SUCCESS;
260 261
  gint32            image_ID;
  gint              k;
Elliot Lee's avatar
Elliot Lee committed
262

263
  INIT_I18N ();
264

Elliot Lee's avatar
Elliot Lee committed
265 266 267
  run_mode = param[0].data.d_int32;

  *nreturn_vals = 2;
268
  *return_vals  = values;
Elliot Lee's avatar
Elliot Lee committed
269

270
  values[0].type          = GIMP_PDB_STATUS;
Elliot Lee's avatar
Elliot Lee committed
271
  values[0].data.d_status = status;
272 273
  values[1].type          = GIMP_PDB_IMAGE;
  values[1].data.d_int32  = -1;
Elliot Lee's avatar
Elliot Lee committed
274 275 276

  switch (run_mode)
    {
Sven Neumann's avatar
Sven Neumann committed
277
    case GIMP_RUN_INTERACTIVE:
Elliot Lee's avatar
Elliot Lee committed
278 279 280 281 282 283 284 285
      /*  Possibly retrieve data  */
      gimp_get_data ("plug_in_film", &filmvals);

      /*  First acquire information with a dialog  */
      if (! film_dialog (param[1].data.d_int32))
	return;
      break;

Sven Neumann's avatar
Sven Neumann committed
286
    case GIMP_RUN_NONINTERACTIVE:
Elliot Lee's avatar
Elliot Lee committed
287 288 289 290
      /*  Make sure all the arguments are there!  */
      /* Also we want to have some images to compose */
      if ((nparams != 12) || (param[10].data.d_int32 < 1))
	{
Sven Neumann's avatar
Sven Neumann committed
291
	  status = GIMP_PDB_CALLING_ERROR;
292 293 294 295 296 297
	}
      else
	{
          filmvals.keep_height       = (param[3].data.d_int32 <= 0);
          filmvals.film_height       = (filmvals.keep_height ?
					128 : param[3].data.d_int32);
298
	  filmvals.film_color        = param[4].data.d_color;
299
          filmvals.number_start      = param[5].data.d_int32;
300
          g_strlcpy (filmvals.number_font, param[6].data.d_string, FONT_LEN);
301
	  filmvals.number_color      = param[7].data.d_color;
302 303 304
          filmvals.number_pos[0]     = param[8].data.d_int32;
          filmvals.number_pos[1]     = param[9].data.d_int32;
          filmvals.num_images        = param[10].data.d_int32;
Elliot Lee's avatar
Elliot Lee committed
305 306 307 308 309 310 311
          if (filmvals.num_images > MAX_FILM_PICTURES)
            filmvals.num_images = MAX_FILM_PICTURES;
          for (k = 0; k < filmvals.num_images; k++)
            filmvals.image[k] = param[11].data.d_int32array[k];
	}
      break;

Sven Neumann's avatar
Sven Neumann committed
312
    case GIMP_RUN_WITH_LAST_VALS:
Elliot Lee's avatar
Elliot Lee committed
313 314 315 316 317 318 319 320
      /*  Possibly retrieve data  */
      gimp_get_data ("plug_in_film", &filmvals);
      break;

    default:
      break;
    }

321
  if (! check_filmvals ())
Sven Neumann's avatar
Sven Neumann committed
322
    status = GIMP_PDB_CALLING_ERROR;
Elliot Lee's avatar
Elliot Lee committed
323

Sven Neumann's avatar
Sven Neumann committed
324
  if (status == GIMP_PDB_SUCCESS)
Elliot Lee's avatar
Elliot Lee committed
325
    {
Sven Neumann's avatar
Sven Neumann committed
326
      if (run_mode != GIMP_RUN_NONINTERACTIVE)
327
        gimp_progress_init (_("Composing Images..."));
Elliot Lee's avatar
Elliot Lee committed
328 329 330

      image_ID = film ();

331
      if (image_ID < 0)
332
	{
Sven Neumann's avatar
Sven Neumann committed
333
	  status = GIMP_PDB_EXECUTION_ERROR;
334
	}
Elliot Lee's avatar
Elliot Lee committed
335
      else
336 337 338 339
	{
	  values[1].data.d_int32 = image_ID;
	  gimp_image_undo_enable (image_ID);
	  gimp_image_clean_all (image_ID);
Sven Neumann's avatar
Sven Neumann committed
340
	  if (run_mode != GIMP_RUN_NONINTERACTIVE)
341 342
	    gimp_display_new (image_ID);
	}
Elliot Lee's avatar
Elliot Lee committed
343 344

      /*  Store data  */
Sven Neumann's avatar
Sven Neumann committed
345
      if (run_mode == GIMP_RUN_INTERACTIVE)
Elliot Lee's avatar
Elliot Lee committed
346 347 348 349 350 351 352 353 354 355
        gimp_set_data ("plug_in_film", &filmvals, sizeof (FilmVals));
    }

  values[0].data.d_status = status;
}

/* Compose a roll film image from several images */
static gint32
film (void)
{
356 357 358 359 360 361 362 363
  gint width, height, tile_height, scan_lines;
  guchar *dst, *hole;
  gint film_height, film_width;
  gint picture_width, picture_height, picture_space, picture_x0, picture_y0;
  gint hole_offset, hole_width, hole_height, hole_space, hole_x;
  gint number_height, num_images, num_pictures;
  gint i, j, k, picture_count;
  gdouble f;
Sven Neumann's avatar
Sven Neumann committed
364
  GimpRGB foreground;
365
  gint num_layers;
366 367
  gint32 *image_ID_src, image_ID_dst, layer_ID_src, layer_ID_dst;
  gint32 *layers;
Sven Neumann's avatar
Sven Neumann committed
368 369
  GimpDrawable *drawable_dst;
  GimpPixelRgn pixel_rgn_dst;
370 371 372 373 374 375 376 377 378 379 380 381 382

  /* initialize */

  layers = NULL;

  num_images = filmvals.num_images;
  image_ID_src = filmvals.image;

  if (num_images <= 0)
    return (-1);

  tile_height = gimp_tile_height ();
  /* Save foreground colour */
383
  gimp_palette_get_foreground (&foreground);
384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419

  if (filmvals.keep_height) /* Search maximum picture height */
    {
      picture_height = 0;
      for (j = 0; j < num_images; j++)
	{
	  height = gimp_image_height (image_ID_src[j]);
	  if (height > picture_height) picture_height = height;
	}
      film_height = (int)(picture_height / filmvals.picture_height + 0.5);
      filmvals.film_height = film_height;
    }
  else
    {
      film_height = filmvals.film_height;
      picture_height = (int)(film_height * filmvals.picture_height + 0.5);
    }
  picture_space = (int)(film_height * filmvals.picture_space + 0.5);
  picture_y0 = (film_height - picture_height)/2;

  number_height = film_height * filmvals.number_height;

  /* Calculate total film width */
  film_width = 0;
  num_pictures = 0;
  for (j = 0; j < num_images; j++)
    {
      layers = gimp_image_get_layers (image_ID_src[j], &num_layers);
      /* Get scaled image size */
      width = gimp_image_width (image_ID_src[j]);
      height = gimp_image_height (image_ID_src[j]);
      f = ((double)picture_height) / (double)height;
      picture_width = width * f;

      for (k = 0; k < num_layers; k++)
	{
420
	  if (gimp_layer_is_floating_sel (layers[k]))
421 422 423 424 425 426 427 428
	    continue;

	  film_width += (picture_space/2);  /* Leading space */
	  film_width += picture_width;      /* Scaled image width */
	  film_width += (picture_space/2);  /* Trailing space */
	  num_pictures++;
	}

429
      g_free (layers);
430
    }
Elliot Lee's avatar
Elliot Lee committed
431
#ifdef FILM_DEBUG
432 433 434 435
  g_printerr ("film_height = %d, film_width = %d\n", film_height, film_width);
  g_printerr ("picture_height = %d, picture_space = %d, picture_y0 = %d\n",
              picture_height, picture_space, picture_y0);
  g_printerr ("Number of pictures = %d\n", num_pictures);
Elliot Lee's avatar
Elliot Lee committed
436 437
#endif

Michael Natterer's avatar
Michael Natterer committed
438 439
  image_ID_dst = create_new_image (_("Untitled"),
				   (guint) film_width, (guint) film_height,
Sven Neumann's avatar
Sven Neumann committed
440
				   GIMP_RGB_IMAGE, &layer_ID_dst,
441
				   &drawable_dst, &pixel_rgn_dst);
Elliot Lee's avatar
Elliot Lee committed
442

443
  dst = g_new (guchar, film_width * tile_height * 3);
Elliot Lee's avatar
Elliot Lee committed
444

445 446 447 448 449 450
  /* Fill film background */
  i = 0;
  while (i < film_height)
    {
      scan_lines =
	(i + tile_height - 1 < film_height) ? tile_height : (film_height - i);
Elliot Lee's avatar
Elliot Lee committed
451

Sven Neumann's avatar
Sven Neumann committed
452
      set_pixels (film_width * scan_lines, dst, &filmvals.film_color);
Elliot Lee's avatar
Elliot Lee committed
453

454 455 456 457 458
      gimp_pixel_rgn_set_rect (&pixel_rgn_dst, dst, 0, i,
			       film_width, scan_lines);
      i += scan_lines;
    }
  g_free (dst);
Elliot Lee's avatar
Elliot Lee committed
459

460 461 462 463 464 465
  /* Draw all the holes */
  hole_offset = film_height * filmvals.hole_offset;
  hole_width = film_height * filmvals.hole_width;
  hole_height = film_height * filmvals.hole_height;
  hole_space = film_height * filmvals.hole_space;
  hole_x = hole_space / 2;
Elliot Lee's avatar
Elliot Lee committed
466 467

#ifdef FILM_DEBUG
468 469
  g_printerr ("hole_x %d hole_offset %d hole_width %d hole_height %d hole_space %d\n",
              hole_x, hole_offset, hole_width, hole_height, hole_space );
Elliot Lee's avatar
Elliot Lee committed
470 471
#endif

472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488
  hole = create_hole_rgb (hole_width, hole_height);
  if (hole)
    {
      while (hole_x < film_width)
	{
	  draw_hole_rgb (drawable_dst, hole_x,
			 hole_offset,
			 hole_width, hole_height, hole);
	  draw_hole_rgb (drawable_dst, hole_x,
			 film_height-hole_offset-hole_height,
			 hole_width, hole_height, hole);

	  hole_x += hole_width + hole_space;
	}
      g_free (hole);
    }
  gimp_drawable_detach (drawable_dst);
Elliot Lee's avatar
Elliot Lee committed
489

490 491 492 493 494 495 496
  /* Compose all images and layers */
  picture_x0 = 0;
  picture_count = 0;
  for (j = 0; j < num_images; j++)
    {
      width = gimp_image_width (image_ID_src[j]);
      height = gimp_image_height (image_ID_src[j]);
Michael Natterer's avatar
Michael Natterer committed
497
      f = ((gdouble) picture_height) / (gdouble) height;
498
      picture_width = width * f;
Elliot Lee's avatar
Elliot Lee committed
499

500
      layers = gimp_image_get_layers (image_ID_src[j], &num_layers);
Elliot Lee's avatar
Elliot Lee committed
501

502 503
      for (k = 0; k < num_layers; k++)
	{
504
	  if (gimp_layer_is_floating_sel (layers[k]))
505 506
	    continue;

507
	  picture_x0 += picture_space / 2;
508 509 510

	  layer_ID_src = layers[k];
	  /* Scale the layer and insert int new image */
511 512 513
	  if (! scale_layer (layer_ID_src, 0, 0, width, height,
                             layer_ID_dst, picture_x0, picture_y0,
                             picture_width, picture_height))
514
	    {
515
	      g_printerr ("film: error during scale_layer\n");
516 517 518 519 520 521 522
	      return -1;
	    }

	  /* Draw picture numbers */
	  if ((number_height > 0) &&
	      (filmvals.number_pos[0] || filmvals.number_pos[1]))
	    {
523
	      gimp_palette_set_foreground (&filmvals.number_color);
524 525 526 527 528 529 530 531 532 533 534

	      if (filmvals.number_pos[0])
		draw_number (layer_ID_dst, filmvals.number_start + picture_count,
			     picture_x0 + picture_width/2,
			     (hole_offset-number_height)/2, number_height);
	      if (filmvals.number_pos[1])
		draw_number (layer_ID_dst, filmvals.number_start + picture_count,
			     picture_x0 + picture_width/2,
			     film_height - (hole_offset + number_height)/2,
			     number_height);

535
	      gimp_palette_set_foreground (&foreground);
536 537 538 539
	    }

	  picture_x0 += picture_width + (picture_space/2);

Sven Neumann's avatar
Sven Neumann committed
540
	  if (run_mode != GIMP_RUN_NONINTERACTIVE)
541 542 543 544 545 546 547
	    gimp_progress_update (((gdouble) (picture_count + 1)) /
				  (gdouble) num_pictures);

	  picture_count++;
	}
    }

548
  g_free (layers);
Elliot Lee's avatar
Elliot Lee committed
549

550
  /* Drawing text/numbers leaves us with a floating selection. Stop it */
551
  gimp_floating_sel_anchor (gimp_image_get_floating_sel (image_ID_dst));
552

553
  /* Restore foreground */
554
  gimp_palette_set_foreground (&foreground);
Elliot Lee's avatar
Elliot Lee committed
555

556
  return image_ID_dst;
Elliot Lee's avatar
Elliot Lee committed
557 558 559
}

/* Check filmvals. Unreasonable values are reset to a default. */
560 561
/* If this is not possible, FALSE is returned. Otherwise TRUE is returned. */
static gboolean
Elliot Lee's avatar
Elliot Lee committed
562 563
check_filmvals (void)
{
564 565 566 567 568 569
  if (filmvals.film_height < 10)
    filmvals.film_height = 10;

  if (filmvals.number_start < 0)
    filmvals.number_start = 0;

570 571
  if (filmvals.number_font[0] == '\0')
    strcpy (filmvals.number_font, "Monospace");
572 573

  if (filmvals.num_images < 1)
574
    return FALSE;
575

576
  return TRUE;
Elliot Lee's avatar
Elliot Lee committed
577 578 579
}

/* Converts numpix pixels from src to RGB at dst */
580
static void
Sven Neumann's avatar
Sven Neumann committed
581
convert_to_rgb (GimpDrawable *srcdrawable,
582 583 584
		gint          numpix,
		guchar       *src,
		guchar       *dst)
Elliot Lee's avatar
Elliot Lee committed
585
{
586 587
 register guchar *from = src, *to = dst;
 register gint k;
Elliot Lee's avatar
Elliot Lee committed
588 589 590
 register guchar *cmap, *colour;
 gint ncols;

591
 switch (gimp_drawable_type (srcdrawable->drawable_id))
592
   {
Sven Neumann's avatar
Sven Neumann committed
593
   case GIMP_RGB_IMAGE:
Elliot Lee's avatar
Elliot Lee committed
594 595 596
     memcpy ((char *)dst, (char *)src, numpix*3);
     break;

Sven Neumann's avatar
Sven Neumann committed
597
   case GIMP_RGBA_IMAGE:
Elliot Lee's avatar
Elliot Lee committed
598 599 600 601
     from = src;
     to = dst;
     k = numpix;
     while (k-- > 0)
602 603 604 605
       {
	 *(to++) = *(from++); *(to++) = *(from++); *(to++) = *(from++);
	 from++;
       }
Elliot Lee's avatar
Elliot Lee committed
606 607
     break;

Sven Neumann's avatar
Sven Neumann committed
608
   case GIMP_GRAY_IMAGE:
Elliot Lee's avatar
Elliot Lee committed
609 610 611 612
     from = src;
     to = dst;
     k = numpix;
     while (k-- > 0)
613 614 615 616
       {
	 to[0] = to[1] = to[2] = *(from++);
	 to += 3;
       }
Elliot Lee's avatar
Elliot Lee committed
617 618
     break;

Sven Neumann's avatar
Sven Neumann committed
619
   case GIMP_GRAYA_IMAGE:
Elliot Lee's avatar
Elliot Lee committed
620 621 622 623
     from = src;
     to = dst;
     k = numpix;
     while (k-- > 0)
624 625 626 627 628
       {
	 to[0] = to[1] = to[2] = *from;
	 from += 2;
	 to += 3;
       }
Elliot Lee's avatar
Elliot Lee committed
629 630
     break;

Sven Neumann's avatar
Sven Neumann committed
631 632
   case GIMP_INDEXED_IMAGE:
   case GIMP_INDEXEDA_IMAGE:
633
     cmap = gimp_image_get_cmap (gimp_drawable_get_image (srcdrawable->drawable_id),
Elliot Lee's avatar
Elliot Lee committed
634 635 636
                                 &ncols);
     if (cmap)
       {
637 638 639 640 641 642 643 644 645 646 647
	 from = src;
	 to = dst;
	 k = numpix;
	 while (k-- > 0)
	   {
	     colour = cmap + 3*(int)(*from);
	     *(to++) = *(colour++);
	     *(to++) = *(colour++);
	     *(to++) = *(colour++);
	     from += srcdrawable->bpp;
	   }
Elliot Lee's avatar
Elliot Lee committed
648 649 650 651
       }
     break;

   default:
652
     g_printerr ("convert_to_rgb: unknown image type\n");
Elliot Lee's avatar
Elliot Lee committed
653
     break;
654
   }
Elliot Lee's avatar
Elliot Lee committed
655 656 657 658
}

/* Assigns numpix pixels starting at dst with color r,g,b */
static void
Sven Neumann's avatar
Sven Neumann committed
659 660 661
set_pixels (gint     numpix,
            guchar  *dst,
            GimpRGB *color)
662 663 664
{
  register gint k;
  register guchar ur, ug, ub, *udest;
Elliot Lee's avatar
Elliot Lee committed
665

Sven Neumann's avatar
Sven Neumann committed
666 667 668
  ur = color->r * 255.999;
  ug = color->g * 255.999;
  ub = color->b * 255.999;
669 670
  k = numpix;
  udest = dst;
Sven Neumann's avatar
Sven Neumann committed
671

672 673 674 675 676 677
  while (k-- > 0)
    {
      *(udest++) = ur;
      *(udest++) = ug;
      *(udest++) = ub;
    }
Elliot Lee's avatar
Elliot Lee committed
678 679 680
}

/* Scales a portion of a layer and places it in another layer. */
681 682
/* On success, TRUE is returned. Otherwise FALSE is returned */
static gboolean
683 684 685 686 687 688 689 690 691 692
scale_layer (gint32  src_layer,
	     gint    src_x0,
	     gint    src_y0,
	     gint    src_width,
	     gint    src_height,
	     gint32  dst_layer,
	     gint    dst_x0,
	     gint    dst_y0,
	     gint    dst_width,
	     gint    dst_height)
Elliot Lee's avatar
Elliot Lee committed
693
{
694 695 696
  gint tile_height, i, scan_lines, numpix;
  guchar *src, *tmp = (guchar *) ident; /* Just to satisfy gcc */
  gint32 tmp_image, tmp_layer;
Sven Neumann's avatar
Sven Neumann committed
697 698
  GimpDrawable *tmp_drawable, *src_drawable, *dst_drawable;
  GimpPixelRgn tmp_pixel_rgn, src_pixel_rgn, dst_pixel_rgn;
Elliot Lee's avatar
Elliot Lee committed
699

700
  tile_height = gimp_tile_height ();
Elliot Lee's avatar
Elliot Lee committed
701

702
  src_drawable = gimp_drawable_get (src_layer);
Elliot Lee's avatar
Elliot Lee committed
703

704
  /*** Get a RGB copy of the source region ***/
Elliot Lee's avatar
Elliot Lee committed
705

706
  tmp_image = create_new_image (_("Temporary"), src_width, src_height,
Sven Neumann's avatar
Sven Neumann committed
707
				GIMP_RGB_IMAGE,
708
				&tmp_layer, &tmp_drawable, &tmp_pixel_rgn);
Elliot Lee's avatar
Elliot Lee committed
709

710 711
  src = g_new (guchar, src_width * tile_height * src_drawable->bpp);
  tmp = g_new (guchar, src_width * tile_height * tmp_drawable->bpp);
Elliot Lee's avatar
Elliot Lee committed
712

713 714
  gimp_pixel_rgn_init (&src_pixel_rgn, src_drawable, src_x0, src_y0,
		       src_width, src_height, FALSE, FALSE);
Elliot Lee's avatar
Elliot Lee committed
715

716 717 718 719 720
  i = 0;
  while (i < src_height)
    {
      scan_lines = (i+tile_height-1 < src_height) ? tile_height : (src_height-i);
      numpix = scan_lines*src_width;
Elliot Lee's avatar
Elliot Lee committed
721

722 723 724
      /* Get part of source image */
      gimp_pixel_rgn_get_rect (&src_pixel_rgn, src, src_x0, src_y0+i,
			       src_width, scan_lines);
Elliot Lee's avatar
Elliot Lee committed
725

726
      convert_to_rgb (src_drawable, numpix, src, tmp);
Elliot Lee's avatar
Elliot Lee committed
727

728 729
      /* Set part of temporary image */
      gimp_pixel_rgn_set_rect (&tmp_pixel_rgn, tmp, 0, i, src_width, scan_lines);
Elliot Lee's avatar
Elliot Lee committed
730

731 732
      i += scan_lines;
    }
Elliot Lee's avatar
Elliot Lee committed
733

734 735 736 737 738
  /* Now we have an image that is a copy of the */
  /* source region and has been converted to RGB. */
  /* We dont need any more access to the source image. */
  gimp_drawable_detach (src_drawable);
  g_free (src);
Elliot Lee's avatar
Elliot Lee committed
739

740 741 742 743
  /*** Resize the temporary image if necessary ***/
  if ((src_width != dst_width) || (src_height != dst_height))
    {
      gimp_drawable_detach (tmp_drawable);
Elliot Lee's avatar
Elliot Lee committed
744

745
      gimp_layer_scale (tmp_layer, dst_width, dst_height, 0);
Elliot Lee's avatar
Elliot Lee committed
746

747 748
      tmp_drawable = gimp_drawable_get (tmp_layer);
    }
Elliot Lee's avatar
Elliot Lee committed
749

750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773
  /*** Copy temporary image to destination image */
  gimp_pixel_rgn_init (&tmp_pixel_rgn, tmp_drawable, 0, 0,
		       dst_width, dst_height, FALSE, FALSE);
  g_free (tmp);

  tmp = g_new (guchar, dst_width * tile_height * tmp_drawable->bpp);

  dst_drawable = gimp_drawable_get (dst_layer);
  gimp_pixel_rgn_init (&dst_pixel_rgn, dst_drawable, dst_x0, dst_y0,
		       dst_width, dst_height, TRUE, FALSE);
  i = 0;
  while (i < dst_height)
    {
      scan_lines = (i+tile_height-1 < dst_height) ? tile_height : (dst_height-i);

      /* Get strip of temporary image */
      gimp_pixel_rgn_get_rect (&tmp_pixel_rgn, tmp, 0, i,
			       dst_width, scan_lines);

      /* Set strip of destination image */
      gimp_pixel_rgn_set_rect (&dst_pixel_rgn, tmp, dst_x0, dst_y0+i,
			       dst_width, scan_lines);
      i += scan_lines;
    }
Elliot Lee's avatar
Elliot Lee committed
774

775 776 777 778
  /* No more access to the temporary image */
  gimp_drawable_detach (tmp_drawable);
  g_free (tmp);
  gimp_image_delete (tmp_image);
Elliot Lee's avatar
Elliot Lee committed
779

780
  gimp_drawable_detach (dst_drawable);
Elliot Lee's avatar
Elliot Lee committed
781

782
  return TRUE;
Elliot Lee's avatar
Elliot Lee committed
783 784 785
}

/* Create the RGB-pixels that make up the hole */
786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806
static guchar *
create_hole_rgb (gint width,
		 gint height)
{
  guchar *hole, *top, *bottom;
  gint radius, length, k;

  hole = g_new (guchar, width * height * 3);

  /* Fill a rectangle with white */
  memset (hole, 255, width * height * 3);
  radius = height / 4;
  if (radius > width / 2)
    radius = width / 2;
  top = hole;
  bottom = hole + (height-1)*width*3;
  for (k = radius-1; k > 0; k--)  /* Rounding corners */
    {
      length = (int)(radius - sqrt ((gdouble) (radius * radius - k * k)) - 0.5);
      if (length > 0)
	{
Sven Neumann's avatar
Sven Neumann committed
807 808 809 810
	  set_pixels (length, top, &filmvals.film_color);
	  set_pixels (length, top + (width-length)*3, &filmvals.film_color);
	  set_pixels (length, bottom, &filmvals.film_color);
	  set_pixels (length, bottom + (width-length)*3, &filmvals.film_color);
811 812 813 814 815 816
	}
      top += width*3;
      bottom -= width*3;
    }

  return hole;
Elliot Lee's avatar
Elliot Lee committed
817 818 819 820
}

/* Draw the hole at the specified position */
static void
Sven Neumann's avatar
Sven Neumann committed
821
draw_hole_rgb (GimpDrawable *drw,
822 823 824 825 826
               gint          x,
               gint          y,
               gint          width,
               gint          height,
               guchar       *hole)
827
{
Sven Neumann's avatar
Sven Neumann committed
828
  GimpPixelRgn rgn;
829 830
  guchar *data;
  gint tile_height = gimp_tile_height ();
831
  gint i, j, scan_lines, d_width = gimp_drawable_width (drw->drawable_id);
832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859
  gint length;

  if ((width <= 0) || (height <= 0))
    return;
  if ((x+width <= 0) || (x >= d_width))
    return;
  length = width;   /* Check that we dont draw past the image */
  if ((x+length) >= d_width)
    length = d_width-x;

  data = g_new (guchar, length * tile_height * drw->bpp);

  gimp_pixel_rgn_init (&rgn, drw, x, y, length, height, TRUE, FALSE);

  i = 0;
  while (i < height)
    {
      scan_lines = (i+tile_height-1 < height) ? tile_height : (height-i);
      if (length == width)
	{
	  memcpy (data, hole + 3*width*i, width*scan_lines*3);
	}
      else  /* We have to do some clipping */
	{
	  for (j = 0; j < scan_lines; j++)
	    memcpy (data + j*length*3, hole + (i+j)*width*3, length*3);
	}
      gimp_pixel_rgn_set_rect (&rgn, data, x, y+i, length, scan_lines);
Elliot Lee's avatar
Elliot Lee committed
860

861 862
      i += scan_lines;
    }
Elliot Lee's avatar
Elliot Lee committed
863

864
  g_free (data);
Elliot Lee's avatar
Elliot Lee committed
865 866 867 868 869
}

/* Draw the number of the picture onto the film */
static void
draw_number (gint32 layer_ID,
870 871 872 873 874 875
             gint   num,
             gint   x,
             gint   y,
             gint   height)
{
  gchar buf[32];
876 877 878 879 880
  GimpDrawable *drw;
  gint k, delta, max_delta;
  gint32 image_ID;
  gint32 text_layer_ID;
  gint   text_width, text_height, text_ascent, descent;
881
  gchar *fontname = filmvals.number_font;
882 883 884 885

  g_snprintf (buf, sizeof (buf), "%d", num);

  drw = gimp_drawable_get (layer_ID);
886
  image_ID = gimp_drawable_get_image (layer_ID);
887 888 889 890 891 892

  max_delta = height / 10;
  if (max_delta < 1)
    max_delta = 1;

  /* Numbers dont need the descent. Inquire it and move the text down */
893 894 895 896 897
  for (k = 0; k < max_delta * 2 + 1; k++)
    {
      /* Try different font sizes if inquire of extent failed */
      gboolean success;

898
      delta = (k+1) / 2;
899 900 901 902 903 904 905 906 907 908 909

      if ((k & 1) == 0)
	delta = -delta;

      success = gimp_text_get_extents_fontname (buf,
						height + delta, GIMP_PIXELS,
						fontname,
						&text_width, &text_height,
						&text_ascent, &descent);

      if (success)
910 911 912 913 914
	{
	  height += delta;
	  break;
	}
    }
Elliot Lee's avatar
Elliot Lee committed
915

916 917 918 919 920
  text_layer_ID = gimp_text_fontname (image_ID, layer_ID,
				      x, y + descent / 2,
				      buf, 1, FALSE,
				      height, GIMP_PIXELS,
				      fontname);
921 922 923

  if (text_layer_ID == -1)
    g_message ("draw_number: Error in drawing text\n");
924 925

  gimp_drawable_detach (drw);
Elliot Lee's avatar
Elliot Lee committed
926 927 928 929
}

/* Create an image. Sets layer_ID, drawable and rgn. Returns image_ID */
static gint32
930
create_new_image (const gchar    *filename,
931 932
                  guint           width,
                  guint           height,
Sven Neumann's avatar
Sven Neumann committed
933
                  GimpImageType   gdtype,
934
                  gint32         *layer_ID,
935 936
                  GimpDrawable  **drawable,
                  GimpPixelRgn   *pixel_rgn)
Elliot Lee's avatar
Elliot Lee committed
937
{
938
  gint32            image_ID;
Sven Neumann's avatar
Sven Neumann committed
939
  GimpImageBaseType gitype;
Elliot Lee's avatar
Elliot Lee committed
940

Sven Neumann's avatar
Sven Neumann committed
941 942 943 944
  if ((gdtype == GIMP_GRAY_IMAGE) || (gdtype == GIMP_GRAYA_IMAGE))
    gitype = GIMP_GRAY;
  else if ((gdtype == GIMP_INDEXED_IMAGE) || (gdtype == GIMP_INDEXEDA_IMAGE))
    gitype = GIMP_INDEXED;
945
  else
Sven Neumann's avatar
Sven Neumann committed
946
    gitype = GIMP_RGB;
Elliot Lee's avatar
Elliot Lee committed
947

948 949
  image_ID = gimp_image_new (width, height, gitype);
  gimp_image_set_filename (image_ID, filename);
Elliot Lee's avatar
Elliot Lee committed
950

951
  gimp_image_undo_disable (image_ID);
952
  *layer_ID = gimp_layer_new (image_ID, _("Background"), width, height,
Sven Neumann's avatar
Sven Neumann committed