예제 #1
0
static void
gimp_image_map_tool_map (GimpImageMapTool *tool)
{
  GimpDisplayShell *shell = GIMP_DISPLAY_SHELL (GIMP_TOOL (tool)->display->shell);
  GimpItem         *item  = GIMP_ITEM (tool->drawable);
  gint              x, y;
  gint              w, h;
  gint              off_x, off_y;
  GeglRectangle     visible;

  GIMP_IMAGE_MAP_TOOL_GET_CLASS (tool)->map (tool);

  gimp_display_shell_untransform_viewport (shell, &x, &y, &w, &h);

  gimp_item_offsets (item, &off_x, &off_y);

  gimp_rectangle_intersect (x, y, w, h,
                            off_x,
                            off_y,
                            gimp_item_width  (item),
                            gimp_item_height (item),
                            &visible.x,
                            &visible.y,
                            &visible.width,
                            &visible.height);

  visible.x -= off_x;
  visible.y -= off_y;

  gimp_image_map_apply (tool->image_map, &visible);
}
예제 #2
0
static void
gimp_cage_tool_image_map_update (GimpCageTool *ct)
{
    GimpTool         *tool  = GIMP_TOOL (ct);
    GimpDisplayShell *shell = gimp_display_get_shell (tool->display);
    GimpItem         *item  = GIMP_ITEM (tool->drawable);
    gint              x, y;
    gint              w, h;
    gint              off_x, off_y;
    GeglRectangle     visible;

    gimp_display_shell_untransform_viewport (shell, &x, &y, &w, &h);

    gimp_item_get_offset (item, &off_x, &off_y);

    gimp_rectangle_intersect (x, y, w, h,
                              off_x,
                              off_y,
                              gimp_item_get_width  (item),
                              gimp_item_get_height (item),
                              &visible.x,
                              &visible.y,
                              &visible.width,
                              &visible.height);

    visible.x -= off_x;
    visible.y -= off_y;

    gimp_image_map_apply (ct->image_map, &visible);
}
예제 #3
0
void
gimp_channel_combine_buffer (GimpChannel    *mask,
                             GeglBuffer     *add_on_buffer,
                             GimpChannelOps  op,
                             gint            off_x,
                             gint            off_y)
{
  GeglBuffer *buffer;
  gint        x, y, w, h;

  g_return_if_fail (GIMP_IS_CHANNEL (mask));
  g_return_if_fail (GEGL_IS_BUFFER (add_on_buffer));

  buffer = gimp_drawable_get_buffer (GIMP_DRAWABLE (mask));

  if (! gimp_gegl_mask_combine_buffer (buffer, add_on_buffer,
                                       op, off_x, off_y))
    return;

  gimp_rectangle_intersect (off_x, off_y,
                            gegl_buffer_get_width  (add_on_buffer),
                            gegl_buffer_get_height (add_on_buffer),
                            0, 0,
                            gimp_item_get_width  (GIMP_ITEM (mask)),
                            gimp_item_get_height (GIMP_ITEM (mask)),
                            &x, &y, &w, &h);

  mask->bounds_known = FALSE;

  gimp_drawable_update (GIMP_DRAWABLE (mask), x, y, w, h);
}
예제 #4
0
void
gimp_channel_combine_mask (GimpChannel    *mask,
                           GimpChannel    *add_on,
                           GimpChannelOps  op,
                           gint            off_x,
                           gint            off_y)
{
  PixelRegion srcPR, destPR;
  gint        x, y, w, h;

  g_return_if_fail (GIMP_IS_CHANNEL (mask));
  g_return_if_fail (GIMP_IS_CHANNEL (add_on));

  if (! gimp_rectangle_intersect (off_x, off_y,
                                  gimp_item_get_width  (GIMP_ITEM (add_on)),
                                  gimp_item_get_height (GIMP_ITEM (add_on)),
                                  0, 0,
                                  gimp_item_get_width  (GIMP_ITEM (mask)),
                                  gimp_item_get_height (GIMP_ITEM (mask)),
                                  &x, &y, &w, &h))
    return;

  pixel_region_init (&srcPR, gimp_drawable_get_tiles (GIMP_DRAWABLE (add_on)),
                     x - off_x, y - off_y, w, h, FALSE);
  pixel_region_init (&destPR, gimp_drawable_get_tiles (GIMP_DRAWABLE (mask)),
                     x, y, w, h, TRUE);

  switch (op)
    {
    case GIMP_CHANNEL_OP_ADD:
    case GIMP_CHANNEL_OP_REPLACE:
      pixel_regions_process_parallel ((PixelProcessorFunc)
                                      gimp_channel_combine_sub_region_add,
                                      NULL, 2, &srcPR, &destPR);
      break;

    case GIMP_CHANNEL_OP_SUBTRACT:
      pixel_regions_process_parallel ((PixelProcessorFunc)
                                      gimp_channel_combine_sub_region_sub,
                                      NULL, 2, &srcPR, &destPR);
      break;

    case GIMP_CHANNEL_OP_INTERSECT:
      pixel_regions_process_parallel ((PixelProcessorFunc)
                                      gimp_channel_combine_sub_region_intersect,
                                      NULL, 2, &srcPR, &destPR);
      break;

    default:
      g_warning ("%s: unknown operation type", G_STRFUNC);
      break;
    }

  mask->bounds_known = FALSE;

  gimp_drawable_update (GIMP_DRAWABLE (mask), x, y, w, h);
}
예제 #5
0
void
floating_sel_anchor (GimpLayer *layer)
{
  GimpImage    *image;
  GimpDrawable *drawable;
  GimpFilter   *filter = NULL;
  gint          off_x, off_y;
  gint          dr_off_x, dr_off_y;

  g_return_if_fail (GIMP_IS_LAYER (layer));
  g_return_if_fail (gimp_layer_is_floating_sel (layer));

  /* Don't let gimp_image_remove_layer free the layer while we still need it */
  g_object_ref (layer);

  image = gimp_item_get_image (GIMP_ITEM (layer));

  gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_FS_ANCHOR,
                               C_("undo-type", "Anchor Floating Selection"));

  drawable = gimp_layer_get_floating_sel_drawable (layer);

  gimp_item_get_offset (GIMP_ITEM (layer), &off_x, &off_y);
  gimp_item_get_offset (GIMP_ITEM (drawable), &dr_off_x, &dr_off_y);

  if (gimp_item_get_visible (GIMP_ITEM (layer)) &&
      gimp_rectangle_intersect (off_x, off_y,
                                gimp_item_get_width  (GIMP_ITEM (layer)),
                                gimp_item_get_height (GIMP_ITEM (layer)),
                                dr_off_x, dr_off_y,
                                gimp_item_get_width  (GIMP_ITEM (drawable)),
                                gimp_item_get_height (GIMP_ITEM (drawable)),
                                NULL, NULL, NULL, NULL))
    {
      filter = gimp_drawable_get_floating_sel_filter (drawable);
      g_object_ref (filter);
    }

  /*  first remove the filter, then merge it, or we will get warnings
   *  about already connected nodes
   */
  gimp_image_remove_layer (image, layer, TRUE, NULL);

  if (filter)
    {
      gimp_drawable_merge_filter (drawable, filter, NULL, NULL);
      g_object_unref (filter);
    }

  gimp_image_undo_group_end (image);

  /*  invalidate the boundaries  */
  gimp_drawable_invalidate_boundary (GIMP_DRAWABLE (gimp_image_get_mask (image)));

  g_object_unref (layer);
}
예제 #6
0
/* --------------------------------------------
 * gap_drawable_foreground_extract_matting_init
 * --------------------------------------------
 *
 */
static GappMattingState *
gap_drawable_foreground_extract_matting_init (GimpDrawable *drawable,
                                               gint          mask_x,
                                               gint          mask_y,
                                               gint          mask_width,
                                               gint          mask_height)
{
  GappMattingState *state;
  GappTileManager *tm;
  const guchar *colormap = NULL;
  gboolean      intersect;
  gint          offset_x;
  gint          offset_y;
  gint          is_x, is_y, is_width, is_height;

  if(gap_debug)
  {
    printf("init: START\n");
  }

  /* get offsets within the image */
  gimp_drawable_offsets (drawable->drawable_id, &offset_x, &offset_y);

  intersect = gimp_rectangle_intersect (offset_x, offset_y,
                                        drawable->width,
                                        drawable->height,
                                        mask_x, mask_y, mask_width, mask_height,
                                        &is_x, &is_y, &is_width, &is_height);


  /* FIXME:
   * Clear the mask outside the rectangle that we are working on?
   */

  if (! intersect)
  {
    return NULL;
  }

  tm = gapp_tile_manager_new(drawable);

  state = matting_init (tm, colormap,
                       offset_x, offset_y,
                       is_x, is_y, is_width, is_height);
  if(gap_debug)
  {
    printf("init: END state:%d\n"
      ,(int) state
      );
  }

  return (state);


}  /* end gap_drawable_foreground_extract_matting_init */
예제 #7
0
void
gimp_channel_combine_rect (GimpChannel    *mask,
                           GimpChannelOps  op,
                           gint            x,
                           gint            y,
                           gint            w,
                           gint            h)
{
  GeglBuffer *buffer;

  g_return_if_fail (GIMP_IS_CHANNEL (mask));

  buffer = gimp_drawable_get_buffer (GIMP_DRAWABLE (mask));

  if (! gimp_gegl_mask_combine_rect (buffer, op, x, y, w, h))
    return;

  gimp_rectangle_intersect (x, y, w, h,
                            0, 0,
                            gimp_item_get_width  (GIMP_ITEM (mask)),
                            gimp_item_get_height (GIMP_ITEM (mask)),
                            &x, &y, &w, &h);

  /*  Determine new boundary  */
  if (mask->bounds_known && (op == GIMP_CHANNEL_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 == GIMP_CHANNEL_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_item_get_width  (GIMP_ITEM (mask)));
  mask->y1 = CLAMP (mask->y1, 0, gimp_item_get_height (GIMP_ITEM (mask)));
  mask->x2 = CLAMP (mask->x2, 0, gimp_item_get_width  (GIMP_ITEM (mask)));
  mask->y2 = CLAMP (mask->y2, 0, gimp_item_get_height (GIMP_ITEM (mask)));

  gimp_drawable_update (GIMP_DRAWABLE (mask), x, y, w, h);
}
예제 #8
0
void
gimp_paint_core_cancel (GimpPaintCore *core,
                        GimpDrawable  *drawable)
{
  gint x, y;
  gint width, height;

  g_return_if_fail (GIMP_IS_PAINT_CORE (core));
  g_return_if_fail (GIMP_IS_DRAWABLE (drawable));
  g_return_if_fail (gimp_item_is_attached (GIMP_ITEM (drawable)));

  /*  Determine if any part of the image has been altered--
   *  if nothing has, then just return...
   */
  if ((core->x2 == core->x1) || (core->y2 == core->y1))
    return;

  if (gimp_rectangle_intersect (core->x1, core->y1,
                                core->x2 - core->x1,
                                core->y2 - core->y1,
                                0, 0,
                                gimp_item_get_width  (GIMP_ITEM (drawable)),
                                gimp_item_get_height (GIMP_ITEM (drawable)),
                                &x, &y, &width, &height))
    {
      gegl_buffer_copy (core->undo_buffer,
                        GEGL_RECTANGLE (x, y, width, height),
                        gimp_drawable_get_buffer (drawable),
                        GEGL_RECTANGLE (x, y, width, height));
    }

  g_object_unref (core->undo_buffer);
  core->undo_buffer = NULL;

  if (core->saved_proj_buffer)
    {
      g_object_unref (core->saved_proj_buffer);
      core->saved_proj_buffer = NULL;
    }

  gimp_drawable_update (drawable, x, y, width, height);

  gimp_viewable_preview_thaw (GIMP_VIEWABLE (drawable));
}
SioxState *
gimp_drawable_foreground_extract_siox_init (GimpDrawable *drawable,
                                            gint          x,
                                            gint          y,
                                            gint          width,
                                            gint          height)
{
  GeglBuffer   *buffer;
  const guchar *colormap = NULL;
  gboolean      intersect;
  gint          offset_x;
  gint          offset_y;

  g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), NULL);
  g_return_val_if_fail (gimp_item_is_attached (GIMP_ITEM (drawable)), NULL);

  if (gimp_drawable_is_indexed (drawable))
    colormap = gimp_drawable_get_colormap (drawable);

  gimp_item_get_offset (GIMP_ITEM (drawable), &offset_x, &offset_y);

  intersect = gimp_rectangle_intersect (offset_x, offset_y,
                                        gimp_item_get_width  (GIMP_ITEM (drawable)),
                                        gimp_item_get_height (GIMP_ITEM (drawable)),
                                        x, y, width, height,
                                        &x, &y, &width, &height);


  /* FIXME:
   * Clear the mask outside the rectangle that we are working on?
   */

  if (! intersect)
    return NULL;

  buffer = gimp_drawable_get_buffer (drawable);

  return siox_init (gimp_gegl_buffer_get_tiles (buffer), colormap,
                    offset_x, offset_y,
                    x, y, width, height);
}
예제 #10
0
static void
gimp_seamless_clone_tool_filter_update (GimpSeamlessCloneTool *sc)
{
  GimpTool         *tool  = GIMP_TOOL (sc);
  GimpDisplayShell *shell = gimp_display_get_shell (tool->display);
  GimpItem         *item  = GIMP_ITEM (tool->drawable);
  gint              x, y;
  gint              w, h;
  gint              off_x, off_y;
  GeglRectangle     visible;
  GeglOperation    *op = NULL;

  GimpProgress     *progress;
  GeglNode         *output;
  GeglProcessor    *processor;
  gdouble           value;

  progress = gimp_progress_start (GIMP_PROGRESS (sc), FALSE,
                                  _("Cloning the foreground object"));

  /* Find out at which x,y is the top left corner of the currently
   * displayed part */
  gimp_display_shell_untransform_viewport (shell, &x, &y, &w, &h);

  /* Find out where is our drawable positioned */
  gimp_item_get_offset (item, &off_x, &off_y);

  /* Create a rectangle from the intersection of the currently displayed
   * part with the drawable */
  gimp_rectangle_intersect (x, y, w, h,
                            off_x,
                            off_y,
                            gimp_item_get_width  (item),
                            gimp_item_get_height (item),
                            &visible.x,
                            &visible.y,
                            &visible.width,
                            &visible.height);

  /* Since the filter_apply function receives a rectangle describing
   * where it should update the preview, and since that rectangle should
   * be relative to the drawable's location, we now offset back by the
   * drawable's offsetts. */
  visible.x -= off_x;
  visible.y -= off_y;

  g_object_get (sc->sc_node, "gegl-operation", &op, NULL);
  /* If any cache of the visible area was present, clear it!
   * We need to clear the cache in the sc_node, since that is
   * where the previous paste was located
   */
  gegl_operation_invalidate (op, &visible, TRUE);
  g_object_unref (op);

  /* Now update the image map and show this area */
  gimp_drawable_filter_apply (sc->filter, NULL);

  /* Show update progress. */
  output = gegl_node_get_output_proxy (sc->render_node, "output");
  processor = gegl_node_new_processor (output, NULL);

  while (gegl_processor_work (processor, &value))
    {
      if (progress)
        gimp_progress_set_value (progress, value);
    }

  if (progress)
    gimp_progress_end (progress);

  g_object_unref (processor);
}
예제 #11
0
GeglBuffer *
gimp_drawable_transform_buffer_flip (GimpDrawable        *drawable,
                                     GimpContext         *context,
                                     GeglBuffer          *orig_buffer,
                                     gint                 orig_offset_x,
                                     gint                 orig_offset_y,
                                     GimpOrientationType  flip_type,
                                     gdouble              axis,
                                     gboolean             clip_result,
                                     gint                *new_offset_x,
                                     gint                *new_offset_y)
{
  GeglBuffer    *new_buffer;
  GeglRectangle  src_rect;
  GeglRectangle  dest_rect;
  gint           orig_x, orig_y;
  gint           orig_width, orig_height;
  gint           new_x, new_y;
  gint           new_width, new_height;
  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);
  g_return_val_if_fail (GIMP_IS_CONTEXT (context), NULL);
  g_return_val_if_fail (GEGL_IS_BUFFER (orig_buffer), NULL);

  orig_x      = orig_offset_x;
  orig_y      = orig_offset_y;
  orig_width  = gegl_buffer_get_width (orig_buffer);
  orig_height = gegl_buffer_get_height (orig_buffer);

  new_x      = orig_x;
  new_y      = orig_y;
  new_width  = orig_width;
  new_height = orig_height;

  switch (flip_type)
    {
    case GIMP_ORIENTATION_HORIZONTAL:
      new_x = RINT (-((gdouble) orig_x +
                      (gdouble) orig_width - axis) + axis);
      break;

    case GIMP_ORIENTATION_VERTICAL:
      new_y = RINT (-((gdouble) orig_y +
                      (gdouble) orig_height - axis) + axis);
      break;

    case GIMP_ORIENTATION_UNKNOWN:
      g_return_val_if_reached (NULL);
      break;
    }

  new_buffer = gimp_gegl_buffer_new (GEGL_RECTANGLE (0, 0,
                                                     new_width, new_height),
                                     gegl_buffer_get_format (orig_buffer));

  if (clip_result && (new_x != orig_x || new_y != orig_y))
    {
      GimpRGB    bg;
      GeglColor *color;
      gint       clip_x, clip_y;
      gint       clip_width, clip_height;

      *new_offset_x = orig_x;
      *new_offset_y = orig_y;

      /*  "Outside" a channel is transparency, not the bg color  */
      if (GIMP_IS_CHANNEL (drawable))
        gimp_rgba_set (&bg, 0.0, 0.0, 0.0, 0.0);
      else
        gimp_context_get_background (context, &bg);

      color = gimp_gegl_color_new (&bg);
      gegl_buffer_set_color (new_buffer, NULL, color);
      g_object_unref (color);

      if (gimp_rectangle_intersect (orig_x, orig_y, orig_width, orig_height,
                                    new_x, new_y, new_width, new_height,
                                    &clip_x, &clip_y,
                                    &clip_width, &clip_height))
        {
          orig_x = new_x = clip_x - orig_x;
          orig_y = new_y = clip_y - orig_y;
        }

      orig_width  = new_width  = clip_width;
      orig_height = new_height = clip_height;
    }
  else
    {
      *new_offset_x = new_x;
      *new_offset_y = new_y;

      orig_x = 0;
      orig_y = 0;
      new_x  = 0;
      new_y  = 0;
    }

  if (new_width == 0 && new_height == 0)
    return new_buffer;

  switch (flip_type)
    {
    case GIMP_ORIENTATION_HORIZONTAL:
      src_rect.x      = orig_x;
      src_rect.y      = orig_y;
      src_rect.width  = 1;
      src_rect.height = orig_height;

      dest_rect.x      = new_x + new_width - 1;
      dest_rect.y      = new_y;
      dest_rect.width  = 1;
      dest_rect.height = new_height;

      for (i = 0; i < orig_width; i++)
        {
          src_rect.x  = i + orig_x;
          dest_rect.x = new_x + new_width - i - 1;

          gegl_buffer_copy (orig_buffer, &src_rect,
                            new_buffer, &dest_rect);
        }
      break;

    case GIMP_ORIENTATION_VERTICAL:
      src_rect.x      = orig_x;
      src_rect.y      = orig_y;
      src_rect.width  = orig_width;
      src_rect.height = 1;

      dest_rect.x      = new_x;
      dest_rect.y      = new_y + new_height - 1;
      dest_rect.width  = new_width;
      dest_rect.height = 1;

      for (i = 0; i < orig_height; i++)
        {
          src_rect.y  = i + orig_y;
          dest_rect.y = new_y + new_height - i - 1;

          gegl_buffer_copy (orig_buffer, &src_rect,
                            new_buffer, &dest_rect);
        }
      break;

    case GIMP_ORIENTATION_UNKNOWN:
      break;
    }

  return new_buffer;
}
예제 #12
0
/**
 * gimp_drawable_get_line_art_fill_buffer:
 * @drawable: the #GimpDrawable to edit.
 * @line_art: the #GimpLineArt computed as fill source.
 * @options: the #GimpFillOptions.
 * @sample_merged:
 * @seed_x: X coordinate to start the fill.
 * @seed_y: Y coordinate to start the fill.
 * @mask_buffer: mask of the fill in-progress when in an interactive
 *               filling process. Set to NULL if you need a one-time
 *               fill.
 * @mask_x: returned x bound of @mask_buffer.
 * @mask_y: returned x bound of @mask_buffer.
 * @mask_width: returned width bound of @mask_buffer.
 * @mask_height: returned height bound of @mask_buffer.
 *
 * Creates the fill buffer for a bucket fill operation on @drawable
 * based on @line_art and @options, without actually applying it.
 * If @mask_buffer is not NULL, the intermediate fill mask will also be
 * returned. This fill mask can later be reused in successive calls to
 * gimp_drawable_get_bucket_fill_buffer() for interactive filling.
 *
 * Returns: a fill buffer which can be directly applied to @drawable, or
 *          used in a drawable filter as preview.
 */
GeglBuffer *
gimp_drawable_get_line_art_fill_buffer (GimpDrawable     *drawable,
                                        GimpLineArt      *line_art,
                                        GimpFillOptions  *options,
                                        gboolean          sample_merged,
                                        gdouble           seed_x,
                                        gdouble           seed_y,
                                        GeglBuffer      **mask_buffer,
                                        gdouble          *mask_x,
                                        gdouble          *mask_y,
                                        gint             *mask_width,
                                        gint             *mask_height)
{
  GimpImage  *image;
  GeglBuffer *buffer;
  GeglBuffer *new_mask;
  gint        x, y, width, height;
  gint        mask_offset_x = 0;
  gint        mask_offset_y = 0;
  gint        sel_x, sel_y, sel_width, sel_height;

  g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), NULL);
  g_return_val_if_fail (gimp_item_is_attached (GIMP_ITEM (drawable)), NULL);
  g_return_val_if_fail (GIMP_IS_FILL_OPTIONS (options), NULL);

  image = gimp_item_get_image (GIMP_ITEM (drawable));

  if (! gimp_item_mask_intersect (GIMP_ITEM (drawable),
                                  &sel_x, &sel_y, &sel_width, &sel_height))
    return NULL;

  if (mask_buffer && *mask_buffer)
    {
      gfloat pixel;

      gegl_buffer_sample (*mask_buffer, seed_x, seed_y, NULL, &pixel,
                          babl_format ("Y float"),
                          GEGL_SAMPLER_NEAREST, GEGL_ABYSS_NONE);

      if (pixel != 0.0)
        /* Already selected. This seed won't change the selection. */
        return NULL;
    }

  gimp_set_busy (image->gimp);

  /*  Do a seed bucket fill...To do this, calculate a new
   *  contiguous region.
   */
  new_mask = gimp_pickable_contiguous_region_by_line_art (NULL, line_art,
                                                          (gint) seed_x,
                                                          (gint) seed_y);
  if (mask_buffer && *mask_buffer)
    {
      gimp_gegl_mask_combine_buffer (new_mask, *mask_buffer,
                                     GIMP_CHANNEL_OP_ADD, 0, 0);
      g_object_unref (*mask_buffer);
    }
  if (mask_buffer)
    *mask_buffer = new_mask;

  gimp_gegl_mask_bounds (new_mask, &x, &y, &width, &height);
  width  -= x;
  height -= y;

  /*  If there is a selection, intersect the region bounds
   *  with the selection bounds, to avoid processing areas
   *  that are going to be masked out anyway.  The actual
   *  intersection of the fill region with the mask data
   *  happens when combining the fill buffer, in
   *  gimp_drawable_apply_buffer().
   */
  if (! gimp_channel_is_empty (gimp_image_get_mask (image)))
    {
      gint off_x = 0;
      gint off_y = 0;

      if (sample_merged)
        gimp_item_get_offset (GIMP_ITEM (drawable), &off_x, &off_y);

      if (! gimp_rectangle_intersect (x, y, width, height,

                                      sel_x + off_x, sel_y + off_y,
                                      sel_width,     sel_height,

                                      &x, &y, &width, &height))
        {
          if (! mask_buffer)
            g_object_unref (new_mask);
          /*  The fill region and the selection are disjoint; bail.  */
          gimp_unset_busy (image->gimp);

          return NULL;
        }
    }

  /*  make sure we handle the mask correctly if it was sample-merged  */
  if (sample_merged)
    {
      GimpItem *item = GIMP_ITEM (drawable);
      gint      off_x, off_y;

      /*  Limit the channel bounds to the drawable's extents  */
      gimp_item_get_offset (item, &off_x, &off_y);

      gimp_rectangle_intersect (x, y, width, height,

                                off_x, off_y,
                                gimp_item_get_width (item),
                                gimp_item_get_height (item),

                                &x, &y, &width, &height);

      mask_offset_x = x;
      mask_offset_y = y;

     /*  translate mask bounds to drawable coords  */
      x -= off_x;
      y -= off_y;
    }
  else
    {
      mask_offset_x = x;
      mask_offset_y = y;
    }

  buffer = gimp_fill_options_create_buffer (options, drawable,
                                            GEGL_RECTANGLE (0, 0,
                                                            width, height),
                                            -x, -y);

  gimp_gegl_apply_opacity (buffer, NULL, NULL, buffer, new_mask,
                           -mask_offset_x, -mask_offset_y, 1.0);

  if (gimp_fill_options_get_antialias (options))
    {
      /* Antialias for the line art algorithm is not applied during mask
       * creation because it is not based on individual pixel colors.
       * Instead we just want to apply it on the borders of the mask at
       * the end (since the mask can evolve, we don't want to actually
       * touch it, but only the intermediate results).
       */
      GeglNode   *graph;
      GeglNode   *input;
      GeglNode   *op;

      graph = gegl_node_new ();
      input = gegl_node_new_child (graph,
                                   "operation", "gegl:buffer-source",
                                   "buffer", buffer,
                                   NULL);
      op  = gegl_node_new_child (graph,
                                 "operation", "gegl:gaussian-blur",
                                 "std-dev-x", 0.5,
                                 "std-dev-y", 0.5,
                                 NULL);
      gegl_node_connect_to (input, "output", op, "input");
      gegl_node_blit_buffer (op, buffer, NULL, 0,
                             GEGL_ABYSS_NONE);
      g_object_unref (graph);
    }

  if (mask_x)
    *mask_x = x;
  if (mask_y)
    *mask_y = y;
  if (mask_width)
    *mask_width = width;
  if (mask_height)
    *mask_height = height;

  if (! mask_buffer)
    g_object_unref (new_mask);

  gimp_unset_busy (image->gimp);

  return buffer;
}
예제 #13
0
/**
 * gimp_channel_combine_ellipse_rect:
 * @mask:      the channel with which to combine the elliptic rect
 * @op:        whether to replace, add to, or subtract from the current
 *             contents
 * @x:         x coordinate of upper left corner of bounding rect
 * @y:         y coordinate of upper left corner of bounding rect
 * @w:         width of bounding rect
 * @h:         height of bounding rect
 * @a:         elliptic a-constant applied to corners
 * @b:         elliptic b-constant applied to corners
 * @antialias: if %TRUE, antialias the elliptic corners
 *
 * Used for rounded cornered rectangles and ellipses.  If @op is
 * %GIMP_CHANNEL_OP_REPLACE or %GIMP_CHANNEL_OP_ADD, sets pixels
 * within the ellipse to 255.  If @op is %GIMP_CHANNEL_OP_SUBTRACT,
 * sets pixels within to zero.  If @antialias is %TRUE, pixels that
 * impinge on the edge of the ellipse are set to intermediate values,
 * depending on how much they overlap.
 **/
void
gimp_channel_combine_ellipse_rect (GimpChannel    *mask,
                                   GimpChannelOps  op,
                                   gint            x,
                                   gint            y,
                                   gint            w,
                                   gint            h,
                                   gdouble         a,
                                   gdouble         b,
                                   gboolean        antialias)
{
  PixelRegion  maskPR;
  gdouble      a_sqr;
  gdouble      b_sqr;
  gdouble      ellipse_center_x;
  gint         x0, y0;
  gint         width, height;
  gpointer     pr;

  g_return_if_fail (GIMP_IS_CHANNEL (mask));
  g_return_if_fail (a >= 0.0 && b >= 0.0);
  g_return_if_fail (op != GIMP_CHANNEL_OP_INTERSECT);

  /* Make sure the elliptic corners fit into the rect */
  a = MIN (a, w / 2.0);
  b = MIN (b, h / 2.0);

  a_sqr = SQR (a);
  b_sqr = SQR (b);

  if (! gimp_rectangle_intersect (x, y, w, h,
                                  0, 0,
                                  gimp_item_get_width  (GIMP_ITEM (mask)),
                                  gimp_item_get_height (GIMP_ITEM (mask)),
                                  &x0, &y0, &width, &height))
    return;

  ellipse_center_x = x + a;

  pixel_region_init (&maskPR, gimp_drawable_get_tiles (GIMP_DRAWABLE (mask)),
                     x0, y0, width, height, TRUE);

  for (pr = pixel_regions_register (1, &maskPR);
       pr != NULL;
       pr = pixel_regions_process (pr))
    {
      guchar *data = maskPR.data;
      gint    py;

      for (py = maskPR.y;
           py < maskPR.y + maskPR.h;
           py++, data += maskPR.rowstride)
        {
          const gint px = maskPR.x;
          gdouble    ellipse_center_y;

          if (py >= y + b && py < y + h - b)
            {
              /*  we are on a row without rounded corners  */
              gimp_channel_combine_span (data, op, 0, maskPR.w, 255);
              continue;
            }

          /* Match the ellipse center y with our current y */
          if (py < y + b)
            {
              ellipse_center_y = y + b;
            }
          else
            {
              ellipse_center_y = y + h - b;
            }

          /* For a non-antialiased ellipse, use the normal equation
           * for an ellipse with an arbitrary center
           * (ellipse_center_x, ellipse_center_y).
           */
          if (! antialias)
            {
              gdouble     half_ellipse_width_at_y;
              gint        x_start;
              gint        x_end;

              half_ellipse_width_at_y =
                sqrt (a_sqr -
                      a_sqr * SQR (py + 0.5f - ellipse_center_y) / b_sqr);

              x_start = ROUND (ellipse_center_x - half_ellipse_width_at_y);
              x_end   = ROUND (ellipse_center_x + w - 2 * a +
                               half_ellipse_width_at_y);

              gimp_channel_combine_span (data, op,
                                         MAX (x_start - px, 0),
                                         MIN (x_end   - px, maskPR.w), 255);
            }
          else  /* use antialiasing */
            {
              /* algorithm changed 7-18-04, because the previous one
               * did not work well for eccentric ellipses.  The new
               * algorithm measures the distance to the ellipse in the
               * X and Y directions, and uses trigonometry to
               * approximate the distance to the ellipse as the
               * distance to the hypotenuse of a right triangle whose
               * legs are the X and Y distances.  (WES)
               */
              const gfloat yi       = ABS (py + 0.5 - ellipse_center_y);
              gint         last_val = -1;
              gint         x_start  = px;
              gint         cur_x;

              for (cur_x = px; cur_x < (px + maskPR.w); cur_x++)
                {
                  gfloat  xj;
                  gfloat  xdist;
                  gfloat  ydist;
                  gfloat  r;
                  gfloat  dist;
                  gint    val;

                  if (cur_x < x + w / 2)
                    {
                      ellipse_center_x = x + a;
                    }
                  else
                    {
                      ellipse_center_x = x + w - a;
                    }

                  xj = ABS (cur_x + 0.5 - ellipse_center_x);

                  if (yi < b)
                    xdist = xj - a * sqrt (1 - SQR (yi) / b_sqr);
                  else
                    xdist = 1000.0;  /* anything large will work */

                  if (xj < a)
                    ydist = yi - b * sqrt (1 - SQR (xj) / a_sqr);
                  else
                    ydist = 1000.0;  /* anything large will work */

                  r = hypot (xdist, ydist);

                  if (r < 0.001)
                    dist = 0.;
                  else
                    dist = xdist * ydist / r; /* trig formula for distance to
                                               * hypotenuse
                                               */

                  if (xdist < 0.0)
                    dist *= -1;

                  if (dist < -0.5)
                    val = 255;
                  else if (dist < 0.5)
                    val = (gint) (255 * (1 - (dist + 0.5)));
                  else
                    val = 0;

                  if (last_val != val)
                    {
                      if (last_val != -1)
                        gimp_channel_combine_span (data, op,
                                                   MAX (x_start - px, 0),
                                                   MIN (cur_x   - px, maskPR.w),
                                                   last_val);

                      x_start = cur_x;
                      last_val = val;
                    }

                  /*  skip ahead if we are on the straight segment
                   *  between rounded corners
                   */
                  if (cur_x >= x + a && cur_x < x + w - a)
                    {
                      gimp_channel_combine_span (data, op,
                                                 MAX (x_start - px, 0),
                                                 MIN (cur_x   - px, maskPR.w),
                                                 last_val);

                      x_start = cur_x;
                      cur_x = x + w - a;
                      last_val = val = 255;
                    }

                  /* Time to change center? */
                  if (cur_x >= x + w / 2)
                    {
                      ellipse_center_x = x + w - a;
                    }
                }

              gimp_channel_combine_span (data, op,
                                         MAX (x_start - px, 0),
                                         MIN (cur_x   - px, maskPR.w),
                                         last_val);
            }
        }
    }

  /*  use the intersected values for the boundary calculation  */
  x = x0;
  y = y0;
  w = width;
  h = height;

  /*  determine new boundary  */
  if (mask->bounds_known && (op == GIMP_CHANNEL_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 == GIMP_CHANNEL_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;
    }

  gimp_drawable_update (GIMP_DRAWABLE (mask), x, y, w, h);
}
예제 #14
0
void
gimp_paint_core_finish (GimpPaintCore *core,
                        GimpDrawable  *drawable,
                        gboolean       push_undo)
{
  GimpImage *image;

  g_return_if_fail (GIMP_IS_PAINT_CORE (core));
  g_return_if_fail (GIMP_IS_DRAWABLE (drawable));
  g_return_if_fail (gimp_item_is_attached (GIMP_ITEM (drawable)));

  if (core->applicator)
    {
      g_object_unref (core->applicator);
      core->applicator = NULL;
    }

  if (core->stroke_buffer)
    {
      g_array_free (core->stroke_buffer, TRUE);
      core->stroke_buffer = NULL;
    }

  if (core->mask_buffer)
    {
      g_object_unref (core->mask_buffer);
      core->mask_buffer = NULL;
    }

  if (core->comp_buffer)
    {
      g_object_unref (core->comp_buffer);
      core->comp_buffer = NULL;
    }

  image = gimp_item_get_image (GIMP_ITEM (drawable));

  /*  Determine if any part of the image has been altered--
   *  if nothing has, then just return...
   */
  if ((core->x2 == core->x1) || (core->y2 == core->y1))
    {
      gimp_viewable_preview_thaw (GIMP_VIEWABLE (drawable));
      return;
    }

  if (push_undo)
    {
      GeglBuffer *buffer;
      gint        x, y, width, height;

      gimp_rectangle_intersect (core->x1, core->y1,
                                core->x2 - core->x1, core->y2 - core->y1,
                                0, 0,
                                gimp_item_get_width  (GIMP_ITEM (drawable)),
                                gimp_item_get_height (GIMP_ITEM (drawable)),
                                &x, &y, &width, &height);

      gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_PAINT,
                                   core->undo_desc);

      GIMP_PAINT_CORE_GET_CLASS (core)->push_undo (core, image, NULL);

      buffer = gegl_buffer_new (GEGL_RECTANGLE (0, 0, width, height),
                                gimp_drawable_get_format (drawable));

      gegl_buffer_copy (core->undo_buffer,
                        GEGL_RECTANGLE (x, y, width, height),
                        buffer,
                        GEGL_RECTANGLE (0, 0, 0, 0));

      gimp_drawable_push_undo (drawable, NULL,
                               buffer, x, y, width, height);

      g_object_unref (buffer);

      gimp_image_undo_group_end (image);
    }

  g_object_unref (core->undo_buffer);
  core->undo_buffer = NULL;

  if (core->saved_proj_buffer)
    {
      g_object_unref (core->saved_proj_buffer);
      core->saved_proj_buffer = NULL;
    }

  gimp_viewable_preview_thaw (GIMP_VIEWABLE (drawable));
}
예제 #15
0
void
gimp_channel_combine_rect (GimpChannel    *mask,
                           GimpChannelOps  op,
                           gint            x,
                           gint            y,
                           gint            w,
                           gint            h)
{
  PixelRegion maskPR;
  guchar      color;

  g_return_if_fail (GIMP_IS_CHANNEL (mask));

  if (! gimp_rectangle_intersect (x, y, w, h,
                                  0, 0,
                                  gimp_item_get_width  (GIMP_ITEM (mask)),
                                  gimp_item_get_height (GIMP_ITEM (mask)),
                                  &x, &y, &w, &h))
    return;

  pixel_region_init (&maskPR, gimp_drawable_get_tiles (GIMP_DRAWABLE (mask)),
                     x, y, w, h, TRUE);

  if (op == GIMP_CHANNEL_OP_ADD || op == GIMP_CHANNEL_OP_REPLACE)
    color = OPAQUE_OPACITY;
  else
    color = TRANSPARENT_OPACITY;

  color_region (&maskPR, &color);

  /*  Determine new boundary  */
  if (mask->bounds_known && (op == GIMP_CHANNEL_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 == GIMP_CHANNEL_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_item_get_width  (GIMP_ITEM (mask)));
  mask->y1 = CLAMP (mask->y1, 0, gimp_item_get_height (GIMP_ITEM (mask)));
  mask->x2 = CLAMP (mask->x2, 0, gimp_item_get_width  (GIMP_ITEM (mask)));
  mask->y2 = CLAMP (mask->y2, 0, gimp_item_get_height (GIMP_ITEM (mask)));

  gimp_drawable_update (GIMP_DRAWABLE (mask), x, y, w, h);
}
예제 #16
0
GeglBuffer *
gimp_drawable_transform_buffer_rotate (GimpDrawable      *drawable,
                                       GimpContext       *context,
                                       GeglBuffer        *orig_buffer,
                                       gint               orig_offset_x,
                                       gint               orig_offset_y,
                                       GimpRotationType   rotate_type,
                                       gdouble            center_x,
                                       gdouble            center_y,
                                       gboolean           clip_result,
                                       GimpColorProfile **buffer_profile,
                                       gint              *new_offset_x,
                                       gint              *new_offset_y)
{
  const Babl    *format;
  GeglBuffer    *new_buffer;
  GeglRectangle  src_rect;
  GeglRectangle  dest_rect;
  gint           orig_x, orig_y;
  gint           orig_width, orig_height;
  gint           orig_bpp;
  gint           new_x, new_y;
  gint           new_width, new_height;

  g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), NULL);
  g_return_val_if_fail (gimp_item_is_attached (GIMP_ITEM (drawable)), NULL);
  g_return_val_if_fail (GIMP_IS_CONTEXT (context), NULL);
  g_return_val_if_fail (GEGL_IS_BUFFER (orig_buffer), NULL);
  g_return_val_if_fail (buffer_profile != NULL, NULL);
  g_return_val_if_fail (new_offset_x != NULL, NULL);
  g_return_val_if_fail (new_offset_y != NULL, NULL);

  *buffer_profile =
    gimp_color_managed_get_color_profile (GIMP_COLOR_MANAGED (drawable));

  orig_x      = orig_offset_x;
  orig_y      = orig_offset_y;
  orig_width  = gegl_buffer_get_width (orig_buffer);
  orig_height = gegl_buffer_get_height (orig_buffer);
  orig_bpp    = babl_format_get_bytes_per_pixel (gegl_buffer_get_format (orig_buffer));

  switch (rotate_type)
    {
    case GIMP_ROTATE_90:
      gimp_drawable_transform_rotate_point (orig_x,
                                            orig_y + orig_height,
                                            rotate_type, center_x, center_y,
                                            &new_x, &new_y);
      new_width  = orig_height;
      new_height = orig_width;
      break;

    case GIMP_ROTATE_180:
      gimp_drawable_transform_rotate_point (orig_x + orig_width,
                                            orig_y + orig_height,
                                            rotate_type, center_x, center_y,
                                            &new_x, &new_y);
      new_width  = orig_width;
      new_height = orig_height;
      break;

    case GIMP_ROTATE_270:
      gimp_drawable_transform_rotate_point (orig_x + orig_width,
                                            orig_y,
                                            rotate_type, center_x, center_y,
                                            &new_x, &new_y);
      new_width  = orig_height;
      new_height = orig_width;
      break;

    default:
      g_return_val_if_reached (NULL);
      break;
    }

  format = gegl_buffer_get_format (orig_buffer);

  if (clip_result && (new_x != orig_x || new_y != orig_y ||
                      new_width != orig_width || new_height != orig_height))

    {
      GimpRGB    bg;
      GeglColor *color;
      gint       clip_x, clip_y;
      gint       clip_width, clip_height;

      new_buffer = gegl_buffer_new (GEGL_RECTANGLE (0, 0,
                                                    orig_width, orig_height),
                                    format);

      *new_offset_x = orig_x;
      *new_offset_y = orig_y;

      /*  Use transparency, rather than the bg color, as the "outside" color of
       *  channels, and drawables with an alpha channel.
       */
      if (GIMP_IS_CHANNEL (drawable) || babl_format_has_alpha (format))
        {
          gimp_rgba_set (&bg, 0.0, 0.0, 0.0, 0.0);
        }
      else
        {
          gimp_context_get_background (context, &bg);
          gimp_pickable_srgb_to_image_color (GIMP_PICKABLE (drawable),
                                             &bg, &bg);
        }

      color = gimp_gegl_color_new (&bg, gimp_drawable_get_space (drawable));
      gegl_buffer_set_color (new_buffer, NULL, color);
      g_object_unref (color);

      if (gimp_rectangle_intersect (orig_x, orig_y, orig_width, orig_height,
                                    new_x, new_y, new_width, new_height,
                                    &clip_x, &clip_y,
                                    &clip_width, &clip_height))
        {
          gint saved_orig_x = orig_x;
          gint saved_orig_y = orig_y;

          new_x = clip_x - orig_x;
          new_y = clip_y - orig_y;

          switch (rotate_type)
            {
            case GIMP_ROTATE_90:
              gimp_drawable_transform_rotate_point (clip_x + clip_width,
                                                    clip_y,
                                                    GIMP_ROTATE_270,
                                                    center_x,
                                                    center_y,
                                                    &orig_x,
                                                    &orig_y);
              orig_x      -= saved_orig_x;
              orig_y      -= saved_orig_y;
              orig_width   = clip_height;
              orig_height  = clip_width;
              break;

            case GIMP_ROTATE_180:
              orig_x      = clip_x - orig_x;
              orig_y      = clip_y - orig_y;
              orig_width  = clip_width;
              orig_height = clip_height;
              break;

            case GIMP_ROTATE_270:
              gimp_drawable_transform_rotate_point (clip_x,
                                                    clip_y + clip_height,
                                                    GIMP_ROTATE_90,
                                                    center_x,
                                                    center_y,
                                                    &orig_x,
                                                    &orig_y);
              orig_x      -= saved_orig_x;
              orig_y      -= saved_orig_y;
              orig_width   = clip_height;
              orig_height  = clip_width;
              break;
            }

          new_width  = clip_width;
          new_height = clip_height;
        }
      else
        {
          new_width  = 0;
          new_height = 0;
        }
    }
  else
    {
      new_buffer = gegl_buffer_new (GEGL_RECTANGLE (0, 0,
                                                    new_width, new_height),
                                    format);

      *new_offset_x = new_x;
      *new_offset_y = new_y;

      orig_x = 0;
      orig_y = 0;
      new_x  = 0;
      new_y  = 0;
    }

  if (new_width < 1 || new_height < 1)
    return new_buffer;

  src_rect.x      = orig_x;
  src_rect.y      = orig_y;
  src_rect.width  = orig_width;
  src_rect.height = orig_height;

  dest_rect.x      = new_x;
  dest_rect.y      = new_y;
  dest_rect.width  = new_width;
  dest_rect.height = new_height;

  switch (rotate_type)
    {
    case GIMP_ROTATE_90:
      {
        guchar *buf = g_new (guchar, new_height * orig_bpp);
        gint    i;

        /* Not cool, we leak memory if we return, but anyway that is
         * never supposed to happen. If we see this warning, a bug has
         * to be fixed!
         */
        g_return_val_if_fail (new_height == orig_width, NULL);

        src_rect.y      = orig_y + orig_height - 1;
        src_rect.height = 1;

        dest_rect.x     = new_x;
        dest_rect.width = 1;

        for (i = 0; i < orig_height; i++)
          {
            src_rect.y  = orig_y + orig_height - 1 - i;
            dest_rect.x = new_x + i;

            gegl_buffer_get (orig_buffer, &src_rect, 1.0, NULL, buf,
                             GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE);
            gegl_buffer_set (new_buffer, &dest_rect, 0, NULL, buf,
                             GEGL_AUTO_ROWSTRIDE);
          }

        g_free (buf);
      }
      break;

    case GIMP_ROTATE_180:
      {
        guchar *buf = g_new (guchar, new_width * orig_bpp);
        gint    i, j, k;

        /* Not cool, we leak memory if we return, but anyway that is
         * never supposed to happen. If we see this warning, a bug has
         * to be fixed!
         */
        g_return_val_if_fail (new_width == orig_width, NULL);

        src_rect.y      = orig_y + orig_height - 1;
        src_rect.height = 1;

        dest_rect.y      = new_y;
        dest_rect.height = 1;

        for (i = 0; i < orig_height; i++)
          {
            src_rect.y  = orig_y + orig_height - 1 - i;
            dest_rect.y = new_y + i;

            gegl_buffer_get (orig_buffer, &src_rect, 1.0, NULL, buf,
                             GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE);

            for (j = 0; j < orig_width / 2; j++)
              {
                guchar *left  = buf + j * orig_bpp;
                guchar *right = buf + (orig_width - 1 - j) * orig_bpp;

                for (k = 0; k < orig_bpp; k++)
                  {
                    guchar tmp = left[k];
                    left[k]    = right[k];
                    right[k]   = tmp;
                  }
              }

            gegl_buffer_set (new_buffer, &dest_rect, 0, NULL, buf,
                             GEGL_AUTO_ROWSTRIDE);
          }

        g_free (buf);
      }
      break;

    case GIMP_ROTATE_270:
      {
        guchar *buf = g_new (guchar, new_width * orig_bpp);
        gint    i;

        /* Not cool, we leak memory if we return, but anyway that is
         * never supposed to happen. If we see this warning, a bug has
         * to be fixed!
         */
        g_return_val_if_fail (new_width == orig_height, NULL);

        src_rect.x     = orig_x + orig_width - 1;
        src_rect.width = 1;

        dest_rect.y      = new_y;
        dest_rect.height = 1;

        for (i = 0; i < orig_width; i++)
          {
            src_rect.x  = orig_x + orig_width - 1 - i;
            dest_rect.y = new_y + i;

            gegl_buffer_get (orig_buffer, &src_rect, 1.0, NULL, buf,
                             GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE);
            gegl_buffer_set (new_buffer, &dest_rect, 0, NULL, buf,
                             GEGL_AUTO_ROWSTRIDE);
          }

        g_free (buf);
      }
      break;
    }

  return new_buffer;
}
예제 #17
0
static void
gimp_image_map_tool_options_notify (GimpTool         *tool,
                                    GimpToolOptions  *options,
                                    const GParamSpec *pspec)
{
  GimpImageMapTool    *im_tool    = GIMP_IMAGE_MAP_TOOL (tool);
  GimpImageMapOptions *im_options = GIMP_IMAGE_MAP_OPTIONS (options);

  if (! strcmp (pspec->name, "preview") &&
      im_tool->image_map)
    {
      if (im_options->preview)
        {
          gimp_tool_control_push_preserve (tool->control, TRUE);

          gimp_image_map_apply (im_tool->image_map, NULL);

          gimp_tool_control_pop_preserve (tool->control);

          if (im_options->preview_split)
            gimp_image_map_tool_add_guide (im_tool);
        }
      else
        {
          gimp_tool_control_push_preserve (tool->control, TRUE);

          gimp_image_map_abort (im_tool->image_map);

          gimp_tool_control_pop_preserve (tool->control);

          if (im_options->preview_split)
            gimp_image_map_tool_remove_guide (im_tool);
        }
    }
  else if (! strcmp (pspec->name, "preview-split") &&
           im_tool->image_map)
    {
      if (im_options->preview_split)
        {
          GimpDisplayShell *shell = gimp_display_get_shell (tool->display);
          GimpItem         *item  = GIMP_ITEM (im_tool->drawable);
          gint              x, y, width, height;

          gimp_display_shell_untransform_viewport (shell,
                                                   &x, &y, &width, &height);

          if (gimp_rectangle_intersect (gimp_item_get_offset_x (item),
                                        gimp_item_get_offset_y (item),
                                        gimp_item_get_width  (item),
                                        gimp_item_get_height (item),
                                        x, y, width, height,
                                        &x, &y, &width, &height))
            {
              gdouble position;

              if (im_options->preview_alignment == GIMP_ALIGN_LEFT ||
                  im_options->preview_alignment == GIMP_ALIGN_RIGHT)
                {
                  position = ((gdouble) ((x + width / 2) -
                                         gimp_item_get_offset_x (item)) /
                              (gdouble) gimp_item_get_width (item));
                }
              else
                {
                  position = ((gdouble) ((y + height / 2) -
                                         gimp_item_get_offset_y (item)) /
                              (gdouble) gimp_item_get_height (item));
                }

              g_object_set (options,
                            "preview-position", CLAMP (position, 0.0, 1.0),
                            NULL);

            }
        }

      gimp_image_map_set_preview (im_tool->image_map,
                                  im_options->preview_split,
                                  im_options->preview_alignment,
                                  im_options->preview_position);

      if (im_options->preview_split)
        gimp_image_map_tool_add_guide (im_tool);
      else
        gimp_image_map_tool_remove_guide (im_tool);
    }
  else if (! strcmp (pspec->name, "preview-alignment") &&
           im_tool->image_map)
    {
      gimp_image_map_set_preview (im_tool->image_map,
                                  im_options->preview_split,
                                  im_options->preview_alignment,
                                  im_options->preview_position);

      if (im_options->preview_split)
        gimp_image_map_tool_move_guide (im_tool);
    }
  else if (! strcmp (pspec->name, "preview-position") &&
           im_tool->image_map)
    {
      gimp_image_map_set_preview (im_tool->image_map,
                                  im_options->preview_split,
                                  im_options->preview_alignment,
                                  im_options->preview_position);

      if (im_options->preview_split)
        gimp_image_map_tool_move_guide (im_tool);
    }
  else if (! strcmp (pspec->name, "region") &&
           im_tool->image_map)
    {
      gimp_image_map_set_region (im_tool->image_map, im_options->region);
      gimp_image_map_tool_preview (im_tool);
    }
}
예제 #18
0
void
gimp_drawable_real_apply_buffer (GimpDrawable         *drawable,
                                 GeglBuffer           *buffer,
                                 const GeglRectangle  *buffer_region,
                                 gboolean              push_undo,
                                 const gchar          *undo_desc,
                                 gdouble               opacity,
                                 GimpLayerModeEffects  mode,
                                 GeglBuffer           *base_buffer,
                                 gint                  base_x,
                                 gint                  base_y)
{
  GimpItem          *item        = GIMP_ITEM (drawable);
  GimpImage         *image       = gimp_item_get_image (item);
  GimpChannel       *mask        = gimp_image_get_mask (image);
  GeglBuffer        *mask_buffer = NULL;
  GeglNode          *apply;
  GimpComponentMask  affect;
  gint               x, y, width, height;
  gint               offset_x, offset_y;

  /*  don't apply the mask to itself and don't apply an empty mask  */
  if (GIMP_DRAWABLE (mask) == drawable || gimp_channel_is_empty (mask))
    mask = NULL;

  if (! base_buffer)
    base_buffer = gimp_drawable_get_buffer (drawable);

  /*  get the layer offsets  */
  gimp_item_get_offset (item, &offset_x, &offset_y);

  /*  make sure the image application coordinates are within drawable bounds  */
  gimp_rectangle_intersect (base_x, base_y,
                            buffer_region->width, buffer_region->height,
                            0, 0,
                            gimp_item_get_width  (item),
                            gimp_item_get_height (item),
                            &x, &y, &width, &height);

  if (mask)
    {
      GimpItem *mask_item = GIMP_ITEM (mask);

      /*  make sure coordinates are in mask bounds ...
       *  we need to add the layer offset to transform coords
       *  into the mask coordinate system
       */
      gimp_rectangle_intersect (x, y, width, height,
                                -offset_x, -offset_y,
                                gimp_item_get_width  (mask_item),
                                gimp_item_get_height (mask_item),
                                &x, &y, &width, &height);
    }

  if (push_undo)
    {
      GimpDrawableUndo *undo;

      gimp_drawable_push_undo (drawable, undo_desc,
                               NULL, x, y, width, height);

      undo = GIMP_DRAWABLE_UNDO (gimp_image_undo_get_fadeable (image));

      if (undo)
        {
          undo->paint_mode = mode;
          undo->opacity    = opacity;

          undo->applied_buffer =
            gegl_buffer_new (GEGL_RECTANGLE (0, 0, width, height),
                             gegl_buffer_get_format (buffer));

          gegl_buffer_copy (buffer,
                            GEGL_RECTANGLE (buffer_region->x + (x - base_x),
                                            buffer_region->y + (y - base_y),
                                            width, height),
                            undo->applied_buffer,
                            GEGL_RECTANGLE (0, 0, width, height));
        }
    }

  if (mask)
    mask_buffer = gimp_drawable_get_buffer (GIMP_DRAWABLE (mask));

  affect = gimp_drawable_get_active_mask (drawable);

  apply = gimp_gegl_create_apply_buffer_node (buffer,
                                              base_x - buffer_region->x,
                                              base_y - buffer_region->y,
                                              0,
                                              0,
                                              0,
                                              0,
                                              mask_buffer,
                                              -offset_x,
                                              -offset_y,
                                              opacity,
                                              mode,
                                              affect);

  gimp_gegl_apply_operation (base_buffer, NULL, NULL,
                             apply,
                             gimp_drawable_get_buffer (drawable),
                             GEGL_RECTANGLE (x, y, width, height));

  g_object_unref (apply);
}
예제 #19
0
void
gimp_paint_core_paste (GimpPaintCore            *core,
                       PixelRegion              *paint_maskPR,
                       GimpDrawable             *drawable,
                       gdouble                   paint_opacity,
                       gdouble                   image_opacity,
                       GimpLayerModeEffects      paint_mode,
                       GimpPaintApplicationMode  mode)
{
  TileManager *alt = NULL;
  PixelRegion  srcPR;

  /*  set undo blocks  */
  gimp_paint_core_validate_undo_tiles (core, drawable,
                                       core->canvas_buf->x,
                                       core->canvas_buf->y,
                                       core->canvas_buf->width,
                                       core->canvas_buf->height);

  if (core->use_saved_proj)
    {
      GimpImage      *image      = gimp_item_get_image (GIMP_ITEM (drawable));
      GimpProjection *projection = gimp_image_get_projection (image);
      gint            off_x;
      gint            off_y;
      gint            x, y;
      gint            w, h;

      gimp_item_get_offset (GIMP_ITEM (drawable), &off_x, &off_y);

      if (gimp_rectangle_intersect (core->canvas_buf->x + off_x,
                                    core->canvas_buf->y + off_y,
                                    core->canvas_buf->width,
                                    core->canvas_buf->height,
                                    0, 0,
                                    tile_manager_width (core->saved_proj_tiles),
                                    tile_manager_height (core->saved_proj_tiles),
                                    &x, &y, &w, &h))
        {
          gimp_paint_core_validate_saved_proj_tiles (core,
                                                     GIMP_PICKABLE (projection),
                                                     x, y, w, h);
        }
    }

  /*  If the mode is CONSTANT:
   *   combine the canvas buf, the paint mask to the canvas tiles
   */
  if (mode == GIMP_PAINT_CONSTANT)
    {
      /* Some tools (ink) paint the mask to paint_core->canvas_tiles
       * directly. Don't need to copy it in this case.
       */
      if (paint_maskPR->tiles != core->canvas_tiles)
        {
          /*  initialize any invalid canvas tiles  */
          gimp_paint_core_validate_canvas_tiles (core,
                                                 core->canvas_buf->x,
                                                 core->canvas_buf->y,
                                                 core->canvas_buf->width,
                                                 core->canvas_buf->height);

          paint_mask_to_canvas_tiles (core, paint_maskPR, paint_opacity);
        }

      canvas_tiles_to_canvas_buf (core);
      alt = core->undo_tiles;
    }
  /*  Otherwise:
   *   combine the canvas buf and the paint mask to the canvas buf
   */
  else
    {
      paint_mask_to_canvas_buf (core, paint_maskPR, paint_opacity);
    }

  /*  intialize canvas buf source pixel regions  */
  pixel_region_init_temp_buf (&srcPR, core->canvas_buf,
                              0, 0,
                              core->canvas_buf->width,
                              core->canvas_buf->height);

  /*  apply the paint area to the image  */
  gimp_drawable_apply_region (drawable, &srcPR,
                              FALSE, NULL,
                              image_opacity, paint_mode,
                              alt,  /*  specify an alternative src1  */
                              NULL,
                              core->canvas_buf->x,
                              core->canvas_buf->y);

  /*  Update the undo extents  */
  core->x1 = MIN (core->x1, core->canvas_buf->x);
  core->y1 = MIN (core->y1, core->canvas_buf->y);
  core->x2 = MAX (core->x2, core->canvas_buf->x + core->canvas_buf->width);
  core->y2 = MAX (core->y2, core->canvas_buf->y + core->canvas_buf->height);

  /*  Update the drawable  */
  gimp_drawable_update (drawable,
                        core->canvas_buf->x,
                        core->canvas_buf->y,
                        core->canvas_buf->width,
                        core->canvas_buf->height);
}
예제 #20
0
/*  Similar to gimp_drawable_apply_region but works in "replace" mode (i.e.
 *  transparent pixels in src2 make the result transparent rather than
 *  opaque.
 *
 * Takes an additional mask pixel region as well.
 */
void
gimp_drawable_real_replace_buffer (GimpDrawable        *drawable,
                                   GeglBuffer          *buffer,
                                   const GeglRectangle *buffer_region,
                                   gboolean             push_undo,
                                   const gchar         *undo_desc,
                                   gdouble              opacity,
                                   GeglBuffer          *mask_buffer,
                                   const GeglRectangle *mask_buffer_region,
                                   gint                 dest_x,
                                   gint                 dest_y)
{
  GimpItem        *item  = GIMP_ITEM (drawable);
  GimpImage       *image = gimp_item_get_image (item);
  GimpChannel     *mask  = gimp_image_get_mask (image);
  GeglBuffer      *drawable_buffer;
  gint             x, y, width, height;
  gint             offset_x, offset_y;
  gboolean         active_components[MAX_CHANNELS];

  /*  don't apply the mask to itself and don't apply an empty mask  */
  if (GIMP_DRAWABLE (mask) == drawable || gimp_channel_is_empty (mask))
    mask = NULL;

  /*  configure the active channel array  */
  gimp_drawable_get_active_components (drawable, active_components);

  /*  get the layer offsets  */
  gimp_item_get_offset (item, &offset_x, &offset_y);

  /*  make sure the image application coordinates are within drawable bounds  */
  gimp_rectangle_intersect (dest_x, dest_y,
                            buffer_region->width, buffer_region->height,
                            0, 0,
                            gimp_item_get_width  (item),
                            gimp_item_get_height (item),
                            &x, &y, &width, &height);

  if (mask)
    {
      GimpItem *mask_item = GIMP_ITEM (mask);

      /*  make sure coordinates are in mask bounds ...
       *  we need to add the layer offset to transform coords
       *  into the mask coordinate system
       */
      gimp_rectangle_intersect (x, y, width, height,
                                -offset_x, -offset_y,
                                gimp_item_get_width  (mask_item),
                                gimp_item_get_height (mask_item),
                                &x, &y, &width, &height);
    }

  /*  If the calling procedure specified an undo step...  */
  if (push_undo)
    gimp_drawable_push_undo (drawable, undo_desc,
                             NULL, x, y, width, height);

  drawable_buffer = gimp_drawable_get_buffer (drawable);

  if (mask)
    {
      GeglBuffer *src_buffer;
      GeglBuffer *dest_buffer;

      src_buffer = gimp_drawable_get_buffer (GIMP_DRAWABLE (mask));

      dest_buffer = gegl_buffer_new (GEGL_RECTANGLE (0, 0, width, height),
                                     gegl_buffer_get_format (src_buffer));

      gegl_buffer_copy (src_buffer,
                        GEGL_RECTANGLE (x + offset_x, y + offset_y,
                                        width, height),
                        dest_buffer,
                        GEGL_RECTANGLE (0, 0, 0, 0));

      gimp_gegl_combine_mask (mask_buffer, mask_buffer_region,
                              dest_buffer, GEGL_RECTANGLE (0, 0, width, height),
                              1.0);

      gimp_gegl_replace (buffer,          buffer_region,
                         drawable_buffer, GEGL_RECTANGLE (x, y, width, height),
                         dest_buffer,     GEGL_RECTANGLE (0, 0, width, height),
                         drawable_buffer, GEGL_RECTANGLE (x, y, width, height),
                         opacity,
                         active_components);

      g_object_unref (dest_buffer);
    }
  else
    {
      gimp_gegl_replace (buffer,          buffer_region,
                         drawable_buffer, GEGL_RECTANGLE (x, y, width, height),
                         mask_buffer,     mask_buffer_region,
                         drawable_buffer, GEGL_RECTANGLE (x, y, width, height),
                         opacity,
                         active_components);
    }
}
예제 #21
0
void
gimp_drawable_bucket_fill (GimpDrawable         *drawable,
                           GimpFillOptions      *options,
                           gboolean              fill_transparent,
                           GimpSelectCriterion   fill_criterion,
                           gdouble               threshold,
                           gboolean              sample_merged,
                           gboolean              diagonal_neighbors,
                           gdouble               seed_x,
                           gdouble               seed_y)
{
    GimpImage    *image;
    GimpPickable *pickable;
    GeglBuffer   *buffer;
    GeglBuffer   *mask_buffer;
    gboolean      antialias;
    gint          x, y, width, height;
    gint          mask_offset_x = 0;
    gint          mask_offset_y = 0;
    gint          sel_x, sel_y, sel_width, sel_height;

    g_return_if_fail (GIMP_IS_DRAWABLE (drawable));
    g_return_if_fail (gimp_item_is_attached (GIMP_ITEM (drawable)));
    g_return_if_fail (GIMP_IS_FILL_OPTIONS (options));

    image = gimp_item_get_image (GIMP_ITEM (drawable));

    if (! gimp_item_mask_intersect (GIMP_ITEM (drawable),
                                    &sel_x, &sel_y, &sel_width, &sel_height))
        return;

    gimp_set_busy (image->gimp);

    if (sample_merged)
        pickable = GIMP_PICKABLE (image);
    else
        pickable = GIMP_PICKABLE (drawable);

    antialias = gimp_fill_options_get_antialias (options);

    /*  Do a seed bucket fill...To do this, calculate a new
     *  contiguous region.
     */
    mask_buffer = gimp_pickable_contiguous_region_by_seed (pickable,
                  antialias,
                  threshold,
                  fill_transparent,
                  fill_criterion,
                  diagonal_neighbors,
                  (gint) seed_x,
                  (gint) seed_y);

    gimp_gegl_mask_bounds (mask_buffer, &x, &y, &width, &height);
    width  -= x;
    height -= y;

    /*  If there is a selection, inersect the region bounds
     *  with the selection bounds, to avoid processing areas
     *  that are going to be masked out anyway.  The actual
     *  intersection of the fill region with the mask data
     *  happens when combining the fill buffer, in
     *  gimp_drawable_apply_buffer().
     */
    if (! gimp_channel_is_empty (gimp_image_get_mask (image)))
    {
        gint off_x = 0;
        gint off_y = 0;

        if (sample_merged)
            gimp_item_get_offset (GIMP_ITEM (drawable), &off_x, &off_y);

        if (! gimp_rectangle_intersect (x, y, width, height,

                                        sel_x + off_x, sel_y + off_y,
                                        sel_width,     sel_height,

                                        &x, &y, &width, &height))
        {
            /*  The fill region and the selection are disjoint; bail.  */

            g_object_unref (mask_buffer);

            gimp_unset_busy (image->gimp);

            return;
        }
    }

    /*  make sure we handle the mask correctly if it was sample-merged  */
    if (sample_merged)
    {
        GimpItem *item = GIMP_ITEM (drawable);
        gint      off_x, off_y;

        /*  Limit the channel bounds to the drawable's extents  */
        gimp_item_get_offset (item, &off_x, &off_y);

        gimp_rectangle_intersect (x, y, width, height,

                                  off_x, off_y,
                                  gimp_item_get_width (item),
                                  gimp_item_get_height (item),

                                  &x, &y, &width, &height);

        mask_offset_x = x;
        mask_offset_y = y;

        /*  translate mask bounds to drawable coords  */
        x -= off_x;
        y -= off_y;
    }
    else
    {
        mask_offset_x = x;
        mask_offset_y = y;
    }

    buffer = gimp_fill_options_create_buffer (options, drawable,
             GEGL_RECTANGLE (0, 0,
                             width, height));

    gimp_gegl_apply_opacity (buffer, NULL, NULL, buffer,
                             mask_buffer,
                             -mask_offset_x,
                             -mask_offset_y,
                             1.0);
    g_object_unref (mask_buffer);

    /*  Apply it to the image  */
    gimp_drawable_apply_buffer (drawable, buffer,
                                GEGL_RECTANGLE (0, 0, width, height),
                                TRUE, C_("undo-type", "Bucket Fill"),
                                gimp_context_get_opacity (GIMP_CONTEXT (options)),
                                gimp_context_get_paint_mode (GIMP_CONTEXT (options)),
                                NULL, x, y);

    g_object_unref (buffer);

    gimp_drawable_update (drawable, x, y, width, height);

    gimp_unset_busy (image->gimp);
}
예제 #22
0
파일: gimp-edit.c 프로젝트: LebedevRI/gimp
void
gimp_edit_get_paste_offset (GimpImage    *image,
                            GimpDrawable *drawable,
                            GimpObject   *paste,
                            gint          viewport_x,
                            gint          viewport_y,
                            gint          viewport_width,
                            gint          viewport_height,
                            gint         *offset_x,
                            gint         *offset_y)
{
  gint     image_width;
  gint     image_height;
  gint     width;
  gint     height;
  gboolean clamp_to_image = TRUE;

  g_return_if_fail (GIMP_IS_IMAGE (image));
  g_return_if_fail (drawable == NULL || GIMP_IS_DRAWABLE (drawable));
  g_return_if_fail (drawable == NULL ||
                    gimp_item_is_attached (GIMP_ITEM (drawable)));
  g_return_if_fail (GIMP_IS_VIEWABLE (paste));
  g_return_if_fail (offset_x != NULL);
  g_return_if_fail (offset_y != NULL);

  image_width  = gimp_image_get_width  (image);
  image_height = gimp_image_get_height (image);

  gimp_viewable_get_size (GIMP_VIEWABLE (paste), &width, &height);

  if (viewport_width  == image_width &&
      viewport_height == image_height)
    {
      /* if the whole image is visible, act as if there was no viewport */

      viewport_x      = 0;
      viewport_y      = 0;
      viewport_width  = 0;
      viewport_height = 0;
    }

  if (drawable)
    {
      /*  if pasting to a drawable  */

      GimpContainer *children;
      gint           off_x, off_y;
      gint           target_x, target_y;
      gint           target_width, target_height;
      gint           paste_x, paste_y;
      gint           paste_width, paste_height;
      gboolean       have_mask;

      have_mask = ! gimp_channel_is_empty (gimp_image_get_mask (image));

      gimp_item_get_offset (GIMP_ITEM (drawable), &off_x, &off_y);

      children = gimp_viewable_get_children (GIMP_VIEWABLE (drawable));

      if (children && gimp_container_get_n_children (children) == 0)
        {
          /* treat empty layer groups as image-sized, use the selection
           * as target
           */
          gimp_item_bounds (GIMP_ITEM (gimp_image_get_mask (image)),
                            &target_x, &target_y,
                            &target_width, &target_height);
        }
      else
        {
          gimp_item_mask_intersect (GIMP_ITEM (drawable),
                                    &target_x, &target_y,
                                    &target_width, &target_height);
        }

      if (! have_mask         &&    /* if we have no mask */
          viewport_width  > 0 &&    /* and we have a viewport */
          viewport_height > 0 &&
          (width  < target_width || /* and the paste is smaller than the target */
           height < target_height) &&

          /* and the viewport intersects with the target */
          gimp_rectangle_intersect (viewport_x, viewport_y,
                                    viewport_width, viewport_height,
                                    off_x, off_y, /* target_x,y are 0 */
                                    target_width, target_height,
                                    &paste_x, &paste_y,
                                    &paste_width, &paste_height))
        {
          /*  center on the viewport  */

          *offset_x = paste_x + (paste_width - width)  / 2;
          *offset_y = paste_y + (paste_height- height) / 2;
        }
      else
        {
          /*  otherwise center on the target  */

          *offset_x = off_x + target_x + (target_width  - width)  / 2;
          *offset_y = off_y + target_y + (target_height - height) / 2;

          /*  and keep it that way  */
          clamp_to_image = FALSE;
        }
    }
  else if (viewport_width  > 0 &&  /* if we have a viewport */
           viewport_height > 0 &&
           (width  < image_width || /* and the paste is       */
            height < image_height)) /* smaller than the image */
    {
      /*  center on the viewport  */

      *offset_x = viewport_x + (viewport_width  - width)  / 2;
      *offset_y = viewport_y + (viewport_height - height) / 2;
    }
  else
    {
      /*  otherwise center on the image  */

      *offset_x = (image_width  - width)  / 2;
      *offset_y = (image_height - height) / 2;

      /*  and keep it that way  */
      clamp_to_image = FALSE;
    }

  if (clamp_to_image)
    {
      /*  Ensure that the pasted layer is always within the image, if it
       *  fits and aligned at top left if it doesn't. (See bug #142944).
       */
      *offset_x = MIN (*offset_x, image_width  - width);
      *offset_y = MIN (*offset_y, image_height - height);
      *offset_x = MAX (*offset_x, 0);
      *offset_y = MAX (*offset_y, 0);
    }
}
예제 #23
0
GeglBuffer *
gimp_drawable_transform_buffer_rotate (GimpDrawable     *drawable,
                                       GimpContext      *context,
                                       GeglBuffer       *orig_buffer,
                                       gint              orig_offset_x,
                                       gint              orig_offset_y,
                                       GimpRotationType  rotate_type,
                                       gdouble           center_x,
                                       gdouble           center_y,
                                       gboolean          clip_result,
                                       gint             *new_offset_x,
                                       gint             *new_offset_y)
{
  GeglBuffer    *new_buffer;
  GeglRectangle  src_rect;
  GeglRectangle  dest_rect;
  gint           orig_x, orig_y;
  gint           orig_width, orig_height;
  gint           orig_bpp;
  gint           new_x, new_y;
  gint           new_width, new_height;

  g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), NULL);
  g_return_val_if_fail (gimp_item_is_attached (GIMP_ITEM (drawable)), NULL);
  g_return_val_if_fail (GIMP_IS_CONTEXT (context), NULL);
  g_return_val_if_fail (GEGL_IS_BUFFER (orig_buffer), NULL);

  orig_x      = orig_offset_x;
  orig_y      = orig_offset_y;
  orig_width  = gegl_buffer_get_width (orig_buffer);
  orig_height = gegl_buffer_get_height (orig_buffer);
  orig_bpp    = babl_format_get_bytes_per_pixel (gegl_buffer_get_format (orig_buffer));

  switch (rotate_type)
    {
    case GIMP_ROTATE_90:
      gimp_drawable_transform_rotate_point (orig_x,
                                            orig_y + orig_height,
                                            rotate_type, center_x, center_y,
                                            &new_x, &new_y);
      new_width  = orig_height;
      new_height = orig_width;
      break;

    case GIMP_ROTATE_180:
      gimp_drawable_transform_rotate_point (orig_x + orig_width,
                                            orig_y + orig_height,
                                            rotate_type, center_x, center_y,
                                            &new_x, &new_y);
      new_width  = orig_width;
      new_height = orig_height;
      break;

    case GIMP_ROTATE_270:
      gimp_drawable_transform_rotate_point (orig_x + orig_width,
                                            orig_y,
                                            rotate_type, center_x, center_y,
                                            &new_x, &new_y);
      new_width  = orig_height;
      new_height = orig_width;
      break;

    default:
      g_return_val_if_reached (NULL);
      break;
    }

  if (clip_result && (new_x != orig_x || new_y != orig_y ||
                      new_width != orig_width || new_height != orig_height))

    {
      GimpRGB    bg;
      GeglColor *color;
      gint       clip_x, clip_y;
      gint       clip_width, clip_height;

      new_buffer = gimp_gegl_buffer_new (GEGL_RECTANGLE (0, 0,
                                                         orig_width, orig_height),
                                         gegl_buffer_get_format (orig_buffer));

      *new_offset_x = orig_x;
      *new_offset_y = orig_y;

      /*  "Outside" a channel is transparency, not the bg color  */
      if (GIMP_IS_CHANNEL (drawable))
        gimp_rgba_set (&bg, 0.0, 0.0, 0.0, 0.0);
      else
        gimp_context_get_background (context, &bg);

      color = gimp_gegl_color_new (&bg);
      gegl_buffer_set_color (new_buffer, NULL, color);
      g_object_unref (color);

      if (gimp_rectangle_intersect (orig_x, orig_y, orig_width, orig_height,
                                    new_x, new_y, new_width, new_height,
                                    &clip_x, &clip_y,
                                    &clip_width, &clip_height))
        {
          gint saved_orig_x = orig_x;
          gint saved_orig_y = orig_y;

          new_x = clip_x - orig_x;
          new_y = clip_y - orig_y;

          switch (rotate_type)
            {
            case GIMP_ROTATE_90:
              gimp_drawable_transform_rotate_point (clip_x + clip_width,
                                                    clip_y,
                                                    GIMP_ROTATE_270,
                                                    center_x,
                                                    center_y,
                                                    &orig_x,
                                                    &orig_y);
              orig_x      -= saved_orig_x;
              orig_y      -= saved_orig_y;
              orig_width   = clip_height;
              orig_height  = clip_width;
              break;

            case GIMP_ROTATE_180:
              orig_x      = clip_x - orig_x;
              orig_y      = clip_y - orig_y;
              orig_width  = clip_width;
              orig_height = clip_height;
              break;

            case GIMP_ROTATE_270:
              gimp_drawable_transform_rotate_point (clip_x,
                                                    clip_y + clip_height,
                                                    GIMP_ROTATE_90,
                                                    center_x,
                                                    center_y,
                                                    &orig_x,
                                                    &orig_y);
              orig_x      -= saved_orig_x;
              orig_y      -= saved_orig_y;
              orig_width   = clip_height;
              orig_height  = clip_width;
              break;
            }

          new_width  = clip_width;
          new_height = clip_height;
        }
      else
        {
          new_width  = 0;
          new_height = 0;
        }
    }
  else
    {
      new_buffer = gimp_gegl_buffer_new (GEGL_RECTANGLE (0, 0,
                                                         new_width, new_height),
                                         gegl_buffer_get_format (orig_buffer));

      *new_offset_x = new_x;
      *new_offset_y = new_y;

      orig_x = 0;
      orig_y = 0;
      new_x  = 0;
      new_y  = 0;
    }

  if (new_width < 1 || new_height < 1)
    return new_buffer;

  src_rect.x      = orig_x;
  src_rect.y      = orig_y;
  src_rect.width  = orig_width;
  src_rect.height = orig_height;

  dest_rect.x      = new_x;
  dest_rect.y      = new_y;
  dest_rect.width  = new_width;
  dest_rect.height = new_height;

  switch (rotate_type)
    {
    case GIMP_ROTATE_90:
      {
        guchar *buf = g_new (guchar, new_height * orig_bpp);
        gint    i;

        g_assert (new_height == orig_width);

        src_rect.y      = orig_y + orig_height - 1;
        src_rect.height = 1;

        dest_rect.x     = new_x;
        dest_rect.width = 1;

        for (i = 0; i < orig_height; i++)
          {
            src_rect.y  = orig_y + orig_height - 1 - i;
            dest_rect.x = new_x + i;

            gegl_buffer_get (orig_buffer, &src_rect, 1.0, NULL, buf,
                             GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE);
            gegl_buffer_set (new_buffer, &dest_rect, 0, NULL, buf,
                             GEGL_AUTO_ROWSTRIDE);
          }

        g_free (buf);
      }
      break;

    case GIMP_ROTATE_180:
      {
        guchar *buf = g_new (guchar, new_width * orig_bpp);
        gint    i, j, k;

        g_assert (new_width == orig_width);

        src_rect.y      = orig_y + orig_height - 1;
        src_rect.height = 1;

        dest_rect.y      = new_y;
        dest_rect.height = 1;

        for (i = 0; i < orig_height; i++)
          {
            src_rect.y  = orig_y + orig_height - 1 - i;
            dest_rect.y = new_y + i;

            gegl_buffer_get (orig_buffer, &src_rect, 1.0, NULL, buf,
                             GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE);

            for (j = 0; j < orig_width / 2; j++)
              {
                guchar *left  = buf + j * orig_bpp;
                guchar *right = buf + (orig_width - 1 - j) * orig_bpp;

                for (k = 0; k < orig_bpp; k++)
                  {
                    guchar tmp = left[k];
                    left[k]    = right[k];
                    right[k]   = tmp;
                  }
              }

            gegl_buffer_set (new_buffer, &dest_rect, 0, NULL, buf,
                             GEGL_AUTO_ROWSTRIDE);
          }

        g_free (buf);
      }
      break;

    case GIMP_ROTATE_270:
      {
        guchar *buf = g_new (guchar, new_width * orig_bpp);
        gint    i;

        g_assert (new_width == orig_height);

        src_rect.x     = orig_x + orig_width - 1;
        src_rect.width = 1;

        dest_rect.y      = new_y;
        dest_rect.height = 1;

        for (i = 0; i < orig_width; i++)
          {
            src_rect.x  = orig_x + orig_width - 1 - i;
            dest_rect.y = new_y + i;

            gegl_buffer_get (orig_buffer, &src_rect, 1.0, NULL, buf,
                             GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE);
            gegl_buffer_set (new_buffer, &dest_rect, 0, NULL, buf,
                             GEGL_AUTO_ROWSTRIDE);
          }

        g_free (buf);
      }
      break;
    }

  return new_buffer;
}
예제 #24
0
GimpLayer *
gimp_edit_paste (GimpImage    *image,
                 GimpDrawable *drawable,
                 GimpBuffer   *paste,
                 gboolean      paste_into,
                 gint          viewport_x,
                 gint          viewport_y,
                 gint          viewport_width,
                 gint          viewport_height)
{
  GimpLayer  *layer;
  const Babl *format;
  gint        image_width;
  gint        image_height;
  gint        width;
  gint        height;
  gint        offset_x;
  gint        offset_y;
  gboolean    clamp_to_image = TRUE;

  g_return_val_if_fail (GIMP_IS_IMAGE (image), NULL);
  g_return_val_if_fail (drawable == NULL || GIMP_IS_DRAWABLE (drawable), NULL);
  g_return_val_if_fail (drawable == NULL ||
                        gimp_item_is_attached (GIMP_ITEM (drawable)), NULL);
  g_return_val_if_fail (GIMP_IS_BUFFER (paste), NULL);

  /*  Make a new layer: if drawable == NULL,
   *  user is pasting into an empty image.
   */

  if (drawable)
    format = gimp_drawable_get_format_with_alpha (drawable);
  else
    format = gimp_image_get_layer_format (image, TRUE);

  layer = gimp_layer_new_from_buffer (paste, image,
                                      format,
                                      _("Pasted Layer"),
                                      GIMP_OPACITY_OPAQUE, GIMP_NORMAL_MODE);

  if (! layer)
    return NULL;

  image_width  = gimp_image_get_width  (image);
  image_height = gimp_image_get_height (image);

  width  = gimp_item_get_width  (GIMP_ITEM (layer));
  height = gimp_item_get_height (GIMP_ITEM (layer));

  if (viewport_width  == image_width &&
      viewport_height == image_height)
    {
      /* if the whole image is visible, act as if there was no viewport */

      viewport_x      = 0;
      viewport_y      = 0;
      viewport_width  = 0;
      viewport_height = 0;
    }

  if (drawable)
    {
      /*  if pasting to a drawable  */

      gint     off_x, off_y;
      gint     x1, y1, x2, y2;
      gint     paste_x, paste_y;
      gint     paste_width, paste_height;
      gboolean have_mask;

      gimp_item_get_offset (GIMP_ITEM (drawable), &off_x, &off_y);
      have_mask = gimp_item_mask_bounds (GIMP_ITEM (drawable),
                                         &x1, &y1, &x2, &y2);

      if (! have_mask         && /* if we have no mask */
          viewport_width  > 0 && /* and we have a viewport */
          viewport_height > 0 &&
          (width  < (x2 - x1) || /* and the paste is smaller than the target */
           height < (y2 - y1)) &&

          /* and the viewport intersects with the target */
          gimp_rectangle_intersect (viewport_x, viewport_y,
                                    viewport_width, viewport_height,
                                    off_x, off_y,
                                    x2 - x1, y2 - y1,
                                    &paste_x, &paste_y,
                                    &paste_width, &paste_height))
        {
          /*  center on the viewport  */

          offset_x = paste_x + (paste_width - width)  / 2;
          offset_y = paste_y + (paste_height- height) / 2;
        }
      else
        {
          /*  otherwise center on the target  */

          offset_x = off_x + ((x1 + x2) - width)  / 2;
          offset_y = off_y + ((y1 + y2) - height) / 2;

          /*  and keep it that way  */
          clamp_to_image = FALSE;
        }
    }
  else if (viewport_width  > 0 &&  /* if we have a viewport */
           viewport_height > 0 &&
           (width  < image_width || /* and the paste is       */
            height < image_height)) /* smaller than the image */
    {
      /*  center on the viewport  */

      offset_x = viewport_x + (viewport_width  - width)  / 2;
      offset_y = viewport_y + (viewport_height - height) / 2;
    }
  else
    {
      /*  otherwise center on the image  */

      offset_x = (image_width  - width)  / 2;
      offset_y = (image_height - height) / 2;

      /*  and keep it that way  */
      clamp_to_image = FALSE;
    }

  if (clamp_to_image)
    {
      /*  Ensure that the pasted layer is always within the image, if it
       *  fits and aligned at top left if it doesn't. (See bug #142944).
       */
      offset_x = MIN (offset_x, image_width  - width);
      offset_y = MIN (offset_y, image_height - height);
      offset_x = MAX (offset_x, 0);
      offset_y = MAX (offset_y, 0);
    }

  gimp_item_set_offset (GIMP_ITEM (layer), offset_x, offset_y);

  /*  Start a group undo  */
  gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_EDIT_PASTE,
                               C_("undo-type", "Paste"));

  /*  If there is a selection mask clear it--
   *  this might not always be desired, but in general,
   *  it seems like the correct behavior.
   */
  if (! gimp_channel_is_empty (gimp_image_get_mask (image)) && ! paste_into)
    gimp_channel_clear (gimp_image_get_mask (image), NULL, TRUE);

  /*  if there's a drawable, add a new floating selection  */
  if (drawable)
    floating_sel_attach (layer, drawable);
  else
    gimp_image_add_layer (image, layer, NULL, 0, TRUE);

  /*  end the group undo  */
  gimp_image_undo_group_end (image);

  return layer;
}
예제 #25
0
/* --------------------------------------------
 * p_attempt_locate_at_current_offset
 * --------------------------------------------
 */
static void
p_attempt_locate_at_current_offset(Context *context, gint32 px, gint32 py)
{
  GimpPixelRgn refPR;
  GimpPixelRgn targetPR;
  gpointer  pr;
  gint      rx1, ry1, rWidth, rHeight;
  gint      tx1, ty1, tWidth, tHeight;
  gint      commonAreaWidth, commonAreaHeight;
  gint      fullShapeWidth,  fullShapeHeight;
  gint      rWidthRequired, rHeightRequired;
  gboolean  isIntersect;

  gint    leftShapeRadius;
  gint    upperShapeRadius;


  if (context->isFinishedFlag)
  {
    return;
  }
  
  fullShapeWidth = (2 * context->refShapeRadius);
  fullShapeHeight = (2 * context->refShapeRadius);

  /* calculate processing relevant intersecting reference / target rectangles */  

  isIntersect =
   gimp_rectangle_intersect((context->refX - context->refShapeRadius)  /* origin1 */
                          , (context->refY - context->refShapeRadius)
                          , fullShapeWidth               /*  width1 */
                          , fullShapeHeight              /* height1 */
                          ,0
                          ,0
                          ,context->refDrawable->width
                          ,context->refDrawable->height
                          ,&rx1
                          ,&ry1
                          ,&rWidth
                          ,&rHeight
                          );
  if (!isIntersect)
  {
    return;
  }
  
  leftShapeRadius = context->refX - rx1;
  upperShapeRadius = context->refY - ry1;

  isIntersect =
   gimp_rectangle_intersect((px - leftShapeRadius)  /* origin1 */
                          , (py - upperShapeRadius)
                          , rWidth               /*  width1 */
                          , rHeight               /* height1 */
                          ,0
                          ,0
                          ,context->targetDrawable->width
                          ,context->targetDrawable->height
                          ,&tx1
                          ,&ty1
                          ,&tWidth
                          ,&tHeight
                          );
  if (!isIntersect)
  {
    return;
  }
  
  commonAreaWidth = tWidth;
  commonAreaHeight = tHeight;

  // TODO test if 2/3 of the fullShapeWidth and fullShapeHeight is sufficient for usable results.
  // alternative1: maybe require  rWidth and rHeight
  // alternative2: maybe require  fullShapeWidth and fullShapeHeight
  rWidthRequired = (fullShapeWidth * 2) / 3;
  rHeightRequired = (fullShapeHeight * 2) / 3;
  
  if ((commonAreaWidth < rWidthRequired) 
  ||  (commonAreaHeight < rHeightRequired))
  {
    /* the common area is significant smaller than the reference shape 
     * skip the compare attempt in this case to avoid unpredictable results (near borders)
     */
    return;
  }

  

//   if(gap_debug)
//   {
//     printf("p_attempt_locate_at: px: %04d py:%04d\n"
//            "                     rx1:%04d ry1:%04d rWidth:%d rHeight:%d\n"
//            "                     tx1:%04d ty1:%04d tWidth:%d tHeight:%d\n"
//            "                     commonAreaWidth:%d commonAreaHeight:%d\n"
//       ,(int)px
//       ,(int)py
//       ,(int)rx1
//       ,(int)ry1
//       ,(int)rWidth
//       ,(int)rHeight
//       ,(int)tx1
//       ,(int)ty1
//       ,(int)tWidth
//       ,(int)tHeight
//       ,(int)commonAreaWidth
//       ,(int)commonAreaHeight
//       );
//   }

  /* rest 'per offset' values in the context */
  context->cancelAttemptFlag = FALSE;
  context->sumDiffValue = 0;
  context->involvedPixelCount = 0;
  context->currentDistance = p_calculate_distance_to_ref_coord(context, px, py);
  context->px = px;
  context->py = py;

  gimp_pixel_rgn_init (&refPR, context->refDrawable, rx1, ry1
                      , commonAreaWidth, commonAreaHeight
                      , FALSE     /* dirty */
                      , FALSE     /* shadow */
                       );

  gimp_pixel_rgn_init (&targetPR, context->targetDrawable, tx1, ty1
                      , commonAreaWidth, commonAreaHeight
                      , FALSE     /* dirty */
                      , FALSE     /* shadow */
                       );

  /* compare pixel areas in tiled portions via pixel region processing loops.
   */
  for (pr = gimp_pixel_rgns_register (2, &refPR, &targetPR);
       pr != NULL;
       pr = gimp_pixel_rgns_process (pr))
  {
    if (context->cancelAttemptFlag)
    {
      break;
    }
    else
    {
      p_compare_regions(&refPR, &targetPR, context);
    }
  }

  if (pr != NULL)
  {
     /* NOTE:
      * early escaping from the loop with pr != NULL
      * leads to memory leaks due to unbalanced tile ref/unref calls.
      * the call to gap_gimp_pixel_rgns_unref cals unref on the current tile
      * (in the same way as gimp_pixel_rgns_process does)
      * but does not ref another available tile.
      */
    gap_gimp_pixel_rgns_unref (pr);
  
  }
  

  
  if ((context->involvedPixelCount >= context->requiredPixelCount)
  &&  (context->sumDiffValue <= context->bestMatchingSumDiffValue))
  {
    if((context->sumDiffValue < context->bestMatchingSumDiffValue)
    || ( context->currentDistance < context->bestMatchingDistance))
    {
      context->bestMatchingSumDiffValue = context->sumDiffValue;
      context->bestMatchingDistance = context->currentDistance;
      context->bestMatchingPixelCount = context->involvedPixelCount;
      context->bestX = px;
      context->bestY = py;
 
      if(gap_debug)
      {
        gdouble bestMatchingAvgColordiff;
        
        bestMatchingAvgColordiff = p_calculate_average_colordiff(context->bestMatchingSumDiffValue
                                    , context->bestMatchingPixelCount
                                    );
        printf("FOUND: bestX:%d bestY:%d squareDist:%d\n"
               "             sumDiffValues:%d pixelCount:%d bestMatchingAvgColordiff:%.5f\n"
          , (int)context->bestX
          , (int)context->bestY
          , (int)context->bestMatchingDistance
          , (int)context->bestMatchingSumDiffValue
          , (int)context->bestMatchingPixelCount
          , (float)bestMatchingAvgColordiff
          );
      }
       
      if ((context->currentDistance <= context->veryNearDistance)
      &&  (context->sumDiffValue == 0))
      {
        /* stop all further attempts on exact matching area when near reference origin */
        context->isFinishedFlag = TRUE;
      }
    }
  }

  
}  /* end p_attempt_locate_at_current_offset */
예제 #26
0
static GeglBuffer *
gimp_perspective_clone_get_source (GimpSourceCore   *source_core,
                                   GimpDrawable     *drawable,
                                   GimpPaintOptions *paint_options,
                                   GimpPickable     *src_pickable,
                                   gint              src_offset_x,
                                   gint              src_offset_y,
                                   GeglBuffer       *paint_buffer,
                                   gint              paint_buffer_x,
                                   gint              paint_buffer_y,
                                   gint             *paint_area_offset_x,
                                   gint             *paint_area_offset_y,
                                   gint             *paint_area_width,
                                   gint             *paint_area_height,
                                   GeglRectangle    *src_rect)
{
  GimpPerspectiveClone *clone         = GIMP_PERSPECTIVE_CLONE (source_core);
  GimpCloneOptions     *clone_options = GIMP_CLONE_OPTIONS (paint_options);
  GeglBuffer           *src_buffer;
  GeglBuffer           *dest_buffer;
  const Babl           *src_format_alpha;
  gint                  x1d, y1d, x2d, y2d;
  gdouble               x1s, y1s, x2s, y2s, x3s, y3s, x4s, y4s;
  gint                  xmin, ymin, xmax, ymax;
  GimpMatrix3           matrix;
  GimpMatrix3           gegl_matrix;

  src_buffer       = gimp_pickable_get_buffer (src_pickable);
  src_format_alpha = gimp_pickable_get_format_with_alpha (src_pickable);

  /* Destination coordinates that will be painted */
  x1d = paint_buffer_x;
  y1d = paint_buffer_y;
  x2d = paint_buffer_x + gegl_buffer_get_width  (paint_buffer);
  y2d = paint_buffer_y + gegl_buffer_get_height (paint_buffer);

  /* Boundary box for source pixels to copy: Convert all the vertex of
   * the box to paint in destination area to its correspondent in
   * source area bearing in mind perspective
   */
  gimp_perspective_clone_get_source_point (clone, x1d, y1d, &x1s, &y1s);
  gimp_perspective_clone_get_source_point (clone, x1d, y2d, &x2s, &y2s);
  gimp_perspective_clone_get_source_point (clone, x2d, y1d, &x3s, &y3s);
  gimp_perspective_clone_get_source_point (clone, x2d, y2d, &x4s, &y4s);

  xmin = floor (MIN4 (x1s, x2s, x3s, x4s));
  ymin = floor (MIN4 (y1s, y2s, y3s, y4s));
  xmax = ceil  (MAX4 (x1s, x2s, x3s, x4s));
  ymax = ceil  (MAX4 (y1s, y2s, y3s, y4s));

  switch (clone_options->clone_type)
    {
    case GIMP_IMAGE_CLONE:
      if (! gimp_rectangle_intersect (xmin, ymin,
                                      xmax - xmin, ymax - ymin,
                                      0, 0,
                                      gegl_buffer_get_width  (src_buffer),
                                      gegl_buffer_get_height (src_buffer),
                                      NULL, NULL, NULL, NULL))
        {
          /* if the source area is completely out of the image */
          return NULL;
        }
      break;

    case GIMP_PATTERN_CLONE:
      gegl_node_set (clone->crop,
                     "x",      (gdouble) xmin,
                     "y",      (gdouble) ymin,
                     "width",  (gdouble) xmax - xmin,
                     "height", (gdouble) ymax - ymin,
                     NULL);
      break;
    }

  dest_buffer = gegl_buffer_new (GEGL_RECTANGLE (0, 0, x2d - x1d, y2d - y1d),
                                 src_format_alpha);

  gimp_perspective_clone_get_matrix (clone, &matrix);

  gimp_matrix3_identity (&gegl_matrix);
  gimp_matrix3_mult (&matrix, &gegl_matrix);
  gimp_matrix3_translate (&gegl_matrix, -x1d, -y1d);

  gimp_gegl_node_set_matrix (clone->transform_node, &gegl_matrix);

  gegl_node_set (clone->dest_node,
                 "buffer", dest_buffer,
                 NULL);

  gegl_node_blit (clone->dest_node, 1.0,
                  GEGL_RECTANGLE (0, 0, x2d - x1d, y2d - y1d),
                  NULL, NULL, 0, GEGL_BLIT_DEFAULT);

  *src_rect = *GEGL_RECTANGLE (0, 0, x2d - x1d, y2d - y1d);

  return dest_buffer;
}
예제 #27
0
static GeglBuffer *
gimp_source_core_real_get_source (GimpSourceCore   *source_core,
                                  GimpDrawable     *drawable,
                                  GimpPaintOptions *paint_options,
                                  GimpPickable     *src_pickable,
                                  gint              src_offset_x,
                                  gint              src_offset_y,
                                  GeglBuffer       *paint_buffer,
                                  gint              paint_buffer_x,
                                  gint              paint_buffer_y,
                                  gint             *paint_area_offset_x,
                                  gint             *paint_area_offset_y,
                                  gint             *paint_area_width,
                                  gint             *paint_area_height,
                                  GeglRectangle    *src_rect)
{
  GimpSourceOptions *options    = GIMP_SOURCE_OPTIONS (paint_options);
  GimpImage         *image      = gimp_item_get_image (GIMP_ITEM (drawable));
  GimpImage         *src_image  = gimp_pickable_get_image (src_pickable);
  GeglBuffer        *src_buffer = gimp_pickable_get_buffer (src_pickable);
  GeglBuffer        *dest_buffer;
  gint               x, y;
  gint               width, height;

  if (! gimp_rectangle_intersect (paint_buffer_x + src_offset_x,
                                  paint_buffer_y + src_offset_y,
                                  gegl_buffer_get_width  (paint_buffer),
                                  gegl_buffer_get_height (paint_buffer),
                                  0, 0,
                                  gegl_buffer_get_width  (src_buffer),
                                  gegl_buffer_get_height (src_buffer),
                                  &x, &y,
                                  &width, &height))
    {
      return FALSE;
    }

  /*  If the source image is different from the destination,
   *  then we should copy straight from the source image
   *  to the canvas.
   *  Otherwise, we need a call to get_orig_image to make sure
   *  we get a copy of the unblemished (offset) image
   */
  if ((  options->sample_merged && (src_image                 != image)) ||
      (! options->sample_merged && (source_core->src_drawable != drawable)))
    {
      dest_buffer = src_buffer;
    }
  else
    {
      /*  get the original image  */
      if (options->sample_merged)
        dest_buffer = gimp_paint_core_get_orig_proj (GIMP_PAINT_CORE (source_core));
      else
        dest_buffer = gimp_paint_core_get_orig_image (GIMP_PAINT_CORE (source_core));
    }

  *paint_area_offset_x = x - (paint_buffer_x + src_offset_x);
  *paint_area_offset_y = y - (paint_buffer_y + src_offset_y);
  *paint_area_width    = width;
  *paint_area_height   = height;

  *src_rect = *GEGL_RECTANGLE (x, y, width, height);

  return g_object_ref (dest_buffer);
}
예제 #28
0
/**
 * gimp_drawable_get_bucket_fill_buffer:
 * @drawable: the #GimpDrawable to edit.
 * @options:
 * @fill_transparent:
 * @fill_criterion:
 * @threshold:
 * @sample_merged:
 * @diagonal_neighbors:
 * @seed_x: X coordinate to start the fill.
 * @seed_y: Y coordinate to start the fill.
 * @mask_buffer: mask of the fill in-progress when in an interactive
 *               filling process. Set to NULL if you need a one-time
 *               fill.
 * @mask_x: returned x bound of @mask_buffer.
 * @mask_y: returned x bound of @mask_buffer.
 * @mask_width: returned width bound of @mask_buffer.
 * @mask_height: returned height bound of @mask_buffer.
 *
 * Creates the fill buffer for a bucket fill operation on @drawable,
 * without actually applying it (if you want to apply it directly as a
 * one-time operation, use gimp_drawable_bucket_fill() instead). If
 * @mask_buffer is not NULL, the intermediate fill mask will also be
 * returned. This fill mask can later be reused in successive calls to
 * gimp_drawable_get_bucket_fill_buffer() for interactive filling.
 *
 * Returns: a fill buffer which can be directly applied to @drawable, or
 *          used in a drawable filter as preview.
 */
GeglBuffer *
gimp_drawable_get_bucket_fill_buffer (GimpDrawable         *drawable,
                                      GimpFillOptions      *options,
                                      gboolean              fill_transparent,
                                      GimpSelectCriterion   fill_criterion,
                                      gdouble               threshold,
                                      gboolean              sample_merged,
                                      gboolean              diagonal_neighbors,
                                      gdouble               seed_x,
                                      gdouble               seed_y,
                                      GeglBuffer          **mask_buffer,
                                      gdouble              *mask_x,
                                      gdouble              *mask_y,
                                      gint                 *mask_width,
                                      gint                 *mask_height)
{
  GimpImage    *image;
  GimpPickable *pickable;
  GeglBuffer   *buffer;
  GeglBuffer   *new_mask;
  gboolean      antialias;
  gint          x, y, width, height;
  gint          mask_offset_x = 0;
  gint          mask_offset_y = 0;
  gint          sel_x, sel_y, sel_width, sel_height;

  g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), NULL);
  g_return_val_if_fail (gimp_item_is_attached (GIMP_ITEM (drawable)), NULL);
  g_return_val_if_fail (GIMP_IS_FILL_OPTIONS (options), NULL);

  image = gimp_item_get_image (GIMP_ITEM (drawable));

  if (! gimp_item_mask_intersect (GIMP_ITEM (drawable),
                                  &sel_x, &sel_y, &sel_width, &sel_height))
    return NULL;

  if (mask_buffer && *mask_buffer && threshold == 0.0)
    {
      gfloat pixel;

      gegl_buffer_sample (*mask_buffer, seed_x, seed_y, NULL, &pixel,
                          babl_format ("Y float"),
                          GEGL_SAMPLER_NEAREST, GEGL_ABYSS_NONE);

      if (pixel != 0.0)
        /* Already selected. This seed won't change the selection. */
        return NULL;
    }

  gimp_set_busy (image->gimp);
  if (sample_merged)
    pickable = GIMP_PICKABLE (image);
  else
    pickable = GIMP_PICKABLE (drawable);

  antialias = gimp_fill_options_get_antialias (options);

  /*  Do a seed bucket fill...To do this, calculate a new
   *  contiguous region.
   */
  new_mask = gimp_pickable_contiguous_region_by_seed (pickable,
                                                      antialias,
                                                      threshold,
                                                      fill_transparent,
                                                      fill_criterion,
                                                      diagonal_neighbors,
                                                      (gint) seed_x,
                                                      (gint) seed_y);
  if (mask_buffer && *mask_buffer)
    {
      gimp_gegl_mask_combine_buffer (new_mask, *mask_buffer,
                                     GIMP_CHANNEL_OP_ADD, 0, 0);
      g_object_unref (*mask_buffer);
    }
  if (mask_buffer)
    *mask_buffer = new_mask;

  gimp_gegl_mask_bounds (new_mask, &x, &y, &width, &height);
  width  -= x;
  height -= y;

  /*  If there is a selection, intersect the region bounds
   *  with the selection bounds, to avoid processing areas
   *  that are going to be masked out anyway.  The actual
   *  intersection of the fill region with the mask data
   *  happens when combining the fill buffer, in
   *  gimp_drawable_apply_buffer().
   */
  if (! gimp_channel_is_empty (gimp_image_get_mask (image)))
    {
      gint off_x = 0;
      gint off_y = 0;

      if (sample_merged)
        gimp_item_get_offset (GIMP_ITEM (drawable), &off_x, &off_y);

      if (! gimp_rectangle_intersect (x, y, width, height,

                                      sel_x + off_x, sel_y + off_y,
                                      sel_width,     sel_height,

                                      &x, &y, &width, &height))
        {
          if (! mask_buffer)
            g_object_unref (new_mask);
          /*  The fill region and the selection are disjoint; bail.  */
          gimp_unset_busy (image->gimp);

          return NULL;
        }
    }

  /*  make sure we handle the mask correctly if it was sample-merged  */
  if (sample_merged)
    {
      GimpItem *item = GIMP_ITEM (drawable);
      gint      off_x, off_y;

      /*  Limit the channel bounds to the drawable's extents  */
      gimp_item_get_offset (item, &off_x, &off_y);

      gimp_rectangle_intersect (x, y, width, height,

                                off_x, off_y,
                                gimp_item_get_width (item),
                                gimp_item_get_height (item),

                                &x, &y, &width, &height);

      mask_offset_x = x;
      mask_offset_y = y;

     /*  translate mask bounds to drawable coords  */
      x -= off_x;
      y -= off_y;
    }
  else
    {
      mask_offset_x = x;
      mask_offset_y = y;
    }

  buffer = gimp_fill_options_create_buffer (options, drawable,
                                            GEGL_RECTANGLE (0, 0,
                                                            width, height),
                                            -x, -y);

  gimp_gegl_apply_opacity (buffer, NULL, NULL, buffer, new_mask,
                           -mask_offset_x, -mask_offset_y, 1.0);

  if (mask_x)
    *mask_x = x;
  if (mask_y)
    *mask_y = y;
  if (mask_width)
    *mask_width = width;
  if (mask_height)
    *mask_height = height;

  if (! mask_buffer)
    g_object_unref (new_mask);

  gimp_unset_busy (image->gimp);

  return buffer;
}
예제 #29
0
GeglBuffer *
gimp_drawable_transform_buffer_flip (GimpDrawable         *drawable,
                                     GimpContext          *context,
                                     GeglBuffer           *orig_buffer,
                                     gint                  orig_offset_x,
                                     gint                  orig_offset_y,
                                     GimpOrientationType   flip_type,
                                     gdouble               axis,
                                     gboolean              clip_result,
                                     GimpColorProfile    **buffer_profile,
                                     gint                 *new_offset_x,
                                     gint                 *new_offset_y)
{
  const Babl         *format;
  GeglBuffer         *new_buffer;
  GeglBufferIterator *iter;
  GeglRectangle       src_rect;
  GeglRectangle       dest_rect;
  gint                bpp;
  gint                orig_x, orig_y;
  gint                orig_width, orig_height;
  gint                new_x, new_y;
  gint                new_width, new_height;
  gint                x, y;

  g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), NULL);
  g_return_val_if_fail (gimp_item_is_attached (GIMP_ITEM (drawable)), NULL);
  g_return_val_if_fail (GIMP_IS_CONTEXT (context), NULL);
  g_return_val_if_fail (GEGL_IS_BUFFER (orig_buffer), NULL);
  g_return_val_if_fail (buffer_profile != NULL, NULL);
  g_return_val_if_fail (new_offset_x != NULL, NULL);
  g_return_val_if_fail (new_offset_y != NULL, NULL);

  *buffer_profile =
    gimp_color_managed_get_color_profile (GIMP_COLOR_MANAGED (drawable));

  orig_x      = orig_offset_x;
  orig_y      = orig_offset_y;
  orig_width  = gegl_buffer_get_width (orig_buffer);
  orig_height = gegl_buffer_get_height (orig_buffer);

  new_x      = orig_x;
  new_y      = orig_y;
  new_width  = orig_width;
  new_height = orig_height;

  switch (flip_type)
    {
    case GIMP_ORIENTATION_HORIZONTAL:
      new_x = RINT (-((gdouble) orig_x +
                      (gdouble) orig_width - axis) + axis);
      break;

    case GIMP_ORIENTATION_VERTICAL:
      new_y = RINT (-((gdouble) orig_y +
                      (gdouble) orig_height - axis) + axis);
      break;

    case GIMP_ORIENTATION_UNKNOWN:
      g_return_val_if_reached (NULL);
      break;
    }

  format = gegl_buffer_get_format (orig_buffer);
  bpp    = babl_format_get_bytes_per_pixel (format);

  new_buffer = gegl_buffer_new (GEGL_RECTANGLE (0, 0,
                                                new_width, new_height),
                                format);

  if (clip_result && (new_x != orig_x || new_y != orig_y))
    {
      GimpRGB    bg;
      GeglColor *color;
      gint       clip_x, clip_y;
      gint       clip_width, clip_height;

      *new_offset_x = orig_x;
      *new_offset_y = orig_y;

      /*  Use transparency, rather than the bg color, as the "outside" color of
       *  channels, and drawables with an alpha channel.
       */
      if (GIMP_IS_CHANNEL (drawable) || babl_format_has_alpha (format))
        {
          gimp_rgba_set (&bg, 0.0, 0.0, 0.0, 0.0);
        }
      else
        {
          gimp_context_get_background (context, &bg);
          gimp_pickable_srgb_to_image_color (GIMP_PICKABLE (drawable),
                                             &bg, &bg);
        }

      color = gimp_gegl_color_new (&bg, gimp_drawable_get_space (drawable));
      gegl_buffer_set_color (new_buffer, NULL, color);
      g_object_unref (color);

      if (gimp_rectangle_intersect (orig_x, orig_y, orig_width, orig_height,
                                    new_x, new_y, new_width, new_height,
                                    &clip_x, &clip_y,
                                    &clip_width, &clip_height))
        {
          orig_x = new_x = clip_x - orig_x;
          orig_y = new_y = clip_y - orig_y;
        }

      orig_width  = new_width  = clip_width;
      orig_height = new_height = clip_height;
    }
  else
    {
      *new_offset_x = new_x;
      *new_offset_y = new_y;

      orig_x = 0;
      orig_y = 0;
      new_x  = 0;
      new_y  = 0;
    }

  if (new_width == 0 && new_height == 0)
    return new_buffer;

  dest_rect.x      = new_x;
  dest_rect.y      = new_y;
  dest_rect.width  = new_width;
  dest_rect.height = new_height;

  iter = gegl_buffer_iterator_new (new_buffer, &dest_rect, 0, NULL,
                                   GEGL_BUFFER_WRITE, GEGL_ABYSS_NONE, 1);

  switch (flip_type)
    {
    case GIMP_ORIENTATION_HORIZONTAL:
      while (gegl_buffer_iterator_next (iter))
        {
          gint stride = iter->items[0].roi.width * bpp;

          src_rect = iter->items[0].roi;

          src_rect.x = (orig_x + orig_width)          -
                       (iter->items[0].roi.x - dest_rect.x) -
                       iter->items[0].roi.width;

          gegl_buffer_get (orig_buffer, &src_rect, 1.0, NULL, iter->items[0].data,
                           stride, GEGL_ABYSS_NONE);

          for (y = 0; y < iter->items[0].roi.height; y++)
            {
              guint8 *left  = iter->items[0].data;
              guint8 *right = iter->items[0].data;

              left  += y * stride;
              right += y * stride + (iter->items[0].roi.width - 1) * bpp;

              for (x = 0; x < iter->items[0].roi.width / 2; x++)
                {
                  guint8 temp[bpp];

                  memcpy (temp,  left,  bpp);
                  memcpy (left,  right, bpp);
                  memcpy (right, temp,  bpp);

                  left  += bpp;
                  right -= bpp;
                }
            }
        }
      break;

    case GIMP_ORIENTATION_VERTICAL:
      while (gegl_buffer_iterator_next (iter))
        {
          gint stride = iter->items[0].roi.width * bpp;

          src_rect = iter->items[0].roi;

          src_rect.y = (orig_y + orig_height)         -
                       (iter->items[0].roi.y - dest_rect.y) -
                       iter->items[0].roi.height;

          gegl_buffer_get (orig_buffer, &src_rect, 1.0, NULL, iter->items[0].data,
                           stride, GEGL_ABYSS_NONE);

          for (x = 0; x < iter->items[0].roi.width; x++)
            {
              guint8 *top    = iter->items[0].data;
              guint8 *bottom = iter->items[0].data;

              top    += x * bpp;
              bottom += x * bpp + (iter->items[0].roi.height - 1) * stride;

              for (y = 0; y < iter->items[0].roi.height / 2; y++)
                {
                  guint8 temp[bpp];

                  memcpy (temp,   top,    bpp);
                  memcpy (top,    bottom, bpp);
                  memcpy (bottom, temp,   bpp);

                  top    += stride;
                  bottom -= stride;
                }
            }
        }
      break;

    case GIMP_ORIENTATION_UNKNOWN:
      gegl_buffer_iterator_stop (iter);
      break;
    }

  return new_buffer;
}
예제 #30
0
/**
 * gimp_scan_convert_render_full:
 * @sc:        a #GimpScanConvert context
 * @buffer:    the #GeglBuffer to render to
 * @off_x:     horizontal offset into the @buffer
 * @off_y:     vertical offset into the @buffer
 * @replace:   if true the original content of the @buffer gets estroyed
 * @antialias: if true the rendering happens antialiased
 * @value:     value to use for covered pixels
 *
 * This function renders the area described by the path to the
 * @buffer, taking the offset @off_x and @off_y in the buffer into
 * account.  The rendering can happen antialiased and be rendered on
 * top of existing content or replacing it completely. The @value
 * specifies the opacity value to be used for the objects in the @sc.
 *
 * You cannot add additional polygons after this command.
 */
void
gimp_scan_convert_render_full (GimpScanConvert *sc,
                               GeglBuffer      *buffer,
                               gint             off_x,
                               gint             off_y,
                               gboolean         replace,
                               gboolean         antialias,
                               gdouble          value)
{
  const Babl         *format;
  GeglBufferIterator *iter;
  GeglRectangle      *roi;
  cairo_t            *cr;
  cairo_surface_t    *surface;
  cairo_path_t        path;
  gint                bpp;
  gint                x, y;
  gint                width, height;

  g_return_if_fail (sc != NULL);
  g_return_if_fail (GEGL_IS_BUFFER (buffer));

  x      = 0;
  y      = 0;
  width  = gegl_buffer_get_width  (buffer);
  height = gegl_buffer_get_height (buffer);

  if (sc->clip && ! gimp_rectangle_intersect (x, y, width, height,
                                              sc->clip_x, sc->clip_y,
                                              sc->clip_w, sc->clip_h,
                                              &x, &y, &width, &height))
    return;

  path.status   = CAIRO_STATUS_SUCCESS;
  path.data     = (cairo_path_data_t *) sc->path_data->data;
  path.num_data = sc->path_data->len;

  format = babl_format ("Y u8");
  bpp    = babl_format_get_bytes_per_pixel (format);

  iter = gegl_buffer_iterator_new (buffer, NULL, 0, format,
                                   GEGL_BUFFER_READWRITE, GEGL_ABYSS_NONE);
  roi = &iter->roi[0];

  while (gegl_buffer_iterator_next (iter))
    {
      guchar     *data    = iter->data[0];
      guchar     *tmp_buf = NULL;
      const gint  stride  = cairo_format_stride_for_width (CAIRO_FORMAT_A8,
                                                           roi->width);

      /*  cairo rowstrides are always multiples of 4, whereas
       *  maskPR.rowstride can be anything, so to be able to create an
       *  image surface, we maybe have to create our own temporary
       *  buffer
       */
      if (roi->width * bpp != stride)
        {
          tmp_buf = g_alloca (stride * roi->height);

          if (! replace)
            {
              const guchar *src  = data;
              guchar       *dest = tmp_buf;
              gint          i;

              for (i = 0; i < roi->height; i++)
                {
                  memcpy (dest, src, roi->width * bpp);

                  src  += roi->width * bpp;
                  dest += stride;
                }
            }
        }

      surface = cairo_image_surface_create_for_data (tmp_buf ?
                                                     tmp_buf : data,
                                                     CAIRO_FORMAT_A8,
                                                     roi->width, roi->height,
                                                     stride);

      cairo_surface_set_device_offset (surface,
                                       -off_x - roi->x,
                                       -off_y - roi->y);
      cr = cairo_create (surface);
      cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);

      if (replace)
        {
          cairo_set_source_rgba (cr, 0, 0, 0, 0);
          cairo_paint (cr);
        }

      cairo_set_source_rgba (cr, 0, 0, 0, value);
      cairo_append_path (cr, &path);

      cairo_set_antialias (cr, antialias ?
                           CAIRO_ANTIALIAS_GRAY : CAIRO_ANTIALIAS_NONE);
      cairo_set_miter_limit (cr, sc->miter);

      if (sc->do_stroke)
        {
          cairo_set_line_cap (cr,
                              sc->cap == GIMP_CAP_BUTT ? CAIRO_LINE_CAP_BUTT :
                              sc->cap == GIMP_CAP_ROUND ? CAIRO_LINE_CAP_ROUND :
                              CAIRO_LINE_CAP_SQUARE);
          cairo_set_line_join (cr,
                               sc->join == GIMP_JOIN_MITER ? CAIRO_LINE_JOIN_MITER :
                               sc->join == GIMP_JOIN_ROUND ? CAIRO_LINE_JOIN_ROUND :
                               CAIRO_LINE_JOIN_BEVEL);

          cairo_set_line_width (cr, sc->width);

          if (sc->dash_info)
            cairo_set_dash (cr,
                            (double *) sc->dash_info->data,
                            sc->dash_info->len,
                            sc->dash_offset);

          cairo_scale (cr, 1.0, sc->ratio_xy);
          cairo_stroke (cr);
        }
      else
        {
          cairo_set_fill_rule (cr, CAIRO_FILL_RULE_EVEN_ODD);
          cairo_fill (cr);
        }

      cairo_destroy (cr);
      cairo_surface_destroy (surface);

      if (tmp_buf)
        {
          const guchar *src  = tmp_buf;
          guchar       *dest = data;
          gint          i;

          for (i = 0; i < roi->height; i++)
            {
              memcpy (dest, src, roi->width * bpp);

              src  += stride;
              dest += roi->width * bpp;
            }
        }
    }
}