93
static GimpParamDef args[] =
87
static const GimpParamDef args[] =
95
{ GIMP_PDB_INT32, "run_mode", "Interactive, non-interactive" },
96
{ GIMP_PDB_IMAGE, "image", "Input image (unused)" },
97
{ GIMP_PDB_DRAWABLE, "drawable", "Input drawable" },
98
{ GIMP_PDB_INT32, "mask_size", "Oil paint mask size" },
99
{ GIMP_PDB_INT32, "mode", "Algorithm {RGB (0), INTENSITY (1)}" }
89
{ GIMP_PDB_INT32, "run-mode", "Interactive, non-interactive" },
90
{ GIMP_PDB_IMAGE, "image", "Input image (unused)" },
91
{ GIMP_PDB_DRAWABLE, "drawable", "Input drawable" },
92
{ GIMP_PDB_INT32, "mask-size", "Oil paint mask size" },
93
{ GIMP_PDB_INT32, "mode", "Algorithm {RGB (0), INTENSITY (1)}" }
102
gimp_install_procedure ("plug_in_oilify",
103
"Modify the specified drawable to resemble an oil "
96
gimp_install_procedure (PLUG_IN_PROC,
97
N_("Smear colors to simulate an oil painting"),
105
98
"This function performs the well-known oil-paint "
106
99
"effect on the specified drawable. The size of the "
107
100
"input mask is specified by 'mask_size'.",
212
* For each RGB channel, replace the pixel at (x,y) with the
213
* value that occurs most often in the n x n chunk centered
205
* For each i in [0, HISTSIZE), hist[i] is the number of occurrences of the
206
* value i. Return a value in [0, HISTSIZE) weighted heavily toward the
207
* most frequent values in the histogram.
209
* Assuming that hist_max is the maximum number of occurrences for any
210
* value in the histogram, the weight given to each value i is
212
* weight = (hist[i] / hist_max)^8
214
* The 8 is subjective. Lower powers give fuzzier edges.
217
weighted_average_value (gint hist[HISTSIZE])
226
for (i = 0; i < HISTSIZE; i++)
227
max = MAX (max, hist[i]);
229
for (i = 0; i < HISTSIZE; i++)
231
weight = (gfloat) hist[i] / (gfloat) max;
234
weight *= weight; /* w' = w^8 */
236
sum += weight * (gfloat) i;
240
value = (gint) (sum / div);
242
return (guchar) CLAMP (value, 0, HISTSIZE - 1);
246
* For each i in [0, HISTSIZE), hist[i] is the number of occurrences of
247
* pixels with intensity i. hist_rgb[][i] is the average color of those
248
* pixels with intensity i, each channel multiplied by hist[i]. Write to
249
* dest a pixel whose color is a weighted average of all the colors in
250
* hist_rgb[][], biased heavily toward those with the most frequently-
251
* occurring intensities (as noted in hist[]).
253
* The weight formula is the same as in weighted_average_value().
256
weighted_average_color (gint hist[HISTSIZE],
257
gint hist_rgb[4][HISTSIZE],
265
gfloat color[4] = { 0.0, 0.0, 0.0, 0.0 };
267
for (i = 0; i < HISTSIZE; i++)
268
max = MAX (max, hist[i]);
270
for (i = 0; i < HISTSIZE; i++)
272
weight = (gfloat) hist[i] / (gfloat) max;
275
weight *= weight; /* w' = w^8 */
278
for (b = 0; b < bytes; b++)
279
color[b] += weight * (gfloat) hist_rgb[b][i] / (gfloat) hist[i];
284
for (b = 0; b < bytes; b++)
286
c = (gint) (color[b] / div);
287
dest[b] = (guchar) CLAMP (c, 0, HISTSIZE - 1);
292
* For all x and y as desired, replace the pixel at (x,y)
293
* with a weighted average of the most frequently occurring
294
* values in a circle of radius n centered at (x,y).
217
oilify_rgb (GimpDrawable *drawable,
218
GimpPreview *preview)
297
oilify (GimpDrawable *drawable,
298
GimpPreview *preview)
300
gboolean use_inten_alg;
220
301
GimpPixelRgn src_rgn, dest_rgn;
222
303
gint width, height;
223
304
guchar *src_row, *src;
224
305
guchar *dest_row, *dest;
225
gint x, y, c, b, xx, yy, n;
229
gint Hist[4][HISTSIZE];
231
gint progress, max_progress;
234
/* get the selection bounds */
237
gimp_preview_get_position (preview, &x1, &y1);
238
gimp_preview_get_size (preview, &width, &height);
245
gimp_drawable_mask_bounds (drawable->drawable_id, &x1, &y1, &x2, &y2);
251
max_progress = width * height;
253
bytes = drawable->bpp;
255
n = (int) ovals.mask_size / 2;
257
gimp_pixel_rgn_init (&dest_rgn, drawable,
258
x1, y1, width, height, (preview == NULL), TRUE);
259
gimp_pixel_rgn_init (&src_rgn, drawable,
260
x1, y1, width, height, FALSE, FALSE);
261
src_buf = g_new (guchar, width * height * bytes);
262
gimp_pixel_rgn_get_rect (&src_rgn, src_buf, x1, y1, width, height);
264
for (pr1 = gimp_pixel_rgns_register (1, &dest_rgn);
266
pr1 = gimp_pixel_rgns_process (pr1))
268
dest_row = dest_rgn.data;
270
for (y = dest_rgn.y; y < (dest_rgn.y + dest_rgn.h); y++)
274
for (x = dest_rgn.x; x < (dest_rgn.x + dest_rgn.w); x++)
276
x3 = CLAMP ((x - n), x1, x2);
277
y3 = CLAMP ((y - n), y1, y2);
278
x4 = CLAMP ((x + n + 1), x1, x2);
279
y4 = CLAMP ((y + n + 1), y1, y2);
281
memset(Cnt, 0, sizeof(Cnt));
282
memset(Hist, 0, sizeof(Hist));
284
src_row = src_buf + ((y3 - y1) * width + (x3 - x1)) * bytes;
285
for (yy = y3 ; yy < y4 ; yy++)
288
for (xx = x3 ; xx < x4 ; xx++)
290
for (b = 0; b < bytes; b++)
292
if ((c = ++Hist[b][src[b]]) > Cnt[b])
300
src_row += width * bytes;
306
dest_row += dest_rgn.rowstride;
311
gimp_drawable_preview_draw_region (GIMP_DRAWABLE_PREVIEW (preview),
316
progress += dest_rgn.w * dest_rgn.h;
317
if ((progress % 5) == 0)
318
gimp_progress_update ((double) progress / (double) max_progress);
326
/* update the oil-painted region */
327
gimp_drawable_flush (drawable);
328
gimp_drawable_merge_shadow (drawable->drawable_id, TRUE);
329
gimp_drawable_update (drawable->drawable_id, x1, y1, width, height);
334
* For each RGB channel, replace the pixel at (x,y) with the
335
* value that occurs most often in the n x n chunk centered
336
* at (x,y). Histogram is based on intensity.
339
oilify_intensity (GimpDrawable *drawable,
340
GimpPreview *preview)
342
GimpPixelRgn src_rgn, dest_rgn;
345
guchar *src_row, *src, *selected_src = NULL;
346
guchar *dest_row, *dest;
347
gint x, y, c, xx, yy, n;
306
gint x, y, b, c, xx, yy, n;
351
309
gint Hist[HISTSIZE];
310
gint Hist_rgb[4][HISTSIZE];
353
312
gint progress, max_progress;
317
use_inten_alg = gimp_drawable_is_rgb (drawable->drawable_id) &&
318
ovals.mode == MODE_INTEN;
356
320
/* get the selection bounds */