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

« back to all changes in this revision

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

  • Committer: Bazaar Package Importer
  • Author(s): Sebastien Bacher
  • Date: 2008-10-06 13:30:41 UTC
  • mto: This revision was merged to the branch mainline in revision 35.
  • Revision ID: james.westby@ubuntu.com-20081006133041-3panbkcanaymfsmp
Tags: upstream-2.6.0
ImportĀ upstreamĀ versionĀ 2.6.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* GIMP - The GNU Image Manipulation Program
2
 
 * Copyright (C) 1995 Spencer Kimball and Peter Mattis
3
 
 *
4
 
 * Multiple-image Network Graphics (MNG) plug-in
5
 
 *
6
 
 * Copyright (C) 2002 S. Mukund <muks@mukund.org>
7
 
 * Portions are copyright of the authors of the file-gif-save, file-png-save
8
 
 * and file-jpeg-save plug-ins' code. The exact ownership of these code
9
 
 * fragments has not been determined.
10
 
 *
11
 
 * This work was sponsored by Xinit Systems Limited, UK.
12
 
 * http://www.xinitsystems.com/
13
 
 *
14
 
 * THIS SOURCE CODE DOES NOT INCLUDE ANY FUNCTIONALITY FOR READING
15
 
 * OR WRITING CONTENT IN THE GIF IMAGE FORMAT.
16
 
 *
17
 
 * This program is free software; you can redistribute it and/or modify
18
 
 * it under the terms of the GNU General Public License as published by
19
 
 * the Free Software Foundation; either version 2 of the License, or
20
 
 * (at your option) any later version.
21
 
 *
22
 
 * This program is distributed in the hope that it will be useful,
23
 
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24
 
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
25
 
 * GNU General Public License for more details.
26
 
 *
27
 
 * You should have received a copy of the GNU General Public License
28
 
 * along with this program; if not, write to the Free Software
29
 
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
30
 
 * --
31
 
 *
32
 
 * For now, this MNG plug-in can only save images. It cannot load images.
33
 
 * Save your working copy as .xcf and use this for "exporting" your images
34
 
 * to MNG. Supports animation the same way as animated GIFs. Supports alpha
35
 
 * transparency. Uses the libmng library (http://www.libmng.com/).
36
 
 * The MIME content-type for MNG images is video/x-mng for now. Make sure
37
 
 * your web-server is configured appropriately if you want to serve MNG
38
 
 * images.
39
 
 *
40
 
 * Since libmng cannot write PNG, JNG and delta PNG chunks at this time
41
 
 * (when this text was written), this plug-in uses libpng and jpeglib to
42
 
 * create the data for the chunks.
43
 
 *
44
 
 */
45
 
 
46
 
#include "config.h"
47
 
 
48
 
#include <errno.h>
49
 
#include <stdlib.h>
50
 
#include <string.h>
51
 
#include <time.h>
52
 
 
53
 
#include <glib/gstdio.h>
54
 
 
55
 
#ifdef HAVE_UNISTD_H
56
 
#include <unistd.h>
57
 
#endif
58
 
 
59
 
 
60
 
/* libpng and jpeglib are currently used in this plug-in. */
61
 
 
62
 
#include <png.h>
63
 
#include <jpeglib.h>
64
 
 
65
 
 
66
 
/* Grrr. The grrr is because the following have to be defined
67
 
 * by the application as well for some reason, although they
68
 
 * were enabled when libmng was compiled. The authors of libmng
69
 
 * must look into this. */
70
 
 
71
 
#if !defined(MNG_SUPPORT_FULL)
72
 
#define MNG_SUPPORT_FULL 1
73
 
#endif
74
 
 
75
 
#if !defined(MNG_SUPPORT_READ)
76
 
#define MNG_SUPPORT_READ 1
77
 
#endif
78
 
 
79
 
#if !defined(MNG_SUPPORT_WRITE)
80
 
#define MNG_SUPPORT_WRITE 1
81
 
#endif
82
 
 
83
 
#if !defined(MNG_SUPPORT_DISPLAY)
84
 
#define MNG_SUPPORT_DISPLAY 1
85
 
#endif
86
 
 
87
 
#if !defined(MNG_ACCESS_CHUNKS)
88
 
#define MNG_ACCESS_CHUNKS 1
89
 
#endif
90
 
 
91
 
#include <libmng.h>
92
 
 
93
 
#include "libgimp/gimp.h"
94
 
#include "libgimp/gimpui.h"
95
 
 
96
 
#include "libgimp/stdplugins-intl.h"
97
 
 
98
 
 
99
 
#define SAVE_PROC      "file-mng-save"
100
 
#define PLUG_IN_BINARY "mng"
101
 
#define SCALE_WIDTH    125
102
 
 
103
 
enum
104
 
{
105
 
  CHUNKS_PNG_D,
106
 
  CHUNKS_JNG_D,
107
 
  CHUNKS_PNG,
108
 
  CHUNKS_JNG
109
 
};
110
 
 
111
 
enum
112
 
{
113
 
  DISPOSE_COMBINE,
114
 
  DISPOSE_REPLACE
115
 
};
116
 
 
117
 
 
118
 
/* The contents of this struct remain static among multiple
119
 
 * invocations of the plug-in. */
120
 
 
121
 
/* TODO: describe the members of the struct */
122
 
 
123
 
struct mng_data_t
124
 
{
125
 
  gint32 interlaced;
126
 
  gint32 bkgd;
127
 
  gint32 gama;
128
 
  gint32 phys;
129
 
  gint32 time;
130
 
  gint32 default_chunks;
131
 
 
132
 
  gfloat quality;
133
 
  gfloat smoothing;
134
 
 
135
 
  gint32 compression_level;
136
 
 
137
 
  gint32 loop;
138
 
  gint32 default_delay;
139
 
  gint32 default_dispose;
140
 
};
141
 
 
142
 
 
143
 
/* Values of the instance of the above struct when the plug-in is
144
 
 * first invoked. */
145
 
 
146
 
struct mng_data_t mng_data =
147
 
{
148
 
  FALSE,                        /* interlaced */
149
 
  FALSE,                        /* bkgd */
150
 
  FALSE,                        /* gama */
151
 
  TRUE,                         /* phys */
152
 
  TRUE,                         /* time */
153
 
  CHUNKS_PNG_D,                 /* default_chunks */
154
 
 
155
 
  0.75,                         /* quality */
156
 
  0.0,                          /* smoothing */
157
 
 
158
 
  9,                            /* compression_level */
159
 
 
160
 
  TRUE,                         /* loop */
161
 
  100,                          /* default_delay */
162
 
  DISPOSE_COMBINE               /* default_dispose */
163
 
};
164
 
 
165
 
 
166
 
/* The output FILE pointer which is used by libmng;
167
 
 * passed around as user data. */
168
 
struct mnglib_userdata_t
169
 
{
170
 
  FILE *fp;
171
 
};
172
 
 
173
 
 
174
 
/*
175
 
 * Function prototypes
176
 
 */
177
 
 
178
 
static mng_ptr   myalloc                   (mng_size_t        size);
179
 
static void      myfree                    (mng_ptr           ptr,
180
 
                                            mng_size_t        size);
181
 
static mng_bool  myopenstream              (mng_handle        handle);
182
 
static mng_bool  myclosestream             (mng_handle        handle);
183
 
static mng_bool  mywritedata               (mng_handle        handle,
184
 
                                            mng_ptr           buf,
185
 
                                            mng_uint32        size,
186
 
                                            mng_uint32       *written_size);
187
 
 
188
 
static gint32    parse_chunks_type_from_layer_name   (const gchar *str);
189
 
static gint32    parse_disposal_type_from_layer_name (const gchar *str);
190
 
static gint32    parse_ms_tag_from_layer_name        (const gchar *str);
191
 
 
192
 
static gint      find_unused_ia_colour     (guchar           *pixels,
193
 
                                            gint              numpixels,
194
 
                                            gint             *colors);
195
 
static gboolean  ia_has_transparent_pixels (guchar           *pixels,
196
 
                                            gint              numpixels);
197
 
static gboolean  respin_cmap               (png_structp       png_ptr,
198
 
                                            png_infop         png_info_ptr,
199
 
                                            guchar           *remap,
200
 
                                            gint32            image_id,
201
 
                                            GimpDrawable     *drawable);
202
 
 
203
 
static gint      mng_save_image            (const gchar      *filename,
204
 
                                            gint32            image_id,
205
 
                                            gint32            drawable_id,
206
 
                                            gint32            original_image_id);
207
 
static gint      mng_save_dialog           (gint32            image_id);
208
 
 
209
 
static void      query                     (void);
210
 
static void      run                       (const gchar      *name,
211
 
                                            gint              nparams,
212
 
                                            const GimpParam  *param,
213
 
                                            gint             *nreturn_vals,
214
 
                                            GimpParam       **return_vals);
215
 
 
216
 
/*
217
 
 * Callbacks for libmng
218
 
 */
219
 
 
220
 
static mng_ptr
221
 
myalloc (mng_size_t size)
222
 
{
223
 
  gpointer ptr;
224
 
  ptr = g_try_malloc ((gulong) size);
225
 
 
226
 
  if (ptr != NULL)
227
 
    memset (ptr, 0, size);
228
 
 
229
 
  return ((mng_ptr) ptr);
230
 
}
231
 
 
232
 
static void
233
 
myfree (mng_ptr    ptr,
234
 
        mng_size_t size)
235
 
{
236
 
  g_free (ptr);
237
 
}
238
 
 
239
 
static mng_bool
240
 
myopenstream (mng_handle handle)
241
 
{
242
 
  return MNG_TRUE;
243
 
}
244
 
 
245
 
static mng_bool
246
 
myclosestream (mng_handle handle)
247
 
{
248
 
  return MNG_TRUE;
249
 
}
250
 
 
251
 
static mng_bool
252
 
mywritedata (mng_handle  handle,
253
 
             mng_ptr     buf,
254
 
             mng_uint32  size,
255
 
             mng_uint32 *written_size)
256
 
{
257
 
  struct mnglib_userdata_t *userdata =
258
 
    (struct mnglib_userdata_t *) mng_get_userdata (handle);
259
 
 
260
 
 
261
 
  *written_size = (mng_uint32) fwrite ((void *) buf, 1,
262
 
                                       (size_t) size, userdata->fp);
263
 
 
264
 
  return MNG_TRUE;
265
 
}
266
 
 
267
 
 
268
 
/* Parses which output chunk type to use for this layer
269
 
 * from the layer name. */
270
 
 
271
 
static gint32
272
 
parse_chunks_type_from_layer_name (const gchar *str)
273
 
{
274
 
  guint i;
275
 
 
276
 
  for (i = 0; (i + 5) <= strlen (str); i++)
277
 
    {
278
 
      if (g_ascii_strncasecmp (str + i, "(png)", 5) == 0)
279
 
        return CHUNKS_PNG;
280
 
      else if (g_ascii_strncasecmp (str + i, "(jng)", 5) == 0)
281
 
        return CHUNKS_JNG;
282
 
    }
283
 
 
284
 
  return mng_data.default_chunks;
285
 
}
286
 
 
287
 
 
288
 
/* Parses which disposal type to use for this layer
289
 
 * from the layer name. */
290
 
 
291
 
static gint32
292
 
parse_disposal_type_from_layer_name (const gchar *str)
293
 
{
294
 
  guint i;
295
 
 
296
 
 
297
 
  for (i = 0; (i + 9) <= strlen (str); i++)
298
 
    {
299
 
      if (g_ascii_strncasecmp (str + i, "(combine)", 9) == 0)
300
 
        return DISPOSE_COMBINE;
301
 
      else if (g_ascii_strncasecmp (str + i, "(replace)", 9) == 0)
302
 
        return DISPOSE_REPLACE;
303
 
    }
304
 
 
305
 
  return mng_data.default_dispose;
306
 
}
307
 
 
308
 
 
309
 
/* Parses the millisecond delay to use for this layer
310
 
 * from the layer name. */
311
 
 
312
 
static gint32
313
 
parse_ms_tag_from_layer_name (const gchar *str)
314
 
{
315
 
  guint offset = 0;
316
 
  gint32 sum = 0;
317
 
  guint length = strlen (str);
318
 
 
319
 
 
320
 
  while (TRUE)
321
 
    {
322
 
 
323
 
      while ((offset < length) && (str[offset] != '('))
324
 
        offset++;
325
 
 
326
 
      if (offset >= length)
327
 
        return mng_data.default_delay;
328
 
 
329
 
      offset++;
330
 
 
331
 
      if (g_ascii_isdigit (str[offset]))
332
 
        break;
333
 
    }
334
 
 
335
 
  do
336
 
    {
337
 
      sum *= 10;
338
 
      sum += str[offset] - '0';
339
 
      offset++;
340
 
    }
341
 
  while ((offset < length) && (g_ascii_isdigit (str[offset])));
342
 
 
343
 
  if ((length - offset) <= 2)
344
 
    return mng_data.default_delay;
345
 
 
346
 
  if ((g_ascii_toupper (str[offset]) != 'M') ||
347
 
      (g_ascii_toupper (str[offset + 1]) != 'S'))
348
 
    return mng_data.default_delay;
349
 
 
350
 
  return sum;
351
 
}
352
 
 
353
 
 
354
 
/* Try to find a colour in the palette which isn't actually
355
 
 * used in the image, so that we can use it as the transparency
356
 
 * index. Taken from png.c */
357
 
static gint
358
 
find_unused_ia_colour (guchar *pixels,
359
 
                       gint    numpixels,
360
 
                       gint   *colors)
361
 
{
362
 
  gint     i;
363
 
  gboolean ix_used[256];
364
 
  gboolean trans_used = FALSE;
365
 
 
366
 
  for (i = 0; i < *colors; i++)
367
 
    {
368
 
      ix_used[i] = FALSE;
369
 
    }
370
 
 
371
 
  for (i = 0; i < numpixels; i++)
372
 
    {
373
 
      /* If alpha is over a threshold, the colour index in the
374
 
       * palette is taken. Otherwise, this pixel is transparent. */
375
 
      if (pixels[i * 2 + 1] > 127)
376
 
        ix_used[pixels[i * 2]] = TRUE;
377
 
      else
378
 
        trans_used = TRUE;
379
 
    }
380
 
 
381
 
  /* If there is no transparency, ignore alpha. */
382
 
  if (trans_used == FALSE)
383
 
    return -1;
384
 
 
385
 
  for (i = 0; i < *colors; i++)
386
 
    {
387
 
      if (ix_used[i] == FALSE)
388
 
        {
389
 
          return i;
390
 
        }
391
 
    }
392
 
 
393
 
  /* Couldn't find an unused colour index within the number of
394
 
     bits per pixel we wanted.  Will have to increment the number
395
 
     of colours in the image and assign a transparent pixel there. */
396
 
  if ((*colors) < 256)
397
 
    {
398
 
      (*colors)++;
399
 
      return ((*colors) - 1);
400
 
    }
401
 
 
402
 
  return (-1);
403
 
}
404
 
 
405
 
 
406
 
static gboolean
407
 
ia_has_transparent_pixels (guchar *pixels,
408
 
                           gint    numpixels)
409
 
{
410
 
  while (numpixels --)
411
 
    {
412
 
      if (pixels [1] <= 127)
413
 
        return TRUE;
414
 
      pixels += 2;
415
 
    }
416
 
  return FALSE;
417
 
}
418
 
 
419
 
 
420
 
/* Spins the color map (palette) putting the transparent color at
421
 
 * index 0 if there is space. If there isn't any space, warn the user
422
 
 * and forget about transparency. Returns TRUE if the colormap has
423
 
 * been changed and FALSE otherwise.
424
 
 */
425
 
 
426
 
static gboolean
427
 
respin_cmap (png_structp  png_ptr,
428
 
             png_infop    png_info_ptr,
429
 
             guchar       *remap,
430
 
             gint32       image_id,
431
 
             GimpDrawable *drawable)
432
 
{
433
 
  static guchar  trans[] = { 0 };
434
 
  guchar        *before;
435
 
  guchar        *pixels;
436
 
  gint           numpixels;
437
 
  gint           colors;
438
 
  gint           transparent;
439
 
  gint           cols, rows;
440
 
  GimpPixelRgn   pixel_rgn;
441
 
 
442
 
  before = gimp_image_get_colormap (image_id, &colors);
443
 
 
444
 
  /*
445
 
   * Make sure there is something in the colormap.
446
 
   */
447
 
  if (colors == 0)
448
 
    {
449
 
      before = g_new0 (guchar, 3);
450
 
      colors = 1;
451
 
    }
452
 
 
453
 
  cols      = drawable->width;
454
 
  rows      = drawable->height;
455
 
  numpixels = cols * rows;
456
 
 
457
 
  gimp_pixel_rgn_init (&pixel_rgn, drawable, 0, 0,
458
 
                       drawable->width, drawable->height, FALSE, FALSE);
459
 
 
460
 
  pixels = (guchar *) g_malloc (numpixels * 2);
461
 
 
462
 
  gimp_pixel_rgn_get_rect (&pixel_rgn, pixels, 0, 0,
463
 
                           drawable->width, drawable->height);
464
 
 
465
 
  if (ia_has_transparent_pixels (pixels, numpixels))
466
 
    {
467
 
      transparent = find_unused_ia_colour (pixels, numpixels, &colors);
468
 
 
469
 
      if (transparent != -1)
470
 
        {
471
 
          png_color palette[256];
472
 
          gint i;
473
 
 
474
 
          png_set_tRNS (png_ptr, png_info_ptr, (png_bytep) trans, 1, NULL);
475
 
 
476
 
          /* Transform all pixels with a value = transparent to
477
 
           * 0 and vice versa to compensate for re-ordering in palette
478
 
           * due to png_set_tRNS() */
479
 
 
480
 
          remap[0] = transparent;
481
 
          remap[transparent] = 0;
482
 
 
483
 
          /* Copy from index 0 to index transparent - 1 to index 1 to
484
 
           * transparent of after, then from transparent+1 to colors-1
485
 
           * unchanged, and finally from index transparent to index 0. */
486
 
 
487
 
          for (i = 0; i < colors; i++)
488
 
            {
489
 
              palette[i].red = before[3 * remap[i]];
490
 
              palette[i].green = before[3 * remap[i] + 1];
491
 
              palette[i].blue = before[3 * remap[i] + 2];
492
 
            }
493
 
 
494
 
          png_set_PLTE (png_ptr, png_info_ptr, (png_colorp) palette, colors);
495
 
 
496
 
          return TRUE;
497
 
        }
498
 
      else
499
 
        g_message (_("Couldn't losslessly save transparency, "
500
 
                     "saving opacity instead."));
501
 
    }
502
 
 
503
 
  png_set_PLTE (png_ptr, png_info_ptr, (png_colorp) before, colors);
504
 
 
505
 
  return FALSE;
506
 
}
507
 
 
508
 
 
509
 
static gint
510
 
mng_save_image (const gchar *filename,
511
 
                gint32       image_id,
512
 
                gint32       drawable_id,
513
 
                gint32       original_image_id)
514
 
{
515
 
  gint            rows, cols;
516
 
  volatile gint   i;
517
 
  time_t          t;
518
 
  struct tm      *gmt;
519
 
 
520
 
  gint            num_layers;
521
 
  gint32         *layers;
522
 
 
523
 
  struct mnglib_userdata_t *userdata;
524
 
  mng_handle      handle;
525
 
  mng_retcode     ret;
526
 
  guint32         mng_ticks_per_second;
527
 
  guint32         mng_simplicity_profile;
528
 
 
529
 
  layers = gimp_image_get_layers (image_id, &num_layers);
530
 
 
531
 
  if (num_layers < 1)
532
 
    return 0;
533
 
 
534
 
  if (num_layers > 1)
535
 
    mng_ticks_per_second = 1000;
536
 
  else
537
 
    mng_ticks_per_second = 0;
538
 
 
539
 
  rows = gimp_image_height (image_id);
540
 
  cols = gimp_image_width (image_id);
541
 
 
542
 
  mng_simplicity_profile =
543
 
    (MNG_SIMPLICITY_VALID | MNG_SIMPLICITY_SIMPLEFEATURES |
544
 
     MNG_SIMPLICITY_COMPLEXFEATURES);
545
 
  mng_simplicity_profile |= (MNG_SIMPLICITY_JNG | MNG_SIMPLICITY_DELTAPNG);     /* JNG and delta-PNG chunks exist */
546
 
 
547
 
  for (i = 0; i < num_layers; i++)
548
 
    if (gimp_drawable_has_alpha (layers[i]))
549
 
      {
550
 
        mng_simplicity_profile |= MNG_SIMPLICITY_TRANSPARENCY;  /* internal transparency exists */
551
 
        mng_simplicity_profile |= 0x00000040;   /* validity of following */
552
 
        mng_simplicity_profile |= 0x00000100;   /* semi-transparency exists */
553
 
        mng_simplicity_profile |= 0x00000080;   /* background transparency should happen */
554
 
        break;
555
 
      }
556
 
 
557
 
  userdata = g_new0 (struct mnglib_userdata_t, 1);
558
 
 
559
 
  if ((userdata->fp = g_fopen (filename, "wb")) == NULL)
560
 
    {
561
 
      g_message (_("Could not open '%s' for writing: %s"),
562
 
                 gimp_filename_to_utf8 (filename), g_strerror (errno));
563
 
      g_free (userdata);
564
 
      return 0;
565
 
    }
566
 
 
567
 
  if ((handle =
568
 
       mng_initialize ((mng_ptr) userdata, myalloc, myfree,
569
 
                       MNG_NULL)) == NULL)
570
 
    {
571
 
      g_warning ("Unable to mng_initialize() in mng_save_image()");
572
 
      fclose (userdata->fp);
573
 
      g_free (userdata);
574
 
      return 0;
575
 
    }
576
 
 
577
 
  if (((ret = mng_setcb_openstream (handle, myopenstream)) != MNG_NOERROR) ||
578
 
      ((ret = mng_setcb_closestream (handle, myclosestream)) != MNG_NOERROR)
579
 
      || ((ret = mng_setcb_writedata (handle, mywritedata)) != MNG_NOERROR))
580
 
    {
581
 
      g_warning ("Unable to setup callbacks in mng_save_image()");
582
 
      mng_cleanup (&handle);
583
 
      fclose (userdata->fp);
584
 
      g_free (userdata);
585
 
      return 0;
586
 
    }
587
 
 
588
 
  if ((ret = mng_create (handle)) != MNG_NOERROR)
589
 
    {
590
 
      g_warning ("Unable to mng_create() image in mng_save_image()");
591
 
      mng_cleanup (&handle);
592
 
      fclose (userdata->fp);
593
 
      g_free (userdata);
594
 
      return 0;
595
 
    }
596
 
 
597
 
  if ((ret =
598
 
       mng_putchunk_mhdr (handle, cols, rows, mng_ticks_per_second, 1,
599
 
                          num_layers, mng_data.default_delay,
600
 
                          mng_simplicity_profile)) != MNG_NOERROR)
601
 
    {
602
 
      g_warning ("Unable to mng_putchunk_mhdr() in mng_save_image()");
603
 
      mng_cleanup (&handle);
604
 
      fclose (userdata->fp);
605
 
      g_free (userdata);
606
 
      return 0;
607
 
    }
608
 
 
609
 
  if ((num_layers > 1) && (mng_data.loop))
610
 
    {
611
 
      if ((ret =
612
 
           mng_putchunk_term (handle, MNG_TERMACTION_REPEAT,
613
 
                              MNG_ITERACTION_LASTFRAME,
614
 
                              parse_ms_tag_from_layer_name
615
 
                              (gimp_drawable_get_name (layers[0])),
616
 
                              0x7fffffff)) != MNG_NOERROR)
617
 
        {
618
 
          g_warning ("Unable to mng_putchunk_term() in mng_save_image()");
619
 
          mng_cleanup (&handle);
620
 
          fclose (userdata->fp);
621
 
          g_free (userdata);
622
 
          return 0;
623
 
        }
624
 
    }
625
 
  else
626
 
    {
627
 
      if ((ret =
628
 
           mng_putchunk_term (handle, MNG_TERMACTION_LASTFRAME,
629
 
                              MNG_ITERACTION_LASTFRAME,
630
 
                              parse_ms_tag_from_layer_name
631
 
                              (gimp_drawable_get_name (layers[0])),
632
 
                              0x7fffffff)) != MNG_NOERROR)
633
 
        {
634
 
          g_warning ("Unable to mng_putchunk_term() in mng_save_image()");
635
 
          mng_cleanup (&handle);
636
 
          fclose (userdata->fp);
637
 
          g_free (userdata);
638
 
          return 0;
639
 
        }
640
 
    }
641
 
 
642
 
 
643
 
  /* For now, we hardwire a comment */
644
 
 
645
 
  if ((ret =
646
 
       mng_putchunk_text (handle, strlen (MNG_TEXT_TITLE), MNG_TEXT_TITLE, 22,
647
 
                          "Created using GIMP")) != MNG_NOERROR)
648
 
    {
649
 
      g_warning ("Unable to mng_putchunk_text() in mng_save_image()");
650
 
      mng_cleanup (&handle);
651
 
      fclose (userdata->fp);
652
 
      g_free (userdata);
653
 
      return 0;
654
 
    }
655
 
 
656
 
#if 0
657
 
        /* how do we get this to work? */
658
 
 
659
 
        if (mng_data.bkgd)
660
 
        {
661
 
                GimpRGB bgcolor;
662
 
                guchar red, green, blue;
663
 
 
664
 
                gimp_context_get_background(&bgcolor);
665
 
                gimp_rgb_get_uchar(&bgcolor, &red, &green, &blue);
666
 
 
667
 
                if ((ret = mng_putchunk_back(handle, red, green, blue,
668
 
                                             MNG_BACKGROUNDCOLOR_MANDATORY,
669
 
                                             0, MNG_BACKGROUNDIMAGE_NOTILE)) != MNG_NOERROR)
670
 
                {
671
 
                        g_warning("Unable to mng_putchunk_back() in mng_save_image()");
672
 
                        mng_cleanup(&handle);
673
 
                        fclose(userdata->fp);
674
 
                        g_free(userdata);
675
 
                        return 0;
676
 
                }
677
 
 
678
 
                if ((ret = mng_putchunk_bkgd(handle, MNG_FALSE, 2, 0,
679
 
                                             gimp_rgb_luminance_uchar(&bgcolor),
680
 
                                             red, green, blue)) != MNG_NOERROR)
681
 
                {
682
 
                        g_warning("Unable to mng_putchunk_bkgd() in mng_save_image()");
683
 
                        mng_cleanup(&handle);
684
 
                        fclose(userdata->fp);
685
 
                        g_free(userdata);
686
 
                        return 0;
687
 
                }
688
 
        }
689
 
#endif
690
 
 
691
 
  if (mng_data.gama)
692
 
    {
693
 
      if ((ret =
694
 
           mng_putchunk_gama (handle, MNG_FALSE,
695
 
                              (1.0 / (gimp_gamma ()) * 100000))) != MNG_NOERROR)
696
 
        {
697
 
          g_warning ("Unable to mng_putchunk_gama() in mng_save_image()");
698
 
          mng_cleanup (&handle);
699
 
          fclose (userdata->fp);
700
 
          g_free (userdata);
701
 
          return 0;
702
 
        }
703
 
    }
704
 
 
705
 
#if 0
706
 
        /* how do we get this to work? */
707
 
 
708
 
        if (mng_data.phys)
709
 
        {
710
 
                gimp_image_get_resolution(original_image_id, &xres, &yres);
711
 
 
712
 
                if ((ret = mng_putchunk_phyg(handle, MNG_FALSE, (mng_uint32) (xres * 39.37), (mng_uint32) (yres * 39.37), 1)) != MNG_NOERROR)
713
 
                {
714
 
                        g_warning("Unable to mng_putchunk_phyg() in mng_save_image()");
715
 
                        mng_cleanup(&handle);
716
 
                        fclose(userdata->fp);
717
 
                        g_free(userdata);
718
 
                        return 0;
719
 
                }
720
 
 
721
 
                if ((ret = mng_putchunk_phys(handle, MNG_FALSE, (mng_uint32) (xres * 39.37), (mng_uint32) (yres * 39.37), 1)) != MNG_NOERROR)
722
 
                {
723
 
                        g_warning("Unable to mng_putchunk_phys() in mng_save_image()");
724
 
                        mng_cleanup(&handle);
725
 
                        fclose(userdata->fp);
726
 
                        g_free(userdata);
727
 
                        return 0;
728
 
                }
729
 
        }
730
 
#endif
731
 
 
732
 
  if (mng_data.time)
733
 
    {
734
 
      t = time (NULL);
735
 
      gmt = gmtime (&t);
736
 
 
737
 
      if ((ret =
738
 
           mng_putchunk_time (handle, gmt->tm_year + 1900, gmt->tm_mon + 1,
739
 
                              gmt->tm_mday, gmt->tm_hour, gmt->tm_min,
740
 
                              gmt->tm_sec)) != MNG_NOERROR)
741
 
        {
742
 
          g_warning ("Unable to mng_putchunk_time() in mng_save_image()");
743
 
          mng_cleanup (&handle);
744
 
          fclose (userdata->fp);
745
 
          g_free (userdata);
746
 
          return 0;
747
 
        }
748
 
    }
749
 
 
750
 
  if (gimp_image_base_type (image_id) == GIMP_INDEXED)
751
 
    {
752
 
      guchar *palette;
753
 
      gint    numcolors;
754
 
 
755
 
      palette = gimp_image_get_colormap (image_id, &numcolors);
756
 
 
757
 
      if (numcolors != 0 &&
758
 
          (ret = mng_putchunk_plte (handle, numcolors, (mng_palette8e *) palette))
759
 
          != MNG_NOERROR)
760
 
        {
761
 
          g_warning ("Unable to mng_putchunk_plte() in mng_save_image()");
762
 
          mng_cleanup (&handle);
763
 
          fclose (userdata->fp);
764
 
          g_free (userdata);
765
 
          return 0;
766
 
        }
767
 
    }
768
 
 
769
 
  for (i = (num_layers - 1); i >= 0; i--)
770
 
    {
771
 
      gint            num_colors;
772
 
      GimpImageType   layer_drawable_type;
773
 
      GimpDrawable   *layer_drawable;
774
 
      gint            layer_offset_x, layer_offset_y;
775
 
      gint            layer_rows, layer_cols;
776
 
      gchar          *layer_name;
777
 
      gint            layer_chunks_type;
778
 
      volatile gint   layer_bpp;
779
 
      GimpPixelRgn    layer_pixel_rgn;
780
 
 
781
 
      guint8          layer_mng_colortype;
782
 
      guint8          layer_mng_compression_type;
783
 
      guint8          layer_mng_interlace_type;
784
 
      gboolean        layer_has_unique_palette;
785
 
 
786
 
      gchar           frame_mode;
787
 
      int             frame_delay;
788
 
      gchar          *temp_file_name;
789
 
      png_structp     png_ptr;
790
 
      png_infop       png_info_ptr;
791
 
      FILE           *infile, *outfile;
792
 
      int             num_passes;
793
 
      int             tile_height;
794
 
      guchar        **layer_pixels, *layer_pixel;
795
 
      int             pass, j, k, begin, end, num;
796
 
      guchar         *fixed;
797
 
      guchar          layer_remap[256];
798
 
 
799
 
 
800
 
      layer_name          = gimp_drawable_get_name (layers[i]);
801
 
      layer_chunks_type   = parse_chunks_type_from_layer_name (layer_name);
802
 
      layer_drawable_type = gimp_drawable_type (layers[i]);
803
 
 
804
 
      layer_drawable      = gimp_drawable_get (layers[i]);
805
 
      layer_rows          = layer_drawable->height;
806
 
      layer_cols          = layer_drawable->width;
807
 
      gimp_drawable_offsets (layers[i], &layer_offset_x, &layer_offset_y);
808
 
 
809
 
      layer_has_unique_palette = TRUE;
810
 
 
811
 
      for (j = 0; j < 256; j++)
812
 
        layer_remap[j] = j;
813
 
 
814
 
      switch (layer_drawable_type)
815
 
        {
816
 
        case GIMP_RGB_IMAGE:
817
 
          layer_bpp = 3;
818
 
          layer_mng_colortype = MNG_COLORTYPE_RGB;
819
 
          break;
820
 
        case GIMP_RGBA_IMAGE:
821
 
          layer_bpp = 4;
822
 
          layer_mng_colortype = MNG_COLORTYPE_RGBA;
823
 
          break;
824
 
        case GIMP_GRAY_IMAGE:
825
 
          layer_bpp = 1;
826
 
          layer_mng_colortype = MNG_COLORTYPE_GRAY;
827
 
          break;
828
 
        case GIMP_GRAYA_IMAGE:
829
 
          layer_bpp = 2;
830
 
          layer_mng_colortype = MNG_COLORTYPE_GRAYA;
831
 
          break;
832
 
        case GIMP_INDEXED_IMAGE:
833
 
          layer_bpp = 1;
834
 
          layer_mng_colortype = MNG_COLORTYPE_INDEXED;
835
 
          break;
836
 
        case GIMP_INDEXEDA_IMAGE:
837
 
          layer_bpp = 2;
838
 
          layer_mng_colortype = MNG_COLORTYPE_INDEXED | MNG_COLORTYPE_GRAYA;
839
 
          break;
840
 
        default:
841
 
          g_warning ("Unsupported GimpImageType in mng_save_image()");
842
 
          mng_cleanup (&handle);
843
 
          fclose (userdata->fp);
844
 
          g_free (userdata);
845
 
          return 0;
846
 
        }
847
 
 
848
 
      /* Delta PNG chunks are not yet supported */
849
 
 
850
 
      /* if (i == (num_layers - 1)) */
851
 
      {
852
 
        if (layer_chunks_type == CHUNKS_JNG_D)
853
 
          layer_chunks_type = CHUNKS_JNG;
854
 
        else if (layer_chunks_type == CHUNKS_PNG_D)
855
 
          layer_chunks_type = CHUNKS_PNG;
856
 
      }
857
 
 
858
 
      switch (layer_chunks_type)
859
 
        {
860
 
        case CHUNKS_PNG_D:
861
 
          layer_mng_compression_type = MNG_COMPRESSION_DEFLATE;
862
 
          if (mng_data.interlaced != 0)
863
 
            layer_mng_interlace_type = MNG_INTERLACE_ADAM7;
864
 
          else
865
 
            layer_mng_interlace_type = MNG_INTERLACE_NONE;
866
 
          break;
867
 
        case CHUNKS_JNG_D:
868
 
          layer_mng_compression_type = MNG_COMPRESSION_DEFLATE;
869
 
          if (mng_data.interlaced != 0)
870
 
            layer_mng_interlace_type = MNG_INTERLACE_ADAM7;
871
 
          else
872
 
            layer_mng_interlace_type = MNG_INTERLACE_NONE;
873
 
          break;
874
 
        case CHUNKS_PNG:
875
 
          layer_mng_compression_type = MNG_COMPRESSION_DEFLATE;
876
 
          if (mng_data.interlaced != 0)
877
 
            layer_mng_interlace_type = MNG_INTERLACE_ADAM7;
878
 
          else
879
 
            layer_mng_interlace_type = MNG_INTERLACE_NONE;
880
 
          break;
881
 
        case CHUNKS_JNG:
882
 
          layer_mng_compression_type = MNG_COMPRESSION_BASELINEJPEG;
883
 
          if (mng_data.interlaced != 0)
884
 
            layer_mng_interlace_type = MNG_INTERLACE_PROGRESSIVE;
885
 
          else
886
 
            layer_mng_interlace_type = MNG_INTERLACE_SEQUENTIAL;
887
 
          break;
888
 
        default:
889
 
          g_warning
890
 
            ("Huh? Programmer stupidity error with 'layer_chunks_type'");
891
 
          mng_cleanup (&handle);
892
 
          fclose (userdata->fp);
893
 
          g_free (userdata);
894
 
          return 0;
895
 
        }
896
 
 
897
 
      if ((i == (num_layers - 1))
898
 
          || (parse_disposal_type_from_layer_name (layer_name) !=
899
 
              DISPOSE_COMBINE))
900
 
        frame_mode = MNG_FRAMINGMODE_3;
901
 
      else
902
 
        frame_mode = MNG_FRAMINGMODE_1;
903
 
 
904
 
      frame_delay = parse_ms_tag_from_layer_name (layer_name);
905
 
 
906
 
      if ((ret = mng_putchunk_fram (handle, MNG_FALSE, frame_mode, 0, NULL,
907
 
                                    MNG_CHANGEDELAY_DEFAULT,
908
 
                                    MNG_CHANGETIMOUT_NO,
909
 
                                    MNG_CHANGECLIPPING_DEFAULT,
910
 
                                    MNG_CHANGESYNCID_NO,
911
 
                                    frame_delay, 0, 0,
912
 
                                    layer_offset_x,
913
 
                                    layer_offset_x + layer_cols,
914
 
                                    layer_offset_y,
915
 
                                    layer_offset_y + layer_rows,
916
 
                                    0, 0)) != MNG_NOERROR)
917
 
        {
918
 
          g_warning ("Unable to mng_putchunk_fram() in mng_save_image()");
919
 
          mng_cleanup (&handle);
920
 
          fclose (userdata->fp);
921
 
          g_free (userdata);
922
 
          return 0;
923
 
        }
924
 
 
925
 
      if ((layer_offset_x != 0) || (layer_offset_y != 0))
926
 
        if ((ret =
927
 
             mng_putchunk_defi (handle, 0, 0, 1, 1, layer_offset_x,
928
 
                                layer_offset_y, 1, layer_offset_x,
929
 
                                layer_offset_x + layer_cols, layer_offset_y,
930
 
                                layer_offset_y + layer_rows)) != MNG_NOERROR)
931
 
          {
932
 
            g_warning ("Unable to mng_putchunk_defi() in mng_save_image()");
933
 
            mng_cleanup (&handle);
934
 
            fclose (userdata->fp);
935
 
            g_free (userdata);
936
 
            return 0;
937
 
          }
938
 
 
939
 
      if ((temp_file_name = gimp_temp_name ("mng")) == NULL)
940
 
        {
941
 
          g_warning ("gimp_temp_name() failed in mng_save_image(");
942
 
          mng_cleanup (&handle);
943
 
          fclose (userdata->fp);
944
 
          g_free (userdata);
945
 
          return 0;
946
 
        }
947
 
 
948
 
      if ((outfile = g_fopen (temp_file_name, "wb")) == NULL)
949
 
        {
950
 
          g_message (_("Could not open '%s' for writing: %s"),
951
 
                     gimp_filename_to_utf8 (temp_file_name),
952
 
                     g_strerror (errno));
953
 
          g_unlink (temp_file_name);
954
 
          mng_cleanup (&handle);
955
 
          fclose (userdata->fp);
956
 
          g_free (userdata);
957
 
          return 0;
958
 
        }
959
 
 
960
 
      if ((png_ptr = png_create_write_struct (PNG_LIBPNG_VER_STRING,
961
 
                                              (png_voidp) NULL,
962
 
                                              (png_error_ptr) NULL,
963
 
                                              (png_error_ptr) NULL)) == NULL)
964
 
        {
965
 
          g_warning
966
 
            ("Unable to png_create_write_struct() in mng_save_image()");
967
 
          fclose (outfile);
968
 
          g_unlink (temp_file_name);
969
 
          mng_cleanup (&handle);
970
 
          fclose (userdata->fp);
971
 
          g_free (userdata);
972
 
          return 0;
973
 
        }
974
 
 
975
 
      if ((png_info_ptr = png_create_info_struct (png_ptr)) == NULL)
976
 
        {
977
 
          g_warning
978
 
            ("Unable to png_create_info_struct() in mng_save_image()");
979
 
          png_destroy_write_struct (&png_ptr, (png_infopp) NULL);
980
 
          fclose (outfile);
981
 
          g_unlink (temp_file_name);
982
 
          mng_cleanup (&handle);
983
 
          fclose (userdata->fp);
984
 
          g_free (userdata);
985
 
          return 0;
986
 
        }
987
 
 
988
 
      if (setjmp (png_ptr->jmpbuf) != 0)
989
 
        {
990
 
          g_warning ("HRM saving PNG in mng_save_image()");
991
 
          png_destroy_write_struct (&png_ptr, (png_infopp) NULL);
992
 
          fclose (outfile);
993
 
          g_unlink (temp_file_name);
994
 
          mng_cleanup (&handle);
995
 
          fclose (userdata->fp);
996
 
          g_free (userdata);
997
 
          return 0;
998
 
        }
999
 
 
1000
 
      png_init_io (png_ptr, outfile);
1001
 
      png_set_compression_level (png_ptr, mng_data.compression_level);
1002
 
 
1003
 
      png_info_ptr->width = layer_cols;
1004
 
      png_info_ptr->height = layer_rows;
1005
 
      png_info_ptr->interlace_type = ((mng_data.interlaced == 0) ? 0 : 1);
1006
 
      png_info_ptr->bit_depth = 8;
1007
 
 
1008
 
      switch (layer_drawable_type)
1009
 
        {
1010
 
        case GIMP_RGB_IMAGE:
1011
 
          png_info_ptr->color_type = PNG_COLOR_TYPE_RGB;
1012
 
          break;
1013
 
        case GIMP_RGBA_IMAGE:
1014
 
          png_info_ptr->color_type = PNG_COLOR_TYPE_RGB_ALPHA;
1015
 
          break;
1016
 
        case GIMP_GRAY_IMAGE:
1017
 
          png_info_ptr->color_type = PNG_COLOR_TYPE_GRAY;
1018
 
          break;
1019
 
        case GIMP_GRAYA_IMAGE:
1020
 
          png_info_ptr->color_type = PNG_COLOR_TYPE_GRAY_ALPHA;
1021
 
          break;
1022
 
        case GIMP_INDEXED_IMAGE:
1023
 
          png_info_ptr->color_type = PNG_COLOR_TYPE_PALETTE;
1024
 
          png_info_ptr->valid |= PNG_INFO_PLTE;
1025
 
          png_info_ptr->palette =
1026
 
            (png_colorp) gimp_image_get_colormap (image_id, &num_colors);
1027
 
          png_info_ptr->num_palette = num_colors;
1028
 
          break;
1029
 
        case GIMP_INDEXEDA_IMAGE:
1030
 
          png_info_ptr->color_type = PNG_COLOR_TYPE_PALETTE;
1031
 
          layer_has_unique_palette =
1032
 
            respin_cmap (png_ptr, png_info_ptr, layer_remap,
1033
 
                         image_id, layer_drawable);
1034
 
          break;
1035
 
        default:
1036
 
          g_warning ("This can't be!\n");
1037
 
          return 0;
1038
 
        }
1039
 
 
1040
 
      if ((png_info_ptr->valid & PNG_INFO_PLTE) == PNG_INFO_PLTE)
1041
 
        {
1042
 
          if (png_info_ptr->num_palette <= 2)
1043
 
            png_info_ptr->bit_depth = 1;
1044
 
          else if (png_info_ptr->num_palette <= 4)
1045
 
            png_info_ptr->bit_depth = 2;
1046
 
          else if (png_info_ptr->num_palette <= 16)
1047
 
            png_info_ptr->bit_depth = 4;
1048
 
        }
1049
 
 
1050
 
      png_write_info (png_ptr, png_info_ptr);
1051
 
 
1052
 
      if (mng_data.interlaced != 0)
1053
 
        num_passes = png_set_interlace_handling (png_ptr);
1054
 
      else
1055
 
        num_passes = 1;
1056
 
 
1057
 
      if ((png_info_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
1058
 
          && (png_info_ptr->bit_depth < 8))
1059
 
        png_set_packing (png_ptr);
1060
 
 
1061
 
      tile_height = gimp_tile_height ();
1062
 
      layer_pixel = g_new (guchar, tile_height * layer_cols * layer_bpp);
1063
 
      layer_pixels = g_new (guchar *, tile_height);
1064
 
 
1065
 
      for (j = 0; j < tile_height; j++)
1066
 
        layer_pixels[j] = layer_pixel + (layer_cols * layer_bpp * j);
1067
 
 
1068
 
      gimp_pixel_rgn_init (&layer_pixel_rgn, layer_drawable, 0, 0, layer_cols,
1069
 
                           layer_rows, FALSE, FALSE);
1070
 
 
1071
 
      for (pass = 0; pass < num_passes; pass++)
1072
 
        {
1073
 
          for (begin = 0, end = tile_height; begin < layer_rows;
1074
 
               begin += tile_height, end += tile_height)
1075
 
            {
1076
 
              if (end > layer_rows)
1077
 
                end = layer_rows;
1078
 
 
1079
 
              num = end - begin;
1080
 
              gimp_pixel_rgn_get_rect (&layer_pixel_rgn, layer_pixel, 0,
1081
 
                                       begin, layer_cols, num);
1082
 
 
1083
 
              if ((png_info_ptr->valid & PNG_INFO_tRNS) == PNG_INFO_tRNS)
1084
 
                {
1085
 
                  for (j = 0; j < num; j++)
1086
 
                    {
1087
 
                      fixed = layer_pixels[j];
1088
 
 
1089
 
                      for (k = 0; k < layer_cols; k++)
1090
 
                        fixed[k] =
1091
 
                          ((fixed[k * 2 + 1] > 127) ? layer_remap[fixed[k * 2]] : 0);
1092
 
                    }
1093
 
                }
1094
 
              else
1095
 
                if (((png_info_ptr->valid & PNG_INFO_PLTE) == PNG_INFO_PLTE)
1096
 
                    && (layer_bpp == 2))
1097
 
                {
1098
 
                  for (j = 0; j < num; j++)
1099
 
                    {
1100
 
                      fixed = layer_pixels[j];
1101
 
 
1102
 
                      for (k = 0; k < layer_cols; k++)
1103
 
                        fixed[k] = fixed[k * 2];
1104
 
                    }
1105
 
                }
1106
 
 
1107
 
              png_write_rows (png_ptr, layer_pixels, num);
1108
 
            }
1109
 
        }
1110
 
 
1111
 
      png_write_end (png_ptr, png_info_ptr);
1112
 
      png_destroy_write_struct (&png_ptr, &png_info_ptr);
1113
 
 
1114
 
      g_free (layer_pixels);
1115
 
      g_free (layer_pixel);
1116
 
 
1117
 
      fclose (outfile);
1118
 
 
1119
 
      if ((infile = g_fopen (temp_file_name, "rb")) == NULL)
1120
 
        {
1121
 
          g_message (_("Could not open '%s' for reading: %s"),
1122
 
                     gimp_filename_to_utf8 (temp_file_name),
1123
 
                     g_strerror (errno));
1124
 
          g_unlink (temp_file_name);
1125
 
          mng_cleanup (&handle);
1126
 
          fclose (userdata->fp);
1127
 
          g_free (userdata);
1128
 
          return 0;
1129
 
        }
1130
 
 
1131
 
      fseek (infile, 8L, SEEK_SET);
1132
 
 
1133
 
      while (!feof (infile))
1134
 
        {
1135
 
          guchar  chunksize_chars[4];
1136
 
          gulong  chunksize;
1137
 
          gchar   chunkname[5];
1138
 
          guchar *chunkbuffer;
1139
 
          glong   chunkwidth;
1140
 
          glong   chunkheight;
1141
 
          gchar   chunkbitdepth;
1142
 
          gchar   chunkcolortype;
1143
 
          gchar   chunkcompression;
1144
 
          gchar   chunkfilter;
1145
 
          gchar   chunkinterlaced;
1146
 
 
1147
 
 
1148
 
          if (fread (chunksize_chars, 1, 4, infile) != 4)
1149
 
            break;
1150
 
 
1151
 
          if (fread (chunkname, 1, 4, infile) != 4)
1152
 
            break;
1153
 
 
1154
 
          chunkname[4] = 0;
1155
 
 
1156
 
          chunksize = (chunksize_chars[0] << 24) | (chunksize_chars[1] << 16)
1157
 
            | (chunksize_chars[2] << 8) | chunksize_chars[3];
1158
 
 
1159
 
          chunkbuffer = NULL;
1160
 
 
1161
 
          if (chunksize > 0)
1162
 
            {
1163
 
              chunkbuffer = g_new (guchar, chunksize);
1164
 
 
1165
 
              if (fread (chunkbuffer, 1, chunksize, infile) != chunksize)
1166
 
                break;
1167
 
            }
1168
 
 
1169
 
          if (strncmp (chunkname, "IHDR", 4) == 0)
1170
 
            {
1171
 
              chunkwidth = (chunkbuffer[0] << 24) | (chunkbuffer[1] << 16)
1172
 
                | (chunkbuffer[2] << 8) | chunkbuffer[3];
1173
 
 
1174
 
              chunkheight = (chunkbuffer[4] << 24) | (chunkbuffer[5] << 16)
1175
 
                | (chunkbuffer[6] << 8) | chunkbuffer[7];
1176
 
 
1177
 
              chunkbitdepth = chunkbuffer[8];
1178
 
              chunkcolortype = chunkbuffer[9];
1179
 
              chunkcompression = chunkbuffer[10];
1180
 
              chunkfilter = chunkbuffer[11];
1181
 
              chunkinterlaced = chunkbuffer[12];
1182
 
 
1183
 
              if ((ret =
1184
 
                   mng_putchunk_ihdr (handle, chunkwidth, chunkheight,
1185
 
                                      chunkbitdepth, chunkcolortype,
1186
 
                                      chunkcompression, chunkfilter,
1187
 
                                      chunkinterlaced)) != MNG_NOERROR)
1188
 
                {
1189
 
                  g_warning
1190
 
                    ("Unable to mng_putchunk_ihdr() in mng_save_image()");
1191
 
                  mng_cleanup (&handle);
1192
 
                  fclose (userdata->fp);
1193
 
                  g_free (userdata);
1194
 
                  return 0;
1195
 
                }
1196
 
            }
1197
 
          else if (strncmp (chunkname, "IDAT", 4) == 0)
1198
 
            {
1199
 
              if ((ret =
1200
 
                   mng_putchunk_idat (handle, chunksize,
1201
 
                                      chunkbuffer)) != MNG_NOERROR)
1202
 
                {
1203
 
                  g_warning
1204
 
                    ("Unable to mng_putchunk_idat() in mng_save_image()");
1205
 
                  mng_cleanup (&handle);
1206
 
                  fclose (userdata->fp);
1207
 
                  g_free (userdata);
1208
 
                  return 0;
1209
 
                }
1210
 
            }
1211
 
          else if (strncmp (chunkname, "IEND", 4) == 0)
1212
 
            {
1213
 
              if ((ret = mng_putchunk_iend (handle)) != MNG_NOERROR)
1214
 
                {
1215
 
                  g_warning
1216
 
                    ("Unable to mng_putchunk_iend() in mng_save_image()");
1217
 
                  mng_cleanup (&handle);
1218
 
                  fclose (userdata->fp);
1219
 
                  g_free (userdata);
1220
 
                  return 0;
1221
 
                }
1222
 
            }
1223
 
          else if (strncmp (chunkname, "PLTE", 4) == 0)
1224
 
            {
1225
 
              /* if this frame's palette is the same as the global palette,
1226
 
                 write a 0-color palette chunk */
1227
 
              if ((ret =
1228
 
                   mng_putchunk_plte (handle,
1229
 
                                      layer_has_unique_palette ? (chunksize / 3) : 0,
1230
 
                                      (mng_palette8e *) chunkbuffer))
1231
 
                  != MNG_NOERROR)
1232
 
                {
1233
 
                  g_warning
1234
 
                    ("Unable to mng_putchunk_plte() in mng_save_image()");
1235
 
                  mng_cleanup (&handle);
1236
 
                  fclose (userdata->fp);
1237
 
                  g_free (userdata);
1238
 
                  return 0;
1239
 
                }
1240
 
            }
1241
 
          else if (strncmp (chunkname, "tRNS", 4) == 0)
1242
 
            {
1243
 
              if ((ret =
1244
 
                   mng_putchunk_trns (handle, 0, 0, 3, chunksize,
1245
 
                                      (mng_uint8 *) chunkbuffer, 0, 0, 0, 0,
1246
 
                                      0,
1247
 
                                      (mng_uint8 *) chunkbuffer)) !=
1248
 
                  MNG_NOERROR)
1249
 
                {
1250
 
                  g_warning
1251
 
                    ("Unable to mng_putchunk_trns() in mng_save_image()");
1252
 
                  mng_cleanup (&handle);
1253
 
                  fclose (userdata->fp);
1254
 
                  g_free (userdata);
1255
 
                  return 0;
1256
 
                }
1257
 
            }
1258
 
 
1259
 
          if (chunksize > 0)
1260
 
            g_free (chunkbuffer);
1261
 
 
1262
 
          /* read 4 bytes after the chunk */
1263
 
 
1264
 
          fread (chunkname, 1, 4, infile);
1265
 
        }
1266
 
 
1267
 
      fclose (infile);
1268
 
      g_unlink (temp_file_name);
1269
 
    }
1270
 
 
1271
 
  if ((ret = mng_putchunk_mend (handle)) != MNG_NOERROR)
1272
 
    {
1273
 
      g_warning ("Unable to mng_putchunk_mend() in mng_save_image()");
1274
 
      mng_cleanup (&handle);
1275
 
      fclose (userdata->fp);
1276
 
      g_free (userdata);
1277
 
      return 0;
1278
 
    }
1279
 
 
1280
 
  if ((ret = mng_write (handle)) != MNG_NOERROR)
1281
 
    {
1282
 
      g_warning ("Unable to mng_write() the image in mng_save_image()");
1283
 
      mng_cleanup (&handle);
1284
 
      fclose (userdata->fp);
1285
 
      g_free (userdata);
1286
 
      return 0;
1287
 
    }
1288
 
 
1289
 
  mng_cleanup (&handle);
1290
 
  fclose (userdata->fp);
1291
 
  g_free (userdata);
1292
 
 
1293
 
  return TRUE;
1294
 
}
1295
 
 
1296
 
 
1297
 
/* The interactive dialog. */
1298
 
 
1299
 
static gint
1300
 
mng_save_dialog (gint32 image_id)
1301
 
{
1302
 
  GtkWidget *dialog;
1303
 
  GtkWidget *main_vbox;
1304
 
  GtkWidget *frame;
1305
 
  GtkWidget *vbox;
1306
 
  GtkWidget *table;
1307
 
  GtkWidget *toggle;
1308
 
  GtkWidget *hbox;
1309
 
  GtkWidget *combo;
1310
 
  GtkWidget *label;
1311
 
  GtkWidget *scale;
1312
 
  GtkObject *scale_adj;
1313
 
  GtkWidget *spinbutton;
1314
 
  GtkObject *spinbutton_adj;
1315
 
  gint       num_layers;
1316
 
  gboolean   run;
1317
 
 
1318
 
 
1319
 
  dialog = gimp_dialog_new (_("Save as MNG"), PLUG_IN_BINARY,
1320
 
                            NULL, 0,
1321
 
                            gimp_standard_help_func, SAVE_PROC,
1322
 
 
1323
 
                            GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
1324
 
                            GTK_STOCK_SAVE,   GTK_RESPONSE_OK,
1325
 
 
1326
 
                            NULL);
1327
 
 
1328
 
  gtk_dialog_set_alternative_button_order (GTK_DIALOG (dialog),
1329
 
                                           GTK_RESPONSE_OK,
1330
 
                                           GTK_RESPONSE_CANCEL,
1331
 
                                           -1);
1332
 
 
1333
 
  gimp_window_set_transient (GTK_WINDOW (dialog));
1334
 
 
1335
 
  main_vbox = gtk_vbox_new (FALSE, 12);
1336
 
  gtk_container_set_border_width (GTK_CONTAINER (main_vbox), 12);
1337
 
  gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), main_vbox);
1338
 
 
1339
 
  frame = gimp_frame_new (_("MNG Options"));
1340
 
  gtk_box_pack_start (GTK_BOX (main_vbox), frame, TRUE, TRUE, 0);
1341
 
 
1342
 
  vbox = gtk_vbox_new (FALSE, 6);
1343
 
  gtk_container_add (GTK_CONTAINER (frame), vbox);
1344
 
 
1345
 
  toggle = gtk_check_button_new_with_label (_("Interlace"));
1346
 
  gtk_box_pack_start (GTK_BOX (vbox), toggle, FALSE, FALSE, 0);
1347
 
 
1348
 
  g_signal_connect (toggle, "toggled",
1349
 
                    G_CALLBACK (gimp_toggle_button_update),
1350
 
                    &mng_data.interlaced);
1351
 
 
1352
 
  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle),
1353
 
                                mng_data.interlaced);
1354
 
 
1355
 
  gtk_widget_show (toggle);
1356
 
 
1357
 
  toggle = gtk_check_button_new_with_label (_("Save background color"));
1358
 
  gtk_widget_set_sensitive (toggle, FALSE);
1359
 
  gtk_box_pack_start (GTK_BOX (vbox), toggle, FALSE, FALSE, 0);
1360
 
  g_signal_connect (toggle, "toggled",
1361
 
                    G_CALLBACK (gimp_toggle_button_update),
1362
 
                    &mng_data.bkgd);
1363
 
 
1364
 
  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle), mng_data.bkgd);
1365
 
 
1366
 
  gtk_widget_show (toggle);
1367
 
 
1368
 
  toggle = gtk_check_button_new_with_label (_("Save gamma"));
1369
 
  gtk_box_pack_start (GTK_BOX (vbox), toggle, FALSE, FALSE, 0);
1370
 
  g_signal_connect (toggle, "toggled",
1371
 
                    G_CALLBACK (gimp_toggle_button_update),
1372
 
                    &mng_data.gama);
1373
 
 
1374
 
  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle), mng_data.gama);
1375
 
 
1376
 
  gtk_widget_show (toggle);
1377
 
 
1378
 
  toggle = gtk_check_button_new_with_label (_("Save resolution"));
1379
 
  gtk_widget_set_sensitive (toggle, FALSE);
1380
 
  gtk_box_pack_start (GTK_BOX (vbox), toggle, FALSE, FALSE, 0);
1381
 
  g_signal_connect (toggle, "toggled",
1382
 
                    G_CALLBACK (gimp_toggle_button_update),
1383
 
                    &mng_data.phys);
1384
 
 
1385
 
  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle), mng_data.phys);
1386
 
 
1387
 
  gtk_widget_show (toggle);
1388
 
 
1389
 
  toggle = gtk_check_button_new_with_label (_("Save creation time"));
1390
 
  gtk_box_pack_start (GTK_BOX (vbox), toggle, FALSE, FALSE, 0);
1391
 
  g_signal_connect (toggle, "toggled",
1392
 
                    G_CALLBACK (gimp_toggle_button_update),
1393
 
                    &mng_data.time);
1394
 
 
1395
 
  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle), mng_data.time);
1396
 
 
1397
 
  gtk_widget_show (toggle);
1398
 
 
1399
 
  table = gtk_table_new (2, 4, FALSE);
1400
 
  gtk_table_set_col_spacings (GTK_TABLE (table), 6);
1401
 
  gtk_table_set_row_spacings (GTK_TABLE (table), 6);
1402
 
  gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, FALSE, 0);
1403
 
  gtk_widget_show (table);
1404
 
 
1405
 
  gimp_image_get_layers (image_id, &num_layers);
1406
 
 
1407
 
  if (num_layers == 1)
1408
 
    combo = gimp_int_combo_box_new (_("PNG"), CHUNKS_PNG_D,
1409
 
                                    _("JNG"), CHUNKS_JNG_D,
1410
 
                                    NULL);
1411
 
  else
1412
 
    combo = gimp_int_combo_box_new (_("PNG + delta PNG"), CHUNKS_PNG_D,
1413
 
                                    _("JNG + delta PNG"), CHUNKS_JNG_D,
1414
 
                                    _("All PNG"),         CHUNKS_PNG,
1415
 
                                    _("All JNG"),         CHUNKS_JNG,
1416
 
                                    NULL);
1417
 
 
1418
 
  gimp_int_combo_box_set_active (GIMP_INT_COMBO_BOX (combo),
1419
 
                                 mng_data.default_chunks);
1420
 
 
1421
 
  g_signal_connect (combo, "changed",
1422
 
                    G_CALLBACK (gimp_int_combo_box_get_active),
1423
 
                    &mng_data.default_chunks);
1424
 
 
1425
 
  gtk_widget_set_sensitive (combo, FALSE);
1426
 
  gimp_table_attach_aligned (GTK_TABLE (table), 0, 0,
1427
 
                             _("Default chunks type:"), 0.0, 0.5,
1428
 
                             combo, 1, FALSE);
1429
 
 
1430
 
  combo = gimp_int_combo_box_new (_("Combine"), DISPOSE_COMBINE,
1431
 
                                  _("Replace"), DISPOSE_REPLACE,
1432
 
                                  NULL);
1433
 
 
1434
 
  gimp_int_combo_box_set_active (GIMP_INT_COMBO_BOX (combo),
1435
 
                                 mng_data.default_dispose);
1436
 
 
1437
 
  g_signal_connect (combo, "changed",
1438
 
                    G_CALLBACK (gimp_int_combo_box_get_active),
1439
 
                    &mng_data.default_dispose);
1440
 
 
1441
 
  gimp_table_attach_aligned (GTK_TABLE (table), 0, 1,
1442
 
                             _("Default frame disposal:"), 0.0, 0.5,
1443
 
                             combo, 1, FALSE);
1444
 
 
1445
 
  scale_adj = gtk_adjustment_new (mng_data.compression_level,
1446
 
                                  0.0, 9.0, 1.0, 1.0, 0.0);
1447
 
 
1448
 
  scale = gtk_hscale_new (GTK_ADJUSTMENT (scale_adj));
1449
 
  gtk_widget_set_size_request (scale, SCALE_WIDTH, -1);
1450
 
  gtk_scale_set_value_pos (GTK_SCALE (scale), GTK_POS_TOP);
1451
 
  gtk_scale_set_digits (GTK_SCALE (scale), 0);
1452
 
  gtk_range_set_update_policy (GTK_RANGE (scale), GTK_UPDATE_DELAYED);
1453
 
  gimp_table_attach_aligned (GTK_TABLE (table), 0, 2,
1454
 
                             _("PNG compression level:"), 0.0, 0.9,
1455
 
                             scale, 1, FALSE);
1456
 
 
1457
 
  g_signal_connect (scale_adj, "value-changed",
1458
 
                    G_CALLBACK (gimp_int_adjustment_update),
1459
 
                    &mng_data.compression_level);
1460
 
 
1461
 
  gimp_help_set_help_data (scale,
1462
 
                           _("Choose a high compression level "
1463
 
                             "for small file size"),
1464
 
                           NULL);
1465
 
 
1466
 
  scale_adj = gtk_adjustment_new (mng_data.quality,
1467
 
                                  0.0, 1.0, 0.01, 0.01, 0.0);
1468
 
 
1469
 
  scale = gtk_hscale_new (GTK_ADJUSTMENT (scale_adj));
1470
 
  gtk_widget_set_size_request (scale, SCALE_WIDTH, -1);
1471
 
  gtk_scale_set_value_pos (GTK_SCALE (scale), GTK_POS_TOP);
1472
 
  gtk_scale_set_digits (GTK_SCALE (scale), 2);
1473
 
  gtk_range_set_update_policy (GTK_RANGE (scale), GTK_UPDATE_DELAYED);
1474
 
  gtk_widget_set_sensitive (scale, FALSE);
1475
 
  gimp_table_attach_aligned (GTK_TABLE (table), 0, 3,
1476
 
                             _("JPEG compression quality:"), 0.0, 0.9,
1477
 
                             scale, 1, FALSE);
1478
 
 
1479
 
  g_signal_connect (scale_adj, "value-changed",
1480
 
                    G_CALLBACK (gimp_int_adjustment_update),
1481
 
                    &mng_data.quality);
1482
 
 
1483
 
  scale_adj = gtk_adjustment_new (mng_data.smoothing,
1484
 
                                  0.0, 1.0, 0.01, 0.01, 0.0);
1485
 
 
1486
 
  scale = gtk_hscale_new (GTK_ADJUSTMENT (scale_adj));
1487
 
  gtk_widget_set_size_request (scale, SCALE_WIDTH, -1);
1488
 
  gtk_scale_set_value_pos (GTK_SCALE (scale), GTK_POS_TOP);
1489
 
  gtk_scale_set_digits (GTK_SCALE (scale), 2);
1490
 
  gtk_range_set_update_policy (GTK_RANGE (scale), GTK_UPDATE_DELAYED);
1491
 
  gtk_widget_set_sensitive (scale, FALSE);
1492
 
  gimp_table_attach_aligned (GTK_TABLE (table), 0, 4,
1493
 
                             _("JPEG smoothing factor:"), 0.0, 0.9,
1494
 
                             scale, 1, FALSE);
1495
 
 
1496
 
  g_signal_connect (scale_adj, "value-changed",
1497
 
                    G_CALLBACK (gimp_int_adjustment_update),
1498
 
                    &mng_data.smoothing);
1499
 
 
1500
 
  gtk_widget_show (vbox);
1501
 
  gtk_widget_show (frame);
1502
 
 
1503
 
  frame = gimp_frame_new (_("Animated MNG Options"));
1504
 
  gtk_box_pack_start (GTK_BOX (main_vbox), frame, TRUE, TRUE, 0);
1505
 
 
1506
 
  vbox = gtk_vbox_new (FALSE, 6);
1507
 
  gtk_container_add (GTK_CONTAINER (frame), vbox);
1508
 
 
1509
 
  toggle = gtk_check_button_new_with_label (_("Loop"));
1510
 
  gtk_box_pack_start (GTK_BOX (vbox), toggle, FALSE, FALSE, 0);
1511
 
  g_signal_connect (toggle, "toggled",
1512
 
                    G_CALLBACK (gimp_toggle_button_update),
1513
 
                    &mng_data.loop);
1514
 
 
1515
 
  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle),
1516
 
                                mng_data.loop);
1517
 
 
1518
 
  gtk_widget_show (toggle);
1519
 
 
1520
 
  hbox = gtk_hbox_new (FALSE, 4);
1521
 
  gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
1522
 
 
1523
 
  label = gtk_label_new (_("Default frame delay:"));
1524
 
  gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
1525
 
  gtk_widget_show (label);
1526
 
 
1527
 
  spinbutton = gimp_spin_button_new (&spinbutton_adj,
1528
 
                                     mng_data.default_delay,
1529
 
                                     0, 65000, 10, 100, 0, 1, 0);
1530
 
 
1531
 
  g_signal_connect (spinbutton_adj, "value-changed",
1532
 
                    G_CALLBACK (gimp_int_adjustment_update),
1533
 
                    &mng_data.default_delay);
1534
 
 
1535
 
  gtk_box_pack_start (GTK_BOX (hbox), spinbutton, FALSE, FALSE, 0);
1536
 
 
1537
 
  gtk_widget_show (spinbutton);
1538
 
 
1539
 
  label = gtk_label_new (_("milliseconds"));
1540
 
  gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
1541
 
  gtk_widget_show (label);
1542
 
 
1543
 
  gtk_widget_show (hbox);
1544
 
 
1545
 
  gtk_widget_show (vbox);
1546
 
  gtk_widget_show (frame);
1547
 
 
1548
 
  gtk_widget_set_sensitive (frame, num_layers > 1);
1549
 
 
1550
 
  gtk_widget_show (main_vbox);
1551
 
  gtk_widget_show (dialog);
1552
 
 
1553
 
  run = (gimp_dialog_run (GIMP_DIALOG (dialog)) == GTK_RESPONSE_OK);
1554
 
 
1555
 
  gtk_widget_destroy (dialog);
1556
 
 
1557
 
  return run;
1558
 
}
1559
 
 
1560
 
 
1561
 
/* GIMP calls these methods. */
1562
 
 
1563
 
static void
1564
 
query (void)
1565
 
{
1566
 
  static const GimpParamDef save_args[] =
1567
 
  {
1568
 
    { GIMP_PDB_INT32,    "run-mode",        "Interactive, non-interactive" },
1569
 
    { GIMP_PDB_IMAGE,    "image",           "Input image" },
1570
 
    { GIMP_PDB_DRAWABLE, "drawable",        "Drawable to save" },
1571
 
    { GIMP_PDB_STRING,   "filename",        "The name of the file to save the image in" },
1572
 
    { GIMP_PDB_STRING,   "raw-filename",    "The name of the file to save the image in" },
1573
 
 
1574
 
    { GIMP_PDB_INT32,    "interlace",       "Use interlacing" },
1575
 
    { GIMP_PDB_INT32,    "compression",     "PNG deflate compression level (0 - 9)" },
1576
 
    { GIMP_PDB_FLOAT,    "quality",         "JPEG quality factor (0.00 - 1.00)" },
1577
 
    { GIMP_PDB_FLOAT,    "smoothing",       "JPEG smoothing factor (0.00 - 1.00)" },
1578
 
    { GIMP_PDB_INT32,    "loop",            "(ANIMATED MNG) Loop infinitely" },
1579
 
    { GIMP_PDB_INT32,    "default-delay",   "(ANIMATED MNG) Default delay between frames in milliseconds" },
1580
 
    { GIMP_PDB_INT32,    "default-chunks",  "(ANIMATED MNG) Default chunks type (0 = PNG + Delta PNG; 1 = JNG + Delta PNG; 2 = All PNG; 3 = All JNG)" },
1581
 
    { GIMP_PDB_INT32,    "default-dispose", "(ANIMATED MNG) Default dispose type (0 = combine; 1 = replace)" },
1582
 
    { GIMP_PDB_INT32,    "bkgd",            "Write bKGD (background color) chunk" },
1583
 
    { GIMP_PDB_INT32,    "gama",            "Write gAMA (gamma) chunk"},
1584
 
    { GIMP_PDB_INT32,    "phys",            "Write pHYs (image resolution) chunk" },
1585
 
    { GIMP_PDB_INT32,    "time",            "Write tIME (creation time) chunk" }
1586
 
  };
1587
 
 
1588
 
  gimp_install_procedure (SAVE_PROC,
1589
 
                          "Saves images in the MNG file format",
1590
 
                          "This plug-in saves images in the Multiple-image "
1591
 
                          "Network Graphics (MNG) format which can be used as "
1592
 
                          "a replacement for animated GIFs, and more.",
1593
 
                          "S. Mukund <muks@mukund.org>",
1594
 
                          "S. Mukund <muks@mukund.org>",
1595
 
                          "November 19, 2002",
1596
 
                          N_("MNG animation"),
1597
 
                          "RGB*,GRAY*,INDEXED*",
1598
 
                          GIMP_PLUGIN,
1599
 
                          G_N_ELEMENTS (save_args), 0,
1600
 
                          save_args, NULL);
1601
 
 
1602
 
  gimp_register_file_handler_mime (SAVE_PROC, "image/x-mng");
1603
 
  gimp_register_save_handler (SAVE_PROC, "mng", "");
1604
 
}
1605
 
 
1606
 
static void
1607
 
run (const gchar      *name,
1608
 
     gint              nparams,
1609
 
     const GimpParam  *param,
1610
 
     gint             *nreturn_vals,
1611
 
     GimpParam       **return_vals)
1612
 
{
1613
 
  static GimpParam values[1];
1614
 
 
1615
 
  INIT_I18N ();
1616
 
 
1617
 
  *nreturn_vals = 1;
1618
 
  *return_vals  = values;
1619
 
  values[0].type          = GIMP_PDB_STATUS;
1620
 
  values[0].data.d_status = GIMP_PDB_SUCCESS;
1621
 
 
1622
 
  if (strcmp (name, SAVE_PROC) == 0)
1623
 
    {
1624
 
      GimpRunMode      run_mode;
1625
 
      gint32           image_id, original_image_id;
1626
 
      gint32           drawable_id;
1627
 
      GimpExportReturn export = GIMP_EXPORT_IGNORE;
1628
 
 
1629
 
      run_mode = param[0].data.d_int32;
1630
 
      image_id = original_image_id = param[1].data.d_int32;
1631
 
      drawable_id = param[2].data.d_int32;
1632
 
 
1633
 
      if ((run_mode == GIMP_RUN_INTERACTIVE)
1634
 
          || (run_mode == GIMP_RUN_WITH_LAST_VALS))
1635
 
        {
1636
 
          gimp_procedural_db_get_data (SAVE_PROC, &mng_data);
1637
 
 
1638
 
          gimp_ui_init (PLUG_IN_BINARY, FALSE);
1639
 
          export = gimp_export_image (&image_id, &drawable_id, "MNG",
1640
 
                                      (GIMP_EXPORT_CAN_HANDLE_RGB |
1641
 
                                       GIMP_EXPORT_CAN_HANDLE_GRAY |
1642
 
                                       GIMP_EXPORT_CAN_HANDLE_INDEXED |
1643
 
                                       GIMP_EXPORT_CAN_HANDLE_ALPHA |
1644
 
                                       GIMP_EXPORT_CAN_HANDLE_LAYERS_AS_ANIMATION));
1645
 
        }
1646
 
 
1647
 
      if (export == GIMP_EXPORT_CANCEL)
1648
 
        values[0].data.d_status = GIMP_PDB_CANCEL;
1649
 
      else if ((export == GIMP_EXPORT_IGNORE)
1650
 
               || (export == GIMP_EXPORT_EXPORT))
1651
 
        {
1652
 
          if (run_mode == GIMP_RUN_INTERACTIVE)
1653
 
            {
1654
 
              if (mng_save_dialog (image_id) == 0)
1655
 
                values[0].data.d_status = GIMP_PDB_CANCEL;
1656
 
            }
1657
 
          else if (run_mode == GIMP_RUN_NONINTERACTIVE)
1658
 
            {
1659
 
              if (nparams != 17)
1660
 
                {
1661
 
                  g_message ("Incorrect number of parameters "
1662
 
                             "passed to file-mng-save()");
1663
 
                  values[0].data.d_status = GIMP_PDB_CALLING_ERROR;
1664
 
                }
1665
 
              else
1666
 
                {
1667
 
                  mng_data.interlaced = param[5].data.d_int32;
1668
 
                  mng_data.compression_level = param[6].data.d_int32;
1669
 
                  mng_data.quality = param[7].data.d_float;
1670
 
                  mng_data.smoothing = param[8].data.d_float;
1671
 
                  mng_data.loop = param[9].data.d_int32;
1672
 
                  mng_data.default_delay = param[10].data.d_int32;
1673
 
                  mng_data.default_chunks = param[11].data.d_int32;
1674
 
                  mng_data.default_dispose = param[12].data.d_int32;
1675
 
                  mng_data.bkgd = param[13].data.d_int32;
1676
 
                  mng_data.gama = param[14].data.d_int32;
1677
 
                  mng_data.phys = param[15].data.d_int32;
1678
 
                  mng_data.time = param[16].data.d_int32;
1679
 
 
1680
 
                  if ((mng_data.compression_level < 0)
1681
 
                      || (mng_data.compression_level > 9))
1682
 
                    {
1683
 
                      g_warning ("Parameter 'compression_level' passed to file-mng-save() must be in the range 0 - 9; Clamping it to the default value of 6.");
1684
 
                      mng_data.compression_level = 6;
1685
 
                    }
1686
 
 
1687
 
                  if ((mng_data.quality < ((float) 0))
1688
 
                      || (mng_data.quality > ((float) 1)))
1689
 
                    {
1690
 
                      g_warning ("Parameter 'quality' passed to file-mng-save() must be in the range 0.00 - 1.00; Clamping it to the default value of 0.75.");
1691
 
                      mng_data.quality = 0.75;
1692
 
                    }
1693
 
 
1694
 
                  if ((mng_data.smoothing < ((float) 0))
1695
 
                      || (mng_data.smoothing > ((float) 1)))
1696
 
                    {
1697
 
                      g_warning ("Parameter 'smoothing' passed to file-mng-save() must be in the range 0.00 - 1.00; Clamping it to the default value of 0.00.");
1698
 
                      mng_data.smoothing = 0.0;
1699
 
                    }
1700
 
 
1701
 
                  if ((mng_data.default_chunks < 0)
1702
 
                      || (mng_data.default_chunks > 3))
1703
 
                    {
1704
 
                      g_warning ("Parameter 'default_chunks' passed to file-mng-save() must be in the range 0 - 2.");
1705
 
                      values[0].data.d_status = GIMP_PDB_CALLING_ERROR;
1706
 
                    }
1707
 
 
1708
 
                  if ((mng_data.default_dispose < 0)
1709
 
                      || (mng_data.default_dispose > 1))
1710
 
                    {
1711
 
                      g_warning ("Parameter 'default_dispose' passed to file-mng-save() must be in the range 0 - 1.");
1712
 
                      values[0].data.d_status = GIMP_PDB_CALLING_ERROR;
1713
 
                    }
1714
 
                }
1715
 
            }
1716
 
 
1717
 
          if (values[0].data.d_status == GIMP_PDB_SUCCESS)
1718
 
            {
1719
 
              if (mng_save_image
1720
 
                  (param[3].data.d_string, image_id, drawable_id,
1721
 
                   original_image_id) != 0)
1722
 
                gimp_set_data (SAVE_PROC, &mng_data, sizeof (mng_data));
1723
 
              else
1724
 
                values[0].data.d_status = GIMP_PDB_EXECUTION_ERROR;
1725
 
            }
1726
 
 
1727
 
          if (export == GIMP_EXPORT_EXPORT)
1728
 
            gimp_image_delete (image_id);
1729
 
        }
1730
 
 
1731
 
    }
1732
 
  else
1733
 
    values[0].data.d_status = GIMP_PDB_EXECUTION_ERROR;
1734
 
}
1735
 
 
1736
 
 
1737
 
/* Only query and run are implemented by this plug-in. */
1738
 
 
1739
 
const GimpPlugInInfo PLUG_IN_INFO =
1740
 
{
1741
 
  NULL,
1742
 
  NULL,
1743
 
  query,
1744
 
  run
1745
 
};
1746
 
 
1747
 
MAIN ()