gimp/plug-ins/file-jpeg/jpeg.c

648 lines
23 KiB
C
Raw Normal View History

/* GIMP - The GNU Image Manipulation Program
2005-01-04 05:36:43 +08:00
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* This program is free software: you can redistribute it and/or modify
2005-01-04 05:36:43 +08:00
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
2005-01-04 05:36:43 +08:00
* (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, see <https://www.gnu.org/licenses/>.
2005-01-04 05:36:43 +08:00
*/
#include "config.h"
#include <stdio.h>
#include <setjmp.h>
#include <string.h>
#include <jpeglib.h>
#include <jerror.h>
#include <libgimp/gimp.h>
#include <libgimp/gimpui.h>
#include "libgimp/stdplugins-intl.h"
2005-01-04 05:36:43 +08:00
#include "jpeg.h"
#include "jpeg-settings.h"
2005-01-04 05:36:43 +08:00
#include "jpeg-load.h"
#include "jpeg-save.h"
typedef struct _Jpeg Jpeg;
typedef struct _JpegClass JpegClass;
struct _Jpeg
{
GimpPlugIn parent_instance;
};
struct _JpegClass
{
GimpPlugInClass parent_class;
};
#define JPEG_TYPE (jpeg_get_type ())
#define JPEG (obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), JPEG_TYPE, Jpeg))
GType jpeg_get_type (void) G_GNUC_CONST;
static GList * jpeg_query_procedures (GimpPlugIn *plug_in);
static GimpProcedure * jpeg_create_procedure (GimpPlugIn *plug_in,
const gchar *name);
static GimpValueArray * jpeg_load (GimpProcedure *procedure,
GimpRunMode run_mode,
GFile *file,
GimpMetadata *metadata,
GimpMetadataLoadFlags *flags,
GimpProcedureConfig *config,
gpointer run_data);
static GimpValueArray * jpeg_load_thumb (GimpProcedure *procedure,
GFile *file,
gint size,
GimpProcedureConfig *config,
gpointer run_data);
static GimpValueArray * jpeg_save (GimpProcedure *procedure,
GimpRunMode run_mode,
GimpImage *image,
gint n_drawables,
GimpDrawable **drawables,
GFile *file,
GimpMetadata *metadata,
GimpProcedureConfig *config,
gpointer run_data);
G_DEFINE_TYPE (Jpeg, jpeg, GIMP_TYPE_PLUG_IN)
GIMP_MAIN (JPEG_TYPE)
DEFINE_STD_SET_I18N
gboolean undo_touched = FALSE;
GimpDisplay *display = NULL;
gboolean separate_display = FALSE;
GimpImage *orig_image_global = NULL;
GimpDrawable *drawable_global = NULL;
2005-01-04 05:36:43 +08:00
static void
jpeg_class_init (JpegClass *klass)
2005-01-04 05:36:43 +08:00
{
GimpPlugInClass *plug_in_class = GIMP_PLUG_IN_CLASS (klass);
2005-01-04 05:36:43 +08:00
plug_in_class->query_procedures = jpeg_query_procedures;
plug_in_class->create_procedure = jpeg_create_procedure;
plug_in_class->set_i18n = STD_SET_I18N;
}
2005-01-04 05:36:43 +08:00
static void
jpeg_init (Jpeg *jpeg)
2005-01-04 05:36:43 +08:00
{
}
static GList *
jpeg_query_procedures (GimpPlugIn *plug_in)
2005-01-04 05:36:43 +08:00
{
GList *list = NULL;
2005-01-04 05:36:43 +08:00
list = g_list_append (list, g_strdup (LOAD_THUMB_PROC));
list = g_list_append (list, g_strdup (LOAD_PROC));
list = g_list_append (list, g_strdup (SAVE_PROC));
return list;
}
static GimpProcedure *
jpeg_create_procedure (GimpPlugIn *plug_in,
const gchar *name)
{
GimpProcedure *procedure = NULL;
if (! strcmp (name, LOAD_PROC))
{
procedure = gimp_load_procedure_new (plug_in, name,
GIMP_PDB_PROC_TYPE_PLUGIN,
jpeg_load, NULL, NULL);
gimp_procedure_set_menu_label (procedure, _("JPEG image"));
gimp_procedure_set_documentation (procedure,
"Loads files in the JPEG file format",
"Loads files in the JPEG file format",
name);
gimp_procedure_set_attribution (procedure,
"Spencer Kimball, Peter Mattis & others",
"Spencer Kimball & Peter Mattis",
"1995-2007");
gimp_file_procedure_set_mime_types (GIMP_FILE_PROCEDURE (procedure),
"image/jpeg");
gimp_file_procedure_set_extensions (GIMP_FILE_PROCEDURE (procedure),
"jpg,jpeg,jpe");
gimp_file_procedure_set_magics (GIMP_FILE_PROCEDURE (procedure),
"0,string,\xff\xd8\xff");
gimp_load_procedure_set_thumbnail_loader (GIMP_LOAD_PROCEDURE (procedure),
LOAD_THUMB_PROC);
}
else if (! strcmp (name, LOAD_THUMB_PROC))
{
procedure = gimp_thumbnail_procedure_new (plug_in, name,
GIMP_PDB_PROC_TYPE_PLUGIN,
jpeg_load_thumb, NULL, NULL);
gimp_procedure_set_documentation (procedure,
"Loads a thumbnail from a JPEG image",
"Loads a thumbnail from a JPEG image, "
"if one exists",
name);
gimp_procedure_set_attribution (procedure,
"Mukund Sivaraman <muks@mukund.org>, "
"Sven Neumann <sven@gimp.org>",
"Mukund Sivaraman <muks@mukund.org>, "
"Sven Neumann <sven@gimp.org>",
"November 15, 2004");
}
else if (! strcmp (name, SAVE_PROC))
{
procedure = gimp_save_procedure_new (plug_in, name,
GIMP_PDB_PROC_TYPE_PLUGIN,
TRUE, jpeg_save, NULL, NULL);
gimp_procedure_set_image_types (procedure, "RGB*, GRAY*");
gimp_procedure_set_menu_label (procedure, _("JPEG image"));
gimp_procedure_set_documentation (procedure,
"Saves files in the JPEG file format",
"Saves files in the lossy, widely "
"supported JPEG format",
name);
gimp_procedure_set_attribution (procedure,
"Spencer Kimball, Peter Mattis & others",
"Spencer Kimball & Peter Mattis",
"1995-2007");
gimp_file_procedure_set_format_name (GIMP_FILE_PROCEDURE (procedure),
_("JPEG"));
gimp_file_procedure_set_mime_types (GIMP_FILE_PROCEDURE (procedure),
"image/jpeg");
gimp_file_procedure_set_extensions (GIMP_FILE_PROCEDURE (procedure),
"jpg,jpeg,jpe");
/* See bugs #63610 and #61088 for a discussion about the quality
* settings
*/
GIMP_PROC_ARG_DOUBLE (procedure, "quality",
_("_Quality"),
_("Quality of exported image"),
0.0, 1.0, 0.9,
G_PARAM_READWRITE);
GIMP_PROC_ARG_DOUBLE (procedure, "smoothing",
_("S_moothing"),
_("Smoothing factor for exported image"),
0.0, 1.0, 0.0,
G_PARAM_READWRITE);
GIMP_PROC_ARG_BOOLEAN (procedure, "optimize",
_("Optimi_ze"),
_("Use optimized tables during Huffman coding"),
TRUE,
G_PARAM_READWRITE);
GIMP_PROC_ARG_BOOLEAN (procedure, "progressive",
_("_Progressive"),
_("Create progressive JPEG images"),
TRUE,
G_PARAM_READWRITE);
plug-ins: support CMYK import/export for JPEG. We already had import support through littleCMS. We now use fully babl/GEGL which makes our code more straightforward and identical, whichever the input format. The export support is totally new. It comes with a checkbox to propose selecting CMYK export and a label displaying the CMYK profile which will be used. Now this whole implementation has a few drawbacks so far, but it will be a good first sample for future CMYK-related improvements to come: * The export profile I am using is what we call the "simulation profile" from the GimpColorConfig. This corresponds to the default "Soft-proofing" profile as set in Preferences. In particular, this is not the actual soft-proofing profile for this image which might have been changed through the View menu because this information is currently and unfortunately unavailable to plug-ins. It is not the "Preferred CMYK Profile" either, as set in Preferences. TODOS: - We really need to straighten the soft-proof profile core concept by storing it in the image and making it visible to plug-in. - Another interesting improvement could be to create a GimpColorProfile procedure argument which would be mapped to a color profile chooser widget, allowing people to choose profiles in plug-ins. For an export plug-in in particular, it could allow to select a profile different from the soft-proof one at export time. * When we export, if no profile is choosen, babl will use a naive profile. It would be nice to store this naive profile into the JPEG if the "Save color profile" option is checked (same as we store a generic sRGB profile when no RGB profile is set). * When we import, we just import the image as sRGB. Since CMYK gamuts are not necessarily within sRGB (some part of the spectrum is usually well within, but other well outside), other than the basic conversion accuracy issue, we may lose colors. It would be much nicer to be able to select an output RGB profile. Optionally if we could create a RGB color space which is made to contain the whole input CMYK profile color space, without explicit choice step, it would be nice too. * I am using babl's "cmyk" format, not the expected "CMYK" format. "cmyk" is meant to be an inverted CMYK where 0.0 is full ink coverage and 1.0 none. Nevertheless when loading the resulting JPEG in other software (editors or viewers alike), the normal CMYK would always display inverted colors and the inverted cmyk would look fine. Finally I found a docs from libjpeg-turbo library, explaining that Photoshop was wrongly inverting CMYK color data while it should not. This text dates back from 1994, looking at the commit date which introduced this paragraph. In the 28 years since then, could this color inversion have become the de-facto standard for JPEG because one of the main editor would just output all its JPEG files this way? See: https://github.com/libjpeg-turbo/libjpeg-turbo/blob/dfc63d42ee3d1ae8eacb921e89e64ac57861dff6/libjpeg.txt#L1425-L1438
2022-04-18 02:26:41 +08:00
GIMP_PROC_ARG_BOOLEAN (procedure, "cmyk",
_("Export as CM_YK"),
_("Create a CMYK JPEG image using the soft-proofing color profile"),
plug-ins: support CMYK import/export for JPEG. We already had import support through littleCMS. We now use fully babl/GEGL which makes our code more straightforward and identical, whichever the input format. The export support is totally new. It comes with a checkbox to propose selecting CMYK export and a label displaying the CMYK profile which will be used. Now this whole implementation has a few drawbacks so far, but it will be a good first sample for future CMYK-related improvements to come: * The export profile I am using is what we call the "simulation profile" from the GimpColorConfig. This corresponds to the default "Soft-proofing" profile as set in Preferences. In particular, this is not the actual soft-proofing profile for this image which might have been changed through the View menu because this information is currently and unfortunately unavailable to plug-ins. It is not the "Preferred CMYK Profile" either, as set in Preferences. TODOS: - We really need to straighten the soft-proof profile core concept by storing it in the image and making it visible to plug-in. - Another interesting improvement could be to create a GimpColorProfile procedure argument which would be mapped to a color profile chooser widget, allowing people to choose profiles in plug-ins. For an export plug-in in particular, it could allow to select a profile different from the soft-proof one at export time. * When we export, if no profile is choosen, babl will use a naive profile. It would be nice to store this naive profile into the JPEG if the "Save color profile" option is checked (same as we store a generic sRGB profile when no RGB profile is set). * When we import, we just import the image as sRGB. Since CMYK gamuts are not necessarily within sRGB (some part of the spectrum is usually well within, but other well outside), other than the basic conversion accuracy issue, we may lose colors. It would be much nicer to be able to select an output RGB profile. Optionally if we could create a RGB color space which is made to contain the whole input CMYK profile color space, without explicit choice step, it would be nice too. * I am using babl's "cmyk" format, not the expected "CMYK" format. "cmyk" is meant to be an inverted CMYK where 0.0 is full ink coverage and 1.0 none. Nevertheless when loading the resulting JPEG in other software (editors or viewers alike), the normal CMYK would always display inverted colors and the inverted cmyk would look fine. Finally I found a docs from libjpeg-turbo library, explaining that Photoshop was wrongly inverting CMYK color data while it should not. This text dates back from 1994, looking at the commit date which introduced this paragraph. In the 28 years since then, could this color inversion have become the de-facto standard for JPEG because one of the main editor would just output all its JPEG files this way? See: https://github.com/libjpeg-turbo/libjpeg-turbo/blob/dfc63d42ee3d1ae8eacb921e89e64ac57861dff6/libjpeg.txt#L1425-L1438
2022-04-18 02:26:41 +08:00
FALSE,
G_PARAM_READWRITE);
GIMP_PROC_ARG_INT (procedure, "sub-sampling",
_("Su_bsampling"),
_("Sub-sampling type { 0 == 4:2:0 (chroma quartered), "
"1 == 4:2:2 (chroma halved horizontally), "
"2 == 4:4:4 (best quality), "
"3 == 4:4:0 (chroma halved vertically)"),
JPEG_SUBSAMPLING_2x2_1x1_1x1,
JPEG_SUBSAMPLING_1x2_1x1_1x1,
JPEG_SUBSAMPLING_1x1_1x1_1x1,
G_PARAM_READWRITE);
GIMP_PROC_ARG_BOOLEAN (procedure, "baseline",
_("Baseline"),
_("Force creation of a baseline JPEG "
"(non-baseline JPEGs can't be read by all decoders)"),
TRUE,
G_PARAM_READWRITE);
GIMP_PROC_ARG_INT (procedure, "restart",
_("Inter_val (MCU rows):"),
_("Interval of restart markers "
"(in MCU rows, 0 = no restart markers)"),
0, 64, 0,
G_PARAM_READWRITE);
GIMP_PROC_ARG_INT (procedure, "dct",
_("_DCT method"),
_("DCT method to use { INTEGER (0), FIXED (1), "
"FLOAT (2) }"),
0, 2, 0,
G_PARAM_READWRITE);
/* Some auxiliary arguments mostly for interactive usage. */
GIMP_PROC_AUX_ARG_BOOLEAN (procedure, "use-original-quality",
_("_Use quality settings from original image"),
_("If the original image was loaded from a JPEG "
"file using non-standard quality settings "
"(quantization tables), enable this option to "
"get almost the same quality and file size."),
FALSE,
G_PARAM_READWRITE);
GIMP_PROC_AUX_ARG_INT (procedure, "original-quality",
NULL, NULL,
-1, 100, -1,
G_PARAM_READWRITE);
GIMP_PROC_AUX_ARG_INT (procedure, "original-sub-sampling",
NULL, NULL,
JPEG_SUBSAMPLING_2x2_1x1_1x1,
JPEG_SUBSAMPLING_1x2_1x1_1x1,
JPEG_SUBSAMPLING_2x2_1x1_1x1,
G_PARAM_READWRITE);
GIMP_PROC_AUX_ARG_INT (procedure, "original-num-quant-tables",
NULL, NULL,
-1, 4, -1,
G_PARAM_READWRITE);
GIMP_PROC_AUX_ARG_BOOLEAN (procedure, "show-preview",
_("Sho_w preview in image window"),
_("Creates a temporary layer with an export preview"),
FALSE,
G_PARAM_READWRITE);
GIMP_PROC_AUX_ARG_BOOLEAN (procedure, "use-arithmetic-coding",
_("Use _arithmetic coding"),
_("Older software may have trouble opening "
"arithmetic-coded images"),
FALSE,
G_PARAM_READWRITE);
GIMP_PROC_AUX_ARG_BOOLEAN (procedure, "use-restart",
_("Use restart mar_kers"),
NULL, FALSE,
G_PARAM_READWRITE);
gimp_save_procedure_set_support_exif (GIMP_SAVE_PROCEDURE (procedure), TRUE);
gimp_save_procedure_set_support_iptc (GIMP_SAVE_PROCEDURE (procedure), TRUE);
gimp_save_procedure_set_support_xmp (GIMP_SAVE_PROCEDURE (procedure), TRUE);
gimp_save_procedure_set_support_profile (GIMP_SAVE_PROCEDURE (procedure), TRUE);
gimp_save_procedure_set_support_thumbnail (GIMP_SAVE_PROCEDURE (procedure), TRUE);
gimp_save_procedure_set_support_comment (GIMP_SAVE_PROCEDURE (procedure), TRUE);
}
return procedure;
}
static GimpValueArray *
jpeg_load (GimpProcedure *procedure,
GimpRunMode run_mode,
GFile *file,
GimpMetadata *metadata,
GimpMetadataLoadFlags *flags,
GimpProcedureConfig *config,
gpointer run_data)
{
GimpValueArray *return_vals;
GimpImage *image;
gboolean resolution_loaded = FALSE;
gboolean ps_metadata_loaded = FALSE;
GError *error = NULL;
2005-01-04 05:36:43 +08:00
gegl_init (NULL, NULL);
2005-01-04 05:36:43 +08:00
preview_image = NULL;
preview_layer = NULL;
switch (run_mode)
2005-01-04 05:36:43 +08:00
{
case GIMP_RUN_INTERACTIVE:
case GIMP_RUN_WITH_LAST_VALS:
gimp_ui_init (PLUG_IN_BINARY);
break;
default:
break;
}
image = load_image (file, run_mode, FALSE,
&resolution_loaded, &ps_metadata_loaded, &error);
if (image)
{
if (resolution_loaded)
*flags &= ~GIMP_METADATA_LOAD_RESOLUTION;
}
if (! image)
return gimp_procedure_new_return_values (procedure,
GIMP_PDB_EXECUTION_ERROR,
error);
return_vals = gimp_procedure_new_return_values (procedure,
GIMP_PDB_SUCCESS,
NULL);
GIMP_VALUES_SET_IMAGE (return_vals, 1, image);
return return_vals;
}
static GimpValueArray *
jpeg_load_thumb (GimpProcedure *procedure,
GFile *file,
gint size,
GimpProcedureConfig *config,
gpointer run_data)
{
GimpValueArray *return_vals;
GimpImage *image;
gint width = 0;
gint height = 0;
GimpImageType type = -1;
GError *error = NULL;
gegl_init (NULL, NULL);
preview_image = NULL;
preview_layer = NULL;
2005-01-04 05:36:43 +08:00
image = load_thumbnail_image (file, &width, &height, &type,
&error);
if (! image)
return gimp_procedure_new_return_values (procedure,
GIMP_PDB_EXECUTION_ERROR,
error);
2005-01-04 05:36:43 +08:00
return_vals = gimp_procedure_new_return_values (procedure,
GIMP_PDB_SUCCESS,
NULL);
GIMP_VALUES_SET_IMAGE (return_vals, 1, image);
GIMP_VALUES_SET_INT (return_vals, 2, width);
GIMP_VALUES_SET_INT (return_vals, 3, height);
GIMP_VALUES_SET_ENUM (return_vals, 4, type);
GIMP_VALUES_SET_INT (return_vals, 5, 1); /* 1 layer */
return return_vals;
}
static GimpValueArray *
jpeg_save (GimpProcedure *procedure,
GimpRunMode run_mode,
GimpImage *image,
gint n_drawables,
GimpDrawable **drawables,
GFile *file,
GimpMetadata *metadata,
GimpProcedureConfig *config,
gpointer run_data)
{
GimpPDBStatusType status = GIMP_PDB_SUCCESS;
GimpImage *orig_image;
GimpExportReturn export = GIMP_EXPORT_CANCEL;
GError *error = NULL;
gint orig_num_quant_tables = -1;
gint orig_quality = -1;
JpegSubsampling orig_subsmp = JPEG_SUBSAMPLING_2x2_1x1_1x1;
gegl_init (NULL, NULL);
preview_image = NULL;
preview_layer = NULL;
orig_image = image;
switch (run_mode)
{
case GIMP_RUN_INTERACTIVE:
case GIMP_RUN_WITH_LAST_VALS:
gimp_ui_init (PLUG_IN_BINARY);
export = gimp_export_image (&image, &n_drawables, &drawables, "JPEG",
GIMP_EXPORT_CAN_HANDLE_RGB |
GIMP_EXPORT_CAN_HANDLE_GRAY);
switch (export)
{
case GIMP_EXPORT_EXPORT:
display = NULL;
separate_display = TRUE;
break;
case GIMP_EXPORT_IGNORE:
2005-01-04 05:36:43 +08:00
break;
case GIMP_EXPORT_CANCEL:
return gimp_procedure_new_return_values (procedure,
GIMP_PDB_CANCEL,
NULL);
2005-01-04 05:36:43 +08:00
break;
}
break;
2005-01-04 05:36:43 +08:00
default:
break;
}
if (n_drawables != 1)
{
g_set_error (&error, G_FILE_ERROR, 0,
_("JPEG format does not support multiple layers."));
return gimp_procedure_new_return_values (procedure,
GIMP_PDB_CALLING_ERROR,
error);
}
/* Override preferences from JPG export defaults (if saved). */
switch (run_mode)
{
case GIMP_RUN_NONINTERACTIVE:
g_object_set (config, "show-preview", FALSE, NULL);
break;
case GIMP_RUN_INTERACTIVE:
case GIMP_RUN_WITH_LAST_VALS:
2005-01-04 05:36:43 +08:00
{
/* restore the values found when loading the file (if available) */
gdouble dquality;
gint quality;
gint subsmp;
jpeg_restore_original_settings (orig_image,
&orig_quality,
&orig_subsmp,
&orig_num_quant_tables);
g_object_get (config,
"quality", &dquality,
"sub-sampling", &subsmp,
NULL);
quality = (gint) (dquality * 100.0);
/* If this image was loaded from a JPEG file and has not
* been saved yet, try to use some of the settings from the
* original file if they are better than the default values.
*/
if (orig_quality > quality)
2005-01-04 05:36:43 +08:00
{
quality = orig_quality;
dquality = (gdouble) quality / 100.0;
g_object_set (config, "quality", dquality, NULL);
2005-01-04 05:36:43 +08:00
}
if (orig_quality > 0)
2005-01-04 05:36:43 +08:00
{
/* Skip changing subsampling to original if we already have
* best setting or if original have worst setting
*/
if (!(subsmp == JPEG_SUBSAMPLING_1x1_1x1_1x1 ||
orig_subsmp == JPEG_SUBSAMPLING_2x2_1x1_1x1))
{
subsmp = orig_subsmp;
g_object_set (config, "sub-sampling", orig_subsmp, NULL);
}
if (orig_quality == quality && orig_subsmp == subsmp)
{
g_object_set (config, "use-original-quality", TRUE, NULL);
}
}
}
break;
}
g_object_set (config,
"original-sub-sampling", orig_subsmp,
"original-quality", orig_quality,
"original-num-quant-tables", orig_num_quant_tables,
NULL);
2005-01-04 05:36:43 +08:00
if (run_mode == GIMP_RUN_INTERACTIVE)
{
gboolean show_preview = FALSE;
g_object_get (config, "show-preview", &show_preview, NULL);
if (show_preview)
{
/* we freeze undo saving so that we can avoid sucking up
* tile cache with our unneeded preview steps. */
gimp_image_undo_freeze (image);
undo_touched = TRUE;
2005-01-04 05:36:43 +08:00
}
/* prepare for the preview */
preview_image = image;
orig_image_global = orig_image;
drawable_global = drawables[0];
/* First acquire information with a dialog */
if (! save_dialog (procedure, config, drawables[0], orig_image))
2005-01-04 05:36:43 +08:00
{
status = GIMP_PDB_CANCEL;
2005-01-04 05:36:43 +08:00
}
if (undo_touched)
2005-01-04 05:36:43 +08:00
{
/* thaw undo saving and flush the displays to have them
* reflect the current shortcuts
*/
gimp_image_undo_thaw (image);
gimp_displays_flush ();
}
}
2005-01-04 05:36:43 +08:00
if (status == GIMP_PDB_SUCCESS)
{
if (! save_image (file, config,
image, drawables[0], orig_image, FALSE,
&error))
2005-01-04 05:36:43 +08:00
{
status = GIMP_PDB_EXECUTION_ERROR;
}
}
if (status == GIMP_PDB_SUCCESS)
{
if (metadata)
gimp_metadata_set_bits_per_sample (metadata, 8);
}
if (export == GIMP_EXPORT_EXPORT)
{
/* If the image was exported, delete the new display. This also
* deletes the image.
*/
if (display)
{
gimp_display_delete (display);
gimp_display_present (gimp_default_display ());
}
else
{
gimp_image_delete (image);
}
g_free (drawables);
}
return gimp_procedure_new_return_values (procedure, status, error);
2005-01-04 05:36:43 +08:00
}
/*
* Here's the routine that will replace the standard error_exit method:
*/
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);
}
void
my_output_message (j_common_ptr cinfo)
{
gchar buffer[JMSG_LENGTH_MAX + 1];
(*cinfo->err->format_message)(cinfo, buffer);
g_message ("%s", buffer);
2005-01-04 05:36:43 +08:00
}