diff options
author | Øyvind Kolås <pippin@gimp.org> | 2015-06-08 19:27:35 +0200 |
---|---|---|
committer | Øyvind Kolås <pippin@gimp.org> | 2015-06-08 19:29:48 +0200 |
commit | f8447e2cebf51d80d76398fa7e91bbcd892a3200 (patch) | |
tree | 36be68f80b305db6f559195abf20cc17f2e6a8f7 | |
parent | 0ae4d72520bee8c3324d201fb0514021dc9cf46a (diff) |
libraw: rewrite from Paul Sbarra
A more feature-rich and less glitchy, implementation from Paul Sbarra
<tones111@hotmail.com> in bug #647733
-rw-r--r-- | 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 e66b5d3a..85eb7c1b 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"); |