home *** CD-ROM | disk | FTP | other *** search
- /* The GIMP -- an image manipulation program
- * Copyright (C) 1995 Spencer Kimball and Peter Mattis
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
- #include "config.h"
-
- #include <stdlib.h>
- #include <string.h>
-
- #include <gtk/gtk.h>
-
- #include "apptypes.h"
-
- #include "appenv.h"
- #include "channel.h"
- #include "drawable.h"
- #include "gdisplay.h"
- #include "gimage_mask.h"
- #include "layer.h"
- #include "paint_funcs.h"
- #include "parasitelist.h"
- #include "temp_buf.h"
- #include "undo.h"
- #include "gimpsignal.h"
- #include "gimppreviewcache.h"
-
- #include "channel_pvt.h"
- #include "tile.h"
-
- #include "gimplut.h"
- #include "lut_funcs.h"
-
- #include "libgimp/gimpmath.h"
-
- #include "libgimp/gimpintl.h"
-
-
- enum {
- REMOVED,
- LAST_SIGNAL
- };
-
- static void gimp_channel_class_init (GimpChannelClass *klass);
- static void gimp_channel_init (GimpChannel *channel);
- static void gimp_channel_destroy (GtkObject *object);
-
- static TempBuf * channel_preview_private (Channel *channel,
- gint width,
- gint height);
-
- static guint channel_signals[LAST_SIGNAL] = { 0 };
-
- static GimpDrawableClass *parent_class = NULL;
-
- GtkType
- gimp_channel_get_type ()
- {
- static GtkType channel_type = 0;
-
- if (!channel_type)
- {
- GtkTypeInfo channel_info =
- {
- "GimpChannel",
- sizeof (GimpChannel),
- sizeof (GimpChannelClass),
- (GtkClassInitFunc) gimp_channel_class_init,
- (GtkObjectInitFunc) gimp_channel_init,
- /* reserved_1 */ NULL,
- /* reserved_2 */ NULL,
- (GtkClassInitFunc) NULL,
- };
-
- channel_type = gtk_type_unique (gimp_drawable_get_type (), &channel_info);
- }
-
- return channel_type;
- }
-
- static void
- gimp_channel_class_init (GimpChannelClass *class)
- {
- GtkObjectClass *object_class;
-
- object_class = (GtkObjectClass*) class;
- parent_class = gtk_type_class (gimp_drawable_get_type ());
-
- channel_signals[REMOVED] =
- gimp_signal_new ("removed",
- 0, object_class->type, 0, gimp_sigtype_void);
-
- gtk_object_class_add_signals (object_class, channel_signals, LAST_SIGNAL);
-
- object_class->destroy = gimp_channel_destroy;
- }
-
- static void
- gimp_channel_init (GimpChannel *channel)
- {
- }
-
- /**************************/
- /* Function definitions */
- /**************************/
-
- static void
- channel_validate (TileManager *tm,
- Tile *tile)
- {
- /* Set the contents of the tile to empty */
- memset (tile_data_pointer (tile, 0, 0),
- TRANSPARENT_OPACITY, tile_size (tile));
- }
-
- Channel *
- channel_new (GimpImage *gimage,
- gint width,
- gint height,
- gchar *name,
- gint opacity,
- guchar *col)
- {
- Channel * channel;
- gint i;
-
- channel = gtk_type_new (gimp_channel_get_type ());
-
- gimp_drawable_configure (GIMP_DRAWABLE (channel),
- gimage, width, height, GRAY_GIMAGE, name);
-
- /* set the channel color and opacity */
- for (i = 0; i < 3; i++)
- channel->col[i] = col[i];
-
- channel->opacity = opacity;
- channel->show_masked = TRUE;
-
- /* selection mask variables */
- channel->empty = TRUE;
- channel->segs_in = NULL;
- channel->segs_out = NULL;
- channel->num_segs_in = 0;
- channel->num_segs_out = 0;
- channel->bounds_known = TRUE;
- channel->boundary_known = TRUE;
- channel->x1 = 0;
- channel->y1 = 0;
- channel->x2 = width;
- channel->y2 = height;
-
- return channel;
- }
-
- Channel *
- channel_ref (Channel *channel)
- {
- gtk_object_ref (GTK_OBJECT (channel));
- gtk_object_sink (GTK_OBJECT (channel));
-
- return channel;
- }
-
- void
- channel_unref (Channel *channel)
- {
- gtk_object_unref (GTK_OBJECT (channel));
- }
-
- Channel *
- channel_copy (Channel *channel)
- {
- gchar *channel_name;
- Channel *new_channel;
- PixelRegion srcPR, destPR;
- gchar *ext;
- gint number;
- gchar *name;
- gint len;
-
- /* formulate the new channel name */
- name = channel_get_name (channel);
- ext = strrchr (name, '#');
- len = strlen (_("copy"));
- if ((strlen (name) >= len &&
- strcmp (&name[strlen (name) - len], _("copy")) == 0) ||
- (ext && (number = atoi (ext + 1)) > 0 &&
- ((int)(log10 (number) + 1)) == strlen (ext + 1)))
- /* don't have redundant "copy"s */
- channel_name = g_strdup (name);
- else
- channel_name = g_strdup_printf (_("%s copy"), name);
-
- /* allocate a new channel object */
- new_channel = channel_new (GIMP_DRAWABLE (channel)->gimage,
- GIMP_DRAWABLE (channel)->width,
- GIMP_DRAWABLE (channel)->height,
- channel_name, channel->opacity, channel->col);
- GIMP_DRAWABLE (new_channel)->visible = GIMP_DRAWABLE (channel)->visible;
- new_channel->show_masked = channel->show_masked;
-
- /* copy the contents across channels */
- pixel_region_init (&srcPR, GIMP_DRAWABLE (channel)->tiles, 0, 0,
- GIMP_DRAWABLE (channel)->width,
- GIMP_DRAWABLE (channel)->height, FALSE);
- pixel_region_init (&destPR, GIMP_DRAWABLE (new_channel)->tiles,
- 0, 0,
- GIMP_DRAWABLE (channel)->width,
- GIMP_DRAWABLE (channel)->height, TRUE);
- copy_region (&srcPR, &destPR);
-
- /* copy the parasites */
- GIMP_DRAWABLE (new_channel)->parasites
- = parasite_list_copy (GIMP_DRAWABLE (channel)->parasites);
-
- /* free up the channel_name memory */
- g_free (channel_name);
-
- return new_channel;
- }
-
- void
- channel_set_name (Channel *channel,
- gchar *name)
- {
- gimp_drawable_set_name (GIMP_DRAWABLE (channel), name);
- }
-
- gchar *
- channel_get_name (Channel *channel)
- {
- return gimp_drawable_get_name (GIMP_DRAWABLE (channel));
- }
-
- void
- channel_set_color (Channel *channel,
- guchar *color)
- {
- gint i;
-
- if (color)
- {
- for (i = 0; i < 3; i++)
- channel->col[i] = color[i];
- }
- }
-
- guchar *
- channel_get_color (Channel *channel)
- {
- return (GIMP_CHANNEL (channel)->col);
- }
-
- int
- channel_get_opacity (Channel *channel)
- {
- return channel->opacity;
- }
-
- void
- channel_set_opacity (Channel *channel,
- gint opacity)
- {
- if (opacity >=0 && opacity <= 100)
- channel->opacity = (gint) (opacity * 255) / 100;
- }
-
- Channel *
- channel_get_ID (gint ID)
- {
- GimpDrawable *drawable;
-
- drawable = drawable_get_ID (ID);
- if (drawable && GIMP_IS_CHANNEL (drawable))
- return GIMP_CHANNEL (drawable);
- else
- return NULL;
- }
-
- void
- channel_delete (Channel *channel)
- {
- gtk_object_unref (GTK_OBJECT (channel));
- }
-
- static void
- gimp_channel_destroy (GtkObject *object)
- {
- GimpChannel *channel;
-
- g_return_if_fail (object != NULL);
- g_return_if_fail (GIMP_IS_CHANNEL (object));
-
- channel = GIMP_CHANNEL (object);
-
- /* free the segments? */
- if (channel->segs_in)
- g_free (channel->segs_in);
- if (channel->segs_out)
- g_free (channel->segs_out);
-
- if (GTK_OBJECT_CLASS (parent_class)->destroy)
- (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
-
- }
-
- /* The removed signal is sent out when the channel is no longer
- * associcated with an image. It's needed because channels aren't
- * destroyed immediately, but kept around for undo purposes. Connect
- * to the removed signal to update bits of UI that are tied to a
- * particular layer. */
- void
- channel_removed (Channel *channel,
- gpointer data)
- {
- g_return_if_fail (channel != NULL);
- g_return_if_fail (GIMP_IS_CHANNEL (channel));
-
- gtk_signal_emit (GTK_OBJECT (channel), channel_signals[REMOVED]);
- }
-
-
- void
- channel_scale (Channel *channel,
- gint new_width,
- gint new_height)
- {
- PixelRegion srcPR, destPR;
- TileManager *new_tiles;
-
- if (new_width == 0 || new_height == 0)
- return;
-
- /* Update the old channel position */
- drawable_update (GIMP_DRAWABLE (channel),
- 0, 0,
- GIMP_DRAWABLE (channel)->width,
- GIMP_DRAWABLE (channel)->height);
-
- /* Configure the pixel regions */
- pixel_region_init (&srcPR, GIMP_DRAWABLE (channel)->tiles,
- 0, 0,
- GIMP_DRAWABLE (channel)->width,
- GIMP_DRAWABLE (channel)->height, FALSE);
-
- /* Allocate the new channel, configure dest region */
- new_tiles = tile_manager_new (new_width, new_height, 1);
- pixel_region_init (&destPR, new_tiles, 0, 0, new_width, new_height, TRUE);
-
- /* Add an alpha channel */
- scale_region (&srcPR, &destPR);
-
- /* Push the channel on the undo stack */
- undo_push_channel_mod (GIMP_DRAWABLE (channel)->gimage, channel);
-
- /* Configure the new channel */
- GIMP_DRAWABLE (channel)->tiles = new_tiles;
- GIMP_DRAWABLE (channel)->width = new_width;
- GIMP_DRAWABLE (channel)->height = new_height;
-
- /* bounds are now unknown */
- channel->bounds_known = FALSE;
-
- /* Update the new channel position */
- drawable_update (GIMP_DRAWABLE (channel),
- 0, 0,
- GIMP_DRAWABLE (channel)->width,
- GIMP_DRAWABLE (channel)->height);
- }
-
- void
- channel_resize (Channel *channel,
- gint new_width,
- gint new_height,
- gint offx,
- gint offy)
- {
- PixelRegion srcPR, destPR;
- TileManager *new_tiles;
- guchar bg = 0;
- gint clear;
- gint w, h;
- gint x1, y1, x2, y2;
-
- if (!new_width || !new_height)
- return;
-
- x1 = CLAMP (offx, 0, new_width);
- y1 = CLAMP (offy, 0, new_height);
- x2 = CLAMP ((offx + GIMP_DRAWABLE (channel)->width), 0, new_width);
- y2 = CLAMP ((offy + GIMP_DRAWABLE (channel)->height), 0, new_height);
- w = x2 - x1;
- h = y2 - y1;
-
- if (offx > 0)
- {
- x1 = 0;
- x2 = offx;
- }
- else
- {
- x1 = -offx;
- x2 = 0;
- }
-
- if (offy > 0)
- {
- y1 = 0;
- y2 = offy;
- }
- else
- {
- y1 = -offy;
- y2 = 0;
- }
-
- /* Update the old channel position */
- drawable_update (GIMP_DRAWABLE (channel),
- 0, 0,
- GIMP_DRAWABLE (channel)->width,
- GIMP_DRAWABLE (channel)->height);
-
- /* Configure the pixel regions */
- pixel_region_init (&srcPR, GIMP_DRAWABLE (channel)->tiles,
- x1, y1, w, h, FALSE);
-
- /* Determine whether the new channel needs to be initially cleared */
- if ((new_width > GIMP_DRAWABLE (channel)->width) ||
- (new_height > GIMP_DRAWABLE (channel)->height) ||
- (x2 || y2))
- clear = TRUE;
- else
- clear = FALSE;
-
- /* Allocate the new channel, configure dest region */
- new_tiles = tile_manager_new (new_width, new_height, 1);
-
- /* Set to black (empty--for selections) */
- if (clear)
- {
- pixel_region_init (&destPR, new_tiles, 0, 0, new_width, new_height, TRUE);
- color_region (&destPR, &bg);
- }
-
- /* copy from the old to the new */
- pixel_region_init (&destPR, new_tiles, x2, y2, w, h, TRUE);
- if (w && h)
- copy_region (&srcPR, &destPR);
-
- /* Push the channel on the undo stack */
- undo_push_channel_mod (GIMP_DRAWABLE (channel)->gimage, channel);
-
- /* Configure the new channel */
- GIMP_DRAWABLE (channel)->tiles = new_tiles;
- GIMP_DRAWABLE (channel)->width = new_width;
- GIMP_DRAWABLE (channel)->height = new_height;
-
- /* bounds are now unknown */
- channel->bounds_known = FALSE;
-
- /* update the new channel area */
- drawable_update (GIMP_DRAWABLE (channel),
- 0, 0,
- GIMP_DRAWABLE (channel)->width,
- GIMP_DRAWABLE (channel)->height);
- }
-
- void
- channel_update (Channel *channel)
- {
- drawable_update (GIMP_DRAWABLE (channel),
- 0, 0,
- GIMP_DRAWABLE (channel)->width,
- GIMP_DRAWABLE (channel)->height);
- gdisplays_flush ();
- }
-
- /**********************/
- /* access functions */
- /**********************/
-
- gboolean
- channel_toggle_visibility (Channel *channel)
- {
- GIMP_DRAWABLE (channel)->visible = !GIMP_DRAWABLE (channel)->visible;
-
- return GIMP_DRAWABLE (channel)->visible;
- }
-
- TempBuf *
- channel_preview (Channel *channel,
- gint width,
- gint height)
- {
- /* Ok prime the cache with a large preview if the cache is invalid */
- if (! GIMP_DRAWABLE (channel)->preview_valid &&
- width <= PREVIEW_CACHE_PRIME_WIDTH &&
- height <= PREVIEW_CACHE_PRIME_HEIGHT &&
- GIMP_DRAWABLE (channel)->gimage &&
- GIMP_DRAWABLE (channel)->gimage->width > PREVIEW_CACHE_PRIME_WIDTH &&
- GIMP_DRAWABLE (channel)->gimage->height > PREVIEW_CACHE_PRIME_HEIGHT)
- {
- TempBuf * tb = channel_preview_private (channel,
- PREVIEW_CACHE_PRIME_WIDTH,
- PREVIEW_CACHE_PRIME_HEIGHT);
-
- /* Save the 2nd call */
- if (width == PREVIEW_CACHE_PRIME_WIDTH &&
- height == PREVIEW_CACHE_PRIME_HEIGHT)
- return tb;
- }
-
- /* Second call - should NOT visit the tile cache...*/
- return channel_preview_private (channel, width, height);
- }
-
- static TempBuf *
- channel_preview_private (Channel *channel,
- gint width,
- gint height)
- {
- MaskBuf *preview_buf;
- PixelRegion srcPR;
- PixelRegion destPR;
- gint subsample;
- TempBuf *ret_buf;
-
- g_return_val_if_fail (channel != NULL, NULL);
- g_return_val_if_fail (GIMP_IS_CHANNEL (channel), NULL);
-
- /* The easy way */
- if (GIMP_DRAWABLE (channel)->preview_valid &&
- (ret_buf =
- gimp_preview_cache_get (& (GIMP_DRAWABLE (channel)->preview_cache),
- width, height)))
- return ret_buf;
- /* The hard way */
- else
- {
- /* calculate 'acceptable' subsample */
- subsample = 1;
- if (width < 1) width = 1;
- if (height < 1) height = 1;
- while ((width * (subsample + 1) * 2 < GIMP_DRAWABLE (channel)->width) &&
- (height * (subsample + 1) * 2 < GIMP_DRAWABLE (channel)->height))
- subsample = subsample + 1;
-
- pixel_region_init (&srcPR, GIMP_DRAWABLE (channel)->tiles,
- 0, 0,
- GIMP_DRAWABLE (channel)->width,
- GIMP_DRAWABLE (channel)->height, FALSE);
-
- preview_buf = mask_buf_new (width, height);
- destPR.bytes = 1;
- destPR.x = 0;
- destPR.y = 0;
- destPR.w = width;
- destPR.h = height;
- destPR.rowstride = width;
- destPR.data = mask_buf_data (preview_buf);
-
- subsample_region (&srcPR, &destPR, subsample);
-
- if (!GIMP_DRAWABLE (channel)->preview_valid)
- gimp_preview_cache_invalidate (&(GIMP_DRAWABLE(channel)->preview_cache));
-
- GIMP_DRAWABLE (channel)->preview_valid = TRUE;
- gimp_preview_cache_add (&(GIMP_DRAWABLE (channel)->preview_cache),
- preview_buf);
- return preview_buf;
- }
- }
-
- void
- channel_invalidate_previews (GimpImage* gimage)
- {
- GSList * tmp;
- Channel * channel;
-
- g_return_if_fail (gimage != NULL);
-
- tmp = gimage->channels;
-
- while (tmp)
- {
- channel = (Channel *) tmp->data;
- gimp_drawable_invalidate_preview (GIMP_DRAWABLE (channel), TRUE);
- tmp = g_slist_next (tmp);
- }
- }
-
- Tattoo
- channel_get_tattoo (const Channel *channel)
- {
- return (gimp_drawable_get_tattoo (GIMP_DRAWABLE (channel)));
- }
-
- void
- channel_set_tattoo (const Channel *channel,
- Tattoo value)
- {
- gimp_drawable_set_tattoo (GIMP_DRAWABLE (channel), value);
- }
-
- /******************************/
- /* selection mask functions */
- /******************************/
-
- Channel *
- channel_new_mask (GimpImage *gimage,
- gint width,
- gint height)
- {
- guchar black[3] = {0, 0, 0};
- Channel *new_channel;
-
- /* Create the new channel */
- new_channel = channel_new (gimage, width, height,
- _("Selection Mask"), 127, black);
-
- /* Set the validate procedure */
- tile_manager_set_validate_proc (GIMP_DRAWABLE (new_channel)->tiles,
- channel_validate);
-
- return new_channel;
- }
-
- gboolean
- channel_boundary (Channel *mask,
- BoundSeg **segs_in,
- BoundSeg **segs_out,
- gint *num_segs_in,
- gint *num_segs_out,
- gint x1,
- gint y1,
- gint x2,
- gint y2)
- {
- gint x3, y3, x4, y4;
- PixelRegion bPR;
-
- if (! mask->boundary_known)
- {
- /* free the out of date boundary segments */
- if (mask->segs_in)
- g_free (mask->segs_in);
- if (mask->segs_out)
- g_free (mask->segs_out);
-
- if (channel_bounds (mask, &x3, &y3, &x4, &y4))
- {
- pixel_region_init (&bPR, GIMP_DRAWABLE (mask)->tiles,
- x3, y3, (x4 - x3), (y4 - y3), FALSE);
- mask->segs_out = find_mask_boundary (&bPR, &mask->num_segs_out,
- IgnoreBounds,
- x1, y1,
- x2, y2);
- x1 = MAX (x1, x3);
- y1 = MAX (y1, y3);
- x2 = MIN (x2, x4);
- y2 = MIN (y2, y4);
-
- if (x2 > x1 && y2 > y1)
- {
- pixel_region_init (&bPR, GIMP_DRAWABLE (mask)->tiles,
- 0, 0,
- GIMP_DRAWABLE (mask)->width,
- GIMP_DRAWABLE (mask)->height, FALSE);
- mask->segs_in = find_mask_boundary (&bPR, &mask->num_segs_in,
- WithinBounds,
- x1, y1,
- x2, y2);
- }
- else
- {
- mask->segs_in = NULL;
- mask->num_segs_in = 0;
- }
- }
- else
- {
- mask->segs_in = NULL;
- mask->segs_out = NULL;
- mask->num_segs_in = 0;
- mask->num_segs_out = 0;
- }
- mask->boundary_known = TRUE;
- }
-
- *segs_in = mask->segs_in;
- *segs_out = mask->segs_out;
- *num_segs_in = mask->num_segs_in;
- *num_segs_out = mask->num_segs_out;
-
- return TRUE;
- }
-
- gint
- channel_value (Channel *mask,
- gint x,
- gint y)
- {
- Tile *tile;
- gint val;
-
- /* Some checks to cut back on unnecessary work */
- if (mask->bounds_known)
- {
- if (mask->empty)
- return 0;
- else if (x < mask->x1 || x >= mask->x2 || y < mask->y1 || y >= mask->y2)
- return 0;
- }
- else
- {
- if (x < 0 || x >= GIMP_DRAWABLE (mask)->width ||
- y < 0 || y >= GIMP_DRAWABLE (mask)->height)
- return 0;
- }
-
- tile = tile_manager_get_tile (GIMP_DRAWABLE (mask)->tiles, x, y, TRUE, FALSE);
- val = *(guchar *) (tile_data_pointer (tile, x % TILE_WIDTH, y % TILE_HEIGHT));
- tile_release (tile, FALSE);
-
- return val;
- }
-
- gboolean
- channel_bounds (Channel *mask,
- gint *x1,
- gint *y1,
- gint *x2,
- gint *y2)
- {
- PixelRegion maskPR;
- guchar *data, *data1;
- gint x, y;
- gint ex, ey;
- gint tx1, tx2, ty1, ty2;
- gint minx, maxx;
- gpointer pr;
-
- /* if the mask's bounds have already been reliably calculated... */
- if (mask->bounds_known)
- {
- *x1 = mask->x1;
- *y1 = mask->y1;
- *x2 = mask->x2;
- *y2 = mask->y2;
-
- return !mask->empty;
- }
-
- /* go through and calculate the bounds */
- tx1 = GIMP_DRAWABLE (mask)->width;
- ty1 = GIMP_DRAWABLE (mask)->height;
- tx2 = 0;
- ty2 = 0;
-
- pixel_region_init (&maskPR, GIMP_DRAWABLE (mask)->tiles,
- 0, 0,
- GIMP_DRAWABLE (mask)->width,
- GIMP_DRAWABLE (mask)->height, FALSE);
- for (pr = pixel_regions_register (1, &maskPR);
- pr != NULL;
- pr = pixel_regions_process (pr))
- {
- data1 = data = maskPR.data;
- ex = maskPR.x + maskPR.w;
- ey = maskPR.y + maskPR.h;
- /* only check the pixels if this tile is not fully within the currently
- computed bounds */
- if (maskPR.x < tx1 || ex > tx2 ||
- maskPR.y < ty1 || ey > ty2)
- {
- /* Check upper left and lower right corners to see if we can
- avoid checking the rest of the pixels in this tile */
- if (data[0] && data[maskPR.rowstride*(maskPR.h - 1) + maskPR.w - 1])
- {
- if (maskPR.x < tx1)
- tx1 = maskPR.x;
- if (ex > tx2)
- tx2 = ex;
- if (maskPR.y < ty1)
- ty1 = maskPR.y;
- if (ey > ty2)
- ty2 = ey;
- }
- else
- for (y = maskPR.y; y < ey; y++, data1 += maskPR.rowstride)
- {
- for (x = maskPR.x, data = data1; x < ex; x++, data++)
- if (*data)
- {
- minx = x;
- maxx = x;
- for (; x < ex; x++, data++)
- if (*data)
- maxx = x;
- if (minx < tx1)
- tx1 = minx;
- if (maxx > tx2)
- tx2 = maxx;
- if (y < ty1)
- ty1 = y;
- if (y > ty2)
- ty2 = y;
- }
- }
- }
- }
-
- tx2 = CLAMP (tx2 + 1, 0, GIMP_DRAWABLE (mask)->width);
- ty2 = CLAMP (ty2 + 1, 0, GIMP_DRAWABLE (mask)->height);
-
- if (tx1 == GIMP_DRAWABLE (mask)->width && ty1 == GIMP_DRAWABLE (mask)->height)
- {
- mask->empty = TRUE;
- mask->x1 = 0;
- mask->y1 = 0;
- mask->x2 = GIMP_DRAWABLE (mask)->width;
- mask->y2 = GIMP_DRAWABLE (mask)->height;
- }
- else
- {
- mask->empty = FALSE;
- mask->x1 = tx1;
- mask->y1 = ty1;
- mask->x2 = tx2;
- mask->y2 = ty2;
- }
- mask->bounds_known = TRUE;
-
- *x1 = tx1;
- *x2 = tx2;
- *y1 = ty1;
- *y2 = ty2;
-
- return !mask->empty;
- }
-
- gboolean
- channel_is_empty (Channel *mask)
- {
- PixelRegion maskPR;
- guchar * data;
- gint x, y;
- gpointer pr;
-
- if (mask->bounds_known)
- return mask->empty;
-
- pixel_region_init (&maskPR, GIMP_DRAWABLE (mask)->tiles,
- 0, 0,
- GIMP_DRAWABLE (mask)->width,
- GIMP_DRAWABLE (mask)->height, FALSE);
- for (pr = pixel_regions_register (1, &maskPR);
- pr != NULL;
- pr = pixel_regions_process (pr))
- {
- /* check if any pixel in the mask is non-zero */
- data = maskPR.data;
- for (y = 0; y < maskPR.h; y++)
- for (x = 0; x < maskPR.w; x++)
- if (*data++)
- {
- pixel_regions_process_stop (pr);
- return FALSE;
- }
- }
-
- /* The mask is empty, meaning we can set the bounds as known */
- if (mask->segs_in)
- g_free (mask->segs_in);
- if (mask->segs_out)
- g_free (mask->segs_out);
-
- mask->empty = TRUE;
- mask->segs_in = NULL;
- mask->segs_out = NULL;
- mask->num_segs_in = 0;
- mask->num_segs_out = 0;
- mask->bounds_known = TRUE;
- mask->boundary_known = TRUE;
- mask->x1 = 0;
- mask->y1 = 0;
- mask->x2 = GIMP_DRAWABLE (mask)->width;
- mask->y2 = GIMP_DRAWABLE (mask)->height;
-
- return TRUE;
- }
-
- void
- channel_add_segment (Channel *mask,
- gint x,
- gint y,
- gint width,
- gint value)
- {
- PixelRegion maskPR;
- guchar *data;
- gint val;
- gint x2;
- gpointer pr;
-
- /* check horizontal extents... */
- x2 = x + width;
- if (x2 < 0) x2 = 0;
- if (x2 > GIMP_DRAWABLE (mask)->width) x2 = GIMP_DRAWABLE (mask)->width;
- if (x < 0) x = 0;
- if (x > GIMP_DRAWABLE (mask)->width) x = GIMP_DRAWABLE (mask)->width;
- width = x2 - x;
- if (!width) return;
-
- if (y < 0 || y > GIMP_DRAWABLE (mask)->height)
- return;
-
- pixel_region_init (&maskPR, GIMP_DRAWABLE (mask)->tiles,
- x, y, width, 1, TRUE);
- for (pr = pixel_regions_register (1, &maskPR);
- pr != NULL;
- pr = pixel_regions_process (pr))
- {
- data = maskPR.data;
- width = maskPR.w;
- while (width--)
- {
- val = *data + value;
- if (val > 255)
- val = 255;
- *data++ = val;
- }
- }
- }
-
- void
- channel_sub_segment (Channel *mask,
- gint x,
- gint y,
- gint width,
- gint value)
- {
- PixelRegion maskPR;
- guchar *data;
- gint val;
- gint x2;
- gpointer pr;
-
- /* check horizontal extents... */
- x2 = x + width;
- if (x2 < 0) x2 = 0;
- if (x2 > GIMP_DRAWABLE (mask)->width) x2 = GIMP_DRAWABLE (mask)->width;
- if (x < 0) x = 0;
- if (x > GIMP_DRAWABLE (mask)->width) x = GIMP_DRAWABLE (mask)->width;
- width = x2 - x;
- if (!width) return;
-
- if (y < 0 || y > GIMP_DRAWABLE (mask)->height)
- return;
-
- pixel_region_init (&maskPR, GIMP_DRAWABLE (mask)->tiles, x, y, width, 1, TRUE);
- for (pr = pixel_regions_register (1, &maskPR);
- pr != NULL;
- pr = pixel_regions_process (pr))
- {
- data = maskPR.data;
- width = maskPR.w;
- while (width--)
- {
- val = *data - value;
- if (val < 0)
- val = 0;
- *data++ = val;
- }
- }
- }
-
- void
- channel_combine_rect (Channel *mask,
- ChannelOps op,
- gint x,
- gint y,
- gint w,
- gint h)
- {
- gint x2, y2;
- PixelRegion maskPR;
- guchar color;
-
- y2 = y + h;
- x2 = x + w;
-
- x = CLAMP (x, 0, GIMP_DRAWABLE (mask)->width);
- y = CLAMP (y, 0, GIMP_DRAWABLE (mask)->height);
- x2 = CLAMP (x2, 0, GIMP_DRAWABLE (mask)->width);
- y2 = CLAMP (y2, 0, GIMP_DRAWABLE (mask)->height);
-
- if (x2 - x <= 0 || y2 - y <= 0)
- return;
-
- pixel_region_init (&maskPR, GIMP_DRAWABLE (mask)->tiles,
- x, y, x2 - x, y2 - y, TRUE);
- if (op == ADD || op == REPLACE)
- color = 255;
- else
- color = 0;
- color_region (&maskPR, &color);
-
- /* Determine new boundary */
- if (mask->bounds_known && (op == ADD) && !mask->empty)
- {
- if (x < mask->x1)
- mask->x1 = x;
- if (y < mask->y1)
- mask->y1 = y;
- if ((x + w) > mask->x2)
- mask->x2 = (x + w);
- if ((y + h) > mask->y2)
- mask->y2 = (y + h);
- }
- else if (op == REPLACE || mask->empty)
- {
- mask->empty = FALSE;
- mask->x1 = x;
- mask->y1 = y;
- mask->x2 = x + w;
- mask->y2 = y + h;
- }
- else
- mask->bounds_known = FALSE;
-
- mask->x1 = CLAMP (mask->x1, 0, GIMP_DRAWABLE (mask)->width);
- mask->y1 = CLAMP (mask->y1, 0, GIMP_DRAWABLE (mask)->height);
- mask->x2 = CLAMP (mask->x2, 0, GIMP_DRAWABLE (mask)->width);
- mask->y2 = CLAMP (mask->y2, 0, GIMP_DRAWABLE (mask)->height);
- }
-
- void
- channel_combine_ellipse (Channel *mask,
- ChannelOps op,
- gint x,
- gint y,
- gint w,
- gint h,
- gboolean antialias)
- {
- gint i, j;
- gint x0, x1, x2;
- gint val, last;
- gfloat a_sqr, b_sqr, aob_sqr;
- gfloat w_sqr, h_sqr;
- gfloat y_sqr;
- gfloat t0, t1;
- gfloat r;
- gfloat cx, cy;
- gfloat rad;
- gfloat dist;
-
- if (!w || !h)
- return;
-
- a_sqr = (w * w / 4.0);
- b_sqr = (h * h / 4.0);
- aob_sqr = a_sqr / b_sqr;
-
- cx = x + w / 2.0;
- cy = y + h / 2.0;
-
- for (i = y; i < (y + h); i++)
- {
- if (i >= 0 && i < GIMP_DRAWABLE (mask)->height)
- {
- /* Non-antialiased code */
- if (!antialias)
- {
- y_sqr = (i + 0.5 - cy) * (i + 0.5 - cy);
- rad = sqrt (a_sqr - a_sqr * y_sqr / (double) b_sqr);
- x1 = ROUND (cx - rad);
- x2 = ROUND (cx + rad);
-
- switch (op)
- {
- case ADD: case REPLACE:
- channel_add_segment (mask, x1, i, (x2 - x1), 255);
- break;
- case SUB :
- channel_sub_segment (mask, x1, i, (x2 - x1), 255);
- break;
- default:
- g_warning ("Only ADD, REPLACE and SUB are valid for channel_combine!");
- break;
- }
- }
- /* antialiasing */
- else
- {
- x0 = x;
- last = 0;
- h_sqr = (i + 0.5 - cy) * (i + 0.5 - cy);
- for (j = x; j < (x + w); j++)
- {
- w_sqr = (j + 0.5 - cx) * (j + 0.5 - cx);
-
- if (h_sqr != 0)
- {
- t0 = w_sqr / h_sqr;
- t1 = a_sqr / (t0 + aob_sqr);
- r = sqrt (t1 + t0 * t1);
- rad = sqrt (w_sqr + h_sqr);
- dist = rad - r;
- }
- else
- dist = -1.0;
-
- if (dist < -0.5)
- val = 255;
- else if (dist < 0.5)
- val = (int) (255 * (1 - (dist + 0.5)));
- else
- val = 0;
-
- if (last != val && last)
- {
- switch (op)
- {
- case ADD: case REPLACE:
- channel_add_segment (mask, x0, i, j - x0, last);
- break;
- case SUB:
- channel_sub_segment (mask, x0, i, j - x0, last);
- break;
- default:
- g_warning ("Only ADD, REPLACE and SUB are valid for channel_combine!");
- break;
- }
- }
-
- if (last != val)
- {
- x0 = j;
- last = val;
- /* because we are symetric accross the y axis we can
- skip ahead a bit if we are inside the ellipse*/
- if (val == 255 && j < cx)
- j = cx + (cx - j) - 1;
- }
- }
-
- if (last)
- {
- if (op == ADD || op == REPLACE)
- channel_add_segment (mask, x0, i, j - x0, last);
- else if (op == SUB)
- channel_sub_segment (mask, x0, i, j - x0, last);
- else
- g_warning ("Only ADD, REPLACE and SUB are valid for channel_combine!");
- }
- }
-
- }
- }
-
- /* Determine new boundary */
- if (mask->bounds_known && (op == ADD) && !mask->empty)
- {
- if (x < mask->x1)
- mask->x1 = x;
- if (y < mask->y1)
- mask->y1 = y;
- if ((x + w) > mask->x2)
- mask->x2 = (x + w);
- if ((y + h) > mask->y2)
- mask->y2 = (y + h);
- }
- else if (op == REPLACE || mask->empty)
- {
- mask->empty = FALSE;
- mask->x1 = x;
- mask->y1 = y;
- mask->x2 = x + w;
- mask->y2 = y + h;
- }
- else
- mask->bounds_known = FALSE;
-
- mask->x1 = CLAMP (mask->x1, 0, GIMP_DRAWABLE (mask)->width);
- mask->y1 = CLAMP (mask->y1, 0, GIMP_DRAWABLE (mask)->height);
- mask->x2 = CLAMP (mask->x2, 0, GIMP_DRAWABLE (mask)->width);
- mask->y2 = CLAMP (mask->y2, 0, GIMP_DRAWABLE (mask)->height);
- }
-
- static void
- channel_combine_sub_region_add (void *unused,
- PixelRegion *srcPR,
- PixelRegion *destPR)
- {
- guchar *src, *dest;
- gint x, y, val;
-
- src = srcPR->data;
- dest = destPR->data;
-
- for (y = 0; y < srcPR->h; y++)
- {
- for (x = 0; x < srcPR->w; x++)
- {
- val = dest[x] + src[x];
- if (val > 255)
- dest[x] = 255;
- else
- dest[x] = val;
- }
- src += srcPR->rowstride;
- dest += destPR->rowstride;
- }
- }
-
- static void
- channel_combine_sub_region_sub (void *unused,
- PixelRegion *srcPR,
- PixelRegion *destPR)
- {
- guchar *src, *dest;
- gint x, y;
-
- src = srcPR->data;
- dest = destPR->data;
-
- for (y = 0; y < srcPR->h; y++)
- {
- for (x = 0; x < srcPR->w; x++)
- {
- if (src[x] > dest[x])
- dest[x] = 0;
- else
- dest[x]-= src[x];
- }
- src += srcPR->rowstride;
- dest += destPR->rowstride;
- }
- }
-
- static void
- channel_combine_sub_region_intersect (void *unused,
- PixelRegion *srcPR,
- PixelRegion *destPR)
- {
- guchar *src, *dest;
- gint x, y;
-
- src = srcPR->data;
- dest = destPR->data;
-
- for (y = 0; y < srcPR->h; y++)
- {
- for (x = 0; x < srcPR->w; x++)
- {
- dest[x] = MIN (dest[x], src[x]);
- }
- src += srcPR->rowstride;
- dest += destPR->rowstride;
- }
- }
-
- void
- channel_combine_mask (Channel *mask,
- Channel *add_on,
- ChannelOps op,
- gint off_x,
- gint off_y)
- {
- PixelRegion srcPR, destPR;
- gint x1, y1, x2, y2;
- gint w, h;
-
- x1 = CLAMP (off_x, 0, GIMP_DRAWABLE (mask)->width);
- y1 = CLAMP (off_y, 0, GIMP_DRAWABLE (mask)->height);
- x2 = CLAMP (off_x + GIMP_DRAWABLE (add_on)->width, 0,
- GIMP_DRAWABLE (mask)->width);
- y2 = CLAMP (off_y + GIMP_DRAWABLE (add_on)->height, 0,
- GIMP_DRAWABLE (mask)->height);
-
- w = (x2 - x1);
- h = (y2 - y1);
-
- pixel_region_init (&srcPR, GIMP_DRAWABLE (add_on)->tiles,
- (x1 - off_x), (y1 - off_y), w, h, FALSE);
- pixel_region_init (&destPR, GIMP_DRAWABLE (mask)->tiles, x1, y1, w, h, TRUE);
-
- switch (op)
- {
- case ADD: case REPLACE:
- pixel_regions_process_parallel ((p_func) channel_combine_sub_region_add,
- NULL, 2, &srcPR, &destPR);
- break;
- case SUB:
- pixel_regions_process_parallel ((p_func) channel_combine_sub_region_sub,
- NULL, 2, &srcPR, &destPR);
- break;
- case INTERSECT:
- pixel_regions_process_parallel ((p_func)
- channel_combine_sub_region_intersect,
- NULL, 2, &srcPR, &destPR);
- break;
- default:
- g_message ("Error: unknown opperation type in channel_combine_mask\n");
- break;
- }
- mask->bounds_known = FALSE;
- }
-
- void
- channel_feather (Channel *input,
- Channel *output,
- gdouble radius_x,
- gdouble radius_y,
- ChannelOps op,
- gint off_x,
- gint off_y)
- {
- gint x1, y1, x2, y2;
- PixelRegion srcPR;
-
- x1 = CLAMP (off_x, 0, GIMP_DRAWABLE (output)->width);
- y1 = CLAMP (off_y, 0, GIMP_DRAWABLE (output)->height);
- x2 = CLAMP (off_x + GIMP_DRAWABLE (input)->width, 0,
- GIMP_DRAWABLE (output)->width);
- y2 = CLAMP (off_y + GIMP_DRAWABLE (input)->height, 0,
- GIMP_DRAWABLE (output)->height);
-
- pixel_region_init (&srcPR, GIMP_DRAWABLE (input)->tiles,
- (x1 - off_x), (y1 - off_y), (x2 - x1), (y2 - y1), FALSE);
- gaussian_blur_region (&srcPR, radius_x, radius_y);
-
- if (input != output)
- channel_combine_mask (output, input, op, 0, 0);
-
- output->bounds_known = FALSE;
- }
-
- void
- channel_push_undo (Channel *mask)
- {
- gint x1, y1, x2, y2;
- MaskUndo *mask_undo;
- TileManager *undo_tiles;
- PixelRegion srcPR, destPR;
- GImage *gimage;
-
- mask_undo = g_new (MaskUndo, 1);
- if (channel_bounds (mask, &x1, &y1, &x2, &y2))
- {
- undo_tiles = tile_manager_new ((x2 - x1), (y2 - y1), 1);
- pixel_region_init (&srcPR, GIMP_DRAWABLE (mask)->tiles,
- x1, y1, (x2 - x1), (y2 - y1), FALSE);
- pixel_region_init (&destPR, undo_tiles, 0, 0, (x2 - x1), (y2 - y1), TRUE);
- copy_region (&srcPR, &destPR);
- }
- else
- undo_tiles = NULL;
-
- mask_undo->tiles = undo_tiles;
- mask_undo->x = x1;
- mask_undo->y = y1;
-
- /* push the undo buffer onto the undo stack */
- gimage = GIMP_DRAWABLE (mask)->gimage;
- undo_push_mask (gimage, mask_undo);
- gimage_mask_invalidate (gimage);
-
- /* invalidate the preview */
- GIMP_DRAWABLE (mask)->preview_valid = FALSE;
- }
-
- void
- channel_clear (Channel *mask)
- {
- PixelRegion maskPR;
- guchar bg = 0;
-
- /* push the current channel onto the undo stack */
- channel_push_undo (mask);
-
- if (mask->bounds_known && !mask->empty)
- {
- pixel_region_init (&maskPR, GIMP_DRAWABLE (mask)->tiles,
- mask->x1, mask->y1,
- (mask->x2 - mask->x1), (mask->y2 - mask->y1), TRUE);
- color_region (&maskPR, &bg);
- }
- else
- {
- /* clear the mask */
- pixel_region_init (&maskPR, GIMP_DRAWABLE (mask)->tiles,
- 0, 0,
- GIMP_DRAWABLE (mask)->width,
- GIMP_DRAWABLE (mask)->height, TRUE);
- color_region (&maskPR, &bg);
- }
-
- /* we know the bounds */
- mask->bounds_known = TRUE;
- mask->empty = TRUE;
- mask->x1 = 0;
- mask->y1 = 0;
- mask->x2 = GIMP_DRAWABLE (mask)->width;
- mask->y2 = GIMP_DRAWABLE (mask)->height;
- }
-
- void
- channel_invert (Channel *mask)
- {
- PixelRegion maskPR;
- GimpLut *lut;
-
- /* push the current channel onto the undo stack */
- channel_push_undo (mask);
-
- pixel_region_init (&maskPR, GIMP_DRAWABLE (mask)->tiles,
- 0, 0,
- GIMP_DRAWABLE (mask)->width,
- GIMP_DRAWABLE (mask)->height, TRUE);
-
- lut = invert_lut_new (1);
-
- pixel_regions_process_parallel ((p_func) gimp_lut_process_inline,
- lut, 1, &maskPR);
- gimp_lut_free (lut);
- mask->bounds_known = FALSE;
- }
-
- void
- channel_sharpen (Channel *mask)
- {
- PixelRegion maskPR;
- GimpLut *lut;
-
- /* push the current channel onto the undo stack */
- channel_push_undo (mask);
-
- pixel_region_init (&maskPR, GIMP_DRAWABLE (mask)->tiles,
- 0, 0,
- GIMP_DRAWABLE (mask)->width,
- GIMP_DRAWABLE (mask)->height, TRUE);
- lut = threshold_lut_new (0.5, 1);
-
- pixel_regions_process_parallel ((p_func) gimp_lut_process_inline,
- lut, 1, &maskPR);
- gimp_lut_free (lut);
- }
-
- void
- channel_all (Channel *mask)
- {
- PixelRegion maskPR;
- guchar bg = 255;
-
- /* push the current channel onto the undo stack */
- channel_push_undo (mask);
-
- /* clear the mask */
- pixel_region_init (&maskPR, GIMP_DRAWABLE (mask)->tiles,
- 0, 0,
- GIMP_DRAWABLE (mask)->width,
- GIMP_DRAWABLE (mask)->height, TRUE);
- color_region (&maskPR, &bg);
-
- /* we know the bounds */
- mask->bounds_known = TRUE;
- mask->empty = FALSE;
- mask->x1 = 0;
- mask->y1 = 0;
- mask->x2 = GIMP_DRAWABLE (mask)->width;
- mask->y2 = GIMP_DRAWABLE (mask)->height;
- }
-
- void
- channel_border (Channel *mask,
- gint radius_x,
- gint radius_y)
- {
- PixelRegion bPR;
- gint x1, y1, x2, y2;
-
- if (radius_x < 0 || radius_y < 0)
- return;
-
- if (! channel_bounds (mask, &x1, &y1, &x2, &y2))
- return;
- if (channel_is_empty (mask))
- return;
-
- if (x1 - radius_x < 0)
- x1 = 0;
- else
- x1 -= radius_x;
- if (x2 + radius_x > GIMP_DRAWABLE (mask)->width)
- x2 = GIMP_DRAWABLE (mask)->width;
- else
- x2 += radius_x;
-
- if (y1 - radius_y < 0)
- y1 = 0;
- else
- y1 -= radius_y;
- if (y2 + radius_y > GIMP_DRAWABLE (mask)->height)
- y2 = GIMP_DRAWABLE (mask)->height;
- else
- y2 += radius_y;
- /* push the current channel onto the undo stack */
- channel_push_undo (mask);
-
- pixel_region_init (&bPR, GIMP_DRAWABLE (mask)->tiles, x1, y1,
- (x2-x1), (y2-y1), TRUE);
-
- border_region (&bPR, radius_x, radius_y);
-
- mask->bounds_known = FALSE;
- }
-
- void
- channel_grow (Channel *mask,
- gint radius_x,
- gint radius_y)
- {
- PixelRegion bPR;
- gint x1, y1, x2, y2;
-
- if (radius_x == 0 && radius_y == 0)
- return;
-
- if (radius_x <= 0 && radius_y <= 0)
- {
- channel_shrink (mask, -radius_x, -radius_y, FALSE);
- return;
- }
-
- if (radius_x < 0 || radius_y < 0)
- return;
-
- if (! channel_bounds (mask, &x1, &y1, &x2, &y2))
- return;
- if (channel_is_empty (mask))
- return;
-
- if (x1 - radius_x > 0)
- x1 = x1 - radius_x;
- else
- x1 = 0;
- if (y1 - radius_y > 0)
- y1 = y1 - radius_y;
- else
- y1 = 0;
- if (x2 + radius_x < GIMP_DRAWABLE (mask)->width)
- x2 = x2 + radius_x;
- else
- x2 = GIMP_DRAWABLE (mask)->width;
- if (y2 + radius_y < GIMP_DRAWABLE (mask)->height)
- y2 = y2 + radius_y;
- else
- y2 = GIMP_DRAWABLE (mask)->height;
-
- /* push the current channel onto the undo stack */
- channel_push_undo (mask);
-
- /* need full extents for grow, not! */
- pixel_region_init (&bPR, GIMP_DRAWABLE (mask)->tiles, x1, y1, (x2 - x1),
- (y2 - y1), TRUE);
-
- fatten_region (&bPR, radius_x, radius_y);
-
- mask->bounds_known = FALSE;
- }
-
- void
- channel_shrink (Channel *mask,
- gint radius_x,
- gint radius_y,
- gboolean edge_lock)
- {
- PixelRegion bPR;
- gint x1, y1, x2, y2;
-
- if (radius_x == 0 && radius_y == 0)
- return;
-
- if (radius_x <= 0 && radius_y <= 0)
- {
- channel_grow (mask, -radius_x, -radius_y);
- return;
- }
-
- if (radius_x < 0 || radius_y < 0)
- return;
-
- if (! channel_bounds (mask, &x1, &y1, &x2, &y2))
- return;
- if (channel_is_empty (mask))
- return;
-
- if (x1 > 0)
- x1--;
- if (y1 > 0)
- y1--;
- if (x2 < GIMP_DRAWABLE (mask)->width)
- x2++;
- if (y2 < GIMP_DRAWABLE (mask)->height)
- y2++;
-
- /* push the current channel onto the undo stack */
- channel_push_undo (mask);
-
- pixel_region_init (&bPR, GIMP_DRAWABLE (mask)->tiles, x1, y1, (x2 - x1),
- (y2 - y1), TRUE);
-
- thin_region (&bPR, radius_x, radius_y, edge_lock);
-
- mask->bounds_known = FALSE;
- }
-
- void
- channel_translate (Channel *mask,
- gint off_x,
- gint off_y)
- {
- gint width, height;
- Channel *tmp_mask;
- PixelRegion srcPR, destPR;
- guchar empty = 0;
- gint x1, y1, x2, y2;
-
- tmp_mask = NULL;
-
- /* push the current channel onto the undo stack */
- channel_push_undo (mask);
-
- channel_bounds (mask, &x1, &y1, &x2, &y2);
- x1 = CLAMP ((x1 + off_x), 0, GIMP_DRAWABLE (mask)->width);
- y1 = CLAMP ((y1 + off_y), 0, GIMP_DRAWABLE (mask)->height);
- x2 = CLAMP ((x2 + off_x), 0, GIMP_DRAWABLE (mask)->width);
- y2 = CLAMP ((y2 + off_y), 0, GIMP_DRAWABLE (mask)->height);
-
- width = x2 - x1;
- height = y2 - y1;
-
- /* make sure width and height are non-zero */
- if (width != 0 && height != 0)
- {
- /* copy the portion of the mask we will keep to a
- * temporary buffer
- */
- tmp_mask = channel_new_mask (GIMP_DRAWABLE (mask)->gimage, width, height);
-
- pixel_region_init (&srcPR, GIMP_DRAWABLE (mask)->tiles,
- x1 - off_x, y1 - off_y, width, height, FALSE);
- pixel_region_init (&destPR, GIMP_DRAWABLE (tmp_mask)->tiles,
- 0, 0, width, height, TRUE);
- copy_region (&srcPR, &destPR);
- }
-
- /* clear the mask */
- pixel_region_init (&srcPR, GIMP_DRAWABLE (mask)->tiles,
- 0, 0,
- GIMP_DRAWABLE (mask)->width,
- GIMP_DRAWABLE (mask)->height, TRUE);
- color_region (&srcPR, &empty);
-
- if (width != 0 && height != 0)
- {
- /* copy the temp mask back to the mask */
- pixel_region_init (&srcPR, GIMP_DRAWABLE (tmp_mask)->tiles,
- 0, 0, width, height, FALSE);
- pixel_region_init (&destPR, GIMP_DRAWABLE (mask)->tiles,
- x1, y1, width, height, TRUE);
- copy_region (&srcPR, &destPR);
-
- /* free the temporary mask */
- channel_delete (tmp_mask);
- }
-
- /* calculate new bounds */
- if (width == 0 || height == 0)
- {
- mask->empty = TRUE;
- mask->x1 = 0; mask->y1 = 0;
- mask->x2 = GIMP_DRAWABLE (mask)->width;
- mask->y2 = GIMP_DRAWABLE (mask)->height;
- }
- else
- {
- mask->x1 = x1;
- mask->y1 = y1;
- mask->x2 = x2;
- mask->y2 = y2;
- }
- }
-
- void
- channel_layer_alpha (Channel *mask,
- Layer *layer)
- {
- PixelRegion srcPR, destPR;
- guchar empty = 0;
- gint x1, y1, x2, y2;
-
- /* push the current mask onto the undo stack */
- channel_push_undo (mask);
-
- /* clear the mask */
- pixel_region_init (&destPR, GIMP_DRAWABLE (mask)->tiles,
- 0, 0,
- GIMP_DRAWABLE (mask)->width,
- GIMP_DRAWABLE (mask)->height, TRUE);
- color_region (&destPR, &empty);
-
- x1 = CLAMP (GIMP_DRAWABLE (layer)->offset_x, 0, GIMP_DRAWABLE (mask)->width);
- y1 = CLAMP (GIMP_DRAWABLE (layer)->offset_y, 0, GIMP_DRAWABLE (mask)->height);
- x2 = CLAMP (GIMP_DRAWABLE (layer)->offset_x + GIMP_DRAWABLE (layer)->width,
- 0, GIMP_DRAWABLE (mask)->width);
- y2 = CLAMP (GIMP_DRAWABLE( layer)->offset_y + GIMP_DRAWABLE (layer)->height,
- 0, GIMP_DRAWABLE (mask)->height);
-
- pixel_region_init (&srcPR, GIMP_DRAWABLE (layer)->tiles,
- (x1 - GIMP_DRAWABLE (layer)->offset_x),
- (y1 - GIMP_DRAWABLE (layer)->offset_y),
- (x2 - x1), (y2 - y1), FALSE);
- pixel_region_init (&destPR, GIMP_DRAWABLE (mask)->tiles,
- x1, y1, (x2 - x1), (y2 - y1), TRUE);
- extract_alpha_region (&srcPR, NULL, &destPR);
-
- mask->bounds_known = FALSE;
- }
-
- void
- channel_load (Channel *mask,
- Channel *channel)
- {
- PixelRegion srcPR, destPR;
-
- /* push the current mask onto the undo stack */
- channel_push_undo (mask);
-
- /* copy the channel to the mask */
- pixel_region_init (&srcPR, GIMP_DRAWABLE (channel)->tiles,
- 0, 0,
- GIMP_DRAWABLE (channel)->width,
- GIMP_DRAWABLE (channel)->height, FALSE);
- pixel_region_init (&destPR, GIMP_DRAWABLE (mask)->tiles,
- 0, 0,
- GIMP_DRAWABLE (channel)->width,
- GIMP_DRAWABLE (channel)->height, TRUE);
- copy_region (&srcPR, &destPR);
-
- mask->bounds_known = FALSE;
- }
-
- void
- channel_invalidate_bounds (Channel *channel)
- {
- channel->bounds_known = FALSE;
- }
-
-