static void set_property(GObject *gobject, guint property_id, const GValue *value, GParamSpec *pspec) { GeglGtkView *self = GEGL_GTK_VIEW(gobject); ViewHelper *priv = GET_PRIVATE(self); switch (property_id) { case PROP_NODE: gegl_gtk_view_set_node(self, GEGL_NODE(g_value_get_object(value))); break; case PROP_BLOCK: priv->block = g_value_get_boolean(value); break; case PROP_SCALE: gegl_gtk_view_set_scale(self, g_value_get_double(value)); break; case PROP_AUTOSCALE_POLICY: gegl_gtk_view_set_autoscale_policy(self, g_value_get_enum(value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID(gobject, property_id, pspec); break; } }
static void print_info(GeglNode* gegl) { GSList *list = gegl_node_get_children(gegl); for(;list != NULL; list = list->next) { GeglNode* node = GEGL_NODE(list->data); g_print("Node %s\n", gegl_node_get_operation(node)); if(gegl_node_get_pad(node, "output") == NULL) { g_print("Output pad is NULL\n"); } /* GeglNode** nodes; const gchar** pads; gint num = gegl_node_get_consumers(node, "output", &nodes, &pads); g_print("%s: %d consumer(s)\n", gegl_node_get_operation(node), num); int i; for(i = 0; i < num; i++) { g_print("Connection: (%s to %s)\n", gegl_node_get_operation(node), gegl_node_get_operation(nodes[0]), pads[0]); } g_print("\n");*/ } }
static void photos_print_setup_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { PhotosPrintSetup *self = PHOTOS_PRINT_SETUP (object); PhotosPrintSetupPrivate *priv = self->priv; switch (prop_id) { case PROP_NODE: { GdkPixbuf *pixbuf; priv->node = GEGL_NODE (g_value_dup_object (value)); pixbuf = photos_utils_create_pixbuf_from_node (priv->node); if (pixbuf != NULL) { g_object_set (priv->preview, "pixbuf", pixbuf, NULL); g_object_unref (pixbuf); } } break; case PROP_PAGE_SETUP: priv->page_setup = GTK_PAGE_SETUP (g_value_get_object (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } }
/** * gegl_graph_prepare: * @path: The traversal path * * Prepare all nodes, initializing their output formats and have rects. */ void gegl_graph_prepare (GeglGraphTraversal *path) { GList *list_iter = NULL; for (list_iter = path->dfs_path; list_iter; list_iter = list_iter->next) { GeglNode *node = GEGL_NODE (list_iter->data); GeglOperation *operation = node->operation; g_mutex_lock (&node->mutex); gegl_operation_prepare (operation); node->have_rect = gegl_operation_get_bounding_box (operation); node->valid_have_rect = TRUE; if (node->cache) { gegl_buffer_set_extent (GEGL_BUFFER (node->cache), &node->have_rect); } g_mutex_unlock (&node->mutex); if (!g_hash_table_contains (path->contexts, node)) { GeglOperationContext *context = gegl_operation_context_new (node->operation); g_hash_table_insert (path->contexts, node, context); } } }
void refresh_images(GeglEditorLayer* self) { return; GSList* pair = self->pairs; for(;pair != NULL; pair = pair->next) { node_id_pair *data = pair->data; /* if(node->image != NULL) cairo_surface_destroy(node->image); //TODO: only destory if it has changed*/ const Babl *cairo_argb32 = babl_format("cairo-ARGB32"); const GeglRectangle roi = gegl_node_get_bounding_box(GEGL_NODE(data->node)); g_print("Rect: %dx%d\n", roi.x, roi.y); if(roi.width == 0 || roi.height == 0) { g_print("Empty rectangle: %s\n", gegl_node_get_operation(GEGL_NODE(data->node))); continue; //skip } gegl_editor_show_node_image(self->editor, data->id); gint stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, roi.width); guchar* buf = malloc(stride*roi.height); //make buffer in memory gegl_node_blit(GEGL_NODE(data->node), 1.0, &roi, cairo_argb32, buf, GEGL_AUTO_ROWSTRIDE, GEGL_BLIT_CACHE); cairo_surface_t* image = cairo_image_surface_create_for_data(buf, CAIRO_FORMAT_ARGB32, roi.width, roi.height, stride); // free(buf); gegl_editor_set_node_image(self->editor, data->id, image); } }
/** * gegl_graph_get_bounding_box: * @path: The traversal path * * Get output bounding box for this graph, which is the * have rect of the final node. * * Return value: Output rect of @path */ GeglRectangle gegl_graph_get_bounding_box (GeglGraphTraversal *path) { GeglNode *node = GEGL_NODE (g_list_last (path->dfs_path)->data); if (node->valid_have_rect) { return node->have_rect; } return *GEGL_RECTANGLE(0, 0, 0, 0); }
static void set_property (GObject *gobject, guint property_id, const GValue *value, GParamSpec *pspec) { GeglCache *self = GEGL_CACHE (gobject); switch (property_id) { case PROP_NODE: g_mutex_lock (self->mutex); if (self->node) { gulong handler; handler = g_signal_handler_find (self->node, G_SIGNAL_MATCH_DATA, g_signal_lookup ("invalidated", GEGL_TYPE_NODE), 0, NULL, NULL, self); if (handler) { g_signal_handler_disconnect (self->node, handler); } } /* just getting the node, the cache holds no reference on the node, * it is the node that holds reference on the cache */ self->node = GEGL_NODE (g_value_get_object (value)); g_signal_connect (G_OBJECT (self->node), "invalidated", G_CALLBACK (node_invalidated), self); g_mutex_unlock (self->mutex); break; case PROP_X: g_object_set_property (gobject, "GeglBuffer::x", value); break; case PROP_Y: g_object_set_property (gobject, "GeglBuffer::y", value); break; case PROP_WIDTH: g_object_set_property (gobject, "GeglBuffer::width", value); break; case PROP_HEIGHT: g_object_set_property (gobject, "GeglBuffer::height", value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, property_id, pspec); break; } }
/* Loading a graph with X child nodes should result in * a GeglNode with X children, where the bottom-most node * is child 0. * * Note: Properties are not tested. */ static void test_load_multiple_nodes (void) { const gchar * const xml = \ "<?xml version='1.0' encoding='UTF-8'?>\n\ <gegl>\n\ <node operation='gegl:invert-linear'>\n\ </node>\n\ <node operation='gegl:crop'>\n\ <params>\n\ <param name='x'>0</param>\n\ <param name='y'>0</param>\n\ <param name='width'>0</param>\n\ <param name='height'>0</param>\n\ </params>\n\ </node>\n\ </gegl>\n"; GeglNode *graph, *node; GSList *children; gchar *op_name; graph = gegl_node_new_from_xml(xml, ""); g_assert(graph); children = gegl_node_get_children(graph); g_assert_cmpuint(g_slist_length(children), ==, 2); node = GEGL_NODE(g_slist_nth_data(children, 0)); gegl_node_get(node, "operation", &op_name, NULL); g_assert_cmpstr(op_name, ==, "gegl:crop"); g_free(op_name); node = GEGL_NODE(g_slist_nth_data(children, 1)); gegl_node_get(node, "operation", &op_name, NULL); g_assert_cmpstr(op_name, ==, "gegl:invert-linear"); g_free(op_name); g_slist_free(children); g_object_unref(graph); }
void layer_set_graph(GeglEditorLayer* self, GeglNode* gegl) { //properly dispose of old gegl graph self->gegl = gegl; gegl_editor_remove_all_nodes(self->editor); GSList *list = gegl_node_get_children(gegl); for(;list != NULL; list = list->next) { GeglNode* node = GEGL_NODE(list->data); g_print("Loading %s\n", gegl_node_get_operation(node)); layer_add_gegl_node(self, node); } list = gegl_node_get_children(gegl); for(list = g_slist_reverse(list); list != NULL; list = list->next) { GeglNode* node = GEGL_NODE(list->data); gint from = get_editor_node_id(self, node); GeglNode** nodes; const gchar** pads; if(!gegl_node_has_pad(node, "output")) { break;} gint num = gegl_node_get_consumers(node, "output", &nodes, &pads); int i; g_print("%s: %d consumer(s)\n", gegl_node_get_operation(node), num); for(i = 0; i < num; i++) { gint to = get_editor_node_id(self, nodes[i]); g_print("Connecting to consumer (%s to %s): output->%s\n", gegl_node_get_operation(node), gegl_node_get_operation(nodes[0]), pads[0]); gegl_editor_add_connection(self->editor, from, to, "output", pads[0]); } } }
static void gegl_introspect_load_cache (GeglProperties *op_introspect) { GeglBuffer *new_buffer = NULL; GeglNode *png_load = NULL; GeglNode *buffer_sink = NULL; gchar *dot_string = NULL; gchar *png_filename = NULL; gchar *dot_filename = NULL; gchar *dot_cmd = NULL; if (op_introspect->user_data || op_introspect->node == NULL) return; /* Construct temp filenames */ dot_filename = g_build_filename (g_get_tmp_dir (), "gegl-introspect.dot", NULL); png_filename = g_build_filename (g_get_tmp_dir (), "gegl-introspect.png", NULL); /* Construct the .dot source */ dot_string = gegl_to_dot (GEGL_NODE (op_introspect->node)); g_file_set_contents (dot_filename, dot_string, -1, NULL); /* Process the .dot to a .png */ dot_cmd = g_strdup_printf ("dot -o %s -Tpng %s", png_filename, dot_filename); if (system (dot_cmd) == -1) g_warning ("Error executing GraphViz dot program"); /* Create a graph that loads the png into a GeglBuffer and process * it */ png_load = gegl_node_new_child (NULL, "operation", "gegl:png-load", "path", png_filename, NULL); buffer_sink = gegl_node_new_child (NULL, "operation", "gegl:buffer-sink", "buffer", &new_buffer, NULL); gegl_node_link_many (png_load, buffer_sink, NULL); gegl_node_process (buffer_sink); op_introspect->user_data= new_buffer; /* Cleanup */ g_object_unref (buffer_sink); g_object_unref (png_load); g_free (dot_string); g_free (dot_cmd); g_free (dot_filename); g_free (png_filename); }
static void photos_print_operation_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { PhotosPrintOperation *self = PHOTOS_PRINT_OPERATION (object); switch (prop_id) { case PROP_ITEM: self->item = PHOTOS_BASE_ITEM (g_value_dup_object (value)); break; case PROP_NODE: self->node = GEGL_NODE (g_value_dup_object (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } }
static void photos_image_view_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { PhotosImageView *self = PHOTOS_IMAGE_VIEW (object); switch (prop_id) { case PROP_NODE: { GeglNode *node; node = GEGL_NODE (g_value_get_object (value)); photos_image_view_set_node (self, node); break; } default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } }
/** * gegl_graph_process: * @path: The traversal path * * Process the prepared request. This will return the * resulting buffer from the final node, or NULL if * that node is a sink. * * If gegl_graph_prepare_request has not been called * the behavior of this function is undefined. * * Return value: (transfer full): The result of the graph, or NULL if * there is no output pad. */ GeglBuffer * gegl_graph_process (GeglGraphTraversal *path, gint level) { GList *list_iter = NULL; GeglBuffer *result = NULL; GeglOperationContext *context = NULL; GeglOperationContext *last_context = NULL; GeglBuffer *operation_result = NULL; for (list_iter = path->dfs_path; list_iter; list_iter = list_iter->next) { GeglNode *node = GEGL_NODE (list_iter->data); GeglOperation *operation = node->operation; g_return_val_if_fail (node, NULL); g_return_val_if_fail (operation, NULL); GEGL_INSTRUMENT_START(); operation_result = NULL; if (last_context) gegl_operation_context_purge (last_context); context = g_hash_table_lookup (path->contexts, node); g_return_val_if_fail (context, NULL); GEGL_NOTE (GEGL_DEBUG_PROCESS, "Will process %s result_rect = %d, %d %d×%d", gegl_node_get_debug_name (node), context->result_rect.x, context->result_rect.y, context->result_rect.width, context->result_rect.height); if (context->need_rect.width > 0 && context->need_rect.height > 0) { if (context->cached) { GEGL_NOTE (GEGL_DEBUG_PROCESS, "Using cached result for %s", gegl_node_get_debug_name (node)); operation_result = GEGL_BUFFER (node->cache); } else { /* provide something on input pad, always - this makes having behavior depending on it not being set.. not work, is sacrifising that worth it? */ if (gegl_node_has_pad (node, "input") && !gegl_operation_context_get_object (context, "input")) { gegl_operation_context_set_object (context, "input", G_OBJECT (gegl_graph_get_shared_empty(path))); } context->level = level; /* note: this hard-coding of "output" makes some more custom * graph topologies harder than neccesary. */ gegl_operation_process (operation, context, "output", &context->need_rect, context->level); operation_result = GEGL_BUFFER (gegl_operation_context_get_object (context, "output")); if (operation_result && operation_result == (GeglBuffer *)operation->node->cache) gegl_cache_computed (operation->node->cache, &context->need_rect, level); } } else { operation_result = NULL; } if (operation_result) { GeglPad *output_pad = gegl_node_get_pad (node, "output"); GList *targets = gegl_graph_get_connected_output_contexts (path, output_pad); GList *targets_iter; GEGL_NOTE (GEGL_DEBUG_PROCESS, "Will deliver the results of %s:%s to %d targets", gegl_node_get_debug_name (node), "output", g_list_length (targets)); if (g_list_length (targets) > 1) gegl_object_set_has_forked (G_OBJECT (operation_result)); for (targets_iter = targets; targets_iter; targets_iter = g_list_next (targets_iter)) { ContextConnection *target_con = targets_iter->data; gegl_operation_context_set_object (target_con->context, target_con->name, G_OBJECT (operation_result)); } g_list_free_full (targets, free_context_connection); } last_context = context; GEGL_INSTRUMENT_END ("process", gegl_node_get_operation (node)); } if (last_context) { if (operation_result) result = g_object_ref (operation_result); else if (gegl_node_has_pad (last_context->operation->node, "output")) result = g_object_ref (gegl_graph_get_shared_empty (path)); gegl_operation_context_purge (last_context); } return result; }
void gegl_graph_prepare_request (GeglGraphTraversal *path, const GeglRectangle *request_roi, gint level) { GList *list_iter = NULL; static const GeglRectangle empty_rect = {0, 0, 0, 0}; g_return_if_fail (path->bfs_path); if (path->rects_dirty) { /* Zero all the needs rects so we can intersect with them below */ for (list_iter = path->bfs_path; list_iter; list_iter = list_iter->next) { GeglNode *node = GEGL_NODE (list_iter->data); GeglOperationContext *context = g_hash_table_lookup (path->contexts, node); /* We only need to reset the need rect, result will always get overwritten */ gegl_operation_context_set_need_rect (context, &empty_rect); /* Reset cached status, because the rect we need may have changed */ context->cached = FALSE; } } path->rects_dirty = TRUE; { /* Prep the first node */ GeglNode *node = GEGL_NODE (path->bfs_path->data); GeglOperationContext *context = g_hash_table_lookup (path->contexts, node); GeglRectangle new_need; g_return_if_fail (context); gegl_rectangle_intersect (&new_need, &node->have_rect, request_roi); gegl_operation_context_set_need_rect (context, &new_need); gegl_operation_context_set_result_rect (context, &new_need); } /* Iterate over all the nodes and propagate the requested rectangle */ for (list_iter = path->bfs_path; list_iter; list_iter = list_iter->next) { GeglNode *node = GEGL_NODE (list_iter->data); GeglOperation *operation = node->operation; GeglOperationContext *context; GeglRectangle *request; GSList *input_pads; context = g_hash_table_lookup (path->contexts, node); g_return_if_fail (context); request = gegl_operation_context_get_need_rect (context); if (request->width == 0 || request->height == 0) { gegl_operation_context_set_result_rect (context, &empty_rect); continue; } if (node->cache) { gint i; for (i = level; i >=0 && !context->cached; i--) { if (gegl_region_rect_in (node->cache->valid_region[level], request) == GEGL_OVERLAP_RECTANGLE_IN) { /* This node is cached and the cache fulfills our need rect */ context->cached = TRUE; gegl_operation_context_set_result_rect (context, &empty_rect); } } if (context->cached) continue; } { /* Expand request if the operation has a minimum processing requirement */ GeglRectangle full_request = gegl_operation_get_cached_region (operation, request); gegl_operation_context_set_need_rect (context, &full_request); /* FIXME: We could trim this down based on the cache, instead of being all or nothing */ gegl_operation_context_set_result_rect (context, request); for (input_pads = node->input_pads; input_pads; input_pads = input_pads->next) { GeglPad *source_pad = gegl_pad_get_connected_to (input_pads->data); if (source_pad) { GeglNode *source_node = gegl_pad_get_node (source_pad); GeglOperationContext *source_context = g_hash_table_lookup (path->contexts, source_node); const gchar *pad_name = gegl_pad_get_name (input_pads->data); GeglRectangle rect, current_need, new_need; /* Combine this need rect with any existing request */ rect = gegl_operation_get_required_for_output (operation, pad_name, &full_request); current_need = *gegl_operation_context_get_need_rect (source_context); gegl_rectangle_bounding_box (&new_need, &rect, ¤t_need); /* Limit request to the nodes output */ gegl_rectangle_intersect (&new_need, &source_node->have_rect, &new_need); gegl_operation_context_set_need_rect (source_context, &new_need); } } } } }