/* ------------------------------------------- * gap_morph_shape_generate_outline_workpoints * ------------------------------------------- */ void gap_morph_shape_generate_outline_workpoints(GapMorphGlobalParams *mgpp) { GapMorphWorkPoint *wp; GimpPixelFetcher *src_pixfet; GimpPixelFetcher *dst_pixfet; GimpDrawable *dst_drawable; GimpDrawable *src_drawable; gdouble alpha_rad; gdouble step_rad; gint ii; src_drawable = gimp_drawable_get (mgpp->osrc_layer_id); dst_drawable = gimp_drawable_get (mgpp->fdst_layer_id); src_pixfet = gimp_pixel_fetcher_new (src_drawable, FALSE /*shadow*/); dst_pixfet = gimp_pixel_fetcher_new (dst_drawable, FALSE /*shadow*/); step_rad = (2.0 * G_PI) / MAX(1, mgpp->numOutlinePoints); alpha_rad = 0.0; /* loop from 0 to 360 degree */ for(ii=0; ii < mgpp->numOutlinePoints; ii++) { gdouble sx, sy, dx, dy; p_find_outmost_opaque_pixel(src_pixfet ,src_drawable->bpp ,alpha_rad ,src_drawable->width ,src_drawable->height ,&sx ,&sy ); p_find_outmost_opaque_pixel(dst_pixfet ,dst_drawable->bpp ,alpha_rad ,dst_drawable->width ,dst_drawable->height ,&dx ,&dy ); /* create a new workpoint with sx,sy, dx, dy coords */ wp = gap_morph_shape_new_workpont(sx ,sy ,dx ,dy); wp->next = mgpp->master_wp_list; mgpp->master_wp_list = wp; alpha_rad += step_rad; } gimp_pixel_fetcher_destroy (src_pixfet); gimp_pixel_fetcher_destroy (dst_pixfet); gimp_drawable_detach(src_drawable); gimp_drawable_detach(dst_drawable); } /* end gap_morph_shape_generate_outline_workpoints */
static void pf_dealloc(PyGimpPixelFetcher *self) { gimp_pixel_fetcher_destroy(self->pf); Py_XDECREF(self->drawable); PyObject_DEL(self); }
static void lens_distort_preview (GimpDrawable *drawable, GimpPreview *preview) { guchar *dest; guchar *pixel; gint width, height, bpp; gint x, y; GimpPixelFetcher *pft; GimpRGB background; pft = gimp_pixel_fetcher_new (drawable, FALSE); gimp_context_get_background (&background); gimp_rgb_set_alpha (&background, 0.0); gimp_pixel_fetcher_set_bg_color (pft, &background); gimp_pixel_fetcher_set_edge_mode (pft, GIMP_PIXEL_FETCHER_EDGE_BACKGROUND); lens_setup_calc (drawable->width, drawable->height); dest = gimp_zoom_preview_get_source (GIMP_ZOOM_PREVIEW (preview), &width, &height, &bpp); pixel = dest; for (y = 0; y < height; y++) { for (x = 0; x < width; x++) { gint sx, sy; gimp_preview_untransform (preview, x, y, &sx, &sy); lens_distort_func (sx, sy, pixel, bpp, pft); pixel += bpp; } } gimp_pixel_fetcher_destroy (pft); gimp_preview_draw_buffer (preview, dest, width * bpp); g_free (dest); }
static void polarize (GimpDrawable *drawable) { GimpRgnIterator *iter; GimpPixelFetcher *pft; GimpRGB background; pft = gimp_pixel_fetcher_new (drawable, FALSE); gimp_context_get_background (&background); gimp_rgb_set_alpha (&background, 0.0); gimp_pixel_fetcher_set_bg_color (pft, &background); gimp_pixel_fetcher_set_edge_mode (pft, GIMP_PIXEL_FETCHER_EDGE_SMEAR); gimp_progress_init (_("Polar coordinates")); iter = gimp_rgn_iterator_new (drawable, 0); gimp_rgn_iterator_dest (iter, polarize_func, pft); gimp_rgn_iterator_free (iter); gimp_pixel_fetcher_destroy (pft); }
static void lens_distort (GimpDrawable *drawable) { GimpRgnIterator *iter; GimpPixelFetcher *pft; GimpRGB background; lens_setup_calc (drawable->width, drawable->height); pft = gimp_pixel_fetcher_new (drawable, FALSE); gimp_context_get_background (&background); gimp_rgb_set_alpha (&background, 0.0); gimp_pixel_fetcher_set_bg_color (pft, &background); gimp_pixel_fetcher_set_edge_mode (pft, GIMP_PIXEL_FETCHER_EDGE_BACKGROUND); gimp_progress_init (_("Lens distortion")); iter = gimp_rgn_iterator_new (drawable, 0); gimp_rgn_iterator_dest (iter, (GimpRgnFuncDest) lens_distort_func, pft); gimp_rgn_iterator_free (iter); gimp_pixel_fetcher_destroy (pft); }
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); }
static void dialog_update_preview (GimpDrawable *drawable, GimpPreview *preview) { gdouble cx, cy; gint x, y; gint sx, sy; gint width, height; guchar *pixel; guchar outside[4]; GimpRGB background; guchar *dest; gint j; gint bpp; GimpPixelFetcher *pft; guchar in_pixels[4][4]; guchar *in_values[4]; for (j = 0; j < 4; j++) in_values[j] = in_pixels[j]; pft = gimp_pixel_fetcher_new (drawable, FALSE); gimp_context_get_background (&background); gimp_rgb_set_alpha (&background, 0.0); gimp_drawable_get_color_uchar (drawable->drawable_id, &background, outside); gimp_pixel_fetcher_set_bg_color (pft, &background); gimp_pixel_fetcher_set_edge_mode (pft, GIMP_PIXEL_FETCHER_EDGE_SMEAR); dest = gimp_zoom_preview_get_source (GIMP_ZOOM_PREVIEW (preview), &width, &height, &bpp); pixel = dest; for (y = 0; y < height; y++) { for (x = 0; x < width; x++) { gimp_preview_untransform (preview, x, y, &sx, &sy); if (calc_undistorted_coords ((gdouble)sx, (gdouble)sy, &cx, &cy)) { gimp_pixel_fetcher_get_pixel (pft, cx, cy, in_pixels[0]); gimp_pixel_fetcher_get_pixel (pft, cx + 1, cy, in_pixels[1]); gimp_pixel_fetcher_get_pixel (pft, cx, cy + 1, in_pixels[2]); gimp_pixel_fetcher_get_pixel (pft, cx + 1, cy + 1, in_pixels[3]); gimp_bilinear_pixels_8 (pixel, cx, cy, bpp, img_has_alpha, in_values); } else { for (j = 0; j < bpp; j++) pixel[j] = outside[j]; } pixel += bpp; } } gimp_pixel_fetcher_destroy (pft); gimp_preview_draw_buffer (preview, dest, width * bpp); g_free (dest); }
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); }
/* ---------------------------------------- * gap_edgeDetection * ---------------------------------------- * * returns the drawable id of a newly created channel * representing edges of the specified image. * * black pixels indicate areas of same or similar colors, * white indicates sharp edges. * */ gint32 gap_edgeDetection(gint32 refDrawableId , gdouble edgeColordiffThreshold , gint32 *countEdgePixels ) { GapEdgeContext edgeContext; GapEdgeContext *ectx; gdouble edgeOpacityThreshold; /* init context */ ectx = &edgeContext; ectx->refDrawable = gimp_drawable_get(refDrawableId); ectx->edgeDrawable = NULL; ectx->edgeColordiffThreshold = CLAMP(edgeColordiffThreshold, 0.0, 1.0); edgeOpacityThreshold = CLAMP((edgeColordiffThreshold * 255), 0, 255); ectx->edgeOpacityThreshold255 = edgeOpacityThreshold; ectx->edgeDrawableId = -1; ectx->countEdgePixels = 0; if(gap_debug) { printf("gap_edgeDetection START edgeColordiffThreshold:%.5f refDrawableId:%d\n" , (float)ectx->edgeColordiffThreshold , (int)refDrawableId ); } if(ectx->refDrawable != NULL) { ectx->pftRef = gimp_pixel_fetcher_new (ectx->refDrawable, FALSE /* shadow */); gimp_pixel_fetcher_set_edge_mode (ectx->pftRef, GIMP_PIXEL_FETCHER_EDGE_BLACK); p_edgeDetection(ectx); gimp_pixel_fetcher_destroy (ectx->pftRef); } if(ectx->refDrawable != NULL) { gimp_drawable_detach(ectx->refDrawable); ectx->refDrawable = NULL; } if(ectx->edgeDrawable != NULL) { gimp_drawable_detach(ectx->edgeDrawable); ectx->edgeDrawable = NULL; } *countEdgePixels = ectx->countEdgePixels; if(gap_debug) { printf("gap_edgeDetection END resulting edgeDrawableId:%d countEdgePixels:%d\n" , (int)ectx->edgeDrawableId , (int)*countEdgePixels ); } return (ectx->edgeDrawableId); } /* end gap_edgeDetection */
static void edge (GimpDrawable *drawable) { GimpPixelRgn src_rgn, dest_rgn; gpointer pr; GimpPixelFetcher *pft; guchar *srcrow, *src; guchar *destrow, *dest; guchar pix00[4], pix01[4], pix02[4]; guchar pix10[4], pix11[4], pix12[4]; guchar pix20[4], pix21[4], pix22[4]; glong width, height; gint alpha; gboolean has_alpha; gint chan; gint x, y; gint x1, y1, x2, y2; gint maxval; gint cur_progress; gint max_progress; gdouble per_progress; if (evals.amount < 1.0) evals.amount = 1.0; pft = gimp_pixel_fetcher_new (drawable, FALSE); gimp_pixel_fetcher_set_edge_mode (pft, evals.wrapmode); gimp_drawable_mask_bounds (drawable->drawable_id, &x1, &y1, &x2, &y2); width = gimp_drawable_width (drawable->drawable_id); height = gimp_drawable_height (drawable->drawable_id); alpha = gimp_drawable_bpp (drawable->drawable_id); has_alpha = gimp_drawable_has_alpha (drawable->drawable_id); if (has_alpha) alpha--; maxval = 255; cur_progress = 0; per_progress = 0.0; max_progress = (x2 - x1) * (y2 - y1) / 100; gimp_pixel_rgn_init (&src_rgn, drawable, x1, y1, x2-x1, y2-y1, FALSE, FALSE); gimp_pixel_rgn_init (&dest_rgn, drawable, x1, y1, x2-x1, y2-y1, TRUE, TRUE); for (pr = gimp_pixel_rgns_register (2, &src_rgn, &dest_rgn); pr != NULL; pr = gimp_pixel_rgns_process (pr)) { srcrow = src_rgn.data; destrow = dest_rgn.data; for (y = dest_rgn.y; y < (dest_rgn.y + dest_rgn.h); y++, srcrow += src_rgn.rowstride, destrow += dest_rgn.rowstride) { src = srcrow; dest = destrow; for (x = dest_rgn.x; x < (dest_rgn.x + dest_rgn.w); x++, src += src_rgn.bpp, dest += dest_rgn.bpp) { if (dest_rgn.x < x && x < dest_rgn.x + dest_rgn.w - 2 && dest_rgn.y < y && y < dest_rgn.y + dest_rgn.h - 2) { /* * 3x3 kernel is inside of the tile -- do fast * version */ for (chan = 0; chan < alpha; chan++) { /* get the 3x3 kernel into a guchar array, * and send it to edge_detect */ guchar kernel[9]; gint i,j; #define PIX(X,Y) src[ (Y-1)*(int)src_rgn.rowstride + (X-1)*(int)src_rgn.bpp + chan ] /* make convolution */ for(i = 0; i < 3; i++) for(j = 0; j < 3; j++) kernel[3*i + j] = PIX(i,j); #undef PIX dest[chan] = edge_detect (kernel); } } else { /* * The kernel is not inside of the tile -- do slow * version */ gimp_pixel_fetcher_get_pixel (pft, x-1, y-1, pix00); gimp_pixel_fetcher_get_pixel (pft, x , y-1, pix10); gimp_pixel_fetcher_get_pixel (pft, x+1, y-1, pix20); gimp_pixel_fetcher_get_pixel (pft, x-1, y , pix01); gimp_pixel_fetcher_get_pixel (pft, x , y , pix11); gimp_pixel_fetcher_get_pixel (pft, x+1, y , pix21); gimp_pixel_fetcher_get_pixel (pft, x-1, y+1, pix02); gimp_pixel_fetcher_get_pixel (pft, x , y+1, pix12); gimp_pixel_fetcher_get_pixel (pft, x+1, y+1, pix22); for (chan = 0; chan < alpha; chan++) { guchar kernel[9]; kernel[0] = pix00[chan]; kernel[1] = pix01[chan]; kernel[2] = pix02[chan]; kernel[3] = pix10[chan]; kernel[4] = pix11[chan]; kernel[5] = pix12[chan]; kernel[6] = pix20[chan]; kernel[7] = pix21[chan]; kernel[8] = pix22[chan]; dest[chan] = edge_detect (kernel); } } if (has_alpha) dest[alpha] = src[alpha]; } } cur_progress += dest_rgn.w * dest_rgn.h; if (cur_progress > max_progress) { cur_progress = cur_progress - max_progress; per_progress = per_progress + 0.01; gimp_progress_update (per_progress); } } gimp_progress_update (1.0); gimp_pixel_fetcher_destroy (pft); gimp_drawable_flush (drawable); gimp_drawable_merge_shadow (drawable->drawable_id, TRUE); gimp_drawable_update (drawable->drawable_id, x1, y1, (x2 - x1), (y2 - y1)); }
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); } }
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); } }
/* -------------------------------- * gap_moprhShapeDetectionEdgeBased * -------------------------------- * * generates morph workpoints via edge based shape detection. * This is done by edge detection in the source image * (specified via mgup->mgpp->osrc_layer_id) * * and picking workpoints on the detected edges * and locating the corresponding point in the destination image. * * IN: mgup->num_shapepoints specifies the number of workpoints to be generated. */ void gap_moprhShapeDetectionEdgeBased(GapMorphGUIParams *mgup, gboolean *cancelFlagPtr) { GapMorphShapeContext morphShapeContext; GapMorphShapeContext *msctx; gboolean deleteEdgeImage; GapMorphGlobalParams *mgpp; mgpp = mgup->mgpp; if(mgup->workpointGenerationBusy == TRUE) { return; } mgup->workpointGenerationBusy = TRUE; deleteEdgeImage = TRUE; /* init context */ msctx = &morphShapeContext; msctx->edgeColordiffThreshold = CLAMP(mgpp->edgeColordiffThreshold, 0.0, 1.0); msctx->locateColordiffThreshold = CLAMP(mgpp->locateColordiffThreshold, 0.0, 1.0); msctx->locateDetailShapeRadius = mgpp->locateDetailShapeRadius; msctx->locateDetailMoveRadius = mgpp->locateDetailMoveRadius; msctx->colorSensitivity = GAP_COLORDIFF_DEFAULT_SENSITIVITY; msctx->refLayerId = mgpp->osrc_layer_id; msctx->targetLayerId = mgpp->fdst_layer_id; msctx->numShapePoints = mgpp->numWorkpoints; msctx->countGeneratedPoints = 0; msctx->doProgress = TRUE; msctx->progressBar = mgup->progressBar; if(msctx->progressBar == NULL) { msctx->doProgress = FALSE; } msctx->cancelWorkpointGenerationPtr = cancelFlagPtr; if(gap_debug) { printf("gap_moprhShapeDetectionEdgeBased START edgeThres:%.5f locateThres:%.5f locateRadius:%d\n" , (float)msctx->edgeColordiffThreshold , (float)msctx->locateDetailMoveRadius , (int)msctx->locateDetailMoveRadius ); } msctx->edgeLayerId = gap_edgeDetection(mgup->mgpp->osrc_layer_id /* refDrawableId */ ,mgup->mgpp->edgeColordiffThreshold ,&msctx->countEdgePixels ); msctx->edgeImageId = gimp_drawable_get_image(msctx->edgeLayerId); if(gap_debug) { /* show the edge image for debug purpose * (this image is intended for internal processing usage) */ gimp_display_new(msctx->edgeImageId); deleteEdgeImage = FALSE; } msctx->edgeDrawable = gimp_drawable_get(msctx->edgeLayerId); if(msctx->edgeDrawable != NULL) { gint maxWidth; gint maxHeight; maxWidth = msctx->edgeDrawable->width-1; maxHeight = msctx->edgeDrawable->height-1; if((mgup->src_win.zoom < 1.0) && (mgup->src_win.zoom > 0.0)) { gdouble fwidth; gdouble fheight; gint width; gint height; fwidth = mgup->src_win.zoom * (gdouble)mgup->src_win.pv_ptr->pv_width; fheight = mgup->src_win.zoom * (gdouble)mgup->src_win.pv_ptr->pv_height; width = CLAMP((gint)fwidth, 1, maxWidth); height = CLAMP((gint)fheight, 1, maxHeight); msctx->sel1X = CLAMP(mgup->src_win.offs_x, 0, maxWidth); msctx->sel1Y = CLAMP(mgup->src_win.offs_y, 0, maxHeight); msctx->sel2X = CLAMP((msctx->sel1X + width), 0, maxWidth); msctx->sel2Y = CLAMP((msctx->sel1Y + height), 0, maxHeight); } else { msctx->sel1X = 0; msctx->sel1Y = 0; msctx->sel2X = maxWidth; msctx->sel2Y = maxHeight; } if(gap_debug) { printf("Boundaries: sel1: %d / %d sel2: %d / %d zoom:%.5f\n" , (int)msctx->sel1X , (int)msctx->sel1Y , (int)msctx->sel2X , (int)msctx->sel2Y , (float)mgup->src_win.zoom ); } msctx->pftEdge = gimp_pixel_fetcher_new (msctx->edgeDrawable, FALSE /* shadow */); gimp_pixel_fetcher_set_edge_mode (msctx->pftEdge, GIMP_PIXEL_FETCHER_EDGE_BLACK); p_generateWorkpoints(msctx, mgpp); gimp_pixel_fetcher_destroy (msctx->pftEdge); } if(msctx->edgeDrawable != NULL) { gimp_drawable_detach(msctx->edgeDrawable); msctx->edgeDrawable = NULL; } if(deleteEdgeImage == TRUE) { gap_image_delete_immediate(msctx->edgeImageId); } if(gap_debug) { printf("gap_moprhShapeDetectionEdgeBased END\n"); } mgup->workpointGenerationBusy = FALSE; return ; } /* end gap_moprhShapeDetectionEdgeBased */