Exemple #1
0
static void inline
get_rgba_pixel (void       *data,
                int         img_no,
                int         x,
                int         y,
                lua_Number  pixel[4])
{
  Priv *p;
  gfloat buf[4];

  p = data;

  if (img_no == 0)
    {
      gint i;
      if (!p->in_drawable)
        return;
      gegl_buffer_sample (p->in_drawable, x, y, NULL, buf,
                          p->rgba_float,
                          GEGL_SAMPLER_NEAREST, GEGL_ABYSS_NONE);
      for (i = 0; i < 4; i++)
        pixel[i] = buf[i];
    }
  else if (img_no == 1)
    {
      gint i;
      if (!p->aux_drawable)
        return;
      gegl_buffer_sample (p->aux_drawable, x, y, NULL, buf,
                          p->rgba_float,
                          GEGL_SAMPLER_NEAREST, GEGL_ABYSS_NONE);
      for (i = 0; i < 4; i++)
        pixel[i] = buf[i];
    }
}
Exemple #2
0
/* Apply the actual transform */
static void
apply_spread (gint                 x_amount,
              gint                 y_amount,
              gint                 img_width,
              gint                 img_height,
              const Babl          *format,
              GeglBuffer          *src,
              GeglBuffer          *dst,
              const GeglRectangle *roi)
{
  gfloat *dst_buf;
  gint x1, y1; // Noise image
  gdouble x, y;   // Source Image

  GRand    *gr = g_rand_new ();

  /* Get buffer in which to place dst pixels. */
  dst_buf = g_new0 (gfloat, roi->width * roi->height * 4);

  for (y1 = 0; y1 < roi->height; y1++) {
    for (x1 = 0; x1 < roi->width; x1++) {

      calc_sample_coords (x1, y1, x_amount, y_amount, gr, &x, &y);
      /* Only displace the pixel if it's within the bounds of the image. */
      if (x >= 0 && x < img_width && y >= 0 && y < img_height)
        gegl_buffer_sample (src, x, y, NULL, &dst_buf[(y1 * roi->width + x1) * 4], format,
                            GEGL_SAMPLER_LINEAR, GEGL_ABYSS_NONE);
      else /* Else just copy it */
        gegl_buffer_sample (src, x1, y1, NULL, &dst_buf[(y1 * roi->width + x1) * 4], format,
                            GEGL_SAMPLER_LINEAR, GEGL_ABYSS_NONE);
    } /* for */
  } /* for */

  gegl_buffer_sample_cleanup (src);

  /* Store dst pixels. */
  gegl_buffer_set (dst, roi, 0, format, dst_buf, GEGL_AUTO_ROWSTRIDE);

  gegl_buffer_flush(dst);

  g_free (dst_buf);
  g_rand_free (gr);
}
Exemple #3
0
static void
apply_whirl_pinch (gdouble whirl, gdouble pinch, gdouble radius,
                   gdouble cen_x, gdouble cen_y,
                   Babl    *format,
                   GeglBuffer *src,
                   GeglRectangle *in_boundary,
                   GeglBuffer *dst,
                   GeglRectangle *boundary,
                   const GeglRectangle *roi)
{
  gfloat *dst_buf;
  gint row, col;
  gdouble scale_x, scale_y;
  gdouble cx, cy;

  /* Get buffer in which to place dst pixels. */
  dst_buf = g_new0 (gfloat, roi->width * roi->height * 4);

  whirl = whirl * G_PI / 180;

  scale_x = 1.0;
  scale_y = roi->width / (gdouble) roi->height;

  for (row = 0; row < roi->height; row++) {
    for (col = 0; col < roi->width; col++) {

        calc_undistorted_coords (roi->x + col, roi->y + row,
                                 cen_x, cen_y,
                                 scale_x, scale_y,
                                 whirl, pinch, radius,
                                 &cx, &cy);

        gegl_buffer_sample (src, cx, cy, 1.0, &dst_buf[(row * roi->width + col) * 4], format,  GEGL_INTERPOLATION_LINEAR);
    } /* for */
  } /* for */

  gegl_buffer_sample_cleanup (src);

  /* Store dst pixels. */
  gegl_buffer_set (dst, roi, format, dst_buf, GEGL_AUTO_ROWSTRIDE);

  gegl_buffer_flush(dst);

  g_free (dst_buf);

}
guchar
sel_pixel_value (gint row,
                 gint col)
{
  guchar ret;

  if (col > sel_width || row > sel_height)
    {
      g_warning ("sel_pixel_value [%d,%d] out of bounds", col, row);
      return 0;
    }

  gegl_buffer_sample (sel_buffer, col + sel_x1, row + sel_y1, NULL,
                      &ret, babl_format ("Y u8"),
                      GEGL_SAMPLER_NEAREST, GEGL_ABYSS_NONE);

  return ret;
}
static GimpVector2
gimp_cage_transform_compute_destination (GimpCageConfig *config,
                                         gfloat         *coef,
                                         Babl           *format_coef,
                                         GeglBuffer     *coef_buf,
                                         GimpVector2     coords)
{
  gdouble        pos_x, pos_y;
  GimpVector2    result;
  gint           cvn = config->n_cage_vertices;
  gint           i;

  /* When Gegl bug #645810 will be solved, this should be a good optimisation */
  #ifdef GEGL_BUG_645810_SOLVED
    gegl_buffer_sample (coef_buf, coords.x, coords.y, 1.0, coef, format_coef, GEGL_INTERPOLATION_LANCZOS);
  #else
    GeglRectangle  rect;

    rect.height = 1;
    rect.width  = 1;
    rect.x      = coords.x;
    rect.y      = coords.y;

    gegl_buffer_get (coef_buf, 1, &rect, format_coef, coef, GEGL_AUTO_ROWSTRIDE);
  #endif

  pos_x = 0;
  pos_y = 0;

  for (i = 0; i < cvn; i++)
    {
      pos_x += coef[i] * config->cage_points[i].dest_point.x;
      pos_y += coef[i] * config->cage_points[i].dest_point.y;

      pos_x += coef[i + cvn] * config->cage_points[i].edge_scaling_factor * config->cage_points[i].edge_normal.x;
      pos_y += coef[i + cvn] * config->cage_points[i].edge_scaling_factor * config->cage_points[i].edge_normal.y;
    }

  result.x = pos_x;
  result.y = pos_y;

  return result;
}
Exemple #6
0
static gboolean
gimp_projection_get_pixel_at (GimpPickable *pickable,
                              gint          x,
                              gint          y,
                              const Babl   *format,
                              gpointer      pixel)
{
  GeglBuffer *buffer = gimp_projection_get_buffer (pickable);

  if (x <  0                               ||
      y <  0                               ||
      x >= gegl_buffer_get_width  (buffer) ||
      y >= gegl_buffer_get_height (buffer))
    return FALSE;

  gegl_buffer_sample (buffer, x, y, NULL, pixel, format,
                      GEGL_SAMPLER_NEAREST, GEGL_ABYSS_NONE);

  return TRUE;
}
static GimpVector2
gimp_cage_transform_compute_destination (GimpCageConfig *config,
                                         gfloat         *coef,
                                         const Babl     *format_coef,
                                         GeglBuffer     *coef_buf,
                                         GimpVector2     coords)
{
  GimpVector2    result = {0, 0};
  gint           n_cage_vertices = gimp_cage_config_get_n_points (config);
  gint           i;
  GimpCagePoint *point;

  /* When Gegl bug #645810 will be solved, this should be a good optimisation */
  #ifdef GEGL_BUG_645810_SOLVED
    gegl_buffer_sample (coef_buf, coords.x, coords.y, 1.0, coef, format_coef, GEGL_INTERPOLATION_NEAREST);
  #else
    GeglRectangle  rect;

    rect.height = 1;
    rect.width  = 1;
    rect.x      = coords.x;
    rect.y      = coords.y;

    gegl_buffer_get (coef_buf, &rect, 1.0, format_coef, coef,
                     GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE);
  #endif

  for (i = 0; i < n_cage_vertices; i++)
    {
      point = &g_array_index (config->cage_points, GimpCagePoint, i);

      result.x += coef[i] * point->dest_point.x;
      result.y += coef[i] * point->dest_point.y;

      result.x += coef[i + n_cage_vertices] * point->edge_scaling_factor * point->edge_normal.x;
      result.y += coef[i + n_cage_vertices] * point->edge_scaling_factor * point->edge_normal.y;
    }

  return result;
}
Exemple #8
0
static gboolean
do_plasma (PlasmaContext *context,
           gint           x1,
           gint           y1,
           gint           x2,
           gint           y2,
           gint           plasma_depth,
           gint           recursion_depth)
{
  gfloat tl[3], ml[3], bl[3], mt[3], mm[3], mb[3], tr[3], mr[3], br[3];
  gfloat tmp[3];
  gint    xm, ym;
  gfloat  ran;

  if (G_UNLIKELY ((!context->using_buffer) &&
                  ((x2 - x1 + 1) <= TILE_SIZE) &&
                  ((y2 - y1 + 1) <= TILE_SIZE)))
    {
      gboolean ret;
      GeglRectangle rect;

      rect.x = x1;
      rect.y = y1;
      rect.width = x2 - x1 + 1;
      rect.height = y2 - y1 + 1;

      gegl_buffer_get (context->output, &rect, 1.0, babl_format ("R'G'B' float"),
                       context->buffer, GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE);

      context->using_buffer = TRUE;
      context->buffer_x = x1;
      context->buffer_y = y1;
      context->buffer_width = x2 - x1 + 1;

      ret = do_plasma (context, x1, y1, x2, y2, plasma_depth, recursion_depth);

      context->using_buffer = FALSE;

      gegl_buffer_set (context->output, &rect, 0, babl_format ("R'G'B' float"),
                       context->buffer, GEGL_AUTO_ROWSTRIDE);

      return ret;
    }

  xm = (x1 + x2) / 2;
  ym = (y1 + y2) / 2;

  if (plasma_depth == -1)
    {
      random_rgba (context->gr, tl);
      put_pixel (context, tl, x1, y1);

      random_rgba (context->gr, tr);
      put_pixel (context, tr, x2, y1);

      random_rgba (context->gr, bl);
      put_pixel (context, bl, x1, y2);

      random_rgba (context->gr, br);
      put_pixel (context, br, x2, y2);

      random_rgba (context->gr, mm);
      put_pixel (context, mm, xm, ym);

      random_rgba (context->gr, ml);
      put_pixel (context, ml, x1, ym);

      random_rgba (context->gr, mr);
      put_pixel (context, mr, x2, ym);

      random_rgba (context->gr, mt);
      put_pixel (context, mt, xm, y1);

      random_rgba (context->gr, mb);
      put_pixel (context, mb, xm, y2);

      return FALSE;
    }

  if (!plasma_depth)
    {
      if (x1 == x2 && y1 == y2)
        return FALSE;

      gegl_buffer_sample (context->output, x1, y1, NULL, tl,
                          babl_format ("R'G'B' float"),
                          GEGL_SAMPLER_NEAREST, GEGL_ABYSS_NONE);
      gegl_buffer_sample (context->output, x1, y2, NULL, bl,
                          babl_format ("R'G'B' float"),
                          GEGL_SAMPLER_NEAREST, GEGL_ABYSS_NONE);
      gegl_buffer_sample (context->output, x2, y1, NULL, tr,
                          babl_format ("R'G'B' float"),
                          GEGL_SAMPLER_NEAREST, GEGL_ABYSS_NONE);
      gegl_buffer_sample (context->output, x2, y2, NULL, br,
                          babl_format ("R'G'B' float"),
                          GEGL_SAMPLER_NEAREST, GEGL_ABYSS_NONE);

      ran = context->o->turbulence / (2.0 * recursion_depth);

      if (xm != x1 || xm != x2)
        {
          /* Left. */
          average_pixel (ml, tl, bl);
          add_random (context->gr, ml, ran);
          put_pixel (context, ml, x1, ym);

          /* Right. */
          if (x1 != x2)
            {
              average_pixel (mr, tr, br);
              add_random (context->gr, mr, ran);
              put_pixel (context, mr, x2, ym);
            }
        }


      if (ym != y1 || ym != x2)
        {
          /* Bottom. */
          if (x1 != xm || ym != y2)
            {
              average_pixel (mb, bl, br);
              add_random (context->gr, mb, ran);
              put_pixel (context, mb, xm, y2);
            }

          if (y1 != y2)
            {
              /* Top. */
              average_pixel (mt, tl, tr);
              add_random (context->gr, mt, ran);
              put_pixel (context, mt, xm, y1);
            }
        }

      if (y1 != y2 || x1 != x2)
        {
          /* Middle pixel. */
          average_pixel (mm, tl, br);
          average_pixel (tmp, bl, tr);
          average_pixel (mm, mm, tmp);

          add_random (context->gr, mm, ran);
          put_pixel (context, mm, xm, ym);
        }

      return x2 - x1 < 3 && y2 - y1 < 3;
    }

  if (x1 < x2 || y1 < y2)
    {
      /* Top left. */
      do_plasma (context, x1, y1, xm, ym, plasma_depth - 1, recursion_depth + 1);
      /* Bottom left. */
      do_plasma (context, x1, ym, xm, y2, plasma_depth - 1, recursion_depth + 1);
      /* Top right. */
      do_plasma (context, xm, y1, x2, ym, plasma_depth - 1, recursion_depth + 1);
      /* Bottom right. */
      return do_plasma (context, xm, ym, x2, y2,
                        plasma_depth - 1, recursion_depth + 1);
    }

  return TRUE;
}
static gboolean
find_contiguous_segment (const gfloat        *col,
                         GeglBuffer          *src_buffer,
                         GeglBuffer          *mask_buffer,
                         const Babl          *format,
                         gint                 n_components,
                         gboolean             has_alpha,
                         gint                 width,
                         gboolean             select_transparent,
                         GimpSelectCriterion  select_criterion,
                         gboolean             antialias,
                         gfloat               threshold,
                         gint                 initial_x,
                         gint                 initial_y,
                         gint                *start,
                         gint                *end,
                         gfloat              *row)
{
  gfloat *s;
  gfloat  mask_row[width];
  gfloat  diff;

#ifdef FETCH_ROW
  gegl_buffer_get (src_buffer, GEGL_RECTANGLE (0, initial_y, width, 1), 1.0,
                   format,
                   row, GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE);
  s = row + initial_x * n_components;
#else
  s = g_alloca (n_components * sizeof (gfloat));

  gegl_buffer_sample (src_buffer, initial_x, initial_y, NULL, s, format,
                      GEGL_SAMPLER_NEAREST, GEGL_ABYSS_NONE);
#endif

  diff = pixel_difference (col, s, antialias, threshold,
                           n_components, has_alpha, select_transparent,
                           select_criterion);

  /* check the starting pixel */
  if (! diff)
    return FALSE;

  mask_row[initial_x] = diff;

  *start = initial_x - 1;
#ifdef FETCH_ROW
  s = row + *start * n_components;
#endif

  while (*start >= 0 && diff)
    {
#ifndef FETCH_ROW
      gegl_buffer_sample (src_buffer, *start, initial_y, NULL, s, format,
                          GEGL_SAMPLER_NEAREST, GEGL_ABYSS_NONE);
#endif

      diff = pixel_difference (col, s, antialias, threshold,
                               n_components, has_alpha, select_transparent,
                               select_criterion);

      mask_row[*start] = diff;

      if (diff)
        {
          (*start)--;
#ifdef FETCH_ROW
          s -= n_components;
#endif
        }
    }

  diff = 1;
  *end = initial_x + 1;
#ifdef FETCH_ROW
  s = row + *end * n_components;
#endif

  while (*end < width && diff)
    {
#ifndef FETCH_ROW
      gegl_buffer_sample (src_buffer, *end, initial_y, NULL, s, format,
                          GEGL_SAMPLER_NEAREST, GEGL_ABYSS_NONE);
#endif

      diff = pixel_difference (col, s, antialias, threshold,
                               n_components, has_alpha, select_transparent,
                               select_criterion);

      mask_row[*end] = diff;

      if (diff)
        {
          (*end)++;
#ifdef FETCH_ROW
          s += n_components;
#endif
        }
    }

  gegl_buffer_set (mask_buffer, GEGL_RECTANGLE (*start, initial_y,
                                                *end - *start, 1),
                   0, babl_format ("Y float"), &mask_row[*start],
                   GEGL_AUTO_ROWSTRIDE);

  return TRUE;
}
/**
 * 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;
}
static void
convolve_pixel(gfloat               *src_buf,
               gfloat               *dst_buf,
               const GeglRectangle  *result,
               const GeglRectangle  *extended,
               const GeglRectangle  *boundary,
               gdouble             **matrix,
               GeglChantO           *o,
               GeglBuffer           *input,
               gint                  xx,
               gint                  yy,
               gdouble               matrixsum)
{
  gint    i, x, y, temp, s_x, s_y;
  gdouble sum;
  gfloat  color[4];
  gint    d_offset, s_offset;
  gint    half;

  gdouble alphasum  = 0.0;

  s_x = 0;
  s_y = 0;

  half = (MATRIX_SIZE / 2) + (MATRIX_SIZE % 2);

  d_offset = ((yy - result->y)*result->width * 4) + (xx - result->x) * 4;
  s_offset = (yy - result->y + HALF_WINDOW) * extended->width * 4 +
    (xx - result->x + HALF_WINDOW) * 4;

  for (i=0; i < 4; i++)
    {
      sum  = 0.0;
      if ((i==0 && o->red) || (i==1 && o->blue) || (i==2 && o->green)
          || (i==3 && o->alpha))
        {
          for (x=0;x < MATRIX_SIZE; x++)
            for (y=0; y < MATRIX_SIZE; y++)
              {
                if (!strcmp(o->border,"wrap"))
                  {
                    s_x = fmod (x+xx, boundary->width);
                    while (s_x < 0)
                      s_x +=boundary->width;

                    s_y = fmod (y+yy, boundary->height);
                    while (s_y < 0)
                      s_y +=boundary->width;
                  }
                else if (!strcmp(o->border,"extend"))
                  {
                    s_x = CLAMP (x+xx, 0, boundary->width);
                    s_y = CLAMP (y+yy, 0, boundary->height);
                  }
                temp = (s_y - extended->y) * extended->width * 4 +
                  (s_x - extended->x) * 4;

                if ((s_x >= extended->x && (s_x < extended->x + extended->width))
                    && (s_y >=extended->y && (s_y < extended->y + extended->height)))
                  {
                    if (i!=3 && o->weight)
                      sum += matrix[x][y] * src_buf[temp + i]
                        * src_buf[temp + 3];
                    else
                      sum += matrix[x][y] * src_buf[temp + i];

                    if (i==3)
                      alphasum += fabs (matrix[x][y] * src_buf[temp+i]);
                  }
                else
                  {
                    gfloat temp_color[4];
                    gegl_buffer_sample (input, s_x, s_y, NULL, temp_color,
                                        babl_format ("RGBA float"),
                                        GEGL_SAMPLER_NEAREST,
                                        GEGL_ABYSS_NONE);
                    if (i!=3 && o->weight)
                      sum += matrix[x][y] * temp_color[i]
                        * temp_color[3];
                    else
                      sum += matrix[x][y] * temp_color[i];

                    if (i==3)
                      alphasum += fabs (matrix[x][y] * temp_color[i]);
                  }
              }
          sum = sum / o->div;

          if (i==3 && o->weight)
            {
              if (alphasum != 0)
                sum = sum * matrixsum / alphasum;
              else sum = 0.0;
            }
          sum += o->off;

          color[i] = sum;
        }
      else
        color[i] = src_buf[s_offset + i];
    }

  for (i=0; i < 4; i++)
    dst_buf[d_offset + i] = color[i];
}
Exemple #12
0
static void
lens_distort_func (gfloat              *src_buf,
                   gfloat              *dst_buf,
                   const GeglRectangle *extended,
                   const GeglRectangle *result,
                   const GeglRectangle *boundary,
                   LensValues          *lens,
                   gint                 xx,
                   gint                 yy,
                   GeglBuffer          *input,
                   gfloat              *background)
{
  gdouble sx, sy, mag;
  gdouble brighten;
  gfloat  pixel_buffer [16 * 4], temp[4];
  gdouble dx, dy;
  gint    x_int, y_int, x = 0, y = 0, offset = 0;

  temp[0] = temp[1] = temp[2] = temp[3] = 0.0;

  lens_get_source_coord ((gdouble) xx, (gdouble) yy, &sx, &sy, &mag, lens);

  /* pseudo gamma transformation, since the input is scRGB */
  brighten = pow (MAX (1.0 + mag * lens->brighten, 0.0), 2.4);

  x_int = floor (sx);
  dx = sx - x_int;

  y_int = floor (sy);
  dy = sy - y_int;

  for (y = y_int - 1; y <= y_int + 2; y++)
    {
      for (x = x_int - 1; x <= x_int + 2; x++)
        {
          gint b;

          if (x < boundary->x || x >= (boundary->x + boundary->width) ||
              y < boundary->y || y >= (boundary->y + boundary->height))
            {
              for (b = 0; b < 4; b++)
                pixel_buffer[offset++] = background[b];
            }
          else
            {

              if (x >= extended->x && x < (extended->x + extended->width) &&
                  y >= extended->y && y < (extended->y + extended->height))
                {
                  gint src_off;
                  src_off = (y - extended->y) * extended->width * 4 +
                    (x - extended->x) * 4;

                  for (b = 0; b < 4; b++)
                    temp[b] = src_buf[src_off++];
                }
              else
                {
                  gegl_buffer_sample (input, x, y, NULL, temp,
                                      babl_format ("RGBA float"),
                                      GEGL_SAMPLER_LINEAR,
                                      GEGL_ABYSS_CLAMP);
                }

              for (b = 0; b < 4; b++)
                pixel_buffer[offset++] = temp[b];
            }
        }
    }

  lens_cubic_interpolate (pixel_buffer, temp, dx, dy, brighten);

  offset = (yy - result->y) * result->width * 4 + (xx - result->x) * 4;

  for (x = 0; x < 4; x++)
    dst_buf[offset++] = temp[x];
}
/**
 * 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;
}
Exemple #14
0
static void
fractaltrace (GeglBuffer            *input,
              const GeglRectangle   *picture,
              gfloat                *dst_buf,
              const GeglRectangle   *roi,
              GeglChantO            *o,
              gint                   y,
              GeglFractalTraceType  fractal_type,
              const Babl           *format)
{
  GeglMatrix2  scale;        /* a matrix indicating scaling factors around the
                                current center pixel.
                              */
  gint         x, i, offset;
  gdouble      scale_x, scale_y;
  gdouble      bailout2;
  gfloat       dest[4];

  scale_x = (o->X2 - o->X1) / picture->width;
  scale_y = (o->Y2 - o->Y1) / picture->height;

  bailout2 = o->bailout * o->bailout;

  offset = (y - roi->y) * roi->width * 4;

  for (x = roi->x; x < roi->x + roi->width; x++)
    {
      gdouble cx, cy;
      gdouble px, py;
      dest[1] = dest[2] = dest[3] = dest[0] = 0.0;

      switch (fractal_type)
        {
        case GEGL_FRACTAL_TRACE_TYPE_JULIA:
#define gegl_unmap(u,v,ud,vd) {                                         \
            gdouble rx, ry;                                             \
            cx = o->X1 + ((u) - picture->x) * scale_x;                  \
            cy = o->Y1 + ((v) - picture->y) * scale_y;                  \
            julia (cx, cy, o->JX, o->JY, &rx, &ry, o->depth, bailout2); \
            ud = (rx - o->X1) / scale_x + picture->x;                   \
            vd = (ry - o->Y1) / scale_y + picture->y;                   \
          }
        gegl_sampler_compute_scale (scale, x, y);
        gegl_unmap(x,y,px,py);
#undef gegl_unmap
        break;

        case GEGL_FRACTAL_TRACE_TYPE_MANDELBROT:
#define gegl_unmap(u,v,ud,vd) {                                     \
            gdouble rx, ry;                                         \
            cx = o->X1 + ((u) - picture->x) * scale_x;              \
            cy = o->Y1 + ((v) - picture->y) * scale_y;              \
            julia (cx, cy, cx, cy, &rx, &ry, o->depth, bailout2);   \
            ud = (rx - o->X1) / scale_x + picture->x;               \
            vd = (ry - o->Y1) / scale_y + picture->y;               \
          }
        gegl_sampler_compute_scale (scale, x, y);
        gegl_unmap(x,y,px,py);
#undef gegl_unmap
        break;

        default:
          g_error (_("Unsupported fractal type"));
        }

      gegl_buffer_sample (input, px, py, &scale, dest, format,
                          GEGL_SAMPLER_NOHALO, o->abyss_policy);

      for (i = 0; i < 4; i++)
        dst_buf[offset++] = dest[i];
    }
}
Exemple #15
0
static void
lens_distort_func (gfloat              *src_buf,
                   gfloat              *dst_buf,
                   const GeglRectangle *extended,
                   const GeglRectangle *result,
                   const GeglRectangle *boundary,
                   LensDistortion       old,
                   gint                 xx,
                   gint                 yy,
                   GeglBuffer          *input)
{
  gdouble sx, sy, mag;
  gdouble brighten;
  gfloat  pixel_buffer [16 * 4], temp[4];
  gdouble dx, dy;
  gint    x_int, y_int, x = 0, y = 0, offset = 0;

  temp[0] = temp[1] = temp[2] = temp[3] = 0.0;

  lens_get_source_coord ((gdouble)xx, (gdouble)yy, &sx, &sy, &mag, &old);

  brighten = 1.0 + mag * old.brighten;

  x_int = floor (sx);
  dx = sx - x_int;

  y_int = floor (sy);
  dy = sy - y_int;

  for (y = y_int - 1; y <= y_int + 2; y++)
    {
      for (x = x_int - 1; x <= x_int + 2; x++)
        {
          gint b;

          if (x >= extended->x && x<(extended->x + extended->width)
              && y >= extended->y && y < (extended->y + extended->height))
            {
              gint src_off;
              src_off = (y - extended->y) * extended->width * 4 +
                (x - extended->x) * 4;
              for (b=0; b<4; b++)
                temp[b] = src_buf[src_off++];

            }
          else if (x >= boundary->x && x < boundary->x + boundary->width &&
                   y >= boundary->y && y < boundary->y + boundary->height)
            {
              gegl_buffer_sample (input, x, y, NULL, temp,
                                  babl_format ("RGBA float"),
                                  GEGL_SAMPLER_CUBIC,
                                  GEGL_ABYSS_NONE);
            }
          else
            {
              for (b=0; b<4; b++)
                temp[b] = 0.0;
            }

          for (b=0; b<4; b++)
            pixel_buffer[offset++] = temp[b];
        }
    }

  lens_cubic_interpolate (pixel_buffer, temp, dx, dy, brighten);

  offset = (yy - result->y) * result->width * 4 + (xx - result->x) * 4;
  for (x=0; x<4; x++)
    dst_buf[offset++] = temp[x];
}
Exemple #16
0
static gboolean
save_image (const gchar  *filename,
            GeglBuffer   *buffer,
            GError      **error)
{
  const Babl *format = babl_format ("R'G'B'A u8");
  gint        row, col, cols, rows, x, y;
  gint        colcount, colspan, rowspan;
  gint       *palloc;
  guchar     *buf, *buf2;
  gchar      *width, *height;
  FILE       *fp;

  cols = gegl_buffer_get_width  (buffer);
  rows = gegl_buffer_get_height (buffer);

  fp = g_fopen (filename, "w");

  if (! fp)
    {
      g_set_error (error, G_FILE_ERROR, g_file_error_from_errno (errno),
                   _("Could not open '%s' for writing: %s"),
                   gimp_filename_to_utf8 (filename), g_strerror (errno));
      return FALSE;
    }

  palloc = g_new (int, rows * cols);

  if (gtmvals.fulldoc)
    {
      fprintf (fp, "<HTML>\n<HEAD><TITLE>%s</TITLE></HEAD>\n<BODY>\n",
               filename);
      fprintf (fp, "<H1>%s</H1>\n",
               filename);
    }

  fprintf (fp, "<TABLE BORDER=%d CELLPADDING=%d CELLSPACING=%d>\n",
           gtmvals.border, gtmvals.cellpadding, gtmvals.cellspacing);

  if (gtmvals.caption)
    fprintf (fp, "<CAPTION>%s</CAPTION>\n",
             gtmvals.captiontxt);

  gimp_progress_init_printf (_("Saving '%s'"),
                             gimp_filename_to_utf8 (filename));

  buf  = g_new (guchar, babl_format_get_bytes_per_pixel (format));
  buf2 = g_new (guchar, babl_format_get_bytes_per_pixel (format));

  width = height = NULL;

  if (strcmp (gtmvals.clwidth, "") != 0)
    {
      width = g_strdup_printf (" WIDTH=\"%s\"", gtmvals.clwidth);
    }

  if (strcmp (gtmvals.clheight, "") != 0)
    {
      height = g_strdup_printf (" HEIGHT=\"%s\" ", gtmvals.clheight);
    }

  if (! width)
    width = g_strdup (" ");

  if (! height)
    height = g_strdup (" ");

  /* Initialize array to hold ROWSPAN and COLSPAN cell allocation table */

  for (row = 0; row < rows; row++)
    for (col = 0; col < cols; col++)
      palloc[cols * row + col] = 1;

  colspan = 0;
  rowspan = 0;

  for (y = 0; y < rows; y++)
    {
      fprintf (fp,"   <TR>\n");

      for (x = 0; x < cols; x++)
        {
          gegl_buffer_sample (buffer, x, y, NULL, buf, format,
                              GEGL_SAMPLER_NEAREST, GEGL_ABYSS_NONE);

          /* Determine ROWSPAN and COLSPAN */

          if (gtmvals.spantags)
            {
              col      = x;
              row      = y;
              colcount = 0;
              colspan  = 0;
              rowspan  = 0;

              gegl_buffer_sample (buffer, col, row, NULL, buf2, format,
                                  GEGL_SAMPLER_NEAREST, GEGL_ABYSS_NONE);

              while (color_comp (buf, buf2) &&
                     palloc[cols * row + col] == 1 &&
                     row < rows)
                {
                  while (color_comp (buf, buf2) &&
                         palloc[cols * row + col] == 1 &&
                         col < cols)
                    {
                      colcount++;
                      col++;

                      gegl_buffer_sample (buffer, col, row, NULL, buf2, format,
                                          GEGL_SAMPLER_NEAREST, GEGL_ABYSS_NONE);
                    }

                  if (colcount != 0)
                    {
                      row++;
                      rowspan++;
                    }

                  if (colcount < colspan || colspan == 0)
                    colspan = colcount;

                  col = x;
                  colcount = 0;

                  gegl_buffer_sample (buffer, col, row, NULL, buf2, format,
                                      GEGL_SAMPLER_NEAREST, GEGL_ABYSS_NONE);
                }

              if (colspan > 1 || rowspan > 1)
                {
                  for (row = 0; row < rowspan; row++)
                    for (col = 0; col < colspan; col++)
                      palloc[cols * (row + y) + (col + x)] = 0;

                  palloc[cols * y + x] = 2;
                }
            }

          if (palloc[cols * y + x] == 1)
            fprintf (fp, "      <TD%s%sBGCOLOR=#%02x%02x%02x>",
                     width, height, buf[0], buf[1], buf[2]);

          if (palloc[cols * y + x] == 2)
            fprintf (fp,"      <TD ROWSPAN=\"%d\" COLSPAN=\"%d\"%s%sBGCOLOR=#%02x%02x%02x>",
                     rowspan, colspan, width, height,
                     buf[0], buf[1], buf[2]);

          if (palloc[cols * y + x] != 0)
            {
              if (gtmvals.tdcomp)
                fprintf (fp, "%s</TD>\n", gtmvals.cellcontent);
              else
                fprintf (fp, "\n      %s\n      </TD>\n", gtmvals.cellcontent);
            }
        }

      fprintf (fp,"   </TR>\n");

      gimp_progress_update ((double) y / (double) rows);
    }

  gimp_progress_update (1.0);

  if (gtmvals.fulldoc)
    fprintf (fp, "</TABLE></BODY></HTML>\n");
  else
    fprintf (fp, "</TABLE>\n");

  fclose (fp);
  g_free (width);
  g_free (height);
  g_free (palloc);

  return TRUE;
}
Exemple #17
0
static gboolean
process (GeglOperation       *operation,
         GeglBuffer          *input,
         GeglBuffer          *output,
         const GeglRectangle *result,
         gint                 level)
{
  GeglChantO              *o            = GEGL_CHANT_PROPERTIES (operation);
  GeglOperationAreaFilter *op_area      = GEGL_OPERATION_AREA_FILTER (operation);
  GeglRectangle            boundary     = get_effective_area (operation);
  GeglRectangle            extended;
  const Babl              *format       = babl_format ("RGBA float");

  GRand  *gr = g_rand_new_with_seed (o->seed);
  gfloat  color[4];
  gint    cols, rows, num_tiles, count;
  gint   *random_indices;
  gfloat *dst_buf;

  Polygon poly;
  gint    i;

  extended.x      = CLAMP (result->x - op_area->left, boundary.x, boundary.x +
                           boundary.width);
  extended.width  = CLAMP (result->width + op_area->left + op_area->right, 0,
                           boundary.width);
  extended.y      = CLAMP (result->y - op_area->top, boundary.y, boundary.y +
                           boundary.width);
  extended.height = CLAMP (result->height + op_area->top + op_area->bottom, 0,
                           boundary.height);

  dst_buf = g_new0 (gfloat, extended.width * extended.height * 4);

  cols = (result->width + o->tile_size - 1) / o->tile_size;
  rows = (result->height + o->tile_size - 1) / o->tile_size;

  num_tiles = (rows + 1) * (cols + 1);

  random_indices = g_new0 (gint, num_tiles);

  for (i = 0; i < num_tiles; i++)
    random_indices[i] = i;

  randomize_indices (num_tiles, random_indices, gr);

  for (count = 0; count < num_tiles; count++)
    {
      gint i, j, ix, iy;
      gdouble x, y, width, height, theta;

      i = random_indices[count] / (cols + 1);
      j = random_indices[count] % (cols + 1);

      x = j * o->tile_size + (o->tile_size / 4.0)
        - g_rand_double_range (gr, 0, (o->tile_size /2.0)) + result->x;

      y = i * o->tile_size + (o->tile_size / 4.0)
        - g_rand_double_range (gr, 0, (o->tile_size /2.0)) + result->y;

      width  = (o->tile_size +
                g_rand_double_range (gr, -o->tile_size / 8.0, o->tile_size / 8.0))
        * o->tile_saturation;

      height = (o->tile_size +
                g_rand_double_range (gr, -o->tile_size / 8.0, o->tile_size / 8.0))
        * o->tile_saturation;

      theta = g_rand_double_range (gr, 0, 2 * G_PI);

      polygon_reset (&poly);
      polygon_add_point (&poly, -width / 2.0, -height / 2.0);
      polygon_add_point (&poly,  width / 2.0,  -height / 2.0);
      polygon_add_point (&poly,  width / 2.0,   height / 2.0);
      polygon_add_point (&poly, -width / 2.0,  height / 2.0);
      polygon_rotate (&poly, theta);
      polygon_translate (&poly, x, y);

      ix = CLAMP (x, boundary.x, boundary.x + boundary.width - 1);
      iy = CLAMP (y, boundary.y, boundary.y + boundary.height - 1);

      gegl_buffer_sample (input, ix, iy, NULL, color, format,
                          GEGL_SAMPLER_NEAREST, GEGL_ABYSS_NONE);

      fill_poly_color (&poly, &extended, &boundary, dst_buf, color);
    }

  gegl_buffer_set (output, &extended, 0, format, dst_buf, GEGL_AUTO_ROWSTRIDE);

  g_free (dst_buf);
  g_free (random_indices);
  g_free (gr);

  return TRUE;
}
GeglBuffer *
gimp_pickable_contiguous_region_by_seed (GimpPickable        *pickable,
                                         gboolean             antialias,
                                         gfloat               threshold,
                                         gboolean             select_transparent,
                                         GimpSelectCriterion  select_criterion,
                                         gboolean             diagonal_neighbors,
                                         gint                 x,
                                         gint                 y)
{
  GeglBuffer    *src_buffer;
  GeglBuffer    *mask_buffer;
  const Babl    *format;
  GeglRectangle  extent;
  gint           n_components;
  gboolean       has_alpha;
  gfloat         start_col[MAX_CHANNELS];

  g_return_val_if_fail (GIMP_IS_PICKABLE (pickable), NULL);

  gimp_pickable_flush (pickable);

  src_buffer = gimp_pickable_get_buffer (pickable);

  format = choose_format (src_buffer, select_criterion,
                          &n_components, &has_alpha);

  gegl_buffer_sample (src_buffer, x, y, NULL, start_col, format,
                      GEGL_SAMPLER_NEAREST, GEGL_ABYSS_NONE);

  if (has_alpha)
    {
      if (select_transparent)
        {
          /*  don't select transparent regions if the start pixel isn't
           *  fully transparent
           */
          if (start_col[n_components - 1] > 0)
            select_transparent = FALSE;
        }
    }
  else
    {
      select_transparent = FALSE;
    }

  extent = *gegl_buffer_get_extent (src_buffer);

  mask_buffer = gegl_buffer_new (&extent, babl_format ("Y float"));

  if (x >= extent.x && x < (extent.x + extent.width) &&
      y >= extent.y && y < (extent.y + extent.height))
    {
      GIMP_TIMER_START();

      find_contiguous_region (src_buffer, mask_buffer,
                              format, n_components, has_alpha,
                              select_transparent, select_criterion,
                              antialias, threshold, diagonal_neighbors,
                              x, y, start_col);

      GIMP_TIMER_END("foo");
    }

  return mask_buffer;
}
GeglBuffer *
gimp_image_contiguous_region_by_seed (GimpImage           *image,
                                      GimpDrawable        *drawable,
                                      gboolean             sample_merged,
                                      gboolean             antialias,
                                      gfloat               threshold,
                                      gboolean             select_transparent,
                                      GimpSelectCriterion  select_criterion,
                                      gint                 x,
                                      gint                 y)
{
  GimpPickable *pickable;
  GeglBuffer   *src_buffer;
  GeglBuffer   *mask_buffer;
  const Babl   *format;
  gint          n_components;
  gboolean      has_alpha;
  gfloat        start_col[MAX_CHANNELS];

  g_return_val_if_fail (GIMP_IS_IMAGE (image), NULL);
  g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), NULL);

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

  gimp_pickable_flush (pickable);

  src_buffer = gimp_pickable_get_buffer (pickable);

  format = choose_format (src_buffer, select_criterion,
                          &n_components, &has_alpha);

  gegl_buffer_sample (src_buffer, x, y, NULL, start_col, format,
                      GEGL_SAMPLER_NEAREST, GEGL_ABYSS_NONE);

  if (has_alpha)
    {
      if (select_transparent)
        {
          /*  don't select transparent regions if the start pixel isn't
           *  fully transparent
           */
          if (start_col[n_components - 1] > 0)
            select_transparent = FALSE;
        }
    }
  else
    {
      select_transparent = FALSE;
    }

  mask_buffer = gegl_buffer_new (gegl_buffer_get_extent (src_buffer),
                                 babl_format ("Y float"));

  find_contiguous_region_helper (src_buffer, mask_buffer,
                                 format, n_components, has_alpha,
                                 select_transparent, select_criterion,
                                 antialias, threshold,
                                 x, y, start_col);

  return mask_buffer;
}
static void
find_contiguous_region_helper (GeglBuffer          *src_buffer,
                               GeglBuffer          *mask_buffer,
                               const Babl          *format,
                               gint                 n_components,
                               gboolean             has_alpha,
                               gboolean             select_transparent,
                               GimpSelectCriterion  select_criterion,
                               gboolean             antialias,
                               gfloat               threshold,
                               gint                 x,
                               gint                 y,
                               const gfloat        *col)
{
  gint    start, end;
  gint    new_start, new_end;
  GQueue *coord_stack;

  coord_stack = g_queue_new ();

  /* To avoid excessive memory allocation (y, start, end) tuples are
   * stored in interleaved format:
   *
   * [y1] [start1] [end1] [y2] [start2] [end2]
   */
  g_queue_push_tail (coord_stack, GINT_TO_POINTER (y));
  g_queue_push_tail (coord_stack, GINT_TO_POINTER (x - 1));
  g_queue_push_tail (coord_stack, GINT_TO_POINTER (x + 1));

  do
    {
      y     = GPOINTER_TO_INT (g_queue_pop_head (coord_stack));
      start = GPOINTER_TO_INT (g_queue_pop_head (coord_stack));
      end   = GPOINTER_TO_INT (g_queue_pop_head (coord_stack));

      for (x = start + 1; x < end; x++)
        {
          gfloat val;

          gegl_buffer_sample (mask_buffer, x, y, NULL, &val,
                              babl_format ("Y float"),
                              GEGL_SAMPLER_NEAREST, GEGL_ABYSS_NONE);
          if (val != 0.0)
            continue;

          if (! find_contiguous_segment (col, src_buffer, mask_buffer,
                                         format,
                                         n_components,
                                         has_alpha,
                                         gegl_buffer_get_width (src_buffer),
                                         select_transparent, select_criterion,
                                         antialias, threshold, x, y,
                                         &new_start, &new_end))
            continue;

          if (y + 1 < gegl_buffer_get_height (src_buffer))
            {
              g_queue_push_tail (coord_stack, GINT_TO_POINTER (y + 1));
              g_queue_push_tail (coord_stack, GINT_TO_POINTER (new_start));
              g_queue_push_tail (coord_stack, GINT_TO_POINTER (new_end));
            }

          if (y - 1 >= 0)
            {
              g_queue_push_tail (coord_stack, GINT_TO_POINTER (y - 1));
              g_queue_push_tail (coord_stack, GINT_TO_POINTER (new_start));
              g_queue_push_tail (coord_stack, GINT_TO_POINTER (new_end));
            }
        }
    }
  while (! g_queue_is_empty (coord_stack));

  g_queue_free (coord_stack);
}
static gboolean
find_contiguous_segment (const gfloat        *col,
                         GeglBuffer          *src_buffer,
                         GeglBuffer          *mask_buffer,
                         const Babl          *format,
                         gint                 n_components,
                         gboolean             has_alpha,
                         gint                 width,
                         gboolean             select_transparent,
                         GimpSelectCriterion  select_criterion,
                         gboolean             antialias,
                         gfloat               threshold,
                         gint                 initial_x,
                         gint                 initial_y,
                         gint                *start,
                         gint                *end)
{
  gfloat s[MAX_CHANNELS];
  gfloat mask_row[width];
  gfloat diff;

  gegl_buffer_sample (src_buffer, initial_x, initial_y, NULL, s, format,
                      GEGL_SAMPLER_NEAREST, GEGL_ABYSS_NONE);

  diff = pixel_difference (col, s, antialias, threshold,
                           n_components, has_alpha, select_transparent,
                           select_criterion);

  /* check the starting pixel */
  if (! diff)
    return FALSE;

  mask_row[initial_x] = diff;

  *start = initial_x - 1;

  while (*start >= 0 && diff)
    {
      gegl_buffer_sample (src_buffer, *start, initial_y, NULL, s, format,
                          GEGL_SAMPLER_NEAREST, GEGL_ABYSS_NONE);

      diff = pixel_difference (col, s, antialias, threshold,
                               n_components, has_alpha, select_transparent,
                               select_criterion);

      mask_row[*start] = diff;

      if (diff)
        (*start)--;
    }

  diff = 1;
  *end = initial_x + 1;

  while (*end < width && diff)
    {
      gegl_buffer_sample (src_buffer, *end, initial_y, NULL, s, format,
                          GEGL_SAMPLER_NEAREST, GEGL_ABYSS_NONE);

      diff = pixel_difference (col, s, antialias, threshold,
                               n_components, has_alpha, select_transparent,
                               select_criterion);

      mask_row[*end] = diff;

      if (diff)
        (*end)++;
    }

  gegl_buffer_set (mask_buffer, GEGL_RECTANGLE (*start, initial_y,
                                                *end - *start, 1),
                   0, babl_format ("Y float"), &mask_row[*start],
                   GEGL_AUTO_ROWSTRIDE);

  return TRUE;
}
Exemple #22
0
static gboolean
process (GeglOperation       *operation,
         GeglBuffer          *input,
         GeglBuffer          *output,
         const GeglRectangle *result,
         gint                 level)
{
  GeglChantO              *o            = GEGL_CHANT_PROPERTIES (operation);
  GeglRectangle            boundary     = get_effective_area (operation);
  const Babl              *format       = babl_format ("RGBA float");

  gint      x,y;
  gfloat   *src_buf, *dst_buf;
  gfloat    dest[4];
  gint      i, offset = 0;
  gboolean  inside;
  gdouble   px, py;

  GeglMatrix2  scale;        /* a matrix indicating scaling factors around the
                                current center pixel.
                             */

  src_buf = g_new0 (gfloat, result->width * result->height * 4);
  dst_buf = g_new0 (gfloat, result->width * result->height * 4);

  gegl_buffer_get (input, result, 1.0, format, src_buf, GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE);

  if (o->middle)
    {
      o->pole_x = boundary.width / 2;
      o->pole_y = boundary.height / 2;
    }

  for (y = result->y; y < result->y + result->height; y++)
    for (x = result->x; x < result->x + result->width; x++)
      {
#define gegl_unmap(u,v,ud,vd) {                                         \
          gdouble rx, ry;                                               \
          inside = calc_undistorted_coords ((gdouble)x, (gdouble)y,     \
                                            &rx, &ry, o, boundary);     \
          ud = rx;                                                      \
          vd = ry;                                                      \
        }
        gegl_sampler_compute_scale (scale, x, y);
        gegl_unmap(x,y,px,py);
#undef gegl_unmap

        if (inside)
          gegl_buffer_sample (input, px, py, &scale, dest, format,
                              GEGL_SAMPLER_NOHALO, GEGL_ABYSS_NONE);
        else
          for (i=0; i<4; i++)
            dest[i] = 0.0;

        for (i=0; i<4; i++)
          dst_buf[offset++] = dest[i];
      }

  gegl_buffer_set (output, result, 0, format, dst_buf, GEGL_AUTO_ROWSTRIDE);

  g_free (src_buf);
  g_free (dst_buf);

  return  TRUE;
}