[gegl] jp2-load: Add support for loading JPEG-2000 images



commit d351c5fba3cc0796fb78e056af8eb7abb1e4b270
Author: Mukund Sivaraman <muks banu com>
Date:   Tue Jun 22 23:41:28 2010 +0530

    jp2-load: Add support for loading JPEG-2000 images
    
    This loader uses the Jasper library.

 configure.ac                             |   21 ++
 operations/workshop/external/Makefile.am |    7 +
 operations/workshop/external/jp2-load.c  |  378 ++++++++++++++++++++++++++++++
 3 files changed, 406 insertions(+), 0 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index 4c1fe36..e874f14 100644
--- a/configure.ac
+++ b/configure.ac
@@ -49,6 +49,7 @@ m4_define([librsvg_required_version], [2.14.0])
 m4_define([openexr_required_version], [0.0.0])
 m4_define([sdl_required_version], [0.0.0])
 m4_define([openraw_required_version], [0.0.5])
+m4_define([jasper_required_version], [1.900.1])
 m4_define([graphviz_required_version], [0.0.0])
 
 AC_INIT(gegl, gegl_major_version.gegl_minor_version.gegl_micro_version)
@@ -816,6 +817,25 @@ AC_SUBST(OPENRAW_CFLAGS)
 AC_SUBST(OPENRAW_LIBS) 
 
 
+##################
+# Check for Jasper
+##################
+
+AC_ARG_WITH(jasper, [  --without-jasper    build without Jasper support])
+
+have_jasper="no"
+if test "x$with_jasper" != "xno"; then
+  PKG_CHECK_MODULES(JASPER, jasper >= jasper_required_version,
+    have_jasper="yes",
+    have_jasper="no  (jasper library not found)")
+fi
+
+AM_CONDITIONAL(HAVE_JASPER, test "$have_jasper" = "yes")
+
+AC_SUBST(JASPER_CFLAGS)
+AC_SUBST(JASPER_LIBS)
+
+
 ####################
 # Check for graphviz
 ####################
@@ -1039,6 +1059,7 @@ Optional dependencies:
   rsvg:            $have_librsvg
   SDL:             $have_sdl
   openraw:         $have_libopenraw
+  Jasper:          $have_jasper
   graphviz:        $have_graphviz
   avformat:        $have_libavformat
   V4L:             $have_v4l
diff --git a/operations/workshop/external/Makefile.am b/operations/workshop/external/Makefile.am
index 6496ab5..d9a1713 100644
--- a/operations/workshop/external/Makefile.am
+++ b/operations/workshop/external/Makefile.am
@@ -32,5 +32,12 @@ gluas_la_LIBADD  = $(op_libs) $(LUA_LIBS)
 gluas_la_CFLAGS  = $(LUA_CFLAGS) $(BABL_CFLAGS) $(GLIB_CFLAGS)
 endif
 
+if HAVE_JASPER
+ops += jp2-load.la
+jp2_load_la_SOURCES = jp2-load.c
+jp2_load_la_LIBADD  = $(op_libs) $(JASPER_LIBS)
+jp2_load_la_CFLAGS  = $(AM_CFLAGS) $(JASPER_CFLAGS)
+endif
+
 opdir = $(libdir)/gegl- GEGL_API_VERSION@
 op_LTLIBRARIES = $(ops)
diff --git a/operations/workshop/external/jp2-load.c b/operations/workshop/external/jp2-load.c
new file mode 100644
index 0000000..315c16b
--- /dev/null
+++ b/operations/workshop/external/jp2-load.c
@@ -0,0 +1,378 @@
+/* This file is an image processing operation for GEGL
+ *
+ * GEGL 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 3 of the License, or (at your option) any later version.
+ *
+ * GEGL 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 GEGL; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * Copyright (c) 2010 Mukund Sivaraman <muks banu com>
+ */
+
+#include "config.h"
+#include <glib/gi18n-lib.h>
+
+
+#ifdef GEGL_CHANT_PROPERTIES
+
+gegl_chant_file_path (path, _("File"), "", _("Path of file to load."))
+
+#else
+
+#define GEGL_CHANT_TYPE_SOURCE
+#define GEGL_CHANT_C_FILE       "jp2-load.c"
+
+#include "gegl-chant.h"
+#include <stdio.h>
+#include <jasper/jasper.h>
+
+static gboolean
+query_jp2 (const gchar   *path,
+           gint          *width,
+           gint          *height,
+           gint          *depth,
+           jas_stream_t **jas_stream,
+           jas_image_t  **jas_image)
+{
+  gboolean ret;
+  jas_stream_t *in;
+  int image_fmt;
+  jas_image_t *image;
+  int numcmpts;
+  int i;
+  gboolean b;
+
+  in = NULL;
+  image = NULL;
+  ret = FALSE;
+
+  do
+    {
+      in = jas_stream_fopen (path, "rb");
+      if (in == NULL)
+	{
+	  g_warning ("Unable to open image file '%s'", path);
+	  break;
+	}
+
+      image_fmt = jas_image_getfmt (in);
+      if (image_fmt < 0)
+	{
+	  g_warning (_("Unknown JPEG-2000 image format in '%s'"), path);
+          break;
+	}
+
+      image = jas_image_decode (in, image_fmt, NULL);
+      if (image == NULL)
+	{
+	  g_warning (_("Unable to open JPEG-2000 image in '%s'"), path);
+	  break;
+	}
+
+      numcmpts = jas_image_numcmpts (image);
+      if (numcmpts != 3)
+	{
+	  g_warning (_("Unsupported non-RGB JPEG-2000 file with "
+                       "%d components in '%s'"), numcmpts, path);
+	  break;
+	}
+
+      *width = jas_image_cmptwidth (image, 0);
+      *height = jas_image_cmptheight (image, 0);
+      *depth = jas_image_cmptprec (image, 0);
+
+      if ((*depth != 8) && (*depth != 16))
+	{
+	  g_warning (_("Unsupported JPEG-2000 file with depth %d in '%s'"),
+                     *depth, path);
+	  break;
+	}
+
+      b = FALSE;
+
+      for (i = 1; i < 3; i++)
+        {
+          if ((jas_image_cmptprec (image, i) != *depth) ||
+              (jas_image_cmptwidth (image, i) != *width) ||
+              (jas_image_cmptheight (image, i) != *height))
+            {
+              g_warning (_("Components of input image '%s' don't match"),
+                         path);
+              b = TRUE;
+              break;
+            }
+        }
+
+      if (b)
+        break;
+
+      ret = TRUE;
+    }
+  while (FALSE); /* structured goto */
+
+  if (jas_image)
+    *jas_image = image;
+  else if (image)
+    jas_image_destroy (image);
+
+  if (jas_stream)
+    *jas_stream = in;
+  else if (in)
+    jas_stream_close (in);
+
+  return ret;
+}
+
+static void
+prepare (GeglOperation *operation)
+{
+  static gboolean initialized = FALSE;
+
+  if (!initialized)
+    {
+      jas_init ();
+      initialized = TRUE;
+    }
+}
+
+static gboolean
+process (GeglOperation       *operation,
+         GeglBuffer          *output,
+         const GeglRectangle *result)
+{
+  GeglChantO   *o = GEGL_CHANT_PROPERTIES (operation);
+  GeglRectangle rect = {0,0,0,0};
+  jas_stream_t *in;
+  jas_image_t *image;
+  gint width, height, depth;
+  gsize bpc;
+  guchar *data = NULL;
+  gboolean ret;
+  int components[3];
+  jas_matrix_t *matrices[3] = {NULL, NULL, NULL};
+  gint i;
+  gint row;
+  gboolean b;
+  gushort *ptr_s;
+  guchar *ptr_b;
+
+  width = height = depth = 0;
+
+  if (!query_jp2 (o->path, &width, &height, &depth, &in, &image))
+    return FALSE;
+
+  rect.height = height;
+  rect.width = width;
+
+  switch (depth)
+    {
+    case 8:
+      bpc = sizeof (guchar);
+      break;
+
+    case 16:
+      bpc = sizeof (gushort);
+      break;
+
+    default:
+      g_warning ("%s: Programmer stupidity error", G_STRLOC);
+      return FALSE;
+    }
+
+  data = (guchar *) g_malloc (width * height * 3 * bpc);
+  ptr_s = (gushort *) data;
+  ptr_b = data;
+
+  switch (depth)
+    {
+    case 16:
+      gegl_buffer_get (output, 1.0, &rect, babl_format ("R'G'B' u16"), data,
+                       GEGL_AUTO_ROWSTRIDE);
+      break;
+
+    case 8:
+    default:
+      gegl_buffer_get (output, 1.0, &rect, babl_format ("R'G'B' u8"), data,
+                       GEGL_AUTO_ROWSTRIDE);
+    }
+
+  ret = FALSE;
+  b = FALSE;
+
+  do
+    {
+      components[0] = jas_image_getcmptbytype
+        (image, JAS_IMAGE_CT_COLOR(JAS_IMAGE_CT_RGB_R));
+      components[1] = jas_image_getcmptbytype
+        (image, JAS_IMAGE_CT_COLOR(JAS_IMAGE_CT_RGB_G));
+      components[2] = jas_image_getcmptbytype
+        (image, JAS_IMAGE_CT_COLOR(JAS_IMAGE_CT_RGB_B));
+
+      if ((components[0] < 0) || (components[1] < 0) || (components[2] < 0))
+        {
+          g_warning (_("One or more of R, G, B components are missing "
+                       "from '%s'"), o->path);
+          break;
+        }
+
+      if (jas_image_cmptsgnd (image, components[0]) ||
+          jas_image_cmptsgnd (image, components[1]) ||
+          jas_image_cmptsgnd (image, components[2]))
+        {
+          g_warning (_("One or more of R, G, B components have signed "
+                       "data in '%s'"), o->path);
+          break;
+        }
+
+      for (i = 0; i < 3; i++)
+        matrices[i] = jas_matrix_create(1, width);
+
+      for (row = 0; row < height; row++)
+        {
+          gint plane, col;
+          jas_seqent_t *jrow[3] = {NULL, NULL, NULL};
+
+          for (plane = 0; plane < 3; plane++)
+            {
+              int r = jas_image_readcmpt (image, components[plane], 0, row,
+                                          width, 1, matrices[plane]);
+              if (r)
+                {
+                  g_warning (_("Error reading row %d component %d from '%s'"),
+                             row, plane, o->path);
+                  b = TRUE;
+                  break;
+                }
+            }
+
+          if (b)
+            break;
+
+          for (plane = 0; plane < 3; plane++)
+            jrow[plane] = jas_matrix_getref (matrices[plane], 0, 0);
+
+          for (col = 0; col < width; col++)
+            {
+              switch (depth)
+                {
+                case 16:
+                  *ptr_s++ = (gushort) jrow[0][col];
+                  *ptr_s++ = (gushort) jrow[1][col];
+                  *ptr_s++ = (gushort) jrow[2][col];
+                  break;
+
+                case 8:
+                default:
+                  *ptr_b++ = (guchar) jrow[0][col];
+                  *ptr_b++ = (guchar) jrow[1][col];
+                  *ptr_b++ = (guchar) jrow[2][col];
+                }
+            }
+        }
+
+      if (b)
+        break;
+
+      switch (depth)
+        {
+        case 16:
+          gegl_buffer_set (output, &rect, babl_format ("R'G'B' u16"), data,
+                           GEGL_AUTO_ROWSTRIDE);
+          break;
+
+        case 8:
+        default:
+          gegl_buffer_set (output, &rect, babl_format ("R'G'B' u8"), data,
+                           GEGL_AUTO_ROWSTRIDE);
+        }
+
+      ret = TRUE;
+    }
+  while (FALSE); /* structured goto */
+
+  for (i = 0; i < 3; i++)
+    if (matrices[i])
+      jas_matrix_destroy (matrices[i]);
+
+  if (data)
+    g_free (data);
+
+  if (image)
+    jas_image_destroy (image);
+
+  if (in)
+    jas_stream_close (in);
+
+  return ret;
+}
+
+static GeglRectangle
+get_bounding_box (GeglOperation * operation)
+{
+  GeglChantO *o = GEGL_CHANT_PROPERTIES (operation);
+  GeglRectangle result = { 0, 0, 0, 0 };
+  gint width, height, depth;
+
+  width = height = depth = 0;
+
+  if (!query_jp2 (o->path, &width, &height, &depth, NULL, NULL))
+    return result;
+
+  result.width = width;
+  result.height = height;
+
+  switch (depth)
+    {
+    case 16:
+      gegl_operation_set_format (operation, "output",
+				 babl_format ("R'G'B' u16"));
+      break;
+
+    case 8:
+      gegl_operation_set_format (operation, "output",
+				 babl_format ("R'G'B' u8"));
+      break;
+
+    default:
+      g_warning ("%s: Programmer stupidity error", G_STRLOC);
+    }
+
+  return result;
+}
+
+static GeglRectangle
+get_cached_region (GeglOperation       *operation,
+                   const GeglRectangle *roi)
+{
+  return get_bounding_box (operation);
+}
+
+static void
+gegl_chant_class_init (GeglChantClass *klass)
+{
+  GeglOperationClass       *operation_class;
+  GeglOperationSourceClass *source_class;
+
+  operation_class = GEGL_OPERATION_CLASS (klass);
+  source_class    = GEGL_OPERATION_SOURCE_CLASS (klass);
+
+  source_class->process = process;
+  operation_class->prepare = prepare;
+  operation_class->get_bounding_box = get_bounding_box;
+  operation_class->get_cached_region = get_cached_region;
+
+  operation_class->name        = "gegl:jp2-load";
+  operation_class->categories  = "hidden";
+  operation_class->description = _("JPEG-2000 image loader.");
+
+  gegl_extension_handler_register (".jp2", "gegl:jp2-load");
+}
+
+#endif



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]