static void gimp_projection_construct_gegl (GimpProjection *proj, gint x, gint y, gint w, gint h) { GeglNode *sink; GeglRectangle rect; sink = gimp_projection_get_sink_node (proj); rect.x = x; rect.y = y; rect.width = w; rect.height = h; if (! proj->processor) proj->processor = gegl_node_new_processor (sink, &rect); else gegl_processor_set_rectangle (proj->processor, &rect); while (gegl_processor_work (proj->processor, NULL)); /* FIXME: Reuse it when it can handle dirty rects when painting * properly */ g_object_unref (proj->processor); proj->processor = NULL; }
static void gimp_cage_tool_compute_coef (GimpCageTool *ct) { GimpCageConfig *config = ct->config; GimpProgress *progress; const Babl *format; GeglNode *gegl; GeglNode *input; GeglNode *output; GeglProcessor *processor; GeglBuffer *buffer; gdouble value; progress = gimp_progress_start (GIMP_PROGRESS (ct), _("Computing Cage Coefficients"), FALSE); if (ct->coef) { g_object_unref (ct->coef); ct->coef = NULL; } format = babl_format_n (babl_type ("float"), gimp_cage_config_get_n_points (config) * 2); gegl = gegl_node_new (); input = gegl_node_new_child (gegl, "operation", "gimp:cage-coef-calc", "config", ct->config, NULL); output = gegl_node_new_child (gegl, "operation", "gegl:buffer-sink", "buffer", &buffer, "format", format, NULL); gegl_node_connect_to (input, "output", output, "input"); processor = gegl_node_new_processor (output, NULL); while (gegl_processor_work (processor, &value)) { if (progress) gimp_progress_set_value (progress, value); } if (progress) gimp_progress_end (progress); g_object_unref (processor); ct->coef = buffer; g_object_unref (gegl); ct->dirty_coef = FALSE; }
void view_helper_set_node(ViewHelper *self, GeglNode *node) { if (self->node == node) return; if (self->node) g_object_unref(self->node); if (node) { g_object_ref(node); self->node = node; g_signal_connect_object(self->node, "computed", G_CALLBACK(computed_event), self, 0); g_signal_connect_object(self->node, "invalidated", G_CALLBACK(invalidated_event), self, 0); if (self->processor) g_object_unref(self->processor); GeglRectangle bbox = gegl_node_get_bounding_box(self->node); self->processor = gegl_node_new_processor(self->node, &bbox); update_autoscale(self); trigger_processing(self, bbox); } else self->node = NULL; }
int dt_dev_pixelpipe_process(dt_dev_pixelpipe_t *pipe, dt_develop_t *dev, int x, int y, int width, int height, float scale) { pipe->processing = 1; printf("pixelpipe process start\n"); // have backbuf in right size: if(pipe->backbuf_size < width*height*4*sizeof(uint8_t)) { pthread_mutex_lock(&pipe->backbuf_mutex); pipe->backbuf_size = width*height*4*sizeof(uint8_t); free(pipe->backbuf); pipe->backbuf = (uint8_t *)dt_alloc_align(16, pipe->backbuf_size); pthread_mutex_unlock(&pipe->backbuf_mutex); } // scale node (is slow): // scale *= 2; // FIXME: this seems to be a bug in gegl. need to manually adjust updated roi here. GeglRectangle roi = (GeglRectangle) { x, y, width, height }; GeglRectangle roio = (GeglRectangle) { roi.x/scale, roi.y/scale, roi.width/scale, roi.height/scale }; roio.x = MAX(0, roio.x); roio.y = MAX(0, roio.y); roio.width = MIN(pipe->iwidth -roio.x-1, roio.width); roio.height = MIN(pipe->iheight-roio.y-1, roio.height); GeglProcessor *processor = gegl_node_new_processor (pipe->output, &roio); // gegl_node_set(pipe->scale, "x", scale, "y", scale, NULL); // GeglProcessor *processor = gegl_node_new_processor (pipe->output, roi); double progress; // TODO: insert constant scale node at beginning, maintain lo-res branch of pipeline (shadowed). // TODO: decide on scale param, which one to use. while (gegl_processor_work (processor, &progress)) { // if history changed, abort processing? if(pipe->changed != DT_DEV_PIPE_UNCHANGED || dev->gui_leaving) return 1; } gegl_processor_destroy (processor); // gegl scale node turned out to be even slower :( gegl_node_blit (pipe->output, scale, &roi, babl_format("RGBA u8"), pipe->backbuf, GEGL_AUTO_ROWSTRIDE, GEGL_BLIT_CACHE); // gegl_node_blit (pipe->output, 1.0, roi, babl_format("RGBA u8"), output, GEGL_AUTO_ROWSTRIDE, GEGL_BLIT_CACHE); // TODO: update histograms here with this data? printf("pixelpipe process end\n"); pipe->processing = 0; return 0; }
static void gimp_drawable_apply_operation_private (GimpDrawable *drawable, GimpProgress *progress, const gchar *undo_desc, GeglNode *operation, gboolean linear, TileManager *dest_tiles, const GeglRectangle *rect) { GeglNode *gegl; GeglNode *input; GeglNode *output; GeglProcessor *processor; gdouble value; gegl = gegl_node_new (); /* Disable caching on all children of the node unless explicitly re-enabled. */ g_object_set (gegl, "dont-cache", TRUE, NULL); input = gegl_node_new_child (gegl, "operation", "gimp:tilemanager-source", "tile-manager", gimp_drawable_get_tiles (drawable), "linear", linear, NULL); output = gegl_node_new_child (gegl, "operation", "gimp:tilemanager-sink", "tile-manager", dest_tiles, "linear", linear, NULL); gegl_node_add_child (gegl, operation); gegl_node_link_many (input, operation, output, NULL); processor = gegl_node_new_processor (output, rect); if (progress) gimp_progress_start (progress, undo_desc, FALSE); while (gegl_processor_work (processor, &value)) if (progress) gimp_progress_set_value (progress, value); g_object_unref (processor); g_object_unref (gegl); }
static void photos_thumbnailer_generate_thumbnail_pixbuf (GObject *source_object, GAsyncResult *res, gpointer user_data) { GCancellable *cancellable; g_autoptr (GTask) task = G_TASK (user_data); g_autoptr (GdkPixbuf) pixbuf = NULL; g_autoptr (GeglBuffer) buffer = NULL; g_autoptr (GeglBuffer) buffer_oriented = NULL; GeglNode *buffer_source; GeglNode *pipeline_node; g_autoptr (GeglProcessor) processor = NULL; PhotosThumbnailerGenerateData *data; cancellable = g_task_get_cancellable (task); data = g_task_get_task_data (task); { g_autoptr (GError) error = NULL; pixbuf = photos_pixbuf_new_from_file_at_size_finish (res, &error); if (error != NULL) { g_task_return_error (task, g_steal_pointer (&error)); goto out; } } buffer = photos_gegl_buffer_new_from_pixbuf (pixbuf); buffer_oriented = photos_gegl_buffer_apply_orientation (buffer, data->orientation); buffer_source = gegl_node_new_child (data->graph, "operation", "gegl:buffer-source", "buffer", buffer_oriented, NULL); pipeline_node = photos_pipeline_get_graph (data->pipeline); gegl_node_link (buffer_source, pipeline_node); processor = gegl_node_new_processor (pipeline_node, NULL); photos_gegl_processor_process_async (processor, cancellable, photos_thumbnailer_generate_thumbnail_process, g_object_ref (task)); out: return; }
static gboolean paint_release (GtkWidget *widget, GdkEventButton *event) { if (event->button == 1) { gdouble x0, x1, y0, y1; GeglProcessor *processor; GeglNode *writebuf; GeglRectangle roi; gegl_path_get_bounds (vector, &x0, &x1, &y0, &y1); roi.x = x0 - LINEWIDTH; roi.y = y0 - LINEWIDTH; roi.width = x1 - x0 + LINEWIDTH * 2; roi.height = y1 - y0 + LINEWIDTH * 2; writebuf = gegl_node_new_child (gegl, "operation", "gegl:write-buffer", "buffer", buffer, NULL); gegl_node_link_many (over, writebuf, NULL); processor = gegl_node_new_processor (writebuf, &roi); while (gegl_processor_work (processor, NULL)) ; gegl_processor_destroy (processor); g_object_unref (writebuf); gegl_node_link_many (top, out, NULL); g_object_unref (over); g_object_unref (stroke); over = NULL; stroke = NULL; pen_down = FALSE; return TRUE; } return FALSE; }
static void gimp_seamless_clone_tool_filter_update (GimpSeamlessCloneTool *sc) { GimpTool *tool = GIMP_TOOL (sc); GimpDisplayShell *shell = gimp_display_get_shell (tool->display); GimpItem *item = GIMP_ITEM (tool->drawable); gint x, y; gint w, h; gint off_x, off_y; GeglRectangle visible; GeglOperation *op = NULL; GimpProgress *progress; GeglNode *output; GeglProcessor *processor; gdouble value; progress = gimp_progress_start (GIMP_PROGRESS (sc), FALSE, _("Cloning the foreground object")); /* Find out at which x,y is the top left corner of the currently * displayed part */ gimp_display_shell_untransform_viewport (shell, &x, &y, &w, &h); /* Find out where is our drawable positioned */ gimp_item_get_offset (item, &off_x, &off_y); /* Create a rectangle from the intersection of the currently displayed * part with the drawable */ gimp_rectangle_intersect (x, y, w, h, off_x, off_y, gimp_item_get_width (item), gimp_item_get_height (item), &visible.x, &visible.y, &visible.width, &visible.height); /* Since the filter_apply function receives a rectangle describing * where it should update the preview, and since that rectangle should * be relative to the drawable's location, we now offset back by the * drawable's offsetts. */ visible.x -= off_x; visible.y -= off_y; g_object_get (sc->sc_node, "gegl-operation", &op, NULL); /* If any cache of the visible area was present, clear it! * We need to clear the cache in the sc_node, since that is * where the previous paste was located */ gegl_operation_invalidate (op, &visible, TRUE); g_object_unref (op); /* Now update the image map and show this area */ gimp_drawable_filter_apply (sc->filter, NULL); /* Show update progress. */ output = gegl_node_get_output_proxy (sc->render_node, "output"); processor = gegl_node_new_processor (output, NULL); while (gegl_processor_work (processor, &value)) { if (progress) gimp_progress_set_value (progress, value); } if (progress) gimp_progress_end (progress); g_object_unref (processor); }
int main(int argc, char *argv[]) { gint result = SUCCESS; GeglRectangle rect1 = { 0, 0, 1, 1 }; GeglRectangle rect2 = { 1, 0, 1, 1 }; GeglRectangle rect3 = { 1, 1, 1, 1 }; GeglRectangle rect4 = { 0, 1, 1, 1 }; GeglColor *color_white = NULL; GeglColor *color_black = NULL; GeglNode *gegl = NULL; GeglNode *white = NULL; GeglNode *translate = NULL; GeglNode *over = NULL; GeglNode *black = NULL; GeglNode *crop = NULL; GeglNode *sink = NULL; GeglProcessor *processor = NULL; /* Convenient line to keep around: g_log_set_always_fatal (G_LOG_LEVEL_WARNING | G_LOG_LEVEL_CRITICAL); */ gegl_init (&argc, &argv); color_white = gegl_color_new ("rgb(1.0, 1.0, 1.0)"); color_black = gegl_color_new ("rgb(0.0, 0.0, 0.0)"); gegl = gegl_node_new (); white = gegl_node_new_child (gegl, "operation", "gegl:color", "value", color_white, NULL); translate = gegl_node_new_child (gegl, "operation", "gegl:translate", "x", -50.0, "y", -20.0, NULL); over = gegl_node_new_child (gegl, "operation", "gegl:over", NULL); black = gegl_node_new_child (gegl, "operation", "gegl:color", "value", color_black, NULL); crop = gegl_node_new_child (gegl, "operation", "gegl:crop", "x", 10.0, "y", 10.0, "width", 100.0, "height", 100.0, NULL); sink = gegl_node_new_child (gegl, "operation", "gegl:buffer-sink", NULL); /* We build our graph for processing complexity, not for compositing * complexity */ gegl_node_link_many (black, over, sink, NULL); gegl_node_link_many (white, crop, translate, NULL); gegl_node_connect_to (translate, "output", over, "aux"); /* Create a processor */ processor = gegl_node_new_processor (sink, NULL); /* Do the tests */ if (!test_change_processor_rect_do_test (processor, &rect1, sink)) { g_printerr ("test-change-processor-rect: First compare failed\n"); result = FAILURE; goto abort; } if (!test_change_processor_rect_do_test (processor, &rect2, sink)) { g_printerr ("test-change-processor-rect: Second compare failed\n"); result = FAILURE; goto abort; } if (!test_change_processor_rect_do_test (processor, &rect3, sink)) { g_printerr ("test-change-processor-rect: Third compare failed\n"); result = FAILURE; goto abort; } if (!test_change_processor_rect_do_test (processor, &rect4, sink)) { g_printerr ("test-change-processor-rect: Fourth compare failed\n"); result = FAILURE; goto abort; } /* Cleanup */ abort: g_object_unref (processor); g_object_unref (color_white); g_object_unref (color_black); g_object_unref (gegl); gegl_exit (); return result; }
void gimp_gegl_apply_operation (GeglBuffer *src_buffer, GimpProgress *progress, const gchar *undo_desc, GeglNode *operation, GeglBuffer *dest_buffer, const GeglRectangle *dest_rect) { GeglNode *gegl; GeglNode *dest_node; GeglRectangle rect = { 0, }; gdouble value; gboolean progress_active = FALSE; g_return_if_fail (src_buffer == NULL || GEGL_IS_BUFFER (src_buffer)); g_return_if_fail (progress == NULL || GIMP_IS_PROGRESS (progress)); g_return_if_fail (GEGL_IS_NODE (operation)); g_return_if_fail (GEGL_IS_BUFFER (dest_buffer)); if (dest_rect) { rect = *dest_rect; } else { rect = *GEGL_RECTANGLE (0, 0, gegl_buffer_get_width (dest_buffer), gegl_buffer_get_height (dest_buffer)); } gegl = gegl_node_new (); if (! gegl_node_get_parent (operation)) gegl_node_add_child (gegl, operation); if (src_buffer && gegl_node_has_pad (operation, "input")) { GeglNode *src_node; /* dup() because reading and writing the same buffer doesn't * work with area ops when using a processor. See bug #701875. */ if (progress && (src_buffer == dest_buffer)) src_buffer = gegl_buffer_dup (src_buffer); else g_object_ref (src_buffer); src_node = gegl_node_new_child (gegl, "operation", "gegl:buffer-source", "buffer", src_buffer, NULL); g_object_unref (src_buffer); gegl_node_connect_to (src_node, "output", operation, "input"); } dest_node = gegl_node_new_child (gegl, "operation", "gegl:write-buffer", "buffer", dest_buffer, NULL); gegl_node_connect_to (operation, "output", dest_node, "input"); if (progress) { GeglProcessor *processor; processor = gegl_node_new_processor (dest_node, &rect); progress_active = gimp_progress_is_active (progress); if (progress_active) { if (undo_desc) gimp_progress_set_text (progress, undo_desc); } else { gimp_progress_start (progress, undo_desc, FALSE); } while (gegl_processor_work (processor, &value)) gimp_progress_set_value (progress, value); g_object_unref (processor); } else { gegl_node_blit (dest_node, 1.0, &rect, NULL, NULL, 0, GEGL_BLIT_DEFAULT); } g_object_unref (gegl); if (progress && ! progress_active) gimp_progress_end (progress); }
int main(int argc, char *argv[]) { gint result = SUCCESS; GeglRectangle rect1 = { 0, 0, 1, 1 }; GeglRectangle rect2 = { 1, 0, 1, 1 }; GeglRectangle rect3 = { 1, 1, 1, 1 }; GeglRectangle rect4 = { 0, 1, 1, 1 }; GeglColor *common_color = NULL; GeglNode *gegl = NULL; GeglNode *color = NULL; GeglNode *layer = NULL; GeglNode *text = NULL; GeglNode *sink = NULL; GeglProcessor *processor = NULL; /* Convenient line to keep around: g_log_set_always_fatal (G_LOG_LEVEL_WARNING | G_LOG_LEVEL_CRITICAL); */ g_thread_init (NULL); gegl_init (&argc, &argv); common_color = gegl_color_new ("rgb(1.0, 1.0, 1.0)"); gegl = gegl_node_new (); color = gegl_node_new_child (gegl, "operation", "gegl:color", "value", common_color, NULL); layer = gegl_node_new_child (gegl, "operation", "gegl:layer", "x", 0.0, "y", 0.0, NULL); text = gegl_node_new_child (gegl, "operation", "gegl:text", "color", common_color, "string", "█████████████████████████", "size", 200.0, NULL); sink = gegl_node_new_child (gegl, "operation", "gegl:buffer-sink", NULL); /* We build our graph for processing complexity, not for compositing * complexity */ gegl_node_link_many (color, layer, sink, NULL); gegl_node_connect_to (text, "output", layer, "aux"); /* Create a processor */ processor = gegl_node_new_processor (sink, NULL); /* Do the tests */ if (!test_change_processor_rect_do_test (processor, &rect1, sink)) { g_printerr ("test-change-processor-rect: First compare failed\n"); result = FAILURE; goto abort; } if (!test_change_processor_rect_do_test (processor, &rect2, sink)) { g_printerr ("test-change-processor-rect: Second compare failed\n"); result = FAILURE; goto abort; } if (!test_change_processor_rect_do_test (processor, &rect3, sink)) { g_printerr ("test-change-processor-rect: Third compare failed\n"); result = FAILURE; goto abort; } if (!test_change_processor_rect_do_test (processor, &rect4, sink)) { g_printerr ("test-change-processor-rect: Fourth compare failed\n"); result = FAILURE; goto abort; } /* Cleanup */ abort: g_object_unref (processor); g_object_unref (common_color); g_object_unref (gegl); gegl_exit (); return result; }
static void gimp_foreground_select_tool_preview (GimpForegroundSelectTool *fg_select, GimpDisplay *display) { GimpTool *tool = GIMP_TOOL (fg_select); GimpForegroundSelectOptions *options = GIMP_FOREGROUND_SELECT_TOOL_GET_OPTIONS (tool); GimpImage *image = gimp_display_get_image (display); GimpDrawable *drawable = gimp_image_get_active_drawable (image); GeglBuffer *trimap_buffer; GeglBuffer *drawable_buffer; GeglNode *gegl; GeglNode *matting_node; GeglNode *input_image; GeglNode *input_trimap; GeglNode *output_mask; GeglBuffer *buffer; GimpProgress *progress; GeglProcessor *processor; gdouble value; if (fg_select->mask) { g_object_unref (fg_select->mask); fg_select->mask = NULL; } progress = gimp_progress_start (GIMP_PROGRESS (fg_select), _("Computing alpha of unknown pixels"), FALSE); trimap_buffer = fg_select->trimap; drawable_buffer = gimp_drawable_get_buffer (drawable); gegl = gegl_node_new (); input_trimap = gegl_node_new_child (gegl, "operation", "gegl:buffer-source", "buffer", trimap_buffer, NULL); input_image = gegl_node_new_child (gegl, "operation", "gegl:buffer-source", "buffer", drawable_buffer, NULL); output_mask = gegl_node_new_child (gegl, "operation", "gegl:buffer-sink", "buffer", &buffer, "format", NULL, NULL); if (options->engine == GIMP_MATTING_ENGINE_GLOBAL) { matting_node = gegl_node_new_child (gegl, "operation", "gegl:matting-global", "iterations", options->iterations, NULL); } else { matting_node = gegl_node_new_child (gegl, "operation", "gegl:matting-levin", "levels", options->levels, "active_levels", options->active_levels, NULL); } gegl_node_connect_to (input_image, "output", matting_node, "input"); gegl_node_connect_to (input_trimap, "output", matting_node, "aux"); gegl_node_connect_to (matting_node, "output", output_mask, "input"); processor = gegl_node_new_processor (output_mask, NULL); while (gegl_processor_work (processor, &value)) { if (progress) gimp_progress_set_value (progress, value); } if (progress) gimp_progress_end (progress); g_object_unref (processor); fg_select->mask = buffer; gimp_foreground_select_tool_set_preview (fg_select, display); g_object_unref (gegl); }
GimpApplicator * gimp_applicator_new (GeglBuffer *dest_buffer, GimpComponentMask affect, GeglBuffer *mask_buffer, gint mask_offset_x, gint mask_offset_y) { GimpApplicator *applicator; g_return_val_if_fail (GEGL_IS_BUFFER (dest_buffer), NULL); g_return_val_if_fail (mask_buffer == NULL || GEGL_IS_BUFFER (mask_buffer), NULL); applicator = g_object_new (GIMP_TYPE_APPLICATOR, NULL); applicator->node = gegl_node_new (); applicator->mode_node = gegl_node_new_child (applicator->node, "operation", "gimp:normal-mode", NULL); applicator->src_node = gegl_node_new_child (applicator->node, "operation", "gegl:buffer-source", NULL); gegl_node_connect_to (applicator->src_node, "output", applicator->mode_node, "input"); applicator->apply_src_node = gegl_node_new_child (applicator->node, "operation", "gegl:buffer-source", NULL); applicator->apply_offset_node = gegl_node_new_child (applicator->node, "operation", "gegl:translate", NULL); gegl_node_connect_to (applicator->apply_src_node, "output", applicator->apply_offset_node, "input"); gegl_node_connect_to (applicator->apply_offset_node, "output", applicator->mode_node, "aux"); if (mask_buffer) { GeglNode *mask_src; mask_src = gegl_node_new_child (applicator->node, "operation", "gegl:buffer-source", "buffer", mask_buffer, NULL); if (mask_offset_x != 0 || mask_offset_y != 0) { GeglNode *offset; offset = gegl_node_new_child (applicator->node, "operation", "gegl:translate", "x", (gdouble) mask_offset_x, "y", (gdouble) mask_offset_y, NULL); gegl_node_connect_to (mask_src, "output", offset, "input"); gegl_node_connect_to (offset, "output", applicator->mode_node, "aux2"); } else { gegl_node_connect_to (mask_src, "output", applicator->mode_node, "aux2"); } } applicator->dest_node = gegl_node_new_child (applicator->node, "operation", "gegl:write-buffer", "buffer", dest_buffer, "flush", FALSE, NULL); if (affect == GIMP_COMPONENT_ALL) { gegl_node_connect_to (applicator->mode_node, "output", applicator->dest_node, "input"); } else { GeglNode *affect_node; affect_node = gegl_node_new_child (applicator->node, "operation", "gimp:mask-components", "mask", affect, NULL); gegl_node_connect_to (applicator->src_node, "output", affect_node, "input"); gegl_node_connect_to (applicator->mode_node, "output", affect_node, "aux"); gegl_node_connect_to (affect_node, "output", applicator->dest_node, "input"); } applicator->processor = gegl_node_new_processor (applicator->dest_node, NULL); return applicator; }
GeglBuffer * gimp_drawable_foreground_extract (GimpDrawable *drawable, GimpMattingEngine engine, gint global_iterations, gint levin_levels, gint levin_active_levels, GeglBuffer *trimap, GimpProgress *progress) { GeglBuffer *drawable_buffer; GeglNode *gegl; GeglNode *input_node; GeglNode *trimap_node; GeglNode *matting_node; GeglNode *output_node; GeglBuffer *buffer; GeglProcessor *processor; gdouble value; g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), NULL); g_return_val_if_fail (GEGL_IS_BUFFER (trimap), NULL); g_return_val_if_fail (progress == NULL || GIMP_IS_PROGRESS (progress), NULL); progress = gimp_progress_start (progress, FALSE, _("Computing alpha of unknown pixels")); drawable_buffer = gimp_drawable_get_buffer (drawable); gegl = gegl_node_new (); trimap_node = gegl_node_new_child (gegl, "operation", "gegl:buffer-source", "buffer", trimap, NULL); input_node = gegl_node_new_child (gegl, "operation", "gegl:buffer-source", "buffer", drawable_buffer, NULL); output_node = gegl_node_new_child (gegl, "operation", "gegl:buffer-sink", "buffer", &buffer, "format", NULL, NULL); if (engine == GIMP_MATTING_ENGINE_GLOBAL) { matting_node = gegl_node_new_child (gegl, "operation", "gegl:matting-global", "iterations", global_iterations, NULL); } else { matting_node = gegl_node_new_child (gegl, "operation", "gegl:matting-levin", "levels", levin_levels, "active_levels", levin_active_levels, NULL); } gegl_node_connect_to (input_node, "output", matting_node, "input"); gegl_node_connect_to (trimap_node, "output", matting_node, "aux"); gegl_node_connect_to (matting_node, "output", output_node, "input"); processor = gegl_node_new_processor (output_node, NULL); while (gegl_processor_work (processor, &value)) { if (progress) gimp_progress_set_value (progress, value); } if (progress) gimp_progress_end (progress); g_object_unref (processor); g_object_unref (gegl); return buffer; }
gboolean gimp_gegl_apply_cached_operation (GeglBuffer *src_buffer, GimpProgress *progress, const gchar *undo_desc, GeglNode *operation, GeglBuffer *dest_buffer, const GeglRectangle *dest_rect, GeglBuffer *cache, const GeglRectangle *valid_rects, gint n_valid_rects, gboolean cancellable) { GeglNode *gegl; GeglNode *dest_node; GeglRectangle rect = { 0, }; GeglProcessor *processor = NULL; gboolean progress_started = FALSE; gdouble value; gboolean cancel = FALSE; g_return_val_if_fail (src_buffer == NULL || GEGL_IS_BUFFER (src_buffer), FALSE); g_return_val_if_fail (progress == NULL || GIMP_IS_PROGRESS (progress), FALSE); g_return_val_if_fail (GEGL_IS_NODE (operation), FALSE); g_return_val_if_fail (GEGL_IS_BUFFER (dest_buffer), FALSE); g_return_val_if_fail (cache == NULL || GEGL_IS_BUFFER (cache), FALSE); g_return_val_if_fail (valid_rects == NULL || cache != NULL, FALSE); g_return_val_if_fail (valid_rects == NULL || n_valid_rects != 0, FALSE); if (dest_rect) { rect = *dest_rect; } else { rect = *GEGL_RECTANGLE (0, 0, gegl_buffer_get_width (dest_buffer), gegl_buffer_get_height (dest_buffer)); } gegl = gegl_node_new (); if (! gegl_node_get_parent (operation)) gegl_node_add_child (gegl, operation); if (src_buffer && gegl_node_has_pad (operation, "input")) { GeglNode *src_node; /* dup() because reading and writing the same buffer doesn't * work with area ops when using a processor. See bug #701875. */ if (progress && (src_buffer == dest_buffer)) src_buffer = gegl_buffer_dup (src_buffer); else g_object_ref (src_buffer); src_node = gegl_node_new_child (gegl, "operation", "gegl:buffer-source", "buffer", src_buffer, NULL); g_object_unref (src_buffer); gegl_node_connect_to (src_node, "output", operation, "input"); } dest_node = gegl_node_new_child (gegl, "operation", "gegl:write-buffer", "buffer", dest_buffer, NULL); gegl_node_connect_to (operation, "output", dest_node, "input"); if (progress) { processor = gegl_node_new_processor (dest_node, &rect); if (gimp_progress_is_active (progress)) { if (undo_desc) gimp_progress_set_text_literal (progress, undo_desc); progress_started = FALSE; cancellable = FALSE; } else { gimp_progress_start (progress, cancellable, "%s", undo_desc); if (cancellable) g_signal_connect (progress, "cancel", G_CALLBACK (gimp_gegl_apply_operation_cancel), &cancel); progress_started = TRUE; } } if (cache) { cairo_region_t *region; gint all_pixels; gint done_pixels = 0; gint n_rects; gint i; region = cairo_region_create_rectangle ((cairo_rectangle_int_t *) &rect); all_pixels = rect.width * rect.height; for (i = 0; i < n_valid_rects; i++) { gegl_buffer_copy (cache, valid_rects + i, GEGL_ABYSS_NONE, dest_buffer, valid_rects + i); cairo_region_subtract_rectangle (region, (cairo_rectangle_int_t *) valid_rects + i); done_pixels += valid_rects[i].width * valid_rects[i].height; if (progress) gimp_progress_set_value (progress, (gdouble) done_pixels / (gdouble) all_pixels); } n_rects = cairo_region_num_rectangles (region); for (i = 0; ! cancel && (i < n_rects); i++) { cairo_rectangle_int_t render_rect; cairo_region_get_rectangle (region, i, &render_rect); if (progress) { gint rect_pixels = render_rect.width * render_rect.height; #ifdef REUSE_PROCESSOR gegl_processor_set_rectangle (processor, (GeglRectangle *) &render_rect); #else g_object_unref (processor); processor = gegl_node_new_processor (dest_node, (GeglRectangle *) &render_rect); #endif while (! cancel && gegl_processor_work (processor, &value)) { gimp_progress_set_value (progress, ((gdouble) done_pixels + value * rect_pixels) / (gdouble) all_pixels); if (cancellable) while (! cancel && g_main_context_pending (NULL)) g_main_context_iteration (NULL, FALSE); } done_pixels += rect_pixels; } else { gegl_node_blit (dest_node, 1.0, (GeglRectangle *) &render_rect, NULL, NULL, 0, GEGL_BLIT_DEFAULT); } } cairo_region_destroy (region); } else { if (progress) { while (! cancel && gegl_processor_work (processor, &value)) { gimp_progress_set_value (progress, value); if (cancellable) while (! cancel && g_main_context_pending (NULL)) g_main_context_iteration (NULL, FALSE); } } else { gegl_node_blit (dest_node, 1.0, &rect, NULL, NULL, 0, GEGL_BLIT_DEFAULT); } } if (processor) g_object_unref (processor); g_object_unref (gegl); if (progress_started) { gimp_progress_end (progress); if (cancellable) g_signal_handlers_disconnect_by_func (progress, gimp_gegl_apply_operation_cancel, &cancel); } return ! cancel; }