[gegl] add libraw based raw loader op



commit 556e8589fe74a281a05f8219eaab4fab29c05753
Author: Øyvind Kolås <pippin gimp org>
Date:   Sat May 23 16:18:40 2015 +0200

    add libraw based raw loader op
    
    Add a libraw op based on rough cleanup to make the patch in
    
    https://bugzilla.gnome.org/show_bug.cgi?id=647733
    
    compile with git master.

 configure.ac                    |   21 +++
 operations/external/Makefile.am |   17 ++-
 operations/external/lraw.c      |  270 +++++++++++++++++++++++++++++++++++++++
 3 files changed, 303 insertions(+), 5 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index 39a190e..52b2572 100644
--- a/configure.ac
+++ b/configure.ac
@@ -50,6 +50,7 @@ m4_define([librsvg_required_version], [2.14.0])
 m4_define([libv4l2_required_version], [1.0.1])
 m4_define([lua_required_version], [5.1.0])
 m4_define([openexr_required_version], [0.0.0])
+m4_define([libraw_required_version], [0.16.0])
 m4_define([openraw_required_version], [0.0.5])
 m4_define([pango_required_version], [0.0.0])
 m4_define([pangocairo_required_version], [0.0.0])
@@ -890,6 +891,25 @@ AC_SUBST(OPENRAW_LIBS)
 
 
 ##################
+# Check for libraw
+##################
+
+AC_ARG_WITH(libraw, [  --without-libraw          build without libraw support])
+
+have_libraw="no"
+if test "x$with_libraw" != "xno"; then
+  PKG_CHECK_MODULES(LIBRAW, libraw >= libraw_required_version,
+    have_libraw="yes",
+    have_libraw="no  (libraw library not found)")
+fi
+
+AM_CONDITIONAL(HAVE_LIBRAW, test "$have_libraw" = "yes")
+
+AC_SUBST(LIBRAW_CFLAGS) 
+AC_SUBST(LIBRAW_LIBS) 
+
+
+##################
 # Check for Jasper
 ##################
 
@@ -1292,6 +1312,7 @@ Optional dependencies:
   rsvg:            $have_librsvg
   SDL:             $have_sdl
   openraw:         $have_libopenraw
+  libraw:          $have_libraw
   Jasper:          $have_jasper
   graphviz:        $have_graphviz
   avformat:        $have_libavformat
diff --git a/operations/external/Makefile.am b/operations/external/Makefile.am
index 63b9fac..d857ef1 100644
--- a/operations/external/Makefile.am
+++ b/operations/external/Makefile.am
@@ -82,11 +82,18 @@ sdl_display_la_LIBADD = $(op_libs) $(SDL_LIBS)
 sdl_display_la_CFLAGS = $(AM_CFLAGS) $(SDL_CFLAGS)
 endif
 
-if HAVE_OPENRAW
-ops += openraw.la
-openraw_la_SOURCES = openraw.c
-openraw_la_LIBADD = $(op_libs) $(OPENRAW_LIBS)
-openraw_la_CFLAGS = $(AM_CFLAGS) $(OPENRAW_CFLAGS)
+#if HAVE_OPENRAW
+#ops += openraw.la
+#openraw_la_SOURCES = openraw.c
+#openraw_la_LIBADD = $(op_libs) $(OPENRAW_LIBS)
+#openraw_la_CFLAGS = $(AM_CFLAGS) $(OPENRAW_CFLAGS)
+#endif
+
+if HAVE_LIBRAW
+ops += lraw.la
+lraw_la_SOURCES = lraw.c
+law_la_LIBADD = $(op_libs) $(LIBRAW_LIBS)
+lraw_la_CFLAGS = $(AM_CFLAGS) $(LIBRAW_CFLAGS)
 endif
 
 if HAVE_V4L
diff --git a/operations/external/lraw.c b/operations/external/lraw.c
new file mode 100644
index 0000000..d48cee5
--- /dev/null
+++ b/operations/external/lraw.c
@@ -0,0 +1,270 @@
+/* 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 2006 Øyvind Kolås <pippin gimp org>
+ * Copyright 2008 Hubert Figuière <hub figuiere net>
+ * Copyright 2011 Chong Kai Xiong <w_velocity yahoo com>
+ */
+
+#include "config.h"
+#include <glib/gi18n-lib.h>
+
+#ifdef GEGL_PROPERTIES
+
+property_file_path (path, "File", "")
+  description (_("Path of file to load."))
+
+#else
+
+#include "gegl-plugin.h"
+struct _GeglOp
+{
+  GeglOperationSource parent_instance;
+  gpointer            properties;
+
+  gchar *cached_path;  /* Path we have cached. Detects need for recache. */
+};
+
+typedef struct
+{
+  GeglOperationSourceClass parent_class;
+} GeglOpClass;
+
+#define GEGL_OP_C_SOURCE lraw.c
+#include "gegl-op.h"
+GEGL_DEFINE_DYNAMIC_OPERATION(GEGL_TYPE_OPERATION_SOURCE)
+
+#include <stdio.h>
+#include <libraw.h>
+
+static void
+free_buffer (GeglOperation * operation)
+{
+  GeglProperties *o    = GEGL_PROPERTIES (operation);
+  GeglOp         *self = GEGL_OP(operation);
+
+  if (o->user_data)
+    {
+      g_assert (self->cached_path);
+      g_object_unref (o->user_data);
+      o->user_data = NULL;
+    }
+
+  if (self->cached_path)
+  {
+    g_free (self->cached_path);
+    self->cached_path = NULL;
+  }
+}
+
+/* Loads the RAW pixel data from the specified path in chant parameters into
+ * a GeglBuffer for caching. Maintains copy of the path that has been cached
+ * so we can check for modifications and recache.
+ */
+static GeglBuffer *
+load_buffer (GeglOperation *operation)
+{
+  GeglProperties *o    = GEGL_PROPERTIES (operation);
+  GeglOp         *self = GEGL_OP(operation);
+
+  libraw_data_t *rawdata;
+
+  /* If the path has changed since last time, destroy our cache */
+  if (!self->cached_path || strcmp (self->cached_path, o->path))
+    {
+      free_buffer(operation);
+    }
+
+  if (o->user_data)
+    {
+      return o->user_data;
+    }
+  g_assert (self->cached_path == NULL);
+
+  rawdata = libraw_init (0);
+
+  if (!rawdata)
+    {
+      return NULL;
+    }
+
+  /* Gather the file and data resources needed for our cache */
+
+  if (libraw_open_file(rawdata, o->path))
+    {
+      goto clean_data;
+    }
+
+  /* TODO: Handle 3-color Foveon and 4-color Sinar 4-shot */
+  if (rawdata->idata.is_foveon)
+    {
+      goto clean_data;
+    }
+
+  if (libraw_unpack (rawdata))
+    {
+      goto clean_data;
+    }
+
+  /* Build a gegl_buffer, backed with the LibRaw supplied data. */
+    {
+      GeglRectangle extent = { 0, 0, 0, 0 };
+      guint32 width, height;
+      gint row, col, component;
+      guint16 *buffer;
+      gint offset;
+
+      width  = rawdata->sizes.iwidth;
+      height = rawdata->sizes.iheight;
+
+      g_assert (height > 0 && width > 0);
+      extent.width  = width;
+      extent.height = height;
+
+      buffer = g_new (guint16, width * height);
+      offset = 0;
+
+      for (row = 0; row < height; row++)
+        for (col = 0; col < width; col++)
+          {
+            component = rawdata->idata.filters >> (((row << 1 & 14) + (col & 1)) << 1) & 3;
+            buffer[offset] = rawdata->image[offset][component];
+            offset++;
+          }
+
+      g_assert (o->user_data == NULL);
+      o->user_data = gegl_buffer_linear_new_from_data (buffer,
+                                                        babl_format ("Y u16"),
+                                                        &extent,
+                                                        GEGL_AUTO_ROWSTRIDE,
+                                                        G_CALLBACK (g_free),
+                                                        NULL);
+    }
+
+  self->cached_path = g_strdup (o->path);
+
+clean_data:
+  libraw_close(rawdata);
+
+  return o->user_data;
+}
+
+
+static void
+prepare (GeglOperation *operation)
+{
+  gegl_operation_set_format (operation, "output", babl_format ("Y u16"));
+}
+
+
+static GeglRectangle
+get_bounding_box (GeglOperation *operation)
+{
+  GeglProperties *o    = GEGL_PROPERTIES (operation);
+  if (!load_buffer (operation))
+    {
+      GeglRectangle nullrect = { 0, 0, 0, 0 };
+      return nullrect;
+    }
+
+  return *gegl_buffer_get_extent (o->user_data);
+}
+
+
+static GeglRectangle
+get_cached_region (GeglOperation       *operation,
+                   const GeglRectangle *roi)
+{
+  return get_bounding_box (operation);
+}
+
+
+static gboolean
+process (GeglOperation          *operation,
+         GeglOperationContext   *context,
+         const gchar            *output_pad,
+         const GeglRectangle    *result)
+{
+  GeglProperties *o    = GEGL_PROPERTIES (operation);
+  g_assert (g_str_equal (output_pad, "output"));
+
+  if (!load_buffer (operation))
+    {
+      return FALSE;
+    }
+
+  /* Give the operation a reference to the object, and keep a reference
+   * ourselves. We desperately do not want to delete our cached object, as
+   * we continue to service metadata calls after giving the object to the
+   * context.
+   */
+  g_assert (o->user_data);
+  gegl_operation_context_take_object (context, "output", G_OBJECT (o->user_data));
+  g_object_ref (G_OBJECT (o->user_data));
+
+  return TRUE;
+}
+
+
+#include <glib-object.h>
+
+static void
+finalize (GObject *object)
+{
+  free_buffer (GEGL_OPERATION (object));
+
+  G_OBJECT_CLASS (gegl_op_parent_class)->finalize (object);
+}
+
+static void
+gegl_op_class_init (GeglOpClass *klass)
+{
+  static gboolean done = FALSE;
+
+  GObjectClass             *object_class;
+  GeglOperationClass       *operation_class;
+
+  object_class    = G_OBJECT_CLASS (klass);
+  operation_class = GEGL_OPERATION_CLASS (klass);
+
+  object_class->finalize = finalize;
+
+  operation_class->process = process;
+  operation_class->get_bounding_box = get_bounding_box;
+  operation_class->get_cached_region = get_cached_region;
+  operation_class->prepare     = prepare;
+
+  gegl_operation_class_set_keys (operation_class,
+    "name",        "gegl:libraw-load",
+    "title",       _("LibRAW File Loader"),
+    "categories",  "hidden",
+    "description", "Camera RAW image loader",
+    NULL);
+
+  if (done)
+    return;
+
+  /* query libopenraw instead. need a new API */
+  gegl_extension_handler_register (".cr2", "gegl:openraw-load");
+  gegl_extension_handler_register (".crw", "gegl:openraw-load");
+  gegl_extension_handler_register (".erf", "gegl:openraw-load");
+  gegl_extension_handler_register (".mrw", "gegl:openraw-load");
+  gegl_extension_handler_register (".nef", "gegl:openraw-load");
+  gegl_extension_handler_register (".dng", "gegl:openraw-load");
+
+  done = TRUE;
+}
+
+#endif


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