1
/* GIMP - The GNU Image Manipulation Program
2
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
4
* This program is free software; you can redistribute it and/or modify
5
* it under the terms of the GNU General Public License as published by
6
* the Free Software Foundation; either version 2 of the License, or
7
* (at your option) any later version.
9
* This program is distributed in the hope that it will be useful,
10
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
* GNU General Public License for more details.
14
* You should have received a copy of the GNU General Public License
15
* along with this program; if not, write to the Free Software
16
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
29
#include <libexif/exif-data.h>
30
#endif /* HAVE_EXIF */
32
#include <libgimp/gimp.h>
33
#include <libgimp/gimpui.h>
35
#include "libgimp/stdplugins-intl.h"
38
#include "jpeg-load.h"
39
#include "jpeg-save.h"
43
/* Declare local functions.
46
static void query (void);
47
static void run (const gchar *name,
49
const GimpParam *param,
51
GimpParam **return_vals);
53
gboolean undo_touched;
54
gboolean load_interactive;
58
gint32 orig_image_ID_global;
59
gint32 drawable_ID_global;
61
const GimpPlugInInfo PLUG_IN_INFO =
65
query, /* query_proc */
76
static const GimpParamDef load_args[] =
78
{ GIMP_PDB_INT32, "run-mode", "Interactive, non-interactive" },
79
{ GIMP_PDB_STRING, "filename", "The name of the file to load" },
80
{ GIMP_PDB_STRING, "raw-filename", "The name of the file to load" }
82
static const GimpParamDef load_return_vals[] =
84
{ GIMP_PDB_IMAGE, "image", "Output image" }
89
static const GimpParamDef thumb_args[] =
91
{ GIMP_PDB_STRING, "filename", "The name of the file to load" },
92
{ GIMP_PDB_INT32, "thumb-size", "Preferred thumbnail size" }
94
static const GimpParamDef thumb_return_vals[] =
96
{ GIMP_PDB_IMAGE, "image", "Thumbnail image" },
97
{ GIMP_PDB_INT32, "image-width", "Width of full-sized image" },
98
{ GIMP_PDB_INT32, "image-height", "Height of full-sized image" }
101
#endif /* HAVE_EXIF */
103
static const GimpParamDef save_args[] =
105
{ GIMP_PDB_INT32, "run-mode", "Interactive, non-interactive" },
106
{ GIMP_PDB_IMAGE, "image", "Input image" },
107
{ GIMP_PDB_DRAWABLE, "drawable", "Drawable to save" },
108
{ GIMP_PDB_STRING, "filename", "The name of the file to save the image in" },
109
{ GIMP_PDB_STRING, "raw-filename", "The name of the file to save the image in" },
110
{ GIMP_PDB_FLOAT, "quality", "Quality of saved image (0 <= quality <= 1)" },
111
{ GIMP_PDB_FLOAT, "smoothing", "Smoothing factor for saved image (0 <= smoothing <= 1)" },
112
{ GIMP_PDB_INT32, "optimize", "Optimization of entropy encoding parameters (0/1)" },
113
{ GIMP_PDB_INT32, "progressive", "Enable progressive jpeg image loading (0/1)" },
114
{ GIMP_PDB_STRING, "comment", "Image comment" },
115
{ GIMP_PDB_INT32, "subsmp", "The subsampling option number" },
116
{ GIMP_PDB_INT32, "baseline", "Force creation of a baseline JPEG (non-baseline JPEGs can't be read by all decoders) (0/1)" },
117
{ GIMP_PDB_INT32, "restart", "Frequency of restart markers (in rows, 0 = no restart markers)" },
118
{ GIMP_PDB_INT32, "dct", "DCT algorithm to use (speed/quality tradeoff)" }
121
gimp_install_procedure (LOAD_PROC,
122
"loads files in the JPEG file format",
123
"loads files in the JPEG file format",
124
"Spencer Kimball, Peter Mattis & others",
125
"Spencer Kimball & Peter Mattis",
130
G_N_ELEMENTS (load_args),
131
G_N_ELEMENTS (load_return_vals),
132
load_args, load_return_vals);
134
gimp_register_file_handler_mime (LOAD_PROC, "image/jpeg");
135
gimp_register_magic_load_handler (LOAD_PROC,
138
"6,string,JFIF,6,string,Exif");
142
gimp_install_procedure (LOAD_THUMB_PROC,
143
"Loads a thumbnail from a JPEG image",
144
"Loads a thumbnail from a JPEG image (only if it exists)",
145
"S. Mukund <muks@mukund.org>, Sven Neumann <sven@gimp.org>",
146
"S. Mukund <muks@mukund.org>, Sven Neumann <sven@gimp.org>",
151
G_N_ELEMENTS (thumb_args),
152
G_N_ELEMENTS (thumb_return_vals),
153
thumb_args, thumb_return_vals);
155
gimp_register_thumbnail_loader (LOAD_PROC, LOAD_THUMB_PROC);
157
#endif /* HAVE_EXIF */
159
gimp_install_procedure (SAVE_PROC,
160
"saves files in the JPEG file format",
161
"saves files in the lossy, widely supported JPEG format",
162
"Spencer Kimball, Peter Mattis & others",
163
"Spencer Kimball & Peter Mattis",
168
G_N_ELEMENTS (save_args), 0,
171
gimp_register_file_handler_mime (SAVE_PROC, "image/jpeg");
172
gimp_register_save_handler (SAVE_PROC, "jpg,jpeg,jpe", "");
176
run (const gchar *name,
178
const GimpParam *param,
180
GimpParam **return_vals)
182
static GimpParam values[4];
183
GimpRunMode run_mode;
184
GimpPDBStatusType status = GIMP_PDB_SUCCESS;
187
gint32 orig_image_ID;
188
GimpParasite *parasite;
190
GimpExportReturn export = GIMP_EXPORT_CANCEL;
192
run_mode = param[0].data.d_int32;
197
*return_vals = values;
198
values[0].type = GIMP_PDB_STATUS;
199
values[0].data.d_status = GIMP_PDB_EXECUTION_ERROR;
201
image_ID_global = -1;
202
layer_ID_global = -1;
204
if (strcmp (name, LOAD_PROC) == 0)
208
case GIMP_RUN_INTERACTIVE:
209
case GIMP_RUN_WITH_LAST_VALS:
210
gimp_ui_init (PLUG_IN_BINARY, FALSE);
211
load_interactive = TRUE;
214
load_interactive = FALSE;
218
image_ID = load_image (param[1].data.d_string, run_mode, FALSE);
223
values[1].type = GIMP_PDB_IMAGE;
224
values[1].data.d_image = image_ID;
228
status = GIMP_PDB_EXECUTION_ERROR;
235
else if (strcmp (name, LOAD_THUMB_PROC) == 0)
239
status = GIMP_PDB_CALLING_ERROR;
243
const gchar *filename = param[0].data.d_string;
248
image_ID = load_thumbnail_image (filename, &width, &height);
253
values[1].type = GIMP_PDB_IMAGE;
254
values[1].data.d_image = image_ID;
255
values[2].type = GIMP_PDB_INT32;
256
values[2].data.d_int32 = width;
257
values[3].type = GIMP_PDB_INT32;
258
values[3].data.d_int32 = height;
262
status = GIMP_PDB_EXECUTION_ERROR;
267
#endif /* HAVE_EXIF */
269
else if (strcmp (name, SAVE_PROC) == 0)
271
image_ID = orig_image_ID = param[1].data.d_int32;
272
drawable_ID = param[2].data.d_int32;
274
/* eventually export the image */
277
case GIMP_RUN_INTERACTIVE:
278
case GIMP_RUN_WITH_LAST_VALS:
279
gimp_ui_init (PLUG_IN_BINARY, FALSE);
280
export = gimp_export_image (&image_ID, &drawable_ID, "JPEG",
281
(GIMP_EXPORT_CAN_HANDLE_RGB |
282
GIMP_EXPORT_CAN_HANDLE_GRAY));
285
case GIMP_EXPORT_EXPORT:
287
gchar *tmp = g_filename_from_utf8 (_("Export Preview"), -1,
291
gimp_image_set_filename (image_ID, tmp);
298
case GIMP_EXPORT_IGNORE:
300
case GIMP_EXPORT_CANCEL:
301
values[0].data.d_status = GIMP_PDB_CANCEL;
310
g_free (image_comment);
311
image_comment = NULL;
313
parasite = gimp_image_parasite_find (orig_image_ID, "gimp-comment");
316
image_comment = g_strndup (gimp_parasite_data (parasite),
317
gimp_parasite_data_size (parasite));
318
gimp_parasite_free (parasite);
323
exif_data = gimp_metadata_generate_exif (orig_image_ID);
325
jpeg_setup_exif_for_save (exif_data, orig_image_ID);
327
#endif /* HAVE_EXIF */
329
jsvals.quality = DEFAULT_QUALITY;
330
jsvals.smoothing = DEFAULT_SMOOTHING;
331
jsvals.optimize = DEFAULT_OPTIMIZE;
332
jsvals.progressive = DEFAULT_PROGRESSIVE;
333
jsvals.baseline = DEFAULT_BASELINE;
334
jsvals.subsmp = DEFAULT_SUBSMP;
335
jsvals.restart = DEFAULT_RESTART;
336
jsvals.dct = DEFAULT_DCT;
337
jsvals.preview = DEFAULT_PREVIEW;
338
jsvals.save_exif = DEFAULT_EXIF;
339
jsvals.save_thumbnail = DEFAULT_THUMBNAIL;
340
jsvals.save_xmp = DEFAULT_XMP;
344
if (exif_data && (exif_data->data))
345
jsvals.save_thumbnail = TRUE;
347
#endif /* HAVE_EXIF */
351
case GIMP_RUN_INTERACTIVE:
352
/* Possibly retrieve data */
353
gimp_get_data (SAVE_PROC, &jsvals);
355
/* load up the previously used values */
356
parasite = gimp_image_parasite_find (orig_image_ID,
357
"jpeg-save-options");
360
const JpegSaveVals *save_vals = gimp_parasite_data (parasite);
362
jsvals.quality = save_vals->quality;
363
jsvals.smoothing = save_vals->smoothing;
364
jsvals.optimize = save_vals->optimize;
365
jsvals.progressive = save_vals->progressive;
366
jsvals.baseline = save_vals->baseline;
367
jsvals.subsmp = save_vals->subsmp;
368
jsvals.restart = save_vals->restart;
369
jsvals.dct = save_vals->dct;
370
jsvals.preview = save_vals->preview;
371
jsvals.save_exif = save_vals->save_exif;
372
jsvals.save_thumbnail = save_vals->save_thumbnail;
373
jsvals.save_xmp = save_vals->save_xmp;
375
gimp_parasite_free (parasite);
380
/* we freeze undo saving so that we can avoid sucking up
381
* tile cache with our unneeded preview steps. */
382
gimp_image_undo_freeze (image_ID);
387
/* prepare for the preview */
388
image_ID_global = image_ID;
389
orig_image_ID_global = orig_image_ID;
390
drawable_ID_global = drawable_ID;
392
/* First acquire information with a dialog */
393
err = save_dialog ();
397
/* thaw undo saving and flush the displays to have them
398
* reflect the current shortcuts */
399
gimp_image_undo_thaw (image_ID);
400
gimp_displays_flush ();
404
status = GIMP_PDB_CANCEL;
407
case GIMP_RUN_NONINTERACTIVE:
408
/* Make sure all the arguments are there! */
409
/* pw - added two more progressive and comment */
410
/* sg - added subsampling, preview, baseline, restarts and DCT */
413
status = GIMP_PDB_CALLING_ERROR;
417
/* Once the PDB gets default parameters, remove this hack */
418
if (param[5].data.d_float > 0.05)
420
jsvals.quality = 100.0 * param[5].data.d_float;
421
jsvals.smoothing = param[6].data.d_float;
422
jsvals.optimize = param[7].data.d_int32;
423
jsvals.progressive = param[8].data.d_int32;
424
jsvals.baseline = param[11].data.d_int32;
425
jsvals.subsmp = param[10].data.d_int32;
426
jsvals.restart = param[12].data.d_int32;
427
jsvals.dct = param[13].data.d_int32;
429
/* free up the default -- wasted some effort earlier */
430
g_free (image_comment);
431
image_comment = g_strdup (param[9].data.d_string);
434
jsvals.preview = FALSE;
436
if (jsvals.quality < 0.0 || jsvals.quality > 100.0)
437
status = GIMP_PDB_CALLING_ERROR;
438
else if (jsvals.smoothing < 0.0 || jsvals.smoothing > 1.0)
439
status = GIMP_PDB_CALLING_ERROR;
440
else if (jsvals.subsmp < 0 || jsvals.subsmp > 2)
441
status = GIMP_PDB_CALLING_ERROR;
442
else if (jsvals.dct < 0 || jsvals.dct > 2)
443
status = GIMP_PDB_CALLING_ERROR;
447
case GIMP_RUN_WITH_LAST_VALS:
448
/* Possibly retrieve data */
449
gimp_get_data (SAVE_PROC, &jsvals);
451
parasite = gimp_image_parasite_find (orig_image_ID,
452
"jpeg-save-options");
455
const JpegSaveVals *save_vals = gimp_parasite_data (parasite);
457
jsvals.quality = save_vals->quality;
458
jsvals.smoothing = save_vals->smoothing;
459
jsvals.optimize = save_vals->optimize;
460
jsvals.progressive = save_vals->progressive;
461
jsvals.baseline = save_vals->baseline;
462
jsvals.subsmp = save_vals->subsmp;
463
jsvals.restart = save_vals->restart;
464
jsvals.dct = save_vals->dct;
465
jsvals.preview = FALSE;
467
gimp_parasite_free (parasite);
475
if (status == GIMP_PDB_SUCCESS)
477
if (save_image (param[3].data.d_string,
483
/* Store mvals data */
484
gimp_set_data (SAVE_PROC, &jsvals, sizeof (JpegSaveVals));
488
status = GIMP_PDB_EXECUTION_ERROR;
492
if (export == GIMP_EXPORT_EXPORT)
494
/* If the image was exported, delete the new display. */
495
/* This also deletes the image. */
497
if (display_ID != -1)
498
gimp_display_delete (display_ID);
500
gimp_image_delete (image_ID);
503
/* pw - now we need to change the defaults to be whatever
504
* was used to save this image. Dump the old parasites
505
* and add new ones. */
507
gimp_image_parasite_detach (orig_image_ID, "gimp-comment");
508
if (image_comment && strlen (image_comment))
510
parasite = gimp_parasite_new ("gimp-comment",
511
GIMP_PARASITE_PERSISTENT,
512
strlen (image_comment) + 1,
514
gimp_image_parasite_attach (orig_image_ID, parasite);
515
gimp_parasite_free (parasite);
517
gimp_image_parasite_detach (orig_image_ID, "jpeg-save-options");
519
parasite = gimp_parasite_new ("jpeg-save-options",
520
0, sizeof (jsvals), &jsvals);
521
gimp_image_parasite_attach (orig_image_ID, parasite);
522
gimp_parasite_free (parasite);
526
status = GIMP_PDB_CALLING_ERROR;
529
values[0].data.d_status = status;
533
* Here's the routine that will replace the standard error_exit method:
537
my_error_exit (j_common_ptr cinfo)
539
/* cinfo->err really points to a my_error_mgr struct, so coerce pointer */
540
my_error_ptr myerr = (my_error_ptr) cinfo->err;
542
/* Always display the message. */
543
/* We could postpone this until after returning, if we chose. */
544
(*cinfo->err->output_message) (cinfo);
546
/* Return control to the setjmp point */
547
longjmp (myerr->setjmp_buffer, 1);
551
my_emit_message (j_common_ptr cinfo,
556
/* disable loading of EXIF data */
557
cinfo->client_data = GINT_TO_POINTER (TRUE);
559
(*cinfo->err->output_message) (cinfo);
564
my_output_message (j_common_ptr cinfo)
566
gchar buffer[JMSG_LENGTH_MAX + 1];
568
(*cinfo->err->format_message)(cinfo, buffer);
570
if (GPOINTER_TO_INT (cinfo->client_data))
572
gchar *msg = g_strconcat (buffer,
574
_("EXIF data will be ignored."),