jpeg.h 64.6 KB
Newer Older
Elliot Lee's avatar
Elliot Lee committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/* The GIMP -- an image manipulation program
 * Copyright (C) 1995 Spencer Kimball and Peter Mattis
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
16
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
Elliot Lee's avatar
Elliot Lee committed
17
18
19
20
21
22
23
24
25
26
 */

/* JPEG loading and saving file filter for the GIMP
 *  -Peter Mattis
 *
 * This filter is heavily based upon the "example.c" file in libjpeg.
 * In fact most of the loading and saving code was simply cut-and-pasted
 *  from that file. The filter, therefore, also uses libjpeg.
 */

27
28
29
30
31
32
33
34
35
36
37
/* 11-JAN-99 - Added support for JPEG comments and Progressive saves.
 *  -pete whiting <pwhiting@sprint.net>
 *
 * Comments of size up to 32k can be stored in the header of jpeg
 * files.  (They are not compressed.)  The JPEG specs and libraries
 * support the storing of multiple comments.  The behavior of this
 * code is to merge all comments in a loading image into a single
 * comment (putting \n between each) and attach that string as a
 * parasite - gimp-comment - to the image.  When saving, the image is
 * checked to see if it has the gimp-comment parasite - if so, that is
 * used as the default comment in the save dialog.  Further, the other
38
 * jpeg parameters (quality, smoothing, compression and progressive)
39
40
 * are attached to the image as a parasite.  This allows the
 * parameters to remain consistent between saves.  I was not able to
41
 * figure out how to determine the quality, smoothing or compression
42
43
44
45
46
47
 * values of an image as it is being loaded, but the code is there to
 * support it if anyone knows how.  Progressive mode is a method of
 * saving the image such that as a browser (or other app supporting
 * progressive loads - gimp doesn't) loads the image it first gets a
 * low res version displayed and then the image is progressively
 * enhanced until you get the final version.  It doesn't add any size
48
49
50
 * to the image (actually it often results in smaller file size) - the
 * only draw backs are that progressive jpegs are not supported by some
 * older viewers/browsers, and some might find it annoying.
51
52
 */

53
/*
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
 * 21-AUG-99 - Added support for JPEG previews, subsampling,
 *             non-baseline JPEGs, restart markers and DCT method choice
 * - Steinar H. Gunderson <sgunderson@bigfoot.com>
 *
 * A small preview appears and changes according to the changes to the
 * compression options. The image itself works as a much bigger preview.
 * For slower machines, the save operation (not the load operation) is
 * done in the background, with a standard GTK+ idle loop, which turned
 * out to be the most portable way. Win32 porters shouldn't have much
 * difficulty porting my changes (at least I hope so...).
 *
 * Subsampling is a pretty obscure feature, but I thought it might be nice
 * to have it in anyway, for people to play with :-) Does anybody have
 * any better suggestions than the ones I've put in the menu? (See wizard.doc
 * from the libjpeg distribution for a tiny bit of information on subsampling.)
 *
 * A baseline JPEG is often larger and/or of worse quality than a non-baseline
 * one (especially at low quality settings), but all decoders are guaranteed
 * to read baseline JPEGs (I think). Not all will read a non-baseline one.
 *
 * Restart markers are useful if you are transmitting the image over an
 * unreliable network. If a file gets corrupted, it will only be corrupted
 * up to the next restart marker. Of course, if there are no restart markers,
 * the rest of the image will be corrupted. Restart markers take up extra
 * space. The libjpeg developers recommend a restart every 1 row for
 * transmitting images over unreliable networks, such as Usenet.
 *
 * The DCT method is said by the libjpeg docs to _only_ influence quality vs.
 * speed, and nothing else. However, I've found that there _are_ size
 * differences. Fast integer, on the other hand, is faster than integer,
 * which in turn is faster than FP. According to the libjpeg docs (and I
 * believe it's true), FP has only a theoretical advantage in quality, and
 * will be slower than the two other methods, unless you're blessed with
 * very a fast FPU. (In addition, images might not be identical on
 * different types of FP hardware.)
 *
 * ...and thus ends my additions to the JPEG plug-in. I hope. *sigh* :-)
 */

93
/*
94
95
96
97
98
99
100
101
102
103
104
105
 * 21-AUG-99 - Bunch O' Fixes.
 * - Adam D. Moss <adam@gimp.org>
 *
 * We now correctly create an alpha-padded layer for our preview --
 * having a non-background non-alpha layer is a no-no in GIMP.
 *
 * I've also tweaked the GIMP undo API a little and changed the JPEG
 * plugin to use gimp_image_{freeze,thaw}_undo so that it doesn't store
 * up a whole load of superfluous tile data every time the preview is
 * changed.
 */

106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
/*
 * 22-DEC-99 - volatiles added
 * - Austin Donnelly <austin@gimp.org>
 *
 * When gcc complains a variable may be clobbered by a longjmp or
 * vfork, it means the following: setjmp() was called by the JPEG
 * library for error recovery purposes, but gcc is keeping some
 * variables in registers without updating the memory locations on the
 * stack consistently.  If JPEG error recovery is every invoked, the
 * values of these variable will be inconsistent.  This is almost
 * always a bug, but not one that's commonly seen unless JPEG recovery
 * code is exercised frequently.  The correct solution is to tell gcc
 * to keep the stack version of the affected variables up to date, by
 * using the "volatile" keyword.   Here endeth the lesson.
 */

122
123
124
125
126
127
128
129
/*
 * 4-SEP-01 - remove the use of GtkText
 * - DindinX <David@dindinx.org>
 *
 * The new version of GTK+ does not support GtkText anymore.
 * I've just replaced the one used for the image comment by
 * a GtkTextView/GtkTextBuffer couple;
 */
130

131
132
133
134
/*
 * 22-JUN-03 - add support for keeping EXIF information
 * - Dave Neary <bolsh@gimp.org>
 *
135
 * This is little more than a modified version fo a patch from the
136
 * libexif owner (Lutz Muller) which attaches exif information to
137
138
 * a GimpImage, and if there is infoprmation available at save
 * time, writes it out. No modification of the exif data is
139
140
141
 * currently possible.
 */

Sven Neumann's avatar
Sven Neumann committed
142
#include "config.h"   /* configure cares about HAVE_PROGRESSIVE_JPEG */
Tor Lillqvist's avatar
Tor Lillqvist committed
143

Sven Neumann's avatar
Sven Neumann committed
144
#include <glib.h>     /* We want glib.h first because of some
Sven Neumann's avatar
Sven Neumann committed
145
146
                       * pretty obscure Win32 compilation issues.
                       */
147
#include <errno.h>
Elliot Lee's avatar
Elliot Lee committed
148
#include <setjmp.h>
149
#include <signal.h>
Elliot Lee's avatar
Elliot Lee committed
150
151
152
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
153
#include <sys/types.h>
154
#include <sys/stat.h>
Tor Lillqvist's avatar
Tor Lillqvist committed
155
#ifdef HAVE_UNISTD_H
156
#include <unistd.h>
Tor Lillqvist's avatar
Tor Lillqvist committed
157
#endif
Elliot Lee's avatar
Elliot Lee committed
158
#include <jpeglib.h>
159
#include <jerror.h>
160

161
162
163
164
#ifdef HAVE_EXIF
#include <libexif/exif-data.h>
#endif /* HAVE_EXIF */

Michael Natterer's avatar
Michael Natterer committed
165
166
#include <libgimp/gimp.h>
#include <libgimp/gimpui.h>
167

168
169
#include "libgimp/stdplugins-intl.h"

Sven Neumann's avatar
Sven Neumann committed
170
#define SCALE_WIDTH         125
Elliot Lee's avatar
Elliot Lee committed
171

172
173
/* if you are not compiling this from inside the gimp tree, you have to  */
/* take care yourself if your JPEG library supports progressive mode     */
174
/* #undef HAVE_PROGRESSIVE_JPEG   if your library doesn't support it     */
175
176
/* #define HAVE_PROGRESSIVE_JPEG  if your library knows how to handle it */

177
/* See bugs #63610 and #61088 for a discussion about the quality settings */
178
#define DEFAULT_QUALITY     85
Sven Neumann's avatar
Sven Neumann committed
179
#define DEFAULT_SMOOTHING   0.0
180
181
182
#define DEFAULT_OPTIMIZE    TRUE
#define DEFAULT_PROGRESSIVE FALSE
#define DEFAULT_BASELINE    TRUE
Sven Neumann's avatar
Sven Neumann committed
183
184
185
#define DEFAULT_SUBSMP      0
#define DEFAULT_RESTART     0
#define DEFAULT_DCT         0
186
187
#define DEFAULT_PREVIEW     FALSE
#define DEFAULT_EXIF        TRUE
188
189

/* sg - these should not be global... */
190
191
192
193
194
195
static gint32 volatile  image_ID_global       = -1;
static gint32           orig_image_ID_global  = -1;
static gint32           drawable_ID_global    = -1;
static gint32           layer_ID_global       = -1;
static GtkWidget       *preview_size          = NULL;
static GimpDrawable    *drawable_global       = NULL;
196
static gboolean         undo_touched          = FALSE;
197

Elliot Lee's avatar
Elliot Lee committed
198
199
typedef struct
{
200
201
202
203
204
205
206
207
208
209
  gdouble  quality;
  gdouble  smoothing;
  gboolean optimize;
  gboolean progressive;
  gboolean baseline;
  gint     subsmp;
  gint     restart;
  gint     dct;
  gboolean preview;
  gboolean save_exif;
Elliot Lee's avatar
Elliot Lee committed
210
211
} JpegSaveVals;

212
typedef struct
213
214
{
  struct jpeg_compress_struct cinfo;
215
216
  gint          tile_height;
  FILE         *outfile;
217
  gboolean      has_alpha;
218
219
220
221
  gint          rowstride;
  guchar       *temp;
  guchar       *data;
  guchar       *src;
Sven Neumann's avatar
Sven Neumann committed
222
223
  GimpDrawable *drawable;
  GimpPixelRgn  pixel_rgn;
224
  const gchar  *file_name;
Sven Neumann's avatar
Sven Neumann committed
225
226
227
228
  gboolean      abort_me;
} PreviewPersistent;

static gboolean *abort_me = NULL;
Sven Neumann's avatar
Sven Neumann committed
229

230

Elliot Lee's avatar
Elliot Lee committed
231
232
/* Declare local functions.
 */
Sven Neumann's avatar
Sven Neumann committed
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
static void      query               (void);
static void      run                 (const gchar      *name,
                                      gint              nparams,
                                      const GimpParam  *param,
                                      gint             *nreturn_vals,
                                      GimpParam       **return_vals);
static gint32    load_image          (const gchar      *filename,
                                      GimpRunMode       runmode,
                                      gboolean          preview);
static gboolean  save_image          (const gchar      *filename,
                                      gint32            image_ID,
                                      gint32            drawable_ID,
                                      gint32            orig_image_ID,
                                      gboolean          preview);

static gboolean  save_dialog         (void);

static void      make_preview        (void);
static void      destroy_preview     (void);

static void      save_restart_update (GtkAdjustment    *adjustment,
                                      GtkWidget        *toggle);
255

Elliot Lee's avatar
Elliot Lee committed
256

Sven Neumann's avatar
Sven Neumann committed
257
GimpPlugInInfo PLUG_IN_INFO =
Elliot Lee's avatar
Elliot Lee committed
258
{
259
260
261
262
  NULL,  /* init_proc  */
  NULL,  /* quit_proc  */
  query, /* query_proc */
  run,   /* run_proc   */
Elliot Lee's avatar
Elliot Lee committed
263
264
265
266
};

static JpegSaveVals jsvals =
{
267
268
269
  DEFAULT_QUALITY,
  DEFAULT_SMOOTHING,
  DEFAULT_OPTIMIZE,
270
271
272
273
274
  DEFAULT_PROGRESSIVE,
  DEFAULT_BASELINE,
  DEFAULT_SUBSMP,
  DEFAULT_RESTART,
  DEFAULT_DCT,
275
276
  DEFAULT_PREVIEW,
  DEFAULT_EXIF
Elliot Lee's avatar
Elliot Lee committed
277
278
279
};


Sven Neumann's avatar
Sven Neumann committed
280
static gchar     *image_comment         = NULL;
281
282
283
static GtkWidget *restart_markers_scale = NULL;
static GtkWidget *restart_markers_label = NULL;

284
285
286
#ifdef HAVE_EXIF
static ExifData  *exif_data             = NULL;
#endif /* HAVE_EXIF */
Sven Neumann's avatar
Sven Neumann committed
287

Elliot Lee's avatar
Elliot Lee committed
288
289
290
MAIN ()

static void
291
query (void)
Elliot Lee's avatar
Elliot Lee committed
292
{
Sven Neumann's avatar
Sven Neumann committed
293
  static GimpParamDef load_args[] =
Elliot Lee's avatar
Elliot Lee committed
294
  {
Sven Neumann's avatar
Sven Neumann committed
295
296
297
    { GIMP_PDB_INT32,    "run_mode",     "Interactive, non-interactive" },
    { GIMP_PDB_STRING,   "filename",     "The name of the file to load" },
    { GIMP_PDB_STRING,   "raw_filename", "The name of the file to load" }
Elliot Lee's avatar
Elliot Lee committed
298
  };
Sven Neumann's avatar
Sven Neumann committed
299
  static GimpParamDef load_return_vals[] =
Elliot Lee's avatar
Elliot Lee committed
300
  {
Sven Neumann's avatar
Sven Neumann committed
301
    { GIMP_PDB_IMAGE,   "image",         "Output image" }
Elliot Lee's avatar
Elliot Lee committed
302
303
  };

Sven Neumann's avatar
Sven Neumann committed
304
  static GimpParamDef save_args[] =
Elliot Lee's avatar
Elliot Lee committed
305
  {
Sven Neumann's avatar
Sven Neumann committed
306
307
308
309
310
311
312
313
314
315
316
317
318
319
    { GIMP_PDB_INT32,    "run_mode",     "Interactive, non-interactive" },
    { GIMP_PDB_IMAGE,    "image",        "Input image" },
    { GIMP_PDB_DRAWABLE, "drawable",     "Drawable to save" },
    { GIMP_PDB_STRING,   "filename",     "The name of the file to save the image in" },
    { GIMP_PDB_STRING,   "raw_filename", "The name of the file to save the image in" },
    { GIMP_PDB_FLOAT,    "quality",      "Quality of saved image (0 <= quality <= 1)" },
    { GIMP_PDB_FLOAT,    "smoothing",    "Smoothing factor for saved image (0 <= smoothing <= 1)" },
    { GIMP_PDB_INT32,    "optimize",     "Optimization of entropy encoding parameters (0/1)" },
    { GIMP_PDB_INT32,    "progressive",  "Enable progressive jpeg image loading - ignored if not compiled with HAVE_PROGRESSIVE_JPEG (0/1)" },
    { GIMP_PDB_STRING,   "comment",      "Image comment" },
    { GIMP_PDB_INT32,    "subsmp",       "The subsampling option number" },
    { GIMP_PDB_INT32,    "baseline",     "Force creation of a baseline JPEG (non-baseline JPEGs can't be read by all decoders) (0/1)" },
    { GIMP_PDB_INT32,    "restart",      "Frequency of restart markers (in rows, 0 = no restart markers)" },
    { GIMP_PDB_INT32,    "dct",          "DCT algorithm to use (speed/quality tradeoff)" }
Elliot Lee's avatar
Elliot Lee committed
320
321
322
  };

  gimp_install_procedure ("file_jpeg_load",
Marc Lehmann's avatar
Marc Lehmann committed
323
324
                          "loads files in the JPEG file format",
                          "loads files in the JPEG file format",
325
                          "Spencer Kimball, Peter Mattis & others",
Elliot Lee's avatar
Elliot Lee committed
326
                          "Spencer Kimball & Peter Mattis",
327
                          "1995-1999",
Sven Neumann's avatar
Sven Neumann committed
328
329
                          N_("JPEG image"),
                          NULL,
Sven Neumann's avatar
Sven Neumann committed
330
                          GIMP_PLUGIN,
331
332
                          G_N_ELEMENTS (load_args),
                          G_N_ELEMENTS (load_return_vals),
Elliot Lee's avatar
Elliot Lee committed
333
334
                          load_args, load_return_vals);

335
336
337
  gimp_plugin_menu_register ("file_jpeg_load", "<Load>");
  gimp_register_file_handler_mime ("file_jpeg_load", "image/jpeg");
  gimp_register_magic_load_handler ("file_jpeg_load",
Sven Neumann's avatar
Sven Neumann committed
338
339
340
                                    "jpg,jpeg,jpe",
                                    "",
                                    "6,string,JFIF,6,string,Exif");
341

Elliot Lee's avatar
Elliot Lee committed
342
  gimp_install_procedure ("file_jpeg_save",
Marc Lehmann's avatar
Marc Lehmann committed
343
344
                          "saves files in the JPEG file format",
                          "saves files in the lossy, widely supported JPEG format",
345
                          "Spencer Kimball, Peter Mattis & others",
Elliot Lee's avatar
Elliot Lee committed
346
                          "Spencer Kimball & Peter Mattis",
347
                          "1995-1999",
348
                          N_("JPEG image"),
Sven Neumann's avatar
Sven Neumann committed
349
                          "RGB*, GRAY*",
Sven Neumann's avatar
Sven Neumann committed
350
                          GIMP_PLUGIN,
351
                          G_N_ELEMENTS (save_args), 0,
Elliot Lee's avatar
Elliot Lee committed
352
353
                          save_args, NULL);

354
355
356
357
358
  gimp_plugin_menu_register ("file_jpeg_save", "<Save>");
  gimp_register_file_handler_mime ("file_jpeg_save", "image/jpeg");
  gimp_register_save_handler ("file_jpeg_save",
                              "jpg,jpeg,jpe",
                              "");
Elliot Lee's avatar
Elliot Lee committed
359
360
361
}

static void
362
363
364
365
366
run (const gchar      *name,
     gint              nparams,
     const GimpParam  *param,
     gint             *nreturn_vals,
     GimpParam       **return_vals)
Elliot Lee's avatar
Elliot Lee committed
367
{
368
369
370
371
372
373
374
375
376
377
  static GimpParam   values[2];
  GimpRunMode        run_mode;
  GimpPDBStatusType  status = GIMP_PDB_SUCCESS;
  gint32             image_ID;
  gint32             drawable_ID;
  gint32             orig_image_ID;
  gint32             display_ID = -1;
  GimpParasite      *parasite;
  gboolean           err;
  GimpExportReturn   export = GIMP_EXPORT_CANCEL;
Elliot Lee's avatar
Elliot Lee committed
378
379
380

  run_mode = param[0].data.d_int32;

381
382
  INIT_I18N ();

Elliot Lee's avatar
Elliot Lee committed
383
  *nreturn_vals = 1;
384
  *return_vals  = values;
Sven Neumann's avatar
Sven Neumann committed
385
386
  values[0].type          = GIMP_PDB_STATUS;
  values[0].data.d_status = GIMP_PDB_EXECUTION_ERROR;
387

Elliot Lee's avatar
Elliot Lee committed
388
389
  if (strcmp (name, "file_jpeg_load") == 0)
    {
390
      image_ID = load_image (param[1].data.d_string, run_mode, FALSE);
Elliot Lee's avatar
Elliot Lee committed
391
392

      if (image_ID != -1)
Sven Neumann's avatar
Sven Neumann committed
393
394
395
396
397
        {
          *nreturn_vals = 2;
          values[1].type         = GIMP_PDB_IMAGE;
          values[1].data.d_image = image_ID;
        }
Elliot Lee's avatar
Elliot Lee committed
398
      else
Sven Neumann's avatar
Sven Neumann committed
399
400
401
        {
          status = GIMP_PDB_EXECUTION_ERROR;
        }
Elliot Lee's avatar
Elliot Lee committed
402
403
404
    }
  else if (strcmp (name, "file_jpeg_save") == 0)
    {
Sven Neumann's avatar
Sven Neumann committed
405
406
407
      image_ID = orig_image_ID = param[1].data.d_int32;
      drawable_ID = param[2].data.d_int32;

408
       /*  eventually export the image */
Sven Neumann's avatar
Sven Neumann committed
409
      switch (run_mode)
Sven Neumann's avatar
Sven Neumann committed
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
        {
        case GIMP_RUN_INTERACTIVE:
        case GIMP_RUN_WITH_LAST_VALS:
          gimp_ui_init ("jpeg", FALSE);
          export = gimp_export_image (&image_ID, &drawable_ID, "JPEG",
                                      (GIMP_EXPORT_CAN_HANDLE_RGB |
                                       GIMP_EXPORT_CAN_HANDLE_GRAY));
          switch (export)
            {
            case GIMP_EXPORT_EXPORT:
              display_ID = gimp_display_new (image_ID);
              gimp_image_set_filename (image_ID, _("Export Preview"));
              gimp_displays_flush ();
              break;
            case GIMP_EXPORT_IGNORE:
              break;
            case GIMP_EXPORT_CANCEL:
              values[0].data.d_status = GIMP_PDB_CANCEL;
              return;
              break;
            }
          break;
        default:
          break;
        }
435

436
437
438
439
440
#ifdef HAVE_EXIF
      exif_data_unref (exif_data);
      exif_data = NULL;
#endif /* HAVE_EXIF */

Sven Neumann's avatar
Sven Neumann committed
441
442
      g_free (image_comment);
      image_comment = NULL;
443

Marc Lehmann's avatar
Marc Lehmann committed
444
      parasite = gimp_image_parasite_find (orig_image_ID, "gimp-comment");
445
      if (parasite)
Sven Neumann's avatar
Sven Neumann committed
446
447
448
449
        {
          image_comment = g_strdup (parasite->data);
          gimp_parasite_free (parasite);
        }
450

451
#ifdef HAVE_EXIF
452
      parasite = gimp_image_parasite_find (orig_image_ID, "exif-data");
453
454
455
456
457
458
459
      if (parasite)
        {
          exif_data = exif_data_new_from_data (parasite->data, parasite->size);
          gimp_parasite_free (parasite);
        }
#endif /* HAVE_EXIF */

460
461
462
      jsvals.quality     = DEFAULT_QUALITY;
      jsvals.smoothing   = DEFAULT_SMOOTHING;
      jsvals.optimize    = DEFAULT_OPTIMIZE;
463
      jsvals.progressive = DEFAULT_PROGRESSIVE;
464
465
466
467
468
      jsvals.baseline    = DEFAULT_BASELINE;
      jsvals.subsmp      = DEFAULT_SUBSMP;
      jsvals.restart     = DEFAULT_RESTART;
      jsvals.dct         = DEFAULT_DCT;
      jsvals.preview     = DEFAULT_PREVIEW;
469
      jsvals.save_exif   = DEFAULT_EXIF;
470

Elliot Lee's avatar
Elliot Lee committed
471
      switch (run_mode)
Sven Neumann's avatar
Sven Neumann committed
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
        {
        case GIMP_RUN_INTERACTIVE:
          /*  Possibly retrieve data  */
          gimp_get_data ("file_jpeg_save", &jsvals);

          /* load up the previously used values */
          parasite = gimp_image_parasite_find (orig_image_ID,
                                               "jpeg-save-options");
          if (parasite)
            {
              jsvals.quality     = ((JpegSaveVals *)parasite->data)->quality;
              jsvals.smoothing   = ((JpegSaveVals *)parasite->data)->smoothing;
              jsvals.optimize    = ((JpegSaveVals *)parasite->data)->optimize;
              jsvals.progressive = ((JpegSaveVals *)parasite->data)->progressive;
              jsvals.baseline    = ((JpegSaveVals *)parasite->data)->baseline;
              jsvals.subsmp      = ((JpegSaveVals *)parasite->data)->subsmp;
              jsvals.restart     = ((JpegSaveVals *)parasite->data)->restart;
              jsvals.dct         = ((JpegSaveVals *)parasite->data)->dct;
              jsvals.preview     = ((JpegSaveVals *)parasite->data)->preview;
              jsvals.save_exif   = ((JpegSaveVals *)parasite->data)->save_exif;
              gimp_parasite_free (parasite);
            }
494

495
496
          if (jsvals.preview)
            {
497
498
              /* we freeze undo saving so that we can avoid sucking up
               * tile cache with our unneeded preview steps. */
499
500
501
502
              gimp_image_undo_freeze (image_ID);

              undo_touched = TRUE;
            }
503

Sven Neumann's avatar
Sven Neumann committed
504
505
506
507
          /* prepare for the preview */
          image_ID_global = image_ID;
          orig_image_ID_global = orig_image_ID;
          drawable_ID_global = drawable_ID;
508

Sven Neumann's avatar
Sven Neumann committed
509
510
          /*  First acquire information with a dialog  */
          err = save_dialog ();
511

512
513
          if (undo_touched)
            {
514
515
              /* thaw undo saving and flush the displays to have them
               * reflect the current shortcuts */
516
              gimp_image_undo_thaw (image_ID);
517
              gimp_displays_flush ();
518
            }
519
520

          if (!err)
Sven Neumann's avatar
Sven Neumann committed
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
            status = GIMP_PDB_CANCEL;
          break;

        case GIMP_RUN_NONINTERACTIVE:
          /*  Make sure all the arguments are there!  */
          /*  pw - added two more progressive and comment */
          /*  sg - added subsampling, preview, baseline, restarts and DCT */
          if (nparams != 14)
            {
              status = GIMP_PDB_CALLING_ERROR;
            }
          else
            {
              /* Once the PDB gets default parameters, remove this hack */
              if (param[5].data.d_float > 0.05)
                {
                  jsvals.quality     = 100.0 * param[5].data.d_float;
                  jsvals.smoothing   = param[6].data.d_float;
                  jsvals.optimize    = param[7].data.d_int32;
540
#ifdef HAVE_PROGRESSIVE_JPEG
Sven Neumann's avatar
Sven Neumann committed
541
                  jsvals.progressive = param[8].data.d_int32;
542
#endif /* HAVE_PROGRESSIVE_JPEG */
Sven Neumann's avatar
Sven Neumann committed
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
                  jsvals.baseline    = param[11].data.d_int32;
                  jsvals.subsmp      = param[10].data.d_int32;
                  jsvals.restart     = param[12].data.d_int32;
                  jsvals.dct         = param[13].data.d_int32;

                  /* free up the default -- wasted some effort earlier */
                  g_free (image_comment);
                  image_comment = g_strdup (param[9].data.d_string);
                }

              jsvals.preview = FALSE;

              if (jsvals.quality < 0.0 || jsvals.quality > 100.0)
                status = GIMP_PDB_CALLING_ERROR;
              else if (jsvals.smoothing < 0.0 || jsvals.smoothing > 1.0)
                status = GIMP_PDB_CALLING_ERROR;
              else if (jsvals.subsmp < 0 || jsvals.subsmp > 2)
                status = GIMP_PDB_CALLING_ERROR;
              else if (jsvals.dct < 0 || jsvals.dct > 2)
                status = GIMP_PDB_CALLING_ERROR;
            }
          break;

        case GIMP_RUN_WITH_LAST_VALS:
          /*  Possibly retrieve data  */
          gimp_get_data ("file_jpeg_save", &jsvals);

          parasite = gimp_image_parasite_find (orig_image_ID,
                                               "jpeg-save-options");
          if (parasite)
            {
              jsvals.quality     = ((JpegSaveVals *)parasite->data)->quality;
              jsvals.smoothing   = ((JpegSaveVals *)parasite->data)->smoothing;
              jsvals.optimize    = ((JpegSaveVals *)parasite->data)->optimize;
              jsvals.progressive = ((JpegSaveVals *)parasite->data)->progressive;
              jsvals.baseline    = ((JpegSaveVals *)parasite->data)->baseline;
              jsvals.subsmp      = ((JpegSaveVals *)parasite->data)->subsmp;
              jsvals.restart     = ((JpegSaveVals *)parasite->data)->restart;
              jsvals.dct         = ((JpegSaveVals *)parasite->data)->dct;
              jsvals.preview     = FALSE;
              gimp_parasite_free (parasite);
            }
          break;

        default:
          break;
        }
Elliot Lee's avatar
Elliot Lee committed
590

Sven Neumann's avatar
Sven Neumann committed
591
      if (status == GIMP_PDB_SUCCESS)
Sven Neumann's avatar
Sven Neumann committed
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
        {
          if (save_image (param[3].data.d_string,
                          image_ID,
                          drawable_ID,
                          orig_image_ID,
                          FALSE))
            {
              /*  Store mvals data  */
              gimp_set_data ("file_jpeg_save", &jsvals, sizeof (JpegSaveVals));
            }
          else
            {
              status = GIMP_PDB_EXECUTION_ERROR;
            }
        }
607

608
      if (export == GIMP_EXPORT_EXPORT)
Sven Neumann's avatar
Sven Neumann committed
609
610
611
        {
          /* If the image was exported, delete the new display. */
          /* This also deletes the image.                       */
612

Sven Neumann's avatar
Sven Neumann committed
613
614
615
616
617
          if (display_ID > -1)
            gimp_display_delete (display_ID);
          else
            gimp_image_delete (image_ID);
        }
Sven Neumann's avatar
Sven Neumann committed
618

619
620
621
      /* pw - now we need to change the defaults to be whatever
       * was used to save this image.  Dump the old parasites
       * and add new ones. */
622

Marc Lehmann's avatar
Marc Lehmann committed
623
      gimp_image_parasite_detach (orig_image_ID, "gimp-comment");
624
      if (image_comment && strlen (image_comment))
Sven Neumann's avatar
Sven Neumann committed
625
626
627
628
629
630
631
632
        {
          parasite = gimp_parasite_new ("gimp-comment",
                                        GIMP_PARASITE_PERSISTENT,
                                        strlen (image_comment) + 1,
                                        image_comment);
          gimp_image_parasite_attach (orig_image_ID, parasite);
          gimp_parasite_free (parasite);
        }
Marc Lehmann's avatar
Marc Lehmann committed
633
      gimp_image_parasite_detach (orig_image_ID, "jpeg-save-options");
634

635
      parasite = gimp_parasite_new ("jpeg-save-options",
Sven Neumann's avatar
Sven Neumann committed
636
                                    0, sizeof (jsvals), &jsvals);
Marc Lehmann's avatar
Marc Lehmann committed
637
      gimp_image_parasite_attach (orig_image_ID, parasite);
638
      gimp_parasite_free (parasite);
Elliot Lee's avatar
Elliot Lee committed
639
    }
640
641
  else
    {
Sven Neumann's avatar
Sven Neumann committed
642
      status = GIMP_PDB_CALLING_ERROR;
643
    }
Elliot Lee's avatar
Elliot Lee committed
644

645
646
  values[0].data.d_status = status;
}
Elliot Lee's avatar
Elliot Lee committed
647

648
/* Read next byte */
649
static guint
650
651
jpeg_getc (j_decompress_ptr cinfo)
{
652
  struct jpeg_source_mgr *datasrc = cinfo->src;
653

654
  if (datasrc->bytes_in_buffer == 0)
Sven Neumann's avatar
Sven Neumann committed
655
656
    {
      if (! (*datasrc->fill_input_buffer) (cinfo))
Sven Neumann's avatar
Sven Neumann committed
657
        ERREXIT (cinfo, JERR_CANT_SUSPEND);
Sven Neumann's avatar
Sven Neumann committed
658
    }
659
  datasrc->bytes_in_buffer--;
660

661
662
663
664
665
666
667
668
669
670
671
672
  return *datasrc->next_input_byte++;
}

/* We need our own marker parser, since early versions of libjpeg
 * don't keep a conventient list of the marker's that have been
 * seen. */

/*
 * Marker processor for COM markers.
 * This replaces the library's built-in processor, which just skips the marker.
 * Note this code relies on a non-suspending data source.
 */
Sven Neumann's avatar
Sven Neumann committed
673
static GString *local_image_comments = NULL;
674
675
676
677

static boolean
COM_handler (j_decompress_ptr cinfo)
{
678
679
  gint  length;
  guint ch;
680
681
682
683
684

  length = jpeg_getc (cinfo) << 8;
  length += jpeg_getc (cinfo);
  if (length < 2)
    return FALSE;
Sven Neumann's avatar
Sven Neumann committed
685
  length -= 2;                  /* discount the length word itself */
686
687
688
689
690
691
692

  if (!local_image_comments)
    local_image_comments = g_string_new (NULL);
  else
    g_string_append_c (local_image_comments, '\n');

  while (length-- > 0)
Sven Neumann's avatar
Sven Neumann committed
693
694
695
696
    {
      ch = jpeg_getc (cinfo);
      g_string_append_c (local_image_comments, ch);
    }
697
698
699
700

  return TRUE;
}

701
702
typedef struct my_error_mgr
{
703
704
705
706
707
708
  struct jpeg_error_mgr pub;            /* "public" fields */

#ifdef __ia64__
  /* Ugh, the jmp_buf field needs to be 16-byte aligned on ia64 and some
   * glibc/icc combinations don't guarantee this. So we pad. See bug #138357
   * for details.
709
   */
710
711
  long double           dummy;
#endif
712

713
  jmp_buf               setjmp_buffer;  /* for return to caller */
Elliot Lee's avatar
Elliot Lee committed
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
} *my_error_ptr;

/*
 * Here's the routine that will replace the standard error_exit method:
 */

static void
my_error_exit (j_common_ptr cinfo)
{
  /* cinfo->err really points to a my_error_mgr struct, so coerce pointer */
  my_error_ptr myerr = (my_error_ptr) cinfo->err;

  /* Always display the message. */
  /* We could postpone this until after returning, if we chose. */
  (*cinfo->err->output_message) (cinfo);

  /* Return control to the setjmp point */
  longjmp (myerr->setjmp_buffer, 1);
}

734
735
736
737
738
static void
my_emit_message (j_common_ptr cinfo,
                 int          msg_level)
{
  if (msg_level == -1)
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
    {
      /*  disable loading of EXIF data  */
      cinfo->client_data = GINT_TO_POINTER (TRUE);

      (*cinfo->err->output_message) (cinfo);
    }
}

static void
my_output_message (j_common_ptr cinfo)
{
  gchar  buffer[JMSG_LENGTH_MAX + 1];

  (*cinfo->err->format_message)(cinfo, buffer);

  if (GPOINTER_TO_INT (cinfo->client_data))
    {
      gchar *msg = g_strconcat (buffer,
                                "\n\n",
                                _("EXIF data will be ignored."),
                                NULL);
      g_message (msg);
      g_free (msg);
    }
  else
    {
      g_message (buffer);
    }
767
768
}

Elliot Lee's avatar
Elliot Lee committed
769
static gint32
770
load_image (const gchar *filename,
Sven Neumann's avatar
Sven Neumann committed
771
772
            GimpRunMode  runmode,
            gboolean     preview)
Elliot Lee's avatar
Elliot Lee committed
773
{
774
775
776
777
  GimpPixelRgn     pixel_rgn;
  GimpDrawable    *drawable;
  gint32 volatile  image_ID;
  gint32           layer_ID;
Elliot Lee's avatar
Elliot Lee committed
778
  struct jpeg_decompress_struct cinfo;
779
780
781
782
  struct my_error_mgr           jerr;
  FILE    *infile;
  guchar  *buf;
  guchar  * volatile padded_buf = NULL;
Elliot Lee's avatar
Elliot Lee committed
783
  guchar **rowbuf;
784
785
786
787
788
  gint     image_type;
  gint     layer_type;
  gint     tile_height;
  gint     scanlines;
  gint     i, start, end;
Elliot Lee's avatar
Elliot Lee committed
789

790
  GimpParasite * volatile comment_parasite = NULL;
791

792
793
#ifdef HAVE_EXIF
  GimpParasite *exif_parasite = NULL;
794
  ExifData     *exif_data     = NULL;
795
796
#endif

Elliot Lee's avatar
Elliot Lee committed
797
798
799
800
  /* We set up the normal JPEG error routines. */
  cinfo.err = jpeg_std_error (&jerr.pub);
  jerr.pub.error_exit = my_error_exit;

801
802
803
  /* flag warnings, so we try to ignore corrupt EXIF data */
  if (!preview)
    {
804
805
806
807
      cinfo.client_data = GINT_TO_POINTER (FALSE);

      jerr.pub.emit_message   = my_emit_message;
      jerr.pub.output_message = my_output_message;
808
809
    }

Elliot Lee's avatar
Elliot Lee committed
810
811
  if ((infile = fopen (filename, "rb")) == NULL)
    {
812
      g_message (_("Could not open '%s' for reading: %s"),
813
                 gimp_filename_to_utf8 (filename), g_strerror (errno));
Elliot Lee's avatar
Elliot Lee committed
814
815
816
      gimp_quit ();
    }

817
818
  if (!preview)
    {
819
820
      gchar *name = g_strdup_printf (_("Opening '%s'..."),
                                     gimp_filename_to_utf8 (filename));
821
822
823
824

      gimp_progress_init (name);
      g_free (name);
    }
Elliot Lee's avatar
Elliot Lee committed
825
826
827
828
829
830
831
832
833
834

  image_ID = -1;
  /* Establish the setjmp return context for my_error_exit to use. */
  if (setjmp (jerr.setjmp_buffer))
    {
      /* If we get here, the JPEG code has signaled an error.
       * We need to clean up the JPEG object, close the input file, and return.
       */
      jpeg_destroy_decompress (&cinfo);
      if (infile)
Sven Neumann's avatar
Sven Neumann committed
835
        fclose (infile);
836
      if (image_ID != -1 && !preview)
Sven Neumann's avatar
Sven Neumann committed
837
        gimp_image_delete (image_ID);
838
      if (preview)
Sven Neumann's avatar
Sven Neumann committed
839
        destroy_preview();
Elliot Lee's avatar
Elliot Lee committed
840
841
      gimp_quit ();
    }
842

Elliot Lee's avatar
Elliot Lee committed
843
844
845
846
847
848
849
  /* Now we can initialize the JPEG decompression object. */
  jpeg_create_decompress (&cinfo);

  /* Step 2: specify data source (eg, a file) */

  jpeg_stdio_src (&cinfo, infile);

850
  /* pw - step 2.1 let the lib know we want the comments. */
851
852

  jpeg_set_marker_processor (&cinfo, JPEG_COM, COM_handler);
853

Elliot Lee's avatar
Elliot Lee committed
854
855
856
  /* Step 3: read file parameters with jpeg_read_header() */

  (void) jpeg_read_header (&cinfo, TRUE);
857

Elliot Lee's avatar
Elliot Lee committed
858
859
860
861
862
863
  /* We can ignore the return value from jpeg_read_header since
   *   (a) suspension is not possible with the stdio data source, and
   *   (b) we passed TRUE to reject a tables-only JPEG file as an error.
   * See libjpeg.doc for more info.
   */

864
  if (!preview)
865
866
    {
      /* if we had any comments then make a parasite for them */
867
      if (local_image_comments && local_image_comments->len)
Sven Neumann's avatar
Sven Neumann committed
868
869
        {
          gchar *comment = local_image_comments->str;
870

Sven Neumann's avatar
Sven Neumann committed
871
          g_string_free (local_image_comments, FALSE);
872

Sven Neumann's avatar
Sven Neumann committed
873
          local_image_comments = NULL;
874
875
876
877
878
879
880

          if (g_utf8_validate (comment, -1, NULL))
            comment_parasite = gimp_parasite_new ("gimp-comment",
                                                  GIMP_PARASITE_PERSISTENT,
                                                  strlen (comment) + 1,
                                                  comment);
          g_free (comment);
Sven Neumann's avatar
Sven Neumann committed
881
        }
882

883
884
885
      /* Do not attach the "jpeg-save-options" parasite to the image
       * because this conflics with the global defaults.  See bug #75398:
       * http://bugzilla.gnome.org/show_bug.cgi?id=75398 */
886
887
    }

Elliot Lee's avatar
Elliot Lee committed
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
  /* Step 4: set parameters for decompression */

  /* In this example, we don't need to change any of the defaults set by
   * jpeg_read_header(), so we do nothing here.
   */

  /* Step 5: Start decompressor */

  jpeg_start_decompress (&cinfo);

  /* We may need to do some setup of our own at this point before reading
   * the data.  After jpeg_start_decompress() we have the correct scaled
   * output image dimensions available, as well as the output colormap
   * if we asked for color quantization.
   * In this example, we need to make an output work buffer of the right size.
   */
  /* temporary buffer */
  tile_height = gimp_tile_height ();
906
  buf = g_new (guchar,
Sven Neumann's avatar
Sven Neumann committed
907
               tile_height * cinfo.output_width * cinfo.output_components);
908

Elliot Lee's avatar
Elliot Lee committed
909
910
911
912
913
914
  rowbuf = g_new (guchar*, tile_height);

  for (i = 0; i < tile_height; i++)
    rowbuf[i] = buf + cinfo.output_width * cinfo.output_components * i;

  /* Create a new image of the proper size and associate the filename with it.
915
916
917

     Preview layers, not being on the bottom of a layer stack, MUST HAVE
     AN ALPHA CHANNEL!
Elliot Lee's avatar
Elliot Lee committed
918
919
920
921
   */
  switch (cinfo.output_components)
    {
    case 1:
Sven Neumann's avatar
Sven Neumann committed
922
923
      image_type = GIMP_GRAY;
      layer_type = preview ? GIMP_GRAYA_IMAGE : GIMP_GRAY_IMAGE;
Elliot Lee's avatar
Elliot Lee committed
924
      break;
925

Elliot Lee's avatar
Elliot Lee committed
926
    case 3:
Sven Neumann's avatar
Sven Neumann committed
927
928
      image_type = GIMP_RGB;
      layer_type = preview ? GIMP_RGBA_IMAGE : GIMP_RGB_IMAGE;
Elliot Lee's avatar
Elliot Lee committed
929
      break;
930

931
932
    case 4:
      if (cinfo.out_color_space == JCS_CMYK)
Sven Neumann's avatar
Sven Neumann committed
933
934
935
936
937
        {
          image_type = GIMP_RGB;
          layer_type = GIMP_RGB_IMAGE;
          break;
        }
938
939
      /*fallthrough*/

Elliot Lee's avatar
Elliot Lee committed
940
    default:
941
942
943
      g_message ("Don't know how to load JPEGs\n"
                 "with %d color channels\n"
                 "using colorspace %d (%d)",
Sven Neumann's avatar
Sven Neumann committed
944
945
                 cinfo.output_components, cinfo.out_color_space,
                 cinfo.jpeg_color_space);
Elliot Lee's avatar
Elliot Lee committed
946
      gimp_quit ();
947
      break;
Elliot Lee's avatar
Elliot Lee committed
948
949
    }

950
951
  if (preview)
    padded_buf = g_new (guchar, tile_height * cinfo.output_width *
Sven Neumann's avatar
Sven Neumann committed
952
                        (cinfo.output_components + 1));
953
954
955
956
957
  else if (cinfo.out_color_space == JCS_CMYK)
    padded_buf = g_new (guchar, tile_height * cinfo.output_width * 3);
  else
    padded_buf = NULL;

958
  if (preview)
Sven Neumann's avatar
Sven Neumann committed
959
960
    {
      image_ID = image_ID_global;
961
962
    }
  else
Sven Neumann's avatar
Sven Neumann committed
963
    {
964
      image_ID = gimp_image_new (cinfo.output_width, cinfo.output_height,
Sven Neumann's avatar
Sven Neumann committed
965
                                 image_type);
Sven Neumann's avatar
Sven Neumann committed
966
967
      gimp_image_set_filename (image_ID, filename);
    }
968

969
  if (preview)
Sven Neumann's avatar
Sven Neumann committed
970
    {
971
      layer_ID_global = layer_ID =
Sven Neumann's avatar
Sven Neumann committed
972
973
974
975
        gimp_layer_new (image_ID, _("JPEG preview"),
                        cinfo.output_width,
                        cinfo.output_height,
                        layer_type, 100, GIMP_NORMAL_MODE);
976
    }
977
  else
Sven Neumann's avatar
Sven Neumann committed
978
979
    {
      layer_ID = gimp_layer_new (image_ID, _("Background"),
Sven Neumann's avatar
Sven Neumann committed
980
981
982
                                 cinfo.output_width,
                                 cinfo.output_height,
                                 layer_type, 100, GIMP_NORMAL_MODE);
Sven Neumann's avatar
Sven Neumann committed
983
    }
Elliot Lee's avatar
Elliot Lee committed
984

985
  drawable_global = drawable = gimp_drawable_get (layer_ID);
986
  gimp_pixel_rgn_init (&pixel_rgn, drawable, 0, 0,
Sven Neumann's avatar
Sven Neumann committed
987
                       drawable->width, drawable->height, TRUE, FALSE);
Elliot Lee's avatar
Elliot Lee committed
988

989
  /* Step 5.1: if the file had resolution information, set it on the image */
990
  if (!preview && cinfo.saw_JFIF_marker)
991
992
993
994
    {
      gdouble xresolution;
      gdouble yresolution;
      gdouble asymmetry;
995

996
997
      xresolution = cinfo.X_density;
      yresolution = cinfo.Y_density;
998

999
      switch (cinfo.density_unit)
Sven Neumann's avatar
Sven Neumann committed
1000
        {
For faster browsing, not all history is shown. View entire blame