[gegl] jp2-load: Add support for loading JPEG-2000 images
- From: Mukund Sivaraman <muks src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gegl] jp2-load: Add support for loading JPEG-2000 images
- Date: Tue, 22 Jun 2010 18:22:52 +0000 (UTC)
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]