|
Packit Service |
2781ba |
/* This file is the public GEGL API
|
|
Packit Service |
2781ba |
*
|
|
Packit Service |
2781ba |
* GEGL is free software; you can redistribute it and/or
|
|
Packit Service |
2781ba |
* modify it under the terms of the GNU Lesser General Public
|
|
Packit Service |
2781ba |
* License as published by the Free Software Foundation; either
|
|
Packit Service |
2781ba |
* version 3 of the License, or (at your option) any later version.
|
|
Packit Service |
2781ba |
*
|
|
Packit Service |
2781ba |
* GEGL is distributed in the hope that it will be useful,
|
|
Packit Service |
2781ba |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit Service |
2781ba |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Packit Service |
2781ba |
* Lesser General Public License for more details.
|
|
Packit Service |
2781ba |
*
|
|
Packit Service |
2781ba |
* You should have received a copy of the GNU Lesser General Public
|
|
Packit Service |
2781ba |
* License along with GEGL; if not, see <http://www.gnu.org/licenses>.
|
|
Packit Service |
2781ba |
*
|
|
Packit Service |
2781ba |
* 2006 © Øyvind Kolås.
|
|
Packit Service |
2781ba |
*/
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
/* FIXME: this file should be implemented using public API only */
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
#include "config.h"
|
|
Packit Service |
2781ba |
#include <stdlib.h>
|
|
Packit Service |
2781ba |
#include <stdio.h>
|
|
Packit Service |
2781ba |
#include <string.h>
|
|
Packit Service |
2781ba |
#include <glib-object.h>
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
#include "gegl.h"
|
|
Packit Service |
2781ba |
#include "gegl-types-internal.h"
|
|
Packit Service |
2781ba |
#include "graph/gegl-node.h"
|
|
Packit Service |
2781ba |
#include "graph/gegl-pad.h"
|
|
Packit Service |
2781ba |
#include "graph/gegl-connection.h"
|
|
Packit Service |
2781ba |
#include "graph/gegl-visitable.h"
|
|
Packit Service |
2781ba |
#include "graph/gegl-visitor.h"
|
|
Packit Service |
2781ba |
#include "gegl-dot.h"
|
|
Packit Service |
2781ba |
#include "gegl-dot-visitor.h"
|
|
Packit Service |
2781ba |
#include "gegl.h"
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
void
|
|
Packit Service |
2781ba |
gegl_dot_util_add_node (GString *string,
|
|
Packit Service |
2781ba |
GeglNode *node)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
g_string_append_printf (string, "op_%p [fontsize=\"10\" label=\"", node);
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
/* We build the record from top to bottom */
|
|
Packit Service |
2781ba |
g_string_append_printf (string, "{");
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
/* The first row is a list of output pads */
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
GSList *pads = gegl_node_get_pads (node);
|
|
Packit Service |
2781ba |
GSList *entry = pads;
|
|
Packit Service |
2781ba |
gboolean got_output = FALSE;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
g_string_append_printf (string, "{");
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
while (entry)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
GeglPad *pad = entry->data;
|
|
Packit Service |
2781ba |
if (gegl_pad_is_output (pad))
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
if (got_output)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
g_string_append (string, "|");
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
got_output = TRUE;
|
|
Packit Service |
2781ba |
g_string_append_printf (string, "<%s>%s",
|
|
Packit Service |
2781ba |
gegl_pad_get_name (pad),
|
|
Packit Service |
2781ba |
gegl_pad_get_name (pad));
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
entry = g_slist_next (entry);
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
g_string_append_printf (string, "}|");
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
/* The second row is the operation name such as gegl:translate */
|
|
Packit Service |
2781ba |
g_string_append_printf (string, "%s |", gegl_node_get_debug_name (node));
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
/* The next rows are property names and their values */
|
|
Packit Service |
2781ba |
if (1)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
guint n_properties;
|
|
Packit Service |
2781ba |
GParamSpec **properties = gegl_operation_list_properties (gegl_node_get_operation (node), &n_properties);
|
|
Packit Service |
2781ba |
guint i;
|
|
Packit Service |
2781ba |
for (i = 0; i < n_properties; i++)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
const gchar *name = properties[i]->name;
|
|
Packit Service |
2781ba |
GValue tvalue = { 0, };
|
|
Packit Service |
2781ba |
GValue svalue = { 0, };
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
if (properties[i]->value_type == GEGL_TYPE_BUFFER)
|
|
Packit Service |
2781ba |
continue;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
g_value_init (&svalue, G_TYPE_STRING);
|
|
Packit Service |
2781ba |
g_value_init (&tvalue, properties[i]->value_type);
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
gegl_node_get_property (node, name, &tvalue);
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
if (g_value_transform (&tvalue, &svalue))
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
gchar *sval = g_value_dup_string (&svalue);
|
|
Packit Service |
2781ba |
if (sval && strlen (sval) > 30)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
sval[28] = '.';
|
|
Packit Service |
2781ba |
sval[29] = '.';
|
|
Packit Service |
2781ba |
sval[30] = '\0';
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
if (sval)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
g_string_append_printf (string, "%s=%s | ", name, sval);
|
|
Packit Service |
2781ba |
g_free (sval);
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
g_value_unset (&svalue);
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
g_value_unset (&tvalue);
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
g_free (properties);
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
/* The last row is input pads */
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
GSList *pads = gegl_node_get_pads (node);
|
|
Packit Service |
2781ba |
GSList *entry = pads;
|
|
Packit Service |
2781ba |
gboolean got_input = FALSE;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
g_string_append_printf (string, "{");
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
while (entry)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
GeglPad *pad = entry->data;
|
|
Packit Service |
2781ba |
if (gegl_pad_is_input (pad))
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
if (got_input)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
g_string_append (string, "|");
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
got_input = TRUE;
|
|
Packit Service |
2781ba |
g_string_append_printf (string, "<%s>%s",
|
|
Packit Service |
2781ba |
gegl_pad_get_name (pad),
|
|
Packit Service |
2781ba |
gegl_pad_get_name (pad));
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
entry = g_slist_next (entry);
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
g_string_append_printf (string, "}");
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
g_string_append_printf (string, "}\"");
|
|
Packit Service |
2781ba |
g_string_append_printf (string, "shape=\"record\"];\n");
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
void
|
|
Packit Service |
2781ba |
gegl_dot_util_add_node_sink_edges (GString *string,
|
|
Packit Service |
2781ba |
GeglNode *node)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
GSList *connections = gegl_node_get_sinks (node);
|
|
Packit Service |
2781ba |
GSList *iter;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
for (iter = connections; iter; iter = g_slist_next (iter))
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
GeglConnection *connection = iter->data;
|
|
Packit Service |
2781ba |
gegl_dot_util_add_connection (string, connection);
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
void
|
|
Packit Service |
2781ba |
gegl_dot_util_add_connection (GString *string,
|
|
Packit Service |
2781ba |
GeglConnection *connection)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
GeglNode *source;
|
|
Packit Service |
2781ba |
GeglNode *sink;
|
|
Packit Service |
2781ba |
GeglPad *source_pad;
|
|
Packit Service |
2781ba |
GeglPad *sink_pad;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
source = gegl_connection_get_source_node (connection);
|
|
Packit Service |
2781ba |
sink = gegl_connection_get_sink_node (connection);
|
|
Packit Service |
2781ba |
source_pad = gegl_connection_get_source_pad (connection);
|
|
Packit Service |
2781ba |
sink_pad = gegl_connection_get_sink_pad (connection);
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
g_string_append_printf (string, "op_%p:%s -> op_%p:%s;\n",
|
|
Packit Service |
2781ba |
source, gegl_pad_get_name (source_pad),
|
|
Packit Service |
2781ba |
sink, gegl_pad_get_name (sink_pad));
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
static void
|
|
Packit Service |
2781ba |
gegl_dot_add_graph (GString *string,
|
|
Packit Service |
2781ba |
GeglNode *node,
|
|
Packit Service |
2781ba |
const gchar *label)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
GeglNode *graph = node;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
g_string_append_printf (string, "subgraph cluster_%s%p { graph [ label=\"%s %p\" fontsize=\"10\" ranksep=\"0.3\" nodesep=\"0.3\"]; node [ fontsize=\"10\" ];\n", label, node, label, node);
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
GSList *nodes = gegl_node_get_children (graph);
|
|
Packit Service |
2781ba |
GSList *entry = nodes;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
while (entry)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
GeglNode *node = entry->data;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
if (node->is_graph)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
gchar *name = g_strdup (gegl_node_get_debug_name (node));
|
|
Packit Service |
2781ba |
gchar *p = name;
|
|
Packit Service |
2781ba |
while (*p)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
if (*p == ' ' ||
|
|
Packit Service |
2781ba |
*p == '-')
|
|
Packit Service |
2781ba |
*p = '_';
|
|
Packit Service |
2781ba |
p++;
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
gegl_dot_add_graph (string, node, name);
|
|
Packit Service |
2781ba |
g_free (name);
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
else
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
gegl_dot_util_add_node (string, node);
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
entry = g_slist_next (entry);
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
g_slist_free (nodes);
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
GSList *nodes = gegl_node_get_children (graph);
|
|
Packit Service |
2781ba |
GSList *entry = nodes;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
while (entry)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
GeglNode *node = entry->data;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
gegl_dot_util_add_node_sink_edges (string, node);
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
entry = g_slist_next (entry);
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
g_slist_free (nodes);
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
g_string_append_printf (string, "}\n");
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
/**
|
|
Packit Service |
2781ba |
* gegl_dot_add_node_and_dependencies:
|
|
Packit Service |
2781ba |
* @string:
|
|
Packit Service |
2781ba |
* @node:
|
|
Packit Service |
2781ba |
*
|
|
Packit Service |
2781ba |
* Adds @node to the graph, and all nodes that @node depends on both
|
|
Packit Service |
2781ba |
* directly and indirectly. There is no grouping of subgraphs.
|
|
Packit Service |
2781ba |
**/
|
|
Packit Service |
2781ba |
static void
|
|
Packit Service |
2781ba |
gegl_dot_add_node_and_dependencies (GString *string,
|
|
Packit Service |
2781ba |
GeglNode *node)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
GeglDotVisitor *dot_visitor;
|
|
Packit Service |
2781ba |
GeglPad *pad;
|
|
Packit Service |
2781ba |
gpointer context_id = string;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
dot_visitor = g_object_new (GEGL_TYPE_DOT_VISITOR,
|
|
Packit Service |
2781ba |
"id", context_id,
|
|
Packit Service |
2781ba |
NULL);
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
gegl_dot_visitor_set_string_to_append (dot_visitor,
|
|
Packit Service |
2781ba |
string);
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
/* Add the nodes */
|
|
Packit Service |
2781ba |
gegl_visitor_bfs_traverse (GEGL_VISITOR (dot_visitor),
|
|
Packit Service |
2781ba |
GEGL_VISITABLE (node));
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
/* Add the edges */
|
|
Packit Service |
2781ba |
pad = gegl_node_get_pad (node, "output");
|
|
Packit Service |
2781ba |
if (! pad)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
pad = gegl_node_get_pad (node, "input");
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
if (pad)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
/* This is a sink node, we need to add these edges manually
|
|
Packit Service |
2781ba |
* since no pad depends on this input pad */
|
|
Packit Service |
2781ba |
GSList *iter;
|
|
Packit Service |
2781ba |
for (iter = pad->connections; iter; iter = g_slist_next (iter))
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
GeglConnection *connection = iter->data;
|
|
Packit Service |
2781ba |
gegl_dot_util_add_connection (string, connection);
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
gegl_visitor_bfs_traverse (GEGL_VISITOR (dot_visitor),
|
|
Packit Service |
2781ba |
GEGL_VISITABLE (pad));
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
g_object_unref (dot_visitor);
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
gchar *
|
|
Packit Service |
2781ba |
gegl_to_dot (GeglNode *node)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
GString *string;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
string = g_string_new ("digraph gegl { graph [ rankdir = \"BT\" fontsize = \"10\" ];\n");
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
if (node->is_graph)
|
|
Packit Service |
2781ba |
gegl_dot_add_graph (string, node, "GEGL");
|
|
Packit Service |
2781ba |
else
|
|
Packit Service |
2781ba |
gegl_dot_add_node_and_dependencies (string, node);
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
g_string_append (string, "}\n");
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
return g_string_free (string, FALSE);
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
/**
|
|
Packit Service |
2781ba |
* gegl_dot_node_to_png_default:
|
|
Packit Service |
2781ba |
* @node:
|
|
Packit Service |
2781ba |
*
|
|
Packit Service |
2781ba |
* Calls gegl_dot_node_to_png() with `png_path' set to "/tmp/node.png".
|
|
Packit Service |
2781ba |
**/
|
|
Packit Service |
2781ba |
void
|
|
Packit Service |
2781ba |
gegl_dot_node_to_png_default (GeglNode *node)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
gegl_dot_node_to_png (node, "/tmp/node.png");
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
/**
|
|
Packit Service |
2781ba |
* gegl_dot_node_to_png:
|
|
Packit Service |
2781ba |
* @node: Node to depict graph for.
|
|
Packit Service |
2781ba |
* @png_path: Path of the png to write.
|
|
Packit Service |
2781ba |
*
|
|
Packit Service |
2781ba |
* This is for debug purposes, meant to be invoked directly from a
|
|
Packit Service |
2781ba |
* debugger.
|
|
Packit Service |
2781ba |
**/
|
|
Packit Service |
2781ba |
void
|
|
Packit Service |
2781ba |
gegl_dot_node_to_png (GeglNode *node,
|
|
Packit Service |
2781ba |
const gchar *png_path)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
gchar *dot_string = NULL;
|
|
Packit Service |
2781ba |
gchar *dot_filename = NULL;
|
|
Packit Service |
2781ba |
gchar *dot_cmd = NULL;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
/* Get dot string */
|
|
Packit Service |
2781ba |
dot_string = gegl_to_dot (node);
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
/* Write it to a file */
|
|
Packit Service |
2781ba |
dot_filename = g_build_filename (g_get_tmp_dir (), "gegl-dot.dot", NULL);
|
|
Packit Service |
2781ba |
g_file_set_contents (dot_filename, dot_string, -1, NULL);
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
/* Create a png from it */
|
|
Packit Service |
2781ba |
dot_cmd = g_strdup_printf ("dot -o %s -Tpng %s", png_path, dot_filename);
|
|
Packit Service |
2781ba |
if (system (dot_cmd) == -1)
|
|
Packit Service |
2781ba |
g_warning ("Error executing GraphViz dot program");
|
|
Packit Service |
2781ba |
}
|