diff --git a/ChangeLog b/ChangeLog index 86cc10ccdf..d056e7d3c3 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,17 @@ +2006-09-05 Michael Natterer + + * app/paint/gimpsourcecore.[ch] (gimp_source_core_motion): do a + lot of stuff that was duplicated in clone and heal. Added lots of + parameters to GimpSourceCore::motion() to get the stuff down to + clone and heal. + + * app/paint/gimpclone.c (gimp_clone_motion): changed accordingly. + + * app/paint/gimpheal.c (gimp_heal_motion): ditto. Made it work for + dest_drawable != src_pickable. Always add alpha to all buffers and + convert the source buffer to the dest drawable's color space + because the algorithm works only on buffers of same depth. + 2006-09-04 Sven Neumann * app/display/gimpdisplayshell.c diff --git a/app/paint/gimpclone.c b/app/paint/gimpclone.c index d664d1dc6d..5cc7e5c45d 100644 --- a/app/paint/gimpclone.c +++ b/app/paint/gimpclone.c @@ -53,7 +53,14 @@ static void gimp_clone_paint (GimpPaintCore *paint_core, static void gimp_clone_motion (GimpSourceCore *source_core, GimpDrawable *drawable, - GimpPaintOptions *paint_options); + GimpPaintOptions *paint_options, + gdouble opacity, + GimpImage *src_image, + GimpPickable *src_pickable, + PixelRegion *srcPR, + TempBuf *paint_area, + gint paint_area_offset_x, + gint paint_area_offset_y); static void gimp_clone_line_image (GimpImage *dest, GimpImage *src, @@ -136,141 +143,46 @@ gimp_clone_paint (GimpPaintCore *paint_core, static void gimp_clone_motion (GimpSourceCore *source_core, GimpDrawable *drawable, - GimpPaintOptions *paint_options) + GimpPaintOptions *paint_options, + gdouble opacity, + GimpImage *src_image, + GimpPickable *src_pickable, + PixelRegion *srcPR, + TempBuf *paint_area, + gint paint_area_offset_x, + gint paint_area_offset_y) { - 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); - GimpPressureOptions *pressure_options = paint_options->pressure_options; + 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; - GimpImage *src_image = NULL; - GimpPickable *src_pickable = NULL; - guchar *s; - guchar *d; - TempBuf *area; gpointer pr = NULL; gint y; - gint x1, y1, x2, y2; - TileManager *src_tiles; - PixelRegion srcPR, destPR; + PixelRegion destPR; GimpPattern *pattern = NULL; - gdouble opacity; - gint offset_x; - gint offset_y; image = gimp_item_get_image (GIMP_ITEM (drawable)); - opacity = gimp_paint_options_get_fade (paint_options, image, - paint_core->pixel_dist); - if (opacity == 0.0) - return; - - /* make local copies because we change them */ - offset_x = source_core->offset_x; - offset_y = source_core->offset_y; - - /* Make sure we still have a source if we are doing image cloning */ - if (options->clone_type == GIMP_IMAGE_CLONE) - { - if (! source_core->src_drawable) - return; - - src_pickable = GIMP_PICKABLE (source_core->src_drawable); - src_image = gimp_pickable_get_image (src_pickable); - - if (source_options->sample_merged) - { - gint off_x, off_y; - - src_pickable = GIMP_PICKABLE (src_image->projection); - - gimp_item_offsets (GIMP_ITEM (source_core->src_drawable), - &off_x, &off_y); - - offset_x += off_x; - offset_y += off_y; - } - - gimp_pickable_flush (src_pickable); - } - - area = gimp_paint_core_get_paint_area (paint_core, drawable, paint_options); - if (! area) - return; - + /* configure the destination */ switch (options->clone_type) { case GIMP_IMAGE_CLONE: - /* Set the paint area to transparent */ - temp_buf_data_clear (area); + pixel_region_init_temp_buf (&destPR, paint_area, + paint_area_offset_x, paint_area_offset_y, + srcPR->w, srcPR->h); - src_tiles = gimp_pickable_get_tiles (src_pickable); - - x1 = CLAMP (area->x + offset_x, - 0, tile_manager_width (src_tiles)); - y1 = CLAMP (area->y + offset_y, - 0, tile_manager_height (src_tiles)); - x2 = CLAMP (area->x + offset_x + area->width, - 0, tile_manager_width (src_tiles)); - y2 = CLAMP (area->y + offset_y + area->height, - 0, tile_manager_height (src_tiles)); - - if (!(x2 - x1) || !(y2 - y1)) - return; - - /* If the source image is different from the destination, - * then we should copy straight from the destination 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 - */ - if ((source_options->sample_merged && - (src_image != image)) || - - (! source_options->sample_merged && - (source_core->src_drawable != drawable))) - { - pixel_region_init (&srcPR, src_tiles, - x1, y1, x2 - x1, y2 - y1, FALSE); - } - else - { - TempBuf *orig; - - /* get the original image */ - if (source_options->sample_merged) - orig = gimp_paint_core_get_orig_proj (paint_core, - src_pickable, - x1, y1, x2, y2); - else - orig = gimp_paint_core_get_orig_image (paint_core, - GIMP_DRAWABLE (src_pickable), - x1, y1, x2, y2); - - pixel_region_init_temp_buf (&srcPR, orig, - 0, 0, x2 - x1, y2 - y1); - } - - offset_x = x1 - (area->x + offset_x); - offset_y = y1 - (area->y + offset_y); - - /* configure the destination */ - pixel_region_init_temp_buf (&destPR, area, - offset_x, offset_y, srcPR.w, srcPR.h); - - pr = pixel_regions_register (2, &srcPR, &destPR); + pr = pixel_regions_register (2, srcPR, &destPR); break; case GIMP_PATTERN_CLONE: pattern = gimp_context_get_pattern (context); - - if (!pattern) + if (! pattern) return; - /* configure the destination */ - pixel_region_init_temp_buf (&destPR, area, - 0, 0, area->width, area->height); + pixel_region_init_temp_buf (&destPR, paint_area, + 0, 0, + paint_area->width, paint_area->height); pr = pixel_regions_register (1, &destPR); break; @@ -278,8 +190,8 @@ gimp_clone_motion (GimpSourceCore *source_core, for (; pr != NULL; pr = pixel_regions_process (pr)) { - s = srcPR.data; - d = destPR.data; + guchar *s = srcPR->data; + guchar *d = destPR.data; for (y = 0; y < destPR.h; y++) { @@ -289,15 +201,15 @@ gimp_clone_motion (GimpSourceCore *source_core, gimp_clone_line_image (image, src_image, drawable, src_pickable, s, d, - srcPR.bytes, destPR.bytes, destPR.w); - s += srcPR.rowstride; + srcPR->bytes, destPR.bytes, destPR.w); + s += srcPR->rowstride; break; case GIMP_PATTERN_CLONE: gimp_clone_line_pattern (image, drawable, pattern, d, - area->x + offset_x, - area->y + y + offset_y, + paint_area->x + paint_area_offset_x, + paint_area->y + y + paint_area_offset_y, destPR.bytes, destPR.w); break; } @@ -306,7 +218,7 @@ gimp_clone_motion (GimpSourceCore *source_core, } } - if (pressure_options->opacity) + if (paint_options->pressure_options->opacity) opacity *= PRESSURE_SCALE * paint_core->cur_coords.pressure; gimp_brush_core_paste_canvas (GIMP_BRUSH_CORE (paint_core), drawable, diff --git a/app/paint/gimpheal.c b/app/paint/gimpheal.c index b951c2822c..0335c42dd3 100644 --- a/app/paint/gimpheal.c +++ b/app/paint/gimpheal.c @@ -51,7 +51,14 @@ static void gimp_heal_motion (GimpSourceCore *source_core, GimpDrawable *drawable, - GimpPaintOptions *paint_options); + GimpPaintOptions *paint_options, + gdouble opacity, + GimpImage *src_image, + GimpPickable *src_pickable, + PixelRegion *srcPR, + TempBuf *paint_area, + gint paint_area_offset_x, + gint paint_area_offset_y); G_DEFINE_TYPE (GimpHeal, gimp_heal, GIMP_TYPE_SOURCE_CORE) @@ -329,75 +336,45 @@ gimp_heal_region (PixelRegion *tempPR, static void gimp_heal_motion (GimpSourceCore *source_core, GimpDrawable *drawable, - GimpPaintOptions *paint_options) + GimpPaintOptions *paint_options, + gdouble opacity, + GimpImage *src_image, + GimpPickable *src_pickable, + PixelRegion *srcPR, + TempBuf *paint_area, + gint paint_area_offset_x, + gint paint_area_offset_y) { - GimpPaintCore *paint_core = GIMP_PAINT_CORE (source_core); - GimpSourceOptions *options = GIMP_SOURCE_OPTIONS (paint_options); - GimpContext *context = GIMP_CONTEXT (paint_options); - GimpPressureOptions *pressure_options = paint_options->pressure_options; - GimpImage *image; - GimpImage *src_image = NULL; - GimpPickable *src_pickable = NULL; - TileManager *src_tiles; - TempBuf *area; - TempBuf *temp; - gdouble opacity; - PixelRegion tempPR; - PixelRegion srcPR; - PixelRegion destPR; - gint offset_x; - gint offset_y; + GimpPaintCore *paint_core = GIMP_PAINT_CORE (source_core); + GimpContext *context = GIMP_CONTEXT (paint_options); + TempBuf *src; + TempBuf *temp; + PixelRegion origPR; + PixelRegion tempPR; + PixelRegion destPR; + GimpImageType src_type; - /* get the image */ - image = gimp_item_get_image (GIMP_ITEM (drawable)); - - /* display a warning about indexed images and return */ - if (GIMP_IMAGE_TYPE_IS_INDEXED (drawable->type)) + if (gimp_drawable_is_indexed (drawable)) { g_message (_("Indexed images are not currently supported.")); return; } - opacity = gimp_paint_options_get_fade (paint_options, image, - paint_core->pixel_dist); + src_type = gimp_pickable_get_image_type (src_pickable); - if (opacity == 0.0) - return; + /* we need the source area with alpha and we modify it, so make a copy */ + src = temp_buf_new (srcPR->w, srcPR->h, + GIMP_IMAGE_TYPE_BYTES (GIMP_IMAGE_TYPE_WITH_ALPHA (src_type)), + 0, 0, NULL); + pixel_region_init_temp_buf (&tempPR, src, 0, 0, src->width, src->height); - if (! source_core->src_drawable) - return; + if (GIMP_IMAGE_TYPE_HAS_ALPHA (src_type)) + copy_region (srcPR, &tempPR); + else + add_alpha_region (srcPR, &tempPR); - /* prepare the regions to get data from */ - src_pickable = GIMP_PICKABLE (source_core->src_drawable); - src_image = gimp_pickable_get_image (src_pickable); - - /* make local copies */ - offset_x = source_core->offset_x; - offset_y = source_core->offset_y; - - /* adjust offsets and pickable if we are merging layers */ - if (options->sample_merged) - { - gint off_x, off_y; - - src_pickable = GIMP_PICKABLE (src_image->projection); - - gimp_item_offsets (GIMP_ITEM (source_core->src_drawable), &off_x, &off_y); - - offset_x += off_x; - offset_y += off_y; - } - - /* get the canvas area */ - area = gimp_paint_core_get_paint_area (paint_core, drawable, paint_options); - if (!area) - return; - - /* clear the area where we want to paint */ - temp_buf_data_clear (area); - - /* get the source tiles */ - src_tiles = gimp_pickable_get_tiles (src_pickable); + /* reinitialize srcPR */ + pixel_region_init_temp_buf (srcPR, src, 0, 0, src->width, src->height); /* FIXME: the area under the cursor and the source area should be x% larger * than the brush size. Otherwise the brush must be a lot bigger than the @@ -406,107 +383,91 @@ gimp_heal_motion (GimpSourceCore *source_core, /* Get the area underneath the cursor */ { - TempBuf *orig; - gint x1, x2, y1, y2; + TileManager *tiles = gimp_drawable_get_tiles (drawable); + TempBuf *orig; + gint x1, x2, y1, y2; - x1 = CLAMP (area->x, - 0, tile_manager_width (src_tiles)); - y1 = CLAMP (area->y, - 0, tile_manager_height (src_tiles)); - x2 = CLAMP (area->x + area->width, - 0, tile_manager_width (src_tiles)); - y2 = CLAMP (area->y + area->height, - 0, tile_manager_height (src_tiles)); + x1 = CLAMP (paint_area->x, + 0, tile_manager_width (tiles)); + y1 = CLAMP (paint_area->y, + 0, tile_manager_height (tiles)); + x2 = CLAMP (paint_area->x + paint_area->width, + 0, tile_manager_width (tiles)); + y2 = CLAMP (paint_area->y + paint_area->height, + 0, tile_manager_height (tiles)); if (! (x2 - x1) || (! (y2 - y1))) - return; + { + temp_buf_free (src); + return; + } /* get the original image data at the cursor location */ - if (options->sample_merged) - orig = gimp_paint_core_get_orig_proj (paint_core, - src_pickable, - x1, y1, x2, y2); - else - orig = gimp_paint_core_get_orig_image (paint_core, - GIMP_DRAWABLE (src_pickable), - x1, y1, x2, y2); + orig = gimp_paint_core_get_orig_image (paint_core, drawable, + x1, y1, x2, y2); - pixel_region_init_temp_buf (&srcPR, orig, 0, 0, x2 - x1, y2 - y1); + pixel_region_init_temp_buf (&origPR, orig, 0, 0, x2 - x1, y2 - y1); } - temp = temp_buf_new (srcPR.w, srcPR.h, srcPR.bytes, 0, 0, NULL); + temp = temp_buf_new (origPR.w, origPR.h, + gimp_drawable_bytes_with_alpha (drawable), + 0, 0, NULL); + pixel_region_init_temp_buf (&tempPR, temp, 0, 0, origPR.w, origPR.h); - pixel_region_init_temp_buf (&tempPR, temp, 0, 0, srcPR.w, srcPR.h); + if (gimp_drawable_has_alpha (drawable)) + copy_region (&origPR, &tempPR); + else + add_alpha_region (&origPR, &tempPR); - copy_region (&srcPR, &tempPR); + if (tempPR.bytes != srcPR->bytes) + { + TempBuf *temp2; + gboolean new_buf; - /* now tempPR holds the data under the cursor */ + temp2 = gimp_image_transform_temp_buf (gimp_item_get_image (GIMP_ITEM (drawable)), + drawable, + temp, &new_buf); - /* get a copy of the location we will sample from */ - { - TempBuf *orig; - gint x1, x2, y1, y2; + if (new_buf) + temp_buf_free (temp); - x1 = CLAMP (area->x + offset_x, - 0, tile_manager_width (src_tiles)); - y1 = CLAMP (area->y + offset_y, - 0, tile_manager_height (src_tiles)); - x2 = CLAMP (area->x + offset_x + area->width, - 0, tile_manager_width (src_tiles)); - y2 = CLAMP (area->y + offset_y + area->height, - 0, tile_manager_height (src_tiles)); + temp = temp2; + } - if (! (x2 - x1) || (! (y2 - y1))) - return; + /* reinitialize tempPR */ + pixel_region_init_temp_buf (&tempPR, temp, 0, 0, temp->width, temp->height); - /* get the original image data at the sample location */ - if (options->sample_merged) - orig = gimp_paint_core_get_orig_proj (paint_core, - src_pickable, - x1, y1, x2, y2); - else - orig = gimp_paint_core_get_orig_image (paint_core, - GIMP_DRAWABLE (src_pickable), - x1, y1, x2, y2); - - pixel_region_init_temp_buf (&srcPR, orig, 0, 0, x2 - x1, y2 - y1); - - /* set the proper offset */ - offset_x = x1 - (area->x + offset_x); - offset_y = y1 - (area->y + offset_y); - } - - /* now srcPR holds the source area to sample from */ + /* now tempPR holds the data under the cursor and + * srcPR holds the area to sample from + */ /* get the destination to paint to */ - pixel_region_init_temp_buf (&destPR, area, offset_x, offset_y, srcPR.w, srcPR.h); + pixel_region_init_temp_buf (&destPR, paint_area, + paint_area_offset_x, paint_area_offset_y, + srcPR->w, srcPR->h); /* FIXME: Can we ensure that this is true in the code above? * Is it already guaranteed to be true before we get here? */ /* check that srcPR, tempPR, and destPR are the same size */ - if ((srcPR.w != tempPR.w ) || (srcPR.w != destPR.w ) || - (srcPR.h != tempPR.h ) || (srcPR.h != destPR.h )) + if ((srcPR->w != tempPR.w) || (srcPR->w != destPR.w) || + (srcPR->h != tempPR.h) || (srcPR->h != destPR.h)) { g_message (_("Source and destination regions are not the same size.")); + temp_buf_free (src); + temp_buf_free (temp); return; } /* heal tempPR using srcPR */ - gimp_heal_region (&tempPR, &srcPR); + gimp_heal_region (&tempPR, srcPR); - /* re-initialize tempPR so that it can be used within copy_region */ - pixel_region_init_data (&tempPR, tempPR.data, tempPR.bytes, tempPR.rowstride, - 0, 0, tempPR.w, tempPR.h); + /* reinitialize tempPR */ + pixel_region_init_temp_buf (&tempPR, temp, 0, 0, temp->width, temp->height); - /* add an alpha region to the area if necessary. - * sample_merged doesn't need an alpha because its always 4 bpp */ - if ((! gimp_drawable_has_alpha (drawable)) && (! options->sample_merged)) - add_alpha_region (&tempPR, &destPR); - else - copy_region (&tempPR, &destPR); + copy_region (&tempPR, &destPR); /* check the brush pressure */ - if (pressure_options->opacity) + if (paint_options->pressure_options->opacity) opacity *= PRESSURE_SCALE * paint_core->cur_coords.pressure; /* replace the canvas with our healed data */ @@ -516,4 +477,7 @@ gimp_heal_motion (GimpSourceCore *source_core, gimp_context_get_opacity (context), gimp_paint_options_get_brush_mode (paint_options), GIMP_PAINT_CONSTANT); + + temp_buf_free (src); + temp_buf_free (temp); } diff --git a/app/paint/gimpsourcecore.c b/app/paint/gimpsourcecore.c index 0dbe636a38..cfeaa5f632 100644 --- a/app/paint/gimpsourcecore.c +++ b/app/paint/gimpsourcecore.c @@ -24,9 +24,14 @@ #include "paint-types.h" +#include "base/temp-buf.h" +#include "base/tile-manager.h" +#include "base/pixel-region.h" + #include "core/gimp.h" #include "core/gimpdrawable.h" #include "core/gimpimage.h" +#include "core/gimppickable.h" #include "gimpsourcecore.h" #include "gimpsourceoptions.h" @@ -269,9 +274,118 @@ gimp_source_core_motion (GimpSourceCore *source_core, GimpDrawable *drawable, GimpPaintOptions *paint_options) { + GimpPaintCore *paint_core = GIMP_PAINT_CORE (source_core); + GimpSourceOptions *options = GIMP_SOURCE_OPTIONS (paint_options); + GimpImage *image = gimp_item_get_image (GIMP_ITEM (drawable)); + GimpImage *src_image = NULL; + GimpPickable *src_pickable = NULL; + PixelRegion srcPR; + TempBuf *paint_area; + gint offset_x; + gint offset_y; + gdouble opacity; + + opacity = gimp_paint_options_get_fade (paint_options, image, + paint_core->pixel_dist); + if (opacity == 0.0) + return; + + offset_x = source_core->offset_x; + offset_y = source_core->offset_y; + + if (options->use_source) + { + if (! source_core->src_drawable) + return; + + src_pickable = GIMP_PICKABLE (source_core->src_drawable); + src_image = gimp_pickable_get_image (src_pickable); + + if (options->sample_merged) + { + gint off_x, off_y; + + src_pickable = GIMP_PICKABLE (src_image->projection); + + gimp_item_offsets (GIMP_ITEM (source_core->src_drawable), + &off_x, &off_y); + + offset_x += off_x; + offset_y += off_y; + } + + gimp_pickable_flush (src_pickable); + } + + paint_area = gimp_paint_core_get_paint_area (paint_core, drawable, + paint_options); + if (! paint_area) + return; + + if (options->use_source) + { + TileManager *src_tiles = gimp_pickable_get_tiles (src_pickable); + gint x1, y1; + gint x2, y2; + + x1 = CLAMP (paint_area->x + offset_x, + 0, tile_manager_width (src_tiles)); + y1 = CLAMP (paint_area->y + offset_y, + 0, tile_manager_height (src_tiles)); + x2 = CLAMP (paint_area->x + offset_x + paint_area->width, + 0, tile_manager_width (src_tiles)); + y2 = CLAMP (paint_area->y + offset_y + paint_area->height, + 0, tile_manager_height (src_tiles)); + + if (!(x2 - x1) || !(y2 - y1)) + return; + + /* 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 + */ + if (( options->sample_merged && (src_image != image)) || + (! options->sample_merged && (source_core->src_drawable != drawable))) + { + pixel_region_init (&srcPR, src_tiles, + x1, y1, x2 - x1, y2 - y1, FALSE); + } + else + { + TempBuf *orig; + + /* get the original image */ + if (options->sample_merged) + orig = gimp_paint_core_get_orig_proj (paint_core, + src_pickable, + x1, y1, x2, y2); + else + orig = gimp_paint_core_get_orig_image (paint_core, + GIMP_DRAWABLE (src_pickable), + x1, y1, x2, y2); + + pixel_region_init_temp_buf (&srcPR, orig, + 0, 0, x2 - x1, y2 - y1); + } + + offset_x = x1 - (paint_area->x + offset_x); + offset_y = y1 - (paint_area->y + offset_y); + } + + /* Set the paint area to transparent */ + temp_buf_data_clear (paint_area); + GIMP_SOURCE_CORE_GET_CLASS (source_core)->motion (source_core, drawable, - paint_options); + paint_options, + opacity, + src_image, + src_pickable, + &srcPR, + paint_area, + offset_x, offset_y); } static void diff --git a/app/paint/gimpsourcecore.h b/app/paint/gimpsourcecore.h index b6d908783a..673e409d24 100644 --- a/app/paint/gimpsourcecore.h +++ b/app/paint/gimpsourcecore.h @@ -58,7 +58,14 @@ struct _GimpSourceCoreClass void (* motion) (GimpSourceCore *source_core, GimpDrawable *drawable, - GimpPaintOptions *paint_options); + GimpPaintOptions *paint_options, + gdouble opacity, + GimpImage *src_image, + GimpPickable *src_pickable, + PixelRegion *srcPR, + TempBuf *paint_area, + gint paint_area_offset_x, + gint paint_area_offset_y); };