[gegl] Created dynamic save operation using save_handlers
- From: Martin Nordholts <martinn src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gegl] Created dynamic save operation using save_handlers
- Date: Thu, 8 Jul 2010 13:35:26 +0000 (UTC)
commit 6656e22398e56ec47bf86954b8cd967c4725c7c8
Author: Danny Robson <danny blubinc net>
Date: Sat May 29 16:45:47 2010 +1000
Created dynamic save operation using save_handlers
Introduced gegl:save, an operation which dynamically instances the
correct operation to save to a given path using the save_handler
routines.
It is implemented in terms of a sink operation, rather than a
meta-operation, so that it works with existing code. In particular, the
processor code uses introspection, and processes sink differently to
other operations.
bin/gegl.c | 4 +-
operations/common/save.c | 195 ++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 196 insertions(+), 3 deletions(-)
---
diff --git a/bin/gegl.c b/bin/gegl.c
index 5b8841e..fa64ca2 100644
--- a/bin/gegl.c
+++ b/bin/gegl.c
@@ -276,10 +276,8 @@ main (gint argc,
#endif
case GEGL_RUN_MODE_OUTPUT:
{
- const gchar *ext = file_utils_get_ext_start (o->output);
- const gchar *handler = gegl_extension_handler_get_saver (ext);
GeglNode *output = gegl_node_new_child (gegl,
- "operation", handler,
+ "operation", "gegl:save",
"path", o->output,
NULL);
gegl_node_connect_from (output, "input", gegl_node_get_output_proxy (gegl, "output"), "output");
diff --git a/operations/common/save.c b/operations/common/save.c
new file mode 100644
index 0000000..8dfea42
--- /dev/null
+++ b/operations/common/save.c
@@ -0,0 +1,195 @@
+/* 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 2010 Danny Robson <danny blubinc net>
+ */
+
+#include "config.h"
+#include <glib/gi18n-lib.h>
+
+
+#ifdef GEGL_CHANT_PROPERTIES
+
+gegl_chant_file_path (path, _("File"), "", _("Path of file to save."))
+
+#else
+
+#define GEGL_CHANT_C_FILE "save.c"
+
+#include "gegl-plugin.h"
+#include "gegl/graph/gegl-node.h"
+
+struct _GeglChant
+{
+ GeglOperationSink parent_instance;
+ gpointer properties;
+
+ GeglNode *input;
+ GeglNode *save;
+ gchar *cached_path;
+};
+
+typedef struct
+{
+ GeglOperationSinkClass parent_class;
+} GeglChantClass;
+
+#include "gegl-chant.h"
+GEGL_DEFINE_DYNAMIC_OPERATION(GEGL_TYPE_OPERATION_SINK)
+
+#include <stdio.h>
+
+
+static gboolean
+gegl_save_set_saver (GeglOperation *operation)
+{
+ GeglChantO *o = GEGL_CHANT_PROPERTIES (operation);
+ GeglChant *self = GEGL_CHANT (operation);
+ const gchar *extension, *handler;
+ gboolean success = FALSE;
+
+ /* If prepare has already been invoked, bail out early */
+ if (self->cached_path && !strcmp (o->path, self->cached_path))
+ return TRUE;
+ g_free (self->cached_path);
+
+ /* Find an extension handler and put it into the graph. The path can be
+ * empty, which indicates an error, but not null. Ideally we'd like to
+ * report an error here, but there's no way to pass it back to GEGL or the
+ * user in prepare()...
+ */
+ g_assert (o->path);
+ extension = strrchr (o->path, '.');
+ handler = extension ? gegl_extension_handler_get_saver (extension) : NULL;
+
+ if (handler)
+ {
+ gegl_node_set (self->save,
+ "operation", handler,
+ "path", o->path,
+ NULL);
+ success = TRUE;
+ }
+ else
+ {
+ g_warning ("Unable to find suitable save handler for path '%s'", o->path);
+ gegl_node_set (self->save,
+ "operation", "gegl:nop",
+ NULL);
+ }
+
+ self->cached_path = g_strdup (o->path);
+ return success;
+}
+
+
+/* Create an input proxy, and temporary save operation, and link together.
+ * These will be passed control when gegl_save_process is called later.
+ */
+static void
+gegl_save_attach (GeglOperation *operation)
+{
+ GeglChant *self = GEGL_CHANT (operation);
+ const gchar *nodename;
+ gchar *childname;
+
+ g_assert (!self->input);
+ g_assert (!self->save);
+ g_assert (!self->cached_path);
+
+ /* Initialise and attach child nodes */
+ self->input = gegl_node_get_input_proxy (operation->node, "input");
+ self->save = gegl_node_new_child (operation->node,
+ "operation", "gegl:nop",
+ NULL);
+
+ /* Set some debug names for the child nodes */
+ nodename = gegl_node_get_debug_name (operation->node);
+ g_assert (nodename);
+
+ childname = g_strconcat (nodename, "-save", NULL);
+ gegl_node_set_name (self->input, childname);
+ g_free (childname);
+
+ childname = g_strconcat (nodename, "-input", NULL);
+ gegl_node_set_name (self->input, childname);
+ g_free (childname);
+
+ /* Link the saving node and attempt to set an appropriate save operation,
+ * might as well at least try to do this before prepare.
+ */
+ gegl_node_link (self->input, self->save);
+ gegl_save_set_saver (operation);
+}
+
+
+static void
+gegl_save_prepare (GeglOperation *operation)
+{
+ gegl_save_set_saver (operation);
+}
+
+
+static gboolean
+gegl_save_process (GeglOperation *operation,
+ GeglOperationContext *context,
+ const gchar *output_pad,
+ const GeglRectangle *roi)
+{
+ GeglChant *self = GEGL_CHANT (operation);
+
+ return gegl_operation_process (self->save->operation,
+ context,
+ output_pad,
+ roi);
+}
+
+static void
+gegl_save_dispose (GObject *object)
+{
+ GeglChant *self = GEGL_CHANT (object);
+
+ g_free (self->cached_path);
+ self->cached_path = NULL;
+
+ G_OBJECT_CLASS (gegl_chant_parent_class)->dispose (object);
+}
+
+
+static void
+gegl_chant_class_init (GeglChantClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ GeglOperationSinkClass *sink_class = GEGL_OPERATION_SINK_CLASS (klass);
+ GeglOperationClass *operation_class = GEGL_OPERATION_CLASS (klass);
+
+ object_class->dispose = gegl_save_dispose;
+
+ operation_class->attach = gegl_save_attach;
+ operation_class->prepare = gegl_save_prepare;
+
+ operation_class->process = gegl_operation_process;
+ operation_class->process = gegl_save_process;
+
+ sink_class->needs_full = TRUE;
+
+ operation_class->name = "gegl:save";
+ operation_class->categories = "meta:output";
+ operation_class->description =
+ _("Multipurpose file saver, that uses other native handlers.");
+}
+
+#endif
+
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]