[gimp/goat-invasion] app: port GimpHeal to GEGL, using insane buffer casting tricks
- From: Michael Natterer <mitch src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gimp/goat-invasion] app: port GimpHeal to GEGL, using insane buffer casting tricks
- Date: Tue, 3 Apr 2012 19:16:25 +0000 (UTC)
commit b7d250c4b5553cb1c5b6c5b88911ef9ab274587f
Author: Michael Natterer <mitch gimp org>
Date: Tue Apr 3 21:06:45 2012 +0200
app: port GimpHeal to GEGL, using insane buffer casting tricks
app/paint/gimpheal.c | 324 ++++++++++++++++++++++++++------------------------
1 files changed, 170 insertions(+), 154 deletions(-)
---
diff --git a/app/paint/gimpheal.c b/app/paint/gimpheal.c
index 86951f8..a740840 100644
--- a/app/paint/gimpheal.c
+++ b/app/paint/gimpheal.c
@@ -26,7 +26,6 @@
#include "paint-types.h"
-#include "base/pixel-region.h"
#include "base/temp-buf.h"
#include "gegl/gimp-gegl-utils.h"
@@ -70,32 +69,6 @@ static gboolean gimp_heal_start (GimpPaintCore *paint_core,
const GimpCoords *coords,
GError **error);
-static void gimp_heal_sub (PixelRegion *topPR,
- PixelRegion *bottomPR,
- gdouble *result);
-
-static void gimp_heal_add (gdouble *first,
- PixelRegion *secondPR,
- PixelRegion *resultPR);
-
-static gdouble gimp_heal_laplace_iteration (gdouble *matrix,
- gint height,
- gint depth,
- gint width,
- gdouble *solution,
- guchar *mask);
-
-static void gimp_heal_laplace_loop (gdouble *matrix,
- gint height,
- gint depth,
- gint width,
- gdouble *solution,
- guchar *mask);
-
-static PixelRegion *gimp_heal_region (PixelRegion *tempPR,
- PixelRegion *srcPR,
- const TempBuf *mask_buf);
-
static void gimp_heal_motion (GimpSourceCore *source_core,
GimpDrawable *drawable,
GimpPaintOptions *paint_options,
@@ -174,92 +147,92 @@ gimp_heal_start (GimpPaintCore *paint_core,
return TRUE;
}
-/* Subtract bottomPR from topPR and store the result as a double
+/* Subtract bottom from top and store in result as a double
*/
static void
-gimp_heal_sub (PixelRegion *topPR,
- PixelRegion *bottomPR,
- gdouble *result)
+gimp_heal_sub (GeglBuffer *top_buffer,
+ const GeglRectangle *top_rect,
+ GeglBuffer *bottom_buffer,
+ const GeglRectangle *bottom_rect,
+ GeglBuffer *result_buffer,
+ const GeglRectangle *result_rect)
{
- gint i, j, k;
+ GeglBufferIterator *iter;
+ const Babl *format = gegl_buffer_get_format (top_buffer);
+ gint bpp = babl_format_get_bytes_per_pixel (format);
- gint height = topPR->h;
- gint width = topPR->w;
- gint depth = topPR->bytes;
+ gegl_buffer_set_format (top_buffer, babl_format_n (babl_type ("u8"), bpp));
+ gegl_buffer_set_format (bottom_buffer, babl_format_n (babl_type ("u8"), bpp));
- guchar *t_data = topPR->data;
- guchar *b_data = bottomPR->data;
+ iter = gegl_buffer_iterator_new (top_buffer, top_rect, 0, NULL,
+ GEGL_BUFFER_READ, GEGL_ABYSS_NONE);
- guchar *t;
- guchar *b;
- gdouble *r = result;
+ gegl_buffer_iterator_add (iter, bottom_buffer, bottom_rect, 0, NULL,
+ GEGL_BUFFER_READ, GEGL_ABYSS_NONE);
- g_assert (topPR->bytes == bottomPR->bytes);
+ gegl_buffer_iterator_add (iter, result_buffer, result_rect, 0,
+ babl_format_n (babl_type ("double"), bpp),
+ GEGL_BUFFER_WRITE, GEGL_ABYSS_NONE);
- for (i = 0; i < height; i++)
+ while (gegl_buffer_iterator_next (iter))
{
- t = t_data;
- b = b_data;
-
- for (j = 0; j < width; j++)
- {
- for (k = 0; k < depth; k++)
- {
- r[k] = (gdouble) (t[k]) - (gdouble) (b[k]);
- }
- t += depth;
- b += depth;
- r += depth;
- }
+ guchar *t = iter->data[0];
+ guchar *b = iter->data[1];
+ gdouble *r = iter->data[2];
+ gint length = iter->length * bpp;
- t_data += topPR->rowstride;
- b_data += bottomPR->rowstride;
+ while (length--)
+ *r++ = (gdouble) *t++ - (gdouble) *b++;
}
+
+ gegl_buffer_set_format (top_buffer, NULL);
+ gegl_buffer_set_format (bottom_buffer, NULL);
}
-/* Add first to secondPR and store the result as a PixelRegion
+/* Add first to second and store in result
*/
static void
-gimp_heal_add (gdouble *first,
- PixelRegion *secondPR,
- PixelRegion *resultPR)
+gimp_heal_add (GeglBuffer *first_buffer,
+ const GeglRectangle *first_rect,
+ GeglBuffer *second_buffer,
+ const GeglRectangle *second_rect,
+ GeglBuffer *result_buffer,
+ const GeglRectangle *result_rect)
{
- gint i, j, k;
+ GeglBufferIterator *iter;
+ const Babl *format = gegl_buffer_get_format (result_buffer);
+ gint bpp = babl_format_get_bytes_per_pixel (format);
- gint height = secondPR->h;
- gint width = secondPR->w;
- gint depth = secondPR->bytes;
+ gegl_buffer_set_format (second_buffer, babl_format_n (babl_type ("u8"), bpp));
+ gegl_buffer_set_format (result_buffer, babl_format_n (babl_type ("u8"), bpp));
- guchar *s_data = secondPR->data;
- guchar *r_data = resultPR->data;
+ iter = gegl_buffer_iterator_new (first_buffer, first_rect, 0,
+ babl_format_n (babl_type ("double"), bpp),
+ GEGL_BUFFER_READ, GEGL_ABYSS_NONE);
- gdouble *f = first;
- guchar *s;
- guchar *r;
+ gegl_buffer_iterator_add (iter, second_buffer, second_rect, 0, NULL,
+ GEGL_BUFFER_READ, GEGL_ABYSS_NONE);
- g_assert (secondPR->bytes == resultPR->bytes);
+ gegl_buffer_iterator_add (iter, result_buffer, result_rect, 0, NULL,
+ GEGL_BUFFER_WRITE, GEGL_ABYSS_NONE);
- for (i = 0; i < height; i++)
+ while (gegl_buffer_iterator_next (iter))
{
- s = s_data;
- r = r_data;
+ gdouble *f = iter->data[0];
+ guchar *s = iter->data[1];
+ guchar *r = iter->data[2];
+ gint length = iter->length * bpp;
- for (j = 0; j < width; j++)
+ while (length--)
{
- for (k = 0; k < depth; k++)
- {
- r[k] = (guchar) CLAMP0255 (ROUND (((gdouble) (f[k])) +
- ((gdouble) (s[k]))));
- }
+ gdouble tmp = ROUND (*f++ + (gdouble) *s++);
- f += depth;
- s += depth;
- r += depth;
+ *r++ = (guchar) CLAMP0255 (tmp);
}
-
- s_data += secondPR->rowstride;
- r_data += resultPR->rowstride;
}
+
+ gegl_buffer_set_format (second_buffer, NULL);
+ gegl_buffer_set_format (result_buffer, NULL);
}
/* Perform one iteration of the laplace solver for matrix. Store the
@@ -411,29 +384,77 @@ gimp_heal_laplace_loop (gdouble *matrix,
* T. Georgiev, "Photoshop Healing Brush: a Tool for Seamless Cloning
* http://www.tgeorgiev.net/Photoshop_Healing.pdf
*/
-static PixelRegion *
-gimp_heal_region (PixelRegion *tempPR,
- PixelRegion *srcPR,
- const TempBuf *mask_buf)
+static void
+gimp_heal (GeglBuffer *src_buffer,
+ const GeglRectangle *src_rect,
+ GeglBuffer *dest_buffer,
+ const GeglRectangle *dest_rect,
+ GeglBuffer *mask_buffer,
+ const GeglRectangle *mask_rect)
{
- gdouble *i_1 = g_new (gdouble, tempPR->h * tempPR->bytes * tempPR->w);
- gdouble *i_2 = g_new (gdouble, tempPR->h * tempPR->bytes * tempPR->w);
- guchar *mask = temp_buf_get_data (mask_buf);
-
- /* substract pattern to image and store the result as a double in i_1 */
- gimp_heal_sub (tempPR, srcPR, i_1);
+ const Babl *src_format;
+ const Babl *dest_format;
+ gint src_bpp;
+ gint dest_bpp;
+ gint width;
+ gint height;
+ gdouble *i_1;
+ gdouble *i_2;
+ GeglBuffer *i_1_buffer;
+ GeglBuffer *i_2_buffer;
+ guchar *mask;
+
+ src_format = gegl_buffer_get_format (src_buffer);
+ dest_format = gegl_buffer_get_format (dest_buffer);
+
+ src_bpp = babl_format_get_bytes_per_pixel (src_format);
+ dest_bpp = babl_format_get_bytes_per_pixel (dest_format);
+
+ width = gegl_buffer_get_width (src_buffer);
+ height = gegl_buffer_get_height (src_buffer);
+
+ g_return_if_fail (src_bpp == dest_bpp);
+
+ i_1 = g_new (gdouble, width * height * src_bpp);
+ i_2 = g_new (gdouble, width * height * src_bpp);
+
+ i_1_buffer =
+ gegl_buffer_linear_new_from_data (i_1,
+ babl_format_n (babl_type ("double"),
+ src_bpp),
+ GEGL_RECTANGLE (0, 0, width, height),
+ GEGL_AUTO_ROWSTRIDE,
+ (GDestroyNotify) g_free, i_1);
+ i_2_buffer =
+ gegl_buffer_linear_new_from_data (i_2,
+ babl_format_n (babl_type ("double"),
+ src_bpp),
+ GEGL_RECTANGLE (0, 0, width, height),
+ GEGL_AUTO_ROWSTRIDE,
+ (GDestroyNotify) g_free, i_2);
+
+ /* substract pattern from image and store the result as a double in i_1 */
+ gimp_heal_sub (dest_buffer, dest_rect,
+ src_buffer, src_rect,
+ i_1_buffer, GEGL_RECTANGLE (0, 0, width, height));
+
+ mask = g_new (guchar, mask_rect->width * mask_rect->height);
+
+ gegl_buffer_get (mask_buffer, mask_rect, 1.0, babl_format ("Y u8"),
+ mask, GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE);
/* FIXME: is a faster implementation needed? */
- gimp_heal_laplace_loop (i_1, tempPR->h, tempPR->bytes, tempPR->w, i_2, mask);
+ gimp_heal_laplace_loop (i_1, height, src_bpp, width, i_2, mask);
- /* add solution to original image and store in tempPR */
- gimp_heal_add (i_2, srcPR, tempPR);
+ g_free (mask);
- /* clean up */
- g_free (i_1);
- g_free (i_2);
+ /* add solution to original image and store in dest */
+ gimp_heal_add (i_2_buffer, GEGL_RECTANGLE (0, 0, width, height),
+ src_buffer, src_rect,
+ dest_buffer, dest_rect);
- return tempPR;
+ g_object_unref (i_1_buffer);
+ g_object_unref (i_2_buffer);
}
static void
@@ -460,11 +481,9 @@ gimp_heal_motion (GimpSourceCore *source_core,
GimpDynamics *dynamics = GIMP_BRUSH_CORE (paint_core)->dynamics;
GimpDynamicsOutput *hardness_output;
GimpImage *image = gimp_item_get_image (GIMP_ITEM (drawable));
- TempBuf *src_temp_buf;
- TempBuf *dest_temp_buf;
+ GeglBuffer *src_copy;
GeglBuffer *dest_buffer;
- PixelRegion srcPR;
- PixelRegion destPR;
+ GeglBuffer *mask_buffer;
const TempBuf *mask_buf;
gdouble fade_point;
gdouble hardness;
@@ -485,32 +504,37 @@ gimp_heal_motion (GimpSourceCore *source_core,
GIMP_BRUSH_HARD,
hardness);
- /* copy the source buffer because we are going to modify it */
- {
- GeglBuffer *tmp;
-
- src_temp_buf = temp_buf_new (src_rect->width, src_rect->height,
- gimp_drawable_bytes_with_alpha (drawable),
- 0, 0, NULL);
-
- tmp = gimp_temp_buf_create_buffer (src_temp_buf,
- gimp_drawable_get_format_with_alpha (drawable),
- FALSE);
+ /* check that all buffers are of the same size */
+ if (src_rect->width != gegl_buffer_get_width (paint_buffer) ||
+ src_rect->height != gegl_buffer_get_height (paint_buffer) ||
+ src_rect->width != mask_buf->width ||
+ src_rect->height != mask_buf->height)
+ {
+ /* this generally means that the source point has hit the edge
+ * of the layer, so it is not an error and we should not
+ * complain, just don't do anything
+ */
+ return;
+ }
- gegl_buffer_copy (src_buffer, src_rect,
- tmp, GEGL_RECTANGLE (0, 0, 0, 0));
- g_object_unref (tmp);
- }
+ src_copy =
+ gegl_buffer_new (GEGL_RECTANGLE (0, 0,
+ src_rect->width,
+ src_rect->height),
+ gimp_drawable_get_format_with_alpha (drawable));
- dest_temp_buf = temp_buf_new (gegl_buffer_get_width (paint_buffer),
- gegl_buffer_get_height (paint_buffer),
- gimp_drawable_bytes_with_alpha (drawable),
- 0, 0, NULL);
+ gegl_buffer_copy (src_buffer,
+ src_rect,
+ src_copy,
+ GEGL_RECTANGLE (0, 0,
+ src_rect->width,
+ src_rect->height));
dest_buffer =
- gimp_temp_buf_create_buffer (dest_temp_buf,
- gimp_drawable_get_format_with_alpha (drawable),
- TRUE);
+ gegl_buffer_new (GEGL_RECTANGLE (0, 0,
+ gegl_buffer_get_width (paint_buffer),
+ gegl_buffer_get_height (paint_buffer)),
+ gimp_drawable_get_format_with_alpha (drawable));
gegl_buffer_copy (gimp_drawable_get_buffer (drawable),
GEGL_RECTANGLE (paint_buffer_x, paint_buffer_y,
@@ -519,31 +543,21 @@ gimp_heal_motion (GimpSourceCore *source_core,
dest_buffer,
GEGL_RECTANGLE (0, 0, 0, 0));
- /* check that srcPR, tempPR, destPR, and mask_buf are the same size */
- if (src_temp_buf->width != dest_temp_buf->width ||
- src_temp_buf->height != dest_temp_buf->height ||
- src_temp_buf->width != mask_buf->width ||
- src_temp_buf->height != mask_buf->height)
- {
- /* this generally means that the source point has hit the edge of the
- layer, so it is not an error and we should not complain, just
- don't do anything */
-
- temp_buf_free (src_temp_buf);
- g_object_unref (dest_buffer);
-
- return;
- }
-
- pixel_region_init_temp_buf (&srcPR, src_temp_buf,
- 0, 0,
- mask_buf->width, mask_buf->height);
- pixel_region_init_temp_buf (&destPR, dest_temp_buf,
- 0, 0,
- mask_buf->width, mask_buf->height);
-
- /* heal destPR using srcPR */
- gimp_heal_region (&destPR, &srcPR, mask_buf);
+ mask_buffer = gimp_temp_buf_create_buffer ((TempBuf *) mask_buf,
+ NULL, FALSE);
+
+ gimp_heal (src_copy,
+ GEGL_RECTANGLE (0, 0,
+ gegl_buffer_get_width (src_copy),
+ gegl_buffer_get_height (src_copy)),
+ dest_buffer,
+ GEGL_RECTANGLE (0, 0,
+ gegl_buffer_get_width (dest_buffer),
+ gegl_buffer_get_height (dest_buffer)),
+ mask_buffer,
+ GEGL_RECTANGLE (0, 0,
+ gegl_buffer_get_width (mask_buffer),
+ gegl_buffer_get_height (mask_buffer)));
gegl_buffer_copy (dest_buffer,
GEGL_RECTANGLE (0, 0, mask_buf->width, mask_buf->height),
@@ -553,7 +567,9 @@ gimp_heal_motion (GimpSourceCore *source_core,
paint_area_width,
paint_area_height));
+ g_object_unref (src_copy);
g_object_unref (dest_buffer);
+ g_object_unref (mask_buffer);
/* replace the canvas with our healed data */
gimp_brush_core_replace_canvas (GIMP_BRUSH_CORE (paint_core), drawable,
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]