~ubuntu-branches/ubuntu/breezy/gimp/breezy

« back to all changes in this revision

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

  • Committer: Bazaar Package Importer
  • Author(s): Sebastien Bacher
  • Date: 2005-10-04 19:04:46 UTC
  • Revision ID: james.westby@ubuntu.com-20051004190446-ukh32kwk56s4sjhu
Tags: upstream-2.2.8
ImportĀ upstreamĀ versionĀ 2.2.8

Show diffs side-by-side

added added

removed removed

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