Esempio n. 1
0
static gboolean
preview_event_handler (GtkWidget *area,
                       GdkEvent  *event,
                       GtkWidget *preview)
{
  gint            pos;
  guchar         *buf;
  guint32         drawable_id;
  GimpRGB         color;
  GdkEventButton *button_event = (GdkEventButton *)event;

  buf = GIMP_PREVIEW_AREA (area)->buf;
  drawable_id = GIMP_DRAWABLE_PREVIEW (preview)->drawable->drawable_id;

  switch (event->type)
    {
    case GDK_BUTTON_PRESS:
      if (button_event->button == 2)
        {
          pos = event->button.x * gimp_drawable_bpp (drawable_id) +
                event->button.y * GIMP_PREVIEW_AREA (area)->rowstride;

          gimp_rgb_set_uchar (&color, buf[pos], buf[pos + 1], buf[pos + 2]);
          gimp_color_button_set_color (GIMP_COLOR_BUTTON (from_colorbutton),
                                       &color);
        }
      break;

   default:
      break;
    }

  return FALSE;
}
Esempio n. 2
0
static void
neon_preview_update (GimpPreview *preview)
{
    neon (GIMP_DRAWABLE_PREVIEW (preview)->drawable,
          evals.radius,
          evals.amount,
          preview);
}
Esempio n. 3
0
static void
sobel_preview_update (GimpPreview *preview)
{
  sobel (gimp_drawable_preview_get_drawable (GIMP_DRAWABLE_PREVIEW (preview)),
         bvals.horizontal,
         bvals.vertical,
         bvals.keep_sign,
         preview);
}
Esempio n. 4
0
// Combine wavelets with latest FFT result and show output in the preview widget
void wavelet_preview(PluginData *pd)
{
	int x, y, w, h;
	gimp_preview_get_position (GIMP_PREVIEW(pd->preview), &x, &y);
	gimp_preview_get_size (GIMP_PREVIEW(pd->preview), &w, &h);
	gimp_pixel_rgn_init (&pd->region, pd->drawable, 0, 0, pd->image_width, pd->image_height, FALSE, TRUE);
	wavelet_apply(pd, x, y, w, h);
	
	gimp_pixel_rgn_set_rect(&pd->region, pd->img_pixels, x, y, w, h);
	gimp_drawable_preview_draw_region(GIMP_DRAWABLE_PREVIEW(pd->preview), &pd->region);
}
Esempio n. 5
0
static void preview_update (GimpPreview *preview)
{
	GimpDrawable *drawable;
	gint          x, y;
	gint          width, height;
	GimpPixelRgn  srcPR;
	GimpPixelRgn  destPR;

	drawable = gimp_drawable_preview_get_drawable (GIMP_DRAWABLE_PREVIEW (preview));

	gimp_pixel_rgn_init ( &srcPR, drawable, 0, 0, drawable->width, drawable->height, FALSE, FALSE);
	gimp_pixel_rgn_init (&destPR, drawable, 0, 0, drawable->width, drawable->height, TRUE, TRUE);

	gimp_preview_get_position (preview, &x, &y);
	gimp_preview_get_size (preview, &width, &height);

	octave_region (&srcPR, &destPR, drawable->bpp, x, y, width, height);

	gimp_pixel_rgn_init (&destPR, drawable, x, y, width, height, FALSE, TRUE);
	gimp_drawable_preview_draw_region (GIMP_DRAWABLE_PREVIEW (preview), &destPR);
}
Esempio n. 6
0
static void
preview_update (GimpPreview *preview)
{
  GimpDrawable *drawable;
  gint          x1, x2;
  gint          y1, y2;
  gint          x, y;
  gint          width, height;
  gint          border;
  GimpPixelRgn  srcPR;
  GimpPixelRgn  destPR;

  drawable =
    gimp_drawable_preview_get_drawable (GIMP_DRAWABLE_PREVIEW (preview));

  gimp_pixel_rgn_init (&srcPR, drawable,
                       0, 0, drawable->width, drawable->height, FALSE, FALSE);
  gimp_pixel_rgn_init (&destPR, drawable,
                       0, 0, drawable->width, drawable->height, TRUE, TRUE);

  gimp_preview_get_position (preview, &x, &y);
  gimp_preview_get_size (preview, &width, &height);

  /* enlarge the region to avoid artefacts at the edges of the preview */
  border = 2.0 * c2g_params.radius + 0.5;
  
  if (border > width/2) border = width/2; //Speed up preview 
  x1 = MAX (0, x - border);
  y1 = MAX (0, y - border);
  x2 = MIN (x + width  + border, drawable->width);
  y2 = MIN (y + height + border, drawable->height);

  c2g_region (&srcPR, &destPR, drawable->bpp,
                  c2g_params.radius, c2g_params.amount, c2g_params.gamma,
                  x1, x2, y1, y2,
                  FALSE);

  gimp_pixel_rgn_init (&destPR, drawable, x, y, width, height, FALSE, TRUE);
  gimp_drawable_preview_draw_region (GIMP_DRAWABLE_PREVIEW (preview), &destPR);
}
Esempio n. 7
0
void
focusblur_fft_buffer_draw (FblurFftBuffer *fft)
{
  GimpDrawablePreview *preview;
  gboolean             dirty;
  guint8              *data;
  GimpPixelRgn         pr;

  if (! fft->source.preview)
    {
      preview = NULL;
      dirty = TRUE;
      data = fft->source.data;
    }
  else
    {
      preview = GIMP_DRAWABLE_PREVIEW (fft->source.preview);
      g_assert (preview != NULL);

      dirty = FALSE;
      data = fft->source.data_preview;
    }

  g_assert (data != NULL);

  gimp_pixel_rgn_init (&pr, fft->source.drawable,
                       fft->source.x1, fft->source.y1,
                       fft->source.width, fft->source.height, dirty, TRUE);
  gimp_pixel_rgn_set_rect (&pr, data,
                           fft->source.x1, fft->source.y1,
                           fft->source.width, fft->source.height);

  if (! preview)
    {
      gimp_drawable_flush (fft->source.drawable);
      gimp_drawable_merge_shadow (fft->source.drawable->drawable_id, TRUE);
      gimp_drawable_update (fft->source.drawable->drawable_id,
                            fft->source.x1, fft->source.y1,
                            fft->source.width, fft->source.height);

      /* this buffer has been dirty */
      focusblur_fft_buffer_clear_source (fft);
    }
  else
    {
      gimp_drawable_preview_draw_region (preview, &pr);

    }
}
Esempio n. 8
0
File: spread.c Progetto: Minoos/gimp
static void
spread_preview_update (GimpPreview *preview,
                       GtkWidget   *size)
{
  GimpDrawable   *drawable;
  SpreadParam_t   param;
  gint            x, y, bpp;
  guchar         *buffer, *dest;
  gint            x_off, y_off;
  gint            width, height;

  drawable =
    gimp_drawable_preview_get_drawable (GIMP_DRAWABLE_PREVIEW (preview));

  param.pft      = gimp_pixel_fetcher_new (drawable, FALSE);
  param.gr       = g_rand_new ();
  param.x_amount = (gimp_size_entry_get_refval (GIMP_SIZE_ENTRY (size),
                                                0) + 1) / 2;
  param.y_amount = (gimp_size_entry_get_refval (GIMP_SIZE_ENTRY (size),
                                                1) + 1) / 2;
  param.width    = drawable->width;
  param.height   = drawable->height;

  gimp_preview_get_size (preview, &width, &height);

  bpp = drawable->bpp;
  dest = buffer = g_new (guchar, width * height * bpp);

  gimp_preview_get_position (preview, &x_off, &y_off);

  for (y = 0 ; y < height ; y++)
    for (x = 0 ; x < width ; x++)
      {
        spread_func (x + x_off, y + y_off, dest, bpp, &param);
        dest += bpp;
      }

  gimp_preview_draw_buffer (preview, buffer, width * bpp);

  g_free (buffer);
  g_rand_free (param.gr);
}
Esempio n. 9
0
static void
mblur_zoom (GimpDrawable *drawable,
            GimpPreview  *preview,
            gint          x1,
            gint          y1,
            gint          width,
            gint          height)
{
  GimpPixelRgn      dest_rgn;
  GimpPixelFetcher *pft;
  gpointer          pr;
  GimpRGB           background;

  gdouble   center_x;
  gdouble   center_y;
  guchar   *dest, *d;
  guchar    pixel[4];
  guchar    p1[4], p2[4], p3[4], p4[4];
  gint32    sum[4];

  gint      progress, max_progress;
  gint      x, y, i, n, p, c;
  gdouble   xx_start, xx_end, yy_start, yy_end;
  gdouble   xx, yy;
  gdouble   dxx, dyy;
  gdouble   dx, dy;
  gint      xy_len;
  gdouble   f, r;
  gint      drawable_x1, drawable_y1;
  gint      drawable_x2, drawable_y2;

  /* initialize */

  xx = 0.0;
  yy = 0.0;
  center_x = mbvals.center_x;
  center_y = mbvals.center_y;

  gimp_drawable_mask_bounds (drawable->drawable_id,
                             &drawable_x1, &drawable_y1,
                             &drawable_x2, &drawable_y2);
  gimp_pixel_rgn_init (&dest_rgn, drawable,
                       x1, y1, width, height, (preview == NULL), TRUE);

  pft = gimp_pixel_fetcher_new (drawable, FALSE);

  gimp_context_get_background (&background);
  gimp_pixel_fetcher_set_bg_color (pft, &background);

  progress     = 0;
  max_progress = width * height;

  n = mbvals.length;

  if (n == 0)
    n = 1;

  r = sqrt (SQR (drawable->width / 2) + SQR (drawable->height / 2));
  n = ((gdouble) n * r / MBLUR_LENGTH_MAX);
  f = (r-n)/r;

  for (pr = gimp_pixel_rgns_register (1, &dest_rgn), p = 0;
       pr != NULL;
       pr = gimp_pixel_rgns_process (pr), p++)
    {
      dest = dest_rgn.data;

      for (y = dest_rgn.y; y < dest_rgn.y + dest_rgn.h; y++)
        {
          d = dest;

          for (x = dest_rgn.x; x < dest_rgn.x + dest_rgn.w; x++)
            {
              for (c = 0; c < img_bpp; c++)
                sum[c] = 0;

              xx_start = x;
              yy_start = y;

              if (mbvals.blur_outward)
                {
                  xx_end = center_x + ((gdouble) x - center_x) * f;
                  yy_end = center_y + ((gdouble) y - center_y) * f;
                }
              else
                {
                  xx_end = center_x + ((gdouble) x - center_x) * (1.0/f);
                  yy_end = center_y + ((gdouble) y - center_y) * (1.0/f);
                }

              xy_len = sqrt (SQR (xx_end-xx_start) + SQR (yy_end-yy_start)) + 1;

              if (xy_len < 3)
                xy_len = 3;

              dxx = (xx_end - xx_start) / (gdouble) xy_len;
              dyy = (yy_end - yy_start) / (gdouble) xy_len;

              xx = xx_start;
              yy = yy_start;

              for (i = 0; i < xy_len; i++)
                {
                  if ((yy < drawable_y1) || (yy >= drawable_y2) ||
                      (xx < drawable_x1) || (xx >= drawable_x2))
                    break;

                  if ((xx+1 < drawable_x2) && (yy+1 < drawable_y2))
                    {
                      dx = xx - floor (xx);
                      dy = yy - floor (yy);

                      gimp_pixel_fetcher_get_pixel (pft, xx,   yy,   p1);
                      gimp_pixel_fetcher_get_pixel (pft, xx+1, yy,   p2);
                      gimp_pixel_fetcher_get_pixel (pft, xx,   yy+1, p3);
                      gimp_pixel_fetcher_get_pixel (pft, xx+1, yy+1, p4);

                      for (c = 0; c < img_bpp; c++)
                        {
                          pixel[c] = (((gdouble)p1[c] * (1.0-dx) +
                                       (gdouble)p2[c] * dx) * (1.0-dy) +
                                      ((gdouble)p3[c] * (1.0-dx) +
                                       (gdouble)p4[c] * dx) * dy);
                        }
                    }
                  else
                    {
                      gimp_pixel_fetcher_get_pixel (pft, xx+.5, yy+.5, pixel);
                    }

                  if (has_alpha)
                    {
                      gint32 alpha = pixel[img_bpp-1];

                      sum[img_bpp-1] += alpha;

                      for (c = 0; c < img_bpp-1; c++)
                        sum[c] += pixel[c] * alpha;
                    }
                  else
                    {
                      for (c = 0; c < img_bpp; c++)
                        sum[c] += pixel[c];
                    }

                  xx += dxx;
                  yy += dyy;
                }

              if (i == 0)
                {
                  gimp_pixel_fetcher_get_pixel (pft, xx, yy, d);
                }
              else
                {
                  if (has_alpha)
                    {
                      gint32 alpha = sum[img_bpp-1];

                      if ((d[img_bpp-1] = alpha/i) != 0)
                        {
                          for (c = 0; c < img_bpp-1; c++)
                            d[c] = sum[c] / alpha;
                        }
                    }
                  else
                    {
                      for (c = 0; c < img_bpp; c++)
                        d[c] = sum[c] / i;
                    }
                }

              d += dest_rgn.bpp;
            }

          dest += dest_rgn.rowstride;
        }

      if (preview)
        {
          gimp_drawable_preview_draw_region (GIMP_DRAWABLE_PREVIEW (preview),
                                             &dest_rgn);
        }
      else
        {
          progress += dest_rgn.w * dest_rgn.h;

          if ((p % 8) == 0)
            gimp_progress_update ((gdouble) progress / max_progress);
        }
    }

  gimp_pixel_fetcher_destroy (pft);
}
Esempio n. 10
0
static void
mblur_radial (GimpDrawable *drawable,
              GimpPreview  *preview,
              gint          x1,
              gint          y1,
              gint          width,
              gint          height)
{
  GimpPixelRgn      dest_rgn;
  GimpPixelFetcher *pft;
  gpointer          pr;
  GimpRGB           background;

  gdouble   center_x;
  gdouble   center_y;
  guchar   *dest;
  guchar   *d;
  guchar    pixel[4];
  guchar    p1[4], p2[4], p3[4], p4[4];
  gint32    sum[4];

  gint      progress, max_progress, c;

  gint      x, y, i, p, n, count;
  gdouble   angle, theta, r, xx, yy, xr, yr;
  gdouble   phi, phi_start, s_val, c_val;
  gdouble   dx, dy;

  /* initialize */

  xx = 0.0;
  yy = 0.0;

  center_x = mbvals.center_x;
  center_y = mbvals.center_y;

  gimp_pixel_rgn_init (&dest_rgn, drawable,
                       x1, y1, width, height, (preview == NULL), TRUE);

  pft = gimp_pixel_fetcher_new (drawable, FALSE);

  gimp_context_get_background (&background);
  gimp_pixel_fetcher_set_bg_color (pft, &background);

  progress     = 0;
  max_progress = width * height;

  angle = gimp_deg_to_rad (mbvals.angle);

  for (pr = gimp_pixel_rgns_register (1, &dest_rgn), p = 0;
       pr != NULL;
       pr = gimp_pixel_rgns_process (pr), p++)
    {
      dest = dest_rgn.data;

      for (y = dest_rgn.y; y < dest_rgn.y + dest_rgn.h; y++)
        {
          d = dest;

          for (x = dest_rgn.x; x < dest_rgn.x + dest_rgn.w; x++)
            {
              xr = (gdouble) x - center_x;
              yr = (gdouble) y - center_y;

              r = sqrt (SQR (xr) + SQR (yr));
              n = r * angle;

              if (angle == 0.0)
                {
                  gimp_pixel_fetcher_get_pixel (pft, x, y, d);
                  d += dest_rgn.bpp;
                  continue;
                }

              /* ensure quality with small angles */
              if (n < 3)
                n = 3;  /* always use at least 3 (interpolation) steps */

              /* limit loop count due to performanc reasons */
              if (n > 100)
                n = 100 + sqrt (n-100);

              if (xr != 0.0)
                {
                  phi = atan(yr/xr);
                  if (xr < 0.0)
                    phi = G_PI + phi;

                }
              else
                {
                  if (yr >= 0.0)
                    phi = G_PI_2;
                  else
                    phi = -G_PI_2;
                }

              for (c = 0; c < img_bpp; c++)
                sum[c] = 0;

              if (n == 1)
                phi_start = phi;
              else
                phi_start = phi + angle/2.0;

              theta = angle / (gdouble)n;
              count = 0;

              for (i = 0; i < n; i++)
                {
                  s_val = sin (phi_start - (gdouble) i * theta);
                  c_val = cos (phi_start - (gdouble) i * theta);

                  xx = center_x + r * c_val;
                  yy = center_y + r * s_val;

                  if ((yy < y1) || (yy >= y1 + height) ||
                      (xx < x1) || (xx >= x1 + width))
                    continue;

                  ++count;
                  if ((xx + 1 < x1 + width) && (yy + 1 < y1 + height))
                    {
                      dx = xx - floor (xx);
                      dy = yy - floor (yy);

                      gimp_pixel_fetcher_get_pixel (pft, xx,   yy,   p1);
                      gimp_pixel_fetcher_get_pixel (pft, xx+1, yy,   p2);
                      gimp_pixel_fetcher_get_pixel (pft, xx,   yy+1, p3);
                      gimp_pixel_fetcher_get_pixel (pft, xx+1, yy+1, p4);

                      for (c = 0; c < img_bpp; c++)
                        {
                          pixel[c] = (((gdouble) p1[c] * (1.0-dx) +
                                       (gdouble) p2[c] * dx) * (1.0-dy) +
                                      ((gdouble) p3[c] * (1.0-dx) +
                                       (gdouble) p4[c] * dx) * dy);
                        }
                    }
                  else
                    {
                      gimp_pixel_fetcher_get_pixel (pft, xx+.5, yy+.5, pixel);
                    }

                  if (has_alpha)
                    {
                      gint32 alpha = pixel[img_bpp-1];

                      sum[img_bpp-1] += alpha;

                      for (c = 0; c < img_bpp-1; c++)
                        sum[c] += pixel[c] * alpha;
                    }
                  else
                    {
                      for (c = 0; c < img_bpp; c++)
                        sum[c] += pixel[c];
                    }
                }

              if (count == 0)
                {
                  gimp_pixel_fetcher_get_pixel (pft, xx, yy, d);
                }
              else
                {
                  if (has_alpha)
                    {
                      gint32 alpha = sum[img_bpp-1];

                      if ((d[img_bpp-1] = alpha/count) != 0)
                        {
                          for (c = 0; c < img_bpp-1; c++)
                            d[c] = sum[c] / alpha;
                        }
                    }
                  else
                    {
                      for (c = 0; c < img_bpp; c++)
                        d[c] = sum[c] / count;
                    }
                }

              d += dest_rgn.bpp;
            }

          dest += dest_rgn.rowstride;
        }

      if (preview)
        {
          gimp_drawable_preview_draw_region (GIMP_DRAWABLE_PREVIEW (preview),
                                             &dest_rgn);
        }
      else
        {
          progress += dest_rgn.w * dest_rgn.h;

          if ((p % 8) == 0)
            gimp_progress_update ((gdouble) progress / max_progress);
        }
    }

  gimp_pixel_fetcher_destroy (pft);

}
Esempio n. 11
0
static void
mblur_linear (GimpDrawable *drawable,
              GimpPreview  *preview,
              gint          x1,
              gint          y1,
              gint          width,
              gint          height)
{
  GimpPixelRgn      dest_rgn;
  GimpPixelFetcher *pft;
  gpointer          pr;
  GimpRGB           background;

  guchar *dest;
  guchar *d;
  guchar  pixel[4];
  gint32  sum[4];
  gint    progress, max_progress;
  gint    c, p;
  gint    x, y, i, xx, yy, n;
  gint    dx, dy, px, py, swapdir, err, e, s1, s2;

  gimp_pixel_rgn_init (&dest_rgn, drawable,
                       x1, y1, width, height, (preview == NULL), TRUE);

  pft = gimp_pixel_fetcher_new (drawable, FALSE);

  gimp_context_get_background (&background);
  gimp_pixel_fetcher_set_bg_color (pft, &background);

  progress     = 0;
  max_progress = width * height;

  n = mbvals.length;
  px = (gdouble) n * cos (mbvals.angle / 180.0 * G_PI);
  py = (gdouble) n * sin (mbvals.angle / 180.0 * G_PI);

  /*
   * Initialization for Bresenham algorithm:
   * dx = abs(x2-x1), s1 = sign(x2-x1)
   * dy = abs(y2-y1), s2 = sign(y2-y1)
   */
  if ((dx = px) != 0)
    {
      if (dx < 0)
        {
          dx = -dx;
          s1 = -1;
        }
      else
        s1 = 1;
    }
  else
    s1 = 0;

  if ((dy = py) != 0)
    {
      if (dy < 0)
        {
          dy = -dy;
          s2 = -1;
        }
      else
        s2 = 1;
    }
  else
    s2 = 0;

  if (dy > dx)
    {
      swapdir = dx;
      dx = dy;
      dy = swapdir;
      swapdir = 1;
    }
  else
    swapdir = 0;

  dy *= 2;
  err = dy - dx;        /* Initial error term   */
  dx *= 2;

  for (pr = gimp_pixel_rgns_register (1, &dest_rgn), p = 0;
       pr != NULL;
       pr = gimp_pixel_rgns_process (pr), p++)
    {
      dest = dest_rgn.data;

      for (y = dest_rgn.y; y < dest_rgn.y + dest_rgn.h; y++)
        {
          d = dest;

          for (x = dest_rgn.x; x < dest_rgn.x + dest_rgn.w; x++)
            {
              xx = x; yy = y; e = err;
              for (c = 0; c < img_bpp; c++)
                sum[c]= 0;

              for (i = 0; i < n; )
                {
                  gimp_pixel_fetcher_get_pixel (pft, xx, yy, pixel);

                  if (has_alpha)
                    {
                      gint32 alpha = pixel[img_bpp-1];

                      sum[img_bpp-1] += alpha;
                      for (c = 0; c < img_bpp-1; c++)
                        sum[c] += pixel[c] * alpha;
                    }
                  else
                    {
                      for (c = 0; c < img_bpp; c++)
                        sum[c] += pixel[c];
                    }
                  i++;

                  while (e >= 0 && dx)
                    {
                      if (swapdir)
                        xx += s1;
                      else
                        yy += s2;
                      e -= dx;
                    }

                  if (swapdir)
                    yy += s2;
                  else
                    xx += s1;

                  e += dy;

                  if ((xx < x1) || (xx >= x1 + width) ||
                      (yy < y1) || (yy >= y1 + height))
                    break;
                }

              if (i == 0)
                {
                  gimp_pixel_fetcher_get_pixel (pft, xx, yy, d);
                }
              else
                {
                  if (has_alpha)
                    {
                      gint32 alpha = sum[img_bpp-1];

                      if ((d[img_bpp-1] = alpha/i) != 0)
                        {
                          for (c = 0; c < img_bpp-1; c++)
                            d[c] = sum[c] / alpha;
                        }
                    }
                  else
                    {
                      for (c = 0; c < img_bpp; c++)
                        d[c] = sum[c] / i;
                    }
                }

              d += dest_rgn.bpp;
            }

          dest += dest_rgn.rowstride;
        }

      if (preview)
        {
          gimp_drawable_preview_draw_region (GIMP_DRAWABLE_PREVIEW (preview),
                                             &dest_rgn);
        }
      else
        {
          progress += dest_rgn.w * dest_rgn.h;

          if ((p % 8) == 0)
            gimp_progress_update ((gdouble) progress / max_progress);
        }
    }

  gimp_pixel_fetcher_destroy (pft);
}
Esempio n. 12
0
/*  -  Filter function  -  I wish all filter functions had a pmode :) */
static void
glasstile (GimpDrawable *drawable,
           GimpPreview  *preview)
{
  GimpPixelRgn  srcPR, destPR;
  gint          width, height;
  gint          bytes;
  guchar       *dest, *d;
  guchar       *cur_row;
  gint          row, col, i;
  gint          x1, y1, x2, y2;

  /* Translations of variable names from Maswan
   * rutbredd = grid width
   * ruthojd = grid height
   * ymitt = y middle
   * xmitt = x middle
   */

  gint rutbredd, xpixel1, xpixel2;
  gint ruthojd , ypixel2;
  gint xhalv, xoffs, xmitt, xplus;
  gint yhalv, yoffs, ymitt, yplus;

  if (preview)
    {
      gimp_preview_get_position (preview, &x1, &y1);
      gimp_preview_get_size (preview, &width, &height);
      x2 = x1 + width;
      y2 = y1 + height;
    }
  else
    {
      gimp_drawable_mask_bounds (drawable->drawable_id, &x1, &y1, &x2, &y2);
      width  = x2 - x1;
      height = y2 - y1;
    }
  bytes  = drawable->bpp;

  cur_row = g_new (guchar, width * bytes);
  dest    = g_new (guchar, width * bytes);

  /* initialize the pixel regions, set grid height/width */
  gimp_pixel_rgn_init (&srcPR, drawable,
                        x1, y1, width, height,
                        FALSE, FALSE);
  gimp_pixel_rgn_init (&destPR, drawable,
                       x1, y1, width, height,
                       preview == NULL, TRUE);

  rutbredd = gtvals.xblock;
  ruthojd  = gtvals.yblock;

  xhalv = rutbredd / 2;
  yhalv = ruthojd  / 2;

  xplus = rutbredd % 2;
  yplus = ruthojd  % 2;

  ymitt = y1;
  yoffs = 0;

  /*  Loop through the rows */
  for (row = y1; row < y2; row++)
    {
      d = dest;

      ypixel2 = ymitt + yoffs * 2;
      ypixel2 = CLAMP (ypixel2, 0, y2 - 1);

      gimp_pixel_rgn_get_row (&srcPR, cur_row, x1, ypixel2, width);
      yoffs++;

      /* if current offset = half, do a displacement next time around */
      if (yoffs == yhalv)
        {
          ymitt += ruthojd;
          yoffs = - (yhalv + yplus);
        }

      xmitt = 0;
      xoffs = 0;

      for (col = 0; col < x2 - x1; col++) /* one pixel */
        {
          xpixel1 = (xmitt + xoffs) * bytes;
          xpixel2 = (xmitt + xoffs * 2) * bytes;

          if (xpixel2 < (x2 - x1) * bytes)
            {
              if (xpixel2 < 0)
                xpixel2 = 0;
              for (i = 0; i < bytes; i++)
                d[xpixel1 + i] = cur_row[xpixel2 + i];
            }
          else
            {
              for (i = 0; i < bytes; i++)
                d[xpixel1 + i] = cur_row[xpixel1 + i];
            }

          xoffs++;

          if (xoffs == xhalv)
            {
              xmitt += rutbredd;
              xoffs = - (xhalv + xplus);
            }
        }

      /*  Store the dest  */
      gimp_pixel_rgn_set_row (&destPR, dest, x1, row, width);

      if (!preview && ((row % 5) == 0))
        {
          gimp_progress_update ((gdouble) row / (gdouble) height);
        }
    }

  /*  Update region  */
  if (preview)
    {
      gimp_drawable_preview_draw_region (GIMP_DRAWABLE_PREVIEW (preview),
                                         &destPR);
    }
  else
    {
      gimp_progress_update (1.0);
      gimp_drawable_flush (drawable);
      gimp_drawable_merge_shadow (drawable->drawable_id, TRUE);
      gimp_drawable_update (drawable->drawable_id,
                            x1, y1, width, height);
    }

  g_free (cur_row);
  g_free (dest);
}
Esempio n. 13
0
static void
value_propagate_body (GimpDrawable *drawable,
                      GimpPreview  *preview)
{
  GimpImageType  dtype;
  ModeParam      operation;
  GimpPixelRgn   srcRgn, destRgn;
  guchar        *here, *best, *dest;
  guchar        *dest_row, *prev_row, *cur_row, *next_row;
  guchar        *pr, *cr, *nr, *swap;
  gint           width, height, bytes, index;
  gint           begx, begy, endx, endy, x, y, dx;
  gint           left_index, right_index, up_index, down_index;
  gpointer       tmp;
  GimpRGB        foreground;

  /* calculate neighbors' indexes */
  left_index  = (vpvals.direction_mask & (1 << Left2Right)) ? -1 : 0;
  right_index = (vpvals.direction_mask & (1 << Right2Left)) ?  1 : 0;
  up_index    = (vpvals.direction_mask & (1 << Top2Bottom)) ? -1 : 0;
  down_index  = (vpvals.direction_mask & (1 << Bottom2Top)) ?  1 : 0;
  operation   = modes[vpvals.propagate_mode];
  tmp         = NULL;

  dtype = gimp_drawable_type (drawable->drawable_id);
  bytes = drawable->bpp;

  /* Here I use the algorithm of blur.c */
  if (preview)
    {
       gimp_preview_get_position (preview, &begx, &begy);
       gimp_preview_get_size (preview, &width, &height);

       endx = begx + width;
       endy = begy + height;
    }
  else
    {
      if (! gimp_drawable_mask_intersect (drawable->drawable_id,
                                          &begx, &begy, &width, &height))
        return;

      endx = begx + width;
      endy = begy + height;
    }

  gimp_tile_cache_ntiles (2 * ((width) / gimp_tile_width () + 1));

  prev_row = g_new (guchar, (width + 2) * bytes);
  cur_row  = g_new (guchar, (width + 2) * bytes);
  next_row = g_new (guchar, (width + 2) * bytes);
  dest_row = g_new (guchar, width * bytes);

  gimp_pixel_rgn_init (&srcRgn, drawable,
                       begx, begy, width, height,
                       FALSE, FALSE);
  gimp_pixel_rgn_init (&destRgn, drawable,
                       begx, begy, width, height,
                       (preview == NULL), TRUE);

  pr = prev_row + bytes;
  cr = cur_row + bytes;
  nr = next_row + bytes;

  prepare_row (&srcRgn, pr, begx, (0 < begy) ? begy : begy - 1, endx-begx);
  prepare_row (&srcRgn, cr, begx, begy, endx-begx);

  best = g_new (guchar, bytes);

  if (!preview)
    gimp_progress_init (_("Value Propagate"));

  gimp_context_get_foreground (&foreground);
  gimp_rgb_get_uchar (&foreground, fore+0, fore+1, fore+2);

  /* start real job */
  for (y = begy ; y < endy ; y++)
    {
      prepare_row (&srcRgn, nr, begx, ((y+1) < endy) ? y+1 : endy, endx-begx);

      for (index = 0; index < (endx - begx) * bytes; index++)
        dest_row[index] = cr[index];

      for (x = 0 ; x < endx - begx; x++)
        {
          dest = dest_row + (x * bytes);
          here = cr + (x * bytes);

          /* *** copy source value to best value holder *** */
          memcpy (best, here, bytes);

          if (operation.initializer)
            (* operation.initializer)(dtype, bytes, best, here, &tmp);

          /* *** gather neighbors' values: loop-unfolded version *** */
          if (up_index == -1)
            for (dx = left_index ; dx <= right_index ; dx++)
              (* operation.updater)(dtype, bytes, here, pr+((x+dx)*bytes), best, tmp);
          for (dx = left_index ; dx <= right_index ; dx++)
            if (dx != 0)
              (* operation.updater)(dtype, bytes, here, cr+((x+dx)*bytes), best, tmp);
          if (down_index == 1)
            for (dx = left_index ; dx <= right_index ; dx++)
              (* operation.updater)(dtype, bytes, here, nr+((x+dx)*bytes), best, tmp);
          /* *** store it to dest_row*** */
          (* operation.finalizer)(dtype, bytes, best, here, dest, tmp);
        }

      /* now store destline to destRgn */
      gimp_pixel_rgn_set_row (&destRgn, dest_row, begx, y, endx - begx);

      /* shift the row pointers  */
      swap = pr;
      pr = cr;
      cr = nr;
      nr = swap;


      if (((y % 16) == 0) && !preview)
        gimp_progress_update ((gdouble) y / (gdouble) (endy - begy));
    }

  if (preview)
    {
      gimp_drawable_preview_draw_region (GIMP_DRAWABLE_PREVIEW (preview),
                                         &destRgn);
    }
  else
    {
      /*  update the region  */
      gimp_progress_update (1.0);
      gimp_drawable_flush (drawable);
      gimp_drawable_merge_shadow (drawable->drawable_id, TRUE);
      gimp_drawable_update (drawable->drawable_id, begx, begy, endx-begx, endy-begy);
    }
}
Esempio n. 14
0
static void
randomize (GimpDrawable *drawable,
           GimpPreview  *preview)
{
  GimpPixelRgn srcPR, destPR, destPR2, *sp, *dp, *tp;
  gint width, height;
  gint bytes;
  guchar *dest, *d;
  guchar *prev_row, *pr;
  guchar *cur_row, *cr;
  guchar *next_row, *nr;
  guchar *tmp;
  gint row, col;
  gint x, y;
  gint cnt;
  gint i, j, k;

  if (preview)
    {
      gimp_preview_get_position (preview, &x, &y);
      gimp_preview_get_size (preview, &width, &height);
    }
  else
    {
      if (! gimp_drawable_mask_intersect (drawable->drawable_id,
                                          &x, &y, &width, &height))
        return;
    }

  bytes = drawable->bpp;

  /*
   *  allocate row buffers
   */
  prev_row = g_new (guchar, (width + 2) * bytes);
  cur_row = g_new (guchar, (width + 2) * bytes);
  next_row = g_new (guchar, (width + 2) * bytes);
  dest = g_new (guchar, width * bytes);

  /*
   *  initialize the pixel regions
   */
  gimp_pixel_rgn_init (&srcPR, drawable, x, y, width, height, FALSE, FALSE);
  gimp_pixel_rgn_init (&destPR, drawable, x, y, width, height, TRUE, TRUE);
  gimp_pixel_rgn_init (&destPR2, drawable, x, y, width, height, TRUE, TRUE);
  sp = &srcPR;
  dp = &destPR;
  tp = NULL;

  pr = prev_row + bytes;
  cr = cur_row + bytes;
  nr = next_row + bytes;

  for (cnt = 1; cnt <= pivals.rndm_rcount; cnt++)
    {
      /*
       *  prepare the first row and previous row
       */
      randomize_prepare_row (sp, pr, x, y - 1, width);
      randomize_prepare_row (sp, cr, x, y, width);
      /*
       *  loop through the rows, applying the selected convolution
       */
      for (row = y; row < y + height; row++)
        {
          /*  prepare the next row  */
          randomize_prepare_row (sp, nr, x, row + 1, width);

          d = dest;
          for (col = 0; col < width; col++)
            {
              if (g_rand_int_range (gr, 0, 100) <= (gint) pivals.rndm_pct)
                {
                  switch (rndm_type)
                    {
                      /*
                       *  HURL
                       *      Just assign a random value.
                       */
                    case RNDM_HURL:
                      for (j = 0; j < bytes; j++)
                        *d++ = g_rand_int_range (gr, 0, 256);
                      break;
                      /*
                       *  PICK
                       *      pick at random from a neighboring pixel.
                       */
                    case RNDM_PICK:
                      k = g_rand_int_range (gr, 0, 9);
                      for (j = 0; j < bytes; j++)
                        {
                          i = col * bytes + j;

                          switch (k)
                            {
                            case 0:
                              *d++ = (gint) pr[i - bytes];
                              break;
                            case 1:
                              *d++ = (gint) pr[i];
                              break;
                            case 2:
                              *d++ = (gint) pr[i + bytes];
                              break;
                            case 3:
                              *d++ = (gint) cr[i - bytes];
                              break;
                            case 4:
                              *d++ = (gint) cr[i];
                              break;
                            case 5:
                              *d++ = (gint) cr[i + bytes];
                              break;
                            case 6:
                              *d++ = (gint) nr[i - bytes];
                              break;
                            case 7:
                              *d++ = (gint) nr[i];
                              break;
                            case 8:
                              *d++ = (gint) nr[i + bytes];
                              break;
                            }
                        }
                      break;
                      /*
                       *  SLUR
                       *      80% chance it's from directly above,
                       *      10% from above left,
                       *      10% from above right.
                       */
                    case RNDM_SLUR:
                      k = g_rand_int_range (gr, 0, 10);
                      for (j = 0; j < bytes; j++)
                        {
                          i = col*bytes + j;

                          switch (k )
                            {
                            case 0:
                              *d++ = (gint) pr[i - bytes];
                              break;
                            case 9:
                              *d++ = (gint) pr[i + bytes];
                              break;
                            default:
                              *d++ = (gint) pr[i];
                              break;
                            }
                        }
                      break;
                    }
                  /*
                   *  Otherwise, this pixel was not selected for randomization,
                   *  so use the current value.
                   */
                }
              else
                {
                  for (j = 0; j < bytes; j++)
                    *d++ = (gint) cr[col*bytes + j];
                }
            }
          /*
           *  Save the modified row, shuffle the row pointers, and every
           *  so often, update the progress meter.
           */
          gimp_pixel_rgn_set_row (dp, dest, x, row, width);

          tmp = pr;
          pr = cr;
          cr = nr;
          nr = tmp;

          if (! preview && PROG_UPDATE_TIME)
            {
              gdouble base = (gdouble) cnt / pivals.rndm_rcount;
              gdouble inc  = (gdouble) row / (height * pivals.rndm_rcount);

              gimp_progress_update (base + inc);
            }
        }

      /*
       *  if we have more cycles to perform, swap the src and dest Pixel Regions
       */
      if (cnt < pivals.rndm_rcount)
        {
          if (tp != NULL)
            {
              tp = dp;
              dp = sp;
              sp = tp;
            }
          else
            {
              tp = &srcPR;
              sp = &destPR;
              dp = &destPR2;
            }
        }
    }

  if (! preview)
    gimp_progress_update (1.0);

  /*
   *  update the randomized region
   */
  if (preview)
    {
      gimp_drawable_preview_draw_region (GIMP_DRAWABLE_PREVIEW (preview),
                                         dp);
    }
  else
    {
      gimp_drawable_flush (drawable);
      gimp_drawable_merge_shadow (drawable->drawable_id, TRUE);
      gimp_drawable_update (drawable->drawable_id, x, y, width, height);
    }

  /*
   *  clean up after ourselves.
   */
  g_free (prev_row);
  g_free (cur_row);
  g_free (next_row);
  g_free (dest);
}
Esempio n. 15
0
/*
 * Photocopy algorithm
 * -----------------
 * Mask radius = radius of pixel neighborhood for intensity comparison
 * Threshold   = relative intensity difference which will result in darkening
 * Ramp        = amount of relative intensity difference before total black
 * Blur radius = mask radius / 3.0
 *
 * Algorithm:
 * For each pixel, calculate pixel intensity value to be: avg (blur radius)
 * relative diff = pixel intensity / avg (mask radius)
 * If relative diff < Threshold
 *   intensity mult = (Ramp - MIN (Ramp, (Threshold - relative diff))) / Ramp
 *   pixel intensity *= intensity mult
 * Else
 *   pixel intensity = white
 */
static void
photocopy (GimpDrawable *drawable,
           GimpPreview  *preview)
{
  GimpPixelRgn  src_rgn, dest_rgn;
  GimpPixelRgn *pr;
  gint          width, height;
  gint          bytes;
  gboolean      has_alpha;
  guchar       *dest1;
  guchar       *dest2;
  guchar       *src1, *sp_p1, *sp_m1;
  guchar       *src2, *sp_p2, *sp_m2;
  gdouble       n_p1[5], n_m1[5];
  gdouble       n_p2[5], n_m2[5];
  gdouble       d_p1[5], d_m1[5];
  gdouble       d_p2[5], d_m2[5];
  gdouble       bd_p1[5], bd_m1[5];
  gdouble       bd_p2[5], bd_m2[5];
  gdouble      *val_p1, *val_m1, *vp1, *vm1;
  gdouble      *val_p2, *val_m2, *vp2, *vm2;
  gint          x1, y1;
  gint          i, j;
  gint          row, col;
  gint          terms;
  gint          progress, max_progress;
  gint          initial_p1[4];
  gint          initial_p2[4];
  gint          initial_m1[4];
  gint          initial_m2[4];
  gdouble       radius;
  gdouble       val;
  gdouble       std_dev1;
  gdouble       std_dev2;
  gdouble       ramp_down;
  gdouble       ramp_up;

  if (preview)
    {
      gimp_preview_get_position (preview, &x1, &y1);
      gimp_preview_get_size (preview, &width, &height);
    }
  else
    {
      gint x2, y2;

      gimp_drawable_mask_bounds (drawable->drawable_id, &x1, &y1, &x2, &y2);

      width  = x2 - x1;
      height = y2 - y1;
    }

  bytes     = drawable->bpp;
  has_alpha = gimp_drawable_has_alpha (drawable->drawable_id);

  val_p1 = g_new (gdouble, MAX (width, height));
  val_p2 = g_new (gdouble, MAX (width, height));
  val_m1 = g_new (gdouble, MAX (width, height));
  val_m2 = g_new (gdouble, MAX (width, height));

  dest1 = g_new0 (guchar, width * height);
  dest2 = g_new0 (guchar, width * height);

  progress = 0;
  max_progress = width * height * 3;

  gimp_pixel_rgn_init (&src_rgn, drawable,
                       x1, y1, width, height, FALSE, FALSE);

  for (pr = gimp_pixel_rgns_register (1, &src_rgn);
       pr != NULL;
       pr = gimp_pixel_rgns_process (pr))
    {
      guchar *src_ptr  = src_rgn.data;
      guchar *dest_ptr = dest1 + (src_rgn.y - y1) * width + (src_rgn.x - x1);

      for (row = 0; row < src_rgn.h; row++)
        {
          for (col = 0; col < src_rgn.w; col++)
            {
              /* desaturate */
              if (bytes > 2)
                dest_ptr[col] = (guchar) gimp_rgb_to_l_int (src_ptr[col * bytes + 0],
                                                            src_ptr[col * bytes + 1],
                                                            src_ptr[col * bytes + 2]);
              else
                dest_ptr[col] = (guchar) src_ptr[col * bytes];

              /* compute  transfer */
              val = pow (dest_ptr[col], (1.0 / GAMMA));
              dest_ptr[col] = (guchar) CLAMP (val, 0, 255);
            }

          src_ptr  += src_rgn.rowstride;
          dest_ptr += width;
        }

      if (!preview)
        {
          progress += src_rgn.w * src_rgn.h;
          gimp_progress_update ((gdouble) progress / (gdouble) max_progress);
        }
    }

  /*  Calculate the standard deviations  */
  radius   = MAX (1.0, 10 * (1.0 - pvals.sharpness));
  radius   = fabs (radius) + 1.0;
  std_dev1 = sqrt (-(radius * radius) / (2 * log (1.0 / 255.0)));

  radius   = fabs (pvals.mask_radius) + 1.0;
  std_dev2 = sqrt (-(radius * radius) / (2 * log (1.0 / 255.0)));

  /*  derive the constants for calculating the gaussian from the std dev  */
  find_constants (n_p1, n_m1, d_p1, d_m1, bd_p1, bd_m1, std_dev1);
  find_constants (n_p2, n_m2, d_p2, d_m2, bd_p2, bd_m2, std_dev2);

  /*  First the vertical pass  */
  for (col = 0; col < width; col++)
    {
      memset (val_p1, 0, height * sizeof (gdouble));
      memset (val_p2, 0, height * sizeof (gdouble));
      memset (val_m1, 0, height * sizeof (gdouble));
      memset (val_m2, 0, height * sizeof (gdouble));

      src1  = dest1 + col;
      sp_p1 = src1;
      sp_m1 = src1 + (height - 1) * width;
      vp1   = val_p1;
      vp2   = val_p2;
      vm1   = val_m1 + (height - 1);
      vm2   = val_m2 + (height - 1);

      /*  Set up the first vals  */
      initial_p1[0] = sp_p1[0];
      initial_m1[0] = sp_m1[0];

      for (row = 0; row < height; row++)
        {
          gdouble *vpptr1, *vmptr1;
          gdouble *vpptr2, *vmptr2;

          terms = (row < 4) ? row : 4;

          vpptr1 = vp1; vmptr1 = vm1;
          vpptr2 = vp2; vmptr2 = vm2;

          for (i = 0; i <= terms; i++)
            {
              *vpptr1 += n_p1[i] * sp_p1[-i * width] - d_p1[i] * vp1[-i];
              *vmptr1 += n_m1[i] * sp_m1[i * width] - d_m1[i] * vm1[i];

              *vpptr2 += n_p2[i] * sp_p1[-i * width] - d_p2[i] * vp2[-i];
              *vmptr2 += n_m2[i] * sp_m1[i * width] - d_m2[i] * vm2[i];
            }

          for (j = i; j <= 4; j++)
            {
              *vpptr1 += (n_p1[j] - bd_p1[j]) * initial_p1[0];
              *vmptr1 += (n_m1[j] - bd_m1[j]) * initial_m1[0];

              *vpptr2 += (n_p2[j] - bd_p2[j]) * initial_p1[0];
              *vmptr2 += (n_m2[j] - bd_m2[j]) * initial_m1[0];
            }

          sp_p1 += width;
          sp_m1 -= width;
          vp1   += 1;
          vp2   += 1;
          vm1   -= 1;
          vm2   -= 1;
        }

      transfer_pixels (val_p1, val_m1, dest1 + col, width, height);
      transfer_pixels (val_p2, val_m2, dest2 + col, width, height);

      if (!preview)
        {
          progress += height;
          if ((col % 5) == 0)
            gimp_progress_update ((gdouble) progress / (gdouble) max_progress);
        }
    }

  for (row = 0; row < height; row++)
    {
      memset (val_p1, 0, width * sizeof (gdouble));
      memset (val_p2, 0, width * sizeof (gdouble));
      memset (val_m1, 0, width * sizeof (gdouble));
      memset (val_m2, 0, width * sizeof (gdouble));

      src1 = dest1 + row * width;
      src2 = dest2 + row * width;

      sp_p1 = src1;
      sp_p2 = src2;
      sp_m1 = src1 + width - 1;
      sp_m2 = src2 + width - 1;
      vp1   = val_p1;
      vp2   = val_p2;
      vm1   = val_m1 + width - 1;
      vm2   = val_m2 + width - 1;

      /*  Set up the first vals  */
      initial_p1[0] = sp_p1[0];
      initial_p2[0] = sp_p2[0];
      initial_m1[0] = sp_m1[0];
      initial_m2[0] = sp_m2[0];

      for (col = 0; col < width; col++)
        {
          gdouble *vpptr1, *vmptr1;
          gdouble *vpptr2, *vmptr2;

          terms = (col < 4) ? col : 4;

          vpptr1 = vp1; vmptr1 = vm1;
          vpptr2 = vp2; vmptr2 = vm2;

          for (i = 0; i <= terms; i++)
            {
              *vpptr1 += n_p1[i] * sp_p1[-i] - d_p1[i] * vp1[-i];
              *vmptr1 += n_m1[i] * sp_m1[i] - d_m1[i] * vm1[i];

              *vpptr2 += n_p2[i] * sp_p2[-i] - d_p2[i] * vp2[-i];
              *vmptr2 += n_m2[i] * sp_m2[i] - d_m2[i] * vm2[i];
            }

          for (j = i; j <= 4; j++)
            {
              *vpptr1 += (n_p1[j] - bd_p1[j]) * initial_p1[0];
              *vmptr1 += (n_m1[j] - bd_m1[j]) * initial_m1[0];

              *vpptr2 += (n_p2[j] - bd_p2[j]) * initial_p2[0];
              *vmptr2 += (n_m2[j] - bd_m2[j]) * initial_m2[0];
            }

          sp_p1 ++;
          sp_p2 ++;
          sp_m1 --;
          sp_m2 --;
          vp1 ++;
          vp2 ++;
          vm1 --;
          vm2 --;
        }

      transfer_pixels (val_p1, val_m1, dest1 + row * width, 1, width);
      transfer_pixels (val_p2, val_m2, dest2 + row * width, 1, width);

      if (!preview)
        {
          progress += width;
          if ((row % 5) == 0)
            gimp_progress_update ((gdouble) progress / (gdouble) max_progress);
        }
    }

  /* Compute the ramp value which sets 'pct_black' % of the darkened pixels black */
  ramp_down = compute_ramp (dest1, dest2, width * height, pvals.pct_black, 1);
  ramp_up   = compute_ramp (dest1, dest2, width * height, 1.0 - pvals.pct_white, 0);

  /* Initialize the pixel regions. */
  gimp_pixel_rgn_init (&src_rgn, drawable, x1, y1, width, height, FALSE, FALSE);
  gimp_pixel_rgn_init (&dest_rgn, drawable, x1, y1, width, height,
                       (preview == NULL), TRUE);

  pr = gimp_pixel_rgns_register (2, &src_rgn, &dest_rgn);

  while (pr)
    {
      guchar  *src_ptr  = src_rgn.data;
      guchar  *dest_ptr = dest_rgn.data;
      guchar  *blur_ptr = dest1 + (src_rgn.y - y1) * width + (src_rgn.x - x1);
      guchar  *avg_ptr  = dest2 + (src_rgn.y - y1) * width + (src_rgn.x - x1);
      gdouble  diff, mult;
      gdouble  lightness = 0.0;

      for (row = 0; row < src_rgn.h; row++)
        {
          for (col = 0; col < src_rgn.w; col++)
            {
              if (avg_ptr[col] > EPSILON)
                {
                  diff = (gdouble) blur_ptr[col] / (gdouble) avg_ptr[col];

                  if (diff < pvals.threshold)
                    {
                      if (ramp_down == 0.0)
                        mult = 0.0;
                      else
                        mult = (ramp_down - MIN (ramp_down,
                                                 (pvals.threshold - diff))) / ramp_down;
                      lightness = CLAMP (blur_ptr[col] * mult, 0, 255);
                    }
                  else
                    {
                      if (ramp_up == 0.0)
                        mult = 1.0;
                      else
                        mult = MIN (ramp_up,
                                    (diff - pvals.threshold)) / ramp_up;

                      lightness = 255 - (1.0 - mult) * (255 - blur_ptr[col]);
                      lightness = CLAMP (lightness, 0, 255);
                    }
                }
              else
                {
                  lightness = 0;
                }

              if (bytes < 3)
                {
                  dest_ptr[col * bytes] = (guchar) lightness;
                  if (has_alpha)
                    dest_ptr[col * bytes + 1] = src_ptr[col * src_rgn.bpp + 1];
                }
              else
                {
                  dest_ptr[col * bytes + 0] = lightness;
                  dest_ptr[col * bytes + 1] = lightness;
                  dest_ptr[col * bytes + 2] = lightness;

                  if (has_alpha)
                    dest_ptr[col * bytes + 3] = src_ptr[col * src_rgn.bpp + 3];
                }
            }

          src_ptr  += src_rgn.rowstride;
          dest_ptr += dest_rgn.rowstride;
          blur_ptr += width;
          avg_ptr  += width;
        }

      if (preview)
        {
          gimp_drawable_preview_draw_region (GIMP_DRAWABLE_PREVIEW (preview),
                                             &dest_rgn);
        }
      else
        {
          progress += src_rgn.w * src_rgn.h;
          gimp_progress_update ((gdouble) progress / (gdouble) max_progress);
        }

      pr = gimp_pixel_rgns_process (pr);
    }

  if (! preview)
    {
      /*  merge the shadow, update the drawable  */
      gimp_drawable_flush (drawable);
      gimp_drawable_merge_shadow (drawable->drawable_id, TRUE);
      gimp_drawable_update (drawable->drawable_id, x1, y1, width, height);
    }

  /*  free up buffers  */
  g_free (val_p1);
  g_free (val_p2);
  g_free (val_m1);
  g_free (val_m2);
  g_free (dest1);
  g_free (dest2);
}
Esempio n. 16
0
/* do the exchanging */
static void
exchange (GimpDrawable *drawable,
          GimpPreview  *preview)
{
  GimpPixelRgn  srcPR, destPR;
  guchar        min_red,  min_green,  min_blue;
  guchar        max_red,  max_green,  max_blue;
  guchar        from_red, from_green, from_blue;
  guchar        to_red,   to_green,   to_blue;
  guchar       *src_row, *dest_row;
  gint          x, y, bpp = drawable->bpp;
  gboolean      has_alpha;
  gint          x1, y1, y2;
  gint          width, height;
  GimpRGB       min;
  GimpRGB       max;

  if (preview)
    {
      gimp_preview_get_position (preview, &x1, &y1);
      gimp_preview_get_size (preview, &width, &height);
    }
  else if (! gimp_drawable_mask_intersect (drawable->drawable_id,
                                           &x1, &y1, &width, &height))
    {
      return;
    }

  y2 = y1 + height;

  has_alpha = gimp_drawable_has_alpha (drawable->drawable_id);
  /* allocate memory */
  src_row = g_new (guchar, drawable->width * bpp);

  gimp_rgb_get_uchar (&xargs.from, &from_red, &from_green, &from_blue);
  gimp_rgb_get_uchar (&xargs.to,   &to_red,   &to_green,   &to_blue);

  /* get boundary values */
  min = xargs.from;
  gimp_rgb_subtract (&min, &xargs.threshold);
  gimp_rgb_clamp (&min);
  gimp_rgb_get_uchar (&min, &min_red, &min_green, &min_blue);

  max = xargs.from;
  gimp_rgb_add (&max, &xargs.threshold);
  gimp_rgb_clamp (&max);
  gimp_rgb_get_uchar (&max, &max_red, &max_green, &max_blue);

  dest_row = g_new (guchar, drawable->width * bpp);

  gimp_pixel_rgn_init (&srcPR, drawable,
                       x1, y1, width, height, FALSE, FALSE);
  gimp_pixel_rgn_init (&destPR, drawable,
                       x1, y1, width, height, (preview == NULL), TRUE);

  for (y = y1; y < y2; y++)
    {
      gimp_pixel_rgn_get_row (&srcPR, src_row, x1, y, width);

      for (x = 0; x < width; x++)
        {
          guchar pixel_red, pixel_green, pixel_blue;
          guchar new_red, new_green, new_blue;
          guint  idx;

          /* get current pixel-values */
          pixel_red   = src_row[x * bpp];
          pixel_green = src_row[x * bpp + 1];
          pixel_blue  = src_row[x * bpp + 2];

          idx = x * bpp;

          /* want this pixel? */
          if (pixel_red >= min_red &&
              pixel_red <= max_red &&
              pixel_green >= min_green &&
              pixel_green <= max_green &&
              pixel_blue >= min_blue &&
              pixel_blue <= max_blue)
            {
              guchar red_delta, green_delta, blue_delta;

              red_delta   = pixel_red > from_red ?
                pixel_red - from_red : from_red - pixel_red;
              green_delta = pixel_green > from_green ?
                pixel_green - from_green : from_green - pixel_green;
              blue_delta  = pixel_blue > from_blue ?
                pixel_blue - from_blue : from_blue - pixel_blue;

              new_red   = CLAMP (to_red   + red_delta,   0, 255);
              new_green = CLAMP (to_green + green_delta, 0, 255);
              new_blue  = CLAMP (to_blue  + blue_delta,  0, 255);
            }
          else
            {
              new_red   = pixel_red;
              new_green = pixel_green;
              new_blue  = pixel_blue;
            }

          /* fill buffer */
          dest_row[idx + 0] = new_red;
          dest_row[idx + 1] = new_green;
          dest_row[idx + 2] = new_blue;

          /* copy alpha-channel */
          if (has_alpha)
            dest_row[idx + 3] = src_row[x * bpp + 3];
        }
      /* store the dest */
      gimp_pixel_rgn_set_row (&destPR, dest_row, x1, y, width);

      /* and tell the user what we're doing */
      if (!preview && (y % 10) == 0)
        gimp_progress_update ((gdouble) y / (gdouble) height);
    }

  g_free (src_row);
  g_free (dest_row);

  if (preview)
    {
      gimp_drawable_preview_draw_region (GIMP_DRAWABLE_PREVIEW (preview),
                                         &destPR);
    }
  else
    {
      gimp_progress_update (1.0);
      /* update the processed region */
      gimp_drawable_flush (drawable);
      gimp_drawable_merge_shadow (drawable->drawable_id, TRUE);
      gimp_drawable_update (drawable->drawable_id, x1, y1, width, height);
    }
}
Esempio n. 17
0
static void
shift (GimpDrawable *drawable,
       GimpPreview  *preview)
{
  GimpPixelRgn      dest_rgn;
  gpointer          pr;
  GimpPixelFetcher *pft;
  gint              width, height;
  gint              bytes;
  guchar           *destline;
  guchar           *dest;
  gint              x1, y1, x2, y2;
  gint              x, y;
  gint              progress, max_progress;
  gint              i, n = 0;
  gint             *offsets;
  GRand            *gr;

  if (preview)
    {
      gimp_preview_get_position (preview, &x1, &y1);
      gimp_preview_get_size (preview, &width, &height);
    }
  else
    {
      gimp_drawable_mask_bounds (drawable->drawable_id, &x1, &y1, &x2, &y2);
      width  = x2 - x1;
      height = y2 - y1;
    }

  bytes  = drawable->bpp;

  progress     = 0;
  max_progress = width * height;

  /* Shift the image.  It's a pretty simple algorithm.  If horizontal
     is selected, then every row is shifted a random number of pixels
     in the range of -shift_amount/2 to shift_amount/2.  The effect is
     just reproduced with columns if vertical is selected.
   */

  n = (shvals.orientation == HORIZONTAL) ? height : width;

  offsets = g_new (gint, n);
  gr = g_rand_new ();

  for (i = 0; i < n; i++)
    offsets[i] = g_rand_int_range (gr,
                                   - (shvals.shift_amount + 1) / 2.0,
                                   + (shvals.shift_amount + 1) / 2.0);

  g_rand_free (gr);

  pft = gimp_pixel_fetcher_new (drawable, FALSE);
  gimp_pixel_fetcher_set_edge_mode (pft, GIMP_PIXEL_FETCHER_EDGE_WRAP);

  gimp_pixel_rgn_init (&dest_rgn, drawable,
                       x1, y1, width, height, (preview == NULL), TRUE);

  for (pr = gimp_pixel_rgns_register (1, &dest_rgn);
       pr != NULL;
       pr = gimp_pixel_rgns_process (pr))
    {
      destline = dest_rgn.data;

      switch (shvals.orientation)
        {
        case HORIZONTAL:
          for (y = dest_rgn.y; y < dest_rgn.y + dest_rgn.h; y++)
            {
              dest = destline;

              for (x = dest_rgn.x; x < dest_rgn.x + dest_rgn.w; x++)
                {
                  gimp_pixel_fetcher_get_pixel (pft,
                                                x + offsets[y - y1], y, dest);
                  dest += bytes;
                }

              destline += dest_rgn.rowstride;
            }
          break;

        case VERTICAL:
          for (x = dest_rgn.x; x < dest_rgn.x + dest_rgn.w; x++)
            {
              dest = destline;

              for (y = dest_rgn.y; y < dest_rgn.y + dest_rgn.h; y++)
                {
                  gimp_pixel_fetcher_get_pixel (pft,
                                                x, y + offsets[x - x1], dest);
                  dest += dest_rgn.rowstride;
                }

              destline += bytes;
            }
          break;
        }

      if (preview)
        {
          gimp_drawable_preview_draw_region (GIMP_DRAWABLE_PREVIEW (preview),
                                             &dest_rgn);
        }
      else
        {
          progress += dest_rgn.w * dest_rgn.h;
          gimp_progress_update ((double) progress / (double) max_progress);
        }
    }

  gimp_pixel_fetcher_destroy (pft);
  g_free (offsets);

  if (! preview)
    {
      gimp_progress_update (1.0);
      /*  update the region  */
      gimp_drawable_flush (drawable);
      gimp_drawable_merge_shadow (drawable->drawable_id, TRUE);
      gimp_drawable_update (drawable->drawable_id, x1, y1, width, height);
    }
}
Esempio n. 18
0
static void
softglow (GimpDrawable *drawable,
          GimpPreview  *preview)
{
  GimpPixelRgn  src_rgn, dest_rgn;
  GimpPixelRgn *pr;
  gint          width, height;
  gint          bytes;
  gboolean      has_alpha;
  guchar       *dest;
  guchar       *src, *sp_p, *sp_m;
  gdouble       n_p[5], n_m[5];
  gdouble       d_p[5], d_m[5];
  gdouble       bd_p[5], bd_m[5];
  gdouble      *val_p, *val_m, *vp, *vm;
  gint          x1, y1, x2, y2;
  gint          i, j;
  gint          row, col, b;
  gint          terms;
  gint          progress, max_progress;
  gint          initial_p[4];
  gint          initial_m[4];
  gint          tmp;
  gdouble       radius;
  gdouble       std_dev;
  gdouble       val;

  if (preview)
    {
      gimp_preview_get_position (preview, &x1, &y1);
      gimp_preview_get_size (preview, &width, &height);
      x2 = x1 + width;
      y2 = y1 + height;
    }
  else
    {
      gimp_drawable_mask_bounds (drawable->drawable_id, &x1, &y1, &x2, &y2);
      width     = (x2 - x1);
      height    = (y2 - y1);
    }

  bytes     = drawable->bpp;
  has_alpha = gimp_drawable_has_alpha (drawable->drawable_id);

  val_p = g_new (gdouble, MAX (width, height));
  val_m = g_new (gdouble, MAX (width, height));

  dest = g_new0 (guchar, width * height);

  progress = 0;
  max_progress = width * height * 3;

  /* Initialize the pixel regions. */
  gimp_pixel_rgn_init (&src_rgn, drawable, x1, y1, width, height, FALSE, FALSE);

  for (pr = gimp_pixel_rgns_register (1, &src_rgn);
       pr != NULL;
       pr = gimp_pixel_rgns_process (pr))
    {
      guchar *src_ptr  = src_rgn.data;
      guchar *dest_ptr = dest + (src_rgn.y - y1) * width + (src_rgn.x - x1);

      for (row = 0; row < src_rgn.h; row++)
        {
          for (col = 0; col < src_rgn.w; col++)
            {
              /* desaturate */
              if (bytes > 2)
                dest_ptr[col] = (guchar) gimp_rgb_to_l_int (src_ptr[col * bytes + 0],
                                                            src_ptr[col * bytes + 1],
                                                            src_ptr[col * bytes + 2]);
              else
                dest_ptr[col] = (guchar) src_ptr[col * bytes];

              /* compute sigmoidal transfer */
              val = dest_ptr[col] / 255.0;
              val = 255.0 / (1 + exp (-(SIGMOIDAL_BASE + (svals.sharpness * SIGMOIDAL_RANGE)) * (val - 0.5)));
              val = val * svals.brightness;
              dest_ptr[col] = (guchar) CLAMP (val, 0, 255);
            }

          src_ptr  += src_rgn.rowstride;
          dest_ptr += width;
        }

      if (!preview)
        {
          progress += src_rgn.w * src_rgn.h;
          gimp_progress_update ((gdouble) progress / (gdouble) max_progress);
        }
    }

  /*  Calculate the standard deviations  */
  radius  = fabs (svals.glow_radius) + 1.0;
  std_dev = sqrt (-(radius * radius) / (2 * log (1.0 / 255.0)));

  /*  derive the constants for calculating the gaussian from the std dev  */
  find_constants (n_p, n_m, d_p, d_m, bd_p, bd_m, std_dev);

  /*  First the vertical pass  */
  for (col = 0; col < width; col++)
    {
      memset (val_p, 0, height * sizeof (gdouble));
      memset (val_m, 0, height * sizeof (gdouble));

      src  = dest + col;
      sp_p = src;
      sp_m = src + width * (height - 1);
      vp   = val_p;
      vm   = val_m + (height - 1);

      /*  Set up the first vals  */
      initial_p[0] = sp_p[0];
      initial_m[0] = sp_m[0];

      for (row = 0; row < height; row++)
        {
          gdouble *vpptr, *vmptr;

          terms = (row < 4) ? row : 4;

          vpptr = vp; vmptr = vm;
          for (i = 0; i <= terms; i++)
            {
              *vpptr += n_p[i] * sp_p[-i * width] - d_p[i] * vp[-i];
              *vmptr += n_m[i] * sp_m[i * width] - d_m[i] * vm[i];
            }
          for (j = i; j <= 4; j++)
            {
              *vpptr += (n_p[j] - bd_p[j]) * initial_p[0];
              *vmptr += (n_m[j] - bd_m[j]) * initial_m[0];
            }

          sp_p += width;
          sp_m -= width;
          vp ++;
          vm --;
        }

      transfer_pixels (val_p, val_m, dest + col, width, height);

      if (!preview)
        {
          progress += height;
          if ((col % 5) == 0)
            gimp_progress_update ((gdouble) progress / (gdouble) max_progress);
        }
    }

  for (row = 0; row < height; row++)
    {
      memset (val_p, 0, width * sizeof (gdouble));
      memset (val_m, 0, width * sizeof (gdouble));

      src = dest + row * width;

      sp_p = src;
      sp_m = src + width - 1;
      vp = val_p;
      vm = val_m + width - 1;

      /*  Set up the first vals  */
      initial_p[0] = sp_p[0];
      initial_m[0] = sp_m[0];

      for (col = 0; col < width; col++)
        {
          gdouble *vpptr, *vmptr;

          terms = (col < 4) ? col : 4;

          vpptr = vp; vmptr = vm;

          for (i = 0; i <= terms; i++)
            {
              *vpptr += n_p[i] * sp_p[-i] - d_p[i] * vp[-i];
              *vmptr += n_m[i] * sp_m[i] - d_m[i] * vm[i];
            }

          for (j = i; j <= 4; j++)
            {
              *vpptr += (n_p[j] - bd_p[j]) * initial_p[0];
              *vmptr += (n_m[j] - bd_m[j]) * initial_m[0];
            }

          sp_p ++;
          sp_m --;
          vp ++;
          vm --;
        }

      transfer_pixels (val_p, val_m, dest + row * width, 1, width);

      if (!preview)
        {
          progress += width;
          if ((row % 5) == 0)
            gimp_progress_update ((gdouble) progress / (gdouble) max_progress);
        }
    }

  /* Initialize the pixel regions. */
  gimp_pixel_rgn_init (&src_rgn, drawable, x1, y1, width, height, FALSE, FALSE);
  gimp_pixel_rgn_init (&dest_rgn, drawable,
                       x1, y1, width, height, (preview == NULL), TRUE);

  for (pr = gimp_pixel_rgns_register (2, &src_rgn, &dest_rgn);
       pr != NULL;
       pr = gimp_pixel_rgns_process (pr))
    {
      guchar *src_ptr  = src_rgn.data;
      guchar *dest_ptr = dest_rgn.data;
      guchar *blur_ptr = dest + (src_rgn.y - y1) * width + (src_rgn.x - x1);

      for (row = 0; row < src_rgn.h; row++)
        {
          for (col = 0; col < src_rgn.w; col++)
            {
              /* screen op */
              for (b = 0; b < (has_alpha ? (bytes - 1) : bytes); b++)
                dest_ptr[col * bytes + b] =
                  255 - INT_MULT((255 - src_ptr[col * bytes + b]),
                                 (255 - blur_ptr[col]), tmp);
              if (has_alpha)
                dest_ptr[col * bytes + b] = src_ptr[col * bytes + b];
            }

          src_ptr  += src_rgn.rowstride;
          dest_ptr += dest_rgn.rowstride;
          blur_ptr += width;
        }

      if (preview)
        {
          gimp_drawable_preview_draw_region (GIMP_DRAWABLE_PREVIEW (preview),
                                             &dest_rgn);
        }
      else
        {
          progress += src_rgn.w * src_rgn.h;
          gimp_progress_update ((gdouble) progress / (gdouble) max_progress);
        }
    }

  if (! preview)
    {
      /*  merge the shadow, update the drawable  */
      gimp_drawable_flush (drawable);
      gimp_drawable_merge_shadow (drawable->drawable_id, TRUE);
      gimp_drawable_update (drawable->drawable_id,
                            x1, y1, (x2 - x1), (y2 - y1));
    }

  /*  free up buffers  */
  g_free (val_p);
  g_free (val_m);
  g_free (dest);
}
Esempio n. 19
0
static void
edge_preview_update (GimpPreview *preview)
{
  /* drawable */
  GimpDrawable *drawable;
  glong         bytes;
  gint          alpha;
  gboolean      has_alpha;

  /* preview */
  guchar       *src           = NULL; /* Buffer to hold source image */
  guchar       *render_buffer = NULL; /* Buffer to hold rendered image */
  guchar       *dest;
  gint          width;                /* Width of preview widget */
  gint          height;               /* Height of preview widget */
  gint          x1;                   /* Upper-left X of preview */
  gint          y1;                   /* Upper-left Y of preview */
  GimpPixelRgn  srcPR;                /* Pixel regions */

  /* algorithm */
  gint x, y;

  /* Get drawable info */
  drawable =
    gimp_drawable_preview_get_drawable (GIMP_DRAWABLE_PREVIEW (preview));
  bytes  = gimp_drawable_bpp (drawable->drawable_id);
  alpha  = bytes;
  has_alpha = gimp_drawable_has_alpha (drawable->drawable_id);
  if (has_alpha)
    alpha--;

  /*
   * Setup for filter...
   */
  gimp_preview_get_position (preview, &x1, &y1);
  gimp_preview_get_size (preview, &width, &height);

  /* initialize pixel regions */
  gimp_pixel_rgn_init (&srcPR, drawable,
                       x1, y1, width, height, FALSE, FALSE);
  src = g_new (guchar, width * height * bytes);
  render_buffer = g_new (guchar, width * height * bytes);

  /* render image */
  gimp_pixel_rgn_get_rect(&srcPR, src, x1, y1, width, height);
  dest = render_buffer;

  /* render algorithm */
  for (y = 0 ; y < height ; y++)
    for (x = 0 ; x < width ; x++)
      {
        gint chan;
        for (chan = 0; chan < alpha; chan++)
          {
            guchar kernel[9];

#define SRC(X,Y) src[bytes * (CLAMP((X), 0, width-1) + \
                              width * CLAMP((Y), 0, height-1)) + chan]

            kernel[0] = SRC (x - 1, y - 1);
            kernel[1] = SRC (x - 1, y    );
            kernel[2] = SRC (x - 1, y + 1);
            kernel[3] = SRC (x    , y - 1);
            kernel[4] = SRC (x    , y    );
            kernel[5] = SRC (x    , y + 1);
            kernel[6] = SRC (x + 1, y - 1);
            kernel[7] = SRC (x + 1, y    );
            kernel[8] = SRC (x + 1, y + 1);

#undef SRC
            dest[chan] = edge_detect (kernel);
          }
        if (has_alpha)
          dest[alpha] = src[bytes * (x + width * y) + alpha];
        dest += bytes;
      }
  /*
   * Draw the preview image on the screen...
   */
  gimp_preview_draw_buffer (preview, render_buffer, width * bytes);

  g_free (render_buffer);
  g_free (src);
}
Esempio n. 20
0
static void
preview_update (GimpPreview *preview)
{
  GimpDrawable *drawable;
  GimpPixelRgn  src_rgn;        /* Source image region */
  guchar       *src_ptr;        /* Current source pixel */
  guchar       *dst_ptr;        /* Current destination pixel */
  intneg       *neg_ptr;        /* Current negative pixel */
  gint          i;              /* Looping var */
  gint          y;              /* Current location in image */
  gint          width;          /* Byte width of the image */
  gint          x1, y1;
  gint          preview_width, preview_height;
  guchar       *preview_src, *preview_dst;
  intneg       *preview_neg;
  gint          img_bpp;        /* Bytes-per-pixel in image */

  void          (*filter)(int, guchar *, guchar *, intneg *, intneg *, intneg *);

  filter = NULL;

  compute_luts();

  gimp_preview_get_position (preview, &x1, &y1);
  gimp_preview_get_size (preview, &preview_width, &preview_height);

  drawable =
    gimp_drawable_preview_get_drawable (GIMP_DRAWABLE_PREVIEW (preview));

  img_bpp = gimp_drawable_bpp (drawable->drawable_id);


  preview_src = g_new (guchar, preview_width * preview_height * img_bpp);
  preview_neg = g_new (intneg, preview_width * preview_height * img_bpp);
  preview_dst = g_new (guchar, preview_width * preview_height * img_bpp);

  gimp_pixel_rgn_init (&src_rgn, drawable,
                       x1, y1, preview_width, preview_height,
                       FALSE, FALSE);

  width = preview_width * img_bpp;

  /*
   * Load the preview area...
   */

  gimp_pixel_rgn_get_rect (&src_rgn, preview_src, x1, y1,
                           preview_width, preview_height);

  for (i = width * preview_height, src_ptr = preview_src, neg_ptr = preview_neg;
       i > 0;
       i --)
    *neg_ptr++ = neg_lut[*src_ptr++];

  /*
   * Select the filter...
   */

  switch (img_bpp)
    {
    case 1:
      filter = gray_filter;
      break;
    case 2:
      filter = graya_filter;
      break;
    case 3:
      filter = rgb_filter;
      break;
    case 4:
      filter = rgba_filter;
      break;
    default:
      g_error ("Programmer stupidity error: img_bpp is %d\n",
               img_bpp);
    }

  /*
   * Sharpen...
   */

  memcpy (preview_dst, preview_src, width);
  memcpy (preview_dst + width * (preview_height - 1),
          preview_src + width * (preview_height - 1),
          width);

  for (y = preview_height - 2, src_ptr = preview_src + width,
           neg_ptr = preview_neg + width + img_bpp,
           dst_ptr = preview_dst + width;
       y > 0;
       y --, src_ptr += width, neg_ptr += width, dst_ptr += width)
    (*filter)(preview_width, src_ptr, dst_ptr, neg_ptr - width,
              neg_ptr, neg_ptr + width);

  gimp_preview_draw_buffer (preview, preview_dst, preview_width * img_bpp);

  g_free (preview_src);
  g_free (preview_neg);
  g_free (preview_dst);
}
Esempio n. 21
0
/*
 * For all x and y as requested, replace the pixel at (x,y)
 * with a weighted average of the most frequently occurring
 * values in a circle of mask_size diameter centered at (x,y).
 */
static void
oilify (GimpDrawable *drawable,
        GimpPreview  *preview)
{
  gboolean      use_inten;
  gboolean      use_msmap = FALSE;
  gboolean      use_emap = FALSE;
  GimpDrawable *mask_size_map_drawable = NULL;
  GimpDrawable *exponent_map_drawable = NULL;
  GimpPixelRgn  mask_size_map_rgn;
  GimpPixelRgn  exponent_map_rgn;
  gint          msmap_bpp = 0;
  gint          emap_bpp = 0;
  GimpPixelRgn  dest_rgn;
  GimpPixelRgn *regions[3];
  gint          n_regions;
  gint          bpp;
  gint         *sqr_lut;
  gint          x1, y1, x2, y2;
  gint          width, height;
  gint          Hist[HISTSIZE];
  gint          Hist_rgb[4][HISTSIZE];
  gpointer      pr;
  gint          progress, max_progress;
  guchar       *src_buf;
  guchar       *src_inten_buf = NULL;
  gint          i;

  use_inten = (ovals.mode == MODE_INTEN);

  /*  Get the selection bounds  */
  if (preview)
    {
      gimp_preview_get_position (preview, &x1, &y1);
      gimp_preview_get_size (preview, &width, &height);

      x2 = x1 + width;
      y2 = y1 + height;
    }
  else
    {
      gimp_drawable_mask_bounds (drawable->drawable_id, &x1, &y1, &x2, &y2);
      width  = x2 - x1;
      height = y2 - y1;
    }

  progress = 0;
  max_progress = width * height;

  bpp = drawable->bpp;

  /*
   * Look-up-table implementation of the square function, for use in the
   * VERY TIGHT inner loops
   */
  {
    gint lut_size = (gint) ovals.mask_size / 2 + 1;

    sqr_lut = g_new (gint, lut_size);

    for (i = 0; i < lut_size; i++)
      sqr_lut[i] = SQR (i);
  }

  /*  Get the map drawables, if applicable  */

  if (ovals.use_mask_size_map && ovals.mask_size_map >= 0)
    {
      use_msmap = TRUE;

      mask_size_map_drawable = gimp_drawable_get (ovals.mask_size_map);
      gimp_pixel_rgn_init (&mask_size_map_rgn, mask_size_map_drawable,
                           x1, y1, width, height, FALSE, FALSE);

      msmap_bpp = mask_size_map_drawable->bpp;
    }

  if (ovals.use_exponent_map && ovals.exponent_map >= 0)
    {
      use_emap = TRUE;

      exponent_map_drawable = gimp_drawable_get (ovals.exponent_map);
      gimp_pixel_rgn_init (&exponent_map_rgn, exponent_map_drawable,
                           x1, y1, width, height, FALSE, FALSE);

      emap_bpp = exponent_map_drawable->bpp;
    }

  gimp_pixel_rgn_init (&dest_rgn, drawable,
                       x1, y1, width, height, (preview == NULL), TRUE);

  {
    GimpPixelRgn src_rgn;

    gimp_pixel_rgn_init (&src_rgn, drawable,
                         x1, y1, width, height, FALSE, FALSE);
    src_buf = g_new (guchar, width * height * bpp);
    gimp_pixel_rgn_get_rect (&src_rgn, src_buf, x1, y1, width, height);
  }

  /*
   * If we're working in intensity mode, then generate a separate intensity
   * map of the source image. This way, we can avoid calculating the
   * intensity of any given source pixel more than once.
   */
  if (use_inten)
    {
      guchar *src;
      guchar *dest;

      src_inten_buf = g_new (guchar, width * height);

      for (i = 0,
           src = src_buf,
           dest = src_inten_buf
           ;
           i < (width * height)
           ;
           i++,
           src += bpp,
           dest++)
        {
          *dest = (guchar) GIMP_RGB_LUMINANCE (src[0], src[1], src[2]);
        }
    }

  n_regions = 0;
  regions[n_regions++] = &dest_rgn;
  if (use_msmap)
    regions[n_regions++] = &mask_size_map_rgn;
  if (use_emap)
    regions[n_regions++] = &exponent_map_rgn;

  for (pr = gimp_pixel_rgns_register2 (n_regions, regions);
       pr != NULL;
       pr = gimp_pixel_rgns_process (pr))
    {
      gint    y;
      guchar *dest_row;
      guchar *src_msmap_row = NULL;
      guchar *src_emap_row = NULL;

      for (y = dest_rgn.y,
           dest_row = dest_rgn.data,
           src_msmap_row = mask_size_map_rgn.data,  /* valid iff use_msmap */
           src_emap_row = exponent_map_rgn.data     /* valid iff use_emap */
           ;
           y < (gint) (dest_rgn.y + dest_rgn.h)
           ;
           y++,
           dest_row += dest_rgn.rowstride,
           src_msmap_row += mask_size_map_rgn.rowstride,  /* valid iff use_msmap */
           src_emap_row += exponent_map_rgn.rowstride)    /* valid iff use_emap */
        {
          gint    x;
          guchar *dest;
          guchar *src_msmap = NULL;
          guchar *src_emap = NULL;

          for (x = dest_rgn.x,
               dest = dest_row,
               src_msmap = src_msmap_row,  /* valid iff use_msmap */
               src_emap = src_emap_row     /* valid iff use_emap */
               ;
               x < (gint) (dest_rgn.x + dest_rgn.w)
               ;
               x++,
               dest += bpp,
               src_msmap += msmap_bpp,  /* valid iff use_msmap */
               src_emap += emap_bpp)    /* valid iff use_emap */
            {
              gint    radius, radius_squared;
              gfloat  exponent;
              gint    mask_x1, mask_y1;
              gint    mask_x2, mask_y2;
              gint    mask_y;
              gint    src_offset;
              guchar *src_row;
              guchar *src_inten_row = NULL;

              if (use_msmap)
                {
                  gfloat factor = get_map_value (src_msmap, msmap_bpp);

                  radius = ROUND (factor * (0.5 * ovals.mask_size));
                }
              else
                {
                  radius = (gint) ovals.mask_size / 2;
                }

              radius_squared = SQR (radius);

              exponent = ovals.exponent;
              if (use_emap)
                exponent *= get_map_value (src_emap, emap_bpp);

              if (use_inten)
                memset (Hist, 0, sizeof (Hist));

              memset (Hist_rgb, 0, sizeof (Hist_rgb));

              mask_x1 = CLAMP ((x - radius), x1, x2);
              mask_y1 = CLAMP ((y - radius), y1, y2);
              mask_x2 = CLAMP ((x + radius + 1), x1, x2);
              mask_y2 = CLAMP ((y + radius + 1), y1, y2);

              src_offset = (mask_y1 - y1) * width + (mask_x1 - x1);

              for (mask_y = mask_y1,
                   src_row = src_buf + src_offset * bpp,
                   src_inten_row = src_inten_buf + src_offset  /* valid iff use_inten */
                   ;
                   mask_y < mask_y2
                   ;
                   mask_y++,
                   src_row += width * bpp,
                   src_inten_row += width)  /* valid iff use_inten */
                {
                  guchar *src;
                  guchar *src_inten = NULL;
                  gint    dy_squared = sqr_lut[ABS (mask_y - y)];
                  gint    mask_x;

                  for (mask_x = mask_x1,
                       src = src_row,
                       src_inten = src_inten_row  /* valid iff use_inten */
                       ;
                       mask_x < mask_x2
                       ;
                       mask_x++,
                       src += bpp,
                       src_inten++)  /* valid iff use_inten */
                    {
                      gint dx_squared = sqr_lut[ABS (mask_x - x)];
                      gint b;

                      /*  Stay inside a circular mask area  */
                      if ((dx_squared + dy_squared) > radius_squared)
                        continue;

                      if (use_inten)
                        {
                          gint inten = *src_inten;
                          ++Hist[inten];
                          for (b = 0; b < bpp; b++)
                            Hist_rgb[b][inten] += src[b];
                        }
                      else
                        {
                          for (b = 0; b < bpp; b++)
                            ++Hist_rgb[b][src[b]];
                        }

                    } /* for mask_x */
                } /* for mask_y */

              if (use_inten)
                {
                  weighted_average_color (Hist, Hist_rgb, exponent, dest, bpp);
                }
              else
                {
                  gint b;

                  for (b = 0; b < bpp; b++)
                    dest[b] = weighted_average_value (Hist_rgb[b], exponent);
                }

            } /* for x */
        } /* for y */

      if (preview)
        {
          gimp_drawable_preview_draw_region (GIMP_DRAWABLE_PREVIEW (preview),
                                             &dest_rgn);
        }
      else
        {
          progress += dest_rgn.w * dest_rgn.h;
          gimp_progress_update ((gdouble) progress / (gdouble) max_progress);
        }
    } /* for pr */

  /*  Detach from the map drawables  */
  if (mask_size_map_drawable)
    gimp_drawable_detach (mask_size_map_drawable);

  if (exponent_map_drawable)
    gimp_drawable_detach (exponent_map_drawable);

  if (src_inten_buf)
    g_free (src_inten_buf);

  g_free (src_buf);
  g_free (sqr_lut);

  if (!preview)
    {
      /*  Update the oil-painted region  */
      gimp_drawable_flush (drawable);
      gimp_drawable_merge_shadow (drawable->drawable_id, TRUE);
      gimp_drawable_update (drawable->drawable_id, x1, y1, width, height);
    }
}