Index: configure.in
===================================================================
--- configure.in	(revision 18683)
+++ configure.in	(working copy)
@@ -757,6 +757,9 @@
 AC_ARG_WITH(libtiff,
             [AC_HELP_STRING([--without-libtiff],
                             [disable TIFF loader for gdk-pixbuf])])
+AC_ARG_WITH(libjasper,
+            [AC_HELP_STRING([--without-libjasper],
+                            [disable JPEG2000 loader for gdk-pixbuf])])
 
 dnl Test for libtiff
   if test x$with_libtiff != xno && test -z "$LIBTIFF"; then
@@ -858,9 +861,21 @@
 *** from CVS.])
   fi
 
+dnl Test for libjasper
+  if test x$with_libjasper != xno && test -z "$LIBJASPER"; then
+    AC_CHECK_LIB(jasper, jas_init, LIBJASPER=-ljasper, [])
+  fi
+
+  if test x$with_libjasper != xno && test -z "$LIBJASPER"; then
+     AC_MSG_ERROR([
+*** Checks for JPEG2000 loader failed. You can build without it by passing 
+*** --without-libjasper to configure])
+  fi
+
 AC_SUBST(LIBTIFF)
 AC_SUBST(LIBJPEG)
 AC_SUBST(LIBPNG)
+AC_SUBST(LIBJASPER)
 
 AM_CONDITIONAL(BUILD_DYNAMIC_MODULES, $dynworks)
 
@@ -930,6 +945,7 @@
 AM_CONDITIONAL(INCLUDE_XBM, [test x"$INCLUDE_xbm" = xyes])
 AM_CONDITIONAL(INCLUDE_TGA, [test x"$INCLUDE_tga" = xyes])
 AM_CONDITIONAL(INCLUDE_PCX, [test x"$INCLUDE_pcx" = xyes])
+AM_CONDITIONAL(INCLUDE_JASPER, [test x"$INCLUDE_jasper" = xyes])
 
 AC_HEADER_SYS_WAIT
 
@@ -938,6 +954,7 @@
 AM_CONDITIONAL(HAVE_TIFF, test "x$LIBTIFF" != x)
 AM_CONDITIONAL(HAVE_PNG, test "x$LIBPNG" != x)
 AM_CONDITIONAL(HAVE_JPEG, test "x$LIBJPEG" != x)
+AM_CONDITIONAL(HAVE_JASPER, test "x$LIBJASPER" != x)
 
 if $dynworks ; then
   STATIC_LIB_DEPS=
@@ -1364,6 +1381,9 @@
     GDK_EXTRA_LIBS="$X_LIBS $x_extra_libs -lXext -lX11 $GDK_EXTRA_LIBS"
   fi
 
+  # Checks for X11/Sunkeysym.h
+  AC_CHECK_HEADERS([X11/Sunkeysym.h])
+
   CPPFLAGS="$gtk_save_cppflags"
   LIBS="$gtk_save_libs"
 
Index: gdk-pixbuf/Makefile.am
===================================================================
--- gdk-pixbuf/Makefile.am	(revision 18683)
+++ gdk-pixbuf/Makefile.am	(working copy)
@@ -172,6 +172,14 @@
 libpixbufloader_pcx_la_LDFLAGS = -avoid-version -module $(no_undefined)
 libpixbufloader_pcx_la_LIBADD = $(module_libs)
 
+#
+# The JPEG2000 loader
+#
+libstatic_pixbufloader_jasper_la_SOURCES = io-jasper.c
+libpixbufloader_jasper_la_SOURCES = io-jasper.c
+libpixbufloader_jasper_la_LDFLAGS = -avoid-version -module $(no_undefined)
+libpixbufloader_jasper_la_LIBADD = $(LIBJASPER) $(module_libs)
+
 if HAVE_PNG
 if INCLUDE_PNG
 STATIC_PNG_LIB = libstatic-pixbufloader-png.la
@@ -262,6 +270,14 @@
 PCX_LIB = libpixbufloader-pcx.la
 endif
 
+if HAVE_JASPER
+if INCLUDE_JASPER
+STATIC_JASPER_LIB = libstatic-pixbufloader-jasper.la
+else
+JASPER_LIB = libpixbufloader-jasper.la
+endif
+endif
+
 if BUILD_DYNAMIC_MODULES
 
 loader_LTLIBRARIES = 	\
@@ -278,7 +294,8 @@
 	$(XPM_LIB)	\
 	$(XBM_LIB)	\
 	$(TGA_LIB)	\
-	$(PCX_LIB)
+	$(PCX_LIB)	\
+	$(JASPER_LIB)
 
 
 endif
@@ -297,7 +314,8 @@
 	$(STATIC_XPM_LIB)	\
 	$(STATIC_XBM_LIB)	\
 	$(STATIC_TGA_LIB)	\
-	$(STATIC_PCX_LIB)
+	$(STATIC_PCX_LIB)	\
+	$(STATIC_JASPER_LIB)
 
 builtin_objs = @INCLUDED_LOADER_OBJ@
 
Index: gdk-pixbuf/io-jasper.c
===================================================================
--- gdk-pixbuf/io-jasper.c	(revision 0)
+++ gdk-pixbuf/io-jasper.c	(revision 0)
@@ -0,0 +1,330 @@
+/* JPEG 2000 loader
+ *
+ * Copyright (c) 2007 Bastien Nocera <hadess@hadess.net>
+ *
+ * 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 <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include "gdk-pixbuf-private.h"
+#include "gdk-pixbuf-io.h"
+
+#include <jasper/jasper.h>
+
+G_MODULE_EXPORT void fill_vtable (GdkPixbufModule * module);
+G_MODULE_EXPORT void fill_info (GdkPixbufFormat * info);
+
+enum {
+	JASPER_TASK_START,
+	JASPER_TASK_HEADERS,
+	JASPER_TASK_DONE,
+	JASPER_TASK_ERROR
+};
+
+struct jasper_context {
+	GdkPixbuf *pixbuf;
+
+	GdkPixbufModuleSizeFunc size_func;
+	GdkPixbufModuleUpdatedFunc updated_func;
+	GdkPixbufModulePreparedFunc prepared_func;
+	gpointer user_data;
+
+	jas_stream_t *stream;
+	jas_image_t *image;
+	jas_image_t *raw_image;
+
+	int state, width, height;
+};
+
+static void
+free_jasper_images (struct jasper_context *context)
+{
+	if (context->raw_image && context->raw_image != context->image) {
+		jas_image_destroy (context->raw_image);
+	}
+	context->raw_image = NULL;
+	if (context->image) {
+		jas_image_destroy (context->image);
+		context->image = NULL;
+	}
+}
+
+static void
+free_jasper_context (struct jasper_context *context)
+{
+	if (!context)
+		return;
+
+	free_jasper_images (context);
+
+	if (context->stream) {
+		jas_stream_close (context->stream);
+		context->stream = NULL;
+	}
+
+	//FIXME unref pixbuf?
+
+	g_free (context);
+}
+
+static gpointer
+jasper_image_begin_load (GdkPixbufModuleSizeFunc size_func,
+			 GdkPixbufModulePreparedFunc prepared_func,
+			 GdkPixbufModuleUpdatedFunc updated_func,
+			 gpointer user_data, GError **error)
+{
+  struct jasper_context *context;
+
+  jas_init ();
+
+  context = g_new0(struct jasper_context, 1);
+  if (!context) {
+  	  g_message ("no context");
+  	  return NULL;
+  }
+
+  context->size_func = size_func;
+  context->updated_func = updated_func;
+  context->prepared_func = prepared_func;
+  context->user_data = user_data;
+  context->width = context->height = -1;
+
+  context->stream = jas_stream_memopen (NULL, -1);
+   /* It's not clear to me whether the following represents a JasPer Library
+    * "bug" but it sure looks goofy:  Unless a stream buffer is marked
+    * "read only", which only happens when the stream's "fillbuf" method is
+    * called, even though our buffers are always "read only", the library
+    * will try to flush out buffer contents when the stream is destroyed,
+    * which makes it die a horrible death.  So, mark the stream buffer
+    * proactively: */
+//  context->stream->bufmode_ |= JAS_STREAM_RDBUF;
+  //FIXME check ret
+
+  context->state = JASPER_TASK_START;
+
+  return context;
+}
+
+static gboolean
+jasper_image_try_load (struct jasper_context *context, gboolean do_error, GError **error)
+{
+	int fmtid;
+	long position;
+
+	position = jas_stream_tell (context->stream);
+	if (position == 0) {
+		//FIXME
+		return FALSE;
+	}
+
+	jas_stream_rewind (context->stream);
+
+	fmtid = jas_image_getfmt (context->stream);
+	if (fmtid < 0) {
+		//FIXME
+		goto bail;
+	}
+
+	//free_jasper_images (context);
+
+	context->raw_image = jas_image_decode (context->stream, fmtid, 0);
+	if (!context->raw_image) {
+		//FIXME
+		goto bail;
+	}
+
+	if (context->width == -1 && context->height == -1) {
+		context->width = jas_image_cmptwidth(context->raw_image, 0);
+		context->height = jas_image_cmptheight(context->raw_image, 0);
+
+		if (context->size_func) {
+			(*context->size_func) (&context->width, &context->height, context->user_data);
+		}
+	}
+
+#if 1
+	int nc = jas_image_numcmpts(context->raw_image);
+	int depth = jas_image_cmptprec(context->raw_image, 0);
+	g_message ("\n\nJAS:: nc %d, w/h %d/%d, depth %d, size: %ld", nc, context->width, context->height, depth, (long) jas_image_rawsize(context->raw_image));
+	g_message("\ncolor model: %d",jas_image_clrspc(context->raw_image));
+	if (nc == 3) {
+		g_message("\ncomponent types: %d %d %d",
+		       jas_image_cmpttype(context->raw_image, 0),jas_image_cmpttype(context->raw_image, 1),jas_image_cmpttype(context->raw_image, 2));
+	}
+	int colourspace = jas_image_clrspc(context->raw_image);
+	int cs_family = jas_clrspc_fam (colourspace);
+#endif
+
+	/* We only know how to handle grayscale and RGB images */
+	if ((nc != 3 && nc != 1) || (cs_family != JAS_CLRSPC_FAM_RGB  && cs_family != JAS_CLRSPC_FAM_GRAY)) {
+		//FIXME set error
+		goto bail;
+	}
+
+	/* Convert all handled types to SRGB */
+	if (colourspace != JAS_CLRSPC_SRGB) {
+		jas_cmprof_t *outprof;
+		if (!(outprof = jas_cmprof_createfromclrspc(JAS_CLRSPC_SRGB)))
+			goto bail;
+
+		if (!(context->image = jas_image_chclrspc(context->raw_image, outprof, JAS_CMXFORM_INTENT_PER)))
+			goto bail;
+
+		if (colourspace == JAS_CLRSPC_GENRGB) {
+			g_message("\ngeneric rgb");
+			//  jas_image_setclrspc(mJASImage, JAS_CLRSPC_SRGB);
+		}
+	}
+
+	if (context->image) {
+		g_message("\thave alt image");
+	} else {
+		g_message("\tno alt image");
+		context->image = context->raw_image;
+	}
+
+	if (!context->pixbuf) {
+		context->pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB,
+						  FALSE, 8, context->width, context->height);
+		if (context->prepared_func)
+			context->prepared_func (context->pixbuf, NULL, context->user_data);
+	}
+	int rowstride = gdk_pixbuf_get_rowstride (context->pixbuf);
+	guchar *pixels = gdk_pixbuf_get_pixels (context->pixbuf);
+
+	/* Loop over the 3 colourspaces
+	 * Some implementations prefer using jas_matrix_create instead */
+	int i;
+	for (i = 0; i < 3; i++) {
+		jas_matrix_t *matrix;
+		matrix = jas_matrix_create (context->width, context->height);
+		jas_image_readcmpt (context->image, JAS_IMAGE_CT_RGB_R, 0, 0, context->width, context->height, matrix);
+		//FIXME file matrix
+		int j;
+
+		for (j = 0; j < context->height; j++) {
+			int k;
+
+			for (k = 0; k < context->width; k++) {
+				pixels[j * rowstride + k * 4 + i] = jas_matrix_get (matrix, k, j);
+			}
+			/* Update once per line */
+			if (context->updated_func && k != 0) {
+				g_message ("updated line %d (up to %d)", j, k);
+				context->updated_func(context->pixbuf, 0, j, k, 1, context->user_data);
+			}
+			/* If we finished prematurely */
+			if (k != context->width)
+				break;
+		}
+
+		jas_matrix_destroy(matrix);
+	}
+
+	/* Reset the stream */
+	jas_stream_seek (context->stream, position, 0);
+
+	if (context->updated_func) {
+		context->updated_func(context->pixbuf, 0, 0, context->width, context->height, context->user_data);
+	}
+
+	return TRUE;
+
+bail:
+	/* Reset the stream */
+	jas_stream_seek (context->stream, position, 0);
+
+	return FALSE;
+}
+
+static gboolean
+jasper_image_stop_load (gpointer data, GError **error)
+{
+	struct jasper_context *context = (struct jasper_context *)data;
+
+	g_message ("jasper_image_stop_load");
+
+	jas_stream_flush(context->stream);
+
+	if (jasper_image_try_load (context, FALSE, NULL)) {
+		free_jasper_context (context);
+	}
+
+	return TRUE;
+}
+
+static gboolean
+jasper_image_load_increment (gpointer data, const guchar *buf, guint size, GError **error)
+{
+	struct jasper_context *context = (struct jasper_context *) data;
+
+	g_message ("writing %d", size);
+
+	g_message ("pos: %ld", jas_stream_tell (context->stream));
+	//FIXME
+	context->stream->bufmode_ |= JAS_STREAM_WRBUF;
+	jas_stream_write(context->stream, buf, size);
+
+	jas_stream_flush(context->stream);
+
+	//FIXME check retvals
+#if 0
+	if (jasper_image_try_load (context, FALSE, NULL)) {
+		//FIXME call something here
+	}
+#endif
+	return TRUE;
+}
+
+void
+fill_vtable (GdkPixbufModule * module)
+{
+  module->begin_load = jasper_image_begin_load;
+  module->stop_load = jasper_image_stop_load;
+  module->load_increment = jasper_image_load_increment;
+}
+
+void
+fill_info (GdkPixbufFormat * info)
+{
+  static GdkPixbufModulePattern signature[] = {
+    { "    jP", "!!!!  ", 100 },		/* file begins with 'jP' at offset 4 */
+    { "\xff\x4f\xff\x51\x00", "   z", 100 },	/* file starts with FF 4F FF 51 00 */
+    { NULL, NULL, 0 }
+  };
+  static gchar *mime_types[] = {
+    "image/jpeg2000",
+    NULL
+  };
+  static gchar *extensions[] = {
+    "jpc",
+    "jp2",
+    NULL
+  };
+
+  info->name = "jpeg2000";
+  info->signature = signature;
+  info->description = N_("The JPEG 2000 image format");
+  info->mime_types = mime_types;
+  info->extensions = extensions;
+  info->flags = GDK_PIXBUF_FORMAT_THREADSAFE;
+  info->license = "LGPL";
+  info->disabled = FALSE;
+}
+
