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 gboolean process (GeglOperation *operation, GeglBuffer *input, GeglBuffer *output, const GeglRectangle *result, gint level) { GeglChantO *o = GEGL_CHANT_PROPERTIES (operation); LensDistortion old_lens; GeglRectangle boundary = *gegl_operation_source_get_bounding_box (operation, "input"); gint x, y; gfloat *src_buf, *dst_buf; src_buf = g_new0 (gfloat, result->width * result->height * 4); dst_buf = g_new0 (gfloat, result->width * result->height * 4); lens_setup_calc (o, boundary, &old_lens); gegl_buffer_get (input, result, 1.0, babl_format ("RGBA float"), src_buf, GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE); for (y = result->y; y < result->y + result->height; y++) for (x = result->x; x < result->x + result->width; x++) { lens_distort_func (src_buf, dst_buf, result, result, &boundary, old_lens, x, y, input); } gegl_buffer_set (output, result, 0, babl_format ("RGBA float"), dst_buf, GEGL_AUTO_ROWSTRIDE); g_free (dst_buf); g_free (src_buf); return TRUE; }
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 gboolean process (GeglOperation *operation, GeglBuffer *input, GeglBuffer *output, const GeglRectangle *result, gint level) { GeglChantO *o = GEGL_CHANT_PROPERTIES (operation); LensValues lens; GeglRectangle boundary; gint i, j; gfloat *src_buf, *dst_buf; gfloat background[4]; boundary = *gegl_operation_source_get_bounding_box (operation, "input"); lens = lens_setup_calc (o, boundary); src_buf = g_new0 (gfloat, SQR (MAX_WH) * 4); dst_buf = g_new0 (gfloat, SQR (CHUNK_SIZE) * 4); gegl_color_get_pixel (o->background, babl_format ("RGBA float"), background); for (j = 0; (j-1) * CHUNK_SIZE < result->height; j++) for (i = 0; (i-1) * CHUNK_SIZE < result->width; i++) { GeglRectangle chunked_result; GeglRectangle area; gint x, y; chunked_result = *GEGL_RECTANGLE (result->x + i * CHUNK_SIZE, result->y + j * CHUNK_SIZE, CHUNK_SIZE, CHUNK_SIZE); gegl_rectangle_intersect (&chunked_result, &chunked_result, result); if (chunked_result.width < 1 || chunked_result.height < 1) continue; area = get_required (&boundary, &chunked_result, operation); clamp_area (&area, lens.centre_x, lens.centre_y); gegl_buffer_get (input, &area, 1.0, babl_format ("RGBA float"), src_buf, GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_CLAMP); for (y = chunked_result.y; y < chunked_result.y + chunked_result.height; y++) for (x = chunked_result.x; x < chunked_result.x + chunked_result.width; x++) { lens_distort_func (src_buf, dst_buf, &area, &chunked_result, &boundary, &lens, x, y, input, background); } gegl_buffer_set (output, &chunked_result, 0, babl_format ("RGBA float"), dst_buf, GEGL_AUTO_ROWSTRIDE); } g_free (dst_buf); g_free (src_buf); return TRUE; }
/* FIXME: not 100% bullet proof */ static GeglRectangle get_required (GeglRectangle *boundary, const GeglRectangle *roi, GeglOperation *operation) { GeglChantO *o; GeglRectangle area; LensValues lens; gdouble x1, y1, x2, y2, x3, y3, x4, y4, mag; gint x, y, width, height; o = GEGL_CHANT_PROPERTIES (operation); lens = lens_setup_calc (o, *boundary); x = roi->x; y = roi->y; width = roi->width; height = roi->height; lens_get_source_coord (x, y, &x1, &y1, &mag, &lens); lens_get_source_coord (x + width, y, &x2, &y2, &mag, &lens); lens_get_source_coord (x, y + height, &x3, &y3, &mag, &lens); lens_get_source_coord (x + width, y + height, &x4, &y4, &mag, &lens); /* This is ugly, and happens * with a crazy set of parameters */ reorder (&x1, &x2); reorder (&x3, &x4); reorder (&y1, &y3); reorder (&y2, &y4); if (lens.centre_y > y && lens.centre_y < y + height) { gdouble x5, y5, x6, y6; lens_get_source_coord (x, lens.centre_y, &x5, &y5, &mag, &lens); lens_get_source_coord (x + width, lens.centre_y, &x6, &y6, &mag, &lens); reorder (&x5, &x6); area.x = floor (MIN3 (x1, x3, x5)) - 1; area.width = ceil (MAX3 (x2, x4, x6)) + 3 - area.x; } else { area.x = floor (MIN (x1, x3)) - 1; area.width = ceil (MAX (x2, x4)) + 3 - area.x; } if (lens.centre_x > x && lens.centre_x < x + width) { gdouble x5, y5, x6, y6; lens_get_source_coord (lens.centre_x, y, &x5, &y5, &mag, &lens); lens_get_source_coord (lens.centre_x, y + height, &x6, &y6, &mag, &lens); reorder (&y5, &y6); area.y = floor (MIN3 (y1, y2, y5)) - 1; area.height = ceil (MAX3 (y3, y4, y6)) + 3 - area.y; } else { area.y = floor (MIN (y1, y2)) - 1; area.height = ceil (MAX (y3, y4)) + 3 - area.y; } return area; }