/** * gimp_drawable_get: * @drawable_ID: the ID of the drawable * * This function creates a #GimpDrawable structure for the core * drawable identified by @drawable_ID. The returned structure * contains some basic information about the drawable and can also * hold tile data for transfer to and from the core. * * Note that the name of this function is somewhat misleading, because * it suggests that it simply returns a handle. This is not the case: * if the function is called multiple times, it creates separate tile * lists each time, which will usually produce undesired results. * * When a plug-in has finished working with a drawable, before exiting * it should call gimp_drawable_detach() to make sure that all tile data is * transferred back to the core. * * Return value: a new #GimpDrawable wrapper **/ GimpDrawable * gimp_drawable_get (gint32 drawable_ID) { GimpDrawable *drawable; gint width; gint height; gint bpp; width = gimp_drawable_width (drawable_ID); height = gimp_drawable_height (drawable_ID); bpp = gimp_drawable_bpp (drawable_ID); g_return_val_if_fail (width > 0 && height > 0 && bpp > 0, NULL); drawable = g_slice_new0 (GimpDrawable); drawable->drawable_id = drawable_ID; drawable->width = width; drawable->height = height; drawable->bpp = bpp; drawable->ntile_rows = (height + TILE_HEIGHT - 1) / TILE_HEIGHT; drawable->ntile_cols = (width + TILE_WIDTH - 1) / TILE_WIDTH; return drawable; }
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); width = preview->width; height = preview->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 gboolean preview_event_handler (GtkWidget *area, GdkEvent *event, GtkWidget *preview) { gint pos; guchar *buf; guint32 drawable_id; GimpRGB color; GdkEventButton *button_event = (GdkEventButton *)event; buf = GIMP_PREVIEW_AREA (area)->buf; drawable_id = GIMP_DRAWABLE_PREVIEW (preview)->drawable->drawable_id; switch (event->type) { case GDK_BUTTON_PRESS: if (button_event->button == 2) { pos = event->button.x * gimp_drawable_bpp (drawable_id) + event->button.y * GIMP_PREVIEW_AREA (area)->rowstride; gimp_rgb_set_uchar (&color, buf[pos], buf[pos + 1], buf[pos + 2]); gimp_color_button_set_color (GIMP_COLOR_BUTTON (from_colorbutton), &color); } break; default: break; } return FALSE; }
static void getrange (GimpDrawable *drawable, guchar *mintab, guchar *maxtab, gint x1, gint y1, gint x2, gint y2) { gint i, j, k, channels; GimpPixelRgn rgn_in; guchar *inrow; channels = gimp_drawable_bpp (drawable->drawable_id); gimp_pixel_rgn_init (&rgn_in, drawable, x1, y1, x2 - x1, y2 - y1, FALSE, FALSE); inrow = g_new (guchar, channels * (x2 - x1)); for (j = 0; j < 4; j++){ mintab[j]=255; maxtab[j]=0; } for (i = y1; i < y2; i++) { /* Get row i */ gimp_pixel_rgn_get_row (&rgn_in, inrow, x1, i, x2 - x1); for (j = x1; j < x2; j++) { for (k = 0; k < channels; k++){ mintab[k]=MIN ( inrow[channels * (j - x1) + k], mintab[k] ) ; maxtab[k]=MAX ( inrow[channels * (j - x1) + k], maxtab[k] ) ; } } } g_free (inrow); }
void precompute_init (gint w, gint h) { gint n; gint bpp=1; xstep = 1.0 / (gdouble) width; ystep = 1.0 / (gdouble) height; pre_w = w; pre_h = h; for (n = 0; n < 3; n++) { if (vertex_normals[n] != NULL) g_free (vertex_normals[n]); if (heights[n] != NULL) g_free (heights[n]); heights[n] = g_new (gdouble, w); vertex_normals[n] = g_new (GimpVector3, w); } for (n = 0; n < 2; n++) if (triangle_normals[n] != NULL) g_free (triangle_normals[n]); if (bumprow != NULL) { g_free (bumprow); bumprow = NULL; } if (mapvals.bumpmap_id != -1) { bpp = gimp_drawable_bpp(mapvals.bumpmap_id); } bumprow = g_new (guchar, w * bpp); triangle_normals[0] = g_new (GimpVector3, (w << 1) + 2); triangle_normals[1] = g_new (GimpVector3, (w << 1) + 2); for (n = 0; n < (w << 1) + 1; n++) { gimp_vector3_set (&triangle_normals[0][n], 0.0, 0.0, 1.0); gimp_vector3_set (&triangle_normals[1][n], 0.0, 0.0, 1.0); } for (n = 0; n < w; n++) { gimp_vector3_set (&vertex_normals[0][n], 0.0, 0.0, 1.0); gimp_vector3_set (&vertex_normals[1][n], 0.0, 0.0, 1.0); gimp_vector3_set (&vertex_normals[2][n], 0.0, 0.0, 1.0); heights[0][n] = 0.0; heights[1][n] = 0.0; heights[2][n] = 0.0; } }
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); }
static gboolean sel2path (gint32 image_ID) { gint32 selection_ID; GimpDrawable *sel_drawable; pixel_outline_list_type olt; spline_list_array_type splines; gimp_selection_bounds (image_ID, &has_sel, &sel_x1, &sel_y1, &sel_x2, &sel_y2); sel_width = sel_x2 - sel_x1; sel_height = sel_y2 - sel_y1; /* Now get the selection channel */ selection_ID = gimp_image_get_selection (image_ID); if (selection_ID < 0) return FALSE; sel_drawable = gimp_drawable_get (selection_ID); if (gimp_drawable_bpp (selection_ID) != 1) { g_warning ("Internal error. Selection bpp > 1"); return FALSE; } gimp_pixel_rgn_init (&selection_rgn, sel_drawable, sel_x1, sel_y1, sel_width, sel_height, FALSE, FALSE); gimp_tile_cache_ntiles (2 * (sel_drawable->width + gimp_tile_width () - 1) / gimp_tile_width ()); olt = find_outline_pixels (); splines = fitted_splines (olt); do_points (splines, image_ID); gimp_drawable_detach (sel_drawable); gimp_displays_flush (); return TRUE; }
static gint32 load_raw( char* filename, FILE* file, enum pix_fmt fmt, struct raw_data* img_data, const gchar* plugin_name ) { gint nr_chls; gint x, y; gint32 img; gint32 layer; GimpDrawable* drawable; GimpPixelRgn pixel_rgn; guchar *pix_row; guint width = img_data->size[0]; guint height = img_data->size[1]; if (width <= 0 || height <= 0) { return ERROR; } img = create_new_image(filename, NULL, width, height, GIMP_RGB, &layer, &drawable, &pixel_rgn); nr_chls = gimp_drawable_bpp(drawable->drawable_id); pix_row = g_new(guchar, nr_chls * width); x = 0; y = 0; while (1) { guchar rgb[3]; if (read_rgb_pixel(file, fmt, rgb) == ERROR) return ERROR; pix_row[nr_chls * x] = rgb[IDX_RED]; pix_row[nr_chls * x + 1] = rgb[IDX_GREEN]; pix_row[nr_chls * x + 2] = rgb[IDX_BLUE]; x++; if (x == width) { gimp_pixel_rgn_set_row(&pixel_rgn, pix_row, 0, y, width); x = 0; y++; } if (y == height) break; } if (fgetc(file) != EOF) { printf("%s: warning: file contains more data\n", plugin_name); } return img; }
/* Returns NGRADSAMPLES samples of active gradient. Each sample has (gimp_drawable_bpp (drawable_id)) bytes. "ripped" from gradmap.c. */ static guchar * get_gradient_samples (gint32 drawable_id, gboolean reverse) { gchar *gradient_name; gint n_f_samples; gdouble *f_samples, *f_samp; /* float samples */ guchar *b_samples, *b_samp; /* byte samples */ gint bpp, color, has_alpha, alpha; gint i, j; gradient_name = gimp_context_get_gradient (); gimp_gradient_get_uniform_samples (gradient_name, NGRADSAMPLES, reverse, &n_f_samples, &f_samples); g_free (gradient_name); bpp = gimp_drawable_bpp (drawable_id); color = gimp_drawable_is_rgb (drawable_id); has_alpha = gimp_drawable_has_alpha (drawable_id); alpha = (has_alpha ? bpp - 1 : bpp); b_samples = g_new (guchar, NGRADSAMPLES * bpp); for (i = 0; i < NGRADSAMPLES; i++) { b_samp = &b_samples[i * bpp]; f_samp = &f_samples[i * 4]; if (color) for (j = 0; j < 3; j++) b_samp[j] = f_samp[j] * 255; else b_samp[0] = GIMP_RGB_LUMINANCE (f_samp[0], f_samp[1], f_samp[2]) * 255; if (has_alpha) b_samp[alpha] = f_samp[3] * 255; } g_free (f_samples); return b_samples; }
static void blur (GimpDrawable *drawable) { gint i, j, k, channels; gint x1, y1, x2, y2; GimpPixelRgn rgn_in, rgn_out; guchar *row1, *row2, *row3; guchar *outrow; gimp_drawable_mask_bounds (drawable->drawable_id, &x1, &y1, &x2, &y2); channels = gimp_drawable_bpp (drawable->drawable_id); gimp_pixel_rgn_init (&rgn_in, drawable, x1, y1, x2 - x1, y2 - y1, FALSE, FALSE); gimp_pixel_rgn_init (&rgn_out, drawable, x1, y1, x2 - x1, y2 - y1, TRUE, TRUE); /* Initialise enough memory for row1, row2, row3, outrow */ row1 = g_new (guchar, channels * (x2 - x1)); outrow = g_new (guchar, channels * (x2 - x1)); for (i = y1; i < y2; i++) { /* Get row i-1, i, i+1 */ gimp_pixel_rgn_get_row (&rgn_in, row1, x1, MAX (y1, i - 1), x2 - x1); for (j = x1; j < x2; j++) { /* For each layer, compute the average of the nine pixels */ for (k = 0; k < channels; k++) { int in = row1[channels * (j - x1) + k]; int a = (1.0 - (in / 255.0)) * 100.0; int r = rand() % 100; outrow[channels * (j - x1) + k] = r < a ? 0 : 255; } } gimp_pixel_rgn_set_row (&rgn_out, outrow, x1, i, x2 - x1); if (i % 10 == 0) gimp_progress_update ((gdouble) (i - y1) / (gdouble) (y2 - y1)); } g_free (row1); g_free (outrow); 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 int pf_init(PyGimpPixelFetcher *self, PyObject *args, PyObject *kwargs) { PyGimpDrawable *drw; gboolean shadow = FALSE; GimpRGB bg_color = { 0.0, 0.0, 0.0, 1.0 }; GimpPixelFetcherEdgeMode edge_mode = GIMP_PIXEL_FETCHER_EDGE_NONE; static char *kwlist[] = { "drawable", "shadow", "bg_color", "edge_mode", NULL }; if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!|iO&i:gimp.PixelFetcher.__init__", kwlist, &PyGimpDrawable_Type, &drw, &shadow, pygimp_rgb_from_pyobject, &bg_color, &edge_mode)) return -1; if(!drw->drawable) drw->drawable = gimp_drawable_get(drw->ID); self->pf = gimp_pixel_fetcher_new(drw->drawable, shadow); Py_INCREF(drw); self->drawable = drw; self->shadow = shadow; self->bg_color = bg_color; self->edge_mode = edge_mode; self->bpp = gimp_drawable_bpp(drw->drawable->drawable_id); gimp_pixel_fetcher_set_bg_color(self->pf, &bg_color); gimp_pixel_fetcher_set_edge_mode(self->pf, edge_mode); return 0; }
static void despeckle (void) { GimpPixelRgn src_rgn; /* Source image region */ GimpPixelRgn dst_rgn; guchar *src; guchar *dst; gint img_bpp; gint x, y; gint width, height; img_bpp = gimp_drawable_bpp (drawable->drawable_id); if (! gimp_drawable_mask_intersect (drawable->drawable_id, &x, &y, &width, &height)) return; gimp_pixel_rgn_init (&src_rgn, drawable, x, y, width, height, FALSE, FALSE); gimp_pixel_rgn_init (&dst_rgn, drawable, x, y, width, height, TRUE, TRUE); src = g_new (guchar, width * height * img_bpp); dst = g_new (guchar, width * height * img_bpp); gimp_pixel_rgn_get_rect (&src_rgn, src, x, y, width, height); despeckle_median (src, dst, width, height, img_bpp, despeckle_radius, FALSE); gimp_pixel_rgn_set_rect (&dst_rgn, dst, x, y, width, height); gimp_drawable_flush (drawable); gimp_drawable_merge_shadow (drawable->drawable_id, TRUE); gimp_drawable_update (drawable->drawable_id, x, y, width, height); g_free (dst); g_free (src); }
static void exponential (GimpDrawable *drawable) { gint i, j, k, channels; gint x1, y1, x2, y2; GimpPixelRgn rgn_in, rgn_out; guchar output[4]; /* Gets upper left and lower right coordinates, * and layers number in the image */ gimp_drawable_mask_bounds (drawable->drawable_id, &x1, &y1, &x2, &y2); channels = gimp_drawable_bpp (drawable->drawable_id); /* Initialises two PixelRgns, one to read original data, * and the other to write output data. That second one will * be merged at the end by the call to * gimp_drawable_merge_shadow() */ gimp_pixel_rgn_init (&rgn_in, drawable, x1, y1, x2 - x1, y2 - y1, FALSE, FALSE); gimp_pixel_rgn_init (&rgn_out, drawable, x1, y1, x2 - x1, y2 - y1, TRUE, TRUE); /* guchar minp[4],maxp[4]; for (j = 0; j < 4; j++){ minp[j]=255; maxp[j]=0; } for (i = x1; i < x2; i++){ for (j = y1; j < y2; j++){ guchar pixel[4]; gimp_pixel_rgn_get_pixel (&rgn_in, pixel, i, j); for (k = 0; k < channels; k++){ if(minp[k]>pixel[k]) minp[k]=pixel[k]; if(maxp[k]<pixel[k]) maxp[k]=pixel[k]; } } } */ for (i = x1; i < x2; i++) { for (j = y1; j < y2; j++) { /* guchar pixel[9][4]; */ guchar pixel[4]; /* Get ONE pixel */ /* gimp_pixel_rgn_get_pixel (&rgn_in, pixel[0], MAX (i - 1, x1), MAX (j - 1, y1)); gimp_pixel_rgn_get_pixel (&rgn_in, pixel[1], MAX (i - 1, x1), j); gimp_pixel_rgn_get_pixel (&rgn_in, pixel[2], MAX (i - 1, x1), MIN (j + 1, y2 - 1)); gimp_pixel_rgn_get_pixel (&rgn_in, pixel[3], i, MAX (j - 1, y1)); */ gimp_pixel_rgn_get_pixel (&rgn_in, pixel, /*[4]*/ i, j); /* gimp_pixel_rgn_get_pixel (&rgn_in, pixel[5], i, MIN (j + 1, y2 - 1)); gimp_pixel_rgn_get_pixel (&rgn_in, pixel[6], MIN (i + 1, x2 - 1), MAX (j - 1, y1)); gimp_pixel_rgn_get_pixel (&rgn_in, pixel[7], MIN (i + 1, x2 - 1), j); gimp_pixel_rgn_get_pixel (&rgn_in, pixel[8], MIN (i + 1, x2 - 1), MIN (j + 1, y2 - 1)); */ /* For each layer, compute the exponential color code (255*(-1 +exp(code))/(-1 +exp(255)) ) */ for (k = 0; k < channels; k++) { double ex = exp(pixel[k])-1, max=exp(255)-1; output[k] = (guchar)(255 *(ex/max)); } gimp_pixel_rgn_set_pixel (&rgn_out, output, i, j); } /*end for j*/ if (i % 10 == 0) gimp_progress_update ((gdouble) (i - x1) / (gdouble) (x2 - x1)); } /*end for i*/ /* Update the modified region */ 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 compose_row (gint frame_num, DisposeType dispose, gint row_num, guchar *dest, gint dest_width, GimpDrawable *drawable, gboolean cleanup) { static guchar *line_buf = NULL; guchar *srcptr; GimpPixelRgn pixel_rgn; gint rawx, rawy, rawbpp, rawwidth, rawheight; gint i; gboolean has_alpha; if (cleanup) { if (line_buf) { g_free (line_buf); line_buf = NULL; } return; } if (dispose == DISPOSE_REPLACE) { total_alpha (dest, dest_width, pixelstep); } gimp_drawable_offsets (drawable->drawable_id, &rawx, &rawy); rawheight = gimp_drawable_height (drawable->drawable_id); /* this frame has nothing to give us for this row; return */ if (row_num >= rawheight + rawy || row_num < rawy) return; rawbpp = gimp_drawable_bpp (drawable->drawable_id); rawwidth = gimp_drawable_width (drawable->drawable_id); has_alpha = gimp_drawable_has_alpha (drawable->drawable_id); if (line_buf) { g_free (line_buf); line_buf = NULL; } line_buf = g_malloc (rawwidth * rawbpp); /* Initialise and fetch the raw new frame row */ gimp_pixel_rgn_init (&pixel_rgn, drawable, 0, row_num - rawy, rawwidth, 1, FALSE, FALSE); gimp_pixel_rgn_get_rect (&pixel_rgn, line_buf, 0, row_num - rawy, rawwidth, 1); /* render... */ srcptr = line_buf; for (i=rawx; i<rawwidth+rawx; i++) { if (i>=0 && i<dest_width) { if ((!has_alpha) || ((*(srcptr+rawbpp-1))&128)) { gint pi; for (pi = 0; pi < pixelstep-1; pi++) { dest[i*pixelstep +pi] = *(srcptr + pi); } dest[i*pixelstep + pixelstep - 1] = 255; } } srcptr += rawbpp; } }
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); }
static void symmetry (GimpDrawable *drawable) { gint i, j, k, channels; gint x1, y1, x2, y2; GimpPixelRgn rgn_in, rgn_out; guchar output[4]; /* Gets upper left and lower right coordinates, * and layers number in the image */ gimp_drawable_mask_bounds (drawable->drawable_id, &x1, &y1, &x2, &y2); channels = gimp_drawable_bpp (drawable->drawable_id); /* Initialises two PixelRgns, one to read original data, * and the other to write output data. That second one will * be merged at the end by the call to * gimp_drawable_merge_shadow() */ gimp_pixel_rgn_init (&rgn_in, drawable, x1, y1, x2 - x1, y2 - y1, FALSE, FALSE); gimp_pixel_rgn_init (&rgn_out, drawable, x1, y1, x2 - x1, y2 - y1, TRUE, TRUE); for (i = x1; i < x2; i++) { for (j = y1; j < y2; j++) { guchar pixel[4]; /* Get ONE pixel */ gimp_pixel_rgn_get_pixel (&rgn_in, pixel, i, j); /* For each layer */ for (k = 0; k < channels; k++) { output[k] = 255 - pixel[k]; } gimp_pixel_rgn_set_pixel (&rgn_out, output, i, j); } /*end for j*/ if (i % 10 == 0) gimp_progress_update ((gdouble) (i - x1) / (gdouble) (x2 - x1)); } /*end for i*/ /* Update the modified region */ 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 sinusrow (GimpDrawable *drawable) { gint i, j, k, channels; gint x1, y1, x2, y2; GimpPixelRgn rgn_in, rgn_out; guchar *inrow; guchar *outrow; /* guchar output[4]; */ /* Gets upper left and lower right coordinates, * and layers number in the image */ gimp_drawable_mask_bounds (drawable->drawable_id, &x1, &y1, &x2, &y2); channels = gimp_drawable_bpp (drawable->drawable_id); /* Initialises two PixelRgns, one to read original data, * and the other to write output data. That second one will * be merged at the end by the call to * gimp_drawable_merge_shadow() */ gimp_pixel_rgn_init (&rgn_in, drawable, x1, y1, x2 - x1, y2 - y1, FALSE, FALSE); gimp_pixel_rgn_init (&rgn_out, drawable, x1, y1, x2 - x1, y2 - y1, TRUE, TRUE); /* Initialise enough memory for inrow, outrow */ inrow = g_new (guchar, channels * (x2 - x1)); outrow = g_new (guchar, channels * (x2 - x1)); guchar minp[4],maxp[4]; getrange(drawable, minp, maxp, x1, x2, y1, y2); for (i = y1; i < y2; i++) { /* Get row i */ gimp_pixel_rgn_get_row (&rgn_in, inrow, x1, i, x2 - x1); for (j = x1; j < x2; j++) { /* For each layer, compute the average of the nine * pixels */ for (k = 0; k < channels; k++) { double angle = inrow[channels * (j - x1) + k], max=255; angle = M_2_PI * (angle / max ) ; outrow[channels * (j - x1) + k] = (guchar)(255*(1+sin(angle))/2); } } /*end for j each pixel of the row*/ gimp_pixel_rgn_set_row (&rgn_out, outrow, x1, i, x2 - x1); if (i % 10 == 0) gimp_progress_update ((gdouble) (i - x1) / (gdouble) (x2 - x1)); } /*end for i each row*/ g_free (inrow); g_free (outrow); /* Update the modified region */ 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 run (const gchar *name, gint nparams, const GimpParam *param, gint *nreturn_vals, GimpParam **return_vals) { static GimpParam values[1]; GimpRunMode run_mode; GimpPDBStatusType status; GimpDrawable *drawable; gint x1, y1, x2, y2; INIT_I18N (); status = GIMP_PDB_SUCCESS; run_mode = param[0].data.d_int32; *nreturn_vals = 1; *return_vals = values; values[0].type = GIMP_PDB_STATUS; values[0].data.d_status = status; /* Get the active drawable info */ drawable = gimp_drawable_get (param[2].data.d_drawable); img_width = gimp_drawable_width (drawable->drawable_id); img_height = gimp_drawable_height (drawable->drawable_id); img_bpp = gimp_drawable_bpp (drawable->drawable_id); gimp_drawable_mask_bounds (drawable->drawable_id, &x1, &y1, &x2, &y2); mbvals.center_x = (gdouble) (x1 + x2 - 1) / 2.0; mbvals.center_y = (gdouble) (y1 + y2 - 1) / 2.0; /* Set the tile cache size */ gimp_tile_cache_ntiles (2 * drawable->ntile_cols); switch (run_mode) { case GIMP_RUN_INTERACTIVE: /* Possibly retrieve data */ gimp_get_data (PLUG_IN_PROC, &mbvals); /* Get information from the dialog */ if (! mblur_dialog (param[1].data.d_image, drawable)) return; break; case GIMP_RUN_NONINTERACTIVE: if (strcmp (name, PLUG_IN_PROC_INWARD) == 0) mbvals.blur_outward = FALSE; if (nparams == 8) { mbvals.center_x = param[6].data.d_float; mbvals.center_y = param[7].data.d_float; } else if (nparams != 6) { status = GIMP_PDB_CALLING_ERROR; } if (status == GIMP_PDB_SUCCESS) { mbvals.mblur_type = param[3].data.d_int32; mbvals.length = param[4].data.d_int32; mbvals.angle = param[5].data.d_int32; } if ((mbvals.mblur_type < 0) || (mbvals.mblur_type > MBLUR_MAX)) status= GIMP_PDB_CALLING_ERROR; break; case GIMP_RUN_WITH_LAST_VALS: /* Possibly retrieve data */ gimp_get_data (PLUG_IN_PROC, &mbvals); break; default: break; } /* Blur the image */ if ((status == GIMP_PDB_SUCCESS) && (gimp_drawable_is_rgb(drawable->drawable_id) || gimp_drawable_is_gray(drawable->drawable_id))) { /* Run! */ has_alpha = gimp_drawable_has_alpha (drawable->drawable_id); mblur (drawable, NULL); /* If run mode is interactive, flush displays */ if (run_mode != GIMP_RUN_NONINTERACTIVE) gimp_displays_flush (); /* Store data */ if (run_mode == GIMP_RUN_INTERACTIVE) gimp_set_data (PLUG_IN_PROC, &mbvals, sizeof (mblur_vals_t)); } else if (status == GIMP_PDB_SUCCESS) status = GIMP_PDB_EXECUTION_ERROR; values[0].data.d_status = status; gimp_drawable_detach (drawable); }
void precompute_normals (gint x1, gint x2, gint y) { GimpVector3 *tmpv, p1, p2, p3, normal; gdouble *tmpd; gint n, i, nv; guchar *map = NULL; gint bpp = 1; guchar mapval; /* First, compute the heights */ /* ========================== */ tmpv = triangle_normals[0]; triangle_normals[0] = triangle_normals[1]; triangle_normals[1] = tmpv; tmpv = vertex_normals[0]; vertex_normals[0] = vertex_normals[1]; vertex_normals[1] = vertex_normals[2]; vertex_normals[2] = tmpv; tmpd = heights[0]; heights[0] = heights[1]; heights[1] = heights[2]; heights[2] = tmpd; if (mapvals.bumpmap_id != -1) { bpp = gimp_drawable_bpp(mapvals.bumpmap_id); } gimp_pixel_rgn_get_row (&bump_region, bumprow, x1, y, x2 - x1); if (mapvals.bumpmaptype > 0) { switch (mapvals.bumpmaptype) { case 1: map = logmap; break; case 2: map = sinemap; break; default: map = spheremap; break; } for (n = 0; n < (x2 - x1); n++) { if (bpp>1) { mapval = (guchar)((float)((bumprow[n * bpp] +bumprow[n * bpp +1] + bumprow[n * bpp + 2])/3.0 )) ; } else { mapval = bumprow[n * bpp]; } heights[2][n] = (gdouble) mapvals.bumpmax * (gdouble) map[mapval] / 255.0; } } else { for (n = 0; n < (x2 - x1); n++) { if (bpp>1) { mapval = (guchar)((float)((bumprow[n * bpp] +bumprow[n * bpp +1] + bumprow[n * bpp + 2])/3.0 )) ; } else { mapval = bumprow[n * bpp]; } heights[2][n] = (gdouble) mapvals.bumpmax * (gdouble) mapval / 255.0; } } /* Compute triangle normals */ /* ======================== */ i = 0; for (n = 0; n < (x2 - x1 - 1); n++) { p1.x = 0.0; p1.y = ystep; p1.z = heights[2][n] - heights[1][n]; p2.x = xstep; p2.y = ystep; p2.z = heights[2][n+1] - heights[1][n]; p3.x = xstep; p3.y = 0.0; p3.z = heights[1][n+1] - heights[1][n]; triangle_normals[1][i] = gimp_vector3_cross_product (&p2, &p1); triangle_normals[1][i+1] = gimp_vector3_cross_product (&p3, &p2); gimp_vector3_normalize (&triangle_normals[1][i]); gimp_vector3_normalize (&triangle_normals[1][i+1]); i += 2; } /* Compute vertex normals */ /* ====================== */ i = 0; gimp_vector3_set (&normal, 0.0, 0.0, 0.0); for (n = 0; n < (x2 - x1 - 1); n++) { nv = 0; if (n > 0) { if (y > 0) { gimp_vector3_add (&normal, &normal, &triangle_normals[0][i-1]); gimp_vector3_add (&normal, &normal, &triangle_normals[0][i-2]); nv += 2; } if (y < pre_h) { gimp_vector3_add (&normal, &normal, &triangle_normals[1][i-1]); nv++; } } if (n <pre_w) { if (y > 0) { gimp_vector3_add (&normal, &normal, &triangle_normals[0][i]); gimp_vector3_add (&normal, &normal, &triangle_normals[0][i+1]); nv += 2; } if (y < pre_h) { gimp_vector3_add (&normal, &normal, &triangle_normals[1][i]); gimp_vector3_add (&normal, &normal, &triangle_normals[1][i+1]); nv += 2; } } gimp_vector3_mul (&normal, 1.0 / (gdouble) nv); gimp_vector3_normalize (&normal); vertex_normals[1][n] = normal; i += 2; } }
static void brushdmenuselect (GtkWidget *widget, gpointer data) { GimpPixelRgn src_rgn; guchar *src_row; guchar *src; gint id; gint bpp; gint x, y; ppm_t *p; gint x1, y1, x2, y2; gint row; GimpDrawable *drawable; gint rowstride; gimp_int_combo_box_get_active (GIMP_INT_COMBO_BOX (widget), &id); if (id == -1) return; if (brush_from_file == 2) return; /* Not finished GUI-building yet */ if (brush_from_file) { #if 0 unselectall (brush_list); #endif preset_save_button_set_sensitive (FALSE); } gtk_adjustment_set_value (brush_gamma_adjust, 1.0); gtk_adjustment_set_value (brush_aspect_adjust, 0.0); drawable = gimp_drawable_get (id); gimp_drawable_mask_bounds (drawable->drawable_id, &x1, &y1, &x2, &y2); bpp = gimp_drawable_bpp (drawable->drawable_id); ppm_kill (&brushppm); ppm_new (&brushppm, x2 - x1, y2 - y1); p = &brushppm; rowstride = p->width * 3; src_row = g_new (guchar, (x2 - x1) * bpp); gimp_pixel_rgn_init (&src_rgn, drawable, 0, 0, x2 - x1, y2 - y1, FALSE, FALSE); if (bpp == 3) { /* RGB */ int bpr = (x2 - x1) * 3; for (row = 0, y = y1; y < y2; row++, y++) { gimp_pixel_rgn_get_row (&src_rgn, src_row, x1, y, (x2 - x1)); memcpy (p->col + row*rowstride, src_row, bpr); } } else { /* RGBA (bpp > 3) GrayA (bpp == 2) or Gray */ gboolean is_gray = ((bpp > 3) ? TRUE : FALSE); for (row = 0, y = y1; y < y2; row++, y++) { guchar *tmprow = p->col + row * rowstride; guchar *tmprow_ptr; gimp_pixel_rgn_get_row (&src_rgn, src_row, x1, y, (x2 - x1)); src = src_row; tmprow_ptr = tmprow; /* Possible micro-optimization here: * src_end = src + src_rgn.bpp * (x2-x1); * for ( ; src < src_end ; src += src_rgn.bpp) */ for (x = x1; x < x2; x++) { *(tmprow_ptr++) = src[0]; *(tmprow_ptr++) = src[is_gray ? 1 : 0]; *(tmprow_ptr++) = src[is_gray ? 2 : 0]; src += src_rgn.bpp; } } } g_free (src_row); if (bpp >= 3) pcvals.color_brushes = 1; else pcvals.color_brushes = 0; brush_from_file = 0; update_brush_preview (NULL); }
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 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)); }
// Run the plugin static void run (const gchar *name, gint nparams, const GimpParam *param, gint *nreturn_vals, GimpParam **return_vals) { // Return values static GimpParam values[1]; gint sel_x1, sel_y1, sel_x2, sel_y2, w, h, padding; PluginData pd; GimpRunMode run_mode; GimpPDBStatusType status = GIMP_PDB_SUCCESS; *nreturn_vals = 1; *return_vals = values; if (param[0].type!= GIMP_PDB_INT32) status=GIMP_PDB_CALLING_ERROR; if (param[2].type!=GIMP_PDB_DRAWABLE) status=GIMP_PDB_CALLING_ERROR; run_mode = (GimpRunMode) param[0].data.d_int32; pd.drawable = gimp_drawable_get(param[2].data.d_drawable); gimp_drawable_mask_bounds(pd.drawable->drawable_id, &sel_x1, &sel_y1, &sel_x2, &sel_y2); pd.selection_width = sel_x2 - sel_x1; pd.selection_height = sel_y2 - sel_y1; pd.selection_offset_x = sel_x1; pd.selection_offset_y = sel_y1; pd.image_width = gimp_drawable_width(pd.drawable->drawable_id); pd.image_height = gimp_drawable_height(pd.drawable->drawable_id); pd.channel_count = gimp_drawable_bpp(pd.drawable->drawable_id); pd.point_grabbed = -1; if (run_mode == GIMP_RUN_INTERACTIVE) { // Interactive call with dialog dialog(&pd); if (pd.curve_user.count > 0) { gimp_set_data (PLUG_IN_BINARY, pd.curve_user.user_points, sizeof (GdkPoint) * pd.curve_user.count); } } else if (run_mode == GIMP_RUN_WITH_LAST_VALS) { // Read a saved curve and apply it fft_prepare(&pd); gimp_get_data(PLUG_IN_BINARY, pd.curve_user.user_points); pd.curve_user.count = gimp_get_data_size(PLUG_IN_BINARY) / sizeof (GdkPoint); gimp_pixel_rgn_init(&pd.region, pd.drawable, 0, 0, pd.image_width, pd.image_height, TRUE, TRUE); fft_apply(&pd); gimp_pixel_rgn_set_rect(&pd.region, pd.img_pixels, 0, 0, pd.image_width, pd.image_height); gimp_drawable_flush(pd.drawable); gimp_drawable_merge_shadow(pd.drawable->drawable_id, TRUE); gimp_drawable_update(pd.drawable->drawable_id, pd.selection_offset_x, pd.selection_offset_y, pd.selection_width, pd.selection_height); fft_destroy(&pd); gimp_displays_flush(); } else { status = GIMP_PDB_CALLING_ERROR; } values[0].type = GIMP_PDB_STATUS; values[0].data.d_status = status; gimp_drawable_detach(pd.drawable); }
static void blur (GimpDrawable *drawable) { gint i, ii, channels; gint x1, y1, x2, y2; GimpPixelRgn rgn_in, rgn_out; guchar **row; guchar *outrow; gint width, height; gimp_progress_init ("My Blur..."); /* Gets upper left and lower right coordinates, * and layers number in the image */ gimp_drawable_mask_bounds (drawable->drawable_id, &x1, &y1, &x2, &y2); width = x2 - x1; height = y2 - y1; channels = gimp_drawable_bpp (drawable->drawable_id); /* Allocate a big enough tile cache */ gimp_tile_cache_ntiles (2 * (drawable->width / gimp_tile_width () + 1)); /* Initialises two PixelRgns, one to read original data, * and the other to write output data. That second one will * be merged at the end by the call to * gimp_drawable_merge_shadow() */ gimp_pixel_rgn_init (&rgn_in, drawable, x1, y1, width, height, FALSE, FALSE); gimp_pixel_rgn_init (&rgn_out, drawable, x1, y1, width, height, TRUE, TRUE); /* Allocate memory for input and output tile rows */ init_mem (&row, &outrow, width * channels); for (ii = -radius; ii <= radius; ii++) { gimp_pixel_rgn_get_row (&rgn_in, row[radius + ii], x1, y1 + CLAMP (ii, 0, height - 1), width); } for (i = 0; i < height; i++) { /* To be done for each tile row */ process_row (row, outrow, x1, y1, width, height, channels, i); gimp_pixel_rgn_set_row (&rgn_out, outrow, x1, i + y1, width); /* shift tile rows to insert the new one at the end */ shuffle (&rgn_in, row, x1, y1, width, height, i); if (i % 10 == 0) gimp_progress_update ((gdouble) i / (gdouble) height); } /* We could also put that in a separate function but it's * rather simple */ for (ii = 0; ii < 2 * radius + 1; ii++) g_free (row[ii]); g_free (row); g_free (outrow); /* Update the modified 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 exponentialrange (GimpDrawable *drawable) { gint i, j, k, channels; gint x1, y1, x2, y2; GimpPixelRgn rgn_in, rgn_out; guchar output[4]; /* Gets upper left and lower right coordinates, * and layers number in the image */ gimp_drawable_mask_bounds (drawable->drawable_id, &x1, &y1, &x2, &y2); channels = gimp_drawable_bpp (drawable->drawable_id); /* Initialises two PixelRgns, one to read original data, * and the other to write output data. That second one will * be merged at the end by the call to * gimp_drawable_merge_shadow() */ gimp_pixel_rgn_init (&rgn_in, drawable, x1, y1, x2 - x1, y2 - y1, FALSE, FALSE); gimp_pixel_rgn_init (&rgn_out, drawable, x1, y1, x2 - x1, y2 - y1, TRUE, TRUE); /* find the range [minp,maxp] */ guchar minp[4],maxp[4]; /* initial values are high for minp, low for maxp*/ for (j = 0; j < 4; j++){ minp[j]=255; // default for guchar 0..255 maxp[j]=0; } /* get the right range */ for (i = x1; i < x2; i++){ for (j = y1; j < y2; j++){ guchar pixel[4]; gimp_pixel_rgn_get_pixel (&rgn_in, pixel, i, j); for (k = 0; k < channels; k++){ if(minp[k]>pixel[k]) minp[k]=pixel[k]; if(maxp[k]<pixel[k]) maxp[k]=pixel[k]; } } } for (i = x1; i < x2; i++) { for (j = y1; j < y2; j++) { guchar pixel[4]; gimp_pixel_rgn_get_pixel (&rgn_in, pixel, /*[4]*/ i, j); /* For each layer, compute the exponential in the same range */ for (k = 0; k < channels; k++) { double ex = exp(pixel[k])- exp(minp[k]); double ran=exp(maxp[k])-exp(minp[k]); output[k] = (guchar)( minp[k] + (maxp[k]-minp[k]) * (ex/ran) ); } gimp_pixel_rgn_set_pixel (&rgn_out, output, i, j); } /*end for j*/ if (i % 10 == 0) gimp_progress_update ((gdouble) (i - x1) / (gdouble) (x2 - x1)); } /*end for i*/ /* Update the modified region */ 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 run (const gchar *name, gint nparams, const GimpParam *param, gint *nreturn_vals, GimpParam **return_vals) { static GimpParam values[1]; gint sel_x1, sel_y1, sel_x2, sel_y2; gint img_height, img_width, img_bpp, img_has_alpha; GimpDrawable *drawable; GimpRunMode run_mode; GimpPDBStatusType status; *nreturn_vals = 1; *return_vals = values; status = GIMP_PDB_SUCCESS; if (param[0].type != GIMP_PDB_INT32) status = GIMP_PDB_CALLING_ERROR; run_mode = param[0].data.d_int32; INIT_I18N (); if (param[2].type != GIMP_PDB_DRAWABLE) status = GIMP_PDB_CALLING_ERROR; drawable = gimp_drawable_get (param[2].data.d_drawable); img_width = gimp_drawable_width (drawable->drawable_id); img_height = gimp_drawable_height (drawable->drawable_id); img_bpp = gimp_drawable_bpp (drawable->drawable_id); img_has_alpha = gimp_drawable_has_alpha (drawable->drawable_id); gimp_drawable_mask_bounds (drawable->drawable_id, &sel_x1, &sel_y1, &sel_x2, &sel_y2); if (!gimp_drawable_is_rgb (drawable->drawable_id)) status = GIMP_PDB_CALLING_ERROR; if (status == GIMP_PDB_SUCCESS) { gr = g_rand_new (); memset (&qbist_info, 0, sizeof (qbist_info)); create_info (&qbist_info.info); qbist_info.oversampling = 4; switch (run_mode) { case GIMP_RUN_INTERACTIVE: /* Possibly retrieve data */ gimp_get_data (PLUG_IN_PROC, &qbist_info); /* Get information from the dialog */ if (dialog_run ()) { status = GIMP_PDB_SUCCESS; gimp_set_data (PLUG_IN_PROC, &qbist_info, sizeof (QbistInfo)); } else status = GIMP_PDB_EXECUTION_ERROR; break; case GIMP_RUN_NONINTERACTIVE: status = GIMP_PDB_CALLING_ERROR; break; case GIMP_RUN_WITH_LAST_VALS: /* Possibly retrieve data */ gimp_get_data (PLUG_IN_PROC, &qbist_info); status = GIMP_PDB_SUCCESS; break; default: status = GIMP_PDB_CALLING_ERROR; break; } if (status == GIMP_PDB_SUCCESS) { GimpPixelRgn imagePR; gpointer pr; gimp_tile_cache_ntiles ((drawable->width + gimp_tile_width () - 1) / gimp_tile_width ()); gimp_pixel_rgn_init (&imagePR, drawable, 0, 0, img_width, img_height, TRUE, TRUE); optimize (&qbist_info.info); gimp_progress_init (_("Qbist")); for (pr = gimp_pixel_rgns_register (1, &imagePR); pr != NULL; pr = gimp_pixel_rgns_process (pr)) { gint row; for (row = 0; row < imagePR.h; row++) { qbist (&qbist_info.info, imagePR.data + row * imagePR.rowstride, imagePR.x, imagePR.y + row, imagePR.w, sel_x2 - sel_x1, sel_y2 - sel_y1, imagePR.bpp, qbist_info.oversampling); } gimp_progress_update ((gfloat) (imagePR.y - sel_y1) / (gfloat) (sel_y2 - sel_y1)); } gimp_drawable_flush (drawable); gimp_drawable_merge_shadow (drawable->drawable_id, TRUE); gimp_drawable_update (drawable->drawable_id, sel_x1, sel_y1, (sel_x2 - sel_x1), (sel_y2 - sel_y1)); gimp_displays_flush (); } g_rand_free (gr); } values[0].type = GIMP_PDB_STATUS; values[0].data.d_status = status; gimp_drawable_detach (drawable); }
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 nova (GimpDrawable *drawable, GimpPreview *preview) { GimpPixelRgn src_rgn; GimpPixelRgn dest_rgn; gpointer pr; guchar *src_row, *dest_row, *save_src; guchar *src, *dest; gint x1, y1, x2, y2, x, y; gint row, col; gint alpha, bpp; gint progress, max_progress; gboolean has_alpha; gint xc, yc; /* center of nova */ gdouble u, v, l, w, w1, c, t; gdouble *spoke; gdouble nova_alpha, src_alpha, new_alpha = 0.0; gdouble compl_ratio, ratio; GimpRGB color; GimpRGB *spokecolor; GimpHSV hsv; gdouble spokecol; gint i; GRand *gr; guchar *cache = NULL; gint width, height; gdouble zoom = 0.0; gr = g_rand_new (); /* initialize */ has_alpha = gimp_drawable_has_alpha (drawable->drawable_id); spoke = g_new (gdouble, pvals.nspoke); spokecolor = g_new (GimpRGB, pvals.nspoke); gimp_rgb_set_alpha (&pvals.color, 1.0); gimp_rgb_to_hsv (&pvals.color, &hsv); for (i = 0; i < pvals.nspoke; i++) { spoke[i] = gauss (gr); hsv.h += ((gdouble) pvals.randomhue / 360.0) * g_rand_double_range (gr, -0.5, 0.5); if (hsv.h < 0) hsv.h += 1.0; else if (hsv.h >= 1.0) hsv.h -= 1.0; gimp_hsv_to_rgb (&hsv, spokecolor + i); } if (preview) { cache = gimp_zoom_preview_get_source (GIMP_ZOOM_PREVIEW (preview), &width, &height, &bpp); zoom = gimp_zoom_preview_get_factor (GIMP_ZOOM_PREVIEW (preview)); gimp_preview_transform (preview, pvals.xcenter, pvals.ycenter, &xc, &yc); x1 = 0; y1 = 0; x2 = width; y2 = height; } else { gimp_drawable_mask_bounds (drawable->drawable_id, &x1, &y1, &x2, &y2); bpp = gimp_drawable_bpp (drawable->drawable_id); xc = pvals.xcenter; yc = pvals.ycenter; 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); } alpha = (has_alpha) ? bpp - 1 : bpp; /* Initialize progress */ progress = 0; max_progress = (x2 - x1) * (y2 - y1); if (preview) { save_src = src_row = g_new (guchar, y2 * width * bpp); memcpy (src_row, cache, y2 * width * bpp); dest_row = g_new (guchar, y2 * width * bpp); dest = dest_row; src = src_row; for (row = 0, y = 0; row < y2; row++, y++) { for (col = 0, x = 0; col < x2; col++, x++) { u = ((gdouble) (x - xc) / ((gdouble) pvals.radius * width / drawable->width * zoom)); v = ((gdouble) (y - yc) / ((gdouble) pvals.radius * height / drawable->height * zoom)); l = sqrt (SQR (u) + SQR (v)); /* This algorithm is still under construction. */ t = (atan2 (u, v) / (2 * G_PI) + .51) * pvals.nspoke; i = (gint) floor (t); t -= i; i %= pvals.nspoke; w1 = spoke[i] * (1 - t) + spoke[(i + 1) % pvals.nspoke] * t; w1 = w1 * w1; w = 1.0 / (l + 0.001) * 0.9; nova_alpha = CLAMP (w, 0.0, 1.0); if (has_alpha) { src_alpha = (gdouble) src[alpha] / 255.0; new_alpha = src_alpha + (1.0 - src_alpha) * nova_alpha; if (new_alpha != 0.0) ratio = nova_alpha / new_alpha; else ratio = 0.0; } else ratio = nova_alpha; compl_ratio = 1.0 - ratio; /* red or gray */ spokecol = (gdouble)spokecolor[i ].r * (1.0-t) + (gdouble)spokecolor[(i+1) % pvals.nspoke].r * t; if (w>1.0) color.r = CLAMP (spokecol * w, 0.0, 1.0); else color.r = src[0]/255.0 * compl_ratio + spokecol * ratio; c = CLAMP (w1 * w, 0.0, 1.0); color.r += c; dest[0] = CLAMP (color.r*255.0, 0, 255); if (bpp>2) { /* green */ spokecol = (gdouble)spokecolor[i ].g * (1.0-t) + (gdouble)spokecolor[(i+1) % pvals.nspoke].g * t; if (w>1.0) color.g = CLAMP (spokecol * w, 0.0, 1.0); else color.g = src[1]/255.0 * compl_ratio + spokecol * ratio; c = CLAMP (w1 * w, 0.0, 1.0); color.g += c; dest[1] = CLAMP (color.g*255.0, 0, 255); /* blue */ spokecol = (gdouble)spokecolor[i ].b * (1.0-t) + (gdouble)spokecolor[(i+1) % pvals.nspoke].b * t; if (w>1.0) color.b = CLAMP (spokecol * w, 0.0, 1.0); else color.b = src[2]/255.0 * compl_ratio + spokecol * ratio; c = CLAMP (w1 * w, 0.0, 1.0); color.b += c; dest[2] = CLAMP (color.b*255.0, 0, 255); } /* alpha */ if (has_alpha) dest[alpha] = new_alpha * 255.0; src += bpp; dest += bpp; } } gimp_preview_draw_buffer (preview, dest_row, bpp * width); g_free (cache); g_free (save_src); g_free (dest_row); } else { /* normal mode */ for (pr = gimp_pixel_rgns_register (2, &src_rgn, &dest_rgn); pr != NULL ; pr = gimp_pixel_rgns_process (pr)) { src_row = src_rgn.data; dest_row = dest_rgn.data; for (row = 0, y = src_rgn.y; row < src_rgn.h; row++, y++) { src = src_row; dest = dest_row; for (col = 0, x = src_rgn.x; col < src_rgn.w; col++, x++) { u = (gdouble) (x-xc) / pvals.radius; v = (gdouble) (y-yc) / pvals.radius; l = sqrt(u*u + v*v); /* This algorithm is still under construction. */ t = (atan2 (u, v) / (2 * G_PI) + .51) * pvals.nspoke; i = (gint) floor (t); t -= i; i %= pvals.nspoke; w1 = spoke[i] * (1 - t) + spoke[(i + 1) % pvals.nspoke] * t; w1 = w1 * w1; w = 1/(l+0.001)*0.9; nova_alpha = CLAMP (w, 0.0, 1.0); if (has_alpha) { src_alpha = (gdouble) src[alpha] / 255.0; new_alpha = src_alpha + (1.0 - src_alpha) * nova_alpha; if (new_alpha != 0.0) ratio = nova_alpha / new_alpha; else ratio = 0.0; } else ratio = nova_alpha; compl_ratio = 1.0 - ratio; switch (bpp) { case 1: case 2: /* gray */ spokecol = (gdouble)spokecolor[i ].r * (1.0-t) + (gdouble)spokecolor[(i+1) % pvals.nspoke].r * t; if (w>1.0) color.r = CLAMP (spokecol * w, 0.0, 1.0); else color.r = src[0]/255.0 * compl_ratio + spokecol * ratio; c = CLAMP (w1 * w, 0.0, 1.0); color.r += c; dest[0] = CLAMP (color.r*255.0, 0, 255); break; case 3: case 4: /* red */ spokecol = (gdouble)spokecolor[i ].r * (1.0-t) + (gdouble)spokecolor[(i+1) % pvals.nspoke].r * t; if (w>1.0) color.r = CLAMP (spokecol * w, 0.0, 1.0); else color.r = src[0]/255.0 * compl_ratio + spokecol * ratio; c = CLAMP (w1 * w, 0.0, 1.0); color.r += c; dest[0] = CLAMP (color.r*255.0, 0, 255); /* green */ spokecol = (gdouble)spokecolor[i ].g * (1.0-t) + (gdouble)spokecolor[(i+1) % pvals.nspoke].g * t; if (w>1.0) color.g = CLAMP (spokecol * w, 0.0, 1.0); else color.g = src[1]/255.0 * compl_ratio + spokecol * ratio; c = CLAMP (w1 * w, 0.0, 1.0); color.g += c; dest[1] = CLAMP (color.g*255.0, 0, 255); /* blue */ spokecol = (gdouble)spokecolor[i ].b * (1.0-t) + (gdouble)spokecolor[(i+1) % pvals.nspoke].b * t; if (w>1.0) color.b = CLAMP (spokecol * w, 0.0, 1.0); else color.b = src[2]/255.0 * compl_ratio + spokecol * ratio; c = CLAMP (w1 * w, 0.0, 1.0); color.b += c; dest[2] = CLAMP (color.b*255.0, 0, 255); break; } if (has_alpha) dest[alpha] = new_alpha * 255.0; src += src_rgn.bpp; dest += dest_rgn.bpp; } src_row += src_rgn.rowstride; dest_row += dest_rgn.rowstride; } /* Update progress */ progress += src_rgn.w * src_rgn.h; gimp_progress_update ((gdouble) progress / (gdouble) max_progress); } 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, (x2 - x1), (y2 - y1)); } g_free (spoke); g_free (spokecolor); g_rand_free (gr); }
/* 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); } }
gint guess_new_size (GtkWidget * button, PreviewData * p_data, GuessDir direction) { gint32 disc_layer_ID; GimpDrawable *drawable; gint z1, z2, k; gint z1min, z1max, z2max; gint width, height; gint lw, lh; gint x_off, y_off; gint bpp, c_bpp; GimpPixelRgn rgn_in; guchar *line; gboolean has_alpha; gdouble sum; gint mask_size; gint max_mask_size = 0; gint old_size; gint new_size; disc_layer_ID = p_data->vals->disc_layer_ID; switch (direction) { case GUESS_DIR_HOR: old_size = p_data->old_width; break; case GUESS_DIR_VERT: old_size = p_data->old_height; break; default: g_message("You just found a bug"); return 0; } LAYER_CHECK_ACTION(disc_layer_ID, gtk_dialog_response (GTK_DIALOG (dlg), RESPONSE_REFRESH), old_size); width = gimp_drawable_width (disc_layer_ID); height = gimp_drawable_height (disc_layer_ID); has_alpha = gimp_drawable_has_alpha (disc_layer_ID); bpp = gimp_drawable_bpp (disc_layer_ID); c_bpp = bpp - (has_alpha ? 1 : 0); drawable = gimp_drawable_get (disc_layer_ID); gimp_pixel_rgn_init (&rgn_in, drawable, 0, 0, width, height, FALSE, FALSE); gimp_drawable_offsets (disc_layer_ID, &x_off, &y_off); x_off -= p_data->x_off; y_off -= p_data->y_off; lw = (MIN (p_data->old_width, width + x_off) - MAX (0, x_off)); lh = (MIN (p_data->old_height, height + y_off) - MAX (0, y_off)); switch (direction) { case GUESS_DIR_HOR: z1min = MAX (0, y_off); z1max = MIN (p_data->old_height, height + y_off); z2max = lw; break; case GUESS_DIR_VERT: z1min = MAX (0, x_off); z1max = MIN (p_data->old_width, width + x_off); z2max = lh; break; default: g_message("You just found a bug"); return 0; } line = g_try_new (guchar, bpp * z2max); for (z1 = z1min; z1 < z1max; z1++) { switch (direction) { case GUESS_DIR_HOR: gimp_pixel_rgn_get_row (&rgn_in, line, MAX (0, -x_off), z1 - y_off, z2max); break; case GUESS_DIR_VERT: gimp_pixel_rgn_get_col (&rgn_in, line, z1 - x_off, MAX (0, -y_off), z2max); break; } mask_size = 0; for (z2 = 0; z2 < z2max; z2++) { sum = 0; for (k = 0; k < c_bpp; k++) { sum += line[bpp * z2 + k]; } sum /= (255 * c_bpp); if (has_alpha) { sum *= (gdouble) line[bpp * (z2 + 1) - 1] / 255; } if (sum >= (0.5 / c_bpp)) { mask_size++; } } if (mask_size > max_mask_size) { max_mask_size = mask_size; } } new_size = old_size - max_mask_size; g_free (line); gimp_drawable_detach (drawable); return new_size; }