static void preview_update (GtkWidget *widget) { GimpPixelRgn src_rgn; /* Source image region */ guchar *dst; /* Output image */ GimpPreview *preview; /* The preview widget */ guchar *src; /* Source pixel rows */ gint img_bpp; gint x1,y1; gint width, height; preview = GIMP_PREVIEW (widget); img_bpp = gimp_drawable_bpp (drawable->drawable_id); gimp_preview_get_size (preview, &width, &height); gimp_preview_get_position (preview, &x1, &y1); gimp_pixel_rgn_init (&src_rgn, drawable, x1, y1, width, height, FALSE, FALSE); dst = g_new (guchar, width * height * img_bpp); src = g_new (guchar, width * height * img_bpp); gimp_pixel_rgn_get_rect (&src_rgn, src, x1, y1, width, height); despeckle_median (src, dst, width, height, img_bpp, despeckle_radius, TRUE); gimp_preview_draw_buffer (preview, dst, width * img_bpp); g_free (src); g_free (dst); }
static void preview_update_preview (GimpPreview *preview, GimpDrawable *drawable) { gint x1, y1; gint width, height; gint bpp; guchar *buffer; GimpPixelRgn src_rgn; GimpPixelRgn preview_rgn; gint32 image_id, src_image_id; gint32 preview_id; GimpDrawable *preview_drawable; bpp = gimp_drawable_bpp (drawable->drawable_id); gimp_preview_get_position (preview, &x1, &y1); gimp_preview_get_size (preview, &width, &height); buffer = g_new (guchar, width * height * bpp); gimp_pixel_rgn_init (&src_rgn, drawable, x1, y1, width, height, FALSE, FALSE); gimp_pixel_rgn_get_rect (&src_rgn, buffer, x1, y1, width, height); /* set up gimp drawable for rendering preview into */ src_image_id = gimp_drawable_get_image (drawable->drawable_id); image_id = gimp_image_new (width, height, gimp_image_base_type (src_image_id)); preview_id = gimp_layer_new (image_id, "preview", width, height, gimp_drawable_type (drawable->drawable_id), 100, GIMP_NORMAL_MODE); preview_drawable = gimp_drawable_get (preview_id); gimp_image_add_layer (image_id, preview_id, 0); gimp_layer_set_offsets (preview_id, 0, 0); gimp_pixel_rgn_init (&preview_rgn, preview_drawable, 0, 0, width, height, TRUE, TRUE); gimp_pixel_rgn_set_rect (&preview_rgn, buffer, 0, 0, width, height); gimp_drawable_flush (preview_drawable); gimp_drawable_merge_shadow (preview_id, TRUE); gimp_drawable_update (preview_id, 0, 0, width, height); dog (image_id, preview_drawable, dogvals.inner, dogvals.outer, FALSE); gimp_pixel_rgn_get_rect (&preview_rgn, buffer, 0, 0, width, height); gimp_preview_draw_buffer (preview, buffer, width * bpp); gimp_image_delete (image_id); g_free (buffer); }
// 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 mblur (GimpDrawable *drawable, GimpPreview *preview) { gint x, y; gint width, height; if (preview) { gimp_preview_get_position (preview, &x, &y); gimp_preview_get_size (preview, &width, &height); } else { gimp_drawable_mask_bounds (drawable->drawable_id, &x, &y, &width, &height); width -= x; height -= y; } if (width < 1 || height < 1) return; if (! preview) gimp_progress_init (_("Motion blurring")); switch (mbvals.mblur_type) { case MBLUR_LINEAR: mblur_linear (drawable, preview, x, y, width, height); break; case MBLUR_RADIAL: mblur_radial (drawable, preview, x, y, width, height); break; case MBLUR_ZOOM: mblur_zoom (drawable, preview, x, y, width, height); break; default: break; } if (! preview) { gimp_drawable_flush (drawable); gimp_drawable_merge_shadow (drawable->drawable_id, TRUE); gimp_drawable_update (drawable->drawable_id, x, y, width, height); } }
static void color_to_alpha_preview (GimpPreview *preview, GimpDrawable *drawable) { GimpPixelRgn src_rgn; gint x, y; gint width, height; gint bpp; gint i; guchar *src, *dest; bpp = drawable->bpp; gimp_preview_get_position (preview, &x, &y); gimp_preview_get_size (preview, &width, &height); dest = g_new (guchar, width * height * 4); src = g_new (guchar, width * height * bpp); gimp_pixel_rgn_init (&src_rgn, drawable, x, y, width, height, FALSE, FALSE); gimp_pixel_rgn_get_rect (&src_rgn, src, x, y, width, height); for (i = 0; i < width * height; i++) to_alpha_func (src + i * bpp, dest + i * 4, bpp, NULL); g_free (src); /* Our code assumes that the drawable has an alpha channel (and adds * one later if the effect is actually performed). For that reason * we have to take care when drawing the preview. */ if (bpp == 4) { gimp_preview_draw_buffer (preview, dest, width * 4); } else { /* This is not correct because we ignore the selection, but it * is the best we can easily do. */ gimp_preview_area_draw (GIMP_PREVIEW_AREA (preview->area), 0, 0, width, height, GIMP_RGBA_IMAGE, dest, width * 4); } g_free (dest); }
/* * Handle the expose event on the preview */ static gboolean nova_center_preview_expose (GtkWidget *widget, GdkEvent *event, NovaCenter *center) { if (show_cursor) { cairo_t *cr; gint x, y, offx, offy; gint width, height; GimpPreviewArea *area = GIMP_PREVIEW_AREA (center->preview->area); GtkAllocation allocation; cr = gdk_cairo_create (gtk_widget_get_window (center->preview->area)); gimp_preview_transform (center->preview, pvals.xcenter, pvals.ycenter, &x, &y); gtk_widget_get_allocation (GTK_WIDGET (area), &allocation); offx = (allocation.width - area->width) / 2; offy = (allocation.height - area->height) / 2; gimp_preview_get_size (center->preview, &width, &height); cairo_move_to (cr, offx + x + 0.5, 0); cairo_line_to (cr, offx + x + 0.5, allocation.height); cairo_move_to (cr, 0, offy + y + 0.5); cairo_line_to (cr, allocation.width, offy + y + 0.5); cairo_set_line_width (cr, 3.0); cairo_set_source_rgba (cr, 1.0, 1.0, 1.0, 0.6); cairo_stroke_preserve (cr); cairo_set_line_width (cr, 1.0); cairo_set_source_rgba (cr, 0.0, 0.0, 0.0, 0.8); cairo_stroke (cr); cairo_destroy (cr); } return FALSE; }
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 nova_center_cursor_draw (NovaCenter *center) { GtkWidget *prvw = center->preview->area; gint width, height; gimp_preview_get_size (center->preview, &width, &height); gdk_gc_set_function (prvw->style->black_gc, GDK_INVERT); if (show_cursor) { if (center->cursor_drawn) { gdk_draw_line (prvw->window, prvw->style->black_gc, center->oldx, 1, center->oldx, height - 1); gdk_draw_line (prvw->window, prvw->style->black_gc, 1, center->oldy, width - 1, center->oldy); } gdk_draw_line (prvw->window, prvw->style->black_gc, center->curx, 1, center->curx, height - 1); gdk_draw_line (prvw->window, prvw->style->black_gc, 1, center->cury, width - 1, center->cury); } /* current position of cursor is updated */ center->oldx = center->curx; center->oldy = center->cury; center->cursor_drawn = TRUE; gdk_gc_set_function (prvw->style->black_gc, GDK_COPY); }
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); }
static void sobel (GimpDrawable *drawable, gboolean do_horizontal, gboolean do_vertical, gboolean keep_sign, GimpPreview *preview) { GimpPixelRgn srcPR, destPR; gint width, height; gint bytes; gint gradient, hor_gradient, ver_gradient; guchar *dest, *d; guchar *prev_row, *pr; guchar *cur_row, *cr; guchar *next_row, *nr; guchar *tmp; gint row, col; gint x1, y1, x2, y2; gboolean alpha; gint counter; guchar *preview_buffer = NULL; 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); gimp_progress_init (_("Sobel edge detecting")); width = x2 - x1; height = y2 - y1; } /* Get the size of the input image. (This will/must be the same * as the size of the output image. */ bytes = drawable->bpp; alpha = gimp_drawable_has_alpha (drawable->drawable_id); /* 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, 0, 0, drawable->width, drawable->height, FALSE, FALSE); if (preview) { preview_buffer = g_new (guchar, width * height * bytes); } else { gimp_pixel_rgn_init (&destPR, drawable, 0, 0, drawable->width, drawable->height, TRUE, TRUE); } pr = prev_row + bytes; cr = cur_row + bytes; nr = next_row + bytes; sobel_prepare_row (&srcPR, pr, x1, y1 - 1, width); sobel_prepare_row (&srcPR, cr, x1, y1, width); counter =0; /* loop through the rows, applying the sobel convolution */ for (row = y1; row < y2; row++) { /* prepare the next row */ sobel_prepare_row (&srcPR, nr, x1, row + 1, width); d = dest; for (col = 0; col < width * bytes; col++) { hor_gradient = (do_horizontal ? ((pr[col - bytes] + 2 * pr[col] + pr[col + bytes]) - (nr[col - bytes] + 2 * nr[col] + nr[col + bytes])) : 0); ver_gradient = (do_vertical ? ((pr[col - bytes] + 2 * cr[col - bytes] + nr[col - bytes]) - (pr[col + bytes] + 2 * cr[col + bytes] + nr[col + bytes])) : 0); gradient = (do_vertical && do_horizontal) ? (ROUND (RMS (hor_gradient, ver_gradient)) / 5.66) /* always >0 */ : (keep_sign ? (127 + (ROUND ((hor_gradient + ver_gradient) / 8.0))) : (ROUND (abs (hor_gradient + ver_gradient) / 4.0))); if (alpha && (((col + 1) % bytes) == 0)) { /* the alpha channel */ *d++ = (counter == 0) ? 0 : 255; counter = 0; } else { *d++ = gradient; if (gradient > 10) counter ++; } } /* shuffle the row pointers */ tmp = pr; pr = cr; cr = nr; nr = tmp; /* store the dest */ if (preview) { memcpy (preview_buffer + width * (row - y1) * bytes, dest, width * bytes); } else { gimp_pixel_rgn_set_row (&destPR, dest, x1, row, width); if ((row % 20) == 0) gimp_progress_update ((double) row / (double) (y2 - y1)); } } if (preview) { gimp_preview_draw_buffer (preview, preview_buffer, width * bytes); g_free (preview_buffer); } else { gimp_progress_update (1.0); /* update the sobeled region */ gimp_drawable_flush (drawable); gimp_drawable_merge_shadow (drawable->drawable_id, TRUE); gimp_drawable_update (drawable->drawable_id, x1, y1, width, height); } 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 gboolean focusblur_fft_buffer_update_source (FblurFftBuffer *fft, GimpDrawable *drawable, GimpPreview *preview) { GimpPixelRgn pr; gsize size; gint x1, x2, y1, y2; gint width, height; gint ntiles; fft->source.drawable = drawable; fft->source.preview = preview; gimp_drawable_mask_bounds (drawable->drawable_id, &x1, &y1, &x2, &y2); if (preview) { gint px1, px2, py1, py2; gint pw, ph; gimp_preview_get_position (GIMP_PREVIEW (preview), &px1, &py1); gimp_preview_get_size (GIMP_PREVIEW (preview), &pw, &ph); px2 = px1 + pw; py2 = py1 + ph; x1 = MAX (px1, x1); x2 = MIN (px2, x2); y1 = MAX (py1, y1); y2 = MIN (py2, y2); } g_assert (x1 < x2); g_assert (y1 < y2); width = x2 - x1; height = y2 - y1; ntiles = 1 + x2 / TILE_WIDTH - x1 / TILE_WIDTH; gimp_tile_cache_ntiles (ntiles); fft->source.has_alpha = gimp_drawable_has_alpha (drawable->drawable_id); fft->source.bpp = drawable->bpp; fft->source.channels = drawable->bpp - (fft->source.has_alpha ? 1 : 0); fft->source.rowstride = drawable->bpp * width; size = fft->source.rowstride * height; if (fft->source.data_preview) { if (! preview) { g_free (fft->source.data_preview); fft->source.data_preview = NULL; } else if (size != fft->source.size) { g_free (fft->source.data_preview); goto allocate2; } } else { allocate2: if (preview) { fft->source.data_preview = g_malloc (size); if (! fft->source.data_preview) return FALSE; } } if (fft->source.data) { if (size != fft->source.size) { g_free (fft->source.data); goto allocate; } } else { allocate: fft->source.size = size; fft->source.data = g_malloc (size); if (! fft->source.data) return FALSE; goto reload; } if (x1 == fft->source.x1 && x2 == fft->source.x2 && y1 == fft->source.y1 && y2 == fft->source.y2) return TRUE; reload: fft->source.x1 = x1; fft->source.x2 = x2; fft->source.y1 = y1; fft->source.y2 = y2; fft->source.width = width; fft->source.height = height; /* need to recount */ fft->depth.count = 0; /* load */ gimp_pixel_rgn_init (&pr, drawable, x1, y1, width, height, FALSE, FALSE); gimp_pixel_rgn_get_rect (&pr, fft->source.data, fft->source.x1, fft->source.y1, fft->source.width, fft->source.height); return TRUE; }
/* * 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); } }
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); }
gboolean focusblur_fft_buffer_update (FblurFftBuffer **fft, FblurParam *param, FblurQualityType quality, GimpPreview *preview) { gint width, height; gint radius, range; gint x1, x2, y1, y2; /* check condition */ if (quality == FBLUR_QUALITY_BEST) return FALSE; if (! focusblur_diffusion_update (&(param->diffusion), *fft, &(param->store), param->brush_name)) { gimp_message (_("Failed to update diffusion table.")); focusblur_fft_buffer_destroy (fft); return FALSE; } radius = ceilf (param->diffusion->model_radius); // without softness range = param->diffusion->model_radius_int; if (radius < 3 || (quality == FBLUR_QUALITY_NORMAL && param->store.enable_depth_map && radius > 63)) // needs more tune return FALSE; gimp_drawable_mask_bounds (param->drawable_ID, &x1, &y1, &x2, &y2); if (preview) { gint px1, px2, py1, py2; gint pw, ph; gimp_preview_get_position (GIMP_PREVIEW (preview), &px1, &py1); gimp_preview_get_size (GIMP_PREVIEW (preview), &pw, &ph); px2 = px1 + pw; py2 = py1 + ph; /* it is not need for GimpDrawablePreview */ if (x1 >= px2 || x2 <= px1 || y1 >= py2 || y2 <= py1) return TRUE; x1 = MAX (px1, x1); x2 = MIN (px2, x2); y1 = MAX (py1, y1); y2 = MIN (py2, y2); } width = x2 - x1; height = y2 - y1; if (width < range || height < range) return FALSE; if (! *fft) { *fft = g_new0 (FblurFftBuffer, 1); if (! *fft) { gimp_message (_("Failed to allocate memory.")); return FALSE; } } //focusblur_source_destroy (&(param->source)); /* fftsource must be updated before to update work and depth */ if (! focusblur_fft_buffer_update_source (*fft, param->drawable, preview)) { gimp_message (_("Failed to update source buffer.")); focusblur_fft_buffer_destroy (fft); return FALSE; } if (param->store.enable_depth_map) { if (! focusblur_depth_map_update (&(param->depth_map), *fft, &(param->store), quality)) { gimp_message (_("Failed to update depth info.")); focusblur_fft_buffer_destroy (fft); return FALSE; } else { gint d = focusblur_depth_map_focal_depth (param->depth_map); focusblur_fft_buffer_update_depth_division (*fft, quality, range, d); focusblur_fft_buffer_update_depth_count (*fft, param->depth_map); } } if (! focusblur_fft_buffer_update_work (*fft, range)) { gimp_message (_("Failed to update working buffer.")); focusblur_fft_buffer_destroy (fft); return FALSE; } if (! focusblur_shine_update (&(param->shine), param->drawable, &(param->store))) { gimp_message (_("Failed to update shine data.")); focusblur_fft_buffer_destroy (fft); return FALSE; } return TRUE; }
static void grid (gint32 image_ID, GimpDrawable *drawable, GimpPreview *preview) { GimpPixelRgn srcPR, destPR; gint bytes; gint x_offset, y_offset; guchar *dest, *buffer = NULL; gint x, y; gboolean alpha; gboolean blend; guchar hcolor[4]; guchar vcolor[4]; guchar icolor[4]; guchar *cmap; gint ncolors; gimp_rgba_get_uchar (&grid_cfg.hcolor, hcolor, hcolor + 1, hcolor + 2, hcolor + 3); gimp_rgba_get_uchar (&grid_cfg.vcolor, vcolor, vcolor + 1, vcolor + 2, vcolor + 3); gimp_rgba_get_uchar (&grid_cfg.icolor, icolor, icolor + 1, icolor + 2, icolor + 3); switch (gimp_image_base_type (image_ID)) { case GIMP_RGB: blend = TRUE; break; case GIMP_GRAY: hcolor[0] = gimp_rgb_luminance_uchar (&grid_cfg.hcolor); vcolor[0] = gimp_rgb_luminance_uchar (&grid_cfg.vcolor); icolor[0] = gimp_rgb_luminance_uchar (&grid_cfg.icolor); blend = TRUE; break; case GIMP_INDEXED: cmap = gimp_image_get_colormap (image_ID, &ncolors); hcolor[0] = best_cmap_match (cmap, ncolors, &grid_cfg.hcolor); vcolor[0] = best_cmap_match (cmap, ncolors, &grid_cfg.vcolor); icolor[0] = best_cmap_match (cmap, ncolors, &grid_cfg.icolor); g_free (cmap); blend = FALSE; break; default: g_assert_not_reached (); blend = FALSE; } bytes = drawable->bpp; alpha = gimp_drawable_has_alpha (drawable->drawable_id); if (preview) { gimp_preview_get_position (preview, &sx1, &sy1); gimp_preview_get_size (preview, &sx2, &sy2); buffer = g_new (guchar, bytes * sx2 * sy2); sx2 += sx1; sy2 += sy1; } else { gimp_drawable_mask_bounds (drawable->drawable_id, &sx1, &sy1, &sx2, &sy2); gimp_pixel_rgn_init (&destPR, drawable, 0, 0, sx2 - sx1, sy2 - sy1, TRUE, TRUE); } gimp_pixel_rgn_init (&srcPR, drawable, 0, 0, sx2 - sx1, sy2 - sy1, FALSE, FALSE); dest = g_new (guchar, (sx2 - sx1) * bytes); for (y = sy1; y < sy2; y++) { gimp_pixel_rgn_get_row (&srcPR, dest, sx1, y, (sx2 - sx1)); y_offset = y - grid_cfg.hoffset; while (y_offset < 0) y_offset += grid_cfg.hspace; if ((y_offset + (grid_cfg.hwidth / 2)) % grid_cfg.hspace < grid_cfg.hwidth) { for (x = sx1; x < sx2; x++) { pix_composite (&dest[(x-sx1) * bytes], hcolor, bytes, blend, alpha); } } for (x = sx1; x < sx2; x++) { x_offset = grid_cfg.vspace + x - grid_cfg.voffset; while (x_offset < 0) x_offset += grid_cfg.vspace; if ((x_offset + (grid_cfg.vwidth / 2)) % grid_cfg.vspace < grid_cfg.vwidth) { pix_composite (&dest[(x-sx1) * bytes], vcolor, bytes, blend, alpha); } if ((x_offset + (grid_cfg.iwidth / 2)) % grid_cfg.vspace < grid_cfg.iwidth && ((y_offset % grid_cfg.hspace >= grid_cfg.ispace && y_offset % grid_cfg.hspace < grid_cfg.ioffset) || (grid_cfg.hspace - (y_offset % grid_cfg.hspace) >= grid_cfg.ispace && grid_cfg.hspace - (y_offset % grid_cfg.hspace) < grid_cfg.ioffset))) { pix_composite (&dest[(x-sx1) * bytes], icolor, bytes, blend, alpha); } } if ((y_offset + (grid_cfg.iwidth / 2)) % grid_cfg.hspace < grid_cfg.iwidth) { for (x = sx1; x < sx2; x++) { x_offset = grid_cfg.vspace + x - grid_cfg.voffset; while (x_offset < 0) x_offset += grid_cfg.vspace; if ((x_offset % grid_cfg.vspace >= grid_cfg.ispace && x_offset % grid_cfg.vspace < grid_cfg.ioffset) || (grid_cfg.vspace - (x_offset % grid_cfg.vspace) >= grid_cfg.ispace && grid_cfg.vspace - (x_offset % grid_cfg.vspace) < grid_cfg.ioffset)) { pix_composite (&dest[(x-sx1) * bytes], icolor, bytes, blend, alpha); } } } if (preview) { memcpy (buffer + (y - sy1) * (sx2 - sx1) * bytes, dest, (sx2 - sx1) * bytes); } else { gimp_pixel_rgn_set_row (&destPR, dest, sx1, y, (sx2 - sx1)); if (y % 16 == 0) gimp_progress_update ((gdouble) y / (gdouble) (sy2 - sy1)); } } g_free (dest); if (preview) { gimp_preview_draw_buffer (preview, buffer, bytes * (sx2 - sx1)); g_free (buffer); } else { gimp_progress_update (1.0); gimp_drawable_flush (drawable); gimp_drawable_merge_shadow (drawable->drawable_id, TRUE); gimp_drawable_update (drawable->drawable_id, sx1, sy1, sx2 - sx1, sy2 - sy1); } }
static void drawlens (GimpDrawable *drawable, GimpPreview *preview) { GimpImageType drawtype = gimp_drawable_type (drawable->drawable_id); GimpPixelRgn srcPR, destPR; gint width, height; gint bytes; gint row; gint x1, y1, x2, y2; guchar *src, *dest; gint i, col; gfloat regionwidth, regionheight, dx, dy, xsqr, ysqr; gfloat a, b, c, asqr, bsqr, csqr, x, y; glong pixelpos, pos; GimpRGB background; guchar bgr_red, bgr_blue, bgr_green; guchar alphaval; gimp_context_get_background (&background); gimp_rgb_get_uchar (&background, &bgr_red, &bgr_green, &bgr_blue); bytes = drawable->bpp; if (preview) { gimp_preview_get_position (preview, &x1, &y1); gimp_preview_get_size (preview, &width, &height); x2 = x1 + width; y2 = y1 + height; src = gimp_drawable_get_thumbnail_data (drawable->drawable_id, &width, &height, &bytes); regionwidth = width; regionheight = height; } else { gimp_drawable_mask_bounds (drawable->drawable_id, &x1, &y1, &x2, &y2); regionwidth = x2 - x1; regionheight = y2 - y1; width = drawable->width; height = drawable->height; gimp_pixel_rgn_init (&srcPR, drawable, 0, 0, width, height, FALSE, FALSE); gimp_pixel_rgn_init (&destPR, drawable, 0, 0, width, height, TRUE, TRUE); src = g_new (guchar, regionwidth * regionheight * bytes); gimp_pixel_rgn_get_rect (&srcPR, src, x1, y1, regionwidth, regionheight); } dest = g_new (guchar, regionwidth * regionheight * bytes); a = regionwidth / 2; b = regionheight / 2; c = MIN (a, b); asqr = a * a; bsqr = b * b; csqr = c * c; for (col = 0; col < regionwidth; col++) { dx = (gfloat) col - a + 0.5; xsqr = dx * dx; for (row = 0; row < regionheight; row++) { pixelpos = (col + row * regionwidth) * bytes; dy = -((gfloat) row - b) - 0.5; ysqr = dy * dy; if (ysqr < (bsqr - (bsqr * xsqr) / asqr)) { find_projected_pos (asqr, bsqr, csqr, dx, dy, &x, &y); y = -y; pos = ((gint) (y + b) * regionwidth + (gint) (x + a)) * bytes; for (i = 0; i < bytes; i++) { dest[pixelpos + i] = src[pos + i]; } } else { if (lvals.keep_surr) { for (i = 0; i < bytes; i++) { dest[pixelpos + i] = src[pixelpos + i]; } } else { if (lvals.set_transparent) alphaval = 0; else alphaval = 255; switch (drawtype) { case GIMP_INDEXEDA_IMAGE: dest[pixelpos + 1] = alphaval; case GIMP_INDEXED_IMAGE: dest[pixelpos + 0] = 0; break; case GIMP_RGBA_IMAGE: dest[pixelpos + 3] = alphaval; case GIMP_RGB_IMAGE: dest[pixelpos + 0] = bgr_red; dest[pixelpos + 1] = bgr_green; dest[pixelpos + 2] = bgr_blue; break; case GIMP_GRAYA_IMAGE: dest[pixelpos + 1] = alphaval; case GIMP_GRAY_IMAGE: dest[pixelpos+0] = bgr_red; break; } } } } if (!preview) { if (((gint) (regionwidth-col) % 5) == 0) gimp_progress_update ((gdouble) col / (gdouble) regionwidth); } } if (preview) { gimp_preview_draw_buffer (preview, dest, bytes * regionwidth); } else { gimp_progress_update (1.0); gimp_pixel_rgn_set_rect (&destPR, dest, x1, y1, regionwidth, regionheight); gimp_drawable_flush (drawable); gimp_drawable_merge_shadow (drawable->drawable_id, TRUE); gimp_drawable_update (drawable->drawable_id, x1, y1, x2 - x1, y2 - y1); } g_free (src); 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 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 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); }
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); }
/* - 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 neon (GimpDrawable *drawable, gdouble radius, gdouble amount, GimpPreview *preview) { GimpPixelRgn src_rgn, dest_rgn; gint width, height; gint bytes, bpp; gboolean has_alpha; guchar *dest; guchar *src, *src2, *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 = 0, max_progress = 1; gint initial_p[4]; gint initial_m[4]; gdouble std_dev; guchar *preview_buffer1 = NULL; guchar *preview_buffer2 = NULL; 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); } if (radius < 1.0) return; bytes = drawable->bpp; bpp = bytes; has_alpha = gimp_drawable_has_alpha(drawable->drawable_id); if (has_alpha) bpp--; val_p = g_new (gdouble, MAX (width, height) * bytes); val_m = g_new (gdouble, MAX (width, height) * bytes); src = g_new (guchar, MAX (width, height) * bytes); src2 = g_new (guchar, MAX (width, height) * bytes); dest = g_new (guchar, MAX (width, height) * bytes); gimp_pixel_rgn_init (&src_rgn, drawable, 0, 0, drawable->width, drawable->height, FALSE, FALSE); if (preview) { preview_buffer1 = g_new (guchar, width * height * bytes); preview_buffer2 = g_new (guchar, width * height * bytes); } else { gimp_pixel_rgn_init (&dest_rgn, drawable, 0, 0, drawable->width, drawable->height, TRUE, TRUE); progress = 0; max_progress = (radius < 1.0 ) ? 0 : width * height * radius * 2; } /* First the vertical pass */ radius = fabs (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); for (col = 0; col < width; col++) { memset (val_p, 0, height * bytes * sizeof (gdouble)); memset (val_m, 0, height * bytes * sizeof (gdouble)); gimp_pixel_rgn_get_col (&src_rgn, src, col + x1, y1, (y2 - y1)); sp_p = src; sp_m = src + (height - 1) * bytes; vp = val_p; vm = val_m + (height - 1) * bytes; /* Set up the first vals */ for (i = 0; i < bytes; i++) { initial_p[i] = sp_p[i]; initial_m[i] = sp_m[i]; } for (row = 0; row < height; row++) { gdouble *vpptr, *vmptr; terms = (row < 4) ? row : 4; for (b = 0; b < bpp; b++) { vpptr = vp + b; vmptr = vm + b; for (i = 0; i <= terms; i++) { *vpptr += n_p[i] * sp_p[(-i * bytes) + b] - d_p[i] * vp[(-i * bytes) + b]; *vmptr += n_m[i] * sp_m[(i * bytes) + b] - d_m[i] * vm[(i * bytes) + b]; } for (j = i; j <= 4; j++) { *vpptr += (n_p[j] - bd_p[j]) * initial_p[b]; *vmptr += (n_m[j] - bd_m[j]) * initial_m[b]; } } if (has_alpha) { vp[bpp] = sp_p[bpp]; vm[bpp] = sp_m[bpp]; } sp_p += bytes; sp_m -= bytes; vp += bytes; vm -= bytes; } transfer_pixels (val_p, val_m, dest, bytes, height); if (preview) { for (row = 0 ; row < height ; row++) memcpy (preview_buffer1 + (row * width + col) * bytes, dest + bytes * row, bytes); } else { gimp_pixel_rgn_set_col (&dest_rgn, dest, col + x1, y1, (y2 - y1)); progress += height * radius; if ((col % 20) == 0) gimp_progress_update ((double) progress / (double) max_progress); } } /* Now the horizontal pass */ gimp_pixel_rgn_init (&src_rgn, drawable, 0, 0, drawable->width, drawable->height, FALSE, FALSE); for (row = 0; row < height; row++) { memset (val_p, 0, width * bytes * sizeof (gdouble)); memset (val_m, 0, width * bytes * sizeof (gdouble)); gimp_pixel_rgn_get_row (&src_rgn, src, x1, row + y1, (x2 - x1)); if (preview) { memcpy (src2, preview_buffer1 + row * width * bytes, width * bytes); } else { gimp_pixel_rgn_get_row (&dest_rgn, src2, x1, row + y1, (x2 - x1)); } sp_p = src; sp_m = src + (width - 1) * bytes; vp = val_p; vm = val_m + (width - 1) * bytes; /* Set up the first vals */ for (i = 0; i < bytes; i++) { initial_p[i] = sp_p[i]; initial_m[i] = sp_m[i]; } for (col = 0; col < width; col++) { gdouble *vpptr, *vmptr; terms = (col < 4) ? col : 4; for (b = 0; b < bpp; b++) { vpptr = vp + b; vmptr = vm + b; for (i = 0; i <= terms; i++) { *vpptr += n_p[i] * sp_p[(-i * bytes) + b] - d_p[i] * vp[(-i * bytes) + b]; *vmptr += n_m[i] * sp_m[(i * bytes) + b] - d_m[i] * vm[(i * bytes) + b]; } for (j = i; j <= 4; j++) { *vpptr += (n_p[j] - bd_p[j]) * initial_p[b]; *vmptr += (n_m[j] - bd_m[j]) * initial_m[b]; } } if (has_alpha) { vp[bpp] = sp_p[bpp]; vm[bpp] = sp_m[bpp]; } sp_p += bytes; sp_m -= bytes; vp += bytes; vm -= bytes; } transfer_pixels (val_p, val_m, dest, bytes, width); combine_to_gradient (dest, src2, bytes, width, amount); if (preview) { memcpy (preview_buffer2 + row * width * bytes, dest, width * bytes); } else { gimp_pixel_rgn_set_row (&dest_rgn, dest, x1, row + y1, (x2 - x1)); progress += width * radius; if ((row % 20) == 0) gimp_progress_update ((double) progress / (double) max_progress); } } if (preview) { gimp_preview_draw_buffer (preview, preview_buffer2, width * bytes); g_free (preview_buffer1); g_free (preview_buffer2); } else { gimp_progress_update (1.0); /* now, merge horizontal and vertical into a magnitude */ gimp_pixel_rgn_init (&src_rgn, drawable, 0, 0, drawable->width, drawable->height, FALSE, TRUE); /* 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 (src); g_free (src2); g_free (dest); }
/* * Cartoon 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 */ static void cartoon (GimpDrawable *drawable, GimpPreview *preview) { GimpPixelRgn src_rgn, dest_rgn; GimpPixelRgn *pr; gint width, height; gint bytes; gboolean has_alpha; guchar *dest1; guchar *dest2; guchar *src; 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, x2, y2; gint i, j; gint row, col, b; 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 std_dev1; gdouble std_dev2; gdouble ramp; guchar *preview_buffer = NULL; 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; has_alpha = gimp_drawable_has_alpha (drawable->drawable_id); val_p1 = g_new (gdouble, MAX (width, height) * bytes); val_p2 = g_new (gdouble, MAX (width, height) * bytes); val_m1 = g_new (gdouble, MAX (width, height) * bytes); val_m2 = g_new (gdouble, MAX (width, height) * bytes); src = g_new (guchar, MAX (width, height) * bytes); dest1 = g_new0 (guchar, width * height); dest2 = g_new0 (guchar, width * height); gimp_pixel_rgn_init (&src_rgn, drawable, 0, 0, drawable->width, drawable->height, FALSE, FALSE); progress = 0; max_progress = width * height * 2; /* Calculate the standard deviations */ radius = 1.0; /* blur radius */ radius = fabs (radius) + 1.0; std_dev1 = sqrt (-(radius * radius) / (2 * log (1.0 / 255.0))); radius = cvals.mask_radius; radius = fabs (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 * bytes * sizeof (gdouble)); memset (val_p2, 0, height * bytes * sizeof (gdouble)); memset (val_m1, 0, height * bytes * sizeof (gdouble)); memset (val_m2, 0, height * bytes * sizeof (gdouble)); gimp_pixel_rgn_get_col (&src_rgn, src, col + x1, y1, height); src1 = src; sp_p1 = src1; sp_m1 = src1 + (height - 1) * bytes; vp1 = val_p1; vp2 = val_p2; vm1 = val_m1 + (height - 1) * bytes; vm2 = val_m2 + (height - 1) * bytes; /* Set up the first vals */ for (i = 0; i < bytes; i++) { initial_p1[i] = sp_p1[i]; initial_m1[i] = sp_m1[i]; } for (row = 0; row < height; row++) { gdouble *vpptr1, *vmptr1; gdouble *vpptr2, *vmptr2; terms = (row < 4) ? row : 4; for (b = 0; b < bytes; b++) { vpptr1 = vp1 + b; vmptr1 = vm1 + b; vpptr2 = vp2 + b; vmptr2 = vm2 + b; for (i = 0; i <= terms; i++) { *vpptr1 += n_p1[i] * sp_p1[(-i * bytes) + b] - d_p1[i] * vp1[(-i * bytes) + b]; *vmptr1 += n_m1[i] * sp_m1[(i * bytes) + b] - d_m1[i] * vm1[(i * bytes) + b]; *vpptr2 += n_p2[i] * sp_p1[(-i * bytes) + b] - d_p2[i] * vp2[(-i * bytes) + b]; *vmptr2 += n_m2[i] * sp_m1[(i * bytes) + b] - d_m2[i] * vm2[(i * bytes) + b]; } for (j = i; j <= 4; j++) { *vpptr1 += (n_p1[j] - bd_p1[j]) * initial_p1[b]; *vmptr1 += (n_m1[j] - bd_m1[j]) * initial_m1[b]; *vpptr2 += (n_p2[j] - bd_p2[j]) * initial_p1[b]; *vmptr2 += (n_m2[j] - bd_m2[j]) * initial_m1[b]; } } sp_p1 += bytes; sp_m1 -= bytes; vp1 += bytes; vp2 += bytes; vm1 -= bytes; vm2 -= bytes; } transfer_pixels (val_p1, val_m1, dest1 + col, width, bytes, height); transfer_pixels (val_p2, val_m2, dest2 + col, width, bytes, 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, 1, width); transfer_pixels (val_p2, val_m2, dest2 + row * width, 1, 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 = compute_ramp (dest1, dest2, width * height, cvals.pct_black); /* Initialize the pixel regions. */ gimp_pixel_rgn_init (&src_rgn, drawable, x1, y1, width, height, FALSE, FALSE); if (preview) { pr = gimp_pixel_rgns_register (1, &src_rgn); preview_buffer = g_new (guchar, width * height * bytes); } else { gimp_pixel_rgn_init (&dest_rgn, drawable, x1, y1, width, height, TRUE, TRUE); pr = gimp_pixel_rgns_register (2, &src_rgn, &dest_rgn); } while (pr) { guchar *src_ptr = src_rgn.data; guchar *dest_ptr; 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; gdouble mult = 0.0; gdouble lightness; if (preview) dest_ptr = preview_buffer + ((src_rgn.y - y1) * width + (src_rgn.x - x1)) * bytes; else dest_ptr = dest_rgn.data; for (row = 0; row < src_rgn.h; row++) { for (col = 0; col < src_rgn.w; col++) { if (avg_ptr[col] != 0) { diff = (gdouble) blur_ptr[col] / (gdouble) avg_ptr[col]; if (diff < cvals.threshold) { if (ramp == 0.0) mult = 0.0; else mult = (ramp - MIN (ramp, (cvals.threshold - diff))) / ramp; } else mult = 1.0; } lightness = CLAMP (blur_ptr[col] * mult, 0, 255); 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 { /* Convert to HLS, set lightness and convert back */ gint r, g, b; r = src_ptr[col * src_rgn.bpp + 0]; g = src_ptr[col * src_rgn.bpp + 1]; b = src_ptr[col * src_rgn.bpp + 2]; gimp_rgb_to_hsl_int (&r, &g, &b); b = lightness; gimp_hsl_to_rgb_int (&r, &g, &b); dest_ptr[col * bytes + 0] = r; dest_ptr[col * bytes + 1] = g; dest_ptr[col * bytes + 2] = b; if (has_alpha) dest_ptr[col * bytes + 3] = src_ptr[col * src_rgn.bpp + 3]; } } src_ptr += src_rgn.rowstride; if (preview) dest_ptr += width * bytes; else dest_ptr += dest_rgn.rowstride; blur_ptr += width; avg_ptr += width; } if (!preview) { progress += src_rgn.w * src_rgn.h; gimp_progress_update ((gdouble) progress / (gdouble) max_progress); } pr = gimp_pixel_rgns_process (pr); } if (preview) { gimp_preview_draw_buffer (preview, preview_buffer, width * bytes); g_free (preview_buffer); } else { /* 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 (src); g_free (dest1); g_free (dest2); }
static void ripple (GimpDrawable *drawable, GimpPreview *preview) { RippleParam_t param; gint edges; gint period; param.pft = gimp_pixel_fetcher_new (drawable, FALSE); param.has_alpha = gimp_drawable_has_alpha (drawable->drawable_id); param.width = drawable->width; param.height = drawable->height; edges = rvals.edges; period = rvals.period; if (rvals.tile) { rvals.edges = WRAP; rvals.period = (param.width / (param.width / rvals.period) * (rvals.orientation == GIMP_ORIENTATION_HORIZONTAL) + param.height / (param.height / rvals.period) * (rvals.orientation == GIMP_ORIENTATION_VERTICAL)); } if (preview) { guchar *buffer, *d; gint bpp = gimp_drawable_bpp (drawable->drawable_id); gint width, height; gint x, y; gint x1, y1; gimp_preview_get_position (preview, &x1, &y1); gimp_preview_get_size (preview, &width, &height); d = buffer = g_new (guchar, width * height * bpp); for (y = 0; y < height ; y++) for (x = 0; x < width ; x++) { if (rvals.orientation == GIMP_ORIENTATION_VERTICAL) ripple_vertical (x1 + x, y1 + y, d, bpp, ¶m); else ripple_horizontal (x1 + x, y1 + y, d, bpp, ¶m); d += bpp; } gimp_preview_draw_buffer (preview, buffer, width * bpp); g_free (buffer); } else { GimpRgnIterator *iter; iter = gimp_rgn_iterator_new (drawable, 0); gimp_rgn_iterator_dest (iter, rvals.orientation == GIMP_ORIENTATION_VERTICAL ? ripple_vertical : ripple_horizontal, ¶m); gimp_rgn_iterator_free (iter); } rvals.edges = edges; rvals.period = period; gimp_pixel_fetcher_destroy (param.pft); }
/* This function operates on the image when pixelwidth >= tile_width. It simply sets the size of GimpPixelRgn as pixelwidth and proceeds. */ static void pixelize_large (GimpDrawable *drawable, gint pixelwidth, gint pixelheight, GimpPreview *preview) { GimpPixelRgn src_rgn, dest_rgn; guchar *src_row, *dest_row; guchar *src, *dest = NULL, *d; gulong average[4]; gint row, col, b, bpp, has_alpha; gint x, y, x_step, y_step; gint i, j; gulong count; gint x1, y1, x2, y2; gint width, height; gint progress = 0, max_progress = 1; gpointer pr; bpp = gimp_drawable_bpp (drawable->drawable_id); has_alpha = gimp_drawable_has_alpha (drawable->drawable_id); if (preview) { gimp_preview_get_position (preview, &x1, &y1); gimp_preview_get_size (preview, &width, &height); x2 = x1 + width; y2 = y1 + height; dest = g_new (guchar, width * height * bpp); } else { gimp_drawable_mask_bounds (drawable->drawable_id, &x1, &y1, &x2, &y2); width = x2 - x1; height = y2 - y1; /* Initialize progress */ progress = 0; max_progress = 2 * width * height; } for (y = y1; y < y2; y += pixelheight - (y % pixelheight)) { for (x = x1; x < x2; x += pixelwidth - (x % pixelwidth)) { x_step = pixelwidth - (x % pixelwidth); y_step = pixelheight - (y % pixelheight); x_step = MIN (x_step, x2 - x); y_step = MIN (y_step, y2 - y); gimp_pixel_rgn_init (&src_rgn, drawable, x, y, x_step, y_step, FALSE, FALSE); for (b = 0; b < bpp; b++) average[b] = 0; count = 0; for (pr = gimp_pixel_rgns_register (1, &src_rgn); pr != NULL; pr = gimp_pixel_rgns_process (pr)) { src_row = src_rgn.data; for (row = 0; row < src_rgn.h; row++) { src = src_row; if (has_alpha) { for (col = 0; col < src_rgn.w; col++) { gulong alpha = src[bpp - 1]; average[bpp - 1] += alpha; for (b = 0; b < bpp - 1; b++) average[b] += src[b] * alpha; src += src_rgn.bpp; } } else { for (col = 0; col < src_rgn.w; col++) { for (b = 0; b < bpp; b++) average[b] += src[b]; src += src_rgn.bpp; } } src_row += src_rgn.rowstride; } count += src_rgn.w * src_rgn.h; if (!preview) { /* Update progress */ progress += src_rgn.w * src_rgn.h; gimp_progress_update ((double) progress / (double) max_progress); } } if (count > 0) { if (has_alpha) { gulong alpha = average[bpp - 1]; if ((average[bpp - 1] = alpha / count)) for (b = 0; b < bpp - 1; b++) average[b] /= alpha; } else { for (b = 0; b < bpp; b++) average[b] /= count; } } if (preview) { dest_row = dest + ((y - y1) * width + (x - x1)) * bpp; for (j = 0; j < y_step; j++) { d = dest_row; for (i = 0; i < x_step; i++) for (b = 0; b < bpp; b++) *d++ = average[b]; dest_row += width * bpp; } } else { gimp_pixel_rgn_init (&dest_rgn, drawable, x, y, x_step, y_step, TRUE, TRUE); for (pr = gimp_pixel_rgns_register (1, &dest_rgn); pr != NULL; pr = gimp_pixel_rgns_process (pr)) { dest_row = dest_rgn.data; for (row = 0; row < dest_rgn.h; row++) { dest = dest_row; for (col = 0; col < dest_rgn.w; col++) { for (b = 0; b < bpp; b++) dest[b] = average[b]; dest += dest_rgn.bpp; } dest_row += dest_rgn.rowstride; } /* Update progress */ progress += dest_rgn.w * dest_rgn.h; gimp_progress_update ((double) progress / (double) max_progress); } } } } if (preview) { gimp_preview_draw_buffer (preview, dest, width * bpp); g_free (dest); } else { /* update the blurred 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 displace (GimpDrawable *drawable, GimpPreview *preview) { GimpDrawable *map_x = NULL; GimpDrawable *map_y = NULL; GimpPixelRgn dest_rgn; GimpPixelRgn map_x_rgn; GimpPixelRgn map_y_rgn; gpointer pr; GimpPixelFetcher *pft; gint width; gint height; gint bytes; guchar *destrow, *dest; guchar *mxrow, *mx; guchar *myrow, *my; guchar pixel[4][4]; gint x1, y1, x2, y2; gint x, y; gdouble cx, cy; gint progress, max_progress; gdouble amnt; gdouble needx, needy; gdouble radius, d_alpha; gint xi, yi; guchar values[4]; guchar val; gint k; gdouble xm_val, ym_val; gint xm_alpha = 0; gint ym_alpha = 0; gint xm_bytes = 1; gint ym_bytes = 1; guchar *buffer = NULL; gdouble pi; /* initialize */ /* get rid of uninitialized warnings */ cx = cy = needx = needy = radius = d_alpha = 0.0; pi = 4 * atan (1); mxrow = NULL; myrow = NULL; pft = gimp_pixel_fetcher_new (drawable, FALSE); gimp_pixel_fetcher_set_edge_mode (pft, dvals.displace_type); bytes = drawable->bpp; gimp_drawable_mask_bounds (drawable->drawable_id, &x1, &y1, &x2, &y2); width = x2 - x1; height = y2 - y1; if (dvals.mode == POLAR_MODE) { cx = x1 + width / 2.0; cy = y1 + height / 2.0; } if (preview) { gimp_preview_get_position (preview, &x1, &y1); gimp_preview_get_size (preview, &width, &height); x2 = x1 + width; y2 = y1 + height; buffer = g_new (guchar, width * height * bytes); } progress = 0; max_progress = width * height; /* * The algorithm used here is simple - see * http://the-tech.mit.edu/KPT/Tips/KPT7/KPT7.html for a description. */ /* Get the drawables */ if (dvals.displace_map_x != -1 && dvals.do_x) { map_x = gimp_drawable_get (dvals.displace_map_x); gimp_pixel_rgn_init (&map_x_rgn, map_x, x1, y1, width, height, FALSE, FALSE); if (gimp_drawable_has_alpha (map_x->drawable_id)) xm_alpha = 1; xm_bytes = gimp_drawable_bpp (map_x->drawable_id); } if (dvals.displace_map_y != -1 && dvals.do_y) { map_y = gimp_drawable_get (dvals.displace_map_y); gimp_pixel_rgn_init (&map_y_rgn, map_y, x1, y1, width, height, FALSE, FALSE); if (gimp_drawable_has_alpha (map_y->drawable_id)) ym_alpha = 1; ym_bytes = gimp_drawable_bpp (map_y->drawable_id); } gimp_pixel_rgn_init (&dest_rgn, drawable, x1, y1, width, height, preview == NULL, preview == NULL); /* Register the pixel regions */ if (dvals.do_x && dvals.do_y) pr = gimp_pixel_rgns_register (3, &dest_rgn, &map_x_rgn, &map_y_rgn); else if (dvals.do_x) pr = gimp_pixel_rgns_register (2, &dest_rgn, &map_x_rgn); else if (dvals.do_y) pr = gimp_pixel_rgns_register (2, &dest_rgn, &map_y_rgn); else pr = NULL; for (pr = pr; pr != NULL; pr = gimp_pixel_rgns_process (pr)) { destrow = dest_rgn.data; if (dvals.do_x) mxrow = map_x_rgn.data; if (dvals.do_y) myrow = map_y_rgn.data; for (y = dest_rgn.y; y < (dest_rgn.y + dest_rgn.h); y++) { if (preview) dest = buffer + ((y - y1) * width + (dest_rgn.x - x1)) * bytes; else dest = destrow; mx = mxrow; my = myrow; /* * We could move the displacement image address calculation * out of here, but when we can have different sized * displacement and destination images we'd have to move it * back anyway. */ for (x = dest_rgn.x; x < (dest_rgn.x + dest_rgn.w); x++) { if (dvals.do_x) { xm_val = displace_map_give_value(mx, xm_alpha, xm_bytes); amnt = dvals.amount_x * (xm_val - 127.5) / 127.5; /* CARTESIAN_MODE == 0 - performance important here */ if (! dvals.mode) { needx = x + amnt; } else { radius = sqrt (SQR (x - cx) + SQR (y - cy)) + amnt; } mx += xm_bytes; } else { if (! dvals.mode) needx = x; else radius = sqrt ((x - cx) * (x - cx) + (y - cy) * (y - cy)); } if (dvals.do_y) { ym_val = displace_map_give_value(my, ym_alpha, ym_bytes); amnt = dvals.amount_y * (ym_val - 127.5) / 127.5; if (! dvals.mode) { needy = y + amnt; } else { d_alpha = atan2 (x - cx, y - cy) + (dvals.amount_y / 180) * pi * (ym_val - 127.5) / 127.5; } my += ym_bytes; } else { if (! dvals.mode) needy = y; else d_alpha = atan2 (x - cx, y - cy); } if (dvals.mode) { needx = cx + radius * sin (d_alpha); needy = cy + radius * cos (d_alpha); } /* Calculations complete; now copy the proper pixel */ if (needx >= 0.0) xi = (int) needx; else xi = -((int) -needx + 1); if (needy >= 0.0) yi = (int) needy; else yi = -((int) -needy + 1); gimp_pixel_fetcher_get_pixel (pft, xi, yi, pixel[0]); gimp_pixel_fetcher_get_pixel (pft, xi + 1, yi, pixel[1]); gimp_pixel_fetcher_get_pixel (pft, xi, yi + 1, pixel[2]); gimp_pixel_fetcher_get_pixel (pft, xi + 1, yi + 1, pixel[3]); for (k = 0; k < bytes; k++) { values[0] = pixel[0][k]; values[1] = pixel[1][k]; values[2] = pixel[2][k]; values[3] = pixel[3][k]; val = gimp_bilinear_8 (needx, needy, values); *dest++ = val; } /* for */ } destrow += dest_rgn.rowstride; if (dvals.do_x) mxrow += map_x_rgn.rowstride; if (dvals.do_y) myrow += map_y_rgn.rowstride; } if (!preview) { progress += dest_rgn.w * dest_rgn.h; gimp_progress_update ((double) progress / (double) max_progress); } } /* for */ gimp_pixel_fetcher_destroy (pft); /* detach from the map drawables */ if (dvals.do_x) gimp_drawable_detach (map_x); if (dvals.do_y) gimp_drawable_detach (map_y); if (preview) { /* gimp_drawable_preview_draw_region (GIMP_DRAWABLE_PREVIEW (preview), &dest_rgn);*/ gimp_preview_draw_buffer (preview, buffer, width * bytes); g_free (buffer); } else { /* 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); } }