void gimp_gegl_apply_set_alpha (GeglBuffer *src_buffer, GimpProgress *progress, const gchar *undo_desc, GeglBuffer *dest_buffer, gdouble value) { GeglNode *node; g_return_if_fail (GEGL_IS_BUFFER (src_buffer)); g_return_if_fail (progress == NULL || GIMP_IS_PROGRESS (progress)); g_return_if_fail (GEGL_IS_BUFFER (dest_buffer)); node = gegl_node_new_child (NULL, "operation", "gimp:set-alpha", "value", value, NULL); gimp_gegl_apply_operation (src_buffer, progress, undo_desc, node, dest_buffer, NULL); g_object_unref (node); }
GeglNode * gimp_gegl_create_apply_opacity_node (GeglBuffer *mask, gint mask_offset_x, gint mask_offset_y, gdouble opacity) { GeglNode *node; GeglNode *input; GeglNode *output; GeglNode *opacity_node; GeglNode *mask_source; g_return_val_if_fail (GEGL_IS_BUFFER (mask), NULL); node = gegl_node_new (); input = gegl_node_get_input_proxy (node, "input"); output = gegl_node_get_output_proxy (node, "output"); opacity_node = gegl_node_new_child (node, "operation", "gegl:opacity", "value", opacity, NULL); mask_source = gimp_gegl_add_buffer_source (node, mask, mask_offset_x, mask_offset_y); gegl_node_connect_to (input, "output", opacity_node, "input"); gegl_node_connect_to (mask_source, "output", opacity_node, "aux"); gegl_node_connect_to (opacity_node, "output", output, "input"); return node; }
void gimp_gegl_apply_gaussian_blur (GeglBuffer *src_buffer, GimpProgress *progress, const gchar *undo_desc, GeglBuffer *dest_buffer, gdouble std_dev_x, gdouble std_dev_y) { GeglNode *node; g_return_if_fail (GEGL_IS_BUFFER (src_buffer)); g_return_if_fail (progress == NULL || GIMP_IS_PROGRESS (progress)); g_return_if_fail (GEGL_IS_BUFFER (dest_buffer)); node = gegl_node_new_child (NULL, "operation", "gegl:gaussian-blur", "std-dev-x", std_dev_x, "std-dev-y", std_dev_y, NULL); gimp_gegl_apply_operation (src_buffer, progress, undo_desc, node, dest_buffer, NULL); g_object_unref (node); }
/* in attach we hook into graph adding the needed nodes */ static void attach (GeglOperation *operation) { GeglNode *gegl = operation->node; GeglNode *input, *output, *over, *translate, *opacity, *blur, *darken, *color; GeglColor *black_color = gegl_color_new ("rgb(0.0,0.0,0.0)"); input = gegl_node_get_input_proxy (gegl, "input"); output = gegl_node_get_output_proxy (gegl, "output"); over = gegl_node_new_child (gegl, "operation", "gegl:over", NULL); translate = gegl_node_new_child (gegl, "operation", "gegl:translate", NULL); opacity = gegl_node_new_child (gegl, "operation", "gegl:opacity", NULL); blur = gegl_node_new_child (gegl, "operation", "gegl:gaussian-blur", "clip-extent", FALSE, "abyss-policy", 0, NULL); darken = gegl_node_new_child (gegl, "operation", "gegl:src-in", NULL); color = gegl_node_new_child (gegl, "operation", "gegl:color", "value", black_color, NULL); g_object_unref (black_color); gegl_node_link_many (input, darken, blur, opacity, translate, over, output, NULL); gegl_node_connect_from (over, "aux", input, "output"); gegl_node_connect_from (darken, "aux", color, "output"); gegl_operation_meta_redirect (operation, "radius", blur, "std-dev-x"); gegl_operation_meta_redirect (operation, "radius", blur, "std-dev-y"); gegl_operation_meta_redirect (operation, "x", translate, "x"); gegl_operation_meta_redirect (operation, "y", translate, "y"); gegl_operation_meta_redirect (operation, "color", color, "value"); gegl_operation_meta_redirect (operation, "opacity", opacity, "value"); gegl_operation_meta_watch_nodes (operation, over, translate, opacity, blur, darken, color, NULL); }
/** * gimp_drawable_get_line_art_fill_buffer: * @drawable: the #GimpDrawable to edit. * @line_art: the #GimpLineArt computed as fill source. * @options: the #GimpFillOptions. * @sample_merged: * @seed_x: X coordinate to start the fill. * @seed_y: Y coordinate to start the fill. * @mask_buffer: mask of the fill in-progress when in an interactive * filling process. Set to NULL if you need a one-time * fill. * @mask_x: returned x bound of @mask_buffer. * @mask_y: returned x bound of @mask_buffer. * @mask_width: returned width bound of @mask_buffer. * @mask_height: returned height bound of @mask_buffer. * * Creates the fill buffer for a bucket fill operation on @drawable * based on @line_art and @options, without actually applying it. * If @mask_buffer is not NULL, the intermediate fill mask will also be * returned. This fill mask can later be reused in successive calls to * gimp_drawable_get_bucket_fill_buffer() for interactive filling. * * Returns: a fill buffer which can be directly applied to @drawable, or * used in a drawable filter as preview. */ GeglBuffer * gimp_drawable_get_line_art_fill_buffer (GimpDrawable *drawable, GimpLineArt *line_art, GimpFillOptions *options, gboolean sample_merged, gdouble seed_x, gdouble seed_y, GeglBuffer **mask_buffer, gdouble *mask_x, gdouble *mask_y, gint *mask_width, gint *mask_height) { GimpImage *image; GeglBuffer *buffer; GeglBuffer *new_mask; gint x, y, width, height; gint mask_offset_x = 0; gint mask_offset_y = 0; gint sel_x, sel_y, sel_width, sel_height; g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), NULL); g_return_val_if_fail (gimp_item_is_attached (GIMP_ITEM (drawable)), NULL); g_return_val_if_fail (GIMP_IS_FILL_OPTIONS (options), NULL); image = gimp_item_get_image (GIMP_ITEM (drawable)); if (! gimp_item_mask_intersect (GIMP_ITEM (drawable), &sel_x, &sel_y, &sel_width, &sel_height)) return NULL; if (mask_buffer && *mask_buffer) { gfloat pixel; gegl_buffer_sample (*mask_buffer, seed_x, seed_y, NULL, &pixel, babl_format ("Y float"), GEGL_SAMPLER_NEAREST, GEGL_ABYSS_NONE); if (pixel != 0.0) /* Already selected. This seed won't change the selection. */ return NULL; } gimp_set_busy (image->gimp); /* Do a seed bucket fill...To do this, calculate a new * contiguous region. */ new_mask = gimp_pickable_contiguous_region_by_line_art (NULL, line_art, (gint) seed_x, (gint) seed_y); if (mask_buffer && *mask_buffer) { gimp_gegl_mask_combine_buffer (new_mask, *mask_buffer, GIMP_CHANNEL_OP_ADD, 0, 0); g_object_unref (*mask_buffer); } if (mask_buffer) *mask_buffer = new_mask; gimp_gegl_mask_bounds (new_mask, &x, &y, &width, &height); width -= x; height -= y; /* If there is a selection, intersect the region bounds * with the selection bounds, to avoid processing areas * that are going to be masked out anyway. The actual * intersection of the fill region with the mask data * happens when combining the fill buffer, in * gimp_drawable_apply_buffer(). */ if (! gimp_channel_is_empty (gimp_image_get_mask (image))) { gint off_x = 0; gint off_y = 0; if (sample_merged) gimp_item_get_offset (GIMP_ITEM (drawable), &off_x, &off_y); if (! gimp_rectangle_intersect (x, y, width, height, sel_x + off_x, sel_y + off_y, sel_width, sel_height, &x, &y, &width, &height)) { if (! mask_buffer) g_object_unref (new_mask); /* The fill region and the selection are disjoint; bail. */ gimp_unset_busy (image->gimp); return NULL; } } /* make sure we handle the mask correctly if it was sample-merged */ if (sample_merged) { GimpItem *item = GIMP_ITEM (drawable); gint off_x, off_y; /* Limit the channel bounds to the drawable's extents */ gimp_item_get_offset (item, &off_x, &off_y); gimp_rectangle_intersect (x, y, width, height, off_x, off_y, gimp_item_get_width (item), gimp_item_get_height (item), &x, &y, &width, &height); mask_offset_x = x; mask_offset_y = y; /* translate mask bounds to drawable coords */ x -= off_x; y -= off_y; } else { mask_offset_x = x; mask_offset_y = y; } buffer = gimp_fill_options_create_buffer (options, drawable, GEGL_RECTANGLE (0, 0, width, height), -x, -y); gimp_gegl_apply_opacity (buffer, NULL, NULL, buffer, new_mask, -mask_offset_x, -mask_offset_y, 1.0); if (gimp_fill_options_get_antialias (options)) { /* Antialias for the line art algorithm is not applied during mask * creation because it is not based on individual pixel colors. * Instead we just want to apply it on the borders of the mask at * the end (since the mask can evolve, we don't want to actually * touch it, but only the intermediate results). */ GeglNode *graph; GeglNode *input; GeglNode *op; graph = gegl_node_new (); input = gegl_node_new_child (graph, "operation", "gegl:buffer-source", "buffer", buffer, NULL); op = gegl_node_new_child (graph, "operation", "gegl:gaussian-blur", "std-dev-x", 0.5, "std-dev-y", 0.5, NULL); gegl_node_connect_to (input, "output", op, "input"); gegl_node_blit_buffer (op, buffer, NULL, 0, GEGL_ABYSS_NONE); g_object_unref (graph); } if (mask_x) *mask_x = x; if (mask_y) *mask_y = y; if (mask_width) *mask_width = width; if (mask_height) *mask_height = height; if (! mask_buffer) g_object_unref (new_mask); gimp_unset_busy (image->gimp); return buffer; }
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); }
static void gimp_perspective_clone_paint (GimpPaintCore *paint_core, GimpDrawable *drawable, GimpPaintOptions *paint_options, const GimpCoords *coords, GimpPaintState paint_state, guint32 time) { GimpSourceCore *source_core = GIMP_SOURCE_CORE (paint_core); GimpPerspectiveClone *clone = GIMP_PERSPECTIVE_CLONE (paint_core); GimpContext *context = GIMP_CONTEXT (paint_options); GimpCloneOptions *clone_options = GIMP_CLONE_OPTIONS (paint_options); GimpSourceOptions *options = GIMP_SOURCE_OPTIONS (paint_options); switch (paint_state) { case GIMP_PAINT_STATE_INIT: if (source_core->set_source) { g_object_set (source_core, "src-drawable", drawable, NULL); source_core->src_x = coords->x; source_core->src_y = coords->y; /* get source coordinates in front view perspective */ gimp_matrix3_transform_point (&clone->transform_inv, source_core->src_x, source_core->src_y, &clone->src_x_fv, &clone->src_y_fv); source_core->first_stroke = TRUE; } else { GeglBuffer *orig_buffer = NULL; GeglNode *tile = NULL; GeglNode *src_node; if (options->align_mode == GIMP_SOURCE_ALIGN_NO) { source_core->orig_src_x = source_core->src_x; source_core->orig_src_y = source_core->src_y; source_core->first_stroke = TRUE; } clone->node = gegl_node_new (); g_object_set (clone->node, "dont-cache", TRUE, NULL); switch (clone_options->clone_type) { case GIMP_IMAGE_CLONE: { GimpPickable *src_pickable; GimpImage *src_image; GimpImage *dest_image; /* If the source image is different from the * destination, then we should copy straight from the * source image to the canvas. * Otherwise, we need a call to get_orig_image to make sure * we get a copy of the unblemished (offset) image */ src_pickable = GIMP_PICKABLE (source_core->src_drawable); src_image = gimp_pickable_get_image (src_pickable); if (options->sample_merged) src_pickable = GIMP_PICKABLE (gimp_image_get_projection (src_image)); dest_image = gimp_item_get_image (GIMP_ITEM (drawable)); if ((options->sample_merged && (src_image != dest_image)) || (! options->sample_merged && (source_core->src_drawable != drawable))) { orig_buffer = gimp_pickable_get_buffer (src_pickable); } else { if (options->sample_merged) orig_buffer = gimp_paint_core_get_orig_proj (paint_core); else orig_buffer = gimp_paint_core_get_orig_image (paint_core); } } break; case GIMP_PATTERN_CLONE: { GimpPattern *pattern = gimp_context_get_pattern (context); orig_buffer = gimp_pattern_create_buffer (pattern); tile = gegl_node_new_child (clone->node, "operation", "gegl:tile", NULL); clone->crop = gegl_node_new_child (clone->node, "operation", "gegl:crop", NULL); } break; } src_node = gegl_node_new_child (clone->node, "operation", "gegl:buffer-source", "buffer", orig_buffer, NULL); clone->transform_node = gegl_node_new_child (clone->node, "operation", "gegl:transform", "sampler", GIMP_INTERPOLATION_LINEAR, NULL); clone->dest_node = gegl_node_new_child (clone->node, "operation", "gegl:write-buffer", NULL); if (tile) { gegl_node_link_many (src_node, tile, clone->crop, clone->transform_node, clone->dest_node, NULL); g_object_unref (orig_buffer); } else { gegl_node_link_many (src_node, clone->transform_node, clone->dest_node, NULL); } } break; case GIMP_PAINT_STATE_MOTION: if (source_core->set_source) { /* If the control key is down, move the src target and return */ source_core->src_x = coords->x; source_core->src_y = coords->y; /* get source coordinates in front view perspective */ gimp_matrix3_transform_point (&clone->transform_inv, source_core->src_x, source_core->src_y, &clone->src_x_fv, &clone->src_y_fv); source_core->first_stroke = TRUE; } else { /* otherwise, update the target */ gint dest_x; gint dest_y; dest_x = coords->x; dest_y = coords->y; if (options->align_mode == GIMP_SOURCE_ALIGN_REGISTERED) { source_core->offset_x = 0; source_core->offset_y = 0; } else if (options->align_mode == GIMP_SOURCE_ALIGN_FIXED) { source_core->offset_x = source_core->src_x - dest_x; source_core->offset_y = source_core->src_y - dest_y; } else if (source_core->first_stroke) { source_core->offset_x = source_core->src_x - dest_x; source_core->offset_y = source_core->src_y - dest_y; /* get destination coordinates in front view perspective */ gimp_matrix3_transform_point (&clone->transform_inv, dest_x, dest_y, &clone->dest_x_fv, &clone->dest_y_fv); source_core->first_stroke = FALSE; } gimp_source_core_motion (source_core, drawable, paint_options, coords); } break; case GIMP_PAINT_STATE_FINISH: if (clone->node) { g_object_unref (clone->node); clone->node = NULL; clone->crop = NULL; clone->transform_node = NULL; clone->dest_node = NULL; } break; default: break; } g_object_notify (G_OBJECT (clone), "src-x"); g_object_notify (G_OBJECT (clone), "src-y"); }
gint main (gint argc, gchar **argv) { GeglNode *gegl, *imgA, *imgB, *comparison; GeglRectangle boundsA, boundsB; gdouble max_diff, avg_diff_wrong, avg_diff_total; gint wrong_pixels, total_pixels; gegl_init (&argc, &argv); if (argc != 3) { g_print ("This is simple image difference detection tool for use in regression testing.\n" "Exit code is non zero if images are different, if they are equal" "the output will contain the string identical.\n"); g_print ("Usage: %s <imageA> <imageB>\n", argv[0]); return ERROR_WRONG_ARGUMENTS; } gegl = gegl_node_new (); imgA = gegl_node_new_child (gegl, "operation", "gegl:load", "path", argv[1], NULL); imgB = gegl_node_new_child (gegl, "operation", "gegl:load", "path", argv[2], NULL); boundsA = gegl_node_get_bounding_box (imgA); boundsB = gegl_node_get_bounding_box (imgB); total_pixels = boundsA.width * boundsA.height; if (boundsA.width != boundsB.width || boundsA.height != boundsB.height) { g_printerr ("%s and %s differ in size\n", argv[1], argv[2]); g_printerr (" %ix%i vs %ix%i\n", boundsA.width, boundsA.height, boundsB.width, boundsB.height); return ERROR_WRONG_SIZE; } comparison = gegl_node_create_child (gegl, "gegl:image-compare"); gegl_node_link (imgA, comparison); gegl_node_connect_to (imgB, "output", comparison, "aux"); gegl_node_process (comparison); gegl_node_get (comparison, "max diff", &max_diff, "avg-diff-wrong", &avg_diff_wrong, "avg-diff-total", &avg_diff_total, "wrong-pixels", &wrong_pixels, NULL); if (max_diff >= 0.1) { g_printerr ("%s and %s differ\n" " wrong pixels : %i/%i (%2.2f%%)\n" " max Δe : %2.3f\n" " avg Δe (wrong) : %2.3f(wrong) %2.3f(total)\n", argv[1], argv[2], wrong_pixels, total_pixels, (wrong_pixels*100.0/total_pixels), max_diff, avg_diff_wrong, avg_diff_total); if (!strstr (argv[2], "broken")) { GeglNode *save; gchar *debug_path = g_malloc (strlen (argv[2])+16); memcpy (debug_path, argv[2], strlen (argv[2])+1); memcpy (debug_path + strlen(argv[2])-4, "-diff.png", 11); save = gegl_node_new_child (gegl, "operation", "gegl:png-save", "path", debug_path, NULL); gegl_node_link (comparison, save); gegl_node_process (save); /*gegl_graph (sink=gegl_node ("gegl:png-save", "path", debug_path, NULL, gegl_node ("gegl:buffer-source", "buffer", debug_buf, NULL)));*/ if (max_diff > 1.5) return ERROR_PIXELS_DIFFERENT; } if (strstr (argv[2], "broken")) g_print ("because the test is expected to fail "); else g_print ("because the error is small "); g_print ("we'll say "); } g_print ("%s and %s are identical\n", argv[1], argv[2]); g_object_unref (gegl); gegl_exit (); return SUCCESS; }
static void attach (GeglOperation *operation) { JsonOp *self = (JsonOp *)operation; GeglNode *gegl = operation->node; JsonArray *connections; GList *l; // Processes JsonObject *root = self->json_root; JsonObject *processes = json_object_get_object_member(root, "processes"); GList *process_names = json_object_get_members(processes); for (l = process_names; l != NULL; l = l->next) { const gchar *name = l->data; JsonObject *proc = json_object_get_object_member(processes, name); const gchar *component = json_object_get_string_member(proc, "component"); gchar *opname = component2geglop(component); GeglNode *node = gegl_node_new_child (gegl, "operation", opname, NULL); gegl_operation_meta_watch_node (operation, node); g_assert(node); g_hash_table_insert(self->nodes, (gpointer)g_strdup(name), (gpointer)node); g_free(opname); } g_list_free(process_names); // Connections connections = json_object_get_array_member(root, "connections"); g_assert(connections); for (int i=0; i<json_array_get_length(connections); i++) { JsonObject *conn = json_array_get_object_element(connections, i); JsonObject *tgt = json_object_get_object_member(conn, "tgt"); const gchar *tgt_proc = json_object_get_string_member(tgt, "process"); const gchar *tgt_port = json_object_get_string_member(tgt, "port"); GeglNode *tgt_node = g_hash_table_lookup(self->nodes, tgt_proc); JsonNode *srcnode; g_assert(tgt_node); srcnode = json_object_get_member(conn, "src"); if (srcnode) { // Connection JsonObject *src = json_object_get_object_member(conn, "src"); const gchar *src_proc = json_object_get_string_member(src, "process"); const gchar *src_port = json_object_get_string_member(src, "port"); GeglNode *src_node = g_hash_table_lookup(self->nodes, src_proc); g_assert(src_node); gegl_node_connect_to (src_node, src_port, tgt_node, tgt_port); } else { // IIP JsonNode *datanode = json_object_get_member(conn, "data"); GValue value = G_VALUE_INIT; GParamSpec *paramspec; g_assert(JSON_NODE_HOLDS_VALUE(datanode)); json_node_get_value(datanode, &value); paramspec = gegl_node_find_property(tgt_node, tgt_port); set_prop(tgt_node, tgt_port, paramspec, &value); g_value_unset(&value); } } // Exported ports if (json_object_has_member(root, "inports")) { JsonObject *inports = json_object_get_object_member(root, "inports"); GList *inport_names = json_object_get_members(inports); for (l = inport_names; l != NULL; l = l->next) { const gchar *name = l->data; JsonObject *conn = json_object_get_object_member(inports, name); const gchar *proc = json_object_get_string_member(conn, "process"); const gchar *port = json_object_get_string_member(conn, "port"); GeglNode *node = g_hash_table_lookup(self->nodes, proc); g_assert(node); if (g_strcmp0(name, "input") == 0) { GeglNode *input = gegl_node_get_input_proxy (gegl, "input"); gegl_node_connect_to (input, "output", node, "input"); } else { gegl_operation_meta_redirect (operation, name, node, port); } } g_list_free(inport_names); } if (json_object_has_member(root, "outports")) { JsonObject *outports = json_object_get_object_member(root, "outports"); GList *outport_names = json_object_get_members(outports); for (l = outport_names; l != NULL; l = l->next) { const gchar *name = l->data; JsonObject *conn = json_object_get_object_member(outports, name); const gchar *proc = json_object_get_string_member(conn, "process"); const gchar *port = json_object_get_string_member(conn, "port"); GeglNode *node = g_hash_table_lookup(self->nodes, proc); g_assert(node); if (g_strcmp0(name, "output") == 0) { GeglNode *proxy = gegl_node_get_output_proxy (gegl, "output"); gegl_node_connect_to (node, port, proxy, "input"); } else { g_warning("Unsupported output '%s' exported in .json file", name); } } g_list_free(outport_names); } }
GeglBuffer * gimp_drawable_transform_buffer_affine (GimpDrawable *drawable, GimpContext *context, GeglBuffer *orig_buffer, gint orig_offset_x, gint orig_offset_y, const GimpMatrix3 *matrix, GimpTransformDirection direction, GimpInterpolationType interpolation_type, gint recursion_level, GimpTransformResize clip_result, gint *new_offset_x, gint *new_offset_y, GimpProgress *progress) { GeglBuffer *new_buffer; GimpMatrix3 m; GimpMatrix3 inv; gint u1, v1, u2, v2; /* source bounding box */ gint x1, y1, x2, y2; /* target bounding box */ GeglNode *affine; GimpMatrix3 gegl_matrix; g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), NULL); g_return_val_if_fail (gimp_item_is_attached (GIMP_ITEM (drawable)), NULL); g_return_val_if_fail (GIMP_IS_CONTEXT (context), NULL); g_return_val_if_fail (GEGL_IS_BUFFER (orig_buffer), NULL); g_return_val_if_fail (matrix != NULL, NULL); g_return_val_if_fail (new_offset_x != NULL, NULL); g_return_val_if_fail (new_offset_y != NULL, NULL); g_return_val_if_fail (progress == NULL || GIMP_IS_PROGRESS (progress), NULL); m = *matrix; inv = *matrix; if (direction == GIMP_TRANSFORM_BACKWARD) { /* keep the original matrix here, so we dont need to recalculate * the inverse later */ gimp_matrix3_invert (&inv); } else { /* Find the inverse of the transformation matrix */ gimp_matrix3_invert (&m); } u1 = orig_offset_x; v1 = orig_offset_y; u2 = u1 + gegl_buffer_get_width (orig_buffer); v2 = v1 + gegl_buffer_get_height (orig_buffer); /* Always clip unfloated buffers since they must keep their size */ if (G_TYPE_FROM_INSTANCE (drawable) == GIMP_TYPE_CHANNEL && ! babl_format_has_alpha (gegl_buffer_get_format (orig_buffer))) clip_result = GIMP_TRANSFORM_RESIZE_CLIP; /* Find the bounding coordinates of target */ gimp_transform_resize_boundary (&inv, clip_result, u1, v1, u2, v2, &x1, &y1, &x2, &y2); /* Get the new temporary buffer for the transformed result */ new_buffer = gimp_gegl_buffer_new (GEGL_RECTANGLE (0, 0, x2 - x1, y2 - y1), gegl_buffer_get_format (orig_buffer)); gimp_matrix3_identity (&gegl_matrix); gimp_matrix3_translate (&gegl_matrix, u1, v1); gimp_matrix3_mult (&inv, &gegl_matrix); gimp_matrix3_translate (&gegl_matrix, -x1, -y1); affine = gegl_node_new_child (NULL, "operation", "gegl:transform", "filter", gimp_interpolation_to_gegl_filter (interpolation_type), "hard-edges", TRUE, NULL); gimp_gegl_node_set_matrix (affine, &gegl_matrix); gimp_apply_operation (orig_buffer, progress, NULL, affine, new_buffer, NULL); g_object_unref (affine); *new_offset_x = x1; *new_offset_y = y1; return new_buffer; }
void gimp_drawable_edit_fill (GimpDrawable *drawable, GimpFillOptions *options, const gchar *undo_desc) { GimpContext *context; gint x, y, width, height; g_return_if_fail (GIMP_IS_DRAWABLE (drawable)); g_return_if_fail (gimp_item_is_attached (GIMP_ITEM (drawable))); g_return_if_fail (GIMP_IS_FILL_OPTIONS (options)); if (! gimp_item_mask_intersect (GIMP_ITEM (drawable), &x, &y, &width, &height)) { return; /* nothing to do, but the fill succeeded */ } context = GIMP_CONTEXT (options); if (gimp_layer_mode_is_alpha_only (gimp_context_get_paint_mode (context))) { if (! gimp_drawable_has_alpha (drawable) || ! (gimp_drawable_get_active_mask (drawable) & GIMP_COMPONENT_MASK_ALPHA)) { return; /* nothing to do, but the fill succeeded */ } } if (! undo_desc) undo_desc = gimp_fill_options_get_undo_desc (options); /* check if we can fill the drawable's buffer directly */ if (gimp_drawable_edit_can_fill_direct (drawable, options)) { gimp_drawable_edit_fill_direct (drawable, options, undo_desc); gimp_drawable_update (drawable, x, y, width, height); } else { GeglNode *operation; GimpDrawableFilter *filter; gdouble opacity; GimpLayerMode mode; GimpLayerMode composite_mode; opacity = gimp_context_get_opacity (context); mode = gimp_context_get_paint_mode (context); composite_mode = gimp_layer_mode_get_paint_composite_mode (mode); operation = gegl_node_new_child (NULL, "operation", "gimp:fill-source", "options", options, "drawable", drawable, "pattern-offset-x", -x, "pattern-offset-y", -y, NULL); filter = gimp_drawable_filter_new (drawable, undo_desc, operation, NULL); gimp_drawable_filter_set_opacity (filter, opacity); gimp_drawable_filter_set_mode (filter, mode, GIMP_LAYER_COLOR_SPACE_AUTO, GIMP_LAYER_COLOR_SPACE_AUTO, composite_mode); gimp_drawable_filter_apply (filter, NULL); gimp_drawable_filter_commit (filter, NULL, FALSE); g_object_unref (filter); g_object_unref (operation); } }
static gboolean test_operation (const char *operation_name) { gboolean result = FALSE; const Babl *format = babl_format ("RGBA u8"); const gint bpp = babl_format_get_bytes_per_pixel (format); const gint out_width = 5 + 10; const gint out_height = 5 + 10; guchar *output_with_abyss = gegl_malloc (out_width * out_height * bpp); guchar *output_no_abyss = gegl_malloc (out_width * out_height * bpp); GeglColor *upper_color = gegl_color_new ("rgb(0.2, 0.8, 0.2)"); GeglColor *lower_color = gegl_color_new ("rgb(0.0, 0.0, 0.0)"); GeglColor *transparent = gegl_color_new ("rgba(0.0, 0.0, 0.0, 0.0)"); { /* Using abyss */ GeglNode *ptn = gegl_node_new(); GeglNode *test_op, *upper_rect, *lower_rect; test_op = gegl_node_new_child (ptn, "operation", operation_name, NULL); upper_rect = gegl_node_new_child (ptn, "operation", "gegl:rectangle", "color", upper_color, "x", 5.0, "y", 5.0, "width", 10.0, "height", 10.0, NULL); lower_rect = gegl_node_new_child (ptn, "operation", "gegl:rectangle", "color", lower_color, "x", 0.0, "y", 0.0, "width", 10.0, "height", 10.0, NULL); gegl_node_connect_to (lower_rect, "output", test_op, "input"); gegl_node_connect_to (upper_rect, "output", test_op, "aux"); { int i; guchar *out = output_with_abyss; for (i = 0; i < out_height; i++) { gegl_node_blit (test_op, 1.0, GEGL_RECTANGLE (0, i, out_width, 1), format, out, GEGL_AUTO_ROWSTRIDE, 0); out += out_width * bpp; } } g_object_unref (ptn); } { /* Explicit transparency */ GeglNode *ptn = gegl_node_new(); GeglNode *test_op, *upper_rect, *lower_rect; GeglNode *upper_over, *lower_over; GeglNode *background; test_op = gegl_node_new_child (ptn, "operation", operation_name, NULL); background = gegl_node_new_child (ptn, "operation", "gegl:rectangle", "color", transparent, "x", 0.0, "y", 0.0, "width", 10.0 + 5.0, "height", 10.0 + 5.0, NULL); upper_rect = gegl_node_new_child (ptn, "operation", "gegl:rectangle", "color", upper_color, "x", 5.0, "y", 5.0, "width", 10.0, "height", 10.0, NULL); upper_over = gegl_node_new_child (ptn, "operation", "gegl:over", NULL); lower_rect = gegl_node_new_child (ptn, "operation", "gegl:rectangle", "color", lower_color, "x", 0.0, "y", 0.0, "width", 10.0, "height", 10.0, NULL); lower_over = gegl_node_new_child (ptn, "operation", "gegl:over", NULL); gegl_node_connect_to (lower_rect, "output", lower_over, "aux"); gegl_node_connect_to (upper_rect, "output", upper_over, "aux"); gegl_node_connect_to (background, "output", lower_over, "input"); gegl_node_connect_to (background, "output", upper_over, "input"); gegl_node_connect_to (lower_over, "output", test_op, "input"); gegl_node_connect_to (upper_over, "output", test_op, "aux"); { int i; guchar *out = output_no_abyss; for (i = 0; i < out_height; i++) { gegl_node_blit (test_op, 1.0, GEGL_RECTANGLE (0, i, out_width, 1), format, out, GEGL_AUTO_ROWSTRIDE, 0); out += out_width * bpp; } } g_object_unref (ptn); } if (0 == memcmp (output_with_abyss, output_no_abyss, out_width * out_height * bpp)) { printf ("."); fflush(stdout); result = TRUE; } else { printf ("\n %s ... FAIL\n", operation_name); result = FALSE; } if (!result) { GeglBuffer *linear; gchar *filename; filename = g_strconcat (operation_name, " - with abyss.png", NULL); linear = gegl_buffer_linear_new_from_data (output_with_abyss, format, GEGL_RECTANGLE (0, 0, out_width, out_height), GEGL_AUTO_ROWSTRIDE, NULL, NULL); dump_to_png (filename, linear); g_free (filename); g_object_unref (linear); filename = g_strconcat (operation_name, " - no abyss.png", NULL); linear = gegl_buffer_linear_new_from_data (output_no_abyss, format, GEGL_RECTANGLE (0, 0, out_width, out_height), GEGL_AUTO_ROWSTRIDE, NULL, NULL); dump_to_png (filename, linear); g_free (filename); g_object_unref (linear); } gegl_free (output_with_abyss); gegl_free (output_no_abyss); return result; }
GimpApplicator * gimp_applicator_new (GeglNode *parent, gboolean linear, gboolean use_split_preview, gboolean use_result_cache) { GimpApplicator *applicator; g_return_val_if_fail (parent == NULL || GEGL_IS_NODE (parent), NULL); applicator = g_object_new (GIMP_TYPE_APPLICATOR, NULL); applicator->linear = linear; if (parent) applicator->node = g_object_ref (parent); else applicator->node = gegl_node_new (); applicator->input_node = gegl_node_get_input_proxy (applicator->node, "input"); applicator->aux_node = gegl_node_get_input_proxy (applicator->node, "aux"); applicator->output_node = gegl_node_get_output_proxy (applicator->node, "output"); applicator->mode_node = gegl_node_new_child (applicator->node, "operation", "gimp:normal-mode", NULL); gimp_gegl_mode_node_set_mode (applicator->mode_node, applicator->paint_mode, applicator->linear); gimp_gegl_mode_node_set_opacity (applicator->mode_node, applicator->opacity); gegl_node_connect_to (applicator->input_node, "output", applicator->mode_node, "input"); applicator->apply_offset_node = gegl_node_new_child (applicator->node, "operation", "gegl:translate", NULL); applicator->dup_apply_buffer_node = gegl_node_new_child (applicator->node, "operation", "gegl:copy-buffer", NULL); gegl_node_link_many (applicator->aux_node, applicator->apply_offset_node, applicator->dup_apply_buffer_node, NULL); if (use_split_preview) { applicator->preview_cache_node = gegl_node_new_child (applicator->node, "operation", "gegl:cache", NULL); applicator->preview_crop_node = gegl_node_new_child (applicator->node, "operation", "gegl:nop", NULL); gegl_node_link_many (applicator->dup_apply_buffer_node, applicator->preview_cache_node, applicator->preview_crop_node, NULL); gegl_node_connect_to (applicator->preview_crop_node, "output", applicator->mode_node, "aux"); } else { gegl_node_connect_to (applicator->dup_apply_buffer_node, "output", applicator->mode_node, "aux"); } applicator->mask_node = gegl_node_new_child (applicator->node, "operation", "gegl:buffer-source", NULL); applicator->mask_offset_node = gegl_node_new_child (applicator->node, "operation", "gegl:translate", NULL); gegl_node_connect_to (applicator->mask_node, "output", applicator->mask_offset_node, "input"); /* don't connect the the mask offset node to mode's aux2 yet */ applicator->affect_node = gegl_node_new_child (applicator->node, "operation", "gimp:mask-components", "mask", applicator->affect, NULL); if (use_result_cache) { applicator->output_cache_node = gegl_node_new_child (applicator->node, "operation", "gegl:cache", NULL); gegl_node_link_many (applicator->input_node, applicator->affect_node, applicator->output_cache_node, applicator->output_node, NULL); } else { gegl_node_link_many (applicator->input_node, applicator->affect_node, applicator->output_node, NULL); } gegl_node_connect_to (applicator->mode_node, "output", applicator->affect_node, "aux"); return applicator; }
int main(int argc, char *argv[]) { int result = SUCCESS; GeglNode *graph = NULL; GeglNode *node = NULL; GeglColor *color = NULL; double x = -5; double y = -5; char *name = NULL; gboolean cache = TRUE; /* Init */ gegl_init (&argc, &argv); color = gegl_color_new ("rgb(0.0, 1.0, 0.0)"); graph = gegl_node_new (); node = gegl_node_new_child (graph, "operation", "gegl:color", "value", color, NULL); gegl_node_get (node, "operation", &name, NULL); if (!(!strcmp (name, "gegl:color"))) { result = FAILURE; printf ("operation: %s\n", name); goto abort; } gegl_node_set (node, "operation", "gegl:translate", "x", 50.0, "y", 100.0, NULL); gegl_node_get (node, "operation", &name, "x", &x, "y", &y, NULL); if (!(!strcmp (name, "gegl:translate") && (int)x == 50 && (int)y == 100)) { result = FAILURE; printf ("operation: %s\n", name); printf ("x, y: %f, %f\n", x, y); goto abort; } gegl_node_set (node, "x", 5.0, "y", 10.0, NULL); gegl_node_get (node, "y", &y, "operation", &name, "x", &x, NULL); if (!(!strcmp (name, "gegl:translate") && (int)x == 5 && (int)y == 10)) { result = FAILURE; printf ("operation: %s\n", name); printf ("x, y: %f, %f\n", x, y); goto abort; } gegl_node_set (node, "operation", "gegl:doesnt-exist", NULL); gegl_node_get (node, "operation", &name, NULL); if (!(!strcmp (name, "gegl:nop"))) { result = FAILURE; printf ("operation: %s\n", name); goto abort; } gegl_node_set (node, "operation", "gegl:nop", NULL); gegl_node_get (node, "operation", &name, NULL); if (!(!strcmp (name, "gegl:nop"))) { result = FAILURE; printf ("operation: %s\n", name); goto abort; } gegl_node_set (node, "operation", "gegl:translate", NULL); gegl_node_get (node, "operation", &name, "x", &x, "y", &y, NULL); if (!(!strcmp (name, "gegl:translate") && (int)x == 0 && (int)y == 0)) { result = FAILURE; printf ("operation: %s\n", name); printf ("x, y: %f, %f\n", x, y); goto abort; } gegl_node_set (node, "operation", "gegl:translate", "name", "Brian", "dont-cache", FALSE, NULL); gegl_node_get (node, "name", &name, "dont-cache", &cache, NULL); if (!(!strcmp (name, "Brian") && cache == FALSE)) { result = FAILURE; printf ("name: %s\n", name); printf ("cache: %d\n", cache); goto abort; } gegl_node_set (node, "dont-cache", TRUE, "name", "Steve", NULL); gegl_node_get (node, "name", &name, "dont-cache", &cache, NULL); if (!(!strcmp (name, "Steve") && cache == TRUE)) { result = FAILURE; printf ("name: %s\n", name); printf ("cache: %d\n", cache); goto abort; } abort: /* Cleanup */ g_object_unref (graph); g_object_unref (color); gegl_exit (); return result; }
gint main (gint argc, gchar **argv) { gegl_init (&argc, &argv); /* initialize the GEGL library */ /* license for this application, needed by fractal-explorer */ g_object_set (gegl_config (), "application-license", "GPL3", NULL); { /* instantiate a graph */ GeglNode *gegl = gegl_node_new (); /* This is the graph we're going to construct: .-----------. | display | `-----------' | .--------. | crop | `--------' | .--------. | over | `--------' | \ | \ | \ | | | .------. | | text | | `------' .------------------. | fractal-explorer | `------------------' */ /*< The image nodes representing operations we want to perform */ GeglNode *display = gegl_node_create_child (gegl, "gegl:ff-save"); GeglNode *crop = gegl_node_new_child (gegl, "operation", "gegl:crop", "width", 512.0, "height", 384.0, NULL); GeglNode *over = gegl_node_new_child (gegl, "operation", "gegl:over", NULL); GeglNode *text = gegl_node_new_child (gegl, "operation", "gegl:text", "size", 10.0, "color", gegl_color_new ("rgb(1.0,1.0,1.0)"), NULL); GeglNode *mandelbrot = gegl_node_new_child (gegl, "operation", "gegl:fractal-explorer", "shiftx", -256.0, NULL); gegl_node_link_many (mandelbrot, over, crop, display, NULL); gegl_node_connect_to (text, "output", over, "aux"); /* request that the save node is processed, all dependencies will * be processed as well */ { gint frame; gint frames = 200; for (frame=0; frame<frames; frame++) { gchar string[512]; gdouble t = frame * 1.0/frames; #define INTERPOLATE(min,max) ((max)*(t)+(min)*(1.0-t)) gdouble shiftx = INTERPOLATE(-256.0, -512.0); gdouble shifty = INTERPOLATE(0.0, -256.0); gdouble zoom = INTERPOLATE(300.0, 400.0); gegl_node_set (mandelbrot, "shiftx", shiftx, "shifty", shifty, "zoom", zoom, NULL); g_sprintf (string, "x=%1.3f y=%1.3f z=%1.3f", shiftx, shifty, zoom); gegl_node_set (text, "string", string, NULL); gegl_node_process (display); } } /* free resources used by the graph and the nodes it owns */ g_object_unref (gegl); } /* free resources globally used by GEGL */ gegl_exit (); return 0; }
static gboolean test_operation (const gchar *op_name, const gchar *image, gchar *output_path) { gchar *ref_path; GeglNode *img, *ref_img, *gegl; GeglRectangle ref_bounds, comp_bounds; gint ref_pixels; gboolean result = TRUE; gegl = gegl_node_new (); ref_path = g_build_path (G_DIR_SEPARATOR_S, reference_dir, image, NULL); ref_img = gegl_node_new_child (gegl, "operation", "gegl:load", "path", ref_path, NULL); g_free (ref_path); img = gegl_node_new_child (gegl, "operation", "gegl:load", "path", output_path, NULL); ref_bounds = gegl_node_get_bounding_box (ref_img); comp_bounds = gegl_node_get_bounding_box (img); ref_pixels = ref_bounds.width * ref_bounds.height; if (ref_bounds.width != comp_bounds.width || ref_bounds.height != comp_bounds.height) { g_printf ("FAIL\n Reference and composition differ in size\n"); result = FALSE; } else { GeglNode *comparison; gdouble max_diff; comparison = gegl_node_create_child (gegl, "gegl:image-compare"); gegl_node_link (img, comparison); gegl_node_connect_to (ref_img, "output", comparison, "aux"); gegl_node_process (comparison); gegl_node_get (comparison, "max diff", &max_diff, NULL); if (max_diff < 1.0) { g_printf ("PASS\n"); result = TRUE; } else { GeglNode *output; gchar *diff_path; gdouble avg_diff_wrong, avg_diff_total; gint wrong_pixels; gegl_node_get (comparison, "avg_diff_wrong", &avg_diff_wrong, "avg_diff_total", &avg_diff_total, "wrong_pixels", &wrong_pixels, NULL); g_printf ("FAIL\n Reference image and composition differ\n" " wrong pixels : %i/%i (%2.2f%%)\n" " max Δe : %2.3f\n" " avg Δe : %2.3f (wrong) %2.3f (total)\n", wrong_pixels, ref_pixels, (wrong_pixels * 100.0 / ref_pixels), max_diff, avg_diff_wrong, avg_diff_total); diff_path = operation_to_path (op_name, TRUE); output = gegl_node_new_child (gegl, "operation", "gegl:png-save", "path", diff_path, NULL); gegl_node_link (comparison, output); gegl_node_process (output); g_free (diff_path); result = FALSE; } } g_object_unref (gegl); return result; }
static gboolean process_operations (GType type) { GType *operations; gboolean result = TRUE; guint count; gint i; operations = g_type_children (type, &count); if (!operations) { g_free (operations); return TRUE; } for (i = 0; i < count; i++) { GeglOperationClass *operation_class; const gchar *image, *xml, *name; gboolean matches; operation_class = g_type_class_ref (operations[i]); image = gegl_operation_class_get_key (operation_class, "reference-image"); xml = gegl_operation_class_get_key (operation_class, "reference-composition"); name = gegl_operation_class_get_key (operation_class, "name"); if (name == NULL) { result = result && process_operations (operations[i]); continue; } matches = g_regex_match (regex, name, 0, NULL) && !g_regex_match (exc_regex, name, 0, NULL); if (xml && matches) { GeglNode *composition; if (output_all) g_printf ("%s\n", name); else if (image) g_printf ("%s: ", name); /* more information will follow if we're testing */ composition = gegl_node_new_from_xml (xml, data_dir); if (!composition) { g_printf ("FAIL\n Composition graph is flawed\n"); result = FALSE; } else if (image || output_all) { gchar *output_path = operation_to_path (name, FALSE); GeglNode *output = gegl_node_new_child (composition, "operation", "gegl:png-save", "compression", 9, "path", output_path, NULL); gegl_node_link (composition, output); gegl_node_process (output); g_object_unref (composition); /* don't test if run with --all */ if (!output_all && image) result = test_operation (name, image, output_path) && result; g_free (output_path); } } /* if we are running with --all and the operation doesn't have a composition, use standard composition and images, don't test */ else if (output_all && matches && !(g_type_is_a (operations[i], GEGL_TYPE_OPERATION_SINK) || g_type_is_a (operations[i], GEGL_TYPE_OPERATION_TEMPORAL))) { g_printf ("%s\n", name); standard_output (name); } result = process_operations (operations[i]) && result; } g_free (operations); return result; }
static void standard_output (const gchar *op_name) { GeglNode *composition, *input, *aux, *operation, *crop, *output, *translate; GeglNode *background, *over; gchar *input_path = g_build_path (G_DIR_SEPARATOR_S, data_dir, "standard-input.png", NULL); gchar *aux_path = g_build_path (G_DIR_SEPARATOR_S, data_dir, "standard-aux.png", NULL); gchar *output_path = operation_to_path (op_name, FALSE); composition = gegl_node_new (); operation = gegl_node_create_child (composition, op_name); if (gegl_node_has_pad (operation, "output")) { input = gegl_node_new_child (composition, "operation", "gegl:load", "path", input_path, NULL); translate = gegl_node_new_child (composition, "operation", "gegl:translate", "x", 0.0, "y", 80.0, NULL); aux = gegl_node_new_child (composition, "operation", "gegl:load", "path", aux_path, NULL); crop = gegl_node_new_child (composition, "operation", "gegl:crop", "width", 200.0, "height", 200.0, NULL); output = gegl_node_new_child (composition, "operation", "gegl:png-save", "compression", 9, "path", output_path, NULL); background = gegl_node_new_child (composition, "operation", "gegl:checkerboard", "color1", gegl_color_new ("rgb(0.75,0.75,0.75)"), "color2", gegl_color_new ("rgb(0.25,0.25,0.25)"), NULL); over = gegl_node_new_child (composition, "operation", "gegl:over", NULL); if (gegl_node_has_pad (operation, "input")) gegl_node_link (input, operation); if (gegl_node_has_pad (operation, "aux")) { gegl_node_connect_to (aux, "output", translate, "input"); gegl_node_connect_to (translate, "output", operation, "aux"); } gegl_node_connect_to (background, "output", over, "input"); gegl_node_connect_to (operation, "output", over, "aux"); gegl_node_connect_to (over, "output", crop, "input"); gegl_node_connect_to (crop, "output", output, "input"); gegl_node_process (output); } g_free (input_path); g_free (aux_path); g_free (output_path); g_object_unref (composition); }
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; }
gint main (gint argc, gchar **argv) { GeglRectangle terrain_rect; if (argc < 2) usage(); gegl_init (&argc, &argv); parse_args (argc, argv); gegl_decode = gegl_node_new (); store = gegl_node_new_child (gegl_decode, "operation", "gegl:buffer-sink", "buffer", &video_frame, NULL); load = gegl_node_new_child (gegl_decode, "operation", "gegl:ff-load", "frame", 0, "path", video_path, NULL); gegl_node_link_many (load, store, NULL); decode_frame_no (0); /* we issue a processing/decoding of a frame - to get metadata */ { gegl_node_get (load, "frame-rate", &frame_rate, NULL); total_frames = 0; gegl_node_get (load, "frames", &total_frames, NULL); if (frame_end == 0) frame_end = total_frames; } if (horizontal) terrain_rect = (GeglRectangle){0, 0, frame_end - frame_start + 1, 1024}; else terrain_rect = (GeglRectangle){0, 0, 1024, frame_end - frame_start + 1}; if (input_analysis_path && g_file_test (input_analysis_path, G_FILE_TEST_IS_REGULAR)) { GeglNode *load_graph = gegl_node_new (); GeglNode *load = gegl_node_new_child (load_graph, "operation", "gegl:load", "path", input_analysis_path, NULL); GeglNode *store = gegl_node_new_child (load_graph, "operation", "gegl:buffer-sink", "buffer", &terrain, NULL); gegl_node_link_many (load, store, NULL); gegl_node_process (store); g_object_unref (load_graph); frame_end = frame_start + gegl_buffer_get_extent (terrain)->height; /* the last frame aavilavle for analysis is the last one loaded rom cache,.. perhaps with some timeout */ } else { terrain = gegl_buffer_new (&terrain_rect, babl_format ("RGBA u8")); { gint frame; gint max_buf_pos = 0; for (frame = frame_start; frame <= frame_end; frame++) { FrameInfo info = {{0}}; uint8_t buffer[4096] = {0,}; int buffer_pos = 0; GeglRectangle terrain_row; char *p = format; GString *word = g_string_new (""); if (show_progress) { double percent_full = 100.0 * (frame-frame_start) / (frame_end-frame_start); double percent_time = time_out?100.0 * babl_ticks()/1000.0/1000.0 / time_out:0.0; fprintf (stdout, "\r%2.1f%% %i/%i (%i)", percent_full>percent_time?percent_full:percent_time, frame-frame_start, frame_end-frame_start, frame); fflush (stdout); } if (horizontal) terrain_row = (GeglRectangle){frame-frame_start, 0, 1, 1024}; else terrain_row = (GeglRectangle){0, frame-frame_start, 1024, 1}; decode_frame_no (frame); //for (int i=0;i<(signed)sizeof(buffer);i++)buffer[i]=0; while (*p == ' ') p++; for (p= format;p==format || p[-1]!='\0';p++) { if (*p != '\0' && *p != ' ') { g_string_append_c (word, *p); } else { if (!strcmp (word->str, "histogram")) { record_pix_stats (video_frame, previous_video_frame, &(info.rgb_hist[0]), &(info.rgb_square_diff)[0]); for (int i = 0; i < NEGL_RGB_HIST_SLOTS; i++) { buffer[buffer_pos] = info.rgb_hist[i]; buffer_pos++; } for (int i = 0; i < 3; i++) { buffer[buffer_pos] = info.rgb_square_diff[i]; buffer_pos++; } } else if (!strcmp (word->str, "mid-row")) { int samples = NEGL_RGB_HEIGHT; if (p[1] >= '0' && p[1] <= '9') { samples = g_strtod (&p[1], &p); } buffer_pos += extract_mid_row (video_frame, &(buffer)[buffer_pos], samples); } else if (!strcmp (word->str, "mid-col")) { int samples = NEGL_RGB_HEIGHT; if (p[1] >= '0' && p[1] <= '9') { samples = g_strtod (&p[1], &p); } buffer_pos += extract_mid_col (video_frame, &(buffer)[buffer_pos], samples); } else if (!strcmp (word->str, "thumb")) { int samples = NEGL_RGB_THEIGHT; int samples2; if (p[1] >= '0' && p[1] <= '9') { samples = g_strtod (&p[1], &p); } if (horizontal) samples2 = samples * gegl_buffer_get_width (video_frame)/gegl_buffer_get_height(video_frame); else samples2 = samples * gegl_buffer_get_height (video_frame)/gegl_buffer_get_width(video_frame); buffer_pos += extract_thumb (video_frame, &(buffer)[buffer_pos], samples, samples2); } else if (!strcmp (word->str, "audio")) { int dups = 1; GeglAudioFragment *audio = NULL; if (p[1] >= '0' && p[1] <= '9') { dups = g_strtod (&p[1], &p); } gegl_node_get (load, "audio", &audio, NULL); if (audio) { extract_audio_energy (audio, &buffer[buffer_pos], dups); g_object_unref (audio); } buffer_pos+=3 * dups; } g_string_assign (word, ""); } } max_buf_pos = buffer_pos; g_string_free (word, TRUE); gegl_buffer_set (terrain, &terrain_row, 0, babl_format("RGB u8"), buffer, GEGL_AUTO_ROWSTRIDE); if (time_out > 1.0 && babl_ticks()/1000.0/1000.0 > time_out) { frame_end = frame; if (horizontal) terrain_rect.width = frame_end - frame_start + 1; else terrain_rect.height = frame_end - frame_start + 1; // gegl_buffer_set_extent (terrain, &terrain_rect); } if (horizontal) terrain_rect.height = max_buf_pos/3; else terrain_rect.width = max_buf_pos/3; gegl_buffer_set_extent (terrain, &terrain_rect); } if (show_progress) { fprintf (stdout, "\n"); fflush (stdout); } } if (output_analysis_path) { GeglNode *save_graph = gegl_node_new (); GeglNode *readbuf = gegl_node_new_child (save_graph, "operation", "gegl:buffer-source", "buffer", terrain, NULL); GeglNode *save = gegl_node_new_child (save_graph, "operation", "gegl:png-save", "path", output_analysis_path, NULL); gegl_node_link_many (readbuf, save, NULL); gegl_node_process (save); g_object_unref (save_graph); } } if (thumb_path) { GeglNode *save_graph = gegl_node_new (); find_best_thumb (); if (frame_thumb != 0) decode_frame_no (frame_thumb-1); decode_frame_no (frame_thumb); { GeglNode *readbuf = gegl_node_new_child (save_graph, "operation", "gegl:buffer-source", "buffer", video_frame, NULL); GeglNode *save = gegl_node_new_child (save_graph, "operation", "gegl:png-save", "path", thumb_path, NULL); gegl_node_link_many (readbuf, save, NULL); gegl_node_process (save); g_object_unref (save_graph); } } if (video_frame) g_object_unref (video_frame); video_frame = NULL; if (previous_video_frame) g_object_unref (previous_video_frame); previous_video_frame = NULL; if (terrain) g_object_unref (terrain); terrain = NULL; g_object_unref (gegl_decode); gegl_exit (); return 0; }
/** * gimp_seamless_clone_tool_create_render_node: * @sc: The GimpSeamlessCloneTool to initialize * * This function creates a Gegl node graph of the composition which is * needed to render the drawable. The graph should have an "input" pad * which will receive the drawable on which the preview is applied, and * it should also have an "output" pad to which the final result will be * rendered */ static void gimp_seamless_clone_tool_create_render_node (GimpSeamlessCloneTool *sc) { /* Here is a textual description of the graph we are going to create: * * <input> <- drawable * +--+--------------------------+ * | |output | * | | | * | | <buffer-source> <- paste | * | | |output | * | | | | * | |input |aux | * |<seamless-paste-render> | * | |output | * | | | * | |input | * +----+------------------------+ * <output> */ GimpSeamlessCloneOptions *options = GIMP_SEAMLESS_CLONE_TOOL_GET_OPTIONS (sc); GeglNode *node; GeglNode *op, *paste, *overlay; GeglNode *input, *output; node = gegl_node_new (); input = gegl_node_get_input_proxy (node, "input"); output = gegl_node_get_output_proxy (node, "output"); paste = gegl_node_new_child (node, "operation", "gegl:buffer-source", "buffer", sc->paste, NULL); op = gegl_node_new_child (node, "operation", "gegl:seamless-clone", "max-refine-scale", options->max_refine_scale, NULL); overlay = gegl_node_new_child (node, "operation", "svg:dst-over", NULL); gegl_node_connect_to (input, "output", op, "input"); gegl_node_connect_to (paste, "output", op, "aux"); gegl_node_connect_to (op, "output", overlay, "input"); gegl_node_connect_to (input, "output", overlay, "aux"); gegl_node_connect_to (overlay, "output", output, "input"); sc->render_node = node; sc->sc_node = op; }
static gboolean test_scale (const gdouble scale, const gint x, const gint y, const Babl *format) { GeglNode *checkerboard; GeglBuffer *tmp_buffer; gboolean result = FALSE; const gint bpp = babl_format_get_bytes_per_pixel (format); const gint scaled_width = 32; const gint scaled_height = 32; gint pad = 32; guchar *output_buffer_scaled = gegl_malloc (scaled_width * scaled_height * bpp); guchar *output_node_scaled = gegl_malloc (scaled_width * scaled_height * bpp); if (2 / scale > pad) pad = 2 / scale + 2; tmp_buffer = gegl_buffer_new (GEGL_RECTANGLE ((x / scale) - pad, (y / scale) - pad, (scaled_width / scale) + (2 * pad), (scaled_height / scale) + (2 * pad)), babl_format ("RGBA float")); checkerboard = gegl_node_new_child(NULL, "operation", "gegl:checkerboard", "x", 16, "y", 16, NULL); gegl_node_blit_buffer (checkerboard, tmp_buffer, NULL, 0, GEGL_ABYSS_NONE); gegl_buffer_get (tmp_buffer, GEGL_RECTANGLE (x, y, scaled_width, scaled_height), scale, format, output_buffer_scaled, GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE); g_object_unref (checkerboard); g_object_unref (tmp_buffer); /* Re-create the node so we don't hit its cache */ checkerboard = gegl_node_new_child(NULL, "operation", "gegl:checkerboard", "x", 16, "y", 16, NULL); gegl_node_blit (checkerboard, scale, GEGL_RECTANGLE (x, y, scaled_width, scaled_height), format, output_node_scaled, GEGL_AUTO_ROWSTRIDE, 0); g_object_unref (checkerboard); if (0 == memcmp (output_buffer_scaled, output_node_scaled, scaled_width * scaled_height * bpp)) { printf ("."); fflush(stdout); result = TRUE; } else { printf ("\n scale=%.4f at %d, %d in \"%s\" ... FAIL\n", scale, x, y, babl_get_name (format)); result = FALSE; } gegl_free (output_buffer_scaled); gegl_free (output_node_scaled); return result; }
gint main (gint argc, gchar **argv) { g_thread_init (NULL); gtk_init (&argc, &argv); gegl_init (&argc, &argv); window = gtk_window_new (GTK_WINDOW_TOPLEVEL); gtk_window_set_title (GTK_WINDOW (window), "GEGL destructive painter"); if (argv[1] == NULL) { GeglRectangle rect = {0, 0, 512, 512}; gpointer buf; /* XXX: for best overall performance, this format should probably * be RaGaBaA float, overeager in-place processing code makes that fail though. */ buffer = gegl_buffer_new (&rect, babl_format("R'G'B' u8")); /* it would be useful to have a programmatic way of doing this, filling * with a given pixel value */ buf = gegl_buffer_linear_open (buffer, NULL, NULL, babl_format ("Y' u8")); memset (buf, 255, 512 * 512); gegl_buffer_linear_close (buffer, buf); } else { buffer = gegl_buffer_open (argv[1]); } gegl = gegl_node_new (); { GeglNode *loadbuf = gegl_node_new_child (gegl, "operation", "gegl:buffer-source", "buffer", buffer, NULL); out = gegl_node_new_child (gegl, "operation", "gegl:nop", NULL); gegl_node_link_many (loadbuf, out, NULL); view = g_object_new (GEGL_TYPE_VIEW, "node", out, NULL); top = loadbuf; } g_signal_connect (GTK_OBJECT (view), "motion-notify-event", (GCallback) paint_motion, NULL); g_signal_connect (GTK_OBJECT (view), "button-press-event", (GCallback) paint_press, NULL); g_signal_connect (GTK_OBJECT (view), "button-release-event", (GCallback) paint_release, NULL); gtk_widget_add_events (view, GDK_BUTTON_RELEASE_MASK); gtk_container_add (GTK_CONTAINER (window), view); gtk_widget_set_size_request (view, 512, 512); g_signal_connect (G_OBJECT (window), "delete-event", G_CALLBACK (gtk_main_quit), window); gtk_widget_show_all (window); gtk_main (); g_object_unref (gegl); gegl_buffer_destroy (buffer); gegl_exit (); return 0; }
void gimp_operation_tool_set_operation (GimpOperationTool *tool, const gchar *operation, const gchar *undo_desc, const gchar *icon_name) { GimpImageMapTool *im_tool; g_return_if_fail (GIMP_IS_OPERATION_TOOL (tool)); g_return_if_fail (operation != NULL); im_tool = GIMP_IMAGE_MAP_TOOL (tool); if (tool->operation) g_free (tool->operation); if (tool->undo_desc) g_free (tool->undo_desc); if (tool->icon_name) g_free (tool->icon_name); tool->operation = g_strdup (operation); tool->undo_desc = g_strdup (undo_desc); tool->icon_name = g_strdup (icon_name); if (tool->aux_input) { g_object_unref (tool->aux_input); tool->aux_input = NULL; } if (tool->aux2_input) { g_object_unref (tool->aux2_input); tool->aux2_input = NULL; } gimp_image_map_tool_get_operation (im_tool); if (undo_desc) GIMP_IMAGE_MAP_TOOL_GET_CLASS (tool)->settings_name = "yes"; /* XXX hack */ else GIMP_IMAGE_MAP_TOOL_GET_CLASS (tool)->settings_name = NULL; /* XXX hack */ if (tool->aux_input_box) { gtk_widget_destroy (tool->aux_input_box); tool->aux_input_button = NULL; tool->aux_input_box = NULL; } if (tool->aux2_input_box) { gtk_widget_destroy (tool->aux2_input_box); tool->aux2_input_button = NULL; tool->aux2_input_box = NULL; } if (tool->options_gui) { gtk_widget_destroy (tool->options_gui); tool->options_gui = NULL; if (im_tool->active_picker) { im_tool->active_picker = NULL; gimp_color_tool_disable (GIMP_COLOR_TOOL (tool)); } } if (gegl_node_has_pad (im_tool->operation, "aux")) { GimpContext *context; GtkWidget *label; tool->aux_input = gegl_node_new_child (NULL, "operation", "gegl:buffer-source", NULL); gegl_node_connect_to (tool->aux_input, "output", im_tool->operation, "aux"); context = GIMP_CONTEXT (GIMP_TOOL_GET_OPTIONS (tool)); tool->aux_input_box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 4); label = gtk_label_new_with_mnemonic (_("_Aux Input")); gtk_box_pack_start (GTK_BOX (tool->aux_input_box), label, FALSE, FALSE, 0); gtk_widget_show (label); tool->aux_input_button = gimp_pickable_button_new (context, GIMP_VIEW_SIZE_LARGE, 1); gtk_box_pack_start (GTK_BOX (tool->aux_input_box), tool->aux_input_button, FALSE, FALSE, 0); gtk_widget_show (tool->aux_input_button); gtk_label_set_mnemonic_widget (GTK_LABEL (label), tool->aux_input_button); if (tool->options_box) { gtk_box_pack_start (GTK_BOX (tool->options_box), tool->aux_input_box, FALSE, FALSE, 0); gtk_widget_show (tool->aux_input_box); } g_signal_connect_object (tool->aux_input_button, "notify::pickable", G_CALLBACK (gimp_operation_tool_aux_notify), tool->aux_input, 0); } if (gegl_node_has_pad (im_tool->operation, "aux2")) { GimpContext *context; GtkWidget *label; tool->aux2_input = gegl_node_new_child (NULL, "operation", "gegl:buffer-source", NULL); gegl_node_connect_to (tool->aux2_input, "output", im_tool->operation, "aux2"); context = GIMP_CONTEXT (GIMP_TOOL_GET_OPTIONS (tool)); tool->aux2_input_box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 4); label = gtk_label_new_with_mnemonic (_("_Aux2 Input")); gtk_box_pack_start (GTK_BOX (tool->aux2_input_box), label, FALSE, FALSE, 0); gtk_widget_show (label); tool->aux2_input_button = gimp_pickable_button_new (context, GIMP_VIEW_SIZE_LARGE, 1); gtk_box_pack_start (GTK_BOX (tool->aux2_input_box), tool->aux2_input_button, FALSE, FALSE, 0); gtk_widget_show (tool->aux2_input_button); gtk_label_set_mnemonic_widget (GTK_LABEL (label), tool->aux2_input_button); if (tool->options_box) { gtk_box_pack_start (GTK_BOX (tool->options_box), tool->aux2_input_box, FALSE, FALSE, 0); gtk_widget_show (tool->aux2_input_box); } g_signal_connect_object (tool->aux2_input_button, "notify::pickable", G_CALLBACK (gimp_operation_tool_aux_notify), tool->aux2_input, 0); } if (im_tool->config) { tool->options_gui = gimp_prop_gui_new (G_OBJECT (im_tool->config), G_TYPE_FROM_INSTANCE (im_tool->config), GIMP_CONTEXT (GIMP_TOOL_GET_OPTIONS (tool)), (GimpCreatePickerFunc) gimp_image_map_tool_add_color_picker, tool); if (tool->options_box) { gtk_box_pack_start (GTK_BOX (tool->options_box), tool->options_gui, FALSE, FALSE, 0); gtk_widget_show (tool->options_gui); } } if (im_tool->gui) { if (undo_desc) gimp_tool_gui_set_description (im_tool->gui, undo_desc); if (icon_name) gimp_tool_gui_set_icon_name (im_tool->gui, icon_name); } if (GIMP_TOOL (tool)->drawable) { gimp_operation_tool_sync_op (tool, GIMP_TOOL (tool)->drawable); gimp_image_map_tool_preview (im_tool); } }
static void gimp_n_point_deformation_tool_start (GimpNPointDeformationTool *npd_tool, GimpDisplay *display) { GimpTool *tool = GIMP_TOOL (npd_tool); GimpNPointDeformationOptions *npd_options; GimpImage *image; GeglBuffer *source_buffer; GeglBuffer *preview_buffer; NPDModel *model; npd_options = GIMP_N_POINT_DEFORMATION_TOOL_GET_OPTIONS (npd_tool); gimp_tool_control (tool, GIMP_TOOL_ACTION_HALT, display); image = gimp_display_get_image (display); tool->display = display; tool->drawable = gimp_image_get_active_drawable (image); npd_tool->active = TRUE; /* create GEGL graph */ source_buffer = gimp_drawable_get_buffer (tool->drawable); preview_buffer = gegl_buffer_new (gegl_buffer_get_extent (source_buffer), babl_format ("cairo-ARGB32")); npd_tool->graph = gegl_node_new (); npd_tool->source = gegl_node_new_child (npd_tool->graph, "operation", "gegl:buffer-source", "buffer", source_buffer, NULL); npd_tool->npd_node = gegl_node_new_child (npd_tool->graph, "operation", "gegl:npd", NULL); npd_tool->sink = gegl_node_new_child (npd_tool->graph, "operation", "gegl:write-buffer", "buffer", preview_buffer, NULL); gegl_node_link_many (npd_tool->source, npd_tool->npd_node, npd_tool->sink, NULL); /* initialize some options */ g_object_set (G_OBJECT (npd_options), "mesh-visible", TRUE, NULL); gimp_n_point_deformation_options_set_sensitivity (npd_options, TRUE); /* compute and get model */ gegl_node_process (npd_tool->npd_node); gegl_node_get (npd_tool->npd_node, "model", &model, NULL); npd_tool->model = model; npd_tool->preview_buffer = preview_buffer; npd_tool->selected_cp = NULL; npd_tool->hovering_cp = NULL; npd_tool->selected_cps = NULL; npd_tool->rubber_band = FALSE; npd_tool->lattice_points = g_new (GimpVector2, 5 * model->hidden_model->num_of_bones); gimp_item_get_offset (GIMP_ITEM (tool->drawable), &npd_tool->offset_x, &npd_tool->offset_y); gimp_npd_debug (("offset: %f %f\n", npd_tool->offset_x, npd_tool->offset_y)); gimp_draw_tool_start (GIMP_DRAW_TOOL (npd_tool), display); gimp_n_point_deformation_tool_perform_deformation (npd_tool); /* hide original image */ gimp_item_set_visible (GIMP_ITEM (tool->drawable), FALSE, FALSE); gimp_image_flush (image); /* create and start a deformation thread */ npd_tool->deform_thread = g_thread_new ("deform thread", (GThreadFunc) gimp_n_point_deformation_tool_deform_thread_func, npd_tool); /* create and start canvas update timeout */ npd_tool->draw_timeout_id = gdk_threads_add_timeout_full (G_PRIORITY_DEFAULT_IDLE, GIMP_NPD_DRAW_INTERVAL, (GSourceFunc) gimp_n_point_deformation_tool_canvas_update_timeout, npd_tool, NULL); }
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; }
GimpApplicator * gimp_applicator_new (GeglNode *parent) { GimpApplicator *applicator; g_return_val_if_fail (parent == NULL || GEGL_IS_NODE (parent), NULL); applicator = g_object_new (GIMP_TYPE_APPLICATOR, NULL); if (parent) applicator->node = g_object_ref (parent); else applicator->node = gegl_node_new (); applicator->input_node = gegl_node_get_input_proxy (applicator->node, "input"); applicator->aux_node = gegl_node_get_input_proxy (applicator->node, "aux"); applicator->output_node = gegl_node_get_output_proxy (applicator->node, "output"); applicator->mode_node = gegl_node_new_child (applicator->node, "operation", "gimp:normal", NULL); gimp_gegl_mode_node_set_mode (applicator->mode_node, applicator->paint_mode, applicator->blend_space, applicator->composite_space, applicator->composite_mode); gimp_gegl_mode_node_set_opacity (applicator->mode_node, applicator->opacity); gegl_node_connect_to (applicator->input_node, "output", applicator->mode_node, "input"); applicator->apply_offset_node = gegl_node_new_child (applicator->node, "operation", "gegl:translate", NULL); gegl_node_link_many (applicator->aux_node, applicator->apply_offset_node, NULL); gegl_node_connect_to (applicator->apply_offset_node, "output", applicator->mode_node, "aux"); applicator->mask_node = gegl_node_new_child (applicator->node, "operation", "gegl:buffer-source", NULL); applicator->mask_offset_node = gegl_node_new_child (applicator->node, "operation", "gegl:translate", NULL); gegl_node_connect_to (applicator->mask_node, "output", applicator->mask_offset_node, "input"); /* don't connect the the mask offset node to mode's aux2 yet */ applicator->affect_node = gegl_node_new_child (applicator->node, "operation", "gimp:mask-components", "mask", applicator->affect, NULL); applicator->convert_format_node = gegl_node_new_child (applicator->node, "operation", "gegl:nop", NULL); applicator->cache_node = gegl_node_new_child (applicator->node, "operation", "gegl:nop", NULL); applicator->crop_node = gegl_node_new_child (applicator->node, "operation", "gegl:nop", NULL); gegl_node_link_many (applicator->input_node, applicator->affect_node, applicator->convert_format_node, applicator->cache_node, applicator->crop_node, applicator->output_node, NULL); gegl_node_connect_to (applicator->mode_node, "output", applicator->affect_node, "aux"); return applicator; }
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); }
static GeglBuffer * gradient_precalc_shapeburst (GimpImage *image, GimpDrawable *drawable, const GeglRectangle *region, gdouble dist, GimpProgress *progress) { GimpChannel *mask; GeglBuffer *dist_buffer; GeglBuffer *temp_buffer; GeglNode *shapeburst; gdouble max; gfloat max_iteration; gimp_progress_set_text (progress, _("Calculating distance map")); /* allocate the distance map */ dist_buffer = gegl_buffer_new (GEGL_RECTANGLE (0, 0, region->width, region->height), babl_format ("Y float")); /* allocate the selection mask copy * XXX: its format should be the same of gimp:shapeburst input buffer * porting the op to 'float' should be reflected here as well */ temp_buffer = gegl_buffer_new (GEGL_RECTANGLE (0, 0, region->width, region->height), babl_format ("Y u8")); mask = gimp_image_get_mask (image); /* If the image mask is not empty, use it as the shape burst source */ if (! gimp_channel_is_empty (mask)) { gint x, y, width, height; gint off_x, off_y; gimp_item_mask_intersect (GIMP_ITEM (drawable), &x, &y, &width, &height); gimp_item_get_offset (GIMP_ITEM (drawable), &off_x, &off_y); /* copy the mask to the temp mask */ gegl_buffer_copy (gimp_drawable_get_buffer (GIMP_DRAWABLE (mask)), GEGL_RECTANGLE (x + off_x, y + off_y, width, height), temp_buffer, GEGL_RECTANGLE (0, 0, 0, 0)); } else { /* If the intended drawable has an alpha channel, use that */ if (gimp_drawable_has_alpha (drawable)) { const Babl *component_format; component_format = babl_format ("A u8"); /* extract the aplha into the temp mask */ gegl_buffer_set_format (temp_buffer, component_format); gegl_buffer_copy (gimp_drawable_get_buffer (drawable), GEGL_RECTANGLE (region->x, region->y, region->width, region->height), temp_buffer, GEGL_RECTANGLE (0, 0, 0, 0)); gegl_buffer_set_format (temp_buffer, NULL); } else { GeglColor *white = gegl_color_new ("white"); /* Otherwise, just fill the shapeburst to white */ gegl_buffer_set_color (temp_buffer, NULL, white); g_object_unref (white); } } shapeburst = gegl_node_new_child (NULL, "operation", "gimp:shapeburst", NULL); gimp_gegl_progress_connect (shapeburst, progress, NULL); gimp_gegl_apply_operation (temp_buffer, NULL, NULL, shapeburst, dist_buffer, NULL); gegl_node_get (shapeburst, "max-iterations", &max, NULL); g_object_unref (shapeburst); max_iteration = max; g_object_unref (temp_buffer); /* normalize the shapeburst with the max iteration */ if (max_iteration > 0) { GeglBufferIterator *iter; iter = gegl_buffer_iterator_new (dist_buffer, NULL, 0, NULL, GEGL_BUFFER_READWRITE, GEGL_ABYSS_NONE); while (gegl_buffer_iterator_next (iter)) { gint count = iter->length; gfloat *data = iter->data[0]; while (count--) *data++ /= max_iteration; } } return dist_buffer; }
static GeglBuffer * gradient_precalc_shapeburst (GimpImage *image, GimpDrawable *drawable, const GeglRectangle *region, gdouble dist, GimpProgress *progress) { GimpChannel *mask; GeglBuffer *dist_buffer; GeglBuffer *temp_buffer; GeglNode *shapeburst; gimp_progress_set_text (progress, _("Calculating distance map")); /* allocate the distance map */ dist_buffer = gegl_buffer_new (GEGL_RECTANGLE (0, 0, region->width, region->height), babl_format ("Y float")); /* allocate the selection mask copy */ temp_buffer = gegl_buffer_new (GEGL_RECTANGLE (0, 0, region->width, region->height), babl_format ("Y float")); mask = gimp_image_get_mask (image); /* If the image mask is not empty, use it as the shape burst source */ if (! gimp_channel_is_empty (mask)) { gint x, y, width, height; gint off_x, off_y; gimp_item_mask_intersect (GIMP_ITEM (drawable), &x, &y, &width, &height); gimp_item_get_offset (GIMP_ITEM (drawable), &off_x, &off_y); /* copy the mask to the temp mask */ gegl_buffer_copy (gimp_drawable_get_buffer (GIMP_DRAWABLE (mask)), GEGL_RECTANGLE (x + off_x, y + off_y, width, height), temp_buffer, GEGL_RECTANGLE (0, 0, 0, 0)); } else { /* If the intended drawable has an alpha channel, use that */ if (gimp_drawable_has_alpha (drawable)) { const Babl *component_format; component_format = babl_format ("A float"); /* extract the aplha into the temp mask */ gegl_buffer_set_format (temp_buffer, component_format); gegl_buffer_copy (gimp_drawable_get_buffer (drawable), GEGL_RECTANGLE (region->x, region->y, region->width, region->height), temp_buffer, GEGL_RECTANGLE (0, 0, 0, 0)); gegl_buffer_set_format (temp_buffer, NULL); } else { GeglColor *white = gegl_color_new ("white"); /* Otherwise, just fill the shapeburst to white */ gegl_buffer_set_color (temp_buffer, NULL, white); g_object_unref (white); } } shapeburst = gegl_node_new_child (NULL, "operation", "gimp:shapeburst", "normalize", TRUE, NULL); gimp_gegl_progress_connect (shapeburst, progress, NULL); gimp_gegl_apply_operation (temp_buffer, NULL, NULL, shapeburst, dist_buffer, NULL); g_object_unref (shapeburst); g_object_unref (temp_buffer); return dist_buffer; }