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; }
static void neon_preview_update (GimpPreview *preview) { neon (GIMP_DRAWABLE_PREVIEW (preview)->drawable, evals.radius, evals.amount, preview); }
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); }
// 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); }
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); }
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); }
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); } }
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, ¶m); dest += bpp; } gimp_preview_draw_buffer (preview, buffer, width * bpp); g_free (buffer); g_rand_free (param.gr); }
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); }
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); }
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); }
/* - 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); }
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); } }
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); }
/* * 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); }
/* 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); } }
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); } }
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); }
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); }
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); }
/* * 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); } }