gimpchannel-select.c 12.3 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
/* 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 <glib-object.h>

#include "core-types.h"

#include "gimpchannel.h"
#include "gimpimage.h"
#include "gimpimage-contiguous-region.h"
#include "gimpimage-mask.h"
#include "gimpimage-mask-select.h"
#include "gimpscanconvert.h"

32 33 34
#include "vectors/gimpstroke.h"
#include "vectors/gimpvectors.h"

35 36
#include "libgimp/gimpintl.h"

37 38

void
39 40 41 42 43 44 45 46 47
gimp_image_mask_select_rectangle (GimpImage      *gimage,
                                  gint            x,
                                  gint            y,
                                  gint            w,
                                  gint            h,
                                  GimpChannelOps  op,
                                  gboolean        feather,
                                  gdouble         feather_radius_x,
                                  gdouble         feather_radius_y)
48 49 50 51
{
  g_return_if_fail (GIMP_IS_IMAGE (gimage));

  /*  if applicable, replace the current selection  */
52
  if (op == GIMP_CHANNEL_OP_REPLACE)
53
    gimp_image_mask_clear (gimage, _("Rectangular Selection"));
54
  else
55
    gimp_image_mask_push_undo (gimage, _("Rectangular Selection"));
56 57 58 59

  /*  if feathering for rect, make a new mask with the
   *  rectangle and feather that with the old mask
   */
60
  if (feather || op == GIMP_CHANNEL_OP_INTERSECT)
61
    {
62 63 64
      GimpChannel *mask;

      mask = gimp_channel_new_mask (gimage, gimage->width, gimage->height);
65
      gimp_channel_combine_rect (mask, GIMP_CHANNEL_OP_ADD, x, y, w, h);
66 67 68 69 70 71 72 73

      if (feather)
        gimp_channel_feather (mask,
                              feather_radius_x,
                              feather_radius_y,
                              FALSE /* no undo */);

      gimp_channel_combine_mask (gimp_image_get_mask (gimage), mask, op, 0, 0);
74
      g_object_unref (mask);
75 76 77 78 79
    }
  else
    {
      gimp_channel_combine_rect (gimp_image_get_mask (gimage), op, x, y, w, h);
    }
80 81

  gimp_image_mask_changed (gimage);
82 83 84
}

void
85 86 87 88 89 90 91 92 93 94
gimp_image_mask_select_ellipse (GimpImage      *gimage,
                                gint            x,
                                gint            y,
                                gint            w,
                                gint            h,
                                GimpChannelOps  op,
                                gboolean        antialias,
                                gboolean        feather,
                                gdouble         feather_radius_x,
                                gdouble         feather_radius_y)
95 96 97 98
{
  g_return_if_fail (GIMP_IS_IMAGE (gimage));

  /*  if applicable, replace the current selection  */
99
  if (op == GIMP_CHANNEL_OP_REPLACE)
100
    gimp_image_mask_clear (gimage, _("Ellipse Selection"));
101
  else
102
    gimp_image_mask_push_undo (gimage, _("Ellipse Selection"));
103 104 105 106

  /*  if feathering for rect, make a new mask with the
   *  rectangle and feather that with the old mask
   */
107
  if (feather || op == GIMP_CHANNEL_OP_INTERSECT)
108
    {
109 110 111
      GimpChannel *mask;

      mask = gimp_channel_new_mask (gimage, gimage->width, gimage->height);
112 113
      gimp_channel_combine_ellipse (mask, GIMP_CHANNEL_OP_ADD, 
                                    x, y, w, h, antialias);
114 115 116 117 118 119 120 121

      if (feather)
        gimp_channel_feather (mask,
                              feather_radius_x,
                              feather_radius_y,
                              FALSE /* no undo */);

      gimp_channel_combine_mask (gimp_image_get_mask (gimage), mask, op, 0, 0);
122
      g_object_unref (mask);
123 124 125 126 127 128
    }
  else
    {
      gimp_channel_combine_ellipse (gimp_image_get_mask (gimage), op,
				    x, y, w, h, antialias);
    }
129 130

  gimp_image_mask_changed (gimage);
131 132 133
}

void
134 135 136 137 138 139 140 141 142
gimp_image_mask_select_polygon (GimpImage      *gimage,
                                const gchar    *undo_name,
                                gint            n_points,
                                GimpVector2    *points,
                                GimpChannelOps  op,
                                gboolean        antialias,
                                gboolean        feather,
                                gdouble         feather_radius_x,
                                gdouble         feather_radius_y)
143 144
{
  GimpScanConvert *scan_convert;
145
  GimpChannel     *mask;
146 147 148

  g_return_if_fail (GIMP_IS_IMAGE (gimage));

149 150 151
  /*  if applicable, replace the current selection
   *  or insure that a floating selection is anchored down...
   */
152
  if (op == GIMP_CHANNEL_OP_REPLACE)
153
    gimp_image_mask_clear (gimage, undo_name);
154
  else
155
    gimp_image_mask_push_undo (gimage, undo_name);
156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177

#define SUPERSAMPLE 3

  scan_convert = gimp_scan_convert_new (gimage->width,
                                        gimage->height,
                                        antialias ? SUPERSAMPLE : 1);
  gimp_scan_convert_add_points (scan_convert, n_points, points);

  mask = gimp_scan_convert_to_channel (scan_convert, gimage);

  gimp_scan_convert_free (scan_convert);

#undef SUPERSAMPLE

  if (mask)
    {
      if (feather)
	gimp_channel_feather (mask,
			      feather_radius_x,
			      feather_radius_y,
                              FALSE /* no undo */);

178
      gimp_channel_combine_mask (gimp_image_get_mask (gimage), mask, op, 0, 0);
179
      g_object_unref (mask);
180
    }
181 182

  gimp_image_mask_changed (gimage);
183 184
}

185
void
186 187 188 189 190 191 192
gimp_image_mask_select_vectors (GimpImage      *gimage,
                                GimpVectors    *vectors,
                                GimpChannelOps  op,
                                gboolean        antialias,
                                gboolean        feather,
                                gdouble         feather_radius_x,
                                gdouble         feather_radius_y)
193 194
{
  GimpStroke *stroke;
195
  GArray     *coords = NULL;
196 197 198 199 200 201 202 203 204
  gboolean    closed;

  g_return_if_fail (GIMP_IS_IMAGE (gimage));

  /*  gimp_stroke_interpolate() may return NULL, so iterate over the
   *  list of strokes until one returns coords
   */
  for (stroke = vectors->strokes; stroke; stroke = stroke->next)
    {
205
      coords = gimp_stroke_interpolate (stroke, 1.0, &closed);
206 207 208 209 210 211 212 213 214 215

      if (coords)
        break;
    }

  if (coords)
    {
      GimpVector2 *points;
      gint         i;

216
      points = g_new0 (GimpVector2, coords->len);
217

218
      for (i = 0; i < coords->len; i++)
219
        {
220 221
          points[i].x = g_array_index (coords, GimpCoords, i).x;
          points[i].y = g_array_index (coords, GimpCoords, i).y;
222 223 224
        }

      gimp_image_mask_select_polygon (GIMP_ITEM (vectors)->gimage,
225
                                      _("Selection from Path"),
226
                                      coords->len,
227 228 229 230 231 232 233
                                      points,
                                      op,
                                      antialias,
                                      feather,
                                      feather_radius_x,
                                      feather_radius_y);

234
      g_array_free (coords, TRUE);
235 236 237 238
      g_free (points);
    }
}

239
void
240
gimp_image_mask_select_channel (GimpImage      *gimage,
241
                                const gchar    *undo_desc,
242 243 244 245 246 247 248
                                GimpChannel    *channel,
                                gint            offset_x,
                                gint            offset_y,
                                GimpChannelOps  op, 
                                gboolean        feather,
                                gdouble         feather_radius_x,
                                gdouble         feather_radius_y)
249 250 251 252 253
{
  g_return_if_fail (GIMP_IS_IMAGE (gimage));
  g_return_if_fail (GIMP_IS_CHANNEL (channel));

  /*  if applicable, replace the current selection  */
254
  if (op == GIMP_CHANNEL_OP_REPLACE)
255
    gimp_image_mask_clear (gimage, undo_desc);
256
  else
257
    gimp_image_mask_push_undo (gimage, undo_desc);
258 259 260 261 262 263 264

  if (feather)
    gimp_channel_feather (channel,
			  feather_radius_x,
			  feather_radius_y,
                          FALSE /* no undo */);

265
  gimp_channel_combine_mask (gimp_image_get_mask (gimage), channel,
266
                             op, offset_x, offset_y);
267 268

  gimp_image_mask_changed (gimage);
269 270 271
}

void
272 273 274 275 276 277 278 279 280 281 282 283
gimp_image_mask_select_fuzzy (GimpImage      *gimage,
                              GimpDrawable   *drawable,
                              gboolean        sample_merged,
                              gint            x,
                              gint            y,
                              gint            threshold,
                              gboolean        select_transparent,
                              GimpChannelOps  op,
                              gboolean        antialias,
                              gboolean        feather,
                              gdouble         feather_radius_x,
                              gdouble         feather_radius_y)
284 285
{
  GimpChannel *mask;
286 287
  gint         mask_x;
  gint         mask_y;
288 289 290 291 292 293 294 295

  g_return_if_fail (GIMP_IS_IMAGE (gimage));
  g_return_if_fail (GIMP_IS_DRAWABLE (drawable));

  mask = gimp_image_contiguous_region_by_seed (gimage, drawable,
                                               sample_merged,
                                               antialias,
                                               threshold,
296
                                               select_transparent,
297 298
                                               x, y);

299 300 301 302 303 304 305 306 307 308
  if (sample_merged)
    {
      mask_x = 0;
      mask_y = 0;
    }
  else
    {
      gimp_drawable_offsets (drawable, &mask_x, &mask_y);
    }

309
  gimp_image_mask_select_channel (gimage,
310
                                  _("Select Fuzzy"),
311
                                  mask,
312 313
                                  mask_x,
                                  mask_y,
314 315 316 317 318
                                  op,
                                  feather,
                                  feather_radius_x,
                                  feather_radius_y);

319
  g_object_unref (mask);
320 321 322
}

void
323 324 325 326 327 328 329 330 331 332 333
gimp_image_mask_select_by_color (GimpImage      *gimage,
                                 GimpDrawable   *drawable,
                                 gboolean        sample_merged,
                                 const GimpRGB  *color,
                                 gint            threshold,
                                 gboolean        select_transparent,
                                 GimpChannelOps  op,
                                 gboolean        antialias,
                                 gboolean        feather,
                                 gdouble         feather_radius_x,
                                 gdouble         feather_radius_y)
334 335
{
  GimpChannel *mask;
336 337
  gint         mask_x;
  gint         mask_y;
338 339 340 341 342 343 344 345 346

  g_return_if_fail (GIMP_IS_IMAGE (gimage));
  g_return_if_fail (GIMP_IS_DRAWABLE (drawable));
  g_return_if_fail (color != NULL);

  mask = gimp_image_contiguous_region_by_color (gimage, drawable,
                                                sample_merged,
                                                antialias,
                                                threshold,
347
                                                select_transparent,
348 349
                                                color);

350 351 352 353 354 355 356 357 358 359
  if (sample_merged)
    {
      mask_x = 0;
      mask_y = 0;
    }
  else
    {
      gimp_drawable_offsets (drawable, &mask_x, &mask_y);
    }

360
  gimp_image_mask_select_channel (gimage,
361
                                  _("Select by Color"),
362
                                  mask,
363 364
                                  mask_x,
                                  mask_y,
365 366 367 368 369
                                  op,
                                  feather,
                                  feather_radius_x,
                                  feather_radius_y);

370
  g_object_unref (mask);
371
}