+/*
+ * Geeqie
+ * (C) 2004 John Ellis
+ * Copyright (C) 2008 - 2011 The Geeqie Team
+ *
+ * Author: Vladimir Nadvornik
+ *
+ * This software is released under the GNU General Public License (GNU GPL).
+ * Please read the included file COPYING for more information.
+ * This software comes with no warranty of any kind, use at your own risk!
+ */
+
+/* based on code from GdkPixbuf library - JPEG image loader
+ *
+ * Copyright (C) 1999 Michael Zucchi
+ * Copyright (C) 1999 The Free Software Foundation
+ *
+ * Progressive loading code Copyright (C) 1999 Red Hat, Inc.
+ *
+ * Authors: Michael Zucchi <zucchi@zedzone.mmc.com.au>
+ * Federico Mena-Quintero <federico@gimp.org>
+ * Michael Fulbright <drmike@redhat.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
#include "main.h"
+
#include "image-load.h"
#include "image_load_jpeg.h"
#include "jpeg_parser.h"
+#ifdef HAVE_JPEG
+
#include <setjmp.h>
#include <jpeglib.h>
#include <jerror.h>
guint requested_height;
gboolean abort;
+ gboolean stereo;
};
}
}
+
+static void init_source (j_decompress_ptr cinfo) {}
+static boolean fill_input_buffer (j_decompress_ptr cinfo)
+{
+ ERREXIT(cinfo, JERR_INPUT_EMPTY);
+ return TRUE;
+}
+static void skip_input_data (j_decompress_ptr cinfo, long num_bytes)
+{
+ struct jpeg_source_mgr* src = (struct jpeg_source_mgr*) cinfo->src;
+
+ if (num_bytes > src->bytes_in_buffer)
+ {
+ ERREXIT(cinfo, JERR_INPUT_EOF);
+ }
+ else if (num_bytes > 0)
+ {
+ src->next_input_byte += (size_t) num_bytes;
+ src->bytes_in_buffer -= (size_t) num_bytes;
+ }
+}
+static void term_source (j_decompress_ptr cinfo) {}
+static void set_mem_src (j_decompress_ptr cinfo, void* buffer, long nbytes)
+{
+ struct jpeg_source_mgr* src;
+
+ if (cinfo->src == NULL)
+ { /* first time for this JPEG object? */
+ cinfo->src = (struct jpeg_source_mgr *) (*cinfo->mem->alloc_small) (
+ (j_common_ptr) cinfo, JPOOL_PERMANENT,
+ sizeof(struct jpeg_source_mgr));
+ }
+
+ src = (struct jpeg_source_mgr*) cinfo->src;
+ src->init_source = init_source;
+ src->fill_input_buffer = fill_input_buffer;
+ src->skip_input_data = skip_input_data;
+ src->resync_to_restart = jpeg_resync_to_restart; /* use default method */
+ src->term_source = term_source;
+ src->bytes_in_buffer = nbytes;
+ src->next_input_byte = (JOCTET*)buffer;
+}
+
+
static gboolean image_loader_jpeg_load (gpointer loader, const guchar *buf, gsize count, GError **error)
{
ImageLoaderJpeg *lj = (ImageLoaderJpeg *) loader;
struct jpeg_decompress_struct cinfo2;
guchar *dptr, *dptr2;
guint rowstride;
+ guchar *stereo_buf2 = NULL;
+ guint stereo_length = 0;
struct error_handler_data jerr;
-// stdio_src_ptr src;
+
+ lj->stereo = FALSE;
+
MPOData *mpo = jpeg_get_mpo_data(buf, count);
- gboolean stereo = (mpo && mpo->num_images > 1);
+ if (mpo && mpo->num_images > 1)
+ {
+ guint i;
+ gint idx1 = -1, idx2 = -1;
+ guint num2 = 1;
+
+ for (i = 0; i < mpo->num_images; i++)
+ {
+ if (mpo->images[i].type_code == 0x20002)
+ {
+ if (mpo->images[i].MPIndividualNum == 1)
+ {
+ idx1 = i;
+ }
+ else if (mpo->images[i].MPIndividualNum > num2)
+ {
+ idx2 = i;
+ num2 = mpo->images[i].MPIndividualNum;
+ }
+ }
+ }
+
+ if (idx1 >= 0 && idx2 >= 0)
+ {
+ lj->stereo = TRUE;
+ stereo_buf2 = (unsigned char *)buf + mpo->images[idx2].offset;
+ stereo_length = mpo->images[idx2].length;
+ buf = (unsigned char *)buf + mpo->images[idx1].offset;
+ count = mpo->images[idx1].length;
+ }
+ }
+ jpeg_mpo_data_free(mpo);
/* setup error handler */
cinfo.err = jpeg_std_error (&jerr.pub);
- if (stereo) cinfo2.err = jpeg_std_error (&jerr.pub);
+ if (lj->stereo) cinfo2.err = jpeg_std_error (&jerr.pub);
jerr.pub.error_exit = fatal_error_handler;
jerr.pub.output_message = output_message_handler;
* We need to clean up the JPEG object, close the input file, and return.
*/
jpeg_destroy_decompress(&cinfo);
- if (stereo) jpeg_destroy_decompress(&cinfo2);
+ if (lj->stereo) jpeg_destroy_decompress(&cinfo2);
return FALSE;
}
jpeg_create_decompress(&cinfo);
- jpeg_mem_src(&cinfo, (unsigned char *)buf, count);
+ set_mem_src(&cinfo, (unsigned char *)buf, count);
jpeg_read_header(&cinfo, TRUE);
- if (stereo)
+ if (lj->stereo)
{
- printf("decoding stereo");
jpeg_create_decompress(&cinfo2);
- jpeg_mem_src(&cinfo2, (unsigned char *)buf + mpo->images[1].offset, mpo->images[1].length);
+ set_mem_src(&cinfo2, stereo_buf2, stereo_length);
jpeg_read_header(&cinfo2, TRUE);
if (cinfo.image_width != cinfo2.image_width ||
{
DEBUG_1("stereo data with different size");
jpeg_destroy_decompress(&cinfo2);
- stereo = FALSE;
+ lj->stereo = FALSE;
}
}
- lj->requested_width = stereo ? cinfo.image_width * 2: cinfo.image_width;
+ lj->requested_width = lj->stereo ? cinfo.image_width * 2: cinfo.image_width;
lj->requested_height = cinfo.image_height;
lj->size_cb(loader, lj->requested_width, lj->requested_height, lj->data);
cinfo.scale_num = 1;
for (cinfo.scale_denom = 2; cinfo.scale_denom <= 8; cinfo.scale_denom *= 2) {
jpeg_calc_output_dimensions(&cinfo);
- if (cinfo.output_width < (stereo ? lj->requested_width / 2 : lj->requested_width) || cinfo.output_height < lj->requested_height) {
+ if (cinfo.output_width < (lj->stereo ? lj->requested_width / 2 : lj->requested_width) || cinfo.output_height < lj->requested_height) {
cinfo.scale_denom /= 2;
break;
}
}
jpeg_calc_output_dimensions(&cinfo);
- if (stereo)
+ if (lj->stereo)
{
cinfo2.scale_num = cinfo.scale_num;
cinfo2.scale_denom = cinfo.scale_denom;
jpeg_start_decompress(&cinfo);
- if (stereo)
+ if (lj->stereo)
{
if (cinfo.output_width != cinfo2.output_width ||
cinfo.output_height != cinfo2.output_height ||
{
DEBUG_1("stereo data with different output size");
jpeg_destroy_decompress(&cinfo2);
- stereo = FALSE;
+ lj->stereo = FALSE;
}
}
lj->pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB,
cinfo.out_color_components == 4 ? TRUE : FALSE,
- 8, stereo ? cinfo.output_width * 2: cinfo.output_width, cinfo.output_height);
+ 8, lj->stereo ? cinfo.output_width * 2: cinfo.output_width, cinfo.output_height);
if (!lj->pixbuf)
{
jpeg_destroy_decompress (&cinfo);
- if (stereo) jpeg_destroy_decompress (&cinfo2);
+ if (lj->stereo) jpeg_destroy_decompress (&cinfo2);
return 0;
}
- if (stereo) g_object_set_data(G_OBJECT(lj->pixbuf), "stereo_data", GINT_TO_POINTER(STEREO_PIXBUF_CROSS));
+ if (lj->stereo) g_object_set_data(G_OBJECT(lj->pixbuf), "stereo_data", GINT_TO_POINTER(STEREO_PIXBUF_CROSS));
lj->area_prepared_cb(loader, lj->data);
rowstride = gdk_pixbuf_get_rowstride(lj->pixbuf);
guint scanline = cinfo.output_scanline;
image_loader_jpeg_read_scanline(&cinfo, &dptr, rowstride);
lj->area_updated_cb(loader, 0, scanline, cinfo.output_width, cinfo.rec_outbuf_height, lj->data);
- if (stereo)
+ if (lj->stereo)
{
guint scanline = cinfo2.output_scanline;
image_loader_jpeg_read_scanline(&cinfo2, &dptr2, rowstride);
jpeg_finish_decompress(&cinfo);
jpeg_destroy_decompress(&cinfo);
- if (stereo)
+ if (lj->stereo)
{
jpeg_finish_decompress(&cinfo);
jpeg_destroy_decompress(&cinfo);
+#endif
+
+
+/* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */