Exemple #1
0
static gboolean
gimp_drawable_edit_can_fill_direct (GimpDrawable    *drawable,
                                    GimpFillOptions *options)
{
  GimpImage                *image;
  GimpContext              *context;
  gdouble                   opacity;
  GimpComponentMask         affect;
  GimpLayerMode             mode;
  GimpLayerCompositeMode    composite_mode;
  GimpLayerCompositeRegion  composite_region;

  image            = gimp_item_get_image (GIMP_ITEM (drawable));
  context          = GIMP_CONTEXT (options);
  opacity          = gimp_context_get_opacity (context);
  affect           = gimp_drawable_get_active_mask (drawable);
  mode             = gimp_context_get_paint_mode (context);
  composite_mode   = gimp_layer_mode_get_paint_composite_mode (mode);
  composite_region = gimp_layer_mode_get_included_region (mode, composite_mode);

  if (gimp_channel_is_empty (gimp_image_get_mask (image)) &&
      opacity == GIMP_OPACITY_OPAQUE                      &&
      affect  == GIMP_COMPONENT_MASK_ALL                  &&
      gimp_layer_mode_is_trivial (mode)                   &&
      (! gimp_layer_mode_is_subtractive (mode)            ^
       ! (composite_region & GIMP_LAYER_COMPOSITE_REGION_SOURCE)))
    {
      switch (gimp_fill_options_get_style (options))
        {
        case GIMP_FILL_STYLE_SOLID:
          return TRUE;

        case GIMP_FILL_STYLE_PATTERN:
          {
            GimpPattern *pattern;
            GimpTempBuf *mask;
            const Babl  *format;

            pattern = gimp_context_get_pattern (context);
            mask    = gimp_pattern_get_mask (pattern);
            format  = gimp_temp_buf_get_format (mask);

            return ! babl_format_has_alpha (format);
          }
        }
    }

  return FALSE;
}
Exemple #2
0
void
gimp_paint_core_paste (GimpPaintCore            *core,
                       const GimpTempBuf        *paint_mask,
                       gint                      paint_mask_offset_x,
                       gint                      paint_mask_offset_y,
                       GimpDrawable             *drawable,
                       gdouble                   paint_opacity,
                       gdouble                   image_opacity,
                       GimpLayerModeEffects      paint_mode,
                       GimpPaintApplicationMode  mode)
{
  gint width  = gegl_buffer_get_width  (core->paint_buffer);
  gint height = gegl_buffer_get_height (core->paint_buffer);

  if (core->applicator)
    {
      /*  If the mode is CONSTANT:
       *   combine the canvas buf, the paint mask to the canvas buffer
       */
      if (mode == GIMP_PAINT_CONSTANT)
        {
          /* Some tools (ink) paint the mask to paint_core->canvas_buffer
           * directly. Don't need to copy it in this case.
           */
          if (paint_mask != NULL)
            {
              GeglBuffer *paint_mask_buffer =
                gimp_temp_buf_create_buffer ((GimpTempBuf *) paint_mask);

              gimp_gegl_combine_mask_weird (paint_mask_buffer,
                                            GEGL_RECTANGLE (paint_mask_offset_x,
                                                            paint_mask_offset_y,
                                                            width, height),
                                            core->canvas_buffer,
                                            GEGL_RECTANGLE (core->paint_buffer_x,
                                                            core->paint_buffer_y,
                                                            width, height),
                                            paint_opacity,
                                            GIMP_IS_AIRBRUSH (core));

              g_object_unref (paint_mask_buffer);
            }

          gimp_gegl_apply_mask (core->canvas_buffer,
                                GEGL_RECTANGLE (core->paint_buffer_x,
                                                core->paint_buffer_y,
                                                width, height),
                                core->paint_buffer,
                                GEGL_RECTANGLE (0, 0, width, height),
                                1.0);

          gimp_applicator_set_src_buffer (core->applicator,
                                          core->undo_buffer);
        }
      /*  Otherwise:
       *   combine the canvas buf and the paint mask to the canvas buf
       */
      else
        {
          GeglBuffer *paint_mask_buffer =
            gimp_temp_buf_create_buffer ((GimpTempBuf *) paint_mask);

          gimp_gegl_apply_mask (paint_mask_buffer,
                                GEGL_RECTANGLE (paint_mask_offset_x,
                                                paint_mask_offset_y,
                                                width, height),
                                core->paint_buffer,
                                GEGL_RECTANGLE (0, 0, width, height),
                                paint_opacity);

          g_object_unref (paint_mask_buffer);

          gimp_applicator_set_src_buffer (core->applicator,
                                          gimp_drawable_get_buffer (drawable));
        }

      gimp_applicator_set_apply_buffer (core->applicator,
                                        core->paint_buffer);
      gimp_applicator_set_apply_offset (core->applicator,
                                        core->paint_buffer_x,
                                        core->paint_buffer_y);

      gimp_applicator_set_mode (core->applicator,
                                image_opacity, paint_mode);

      /*  apply the paint area to the image  */
      gimp_applicator_blit (core->applicator,
                            GEGL_RECTANGLE (core->paint_buffer_x,
                                            core->paint_buffer_y,
                                            width, height));
    }
  else
    {
      GimpTempBuf *paint_buf = gimp_gegl_buffer_get_temp_buf (core->paint_buffer);
      GeglBuffer  *dest_buffer;
      GeglBuffer  *src_buffer;

      if (! paint_buf)
        return;

      if (core->comp_buffer)
        dest_buffer = core->comp_buffer;
      else
        dest_buffer = gimp_drawable_get_buffer (drawable);

      if (mode == GIMP_PAINT_CONSTANT)
        {
          /* This step is skipped by the ink tool, which writes
           * directly to canvas_buffer
           */
          if (paint_mask != NULL)
            {
              /* Mix paint mask and canvas_buffer */
              combine_paint_mask_to_canvas_mask (paint_mask,
                                                 paint_mask_offset_x,
                                                 paint_mask_offset_y,
                                                 core->canvas_buffer,
                                                 core->paint_buffer_x,
                                                 core->paint_buffer_y,
                                                 paint_opacity,
                                                 GIMP_IS_AIRBRUSH (core));
            }

          /* Write canvas_buffer to paint_buf */
          canvas_buffer_to_paint_buf_alpha (paint_buf,
                                            core->canvas_buffer,
                                            core->paint_buffer_x,
                                            core->paint_buffer_y);

          /* undo buf -> paint_buf -> dest_buffer */
          src_buffer = core->undo_buffer;
        }
      else
        {
          g_return_if_fail (paint_mask);

          /* Write paint_mask to paint_buf, does not modify canvas_buffer */
          paint_mask_to_paint_buffer (paint_mask,
                                      paint_mask_offset_x,
                                      paint_mask_offset_y,
                                      paint_buf,
                                      paint_opacity);

          /* dest_buffer -> paint_buf -> dest_buffer */
          src_buffer = dest_buffer;
        }

      do_layer_blend (src_buffer,
                      dest_buffer,
                      paint_buf,
                      core->mask_buffer,
                      image_opacity,
                      core->paint_buffer_x,
                      core->paint_buffer_y,
                      core->mask_x_offset,
                      core->mask_y_offset,
                      core->linear_mode,
                      paint_mode);

      if (core->comp_buffer)
        {
          mask_components_onto (src_buffer,
                                core->comp_buffer,
                                gimp_drawable_get_buffer (drawable),
                                GEGL_RECTANGLE(core->paint_buffer_x,
                                               core->paint_buffer_y,
                                               width,
                                               height),
                                gimp_drawable_get_active_mask (drawable),
                                core->linear_mode);
        }
    }

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

  /*  Update the drawable  */
  gimp_drawable_update (drawable,
                        core->paint_buffer_x,
                        core->paint_buffer_y,
                        width, height);
}
Exemple #3
0
gboolean
gimp_paint_core_start (GimpPaintCore     *core,
                       GimpDrawable      *drawable,
                       GimpPaintOptions  *paint_options,
                       const GimpCoords  *coords,
                       GError           **error)
{
  GimpImage   *image;
  GimpItem    *item;
  GimpChannel *mask;

  g_return_val_if_fail (GIMP_IS_PAINT_CORE (core), FALSE);
  g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), FALSE);
  g_return_val_if_fail (gimp_item_is_attached (GIMP_ITEM (drawable)), FALSE);
  g_return_val_if_fail (GIMP_IS_PAINT_OPTIONS (paint_options), FALSE);
  g_return_val_if_fail (coords != NULL, FALSE);
  g_return_val_if_fail (error == NULL || *error == NULL, FALSE);

  item  = GIMP_ITEM (drawable);
  image = gimp_item_get_image (item);

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

  core->stroke_buffer = g_array_sized_new (TRUE, TRUE,
                                           sizeof (GimpCoords),
                                           STROKE_BUFFER_INIT_SIZE);

  /* remember the last stroke's endpoint for later undo */
  core->start_coords = core->last_coords;

  core->cur_coords = *coords;

  if (! GIMP_PAINT_CORE_GET_CLASS (core)->start (core, drawable,
                                                 paint_options,
                                                 coords, error))
    {
      return FALSE;
    }

  /*  Allocate the undo structure  */
  if (core->undo_buffer)
    g_object_unref (core->undo_buffer);

  core->undo_buffer = gegl_buffer_dup (gimp_drawable_get_buffer (drawable));

  /*  Allocate the saved proj structure  */
  if (core->saved_proj_buffer)
    {
      g_object_unref (core->saved_proj_buffer);
      core->saved_proj_buffer = NULL;
    }

  if (core->use_saved_proj)
    {
      GeglBuffer *buffer = gimp_pickable_get_buffer (GIMP_PICKABLE (image));

      core->saved_proj_buffer = gegl_buffer_dup (buffer);
    }

  /*  Allocate the canvas blocks structure  */
  if (core->canvas_buffer)
    g_object_unref (core->canvas_buffer);

  core->canvas_buffer =
    gegl_buffer_new (GEGL_RECTANGLE (0, 0,
                                     gimp_item_get_width  (item),
                                     gimp_item_get_height (item)),
                     babl_format ("Y float"));

  /*  Get the initial undo extents  */

  core->x1 = core->x2 = core->cur_coords.x;
  core->y1 = core->y2 = core->cur_coords.y;

  core->last_paint.x = -1e6;
  core->last_paint.y = -1e6;

  mask = gimp_image_get_mask (image);

  /*  don't apply the mask to itself and don't apply an empty mask  */
  if (GIMP_DRAWABLE (mask) != drawable && ! gimp_channel_is_empty (mask))
    {
      GeglBuffer *mask_buffer;
      gint        offset_x;
      gint        offset_y;

      mask_buffer = gimp_drawable_get_buffer (GIMP_DRAWABLE (mask));
      gimp_item_get_offset (item, &offset_x, &offset_y);

      core->mask_buffer   = g_object_ref (mask_buffer);
      core->mask_x_offset = -offset_x;
      core->mask_y_offset = -offset_y;
    }
  else
    {
      core->mask_buffer = NULL;
    }

  core->linear_mode = gimp_drawable_get_linear (drawable);

  if (paint_options->use_applicator)
    {
      core->applicator = gimp_applicator_new (NULL, core->linear_mode);

      if (core->mask_buffer)
        {
          gimp_applicator_set_mask_buffer (core->applicator,
                                           core->mask_buffer);
          gimp_applicator_set_mask_offset (core->applicator,
                                           core->mask_x_offset,
                                           core->mask_y_offset);
        }

      gimp_applicator_set_affect (core->applicator,
                                  gimp_drawable_get_active_mask (drawable));
      gimp_applicator_set_dest_buffer (core->applicator,
                                       gimp_drawable_get_buffer (drawable));
    }
  else
    {
      if (core->comp_buffer)
        {
          g_object_unref (core->comp_buffer);
          core->comp_buffer = NULL;
        }

      /* Allocate the scratch buffer if there's a component mask */
      if (gimp_drawable_get_active_mask (drawable) != GIMP_COMPONENT_ALL)
        {
          const Babl *format;

          if (core->linear_mode)
            format = babl_format ("RGBA float");
          else
            format = babl_format ("R'G'B'A float");

          core->comp_buffer =
            gegl_buffer_new (GEGL_RECTANGLE (0, 0,
                                             gimp_item_get_width  (item),
                                             gimp_item_get_height (item)),
                             format);
        }
    }

  /*  Freeze the drawable preview so that it isn't constantly updated.  */
  gimp_viewable_preview_freeze (GIMP_VIEWABLE (drawable));

  return TRUE;
}
gboolean
gimp_paint_core_start (GimpPaintCore     *core,
                       GimpDrawable      *drawable,
                       GimpPaintOptions  *paint_options,
                       const GimpCoords  *coords,
                       GError           **error)
{
  GimpItem *item;

  g_return_val_if_fail (GIMP_IS_PAINT_CORE (core), FALSE);
  g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), FALSE);
  g_return_val_if_fail (gimp_item_is_attached (GIMP_ITEM (drawable)), FALSE);
  g_return_val_if_fail (GIMP_IS_PAINT_OPTIONS (paint_options), FALSE);
  g_return_val_if_fail (coords != NULL, FALSE);
  g_return_val_if_fail (error == NULL || *error == NULL, FALSE);

  item = GIMP_ITEM (drawable);

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

  core->stroke_buffer = g_array_sized_new (TRUE, TRUE,
                                           sizeof (GimpCoords),
                                           STROKE_BUFFER_INIT_SIZE);

  core->cur_coords = *coords;

  if (! GIMP_PAINT_CORE_GET_CLASS (core)->start (core, drawable,
                                                 paint_options,
                                                 coords, error))
    {
      return FALSE;
    }

  /*  Allocate the undo structure  */
  if (core->undo_buffer)
    g_object_unref (core->undo_buffer);

  core->undo_buffer = gegl_buffer_dup (gimp_drawable_get_buffer (drawable));

  /*  Allocate the saved proj structure  */
  if (core->saved_proj_buffer)
    {
      g_object_unref (core->saved_proj_buffer);
      core->saved_proj_buffer = NULL;
    }

  if (core->use_saved_proj)
    {
      GimpImage    *image    = gimp_item_get_image (item);
      GimpPickable *pickable = GIMP_PICKABLE (gimp_image_get_projection (image));
      GeglBuffer   *buffer   = gimp_pickable_get_buffer (pickable);

      core->saved_proj_buffer = gegl_buffer_dup (buffer);
    }

  /*  Allocate the canvas blocks structure  */
  if (core->canvas_buffer)
    g_object_unref (core->canvas_buffer);

  core->canvas_buffer =
    gegl_buffer_new (GEGL_RECTANGLE (0, 0,
                                     gimp_item_get_width  (item),
                                     gimp_item_get_height (item)),
                     babl_format ("Y u8"));

  /*  Get the initial undo extents  */

  core->x1 = core->x2 = core->cur_coords.x;
  core->y1 = core->y2 = core->cur_coords.y;

  core->last_paint.x = -1e6;
  core->last_paint.y = -1e6;

  {
    GimpImage   *image;
    GimpChannel *mask;
    GeglBuffer  *mask_buffer = NULL;
    gint         offset_x    = 0;
    gint         offset_y    = 0;

    image = gimp_item_get_image (item);
    mask  = gimp_image_get_mask (image);

    /*  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 (mask)
      {
        mask_buffer = gimp_drawable_get_buffer (GIMP_DRAWABLE (mask));

        gimp_item_get_offset (item, &offset_x, &offset_y);
      }

    core->applicator =
      gimp_applicator_new (gimp_drawable_get_buffer (drawable),
                           gimp_drawable_get_active_mask (drawable),
                           mask_buffer,
                           -offset_x, -offset_y);
  }

  /*  Freeze the drawable preview so that it isn't constantly updated.  */
  gimp_viewable_preview_freeze (GIMP_VIEWABLE (drawable));

  return TRUE;
}
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);
}
Exemple #6
0
void
gimp_drawable_edit_fill (GimpDrawable    *drawable,
                         GimpFillOptions *options,
                         const gchar     *undo_desc)
{
  GimpContext *context;
  gint         x, y, width, 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));

  if (! gimp_item_mask_intersect (GIMP_ITEM (drawable),
                                  &x, &y, &width, &height))
    {
      return;  /*  nothing to do, but the fill succeeded  */
    }

  context = GIMP_CONTEXT (options);

  if (gimp_layer_mode_is_alpha_only (gimp_context_get_paint_mode (context)))
    {
      if (! gimp_drawable_has_alpha (drawable) ||
          ! (gimp_drawable_get_active_mask (drawable) &
             GIMP_COMPONENT_MASK_ALPHA))
        {
          return;  /*  nothing to do, but the fill succeeded  */
        }
    }

  if (! undo_desc)
    undo_desc = gimp_fill_options_get_undo_desc (options);

  /* check if we can fill the drawable's buffer directly */
  if (gimp_drawable_edit_can_fill_direct (drawable, options))
    {
      gimp_drawable_edit_fill_direct (drawable, options, undo_desc);

      gimp_drawable_update (drawable, x, y, width, height);
    }
  else
    {
      GeglNode           *operation;
      GimpDrawableFilter *filter;
      gdouble             opacity;
      GimpLayerMode       mode;
      GimpLayerMode       composite_mode;

      opacity        = gimp_context_get_opacity (context);
      mode           = gimp_context_get_paint_mode (context);
      composite_mode = gimp_layer_mode_get_paint_composite_mode (mode);

      operation = gegl_node_new_child (NULL,
                                       "operation",        "gimp:fill-source",
                                       "options",          options,
                                       "drawable",         drawable,
                                       "pattern-offset-x", -x,
                                       "pattern-offset-y", -y,
                                       NULL);

      filter = gimp_drawable_filter_new (drawable, undo_desc, operation, NULL);

      gimp_drawable_filter_set_opacity (filter, opacity);
      gimp_drawable_filter_set_mode    (filter,
                                        mode,
                                        GIMP_LAYER_COLOR_SPACE_AUTO,
                                        GIMP_LAYER_COLOR_SPACE_AUTO,
                                        composite_mode);

      gimp_drawable_filter_apply  (filter, NULL);
      gimp_drawable_filter_commit (filter, NULL, FALSE);

      g_object_unref (filter);
      g_object_unref (operation);
    }
}