Пример #1
0
/*
 * blend_pixels patched 8-24-05 to fix bug #163721.  Note that this change
 * causes the function to treat src1 and src2 asymmetrically.  This gives the
 * right behavior for the smudge tool, which is the only user of this function
 * at the time of patching.  If you want to use the function for something
 * else, caveat emptor.
 */
void
gimp_gegl_smudge_blend (GeglBuffer          *top_buffer,
                        const GeglRectangle *top_rect,
                        GeglBuffer          *bottom_buffer,
                        const GeglRectangle *bottom_rect,
                        GeglBuffer          *dest_buffer,
                        const GeglRectangle *dest_rect,
                        gdouble              blend)
{
  GeglBufferIterator *iter;

  iter = gegl_buffer_iterator_new (top_buffer, top_rect, 0,
                                   babl_format ("RGBA float"),
                                   GEGL_BUFFER_READ, GEGL_ABYSS_NONE);

  gegl_buffer_iterator_add (iter, bottom_buffer, bottom_rect, 0,
                            babl_format ("RGBA float"),
                            GEGL_BUFFER_READ, GEGL_ABYSS_NONE);

  gegl_buffer_iterator_add (iter, dest_buffer, dest_rect, 0,
                            babl_format ("RGBA float"),
                            GEGL_BUFFER_WRITE, GEGL_ABYSS_NONE);

  while (gegl_buffer_iterator_next (iter))
    {
      const gfloat *top    = iter->data[0];
      const gfloat *bottom = iter->data[1];
      gfloat       *dest   = iter->data[2];
      gint          count  = iter->length;
      const gfloat  blend1 = 1.0 - blend;
      const gfloat  blend2 = blend;

      while (count--)
        {
          const gfloat a1 = blend1 * bottom[3];
          const gfloat a2 = blend2 * top[3];
          const gfloat a  = a1 + a2;
          gint         b;

          if (a == 0)
            {
              for (b = 0; b < 4; b++)
                dest[b] = 0;
            }
          else
            {
              for (b = 0; b < 3; b++)
                dest[b] =
                  bottom[b] + (bottom[b] * a1 + top[b] * a2 - a * bottom[b]);

              dest[3] = a;
            }

          top    += 4;
          bottom += 4;
          dest   += 4;
        }
    }
}
Пример #2
0
void
mask_components_onto (GeglBuffer        *src_buffer,
                      GeglBuffer        *aux_buffer,
                      GeglBuffer        *dst_buffer,
                      GeglRectangle     *roi,
                      GimpComponentMask  mask,
                      gboolean           linear_mode)
{
  GeglBufferIterator *iter;
  const Babl         *iterator_format;

  if (linear_mode)
    iterator_format = babl_format ("RGBA float");
  else
    iterator_format = babl_format ("R'G'B'A float");

  iter = gegl_buffer_iterator_new (dst_buffer, roi, 0,
                                   iterator_format,
                                   GEGL_ACCESS_WRITE, GEGL_ABYSS_NONE);

  gegl_buffer_iterator_add (iter, src_buffer, roi, 0,
                            iterator_format,
                            GEGL_ACCESS_READ, GEGL_ABYSS_NONE);

  gegl_buffer_iterator_add (iter, aux_buffer, roi, 0,
                            iterator_format,
                            GEGL_ACCESS_READ, GEGL_ABYSS_NONE);

  while (gegl_buffer_iterator_next (iter))
    {
      gfloat *dest    = (gfloat *)iter->data[0];
      gfloat *src     = (gfloat *)iter->data[1];
      gfloat *aux     = (gfloat *)iter->data[2];
      glong   samples = iter->length;

      while (samples--)
        {
          dest[RED]   = (mask & GIMP_COMPONENT_MASK_RED)   ? aux[RED]   : src[RED];
          dest[GREEN] = (mask & GIMP_COMPONENT_MASK_GREEN) ? aux[GREEN] : src[GREEN];
          dest[BLUE]  = (mask & GIMP_COMPONENT_MASK_BLUE)  ? aux[BLUE]  : src[BLUE];
          dest[ALPHA] = (mask & GIMP_COMPONENT_MASK_ALPHA) ? aux[ALPHA] : src[ALPHA];

          src  += 4;
          aux  += 4;
          dest += 4;
        }
    }
}
Пример #3
0
void
gimp_gegl_combine_mask (GeglBuffer          *mask_buffer,
                        const GeglRectangle *mask_rect,
                        GeglBuffer          *dest_buffer,
                        const GeglRectangle *dest_rect,
                        gdouble              opacity)
{
  GeglBufferIterator *iter;

  iter = gegl_buffer_iterator_new (mask_buffer, mask_rect, 0,
                                   babl_format ("Y float"),
                                   GEGL_BUFFER_READ, GEGL_ABYSS_NONE);

  gegl_buffer_iterator_add (iter, dest_buffer, dest_rect, 0,
                            babl_format ("Y float"),
                            GEGL_BUFFER_READWRITE, GEGL_ABYSS_NONE);

  while (gegl_buffer_iterator_next (iter))
    {
      const gfloat *mask  = iter->data[0];
      gfloat       *dest  = iter->data[1];
      gint          count = iter->length;

      while (count--)
        {
          *dest *= *mask * opacity;

          mask += 1;
          dest += 1;
        }
    }
}
static gboolean
gegl_operation_point_filter_process (GeglOperation       *operation,
                                     GeglBuffer          *input,
                                     GeglBuffer          *output,
                                     const GeglRectangle *result)
{
  const Babl *in_format  = gegl_operation_get_format (operation, "input");
  const Babl *out_format = gegl_operation_get_format (operation, "output");
  GeglOperationPointFilterClass *point_filter_class;

  point_filter_class = GEGL_OPERATION_POINT_FILTER_GET_CLASS (operation);

  if ((result->width > 0) && (result->height > 0))
    {

      {
        GeglBufferIterator *i = gegl_buffer_iterator_new (output, result, out_format, GEGL_BUFFER_WRITE);
        gint read = /*output == input ? 0 :*/ gegl_buffer_iterator_add (i, input,  result, in_format, GEGL_BUFFER_READ);
        /* using separate read and write iterators for in-place ideally a single
         * readwrite indice would be sufficient
         */
          while (gegl_buffer_iterator_next (i))
            point_filter_class->process (operation, i->data[read], i->data[0], i->length, &i->roi[0]);
      }
    }
  return TRUE;
}
Пример #5
0
static void
transfer_registration_color (GeglBuffer  *src,
                             GeglBuffer **dst,
                             gint         count)
{
  GimpRGB color, test;
  GeglBufferIterator *gi;
  const Babl *src_format, *dst_format;
  gint i, src_bpp, dst_bpp;
  gdouble white;

  gimp_context_get_foreground (&color);
  white = 1.0;

  src_format = gegl_buffer_get_format (src);
  src_bpp = babl_format_get_bytes_per_pixel (src_format);

  dst_format = gegl_buffer_get_format (dst[0]);
  dst_bpp = babl_format_get_bytes_per_pixel (dst_format);

  gi = gegl_buffer_iterator_new (src, NULL, 0, NULL,
                                 GEGL_BUFFER_READ, GEGL_ABYSS_NONE);

  for (i = 0; i < count; i++)
    {
      gegl_buffer_iterator_add (gi, dst[i], NULL, 0, NULL,
                                GEGL_BUFFER_READWRITE, GEGL_ABYSS_NONE);
    }

  while (gegl_buffer_iterator_next (gi))
    {
      guint j, k;
      gpointer src_data, dst_data[MAX_EXTRACT_IMAGES];

      src_data = gi->data[0];
      for (j = 0; j < count; j++)
        dst_data[j] = gi->data[j+1];

      for (k = 0; k < gi->length; k++)
        {
          gulong pos;
          pos = k * src_bpp;
          gimp_rgba_set_pixel (&test, src_format, ((guchar *)src_data) + pos);

          if (gimp_rgb_distance (&test, &color) < 1e-6)
            {
              for (j = 0; j < count; j++)
                {
                  gpointer data;
                  data = dst_data[j];
                  babl_process (babl_fish (babl_format ("Y double"), dst_format),
                                &white, (guchar *)data + (k * dst_bpp), 1);
                }
            }
        }
    }
}
Пример #6
0
GeglBufferIterator *gegl_buffer_iterator_new (GeglBuffer          *buffer,
                                              const GeglRectangle *roi,
                                              const Babl          *format,
                                              guint                flags)
{
  GeglBufferIterator *i = (gpointer)g_slice_new0 (GeglBufferIterators);
  /* Because the iterator is nulled above, we can forgo explicitly setting
   * i->is_finished to FALSE. */
  gegl_buffer_iterator_add (i, buffer, roi, format, flags);
  return i;
}
Пример #7
0
static void
process_standard (GeglBuffer          *input,
                  GeglBuffer          *output,
                  const GeglRectangle *result,
                  guint               *channel_bits,
                  GeglRandom          *rand,
                  GeglDitherStrategy   dither_strategy)
{
  GeglBufferIterator *gi;
  guint               channel_mask [4];

  generate_channel_masks (channel_bits, channel_mask);

  gi = gegl_buffer_iterator_new (input, result, 0, babl_format ("R'G'B'A u16"),
                                 GEGL_ACCESS_READ, GEGL_ABYSS_NONE);

  gegl_buffer_iterator_add (gi, output, result, 0, babl_format ("R'G'B'A u16"),
                            GEGL_ACCESS_WRITE, GEGL_ABYSS_NONE);

  while (gegl_buffer_iterator_next (gi))
    {
      guint    y;
      for (y = 0; y < gi->roi->height; y++)
        {
          switch (dither_strategy)
            {
            case GEGL_DITHER_NONE:
              process_row_no_dither (gi, channel_mask, channel_bits, y);
              break;
            case GEGL_DITHER_RANDOM:
              process_row_random (gi, channel_mask, channel_bits, y, rand);
              break;
            case GEGL_DITHER_RESILIENT:
              process_row_resilient (gi, channel_mask, channel_bits, y, rand);
              break;
            case GEGL_DITHER_RANDOM_COVARIANT:
              process_row_random_covariant (gi, channel_mask, channel_bits, y, rand);
              break;
            case GEGL_DITHER_BAYER:
              process_row_bayer (gi, channel_mask, channel_bits, y);
              break;
            case GEGL_DITHER_FLOYD_STEINBERG:
              /* Done separately */
              break;
            default:
              process_row_no_dither (gi, channel_mask, channel_bits, y);
            }
        }
    }
}
Пример #8
0
GeglBufferIterator *
gegl_buffer_iterator_new (GeglBuffer          *buf,
                          const GeglRectangle *roi,
                          gint                 level,
                          const Babl          *format,
                          unsigned int         flags,
                          GeglAbyssPolicy      abyss_policy)
{
  GeglBufferIterator *iter = gegl_buffer_iterator_empty_new ();

  gegl_buffer_iterator_add (iter, buf, roi, level, format, flags, abyss_policy);

  return iter;
}
GeglBufferIterator *
gegl_buffer_iterator_new (GeglBuffer          *buffer,
                          const GeglRectangle *roi,
                          gint                 level,
                          const Babl          *format,
                          guint                flags,
                          GeglAbyssPolicy      abyss_policy)
{
  GeglBufferIterator *i = (gpointer)g_slice_new0 (GeglBufferIterators);
  /* Because the iterator is nulled above, we can forgo explicitly setting
   * i->is_finished to FALSE. */
  i->level = level;
  gegl_buffer_iterator_add (i, buffer, roi, level, format, flags, abyss_policy);
  return i;
}
Пример #10
0
GeglBufferIterator *
gegl_buffer_iterator_new (GeglBuffer          *buf,
                          const GeglRectangle *roi,
                          gint                 level,
                          const Babl          *format,
                          GeglAccessMode       access_mode,
                          GeglAbyssPolicy      abyss_policy)
{
  GeglBufferIterator *iter = gegl_buffer_iterator_empty_new ();

  gegl_buffer_iterator_add (iter, buf, roi, level, format,
                            access_mode, abyss_policy);

  return iter;
}
Пример #11
0
void
gimp_gegl_combine_mask_weird (GeglBuffer          *mask_buffer,
                              const GeglRectangle *mask_rect,
                              GeglBuffer          *dest_buffer,
                              const GeglRectangle *dest_rect,
                              gdouble              opacity,
                              gboolean             stipple)
{
  GeglBufferIterator *iter;

  iter = gegl_buffer_iterator_new (mask_buffer, mask_rect, 0,
                                   babl_format ("Y float"),
                                   GEGL_BUFFER_READ, GEGL_ABYSS_NONE);

  gegl_buffer_iterator_add (iter, dest_buffer, dest_rect, 0,
                            babl_format ("Y float"),
                            GEGL_BUFFER_READWRITE, GEGL_ABYSS_NONE);

  while (gegl_buffer_iterator_next (iter))
    {
      const gfloat *mask  = iter->data[0];
      gfloat       *dest  = iter->data[1];
      gint          count = iter->length;

      if (stipple)
        {
          while (count--)
            {
              dest[0] += (1.0 - dest[0]) * *mask * opacity;

              mask += 1;
              dest += 1;
            }
        }
      else
        {
          while (count--)
            {
              if (opacity > dest[0])
                dest[0] += (opacity - dest[0]) * *mask * opacity;

              mask += 1;
              dest += 1;
            }
        }
    }
}
Пример #12
0
static gboolean
process (GeglOperation       *operation,
         GeglBuffer          *input,
         GeglBuffer          *output,
         const GeglRectangle *result,
         gint                 level)
{
  AutostretchData     data;
  GeglBufferIterator *gi;

  buffer_get_auto_strech_data (input, &data);
  clean_autostretch_data (&data);

  gi = gegl_buffer_iterator_new (input, result, 0, babl_format ("HSVA float"),
                                 GEGL_ACCESS_READ, GEGL_ABYSS_NONE);

  gegl_buffer_iterator_add (gi, output, result, 0, babl_format ("HSVA float"),
                            GEGL_ACCESS_WRITE, GEGL_ABYSS_NONE);

  while (gegl_buffer_iterator_next (gi))
    {
      gfloat *in  = gi->data[0];
      gfloat *out = gi->data[1];
      gint    i;

      for (i = 0; i < gi->length; i++)
        {
          out[0] = in[0]; /* Keep hue */
          out[1] = (in[1] - data.slo) / data.sdiff;
          out[2] = (in[2] - data.vlo) / data.vdiff;
          out[3] = in[3]; /* Keep alpha */

          in  += 4;
          out += 4;
        }
    }

  return TRUE;
}
Пример #13
0
void
gimp_gegl_index_to_mask (GeglBuffer          *indexed_buffer,
                         const GeglRectangle *indexed_rect,
                         const Babl          *indexed_format,
                         GeglBuffer          *mask_buffer,
                         const GeglRectangle *mask_rect,
                         gint                 index)
{
  GeglBufferIterator *iter;

  iter = gegl_buffer_iterator_new (indexed_buffer, indexed_rect, 0,
                                   indexed_format,
                                   GEGL_ACCESS_READ, GEGL_ABYSS_NONE);

  gegl_buffer_iterator_add (iter, mask_buffer, mask_rect, 0,
                            babl_format ("Y float"),
                            GEGL_ACCESS_WRITE, GEGL_ABYSS_NONE);

  while (gegl_buffer_iterator_next (iter))
    {
      const guchar *indexed = iter->data[0];
      gfloat       *mask    = iter->data[1];
      gint          count   = iter->length;

      while (count--)
        {
          if (*indexed == index)
            *mask = 1.0;
          else
            *mask = 0.0;

          indexed++;
          mask++;
        }
    }
}
Пример #14
0
static int
gimp_mypaint_surface_draw_dab (MyPaintSurface *base_surface,
                               float           x,
                               float           y,
                               float           radius,
                               float           color_r,
                               float           color_g,
                               float           color_b,
                               float           opaque,
                               float           hardness,
                               float           color_a,
                               float           aspect_ratio,
                               float           angle,
                               float           lock_alpha,
                               float           colorize)
{
  GimpMybrushSurface *surface = (GimpMybrushSurface *)base_surface;
  GeglBufferIterator *iter;
  GeglRectangle       dabRect;
  GimpComponentMask   component_mask = surface->component_mask;

  const float one_over_radius2 = 1.0f / (radius * radius);
  const double angle_rad = angle / 360 * 2 * M_PI;
  const float cs = cos(angle_rad);
  const float sn = sin(angle_rad);
  float normal_mode;
  float segment1_slope;
  float segment2_slope;
  float r_aa_start;

  hardness = CLAMP (hardness, 0.0f, 1.0f);
  segment1_slope = -(1.0f / hardness - 1.0f);
  segment2_slope = -hardness / (1.0f - hardness);
  aspect_ratio = MAX (1.0f, aspect_ratio);

  r_aa_start = radius - 1.0f;
  r_aa_start = MAX (r_aa_start, 0);
  r_aa_start = (r_aa_start * r_aa_start) / aspect_ratio;

  normal_mode = opaque * (1.0f - colorize);
  colorize = opaque * colorize;

  /* FIXME: This should use the real matrix values to trim aspect_ratio dabs */
  dabRect = calculate_dab_roi (x, y, radius);
  gegl_rectangle_intersect (&dabRect, &dabRect, gegl_buffer_get_extent (surface->buffer));

  if (dabRect.width <= 0 || dabRect.height <= 0)
    return 0;

  gegl_rectangle_bounding_box (&surface->dirty, &surface->dirty, &dabRect);

  iter = gegl_buffer_iterator_new (surface->buffer, &dabRect, 0,
                                   babl_format ("R'G'B'A float"),
                                   GEGL_BUFFER_READWRITE,
                                   GEGL_ABYSS_NONE);
  if (surface->paint_mask)
    {
      GeglRectangle mask_roi = dabRect;
      mask_roi.x -= surface->paint_mask_x;
      mask_roi.y -= surface->paint_mask_y;
      gegl_buffer_iterator_add (iter, surface->paint_mask, &mask_roi, 0,
                                babl_format ("Y float"),
                                GEGL_ACCESS_READ, GEGL_ABYSS_NONE);
    }

  while (gegl_buffer_iterator_next (iter))
    {
      float *pixel = (float *)iter->data[0];
      float *mask;
      int iy, ix;

      if (surface->paint_mask)
        mask = iter->data[1];
      else
        mask = NULL;

      for (iy = iter->roi[0].y; iy < iter->roi[0].y + iter->roi[0].height; iy++)
        {
          for (ix = iter->roi[0].x; ix < iter->roi[0].x +  iter->roi[0].width; ix++)
            {
              float rr, base_alpha, alpha, dst_alpha, r, g, b, a;
              if (radius < 3.0f)
                rr = calculate_rr_antialiased (ix, iy, x, y, aspect_ratio, sn, cs, one_over_radius2, r_aa_start);
              else
                rr = calculate_rr (ix, iy, x, y, aspect_ratio, sn, cs, one_over_radius2);
              base_alpha = calculate_alpha_for_rr (rr, hardness, segment1_slope, segment2_slope);
              alpha = base_alpha * normal_mode;
              if (mask)
                alpha *= *mask;
              dst_alpha = pixel[ALPHA];
              /* a = alpha * color_a + dst_alpha * (1.0f - alpha);
               * which converts to: */
              a = alpha * (color_a - dst_alpha) + dst_alpha;
              r = pixel[RED];
              g = pixel[GREEN];
              b = pixel[BLUE];

              if (a > 0.0f)
                {
                  /* By definition the ratio between each color[] and pixel[] component in a non-pre-multipled blend always sums to 1.0f.
                   * Originaly this would have been "(color[n] * alpha * color_a + pixel[n] * dst_alpha * (1.0f - alpha)) / a",
                   * instead we only calculate the cheaper term. */
                  float src_term = (alpha * color_a) / a;
                  float dst_term = 1.0f - src_term;
                  r = color_r * src_term + r * dst_term;
                  g = color_g * src_term + g * dst_term;
                  b = color_b * src_term + b * dst_term;
                }

              if (colorize > 0.0f && base_alpha > 0.0f)
                {
                  alpha = base_alpha * colorize;
                  a = alpha + dst_alpha - alpha * dst_alpha;
                  if (a > 0.0f)
                    {
                      GimpHSL pixel_hsl, out_hsl;
                      GimpRGB pixel_rgb = {color_r, color_g, color_b};
                      GimpRGB out_rgb   = {r, g, b};
                      float src_term = alpha / a;
                      float dst_term = 1.0f - src_term;

                      gimp_rgb_to_hsl (&pixel_rgb, &pixel_hsl);
                      gimp_rgb_to_hsl (&out_rgb, &out_hsl);

                      out_hsl.h = pixel_hsl.h;
                      out_hsl.s = pixel_hsl.s;
                      gimp_hsl_to_rgb (&out_hsl, &out_rgb);

                      r = (float)out_rgb.r * src_term + r * dst_term;
                      g = (float)out_rgb.g * src_term + g * dst_term;
                      b = (float)out_rgb.b * src_term + b * dst_term;
                    }
                }

              if (component_mask != GIMP_COMPONENT_MASK_ALL)
                {
                  if (component_mask & GIMP_COMPONENT_MASK_RED)
                    pixel[RED]   = r;
                  if (component_mask & GIMP_COMPONENT_MASK_GREEN)
                    pixel[GREEN] = g;
                  if (component_mask & GIMP_COMPONENT_MASK_BLUE)
                    pixel[BLUE]  = b;
                  if (component_mask & GIMP_COMPONENT_MASK_ALPHA)
                    pixel[ALPHA] = a;
                }
              else
                {
                  pixel[RED]   = r;
                  pixel[GREEN] = g;
                  pixel[BLUE]  = b;
                  pixel[ALPHA] = a;
                }

              pixel += 4;
              if (mask)
                mask += 1;
            }
        }
    }

  return 1;
}
Пример #15
0
static void
gimp_mypaint_surface_get_color (MyPaintSurface *base_surface,
                                float           x,
                                float           y,
                                float           radius,
                                float          *color_r,
                                float          *color_g,
                                float          *color_b,
                                float          *color_a)
{
  GimpMybrushSurface *surface = (GimpMybrushSurface *)base_surface;
  GeglRectangle dabRect;

  if (radius < 1.0f)
    radius = 1.0f;

  dabRect = calculate_dab_roi (x, y, radius);

  *color_r = 0.0f;
  *color_g = 0.0f;
  *color_b = 0.0f;
  *color_a = 0.0f;

  if (dabRect.width > 0 || dabRect.height > 0)
  {
    const float one_over_radius2 = 1.0f / (radius * radius);
    float sum_weight = 0.0f;
    float sum_r = 0.0f;
    float sum_g = 0.0f;
    float sum_b = 0.0f;
    float sum_a = 0.0f;

     /* Read in clamp mode to avoid transparency bleeding in at the edges */
    GeglBufferIterator *iter = gegl_buffer_iterator_new (surface->buffer, &dabRect, 0,
                                                         babl_format ("R'aG'aB'aA float"),
                                                         GEGL_BUFFER_READ,
                                                         GEGL_ABYSS_CLAMP);
    if (surface->paint_mask)
      {
        GeglRectangle mask_roi = dabRect;
        mask_roi.x -= surface->paint_mask_x;
        mask_roi.y -= surface->paint_mask_y;
        gegl_buffer_iterator_add (iter, surface->paint_mask, &mask_roi, 0,
                                  babl_format ("Y float"),
                                  GEGL_ACCESS_READ, GEGL_ABYSS_NONE);
      }

    while (gegl_buffer_iterator_next (iter))
      {
        float *pixel = (float *)iter->data[0];
        float *mask;
        int iy, ix;

        if (surface->paint_mask)
          mask = iter->data[1];
        else
          mask = NULL;

        for (iy = iter->roi[0].y; iy < iter->roi[0].y + iter->roi[0].height; iy++)
          {
            float yy = (iy + 0.5f - y);
            for (ix = iter->roi[0].x; ix < iter->roi[0].x +  iter->roi[0].width; ix++)
              {
                /* pixel_weight == a standard dab with hardness = 0.5, aspect_ratio = 1.0, and angle = 0.0 */
                float xx = (ix + 0.5f - x);
                float rr = (yy * yy + xx * xx) * one_over_radius2;
                float pixel_weight = 0.0f;
                if (rr <= 1.0f)
                  pixel_weight = 1.0f - rr;
                if (mask)
                  pixel_weight *= *mask;

                sum_r += pixel_weight * pixel[RED];
                sum_g += pixel_weight * pixel[GREEN];
                sum_b += pixel_weight * pixel[BLUE];
                sum_a += pixel_weight * pixel[ALPHA];
                sum_weight += pixel_weight;

                pixel += 4;
                if (mask)
                  mask += 1;
              }
          }
      }

    if (sum_a > 0.0f && sum_weight > 0.0f)
      {
        sum_r /= sum_weight;
        sum_g /= sum_weight;
        sum_b /= sum_weight;
        sum_a /= sum_weight;

        sum_r /= sum_a;
        sum_g /= sum_a;
        sum_b /= sum_a;

        /* FIXME: Clamping is wrong because GEGL allows alpha > 1, this should probably re-multipy things */
        *color_r = CLAMP(sum_r, 0.0f, 1.0f);
        *color_g = CLAMP(sum_g, 0.0f, 1.0f);
        *color_b = CLAMP(sum_b, 0.0f, 1.0f);
        *color_a = CLAMP(sum_a, 0.0f, 1.0f);
      }
  }

}
Пример #16
0
static gboolean
process (GeglOperation       *operation,
         GeglBuffer          *input,
         GeglBuffer          *output,
         const GeglRectangle *result,
         gint                 level)
{
  GeglChantO *o = GEGL_CHANT_PROPERTIES (operation);

  cmsHTRANSFORM transform;
  const Babl *in_format, *out_format;

  gboolean alpha;
  gint bpp;

  in_format = babl_format_n (babl_type ("float"),
                 babl_format_get_n_components (gegl_buffer_get_format (input)));

  bpp = babl_format_get_bytes_per_pixel (in_format);

  /* create the transformation */
  {
    cmsHPROFILE in_profile, out_profile;
    cmsUInt32Number format;

    in_profile = o->src_profile;

    format = determine_lcms_format (in_format, in_profile);

    if (format == 0)
      return FALSE;

    if (format & EXTRA_SH (1))
      alpha = TRUE;
    else
      alpha = FALSE;

    out_profile = create_lcms_linear_rgb_profile ();

    transform = cmsCreateTransform (in_profile, format,
                                    out_profile, alpha ? TYPE_RGBA_FLT : TYPE_RGB_FLT,
                                    o->intent, o->black_point_compensation ? cmsFLAGS_BLACKPOINTCOMPENSATION : 0);

    cmsCloseProfile (out_profile);
  }

  out_format = alpha ? babl_format ("RGBA float") : babl_format ("RGB float");

  /* iterate over the pixels */
  {
    GeglBufferIterator *gi;

    gi = gegl_buffer_iterator_new (input, result, 0, in_format,
                                   GEGL_BUFFER_READ, GEGL_ABYSS_NONE);

    gegl_buffer_iterator_add (gi, output, result, 0, out_format,
                              GEGL_BUFFER_WRITE, GEGL_ABYSS_NONE);

    while (gegl_buffer_iterator_next (gi))
      {
        if (alpha)
          memcpy (gi->data[1], gi->data[0], bpp * gi->length);

        cmsDoTransform (transform, gi->data[0], gi->data[1], gi->length);
      }
  }

  cmsDeleteTransform (transform);

  return TRUE;
}
Пример #17
0
static void
lcms_layers_transform_rgb (gint                     *layers,
                           gint                      num_layers,
                           cmsHPROFILE               src_profile,
                           cmsHPROFILE               dest_profile,
                           GimpColorRenderingIntent  intent,
                           gboolean                  bpc)
{
  gint i;

  for (i = 0; i < num_layers; i++)
    {
      gint32           layer_id = layers[i];
      const Babl      *layer_format;
      gboolean         has_alpha;
      const Babl      *type;
      const Babl      *iter_format = NULL;
      cmsUInt32Number  lcms_format = 0;
      cmsHTRANSFORM    transform   = NULL;
      gint            *children;
      gint             num_children;

      children = gimp_item_get_children (layer_id, &num_children);

      if (children)
        {
          lcms_layers_transform_rgb (children, num_children,
                                     src_profile, dest_profile,
                                     intent, bpc);

          g_free (children);

          continue;
        }

      layer_format = gimp_drawable_get_format (layer_id);
      has_alpha    = babl_format_has_alpha (layer_format);
      type         = babl_format_get_type (layer_format, 0);

      if (type == babl_type ("u8"))
        {
          if (has_alpha)
            {
              lcms_format = TYPE_RGBA_8;
              iter_format = babl_format ("R'G'B'A u8");
            }
          else
            {
              lcms_format = TYPE_RGB_8;
              iter_format = babl_format ("R'G'B' u8");
            }
        }
      else if (type == babl_type ("u16"))
        {
          if (has_alpha)
            {
              lcms_format = TYPE_RGBA_16;
              iter_format = babl_format ("R'G'B'A u16");
            }
          else
            {
              lcms_format = TYPE_RGB_16;
              iter_format = babl_format ("R'G'B' u16");
            }
        }
      else if (type == babl_type ("half")) /* 16-bit floating point (half) */
        {
#ifdef TYPE_RGB_HALF_FLT
          /* half float types are only in lcms 2.4 and newer */
          if (has_alpha)
            {
              lcms_format = TYPE_RGBA_HALF_FLT;
              iter_format = babl_format ("R'G'B'A half");
            }
          else
            {
              lcms_format = TYPE_RGB_HALF_FLT;
              iter_format = babl_format ("R'G'B' float");
            }
#endif /* TYPE_RGB_HALF_FLT */
        }
      else if (type == babl_type ("float"))
        {
          if (has_alpha)
            {
              lcms_format = TYPE_RGBA_FLT;
              iter_format = babl_format ("R'G'B'A float");
            }
          else
            {
              lcms_format = TYPE_RGB_FLT;
              iter_format = babl_format ("R'G'B' float");
            }
        }
      else if (type == babl_type ("double"))
        {
          if (has_alpha)
            {
#ifdef TYPE_RGBA_DBL
              /* RGBA double not implemented in lcms */
              lcms_format = TYPE_RGBA_DBL;
              iter_format = babl_format ("R'G'B'A double");
#endif /* TYPE_RGBA_DBL */
            }
          else
            {
              lcms_format = TYPE_RGB_DBL;
              iter_format = babl_format ("R'G'B' double");
            }
        }

      if (lcms_format == 0)
        {
          g_printerr ("lcms: layer format %s not supported, "
                      "falling back to float\n",
                      babl_get_name (layer_format));

          if (has_alpha)
            {
              lcms_format = TYPE_RGBA_FLT;
              iter_format = babl_format ("R'G'B'A float");
            }
          else
            {
              lcms_format = TYPE_RGB_FLT;
              iter_format = babl_format ("R'G'B' float");
            }
        }

      transform = cmsCreateTransform (src_profile,  lcms_format,
                                      dest_profile, lcms_format,
                                      intent,
                                      cmsFLAGS_NOOPTIMIZE |
                                      (bpc ? cmsFLAGS_BLACKPOINTCOMPENSATION : 0));

      if (transform)
        {
          GeglBuffer         *src_buffer;
          GeglBuffer         *dest_buffer;
          GeglBufferIterator *iter;
          gint                layer_width;
          gint                layer_height;
          gint                layer_bpp;
          gboolean            layer_alpha;
          gdouble             progress_start = (gdouble) i / num_layers;
          gdouble             progress_end   = (gdouble) (i + 1) / num_layers;
          gdouble             range          = progress_end - progress_start;
          gint                count          = 0;
          gint                done           = 0;

          src_buffer   = gimp_drawable_get_buffer (layer_id);
          dest_buffer  = gimp_drawable_get_shadow_buffer (layer_id);
          layer_width  = gegl_buffer_get_width (src_buffer);
          layer_height = gegl_buffer_get_height (src_buffer);
          layer_bpp    = babl_format_get_bytes_per_pixel (iter_format);
          layer_alpha  = babl_format_has_alpha (iter_format);

          iter = gegl_buffer_iterator_new (src_buffer, NULL, 0,
                                           iter_format,
                                           GEGL_ACCESS_READ, GEGL_ABYSS_NONE);

          gegl_buffer_iterator_add (iter, dest_buffer, NULL, 0,
                                    iter_format,
                                    GEGL_ACCESS_WRITE, GEGL_ABYSS_NONE);

          while (gegl_buffer_iterator_next (iter))
            {
              /*  lcms doesn't touch the alpha channel, simply
               *  copy everything to dest before the transform
               */
              if (layer_alpha)
                memcpy (iter->data[1], iter->data[0],
                        iter->length * layer_bpp);

              cmsDoTransform (transform,
                              iter->data[0], iter->data[1], iter->length);
            }

          g_object_unref (src_buffer);
          g_object_unref (dest_buffer);

          gimp_drawable_merge_shadow (layer_id, TRUE);
          gimp_drawable_update (layer_id, 0, 0, layer_width, layer_height);

          if (count++ % 32 == 0)
            {
              gimp_progress_update (progress_start +
                                    (gdouble) done /
                                    (layer_width * layer_height) * range);
            }

          cmsDeleteTransform (transform);
        }
    }
}
Пример #18
0
static gboolean
process (GeglOperation       *operation,
         GeglBuffer          *input,
         GeglBuffer          *output,
         const GeglRectangle *roi,
         gint                 level)
{
  GeglProperties      *o      = GEGL_PROPERTIES (operation);
  const Babl          *format = babl_format ("RGBA float");
  GeglSampler         *sampler;
  GeglBufferIterator  *iter;
  const GeglRectangle *in_extent;
  gdouble              cx, cy;
  gdouble              dx = 0.0, dy = 0.0;
  gdouble              coangle_of_view_2;
  gdouble              focal_length;
  gdouble              curvature_sign;
  gdouble              cap_angle_2;
  gdouble              cap_radius;
  gdouble              cap_depth;
  gdouble              factor;
  gdouble              f, f2, r, r_inv, r2, p, f_p, f_p2, f_pf, a, a_inv, sgn;
  gboolean             perspective;
  gboolean             inverse;
  gint                 i, j;

  sampler = gegl_buffer_sampler_new_at_level (input, format,
                                              o->sampler_type, level);

  iter = gegl_buffer_iterator_new (output, roi, level, format,
                                   GEGL_ACCESS_WRITE, GEGL_ABYSS_NONE);

  gegl_buffer_iterator_add (iter, input, roi, level, format,
                            GEGL_ACCESS_READ, GEGL_ABYSS_NONE);

  in_extent = gegl_operation_source_get_bounding_box (operation, "input");

  cx = in_extent->x + in_extent->width  / 2.0;
  cy = in_extent->y + in_extent->height / 2.0;

  if (o->mode == GEGL_SPHERIZE_MODE_RADIAL ||
      o->mode == GEGL_SPHERIZE_MODE_HORIZONTAL)
    {
      dx = 2.0 / (in_extent->width - 1);
    }
  if (o->mode == GEGL_SPHERIZE_MODE_RADIAL ||
      o->mode == GEGL_SPHERIZE_MODE_VERTICAL)
    {
      dy = 2.0 / (in_extent->height - 1);
    }

  coangle_of_view_2 = MAX (180.0 - o->angle_of_view, 0.01) * G_PI / 360.0;
  focal_length      = tan (coangle_of_view_2);
  curvature_sign    = o->curvature > 0.0 ? +1.0 : -1.0;
  cap_angle_2       = fabs (o->curvature) * coangle_of_view_2;
  cap_radius        = 1.0 / sin (cap_angle_2);
  cap_depth         = curvature_sign * cap_radius * cos (cap_angle_2);
  factor            = fabs (o->amount);

  f     = focal_length;
  f2    = f * f;
  r     = cap_radius;
  r_inv = 1 / r;
  r2    = r * r;
  p     = cap_depth;
  f_p   = f + p;
  f_p2  = f_p * f_p;
  f_pf  = f_p * f;
  a     = cap_angle_2;
  a_inv = 1 / a;
  sgn   = curvature_sign;

  perspective = o->angle_of_view > EPSILON;
  inverse     = o->amount < 0.0;

  while (gegl_buffer_iterator_next (iter))
    {
      gfloat       *out_pixel = iter->data[0];
      const gfloat *in_pixel  = iter->data[1];
      gfloat        x,  y;

      y = dy * (iter->roi->y + 0.5 - cy);

      for (j = iter->roi->y; j < iter->roi->y + iter->roi->height; j++, y += dy)
        {
          x = dx * (iter->roi->x + 0.5 - cx);

          for (i = iter->roi->x; i < iter->roi->x + iter->roi->width; i++, x += dx)
            {
              gfloat d2;

              d2 = x * x + y * y;

              if (d2 > EPSILON && d2 < 1.0 - EPSILON)
                {
                  gdouble d     = sqrt (d2);
                  gdouble src_d = d;
                  gdouble src_x, src_y;

                  if (! inverse)
                    {
                      gdouble d2_f2 = d2 + f2;

                      if (perspective)
                        src_d = (f_pf - sgn * sqrt (d2_f2 * r2 - f_p2 * d2)) * d / d2_f2;

                      src_d = (G_PI_2 - acos (src_d * r_inv)) * a_inv;
                    }
                  else
                    {
                      src_d = r * cos (G_PI_2 - src_d * a);

                      if (perspective)
                        src_d = f * src_d / (f_p - sgn * sqrt (r2 - src_d * src_d));
                    }

                  if (factor < 1.0)
                    src_d = d + (src_d - d) * factor;

                  src_x = dx ? cx + src_d * x / (dx * d) :
                               i + 0.5;
                  src_y = dy ? cy + src_d * y / (dy * d) :
                               j + 0.5;

                  gegl_sampler_get (sampler, src_x, src_y,
                                    NULL, out_pixel, GEGL_ABYSS_NONE);
                }
              else
                {
                  memcpy (out_pixel, in_pixel, sizeof (gfloat) * 4);
                }

              out_pixel += 4;
              in_pixel  += 4;
            }
        }
    }

  g_object_unref (sampler);

  return TRUE;
}
Пример #19
0
static void
set_background (GeglProperties      *o,
                const GeglRectangle *rect,
                GeglBuffer          *input,
                GeglBuffer          *output,
                gint                 division_x,
                gint                 division_y,
                gint                 offset_x,
                gint                 offset_y)
{
  const Babl *format = babl_format ("RGBA float");

  if (o->background_type == GEGL_BACKGROUND_TYPE_TRANSPARENT)
    {
      GeglColor *color = gegl_color_new ("rgba(0.0,0.0,0.0,0.0)");
      gegl_buffer_set_color (output, rect, color);
      g_object_unref (color);
    }
  else if (o->background_type == GEGL_BACKGROUND_TYPE_COLOR)
    {
      gegl_buffer_set_color (output, rect, o->bg_color);
    }
  else if (o->background_type == GEGL_BACKGROUND_TYPE_IMAGE)
    {
      gegl_buffer_copy (input, NULL, GEGL_ABYSS_NONE, output, NULL);
    }
  else
    {
      /* GEGL_BACKGROUND_TYPE_INVERT */

      GeglBufferIterator  *iter;
      GeglRectangle        clear = *rect;

      if (o->fractional_type == GEGL_FRACTIONAL_TYPE_IGNORE)
        {
          clear.x      = offset_x;
          clear.y      = offset_y;
          clear.width  = o->tile_width * (rect->width / o->tile_width);
          clear.height = o->tile_height * (rect->height / o->tile_height);
        }

      iter = gegl_buffer_iterator_new (input, &clear, 0, format,
                                       GEGL_ACCESS_READ, GEGL_ABYSS_NONE);
      gegl_buffer_iterator_add (iter, output, &clear, 0, format,
                                GEGL_ACCESS_WRITE, GEGL_ABYSS_NONE);

      while (gegl_buffer_iterator_next (iter))
        {
          gfloat  *src      = iter->data[0];
          gfloat  *dst      = iter->data[1];
          glong    n_pixels = iter->length;

          while (n_pixels--)
            {
              *dst++ = 1.f - *src++;
              *dst++ = 1.f - *src++;
              *dst++ = 1.f - *src++;
              *dst++ = *src++;
            }
        }
    }
}
Пример #20
0
static gboolean
process (GeglOperation       *operation,
         GeglBuffer          *input,
         GeglBuffer          *output,
         const GeglRectangle *result,
         gint                 level)
{
  gfloat  min[3], max[3], diff[3];
  GeglBufferIterator *gi;
  GeglProperties         *o;
  gint                c;

  if (gegl_cl_is_accelerated ())
    if (cl_process (operation, input, output, result))
      return TRUE;

  o = GEGL_PROPERTIES (operation);

  buffer_get_min_max (input, min, max);

  if (o->keep_colors)
    reduce_min_max_global (min, max);

  for (c = 0; c < 3; c++)
    {
      diff[c] = max[c] - min[c];

      /* Avoid a divide by zero error if the image is a solid color */
      if (diff[c] < 1e-3)
        {
          min[c]  = 0.0;
          diff[c] = 1.0;
        }
    }

  gi = gegl_buffer_iterator_new (input, result, 0, babl_format ("RGBA float"),
                                 GEGL_ACCESS_READ, GEGL_ABYSS_NONE);

  gegl_buffer_iterator_add (gi, output, result, 0, babl_format ("RGBA float"),
                            GEGL_ACCESS_WRITE, GEGL_ABYSS_NONE);

  while (gegl_buffer_iterator_next (gi))
    {
      gfloat *in  = gi->data[0];
      gfloat *out = gi->data[1];

      gint o;
      for (o = 0; o < gi->length; o++)
        {
          for (c = 0; c < 3; c++)
            out[c] = (in[c] - min[c]) / diff[c];

          out[3] = in[3];

          in  += 4;
          out += 4;
        }
    }

  return TRUE;
}
Пример #21
0
static gboolean
process (GeglOperation       *operation,
         GeglBuffer          *input,
         GeglBuffer          *output,
         const GeglRectangle *result,
         gint                 level)
{
  const GeglRectangle *whole_region;
  GeglRectangle        shift_region;
  GeglBufferIterator  *gi;
  gint                 half_width;
  gint                 half_height;
  gint                 index_iter;
  gint                 index_iter2;

  whole_region = gegl_operation_source_get_bounding_box (operation, "input");

  half_width  = whole_region->width / 2;
  half_height = whole_region->height / 2;

  shift_region.x = whole_region->x + half_width;
  shift_region.y = whole_region->y + half_height;
  shift_region.width  = whole_region->width;
  shift_region.height = whole_region->height;

  gi = gegl_buffer_iterator_new (output, whole_region,
                                 0, babl_format ("R'G'B'A float"),
                                 GEGL_ACCESS_WRITE, GEGL_ABYSS_NONE);

  index_iter = gegl_buffer_iterator_add (gi, input, whole_region,
                                         0, babl_format ("R'G'B'A float"),
                                         GEGL_ACCESS_READ, GEGL_ABYSS_NONE);

  index_iter2 = gegl_buffer_iterator_add (gi, input, &shift_region,
                                          0, babl_format ("R'G'B'A float"),
                                          GEGL_ACCESS_READ, GEGL_ABYSS_LOOP);

  while (gegl_buffer_iterator_next (gi))
    {
      guint   k;
      gfloat *data_out;
      gfloat *data_in1;
      gfloat *data_in2;

      data_out = (gfloat*) gi->data[0];
      data_in1 = (gfloat*) gi->data[index_iter];
      data_in2 = (gfloat*) gi->data[index_iter2];

      for (k = 0; k < gi->length; k++)
        {
          gint x, y, b;
          gfloat alpha;
          gfloat val_x, val_y;
          gfloat w, w1, w2;
          const gfloat eps = 1e-4;

          x = gi->roi[0].x + k % gi->roi[0].width;
          y = gi->roi[0].y + k / gi->roi[0].width;

          val_x = (half_width - x) / (gfloat) half_width;
          val_y = (half_height - y) / (gfloat) half_height;

          val_x = ABS (CLAMP (val_x, -1.0, 1.0));
          val_y = ABS (CLAMP (val_y, -1.0, 1.0));

          /* ambiguous position */
          if (ABS (val_x - val_y) >= 1.0 - eps)
            w = 0.0;
          else
            w = val_x * val_y / (val_x * val_y + (1.0 - val_x) * (1.0 - val_y));

          alpha = data_in1[3] * (1.0 - w) + data_in2[3] * w;

          w1 = (1.0 - w) * data_in1[3] / alpha;
          w2 = w * data_in2[3] / alpha;

          for (b = 0; b < 3; b++)
            data_out[b] = data_in1[b] * w1 + data_in2[b] * w2;

          data_out[3] = alpha;

          data_out += 4;
          data_in1 += 4;
          data_in2 += 4;
        }
    }

  return TRUE;
}
Пример #22
0
static gboolean
process (GeglOperation       *operation,
         GeglBuffer          *input,
         GeglBuffer          *aux,
         GeglBuffer          *output,
         const GeglRectangle *result,
         gint                 level)
{
  GeglProperties       *o = GEGL_PROPERTIES (operation);
  const Babl           *format_io, *format_coords;
  GeglSampler          *sampler;
  GeglBufferIterator   *it;
  gint                  index_in, index_out, index_coords;

  format_io = babl_format ("RGBA float");
  format_coords = babl_format_n (babl_type ("float"), 2);

  sampler = gegl_buffer_sampler_new_at_level (input, format_io, o->sampler_type, level);

  if (aux != NULL)
    {
      it = gegl_buffer_iterator_new (output, result, level, format_io,
                                     GEGL_ACCESS_WRITE, GEGL_ABYSS_NONE);
      index_out = 0;

      index_coords = gegl_buffer_iterator_add (it, aux, result, level, format_coords,
                                               GEGL_ACCESS_READ, GEGL_ABYSS_NONE);
      index_in = gegl_buffer_iterator_add (it, input, result, level, format_io,
                                           GEGL_ACCESS_READ, GEGL_ABYSS_NONE);

      while (gegl_buffer_iterator_next (it))
        {
          gint        i;
          gint        n_pixels = it->length;
          gint        x = it->roi->x; /* initial x                   */
          gint        y = it->roi->y; /*           and y coordinates */
          gdouble     scaling = GEGL_PROPERTIES (operation)->scaling;
          gfloat     *in = it->data[index_in];
          gfloat     *out = it->data[index_out];
          gfloat     *coords = it->data[index_coords];

          for (i=0; i<n_pixels; i++)
            {
              /* if the coordinate asked is an exact pixel, we fetch it
               * directly, to avoid the blur of sampling */
              if (coords[0] == 0 && coords[1] == 0)
                {
                  out[0] = in[0];
                  out[1] = in[1];
                  out[2] = in[2];
                  out[3] = in[3];
                }
              else
                {
                  gegl_sampler_get (sampler, x+coords[0] * scaling,
                                             y+coords[1] * scaling,
                                             NULL, out,
                                             GEGL_ABYSS_NONE);
                }

              coords += 2;
              in += 4;
              out += 4;

              /* update x and y coordinates */
              x++;
              if (x >= (it->roi->x + it->roi->width))
                {
                  x = it->roi->x;
                  y++;
                }

            }
        }
    }
  else
    {
      gegl_buffer_copy (input, result, GEGL_ABYSS_NONE,
                        output, result);
    }

  g_object_unref (sampler);

  return TRUE;
}
Пример #23
0
void
gimp_gegl_dodgeburn (GeglBuffer          *src_buffer,
                     const GeglRectangle *src_rect,
                     GeglBuffer          *dest_buffer,
                     const GeglRectangle *dest_rect,
                     gdouble              exposure,
                     GimpDodgeBurnType    type,
                     GimpTransferMode     mode)
{
  GeglBufferIterator *iter;

  if (type == GIMP_DODGE_BURN_TYPE_BURN)
    exposure = -exposure;

  iter = gegl_buffer_iterator_new (src_buffer, src_rect, 0,
                                   babl_format ("R'G'B'A float"),
                                   GEGL_BUFFER_READ, GEGL_ABYSS_NONE);

  gegl_buffer_iterator_add (iter, dest_buffer, dest_rect, 0,
                            babl_format ("R'G'B'A float"),
                            GEGL_BUFFER_WRITE, GEGL_ABYSS_NONE);

  switch (mode)
    {
      gfloat factor;

    case GIMP_TRANSFER_HIGHLIGHTS:
      factor = 1.0 + exposure * (0.333333);

      while (gegl_buffer_iterator_next (iter))
        {
          gfloat *src   = iter->data[0];
          gfloat *dest  = iter->data[1];
          gint    count = iter->length;

          while (count--)
            {
              *dest++ = *src++ * factor;
              *dest++ = *src++ * factor;
              *dest++ = *src++ * factor;

              *dest++ = *src++;
            }
        }
      break;

    case GIMP_TRANSFER_MIDTONES:
      if (exposure < 0)
        factor = 1.0 - exposure * (0.333333);
      else
        factor = 1.0 / (1.0 + exposure);

      while (gegl_buffer_iterator_next (iter))
        {
          gfloat *src   = iter->data[0];
          gfloat *dest  = iter->data[1];
          gint    count = iter->length;

          while (count--)
            {
              *dest++ = pow (*src++, factor);
              *dest++ = pow (*src++, factor);
              *dest++ = pow (*src++, factor);

              *dest++ = *src++;
            }
        }
      break;

    case GIMP_TRANSFER_SHADOWS:
      if (exposure >= 0)
        factor = 0.333333 * exposure;
      else
        factor = -0.333333 * exposure;

      while (gegl_buffer_iterator_next (iter))
        {
          gfloat *src   = iter->data[0];
          gfloat *dest  = iter->data[1];
          gint    count = iter->length;

          while (count--)
            {
              if (exposure >= 0)
                {
                  gfloat s;

                  s = *src++; *dest++ = factor + s - factor * s;
                  s = *src++; *dest++ = factor + s - factor * s;
                  s = *src++; *dest++ = factor + s - factor * s;
                }
              else
                {
                  gfloat s;

                  s = *src++;
                  if (s < factor)
                    *dest++ = 0;
                  else /* factor <= value <=1 */
                    *dest++ = (s - factor) / (1.0 - factor);

                  s = *src++;
                  if (s < factor)
                    *dest++ = 0;
                  else /* factor <= value <=1 */
                    *dest++ = (s - factor) / (1.0 - factor);

                  s = *src++;
                  if (s < factor)
                    *dest++ = 0;
                  else /* factor <= value <=1 */
                    *dest++ = (s - factor) / (1.0 - factor);
                }

              *dest++ = *src++;
           }
        }
      break;
    }
}
Пример #24
0
void
gimp_gegl_convolve (GeglBuffer          *src_buffer,
                    const GeglRectangle *src_rect,
                    GeglBuffer          *dest_buffer,
                    const GeglRectangle *dest_rect,
                    const gfloat        *kernel,
                    gint                 kernel_size,
                    gdouble              divisor,
                    GimpConvolutionType  mode,
                    gboolean             alpha_weighting)
{
  GeglBufferIterator *iter;
  GeglRectangle      *src_roi;
  GeglRectangle      *dest_roi;
  const Babl         *src_format;
  const Babl         *dest_format;
  gint                src_components;
  gint                dest_components;

  src_format = gegl_buffer_get_format (src_buffer);

  if (babl_format_is_palette (src_format))
    src_format = gimp_babl_format (GIMP_RGB,
                                   GIMP_PRECISION_FLOAT_LINEAR,
                                   babl_format_has_alpha (src_format));
  else
    src_format = gimp_babl_format (gimp_babl_format_get_base_type (src_format),
                                   GIMP_PRECISION_FLOAT_LINEAR,
                                   babl_format_has_alpha (src_format));

  dest_format = gegl_buffer_get_format (dest_buffer);

  if (babl_format_is_palette (dest_format))
    dest_format = gimp_babl_format (GIMP_RGB,
                                    GIMP_PRECISION_FLOAT_LINEAR,
                                    babl_format_has_alpha (dest_format));
  else
    dest_format = gimp_babl_format (gimp_babl_format_get_base_type (dest_format),
                                    GIMP_PRECISION_FLOAT_LINEAR,
                                    babl_format_has_alpha (dest_format));

  src_components  = babl_format_get_n_components (src_format);
  dest_components = babl_format_get_n_components (dest_format);

  iter = gegl_buffer_iterator_new (src_buffer, src_rect, 0, src_format,
                                   GEGL_BUFFER_READ, GEGL_ABYSS_NONE);
  src_roi = &iter->roi[0];

  gegl_buffer_iterator_add (iter, dest_buffer, dest_rect, 0, dest_format,
                            GEGL_BUFFER_WRITE, GEGL_ABYSS_NONE);
  dest_roi = &iter->roi[1];

  while (gegl_buffer_iterator_next (iter))
    {
      /*  Convolve the src image using the convolution kernel, writing
       *  to dest Convolve is not tile-enabled--use accordingly
       */
      const gfloat *src         = iter->data[0];
      gfloat       *dest        = iter->data[1];
      const gint    components  = src_components;
      const gint    a_component = components - 1;
      const gint    rowstride   = src_components * src_roi->width;
      const gint    margin      = kernel_size / 2;
      const gint    x1          = src_roi->x;
      const gint    y1          = src_roi->y;
      const gint    x2          = src_roi->x + src_roi->width  - 1;
      const gint    y2          = src_roi->y + src_roi->height - 1;
      gint          x, y;
      gfloat        offset;

      /*  If the mode is NEGATIVE_CONVOL, the offset should be 128  */
      if (mode == GIMP_NEGATIVE_CONVOL)
        {
          offset = 0.5;
          mode = GIMP_NORMAL_CONVOL;
        }
      else
        {
          offset = 0.0;
        }

      for (y = 0; y < dest_roi->height; y++)
        {
          gfloat *d = dest;

          if (alpha_weighting)
            {
              for (x = 0; x < dest_roi->width; x++)
                {
                  const gfloat *m                = kernel;
                  gdouble       total[4]         = { 0.0, 0.0, 0.0, 0.0 };
                  gdouble       weighted_divisor = 0.0;
                  gint          i, j, b;

                  for (j = y - margin; j <= y + margin; j++)
                    {
                      for (i = x - margin; i <= x + margin; i++, m++)
                        {
                          gint          xx = CLAMP (i, x1, x2);
                          gint          yy = CLAMP (j, y1, y2);
                          const gfloat *s  = src + yy * rowstride + xx * components;
                          const gfloat  a  = s[a_component];

                          if (a)
                            {
                              gdouble mult_alpha = *m * a;

                              weighted_divisor += mult_alpha;

                              for (b = 0; b < a_component; b++)
                                total[b] += mult_alpha * s[b];

                              total[a_component] += mult_alpha;
                            }
                        }
                    }

                  if (weighted_divisor == 0.0)
                    weighted_divisor = divisor;

                  for (b = 0; b < a_component; b++)
                    total[b] /= weighted_divisor;

                  total[a_component] /= divisor;

                  for (b = 0; b < components; b++)
                    {
                      total[b] += offset;

                      if (mode != GIMP_NORMAL_CONVOL && total[b] < 0.0)
                        total[b] = - total[b];

                      *d++ = CLAMP (total[b], 0.0, 1.0);
                    }
                }
            }
          else
            {
              for (x = 0; x < dest_roi->width; x++)
                {
                  const gfloat *m        = kernel;
                  gdouble       total[4] = { 0.0, 0.0, 0.0, 0.0 };
                  gint          i, j, b;

                  for (j = y - margin; j <= y + margin; j++)
                    {
                      for (i = x - margin; i <= x + margin; i++, m++)
                        {
                          gint          xx = CLAMP (i, x1, x2);
                          gint          yy = CLAMP (j, y1, y2);
                          const gfloat *s  = src + yy * rowstride + xx * components;

                          for (b = 0; b < components; b++)
                            total[b] += *m * s[b];
                        }
                    }

                  for (b = 0; b < components; b++)
                    {
                      total[b] = total[b] / divisor + offset;

                      if (mode != GIMP_NORMAL_CONVOL && total[b] < 0.0)
                        total[b] = - total[b];

                      total[b] = CLAMP (total[b], 0.0, 1.0);
                    }
                }
            }

          dest += dest_roi->width * dest_components;
        }
    }
}
Пример #25
0
static void record_pix_stats (GeglBuffer *buffer, GeglBuffer *previous_buffer,
         uint8_t *info_rgb_hist,
         uint8_t *rgb_square_diff)
{
  int rgb_hist[NEGL_RGB_HIST_DIM * NEGL_RGB_HIST_DIM * NEGL_RGB_HIST_DIM]={0,};
  int sum = 0;
  int second_max_hist = 0;
  int max_hist = 0;
  int slot;
  long r_square_diff = 0;
  long g_square_diff = 0;
  long b_square_diff = 0;
  GeglBufferIterator *it = gegl_buffer_iterator_new (buffer, NULL, 0,
          babl_format ("RGBA u8"),
          GEGL_BUFFER_READ,
          GEGL_ABYSS_NONE);
  if (previous_video_frame)
    gegl_buffer_iterator_add (it, previous_buffer, NULL, 0,
          babl_format ("RGBA u8"),
          GEGL_BUFFER_READ,
          GEGL_ABYSS_NONE);

  for (slot = 0; slot < NEGL_RGB_HIST_SLOTS; slot ++)
    rgb_hist[slot] = 0;

  while (gegl_buffer_iterator_next (it))
  {
    uint8_t *data = (void*)it->data[0];
    int i;
    if (strstr (format, "histogram"))
    {
      for (i = 0; i < it->length; i++)
      {
        int r = data[i * 3 + 0] / 256.0 * NEGL_RGB_HIST_DIM;
        int g = data[i * 3 + 1] / 256.0 * NEGL_RGB_HIST_DIM;
        int b = data[i * 3 + 2] / 256.0 * NEGL_RGB_HIST_DIM;
        int slot = r * NEGL_RGB_HIST_DIM * NEGL_RGB_HIST_DIM +
                   g * NEGL_RGB_HIST_DIM +
                   b;
        if (slot < 0) slot = 0;
        if (slot >= NEGL_RGB_HIST_SLOTS)
            slot = NEGL_RGB_HIST_SLOTS;

        rgb_hist[slot]++;
        if (rgb_hist[slot] > max_hist)
        {
          second_max_hist = max_hist;
          max_hist = rgb_hist[slot];
        }
        sum++;
      }
    }

      if (previous_buffer)
      {
        uint8_t *data_prev = (void*)it->data[1];
        int i;
        for (i = 0; i < it->length; i++)
        {
  #define square(a) ((a)*(a))
          r_square_diff += square(data[i * 3 + 0] -data_prev [i * 3 + 0]);
          g_square_diff += square(data[i * 3 + 1] -data_prev [i * 3 + 1]);
          b_square_diff += square(data[i * 3 + 2] -data_prev [i * 3 + 2]);
        }
      }
  }

  if (strstr(format, "histogram"))
  {
   int slot;
   for (slot = 0; slot < NEGL_RGB_HIST_SLOTS; slot ++)
   {
     int val = (sqrtf(rgb_hist[slot]) / (sqrtf(second_max_hist) * 0.9 + sqrtf(max_hist) * 0.1)) * 255;
     if (val > 255)
       val = 255;
     info_rgb_hist[rgb_hist_shuffle (slot)] = val;
    }
  }
  if (previous_buffer)
  {
    rgb_square_diff[0] = sqrt(r_square_diff) * 255 / sum;
    rgb_square_diff[1] = sqrt(g_square_diff) * 255 / sum;
    rgb_square_diff[2] = sqrt(b_square_diff) * 255 / sum;
  }
}
Пример #26
0
void
gimp_gegl_replace (GeglBuffer          *top_buffer,
                   const GeglRectangle *top_rect,
                   GeglBuffer          *bottom_buffer,
                   const GeglRectangle *bottom_rect,
                   GeglBuffer          *mask_buffer,
                   const GeglRectangle *mask_rect,
                   GeglBuffer          *dest_buffer,
                   const GeglRectangle *dest_rect,
                   gdouble              opacity,
                   const gboolean      *affect)
{
  GeglBufferIterator *iter;

  iter = gegl_buffer_iterator_new (top_buffer, top_rect, 0,
                                   babl_format ("RGBA float"),
                                   GEGL_BUFFER_READ, GEGL_ABYSS_NONE);

  gegl_buffer_iterator_add (iter, bottom_buffer, bottom_rect, 0,
                            babl_format ("RGBA float"),
                            GEGL_BUFFER_READ, GEGL_ABYSS_NONE);

  gegl_buffer_iterator_add (iter, mask_buffer, mask_rect, 0,
                            babl_format ("Y float"),
                            GEGL_BUFFER_READ, GEGL_ABYSS_NONE);

  gegl_buffer_iterator_add (iter, dest_buffer, dest_rect, 0,
                            babl_format ("RGBA float"),
                            GEGL_BUFFER_WRITE, GEGL_ABYSS_NONE);

  while (gegl_buffer_iterator_next (iter))
    {
      const gfloat *top    = iter->data[0];
      const gfloat *bottom = iter->data[1];
      const gfloat *mask   = iter->data[2];
      gfloat       *dest   = iter->data[3];
      gint          count  = iter->length;

      while (count--)
        {
          gint    b;
          gdouble mask_val = *mask * opacity;

          /* calculate new alpha first. */
          gfloat   s1_a  = bottom[3];
          gfloat   s2_a  = top[3];
          gdouble  a_val = s1_a + mask_val * (s2_a - s1_a);

          if (a_val == 0.0)
            {
              /* In any case, write out versions of the blending
               * function that result when combinations of s1_a, s2_a,
               * and mask_val --> 0 (or mask_val -->1)
               */

              /* 1: s1_a, s2_a, AND mask_val all approach 0+: */
              /* 2: s1_a AND s2_a both approach 0+, regardless of mask_val: */
              if (s1_a + s2_a == 0.0)
                {
                  for (b = 0; b < 3; b++)
                    {
                      gfloat new_val;

                      new_val = bottom[b] + mask_val * (top[b] - bottom[b]);

                      dest[b] = affect[b] ? MIN (new_val, 1.0) : bottom[b];
                    }
                }

              /* 3: mask_val AND s1_a both approach 0+, regardless of s2_a  */
              else if (s1_a + mask_val == 0.0)
                {
                  for (b = 0; b < 3; b++)
                    dest[b] = bottom[b];
                }

              /* 4: mask_val -->1 AND s2_a -->0, regardless of s1_a */
              else if (1.0 - mask_val + s2_a == 0.0)
                {
                  for (b = 0; b < 3; b++)
                    dest[b] = affect[b] ? top[b] : bottom[b];
                }
            }
          else
            {
              gdouble a_recip = 1.0 / a_val;

              /* possible optimization: fold a_recip into s1_a and s2_a */
              for (b = 0; b < 3; b++)
                {
                  gfloat new_val = a_recip * (bottom[b] * s1_a + mask_val *
                                              (top[b] * s2_a - bottom[b] * s1_a));
                  dest[b] = affect[b] ? MIN (new_val, 1.0) : bottom[b];
                }
            }

          dest[3] = affect[3] ? a_val : s1_a;

          top    += 4;
          bottom += 4;
          mask   += 1;
          dest   += 4;
        }
    }
}
Пример #27
0
static gboolean
process (GeglOperation       *operation,
         GeglBuffer          *input,
         GeglBuffer          *output,
         const GeglRectangle *result,
         gint                 level)
{
  GeglOperationAreaFilter *area = GEGL_OPERATION_AREA_FILTER (operation);
  GeglProperties              *o    = GEGL_PROPERTIES (operation);

  GeglBuffer *dest, *dest_tmp;

  GeglRectangle  working_region;
  GeglRectangle *whole_region;

  GeglBufferIterator *iter;

  whole_region = gegl_operation_source_get_bounding_box (operation, "input");

  working_region.x      = result->x - area->left;
  working_region.width  = result->width + area->left + area->right;
  working_region.y      = result->y - area->top;
  working_region.height = result->height + area->top + area->bottom;

  gegl_rectangle_intersect (&working_region, &working_region, whole_region);

  dest_tmp = gegl_buffer_new (&working_region, babl_format ("Y' float"));

  iter = gegl_buffer_iterator_new (dest_tmp, &working_region, 0, babl_format ("Y' float"),
                                   GEGL_ACCESS_WRITE, GEGL_ABYSS_NONE);

  gegl_buffer_iterator_add (iter, input, &working_region, 0, babl_format ("Y' float"),
                            GEGL_ACCESS_READ, GEGL_ABYSS_NONE);

  while (gegl_buffer_iterator_next (iter))
    {
      gint    i;
      gfloat *data_out = iter->data[0];
      gfloat *data_in  = iter->data[1];

      for (i = 0; i < iter->length; i++)
        {
          /* compute sigmoidal transfer */
          gfloat val = *data_in;
          val = 1.0 / (1.0 + exp (-(SIGMOIDAL_BASE + (o->sharpness * SIGMOIDAL_RANGE)) * (val - 0.5)));
          val = val * o->brightness;
          *data_out = CLAMP (val, 0.0, 1.0);

          data_out +=1;
          data_in  +=1;
        }
    }

  dest = grey_blur_buffer (dest_tmp, o->glow_radius, result);

  iter = gegl_buffer_iterator_new (output, result, 0, babl_format ("RGBA float"),
                                   GEGL_ACCESS_WRITE, GEGL_ABYSS_NONE);

  gegl_buffer_iterator_add (iter, input, result, 0, babl_format ("RGBA float"),
                            GEGL_ACCESS_READ, GEGL_ABYSS_NONE);

  gegl_buffer_iterator_add (iter, dest, result, 0, babl_format ("Y' float"),
                            GEGL_ACCESS_READ, GEGL_ABYSS_NONE);

  while (gegl_buffer_iterator_next (iter))
    {
      gint    i;
      gfloat *data_out  = iter->data[0];
      gfloat *data_in   = iter->data[1];
      gfloat *data_blur = iter->data[2];

      for (i = 0; i < iter->length; i++)
        {
          gint c;
          for (c = 0; c < 3; c++)
            {
              gfloat tmp = (1.0 - data_in[c]) * (1.0 - *data_blur);
              data_out[c] = CLAMP (1.0 - tmp, 0.0, 1.0);
            }

          data_out[3] = data_in[3];

          data_out += 4;
          data_in  += 4;
          data_blur+= 1;
        }
    }

  g_object_unref (dest);
  g_object_unref (dest_tmp);

  return TRUE;
}
Пример #28
0
static gboolean
process (GeglOperation       *operation,
         GeglBuffer          *input,
         GeglBuffer          *output,
         const GeglRectangle *roi,
         gint                 level)
{
  GeglProperties       *o = GEGL_PROPERTIES (operation);
  AlParamsType    *params = (AlParamsType *) o->user_data;
  const Babl      *format = babl_format ("RGBA float");

  GeglSampler        *sampler;
  GeglBufferIterator *iter;
  gint                x, y;

  sampler = gegl_buffer_sampler_new_at_level (input, format,
                                              GEGL_SAMPLER_CUBIC, level);

  iter = gegl_buffer_iterator_new (output, roi, level, format,
                                   GEGL_ACCESS_WRITE, GEGL_ABYSS_NONE);

  gegl_buffer_iterator_add (iter, input, roi, level, format,
                            GEGL_ACCESS_READ, GEGL_ABYSS_NONE);

  while (gegl_buffer_iterator_next (iter))
    {
      gfloat *out_pixel = iter->data[0];
      gfloat *in_pixel  = iter->data[1];

      for (y = iter->roi->y; y < iter->roi->y + iter->roi->height; y++)
        {
          gdouble dy, dysqr;

          dy = -((gdouble) y - params->b + 0.5);
          dysqr = dy * dy;

          for (x = iter->roi->x; x < iter->roi->x + iter->roi->width; x++)
            {
              gdouble dx, dxsqr;

              dx = (gdouble) x - params->a + 0.5;
              dxsqr = dx * dx;

              if (dysqr < (params->bsqr - (params->bsqr * dxsqr) / params->asqr))
                {
                  /**
                   * If (x, y) is inside the affected region, we can find its original
                   * position and fetch the pixel with the sampler
                   */
                  gdouble ox, oy;
                  find_undistorted_pos (dx, dy, o->refraction_index, params,
                                        &ox, &oy);

                  gegl_sampler_get (sampler, ox + params->a, params->b - oy,
                                    NULL, out_pixel, GEGL_ABYSS_NONE);
                }
              else
                {
                  /**
                   * Otherwise (that is for pixels outside the lens), we could either leave
                   * the image data unchanged, or set it to a specified 'background_color',
                   * depending on the user input.
                   */
                  if (o->keep_surroundings)
                    memcpy (out_pixel, in_pixel, sizeof (gfloat) * 4);
                  else
                    memcpy (out_pixel, params->bg_color, sizeof (gfloat) * 4);
                }

              out_pixel += 4;
              in_pixel  += 4;
            }
        }
    }

  g_object_unref (sampler);

  return TRUE;
}
Пример #29
0
/**
 * gimp_color_transform_process_buffer:
 * @transform:
 * @src_format:
 * @src_rect:
 * @dest_format:
 * @dest_rect:
 *
 * This function transforms buffer into another buffer.
 *
 * Since: 2.10
 **/
void
gimp_color_transform_process_buffer (GimpColorTransform  *transform,
                                     GeglBuffer          *src_buffer,
                                     const GeglRectangle *src_rect,
                                     GeglBuffer          *dest_buffer,
                                     const GeglRectangle *dest_rect)
{
  GimpColorTransformPrivate *priv;
  GeglBufferIterator        *iter;
  gint                       total_pixels;
  gint                       done_pixels = 0;

  g_return_if_fail (GIMP_IS_COLOR_TRANSFORM (transform));
  g_return_if_fail (GEGL_IS_BUFFER (src_buffer));
  g_return_if_fail (GEGL_IS_BUFFER (dest_buffer));

  priv = transform->priv;

  if (src_rect)
    {
      total_pixels = src_rect->width * src_rect->height;
    }
  else
    {
      total_pixels = (gegl_buffer_get_width  (src_buffer) *
                      gegl_buffer_get_height (src_buffer));
    }

  if (src_buffer != dest_buffer)
    {
      const Babl *fish = NULL;

      if (babl_format_has_alpha (priv->dest_format))
        fish = babl_fish (priv->src_format,
                          priv->dest_format);

      iter = gegl_buffer_iterator_new (src_buffer, src_rect, 0,
                                       priv->src_format,
                                       GEGL_ACCESS_READ,
                                       GEGL_ABYSS_NONE);

      gegl_buffer_iterator_add (iter, dest_buffer, dest_rect, 0,
                                priv->dest_format,
                                GEGL_ACCESS_WRITE,
                                GEGL_ABYSS_NONE);

      while (gegl_buffer_iterator_next (iter))
        {
          /* make sure the alpha channel is copied too, lcms doesn't copy it */
          if (fish)
            babl_process (fish, iter->data[0], iter->data[1], iter->length);

          cmsDoTransform (priv->transform,
                          iter->data[0], iter->data[1], iter->length);

          done_pixels += iter->roi[0].width * iter->roi[0].height;

          g_signal_emit (transform, gimp_color_transform_signals[PROGRESS], 0,
                         (gdouble) done_pixels /
                         (gdouble) total_pixels);
        }
    }
  else
    {
      iter = gegl_buffer_iterator_new (src_buffer, src_rect, 0,
                                       priv->src_format,
                                       GEGL_ACCESS_READWRITE,
                                       GEGL_ABYSS_NONE);

      while (gegl_buffer_iterator_next (iter))
        {
          cmsDoTransform (priv->transform,
                          iter->data[0], iter->data[0], iter->length);

          done_pixels += iter->roi[0].width * iter->roi[0].height;

          g_signal_emit (transform, gimp_color_transform_signals[PROGRESS], 0,
                         (gdouble) done_pixels /
                         (gdouble) total_pixels);
        }
    }

  g_signal_emit (transform, gimp_color_transform_signals[PROGRESS], 0,
                 1.0);
}
GeglBuffer *
gimp_image_contiguous_region_by_color (GimpImage            *image,
                                       GimpDrawable         *drawable,
                                       gboolean              sample_merged,
                                       gboolean              antialias,
                                       gfloat                threshold,
                                       gboolean              select_transparent,
                                       GimpSelectCriterion   select_criterion,
                                       const GimpRGB        *color)
{
  /*  Scan over the image's active layer, finding pixels within the
   *  specified threshold from the given R, G, & B values.  If
   *  antialiasing is on, use the same antialiasing scheme as in
   *  fuzzy_select.  Modify the image's mask to reflect the
   *  additional selection
   */
  GeglBufferIterator *iter;
  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);
  g_return_val_if_fail (color != NULL, 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);

  gimp_rgba_get_pixel (color, format, start_col);

  if (has_alpha)
    {
      if (select_transparent)
        {
          /*  don't select transparancy if "color" isn't fully transparent
           */
          if (start_col[n_components - 1] > 0.0)
            select_transparent = FALSE;
        }
    }
  else
    {
      select_transparent = FALSE;
    }

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

  iter = gegl_buffer_iterator_new (src_buffer,
                                   NULL, 0, format,
                                   GEGL_BUFFER_READ, GEGL_ABYSS_NONE);

  gegl_buffer_iterator_add (iter, mask_buffer,
                            NULL, 0, babl_format ("Y float"),
                            GEGL_BUFFER_WRITE, GEGL_ABYSS_NONE);

  while (gegl_buffer_iterator_next (iter))
    {
      const gfloat *src   = iter->data[0];
      gfloat       *dest  = iter->data[1];
      gint          count = iter->length;

      while (count--)
        {
          /*  Find how closely the colors match  */
          *dest = pixel_difference (start_col, src,
                                    antialias,
                                    threshold,
                                    n_components,
                                    has_alpha,
                                    select_transparent,
                                    select_criterion);

          src  += n_components;
          dest += 1;
        }
    }

  return mask_buffer;
}