コード例 #1
0
ファイル: gimp-gegl-utils.c プロジェクト: 1ynx/gimp
TileManager *
gimp_buffer_to_tiles (GeglBuffer *buffer)
{
  const Babl    *format     = gegl_buffer_get_format (buffer);
  TileManager   *new_tiles  = NULL;
  GeglNode      *source     = NULL;
  GeglNode      *sink       = NULL;

  g_return_val_if_fail (buffer != NULL, NULL);

  /* Setup and process the graph */
  new_tiles = tile_manager_new (gegl_buffer_get_width (buffer),
                                gegl_buffer_get_height (buffer),
                                gimp_babl_format_to_legacy_bpp (format));
  source = gegl_node_new_child (NULL,
                                "operation", "gegl:buffer-source",
                                "buffer",    buffer,
                                NULL);
  sink = gegl_node_new_child (NULL,
                              "operation",    "gimp:tilemanager-sink",
                              "tile-manager", new_tiles,
                              NULL);
  gegl_node_link_many (source, sink, NULL);
  gegl_node_process (sink);

  /* Clenaup */
  g_object_unref (sink);
  g_object_unref (source);

  return new_tiles;
}
コード例 #2
0
ファイル: gimpbuffer.c プロジェクト: Amerekanets/gimp
GimpBuffer *
gimp_buffer_new_from_pixbuf (GdkPixbuf   *pixbuf,
                             const gchar *name)
{
  TileManager *tiles;
  guchar      *pixels;
  PixelRegion  destPR;
  gint         width;
  gint         height;
  gint         rowstride;
  gint         channels;
  gint         y;

  g_return_val_if_fail (GDK_IS_PIXBUF (pixbuf), NULL);
  g_return_val_if_fail (name != NULL, NULL);

  width     = gdk_pixbuf_get_width (pixbuf);
  height    = gdk_pixbuf_get_height (pixbuf);
  rowstride = gdk_pixbuf_get_rowstride (pixbuf);
  channels  = gdk_pixbuf_get_n_channels (pixbuf);

  tiles = tile_manager_new (width, height, channels);

  pixel_region_init (&destPR, tiles, 0, 0, width, height, TRUE);

  for (y = 0, pixels = gdk_pixbuf_get_pixels (pixbuf);
       y < height;
       y++, pixels += rowstride)
    {
      pixel_region_set_row (&destPR, 0, y, width, pixels);
   }

  return gimp_buffer_new (tiles, name, FALSE);
}
コード例 #3
0
ファイル: tile-pyramid.c プロジェクト: Amerekanets/gimp
/**
 * tile_pyramid_new:
 * @type:   type of pixel data stored in the pyramid
 * @width:  bottom level width
 * @height: bottom level height
 *
 * Creates a new #TilePyramid, managing a set of tile-managers where
 * each level is a sized-down version of the level below.
 *
 * This only works correctly if you set a validate procedure using
 * tile_pyramid_set_validate_proc() and invalidate areas. With some
 * small changes, it could be made to work for non-validating tile
 * managers also. But currently only the projection uses it.
 *
 * Only the bottom-most tile-manager is allocated at this point. Upper
 * levels are created only if they are requested.
 *
 * Return value: a newly allocate #TilePyramid
 **/
TilePyramid *
tile_pyramid_new (GimpImageType  type,
                  gint           width,
                  gint           height)
{
  TilePyramid *pyramid;

  g_return_val_if_fail (width > 0, NULL);
  g_return_val_if_fail (height > 0, NULL);

  pyramid = g_slice_new0 (TilePyramid);

  pyramid->type   = type;
  pyramid->width  = width;
  pyramid->height = height;

  switch (type)
    {
    case GIMP_GRAY_IMAGE:
      pyramid->bytes = 1;
      break;

    case GIMP_GRAYA_IMAGE:
      pyramid->bytes = 2;
      break;

    case GIMP_RGB_IMAGE:
      pyramid->bytes = 3;
      break;

    case GIMP_RGBA_IMAGE:
      pyramid->bytes = 4;
      break;

    case GIMP_INDEXED_IMAGE:
    case GIMP_INDEXEDA_IMAGE:
      g_assert_not_reached ();
      break;
    }

  pyramid->tiles[0] = tile_manager_new (width, height, pyramid->bytes);

  return pyramid;
}
コード例 #4
0
void
floating_sel_attach (GimpLayer    *layer,
                     GimpDrawable *drawable)
{
  GimpImage *image;
  GimpLayer *floating_sel;

  g_return_if_fail (GIMP_IS_LAYER (layer));
  g_return_if_fail (GIMP_IS_DRAWABLE (drawable));
  g_return_if_fail (gimp_item_is_attached (GIMP_ITEM (drawable)));
  g_return_if_fail (drawable != GIMP_DRAWABLE (layer));
  g_return_if_fail (gimp_item_get_image (GIMP_ITEM (layer)) ==
                    gimp_item_get_image (GIMP_ITEM (drawable)));

  image = gimp_item_get_image (GIMP_ITEM (drawable));

  floating_sel = gimp_image_floating_sel (image);

  /*  If there is already a floating selection, anchor it  */
  if (floating_sel)
    {
      floating_sel_anchor (floating_sel);

      /*  if we were pasting to the old floating selection, paste now
       *  to the drawable
       */
      if (drawable == (GimpDrawable *) floating_sel)
        drawable = gimp_image_get_active_drawable (image);
    }

  /*  set the drawable and allocate a backing store  */
  gimp_layer_set_lock_alpha (layer, TRUE, FALSE);
  layer->fs.drawable      = drawable;
  layer->fs.backing_store = tile_manager_new (GIMP_ITEM (layer)->width,
                                              GIMP_ITEM (layer)->height,
                                              gimp_drawable_bytes (drawable));

  /*  add the layer to the image  */
  gimp_image_add_layer (image, layer, 0);

  /*  store the affected area from the drawable in the backing store  */
  floating_sel_rigor (layer, TRUE);
}
コード例 #5
0
ファイル: gimpbuffer.c プロジェクト: Amerekanets/gimp
GimpBuffer *
gimp_buffer_new (TileManager *tiles,
                 const gchar *name,
                 gboolean     copy_pixels)
{
  GimpBuffer *buffer;
  gint        width, height;

  g_return_val_if_fail (tiles != NULL, NULL);
  g_return_val_if_fail (name != NULL, NULL);

  width  = tile_manager_width (tiles);
  height = tile_manager_height (tiles);

  buffer = g_object_new (GIMP_TYPE_BUFFER,
                         "name", name,
                         NULL);

  if (copy_pixels)
    {
      PixelRegion srcPR, destPR;

      buffer->tiles = tile_manager_new (width, height,
                                        tile_manager_bpp (tiles));

      pixel_region_init (&srcPR, tiles, 0, 0, width, height, FALSE);
      pixel_region_init (&destPR, buffer->tiles, 0, 0, width, height, TRUE);
      copy_region (&srcPR, &destPR);
    }
  else
    {
      buffer->tiles = tiles;
    }

  return buffer;
}
コード例 #6
0
ファイル: tile-pyramid.c プロジェクト: Amerekanets/gimp
/* This function make sure that levels are allocated up to the level
 * it returns. The return value may be smaller than the level that
 * was actually requested.
 */
static gint
tile_pyramid_alloc_levels (TilePyramid *pyramid,
                           gint         top_level)
{
  gint level;

  top_level = MIN (top_level, PYRAMID_MAX_LEVELS - 1);

  if (top_level <= pyramid->top_level)
    return top_level;

  for (level = pyramid->top_level + 1; level <= top_level; level++)
    {
      gint width  = pyramid->width  >> level;
      gint height = pyramid->height >> level;

      if (width == 0 || height == 0)
        return pyramid->top_level;

      /* There is no use having levels that have the same number of
       * tiles as the parent level.
       */
      if (width <= TILE_WIDTH / 2 && height <= TILE_HEIGHT / 2)
        return pyramid->top_level;

      pyramid->top_level    = level;
      pyramid->tiles[level] = tile_manager_new (width, height, pyramid->bytes);

      /* Use the level below to validate tiles. */
      tile_manager_set_validate_proc (pyramid->tiles[level],
                                      (TileValidateProc) tile_pyramid_validate_tile,
                                      pyramid->tiles[level - 1]);
    }

  return pyramid->top_level;
}
コード例 #7
0
ファイル: gimpdrawable-combine.c プロジェクト: 1ynx/gimp
void
gimp_drawable_real_apply_region (GimpDrawable         *drawable,
                                 PixelRegion          *src2PR,
                                 gboolean              push_undo,
                                 const gchar          *undo_desc,
                                 gdouble               opacity,
                                 GimpLayerModeEffects  mode,
                                 TileManager          *src1_tiles,
                                 PixelRegion          *destPR,
                                 gint                  x,
                                 gint                  y)
{
  GimpItem        *item  = GIMP_ITEM (drawable);
  GimpImage       *image = gimp_item_get_image (item);
  GimpChannel     *mask  = gimp_image_get_mask (image);
  gint             x1, y1, x2, y2;
  gint             offset_x, offset_y;
  PixelRegion      src1PR, my_destPR;
  CombinationMode  operation;
  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);

  /*  determine what sort of operation is being attempted and
   *  if it's actually legal...
   */
  operation = gimp_image_get_combination_mode (gimp_drawable_type (drawable),
                                               src2PR->bytes);
  if (operation == -1)
    {
      g_warning ("%s: illegal parameters.", G_STRFUNC);
      return;
    }

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

  /*  make sure the image application coordinates are within drawable bounds  */
  x1 = CLAMP (x,             0, gimp_item_get_width  (item));
  y1 = CLAMP (y,             0, gimp_item_get_height (item));
  x2 = CLAMP (x + src2PR->w, 0, gimp_item_get_width  (item));
  y2 = CLAMP (y + src2PR->h, 0, gimp_item_get_height (item));

  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
       */
      x1 = CLAMP (x1, -offset_x, gimp_item_get_width  (mask_item) - offset_x);
      y1 = CLAMP (y1, -offset_y, gimp_item_get_height (mask_item) - offset_y);
      x2 = CLAMP (x2, -offset_x, gimp_item_get_width  (mask_item) - offset_x);
      y2 = CLAMP (y2, -offset_y, gimp_item_get_height (mask_item) - offset_y);
    }

  /*  If the calling procedure specified an undo step...  */
  if (push_undo)
    {
      GimpDrawableUndo *undo;

      gimp_drawable_push_undo (drawable, undo_desc,
                               x1, y1,
                               x2 - x1, y2 - y1,
                               NULL, FALSE);

      undo = GIMP_DRAWABLE_UNDO (gimp_image_undo_get_fadeable (image));

      if (undo)
        {
          PixelRegion tmp_srcPR;
          PixelRegion tmp_destPR;

          undo->paint_mode = mode;
          undo->opacity    = opacity;
          undo->src2_tiles = tile_manager_new (x2 - x1, y2 - y1,
                                               src2PR->bytes);

          tmp_srcPR = *src2PR;
          pixel_region_resize (&tmp_srcPR,
                               src2PR->x + (x1 - x), src2PR->y + (y1 - y),
                               x2 - x1, y2 - y1);
          pixel_region_init (&tmp_destPR, undo->src2_tiles,
                             0, 0,
                             x2 - x1, y2 - y1, TRUE);

          copy_region (&tmp_srcPR, &tmp_destPR);
        }
    }

  /* configure the pixel regions */

  /* check if an alternative to using the drawable's data as src1 was
   * provided...
   */
  if (src1_tiles)
    {
      pixel_region_init (&src1PR, src1_tiles,
                         x1, y1, x2 - x1, y2 - y1,
                         FALSE);
    }
  else
    {
      pixel_region_init (&src1PR, gimp_drawable_get_tiles (drawable),
                         x1, y1, x2 - x1, y2 - y1,
                         FALSE);
    }

  /* check if an alternative to using the drawable's data as dest was
   * provided...
   */
  if (!destPR)
    {
      pixel_region_init (&my_destPR, gimp_drawable_get_tiles (drawable),
                         x1, y1, x2 - x1, y2 - y1,
                         TRUE);
      destPR = &my_destPR;
    }

  pixel_region_resize (src2PR,
                       src2PR->x + (x1 - x), src2PR->y + (y1 - y),
                       x2 - x1, y2 - y1);

  if (mask)
    {
      PixelRegion maskPR;

      pixel_region_init (&maskPR,
                         gimp_drawable_get_tiles (GIMP_DRAWABLE (mask)),
                         x1 + offset_x,
                         y1 + offset_y,
                         x2 - x1, y2 - y1,
                         FALSE);

      combine_regions (&src1PR, src2PR, destPR, &maskPR, NULL,
                       opacity * 255.999,
                       mode,
                       active_components,
                       operation);
    }
  else
    {
      combine_regions (&src1PR, src2PR, destPR, NULL, NULL,
                       opacity * 255.999,
                       mode,
                       active_components,
                       operation);
    }
}
コード例 #8
0
ファイル: gimpdrawable-bucket-fill.c プロジェクト: 1ynx/gimp
void
gimp_drawable_bucket_fill_full (GimpDrawable        *drawable,
                                GimpBucketFillMode   fill_mode,
                                gint                 paint_mode,
                                gdouble              opacity,
                                gboolean             do_seed_fill,
                                gboolean             fill_transparent,
                                GimpSelectCriterion  fill_criterion,
                                gdouble              threshold,
                                gboolean             sample_merged,
                                gdouble              x,
                                gdouble              y,
                                const GimpRGB       *color,
                                GimpPattern         *pattern)
{
  GimpImage   *image;
  TileManager *buf_tiles;
  PixelRegion  bufPR, maskPR;
  GimpChannel *mask = NULL;
  gint         bytes;
  gint         x1, y1, x2, y2;
  guchar       col[MAX_CHANNELS];
  TempBuf     *pat_buf = NULL;
  gboolean     new_buf = FALSE;
  gboolean     selection;

  g_return_if_fail (GIMP_IS_DRAWABLE (drawable));
  g_return_if_fail (gimp_item_is_attached (GIMP_ITEM (drawable)));
  g_return_if_fail (fill_mode != GIMP_PATTERN_BUCKET_FILL ||
                    GIMP_IS_PATTERN (pattern));
  g_return_if_fail (fill_mode == GIMP_PATTERN_BUCKET_FILL ||
                    color != NULL);

  image = gimp_item_get_image (GIMP_ITEM (drawable));

  bytes     = gimp_drawable_bytes (drawable);
  selection = gimp_item_mask_bounds (GIMP_ITEM (drawable), &x1, &y1, &x2, &y2);

  if ((x1 == x2) || (y1 == y2))
    return;

  if (fill_mode == GIMP_FG_BUCKET_FILL ||
      fill_mode == GIMP_BG_BUCKET_FILL)
    {
      guchar tmp_col[MAX_CHANNELS];

      gimp_rgb_get_uchar (color,
                          &tmp_col[RED],
                          &tmp_col[GREEN],
                          &tmp_col[BLUE]);

      gimp_image_transform_color (image, gimp_drawable_type (drawable), col,
                                  GIMP_RGB, tmp_col);
      col[gimp_drawable_bytes_with_alpha (drawable) - 1] = OPAQUE_OPACITY;
    }
  else if (fill_mode == GIMP_PATTERN_BUCKET_FILL)
    {
      pat_buf = gimp_image_transform_temp_buf (image,
                                               gimp_drawable_type (drawable),
                                               pattern->mask, &new_buf);
    }
  else
    {
      g_warning ("%s: invalid fill_mode passed", G_STRFUNC);
      return;
    }

  gimp_set_busy (image->gimp);

  /*  Do a seed bucket fill...To do this, calculate a new
   *  contiguous region. If there is a selection, calculate the
   *  intersection of this region with the existing selection.
   */
  if (do_seed_fill)
    {
      mask = gimp_image_contiguous_region_by_seed (image, drawable,
                                                   sample_merged,
                                                   TRUE,
                                                   (gint) threshold,
                                                   fill_transparent,
                                                   fill_criterion,
                                                   (gint) x,
                                                   (gint) y);

      if (selection)
        {
          gint off_x = 0;
          gint off_y = 0;

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

          gimp_channel_combine_mask (mask, gimp_image_get_mask (image),
                                     GIMP_CHANNEL_OP_INTERSECT,
                                     -off_x, -off_y);
        }

      gimp_channel_bounds (mask, &x1, &y1, &x2, &y2);

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

          item = GIMP_ITEM (drawable);

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

          x1 = CLAMP (x1, off_x, (off_x + gimp_item_get_width (item)));
          y1 = CLAMP (y1, off_y, (off_y + gimp_item_get_height (item)));
          x2 = CLAMP (x2, off_x, (off_x + gimp_item_get_width (item)));
          y2 = CLAMP (y2, off_y, (off_y + gimp_item_get_height (item)));

          pixel_region_init (&maskPR,
                             gimp_drawable_get_tiles (GIMP_DRAWABLE (mask)),
                             x1, y1, (x2 - x1), (y2 - y1), TRUE);

          /*  translate mask bounds to drawable coords  */
          x1 -= off_x;
          y1 -= off_y;
          x2 -= off_x;
          y2 -= off_y;
        }
      else
        {
          pixel_region_init (&maskPR,
                             gimp_drawable_get_tiles (GIMP_DRAWABLE (mask)),
                             x1, y1, (x2 - x1), (y2 - y1), TRUE);
        }

      /*  if the image doesn't have an alpha channel, make sure that
       *  the buf_tiles have.  We need the alpha channel to fill with
       *  the region calculated above
       */
      if (! gimp_drawable_has_alpha (drawable))
        bytes++;
    }
  else if (fill_mode == GIMP_PATTERN_BUCKET_FILL &&
           (pat_buf->bytes == 2 || pat_buf->bytes == 4))
    {
      /* If pattern being applied has an alpha channel, add one to the
       * buf_tiles.
       */
      if (! gimp_drawable_has_alpha (drawable))
        bytes++;
    }

  buf_tiles = tile_manager_new ((x2 - x1), (y2 - y1), bytes);
  pixel_region_init (&bufPR, buf_tiles, 0, 0, (x2 - x1), (y2 - y1), TRUE);

  switch (fill_mode)
    {
    case GIMP_FG_BUCKET_FILL:
    case GIMP_BG_BUCKET_FILL:
      if (mask)
        color_region_mask (&bufPR, &maskPR, col);
      else
        color_region (&bufPR, col);
      break;

    case GIMP_PATTERN_BUCKET_FILL:
      if (mask)
        pattern_region (&bufPR, &maskPR, pat_buf, x1, y1);
      else
        pattern_region (&bufPR, NULL, pat_buf, x1, y1);
      break;
    }

  /*  Apply it to the image  */
  pixel_region_init (&bufPR, buf_tiles, 0, 0, (x2 - x1), (y2 - y1), FALSE);
  gimp_drawable_apply_region (drawable, &bufPR,
                              TRUE, C_("undo-type", "Bucket Fill"),
                              opacity, paint_mode,
                              NULL, NULL, x1, y1);
  tile_manager_unref (buf_tiles);

  /*  update the image  */
  gimp_drawable_update (drawable, x1, y1, x2 - x1, y2 - y1);

  /*  free the mask  */
  if (mask)
    g_object_unref (mask);

  if (new_buf)
    temp_buf_free (pat_buf);

  gimp_unset_busy (image->gimp);
}
コード例 #9
0
static gboolean
gimp_text_layer_render (GimpTextLayer *layer)
{
  GimpDrawable   *drawable;
  GimpItem       *item;
  GimpImage      *image;
  GimpTextLayout *layout;
  gdouble         xres;
  gdouble         yres;
  gint            width;
  gint            height;

  if (! layer->text)
    return FALSE;

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

  if (gimp_container_is_empty (image->gimp->fonts))
    {
      gimp_message_literal (image->gimp, NULL, GIMP_MESSAGE_ERROR,
			    _("Due to lack of any fonts, "
			      "text functionality is not available."));
      return FALSE;
    }

  gimp_image_get_resolution (image, &xres, &yres);

  layout = gimp_text_layout_new (layer->text, xres, yres);

  g_object_freeze_notify (G_OBJECT (drawable));

  if (gimp_text_layout_get_size (layout, &width, &height) &&
      (width  != gimp_item_get_width  (item) ||
       height != gimp_item_get_height (item)))
    {
      TileManager *new_tiles = tile_manager_new (width, height,
                                                 gimp_drawable_bytes (drawable));

      gimp_drawable_set_tiles (drawable, FALSE, NULL, new_tiles,
                               gimp_drawable_type (drawable));

      tile_manager_unref (new_tiles);

      if (gimp_layer_get_mask (GIMP_LAYER (layer)))
        {
          GimpLayerMask *mask = gimp_layer_get_mask (GIMP_LAYER (layer));

          static GimpContext *unused_eek = NULL;

          if (! unused_eek)
            unused_eek = gimp_context_new (image->gimp, "eek", NULL);

          gimp_item_resize (GIMP_ITEM (mask), unused_eek, width, height, 0, 0);
        }
    }

  if (layer->auto_rename)
    {
      GimpItem *item = GIMP_ITEM (layer);
      gchar    *name = NULL;

      if (layer->text->text)
        {
          name = gimp_utf8_strtrim (layer->text->text, 30);
        }
      else if (layer->text->markup)
        {
          gchar *tmp = gimp_markup_extract_text (layer->text->markup);
          name = gimp_utf8_strtrim (tmp, 30);
          g_free (tmp);
        }

      if (! name)
        name = g_strdup (_("Empty Text Layer"));

      if (gimp_item_is_attached (item))
        {
          gimp_item_tree_rename_item (gimp_item_get_tree (item), item,
                                      name, FALSE, NULL);
          g_free (name);
        }
      else
        {
          gimp_object_take_name (GIMP_OBJECT (layer), name);
        }
    }

  gimp_text_layer_render_layout (layer, layout);

  g_object_unref (layout);

  g_object_thaw_notify (G_OBJECT (drawable));

  return (width > 0 && height > 0);
}
コード例 #10
0
static void
gimp_drawable_stroke_scan_convert (GimpDrawable      *drawable,
                                   GimpStrokeOptions *options,
                                   GimpScanConvert   *scan_convert)
{
  GimpContext *context = GIMP_CONTEXT (options);
  GimpImage   *image;
  gdouble      width;
  TileManager *base;
  TileManager *mask;
  gint         x, y, w, h;
  gint         bytes;
  gint         off_x, off_y;
  guchar       bg[1] = { 0, };
  PixelRegion  maskPR, basePR;

  image = gimp_item_get_image (GIMP_ITEM (drawable));

  /*  must call gimp_channel_is_empty() instead of relying on
   *  gimp_drawable_mask_intersect() because the selection pretends to
   *  be empty while it is being stroked, to prevent masking itself.
   */
  if (gimp_channel_is_empty (gimp_image_get_mask (image)))
    {
      x = 0;
      y = 0;
      w = gimp_item_width (GIMP_ITEM (drawable));
      h = gimp_item_height (GIMP_ITEM (drawable));
    }
  else if (! gimp_drawable_mask_intersect (drawable, &x, &y, &w, &h))
    {
      return;
    }

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

  width = options->width;

  if (options->unit != GIMP_UNIT_PIXEL)
    {
      gimp_scan_convert_set_pixel_ratio (scan_convert,
                                         image->yresolution /
                                         image->xresolution);

      width *= (image->yresolution /
                _gimp_unit_get_factor (image->gimp, options->unit));
    }

  gimp_scan_convert_stroke (scan_convert, width,
                            options->join_style,
                            options->cap_style,
                            options->miter_limit,
                            options->dash_offset,
                            options->dash_info);

  /* fill a 1-bpp Tilemanager with black, this will describe the shape
   * of the stroke.
   */
  mask = tile_manager_new (w, h, 1);
  pixel_region_init (&maskPR, mask, 0, 0, w, h, TRUE);
  color_region (&maskPR, bg);

  /* render the stroke into it */
  gimp_scan_convert_render (scan_convert, mask,
                            x + off_x, y + off_y,
                            options->antialias);

  bytes = gimp_drawable_bytes_with_alpha (drawable);

  base = tile_manager_new (w, h, bytes);
  pixel_region_init (&basePR, base, 0, 0, w, h, TRUE);
  pixel_region_init (&maskPR, mask, 0, 0, w, h, FALSE);

  switch (options->style)
    {
    case GIMP_STROKE_STYLE_SOLID:
      {
        guchar tmp_col[MAX_CHANNELS] = { 0, };
        guchar col[MAX_CHANNELS]     = { 0, };

        gimp_rgb_get_uchar (&context->foreground,
                            &tmp_col[RED_PIX],
                            &tmp_col[GREEN_PIX],
                            &tmp_col[BLUE_PIX]);

        gimp_image_transform_color (image, gimp_drawable_type (drawable), col,
                                    GIMP_RGB, tmp_col);
        col[bytes - 1] = OPAQUE_OPACITY;

        color_region_mask (&basePR, &maskPR, col);
      }
      break;

    case GIMP_STROKE_STYLE_PATTERN:
      {
        GimpPattern *pattern;
        TempBuf     *pat_buf;
        gboolean     new_buf;

        pattern = gimp_context_get_pattern (context);
        pat_buf = gimp_image_transform_temp_buf (image,
                                                 gimp_drawable_type (drawable),
                                                 pattern->mask, &new_buf);

        pattern_region (&basePR, &maskPR, pat_buf, x, y);

        if (new_buf)
          temp_buf_free (pat_buf);
      }
      break;
    }

  /* Apply to drawable */
  pixel_region_init (&basePR, base, 0, 0, w, h, FALSE);
  gimp_drawable_apply_region (drawable, &basePR,
                              TRUE, _("Render Stroke"),
                              gimp_context_get_opacity (context),
                              gimp_context_get_paint_mode (context),
                              NULL, x, y);

  tile_manager_unref (mask);
  tile_manager_unref (base);

  gimp_drawable_update (drawable, x, y, w, h);
}
コード例 #11
0
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_tiles)
    tile_manager_unref (core->undo_tiles);

  core->undo_tiles = tile_manager_new (gimp_item_get_width  (item),
                                       gimp_item_get_height (item),
                                       gimp_drawable_bytes (drawable));

  /*  Allocate the saved proj structure  */
  if (core->saved_proj_tiles)
    tile_manager_unref (core->saved_proj_tiles);

  core->saved_proj_tiles = NULL;

  if (core->use_saved_proj)
    {
      GimpImage    *image    = gimp_item_get_image (item);
      GimpPickable *pickable = GIMP_PICKABLE (gimp_image_get_projection (image));
      TileManager  *tiles    = gimp_pickable_get_tiles (pickable);

      core->saved_proj_tiles = tile_manager_new (tile_manager_width (tiles),
                                                 tile_manager_height (tiles),
                                                 tile_manager_bpp (tiles));
    }

  /*  Allocate the canvas blocks structure  */
  if (core->canvas_tiles)
    tile_manager_unref (core->canvas_tiles);

  core->canvas_tiles = tile_manager_new (gimp_item_get_width  (item),
                                         gimp_item_get_height (item),
                                         1);

  /*  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;

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

  return TRUE;
}
コード例 #12
0
void
floating_sel_store (GimpLayer *layer,
                    gint       x,
                    gint       y,
                    gint       w,
                    gint       h)
{
  PixelRegion srcPR, destPR;
  gint        offx, offy;
  gint        x1, y1, x2, y2;

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

  /*  Check the backing store & make sure it has the correct dimensions  */
  if ((tile_manager_width  (layer->fs.backing_store) !=
       gimp_item_width (GIMP_ITEM(layer)))  ||
      (tile_manager_height (layer->fs.backing_store) !=
       gimp_item_height (GIMP_ITEM(layer))) ||
      (tile_manager_bpp    (layer->fs.backing_store) !=
       gimp_drawable_bytes (layer->fs.drawable)))
    {
      /*  free the backing store and allocate anew  */
      tile_manager_unref (layer->fs.backing_store);

      layer->fs.backing_store =
        tile_manager_new (GIMP_ITEM (layer)->width,
                          GIMP_ITEM (layer)->height,
                          gimp_drawable_bytes (layer->fs.drawable));
    }

  /*  What this function does is save the specified area of the
   *  drawable that this floating selection obscures.  We do this so
   *  that it will be possible to subsequently restore the drawable's area
   */
  gimp_item_offsets (GIMP_ITEM (layer->fs.drawable), &offx, &offy);

  /*  Find the minimum area we need to uncover -- in image space  */
  x1 = MAX (GIMP_ITEM (layer)->offset_x, offx);
  y1 = MAX (GIMP_ITEM (layer)->offset_y, offy);
  x2 = MIN (GIMP_ITEM (layer)->offset_x + GIMP_ITEM (layer)->width,
            offx + gimp_item_width (GIMP_ITEM (layer->fs.drawable)));
  y2 = MIN (GIMP_ITEM (layer)->offset_y + GIMP_ITEM (layer)->height,
            offy + gimp_item_height (GIMP_ITEM (layer->fs.drawable)));

  x1 = CLAMP (x, x1, x2);
  y1 = CLAMP (y, y1, y2);
  x2 = CLAMP (x + w, x1, x2);
  y2 = CLAMP (y + h, y1, y2);

  if ((x2 - x1) > 0 && (y2 - y1) > 0)
    {
      /*  Copy the area from the drawable to the backing store  */
      pixel_region_init (&srcPR, gimp_drawable_get_tiles (layer->fs.drawable),
                         (x1 - offx), (y1 - offy), (x2 - x1), (y2 - y1), FALSE);
      pixel_region_init (&destPR, layer->fs.backing_store,
                         (x1 - GIMP_ITEM (layer)->offset_x),
                         (y1 - GIMP_ITEM (layer)->offset_y),
                         (x2 - x1), (y2 - y1), TRUE);

      copy_region (&srcPR, &destPR);
    }
}
コード例 #13
0
static gboolean
gimp_perspective_clone_get_source (GimpSourceCore   *source_core,
                                   GimpDrawable     *drawable,
                                   GimpPaintOptions *paint_options,
                                   GimpPickable     *src_pickable,
                                   gint              src_offset_x,
                                   gint              src_offset_y,
                                   TempBuf          *paint_area,
                                   gint             *paint_area_offset_x,
                                   gint             *paint_area_offset_y,
                                   gint             *paint_area_width,
                                   gint             *paint_area_height,
                                   PixelRegion      *srcPR)
{
  GimpPerspectiveClone *clone      = GIMP_PERSPECTIVE_CLONE (source_core);
  GimpPaintCore        *paint_core = GIMP_PAINT_CORE (source_core);
  GimpSourceOptions    *options    = GIMP_SOURCE_OPTIONS (paint_options);
  GimpImage            *src_image;
  GimpImage            *image;
  GimpImageType         src_type;
  gint                  x1d, y1d, x2d, y2d;
  gdouble               x1s, y1s, x2s, y2s, x3s, y3s, x4s, y4s;
  gint                  xmin, ymin, xmax, ymax;
  TileManager          *src_tiles;
  TileManager          *orig_tiles;
  PixelRegion           origPR;
  PixelRegion           destPR;
  GimpMatrix3           matrix;
  gint                  bytes;

  src_image = gimp_pickable_get_image (src_pickable);
  image     = gimp_item_get_image (GIMP_ITEM (drawable));

  src_type  = gimp_pickable_get_image_type (src_pickable);
  src_tiles = gimp_pickable_get_tiles (src_pickable);

  /* Destination coordinates that will be painted */
  x1d = paint_area->x;
  y1d = paint_area->y;
  x2d = paint_area->x + paint_area->width;
  y2d = paint_area->y + paint_area->height;

  /* 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));

  xmin = CLAMP (xmin - 1, 0, tile_manager_width  (src_tiles));
  ymin = CLAMP (ymin - 1, 0, tile_manager_height (src_tiles));
  xmax = CLAMP (xmax + 1, 0, tile_manager_width  (src_tiles));
  ymax = CLAMP (ymax + 1, 0, tile_manager_height (src_tiles));

  /* if the source area is completely out of the image */
  if (!(xmax - xmin) || !(ymax - ymin))
    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)))
    {
      pixel_region_init (&origPR, src_tiles,
                         xmin, ymin, xmax - xmin, ymax - ymin, FALSE);
    }
  else
    {
      TempBuf *orig;

      /*  get the original image  */
      if (options->sample_merged)
        orig = gimp_paint_core_get_orig_proj (paint_core,
                                              src_pickable,
                                              xmin, ymin, xmax, ymax);
      else
        orig = gimp_paint_core_get_orig_image (paint_core,
                                               GIMP_DRAWABLE (src_pickable),
                                               xmin, ymin, xmax, ymax);

      pixel_region_init_temp_buf (&origPR, orig,
                                  0, 0, xmax - xmin, ymax - ymin);
    }

  /*  copy the original image to a tile manager, adding alpha if needed  */

  bytes = GIMP_IMAGE_TYPE_BYTES (GIMP_IMAGE_TYPE_WITH_ALPHA (src_type));

  orig_tiles = tile_manager_new (xmax - xmin, ymax - ymin, bytes);

  tile_manager_set_offsets (orig_tiles, xmin, ymin);

  pixel_region_init (&destPR, orig_tiles,
                     0, 0, xmax - xmin, ymax - ymin,
                     TRUE);

  if (bytes > origPR.bytes)
    add_alpha_region (&origPR, &destPR);
  else
    copy_region (&origPR, &destPR);

  clone->src_area = temp_buf_resize (clone->src_area,
                                     tile_manager_bpp (orig_tiles),
                                     0, 0,
                                     x2d - x1d, y2d - y1d);

  pixel_region_init_temp_buf (&destPR, clone->src_area,
                              0, 0,
                              x2d - x1d, y2d - y1d);

  gimp_perspective_clone_get_matrix (clone, &matrix);

  gimp_transform_region (src_pickable,
                         GIMP_CONTEXT (paint_options),
                         orig_tiles,
                         &destPR,
                         x1d, y1d, x2d, y2d,
                         &matrix,
                         GIMP_INTERPOLATION_LINEAR, 0, NULL);

  tile_manager_unref (orig_tiles);

  pixel_region_init_temp_buf (srcPR, clone->src_area,
                              0, 0, x2d - x1d, y2d - y1d);

  return TRUE;
}