예제 #1
0
static void
gimp_clone_line_image (GimpImage     *dest_image,
                       GimpImageType  dest_type,
                       GimpImage     *src_image,
                       GimpImageType  src_type,
                       guchar        *s,
                       guchar        *d,
                       gint           src_bytes,
                       gint           dest_bytes,
                       gint           width)
{
  guchar rgba[MAX_CHANNELS];
  gint   alpha;

  alpha = dest_bytes - 1;

  while (width--)
    {
      gimp_image_get_color (src_image, src_type, s, rgba);
      gimp_image_transform_color (dest_image, dest_type, d,
                                  GIMP_RGB, rgba);

      d[alpha] = rgba[ALPHA];

      s += src_bytes;
      d += dest_bytes;
    }
}
예제 #2
0
static void
gimp_clone_line_pattern (GimpImage     *dest_image,
                         GimpImageType  dest_type,
                         GimpPattern   *pattern,
                         guchar        *d,
                         gint           x,
                         gint           y,
                         gint           dest_bytes,
                         gint           width)
{
  guchar            *pat, *p;
  GimpImageBaseType  color_type;
  gint               alpha;
  gint               pat_bytes;
  gint               i;

  pat_bytes = pattern->mask->bytes;

  /*  Make sure x, y are positive  */
  while (x < 0)
    x += pattern->mask->width;
  while (y < 0)
    y += pattern->mask->height;

  /*  Get a pointer to the appropriate scanline of the pattern buffer  */
  pat = temp_buf_get_data (pattern->mask) +
    (y % pattern->mask->height) * pattern->mask->width * pat_bytes;

  color_type = (pat_bytes == 3 ||
                pat_bytes == 4) ? GIMP_RGB : GIMP_GRAY;

  alpha = dest_bytes - 1;

  for (i = 0; i < width; i++)
    {
      p = pat + ((i + x) % pattern->mask->width) * pat_bytes;

      gimp_image_transform_color (dest_image, dest_type, d,
                                  color_type, p);

      if (pat_bytes == 2 || pat_bytes == 4)
        d[alpha] = p[pat_bytes - 1];
      else
        d[alpha] = OPAQUE_OPACITY;

      d += dest_bytes;
    }
}
예제 #3
0
static void
gimp_text_layer_render_layout (GimpTextLayer  *layer,
                               GimpTextLayout *layout)
{
  GimpDrawable    *drawable = GIMP_DRAWABLE (layer);
  GimpItem        *item     = GIMP_ITEM (layer);
  GimpImage       *image    = gimp_item_get_image (item);
  cairo_t         *cr;
  cairo_surface_t *surface;
  PixelRegion      layerPR;
  const guchar    *data;
  GimpImageType    layer_type;
  gint             layer_alpha_byte;
  gint             rowstride;
  gint             width;
  gint             height;
  gpointer         pr;

  g_return_if_fail (gimp_drawable_has_alpha (drawable));

  width  = gimp_item_get_width  (item);
  height = gimp_item_get_height (item);

  surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height);

  cr = cairo_create (surface);
  gimp_text_layout_render (layout, cr, layer->text->base_dir, FALSE);
  cairo_destroy (cr);

  pixel_region_init (&layerPR, gimp_drawable_get_tiles (drawable),
                     0, 0, width, height, TRUE);

  layer_type = gimp_drawable_type (drawable);
  layer_alpha_byte = layerPR.bytes - 1;

  cairo_surface_flush (surface);
  data      = cairo_image_surface_get_data (surface);
  rowstride = cairo_image_surface_get_stride (surface);

  for (pr = pixel_regions_register (1, &layerPR);
       pr != NULL;
       pr = pixel_regions_process (pr))
    {
      const guchar *src  = data + layerPR.y * rowstride + layerPR.x * 4;
      guchar       *dest = layerPR.data;
      gint          rows = layerPR.h;

      while (rows--)
        {
          const guchar *s = src;
          guchar       *d = dest;
          gint          w = layerPR.w;

          while (w--)
            {
              guchar color[4];

              GIMP_CAIRO_ARGB32_GET_PIXEL (s,
                                           color[0],
                                           color[1],
                                           color[2],
                                           color[3]);

              gimp_image_transform_color (image,
                                          layer_type, d, GIMP_RGB, color);
              d[layer_alpha_byte] = color[3];

              s += 4;
              d += layerPR.bytes;
            }

          src  += rowstride;
          dest += layerPR.rowstride;
        }
    }

  cairo_surface_destroy (surface);

  gimp_drawable_update (drawable, 0, 0, width, height);
}
예제 #4
0
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);
}
예제 #5
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);
}