[gegl] webp: Port webp-load operation to GIO
- From: Øyvind Kolås <ok src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gegl] webp: Port webp-load operation to GIO
- Date: Fri, 12 Feb 2016 15:10:14 +0000 (UTC)
commit df44954d8b0f137f5d127076e9e2f0e55e4170cb
Author: Martin Blanchard <tchaik gmx com>
Date: Wed Feb 3 22:08:43 2016 +0100
webp: Port webp-load operation to GIO
Make use of gegl_gio_open_input_stream() service. New 'uri'
property (along the existing 'path' one); benefit is that files
can be opened from distant locations now.
https://bugzilla.gnome.org/show_bug.cgi?id=761521
operations/external/webp-load.c | 292 +++++++++++++++++++++++++++++++++------
1 files changed, 248 insertions(+), 44 deletions(-)
---
diff --git a/operations/external/webp-load.c b/operations/external/webp-load.c
index c661cfd..72412a4 100644
--- a/operations/external/webp-load.c
+++ b/operations/external/webp-load.c
@@ -23,86 +23,246 @@
#ifdef GEGL_PROPERTIES
property_file_path (path, _("File"), "")
- description(_("Path of file to load."))
+ description (_("Path of file to load"))
+property_uri (uri, _("URI"), "")
+ description (_("URI for file to load"))
#else
#define GEGL_OP_SOURCE
#define GEGL_OP_C_SOURCE webp-load.c
-#include "gegl-op.h"
+#include <gegl-op.h>
+#include <gegl-gio-private.h>
#include <webp/decode.h>
-static gboolean
-read_webp (const gchar *path, GeglBuffer *buf, GeglRectangle *bounds_out, const Babl **format_out)
+#define IO_BUFFER_SIZE 4096
+
+typedef struct
{
- GMappedFile *map = g_mapped_file_new (path, FALSE, NULL);
+ GFile *file;
+ GInputStream *stream;
+
+ WebPDecoderConfig *config;
+ WebPIDecoder *decoder;
- const gpointer data = g_mapped_file_get_contents (map);
- gsize data_size = g_mapped_file_get_length (map);
+ const Babl *format;
- const Babl* format;
- GeglRectangle bounds = {0, };
+ gint width;
+ gint height;
+} Priv;
- WebPDecoderConfig config;
- if (!WebPInitDecoderConfig (&config) ||
- WebPGetFeatures (data, data_size, &config.input) != VP8_STATUS_OK)
+static void
+cleanup(GeglOperation *operation)
+{
+ GeglProperties *o = GEGL_PROPERTIES (operation);
+ Priv *p = (Priv*) o->user_data;
+
+ if (p != NULL)
{
- g_mapped_file_unref (map);
- return FALSE;
+ if (p->decoder != NULL)
+ WebPIDelete (p->decoder);
+ p->decoder = NULL;
+ if (p->config != NULL)
+ WebPFreeDecBuffer (&p->config->output);
+ if (p->config != NULL)
+ g_free (p->config);
+ p->config = NULL;
+
+ if (p->stream != NULL)
+ g_input_stream_close (G_INPUT_STREAM (p->stream), NULL, NULL);
+ if (p->stream != NULL)
+ g_clear_object (&p->stream);
+
+ if (p->file != NULL)
+ g_clear_object (&p->file);
+
+ p->width = p->height = 0;
+ p->format = NULL;
}
+}
+
+static gsize
+read_from_stream (GInputStream *stream,
+ guchar **buffer,
+ gsize size)
+{
+ GError *error = NULL;
+ gboolean success;
+ gsize read;
+
+ *buffer = g_try_new (guchar, size);
- bounds.width = config.input.width;
- bounds.height = config.input.height;
+ g_assert (*buffer != NULL);
- if (config.input.has_alpha)
+ success = g_input_stream_read_all (G_INPUT_STREAM (stream),
+ (void *) *buffer, size, &read,
+ NULL, &error);
+ if (!success || error != NULL)
{
- config.output.colorspace = MODE_RGBA;
- format = babl_format ("R'G'B'A u8");
+ g_warning (error->message);
+ g_error_free (error);
+ return -1;
+ }
+
+ return read;
+}
+
+static gsize
+decode_from_stream (GInputStream *stream,
+ WebPIDecoder *decoder)
+{
+ GError *error = NULL;
+ const gsize size = IO_BUFFER_SIZE;
+ guchar *buffer;
+ gsize read, total = 0;
+ VP8StatusCode status;
+ gboolean success;
+
+ buffer = g_try_new (guchar, size);
+
+ g_assert (buffer != NULL);
+
+ do
+ {
+ success = g_input_stream_read_all (G_INPUT_STREAM (stream),
+ (void *) buffer, size, &read,
+ NULL, &error);
+ if (!success || error != NULL)
+ {
+ g_warning (error->message);
+ g_error_free (error);
+ return -1;
+ }
+ else if (read > 0)
+ {
+ total += read;
+
+ status = WebPIAppend (decoder, buffer, read);
+ if (status != VP8_STATUS_OK && status != VP8_STATUS_SUSPENDED)
+ return -1;
+ else if (status == VP8_STATUS_OK)
+ break;
+ }
+ }
+ while (success && read > 0);
+
+ return total;
+}
+
+static gboolean
+query_webp (GeglOperation *operation)
+{
+ GeglProperties *o = GEGL_PROPERTIES (operation);
+ Priv *p = (Priv*) o->user_data;
+
+ g_return_val_if_fail (p->config != NULL, FALSE);
+
+ if (p->config->input.has_alpha)
+ {
+ p->config->output.colorspace = MODE_RGBA;
+ p->format = babl_format ("R'G'B'A u8");
}
else
{
- config.output.colorspace = MODE_RGB;
- format = babl_format ("R'G'B' u8");
+ p->config->output.colorspace = MODE_RGB;
+ p->format = babl_format ("R'G'B' u8");
}
- if (buf)
+ p->height = p->config->input.height;
+ p->width = p->config->input.width;
+
+ return TRUE;
+}
+
+static void
+prepare (GeglOperation *operation)
+{
+ GeglProperties *o = GEGL_PROPERTIES (operation);
+ Priv *p = (o->user_data) ? o->user_data : g_new0 (Priv, 1);
+ GError *error = NULL;
+ GFile *file = NULL;
+ guchar *buffer;
+ gsize read;
+
+ g_assert (p != NULL);
+
+ if (p->file != NULL && (o->uri || o->path))
{
- if (WebPDecode (data, data_size, &config) != VP8_STATUS_OK)
+ if (o->uri && strlen (o->uri) > 0)
+ file = g_file_new_for_uri (o->uri);
+ else if (o->path && strlen (o->path) > 0)
+ file = g_file_new_for_path (o->path);
+ if (file != NULL)
{
- WebPFreeDecBuffer (&config.output);
- g_mapped_file_unref (map);
- return FALSE;
+ if (!g_file_equal (p->file, file))
+ cleanup (operation);
+ g_object_unref (file);
}
+ }
- gegl_buffer_set (buf, &bounds, 0, format, config.output.u.RGBA.rgba,
- config.output.u.RGBA.stride);
+ o->user_data = (void*) p;
- WebPFreeDecBuffer (&config.output);
- }
+ if (p->config == NULL)
+ {
+ p->stream = gegl_gio_open_input_stream (o->uri, o->path, &p->file, &error);
+ if (p->stream == NULL)
+ {
+ g_warning (error->message);
+ g_error_free (error);
+ cleanup (operation);
+ return;
+ }
+
+ p->config = g_try_new (WebPDecoderConfig, 1);
+ p->decoder = WebPINewDecoder (&p->config->output);
+
+ g_assert (p->config != NULL);
- if (bounds_out)
- *bounds_out = bounds;
+ if (!WebPInitDecoderConfig (p->config))
+ {
+ g_warning ("could not initialise WebP decoder configuration");
+ cleanup (operation);
+ return;
+ }
+
+ read = read_from_stream (p->stream, &buffer, IO_BUFFER_SIZE);
+ if (WebPGetFeatures (buffer, read, &p->config->input) != VP8_STATUS_OK)
+ {
+ g_warning ("failed reading WebP image file");
+ cleanup (operation);
+ g_free (buffer);
+ return;
+ }
- if (format_out)
- *format_out = format;
+ if (!query_webp (operation))
+ {
+ g_warning ("could not query WebP image file");
+ cleanup (operation);
+ g_free (buffer);
+ return;
+ }
- g_mapped_file_unref (map);
+ WebPIAppend (p->decoder, buffer, read);
- return TRUE;
+ g_free (buffer);
+ }
+
+ gegl_operation_set_format (operation, "output", p->format);
}
static GeglRectangle
get_bounding_box (GeglOperation *operation)
{
- GeglProperties *o = GEGL_PROPERTIES (operation);
- GeglRectangle result = {0,0,0,0};
- const Babl *format = NULL;
-
- read_webp (o->path, NULL, &result, &format);
+ GeglProperties *o = GEGL_PROPERTIES (operation);
+ GeglRectangle result = { 0, 0, 0, 0 };
+ Priv *p = (Priv*) o->user_data;
- if (format)
- gegl_operation_set_format (operation, "output", format);
+ if (p->config != NULL)
+ {
+ result.width = p->width;
+ result.height = p->height;
+ }
return result;
}
@@ -114,7 +274,32 @@ process (GeglOperation *operation,
gint level)
{
GeglProperties *o = GEGL_PROPERTIES (operation);
- return read_webp (o->path, output, NULL, NULL);
+ Priv *p = (Priv*) o->user_data;
+
+ if (p->config != NULL)
+ {
+ if (p->decoder != NULL)
+ {
+ if (decode_from_stream (p->stream, p->decoder) < 0)
+ {
+ g_warning ("failed decoding WebP image file");
+ cleanup (operation);
+ return FALSE;
+ }
+
+ g_input_stream_close (G_INPUT_STREAM (p->stream), NULL, NULL);
+ g_clear_object (&p->stream);
+
+ WebPIDelete (p->decoder);
+ p->decoder = NULL;
+ }
+
+ gegl_buffer_set (output, result, 0, p->format,
+ p->config->output.u.RGBA.rgba,
+ p->config->output.u.RGBA.stride);
+ }
+
+ return FALSE;
}
static GeglRectangle
@@ -125,15 +310,34 @@ get_cached_region (GeglOperation *operation,
}
static void
+finalize(GObject *object)
+{
+ GeglProperties *o = GEGL_PROPERTIES (object);
+
+ if (o->user_data != NULL)
+ {
+ cleanup (GEGL_OPERATION (object));
+ if (o->user_data != NULL)
+ g_free (o->user_data);
+ o->user_data = NULL;
+ }
+
+ G_OBJECT_CLASS (gegl_op_parent_class)->finalize (object);
+}
+
+static void
gegl_op_class_init (GeglOpClass *klass)
{
GeglOperationClass *operation_class;
GeglOperationSourceClass *source_class;
+ G_OBJECT_CLASS(klass)->finalize = finalize;
+
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;
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]