updated randomize and blur plugins, split out libgpc into it's own dir

-Yosh
This commit is contained in:
Manish Singh 1998-04-30 23:42:31 +00:00
parent 38d2f7ee21
commit 401690a4fe
16 changed files with 2342 additions and 861 deletions

View File

@ -1,3 +1,8 @@
Thu Apr 30 16:38:59 PDT 1998 Manish Singh <yosh@gimp.org>
* updated randomize and blur plugins, split out libgpc into
it's own dir
Thu Apr 30 14:32:16 PDT 1998 Manish Singh <yosh@gimp.org>
* upgraded to libtool 1.2

View File

@ -14,7 +14,7 @@ DIE=0
(libtool --version) < /dev/null > /dev/null 2>&1 || {
echo
echo "You must have libtool installed to compile GIMP."
echo "Get ftp://alpha.gnu.org/gnu/libtool-1.0h.tar.gz"
echo "Get ftp://ftp.gnu.org/pub/gnu/libtool-1.2.tar.gz"
echo "(or a newer version if it is available)"
DIE=1
}
@ -22,7 +22,7 @@ DIE=0
(automake --version) < /dev/null > /dev/null 2>&1 || {
echo
echo "You must have automake installed to compile GIMP."
echo "Get ftp://ftp.cygnus.com/pub/home/tromey/automake-1.2f.tar.gz"
echo "Get ftp://ftp.gnu.org/pub/gnu/automake-1.3.tar.gz"
echo "(or a newer version if it is available)"
DIE=1
}

View File

@ -548,6 +548,7 @@ plug-ins/gfig/gfig-examples/Makefile
plug-ins/screenshot/Makefile
plug-ins/sharpen/Makefile
plug-ins/psd/Makefile
plug-ins/gpc/Makefile
app/Makefile
docs/Makefile
data/Makefile

View File

@ -3,6 +3,7 @@
SUBDIRS = \
libgck \
megawidget \
gpc \
MapObject \
AlienMap \
dbbrowser \

View File

@ -5,7 +5,7 @@ pluginlibdir = $(gimpplugindir)/plug-ins
pluginlib_PROGRAMS = blur
blur_SOURCES = \
blur.c
blur.c $(top_srcdir)/plug-ins/gpc/gpc.h
INCLUDES = \
$(X_CFLAGS) \
@ -13,14 +13,15 @@ INCLUDES = \
-I$(includedir)
LDADD = \
$(top_builddir)/plug-ins/gpc/libgpc.a \
$(top_builddir)/libgimp/libgimpui.la \
$(top_builddir)/libgimp/libgimp.la \
$(X_LIBS) \
\
-lc
DEPS = \
$(top_builddir)/libgimp/libgimpui.la \
$(top_builddir)/plug-ins/gpc/libgpc.a \
$(top_builddir)/libgimp/libgimp.la
blur_DEPENDENCIES = $(DEPS)

View File

@ -1,5 +1,15 @@
/* The GIMP -- an image manipulation program
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
/****************************************************************************
* This is a plugin for the GIMP v 0.99.8 or later. Documentation is
* available at http://www.rru.com/~meo/gimp/ .
*
* Copyright (C) 1997 Miles O'Neal <meo@rru.com> http://www.rru.com/~meo/
* Blur code Copyright (C) 1995 Spencer Kimball and Peter Mattis
* GUI based on GTK code from:
* alienmap (Copyright (C) 1996, 1997 Daniel Cotting)
* plasma (Copyright (C) 1996 Stephen Norris),
* oilify (Copyright (C) 1996 Torsten Martinsen),
* ripple (Copyright (C) 1997 Brian Degenhardt) and
* whirl (Copyright (C) 1997 Federico Mena Quintero).
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -14,134 +24,362 @@
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <stdlib.h>
#include "libgimp/gimp.h"
*
****************************************************************************/
/* Declare local functions.
/****************************************************************************
* Blur:
*
* blur version 2.0 (6 Feb 1998, MEO)
* history
* 2.0 - 6 Feb 1998 MEO
* based on randomize 1.5
*
* Please send any patches or suggestions to the author: meo@rru.com .
*
* Blur applies a 3x3 blurring convolution kernel to the specified drawable.
*
* For each pixel in the selection or image,
* whether to change the pixel is decided by picking a
* random number, weighted by the user's "randomization" percentage.
* If the random number is in range, the pixel is modified. For
* blurring, an average is determined from the current and adjacent
* pixels. *(Except for the random factor, the blur code came
* straight from the original S&P blur plug-in.)*
*
* This works only with RGB and grayscale images.
*
****************************************************************************/
#include <stdlib.h>
#include <time.h>
#include "libgimp/gimp.h"
#include "gtk/gtk.h"
#include <plug-ins/gpc/gpc.h>
/*********************************
*
* PLUGIN-SPECIFIC CONSTANTS
*
********************************/
/*
* progress meter update frequency
*/
static void query (void);
static void run (char *name,
#define PROG_UPDATE_TIME ((row % 10) == 0)
#define PLUG_IN_NAME "plug_in_blur"
#define BLUR_VERSION "Blur 2.0"
#define SEED_TIME 10
#define SEED_USER 11
#define ENTRY_WIDTH 75
#define SCALE_WIDTH 100
/*********************************
*
* PLUGIN-SPECIFIC STRUCTURES AND DATA
*
********************************/
typedef struct {
gdouble blur_pct; /* likelihood of randomization (as %age) */
gint seed_type; /* seed init. type - current time or user value */
gint blur_seed; /* seed value for rand() function */
gdouble blur_rcount; /* repeat count */
} BlurVals;
static BlurVals pivals = {
50.0,
SEED_TIME,
0,
1.0,
};
typedef struct {
gint run;
} BlurInterface;
static BlurInterface blur_int = {
FALSE /* have we run? */
};
/*********************************
*
* LOCAL FUNCTIONS
*
********************************/
static void query(void);
static void run(
char *name,
int nparams,
GParam *param,
int *nreturn_vals,
GParam **return_vals);
GParam **return_vals
);
static void blur (GDrawable *drawable);
static void blur_prepare_row (GPixelRgn *pixel_rgn,
guchar *data,
int x,
int y,
int w);
GPlugInInfo PLUG_IN_INFO =
{
GPlugInInfo PLUG_IN_INFO = {
NULL, /* init_proc */
NULL, /* quit_proc */
query, /* query_proc */
run, /* run_proc */
};
static void blur(GDrawable *drawable);
MAIN ()
static inline void blur_prepare_row(
GPixelRgn *pixel_rgn,
guchar *data,
int x,
int y,
int w
);
static gint blur_dialog();
static void blur_ok_callback(
GtkWidget *widget,
gpointer data
);
/************************************ Guts ***********************************/
MAIN()
/*********************************
*
* query() - query_proc
*
* called by the GIMP to learn about this plug-in
*
********************************/
static void
query ()
query()
{
static GParamDef args[] =
{
{ PARAM_INT32, "run_mode", "Interactive, non-interactive" },
static GParamDef args_ni[] = {
{ PARAM_INT32, "run_mode", "non-interactive" },
{ PARAM_IMAGE, "image", "Input image (unused)" },
{ PARAM_DRAWABLE, "drawable", "Input drawable" },
};
static int nargs_ni = sizeof(args_ni) / sizeof (args_ni[0]);
static GParamDef args[] = {
{ PARAM_INT32, "run_mode", "Interactive, non-interactive" },
{ PARAM_IMAGE, "image", "Input image (unused)" },
{ PARAM_DRAWABLE, "drawable", "Input drawable" },
{ PARAM_FLOAT, "blur_pct", "Randomization percentage (1 - 100)" },
{ PARAM_FLOAT, "blur_rcount", "Repeat count(1 - 100)" },
};
static int nargs = sizeof(args) / sizeof (args[0]);
static GParamDef *return_vals = NULL;
static int nargs = sizeof (args) / sizeof (args[0]);
static int nreturn_vals = 0;
gimp_install_procedure ("plug_in_blur",
"Blur the contents of the specified drawable",
"This function applies a 3x3 blurring convolution kernel to the specified drawable.",
"Spencer Kimball & Peter Mattis",
"Spencer Kimball & Peter Mattis",
"1995-1996",
const char *blurb = "Apply a 3x3 blurring convolution kernel to the specified drawable.";
const char *help = "This function randomly blurs the specified drawable, using a 3x3 blur. The type and percentage are user selectable. Blurring is not supported for indexed images.";
const char *author = "Miles O'Neal <meo@rru.com> http://www.rru.com/~meo/";
const char *copyrights = "Miles O'Neal, Spencer Kimball, Peter Mattis, Torsten Martinsen, Brian Degenhardt, Federico Mena Quintero, Stephen Norris, Daniel Cotting";
const char *copyright_date = "1995-1998";
gimp_install_procedure("plug_in_blur_randomize",
(char *) blurb,
(char *) help,
(char *) author,
(char *) copyrights,
(char *) copyright_date,
"<Image>/Filters/Blur/Blur",
"RGB*, GRAY*",
PROC_PLUG_IN,
nargs, nreturn_vals,
args, return_vals);
gimp_install_procedure(PLUG_IN_NAME,
(char *) blurb,
(char *) help,
(char *) author,
(char *) copyrights,
(char *) copyright_date,
NULL,
"RGB*, GRAY*",
PROC_PLUG_IN,
nargs_ni, nreturn_vals,
args_ni, return_vals);
}
/*********************************
*
* run() - main routine
*
* This handles the main interaction with the GIMP itself,
* and invokes the routine that actually does the work.
*
********************************/
static void
run (char *name,
int nparams,
GParam *param,
int *nreturn_vals,
run(char *name, int nparams, GParam *param, int *nreturn_vals,
GParam **return_vals)
{
static GParam values[1];
GDrawable *drawable;
GRunModeType run_mode;
GStatusType status = STATUS_SUCCESS;
GStatusType status = STATUS_SUCCESS; /* assume the best! */
char prog_label[32];
static GParam values[1];
/*
* Get the specified drawable, do standard initialization.
*/
run_mode = param[0].data.d_int32;
/* Get the specified drawable */
drawable = gimp_drawable_get (param[2].data.d_drawable);
/* Make sure that the drawable is gray or RGB color */
if (gimp_drawable_color (drawable->id) || gimp_drawable_gray (drawable->id))
{
gimp_progress_init ("blur");
gimp_tile_cache_ntiles (2 * (drawable->width / gimp_tile_width () + 1));
blur (drawable);
if (run_mode != RUN_NONINTERACTIVE)
gimp_displays_flush ();
}
else
{
/* gimp_message ("blur: cannot operate on indexed color images"); */
status = STATUS_EXECUTION_ERROR;
}
*nreturn_vals = 1;
*return_vals = values;
drawable = gimp_drawable_get(param[2].data.d_drawable);
values[0].type = PARAM_STATUS;
values[0].data.d_status = status;
*nreturn_vals = 1;
*return_vals = values;
/*
* Make sure the drawable type is appropriate.
*/
if (gimp_drawable_color(drawable->id) ||
gimp_drawable_gray(drawable->id)) {
gimp_drawable_detach (drawable);
switch (run_mode) {
/*
* If we're running interactively, pop up the dialog box.
*/
case RUN_INTERACTIVE:
gimp_get_data(PLUG_IN_NAME, &pivals);
if (!blur_dialog()) /* return on Cancel */
return;
break;
/*
* If we're not interactive (probably scripting), we
* get the parameters from the param[] array, since
* we don't use the dialog box. Make sure all
* parameters have legitimate values.
*/
case RUN_NONINTERACTIVE:
if ((strcmp(name, "plug_in_blur_randomize") == 0) &&
(nparams == 5)) {
pivals.blur_pct = (gdouble)param[3].data.d_float;
pivals.blur_pct = (gdouble)MIN(100.0, pivals.blur_pct);
pivals.blur_pct = (gdouble)MAX(1.0, pivals.blur_pct);
pivals.blur_rcount = (gdouble)param[4].data.d_float;
pivals.blur_rcount = (gdouble)MIN(100.0,pivals.blur_rcount);
pivals.blur_rcount = (gdouble)MAX(1.0, pivals.blur_rcount);
status = STATUS_SUCCESS;
} else if ((strcmp(name, PLUG_IN_NAME) == 0) &&
(nparams == 3)) {
pivals.blur_pct = (gdouble) 100.0;
pivals.blur_rcount = (gdouble) 1.0;
status = STATUS_SUCCESS;
} else {
status = STATUS_CALLING_ERROR;
}
break;
/*
* If we're running with the last set of values, get those values.
*/
case RUN_WITH_LAST_VALS:
gimp_get_data(PLUG_IN_NAME, &pivals);
break;
/*
* Hopefully we never get here!
*/
default:
break;
}
if (status == STATUS_SUCCESS) {
/*
* JUST DO IT!
*/
strcpy(prog_label, BLUR_VERSION);
gimp_progress_init(prog_label);
gimp_tile_cache_ntiles(2 * (drawable->width / gimp_tile_width() + 1));
/*
* Initialize the rand() function seed
*/
if (pivals.seed_type == SEED_TIME)
srand(time(NULL));
else
srand(pivals.blur_seed);
blur(drawable);
/*
* If we ran interactively (even repeating) update the display.
*/
if (run_mode != RUN_NONINTERACTIVE) {
gimp_displays_flush();
}
/*
* If we use the dialog popup, set the data for future use.
*/
if (run_mode == RUN_INTERACTIVE) {
gimp_set_data(PLUG_IN_NAME, &pivals, sizeof(BlurVals));
}
}
} else {
/*
* If we got the wrong drawable type, we need to complain.
*/
status = STATUS_EXECUTION_ERROR;
}
/*
* DONE!
* Set the status where the GIMP can see it, and let go
* of the drawable.
*/
values[0].data.d_status = status;
gimp_drawable_detach(drawable);
}
static void
blur_prepare_row (GPixelRgn *pixel_rgn,
guchar *data,
int x,
int y,
int w)
/*********************************
*
* blur_prepare_row()
*
* Get a row of pixels. If the requested row
* is off the edge, clone the edge row.
*
********************************/
static inline void
blur_prepare_row(GPixelRgn *pixel_rgn, guchar *data, int x, int y, int w)
{
int b;
if (y == 0)
gimp_pixel_rgn_get_row (pixel_rgn, data, x, (y + 1), w);
else if (y == pixel_rgn->h)
gimp_pixel_rgn_get_row (pixel_rgn, data, x, (y - 1), w);
else
gimp_pixel_rgn_get_row (pixel_rgn, data, x, y, w);
/* Fill in edge pixels */
for (b = 0; b < pixel_rgn->bpp; b++)
{
if (y == 0) {
gimp_pixel_rgn_get_row(pixel_rgn, data, x, (y + 1), w);
} else if (y == pixel_rgn->h) {
gimp_pixel_rgn_get_row(pixel_rgn, data, x, (y - 1), w);
} else {
gimp_pixel_rgn_get_row(pixel_rgn, data, x, y, w);
}
/*
* Fill in edge pixels
*/
for (b = 0; b < pixel_rgn->bpp; b++) {
data[-(gint)pixel_rgn->bpp + b] = data[b];
data[w * pixel_rgn->bpp + b] = data[(w - 1) * pixel_rgn->bpp + b];
}
}
/*********************************
*
* blur()
*
* Actually mess with the image.
*
********************************/
static void
blur (GDrawable *drawable)
blur(GDrawable *drawable)
{
GPixelRgn srcPR, destPR;
GPixelRgn srcPR, destPR, destPR2, *sp, *dp, *tp;
gint width, height;
gint bytes;
guchar *dest, *d;
@ -151,64 +389,80 @@ blur (GDrawable *drawable)
guchar *tmp;
gint row, col;
gint x1, y1, x2, y2;
gint cnt;
gint has_alpha, ind;
/* Get the input area. This is the bounding box of the selection in
/*
* Get the input area. This is the bounding box of the selection in
* the image (or the entire image if there is no selection). Only
* operating on the input area is simply an optimization. It doesn't
* need to be done for correct operation. (It simply makes it go
* faster, since fewer pixels need to be operated on).
*/
gimp_drawable_mask_bounds (drawable->id, &x1, &y1, &x2, &y2);
/* Get the size of the input image. (This will/must be the same
* as the size of the output image.
gimp_drawable_mask_bounds(drawable->id, &x1, &y1, &x2, &y2);
/*
* Get the size of the input image. (This will/must be the same
* as the size of the output image. Also get alpha info.
*/
width = drawable->width;
height = drawable->height;
bytes = drawable->bpp;
has_alpha = gimp_drawable_has_alpha(drawable->id);
/*
* allocate row buffers
*/
prev_row = (guchar *) malloc((x2 - x1 + 2) * bytes);
cur_row = (guchar *) malloc((x2 - x1 + 2) * bytes);
next_row = (guchar *) malloc((x2 - x1 + 2) * bytes);
dest = (guchar *) malloc((x2 - x1) * bytes);
/* allocate row buffers */
prev_row = (guchar *) malloc ((x2 - x1 + 2) * bytes);
cur_row = (guchar *) malloc ((x2 - x1 + 2) * bytes);
next_row = (guchar *) malloc ((x2 - x1 + 2) * bytes);
dest = (guchar *) malloc ((x2 - x1) * bytes);
/* initialize the pixel regions */
gimp_pixel_rgn_init (&srcPR, drawable, 0, 0, width, height, FALSE, FALSE);
gimp_pixel_rgn_init (&destPR, drawable, 0, 0, width, height, TRUE, TRUE);
/*
* initialize the pixel regions
*/
gimp_pixel_rgn_init(&srcPR, drawable, 0, 0, width, height, FALSE, FALSE);
gimp_pixel_rgn_init(&destPR, drawable, 0, 0, width, height, TRUE, TRUE);
gimp_pixel_rgn_init(&destPR2, drawable, 0, 0, width, height, TRUE, TRUE);
sp = &srcPR;
dp = &destPR;
tp = NULL;
pr = prev_row + bytes;
cr = cur_row + bytes;
nr = next_row + bytes;
blur_prepare_row (&srcPR, pr, x1, y1 - 1, (x2 - x1));
blur_prepare_row (&srcPR, cr, x1, y1, (x2 - x1));
/* loop through the rows, applying the blur convolution */
for (row = y1; row < y2; row++)
{
for (cnt = 1; cnt <= pivals.blur_rcount; cnt++) {
/*
* prepare the first row and previous row
*/
blur_prepare_row(sp, pr, x1, y1 - 1, (x2 - x1));
blur_prepare_row(dp, cr, x1, y1, (x2 - x1));
/*
* loop through the rows, applying the selected convolution
*/
for (row = y1; row < y2; row++) {
/* prepare the next row */
blur_prepare_row (&srcPR, nr, x1, row + 1, (x2 - x1));
blur_prepare_row(sp, nr, x1, row + 1, (x2 - x1));
d = dest;
ind = 0;
for (col = 0; col < (x2 - x1) * bytes; col++)
{
for (col = 0; col < (x2 - x1) * bytes; col++) {
if (((rand() % 100)) <= (gint) pivals.blur_pct) {
ind++;
if (ind==bytes || !(has_alpha))
{ /* we always do the alpha channel,
or if there's none we have no problem
so the algorithm stays the same */
*d++ = ((gint) pr[col - bytes] + (gint) pr[col] + (gint) pr[col + bytes] +
(gint) cr[col - bytes] + (gint) cr[col] + (gint) cr[col + bytes] +
(gint) nr[col - bytes] + (gint) nr[col] + (gint) nr[col + bytes]) / 9;
ind=0;
}
else { /* we have an alpha channel picture, and do the color part here */
if (ind==bytes || !(has_alpha)) {
/*
* If no alpha channel, or if there is one and this is it...
*/
*d++ = ((gint) pr[col - bytes] + (gint) pr[col] +
(gint) pr[col + bytes] +
(gint) cr[col - bytes] + (gint) cr[col] +
(gint) cr[col + bytes] +
(gint) nr[col - bytes] + (gint) nr[col] +
(gint) nr[col + bytes]) / 9;
ind = 0;
} else {
/*
* otherwise we have an alpha channel, but this is a color channel
*/
*d++ = ((gint) (((gdouble) (pr[col - bytes] * pr[col - ind])
+ (gdouble) (pr[col] * pr[col + bytes - ind])
+ (gdouble) (pr[col + bytes] * pr[col + 2*bytes - ind])
@ -228,27 +482,203 @@ blur (GDrawable *drawable)
+ (gdouble) nr[col + bytes - ind]
+ (gdouble) nr[col + 2*bytes - ind])));
}
/*
* Otherwise, this pixel was not selected for randomization,
* so use the current value.
*/
} else {
*d++ = (gint) cr[col];
}
/* store the dest */
gimp_pixel_rgn_set_row (&destPR, dest, x1, row, (x2 - x1));
}
/*
* Save the modified row, shuffle the row pointers, and every
* so often, update the progress meter.
*/
gimp_pixel_rgn_set_row(dp, dest, x1, row, (x2 - x1));
/* shuffle the row pointers */
tmp = pr;
pr = cr;
cr = nr;
nr = tmp;
if ((row % 5) == 0)
gimp_progress_update ((double) row / (double) (y2 - y1));
if (PROG_UPDATE_TIME)
gimp_progress_update((double) row / (double) (y2 - y1));
}
/*
* if we have more cycles to perform, swap the src and dest Pixel Regions
*/
if (cnt < pivals.blur_rcount) {
if (tp != NULL) {
tp = dp;
dp = sp;
sp = tp;
} else {
tp = &srcPR;
sp = &destPR;
dp = &destPR2;
}
}
}
gimp_progress_update((double) 100);
/*
* update the blurred region
*/
gimp_drawable_flush(drawable);
gimp_drawable_merge_shadow(drawable->id, TRUE);
gimp_drawable_update(drawable->id, x1, y1, (x2 - x1), (y2 - y1));
/*
* clean up after ourselves.
*/
free(prev_row);
free(cur_row);
free(next_row);
free(dest);
}
/*********************************
*
* GUI ROUTINES
*
********************************/
/*********************************
*
* blur_dialog() - set up the plug-in's dialog box
*
********************************/
static gint
blur_dialog()
{
GtkWidget *dlg, *entry, *frame,
*seed_hbox, *seed_vbox, *table;
GSList *seed_group = NULL;
gchar **argv;
gint argc;
gchar buffer[10];
/*
* various initializations
*/
gint do_time = (pivals.seed_type == SEED_TIME);
gint do_user = (pivals.seed_type == SEED_USER);
argc = 1;
argv = g_new(gchar *, 1);
argv[0] = g_strdup("blur");
gtk_init(&argc, &argv);
gtk_rc_parse(gimp_gtkrc());
/*
* Open a new dialog, label it and set up its
* destroy callback.
*/
dlg = gtk_dialog_new();
gtk_window_set_title(GTK_WINDOW(dlg), BLUR_VERSION);
gtk_window_position(GTK_WINDOW(dlg), GTK_WIN_POS_MOUSE);
gtk_signal_connect(GTK_OBJECT(dlg), "destroy",
(GtkSignalFunc) gpc_close_callback, NULL);
/*
* Parameter settings
*
* First set up the basic containers, label them, etc.
*/
frame = gtk_frame_new("Parameter Settings");
gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_ETCHED_IN);
gtk_container_border_width(GTK_CONTAINER(frame), 10);
gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dlg)->vbox), frame, TRUE, TRUE, 0);
table = gtk_table_new(4, 2, FALSE);
gtk_container_border_width(GTK_CONTAINER(table), 10);
gtk_container_add(GTK_CONTAINER(frame), table);
gtk_widget_show(table);
gpc_setup_tooltips(table);
/*
* Action area OK & Cancel buttons
*/
gpc_add_action_button("OK", (GtkSignalFunc) blur_ok_callback, dlg,
"Accept settings and apply filter to image");
gpc_add_action_button("Cancel", (GtkSignalFunc) gpc_cancel_callback, dlg,
"Close plug-in without making any changes");
/*
* Randomization seed initialization controls
*/
gpc_add_label("Randomization Seed:", table, 0, 1, 1, 2);
/*
* Box to hold seed initialization radio buttons
*/
seed_vbox = gtk_vbox_new(FALSE, 2);
gtk_container_border_width(GTK_CONTAINER(seed_vbox), 5);
gtk_table_attach(GTK_TABLE(table), seed_vbox, 1, 2, 1, 2,
GTK_FILL | GTK_EXPAND, GTK_FILL, 5, 0);
/*
* Time button
*/
gpc_add_radio_button(&seed_group, "Current Time", seed_vbox, &do_time,
"Seed random number generator from the current time - this guarantees a reasonable randomization");
/*
* Box to hold seed user initialization controls
*/
seed_hbox = gtk_hbox_new(FALSE, 3);
gtk_container_border_width(GTK_CONTAINER(seed_hbox), 0);
gtk_box_pack_start(GTK_BOX(seed_vbox), seed_hbox, FALSE, FALSE, 0);
/*
* User button
*/
gpc_add_radio_button(&seed_group, "Other Value", seed_hbox, &do_user,
"Enable user-entered value for random number generator seed - this allows you to repeat a given \"random\" operation");
/*
* Randomization seed number (text)
*/
entry = gtk_entry_new();
gtk_widget_set_usize(entry, ENTRY_WIDTH, 0);
gtk_box_pack_start(GTK_BOX(seed_hbox), entry, FALSE, FALSE, 0);
sprintf(buffer, "%d", pivals.blur_seed);
gtk_entry_set_text(GTK_ENTRY(entry), buffer);
gtk_signal_connect(GTK_OBJECT(entry), "changed",
(GtkSignalFunc) gpc_text_update, &pivals.blur_seed);
gtk_widget_show(entry);
gpc_set_tooltip(entry, "Value for seeding the random number generator");
gtk_widget_show(seed_hbox);
/*
* Randomization percentage label & scale (1 to 100)
*/
gpc_add_label("Randomization %:", table, 0, 1, 2, 3);
gpc_add_hscale(table, SCALE_WIDTH,
1.0, 100.0, &pivals.blur_pct, 1, 2, 2, 3,
"Percentage of pixels to be filtered");
/*
* Repeat count label & scale (1 to 100)
*/
gpc_add_label("Repeat:", table, 0, 1, 3, 4);
gpc_add_hscale(table, SCALE_WIDTH,
1.0, 100.0, &pivals.blur_rcount, 1, 2, 3, 4,
"Number of times to apply filter");
/*
* Display everything.
*/
gtk_widget_show(frame);
gtk_widget_show(dlg);
gtk_main();
gdk_flush();
/*
* Figure out which type of seed initialization to apply.
*/
if (do_time) {
pivals.seed_type = SEED_TIME;
} else {
pivals.seed_type = SEED_USER;
}
/* update the blurred region */
gimp_drawable_flush (drawable);
gimp_drawable_merge_shadow (drawable->id, TRUE);
gimp_drawable_update (drawable->id, x1, y1, (x2 - x1), (y2 - y1));
free (prev_row);
free (cur_row);
free (next_row);
free (dest);
return blur_int.run;
}
static void
blur_ok_callback(GtkWidget *widget, gpointer data) {
blur_int.run = TRUE;
gtk_widget_destroy(GTK_WIDGET(data));
}

View File

@ -1,5 +1,15 @@
/* The GIMP -- an image manipulation program
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
/****************************************************************************
* This is a plugin for the GIMP v 0.99.8 or later. Documentation is
* available at http://www.rru.com/~meo/gimp/ .
*
* Copyright (C) 1997 Miles O'Neal <meo@rru.com> http://www.rru.com/~meo/
* Blur code Copyright (C) 1995 Spencer Kimball and Peter Mattis
* GUI based on GTK code from:
* alienmap (Copyright (C) 1996, 1997 Daniel Cotting)
* plasma (Copyright (C) 1996 Stephen Norris),
* oilify (Copyright (C) 1996 Torsten Martinsen),
* ripple (Copyright (C) 1997 Brian Degenhardt) and
* whirl (Copyright (C) 1997 Federico Mena Quintero).
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -14,134 +24,362 @@
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <stdlib.h>
#include "libgimp/gimp.h"
*
****************************************************************************/
/* Declare local functions.
/****************************************************************************
* Blur:
*
* blur version 2.0 (6 Feb 1998, MEO)
* history
* 2.0 - 6 Feb 1998 MEO
* based on randomize 1.5
*
* Please send any patches or suggestions to the author: meo@rru.com .
*
* Blur applies a 3x3 blurring convolution kernel to the specified drawable.
*
* For each pixel in the selection or image,
* whether to change the pixel is decided by picking a
* random number, weighted by the user's "randomization" percentage.
* If the random number is in range, the pixel is modified. For
* blurring, an average is determined from the current and adjacent
* pixels. *(Except for the random factor, the blur code came
* straight from the original S&P blur plug-in.)*
*
* This works only with RGB and grayscale images.
*
****************************************************************************/
#include <stdlib.h>
#include <time.h>
#include "libgimp/gimp.h"
#include "gtk/gtk.h"
#include <plug-ins/gpc/gpc.h>
/*********************************
*
* PLUGIN-SPECIFIC CONSTANTS
*
********************************/
/*
* progress meter update frequency
*/
static void query (void);
static void run (char *name,
#define PROG_UPDATE_TIME ((row % 10) == 0)
#define PLUG_IN_NAME "plug_in_blur"
#define BLUR_VERSION "Blur 2.0"
#define SEED_TIME 10
#define SEED_USER 11
#define ENTRY_WIDTH 75
#define SCALE_WIDTH 100
/*********************************
*
* PLUGIN-SPECIFIC STRUCTURES AND DATA
*
********************************/
typedef struct {
gdouble blur_pct; /* likelihood of randomization (as %age) */
gint seed_type; /* seed init. type - current time or user value */
gint blur_seed; /* seed value for rand() function */
gdouble blur_rcount; /* repeat count */
} BlurVals;
static BlurVals pivals = {
50.0,
SEED_TIME,
0,
1.0,
};
typedef struct {
gint run;
} BlurInterface;
static BlurInterface blur_int = {
FALSE /* have we run? */
};
/*********************************
*
* LOCAL FUNCTIONS
*
********************************/
static void query(void);
static void run(
char *name,
int nparams,
GParam *param,
int *nreturn_vals,
GParam **return_vals);
GParam **return_vals
);
static void blur (GDrawable *drawable);
static void blur_prepare_row (GPixelRgn *pixel_rgn,
guchar *data,
int x,
int y,
int w);
GPlugInInfo PLUG_IN_INFO =
{
GPlugInInfo PLUG_IN_INFO = {
NULL, /* init_proc */
NULL, /* quit_proc */
query, /* query_proc */
run, /* run_proc */
};
static void blur(GDrawable *drawable);
MAIN ()
static inline void blur_prepare_row(
GPixelRgn *pixel_rgn,
guchar *data,
int x,
int y,
int w
);
static gint blur_dialog();
static void blur_ok_callback(
GtkWidget *widget,
gpointer data
);
/************************************ Guts ***********************************/
MAIN()
/*********************************
*
* query() - query_proc
*
* called by the GIMP to learn about this plug-in
*
********************************/
static void
query ()
query()
{
static GParamDef args[] =
{
{ PARAM_INT32, "run_mode", "Interactive, non-interactive" },
static GParamDef args_ni[] = {
{ PARAM_INT32, "run_mode", "non-interactive" },
{ PARAM_IMAGE, "image", "Input image (unused)" },
{ PARAM_DRAWABLE, "drawable", "Input drawable" },
};
static int nargs_ni = sizeof(args_ni) / sizeof (args_ni[0]);
static GParamDef args[] = {
{ PARAM_INT32, "run_mode", "Interactive, non-interactive" },
{ PARAM_IMAGE, "image", "Input image (unused)" },
{ PARAM_DRAWABLE, "drawable", "Input drawable" },
{ PARAM_FLOAT, "blur_pct", "Randomization percentage (1 - 100)" },
{ PARAM_FLOAT, "blur_rcount", "Repeat count(1 - 100)" },
};
static int nargs = sizeof(args) / sizeof (args[0]);
static GParamDef *return_vals = NULL;
static int nargs = sizeof (args) / sizeof (args[0]);
static int nreturn_vals = 0;
gimp_install_procedure ("plug_in_blur",
"Blur the contents of the specified drawable",
"This function applies a 3x3 blurring convolution kernel to the specified drawable.",
"Spencer Kimball & Peter Mattis",
"Spencer Kimball & Peter Mattis",
"1995-1996",
const char *blurb = "Apply a 3x3 blurring convolution kernel to the specified drawable.";
const char *help = "This function randomly blurs the specified drawable, using a 3x3 blur. The type and percentage are user selectable. Blurring is not supported for indexed images.";
const char *author = "Miles O'Neal <meo@rru.com> http://www.rru.com/~meo/";
const char *copyrights = "Miles O'Neal, Spencer Kimball, Peter Mattis, Torsten Martinsen, Brian Degenhardt, Federico Mena Quintero, Stephen Norris, Daniel Cotting";
const char *copyright_date = "1995-1998";
gimp_install_procedure("plug_in_blur_randomize",
(char *) blurb,
(char *) help,
(char *) author,
(char *) copyrights,
(char *) copyright_date,
"<Image>/Filters/Blur/Blur",
"RGB*, GRAY*",
PROC_PLUG_IN,
nargs, nreturn_vals,
args, return_vals);
gimp_install_procedure(PLUG_IN_NAME,
(char *) blurb,
(char *) help,
(char *) author,
(char *) copyrights,
(char *) copyright_date,
NULL,
"RGB*, GRAY*",
PROC_PLUG_IN,
nargs_ni, nreturn_vals,
args_ni, return_vals);
}
/*********************************
*
* run() - main routine
*
* This handles the main interaction with the GIMP itself,
* and invokes the routine that actually does the work.
*
********************************/
static void
run (char *name,
int nparams,
GParam *param,
int *nreturn_vals,
run(char *name, int nparams, GParam *param, int *nreturn_vals,
GParam **return_vals)
{
static GParam values[1];
GDrawable *drawable;
GRunModeType run_mode;
GStatusType status = STATUS_SUCCESS;
GStatusType status = STATUS_SUCCESS; /* assume the best! */
char prog_label[32];
static GParam values[1];
/*
* Get the specified drawable, do standard initialization.
*/
run_mode = param[0].data.d_int32;
/* Get the specified drawable */
drawable = gimp_drawable_get (param[2].data.d_drawable);
/* Make sure that the drawable is gray or RGB color */
if (gimp_drawable_color (drawable->id) || gimp_drawable_gray (drawable->id))
{
gimp_progress_init ("blur");
gimp_tile_cache_ntiles (2 * (drawable->width / gimp_tile_width () + 1));
blur (drawable);
if (run_mode != RUN_NONINTERACTIVE)
gimp_displays_flush ();
}
else
{
/* gimp_message ("blur: cannot operate on indexed color images"); */
status = STATUS_EXECUTION_ERROR;
}
*nreturn_vals = 1;
*return_vals = values;
drawable = gimp_drawable_get(param[2].data.d_drawable);
values[0].type = PARAM_STATUS;
values[0].data.d_status = status;
*nreturn_vals = 1;
*return_vals = values;
/*
* Make sure the drawable type is appropriate.
*/
if (gimp_drawable_color(drawable->id) ||
gimp_drawable_gray(drawable->id)) {
gimp_drawable_detach (drawable);
switch (run_mode) {
/*
* If we're running interactively, pop up the dialog box.
*/
case RUN_INTERACTIVE:
gimp_get_data(PLUG_IN_NAME, &pivals);
if (!blur_dialog()) /* return on Cancel */
return;
break;
/*
* If we're not interactive (probably scripting), we
* get the parameters from the param[] array, since
* we don't use the dialog box. Make sure all
* parameters have legitimate values.
*/
case RUN_NONINTERACTIVE:
if ((strcmp(name, "plug_in_blur_randomize") == 0) &&
(nparams == 5)) {
pivals.blur_pct = (gdouble)param[3].data.d_float;
pivals.blur_pct = (gdouble)MIN(100.0, pivals.blur_pct);
pivals.blur_pct = (gdouble)MAX(1.0, pivals.blur_pct);
pivals.blur_rcount = (gdouble)param[4].data.d_float;
pivals.blur_rcount = (gdouble)MIN(100.0,pivals.blur_rcount);
pivals.blur_rcount = (gdouble)MAX(1.0, pivals.blur_rcount);
status = STATUS_SUCCESS;
} else if ((strcmp(name, PLUG_IN_NAME) == 0) &&
(nparams == 3)) {
pivals.blur_pct = (gdouble) 100.0;
pivals.blur_rcount = (gdouble) 1.0;
status = STATUS_SUCCESS;
} else {
status = STATUS_CALLING_ERROR;
}
break;
/*
* If we're running with the last set of values, get those values.
*/
case RUN_WITH_LAST_VALS:
gimp_get_data(PLUG_IN_NAME, &pivals);
break;
/*
* Hopefully we never get here!
*/
default:
break;
}
if (status == STATUS_SUCCESS) {
/*
* JUST DO IT!
*/
strcpy(prog_label, BLUR_VERSION);
gimp_progress_init(prog_label);
gimp_tile_cache_ntiles(2 * (drawable->width / gimp_tile_width() + 1));
/*
* Initialize the rand() function seed
*/
if (pivals.seed_type == SEED_TIME)
srand(time(NULL));
else
srand(pivals.blur_seed);
blur(drawable);
/*
* If we ran interactively (even repeating) update the display.
*/
if (run_mode != RUN_NONINTERACTIVE) {
gimp_displays_flush();
}
/*
* If we use the dialog popup, set the data for future use.
*/
if (run_mode == RUN_INTERACTIVE) {
gimp_set_data(PLUG_IN_NAME, &pivals, sizeof(BlurVals));
}
}
} else {
/*
* If we got the wrong drawable type, we need to complain.
*/
status = STATUS_EXECUTION_ERROR;
}
/*
* DONE!
* Set the status where the GIMP can see it, and let go
* of the drawable.
*/
values[0].data.d_status = status;
gimp_drawable_detach(drawable);
}
static void
blur_prepare_row (GPixelRgn *pixel_rgn,
guchar *data,
int x,
int y,
int w)
/*********************************
*
* blur_prepare_row()
*
* Get a row of pixels. If the requested row
* is off the edge, clone the edge row.
*
********************************/
static inline void
blur_prepare_row(GPixelRgn *pixel_rgn, guchar *data, int x, int y, int w)
{
int b;
if (y == 0)
gimp_pixel_rgn_get_row (pixel_rgn, data, x, (y + 1), w);
else if (y == pixel_rgn->h)
gimp_pixel_rgn_get_row (pixel_rgn, data, x, (y - 1), w);
else
gimp_pixel_rgn_get_row (pixel_rgn, data, x, y, w);
/* Fill in edge pixels */
for (b = 0; b < pixel_rgn->bpp; b++)
{
if (y == 0) {
gimp_pixel_rgn_get_row(pixel_rgn, data, x, (y + 1), w);
} else if (y == pixel_rgn->h) {
gimp_pixel_rgn_get_row(pixel_rgn, data, x, (y - 1), w);
} else {
gimp_pixel_rgn_get_row(pixel_rgn, data, x, y, w);
}
/*
* Fill in edge pixels
*/
for (b = 0; b < pixel_rgn->bpp; b++) {
data[-(gint)pixel_rgn->bpp + b] = data[b];
data[w * pixel_rgn->bpp + b] = data[(w - 1) * pixel_rgn->bpp + b];
}
}
/*********************************
*
* blur()
*
* Actually mess with the image.
*
********************************/
static void
blur (GDrawable *drawable)
blur(GDrawable *drawable)
{
GPixelRgn srcPR, destPR;
GPixelRgn srcPR, destPR, destPR2, *sp, *dp, *tp;
gint width, height;
gint bytes;
guchar *dest, *d;
@ -151,64 +389,80 @@ blur (GDrawable *drawable)
guchar *tmp;
gint row, col;
gint x1, y1, x2, y2;
gint cnt;
gint has_alpha, ind;
/* Get the input area. This is the bounding box of the selection in
/*
* Get the input area. This is the bounding box of the selection in
* the image (or the entire image if there is no selection). Only
* operating on the input area is simply an optimization. It doesn't
* need to be done for correct operation. (It simply makes it go
* faster, since fewer pixels need to be operated on).
*/
gimp_drawable_mask_bounds (drawable->id, &x1, &y1, &x2, &y2);
/* Get the size of the input image. (This will/must be the same
* as the size of the output image.
gimp_drawable_mask_bounds(drawable->id, &x1, &y1, &x2, &y2);
/*
* Get the size of the input image. (This will/must be the same
* as the size of the output image. Also get alpha info.
*/
width = drawable->width;
height = drawable->height;
bytes = drawable->bpp;
has_alpha = gimp_drawable_has_alpha(drawable->id);
/*
* allocate row buffers
*/
prev_row = (guchar *) malloc((x2 - x1 + 2) * bytes);
cur_row = (guchar *) malloc((x2 - x1 + 2) * bytes);
next_row = (guchar *) malloc((x2 - x1 + 2) * bytes);
dest = (guchar *) malloc((x2 - x1) * bytes);
/* allocate row buffers */
prev_row = (guchar *) malloc ((x2 - x1 + 2) * bytes);
cur_row = (guchar *) malloc ((x2 - x1 + 2) * bytes);
next_row = (guchar *) malloc ((x2 - x1 + 2) * bytes);
dest = (guchar *) malloc ((x2 - x1) * bytes);
/* initialize the pixel regions */
gimp_pixel_rgn_init (&srcPR, drawable, 0, 0, width, height, FALSE, FALSE);
gimp_pixel_rgn_init (&destPR, drawable, 0, 0, width, height, TRUE, TRUE);
/*
* initialize the pixel regions
*/
gimp_pixel_rgn_init(&srcPR, drawable, 0, 0, width, height, FALSE, FALSE);
gimp_pixel_rgn_init(&destPR, drawable, 0, 0, width, height, TRUE, TRUE);
gimp_pixel_rgn_init(&destPR2, drawable, 0, 0, width, height, TRUE, TRUE);
sp = &srcPR;
dp = &destPR;
tp = NULL;
pr = prev_row + bytes;
cr = cur_row + bytes;
nr = next_row + bytes;
blur_prepare_row (&srcPR, pr, x1, y1 - 1, (x2 - x1));
blur_prepare_row (&srcPR, cr, x1, y1, (x2 - x1));
/* loop through the rows, applying the blur convolution */
for (row = y1; row < y2; row++)
{
for (cnt = 1; cnt <= pivals.blur_rcount; cnt++) {
/*
* prepare the first row and previous row
*/
blur_prepare_row(sp, pr, x1, y1 - 1, (x2 - x1));
blur_prepare_row(dp, cr, x1, y1, (x2 - x1));
/*
* loop through the rows, applying the selected convolution
*/
for (row = y1; row < y2; row++) {
/* prepare the next row */
blur_prepare_row (&srcPR, nr, x1, row + 1, (x2 - x1));
blur_prepare_row(sp, nr, x1, row + 1, (x2 - x1));
d = dest;
ind = 0;
for (col = 0; col < (x2 - x1) * bytes; col++)
{
for (col = 0; col < (x2 - x1) * bytes; col++) {
if (((rand() % 100)) <= (gint) pivals.blur_pct) {
ind++;
if (ind==bytes || !(has_alpha))
{ /* we always do the alpha channel,
or if there's none we have no problem
so the algorithm stays the same */
*d++ = ((gint) pr[col - bytes] + (gint) pr[col] + (gint) pr[col + bytes] +
(gint) cr[col - bytes] + (gint) cr[col] + (gint) cr[col + bytes] +
(gint) nr[col - bytes] + (gint) nr[col] + (gint) nr[col + bytes]) / 9;
ind=0;
}
else { /* we have an alpha channel picture, and do the color part here */
if (ind==bytes || !(has_alpha)) {
/*
* If no alpha channel, or if there is one and this is it...
*/
*d++ = ((gint) pr[col - bytes] + (gint) pr[col] +
(gint) pr[col + bytes] +
(gint) cr[col - bytes] + (gint) cr[col] +
(gint) cr[col + bytes] +
(gint) nr[col - bytes] + (gint) nr[col] +
(gint) nr[col + bytes]) / 9;
ind = 0;
} else {
/*
* otherwise we have an alpha channel, but this is a color channel
*/
*d++ = ((gint) (((gdouble) (pr[col - bytes] * pr[col - ind])
+ (gdouble) (pr[col] * pr[col + bytes - ind])
+ (gdouble) (pr[col + bytes] * pr[col + 2*bytes - ind])
@ -228,27 +482,203 @@ blur (GDrawable *drawable)
+ (gdouble) nr[col + bytes - ind]
+ (gdouble) nr[col + 2*bytes - ind])));
}
/*
* Otherwise, this pixel was not selected for randomization,
* so use the current value.
*/
} else {
*d++ = (gint) cr[col];
}
/* store the dest */
gimp_pixel_rgn_set_row (&destPR, dest, x1, row, (x2 - x1));
}
/*
* Save the modified row, shuffle the row pointers, and every
* so often, update the progress meter.
*/
gimp_pixel_rgn_set_row(dp, dest, x1, row, (x2 - x1));
/* shuffle the row pointers */
tmp = pr;
pr = cr;
cr = nr;
nr = tmp;
if ((row % 5) == 0)
gimp_progress_update ((double) row / (double) (y2 - y1));
if (PROG_UPDATE_TIME)
gimp_progress_update((double) row / (double) (y2 - y1));
}
/*
* if we have more cycles to perform, swap the src and dest Pixel Regions
*/
if (cnt < pivals.blur_rcount) {
if (tp != NULL) {
tp = dp;
dp = sp;
sp = tp;
} else {
tp = &srcPR;
sp = &destPR;
dp = &destPR2;
}
}
}
gimp_progress_update((double) 100);
/*
* update the blurred region
*/
gimp_drawable_flush(drawable);
gimp_drawable_merge_shadow(drawable->id, TRUE);
gimp_drawable_update(drawable->id, x1, y1, (x2 - x1), (y2 - y1));
/*
* clean up after ourselves.
*/
free(prev_row);
free(cur_row);
free(next_row);
free(dest);
}
/*********************************
*
* GUI ROUTINES
*
********************************/
/*********************************
*
* blur_dialog() - set up the plug-in's dialog box
*
********************************/
static gint
blur_dialog()
{
GtkWidget *dlg, *entry, *frame,
*seed_hbox, *seed_vbox, *table;
GSList *seed_group = NULL;
gchar **argv;
gint argc;
gchar buffer[10];
/*
* various initializations
*/
gint do_time = (pivals.seed_type == SEED_TIME);
gint do_user = (pivals.seed_type == SEED_USER);
argc = 1;
argv = g_new(gchar *, 1);
argv[0] = g_strdup("blur");
gtk_init(&argc, &argv);
gtk_rc_parse(gimp_gtkrc());
/*
* Open a new dialog, label it and set up its
* destroy callback.
*/
dlg = gtk_dialog_new();
gtk_window_set_title(GTK_WINDOW(dlg), BLUR_VERSION);
gtk_window_position(GTK_WINDOW(dlg), GTK_WIN_POS_MOUSE);
gtk_signal_connect(GTK_OBJECT(dlg), "destroy",
(GtkSignalFunc) gpc_close_callback, NULL);
/*
* Parameter settings
*
* First set up the basic containers, label them, etc.
*/
frame = gtk_frame_new("Parameter Settings");
gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_ETCHED_IN);
gtk_container_border_width(GTK_CONTAINER(frame), 10);
gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dlg)->vbox), frame, TRUE, TRUE, 0);
table = gtk_table_new(4, 2, FALSE);
gtk_container_border_width(GTK_CONTAINER(table), 10);
gtk_container_add(GTK_CONTAINER(frame), table);
gtk_widget_show(table);
gpc_setup_tooltips(table);
/*
* Action area OK & Cancel buttons
*/
gpc_add_action_button("OK", (GtkSignalFunc) blur_ok_callback, dlg,
"Accept settings and apply filter to image");
gpc_add_action_button("Cancel", (GtkSignalFunc) gpc_cancel_callback, dlg,
"Close plug-in without making any changes");
/*
* Randomization seed initialization controls
*/
gpc_add_label("Randomization Seed:", table, 0, 1, 1, 2);
/*
* Box to hold seed initialization radio buttons
*/
seed_vbox = gtk_vbox_new(FALSE, 2);
gtk_container_border_width(GTK_CONTAINER(seed_vbox), 5);
gtk_table_attach(GTK_TABLE(table), seed_vbox, 1, 2, 1, 2,
GTK_FILL | GTK_EXPAND, GTK_FILL, 5, 0);
/*
* Time button
*/
gpc_add_radio_button(&seed_group, "Current Time", seed_vbox, &do_time,
"Seed random number generator from the current time - this guarantees a reasonable randomization");
/*
* Box to hold seed user initialization controls
*/
seed_hbox = gtk_hbox_new(FALSE, 3);
gtk_container_border_width(GTK_CONTAINER(seed_hbox), 0);
gtk_box_pack_start(GTK_BOX(seed_vbox), seed_hbox, FALSE, FALSE, 0);
/*
* User button
*/
gpc_add_radio_button(&seed_group, "Other Value", seed_hbox, &do_user,
"Enable user-entered value for random number generator seed - this allows you to repeat a given \"random\" operation");
/*
* Randomization seed number (text)
*/
entry = gtk_entry_new();
gtk_widget_set_usize(entry, ENTRY_WIDTH, 0);
gtk_box_pack_start(GTK_BOX(seed_hbox), entry, FALSE, FALSE, 0);
sprintf(buffer, "%d", pivals.blur_seed);
gtk_entry_set_text(GTK_ENTRY(entry), buffer);
gtk_signal_connect(GTK_OBJECT(entry), "changed",
(GtkSignalFunc) gpc_text_update, &pivals.blur_seed);
gtk_widget_show(entry);
gpc_set_tooltip(entry, "Value for seeding the random number generator");
gtk_widget_show(seed_hbox);
/*
* Randomization percentage label & scale (1 to 100)
*/
gpc_add_label("Randomization %:", table, 0, 1, 2, 3);
gpc_add_hscale(table, SCALE_WIDTH,
1.0, 100.0, &pivals.blur_pct, 1, 2, 2, 3,
"Percentage of pixels to be filtered");
/*
* Repeat count label & scale (1 to 100)
*/
gpc_add_label("Repeat:", table, 0, 1, 3, 4);
gpc_add_hscale(table, SCALE_WIDTH,
1.0, 100.0, &pivals.blur_rcount, 1, 2, 3, 4,
"Number of times to apply filter");
/*
* Display everything.
*/
gtk_widget_show(frame);
gtk_widget_show(dlg);
gtk_main();
gdk_flush();
/*
* Figure out which type of seed initialization to apply.
*/
if (do_time) {
pivals.seed_type = SEED_TIME;
} else {
pivals.seed_type = SEED_USER;
}
/* update the blurred region */
gimp_drawable_flush (drawable);
gimp_drawable_merge_shadow (drawable->id, TRUE);
gimp_drawable_update (drawable->id, x1, y1, (x2 - x1), (y2 - y1));
free (prev_row);
free (cur_row);
free (next_row);
free (dest);
return blur_int.run;
}
static void
blur_ok_callback(GtkWidget *widget, gpointer data) {
blur_int.run = TRUE;
gtk_widget_destroy(GTK_WIDGET(data));
}

View File

@ -3,7 +3,6 @@
* available at http://www.rru.com/~meo/gimp/ .
*
* Copyright (C) 1997 Miles O'Neal <meo@rru.com> http://www.rru.com/~meo/
* Blur code Copyright (C) 1995 Spencer Kimball and Peter Mattis
* GUI based on GTK code from:
* alienmap (Copyright (C) 1996, 1997 Daniel Cotting)
* plasma (Copyright (C) 1996 Stephen Norris),
@ -30,8 +29,12 @@
/****************************************************************************
* Randomize:
*
* randomize version 1.4 (3 Feb 1998, MEO)
* randomize version 1.6 (29 Apr 1998, MEO)
* history
* 1.6 - 29 Apr 1998 MEO
* moved blur to separate plugin (blur 2.0)
* 1.5 - 5 Feb 1998 MEO
* added alpha layer handling to blur code
* 1.4 - 3 Feb 1998 MEO
* added details to PDB parameter help strings
* 1.3 - 3 Feb 1998 MEO
@ -88,7 +91,6 @@
* This plug-in adds a user-defined amount of randomization to an
* image. Variations include:
*
* - blurring
* - hurling (spewing random colors)
* - picking a nearby pixel at random
* - slurring (a crude form of melting)
@ -96,10 +98,7 @@
* In any case, for each pixel in the selection or image,
* whether to change the pixel is decided by picking a
* random number, weighted by the user's "randomization" percentage.
* If the random number is in range, the pixel is modified. For
* blurring, an average is determined from the current and adjacent
* pixels. *(Except for the random factor, the blur code came
* straight from the original S&P blur plug-in.)* Picking
* If the random number is in range, the pixel is modified. Picking
* one selects the new pixel value at random from the current and
* adjacent pixels. Hurling assigns a random value to the pixel.
* Slurring sort of melts downwards; if a pixel is to be slurred,
@ -107,10 +106,7 @@
* of the pixels adjacent to the one above is used (even odds as
* to which it will be).
*
* Picking, hurling and slurring work with any image type. Blurring
* works only with RGB and grayscale images. If randomize is
* run against an indexed image, "blur" is not presented as an
* option.
* Picking, hurling and slurring work with any image type.
*
* This plug-in's effectiveness varies a lot with the type
* and clarity of the image being "randomized".
@ -131,7 +127,7 @@
#include <time.h>
#include "libgimp/gimp.h"
#include "gtk/gtk.h"
#include "gpc.h"
#include <plug-ins/gpc/gpc.h>
/*********************************
*
@ -146,12 +142,11 @@
#define PROG_UPDATE_TIME ((row % 10) == 0)
#define PLUG_IN_NAME "plug_in_randomize"
#define RNDM_VERSION "Randomize 1.4"
#define RNDM_VERSION "Randomize 1.6"
#define RNDM_BLUR 1
#define RNDM_HURL 2
#define RNDM_PICK 3
#define RNDM_SLUR 4
#define RNDM_HURL 1
#define RNDM_PICK 2
#define RNDM_SLUR 3
#define SEED_TIME 10
#define SEED_USER 11
@ -174,7 +169,7 @@ typedef struct {
} RandomizeVals;
static RandomizeVals pivals = {
RNDM_BLUR,
RNDM_HURL,
50.0,
SEED_TIME,
0,
@ -189,7 +184,6 @@ static RandomizeInterface rndm_int = {
FALSE /* have we run? */
};
static gint is_indexed_drawable = FALSE;
/*********************************
*
@ -251,7 +245,7 @@ query()
{ PARAM_IMAGE, "image", "Input image (unused)" },
{ PARAM_DRAWABLE, "drawable", "Input drawable" },
{ PARAM_INT32, "rndm_type",
"Randomization type (1=blur 2=hurl 3=pick 4=slur)" },
"Randomization type (1=hurl 2=pick 3=slur)" },
{ PARAM_FLOAT, "rndm_pct", "Randomization percentage (1 - 100)" },
{ PARAM_FLOAT, "rndm_rcount", "Repeat count(1 - 100)" },
};
@ -259,8 +253,8 @@ query()
static int nargs = sizeof(args) / sizeof (args[0]);
static int nreturn_vals = 0;
const char *blurb = "Add a random factor to the image, by blurring, picking a nearby pixel, slurring (similar to melting), or just hurling on it.";
const char *help = "This function randomly ``blurs'' the specified drawable, using either a 3x3 blur, picking a nearby pixel, slurring (cheezy melting), or hurling (spewing colors). The type and percentage are user selectable. Blurring is not supported for indexed images.";
const char *blurb = "Add a random factor to the image, by picking a nearby pixel, slurring (similar to melting), or just hurling on it.";
const char *help = "This function randomly modified the drawable, either by picking a nearby pixel, slurring (cheezy melting), or hurling (spewing colors). The type and percentage are user selectable.";
const char *author = "Miles O'Neal <meo@rru.com> http://www.rru.com/~meo/";
const char *copyrights = "Miles O'Neal, Spencer Kimball, Peter Mattis, Torsten Martinsen, Brian Degenhardt, Federico Mena Quintero, Stephen Norris, Daniel Cotting";
const char *copyright_date = "1995-1997";
@ -278,21 +272,6 @@ query()
args, return_vals);
}
/*
* If it's indexed and the current action is BLUR,
* use something else. PICK seems the likeliest
* candidate, although in the spirit of randomity
* we could pick one at random!
*/
void
fix_index_blur(GDrawable *drawable) {
if (gimp_drawable_indexed(drawable->id)) {
is_indexed_drawable = TRUE;
if (pivals.rndm_type == RNDM_BLUR) {
pivals.rndm_type = RNDM_PICK;
}
}
}
/*********************************
@ -337,7 +316,6 @@ run(char *name, int nparams, GParam *param, int *nreturn_vals,
* If we're running interactively, pop up the dialog box.
*/
case RUN_INTERACTIVE:
fix_index_blur(drawable);
gimp_get_data(PLUG_IN_NAME, &pivals);
if (!randomize_dialog()) /* return on Cancel */
return;
@ -349,7 +327,6 @@ run(char *name, int nparams, GParam *param, int *nreturn_vals,
* parameters have legitimate values.
*/
case RUN_NONINTERACTIVE:
fix_index_blur(drawable);
if (nparams != 6) {
status = STATUS_CALLING_ERROR;
}
@ -360,7 +337,6 @@ run(char *name, int nparams, GParam *param, int *nreturn_vals,
}
if (status == STATUS_SUCCESS &&
((pivals.rndm_type != RNDM_PICK &&
pivals.rndm_type != RNDM_BLUR &&
pivals.rndm_type != RNDM_SLUR &&
pivals.rndm_type != RNDM_HURL) ||
(pivals.rndm_pct < 1.0 || pivals.rndm_pct > 100.0) ||
@ -385,7 +361,6 @@ run(char *name, int nparams, GParam *param, int *nreturn_vals,
* JUST DO IT!
*/
switch (pivals.rndm_type) {
case RNDM_BLUR: rndm_type_str = "blur"; break;
case RNDM_HURL: rndm_type_str = "hurl"; break;
case RNDM_PICK: rndm_type_str = "pick"; break;
case RNDM_SLUR: rndm_type_str = "slur"; break;
@ -482,6 +457,7 @@ randomize(GDrawable *drawable)
gint row, col;
gint x1, y1, x2, y2;
gint cnt;
gint has_alpha, ind;
/*
* Get the input area. This is the bounding box of the selection in
@ -493,11 +469,12 @@ randomize(GDrawable *drawable)
gimp_drawable_mask_bounds(drawable->id, &x1, &y1, &x2, &y2);
/*
* Get the size of the input image. (This will/must be the same
* as the size of the output image.
* as the size of the output image. Also get alpha info.
*/
width = drawable->width;
height = drawable->height;
bytes = drawable->bpp;
has_alpha = gimp_drawable_has_alpha(drawable->id);
/*
* allocate row buffers
*/
@ -534,21 +511,10 @@ randomize(GDrawable *drawable)
randomize_prepare_row(sp, nr, x1, row + 1, (x2 - x1));
d = dest;
ind = 0;
for (col = 0; col < (x2 - x1) * bytes; col++) {
if (((rand() % 100)) <= (gint) pivals.rndm_pct) {
switch (pivals.rndm_type) {
/*
* BLUR
* Use the average of the neighboring pixels.
*/
case RNDM_BLUR:
*d++ = ((gint) pr[col - bytes] + (gint) pr[col] +
(gint) pr[col + bytes] +
(gint) cr[col - bytes] + (gint) cr[col] +
(gint) cr[col + bytes] +
(gint) nr[col - bytes] + (gint) nr[col] +
(gint) nr[col + bytes]) / 9;
break;
/*
* HURL
* Just assign a random value.
@ -690,7 +656,6 @@ randomize_dialog()
/*
* various initializations
*/
gint do_blur = (pivals.rndm_type == RNDM_BLUR);
gint do_pick = (pivals.rndm_type == RNDM_PICK);
gint do_hurl = (pivals.rndm_type == RNDM_HURL);
gint do_slur = (pivals.rndm_type == RNDM_SLUR);
@ -731,10 +696,10 @@ randomize_dialog()
/*
* Action area OK & Cancel buttons
*/
gpc_add_action_button("OK", (GtkSignalFunc) randomize_ok_callback, dlg
/* , "Accept settings and apply filter to image" */);
gpc_add_action_button("Cancel", (GtkSignalFunc) gpc_cancel_callback, dlg
/* , "Close plug-in without making any changes" */);
gpc_add_action_button("OK", (GtkSignalFunc) randomize_ok_callback, dlg,
"Accept settings and apply filter to image");
gpc_add_action_button("Cancel", (GtkSignalFunc) gpc_cancel_callback, dlg,
"Close plug-in without making any changes");
/*
* Randomization Type - label & radio buttons
*/
@ -744,14 +709,6 @@ randomize_dialog()
gtk_container_border_width(GTK_CONTAINER(toggle_hbox), 5);
gtk_table_attach(GTK_TABLE(table), toggle_hbox, 1, 2, 0, 1,
GTK_FILL | GTK_EXPAND, GTK_FILL, 5, 0);
/*
* Blur button (won't work with indexed - if the drawable is indexed,
* don't allow blur as an option)
*/
if (! is_indexed_drawable) {
gpc_add_radio_button(&type_group, "Blur", toggle_hbox, &do_blur,
"Blur each pixel by averaging its value with those of its neighbors");
}
/*
* Hurl, Pick and Slur buttons
*/
@ -828,9 +785,7 @@ randomize_dialog()
/*
* Figure out which type of randomization to apply.
*/
if (do_blur) {
pivals.rndm_type = RNDM_BLUR;
} else if (do_pick) {
if (do_pick) {
pivals.rndm_type = RNDM_PICK;
} else if (do_slur) {
pivals.rndm_type = RNDM_SLUR;

6
plug-ins/gpc/.cvsignore Normal file
View File

@ -0,0 +1,6 @@
Makefile.in
Makefile
.deps
_libs
.libs
gpc

41
plug-ins/gpc/Makefile.am Normal file
View File

@ -0,0 +1,41 @@
## Process this file with automake to produce Makefile.in
pluginlibdir = $(gimpplugindir)/plug-ins
pluginlib_LIBRARIES = libgpc.a
libgpc_a_SOURCES = \
gpc.c gpc.h
INCLUDES = \
$(X_CFLAGS) \
-I$(top_srcdir) \
-I$(includedir)
LDADD = \
$(top_builddir)/libgimp/libgimpui.la \
$(top_builddir)/libgimp/libgimp.la \
$(X_LIBS) \
-lc
DEPS = \
$(top_builddir)/libgimp/libgimpui.la \
$(top_builddir)/libgimp/libgimp.la
libgpc_aDEPENDENCIES = $(DEPS)
man_MANS=gpc.3
.PHONY: files
files:
@files=`ls $(DISTFILES) 2> /dev/null`; for p in $$files; do \
echo $$p; \
done
@for subdir in $(SUBDIRS); do \
files=`cd $$subdir; $(MAKE) files | grep -v "make\[[1-9]\]"`; \
for file in $$files; do \
echo $$subdir/$$file; \
done; \
done

293
plug-ins/gpc/gpc.3 Normal file
View File

@ -0,0 +1,293 @@
.TH gpc 3 "30 Apr 1998" "Roadkills-R-Us" "Gimp Plug-ins"
.\"Copyright 1997-8, Roadkills-R-Us, Austin, TX, USA. All rights reserved.
.\"
.\" gpc version 1.4
.de Ss
.sp
.ft CW
.nf
..
.de Se
.fi
.ft P
.sp
..
.SH NAME
GPC \- GTK Plug-in Convenience library
.SH SYNOPSIS
.Ss
#include <plug-ins/gpc/gpc.h>
.Se
.Ss
void gpc_setup_tooltips(GtkWidget *parent);
.Se
Initialize tooltips interface, set colors.
.Ss
void gpc_set_tooltip(GtkWidget *widget, const char *tip);
.Se
Set tooltip for a widget (if tip is non-null).
.Ss
void gpc_add_action_button(char *label,
GtkSignalFunc callback, GtkWidget *dialog, char *tip);
.Se
Add action button (with tooltip) to a dialog.
.Ss
void gpc_add_radio_button(GSList **group, char *label,
GtkWidget *box, gint *value, char *tip);
.Se
Add radio button (with tooltip) to a dialog.
.Ss
void gpc_add_hscale(GtkWidget *table, int width,
float low, float high, gdouble *val,
int left, int right, int top, int bottom, char *tip);
.Se
Add horizontal scale widget (with tooltip) to a dialog at given location.
.Ss
void gpc_add_label(char *value, GtkWidget *parent,
int left, int right, int top, int bottom);
.Se
Add label widget (no tooltip) to a dialog at given location.
.Ss
void gpc_close_callback(GtkWidget *widget, gpointer data);
.Se
Destroy callback - quit this plug-in.
.Ss
void gpc_cancel_callback(GtkWidget *widget, gpointer data);
.Se
Cancel button callback - go away without saving state, etc.
.Ss
void gpc_scale_update(GtkAdjustment *adjustment, double *scale_val);
.Se
Scale update callback - update the SCALE widget's data.
.Ss
void gpc_text_update(GtkWidget *widget, gpointer data);
.Se
Text update callback - update the TEXT widget's data.
.SH DESCRIPTION
This is a set of routines to make life easier on plug-in writers.
It helps keep the GUI code short and sweet. (In the plug-in for
which it was originally designed, it cut the GUI code in half.)
It's somewhat arbitrary in what it includes so far, because I
haven't needed everything in GTK. Feel free to contribute more
to it.
.SS TOOLTIPS ROUTINES
.B gpc_setup_tooltips()
must be called first. This initializes internal data
structures and sets the tooltip colors. It can be called
with any widget high enough in the hierarchy to contain
all the widgets needing tooltips. Typically this will be
the container widget under the top-level frame:
.nf
Example:
frame = gtk_frame_new("Parameter Settings");
:
gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dlg)->vbox),
frame, TRUE, TRUE, 0);
table = gtk_table_new(4, 2, FALSE);
:
gtk_widget_show(table);
gpc_setup_tooltips(table);
.fi
.PP
.B gpc_set_tooltip()
may be called directly, but is usually called inside other convenience
functions. If called directly, it must still be after the call to
gpc_setup_tooltips(). It hides a lot of detail of the GTK tooltips:
.nf
Example:
gtk_widget_show(button);
gpc_set_tooltip(button, tip);
.fi
.SS USER INTERFACE ROUTINES
These routines all hide implementation details to make it
easier to lay out a GUI with a consitent, gimp-style interface,
while keeping the plug-in code cleaner.
.PP
.B gpc_add_action_button()
adds an action button (such as [Cancel]
or [OK] to the action button area of a frame. The
.I callback
argument has the standard GTK callback interface. A standard
callback is provided for [Cancel] buttons if you wish to use it.
.PP
Usage:
.nf
void
gpc_add_action_button(
char *label, /* text for action button */
GtkSignalFunc callback, /* callback function address */
GtkWidget *dialog, /* dialog widget to contain button */
char *tip /* tooltip text */
)
Example:
static void
randomize_ok_callback(GtkWidget *widget, gpointer data) {
rndm_int.run = TRUE;
gtk_widget_destroy(GTK_WIDGET(data));
}
:
gpc_add_action_button("OK",
(GtkSignalFunc) randomize_ok_callback, dlg,
"Accept settings and apply filter to image");
gpc_add_action_button("Cancel",
(GtkSignalFunc) gpc_cancel_callback, dlg,
"Close plug-in without making any changes");
.fi
.PP
.B gpc_add_radio_button()
adds a radio button. If the radio group does not exist,
it will be created and passed back in the
.I group
argument. A standard callback will be attached to the radio
button, requiring a state variable which you provide via the
.I value
argument.
.nf
Usage:
void
gpc_add_radio_button(
GSList **group, /* address of radio group */
char *label, /* label for new radio button */
GtkWidget *box, /* radio box for this radio button */
gint *value, /* address of state variable */
char *tip /* tooltip text */
)
Example:
GSList *type_group = NULL;
:
gpc_add_label("Randomization Type:", table, 0, 1, 0, 1);
toggle_hbox = gtk_hbox_new(FALSE, 5);
gtk_container_border_width(GTK_CONTAINER(toggle_hbox), 5);
gtk_table_attach(GTK_TABLE(table), toggle_hbox, 1, 2, 0, 1,
GTK_FILL | GTK_EXPAND, GTK_FILL, 5, 0);
gpc_add_radio_button(&type_group,
"Hurl", toggle_hbox, &do_hurl,
"Hurl random colors onto pixels");
gpc_add_radio_button(&type_group,
"Pick", toggle_hbox, &do_pick,
"Pick at random from neighboring pixels");
gpc_add_radio_button(&type_group,
"Slur", toggle_hbox, &do_slur,
"Simplistic melt");
.fi
.PP
.B gpc_add_hscale()
adds a horizontal scale to a table container at the designated coordinates.
A standard callback will be attached to the scale,
requiring a state variable which you provide via the
.I value
argument.
.nf
Usage:
void
gpc_add_hscale(
GtkWidget *table, /* table widget to hold scale */
int width, /* width (in pixels) of scale */
float low, /* low value for scale */
float high, /* high value for scale */
gdouble *value, /* pointer to current value */
int left, /* left table position info */
int right, /* right table position info */
int top, /* top table position info */
int bottom, /* bottom table position info */
char *tip /* tooltip text */
)
Example:
gpc_add_label("Randomization %:", table, 0, 1, 2, 3);
gpc_add_hscale(table, SCALE_WIDTH,
1.0, 100.0, &pivals.rndm_pct, 1, 2, 2, 3,
"Percentage of pixels to be filtered");
.fi
.PP
.B gpc_add_label()
simply adds a label at the designated coordinates in the table.
Labels don't get tooltips.
.nf
Usage:
void
gpc_add_label(
char *value, /* text for new label */
GtkWidget *table, /* table widget to hold label */
int left, /* left table position info */
int right, /* right table position info */
int top, /* top table position info */
int bottom /* bottom table position info */
)
Example:
gpc_add_label("Randomization %:", table, 0, 1, 2, 3);
.fi
.SS CALLBACKS:
.B gpc_close_callback()
is used in OK callbacks, and anywhere else
you need a callback to destroy widgets.
The default cancel callback,
.B gpc_cancel_callback()
simply closes (destroys) the current panel.
The
.B gpc_scale_update()
and
.B gpc_text_update()
callbacks update the appropriate widget's data from
that widget.
.DIAGNOSTICS
No special diagnostics are provided.
.SH BUGS
This software should be 100% Bug-Free [tm].
.SH AUTHOR
Miles O'Neal
.br
<meo@rru.com>
.br
http://www.rru.com/~meo/
.br
Leander, TX
.br
Additionally, some of the code may have been distilled from
the following plug-ins:
.I alienmap
(Copyright (C) 1996, 1997 Daniel Cotting)
.I plasma
(Copyright (C) 1996 Stephen Norris),
.I oilify
(Copyright (C) 1996 Torsten Martinsen),
.I ripple
(Copyright (C) 1997 Brian Degenhardt) and
.I whirl
(Copyright (C) 1997 Federico Mena Quintero).

View File

@ -2,9 +2,8 @@
* This is a convenience library for plugins for the GIMP v 0.99.8 or later.
* Documentation is available at http://www.rru.com/~meo/gimp/ .
*
* Copyright (C) 1997 Miles O'Neal <meo@rru.com> http://www.rru.com/~meo/
* Blur code Copyright (C) 1995 Spencer Kimball and Peter Mattis
* GUI based on GTK code from:
* Copyright (C) 1997, 1998 Miles O'Neal <meo@rru.com> http://www.rru.com/~meo/
* GUI may include GTK code from:
* alienmap (Copyright (C) 1996, 1997 Daniel Cotting)
* plasma (Copyright (C) 1996 Stephen Norris),
* oilify (Copyright (C) 1996 Torsten Martinsen),
@ -28,10 +27,16 @@
****************************************************************************/
/****************************************************************************
* gpc:
* gpc: GTK Plug-in Convenience library
*
* gpc version 1.1 (3 Feb 1998, MEO)
* history
* 1.4 - 30 Apr 1998 MEO
* added man page
* 1.3 - 29 Apr 1998 MEO
* GTK 1.0 port (minor tooltips change)
* restored tooltips to action buttons
* 1.2 - 11 Feb 1998 MEO
* added basic comments
* 1.1 - 3 Feb 1998 MEO
* removed tooltips from action buttons
* 1.0 - 2 Feb 1998 MEO
@ -48,7 +53,7 @@
/*
* TOGGLE UPDATE callback
* TOGGLE UPDATE callback - toggles the TOGGLE widget's data
*/
static void
gpc_toggle_update(GtkWidget *widget, gpointer data) {
@ -62,7 +67,7 @@ gpc_toggle_update(GtkWidget *widget, gpointer data) {
*toggle_val = FALSE;
}
/*
* DESTROY callback
* DESTROY callback - quit this plug-in
*/
void
gpc_close_callback(GtkWidget *widget, gpointer data) {
@ -70,7 +75,7 @@ gpc_close_callback(GtkWidget *widget, gpointer data) {
}
/*
* CANCEL BUTTON callback
* CANCEL BUTTON callback - go away without saving state, etc.
*/
void
gpc_cancel_callback(GtkWidget *widget, gpointer data) {
@ -78,7 +83,7 @@ gpc_cancel_callback(GtkWidget *widget, gpointer data) {
}
/*
* SCALE UPDATE callback
* SCALE UPDATE callback - update the SCALE widget's data
*/
void
gpc_scale_update(GtkAdjustment *adjustment, double *scale_val) {
@ -87,7 +92,7 @@ gpc_scale_update(GtkAdjustment *adjustment, double *scale_val) {
/*
* TEXT UPDATE callback
* TEXT UPDATE callback - update the TEXT widget's data
*/
void
gpc_text_update(GtkWidget *widget, gpointer data) {
@ -106,6 +111,9 @@ gpc_text_update(GtkWidget *widget, gpointer data) {
static GtkTooltips *tips;
/*
* TOOLTIP INITIALIZATION
*/
void
gpc_setup_tooltips(GtkWidget *parent)
{
@ -131,16 +139,23 @@ gpc_setup_tooltips(GtkWidget *parent)
}
/*
* SET TOOLTIP for a widget
*/
void
gpc_set_tooltip(GtkWidget *widget, const char *tip)
{
if (tip && tip[0])
gtk_tooltips_set_tip (tips, widget, (char *) tip,NULL);
gtk_tooltips_set_tip(tips, widget, (char *) tip, NULL);
}
/*
* ADD ACTION BUTTON to a dialog
*/
void
gpc_add_action_button(char *label, GtkSignalFunc callback, GtkWidget *dialog
/* , char *tip */ )
gpc_add_action_button(char *label, GtkSignalFunc callback, GtkWidget *dialog,
char *tip)
{
GtkWidget *button;
@ -151,9 +166,13 @@ gpc_add_action_button(char *label, GtkSignalFunc callback, GtkWidget *dialog
button, TRUE, TRUE, 0);
gtk_widget_grab_default(button);
gtk_widget_show(button);
/* gpc_set_tooltip(button, tip); */
gpc_set_tooltip(button, tip);
}
/*
* ADD RADIO BUTTON to a dialog
*/
void
gpc_add_radio_button(GSList **group, char *label, GtkWidget *box,
gint *value, char *tip)
@ -171,6 +190,10 @@ gpc_add_radio_button(GSList **group, char *label, GtkWidget *box,
gpc_set_tooltip(toggle, tip);
}
/*
* ADD LABEL widget to a dialog at given location
*/
void
gpc_add_label(char *value, GtkWidget *table, int left, int right,
int top, int bottom)
@ -184,6 +207,10 @@ gpc_add_label(char *value, GtkWidget *table, int left, int right,
gtk_widget_show(label);
}
/*
* ADD HORIZONTAL SCALE widget to a dialog at given location
*/
void
gpc_add_hscale(GtkWidget *table, int width, float low, float high,
gdouble *val, int left, int right, int top, int bottom, char *tip)

View File

@ -2,9 +2,8 @@
* This is a convenience library for plugins for the GIMP v 0.99.8 or later.
* Documentation is available at http://www.rru.com/~meo/gimp/ .
*
* Copyright (C) 1997 Miles O'Neal <meo@rru.com> http://www.rru.com/~meo/
* Blur code Copyright (C) 1995 Spencer Kimball and Peter Mattis
* GUI based on GTK code from:
* Copyright (C) 1997, 1998 Miles O'Neal <meo@rru.com> http://www.rru.com/~meo/
* GUI may include GTK code from:
* alienmap (Copyright (C) 1996, 1997 Daniel Cotting)
* plasma (Copyright (C) 1996 Stephen Norris),
* oilify (Copyright (C) 1996 Torsten Martinsen),
@ -28,10 +27,16 @@
****************************************************************************/
/****************************************************************************
* gpc:
* gpc: GTK Plug-in Convenience library
*
* gpc version 1.1 (3 Feb 1998, MEO)
* history
* 1.4 - 30 Apr 1998 MEO
* added man page
* 1.3 - 29 Apr 1998 MEO
* GTK 1.0 port (minor tooltips change)
* restored tooltips to action buttons
* 1.2 - 11 Feb 1998 MEO
* added basic comments
* 1.1 - 3 Feb 1998 MEO
* removed tooltips from action buttons
* 1.0 - 2 Feb 1998 MEO
@ -60,8 +65,8 @@ void
gpc_set_tooltip(GtkWidget *widget, const char *tip);
void
gpc_add_action_button(char *label, GtkSignalFunc callback, GtkWidget *dialog
/* , char *tip */ );
gpc_add_action_button(char *label, GtkSignalFunc callback, GtkWidget *dialog,
char *tip);
void
gpc_add_radio_button(GSList **group, char *label, GtkWidget *box,

330
plug-ins/gpc/gpc.man Normal file
View File

@ -0,0 +1,330 @@
gpc(3) Gimp Plug-ins gpc(3)
NAME
GPC - GTK Plug-in Convenience library
SYNOPSIS
#include <plug-ins/gpc/gpc.h>
void gpc_setup_tooltips(GtkWidget *parent);
Initialize tooltips interface, set colors.
void gpc_set_tooltip(GtkWidget *widget, const char *tip);
Set tooltip for a widget (if tip is non-null).
void gpc_add_action_button(char *label,
GtkSignalFunc callback, GtkWidget *dialog, char *tip);
Add action button (with tooltip) to a dialog.
void gpc_add_radio_button(GSList **group, char *label,
GtkWidget *box, gint *value, char *tip);
Add radio button (with tooltip) to a dialog.
void gpc_add_hscale(GtkWidget *table, int width,
float low, float high, gdouble *val,
int left, int right, int top, int bottom, char *tip);
Add horizontal scale widget (with tooltip) to a dialog at
given location.
void gpc_add_label(char *value, GtkWidget *parent,
int left, int right, int top, int bottom);
Add label widget (no tooltip) to a dialog at given loca-
tion.
void gpc_close_callback(GtkWidget *widget, gpointer data);
Destroy callback - quit this plug-in.
void gpc_cancel_callback(GtkWidget *widget, gpointer data);
Cancel button callback - go away without saving state,
etc.
void gpc_scale_update(GtkAdjustment *adjustment, double *scale_val);
Scale update callback - update the SCALE widget's data.
Roadkills-R-Us 30 Apr 1998 1
gpc(3) Gimp Plug-ins gpc(3)
void gpc_text_update(GtkWidget *widget, gpointer data);
Text update callback - update the TEXT widget's data.
DESCRIPTION
This is a set of routines to make life easier on plug-in
writers. It helps keep the GUI code short and sweet. (In
the plug-in for which it was originally designed, it cut
the GUI code in half.) It's somewhat arbitrary in what it
includes so far, because I haven't needed everything in
GTK. Feel free to contribute more to it.
TOOLTIPS ROUTINES
gpc_setup_tooltips() must be called first. This initial-
izes internal data structures and sets the tooltip colors.
It can be called with any widget high enough in the hier-
archy to contain all the widgets needing tooltips. Typi-
cally this will be the container widget under the top-
level frame:
Example:
frame = gtk_frame_new("Parameter Settings");
:
gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dlg)->vbox),
frame, TRUE, TRUE, 0);
table = gtk_table_new(4, 2, FALSE);
:
gtk_widget_show(table);
gpc_setup_tooltips(table);
gpc_set_tooltip() may be called directly, but is usually
called inside other convenience functions. If called
directly, it must still be after the call to
gpc_setup_tooltips(). It hides a lot of detail of the GTK
tooltips:
Example:
gtk_widget_show(button);
gpc_set_tooltip(button, tip);
USER INTERFACE ROUTINES
These routines all hide implementation details to make it
easier to lay out a GUI with a consitent, gimp-style
interface, while keeping the plug-in code cleaner.
gpc_add_action_button() adds an action button (such as
[Cancel] or [OK] to the action button area of a frame.
Roadkills-R-Us 30 Apr 1998 2
gpc(3) Gimp Plug-ins gpc(3)
The callback argument has the standard GTK callback inter-
face. A standard callback is provided for [Cancel] but-
tons if you wish to use it.
Usage:
void
gpc_add_action_button(
char *label, /* text for action button */
GtkSignalFunc callback, /* callback function address */
GtkWidget *dialog, /* dialog widget to contain button */
char *tip /* tooltip text */
)
Example:
static void
randomize_ok_callback(GtkWidget *widget, gpointer data) {
rndm_int.run = TRUE;
gtk_widget_destroy(GTK_WIDGET(data));
}
:
gpc_add_action_button("OK",
(GtkSignalFunc) randomize_ok_callback, dlg,
"Accept settings and apply filter to image");
gpc_add_action_button("Cancel",
(GtkSignalFunc) gpc_cancel_callback, dlg,
"Close plug-in without making any changes");
gpc_add_radio_button() adds a radio button. If the radio
group does not exist, it will be created and passed back
in the group argument. A standard callback will be
attached to the radio button, requiring a state variable
which you provide via the value argument.
Usage:
void
gpc_add_radio_button(
GSList **group, /* address of radio group */
char *label, /* label for new radio button */
GtkWidget *box, /* radio box for this radio button */
gint *value, /* address of state variable */
char *tip /* tooltip text */
)
Example:
GSList *type_group = NULL;
:
gpc_add_label("Randomization Type:", table, 0, 1, 0, 1);
toggle_hbox = gtk_hbox_new(FALSE, 5);
gtk_container_border_width(GTK_CONTAINER(toggle_hbox), 5);
gtk_table_attach(GTK_TABLE(table), toggle_hbox, 1, 2, 0, 1,
GTK_FILL | GTK_EXPAND, GTK_FILL, 5, 0);
Roadkills-R-Us 30 Apr 1998 3
gpc(3) Gimp Plug-ins gpc(3)
gpc_add_radio_button(&type_group,
"Hurl", toggle_hbox, &do_hurl,
"Hurl random colors onto pixels");
gpc_add_radio_button(&type_group,
"Pick", toggle_hbox, &do_pick,
"Pick at random from neighboring pixels");
gpc_add_radio_button(&type_group,
"Slur", toggle_hbox, &do_slur,
"Simplistic melt");
gpc_add_hscale() adds a horizontal scale to a table con-
tainer at the designated coordinates. A standard callback
will be attached to the scale, requiring a state variable
which you provide via the value argument.
Usage:
void
gpc_add_hscale(
GtkWidget *table, /* table widget to hold scale */
int width, /* width (in pixels) of scale */
float low, /* low value for scale */
float high, /* high value for scale */
gdouble *value, /* pointer to current value */
int left, /* left table position info */
int right, /* right table position info */
int top, /* top table position info */
int bottom, /* bottom table position info */
char *tip /* tooltip text */
)
Example:
gpc_add_label("Randomization %:", table, 0, 1, 2, 3);
gpc_add_hscale(table, SCALE_WIDTH,
1.0, 100.0, &pivals.rndm_pct, 1, 2, 2, 3,
"Percentage of pixels to be filtered");
gpc_add_label() simply adds a label at the designated
coordinates in the table. Labels don't get tooltips.
Usage:
void
gpc_add_label(
char *value, /* text for new label */
GtkWidget *table, /* table widget to hold label */
int left, /* left table position info */
int right, /* right table position info */
int top, /* top table position info */
int bottom /* bottom table position info */
)
Example:
Roadkills-R-Us 30 Apr 1998 4
gpc(3) Gimp Plug-ins gpc(3)
gpc_add_label("Randomization %:", table, 0, 1, 2, 3);
CALLBACKS:
gpc_close_callback() is used in OK callbacks, and anywhere
else you need a callback to destroy widgets. The default
cancel callback, gpc_cancel_callback() simply closes
(destroys) the current panel. The gpc_scale_update() and
gpc_text_update() callbacks update the appropriate wid-
get's data from that widget.
No special diagnostics are provided.
BUGS
This software should be 100% Bug-Free [tm].
AUTHOR
Miles O'Neal
<meo@rru.com>
http://www.rru.com/~meo/
Leander, TX
Additionally, some of the code may have been distilled
from the following plug-ins: alienmap (Copyright (C) 1996,
1997 Daniel Cotting) plasma (Copyright (C) 1996 Stephen
Norris), oilify (Copyright (C) 1996 Torsten Martinsen),
ripple (Copyright (C) 1997 Brian Degenhardt) and whirl
(Copyright (C) 1997 Federico Mena Quintero).
Roadkills-R-Us 30 Apr 1998 5

View File

@ -5,7 +5,7 @@ pluginlibdir = $(gimpplugindir)/plug-ins
pluginlib_PROGRAMS = randomize
randomize_SOURCES = \
randomize.c gpc.c gpc.h
randomize.c $(top_srcdir)/plug-ins/gpc/gpc.h
INCLUDES = \
$(X_CFLAGS) \
@ -13,14 +13,15 @@ INCLUDES = \
-I$(includedir)
LDADD = \
$(top_builddir)/plug-ins/gpc/libgpc.a \
$(top_builddir)/libgimp/libgimpui.la \
$(top_builddir)/libgimp/libgimp.la \
$(X_LIBS) \
\
-lc
DEPS = \
$(top_builddir)/libgimp/libgimpui.la \
$(top_builddir)/plug-ins/gpc/libgpc.a \
$(top_builddir)/libgimp/libgimp.la
randomize_DEPENDENCIES = $(DEPS)

View File

@ -3,7 +3,6 @@
* available at http://www.rru.com/~meo/gimp/ .
*
* Copyright (C) 1997 Miles O'Neal <meo@rru.com> http://www.rru.com/~meo/
* Blur code Copyright (C) 1995 Spencer Kimball and Peter Mattis
* GUI based on GTK code from:
* alienmap (Copyright (C) 1996, 1997 Daniel Cotting)
* plasma (Copyright (C) 1996 Stephen Norris),
@ -30,8 +29,12 @@
/****************************************************************************
* Randomize:
*
* randomize version 1.4 (3 Feb 1998, MEO)
* randomize version 1.6 (29 Apr 1998, MEO)
* history
* 1.6 - 29 Apr 1998 MEO
* moved blur to separate plugin (blur 2.0)
* 1.5 - 5 Feb 1998 MEO
* added alpha layer handling to blur code
* 1.4 - 3 Feb 1998 MEO
* added details to PDB parameter help strings
* 1.3 - 3 Feb 1998 MEO
@ -88,7 +91,6 @@
* This plug-in adds a user-defined amount of randomization to an
* image. Variations include:
*
* - blurring
* - hurling (spewing random colors)
* - picking a nearby pixel at random
* - slurring (a crude form of melting)
@ -96,10 +98,7 @@
* In any case, for each pixel in the selection or image,
* whether to change the pixel is decided by picking a
* random number, weighted by the user's "randomization" percentage.
* If the random number is in range, the pixel is modified. For
* blurring, an average is determined from the current and adjacent
* pixels. *(Except for the random factor, the blur code came
* straight from the original S&P blur plug-in.)* Picking
* If the random number is in range, the pixel is modified. Picking
* one selects the new pixel value at random from the current and
* adjacent pixels. Hurling assigns a random value to the pixel.
* Slurring sort of melts downwards; if a pixel is to be slurred,
@ -107,10 +106,7 @@
* of the pixels adjacent to the one above is used (even odds as
* to which it will be).
*
* Picking, hurling and slurring work with any image type. Blurring
* works only with RGB and grayscale images. If randomize is
* run against an indexed image, "blur" is not presented as an
* option.
* Picking, hurling and slurring work with any image type.
*
* This plug-in's effectiveness varies a lot with the type
* and clarity of the image being "randomized".
@ -131,7 +127,7 @@
#include <time.h>
#include "libgimp/gimp.h"
#include "gtk/gtk.h"
#include "gpc.h"
#include <plug-ins/gpc/gpc.h>
/*********************************
*
@ -146,12 +142,11 @@
#define PROG_UPDATE_TIME ((row % 10) == 0)
#define PLUG_IN_NAME "plug_in_randomize"
#define RNDM_VERSION "Randomize 1.4"
#define RNDM_VERSION "Randomize 1.6"
#define RNDM_BLUR 1
#define RNDM_HURL 2
#define RNDM_PICK 3
#define RNDM_SLUR 4
#define RNDM_HURL 1
#define RNDM_PICK 2
#define RNDM_SLUR 3
#define SEED_TIME 10
#define SEED_USER 11
@ -174,7 +169,7 @@ typedef struct {
} RandomizeVals;
static RandomizeVals pivals = {
RNDM_BLUR,
RNDM_HURL,
50.0,
SEED_TIME,
0,
@ -189,7 +184,6 @@ static RandomizeInterface rndm_int = {
FALSE /* have we run? */
};
static gint is_indexed_drawable = FALSE;
/*********************************
*
@ -251,7 +245,7 @@ query()
{ PARAM_IMAGE, "image", "Input image (unused)" },
{ PARAM_DRAWABLE, "drawable", "Input drawable" },
{ PARAM_INT32, "rndm_type",
"Randomization type (1=blur 2=hurl 3=pick 4=slur)" },
"Randomization type (1=hurl 2=pick 3=slur)" },
{ PARAM_FLOAT, "rndm_pct", "Randomization percentage (1 - 100)" },
{ PARAM_FLOAT, "rndm_rcount", "Repeat count(1 - 100)" },
};
@ -259,8 +253,8 @@ query()
static int nargs = sizeof(args) / sizeof (args[0]);
static int nreturn_vals = 0;
const char *blurb = "Add a random factor to the image, by blurring, picking a nearby pixel, slurring (similar to melting), or just hurling on it.";
const char *help = "This function randomly ``blurs'' the specified drawable, using either a 3x3 blur, picking a nearby pixel, slurring (cheezy melting), or hurling (spewing colors). The type and percentage are user selectable. Blurring is not supported for indexed images.";
const char *blurb = "Add a random factor to the image, by picking a nearby pixel, slurring (similar to melting), or just hurling on it.";
const char *help = "This function randomly modified the drawable, either by picking a nearby pixel, slurring (cheezy melting), or hurling (spewing colors). The type and percentage are user selectable.";
const char *author = "Miles O'Neal <meo@rru.com> http://www.rru.com/~meo/";
const char *copyrights = "Miles O'Neal, Spencer Kimball, Peter Mattis, Torsten Martinsen, Brian Degenhardt, Federico Mena Quintero, Stephen Norris, Daniel Cotting";
const char *copyright_date = "1995-1997";
@ -278,21 +272,6 @@ query()
args, return_vals);
}
/*
* If it's indexed and the current action is BLUR,
* use something else. PICK seems the likeliest
* candidate, although in the spirit of randomity
* we could pick one at random!
*/
void
fix_index_blur(GDrawable *drawable) {
if (gimp_drawable_indexed(drawable->id)) {
is_indexed_drawable = TRUE;
if (pivals.rndm_type == RNDM_BLUR) {
pivals.rndm_type = RNDM_PICK;
}
}
}
/*********************************
@ -337,7 +316,6 @@ run(char *name, int nparams, GParam *param, int *nreturn_vals,
* If we're running interactively, pop up the dialog box.
*/
case RUN_INTERACTIVE:
fix_index_blur(drawable);
gimp_get_data(PLUG_IN_NAME, &pivals);
if (!randomize_dialog()) /* return on Cancel */
return;
@ -349,7 +327,6 @@ run(char *name, int nparams, GParam *param, int *nreturn_vals,
* parameters have legitimate values.
*/
case RUN_NONINTERACTIVE:
fix_index_blur(drawable);
if (nparams != 6) {
status = STATUS_CALLING_ERROR;
}
@ -360,7 +337,6 @@ run(char *name, int nparams, GParam *param, int *nreturn_vals,
}
if (status == STATUS_SUCCESS &&
((pivals.rndm_type != RNDM_PICK &&
pivals.rndm_type != RNDM_BLUR &&
pivals.rndm_type != RNDM_SLUR &&
pivals.rndm_type != RNDM_HURL) ||
(pivals.rndm_pct < 1.0 || pivals.rndm_pct > 100.0) ||
@ -385,7 +361,6 @@ run(char *name, int nparams, GParam *param, int *nreturn_vals,
* JUST DO IT!
*/
switch (pivals.rndm_type) {
case RNDM_BLUR: rndm_type_str = "blur"; break;
case RNDM_HURL: rndm_type_str = "hurl"; break;
case RNDM_PICK: rndm_type_str = "pick"; break;
case RNDM_SLUR: rndm_type_str = "slur"; break;
@ -482,6 +457,7 @@ randomize(GDrawable *drawable)
gint row, col;
gint x1, y1, x2, y2;
gint cnt;
gint has_alpha, ind;
/*
* Get the input area. This is the bounding box of the selection in
@ -493,11 +469,12 @@ randomize(GDrawable *drawable)
gimp_drawable_mask_bounds(drawable->id, &x1, &y1, &x2, &y2);
/*
* Get the size of the input image. (This will/must be the same
* as the size of the output image.
* as the size of the output image. Also get alpha info.
*/
width = drawable->width;
height = drawable->height;
bytes = drawable->bpp;
has_alpha = gimp_drawable_has_alpha(drawable->id);
/*
* allocate row buffers
*/
@ -534,21 +511,10 @@ randomize(GDrawable *drawable)
randomize_prepare_row(sp, nr, x1, row + 1, (x2 - x1));
d = dest;
ind = 0;
for (col = 0; col < (x2 - x1) * bytes; col++) {
if (((rand() % 100)) <= (gint) pivals.rndm_pct) {
switch (pivals.rndm_type) {
/*
* BLUR
* Use the average of the neighboring pixels.
*/
case RNDM_BLUR:
*d++ = ((gint) pr[col - bytes] + (gint) pr[col] +
(gint) pr[col + bytes] +
(gint) cr[col - bytes] + (gint) cr[col] +
(gint) cr[col + bytes] +
(gint) nr[col - bytes] + (gint) nr[col] +
(gint) nr[col + bytes]) / 9;
break;
/*
* HURL
* Just assign a random value.
@ -690,7 +656,6 @@ randomize_dialog()
/*
* various initializations
*/
gint do_blur = (pivals.rndm_type == RNDM_BLUR);
gint do_pick = (pivals.rndm_type == RNDM_PICK);
gint do_hurl = (pivals.rndm_type == RNDM_HURL);
gint do_slur = (pivals.rndm_type == RNDM_SLUR);
@ -731,10 +696,10 @@ randomize_dialog()
/*
* Action area OK & Cancel buttons
*/
gpc_add_action_button("OK", (GtkSignalFunc) randomize_ok_callback, dlg
/* , "Accept settings and apply filter to image" */);
gpc_add_action_button("Cancel", (GtkSignalFunc) gpc_cancel_callback, dlg
/* , "Close plug-in without making any changes" */);
gpc_add_action_button("OK", (GtkSignalFunc) randomize_ok_callback, dlg,
"Accept settings and apply filter to image");
gpc_add_action_button("Cancel", (GtkSignalFunc) gpc_cancel_callback, dlg,
"Close plug-in without making any changes");
/*
* Randomization Type - label & radio buttons
*/
@ -744,14 +709,6 @@ randomize_dialog()
gtk_container_border_width(GTK_CONTAINER(toggle_hbox), 5);
gtk_table_attach(GTK_TABLE(table), toggle_hbox, 1, 2, 0, 1,
GTK_FILL | GTK_EXPAND, GTK_FILL, 5, 0);
/*
* Blur button (won't work with indexed - if the drawable is indexed,
* don't allow blur as an option)
*/
if (! is_indexed_drawable) {
gpc_add_radio_button(&type_group, "Blur", toggle_hbox, &do_blur,
"Blur each pixel by averaging its value with those of its neighbors");
}
/*
* Hurl, Pick and Slur buttons
*/
@ -828,9 +785,7 @@ randomize_dialog()
/*
* Figure out which type of randomization to apply.
*/
if (do_blur) {
pivals.rndm_type = RNDM_BLUR;
} else if (do_pick) {
if (do_pick) {
pivals.rndm_type = RNDM_PICK;
} else if (do_slur) {
pivals.rndm_type = RNDM_SLUR;