/* --------------------------------------------
 * gap_fg_from_selection_exec_apply_run
 * --------------------------------------------
 * generate a tri map from the current selection by filling the shrinked
 * shape with white, the expanded shape with black and the borderline
 * between shrinked and expanded selection with medium gray.
 * the trimap is attached as layermask to the input drawable,
 * and used as input for the foreground selection via alpha matting algorithm,
 * that creates a resulting layer with trimmed selection.
 *
 */
gint
gap_fg_from_selection_exec_apply_run (gint32 image_id, gint32 drawable_id
                             , gboolean doProgress, gboolean doFlush
                             , GapFgSelectValues *fsValPtr)
{
  GimpRGB   color;
  gint32    activeSelection;
  gint32    shrinkedSelection;
  gint32    trimap;
  gboolean  hadSelection;
  gint      rc;

  rc = 0;
  trimap = -1;
  activeSelection = -1;
  shrinkedSelection = -1;
  hadSelection = FALSE;
  
  gimp_context_push();
  gimp_image_undo_group_start(image_id);
  

  if (gimp_selection_is_empty(image_id) == TRUE)
  {
     if (gimp_drawable_has_alpha(drawable_id) == FALSE)
     {
       /* if the layer has no alpha select all */
       gimp_selection_all(image_id);
     }
     else
     {
       gimp_selection_layer_alpha(drawable_id);
     }
     activeSelection = gimp_selection_save(image_id);
  }
  else
  {
    activeSelection = gimp_selection_save(image_id);
    hadSelection = TRUE;
  }


  trimap = gimp_layer_get_mask(drawable_id);
  if (trimap < 0)
  {
    /* create trimap as new layermask */
    trimap = gimp_layer_create_mask(drawable_id, GIMP_ADD_BLACK_MASK);
    gimp_layer_add_mask(drawable_id, trimap);
  }
  else
  {
    /* use BLACK color to fill the already existing layermask
     * (note that gimp_drawable_fill is used to fill the entire mask
     * regardless to the current selection)
     */
    color.r = 0.0;
    color.g = 0.0;
    color.b = 0.0;
    color.a = 1.0;
    gimp_context_set_background (&color);
    gimp_drawable_fill(trimap, GIMP_BACKGROUND_FILL);
  }
  
  gimp_selection_sharpen(image_id);
  if (fsValPtr->innerRadius > 0)
  {
    gimp_selection_shrink(image_id, fsValPtr->innerRadius);
  }
  shrinkedSelection = gimp_selection_save(image_id);
  
  
  /* use WHITE color to mark foreground regions
   */
  color.r = 1.0;
  color.g = 1.0;
  color.b = 1.0;
  color.a = 1.0;
  gimp_context_set_background (&color);
  gimp_edit_fill(trimap, GIMP_BACKGROUND_FILL);
  
  gimp_selection_load(activeSelection);
  gimp_selection_sharpen(image_id);
  if (fsValPtr->outerRadius > 0)
  {
    gimp_selection_grow(image_id, fsValPtr->outerRadius);
  }
  gimp_selection_combine(shrinkedSelection, GIMP_CHANNEL_OP_SUBTRACT);

  /* use medium GRAY to mark undefined regions
   */
  color.r = 0.5;
  color.g = 0.5;
  color.b = 0.5;
  color.a = 1.0;
  gimp_context_set_background (&color);
  gimp_edit_fill(trimap, GIMP_BACKGROUND_FILL);

  gimp_selection_none(image_id);

  /* perform the foreground selection (that creates the resulting layer) */
  {
    GapFgExtractValues fgExtractValues;
    GapFgExtractValues *fgValPtr;
    
    fgValPtr = &fgExtractValues;
    fgValPtr->input_drawable_id = drawable_id;
    fgValPtr->tri_map_drawable_id = trimap;
    fgValPtr->create_result = TRUE;
    fgValPtr->create_layermask = fsValPtr->create_layermask;
    fgValPtr->lock_color = fsValPtr->lock_color;
    fgValPtr->colordiff_threshold = fsValPtr->colordiff_threshold;

    rc = gap_fg_matting_exec_apply_run (image_id, drawable_id
                                 , doProgress, doFlush
                                 , fgValPtr
                                 );
  }
  
  
  /* restore original selection */
  if (hadSelection == TRUE)
  {
    gimp_selection_load(activeSelection);
  }

  gimp_image_undo_group_end(image_id);
  gimp_context_pop();
  
  return (rc);

}  /* end gap_fg_from_selection_exec_apply_run */
Exemple #2
0
/* -------------------------------------------------------
 * gap_image_set_selection_from_selection_or_drawable
 * -------------------------------------------------------
 * create a selection in the specified image_id.
 * The selection is a scaled copy of the selection in another image,
 * referred by ref_drawable_id, or a Grayscale copy of the specified ref_drawable_id
 * (in case the referred image has no selection or the flag force_from_drawable is TRUE)
 *
 *  - operates on a duplicate of the image referred by ref_drawable_id.
 *  - this duplicate is scaled to same size as specified image_id
 *
 * return TRUE in case the selection was successfully created .
 */
gboolean
gap_image_set_selection_from_selection_or_drawable(gint32 image_id, gint32 ref_drawable_id
  , gboolean force_from_drawable)
{
  gint32        l_aux_channel_id;
  gint32        ref_image_id;
  gint32        work_drawable_id;   /* the duplicate of the layer that is used as selction mask */
  gint32        dup_image_id;
  gboolean has_selection;
  gboolean non_empty;
  gint     x1, y1, x2, y2;

  if ((image_id < 0) || (ref_drawable_id < 0))
  {
    return (FALSE);
  }
  ref_image_id = gimp_item_get_image(ref_drawable_id);

  if (ref_image_id < 0)
  {
    printf("ref_drawable_id does not refer to a valid image layer_id:%d\n", (int)ref_drawable_id);
    return (FALSE);
  }



  dup_image_id = gimp_image_duplicate(ref_image_id);
  if (dup_image_id < 0)
  {
    printf("duplicating of image failed, referred souce image_id:%d\n", (int)ref_image_id);
    return (FALSE);
  }
  /* clear undo stack */
  if (gimp_image_undo_is_enabled(dup_image_id))
  {
    gimp_image_undo_disable(dup_image_id);
  }

  if ((gimp_image_width(image_id) != gimp_image_width(dup_image_id))
  ||  (gimp_image_height(image_id) != gimp_image_height(dup_image_id)))
  {
     if(gap_debug)
     {
       printf("scaling tmp image_id: %d\n", (int)dup_image_id);
     }
     gimp_image_scale(dup_image_id, gimp_image_width(image_id), gimp_image_height(image_id));
  }

  has_selection  = gimp_selection_bounds(ref_image_id, &non_empty, &x1, &y1, &x2, &y2);
  if ((has_selection) && (non_empty) && (force_from_drawable != TRUE))
  {
    /* use scaled copy of the already exisating selection in the referred image */
    work_drawable_id = gimp_image_get_selection(dup_image_id);
  }
  else
  {
    gint32        active_layer_stackposition;

    /* create selection as gray copy of the alt_selection layer */

    active_layer_stackposition = gap_layer_get_stackposition(ref_image_id, ref_drawable_id);

    if(gimp_image_base_type(dup_image_id) != GIMP_GRAY)
    {
       if(gap_debug)
       {
         printf("convert to GRAYSCALE tmp image_id: %d\n", (int)dup_image_id);
       }
       gimp_image_convert_grayscale(dup_image_id);
    }
    work_drawable_id = gap_layer_get_id_by_stackposition(dup_image_id, active_layer_stackposition);
    gimp_layer_resize_to_image_size (work_drawable_id);
  }

  gimp_selection_all(image_id);
  //l_sel_channel_id = gimp_image_get_selection(image_id);
  l_aux_channel_id = gimp_selection_save(image_id);

  /* copy the work drawable (layer or channel) into the selection channel
   * the work layer is a grayscale copy GRAY or GRAYA of the alt_selection layer
   *  that is already scaled and resized to fit the size of the target image
   * the work channel is the scaled selection of the image refred by ref_drawable_id
   *
   * copying is done into an auxiliary channel from where we regulary load the selection.
   * this is done because subseqent queries of the selection boudaries will deliver
   * full channel size rectangle after a direct copy into the selection.
   */
  gap_layer_copy_picked_channel (l_aux_channel_id  /* dst_drawable_id*/
                              , 0                  /* dst_channel_pick */
                              , work_drawable_id   /* src_drawable_id */
                              , 0                  /* src_channel_pick */
                              , FALSE              /* gboolean shadow */
                              );

  gimp_image_select_item(image_id, GIMP_CHANNEL_OP_REPLACE, l_aux_channel_id);
  gimp_image_remove_channel(image_id, l_aux_channel_id);

  gap_image_delete_immediate(dup_image_id);
  return (TRUE);

}  /* end gap_image_set_selection_from_selection_or_drawable */