jpeg-load.c 58 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
38
39
40
41
42
43
44
45
46
47
/* 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
 * jpeg parameters (quaility, smoothing, compression and progressive)
 * are attached to the image as a parasite.  This allows the
 * parameters to remain consistent between saves.  I was not able to
 * figure out how to determine the quaility, smoothing or compression
 * 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.
 */

Tor Lillqvist's avatar
Tor Lillqvist committed
106
107
108
109
110
#include "config.h"		/* configure cares about HAVE_PROGRESSIVE_JPEG */

#include <glib.h>		/* We want glib.h first because of some
				 * pretty obscure Win32 compilation issues.
				 */
Elliot Lee's avatar
Elliot Lee committed
111
112
113
114
#include <setjmp.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
115
#include <sys/types.h>
116
#include <sys/stat.h>
Tor Lillqvist's avatar
Tor Lillqvist committed
117
#ifdef HAVE_UNISTD_H
118
#include <unistd.h>
Tor Lillqvist's avatar
Tor Lillqvist committed
119
#endif
Elliot Lee's avatar
Elliot Lee committed
120
#include <jpeglib.h>
121
#include <jerror.h>
Elliot Lee's avatar
Elliot Lee committed
122
#include "libgimp/gimp.h"
Sven Neumann's avatar
Sven Neumann committed
123
#include "libgimp/gimpui.h"
124
125
#include "libgimp/stdplugins-intl.h"

Elliot Lee's avatar
Elliot Lee committed
126

Sven Neumann's avatar
Sven Neumann committed
127
#define SCALE_WIDTH         125
Elliot Lee's avatar
Elliot Lee committed
128

129
130
/* if you are not compiling this from inside the gimp tree, you have to  */
/* take care yourself if your JPEG library supports progressive mode     */
131
/* #undef HAVE_PROGRESSIVE_JPEG   if your library doesn't support it     */
132
133
/* #define HAVE_PROGRESSIVE_JPEG  if your library knows how to handle it */

Sven Neumann's avatar
Sven Neumann committed
134
135
136
#define DEFAULT_QUALITY     0.75
#define DEFAULT_SMOOTHING   0.0
#define DEFAULT_OPTIMIZE    1
137
#define DEFAULT_PROGRESSIVE 0
Sven Neumann's avatar
Sven Neumann committed
138
139
140
141
142
#define DEFAULT_BASELINE    1
#define DEFAULT_SUBSMP      0
#define DEFAULT_RESTART     0
#define DEFAULT_DCT         0
#define DEFAULT_PREVIEW     1
143

Sven Neumann's avatar
Sven Neumann committed
144
#define DEFAULT_COMMENT     "Created with The GIMP"
145

146
/* sg - these should not be global... */
Sven Neumann's avatar
Sven Neumann committed
147
gint32 volatile image_ID_global = -1, orig_image_ID_global, drawable_ID_global = -1, layer_ID_global = -1;
148
149
150
GtkWidget *preview_size = NULL;
GDrawable *drawable_global = NULL;

Elliot Lee's avatar
Elliot Lee committed
151
152
153
154
155
typedef struct
{
  gdouble quality;
  gdouble smoothing;
  gint optimize;
156
  gint progressive;
157
158
159
160
161
  gint baseline;
  gint subsmp;
  gint restart;
  gint dct;
  gint preview;
Elliot Lee's avatar
Elliot Lee committed
162
163
164
165
166
167
168
} JpegSaveVals;

typedef struct
{
  gint  run;
} JpegSaveInterface;

169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
typedef struct 
{
  struct jpeg_compress_struct cinfo;
  gint tile_height;
  FILE *outfile;
  gint has_alpha;
  gint rowstride;
  guchar *temp;
  guchar *data;
  guchar *src;
  GDrawable *drawable;
  GPixelRgn pixel_rgn;
  char *file_name;

  gint abort_me;
} preview_persistent;
Sven Neumann's avatar
Sven Neumann committed
185

186
187
188
189
190
gint *abort_me = NULL;

typedef void (*MenuItemCallback) (GtkWidget *widget,
                                  gpointer   user_data);

Elliot Lee's avatar
Elliot Lee committed
191
192
/* Declare local functions.
 */
Sven Neumann's avatar
Sven Neumann committed
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
static void   query                     (void);
static void   run                       (char    *name,
					 int      nparams,
					 GParam  *param,
					 int     *nreturn_vals,
					 GParam **return_vals);
static gint32 load_image                (char   *filename, 
					 GRunModeType runmode, 
					 int preview);
static gint   save_image                (char   *filename,
					 gint32  image_ID,
					 gint32  drawable_ID,
					 gint32  orig_image_ID,
					 int     preview);

static void   add_menu_item             (GtkWidget *menu,
					 char *label,
					 guint op_no,
					 MenuItemCallback callback);

static void   init_gtk                   (void);
static gint   save_dialog                (void);

static void   save_close_callback        (GtkWidget *widget,
					  gpointer   data);
static void   save_ok_callback           (GtkWidget *widget,
					  gpointer   data);
static void   save_scale_update          (GtkAdjustment *adjustment,
					  double        *scale_val);
222
223
static void   save_restart_toggle_update (GtkWidget     *toggle,
					  GtkAdjustment *adjustment);
Sven Neumann's avatar
Sven Neumann committed
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
static void   save_restart_update        (GtkAdjustment *adjustment,
					  GtkWidget     *toggle);
static void   save_optimize_update       (GtkWidget *widget,
					  gpointer   data);
static void   save_progressive_toggle    (GtkWidget *widget,
					  gpointer   data);
static void   save_baseline_toggle       (GtkWidget *widget,
					  gpointer   data);
static void   save_preview_toggle        (GtkWidget *widget,
					  gpointer  data);


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

static void   subsmp_callback            (GtkWidget *widget, 
					  gpointer data);
static void   dct_callback               (GtkWidget *widget, 
					  gpointer data);
Elliot Lee's avatar
Elliot Lee committed
243
244
245
246
247
248
249
250
251
252
253

GPlugInInfo PLUG_IN_INFO =
{
  NULL,    /* init_proc */
  NULL,    /* quit_proc */
  query,   /* query_proc */
  run,     /* run_proc */
};

static JpegSaveVals jsvals =
{
254
255
256
  DEFAULT_QUALITY,
  DEFAULT_SMOOTHING,
  DEFAULT_OPTIMIZE,
257
258
259
260
261
262
  DEFAULT_PROGRESSIVE,
  DEFAULT_BASELINE,
  DEFAULT_SUBSMP,
  DEFAULT_RESTART,
  DEFAULT_DCT,
  DEFAULT_PREVIEW
Elliot Lee's avatar
Elliot Lee committed
263
264
265
266
267
268
269
};

static JpegSaveInterface jsint =
{
  FALSE   /*  run  */
};

270
char *image_comment=NULL;
Elliot Lee's avatar
Elliot Lee committed
271

272
273
274
static GtkWidget *restart_markers_scale = NULL;
static GtkWidget *restart_markers_label = NULL;

Elliot Lee's avatar
Elliot Lee committed
275
276
277
278
279
280
281
MAIN ()

static void
query ()
{
  static GParamDef load_args[] =
  {
Sven Neumann's avatar
Sven Neumann committed
282
283
284
    { PARAM_INT32,    "run_mode",     "Interactive, non-interactive" },
    { PARAM_STRING,   "filename",     "The name of the file to load" },
    { PARAM_STRING,   "raw_filename", "The name of the file to load" },
Elliot Lee's avatar
Elliot Lee committed
285
286
287
  };
  static GParamDef load_return_vals[] =
  {
Sven Neumann's avatar
Sven Neumann committed
288
    { PARAM_IMAGE,   "image",         "Output image" },
Elliot Lee's avatar
Elliot Lee committed
289
  };
Sven Neumann's avatar
Sven Neumann committed
290
  static int nload_args        = sizeof (load_args) / sizeof (load_args[0]);
Elliot Lee's avatar
Elliot Lee committed
291
292
293
294
  static int nload_return_vals = sizeof (load_return_vals) / sizeof (load_return_vals[0]);

  static GParamDef save_args[] =
  {
Sven Neumann's avatar
Sven Neumann committed
295
296
297
298
299
300
301
302
303
304
305
306
307
308
    { PARAM_INT32,    "run_mode",     "Interactive, non-interactive" },
    { PARAM_IMAGE,    "image",        "Input image" },
    { PARAM_DRAWABLE, "drawable",     "Drawable to save" },
    { PARAM_STRING,   "filename",     "The name of the file to save the image in" },
    { PARAM_STRING,   "raw_filename", "The name of the file to save the image in" },
    { PARAM_FLOAT,    "quality",      "Quality of saved image (0 <= quality <= 1)" },
    { PARAM_FLOAT,    "smoothing",    "Smoothing factor for saved image (0 <= smoothing <= 1)" },
    { PARAM_INT32,    "optimize",     "Optimization of entropy encoding parameters (0/1)" },
    { PARAM_INT32,    "progressive",  "Enable progressive jpeg image loading - ignored if not compiled with HAVE_PROGRESSIVE_JPEG (0/1)" },
    { PARAM_STRING,   "comment",      "Image comment" },
    { PARAM_INT32,    "subsmp",       "The subsampling option number" },
    { PARAM_INT32,    "baseline",     "Force creation of a baseline JPEG (non-baseline JPEGs can't be read by all decoders) (0/1)" },
    { PARAM_INT32,    "restart",      "Frequency of restart markers (in rows, 0 = no restart markers)" },
    { PARAM_INT32,    "dct",          "DCT algorithm to use (speed/quality tradeoff)" }
Elliot Lee's avatar
Elliot Lee committed
309
310
311
  };
  static int nsave_args = sizeof (save_args) / sizeof (save_args[0]);

312
313
  INIT_I18N();

Elliot Lee's avatar
Elliot Lee committed
314
  gimp_install_procedure ("file_jpeg_load",
315
316
317
                          _("loads files in the JPEG file format"),
                          _("loads files in the JPEG file format"),
                          "Spencer Kimball, Peter Mattis & others",
Elliot Lee's avatar
Elliot Lee committed
318
                          "Spencer Kimball & Peter Mattis",
319
                          "1995-1999",
Elliot Lee's avatar
Elliot Lee committed
320
321
322
323
324
325
326
			  "<Load>/Jpeg",
			  NULL,
                          PROC_PLUG_IN,
                          nload_args, nload_return_vals,
                          load_args, load_return_vals);

  gimp_install_procedure ("file_jpeg_save",
327
328
329
                          _("saves files in the JPEG file format"),
                          _("saves files in the lossy, widely supported JPEG format"),
                          "Spencer Kimball, Peter Mattis & others",
Elliot Lee's avatar
Elliot Lee committed
330
                          "Spencer Kimball & Peter Mattis",
331
                          "1995-1999",
Elliot Lee's avatar
Elliot Lee committed
332
333
334
335
336
337
338
                          "<Save>/Jpeg",
			  "RGB*, GRAY*",
                          PROC_PLUG_IN,
                          nsave_args, 0,
                          save_args, NULL);

  gimp_register_magic_load_handler ("file_jpeg_load", "jpg,jpeg", "", "6,string,JFIF");
Sven Neumann's avatar
Sven Neumann committed
339
  gimp_register_save_handler       ("file_jpeg_save", "jpg,jpeg", "");
Elliot Lee's avatar
Elliot Lee committed
340
341
342
343
344
345
346
347
348
349
350
351
352
}

static void
run (char    *name,
     int      nparams,
     GParam  *param,
     int     *nreturn_vals,
     GParam **return_vals)
{
  static GParam values[2];
  GRunModeType run_mode;
  GStatusType status = STATUS_SUCCESS;
  gint32 image_ID;
Sven Neumann's avatar
Sven Neumann committed
353
354
355
  gint32 drawable_ID;
  gint32 orig_image_ID;
  gint32 display_ID = -1;
356
357
358
#ifdef GIMP_HAVE_PARASITES
  Parasite *parasite;
#endif /* GIMP_HAVE_PARASITES */
359
  int err;
Sven Neumann's avatar
Sven Neumann committed
360
  GimpExportReturnType export = EXPORT_CANCEL;
Elliot Lee's avatar
Elliot Lee committed
361
362
363
364
365
366
367
368
369
370

  run_mode = param[0].data.d_int32;

  *nreturn_vals = 1;
  *return_vals = values;
  values[0].type = PARAM_STATUS;
  values[0].data.d_status = STATUS_CALLING_ERROR;

  if (strcmp (name, "file_jpeg_load") == 0)
    {
371
372
      INIT_I18N();

373
      image_ID = load_image (param[1].data.d_string, run_mode, FALSE);
Elliot Lee's avatar
Elliot Lee committed
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388

      if (image_ID != -1)
	{
	  *nreturn_vals = 2;
	  values[0].data.d_status = STATUS_SUCCESS;
	  values[1].type = PARAM_IMAGE;
	  values[1].data.d_image = image_ID;
	}
      else
	{
	  values[0].data.d_status = STATUS_EXECUTION_ERROR;
	}
    }
  else if (strcmp (name, "file_jpeg_save") == 0)
    {
Manish Singh's avatar
Manish Singh committed
389
      INIT_I18N_UI();
390

Sven Neumann's avatar
Sven Neumann committed
391
392
393
394
395
396
397
398
399
400
401
      image_ID = orig_image_ID = param[1].data.d_int32;
      drawable_ID = param[2].data.d_int32;

       /*  eventually export the image */ 
      switch (run_mode)
	{
	case RUN_INTERACTIVE:
	case RUN_WITH_LAST_VALS:
	  init_gtk ();
	  export = gimp_export_image (&image_ID, &drawable_ID, "JPEG", 
				      (CAN_HANDLE_RGB | CAN_HANDLE_GRAY));
Sven Neumann's avatar
Sven Neumann committed
402
	  switch (export)
Sven Neumann's avatar
Sven Neumann committed
403
	    {
Sven Neumann's avatar
Sven Neumann committed
404
	    case EXPORT_EXPORT: 
Sven Neumann's avatar
Sven Neumann committed
405
	      display_ID = gimp_display_new (image_ID);
406
	      gimp_image_set_filename (image_ID, _("Export Preview"));
Sven Neumann's avatar
Sven Neumann committed
407
	      gimp_displays_flush ();
Sven Neumann's avatar
Sven Neumann committed
408
409
410
411
412
413
414
415
	      break;
	    case EXPORT_IGNORE:
	      break;
	    case EXPORT_CANCEL:
	      *nreturn_vals = 1;
	      values[0].data.d_status = STATUS_EXECUTION_ERROR;
	      return;
	      break;
Sven Neumann's avatar
Sven Neumann committed
416
417
418
419
420
421
422
423
424
425
426
	    }
	  break;
	default:
	  break;
	}
      
      if (image_comment) 
	{
	  g_free (image_comment);
	  image_comment = NULL;
	}
427
#ifdef GIMP_HAVE_PARASITES
Marc Lehmann's avatar
Marc Lehmann committed
428
      parasite = gimp_image_parasite_find (orig_image_ID, "gimp-comment");
Sven Neumann's avatar
Sven Neumann committed
429
430
431
432
433
      if (parasite) 
	{
	  image_comment = g_strdup (parasite->data);
	  parasite_free (parasite);
	}
434
#endif /* GIMP_HAVE_PARASITES */
Sven Neumann's avatar
Sven Neumann committed
435
436
437
      if (!image_comment) 
	image_comment = g_strdup (DEFAULT_COMMENT);

438
439
440
441
      jsvals.quality = DEFAULT_QUALITY;
      jsvals.smoothing = DEFAULT_SMOOTHING;
      jsvals.optimize = DEFAULT_OPTIMIZE;
      jsvals.progressive = DEFAULT_PROGRESSIVE;
442
443
444
445
446
      jsvals.baseline = DEFAULT_BASELINE;
      jsvals.subsmp = DEFAULT_SUBSMP;
      jsvals.restart = DEFAULT_RESTART;
      jsvals.dct = DEFAULT_DCT;
      jsvals.preview = DEFAULT_PREVIEW;
447
      
Elliot Lee's avatar
Elliot Lee committed
448
449
450
451
452
453
      switch (run_mode)
	{
	case RUN_INTERACTIVE:
	  /*  Possibly retrieve data  */
	  gimp_get_data ("file_jpeg_save", &jsvals);

454
455
#ifdef GIMP_HAVE_PARASITES
	  /* load up the previously used values */
Marc Lehmann's avatar
Marc Lehmann committed
456
	  parasite = gimp_image_parasite_find (orig_image_ID, "jpeg-save-options");
457
	  if (parasite)
Sven Neumann's avatar
Sven Neumann committed
458
459
460
461
462
463
464
465
466
467
468
469
	    {
	      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;
	      parasite_free(parasite);
	    }
470
471
#endif /* GIMP_HAVE_PARASITES */
	  
Sven Neumann's avatar
Sven Neumann committed
472
473
474
475
476
477
	  if (!export)
	    {
	      /* we start an undo_group and immediately freeze undo saving
		 so that we can avoid sucking up tile cache with our unneeded
		 preview steps. */
	      gimp_undo_push_group_start (image_ID);
Marc Lehmann's avatar
Marc Lehmann committed
478
	      gimp_image_undo_freeze (image_ID);
Sven Neumann's avatar
Sven Neumann committed
479
	    }
480
481
	  /* prepare for the preview */
	  image_ID_global = image_ID;
Sven Neumann's avatar
Sven Neumann committed
482
483
	  orig_image_ID_global = orig_image_ID;
	  drawable_ID_global = drawable_ID;
484
 
Elliot Lee's avatar
Elliot Lee committed
485
	  /*  First acquire information with a dialog  */
486
	  err = save_dialog ();
Sven Neumann's avatar
Sven Neumann committed
487
 
Sven Neumann's avatar
Sven Neumann committed
488
	  if (export != EXPORT_EXPORT)
Sven Neumann's avatar
Sven Neumann committed
489
490
	    {
	      /* thaw undo saving and end the undo_group. */
Marc Lehmann's avatar
Marc Lehmann committed
491
	      gimp_image_undo_thaw (image_ID);
Sven Neumann's avatar
Sven Neumann committed
492
493
	      gimp_undo_push_group_end (image_ID); 
	    }
494
495

          if (!err)
Elliot Lee's avatar
Elliot Lee committed
496
497
498
499
500
	    return;
	  break;

	case RUN_NONINTERACTIVE:
	  /*  Make sure all the arguments are there!  */
501
	  /*  pw - added two more progressive and comment */
502
	  /*  sg - added subsampling, preview, baseline, restarts and DCT */
Sven Neumann's avatar
Sven Neumann committed
503
	  if (nparams != 14)
Elliot Lee's avatar
Elliot Lee committed
504
505
506
	    status = STATUS_CALLING_ERROR;
	  if (status == STATUS_SUCCESS)
	    {
Sven Neumann's avatar
Sven Neumann committed
507
508
509
	      jsvals.quality     = param[5].data.d_float;
	      jsvals.smoothing   = param[6].data.d_float;
	      jsvals.optimize    = param[7].data.d_int32;
510
511
512
#ifdef HAVE_PROGRESSIVE_JPEG
	      jsvals.progressive = param[8].data.d_int32;
#endif /* HAVE_PROGRESSIVE_JPEG */
Sven Neumann's avatar
Sven Neumann committed
513
514
515
516
517
	      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;
	      jsvals.preview     = FALSE;
518

519
	      /* free up the default -- wasted some effort earlier */
Sven Neumann's avatar
Sven Neumann committed
520
521
522
	      if (image_comment) 
		g_free (image_comment);
	      image_comment = g_strdup (param[9].data.d_string);
Elliot Lee's avatar
Elliot Lee committed
523
524
525
526
527
528
529
	    }
	  if (status == STATUS_SUCCESS &&
	      (jsvals.quality < 0.0 || jsvals.quality > 1.0))
	    status = STATUS_CALLING_ERROR;
	  if (status == STATUS_SUCCESS &&
	      (jsvals.smoothing < 0.0 || jsvals.smoothing > 1.0))
	    status = STATUS_CALLING_ERROR;
530
531
532
533
534
535
	  if (status == STATUS_SUCCESS &&
            (jsvals.subsmp < 0 || jsvals.subsmp > 2))
	    status = STATUS_CALLING_ERROR;
	  if (status == STATUS_SUCCESS &&
	    (jsvals.dct < 0 || jsvals.dct > 2))
	    status = STATUS_CALLING_ERROR;
Manish Singh's avatar
Manish Singh committed
536
	  break;
Elliot Lee's avatar
Elliot Lee committed
537
538
539
540

	case RUN_WITH_LAST_VALS:
	  /*  Possibly retrieve data  */
	  gimp_get_data ("file_jpeg_save", &jsvals);
541
#ifdef GIMP_HAVE_PARASITES
Marc Lehmann's avatar
Marc Lehmann committed
542
	  parasite = gimp_image_parasite_find (orig_image_ID, "jpeg-save-options");
543
	  if (parasite)
Sven Neumann's avatar
Sven Neumann committed
544
545
546
547
548
549
550
551
552
553
554
555
	    {
	      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;
	      parasite_free(parasite);
	    }
556
#endif /* GIMP_HAVE_PARASITES */
Elliot Lee's avatar
Elliot Lee committed
557
558
559
560
561
562
563
	  break;

	default:
	  break;
	}

      *nreturn_vals = 1;
564
      if (save_image (param[3].data.d_string,
Sven Neumann's avatar
Sven Neumann committed
565
566
567
		      image_ID,
		      drawable_ID,
		      orig_image_ID,
568
		      FALSE))
Elliot Lee's avatar
Elliot Lee committed
569
570
571
572
573
574
575
576
	{
	  /*  Store mvals data  */
	  gimp_set_data ("file_jpeg_save", &jsvals, sizeof (JpegSaveVals));

	  values[0].data.d_status = STATUS_SUCCESS;
	}
      else
	values[0].data.d_status = STATUS_EXECUTION_ERROR;
577

Sven Neumann's avatar
Sven Neumann committed
578
      if (export == EXPORT_EXPORT)
Sven Neumann's avatar
Sven Neumann committed
579
	{
Sven Neumann's avatar
Sven Neumann committed
580
581
	  /* If the image was exported, delete the new display. */
	  /* This also deletes the image.                       */
Sven Neumann's avatar
Sven Neumann committed
582
583
584
585
586
587
588
	  
	  if (display_ID > -1)
	    gimp_display_delete (display_ID);
	  else
	    gimp_image_delete (image_ID);
	}

589
590
591
592
593
594
#ifdef GIMP_HAVE_PARASITES

      /* 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. */
      
Marc Lehmann's avatar
Marc Lehmann committed
595
      gimp_image_parasite_detach (orig_image_ID, "gimp-comment");
Sven Neumann's avatar
Sven Neumann committed
596
597
598
599
600
601
      if (strlen (image_comment)) 
	{
	  parasite = parasite_new ("gimp-comment",
				   PARASITE_PERSISTENT,
				   strlen (image_comment) + 1,
				   image_comment);
Marc Lehmann's avatar
Marc Lehmann committed
602
	  gimp_image_parasite_attach (orig_image_ID, parasite);
Sven Neumann's avatar
Sven Neumann committed
603
	  parasite_free (parasite);
Sven Neumann's avatar
Sven Neumann committed
604
	}
Marc Lehmann's avatar
Marc Lehmann committed
605
      gimp_image_parasite_detach (orig_image_ID, "jpeg-save-options");
606
      
Sven Neumann's avatar
Sven Neumann committed
607
      parasite = parasite_new ("jpeg-save-options", 0, sizeof (jsvals), &jsvals);
Marc Lehmann's avatar
Marc Lehmann committed
608
      gimp_image_parasite_attach (orig_image_ID, parasite);
Sven Neumann's avatar
Sven Neumann committed
609
      parasite_free (parasite);
610

Sven Neumann's avatar
Sven Neumann committed
611
#endif /* Have Parasites */  
Elliot Lee's avatar
Elliot Lee committed
612
613
614
615
    }
}


616
617
618
619
620
621
/* Read next byte */
static unsigned int
jpeg_getc (j_decompress_ptr cinfo)
{
  struct jpeg_source_mgr * datasrc = cinfo->src;

Sven Neumann's avatar
Sven Neumann committed
622
623
624
625
626
  if (datasrc->bytes_in_buffer == 0) 
    {
      if (! (*datasrc->fill_input_buffer) (cinfo))
	ERREXIT (cinfo, JERR_CANT_SUSPEND);
    }
627
628
629
630
631
632
633
634
635
636
637
638
639
  datasrc->bytes_in_buffer--;
  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
640
static GString *local_image_comments = NULL;
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659

static boolean
COM_handler (j_decompress_ptr cinfo)
{
  int length;
  unsigned int ch;

  length = jpeg_getc (cinfo) << 8;
  length += jpeg_getc (cinfo);
  if (length < 2)
    return FALSE;
  length -= 2;			/* discount the length word itself */

  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
660
661
662
663
    {
      ch = jpeg_getc (cinfo);
      g_string_append_c (local_image_comments, ch);
    }
664
665
666
667

  return TRUE;
}

Elliot Lee's avatar
Elliot Lee committed
668
typedef struct my_error_mgr {
669
  struct jpeg_error_mgr pub;    /* "public" fields */
Elliot Lee's avatar
Elliot Lee committed
670

671
  jmp_buf setjmp_buffer;        /* for return to caller */
Elliot Lee's avatar
Elliot Lee committed
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
} *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);
}

static gint32
Sven Neumann's avatar
Sven Neumann committed
693
694
695
load_image (char         *filename, 
	    GRunModeType  runmode, 
	    int           preview)
Elliot Lee's avatar
Elliot Lee committed
696
697
698
{
  GPixelRgn pixel_rgn;
  GDrawable *drawable;
699
  gint32 volatile image_ID;
Elliot Lee's avatar
Elliot Lee committed
700
701
702
703
704
  gint32 layer_ID;
  struct jpeg_decompress_struct cinfo;
  struct my_error_mgr jerr;
  FILE *infile;
  guchar *buf;
705
  guchar *padded_buf = NULL;
Elliot Lee's avatar
Elliot Lee committed
706
707
708
709
710
711
712
713
  guchar **rowbuf;
  char *name;
  int image_type;
  int layer_type;
  int tile_height;
  int scanlines;
  int i, start, end;

714
715
716
717
#ifdef GIMP_HAVE_PARASITES
  JpegSaveVals local_save_vals;
  Parasite *comment_parasite;
  Parasite *vals_parasite;
718
#endif /* GIMP_HAVE_PARASITES */
719
720

  
Elliot Lee's avatar
Elliot Lee committed
721
722
723
724
725
726
  /* We set up the normal JPEG error routines. */
  cinfo.err = jpeg_std_error (&jerr.pub);
  jerr.pub.error_exit = my_error_exit;

  if ((infile = fopen (filename, "rb")) == NULL)
    {
727
      g_warning (_("can't open \"%s\"\n"), filename);
Elliot Lee's avatar
Elliot Lee committed
728
729
730
      gimp_quit ();
    }

731
732
733
  if (runmode != RUN_NONINTERACTIVE)
    {
      name = malloc (strlen (filename) + 12);
734
      sprintf (name, _("Loading %s:"), filename);
735
736
737
      gimp_progress_init (name);
      free (name);
    }
Elliot Lee's avatar
Elliot Lee committed
738
739
740
741
742
743
744
745
746
747
748

  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)
	fclose (infile);
749
      if (image_ID != -1 && !preview)
Elliot Lee's avatar
Elliot Lee committed
750
	gimp_image_delete (image_ID);
751
752
      if (preview)
	destroy_preview();
Elliot Lee's avatar
Elliot Lee committed
753
754
755
756
757
758
759
760
761
      gimp_quit ();
    }
  /* 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);

762
  /* pw - step 2.1 let the lib know we want the comments. */
763
764

  jpeg_set_marker_processor (&cinfo, JPEG_COM, COM_handler);
765

Elliot Lee's avatar
Elliot Lee committed
766
767
768
769
770
771
772
773
774
  /* Step 3: read file parameters with jpeg_read_header() */

  (void) jpeg_read_header (&cinfo, TRUE);
  /* 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.
   */

775
#ifdef GIMP_HAVE_PARASITES
776
777
  if (!preview) {
    /* if we had any comments then make a parasite for them */
Sven Neumann's avatar
Sven Neumann committed
778
779
780
781
782
783
784
785
786
787
788
    if (local_image_comments) 
      {
	char *string = local_image_comments->str;
	g_string_free (local_image_comments,FALSE);
	comment_parasite = parasite_new ("gimp-comment", PARASITE_PERSISTENT,
					 strlen (string) + 1, string);
      } 
    else 
      {
	comment_parasite = NULL;
      }
789
  
790
791
792
793
794
    /* pw - figuring out what the saved values were is non-trivial.
     * They don't seem to be in the cinfo structure. For now, I will
     * just use the defaults, but if someone figures out how to derive
     * them this is the place to store them. */

Sven Neumann's avatar
Sven Neumann committed
795
796
797
    local_save_vals.quality     = DEFAULT_QUALITY;
    local_save_vals.smoothing   = DEFAULT_SMOOTHING;
    local_save_vals.optimize    = DEFAULT_OPTIMIZE;
798
799
  
#ifdef HAVE_PROGRESSIVE_JPEG 
Sven Neumann's avatar
Sven Neumann committed
800
    local_save_vals.progressive = cinfo.progressive_mode;
801
#else
Sven Neumann's avatar
Sven Neumann committed
802
    local_save_vals.progressive = 0;
803
#endif /* HAVE_PROGRESSIVE_JPEG */
Sven Neumann's avatar
Sven Neumann committed
804
805
806
807
808
    local_save_vals.baseline    = DEFAULT_BASELINE;
    local_save_vals.subsmp      = DEFAULT_SUBSMP;   /* sg - this _is_ there, but I'm too lazy */ 
    local_save_vals.restart     = DEFAULT_RESTART;
    local_save_vals.dct         = DEFAULT_DCT;
    local_save_vals.preview     = DEFAULT_PREVIEW;
809
  
Sven Neumann's avatar
Sven Neumann committed
810
811
    vals_parasite = parasite_new ("jpeg-save-options", 0,
				  sizeof (local_save_vals), &local_save_vals);
812
  } 
813
814
815
#endif /* GIMP_HAVE_PARASITES */
  
  
Elliot Lee's avatar
Elliot Lee committed
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
  /* 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 ();
  buf = g_new (guchar, tile_height * cinfo.output_width * cinfo.output_components);
835
836
837
838
839
  
  if (preview)
    padded_buf = g_new (guchar, tile_height * cinfo.output_width *
			(cinfo.output_components + 1));

Elliot Lee's avatar
Elliot Lee committed
840
841
842
843
844
845
  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.
846
847
848

     Preview layers, not being on the bottom of a layer stack, MUST HAVE
     AN ALPHA CHANNEL!
Elliot Lee's avatar
Elliot Lee committed
849
850
851
852
853
   */
  switch (cinfo.output_components)
    {
    case 1:
      image_type = GRAY;
854
      layer_type = preview ? GRAYA_IMAGE : GRAY_IMAGE;
Elliot Lee's avatar
Elliot Lee committed
855
856
857
      break;
    case 3:
      image_type = RGB;
858
      layer_type = preview ? RGBA_IMAGE : RGB_IMAGE;
Elliot Lee's avatar
Elliot Lee committed
859
860
      break;
    default:
861
      g_message (_("don't know how to load JPEGs\nwith %d color channels"),
862
                   cinfo.output_components);
Elliot Lee's avatar
Elliot Lee committed
863
864
865
      gimp_quit ();
    }

Sven Neumann's avatar
Sven Neumann committed
866
867
868
869
870
871
872
873
874
  if (preview) 
    {
      image_ID = image_ID_global;
    } 
  else 
    {
      image_ID = gimp_image_new (cinfo.output_width, cinfo.output_height, image_type);
      gimp_image_set_filename (image_ID, filename);
    }
875

Sven Neumann's avatar
Sven Neumann committed
876
877
878
879
880
881
882
883
884
885
886
887
888
889
  if (preview) 
    {
      layer_ID_global = layer_ID = gimp_layer_new (image_ID, _("JPEG preview"),
						   cinfo.output_width,
						   cinfo.output_height,
						   layer_type, 100, NORMAL_MODE);
    } 
  else 
    {
      layer_ID = gimp_layer_new (image_ID, _("Background"),
				 cinfo.output_width,
				 cinfo.output_height,
				 layer_type, 100, NORMAL_MODE);
    }
Elliot Lee's avatar
Elliot Lee committed
890

891
  drawable_global = drawable = gimp_drawable_get (layer_ID);
Elliot Lee's avatar
Elliot Lee committed
892
893
  gimp_pixel_rgn_init (&pixel_rgn, drawable, 0, 0, drawable->width, drawable->height, TRUE, FALSE);

894
895
896
  /* Step 5.1: if the file had resolution information, set it on the
   * image */
#ifdef GIMP_HAVE_RESOLUTION_INFO
897
  if (!preview && cinfo.saw_JFIF_marker)
898
899
900
901
902
903
904
905
906
907
  {
    float xresolution;
    float yresolution;
    float asymmetry;

    xresolution = cinfo.X_density;
    yresolution = cinfo.Y_density;

    switch (cinfo.density_unit) {
    case 0: /* unknown */
Sven Neumann's avatar
Sven Neumann committed
908
909
910
911
912
      asymmetry = xresolution / yresolution;
      xresolution = 72 * asymmetry;
      yresolution = 72;
      break;
      
913
    case 1: /* dots per inch */
Sven Neumann's avatar
Sven Neumann committed
914
      break;
915
916

    case 2: /* dots per cm */
Sven Neumann's avatar
Sven Neumann committed
917
918
919
920
      xresolution *= 2.54;
      yresolution *= 2.54;
      break;
      
921
    default:
Sven Neumann's avatar
Sven Neumann committed
922
923
924
925
      g_message (_("unknown density unit %d\nassuming dots per inch"),
		 cinfo.density_unit);
      break;
    }
926
927
928
929
930
931
932

    if (xresolution > 1e-5 && yresolution > 1e-5)
      gimp_image_set_resolution (image_ID, xresolution, yresolution);
  }
#endif /* GIMP_HAVE_RESOLUTION_INFO */


Elliot Lee's avatar
Elliot Lee committed
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
  /* Step 6: while (scan lines remain to be read) */
  /*           jpeg_read_scanlines(...); */

  /* Here we use the library's state variable cinfo.output_scanline as the
   * loop counter, so that we don't have to keep track ourselves.
   */
  while (cinfo.output_scanline < cinfo.output_height)
    {
      start = cinfo.output_scanline;
      end = cinfo.output_scanline + tile_height;
      end = MIN (end, cinfo.output_height);
      scanlines = end - start;

      for (i = 0; i < scanlines; i++)
	jpeg_read_scanlines (&cinfo, (JSAMPARRAY) &rowbuf[i], 1);

      /*
      for (i = start; i < end; i++)
	gimp_pixel_rgn_set_row (&pixel_rgn, tilerow[i - start], 0, i, drawable->width);
	*/

954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
      if (preview) /* Add a dummy alpha channel -- convert buf to padded_buf */
	{
	  guchar *dest = padded_buf;
	  guchar *src  = buf;
	  gint num = drawable->width * scanlines;

	  switch (cinfo.output_components)
	    {
	    case 1:
	      for (i=0; i<num; i++)
		{
		  *(dest++) = *(src++);
		  *(dest++) = 255;
		}
	      break;
	    case 3:
	      for (i=0; i<num; i++)
		{
		  *(dest++) = *(src++);
		  *(dest++) = *(src++);
		  *(dest++) = *(src++);
		  *(dest++) = 255;
		}
	      break;
	    default:
	      g_warning ("JPEG - shouldn't have gotten here.  Report to adam@gimp.org");
	    }
	}

      gimp_pixel_rgn_set_rect (&pixel_rgn, preview ? padded_buf : buf,
			       0, start, drawable->width, scanlines);
Elliot Lee's avatar
Elliot Lee committed
985

986
987
988
989
      if (runmode != RUN_NONINTERACTIVE)
	{
	  gimp_progress_update ((double) cinfo.output_scanline / (double) cinfo.output_height);
	}
Elliot Lee's avatar
Elliot Lee committed
990
991
992
993
994
995
996
997
998
999
1000
    }

  /* Step 7: Finish decompression */

  jpeg_finish_decompress (&cinfo);
  /* We can ignore the return value since suspension is not possible
   * with the stdio data source.
   */

  /* Step 8: Release JPEG decompression object */