[gegl] libraw: rewrite from Paul Sbarra



commit f8447e2cebf51d80d76398fa7e91bbcd892a3200
Author: Øyvind Kolås <pippin gimp org>
Date:   Mon Jun 8 19:27:35 2015 +0200

    libraw: rewrite from Paul Sbarra
    
    A more feature-rich and less glitchy, implementation from Paul Sbarra
    <tones111 hotmail com> in bug #647733

 operations/external/raw-load.c |  287 +++++++++++++++++++---------------------
 1 files changed, 137 insertions(+), 150 deletions(-)
---
diff --git a/operations/external/raw-load.c b/operations/external/raw-load.c
index e66b5d3..85eb7c1 100644
--- a/operations/external/raw-load.c
+++ b/operations/external/raw-load.c
@@ -16,6 +16,7 @@
  * 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>
+ * Copyright 2011 Paul Sbarra <tones111 hotmail com>
  */
 
 #include "config.h"
@@ -25,6 +26,9 @@
 
 property_file_path (path, "File", "")
   description (_("Path of file to load."))
+property_int (image_num, "Image number", 0)
+property_int (bps, "bits per sample", 16)
+property_int (quality, "quality", 10)
 
 #else
 
@@ -49,184 +53,166 @@ GEGL_DEFINE_DYNAMIC_OPERATION(GEGL_TYPE_OPERATION_SOURCE)
 #include <stdio.h>
 #include <libraw.h>
 
+#include <stdio.h>
+#include <string.h>
+#include <libraw/libraw.h>
+
+typedef struct {
+  libraw_data_t            *LibRaw;
+  libraw_processed_image_t *image;
+} Private;
+
+unsigned char first_pass = 1;
+
 static void
-free_buffer (GeglOperation * operation)
+prepare (GeglOperation *operation)
 {
-  GeglProperties *o    = GEGL_PROPERTIES (operation);
-  GeglOp         *self = GEGL_OP(operation);
+  GeglProperties *o = GEGL_PROPERTIES (operation);
+  Private    *p = (Private*)o->user_data;
+  int         ret;
 
-  if (o->user_data)
+  if (p == NULL && first_pass)
     {
-      g_assert (self->cached_path);
-      g_object_unref (o->user_data);
-      o->user_data = NULL;
+      first_pass = 0;
+      
+      if ((p = g_new0(Private, 1)) == NULL)
+        g_warning ("raw-load: Error creating private structure");
+      else
+        {
+          o->user_data = (gpointer)p;
+          p->LibRaw = NULL;
+          p->image = NULL;
+
+          if ((p->LibRaw = libraw_init(0)) == NULL)
+            g_warning ("raw-load: Error Initializing raw library");
+          else
+            {
+              p->LibRaw->params.shot_select = o->image_num;
+        
+              p->LibRaw->params.gamm[0] = 1.0;
+              p->LibRaw->params.gamm[1] = 1.0;
+              p->LibRaw->params.no_auto_bright = 1;
+
+              p->LibRaw->params.output_bps = o->bps > 8 ? 16 : 8;
+              p->LibRaw->params.user_qual = o->quality;
+
+              if ((ret = libraw_open_file(p->LibRaw, o->path)) != LIBRAW_SUCCESS)
+                g_warning ("raw-load: Unable to open %s: %s", o->path, libraw_strerror (ret));
+            }
+        }
     }
-
-  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)
+static GeglRectangle
+get_bounding_box (GeglOperation *operation)
 {
-  GeglProperties *o    = GEGL_PROPERTIES (operation);
-  GeglOp         *self = GEGL_OP(operation);
-
-  libraw_data_t *rawdata;
+  GeglProperties *o      = GEGL_PROPERTIES (operation);
+  Private        *p      = (Private*)o->user_data;
+  GeglRectangle  result = {0,0,0,0};
 
-  /* If the path has changed since last time, destroy our cache */
-  if (!self->cached_path || strcmp (self->cached_path, o->path))
+  if (p == NULL)
     {
-      free_buffer(operation);
+      prepare(operation);
+      p = (Private*)o->user_data;
     }
 
-  if (o->user_data)
+  if (p != NULL &&
+      p->LibRaw != NULL &&
+      (p->LibRaw->progress_flags & LIBRAW_PROGRESS_IDENTIFY)) 
     {
-      return o->user_data;
+      result.width  = p->LibRaw->sizes.width;
+      result.height = p->LibRaw->sizes.height;
+      gegl_operation_set_format (operation, "output", babl_format ("RGB u16"));
     }
-  g_assert (self->cached_path == NULL);
-
-  rawdata = libraw_init (0);
 
-  if (!rawdata)
-    {
-      return NULL;
-    }
-
-  /* Gather the file and data resources needed for our cache */
+  return result;
+}
 
-  if (libraw_open_file(rawdata, o->path))
-    {
-      goto clean_data;
-    }
+static gboolean
+process (GeglOperation       *operation,
+         GeglBuffer          *output,
+         const GeglRectangle *result,
+         int                  level)
+{
+  GeglProperties *o = GEGL_PROPERTIES (operation);
+  Private *p = (Private*)o->user_data;
+  GeglRectangle rect = {0,0,0,0};
+  const Babl *format = NULL;
+  int ret;
 
-  /* TODO: Handle 3-color Foveon and 4-color Sinar 4-shot */
-  if (rawdata->idata.is_foveon)
+  if (p == NULL)
     {
-      goto clean_data;
+      prepare(operation);
+      p = (Private*)o->user_data;
     }
 
-  if (libraw_unpack (rawdata))
+  if (p != NULL &&
+      p->LibRaw != NULL)
     {
-      goto clean_data;
+      if (!(p->LibRaw->progress_flags & LIBRAW_PROGRESS_LOAD_RAW))
+        {
+          if ((ret = libraw_unpack(p->LibRaw)) != LIBRAW_SUCCESS)
+            g_warning ("raw-load: Error unpacking data: %s", libraw_strerror (ret));
+
+          if (ret == LIBRAW_SUCCESS && !(p->LibRaw->progress_flags & LIBRAW_PROGRESS_CONVERT_RGB))
+            {
+              if ((ret = libraw_dcraw_process(p->LibRaw)) != LIBRAW_SUCCESS)
+                g_warning ("raw-load: Error processing data: %s", libraw_strerror (ret));
+              else if ((p->image = libraw_dcraw_make_mem_image(p->LibRaw, &ret)) == NULL)
+                g_warning ("raw-load: Error converting image: %s", libraw_strerror (ret));
+            }
+        }
     }
 
-  /* Build a gegl_buffer, backed with the LibRaw supplied data. */
+  if (p->image != NULL)
     {
-      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,
-                                                        (void*)g_free,
-                                                        NULL);
+      g_assert (p->image->type == LIBRAW_IMAGE_BITMAP);
+      rect.width  = p->image->width;
+      rect.height = p->image->height;
+
+      if (p->image->bits == 8)
+        {
+          if (p->image->colors == 1)
+            format = babl_format ("Y u8");
+          else // 3 color channels
+            format = babl_format ("RGB u8");
+        }
+      else // 16-bit
+        {
+          if (p->image->colors == 1)
+            format = babl_format ("Y u16");
+          else // 3 color channels
+            format = babl_format ("RGB u16");
+        }
+
+      gegl_buffer_set (output, &rect, 0, format, p->image->data, GEGL_AUTO_ROWSTRIDE);
+      return TRUE;
     }
 
-  self->cached_path = g_strdup (o->path);
-
-clean_data:
-  libraw_close(rawdata);
-
-  return o->user_data;
+  return FALSE;
 }
 
-
 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,
-         int                     level)
+finalize (GObject *object)
 {
-  GeglProperties *o    = GEGL_PROPERTIES (operation);
-  g_assert (g_str_equal (output_pad, "output"));
+  GeglProperties *o = GEGL_PROPERTIES (object);
 
-  if (!load_buffer (operation))
+  if (o->user_data)
     {
-      return FALSE;
+      Private *p = (Private*)o->user_data;
+      if (p->LibRaw != NULL)
+        {
+          if (p->image != NULL)
+            libraw_dcraw_clear_mem (p->image);
+          
+          libraw_close (p->LibRaw);
+        }
+
+      g_free (o->user_data);
+      o->user_data = NULL;
     }
 
-  /* 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);
+  G_OBJECT_CLASS (gegl_op_parent_class)->finalize(object);
 }
 
 static void
@@ -236,20 +222,20 @@ gegl_op_class_init (GeglOpClass *klass)
 
   GObjectClass             *object_class;
   GeglOperationClass       *operation_class;
+  GeglOperationSourceClass *source_class;
 
   object_class    = G_OBJECT_CLASS (klass);
   operation_class = GEGL_OPERATION_CLASS (klass);
+  source_class = GEGL_OPERATION_SOURCE_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;
+  operation_class->get_bounding_box = get_bounding_box;
+  source_class->process = process;
+  object_class->finalize = finalize;
 
   gegl_operation_class_set_keys (operation_class,
     "name",        "gegl:raw-load",
-    "title",       _("LibRAW File Loader"),
+    "title",       _("libraw File Loader"),
     "categories",  "hidden",
     "description", "Camera RAW image loader",
     NULL);
@@ -262,6 +248,7 @@ gegl_op_class_init (GeglOpClass *klass)
   gegl_extension_handler_register (".nef", "gegl:raw-load");
   gegl_extension_handler_register (".raf", "gegl:raw-load");
   gegl_extension_handler_register (".orf", "gegl:raw-load");
+  gegl_extension_handler_register (".erf", "gegl:raw-load");
   gegl_extension_handler_register (".mrw", "gegl:raw-load");
   gegl_extension_handler_register (".crw", "gegl:raw-load");
   gegl_extension_handler_register (".cr2", "gegl:raw-load");


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