static void ripple_horizontal (gint x, gint y, guchar *dest, gint bpp, gpointer data) { RippleParam_t *param = (RippleParam_t*) data; GimpPixelFetcher *pft; guchar pixel[2][4]; gdouble needx; gint xi, xi_a, width; pft = param->pft; width = param->width; needx = x + displace_amount(y); xi = floor (needx); xi_a = xi+1; /* Tile the image. */ if (rvals.edges == WRAP) { needx = fmod((needx), width); while (needx < 0.0) needx += width; xi = (xi % width); while (xi < 0) xi += width; xi_a = (xi+1) % width; } /* Smear out the edges of the image by repeating pixels. */ else if (rvals.edges == SMEAR) { needx = CLAMP(needx , 0, width - 1); xi = CLAMP(xi , 0, width - 1); xi_a = CLAMP(xi + 1, 0, width - 1); } if (rvals.antialias) { if (xi >= 0 && xi < width) gimp_pixel_fetcher_get_pixel (pft, xi, y, pixel[0]); else memset(pixel[0], 0, 4); if (xi_a >= 0 && xi_a < width) gimp_pixel_fetcher_get_pixel (pft, xi_a, y, pixel[1]); else memset(pixel[1], 0, 4); average_two_pixels (dest, pixel, needx - xi, bpp, param->has_alpha); } /* antialias */ else { if (xi >=0 && xi < width) gimp_pixel_fetcher_get_pixel (pft, xi, y, dest); else memset(dest, 0, bpp); } }
static void spread_func (gint x, gint y, guchar *dest, gint bpp, gpointer data) { SpreadParam_t *param = (SpreadParam_t*) data; gdouble angle; gint xdist, ydist; gint xi, yi; /* get random angle, x distance, and y distance */ xdist = (param->x_amount > 0 ? g_rand_int_range (param->gr, -param->x_amount, param->x_amount) : 0); ydist = (param->y_amount > 0 ? g_rand_int_range (param->gr, -param->y_amount, param->y_amount) : 0); angle = g_rand_double_range (param->gr, -G_PI, G_PI); xi = x + floor (sin (angle) * xdist); yi = y + floor (cos (angle) * ydist); /* Only displace the pixel if it's within the bounds of the image. */ if (xi >= 0 && xi < param->width && yi >= 0 && yi < param->height) { gimp_pixel_fetcher_get_pixel (param->pft, xi, yi, dest); } else /* Else just copy it */ { gimp_pixel_fetcher_get_pixel (param->pft, x, y, dest); } }
static void ripple_vertical (gint x, gint y, guchar *dest, gint bpp, gpointer data) { RippleParam_t *param = (RippleParam_t*) data; GimpPixelFetcher *pft; guchar pixel[2][4]; gdouble needy; gint yi, yi_a, height; pft = param->pft; height = param->height; needy = y + displace_amount(x); yi = floor(needy); yi_a = yi+1; /* Tile the image. */ if (rvals.edges == WRAP) { needy = fmod(needy, height); if (needy < 0.0) needy += height; yi = (yi % height); if (yi < 0) yi += height; yi_a = (yi+1) % height; } /* Smear out the edges of the image by repeating pixels. */ else if (rvals.edges == SMEAR) { needy= CLAMP (needy , 0, height - 1); yi = CLAMP (yi , 0, height - 1); yi_a = CLAMP (yi_a + 1, 0, height - 1); } if (rvals.antialias) { if (yi >=0 && yi < height) gimp_pixel_fetcher_get_pixel (pft, x, yi , pixel[0]); else memset(pixel[0], 0, 4); if (yi_a >=0 && yi_a < height) gimp_pixel_fetcher_get_pixel (pft, x, yi_a, pixel[1]); else memset(pixel[1], 0, 4); average_two_pixels (dest, pixel, needy - yi, bpp, param->has_alpha); } /* antialias */ else { if (yi >=0 && yi < height) gimp_pixel_fetcher_get_pixel (pft, x, yi, dest); else memset(dest, 0, bpp); } }
static PyObject * pf_subscript(PyGimpPixelFetcher *self, PyObject *key) { PyObject *py_x, *py_y; int x, y; guchar pixel[4]; if (!PyTuple_Check(key) || PyTuple_Size(key) != 2) { PyErr_SetString(PyExc_TypeError, "subscript must be a 2-tuple"); return NULL; } if (!PyArg_ParseTuple(key, "OO", &py_x, &py_y)) return NULL; if (PyInt_Check(py_x)) { if (PyInt_Check(py_y)) { x = PyInt_AsLong(py_x); y = PyInt_AsLong(py_y); gimp_pixel_fetcher_get_pixel(self->pf, x, y, pixel); return PyString_FromStringAndSize((char *)pixel, self->bpp); } else { PyErr_SetString(PyExc_TypeError, "invalid y subscript"); return NULL; } } else { PyErr_SetString(PyExc_TypeError, "invalid x subscript"); return NULL; } }
/* ----------------------------- * p_pixel_check_opaque * ----------------------------- * check average opacity in an area * of 2x2 pixels * return TRUE if average alpha is 50% or more opaque */ static gboolean p_pixel_check_opaque(GimpPixelFetcher *pft, gint bpp, gdouble needx, gdouble needy) { guchar pixel[4][4]; gdouble alpha_val; gint xi, yi; gint alpha_idx; 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]); alpha_idx = bpp -1; /* average aplha channel normalized to range 0.0 upto 1.0 */ alpha_val = ( (gdouble)pixel[0][alpha_idx] / 255.0 + (gdouble)pixel[1][alpha_idx] / 255.0 + (gdouble)pixel[2][alpha_idx] / 255.0 + (gdouble)pixel[3][alpha_idx] / 255.0 ) / 4.0; if (alpha_val > 0.5) /* fix THRESHOLD half or more opaque */ { return (TRUE); } return (FALSE); } /* end p_pixel_check_opaque */
static void lens_distort_func (gint ix, gint iy, guchar *dest, gint bpp, GimpPixelFetcher *pft) { gdouble src_x, src_y, mag; gdouble brighten; guchar pixel_buffer[16 * LENS_MAX_PIXEL_DEPTH]; guchar *pixel; gdouble dx, dy; gint x_int, y_int; gint x, y; lens_get_source_coords (ix, iy, &src_x, &src_y, &mag); brighten = 1.0 + mag * calc_vals.brighten; x_int = floor (src_x); dx = src_x - x_int; y_int = floor (src_y); dy = src_y - y_int; pixel = pixel_buffer; for (y = y_int - 1; y <= y_int + 2; y++) { for (x = x_int -1; x <= x_int + 2; x++) { if (x >= 0 && y >= 0 && x < drawable_width && y < drawable_height) { gimp_pixel_fetcher_get_pixel (pft, x, y, pixel); } else { gint i; for (i = 0; i < bpp; i++) pixel[i] = background_color[i]; } pixel += bpp; } } lens_cubic_interpolate (pixel_buffer, bpp * 4, bpp, dest, bpp, dx, dy, brighten); }
static void polarize_func (gint x, gint y, guchar *dest, gint bpp, gpointer data) { double cx, cy; if (calc_undistorted_coords (x, y, &cx, &cy)) { guchar pixel1[4], pixel2[4], pixel3[4], pixel4[4]; guchar *values[4]; GimpPixelFetcher *pft = (GimpPixelFetcher*) data; values[0] = pixel1; values[1] = pixel2; values[2] = pixel3; values[3] = pixel4; gimp_pixel_fetcher_get_pixel (pft, cx, cy, pixel1); gimp_pixel_fetcher_get_pixel (pft, cx + 1, cy, pixel2); gimp_pixel_fetcher_get_pixel (pft, cx, cy + 1, pixel3); gimp_pixel_fetcher_get_pixel (pft, cx + 1, cy + 1, pixel4); gimp_bilinear_pixels_8 (dest, cx, cy, bpp, img_has_alpha, values); } else { gint b; for (b = 0; b < bpp; b++) { dest[b] = back_color[b]; } } }
static PyObject * pf_get_pixel(PyGimpPixelFetcher *self, PyObject *args, PyObject *kwargs) { int x, y; guchar pixel[4]; static char *kwlist[] = { "x", "y", NULL }; if (!PyArg_ParseTupleAndKeywords(args, kwargs, "ii:get_pixel", kwlist, &x, &y)) return NULL; gimp_pixel_fetcher_get_pixel(self->pf, x, y, pixel); return PyString_FromStringAndSize((char *)pixel, self->bpp); }
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 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); } }
/* -------------------------------- * p_generateWorkpoints * -------------------------------- * scan the edge drawable with descending grid size (defined stepSizeTab) * and descending edge threshold. This shall spread the generated * workpoints all over the whole area where bright edge points * are picked first. */ static void p_generateWorkpoints(GapMorphShapeContext *msctx, GapMorphGlobalParams *mgpp) { #define LOOP_LOOKUP_TAB_SIZE 5 static gint32 edgeThresTab[LOOP_LOOKUP_TAB_SIZE] = { 120, 60, 30, 10, 1 }; static gint32 nearRadiusTab[LOOP_LOOKUP_TAB_SIZE] = { 20, 14, 10, 6, 2 }; static gint32 stepSizeTab[LOOP_LOOKUP_TAB_SIZE] = { 10, 8, 6, 2, 1 }; gint32 ex; gint32 ey; gdouble srcX; gdouble srcY; gint32 nearRadius; gint32 edgePixelThreshold255; gint32 stepSize; gint32 ii; for(ii=0; ii < LOOP_LOOKUP_TAB_SIZE; ii++) { edgePixelThreshold255 = edgeThresTab[ii]; nearRadius = nearRadiusTab[ii]; stepSize = stepSizeTab[ii]; for(ey=msctx->sel1Y; ey < msctx->sel2Y; ey += stepSize) { srcY = ey +1; for(ex=msctx->sel1X; ex < msctx->sel2X; ex += stepSize) { guchar pixel[4]; if(*msctx->cancelWorkpointGenerationPtr == TRUE) { return; } gimp_pixel_fetcher_get_pixel (msctx->pftEdge, ex, ey, &pixel[0]); if(pixel[0] >= edgePixelThreshold255) { /* found an edge pixel */ GapMorphWorkPoint *wp; srcX = ex +1; /* chek if workpoint with this (or very near) coords does already exist */ wp = p_find_workpoint_near_src_coords(mgpp , srcX , srcY , nearRadius ); if(wp == NULL) { gboolean success; gdouble dstX; gdouble dstY; gdouble locateColordiff; success = p_locate_workpoint(msctx , srcX, srcY , &dstX, &dstY , &locateColordiff ); if(success) { wp = gap_morph_shape_new_workpont(srcX, srcY, dstX, dstY); wp->locateColordiff = locateColordiff; if(TRUE == p_workpoint_plausiblity_filter(msctx , mgpp , wp )) { msctx->countGeneratedPoints++; /* add new workpoint as 1st listelement */ wp->next = mgpp->master_wp_list; mgpp->master_wp_list = wp; p_doProgress(msctx); if(msctx->countGeneratedPoints >= msctx->numShapePoints) { return; } } else { g_free(wp); } } } } } } } } /* end p_generateWorkpoints */
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_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); }
/* --------------------------------- * p_edgeProcessingForOneRegion * --------------------------------- * render edge drawable for the current processed pixel region. * (use a pixelfetcher on region boundaries) */ static void p_edgeProcessingForOneRegion (const GimpPixelRgn *refPR ,const GimpPixelRgn *edgePR ,GapEdgeContext *ectx) { guint row; guchar* ref = refPR->data; guchar* edge = edgePR->data; guchar rightPixel[4]; guchar botPixel[4]; guchar rbPixel[4]; guchar* rightPixelPtr; guchar* botPixelPtr; guchar* rbPixelPtr; gint32 rx; gint32 ry; gboolean debugPrint; if(gap_debug) { printf("p_edgeProcessingForOneRegion START\n"); } debugPrint = FALSE; for (row = 0; row < edgePR->h; row++) { guint col; guint idxref; guint idxedge; ry = refPR->y + row; idxref = 0; idxedge = 0; for(col = 0; col < edgePR->w; col++) { gdouble colordiff1; gdouble colordiff2; gdouble colordiff3; gdouble maxColordiff; gboolean isColorCompareRequired; rbPixelPtr = &ref[idxref]; rx = refPR->x + col; isColorCompareRequired = TRUE; /* * if(gap_debug) * { * debugPrint = FALSE; * if((rx == 596) || (rx == 597)) * { * if((ry==818) ||(ry==818)) * { * debugPrint = TRUE; * } * } * } */ if(col < edgePR->w -1) { rightPixelPtr = &ref[idxref + refPR->bpp]; if(row < edgePR->h -1) { rbPixelPtr = &ref[idxref + refPR->bpp + refPR->rowstride]; } } else if(rx >= ectx->refDrawable->width -1) { /* drawable border is not considered as edge */ rightPixelPtr = &ref[idxref]; } else { rightPixelPtr = &rightPixel[0]; gimp_pixel_fetcher_get_pixel (ectx->pftRef, rx +1, ry, rightPixelPtr); if(ry >= ectx->refDrawable->height -1) { rbPixelPtr = &rbPixel[0]; gimp_pixel_fetcher_get_pixel (ectx->pftRef, rx +1, ry +1, rbPixelPtr); } } if(row < edgePR->h -1) { botPixelPtr = &ref[idxref + refPR->rowstride]; } else if(ry >= ectx->refDrawable->height -1) { /* drawable border is not considered as edge */ botPixelPtr = &ref[idxref]; } else { botPixelPtr = &botPixel[0]; gimp_pixel_fetcher_get_pixel (ectx->pftRef, rx, ry +1, botPixelPtr); } if(refPR->bpp > 3) { /* reference drawable has alpha channel * in this case significant changes of opacity shall detect edge */ gint32 maxAlphaDiff; maxAlphaDiff = MAX(abs(ref[idxref +3] - rightPixelPtr[3]) ,abs(ref[idxref +3] - botPixelPtr[3])); maxAlphaDiff = MAX(maxAlphaDiff ,abs(ref[idxref +3] - rbPixelPtr[3])); if(debugPrint) { printf("rx:%d ry:%d idxref:%d idxedge:%d (maxAlphaDiff):%d Thres:%d Alpha ref:%d right:%d bot:%d rb:%d\n" , (int)rx , (int)ry , (int)idxref , (int)idxedge , (int)maxAlphaDiff , (int)ectx->edgeOpacityThreshold255 , (int)ref[idxref +3] , (int)rightPixelPtr[3] , (int)botPixelPtr[3] , (int)rbPixelPtr[3] ); } if(maxAlphaDiff > ectx->edgeOpacityThreshold255) { ectx->countEdgePixels++; edge[idxedge] = maxAlphaDiff; isColorCompareRequired = FALSE; } else if(ref[idxref +3] < OPACITY_LEVEL_UCHAR) { /* transparent pixel is not considered as edge */ edge[idxedge] = 0; isColorCompareRequired = FALSE; } } if(isColorCompareRequired == TRUE) { colordiff1 = gap_colordiff_simple_guchar(&ref[idxref] , &rightPixelPtr[0] , debugPrint /* debugPrint */ ); colordiff2 = gap_colordiff_simple_guchar(&ref[idxref] , &botPixelPtr[0] , debugPrint /* debugPrint */ ); colordiff3 = gap_colordiff_simple_guchar(&ref[idxref] , &rbPixelPtr[0] , debugPrint /* debugPrint */ ); maxColordiff = MAX(colordiff1, colordiff2); maxColordiff = MAX(maxColordiff, colordiff3); if(debugPrint) { printf("rx:%d ry:%d colordiff(1): %.5f (2):%.5f (3):%.5f (max):%.5f Thres:%.5f\n" , (int)rx , (int)ry , (float)colordiff1 , (float)colordiff2 , (float)colordiff3 , (float)maxColordiff , (float)ectx->edgeColordiffThreshold ); } if (maxColordiff < ectx->edgeColordiffThreshold) { edge[idxedge] = 0; } else { gdouble value; value = maxColordiff * 255.0; edge[idxedge] = CLAMP(value, 1, 255); ectx->countEdgePixels++; } } idxref += refPR->bpp; idxedge += edgePR->bpp; } ref += refPR->rowstride; edge += edgePR->rowstride; } } /* end p_edgeProcessingForOneRegion */