~ubuntu-branches/ubuntu/jaunty/gimp/jaunty-security

« back to all changes in this revision

Viewing changes to plug-ins/common/gif.c

  • Committer: Bazaar Package Importer
  • Author(s): Daniel Holbach
  • Date: 2007-05-02 16:33:03 UTC
  • mfrom: (1.1.4 upstream)
  • Revision ID: james.westby@ubuntu.com-20070502163303-bvzhjzbpw8qglc4y
Tags: 2.3.16-1ubuntu1
* Resynchronized with Debian, remaining Ubuntu changes:
  - debian/rules: i18n magic.
* debian/control.in:
  - Maintainer: Ubuntu Core Developers <ubuntu-devel@lists.ubuntu.com>
* debian/patches/02_help-message.patch,
  debian/patches/03_gimp.desktop.in.in.patch,
  debian/patches/10_dont_show_wizard.patch: updated.
* debian/patches/04_composite-signedness.patch,
  debian/patches/05_add-letter-spacing.patch: dropped, used upstream.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* GIF saving file filter for The GIMP version 1.3/1.4
 
1
/* GIF saving file filter for GIMP
2
2
 *
3
3
 *    Copyright
4
4
 *    - Adam D. Moss
275
275
#include "config.h"
276
276
 
277
277
#include <errno.h>
278
 
#include <stdio.h>
279
 
#include <stdlib.h>
280
278
#include <string.h>
281
279
 
 
280
#include <glib/gstdio.h>
 
281
 
282
282
#include <libgimp/gimp.h>
283
283
#include <libgimp/gimpui.h>
284
284
 
285
285
#include "libgimp/stdplugins-intl.h"
286
286
 
287
287
 
 
288
#define SAVE_PROC      "file-gif-save"
 
289
#define PLUG_IN_BINARY "gif"
 
290
 
 
291
 
288
292
/* Define only one of these to determine which kind of gif's you would like.
289
293
 * GIF_UN means use uncompressed gifs.  These will be large, but no
290
294
 * patent problems.
312
316
 
313
317
typedef struct
314
318
{
315
 
  gint interlace;
316
 
  gint save_comment;
317
 
  gint loop;
318
 
  gint default_delay;
319
 
  gint default_dispose;
 
319
  gint     interlace;
 
320
  gint     save_comment;
 
321
  gint     loop;
 
322
  gint     default_delay;
 
323
  gint     default_dispose;
 
324
  gboolean always_use_default_delay;
 
325
  gboolean always_use_default_dispose;
320
326
} GIFSaveVals;
321
327
 
322
328
 
324
330
 */
325
331
static void   query                    (void);
326
332
static void   run                      (const gchar      *name,
327
 
                                        gint              nparams,
328
 
                                        const GimpParam  *param,
329
 
                                        gint             *nreturn_vals,
330
 
                                        GimpParam       **return_vals);
 
333
                                        gint              nparams,
 
334
                                        const GimpParam  *param,
 
335
                                        gint             *nreturn_vals,
 
336
                                        GimpParam       **return_vals);
331
337
static gint   save_image               (const gchar      *filename,
332
 
                                        gint32            image_ID,
333
 
                                        gint32            drawable_ID,
334
 
                                        gint32            orig_image_ID);
 
338
                                        gint32            image_ID,
 
339
                                        gint32            drawable_ID,
 
340
                                        gint32            orig_image_ID);
335
341
 
336
 
static gboolean boundscheck            (gint32            image_ID);
337
 
static gboolean badbounds_dialog       (void);
 
342
static gboolean bounds_check           (gint32            image_ID);
 
343
static gboolean bad_bounds_dialog      (void);
338
344
 
339
345
static gboolean save_dialog            (gint32            image_ID);
340
346
static void     comment_entry_callback (GtkTextBuffer    *buffer);
351
357
static gint Interlace;
352
358
 
353
359
 
354
 
GimpPlugInInfo PLUG_IN_INFO =
 
360
const GimpPlugInInfo PLUG_IN_INFO =
355
361
{
356
362
  NULL,  /* init_proc  */
357
363
  NULL,  /* quit_proc  */
365
371
  TRUE,    /* save comment                         */
366
372
  TRUE,    /* loop infinitely                      */
367
373
  100,     /* default_delay between frames (100ms) */
368
 
  0        /* default_dispose = "don't care"       */
 
374
  0,       /* default_dispose = "don't care"       */
 
375
  FALSE,   /* don't always use default_delay       */
 
376
  FALSE    /* don't always use default_dispose     */
369
377
};
370
378
 
371
379
 
374
382
static void
375
383
query (void)
376
384
{
377
 
  static GimpParamDef save_args[] =
 
385
  static const GimpParamDef save_args[] =
378
386
  {
379
 
    { GIMP_PDB_INT32,    "run_mode",        "Interactive, non-interactive" },
 
387
    { GIMP_PDB_INT32,    "run-mode",        "Interactive, non-interactive" },
380
388
    { GIMP_PDB_IMAGE,    "image",           "Image to save" },
381
389
    { GIMP_PDB_DRAWABLE, "drawable",        "Drawable to save" },
382
390
    { GIMP_PDB_STRING,   "filename",        "The name of the file to save the image in" },
383
 
    { GIMP_PDB_STRING,   "raw_filename",    "The name entered" },
 
391
    { GIMP_PDB_STRING,   "raw-filename",    "The name entered" },
384
392
    { GIMP_PDB_INT32,    "interlace",       "Try to save as interlaced" },
385
393
    { GIMP_PDB_INT32,    "loop",            "(animated gif) loop infinitely" },
386
 
    { GIMP_PDB_INT32,    "default_delay",   "(animated gif) Default delay between framese in milliseconds" },
387
 
    { GIMP_PDB_INT32,    "default_dispose", "(animated gif) Default disposal type (0=`don't care`, 1=combine, 2=replace)" }
 
394
    { GIMP_PDB_INT32,    "default-delay",   "(animated gif) Default delay between framese in milliseconds" },
 
395
    { GIMP_PDB_INT32,    "default-dispose", "(animated gif) Default disposal type (0=`don't care`, 1=combine, 2=replace)" }
388
396
  };
389
397
 
390
 
  gimp_install_procedure ("file_gif_save",
 
398
  gimp_install_procedure (SAVE_PROC,
391
399
                          "saves files in Compuserve GIF file format",
392
400
                          "Save a file in Compuserve GIF format, with "
393
 
                          "possible animation, transparency, and comment.  "
394
 
                          "To save an animation, operate on a multi-layer "
395
 
                          "file.  The plug-in will intrepret <50% alpha as "
396
 
                          "transparent.  When run non-interactively, the "
397
 
                          "value for the comment is taken from the "
398
 
                          "'gimp-comment' parasite.  ",
 
401
                          "possible animation, transparency, and comment.  "
 
402
                          "To save an animation, operate on a multi-layer "
 
403
                          "file.  The plug-in will intrepret <50% alpha as "
 
404
                          "transparent.  When run non-interactively, the "
 
405
                          "value for the comment is taken from the "
 
406
                          "'gimp-comment' parasite.  ",
399
407
                          "Spencer Kimball, Peter Mattis, Adam Moss, David Koblas",
400
408
                          "Spencer Kimball, Peter Mattis, Adam Moss, David Koblas",
401
409
                          "1995-1997",
402
410
                          N_("GIF image"),
403
 
                          "INDEXED*, GRAY*",
 
411
                          "INDEXED*, GRAY*",
404
412
                          GIMP_PLUGIN,
405
413
                          G_N_ELEMENTS (save_args), 0,
406
414
                          save_args, NULL);
407
415
 
408
 
  gimp_register_file_handler_mime ("file_gif_save", "image/gif");
409
 
  gimp_register_save_handler ("file_gif_save", "gif", "");
 
416
  gimp_register_file_handler_mime (SAVE_PROC, "image/gif");
 
417
  gimp_register_save_handler (SAVE_PROC, "gif", "");
410
418
}
411
419
 
412
420
static void
432
440
  values[0].type          = GIMP_PDB_STATUS;
433
441
  values[0].data.d_status = GIMP_PDB_EXECUTION_ERROR;
434
442
 
435
 
  if (strcmp (name, "file_gif_save") == 0)
 
443
  if (strcmp (name, SAVE_PROC) == 0)
436
444
    {
437
445
      image_ID    = orig_image_ID = param[1].data.d_int32;
438
446
      drawable_ID = param[2].data.d_int32;
439
447
 
440
448
      /*  eventually export the image */
441
449
      switch (run_mode)
442
 
        {
443
 
        case GIMP_RUN_INTERACTIVE:
444
 
        case GIMP_RUN_WITH_LAST_VALS:
445
 
          gimp_ui_init ("gif", FALSE);
446
 
          export = gimp_export_image (&image_ID, &drawable_ID, "GIF",
447
 
                                      (GIMP_EXPORT_CAN_HANDLE_INDEXED |
448
 
                                       GIMP_EXPORT_CAN_HANDLE_GRAY |
449
 
                                       GIMP_EXPORT_CAN_HANDLE_ALPHA  |
450
 
                                       GIMP_EXPORT_CAN_HANDLE_LAYERS_AS_ANIMATION));
451
 
          if (export == GIMP_EXPORT_CANCEL)
452
 
            {
453
 
              values[0].data.d_status = GIMP_PDB_CANCEL;
454
 
              return;
455
 
            }
456
 
          break;
457
 
        default:
458
 
          break;
459
 
        }
460
 
 
461
 
      if (boundscheck (image_ID))
462
 
        /* The image may or may not have had layers out of
463
 
           bounds, but the user didn't mind cropping it down. */
464
 
        {
465
 
          switch (run_mode)
466
 
            {
467
 
            case GIMP_RUN_INTERACTIVE:
468
 
              /*  Possibly retrieve data  */
469
 
              gimp_get_data ("file_gif_save", &gsvals);
470
 
 
471
 
              /*  First acquire information with a dialog  */
472
 
              if (! save_dialog (image_ID))
473
 
                status = GIMP_PDB_CANCEL;
474
 
              break;
475
 
 
476
 
            case GIMP_RUN_NONINTERACTIVE:
477
 
              /*  Make sure all the arguments are there!  */
478
 
              if (nparams != 9)
479
 
                {
480
 
                  status = GIMP_PDB_CALLING_ERROR;
481
 
                }
482
 
              else
483
 
                {
484
 
                  gsvals.interlace       = (param[5].data.d_int32) ? TRUE : FALSE;
485
 
                  gsvals.save_comment    = TRUE;  /*  no way to to specify that through the PDB  */
486
 
                  gsvals.loop            = (param[6].data.d_int32) ? TRUE : FALSE;
487
 
                  gsvals.default_delay   = param[7].data.d_int32;
488
 
                  gsvals.default_dispose = param[8].data.d_int32;
489
 
                }
490
 
              break;
491
 
 
492
 
            case GIMP_RUN_WITH_LAST_VALS:
493
 
              /*  Possibly retrieve data  */
494
 
              gimp_get_data ("file_gif_save", &gsvals);
495
 
              break;
496
 
 
497
 
            default:
498
 
              break;
499
 
            }
500
 
 
501
 
          if (status == GIMP_PDB_SUCCESS)
502
 
            {
503
 
              if (save_image (param[3].data.d_string,
504
 
                              image_ID,
505
 
                              drawable_ID,
506
 
                              orig_image_ID))
507
 
                {
508
 
                  /*  Store psvals data  */
509
 
                  gimp_set_data ("file_gif_save",
510
 
                                 &gsvals, sizeof (GIFSaveVals));
511
 
                }
512
 
              else
513
 
                {
514
 
                  status = GIMP_PDB_EXECUTION_ERROR;
515
 
                }
516
 
            }
517
 
        }
518
 
      else /* Some layers were out of bounds and the user wishes
519
 
              to abort.  */
520
 
        {
521
 
          status = GIMP_PDB_CANCEL;
522
 
        }
 
450
        {
 
451
        case GIMP_RUN_INTERACTIVE:
 
452
        case GIMP_RUN_WITH_LAST_VALS:
 
453
          gimp_ui_init (PLUG_IN_BINARY, FALSE);
 
454
          export = gimp_export_image (&image_ID, &drawable_ID, "GIF",
 
455
                                      (GIMP_EXPORT_CAN_HANDLE_INDEXED |
 
456
                                       GIMP_EXPORT_CAN_HANDLE_GRAY |
 
457
                                       GIMP_EXPORT_CAN_HANDLE_ALPHA  |
 
458
                                       GIMP_EXPORT_CAN_HANDLE_LAYERS_AS_ANIMATION));
 
459
          if (export == GIMP_EXPORT_CANCEL)
 
460
            {
 
461
              values[0].data.d_status = GIMP_PDB_CANCEL;
 
462
              return;
 
463
            }
 
464
          break;
 
465
        default:
 
466
          break;
 
467
        }
 
468
 
 
469
      if (bounds_check (image_ID))
 
470
        /* The image may or may not have had layers out of
 
471
           bounds, but the user didn't mind cropping it down. */
 
472
        {
 
473
          switch (run_mode)
 
474
            {
 
475
            case GIMP_RUN_INTERACTIVE:
 
476
              /*  Possibly retrieve data  */
 
477
              gimp_get_data (SAVE_PROC, &gsvals);
 
478
 
 
479
              /*  First acquire information with a dialog  */
 
480
              if (! save_dialog (image_ID))
 
481
                status = GIMP_PDB_CANCEL;
 
482
              break;
 
483
 
 
484
            case GIMP_RUN_NONINTERACTIVE:
 
485
              /*  Make sure all the arguments are there!  */
 
486
              if (nparams != 9)
 
487
                {
 
488
                  status = GIMP_PDB_CALLING_ERROR;
 
489
                }
 
490
              else
 
491
                {
 
492
                  gsvals.interlace       = (param[5].data.d_int32) ? TRUE : FALSE;
 
493
                  gsvals.save_comment    = TRUE;  /*  no way to to specify that through the PDB  */
 
494
                  gsvals.loop            = (param[6].data.d_int32) ? TRUE : FALSE;
 
495
                  gsvals.default_delay   = param[7].data.d_int32;
 
496
                  gsvals.default_dispose = param[8].data.d_int32;
 
497
                }
 
498
              break;
 
499
 
 
500
            case GIMP_RUN_WITH_LAST_VALS:
 
501
              /*  Possibly retrieve data  */
 
502
              gimp_get_data (SAVE_PROC, &gsvals);
 
503
              break;
 
504
 
 
505
            default:
 
506
              break;
 
507
            }
 
508
 
 
509
          if (status == GIMP_PDB_SUCCESS)
 
510
            {
 
511
              if (save_image (param[3].data.d_string,
 
512
                              image_ID,
 
513
                              drawable_ID,
 
514
                              orig_image_ID))
 
515
                {
 
516
                  /*  Store psvals data  */
 
517
                  gimp_set_data (SAVE_PROC, &gsvals, sizeof (GIFSaveVals));
 
518
                }
 
519
              else
 
520
                {
 
521
                  status = GIMP_PDB_EXECUTION_ERROR;
 
522
                }
 
523
            }
 
524
        }
 
525
      else
 
526
        /* Some layers were out of bounds and the user wishes
 
527
          to abort.  */
 
528
        {
 
529
          status = GIMP_PDB_CANCEL;
 
530
        }
523
531
 
524
532
      if (export == GIMP_EXPORT_EXPORT)
525
 
        gimp_image_delete (image_ID);
 
533
        gimp_image_delete (image_ID);
526
534
    }
527
535
 
528
536
  values[0].data.d_status = status;
529
537
}
530
538
 
531
 
#define MAXCOLORMAPSIZE  256
532
 
 
533
 
#define INTERLACE          0x40
534
 
#define LOCALCOLORMAP      0x80
535
 
 
536
 
#define GRAYSCALE        1
537
 
#define COLOR            2
538
 
 
539
 
typedef guchar CMap[3][MAXCOLORMAPSIZE];
540
 
 
541
 
 
542
539
static gchar * globalcomment = NULL;
543
540
 
544
541
 
586
583
 
587
584
 
588
585
 
589
 
static gint find_unused_ia_colour         (guchar *pixels,
590
 
                                           gint    numpixels,
591
 
                                           gint    num_indices,
592
 
                                           gint   *colors);
 
586
static gint find_unused_ia_colour   (const guchar *pixels,
 
587
                                     gint          numpixels,
 
588
                                     gint          num_indices,
 
589
                                     gint         *colors);
593
590
 
594
591
static void special_flatten_indexed_alpha (guchar *pixels,
595
 
                                           gint   *transparent,
596
 
                                           gint   *colors,
 
592
                                           gint   transparent,
597
593
                                           gint    numpixels);
598
 
static int colorstobpp (int);
599
 
static int bpptocolors (int);
600
 
static int GetPixel (int, int);
601
 
static void BumpPixel (void);
602
 
static int GIFNextPixel (ifunptr);
603
 
 
604
 
static void GIFEncodeHeader (FILE *, gboolean, int, int, int, int,
605
 
                             int *, int *, int *, ifunptr);
606
 
static void GIFEncodeGraphicControlExt (FILE *, int, int, int, int,
607
 
                                        int, int, int, ifunptr);
608
 
static void GIFEncodeImageData (FILE *, int, int, int, int,
609
 
                                ifunptr, gint, gint);
610
 
static void GIFEncodeClose (FILE *);
611
 
static void GIFEncodeLoopExt (FILE *, guint);
612
 
static void GIFEncodeCommentExt (FILE *, const gchar *comment);
613
 
 
614
 
int rowstride;
615
 
guchar *pixels;
616
 
int cur_progress;
617
 
int max_progress;
618
 
 
619
 
static void Putword (int, FILE *);
620
 
static void compress (int, FILE *, ifunptr);
 
594
static int colors_to_bpp  (int);
 
595
static int bpp_to_colors  (int);
 
596
static int get_pixel      (int, int);
 
597
static int gif_next_pixel (ifunptr);
 
598
static void bump_pixel    (void);
 
599
 
 
600
static void gif_encode_header              (FILE *, gboolean, int, int, int, int,
 
601
                                            int *, int *, int *, ifunptr);
 
602
static void gif_encode_graphic_control_ext (FILE *, int, int, int, int,
 
603
                                            int, int, int, ifunptr);
 
604
static void gif_encode_image_data          (FILE *, int, int, int, int,
 
605
                                            ifunptr, gint, gint);
 
606
static void gif_encode_close               (FILE *);
 
607
static void gif_encode_loop_ext            (FILE *, guint);
 
608
static void gif_encode_comment_ext         (FILE *, const gchar *comment);
 
609
 
 
610
static gint     rowstride;
 
611
static guchar  *pixels;
 
612
static gint     cur_progress;
 
613
static gint     max_progress;
 
614
 
621
615
#ifdef GIF_UN
622
 
static void nocompress (int, FILE *, ifunptr);
 
616
static void no_compress     (int, FILE *, ifunptr);
623
617
#else
624
618
#ifdef GIF_RLE
625
 
static void rlecompress (int, FILE *, ifunptr);
 
619
static void rle_compress    (int, FILE *, ifunptr);
626
620
#else
627
 
static void normalcompress (int, FILE *, ifunptr);
628
 
#endif
629
 
#endif
630
 
static void output (code_int);
631
 
static void cl_block (void);
632
 
static void cl_hash (count_int);
633
 
static void writeerr (void);
634
 
static void char_init (void);
635
 
static void char_out (int);
 
621
static void normal_compress (int, FILE *, ifunptr);
 
622
#endif
 
623
#endif
 
624
static void put_word   (int, FILE *);
 
625
static void compress   (int, FILE *, ifunptr);
 
626
static void output     (code_int);
 
627
static void cl_block   (void);
 
628
static void cl_hash    (count_int);
 
629
static void write_err  (void);
 
630
static void char_init  (void);
 
631
static void char_out   (int);
636
632
static void flush_char (void);
637
633
 
638
634
 
639
635
 
640
636
static gint
641
 
find_unused_ia_colour (guchar *pixels,
642
 
                       gint    numpixels,
643
 
                       gint    num_indices,
644
 
                       gint   *colors)
 
637
find_unused_ia_colour (const guchar *pixels,
 
638
                       gint          numpixels,
 
639
                       gint          num_indices,
 
640
                       gint         *colors)
645
641
{
646
 
  int i;
647
642
  gboolean ix_used[256];
 
643
  gint i;
648
644
 
649
645
#ifdef GIFDEBUG
650
646
  g_printerr ("GIF: fuiac: Image claims to use %d/%d indices - finding free "
651
 
              "index...\n", (int)(*colors),(int)num_indices);
 
647
              "index...\n", *colors, num_indices);
652
648
#endif
653
649
 
654
 
  for (i=0; i<256; i++)
655
 
    {
656
 
      ix_used[i] = (gboolean)FALSE;
657
 
    }
658
 
 
659
 
  for (i=0; i<numpixels; i++)
660
 
    {
661
 
      if (pixels[i*2+1]) ix_used[pixels[i*2]] = (gboolean) TRUE;
662
 
    }
663
 
 
664
 
  for (i=num_indices-1; i>=0; i--)
665
 
    {
666
 
      if (ix_used[i] == (gboolean)FALSE)
667
 
        {
 
650
  for (i = 0; i < 256; i++)
 
651
    ix_used[i] = FALSE;
 
652
 
 
653
  for (i = 0; i < numpixels; i++)
 
654
    {
 
655
      if (pixels[i * 2 + 1])
 
656
        ix_used[pixels[i * 2]] = TRUE;
 
657
    }
 
658
 
 
659
  for (i = num_indices - 1; i >= 0; i--)
 
660
    {
 
661
      if (! ix_used[i])
 
662
        {
668
663
#ifdef GIFDEBUG
669
 
          g_printerr ("GIF: Found unused colour index %d.\n", (int) i);
 
664
          g_printerr ("GIF: Found unused colour index %d.\n", (int) i);
670
665
#endif
671
 
          return i;
672
 
        }
 
666
          return i;
 
667
        }
673
668
    }
674
669
 
675
670
  /* Couldn't find an unused colour index within the number of
676
671
     bits per pixel we wanted.  Will have to increment the number
677
672
     of colours in the image and assign a transparent pixel there. */
678
 
  if ((*colors) < 256)
 
673
  if (*colors < 256)
679
674
    {
680
675
      (*colors)++;
 
676
 
681
677
      g_printerr ("GIF: 2nd pass "
682
678
                  "- Increasing bounds and using colour index %d.\n",
683
 
                  (int) (*colors)-1);
684
 
      return ((*colors)-1);
 
679
                  *colors - 1);
 
680
      return ((*colors) - 1);
685
681
    }
686
682
 
687
683
  g_message (_("Couldn't simply reduce colors further. Saving as opaque."));
688
 
  return (-1);
 
684
 
 
685
  return -1;
689
686
}
690
687
 
691
688
 
692
689
static void
693
690
special_flatten_indexed_alpha (guchar *pixels,
694
 
                               int *transparent,
695
 
                               int *colors,
696
 
                               int numpixels)
 
691
                               gint    transparent,
 
692
                               gint    numpixels)
697
693
{
698
694
  guint32 i;
699
695
 
700
696
  /* Each transparent pixel in the image is mapped to a uniform value for
701
697
     encoding, if image already has <=255 colours */
702
698
 
703
 
  if ((*transparent) == -1) /* tough, no indices left for the trans. index */
 
699
  if (transparent == -1) /* tough, no indices left for the trans. index */
704
700
    {
705
 
      for (i=0; i<numpixels; i++)
706
 
        pixels[i] = pixels[i*2];
 
701
      for (i = 0; i < numpixels; i++)
 
702
        pixels[i] = pixels[i * 2];
707
703
    }
708
704
  else  /* make transparent */
709
705
    {
710
 
      for (i=0; i<numpixels; i++)
711
 
        {
712
 
          if (!(pixels[i*2+1] & 128))
713
 
            {
714
 
              pixels[i] = (guchar)(*transparent);
715
 
            }
716
 
          else
717
 
            {
718
 
              pixels[i] = pixels[i*2];
719
 
            }
720
 
        }
 
706
      for (i = 0; i < numpixels; i++)
 
707
        {
 
708
          if (! (pixels[i * 2 + 1] & 128))
 
709
            {
 
710
              pixels[i] = (guchar) transparent;
 
711
            }
 
712
          else
 
713
            {
 
714
              pixels[i] = pixels[i * 2];
 
715
            }
 
716
        }
721
717
    }
722
 
 
723
 
 
724
 
  /* Pixel data now takes half as much space (the alpha data has been
725
 
     discarded) */
726
 
  /*  pixels = g_realloc (pixels, numpixels);*/
727
718
}
728
719
 
729
720
 
730
 
static int
731
 
parse_ms_tag (char *str)
 
721
static gint
 
722
parse_ms_tag (const gchar *str)
732
723
{
733
724
  gint sum = 0;
734
725
  gint offset = 0;
738
729
 
739
730
find_another_bra:
740
731
 
741
 
  while ((offset<length) && (str[offset]!='('))
 
732
  while ((offset < length) && (str[offset] != '('))
742
733
    offset++;
743
734
 
744
 
  if (offset>=length)
 
735
  if (offset >= length)
745
736
    return(-1);
746
737
 
747
 
  if (!g_ascii_isdigit (str[++offset]))
 
738
  if (! g_ascii_isdigit (str[++offset]))
748
739
    goto find_another_bra;
749
740
 
750
741
  do
753
744
      sum += str[offset] - '0';
754
745
      offset++;
755
746
    }
756
 
  while ((offset<length) && (g_ascii_isdigit (str[offset])));
 
747
  while ((offset < length) && (g_ascii_isdigit (str[offset])));
757
748
 
758
 
  if (length-offset <= 2)
 
749
  if (length - offset <= 2)
759
750
    return(-3);
760
751
 
761
 
  if ((g_ascii_toupper (str[offset]) != 'M') ||
762
 
      (g_ascii_toupper (str[offset+1]) != 'S'))
 
752
  if ((g_ascii_toupper (str[offset]) != 'M')
 
753
      || (g_ascii_toupper (str[offset+1]) != 'S'))
763
754
    return -4;
764
755
 
765
756
  return sum;
766
757
}
767
758
 
768
759
 
769
 
static int
770
 
parse_disposal_tag (char *str)
 
760
static gint
 
761
parse_disposal_tag (const gchar *str)
771
762
{
772
763
  gint offset = 0;
773
764
  gint length;
774
765
 
775
766
  length = strlen(str);
776
767
 
777
 
  while ((offset+9)<=length)
 
768
  while ((offset + 9) <= length)
778
769
    {
779
 
      if (strncmp(&str[offset],"(combine)",9)==0)
780
 
        return(0x01);
781
 
      if (strncmp(&str[offset],"(replace)",9)==0)
782
 
        return(0x02);
 
770
      if (strncmp(&str[offset], "(combine)", 9) == 0)
 
771
        return(0x01);
 
772
      if (strncmp(&str[offset], "(replace)", 9) == 0)
 
773
        return(0x02);
783
774
      offset++;
784
775
    }
785
776
 
788
779
 
789
780
 
790
781
static gboolean
791
 
boundscheck (gint32 image_ID)
 
782
bounds_check (gint32 image_ID)
792
783
{
793
784
  GimpDrawable *drawable;
794
785
  gint32       *layers;
808
799
      drawable = gimp_drawable_get (layers[i]);
809
800
      gimp_drawable_offsets (layers[i], &offset_x, &offset_y);
810
801
 
811
 
      if ((offset_x < 0) ||
812
 
          (offset_y < 0) ||
813
 
          (offset_x+drawable->width > gimp_image_width(image_ID)) ||
814
 
          (offset_y+drawable->height > gimp_image_height(image_ID)))
815
 
        {
816
 
          g_free (layers);
817
 
          gimp_drawable_detach(drawable);
818
 
 
819
 
          /* Image has illegal bounds - ask the user what it wants to do */
820
 
 
821
 
          /* Do the crop if we can't talk to the user, or if we asked
822
 
           * the user and they said yes. */
823
 
          if ((run_mode == GIMP_RUN_NONINTERACTIVE) || badbounds_dialog ())
824
 
            {
825
 
              gimp_image_crop (image_ID,
826
 
                               gimp_image_width (image_ID),
827
 
                               gimp_image_height (image_ID),
828
 
                               0, 0);
829
 
              return TRUE;
830
 
            }
831
 
          else
832
 
            {
833
 
              return FALSE;
834
 
            }
835
 
        }
 
802
      if ((offset_x < 0)
 
803
          || (offset_y < 0)
 
804
          || (offset_x+drawable->width > gimp_image_width(image_ID))
 
805
          || (offset_y+drawable->height > gimp_image_height(image_ID)))
 
806
        {
 
807
          g_free (layers);
 
808
          gimp_drawable_detach (drawable);
 
809
 
 
810
          /* Image has illegal bounds - ask the user what it wants to do */
 
811
 
 
812
          /* Do the crop if we can't talk to the user, or if we asked
 
813
           * the user and they said yes. */
 
814
          if ((run_mode == GIMP_RUN_NONINTERACTIVE) || bad_bounds_dialog ())
 
815
            {
 
816
              gimp_image_crop (image_ID,
 
817
                               gimp_image_width (image_ID),
 
818
                               gimp_image_height (image_ID),
 
819
                               0, 0);
 
820
              return TRUE;
 
821
            }
 
822
          else
 
823
            {
 
824
              return FALSE;
 
825
            }
 
826
        }
836
827
      else
837
 
        {
838
 
          gimp_drawable_detach (drawable);
839
 
        }
 
828
        {
 
829
          gimp_drawable_detach (drawable);
 
830
        }
840
831
    }
841
832
 
842
833
  g_free (layers);
847
838
 
848
839
static gint
849
840
save_image (const gchar *filename,
850
 
            gint32       image_ID,
851
 
            gint32       drawable_ID,
852
 
            gint32       orig_image_ID)
 
841
            gint32       image_ID,
 
842
            gint32       drawable_ID,
 
843
            gint32       orig_image_ID)
853
844
{
854
845
  GimpPixelRgn pixel_rgn;
855
846
  GimpDrawable *drawable;
860
851
  gint Blue[MAXCOLORS];
861
852
  guchar *cmap;
862
853
  guint rows, cols;
863
 
  gint BitsPerPixel, liberalBPP=0, useBPP=0;
 
854
  gint BitsPerPixel, liberalBPP = 0, useBPP = 0;
864
855
  gint colors;
865
 
  gchar *temp_buf;
866
856
  gint i;
867
857
  gint transparent;
868
858
  gint offset_x, offset_y;
887
877
  if (globalcomment != NULL && comment_was_edited)
888
878
    {
889
879
      comment_parasite = gimp_parasite_new ("gimp-comment",
890
 
                                            GIMP_PARASITE_PERSISTENT,
891
 
                                            strlen (globalcomment)+1,
892
 
                                            (void*) globalcomment);
 
880
                                            GIMP_PARASITE_PERSISTENT,
 
881
                                            strlen (globalcomment) + 1,
 
882
                                            (void*) globalcomment);
893
883
      gimp_image_parasite_attach (orig_image_ID, comment_parasite);
894
884
      gimp_parasite_free (comment_parasite);
895
885
      comment_parasite = NULL;
920
910
  /* get a list of layers for this image_ID */
921
911
  layers = gimp_image_get_layers (image_ID, &nlayers);
922
912
 
923
 
 
924
913
  drawable_type = gimp_drawable_type (layers[0]);
925
914
 
926
 
 
927
915
  /* If the image has multiple layers (i.e. will be animated), a comment,
928
916
     or transparency, then it must be encoded as a GIF89a file, not a vanilla
929
917
     GIF87a. */
944
932
      gimp_rgb_get_uchar (&background, &bgred, &bggreen, &bgblue);
945
933
 
946
934
      for (i = 0; i < colors; i++)
947
 
        {
948
 
          Red[i]   = *cmap++;
949
 
          Green[i] = *cmap++;
950
 
          Blue[i]  = *cmap++;
951
 
        }
 
935
        {
 
936
          Red[i]   = *cmap++;
 
937
          Green[i] = *cmap++;
 
938
          Blue[i]  = *cmap++;
 
939
        }
952
940
      for ( ; i < 256; i++)
953
 
        {
954
 
          Red[i]   = bgred;
955
 
          Green[i] = bggreen;
956
 
          Blue[i]  = bgblue;
957
 
        }
 
941
        {
 
942
          Red[i]   = bgred;
 
943
          Green[i] = bggreen;
 
944
          Blue[i]  = bgblue;
 
945
        }
958
946
      break;
959
947
    case GIMP_GRAYA_IMAGE:
960
948
      is_gif89 = TRUE;
961
949
    case GIMP_GRAY_IMAGE:
962
950
      colors = 256;                   /* FIXME: Not ideal. */
963
951
      for ( i = 0;  i < 256; i++)
964
 
        {
965
 
          Red[i] = Green[i] = Blue[i] = i;
966
 
        }
 
952
        {
 
953
          Red[i] = Green[i] = Blue[i] = i;
 
954
        }
967
955
      break;
968
956
 
969
957
    default:
975
963
 
976
964
  /* find earliest index in palette which is closest to the background
977
965
     colour, and ATTEMPT to use that as the GIF's default background colour. */
978
 
  for (i=255; i>=0; --i) {
979
 
    unsigned int local_error = 0;
980
 
    local_error += (Red[i] - bgred)     * (Red[i] - bgred);
981
 
    local_error += (Green[i] - bggreen) * (Green[i] - bggreen);
982
 
    local_error += (Blue[i] - bgblue)   * (Blue[i] - bgblue);
983
 
    if (local_error <= best_error) {
984
 
      bgindex = i;
985
 
      best_error = local_error;
 
966
  for (i = 255; i >= 0; --i)
 
967
    {
 
968
      guint local_error = 0;
 
969
 
 
970
      local_error += (Red[i] - bgred)     * (Red[i] - bgred);
 
971
      local_error += (Green[i] - bggreen) * (Green[i] - bggreen);
 
972
      local_error += (Blue[i] - bgblue)   * (Blue[i] - bgblue);
 
973
 
 
974
      if (local_error <= best_error)
 
975
        {
 
976
          bgindex = i;
 
977
          best_error = local_error;
 
978
        }
986
979
    }
987
 
  }
988
980
 
989
981
 
990
982
  /* open the destination file for writing */
991
 
  outfile = fopen (filename, "wb");
 
983
  outfile = g_fopen (filename, "wb");
992
984
  if (!outfile)
993
985
    {
994
986
      g_message (_("Could not open '%s' for writing: %s"),
998
990
 
999
991
 
1000
992
  /* init the progress meter */
1001
 
  temp_buf = g_strdup_printf (_("Saving '%s'..."),
1002
 
                              gimp_filename_to_utf8 (filename));
1003
 
  gimp_progress_init (temp_buf);
1004
 
  g_free (temp_buf);
 
993
  gimp_progress_init_printf (_("Saving '%s'"),
 
994
                             gimp_filename_to_utf8 (filename));
1005
995
 
1006
996
 
1007
997
  /* write the GIFheader */
1009
999
  if (colors < 256)
1010
1000
    {
1011
1001
      /* we keep track of how many bits we promised to have in liberalBPP,
1012
 
         so that we don't accidentally come under this when doing
1013
 
         clever transparency stuff where we can re-use wasted indices. */
 
1002
         so that we don't accidentally come under this when doing
 
1003
         clever transparency stuff where we can re-use wasted indices. */
1014
1004
      liberalBPP = BitsPerPixel =
1015
 
        colorstobpp (colors + ((drawable_type==GIMP_INDEXEDA_IMAGE) ? 1 : 0));
 
1005
        colors_to_bpp (colors + ((drawable_type==GIMP_INDEXEDA_IMAGE) ? 1 : 0));
1016
1006
    }
1017
1007
  else
1018
1008
    {
1019
1009
      liberalBPP = BitsPerPixel =
1020
 
        colorstobpp (256);
 
1010
        colors_to_bpp (256);
1021
1011
 
1022
 
      if (drawable_type==GIMP_INDEXEDA_IMAGE)
1023
 
        {
1024
 
          g_printerr ("GIF: Too many colours?\n");
1025
 
        }
 
1012
      if (drawable_type == GIMP_INDEXEDA_IMAGE)
 
1013
        {
 
1014
          g_printerr ("GIF: Too many colours?\n");
 
1015
        }
1026
1016
    }
1027
1017
 
1028
1018
  cols = gimp_image_width (image_ID);
1029
1019
  rows = gimp_image_height (image_ID);
1030
1020
  Interlace = gsvals.interlace;
1031
 
  GIFEncodeHeader (outfile, is_gif89, cols, rows, bgindex,
1032
 
                   BitsPerPixel, Red, Green, Blue, GetPixel);
 
1021
  gif_encode_header (outfile, is_gif89, cols, rows, bgindex,
 
1022
                     BitsPerPixel, Red, Green, Blue, get_pixel);
1033
1023
 
1034
1024
 
1035
1025
  /* If the image has multiple layers it'll be made into an
1036
1026
     animated GIF, so write out the infinite-looping extension */
1037
1027
  if ((nlayers > 1) && (gsvals.loop))
1038
 
    GIFEncodeLoopExt (outfile, 0);
 
1028
    gif_encode_loop_ext (outfile, 0);
1039
1029
 
1040
1030
  /* Write comment extension - mustn't be written before the looping ext. */
1041
1031
  if (gsvals.save_comment && globalcomment)
1042
1032
    {
1043
 
      GIFEncodeCommentExt (outfile, globalcomment);
 
1033
      gif_encode_comment_ext (outfile, globalcomment);
1044
1034
    }
1045
1035
 
1046
1036
 
1047
 
 
1048
1037
  /*** Now for each layer in the image, save an image in a compound GIF ***/
1049
1038
  /************************************************************************/
1050
1039
 
1051
 
  i = nlayers-1;
 
1040
  cur_progress = 0;
 
1041
  max_progress = nlayers * rows;
1052
1042
 
1053
 
  while (i >= 0)
 
1043
  for (i = nlayers - 1; i >= 0; i--, cur_progress = (nlayers - i) * rows)
1054
1044
    {
1055
1045
      drawable_type = gimp_drawable_type (layers[i]);
1056
1046
      drawable = gimp_drawable_get (layers[i]);
1060
1050
      rowstride = drawable->width;
1061
1051
 
1062
1052
      gimp_pixel_rgn_init (&pixel_rgn, drawable, 0, 0,
1063
 
                           drawable->width, drawable->height, FALSE, FALSE);
1064
 
 
1065
 
      cur_progress = 0;
1066
 
      max_progress = drawable->height;
1067
 
 
1068
 
      pixels = (guchar *) g_malloc (drawable->width *
1069
 
                                    drawable->height *
1070
 
                                    (((drawable_type == GIMP_INDEXEDA_IMAGE)||
1071
 
                                      (drawable_type == GIMP_GRAYA_IMAGE)) ? 2:1) );
 
1053
                           drawable->width, drawable->height, FALSE, FALSE);
 
1054
 
 
1055
      pixels = g_new (guchar, (drawable->width * drawable->height
 
1056
                               * (((drawable_type == GIMP_INDEXEDA_IMAGE)
 
1057
                                   || (drawable_type == GIMP_GRAYA_IMAGE)) ? 2 : 1)));
1072
1058
 
1073
1059
      gimp_pixel_rgn_get_rect (&pixel_rgn, pixels, 0, 0,
1074
 
                               drawable->width, drawable->height);
 
1060
                               drawable->width, drawable->height);
1075
1061
 
1076
1062
 
1077
1063
      /* sort out whether we need to do transparency jiggery-pokery */
1078
 
      if ((drawable_type == GIMP_INDEXEDA_IMAGE)||(drawable_type == GIMP_GRAYA_IMAGE))
1079
 
        {
1080
 
          /* Try to find an entry which isn't actually used in the
1081
 
             image, for a transparency index. */
1082
 
 
1083
 
          transparent =
1084
 
            find_unused_ia_colour(pixels,
1085
 
                                  drawable->width * drawable->height,
1086
 
                                  bpptocolors(colorstobpp(colors)),
1087
 
                                  &colors);
1088
 
 
1089
 
          special_flatten_indexed_alpha (pixels,
1090
 
                                         &transparent,
1091
 
                                         &colors,
1092
 
                                         drawable->width * drawable->height);
1093
 
        }
 
1064
      if ((drawable_type == GIMP_INDEXEDA_IMAGE)
 
1065
          || (drawable_type == GIMP_GRAYA_IMAGE))
 
1066
        {
 
1067
          /* Try to find an entry which isn't actually used in the
 
1068
             image, for a transparency index. */
 
1069
 
 
1070
          transparent =
 
1071
            find_unused_ia_colour (pixels,
 
1072
                                   drawable->width * drawable->height,
 
1073
                                   bpp_to_colors (colors_to_bpp (colors)),
 
1074
                                   &colors);
 
1075
 
 
1076
          special_flatten_indexed_alpha (pixels,
 
1077
                                         transparent,
 
1078
                                         drawable->width * drawable->height);
 
1079
        }
1094
1080
      else
1095
 
        transparent = -1;
1096
 
 
1097
 
 
1098
 
      BitsPerPixel = colorstobpp (colors);
 
1081
        {
 
1082
          transparent = -1;
 
1083
        }
 
1084
 
 
1085
      BitsPerPixel = colors_to_bpp (colors);
1099
1086
 
1100
1087
      if (BitsPerPixel != liberalBPP)
1101
 
        {
1102
 
          /* We were able to re-use an index within the existing bitspace,
1103
 
             whereas the estimate in the header was pessimistic but still
1104
 
             needs to be upheld... */
1105
 
          static gboolean onceonly = FALSE;
 
1088
        {
 
1089
          /* We were able to re-use an index within the existing bitspace,
 
1090
             whereas the estimate in the header was pessimistic but still
 
1091
             needs to be upheld... */
 
1092
#ifdef GIFDEBUG
 
1093
          static gboolean onceonly = FALSE;
1106
1094
 
1107
 
          if (!onceonly)
1108
 
            {
1109
 
#ifdef GIFDEBUG
1110
 
              g_warning ("Promised %d bpp, pondered writing chunk with %d bpp!",
 
1095
          if (! onceonly)
 
1096
            {
 
1097
              g_warning ("Promised %d bpp, pondered writing chunk with %d bpp!",
1111
1098
                         liberalBPP, BitsPerPixel);
1112
 
#endif
1113
 
              g_message (_("Warning:\n"
1114
 
                           "Transparent color in written file might be "
1115
 
                           "incorrect on viewers which don't support "
1116
 
                           "transparency."));
1117
1099
              onceonly = TRUE;
1118
 
            }
1119
 
        }
 
1100
            }
 
1101
#endif
 
1102
        }
 
1103
 
1120
1104
      useBPP = (BitsPerPixel > liberalBPP) ? BitsPerPixel : liberalBPP;
1121
1105
 
1122
 
 
1123
1106
      if (is_gif89)
1124
 
        {
1125
 
          if (i > 0)
1126
 
            {
1127
 
              layer_name = gimp_drawable_get_name (layers[i - 1]);
1128
 
              Disposal = parse_disposal_tag (layer_name);
1129
 
              g_free (layer_name);
1130
 
            }
1131
 
          else
1132
 
            Disposal = gsvals.default_dispose;
1133
 
 
1134
 
          layer_name = gimp_drawable_get_name (layers[i]);
1135
 
          Delay89 = parse_ms_tag (layer_name);
1136
 
          g_free (layer_name);
1137
 
 
1138
 
          if (Delay89 < 0)
1139
 
            Delay89 = (gsvals.default_delay + 5) / 10;
1140
 
          else
1141
 
            Delay89 = (Delay89 + 5) / 10;
1142
 
 
1143
 
          /* don't allow a CPU-sucking completely 0-delay looping anim */
1144
 
          if ((nlayers > 1) &&
1145
 
              gsvals.loop &&
1146
 
              (Delay89 == 0))
1147
 
            {
1148
 
              static gboolean onceonly = FALSE;
1149
 
 
1150
 
              if (!onceonly)
1151
 
                {
1152
 
                  g_message (_("Delay inserted to prevent evil "
1153
 
                               "CPU-sucking anim."));
1154
 
                  onceonly = TRUE;
1155
 
                }
1156
 
              Delay89 = 1;
1157
 
            }
1158
 
 
1159
 
          GIFEncodeGraphicControlExt (outfile, Disposal, Delay89, nlayers,
1160
 
                                      cols, rows,
1161
 
                                      transparent,
1162
 
                                      useBPP,
1163
 
                                      GetPixel);
1164
 
        }
1165
 
 
1166
 
      GIFEncodeImageData (outfile, cols, rows,
1167
 
                          (rows>4) ? gsvals.interlace : 0,
1168
 
                          useBPP,
1169
 
                          GetPixel,
1170
 
                          offset_x, offset_y);
1171
 
 
1172
 
      gimp_drawable_detach (drawable);
1173
 
 
1174
 
      g_free (pixels);
1175
 
 
1176
 
      i--;
1177
 
    }
 
1107
        {
 
1108
          if (i > 0 && ! gsvals.always_use_default_dispose)
 
1109
            {
 
1110
              layer_name = gimp_drawable_get_name (layers[i - 1]);
 
1111
              Disposal = parse_disposal_tag (layer_name);
 
1112
              g_free (layer_name);
 
1113
            }
 
1114
          else
 
1115
            {
 
1116
              Disposal = gsvals.default_dispose;
 
1117
            }
 
1118
 
 
1119
          layer_name = gimp_drawable_get_name (layers[i]);
 
1120
          Delay89 = parse_ms_tag (layer_name);
 
1121
          g_free (layer_name);
 
1122
 
 
1123
          if (Delay89 < 0 || gsvals.always_use_default_delay)
 
1124
            Delay89 = (gsvals.default_delay + 5) / 10;
 
1125
          else
 
1126
            Delay89 = (Delay89 + 5) / 10;
 
1127
 
 
1128
          /* don't allow a CPU-sucking completely 0-delay looping anim */
 
1129
          if ((nlayers > 1) && gsvals.loop && (Delay89 == 0))
 
1130
            {
 
1131
              static gboolean onceonly = FALSE;
 
1132
 
 
1133
              if (!onceonly)
 
1134
                {
 
1135
                  g_message (_("Delay inserted to prevent evil "
 
1136
                               "CPU-sucking animation."));
 
1137
                  onceonly = TRUE;
 
1138
                }
 
1139
              Delay89 = 1;
 
1140
            }
 
1141
 
 
1142
          gif_encode_graphic_control_ext (outfile, Disposal, Delay89, nlayers,
 
1143
                                          cols, rows,
 
1144
                                          transparent,
 
1145
                                          useBPP,
 
1146
                                          get_pixel);
 
1147
        }
 
1148
 
 
1149
     gif_encode_image_data (outfile, cols, rows,
 
1150
                            (rows > 4) ? gsvals.interlace : 0,
 
1151
                            useBPP,
 
1152
                            get_pixel,
 
1153
                            offset_x, offset_y);
 
1154
 
 
1155
     gimp_drawable_detach (drawable);
 
1156
 
 
1157
     g_free (pixels);
 
1158
  }
1178
1159
 
1179
1160
  g_free(layers);
1180
1161
 
1181
 
  GIFEncodeClose (outfile);
 
1162
  gif_encode_close (outfile);
1182
1163
 
1183
1164
  return TRUE;
1184
1165
}
1185
1166
 
1186
1167
static gboolean
1187
 
badbounds_dialog (void)
 
1168
bad_bounds_dialog (void)
1188
1169
{
1189
 
  GtkWidget *dlg;
1190
 
  GtkWidget *label;
1191
 
  GtkWidget *vbox;
 
1170
  GtkWidget *dialog;
1192
1171
  gboolean   crop;
1193
1172
 
1194
 
  dlg = gimp_dialog_new (_("GIF Warning"), "gif_warning",
1195
 
                         NULL, 0,
1196
 
                         gimp_standard_help_func, "file-gif-save",
1197
 
 
1198
 
                         GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
1199
 
                         GTK_STOCK_OK,     GTK_RESPONSE_OK,
1200
 
 
1201
 
                         NULL);
1202
 
 
1203
 
  /*  the warning message  */
1204
 
 
1205
 
  vbox = gtk_vbox_new (FALSE, 12);
1206
 
  gtk_container_set_border_width (GTK_CONTAINER (vbox), 12);
1207
 
  gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dlg)->vbox), vbox, TRUE, TRUE, 0);
1208
 
  gtk_widget_show (vbox);
1209
 
 
1210
 
  label= gtk_label_new (_("The image which you are trying to save as a GIF\n"
1211
 
                          "contains layers which extend beyond the actual\n"
1212
 
                          "borders of the image.  This isn't allowed in GIFs,\n"
1213
 
                          "I'm afraid.\n\n"
1214
 
                          "You may choose whether to crop all of the layers to\n"
1215
 
                          "the image borders, or cancel this save."));
1216
 
  gtk_box_pack_start (GTK_BOX (vbox), label, TRUE, TRUE, 0);
1217
 
  gtk_widget_show (label);
1218
 
 
1219
 
  gtk_widget_show (dlg);
1220
 
 
1221
 
  crop = (gimp_dialog_run (GIMP_DIALOG (dlg)) == GTK_RESPONSE_OK);
1222
 
 
1223
 
  gtk_widget_destroy (dlg);
 
1173
  dialog = gtk_message_dialog_new (NULL, 0,
 
1174
                                   GTK_MESSAGE_WARNING, GTK_BUTTONS_NONE,
 
1175
                                   _("The image you are trying to save as a "
 
1176
                                     "GIF contains layers which extend beyond "
 
1177
                                     "the actual borders of the image."));
 
1178
 
 
1179
  gtk_dialog_add_buttons (GTK_DIALOG (dialog),
 
1180
                          GTK_STOCK_CANCEL,     GTK_RESPONSE_CANCEL,
 
1181
                          GIMP_STOCK_TOOL_CROP, GTK_RESPONSE_OK,
 
1182
                          NULL);
 
1183
 
 
1184
  gtk_dialog_set_alternative_button_order (GTK_DIALOG (dialog),
 
1185
                                           GTK_RESPONSE_OK,
 
1186
                                           GTK_RESPONSE_CANCEL,
 
1187
                                           -1);
 
1188
 
 
1189
  gimp_window_set_transient (GTK_WINDOW (dialog));
 
1190
 
 
1191
  gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
 
1192
                                            _("The GIF file format does not "
 
1193
                                              "allow this.  You may choose "
 
1194
                                              "whether to crop all of the "
 
1195
                                              "layers to the image borders, "
 
1196
                                              "or cancel this save."));
 
1197
 
 
1198
  gtk_widget_show (dialog);
 
1199
 
 
1200
  crop = (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK);
 
1201
 
 
1202
  gtk_widget_destroy (dialog);
1224
1203
 
1225
1204
  return crop;
1226
1205
}
1229
1208
static gint
1230
1209
save_dialog (gint32 image_ID)
1231
1210
{
1232
 
  GtkWidget     *dlg;
 
1211
  GtkWidget     *dialog;
1233
1212
  GtkWidget     *main_vbox;
1234
1213
  GtkWidget     *toggle;
1235
1214
  GtkWidget     *label;
1251
1230
 
1252
1231
  gimp_image_get_layers (image_ID, &nlayers);
1253
1232
 
1254
 
  dlg = gimp_dialog_new (_("Save as GIF"), "gif",
1255
 
                         NULL, 0,
1256
 
                         gimp_standard_help_func, "file-gif-save",
1257
 
 
1258
 
                         GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
1259
 
                         GTK_STOCK_OK,     GTK_RESPONSE_OK,
1260
 
 
1261
 
                         NULL);
 
1233
  dialog = gimp_dialog_new (_("Save as GIF"), PLUG_IN_BINARY,
 
1234
                            NULL, 0,
 
1235
                            gimp_standard_help_func, SAVE_PROC,
 
1236
 
 
1237
                            GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
 
1238
                            GTK_STOCK_SAVE,   GTK_RESPONSE_OK,
 
1239
 
 
1240
                            NULL);
 
1241
 
 
1242
  gtk_dialog_set_alternative_button_order (GTK_DIALOG (dialog),
 
1243
                                           GTK_RESPONSE_OK,
 
1244
                                           GTK_RESPONSE_CANCEL,
 
1245
                                           -1);
 
1246
 
 
1247
  gimp_window_set_transient (GTK_WINDOW (dialog));
1262
1248
 
1263
1249
  main_vbox = gtk_vbox_new (FALSE, 12);
1264
1250
  gtk_container_set_border_width (GTK_CONTAINER (main_vbox), 12);
1265
 
  gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dlg)->vbox), main_vbox);
 
1251
  gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), main_vbox);
1266
1252
  gtk_widget_show (main_vbox);
1267
1253
 
1268
1254
  /*  regular gif parameter settings  */
1272
1258
  vbox = gtk_vbox_new (FALSE, 6);
1273
1259
  gtk_container_add (GTK_CONTAINER (frame), vbox);
1274
1260
 
1275
 
  toggle = gtk_check_button_new_with_mnemonic (_("_Interlace"));
 
1261
  toggle = gtk_check_button_new_with_mnemonic (_("I_nterlace"));
1276
1262
  gtk_box_pack_start (GTK_BOX (vbox), toggle, FALSE, FALSE, 0);
1277
1263
  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle), gsvals.interlace);
1278
1264
  gtk_widget_show (toggle);
1364
1350
  hbox = gtk_hbox_new (FALSE, 6);
1365
1351
  gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
1366
1352
 
1367
 
  label = gtk_label_new (_("_Delay between frames where unspecified:"));
 
1353
  label = gtk_label_new_with_mnemonic (_("_Delay between frames where unspecified:"));
1368
1354
  gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
1369
1355
  gtk_widget_show (label);
1370
1356
 
1371
1357
  spinbutton = gimp_spin_button_new (&adj, gsvals.default_delay,
1372
 
                                     0, 65000, 10, 100, 0, 1, 0);
 
1358
                                     0, 65000, 10, 100, 0, 1, 0);
1373
1359
  gtk_box_pack_start (GTK_BOX (hbox), spinbutton, FALSE, FALSE, 0);
1374
1360
  gtk_widget_show (spinbutton);
1375
1361
 
1376
 
  g_signal_connect (adj, "value_changed",
 
1362
  gtk_label_set_mnemonic_widget (GTK_LABEL (label), spinbutton);
 
1363
 
 
1364
  g_signal_connect (adj, "value-changed",
1377
1365
                    G_CALLBACK (gimp_int_adjustment_update),
1378
1366
                    &gsvals.default_delay);
1379
1367
 
1387
1375
  hbox = gtk_hbox_new (FALSE, 6);
1388
1376
  gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
1389
1377
 
1390
 
  label = gtk_label_new (_("Frame disposal where unspecified: "));
 
1378
  label = gtk_label_new_with_mnemonic (_("_Frame disposal where unspecified:"));
1391
1379
  gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
1392
1380
  gtk_widget_show (label);
1393
1381
 
1401
1389
  gimp_int_combo_box_set_active (GIMP_INT_COMBO_BOX (combo),
1402
1390
                                 gsvals.default_dispose);
1403
1391
 
 
1392
  gtk_label_set_mnemonic_widget (GTK_LABEL (label), combo);
 
1393
 
1404
1394
  g_signal_connect (combo, "changed",
1405
1395
                    G_CALLBACK (gimp_int_combo_box_get_active),
1406
1396
                    &gsvals.default_dispose);
1408
1398
  gtk_box_pack_start (GTK_BOX (hbox), combo, FALSE, FALSE, 0);
1409
1399
  gtk_widget_show (combo);
1410
1400
 
 
1401
  /* The "Always use default values" toggles */
 
1402
  toggle = gtk_check_button_new_with_mnemonic (_("_Use delay entered above for all frames"));
 
1403
  gtk_box_pack_start (GTK_BOX (vbox), toggle, FALSE, FALSE, 0);
 
1404
  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle),
 
1405
                                gsvals.always_use_default_delay);
 
1406
  gtk_widget_show (toggle);
 
1407
 
 
1408
  g_signal_connect (G_OBJECT (toggle), "toggled",
 
1409
                    G_CALLBACK (gimp_toggle_button_update),
 
1410
                    &gsvals.always_use_default_delay);
 
1411
 
 
1412
  toggle = gtk_check_button_new_with_mnemonic (_("U_se disposal entered above for all frames"));
 
1413
  gtk_box_pack_start (GTK_BOX (vbox), toggle, FALSE, FALSE, 0);
 
1414
  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle),
 
1415
                                gsvals.always_use_default_dispose);
 
1416
  gtk_widget_show (toggle);
 
1417
 
 
1418
  g_signal_connect (G_OBJECT (toggle), "toggled",
 
1419
                    G_CALLBACK (gimp_toggle_button_update),
 
1420
                    &gsvals.always_use_default_dispose);
 
1421
 
1411
1422
  gtk_widget_show (hbox);
1412
1423
  gtk_widget_show (vbox);
1413
1424
 
1418
1429
    gtk_widget_set_sensitive (frame, FALSE);
1419
1430
 
1420
1431
  gtk_widget_show (frame);
1421
 
  gtk_widget_show (dlg);
1422
 
 
1423
 
  run = (gimp_dialog_run (GIMP_DIALOG (dlg)) == GTK_RESPONSE_OK);
1424
 
 
1425
 
  gtk_widget_destroy (dlg);
 
1432
  gtk_widget_show (dialog);
 
1433
 
 
1434
  run = (gimp_dialog_run (GIMP_DIALOG (dialog)) == GTK_RESPONSE_OK);
 
1435
 
 
1436
  gtk_widget_destroy (dialog);
1426
1437
 
1427
1438
  return run;
1428
1439
}
1429
1440
 
1430
1441
 
1431
1442
static int
1432
 
colorstobpp (int colors)
 
1443
colors_to_bpp (int colors)
1433
1444
{
1434
1445
  int bpp;
1435
1446
 
1451
1462
    bpp = 8;
1452
1463
  else
1453
1464
    {
1454
 
      g_warning ("GIF: colorstobpp - Eep! too many colours: %d\n", colors);
 
1465
      g_warning ("GIF: colors_to_bpp - Eep! too many colours: %d\n", colors);
1455
1466
      return 8;
1456
1467
    }
1457
1468
 
1460
1471
 
1461
1472
 
1462
1473
static int
1463
 
bpptocolors (int bpp)
 
1474
bpp_to_colors (int bpp)
1464
1475
{
1465
1476
  int colors;
1466
1477
 
1467
1478
  if (bpp>8)
1468
1479
    {
1469
 
      g_warning ("GIF: bpptocolors - Eep! bpp==%d !\n", bpp);
 
1480
      g_warning ("GIF: bpp_to_colors - Eep! bpp==%d !\n", bpp);
1470
1481
      return 256;
1471
1482
    }
1472
1483
 
1478
1489
 
1479
1490
 
1480
1491
static int
1481
 
GetPixel (int x,
1482
 
          int y)
 
1492
get_pixel (int x,
 
1493
           int y)
1483
1494
{
1484
1495
  return *(pixels + (rowstride * (long) y) + (long) x);
1485
1496
}
1490
1501
 * GIFENCODE.C    - GIF Image compression interface
1491
1502
 *
1492
1503
 * GIFEncode( FName, GHeight, GWidth, GInterlace, Background, Transparent,
1493
 
 *            BitsPerPixel, Red, Green, Blue, GetPixel )
 
1504
 *            BitsPerPixel, Red, Green, Blue, get_pixel )
1494
1505
 *
1495
1506
 *****************************************************************************/
1496
1507
 
1503
1514
 * Bump the 'curx' and 'cury' to point to the next pixel
1504
1515
 */
1505
1516
static void
1506
 
BumpPixel (void)
 
1517
bump_pixel (void)
1507
1518
{
1508
1519
  /*
1509
1520
   * Bump the current X position
1518
1529
  if (curx == Width)
1519
1530
    {
1520
1531
      cur_progress++;
 
1532
 
1521
1533
      if ((cur_progress % 16) == 0)
1522
 
        gimp_progress_update ((double) cur_progress / (double) max_progress);
 
1534
        gimp_progress_update ((gdouble) cur_progress / (gdouble) max_progress);
1523
1535
 
1524
1536
      curx = 0;
1525
1537
 
1526
 
      if (!Interlace)
1527
 
        ++cury;
 
1538
      if (! Interlace)
 
1539
        ++cury;
1528
1540
      else
1529
 
        {
1530
 
          switch (Pass)
1531
 
            {
1532
 
 
1533
 
            case 0:
1534
 
              cury += 8;
1535
 
              if (cury >= Height)
1536
 
                {
1537
 
                  Pass++;
1538
 
                  cury = 4;
1539
 
                }
1540
 
              break;
1541
 
 
1542
 
            case 1:
1543
 
              cury += 8;
1544
 
              if (cury >= Height)
1545
 
                {
1546
 
                  Pass++;
1547
 
                  cury = 2;
1548
 
                }
1549
 
              break;
1550
 
 
1551
 
            case 2:
1552
 
              cury += 4;
1553
 
              if (cury >= Height)
1554
 
                {
1555
 
                  Pass++;
1556
 
                  cury = 1;
1557
 
                }
1558
 
              break;
1559
 
 
1560
 
            case 3:
1561
 
              cury += 2;
1562
 
              break;
1563
 
            }
1564
 
        }
 
1541
        {
 
1542
          switch (Pass)
 
1543
            {
 
1544
 
 
1545
            case 0:
 
1546
              cury += 8;
 
1547
              if (cury >= Height)
 
1548
                {
 
1549
                  Pass++;
 
1550
                  cury = 4;
 
1551
                }
 
1552
              break;
 
1553
 
 
1554
            case 1:
 
1555
              cury += 8;
 
1556
              if (cury >= Height)
 
1557
                {
 
1558
                  Pass++;
 
1559
                  cury = 2;
 
1560
                }
 
1561
              break;
 
1562
 
 
1563
            case 2:
 
1564
              cury += 4;
 
1565
              if (cury >= Height)
 
1566
                {
 
1567
                  Pass++;
 
1568
                  cury = 1;
 
1569
                }
 
1570
              break;
 
1571
 
 
1572
            case 3:
 
1573
              cury += 2;
 
1574
              break;
 
1575
            }
 
1576
        }
1565
1577
    }
1566
1578
}
1567
1579
 
1569
1581
 * Return the next pixel from the image
1570
1582
 */
1571
1583
static int
1572
 
GIFNextPixel (ifunptr getpixel)
 
1584
gif_next_pixel (ifunptr getpixel)
1573
1585
{
1574
1586
  int r;
1575
1587
 
1580
1592
 
1581
1593
  r = (*getpixel) (curx, cury);
1582
1594
 
1583
 
  BumpPixel ();
 
1595
  bump_pixel ();
1584
1596
 
1585
1597
  return r;
1586
1598
}
1588
1600
/* public */
1589
1601
 
1590
1602
static void
1591
 
GIFEncodeHeader (FILE    *fp,
1592
 
                 gboolean gif89,
1593
 
                 int      GWidth,
1594
 
                 int      GHeight,
1595
 
                 int      Background,
1596
 
                 int      BitsPerPixel,
1597
 
                 int      Red[],
1598
 
                 int      Green[],
1599
 
                 int      Blue[],
1600
 
                 ifunptr  GetPixel)
 
1603
gif_encode_header (FILE    *fp,
 
1604
                  gboolean gif89,
 
1605
                  int      GWidth,
 
1606
                  int      GHeight,
 
1607
                  int      Background,
 
1608
                  int      BitsPerPixel,
 
1609
                  int      Red[],
 
1610
                  int      Green[],
 
1611
                  int      Blue[],
 
1612
                  ifunptr  get_pixel)
1601
1613
{
1602
1614
  int B;
1603
1615
  int RWidth, RHeight;
1646
1658
  /*
1647
1659
   * Write out the screen width and height
1648
1660
   */
1649
 
  Putword (RWidth, fp);
1650
 
  Putword (RHeight, fp);
 
1661
  put_word (RWidth, fp);
 
1662
  put_word (RHeight, fp);
1651
1663
 
1652
1664
  /*
1653
1665
   * Indicate that there is a global colour map
1654
1666
   */
1655
 
  B = 0x80;                     /* Yes, there is a color map */
 
1667
  B = 0x80;                        /* Yes, there is a color map */
1656
1668
 
1657
1669
  /*
1658
1670
   * OR in the resolution
1692
1704
 
1693
1705
 
1694
1706
static void
1695
 
GIFEncodeGraphicControlExt (FILE    *fp,
1696
 
                            int      Disposal,
1697
 
                            int      Delay89,
1698
 
                            int      NumFramesInImage,
1699
 
                            int      GWidth,
1700
 
                            int      GHeight,
1701
 
                            int      Transparent,
1702
 
                            int      BitsPerPixel,
1703
 
                            ifunptr  GetPixel)
 
1707
gif_encode_graphic_control_ext (FILE    *fp,
 
1708
                                int      Disposal,
 
1709
                                int      Delay89,
 
1710
                                int      NumFramesInImage,
 
1711
                                int      GWidth,
 
1712
                                int      GHeight,
 
1713
                                int      Transparent,
 
1714
                                int      BitsPerPixel,
 
1715
                                ifunptr  get_pixel)
1704
1716
{
1705
1717
  int RWidth, RHeight;
1706
1718
  int LeftOfs, TopOfs;
1755
1767
      /*                    s8421                                        */
1756
1768
      fputc ( ((Transparent >= 0) ? 0x01 : 0x00) /* TRANSPARENCY */
1757
1769
 
1758
 
              /* DISPOSAL */
1759
 
              | ((NumFramesInImage > 1) ? (Disposal << 2) : 0x00 ),
1760
 
              /* 0x03 or 0x01 build frames cumulatively */
1761
 
              /* 0x02 clears frame before drawing */
1762
 
              /* 0x00 'don't care' */
 
1770
              /* DISPOSAL */
 
1771
              | ((NumFramesInImage > 1) ? (Disposal << 2) : 0x00 ),
 
1772
              /* 0x03 or 0x01 build frames cumulatively */
 
1773
              /* 0x02 clears frame before drawing */
 
1774
              /* 0x00 'don't care' */
1763
1775
 
1764
 
              fp);
 
1776
              fp);
1765
1777
 
1766
1778
      fputc (Delay89 & 255, fp);
1767
 
      fputc ((Delay89>>8) & 255, fp);
 
1779
      fputc ((Delay89 >> 8) & 255, fp);
1768
1780
 
1769
1781
      fputc (Transparent, fp);
1770
1782
      fputc (0, fp);
1773
1785
 
1774
1786
 
1775
1787
static void
1776
 
GIFEncodeImageData (FILE    *fp,
1777
 
                    int      GWidth,
1778
 
                    int      GHeight,
1779
 
                    int      GInterlace,
1780
 
                    int      BitsPerPixel,
1781
 
                    ifunptr  GetPixel,
1782
 
                    gint     offset_x,
1783
 
                    gint     offset_y)
 
1788
gif_encode_image_data (FILE    *fp,
 
1789
                       int      GWidth,
 
1790
                       int      GHeight,
 
1791
                       int      GInterlace,
 
1792
                       int      BitsPerPixel,
 
1793
                       ifunptr  get_pixel,
 
1794
                       gint     offset_x,
 
1795
                       gint     offset_y)
1784
1796
{
1785
1797
  int RWidth, RHeight;
1786
1798
  int LeftOfs, TopOfs;
1802
1814
  /*
1803
1815
   * Calculate number of bits we are expecting
1804
1816
   */
1805
 
  CountDown = (long) Width *(long) Height;
 
1817
  CountDown = (long) Width * (long) Height;
1806
1818
 
1807
1819
  /*
1808
1820
   * Indicate which pass we are on (if interlace)
1822
1834
   */
1823
1835
  curx = cury = 0;
1824
1836
 
 
1837
  /*
 
1838
   * Write an Image separator
 
1839
   */
 
1840
  fputc (',', fp);
 
1841
 
 
1842
  /*
 
1843
   * Write the Image header
 
1844
   */
 
1845
 
 
1846
  put_word (LeftOfs, fp);
 
1847
  put_word (TopOfs, fp);
 
1848
  put_word (Width, fp);
 
1849
  put_word (Height, fp);
 
1850
 
 
1851
  /*
 
1852
   * Write out whether or not the image is interlaced
 
1853
   */
 
1854
  if (Interlace)
 
1855
    fputc (0x40, fp);
 
1856
  else
 
1857
    fputc (0x00, fp);
 
1858
 
 
1859
  /*
 
1860
   * Write out the initial code size
 
1861
   */
 
1862
  fputc (InitCodeSize, fp);
 
1863
 
 
1864
  /*
 
1865
   * Go and actually compress the data
 
1866
   */
 
1867
  compress (InitCodeSize + 1, fp, get_pixel);
 
1868
 
 
1869
  /*
 
1870
   * Write out a Zero-length packet (to end the series)
 
1871
   */
 
1872
  fputc (0, fp);
 
1873
 
1825
1874
#if 0
1826
 
  /*
1827
 
   * Write an Image separator
1828
 
   */
1829
 
  fputc (',', fp);
1830
 
 
1831
 
  /*
1832
 
   * Write the Image header
1833
 
   */
1834
 
 
1835
 
  Putword (LeftOfs, fp);
1836
 
  Putword (TopOfs, fp);
1837
 
  Putword (Width, fp);
1838
 
  Putword (Height, fp);
1839
 
 
1840
 
  /*
1841
 
   * Write out whether or not the image is interlaced
1842
 
   */
1843
 
  if (Interlace)
1844
 
    fputc (0x40, fp);
1845
 
  else
1846
 
    fputc (0x00, fp);
1847
 
 
1848
 
  /*
1849
 
   * Write out the initial code size
1850
 
   */
1851
 
  fputc (InitCodeSize, fp);
1852
 
 
1853
 
  /*
1854
 
   * Go and actually compress the data
1855
 
   */
1856
 
  compress (InitCodeSize + 1, fp, GetPixel);
1857
 
 
1858
 
  /*
1859
 
   * Write out a Zero-length packet (to end the series)
1860
 
   */
1861
 
  fputc (0, fp);
1862
 
 
1863
 
 
1864
1875
  /***************************/
1865
1876
  Interlace = GInterlace;
1866
1877
  ColorMapSize = 1 << BitsPerPixel;
1882
1893
   * Set up the current x and y position
1883
1894
   */
1884
1895
  curx = cury = 0;
1885
 
 
1886
1896
#endif
1887
 
 
1888
 
 
1889
 
  cur_progress = 0;
1890
 
 
1891
 
 
1892
 
  /*
1893
 
   * Write an Image separator
1894
 
   */
1895
 
  fputc (',', fp);
1896
 
 
1897
 
  /*
1898
 
   * Write the Image header
1899
 
   */
1900
 
 
1901
 
  Putword (LeftOfs, fp);
1902
 
  Putword (TopOfs, fp);
1903
 
  Putword (Width, fp);
1904
 
  Putword (Height, fp);
1905
 
 
1906
 
  /*
1907
 
   * Write out whether or not the image is interlaced
1908
 
   */
1909
 
  if (Interlace)
1910
 
    fputc (0x40, fp);
1911
 
  else
1912
 
    fputc (0x00, fp);
1913
 
 
1914
 
  /*
1915
 
   * Write out the initial code size
1916
 
   */
1917
 
  fputc (InitCodeSize, fp);
1918
 
 
1919
 
  /*
1920
 
   * Go and actually compress the data
1921
 
   */
1922
 
  compress (InitCodeSize + 1, fp, GetPixel);
1923
 
 
1924
 
  /*
1925
 
   * Write out a Zero-length packet (to end the series)
1926
 
   */
1927
 
  fputc (0, fp);
1928
1897
}
1929
1898
 
1930
1899
 
1931
1900
static void
1932
 
GIFEncodeClose (FILE    *fp)
 
1901
gif_encode_close (FILE    *fp)
1933
1902
{
1934
1903
  /*
1935
1904
   * Write the GIF file terminator
1944
1913
 
1945
1914
 
1946
1915
static void
1947
 
GIFEncodeLoopExt (FILE    *fp,
1948
 
                  guint    num_loops)
 
1916
gif_encode_loop_ext (FILE    *fp,
 
1917
                     guint    num_loops)
1949
1918
{
1950
 
  fputc(0x21,fp);
1951
 
  fputc(0xff,fp);
1952
 
  fputc(0x0b,fp);
1953
 
  fputs("NETSCAPE2.0",fp);
1954
 
  fputc(0x03,fp);
1955
 
  fputc(0x01,fp);
1956
 
  Putword(num_loops,fp);
1957
 
  fputc(0x00,fp);
 
1919
  fputc(0x21, fp);
 
1920
  fputc(0xff, fp);
 
1921
  fputc(0x0b, fp);
 
1922
  fputs("NETSCAPE2.0", fp);
 
1923
  fputc(0x03, fp);
 
1924
  fputc(0x01, fp);
 
1925
  put_word(num_loops, fp);
 
1926
  fputc(0x00, fp);
1958
1927
 
1959
 
  /* NOTE: num_loops==0 means 'loop infinitely' */
 
1928
  /* NOTE: num_loops == 0 means 'loop infinitely' */
1960
1929
}
1961
1930
 
1962
1931
 
1963
1932
static void
1964
 
GIFEncodeCommentExt (FILE        *fp,
1965
 
                     const gchar *comment)
 
1933
gif_encode_comment_ext (FILE        *fp,
 
1934
                        const gchar *comment)
1966
1935
{
1967
1936
  if (!comment || !*comment)
1968
1937
    return;
1987
1956
 * Write out a word to the GIF file
1988
1957
 */
1989
1958
static void
1990
 
Putword (int   w,
1991
 
         FILE *fp)
 
1959
put_word (int   w,
 
1960
          FILE *fp)
1992
1961
{
1993
1962
  fputc (w & 0xff, fp);
1994
1963
  fputc ((w / 256) & 0xff, fp);
2010
1979
 
2011
1980
#define GIF_BITS    12
2012
1981
 
2013
 
#define HSIZE  5003             /* 80% occupancy */
 
1982
#define HSIZE  5003                /* 80% occupancy */
2014
1983
 
2015
1984
#ifdef NO_UCHAR
2016
1985
typedef char char_type;
2033
2002
 *
2034
2003
 */
2035
2004
 
2036
 
#define ARGVAL() (*++(*argv) || (--argc && *++argv))
2037
 
 
2038
 
static int n_bits;              /* number of bits/code */
2039
 
static int maxbits = GIF_BITS;  /* user settable max # bits/code */
2040
 
static code_int maxcode;        /* maximum code, given n_bits */
2041
 
static code_int maxmaxcode = (code_int) 1 << GIF_BITS;  /* should NEVER generate this code */
2042
 
#ifdef COMPATIBLE               /* But wrong! */
 
2005
static int n_bits;                /* number of bits/code */
 
2006
static int maxbits = GIF_BITS;        /* user settable max # bits/code */
 
2007
static code_int maxcode;        /* maximum code, given n_bits */
 
2008
static code_int maxmaxcode = (code_int) 1 << GIF_BITS;        /* should NEVER generate this code */
 
2009
#ifdef COMPATIBLE                /* But wrong! */
2043
2010
#define MAXCODE(Mn_bits)        ((code_int) 1 << (Mn_bits) - 1)
2044
2011
#else /*COMPATIBLE */
2045
2012
#define MAXCODE(Mn_bits)        (((code_int) 1 << (Mn_bits)) - 1)
2050
2017
#define HashTabOf(i)       htab[i]
2051
2018
#define CodeTabOf(i)    codetab[i]
2052
2019
 
2053
 
static const code_int hsize = HSIZE;    /* the original reason for this being
2054
 
                                   variable was "for dynamic table sizing",
2055
 
                                   but since it was never actually changed
2056
 
                                   I made it const   --Adam. */
2057
 
 
2058
 
/*
2059
 
 * To save much memory, we overlay the table used by compress() with those
2060
 
 * used by decompress().  The tab_prefix table is the same size and type
2061
 
 * as the codetab.  The tab_suffix table needs 2**GIF_BITS characters.  We
2062
 
 * get this from the beginning of htab.  The output stack uses the rest
2063
 
 * of htab, and contains characters.  There is plenty of room for any
2064
 
 * possible stack (stack used to be 8000 characters).
2065
 
 */
2066
 
 
2067
 
#define tab_prefixof(i) CodeTabOf(i)
2068
 
#define tab_suffixof(i)        ((char_type*)(htab))[i]
2069
 
#define de_stack               ((char_type*)&tab_suffixof((code_int)1<<GIF_BITS))
2070
 
 
2071
 
static code_int free_ent = 0;   /* first unused entry */
 
2020
static const code_int hsize = HSIZE; /* the original reason for this being
 
2021
                                        variable was "for dynamic table sizing",
 
2022
                                        but since it was never actually changed
 
2023
                                        I made it const   --Adam. */
 
2024
 
 
2025
static code_int free_ent = 0;        /* first unused entry */
2072
2026
 
2073
2027
/*
2074
2028
 * block compression parameters -- after all codes are used up,
2077
2031
static int clear_flg = 0;
2078
2032
 
2079
2033
static int offset;
2080
 
static long int in_count = 1;   /* length of input */
2081
 
static long int out_count = 0;  /* # of codes output (for debugging) */
 
2034
static long int in_count = 1;        /* length of input */
 
2035
static long int out_count = 0;        /* # of codes output (for debugging) */
2082
2036
 
2083
2037
/*
2084
2038
 * compress stdin to stdout
2107
2061
static int cur_bits;
2108
2062
 
2109
2063
static unsigned long masks[] =
2110
 
{0x0000, 0x0001, 0x0003, 0x0007, 0x000F,
2111
 
 0x001F, 0x003F, 0x007F, 0x00FF,
2112
 
 0x01FF, 0x03FF, 0x07FF, 0x0FFF,
2113
 
 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF};
 
2064
{0x0000, 0x0001, 0x0003, 0x0007,
 
2065
 0x000F, 0x001F, 0x003F, 0x007F,
 
2066
 0x00FF, 0x01FF, 0x03FF, 0x07FF,
 
2067
 0x0FFF, 0x1FFF, 0x3FFF, 0x7FFF,
 
2068
 0xFFFF};
2114
2069
 
2115
2070
 
2116
2071
static void
2117
2072
compress (int      init_bits,
2118
 
          FILE    *outfile,
2119
 
          ifunptr  ReadValue)
 
2073
          FILE    *outfile,
 
2074
          ifunptr  ReadValue)
2120
2075
{
2121
2076
#ifdef GIF_UN
2122
 
        nocompress(init_bits, outfile, ReadValue);
 
2077
        no_compress(init_bits, outfile, ReadValue);
2123
2078
#else
2124
2079
#ifdef GIF_RLE
2125
 
        rlecompress(init_bits, outfile, ReadValue);
 
2080
        rle_compress(init_bits, outfile, ReadValue);
2126
2081
#else
2127
 
        normalcompress(init_bits, outfile, ReadValue);
 
2082
        normal_compress(init_bits, outfile, ReadValue);
2128
2083
#endif
2129
2084
#endif
2130
2085
}
2131
2086
 
2132
2087
#ifdef GIF_UN
2133
2088
static void
2134
 
nocompress (int      init_bits,
2135
 
          FILE    *outfile,
2136
 
          ifunptr  ReadValue)
 
2089
no_compress (int      init_bits,
 
2090
             FILE    *outfile,
 
2091
             ifunptr  ReadValue)
2137
2092
{
2138
2093
  register long fcode;
2139
2094
  register code_int i /* = 0 */ ;
2174
2129
 
2175
2130
  char_init ();
2176
2131
 
2177
 
  ent = GIFNextPixel (ReadValue);
 
2132
  ent = gif_next_pixel (ReadValue);
2178
2133
 
2179
2134
  hshift = 0;
2180
2135
  for (fcode = (long) hsize; fcode < 65536L; fcode *= 2L)
2181
2136
    ++hshift;
2182
 
  hshift = 8 - hshift;          /* set hash code range bound */
 
2137
  hshift = 8 - hshift;                /* set hash code range bound */
2183
2138
 
2184
2139
  hsize_reg = hsize;
2185
 
  cl_hash ((count_int) hsize_reg);      /* clear hash table */
 
2140
  cl_hash ((count_int) hsize_reg);        /* clear hash table */
2186
2141
 
2187
2142
  output ((code_int) ClearCode);
2188
2143
 
2189
2144
 
2190
2145
#ifdef SIGNED_COMPARE_SLOW
2191
 
  while ((c = GIFNextPixel (ReadValue)) != (unsigned) EOF)
 
2146
  while ((c = gif_next_pixel (ReadValue)) != (unsigned) EOF)
2192
2147
    {
2193
2148
#else /*SIGNED_COMPARE_SLOW */
2194
 
  while ((c = GIFNextPixel (ReadValue)) != EOF)
2195
 
    {                           /* } */
 
2149
  while ((c = gif_next_pixel (ReadValue)) != EOF)
 
2150
    {                                /* } */
2196
2151
#endif /*SIGNED_COMPARE_SLOW */
2197
2152
 
2198
2153
      ++in_count;
2199
2154
 
2200
2155
      fcode = (long) (((long) c << maxbits) + ent);
2201
 
      i = (((code_int) c << hshift) ^ ent);     /* xor hashing */
 
2156
      i = (((code_int) c << hshift) ^ ent);        /* xor hashing */
2202
2157
 
2203
2158
      output ((code_int) ent);
2204
2159
      ++out_count;
2205
2160
      ent = c;
2206
2161
#ifdef SIGNED_COMPARE_SLOW
2207
2162
      if ((unsigned) free_ent < (unsigned) maxmaxcode)
2208
 
        {
 
2163
        {
2209
2164
#else /*SIGNED_COMPARE_SLOW */
2210
2165
      if (free_ent < maxmaxcode)
2211
 
        {                       /* } */
 
2166
        {                        /* } */
2212
2167
#endif /*SIGNED_COMPARE_SLOW */
2213
 
          CodeTabOf (i) = free_ent++;   /* code -> hashtable */
2214
 
          HashTabOf (i) = fcode;
2215
 
        }
 
2168
          CodeTabOf (i) = free_ent++;        /* code -> hashtable */
 
2169
          HashTabOf (i) = fcode;
 
2170
        }
2216
2171
      else
2217
 
        cl_block ();
 
2172
        cl_block ();
2218
2173
    }
2219
2174
 
2220
2175
  /*
2228
2183
#ifdef GIF_RLE
2229
2184
 
2230
2185
static void
2231
 
rlecompress (int      init_bits,
2232
 
          FILE    *outfile,
2233
 
          ifunptr  ReadValue)
 
2186
rle_compress (int      init_bits,
 
2187
              FILE    *outfile,
 
2188
              ifunptr  ReadValue)
2234
2189
{
2235
2190
  register long fcode;
2236
2191
  register code_int i /* = 0 */ ;
2272
2227
 
2273
2228
  char_init ();
2274
2229
 
2275
 
  last = ent = GIFNextPixel (ReadValue);
 
2230
  last = ent = gif_next_pixel (ReadValue);
2276
2231
 
2277
2232
  hshift = 0;
2278
2233
  for (fcode = (long) hsize; fcode < 65536L; fcode *= 2L)
2279
2234
    ++hshift;
2280
 
  hshift = 8 - hshift;          /* set hash code range bound */
 
2235
  hshift = 8 - hshift;                /* set hash code range bound */
2281
2236
 
2282
2237
  hsize_reg = hsize;
2283
 
  cl_hash ((count_int) hsize_reg);      /* clear hash table */
 
2238
  cl_hash ((count_int) hsize_reg);        /* clear hash table */
2284
2239
 
2285
2240
  output ((code_int) ClearCode);
2286
2241
 
2287
2242
 
2288
2243
 
2289
2244
#ifdef SIGNED_COMPARE_SLOW
2290
 
  while ((c = GIFNextPixel (ReadValue)) != (unsigned) EOF)
 
2245
  while ((c = gif_next_pixel (ReadValue)) != (unsigned) EOF)
2291
2246
    {
2292
2247
#else /*SIGNED_COMPARE_SLOW */
2293
 
  while ((c = GIFNextPixel (ReadValue)) != EOF)
2294
 
    {                           /* } */
 
2248
  while ((c = gif_next_pixel (ReadValue)) != EOF)
 
2249
    {                                /* } */
2295
2250
#endif /*SIGNED_COMPARE_SLOW */
2296
2251
 
2297
2252
      ++in_count;
2298
2253
 
2299
2254
      fcode = (long) (((long) c << maxbits) + ent);
2300
 
      i = (((code_int) c << hshift) ^ ent);     /* xor hashing */
 
2255
      i = (((code_int) c << hshift) ^ ent);        /* xor hashing */
2301
2256
 
2302
2257
 
2303
2258
      if (last == c) {
2304
2259
        if (HashTabOf (i) == fcode)
2305
 
          {
2306
 
            ent = CodeTabOf (i);
2307
 
            continue;
2308
 
          }
2309
 
        else if ((long) HashTabOf (i) < 0)      /* empty slot */
2310
 
          goto nomatch;
2311
 
        disp = hsize_reg - i;   /* secondary hash (after G. Knott) */
 
2260
          {
 
2261
            ent = CodeTabOf (i);
 
2262
            continue;
 
2263
          }
 
2264
        else if ((long) HashTabOf (i) < 0)        /* empty slot */
 
2265
          goto nomatch;
 
2266
        disp = hsize_reg - i;        /* secondary hash (after G. Knott) */
2312
2267
        if (i == 0)
2313
 
          disp = 1;
 
2268
          disp = 1;
2314
2269
      probe:
2315
2270
        if ((i -= disp) < 0)
2316
 
          i += hsize_reg;
 
2271
          i += hsize_reg;
2317
2272
 
2318
2273
        if (HashTabOf (i) == fcode)
2319
 
          {
2320
 
            ent = CodeTabOf (i);
2321
 
            continue;
2322
 
          }
 
2274
          {
 
2275
            ent = CodeTabOf (i);
 
2276
            continue;
 
2277
          }
2323
2278
        if ((long) HashTabOf (i) > 0)
2324
 
          goto probe;
 
2279
          goto probe;
2325
2280
        }
2326
2281
    nomatch:
2327
2282
      output ((code_int) ent);
2329
2284
      last = ent = c;
2330
2285
#ifdef SIGNED_COMPARE_SLOW
2331
2286
      if ((unsigned) free_ent < (unsigned) maxmaxcode)
2332
 
        {
 
2287
        {
2333
2288
#else /*SIGNED_COMPARE_SLOW */
2334
2289
      if (free_ent < maxmaxcode)
2335
 
        {                       /* } */
 
2290
        {                        /* } */
2336
2291
#endif /*SIGNED_COMPARE_SLOW */
2337
 
          CodeTabOf (i) = free_ent++;   /* code -> hashtable */
2338
 
          HashTabOf (i) = fcode;
2339
 
        }
 
2292
          CodeTabOf (i) = free_ent++;        /* code -> hashtable */
 
2293
          HashTabOf (i) = fcode;
 
2294
        }
2340
2295
      else
2341
 
        cl_block ();
 
2296
        cl_block ();
2342
2297
    }
2343
2298
 
2344
2299
  /*
2352
2307
#else
2353
2308
 
2354
2309
static void
2355
 
normalcompress (int      init_bits,
2356
 
                FILE    *outfile,
2357
 
                ifunptr  ReadValue)
 
2310
normal_compress (int      init_bits,
 
2311
                 FILE    *outfile,
 
2312
                 ifunptr  ReadValue)
2358
2313
{
2359
2314
  register long fcode;
2360
2315
  register code_int i /* = 0 */ ;
2396
2351
 
2397
2352
  char_init ();
2398
2353
 
2399
 
  ent = GIFNextPixel (ReadValue);
 
2354
  ent = gif_next_pixel (ReadValue);
2400
2355
 
2401
2356
  hshift = 0;
2402
2357
  for (fcode = (long) hsize; fcode < 65536L; fcode *= 2L)
2403
2358
    ++hshift;
2404
 
  hshift = 8 - hshift;          /* set hash code range bound */
 
2359
  hshift = 8 - hshift;                /* set hash code range bound */
2405
2360
 
2406
2361
  hsize_reg = hsize;
2407
 
  cl_hash ((count_int) hsize_reg);      /* clear hash table */
 
2362
  cl_hash ((count_int) hsize_reg);        /* clear hash table */
2408
2363
 
2409
2364
  output ((code_int) ClearCode);
2410
2365
 
2411
2366
 
2412
2367
 
2413
2368
#ifdef SIGNED_COMPARE_SLOW
2414
 
  while ((c = GIFNextPixel (ReadValue)) != (unsigned) EOF)
 
2369
  while ((c = gif_next_pixel (ReadValue)) != (unsigned) EOF)
2415
2370
    {
2416
2371
#else /*SIGNED_COMPARE_SLOW */
2417
 
  while ((c = GIFNextPixel (ReadValue)) != EOF)
2418
 
    {                           /* } */
 
2372
  while ((c = gif_next_pixel (ReadValue)) != EOF)
 
2373
    {                                /* } */
2419
2374
#endif /*SIGNED_COMPARE_SLOW */
2420
2375
 
2421
2376
      ++in_count;
2422
2377
 
2423
2378
      fcode = (long) (((long) c << maxbits) + ent);
2424
 
      i = (((code_int) c << hshift) ^ ent);     /* xor hashing */
 
2379
      i = (((code_int) c << hshift) ^ ent);        /* xor hashing */
2425
2380
 
2426
2381
      if (HashTabOf (i) == fcode)
2427
 
        {
2428
 
          ent = CodeTabOf (i);
2429
 
          continue;
2430
 
        }
2431
 
      else if ((long) HashTabOf (i) < 0)        /* empty slot */
2432
 
        goto nomatch;
2433
 
      disp = hsize_reg - i;     /* secondary hash (after G. Knott) */
 
2382
        {
 
2383
          ent = CodeTabOf (i);
 
2384
          continue;
 
2385
        }
 
2386
      else if ((long) HashTabOf (i) < 0)        /* empty slot */
 
2387
        goto nomatch;
 
2388
      disp = hsize_reg - i;        /* secondary hash (after G. Knott) */
2434
2389
      if (i == 0)
2435
 
        disp = 1;
 
2390
        disp = 1;
2436
2391
    probe:
2437
2392
      if ((i -= disp) < 0)
2438
 
        i += hsize_reg;
 
2393
        i += hsize_reg;
2439
2394
 
2440
2395
      if (HashTabOf (i) == fcode)
2441
 
        {
2442
 
          ent = CodeTabOf (i);
2443
 
          continue;
2444
 
        }
 
2396
        {
 
2397
          ent = CodeTabOf (i);
 
2398
          continue;
 
2399
        }
2445
2400
      if ((long) HashTabOf (i) > 0)
2446
 
        goto probe;
 
2401
        goto probe;
2447
2402
    nomatch:
2448
2403
      output ((code_int) ent);
2449
2404
      ++out_count;
2450
2405
      ent = c;
2451
2406
#ifdef SIGNED_COMPARE_SLOW
2452
2407
      if ((unsigned) free_ent < (unsigned) maxmaxcode)
2453
 
        {
 
2408
        {
2454
2409
#else /*SIGNED_COMPARE_SLOW */
2455
2410
      if (free_ent < maxmaxcode)
2456
 
        {                       /* } */
 
2411
        {                        /* } */
2457
2412
#endif /*SIGNED_COMPARE_SLOW */
2458
 
          CodeTabOf (i) = free_ent++;   /* code -> hashtable */
2459
 
          HashTabOf (i) = fcode;
2460
 
        }
 
2413
          CodeTabOf (i) = free_ent++;        /* code -> hashtable */
 
2414
          HashTabOf (i) = fcode;
 
2415
        }
2461
2416
      else
2462
 
        cl_block ();
 
2417
        cl_block ();
2463
2418
    }
2464
2419
 
2465
2420
  /*
2516
2471
   */
2517
2472
  if (free_ent > maxcode || clear_flg)
2518
2473
    {
2519
 
 
2520
2474
      if (clear_flg)
2521
 
        {
2522
 
 
2523
 
          maxcode = MAXCODE (n_bits = g_init_bits);
2524
 
          clear_flg = 0;
2525
 
 
2526
 
        }
 
2475
        {
 
2476
 
 
2477
          maxcode = MAXCODE (n_bits = g_init_bits);
 
2478
          clear_flg = 0;
 
2479
 
 
2480
        }
2527
2481
      else
2528
 
        {
 
2482
        {
2529
2483
 
2530
 
          ++n_bits;
2531
 
          if (n_bits == maxbits)
2532
 
            maxcode = maxmaxcode;
2533
 
          else
2534
 
            maxcode = MAXCODE (n_bits);
2535
 
        }
 
2484
          ++n_bits;
 
2485
          if (n_bits == maxbits)
 
2486
            maxcode = maxmaxcode;
 
2487
          else
 
2488
            maxcode = MAXCODE (n_bits);
 
2489
        }
2536
2490
    }
2537
2491
 
2538
2492
  if (code == EOFCode)
2541
2495
       * At EOF, write the rest of the buffer.
2542
2496
       */
2543
2497
      while (cur_bits > 0)
2544
 
        {
2545
 
          char_out ((unsigned int) (cur_accum & 0xff));
2546
 
          cur_accum >>= 8;
2547
 
          cur_bits -= 8;
2548
 
        }
 
2498
        {
 
2499
          char_out ((unsigned int) (cur_accum & 0xff));
 
2500
          cur_accum >>= 8;
 
2501
          cur_bits -= 8;
 
2502
        }
2549
2503
 
2550
2504
      flush_char ();
2551
2505
 
2552
2506
      fflush (g_outfile);
2553
2507
 
2554
2508
      if (ferror (g_outfile))
2555
 
        writeerr ();
 
2509
        write_err ();
2556
2510
    }
2557
2511
}
2558
2512
 
2560
2514
 * Clear out the hash table
2561
2515
 */
2562
2516
static void
2563
 
cl_block (void)                 /* table clear for block compress */
 
2517
cl_block (void)                        /* table clear for block compress */
2564
2518
{
2565
2519
  cl_hash ((count_int) hsize);
2566
2520
  free_ent = ClearCode + 2;
2570
2524
}
2571
2525
 
2572
2526
static void
2573
 
cl_hash (count_int hsize)       /* reset code table */
 
2527
cl_hash (count_int hsize)        /* reset code table */
2574
2528
{
2575
2529
 
2576
2530
  register count_int *htab_p = htab + hsize;
2580
2534
 
2581
2535
  i = hsize - 16;
2582
2536
  do
2583
 
    {                           /* might use Sys V memset(3) here */
 
2537
    {                                /* might use Sys V memset(3) here */
2584
2538
      *(htab_p - 16) = m1;
2585
2539
      *(htab_p - 15) = m1;
2586
2540
      *(htab_p - 14) = m1;
2606
2560
}
2607
2561
 
2608
2562
static void
2609
 
writeerr (void)
 
2563
write_err (void)
2610
2564
{
2611
2565
  g_message (_("Error writing output file."));
2612
2566
  return;