diff options
Diffstat (limited to '')
-rw-r--r-- | libgimp/gimpregioniterator.c | 397 |
1 files changed, 397 insertions, 0 deletions
diff --git a/libgimp/gimpregioniterator.c b/libgimp/gimpregioniterator.c new file mode 100644 index 0000000..ad866c5 --- /dev/null +++ b/libgimp/gimpregioniterator.c @@ -0,0 +1,397 @@ +/* LIBGIMP - The GIMP Library + * Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball + * + * gimpregioniterator.c + * + * This library is free software: you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + * <https://www.gnu.org/licenses/>. + */ + +#include "config.h" + +#include <glib.h> + +#define GIMP_DISABLE_DEPRECATION_WARNINGS + +#include "gimp.h" +#include "gimpregioniterator.h" + + +/** + * SECTION: gimpregioniterator + * @title: gimpregioniterator + * @short_description: Functions to traverse a pixel regions. + * + * The GimpRgnIterator functions provide a variety of common ways to + * traverse a PixelRegion, using a pre-defined function pointer per + * pixel. + **/ + + +struct _GimpRgnIterator +{ + GimpDrawable *drawable; + gint x1; + gint y1; + gint x2; + gint y2; +}; + + +static void gimp_rgn_iterator_iter_single (GimpRgnIterator *iter, + GimpPixelRgn *srcPR, + GimpRgnFuncSrc func, + gpointer data); +static void gimp_rgn_render_row (const guchar *src, + guchar *dest, + gint col, + gint bpp, + GimpRgnFunc2 func, + gpointer data); +static void gimp_rgn_render_region (const GimpPixelRgn *srcPR, + const GimpPixelRgn *destPR, + GimpRgnFunc2 func, + gpointer data); + + +/** + * gimp_rgn_iterator_new: + * @drawable: a #GimpDrawable + * @unused: ignored + * + * Creates a new #GimpRgnIterator for @drawable. The #GimpRunMode + * parameter is ignored. Use gimp_rgn_iterator_free() to free this + * iterator. + * + * Return value: a newly allocated #GimpRgnIterator. + **/ +GimpRgnIterator * +gimp_rgn_iterator_new (GimpDrawable *drawable, + GimpRunMode unused) +{ + GimpRgnIterator *iter; + + g_return_val_if_fail (drawable != NULL, NULL); + + iter = g_slice_new (GimpRgnIterator); + + iter->drawable = drawable; + + gimp_drawable_mask_bounds (drawable->drawable_id, + &iter->x1, &iter->y1, + &iter->x2, &iter->y2); + + return iter; +} + +/** + * gimp_rgn_iterator_free: + * @iter: a #GimpRgnIterator + * + * Frees the resources allocated for @iter. + **/ +void +gimp_rgn_iterator_free (GimpRgnIterator *iter) +{ + g_return_if_fail (iter != NULL); + + g_slice_free (GimpRgnIterator, iter); +} + +void +gimp_rgn_iterator_src (GimpRgnIterator *iter, + GimpRgnFuncSrc func, + gpointer data) +{ + GimpPixelRgn srcPR; + + g_return_if_fail (iter != NULL); + + gimp_pixel_rgn_init (&srcPR, iter->drawable, + iter->x1, iter->y1, + iter->x2 - iter->x1, iter->y2 - iter->y1, + FALSE, FALSE); + gimp_rgn_iterator_iter_single (iter, &srcPR, func, data); +} + +void +gimp_rgn_iterator_src_dest (GimpRgnIterator *iter, + GimpRgnFuncSrcDest func, + gpointer data) +{ + GimpPixelRgn srcPR, destPR; + gint x1, y1, x2, y2; + gint bpp; + gint count; + gpointer pr; + gint total_area; + gint area_so_far; + + g_return_if_fail (iter != NULL); + + x1 = iter->x1; + y1 = iter->y1; + x2 = iter->x2; + y2 = iter->y2; + + total_area = (x2 - x1) * (y2 - y1); + area_so_far = 0; + + gimp_pixel_rgn_init (&srcPR, iter->drawable, x1, y1, x2 - x1, y2 - y1, + FALSE, FALSE); + gimp_pixel_rgn_init (&destPR, iter->drawable, x1, y1, x2 - x1, y2 - y1, + TRUE, TRUE); + + bpp = srcPR.bpp; + + for (pr = gimp_pixel_rgns_register (2, &srcPR, &destPR), count = 0; + pr != NULL; + pr = gimp_pixel_rgns_process (pr), count++) + { + const guchar *src = srcPR.data; + guchar *dest = destPR.data; + gint y; + + for (y = srcPR.y; y < srcPR.y + srcPR.h; y++) + { + const guchar *s = src; + guchar *d = dest; + gint x; + + for (x = srcPR.x; x < srcPR.x + srcPR.w; x++) + { + func (x, y, s, d, bpp, data); + + s += bpp; + d += bpp; + } + + src += srcPR.rowstride; + dest += destPR.rowstride; + } + + area_so_far += srcPR.w * srcPR.h; + + if ((count % 16) == 0) + gimp_progress_update ((gdouble) area_so_far / (gdouble) total_area); + } + + gimp_drawable_flush (iter->drawable); + gimp_drawable_merge_shadow (iter->drawable->drawable_id, TRUE); + gimp_drawable_update (iter->drawable->drawable_id, + x1, y1, x2 - x1, y2 - y1); +} + +void +gimp_rgn_iterator_dest (GimpRgnIterator *iter, + GimpRgnFuncDest func, + gpointer data) +{ + GimpPixelRgn destPR; + + g_return_if_fail (iter != NULL); + + gimp_pixel_rgn_init (&destPR, iter->drawable, + iter->x1, iter->y1, + iter->x2 - iter->x1, iter->y2 - iter->y1, + TRUE, TRUE); + gimp_rgn_iterator_iter_single (iter, &destPR, (GimpRgnFuncSrc) func, data); + + /* update the processed region */ + gimp_drawable_flush (iter->drawable); + gimp_drawable_merge_shadow (iter->drawable->drawable_id, TRUE); + gimp_drawable_update (iter->drawable->drawable_id, + iter->x1, iter->y1, + iter->x2 - iter->x1, iter->y2 - iter->y1); +} + + +void +gimp_rgn_iterate1 (GimpDrawable *drawable, + GimpRunMode unused, + GimpRgnFunc1 func, + gpointer data) +{ + GimpPixelRgn srcPR; + gint x1, y1, x2, y2; + gpointer pr; + gint total_area; + gint area_so_far; + gint count; + + g_return_if_fail (drawable != NULL); + + gimp_drawable_mask_bounds (drawable->drawable_id, &x1, &y1, &x2, &y2); + + total_area = (x2 - x1) * (y2 - y1); + area_so_far = 0; + + if (total_area <= 0) + return; + + gimp_pixel_rgn_init (&srcPR, drawable, + x1, y1, (x2 - x1), (y2 - y1), FALSE, FALSE); + + for (pr = gimp_pixel_rgns_register (1, &srcPR), count = 0; + pr != NULL; + pr = gimp_pixel_rgns_process (pr), count++) + { + const guchar *src = srcPR.data; + gint y; + + for (y = 0; y < srcPR.h; y++) + { + const guchar *s = src; + gint x; + + for (x = 0; x < srcPR.w; x++) + { + func (s, srcPR.bpp, data); + s += srcPR.bpp; + } + + src += srcPR.rowstride; + } + + area_so_far += srcPR.w * srcPR.h; + + if ((count % 16) == 0) + gimp_progress_update ((gdouble) area_so_far / (gdouble) total_area); + } +} + +void +gimp_rgn_iterate2 (GimpDrawable *drawable, + GimpRunMode unused, + GimpRgnFunc2 func, + gpointer data) +{ + GimpPixelRgn srcPR, destPR; + gint x1, y1, x2, y2; + gpointer pr; + gint total_area; + gint area_so_far; + gint count; + + g_return_if_fail (drawable != NULL); + + gimp_drawable_mask_bounds (drawable->drawable_id, &x1, &y1, &x2, &y2); + + total_area = (x2 - x1) * (y2 - y1); + area_so_far = 0; + + if (total_area <= 0) + return; + + /* Initialize the pixel regions. */ + gimp_pixel_rgn_init (&srcPR, drawable, x1, y1, (x2 - x1), (y2 - y1), + FALSE, FALSE); + gimp_pixel_rgn_init (&destPR, drawable, x1, y1, (x2 - x1), (y2 - y1), + TRUE, TRUE); + + for (pr = gimp_pixel_rgns_register (2, &srcPR, &destPR), count = 0; + pr != NULL; + pr = gimp_pixel_rgns_process (pr), count++) + { + gimp_rgn_render_region (&srcPR, &destPR, func, data); + + area_so_far += srcPR.w * srcPR.h; + + if ((count % 16) == 0) + gimp_progress_update ((gdouble) area_so_far / (gdouble) total_area); + } + + /* update the processed region */ + gimp_drawable_flush (drawable); + gimp_drawable_merge_shadow (drawable->drawable_id, TRUE); + gimp_drawable_update (drawable->drawable_id, x1, y1, (x2 - x1), (y2 - y1)); +} + +static void +gimp_rgn_iterator_iter_single (GimpRgnIterator *iter, + GimpPixelRgn *srcPR, + GimpRgnFuncSrc func, + gpointer data) +{ + gpointer pr; + gint total_area; + gint area_so_far; + gint count; + + total_area = (iter->x2 - iter->x1) * (iter->y2 - iter->y1); + area_so_far = 0; + + for (pr = gimp_pixel_rgns_register (1, srcPR), count = 0; + pr != NULL; + pr = gimp_pixel_rgns_process (pr), count++) + { + const guchar *src = srcPR->data; + gint y; + + for (y = srcPR->y; y < srcPR->y + srcPR->h; y++) + { + const guchar *s = src; + gint x; + + for (x = srcPR->x; x < srcPR->x + srcPR->w; x++) + { + func (x, y, s, srcPR->bpp, data); + s += srcPR->bpp; + } + + src += srcPR->rowstride; + } + + area_so_far += srcPR->w * srcPR->h; + + if ((count % 16) == 0) + gimp_progress_update ((gdouble) area_so_far / (gdouble) total_area); + } +} + +static void +gimp_rgn_render_row (const guchar *src, + guchar *dest, + gint col, /* row width in pixels */ + gint bpp, + GimpRgnFunc2 func, + gpointer data) +{ + while (col--) + { + func (src, dest, bpp, data); + + src += bpp; + dest += bpp; + } +} + +static void +gimp_rgn_render_region (const GimpPixelRgn *srcPR, + const GimpPixelRgn *destPR, + GimpRgnFunc2 func, + gpointer data) +{ + const guchar *src = srcPR->data; + guchar *dest = destPR->data; + gint row; + + for (row = 0; row < srcPR->h; row++) + { + gimp_rgn_render_row (src, dest, srcPR->w, srcPR->bpp, func, data); + + src += srcPR->rowstride; + dest += destPR->rowstride; + } +} |