Index: app/core/gimpdrawable-transform.c =================================================================== RCS file: /cvs/gnome/gimp/app/core/gimpdrawable-transform.c,v retrieving revision 1.114 diff -u -p -r1.114 gimpdrawable-transform.c --- app/core/gimpdrawable-transform.c 12 Apr 2006 12:49:16 -0000 1.114 +++ app/core/gimpdrawable-transform.c 1 Jun 2006 11:25:06 -0000 @@ -1110,6 +1110,9 @@ gimp_drawable_transform_cut (GimpDrawabl { GimpImage *image; TileManager *tiles; + gboolean active_components[MAX_CHANNELS]; + gint bytes; + gint i; g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), NULL); g_return_val_if_fail (gimp_item_is_attached (GIMP_ITEM (drawable)), NULL); @@ -1118,21 +1121,30 @@ gimp_drawable_transform_cut (GimpDrawabl image = gimp_item_get_image (GIMP_ITEM (drawable)); - /* extract the selected mask if there is a selection */ - if (! gimp_channel_is_empty (gimp_image_get_mask (image))) + gimp_drawable_get_active_components (drawable, active_components); + bytes = gimp_drawable_bytes (drawable); + + *new_layer = ! gimp_channel_is_empty (gimp_image_get_mask (image)); + + for (i = 0; i < bytes; i++) + if (! active_components[i]) + *new_layer = FALSE; + + /* extract the selected mask if there is a selection or if + * any of the image components is not active + */ + if (*new_layer) { gint x, y, w, h; - /* set the keep_indexed flag to FALSE here, since we use - * gimp_layer_new_from_tiles() later which assumes that the tiles - * are either RGB or GRAY. Eeek!!! (Sven) - */ if (gimp_drawable_mask_intersect (drawable, &x, &y, &w, &h)) { + /* set the keep_indexed flag to FALSE here, since we use + * gimp_layer_new_from_tiles() later which assumes that the tiles + * are either RGB or GRAY. Eeek!!! (Sven) + */ tiles = gimp_selection_extract (gimp_image_get_mask (image), drawable, context, TRUE, FALSE, TRUE); - - *new_layer = TRUE; } else { @@ -1148,8 +1160,6 @@ gimp_drawable_transform_cut (GimpDrawabl else tiles = gimp_selection_extract (gimp_image_get_mask (image), drawable, context, FALSE, TRUE, FALSE); - - *new_layer = FALSE; } return tiles; Index: app/core/gimpselection.c =================================================================== RCS file: /cvs/gnome/gimp/app/core/gimpselection.c,v retrieving revision 1.40 diff -u -p -r1.40 gimpselection.c --- app/core/gimpselection.c 15 May 2006 09:46:15 -0000 1.40 +++ app/core/gimpselection.c 1 Jun 2006 11:25:07 -0000 @@ -595,13 +595,20 @@ gimp_selection_extract (GimpChannel *se { GimpImage *image; TileManager *tiles; - PixelRegion srcPR, destPR, maskPR; + PixelRegion srcPR, destPR; guchar bg_color[MAX_CHANNELS]; - GimpImageBaseType base_type = GIMP_RGB; - gint bytes = 0; + GimpImageBaseType base_type = GIMP_RGB; + gint bytes = 0; + gboolean has_alpha = FALSE; gint x1, y1, x2, y2; gboolean non_empty; + gboolean need_extract = FALSE; gint off_x, off_y; + gboolean active_components[MAX_CHANNELS]; + gboolean extract_component = FALSE; + gint extract_pixel = -1; + gboolean affect_alpha = FALSE; + gint i; g_return_val_if_fail (GIMP_IS_SELECTION (selection), NULL); g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), NULL); @@ -624,36 +631,62 @@ gimp_selection_extract (GimpChannel *se return NULL; } - /* If there is a selection, we must add alpha because the selection - * could have any shape. + has_alpha = gimp_drawable_has_alpha (drawable); + + gimp_drawable_get_active_components (drawable, active_components); + bytes = gimp_drawable_bytes (drawable); + + need_extract = non_empty; + + for (i = 0; i < bytes; i++) + if (! active_components[i]) + need_extract = TRUE; + + /* If there is a selection or any of the image's components are not + * active, we must add alpha because the selection could have any + * shape and the extracted tiles will float if attached. */ - if (non_empty) - add_alpha = TRUE; + if (need_extract) + { + add_alpha = TRUE; + keep_indexed = FALSE; + } + + if (add_alpha) + bytes = gimp_drawable_bytes_with_alpha (drawable); /* How many bytes in the temp buffer? */ switch (GIMP_IMAGE_TYPE_BASE_TYPE (gimp_drawable_type (drawable))) { case GIMP_RGB: - bytes = add_alpha ? 4 : drawable->bytes; base_type = GIMP_RGB; + + if ((active_components[0] + + active_components[1] + + active_components[2]) == 1) + { + bytes = (has_alpha || add_alpha) ? 2 : 1; + + extract_component = TRUE; + extract_pixel = (active_components[0] ? 0 : + active_components[1] ? 1 : 2); + + if (has_alpha && active_components[3]) + affect_alpha = TRUE; + } break; case GIMP_GRAY: - bytes = add_alpha ? 2 : drawable->bytes; base_type = GIMP_GRAY; break; case GIMP_INDEXED: - if (keep_indexed) - { - bytes = add_alpha ? 2 : drawable->bytes; - base_type = GIMP_GRAY; - } - else + base_type = GIMP_GRAY; /* causes a 1:1 copy of the channels */ + + if (! keep_indexed) { - bytes = (add_alpha || - gimp_drawable_has_alpha (drawable)) ? 4 : 3; base_type = GIMP_INDEXED; + bytes = (has_alpha || add_alpha) ? 4 : 3; } break; @@ -664,10 +697,10 @@ gimp_selection_extract (GimpChannel *se gimp_image_get_background (image, drawable, context, bg_color); - /* If a cut was specified, and the selection mask is not empty, + /* If a cut was specified, and the we need to extract pixels, * push an undo */ - if (cut_image && non_empty) + if (cut_image && need_extract) gimp_drawable_push_undo (drawable, NULL, x1, y1, x2, y2, NULL, FALSE); gimp_item_offsets (GIMP_ITEM (drawable), &off_x, &off_y); @@ -686,16 +719,29 @@ gimp_selection_extract (GimpChannel *se x2 - x1, y2 - y1, TRUE); - if (non_empty) /* If there is a selection, extract from it */ + if (need_extract) /* If we need to extract pixels */ { - pixel_region_init (&maskPR, - gimp_drawable_get_tiles (GIMP_DRAWABLE (selection)), - (x1 + off_x), (y1 + off_y), (x2 - x1), (y2 - y1), - FALSE); - - extract_from_region (&srcPR, &destPR, &maskPR, - gimp_drawable_get_colormap (drawable), - bg_color, base_type, cut_image); + PixelRegion maskPR; + + if (non_empty) + pixel_region_init (&maskPR, + gimp_drawable_get_tiles (GIMP_DRAWABLE (selection)), + x1 + off_x, y1 + off_y, x2 - x1, y2 - y1, + FALSE); + + if (extract_component) + { + extract_from_component (&srcPR, &destPR, non_empty ? &maskPR : NULL, + extract_pixel, affect_alpha, + bg_color, cut_image); + } + else + { + extract_from_region (&srcPR, &destPR, non_empty ? &maskPR : NULL, + active_components, + gimp_drawable_get_colormap (drawable), + bg_color, base_type, cut_image); + } if (cut_image) { @@ -703,22 +749,29 @@ gimp_selection_extract (GimpChannel *se gimp_channel_clear (selection, NULL, TRUE); /* Update the region */ - gimp_drawable_update (drawable, x1, y1, (x2 - x1), (y2 - y1)); + gimp_drawable_update (drawable, x1, y1, x2 - x1, y2 - y1); } } - else /* Otherwise, get the entire active layer */ + else /* Otherwise, get the entire active drawable */ { - /* If the layer is indexed...we need to extract pixels */ if (base_type == GIMP_INDEXED && !keep_indexed) - extract_from_region (&srcPR, &destPR, NULL, - gimp_drawable_get_colormap (drawable), - bg_color, base_type, FALSE); - /* If the layer doesn't have an alpha channel, add one */ + { + /* If the layer is indexed...we need to extract pixels */ + extract_from_region (&srcPR, &destPR, NULL, + active_components, + gimp_drawable_get_colormap (drawable), + bg_color, base_type, FALSE); + } else if (bytes > srcPR.bytes) - add_alpha_region (&srcPR, &destPR); - /* Otherwise, do a straight copy */ + { + /* If the layer doesn't have an alpha channel, add one */ + add_alpha_region (&srcPR, &destPR); + } else - copy_region (&srcPR, &destPR); + { + /* Otherwise, do a straight copy */ + copy_region (&srcPR, &destPR); + } /* If we're cutting, remove either the layer (or floating selection), * the layer mask, or the channel Index: app/paint-funcs/paint-funcs.c =================================================================== RCS file: /cvs/gnome/gimp/app/paint-funcs/paint-funcs.c,v retrieving revision 1.188 diff -u -p -r1.188 paint-funcs.c --- app/paint-funcs/paint-funcs.c 23 May 2006 19:18:00 -0000 1.188 +++ app/paint-funcs/paint-funcs.c 1 Jun 2006 11:25:08 -0000 @@ -1968,14 +1968,15 @@ color_erase_inten_pixels (const guchar void -extract_from_inten_pixels (guchar *src, - guchar *dest, - const guchar *mask, - const guchar *bg, - gboolean cut, - guint length, - guint src_bytes, - guint dest_bytes) +extract_from_inten_pixels (guchar *src, + guchar *dest, + const guchar *mask, + const gboolean *affect, + const guchar *bg, + gboolean cut, + guint length, + guint src_bytes, + guint dest_bytes) { gint b, alpha; const guchar *m; @@ -1991,13 +1992,20 @@ extract_from_inten_pixels (guchar while (length --) { for (b = 0; b < alpha; b++) - dest[b] = src[b]; + dest[b] = affect[b] ? src[b] : 0; if (HAS_ALPHA (src_bytes)) { - dest[alpha] = INT_MULT(*m, src[alpha], tmp); + dest[alpha] = affect[alpha] ? INT_MULT(*m, src[alpha], tmp) : *m; if (cut) - src[alpha] = INT_MULT((255 - *m), src[alpha], tmp); + { + if (affect[alpha]) + src[alpha] = INT_MULT((255 - *m), src[alpha], tmp); + else + for (b = 0; b < alpha; b++) + if (affect[b]) + src[b] = INT_BLEND(bg[b], src[b], *m, tmp); + } } else { @@ -2006,7 +2014,8 @@ extract_from_inten_pixels (guchar if (cut) for (b = 0; b < src_bytes; b++) - src[b] = INT_BLEND(bg[b], src[b], *m, tmp); + if (affect[b]) + src[b] = INT_BLEND(bg[b], src[b], *m, tmp); } if (mask) @@ -2019,15 +2028,16 @@ extract_from_inten_pixels (guchar void -extract_from_indexed_pixels (guchar *src, - guchar *dest, - const guchar *mask, - const guchar *cmap, - const guchar *bg, - gboolean cut, - guint length, - guint src_bytes, - guint dest_bytes) +extract_from_indexed_pixels (guchar *src, + guchar *dest, + const guchar *mask, + const gboolean *affect, + const guchar *cmap, + const guchar *bg, + gboolean cut, + guint length, + guint src_bytes, + guint dest_bytes) { gint b; gint index; @@ -2043,12 +2053,12 @@ extract_from_indexed_pixels (guchar { index = src[0] * 3; for (b = 0; b < 3; b++) - dest[b] = cmap[index + b]; + dest[b] = affect[0] ? cmap[index + b] : 0; if (HAS_ALPHA (src_bytes)) { - dest[3] = INT_MULT (*m, src[1], t); - if (cut) + dest[3] = affect[1] ? INT_MULT (*m, src[1], t) : 255; + if (cut && affect[1]) src[1] = INT_MULT ((255 - *m), src[1], t); } else @@ -2056,7 +2066,7 @@ extract_from_indexed_pixels (guchar if (HAS_ALPHA (dest_bytes)) dest[3] = *m; - if (cut) + if (cut && affect[0]) src[0] = (*m > 127) ? bg[0] : src[0]; } @@ -2069,6 +2079,63 @@ extract_from_indexed_pixels (guchar } +void +extract_from_component_pixels (guchar *src, + guchar *dest, + const guchar *mask, + gint pixel, + gboolean affect_alpha, + const guchar *bg, + gboolean cut, + guint length, + guint src_bytes, + guint dest_bytes) +{ + gint alpha; + const guchar *m; + gint tmp; + + if (mask) + m = mask; + else + m = &no_mask; + + alpha = HAS_ALPHA (src_bytes) ? src_bytes - 1 : src_bytes; + + while (length --) + { + dest[0] = src[pixel]; + + if (HAS_ALPHA (src_bytes)) + { + dest[1] = affect_alpha ? INT_MULT(*m, src[alpha], tmp) : *m; + + if (cut) + { + if (affect_alpha) + src[alpha] = INT_MULT((255 - *m), src[alpha], tmp); + + src[pixel] = INT_BLEND(bg[pixel], src[pixel], *m, tmp); + } + } + else + { + if (HAS_ALPHA (dest_bytes)) + dest[1] = *m; + + if (cut) + src[pixel] = INT_BLEND(bg[pixel], src[pixel], *m, tmp); + } + + src += src_bytes; + dest += dest_bytes; + + if (mask) + m++; + } +} + + /**************************************************/ /* REGION FUNCTIONS */ /**************************************************/ @@ -2406,6 +2473,7 @@ void extract_from_region (PixelRegion *src, PixelRegion *dest, PixelRegion *mask, + const gboolean *affect, const guchar *cmap, const guchar *bg, GimpImageBaseType type, @@ -2430,15 +2498,52 @@ extract_from_region (PixelRegion * { case GIMP_RGB: case GIMP_GRAY: - extract_from_inten_pixels (s, d, m, bg, cut, src->w, - src->bytes, dest->bytes); + extract_from_inten_pixels (s, d, m, affect, bg, cut, + src->w, src->bytes, dest->bytes); break; case GIMP_INDEXED: - extract_from_indexed_pixels (s, d, m, cmap, bg, cut, src->w, - src->bytes, dest->bytes); + extract_from_indexed_pixels (s, d, m, affect, cmap, bg, cut, + src->w, src->bytes, dest->bytes); break; } + + s += src->rowstride; + d += dest->rowstride; + if (mask) + m += mask->rowstride; + } + } +} + + +void +extract_from_component (PixelRegion *src, + PixelRegion *dest, + PixelRegion *mask, + gint pixel, + gboolean affect_alpha, + const guchar *bg, + gboolean cut) +{ + gint h; + guchar *s, *d, *m; + void *pr; + + for (pr = pixel_regions_register (3, src, dest, mask); + pr != NULL; + pr = pixel_regions_process (pr)) + { + s = src->data; + d = dest->data; + m = mask ? mask->data : NULL; + + h = src->h; + + while (h --) + { + extract_from_component_pixels (s, d, m, pixel, affect_alpha, bg, cut, + src->w, src->bytes, dest->bytes); s += src->rowstride; d += dest->rowstride; Index: app/paint-funcs/paint-funcs.h =================================================================== RCS file: /cvs/gnome/gimp/app/paint-funcs/paint-funcs.h,v retrieving revision 1.57 diff -u -p -r1.57 paint-funcs.h --- app/paint-funcs/paint-funcs.h 16 May 2006 13:11:47 -0000 1.57 +++ app/paint-funcs/paint-funcs.h 1 Jun 2006 11:25:08 -0000 @@ -292,27 +292,43 @@ void combine_inten_a_and_channel_select /* extract information from intensity pixels based on * a mask. */ -void extract_from_inten_pixels (guchar *src, - guchar *dest, - const guchar *mask, - const guchar *bg, - gboolean cut, - guint length, - guint src_bytes, - guint dest_bytes); +void extract_from_inten_pixels (guchar *src, + guchar *dest, + const guchar *mask, + const gboolean *affect, + const guchar *bg, + gboolean cut, + guint length, + guint src_bytes, + guint dest_bytes); /* extract information from indexed pixels based on * a mask. */ -void extract_from_indexed_pixels (guchar *src, - guchar *dest, - const guchar *mask, - const guchar *cmap, - const guchar *bg, - gboolean cut, - guint length, - guint src_bytes, - guint dest_bytes); +void extract_from_indexed_pixels (guchar *src, + guchar *dest, + const guchar *mask, + const gboolean *affect, + const guchar *cmap, + const guchar *bg, + gboolean cut, + guint length, + guint src_bytes, + guint dest_bytes); + +/* extract information from one intensity component based on + * a mask. + */ +void extract_from_component_pixels (guchar *src, + guchar *dest, + const guchar *mask, + gint pixel, + gboolean affect_alpha, + const guchar *bg, + gboolean cut, + guint length, + guint src_bytes, + guint dest_bytes); /* Region functions */ @@ -357,9 +373,18 @@ void extract_alpha_region void extract_from_region (PixelRegion *src, PixelRegion *dest, PixelRegion *mask, + const gboolean *affect, const guchar *cmap, const guchar *bg, GimpImageBaseType type, + gboolean cut); + +void extract_from_component (PixelRegion *src, + PixelRegion *dest, + PixelRegion *mask, + gint pixel, + gboolean affect_alpha, + const guchar *bg, gboolean cut);