mirror of https://github.com/GNOME/gimp.git
396 lines
11 KiB
C
396 lines
11 KiB
C
/* 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
|
|
* <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include "config.h"
|
|
|
|
#include <glib.h>
|
|
|
|
#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 thsi
|
|
* 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;
|
|
}
|
|
}
|