From 8abc7b4549e7271ff85a4ced227992f4ef2a7335 Mon Sep 17 00:00:00 2001 From: Sven Neumann Date: Sun, 26 Apr 1998 15:58:14 +0000 Subject: [PATCH] Updated engrave and oilify using the patches Torsten sent to gimp-devel. Had to fiddle around a bit to make them apply cleanly, but now everything seems to work fine. Changed the scripts that call oilify since the number of parameters has changed. --Sven --- ChangeLog | 7 + plug-ins/common/engrave.c | 4 +- plug-ins/common/oilify.c | 405 +++++++++++++++++-------- plug-ins/engrave/engrave.c | 4 +- plug-ins/oilify/oilify.c | 405 +++++++++++++++++-------- plug-ins/script-fu/scripts/circuit.scm | 2 +- plug-ins/script-fu/scripts/lava.scm | 2 +- 7 files changed, 559 insertions(+), 270 deletions(-) diff --git a/ChangeLog b/ChangeLog index 583e381c8f..f069381d68 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +Sun Apr 26 17:50:36 MEST 1998 Sven Neumann + + * updated engrave plug-in + + * updated oilify plug-in + * changed the call to plug-in-oilify in circuit.scm and lava.scm + Sun Apr 26 03:06:16 PDT 1998 Manish Singh * oh goodie, the PSD plugin doesn't relay on endian junk anymore diff --git a/plug-ins/common/engrave.c b/plug-ins/common/engrave.c index fe890103fc..04828c3c9d 100644 --- a/plug-ins/common/engrave.c +++ b/plug-ins/common/engrave.c @@ -114,12 +114,12 @@ query() gimp_install_procedure("plug_in_engrave", "Engrave the contents of the specified drawable", - "More help", + "Creates a black-and-white 'engraved' version of an image as seen in old illustrations", "Spencer Kimball & Peter Mattis, Eiichi Takamori, Torsten Martinsen", "Spencer Kimball & Peter Mattis, Eiichi Takamori, Torsten Martinsen", "1995,1996,1997", "/Filters/Distorts/Engrave", - "RGB, GRAY", + "RGBA, GRAYA", PROC_PLUG_IN, nargs, nreturn_vals, args, return_vals); diff --git a/plug-ins/common/oilify.c b/plug-ins/common/oilify.c index 8b843391da..8c392649d1 100644 --- a/plug-ins/common/oilify.c +++ b/plug-ins/common/oilify.c @@ -29,9 +29,16 @@ #define ENTRY_WIDTH 30 #define SCALE_WIDTH 125 #define HISTSIZE 256 +#define BOUNDS(a,x,y) ((a < x) ? x : ((a > y) ? y : a)) + +#define MODE_RGB 0 +#define MODE_INTEN 1 + +#define INTENSITY(p) ((unsigned int) (p[0]*77+p[1]*150+p[2]*29) >> 8) typedef struct { gdouble mask_size; + gint mode; } OilifyVals; typedef struct { @@ -42,28 +49,32 @@ typedef struct { */ static void query (void); static void run (char *name, - int nparams, - GParam *param, - int *nreturn_vals, - GParam **return_vals); -static void oilify (GDrawable * drawable); + int nparams, + GParam *param, + int *nreturn_vals, + GParam **return_vals); +static void oilify_rgb (GDrawable * drawable); +static void oilify_intensity (GDrawable * drawable); static gint oilify_dialog (); static void oilify_close_callback (GtkWidget *widget, - gpointer data); + gpointer data); static void oilify_ok_callback (GtkWidget *widget, - gpointer data); + gpointer data); static void oilify_scale_update (GtkAdjustment *adjustment, - double *scale_val); + double *scale_val); static void oilify_entry_update (GtkWidget *widget, - gdouble *value); -static void dialog_create_value (char *title, - GtkTable *table, - int row, - gdouble *value, - double left, - double right); + gdouble *value); +static void dialog_create_value (char *title, + GtkTable *table, + int row, + gdouble *value, + double left, + double right); + +static void oilify_toggle_update (GtkWidget *widget, + gpointer data); GPlugInInfo PLUG_IN_INFO = { @@ -75,7 +86,8 @@ GPlugInInfo PLUG_IN_INFO = static OilifyVals ovals = { - 7.0 /* mask size */ + 7.0, /* mask size */ + 0 /* mode */ }; static OilifyInterface oint = @@ -95,6 +107,7 @@ query () { PARAM_IMAGE, "image", "Input image (unused)" }, { PARAM_DRAWABLE, "drawable", "Input drawable" }, { PARAM_INT32, "mask_size", "Oil paint mask size" }, + { PARAM_INT32, "mode", "Algorithm {RGB (0), INTENSITY (1)}" } }; static GParamDef *return_vals = NULL; static int nargs = sizeof (args) / sizeof (args[0]); @@ -127,7 +140,7 @@ run (char *name, run_mode = param[0].data.d_int32; - *nreturn_vals = 1; + *nreturn_vals = 2; *return_vals = values; values[0].type = PARAM_STATUS; @@ -141,20 +154,22 @@ run (char *name, /* First acquire information with a dialog */ if (! oilify_dialog ()) - return; + return; break; case RUN_NONINTERACTIVE: /* Make sure all the arguments are there! */ - if (nparams != 4) - status = STATUS_CALLING_ERROR; + if (nparams != 5) + status = STATUS_CALLING_ERROR; if (status == STATUS_SUCCESS) - { - ovals.mask_size = (gdouble) param[3].data.d_int32; - } + { + ovals.mask_size = (gdouble) param[3].data.d_int32; + ovals.mode = (gint) param[4].data.d_int32; + } if (status == STATUS_SUCCESS && - (ovals.mask_size < 1.0)) - status = STATUS_CALLING_ERROR; + ((ovals.mask_size < 1.0) || + ((ovals.mode != MODE_INTEN) && (ovals.mode != MODE_RGB)))) + status = STATUS_CALLING_ERROR; break; case RUN_WITH_LAST_VALS: @@ -175,14 +190,18 @@ run (char *name, { gimp_progress_init ("Oil Painting..."); gimp_tile_cache_ntiles (2 * (drawable->width / gimp_tile_width () + 1)); - oilify (drawable); + + if (gimp_drawable_color (drawable->id) && (ovals.mode == MODE_INTEN)) + oilify_intensity (drawable); + else + oilify_rgb (drawable); if (run_mode != RUN_NONINTERACTIVE) - gimp_displays_flush (); + gimp_displays_flush (); /* Store data */ if (run_mode == RUN_INTERACTIVE) - gimp_set_data ("plug_in_oilify", &ovals, sizeof (OilifyVals)); + gimp_set_data ("plug_in_oilify", &ovals, sizeof (OilifyVals)); } else { @@ -201,14 +220,14 @@ run (char *name, * at (x,y). */ static void -oilify (GDrawable *drawable) +oilify_rgb (GDrawable *drawable) { GPixelRgn src_rgn, dest_rgn; gint bytes; gint width, height; guchar *src_row, *src; guchar *dest_row, *dest; - gint x, y, c, b, xx, yy, n; + gint x, y, c, b, i, px, xx, yy, n; gint x1, y1, x2, y2; gint x3, y3, x4, y4; gint Val[4]; @@ -216,8 +235,6 @@ oilify (GDrawable *drawable) gint Hist[4][HISTSIZE]; gpointer pr1, pr2; gint progress, max_progress; - gint *tmp1, *tmp2; - guchar *guc_tmp1; /* get the selection bounds */ gimp_drawable_mask_bounds (drawable->id, &x1, &y1, &x2, &y2); @@ -239,63 +256,163 @@ oilify (GDrawable *drawable) for (y = dest_rgn.y; y < (dest_rgn.y + dest_rgn.h); y++) { dest = dest_row; - + for (x = dest_rgn.x; x < (dest_rgn.x + dest_rgn.w); x++) { - memset(Cnt, 0, sizeof(Cnt)); - memset(Val, 0, sizeof(Val)); - memset(Hist, 0, sizeof(Hist)); - - x3 = CLAMP ((x - n), x1, x2); - y3 = CLAMP ((y - n), y1, y2); - x4 = CLAMP ((x + n + 1), x1, x2); - y4 = CLAMP ((y + n + 1), y1, y2); - + for (b = 0; b < bytes; b++) + { + Cnt[b] = 0; + Val[b] = 0; + for (i = 0; i < HISTSIZE; i++) + Hist[b][i] = 0; + } + + x3 = BOUNDS ((x - n), x1, x2); + y3 = BOUNDS ((y - n), y1, y2); + x4 = BOUNDS ((x + n + 1), x1, x2); + y4 = BOUNDS ((y + n + 1), y1, y2); + gimp_pixel_rgn_init (&src_rgn, drawable, x3, y3, (x4 - x3), (y4 - y3), FALSE, FALSE); - + for (pr2 = gimp_pixel_rgns_register (1, &src_rgn); pr2 != NULL; pr2 = gimp_pixel_rgns_process (pr2)) { src_row = src_rgn.data; - + for (yy = 0; yy < src_rgn.h; yy++) { src = src_row; - + for (xx = 0; xx < src_rgn.w; xx++) { - for (b = 0, - tmp1 = Val, - tmp2 = Cnt, - guc_tmp1 = src; - b < bytes; - b++, tmp1++, tmp2++, guc_tmp1++) + for (b = 0; b < bytes; b++) { - if ((c = ++Hist[b][*guc_tmp1]) > *tmp2) + if ((c = ++Hist[b][px = src[b]]) > Cnt[b]) { - *tmp1 = *guc_tmp1; - *tmp2 = c; + Val[b] = px; + Cnt[b] = c; } } - + src += src_rgn.bpp; } - + src_row += src_rgn.rowstride; } } - - for (b = 0, tmp1 = Val; b < bytes; b++) - *dest++ = *tmp1++; + + for (b = 0; b < bytes; b++) + *dest++ = Val[b]; } - + dest_row += dest_rgn.rowstride; } + + progress += dest_rgn.w * dest_rgn.h; + gimp_progress_update ((double) progress / (double) max_progress); + } + + /* update the oil-painted region */ + gimp_drawable_flush (drawable); + gimp_drawable_merge_shadow (drawable->id, TRUE); + gimp_drawable_update (drawable->id, x1, y1, (x2 - x1), (y2 - y1)); +} +/* + * For each RGB channel, replace the pixel at (x,y) with the + * value that occurs most often in the n x n chunk centered + * at (x,y). Histogram is based on intensity. + */ +static void +oilify_intensity (GDrawable *drawable) +{ + GPixelRgn src_rgn, dest_rgn; + gint bytes; + gint width, height; + guchar *src_row, *src; + guchar *dest_row, *dest; + gint x, y, c, b, i, xx, yy, n; + gint x1, y1, x2, y2; + gint x3, y3, x4, y4; + gint Val[4]; + gint Cnt; + gint Hist[HISTSIZE]; + gpointer pr1, pr2; + gint progress, max_progress; + + /* get the selection bounds */ + gimp_drawable_mask_bounds (drawable->id, &x1, &y1, &x2, &y2); + progress = 0; + max_progress = (x2 - x1) * (y2 - y1); + + width = drawable->width; + height = drawable->height; + bytes = drawable->bpp; + + n = (int) ovals.mask_size / 2; + + gimp_pixel_rgn_init (&dest_rgn, drawable, x1, y1, (x2 - x1), (y2 - y1), TRUE, TRUE); + + for (pr1 = gimp_pixel_rgns_register (1, &dest_rgn); pr1 != NULL; pr1 = gimp_pixel_rgns_process (pr1)) + { + dest_row = dest_rgn.data; + + for (y = dest_rgn.y; y < (dest_rgn.y + dest_rgn.h); y++) + { + dest = dest_row; + + for (x = dest_rgn.x; x < (dest_rgn.x + dest_rgn.w); x++) + { + Cnt = 0; + for (b = 0; b < bytes; b++) + { + Val[b] = 0; + for (i = 0; i < HISTSIZE; i++) + Hist[i] = 0; + } + + x3 = BOUNDS ((x - n), x1, x2); + y3 = BOUNDS ((y - n), y1, y2); + x4 = BOUNDS ((x + n + 1), x1, x2); + y4 = BOUNDS ((y + n + 1), y1, y2); + + gimp_pixel_rgn_init (&src_rgn, drawable, x3, y3, (x4 - x3), (y4 - y3), FALSE, FALSE); + + for (pr2 = gimp_pixel_rgns_register (1, &src_rgn); pr2 != NULL; pr2 = gimp_pixel_rgns_process (pr2)) + { + src_row = src_rgn.data; + + for (yy = 0; yy < src_rgn.h; yy++) + { + src = src_row; + + for (xx = 0; xx < src_rgn.w; xx++) + { + if ((c = ++Hist[INTENSITY(src)]) > Cnt) + { + Cnt = c; + for (b = 0; b < bytes; b++) + Val[b] = src[b]; + } + + src += src_rgn.bpp; + } + + src_row += src_rgn.rowstride; + } + } + + for (b = 0; b < bytes; b++) + *dest++ = Val[b]; + } + + dest_row += dest_rgn.rowstride; + } + progress += dest_rgn.w * dest_rgn.h; if((progress % 5) == 0) gimp_progress_update ((double) progress / (double) max_progress); } - + /* update the oil-painted region */ gimp_drawable_flush (drawable); gimp_drawable_merge_shadow (drawable->id, TRUE); @@ -309,6 +426,7 @@ oilify_dialog () GtkWidget *button; GtkWidget *frame; GtkWidget *table; + GtkWidget *toggle; gchar **argv; gint argc; @@ -323,8 +441,8 @@ oilify_dialog () gtk_window_set_title (GTK_WINDOW (dlg), "Oilify"); gtk_window_position (GTK_WINDOW (dlg), GTK_WIN_POS_MOUSE); gtk_signal_connect (GTK_OBJECT (dlg), "destroy", - (GtkSignalFunc) oilify_close_callback, - NULL); + (GtkSignalFunc) oilify_close_callback, + NULL); /* Action area */ button = gtk_button_new_with_label ("OK"); @@ -339,8 +457,8 @@ oilify_dialog () button = gtk_button_new_with_label ("Cancel"); GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); gtk_signal_connect_object (GTK_OBJECT (button), "clicked", - (GtkSignalFunc) gtk_widget_destroy, - GTK_OBJECT (dlg)); + (GtkSignalFunc) gtk_widget_destroy, + GTK_OBJECT (dlg)); gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dlg)->action_area), button, TRUE, TRUE, 0); gtk_widget_show (button); @@ -353,7 +471,15 @@ oilify_dialog () gtk_container_border_width (GTK_CONTAINER (table), 10); gtk_container_add (GTK_CONTAINER (frame), table); - dialog_create_value("Mask Size", GTK_TABLE(table), 1, &ovals.mask_size, 1.0, 50.0); + toggle = gtk_check_button_new_with_label ("Use intensity algorithm"); + gtk_table_attach (GTK_TABLE (table), toggle, 0, 2, 0, 1, GTK_FILL, 0, 0, 0); + gtk_signal_connect (GTK_OBJECT (toggle), "toggled", + (GtkSignalFunc) oilify_toggle_update, + &ovals.mode); + gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (toggle), ovals.mode); + gtk_widget_show (toggle); + + dialog_create_value("Mask Size", GTK_TABLE(table), 1, &ovals.mask_size, 3.0, 50.0); gtk_widget_show (frame); gtk_widget_show (table); @@ -370,14 +496,14 @@ oilify_dialog () static void oilify_close_callback (GtkWidget *widget, - gpointer data) + gpointer data) { gtk_main_quit (); } static void oilify_ok_callback (GtkWidget *widget, - gpointer data) + gpointer data) { oint.run = TRUE; gtk_widget_destroy (GTK_WIDGET (data)); @@ -389,80 +515,95 @@ oilify_ok_callback (GtkWidget *widget, static void dialog_create_value(char *title, GtkTable *table, int row, gdouble *value, double left, double right) { - GtkWidget *label; - GtkWidget *scale; - GtkWidget *entry; - GtkObject *scale_data; - char buf[256]; - - label = gtk_label_new(title); - gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5); - gtk_table_attach(table, label, 0, 1, row, row + 1, GTK_FILL, GTK_FILL, 4, 0); - gtk_widget_show(label); - - scale_data = gtk_adjustment_new(*value, left, right, - 1.0, 5.0, 5.0); - - gtk_signal_connect(GTK_OBJECT(scale_data), "value_changed", - (GtkSignalFunc) oilify_scale_update, - value); - - scale = gtk_hscale_new(GTK_ADJUSTMENT(scale_data)); - gtk_widget_set_usize(scale, SCALE_WIDTH, 0); - gtk_table_attach(table, scale, 1, 2, row, row + 1, GTK_EXPAND | GTK_FILL, GTK_FILL, 0, 0); - gtk_scale_set_draw_value(GTK_SCALE(scale), FALSE); - gtk_scale_set_digits(GTK_SCALE(scale), 3); - gtk_range_set_update_policy(GTK_RANGE(scale), GTK_UPDATE_CONTINUOUS); - gtk_widget_show(scale); - - entry = gtk_entry_new(); - gtk_object_set_user_data(GTK_OBJECT(entry), scale_data); - gtk_object_set_user_data(scale_data, entry); - gtk_widget_set_usize(entry, ENTRY_WIDTH, 0); - sprintf(buf, "%.0f", *value); - gtk_entry_set_text(GTK_ENTRY(entry), buf); - gtk_signal_connect(GTK_OBJECT(entry), "changed", - (GtkSignalFunc) oilify_entry_update, - value); - gtk_table_attach(GTK_TABLE(table), entry, 2, 3, row, row + 1, GTK_FILL, GTK_FILL, 4, 0); - gtk_widget_show(entry); + GtkWidget *label; + GtkWidget *scale; + GtkWidget *entry; + GtkObject *scale_data; + char buf[256]; + + label = gtk_label_new(title); + gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5); + gtk_table_attach(table, label, 0, 1, row, row + 1, GTK_FILL, GTK_FILL, 4, 0); + gtk_widget_show(label); + + scale_data = gtk_adjustment_new(*value, left, right, 1.0, 5.0, 5.0); + + gtk_signal_connect(GTK_OBJECT(scale_data), "value_changed", + (GtkSignalFunc) oilify_scale_update, + value); + + scale = gtk_hscale_new(GTK_ADJUSTMENT(scale_data)); + gtk_widget_set_usize(scale, SCALE_WIDTH, 0); + gtk_table_attach(table, scale, 1, 2, row, row + 1, GTK_EXPAND | GTK_FILL, GTK_FILL, 0, 0); + gtk_scale_set_draw_value(GTK_SCALE(scale), FALSE); + gtk_scale_set_digits(GTK_SCALE(scale), 3); + gtk_range_set_update_policy(GTK_RANGE(scale), GTK_UPDATE_CONTINUOUS); + gtk_widget_show(scale); + + entry = gtk_entry_new(); + gtk_object_set_user_data(GTK_OBJECT(entry), scale_data); + gtk_object_set_user_data(scale_data, entry); + gtk_widget_set_usize(entry, ENTRY_WIDTH, 0); + sprintf(buf, "%.0f", *value); + gtk_entry_set_text(GTK_ENTRY(entry), buf); + gtk_signal_connect(GTK_OBJECT(entry), "changed", + (GtkSignalFunc) oilify_entry_update, + value); + gtk_table_attach(GTK_TABLE(table), entry, 2, 3, row, row + 1, GTK_FILL, GTK_FILL, 4, 0); + gtk_widget_show(entry); } static void oilify_entry_update(GtkWidget *widget, gdouble *value) { - GtkAdjustment *adjustment; - gdouble new_value; + GtkAdjustment *adjustment; + gdouble new_value; - new_value = atof(gtk_entry_get_text(GTK_ENTRY(widget))); + new_value = atof(gtk_entry_get_text(GTK_ENTRY(widget))); + + if (*value != new_value) { + adjustment = gtk_object_get_user_data(GTK_OBJECT(widget)); - if (*value != new_value) { - adjustment = gtk_object_get_user_data(GTK_OBJECT(widget)); - - if ((new_value >= adjustment->lower) && - (new_value <= adjustment->upper)) { - *value = new_value; - adjustment->value = new_value; - - gtk_signal_emit_by_name(GTK_OBJECT(adjustment), "value_changed"); - } /* if */ - } /* if */ + if ((new_value >= adjustment->lower) && + (new_value <= adjustment->upper)) { + *value = new_value; + adjustment->value = new_value; + + gtk_signal_emit_by_name(GTK_OBJECT(adjustment), "value_changed"); + } /* if */ + } /* if */ } static void oilify_scale_update (GtkAdjustment *adjustment, gdouble *value) { - GtkWidget *entry; - char buf[256]; - - if (*value != adjustment->value) { - *value = adjustment->value; - - entry = gtk_object_get_user_data(GTK_OBJECT(adjustment)); - sprintf(buf, "%.0f", *value); - - gtk_signal_handler_block_by_data(GTK_OBJECT(entry), value); - gtk_entry_set_text(GTK_ENTRY(entry), buf); - gtk_signal_handler_unblock_by_data(GTK_OBJECT(entry), value); - } /* if */ + GtkWidget *entry; + char buf[256]; + + if (*value != adjustment->value) { + adjustment->value = (int) adjustment->value | 1; + *value = adjustment->value; + + entry = gtk_object_get_user_data(GTK_OBJECT(adjustment)); + sprintf(buf, "%.0f", *value); + + gtk_signal_handler_block_by_data(GTK_OBJECT(entry), value); + gtk_entry_set_text(GTK_ENTRY(entry), buf); + gtk_signal_handler_unblock_by_data(GTK_OBJECT(entry), value); + } /* if */ } + +static void +oilify_toggle_update (GtkWidget *widget, + gpointer data) +{ + int *toggle_val; + + toggle_val = (int *) data; + + if (GTK_TOGGLE_BUTTON (widget)->active) + *toggle_val = MODE_INTEN; + else + *toggle_val = MODE_RGB; +} + diff --git a/plug-ins/engrave/engrave.c b/plug-ins/engrave/engrave.c index fe890103fc..04828c3c9d 100644 --- a/plug-ins/engrave/engrave.c +++ b/plug-ins/engrave/engrave.c @@ -114,12 +114,12 @@ query() gimp_install_procedure("plug_in_engrave", "Engrave the contents of the specified drawable", - "More help", + "Creates a black-and-white 'engraved' version of an image as seen in old illustrations", "Spencer Kimball & Peter Mattis, Eiichi Takamori, Torsten Martinsen", "Spencer Kimball & Peter Mattis, Eiichi Takamori, Torsten Martinsen", "1995,1996,1997", "/Filters/Distorts/Engrave", - "RGB, GRAY", + "RGBA, GRAYA", PROC_PLUG_IN, nargs, nreturn_vals, args, return_vals); diff --git a/plug-ins/oilify/oilify.c b/plug-ins/oilify/oilify.c index 8b843391da..8c392649d1 100644 --- a/plug-ins/oilify/oilify.c +++ b/plug-ins/oilify/oilify.c @@ -29,9 +29,16 @@ #define ENTRY_WIDTH 30 #define SCALE_WIDTH 125 #define HISTSIZE 256 +#define BOUNDS(a,x,y) ((a < x) ? x : ((a > y) ? y : a)) + +#define MODE_RGB 0 +#define MODE_INTEN 1 + +#define INTENSITY(p) ((unsigned int) (p[0]*77+p[1]*150+p[2]*29) >> 8) typedef struct { gdouble mask_size; + gint mode; } OilifyVals; typedef struct { @@ -42,28 +49,32 @@ typedef struct { */ static void query (void); static void run (char *name, - int nparams, - GParam *param, - int *nreturn_vals, - GParam **return_vals); -static void oilify (GDrawable * drawable); + int nparams, + GParam *param, + int *nreturn_vals, + GParam **return_vals); +static void oilify_rgb (GDrawable * drawable); +static void oilify_intensity (GDrawable * drawable); static gint oilify_dialog (); static void oilify_close_callback (GtkWidget *widget, - gpointer data); + gpointer data); static void oilify_ok_callback (GtkWidget *widget, - gpointer data); + gpointer data); static void oilify_scale_update (GtkAdjustment *adjustment, - double *scale_val); + double *scale_val); static void oilify_entry_update (GtkWidget *widget, - gdouble *value); -static void dialog_create_value (char *title, - GtkTable *table, - int row, - gdouble *value, - double left, - double right); + gdouble *value); +static void dialog_create_value (char *title, + GtkTable *table, + int row, + gdouble *value, + double left, + double right); + +static void oilify_toggle_update (GtkWidget *widget, + gpointer data); GPlugInInfo PLUG_IN_INFO = { @@ -75,7 +86,8 @@ GPlugInInfo PLUG_IN_INFO = static OilifyVals ovals = { - 7.0 /* mask size */ + 7.0, /* mask size */ + 0 /* mode */ }; static OilifyInterface oint = @@ -95,6 +107,7 @@ query () { PARAM_IMAGE, "image", "Input image (unused)" }, { PARAM_DRAWABLE, "drawable", "Input drawable" }, { PARAM_INT32, "mask_size", "Oil paint mask size" }, + { PARAM_INT32, "mode", "Algorithm {RGB (0), INTENSITY (1)}" } }; static GParamDef *return_vals = NULL; static int nargs = sizeof (args) / sizeof (args[0]); @@ -127,7 +140,7 @@ run (char *name, run_mode = param[0].data.d_int32; - *nreturn_vals = 1; + *nreturn_vals = 2; *return_vals = values; values[0].type = PARAM_STATUS; @@ -141,20 +154,22 @@ run (char *name, /* First acquire information with a dialog */ if (! oilify_dialog ()) - return; + return; break; case RUN_NONINTERACTIVE: /* Make sure all the arguments are there! */ - if (nparams != 4) - status = STATUS_CALLING_ERROR; + if (nparams != 5) + status = STATUS_CALLING_ERROR; if (status == STATUS_SUCCESS) - { - ovals.mask_size = (gdouble) param[3].data.d_int32; - } + { + ovals.mask_size = (gdouble) param[3].data.d_int32; + ovals.mode = (gint) param[4].data.d_int32; + } if (status == STATUS_SUCCESS && - (ovals.mask_size < 1.0)) - status = STATUS_CALLING_ERROR; + ((ovals.mask_size < 1.0) || + ((ovals.mode != MODE_INTEN) && (ovals.mode != MODE_RGB)))) + status = STATUS_CALLING_ERROR; break; case RUN_WITH_LAST_VALS: @@ -175,14 +190,18 @@ run (char *name, { gimp_progress_init ("Oil Painting..."); gimp_tile_cache_ntiles (2 * (drawable->width / gimp_tile_width () + 1)); - oilify (drawable); + + if (gimp_drawable_color (drawable->id) && (ovals.mode == MODE_INTEN)) + oilify_intensity (drawable); + else + oilify_rgb (drawable); if (run_mode != RUN_NONINTERACTIVE) - gimp_displays_flush (); + gimp_displays_flush (); /* Store data */ if (run_mode == RUN_INTERACTIVE) - gimp_set_data ("plug_in_oilify", &ovals, sizeof (OilifyVals)); + gimp_set_data ("plug_in_oilify", &ovals, sizeof (OilifyVals)); } else { @@ -201,14 +220,14 @@ run (char *name, * at (x,y). */ static void -oilify (GDrawable *drawable) +oilify_rgb (GDrawable *drawable) { GPixelRgn src_rgn, dest_rgn; gint bytes; gint width, height; guchar *src_row, *src; guchar *dest_row, *dest; - gint x, y, c, b, xx, yy, n; + gint x, y, c, b, i, px, xx, yy, n; gint x1, y1, x2, y2; gint x3, y3, x4, y4; gint Val[4]; @@ -216,8 +235,6 @@ oilify (GDrawable *drawable) gint Hist[4][HISTSIZE]; gpointer pr1, pr2; gint progress, max_progress; - gint *tmp1, *tmp2; - guchar *guc_tmp1; /* get the selection bounds */ gimp_drawable_mask_bounds (drawable->id, &x1, &y1, &x2, &y2); @@ -239,63 +256,163 @@ oilify (GDrawable *drawable) for (y = dest_rgn.y; y < (dest_rgn.y + dest_rgn.h); y++) { dest = dest_row; - + for (x = dest_rgn.x; x < (dest_rgn.x + dest_rgn.w); x++) { - memset(Cnt, 0, sizeof(Cnt)); - memset(Val, 0, sizeof(Val)); - memset(Hist, 0, sizeof(Hist)); - - x3 = CLAMP ((x - n), x1, x2); - y3 = CLAMP ((y - n), y1, y2); - x4 = CLAMP ((x + n + 1), x1, x2); - y4 = CLAMP ((y + n + 1), y1, y2); - + for (b = 0; b < bytes; b++) + { + Cnt[b] = 0; + Val[b] = 0; + for (i = 0; i < HISTSIZE; i++) + Hist[b][i] = 0; + } + + x3 = BOUNDS ((x - n), x1, x2); + y3 = BOUNDS ((y - n), y1, y2); + x4 = BOUNDS ((x + n + 1), x1, x2); + y4 = BOUNDS ((y + n + 1), y1, y2); + gimp_pixel_rgn_init (&src_rgn, drawable, x3, y3, (x4 - x3), (y4 - y3), FALSE, FALSE); - + for (pr2 = gimp_pixel_rgns_register (1, &src_rgn); pr2 != NULL; pr2 = gimp_pixel_rgns_process (pr2)) { src_row = src_rgn.data; - + for (yy = 0; yy < src_rgn.h; yy++) { src = src_row; - + for (xx = 0; xx < src_rgn.w; xx++) { - for (b = 0, - tmp1 = Val, - tmp2 = Cnt, - guc_tmp1 = src; - b < bytes; - b++, tmp1++, tmp2++, guc_tmp1++) + for (b = 0; b < bytes; b++) { - if ((c = ++Hist[b][*guc_tmp1]) > *tmp2) + if ((c = ++Hist[b][px = src[b]]) > Cnt[b]) { - *tmp1 = *guc_tmp1; - *tmp2 = c; + Val[b] = px; + Cnt[b] = c; } } - + src += src_rgn.bpp; } - + src_row += src_rgn.rowstride; } } - - for (b = 0, tmp1 = Val; b < bytes; b++) - *dest++ = *tmp1++; + + for (b = 0; b < bytes; b++) + *dest++ = Val[b]; } - + dest_row += dest_rgn.rowstride; } + + progress += dest_rgn.w * dest_rgn.h; + gimp_progress_update ((double) progress / (double) max_progress); + } + + /* update the oil-painted region */ + gimp_drawable_flush (drawable); + gimp_drawable_merge_shadow (drawable->id, TRUE); + gimp_drawable_update (drawable->id, x1, y1, (x2 - x1), (y2 - y1)); +} +/* + * For each RGB channel, replace the pixel at (x,y) with the + * value that occurs most often in the n x n chunk centered + * at (x,y). Histogram is based on intensity. + */ +static void +oilify_intensity (GDrawable *drawable) +{ + GPixelRgn src_rgn, dest_rgn; + gint bytes; + gint width, height; + guchar *src_row, *src; + guchar *dest_row, *dest; + gint x, y, c, b, i, xx, yy, n; + gint x1, y1, x2, y2; + gint x3, y3, x4, y4; + gint Val[4]; + gint Cnt; + gint Hist[HISTSIZE]; + gpointer pr1, pr2; + gint progress, max_progress; + + /* get the selection bounds */ + gimp_drawable_mask_bounds (drawable->id, &x1, &y1, &x2, &y2); + progress = 0; + max_progress = (x2 - x1) * (y2 - y1); + + width = drawable->width; + height = drawable->height; + bytes = drawable->bpp; + + n = (int) ovals.mask_size / 2; + + gimp_pixel_rgn_init (&dest_rgn, drawable, x1, y1, (x2 - x1), (y2 - y1), TRUE, TRUE); + + for (pr1 = gimp_pixel_rgns_register (1, &dest_rgn); pr1 != NULL; pr1 = gimp_pixel_rgns_process (pr1)) + { + dest_row = dest_rgn.data; + + for (y = dest_rgn.y; y < (dest_rgn.y + dest_rgn.h); y++) + { + dest = dest_row; + + for (x = dest_rgn.x; x < (dest_rgn.x + dest_rgn.w); x++) + { + Cnt = 0; + for (b = 0; b < bytes; b++) + { + Val[b] = 0; + for (i = 0; i < HISTSIZE; i++) + Hist[i] = 0; + } + + x3 = BOUNDS ((x - n), x1, x2); + y3 = BOUNDS ((y - n), y1, y2); + x4 = BOUNDS ((x + n + 1), x1, x2); + y4 = BOUNDS ((y + n + 1), y1, y2); + + gimp_pixel_rgn_init (&src_rgn, drawable, x3, y3, (x4 - x3), (y4 - y3), FALSE, FALSE); + + for (pr2 = gimp_pixel_rgns_register (1, &src_rgn); pr2 != NULL; pr2 = gimp_pixel_rgns_process (pr2)) + { + src_row = src_rgn.data; + + for (yy = 0; yy < src_rgn.h; yy++) + { + src = src_row; + + for (xx = 0; xx < src_rgn.w; xx++) + { + if ((c = ++Hist[INTENSITY(src)]) > Cnt) + { + Cnt = c; + for (b = 0; b < bytes; b++) + Val[b] = src[b]; + } + + src += src_rgn.bpp; + } + + src_row += src_rgn.rowstride; + } + } + + for (b = 0; b < bytes; b++) + *dest++ = Val[b]; + } + + dest_row += dest_rgn.rowstride; + } + progress += dest_rgn.w * dest_rgn.h; if((progress % 5) == 0) gimp_progress_update ((double) progress / (double) max_progress); } - + /* update the oil-painted region */ gimp_drawable_flush (drawable); gimp_drawable_merge_shadow (drawable->id, TRUE); @@ -309,6 +426,7 @@ oilify_dialog () GtkWidget *button; GtkWidget *frame; GtkWidget *table; + GtkWidget *toggle; gchar **argv; gint argc; @@ -323,8 +441,8 @@ oilify_dialog () gtk_window_set_title (GTK_WINDOW (dlg), "Oilify"); gtk_window_position (GTK_WINDOW (dlg), GTK_WIN_POS_MOUSE); gtk_signal_connect (GTK_OBJECT (dlg), "destroy", - (GtkSignalFunc) oilify_close_callback, - NULL); + (GtkSignalFunc) oilify_close_callback, + NULL); /* Action area */ button = gtk_button_new_with_label ("OK"); @@ -339,8 +457,8 @@ oilify_dialog () button = gtk_button_new_with_label ("Cancel"); GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); gtk_signal_connect_object (GTK_OBJECT (button), "clicked", - (GtkSignalFunc) gtk_widget_destroy, - GTK_OBJECT (dlg)); + (GtkSignalFunc) gtk_widget_destroy, + GTK_OBJECT (dlg)); gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dlg)->action_area), button, TRUE, TRUE, 0); gtk_widget_show (button); @@ -353,7 +471,15 @@ oilify_dialog () gtk_container_border_width (GTK_CONTAINER (table), 10); gtk_container_add (GTK_CONTAINER (frame), table); - dialog_create_value("Mask Size", GTK_TABLE(table), 1, &ovals.mask_size, 1.0, 50.0); + toggle = gtk_check_button_new_with_label ("Use intensity algorithm"); + gtk_table_attach (GTK_TABLE (table), toggle, 0, 2, 0, 1, GTK_FILL, 0, 0, 0); + gtk_signal_connect (GTK_OBJECT (toggle), "toggled", + (GtkSignalFunc) oilify_toggle_update, + &ovals.mode); + gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (toggle), ovals.mode); + gtk_widget_show (toggle); + + dialog_create_value("Mask Size", GTK_TABLE(table), 1, &ovals.mask_size, 3.0, 50.0); gtk_widget_show (frame); gtk_widget_show (table); @@ -370,14 +496,14 @@ oilify_dialog () static void oilify_close_callback (GtkWidget *widget, - gpointer data) + gpointer data) { gtk_main_quit (); } static void oilify_ok_callback (GtkWidget *widget, - gpointer data) + gpointer data) { oint.run = TRUE; gtk_widget_destroy (GTK_WIDGET (data)); @@ -389,80 +515,95 @@ oilify_ok_callback (GtkWidget *widget, static void dialog_create_value(char *title, GtkTable *table, int row, gdouble *value, double left, double right) { - GtkWidget *label; - GtkWidget *scale; - GtkWidget *entry; - GtkObject *scale_data; - char buf[256]; - - label = gtk_label_new(title); - gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5); - gtk_table_attach(table, label, 0, 1, row, row + 1, GTK_FILL, GTK_FILL, 4, 0); - gtk_widget_show(label); - - scale_data = gtk_adjustment_new(*value, left, right, - 1.0, 5.0, 5.0); - - gtk_signal_connect(GTK_OBJECT(scale_data), "value_changed", - (GtkSignalFunc) oilify_scale_update, - value); - - scale = gtk_hscale_new(GTK_ADJUSTMENT(scale_data)); - gtk_widget_set_usize(scale, SCALE_WIDTH, 0); - gtk_table_attach(table, scale, 1, 2, row, row + 1, GTK_EXPAND | GTK_FILL, GTK_FILL, 0, 0); - gtk_scale_set_draw_value(GTK_SCALE(scale), FALSE); - gtk_scale_set_digits(GTK_SCALE(scale), 3); - gtk_range_set_update_policy(GTK_RANGE(scale), GTK_UPDATE_CONTINUOUS); - gtk_widget_show(scale); - - entry = gtk_entry_new(); - gtk_object_set_user_data(GTK_OBJECT(entry), scale_data); - gtk_object_set_user_data(scale_data, entry); - gtk_widget_set_usize(entry, ENTRY_WIDTH, 0); - sprintf(buf, "%.0f", *value); - gtk_entry_set_text(GTK_ENTRY(entry), buf); - gtk_signal_connect(GTK_OBJECT(entry), "changed", - (GtkSignalFunc) oilify_entry_update, - value); - gtk_table_attach(GTK_TABLE(table), entry, 2, 3, row, row + 1, GTK_FILL, GTK_FILL, 4, 0); - gtk_widget_show(entry); + GtkWidget *label; + GtkWidget *scale; + GtkWidget *entry; + GtkObject *scale_data; + char buf[256]; + + label = gtk_label_new(title); + gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5); + gtk_table_attach(table, label, 0, 1, row, row + 1, GTK_FILL, GTK_FILL, 4, 0); + gtk_widget_show(label); + + scale_data = gtk_adjustment_new(*value, left, right, 1.0, 5.0, 5.0); + + gtk_signal_connect(GTK_OBJECT(scale_data), "value_changed", + (GtkSignalFunc) oilify_scale_update, + value); + + scale = gtk_hscale_new(GTK_ADJUSTMENT(scale_data)); + gtk_widget_set_usize(scale, SCALE_WIDTH, 0); + gtk_table_attach(table, scale, 1, 2, row, row + 1, GTK_EXPAND | GTK_FILL, GTK_FILL, 0, 0); + gtk_scale_set_draw_value(GTK_SCALE(scale), FALSE); + gtk_scale_set_digits(GTK_SCALE(scale), 3); + gtk_range_set_update_policy(GTK_RANGE(scale), GTK_UPDATE_CONTINUOUS); + gtk_widget_show(scale); + + entry = gtk_entry_new(); + gtk_object_set_user_data(GTK_OBJECT(entry), scale_data); + gtk_object_set_user_data(scale_data, entry); + gtk_widget_set_usize(entry, ENTRY_WIDTH, 0); + sprintf(buf, "%.0f", *value); + gtk_entry_set_text(GTK_ENTRY(entry), buf); + gtk_signal_connect(GTK_OBJECT(entry), "changed", + (GtkSignalFunc) oilify_entry_update, + value); + gtk_table_attach(GTK_TABLE(table), entry, 2, 3, row, row + 1, GTK_FILL, GTK_FILL, 4, 0); + gtk_widget_show(entry); } static void oilify_entry_update(GtkWidget *widget, gdouble *value) { - GtkAdjustment *adjustment; - gdouble new_value; + GtkAdjustment *adjustment; + gdouble new_value; - new_value = atof(gtk_entry_get_text(GTK_ENTRY(widget))); + new_value = atof(gtk_entry_get_text(GTK_ENTRY(widget))); + + if (*value != new_value) { + adjustment = gtk_object_get_user_data(GTK_OBJECT(widget)); - if (*value != new_value) { - adjustment = gtk_object_get_user_data(GTK_OBJECT(widget)); - - if ((new_value >= adjustment->lower) && - (new_value <= adjustment->upper)) { - *value = new_value; - adjustment->value = new_value; - - gtk_signal_emit_by_name(GTK_OBJECT(adjustment), "value_changed"); - } /* if */ - } /* if */ + if ((new_value >= adjustment->lower) && + (new_value <= adjustment->upper)) { + *value = new_value; + adjustment->value = new_value; + + gtk_signal_emit_by_name(GTK_OBJECT(adjustment), "value_changed"); + } /* if */ + } /* if */ } static void oilify_scale_update (GtkAdjustment *adjustment, gdouble *value) { - GtkWidget *entry; - char buf[256]; - - if (*value != adjustment->value) { - *value = adjustment->value; - - entry = gtk_object_get_user_data(GTK_OBJECT(adjustment)); - sprintf(buf, "%.0f", *value); - - gtk_signal_handler_block_by_data(GTK_OBJECT(entry), value); - gtk_entry_set_text(GTK_ENTRY(entry), buf); - gtk_signal_handler_unblock_by_data(GTK_OBJECT(entry), value); - } /* if */ + GtkWidget *entry; + char buf[256]; + + if (*value != adjustment->value) { + adjustment->value = (int) adjustment->value | 1; + *value = adjustment->value; + + entry = gtk_object_get_user_data(GTK_OBJECT(adjustment)); + sprintf(buf, "%.0f", *value); + + gtk_signal_handler_block_by_data(GTK_OBJECT(entry), value); + gtk_entry_set_text(GTK_ENTRY(entry), buf); + gtk_signal_handler_unblock_by_data(GTK_OBJECT(entry), value); + } /* if */ } + +static void +oilify_toggle_update (GtkWidget *widget, + gpointer data) +{ + int *toggle_val; + + toggle_val = (int *) data; + + if (GTK_TOGGLE_BUTTON (widget)->active) + *toggle_val = MODE_INTEN; + else + *toggle_val = MODE_RGB; +} + diff --git a/plug-ins/script-fu/scripts/circuit.scm b/plug-ins/script-fu/scripts/circuit.scm index 8eee943fa8..6bf14f4fec 100644 --- a/plug-ins/script-fu/scripts/circuit.scm +++ b/plug-ins/script-fu/scripts/circuit.scm @@ -93,7 +93,7 @@ (gimp-selection-load image active-selection) (plug-in-maze 1 image active-layer 5 5 TRUE seed 57 1) - (plug-in-oilify 1 image active-layer mask-size) + (plug-in-oilify 1 image active-layer mask-size 0) (plug-in-edge 1 image active-layer 2 1) (gimp-desaturate image active-layer) diff --git a/plug-ins/script-fu/scripts/lava.scm b/plug-ins/script-fu/scripts/lava.scm index 52281592fa..b437f55063 100644 --- a/plug-ins/script-fu/scripts/lava.scm +++ b/plug-ins/script-fu/scripts/lava.scm @@ -82,7 +82,7 @@ (plug-in-solid-noise 1 image active-layer FALSE TRUE seed 2 2 2) (plug-in-cubism 1 image active-layer tile_size 2.5 0) - (plug-in-oilify 1 image active-layer mask_size) + (plug-in-oilify 1 image active-layer mask_size 0) (plug-in-edge 1 image active-layer 2 0) (plug-in-gauss-rle 1 image active-layer 2 TRUE TRUE) (plug-in-gradmap 1 image active-layer)