mirror of https://github.com/GNOME/gimp.git
Recommitting, perserving history
This commit is contained in:
parent
4d1396596d
commit
e5943a6393
|
@ -0,0 +1,912 @@
|
|||
/* 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
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include "jpeg.h"
|
||||
#include "jpeg-load.h"
|
||||
|
||||
/* Read next byte */
|
||||
static guint
|
||||
jpeg_getc (j_decompress_ptr cinfo)
|
||||
{
|
||||
struct jpeg_source_mgr *datasrc = cinfo->src;
|
||||
|
||||
if (datasrc->bytes_in_buffer == 0)
|
||||
{
|
||||
if (! (*datasrc->fill_input_buffer) (cinfo))
|
||||
ERREXIT (cinfo, JERR_CANT_SUSPEND);
|
||||
}
|
||||
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.
|
||||
*/
|
||||
static GString *local_image_comments = NULL;
|
||||
|
||||
static boolean
|
||||
COM_handler (j_decompress_ptr cinfo)
|
||||
{
|
||||
gint length;
|
||||
guint 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)
|
||||
{
|
||||
ch = jpeg_getc (cinfo);
|
||||
g_string_append_c (local_image_comments, ch);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gint32
|
||||
load_image (const gchar *filename,
|
||||
GimpRunMode runmode,
|
||||
gboolean preview)
|
||||
{
|
||||
GimpPixelRgn pixel_rgn;
|
||||
GimpDrawable *drawable;
|
||||
gint32 volatile image_ID;
|
||||
gint32 layer_ID;
|
||||
struct jpeg_decompress_struct cinfo;
|
||||
struct my_error_mgr jerr;
|
||||
FILE *infile;
|
||||
guchar *buf;
|
||||
guchar * volatile padded_buf = NULL;
|
||||
guchar **rowbuf;
|
||||
gint image_type;
|
||||
gint layer_type;
|
||||
gint tile_height;
|
||||
gint scanlines;
|
||||
gint i, start, end;
|
||||
|
||||
GimpParasite * volatile comment_parasite = NULL;
|
||||
|
||||
#ifdef HAVE_EXIF
|
||||
GimpParasite *exif_parasite = NULL;
|
||||
ExifData *exif_data = NULL;
|
||||
#endif
|
||||
|
||||
/* We set up the normal JPEG error routines. */
|
||||
cinfo.err = jpeg_std_error (&jerr.pub);
|
||||
jerr.pub.error_exit = my_error_exit;
|
||||
|
||||
/* flag warnings, so we try to ignore corrupt EXIF data */
|
||||
if (!preview)
|
||||
{
|
||||
cinfo.client_data = GINT_TO_POINTER (FALSE);
|
||||
|
||||
jerr.pub.emit_message = my_emit_message;
|
||||
jerr.pub.output_message = my_output_message;
|
||||
}
|
||||
|
||||
if ((infile = fopen (filename, "rb")) == NULL)
|
||||
{
|
||||
g_message (_("Could not open '%s' for reading: %s"),
|
||||
gimp_filename_to_utf8 (filename), g_strerror (errno));
|
||||
gimp_quit ();
|
||||
}
|
||||
|
||||
if (!preview)
|
||||
{
|
||||
gchar *name = g_strdup_printf (_("Opening '%s'..."),
|
||||
gimp_filename_to_utf8 (filename));
|
||||
|
||||
gimp_progress_init (name);
|
||||
g_free (name);
|
||||
}
|
||||
|
||||
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);
|
||||
if (image_ID != -1 && !preview)
|
||||
gimp_image_delete (image_ID);
|
||||
if (preview)
|
||||
destroy_preview();
|
||||
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);
|
||||
|
||||
/* pw - step 2.1 let the lib know we want the comments. */
|
||||
|
||||
jpeg_set_marker_processor (&cinfo, JPEG_COM, COM_handler);
|
||||
|
||||
/* 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.
|
||||
*/
|
||||
|
||||
if (!preview)
|
||||
{
|
||||
/* if we had any comments then make a parasite for them */
|
||||
if (local_image_comments && local_image_comments->len)
|
||||
{
|
||||
gchar *comment = local_image_comments->str;
|
||||
|
||||
g_string_free (local_image_comments, FALSE);
|
||||
|
||||
local_image_comments = NULL;
|
||||
|
||||
if (g_utf8_validate (comment, -1, NULL))
|
||||
comment_parasite = gimp_parasite_new ("gimp-comment",
|
||||
GIMP_PARASITE_PERSISTENT,
|
||||
strlen (comment) + 1,
|
||||
comment);
|
||||
g_free (comment);
|
||||
}
|
||||
|
||||
/* 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 */
|
||||
}
|
||||
|
||||
/* 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);
|
||||
|
||||
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.
|
||||
|
||||
Preview layers, not being on the bottom of a layer stack, MUST HAVE
|
||||
AN ALPHA CHANNEL!
|
||||
*/
|
||||
switch (cinfo.output_components)
|
||||
{
|
||||
case 1:
|
||||
image_type = GIMP_GRAY;
|
||||
layer_type = preview ? GIMP_GRAYA_IMAGE : GIMP_GRAY_IMAGE;
|
||||
break;
|
||||
|
||||
case 3:
|
||||
image_type = GIMP_RGB;
|
||||
layer_type = preview ? GIMP_RGBA_IMAGE : GIMP_RGB_IMAGE;
|
||||
break;
|
||||
|
||||
case 4:
|
||||
if (cinfo.out_color_space == JCS_CMYK)
|
||||
{
|
||||
image_type = GIMP_RGB;
|
||||
layer_type = GIMP_RGB_IMAGE;
|
||||
break;
|
||||
}
|
||||
/*fallthrough*/
|
||||
|
||||
default:
|
||||
g_message ("Don't know how to load JPEGs\n"
|
||||
"with %d color channels\n"
|
||||
"using colorspace %d (%d)",
|
||||
cinfo.output_components, cinfo.out_color_space,
|
||||
cinfo.jpeg_color_space);
|
||||
gimp_quit ();
|
||||
break;
|
||||
}
|
||||
|
||||
if (preview)
|
||||
padded_buf = g_new (guchar, tile_height * cinfo.output_width *
|
||||
(cinfo.output_components + 1));
|
||||
else if (cinfo.out_color_space == JCS_CMYK)
|
||||
padded_buf = g_new (guchar, tile_height * cinfo.output_width * 3);
|
||||
else
|
||||
padded_buf = NULL;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
if (preview)
|
||||
{
|
||||
layer_ID_global = layer_ID =
|
||||
gimp_layer_new (image_ID, _("JPEG preview"),
|
||||
cinfo.output_width,
|
||||
cinfo.output_height,
|
||||
layer_type, 100, GIMP_NORMAL_MODE);
|
||||
}
|
||||
else
|
||||
{
|
||||
layer_ID = gimp_layer_new (image_ID, _("Background"),
|
||||
cinfo.output_width,
|
||||
cinfo.output_height,
|
||||
layer_type, 100, GIMP_NORMAL_MODE);
|
||||
}
|
||||
|
||||
drawable_global = drawable = gimp_drawable_get (layer_ID);
|
||||
gimp_pixel_rgn_init (&pixel_rgn, drawable, 0, 0,
|
||||
drawable->width, drawable->height, TRUE, FALSE);
|
||||
|
||||
/* Step 5.1: if the file had resolution information, set it on the image */
|
||||
if (!preview && cinfo.saw_JFIF_marker)
|
||||
{
|
||||
gdouble xresolution;
|
||||
gdouble yresolution;
|
||||
gdouble asymmetry;
|
||||
|
||||
xresolution = cinfo.X_density;
|
||||
yresolution = cinfo.Y_density;
|
||||
|
||||
switch (cinfo.density_unit)
|
||||
{
|
||||
case 0: /* unknown -> set the aspect ratio but use the default
|
||||
* image resolution
|
||||
*/
|
||||
if (cinfo.Y_density != 0)
|
||||
asymmetry = xresolution / yresolution;
|
||||
else
|
||||
asymmetry = 1.0;
|
||||
|
||||
gimp_image_get_resolution (image_ID, &xresolution, &yresolution);
|
||||
xresolution *= asymmetry;
|
||||
break;
|
||||
|
||||
case 1: /* dots per inch */
|
||||
break;
|
||||
|
||||
case 2: /* dots per cm */
|
||||
xresolution *= 2.54;
|
||||
yresolution *= 2.54;
|
||||
gimp_image_set_unit (image_ID, GIMP_UNIT_MM);
|
||||
break;
|
||||
|
||||
default:
|
||||
g_message ("Unknown density unit %d\nassuming dots per inch",
|
||||
cinfo.density_unit);
|
||||
break;
|
||||
}
|
||||
|
||||
gimp_image_set_resolution (image_ID, xresolution, yresolution);
|
||||
}
|
||||
|
||||
/* 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);
|
||||
|
||||
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.\nReport to http://bugzilla.gnome.org/");
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (cinfo.out_color_space == JCS_CMYK) /* buf-> RGB in padded_buf */
|
||||
{
|
||||
guchar *dest = padded_buf;
|
||||
guchar *src = buf;
|
||||
gint num = drawable->width * scanlines;
|
||||
|
||||
for (i = 0; i < num; i++)
|
||||
{
|
||||
guint r_c, g_m, b_y, a_k;
|
||||
|
||||
r_c = *(src++);
|
||||
g_m = *(src++);
|
||||
b_y = *(src++);
|
||||
a_k = *(src++);
|
||||
*(dest++) = (r_c * a_k) / 255;
|
||||
*(dest++) = (g_m * a_k) / 255;
|
||||
*(dest++) = (b_y * a_k) / 255;
|
||||
}
|
||||
}
|
||||
|
||||
gimp_pixel_rgn_set_rect (&pixel_rgn, padded_buf ? padded_buf : buf,
|
||||
0, start, drawable->width, scanlines);
|
||||
|
||||
if (! preview)
|
||||
gimp_progress_update ((gdouble) cinfo.output_scanline /
|
||||
(gdouble) cinfo.output_height);
|
||||
}
|
||||
|
||||
/* 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 */
|
||||
|
||||
/* This is an important step since it will release a good deal of memory. */
|
||||
jpeg_destroy_decompress (&cinfo);
|
||||
|
||||
/* free up the temporary buffers */
|
||||
g_free (rowbuf);
|
||||
g_free (buf);
|
||||
g_free (padded_buf);
|
||||
|
||||
/* After finish_decompress, we can close the input file.
|
||||
* Here we postpone it until after no more JPEG errors are possible,
|
||||
* so as to simplify the setjmp error logic above. (Actually, I don't
|
||||
* think that jpeg_destroy can do an error exit, but why assume anything...)
|
||||
*/
|
||||
fclose (infile);
|
||||
|
||||
/* At this point you may want to check to see whether any corrupt-data
|
||||
* warnings occurred (test whether jerr.num_warnings is nonzero).
|
||||
*/
|
||||
|
||||
/* Tell the GIMP to display the image.
|
||||
*/
|
||||
gimp_image_add_layer (image_ID, layer_ID, 0);
|
||||
gimp_drawable_flush (drawable);
|
||||
|
||||
/* pw - Last of all, attach the parasites (couldn't do it earlier -
|
||||
there was no image. */
|
||||
|
||||
if (!preview)
|
||||
{
|
||||
if (comment_parasite)
|
||||
{
|
||||
gimp_image_parasite_attach (image_ID, comment_parasite);
|
||||
gimp_parasite_free (comment_parasite);
|
||||
|
||||
comment_parasite = NULL;
|
||||
}
|
||||
|
||||
#ifdef HAVE_EXIF
|
||||
#define EXIF_HEADER_SIZE 8
|
||||
|
||||
if (! GPOINTER_TO_INT (cinfo.client_data))
|
||||
{
|
||||
exif_data = exif_data_new_from_file (filename);
|
||||
if (exif_data)
|
||||
{
|
||||
guchar *exif_buf;
|
||||
guint exif_buf_len;
|
||||
|
||||
exif_data_save_data (exif_data, &exif_buf, &exif_buf_len);
|
||||
exif_data_unref (exif_data);
|
||||
|
||||
if (exif_buf_len > EXIF_HEADER_SIZE)
|
||||
{
|
||||
exif_parasite = gimp_parasite_new ("exif-data",
|
||||
GIMP_PARASITE_PERSISTENT,
|
||||
exif_buf_len, exif_buf);
|
||||
gimp_image_parasite_attach (image_ID, exif_parasite);
|
||||
gimp_parasite_free (exif_parasite);
|
||||
}
|
||||
|
||||
free (exif_buf);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
return image_ID;
|
||||
}
|
||||
|
||||
#ifdef HAVE_EXIF
|
||||
|
||||
typedef struct
|
||||
{
|
||||
struct jpeg_source_mgr pub; /* public fields */
|
||||
|
||||
gchar *buffer;
|
||||
gint size;
|
||||
JOCTET terminal[2];
|
||||
} my_source_mgr;
|
||||
|
||||
typedef my_source_mgr * my_src_ptr;
|
||||
|
||||
static void
|
||||
init_source (j_decompress_ptr cinfo)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
static boolean
|
||||
fill_input_buffer (j_decompress_ptr cinfo)
|
||||
{
|
||||
my_src_ptr src = (my_src_ptr) cinfo->src;
|
||||
|
||||
/* Since we have given all we have got already
|
||||
* we simply fake an end of file
|
||||
*/
|
||||
|
||||
src->pub.next_input_byte = src->terminal;
|
||||
src->pub.bytes_in_buffer = 2;
|
||||
src->terminal[0] = (JOCTET) 0xFF;
|
||||
src->terminal[1] = (JOCTET) JPEG_EOI;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
skip_input_data (j_decompress_ptr cinfo,
|
||||
long num_bytes)
|
||||
{
|
||||
my_src_ptr src = (my_src_ptr) cinfo->src;
|
||||
|
||||
src->pub.next_input_byte = src->pub.next_input_byte + num_bytes;
|
||||
}
|
||||
|
||||
static void
|
||||
term_source (j_decompress_ptr cinfo)
|
||||
{
|
||||
}
|
||||
|
||||
gint32
|
||||
load_thumbnail_image (const gchar *filename,
|
||||
gint *width,
|
||||
gint *height)
|
||||
{
|
||||
gint32 volatile image_ID;
|
||||
ExifData *exif_data;
|
||||
GimpPixelRgn pixel_rgn;
|
||||
GimpDrawable *drawable;
|
||||
gint32 layer_ID;
|
||||
struct jpeg_decompress_struct cinfo;
|
||||
struct my_error_mgr jerr;
|
||||
guchar *buf;
|
||||
guchar * volatile padded_buf = NULL;
|
||||
guchar **rowbuf;
|
||||
gint image_type;
|
||||
gint layer_type;
|
||||
gint tile_height;
|
||||
gint scanlines;
|
||||
gint i, start, end;
|
||||
my_src_ptr src;
|
||||
FILE *infile;
|
||||
|
||||
image_ID = -1;
|
||||
exif_data = exif_data_new_from_file (filename);
|
||||
|
||||
if (! ((exif_data) && (exif_data->data) && (exif_data->size > 0)))
|
||||
return -1;
|
||||
|
||||
cinfo.err = jpeg_std_error (&jerr.pub);
|
||||
jerr.pub.error_exit = my_error_exit;
|
||||
|
||||
cinfo.client_data = GINT_TO_POINTER (FALSE);
|
||||
|
||||
jerr.pub.emit_message = my_emit_message;
|
||||
jerr.pub.output_message = my_output_message;
|
||||
|
||||
{
|
||||
gchar *name = g_strdup_printf (_("Opening thumbnail for '%s'..."),
|
||||
gimp_filename_to_utf8 (filename));
|
||||
gimp_progress_init (name);
|
||||
g_free (name);
|
||||
}
|
||||
|
||||
/* 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 (image_ID != -1)
|
||||
gimp_image_delete (image_ID);
|
||||
|
||||
if (exif_data)
|
||||
{
|
||||
exif_data_unref (exif_data);
|
||||
exif_data = NULL;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Now we can initialize the JPEG decompression object. */
|
||||
jpeg_create_decompress (&cinfo);
|
||||
|
||||
/* Step 2: specify data source (eg, a file) */
|
||||
|
||||
if (cinfo.src == NULL)
|
||||
cinfo.src = (struct jpeg_source_mgr *)(*cinfo.mem->alloc_small)
|
||||
((j_common_ptr) &cinfo, JPOOL_PERMANENT,
|
||||
sizeof (my_source_mgr));
|
||||
|
||||
src = (my_src_ptr) cinfo.src;
|
||||
|
||||
src->pub.init_source = init_source;
|
||||
src->pub.fill_input_buffer = fill_input_buffer;
|
||||
src->pub.skip_input_data = skip_input_data;
|
||||
src->pub.resync_to_restart = jpeg_resync_to_restart;
|
||||
src->pub.term_source = term_source;
|
||||
|
||||
src->pub.bytes_in_buffer = exif_data->size;
|
||||
src->pub.next_input_byte = exif_data->data;
|
||||
|
||||
src->buffer = exif_data->data;
|
||||
src->size = exif_data->size;
|
||||
|
||||
/* Step 3: read file parameters with jpeg_read_header() */
|
||||
|
||||
jpeg_read_header (&cinfo, TRUE);
|
||||
|
||||
/* 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);
|
||||
|
||||
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.
|
||||
*
|
||||
* Preview layers, not being on the bottom of a layer stack,
|
||||
* MUST HAVE AN ALPHA CHANNEL!
|
||||
*/
|
||||
switch (cinfo.output_components)
|
||||
{
|
||||
case 1:
|
||||
image_type = GIMP_GRAY;
|
||||
layer_type = GIMP_GRAY_IMAGE;
|
||||
break;
|
||||
|
||||
case 3:
|
||||
image_type = GIMP_RGB;
|
||||
layer_type = GIMP_RGB_IMAGE;
|
||||
break;
|
||||
|
||||
case 4:
|
||||
if (cinfo.out_color_space == JCS_CMYK)
|
||||
{
|
||||
image_type = GIMP_RGB;
|
||||
layer_type = GIMP_RGB_IMAGE;
|
||||
break;
|
||||
}
|
||||
/*fallthrough*/
|
||||
|
||||
default:
|
||||
g_message ("Don't know how to load JPEGs\n"
|
||||
"with %d color channels\n"
|
||||
"using colorspace %d (%d)",
|
||||
cinfo.output_components, cinfo.out_color_space,
|
||||
cinfo.jpeg_color_space);
|
||||
|
||||
if (exif_data)
|
||||
{
|
||||
exif_data_unref (exif_data);
|
||||
exif_data = NULL;
|
||||
}
|
||||
|
||||
return -1;
|
||||
break;
|
||||
}
|
||||
|
||||
if (cinfo.out_color_space == JCS_CMYK)
|
||||
padded_buf = g_new (guchar, tile_height * cinfo.output_width * 3);
|
||||
else
|
||||
padded_buf = NULL;
|
||||
|
||||
image_ID = gimp_image_new (cinfo.output_width, cinfo.output_height,
|
||||
image_type);
|
||||
gimp_image_set_filename (image_ID, filename);
|
||||
|
||||
layer_ID = gimp_layer_new (image_ID, _("Background"),
|
||||
cinfo.output_width,
|
||||
cinfo.output_height,
|
||||
layer_type, 100, GIMP_NORMAL_MODE);
|
||||
|
||||
drawable_global = drawable = gimp_drawable_get (layer_ID);
|
||||
gimp_pixel_rgn_init (&pixel_rgn, drawable, 0, 0,
|
||||
drawable->width, drawable->height, TRUE, FALSE);
|
||||
|
||||
/* Step 5.1: if the file had resolution information, set it on the image */
|
||||
if (cinfo.saw_JFIF_marker)
|
||||
{
|
||||
gdouble xresolution;
|
||||
gdouble yresolution;
|
||||
gdouble asymmetry;
|
||||
|
||||
xresolution = cinfo.X_density;
|
||||
yresolution = cinfo.Y_density;
|
||||
|
||||
switch (cinfo.density_unit)
|
||||
{
|
||||
case 0: /* unknown -> set the aspect ratio but use the default
|
||||
* image resolution
|
||||
*/
|
||||
if (cinfo.Y_density != 0)
|
||||
asymmetry = xresolution / yresolution;
|
||||
else
|
||||
asymmetry = 1.0;
|
||||
|
||||
gimp_image_get_resolution (image_ID, &xresolution, &yresolution);
|
||||
xresolution *= asymmetry;
|
||||
break;
|
||||
|
||||
case 1: /* dots per inch */
|
||||
break;
|
||||
|
||||
case 2: /* dots per cm */
|
||||
xresolution *= 2.54;
|
||||
yresolution *= 2.54;
|
||||
gimp_image_set_unit (image_ID, GIMP_UNIT_MM);
|
||||
break;
|
||||
|
||||
default:
|
||||
g_message ("Unknown density unit %d\nassuming dots per inch",
|
||||
cinfo.density_unit);
|
||||
break;
|
||||
}
|
||||
|
||||
gimp_image_set_resolution (image_ID, xresolution, yresolution);
|
||||
}
|
||||
|
||||
/* 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);
|
||||
|
||||
if (cinfo.out_color_space == JCS_CMYK) /* buf-> RGB in padded_buf */
|
||||
{
|
||||
guchar *dest = padded_buf;
|
||||
guchar *src = buf;
|
||||
gint num = drawable->width * scanlines;
|
||||
|
||||
for (i = 0; i < num; i++)
|
||||
{
|
||||
guint r_c, g_m, b_y, a_k;
|
||||
|
||||
r_c = *(src++);
|
||||
g_m = *(src++);
|
||||
b_y = *(src++);
|
||||
a_k = *(src++);
|
||||
*(dest++) = (r_c * a_k) / 255;
|
||||
*(dest++) = (g_m * a_k) / 255;
|
||||
*(dest++) = (b_y * a_k) / 255;
|
||||
}
|
||||
}
|
||||
|
||||
gimp_pixel_rgn_set_rect (&pixel_rgn, padded_buf ? padded_buf : buf,
|
||||
0, start, drawable->width, scanlines);
|
||||
|
||||
gimp_progress_update ((gdouble) cinfo.output_scanline /
|
||||
(gdouble) cinfo.output_height);
|
||||
}
|
||||
|
||||
/* 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 */
|
||||
|
||||
/* This is an important step since it will release a good deal
|
||||
* of memory.
|
||||
*/
|
||||
jpeg_destroy_decompress (&cinfo);
|
||||
|
||||
/* free up the temporary buffers */
|
||||
g_free (rowbuf);
|
||||
g_free (buf);
|
||||
g_free (padded_buf);
|
||||
|
||||
/* At this point you may want to check to see whether any
|
||||
* corrupt-data warnings occurred (test whether
|
||||
* jerr.num_warnings is nonzero).
|
||||
*/
|
||||
gimp_image_add_layer (image_ID, layer_ID, 0);
|
||||
|
||||
|
||||
/* NOW to get the dimensions of the actual image to return the
|
||||
* calling app
|
||||
*/
|
||||
cinfo.err = jpeg_std_error (&jerr.pub);
|
||||
jerr.pub.error_exit = my_error_exit;
|
||||
|
||||
cinfo.client_data = GINT_TO_POINTER (FALSE);
|
||||
|
||||
jerr.pub.emit_message = my_emit_message;
|
||||
jerr.pub.output_message = my_output_message;
|
||||
|
||||
if ((infile = fopen (filename, "rb")) == NULL)
|
||||
{
|
||||
g_message (_("Could not open '%s' for reading: %s"),
|
||||
gimp_filename_to_utf8 (filename), g_strerror (errno));
|
||||
|
||||
if (exif_data)
|
||||
{
|
||||
exif_data_unref (exif_data);
|
||||
exif_data = NULL;
|
||||
}
|
||||
|
||||
return -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 (image_ID != -1)
|
||||
gimp_image_delete (image_ID);
|
||||
|
||||
if (exif_data)
|
||||
{
|
||||
exif_data_unref (exif_data);
|
||||
exif_data = NULL;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* 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);
|
||||
|
||||
/* Step 3: read file parameters with jpeg_read_header() */
|
||||
|
||||
jpeg_read_header (&cinfo, TRUE);
|
||||
|
||||
jpeg_start_decompress (&cinfo);
|
||||
|
||||
*width = cinfo.output_width;
|
||||
*height = cinfo.output_height;
|
||||
|
||||
/* Step 4: Release JPEG decompression object */
|
||||
|
||||
/* This is an important step since it will release a good deal
|
||||
* of memory.
|
||||
*/
|
||||
jpeg_destroy_decompress (&cinfo);
|
||||
|
||||
if (exif_data)
|
||||
{
|
||||
exif_data_unref (exif_data);
|
||||
exif_data = NULL;
|
||||
}
|
||||
|
||||
return image_ID;
|
||||
}
|
||||
|
||||
#endif /* HAVE_EXIF */
|
|
@ -0,0 +1,30 @@
|
|||
/* 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
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
gint32 load_image (const gchar *filename,
|
||||
GimpRunMode runmode,
|
||||
gboolean preview);
|
||||
|
||||
|
||||
#ifdef HAVE_EXIF
|
||||
|
||||
gint32 load_thumbnail_image (const gchar *filename,
|
||||
gint *width,
|
||||
gint *height);
|
||||
|
||||
#endif /* HAVE_EXIF */
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,74 @@
|
|||
/* 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
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#define SCALE_WIDTH 125
|
||||
|
||||
/* if you are not compiling this from inside the gimp tree, you have to */
|
||||
/* take care yourself if your JPEG library supports progressive mode */
|
||||
/* #undef HAVE_PROGRESSIVE_JPEG if your library doesn't support it */
|
||||
/* #define HAVE_PROGRESSIVE_JPEG if your library knows how to handle it */
|
||||
|
||||
/* See bugs #63610 and #61088 for a discussion about the quality settings */
|
||||
#define DEFAULT_QUALITY 85
|
||||
#define DEFAULT_SMOOTHING 0.0
|
||||
#define DEFAULT_OPTIMIZE TRUE
|
||||
#define DEFAULT_PROGRESSIVE FALSE
|
||||
#define DEFAULT_BASELINE TRUE
|
||||
#define DEFAULT_SUBSMP 0
|
||||
#define DEFAULT_RESTART 0
|
||||
#define DEFAULT_DCT 0
|
||||
#define DEFAULT_PREVIEW FALSE
|
||||
#define DEFAULT_EXIF TRUE
|
||||
#define DEFAULT_THUMBNAIL FALSE
|
||||
|
||||
typedef struct
|
||||
{
|
||||
gdouble quality;
|
||||
gdouble smoothing;
|
||||
gboolean optimize;
|
||||
gboolean progressive;
|
||||
gboolean baseline;
|
||||
gint subsmp;
|
||||
gint restart;
|
||||
gint dct;
|
||||
gboolean preview;
|
||||
gboolean save_exif;
|
||||
gboolean save_thumbnail;
|
||||
} JpegSaveVals;
|
||||
|
||||
JpegSaveVals jsvals;
|
||||
|
||||
gint32 orig_image_ID_global;
|
||||
gint32 drawable_ID_global;
|
||||
|
||||
gboolean save_image (const gchar *filename,
|
||||
gint32 image_ID,
|
||||
gint32 drawable_ID,
|
||||
gint32 orig_image_ID,
|
||||
gboolean preview);
|
||||
|
||||
gboolean save_dialog (void);
|
||||
|
||||
#ifdef HAVE_EXIF
|
||||
|
||||
gint create_thumbnail (gint32 image_ID,
|
||||
gint32 drawable_ID,
|
||||
gchar **thumbnail_buffer);
|
||||
|
||||
#endif /* HAVE_EXIF */
|
||||
|
|
@ -0,0 +1,553 @@
|
|||
/* 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
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include "jpeg.h"
|
||||
#include "jpeg-save.h"
|
||||
#include "jpeg-load.h"
|
||||
|
||||
|
||||
|
||||
/* Declare local functions.
|
||||
*/
|
||||
static void query (void);
|
||||
static void run (const gchar *name,
|
||||
gint nparams,
|
||||
const GimpParam *param,
|
||||
gint *nreturn_vals,
|
||||
GimpParam **return_vals);
|
||||
|
||||
GimpPlugInInfo PLUG_IN_INFO =
|
||||
{
|
||||
NULL, /* init_proc */
|
||||
NULL, /* quit_proc */
|
||||
query, /* query_proc */
|
||||
run, /* run_proc */
|
||||
};
|
||||
|
||||
|
||||
|
||||
MAIN ()
|
||||
|
||||
|
||||
static void
|
||||
query (void)
|
||||
{
|
||||
static GimpParamDef load_args[] =
|
||||
{
|
||||
{ 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" }
|
||||
};
|
||||
static GimpParamDef load_return_vals[] =
|
||||
{
|
||||
{ GIMP_PDB_IMAGE, "image", "Output image" }
|
||||
};
|
||||
|
||||
#ifdef HAVE_EXIF
|
||||
|
||||
static GimpParamDef thumb_args[] =
|
||||
{
|
||||
{ GIMP_PDB_STRING, "filename", "The name of the file to load" },
|
||||
{ GIMP_PDB_INT32, "thumb_size", "Preferred thumbnail size" }
|
||||
};
|
||||
static GimpParamDef thumb_return_vals[] =
|
||||
{
|
||||
{ GIMP_PDB_IMAGE, "image", "Thumbnail image" },
|
||||
{ GIMP_PDB_INT32, "image_width", "Width of full-sized image" },
|
||||
{ GIMP_PDB_INT32, "image_height", "Height of full-sized image" }
|
||||
};
|
||||
|
||||
#endif /* HAVE_EXIF */
|
||||
|
||||
static GimpParamDef save_args[] =
|
||||
{
|
||||
{ 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)" }
|
||||
};
|
||||
|
||||
gimp_install_procedure ("file_jpeg_load",
|
||||
"loads files in the JPEG file format",
|
||||
"loads files in the JPEG file format",
|
||||
"Spencer Kimball, Peter Mattis & others",
|
||||
"Spencer Kimball & Peter Mattis",
|
||||
"1995-1999",
|
||||
N_("JPEG image"),
|
||||
NULL,
|
||||
GIMP_PLUGIN,
|
||||
G_N_ELEMENTS (load_args),
|
||||
G_N_ELEMENTS (load_return_vals),
|
||||
load_args, load_return_vals);
|
||||
|
||||
gimp_register_file_handler_mime ("file_jpeg_load", "image/jpeg");
|
||||
gimp_register_magic_load_handler ("file_jpeg_load",
|
||||
"jpg,jpeg,jpe",
|
||||
"",
|
||||
"6,string,JFIF,6,string,Exif");
|
||||
|
||||
#ifdef HAVE_EXIF
|
||||
|
||||
gimp_install_procedure ("file_jpeg_load_thumb",
|
||||
"Loads a thumbnail from a JPEG image",
|
||||
"Loads a thumbnail from a JPEG image (only if it exists)",
|
||||
"S. Mukund <muks@mukund.org>, Sven Neumann <sven@gimp.org>",
|
||||
"S. Mukund <muks@mukund.org>, Sven Neumann <sven@gimp.org>",
|
||||
"November 15, 2004",
|
||||
NULL,
|
||||
NULL,
|
||||
GIMP_PLUGIN,
|
||||
G_N_ELEMENTS (thumb_args),
|
||||
G_N_ELEMENTS (thumb_return_vals),
|
||||
thumb_args, thumb_return_vals);
|
||||
|
||||
gimp_register_thumbnail_loader ("file_jpeg_load", "file_jpeg_load_thumb");
|
||||
|
||||
#endif /* HAVE_EXIF */
|
||||
|
||||
gimp_install_procedure ("file_jpeg_save",
|
||||
"saves files in the JPEG file format",
|
||||
"saves files in the lossy, widely supported JPEG format",
|
||||
"Spencer Kimball, Peter Mattis & others",
|
||||
"Spencer Kimball & Peter Mattis",
|
||||
"1995-1999",
|
||||
N_("JPEG image"),
|
||||
"RGB*, GRAY*",
|
||||
GIMP_PLUGIN,
|
||||
G_N_ELEMENTS (save_args), 0,
|
||||
save_args, NULL);
|
||||
|
||||
gimp_register_file_handler_mime ("file_jpeg_save", "image/jpeg");
|
||||
gimp_register_save_handler ("file_jpeg_save", "jpg,jpeg,jpe", "");
|
||||
}
|
||||
|
||||
static void
|
||||
run (const gchar *name,
|
||||
gint nparams,
|
||||
const GimpParam *param,
|
||||
gint *nreturn_vals,
|
||||
GimpParam **return_vals)
|
||||
{
|
||||
static GimpParam values[4];
|
||||
GimpRunMode run_mode;
|
||||
GimpPDBStatusType status = GIMP_PDB_SUCCESS;
|
||||
gint32 image_ID;
|
||||
gint32 drawable_ID;
|
||||
gint32 orig_image_ID;
|
||||
GimpParasite *parasite;
|
||||
gboolean err;
|
||||
GimpExportReturn export = GIMP_EXPORT_CANCEL;
|
||||
|
||||
run_mode = param[0].data.d_int32;
|
||||
|
||||
INIT_I18N ();
|
||||
|
||||
*nreturn_vals = 1;
|
||||
*return_vals = values;
|
||||
values[0].type = GIMP_PDB_STATUS;
|
||||
values[0].data.d_status = GIMP_PDB_EXECUTION_ERROR;
|
||||
|
||||
if (strcmp (name, "file_jpeg_load") == 0)
|
||||
{
|
||||
image_ID = load_image (param[1].data.d_string, run_mode, FALSE);
|
||||
|
||||
if (image_ID != -1)
|
||||
{
|
||||
*nreturn_vals = 2;
|
||||
values[1].type = GIMP_PDB_IMAGE;
|
||||
values[1].data.d_image = image_ID;
|
||||
}
|
||||
else
|
||||
{
|
||||
status = GIMP_PDB_EXECUTION_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef HAVE_EXIF
|
||||
|
||||
else if (strcmp (name, "file_jpeg_load_thumb") == 0)
|
||||
{
|
||||
if (nparams < 2)
|
||||
{
|
||||
status = GIMP_PDB_CALLING_ERROR;
|
||||
}
|
||||
else
|
||||
{
|
||||
const gchar *filename = param[0].data.d_string;
|
||||
gint width = 0;
|
||||
gint height = 0;
|
||||
gint32 image_ID;
|
||||
|
||||
image_ID = load_thumbnail_image (filename, &width, &height);
|
||||
|
||||
if (image_ID != -1)
|
||||
{
|
||||
*nreturn_vals = 4;
|
||||
values[1].type = GIMP_PDB_IMAGE;
|
||||
values[1].data.d_image = image_ID;
|
||||
values[2].type = GIMP_PDB_INT32;
|
||||
values[2].data.d_int32 = width;
|
||||
values[3].type = GIMP_PDB_INT32;
|
||||
values[3].data.d_int32 = height;
|
||||
}
|
||||
else
|
||||
{
|
||||
status = GIMP_PDB_EXECUTION_ERROR;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* HAVE_EXIF */
|
||||
|
||||
else if (strcmp (name, "file_jpeg_save") == 0)
|
||||
{
|
||||
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 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:
|
||||
{
|
||||
gchar *tmp = g_filename_from_utf8 (_("Export Preview"), -1,
|
||||
NULL, NULL, NULL);
|
||||
if (tmp)
|
||||
{
|
||||
gimp_image_set_filename (image_ID, tmp);
|
||||
g_free (tmp);
|
||||
}
|
||||
|
||||
display_ID = -1;
|
||||
}
|
||||
break;
|
||||
case GIMP_EXPORT_IGNORE:
|
||||
break;
|
||||
case GIMP_EXPORT_CANCEL:
|
||||
values[0].data.d_status = GIMP_PDB_CANCEL;
|
||||
return;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
#ifdef HAVE_EXIF
|
||||
exif_data_unref (exif_data);
|
||||
exif_data = NULL;
|
||||
#endif /* HAVE_EXIF */
|
||||
|
||||
g_free (image_comment);
|
||||
image_comment = NULL;
|
||||
|
||||
parasite = gimp_image_parasite_find (orig_image_ID, "gimp-comment");
|
||||
if (parasite)
|
||||
{
|
||||
image_comment = g_strndup (gimp_parasite_data (parasite),
|
||||
gimp_parasite_data_size (parasite));
|
||||
gimp_parasite_free (parasite);
|
||||
}
|
||||
|
||||
#ifdef HAVE_EXIF
|
||||
|
||||
parasite = gimp_image_parasite_find (orig_image_ID, "exif-data");
|
||||
if (parasite)
|
||||
{
|
||||
exif_data = exif_data_new_from_data (gimp_parasite_data (parasite),
|
||||
gimp_parasite_data_size (parasite));
|
||||
gimp_parasite_free (parasite);
|
||||
}
|
||||
|
||||
#endif /* HAVE_EXIF */
|
||||
|
||||
jsvals.quality = DEFAULT_QUALITY;
|
||||
jsvals.smoothing = DEFAULT_SMOOTHING;
|
||||
jsvals.optimize = DEFAULT_OPTIMIZE;
|
||||
jsvals.progressive = DEFAULT_PROGRESSIVE;
|
||||
jsvals.baseline = DEFAULT_BASELINE;
|
||||
jsvals.subsmp = DEFAULT_SUBSMP;
|
||||
jsvals.restart = DEFAULT_RESTART;
|
||||
jsvals.dct = DEFAULT_DCT;
|
||||
jsvals.preview = DEFAULT_PREVIEW;
|
||||
jsvals.save_exif = DEFAULT_EXIF;
|
||||
jsvals.save_thumbnail = DEFAULT_THUMBNAIL;
|
||||
|
||||
#ifdef HAVE_EXIF
|
||||
|
||||
if (exif_data && (exif_data->data))
|
||||
jsvals.save_thumbnail = TRUE;
|
||||
|
||||
#endif /* HAVE_EXIF */
|
||||
|
||||
switch (run_mode)
|
||||
{
|
||||
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)
|
||||
{
|
||||
const JpegSaveVals *save_vals = gimp_parasite_data (parasite);
|
||||
|
||||
jsvals.quality = save_vals->quality;
|
||||
jsvals.smoothing = save_vals->smoothing;
|
||||
jsvals.optimize = save_vals->optimize;
|
||||
jsvals.progressive = save_vals->progressive;
|
||||
jsvals.baseline = save_vals->baseline;
|
||||
jsvals.subsmp = save_vals->subsmp;
|
||||
jsvals.restart = save_vals->restart;
|
||||
jsvals.dct = save_vals->dct;
|
||||
jsvals.preview = save_vals->preview;
|
||||
jsvals.save_exif = save_vals->save_exif;
|
||||
jsvals.save_thumbnail = save_vals->save_thumbnail;
|
||||
|
||||
gimp_parasite_free (parasite);
|
||||
}
|
||||
|
||||
if (jsvals.preview)
|
||||
{
|
||||
/* we freeze undo saving so that we can avoid sucking up
|
||||
* tile cache with our unneeded preview steps. */
|
||||
gimp_image_undo_freeze (image_ID);
|
||||
|
||||
undo_touched = TRUE;
|
||||
}
|
||||
|
||||
/* prepare for the preview */
|
||||
image_ID_global = image_ID;
|
||||
orig_image_ID_global = orig_image_ID;
|
||||
drawable_ID_global = drawable_ID;
|
||||
|
||||
/* First acquire information with a dialog */
|
||||
err = save_dialog ();
|
||||
|
||||
if (undo_touched)
|
||||
{
|
||||
/* thaw undo saving and flush the displays to have them
|
||||
* reflect the current shortcuts */
|
||||
gimp_image_undo_thaw (image_ID);
|
||||
gimp_displays_flush ();
|
||||
}
|
||||
|
||||
if (!err)
|
||||
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;
|
||||
#ifdef HAVE_PROGRESSIVE_JPEG
|
||||
jsvals.progressive = param[8].data.d_int32;
|
||||
#endif /* HAVE_PROGRESSIVE_JPEG */
|
||||
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)
|
||||
{
|
||||
const JpegSaveVals *save_vals = gimp_parasite_data (parasite);
|
||||
|
||||
jsvals.quality = save_vals->quality;
|
||||
jsvals.smoothing = save_vals->smoothing;
|
||||
jsvals.optimize = save_vals->optimize;
|
||||
jsvals.progressive = save_vals->progressive;
|
||||
jsvals.baseline = save_vals->baseline;
|
||||
jsvals.subsmp = save_vals->subsmp;
|
||||
jsvals.restart = save_vals->restart;
|
||||
jsvals.dct = save_vals->dct;
|
||||
jsvals.preview = FALSE;
|
||||
|
||||
gimp_parasite_free (parasite);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (status == GIMP_PDB_SUCCESS)
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
if (export == GIMP_EXPORT_EXPORT)
|
||||
{
|
||||
/* If the image was exported, delete the new display. */
|
||||
/* This also deletes the image. */
|
||||
|
||||
if (display_ID != -1)
|
||||
gimp_display_delete (display_ID);
|
||||
else
|
||||
gimp_image_delete (image_ID);
|
||||
}
|
||||
|
||||
/* 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. */
|
||||
|
||||
gimp_image_parasite_detach (orig_image_ID, "gimp-comment");
|
||||
if (image_comment && strlen (image_comment))
|
||||
{
|
||||
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);
|
||||
}
|
||||
gimp_image_parasite_detach (orig_image_ID, "jpeg-save-options");
|
||||
|
||||
parasite = gimp_parasite_new ("jpeg-save-options",
|
||||
0, sizeof (jsvals), &jsvals);
|
||||
gimp_image_parasite_attach (orig_image_ID, parasite);
|
||||
gimp_parasite_free (parasite);
|
||||
}
|
||||
else
|
||||
{
|
||||
status = GIMP_PDB_CALLING_ERROR;
|
||||
}
|
||||
|
||||
values[0].data.d_status = status;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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_emit_message (j_common_ptr cinfo,
|
||||
int msg_level)
|
||||
{
|
||||
if (msg_level == -1)
|
||||
{
|
||||
/* disable loading of EXIF data */
|
||||
cinfo->client_data = GINT_TO_POINTER (TRUE);
|
||||
|
||||
(*cinfo->err->output_message) (cinfo);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,76 @@
|
|||
#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.
|
||||
*/
|
||||
#include <errno.h>
|
||||
#include <setjmp.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include <jpeglib.h>
|
||||
#include <jerror.h>
|
||||
|
||||
#ifdef HAVE_EXIF
|
||||
#include <libexif/exif-data.h>
|
||||
#endif /* HAVE_EXIF */
|
||||
|
||||
#include <libgimp/gimp.h>
|
||||
#include <libgimp/gimpui.h>
|
||||
|
||||
#include "libgimp/stdplugins-intl.h"
|
||||
|
||||
typedef struct my_error_mgr
|
||||
{
|
||||
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.
|
||||
*/
|
||||
long double dummy;
|
||||
#endif
|
||||
|
||||
jmp_buf setjmp_buffer; /* for return to caller */
|
||||
} *my_error_ptr;
|
||||
|
||||
|
||||
gint32 volatile image_ID_global;
|
||||
gint32 layer_ID_global;
|
||||
GimpDrawable *drawable_global;
|
||||
gboolean undo_touched;
|
||||
gint32 display_ID;
|
||||
gchar *image_comment;
|
||||
|
||||
#ifdef HAVE_EXIF
|
||||
ExifData *exif_data;
|
||||
#endif /* HAVE_EXIF */
|
||||
|
||||
|
||||
|
||||
|
||||
gint32 load_image (const gchar *filename,
|
||||
GimpRunMode runmode,
|
||||
gboolean preview);
|
||||
|
||||
void destroy_preview (void);
|
||||
|
||||
#ifdef HAVE_EXIF
|
||||
|
||||
gint32 load_thumbnail_image(const gchar *filename,
|
||||
gint *width,
|
||||
gint *height);
|
||||
|
||||
#endif /* HAVE_EXIF */
|
||||
|
||||
void my_error_exit (j_common_ptr cinfo);
|
||||
void my_emit_message (j_common_ptr cinfo,
|
||||
int msg_level);
|
||||
void my_output_message (j_common_ptr cinfo);
|
Loading…
Reference in New Issue