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"); }
static void gimp_drawable_bucket_fill_internal (GimpDrawable *drawable, GimpFillType fill_type, gint paint_mode, gdouble opacity, gboolean fill_transparent, GimpSelectCriterion fill_criterion, gdouble threshold, gboolean sample_merged, gboolean diagonal_neighbors, gdouble x, gdouble y, const GimpRGB *color, GimpPattern *pattern) { GimpImage *image; GimpPickable *pickable; GeglBuffer *buffer; GeglBuffer *mask_buffer; gint x1, y1, x2, y2; gint mask_offset_x = 0; gint mask_offset_y = 0; gboolean selection; g_return_if_fail (GIMP_IS_DRAWABLE (drawable)); g_return_if_fail (gimp_item_is_attached (GIMP_ITEM (drawable))); g_return_if_fail (fill_type != GIMP_FILL_PATTERN || GIMP_IS_PATTERN (pattern)); g_return_if_fail (fill_type == GIMP_FILL_PATTERN || color != NULL); image = gimp_item_get_image (GIMP_ITEM (drawable)); selection = gimp_item_mask_bounds (GIMP_ITEM (drawable), &x1, &y1, &x2, &y2); if ((x1 == x2) || (y1 == y2)) return; gimp_set_busy (image->gimp); if (sample_merged) pickable = GIMP_PICKABLE (image); else pickable = GIMP_PICKABLE (drawable); /* Do a seed bucket fill...To do this, calculate a new * contiguous region. If there is a selection, calculate the * intersection of this region with the existing selection. */ mask_buffer = gimp_pickable_contiguous_region_by_seed (pickable, TRUE, threshold, fill_transparent, fill_criterion, diagonal_neighbors, (gint) x, (gint) y); if (selection) { GimpDrawable *sel; gint off_x = 0; gint off_y = 0; if (! sample_merged) gimp_item_get_offset (GIMP_ITEM (drawable), &off_x, &off_y); sel = GIMP_DRAWABLE (gimp_image_get_mask (image)); gimp_gegl_mask_combine_buffer (mask_buffer, gimp_drawable_get_buffer (sel), GIMP_CHANNEL_OP_INTERSECT, -off_x, -off_y); } gimp_gegl_mask_bounds (mask_buffer, &x1, &y1, &x2, &y2); /* 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); x1 = CLAMP (x1, off_x, (off_x + gimp_item_get_width (item))); y1 = CLAMP (y1, off_y, (off_y + gimp_item_get_height (item))); x2 = CLAMP (x2, off_x, (off_x + gimp_item_get_width (item))); y2 = CLAMP (y2, off_y, (off_y + gimp_item_get_height (item))); mask_offset_x = x1; mask_offset_y = y1; /* translate mask bounds to drawable coords */ x1 -= off_x; y1 -= off_y; x2 -= off_x; y2 -= off_y; } else { mask_offset_x = x1; mask_offset_y = y1; } buffer = gegl_buffer_new (GEGL_RECTANGLE (0, 0, x2 - x1, y2 - y1), gimp_drawable_get_format_with_alpha (drawable)); switch (fill_type) { case GIMP_FILL_FOREGROUND: case GIMP_FILL_BACKGROUND: case GIMP_FILL_WHITE: case GIMP_FILL_TRANSPARENT: { GeglColor *gegl_color = gimp_gegl_color_new (color); gegl_buffer_set_color (buffer, NULL, gegl_color); g_object_unref (gegl_color); } break; case GIMP_FILL_PATTERN: { GeglBuffer *pattern_buffer = gimp_pattern_create_buffer (pattern); gegl_buffer_set_pattern (buffer, NULL, pattern_buffer, -x1, -y1); g_object_unref (pattern_buffer); } break; } gimp_gegl_apply_opacity (buffer, NULL, NULL, buffer, mask_buffer, -mask_offset_x, -mask_offset_y, 1.0); g_object_unref (mask_buffer); /* Apply it to the image */ gimp_drawable_apply_buffer (drawable, buffer, GEGL_RECTANGLE (0, 0, x2 - x1, y2 - y1), TRUE, C_("undo-type", "Bucket Fill"), opacity, paint_mode, NULL, x1, y1); g_object_unref (buffer); gimp_drawable_update (drawable, x1, y1, x2 - x1, y2 - y1); gimp_unset_busy (image->gimp); }
gboolean gimp_edit_fill_full (GimpImage *image, GimpDrawable *drawable, const GimpRGB *color, GimpPattern *pattern, gdouble opacity, GimpLayerModeEffects paint_mode, const gchar *undo_desc) { GeglBuffer *dest_buffer; const Babl *format; gint x, y, width, height; g_return_val_if_fail (GIMP_IS_IMAGE (image), FALSE); g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), FALSE); g_return_val_if_fail (gimp_item_is_attached (GIMP_ITEM (drawable)), FALSE); g_return_val_if_fail (color != NULL || pattern != NULL, FALSE); if (! gimp_item_mask_intersect (GIMP_ITEM (drawable), &x, &y, &width, &height)) return TRUE; /* nothing to do, but the fill succeeded */ if (pattern && babl_format_has_alpha (gimp_temp_buf_get_format (pattern->mask)) && ! gimp_drawable_has_alpha (drawable)) { format = gimp_drawable_get_format_with_alpha (drawable); } else { format = gimp_drawable_get_format (drawable); } dest_buffer = gegl_buffer_new (GEGL_RECTANGLE (0, 0, width, height), format); if (pattern) { GeglBuffer *src_buffer = gimp_pattern_create_buffer (pattern); gegl_buffer_set_pattern (dest_buffer, NULL, src_buffer, 0, 0); g_object_unref (src_buffer); } else { GeglColor *gegl_color = gimp_gegl_color_new (color); gegl_buffer_set_color (dest_buffer, NULL, gegl_color); g_object_unref (gegl_color); } gimp_drawable_apply_buffer (drawable, dest_buffer, GEGL_RECTANGLE (0, 0, width, height), TRUE, undo_desc, opacity, paint_mode, NULL, x, y); g_object_unref (dest_buffer); gimp_drawable_update (drawable, x, y, width, height); return TRUE; }
void gimp_edit_fill (GimpImage *image, GimpDrawable *drawable, GimpFillOptions *options, const gchar *undo_desc) { GeglBuffer *dest_buffer; GimpPattern *pattern = NULL; GimpRGB color; const Babl *format; gint x, y, width, height; g_return_if_fail (GIMP_IS_IMAGE (image)); 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 */ switch (gimp_fill_options_get_style (options)) { case GIMP_FILL_STYLE_SOLID: gimp_context_get_foreground (GIMP_CONTEXT (options), &color); break; case GIMP_FILL_STYLE_PATTERN: pattern = gimp_context_get_pattern (GIMP_CONTEXT (options)); break; } if (pattern && babl_format_has_alpha (gimp_temp_buf_get_format (pattern->mask)) && ! gimp_drawable_has_alpha (drawable)) { format = gimp_drawable_get_format_with_alpha (drawable); } else { format = gimp_drawable_get_format (drawable); } dest_buffer = gegl_buffer_new (GEGL_RECTANGLE (0, 0, width, height), format); if (pattern) { GeglBuffer *src_buffer = gimp_pattern_create_buffer (pattern); gegl_buffer_set_pattern (dest_buffer, NULL, src_buffer, 0, 0); g_object_unref (src_buffer); } else { GeglColor *gegl_color = gimp_gegl_color_new (&color); gegl_buffer_set_color (dest_buffer, NULL, gegl_color); g_object_unref (gegl_color); } if (! undo_desc) undo_desc = gimp_fill_options_get_undo_desc (options); gimp_drawable_apply_buffer (drawable, dest_buffer, GEGL_RECTANGLE (0, 0, width, height), TRUE, undo_desc, gimp_context_get_opacity (GIMP_CONTEXT (options)), gimp_context_get_paint_mode (GIMP_CONTEXT (options)), NULL, x, y); g_object_unref (dest_buffer); gimp_drawable_update (drawable, x, y, width, height); }
static void gimp_clone_motion (GimpSourceCore *source_core, GimpDrawable *drawable, GimpPaintOptions *paint_options, const GimpCoords *coords, gdouble opacity, GimpPickable *src_pickable, GeglBuffer *src_buffer, GeglRectangle *src_rect, gint src_offset_x, gint src_offset_y, GeglBuffer *paint_buffer, gint paint_buffer_x, gint paint_buffer_y, gint paint_area_offset_x, gint paint_area_offset_y, gint paint_area_width, gint paint_area_height) { GimpPaintCore *paint_core = GIMP_PAINT_CORE (source_core); GimpCloneOptions *options = GIMP_CLONE_OPTIONS (paint_options); GimpSourceOptions *source_options = GIMP_SOURCE_OPTIONS (paint_options); GimpContext *context = GIMP_CONTEXT (paint_options); GimpImage *image = gimp_item_get_image (GIMP_ITEM (drawable)); gdouble fade_point; gdouble force; if (gimp_source_core_use_source (source_core, source_options)) { gegl_buffer_copy (src_buffer, GEGL_RECTANGLE (src_rect->x, src_rect->y, paint_area_width, paint_area_height), paint_buffer, GEGL_RECTANGLE (paint_area_offset_x, paint_area_offset_y, 0, 0)); } else if (options->clone_type == GIMP_PATTERN_CLONE) { GimpPattern *pattern = gimp_context_get_pattern (context); GeglBuffer *src_buffer = gimp_pattern_create_buffer (pattern); gegl_buffer_set_pattern (paint_buffer, GEGL_RECTANGLE (paint_area_offset_x, paint_area_offset_y, paint_area_width, paint_area_height), src_buffer, - paint_buffer_x - src_offset_x, - paint_buffer_y - src_offset_y); g_object_unref (src_buffer); } else { g_return_if_reached (); } fade_point = gimp_paint_options_get_fade (paint_options, image, paint_core->pixel_dist); force = gimp_dynamics_get_linear_value (GIMP_BRUSH_CORE (paint_core)->dynamics, GIMP_DYNAMICS_OUTPUT_FORCE, coords, paint_options, fade_point); gimp_brush_core_paste_canvas (GIMP_BRUSH_CORE (paint_core), drawable, coords, MIN (opacity, GIMP_OPACITY_OPAQUE), gimp_context_get_opacity (context), gimp_context_get_paint_mode (context), gimp_paint_options_get_brush_mode (paint_options), force, /* In fixed mode, paint incremental so the * individual brushes are properly applied * on top of each other. * Otherwise the stuff we paint is seamless * and we don't need intermediate masking. */ source_options->align_mode == GIMP_SOURCE_ALIGN_FIXED ? GIMP_PAINT_INCREMENTAL : GIMP_PAINT_CONSTANT); }