Removed all the old plugin files from the plugins dir.

they should all be in sub dirs now.
This commit is contained in:
Adrian Likins 1997-12-06 20:14:46 +00:00
parent f430950e74
commit eb3dda1484
121 changed files with 0 additions and 99307 deletions

View File

@ -1,331 +0,0 @@
/* cel.c -- KISS CEL file format plug-in for The GIMP
* (copyright) 1997 Nick Lamb (njl195@ecs.soton.ac.uk)
*
* Skeleton cloned from Michael Sweet's PNG plug-in. KISS format courtesy
* of the KISS/GS documentation. Problem reports to the above address
*/
/* History:
* 0.1 Very limited functionality (modern 4bit only)
* 0.2 Default palette (nice yellows) is automatically used
* 0.3 Support for the older (pre KISS/GS) cell format
* 0.4 First support for saving images
* Future additions:
* + Automagically or via dialog box choose a KCF palette
* + Save (perhaps optionally?) the palette in a KCF
* + Support offsets -- like GIF?
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <gtk/gtk.h>
#include <libgimp/gimp.h>
#define VERSION "0.4"
static void query(void);
static void run(char *name, int nparams, GParam *param,
int *nreturn_vals, GParam **return_vals);
static gint32 load_image(char *file, char *brief);
static gint save_image(char *file, char *brief,
gint32 image, gint32 layer);
/* Globals... */
GPlugInInfo PLUG_IN_INFO =
{
NULL, /* init_proc */
NULL, /* quit_proc */
query, /* query_proc */
run, /* run_proc */
};
/* Let GIMP library handle initialisation (and inquisitive users) */
int main(int argc, char *argv[]) {
return (gimp_main(argc, argv));
}
/* GIMP queries plug-in for parameters etc. */
static void query(void) {
static GParamDef load_args[] =
{
{ PARAM_INT32, "run_mode", "Interactive, non-interactive" },
{ PARAM_STRING, "filename", "The name of the file to load" },
{ PARAM_STRING, "raw_filename", "The name of the file to load" },
};
static GParamDef load_return_vals[] =
{
{ PARAM_IMAGE, "image", "Output image" },
};
static int nload_args = sizeof (load_args) / sizeof (load_args[0]);
static int nload_return_vals = sizeof (load_return_vals) / sizeof (load_return_vals[0]);
static GParamDef save_args[] =
{
{ PARAM_INT32, "run_mode", "Interactive, non-interactive" },
{ PARAM_IMAGE, "image", "Input image" },
{ PARAM_DRAWABLE, "drawable", "Drawable to save" },
{ PARAM_STRING, "filename", "The name of the file to save the image in" },
{ PARAM_STRING, "raw_filename", "The name of the file to save the image in" },
};
static int nsave_args = sizeof (save_args) / sizeof (save_args[0]);
gimp_install_procedure("file_cel_load",
"Loads files in KISS CEL file format",
"This plug-in loads individual KISS cell files.",
"Nick Lamb", "Nick Lamb", VERSION,
"<Load>/CEL", NULL, PROC_PLUG_IN,
nload_args, nload_return_vals, load_args, load_return_vals);
gimp_register_magic_load_handler("file_cel_load", "cel",
"", "0,string,KiSS");
gimp_install_procedure("file_cel_save",
"Saves files in KISS CEL file format",
"This plug-in saves individual KISS cell files.",
"Nick Lamb", "Nick Lamb", VERSION, "<Save>/CEL", "INDEXED*",
PROC_PLUG_IN, nsave_args, 0, save_args, NULL);
gimp_register_save_handler("file_cel_save", "cel", "");
}
static void run(char *name, int nparams, GParam *param,
int *nreturn_vals, GParam **return_vals) {
gint32 image; /* image ID after load */
gint status; /* status after save */
static GParam values[2]; /* Return values */
/* Set up default return values */
values[0].type = PARAM_STATUS;
values[0].data.d_status = STATUS_SUCCESS;
*nreturn_vals = 1;
*return_vals = values;
if (strcmp(name, "file_cel_load") == 0) {
image = load_image(param[1].data.d_string, param[2].data.d_string);
if (image != -1) {
*nreturn_vals = 2;
values[1].type = PARAM_IMAGE;
values[1].data.d_image = image;
} else {
values[0].data.d_status = STATUS_EXECUTION_ERROR;
}
} else if (strcmp (name, "file_cel_save") == 0) {
save_image(param[3].data.d_string, param[4].data.d_string,
param[1].data.d_int32, param[2].data.d_int32);
} else {
values[0].data.d_status = STATUS_EXECUTION_ERROR;
}
}
/* Load CEL image into The GIMP */
static gint32 load_image(char *file, char *brief) {
FILE* fp; /* Read file pointer */
char progress[255]; /* Title for progress display */
guchar header[32]; /* File header */
int height, width, /* Dimensions of image */
colours; /* Number of colours */
gint32 image, /* Image */
layer; /* Layer */
guchar *palette, /* 24 bit palette */
*buffer, /* Temporary buffer */
*line; /* Pixel data */
GDrawable *drawable; /* Drawable for layer */
GPixelRgn pixel_rgn; /* Pixel region for layer */
int i, j, k; /* Counters */
/* Open the file for reading */
fp = fopen(file, "r");
sprintf(progress, "Loading %s:", brief);
gimp_progress_init(progress);
/* Get the image dimensions and create the image... */
fread(header, 4, 1, fp);
if (strncmp(header, "KiSS", 4)) {
colours= 16;
width= header[0] + (256 * header[1]);
height= header[2] + (256 * header[3]);
} else {
fread(header, 28, 1, fp);
colours= (1 << header[1]);
width= header[4] + (256 * header[5]);
height= header[6] + (256 * header[7]);
}
image = gimp_image_new(width, height, INDEXED);
if (image == -1) {
g_print("Can't allocate new image\n");
gimp_quit();
}
gimp_image_set_filename(image, file);
palette = g_new(guchar, colours*3);
/* FIXME Default palette -- hopefully nasty enough to encourage a fix */
for (i= 1; i < colours; ++i)
palette[i*3+1]= palette[i*3]= i * 256 / colours;
gimp_image_set_cmap(image, palette, colours);
/* Create an indexed-alpha layer to hold the image... */
layer = gimp_layer_new(image, "Background", width, height,
INDEXEDA_IMAGE, 100, NORMAL_MODE);
gimp_image_add_layer(image, layer, 0);
/* Get the drawable and set the pixel region for our load... */
drawable = gimp_drawable_get(layer);
gimp_pixel_rgn_init(&pixel_rgn, drawable, 0, 0, drawable->width,
drawable->height, TRUE, FALSE);
/* Read the image in and give it to the GIMP a line at a time */
buffer = g_new(guchar, width);
line = g_new(guchar, (width+1) * 2);
for (i = 0; i < height; ++i) {
switch (colours) {
case 16:
fread(buffer, (width+1)/2, 1, fp);
for (j = 0, k = 0; j < width*2; j+= 4, ++k) {
line[j]= buffer[k] / 16;
line[j+1]= line[j] ? 255 : 0;
line[j+2]= buffer[k] & 15;
line[j+3]= line[j+2] ? 255 : 0;
}
break;
case 256:
fread(buffer, width, 1, fp);
for (j = 0, k = 0; j < width*2; j+= 2, ++k) {
line[j]= buffer[k];
line[j+1]= line[j] ? 255 : 0;
}
break;
}
gimp_pixel_rgn_set_rect(&pixel_rgn, line, 0, i, drawable->width, 1);
gimp_progress_update((float) i / (float) height);
}
/* Close files, give back allocated memory */
fclose(fp);
free(buffer);
free(line);
free(palette);
/* Now get everything redrawn and hand back the finished image */
gimp_drawable_flush(drawable);
gimp_drawable_detach(drawable);
return (image);
}
static gint save_image(char *file, char *brief, gint32 image, gint32 layer) {
FILE* fp; /* Write file pointer */
char progress[255]; /* Title for progress display */
guchar header[32]; /* File header */
gint colours, type; /* Number of colours, type of layer */
guchar *palette, /* 24 bit palette */
*buffer, /* Temporary buffer */
*line; /* Pixel data */
GDrawable *drawable; /* Drawable for layer */
GPixelRgn pixel_rgn; /* Pixel region for layer */
int i, j, k; /* Counters */
/* Check that this is an indexed image, fail otherwise */
type= gimp_drawable_type(layer);
if (type != INDEXED_IMAGE && type != INDEXEDA_IMAGE) {
g_print("GIMP tried to save a non-indexed image as CEL.\n");
return FALSE;
}
drawable = gimp_drawable_get(layer);
/* Open the file for writing */
fp = fopen(file, "w");
sprintf(progress, "Saving %s:", brief);
gimp_progress_init(progress);
/* Headers */
bzero(header, 32);
strcpy(header, "KiSS");
header[4]= 0x20;
/* Work out whether to save as 8bit or 4bit */
gimp_image_get_cmap(image, &colours);
if (colours > 16) {
header[5]= 8;
} else {
header[5]= 4;
}
/* Fill in the blanks ... */
header[8]= drawable->width % 256;
header[9]= drawable->width / 256;
header[10]= drawable->height % 256;
header[11]= drawable->height / 256;
fwrite(header, 32, 1, fp);
/* Arrange for memory etc. */
gimp_pixel_rgn_init(&pixel_rgn, drawable, 0, 0, drawable->width,
drawable->height, TRUE, FALSE);
buffer = g_new(guchar, drawable->width);
line = g_new(guchar, (drawable->width+1) * 2);
/* Get the image from the GIMP one line at a time and write it out */
for (i = 0; i < drawable->height; ++i) {
gimp_pixel_rgn_get_rect(&pixel_rgn, line, 0, i, drawable->width, 1);
switch (colours) {
case 16:
for (j = 0, k = 0; j < drawable->width*2; j+= 4, ++k) {
buffer[k]= 16 * (line[j+1] ? line[j] : 0)
+ (line[j+3] ? line[j+2] : 0);
}
fwrite(buffer, (drawable->width+1)/2, 1, fp);
break;
case 256:
for (j = 0, k = 0; j < drawable->width*2; j+= 2, ++k) {
buffer[k]= line[j+1] ? line[j] : 0;
}
fwrite(buffer, drawable->width, 1, fp);
break;
}
gimp_progress_update((float) i / (float) drawable->height);
}
/* Close files, give back allocated memory */
fclose(fp);
free(buffer);
free(line);
return TRUE;
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,934 +0,0 @@
/*
* Animation Playback plug-in version 0.81.7
*
* by Adam D. Moss, 1997
* adam@gimp.org
* adam@foxbox.org
*
* This is part of the GIMP package and falls under the GPL.
*/
/*
* REVISION HISTORY:
*
* 97.09.16 : version 0.81.7
* Fixed progress bar's off-by-one problem with
* the new timing. Fixed erroneous black bars which
* were sometimes visible when the first frame was
* smaller than the image itself. Made playback
* controls inactive when image doesn't have multiple
* frames. Moved progress bar above control buttons,
* it's less distracting there. More cosmetic stuff.
*
* 97.09.15 : version 0.81.0
* Now plays INDEXED and GRAY animations.
*
* 97.09.15 : version 0.75.0
* Next frame is generated ahead of time - results
* in more precise timing.
*
* 97.09.14 : version 0.70.0
* Initial release. RGB only.
*/
/*
* BUGS:
* Leaks memory. Not sure why.
* Gets understandably upset if the source image is deleted
* while the animation is playing.
* Decent solutions to either of the above are most welcome.
*
* Any more? Let me know!
*/
/*
* TODO:
* pdb interface - should we bother?
* speedups (caching? most bottlenecks seem to be in pixelrgns)
* write other half of the user interface
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include "libgimp/gimp.h"
#include "gtk/gtk.h"
typedef enum
{
DISPOSE_UNDEFINED = 0x00,
DISPOSE_COMBINE = 0x01,
DISPOSE_REPLACE = 0x02
} DisposeType;
/* Declare local functions. */
static void query(void);
static void run(char *name,
int nparams,
GParam * param,
int *nreturn_vals,
GParam ** return_vals);
static void do_playback (void);
static int parse_ms_tag (char *str);
static DisposeType parse_disposal_tag (char *str);
static void window_close_callback (GtkWidget *widget,
gpointer data);
static void playstop_callback (GtkWidget *widget,
gpointer data);
static void rewind_callback (GtkWidget *widget,
gpointer data);
static void step_callback (GtkWidget *widget,
gpointer data);
static DisposeType get_frame_disposal (guint whichframe);
static void render_frame (gint32 whichframe);
static void show_frame (void);
static void total_alpha_preview (void);
static void init_preview_misc (void);
GPlugInInfo PLUG_IN_INFO =
{
NULL, /* init_proc */
NULL, /* quit_proc */
query, /* query_proc */
run, /* run_proc */
};
/* Global widgets'n'stuff */
guchar* preview_data;
static GtkWidget* preview = NULL;
GtkWidget* progress;
guint width,height;
guchar* preview_alpha1_data;
guchar* preview_alpha2_data;
gint32 image_id;
gint32 total_frames;
guint frame_number;
gint32* layers;
GDrawable* drawable;
gboolean playing = FALSE;
int timer = 0;
GImageType imagetype;
guchar* palette;
gint ncolours;
MAIN()
static void query()
{
static GParamDef args[] =
{
{PARAM_INT32, "run_mode", "Interactive, non-interactive"},
{PARAM_IMAGE, "image", "Input image"},
{PARAM_DRAWABLE, "drawable", "Input drawable (unused)"},
};
static GParamDef *return_vals = NULL;
static int nargs = sizeof(args) / sizeof(args[0]);
static int nreturn_vals = 0;
gimp_install_procedure("plug_in_animationplay",
"This plugin allows you to preview a GIMP layer-based animation.",
"",
"Adam D. Moss <adam@gimp.org>",
"Adam D. Moss <adam@gimp.org>",
"1997",
"<Image>/Filters/Animation/Animation Playback",
"RGB*, INDEXED*, GRAY*",
PROC_PLUG_IN,
nargs, nreturn_vals,
args, return_vals);
}
static void run(char *name, int n_params, GParam * param, int *nreturn_vals,
GParam ** return_vals)
{
static GParam values[1];
GRunModeType run_mode;
GStatusType status = STATUS_SUCCESS;
*nreturn_vals = 1;
*return_vals = values;
run_mode = param[0].data.d_int32;
if (run_mode == RUN_NONINTERACTIVE) {
if (n_params != 3) {
status = STATUS_CALLING_ERROR;
}
}
if (status == STATUS_SUCCESS) {
image_id = param[1].data.d_image;
do_playback();
if (run_mode != RUN_NONINTERACTIVE)
gimp_displays_flush();
}
values[0].type = PARAM_STATUS;
values[0].data.d_status = status;
}
static int
parse_ms_tag (char *str)
{
gint sum = 0;
gint offset = 0;
gint length;
length = strlen(str);
while ((offset<length) && (str[offset]!='('))
offset++;
if (offset>=length)
return(-1);
if (!isdigit(str[++offset]))
return(-2);
do
{
sum *= 10;
sum += str[offset] - '0';
offset++;
}
while ((offset<length) && (isdigit(str[offset])));
if (length-offset <= 2)
return(-3);
if ((toupper(str[offset]) != 'M') || (toupper(str[offset+1]) != 'S'))
return(-4);
return (sum);
}
static DisposeType
parse_disposal_tag (char *str)
{
gint offset = 0;
gint length;
length = strlen(str);
while ((offset+9)<=length)
{
if (strncmp(&str[offset],"(combine)",9)==0)
return(DISPOSE_COMBINE);
if (strncmp(&str[offset],"(replace)",9)==0)
return(DISPOSE_REPLACE);
offset++;
}
return (DISPOSE_UNDEFINED); /* FIXME */
}
static void
build_dialog(GImageType basetype,
char* imagename)
{
gchar** argv;
gint argc;
gchar* windowname;
GtkWidget* dlg;
GtkWidget* button;
GtkWidget* toggle;
GtkWidget* label;
GtkWidget* entry;
GtkWidget* frame;
GtkWidget* frame2;
GtkWidget* vbox;
GtkWidget* vbox2;
GtkWidget* hbox;
GtkWidget* hbox2;
guchar* color_cube;
GSList* group = NULL;
argc = 1;
argv = g_new (gchar *, 1);
argv[0] = g_strdup ("animationplay");
gtk_init (&argc, &argv);
gtk_rc_parse (gimp_gtkrc ());
gdk_set_use_xshm (gimp_use_xshm ());
gtk_preview_set_gamma (gimp_gamma ());
gtk_preview_set_install_cmap (gimp_install_cmap ());
color_cube = gimp_color_cube ();
gtk_preview_set_color_cube (color_cube[0], color_cube[1],
color_cube[2], color_cube[3]);
gtk_widget_set_default_visual (gtk_preview_get_visual ());
gtk_widget_set_default_colormap (gtk_preview_get_cmap ());
dlg = gtk_dialog_new ();
windowname = g_malloc(strlen("Animation Playback: ")+strlen(imagename)+1);
strcpy(windowname,"Animation Playback: ");
strcat(windowname,imagename);
gtk_window_set_title (GTK_WINDOW (dlg), windowname);
g_free(windowname);
gtk_window_position (GTK_WINDOW (dlg), GTK_WIN_POS_MOUSE);
gtk_signal_connect (GTK_OBJECT (dlg), "destroy",
(GtkSignalFunc) window_close_callback,
NULL);
/* Action area - 'close' button only. */
button = gtk_button_new_with_label ("Close");
GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
(GtkSignalFunc) window_close_callback,
NULL);
gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dlg)->action_area),
button, TRUE, TRUE, 0);
gtk_widget_grab_default (button);
gtk_widget_show (button);
{
/* The 'playback' half of the dialog */
windowname = g_malloc(strlen("Playback: ")+strlen(imagename)+1);
strcpy(windowname,"Playback: ");
strcat(windowname,imagename);
frame = gtk_frame_new (windowname);
g_free(windowname);
gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_IN);
gtk_container_border_width (GTK_CONTAINER (frame), 3);
gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dlg)->vbox),
frame, TRUE, TRUE, 0);
{
hbox = gtk_hbox_new (FALSE, 5);
gtk_container_border_width (GTK_CONTAINER (hbox), 3);
gtk_container_add (GTK_CONTAINER (frame), hbox);
{
vbox = gtk_vbox_new (FALSE, 5);
gtk_container_border_width (GTK_CONTAINER (vbox), 3);
gtk_container_add (GTK_CONTAINER (hbox), vbox);
{
progress = gtk_progress_bar_new ();
gtk_widget_set_usize (progress, 150, 15);
gtk_box_pack_start (GTK_BOX (vbox), progress, TRUE, TRUE, 0);
gtk_widget_show (progress);
hbox2 = gtk_hbox_new (FALSE, 0);
gtk_container_border_width (GTK_CONTAINER (hbox2), 0);
gtk_box_pack_start (GTK_BOX (vbox), hbox2, TRUE, TRUE, 0);
{
button = gtk_button_new_with_label ("Play/Stop");
gtk_signal_connect (GTK_OBJECT (button), "clicked",
(GtkSignalFunc) playstop_callback, NULL);
gtk_box_pack_start (GTK_BOX (hbox2), button, TRUE, TRUE, 0);
gtk_widget_show (button);
button = gtk_button_new_with_label ("Rewind");
gtk_signal_connect (GTK_OBJECT (button), "clicked",
(GtkSignalFunc) rewind_callback, NULL);
gtk_box_pack_start (GTK_BOX (hbox2), button, TRUE, TRUE, 0);
gtk_widget_show (button);
button = gtk_button_new_with_label ("Step");
gtk_signal_connect (GTK_OBJECT (button), "clicked",
(GtkSignalFunc) step_callback, NULL);
gtk_box_pack_start (GTK_BOX (hbox2), button, TRUE, TRUE, 0);
gtk_widget_show (button);
}
/* If there aren't multiple frames, playback controls make no
sense */
if (total_frames<=1) gtk_widget_set_sensitive (hbox2, FALSE);
gtk_widget_show(hbox2);
frame2 = gtk_frame_new (NULL);
gtk_frame_set_shadow_type (GTK_FRAME (frame2), GTK_SHADOW_ETCHED_IN);
gtk_box_pack_start (GTK_BOX (vbox), frame2, FALSE, FALSE, 0);
{
preview = gtk_preview_new (GTK_PREVIEW_COLOR); /* FIXME */
gtk_preview_size (GTK_PREVIEW (preview), width, height);
gtk_container_add (GTK_CONTAINER (frame2), preview);
gtk_widget_show(preview);
}
gtk_widget_show(frame2);
}
gtk_widget_show(vbox);
}
gtk_widget_show(hbox);
}
gtk_widget_show(frame);
}
gtk_widget_show(dlg);
}
static void do_playback(void)
{
GPixelRgn srcPR, destPR;
guchar *buffer;
int nreturn_vals, i;
width = gimp_image_width(image_id);
height = gimp_image_height(image_id);
layers = gimp_image_get_layers (image_id, &total_frames);
imagetype = gimp_image_base_type(image_id);
if (imagetype == INDEXED)
palette = gimp_image_get_cmap(image_id, &ncolours);
else if (imagetype == GRAY)
{
/* This is a bit sick, until this plugin ever gets
real GRAY support (not worth it?) */
palette = g_malloc(768);
for (i=0;i<256;i++)
{
palette[i*3] = palette[i*3+1] = palette[i*3+2] = i;
}
ncolours = 256;
}
frame_number = 0;
/* cache hint "cache nothing", since we iterate over every
tile in every layer. */
gimp_tile_cache_size (0);
init_preview_misc();
build_dialog(gimp_image_base_type(image_id),
gimp_image_get_filename(image_id));
/* Make sure that whole preview is dirtied with pure-alpha */
total_alpha_preview();
for (i=0;i<height;i++)
{
gtk_preview_draw_row (GTK_PREVIEW (preview),
&preview_data[3*i*width],
0, i, width);
}
render_frame(0);
show_frame();
gtk_main ();
gdk_flush ();
}
/* Rendering Functions */
static void
render_frame(gint32 whichframe)
{
GPixelRgn pixel_rgn;
static guchar *rawframe = NULL;
static gint rawwidth=0, rawheight=0, rawbpp=0;
gint rawx=0, rawy=0;
guchar* srcptr;
guchar* destptr;
gint i,j;
DisposeType dispose;
if (whichframe >= total_frames)
{
printf("playback: Asked for frame number %d in a %d-frame animation!\n",
(int) (whichframe+1), (int) total_frames);
exit(-1);
}
drawable = gimp_drawable_get (layers[total_frames-(whichframe+1)]);
dispose = get_frame_disposal(frame_number);
/* Image has been closed/etc since we got the layer list? */
/* FIXME - How do we tell if a gimp_drawable_get() fails? */
if (gimp_drawable_width(drawable->id)==0)
{
window_close_callback(NULL, NULL);
}
if (((dispose==DISPOSE_REPLACE)||(whichframe==0)) &&
gimp_drawable_has_alpha(drawable->id))
{
total_alpha_preview();
}
/* only get a new 'raw' drawable-data buffer if this and
the previous raw buffer were different sizes*/
if ((rawwidth*rawheight*rawbpp)
!=
((gimp_drawable_width(drawable->id)*
gimp_drawable_height(drawable->id)*
gimp_drawable_bpp(drawable->id))))
{
if (rawframe != NULL) g_free(rawframe);
rawframe = g_malloc((gimp_drawable_width(drawable->id)) *
(gimp_drawable_height(drawable->id)) *
(gimp_drawable_bpp(drawable->id)));
}
rawwidth = gimp_drawable_width(drawable->id);
rawheight = gimp_drawable_height(drawable->id);
rawbpp = gimp_drawable_bpp(drawable->id);
/* Initialise and fetch the whole raw new frame */
gimp_pixel_rgn_init (&pixel_rgn,
drawable,
0, 0,
drawable->width, drawable->height,
FALSE,
FALSE);
gimp_pixel_rgn_get_rect (&pixel_rgn,
rawframe,
0, 0,
drawable->width, drawable->height);
/* gimp_pixel_rgns_register (1, &pixel_rgn);*/
gimp_drawable_offsets (drawable->id,
&rawx,
&rawy);
/* render... */
switch (imagetype)
{
case RGB:
if ((rawwidth==width) &&
(rawheight==height) &&
(rawx==0) &&
(rawy==0))
{
/* --- These cases are for the best cases, in --- */
/* --- which this frame is the same size and position --- */
/* --- as the preview buffer itself --- */
if (gimp_drawable_has_alpha (drawable->id))
{ /* alpha */
destptr = preview_data;
srcptr = rawframe;
i = rawwidth*rawheight;
while (--i)
{
if (!(*(srcptr+3)&128))
{
srcptr += 4;
destptr += 3;
continue;
}
*(destptr++) = *(srcptr++);
*(destptr++) = *(srcptr++);
*(destptr++) = *(srcptr++);
srcptr++;
}
}
else /* no alpha */
{
if ((rawwidth==width)&&(rawheight==height))
{
/*printf("quickie\n");fflush(stdout);*/
memcpy(preview_data, rawframe, width*height*3);
}
}
/* Display the preview buffer... finally. */
for (i=0;i<height;i++)
{
gtk_preview_draw_row (GTK_PREVIEW (preview),
&preview_data[3*i*width],
0, i, width);
}
}
else
{
/* --- These are suboptimal catch-all cases for when --- */
/* --- this frame is bigger/smaller than the preview --- */
/* --- buffer, and/or offset within it. --- */
/* FIXME: FINISH ME! */
if (gimp_drawable_has_alpha (drawable->id))
{ /* alpha */
srcptr = rawframe;
for (j=rawy; j<rawheight+rawy; j++)
{
for (i=rawx; i<rawwidth+rawx; i++)
{
if ((i>=0 && i<width) &&
(j>=0 && j<height))
{
if (*(srcptr+3)&128)
{
preview_data[(j*width+i)*3 ] = *(srcptr);
preview_data[(j*width+i)*3 +1] = *(srcptr+1);
preview_data[(j*width+i)*3 +2] = *(srcptr+2);
}
}
srcptr += 4;
}
}
}
else
{
/* noalpha */
}
/* Display the preview buffer... finally. */
if (dispose!=DISPOSE_REPLACE)
{
for (i=rawy;i<rawy+rawheight;i++)
{
if (i>=0 && i<height)
gtk_preview_draw_row (GTK_PREVIEW (preview),
&preview_data[3*i*width],
0, i, width);
}
}
else
{
for (i=0;i<height;i++)
{
gtk_preview_draw_row (GTK_PREVIEW (preview),
&preview_data[3*i*width],
0, i, width);
}
}
}
break;
case GRAY:
case INDEXED:
if ((rawwidth==width) &&
(rawheight==height) &&
(rawx==0) &&
(rawy==0))
{
/* --- These cases are for the best cases, in --- */
/* --- which this frame is the same size and position --- */
/* --- as the preview buffer itself --- */
if (gimp_drawable_has_alpha (drawable->id))
{ /* alpha */
destptr = preview_data;
srcptr = rawframe;
i = rawwidth*rawheight;
while (--i)
{
if (!(*(srcptr+1)))
{
srcptr += 2;
destptr += 3;
continue;
}
*(destptr++) = palette[3*(*(srcptr))];
*(destptr++) = palette[1+3*(*(srcptr))];
*(destptr++) = palette[2+3*(*(srcptr))];
srcptr+=2;
}
}
else /* no alpha */
{
destptr = preview_data;
srcptr = rawframe;
i = rawwidth*rawheight;
while (--i)
{
*(destptr++) = palette[3*(*(srcptr))];
*(destptr++) = palette[1+3*(*(srcptr))];
*(destptr++) = palette[2+3*(*(srcptr))];
srcptr++;
}
}
/* Display the preview buffer... finally. */
for (i=0;i<height;i++)
{
gtk_preview_draw_row (GTK_PREVIEW (preview),
&preview_data[3*i*width],
0, i, width);
}
}
else
{
/* --- These are suboptimal catch-all cases for when --- */
/* --- this frame is bigger/smaller than the preview --- */
/* --- buffer, and/or offset within it. --- */
/* FIXME: FINISH ME! */
if (gimp_drawable_has_alpha (drawable->id))
{ /* alpha */
srcptr = rawframe;
for (j=rawy; j<rawheight+rawy; j++)
{
for (i=rawx; i<rawwidth+rawx; i++)
{
if ((i>=0 && i<width) &&
(j>=0 && j<height))
{
if (*(srcptr+1))
{
preview_data[(j*width+i)*3 ] =
palette[3*(*(srcptr))];
preview_data[(j*width+i)*3 +1] =
palette[1+3*(*(srcptr))];
preview_data[(j*width+i)*3 +2] =
palette[2+3*(*(srcptr))];
}
}
srcptr += 2;
}
}
}
else
{
/* noalpha */
}
/* Display the preview buffer... finally. */
if (dispose!=DISPOSE_REPLACE)
{
for (i=rawy;i<rawy+rawheight;i++)
{
if (i>=0 && i<height)
gtk_preview_draw_row (GTK_PREVIEW (preview),
&preview_data[3*i*width],
0, i, width);
}
}
else
{
for (i=0;i<height;i++)
{
gtk_preview_draw_row (GTK_PREVIEW (preview),
&preview_data[3*i*width],
0, i, width);
}
}
}
break;
}
/* clean up */
gimp_drawable_detach(drawable);
}
static void
show_frame(void)
{
/* Tell GTK to physically draw the preview */
gtk_widget_draw (preview, NULL);
gdk_flush ();
/* update the dialog's progress bar */
gtk_progress_bar_update (GTK_PROGRESS_BAR (progress),
((float)frame_number/(float)(total_frames-0.999)));
}
static void
init_preview_misc(void)
{
int i;
preview_data = g_malloc(width*height*3);
preview_alpha1_data = g_malloc(width*3);
preview_alpha2_data = g_malloc(width*3);
for (i=0;i<width;i++)
{
if (i&8)
{
preview_alpha1_data[i*3 +0] =
preview_alpha1_data[i*3 +1] =
preview_alpha1_data[i*3 +2] = 102;
preview_alpha2_data[i*3 +0] =
preview_alpha2_data[i*3 +1] =
preview_alpha2_data[i*3 +2] = 154;
}
else
{
preview_alpha1_data[i*3 +0] =
preview_alpha1_data[i*3 +1] =
preview_alpha1_data[i*3 +2] = 154;
preview_alpha2_data[i*3 +0] =
preview_alpha2_data[i*3 +1] =
preview_alpha2_data[i*3 +2] = 102;
}
}
}
static void
total_alpha_preview(void)
{
int i;
for (i=0;i<height;i++)
{
if (i&8)
memcpy(&preview_data[i*3*width], preview_alpha1_data, 3*width);
else
memcpy(&preview_data[i*3*width], preview_alpha2_data, 3*width);
}
}
/* Util. */
static void
remove_timer(void)
{
if (timer)
{
gtk_timeout_remove (timer);
timer = 0;
}
}
static void
do_step(void)
{
frame_number = (frame_number+1)%total_frames;
render_frame(frame_number);
}
static guint32
get_frame_duration (guint whichframe)
{
gchar* layer_name;
gint duration;
layer_name = gimp_layer_get_name(layers[total_frames-(whichframe+1)]);
duration = parse_ms_tag(layer_name);
g_free(layer_name);
if (duration < 0) duration = 100; /* FIXME for default-if-not-said */
if (duration == 0) duration = 60; /* FIXME - 0-wait is nasty */
return ((guint32) duration);
}
static DisposeType
get_frame_disposal (guint whichframe)
{
gchar* layer_name;
DisposeType disposal;
layer_name = gimp_layer_get_name(layers[total_frames-(whichframe+1)]);
disposal = parse_disposal_tag(layer_name);
g_free(layer_name);
return(disposal);
}
/* Callbacks */
static void
window_close_callback (GtkWidget *widget,
gpointer data)
{
gtk_main_quit();
}
static void
advance_frame_callback (GtkWidget *widget,
gpointer data)
{
remove_timer();
timer = gtk_timeout_add (get_frame_duration(frame_number),
(GtkFunction) advance_frame_callback, NULL);
show_frame();
do_step();
}
static void
playstop_callback (GtkWidget *widget,
gpointer data)
{
if (!playing)
{ /* START PLAYING */
playing = TRUE;
timer = gtk_timeout_add (0, (GtkFunction) advance_frame_callback, NULL);
}
else
{ /* STOP PLAYING */
playing = FALSE;
remove_timer();
}
}
static void
rewind_callback (GtkWidget *widget,
gpointer data)
{
playing = FALSE;
remove_timer();
frame_number = 0;
render_frame(frame_number);
show_frame();
}
static void
step_callback (GtkWidget *widget,
gpointer data)
{
playing = FALSE;
remove_timer();
do_step();
show_frame();
}

View File

@ -1,501 +0,0 @@
/* The GIMP -- an image manipulation program
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* Apply lens plug-in --- makes your selected part of the image look like it
* is viewed under a solid lens.
* Copyright (C) 1997 Morten Eriksen
* mortene@pvv.ntnu.no
* (If you do anything cool with this plug-in, or have ideas for
* improvements (which aren't on my ToDo-list) - send me an email).
*
* 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
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/*
* Compile with (on Linux):
* gcc -I/usr/local/include -I/usr/local/include/glib -o apply_lens apply_lens.c -L/usr/local/lib -L/usr/X11/lib -lgtk -lgdk -lgimp -lglib -lXext -lX11 -lm
*
*/
/* Version 0.1:
*
* First release. No known serious bugs, and basically does what you want.
* All fancy features postponed until the next release, though. :)
*
*/
/*
TO DO:
- antialiasing
- preview image
- adjustable (R, G, B and A) filter
- optimize for speed!
- refraction index warning dialog box when value < 1.0
- use "true" lens with specified thickness
- option to apply inverted lens
- adjustable "c" value in the ellipsoid formula
- radiobuttons for "ellipsoid" or "only horiz" and "only vert" (like in the
Ad*b* Ph*t*sh*p Spherify plug-in..)
- clean up source code
*/
#include <stdlib.h>
#include <math.h>
#include "libgimp/gimp.h"
#include "gtk/gtk.h"
#define ENTRY_WIDTH 100
/* Declare local functions.
*/
static void query(void);
static void run(char *name, int nparams,
GParam *param,
int *nreturn_vals,
GParam **return_vals);
static void drawlens(GDrawable *drawable);
static gint lens_dialog(GDrawable *drawable);
GPlugInInfo PLUG_IN_INFO =
{
NULL, /* init_proc */
NULL, /* quit_proc */
query, /* query_proc */
run, /* run_proc */
};
typedef struct
{
gdouble refraction;
gint keep_surr, use_bkgr, set_transparent;
} LensValues;
static LensValues lvals =
{
/* Lens refraction value */
1.7,
/* Surroundings options */
TRUE, FALSE, FALSE
};
typedef struct
{
gint run;
} LensInterface;
static LensInterface bint =
{
FALSE /* run */
};
MAIN()
static void
query(void)
{
static GParamDef args[] =
{
{ PARAM_INT32, "run_mode", "Interactive, non-interactive" },
{ PARAM_IMAGE, "image", "Input image (unused)" },
{ PARAM_DRAWABLE, "drawable", "Input drawable" },
{ PARAM_FLOAT, "refraction", "Lens refraction index" },
{ PARAM_INT32, "keep_surroundings", "Keep lens surroundings" },
{ PARAM_INT32, "set_background", "Set lens surroundings to bkgr value" },
{ PARAM_INT32, "set_transparent", "Set lens surroundings transparent" },
};
static GParamDef *return_vals = NULL;
static int nargs = sizeof(args)/ sizeof(args[0]);
static int nreturn_vals = 0;
gimp_install_procedure("plug_in_applylens",
"Apply a lens effect",
"This plug-in uses Snell's law to draw an ellipsoid lens over the image",
"Morten Eriksen",
"Morten Eriksen",
"1997",
"<Image>/Filters/Distorts/Apply lens",
"RGB*, GRAY*, INDEXED*",
PROC_PLUG_IN,
nargs, nreturn_vals,
args, return_vals);
}
static void
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;
run_mode = param[0].data.d_int32;
values[0].type = PARAM_STATUS;
values[0].data.d_status = status;
*nreturn_vals = 1;
*return_vals = values;
drawable = gimp_drawable_get(param[2].data.d_drawable);
switch(run_mode) {
case RUN_INTERACTIVE:
gimp_get_data("plug_in_applylens", &lvals);
if(!lens_dialog(drawable)) return;
break;
case RUN_NONINTERACTIVE:
if(nparams != 7) status = STATUS_CALLING_ERROR;
if(status == STATUS_SUCCESS) {
lvals.refraction = param[3].data.d_float;
lvals.keep_surr = param[4].data.d_int32;
lvals.use_bkgr = param[5].data.d_int32;
lvals.set_transparent = param[6].data.d_int32;
}
if(status == STATUS_SUCCESS && (lvals.refraction < 1.0))
status = STATUS_CALLING_ERROR;
break;
case RUN_WITH_LAST_VALS:
gimp_get_data ("plug_in_applylens", &lvals);
break;
default:
break;
}
gimp_tile_cache_ntiles(2 *(drawable->width / gimp_tile_width() + 1));
gimp_progress_init("Applying lens...");
drawlens(drawable);
if(run_mode != RUN_NONINTERACTIVE)
gimp_displays_flush();
if(run_mode == RUN_INTERACTIVE)
gimp_set_data("plug_in_applylens", &lvals, sizeof(LensValues));
values[0].data.d_status = status;
gimp_drawable_detach(drawable);
}
/*
Ellipsoid formula: x^2/a^2 + y^2/b^2 + z^2/c^2 = 1
*/
static void
find_projected_pos(gfloat a, gfloat b,
gfloat x, gfloat y,
gfloat *projx, gfloat *projy)
{
gfloat c;
gfloat n[3];
gfloat nxangle, nyangle, theta1, theta2;
gfloat ri1 = 1.0, ri2 = lvals.refraction;
/* PARAM */
c = MIN(a, b);
n[0] = x;
n[1] = y;
n[2] = sqrt((1-x*x/(a*a)-y*y/(b*b))*(c*c));
nxangle = acos(n[0]/sqrt(n[0]*n[0]+n[2]*n[2]));
theta1 = M_PI/2 - nxangle;
theta2 = asin(sin(theta1)*ri1/ri2);
theta2 = M_PI/2 - nxangle - theta2;
*projx = x - tan(theta2)*n[2];
nyangle = acos(n[1]/sqrt(n[1]*n[1]+n[2]*n[2]));
theta1 = M_PI/2 - nyangle;
theta2 = asin(sin(theta1)*ri1/ri2);
theta2 = M_PI/2 - nyangle - theta2;
*projy = y - tan(theta2)*n[2];
}
static void
drawlens(GDrawable *drawable)
{
GPixelRgn srcPR, destPR;
gint width, height;
gint bytes;
gint row;
gint x1, y1, x2, y2;
guchar *src, *dest;
gint i, col;
gfloat regionwidth, regionheight, dx, dy, xsqr, ysqr;
gfloat a, b, asqr, bsqr, midx, midy, x, y;
glong pixelpos, pos;
guchar bgr_red, bgr_blue, bgr_green, alphaval;
GDrawableType drawtype = gimp_drawable_type(drawable->id);
gimp_palette_get_background(&bgr_red, &bgr_green, &bgr_blue);
gimp_drawable_mask_bounds(drawable->id, &x1, &y1, &x2, &y2);
regionwidth = x2-x1;
a = regionwidth/2;
regionheight = y2-y1;
b = regionheight/2;
asqr = a*a;
bsqr = b*b;
width = drawable->width;
height = drawable->height;
bytes = drawable->bpp;
gimp_pixel_rgn_init(&srcPR, drawable, 0, 0, width, height, FALSE, FALSE);
gimp_pixel_rgn_init(&destPR, drawable, 0, 0, width, height, TRUE, TRUE);
src = g_malloc((x2-x1)*(y2-y1)*bytes);
dest = g_malloc((x2-x1)*(y2-y1)*bytes);
gimp_pixel_rgn_get_rect(&srcPR, src, x1, y1, regionwidth, regionheight);
for(col = 0; col < regionwidth; col++) {
dx = (gfloat)col - a + 0.5;
xsqr = dx*dx;
for(row = 0; row < regionheight; row++) {
pixelpos = (col+row*regionwidth)*bytes;
dy = -((gfloat)row - b) - 0.5;
ysqr = dy*dy;
if(ysqr < (bsqr - (bsqr*xsqr)/asqr)) {
find_projected_pos(a, b, dx, dy, &x, &y);
y = -y;
pos = ((gint)(y+b)*regionwidth + (gint)(x+a)) * bytes;
for(i = 0; i < bytes; i++) {
dest[pixelpos+i] = src[pos+i];
}
}
else {
if(lvals.keep_surr) {
for(i = 0; i < bytes; i++) {
dest[pixelpos+i] = src[pixelpos+i];
}
}
else {
if(lvals.set_transparent) alphaval = 0;
else alphaval = 255;
switch(drawtype) {
case INDEXEDA_IMAGE:
dest[pixelpos+1] = alphaval;
case INDEXED_IMAGE:
dest[pixelpos+0] = 0;
break;
case RGBA_IMAGE:
dest[pixelpos+3] = alphaval;
case RGB_IMAGE:
dest[pixelpos+0] = bgr_red;
dest[pixelpos+1] = bgr_green;
dest[pixelpos+2] = bgr_blue;
break;
case GRAYA_IMAGE:
dest[pixelpos+1] = alphaval;
case GRAY_IMAGE:
dest[pixelpos+0] = bgr_red;
break;
}
}
}
}
if(((gint)(regionwidth-col) % 5) == 0)
gimp_progress_update((gdouble)col/(gdouble)regionwidth);
}
gimp_pixel_rgn_set_rect(&destPR, dest, x1, y1, regionwidth, regionheight);
g_free(src);
g_free(dest);
gimp_drawable_flush(drawable);
gimp_drawable_merge_shadow(drawable->id, TRUE);
gimp_drawable_update(drawable->id, x1, y1,(x2 - x1),(y2 - y1));
}
static void
lens_close_callback(GtkWidget *widget,
gpointer data)
{
gtk_main_quit();
}
static void
lens_ok_callback(GtkWidget *widget,
gpointer data)
{
bint.run = TRUE;
gtk_widget_destroy(GTK_WIDGET (data));
}
static void
lens_toggle_update(GtkWidget *widget,
gpointer data)
{
int *toggle_val;
toggle_val = (int *)data;
if(GTK_TOGGLE_BUTTON (widget)->active)
*toggle_val = TRUE;
else
*toggle_val = FALSE;
}
static void
lens_entry_callback(GtkWidget *widget,
gpointer data)
{
lvals.refraction = atof(gtk_entry_get_text(GTK_ENTRY(widget)));
if(lvals.refraction < 1.0) lvals.refraction = 1.0;
}
static gint
lens_dialog(GDrawable *drawable)
{
GtkWidget *dlg;
GtkWidget *label;
GtkWidget *entry;
GtkWidget *button;
GtkWidget *toggle;
GtkWidget *frame;
GtkWidget *vbox;
GtkWidget *hbox;
gchar buffer[12];
gchar **argv;
gint argc;
GSList *group = NULL;
GDrawableType drawtype;
drawtype = gimp_drawable_type(drawable->id);
argc = 1;
argv = g_new(gchar *, 1);
argv[0] = g_strdup("apply_lens");
gtk_init(&argc, &argv);
gtk_rc_parse(gimp_gtkrc());
dlg = gtk_dialog_new();
gtk_window_set_title(GTK_WINDOW(dlg), "Lens effect");
gtk_window_position(GTK_WINDOW(dlg), GTK_WIN_POS_MOUSE);
gtk_signal_connect(GTK_OBJECT(dlg), "destroy",
(GtkSignalFunc)lens_close_callback,
NULL);
button = gtk_button_new_with_label("OK");
GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT);
gtk_signal_connect(GTK_OBJECT(button), "clicked",
(GtkSignalFunc)lens_ok_callback,
dlg);
gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dlg)->action_area),
button, TRUE, TRUE, 0);
gtk_widget_grab_default(button);
gtk_widget_show(button);
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));
gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dlg)->action_area),
button, TRUE, TRUE, 0);
gtk_widget_show(button);
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);
vbox = gtk_vbox_new(FALSE, 5);
gtk_container_border_width(GTK_CONTAINER(vbox), 10);
gtk_container_add(GTK_CONTAINER(frame), vbox);
toggle = gtk_radio_button_new_with_label(group,
"Keep original surroundings");
group = gtk_radio_button_group(GTK_RADIO_BUTTON(toggle));
gtk_box_pack_start(GTK_BOX(vbox), toggle, FALSE, FALSE, 0);
gtk_signal_connect(GTK_OBJECT(toggle), "toggled",
(GtkSignalFunc) lens_toggle_update,
&lvals.keep_surr);
gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(toggle), lvals.keep_surr);
gtk_widget_show(toggle);
toggle =
gtk_radio_button_new_with_label(group,
drawtype == INDEXEDA_IMAGE ||
drawtype == INDEXED_IMAGE ?
"Set surroundings to index 0" :
"Set surroundings to background color");
group = gtk_radio_button_group(GTK_RADIO_BUTTON(toggle));
gtk_box_pack_start(GTK_BOX(vbox), toggle, FALSE, FALSE, 0);
gtk_signal_connect(GTK_OBJECT(toggle), "toggled",
(GtkSignalFunc) lens_toggle_update,
&lvals.use_bkgr);
gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(toggle), lvals.use_bkgr);
gtk_widget_show(toggle);
if((drawtype == INDEXEDA_IMAGE) ||
(drawtype == GRAYA_IMAGE) ||
(drawtype == RGBA_IMAGE)) {
toggle = gtk_radio_button_new_with_label(group,
"Make surroundings transparent");
group = gtk_radio_button_group(GTK_RADIO_BUTTON(toggle));
gtk_box_pack_start(GTK_BOX(vbox), toggle, FALSE, FALSE, 0);
gtk_signal_connect(GTK_OBJECT(toggle), "toggled",
(GtkSignalFunc) lens_toggle_update,
&lvals.set_transparent);
gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(toggle),
lvals.set_transparent);
gtk_widget_show(toggle);
}
hbox = gtk_hbox_new(FALSE, 5);
gtk_box_pack_start(GTK_BOX(vbox), hbox, TRUE, TRUE, 0);
label = gtk_label_new("Lens refraction index: ");
gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, FALSE, 0);
gtk_widget_show(label);
entry = gtk_entry_new();
gtk_box_pack_start(GTK_BOX(hbox), entry, TRUE, TRUE, 0);
gtk_widget_set_usize(entry, ENTRY_WIDTH, 0);
sprintf(buffer, "%.2f", lvals.refraction);
gtk_entry_set_text(GTK_ENTRY(entry), buffer);
gtk_signal_connect(GTK_OBJECT(entry), "changed",
(GtkSignalFunc)lens_entry_callback,
NULL);
gtk_widget_show(entry);
gtk_widget_show(hbox);
gtk_widget_show(vbox);
gtk_widget_show(frame);
gtk_widget_show(dlg);
gtk_main();
gdk_flush();
return bint.run;
}

View File

@ -1,271 +0,0 @@
/*
* Autocrop plug-in version 1.00
* by Tim Newsome <drz@froody.bloke.com>
* thanks to quartic for finding a nasty bug for me
*/
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include "libgimp/gimp.h"
#include "gtk/gtk.h"
/* Declare local functions. */
static void query(void);
static void run(char *name,
int nparams,
GParam * param,
int *nreturn_vals,
GParam ** return_vals);
static int colors_equal(gchar *col1, gchar *col2, int bytes);
static int guess_bgcolor(GPixelRgn *pr, int width, int height, int bytes,
gchar *color);
static void doit(GDrawable *drawable, gint32);
GPlugInInfo PLUG_IN_INFO =
{
NULL, /* init_proc */
NULL, /* quit_proc */
query, /* query_proc */
run, /* run_proc */
};
gint bytes;
gint sx1, sy1, sx2, sy2;
int run_flag = 0;
MAIN()
static void query()
{
static GParamDef args[] =
{
{PARAM_INT32, "run_mode", "Interactive, non-interactive"},
{PARAM_IMAGE, "image", "Input image"},
{PARAM_DRAWABLE, "drawable", "Input drawable"},
};
static GParamDef *return_vals = NULL;
static int nargs = sizeof(args) / sizeof(args[0]);
static int nreturn_vals = 0;
gimp_install_procedure("plug_in_autocrop",
"Automagically crops a picture.",
"",
"Tim Newsome",
"Tim Newsome",
"1997",
"<Image>/Filters/Transforms/Autocrop",
"RGB*, GRAY*, INDEXED*",
PROC_PLUG_IN,
nargs, nreturn_vals,
args, return_vals);
}
static void run(char *name, int n_params, GParam * param, int *nreturn_vals,
GParam ** return_vals)
{
static GParam values[1];
GDrawable *drawable;
GRunModeType run_mode;
GStatusType status = STATUS_SUCCESS;
gint32 image_id;
*nreturn_vals = 1;
*return_vals = values;
run_mode = param[0].data.d_int32;
if (run_mode == RUN_NONINTERACTIVE) {
if (n_params != 3) {
status = STATUS_CALLING_ERROR;
}
}
if (status == STATUS_SUCCESS) {
/* Get the specified drawable */
drawable = gimp_drawable_get(param[2].data.d_drawable);
image_id = param[1].data.d_image;
/* Make sure that the drawable is gray or RGB color */
if (gimp_drawable_color(drawable->id) ||
gimp_drawable_gray(drawable->id) ||
gimp_drawable_indexed(drawable->id)) {
gimp_progress_init("Cropping...");
gimp_tile_cache_ntiles(2 * (drawable->width / gimp_tile_width() + 1));
srand(time(NULL));
doit(drawable, image_id);
if (run_mode != RUN_NONINTERACTIVE)
gimp_displays_flush();
/* if (run_mode == RUN_INTERACTIVE)
gimp_set_data("plug_in_autocrop", &my_config, sizeof(my_config)); */
} else {
status = STATUS_EXECUTION_ERROR;
}
/*gimp_drawable_detach(drawable);*/
}
values[0].type = PARAM_STATUS;
values[0].data.d_status = status;
}
static void doit(GDrawable *drawable, gint32 image_id)
{
GPixelRgn srcPR;
gint width, height;
int x, y, abort;
gint32 nx, ny, nw, nh;
guchar *buffer;
guchar color[4] = {0, 0, 0, 0};
int nreturn_vals;
width = drawable->width;
height = drawable->height;
bytes = drawable->bpp;
nx = 0;
ny = 0;
nw = width;
nh = height;
/* initialize the pixel regions */
gimp_pixel_rgn_init(&srcPR, drawable, 0, 0, width, height, FALSE, FALSE);
/* First, let's figure out what exactly to crop. */
buffer = malloc((width > height ? width : height) * bytes);
guess_bgcolor(&srcPR, width, height, bytes, color);
/* Check how many of the top lines are uniform. */
abort = 0;
for (y = 0; y < height && !abort; y++) {
gimp_pixel_rgn_get_row(&srcPR, buffer, 0, y, width);
for (x = 0; x < width && !abort; x++) {
abort = !colors_equal(color, buffer + x * bytes, bytes);
}
}
if (y == height) {
free(buffer);
}
y--;
ny = y;
nh = height - y;
gimp_progress_update(.25);
/* Check how many of the bottom lines are uniform. */
abort = 0;
for (y = height - 1; y >= 0 && !abort; y--) {
gimp_pixel_rgn_get_row(&srcPR, buffer, 0, y, width);
for (x = 0; x < width && !abort; x++) {
abort = !colors_equal(color, buffer + x * bytes, bytes);
}
}
nh = y - ny + 2;
gimp_progress_update(.5);
/* Check how many of the left lines are uniform. */
abort = 0;
for (x = 0; x < width && !abort; x++) {
gimp_pixel_rgn_get_col(&srcPR, buffer, x, ny, nh);
for (y = 0; y < nh && !abort; y++) {
abort = !colors_equal(color, buffer + y * bytes, bytes);
}
}
x--;
nx = x;
nw = width - x;
gimp_progress_update(.75);
/* Check how many of the right lines are uniform. */
abort = 0;
for (x = width - 1; x >= 0 && !abort; x--) {
gimp_pixel_rgn_get_col(&srcPR, buffer, x, ny, nh);
for (y = 0; y < nh && !abort; y++) {
abort = !colors_equal(color, buffer + y * bytes, bytes);
}
}
nw = x - nx + 2;
free(buffer);
gimp_drawable_detach(drawable);
if (nw != width || nh != height) {
gimp_run_procedure("gimp_crop", &nreturn_vals,
PARAM_IMAGE, image_id,
PARAM_INT32, nw,
PARAM_INT32, nh,
PARAM_INT32, nx,
PARAM_INT32, ny,
PARAM_END);
}
/* update the timred region */
/*gimp_drawable_merge_shadow(drawable->id, TRUE);*/
gimp_displays_flush();
}
static int guess_bgcolor(GPixelRgn *pr, int width, int height, int bytes,
gchar *color) {
gchar tl[4], tr[4], bl[4], br[4];
gimp_pixel_rgn_get_pixel(pr, tl, 0, 0);
gimp_pixel_rgn_get_pixel(pr, tr, width - 1, 0);
gimp_pixel_rgn_get_pixel(pr, bl, 0, height - 1);
gimp_pixel_rgn_get_pixel(pr, br, width - 1, height - 1);
/* Algorithm pinched from pnmcrop.
* To guess the background, first see if 3 corners are equal.
* Then if two are equal.
* Otherwise average the colors.
*/
if (colors_equal(tr, bl, bytes) && colors_equal(tr, br, bytes)) {
memcpy(color, tr, bytes);
return 3;
} else if (colors_equal(tl, bl, bytes) && colors_equal(tl, br, bytes)) {
memcpy(color, tl, bytes);
return 3;
} else if (colors_equal(tl, tr, bytes) && colors_equal(tl, br, bytes)) {
memcpy(color, tl, bytes);
return 3;
} else if (colors_equal(tl, tr, bytes) && colors_equal(tl, bl, bytes)) {
memcpy(color, tl, bytes);
return 3;
} else if (colors_equal(tl, tr, bytes) || colors_equal(tl, bl, bytes) ||
colors_equal(tl, br, bytes)) {
memcpy(color, tl, bytes);
return 2;
} else if (colors_equal(tr, bl, bytes) || colors_equal(tr, bl, bytes)) {
memcpy(color, tr, bytes);
return 2;
} else if (colors_equal(br, bl, bytes)) {
memcpy(color, br, bytes);
return 2;
} else {
while (bytes--) {
color[bytes] = (tl[bytes] + tr[bytes] + bl[bytes] + br[bytes]) / 4;
}
return 0;
}
}
static int colors_equal(gchar *col1, gchar *col2, int bytes) {
int equal = 1;
int b;
for (b = 0; b < bytes; b++) {
if (col1[b] != col2[b]) {
equal = 0;
break;
}
}
return equal;
}

View File

@ -1,434 +0,0 @@
/* Autostretch HSV 0.10 --- image filter plug-in for The Gimp image
* manipulation program
*
* Copyright (C) 1997 Scott Goehring
* Copyright (C) 1996 Federico Mena Quintero
*
* You can contact me at scott@poverty.bloomington.in.us
* You can contact the original The Gimp authors at gimp@xcf.berkeley.edu
*
* 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
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/* This simple plug-in does an automatic contrast stretch. For each
channel in the image, it finds the minimum and maximum values... it
uses those values to stretch the individual histograms to the full
contrast range. For some images it may do just what you want; for
others it may be total crap :) This version operates in HSV space
and preserves hue, unlike the original Contrast Autostretch. */
#include <stdlib.h>
#include <stdio.h>
#include "libgimp/gimp.h"
/* Declare local functions.
*/
static void query (void);
static void run (char *name,
int nparams,
GParam *param,
int *nreturn_vals,
GParam **return_vals);
static void autostretch_hsv (GDrawable * drawable);
static void indexed_autostretch_hsv (gint32 image_ID);
static void calc_rgb_to_hsv(guchar *rgb, double *h, double *s, double *v);
static void calc_hsv_to_rgb(guchar *rgb, double h, double s, double v);
GPlugInInfo PLUG_IN_INFO =
{
NULL, /* init_proc */
NULL, /* quit_proc */
query, /* query_proc */
run, /* run_proc */
};
MAIN ()
static void
query ()
{
static GParamDef args[] =
{
{ PARAM_INT32, "run_mode", "Interactive, non-interactive" },
{ PARAM_IMAGE, "image", "Input image" },
{ PARAM_DRAWABLE, "drawable", "Input drawable" },
};
static GParamDef *return_vals = NULL;
static int nargs = sizeof (args) / sizeof (args[0]);
static int nreturn_vals = 0;
gimp_install_procedure ("plug_in_autostretch_hsv",
"Automatically stretch the contrast of the specified drawable to cover all possible ranges.",
"This simple plug-in does an automatic contrast stretch. For each channel in the image, it finds the minimum and maximum values... it uses those values to stretch the individual histograms to the full contrast range. For some images it may do just what you want; for others it may be total crap :). This version differs from Contrast Autostretch in that it works in HSV space, and preserves hue.",
"Scott Goehring and Federico Mena Quintero",
"Scott Goehring and Federico Mena Quintero",
"1997",
"<Image>/Filters/Image/Auto-Stretch HSV",
"RGB*, INDEXED*",
PROC_PLUG_IN,
nargs, nreturn_vals,
args, return_vals);
}
static void
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;
gint32 image_ID;
run_mode = param[0].data.d_int32;
/* Get the specified drawable */
drawable = gimp_drawable_get (param[2].data.d_drawable);
image_ID = param[1].data.d_image;
/* Make sure that the drawable is gray or RGB color */
if (gimp_drawable_color (drawable->id) || gimp_drawable_gray (drawable->id))
{
gimp_progress_init ("Auto-Stretching Contrast...");
gimp_tile_cache_ntiles (2 * (drawable->width / gimp_tile_width () + 1));
autostretch_hsv (drawable);
if (run_mode != RUN_NONINTERACTIVE)
gimp_displays_flush ();
}
else if (gimp_drawable_indexed (drawable->id))
{
indexed_autostretch_hsv (image_ID);
/* GIMP doesn't implicitly update an image whose cmap has
changed - it probably should. */
gimp_drawable_update (drawable->id, 0, 0,
gimp_drawable_width(drawable->id),
gimp_drawable_height(drawable->id));
gimp_displays_flush ();
}
else
{
/* gimp_message ("autostretch_hsv: cannot operate on indexed color images"); */
status = STATUS_EXECUTION_ERROR;
}
*nreturn_vals = 1;
*return_vals = values;
values[0].type = PARAM_STATUS;
values[0].data.d_status = status;
gimp_drawable_detach (drawable);
}
static void
indexed_autostretch_hsv(gint32 image_ID) /* a.d.m. */
{
guchar *cmap;
gint ncols,i;
double shi = 0.0, vhi = 0.0, slo = 1.0, vlo = 1.0;
cmap = gimp_image_get_cmap (image_ID, &ncols);
if (cmap==NULL)
{
printf("autostretch_hsv: cmap was NULL! Quitting...\n");
gimp_quit();
}
for (i=0;i<ncols;i++)
{
double h, s, v;
calc_rgb_to_hsv(&cmap[i*3], &h, &s, &v);
if (s > shi) shi = s;
if (s < slo) slo = s;
if (v > vhi) vhi = v;
if (v < vlo) vlo = v;
}
for (i=0;i<ncols;i++)
{
double h, s, v;
calc_rgb_to_hsv(&cmap[i*3], &h, &s, &v);
if (shi!=slo)
s = (s-slo) / (shi-slo);
if (vhi!=vlo)
v = (v-vlo) / (vhi-vlo);
calc_hsv_to_rgb(&cmap[i*3], h, s, v);
}
gimp_image_set_cmap (image_ID, cmap, ncols);
}
static void
autostretch_hsv (GDrawable *drawable)
{
GPixelRgn src_rgn, dest_rgn;
guchar *src, *s;
guchar *dest, *d;
double shi = 0.0, slo = 1.0, vhi = 0.0, vlo = 1.0;
gint progress, max_progress;
gint has_alpha, alpha;
gint x1, y1, x2, y2;
gint x, y, b;
gpointer pr;
/* Get selection area */
gimp_drawable_mask_bounds (drawable->id, &x1, &y1, &x2, &y2);
has_alpha = gimp_drawable_has_alpha (drawable->id);
alpha = (has_alpha) ? drawable->bpp - 1 : drawable->bpp;
/* Initialize progress */
progress = 0;
max_progress = (x2 - x1) * (y2 - y1) * 2;
gimp_pixel_rgn_init (&src_rgn, drawable, x1, y1, (x2 - x1), (y2 - y1), FALSE, FALSE);
for (pr = gimp_pixel_rgns_register (1, &src_rgn); pr != NULL; pr = gimp_pixel_rgns_process (pr))
{
src = src_rgn.data;
for (y = 0; y < src_rgn.h; y++)
{
s = src;
for (x = 0; x < src_rgn.w; x++)
{
if (!has_alpha || (has_alpha && s[alpha]))
{
double h, z, v;
calc_rgb_to_hsv(s, &h, &z, &v);
if (z > shi) shi = z;
if (z < slo) slo = z;
if (v > vhi) vhi = v;
if (v < vlo) vlo = v;
}
s += src_rgn.bpp;
}
src += src_rgn.rowstride;
}
/* Update progress */
progress += src_rgn.w * src_rgn.h;
gimp_progress_update ((double) progress / (double) max_progress);
}
/* Now substitute pixel vales */
gimp_pixel_rgn_init (&src_rgn, drawable, x1, y1, (x2 - x1), (y2 - y1), FALSE, FALSE);
gimp_pixel_rgn_init (&dest_rgn, drawable, x1, y1, (x2 - x1), (y2 - y1), TRUE, TRUE);
for (pr = gimp_pixel_rgns_register (2, &src_rgn, &dest_rgn); pr != NULL; pr = gimp_pixel_rgns_process (pr))
{
src = src_rgn.data;
dest = dest_rgn.data;
for (y = 0; y < src_rgn.h; y++)
{
s = src;
d = dest;
for (x = 0; x < src_rgn.w; x++)
{
double h, z, v;
calc_rgb_to_hsv(s, &h, &z, &v);
if (shi!=slo)
z = (z-slo) / (shi-slo);
if (vhi!=vlo)
v = (v-vlo) / (vhi-vlo);
calc_hsv_to_rgb(d, h, z, v);
if (has_alpha)
d[alpha] = s[alpha];
s += src_rgn.bpp;
d += dest_rgn.bpp;
}
src += src_rgn.rowstride;
dest += dest_rgn.rowstride;
}
/* Update progress */
progress += src_rgn.w * src_rgn.h;
gimp_progress_update ((double) progress / (double) max_progress);
}
/* update the region */
gimp_drawable_flush (drawable);
gimp_drawable_merge_shadow (drawable->id, TRUE);
gimp_drawable_update (drawable->id, x1, y1, (x2 - x1), (y2 - y1));
}
static void
calc_rgb_to_hsv(guchar *rgb, double *hue, double *sat, double *val)
{
double red, green, blue;
double h, s, v;
double min, max;
double delta;
red = rgb[0] / 255.0;
green = rgb[1] / 255.0;
blue = rgb[2] / 255.0;
h = 0.0; /* Shut up -Wall */
if (red > green)
{
if (red > blue)
max = red;
else
max = blue;
if (green < blue)
min = green;
else
min = blue;
}
else
{
if (green > blue)
max = green;
else
max = blue;
if (red < blue)
min = red;
else
min = blue;
}
v = max;
if (max != 0.0)
s = (max - min) / max;
else
s = 0.0;
if (s == 0.0)
h = 0.0;
else
{
delta = max - min;
if (red == max)
h = (green - blue) / delta;
else if (green == max)
h = 2 + (blue - red) / delta;
else if (blue == max)
h = 4 + (red - green) / delta;
h /= 6.0;
if (h < 0.0)
h += 1.0;
else if (h > 1.0)
h -= 1.0;
}
*hue = h;
*sat = s;
*val = v;
}
static void
calc_hsv_to_rgb(guchar *rgb, double h, double s, double v)
{
double hue, saturation, value;
double f, p, q, t;
if (s == 0.0)
{
h = v;
s = v;
v = v; /* heh */
}
else
{
hue = h * 6.0;
saturation = s;
value = v;
if (hue == 6.0)
hue = 0.0;
f = hue - (int) hue;
p = value * (1.0 - saturation);
q = value * (1.0 - saturation * f);
t = value * (1.0 - saturation * (1.0 - f));
switch ((int) hue)
{
case 0:
h = value;
s = t;
v = p;
break;
case 1:
h = q;
s = value;
v = p;
break;
case 2:
h = p;
s = value;
v = t;
break;
case 3:
h = p;
s = q;
v = value;
break;
case 4:
h = t;
s = p;
v = value;
break;
case 5:
h = value;
s = p;
v = q;
break;
}
}
rgb[0] = h*255;
rgb[1] = s*255;
rgb[2] = v*255;
}

File diff suppressed because it is too large Load Diff

View File

@ -1,254 +0,0 @@
/* The GIMP -- an image manipulation program
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* 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
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <stdlib.h>
#include "libgimp/gimp.h"
/* Declare local functions.
*/
static void query (void);
static void run (char *name,
int nparams,
GParam *param,
int *nreturn_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 =
{
NULL, /* init_proc */
NULL, /* quit_proc */
query, /* query_proc */
run, /* run_proc */
};
MAIN ()
static void
query ()
{
static GParamDef args[] =
{
{ PARAM_INT32, "run_mode", "Interactive, non-interactive" },
{ PARAM_IMAGE, "image", "Input image (unused)" },
{ PARAM_DRAWABLE, "drawable", "Input drawable" },
};
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",
"<Image>/Filters/Blur/Blur",
"RGB*, GRAY*",
PROC_PLUG_IN,
nargs, nreturn_vals,
args, return_vals);
}
static void
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;
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;
values[0].type = PARAM_STATUS;
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)
{
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++)
{
data[-pixel_rgn->bpp + b] = data[b];
data[w * pixel_rgn->bpp + b] = data[(w - 1) * pixel_rgn->bpp + b];
}
}
static void
blur (GDrawable *drawable)
{
GPixelRgn srcPR, destPR;
gint width, height;
gint bytes;
guchar *dest, *d;
guchar *prev_row, *pr;
guchar *cur_row, *cr;
guchar *next_row, *nr;
guchar *tmp;
gint row, col;
gint x1, y1, x2, y2;
gint has_alpha, ind;
/* 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.
*/
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);
/* 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);
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++)
{
/* prepare the next row */
blur_prepare_row (&srcPR, nr, x1, row + 1, (x2 - x1));
d = dest;
ind = 0;
for (col = 0; col < (x2 - x1) * bytes; col++)
{
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 */
*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])
+ (gdouble) (cr[col - bytes] * cr[col - ind])
+ (gdouble) (cr[col] * cr[col + bytes - ind])
+ (gdouble) (cr[col + bytes] * cr[col + 2*bytes - ind])
+ (gdouble) (nr[col - bytes] * nr[col - ind])
+ (gdouble) (nr[col] * nr[col + bytes - ind])
+ (gdouble) (nr[col + bytes] * nr[col + 2*bytes - ind]))
/ ((gdouble) pr[col - ind]
+ (gdouble) pr[col + bytes - ind]
+ (gdouble) pr[col + 2*bytes - ind]
+ (gdouble) cr[col - ind]
+ (gdouble) cr[col + bytes - ind]
+ (gdouble) cr[col + 2*bytes - ind]
+ (gdouble) nr[col - ind]
+ (gdouble) nr[col + bytes - ind]
+ (gdouble) nr[col + 2*bytes - ind])));
}
}
/* store the dest */
gimp_pixel_rgn_set_row (&destPR, 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));
}
/* 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);
}

View File

@ -1,544 +0,0 @@
/*
* This is a plug-in for the GIMP.
*
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
* Copyright (C) 1996 Torsten Martinsen
*
* 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
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id$
*/
/*
* This filter is like the standard 'blur', except that it uses
* a convolution kernel of variable size.
*
* I am greatly indebted to Johan Klockars <d8klojo@dtek.chalmers.se>
* for supplying the algorithm used here, which is of complexity O(1).
* Compared with the original naive algorithm, which is O(k^2) (where
* k is the kernel size), it gives _massive_ speed improvements.
* The code is quite simple, too.
*/
#include <stdlib.h>
#include <stdio.h> /**/
#include "gtk/gtk.h"
#include "libgimp/gimp.h"
#define ENTRY_WIDTH 30
#define SCALE_WIDTH 125
typedef struct {
gdouble mask_size;
} BlurVals;
typedef struct {
gint run;
} BlurInterface;
/* Declare local functions.
*/
static void query(void);
static void run(char *name,
int nparams,
GParam * param,
int *nreturn_vals,
GParam ** return_vals);
static void blur(GDrawable * drawable);
static gint blur2_dialog ();
static void blur2_close_callback (GtkWidget *widget,
gpointer data);
static void blur2_ok_callback (GtkWidget *widget,
gpointer data);
static void blur2_scale_update (GtkAdjustment *adjustment,
double *scale_val);
static void blur2_entry_update (GtkWidget *widget,
gdouble *value);
static void dialog_create_value (char *title,
GtkTable *table,
int row,
gdouble *value,
double left,
double right);
GPlugInInfo PLUG_IN_INFO =
{
NULL, /* init_proc */
NULL, /* quit_proc */
query, /* query_proc */
run, /* run_proc */
};
static BlurVals bvals =
{
6+5.0 /* mask size */
};
static BlurInterface bint =
{
FALSE /* run */
};
MAIN()
static void
query()
{
static GParamDef args[] =
{
{PARAM_INT32, "run_mode", "Interactive, non-interactive"},
{PARAM_IMAGE, "image", "Input image (unused)"},
{PARAM_DRAWABLE, "drawable", "Input drawable"},
{PARAM_INT32, "mask_size", "Blur mask size"},
};
static GParamDef *return_vals = NULL;
static int nargs = sizeof(args) / sizeof(args[0]);
static int nreturn_vals = 0;
gimp_install_procedure("plug_in_blur2",
"Blur the contents of the specified drawable",
"This function applies a NxN blurring convolution kernel to the specified drawable.",
"Torsten Martinsen",
"Torsten Martinsen",
"1996-1997",
"<Image>/Filters/Blur/Variable Blur",
"RGB, GRAY",
PROC_PLUG_IN,
nargs, nreturn_vals,
args, return_vals);
}
static void
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;
run_mode = param[0].data.d_int32;
switch (run_mode) {
case RUN_INTERACTIVE:
/* Possibly retrieve data */
gimp_get_data("plug_in_blur2", &bvals);
/* First acquire information with a dialog */
if (!blur2_dialog())
return;
break;
case RUN_NONINTERACTIVE:
/* Make sure all the arguments are there! */
if (nparams != 4)
status = STATUS_CALLING_ERROR;
if (status == STATUS_SUCCESS) {
bvals.mask_size = (gdouble) param[3].data.d_int32;
}
if (status == STATUS_SUCCESS &&
(bvals.mask_size < 1.0))
status = STATUS_CALLING_ERROR;
break;
case RUN_WITH_LAST_VALS:
/* Possibly retrieve data */
gimp_get_data("plug_in_blur2", &bvals);
break;
default:
break;
}
/* 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("Variable Blur");
gimp_tile_cache_ntiles(2 * (drawable->width / gimp_tile_width() + 1));
blur(drawable);
if (run_mode != RUN_NONINTERACTIVE)
gimp_displays_flush();
/* Store data */
if (run_mode == RUN_INTERACTIVE)
gimp_set_data ("plug_in_blur2", &bvals, sizeof (BlurVals));
} else {
/* gimp_message ("blur2: cannot operate on indexed color images"); */
status = STATUS_EXECUTION_ERROR;
}
*nreturn_vals = 1;
*return_vals = values;
values[0].type = PARAM_STATUS;
values[0].data.d_status = status;
gimp_drawable_detach(drawable);
}
static void
blur(GDrawable * drawable)
{
GPixelRgn srcPR, destPR;
gint width, height;
gint bytes;
guchar *dest, *d;
guchar *cr, *cc;
gint sum[4];
gint row, col, i, n, div;
gint x1, y1, x2, y2;
/* 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).
*/
width = drawable->width;
height = drawable->height;
bytes = drawable->bpp;
n = bvals.mask_size;
/* Include edges if possible */
x1 = MAX(x1 - n / 2, 0);
x2 = MIN(x2 + n / 2 + 1, width);
y1 = MAX(y1 - n / 2, 0);
y2 = MIN(y2 + n / 2 + 1, height);
/* 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);
/* allocate row buffers */
cr = (guchar *) malloc((x2 - x1 + 2) * bytes);
dest = (guchar *) malloc((x2 - x1) * bytes);
/* loop through the rows, applying horizontal blur */
for (row = y1; row < y2; row++) {
gimp_pixel_rgn_get_row(&srcPR, cr, x1, row, (x2 - x1));
d = dest + bytes * (n / 2);
for (i = 0; i < bytes; ++i)
sum[i] = 0;
for (i = 0; i < n * bytes; ++i)
sum[i % bytes] += cr[i];
for (col = 0; col < (x2 - x1 - n) * bytes; col++) {
sum[col % bytes] += cr[col + n * bytes] - cr[col];
*d++ = sum[col % bytes]/n;
}
/* store the dest */
gimp_pixel_rgn_set_row(&destPR, dest, x1, row, (x2 - x1));
if ((row % 5) == 0)
gimp_progress_update((double) (row/2) / (double) (x2 - x1));
}
free(cr);
free(dest);
cc = (guchar *) malloc((y2 - y1 + 2) * bytes);
dest = (guchar *) malloc((y2 - y1) * bytes);
/* loop through the columns, applying vertical blur */
for (col = x1; col < x2; col++) {
gimp_pixel_rgn_get_col(&destPR, cc, col, y1, (y2 - y1));
d = dest + bytes * (n / 2);
for (i = 0; i < bytes; ++i)
sum[i] = 0;
for (i = 0; i < n * bytes; ++i)
sum[i % bytes] += cc[i];
for (row = 0; row < (y2 - y1 - n) * bytes; row++) {
sum[row % bytes] += cc[row + n * bytes] - cc[row];
*d++ = sum[row % bytes]/n;
}
/* store the dest */
gimp_pixel_rgn_set_col(&destPR, dest, col, y1, (y2 - y1));
if ((col % 5) == 0)
gimp_progress_update(((double) (x2-x1)/2+(col/2)) / (double) (x2-x1));
}
div = n/2+1;
if (y1-n/2 < 0)
for (col = x1; col < x2; ++col) {
gimp_pixel_rgn_get_col(&srcPR, cc, col, 0, div);
gimp_pixel_rgn_set_col(&destPR, cc, col, 0, div);
}
if (y2+n/2 > height)
for (col = x1; col < x2; ++col) {
gimp_pixel_rgn_get_col(&srcPR, cc, col, height-div, div);
gimp_pixel_rgn_set_col(&destPR, cc, col, height-div, div);
}
if (x1-n/2 < 0)
for (row = y1; row < y2; ++row) {
gimp_pixel_rgn_get_row(&srcPR, cr, 0, row, div);
gimp_pixel_rgn_set_row(&destPR, cr, 0, row, div);
}
if (x2+n/2 > width)
for (row = y1; row < y2; ++row) {
gimp_pixel_rgn_get_row(&srcPR, cr, width-div, row, div);
gimp_pixel_rgn_set_row(&destPR, cr, width-div, row, div);
}
#if 0
/* Do remaining top pixels, if any */
if (y1-n/2 < 0) {
for (col = x1; col < x2; ++col) {
div = n/2+1;
gimp_pixel_rgn_get_col(&srcPR, cc, col, 0, div);
d = dest;
s = cc;
for (i = 0; i < bytes; ++i)
sum[i] = 0;
for (i = 0; i < div * bytes; ++i)
sum[i % bytes] += *s++;
memset(dest, 0, (y2 - y1) * bytes);
for (i = 0; i < bytes; ++i)
*d++ = sum[i]/div;
for (row = 0; row < n/2; ++row) {
++div;
for (i = 0; i < bytes; ++i) {
sum[i] += *s++;
*d++ = sum[i]/div;
}
}
gimp_pixel_rgn_set_col(&destPR, dest, col, 0, n/2+1);
}
}
/* Do remaining bottom pixels, if any */
if (y2+n/2 > height) {
for (col = x1; col < x2; ++col) {
div = n/2+1;
gimp_pixel_rgn_get_col(&srcPR, cc, col, height-1-div, div);
s = cc+div*bytes-1;
d = dest+div*bytes-1; /* points to last byte */
for (i = 0; i < bytes; ++i)
sum[i] = 0;
for (i = 0; i < div * bytes; ++i)
sum[i % bytes] += *s--;
for (i = 0; i < bytes; ++i)
*d-- = sum[i]/div;
for (row = 0; row < n/2; ++row) {
for (i = 0; i < bytes; ++i) {
sum[i] += *s--;
*d-- = sum[i]/div;
}
++div;
}
gimp_pixel_rgn_set_col(&destPR, dest, col, height-1-div, n/2+1);
}
}
#endif
free(cc);
free(dest);
/* 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));
}
static gint
blur2_dialog ()
{
GtkWidget *dlg;
GtkWidget *button;
GtkWidget *frame;
GtkWidget *table;
gchar **argv;
gint argc;
argc = 1;
argv = g_new (gchar *, 1);
argv[0] = g_strdup ("blur2");
gtk_init (&argc, &argv);
dlg = gtk_dialog_new ();
gtk_window_set_title (GTK_WINDOW (dlg), "Variable Blur");
gtk_window_position (GTK_WINDOW (dlg), GTK_WIN_POS_MOUSE);
gtk_signal_connect (GTK_OBJECT (dlg), "destroy",
(GtkSignalFunc) blur2_close_callback,
NULL);
/* Action area */
button = gtk_button_new_with_label ("OK");
GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
gtk_signal_connect (GTK_OBJECT (button), "clicked",
(GtkSignalFunc) blur2_ok_callback,
dlg);
gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dlg)->action_area), button, TRUE, TRUE, 0);
gtk_widget_grab_default (button);
gtk_widget_show (button);
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));
gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dlg)->action_area), button, TRUE, TRUE, 0);
gtk_widget_show (button);
/* parameter settings */
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 (3, 3, FALSE);
gtk_container_border_width (GTK_CONTAINER (table), 10);
gtk_container_add (GTK_CONTAINER (frame), table);
dialog_create_value("Mask Size", GTK_TABLE(table), 1, &bvals.mask_size, 3.0, 50.0);
gtk_widget_show (frame);
gtk_widget_show (table);
gtk_widget_show (dlg);
gtk_main ();
gdk_flush ();
return bint.run;
}
static void
blur2_close_callback (GtkWidget *widget,
gpointer data)
{
gtk_main_quit ();
}
static void
blur2_ok_callback (GtkWidget *widget,
gpointer data)
{
bint.run = TRUE;
gtk_widget_destroy (GTK_WIDGET (data));
}
/*
* Thanks to Quartic for these.
*/
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) blur2_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) blur2_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
blur2_entry_update(GtkWidget *widget, gdouble *value)
{
GtkAdjustment *adjustment;
gdouble new_value;
new_value = atof(gtk_entry_get_text(GTK_ENTRY(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 */
}
static void
blur2_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 */
}

View File

@ -1,165 +0,0 @@
/* bmp.c */
/* This is a File input and output filter for */
/* Gimp. It loads and saves images in windows(TM) */
/* bitmap format. */
/* Some Parts that deal with the interaction with */
/* the Gimp are taken from the GIF plugin by */
/* Peter Mattis & Spencer Kimball and from the */
/* PCX plugin by Francisco Bustamante. */
/* */
/* Alexander.Schulz@stud.uni-karlsruhe.de */
#include <string.h>
#include <libgimp/gimp.h>
#include <gtk/gtk.h>
#include <stdio.h>
#include <stdlib.h>
#include "bmp.h"
FILE *errorfile;
char *prog_name="bmp";
char *filename;
int interactive_bmp;
/* Declare some local functions.
*/
static void query (void);
static void run (char *name,
int nparams,
GParam *param,
int *nreturn_vals,
GParam **return_vals);
GPlugInInfo PLUG_IN_INFO =
{
NULL, /* init_proc */
NULL, /* quit_proc */
query, /* query_proc */
run, /* run_proc */
};
MAIN ()
static void
query ()
{
static GParamDef load_args[] =
{
{ PARAM_INT32, "run_mode", "Interactive, non-interactive" },
{ PARAM_STRING, "filename", "The name of the file to load" },
{ PARAM_STRING, "raw_filename", "The name entered" },
};
static GParamDef load_return_vals[] =
{
{ PARAM_IMAGE, "image", "Output image" },
};
static int nload_args = sizeof (load_args) / sizeof (load_args[0]);
static int nload_return_vals = sizeof (load_return_vals) / sizeof (load_return_vals[0]);
static GParamDef save_args[] =
{
{ PARAM_INT32, "run_mode", "Interactive, non-interactive" },
{ PARAM_IMAGE, "image", "Input image" },
{ PARAM_DRAWABLE, "drawable", "Drawable to save" },
{ PARAM_STRING, "filename", "The name of the file to save the image in" },
{ PARAM_STRING, "raw_filename", "The name entered" },
};
static int nsave_args = sizeof (save_args) / sizeof (save_args[0]);
gimp_install_procedure ("file_bmp_load",
"Loads files of Windows BMP file format",
"Loads files of Windows BMP file format",
"Alexander Schulz",
"Alexander Schulz",
"1997",
"<Load>/BMP",
NULL,
PROC_PLUG_IN,
nload_args, nload_return_vals,
load_args, load_return_vals);
gimp_install_procedure ("file_bmp_save",
"Saves files in Windows BMP file format",
"Saves files in Windows BMP file format",
"Alexander Schulz",
"Alexander Schulz",
"1997",
"<Save>/BMP",
"INDEXED*, GRAY*, RGB*",
PROC_PLUG_IN,
nsave_args, 0,
save_args, NULL);
gimp_register_magic_load_handler ("file_bmp_load", "bmp", "", "0,string,BM");
gimp_register_save_handler ("file_bmp_save", "bmp", "");
}
static void
run (char *name,
int nparams,
GParam *param,
int *nreturn_vals,
GParam **return_vals)
{
static GParam values[2];
GStatusType status = STATUS_SUCCESS;
GRunModeType run_mode;
gint32 image_ID;
run_mode = param[0].data.d_int32;
*nreturn_vals = 1;
*return_vals = values;
values[0].type = PARAM_STATUS;
values[0].data.d_status = STATUS_CALLING_ERROR;
if (strcmp (name, "file_bmp_load") == 0)
{
image_ID = ReadBMP(param[1].data.d_string);
if (image_ID != -1)
{
*nreturn_vals = 2;
values[0].data.d_status = STATUS_SUCCESS;
values[1].type = PARAM_IMAGE;
values[1].data.d_image = image_ID;
}
else
{
values[0].data.d_status = STATUS_EXECUTION_ERROR;
}
}
else if (strcmp (name, "file_bmp_save") == 0)
{
switch (run_mode)
{
case RUN_INTERACTIVE:
interactive_bmp = TRUE;
break;
case RUN_NONINTERACTIVE:
/* Make sure all the arguments are there! */
interactive_bmp = FALSE;
if (nparams != 5)
status = STATUS_CALLING_ERROR;
break;
case RUN_WITH_LAST_VALS:
interactive_bmp = FALSE;
break;
default:
break;
}
*nreturn_vals = 1;
if (WriteBMP(param[3].data.d_string, param[1].data.d_int32, param[2].data.d_int32))
{
values[0].data.d_status = STATUS_SUCCESS;
}
else
values[0].data.d_status = STATUS_EXECUTION_ERROR;
}
}

View File

@ -1,342 +0,0 @@
/* bmpread.c reads any bitmap I could get for testing */
/* except OS2 bitmaps (wrong colors) */
/* Alexander.Schulz@stud.uni-karlsruhe.de */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <libgimp/gimp.h>
#include <gtk/gtk.h>
#include "bmp.h"
gint32 ReadBMP (name)
char *name;
{
FILE *fd;
char *temp_buf;
char buf[5];
int ColormapSize, SpeicherZeile, Maps, Grey;
unsigned char ColorMap[256][3];
temp_buf = g_malloc (strlen (name) + 11);
sprintf (temp_buf, "Loading %s:", name);
gimp_progress_init (temp_buf);
g_free (temp_buf);
filename = name;
fd = fopen (filename, "rb");
/* Is this a valid File? Should never be used because gimp tests it. */
if (!fd)
{
printf ("%s: can't open \"%s\"\n", prog_name, filename);
return -1;
}
/* It is a File. Now is it a Bitmap? */
if (!ReadOK(fd,buf,2) || (strncmp(buf,"BM",2)))
{
printf ("%s: not a valid BMP file %s\n", prog_name,buf);
return -1;
}
/* How long is the Header? */
if (!ReadOK (fd, &Bitmap_File_Head, 0x10))
{
printf ("%s: error reading bitmap file header\n", prog_name);
return -1;
}
/* Is it a Windows (R) Bitmap or not */
if (Bitmap_File_Head.biSize!=40)
{
printf("\nos2 unsupported!\n");
if (!ReadOK (fd, &Bitmap_OS2_Head, Bitmap_File_Head.biSize))
{
printf ("%s: error reading bitmap header\n", prog_name);
return -1;
}
Bitmap_Head.biPlanes_biBitCnt=Bitmap_OS2_Head.bcPlanes_bcBitCnt;
Bitmap_File_Head.bfSize=(Bitmap_File_Head.bfSize*4)-(Bitmap_File_Head.bfOffs*3);
Bitmap_Head.biHeight=bcHeight;
Bitmap_Head.biWidth=bcWidth;
Bitmap_Head.biClrUsed=0;
Bitmap_Head.biCompr=0;
Maps=3;
}
else
{
if (!ReadOK (fd, &Bitmap_Head, 36))
{
printf ("\n%s: error reading bitmap header\n", prog_name);
return -1;
}
Maps=4;
}
/* This means wrong file Format. I test this because it could crash the */
/* entire gimp. */
if (biBitCnt>24)
{
printf("\n%s: to many colors: %u\n",prog_name,(unsigned int) biBitCnt);
return -1;
}
/* There should be some colors used! */
ColormapSize = (Bitmap_File_Head.bfOffs-Bitmap_File_Head.biSize-14) / Maps;
if ((Bitmap_Head.biClrUsed==0) && (biBitCnt<24)) Bitmap_Head.biClrUsed=ColormapSize;
if (biBitCnt==24) SpeicherZeile=((Bitmap_File_Head.bfSize-Bitmap_File_Head.bfOffs)/Bitmap_Head.biHeight);
else SpeicherZeile=((Bitmap_File_Head.bfSize-Bitmap_File_Head.bfOffs)/Bitmap_Head.biHeight)*(8/biBitCnt);
#ifdef DEBUG
printf("\nSize: %u, Colors: %u, Bits: %u, Width: %u, Height: %u, Comp: %u, Zeile: %u\n",
Bitmap_File_Head.bfSize,Bitmap_Head.biClrUsed,biBitCnt,Bitmap_Head.biWidth,
Bitmap_Head.biHeight, Bitmap_Head.biCompr, SpeicherZeile);
#endif
/* Get the Colormap */
if (ReadColorMap(fd, ColorMap, ColormapSize, Maps, &Grey) == -1) return -1;
#ifdef DEBUG
printf("Colormap read\n");
#endif
/* Get the Image and return the ID or -1 on error*/
return(ReadImage(fd, Bitmap_Head.biWidth, Bitmap_Head.biHeight, ColorMap,
Bitmap_Head.biClrUsed, biBitCnt, Bitmap_Head.biCompr, SpeicherZeile, Grey));
}
gint ReadColorMap (fd, buffer, number, size, grey)
FILE *fd;
int number;
unsigned char buffer[256][3];
int size;
int *grey;
{
int i;
unsigned char rgb[4];
*grey=(number>2);
for (i = 0; i < number ; i++)
{
if (!ReadOK (fd, rgb, size))
{
printf ("%s: bad colormap\n", prog_name);
return -1;
}
/* Bitmap save the colors in another order! But change only once! */
if (size==4) {
buffer[i][0] = rgb[2];
buffer[i][1] = rgb[1];
buffer[i][2] = rgb[0];
} else {
/* this one is for old os2 Bitmaps, but it dosn't work well */
buffer[i][0] = rgb[1];
buffer[i][1] = rgb[0];
buffer[i][2] = rgb[2];
}
*grey=((*grey) && (rgb[0]==rgb[1]) && (rgb[1]==rgb[2]));
}
return(0);
}
Image ReadImage (fd, len, height, cmap, ncols, bpp, compression, spzeile, grey)
FILE *fd;
int len, height;
unsigned char cmap[256][3];
int ncols, bpp, compression, spzeile, grey;
{
char *name_buf;
unsigned char v,wieviel;
GPixelRgn pixel_rgn;
char buf[16];
int xpos = 0, ypos = 0;
Image image;
gint32 layer;
GDrawable *drawable;
guchar *dest, *temp;
guchar gimp_cmap[768];
long rowstride, channels;
int i, j, cur_progress, max_progress, egal;
/* Make a new image in the gimp */
if (grey)
{
image = gimp_image_new (len, height, GRAY);
layer = gimp_layer_new (image, "Background", len, height, GRAY_IMAGE, 100, NORMAL_MODE);
channels = 1;
}
else
{
if (bpp<24)
{
image = gimp_image_new (len, height, INDEXED);
layer = gimp_layer_new (image, "Background", len, height, INDEXED_IMAGE, 100, NORMAL_MODE);
channels = 1;
}
else
{
image = gimp_image_new (len, height, RGB);
layer = gimp_layer_new (image, "Background", len, height, RGB_IMAGE, 100, NORMAL_MODE);
channels = 3;
}
}
name_buf = g_malloc (strlen (filename) + 10);
sprintf (name_buf, "%s", filename);
gimp_image_set_filename(image,name_buf);
free (name_buf);
gimp_image_add_layer(image,layer,0);
drawable = gimp_drawable_get(layer);
dest = g_malloc(drawable->width*drawable->height*channels);
rowstride = drawable->width * channels;
ypos=height-1; /* Bitmaps begin in the lower left corner */
cur_progress = 0;
max_progress = height;
if (bpp==24)
{
while (ReadOK(fd,buf,3))
{
temp = dest + (ypos * rowstride) + (xpos * channels);
*temp=buf[2];
temp++;
*temp=buf[1];
temp++;
*temp=buf[0];
xpos++;
if (xpos == len)
{
egal=ReadOK(fd,buf,spzeile-(len*3));
ypos--;
xpos=0;
cur_progress++;
if ((cur_progress % 5) == 0)
gimp_progress_update ((double) cur_progress / (double) max_progress);
}
if (ypos < 0) break;
}
}
else { switch(compression)
{
case 0: /* uncompressed */
{
while (ReadOK(fd,&v,1))
{
for (i=1;(i<=(8/bpp)) && (xpos<len);i++,xpos++)
{
temp = dest + (ypos * rowstride) + (xpos * channels);
/* look at my bitmask !! */
*temp=( v & ( ((1<<bpp)-1) << (8-(i*bpp)) ) ) >> (8-(i*bpp));
}
if (xpos == len)
{
egal=ReadOK(fd,buf,(spzeile-len)/(8/bpp));
ypos--;
xpos=0;
cur_progress++;
if ((cur_progress % 5) == 0)
gimp_progress_update ((double) cur_progress / (double) max_progress);
}
if (ypos < 0) break;
}
break;
}
default: /* Compressed images */
{
while (TRUE)
{
/*temp = dest + (ypos * rowstride) + (xpos * channels);*/
egal=ReadOK(fd,buf,2);
if ((unsigned char) buf[0]!=0)
/* Count + Color - record */
{
for (j=0;((unsigned char) j < (unsigned char) buf[0]) && (xpos<len);)
{
#ifdef DEBUG2
printf("%u %u | ",xpos,len);
#endif
for (i=1;((i<=(8/bpp)) && (xpos<len) && ((unsigned char) j < (unsigned char) buf[0]));i++,xpos++,j++)
{
temp = dest + (ypos * rowstride) + (xpos * channels);
*temp=( buf[1] & ( ((1<<bpp)-1) << (8-(i*bpp)) ) ) >> (8-(i*bpp));
}
}
}
if (((unsigned char) buf[0]==0) && ((unsigned char) buf[1]>2))
/* unkomprimierter record */
{
wieviel=buf[1];
for (j=0;j<wieviel;j+=(8/bpp))
{
egal=ReadOK(fd,&v,1);
i=1;
while ((i<=(8/bpp)) && (xpos<len))
{
temp = dest + (ypos * rowstride) + (xpos * channels);
*temp=(v & ( ((1<<bpp)-1) << (8-(i*bpp)) ) ) >> (8-(i*bpp));
i++;
xpos++;
}
}
if ( (wieviel / (8/bpp)) % 2) egal=ReadOK(fd,&v,1);
/*if odd(x div (8 div bpp )) then blockread(f,z^,1);*/
}
if (((unsigned char) buf[0]==0) && ((unsigned char) buf[1]==0))
/* Zeilenende */
{
ypos--;
xpos=0;
cur_progress++;
if ((cur_progress % 5) == 0)
gimp_progress_update ((double) cur_progress / (double) max_progress);
}
if (((unsigned char) buf[0]==0) && ((unsigned char) buf[1]==1))
/* Bitmapende */
{
break;
}
if (((unsigned char) buf[0]==0) && ((unsigned char) buf[1]==2))
/* Deltarecord */
{
xpos+=(unsigned char) buf[2];
ypos+=(unsigned char) buf[3];
}
}
break;
}
}}
fclose(fd);
if (bpp<24) for (i = 0, j = 0; i < ncols; i++)
{
gimp_cmap[j++] = cmap[i][0];
gimp_cmap[j++] = cmap[i][1];
gimp_cmap[j++] = cmap[i][2];
}
gimp_progress_update (1);
gimp_pixel_rgn_init(&pixel_rgn, drawable, 0, 0, drawable->width, drawable->height, TRUE, FALSE);
gimp_pixel_rgn_set_rect(&pixel_rgn, dest, 0, 0, drawable->width, drawable->height);
if (bpp<24) gimp_image_set_cmap(image, gimp_cmap, ncols);
gimp_drawable_flush(drawable);
gimp_drawable_detach(drawable);
g_free(dest);
return(image);
}

View File

@ -1,464 +0,0 @@
/* bmpwrite.c Writes Bitmap files. Even RLE encoded ones. */
/* (Windows (TM) doesn't read all of those, but who */
/* cares? ;-) */
/* Alexander.Schulz@stud.uni-karlsruhe.de */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <gtk/gtk.h>
#include <libgimp/gimp.h>
#include "bmp.h"
guchar *pixels;
int cur_progress;
int max_progress;
typedef struct
{
gint run;
} GIFSaveInterface;
static GIFSaveInterface gsint =
{
FALSE /* run */
};
int encoded = 0;
static gint save_dialog ();
static void save_close_callback (GtkWidget *widget,
gpointer data);
static void save_ok_callback (GtkWidget *widget,
gpointer data);
static void save_toggle_update (GtkWidget *widget,
gpointer data);
/*
static void item_callback (int, void *, void *);
static void ok_callback (int, void *, void *);
static void cancel_callback (int, void *, void *);
static int dialog_ID;
static int group_ID;
static int encoded_ID;
*/
gint
WriteBMP (filename,image,drawable_ID)
char *filename;
gint32 image,drawable_ID;
{
FILE *outfile;
int Red[MAXCOLORS];
int Green[MAXCOLORS];
int Blue[MAXCOLORS];
unsigned char *cmap;
int rows, cols, channels, MapSize, SpZeile;
long BitsPerPixel;
int colors;
char *temp_buf,*pixels;
GPixelRgn pixel_rgn;
GDrawable *drawable;
GDrawableType drawable_type;
int i;
/* first: can we save this image? */
drawable = gimp_drawable_get(drawable_ID);
drawable_type = gimp_drawable_type(drawable_ID);
gimp_pixel_rgn_init(&pixel_rgn, drawable, 0, 0, drawable->width, drawable->height, FALSE, FALSE);
switch (drawable_type)
{
case RGB_IMAGE:
case GRAY_IMAGE:
case INDEXED_IMAGE:
break;
default:
printf("bmp: cannot operate on unknown image types or alpha images");
gimp_quit ();
break;
}
/* We can save it. So what colors do we use? */
switch (drawable_type)
{
case RGB_IMAGE:
colors = 0;
BitsPerPixel = 24;
MapSize = 0;
channels = 3;
break;
case GRAY_IMAGE:
colors = 256;
BitsPerPixel=8;
MapSize=1024;
channels = 1;
for (i = 0; i < colors; i++)
{
Red[i] = i;
Green[i] = i;
Blue[i] = i;
}
break;
case INDEXED_IMAGE:
cmap = gimp_image_get_cmap (image, &colors);
MapSize = 4*colors;
channels = 1;
if (colors>16) BitsPerPixel=8; else if (colors>2) BitsPerPixel=4;
else BitsPerPixel=1;
for (i = 0; i < colors; i++)
{
Red[i] = *cmap++;
Green[i] = *cmap++;
Blue[i] = *cmap++;
}
break;
default:
fprintf (stderr, "%s: you should not receive this error for any reason\n", prog_name);
break;
}
/* Perhaps someone wants RLE encoded Bitmaps */
encoded = 0;
if (((BitsPerPixel==8) || (BitsPerPixel==4)) && interactive_bmp) {if (! save_dialog ()) {return -1;}}
/* Let's take some file */
outfile = fopen (filename, "wb");
if (!outfile)
{
fprintf (stderr, "can't open %s\n", filename);
return -1;
}
/* fetch the image */
pixels = (guchar *) g_malloc(drawable->width*drawable->height*channels);
gimp_pixel_rgn_get_rect(&pixel_rgn, pixels, 0, 0, drawable->width, drawable->height);
/* And let's begin the progress */
temp_buf = g_malloc (strlen (filename) + 11);
sprintf (temp_buf, "Saving %s:", filename);
gimp_progress_init (temp_buf);
g_free (temp_buf);
cur_progress = 0;
max_progress = drawable->height;
/* Now, we need some further information ... */
cols = drawable->width;
rows = drawable->height;
/* ... that we write to our headers. */
if ((((cols*BitsPerPixel)/8) % 4) == 0) SpZeile=((cols*BitsPerPixel)/8);
else SpZeile=((((cols*BitsPerPixel)/8)/4)+1)*4;
Bitmap_File_Head.bfSize=0x36+MapSize+(rows*SpZeile);
Bitmap_File_Head.reserverd=0;
Bitmap_File_Head.bfOffs=0x36+MapSize;
Bitmap_File_Head.biSize=40;
Bitmap_Head.biWidth=cols;
Bitmap_Head.biHeight=rows;
Bitmap_Head.biPlanes_biBitCnt=(BitsPerPixel << 16) + 1;
if (encoded==0) Bitmap_Head.biCompr=0;
else if (BitsPerPixel==8) Bitmap_Head.biCompr=1;
else if (BitsPerPixel==4) Bitmap_Head.biCompr=2;
else Bitmap_Head.biCompr=0;
Bitmap_Head.biSizeIm=cols*rows;
Bitmap_Head.biXPels=1;
Bitmap_Head.biYPels=1;
if (BitsPerPixel<24) Bitmap_Head.biClrUsed=colors;
else Bitmap_Head.biClrUsed=0;
Bitmap_Head.biClrImp=Bitmap_Head.biClrUsed;
#ifdef DEBUG
printf("\nSize: %u, Colors: %u, Bits: %u, Width: %u, Height: %u, Comp: %u, Zeile: %u\n",
Bitmap_File_Head.bfSize,Bitmap_Head.biClrUsed,biBitCnt,Bitmap_Head.biWidth,
Bitmap_Head.biHeight, Bitmap_Head.biCompr,SpZeile);
#endif
/* And now write the header and the colormap (if any) to disk */
WriteOK(outfile,"BM",2);
WriteOK(outfile,&Bitmap_File_Head,16);
WriteOK(outfile,&Bitmap_Head,36);
WriteColorMap(outfile,Red,Green,Blue,MapSize);
/* After that is done, we write the image ... */
WriteImage(outfile, pixels, cols, rows, encoded, channels, BitsPerPixel, SpZeile);
/* ... and exit normally */
fclose(outfile);
gimp_drawable_detach(drawable);
g_free(pixels);
return TRUE;
}
void WriteColorMap(FILE *f, int red[MAXCOLORS], int green[MAXCOLORS],
int blue[MAXCOLORS], int size)
{
char trgb[4];
int i;
size=size/4;
trgb[3]=0;
for (i=0;i<size;i++)
{
trgb[0]=(unsigned char) blue[i];
trgb[1]=(unsigned char) green[i];
trgb[2]=(unsigned char) red[i];
WriteOK(f,trgb,4);
}
}
void WriteImage(f, src, width, height, encoded, channels, bpp, spzeile)
FILE *f;
char *src;
int width,height,encoded,channels,bpp,spzeile;
{
char buf[16];
char *temp,v,g;
int xpos,ypos,i,j,rowstride,laenge;
xpos=0;
rowstride=width*channels;
/* We'll begin with the 24 bit Bitmaps, they are easy :-) */
if (bpp==24)
{
for (ypos=height-1;ypos>=0;ypos--) /* for each row */
{
for (i=0;i<width;i++) /* for each pixel */
{
temp = src + (ypos * rowstride) + (xpos * channels);
buf[2]=(unsigned char) *temp;
temp++;
buf[1]=(unsigned char) *temp;
temp++;
buf[0]=(unsigned char) *temp;
xpos++;
WriteOK(f,buf,3);
}
WriteOK(f,&buf[3],spzeile-(width*3));
cur_progress++;
if ((cur_progress % 5) == 0) gimp_progress_update ((double) cur_progress / (double) max_progress);
xpos=0;
}
} else {
switch(encoded) /* now it gets more difficult */
{ /* uncompressed 1,4 and 8 bit */
case 0:
{
for (ypos=height-1;ypos>=0;ypos--) /* for each row */
{
for (xpos=0;xpos<width;) /* for each _byte_ */
{
v=0;
for (i=1;(i<=(8/bpp)) && (xpos<width);i++,xpos++) /* for each pixel */
{
temp = src + (ypos * rowstride) + (xpos * channels);
v=v | ((unsigned char) *temp << (8-(i*bpp)));
}
WriteOK(f,&v,1);
}
WriteOK(f,&buf[3],spzeile-(width/(8/bpp)));
xpos=0;
cur_progress++;
if ((cur_progress % 5) == 0)
gimp_progress_update ((double) cur_progress / (double) max_progress);
}
break;
}
default:
{ /* Save RLE encoded file, quite difficult */
laenge=0; /* and doesn't work completely */
buf[12]=0;
buf[13]=1;
buf[14]=0;
buf[15]=0;
for (ypos=height-1;ypos>=0;ypos--) /* each row separately */
{
for (xpos=0;xpos<width;) /* loop for one row */
{
temp = src + (ypos * rowstride) + (xpos * channels);
buf[1] = (unsigned char) *temp;
j=0;
while (((unsigned char) *temp == (unsigned char) buf[1]) && (j<255) && (xpos<width))
{
xpos++;
if (xpos<width) temp = src + (ypos * rowstride) + (xpos * channels);
j++;
}
if (1) /* (j>2) */
{
buf[0]=(unsigned char) j;
if (bpp==4)
{
buf[1]=buf[1] | (buf[1] << 4);
}
WriteOK(f,buf,2); /* Count -- Color */
laenge+=2;
}
else /* unpacked */
{
xpos-=j;
j=3;
xpos+=j;
v=*(src + (ypos * rowstride) + ((xpos-1) * channels));
buf[0]=0;
WriteOK(f,buf,1);
laenge++;
temp = src + (ypos * rowstride) + (xpos * channels);
while ((j<255) && (xpos<width) && ((unsigned char) v != ((unsigned char) *temp)))
{
v=(unsigned char) *temp;
xpos++;
j++;
temp = src + (ypos * rowstride) + (xpos * channels);
}
xpos-=j;
buf[0]=(unsigned char) j;
WriteOK(f,buf,1);
laenge++;
for (i=0;i<j;i+=(8/bpp),xpos+=(8/bpp))
{
temp = src + (ypos * rowstride) + (xpos * channels);
v=(unsigned char) *temp;
temp++;
g=(unsigned char) *temp;
if (bpp==4) v=v | (g << 4);
WriteOK(f,&v,1);
}
laenge+=j/(8/bpp);
if ((j/(8/bpp)) % 2) { WriteOK(f,&buf[12],1); laenge++; }
}
}
WriteOK(f,&buf[14],2); /* End of row */
laenge+=2;
cur_progress++;
if ((cur_progress % 5) == 0) gimp_progress_update ((double) cur_progress / (double) max_progress);
}
fseek(f,-2,SEEK_CUR); /* Overwrite last End of row */
WriteOK(f,&buf[12],2); /* End of file */
fseek(f,0x02,SEEK_SET);
if (bpp==8) laenge+=0x36+(256*4); else laenge+=0x36+(16*4);
WriteOK(f,&laenge,4);
break;
}
}
}
gimp_progress_update(1);
}
/* These ones are just copied from the GIF-plugin */
static gint
save_dialog ()
{
GtkWidget *dlg;
GtkWidget *button;
GtkWidget *toggle;
GtkWidget *frame;
GtkWidget *vbox;
gchar **argv;
gint argc;
argc = 1;
argv = g_new (gchar *, 1);
argv[0] = g_strdup ("bmp");
gtk_init (&argc, &argv);
dlg = gtk_dialog_new ();
gtk_window_set_title (GTK_WINDOW (dlg), "Save as BMP");
gtk_window_position (GTK_WINDOW (dlg), GTK_WIN_POS_MOUSE);
gtk_signal_connect (GTK_OBJECT (dlg), "destroy",
(GtkSignalFunc) save_close_callback,
NULL);
/* Action area */
button = gtk_button_new_with_label ("OK");
GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
gtk_signal_connect (GTK_OBJECT (button), "clicked",
(GtkSignalFunc) save_ok_callback,
dlg);
gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dlg)->action_area), button, TRUE, TRUE, 0);
gtk_widget_grab_default (button);
gtk_widget_show (button);
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));
gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dlg)->action_area), button, TRUE, TRUE, 0);
gtk_widget_show (button);
/* parameter settings */
frame = gtk_frame_new ("Save Options");
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);
vbox = gtk_vbox_new (FALSE, 5);
gtk_container_border_width (GTK_CONTAINER (vbox), 5);
gtk_container_add (GTK_CONTAINER (frame), vbox);
toggle = gtk_check_button_new_with_label ("RLE encoded");
gtk_box_pack_start (GTK_BOX (vbox), toggle, TRUE, TRUE, 0);
gtk_signal_connect (GTK_OBJECT (toggle), "toggled",
(GtkSignalFunc) save_toggle_update,
&encoded);
gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (toggle), encoded);
gtk_widget_show (toggle);
gtk_widget_show (vbox);
gtk_widget_show (frame);
gtk_widget_show (dlg);
gtk_main ();
gdk_flush ();
return gsint.run;
}
static void
save_close_callback (GtkWidget *widget,
gpointer data)
{
gtk_main_quit ();
}
static void
save_ok_callback (GtkWidget *widget,
gpointer data)
{
gsint.run = TRUE;
gtk_widget_destroy (GTK_WIDGET (data));
}
static void
save_toggle_update (GtkWidget *widget,
gpointer data)
{
int *toggle_val;
toggle_val = (int *) data;
if (GTK_TOGGLE_BUTTON (widget)->active)
*toggle_val = TRUE;
else
*toggle_val = FALSE;
}

File diff suppressed because it is too large Load Diff

View File

@ -1,396 +0,0 @@
/* The GIMP -- an image manipulation program
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
* Copyright (C) 1997 Daniel Risacher
*
* 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
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/* bzip2 plug-in for the gimp */
/* this is almost exactly the same as the gz(ip) plugin by */
/* Dan Risacher & Josh, so feel free to go look there. */
/* GZ plugin adapted to BZ2 by Adam. I've left all other */
/* credits intact since it was only a super-wussy mod. */
/* This is reads and writes bzip2ed image files for the Gimp
*
* You need to have bzip2 installed for it to work.
*
* It should work with file names of the form
* filename.foo.bz2 where foo is some already-recognized extension
*/
#include <stdlib.h>
#include <stdio.h>
#include <sys/param.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include "gtk/gtk.h"
#include "libgimp/gimp.h"
static void query (void);
static void run (char *name,
int nparams,
GParam *param,
int *nreturn_vals,
GParam **return_vals);
static gint32 load_image (char *filename, gint32 run_mode);
static gint save_image (char *filename,
gint32 image_ID,
gint32 drawable_ID,
gint32 run_mode);
static int valid_file (char* filename) ;
static char* find_extension (char* filename) ;
GPlugInInfo PLUG_IN_INFO =
{
NULL, /* init_proc */
NULL, /* quit_proc */
query, /* query_proc */
run, /* run_proc */
};
MAIN ()
static void
query ()
{
static GParamDef load_args[] =
{
{ PARAM_INT32, "run_mode", "Interactive, non-interactive" },
{ PARAM_STRING, "filename", "The name of the file to load" },
{ PARAM_STRING, "raw_filename", "The name entered" },
};
static GParamDef load_return_vals[] =
{
{ PARAM_IMAGE, "image", "Output image" },
};
static int nload_args = sizeof (load_args) / sizeof (load_args[0]);
static int nload_return_vals = sizeof (load_return_vals) / sizeof (load_return_vals[0]);
static GParamDef save_args[] =
{
{ PARAM_INT32, "run_mode", "Interactive, non-interactive" },
{ PARAM_IMAGE, "image", "Input image" },
{ PARAM_DRAWABLE, "drawable", "Drawable to save" },
{ PARAM_STRING, "filename", "The name of the file to save the image in" },
{ PARAM_STRING, "raw_filename", "The name of the file to save the image in" }
};
static int nsave_args = sizeof (save_args) / sizeof (save_args[0]);
gimp_install_procedure ("file_bz2_load",
"loads files compressed with bzip2",
"You need to have bzip2 installed.",
"Daniel Risacher",
"Daniel Risacher, Spencer Kimball and Peter Mattis",
"1995-1997",
"<Load>/bzip2",
NULL,
PROC_PLUG_IN,
nload_args, nload_return_vals,
load_args, load_return_vals);
gimp_install_procedure ("file_bz2_save",
"saves files compressed with bzip2",
"You need to have bzip2 installed",
"Daniel Risacher",
"Daniel Risacher, Spencer Kimball and Peter Mattis",
"1995-1997",
"<Save>/bzip2",
"RGB*, GRAY*, INDEXED*",
PROC_PLUG_IN,
nsave_args, 0,
save_args, NULL);
gimp_register_load_handler ("file_bz2_load", "xcf.bz2,bz2,xcfbz2", "");
gimp_register_save_handler ("file_bz2_save", "xcf.bz2,bz2,xcfbz2", "");
}
static void
run (char *name,
int nparams,
GParam *param,
int *nreturn_vals,
GParam **return_vals)
{
static GParam values[2];
GRunModeType run_mode;
GStatusType status = STATUS_SUCCESS;
gint32 image_ID;
run_mode = param[0].data.d_int32;
*nreturn_vals = 1;
*return_vals = values;
values[0].type = PARAM_STATUS;
values[0].data.d_status = STATUS_CALLING_ERROR;
if (strcmp (name, "file_bz2_load") == 0)
{
image_ID = load_image (param[1].data.d_string,
param[0].data.d_int32);
if (image_ID != -1)
{
*nreturn_vals = 2;
values[0].data.d_status = STATUS_SUCCESS;
values[1].type = PARAM_IMAGE;
values[1].data.d_image = image_ID;
}
else
{
values[0].data.d_status = STATUS_EXECUTION_ERROR;
g_assert (FALSE);
}
}
else if (strcmp (name, "file_bz2_save") == 0)
{
switch (run_mode)
{
case RUN_INTERACTIVE:
break;
case RUN_NONINTERACTIVE:
/* Make sure all the arguments are there! */
if (nparams != 4)
status = STATUS_CALLING_ERROR;
case RUN_WITH_LAST_VALS:
break;
default:
break;
}
*nreturn_vals = 1;
if (save_image (param[3].data.d_string,
param[1].data.d_int32,
param[2].data.d_int32,
param[0].data.d_int32 ))
{
values[0].data.d_status = STATUS_SUCCESS;
}
else
values[0].data.d_status = STATUS_EXECUTION_ERROR;
}
else
g_assert (FALSE);
}
static gint
save_image (char *filename,
gint32 image_ID,
gint32 drawable_ID,
gint32 run_mode)
{
FILE* f;
GParam* params;
gint retvals;
char* ext;
char* tmpname;
int pid;
int status;
if (NULL == (ext = find_extension(filename))) return -1;
/* get a temp name with the right extension and save into it. */
params = gimp_run_procedure ("gimp_temp_name",
&retvals,
PARAM_STRING, ext + 1,
PARAM_END);
tmpname = params[1].data.d_string;
params = gimp_run_procedure ("gimp_file_save",
&retvals,
PARAM_INT32, run_mode,
PARAM_IMAGE, image_ID,
PARAM_DRAWABLE, drawable_ID,
PARAM_STRING, tmpname,
PARAM_STRING, tmpname,
PARAM_END);
if (params[0].data.d_status == FALSE || !valid_file(tmpname)) {
unlink (tmpname);
return -1;
}
/* if (! file_save(image_ID, tmpname, tmpname)) { */
/* unlink (tmpname); */
/* return -1; */
/* } */
/* fork off a bzip2 process */
if ((pid = fork()) < 0)
{
g_warning ("bz2: fork failed: %s\n", g_strerror(errno));
return -1;
}
else if (pid == 0)
{
f = fopen(filename,"w");
/* make stdout for this process be the output file */
if (-1 == dup2(fileno(f),fileno(stdout)))
g_warning ("bz2: dup2 failed: %s\n", g_strerror(errno));
/* and bzip2 into it */
execlp ("bzip2", "bzip2", "-cf", tmpname, NULL);
g_warning ("bz2: exec failed: bzip2: %s\n", g_strerror(errno));
_exit(127);
}
else
{
waitpid (pid, &status, 0);
if (!WIFEXITED(status) ||
WEXITSTATUS(status) != 0)
{
g_warning ("bz2: bzip2 exited abnormally on file %s\n", tmpname);
return 0;
}
}
unlink (tmpname);
return TRUE;
}
static gint32
load_image (char *filename, gint32 run_mode)
{
GParam* params;
gint retvals;
char* ext;
char* tmpname;
int pid;
int status;
if (NULL == (ext = find_extension(filename))) return -1;
/* find a temp name */
params = gimp_run_procedure ("gimp_temp_name",
&retvals,
PARAM_STRING, ext + 1,
PARAM_END);
tmpname = params[1].data.d_string;
/* fork off a g(un)zip and wait for it */
if ((pid = fork()) < 0)
{
g_warning ("bz2: fork failed: %s\n", g_strerror(errno));
return -1;
}
else if (pid == 0) /* child process */
{
FILE* f;
f = fopen(tmpname,"w");
/* make stdout for this child process be the temp file */
if (-1 == dup2(fileno(f),fileno(stdout)))
g_warning ("bz2: dup2 failed: %s\n", g_strerror(errno));
/* and unzip into it */
execlp ("bzip2", "bzip2", "-cfd", filename, NULL);
g_warning ("bz2: exec failed: bunzip2: %s\n", g_strerror(errno));
_exit(127);
}
else /* parent process */
{
waitpid (pid, &status, 0);
if (!WIFEXITED(status) ||
WEXITSTATUS(status) != 0)
{
g_warning ("bz2: bzip2 exited abnormally on file %s\n", filename);
return -1;
}
}
/* now that we un-bzip2ed it, load the temp file */
params = gimp_run_procedure ("gimp_file_load",
&retvals,
PARAM_INT32, run_mode,
PARAM_STRING, tmpname,
PARAM_STRING, tmpname,
PARAM_END);
unlink (tmpname);
if (params[0].data.d_status == FALSE)
return -1;
else
{
gimp_image_set_filename (params[1].data.d_int32, filename);
return params[1].data.d_int32;
}
}
static int valid_file (char* filename)
{
int stat_res;
struct stat buf;
stat_res = stat(filename, &buf);
if ((0 == stat_res) && (buf.st_size > 0))
return 1;
else
return 0;
}
static char* find_extension (char* filename)
{
char* filename_copy;
char* ext;
/* we never free this copy - aren't we evil! */
filename_copy = malloc(strlen(filename)+1);
strcpy(filename_copy, filename);
/* find the extension, boy! */
ext = strrchr (filename_copy, '.');
while (1) {
if (!ext || ext[1] == 0 || strchr(ext, '/'))
{
g_warning ("bz2: can't open bzip2ed file without a sensible extension\n");
return NULL;
}
if (0 == strcmp(ext, ".xcfbz2")) {
return ".xcf"; /* we've found it */
}
if (0 != strcmp(ext,".bz2")) {
return ext;
} else {
/* we found ".bz2" so strip it, loop back, and look again */
*ext = 0;
ext = strrchr (filename_copy, '.');
}
}
}

View File

@ -1,297 +0,0 @@
/* Contrast Autostretch 1.06 --- image filter plug-in for The Gimp image
* manipulation program
*
* Copyright (C) 1996 Federico Mena Quintero
*
* You can contact me at quartic@polloux.fciencias.unam.mx
* You can contact the original The Gimp authors at gimp@xcf.berkeley.edu
*
* 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
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/* This simple plug-in does an automatic contrast stretch. For each
channel in the image, it finds the minimum and maximum values... it
uses those values to stretch the individual histograms to the full
contrast range. For some images it may do just what you want; for
others it may be total crap :) */
#include <stdlib.h>
#include <stdio.h>
#include "libgimp/gimp.h"
/* Declare local functions.
*/
static void query (void);
static void run (char *name,
int nparams,
GParam *param,
int *nreturn_vals,
GParam **return_vals);
static void c_astretch (GDrawable * drawable);
static void indexed_c_astretch (gint32 image_ID);
GPlugInInfo PLUG_IN_INFO =
{
NULL, /* init_proc */
NULL, /* quit_proc */
query, /* query_proc */
run, /* run_proc */
};
MAIN ()
static void
query ()
{
static GParamDef args[] =
{
{ PARAM_INT32, "run_mode", "Interactive, non-interactive" },
{ PARAM_IMAGE, "image", "Input image" },
{ PARAM_DRAWABLE, "drawable", "Input drawable" },
};
static GParamDef *return_vals = NULL;
static int nargs = sizeof (args) / sizeof (args[0]);
static int nreturn_vals = 0;
gimp_install_procedure ("plug_in_c_astretch",
"Automatically stretch the contrast of the specified drawable to cover all possible ranges.",
"This simple plug-in does an automatic contrast stretch. For each channel in the image, it finds the minimum and maximum values... it uses those values to stretch the individual histograms to the full contrast range. For some images it may do just what you want; for others it may be total crap :)",
"Federico Mena Quintero",
"Federico Mena Quintero",
"1996",
"<Image>/Filters/Image/Contrast Auto-Stretch",
"RGB*, GRAY*, INDEXED*",
PROC_PLUG_IN,
nargs, nreturn_vals,
args, return_vals);
}
static void
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;
gint32 image_ID;
run_mode = param[0].data.d_int32;
/* Get the specified drawable */
drawable = gimp_drawable_get (param[2].data.d_drawable);
image_ID = param[1].data.d_image;
/* Make sure that the drawable is gray or RGB color */
if (gimp_drawable_color (drawable->id) || gimp_drawable_gray (drawable->id))
{
gimp_progress_init ("Auto-Stretching Contrast...");
gimp_tile_cache_ntiles (2 * (drawable->width / gimp_tile_width () + 1));
c_astretch (drawable);
if (run_mode != RUN_NONINTERACTIVE)
gimp_displays_flush ();
}
else if (gimp_drawable_indexed (drawable->id))
{
indexed_c_astretch (image_ID);
/* GIMP doesn't implicitly update an image whose cmap has
changed - it probably should. */
gimp_drawable_update (drawable->id, 0, 0,
gimp_drawable_width(drawable->id),
gimp_drawable_height(drawable->id));
gimp_displays_flush ();
}
else
{
/* gimp_message ("c_astretch: cannot operate on indexed color images"); */
status = STATUS_EXECUTION_ERROR;
}
*nreturn_vals = 1;
*return_vals = values;
values[0].type = PARAM_STATUS;
values[0].data.d_status = status;
gimp_drawable_detach (drawable);
}
static void
indexed_c_astretch(gint32 image_ID) /* a.d.m. */
{
guchar *cmap;
gint ncols,i;
gint rhi=0,ghi=0,bhi=0,rlo=255,glo=255,blo=255;
cmap = gimp_image_get_cmap (image_ID, &ncols);
if (cmap==NULL)
{
printf("c_astretch: cmap was NULL! Quitting...\n");
gimp_quit();
}
for (i=0;i<ncols;i++)
{
if (cmap[i*3 +0] > rhi) rhi=cmap[i*3 +0];
if (cmap[i*3 +1] > ghi) ghi=cmap[i*3 +1];
if (cmap[i*3 +2] > bhi) bhi=cmap[i*3 +2];
if (cmap[i*3 +0] < rlo) rlo=cmap[i*3 +0];
if (cmap[i*3 +1] < glo) glo=cmap[i*3 +1];
if (cmap[i*3 +2] < blo) blo=cmap[i*3 +2];
}
for (i=0;i<ncols;i++)
{
if (rhi!=rlo)
cmap[i*3 +0] = (255 * (cmap[i*3 +0] - rlo)) / (rhi-rlo);
if (ghi!=glo)
cmap[i*3 +1] = (255 * (cmap[i*3 +1] - glo)) / (ghi-glo);
if (rhi!=rlo)
cmap[i*3 +2] = (255 * (cmap[i*3 +2] - blo)) / (bhi-blo);
}
gimp_image_set_cmap (image_ID, cmap, ncols);
}
static void
c_astretch (GDrawable *drawable)
{
GPixelRgn src_rgn, dest_rgn;
guchar *src, *s;
guchar *dest, *d;
guchar min[3], max[3];
guchar range;
guchar lut[256][3];
gint progress, max_progress;
gint has_alpha, alpha;
gint x1, y1, x2, y2;
gint x, y, b;
gpointer pr;
/* Get selection area */
gimp_drawable_mask_bounds (drawable->id, &x1, &y1, &x2, &y2);
has_alpha = gimp_drawable_has_alpha (drawable->id);
alpha = (has_alpha) ? drawable->bpp - 1 : drawable->bpp;
/* Initialize progress */
progress = 0;
max_progress = (x2 - x1) * (y2 - y1) * 2;
/* Get minimum and maximum values for each channel */
min[0] = min[1] = min[2] = 255;
max[0] = max[1] = max[2] = 0;
gimp_pixel_rgn_init (&src_rgn, drawable, x1, y1, (x2 - x1), (y2 - y1), FALSE, FALSE);
for (pr = gimp_pixel_rgns_register (1, &src_rgn); pr != NULL; pr = gimp_pixel_rgns_process (pr))
{
src = src_rgn.data;
for (y = 0; y < src_rgn.h; y++)
{
s = src;
for (x = 0; x < src_rgn.w; x++)
{
for (b = 0; b < alpha; b++)
{
if (!has_alpha || (has_alpha && s[alpha]))
{
if (s[b] < min[b])
min[b] = s[b];
if (s[b] > max[b])
max[b] = s[b];
}
}
s += src_rgn.bpp;
}
src += src_rgn.rowstride;
}
/* Update progress */
progress += src_rgn.w * src_rgn.h;
gimp_progress_update ((double) progress / (double) max_progress);
}
/* Calculate LUTs with stretched contrast */
for (b = 0; b < alpha; b++)
{
range = max[b] - min[b];
if (range != 0)
for (x = min[b]; x <= max[b]; x++)
lut[x][b] = 255 * (x - min[b]) / range;
else
lut[min[b]][b] = min[b];
}
/* Now substitute pixel vales */
gimp_pixel_rgn_init (&src_rgn, drawable, x1, y1, (x2 - x1), (y2 - y1), FALSE, FALSE);
gimp_pixel_rgn_init (&dest_rgn, drawable, x1, y1, (x2 - x1), (y2 - y1), TRUE, TRUE);
for (pr = gimp_pixel_rgns_register (2, &src_rgn, &dest_rgn); pr != NULL; pr = gimp_pixel_rgns_process (pr))
{
src = src_rgn.data;
dest = dest_rgn.data;
for (y = 0; y < src_rgn.h; y++)
{
s = src;
d = dest;
for (x = 0; x < src_rgn.w; x++)
{
for (b = 0; b < alpha; b++)
d[b] = lut[s[b]][b];
if (has_alpha)
d[alpha] = s[alpha];
s += src_rgn.bpp;
d += dest_rgn.bpp;
}
src += src_rgn.rowstride;
dest += dest_rgn.rowstride;
}
/* Update progress */
progress += src_rgn.w * src_rgn.h;
gimp_progress_update ((double) progress / (double) max_progress);
}
/* update the region */
gimp_drawable_flush (drawable);
gimp_drawable_merge_shadow (drawable->id, TRUE);
gimp_drawable_update (drawable->id, x1, y1, (x2 - x1), (y2 - y1));
}

View File

@ -1,466 +0,0 @@
/*
* This is a plug-in for the GIMP.
*
* Copyright (C) 1997 Brent Burton & the Edward Blevins
*
* 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
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
#include <stdio.h>
#include <stdlib.h>
#include "gtk/gtk.h"
#include "libgimp/gimp.h"
/* Variables set in dialog box */
typedef struct data {
gint mode;
gint size;
} CheckVals;
typedef struct {
gint run;
} CheckInterface;
static CheckInterface cint =
{
FALSE
};
static void query (void);
static void run (gchar *name,
gint nparams,
GParam *param,
gint *nreturn_vals,
GParam **return_vals);
static void check (GDrawable * drawable);
static gint check_dialog (void);
static void check_close_callback (GtkWidget *widget, gpointer data);
static void check_ok_callback (GtkWidget *widget, gpointer data);
static void check_toggle_update (GtkWidget *widget, gpointer data);
static void check_slider_update (GtkAdjustment *adjustment, gint *size_val);
GPlugInInfo PLUG_IN_INFO =
{
NULL, /* init_proc */
NULL, /* quit_proc */
query, /* query_proc */
run, /* run_proc */
};
static CheckVals cvals =
{
0,
10
};
static int inblock(int pos, int size);
MAIN ()
static void
query ()
{
static GParamDef args[] =
{
{ PARAM_INT32, "run_mode", "Interactive, non-interactive" },
{ PARAM_IMAGE, "image", "Input image (unused)" },
{ PARAM_DRAWABLE, "drawable", "Input drawable" },
{ PARAM_INT32, "check_mode", "Regular or Physcobilly" },
{ PARAM_INT32, "check_size", "Size of the checks" }
};
static GParamDef *return_vals = NULL;
static int nargs = sizeof (args) / sizeof (args[0]);
static int nreturn_vals = 0;
gimp_install_procedure ("plug_in_checkerboard",
"Adds a checkerboard pattern to an image",
"More here later",
"Brent Burton & the Edward Blevins",
"Brent Burton & the Edward Blevins",
"1997",
"<Image>/Filters/Render/Checkerboard",
"RGB*, GRAY*",
PROC_PLUG_IN,
nargs, nreturn_vals,
args, return_vals);
}
static void
run (gchar *name,
gint nparams,
GParam *param,
gint *nreturn_vals,
GParam **return_vals)
{
static GParam values[1];
GDrawable *drawable;
GRunModeType run_mode;
GStatusType status = STATUS_SUCCESS;
run_mode = param[0].data.d_int32;
*nreturn_vals = 1;
*return_vals = values;
values[0].type = PARAM_STATUS;
values[0].data.d_status = status;
drawable = gimp_drawable_get (param[2].data.d_drawable);
switch (run_mode)
{
case RUN_INTERACTIVE:
gimp_get_data ("plug_in_checkerboard", &cvals);
if (! check_dialog())
{
gimp_drawable_detach (drawable);
return;
}
break;
case RUN_NONINTERACTIVE:
if (nparams != 5)
status = STATUS_CALLING_ERROR;
if (status == STATUS_SUCCESS)
{
cvals.mode = param[3].data.d_int32;
cvals.size = param[4].data.d_int32;
}
break;
case RUN_WITH_LAST_VALS:
gimp_get_data ("plug_in_checkerboard", &cvals);
break;
default:
break;
}
if (gimp_drawable_color (drawable->id) || gimp_drawable_gray (drawable->id))
{
gimp_progress_init ("Adding Checkerboard...");
check (drawable);
if (run_mode != RUN_NONINTERACTIVE)
gimp_displays_flush ();
if (run_mode == RUN_INTERACTIVE)
gimp_set_data ("plug_in_checkerboard", &cvals, sizeof (CheckVals));
}
else
{
status = STATUS_EXECUTION_ERROR;
}
values[0].data.d_status = status;
gimp_drawable_detach (drawable);
}
static void
check( GDrawable * drawable)
{
GPixelRgn dest_rgn;
GParam *return_vals;
gint nreturn_vals;
guchar *dest_row;
guchar *dest;
gint row, col;
gint progress, max_progress;
gint x1, y1, x2, y2, x, y;
guint8 fg[4],bg[4];
gint bp;
gpointer pr;
gimp_drawable_mask_bounds (drawable->id, &x1, &y1, &x2, &y2);
gimp_pixel_rgn_init (&dest_rgn, drawable, x1, y1, (x2 - x1), (y2 - y1), TRUE, TRUE);
progress = 0;
max_progress = (x2 - x1) * (y2 - y1);
/* Get the foreground and background colors */
switch ( gimp_drawable_type (drawable->id) )
{
case RGBA_IMAGE:
fg[3] = 255;
bg[3] = 255;
case RGB_IMAGE :
return_vals = gimp_run_procedure ("gimp_palette_get_foreground",
&nreturn_vals,
PARAM_END);
if (return_vals[0].data.d_status == STATUS_SUCCESS)
{
fg[0] = return_vals[1].data.d_color.red;
fg[1] = return_vals[1].data.d_color.green;
fg[2] = return_vals[1].data.d_color.blue;
}
else
{
fg[0] = 255;
fg[1] = 255;
fg[2] = 255;
}
return_vals = gimp_run_procedure ("gimp_palette_get_background",
&nreturn_vals,
PARAM_END);
if (return_vals[0].data.d_status == STATUS_SUCCESS)
{
bg[0] = return_vals[1].data.d_color.red;
bg[1] = return_vals[1].data.d_color.green;
bg[2] = return_vals[1].data.d_color.blue;
}
else
{
bg[0] = 0;
bg[1] = 0;
bg[2] = 0;
}
break;
case GRAYA_IMAGE:
fg[1] = 255;
bg[1] = 255;
case GRAY_IMAGE :
fg[0] = 255;
bg[0] = 0;
break;
default:
break;
}
for (pr = gimp_pixel_rgns_register (1, &dest_rgn); pr != NULL; pr = gimp_pixel_rgns_process (pr))
{
y = dest_rgn.y;
dest_row = dest_rgn.data;
for ( row = 0; row < dest_rgn.h; row++)
{
dest = dest_row;
x = dest_rgn.x;
for (col = 0; col < dest_rgn.w; col++)
{
gint val, xp, yp;
if (cvals.mode) {
/* Psychobilly Mode */
val = (inblock(x,cvals.size) == inblock(y,cvals.size)) ? 0 : 1;
}
else {
/* Normal, regular checkerboard mode.
* Determine base factor (even or odd) of block
* this x/y position is in.
*/
xp = x/cvals.size;
yp = y/cvals.size;
/* if both even or odd, color sqr */
val = ( (xp&1) == (yp&1) ) ? 0 : 1;
}
for (bp = 0; bp < dest_rgn.bpp; bp++)
dest[bp] = val ? fg[bp] : bg[bp];
dest += dest_rgn.bpp;
x++;
}
dest_row += dest_rgn.rowstride;
y++;
}
progress += dest_rgn.w * dest_rgn.h;
gimp_progress_update ((double) progress / (double) max_progress);
}
gimp_drawable_flush (drawable);
gimp_drawable_merge_shadow (drawable->id, TRUE);
gimp_drawable_update (drawable->id, x1, y1, (x2 - x1), (y2 - y1));
}
static int
inblock( gint pos, gint size)
{
static gint *in = NULL; /* initialized first time */
gint i,j,k, len;
len = size*size;
/*
* Initialize the array; since we'll be called thousands of
* times with the same size value, precompute the array.
*/
if (in == NULL) {
in = (int*)malloc(sizeof(int)* len);
if (in == NULL) {
return 0;
} else {
int cell = 1; /* cell value */
/*
* i is absolute index into in[]
* j is current number of blocks to fill in with a 1 or 0.
* k is just counter for the j cells.
*/
i=0;
for (j=1; j<=size; j++ ) { /* first half */
for (k=0; k<j; k++ ) {
in[i++] = cell;
}
cell = !cell;
}
for ( j=size-1; j>=1; j--) { /* second half */
for (k=0; k<j; k++ ) {
in[i++] = cell;
}
cell = !cell;
}
}
} /* if n NULL */
/* place pos within 0..(len-1) grid and return the value. */
return in[ pos % (len-1) ];
}
static gint
check_dialog ()
{
GtkWidget *dlg;
GtkWidget *button;
GtkWidget *frame;
GtkWidget *table;
GtkWidget *label;
GtkWidget *toggle;
GtkWidget *slider;
GtkObject *size_data;
gchar **argv;
gint argc;
argc = 1;
argv = g_new (gchar *, 1);
argv[0] = g_strdup ("whirl");
gtk_init (&argc, &argv);
gtk_rc_parse (gimp_gtkrc ());
dlg = gtk_dialog_new ();
gtk_window_set_title (GTK_WINDOW (dlg), "Checkerboard");
gtk_window_position (GTK_WINDOW (dlg), GTK_WIN_POS_MOUSE);
gtk_signal_connect (GTK_OBJECT (dlg), "destroy",
(GtkSignalFunc) check_close_callback,
NULL);
/* Action area */
button = gtk_button_new_with_label ("OK");
GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
gtk_signal_connect (GTK_OBJECT (button), "clicked",
(GtkSignalFunc) check_ok_callback,
dlg);
gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dlg)->action_area), button, TRUE, TRUE, 0);
gtk_widget_grab_default (button);
gtk_widget_show (button);
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));
gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dlg)->action_area), button, TRUE, TRUE, 0);
gtk_widget_show (button);
/* parameter settings */
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 (5, 5, FALSE);
gtk_container_border_width (GTK_CONTAINER (table), 10);
gtk_container_add (GTK_CONTAINER (frame), table);
toggle = gtk_check_button_new_with_label ("Psychobilly");
gtk_table_attach (GTK_TABLE (table), toggle, 0, 1, 0, 1, GTK_FILL | GTK_EXPAND, GTK_FILL, 5, 0);
gtk_signal_connect (GTK_OBJECT (toggle), "toggled",
(GtkSignalFunc) check_toggle_update,
&cvals.mode);
gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (toggle), cvals.mode);
gtk_widget_show (toggle);
label = gtk_label_new ("Check Size");
gtk_misc_set_alignment (GTK_MISC (label), 0.5, 0.5);
gtk_table_attach (GTK_TABLE (table), label, 0, 1, 3, 4, GTK_FILL | GTK_EXPAND, GTK_FILL, 0, 0);
gtk_widget_show (label);
size_data = gtk_adjustment_new (cvals.size, 1, 400, 1, 1, 0);
slider = gtk_hscale_new (GTK_ADJUSTMENT (size_data));
gtk_widget_set_usize (slider, 300, 0);
gtk_table_attach (GTK_TABLE (table), slider, 0, 1, 4, 5, GTK_FILL | GTK_EXPAND, GTK_FILL, 0, 0);
gtk_scale_set_value_pos (GTK_SCALE (slider), GTK_POS_TOP);
gtk_scale_set_digits (GTK_SCALE (slider), 0);
gtk_range_set_update_policy (GTK_RANGE (slider), GTK_UPDATE_DELAYED);
gtk_signal_connect (GTK_OBJECT (size_data), "value_changed",
(GtkSignalFunc) check_slider_update,
&cvals.size);
gtk_widget_show (slider);
gtk_widget_show (frame);
gtk_widget_show (table);
gtk_widget_show (dlg);
gtk_main ();
gdk_flush ();
return cint.run;
}
static void
check_slider_update (GtkAdjustment *adjustment,
gint *size_val)
{
*size_val = adjustment->value;
}
static void
check_toggle_update (GtkWidget *widget,
gpointer data)
{
gint *toggle_val;
toggle_val = (gint *) data;
if (GTK_TOGGLE_BUTTON (widget)->active)
*toggle_val = TRUE;
else
*toggle_val = FALSE;
}
static void
check_close_callback (GtkWidget *widget,
gpointer data)
{
gtk_main_quit ();
}
static void
check_ok_callback (GtkWidget *widget,
gpointer data)
{
cint.run = TRUE;
gtk_widget_destroy (GTK_WIDGET (data));
}

View File

@ -1,867 +0,0 @@
/* The GIMP -- an image manipulation program
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
* Compose plug-in (C) 1997 Peter Kirchgessner
* e-mail: pkirchg@aol.com, WWW: http://members.aol.com/pkirchg
*
* 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
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/*
* This plug-in composes RGB-images from several types of channels
*/
/* Event history:
* V 1.00, PK, 29-Jul-97, Creation
*/
static char ident[] = "@(#) GIMP Compose plug-in v1.00 29-Jul-97";
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "gtk/gtk.h"
#include "libgimp/gimp.h"
#include "libgimp/gimpmenu.h"
/* Declare local functions
*/
static void query (void);
static void run (char *name,
int nparams,
GParam *param,
int *nreturn_vals,
GParam **return_vals);
static gint32 compose (char *compose_type,
gint32 *compose_ID);
static gint32 create_new_image (char *filename, guint width, guint height,
GDrawableType gdtype, gint32 *layer_ID, GDrawable **drawable,
GPixelRgn *pixel_rgn);
static int cmp_icase (char *s1, char *s2);
static void compose_rgb (unsigned char **src, int numpix,
unsigned char *dst);
static void compose_rgba (unsigned char **src, int numpix,
unsigned char *dst);
static void compose_hsv (unsigned char **src, int numpix,
unsigned char *dst);
static void compose_cmy (unsigned char **src, int numpix,
unsigned char *dst);
static void compose_cmyk (unsigned char **src, int numpix,
unsigned char *dst);
static void hsv_to_rgb (unsigned char *h, unsigned char *s,
unsigned char *v, unsigned char *rgb);
static gint compose_dialog (char *compose_type,
gint32 image_ID);
static gint check_gray (gint32 image_id,
gint32 drawable_id,
gpointer data);
static void image_menu_callback (gint32 id,
gpointer data);
static void compose_close_callback (GtkWidget *widget,
gpointer data);
static void compose_ok_callback (GtkWidget *widget,
gpointer data);
static void compose_type_toggle_update (GtkWidget *widget,
gpointer data);
/* Maximum number of images to compose */
#define MAX_COMPOSE_IMAGES 4
/* Description of a composition */
typedef struct {
char *compose_type; /* Type of composition ("RGB", "RGBA",...) */
int num_images; /* Number of input images needed */
char *channel_name[MAX_COMPOSE_IMAGES]; /* channel names for dialog */
char *filename; /* Name of new image */
/* Compose functon */
void (*compose_fun)(unsigned char **src, int numpix, unsigned char *dst);
} COMPOSE_DSC;
/* Array of available compositions. */
static COMPOSE_DSC compose_dsc[] = {
{ "RGB", 3, { "Red:", "Green: ", "Blue:", "N/A" },
"rgb-compose", compose_rgb },
{ "RGBA", 4, { "Red:", "Green: ", "Blue:", "Alpha:" },
"rgba-compose", compose_rgba },
{ "HSV", 3, { "Hue:", "Saturation:", "Value:", "N/A" },
"hsv-compose", compose_hsv },
{ "CMY", 3, { "Cyan:", "Magenta: ", "Yellow:", "N/A" },
"cmy-compose", compose_cmy },
{ "CMYK", 4, { "Cyan:", "Magenta: ", "Yellow:", "Black:" },
"cmyk-compose", compose_cmyk }
};
#define MAX_COMPOSE_TYPES (sizeof (compose_dsc) / sizeof (compose_dsc[0]))
typedef struct {
gint32 compose_ID[MAX_COMPOSE_IMAGES]; /* Image IDs of input images */
char compose_type[32]; /* type of composition */
} ComposeVals;
/* Dialog structure */
typedef struct {
GtkWidget *channel_label[MAX_COMPOSE_IMAGES]; /* The labels to change */
gint32 select_ID[MAX_COMPOSE_IMAGES]; /* Image Ids selected by menu */
gint compose_flag[MAX_COMPOSE_TYPES]; /* toggle data of compose type */
gint run;
} ComposeInterface;
GPlugInInfo PLUG_IN_INFO =
{
NULL, /* init_proc */
NULL, /* quit_proc */
query, /* query_proc */
run, /* run_proc */
};
static ComposeVals composevals =
{
{ 0 }, /* Image IDs of images to compose */
"rgb" /* Type of composition */
};
static ComposeInterface composeint =
{
{ NULL }, /* Label Widgets */
{ 0 }, /* Image IDs from menues */
{ 0 }, /* Compose type toggle flags */
FALSE /* run */
};
static GRunModeType run_mode;
MAIN ()
static void
query ()
{
static GParamDef args[] =
{
{ PARAM_INT32, "run_mode", "Interactive, non-interactive" },
{ PARAM_IMAGE, "image", "First input image" },
{ PARAM_DRAWABLE, "drawable", "Input drawable (not used)" },
{ PARAM_IMAGE, "image", "Second input image" },
{ PARAM_IMAGE, "image", "Third input image" },
{ PARAM_IMAGE, "image", "Fourth input image" },
{ PARAM_STRING, "compose_type", "What to compose: RGB, RGBA, HSV,\
CMY, CMYK" }
};
static GParamDef return_vals[] =
{
{ PARAM_IMAGE, "new_image", "Output image" }
};
static int nargs = sizeof (args) / sizeof (args[0]);
static int nreturn_vals = sizeof (return_vals) / sizeof (return_vals[0]);
gimp_install_procedure ("plug_in_compose",
"Compose an image from different types of channels",
"This function creates a new image from\
different channel informations kept in gray images",
"Peter Kirchgessner",
"Peter Kirchgessner (pkirchg@aol.com)",
"1997",
"<Image>/Image/Channel Ops/Compose",
"GRAY",
PROC_PLUG_IN,
nargs, nreturn_vals,
args, return_vals);
}
static void
run (char *name,
int nparams,
GParam *param,
int *nreturn_vals,
GParam **return_vals)
{
static GParam values[2];
GStatusType status = STATUS_SUCCESS;
gint32 image_ID;
run_mode = param[0].data.d_int32;
*nreturn_vals = 2;
*return_vals = values;
values[0].type = PARAM_STATUS;
values[0].data.d_status = status;
values[1].type = PARAM_IMAGE;
values[1].data.d_int32 = -1;
switch (run_mode)
{
case RUN_INTERACTIVE:
/* Possibly retrieve data */
gimp_get_data ("plug_in_compose", &composevals);
/* First acquire information with a dialog */
if (! compose_dialog (composevals.compose_type, param[1].data.d_int32))
return;
break;
case RUN_NONINTERACTIVE:
/* Make sure all the arguments are there! */
if (nparams != 7)
status = STATUS_CALLING_ERROR;
if (status == STATUS_SUCCESS)
{
composevals.compose_ID[0] = param[1].data.d_int32;
composevals.compose_ID[1] = param[3].data.d_int32;
composevals.compose_ID[2] = param[4].data.d_int32;
composevals.compose_ID[3] = param[5].data.d_int32;
strncpy (composevals.compose_type, param[6].data.d_string,
sizeof (composevals.compose_type));
composevals.compose_type[sizeof (composevals.compose_type)-1] = '\0';
}
break;
case RUN_WITH_LAST_VALS:
/* Possibly retrieve data */
gimp_get_data ("plug_in_compose", &composevals);
break;
default:
break;
}
if (status == STATUS_SUCCESS)
{
if (run_mode != RUN_NONINTERACTIVE)
gimp_progress_init ("Composing...");
image_ID = compose (composevals.compose_type, composevals.compose_ID);
if (image_ID <= 0)
{
status = STATUS_EXECUTION_ERROR;
}
else
{
values[1].data.d_int32 = image_ID;
gimp_image_enable_undo (image_ID);
gimp_image_clean_all (image_ID);
if (run_mode != RUN_NONINTERACTIVE)
gimp_display_new (image_ID);
}
/* Store data */
if (run_mode == RUN_INTERACTIVE)
gimp_set_data ("plug_in_compose", &composevals, sizeof (ComposeVals));
}
values[0].data.d_status = status;
}
/* Compose an image from several gray-images */
static gint32
compose (char *compose_type,
gint32 *compose_ID)
{int width, height, tile_height, scan_lines;
int num_images, compose_idx;
int i, j;
gint num_layers;
gint32 *g32, layer_ID_src[MAX_COMPOSE_IMAGES], layer_ID_dst, image_ID_dst;
unsigned char *src[MAX_COMPOSE_IMAGES], *dst = (unsigned char *)ident;
GDrawableType gdtype_dst;
GDrawable *drawable_src[MAX_COMPOSE_IMAGES], *drawable_dst;
GPixelRgn pixel_rgn_src[MAX_COMPOSE_IMAGES], pixel_rgn_dst;
/* Search type of composing */
compose_idx = -1;
for (j = 0; j < MAX_COMPOSE_TYPES; j++)
{
if (cmp_icase (compose_type, compose_dsc[j].compose_type) == 0)
compose_idx = j;
}
if (compose_idx < 0)
return (-1);
num_images = compose_dsc[compose_idx].num_images;
/* Check image sizes */
width = gimp_image_width (compose_ID[0]);
height = gimp_image_height (compose_ID[0]);
tile_height = gimp_tile_height ();
for (j = 1; j < num_images; j++)
{
if ( (width != (int)gimp_image_width (compose_ID[j]))
|| (height != (int)gimp_image_height (compose_ID[j])))
{
printf ("compose: images have different size\n");
return -1;
}
}
/* Get first layer/drawable/pixel region for all input images */
for (j = 0; j < num_images; j++)
{
/* Get first layer of image */
g32 = gimp_image_get_layers (compose_ID[j], &num_layers);
if ((g32 == NULL) || (num_layers <= 0))
{
printf ("compose: error in getting layer IDs\n");
return (-1);
}
layer_ID_src[j] = g32[0];
/* Get drawable for layer */
drawable_src[j] = gimp_drawable_get (layer_ID_src[j]);
if (drawable_src[j]->bpp != 1)
{
printf ("compose: image is not a gray image\n");
return (-1);
}
/* Get pixel region */
gimp_pixel_rgn_init (&(pixel_rgn_src[j]), drawable_src[j], 0, 0,
width, height, FALSE, FALSE);
/* Get memory for retrieving information */
src[j] = (unsigned char *)g_malloc (tile_height * width
* drawable_src[j]->bpp);
if (src[j] == NULL)
{
printf ("compose: not enough memory\n");
return (-1);
}
}
/* Create new image */
gdtype_dst = (compose_dsc[compose_idx].compose_fun == compose_rgba)
? RGBA_IMAGE : RGB_IMAGE;
image_ID_dst = create_new_image (compose_dsc[compose_idx].filename,
width, height, gdtype_dst,
&layer_ID_dst, &drawable_dst, &pixel_rgn_dst);
dst = (unsigned char *)g_malloc (tile_height * width * drawable_dst->bpp);
if (dst == NULL)
{
for (j = 0; j < num_images; j++) g_free (src[j]);
printf ("compose: not enough memory\n");
return (-1);
}
/* Do the composition */
i = 0;
while (i < height)
{
scan_lines = (i+tile_height-1 < height) ? tile_height : (height-i);
/* Get source pixel regions */
for (j = 0; j < num_images; j++)
gimp_pixel_rgn_get_rect (&(pixel_rgn_src[j]), src[j], 0, i,
width, scan_lines);
/* Do the composition */
compose_dsc[compose_idx].compose_fun (src, width*tile_height, dst);
/* Set destination pixel region */
gimp_pixel_rgn_set_rect (&pixel_rgn_dst, dst, 0, i, width, scan_lines);
i += scan_lines;
if (run_mode != RUN_NONINTERACTIVE)
gimp_progress_update (((double)i) / (double)height);
}
for (j = 0; j < num_images; j++)
{
g_free (src[j]);
gimp_drawable_flush (drawable_src[j]);
gimp_drawable_detach (drawable_src[j]);
}
g_free (dst);
gimp_drawable_flush (drawable_dst);
gimp_drawable_detach (drawable_dst);
return image_ID_dst;
}
/* Create an image. Sets layer_ID, drawable and rgn. Returns image_ID */
static gint32
create_new_image (char *filename,
guint width,
guint height,
GDrawableType gdtype,
gint32 *layer_ID,
GDrawable **drawable,
GPixelRgn *pixel_rgn)
{gint32 image_ID;
GImageType gitype;
if ((gdtype == GRAY_IMAGE) || (gdtype == GRAYA_IMAGE))
gitype = GRAY;
else if ((gdtype == INDEXED_IMAGE) || (gdtype == INDEXEDA_IMAGE))
gitype = INDEXED;
else
gitype = RGB;
image_ID = gimp_image_new (width, height, gitype);
gimp_image_set_filename (image_ID, filename);
*layer_ID = gimp_layer_new (image_ID, "Background", width, height,
gdtype, 100, NORMAL_MODE);
gimp_image_add_layer (image_ID, *layer_ID, 0);
*drawable = gimp_drawable_get (*layer_ID);
gimp_pixel_rgn_init (pixel_rgn, *drawable, 0, 0, (*drawable)->width,
(*drawable)->height, TRUE, FALSE);
return (image_ID);
}
/* Compare two strings ignoring case (could also be done by strcasecmp() */
/* but is it available everywhere ?) */
static int cmp_icase (char *s1, char *s2)
{int c1, c2;
c1 = toupper (*s1); c2 = toupper (*s2);
while (*s1 && *s2)
{
if (c1 != c2) return (c2 - c1);
c1 = toupper (*(++s1)); c2 = toupper (*(++s2));
}
return (c2 - c1);
}
static void
compose_rgb (unsigned char **src,
int numpix,
unsigned char *dst)
{register unsigned char *red_src = src[0];
register unsigned char *green_src = src[1];
register unsigned char *blue_src = src[2];
register unsigned char *rgb_dst = dst;
register int count = numpix;
while (count-- > 0)
{
*(rgb_dst++) = *(red_src++);
*(rgb_dst++) = *(green_src++);
*(rgb_dst++) = *(blue_src++);
}
}
static void
compose_rgba (unsigned char **src,
int numpix,
unsigned char *dst)
{register unsigned char *red_src = src[0];
register unsigned char *green_src = src[1];
register unsigned char *blue_src = src[2];
register unsigned char *alpha_src = src[3];
register unsigned char *rgb_dst = dst;
register int count = numpix;
while (count-- > 0)
{
*(rgb_dst++) = *(red_src++);
*(rgb_dst++) = *(green_src++);
*(rgb_dst++) = *(blue_src++);
*(rgb_dst++) = *(alpha_src++);
}
}
static void
compose_hsv (unsigned char **src,
int numpix,
unsigned char *dst)
{register unsigned char *hue_src = src[0];
register unsigned char *sat_src = src[1];
register unsigned char *val_src = src[2];
register unsigned char *rgb_dst = dst;
register int count = numpix;
while (count-- > 0)
{
hsv_to_rgb (hue_src++, sat_src++, val_src++, rgb_dst);
rgb_dst += 3;
}
}
static void
compose_cmy (unsigned char **src,
int numpix,
unsigned char *dst)
{register unsigned char *cyan_src = src[0];
register unsigned char *magenta_src = src[1];
register unsigned char *yellow_src = src[2];
register unsigned char *rgb_dst = dst;
register int count = numpix;
while (count-- > 0)
{
*(rgb_dst++) = 255 - *(cyan_src++);
*(rgb_dst++) = 255 - *(magenta_src++);
*(rgb_dst++) = 255 - *(yellow_src++);
}
}
static void
compose_cmyk (unsigned char **src,
int numpix,
unsigned char *dst)
{register unsigned char *cyan_src = src[0];
register unsigned char *magenta_src = src[1];
register unsigned char *yellow_src = src[2];
register unsigned char *black_src = src[3];
register unsigned char *rgb_dst = dst;
register int count = numpix;
int cyan, magenta, yellow, black;
while (count-- > 0)
{
black = (int)*(black_src++);
if (black)
{
cyan = (int)*(cyan_src++);
magenta = (int)*(magenta_src++);
yellow = (int)*(yellow_src++);
cyan += black; if (cyan > 255) cyan = 255;
magenta += black; if (magenta > 255) magenta = 255;
yellow += black; if (yellow > 255) yellow = 255;
*(rgb_dst++) = 255 - cyan;
*(rgb_dst++) = 255 - magenta;
*(rgb_dst++) = 255 - yellow;
}
else
{
*(rgb_dst++) = 255 - *(cyan_src++);
*(rgb_dst++) = 255 - *(magenta_src++);
*(rgb_dst++) = 255 - *(yellow_src++);
}
}
}
static gint
compose_dialog (char *compose_type,
gint32 image_ID)
{
GtkWidget *dlg;
GtkWidget *button;
GtkWidget *toggle;
GtkWidget *left_frame, *right_frame;
GtkWidget *left_vbox, *right_vbox;
GtkWidget *hbox;
GtkWidget *label;
GtkWidget *table;
GtkWidget *image_option_menu, *image_menu;
GSList *group;
gchar **argv;
gint argc;
int j, compose_idx;
/* Check default compose type */
compose_idx = -1;
for (j = 0; j < MAX_COMPOSE_TYPES; j++)
{
if (cmp_icase (compose_type, compose_dsc[j].compose_type) == 0)
compose_idx = j;
}
if (compose_idx < 0) compose_idx = 0;
argc = 1;
argv = g_new (gchar *, 1);
argv[0] = g_strdup ("Compose");
gtk_init (&argc, &argv);
gtk_rc_parse (gimp_gtkrc ());
dlg = gtk_dialog_new ();
gtk_window_set_title (GTK_WINDOW (dlg), "Compose");
gtk_window_position (GTK_WINDOW (dlg), GTK_WIN_POS_MOUSE);
gtk_signal_connect (GTK_OBJECT (dlg), "destroy",
(GtkSignalFunc) compose_close_callback,
NULL);
/* Action area */
button = gtk_button_new_with_label ("OK");
GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
gtk_signal_connect (GTK_OBJECT (button), "clicked",
(GtkSignalFunc) compose_ok_callback, dlg);
gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dlg)->action_area), button,
TRUE, TRUE, 0);
gtk_widget_grab_default (button);
gtk_widget_show (button);
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));
gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dlg)->action_area), button,
TRUE, TRUE, 0);
gtk_widget_show (button);
/* parameter settings */
hbox = gtk_hbox_new (FALSE, 0);
gtk_container_border_width (GTK_CONTAINER (hbox), 0);
gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dlg)->vbox), hbox, TRUE, TRUE, 0);
gtk_widget_show (hbox);
/* The left frame keeps the compose type toggles */
left_frame = gtk_frame_new ("Compose channels:");
gtk_frame_set_shadow_type (GTK_FRAME (left_frame), GTK_SHADOW_ETCHED_IN);
gtk_container_border_width (GTK_CONTAINER (left_frame), 10);
gtk_box_pack_start (GTK_BOX (hbox), left_frame, TRUE, TRUE, 0);
left_vbox = gtk_vbox_new (FALSE, 5);
gtk_container_border_width (GTK_CONTAINER (left_vbox), 10);
gtk_container_add (GTK_CONTAINER (left_frame), left_vbox);
/* The right frame keeps the selection menues for images. */
/* Because the labels within this frame will change when a toggle */
/* in the left frame is changed, fill in the right part first. */
/* Otherwise it can occur, that a non-existing label might be changed. */
right_frame = gtk_frame_new ("Channel representations:");
gtk_frame_set_shadow_type (GTK_FRAME (right_frame), GTK_SHADOW_ETCHED_IN);
gtk_container_border_width (GTK_CONTAINER (right_frame), 10);
gtk_box_pack_start (GTK_BOX (hbox), right_frame, TRUE, TRUE, 0);
right_vbox = gtk_vbox_new (FALSE, 5);
gtk_container_border_width (GTK_CONTAINER (right_vbox), 10);
gtk_container_add (GTK_CONTAINER (right_frame), right_vbox);
table = gtk_table_new (MAX_COMPOSE_IMAGES, 3, FALSE);
gtk_table_set_row_spacings (GTK_TABLE (table), 5);
gtk_table_set_col_spacings (GTK_TABLE (table), 5);
gtk_box_pack_start (GTK_BOX (right_vbox), table, TRUE, TRUE, 0);
gtk_widget_show (table);
/* Channel names */
for (j = 0; j < MAX_COMPOSE_IMAGES; j++)
{
composeint.channel_label[j] = label =
gtk_label_new (compose_dsc[compose_idx].channel_name[j]);
gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
gtk_table_attach (GTK_TABLE (table), label, 1, 2, j, j+1,
GTK_FILL, GTK_FILL, 0, 0);
gtk_widget_show (label);
}
/* Menues to select images */
for (j = 0; j < MAX_COMPOSE_IMAGES; j++)
{
composeint.select_ID[j] = image_ID;
image_option_menu = gtk_option_menu_new ();
image_menu = gimp_image_menu_new (check_gray, image_menu_callback,
&(composeint.select_ID[j]), composeint.select_ID[j]);
gtk_table_attach (GTK_TABLE (table), image_option_menu, 2, 3, j, j+1,
GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
gtk_widget_show (image_option_menu);
gtk_option_menu_set_menu (GTK_OPTION_MENU (image_option_menu), image_menu);
}
/* Compose types */
group = NULL;
for (j = 0; j < MAX_COMPOSE_TYPES; j++)
{
toggle = gtk_radio_button_new_with_label (group,
compose_dsc[j].compose_type);
group = gtk_radio_button_group (GTK_RADIO_BUTTON (toggle));
gtk_box_pack_start (GTK_BOX (left_vbox), toggle, TRUE, TRUE, 0);
composeint.compose_flag[j] = (j == compose_idx);
gtk_signal_connect (GTK_OBJECT (toggle), "toggled",
(GtkSignalFunc) compose_type_toggle_update,
&(composeint.compose_flag[j]));
gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (toggle),
composeint.compose_flag[j]);
gtk_widget_show (toggle);
}
gtk_widget_show (left_vbox);
gtk_widget_show (right_vbox);
gtk_widget_show (left_frame);
gtk_widget_show (right_frame);
gtk_widget_show (dlg);
gtk_main ();
gdk_flush ();
return composeint.run;
}
/* hsv_to_rgb has been taken from the compose-plug-in of GIMP V 0.54
* and hass been modified a little bit
*/
static void
hsv_to_rgb (unsigned char *h,
unsigned char *s,
unsigned char *v,
unsigned char *rgb)
{double hue, sat, val;
double f, p, q, t;
int red, green, blue;
if (*s == 0)
{
rgb[0] = rgb[1] = rgb[2] = *v;
}
else
{
hue = *h * 6.0 / 255.0;
sat = *s / 255.0;
val = *v / 255.0;
f = hue - (int) hue;
p = val * (1.0 - sat);
q = val * (1.0 - (sat * f));
t = val * (1.0 - (sat * (1.0 - f)));
switch ((int) hue)
{
case 0:
red = (int)(val * 255.0);
green = (int)(t * 255.0);
blue = (int)(p * 255.0);
break;
case 1:
red = (int)(q * 255.0);
green = (int)(val * 255.0);
blue = (int)(p * 255.0);
break;
case 2:
red = (int)(p * 255.0);
green = (int)(val * 255.0);
blue = (int)(t * 255.0);
break;
case 3:
red = (int)(p * 255.0);
green = (int)(q * 255.0);
blue = (int)(val * 255.0);
break;
case 4:
red = (int)(t * 255.0);
green = (int)(p * 255.0);
blue = (int)(val * 255.0);
break;
case 5:
red = (int)(val * 255.0);
green = (int)(p * 255.0);
blue = (int)(q * 255.0);
break;
}
if (red < 0) red = 0; else if (red > 255) red = 255;
if (green < 0) green = 0; else if (green > 255) green = 255;
if (blue < 0) blue = 0; else if (blue > 255) blue = 255;
rgb[0] = (unsigned char)red;
rgb[1] = (unsigned char)green;
rgb[2] = (unsigned char)blue;
}
}
/* Compose interface functions */
static gint
check_gray (gint32 image_id,
gint32 drawable_id,
gpointer data)
{
return (gimp_image_base_type (image_id) == GRAY);
}
static void
image_menu_callback (gint32 id,
gpointer data)
{
*(gint32 *)data = id;
}
static void
compose_close_callback (GtkWidget *widget,
gpointer data)
{
gtk_main_quit ();
}
static void
compose_ok_callback (GtkWidget *widget,
gpointer data)
{int j;
composeint.run = TRUE;
gtk_widget_destroy (GTK_WIDGET (data));
for (j = 0; j < MAX_COMPOSE_IMAGES; j++)
composevals.compose_ID[j] = composeint.select_ID[j];
for (j = 0; j < MAX_COMPOSE_TYPES; j++)
{
if (composeint.compose_flag[j])
{
strcpy (composevals.compose_type, compose_dsc[j].compose_type);
break;
}
}
}
static void
compose_type_toggle_update (GtkWidget *widget,
gpointer data)
{
gint *toggle_val;
gint compose_idx, j;
toggle_val = (gint *) data;
if (GTK_TOGGLE_BUTTON (widget)->active)
{
*toggle_val = TRUE;
compose_idx = toggle_val - &(composeint.compose_flag[0]);
for (j = 0; j < MAX_COMPOSE_IMAGES; j++)
gtk_label_set (GTK_LABEL (composeint.channel_label[j]),
compose_dsc[compose_idx].channel_name[j]);
}
else
*toggle_val = FALSE;
}

View File

@ -1,902 +0,0 @@
/* Convolution Matrix plug-in for the GIMP -- Version 0.1
* Copyright (C) 1997 Lauri Alanko <la@iki.fi>
*
*
* 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
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* The GNU General Public License is also available from
* http://www.fsf.org/copyleft/gpl.html
*
*
* CHANGELOG:
* v0.12 15.9.1997
* Got rid of the unportable snprintf. Also made some _tiny_ GUI fixes.
*
* v0.11 20.7.1997
* Negative values in the matrix are now abs'ed when used to weight
* alpha. Embossing effects should work properly now. Also fixed a
* totally idiotic bug with embossing.
*
* v0.1 2.7.1997
* Initial release. Works... kinda.
*
*
* TODO:
*
* - remove channels selector (that's what the channels dialog is for)
* - remove idiotic slowdowns
* - clean up code
* - preview
* - optimize properly
* - save & load matrices
* - spiffy frontend for designing matrices
*
* What else?
*
*
*/
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <string.h>
#include "libgimp/gimp.h"
#include "gtk/gtk.h"
#include <sys/types.h>
#include <signal.h>
#include <unistd.h>
typedef enum {
EXTEND,
WRAP,
CLEAR,
MIRROR
}BorderMode;
GDrawable *drawable;
char * const channel_labels[]={
"Grey","Red","Green","Blue","Alpha"
};
char * const bmode_labels[]={
"Extend","Wrap","Crop"
};
/* Declare local functions. */
static void query(void);
static void run(char *name,
int nparams,
GParam * param,
int *nreturn_vals,
GParam ** return_vals);
static gint dialog();
static void doit(void);
static void check_config(void);
GPlugInInfo PLUG_IN_INFO =
{
NULL, /* init_proc */
NULL, /* quit_proc */
query, /* query_proc */
run, /* run_proc */
};
gint bytes;
gint sx1, sy1, sx2, sy2;
int run_flag = 0;
typedef struct {
gfloat matrix[5][5];
gfloat divisor;
gfloat offset;
gint alpha_alg;
BorderMode bmode;
gint channels[5];
gint autoset;
} config;
const config default_config =
{
{
{0.0,0.0,0.0,0.0,0.0},
{0.0,0.0,0.0,0.0,0.0},
{0.0,0.0,1.0,0.0,0.0},
{0.0,0.0,0.0,0.0,0.0},
{0.0,0.0,0.0,0.0,0.0}
}, /* matrix */
1, /* divisor */
0, /* offset */
1, /* Alpha-handling algorithm */
CLEAR, /* border-mode */
{1,1,1,1,1}, /* Channels mask */
0 /* autoset */
};
config my_config;
struct{
GtkWidget *matrix[5][5];
GtkWidget *divisor;
GtkWidget *offset;
GtkWidget *alpha_alg;
GtkWidget *bmode[3];
GtkWidget *channels[5];
GtkWidget *autoset;
GtkWidget *ok;
}my_widgets;
MAIN()
static void query()
{
static GParamDef args[] =
{
{PARAM_INT32, "run_mode", "Interactive, non-interactive"},
{PARAM_IMAGE, "image", "Input image (unused)"},
{PARAM_DRAWABLE, "drawable", "Input drawable"},
/* {PARAM_FLOATARRAY, "matrix", "The 5x5 convolution matrix"},
{PARAM_INT32, "alpha_alg", "Enable weighting by alpha channel"},
{PARAM_FLOAT, "divisor", "Divisor"},
{PARAM_FLOAT, "offset", "Offset"},
{PARAM_INT32ARRAY, "channels", "Mask of the channels to be filtered"},
{PARAM_INT32, "bmode", "Mode for treating image borders"}
*/
};
static GParamDef *return_vals = NULL;
static int nargs = (int)(sizeof(args) / sizeof(args[0]));
static int nreturn_vals = 0;
gimp_install_procedure("plug_in_convmatrix",
"A generic 5x5 convolution matrix",
"",
"Lauri Alanko",
"Lauri Alanko",
"1997",
"<Image>/Filters/Image/Convolution Matrix",
"RGB*, GRAY*",
PROC_PLUG_IN,
nargs, nreturn_vals,
args, return_vals);
}
static void run(char *name, int n_params, GParam * param,
int *nreturn_vals, GParam ** return_vals){
static GParam values[1];
GRunModeType run_mode;
GStatusType status = STATUS_SUCCESS;
int x,y;
(void)name; /* Shut up warnings about unused parameters. */
*nreturn_vals = 1;
*return_vals = values;
run_mode = param[0].data.d_int32;
/* Get the specified drawable */
drawable = gimp_drawable_get(param[2].data.d_drawable);
my_config=default_config;
if (run_mode == RUN_NONINTERACTIVE) {
if(n_params!=9)
status=STATUS_CALLING_ERROR;
else{
for(y=0;y<5;y++)
for(x=0;x<5;x++)
my_config.matrix[x][y]=param[3].data.d_floatarray[y*5+x];
my_config.divisor=param[4].data.d_float;
my_config.offset=param[5].data.d_float;
my_config.alpha_alg=param[6].data.d_int32;
my_config.bmode=param[6].data.d_int32;
for(y=0;y<5;y++)
my_config.channels[y]=param[7].data.d_int32array[y];
check_config();
}
} else {
gimp_get_data("plug_in_convmatrix", &my_config);
if (run_mode == RUN_INTERACTIVE) {
/* Oh boy. We get to do a dialog box, because we can't really expect the
* user to set us up with the right values using gdb.
*/
check_config();
if (!dialog()) {
/* The dialog was closed, or something similarly evil happened. */
status = STATUS_EXECUTION_ERROR;
}
}
}
if (status == STATUS_SUCCESS) {
/* Make sure that the drawable is gray or RGB color */
if (gimp_drawable_color(drawable->id) ||
gimp_drawable_gray(drawable->id)) {
gimp_progress_init("Applying convolution");
gimp_tile_cache_ntiles(2 * (drawable->width /
gimp_tile_width() + 1));
doit();
if (run_mode != RUN_NONINTERACTIVE)
gimp_displays_flush();
if (run_mode == RUN_INTERACTIVE)
gimp_set_data("plug_in_convmatrix", &my_config,
sizeof(my_config));
} else {
status = STATUS_EXECUTION_ERROR;
}
gimp_drawable_detach(drawable);
}
values[0].type = PARAM_STATUS;
values[0].data.d_status = status;
}
/* A generic wrapper to gimp_pixel_rgn_get_row which handles unlimited
* wrapping or gives you transparent regions outside the image */
static void my_get_row(GPixelRgn *PR, guchar *dest, int x, int y, int w){
int width, height, bytes;
int i;
width=PR->drawable->width;
height=PR->drawable->height;
bytes=PR->drawable->bpp;
/* Y-wrappings */
switch(my_config.bmode){
case WRAP:
/* Wrapped, so we get the proper row from the other side */
while(y<0) /* This is the _sure_ way to wrap. :) */
y+=height;
while(y>=height)
y-=height;
break;
case CLEAR:
/* Beyond borders, so set full transparent. */
if(y<0 || y>=height){
memset(dest,0,w*bytes);
return; /* Done, so back. */
}
case MIRROR:
/* The border lines are _not_ duplicated in the mirror image */
/* is this right? */
while(y<0 || y>=height){
if(y<0)
y=-y; /* y=-y-1 */
if(y>=height)
y=2*height-y-2; /* y=2*height-y-1 */
}
break;
case EXTEND:
y=CLAMP(y,0,height-1);
break;
}
switch(my_config.bmode){
case CLEAR:
if(x<0){
i=MIN(w,-x);
memset(dest,0,i*bytes);
dest+=i*bytes;
w-=i;
x+=i;
}
if(w){
i=MIN(w,width);
gimp_pixel_rgn_get_row(PR, dest, x, y, i);
dest+=i*bytes;
w-=i;
x+=i;
}
if(w)
memset(dest,0,w*bytes);
break;
case WRAP:
while(x<0)
x+=width;
i=MIN(w, width-x);
gimp_pixel_rgn_get_row(PR, dest, x, y, i);
w-=i;
dest+=i*bytes;
x=0;
while(w){
i=MIN(w, width);
gimp_pixel_rgn_get_row(PR, dest, x, y, i);
w-=i;
dest+=i*bytes;
}
break;
case EXTEND:
if(x<0){
gimp_pixel_rgn_get_pixel(PR, dest, 0, y);
x++;
w--;
dest+=bytes;
while(x<0 && w){
for(i=0;i<bytes;i++){
*dest=*(dest-bytes);
dest++;
}
x++;
w--;
}
}
if(w){
i=MIN(w,width);
gimp_pixel_rgn_get_row(PR, dest, x, y, i);
w-=i;
dest+=i*bytes;
}
while(w){
for(i=0;i<bytes;i++){
*dest=*(dest-bytes);
dest++;
}
x++;
w--;
}
break;
case MIRROR: /* Not yet handled */
break;
}
}
gfloat calcmatrix(guchar **srcrow, gint xoff, int i){
gfloat sum=0, alphasum=0;
static gfloat matrixsum=0;
static gint bytes=0;
gfloat temp;
gint x,y;
if(!bytes){
bytes=drawable->bpp;
for(y=0;y<5;y++)
for(x=0;x<5;x++){
temp=my_config.matrix[x][y];
matrixsum+=ABS(temp);
}
}
for(y=0;y<5;y++)
for(x=0;x<5;x++){
temp=my_config.matrix[x][y];
if(i!=(bytes-1) && my_config.alpha_alg==1){
temp*=srcrow[y][xoff+x*bytes+bytes-1-i];
alphasum+=ABS(temp);
}
temp*=srcrow[y][xoff+x*bytes];
sum+=temp;
}
sum/=my_config.divisor;
if(i!=(bytes-1) && my_config.alpha_alg==1){
if(alphasum!=0)
sum=sum*matrixsum/alphasum;
else
sum=0;
/* sum=srcrow[2][xoff+2*bytes]*my_config.matrix[2][2];*/
}
sum+=my_config.offset;
return sum;
}
static void doit(void)
{
GPixelRgn srcPR, destPR;
gint width, height, row, col;
int w, h, i;
guchar *destrow[3], *srcrow[5], *temprow;
gfloat sum;
gint xoff;
gint chanmask[4];
/* 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, &sx1, &sy1, &sx2, &sy2);
w=sx2-sx1;
h=sy2-sy1;
/* Get the size of the input image. (This will/must be the same
* as the size of the output image.
*/
width = drawable->width;
height = drawable->height;
bytes = drawable->bpp;
if(gimp_drawable_color(drawable->id))
for(i=0;i<3;i++)
chanmask[i]=my_config.channels[i+1];
else /* Grayscale */
chanmask[0]=my_config.channels[0];
if(gimp_drawable_has_alpha(drawable->id))
chanmask[bytes-1]=my_config.channels[4];
for(i=0;i<5;i++)
srcrow[i]=(guchar *) malloc ((w + 4) * bytes);
for(i=0;i<3;i++)
destrow[i]=(guchar *) malloc ((w) * bytes);
/* initialize the pixel regions */
gimp_pixel_rgn_init(&srcPR, drawable, sx1-2, sy1-2, w+4, h+4, FALSE, FALSE);
gimp_pixel_rgn_init(&destPR, drawable, sx1, sy1, w, h, TRUE, TRUE);
/* initialize source arrays */
for(i=0;i<5;i++)
my_get_row(&srcPR, srcrow[i], sx1-2, sy1+i-2,w+4);
for (row=sy1;row<sy2;row++){
xoff=0;
for(col=sx1;col<sx2;col++)
for(i=0;i<bytes;i++){
if(chanmask[i]<=0)
sum=srcrow[2][xoff+2*bytes];
else
sum=calcmatrix(srcrow,xoff,i);
destrow[2][xoff]=(guchar)CLAMP(sum,0,255);
xoff++;
}
if(row>sy1+1)
gimp_pixel_rgn_set_row(&destPR,destrow[0], sx1,row-2,w);
temprow=destrow[0];
destrow[0]=destrow[1];
destrow[1]=destrow[2];
destrow[2]=temprow;
temprow=srcrow[0];
for(i=0;i<4;i++)
srcrow[i]=srcrow[i+1];
srcrow[4]=temprow;
my_get_row(&srcPR,srcrow[4],sx1-2,row+3,w+4);
gimp_progress_update((double)(row-sy1)/h);
}
/* put the final rows in the buffer in place */
if(h<3)
gimp_pixel_rgn_set_row(&destPR,destrow[2], sx1,row-3,w);
if(h>1)
gimp_pixel_rgn_set_row(&destPR,destrow[0], sx1,row-2,w);
if(h>2)
gimp_pixel_rgn_set_row(&destPR,destrow[1], sx1,row-1,w);
/* update the timred region */
gimp_drawable_flush(drawable);
gimp_drawable_merge_shadow(drawable->id, TRUE);
gimp_drawable_update(drawable->id, sx1, sy1, sx2 - sx1, sy2 - sy1);
}
/***************************************************
* GUI stuff
*/
void fprint(gfloat f, gchar *buffer){
int i,t;
sprintf(buffer, "%.7f", f);
for(t=0;buffer[t]!='.';t++);
i=t+1;
while(buffer[i]!='\0'){
if(buffer[i]!='0')
t=i+1;
i++;
}
buffer[t]='\0';
}
static void redraw_matrix(void){
int x,y;
gchar buffer[12];
for(y=0;y<5;y++)
for(x=0;x<5;x++){
fprint(my_config.matrix[x][y],buffer);
gtk_entry_set_text(GTK_ENTRY(my_widgets.matrix[x][y]),buffer);
}
}
static void redraw_channels(void){
int i;
for(i=0;i<5;i++)
gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(my_widgets.channels[i]),
my_config.channels[i]>0);
}
static void redraw_autoset(void){
gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(my_widgets.autoset),my_config.autoset);
}
static void redraw_alpha_alg(void){
gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(my_widgets.alpha_alg),my_config.alpha_alg>0);
}
static void redraw_off_and_div(void){
gchar buffer[12];
fprint(my_config.divisor,buffer);
gtk_entry_set_text(GTK_ENTRY(my_widgets.divisor),buffer);
fprint(my_config.offset,buffer);
gtk_entry_set_text(GTK_ENTRY(my_widgets.offset),buffer);
}
static void redraw_bmode(void){
gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(my_widgets.bmode[my_config.bmode]),TRUE);
}
static void redraw_all(void){
redraw_matrix();
redraw_off_and_div();
redraw_autoset();
redraw_alpha_alg();
redraw_bmode();
redraw_channels();
}
static void check_matrix(void){
int x,y;
int valid=0;
gfloat sum=0.0;
for(y=0;y<5;y++)
for(x=0;x<5;x++){
sum+=my_config.matrix[x][y];
if(my_config.matrix[x][y]!=0.0)
valid=1;
}
if(my_config.autoset){
if(sum>0){
my_config.offset=0;
my_config.divisor=sum;
}else if(sum<0){
my_config.offset=255;
my_config.divisor=-sum;
}else{
my_config.offset=128;
/* The sum is 0, so this is probably some sort of
* embossing filter. Should divisor be autoset to 1
* or left undefined, ie. for the user to define? */
my_config.divisor=1;
}
redraw_off_and_div();
}
/* gtk_widget_set_sensitive(my_widgets.ok,valid); */
}
static void close_callback(GtkWidget *widget, gpointer data){
(void)widget; /* Shut up warnings about unused parameters. */
(void)data;
gtk_main_quit();
}
static void ok_callback(GtkWidget * widget, gpointer data){
(void)widget; /* Shut up warnings about unused parameters. */
run_flag = 1;
gtk_widget_destroy(GTK_WIDGET(data));
}
/* Checks that the configuration is valid for the image type */
static void check_config(void){
int i;
for(i=0;i<5;i++)
if(my_config.channels[i]<0)
my_config.channels[i]=0;
if(gimp_drawable_color(drawable->id))
my_config.channels[0]=-1;
else if(gimp_drawable_gray(drawable->id))
for(i=1;i<4;i++)
my_config.channels[i]=-1;
if(!gimp_drawable_has_alpha(drawable->id)){
my_config.channels[4]=-1;
my_config.alpha_alg=-1;
my_config.bmode=EXTEND;
}
}
static void defaults_callback(GtkWidget * widget, gpointer data){
(void)widget; /* Shut up warnings about unused parameters. */
(void)data;
my_config=default_config;
check_config();
redraw_all();
}
static void entry_callback(GtkWidget * widget, gpointer data)
{
gfloat *value=(gfloat *)data;
*value=atof(gtk_entry_get_text(GTK_ENTRY(widget)));
#if 0
check_matrix();
#else
if(widget==my_widgets.divisor)
gtk_widget_set_sensitive(GTK_WIDGET(my_widgets.ok),(*value!=0.0));
else if(widget!=my_widgets.offset)
check_matrix();
#endif
}
static void my_toggle_callback(GtkWidget * widget, gpointer data)
{
int val=GTK_TOGGLE_BUTTON(widget)->active;
if(val)
*(int *)data=TRUE;
else
*(int *)data=FALSE;
if(widget==my_widgets.alpha_alg){
gtk_widget_set_sensitive(my_widgets.bmode[CLEAR],val);
if(val==0 && my_config.bmode==CLEAR){
my_config.bmode=EXTEND;
redraw_bmode();
}
}else if(widget==my_widgets.autoset){
gtk_widget_set_sensitive(my_widgets.divisor,!val);
gtk_widget_set_sensitive(my_widgets.offset,!val);
check_matrix();
}
}
static void my_bmode_callback(GtkWidget * widget, gpointer data){
(void)widget; /* Shut up warnings about unused parameters. */
(void)data;
my_config.bmode=(int)data-1;
}
static gint dialog()
{
GtkWidget *dlg;
GtkWidget *button;
GtkWidget *label;
GtkWidget *entry;
GtkWidget *table;
GtkWidget *outbox;
GtkWidget *box;
GtkWidget *inbox;
GtkWidget *yetanotherbox;
GtkWidget *frame;
gchar buffer[32];
gchar **argv;
gint argc;
gint x,y,i;
GSList *group;
argc = 1;
argv = g_new(gchar *, 1);
argv[0] = g_strdup("convmatrix");
gtk_init(&argc, &argv);
gtk_rc_parse (gimp_gtkrc ());
dlg = gtk_dialog_new();
gtk_window_set_title(GTK_WINDOW(dlg), "Convolution Matrix");
gtk_window_position(GTK_WINDOW(dlg), GTK_WIN_POS_MOUSE);
gtk_signal_connect(GTK_OBJECT(dlg), "destroy",
(GtkSignalFunc) close_callback, NULL);
/* Action area */
my_widgets.ok = button = gtk_button_new_with_label("OK");
GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT);
gtk_signal_connect(GTK_OBJECT(button), "clicked",
(GtkSignalFunc) ok_callback,
GTK_OBJECT(dlg));
gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dlg)->action_area), button, TRUE, TRUE, 0);
gtk_widget_grab_default(button);
gtk_widget_show(button);
button = gtk_button_new_with_label("Defaults");
GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT);
gtk_signal_connect_object(GTK_OBJECT(button), "clicked",
(GtkSignalFunc) defaults_callback,
GTK_OBJECT(dlg));
gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dlg)->action_area), button, TRUE, TRUE, 0);
gtk_widget_show(button);
button = gtk_button_new_with_label("Cancel");
GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT);
gtk_signal_connect_object(GTK_OBJECT(button), "clicked",
(GtkSignalFunc) close_callback,
GTK_OBJECT(dlg));
gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dlg)->action_area), button, TRUE, TRUE, 0);
gtk_widget_show(button);
/* Outbox */
outbox=gtk_hbox_new(FALSE,0);
gtk_box_pack_start (GTK_BOX (GTK_DIALOG(dlg)->vbox), outbox, TRUE, TRUE, 0);
/* Outbox:YABox */
yetanotherbox=gtk_vbox_new(FALSE,0);
gtk_box_pack_start (GTK_BOX (outbox), yetanotherbox, TRUE, TRUE, 0);
/* Outbox:YABox:Frame */
frame = gtk_frame_new ("Matrix");
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 (yetanotherbox), frame, TRUE, TRUE, 0);
/* Outbox:YABox:Frame:Inbox */
inbox=gtk_vbox_new(FALSE,0);
gtk_container_add(GTK_CONTAINER(frame),inbox);
/* The main table */
/* Set its size (y, x) */
/* Outbox:YABox:Frame:Inbox:Table */
table = gtk_table_new(5, 5, TRUE);
gtk_container_border_width(GTK_CONTAINER(table), 10);
gtk_container_add (GTK_CONTAINER (inbox), table);
gtk_widget_show(table);
gtk_table_set_row_spacings(GTK_TABLE(table), 5);
gtk_table_set_col_spacings(GTK_TABLE(table), 5);
/* The 5x5 matrix entry fields */
for(y=0;y<5;y++)
for(x=0;x<5;x++){
my_widgets.matrix[x][y]= entry = gtk_entry_new();
gtk_table_attach(GTK_TABLE(table), entry, x, x+1, y, y+1, GTK_EXPAND | GTK_FILL,
GTK_EXPAND | GTK_FILL, 0, 0);
gtk_widget_set_usize(entry, 40, 0);
gtk_entry_set_text(GTK_ENTRY(entry), buffer);
gtk_signal_connect(GTK_OBJECT(entry), "changed",
(GtkSignalFunc) entry_callback, &my_config.matrix[x][y]);
gtk_widget_show(entry);
}
gtk_widget_show(table);
/* The remaining two parameters */
/* Outbox:YABox:Frame:Inbox:Box */
box=gtk_hbox_new(TRUE,0);
gtk_container_border_width(GTK_CONTAINER(box),10);
gtk_box_pack_start(GTK_BOX(inbox), box, TRUE, TRUE, 0);
/* divisor */
label=gtk_label_new("Divisor");
gtk_box_pack_start(GTK_BOX(box), label, TRUE, TRUE, 0);
gtk_widget_show(label);
my_widgets.divisor=entry=gtk_entry_new();
gtk_box_pack_start(GTK_BOX(box), entry, TRUE, TRUE, 0);
gtk_container_add(GTK_CONTAINER(frame),entry);
gtk_widget_set_usize(entry, 40, 0);
gtk_signal_connect(GTK_OBJECT(entry), "changed",
(GtkSignalFunc) entry_callback, &my_config.divisor);
gtk_widget_show(entry);
/* Offset */
label=gtk_label_new("Offset");
gtk_box_pack_start(GTK_BOX(box), label, TRUE, TRUE, 0);
gtk_widget_show(label);
my_widgets.offset=entry=gtk_entry_new();
gtk_box_pack_start(GTK_BOX(box), entry, TRUE, TRUE, 0);
gtk_container_add(GTK_CONTAINER(frame),entry);
gtk_widget_set_usize(entry, 40, 0);
gtk_signal_connect(GTK_OBJECT(entry), "changed",
(GtkSignalFunc) entry_callback, &my_config.offset);
gtk_widget_show(entry);
gtk_widget_show(box);
gtk_widget_show(inbox);
gtk_widget_show(frame);
/* Outbox:YABox:Box */
box=gtk_hbox_new(TRUE,0);
gtk_box_pack_start(GTK_BOX(yetanotherbox),box, TRUE, TRUE, 0);
my_widgets.autoset=button=gtk_check_button_new_with_label("Automatic");
gtk_box_pack_start(GTK_BOX(box), button, TRUE, FALSE,0);
gtk_signal_connect(GTK_OBJECT(button), "toggled",
(GtkSignalFunc) my_toggle_callback, &my_config.autoset);
gtk_widget_show(button);
/* Alpha-weighting */
my_widgets.alpha_alg=button=gtk_check_button_new_with_label("Alpha-weighting");
if(my_config.alpha_alg==-1)
gtk_widget_set_sensitive(button,0);
gtk_box_pack_start(GTK_BOX(box),button,TRUE,TRUE,0);
gtk_signal_connect(GTK_OBJECT(button), "toggled",(GtkSignalFunc)my_toggle_callback,&my_config.alpha_alg);
gtk_widget_show(button);
gtk_widget_show(box);
gtk_widget_show(yetanotherbox);
/* Outbox:Inbox */
inbox=gtk_vbox_new(FALSE,0);
gtk_box_pack_start(GTK_BOX(outbox),inbox, FALSE, FALSE,0);
/* Wrap-modes */
/* OutBox:Inbox:Frame */
frame=gtk_frame_new("Border");
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(inbox), frame, TRUE, TRUE,0);
/* OutBox:Inbox:Frame:Box */
box=gtk_vbox_new(TRUE, 0);
gtk_container_add(GTK_CONTAINER(frame),box);
group=NULL;
for(i=0;i<3;i++){
my_widgets.bmode[i]=button=gtk_radio_button_new_with_label(group,bmode_labels[i]);
group=gtk_radio_button_group(GTK_RADIO_BUTTON(button));
gtk_box_pack_start(GTK_BOX(box),button,TRUE,TRUE,0);
gtk_widget_show(button);
gtk_signal_connect(GTK_OBJECT(button),"toggled",
(GtkSignalFunc)my_bmode_callback,(gpointer)(i+1));
/* Gaahh! We cast an int to a gpointer! So sue me.
* The +1 should protect against some null pointers */
}
gtk_widget_show(box);
gtk_widget_show(frame);
/* OutBox:Inbox:Frame */
frame=gtk_frame_new("Channels");
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(inbox), frame, TRUE, TRUE,0);
/* OutBox:Inbox:Frame:Box */
box=gtk_vbox_new(TRUE, 0);
gtk_container_add(GTK_CONTAINER(frame),box);
for(i=0;i<5;i++){
my_widgets.channels[i]=button=gtk_check_button_new_with_label(channel_labels[i]);
if(my_config.channels[i]<0)
gtk_widget_set_sensitive(button,0);
gtk_signal_connect(GTK_OBJECT(button), "toggled",(GtkSignalFunc)my_toggle_callback,&my_config.channels[i]);
gtk_box_pack_start(GTK_BOX(box),button,TRUE,TRUE,0);
gtk_widget_show(button);
}
gtk_widget_show(box);
gtk_widget_show(frame);
gtk_widget_show(inbox);
gtk_widget_show(outbox);
gtk_widget_show(dlg);
redraw_all();
gtk_widget_set_sensitive(my_widgets.bmode[CLEAR],(my_config.alpha_alg>0));
gtk_main();
gdk_flush();
return run_flag;
}

View File

@ -1,754 +0,0 @@
/* Coordinate Map plug-in for The Gimp
* Copyright (C) 1997 Michael Schubart (schubart@best.com)
*
* 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
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/*
* This plug-in for The Gimp uses the algorithm described below to map
* a source image to a destination image. Two grayscale images X and Y
* are used to describe the mapping.
*
* For each position in the destination image, get the luminosity of the
* pixels at the same position in the X and Y images. Interpret this pair
* of values as a coordinate pair. Copy the pixel at these coordinates in
* the source image to the destination image.
*
* The latest version and some examples can be found at
* http://www.best.com/~schubart/cm/
*
* This is my first plug-in for The Gimp. You are very welcome to send
* me any comments you have.
*/
/*
* Version 0.2 -- Sep 1 1997
*
* Cosmetic changes to the source code.
*/
/*
* Version 0.1 -- Aug 28 1997
*
* The first version.
*/
#include <stdlib.h>
#include <stdio.h>
#include "gtk/gtk.h"
#include "libgimp/gimp.h"
#include "libgimp/gimpui.h"
/*
* definitions
*/
#undef GARRULOUS /* lots of messages to stdout? */
#define MODE_COPY 0
#define MODE_GRAY_TO_COLOR 1
#define MODE_COLOR_TO_GRAY 2
#define ALPHA_NONE 0
#define ALPHA_COPY 1
#define ALPHA_CLEAR 2
#define LUMINOSITY(X) ((X[0]*30 + X[1]*59 + X[2]*11)/100)
#define SRC_WIDTH 256
#define SRC_HEIGHT 256
/*
* declare types
*/
typedef struct
{
gint32 src_drawable_id; /* the source drawable */
gint32 x_drawable_id; /* the x drawable */
gint32 y_drawable_id; /* the y drawable */
} coordmap_values_t;
typedef struct
{
gint run; /* did the user press "ok"? */
} coordmap_interface_t;
/*
* declare local functions
*/
static void query(void);
static void run(char *name,
int nparams, GParam *param,
int *nreturn_vals, GParam **return_vals);
static gint coordmap(gint32 dst_drawable_id);
static gint coordmap_dialog(gint32 dst_drawable_id);
static gint coordmap_src_drawable_constraint(gint32 image_id,
gint32 drawable_id,
gpointer data);
static gint coordmap_xy_drawable_constraint(gint32 image_id,
gint32 drawable_id,
gpointer data);
static void message_box(char *message);
static void coordmap_close_callback(GtkWidget *widget, gpointer data);
static void coordmap_ok_callback(GtkWidget *widget, gpointer dialog);
static void coordmap_src_drawable_callback(gint32 id, gpointer data);
static void coordmap_x_drawable_callback(gint32 id, gpointer data);
static void coordmap_y_drawable_callback(gint32 id, gpointer data);
/*
* local variables
*/
static coordmap_values_t cvals=
{
-1, /* src_drawable_id */
-1, /* x_drawable_id */
-1, /* y_drawable_id */
};
static coordmap_interface_t cint=
{
FALSE /* run */
};
GPlugInInfo PLUG_IN_INFO =
{
NULL, /* init_proc */
NULL, /* quit_proc */
query, /* query_proc */
run, /* run_proc */
};
/*
* functions
*/
MAIN ()
static void query()
{
static GParamDef args[] =
{
{ PARAM_INT32, "run_mode", "Interactive, non-interactive" },
{ PARAM_IMAGE, "image", "Input image" },
{ PARAM_DRAWABLE, "dst_drawable", "Destination drawable" },
{ PARAM_DRAWABLE, "src_drawable",
"Source drawable, size must be 256x256" },
{ PARAM_DRAWABLE, "x_drawable",
"X drawable, size must be equal to dst_drawable." },
{ PARAM_DRAWABLE, "y_drawable",
"Y drawable, size must be equal to dst_drawable." },
};
static GParamDef *return_vals = NULL;
static int nargs = sizeof (args) / sizeof (args[0]);
static int nreturn_vals = 0;
gimp_install_procedure ("plug_in_coordmap",
"Maps a source image to a destination image.",
"Maps a source image to a destination image. For each position in "
"the destination image, the luminosity of of the X map and the Y "
"map at the same position are interpreted as coordinates. The pixel "
"that is found at these coordinates in the source image is copied "
"to the destination image.",
"Michael Schubart",
"Michael Schubart",
"Sep 1 1997",
"<Image>/Filters/Distorts/Coordinate Map",
"RGB*, GRAY*",
PROC_PLUG_IN,
nargs, nreturn_vals,
args, return_vals);
}
static void run(char *name,
int nparams, GParam *param,
int *nreturn_vals, GParam **return_vals)
{
static GParam values[1];
GRunModeType run_mode=param[0].data.d_int32;
values[0].type=PARAM_STATUS;
values[0].data.d_status=STATUS_SUCCESS;
*nreturn_vals = 1;
*return_vals = values;
switch (run_mode)
{
case RUN_INTERACTIVE:
/* get the parameter values of the last incocation */
gimp_get_data("plug_in_coordmap",&cvals);
if (!coordmap_dialog(param[2].data.d_drawable))
return;
break;
case RUN_NONINTERACTIVE:
/* check number of parameters */
if (nparams!=6)
values[0].data.d_status=STATUS_CALLING_ERROR;
else
{
cvals.src_drawable_id=param[3].data.d_drawable;
cvals.x_drawable_id=param[4].data.d_drawable;
cvals.y_drawable_id=param[5].data.d_drawable;
}
break;
case RUN_WITH_LAST_VALS:
/* get the parameter values of the last incocation */
gimp_get_data("plug_in_coordmap",&cvals);
break;
default:
break;
}
if (values[0].data.d_status==STATUS_SUCCESS)
{
/*
* @@ Who can explain to me what this gimp_tile_cache_ntiles() is about,
* and what's a good value? Thanks!
*/
gimp_tile_cache_ntiles(48);
if (!coordmap(param[2].data.d_drawable))
/* bad parameter values */
values[0].data.d_status=STATUS_EXECUTION_ERROR;
else
{
if (run_mode!=RUN_NONINTERACTIVE)
gimp_displays_flush();
if (run_mode==RUN_INTERACTIVE)
/* store parameter values for next invocation */
gimp_set_data("plug_in_coordmap",&cvals,sizeof(coordmap_values_t));
}
}
}
static gint coordmap(gint32 dst_drawable_id)
{
GDrawable *dst_drawable;
GDrawable *src_drawable;
GDrawable *x_drawable;
GDrawable *y_drawable;
gint src_mode=MODE_COPY;
gint x_mode=MODE_COPY;
gint y_mode=MODE_COPY;
gint src_bpp;
gint dst_bpp;
gint copy_bpp;
gint src_alpha_index;
gint dst_alpha_index;
gint alpha_mode=ALPHA_NONE;
gint x1,y1,x2,y2;
gint progress,max_progress;
GPixelRgn dst_rgn;
GPixelRgn src_rgn;
GPixelRgn x_rgn;
GPixelRgn y_rgn;
guchar *src;
gpointer pr;
/*
* some tests to see whether we want to run at all
*/
/* crude way to test if the drawables still exist */
if (gimp_drawable_bpp(dst_drawable_id)==-1 ||
gimp_drawable_bpp(cvals.src_drawable_id)==-1 ||
gimp_drawable_bpp(cvals.x_drawable_id)==-1 ||
gimp_drawable_bpp(cvals.y_drawable_id)==-1)
{
#ifdef GARRULOUS
g_print("coordmap: drawable missing\n");
#endif
return FALSE;
}
/* reject indexed drawables */
if (gimp_drawable_indexed(dst_drawable_id) ||
gimp_drawable_indexed(cvals.src_drawable_id) ||
gimp_drawable_indexed(cvals.x_drawable_id) ||
gimp_drawable_indexed(cvals.y_drawable_id))
{
#ifdef GARRULOUS
g_print("coordmap: won't work on indexed images\n");
#endif
return FALSE;
}
/* check source image size */
if (gimp_drawable_width(cvals.src_drawable_id)!=SRC_WIDTH ||
gimp_drawable_height(cvals.src_drawable_id)!=SRC_HEIGHT)
{
#ifdef GARRULOUS
g_print("coordmap: source image size must be 256x256\n");
#endif
return FALSE;
}
/* check x and y map size */
if (gimp_drawable_width(cvals.x_drawable_id)!=
gimp_drawable_width(dst_drawable_id) ||
gimp_drawable_height(cvals.x_drawable_id)!=
gimp_drawable_height(dst_drawable_id) ||
gimp_drawable_width(cvals.y_drawable_id)!=
gimp_drawable_width(dst_drawable_id) ||
gimp_drawable_height(cvals.y_drawable_id)!=
gimp_drawable_height(dst_drawable_id))
{
#ifdef GARRULOUS
g_print("coordmap: x and y map must be of the same size as "
"the destination image\n");
#endif
return FALSE;
}
/*
* examine the drawables to see what kind of transformations we need
*/
/* convert gray source pixel to color destination pixel? */
if (gimp_drawable_gray(cvals.src_drawable_id) &&
gimp_drawable_color(dst_drawable_id))
src_mode=MODE_GRAY_TO_COLOR;
/* convert color source pixel to gray destination pixel? */
if (gimp_drawable_color(cvals.src_drawable_id) &&
gimp_drawable_gray(dst_drawable_id))
src_mode=MODE_COLOR_TO_GRAY;
/* is the x map gray, or do we have to computer its luminosity? */
if (gimp_drawable_color(cvals.x_drawable_id))
x_mode=MODE_COLOR_TO_GRAY;
/* is the y map gray, or do we have to computer its luminosity? */
if (gimp_drawable_color(cvals.y_drawable_id))
y_mode=MODE_COLOR_TO_GRAY;
/* how may bytes of color information in the destination image? */
dst_bpp=gimp_drawable_bpp(dst_drawable_id);
if (gimp_drawable_has_alpha(dst_drawable_id))
{
dst_alpha_index=--dst_bpp;
alpha_mode=ALPHA_CLEAR;
}
/* how may bytes of color information in the source image? */
src_bpp=gimp_drawable_bpp(cvals.src_drawable_id);
if (gimp_drawable_has_alpha(cvals.src_drawable_id))
src_alpha_index=--src_bpp;
/* how many bytes of of color information are we going to copy? */
copy_bpp=MIN(src_bpp,dst_bpp);
/* copy alpha together with color if both drawables have alpha */
if (gimp_drawable_has_alpha(dst_drawable_id) &&
gimp_drawable_has_alpha(cvals.src_drawable_id))
{
if (src_mode==MODE_COPY)
copy_bpp++;
else
alpha_mode=ALPHA_COPY;
}
#ifdef GARRULOUS
/* some debug messages */
if (src_mode==MODE_COPY)
{
g_print("src_mode: MODE_COPY\n");
g_print("copy_bpp: %d\n",copy_bpp);
}
else if (src_mode==MODE_GRAY_TO_COLOR)
g_print("src_mode: MODE_GRAY_TO_COLOR\n");
else
g_print("src_mode: MODE_COLOR_TO_GRAY\n");
if (alpha_mode==ALPHA_NONE)
g_print("alpha_mode: ALPHA_NONE\n");
else if (alpha_mode==ALPHA_COPY)
{
g_print("alpha_mode: ALPHA_COPY\n");
g_print("src_alpha_index: %d\n",src_alpha_index);
g_print("dst_alpha_index: %d\n",dst_alpha_index);
}
else if (alpha_mode==ALPHA_CLEAR)
{
g_print("alpha_mode: ALPHA_CLEAR\n");
g_print("dst_alpha_index: %d\n",dst_alpha_index);
}
g_print("\n");
#endif
/* get the drawables form the drawable ids */
dst_drawable=gimp_drawable_get(dst_drawable_id);
src_drawable=gimp_drawable_get(cvals.src_drawable_id);
x_drawable=gimp_drawable_get(cvals.x_drawable_id);
y_drawable=gimp_drawable_get(cvals.y_drawable_id);
/* copy the source drawable to one big array */
gimp_pixel_rgn_init(&src_rgn,src_drawable,0,0,
SRC_WIDTH,SRC_HEIGHT,FALSE,FALSE);
src=g_new(guchar,SRC_WIDTH*SRC_HEIGHT*src_drawable->bpp);
gimp_pixel_rgn_get_rect(&src_rgn,src,0,0,SRC_WIDTH,SRC_HEIGHT);
/* get the area that is going to be processed */
gimp_drawable_mask_bounds(dst_drawable->id,&x1,&y1,&x2,&y2);
progress=0;
max_progress=(x2-x1)*(y2-y1);
gimp_progress_init("Coordinate Map...");
/* initialize the pixel regions */
gimp_pixel_rgn_init(&dst_rgn,dst_drawable,x1,y1,x2-x1,y2-y1,TRUE,TRUE);
gimp_pixel_rgn_init(&x_rgn,x_drawable,x1,y1,x2-x1,y2-y1,FALSE,FALSE);
gimp_pixel_rgn_init(&y_rgn,y_drawable,x1,y1,x2-x1,y2-y1,FALSE,FALSE);
/* iterate over the areas the Gimp chooses for us */
for (pr=gimp_pixel_rgns_register(3,&dst_rgn,&x_rgn,&y_rgn);
pr!=NULL;pr=gimp_pixel_rgns_process(pr))
{
gint x,y;
guchar *dst_ptr=dst_rgn.data;
guchar *x_ptr=x_rgn.data;
guchar *y_ptr=y_rgn.data;
guchar *src_ptr;
guchar x_value;
guchar y_value;
gint byte;
/* iterate over all pixels in the current area */
for (y=0;y<dst_rgn.h;y++)
for (x=0;x<dst_rgn.w;x++)
{
/* get the source address */
x_value=(x_mode==MODE_COPY)?x_ptr[0]:LUMINOSITY(x_ptr);
y_value=(y_mode==MODE_COPY)?y_ptr[0]:LUMINOSITY(y_ptr);
src_ptr=src+(y_value*SRC_WIDTH+x_value)*src_rgn.bpp;
/* simply copy the color information? */
if (src_mode==MODE_COPY)
for (byte=0;byte<copy_bpp;byte++)
dst_ptr[byte]=src_ptr[byte];
/* or copy a gray value to red, green and blue? */
else if (src_mode==MODE_GRAY_TO_COLOR)
for (byte=0;byte<dst_bpp;byte++)
dst_ptr[byte]=src_ptr[0];
/* or convert from color to gray? (MODE_COLOR_TO_GRAY) */
else
dst_ptr[0]=LUMINOSITY(src_ptr);
/* copy alpha information? */
if (alpha_mode==ALPHA_COPY)
dst_ptr[dst_alpha_index]=src_ptr[src_alpha_index];
/* or clear the alpha chennel? */
else if (alpha_mode==ALPHA_CLEAR)
dst_ptr[dst_alpha_index]=0xff;
/* next pixel */
dst_ptr+=dst_rgn.bpp;
x_ptr+=x_rgn.bpp;
y_ptr+=y_rgn.bpp;
}
/* update progress indicator */
progress+=dst_rgn.w*dst_rgn.h;
gimp_progress_update((double)progress/(double)max_progress);
}
/* update the destination drawable */
gimp_drawable_flush(dst_drawable);
gimp_drawable_merge_shadow(dst_drawable->id,TRUE);
gimp_drawable_update(dst_drawable->id,x1,y1,(x2-x1),(y2-y1));
/* free the memory used for the contents of the source drawable */
g_free(src);
/* free the drawable structs */
gimp_drawable_detach(dst_drawable);
gimp_drawable_detach(src_drawable);
gimp_drawable_detach(x_drawable);
gimp_drawable_detach(y_drawable);
/* success! */
return TRUE;
}
static gint coordmap_dialog(gint32 dst_drawable_id)
{
GtkWidget *dlg;
GtkWidget *button;
GtkWidget *frame;
GtkWidget *table;
GtkWidget *label;
GtkWidget *option_menu;
GtkWidget *menu;
gint argc=1;
gchar **argv=g_new(gchar *,1);
gint src_drawable_count=0;
/* initialize gtk */
argv[0]=g_strdup("Coordinate Map");
gtk_init(&argc,&argv);
gtk_rc_parse(gimp_gtkrc());
g_free(argv[0]);
g_free(argv);
/* the dialog box */
dlg=gtk_dialog_new();
gtk_window_set_title(GTK_WINDOW(dlg),"Coordinate Map");
gtk_window_position(GTK_WINDOW(dlg),GTK_WIN_POS_MOUSE);
gtk_signal_connect(GTK_OBJECT(dlg),"destroy",
(GtkSignalFunc)coordmap_close_callback,
NULL);
/* the "OK" button */
button=gtk_button_new_with_label("OK");
GTK_WIDGET_SET_FLAGS(button,GTK_CAN_DEFAULT);
gtk_signal_connect(GTK_OBJECT(button),"clicked",
(GtkSignalFunc)coordmap_ok_callback,
dlg);
gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dlg)->action_area),
button,TRUE,TRUE,0);
gtk_widget_grab_default(button);
gtk_widget_show(button);
/* the "Cancel" button */
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));
gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dlg)->action_area),
button,TRUE,TRUE,0);
gtk_widget_show (button);
/* a frame for that extra sexy look */
frame=gtk_frame_new("Coordinate Map Options");
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 to arrange the following labels and option menus*/
table=gtk_table_new(3,2,FALSE);
gtk_container_border_width(GTK_CONTAINER(table),10);
gtk_container_add(GTK_CONTAINER(frame),table);
/* the "Source Image" label */
label=gtk_label_new("Source Image");
gtk_misc_set_alignment(GTK_MISC(label),0.0,0.5);
gtk_table_attach(GTK_TABLE(table),label, 0,1,0,1,
GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, 2,2);
gtk_widget_show(label);
/* option menu with a list of the possible source drawables */
option_menu=gtk_option_menu_new();
gtk_table_attach(GTK_TABLE(table),option_menu, 1,2,0,1,
GTK_EXPAND | GTK_SHRINK | GTK_FILL, GTK_SHRINK, 2,2);
menu=gimp_drawable_menu_new(coordmap_src_drawable_constraint,
coordmap_src_drawable_callback,
&src_drawable_count,cvals.src_drawable_id);
gtk_option_menu_set_menu(GTK_OPTION_MENU(option_menu),menu);
gtk_widget_show(option_menu);
/* the "X Map" label */
label=gtk_label_new("X Map");
gtk_misc_set_alignment(GTK_MISC(label),0.0,0.5);
gtk_table_attach(GTK_TABLE(table),label, 0,1,1,2,
GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, 2,2);
gtk_widget_show(label);
/* option menu with a list of the possible x drawables */
option_menu=gtk_option_menu_new();
gtk_table_attach(GTK_TABLE(table),option_menu, 1,2,1,2,
GTK_EXPAND | GTK_SHRINK | GTK_FILL, GTK_SHRINK, 2,2);
menu=gimp_drawable_menu_new(coordmap_xy_drawable_constraint,
coordmap_x_drawable_callback,
&dst_drawable_id,cvals.x_drawable_id);
gtk_option_menu_set_menu(GTK_OPTION_MENU(option_menu),menu);
gtk_widget_show(option_menu);
/* the "Y Map" label */
label=gtk_label_new("Y Map");
gtk_misc_set_alignment(GTK_MISC(label),0.0,0.5);
gtk_table_attach(GTK_TABLE(table),label, 0,1,2,3,
GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, 2,2);
gtk_widget_show(label);
/* option menu with a list of the possible y drawables */
option_menu=gtk_option_menu_new();
gtk_table_attach(GTK_TABLE(table),option_menu,1,2,2,3,
GTK_EXPAND | GTK_SHRINK | GTK_FILL, GTK_SHRINK, 2,2);
menu=gimp_drawable_menu_new(coordmap_xy_drawable_constraint,
coordmap_y_drawable_callback,
&dst_drawable_id,cvals.y_drawable_id);
gtk_option_menu_set_menu(GTK_OPTION_MENU(option_menu),menu);
gtk_widget_show(option_menu);
gtk_widget_show(table);
gtk_widget_show(frame);
/* display error message if no appropriate source drawables were found */
if (src_drawable_count)
gtk_widget_show(dlg);
else
{
gtk_widget_destroy(dlg);
message_box("No source image was found."
"(The source image size must be 256x256)");
}
gtk_main();
gdk_flush();
return cint.run;
}
static gint coordmap_src_drawable_constraint(gint32 image_id,
gint32 drawable_id,
gpointer data)
/*
* only appropriate drawables appear in the the "Source image" option menu:
* size must be SRC_WIDTH x SRC_HEIGHT.
* drawable must not be indexed.
*/
{
gint *src_drawable_count=(gint *)data;
if (drawable_id==-1)
return TRUE;
if (gimp_drawable_width(drawable_id)==SRC_WIDTH &&
gimp_drawable_height(drawable_id)==SRC_HEIGHT &&
!gimp_drawable_indexed(drawable_id))
{
/* count how many valid drawables there are */
(*src_drawable_count)++;
return TRUE;
}
return FALSE;
}
static gint coordmap_xy_drawable_constraint(gint32 image_id,
gint32 drawable_id,
gpointer data)
/*
* only appropriate drawables appear in the the "X/Y MAP" option menus:
* size must be equal to destination drawable.
* drawable must not be indexed.
*/
{
gint32 dst_drawable_id=*(gint32 *)data;
return (drawable_id==-1 ||
(gimp_drawable_width(drawable_id)==
gimp_drawable_width(dst_drawable_id) &&
gimp_drawable_height(drawable_id)==
gimp_drawable_height(dst_drawable_id) &&
!gimp_drawable_indexed(drawable_id)));
}
static void message_box(char *message)
/*
* display a small dialog box for error messages
*/
{
GtkWidget *dlg;
GtkWidget *button;
GtkWidget *label;
/* the dialog box */
dlg=gtk_dialog_new();
gtk_window_set_title(GTK_WINDOW(dlg),"Coordinate Map Error");
gtk_window_position(GTK_WINDOW(dlg),GTK_WIN_POS_MOUSE);
gtk_signal_connect(GTK_OBJECT(dlg),"destroy",
(GtkSignalFunc)coordmap_close_callback,
NULL);
/* the "OK" button */
button=gtk_button_new_with_label("OK");
GTK_WIDGET_SET_FLAGS(button,GTK_CAN_DEFAULT);
gtk_signal_connect_object(GTK_OBJECT(button),"clicked",
(GtkSignalFunc)coordmap_close_callback,
GTK_OBJECT(dlg));
gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dlg)->action_area),
button,TRUE,TRUE,0);
gtk_widget_grab_default(button);
gtk_widget_show(button);
/* the label showing the message */
label=gtk_label_new(message);
gtk_misc_set_padding(GTK_MISC(label),10,10);
gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dlg)->vbox),label,TRUE,TRUE,0);
gtk_widget_show(label);
gtk_widget_show(dlg);
}
static void coordmap_close_callback(GtkWidget *widget, gpointer data)
/*
* gets called when the dialog window is closed via window manager
*/
{
gtk_main_quit();
}
static void coordmap_ok_callback(GtkWidget *widget, gpointer dialog)
/*
* gets called when "OK" is pressed
*/
{
/* yes, we're going to run the plug-in */
cint.run=TRUE;
/* close dialog window */
gtk_widget_destroy(GTK_WIDGET(dialog));
}
static void coordmap_src_drawable_callback(gint32 id, gpointer data)
/*
* gets called when the user selects a different source drawable
*/
{
cvals.src_drawable_id=id;
}
static void coordmap_x_drawable_callback(gint32 id, gpointer data)
/*
* gets called when the user selects a different x drawable
*/
{
cvals.x_drawable_id=id;
}
static void coordmap_y_drawable_callback(gint32 id, gpointer data)
/*
* gets called when the user selects a different y drawable
*/
{
cvals.y_drawable_id=id;
}

View File

@ -1,846 +0,0 @@
/* Cubism --- image filter plug-in for The Gimp image manipulation program
* Copyright (C) 1996 Spencer Kimball, Tracy Scott
*
* 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
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* You can contact me at quartic@polloux.fciencias.unam.mx
* You can contact the original The Gimp authors at gimp@xcf.berkeley.edu
*/
#include <math.h>
#include <stdlib.h>
#include <string.h>
#include "gtk/gtk.h"
#include "libgimp/gimp.h"
/* Some useful macros */
#define SQR(a) ((a) * (a))
#define SCALE_WIDTH 125
#define BLACK 0
#define BG 1
#define SUPERSAMPLE 3
#define MAX_POINTS 4
#define MIN_ANGLE -36000
#define MAX_ANGLE 36000
#define RANDOMNESS 5
typedef struct
{
gdouble x, y;
} Vertex;
typedef struct
{
gint npts;
Vertex pts[MAX_POINTS];
} Polygon;
typedef struct
{
gdouble tile_size;
gdouble tile_saturation;
gint bg_color;
} CubismVals;
typedef struct
{
gint run;
} CubismInterface;
/* Declare local functions.
*/
static void query (void);
static void run (char *name,
int nparams,
GParam *param,
int *nreturn_vals,
GParam **return_vals);
static void cubism (GDrawable *drawable);
static gint cubism_dialog (void);
static void render_cubism (GDrawable * drawable);
static void fill_poly_color (Polygon * poly,
GDrawable * drawable,
guchar * col);
static void convert_segment (gint x1,
gint y1,
gint x2,
gint y2,
gint offset,
gint * min,
gint * max);
static void randomize_indices (gint count,
gint * indices);
static gdouble fp_rand (gdouble val);
static gint int_rand (gint val);
static gdouble calc_alpha_blend (gdouble * vec,
gdouble dist,
gdouble x,
gdouble y);
static void polygon_add_point (Polygon * poly,
gdouble x,
gdouble y);
static void polygon_translate (Polygon * poly,
gdouble tx,
gdouble ty);
static void polygon_rotate (Polygon * poly,
gdouble theta);
static gint polygon_extents (Polygon * poly,
gdouble * min_x,
gdouble * min_y,
gdouble * max_x,
gdouble * max_y);
static void polygon_reset (Polygon * poly);
static void cubism_close_callback (GtkWidget *widget,
gpointer data);
static void cubism_ok_callback (GtkWidget *widget,
gpointer data);
static void cubism_toggle_update (GtkWidget *widget,
gpointer data);
static void cubism_scale_update (GtkAdjustment *adjustment,
double *scale_val);
/*
* Local variables
*/
static guchar bg_col[4];
static CubismVals cvals =
{
10.0, /* tile_size */
2.5, /* tile_saturation */
BLACK /* bg_color */
};
static CubismInterface cint =
{
FALSE /* run */
};
GPlugInInfo PLUG_IN_INFO =
{
NULL, /* init_proc */
NULL, /* quit_proc */
query, /* query_proc */
run, /* run_proc */
};
/*
* Functions
*/
MAIN ()
static void
query ()
{
static GParamDef args[] =
{
{ PARAM_INT32, "run_mode", "Interactive, non-interactive" },
{ PARAM_IMAGE, "image", "Input image" },
{ PARAM_DRAWABLE, "drawable", "Input drawable" },
{ PARAM_FLOAT, "tile_size", "Average diameter of each tile (in pixels)" },
{ PARAM_FLOAT, "tile_saturation", "Expand tiles by this amount" },
{ PARAM_INT32, "bg_color", "Background color: { BLACK (0), BG (1) }" }
};
static GParamDef *return_vals = NULL;
static int nargs = sizeof (args) / sizeof (args[0]);
static int nreturn_vals = 0;
gimp_install_procedure ("plug_in_cubism",
"Convert the input drawable into a collection of rotated squares",
"Help not yet written for this plug-in",
"Spencer Kimball & Tracy Scott",
"Spencer Kimball & Tracy Scott",
"1996",
"<Image>/Filters/Artistic/Cubism",
"RGB*, GRAY*",
PROC_PLUG_IN,
nargs, nreturn_vals,
args, return_vals);
}
static void
run (char *name,
int nparams,
GParam *param,
int *nreturn_vals,
GParam **return_vals)
{
static GParam values[1];
GDrawable *active_drawable;
GRunModeType run_mode;
GStatusType status = STATUS_SUCCESS;
run_mode = param[0].data.d_int32;
*nreturn_vals = 1;
*return_vals = values;
values[0].type = PARAM_STATUS;
values[0].data.d_status = status;
switch (run_mode)
{
case RUN_INTERACTIVE:
/* Possibly retrieve data */
gimp_get_data ("plug_in_cubism", &cvals);
/* First acquire information with a dialog */
if (! cubism_dialog ())
return;
break;
case RUN_NONINTERACTIVE:
/* Make sure all the arguments are there! */
if (nparams != 6)
status = STATUS_CALLING_ERROR;
if (status == STATUS_SUCCESS)
{
cvals.tile_size = param[3].data.d_float;
cvals.tile_saturation = param[4].data.d_float;
cvals.bg_color = param[5].data.d_int32;
}
if (status == STATUS_SUCCESS &&
(cvals.bg_color < BLACK || cvals.bg_color > BG))
status = STATUS_CALLING_ERROR;
break;
case RUN_WITH_LAST_VALS:
/* Possibly retrieve data */
gimp_get_data ("plug_in_cubism", &cvals);
break;
default:
break;
}
/* get the active drawable */
active_drawable = gimp_drawable_get (param[2].data.d_drawable);
/* Render the cubism effect */
if ((status == STATUS_SUCCESS) &&
(gimp_drawable_color (active_drawable->id) || gimp_drawable_gray (active_drawable->id)))
{
/* set cache size */
gimp_tile_cache_ntiles (SQR (4 * cvals.tile_size * cvals.tile_saturation) / SQR (gimp_tile_width ()));
cubism (active_drawable);
/* If the run mode is interactive, flush the displays */
if (run_mode != RUN_NONINTERACTIVE)
gimp_displays_flush ();
/* Store mvals data */
if (run_mode == RUN_INTERACTIVE)
gimp_set_data ("plug_in_cubism", &cvals, sizeof (CubismVals));
}
else if (status == STATUS_SUCCESS)
{
/* gimp_message ("cubism: cannot operate on indexed color images"); */
status = STATUS_EXECUTION_ERROR;
}
values[0].data.d_status = status;
gimp_drawable_detach (active_drawable);
}
static void
cubism (GDrawable *drawable)
{
gint x1, y1, x2, y2;
/* find the drawable mask bounds */
gimp_drawable_mask_bounds (drawable->id, &x1, &y1, &x2, &y2);
/* determine the background color */
if (cvals.bg_color == BLACK)
bg_col[0] = bg_col[1] = bg_col[2] = 0;
else
gimp_palette_get_background (&bg_col[0], &bg_col[1], &bg_col[2]);
if (gimp_drawable_has_alpha (drawable->id))
bg_col[drawable->bpp - 1] = 0;
gimp_progress_init ("Cubistic Transformation");
/* render the cubism */
render_cubism (drawable);
/* merge the shadow, update the drawable */
gimp_drawable_flush (drawable);
gimp_drawable_merge_shadow (drawable->id, TRUE);
gimp_drawable_update (drawable->id, x1, y1, (x2 - x1), (y2 - y1));
}
static gint
cubism_dialog ()
{
GtkWidget *dlg;
GtkWidget *label;
GtkWidget *button;
GtkWidget *toggle;
GtkWidget *scale;
GtkWidget *frame;
GtkWidget *table;
GtkObject *scale_data;
gchar **argv;
gint argc;
argc = 1;
argv = g_new (gchar *, 1);
argv[0] = g_strdup ("cubism");
gtk_init (&argc, &argv);
gtk_rc_parse (gimp_gtkrc ());
dlg = gtk_dialog_new ();
gtk_window_set_title (GTK_WINDOW (dlg), "Cubism");
gtk_window_position (GTK_WINDOW (dlg), GTK_WIN_POS_MOUSE);
gtk_signal_connect (GTK_OBJECT (dlg), "destroy",
(GtkSignalFunc) cubism_close_callback,
NULL);
/* Action area */
button = gtk_button_new_with_label ("OK");
GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
gtk_signal_connect (GTK_OBJECT (button), "clicked",
(GtkSignalFunc) cubism_ok_callback,
dlg);
gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dlg)->action_area), button, TRUE, TRUE, 0);
gtk_widget_grab_default (button);
gtk_widget_show (button);
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));
gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dlg)->action_area), button, TRUE, TRUE, 0);
gtk_widget_show (button);
/* parameter settings */
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 (3, 2, FALSE);
gtk_container_border_width (GTK_CONTAINER (table), 10);
gtk_container_add (GTK_CONTAINER (frame), table);
toggle = gtk_check_button_new_with_label ("Use Background Color");
gtk_table_attach (GTK_TABLE (table), toggle, 0, 2, 0, 1, GTK_FILL, 0, 0, 0);
gtk_signal_connect (GTK_OBJECT (toggle), "toggled",
(GtkSignalFunc) cubism_toggle_update,
&cvals.bg_color);
gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (toggle), (cvals.bg_color == BG));
gtk_widget_show (toggle);
label = gtk_label_new ("Tile Size");
gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
gtk_table_attach (GTK_TABLE (table), label, 0, 1, 1, 2, GTK_FILL, 0, 5, 0);
scale_data = gtk_adjustment_new (cvals.tile_size, 0.0, 100.0, 1.0, 1.0, 0.0);
scale = gtk_hscale_new (GTK_ADJUSTMENT (scale_data));
gtk_widget_set_usize (scale, SCALE_WIDTH, 0);
gtk_table_attach (GTK_TABLE (table), scale, 1, 2, 1, 2, GTK_FILL, 0, 0, 0);
gtk_scale_set_value_pos (GTK_SCALE (scale), GTK_POS_TOP);
gtk_scale_set_digits (GTK_SCALE (scale), 1);
gtk_range_set_update_policy (GTK_RANGE (scale), GTK_UPDATE_DELAYED);
gtk_signal_connect (GTK_OBJECT (scale_data), "value_changed",
(GtkSignalFunc) cubism_scale_update,
&cvals.tile_size);
gtk_widget_show (label);
gtk_widget_show (scale);
label = gtk_label_new ("Tile Saturation");
gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
gtk_table_attach (GTK_TABLE (table), label, 0, 1, 2, 3, GTK_FILL, 0, 5, 0);
scale_data = gtk_adjustment_new (cvals.tile_saturation, 0.0, 10.0, 0.1, 0.1, 0.0);
scale = gtk_hscale_new (GTK_ADJUSTMENT (scale_data));
gtk_widget_set_usize (scale, SCALE_WIDTH, 0);
gtk_table_attach (GTK_TABLE (table), scale, 1, 2, 2, 3, GTK_FILL, 0, 0, 0);
gtk_scale_set_value_pos (GTK_SCALE (scale), GTK_POS_TOP);
gtk_scale_set_digits (GTK_SCALE (scale), 1);
gtk_range_set_update_policy (GTK_RANGE (scale), GTK_UPDATE_DELAYED);
gtk_signal_connect (GTK_OBJECT (scale_data), "value_changed",
(GtkSignalFunc) cubism_scale_update,
&cvals.tile_saturation);
gtk_widget_show (label);
gtk_widget_show (scale);
gtk_widget_show (frame);
gtk_widget_show (table);
gtk_widget_show (dlg);
gtk_main ();
gdk_flush ();
return cint.run;
}
static void
render_cubism (GDrawable *drawable)
{
GPixelRgn src_rgn;
gdouble img_area, tile_area;
gdouble x, y;
gdouble width, height;
gdouble theta;
gint ix, iy;
gint rows, cols;
gint i, j, count;
gint num_tiles;
gint x1, y1, x2, y2;
Polygon poly;
guchar col[4];
guchar *dest;
gint bytes;
gint has_alpha;
gint *random_indices;
gpointer pr;
has_alpha = gimp_drawable_has_alpha (drawable->id);
bytes = drawable->bpp;
gimp_drawable_mask_bounds (drawable->id, &x1, &y1, &x2, &y2);
img_area = (x2 - x1) * (y2 - y1);
tile_area = SQR (cvals.tile_size);
cols = ((x2 - x1) + cvals.tile_size - 1) / cvals.tile_size;
rows = ((y2 - y1) + cvals.tile_size - 1) / cvals.tile_size;
/* Fill the image with the background color */
gimp_pixel_rgn_init (&src_rgn, drawable, x1, y1, (x2 - x1), (y2 - y1), TRUE, TRUE);
for (pr = gimp_pixel_rgns_register (1, &src_rgn); pr != NULL; pr = gimp_pixel_rgns_process (pr))
{
count = src_rgn.w * src_rgn.h;
dest = src_rgn.data;
while (count--)
for (i = 0; i < bytes; i++)
*dest++ = bg_col[i];
}
num_tiles = (rows + 1) * (cols + 1);
random_indices = (gint *) malloc (sizeof (gint) * num_tiles);
for (i = 0; i < num_tiles; i++)
random_indices[i] = i;
randomize_indices (num_tiles, random_indices);
count = 0;
gimp_pixel_rgn_init (&src_rgn, drawable, x1, y1, (x2 - x1), (y2 - y1), FALSE, FALSE);
while (count < num_tiles)
{
i = random_indices[count] / (cols + 1);
j = random_indices[count] % (cols + 1);
x = j * cvals.tile_size + (cvals.tile_size / 4.0) - fp_rand (cvals.tile_size/2.0) + x1;
y = i * cvals.tile_size + (cvals.tile_size / 4.0) - fp_rand (cvals.tile_size/2.0) + y1;
width = (cvals.tile_size + fp_rand (cvals.tile_size / 4.0) - cvals.tile_size / 8.0) *
cvals.tile_saturation;
height = (cvals.tile_size + fp_rand (cvals.tile_size / 4.0) - cvals.tile_size / 8.0) *
cvals.tile_saturation;
theta = fp_rand (2 * M_PI);
polygon_reset (&poly);
polygon_add_point (&poly, -width / 2.0, -height / 2.0);
polygon_add_point (&poly, width / 2.0, -height / 2.0);
polygon_add_point (&poly, width / 2.0, height / 2.0);
polygon_add_point (&poly, -width / 2.0, height / 2.0);
polygon_rotate (&poly, theta);
polygon_translate (&poly, x, y);
/* bounds check on x, y */
ix = (int) x;
iy = (int) y;
if (ix < x1)
ix = x1;
if (ix >= x2)
ix = x2 - 1;
if (iy < y1)
iy = y1;
if (iy >= y2)
iy = y2 - 1;
gimp_pixel_rgn_get_pixel (&src_rgn, col, ix, iy);
if (! has_alpha || (has_alpha && col[bytes - 1] != 0))
fill_poly_color (&poly, drawable, col);
count++;
if ((count % 5) == 0)
gimp_progress_update ((double) count / (double) num_tiles);
}
gimp_progress_update (1.0);
free (random_indices);
}
static void
fill_poly_color (Polygon *poly,
GDrawable *drawable,
guchar *col)
{
GPixelRgn src_rgn;
gdouble dmin_x, dmin_y;
gdouble dmax_x, dmax_y;
gint xs, ys;
gint xe, ye;
gint min_x, min_y;
gint max_x, max_y;
gint size_x, size_y;
gint * max_scanlines;
gint * min_scanlines;
gint * vals;
gint val;
gint alpha;
gint bytes;
guchar buf[4];
gint b, i, j, k, x, y;
gdouble sx, sy;
gdouble ex, ey;
gdouble xx, yy;
gdouble vec[2];
gdouble dist;
gint supersample;
gint supersample2;
gint x1, y1, x2, y2;
sx = poly->pts[0].x;
sy = poly->pts[0].y;
ex = poly->pts[1].x;
ey = poly->pts[1].y;
dist = sqrt (SQR (ex - sx) + SQR (ey - sy));
if (dist > 0.0)
{
vec[0] = (ex - sx) / dist;
vec[1] = (ey - sy) / dist;
}
supersample = SUPERSAMPLE;
supersample2 = SQR (supersample);
gimp_drawable_mask_bounds (drawable->id, &x1, &y1, &x2, &y2);
bytes = drawable->bpp;
polygon_extents (poly, &dmin_x, &dmin_y, &dmax_x, &dmax_y);
min_x = (gint) dmin_x;
min_y = (gint) dmin_y;
max_x = (gint) dmax_x;
max_y = (gint) dmax_y;
size_y = (max_y - min_y) * supersample;
size_x = (max_x - min_x) * supersample;
min_scanlines = (gint *) malloc (sizeof (gint) * size_y);
max_scanlines = (gint *) malloc (sizeof (gint) * size_y);
for (i = 0; i < size_y; i++)
{
min_scanlines[i] = max_x * supersample;
max_scanlines[i] = min_x * supersample;
}
for (i = 0; i < poly->npts; i++)
{
xs = (gint) ((i) ? poly->pts[i-1].x : poly->pts[poly->npts-1].x);
ys = (gint) ((i) ? poly->pts[i-1].y : poly->pts[poly->npts-1].y);
xe = (gint) poly->pts[i].x;
ye = (gint) poly->pts[i].y;
xs *= supersample;
ys *= supersample;
xe *= supersample;
ye *= supersample;
convert_segment (xs, ys, xe, ye, min_y * supersample,
min_scanlines, max_scanlines);
}
gimp_pixel_rgn_init (&src_rgn, drawable, 0, 0,
drawable->width, drawable->height,
TRUE, TRUE);
vals = (gint *) malloc (sizeof (gint) * size_x);
for (i = 0; i < size_y; i++)
{
if (! (i % supersample))
memset (vals, 0, sizeof (gint) * size_x);
yy = (gdouble) i / (gdouble) supersample + min_y;
for (j = min_scanlines[i]; j < max_scanlines[i]; j++)
{
x = j - min_x * supersample;
vals[x] += 255;
}
if (! ((i + 1) % supersample))
{
y = (i / supersample) + min_y;
if (y >= y1 && y < y2)
{
for (j = 0; j < size_x; j += supersample)
{
x = (j / supersample) + min_x;
if (x >= x1 && x < x2)
{
val = 0;
for (k = 0; k < supersample; k++)
val += vals[j + k];
val /= supersample2;
if (val > 0)
{
xx = (gdouble) j / (gdouble) supersample + min_x;
alpha = (gint) (val * calc_alpha_blend (vec, dist, xx - sx, yy - sy));
gimp_pixel_rgn_get_pixel (&src_rgn, buf, x, y);
for (b = 0; b < bytes; b++)
buf[b] = ((col[b] * alpha) + (buf[b] * (255 - alpha))) / 255;
gimp_pixel_rgn_set_pixel (&src_rgn, buf, x, y);
}
}
}
}
}
}
free (vals);
free (min_scanlines);
free (max_scanlines);
}
static void
convert_segment (gint x1,
gint y1,
gint x2,
gint y2,
gint offset,
gint *min,
gint *max)
{
gint ydiff, y, tmp;
gdouble xinc, xstart;
if (y1 > y2)
{ tmp = y2; y2 = y1; y1 = tmp;
tmp = x2; x2 = x1; x1 = tmp; }
ydiff = (y2 - y1);
if ( ydiff )
{
xinc = (gdouble) (x2 - x1) / (gdouble) ydiff;
xstart = x1 + 0.5 * xinc;
for (y = y1 ; y < y2; y++)
{
if (xstart < min[y - offset])
min[y-offset] = xstart;
if (xstart > max[y - offset])
max[y-offset] = xstart;
xstart += xinc;
}
}
}
static gdouble
calc_alpha_blend (gdouble *vec,
gdouble dist,
gdouble x,
gdouble y)
{
gdouble r;
if (!dist)
return 1.0;
else
{
r = (vec[1] * y + vec[0] * x) / dist;
if (r < 0.2)
r = 0.2;
else if (r > 1.0)
r = 1.0;
}
return r;
}
static void
randomize_indices (gint count,
gint *indices)
{
gint i;
gint index1, index2;
gint tmp;
for (i = 0; i < count * RANDOMNESS; i++)
{
index1 = int_rand (count);
index2 = int_rand (count);
tmp = indices[index1];
indices[index1] = indices[index2];
indices[index2] = tmp;
}
}
static gdouble
fp_rand (gdouble val)
{
gdouble rand_val;
rand_val = (gdouble) rand () / (gdouble) (RAND_MAX - 1);
return rand_val * val;
}
static gint
int_rand (gint val)
{
gint rand_val;
rand_val = rand () % val;
return rand_val;
}
static void
polygon_add_point (Polygon *poly,
gdouble x,
gdouble y)
{
if (poly->npts < 12)
{
poly->pts[poly->npts].x = x;
poly->pts[poly->npts].y = y;
poly->npts++;
}
else
g_print ("Unable to add additional point.\n");
}
static void
polygon_rotate (Polygon *poly,
gdouble theta)
{
gint i;
gdouble ct, st;
gdouble ox, oy;
ct = cos (theta);
st = sin (theta);
for (i = 0; i < poly->npts; i++)
{
ox = poly->pts[i].x;
oy = poly->pts[i].y;
poly->pts[i].x = ct * ox - st * oy;
poly->pts[i].y = st * ox + ct * oy;
}
}
static void
polygon_translate (Polygon *poly,
gdouble tx,
gdouble ty)
{
gint i;
for (i = 0; i < poly->npts; i++)
{
poly->pts[i].x += tx;
poly->pts[i].y += ty;
}
}
static gint
polygon_extents (Polygon *poly,
gdouble *x1,
gdouble *y1,
gdouble *x2,
gdouble *y2)
{
gint i;
if (!poly->npts)
return 0;
*x1 = *x2 = poly->pts[0].x;
*y1 = *y2 = poly->pts[0].y;
for (i = 1; i < poly->npts; i++)
{
if (poly->pts[i].x < *x1)
*x1 = poly->pts[i].x;
if (poly->pts[i].x > *x2)
*x2 = poly->pts[i].x;
if (poly->pts[i].y < *y1)
*y1 = poly->pts[i].y;
if (poly->pts[i].y > *y2)
*y2 = poly->pts[i].y;
}
return 1;
}
static void
polygon_reset (Polygon *poly)
{
poly->npts = 0;
}
/* Cubism interface functions */
static void
cubism_close_callback (GtkWidget *widget,
gpointer data)
{
gtk_main_quit ();
}
static void
cubism_ok_callback (GtkWidget *widget,
gpointer data)
{
cint.run = TRUE;
gtk_widget_destroy (GTK_WIDGET (data));
}
static void
cubism_toggle_update (GtkWidget *widget,
gpointer data)
{
int *toggle_val;
toggle_val = (int *) data;
if (GTK_TOGGLE_BUTTON (widget)->active)
*toggle_val = TRUE;
else
*toggle_val = FALSE;
}
static void
cubism_scale_update (GtkAdjustment *adjustment,
double *scale_val)
{
*scale_val = adjustment->value;
}

View File

@ -1,979 +0,0 @@
/* The GIMP -- an image manipulation program
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
* Decompose plug-in (C) 1997 Peter Kirchgessner
* e-mail: pkirchg@aol.com, WWW: http://members.aol.com/pkirchg
*
* 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
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/*
* This filter decomposes RGB-images into several types of channels
*/
/* Event history:
* V 1.00, PK, 29-Jul-97, Creation
*/
static char ident[] = "@(#) GIMP Decompose plug-in v1.00 29-Jul-97";
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "gtk/gtk.h"
#include "libgimp/gimp.h"
/* Declare local functions
*/
static void query (void);
static void run (char *name,
int nparams,
GParam *param,
int *nreturn_vals,
GParam **return_vals);
static gint32 decompose (gint32 image_id,
gint32 drawable_ID,
char *extract_type,
gint32 *drawable_ID_dst);
static gint32 create_new_image (char *filename, guint width, guint height,
GImageType type, gint32 *layer_ID, GDrawable **drawable,
GPixelRgn *pixel_rgn);
static int cmp_icase (char *s1, char *s2);
static void rgb_to_hsv (unsigned char *r, unsigned char *g, unsigned char *b,
unsigned char *h, unsigned char *s, unsigned char *v);
static void extract_rgb (unsigned char *src, int bpp, int numpix,
unsigned char **dst);
static void extract_red (unsigned char *src, int bpp, int numpix,
unsigned char **dst);
static void extract_green (unsigned char *src, int bpp, int numpix,
unsigned char **dst);
static void extract_blue (unsigned char *src, int bpp, int numpix,
unsigned char **dst);
static void extract_alpha (unsigned char *src, int bpp, int numpix,
unsigned char **dst);
static void extract_hsv (unsigned char *src, int bpp, int numpix,
unsigned char **dst);
static void extract_hue (unsigned char *src, int bpp, int numpix,
unsigned char **dst);
static void extract_sat (unsigned char *src, int bpp, int numpix,
unsigned char **dst);
static void extract_val (unsigned char *src, int bpp, int numpix,
unsigned char **dst);
static void extract_cmy (unsigned char *src, int bpp, int numpix,
unsigned char **dst);
static void extract_cyan (unsigned char *src, int bpp, int numpix,
unsigned char **dst);
static void extract_magenta (unsigned char *src, int bpp, int numpix,
unsigned char **dst);
static void extract_yellow (unsigned char *src, int bpp, int numpix,
unsigned char **dst);
static void extract_cmyk (unsigned char *src, int bpp, int numpix,
unsigned char **dst);
static void extract_cyank (unsigned char *src, int bpp, int numpix,
unsigned char **dst);
static void extract_magentak (unsigned char *src, int bpp, int numpix,
unsigned char **dst);
static void extract_yellowk (unsigned char *src, int bpp, int numpix,
unsigned char **dst);
static gint decompose_dialog (void);
static void decompose_close_callback (GtkWidget *widget,
gpointer data);
static void decompose_ok_callback (GtkWidget *widget,
gpointer data);
static void decompose_toggle_update (GtkWidget *widget,
gpointer data);
/* Maximum number of new images generated by an extraction */
#define MAX_EXTRACT_IMAGES 4
/* Description of an extraction */
typedef struct {
char *type; /* What to extract */
int dialog; /* Dialog-Flag. Set it to 1 if you want to appear */
/* this extract function within the dialog */
int num_images; /* Number of images to create */
char *channel_name[MAX_EXTRACT_IMAGES]; /* Names of channels to extract */
/* Function that performs the extraction */
void (*extract_fun)(unsigned char *src, int bpp, int numpix,
unsigned char **dst);
} EXTRACT;
static EXTRACT extract[] = {
{ "RGB", 1, 3, { "red", "green", "blue" }, extract_rgb },
{ "Red", 0, 1, { "red" }, extract_red },
{ "Green", 0, 1, { "green" }, extract_green },
{ "Blue", 0, 1, { "blue" }, extract_blue },
{ "HSV", 1, 3, { "hue", "saturation", "value", }, extract_hsv },
{ "Hue", 0, 1, { "hue" }, extract_hue },
{ "Saturation",0,1, { "saturation", }, extract_sat },
{ "Value", 0, 1, { "value", }, extract_val },
{ "CMY", 1, 3, { "cyan", "magenta", "yellow" }, extract_cmy },
{ "Cyan", 0, 1, { "cyan", }, extract_cyan },
{ "Magenta", 0, 1, { "magenta", }, extract_magenta },
{ "Yellow", 0, 1, { "yellow", }, extract_yellow },
{ "CMYK", 1, 4, { "cyan_k", "magenta_k", "yellow_k", "black" }, extract_cmyk },
{ "Cyan_K", 0, 1, { "cyan_k", }, extract_cyank },
{ "Magenta_K", 0,1, { "magenta_k", }, extract_magentak },
{ "Yellow_K", 0, 1, { "yellow_k", }, extract_yellowk },
{ "Alpha", 1, 1, { "alpha" }, extract_alpha }
};
/* Number of types of extractions */
#define NUM_EXTRACT_TYPES (sizeof (extract)/sizeof (extract[0]))
typedef struct {
char extract_type[32];
} DecoVals;
typedef struct {
gint extract_flag[NUM_EXTRACT_TYPES];
gint run;
} DecoInterface;
GPlugInInfo PLUG_IN_INFO =
{
NULL, /* init_proc */
NULL, /* quit_proc */
query, /* query_proc */
run, /* run_proc */
};
static DecoVals decovals =
{
"rgb" /* Decompose type */
};
static DecoInterface decoint =
{
{ 0 }, /* extract flags */
FALSE /* run */
};
static GRunModeType run_mode;
MAIN ()
static void
query ()
{
static GParamDef args[] =
{
{ PARAM_INT32, "run_mode", "Interactive, non-interactive" },
{ PARAM_IMAGE, "image", "Input image (unused)" },
{ PARAM_DRAWABLE, "drawable", "Input drawable" },
{ PARAM_STRING, "decompose_type", "What to decompose: RGB, Red, Green,\
Blue, HSV, Hue, Saturation, Value, CMY, Cyan, Magenta, Yellow, CMYK,\
Cyan_K, Magenta_K, Yellow_K, Alpha" }
};
static GParamDef return_vals[] =
{
{ PARAM_IMAGE, "new_image", "Output gray image" },
{ PARAM_IMAGE, "new_image", "Output gray image (N/A for single channel extract)" },
{ PARAM_IMAGE, "new_image", "Output gray image (N/A for single channel extract)" },
{ PARAM_IMAGE, "new_image", "Output gray image (N/A for single channel extract)" },
};
static int nargs = sizeof (args) / sizeof (args[0]);
static int nreturn_vals = sizeof (return_vals) / sizeof (return_vals[0]);
gimp_install_procedure ("plug_in_decompose",
"Decompose an image into different types of channels",
"This function creates new gray images with\
different channel information in each of them",
"Peter Kirchgessner",
"Peter Kirchgessner (pkirchg@aol.com)",
"1997",
"<Image>/Image/Channel Ops/Decompose",
"RGB*",
PROC_PLUG_IN,
nargs, nreturn_vals,
args, return_vals);
}
static void
run (char *name,
int nparams,
GParam *param,
int *nreturn_vals,
GParam **return_vals)
{
static GParam values[MAX_EXTRACT_IMAGES+1];
GStatusType status = STATUS_SUCCESS;
GDrawableType drawable_type;
gint32 num_images;
gint32 image_ID_extract[MAX_EXTRACT_IMAGES];
gint j;
run_mode = param[0].data.d_int32;
*nreturn_vals = MAX_EXTRACT_IMAGES+1;
*return_vals = values;
values[0].type = PARAM_STATUS;
values[0].data.d_status = status;
for (j = 0; j < MAX_EXTRACT_IMAGES; j++)
{
values[j+1].type = PARAM_IMAGE;
values[j+1].data.d_int32 = -1;
}
switch (run_mode)
{
case RUN_INTERACTIVE:
/* Possibly retrieve data */
gimp_get_data ("plug_in_decompose", &decovals);
/* First acquire information with a dialog */
if (! decompose_dialog ())
return;
break;
case RUN_NONINTERACTIVE:
/* Make sure all the arguments are there! */
if (nparams != 4)
status = STATUS_CALLING_ERROR;
if (status == STATUS_SUCCESS)
{
strncpy (decovals.extract_type, param[3].data.d_string,
sizeof (decovals.extract_type));
decovals.extract_type[sizeof (decovals.extract_type)-1] = '\0';
}
break;
case RUN_WITH_LAST_VALS:
/* Possibly retrieve data */
gimp_get_data ("plug_in_decompose", &decovals);
break;
default:
break;
}
/* Make sure that the drawable is RGB color */
drawable_type = gimp_drawable_type (param[2].data.d_drawable);
if ((drawable_type != RGB_IMAGE) && (drawable_type != RGBA_IMAGE))
{
printf ("plug_in_decompose: Can only work on RGB*_IMAGE\n");
status = STATUS_CALLING_ERROR;
}
if (status == STATUS_SUCCESS)
{
if (run_mode != RUN_NONINTERACTIVE)
gimp_progress_init ("Decomposing...");
num_images = decompose (param[1].data.d_image, param[2].data.d_drawable,
decovals.extract_type, image_ID_extract);
if (num_images <= 0)
{
status = STATUS_EXECUTION_ERROR;
}
else
{
for (j = 0; j < num_images; j++)
{
values[j+1].data.d_int32 = image_ID_extract[j];
gimp_image_enable_undo (image_ID_extract[j]);
gimp_image_clean_all (image_ID_extract[j]);
if (run_mode != RUN_NONINTERACTIVE)
gimp_display_new (image_ID_extract[j]);
}
/* Store data */
if (run_mode == RUN_INTERACTIVE)
gimp_set_data ("plug_in_decompose", &decovals, sizeof (DecoVals));
}
}
values[0].data.d_status = status;
}
/* Decompose an image. It returns the number of new (gray) images.
The image IDs for the new images are returned in image_ID_dst.
On failure, -1 is returned.
*/
static gint32
decompose (gint32 image_ID,
gint32 drawable_ID,
char *extract_type,
gint32 *image_ID_dst)
{
int i, j, extract_idx, scan_lines;
int height, width, tile_height, num_images;
unsigned char *src = (unsigned char *)ident; /* Just to satisfy gcc/lint */
char filename[1024];
unsigned char *dst[MAX_EXTRACT_IMAGES];
gint32 layer_ID_dst[MAX_EXTRACT_IMAGES];
GDrawable *drawable_src, *drawable_dst[MAX_EXTRACT_IMAGES];
GPixelRgn pixel_rgn_src, pixel_rgn_dst[MAX_EXTRACT_IMAGES];
extract_idx = -1; /* Search extract type */
for (j = 0; j < NUM_EXTRACT_TYPES; j++)
{
if (cmp_icase (extract_type, extract[j].type) == 0)
{
extract_idx = j;
break;
}
}
if (extract_idx < 0) return (-1);
/* Check structure of source image */
drawable_src = gimp_drawable_get (drawable_ID);
if (drawable_src->bpp < 3)
{
printf ("decompose: not an RGB image\n");
return (-1);
}
if ( (extract[extract_idx].extract_fun == extract_alpha)
&& (!gimp_drawable_has_alpha (drawable_ID)))
{
printf ("decompose: No alpha channel available\n");
return (-1);
}
width = drawable_src->width;
height = drawable_src->height;
tile_height = gimp_tile_height ();
gimp_pixel_rgn_init (&pixel_rgn_src, drawable_src, 0, 0, width, height,
FALSE, FALSE);
/* allocate a buffer for retrieving information from the src pixel region */
src = (unsigned char *)g_malloc (tile_height * width * drawable_src->bpp);
/* Create all new gray images */
num_images = extract[extract_idx].num_images;
if (num_images > MAX_EXTRACT_IMAGES) num_images = MAX_EXTRACT_IMAGES;
for (j = 0; j < num_images; j++)
{
sprintf (filename, "%s-%s", gimp_image_get_filename (image_ID),
extract[extract_idx].channel_name[j]);
image_ID_dst[j] = create_new_image (filename, width, height, GRAY,
layer_ID_dst+j, drawable_dst+j, pixel_rgn_dst+j);
dst[j] = (unsigned char *)g_malloc (tile_height * width);
}
if (dst[num_images-1] == NULL)
{
printf ("decompose: out of memory\n");
for (j = 0; j < num_images; j++)
{
if (dst[j] != NULL) g_free (dst[j]);
}
return (-1);
}
i = 0;
while (i < height)
{
/* Get source pixel region */
scan_lines = (i+tile_height-1 < height) ? tile_height : (height-i);
gimp_pixel_rgn_get_rect (&pixel_rgn_src, src, 0, i, width, scan_lines);
/* Extract the channel information */
extract[extract_idx].extract_fun (src, drawable_src->bpp, scan_lines*width,
dst);
/* Set destination pixel regions */
for (j = 0; j < num_images; j++)
gimp_pixel_rgn_set_rect (&(pixel_rgn_dst[j]), dst[j], 0, i, width,
scan_lines);
i += scan_lines;
if (run_mode != RUN_NONINTERACTIVE)
gimp_progress_update (((double)i) / (double)height);
}
g_free (src);
for (j = 0; j < num_images; j++)
{
gimp_drawable_flush (drawable_dst[j]);
gimp_drawable_detach (drawable_dst[j]);
g_free (dst[j]);
}
gimp_drawable_flush (drawable_src);
gimp_drawable_detach (drawable_src);
return (num_images);
}
/* Create an image. Sets layer_ID, drawable and rgn. Returns image_ID */
static gint32
create_new_image (char *filename,
guint width,
guint height,
GImageType type,
gint32 *layer_ID,
GDrawable **drawable,
GPixelRgn *pixel_rgn)
{gint32 image_ID;
GDrawableType gdtype;
if (type == GRAY) gdtype = GRAY_IMAGE;
else if (type == INDEXED) gdtype = INDEXED_IMAGE;
else gdtype = RGB_IMAGE;
image_ID = gimp_image_new (width, height, type);
gimp_image_set_filename (image_ID, filename);
*layer_ID = gimp_layer_new (image_ID, "Background", width, height,
gdtype, 100, NORMAL_MODE);
gimp_image_add_layer (image_ID, *layer_ID, 0);
*drawable = gimp_drawable_get (*layer_ID);
gimp_pixel_rgn_init (pixel_rgn, *drawable, 0, 0, (*drawable)->width,
(*drawable)->height, TRUE, FALSE);
return (image_ID);
}
/* Compare two strings ignoring case (could also be done by strcasecmp() */
/* but is it available everywhere ?) */
static int cmp_icase (char *s1, char *s2)
{int c1, c2;
c1 = toupper (*s1); c2 = toupper (*s2);
while (*s1 && *s2)
{
if (c1 != c2) return (c2 - c1);
c1 = toupper (*(++s1)); c2 = toupper (*(++s2));
}
return (c2 - c1);
}
/* Convert RGB to HSV. This routine was taken from decompose plug-in
of GIMP V 0.54 and modified a little bit.
*/
static void rgb_to_hsv (unsigned char *r, unsigned char *g, unsigned char *b,
unsigned char *h, unsigned char *s, unsigned char *v)
{
int red = (int)*r, green = (int)*g, blue = (int)*b;
double hue;
int min, max, delta, sat_i;
if (red > green)
{
if (red > blue)
max = red;
else
max = blue;
if (green < blue)
min = green;
else
min = blue;
}
else
{
if (green > blue)
max = green;
else
max = blue;
if (red < blue)
min = red;
else
min = blue;
}
*v = (unsigned char)max;
if (max != 0)
sat_i = ((max - min) * 255) / max;
else
sat_i = 0;
*s = (unsigned char)sat_i;
if (sat_i == 0)
{
*h = 0;
}
else
{
delta = max - min;
if (red == max)
hue = (green - blue) / (double)delta;
else if (green == max)
hue = 2.0 + (blue - red) / (double)delta;
else
hue = 4.0 + (red - green) / (double)delta;
hue *= 42.5;
if (hue < 0.0)
hue += 255.0;
if (hue > 255.0)
hue -= 255.0;
*h = (unsigned char)hue;
}
}
/* Extract functions */
static void extract_rgb (unsigned char *src, int bpp, int numpix,
unsigned char **dst)
{register unsigned char *rgb_src = src;
register unsigned char *red_dst = dst[0];
register unsigned char *green_dst = dst[1];
register unsigned char *blue_dst = dst[2];
register int count = numpix, offset = bpp-3;
while (count-- > 0)
{
*(red_dst++) = *(rgb_src++);
*(green_dst++) = *(rgb_src++);
*(blue_dst++) = *(rgb_src++);
rgb_src += offset;
}
}
static void extract_red (unsigned char *src, int bpp, int numpix,
unsigned char **dst)
{register unsigned char *rgb_src = src;
register unsigned char *red_dst = dst[0];
register int count = numpix, offset = bpp;
while (count-- > 0)
{
*(red_dst++) = *rgb_src;
rgb_src += offset;
}
}
static void extract_green (unsigned char *src, int bpp, int numpix,
unsigned char **dst)
{register unsigned char *rgb_src = src+1;
register unsigned char *green_dst = dst[0];
register int count = numpix, offset = bpp;
while (count-- > 0)
{
*(green_dst++) = *rgb_src;
rgb_src += offset;
}
}
static void extract_blue (unsigned char *src, int bpp, int numpix,
unsigned char **dst)
{register unsigned char *rgb_src = src+2;
register unsigned char *blue_dst = dst[0];
register int count = numpix, offset = bpp;
while (count-- > 0)
{
*(blue_dst++) = *rgb_src;
rgb_src += offset;
}
}
static void extract_alpha (unsigned char *src, int bpp, int numpix,
unsigned char **dst)
{register unsigned char *rgb_src = src+3;
register unsigned char *alpha_dst = dst[0];
register int count = numpix, offset = bpp;
while (count-- > 0)
{
*(alpha_dst++) = *rgb_src;
rgb_src += offset;
}
}
static void extract_cmy (unsigned char *src, int bpp, int numpix,
unsigned char **dst)
{register unsigned char *rgb_src = src;
register unsigned char *cyan_dst = dst[0];
register unsigned char *magenta_dst = dst[1];
register unsigned char *yellow_dst = dst[2];
register int count = numpix, offset = bpp-3;
while (count-- > 0)
{
*(cyan_dst++) = 255 - *(rgb_src++);
*(magenta_dst++) = 255 - *(rgb_src++);
*(yellow_dst++) = 255 - *(rgb_src++);
rgb_src += offset;
}
}
static void extract_hsv (unsigned char *src, int bpp, int numpix,
unsigned char **dst)
{register unsigned char *rgb_src = src;
register unsigned char *hue_dst = dst[0];
register unsigned char *sat_dst = dst[1];
register unsigned char *val_dst = dst[2];
register int count = numpix, offset = bpp;
while (count-- > 0)
{
rgb_to_hsv (rgb_src, rgb_src+1, rgb_src+2, hue_dst++, sat_dst++, val_dst++);
rgb_src += offset;
}
}
static void extract_hue (unsigned char *src, int bpp, int numpix,
unsigned char **dst)
{register unsigned char *rgb_src = src;
register unsigned char *hue_dst = dst[0];
unsigned char dmy;
unsigned char *dummy = &dmy;
register int count = numpix, offset = bpp;
while (count-- > 0)
{
rgb_to_hsv (rgb_src, rgb_src+1, rgb_src+2, hue_dst++, dummy, dummy);
rgb_src += offset;
}
}
static void extract_sat (unsigned char *src, int bpp, int numpix,
unsigned char **dst)
{register unsigned char *rgb_src = src;
register unsigned char *sat_dst = dst[0];
unsigned char dmy;
unsigned char *dummy = &dmy;
register int count = numpix, offset = bpp;
while (count-- > 0)
{
rgb_to_hsv (rgb_src, rgb_src+1, rgb_src+2, dummy, sat_dst++, dummy);
rgb_src += offset;
}
}
static void extract_val (unsigned char *src, int bpp, int numpix,
unsigned char **dst)
{register unsigned char *rgb_src = src;
register unsigned char *val_dst = dst[0];
unsigned char dmy;
unsigned char *dummy = &dmy;
register int count = numpix, offset = bpp;
while (count-- > 0)
{
rgb_to_hsv (rgb_src, rgb_src+1, rgb_src+2, dummy, dummy, val_dst++);
rgb_src += offset;
}
}
static void extract_cyan (unsigned char *src, int bpp, int numpix,
unsigned char **dst)
{register unsigned char *rgb_src = src;
register unsigned char *cyan_dst = dst[0];
register int count = numpix, offset = bpp-1;
while (count-- > 0)
{
*(cyan_dst++) = 255 - *(rgb_src++);
rgb_src += offset;
}
}
static void extract_magenta (unsigned char *src, int bpp, int numpix,
unsigned char **dst)
{register unsigned char *rgb_src = src+1;
register unsigned char *magenta_dst = dst[0];
register int count = numpix, offset = bpp-1;
while (count-- > 0)
{
*(magenta_dst++) = 255 - *(rgb_src++);
rgb_src += offset;
}
}
static void extract_yellow (unsigned char *src, int bpp, int numpix,
unsigned char **dst)
{register unsigned char *rgb_src = src+2;
register unsigned char *yellow_dst = dst[0];
register int count = numpix, offset = bpp-1;
while (count-- > 0)
{
*(yellow_dst++) = 255 - *(rgb_src++);
rgb_src += offset;
}
}
static void extract_cmyk (unsigned char *src, int bpp, int numpix,
unsigned char **dst)
{register unsigned char *rgb_src = src;
register unsigned char *cyan_dst = dst[0];
register unsigned char *magenta_dst = dst[1];
register unsigned char *yellow_dst = dst[2];
register unsigned char *black_dst = dst[3];
register unsigned char k, s;
register int count = numpix, offset = bpp-3;
while (count-- > 0)
{
*cyan_dst = k = 255 - *(rgb_src++);
*magenta_dst = s = 255 - *(rgb_src++);
if (s < k) k = s;
*yellow_dst = s = 255 - *(rgb_src++);
if (s < k) k = s; /* Black intensity is minimum of c, m, y */
if (k)
{
*cyan_dst -= k; /* Remove common part of c, m, y */
*magenta_dst -= k;
*yellow_dst -= k;
}
cyan_dst++;
magenta_dst++;
yellow_dst++;
*(black_dst++) = k;
rgb_src += offset;
}
}
static void extract_cyank (unsigned char *src, int bpp, int numpix,
unsigned char **dst)
{register unsigned char *rgb_src = src;
register unsigned char *cyan_dst = dst[0];
register unsigned char s, k;
register int count = numpix, offset = bpp-3;
while (count-- > 0)
{
*cyan_dst = k = 255 - *(rgb_src++);
s = 255 - *(rgb_src++); /* magenta */
if (s < k) k = s;
s = 255 - *(rgb_src++); /* yellow */
if (s < k) k = s;
if (k) *cyan_dst -= k;
cyan_dst++;
rgb_src += offset;
}
}
static void extract_magentak (unsigned char *src, int bpp, int numpix,
unsigned char **dst)
{register unsigned char *rgb_src = src;
register unsigned char *magenta_dst = dst[0];
register unsigned char s, k;
register int count = numpix, offset = bpp-3;
while (count-- > 0)
{
k = 255 - *(rgb_src++); /* cyan */
*magenta_dst = s = 255 - *(rgb_src++); /* magenta */
if (s < k) k = s;
s = 255 - *(rgb_src++); /* yellow */
if (s < k) k = s;
if (k) *magenta_dst -= k;
magenta_dst++;
rgb_src += offset;
}
}
static void extract_yellowk (unsigned char *src, int bpp, int numpix,
unsigned char **dst)
{register unsigned char *rgb_src = src;
register unsigned char *yellow_dst = dst[0];
register unsigned char s, k;
register int count = numpix, offset = bpp-3;
while (count-- > 0)
{
k = 255 - *(rgb_src++); /* cyan */
s = 255 - *(rgb_src++); /* magenta */
if (s < k) k = s;
*yellow_dst = s = 255 - *(rgb_src++);
if (s < k) k = s;
if (k) *yellow_dst -= k;
yellow_dst++;
rgb_src += offset;
}
}
static gint
decompose_dialog (void)
{
GtkWidget *dlg;
GtkWidget *button;
GtkWidget *toggle;
GtkWidget *frame;
GtkWidget *vbox;
GSList *group;
gchar **argv;
gint argc;
int j;
argc = 1;
argv = g_new (gchar *, 1);
argv[0] = g_strdup ("Decompose");
gtk_init (&argc, &argv);
gtk_rc_parse (gimp_gtkrc ());
dlg = gtk_dialog_new ();
gtk_window_set_title (GTK_WINDOW (dlg), "Decompose");
gtk_window_position (GTK_WINDOW (dlg), GTK_WIN_POS_MOUSE);
gtk_signal_connect (GTK_OBJECT (dlg), "destroy",
(GtkSignalFunc) decompose_close_callback,
NULL);
/* Action area */
button = gtk_button_new_with_label ("OK");
GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
gtk_signal_connect (GTK_OBJECT (button), "clicked",
(GtkSignalFunc) decompose_ok_callback,
dlg);
gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dlg)->action_area), button, TRUE, TRUE, 0);
gtk_widget_grab_default (button);
gtk_widget_show (button);
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));
gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dlg)->action_area), button, TRUE, TRUE, 0);
gtk_widget_show (button);
/* parameter settings */
frame = gtk_frame_new ("Extract channels:");
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);
vbox = gtk_vbox_new (FALSE, 5);
gtk_container_border_width (GTK_CONTAINER (vbox), 10);
gtk_container_add (GTK_CONTAINER (frame), vbox);
group = NULL;
for (j = 0; j < NUM_EXTRACT_TYPES; j++)
{
if (!extract[j].dialog) continue;
toggle = gtk_radio_button_new_with_label (group, extract[j].type);
group = gtk_radio_button_group (GTK_RADIO_BUTTON (toggle));
gtk_box_pack_start (GTK_BOX (vbox), toggle, TRUE, TRUE, 0);
decoint.extract_flag[j] =
(cmp_icase (decovals.extract_type, extract[j].type) == 0);
gtk_signal_connect (GTK_OBJECT (toggle), "toggled",
(GtkSignalFunc) decompose_toggle_update,
&(decoint.extract_flag[j]));
gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (toggle),
decoint.extract_flag[j]);
gtk_widget_show (toggle);
}
gtk_widget_show (vbox);
gtk_widget_show (frame);
gtk_widget_show (dlg);
gtk_main ();
gdk_flush ();
return decoint.run;
}
/* Decompose interface functions */
static void
decompose_close_callback (GtkWidget *widget,
gpointer data)
{
gtk_main_quit ();
}
static void
decompose_ok_callback (GtkWidget *widget,
gpointer data)
{int j;
decoint.run = TRUE;
gtk_widget_destroy (GTK_WIDGET (data));
for (j = 0; j < NUM_EXTRACT_TYPES; j++)
{
if (decoint.extract_flag[j])
{
strcpy (decovals.extract_type, extract[j].type);
break;
}
}
}
static void
decompose_toggle_update (GtkWidget *widget,
gpointer data)
{
gint *toggle_val;
toggle_val = (int *) data;
if (GTK_TOGGLE_BUTTON (widget)->active)
*toggle_val = TRUE;
else
*toggle_val = FALSE;
}

View File

@ -1,259 +0,0 @@
/* Deinterlace 1.00 - image processing plug-in for the Gimp 1.0 API
*
* Copyright (C) 1997 Andrew Kieschnick (andrewk@mail.utexas.edu)
*
* Original deinterlace for the Gimp 0.54 API by Federico Mena Quintero
*
* Copyright (C) 1996 Federico Mena Quintero
*
* Any bugs in this code are probably my (Andrew Kieschnick's) fault, as I
* pretty much rewrote it from scratch.
*
* 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
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <stdlib.h>
#include <libgimp/gimp.h>
#include <gtk/gtk.h>
#include "megawidget.h"
/* Declare local functions.
*/
static void query (void);
static void run (char *name,
int nparams,
GParam *param,
int *nreturn_vals,
GParam **return_vals);
static void deinterlace (GDrawable *drawable);
static gint deinterlace_dialog(void);
GPlugInInfo PLUG_IN_INFO =
{
NULL, /* init_proc */
NULL, /* quit_proc */
query, /* query_proc */
run, /* run_proc */
};
static gint DeinterlaceValue = 1;
MAIN ()
static void
query ()
{
static GParamDef args[] =
{
{ PARAM_INT32, "run_mode", "Interactive, non-interactive" },
{ PARAM_IMAGE, "image", "Input image (unused)" },
{ PARAM_DRAWABLE, "drawable", "Input drawable" },
{ PARAM_INT32, "evenodd", "0 = keep odd, 1 = keep even" },
};
static GParamDef *return_vals = NULL;
static int nargs = sizeof (args) / sizeof (args[0]);
static int nreturn_vals = 0;
gimp_install_procedure ("plug_in_deinterlace",
"Deinterlace",
"Deinterlace is useful for processing images from video capture cards. When only the odd or even fields get captured, deinterlace can be used to interpolate between the existing fields to correct this.",
"Andrew Kieschnick",
"Andrew Kieschnick",
"1997",
"<Image>/Filters/Image/Deinterlace",
"RGB*, GRAY*",
PROC_PLUG_IN,
nargs, nreturn_vals,
args, return_vals);
}
static void
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;
run_mode = param[0].data.d_int32;
/* Get the specified drawable */
drawable = gimp_drawable_get (param[2].data.d_drawable);
switch (run_mode)
{
case RUN_INTERACTIVE:
gimp_get_data("plug_in_deinterlace", &DeinterlaceValue);
if (! deinterlace_dialog())
status = STATUS_EXECUTION_ERROR;
break;
case RUN_NONINTERACTIVE:
if (nparams != 1)
status = STATUS_CALLING_ERROR;
if (status == STATUS_SUCCESS)
DeinterlaceValue = param[3].data.d_int32;
break;
case RUN_WITH_LAST_VALS:
gimp_get_data("plug_in_deinterlace", &DeinterlaceValue);
break;
default:
break;
}
if (status == STATUS_SUCCESS)
{
/* Make sure that the drawable is gray or RGB color */
if (gimp_drawable_color (drawable->id) || gimp_drawable_gray (drawable->id))
{
gimp_progress_init ("deinterlace");
gimp_tile_cache_ntiles (2 * (drawable->width / gimp_tile_width () + 1));
deinterlace (drawable);
if (run_mode != RUN_NONINTERACTIVE)
gimp_displays_flush ();
if (run_mode == RUN_INTERACTIVE)
gimp_set_data("plug_in_deinterlace", &DeinterlaceValue, sizeof(DeinterlaceValue));
}
else
{
/* gimp_message ("deinterlace: cannot operate on indexed color images"); */
status = STATUS_EXECUTION_ERROR;
}
}
*nreturn_vals = 1;
*return_vals = values;
values[0].type = PARAM_STATUS;
values[0].data.d_status = status;
gimp_drawable_detach (drawable);
}
static void
deinterlace (GDrawable *drawable)
{
GPixelRgn srcPR, destPR;
gint width, height;
gint bytes;
guchar *dest;
guchar *upper;
guchar *lower;
gint row, col;
gint x1, y1, x2, y2;
/* 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.
*/
width = drawable->width;
height = drawable->height;
bytes = drawable->bpp;
/* allocate row buffers */
dest = (guchar *) malloc ((x2 - x1) * bytes);
upper = (guchar *) malloc ((x2 - x1) * bytes);
lower = (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);
/* loop through the rows, performing our magic*/
for (row = y1; row < y2; row++)
{
gimp_pixel_rgn_get_row (&srcPR, dest, x1, row, (x2-x1));
/* Only do interpolation if the row:
(1) Isn't one we want to keep
(2) Has both an upper and a lower row
Otherwise, just duplicate the source row
*/
if (!((row % 2 == DeinterlaceValue) || (row - 1 < 0) || (row + 1 >= height))) {
gimp_pixel_rgn_get_row (&srcPR, upper, x1, row-1, (x2-x1));
gimp_pixel_rgn_get_row (&srcPR, lower, x1, row+1, (x2-x1));
for (col=(x1*bytes); col < (x2*bytes); col++)
dest[col]=(upper[col]+lower[col])>>1;
}
gimp_pixel_rgn_set_row (&destPR, dest, x1, row, (x2-x1));
if ((row % 5) == 0)
gimp_progress_update ((double) row / (double) (y2 - y1));
}
/* update the deinterlaced region */
gimp_drawable_flush (drawable);
gimp_drawable_merge_shadow (drawable->id, TRUE);
gimp_drawable_update (drawable->id, x1, y1, (x2 - x1), (y2 - y1));
free (dest);
}
static gint deinterlace_dialog()
{
GtkWidget *dlg;
GtkWidget *vbox;
gint runp;
struct mwRadioGroup modes[] = {
{ "Keep Odd Fields", 0},
{ "Keep Even Fields", 0},
{ NULL, 0}};
modes[DeinterlaceValue].var = 1;
dlg = mw_app_new("plug_in_deinterlace", "Deinterlace", &runp);
vbox = gtk_vbox_new(FALSE, 5);
gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dlg)->vbox), vbox, TRUE, TRUE, 0);
gtk_widget_show(vbox);
mw_radio_group_new(vbox, "Mode", modes);
gtk_widget_show(dlg);
gtk_main();
gdk_flush();
DeinterlaceValue = mw_radio_result(modes);
if (runp)
return 1;
else
return 0;
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,951 +0,0 @@
/*
* Destripe filter for The GIMP -- an image manipulation
* program
*
* Copyright 1997 Marc Lehmann, heavily modified from a filter by
* Michael Sweet.
*
* 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
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* Contents:
*
* main() - Main entry - just call gimp_main()...
* query() - Respond to a plug-in query...
* run() - Run the filter...
* destripe() - Destripe an image.
* destripe_dialog() - Popup a dialog window...
* preview_init() - Initialize the preview window...
* preview_scroll_callback() - Update the preview when a scrollbar is moved.
* preview_update() - Update the preview window.
* preview_exit() - Free all memory used by the preview window...
* dialog_create_ivalue() - Create an integer value control...
* dialog_iscale_update() - Update the value field using the scale.
* dialog_ientry_update() - Update the value field using the text entry.
* dialog_histogram_callback()
* dialog_ok_callback() - Start the filter...
* dialog_cancel_callback() - Cancel the filter...
* dialog_close_callback() - Exit the filter dialog application.
*
* 1997/08/16 * Initial Revision.
*/
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <gtk/gtk.h>
#include <libgimp/gimp.h>
#include <libgimp/gimpui.h>
#include <string.h>
#ifdef __GNUC__
#define inline inline
#else
#define inline
#endif
/*
* Constants...
*/
#define PLUG_IN_NAME "plug_in_destripe"
#define PLUG_IN_VERSION "0.1"
#define PREVIEW_SIZE 200
#define SCALE_WIDTH 140
#define ENTRY_WIDTH 40
#define MAX_AVG 400
/*
* Local functions...
*/
static void query(void);
static void run(char *, int, GParam *, int *, GParam **);
static void destripe(void);
static gint destripe_dialog(void);
static void dialog_create_ivalue(char *, GtkTable *, int, gint *, int, int);
static void dialog_iscale_update(GtkAdjustment *, gint *);
static void dialog_ientry_update(GtkWidget *, gint *);
static void dialog_ok_callback(GtkWidget *, gpointer);
static void dialog_cancel_callback(GtkWidget *, gpointer);
static void dialog_close_callback(GtkWidget *, gpointer);
static void preview_init(void);
static void preview_exit(void);
static void preview_update(void);
static void preview_scroll_callback(void);
/*
* Globals...
*/
GPlugInInfo PLUG_IN_INFO =
{
NULL, /* init_proc */
NULL, /* quit_proc */
query, /* query_proc */
run /* run_proc */
};
GtkWidget *preview; /* Preview widget */
int preview_width, /* Width of preview widget */
preview_height, /* Height of preview widget */
preview_x1, /* Upper-left X of preview */
preview_y1, /* Upper-left Y of preview */
preview_x2, /* Lower-right X of preview */
preview_y2; /* Lower-right Y of preview */
GtkObject *hscroll_data, /* Horizontal scrollbar data */
*vscroll_data; /* Vertical scrollbar data */
GDrawable *drawable = NULL; /* Current image */
int sel_x1, /* Selection bounds */
sel_y1,
sel_x2,
sel_y2;
int histogram = FALSE;
int img_bpp; /* Bytes-per-pixel in image */
gint run_filter = FALSE; /* True if we should run the filter */
int avg_width = 36;
/*
* 'main()' - Main entry - just call gimp_main()...
*/
int
main(int argc, /* I - Number of command-line args */
char *argv[]) /* I - Command-line args */
{
return (gimp_main(argc, argv));
}
/*
* 'query()' - Respond to a plug-in query...
*/
static void
query(void)
{
static GParamDef args[] =
{
{ PARAM_INT32, "run_mode", "Interactive, non-interactive" },
{ PARAM_IMAGE, "image", "Input image" },
{ PARAM_DRAWABLE, "drawable", "Input drawable" },
{ PARAM_INT32, "avg_width", "Averaging filter width (default = 36)" }
};
static GParamDef *return_vals = NULL;
static int nargs = sizeof(args) / sizeof(args[0]),
nreturn_vals = 0;
gimp_install_procedure(PLUG_IN_NAME,
"Destripe filter, used to remove vertical stripes caused by cheap scanners.",
"This plug-in selectively performs a median or adaptive box filter on an image.",
"Marc Lehmann", "Marc Lehmann",
PLUG_IN_VERSION,
"<Image>/Filters/Image/Destripe...",
"RGB*, GRAY*",
PROC_PLUG_IN, nargs, nreturn_vals, args, return_vals);
}
/*
* 'run()' - Run the filter...
*/
static void
run(char *name, /* I - Name of filter program. */
int nparams, /* I - Number of parameters passed in */
GParam *param, /* I - Parameter values */
int *nreturn_vals, /* O - Number of return values */
GParam **return_vals) /* O - Return values */
{
GRunModeType run_mode; /* Current run mode */
GStatusType status; /* Return status */
static GParam values[1]; /* Return values */
/*
* Initialize parameter data...
*/
status = STATUS_SUCCESS;
run_mode = param[0].data.d_int32;
values[0].type = PARAM_STATUS;
values[0].data.d_status = status;
*nreturn_vals = 1;
*return_vals = values;
/*
* Get drawable information...
*/
drawable = gimp_drawable_get(param[2].data.d_drawable);
gimp_drawable_mask_bounds(drawable->id, &sel_x1, &sel_y1, &sel_x2, &sel_y2);
img_bpp = gimp_drawable_bpp(drawable->id);
/*
* See how we will run
*/
switch (run_mode)
{
case RUN_INTERACTIVE :
/*
* Possibly retrieve data...
*/
gimp_get_data(PLUG_IN_NAME, &avg_width);
/*
* Get information from the dialog...
*/
if (!destripe_dialog())
return;
break;
case RUN_NONINTERACTIVE :
/*
* Make sure all the arguments are present...
*/
if (nparams != 4)
status = STATUS_CALLING_ERROR;
else
avg_width = param[3].data.d_int32;
break;
case RUN_WITH_LAST_VALS :
/*
* Possibly retrieve data...
*/
gimp_get_data(PLUG_IN_NAME, &avg_width);
break;
default :
status = STATUS_CALLING_ERROR;
break;
};
/*
* Destripe the image...
*/
if (status == STATUS_SUCCESS)
{
if ((gimp_drawable_color(drawable->id) ||
gimp_drawable_gray(drawable->id)))
{
/*
* Set the tile cache size...
*/
gimp_tile_cache_ntiles((drawable->width + gimp_tile_width() - 1) /
gimp_tile_width());
/*
* Run!
*/
destripe();
/*
* If run mode is interactive, flush displays...
*/
if (run_mode != RUN_NONINTERACTIVE)
gimp_displays_flush();
/*
* Store data...
*/
if (run_mode == RUN_INTERACTIVE)
gimp_set_data(PLUG_IN_NAME, &avg_width, sizeof(avg_width));
}
else
status = STATUS_EXECUTION_ERROR;
};
/*
* Reset the current run status...
*/
values[0].data.d_status = status;
/*
* Detach from the drawable...
*/
gimp_drawable_detach(drawable);
}
static inline void
preview_draw_row (int x, int y, int w, guchar *row)
{
guchar *rgb = g_new(guchar, w * 3);
guchar *rgb_ptr;
int i;
switch (img_bpp)
{
case 1:
case 2:
for (i = 0, rgb_ptr = rgb; i < w; i++, row += img_bpp, rgb_ptr += 3)
rgb_ptr[0] = rgb_ptr[1] = rgb_ptr[2] = *row;
gtk_preview_draw_row(GTK_PREVIEW(preview), rgb, x, y, w);
break;
case 3:
gtk_preview_draw_row(GTK_PREVIEW(preview), row, x, y, w);
break;
case 4:
for (i = 0, rgb_ptr = rgb; i < w; i++, row += 4, rgb_ptr += 3)
rgb_ptr[0] = row[0],
rgb_ptr[1] = row[1],
rgb_ptr[2] = row[2];
gtk_preview_draw_row(GTK_PREVIEW(preview), rgb, x, y, w);
break;
}
g_free(rgb);
}
static void
destripe_rect (int sel_x1, int sel_y1, int sel_x2, int sel_y2, int do_preview)
{
GPixelRgn src_rgn; /* source image region */
GPixelRgn dst_rgn; /* destination image region */
guchar *src_rows; /* image data */
double progress, progress_inc;
int sel_width = sel_x2 - sel_x1;
int sel_height = sel_y2 - sel_y1;
long *hist, *corr; /* "histogram" data */
int tile_width = gimp_tile_width ();
int i, x, y, ox, cols;
/*
* Let the user know what we're doing...
*/
if (!do_preview)
{
gimp_progress_init ("Destriping...");
progress = 0;
progress_inc = 0.5 * tile_width / sel_width;
}
/*
* Setup for filter...
*/
gimp_pixel_rgn_init(&src_rgn, drawable, sel_x1, sel_y1, sel_width, sel_height, FALSE, FALSE);
gimp_pixel_rgn_init(&dst_rgn, drawable, sel_x1, sel_y1, sel_width, sel_height, TRUE, TRUE);
hist = g_new (long, sel_width * img_bpp);
corr = g_new (long, sel_width * img_bpp);
src_rows = g_malloc (tile_width * sel_height * img_bpp * sizeof (guchar));
memset (hist, 0, sel_width * img_bpp * sizeof (long));
/*
* collect "histogram" data.
*/
for (ox = sel_x1; ox < sel_x2; ox += tile_width)
{
guchar *rows = src_rows;
cols = sel_x2 - ox;
if (cols > tile_width)
cols = tile_width;
gimp_pixel_rgn_get_rect (&src_rgn, rows, ox, sel_y1, cols, sel_height);
for (y = 0; y < sel_height; y++)
{
long *h = hist + (ox - sel_x1) * img_bpp;
guchar *row_end = rows + cols * img_bpp;
while (rows < row_end)
*h++ += *rows++;
}
if (!do_preview)
gimp_progress_update (progress += progress_inc);
}
/*
* average out histogram
*/
if (1)
{
int extend = (avg_width >> 1) * img_bpp;
for (i = 0; i < MIN (3, img_bpp); i++)
{
long *h = hist - extend + i;
long *c = corr - extend + i;
long sum = 0;
int cnt = 0;
for (x = -extend; x < sel_width * img_bpp; x += img_bpp)
{
if (x + extend < sel_width * img_bpp) { sum += h[ extend]; cnt++; };
if (x - extend >= 0) { sum -= h[-extend]; cnt--; };
if (x >= 0) { *c = ((sum/cnt - *h) << 10) / *h; };
h += img_bpp;
c += img_bpp;
}
}
}
else
{
for (i = 0; i < MIN (3, img_bpp); i++)
{
long *h = hist + i + sel_width * img_bpp - img_bpp;
long *c = corr + i + sel_width * img_bpp - img_bpp;
long i = *h;
*c = 0;
do
{
h -= img_bpp;
c -= img_bpp;
if (*h - i > avg_width && i - *h > avg_width)
i = *h;
*c = (i-128) << 10 / *h;
}
while (h > hist);
}
}
/*
* remove stripes.
*/
for (ox = sel_x1; ox < sel_x2; ox += tile_width)
{
guchar *rows = src_rows;
cols = sel_x2 - ox;
if (cols > tile_width)
cols = tile_width;
gimp_pixel_rgn_get_rect (&src_rgn, rows, ox, sel_y1, cols, sel_height);
if (!do_preview)
gimp_progress_update (progress += progress_inc);
for (y = 0; y < sel_height; y++)
{
long *c = corr + (ox - sel_x1) * img_bpp;
guchar *row_end = rows + cols * img_bpp;
if (histogram)
while (rows < row_end)
{
*rows = MIN (255, MAX (0, 128 + (*rows * *c >> 10)));
c++; rows++;
}
else
while (rows < row_end)
{
*rows = MIN (255, MAX (0, *rows + (*rows * *c >> 10) ));
c++; rows++;
}
if (do_preview)
preview_draw_row (ox - sel_x1, y, cols, rows - cols * img_bpp);
}
if (!do_preview)
{
gimp_pixel_rgn_set_rect (&dst_rgn, src_rows, ox, sel_y1, cols, sel_height);
gimp_progress_update (progress += progress_inc);
}
}
g_free(src_rows);
/*
* Update the screen...
*/
if (do_preview)
{
gtk_widget_draw (preview, NULL);
gdk_flush ();
}
else
{
gimp_drawable_flush (drawable);
gimp_drawable_merge_shadow (drawable->id, TRUE);
gimp_drawable_update (drawable->id, sel_x1, sel_y1, sel_width, sel_height);
}
g_free (hist);
g_free (corr);
}
/*
* 'destripe()' - Destripe an image.
*
*/
static void
destripe (void)
{
destripe_rect (sel_x1, sel_y1, sel_x2, sel_y2, 0);
}
static void
dialog_histogram_callback(GtkWidget *widget, /* I - Toggle button */
gpointer data) /* I - Data */
{
histogram = !histogram;
preview_update ();
}
/*
* 'destripe_dialog()' - Popup a dialog window for the filter box size...
*/
static gint
destripe_dialog(void)
{
GtkWidget *dialog, /* Dialog window */
*table, /* Table "container" for controls */
*ptable, /* Preview table */
*ftable, /* Filter table */
*frame, /* Frame for preview */
*scrollbar, /* Horizontal + vertical scroller */
*button;
gint argc; /* Fake argc for GUI */
gchar **argv; /* Fake argv for GUI */
guchar *color_cube; /* Preview color cube... */
/*
* Initialize the program's display...
*/
argc = 1;
argv = g_new(gchar *, 1);
argv[0] = g_strdup("destripe");
gtk_init(&argc, &argv);
gtk_rc_parse(gimp_gtkrc());
gdk_set_use_xshm(gimp_use_xshm());
signal(SIGBUS, SIG_DFL);
signal(SIGSEGV, SIG_DFL);
gtk_preview_set_gamma(gimp_gamma());
gtk_preview_set_install_cmap(gimp_install_cmap());
color_cube = gimp_color_cube();
gtk_preview_set_color_cube(color_cube[0], color_cube[1], color_cube[2], color_cube[3]);
gtk_widget_set_default_visual(gtk_preview_get_visual());
gtk_widget_set_default_colormap(gtk_preview_get_cmap());
/*
* Dialog window...
*/
dialog = gtk_dialog_new();
gtk_window_set_title(GTK_WINDOW(dialog), "Destripe");
gtk_window_position(GTK_WINDOW(dialog), GTK_WIN_POS_MOUSE);
gtk_container_border_width(GTK_CONTAINER(dialog), 0);
gtk_signal_connect(GTK_OBJECT(dialog), "destroy",
(GtkSignalFunc) dialog_close_callback,
NULL);
/*
* Top-level table for dialog...
*/
table = gtk_table_new(3, 3, FALSE);
gtk_container_border_width(GTK_CONTAINER(table), 6);
gtk_table_set_row_spacings(GTK_TABLE(table), 4);
gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), table, FALSE, FALSE, 0);
gtk_widget_show(table);
/*
* Preview window...
*/
ptable = gtk_table_new(2, 2, FALSE);
gtk_container_border_width(GTK_CONTAINER(ptable), 0);
gtk_table_attach(GTK_TABLE(table), ptable, 0, 2, 0, 1, 0, 0, 0, 0);
gtk_widget_show(ptable);
frame = gtk_frame_new(NULL);
gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_IN);
gtk_table_attach(GTK_TABLE(ptable), frame, 0, 1, 0, 1, 0, 0, 0, 0);
gtk_widget_show(frame);
preview_width = MIN(sel_x2 - sel_x1, PREVIEW_SIZE);
preview_height = MIN(sel_y2 - sel_y1, PREVIEW_SIZE);
preview = gtk_preview_new(GTK_PREVIEW_COLOR);
gtk_preview_size(GTK_PREVIEW(preview), preview_width, preview_height);
gtk_container_add(GTK_CONTAINER(frame), preview);
gtk_widget_show(preview);
hscroll_data = gtk_adjustment_new(0, 0, sel_x2 - sel_x1 - 1, 1.0,
MIN(preview_width, sel_x2 - sel_x1),
MIN(preview_width, sel_x2 - sel_x1));
gtk_signal_connect(hscroll_data, "value_changed",
(GtkSignalFunc)preview_scroll_callback, NULL);
scrollbar = gtk_hscrollbar_new(GTK_ADJUSTMENT(hscroll_data));
gtk_range_set_update_policy(GTK_RANGE(scrollbar), GTK_UPDATE_CONTINUOUS);
gtk_table_attach(GTK_TABLE(ptable), scrollbar, 0, 1, 1, 2, GTK_FILL, 0, 0, 0);
gtk_widget_show(scrollbar);
vscroll_data = gtk_adjustment_new(0, 0, sel_y2 - sel_y1 - 1, 1.0,
MIN(preview_height, sel_y2 - sel_y1),
MIN(preview_height, sel_y2 - sel_y1));
gtk_signal_connect(vscroll_data, "value_changed",
(GtkSignalFunc)preview_scroll_callback, NULL);
scrollbar = gtk_vscrollbar_new(GTK_ADJUSTMENT(vscroll_data));
gtk_range_set_update_policy(GTK_RANGE(scrollbar), GTK_UPDATE_CONTINUOUS);
gtk_table_attach(GTK_TABLE(ptable), scrollbar, 1, 2, 0, 1, 0, GTK_FILL, 0, 0);
gtk_widget_show(scrollbar);
preview_init();
/*
* Filter type controls...
*/
ftable = gtk_table_new(4, 1, FALSE);
gtk_container_border_width(GTK_CONTAINER(ftable), 4);
gtk_table_attach(GTK_TABLE(table), ftable, 2, 3, 0, 1, 0, 0, 0, 0);
gtk_widget_show(ftable);
button = gtk_check_button_new_with_label("Histogram");
gtk_table_attach(GTK_TABLE(ftable), button, 0, 1, 0, 1,
GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(button),
histogram ? TRUE : FALSE);
gtk_signal_connect(GTK_OBJECT(button), "toggled",
(GtkSignalFunc)dialog_histogram_callback,
NULL);
gtk_widget_show(button);
/* button = gtk_check_button_new_with_label("Recursive");
gtk_table_attach(GTK_TABLE(ftable), button, 0, 1, 1, 2,
GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(button),
(filter_type & FILTER_RECURSIVE) ? TRUE : FALSE);
gtk_signal_connect(GTK_OBJECT(button), "toggled",
(GtkSignalFunc)dialog_recursive_callback,
NULL);
gtk_widget_show(button);*/
/*
* Box size (radius) control...
*/
dialog_create_ivalue("Width", GTK_TABLE(table), 2, &avg_width, 2, MAX_AVG);
/*
* OK, cancel buttons...
*/
gtk_container_border_width(GTK_CONTAINER(GTK_DIALOG(dialog)->action_area), 6);
button = gtk_button_new_with_label("OK");
GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT);
gtk_signal_connect(GTK_OBJECT(button), "clicked",
(GtkSignalFunc) dialog_ok_callback,
dialog);
gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->action_area), button, TRUE, TRUE, 0);
gtk_widget_grab_default(button);
gtk_widget_show(button);
button = gtk_button_new_with_label("Cancel");
GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT);
gtk_signal_connect(GTK_OBJECT(button), "clicked",
(GtkSignalFunc) dialog_cancel_callback,
dialog);
gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->action_area), button, TRUE, TRUE, 0);
gtk_widget_show(button);
/*
* Show it and wait for the user to do something...
*/
gtk_widget_show(dialog);
preview_update();
gtk_main();
gdk_flush();
/*
* Free the preview data...
*/
preview_exit();
/*
* Return ok/cancel...
*/
return (run_filter);
}
/*
* 'preview_init()' - Initialize the preview window...
*/
static void
preview_init(void)
{
int width; /* Byte width of the image */
/*
* Setup for preview filter...
*/
width = preview_width * img_bpp;
preview_x1 = sel_x1;
preview_y1 = sel_y1;
preview_x2 = preview_x1 + MIN(preview_width, sel_x2 - sel_x1);
preview_y2 = preview_y1 + MIN(preview_height, sel_y2 -sel_y1);
}
/*
* 'preview_scroll_callback()' - Update the preview when a scrollbar is moved.
*/
static void
preview_scroll_callback(void)
{
preview_x1 = sel_x1 + GTK_ADJUSTMENT(hscroll_data)->value;
preview_y1 = sel_y1 + GTK_ADJUSTMENT(vscroll_data)->value;
preview_x2 = preview_x1 + MIN(preview_width, sel_x2 - sel_x1);
preview_y2 = preview_y1 + MIN(preview_height, sel_y2 - sel_y1);
preview_update();
}
/*
* 'preview_update()' - Update the preview window.
*/
static void
preview_update(void)
{
destripe_rect (preview_x1, preview_y1, preview_x2, preview_y2, 1);
}
/*
* 'preview_exit()' - Free all memory used by the preview window...
*/
static void
preview_exit(void)
{
}
/*
* 'dialog_create_ivalue()' - Create an integer value control...
*/
static void
dialog_create_ivalue(char *title, /* I - Label for control */
GtkTable *table, /* I - Table container to use */
int row, /* I - Row # for container */
gint *value, /* I - Value holder */
int left, /* I - Minimum value for slider */
int right) /* I - Maximum value for slider */
{
GtkWidget *label, /* Control label */
*scale, /* Scale widget */
*entry; /* Text widget */
GtkObject *scale_data; /* Scale data */
char buf[256]; /* String buffer */
/*
* Label...
*/
label = gtk_label_new(title);
gtk_misc_set_alignment(GTK_MISC(label), 0.0, 1.0);
gtk_table_attach(table, label, 0, 1, row, row + 1, GTK_FILL, GTK_FILL, 4, 0);
gtk_widget_show(label);
/*
* Scale...
*/
scale_data = gtk_adjustment_new(*value, left, right, 1.0, 1.0, 1.0);
gtk_signal_connect(GTK_OBJECT(scale_data), "value_changed",
(GtkSignalFunc) dialog_iscale_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_range_set_update_policy(GTK_RANGE(scale), GTK_UPDATE_CONTINUOUS);
gtk_widget_show(scale);
/*
* Text entry...
*/
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, "%d", *value);
gtk_entry_set_text(GTK_ENTRY(entry), buf);
gtk_signal_connect(GTK_OBJECT(entry), "changed",
(GtkSignalFunc) dialog_ientry_update,
value);
gtk_table_attach(GTK_TABLE(table), entry, 2, 3, row, row + 1, GTK_FILL, GTK_FILL, 4, 0);
gtk_widget_show(entry);
}
/*
* 'dialog_iscale_update()' - Update the value field using the scale.
*/
static void
dialog_iscale_update(GtkAdjustment *adjustment, /* I - New value */
gint *value) /* I - Current value */
{
GtkWidget *entry; /* Text entry widget */
char buf[256]; /* Text buffer */
if (*value != adjustment->value)
{
*value = adjustment->value;
entry = gtk_object_get_user_data(GTK_OBJECT(adjustment));
sprintf(buf, "%d", *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);
preview_update();
};
}
/*
* 'dialog_ientry_update()' - Update the value field using the text entry.
*/
static void
dialog_ientry_update(GtkWidget *widget, /* I - Entry widget */
gint *value) /* I - Current value */
{
GtkAdjustment *adjustment;
gint new_value;
new_value = atoi(gtk_entry_get_text(GTK_ENTRY(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");
preview_update();
};
};
}
/*
* 'dialog_ok_callback()' - Start the filter...
*/
static void
dialog_ok_callback(GtkWidget *widget, /* I - OK button widget */
gpointer data) /* I - Dialog window */
{
run_filter = TRUE;
gtk_widget_destroy(GTK_WIDGET(data));
}
/*
* 'dialog_cancel_callback()' - Cancel the filter...
*/
static void
dialog_cancel_callback(GtkWidget *widget, /* I - Cancel button widget */
gpointer data) /* I - Dialog window */
{
gtk_widget_destroy(GTK_WIDGET(data));
}
/*
* 'dialog_close_callback()' - Exit the filter dialog application.
*/
static void
dialog_close_callback(GtkWidget *widget, /* I - Dialog window */
gpointer data) /* I - Dialog window */
{
gtk_main_quit();
}

View File

@ -1,219 +0,0 @@
#include <gtk/gtk.h>
#include <libgimp/gimp.h>
#include <libgimp/gimpmenu.h>
#include "magiceye.h"
int returnvalue = 0;
gint magiceye_ID;
gint magic_dialog(void)
{
GtkWidget *dialog, *button, *label, *menue, *omenue, *frame, *table, *scale, *toggle;
GtkDialog *weg;
gchar **argv;
gint argc;
GtkObject *scale_data;
argc = 1;
argv = g_new(gchar *,1);
argv[0] = g_strdup("magiceye");
gtk_init(&argc,&argv);
/* Dialog */
dialog = gtk_dialog_new();
gtk_window_set_title(GTK_WINDOW(dialog), "Magic Eye");
gtk_window_position(GTK_WINDOW(dialog), GTK_WIN_POS_MOUSE);
gtk_signal_connect(GTK_OBJECT(dialog), "destroy", (GtkSignalFunc) close_callback, NULL);
/* OK-Button */
button = gtk_button_new_with_label ("OK");
GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
gtk_signal_connect (GTK_OBJECT (button), "clicked",
(GtkSignalFunc) ok_callback,
dialog);
gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->action_area), button, TRUE, TRUE, 0);
gtk_widget_show (button);
/* Create-Button */
button = gtk_button_new_with_label("Create");
GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
gtk_signal_connect(GTK_OBJECT(button), "clicked",
(GtkSignalFunc) magiceye_update,
NULL);
gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->action_area), button, TRUE, TRUE, 0);
gtk_widget_grab_default (button);
gtk_widget_show(button);
/* Cancel-Button */
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 (dialog));
gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->action_area), button, TRUE, TRUE, 0);
gtk_widget_show (button);
/* Rahmen */
frame = gtk_frame_new("Magic Eye Options");
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(dialog)->vbox), frame, TRUE, TRUE, 0);
/* Tabelle */
table = gtk_table_new(6, 4, FALSE);
gtk_container_border_width(GTK_CONTAINER(table), 5);
gtk_container_add(GTK_CONTAINER(frame), table);
gtk_table_set_row_spacings (GTK_TABLE (table),5);
gtk_table_set_col_spacings (GTK_TABLE (table),5);
/* Label */
label = gtk_label_new("Background: ");
gtk_table_attach(GTK_TABLE(table), label, 0, 1, 1, 2, GTK_FILL, GTK_FILL, 0, 0);
gtk_widget_show(label);
/* Menue */
omenue = gtk_option_menu_new();
menue = GTK_WIDGET(gimp_drawable_menu_new(magiceye_constrain,drawable_callback,&magiceye_ID,magiceye_ID));
gtk_option_menu_set_menu(GTK_OPTION_MENU(omenue), menue);
gtk_table_attach(GTK_TABLE(table), omenue, 1, 4, 1, 2, GTK_FILL, GTK_FILL, 0, 0);
/* Label */
label = gtk_label_new("Strip-Width: ");
gtk_table_attach(GTK_TABLE(table), label, 0, 1, 2, 3, GTK_FILL, GTK_FILL, 0, 0);
gtk_widget_show(label);
/* Breiten-Regler */
strip_width = STDWIDTH;
scale_data = gtk_adjustment_new (strip_width, 0.0, 300.0, 1.0, 10.0, 0.0);
scale = gtk_hscale_new (GTK_ADJUSTMENT (scale_data));
gtk_scale_set_value_pos (GTK_SCALE (scale), GTK_POS_TOP);
gtk_scale_set_digits (GTK_SCALE (scale), 0);
gtk_range_set_update_policy (GTK_RANGE (scale), GTK_UPDATE_DELAYED);
gtk_signal_connect (GTK_OBJECT (scale_data), "value_changed",
(GtkSignalFunc) scale_update,
&strip_width);
gtk_table_attach(GTK_TABLE(table), scale, 0, 4, 3, 4, GTK_FILL, GTK_FILL, 0, 0);
gtk_widget_show(scale);
/* Label */
label = gtk_label_new("Depth: ");
gtk_table_attach(GTK_TABLE(table), label, 0, 1, 4, 5, GTK_FILL, GTK_FILL, 0, 0);
gtk_widget_show(label);
/* Tiefen-Regler */
depth = STDDEPTH;
scale_data = gtk_adjustment_new (depth, 0.0, 100.0, 1.0, 10.0, 0.0);
scale = gtk_hscale_new (GTK_ADJUSTMENT (scale_data));
gtk_scale_set_value_pos (GTK_SCALE (scale), GTK_POS_TOP);
gtk_scale_set_digits (GTK_SCALE (scale), 0);
gtk_range_set_update_policy (GTK_RANGE (scale), GTK_UPDATE_DELAYED);
gtk_signal_connect (GTK_OBJECT (scale_data), "value_changed",
(GtkSignalFunc) scale_update,
&depth);
gtk_table_attach(GTK_TABLE(table), scale, 1, 4, 4, 5, GTK_FILL, GTK_FILL, 0, 0);
gtk_widget_show(scale);
/* Links oder Mitte? */
from_left = STDFROMLEFT;
toggle = gtk_check_button_new_with_label ("From left");
gtk_signal_connect (GTK_OBJECT (toggle), "toggled",
(GtkSignalFunc) toggle_update,
&from_left);
gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (toggle), from_left);
gtk_table_attach(GTK_TABLE(table), toggle, 0, 2, 5, 6, GTK_FILL, GTK_FILL, 0, 0);
gtk_widget_show (toggle);
/* Hoch oder runter? */
up_down = STDUPDOWN;
toggle = gtk_check_button_new_with_label ("Down");
gtk_signal_connect (GTK_OBJECT (toggle), "toggled",
(GtkSignalFunc) toggle_update,
&up_down);
gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (toggle), up_down);
gtk_table_attach(GTK_TABLE(table), toggle, 2, 4, 5, 6, GTK_FILL, GTK_FILL, 0, 0);
gtk_widget_show (toggle);
/* Darstellung */
gtk_container_add(GTK_CONTAINER(frame), table);
gtk_widget_show(omenue);
gtk_widget_show(table);
gtk_widget_show(frame);
gtk_widget_show(dialog);
gtk_main();
return returnvalue;
}
void
scale_update (GtkAdjustment *adjustment,
double *scale_val)
{
*scale_val = adjustment->value;
}
void
toggle_update(GtkWidget *widget,
gpointer data)
{
int *toggle_val;
toggle_val = (int *) data;
if (GTK_TOGGLE_BUTTON (widget)->active)
*toggle_val = TRUE;
else
*toggle_val = FALSE;
}
void close_callback(GtkWidget *widget, gpointer data)
{
gtk_main_quit();
}
void ok_callback(GtkWidget *widget, gpointer data)
{
returnvalue = 1;
gtk_widget_destroy(GTK_WIDGET(data));
}
gint magiceye_constrain(gint32 image, gint32 drawable_ID, gpointer data)
{
gint moeglich;
moeglich = (gimp_drawable_color(drawable_ID) || gimp_drawable_indexed(drawable_ID) ||gimp_drawable_gray(drawable_ID));
#ifdef DEBUG
printf("%i %i\n",moeglich,drawable_ID);
#endif
if (drawable_ID == -1) return TRUE;
return moeglich;
}
void drawable_callback(gint32 id, gpointer data)
{
/* (gint32 *) data = id; */
magiceye_ID = id;
}
void magiceye_update(GtkWidget *widget, gpointer data)
{
gint32 image_ID, new_layer;
image_ID = magiceye (map_drawable, &new_layer);
if (image_ID>0) gimp_display_new (image_ID);
}

View File

@ -1,830 +0,0 @@
/* The GIMP -- an image manipulation program
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* Diffraction plug-in --- Generate diffraction patterns
* Copyright (C) 1997 Federico Mena Quintero and David Bleecker
* federico@nuclecu.unam.mx
* bleecker@math.hawaii.edu
*
* 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
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <math.h>
#include <signal.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include "gtk/gtk.h"
#include "libgimp/gimp.h"
/***** Magic numbers *****/
#define ITERATIONS 100 /* 100 */
#define WEIRD_FACTOR 0.04 /* 0.04 */
#define PREVIEW_WIDTH 64
#define PREVIEW_HEIGHT 64
#define PROGRESS_WIDTH 32
#define PROGRESS_HEIGHT 16
#define SCALE_WIDTH 150
/***** Types *****/
typedef struct {
gdouble lam_r;
gdouble lam_g;
gdouble lam_b;
gdouble contour_r;
gdouble contour_g;
gdouble contour_b;
gdouble edges_r;
gdouble edges_g;
gdouble edges_b;
gdouble brightness;
gdouble scattering;
gdouble polarization;
} diffraction_vals_t;
typedef struct {
GtkWidget *preview;
GtkWidget *progress;
guchar preview_row[PREVIEW_WIDTH * 3];
gint run;
} diffraction_interface_t;
/***** Prototypes *****/
static void query(void);
static void run(char *name,
int nparams,
GParam *param,
int *nreturn_vals,
GParam **return_vals);
static void diffraction(GDrawable *drawable);
static void diff_init_luts(void);
static void diff_diffract(double x, double y, double *r, double *g, double *b);
static double diff_point(double x, double y, double edges, double contours, double lam);
static double diff_intensity(double x, double y, double lam);
static gint diffraction_dialog(void);
static void dialog_update_preview(void);
static void dialog_create_value(char *title, GtkTable *table, int row, gdouble *value, double left, double right);
static void dialog_update_callback(GtkWidget *widget, gpointer data);
static void dialog_scale_update(GtkAdjustment *adjustment, gdouble *value);
static void dialog_close_callback(GtkWidget *widget, gpointer data);
static void dialog_ok_callback(GtkWidget *widget, gpointer data);
static void dialog_cancel_callback(GtkWidget *widget, gpointer data);
/***** Variables *****/
GPlugInInfo PLUG_IN_INFO = {
NULL, /* init_proc */
NULL, /* quit_proc */
query, /* query_proc */
run /* run_proc */
}; /* PLUG_IN_INFO */
static diffraction_vals_t dvals = {
0.815, /* lam_r */
1.221, /* lam_g */
1.123, /* lam_b */
0.821, /* contour_r */
0.821, /* contour_g */
0.974, /* contour_b */
0.610, /* edges_r */
0.677, /* edges_g */
0.636, /* edges_b */
0.066, /* brightness */
37.126, /* scattering */
-0.473 /* polarization */
}; /* dvals */
static diffraction_interface_t dint = {
NULL, /* preview */
NULL, /* progress */
{ 0 }, /* preview_row */
FALSE /* run */
}; /* dint */
static double cos_lut[ITERATIONS + 1];
static double param_lut1[ITERATIONS + 1];
static double param_lut2[ITERATIONS + 1];
/***** Functions *****/
/*****/
MAIN()
/*****/
static void
query(void)
{
static GParamDef args[] = {
{ PARAM_INT32, "run_mode", "Interactive, non-interactive" },
{ PARAM_IMAGE, "image", "Input image" },
{ PARAM_DRAWABLE, "drawable", "Input drawable" },
{ PARAM_FLOAT, "lam_r", "Light frequency (red)" },
{ PARAM_FLOAT, "lam_g", "Light frequency (green)" },
{ PARAM_FLOAT, "lam_b", "Light frequency (blue)" },
{ PARAM_FLOAT, "contour_r", "Number of contours (red)" },
{ PARAM_FLOAT, "contour_g", "Number of contours (green)" },
{ PARAM_FLOAT, "contour_b", "Number of contours (blue)" },
{ PARAM_FLOAT, "edges_r", "Number of sharp edges (red)" },
{ PARAM_FLOAT, "edges_g", "Number of sharp edges (green)" },
{ PARAM_FLOAT, "edges_b", "Number of sharp edges (blue)" },
{ PARAM_FLOAT, "brightness", "Brightness and shifting/fattening of contours" },
{ PARAM_FLOAT, "scattering", "Scattering (Speed vs. quality)" },
{ PARAM_FLOAT, "polarization", "Polarization" }
}; /* args */
static GParamDef *return_vals = NULL;
static int nargs = sizeof(args) / sizeof(args[0]);
static int nreturn_vals = 0;
gimp_install_procedure("plug_in_diffraction",
"Generate diffraction patterns",
"Help? What help? Real men do not need help :-)", /* FIXME */
"Federico Mena Quintero",
"Federico Mena Quintero & David Bleecker",
"April 1997, 0.5",
"<Image>/Filters/Textures/Diffraction patterns",
/* "<Image>/Diffraction patterns", */
"RGB*",
PROC_PLUG_IN,
nargs,
nreturn_vals,
args,
return_vals);
} /* query */
/*****/
static void
run(char *name,
int nparams,
GParam *param,
int *nreturn_vals,
GParam **return_vals)
{
static GParam values[1];
GDrawable *active_drawable;
GRunModeType run_mode;
GStatusType status;
/* Initialize */
diff_init_luts();
status = STATUS_SUCCESS;
run_mode = param[0].data.d_int32;
values[0].type = PARAM_STATUS;
values[0].data.d_status = status;
*nreturn_vals = 1;
*return_vals = values;
switch (run_mode) {
case RUN_INTERACTIVE:
/* Possibly retrieve data */
gimp_get_data("plug_in_diffraction", &dvals);
/* Get information from the dialog */
if (!diffraction_dialog())
return;
break;
case RUN_NONINTERACTIVE:
/* Make sure all the arguments are present */
if (nparams != 15)
status = STATUS_CALLING_ERROR;
if (status == STATUS_SUCCESS) {
dvals.lam_r = param[3].data.d_float;
dvals.lam_g = param[4].data.d_float;
dvals.lam_b = param[5].data.d_float;
dvals.contour_r = param[6].data.d_float;
dvals.contour_g = param[7].data.d_float;
dvals.contour_b = param[8].data.d_float;
dvals.edges_r = param[9].data.d_float;
dvals.edges_g = param[10].data.d_float;
dvals.edges_b = param[11].data.d_float;
dvals.brightness = param[12].data.d_float;
dvals.scattering = param[13].data.d_float;
dvals.polarization = param[14].data.d_float;
} /* if */
break;
case RUN_WITH_LAST_VALS:
/* Possibly retrieve data */
gimp_get_data("plug_in_diffraction", &dvals);
break;
default:
break;
} /* switch */
/* Get the active drawable */
active_drawable = gimp_drawable_get(param[2].data.d_drawable);
/* Create the diffraction pattern */
if ((status == STATUS_SUCCESS) && gimp_drawable_color(active_drawable->id)) {
/* Set the tile cache size */
gimp_tile_cache_ntiles((active_drawable->width + gimp_tile_width() - 1) / gimp_tile_width());
/* Run! */
diffraction(active_drawable);
/* If run mode is interactive, flush displays */
if (run_mode != RUN_NONINTERACTIVE)
gimp_displays_flush();
/* Store data */
if (run_mode == RUN_INTERACTIVE)
gimp_set_data("plug_in_diffraction", &dvals, sizeof(diffraction_vals_t));
} else if (status == STATUS_SUCCESS)
status = STATUS_EXECUTION_ERROR;
values[0].data.d_status = status;
gimp_drawable_detach(active_drawable);
} /* run */
/*****/
static void
diffraction(GDrawable *drawable)
{
GPixelRgn dest_rgn;
gpointer pr;
gint x1, y1, x2, y2;
gint width, height;
gint has_alpha;
gint row, col;
guchar *dest_row;
guchar *dest;
gint progress, max_progress;
double left, right, bottom, top;
double dhoriz, dvert;
double px, py;
double r, g, b;
/* Get the mask bounds and image size */
gimp_drawable_mask_bounds(drawable->id, &x1, &y1, &x2, &y2);
width = x2 - x1;
height = y2 - y1;
has_alpha = gimp_drawable_has_alpha(drawable->id);
/* Initialize pixel regions */
gimp_pixel_rgn_init(&dest_rgn, drawable, x1, y1, width, height, TRUE, TRUE);
progress = 0;
max_progress = width * height;
gimp_progress_init("Creating diffraction pattern...");
/* Create diffraction pattern */
left = -5.0;
right = 5.0;
bottom = -5.0;
top = 5.0;
dhoriz = (right - left) / (width - 1);
dvert = (bottom - top) / (height - 1);
for (pr = gimp_pixel_rgns_register(1, &dest_rgn);
pr != NULL; pr = gimp_pixel_rgns_process(pr)) {
dest_row = dest_rgn.data;
py = top + dvert * (dest_rgn.y - y1);
for (row = 0; row < dest_rgn.h; row++) {
dest = dest_row;
px = left + dhoriz * (dest_rgn.x - x1);
for (col = 0; col < dest_rgn.w; col++) {
diff_diffract(px, py, &r, &g, &b);
*dest++ = 255.0 * r;
*dest++ = 255.0 * g;
*dest++ = 255.0 * b;
if (has_alpha)
*dest++ = 255;
px += dhoriz;
} /* for */
/* Update progress */
progress += dest_rgn.w;
gimp_progress_update((double) progress / max_progress);
py += dvert;
dest_row += dest_rgn.rowstride;
} /* for */
} /* for */
gimp_drawable_flush(drawable);
gimp_drawable_merge_shadow(drawable->id, TRUE);
gimp_drawable_update(drawable->id, x1, y1, width, height);
} /* diffraction */
static void
diff_init_luts(void)
{
int i;
double a;
double sina;
a = -M_PI;
for (i = 0; i <= ITERATIONS; i++) {
sina = sin(a);
cos_lut[i] = cos(a);
param_lut1[i] = 0.75 * sina;
param_lut2[i] = 0.5 * (4.0 * cos_lut[i] * cos_lut[i] + sina * sina);
a += (2.0 * M_PI / ITERATIONS);
} /* for */
} /* diff_init_luts */
/*****/
static void
diff_diffract(double x, double y, double *r, double *g, double *b)
{
*r = diff_point(x, y, dvals.edges_r, dvals.contour_r, dvals.lam_r);
*g = diff_point(x, y, dvals.edges_g, dvals.contour_g, dvals.lam_g);
*b = diff_point(x, y, dvals.edges_b, dvals.contour_b, dvals.lam_b);
} /* diff_diffract */
/*****/
static double
diff_point(double x, double y, double edges, double contours, double lam)
{
return fabs(edges * sin(contours * atan(dvals.brightness * diff_intensity(x, y, lam))));
} /* diff_point */
/*****/
static double
diff_intensity(double x, double y, double lam)
{
int i;
double cxy, sxy;
double param;
double polpi2;
double cospolpi2, sinpolpi2;
cxy = 0.0;
sxy = 0.0;
lam *= 4.0;
for (i = 0; i <= ITERATIONS; i++) {
param = lam *
(cos_lut[i] * x +
param_lut1[i] * y -
param_lut2[i]);
cxy += cos(param);
sxy += sin(param);
} /* for */
cxy *= WEIRD_FACTOR;
sxy *= WEIRD_FACTOR;
polpi2 = dvals.polarization * (M_PI / 2.0);
cospolpi2 = cos(polpi2);
sinpolpi2 = sin(polpi2);
return dvals.scattering * ((cospolpi2 + sinpolpi2) * cxy * cxy +
(cospolpi2 - sinpolpi2) * sxy * sxy);
} /* diff_intensity */
#if 0
/*****/
static double
diff_intensity(double x, double y, double lam)
{
int i;
double cxy, sxy;
double s;
double cosa, sina;
double twocosa, param;
double polpi2;
double cospolpi2, sinpolpi2;
s = dvals.scattering;
cxy = 0.0;
sxy = 0.0;
for (i = 0; i <= ITERATIONS; i++) {
cosa = cos_lut[i];
sina = sin_lut[i];
twocosa = 2.0 * cosa;
param = 4.0 * lam *
(cosa * x +
0.75 * sina * y -
0.5 * (twocosa * twocosa + sina * sina));
cxy += 0.04 * cos(param);
sxy += 0.04 * sin(param);
} /* for */
polpi2 = dvals.polarization * (M_PI / 2.0);
cospolpi2 = cos(polpi2);
sinpolpi2 = sin(polpi2);
return s * ((cospolpi2 + sinpolpi2) * cxy * cxy +
(cospolpi2 - sinpolpi2) * sxy * sxy);
} /* diff_intensity */
#endif
/*****/
static gint
diffraction_dialog(void)
{
GtkWidget *dialog;
GtkWidget *top_table;
GtkWidget *notebook;
GtkWidget *frame;
GtkWidget *vbox;
GtkWidget *table;
GtkWidget *label;
GtkWidget *button;
gint argc;
gchar **argv;
guchar *color_cube;
#if 0
printf("Waiting... (pid %d)\n", getpid());
kill(getpid(), SIGSTOP);
#endif
argc = 1;
argv = g_new(gchar *, 1);
argv[0] = g_strdup("diffraction");
gtk_init(&argc, &argv);
gtk_rc_parse (gimp_gtkrc ());
gdk_set_use_xshm (gimp_use_xshm ());
gtk_preview_set_gamma(gimp_gamma());
gtk_preview_set_install_cmap(gimp_install_cmap());
color_cube = gimp_color_cube();
gtk_preview_set_color_cube(color_cube[0], color_cube[1], color_cube[2], color_cube[3]);
gtk_widget_set_default_visual(gtk_preview_get_visual());
gtk_widget_set_default_colormap(gtk_preview_get_cmap());
dialog = gtk_dialog_new();
gtk_window_set_title(GTK_WINDOW(dialog), "Diffraction patterns");
gtk_window_position(GTK_WINDOW(dialog), GTK_WIN_POS_MOUSE);
gtk_container_border_width(GTK_CONTAINER(dialog), 0);
gtk_signal_connect(GTK_OBJECT(dialog), "destroy",
(GtkSignalFunc) dialog_close_callback,
NULL);
top_table = gtk_table_new(2, 2, FALSE);
gtk_container_border_width(GTK_CONTAINER(top_table), 6);
gtk_table_set_row_spacings(GTK_TABLE(top_table), 4);
gtk_table_set_col_spacings(GTK_TABLE(top_table), 4);
gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), top_table, FALSE, FALSE, 0);
gtk_widget_show(top_table);
/* Preview */
vbox = gtk_vbox_new(FALSE, 0);
gtk_container_border_width(GTK_CONTAINER(vbox), 0);
gtk_table_attach(GTK_TABLE(top_table), vbox, 0, 1, 0, 1,
GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
gtk_widget_show(vbox);
frame = gtk_frame_new(NULL);
gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_IN);
gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 0);
gtk_widget_show(frame);
dint.preview = gtk_preview_new(GTK_PREVIEW_COLOR);
gtk_preview_size(GTK_PREVIEW(dint.preview), PREVIEW_WIDTH, PREVIEW_HEIGHT);
gtk_container_add(GTK_CONTAINER(frame), dint.preview);
gtk_widget_show(dint.preview);
dint.progress = gtk_progress_bar_new();
gtk_widget_set_usize(dint.progress, PROGRESS_WIDTH, PROGRESS_HEIGHT);
gtk_box_pack_start(GTK_BOX(vbox), dint.progress, TRUE, FALSE, 0);
gtk_widget_show(dint.progress);
button = gtk_button_new_with_label("Preview!");
gtk_signal_connect(GTK_OBJECT(button), "clicked",
(GtkSignalFunc) dialog_update_callback,
NULL);
gtk_table_attach(GTK_TABLE(top_table), button, 0, 1, 1, 2,
GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
gtk_widget_show(button);
/* Notebook */
notebook = gtk_notebook_new();
gtk_notebook_set_tab_pos(GTK_NOTEBOOK(notebook), GTK_POS_TOP);
gtk_table_attach(GTK_TABLE(top_table), notebook, 1, 2, 0, 2, GTK_EXPAND | GTK_FILL, 0, 0, 0);
gtk_widget_show(notebook);
/* Frequencies tab */
vbox = gtk_vbox_new(FALSE, 0);
gtk_container_border_width(GTK_CONTAINER(vbox), 4);
table = gtk_table_new(3, 2, FALSE);
gtk_container_border_width(GTK_CONTAINER(table), 0);
gtk_box_pack_start(GTK_BOX(vbox), table, TRUE, TRUE, 0);
gtk_widget_show(table);
dialog_create_value("Red", GTK_TABLE(table), 0, &dvals.lam_r, 0.0, 20.0);
dialog_create_value("Green", GTK_TABLE(table), 1, &dvals.lam_g, 0.0, 20.0);
dialog_create_value("Blue", GTK_TABLE(table), 2, &dvals.lam_b, 0.0, 20.0);
label = gtk_label_new("Frequencies");
gtk_misc_set_alignment(GTK_MISC(label), 0.5, 0.5);
gtk_notebook_append_page(GTK_NOTEBOOK(notebook), vbox, label);
gtk_widget_show(vbox);
/* Contours tab */
vbox = gtk_vbox_new(FALSE, 0);
gtk_container_border_width(GTK_CONTAINER(vbox), 4);
table = gtk_table_new(3, 2, FALSE);
gtk_container_border_width(GTK_CONTAINER(table), 0);
gtk_box_pack_start(GTK_BOX(vbox), table, TRUE, TRUE, 0);
gtk_widget_show(table);
dialog_create_value("Red", GTK_TABLE(table), 0, &dvals.contour_r, 0.0, 10.0);
dialog_create_value("Green", GTK_TABLE(table), 1, &dvals.contour_g, 0.0, 10.0);
dialog_create_value("Blue", GTK_TABLE(table), 2, &dvals.contour_b, 0.0, 10.0);
label = gtk_label_new("Contours");
gtk_misc_set_alignment(GTK_MISC(label), 0.5, 0.5);
gtk_notebook_append_page(GTK_NOTEBOOK(notebook), vbox, label);
gtk_widget_show(vbox);
/* Sharp edges tab */
vbox = gtk_vbox_new(FALSE, 0);
gtk_container_border_width(GTK_CONTAINER(vbox), 4);
table = gtk_table_new(3, 2, FALSE);
gtk_container_border_width(GTK_CONTAINER(table), 0);
gtk_box_pack_start(GTK_BOX(vbox), table, TRUE, TRUE, 0);
gtk_widget_show(table);
dialog_create_value("Red", GTK_TABLE(table), 0, &dvals.edges_r, 0.0, 1.0);
dialog_create_value("Green", GTK_TABLE(table), 1, &dvals.edges_g, 0.0, 1.0);
dialog_create_value("Blue", GTK_TABLE(table), 2, &dvals.edges_b, 0.0, 1.0);
label = gtk_label_new("Sharp edges");
gtk_misc_set_alignment(GTK_MISC(label), 0.5, 0.5);
gtk_notebook_append_page(GTK_NOTEBOOK(notebook), vbox, label);
gtk_widget_show(vbox);
/* Other options tab */
vbox = gtk_vbox_new(FALSE, 0);
gtk_container_border_width(GTK_CONTAINER(vbox), 4);
table = gtk_table_new(3, 2, FALSE);
gtk_container_border_width(GTK_CONTAINER(table), 0);
gtk_box_pack_start(GTK_BOX(vbox), table, TRUE, TRUE, 0);
gtk_widget_show(table);
dialog_create_value("Brightness", GTK_TABLE(table), 0, &dvals.brightness, 0.0, 1.0);
dialog_create_value("Scattering", GTK_TABLE(table), 1, &dvals.scattering, 0.0, 100.0);
dialog_create_value("Polarization", GTK_TABLE(table), 2, &dvals.polarization, -1.0, 1.0);
label = gtk_label_new("Other options");
gtk_misc_set_alignment(GTK_MISC(label), 0.5, 0.5);
gtk_notebook_append_page(GTK_NOTEBOOK(notebook), vbox, label);
gtk_widget_show(vbox);
/* Buttons */
gtk_container_border_width(GTK_CONTAINER(GTK_DIALOG(dialog)->action_area), 6);
button = gtk_button_new_with_label("OK");
GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT);
gtk_signal_connect(GTK_OBJECT(button), "clicked",
(GtkSignalFunc) dialog_ok_callback,
dialog);
gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->action_area), button, TRUE, TRUE, 0);
gtk_widget_grab_default(button);
gtk_widget_show(button);
button = gtk_button_new_with_label("Cancel");
GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT);
gtk_signal_connect(GTK_OBJECT(button), "clicked",
(GtkSignalFunc) dialog_cancel_callback,
dialog);
gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->action_area), button, TRUE, TRUE, 0);
gtk_widget_show(button);
/* Done */
gtk_widget_show(dialog);
dialog_update_preview();
gtk_main();
gdk_flush();
return dint.run;
} /* diffraction_dialog */
/*****/
static void
dialog_update_preview(void)
{
double left, right, bottom, top;
double px, py;
double dx, dy;
double r, g, b;
int x, y;
guchar *p;
left = -5.0;
right = 5.0;
bottom = -5.0;
top = 5.0;
dx = (right - left) / (PREVIEW_WIDTH - 1);
dy = (bottom - top) / (PREVIEW_HEIGHT - 1);
py = top;
for (y = 0; y < PREVIEW_HEIGHT; y++) {
px = left;
p = dint.preview_row;
for (x = 0; x < PREVIEW_WIDTH; x++) {
diff_diffract(px, py, &r, &g, &b);
*p++ = 255.0 * r;
*p++ = 255.0 * g;
*p++ = 255.0 * b;
px += dx;
} /* for */
gtk_preview_draw_row(GTK_PREVIEW(dint.preview), dint.preview_row, 0, y, PREVIEW_WIDTH);
gtk_progress_bar_update(GTK_PROGRESS_BAR(dint.progress), (double) y / (PREVIEW_HEIGHT - 1));
py += dy;
} /* for */
gtk_widget_draw(dint.preview, NULL);
gtk_progress_bar_update(GTK_PROGRESS_BAR(dint.progress), 0.0);
gdk_flush();
} /* dialog_update_preview */
/*****/
static void
dialog_create_value(char *title, GtkTable *table, int row, gdouble *value, double left, double right)
{
GtkWidget *label;
GtkWidget *scale;
GtkObject *scale_data;
label = gtk_label_new(title);
gtk_misc_set_alignment(GTK_MISC(label), 0.0, 1.0);
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,
(right - left) / 50.0,
(right - left) / 100.0,
0.0);
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, 0, 0, 0);
gtk_scale_set_value_pos(GTK_SCALE(scale), GTK_POS_TOP);
gtk_scale_set_digits(GTK_SCALE(scale), 3);
gtk_range_set_update_policy(GTK_RANGE(scale), GTK_UPDATE_CONTINUOUS);
gtk_signal_connect(GTK_OBJECT(scale_data), "value_changed",
(GtkSignalFunc) dialog_scale_update,
value);
gtk_widget_show(scale);
} /* dialog_create_value */
/*****/
static void
dialog_update_callback(GtkWidget *widget, gpointer data)
{
dialog_update_preview();
} /* dialog_update_callback */
/*****/
static void
dialog_scale_update(GtkAdjustment *adjustment, gdouble *value)
{
*value = adjustment->value;
} /* dialog_scale_update */
/*****/
static void
dialog_close_callback(GtkWidget *widget, gpointer data)
{
gtk_main_quit();
} /* dialog_close_callback */
/*****/
static void
dialog_ok_callback(GtkWidget *widget, gpointer data)
{
dint.run = TRUE;
gtk_widget_destroy(GTK_WIDGET(data));
} /* dialog_ok_callback */
/*****/
static void
dialog_cancel_callback(GtkWidget *widget, gpointer data)
{
gtk_widget_destroy(GTK_WIDGET(data));
} /* dialog_cancel_callback */

View File

@ -1,869 +0,0 @@
/* Displace --- image filter plug-in for The Gimp image manipulation program
* Copyright (C) 1996 Stephen Robert Norris
* Much of the code taken from the pinch plug-in by 1996 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
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* You can contact me at srn@flibble.cs.su.oz.au.
* Please send me any patches or enhancements to this code.
* You can contact the original The Gimp authors at gimp@xcf.berkeley.edu
*
* Extensive modifications to the dialog box, parameters, and some
* legibility stuff in displace() by Federico Mena Quintero ---
* federico@nuclecu.unam.mx. If there are any bugs in these
* changes, they are my fault and not Stephen's.
*
* JTL: May 29th 1997
* Added (part of) the patch from Eiichi Takamori -- the part which removes the border artefacts
* (http://ha1.seikyou.ne.jp/home/taka/gimp/displace/displace.html)
* Added ability to use transparency as the identity transformation
* (Full transparency is treated as if it was grey 0.5)
* and the possibility to use RGB/RGBA pictures where the intensity of the pixel is taken into account
*
*/
/* Version 1.12. */
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <unistd.h>
#include <signal.h>
#include "gtk/gtk.h"
#include "libgimp/gimp.h"
#include "libgimp/gimpui.h"
/* Some useful macros */
#define ENTRY_WIDTH 75
#define TILE_CACHE_SIZE 48
#define WRAP 0
#define SMEAR 1
#define BLACK 2
typedef struct {
gdouble amount_x;
gdouble amount_y;
gint do_x;
gint do_y;
gint displace_map_x;
gint displace_map_y;
gint displace_type;
} DisplaceVals;
typedef struct {
GtkWidget *amount_x;
GtkWidget *amount_y;
GtkWidget *menu_x;
GtkWidget *menu_y;
gint run;
} DisplaceInterface;
/*
* Function prototypes.
*/
static void query (void);
static void run (gchar *name,
gint nparams,
GParam *param,
gint *nreturn_vals,
GParam **return_vals);
static void displace (GDrawable *drawable);
static gint displace_dialog (GDrawable *drawable);
static GTile * displace_pixel (GDrawable * drawable,
GTile * tile,
gint width,
gint height,
gint x1,
gint y1,
gint x2,
gint y2,
gint x,
gint y,
gint * row,
gint * col,
guchar * pixel);
static guchar bilinear (gdouble x,
gdouble y,
guchar * v);
static gint displace_map_constrain (gint32 image_id,
gint32 drawable_id,
gpointer data);
static void displace_map_x_callback (gint32 id,
gpointer data);
static void displace_map_y_callback (gint32 id,
gpointer data);
static void displace_close_callback (GtkWidget *widget,
gpointer data);
static void displace_ok_callback (GtkWidget *widget,
gpointer data);
static void displace_toggle_update (GtkWidget *widget,
gpointer data);
static void displace_x_toggle_update (GtkWidget *widget,
gpointer data);
static void displace_y_toggle_update (GtkWidget *widget,
gpointer data);
static void displace_entry_callback (GtkWidget *widget,
gpointer data);
static gdouble displace_map_give_value (guchar* ptr,
gint alpha,
gint bytes);
/***** Local vars *****/
GPlugInInfo PLUG_IN_INFO =
{
NULL, /* init_proc */
NULL, /* quit_proc */
query, /* query_proc */
run, /* run_proc */
};
static DisplaceVals dvals =
{
20.0, /* amount_x */
20.0, /* amount_y */
TRUE, /* do_x */
TRUE, /* do_y */
-1, /* displace_map_x */
-1, /* displace_map_y */
WRAP /* displace_type */
};
static DisplaceInterface dint =
{
NULL, /* amount_x */
NULL, /* amount_y */
NULL, /* menu_x */
NULL, /* menu_y */
FALSE /* run */
};
/***** Functions *****/
MAIN ()
static void
query ()
{
static GParamDef args[] =
{
{ PARAM_INT32, "run_mode", "Interactive, non-interactive" },
{ PARAM_IMAGE, "image", "Input image (unused)" },
{ PARAM_DRAWABLE, "drawable", "Input drawable" },
{ PARAM_FLOAT, "amount_x", "Displace multiplier for X direction" },
{ PARAM_FLOAT, "amount_y", "Displace multiplier for Y direction" },
{ PARAM_INT32, "do_x", "Displace in X direction?" },
{ PARAM_INT32, "do_y", "Displace in Y direction?" },
{ PARAM_DRAWABLE, "displace_map_x", "Displacement map for X direction" },
{ PARAM_DRAWABLE, "displace_map_y", "Displacement map for Y direction" },
{ PARAM_INT32, "displace_type", "Edge behavior: { WRAP (0), SMEAR (1), BLACK (2) }" }
};
static GParamDef *return_vals = NULL;
static gint nargs = sizeof (args) / sizeof (args[0]);
static gint nreturn_vals = 0;
gimp_install_procedure ("plug_in_displace",
"Displace the contents of the specified drawable",
"Displaces the contents of the specified drawable by the amounts specified by 'amount_x' and 'amount_y' multiplied by the intensity of corresponding pixels in the 'displace_map' drawables. Both 'displace_map' drawables must be of type GRAY_IMAGE for this operation to succeed.",
"Stephen Robert Norris & (ported to 1.0 by) Spencer Kimball",
"Stephen Robert Norris",
"1996",
"<Image>/Filters/Distorts/Displace",
"RGB*, GRAY*",
PROC_PLUG_IN,
nargs, nreturn_vals,
args, return_vals);
}
static void
run (gchar *name,
gint nparams,
GParam *param,
gint *nreturn_vals,
GParam **return_vals)
{
static GParam values[1];
GDrawable *drawable;
GRunModeType run_mode;
GStatusType status = STATUS_SUCCESS;
run_mode = param[0].data.d_int32;
/* Get the specified drawable */
drawable = gimp_drawable_get (param[2].data.d_drawable);
*nreturn_vals = 1;
*return_vals = values;
values[0].type = PARAM_STATUS;
values[0].data.d_status = status;
switch (run_mode)
{
case RUN_INTERACTIVE:
/* Possibly retrieve data */
gimp_get_data ("plug_in_displace", &dvals);
/* First acquire information with a dialog */
if (! displace_dialog (drawable))
return;
break;
case RUN_NONINTERACTIVE:
/* Make sure all the arguments are there! */
if (nparams != 10)
status = STATUS_CALLING_ERROR;
if (status == STATUS_SUCCESS)
{
dvals.amount_x = param[3].data.d_float;
dvals.amount_y = param[4].data.d_float;
dvals.do_x = param[5].data.d_int32;
dvals.do_x = param[6].data.d_int32;
dvals.displace_map_x = param[7].data.d_int32;
dvals.displace_map_y = param[8].data.d_int32;
dvals.displace_type = param[9].data.d_int32;
}
break;
case RUN_WITH_LAST_VALS:
/* Possibly retrieve data */
gimp_get_data ("plug_in_displace", &dvals);
break;
default:
break;
}
if (status == STATUS_SUCCESS && (dvals.do_x || dvals.do_y))
{
gimp_progress_init ("Displacing...");
/* set the tile cache size */
gimp_tile_cache_ntiles (TILE_CACHE_SIZE);
/* run the pinch effect */
displace (drawable);
if (run_mode != RUN_NONINTERACTIVE)
gimp_displays_flush ();
/* Store data */
if (run_mode == RUN_INTERACTIVE)
gimp_set_data ("plug_in_displace", &dvals, sizeof (DisplaceVals));
}
values[0].data.d_status = status;
gimp_drawable_detach (drawable);
}
static int
displace_dialog (GDrawable *drawable)
{
GtkWidget *dlg;
GtkWidget *label;
GtkWidget *button;
GtkWidget *toggle;
GtkWidget *toggle_hbox;
GtkWidget *frame;
GtkWidget *table;
GtkWidget *entry;
GtkWidget *option_menu;
GtkWidget *menu;
GSList *group = NULL;
gchar **argv;
gchar buffer[32];
gint argc;
gint use_wrap = (dvals.displace_type == WRAP);
gint use_smear = (dvals.displace_type == SMEAR);
gint use_black = (dvals.displace_type == BLACK);
argc = 1;
argv = g_new (gchar *, 1);
argv[0] = g_strdup ("displace");
printf("displace: pid = %d\n", getpid());
gtk_init (&argc, &argv);
dlg = gtk_dialog_new ();
gtk_window_set_title (GTK_WINDOW (dlg), "Displace");
gtk_window_position (GTK_WINDOW (dlg), GTK_WIN_POS_MOUSE);
gtk_signal_connect (GTK_OBJECT (dlg), "destroy",
(GtkSignalFunc) displace_close_callback,
NULL);
/* Action area */
button = gtk_button_new_with_label ("OK");
GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
gtk_signal_connect (GTK_OBJECT (button), "clicked",
(GtkSignalFunc) displace_ok_callback,
dlg);
gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dlg)->action_area), button, TRUE, TRUE, 0);
gtk_widget_grab_default (button);
gtk_widget_show (button);
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));
gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dlg)->action_area), button, TRUE, TRUE, 0);
gtk_widget_show (button);
/* The main table */
frame = gtk_frame_new ("Displace Options");
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 (3, 3, FALSE);
gtk_container_border_width (GTK_CONTAINER (table), 5);
gtk_container_add (GTK_CONTAINER (frame), table);
gtk_table_set_row_spacing (GTK_TABLE (table), 0, 10);
gtk_table_set_row_spacing (GTK_TABLE (table), 1, 10);
gtk_table_set_col_spacing (GTK_TABLE (table), 0, 10);
gtk_table_set_col_spacing (GTK_TABLE (table), 1, 10);
/* on_x, on_y */
toggle = gtk_check_button_new_with_label ("X Displacement: ");
gtk_table_attach (GTK_TABLE (table), toggle, 0, 1, 0, 1, GTK_FILL, GTK_FILL, 0, 0);
gtk_signal_connect (GTK_OBJECT (toggle), "toggled",
(GtkSignalFunc) displace_x_toggle_update,
&dvals.do_x);
gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (toggle), dvals.do_x);
gtk_widget_show (toggle);
toggle = gtk_check_button_new_with_label ("Y Displacement: ");
gtk_table_attach (GTK_TABLE (table), toggle, 0, 1, 1, 2, GTK_FILL, GTK_FILL, 0, 0);
gtk_signal_connect (GTK_OBJECT (toggle), "toggled",
(GtkSignalFunc) displace_y_toggle_update,
&dvals.do_y);
gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (toggle), dvals.do_y);
gtk_widget_show (toggle);
/* amount_x, amount_y */
dint.amount_x = entry = gtk_entry_new ();
gtk_table_attach (GTK_TABLE (table), entry, 1, 2, 0, 1, GTK_FILL, GTK_FILL, 0, 0);
gtk_widget_set_usize (entry, ENTRY_WIDTH, 0);
sprintf (buffer, "%f", dvals.amount_x);
gtk_entry_set_text (GTK_ENTRY (entry), buffer);
gtk_signal_connect (GTK_OBJECT (entry), "changed",
(GtkSignalFunc) displace_entry_callback,
&dvals.amount_x);
gtk_widget_show (entry);
dint.amount_y = entry = gtk_entry_new ();
gtk_table_attach (GTK_TABLE (table), entry, 1, 2, 1, 2, GTK_FILL, GTK_FILL, 0, 0);
gtk_widget_set_usize (entry, ENTRY_WIDTH, 0);
sprintf (buffer, "%f", dvals.amount_y);
gtk_entry_set_text (GTK_ENTRY (entry), buffer);
gtk_signal_connect (GTK_OBJECT (entry), "changed",
(GtkSignalFunc) displace_entry_callback,
&dvals.amount_y);
gtk_widget_show (entry);
/* menu_x, menu_y */
dint.menu_x = option_menu = gtk_option_menu_new ();
gtk_table_attach (GTK_TABLE (table), option_menu, 2, 3, 0, 1,
GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
menu = gimp_drawable_menu_new (displace_map_constrain, displace_map_x_callback,
drawable, dvals.displace_map_x);
gtk_option_menu_set_menu (GTK_OPTION_MENU (option_menu), menu);
gtk_widget_show (option_menu);
dint.menu_y = option_menu = gtk_option_menu_new ();
gtk_table_attach (GTK_TABLE (table), option_menu, 2, 3, 1, 2,
GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
menu = gimp_drawable_menu_new (displace_map_constrain, displace_map_y_callback,
drawable, dvals.displace_map_y);
gtk_option_menu_set_menu (GTK_OPTION_MENU (option_menu), menu);
gtk_widget_show (option_menu);
/* Displacement Type */
toggle_hbox = gtk_hbox_new (FALSE, 10);
gtk_container_border_width (GTK_CONTAINER (toggle_hbox), 5);
gtk_table_attach (GTK_TABLE (table), toggle_hbox, 0, 3, 2, 3, GTK_FILL, GTK_FILL, 0, 0);
label = gtk_label_new ("On Edges: ");
gtk_box_pack_start (GTK_BOX (toggle_hbox), label, FALSE, FALSE, 0);
gtk_widget_show (label);
toggle = gtk_radio_button_new_with_label (group, "Wrap");
group = gtk_radio_button_group (GTK_RADIO_BUTTON (toggle));
gtk_box_pack_start (GTK_BOX (toggle_hbox), toggle, FALSE, FALSE, 0);
gtk_signal_connect (GTK_OBJECT (toggle), "toggled",
(GtkSignalFunc) displace_toggle_update,
&use_wrap);
gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (toggle), use_wrap);
gtk_widget_show (toggle);
toggle = gtk_radio_button_new_with_label (group, "Smear");
group = gtk_radio_button_group (GTK_RADIO_BUTTON (toggle));
gtk_box_pack_start (GTK_BOX (toggle_hbox), toggle, FALSE, FALSE, 0);
gtk_signal_connect (GTK_OBJECT (toggle), "toggled",
(GtkSignalFunc) displace_toggle_update,
&use_smear);
gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (toggle), use_smear);
gtk_widget_show (toggle);
toggle = gtk_radio_button_new_with_label (group, "Black");
group = gtk_radio_button_group (GTK_RADIO_BUTTON (toggle));
gtk_box_pack_start (GTK_BOX (toggle_hbox), toggle, FALSE, FALSE, 0);
gtk_signal_connect (GTK_OBJECT (toggle), "toggled",
(GtkSignalFunc) displace_toggle_update,
&use_black);
gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (toggle), use_black);
gtk_widget_show (toggle);
gtk_widget_show (toggle_hbox);
gtk_widget_show (table);
gtk_widget_show (frame);
gtk_widget_show (dlg);
gtk_main ();
gdk_flush ();
/* determine displace type */
if (use_wrap)
dvals.displace_type = WRAP;
else if (use_smear)
dvals.displace_type = SMEAR;
else if (use_black)
dvals.displace_type = BLACK;
return dint.run;
}
/* The displacement is done here. */
static void
displace (GDrawable *drawable)
{
GDrawable *map_x;
GDrawable *map_y;
GPixelRgn dest_rgn;
GPixelRgn map_x_rgn;
GPixelRgn map_y_rgn;
GTile * tile = NULL;
gint row = -1;
gint col = -1;
gpointer pr;
gint width;
gint height;
gint bytes;
guchar *destrow, *dest;
guchar *mxrow, *mx;
guchar *myrow, *my;
guchar pixel[4][4];
gint x1, y1, x2, y2;
gint x, y;
gint progress, max_progress;
gdouble amnt;
gdouble needx, needy;
gint xi, yi;
guchar values[4];
guchar val;
gint k;
gdouble xm_val, ym_val;
gint xm_alpha = 0;
gint ym_alpha = 0;
gint xm_bytes = 1;
gint ym_bytes = 1;
/* Get selection area */
gimp_drawable_mask_bounds (drawable->id, &x1, &y1, &x2, &y2);
width = drawable->width;
height = drawable->height;
bytes = drawable->bpp;
progress = 0;
max_progress = (x2 - x1) * (y2 - y1);
/*
* The algorithm used here is simple - see
* http://the-tech.mit.edu/KPT/Tips/KPT7/KPT7.html for a description.
*/
/* Get the drawables */
if (dvals.displace_map_x != -1 && dvals.do_x)
{
map_x = gimp_drawable_get (dvals.displace_map_x);
gimp_pixel_rgn_init (&map_x_rgn, map_x, x1, y1, (x2 - x1), (y2 - y1), FALSE, FALSE);
if (gimp_drawable_has_alpha(map_x->id))
xm_alpha = 1;
xm_bytes = gimp_drawable_bpp(map_x->id);
}
else
map_x = NULL;
if (dvals.displace_map_y != -1 && dvals.do_y)
{
map_y = gimp_drawable_get (dvals.displace_map_y);
gimp_pixel_rgn_init (&map_y_rgn, map_y, x1, y1, (x2 - x1), (y2 - y1), FALSE, FALSE);
if (gimp_drawable_has_alpha(map_y->id))
ym_alpha = 1;
ym_bytes = gimp_drawable_bpp(map_y->id);
}
else
map_y = NULL;
gimp_pixel_rgn_init (&dest_rgn, drawable, x1, y1, (x2 - x1), (y2 - y1), TRUE, TRUE);
/* Register the pixel regions */
if (dvals.do_x && dvals.do_y)
pr = gimp_pixel_rgns_register (3, &dest_rgn, &map_x_rgn, &map_y_rgn);
else if (dvals.do_x)
pr = gimp_pixel_rgns_register (2, &dest_rgn, &map_x_rgn);
else if (dvals.do_y)
pr = gimp_pixel_rgns_register (2, &dest_rgn, &map_y_rgn);
else
pr = NULL;
for (pr = pr; pr != NULL; pr = gimp_pixel_rgns_process (pr))
{
destrow = dest_rgn.data;
if (dvals.do_x)
mxrow = map_x_rgn.data;
if (dvals.do_y)
myrow = map_y_rgn.data;
for (y = dest_rgn.y; y < (dest_rgn.y + dest_rgn.h); y++)
{
dest = destrow;
mx = mxrow;
my = myrow;
/*
* We could move the displacement image address calculation out of here,
* but when we can have different sized displacement and destination
* images we'd have to move it back anyway.
*/
for (x = dest_rgn.x; x < (dest_rgn.x + dest_rgn.w); x++)
{
if (dvals.do_x)
{
xm_val = displace_map_give_value(mx, xm_alpha, xm_bytes);
amnt = dvals.amount_x * (xm_val - 127.5) / 127.5;
needx = x + amnt;
mx += xm_bytes;
}
else
needx = x;
if (dvals.do_y)
{
ym_val = displace_map_give_value(my, ym_alpha, ym_bytes);
amnt = dvals.amount_y * (ym_val - 127.5) / 127.5;
needy = y + amnt;
my += ym_bytes;
}
else
needy = y;
/* Calculations complete; now copy the proper pixel */
if (needx >= 0.0)
xi = (int) needx;
else
xi = -((int) -needx + 1);
if (needy >= 0.0)
yi = (int) needy;
else
yi = -((int) -needy + 1);
tile = displace_pixel (drawable, tile, width, height, x1, y1, x2, y2, xi, yi, &row, &col, pixel[0]);
tile = displace_pixel (drawable, tile, width, height, x1, y1, x2, y2, xi + 1, yi, &row, &col, pixel[1]);
tile = displace_pixel (drawable, tile, width, height, x1, y1, x2, y2, xi, yi + 1, &row, &col, pixel[2]);
tile = displace_pixel (drawable, tile, width, height, x1, y1, x2, y2, xi + 1, yi + 1, &row, &col, pixel[3]);
for (k = 0; k < bytes; k++)
{
values[0] = pixel[0][k];
values[1] = pixel[1][k];
values[2] = pixel[2][k];
values[3] = pixel[3][k];
val = bilinear(needx, needy, values);
*dest++ = val;
} /* for */
}
destrow += dest_rgn.rowstride;
if (dvals.do_x)
mxrow += map_x_rgn.rowstride;
if (dvals.do_y)
myrow += map_y_rgn.rowstride;
}
progress += dest_rgn.w * dest_rgn.h;
gimp_progress_update ((double) progress / (double) max_progress);
} /* for */
if (tile)
gimp_tile_unref (tile, FALSE);
/* detach from the map drawables */
if (dvals.do_x)
gimp_drawable_detach (map_x);
if (dvals.do_y)
gimp_drawable_detach (map_y);
/* update the region */
gimp_drawable_flush (drawable);
gimp_drawable_merge_shadow (drawable->id, TRUE);
gimp_drawable_update (drawable->id, x1, y1, (x2 - x1), (y2 - y1));
} /* displace */
static gdouble
displace_map_give_value(guchar *pt, gint alpha, gint bytes)
{
gdouble ret, val_alpha;
if (bytes >= 3)
ret = 0.30 * pt[0] + 0.59 * pt[1] + 0.11 * pt[2];
else
ret = (gdouble) *pt;
if (alpha)
{
val_alpha = pt[bytes - 1];
ret = ((ret - 127.5) * val_alpha / 255.0) + 127.5;
};
return (ret);
}
static GTile *
displace_pixel (GDrawable * drawable,
GTile * tile,
gint width,
gint height,
gint x1,
gint y1,
gint x2,
gint y2,
gint x,
gint y,
gint * row,
gint * col,
guchar * pixel)
{
static guchar empty_pixel[4] = {0, 0, 0, 0};
guchar *data;
gint b;
/* Tile the image. */
if (dvals.displace_type == WRAP)
{
if (x < 0)
x = width - (-x % width);
else
x %= width;
if (y < 0)
y = height - (-y % height);
else
y %= height;
}
/* Smear out the edges of the image by repeating pixels. */
else if (dvals.displace_type == SMEAR)
{
if (x < 0)
x = 0;
else if (x > width - 1)
x = width - 1;
if (y < 0)
y = 0;
else if (y > height - 1)
y = height - 1;
}
if (x >= x1 && y >= y1 && x < x2 && y < y2)
{
if ((x >> 6 != *col) || (y >> 6 != *row))
{
*col = x / 64;
*row = y / 64;
if (tile)
gimp_tile_unref (tile, FALSE);
tile = gimp_drawable_get_tile (drawable, FALSE, *row, *col);
gimp_tile_ref (tile);
}
data = tile->data + tile->bpp * (tile->ewidth * (y % 64) + (x % 64));
}
else
data = empty_pixel;
for (b = 0; b < drawable->bpp; b++)
pixel[b] = data[b];
return tile;
}
static guchar
bilinear (gdouble x, gdouble y, guchar *v)
{
gdouble m0, m1;
x = fmod(x, 1.0);
y = fmod(y, 1.0);
if (x < 0)
x += 1.0;
if (y < 0)
y += 1.0;
m0 = (gdouble) v[0] + x * ((gdouble) v[1] - v[0]);
m1 = (gdouble) v[2] + x * ((gdouble) v[3] - v[2]);
return (guchar) (m0 + y * (m1 - m0));
} /* bilinear */
/* Displace interface functions */
static gint
displace_map_constrain (gint32 image_id,
gint32 drawable_id,
gpointer data)
{
GDrawable *drawable;
drawable = (GDrawable *) data;
if (drawable_id == -1)
return TRUE;
if (gimp_drawable_width (drawable_id) == drawable->width &&
gimp_drawable_height (drawable_id) == drawable->height)
return TRUE;
else
return FALSE;
}
static void
displace_map_x_callback (gint32 id,
gpointer data)
{
dvals.displace_map_x = id;
}
static void
displace_map_y_callback (gint32 id,
gpointer data)
{
dvals.displace_map_y = id;
}
static void
displace_close_callback (GtkWidget *widget,
gpointer data)
{
gtk_main_quit ();
}
static void
displace_ok_callback (GtkWidget *widget,
gpointer data)
{
dint.run = TRUE;
gtk_widget_destroy (GTK_WIDGET (data));
}
static void
displace_toggle_update (GtkWidget *widget,
gpointer data)
{
int *toggle_val;
toggle_val = (int *) data;
if (GTK_TOGGLE_BUTTON (widget)->active)
*toggle_val = TRUE;
else
*toggle_val = FALSE;
}
static void
displace_x_toggle_update (GtkWidget *widget,
gpointer data)
{
int *toggle_val;
toggle_val = (int *) data;
if (GTK_TOGGLE_BUTTON (widget)->active)
*toggle_val = TRUE;
else
*toggle_val = FALSE;
if (dint.amount_x)
gtk_widget_set_sensitive (dint.amount_x, *toggle_val);
if (dint.menu_x)
gtk_widget_set_sensitive (dint.menu_x, *toggle_val);
}
static void
displace_y_toggle_update (GtkWidget *widget,
gpointer data)
{
int *toggle_val;
toggle_val = (int *) data;
if (GTK_TOGGLE_BUTTON (widget)->active)
*toggle_val = TRUE;
else
*toggle_val = FALSE;
if (dint.amount_y)
gtk_widget_set_sensitive (dint.amount_y, *toggle_val);
if (dint.menu_y)
gtk_widget_set_sensitive (dint.menu_y, *toggle_val);
}
static void
displace_entry_callback (GtkWidget *widget,
gpointer data)
{
double *text_val;
text_val = (double *) data;
*text_val = atof (gtk_entry_get_text (GTK_ENTRY (widget)));
}

View File

@ -1,847 +0,0 @@
/* edge filter for the GIMP
* -Peter Mattis
*
* This filter performs edge detection on the input image.
* The code for this filter is based on "pgmedge", a program
* that is part of the netpbm package.
*/
/* pgmedge.c - edge-detect a portable graymap
**
** Copyright (C) 1989 by Jef Poskanzer.
**
** Permission to use, copy, modify, and distribute this software and its
** documentation for any purpose and without fee is hereby granted, provided
** that the above copyright notice appear in all copies and that both that
** copyright notice and this permission notice appear in supporting
** documentation. This software is provided "as is" without express or
** implied warranty.
*/
/*
* Ported to GIMP Plug-in API 1.0
* version 1.07
* This version requires GIMP v0.99.10 or above.
*
* This plug-in performs edge detection. The code is based on edge.c
* for GIMP 0.54 by Peter Mattis.
*
* Eiichi Takamori <taka@ma1.seikyou.ne.jp>
* http://ha1.seikyou.ne.jp/home/taka/gimp/
*
* Tips: you can enter arbitrary value into entry.
* (not bounded between 1.0 and 10.0)
*
* Changes from version 1.06 to version 1.07:
* - Added entry
* - Cleaned up code a bit
*
* Differences from Peter Mattis's original `edge' plug-in:
* - Added Wrapmode. (useful for tilable images)
* - Enhanced speed in this version.
* - It works with the alpha channel.
*/
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "gtk/gtk.h"
#include "libgimp/gimp.h"
#include "libgimp/gimpui.h"
#ifdef RCSID
static char rcsid[] = "$Id$";
#endif
/* Some useful macros */
#define TILE_CACHE_SIZE 48
#define SCALE_WIDTH 92
#define ENTRY_WIDTH 40
#define WRAP 0
#define SMEAR 1
#define BLACK 2
typedef struct {
gdouble amount;
gint wrapmode;
} EdgeVals;
typedef struct {
gint run;
} EdgeInterface;
typedef struct {
GTile *tile;
gint row, col; /* tile's row, col */
gint bpp;
gint tile_width, tile_height;
GDrawable *drawable;
gint drawable_width, drawable_height;
} TileBuf;
/*
* Function prototypes.
*/
static void query (void);
static void run (gchar *name,
gint nparams,
GParam *param,
gint *nreturn_vals,
GParam **return_vals);
static void edge (GDrawable *drawable);
static gint edge_dialog (GDrawable *drawable);
static void edge_close_callback (GtkWidget *widget,
gpointer data);
static void edge_ok_callback (GtkWidget *widget,
gpointer data);
static void edge_toggle_update (GtkWidget *widget,
gpointer data);
static void edge_scale_update (GtkAdjustment *ajustment,
gpointer data);
static void edge_entry_update (GtkWidget *entry,
gpointer data);
static long long_sqrt (long n);
static void init_tile_buf ( TileBuf *buf, GDrawable *drawable );
static void get_tile_pixel ( TileBuf *buf, gint x, gint y,
guchar *pixel, gint wrapmode );
static void end_tile_buf ( TileBuf *buf );
/***** Local vars *****/
GPlugInInfo PLUG_IN_INFO =
{
NULL, /* init_proc */
NULL, /* quit_proc */
query, /* query_proc */
run, /* run_proc */
};
static EdgeVals evals =
{
2.0, /* amount */
SMEAR /* wrapmode */
};
static EdgeInterface eint =
{
FALSE /* run */
};
/***** Functions *****/
MAIN ()
static void
query ()
{
static GParamDef args[] =
{
{ PARAM_INT32, "run_mode", "Interactive, non-interactive" },
{ PARAM_IMAGE, "image", "Input image (unused)" },
{ PARAM_DRAWABLE, "drawable", "Input drawable" },
{ PARAM_FLOAT, "amount", "Edge detection amount" },
{ PARAM_INT32, "wrapmode", "Edge detection behavior: { WRAP (0), SMEAR (1), BLACK (2) }" }
};
static GParamDef *return_vals = NULL;
static gint nargs = sizeof (args) / sizeof (args[0]);
static gint nreturn_vals = 0;
gchar *help_string =
" Perform edge detection on the contents of the specified"
" drawable. It applies, I think, convolusion with 3x3 kernel. AMOUNT"
" is an arbitrary constant, WRAPMODE is like displace plug-in"
" (useful for tilable image).";
gimp_install_procedure ("plug_in_edge",
"Perform edge detection on the contents of the specified drawable",
help_string,
"Peter Mattis & (ported to 1.0 by) Eiichi Takamori",
"Peter Mattis",
"1996",
"<Image>/Filters/Edge-Detect/Edge",
"RGB*, GRAY*",
PROC_PLUG_IN,
nargs, nreturn_vals,
args, return_vals);
}
static void
run (gchar *name,
gint nparams,
GParam *param,
gint *nreturn_vals,
GParam **return_vals)
{
static GParam values[1];
GDrawable *drawable;
GRunModeType run_mode;
GStatusType status = STATUS_SUCCESS;
run_mode = param[0].data.d_int32;
/* Get the specified drawable */
drawable = gimp_drawable_get (param[2].data.d_drawable);
*nreturn_vals = 1;
*return_vals = values;
values[0].type = PARAM_STATUS;
values[0].data.d_status = status;
switch (run_mode)
{
case RUN_INTERACTIVE:
/* Possibly retrieve data */
gimp_get_data ("plug_in_edge", &evals);
/* First acquire information with a dialog */
if (! edge_dialog (drawable))
return;
break;
case RUN_NONINTERACTIVE:
/* Make sure all the arguments are there! */
if (nparams != 5)
status = STATUS_CALLING_ERROR;
if (status == STATUS_SUCCESS)
{
evals.amount = param[3].data.d_float;
evals.wrapmode = param[4].data.d_int32;
}
break;
case RUN_WITH_LAST_VALS:
/* Possibly retrieve data */
gimp_get_data ("plug_in_edge", &evals);
break;
default:
break;
}
if (status == STATUS_SUCCESS)
{
gimp_progress_init ("Edge detection...");
/* set the tile cache size */
gimp_tile_cache_ntiles (TILE_CACHE_SIZE);
/* run the edge effect */
edge (drawable);
if (run_mode != RUN_NONINTERACTIVE)
gimp_displays_flush ();
/* Store data */
if (run_mode == RUN_INTERACTIVE)
gimp_set_data ("plug_in_edge", &evals, sizeof (EdgeVals));
}
values[0].data.d_status = status;
gimp_drawable_detach (drawable);
}
/*********************************************************************
TileBuf Util Routines: Util routines for getting arbitrary pixel
CAUTION -- the tile is read only !!
**********************************************************************/
static void
init_tile_buf( TileBuf *buf, GDrawable *drawable )
{
buf->tile = NULL;
buf->col = 0;
buf->row = 0;
if ( gimp_drawable_color( drawable->id ) )
buf->bpp = 3;
else
buf->bpp = 1;
buf->tile_width = gimp_tile_width();
buf->tile_height = gimp_tile_height();
buf->drawable = drawable;
buf->drawable_width = gimp_drawable_width( drawable->id );
buf->drawable_height = gimp_drawable_height( drawable->id );
}
static void
get_tile_pixel( TileBuf *buf, gint x, gint y, guchar *pixel, gint wrapmode )
{
gint b;
gint offx, offy;
gint row, col;
guchar *ptr;
if ( x < 0 || x >= buf->drawable_width ||
y < 0 || y >= buf->drawable_height )
switch( wrapmode )
{
case WRAP:
if ( x < 0 || x >= buf->drawable_width )
{
x %= buf->drawable_width;
if ( x < 0 )
x += buf->drawable_width;
}
if ( y < 0 || y >= buf->drawable_height )
{
y %= buf->drawable_height;
if ( y < 0 )
y += buf->drawable_height;
}
break;
case SMEAR:
if ( x < 0 )
x = 0;
if ( x >= buf->drawable_width )
x = buf->drawable_width - 1;
if ( y < 0 )
y = 0;
if ( y >= buf->drawable_height )
y = buf->drawable_height - 1;
break;
case BLACK:
if ( x < 0 || x >= buf->drawable_width ||
y < 0 || y >= buf->drawable_height )
{
for ( b = 0; b < buf->bpp; b++ )
pixel[b]=0;
return;
}
break;
default:
return;
}
col = x / buf->tile_width;
offx = x % buf->tile_width;
row = y / buf->tile_height;
offy = y % buf->tile_height;
/* retrieve tile */
if ( !buf->tile || col != buf->col || row != buf->row )
{
if( buf->tile )
gimp_tile_unref( buf->tile, FALSE );
buf->col = col;
buf->row = row;
buf->tile = gimp_drawable_get_tile( buf->drawable, FALSE, row, col );
gimp_tile_ref( buf->tile );
}
/* retrieve target pixel */
ptr = buf->tile->data + ( offy * buf->tile->ewidth + offx ) * buf->tile->bpp;
for( b = 0; b < buf->bpp; b++ )
pixel[b] = ptr[b];
}
static void
end_tile_buf( TileBuf *buf )
{
if( buf->tile )
gimp_tile_unref( buf->tile, FALSE );
}
/**********************************************************************
TileBuf Util Routines End
**********************************************************************/
static long
long_sqrt (n)
long n;
{
#define lsqrt_max4pow (1UL << 30)
/* lsqrt_max4pow is the (machine-specific) largest power of 4 that can
* be represented in an unsigned long.
*
* Compute the integer square root of the integer argument n
* Method is to divide n by x computing the quotient x and remainder r
* Notice that the divisor x is changing as the quotient x changes
*
* Instead of shifting the dividend/remainder left, we shift the
* quotient/divisor right. The binary point starts at the extreme
* left, and shifts two bits at a time to the extreme right.
*
* The residue contains n-x^2. (Within these comments, the ^ operator
* signifies exponentiation rather than exclusive or. Also, the /
* operator returns fractions, rather than truncating, so 1/4 means
* one fourth, not zero.)
*
* Since (x + 1/2)^2 == x^2 + x + 1/4,
* n - (x + 1/2)^2 == (n - x^2) - (x + 1/4)
* Thus, we can increase x by 1/2 if we decrease (n-x^2) by (x+1/4)
*/
unsigned long residue; /* n - x^2 */
unsigned long root; /* x + 1/4 */
unsigned long half; /* 1/2 */
residue = n; /* n - (x = 0)^2, with suitable alignment */
/*
* if the correct answer fits in two bits, pull it out of a magic hat
*/
if (residue <= 12)
return (0x03FFEA94 >> (residue *= 2)) & 3;
root = lsqrt_max4pow; /* x + 1/4, shifted all the way left */
/* half = root + root; 1/2, shifted likewise */
/*
* Unwind iterations corresponding to leading zero bits
*/
while (root > residue)
root >>= 2;
/*
* Unwind the iteration corresponding to the first one bit
* Operations have been rearranged and combined for efficiency
* Initialization of half is folded into this iteration
*/
residue -= root; /* Decrease (n-x^2) by (0+1/4) */
half = root >> 2; /* 1/4, with binary point shifted right 2 */
root += half; /* x=1. (root is now (x=1)+1/4.) */
half += half; /* 1/2, properly aligned */
/*
* Normal loop (there is at least one iteration remaining)
*/
do
{
if (root <= residue) /* Whenever we can, */
{
residue -= root; /* decrease (n-x^2) by (x+1/4) */
root += half; /* increase x by 1/2 */
}
half >>= 2; /* Shift binary point 2 places right */
root -= half; /* x{ +1/2 } +1/4 - 1/8 == x { +1/2 } 1/8 */
root >>= 1; /* 2x{ +1 } +1/4, shifted right 2 places */
}
while (half); /* When 1/2 == 0, bin. point is at far right */
/*
* round up if (x+1/2)^2 < n
*/
if (root < residue)
++root;
/*
* Guaranteed to be correctly rounded (or truncated)
*/
return root;
}
/********************************************************/
/* */
/* Edge Detection main */
/* */
/********************************************************/
static void
edge( GDrawable *drawable )
{
/*
* this function is too long, so I must split this into a few
* functions later ... -- taka
*/
GPixelRgn src_rgn, dest_rgn;
gpointer pr;
TileBuf buf;
guchar *srcrow, *src;
guchar *destrow, *dest;
guchar pix00[3], pix01[3], pix02[3];
guchar pix10[3],/*pix11[3],*/ pix12[3];
guchar pix20[3], pix21[3], pix22[3];
glong width, height;
gint alpha, has_alpha, chan;
gint x, y;
gint x1, y1, x2, y2;
glong sum1, sum2;
glong sum, scale;
gint maxval;
gint cur_progress;
gint max_progress;
gint wrapmode;
if (evals.amount < 1.0 ) evals.amount = 1.0;
init_tile_buf( &buf, drawable );
gimp_drawable_mask_bounds ( drawable->id, &x1, &y1, &x2, &y2);
width = gimp_drawable_width ( drawable->id );
height = gimp_drawable_height ( drawable->id );
alpha = gimp_drawable_bpp ( drawable->id );
has_alpha = gimp_drawable_has_alpha ( drawable->id );
if( has_alpha ) alpha--;
maxval = 255;
scale = (10 << 16) / evals.amount;
wrapmode = evals.wrapmode;
cur_progress = 0;
max_progress = (x2 - x1) * (y2 - y1);
gimp_pixel_rgn_init( &src_rgn, drawable, x1, y1, x2-x1, y2-y1, FALSE, FALSE );
gimp_pixel_rgn_init( &dest_rgn, drawable, x1, y1, x2-x1, y2-y1, TRUE, TRUE );
for( pr = gimp_pixel_rgns_register( 2, &src_rgn, &dest_rgn );
pr != NULL;
pr = gimp_pixel_rgns_process(pr) )
{
srcrow = src_rgn.data;
destrow = dest_rgn.data;
for ( y = dest_rgn.y;
y < (dest_rgn.y + dest_rgn.h);
y++, srcrow += src_rgn.rowstride, destrow += dest_rgn.rowstride )
{
src = srcrow;
dest = destrow;
for( x = dest_rgn.x;
x < (dest_rgn.x + dest_rgn.w);
x++, src += src_rgn.bpp, dest += dest_rgn.bpp )
{
if( dest_rgn.x < x && x < dest_rgn.x + dest_rgn.w - 1 &&
dest_rgn.y < y && y < dest_rgn.y + dest_rgn.h - 1 )
{
/*
** 3x3 kernel is inside of the tile -- do fast
** version
*/
for( chan = 0; chan < alpha; chan++ )
{
/*
* PIX(1,1) is the current pixel, so
* e.g. PIX(0,0) means 1 above and 1 left pixel.
*
* There were casting to `long' in GIMP 0.54
* edge code, but I think `guchar' should be
* extended to `int' with minus operators, so
* there's no need to cast to `long'. Both sum1
* and sum2 will be between -4*255 to 4*255
*
* -- taka
*/
#define PIX(X,Y) src[ (Y-1)*src_rgn.rowstride + (X-1)*src_rgn.bpp + chan ]
/* make convolusion */
sum1 = ( PIX(2,0) - PIX(0,0) ) +
2 * ( PIX(2,1) - PIX(0,1) ) +
( PIX(2,2) - PIX(2,0) );
sum2 = ( PIX(0,2) - PIX(0,0) ) +
2 * ( PIX(1,2) - PIX(1,0) ) +
( PIX(2,2) - PIX(2,0) );
#undef PIX
/* common job ... */
sum = long_sqrt ( (long) sum1 * sum1 + (long) sum2 * sum2);
sum = (sum * scale) >> 16; /* arbitrary scaling factor */
if (sum > maxval) sum = maxval;
dest[chan] = sum;
}
} else {
/*
** The kernel is not inside of the tile -- do slow
** version
*/
/*
* When the kernel intersects the boundary of the
* image, get_tile_pixel() will (should) do the
* right work with `wrapmode'.
*/
get_tile_pixel( &buf, x-1, y-1, pix00, wrapmode );
get_tile_pixel( &buf, x , y-1, pix10, wrapmode );
get_tile_pixel( &buf, x+1, y-1, pix20, wrapmode );
get_tile_pixel( &buf, x-1, y , pix01, wrapmode );
get_tile_pixel( &buf, x+1, y , pix21, wrapmode );
get_tile_pixel( &buf, x-1, y+1, pix02, wrapmode );
get_tile_pixel( &buf, x , y+1, pix12, wrapmode );
get_tile_pixel( &buf, x+1, y+1, pix22, wrapmode );
for( chan = 0; chan < alpha; chan++ )
{
/* make convolusion */
sum1 = (pix20[chan] - pix00[chan] ) +
2 * (pix21[chan] - pix01[chan] ) +
(pix22[chan] - pix20[chan] );
sum2 = (pix02[chan] - pix00[chan] ) +
2 * (pix12[chan] - pix10[chan] ) +
(pix22[chan] - pix20[chan] );
/* common job ... */
sum = long_sqrt ( (long) sum1 * sum1 + (long) sum2 * sum2);
sum = (sum * scale) >> 16; /* arbitrary scaling factor */
if (sum > maxval) sum = maxval;
dest[chan] = sum;
}
}
if(has_alpha)
dest[alpha]=src[alpha];
}
}
cur_progress += dest_rgn.w * dest_rgn.h;
gimp_progress_update ( (double) cur_progress / (double) max_progress);
}
end_tile_buf( &buf );
gimp_drawable_flush (drawable);
gimp_drawable_merge_shadow (drawable->id, TRUE);
gimp_drawable_update (drawable->id, x1, y1, (x2 - x1), (y2 - y1));
}
/*******************************************************/
/* */
/* Dialog */
/* */
/*******************************************************/
static gint
edge_dialog(GDrawable *drawable)
{
GtkWidget *dlg;
GtkWidget *frame;
GtkWidget *table;
GtkWidget *hbox;
GtkWidget *button;
GtkWidget *toggle;
GtkWidget *label;
GtkWidget *scale;
GtkObject *scale_data;
GtkWidget *entry;
gchar buffer[256];
GSList *group = NULL;
gchar **argv;
gint argc;
gint use_wrap = (evals.wrapmode == WRAP);
gint use_smear = (evals.wrapmode == SMEAR);
gint use_black = (evals.wrapmode == BLACK);
gdouble init_val;
argc = 1;
argv = g_new (gchar *, 1);
argv[0] = g_strdup ("edge");
gtk_init (&argc, &argv);
gtk_rc_parse (gimp_gtkrc ());
dlg = gtk_dialog_new ();
gtk_window_set_title (GTK_WINDOW (dlg), "Edge Detection");
gtk_window_position (GTK_WINDOW (dlg), GTK_WIN_POS_MOUSE);
gtk_signal_connect (GTK_OBJECT (dlg), "destroy",
(GtkSignalFunc) edge_close_callback,
NULL);
/* Action area */
button = gtk_button_new_with_label ("OK");
GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
gtk_signal_connect (GTK_OBJECT (button), "clicked",
(GtkSignalFunc) edge_ok_callback,
dlg);
gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dlg)->action_area), button, TRUE, TRUE, 0);
gtk_widget_grab_default (button);
gtk_widget_show (button);
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));
gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dlg)->action_area), button, TRUE, TRUE, 0);
gtk_widget_show (button);
/* parameter settings */
frame = gtk_frame_new ("Edge Detection Options");
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 (2, 3, FALSE);
gtk_container_border_width (GTK_CONTAINER (table), 5);
gtk_container_add (GTK_CONTAINER (frame), table);
/*
Label, scale, entry for evals.amount
*/
label = gtk_label_new ("Amount:");
gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
gtk_widget_show (label);
/* This prevents annoying change of adjustment */
init_val = evals.amount < 1.0 ? 1.0 :
evals.amount > 10.0 ? 10.0 : evals.amount;
scale_data = gtk_adjustment_new (init_val, 1.0, 10.0, 0.1, 0.1, 0.0);
scale = gtk_hscale_new (GTK_ADJUSTMENT (scale_data));
gtk_widget_set_usize (scale, SCALE_WIDTH, 0);
gtk_scale_set_draw_value (GTK_SCALE (scale), FALSE);
#if 0
gtk_scale_set_value_pos (GTK_SCALE (scale), GTK_POS_TOP);
gtk_scale_set_digits (GTK_SCALE (scale), 1);
gtk_range_set_update_policy (GTK_RANGE (scale), GTK_UPDATE_DELAYED);
#endif
entry = gtk_entry_new ();
gtk_widget_set_usize (entry, ENTRY_WIDTH, 0);
gtk_widget_show (scale);
gtk_widget_show (entry);
gtk_table_attach (GTK_TABLE (table), label, 0, 1, 0, 1,
GTK_FILL, 0, 5, 0);
gtk_table_attach (GTK_TABLE (table), scale, 2, 3, 0, 1,
GTK_EXPAND | GTK_FILL, 0, 5, 0);
gtk_table_attach (GTK_TABLE (table), entry, 1, 2, 0, 1,
GTK_FILL, 0, 0, 0);
gtk_signal_connect (GTK_OBJECT (scale_data), "value_changed",
(GtkSignalFunc) edge_scale_update,
&evals.amount);
sprintf (buffer, "%0.1f", evals.amount);
gtk_entry_set_text (GTK_ENTRY (entry), buffer);
gtk_signal_connect (GTK_OBJECT (entry), "changed",
(GtkSignalFunc) edge_entry_update,
&evals.amount);
gtk_object_set_user_data (GTK_OBJECT (entry), scale_data);
gtk_object_set_user_data (scale_data, entry);
/*
Radio buttons WRAP, SMEAR, BLACK ...
*/
hbox = gtk_hbox_new (FALSE, 5);
gtk_container_border_width (GTK_CONTAINER (hbox), 5);
gtk_table_attach (GTK_TABLE (table), hbox, 0, 3, 1, 2,
GTK_FILL, GTK_FILL, 0, 0);
toggle = gtk_radio_button_new_with_label (group, "Wrap");
group = gtk_radio_button_group (GTK_RADIO_BUTTON (toggle));
gtk_box_pack_start (GTK_BOX (hbox), toggle, TRUE, TRUE, 0);
gtk_signal_connect (GTK_OBJECT (toggle), "toggled",
(GtkSignalFunc) edge_toggle_update,
&use_wrap);
gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (toggle), use_wrap);
gtk_widget_show (toggle);
toggle = gtk_radio_button_new_with_label (group, "Smear");
group = gtk_radio_button_group (GTK_RADIO_BUTTON (toggle));
gtk_box_pack_start (GTK_BOX (hbox), toggle, TRUE, TRUE, 0);
gtk_signal_connect (GTK_OBJECT (toggle), "toggled",
(GtkSignalFunc) edge_toggle_update,
&use_smear);
gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (toggle), use_smear);
gtk_widget_show (toggle);
toggle = gtk_radio_button_new_with_label (group, "Black");
group = gtk_radio_button_group (GTK_RADIO_BUTTON (toggle));
gtk_box_pack_start (GTK_BOX (hbox), toggle, TRUE, TRUE, 0);
gtk_signal_connect (GTK_OBJECT (toggle), "toggled",
(GtkSignalFunc) edge_toggle_update,
&use_black);
gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (toggle), use_black);
gtk_widget_show (toggle);
gtk_widget_show (hbox);
gtk_widget_show (table);
gtk_widget_show (frame);
gtk_widget_show (dlg);
gtk_main ();
gdk_flush ();
if (use_wrap)
evals.wrapmode = WRAP;
else if (use_smear)
evals.wrapmode = SMEAR;
else if (use_black)
evals.wrapmode = BLACK;
return eint.run;
}
/* Edge detection interface functions */
static void
edge_close_callback (GtkWidget *widget,
gpointer data)
{
gtk_main_quit ();
}
static void
edge_ok_callback (GtkWidget *widget,
gpointer data)
{
eint.run = TRUE;
gtk_widget_destroy (GTK_WIDGET (data));
}
static void
edge_toggle_update (GtkWidget *widget,
gpointer data)
{
int *toggle_val;
toggle_val = (int *) data;
if (GTK_TOGGLE_BUTTON (widget)->active)
*toggle_val = TRUE;
else
*toggle_val = FALSE;
}
static void
edge_scale_update (GtkAdjustment *adjustment,
gpointer data)
{
GtkWidget *entry;
gdouble *ptr = (gdouble *) data;
*ptr = adjustment->value;
entry = gtk_object_get_user_data (GTK_OBJECT (adjustment));
if (entry)
{
gchar buffer[256];
sprintf (buffer, "%0.1f", *ptr);
gtk_signal_handler_block_by_data (GTK_OBJECT (entry), data);
gtk_entry_set_text (GTK_ENTRY (entry), buffer);
gtk_signal_handler_unblock_by_data (GTK_OBJECT (entry), data);
}
}
static void
edge_entry_update (GtkWidget *entry,
gpointer data)
{
GtkAdjustment *adjustment;
gdouble *ptr = (gdouble *) data;
gdouble new_val;
*ptr = atof (gtk_entry_get_text (GTK_ENTRY (entry)));
adjustment = gtk_object_get_user_data (GTK_OBJECT (entry));
if (adjustment)
{
new_val = *ptr < adjustment->lower ? adjustment->lower :
*ptr > adjustment->upper ? adjustment->upper : *ptr;
adjustment->value = new_val;
gtk_signal_handler_block_by_data (GTK_OBJECT (adjustment), data);
gtk_signal_emit_by_name (GTK_OBJECT (adjustment), "value_changed");
gtk_signal_handler_unblock_by_data (GTK_OBJECT (adjustment), data);
}
}

View File

@ -1,487 +0,0 @@
/**************************************************
* file: emboss/emboss.c
*
* Copyright (c) 1997 Eric L. Hernes (erich@rrnet.com)
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. The name of the author may not be used to endorse or promote products
* derived from this software withough specific prior written permission
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* $Id$
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <sys/types.h>
#include <libgimp/gimp.h>
#include <gtk/gtk.h>
#include "megawidget.h"
static mw_preview_t emboss_do_preview;
struct Grgb {
guint8 red;
guint8 green;
guint8 blue;
};
struct GRegion {
gint32 x;
gint32 y;
gint32 width;
gint32 height;
};
struct piArgs {
gint32 img;
gint32 drw;
gdouble azimuth;
gdouble elevation;
gint32 depth;
gint32 embossp;
};
struct embossFilter {
gdouble Lx;
gdouble Ly;
gdouble Lz;
gdouble Nz;
gdouble Nz2;
gdouble NzLz;
gdouble bg;
} Filter;
static void query(void);
static void run(gchar *name, gint nparam, GParam *param,
gint *nretvals, GParam **retvals);
int pluginCore(struct piArgs *argp);
int pluginCoreIA(struct piArgs *argp);
static inline void EmbossInit(gdouble azimuth, gdouble elevation,
gushort width45);
static inline void EmbossRow(guchar *src, guchar *texture, guchar *dst,
guint xSize, guint bypp, gint alpha);
#define DtoR(d) ((d)*(M_PI/(gdouble)180))
GPlugInInfo PLUG_IN_INFO = {
NULL, /* init */
NULL, /* quit */
query, /* query */
run, /* run */
};
static struct mwPreview *thePreview;
MAIN()
static void
query(void){
static GParamDef args[] = {
{ PARAM_INT32, "run_mode", "Interactive, non-interactive" },
{ PARAM_IMAGE, "img", "The Image" },
{ PARAM_DRAWABLE, "drw", "The Drawable" },
{ PARAM_FLOAT, "azimuth", "The Light Angle (degrees)" },
{ PARAM_FLOAT, "elevation", "The Elevation Angle (degrees)" },
{ PARAM_INT32, "depth", "The Filter Width" },
{ PARAM_INT32, "embossp", "Emboss or Bumpmap" },
};
static gint nargs = sizeof (args) / sizeof (args[0]);
static GParamDef *rets = NULL;
static gint nrets = 0;
gimp_install_procedure("plug_in_emboss",
"Emboss filter",
"Emboss or Bumpmap the given drawable, specifying the angle and elevation for the light source.",
"Eric L. Hernes, John Schlag",
"Eric L. Hernes",
"1997",
"<Image>/Filters/Distorts/Emboss",
"RGB",
PROC_PLUG_IN,
nargs, nrets,
args, rets);
}
static void
run(gchar *name, gint nparam, GParam *param,
gint *nretvals, GParam **retvals)
{
static GParam rvals[1];
struct piArgs args;
GDrawable *drw;
*nretvals = 1;
*retvals = rvals;
bzero(&args, sizeof(struct piArgs));
rvals[0].type = PARAM_STATUS;
rvals[0].data.d_status = STATUS_SUCCESS;
switch (param[0].data.d_int32)
{
case RUN_INTERACTIVE:
gimp_get_data("plug_in_emboss", &args);
if (args.img == 0 && args.drw == 0)
{
/* initial conditions */
args.azimuth = 30.0;
args.elevation = 45.0;
args.depth = 20;
args.embossp = 1;
}
args.img = param[1].data.d_image;
args.drw = param[2].data.d_drawable;
drw = gimp_drawable_get(args.drw);
thePreview = mw_preview_build(drw);
if (pluginCoreIA(&args)==-1)
{
rvals[0].data.d_status = STATUS_EXECUTION_ERROR;
}
else
{
gimp_set_data("plug_in_emboss", &args, sizeof(struct piArgs));
}
break;
case RUN_NONINTERACTIVE:
if (nparam != 7)
{
rvals[0].data.d_status = STATUS_CALLING_ERROR;
break;
}
args.img = param[1].data.d_image;
args.drw = param[2].data.d_drawable;
args.azimuth = param[3].data.d_float;
args.elevation = param[4].data.d_float;
args.depth = param[5].data.d_int32;
args.embossp = param[6].data.d_int32;
if (pluginCore(&args)==-1)
{
rvals[0].data.d_status = STATUS_EXECUTION_ERROR;
break;
}
break;
case RUN_WITH_LAST_VALS:
gimp_get_data("plug_in_emboss", &args);
if (pluginCore(&args)==-1) {
rvals[0].data.d_status = STATUS_EXECUTION_ERROR;
}
break;
}
}
#define pixelScale 255.9
void
EmbossInit(gdouble azimuth, gdouble elevation, gushort width45) {
/*
* compute the light vector from the input parameters.
* normalize the length to pixelScale for fast shading calculation.
*/
Filter.Lx = cos(azimuth) * cos(elevation) * pixelScale;
Filter.Ly = sin(azimuth) * cos(elevation) * pixelScale;
Filter.Lz = sin(elevation) * pixelScale;
/*
* constant z component of image surface normal - this depends on the
* image slope we wish to associate with an angle of 45 degrees, which
* depends on the width of the filter used to produce the source image.
*/
Filter.Nz = (6 * 255) / width45;
Filter.Nz2 = Filter.Nz * Filter.Nz;
Filter.NzLz = Filter.Nz * Filter.Lz;
/* optimization for vertical normals: L.[0 0 1] */
Filter.bg = Filter.Lz;
}
/*
* ANSI C code from the article
* "Fast Embossing Effects on Raster Image Data"
* by John Schlag, jfs@kerner.com
* in "Graphics Gems IV", Academic Press, 1994
*
*
* Emboss - shade 24-bit pixels using a single distant light source.
* Normals are obtained by differentiating a monochrome 'bump' image.
* The unary case ('texture' == NULL) uses the shading result as output.
* The binary case multiples the optional 'texture' image by the shade.
* Images are in row major order with interleaved color components (rgbrgb...).
* E.g., component c of pixel x,y of 'dst' is dst[3*(y*xSize + x) + c].
*
*/
void
EmbossRow(guchar *src, guchar *texture, guchar *dst,
guint xSize, guint bypp, gint alpha) {
glong Nx, Ny, NdotL;
guchar *s1, *s2, *s3;
gint x, shade, b;
gint bytes;
/* mung pixels, avoiding edge pixels */
s1 = src + bypp;
s2 = s1 + (xSize*bypp);
s3 = s2 + (xSize*bypp);
dst += bypp;
bytes = (alpha) ? bypp - 1 : bypp;
if (texture) texture += bypp;
for (x = 1; x < xSize-1; x++, s1+=bypp, s2+=bypp, s3+=bypp) {
/*
* compute the normal from the src map. the type of the
* expression before the cast is compiler dependent. in
* some cases the sum is unsigned, in others it is
* signed. ergo, cast to signed.
*/
Nx = (int)(s1[-bypp] + s2[-bypp] + s3[-bypp]
- s1[bypp] - s2[bypp] - s3[bypp]);
Ny = (int)(s3[-bypp] + s3[0] + s3[bypp] - s1[-bypp]
- s1[0] - s1[bypp]);
/* shade with distant light source */
if ( Nx == 0 && Ny == 0 )
shade = Filter.bg;
else if ( (NdotL = Nx*Filter.Lx + Ny*Filter.Ly + Filter.NzLz) < 0 )
shade = 0;
else
shade = NdotL / sqrt(Nx*Nx + Ny*Ny + Filter.Nz2);
/* do something with the shading result */
if ( texture ) {
for(b=0;b<bytes;b++) {
*dst++ = (*texture++ * shade) >> 8;
}
if (alpha) {
*dst++=s2[bytes]; /* preserve the alpha */
texture++;
}
}
else {
for(b=0;b<bytes;b++) {
*dst++ = shade;
}
if (alpha) *dst++=s2[bytes]; /* preserve the alpha */
}
}
if (texture) texture += bypp;
}
int pluginCore(struct piArgs *argp) {
GDrawable *drw;
GPixelRgn src, dst;
gint p_update;
gint y;
guint width, height;
gint bypp, rowsize, has_alpha;
guchar *srcbuf, *dstbuf;
drw=gimp_drawable_get(argp->drw);
width=drw->width;
height=drw->height;
bypp=drw->bpp;
p_update = height/20;
rowsize = width * bypp;
has_alpha = gimp_drawable_has_alpha (argp->drw);
gimp_pixel_rgn_init (&src, drw, 0, 0, width, height, FALSE, FALSE);
gimp_pixel_rgn_init (&dst, drw, 0, 0, width, height, TRUE, TRUE);
srcbuf=(guchar*)malloc(rowsize*3);
dstbuf=(guchar*)malloc(rowsize);
bzero(srcbuf, rowsize*3);
bzero(dstbuf, rowsize);
EmbossInit(DtoR(argp->azimuth), DtoR(argp->elevation), argp->depth);
gimp_progress_init("Emboss");
gimp_tile_cache_ntiles((width + gimp_tile_width() - 1) / gimp_tile_width());
/* first row */
gimp_pixel_rgn_get_rect(&src, srcbuf, 0, 0, width, 3);
bcopy(srcbuf+rowsize, srcbuf, rowsize);
EmbossRow(srcbuf, argp->embossp ? (guchar *)0 : srcbuf,
dstbuf, width, bypp, has_alpha);
gimp_pixel_rgn_set_row(&dst, dstbuf, 0, 0, width);
/* last row */
gimp_pixel_rgn_get_rect(&src, srcbuf, 0, height-3, width, 3);
bcopy(srcbuf+rowsize, srcbuf+rowsize*2, rowsize);
EmbossRow(srcbuf, argp->embossp ? (guchar *)0 : srcbuf,
dstbuf, width, bypp, has_alpha);
gimp_pixel_rgn_set_row(&dst, dstbuf, 0, height-1, width);
for(y=0 ;y<height-2; y++){
if (y%p_update==0) gimp_progress_update((gdouble)y/(gdouble)height);
gimp_pixel_rgn_get_rect(&src, srcbuf, 0, y, width, 3);
EmbossRow(srcbuf, argp->embossp ? (guchar *)0 : srcbuf,
dstbuf, width, bypp, has_alpha);
gimp_pixel_rgn_set_row(&dst, dstbuf, 0, y+1, width);
}
free(srcbuf);
free(dstbuf);
gimp_drawable_flush(drw);
gimp_drawable_merge_shadow (drw->id, TRUE);
gimp_drawable_update(drw->id, 0, 0, width, height);
gimp_displays_flush();
return 0;
}
int pluginCoreIA(struct piArgs *argp) {
GtkWidget *dlg;
GtkWidget *hbox;
GtkWidget *table;
GtkWidget *preview;
GtkWidget *frame;
gint runp;
struct mwRadioGroup functions[] = {
{ "Emboss", 0 },
{ "Bumpmap", 0 },
{ NULL, 0 },
};
functions[!argp->embossp].var = 1;
dlg = mw_app_new("plug_in_emboss", "Emboss", &runp);
hbox = gtk_hbox_new(FALSE, 5);
gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dlg)->vbox), hbox, TRUE, TRUE, 0);
gtk_widget_show(hbox);
preview = mw_preview_new(hbox, thePreview, &emboss_do_preview);
gtk_object_set_data(GTK_OBJECT(preview), "piArgs", argp);
gtk_object_set_data(GTK_OBJECT(preview), "mwRadioGroup", &functions);
emboss_do_preview(preview);
mw_radio_group_new(hbox, "Function", functions);
frame = gtk_frame_new("Parameters");
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);
gtk_widget_show(frame);
table = gtk_table_new(4, 2, FALSE);
gtk_container_border_width(GTK_CONTAINER (table), 5);
gtk_container_add(GTK_CONTAINER(frame), table);
mw_fscale_entry_new(table, "Azimuth", 0.0, 360.0, 1.0, 10.0, 0.0,
0, 1, 1, 2, &argp->azimuth);
mw_fscale_entry_new(table, "Elevation", 0.0, 180.0, 1.0, 10.0, 0.0,
0, 1, 2, 3, &argp->elevation);
mw_iscale_entry_new(table, "Depth", 1, 100, 1, 5, 0,
0, 1, 3, 4, &argp->depth);
gtk_widget_show(table);
gtk_widget_show(table);
gtk_widget_show(dlg);
gtk_main();
gdk_flush();
argp->embossp = !mw_radio_result(functions);
if(runp){
return pluginCore(argp);
} else {
return -1;
}
}
static void
emboss_do_preview(GtkWidget *w) {
static GtkWidget *theWidget = NULL;
struct piArgs *ap;
struct mwRadioGroup *rgp;
guchar *dst, *c;
gint y, rowsize;
if(theWidget==NULL){
theWidget=w;
}
ap = gtk_object_get_data(GTK_OBJECT(theWidget), "piArgs");
rgp = gtk_object_get_data(GTK_OBJECT(theWidget), "mwRadioGroup");
ap->embossp = !mw_radio_result(rgp);
rowsize=thePreview->width*thePreview->bpp;
dst = malloc(rowsize);
c = malloc(rowsize*3);
bcopy(thePreview->bits, c, rowsize);
bcopy(thePreview->bits, c+rowsize, rowsize*2);
EmbossInit(DtoR(ap->azimuth), DtoR(ap->elevation), ap->depth);
EmbossRow(c, ap->embossp ? (guchar *)0 : c,
dst, thePreview->width, thePreview->bpp, FALSE);
gtk_preview_draw_row(GTK_PREVIEW(theWidget),
dst, 0, 0, thePreview->width);
bcopy(thePreview->bits+((thePreview->height-2)*rowsize), c, rowsize*2);
bcopy(thePreview->bits+((thePreview->height-1)*rowsize),
c+(rowsize*2), rowsize);
EmbossRow(c, ap->embossp ? (guchar *)0 : c,
dst, thePreview->width, thePreview->bpp, FALSE);
gtk_preview_draw_row(GTK_PREVIEW(theWidget),
dst, 0, thePreview->height-1, thePreview->width);
free(c);
for(y=0, c=thePreview->bits;y<thePreview->height-2; y++, c+=rowsize){
EmbossRow(c, ap->embossp ? (guchar *)0 : c,
dst, thePreview->width, thePreview->bpp, FALSE);
gtk_preview_draw_row(GTK_PREVIEW(theWidget),
dst, 0, y, thePreview->width);
}
gtk_widget_draw(theWidget, NULL);
gdk_flush();
free(dst);
}
/*
* Local Variables:
* mode: C
* c-indent-level: 2
*
* End:
*/
/* end of file: emboss/emboss.c */

View File

@ -1,643 +0,0 @@
/* The GIMP -- an image manipulation program
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
* Copyright (C) 1997 Eiichi Takamori
* Copyright (C) 1996, 1997 Torsten Martinsen
*
* 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
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/*
* This plug-in creates a black-and-white 'engraved' version of an image.
* Much of the code is stolen from the Pixelize plug-in.
*/
#include <stdio.h>
#include <stdlib.h>
#include "gtk/gtk.h"
#include "libgimp/gimp.h"
/* Some useful macros */
#define ENTRY_WIDTH 60
#define SCALE_WIDTH 125
#define TILE_CACHE_SIZE 16
#define INTENSITY(r,g,b) (r * 0.30 + g * 0.59 + b * 0.11)
typedef struct {
gint height;
gint limit;
} EngraveValues;
typedef struct {
gint run;
} EngraveInterface;
static void query(void);
static void run(gchar * name,
gint nparams,
GParam * param,
gint * nreturn_vals,
GParam ** return_vals);
static gint engrave_dialog(void);
static void engrave_close_callback(GtkWidget * widget,
gpointer data);
static void engrave_ok_callback(GtkWidget * widget,
gpointer data);
static void engrave(GDrawable * drawable);
static void engrave_large(GDrawable * drawable, gint height, gint limit);
static void engrave_small(GDrawable * drawable, gint height, gint limit, gint tile_width);
static void engrave_sub(gint height, gint limit, gint bpp, gint color_n);
static void engrave_toggle_update (GtkWidget *widget,
gpointer data);
static void engrave_scale_update (GtkAdjustment *adjustment,
int *scale_val);
static void engrave_entry_update (GtkWidget *widget,
gint *value);
static void dialog_create_value (char *title,
GtkTable *table,
int row,
gint *value,
int left,
int right);
GPlugInInfo PLUG_IN_INFO =
{
NULL, /* init_proc */
NULL, /* quit_proc */
query, /* query_proc */
run, /* run_proc */
};
static EngraveValues pvals =
{
10
};
static EngraveInterface pint =
{
FALSE /* run */
};
MAIN()
static void
query()
{
static GParamDef args[] =
{
{PARAM_INT32, "run_mode", "Interactive, non-interactive"},
{PARAM_IMAGE, "image", "Input image (unused)"},
{PARAM_DRAWABLE, "drawable", "Input drawable"},
{PARAM_INT32, "height", "Resolution in pixels"},
{PARAM_INT32, "limit", "If true, limit line width"}
};
static GParamDef *return_vals = NULL;
static gint nargs = sizeof(args) / sizeof(args[0]);
static gint nreturn_vals = 0;
gimp_install_procedure("plug_in_engrave",
"Engrave the contents of the specified drawable",
"More help",
"Spencer Kimball & Peter Mattis, Eiichi Takamori, Torsten Martinsen",
"Spencer Kimball & Peter Mattis, Eiichi Takamori, Torsten Martinsen",
"1995,1996,1997",
"<Image>/Filters/Image/Engrave",
"RGB, GRAY",
PROC_PLUG_IN,
nargs, nreturn_vals,
args, return_vals);
}
static void
run(gchar * name,
gint nparams,
GParam * param,
gint * nreturn_vals,
GParam ** return_vals)
{
static GParam values[1];
GDrawable *drawable;
GRunModeType run_mode;
GStatusType status = STATUS_SUCCESS;
run_mode = param[0].data.d_int32;
*nreturn_vals = 1;
*return_vals = values;
values[0].type = PARAM_STATUS;
values[0].data.d_status = status;
/* Get the specified drawable */
drawable = gimp_drawable_get(param[2].data.d_drawable);
switch (run_mode) {
case RUN_INTERACTIVE:
/* Possibly retrieve data */
gimp_get_data("plug_in_engrave", &pvals);
/* First acquire information with a dialog */
if (!engrave_dialog()) {
gimp_drawable_detach(drawable);
return;
}
break;
case RUN_NONINTERACTIVE:
/* Make sure all the arguments are there! */
if (nparams != 5)
status = STATUS_CALLING_ERROR;
if (status == STATUS_SUCCESS) {
pvals.height = param[3].data.d_int32;
pvals.limit = (param[4].data.d_int32) ? TRUE : FALSE;
}
if ((status == STATUS_SUCCESS) &&
pvals.height < 0)
status = STATUS_CALLING_ERROR;
break;
case RUN_WITH_LAST_VALS:
/* Possibly retrieve data */
gimp_get_data("plug_in_engrave", &pvals);
break;
default:
break;
}
if (status == STATUS_SUCCESS) {
gimp_progress_init("Engraving...");
gimp_tile_cache_ntiles(TILE_CACHE_SIZE);
engrave(drawable);
if (run_mode != RUN_NONINTERACTIVE)
gimp_displays_flush();
/* Store data */
if (run_mode == RUN_INTERACTIVE)
gimp_set_data("plug_in_engrave", &pvals, sizeof(EngraveValues));
}
values[0].data.d_status = status;
gimp_drawable_detach(drawable);
}
static gint
engrave_dialog()
{
GtkWidget *dlg;
GtkWidget *frame;
GtkWidget *table;
GtkWidget *button;
GtkWidget *toggle;
gchar **argv;
gint argc;
argc = 1;
argv = g_new(gchar *, 1);
argv[0] = g_strdup("engrave");
gtk_init(&argc, &argv);
gtk_rc_parse(gimp_gtkrc());
dlg = gtk_dialog_new();
gtk_window_set_title(GTK_WINDOW(dlg), "Engrave");
gtk_window_position(GTK_WINDOW(dlg), GTK_WIN_POS_MOUSE);
gtk_signal_connect(GTK_OBJECT(dlg), "destroy",
(GtkSignalFunc) engrave_close_callback,
NULL);
/* Action area */
button = gtk_button_new_with_label("OK");
GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT);
gtk_signal_connect(GTK_OBJECT(button), "clicked",
(GtkSignalFunc) engrave_ok_callback,
dlg);
gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dlg)->action_area), button, TRUE, TRUE, 0);
gtk_widget_grab_default(button);
gtk_widget_show(button);
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));
gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dlg)->action_area), button, TRUE, TRUE, 0);
gtk_widget_show(button);
/* parameter settings */
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(2, 3, FALSE);
gtk_container_border_width(GTK_CONTAINER(table), 10);
gtk_container_add(GTK_CONTAINER(frame), table);
toggle = gtk_check_button_new_with_label ("Limit line width");
gtk_table_attach (GTK_TABLE (table), toggle, 0, 2, 0, 1, GTK_FILL, 0, 0, 0);
gtk_signal_connect (GTK_OBJECT (toggle), "toggled",
(GtkSignalFunc) engrave_toggle_update,
&pvals.limit);
gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (toggle), pvals.limit);
gtk_widget_show (toggle);
dialog_create_value("Height", GTK_TABLE(table), 1, &pvals.height, 2.0, 16.0);
gtk_widget_show(frame);
gtk_widget_show(table);
gtk_widget_show(dlg);
gtk_main();
gdk_flush();
return pint.run;
}
/* Engrave interface functions */
static void
engrave_close_callback(GtkWidget * widget,
gpointer data)
{
gtk_main_quit();
}
static void
engrave_ok_callback(GtkWidget * widget,
gpointer data)
{
pint.run = TRUE;
gtk_widget_destroy(GTK_WIDGET(data));
}
static void
engrave(GDrawable * drawable)
{
gint tile_width;
gint height;
gint limit;
tile_width = gimp_tile_width();
height = (gint) pvals.height;
limit = (gint) pvals.limit;
if (height >= tile_width)
engrave_large(drawable, height, limit);
else
engrave_small(drawable, height, limit, tile_width);
}
static void
engrave_large(GDrawable * drawable, gint height, gint limit)
{
GPixelRgn src_rgn, dest_rgn;
guchar *src_row, *dest_row;
guchar *src, *dest;
gulong *average;
gint row, col, b, bpp;
gint x, y, y_step, inten, v;
gulong count;
gint x1, y1, x2, y2;
gint progress, max_progress;
gpointer pr;
gimp_drawable_mask_bounds(drawable->id, &x1, &y1, &x2, &y2);
if (gimp_drawable_color(drawable->id))
bpp = 3;
else
bpp = 1;
average = g_new(gulong, bpp);
/* Initialize progress */
progress = 0;
max_progress = 2 * (x2 - x1) * (y2 - y1);
for (y = y1; y < y2; y += height - (y % height)) {
for (x = x1; x < x2; ++x) {
y_step = height - (y % height);
y_step = MIN(y_step, x2 - x);
gimp_pixel_rgn_init(&src_rgn, drawable, x, y, 1, y_step, FALSE, FALSE);
for (b = 0; b < bpp; b++)
average[b] = 0;
count = 0;
for (pr = gimp_pixel_rgns_register(1, &src_rgn);
pr != NULL;
pr = gimp_pixel_rgns_process(pr)) {
src_row = src_rgn.data;
for (row = 0; row < src_rgn.h; row++) {
src = src_row;
for (col = 0; col < src_rgn.w; col++) {
for (b = 0; b < bpp; b++)
average[b] += src[b];
src += src_rgn.bpp;
count += 1;
}
src_row += src_rgn.rowstride;
}
/* Update progress */
progress += src_rgn.w * src_rgn.h;
gimp_progress_update((double) progress / (double) max_progress);
}
if (count > 0)
for (b = 0; b < bpp; b++)
average[b] = (guchar) (average[b] / count);
if (bpp < 3)
inten = average[0]/254.0*height;
else
inten = INTENSITY(average[0],
average[1],
average[2])/254.0*height;
gimp_pixel_rgn_init(&dest_rgn, drawable, x, y, 1, y_step, TRUE, TRUE);
for (pr = gimp_pixel_rgns_register(1, &dest_rgn);
pr != NULL;
pr = gimp_pixel_rgns_process(pr)) {
dest_row = dest_rgn.data;
for (row = 0; row < dest_rgn.h; row++) {
dest = dest_row;
v = inten > row ? 255 : 0;
if (limit) {
if (row == 0)
v = 255;
else if (row == height-1)
v = 0;
}
for (b = 0; b < bpp; b++)
dest[b] = v;
dest_row += dest_rgn.rowstride;
}
/* Update progress */
progress += dest_rgn.w * dest_rgn.h;
gimp_progress_update((double) progress / (double) max_progress);
}
}
}
g_free(average);
/* update the engraved region */
gimp_drawable_flush(drawable);
gimp_drawable_merge_shadow(drawable->id, TRUE);
gimp_drawable_update(drawable->id, x1, y1, (x2 - x1), (y2 - y1));
}
typedef struct {
gint x, y, h;
gint width;
guchar *data;
} PixelArea;
PixelArea area;
static void
engrave_small(GDrawable * drawable, gint height, gint limit, gint tile_width)
{
GPixelRgn src_rgn, dest_rgn;
gint bpp, color_n;
gint x1, y1, x2, y2;
gint progress, max_progress;
/*
For speed efficiency, operates on PixelAreas, whose each width and
height are less than tile size.
If both ends of area cannot be divided by height ( as
x1%height != 0 etc.), operates on the remainder pixels.
*/
gimp_drawable_mask_bounds(drawable->id, &x1, &y1, &x2, &y2);
gimp_pixel_rgn_init(&src_rgn, drawable, x1, y1, x2 - x1, y2 - y1, FALSE, FALSE);
gimp_pixel_rgn_init(&dest_rgn, drawable, x1, y1, x2 - x1, y2 - y1, TRUE, TRUE);
/* Initialize progress */
progress = 0;
max_progress = (x2 - x1) * (y2 - y1);
bpp = drawable->bpp;
if (gimp_drawable_color(drawable->id))
color_n = 3;
else
color_n = 1;
area.width = (tile_width / height) * height;
area.data = g_new(guchar, (glong) bpp * area.width * area.width);
for (area.y = y1; area.y < y2;
area.y += area.width - (area.y % area.width)) {
area.h = area.width - (area.y % area.width);
area.h = MIN(area.h, y2 - area.y);
for (area.x = x1; area.x < x2; ++area.x) {
gimp_pixel_rgn_get_rect(&src_rgn, area.data, area.x, area.y, 1, area.h);
engrave_sub(height, limit, bpp, color_n);
gimp_pixel_rgn_set_rect(&dest_rgn, area.data, area.x, area.y, 1, area.h);
/* Update progress */
progress += area.h;
gimp_progress_update((double) progress / (double) max_progress);
}
}
g_free(area.data);
/* update the engraved region */
gimp_drawable_flush(drawable);
gimp_drawable_merge_shadow(drawable->id, TRUE);
gimp_drawable_update(drawable->id, x1, y1, (x2 - x1), (y2 - y1));
}
static void
engrave_sub(gint height, gint limit, gint bpp, gint color_n)
{
glong average[3]; /* color_n <= 3 */
gint y, h, inten, v;
guchar *buf_row, *buf;
gint row;
gint rowstride;
gint count;
gint i;
/*
Since there's so many nested FOR's,
put a few of them here...
*/
rowstride = bpp;
for (y = area.y; y < area.y + area.h; y += height - (y % height)) {
h = height - (y % height);
h = MIN(h, area.y + area.h - y);
for (i = 0; i < color_n; i++)
average[i] = 0;
count = 0;
/* Read */
buf_row = area.data + (y - area.y) * rowstride;
for (row = 0; row < h; row++) {
buf = buf_row;
for (i = 0; i < color_n; i++)
average[i] += buf[i];
count++;
buf_row += rowstride;
}
/* Average */
if (count > 0)
for (i = 0; i < color_n; i++)
average[i] /= count;
if (bpp < 3)
inten = average[0]/254.0*height;
else
inten = INTENSITY(average[0],
average[1],
average[2])/254.0*height;
/* Write */
buf_row = area.data + (y - area.y) * rowstride;
for (row = 0; row < h; row++) {
buf = buf_row;
v = inten > row ? 255 : 0;
if (limit) {
if (row == 0)
v = 255;
else if (row == height-1)
v = 0;
}
for (i = 0; i < color_n; i++)
buf[i] = v;
buf_row += rowstride;
}
}
}
static void
engrave_toggle_update (GtkWidget *widget,
gpointer data)
{
int *toggle_val;
toggle_val = (int *) data;
if (GTK_TOGGLE_BUTTON (widget)->active)
*toggle_val = TRUE;
else
*toggle_val = FALSE;
}
/*
* Thanks to Quartic for these.
*/
static void
dialog_create_value(char *title, GtkTable *table, int row, gint *value, int left, int 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,
1.0,
0.0);
gtk_signal_connect(GTK_OBJECT(scale_data), "value_changed",
(GtkSignalFunc) engrave_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), 0);
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, "%d", *value);
gtk_entry_set_text(GTK_ENTRY(entry), buf);
gtk_signal_connect(GTK_OBJECT(entry), "changed",
(GtkSignalFunc) engrave_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
engrave_entry_update(GtkWidget *widget, gint *value)
{
GtkAdjustment *adjustment;
gint new_value;
new_value = atoi(gtk_entry_get_text(GTK_ENTRY(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 */
}
static void
engrave_scale_update (GtkAdjustment *adjustment, gint *value)
{
GtkWidget *entry;
char buf[256];
if (*value != adjustment->value) {
*value = adjustment->value;
entry = gtk_object_get_user_data(GTK_OBJECT(adjustment));
sprintf(buf, "%d", *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 */
}

View File

@ -1,417 +0,0 @@
/*
* This is a plug-in for the GIMP.
*
* 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
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*
*/
/*
* Exchange one color with the other (settable threshold to convert from
* one color-shade to another...might do wonders on certain images, or be
* totally useless on others).
*
* Author: robert@experimental.net
*
* TODO:
* - preview (working on it already :)
* - threshold for each channel (not hard to implement, but really
* needs a preview window)
*
*/
#include <stdio.h>
#include <stdlib.h>
#include "libgimp/gimp.h"
#include "gtk/gtk.h"
/* big scales */
#define SCALE_WIDTH 225
/* datastructure to store parameters in */
typedef struct
{
guchar fromred, fromgreen, fromblue, tored, togreen, toblue;
guchar threshold;
gint32 image;
gint32 drawable;
} myParams;
/* lets prototype */
static void query();
static void run(char *, int, GParam *, int *, GParam **);
static int doDialog();
static void exchange(GDrawable *);
static void doLabelAndScale(char *, GtkWidget *, guchar *);
static void ok_callback(GtkWidget *, gpointer);
static void close_callback(GtkWidget *, gpointer);
static void scale_callback(GtkAdjustment *, gpointer);
/* some global variables */
myParams xargs = { 0, 0, 0, 0, 0, 0, 0, 0, 0 };
int running = 0;
/* lets declare what we want to do */
GPlugInInfo PLUG_IN_INFO =
{
NULL, /* init_proc */
NULL, /* quit_proc */
query, /* query_proc */
run, /* run_proc */
};
/* run program */
MAIN()
/* tell GIMP who we are */
static
void query()
{
static GParamDef args[] =
{
{ PARAM_INT32, "run_mode", "Interactive" },
{ PARAM_IMAGE, "image", "Input image" },
{ PARAM_DRAWABLE, "drawable", "Input drawable" },
{ PARAM_INT8, "fromred", "Red value (from)" },
{ PARAM_INT8, "fromgreen", "Green value (from)" },
{ PARAM_INT8, "fromblue", "Blue value (from)" },
{ PARAM_INT8, "tored", "Red value (to)" },
{ PARAM_INT8, "togreen", "Green value (to)" },
{ PARAM_INT8, "toblue", "Blue value (to)" },
{ PARAM_INT8, "threshold", "Threshold" },
};
static GParamDef *return_vals = NULL;
static int nargs = sizeof(args) / sizeof(args[0]);
static int nreturn_vals = 0;
gimp_install_procedure("plug_in_exchange",
"Color exchange",
"Exchange one color with another, optionally setting a threshold to convert from one shade to another",
"robert@experimental.net",
"robert@experimental.net",
"June 17th, 1997",
"<Image>/Filters/Image/Color exchange",
"RGB*",
PROC_PLUG_IN,
nargs, nreturn_vals,
args, return_vals);
}
/* main function */
static
void run(char *name, int nparams, GParam *param, int *nreturn_vals, GParam **return_vals)
{
static GParam values[1];
GRunModeType runmode;
GDrawable *drawable;
gint32 imageID;
GStatusType status = STATUS_SUCCESS;
*nreturn_vals = 1;
*return_vals = values;
values[0].type = PARAM_STATUS;
values[0].data.d_status = status;
switch (runmode = param[0].data.d_int32)
{
case RUN_INTERACTIVE:
/* retrieve stored arguments (if any) */
gimp_get_data("plug_in_exchange", &xargs);
/* initialize using foreground color */
gimp_palette_get_foreground(&xargs.fromred, &xargs.fromgreen, &xargs.fromblue);
if (!xargs.image && !xargs.drawable)
xargs.threshold = 0;
/* and initialize some other things */
xargs.image = param[1].data.d_image;
xargs.drawable = param[2].data.d_drawable;
if (!doDialog())
return;
break;
case RUN_WITH_LAST_VALS:
/*
* instead of recalling the last-set values,
* run with the current foreground as 'from'
* color, making ALT-F somewhat more useful.
*/
gimp_palette_get_foreground(&xargs.fromred, &xargs.fromgreen, &xargs.fromblue);
break;
case RUN_NONINTERACTIVE:
status = STATUS_EXECUTION_ERROR;
return;
default:
break;
}
/* Get the specified drawable */
drawable = gimp_drawable_get(param[2].data.d_drawable);
imageID = param[1].data.d_image;
if (status == STATUS_SUCCESS)
{
if (gimp_drawable_color(drawable->id))
{
gimp_progress_init("Color exchange...");
gimp_tile_cache_ntiles(2 * (drawable->width / gimp_tile_width() + 1));
exchange(drawable);
/* store our settings */
gimp_set_data("plug_in_exchange", &xargs, sizeof(myParams));
/* and flush */
gimp_displays_flush();
}
else
status = STATUS_EXECUTION_ERROR;
}
values[0].data.d_status = status;
gimp_drawable_detach(drawable);
}
/* do the exchanging */
static
void exchange(GDrawable *drawable)
{
GPixelRgn srcPR, destPR;
guchar *src_row;
guchar *dest_row;
gint width, height;
gint x, y, bpp;
gint x1, y1, x2, y2;
/*
* 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.
*/
width = drawable->width;
height = drawable->height;
bpp = drawable->bpp;
/* allocate row buffers */
src_row = (guchar *) malloc((x2 - x1) * bpp);
dest_row = (guchar *) malloc((x2 - x1) * bpp);
/* 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);
for (y = y1; y < y2; y++)
{
gimp_pixel_rgn_get_row(&srcPR, src_row, x1, y, (x2 - x1));
for (x = x1; x < x2; x++)
{
guchar red, green, blue,
minred, mingreen, minblue,
maxred, maxgreen, maxblue;
int rest, wanted = 0,
redx = 0, greenx = 0, bluex = 0;
/* get boundary values */
minred = MAX((int) xargs.fromred - xargs.threshold, 0);
mingreen = MAX((int) xargs.fromgreen - xargs.threshold, 0);
minblue = MAX((int) xargs.fromblue - xargs.threshold, 0);
maxred = MIN((int) xargs.fromred + xargs.threshold, 255);
maxgreen = MIN((int) xargs.fromgreen + xargs.threshold, 255);
maxblue = MIN((int) xargs.fromblue + xargs.threshold, 255);
/* get current pixel values */
red = src_row[x * bpp];
green = src_row[x * bpp + 1];
blue = src_row[x * bpp + 2];
/*
* check if we want this pixel (does it fall between
* our boundary?)
*/
if (red >= minred && red <= maxred &&
green >= mingreen && green <= maxgreen &&
blue >= minblue && blue <= maxblue)
{
redx = red - xargs.fromred;
greenx = green - xargs.fromgreen;
bluex = blue - xargs.fromblue;
wanted = 1;
}
/* exchange if needed */
dest_row[x * bpp] = wanted ? MAX(MIN(xargs.tored + redx, 255), 0) : src_row[x * bpp];
dest_row[x * bpp + 1] = wanted ? MAX(MIN(xargs.togreen + greenx, 255), 0) : src_row[x * bpp + 1];
dest_row[x * bpp + 2] = wanted ? MAX(MIN(xargs.toblue + bluex, 255), 0) : src_row[x * bpp + 2];
/* copy rest (most likely alpha-channel) */
for (rest = 3; rest < bpp; rest++)
dest_row[x * bpp + rest] = src_row[x * bpp + rest];
}
/* store the dest */
gimp_pixel_rgn_set_row(&destPR, dest_row, x1, y, (x2 - x1));
/* and tell the user what we're doing */
if ((y % 10) == 0)
gimp_progress_update((double) y / (double) (y2 - y1));
}
/* update the processed region */
gimp_drawable_flush(drawable);
gimp_drawable_merge_shadow(drawable->id, TRUE);
gimp_drawable_update(drawable->id, x1, y1, (x2 - x1), (y2 - y1));
/* and clean up */
free(src_row);
free(dest_row);
}
/* show our dialog */
static
int doDialog()
{
GtkWidget *dialog;
GtkWidget *button;
GtkWidget *frame;
GtkWidget *table;
GtkWidget *mainbox;
GtkWidget *tobox;
GtkWidget *frombox;
gchar **argv;
gint argc;
int framenumber;
argc = 1;
argv = g_new(gchar *, 1);
argv[0] = g_strdup("exchange");
gtk_init(&argc, &argv);
/* set up the dialog */
dialog = gtk_dialog_new();
gtk_window_set_title(GTK_WINDOW(dialog), "Color Exchange");
gtk_window_position(GTK_WINDOW(dialog), GTK_WIN_POS_MOUSE);
gtk_signal_connect(GTK_OBJECT(dialog), "destroy",
(GtkSignalFunc) close_callback,
NULL);
/* lets create some buttons */
button = gtk_button_new_with_label("Ok");
GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT);
gtk_signal_connect(GTK_OBJECT(button), "clicked",
(GtkSignalFunc) ok_callback,
dialog);
gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->action_area),
button, TRUE, TRUE, 0);
gtk_widget_grab_default(button);
gtk_widget_show(button);
button = gtk_button_new_with_label("Cancel");
GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT);
gtk_signal_connect(GTK_OBJECT(button), "clicked",
(GtkSignalFunc) close_callback,
dialog);
gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->action_area),
button, TRUE, TRUE, 0);
gtk_widget_show(button);
/* do some boxes here */
mainbox = gtk_vbox_new(FALSE, 5);
gtk_container_border_width(GTK_CONTAINER(mainbox), 10);
gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), mainbox, TRUE, TRUE, 0);
frombox = gtk_hbox_new(FALSE, 5);
gtk_container_border_width(GTK_CONTAINER(frombox), 10);
gtk_box_pack_start(GTK_BOX(mainbox), frombox, TRUE, TRUE, 0);
tobox = gtk_hbox_new(FALSE, 5);
gtk_container_border_width(GTK_CONTAINER(tobox), 10);
gtk_box_pack_start(GTK_BOX(mainbox), tobox, TRUE, TRUE, 0);
/* and our scales */
for (framenumber = 0; framenumber < 2; framenumber++)
{
frame = gtk_frame_new(framenumber ? "To color" : "From color");
gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_ETCHED_IN);
gtk_container_border_width(GTK_CONTAINER(frame), 10);
gtk_box_pack_start(framenumber ? GTK_BOX(tobox) : GTK_BOX(frombox),
frame, TRUE, TRUE, 0);
gtk_widget_show(frame);
table = gtk_table_new(8, 2, FALSE);
gtk_container_border_width(GTK_CONTAINER(table), 10);
gtk_container_add(GTK_CONTAINER(frame), table);
doLabelAndScale("Red", table, framenumber ? &xargs.tored : &xargs.fromred);
doLabelAndScale("Green", table, framenumber ? &xargs.togreen : &xargs.fromgreen);
doLabelAndScale("Blue", table, framenumber ? &xargs.toblue : &xargs.fromblue);
if (!framenumber)
doLabelAndScale("Threshold", table, &xargs.threshold);
gtk_widget_show(table);
}
/* show everything */
gtk_widget_show(tobox);
gtk_widget_show(frombox);
gtk_widget_show(mainbox);
gtk_widget_show(dialog);
gtk_main();
gdk_flush();
return running;
}
static
void doLabelAndScale(char *labelname, GtkWidget *table, guchar *dest)
{
static int idx = -1;
GtkWidget *label, *scale;
GtkObject *scale_data;
idx++;
label = gtk_label_new(labelname);
gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
gtk_table_attach(GTK_TABLE(table), label, 0, 1, idx, idx + 1, GTK_FILL, 0, 5, 0);
scale_data = gtk_adjustment_new(*dest, 0.0, 255.0, 0.0, 0.0, 0.0);
scale = gtk_hscale_new(GTK_ADJUSTMENT(scale_data));
gtk_widget_set_usize(scale, SCALE_WIDTH, 0);
/* just need 1:1 resolution on scales */
gtk_scale_set_digits(GTK_SCALE(scale), 0);
gtk_table_attach(GTK_TABLE(table), scale, 1, 2, idx, idx + 1, GTK_FILL, 0, 0, 0);
gtk_scale_set_value_pos(GTK_SCALE(scale), GTK_POS_TOP);
gtk_range_set_update_policy(GTK_RANGE(scale), GTK_UPDATE_DELAYED);
gtk_signal_connect(GTK_OBJECT(scale_data), "value_changed",
(GtkSignalFunc) scale_callback,
dest);
gtk_widget_show(label);
gtk_widget_show(scale);
}
static
void ok_callback(GtkWidget *widget, gpointer data)
{
running = 1;
gtk_widget_destroy(GTK_WIDGET(data));
}
static
void close_callback(GtkWidget *widget, gpointer data)
{
gtk_main_quit();
}
static
void scale_callback(GtkAdjustment *adj, gpointer data)
{
guchar *val = data;
*val = (guchar) adj->value;
}

View File

@ -1,468 +0,0 @@
/*
* This is a plugin for the GIMP.
*
* Copyright (C) 1997 Jochen Friedrich
* Parts Copyright (C) 1995 Gert Doering
* Parts Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* 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
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
#define VERSION "0.6"
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <gtk/gtk.h>
#include <libgimp/gimp.h>
#include "g3.h"
/* Declare local functions.
*/
gint32 emitgimp (int, int, char *, int, char *);
static void query (void);
static void run (char *name,
int nparams,
GParam *param,
int *nreturn_vals,
GParam **return_vals);
static gint32 load_image (char *);
GPlugInInfo PLUG_IN_INFO =
{
NULL, /* init_proc */
NULL, /* quit_proc */
query, /* query_proc */
run, /* run_proc */
};
MAIN ()
static void query ()
{
static GParamDef load_args[] =
{
{ PARAM_INT32, "run_mode", "Interactive, non-interactive" },
{ PARAM_STRING, "filename", "The name of the file to load" },
{ PARAM_STRING, "raw_filename", "The name of the file to load" },
};
static GParamDef load_return_vals[] =
{
{ PARAM_IMAGE, "image", "Output image" },
};
static int nload_args = sizeof (load_args) / sizeof (load_args[0]);
static int nload_return_vals = sizeof (load_return_vals) / sizeof (load_return_vals[0]);
gimp_install_procedure ("file_faxg3_load",
"loads g3 fax files",
"This plug-in loads Fax G3 Image files.",
"Jochen Friedrich",
"Jochen Friedrich, Gert Doering, Spencer Kimball & Peter Mattis",
VERSION,
"<Load>/Fax G3",
NULL,
PROC_PLUG_IN,
nload_args, nload_return_vals,
load_args, load_return_vals);
gimp_register_magic_load_handler ("file_faxg3_load", "g3", "", "0,short,0x0001,0,short,0x0014");
}
static void run (char *name,
int nparams,
GParam *param,
int *nreturn_vals,
GParam **return_vals)
{
static GParam values[2];
GRunModeType run_mode;
GStatusType status = STATUS_SUCCESS;
gint32 image_ID;
run_mode = param[0].data.d_int32;
*nreturn_vals = 1;
*return_vals = values;
values[0].type = PARAM_STATUS;
values[0].data.d_status = STATUS_CALLING_ERROR;
if (strcmp (name, "file_faxg3_load") == 0)
{
*nreturn_vals = 2;
image_ID = load_image (param[1].data.d_string);
values[1].type = PARAM_IMAGE;
values[1].data.d_image = image_ID;
if (image_ID != -1)
{
values[0].data.d_status = STATUS_SUCCESS;
}
else
{
values[0].data.d_status = STATUS_EXECUTION_ERROR;
}
}
}
#ifdef DEBUG
void putbin (unsigned long d )
{
unsigned long i = 0x80000000;
while ( i!=0 )
{
putc( ( d & i ) ? '1' : '0', stderr );
i >>= 1;
}
putc( '\n', stderr );
}
#endif
static int byte_tab[ 256 ];
static int o_stretch; /* -stretch: double each line */
static int o_stretch_force=-1; /* -1: guess from filename */
static int o_lj; /* -l: LJ output */
static int o_turn; /* -t: turn 90 degrees right */
struct g3_tree * black, * white;
#define CHUNK 2048;
static char rbuf[2048]; /* read buffer */
static int rp; /* read pointer */
static int rs; /* read buffer size */
#define MAX_ROWS 4300
#define MAX_COLS 1728 /* !! FIXME - command line parameter */
static gint32
load_image (char *filename)
{
gint32 image_ID;
int data;
int hibit;
struct g3_tree * p;
int nr_pels;
int fd;
int color;
int i, rr, rsize;
int cons_eol;
int bperrow = MAX_COLS/8; /* bytes per bit row */
char *bitmap; /* MAX_ROWS by (bperrow) bytes */
char *bp; /* bitmap pointer */
char *name;
int row;
int max_rows; /* max. rows allocated */
int col, hcol; /* column, highest column ever used */
name = (char *) malloc (strlen (filename) + 12);
sprintf (name, "Loading %s:", filename);
gimp_progress_init (name);
free (name);
/* initialize lookup trees */
build_tree( &white, t_white );
build_tree( &white, m_white );
build_tree( &black, t_black );
build_tree( &black, m_black );
init_byte_tab( 0, byte_tab );
fd = open(filename, O_RDONLY );
hibit = 0;
data = 0;
cons_eol = 0; /* consecutive EOLs read - zero yet */
color = 0; /* start with white */
rr = 0;
rsize = lseek(fd, 0L, SEEK_END);
lseek(fd, 0L, 0);
rs = read( fd, rbuf, sizeof(rbuf) );
if ( rs < 0 ) { perror( "read" ); close( rs ); exit(8); }
rr += rs;
gimp_progress_update ((float)rr/rsize/2.0);
/* skip GhostScript header */
rp = ( rs >= 64 && strcmp( rbuf+1, "PC Research, Inc" ) == 0 ) ? 64 : 0;
/* initialize bitmap */
row = col = hcol = 0;
bitmap = (char *) malloc( ( max_rows = MAX_ROWS ) * MAX_COLS / 8 );
if ( bitmap == NULL )
{
fprintf( stderr, "cannot allocate %d bytes for bitmap",
max_rows * MAX_COLS/8 );
close( fd );
exit(9);
}
memset( bitmap, 0, max_rows * MAX_COLS/8 );
bp = &bitmap[ row * MAX_COLS/8 ];
while ( rs > 0 && cons_eol < 4 ) /* i.e., while (!EOF) */
{
#ifdef DEBUG
fprintf( stderr, "hibit=%2d, data=", hibit );
putbin( data );
#endif
while ( hibit < 20 )
{
data |= ( byte_tab[ (int) (unsigned char) rbuf[ rp++] ] << hibit );
hibit += 8;
if ( rp >= rs )
{
rs = read( fd, rbuf, sizeof( rbuf ) );
if ( rs < 0 ) { perror( "read2"); break; }
rr += rs;
gimp_progress_update ((float)rr/rsize/2.0);
rp = 0;
if ( rs == 0 ) { goto do_write; }
}
#ifdef DEBUG
fprintf( stderr, "hibit=%2d, data=", hibit );
putbin( data );
#endif
}
if ( color == 0 ) /* white */
p = white->nextb[ data & BITM ];
else /* black */
p = black->nextb[ data & BITM ];
while ( p != NULL && ! ( p->nr_bits ) )
{
data >>= FBITS;
hibit -= FBITS;
p = p->nextb[ data & BITM ];
}
if ( p == NULL ) /* invalid code */
{
fprintf( stderr, "invalid code, row=%d, col=%d, file offset=%lx, skip to eol\n",
row, col, (unsigned long) lseek( fd, 0, 1 ) - rs + rp );
while ( ( data & 0x03f ) != 0 )
{
data >>= 1; hibit--;
if ( hibit < 20 )
{
data |= ( byte_tab[ (int) (unsigned char) rbuf[ rp++] ] << hibit );
hibit += 8;
if ( rp >= rs ) /* buffer underrun */
{ rs = read( fd, rbuf, sizeof( rbuf ) );
if ( rs < 0 ) { perror( "read4"); break; }
rr += rs;
gimp_progress_update ((float)rr/rsize/2.0);
rp = 0;
if ( rs == 0 ) goto do_write;
}
}
}
nr_pels = -1; /* handle as if eol */
}
else /* p != NULL <-> valid code */
{
data >>= p->nr_bits;
hibit -= p->nr_bits;
nr_pels = ( (struct g3_leaf *) p ) ->nr_pels;
#ifdef DEBUG
fprintf( stderr, "PELs: %d (%c)\n", nr_pels, '0'+color );
#endif
}
/* handle EOL (including fill bits) */
if ( nr_pels == -1 )
{
#ifdef DEBUG
fprintf( stderr, "hibit=%2d, data=", hibit );
putbin( data );
#endif
/* skip filler 0bits -> seek for "1"-bit */
while ( ( data & 0x01 ) != 1 )
{
if ( ( data & 0xf ) == 0 ) /* nibble optimization */
{
hibit-= 4; data >>= 4;
}
else
{
hibit--; data >>= 1;
}
/* fill higher bits */
if ( hibit < 20 )
{
data |= ( byte_tab[ (int) (unsigned char) rbuf[ rp++] ] << hibit );
hibit += 8;
if ( rp >= rs ) /* buffer underrun */
{ rs = read( fd, rbuf, sizeof( rbuf ) );
if ( rs < 0 ) { perror( "read3"); break; }
rr += rs;
gimp_progress_update ((float)rr/rsize/2.0);
rp = 0;
if ( rs == 0 ) goto do_write;
}
}
#ifdef DEBUG
fprintf( stderr, "hibit=%2d, data=", hibit );
putbin( data );
#endif
} /* end skip 0bits */
hibit--; data >>=1;
color=0;
if ( col == 0 )
cons_eol++; /* consecutive EOLs */
else
{
if ( col > hcol && col <= MAX_COLS ) hcol = col;
row++;
/* bitmap memory full? make it larger! */
if ( row >= max_rows )
{
char * p = (char *) realloc( bitmap,
( max_rows += 500 ) * MAX_COLS/8 );
if ( p == NULL )
{
perror( "realloc() failed, page truncated" );
rs = 0;
}
else
{
bitmap = p;
memset( &bitmap[ row * MAX_COLS/8 ], 0,
( max_rows - row ) * MAX_COLS/8 );
}
}
col=0; bp = &bitmap[ row * MAX_COLS/8 ];
cons_eol = 0;
}
}
else /* not eol */
{
if ( col+nr_pels > MAX_COLS ) nr_pels = MAX_COLS - col;
if ( color == 0 ) /* white */
col += nr_pels;
else /* black */
{
register int bit = ( 0x80 >> ( col & 07 ) );
register char *w = & bp[ col>>3 ];
for ( i=nr_pels; i > 0; i-- )
{
*w |= bit;
bit >>=1; if ( bit == 0 ) { bit = 0x80; w++; }
col++;
}
}
if ( nr_pels < 64 ) color = !color; /* terminating code */
}
} /* end main loop */
do_write: /* write pbm (or whatever) file */
if( fd != 0 ) close(fd); /* close input file */
#ifdef DEBUG
fprintf( stderr, "consecutive EOLs: %d, max columns: %d\n", cons_eol, hcol );
#endif
return emitgimp(hcol, row, bitmap, bperrow, filename );
}
/* hcol is the number of columns, row the number of rows
* bperrow is the number of bytes actually used by hcol, which may
* be greater than (hcol+7)/8 [in case of an unscaled g3 image less
* than 1728 pixels wide]
*/
gint32 emitgimp ( int hcol, int row, char *bitmap, int bperrow, char *filename )
{
GPixelRgn pixel_rgn;
GDrawable *drawable;
gint32 image_ID;
gint32 layer_ID;
guchar *buf;
guchar tmp;
int x,y,xx,yy,tile_height;
#ifdef DEBUG
fprintf( stderr, "emit gimp: %d x %d\n", hcol, row);
#endif
image_ID = gimp_image_new (hcol, row, GRAY);
gimp_image_set_filename (image_ID, filename);
layer_ID = gimp_layer_new (image_ID, "Background",
hcol,
row,
GRAY_IMAGE, 100, NORMAL_MODE);
gimp_image_add_layer (image_ID, layer_ID, 0);
drawable = gimp_drawable_get (layer_ID);
gimp_pixel_rgn_init (&pixel_rgn, drawable, 0, 0, drawable->width, drawable->height, TRUE, FALSE);
tile_height = gimp_tile_height ();
#ifdef DEBUG
fprintf( stderr, "tile height: %d\n", tile_height);
#endif
buf = g_new(guchar, hcol*tile_height);
xx=0;
yy=0;
for (y=0; y<row; y++) {
for (x=0; x<hcol; x++) {
if ((x&7)==0) tmp = bitmap[y*bperrow+(x>>3)];
buf[xx++]=tmp&(128>>(x&7))?0:255;
}
if ((y-yy) == tile_height-1) {
#ifdef DEBUG
fprintf( stderr, "update tile height: %d\n", tile_height);
#endif
gimp_pixel_rgn_set_rect (&pixel_rgn, buf, 0, yy, hcol, tile_height);
gimp_progress_update (0.5+(float)y/row/2.0);
xx=0;
yy += tile_height;
}
}
if (row-yy) {
#ifdef DEBUG
fprintf( stderr, "update rest: %d\n", row-yy);
#endif
gimp_pixel_rgn_set_rect (&pixel_rgn, buf, 0, yy, hcol, row-yy);
}
gimp_progress_update (1.0);
g_free (buf);
gimp_drawable_flush (drawable);
return image_ID;
}

View File

@ -1,442 +0,0 @@
/* The GIMP -- an image manipulation program * Copyright (C) 1995 Spencer
* Kimball and Peter Mattis * * 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 * the Free Software Foundation; either
* version 2 of the License, or * (at your option) any later version. * *
* This program is distributed in the hope that it will be useful, * but
* WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU
* General Public License for more details. * * 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., 675 Mass Ave, Cambridge, MA
* 02139, USA. */
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include "libgimp/gimp.h"
#include "gtk/gtk.h"
/* Declare local functions. */
static void query(void);
static void run(char *name,
int nparams,
GParam * param,
int *nreturn_vals,
GParam ** return_vals);
static gint dialog();
static void doit(GDrawable * drawable);
GPlugInInfo PLUG_IN_INFO =
{
NULL, /* init_proc */
NULL, /* quit_proc */
query, /* query_proc */
run, /* run_proc */
};
gint bytes;
gint sx1, sy1, sx2, sy2;
int run_flag = 0;
typedef struct {
gint min_width, max_width;
gint min_height, max_height;
float density;
} config;
config my_config =
{
10, 30, /* min_width, max_width */
10, 30, /* min_height, max_height */
4 /* density */
};
MAIN()
static void query()
{
static GParamDef args[] =
{
{PARAM_INT32, "run_mode", "Interactive, non-interactive"},
{PARAM_IMAGE, "image", "Input image (unused)"},
{PARAM_DRAWABLE, "drawable", "Input drawable"},
{PARAM_FLOAT, "density", "Density"},
{PARAM_INT32, "min_width", "Min. width"},
{PARAM_INT32, "max_width", "Max. width"},
{PARAM_INT32, "min_height", "Min. height"},
{PARAM_INT32, "max_height", "Max. height"},
};
static GParamDef *return_vals = NULL;
static int nargs = sizeof(args) / sizeof(args[0]);
static int nreturn_vals = 0;
gimp_install_procedure("plug_in_figures",
"Draws lots of rectangles.",
"Can be nice to use as \"textures\".",
"Tim Newsome",
"Tim Newsome",
"1997",
"<Image>/Filters/Render/Figures",
"RGB*, GRAY*",
PROC_PLUG_IN,
nargs, nreturn_vals,
args, return_vals);
}
static void run(char *name, int n_params, GParam * param, int *nreturn_vals,
GParam ** return_vals)
{
static GParam values[1];
GDrawable *drawable;
GRunModeType run_mode;
GStatusType status = STATUS_SUCCESS;
*nreturn_vals = 1;
*return_vals = values;
run_mode = param[0].data.d_int32;
if (run_mode == RUN_NONINTERACTIVE) {
if (n_params != 8) {
status = STATUS_CALLING_ERROR;
} else {
my_config.density = param[3].data.d_float;
my_config.min_width = param[4].data.d_int32;
my_config.max_width = param[5].data.d_int32;
my_config.min_height = param[6].data.d_int32;
my_config.max_height = param[7].data.d_int32;
}
} else {
/* Possibly retrieve data */
gimp_get_data("plug_in_figures", &my_config);
if (run_mode == RUN_INTERACTIVE) {
/* Oh boy. We get to do a dialog box, because we can't really expect the
* user to set us up with the right values using gdb.
*/
if (!dialog()) {
/* The dialog was closed, or something similarly evil happened. */
status = STATUS_EXECUTION_ERROR;
}
}
}
if (status == STATUS_SUCCESS) {
/* 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("Drawing Figures...");
gimp_tile_cache_ntiles(2 * (drawable->width / gimp_tile_width() + 1));
srand(time(NULL));
doit(drawable);
if (run_mode != RUN_NONINTERACTIVE)
gimp_displays_flush();
if (run_mode == RUN_INTERACTIVE)
gimp_set_data("plug_in_figures", &my_config, sizeof(my_config));
} else {
status = STATUS_EXECUTION_ERROR;
}
gimp_drawable_detach(drawable);
}
values[0].type = PARAM_STATUS;
values[0].data.d_status = status;
}
/*
* Draws a rectangle in region, using tmp as tempspace, with center x, y,
* width w, height h, with color color, and opaqueness a.
*/
static void draw_rectangle(guchar * tmp, GPixelRgn * region, int x, int y,
int w, int h, guchar color[], float a)
{
int i, j, k;
int rx1, rx2, ry1, ry2;
rx1 = x - w / 2;
rx2 = rx1 + w;
ry1 = y - h / 2;
ry2 = ry1 + h;
rx1 = rx1 < sx1 ? sx1 : rx1;
ry1 = ry1 < sy1 ? sy1 : ry1;
rx2 = rx2 > sx2 ? sx2 : rx2;
ry2 = ry2 > sy2 ? sy2 : ry2;
gimp_pixel_rgn_get_rect(region, tmp, rx1, ry1, rx2 - rx1, ry2 - ry1);
for (j = 0; j < (rx2 - rx1); j++) {
for (k = 0; k < (ry2 - ry1); k++) {
for (i = 0; i < bytes; i++) {
tmp[(j + (rx2 - rx1) * k) * bytes + i] =
(float) tmp[(j + (rx2 - rx1) * k) * bytes + i] * (1 - a) +
(float) color[i] * a;
}
}
}
gimp_pixel_rgn_set_rect(region, tmp, rx1, ry1, rx2 - rx1, ry2 - ry1);
}
static void doit(GDrawable * drawable)
{
GPixelRgn srcPR, destPR;
gint width, height;
int x, y, w, h;
int i, j;
guchar *tmp, *copybuf;
guchar color[4];
int objects;
/* 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, &sx1, &sy1, &sx2, &sy2);
/* Get the size of the input image. (This will/must be the same
* as the size of the output image.
*/
width = drawable->width;
height = drawable->height;
bytes = drawable->bpp;
tmp = (guchar *) malloc(my_config.max_width * my_config.max_height * bytes);
if (tmp == NULL) {
return;
}
/* 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);
/* First off, copy the old one to the new one. */
copybuf = malloc(width * bytes);
for (i = sy1; i < sy2; i++) {
gimp_pixel_rgn_get_row(&srcPR, copybuf, sx1, i, width);
gimp_pixel_rgn_set_row(&destPR, copybuf, sx1, i, width);
}
free(copybuf);
objects = my_config.density * (float) (width * height) /
(float) (((my_config.min_width + my_config.max_width) / 2) *
((my_config.min_height + my_config.max_height)) / 2);
for (i = 0; i < objects; i++) {
w = my_config.min_width + rand() * (double) (my_config.max_width -
my_config.min_width) / (double) RAND_MAX;
h = my_config.min_height + rand() * (double) (my_config.max_height -
my_config.min_height) / (double) RAND_MAX;
x = sx1 + rand() * (double) width / (double) RAND_MAX;
y = sy1 + rand() * (double) height / (double) RAND_MAX;
for (j = 0; j < bytes; j++) {
color[j] = rand() * 255. / (double) RAND_MAX;
}
draw_rectangle(tmp, &destPR, x, y, w, h, color,
rand() / (double) RAND_MAX);
if (!(i % 64)) {
gimp_progress_update((double) i / (double) objects);
}
}
/* update the timred region */
gimp_drawable_flush(drawable);
gimp_drawable_merge_shadow(drawable->id, TRUE);
gimp_drawable_update(drawable->id, sx1, sy1, sx2 - sx1, sy2 - sy1);
}
/***************************************************
* GUI stuff
*/
static void close_callback(GtkWidget * widget, gpointer data)
{
gtk_main_quit();
}
static void ok_callback(GtkWidget * widget, gpointer data)
{
run_flag = 1;
gtk_widget_destroy(GTK_WIDGET(data));
}
static void entry_callback(GtkWidget * widget, gpointer data)
{
if (data == &my_config.density)
my_config.density = atof(gtk_entry_get_text(GTK_ENTRY(widget)));
else if (data == &my_config.min_width)
my_config.min_width = atoi(gtk_entry_get_text(GTK_ENTRY(widget)));
else if (data == &my_config.max_width)
my_config.max_width = atoi(gtk_entry_get_text(GTK_ENTRY(widget)));
else if (data == &my_config.min_height)
my_config.min_height = atoi(gtk_entry_get_text(GTK_ENTRY(widget)));
else if (data == &my_config.max_height)
my_config.max_height = atoi(gtk_entry_get_text(GTK_ENTRY(widget)));
}
static gint dialog()
{
GtkWidget *dlg;
GtkWidget *button;
GtkWidget *label;
GtkWidget *entry;
GtkWidget *table;
gchar buffer[12];
gchar **argv;
gint argc;
argc = 1;
argv = g_new(gchar *, 1);
argv[0] = g_strdup("plasma");
gtk_init(&argc, &argv);
gtk_rc_parse (gimp_gtkrc ());
dlg = gtk_dialog_new();
gtk_window_set_title(GTK_WINDOW(dlg), "Figures");
gtk_window_position(GTK_WINDOW(dlg), GTK_WIN_POS_MOUSE);
gtk_signal_connect(GTK_OBJECT(dlg), "destroy",
(GtkSignalFunc) close_callback, NULL);
/* Action area */
button = gtk_button_new_with_label("OK");
GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT);
gtk_signal_connect(GTK_OBJECT(button), "clicked",
(GtkSignalFunc) ok_callback,
dlg);
gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dlg)->action_area), button, TRUE, TRUE, 0);
gtk_widget_grab_default(button);
gtk_widget_show(button);
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));
gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dlg)->action_area), button, TRUE, TRUE, 0);
gtk_widget_show(button);
/* The main table */
/* Set its size (y, x) */
table = gtk_table_new(5, 3, FALSE);
gtk_container_border_width(GTK_CONTAINER(table), 10);
gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dlg)->vbox), table, TRUE, TRUE, 0);
gtk_widget_show(table);
gtk_table_set_row_spacings(GTK_TABLE(table), 10);
gtk_table_set_col_spacings(GTK_TABLE(table), 10);
/*********************
* The density entry *
*********************/
label = gtk_label_new("Density:");
gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
gtk_table_attach(GTK_TABLE(table), label, 0, 1, 1, 2, GTK_FILL, GTK_FILL, 0,
0);
gtk_widget_show(label);
entry = gtk_entry_new();
gtk_table_attach(GTK_TABLE(table), entry, 1, 3, 1, 2,
GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
gtk_widget_set_usize(entry, 50, 0);
sprintf(buffer, "%0.2f", my_config.density);
gtk_entry_set_text(GTK_ENTRY(entry), buffer);
gtk_signal_connect(GTK_OBJECT(entry), "changed",
(GtkSignalFunc) entry_callback,
&my_config.density);
gtk_widget_show(entry);
/**********************
* The min/max labels *
**********************/
label = gtk_label_new("Min.");
gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
gtk_table_attach(GTK_TABLE(table), label, 1, 2, 2, 3, GTK_FILL, GTK_FILL, 0,
0);
gtk_widget_show(label);
label = gtk_label_new("Max.");
gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
gtk_table_attach(GTK_TABLE(table), label, 2, 3, 2, 3, GTK_FILL, GTK_FILL, 0,
0);
gtk_widget_show(label);
/************************
* The min_width entry: *
************************/
label = gtk_label_new("Width:");
gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
gtk_table_attach(GTK_TABLE(table), label, 0, 1, 3, 4, GTK_FILL, GTK_FILL, 0,
0);
gtk_widget_show(label);
entry = gtk_entry_new();
gtk_table_attach(GTK_TABLE(table), entry, 1, 2, 3, 4, GTK_EXPAND | GTK_FILL,
GTK_EXPAND | GTK_FILL, 0, 0);
gtk_widget_set_usize(entry, 50, 0);
sprintf(buffer, "%i", my_config.min_width);
gtk_entry_set_text(GTK_ENTRY(entry), buffer);
gtk_signal_connect(GTK_OBJECT(entry), "changed",
(GtkSignalFunc) entry_callback, &my_config.min_width);
gtk_widget_show(entry);
/************************
* The max_width entry: *
************************/
entry = gtk_entry_new();
gtk_table_attach(GTK_TABLE(table), entry, 2, 3, 3, 4, GTK_EXPAND | GTK_FILL,
GTK_EXPAND | GTK_FILL, 0, 0);
gtk_widget_set_usize(entry, 50, 0);
sprintf(buffer, "%i", my_config.max_width);
gtk_entry_set_text(GTK_ENTRY(entry), buffer);
gtk_signal_connect(GTK_OBJECT(entry), "changed",
(GtkSignalFunc) entry_callback, &my_config.max_width);
gtk_widget_show(entry);
gtk_widget_show(dlg);
/************************
* The min_height entry: *
************************/
label = gtk_label_new("Height:");
gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
gtk_table_attach(GTK_TABLE(table), label, 0, 1, 4, 5, GTK_FILL, GTK_FILL, 0,
0);
gtk_widget_show(label);
entry = gtk_entry_new();
gtk_table_attach(GTK_TABLE(table), entry, 1, 2, 4, 5, GTK_EXPAND | GTK_FILL,
GTK_EXPAND | GTK_FILL, 0, 0);
gtk_widget_set_usize(entry, 50, 0);
sprintf(buffer, "%i", my_config.min_height);
gtk_entry_set_text(GTK_ENTRY(entry), buffer);
gtk_signal_connect(GTK_OBJECT(entry), "changed",
(GtkSignalFunc) entry_callback, &my_config.min_height);
gtk_widget_show(entry);
/************************
* The max_height entry: *
************************/
entry = gtk_entry_new();
gtk_table_attach(GTK_TABLE(table), entry, 2, 3, 4, 5, GTK_EXPAND | GTK_FILL,
GTK_EXPAND | GTK_FILL, 0, 0);
gtk_widget_set_usize(entry, 50, 0);
sprintf(buffer, "%i", my_config.max_height);
gtk_entry_set_text(GTK_ENTRY(entry), buffer);
gtk_signal_connect(GTK_OBJECT(entry), "changed",
(GtkSignalFunc) entry_callback, &my_config.max_height);
gtk_widget_show(entry);
gtk_widget_show(dlg);
gtk_main();
gdk_flush();
return run_flag;
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,283 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include "gtk/gtk.h"
#include "libgimp/gimp.h"
#include "fp.h"
#include "fp_hsv.h"
FP_Params Current =
{
1,
.25, /* Initial Roughness */
NULL,
.6, /* Initial Degree of Aliasing */
NULL,
60,
NULL,
MIDTONES, /* Initial Range */
BY_VAL, /* Initial God knows what */
TRUE, /* Selection Only */
TRUE, /* Real Time */
0, /* Offset */
HUE|VALUE,
{32,224,255},
{0,0,0}
};
GDrawable *drawable, *mask;
void query (void);
void run (char *name,
int nparams,
GParam *param,
int *nreturn_vals,
GParam **return_vals);
GPlugInInfo PLUG_IN_INFO =
{
NULL, /* init_proc */
NULL, /* quit_proc */
query, /* query_proc */
run, /* run_proc */
};
MAIN()
void
query ()
{
GParamDef args[] =
{
{ PARAM_INT32, "run_mode", "Interactive, non-interactive" },
{ PARAM_IMAGE, "image", "Input image (used for indexed images)" },
{ PARAM_DRAWABLE, "drawable", "Input drawable" },
};
GParamDef *return_vals = NULL;
int nargs = sizeof (args) / sizeof (args[0]);
int nreturn_vals = 0;
gimp_install_procedure ("plug_in_filter_pack",
"Allows the user to change H, S, or C with many previews",
"Then something else here",
"Pavel Grinfeld (pavel@ml.com)",
"Pavel Grinfeld (pavel@ml.com)",
"27th March 1997",
"<Image>/Filters/Darkroom/Filter Pack",
"RGB,INDEXED,GRAY",
PROC_PLUG_IN,
nargs, nreturn_vals,
args, return_vals);
}
/********************************STANDARD RUN*************************/
void
run (char *name,
int nparams,
GParam *param,
int *nreturn_vals,
GParam **return_vals)
{
GParam values[1];
GStatusType status = STATUS_SUCCESS;
*nreturn_vals = 1;
*return_vals = values;
values[0].type = PARAM_STATUS;
values[0].data.d_status = status;
initializeFilterPacks();
drawable = gimp_drawable_get (param[2].data.d_drawable);
mask=gimp_drawable_get(gimp_image_get_selection(param[1].data.d_image));
if (gimp_drawable_indexed (drawable->id) ||gimp_drawable_gray (drawable->id) ) {
ErrorMessage("Convert the image to RGB first!");
status = STATUS_EXECUTION_ERROR;
}
else if (gimp_drawable_color (drawable->id) && fp_dialog())
{
gimp_progress_init ("Applying the Filter Pack...");
gimp_tile_cache_ntiles (2 * (drawable->width / gimp_tile_width () + 1));
fp (drawable);
gimp_displays_flush ();
}
else status = STATUS_EXECUTION_ERROR;
values[0].data.d_status = status;
if (status==STATUS_SUCCESS)
gimp_drawable_detach (drawable);
}
void
fp_row (const guchar *src_row,
guchar *dest_row,
gint row,
gint row_width,
gint bytes)
{
gint col, bytenum, k;
int JudgeBy, Intensity, P[3], backupP[3];
hsv H,S,V;
gint M, m, middle;
for (col = 0; col < row_width ; col++)
{
backupP[0] = P[0] = src_row[col*bytes+0];
backupP[0] = P[1] = src_row[col*bytes+1];
backupP[0] = P[2] = src_row[col*bytes+2];
rgb_to_hsv(P[0]/255.0, P[1]/255.0, P[2]/255.0, &H, &S, &V);
for (JudgeBy=BY_HUE; JudgeBy<JUDGE_BY; JudgeBy++) {
if (!Current.Touched[JudgeBy]) continue;
switch (JudgeBy) {
case BY_HUE:
Intensity=255*H;
break;
case BY_SAT:
Intensity=255*S;
break;
case BY_VAL:
Intensity=255*V;
break;
}
/* It's important to take care of Saturation first!!! */
m = MIN(MIN(P[0],P[1]),P[2]);
M = MAX(MAX(P[0],P[1]),P[2]);
middle=(M+m)/2;
for (k=0; k<3; k++)
if (P[k]!=m && P[k]!=M) middle=P[k];
for (k=0; k<3; k++)
if (M!=m)
if (P[k] == M)
P[k] = MAX(P[k]+Current.satAdj[JudgeBy][Intensity],middle);
else if (P[k] == m)
P[k] = MIN(P[k]-Current.satAdj[JudgeBy][Intensity],middle);
P[0] += Current.redAdj[JudgeBy][Intensity];
P[1] += Current.greenAdj[JudgeBy][Intensity];
P[2] += Current.blueAdj[JudgeBy][Intensity];
P[0] = MAX(0,MIN(255, P[0]));
P[1] = MAX(0,MIN(255, P[1]));
P[2] = MAX(0,MIN(255, P[2]));
}
dest_row[col*bytes + 0] = P[0];
dest_row[col*bytes + 1] = P[1];
dest_row[col*bytes + 2] = P[2];
if (bytes>3)
for (bytenum = 3; bytenum<bytes; bytenum++)
dest_row[col*bytes+bytenum] = src_row[col*bytes+bytenum];
}
}
void fp (GDrawable *drawable)
{
GPixelRgn srcPR, destPR;
gint width, height;
gint bytes;
guchar *src_row, *dest_row;
gint row;
gint x1, y1, x2, y2;
gimp_drawable_mask_bounds (drawable->id, &x1, &y1, &x2, &y2);
width = drawable->width;
height = drawable->height;
bytes = drawable->bpp;
src_row = (guchar *) malloc ((x2 - x1) * bytes);
dest_row = (guchar *) malloc ((x2 - x1) * bytes);
gimp_pixel_rgn_init (&srcPR, drawable, 0, 0, width, height, FALSE, FALSE);
gimp_pixel_rgn_init (&destPR, drawable, 0, 0, width, height, TRUE, TRUE);
for (row = y1; row < y2; row++)
{
gimp_pixel_rgn_get_row (&srcPR, src_row, x1, row, (x2 - x1));
fp_row (src_row,
dest_row,
row,
(x2 - x1),
bytes
);
gimp_pixel_rgn_set_row (&destPR, dest_row, x1, row, (x2 - x1));
if ((row % 10) == 0)
gimp_progress_update ((double) row / (double) (y2 - y1));
}
/* update the processed region */
gimp_drawable_flush (drawable);
gimp_drawable_merge_shadow (drawable->id, TRUE);
gimp_drawable_update (drawable->id, x1, y1, (x2 - x1), (y2 - y1));
free (src_row);
free (dest_row);
}
void
ErrorMessage(guchar *message)
{
GtkWidget *window, *label, *button,*table;
gchar **argv=g_new (gchar *, 1);
gint argc=1;
argv[0] = g_strdup ("fp");
gtk_init (&argc, &argv);
gtk_rc_parse (gimp_gtkrc ());
window=gtk_dialog_new();
gtk_window_position (GTK_WINDOW (window), GTK_WIN_POS_MOUSE);
gtk_window_set_title(GTK_WINDOW(window),"Filter Pack Simulation Message");
gtk_signal_connect (GTK_OBJECT (window), "destroy",
(GtkSignalFunc) fp_close_callback,
NULL);
button = gtk_button_new_with_label ("Got It!");
GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
gtk_signal_connect (GTK_OBJECT (button), "clicked",
(GtkSignalFunc) fp_ok_callback,
window);
gtk_widget_grab_default (button);
gtk_widget_show (button);
gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->action_area), button, TRUE, TRUE, 0);
table=gtk_table_new(2,2,FALSE);
gtk_box_pack_start(GTK_BOX(GTK_DIALOG(window)->vbox),table,TRUE,TRUE,0);
gtk_widget_show(table);
label=gtk_label_new("");
gtk_label_set(GTK_LABEL(label),message);
gtk_widget_show(label);
gtk_table_attach(GTK_TABLE(table),label,0,1,0,1,
GTK_FILL|GTK_EXPAND,GTK_FILL|GTK_EXPAND,15,15);
gtk_widget_show(window);
gtk_main ();
}

View File

@ -1,160 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "gtk/gtk.h"
#include "libgimp/gimp.h"
#include "fp.h"
#include "fp_hsv.h"
extern AdvancedWindow AW;
extern FP_Params Current;
extern gint nudgeArray[256];
void
draw_slider(GdkWindow *window,
GdkGC *border_gc,
GdkGC *fill_gc,
int xpos)
{
int i;
for (i = 0; i < RANGE_HEIGHT; i++)
gdk_draw_line(window, fill_gc,xpos-i/2, i,xpos+i/2,i);
gdk_draw_line(window, border_gc, xpos, 0,
xpos - (RANGE_HEIGHT - 1) / 2, RANGE_HEIGHT - 1);
gdk_draw_line(window, border_gc, xpos, 0,
xpos + (RANGE_HEIGHT - 1) / 2, RANGE_HEIGHT - 1);
gdk_draw_line(window, border_gc,xpos-(RANGE_HEIGHT-1)/2,RANGE_HEIGHT-1,
xpos + (RANGE_HEIGHT-1)/2, RANGE_HEIGHT-1);
}
void
draw_it(GtkWidget *widget)
{
draw_slider(AW.aliasingGraph->window,
AW.aliasingGraph->style->black_gc,
AW.aliasingGraph->style->dark_gc[GTK_STATE_NORMAL],
Current.Cutoffs[SHADOWS]);
draw_slider(AW.aliasingGraph->window,
AW.aliasingGraph->style->black_gc,
AW.aliasingGraph->style->dark_gc[GTK_STATE_NORMAL],
Current.Cutoffs[MIDTONES]);
draw_slider(AW.aliasingGraph->window,
AW.aliasingGraph->style->black_gc,
AW.aliasingGraph->style->dark_gc[GTK_STATE_NORMAL],
Current.Offset);
}
void
slider_erase (GdkWindow *window,
int xpos)
{
gdk_window_clear_area (window, xpos - (RANGE_HEIGHT - 1) / 2, 0,
RANGE_HEIGHT, RANGE_HEIGHT);
}
gint
FP_Range_Change_Events (GtkWidget *widget,
GdkEvent *event,
FP_Params *current)
{
GdkEventButton *bevent;
GdkEventMotion *mevent;
gint shad, mid, offset, min;
static guchar *new;
gint x;
switch(event->type) {
case GDK_EXPOSE:
draw_it(NULL);
case GDK_BUTTON_PRESS:
bevent=(GdkEventButton *) event;
shad = abs(bevent->x - Current.Cutoffs[SHADOWS]);
mid = abs(bevent->x - Current.Cutoffs[MIDTONES]);
offset = abs(bevent->x - Current.Offset);
min= MIN(MIN(shad,mid),offset);
if (bevent->x >0 && bevent->x<256) {
if (min==shad)
new = &Current.Cutoffs[SHADOWS];
else if (min==mid)
new = &Current.Cutoffs[MIDTONES];
else
new = &Current.Offset;
slider_erase(AW.aliasingGraph->window,*new);
*new=bevent->x;
}
draw_it(NULL);
if (Current.RealTime) {
fp_range_preview_spill(AW.rangePreview,Current.ValueBy);
update_range_labels();
fp_create_smoothness_graph(AW.aliasingPreview);
refreshPreviews(Current.VisibleFrames);
}
break;
case GDK_BUTTON_RELEASE:
if (!Current.RealTime) {
fp_range_preview_spill(AW.rangePreview,Current.ValueBy);
update_range_labels();
fp_create_smoothness_graph(AW.aliasingPreview);
refreshPreviews(Current.VisibleFrames);
}
break;
case GDK_MOTION_NOTIFY:
mevent= (GdkEventMotion *) event;
gdk_window_get_pointer(widget->window, &x,NULL, NULL);
if (x>=0 && x<256) {
slider_erase(AW.aliasingGraph->window,*new);
*new=x;
draw_it(NULL);
if (Current.RealTime) {
fp_range_preview_spill(AW.rangePreview,Current.ValueBy);
update_range_labels();
fp_create_smoothness_graph(AW.aliasingPreview);
refreshPreviews(Current.VisibleFrames);
}
}
break;
default:
break;
}
return 0;
}
void
update_range_labels()
{
guchar buffer[3];
gtk_label_set(GTK_LABEL(Current.rangeLabels[1]),"0");
sprintf(buffer,"%d",Current.Cutoffs[SHADOWS]);
gtk_label_set(GTK_LABEL(Current.rangeLabels[3]),buffer);
gtk_label_set(GTK_LABEL(Current.rangeLabels[5]),buffer);
sprintf(buffer,"%d",Current.Cutoffs[MIDTONES]);
gtk_label_set(GTK_LABEL(Current.rangeLabels[7]),buffer);
gtk_label_set(GTK_LABEL(Current.rangeLabels[9]),buffer);
gtk_label_set(GTK_LABEL(Current.rangeLabels[11]),"255");
}

File diff suppressed because it is too large Load Diff

View File

@ -1,93 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "libgimp/gimp.h"
typedef double hsv;
void rgb_to_hsv (hsv r,
hsv g,
hsv b,
hsv *h,
hsv *s,
hsv *l)
{
hsv v;
hsv m;
hsv vm;
hsv r2, g2, b2;
v = MAX(r,g);
v = MAX(v,b);
m = MIN(r,g);
m = MIN(m,b);
if ((*l = (m + v) / 2.0) <= 0.0)
{
*s=*h=0;
return;
}
if ((*s = vm = v - m) > 0.0)
{
*s /= (*l <= 0.5) ? (v + m ) :
(2.0 - v - m) ;
}
else
{
*h=0;
return;
}
r2 = (v - r) / vm;
g2 = (v - g) / vm;
b2 = (v - b) / vm;
if (r == v)
*h = (g == m ? 5.0 + b2 : 1.0 - g2);
else if (g == v)
*h = (b == m ? 1.0 + r2 : 3.0 - b2);
else
*h = (r == m ? 3.0 + g2 : 5.0 - r2);
*h /= 6;
}
void hsv_to_rgb (hsv h,
hsv sl,
hsv l,
hsv *r,
hsv *g,
hsv *b)
{
hsv v;
v = (l <= 0.5) ? (l * (1.0 + sl)) : (l + sl - l * sl);
if (v <= 0)
{
*r = *g = *b = 0.0;
}
else
{
hsv m;
hsv sv;
gint sextant;
hsv fract, vsf, mid1, mid2;
m = l + l - v;
sv = (v - m ) / v;
h *= 6.0;
sextant = h;
fract = h - sextant;
vsf = v * sv * fract;
mid1 = m + vsf;
mid2 = v - vsf;
switch (sextant)
{
case 0: *r = v; *g = mid1; *b = m; break;
case 1: *r = mid2; *g = v; *b = m; break;
case 2: *r = m; *g = v; *b = mid1; break;
case 3: *r = m; *g = mid2; *b = v; break;
case 4: *r = mid1; *g = m; *b = v; break;
case 5: *r = v; *g = m; *b = mid2; break;
}
}
}

View File

@ -1,394 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "gtk/gtk.h"
#include "libgimp/gimp.h"
#include "fp.h"
#include "fp_hsv.h"
extern FP_Params Current;
extern GDrawable *drawable, *mask;
extern ReducedImage *reduced;
extern gint nudgeArray[256];
gint colorSign[3][ALL_PRIMARY]=
{{1,-1,-1,-1,1,1},{-1,1,-1,1,1,-1},{-1,-1,1,1,-1,1}};
void initializeFilterPacks()
{
gint i, j;
for (i=0; i<256; i++)
for (j=BY_HUE; j<JUDGE_BY; j++) {
Current.redAdj [j][i]=0;
Current.greenAdj [j][i]=0;
Current.blueAdj [j][i]=0;
Current.satAdj [j][i]=0;
}
}
void resetFilterPacks()
{
initializeFilterPacks();
refreshPreviews(Current.VisibleFrames);
}
ReducedImage *Reduce_The_Image(GDrawable *drawable,
GDrawable *mask,
gint LongerSize,
gint Slctn)
{
gint width;
gint height;
gint bytes=drawable->bpp;
gint RH, RW;
ReducedImage *temp=(ReducedImage *)malloc(sizeof(ReducedImage));
guchar *tempRGB, *src_row, *tempmask, *src_mask_row,R,G,B;
gint i, j, whichcol, whichrow, x1, x2, y1, y2;
GPixelRgn srcPR, srcMask;
gint NoSelectionMade=TRUE;
hsv *tempHSV, H, S, V;
gimp_drawable_mask_bounds (drawable->id, &x1, &y1, &x2, &y2);
width = x2-x1;
height = y2-y1;
if (width != drawable->width && height != drawable->height)
NoSelectionMade=FALSE;
if (Slctn==0) {
x1=0;
x2=drawable->width;
y1=0;
y2=drawable->height;
}
if (Slctn==2) {
x1=MAX(0, x1-width/2.0);
x2=MIN(drawable->width, x2+width/2.0);
y1=MAX(0, y1-height/2.0);
y2=MIN(drawable->height, y2+height/2.0);
}
width = x2-x1;
height = y2-y1;
if (width>height) {
RW=LongerSize;
RH=(float) height * (float) LongerSize/ (float) width;
}
else {
RH=LongerSize;
RW=(float)width * (float) LongerSize/ (float) height;
}
tempRGB = (guchar *) malloc(RW*RH*bytes);
tempHSV = (hsv *) malloc(RW*RH*bytes*sizeof(hsv));
tempmask = (guchar *) malloc(RW*RH);
gimp_pixel_rgn_init (&srcPR, drawable, x1, y1, width, height, FALSE, FALSE);
gimp_pixel_rgn_init (&srcMask, mask, x1, y1, width, height, FALSE, FALSE);
src_row = (guchar *) malloc (width*bytes);
src_mask_row = (guchar *) malloc (width*bytes);
for (i=0; i<RH; i++) {
whichrow=(float)i*(float)height/(float)RH;
gimp_pixel_rgn_get_row (&srcPR, src_row, x1, y1+whichrow, width);
gimp_pixel_rgn_get_row (&srcMask, src_mask_row, x1, y1+whichrow, width);
for (j=0; j<RW; j++) {
whichcol=(float)j*(float)width/(float)RW;
if (NoSelectionMade)
tempmask[i*RW+j]=255;
else
tempmask[i*RW+j]=src_mask_row[whichcol];
R=src_row[whichcol*bytes+0];
G=src_row[whichcol*bytes+1];
B=src_row[whichcol*bytes+2];
rgb_to_hsv(R/255.0,G/255.0,B/255.0,&H,&S,&V);
tempRGB[i*RW*bytes+j*bytes+0]=R;
tempRGB[i*RW*bytes+j*bytes+1]=G;
tempRGB[i*RW*bytes+j*bytes+2]=B;
tempHSV[i*RW*bytes+j*bytes+0]=H;
tempHSV[i*RW*bytes+j*bytes+1]=S;
tempHSV[i*RW*bytes+j*bytes+2]=V;
if (bytes==4)
tempRGB[i*RW*bytes+j*bytes+3]=src_row[whichcol*bytes+3];
}
}
temp->width=RW;
temp->height=RH;
temp->rgb=tempRGB;
temp->hsv=tempHSV;
temp->mask=tempmask;
return temp;
}
/*************************************************************/
/************** The Preview Function *************************/
void
fp_render_preview(GtkWidget *preview,
gint changewhat,
gint changewhich)
{
guchar *a;
gint Inten, bytes=drawable->bpp;
gint i, j, k, nudge, M, m, middle,JudgeBy;
float partial;
gint RW=reduced->width;
gint RH=reduced->height;
gint backupP[3], P[3], tempSat[JUDGE_BY][256];
a =(guchar *) malloc(bytes*RW);
if (changewhat==SATURATION)
for (k=0; k<256; k++) {
for (JudgeBy=BY_HUE; JudgeBy<JUDGE_BY; JudgeBy++)
tempSat[JudgeBy][k]=0;
tempSat[Current.ValueBy][k] += changewhich*nudgeArray[(k+Current.Offset)%256];
}
for (i=0; i<RH; i++) {
for (j=0; j<RW; j++) {
backupP[0] = P[0] = (int) reduced->rgb[i*RW*bytes + j*bytes + 0];
backupP[1] = P[1] = (int) reduced->rgb[i*RW*bytes + j*bytes + 1];
backupP[2] = P[2] = (int) reduced->rgb[i*RW*bytes + j*bytes + 2];
m = MIN(MIN(P[0],P[1]),P[2]);
M = MAX(MAX(P[0],P[1]),P[2]);
middle=(M+m)/2;
for (k=0; k<3; k++)
if (P[k]!=m && P[k]!=M) middle=P[k];
partial = reduced->mask[i*RW+j]/255.0;
for (JudgeBy=BY_HUE; JudgeBy<JUDGE_BY; JudgeBy++) {
if (!Current.Touched[JudgeBy]) continue;
Inten = reduced->hsv[i*RW*bytes + j*bytes + JudgeBy]*255.0;
/*DO SATURATION FIRST*/
if (changewhat != NONEATALL) {
if (M!=m)
for (k=0; k<3; k++)
if (backupP[k] == M)
P[k] = MAX(P[k]+partial*Current.satAdj[JudgeBy][Inten],middle);
else if (backupP[k] == m)
P[k] = MIN(P[k]-partial*Current.satAdj[JudgeBy][Inten],middle);
P[0] += partial*Current.redAdj[JudgeBy][Inten];
P[1] += partial*Current.greenAdj[JudgeBy][Inten];
P[2] += partial*Current.blueAdj[JudgeBy][Inten];
}
}
Inten = reduced->hsv[i*RW*bytes + j*bytes + Current.ValueBy]*255.0;
nudge = partial*nudgeArray[(Inten+Current.Offset)%256];
switch (changewhat) {
case HUE:
P[0] += colorSign[RED][changewhich] * nudge;
P[1] += colorSign[GREEN][changewhich] * nudge;
P[2] += colorSign[BLUE][changewhich] * nudge;
break;
case SATURATION:
for (JudgeBy=BY_HUE; JudgeBy<JUDGE_BY; JudgeBy++)
for (k=0; k<3; k++)
if (M!=m)
if (backupP[k] == M)
P[k] = MAX(P[k]+
partial*tempSat[JudgeBy][Inten],middle);
else if (backupP[k] == m)
P[k] = MIN(P[k]-
partial*tempSat[JudgeBy][Inten],middle);
break;
case VALUE:
P[0] += changewhich * nudge;
P[1] += changewhich * nudge;
P[2] += changewhich * nudge;
break;
default:
break;
}
a[j*3+0] = MAX(0,MIN(P[0], 255));
a[j*3+1] = MAX(0,MIN(P[1], 255));
a[j*3+2] = MAX(0,MIN(P[2], 255));
}
gtk_preview_draw_row( GTK_PREVIEW(preview),a,0,i,RW);
}
free(a);
gtk_widget_draw(preview,NULL);
gdk_flush();
}
void
Update_Current_FP (gint changewhat,
gint changewhich)
{
int i, nudge;
for (i=0; i<256; i++) {
fp_Create_Nudge(nudgeArray);
nudge=nudgeArray[(i+Current.Offset)%256];
switch (changewhat) {
case HUE:
Current.redAdj[Current.ValueBy][i] +=
colorSign[RED][changewhich] * nudge;
Current.greenAdj[Current.ValueBy][i] +=
colorSign[GREEN][changewhich] * nudge;
Current.blueAdj[Current.ValueBy][i] +=
colorSign[BLUE][changewhich] * nudge;
break;
case SATURATION:
Current.satAdj[Current.ValueBy][i] += changewhich*nudge;
break;
case VALUE:
Current.redAdj[Current.ValueBy][i] += changewhich * nudge;
Current.greenAdj[Current.ValueBy][i] += changewhich * nudge;
Current.blueAdj[Current.ValueBy][i] += changewhich * nudge;
break;
default:
break;
} /* switch */
} /* for */
}
void
fp_create_smoothness_graph (GtkWidget *preview)
{
guchar data[256*3];
gint nArray[256];
int i, j, toBeBlack;
fp_Create_Nudge(nArray);
for (i=0; i<MAX_ROUGHNESS; i++)
{
int coor=MAX_ROUGHNESS-i;
for (j=0; j<256; j++) {
data[3*j+0]=255;
data[3*j+1]=255;
data[3*j+2]=255;
if (!(i%(MAX_ROUGHNESS/4))) {
data[3*j+0]=255;
data[3*j+1]=128;
data[3*j+2]=128;
}
if (!((j+1)%32)) {
data[3*j+0]=255;
data[3*j+1]=128;
data[3*j+2]=128;
}
toBeBlack=0;
if (nArray[j]==coor) toBeBlack=1;
if (j<255) {
int jump=abs(nArray[j]-nArray[j+1]);
if ( abs(coor-nArray[j]) < jump
&& abs(coor-nArray[j+1]) < jump)
toBeBlack=1;
}
if (toBeBlack) {
data[3*j+0]=0;
data[3*j+1]=0;
data[3*j+2]=0;
}
}
gtk_preview_draw_row( GTK_PREVIEW(preview),data,0,i,256);
}
gtk_widget_draw(preview,NULL);
gdk_flush();
}
void
fp_range_preview_spill(GtkWidget *preview, int type)
{
guchar data[256*3];
int i, j;
hsv R,G,B;
for (i=0; i<RANGE_HEIGHT; i++) {
for (j=0; j<256; j++)
if (!((j+1)%32)) {
data[3*j+0]=255;
data[3*j+1]=128;
data[3*j+2]=128;
}
else
switch (type) {
case BY_VAL:
data[3*j+0]=j-Current.Offset;
data[3*j+1]=j-Current.Offset;
data[3*j+2]=j-Current.Offset;
break;
case BY_HUE:
hsv_to_rgb((hsv)((j-Current.Offset+256)%256)/255.0, 1.0, .5, &R, &G, &B);
data[3*j+0]=R*255;
data[3*j+1]=G*255;
data[3*j+2]=B*255;
break;
case BY_SAT:
hsv_to_rgb(.5,(hsv)((j-(gint)Current.Offset+256)%256)/255.0,.5,&R,&G,&B);
data[3*j+0]=R*255;
data[3*j+1]=G*255;
data[3*j+2]=B*255;
break;
}
gtk_preview_draw_row( GTK_PREVIEW(preview),data,0,i,256);
}
gtk_widget_draw(preview,NULL);
gdk_flush();
}
void fp_Create_Nudge(gint *adjArray)
{
int left, right, middle,i;
/* The following function was determined by trial and error */
double Steepness=pow(1-Current.Alias,4)*.8;
left = (Current.Range == SHADOWS) ? 0 : Current.Cutoffs[Current.Range-1];
right = Current.Cutoffs[Current.Range];
middle = (left + right)/2;
if (Current.Alias!=0)
for (i=0; i<256; i++)
if (i<=middle)
adjArray[i] = MAX_ROUGHNESS *
Current.Rough*(1+tanh(Steepness*(i-left)))/2;
else
adjArray[i] = MAX_ROUGHNESS *
Current.Rough*(1+tanh(Steepness*(right-i)))/2;
else
for (i=0; i<256; i++)
if (left<=i && i<=right)
adjArray[i] = MAX_ROUGHNESS * Current.Rough;
else
adjArray[i] = 0;
}

View File

@ -1,275 +0,0 @@
#ident "@(#)g3.c 3.1 95/08/30 Copyright (c) Gert Doering"
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include "g3.h"
struct g3code t_white[66] = {
{ 0, 0, 0x0ac, 8 },
{ 0, 1, 0x038, 6 },
{ 0, 2, 0x00e, 4 },
{ 0, 3, 0x001, 4 },
{ 0, 4, 0x00d, 4 },
{ 0, 5, 0x003, 4 },
{ 0, 6, 0x007, 4 },
{ 0, 7, 0x00f, 4 },
{ 0, 8, 0x019, 5 },
{ 0, 9, 0x005, 5 },
{ 0, 10, 0x01c, 5 },
{ 0, 11, 0x002, 5 },
{ 0, 12, 0x004, 6 },
{ 0, 13, 0x030, 6 },
{ 0, 14, 0x00b, 6 },
{ 0, 15, 0x02b, 6 },
{ 0, 16, 0x015, 6 },
{ 0, 17, 0x035, 6 },
{ 0, 18, 0x072, 7 },
{ 0, 19, 0x018, 7 },
{ 0, 20, 0x008, 7 },
{ 0, 21, 0x074, 7 },
{ 0, 22, 0x060, 7 },
{ 0, 23, 0x010, 7 },
{ 0, 24, 0x00a, 7 },
{ 0, 25, 0x06a, 7 },
{ 0, 26, 0x064, 7 },
{ 0, 27, 0x012, 7 },
{ 0, 28, 0x00c, 7 },
{ 0, 29, 0x040, 8 },
{ 0, 30, 0x0c0, 8 },
{ 0, 31, 0x058, 8 },
{ 0, 32, 0x0d8, 8 },
{ 0, 33, 0x048, 8 },
{ 0, 34, 0x0c8, 8 },
{ 0, 35, 0x028, 8 },
{ 0, 36, 0x0a8, 8 },
{ 0, 37, 0x068, 8 },
{ 0, 38, 0x0e8, 8 },
{ 0, 39, 0x014, 8 },
{ 0, 40, 0x094, 8 },
{ 0, 41, 0x054, 8 },
{ 0, 42, 0x0d4, 8 },
{ 0, 43, 0x034, 8 },
{ 0, 44, 0x0b4, 8 },
{ 0, 45, 0x020, 8 },
{ 0, 46, 0x0a0, 8 },
{ 0, 47, 0x050, 8 },
{ 0, 48, 0x0d0, 8 },
{ 0, 49, 0x04a, 8 },
{ 0, 50, 0x0ca, 8 },
{ 0, 51, 0x02a, 8 },
{ 0, 52, 0x0aa, 8 },
{ 0, 53, 0x024, 8 },
{ 0, 54, 0x0a4, 8 },
{ 0, 55, 0x01a, 8 },
{ 0, 56, 0x09a, 8 },
{ 0, 57, 0x05a, 8 },
{ 0, 58, 0x0da, 8 },
{ 0, 59, 0x052, 8 },
{ 0, 60, 0x0d2, 8 },
{ 0, 61, 0x04c, 8 },
{ 0, 62, 0x0cc, 8 },
{ 0, 63, 0x02c, 8 },
{ 0, -1, 0, 11 }, /* 11 0-bits == EOL, special handling */
{ 0, -1, 0, 0 }}; /* end of table */
/* make-up codes white */
struct g3code m_white[28] = {
{ 0, 64, 0x01b, 5 },
{ 0, 128, 0x009, 5 },
{ 0, 192, 0x03a, 6 },
{ 0, 256, 0x076, 7 },
{ 0, 320, 0x06c, 8 },
{ 0, 384, 0x0ec, 8 },
{ 0, 448, 0x026, 8 },
{ 0, 512, 0x0a6, 8 },
{ 0, 576, 0x016, 8 },
{ 0, 640, 0x0e6, 8 },
{ 0, 704, 0x066, 9 },
{ 0, 768, 0x166, 9 },
{ 0, 832, 0x096, 9 },
{ 0, 896, 0x196, 9 },
{ 0, 960, 0x056, 9 },
{ 0,1024, 0x156, 9 },
{ 0,1088, 0x0d6, 9 },
{ 0,1152, 0x1d6, 9 },
{ 0,1216, 0x036, 9 },
{ 0,1280, 0x136, 9 },
{ 0,1344, 0x0b6, 9 },
{ 0,1408, 0x1b6, 9 },
{ 0,1472, 0x032, 9 },
{ 0,1536, 0x132, 9 },
{ 0,1600, 0x0b2, 9 },
{ 0,1664, 0x006, 6 },
{ 0,1728, 0x1b2, 9 },
{ 0, -1, 0, 0} };
struct g3code t_black[66] = {
{ 0, 0, 0x3b0, 10 },
{ 0, 1, 0x002, 3 },
{ 0, 2, 0x003, 2 },
{ 0, 3, 0x001, 2 },
{ 0, 4, 0x006, 3 },
{ 0, 5, 0x00c, 4 },
{ 0, 6, 0x004, 4 },
{ 0, 7, 0x018, 5 },
{ 0, 8, 0x028, 6 },
{ 0, 9, 0x008, 6 },
{ 0, 10, 0x010, 7 },
{ 0, 11, 0x050, 7 },
{ 0, 12, 0x070, 7 },
{ 0, 13, 0x020, 8 },
{ 0, 14, 0x0e0, 8 },
{ 0, 15, 0x030, 9 },
{ 0, 16, 0x3a0, 10 },
{ 0, 17, 0x060, 10 },
{ 0, 18, 0x040, 10 },
{ 0, 19, 0x730, 11 },
{ 0, 20, 0x0b0, 11 },
{ 0, 21, 0x1b0, 11 },
{ 0, 22, 0x760, 11 },
{ 0, 23, 0x0a0, 11 },
{ 0, 24, 0x740, 11 },
{ 0, 25, 0x0c0, 11 },
{ 0, 26, 0x530, 12 },
{ 0, 27, 0xd30, 12 },
{ 0, 28, 0x330, 12 },
{ 0, 29, 0xb30, 12 },
{ 0, 30, 0x160, 12 },
{ 0, 31, 0x960, 12 },
{ 0, 32, 0x560, 12 },
{ 0, 33, 0xd60, 12 },
{ 0, 34, 0x4b0, 12 },
{ 0, 35, 0xcb0, 12 },
{ 0, 36, 0x2b0, 12 },
{ 0, 37, 0xab0, 12 },
{ 0, 38, 0x6b0, 12 },
{ 0, 39, 0xeb0, 12 },
{ 0, 40, 0x360, 12 },
{ 0, 41, 0xb60, 12 },
{ 0, 42, 0x5b0, 12 },
{ 0, 43, 0xdb0, 12 },
{ 0, 44, 0x2a0, 12 },
{ 0, 45, 0xaa0, 12 },
{ 0, 46, 0x6a0, 12 },
{ 0, 47, 0xea0, 12 },
{ 0, 48, 0x260, 12 },
{ 0, 49, 0xa60, 12 },
{ 0, 50, 0x4a0, 12 },
{ 0, 51, 0xca0, 12 },
{ 0, 52, 0x240, 12 },
{ 0, 53, 0xec0, 12 },
{ 0, 54, 0x1c0, 12 },
{ 0, 55, 0xe40, 12 },
{ 0, 56, 0x140, 12 },
{ 0, 57, 0x1a0, 12 },
{ 0, 58, 0x9a0, 12 },
{ 0, 59, 0xd40, 12 },
{ 0, 60, 0x340, 12 },
{ 0, 61, 0x5a0, 12 },
{ 0, 62, 0x660, 12 },
{ 0, 63, 0xe60, 12 },
{ 0, -1, 0x000, 11 },
{ 0, -1, 0, 0 } };
struct g3code m_black[28] = {
{ 0, 64, 0x3c0, 10 },
{ 0, 128, 0x130, 12 },
{ 0, 192, 0x930, 12 },
{ 0, 256, 0xda0, 12 },
{ 0, 320, 0xcc0, 12 },
{ 0, 384, 0x2c0, 12 },
{ 0, 448, 0xac0, 12 },
{ 0, 512, 0x6c0, 13 },
{ 0, 576,0x16c0, 13 },
{ 0, 640, 0xa40, 13 },
{ 0, 704,0x1a40, 13 },
{ 0, 768, 0x640, 13 },
{ 0, 832,0x1640, 13 },
{ 0, 896, 0x9c0, 13 },
{ 0, 960,0x19c0, 13 },
{ 0,1024, 0x5c0, 13 },
{ 0,1088,0x15c0, 13 },
{ 0,1152, 0xdc0, 13 },
{ 0,1216,0x1dc0, 13 },
{ 0,1280, 0x940, 13 },
{ 0,1344,0x1940, 13 },
{ 0,1408, 0x540, 13 },
{ 0,1472,0x1540, 13 },
{ 0,1536, 0xb40, 13 },
{ 0,1600,0x1b40, 13 },
{ 0,1664, 0x4c0, 13 },
{ 0,1728,0x14c0, 13 },
{ 0, -1, 0, 0 } };
void tree_add_node( struct g3_tree *p, struct g3code * g3c,
int bit_code, int bit_length )
{
int i;
if ( bit_length <= FBITS ) /* leaf (multiple bits) */
{
g3c->nr_bits = bit_length; /* leaf tag */
if ( bit_length == FBITS ) /* full width */
{
p->nextb[ bit_code ] = (struct g3_tree *) g3c;
}
else /* fill bits */
for ( i=0; i< ( 1 << (FBITS-bit_length)); i++ )
{
p->nextb[ bit_code + ( i << bit_length ) ] = (struct g3_tree *) g3c;
}
}
else /* node */
{
struct g3_tree *p2;
p2 = p->nextb[ bit_code & BITM ];
if ( p2 == 0 ) /* no sub-node exists */
{
p2 = p->nextb[ bit_code & BITM ] =
( struct g3_tree * ) calloc( 1, sizeof( struct g3_tree ));
if ( p2 == NULL ) { perror( "malloc 3" ); exit(11); }
p2->nr_bits = 0; /* node tag */
}
if ( p2->nr_bits != 0 )
{
fprintf( stderr, "internal table setup error\n" ); exit(6);
}
tree_add_node( p2, g3c, bit_code >> FBITS, bit_length - FBITS );
}
}
void build_tree (struct g3_tree ** p, struct g3code * c )
{
if ( *p == NULL )
{
(*p) = (struct g3_tree *) calloc( 1, sizeof(struct g3_tree) );
if ( *p == NULL ) { perror( "malloc(1)" ); exit(10); }
(*p)->nr_bits=0;
}
while ( c->bit_length != 0 )
{
tree_add_node( *p, c, c->bit_code, c->bit_length );
c++;
}
}
void init_byte_tab (int reverse, int byte_tab[] )
{
int i;
if ( reverse ) for ( i=0; i<256; i++ ) byte_tab[i] = i;
else
for ( i=0; i<256; i++ )
byte_tab[i] = ( ((i & 0x01) << 7) | ((i & 0x02) << 5) |
((i & 0x04) << 3) | ((i & 0x08) << 1) |
((i & 0x10) >> 1) | ((i & 0x20) >> 3) |
((i & 0x40) >> 5) | ((i & 0x80) >> 7) );
}

View File

@ -1,656 +0,0 @@
/* The GIMP -- an image manipulation program
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* 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
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include "gtk/gtk.h"
#include "libgimp/gimp.h"
#define ENTRY_WIDTH 100
typedef struct
{
gdouble radius;
gint horizontal;
gint vertical;
} BlurValues;
typedef struct
{
gint run;
} BlurInterface;
/* Declare local functions.
*/
static void query (void);
static void run (gchar *name,
gint nparams,
GParam *param,
gint *nreturn_vals,
GParam **return_vals);
static void gauss_iir (GDrawable *drawable,
gint horizontal,
gint vertical,
gdouble std_dev);
/*
* Gaussian blur interface
*/
static gint gauss_iir_dialog (void);
/*
* Gaussian blur helper functions
*/
static void find_constants (gdouble n_p[],
gdouble n_m[],
gdouble d_p[],
gdouble d_m[],
gdouble bd_p[],
gdouble bd_m[],
gdouble std_dev);
static void transfer_pixels (gdouble * src1,
gdouble * src2,
guchar * dest,
gint bytes,
gint width);
static void gauss_close_callback (GtkWidget *widget,
gpointer data);
static void gauss_ok_callback (GtkWidget *widget,
gpointer data);
static void gauss_toggle_update (GtkWidget *widget,
gpointer data);
static void gauss_entry_callback (GtkWidget *widget,
gpointer data);
GPlugInInfo PLUG_IN_INFO =
{
NULL, /* init_proc */
NULL, /* quit_proc */
query, /* query_proc */
run, /* run_proc */
};
static BlurValues bvals =
{
5.0, /* radius */
TRUE, /* horizontal blur */
TRUE /* vertical blur */
};
static BlurInterface bint =
{
FALSE /* run */
};
MAIN ()
static void
query ()
{
static GParamDef args[] =
{
{ PARAM_INT32, "run_mode", "Interactive, non-interactive" },
{ PARAM_IMAGE, "image", "Input image (unused)" },
{ PARAM_DRAWABLE, "drawable", "Input drawable" },
{ PARAM_FLOAT, "radius", "Radius of gaussian blur (in pixels > 1.0)" },
{ PARAM_INT32, "horizontal", "Blur in horizontal direction" },
{ PARAM_INT32, "vertical", "Blur in vertical direction" },
};
static GParamDef *return_vals = NULL;
static gint nargs = sizeof (args) / sizeof (args[0]);
static gint nreturn_vals = 0;
gimp_install_procedure ("plug_in_gauss_iir",
"Applies a gaussian blur to the specified drawable.",
"Applies a gaussian blur to the drawable, with specified radius of affect. The standard deviation of the normal distribution used to modify pixel values is calculated based on the supplied radius. Horizontal and vertical blurring can be independently invoked by specifying only one to run. The IIR gaussian blurring works best for large radius values and for images which are not computer-generated. Values for radius less than 1.0 are invalid as they will generate spurious results.",
"Spencer Kimball & Peter Mattis",
"Spencer Kimball & Peter Mattis",
"1995-1996",
"<Image>/Filters/Blur/Gaussian Blur (IIR)",
"RGB*, GRAY*",
PROC_PLUG_IN,
nargs, nreturn_vals,
args, return_vals);
}
static void
run (gchar *name,
gint nparams,
GParam *param,
gint *nreturn_vals,
GParam **return_vals)
{
static GParam values[1];
GDrawable *drawable;
GRunModeType run_mode;
GStatusType status = STATUS_SUCCESS;
gdouble radius, std_dev;
run_mode = param[0].data.d_int32;
*nreturn_vals = 1;
*return_vals = values;
values[0].type = PARAM_STATUS;
values[0].data.d_status = status;
switch (run_mode)
{
case RUN_INTERACTIVE:
/* Possibly retrieve data */
gimp_get_data ("plug_in_gauss_iir", &bvals);
/* First acquire information with a dialog */
if (! gauss_iir_dialog ())
return;
break;
case RUN_NONINTERACTIVE:
/* Make sure all the arguments are there! */
if (nparams != 6)
status = STATUS_CALLING_ERROR;
if (status == STATUS_SUCCESS)
{
bvals.radius = param[3].data.d_float;
bvals.horizontal = (param[4].data.d_int32) ? TRUE : FALSE;
bvals.vertical = (param[5].data.d_int32) ? TRUE : FALSE;
}
if (status == STATUS_SUCCESS &&
(bvals.radius < 1.0))
status = STATUS_CALLING_ERROR;
break;
case RUN_WITH_LAST_VALS:
/* Possibly retrieve data */
gimp_get_data ("plug_in_gauss_iir", &bvals);
break;
default:
break;
}
/* 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 ("IIR Gaussian Blur");
/* set the tile cache size so that the gaussian blur works well */
gimp_tile_cache_ntiles (2 * (MAX (drawable->width, drawable->height) /
gimp_tile_width () + 1));
radius = fabs (bvals.radius) + 1.0;
std_dev = sqrt (-(radius * radius) / (2 * log (1.0 / 255.0)));
/* run the gaussian blur */
gauss_iir (drawable, bvals.horizontal, bvals.vertical, std_dev);
if (run_mode != RUN_NONINTERACTIVE)
gimp_displays_flush ();
/* Store data */
if (run_mode == RUN_INTERACTIVE)
gimp_set_data ("plug_in_gauss_iir", &bvals, sizeof (BlurValues));
}
else
{
/* gimp_message ("gauss_iir: cannot operate on indexed color images"); */
status = STATUS_EXECUTION_ERROR;
}
values[0].data.d_status = status;
gimp_drawable_detach (drawable);
}
static gint
gauss_iir_dialog ()
{
GtkWidget *dlg;
GtkWidget *label;
GtkWidget *entry;
GtkWidget *button;
GtkWidget *toggle;
GtkWidget *frame;
GtkWidget *vbox;
GtkWidget *hbox;
gchar buffer[12];
gchar **argv;
gint argc;
argc = 1;
argv = g_new (gchar *, 1);
argv[0] = g_strdup ("gauss");
gtk_init (&argc, &argv);
gtk_rc_parse (gimp_gtkrc ());
dlg = gtk_dialog_new ();
gtk_window_set_title (GTK_WINDOW (dlg), "IIR Gaussian Blur");
gtk_window_position (GTK_WINDOW (dlg), GTK_WIN_POS_MOUSE);
gtk_signal_connect (GTK_OBJECT (dlg), "destroy",
(GtkSignalFunc) gauss_close_callback,
NULL);
/* Action area */
button = gtk_button_new_with_label ("OK");
GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
gtk_signal_connect (GTK_OBJECT (button), "clicked",
(GtkSignalFunc) gauss_ok_callback,
dlg);
gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dlg)->action_area), button, TRUE, TRUE, 0);
gtk_widget_grab_default (button);
gtk_widget_show (button);
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));
gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dlg)->action_area), button, TRUE, TRUE, 0);
gtk_widget_show (button);
/* parameter settings */
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);
vbox = gtk_vbox_new (FALSE, 5);
gtk_container_border_width (GTK_CONTAINER (vbox), 10);
gtk_container_add (GTK_CONTAINER (frame), vbox);
toggle = gtk_check_button_new_with_label ("Blur Horizontally");
gtk_box_pack_start (GTK_BOX (vbox), toggle, TRUE, TRUE, 0);
gtk_signal_connect (GTK_OBJECT (toggle), "toggled",
(GtkSignalFunc) gauss_toggle_update,
&bvals.horizontal);
gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (toggle), bvals.horizontal);
gtk_widget_show (toggle);
toggle = gtk_check_button_new_with_label ("Blur Vertically");
gtk_box_pack_start (GTK_BOX (vbox), toggle, TRUE, TRUE, 0);
gtk_signal_connect (GTK_OBJECT (toggle), "toggled",
(GtkSignalFunc) gauss_toggle_update,
&bvals.vertical);
gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (toggle), bvals.vertical);
gtk_widget_show (toggle);
hbox = gtk_hbox_new (FALSE, 5);
gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, TRUE, 0);
label = gtk_label_new ("Blur Radius: ");
gtk_box_pack_start (GTK_BOX (hbox), label, TRUE, FALSE, 0);
gtk_widget_show (label);
entry = gtk_entry_new ();
gtk_box_pack_start (GTK_BOX (hbox), entry, TRUE, TRUE, 0);
gtk_widget_set_usize (entry, ENTRY_WIDTH, 0);
sprintf (buffer, "%f", bvals.radius);
gtk_entry_set_text (GTK_ENTRY (entry), buffer);
gtk_signal_connect (GTK_OBJECT (entry), "changed",
(GtkSignalFunc) gauss_entry_callback,
NULL);
gtk_widget_show (entry);
gtk_widget_show (hbox);
gtk_widget_show (vbox);
gtk_widget_show (frame);
gtk_widget_show (dlg);
gtk_main ();
gdk_flush ();
return bint.run;
}
static void
gauss_iir (GDrawable *drawable,
gint horz,
gint vert,
gdouble std_dev)
{
GPixelRgn src_rgn, dest_rgn;
gint width, height;
gint bytes;
guchar *dest;
guchar *src, *sp_p, *sp_m;
gdouble n_p[5], n_m[5];
gdouble d_p[5], d_m[5];
gdouble bd_p[5], bd_m[5];
gdouble *val_p, *val_m, *vp, *vm;
gint x1, y1, x2, y2;
gint i, j;
gint row, col, b;
gint terms;
gint progress, max_progress;
gint initial_p[4];
gint initial_m[4];
gimp_drawable_mask_bounds (drawable->id, &x1, &y1, &x2, &y2);
width = (x2 - x1);
height = (y2 - y1);
bytes = drawable->bpp;
val_p = (gdouble *) malloc (MAX (width, height) * bytes * sizeof (gdouble));
val_m = (gdouble *) malloc (MAX (width, height) * bytes * sizeof (gdouble));
src = (guchar *) malloc (MAX (width, height) * bytes);
dest = (guchar *) malloc (MAX (width, height) * bytes);
/* derive the constants for calculating the gaussian from the std dev */
find_constants (n_p, n_m, d_p, d_m, bd_p, bd_m, std_dev);
progress = 0;
max_progress = (horz) ? width * height : 0;
max_progress += (vert) ? width * height : 0;
gimp_pixel_rgn_init (&src_rgn, drawable, 0, 0, drawable->width, drawable->height, FALSE, FALSE);
gimp_pixel_rgn_init (&dest_rgn, drawable, 0, 0, drawable->width, drawable->height, TRUE, TRUE);
if (vert)
{
/* First the vertical pass */
for (col = 0; col < width; col++)
{
for (i = 0; i < height * bytes; i++)
{
val_p[i] = val_m[i] = 0;
}
gimp_pixel_rgn_get_col (&src_rgn, src, col + x1, y1, (y2 - y1));
sp_p = src;
sp_m = src + (height - 1) * bytes;
vp = val_p;
vm = val_m + (height - 1) * bytes;
/* Set up the first vals */
for (i = 0; i < bytes; i++)
{
initial_p[i] = sp_p[i];
initial_m[i] = sp_m[i];
}
for (row = 0; row < height; row++)
{
terms = (row < 4) ? row : 4;
for (b = 0; b < bytes; b++)
{
for (i = 0; i <= terms; i++)
{
vp[b] += n_p[i] * sp_p[(-i * bytes) + b] -
d_p[i] * vp[(-i * bytes) + b];
vm[b] += n_m[i] * sp_m[(i * bytes) + b] -
d_m[i] * vm[(i * bytes) + b];
}
for (j = i; j <= 4; j++)
{
vp[b] += (n_p[j] - bd_p[j]) * initial_p[b];
vm[b] += (n_m[j] - bd_m[j]) * initial_m[b];
}
}
sp_p += bytes;
sp_m -= bytes;
vp += bytes;
vm -= bytes;
}
transfer_pixels (val_p, val_m, dest, bytes, height);
gimp_pixel_rgn_set_col (&dest_rgn, dest, col + x1, y1, (y2 - y1));
progress += height;
if ((col % 5) == 0)
gimp_progress_update ((double) progress / (double) max_progress);
}
/* prepare for the horizontal pass */
gimp_pixel_rgn_init (&src_rgn, drawable, 0, 0, drawable->width, drawable->height, FALSE, TRUE);
}
if (horz)
{
/* Now the horizontal pass */
for (row = 0; row < height; row++)
{
for (i = 0; i < width * bytes; i++)
{
val_p[i] = val_m[i] = 0;
}
gimp_pixel_rgn_get_row (&src_rgn, src, x1, row + y1, (x2 - x1));
sp_p = src;
sp_m = src + (width - 1) * bytes;
vp = val_p;
vm = val_m + (width - 1) * bytes;
/* Set up the first vals */
for (i = 0; i < bytes; i++)
{
initial_p[i] = sp_p[i];
initial_m[i] = sp_m[i];
}
for (col = 0; col < width; col++)
{
terms = (col < 4) ? col : 4;
for (b = 0; b < bytes; b++)
{
for (i = 0; i <= terms; i++)
{
vp[b] += n_p[i] * sp_p[(-i * bytes) + b] -
d_p[i] * vp[(-i * bytes) + b];
vm[b] += n_m[i] * sp_m[(i * bytes) + b] -
d_m[i] * vm[(i * bytes) + b];
}
for (j = i; j <= 4; j++)
{
vp[b] += (n_p[j] - bd_p[j]) * initial_p[b];
vm[b] += (n_m[j] - bd_m[j]) * initial_m[b];
}
}
sp_p += bytes;
sp_m -= bytes;
vp += bytes;
vm -= bytes;
}
transfer_pixels (val_p, val_m, dest, bytes, width);
gimp_pixel_rgn_set_row (&dest_rgn, dest, x1, row + y1, (x2 - x1));
progress += width;
if ((row % 5) == 0)
gimp_progress_update ((double) progress / (double) max_progress);
}
}
/* merge the shadow, update the drawable */
gimp_drawable_flush (drawable);
gimp_drawable_merge_shadow (drawable->id, TRUE);
gimp_drawable_update (drawable->id, x1, y1, (x2 - x1), (y2 - y1));
/* free up buffers */
free (val_p);
free (val_m);
free (src);
free (dest);
}
static void
find_constants (gdouble n_p[],
gdouble n_m[],
gdouble d_p[],
gdouble d_m[],
gdouble bd_p[],
gdouble bd_m[],
gdouble std_dev)
{
gint i;
gdouble constants [8];
gdouble div;
/* The constants used in the implemenation of a casual sequence
* using a 4th order approximation of the gaussian operator
*/
div = sqrt(2 * M_PI) * std_dev;
constants [0] = -1.783 / std_dev;
constants [1] = -1.723 / std_dev;
constants [2] = 0.6318 / std_dev;
constants [3] = 1.997 / std_dev;
constants [4] = 1.6803 / div;
constants [5] = 3.735 / div;
constants [6] = -0.6803 / div;
constants [7] = -0.2598 / div;
n_p [0] = constants[4] + constants[6];
n_p [1] = exp (constants[1]) *
(constants[7] * sin (constants[3]) -
(constants[6] + 2 * constants[4]) * cos (constants[3])) +
exp (constants[0]) *
(constants[5] * sin (constants[2]) -
(2 * constants[6] + constants[4]) * cos (constants[2]));
n_p [2] = 2 * exp (constants[0] + constants[1]) *
((constants[4] + constants[6]) * cos (constants[3]) * cos (constants[2]) -
constants[5] * cos (constants[3]) * sin (constants[2]) -
constants[7] * cos (constants[2]) * sin (constants[3])) +
constants[6] * exp (2 * constants[0]) +
constants[4] * exp (2 * constants[1]);
n_p [3] = exp (constants[1] + 2 * constants[0]) *
(constants[7] * sin (constants[3]) - constants[6] * cos (constants[3])) +
exp (constants[0] + 2 * constants[1]) *
(constants[5] * sin (constants[2]) - constants[4] * cos (constants[2]));
n_p [4] = 0.0;
d_p [0] = 0.0;
d_p [1] = -2 * exp (constants[1]) * cos (constants[3]) -
2 * exp (constants[0]) * cos (constants[2]);
d_p [2] = 4 * cos (constants[3]) * cos (constants[2]) * exp (constants[0] + constants[1]) +
exp (2 * constants[1]) + exp (2 * constants[0]);
d_p [3] = -2 * cos (constants[2]) * exp (constants[0] + 2 * constants[1]) -
2 * cos (constants[3]) * exp (constants[1] + 2 * constants[0]);
d_p [4] = exp (2 * constants[0] + 2 * constants[1]);
for (i = 0; i <= 4; i++)
d_m [i] = d_p [i];
n_m[0] = 0.0;
for (i = 1; i <= 4; i++)
n_m [i] = n_p[i] - d_p[i] * n_p[0];
{
gdouble sum_n_p, sum_n_m, sum_d;
gdouble a, b;
sum_n_p = 0.0;
sum_n_m = 0.0;
sum_d = 0.0;
for (i = 0; i <= 4; i++)
{
sum_n_p += n_p[i];
sum_n_m += n_m[i];
sum_d += d_p[i];
}
a = sum_n_p / (1 + sum_d);
b = sum_n_m / (1 + sum_d);
for (i = 0; i <= 4; i++)
{
bd_p[i] = d_p[i] * a;
bd_m[i] = d_m[i] * b;
}
}
}
static void
transfer_pixels (gdouble *src1,
gdouble *src2,
guchar *dest,
gint bytes,
gint width)
{
gint b;
gdouble sum;
while (width --)
{
for (b = 0; b < bytes; b++)
{
sum = src1[b] + src2[b];
if (sum > 255) sum = 255;
else if (sum < 0) sum = 0;
dest[b] = (guchar) sum;
}
src1 += bytes;
src2 += bytes;
dest += bytes;
}
}
/* Gauss interface functions */
static void
gauss_close_callback (GtkWidget *widget,
gpointer data)
{
gtk_main_quit ();
}
static void
gauss_ok_callback (GtkWidget *widget,
gpointer data)
{
bint.run = TRUE;
gtk_widget_destroy (GTK_WIDGET (data));
}
static void
gauss_toggle_update (GtkWidget *widget,
gpointer data)
{
int *toggle_val;
toggle_val = (int *) data;
if (GTK_TOGGLE_BUTTON (widget)->active)
*toggle_val = TRUE;
else
*toggle_val = FALSE;
}
static void
gauss_entry_callback (GtkWidget *widget,
gpointer data)
{
bvals.radius = atof (gtk_entry_get_text (GTK_ENTRY (widget)));
if (bvals.radius < 1.0)
bvals.radius = 1.0;
}

View File

@ -1,610 +0,0 @@
/* The GIMP -- an image manipulation program
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* 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
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include "gtk/gtk.h"
#include "libgimp/gimp.h"
#define ENTRY_WIDTH 100
typedef struct
{
gdouble radius;
gint horizontal;
gint vertical;
} BlurValues;
typedef struct
{
gint run;
} BlurInterface;
/* Declare local functions.
*/
static void query (void);
static void run (gchar *name,
gint nparams,
GParam *param,
gint *nreturn_vals,
GParam **return_vals);
static void gauss_rle (GDrawable *drawable,
gint horizontal,
gint vertical,
gdouble std_dev);
/*
* Gaussian blur interface
*/
static gint gauss_rle_dialog (void);
/*
* Gaussian blur helper functions
*/
static gint * make_curve (gdouble sigma,
gint * length);
static void run_length_encode (guchar * src,
gint * dest,
gint bytes,
gint width);
static void gauss_close_callback (GtkWidget *widget,
gpointer data);
static void gauss_ok_callback (GtkWidget *widget,
gpointer data);
static void gauss_toggle_update (GtkWidget *widget,
gpointer data);
static void gauss_entry_callback (GtkWidget *widget,
gpointer data);
GPlugInInfo PLUG_IN_INFO =
{
NULL, /* init_proc */
NULL, /* quit_proc */
query, /* query_proc */
run, /* run_proc */
};
static BlurValues bvals =
{
5.0, /* radius */
TRUE, /* horizontal blur */
TRUE /* vertical blur */
};
static BlurInterface bint =
{
FALSE /* run */
};
MAIN ()
static void
query ()
{
static GParamDef args[] =
{
{ PARAM_INT32, "run_mode", "Interactive, non-interactive" },
{ PARAM_IMAGE, "image", "Input image (unused)" },
{ PARAM_DRAWABLE, "drawable", "Input drawable" },
{ PARAM_FLOAT, "radius", "Radius of gaussian blur (in pixels > 1.0)" },
{ PARAM_INT32, "horizontal", "Blur in horizontal direction" },
{ PARAM_INT32, "vertical", "Blur in vertical direction" },
};
static GParamDef *return_vals = NULL;
static gint nargs = sizeof (args) / sizeof (args[0]);
static gint nreturn_vals = 0;
gimp_install_procedure ("plug_in_gauss_rle",
"Applies a gaussian blur to the specified drawable.",
"Applies a gaussian blur to the drawable, with specified radius of affect. The standard deviation of the normal distribution used to modify pixel values is calculated based on the supplied radius. Horizontal and vertical blurring can be independently invoked by specifying only one to run. The RLE gaussian blurring performs most efficiently on computer-generated images or images with large areas of constant intensity. Values for radii less than 1.0 are invalid as they will generate spurious results.",
"Spencer Kimball & Peter Mattis",
"Spencer Kimball & Peter Mattis",
"1995-1996",
"<Image>/Filters/Blur/Gaussian Blur (RLE)",
"RGB*, GRAY*",
PROC_PLUG_IN,
nargs, nreturn_vals,
args, return_vals);
}
static void
run (gchar *name,
gint nparams,
GParam *param,
gint *nreturn_vals,
GParam **return_vals)
{
static GParam values[1];
GDrawable *drawable;
GRunModeType run_mode;
GStatusType status = STATUS_SUCCESS;
gdouble radius, std_dev;
run_mode = param[0].data.d_int32;
*nreturn_vals = 1;
*return_vals = values;
values[0].type = PARAM_STATUS;
values[0].data.d_status = status;
switch (run_mode)
{
case RUN_INTERACTIVE:
/* Possibly retrieve data */
gimp_get_data ("plug_in_gauss_rle", &bvals);
/* First acquire information with a dialog */
if (! gauss_rle_dialog ())
return;
break;
case RUN_NONINTERACTIVE:
/* Make sure all the arguments are there! */
if (nparams != 6)
status = STATUS_CALLING_ERROR;
if (status == STATUS_SUCCESS)
{
bvals.radius = param[3].data.d_float;
bvals.horizontal = (param[4].data.d_int32) ? TRUE : FALSE;
bvals.vertical = (param[5].data.d_int32) ? TRUE : FALSE;
}
if (status == STATUS_SUCCESS &&
(bvals.radius < 1.0))
status = STATUS_CALLING_ERROR;
break;
case RUN_WITH_LAST_VALS:
/* Possibly retrieve data */
gimp_get_data ("plug_in_gauss_rle", &bvals);
break;
default:
break;
}
/* 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 ("RLE Gaussian Blur");
/* set the tile cache size so that the gaussian blur works well */
gimp_tile_cache_ntiles (2 * (MAX (drawable->width, drawable->height) /
gimp_tile_width () + 1));
radius = fabs (bvals.radius) + 1.0;
std_dev = sqrt (-(radius * radius) / (2 * log (1.0 / 255.0)));
/* run the gaussian blur */
gauss_rle (drawable, bvals.horizontal, bvals.vertical, std_dev);
if (run_mode != RUN_NONINTERACTIVE)
gimp_displays_flush ();
/* Store data */
if (run_mode == RUN_INTERACTIVE)
gimp_set_data ("plug_in_gauss_rle", &bvals, sizeof (BlurValues));
}
else
{
/* gimp_message ("gauss_rle: cannot operate on indexed color images"); */
status = STATUS_EXECUTION_ERROR;
}
values[0].data.d_status = status;
gimp_drawable_detach (drawable);
}
static gint
gauss_rle_dialog ()
{
GtkWidget *dlg;
GtkWidget *label;
GtkWidget *entry;
GtkWidget *button;
GtkWidget *toggle;
GtkWidget *frame;
GtkWidget *vbox;
GtkWidget *hbox;
gchar buffer[12];
gchar **argv;
gint argc;
argc = 1;
argv = g_new (gchar *, 1);
argv[0] = g_strdup ("gauss");
gtk_init (&argc, &argv);
gtk_rc_parse (gimp_gtkrc ());
dlg = gtk_dialog_new ();
gtk_window_set_title (GTK_WINDOW (dlg), "RLE Gaussian Blur");
gtk_window_position (GTK_WINDOW (dlg), GTK_WIN_POS_MOUSE);
gtk_signal_connect (GTK_OBJECT (dlg), "destroy",
(GtkSignalFunc) gauss_close_callback,
NULL);
/* Action area */
button = gtk_button_new_with_label ("OK");
GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
gtk_signal_connect (GTK_OBJECT (button), "clicked",
(GtkSignalFunc) gauss_ok_callback,
dlg);
gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dlg)->action_area), button, TRUE, TRUE, 0);
gtk_widget_grab_default (button);
gtk_widget_show (button);
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));
gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dlg)->action_area), button, TRUE, TRUE, 0);
gtk_widget_show (button);
/* parameter settings */
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);
vbox = gtk_vbox_new (FALSE, 5);
gtk_container_border_width (GTK_CONTAINER (vbox), 10);
gtk_container_add (GTK_CONTAINER (frame), vbox);
toggle = gtk_check_button_new_with_label ("Blur Horizontally");
gtk_box_pack_start (GTK_BOX (vbox), toggle, TRUE, TRUE, 0);
gtk_signal_connect (GTK_OBJECT (toggle), "toggled",
(GtkSignalFunc) gauss_toggle_update,
&bvals.horizontal);
gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (toggle), bvals.horizontal);
gtk_widget_show (toggle);
toggle = gtk_check_button_new_with_label ("Blur Vertically");
gtk_box_pack_start (GTK_BOX (vbox), toggle, TRUE, TRUE, 0);
gtk_signal_connect (GTK_OBJECT (toggle), "toggled",
(GtkSignalFunc) gauss_toggle_update,
&bvals.vertical);
gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (toggle), bvals.vertical);
gtk_widget_show (toggle);
hbox = gtk_hbox_new (FALSE, 5);
gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, TRUE, 0);
label = gtk_label_new ("Blur Radius: ");
gtk_box_pack_start (GTK_BOX (hbox), label, TRUE, FALSE, 0);
gtk_widget_show (label);
entry = gtk_entry_new ();
gtk_box_pack_start (GTK_BOX (hbox), entry, TRUE, TRUE, 0);
gtk_widget_set_usize (entry, ENTRY_WIDTH, 0);
sprintf (buffer, "%f", bvals.radius);
gtk_entry_set_text (GTK_ENTRY (entry), buffer);
gtk_signal_connect (GTK_OBJECT (entry), "changed",
(GtkSignalFunc) gauss_entry_callback,
NULL);
gtk_widget_show (entry);
gtk_widget_show (hbox);
gtk_widget_show (vbox);
gtk_widget_show (frame);
gtk_widget_show (dlg);
gtk_main ();
gdk_flush ();
return bint.run;
}
static void
gauss_rle (GDrawable *drawable,
gint horz,
gint vert,
gdouble std_dev)
{
GPixelRgn src_rgn, dest_rgn;
gint width, height;
gint bytes;
guchar *dest, *dp;
guchar *src, *sp;
gint *buf, *bb;
gint pixels;
gint total;
gint x1, y1, x2, y2;
gint i, row, col, b;
gint start, end;
gint progress, max_progress;
gint *curve;
gint *sum;
gint val;
gint length;
gint initial_p, initial_m;
curve = make_curve (std_dev, &length);
sum = malloc (sizeof (gint) * (2 * length + 1));
sum[0] = 0;
for (i = 1; i <= length*2; i++)
sum[i] = curve[i-length-1] + sum[i-1];
sum += length;
gimp_drawable_mask_bounds (drawable->id, &x1, &y1, &x2, &y2);
width = (x2 - x1);
height = (y2 - y1);
bytes = drawable->bpp;
buf = (gint *) malloc (sizeof (gint) * MAX (width, height) * 2);
total = sum[length] - sum[-length];
/* allocate buffers for source and destination pixels */
src = (guchar *) malloc (MAX (width, height) * bytes);
dest = (guchar *) malloc (MAX (width, height) * bytes);
gimp_pixel_rgn_init (&src_rgn, drawable, 0, 0, drawable->width, drawable->height, FALSE, FALSE);
gimp_pixel_rgn_init (&dest_rgn, drawable, 0, 0, drawable->width, drawable->height, TRUE, TRUE);
progress = 0;
max_progress = (horz) ? width * height : 0;
max_progress += (vert) ? width * height : 0;
if (vert)
{
for (col = 0; col < width; col++)
{
gimp_pixel_rgn_get_col (&src_rgn, src, col + x1, y1, (y2 - y1));
sp = src;
dp = dest;
for (b = 0; b < bytes; b++)
{
initial_p = sp[b];
initial_m = sp[(height-1) * bytes + b];
/* Determine a run-length encoded version of the row */
run_length_encode (sp + b, buf, bytes, height);
for (row = 0; row < height; row++)
{
start = (row < length) ? -row : -length;
end = (height <= (row + length)) ? (height - row - 1) : length;
val = 0;
i = start;
bb = buf + (row + i) * 2;
if (start != -length)
val += initial_p * (sum[start] - sum[-length]);
while (i < end)
{
pixels = bb[0];
i += pixels;
if (i > end)
i = end;
val += bb[1] * (sum[i] - sum[start]);
bb += (pixels * 2);
start = i;
}
if (end != length)
val += initial_m * (sum[length] - sum[end]);
dp[row * bytes + b] = val / total;
}
}
gimp_pixel_rgn_set_col (&dest_rgn, dest, col + x1, y1, (y2 - y1));
progress += height;
if ((col % 5) == 0)
gimp_progress_update ((double) progress / (double) max_progress);
}
/* prepare for the horizontal pass */
gimp_pixel_rgn_init (&src_rgn, drawable, 0, 0, drawable->width, drawable->height, FALSE, TRUE);
}
if (horz)
{
for (row = 0; row < height; row++)
{
gimp_pixel_rgn_get_row (&src_rgn, src, x1, row + y1, (x2 - x1));
sp = src;
dp = dest;
for (b = 0; b < bytes; b++)
{
initial_p = sp[b];
initial_m = sp[(width-1) * bytes + b];
/* Determine a run-length encoded version of the row */
run_length_encode (sp + b, buf, bytes, width);
for (col = 0; col < width; col++)
{
start = (col < length) ? -col : -length;
end = (width <= (col + length)) ? (width - col - 1) : length;
val = 0;
i = start;
bb = buf + (col + i) * 2;
if (start != -length)
val += initial_p * (sum[start] - sum[-length]);
while (i < end)
{
pixels = bb[0];
i += pixels;
if (i > end)
i = end;
val += bb[1] * (sum[i] - sum[start]);
bb += (pixels * 2);
start = i;
}
if (end != length)
val += initial_m * (sum[length] - sum[end]);
dp[col * bytes + b] = val / total;
}
}
gimp_pixel_rgn_set_row (&dest_rgn, dest, x1, row + y1, (x2 - x1));
progress += width;
if ((row % 5) == 0)
gimp_progress_update ((double) progress / (double) max_progress);
}
}
/* merge the shadow, update the drawable */
gimp_drawable_flush (drawable);
gimp_drawable_merge_shadow (drawable->id, TRUE);
gimp_drawable_update (drawable->id, x1, y1, (x2 - x1), (y2 - y1));
/* free buffers */
free (buf);
free (src);
free (dest);
}
/*
* The equations: g(r) = exp (- r^2 / (2 * sigma^2))
* r = sqrt (x^2 + y ^2)
*/
static gint *
make_curve (gdouble sigma,
gint *length)
{
gint *curve;
gdouble sigma2;
gdouble l;
gint temp;
gint i, n;
sigma2 = 2 * sigma * sigma;
l = sqrt (-sigma2 * log (1.0 / 255.0));
n = ceil (l) * 2;
if ((n % 2) == 0)
n += 1;
curve = malloc (sizeof (gint) * n);
*length = n / 2;
curve += *length;
curve[0] = 255;
for (i = 1; i <= *length; i++)
{
temp = (gint) (exp (- (i * i) / sigma2) * 255);
curve[-i] = temp;
curve[i] = temp;
}
return curve;
}
static void
run_length_encode (guchar *src,
gint *dest,
gint bytes,
gint width)
{
gint start;
gint i;
gint j;
guchar last;
last = *src;
src += bytes;
start = 0;
for (i = 1; i < width; i++)
{
if (*src != last)
{
for (j = start; j < i; j++)
{
*dest++ = (i - j);
*dest++ = last;
}
start = i;
last = *src;
}
src += bytes;
}
for (j = start; j < i; j++)
{
*dest++ = (i - j);
*dest++ = last;
}
}
/* Gauss interface functions */
static void
gauss_close_callback (GtkWidget *widget,
gpointer data)
{
gtk_main_quit ();
}
static void
gauss_ok_callback (GtkWidget *widget,
gpointer data)
{
bint.run = TRUE;
gtk_widget_destroy (GTK_WIDGET (data));
}
static void
gauss_toggle_update (GtkWidget *widget,
gpointer data)
{
int *toggle_val;
toggle_val = (int *) data;
if (GTK_TOGGLE_BUTTON (widget)->active)
*toggle_val = TRUE;
else
*toggle_val = FALSE;
}
static void
gauss_entry_callback (GtkWidget *widget,
gpointer data)
{
bvals.radius = atof (gtk_entry_get_text (GTK_ENTRY (widget)));
if (bvals.radius < 1.0)
bvals.radius = 1.0;
}

View File

@ -1,450 +0,0 @@
/*
* gbr plug-in version 1.00
* Loads/saves version 2 GIMP .gbr files, by Tim Newsome <drz@frody.bloke.com>
* Some bits stolen from the .99.7 source tree.
*/
#include <setjmp.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include "gtk/gtk.h"
#include "libgimp/gimp.h"
#include "app/brush_header.h"
#include <netinet/in.h>
/* Declare local data types
*/
typedef struct {
char description[256];
unsigned int spacing;
} t_info;
t_info info = { /* Initialize to this, change if non-interactive later */
"GIMP Brush",
10
};
int run_flag = 0;
/* Declare some local functions.
*/
static void query (void);
static void run (char *name,
int nparams,
GParam *param,
int *nreturn_vals,
GParam **return_vals);
static gint32 load_image (char *filename);
static gint save_image (char *filename,
gint32 image_ID,
gint32 drawable_ID);
static gint save_dialog ();
static void close_callback(GtkWidget * widget, gpointer data);
static void ok_callback(GtkWidget * widget, gpointer data);
static void entry_callback(GtkWidget * widget, gpointer data);
GPlugInInfo PLUG_IN_INFO =
{
NULL, /* init_proc */
NULL, /* quit_proc */
query, /* query_proc */
run, /* run_proc */
};
MAIN ()
static void
query ()
{
static GParamDef load_args[] =
{
{ PARAM_INT32, "run_mode", "Interactive, non-interactive" },
{ PARAM_STRING, "filename", "The name of the file to load" },
{ PARAM_STRING, "raw_filename", "The name of the file to load" },
};
static GParamDef load_return_vals[] =
{
{ PARAM_IMAGE, "image", "Output image" },
};
static int nload_args = sizeof (load_args) / sizeof (load_args[0]);
static int nload_return_vals = sizeof (load_return_vals) / sizeof (load_return_vals[0]);
static GParamDef save_args[] =
{
{ PARAM_INT32, "run_mode", "Interactive, non-interactive" },
{ PARAM_IMAGE, "image", "Input image" },
{ PARAM_DRAWABLE, "drawable", "Drawable to save" },
{ PARAM_STRING, "filename", "The name of the file to save the image in" },
{ PARAM_STRING, "raw_filename", "The name of the file to save the image in" },
{ PARAM_INT32, "spacing", "Spacing of the brush" },
{ PARAM_STRING, "description", "Short description of the brush" },
};
static int nsave_args = sizeof (save_args) / sizeof (save_args[0]);
gimp_install_procedure ("file_gbr_load",
"loads files of the .gbr file format",
"FIXME: write help",
"Tim Newsome",
"Tim Newsome",
"1997",
"<Load>/GBR",
NULL,
PROC_PLUG_IN,
nload_args, nload_return_vals,
load_args, load_return_vals);
gimp_install_procedure ("file_gbr_save",
"saves files in the .gbr file format",
"Yeah!",
"Tim Newsome",
"Tim Newsome",
"1997",
"<Save>/GBR",
"RGB*, GRAY*",
PROC_PLUG_IN,
nsave_args, 0,
save_args, NULL);
gimp_register_magic_load_handler ("file_gbr_load", "gbr", "", "20,string,GIMP");
gimp_register_save_handler ("file_gbr_save", "gbr", "");
}
static void
run (char *name,
int nparams,
GParam *param,
int *nreturn_vals,
GParam **return_vals)
{
static GParam values[2];
GRunModeType run_mode;
gint32 image_ID;
GStatusType status = STATUS_SUCCESS;
run_mode = param[0].data.d_int32;
*return_vals = values;
values[0].type = PARAM_STATUS;
values[0].data.d_status = STATUS_CALLING_ERROR;
values[1].type = PARAM_IMAGE;
values[1].data.d_image = -1;
if (strcmp (name, "file_gbr_load") == 0) {
image_ID = load_image (param[1].data.d_string);
if (image_ID != -1) {
values[0].data.d_status = STATUS_SUCCESS;
values[1].data.d_image = image_ID;
} else {
values[0].data.d_status = STATUS_EXECUTION_ERROR;
}
*nreturn_vals = 2;
}
else if (strcmp (name, "file_gbr_save") == 0) {
switch (run_mode) {
case RUN_INTERACTIVE:
/* Possibly retrieve data */
gimp_get_data("file_gbr_save", &info);
if (!save_dialog())
return;
break;
case RUN_NONINTERACTIVE: /* FIXME - need a real RUN_NONINTERACTIVE */
if (nparams != 7)
status = STATUS_CALLING_ERROR;
if (status == STATUS_SUCCESS)
{
info.spacing = (param[5].data.d_int32);
strncpy (info.description, param[6].data.d_string, 256);
}
break;
case RUN_WITH_LAST_VALS:
gimp_get_data ("file_gbr_save", &info);
break;
}
if (save_image (param[3].data.d_string, param[1].data.d_int32,
param[2].data.d_int32)) {
gimp_set_data ("file_gbr_save", &info, sizeof(info));
values[0].data.d_status = STATUS_SUCCESS;
} else
values[0].data.d_status = STATUS_EXECUTION_ERROR;
*nreturn_vals = 1;
}
}
static gint32 load_image (char *filename) {
char *temp;
int fd;
BrushHeader ph;
gchar *buffer;
gint32 image_ID, layer_ID;
GDrawable *drawable;
gint line;
GPixelRgn pixel_rgn;
temp = g_malloc(strlen (filename) + 11);
sprintf(temp, "Loading %s:", filename);
gimp_progress_init(temp);
g_free (temp);
fd = open(filename, O_RDONLY);
if (fd == -1) {
return -1;
}
if (read(fd, &ph, sizeof(ph)) != sizeof(ph)) {
close(fd);
return -1;
}
/* rearrange the bytes in each unsigned int */
ph.header_size = ntohl(ph.header_size);
ph.version = ntohl(ph.version);
ph.width = ntohl(ph.width);
ph.height = ntohl(ph.height);
ph.bytes = ntohl(ph.bytes);
ph.magic_number = ntohl(ph.magic_number);
ph.spacing = ntohl(ph.spacing);
if (ph.magic_number != GBRUSH_MAGIC || ph.version != 2 ||
ph.header_size <= sizeof(ph)) {
close(fd);
return -1;
}
if (lseek(fd, ph.header_size - sizeof(ph), SEEK_CUR) !=
ph.header_size) {
close(fd);
return -1;
}
/* Now there's just raw data left. */
/*
* Create a new image of the proper size and associate the filename with it.
*/
image_ID = gimp_image_new(ph.width, ph.height, (ph.bytes >= 3) ? RGB : GRAY);
gimp_image_set_filename(image_ID, filename);
layer_ID = gimp_layer_new(image_ID, "Background", ph.width, ph.height,
(ph.bytes >= 3) ? RGB_IMAGE : GRAY_IMAGE, 100, NORMAL_MODE);
gimp_image_add_layer(image_ID, layer_ID, 0);
drawable = gimp_drawable_get(layer_ID);
gimp_pixel_rgn_init(&pixel_rgn, drawable, 0, 0, drawable->width,
drawable->height, TRUE, FALSE);
buffer = g_malloc(ph.width * ph.bytes);
for (line = 0; line < ph.height; line++) {
if (read(fd, buffer, ph.width * ph.bytes) != ph.width * ph.bytes) {
close(fd);
g_free(buffer);
return -1;
}
gimp_pixel_rgn_set_row(&pixel_rgn, buffer, 0, line, ph.width);
gimp_progress_update((double) line / (double) ph.height);
}
gimp_drawable_flush(drawable);
return image_ID;
}
static gint save_image (char *filename, gint32 image_ID, gint32 drawable_ID) {
int fd;
BrushHeader ph;
unsigned char *buffer;
GDrawable *drawable;
gint line;
GPixelRgn pixel_rgn;
char *temp;
temp = g_malloc(strlen (filename) + 10);
sprintf(temp, "Saving %s:", filename);
gimp_progress_init(temp);
g_free(temp);
drawable = gimp_drawable_get(drawable_ID);
gimp_pixel_rgn_init(&pixel_rgn, drawable, 0, 0, drawable->width,
drawable->height, FALSE, FALSE);
fd = open(filename, O_CREAT | O_TRUNC | O_WRONLY, 0644);
if (fd == -1) {
printf("Unable to open %s\n", filename);
return 0;
}
ph.header_size = htonl(sizeof(ph) + strlen(info.description) + 1);
ph.version = htonl(2);
ph.width = htonl(drawable->width);
ph.height = htonl(drawable->height);
ph.bytes = htonl(drawable->bpp);
ph.magic_number = htonl(GBRUSH_MAGIC);
ph.spacing = htonl(info.spacing);
if (write(fd, &ph, sizeof(ph)) != sizeof(ph)) {
close(fd);
return 0;
}
if (write(fd, info.description, strlen(info.description) + 1) !=
strlen(info.description) + 1) {
close(fd);
return 0;
}
buffer = g_malloc(drawable->width * drawable->bpp);
if (buffer == NULL) {
close(fd);
return 0;
}
for (line = 0; line < drawable->height; line++) {
gimp_pixel_rgn_get_row(&pixel_rgn, buffer, 0, line, drawable->width);
if (write(fd, buffer, drawable->width * drawable->bpp) !=
drawable->width * drawable->bpp) {
close(fd);
return 0;
}
gimp_progress_update((double) line / (double) drawable->height);
}
g_free(buffer);
close(fd);
return 1;
}
static gint save_dialog()
{
GtkWidget *dlg;
GtkWidget *button;
GtkWidget *label;
GtkWidget *entry;
GtkWidget *table;
gchar **argv;
gint argc;
gchar buffer[12];
argc = 1;
argv = g_new(gchar *, 1);
argv[0] = g_strdup("plasma");
gtk_init(&argc, &argv);
gtk_rc_parse (gimp_gtkrc ());
dlg = gtk_dialog_new();
gtk_window_set_title(GTK_WINDOW(dlg), "Save As Brush");
gtk_window_position(GTK_WINDOW(dlg), GTK_WIN_POS_MOUSE);
gtk_signal_connect(GTK_OBJECT(dlg), "destroy",
(GtkSignalFunc) close_callback, NULL);
/* Action area */
button = gtk_button_new_with_label("OK");
GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT);
gtk_signal_connect(GTK_OBJECT(button), "clicked",
(GtkSignalFunc) ok_callback,
dlg);
gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dlg)->action_area), button, TRUE, TRUE, 0);
gtk_widget_grab_default(button);
gtk_widget_show(button);
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));
gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dlg)->action_area), button, TRUE, TRUE, 0);
gtk_widget_show(button);
/* The main table */
/* Set its size (y, x) */
table = gtk_table_new(2, 2, FALSE);
gtk_container_border_width(GTK_CONTAINER(table), 10);
gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dlg)->vbox), table, TRUE, TRUE, 0);
gtk_widget_show(table);
gtk_table_set_row_spacings(GTK_TABLE(table), 10);
gtk_table_set_col_spacings(GTK_TABLE(table), 10);
/**********************
* label
**********************/
label = gtk_label_new("Spacing:");
gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
gtk_table_attach(GTK_TABLE(table), label, 0, 1, 0, 1, GTK_FILL, GTK_FILL, 0,
0);
gtk_widget_show(label);
/************************
* The entry
************************/
entry = gtk_entry_new();
gtk_table_attach(GTK_TABLE(table), entry, 1, 2, 0, 1, GTK_EXPAND | GTK_FILL,
GTK_EXPAND | GTK_FILL, 0, 0);
gtk_widget_set_usize(entry, 200, 0);
sprintf(buffer, "%i", info.spacing);
gtk_entry_set_text(GTK_ENTRY(entry), buffer);
gtk_signal_connect(GTK_OBJECT(entry), "changed",
(GtkSignalFunc) entry_callback, &info.spacing);
gtk_widget_show(entry);
/**********************
* label
**********************/
label = gtk_label_new("Description:");
gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
gtk_table_attach(GTK_TABLE(table), label, 0, 1, 1, 2, GTK_FILL, GTK_FILL, 0,
0);
gtk_widget_show(label);
/************************
* The entry
************************/
entry = gtk_entry_new();
gtk_table_attach(GTK_TABLE(table), entry, 1, 2, 1, 2, GTK_EXPAND | GTK_FILL,
GTK_EXPAND | GTK_FILL, 0, 0);
gtk_widget_set_usize(entry, 200, 0);
gtk_entry_set_text(GTK_ENTRY(entry), info.description);
gtk_signal_connect(GTK_OBJECT(entry), "changed",
(GtkSignalFunc) entry_callback, info.description);
gtk_widget_show(entry);
gtk_widget_show(dlg);
gtk_main();
gdk_flush();
return run_flag;
}
static void close_callback(GtkWidget * widget, gpointer data)
{
gtk_main_quit();
}
static void ok_callback(GtkWidget * widget, gpointer data)
{
run_flag = 1;
gtk_widget_destroy(GTK_WIDGET(data));
}
static void entry_callback(GtkWidget * widget, gpointer data)
{
if (data == info.description)
strncpy(info.description, gtk_entry_get_text(GTK_ENTRY(widget)), 256);
else if (data == &info.spacing)
info.spacing = atoi(gtk_entry_get_text(GTK_ENTRY(widget)));
}

View File

@ -1,467 +0,0 @@
/*
* GFLI 1.0
*
* A gimp plug-in to read FLI and FLC movies.
*
* Copyright (C) 1997 Jens Ch. Restemeier <jchrr@hrz.uni-bielefeld.de>
*
* 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
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* This is a first loader for FLI and FLC movies. It uses as the same method as
* the gif plug-in to store the animation (i.e. 1 layer/frame).
*
* Current disadvantages:
* - All frames must share the same colormap. Maybe I add an option for
* generating RGB images in the next version !
* - Generates A LOT OF warnings.
* - Consumes a lot of memory (See wish-list: use the original data or
* compression).
* - doesn't save movies (will be added to next version, depends on
* feedback). You can save as animated GIF, of course...
*
* Wish-List:
* - I'd like to have a different format for storing animations, so I can use
* Layers and Alpha-Channels for effects. I'm working on another movie-loader
* that _requires_ layers (Gold Disk moviesetter). An older version of
* this plug-in created one image per frame, and went real soon out of
* memory.
* - I'd like a method that requests unmodified frames from the original
* image, and stores modified frames compressed (suggestion: libpng).
* - I'd like a way to store additional information about a image to it, for
* example copyright stuff or a timecode.
*
* Ideas:
* - I could put all the functions for loading / saving fli into a
* gimp-independant library. Anybody interested to save fli from his
* application ?
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "gtk/gtk.h"
#include "libgimp/gimp.h"
#ifdef __GNUC__
#define inline inline
#else
#define inline
#endif
static void query (void);
static void run (char *name,
int nparams,
GParam *param,
int *nreturn_vals,
GParam **return_vals);
gint32 load_image (char *filename);
GPlugInInfo PLUG_IN_INFO =
{
NULL, /* init_proc */
NULL, /* quit_proc */
query, /* query_proc */
run, /* run_proc */
};
MAIN ()
static void
query ()
{
static GParamDef load_args[] =
{
{ PARAM_INT32, "run_mode", "Interactive, non-interactive" },
{ PARAM_STRING, "filename", "The name of the file to load" },
{ PARAM_STRING, "raw_filename", "The name entered" },
};
static GParamDef load_return_vals[] =
{
{ PARAM_IMAGE, "image", "Output image" },
};
static int nload_args = sizeof (load_args) / sizeof (load_args[0]);
static int nload_return_vals = sizeof (load_return_vals) / sizeof (load_return_vals[0]);
gimp_install_procedure ("file_fli_load",
"load AA-movies",
"This is a experimantal plug-in to handle FLI movies",
"Jens Ch. Restemeier",
"Jens Ch. Restemeier",
"1997",
"<Load>/FLI",
NULL,
PROC_PLUG_IN,
nload_args, nload_return_vals,
load_args, load_return_vals);
gimp_register_magic_load_handler ("file_fli_load", "fli,flc", "", "5,byte,175 ");
}
static void
run (char *name,
int nparams,
GParam *param,
int *nreturn_vals,
GParam **return_vals)
{
static GParam values[2];
GRunModeType run_mode;
gint32 image_ID;
run_mode = param[0].data.d_int32;
*nreturn_vals = 1;
*return_vals = values;
values[0].type = PARAM_STATUS;
values[0].data.d_status = STATUS_CALLING_ERROR;
if (strcmp (name, "file_fli_load") == 0)
{
image_ID = load_image (param[1].data.d_string);
if (image_ID != -1)
{
*nreturn_vals = 2;
values[0].data.d_status = STATUS_SUCCESS;
values[1].type = PARAM_IMAGE;
values[1].data.d_image = image_ID;
}
else
{
values[0].data.d_status = STATUS_EXECUTION_ERROR;
}
}
}
typedef struct _fli_header {
unsigned long filesize;
unsigned short magic;
unsigned short frames;
unsigned short width;
unsigned short height;
unsigned short depth;
unsigned short flags;
unsigned long speed;
} s_fli_header;
typedef struct _fli_frame {
unsigned long framesize;
unsigned short magic;
unsigned short chunks;
} s_fli_frame;
/* read byte/word/long */
inline unsigned char fli_read_char(FILE *f)
{
unsigned char b;
fread(&b,1,1,f);
return b;
}
inline unsigned short fli_read_short(FILE *f)
{
unsigned char b[2];
fread(&b,1,2,f);
return (unsigned short)(b[1]<<8) | b[0];
}
inline unsigned long fli_read_long(FILE *f)
{
unsigned char b[4];
fread(&b,1,4,f);
return (unsigned long)(b[3]<<24) | (b[2]<<16) | (b[1]<<8) | b[0];
}
void fli_read_header(FILE *f, s_fli_header *fli_header)
{
fli_header->filesize=fli_read_long(f); /* 0 */
fli_header->magic=fli_read_short(f); /* 4 */
fli_header->frames=fli_read_short(f); /* 6 */
fli_header->width=fli_read_short(f); /* 8 */
fli_header->height=fli_read_short(f); /* 10 */
fli_header->depth=fli_read_short(f); /* 12 */
fli_header->flags=fli_read_short(f); /* 14 */
if (fli_header->magic == 0xAF11) { /* FLI */
/* FLI saves speed in 1/70s */
fli_header->speed=fli_read_short(f)*14; /* 16 */
} else {
if (fli_header->magic == 0xAF12) { /* FLC */
/* FLC saves speed in 1/1000s */
fli_header->speed=fli_read_long(f); /* 16 */
} else {
fprintf(stderr, "error: magic number is wrong !\n");
}
}
}
void fli_read_frame(FILE *f, s_fli_header *fli_header, gchar *framebuf, gchar *cmap)
{
s_fli_frame fli_frame;
unsigned long framepos;
int c;
unsigned short col_pos;
col_pos=0;
framepos=ftell(f);
fli_frame.framesize=fli_read_long(f);
fli_frame.magic=fli_read_short(f);
fli_frame.chunks=fli_read_short(f);
if (fli_frame.magic == 0xF1FA) {
fseek(f, framepos+16, SEEK_SET);
for (c=0;c<fli_frame.chunks;c++) {
unsigned long chunkpos, chunksize;
unsigned short chunktype;
chunkpos = ftell(f);
chunksize=fli_read_long(f);
chunktype=fli_read_short(f);
switch (chunktype) {
case 11 : { /* fli_color */
unsigned short num_packets;
int cnt_packets;
num_packets=fli_read_short(f);
for (cnt_packets=num_packets; cnt_packets>0; cnt_packets--) {
unsigned short skip_col, num_col, col_cnt;
skip_col=fli_read_char(f);
num_col=fli_read_char(f);
if (num_col == 0) {
for (col_pos=0; col_pos<768; col_pos++) {
cmap[col_pos]=fli_read_char(f)<<2;
}
} else {
col_pos+=(skip_col*3);
for (col_cnt=num_col; (col_cnt>0) && (col_pos<768); col_cnt--) {
cmap[col_pos++]=fli_read_char(f)<<2;
cmap[col_pos++]=fli_read_char(f)<<2;
cmap[col_pos++]=fli_read_char(f)<<2;
}
}
}
break;
}
case 13 : /* fli_black */
memset(framebuf, 0, fli_header->width * fli_header->height);
break;
case 15 : { /* fli_brun */
unsigned short yc;
char *pos;
for (yc=0; yc< fli_header->height; yc++) {
unsigned short xc, pc, pcnt;
pc=fli_read_char(f);
xc=0;
pos=framebuf+(fli_header->width * yc);
for (pcnt=pc; pcnt>0; pcnt --) {
unsigned short ps;
ps=fli_read_char(f);
if (ps & 0x80) {
unsigned short len;
ps^=0xFF;
ps+=1;
for (len=ps; len>0; len--) {
pos[xc++]=fli_read_char(f);
}
} else {
unsigned char val;
val=fli_read_char(f);
memset(&(pos[xc]), val, ps);
xc+=ps;
}
}
}
break;
}
case 16 : { /* fli_copy */
unsigned long cc;
char *pos;
pos=framebuf;
for (cc=fli_header->width * fli_header->height; cc>0; cc--) {
*(pos++)=fli_read_char(f);
}
break;
}
case 12 : { /* fli_lc */
unsigned short yc, firstline, numline;
char *pos;
firstline = fli_read_short(f);
numline = fli_read_short(f);
for (yc=0; yc < numline; yc++) {
unsigned short xc, pc, pcnt;
pc=fli_read_char(f);
xc=0;
pos=framebuf+(fli_header->width * (firstline+yc));
for (pcnt=pc; pcnt>0; pcnt --) {
unsigned short ps,skip;
skip=fli_read_char(f);
ps=fli_read_char(f);
xc+=skip;
if (ps & 0x80) {
unsigned char val;
ps^=0xFF;
ps+=1;
val=fli_read_char(f);
memset(&(pos[xc]), val, ps);
xc+=ps;
} else {
unsigned short len;
for (len=ps; len>0; len--) {
pos[xc++]=fli_read_char(f);
}
}
}
}
break;
}
case 7 : { /* fli_lc2 */
unsigned short yc, lc, numline;
char *pos;
yc=0;
numline = fli_read_short(f);
for (lc=0; lc < numline; lc++) {
unsigned short xc, pc, pcnt, lpf, lpn;
pc=fli_read_short(f);
lpf=0; lpn=0;
while (pc & 0x8000) {
if (pc & 0x4000) {
yc+=pc & 0x3FFF;
} else {
lpf=1;lpn=pc&0xFF;
}
pc=fli_read_short(f);
}
xc=0;
pos=framebuf+(fli_header->width * yc);
for (pcnt=pc; pcnt>0; pcnt --) {
unsigned short ps,skip;
skip=fli_read_char(f);
ps=fli_read_char(f);
xc+=skip;
if (ps & 0x80) {
unsigned char v1,v2;
ps^=0xFF;
ps++;
v1=fli_read_char(f);
v2=fli_read_char(f);
while (ps>0) {
pos[xc++]=v1;
pos[xc++]=v2;
ps--;
}
} else {
unsigned short len;
for (len=ps; len>0; len--) {
pos[xc++]=fli_read_char(f);
pos[xc++]=fli_read_char(f);
}
}
}
if (lpf) pos[xc]=lpn;
yc++;
}
break;
}
case 4 : { /* fli_color_2 */
unsigned short num_packets;
int cnt_packets;
num_packets=fli_read_short(f);
col_pos=0;
for (cnt_packets=num_packets; cnt_packets>0; cnt_packets--) {
unsigned short skip_col, num_col, col_cnt;
skip_col=fli_read_char(f);
num_col=fli_read_char(f);
if (num_col == 0) {
for (col_pos=0; col_pos<768; col_pos++) {
cmap[col_pos]=fli_read_char(f);
}
} else {
col_pos+=(skip_col+=3);
for (col_cnt=num_col; (col_cnt>0) && (col_pos<768); col_cnt--) {
cmap[col_pos++]=fli_read_char(f);
cmap[col_pos++]=fli_read_char(f);
cmap[col_pos++]=fli_read_char(f);
}
}
}
break;
}
case 18 : /* fli_mini (ignored) */ break;
}
if (chunksize & 1) chunksize++;
fseek(f,chunkpos+chunksize,SEEK_SET);
}
}
fseek(f, framepos+fli_frame.framesize, SEEK_SET);
}
gint32 load_image (char *filename)
{
FILE *f;
char *name_buf;
GDrawable *drawable;
gint32 image_ID, layer_ID;
gchar *frame_buffer;
gchar cmap[768];
GPixelRgn pixel_rgn;
s_fli_header fli_header;
int cnt;
name_buf = g_malloc (64);
sprintf (name_buf, "Loading %s:", filename);
gimp_progress_init (name_buf);
f=fopen(filename ,"r");
if (!f) {
printf ("FLI: can't open \"%s\"\n", filename);
return -1;
}
fli_read_header(f, &fli_header);
fseek(f,128,SEEK_SET);
image_ID = gimp_image_new (fli_header.width, fli_header.height, INDEXED);
gimp_image_set_filename (image_ID, filename);
frame_buffer=g_malloc(fli_header.width * fli_header.height);
for (cnt=0; cnt< fli_header.frames; cnt++) {
sprintf(name_buf, "Frame (%i)",cnt+1);
layer_ID = gimp_layer_new (
image_ID, name_buf,
fli_header.width, fli_header.height,
INDEXED_IMAGE, 100, NORMAL_MODE);
gimp_image_add_layer (image_ID, layer_ID, 0);
drawable = gimp_drawable_get (layer_ID);
gimp_progress_update ((double) cnt / fli_header.frames);
fli_read_frame(f, &fli_header, frame_buffer, cmap);
gimp_pixel_rgn_init (&pixel_rgn, drawable, 0, 0, fli_header.width, fli_header.height, TRUE, FALSE);
gimp_pixel_rgn_set_rect (&pixel_rgn, frame_buffer, 0, 0, fli_header.width, fli_header.height);
gimp_drawable_flush (drawable);
gimp_drawable_detach (drawable);
}
gimp_image_set_cmap (image_ID, cmap, 256);
fclose(f);
g_free (name_buf);
g_free(frame_buffer);
return image_ID;
}

View File

@ -1,480 +0,0 @@
/* The GIMP -- an image manipulation program
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* 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
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/* saves and loads gimp icon files (For toolbox, etc)...
*/
#include <setjmp.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include "gtk/gtk.h"
#include "libgimp/gimp.h"
#include <netinet/in.h>
typedef struct
{
gchar icon_name[256];
} GIconSaveVals;
typedef struct
{
gint run;
} GIconSaveInterface;
/* Declare some local functions.
*/
static void query (void);
static void run (char *name,
int nparams,
GParam *param,
int *nreturn_vals,
GParam **return_vals);
static gint32 load_image (char *filename);
static gint save_image (char *filename,
gint32 image_ID,
gint32 drawable_ID);
static gint save_dialog (void);
static void close_callback (GtkWidget *widget,
gpointer data);
static void ok_callback (GtkWidget *widget,
gpointer data);
static void entry_callback (GtkWidget *widget,
gpointer data);
GPlugInInfo PLUG_IN_INFO =
{
NULL, /* init_proc */
NULL, /* quit_proc */
query, /* query_proc */
run, /* run_proc */
};
static GIconSaveVals givals =
{
"gicon" /* icon_name */
};
static GIconSaveInterface giint =
{
FALSE /* run */
};
MAIN ()
static void
query ()
{
static GParamDef load_args[] =
{
{ PARAM_INT32, "run_mode", "Interactive, non-interactive" },
{ PARAM_STRING, "filename", "The name of the file to load" },
{ PARAM_STRING, "raw_filename", "The name of the file to load" },
};
static GParamDef load_return_vals[] =
{
{ PARAM_IMAGE, "image", "Output image" },
};
static int nload_args = sizeof (load_args) / sizeof (load_args[0]);
static int nload_return_vals = sizeof (load_return_vals) / sizeof (load_return_vals[0]);
static GParamDef save_args[] =
{
{ PARAM_INT32, "run_mode", "Interactive, non-interactive" },
{ PARAM_IMAGE, "image", "Input image" },
{ PARAM_DRAWABLE, "drawable", "Drawable to save" },
{ PARAM_STRING, "filename", "The name of the file to save the image in" },
{ PARAM_STRING, "raw_filename", "The name of the file to save the image in" },
{ PARAM_STRING, "icon_name", "The name of the icon" }
};
static int nsave_args = sizeof (save_args) / sizeof (save_args[0]);
gimp_install_procedure ("file_gicon_load",
"loads files of the .ico file format",
"FIXME: write help",
"Spencer Kimball",
"Spencer Kimball",
"1997",
"<Load>/GIcon",
NULL,
PROC_PLUG_IN,
nload_args, nload_return_vals,
load_args, load_return_vals);
gimp_install_procedure ("file_gicon_save",
"saves files in the .ico file format",
"FIXME: write help",
"Spencer Kimball",
"Spencer Kimball",
"1997",
"<Save>/GIcon",
"GRAY*",
PROC_PLUG_IN,
nsave_args, 0,
save_args, NULL);
gimp_register_load_handler ("file_gicon_load", "ico", "");
gimp_register_save_handler ("file_gicon_save", "ico", "");
}
static void
run (char *name,
int nparams,
GParam *param,
int *nreturn_vals,
GParam **return_vals)
{
static GParam values[2];
GRunModeType run_mode;
gint32 image_ID;
GStatusType status = STATUS_SUCCESS;
run_mode = param[0].data.d_int32;
*return_vals = values;
values[0].type = PARAM_STATUS;
values[0].data.d_status = STATUS_CALLING_ERROR;
values[1].type = PARAM_IMAGE;
values[1].data.d_image = -1;
if (strcmp (name, "file_gicon_load") == 0)
{
image_ID = load_image (param[1].data.d_string);
if (image_ID != -1)
{
values[0].data.d_status = STATUS_SUCCESS;
values[1].data.d_image = image_ID;
}
else
{
values[0].data.d_status = STATUS_EXECUTION_ERROR;
}
*nreturn_vals = 2;
}
else if (strcmp (name, "file_gicon_save") == 0)
{
switch (run_mode)
{
case RUN_INTERACTIVE:
/* Possibly retrieve data */
gimp_get_data ("file_gicon_save", &givals);
/* First acquire information with a dialog */
if (! save_dialog ())
return;
break;
case RUN_NONINTERACTIVE:
/* Make sure all the arguments are there! */
if (nparams != 6)
status = STATUS_CALLING_ERROR;
else
strncpy (givals.icon_name, param[5].data.d_string, 256);
break;
case RUN_WITH_LAST_VALS:
/* Possibly retrieve data */
gimp_get_data ("file_gicon_save", &givals);
break;
default:
break;
}
if (save_image (param[3].data.d_string,
param[1].data.d_int32,
param[2].data.d_int32))
{
/* Store persistent data */
gimp_set_data ("file_gicon_save", &givals, sizeof (GIconSaveVals));
values[0].data.d_status = STATUS_SUCCESS;
}
else
values[0].data.d_status = STATUS_EXECUTION_ERROR;
*nreturn_vals = 1;
}
}
static gint32
load_image (char *filename)
{
GDrawable *drawable;
GPixelRgn pixel_rgn;
FILE * fp;
gint32 image_ID;
gint32 layer_ID;
char name_buf[256];
char * data_buf;
unsigned char *dest;
int val;
int width, height;
int i, j;
/* Open the requested file */
if (! (fp = fopen (filename, "r")))
{
fprintf (stderr, "gicon: can't open \"%s\"\n", filename);
return -1;
}
/* Check the identifier string */
fscanf (fp, "/* %s icon image format -- S. Kimball, P. Mattis */\n", name_buf);
if (strcmp ("GIMP", name_buf))
{
fprintf (stderr, "Not a GIcon file: %s!\n", filename);
return -1;
}
/* Parse the icon name */
fscanf (fp, "/* Image name: %s */\n", name_buf);
/* Get the width and height */
fscanf (fp, "#define %s %d\n", name_buf, &width);
fscanf (fp, "#define %s %d\n", name_buf, &height);
fscanf (fp, "static char *%s [] = \n{\n", name_buf);
/* Get a new image structure */
image_ID = gimp_image_new (width, height, GRAY);
gimp_image_set_filename (image_ID, filename);
layer_ID = gimp_layer_new (image_ID, "Background", width, height,
GRAYA_IMAGE, 100, NORMAL_MODE);
gimp_image_add_layer (image_ID, layer_ID, 0);
drawable = gimp_drawable_get (layer_ID);
gimp_pixel_rgn_init (&pixel_rgn, drawable, 0, 0, drawable->width,
drawable->height, TRUE, FALSE);
data_buf = g_new (char, width);
dest = g_new (char, width * 2);
for (i = 0; i < height; i++)
{
fscanf (fp, " \"%s\",\n", data_buf);
for (j = 0; j < width; j++)
{
val = data_buf[j];
if (val == '.')
{
dest[j*2+0] = 0;
dest[j*2+1] = 0; /* set alpha channel to transparent */
}
else
{
dest[j*2+0] = (255 * (val - 'a')) / 7;
dest[j*2+1] = 255; /* set alpha channel to opaque */
}
}
gimp_pixel_rgn_set_row (&pixel_rgn, dest, 0, i, width);
}
/* Clean up */
fclose (fp);
gimp_drawable_flush(drawable);
g_free (data_buf);
g_free (dest);
return image_ID;
}
static gint
save_image (char *filename,
gint32 image_ID,
gint32 drawable_ID)
{
GDrawable *drawable;
GPixelRgn pixel_rgn;
FILE * fp;
int i, j;
int w, h;
int has_alpha;
int val;
char ch;
unsigned char *src_buf, *src;
drawable = gimp_drawable_get (drawable_ID);
gimp_pixel_rgn_init (&pixel_rgn, drawable, 0, 0, drawable->width,
drawable->height, FALSE, FALSE);
w = drawable->width;
h = drawable->height;
has_alpha = gimp_drawable_has_alpha (drawable_ID);
/* open the file for writing */
if ((fp = fopen (filename, "w")))
{
fprintf (fp, "/* GIMP icon image format -- S. Kimball, P. Mattis */\n");
fprintf (fp, "/* Image name: %s */\n", givals.icon_name);
fprintf (fp, "\n\n");
fprintf (fp, "#define %s_width %d\n", givals.icon_name, w);
fprintf (fp, "#define %s_height %d\n", givals.icon_name, h);
fprintf (fp, "static char *%s_bits [] = \n{\n", givals.icon_name);
/* write the brush data to the file */
src_buf = g_new (char, w * drawable->bpp);
for (i = 0; i < h; i++)
{
gimp_pixel_rgn_get_row (&pixel_rgn, src_buf, 0, i, w);
src = src_buf;
fprintf (fp, " \"");
for (j = 0; j < w; j++)
{
if (has_alpha && !src[1])
{
ch = '.';
}
else
{
val = (int) ((double) src[0] * 7.0 / 255.0 + 0.5);
ch = 'a' + val;
}
fputc (ch, fp);
src += drawable->bpp;
}
fprintf (fp, (i == (h-1)) ? "\"\n};\n" : "\",\n");
}
/* Clean up */
g_free (src_buf);
fclose (fp);
}
return TRUE;
}
static gint
save_dialog()
{
GtkWidget *dlg;
GtkWidget *button;
GtkWidget *label;
GtkWidget *entry;
GtkWidget *table;
gchar **argv;
gint argc;
argc = 1;
argv = g_new(gchar *, 1);
argv[0] = g_strdup("gicon");
gtk_init(&argc, &argv);
gtk_rc_parse (gimp_gtkrc ());
dlg = gtk_dialog_new();
gtk_window_set_title(GTK_WINDOW(dlg), "Save As GIcon");
gtk_window_position(GTK_WINDOW(dlg), GTK_WIN_POS_MOUSE);
gtk_signal_connect(GTK_OBJECT(dlg), "destroy",
(GtkSignalFunc) close_callback, NULL);
/* Action area */
button = gtk_button_new_with_label("OK");
GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT);
gtk_signal_connect(GTK_OBJECT(button), "clicked",
(GtkSignalFunc) ok_callback,
dlg);
gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dlg)->action_area), button, TRUE, TRUE, 0);
gtk_widget_grab_default(button);
gtk_widget_show(button);
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));
gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dlg)->action_area), button, TRUE, TRUE, 0);
gtk_widget_show(button);
/* The main table */
/* Set its size (y, x) */
table = gtk_table_new(1, 2, FALSE);
gtk_container_border_width(GTK_CONTAINER(table), 10);
gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dlg)->vbox), table, TRUE, TRUE, 0);
gtk_widget_show(table);
gtk_table_set_row_spacings(GTK_TABLE(table), 10);
gtk_table_set_col_spacings(GTK_TABLE(table), 10);
/**********************
* label
**********************/
label = gtk_label_new("Icon Name:");
gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
gtk_table_attach(GTK_TABLE(table), label, 0, 1, 0, 1, GTK_FILL, GTK_FILL, 0, 0);
gtk_widget_show(label);
/************************
* The entry
************************/
entry = gtk_entry_new();
gtk_table_attach(GTK_TABLE(table), entry, 1, 2, 0, 1, GTK_EXPAND | GTK_FILL,
GTK_EXPAND | GTK_FILL, 0, 0);
gtk_widget_set_usize(entry, 200, 0);
gtk_entry_set_text(GTK_ENTRY(entry), givals.icon_name);
gtk_signal_connect(GTK_OBJECT(entry), "changed",
(GtkSignalFunc) entry_callback, givals.icon_name);
gtk_widget_show(entry);
gtk_widget_show(dlg);
gtk_main();
gdk_flush();
return giint.run;
}
static void
close_callback (GtkWidget *widget,
gpointer data)
{
gtk_main_quit();
}
static void
ok_callback (GtkWidget *widget,
gpointer data)
{
giint.run = TRUE;
gtk_widget_destroy (GTK_WIDGET (data));
}
static void
entry_callback (GtkWidget *widget,
gpointer data)
{
strncpy(givals.icon_name, gtk_entry_get_text (GTK_ENTRY (widget)), 256);
}

File diff suppressed because it is too large Load Diff

View File

@ -1,519 +0,0 @@
/*
* Written 1997 Jens Ch. Restemeier <jchrr@hrz.uni-bielefeld.de>
* This program is based on an algorithm / article by
* Jörn Loviscach.
*
* It generates one main formula (the middle button) and 8 variations of it.
* If you select a variation it becomes the new main formula. If you
* press "OK" the main formula will be applied to the image.
*
* 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
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
/*
* History:
* 1.0 first release
* 1.2 now handles RGB*
* 1.5 fixed a small bug
* 1.6 fixed a bug that was added by v1.5 :-(
* 1.7 added patch from Art Haas to make it compile with HP-UX, a small clean-up
*/
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
#include "gtk/gtk.h"
#include "libgimp/gimp.h"
/** qbist renderer ***********************************************************/
#define MAX_TRANSFORMS 36
#define NUM_TRANSFORMS 9
#define NUM_REGISTERS 6
#define PLUG_IN_NAME "plug_in_qbist"
#define PLUG_IN_VERSION "August 1997, 1.6"
#define PREVIEW_SIZE 64
/** types *******************************************************************/
typedef gfloat vreg[3];
typedef struct _info {
int transformSequence [MAX_TRANSFORMS];
int source [MAX_TRANSFORMS];
int control [MAX_TRANSFORMS];
int dest [MAX_TRANSFORMS];
} s_info;
#define PROJECTION 0
#define SHIFT 1
#define SHIFTBACK 2
#define ROTATE 3
#define ROTATE2 4
#define MULTIPLY 5
#define SINE 6
#define CONDITIONAL 7
#define COMPLEMENT 8
/** prototypes **************************************************************/
static void query(void);
static void run(
char *name,
int nparams,
GParam *param,
int *nreturn_vals,
GParam **return_vals);
void dialog_cancel();
void dialog_new_variations(GtkWidget *widget, gpointer data);
void dialog_update_previews(GtkWidget *widget, gpointer data);
void dialog_select_preview (GtkWidget *widget, s_info *n_info);
int dialog_create();
s_info qbist_info;
/** qbist functions *********************************************************/
void create_info(s_info *info)
{
int k;
for(k=0; k<MAX_TRANSFORMS; k++) {
info->transformSequence[k]=rand() % NUM_TRANSFORMS;
info->source[k]=rand() % NUM_REGISTERS;
info->control[k]=rand() % NUM_REGISTERS;
info->dest[k]=rand() % NUM_REGISTERS;
}
info->dest[rand() % MAX_TRANSFORMS]=0;
}
void modify_info(s_info *o_info, s_info *n_info)
{
int k,n;
memcpy(n_info, o_info, sizeof(s_info));
n=rand() % MAX_TRANSFORMS;
for(k=0;k<n; k++) {
switch (rand() % 4) {
case 0: n_info->transformSequence[rand() % MAX_TRANSFORMS] = rand() % NUM_TRANSFORMS; break;
case 1: n_info->source[rand() % MAX_TRANSFORMS] = rand() % NUM_REGISTERS; break;
case 2: n_info->control[rand() % MAX_TRANSFORMS] = rand() % NUM_REGISTERS; break;
case 3: n_info->dest[rand() % MAX_TRANSFORMS] = rand() % NUM_REGISTERS; break;
}
}
}
void qbist(s_info info, gchar *buffer, int xp, int yp, int num, int width, int height, int bpp)
{
gushort gx;
vreg reg [NUM_REGISTERS];
int i;
if (num<=0) return;
for(gx=0; gx<num; gx ++) {
for(i=0; i<NUM_REGISTERS; i++) {
reg[i][0] = ((float)gx+xp) / ((float)(width-1));
reg[i][1] = ((float)yp) / ((float)(height-1));
reg[i][2] = ((float)i) / ((float)NUM_REGISTERS);
}
for(i=0;i<MAX_TRANSFORMS; i++) {
gushort sr,cr,dr;
sr=info.source[i];cr=info.control[i];dr=info.dest[i];
switch (info.transformSequence[i]) {
case PROJECTION: {
gfloat scalarProd;
scalarProd = (reg[sr][0]*reg[cr][0])+(reg[sr][1]*reg[cr][1])+(reg[sr][2]*reg[cr][2]);
reg[dr][0] = scalarProd*reg[sr][0];
reg[dr][1] = scalarProd*reg[sr][1];
reg[dr][2] = scalarProd*reg[sr][2];
break;
}
case SHIFT:
reg[dr][0] = reg[sr][0]+reg[cr][0];
if (reg[dr][0] >= 1.0) reg[dr][0] -= 1.0;
reg[dr][1] = reg[sr][1]+reg[cr][1];
if (reg[dr][1] >= 1.0) reg[dr][1] -= 1.0;
reg[dr][2] = reg[sr][2]+reg[cr][2];
if (reg[dr][2] >= 1.0) reg[dr][2] -= 1.0;
break;
case SHIFTBACK:
reg[dr][0] = reg[sr][0]-reg[cr][0];
if (reg[dr][0] < 0.0) reg[dr][0] += 1.0;
reg[dr][1] = reg[sr][1]-reg[cr][1];
if (reg[dr][1] < 0.0) reg[dr][1] += 1.0;
reg[dr][2] = reg[sr][2]-reg[cr][2];
if (reg[dr][2] < 0.0) reg[dr][2] += 1.0;
break;
case ROTATE:
reg[dr][0] = reg[sr][1];
reg[dr][1] = reg[sr][2];
reg[dr][2] = reg[sr][0];
break;
case ROTATE2:
reg[dr][0] = reg[sr][2];
reg[dr][1] = reg[sr][0];
reg[dr][2] = reg[sr][1];
break;
case MULTIPLY:
reg[dr][0] = reg[sr][0]*reg[cr][0];
reg[dr][1] = reg[sr][1]*reg[cr][1];
reg[dr][2] = reg[sr][2]*reg[cr][2];
break;
case SINE:
reg[dr][0] = 0.5+(0.5*sin(20.0*reg[sr][0]*reg[cr][0]));
reg[dr][1] = 0.5+(0.5*sin(20.0*reg[sr][1]*reg[cr][1]));
reg[dr][2] = 0.5+(0.5*sin(20.0*reg[sr][2]*reg[cr][2]));
break;
case CONDITIONAL:
if ((reg[cr][0]+reg[cr][1]+reg[cr][2]) > 0.5) {
reg[dr][0] = reg[sr][0];
reg[dr][1] = reg[sr][1];
reg[dr][2] = reg[sr][2];
} else {
reg[dr][0] = reg[cr][0];
reg[dr][1] = reg[cr][1];
reg[dr][2] = reg[cr][2];
}
break;
case COMPLEMENT:
reg[dr][0] = 1.0-reg[sr][0];
reg[dr][1] = 1.0-reg[sr][1];
reg[dr][2] = 1.0-reg[sr][2];
break;
}
}
for (i=0; i<bpp; i++) {
if (i<3) {
buffer[i]=floor(255.0 * reg[0][i]);
} else {
buffer[i]=255;
}
}
buffer+=bpp;
}
}
/** Plugin interface *********************************************************/
GPlugInInfo PLUG_IN_INFO = {
NULL, /* init_proc */
NULL, /* quit_proc */
query, /* query_proc */
run /* run_proc */
};
MAIN();
static void
query(void)
{
static GParamDef args[] = {
{ PARAM_INT32, "run_mode", "Interactive, non-interactive" },
{ PARAM_IMAGE, "image", "Input image (unused)" },
{ PARAM_DRAWABLE, "drawable", "Input drawable" }
}; /* args */
static GParamDef *return_vals = NULL;
static int nargs = sizeof(args) / sizeof(args[0]);
static int nreturn_vals = 0;
gimp_install_procedure(PLUG_IN_NAME,
"Create images based on a random genetic formula",
"This Plug-in is based on an article by "
"Jörn Loviscach. It generates modern art "
"pictures from a random genetic formula.",
"Jörn Loviscach, Jens Ch. Restemeier",
"Jörn Loviscach, Jens Ch. Restemeier",
PLUG_IN_VERSION,
"<Image>/Filters/Render/Qbist",
"RGB*",
PROC_PLUG_IN,
nargs,
nreturn_vals,
args,
return_vals);
} /* query */
gint g_min(gint a, gint b)
{
return (a<b) ? a : b;
}
gint g_max(gint a, gint b)
{
return (a>b) ? a : b;
}
static void
run(char *name,
int nparams,
GParam *param,
int *nreturn_vals,
GParam **return_vals)
{
gint sel_x1,sel_y1,sel_x2,sel_y2;
gint img_height, img_width, img_bpp, img_has_alpha;
GParam values[1];
GDrawable *drawable;
GRunModeType run_mode;
GStatusType status;
status = STATUS_SUCCESS;
run_mode = param[0].data.d_int32;
values[0].type = PARAM_STATUS;
values[0].data.d_status = status;
*nreturn_vals = 1;
*return_vals = values;
drawable = gimp_drawable_get(param[2].data.d_drawable);
img_width = gimp_drawable_width(drawable->id);
img_height = gimp_drawable_height(drawable->id);
img_bpp = gimp_drawable_bpp(drawable->id);
img_has_alpha = gimp_drawable_has_alpha(drawable->id);
gimp_drawable_mask_bounds(drawable->id, &sel_x1, &sel_y1, &sel_x2, &sel_y2);
create_info(&qbist_info);
switch (run_mode) {
case RUN_INTERACTIVE:
/* Possibly retrieve data */
gimp_get_data(PLUG_IN_NAME, &qbist_info);
/* Get information from the dialog */
if (!dialog_create())
return;
break;
case RUN_NONINTERACTIVE:
break;
case RUN_WITH_LAST_VALS:
/* Possibly retrieve data */
gimp_get_data(PLUG_IN_NAME, &qbist_info);
break;
default:
break;
}
if ((status == STATUS_SUCCESS) && gimp_drawable_color(drawable->id)) {
GTile *tile=NULL;
gint col, row, line, tile_width, tile_height;
gint max_progress, progress;
tile_width = gimp_tile_width ();
tile_height = gimp_tile_height ();
/* Set the tile cache size */
gimp_tile_cache_ntiles(2 * (drawable->width + gimp_tile_width() - 1) / gimp_tile_width());
/* Run! */
gimp_progress_init ("Qbist ...");
max_progress=((sel_y2-sel_y1) / tile_height) * ((sel_x2-sel_x1) / tile_width);
progress=0;
for (row=(sel_y1 / tile_height); row<=((sel_y2-1) / tile_height); row++) {
for (col=(sel_x1 / tile_width); col<=((sel_x2-1) / tile_width); col++) {
gint t_max_x, t_min_x, t_max_y, t_min_y;
tile = gimp_drawable_get_tile( drawable, TRUE, row, col );
gimp_tile_ref(tile);
t_min_x=g_max(0, sel_x1 - (col * tile_height));
t_max_x=g_min(tile->ewidth, sel_x2 - (col * tile_width));
t_min_y=g_max(0, sel_y1 - (row * tile_height));
t_max_y=g_min(tile->eheight, sel_y2 - (row * tile_height));
for (line=t_min_y; line<t_max_y; line++) {
qbist(qbist_info, tile->data + (((line * tile->ewidth)+t_min_x) * img_bpp) , (col * tile_width) + t_min_x, (row * tile_height) + line, t_max_x - t_min_x, img_width, img_height, img_bpp);
}
gimp_progress_update((double)progress / (double)max_progress);
progress++;
gimp_tile_unref (tile, TRUE);
}
}
gimp_drawable_flush (drawable);
gimp_drawable_merge_shadow (drawable->id, TRUE);
gimp_drawable_update (drawable->id, sel_x1, sel_y1, (sel_x2 - sel_x1), (sel_y2 - sel_y1));
/* If run mode is interactive, flush displays */
if (run_mode != RUN_NONINTERACTIVE)
gimp_displays_flush();
/* Store data */
if (run_mode == RUN_INTERACTIVE)
gimp_set_data(PLUG_IN_NAME, &qbist_info, sizeof(s_info));
} else if (status == STATUS_SUCCESS)
status = STATUS_EXECUTION_ERROR;
values[0].data.d_status = status;
gimp_drawable_detach(drawable);
} /* run */
/** User interface ***********************************************************/
GtkWidget *preview[9];
s_info info[9];
gint result;
void dialog_close(GtkWidget *widget, gpointer data)
{
gtk_main_quit();
}
void dialog_cancel(GtkWidget *widget, gpointer data)
{
result=FALSE;
gtk_widget_destroy(GTK_WIDGET(data));
}
void dialog_ok(GtkWidget *widget, gpointer data)
{
result=TRUE;
gtk_widget_destroy(GTK_WIDGET(data));
}
void dialog_new_variations(GtkWidget *widget, gpointer data)
{
int i;
for (i=1; i<9; i++)
modify_info(&(info[0]),&(info[i]));
}
void dialog_update_previews(GtkWidget *widget, gpointer data)
{
int i,j;
guchar buf[PREVIEW_SIZE * 3];
for (j=0;j<9;j++) {
for (i = 0; i < PREVIEW_SIZE; i++) {
qbist(info[(j+5) % 9], buf, 0, i, PREVIEW_SIZE, PREVIEW_SIZE, PREVIEW_SIZE, 3);
gtk_preview_draw_row (GTK_PREVIEW (preview[j]), buf, 0, i, PREVIEW_SIZE);
}
gtk_widget_draw(preview[j], NULL);
}
}
void dialog_select_preview (GtkWidget *widget, s_info *n_info)
{
memcpy(&(info[0]), n_info, sizeof(s_info));
dialog_new_variations(widget, NULL);
dialog_update_previews(widget, NULL);
}
int dialog_create()
{
GtkWidget *dialog;
GtkWidget *button;
GtkWidget *table;
guchar *color_cube;
gchar **argv;
gint argc;
int i;
srand(time(NULL));
argc = 1;
argv = g_new (gchar *, 1);
argv[0] = g_strdup ("video");
gtk_init (&argc, &argv);
gtk_rc_parse (gimp_gtkrc ());
gdk_set_use_xshm (gimp_use_xshm ());
gtk_preview_set_gamma (gimp_gamma ());
gtk_preview_set_install_cmap (gimp_install_cmap ());
color_cube = gimp_color_cube ();
gtk_preview_set_color_cube (color_cube[0], color_cube[1],
color_cube[2], color_cube[3]);
gtk_widget_set_default_visual (gtk_preview_get_visual ());
gtk_widget_set_default_colormap (gtk_preview_get_cmap ());
dialog=gtk_dialog_new ();
gtk_window_set_title (GTK_WINDOW(dialog), "G-Qbist 1.0");
gtk_signal_connect (GTK_OBJECT (dialog), "destroy",
(GtkSignalFunc) dialog_close,
NULL);
table=gtk_table_new (3,3,FALSE);
gtk_table_set_row_spacings(GTK_TABLE(table), 5);
gtk_table_set_col_spacings(GTK_TABLE(table), 5);
gtk_container_border_width (GTK_CONTAINER (table),5);
gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), table, FALSE, FALSE, 0);
gtk_widget_show(table);
memcpy((char *)&(info[0]),(char *)&qbist_info,sizeof(s_info));
dialog_new_variations(NULL, NULL);
for (i=0; i<9; i++) {
button=gtk_button_new();
gtk_signal_connect (GTK_OBJECT (button), "clicked",
(GtkSignalFunc) dialog_select_preview, (gpointer) &(info[(i+5)%9]));
gtk_table_attach(GTK_TABLE(table),button,i%3,(i%3)+1,i/3,(i/3)+1,
GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
gtk_widget_show(button);
preview[i] = gtk_preview_new(GTK_PREVIEW_COLOR);
gtk_preview_size(GTK_PREVIEW(preview[i]), PREVIEW_SIZE, PREVIEW_SIZE);
gtk_container_add(GTK_CONTAINER(button), preview[i]);
gtk_widget_show(preview[i]);
}
dialog_update_previews(NULL, NULL);
button = gtk_button_new_with_label ("OK");
gtk_signal_connect (GTK_OBJECT (button), "clicked",
(GtkSignalFunc) dialog_ok, (gpointer) dialog);
GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
gtk_box_pack_start (GTK_BOX (GTK_DIALOG(dialog)->action_area), button, TRUE, TRUE, 0);
gtk_widget_show (button);
button = gtk_button_new_with_label ("Cancel");
gtk_signal_connect (GTK_OBJECT (button), "clicked",
(GtkSignalFunc) dialog_cancel, (gpointer) dialog);
gtk_box_pack_end (GTK_BOX (GTK_DIALOG(dialog)->action_area), button, TRUE, TRUE, 0);
GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
gtk_widget_grab_default (button);
gtk_widget_show (button);
gtk_widget_show(dialog);
result=0;
gtk_main();
gdk_flush();
if (result)
memcpy((char *)&qbist_info,(char *)&(info[0]),sizeof(s_info));
return result;
}

View File

@ -1,279 +0,0 @@
/* The GIMP -- an image manipulation program
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* Gradient Map plug-in
* Copyright (C) 1997 Eiichi Takamori <taka@ma1.seikyou.ne.jp>
*
* 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
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/*
* version 1.06
* This plug-in requires GIMP v0.99.10 or above.
*
* This plug-in maps the image using active gradient. (See help_string
* in query ()).
*
* Eiichi Takamori <taka@ma1.seikyou.ne.jp>
* http://ha1.seikyou.ne.jp/home/taka/gimp/
*
* Changes from version 1.05 to version 1.06:
* - Fixed bug that completely white pixel (= grayscale 255) was not
* mapped properly. (Thanks to Dov Grobgeld)
*
* Changes from version 1.04 to version 1.05:
* - Now it uses gimp_gradients_sample_uniform () instead of blend
* tool. Maybe right thing.
*
* Changes from revision 1.1 to version 1.04:
* - Fix bug that it didn't work with alpha channel.
* - Changed calling `gimp_blend' so that it works in v0.99.9.
* - Changed calling `gimp_blend' so that it works with Quartic's
* asupsample patch.
* - Fix the way to calculate luminosity of RGB image.
* (Thanks to Michael Lamertz)
*/
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "libgimp/gimp.h"
#ifdef RCSID
static char rcsid[] = "$Id$";
#endif
/* Some useful macros */
#define NSAMPLES 256
#define TILE_CACHE_SIZE 32
#define LUMINOSITY(X) (X[0] * 0.30 + X[1] * 0.59 + X[2] * 0.11)
/* Declare a local function.
*/
static void query (void);
static void run (gchar *name,
gint nparams,
GParam *param,
gint *nreturn_vals,
GParam **return_vals);
static void gradmap (GDrawable *drawable);
static guchar * get_samples (GDrawable *drawable );
GPlugInInfo PLUG_IN_INFO =
{
NULL, /* init_proc */
NULL, /* quit_proc */
query, /* query_proc */
run, /* run_proc */
};
MAIN ()
static void
query()
{
static GParamDef args[]=
{
{ PARAM_INT32, "run_mode", "Interactive, non-interactive" },
{ PARAM_IMAGE, "image", "Input image (unused)" },
{ PARAM_DRAWABLE, "drawable", "Input drawable" },
};
static GParamDef *return_vals = NULL;
static gint nargs = sizeof (args) / sizeof (args[0]);
static gint nreturn_vals = 0;
gchar *help_string =
" This plug-in maps the contents of the specified drawable with"
" active gradient. It calculates luminosity of each pixel and"
" replaces the pixel by the sample of active gradient at the"
" position proportional to that luminosity. Complete black pixel"
" becomes the leftmost color of the gradient, and complete white"
" becomes the rightmost. Works on both Grayscale and RGB image"
" with/without alpha channel.";
gimp_install_procedure ("plug_in_gradmap",
"Map the contents of the specified drawable with active gradient",
help_string,
"Eiichi Takamori",
"Eiichi Takamori",
"1997",
"<Image>/Filters/Image/Gradient Map",
"RGB*, GRAY*",
PROC_PLUG_IN,
nargs, nreturn_vals,
args, return_vals);
}
static void
run (gchar *name,
gint nparams,
GParam *param,
gint *nreturn_vals,
GParam **return_vals)
{
static GParam values[1];
GDrawable *drawable;
GRunModeType run_mode;
GStatusType status = STATUS_SUCCESS;
run_mode = param[0].data.d_int32;
*nreturn_vals = 1;
*return_vals = values;
values[0].type = PARAM_STATUS;
values[0].data.d_status = status;
/* 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 ("Gradient Map...");
gimp_tile_cache_ntiles (TILE_CACHE_SIZE);
gradmap (drawable);
if (run_mode != RUN_NONINTERACTIVE)
gimp_displays_flush ();
}
else
{
/* gimp_message ("gradmap: cannot operate on indexed color images"); */
status = STATUS_EXECUTION_ERROR;
}
values[0].data.d_status = status;
gimp_drawable_detach (drawable);
}
static void
gradmap (GDrawable *drawable)
{
GPixelRgn src_rgn, dest_rgn;
gpointer pr;
guchar *src_row, *dest_row;
guchar *src, *dest;
gint progress, max_progress;
gint x1, y1, x2, y2;
gint row, col;
gint bpp, color, has_alpha, alpha;
guchar *samples, *samp;
gint lum; /* luminosity */
gint b;
gimp_drawable_mask_bounds (drawable->id, &x1, &y1, &x2, &y2);
bpp = alpha = gimp_drawable_bpp( drawable->id );
color = gimp_drawable_color( drawable->id );
has_alpha = gimp_drawable_has_alpha( drawable->id );
if( has_alpha )
alpha--;
samples = get_samples (drawable);
gimp_pixel_rgn_init (&src_rgn, drawable, x1, y1, x2-x1, y2-y1, FALSE, FALSE);
gimp_pixel_rgn_init (&dest_rgn, drawable, x1, y1, x2-x1, y2-y1, TRUE, TRUE);
/* Initialize progress */
progress = 0;
max_progress = (x2 - x1) * (y2 - y1);
for (pr = gimp_pixel_rgns_register (2, &src_rgn, &dest_rgn);
pr != NULL; pr = gimp_pixel_rgns_process (pr))
{
src_row = src_rgn.data;
dest_row = dest_rgn.data;
for ( row = 0; row < src_rgn.h; row++ )
{
src = src_row;
dest = dest_row;
for ( col = 0; col < src_rgn.w; col++ )
{
if( color )
{
lum = LUMINOSITY (src);
lum = CLAMP (lum, 0, 255); /* to make sure */
}
else
lum = src[0];
samp = &samples[lum * bpp];
for( b = 0; b < bpp; b++ )
dest[b] = samp[b];
src += src_rgn.bpp;
dest += dest_rgn.bpp;
}
src_row += src_rgn.rowstride;
dest_row += dest_rgn.rowstride;
}
/* Update progress */
progress += src_rgn.w * src_rgn.h;
gimp_progress_update ((double) progress / (double) max_progress);
}
g_free (samples);
gimp_drawable_flush (drawable);
gimp_drawable_merge_shadow (drawable->id, TRUE);
gimp_drawable_update (drawable->id, x1, y1, (x2 - x1), (y2 - y1));
}
/*
Returns 256 samples of active gradient.
Each sample has (gimp_drawable_bpp (drawable->id)) bytes.
*/
static guchar *
get_samples (GDrawable *drawable)
{
gdouble *f_samples, *f_samp; /* float samples */
guchar *b_samples, *b_samp; /* byte samples */
gint bpp, color, has_alpha, alpha;
gint i, j;
f_samples = gimp_gradients_sample_uniform (NSAMPLES);
bpp = gimp_drawable_bpp (drawable->id);
color = gimp_drawable_color (drawable->id);
has_alpha = gimp_drawable_has_alpha (drawable->id);
alpha = (has_alpha ? bpp - 1 : bpp);
b_samples = g_new (guchar, NSAMPLES * bpp);
for (i = 0; i < NSAMPLES; i++)
{
b_samp = &b_samples[i * bpp];
f_samp = &f_samples[i * 4];
if (color)
for (j = 0; j < 3; j++)
b_samp[j] = f_samp[j] * 255;
else
b_samp[0] = LUMINOSITY (f_samp) * 255;
if (has_alpha)
b_samp[alpha] = f_samp[3] * 255;
}
g_free (f_samples);
return b_samples;
}

View File

@ -1,379 +0,0 @@
/* The GIMP -- an image manipulation program * Copyright (C) 1995 Spencer
* Kimball and Peter Mattis * * 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 * the Free Software Foundation; either
* version 2 of the License, or * (at your option) any later version. * *
* This program is distributed in the hope that it will be useful, * but
* WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU
* General Public License for more details. * * 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., 675 Mass Ave, Cambridge, MA
* 02139, USA. */
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include "libgimp/gimp.h"
#include "gtk/gtk.h"
/* Declare local functions. */
static void query(void);
static void run(char *name,
int nparams,
GParam * param,
int *nreturn_vals,
GParam ** return_vals);
static gint dialog();
static void doit(GDrawable * drawable);
GPlugInInfo PLUG_IN_INFO =
{
NULL, /* init_proc */
NULL, /* quit_proc */
query, /* query_proc */
run, /* run_proc */
};
gint bytes;
gint sx1, sy1, sx2, sy2;
int run_flag = 0;
typedef struct {
gint width, height;
gint x_offset, y_offset;
} config;
config my_config =
{
16, 16, /* width, height */
0, 0, /* x_offset, y_offset */
};
MAIN()
static void query()
{
static GParamDef args[] =
{
{PARAM_INT32, "run_mode", "Interactive, non-interactive"},
{PARAM_IMAGE, "image", "Input image (unused)"},
{PARAM_DRAWABLE, "drawable", "Input drawable"},
{PARAM_INT32, "width", "Width"},
{PARAM_INT32, "height", "Height"},
{PARAM_INT32, "x_offset", "X Offset"},
{PARAM_INT32, "y_offset", "Y Offset"},
};
static GParamDef *return_vals = NULL;
static int nargs = sizeof(args) / sizeof(args[0]);
static int nreturn_vals = 0;
gimp_install_procedure("plug_in_grid",
"Draws a grid.",
"",
"Tim Newsome",
"Tim Newsome",
"1997",
"<Image>/Filters/Render/Grid",
"RGB, GRAY",
PROC_PLUG_IN,
nargs, nreturn_vals,
args, return_vals);
}
static void run(char *name, int n_params, GParam * param, int *nreturn_vals,
GParam ** return_vals)
{
static GParam values[1];
GDrawable *drawable;
GRunModeType run_mode;
GStatusType status = STATUS_SUCCESS;
*nreturn_vals = 1;
*return_vals = values;
run_mode = param[0].data.d_int32;
if (run_mode == RUN_NONINTERACTIVE) {
if (n_params != 7) {
status = STATUS_CALLING_ERROR;
} else {
my_config.width = param[4].data.d_int32;
my_config.height = param[5].data.d_int32;
my_config.x_offset = param[6].data.d_int32;
my_config.y_offset = param[7].data.d_int32;
}
} else {
/* Possibly retrieve data */
gimp_get_data("plug_in_grid", &my_config);
if (run_mode == RUN_INTERACTIVE) {
/* Oh boy. We get to do a dialog box, because we can't really expect the
* user to set us up with the right values using gdb.
*/
if (!dialog()) {
/* The dialog was closed, or something similarly evil happened. */
status = STATUS_EXECUTION_ERROR;
}
}
}
if (my_config.width <= 0 || my_config.height <= 0) {
status = STATUS_EXECUTION_ERROR;
}
if (status == STATUS_SUCCESS) {
/* 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("Drawing Grid...");
gimp_tile_cache_ntiles(2 * (drawable->width / gimp_tile_width() + 1));
srand(time(NULL));
doit(drawable);
if (run_mode != RUN_NONINTERACTIVE)
gimp_displays_flush();
if (run_mode == RUN_INTERACTIVE)
gimp_set_data("plug_in_grid", &my_config, sizeof(my_config));
} else {
status = STATUS_EXECUTION_ERROR;
}
gimp_drawable_detach(drawable);
}
values[0].type = PARAM_STATUS;
values[0].data.d_status = status;
}
static void doit(GDrawable * drawable)
{
GPixelRgn srcPR, destPR;
gint width, height;
int w, h, b;
guchar *copybuf;
guchar color[4] = {0, 0, 0, 0};
/* 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, &sx1, &sy1, &sx2, &sy2);
/* Get the size of the input image. (This will/must be the same
* as the size of the output image.
*/
width = drawable->width;
height = drawable->height;
bytes = drawable->bpp;
if (gimp_drawable_has_alpha(drawable->id)) {
color[bytes - 1] = 0xff;
}
/* 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);
/* First off, copy the old one to the new one. */
copybuf = malloc(width * bytes);
for (h = sy1; h < sy2; h++) {
gimp_pixel_rgn_get_row(&srcPR, copybuf, sx1, h, width);
if ((h - my_config.y_offset) % my_config.height == 0) {
for (w = sx1; w < sx2; w++) {
for (b = 0; b < bytes; b++) {
copybuf[w * bytes + b] = color[b];
}
}
} else {
for (w = sx1; w < sx2; w++) {
if ((w - my_config.x_offset) % my_config.width == 0) {
for (b = 0; b < bytes; b++) {
copybuf[w * bytes + b] = color[b];
}
}
}
}
gimp_pixel_rgn_set_row(&destPR, copybuf, sx1, h, width);
gimp_progress_update((double) h / (double) (sy2 - sy1));
}
free(copybuf);
/* update the timred region */
gimp_drawable_flush(drawable);
gimp_drawable_merge_shadow(drawable->id, TRUE);
gimp_drawable_update(drawable->id, sx1, sy1, sx2 - sx1, sy2 - sy1);
}
/***************************************************
* GUI stuff
*/
static void close_callback(GtkWidget * widget, gpointer data)
{
gtk_main_quit();
}
static void ok_callback(GtkWidget * widget, gpointer data)
{
run_flag = 1;
gtk_widget_destroy(GTK_WIDGET(data));
}
static void entry_callback(GtkWidget * widget, gpointer data)
{
if (data == &my_config.width)
my_config.width = atof(gtk_entry_get_text(GTK_ENTRY(widget)));
else if (data == &my_config.height)
my_config.height = atoi(gtk_entry_get_text(GTK_ENTRY(widget)));
else if (data == &my_config.x_offset)
my_config.x_offset = atoi(gtk_entry_get_text(GTK_ENTRY(widget)));
else if (data == &my_config.y_offset)
my_config.y_offset = atoi(gtk_entry_get_text(GTK_ENTRY(widget)));
}
static gint dialog()
{
GtkWidget *dlg;
GtkWidget *button;
GtkWidget *label;
GtkWidget *entry;
GtkWidget *table;
gchar buffer[12];
gchar **argv;
gint argc;
argc = 1;
argv = g_new(gchar *, 1);
argv[0] = g_strdup("plasma");
gtk_init(&argc, &argv);
dlg = gtk_dialog_new();
gtk_window_set_title(GTK_WINDOW(dlg), "Grid");
gtk_window_position(GTK_WINDOW(dlg), GTK_WIN_POS_MOUSE);
gtk_signal_connect(GTK_OBJECT(dlg), "destroy",
(GtkSignalFunc) close_callback, NULL);
/* Action area */
button = gtk_button_new_with_label("OK");
GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT);
gtk_signal_connect(GTK_OBJECT(button), "clicked",
(GtkSignalFunc) ok_callback,
dlg);
gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dlg)->action_area), button, TRUE, TRUE, 0);
gtk_widget_grab_default(button);
gtk_widget_show(button);
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));
gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dlg)->action_area), button, TRUE, TRUE, 0);
gtk_widget_show(button);
/* The main table */
/* Set its size (y, x) */
table = gtk_table_new(4, 3, FALSE);
gtk_container_border_width(GTK_CONTAINER(table), 10);
gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dlg)->vbox), table, TRUE, TRUE, 0);
gtk_widget_show(table);
gtk_table_set_row_spacings(GTK_TABLE(table), 10);
gtk_table_set_col_spacings(GTK_TABLE(table), 10);
/**********************
* The X/Y labels *
**********************/
label = gtk_label_new("X");
gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
gtk_table_attach(GTK_TABLE(table), label, 1, 2, 1, 2, GTK_FILL, GTK_FILL, 0,
0);
gtk_widget_show(label);
label = gtk_label_new("Y");
gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
gtk_table_attach(GTK_TABLE(table), label, 2, 3, 1, 2, GTK_FILL, GTK_FILL, 0,
0);
gtk_widget_show(label);
/************************
* The width entry: *
************************/
label = gtk_label_new("Size:");
gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
gtk_table_attach(GTK_TABLE(table), label, 0, 1, 2, 3, GTK_FILL, GTK_FILL, 0,
0);
gtk_widget_show(label);
entry = gtk_entry_new();
gtk_table_attach(GTK_TABLE(table), entry, 1, 2, 2, 3, GTK_EXPAND | GTK_FILL,
GTK_EXPAND | GTK_FILL, 0, 0);
gtk_widget_set_usize(entry, 50, 0);
sprintf(buffer, "%i", my_config.width);
gtk_entry_set_text(GTK_ENTRY(entry), buffer);
gtk_signal_connect(GTK_OBJECT(entry), "changed",
(GtkSignalFunc) entry_callback, &my_config.width);
gtk_widget_show(entry);
/************************
* The height entry: *
************************/
entry = gtk_entry_new();
gtk_table_attach(GTK_TABLE(table), entry, 2, 3, 2, 3, GTK_EXPAND | GTK_FILL,
GTK_EXPAND | GTK_FILL, 0, 0);
gtk_widget_set_usize(entry, 50, 0);
sprintf(buffer, "%i", my_config.height);
gtk_entry_set_text(GTK_ENTRY(entry), buffer);
gtk_signal_connect(GTK_OBJECT(entry), "changed",
(GtkSignalFunc) entry_callback, &my_config.height);
gtk_widget_show(entry);
gtk_widget_show(dlg);
/************************
* The x_offset entry: *
************************/
label = gtk_label_new("Offset:");
gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
gtk_table_attach(GTK_TABLE(table), label, 0, 1, 3, 4, GTK_FILL, GTK_FILL, 0,
0);
gtk_widget_show(label);
entry = gtk_entry_new();
gtk_table_attach(GTK_TABLE(table), entry, 1, 2, 3, 4, GTK_EXPAND | GTK_FILL,
GTK_EXPAND | GTK_FILL, 0, 0);
gtk_widget_set_usize(entry, 50, 0);
sprintf(buffer, "%i", my_config.x_offset);
gtk_entry_set_text(GTK_ENTRY(entry), buffer);
gtk_signal_connect(GTK_OBJECT(entry), "changed",
(GtkSignalFunc) entry_callback, &my_config.x_offset);
gtk_widget_show(entry);
/************************
* The y_offset entry: *
************************/
entry = gtk_entry_new();
gtk_table_attach(GTK_TABLE(table), entry, 2, 3, 3, 4, GTK_EXPAND | GTK_FILL,
GTK_EXPAND | GTK_FILL, 0, 0);
gtk_widget_set_usize(entry, 50, 0);
sprintf(buffer, "%i", my_config.y_offset);
gtk_entry_set_text(GTK_ENTRY(entry), buffer);
gtk_signal_connect(GTK_OBJECT(entry), "changed",
(GtkSignalFunc) entry_callback, &my_config.y_offset);
gtk_widget_show(entry);
gtk_widget_show(dlg);
gtk_main();
gdk_flush();
return run_flag;
}

View File

@ -1,435 +0,0 @@
/* The GIMP -- an image manipulation program
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
* Copyright (C) 1997 Daniel Risacher, magnus@alum.mit.edu
*
* 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
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/* Minor changes to support file magic */
/* 4 Oct 1997 -- Risacher */
/* gzip plug-in for the gimp */
/* loosley based on url.c by */
/* Josh MacDonald, jmacd@cs.berkeley.edu */
/* and, very loosely on hrz.c by */
/* Albert Cahalan <acahalan at cs.uml.edu> */
/* This is reads and writes gziped image files for the Gimp
*
* You need to have gzip installed for it to work.
*
* It should work with file names of the form
* filename.foo.gz where foo is some already-recognized extension
*
* and it also works for names of the form
* filename.xcfgz - which is equivalent to
* filename.xcf.gz
*
* I added the xcfgz bit because having a default extension of xcf.gz
* can confuse the file selection dialog box somewhat, forcing the
* user to type sometimes when he/she otherwise wouldn't need to.
*
* I later decided I didn't like it because I don't like to bloat
* the file-extension namespace. But I left in the recognition
* feature/bug so if people want to use files named foo.xcfgz by
* default, they can just hack their pluginrc file.
*
* to do this hack, change :
* "xcf.gz,gz,xcfgz"
* to
* "xcfgz,gz,xcf.gz"
*
*
* -Dan Risacher, 0430 CDT, 26 May 1997
*/
#include <stdlib.h>
#include <stdio.h>
#include <sys/param.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include "gtk/gtk.h"
#include "libgimp/gimp.h"
/* Author 1: Josh MacDonald (url.c) */
/* Author 2: Daniel Risacher (gz.c) */
/* According to USAF Lt Steve Werhle, US DoD software development
* contracts average about $25 USD per source line of code (SLOC). By
* that metric, I figure this plug-in is worth about $10,000 USD */
/* But you got it free. Magic of Gnu. */
static void query (void);
static void run (char *name,
int nparams,
GParam *param,
int *nreturn_vals,
GParam **return_vals);
static gint32 load_image (char *filename, gint32 run_mode);
static gint save_image (char *filename,
gint32 image_ID,
gint32 drawable_ID,
gint32 run_mode);
static int valid_file (char* filename) ;
static char* find_extension (char* filename);
GPlugInInfo PLUG_IN_INFO =
{
NULL, /* init_proc */
NULL, /* quit_proc */
query, /* query_proc */
run, /* run_proc */
};
MAIN ()
static void
query ()
{
static GParamDef load_args[] =
{
{ PARAM_INT32, "run_mode", "Interactive, non-interactive" },
{ PARAM_STRING, "filename", "The name of the file to load" },
{ PARAM_STRING, "raw_filename", "The name entered" },
};
static GParamDef load_return_vals[] =
{
{ PARAM_IMAGE, "image", "Output image" },
};
static int nload_args = sizeof (load_args) / sizeof (load_args[0]);
static int nload_return_vals = sizeof (load_return_vals) / sizeof (load_return_vals[0]);
static GParamDef save_args[] =
{
{ PARAM_INT32, "run_mode", "Interactive, non-interactive" },
{ PARAM_IMAGE, "image", "Input image" },
{ PARAM_DRAWABLE, "drawable", "Drawable to save" },
{ PARAM_STRING, "filename", "The name of the file to save the image in" },
{ PARAM_STRING, "raw_filename", "The name of the file to save the image in" }
};
static int nsave_args = sizeof (save_args) / sizeof (save_args[0]);
gimp_install_procedure ("file_gz_load",
"loads files compressed with gzip",
"You need to have gzip installed.",
"Daniel Risacher",
"Daniel Risacher, Spencer Kimball and Peter Mattis",
"1995-1997",
"<Load>/gzip",
NULL,
PROC_PLUG_IN,
nload_args, nload_return_vals,
load_args, load_return_vals);
gimp_install_procedure ("file_gz_save",
"saves files compressed with gzip",
"You need to have gzip installed",
"Daniel Risacher",
"Daniel Risacher, Spencer Kimball and Peter Mattis",
"1995-1997",
"<Save>/gzip",
"RGB*, GRAY*, INDEXED*",
PROC_PLUG_IN,
nsave_args, 0,
save_args, NULL);
gimp_register_magic_load_handler ("file_gz_load", "xcf.gz,gz,xcfgz",
"", "0,string,\037\213");
gimp_register_save_handler ("file_gz_save", "xcf.gz,gz,xcfgz", "");
}
static void
run (char *name,
int nparams,
GParam *param,
int *nreturn_vals,
GParam **return_vals)
{
static GParam values[2];
GRunModeType run_mode;
GStatusType status = STATUS_SUCCESS;
gint32 image_ID;
run_mode = param[0].data.d_int32;
*nreturn_vals = 1;
*return_vals = values;
values[0].type = PARAM_STATUS;
values[0].data.d_status = STATUS_CALLING_ERROR;
if (strcmp (name, "file_gz_load") == 0)
{
image_ID = load_image (param[1].data.d_string,
param[0].data.d_int32);
if (image_ID != -1)
{
*nreturn_vals = 2;
values[0].data.d_status = STATUS_SUCCESS;
values[1].type = PARAM_IMAGE;
values[1].data.d_image = image_ID;
}
else
{
values[0].data.d_status = STATUS_EXECUTION_ERROR;
g_assert (FALSE);
}
}
else if (strcmp (name, "file_gz_save") == 0)
{
switch (run_mode)
{
case RUN_INTERACTIVE:
break;
case RUN_NONINTERACTIVE:
/* Make sure all the arguments are there! */
if (nparams != 4)
status = STATUS_CALLING_ERROR;
case RUN_WITH_LAST_VALS:
break;
default:
break;
}
*nreturn_vals = 1;
if (save_image (param[3].data.d_string,
param[1].data.d_int32,
param[2].data.d_int32,
param[0].data.d_int32 ))
{
values[0].data.d_status = STATUS_SUCCESS;
}
else
values[0].data.d_status = STATUS_EXECUTION_ERROR;
}
else
g_assert (FALSE);
}
static gint
save_image (char *filename,
gint32 image_ID,
gint32 drawable_ID,
gint32 run_mode)
{
FILE* f;
GParam* params;
gint retvals;
char* ext;
char* tmpname;
int pid;
int status;
ext = find_extension(filename);
if (0 == *ext) {
g_warning("gz: no sensible extension, saving as gzip'd xcf\n");
ext = ".xcf";
}
/* get a temp name with the right extension and save into it. */
params = gimp_run_procedure ("gimp_temp_name",
&retvals,
PARAM_STRING, ext + 1,
PARAM_END);
tmpname = params[1].data.d_string;
params = gimp_run_procedure ("gimp_file_save",
&retvals,
PARAM_INT32, run_mode,
PARAM_IMAGE, image_ID,
PARAM_DRAWABLE, drawable_ID,
PARAM_STRING, tmpname,
PARAM_STRING, tmpname,
PARAM_END);
if (params[0].data.d_status == FALSE || !valid_file(tmpname)) {
unlink (tmpname);
return -1;
}
/* if (! file_save(image_ID, tmpname, tmpname)) { */
/* unlink (tmpname); */
/* return -1; */
/* } */
/* fork off a gzip process */
if ((pid = fork()) < 0)
{
g_warning ("gz: fork failed: %s\n", g_strerror(errno));
return -1;
}
else if (pid == 0)
{
f = fopen(filename,"w");
/* make stdout for this process be the output file */
if (-1 == dup2(fileno(f),fileno(stdout)))
g_warning ("gz: dup2 failed: %s\n", g_strerror(errno));
/* and gzip into it */
execlp ("gzip", "gzip", "-cf", tmpname, NULL);
g_warning ("gz: exec failed: gzip: %s\n", g_strerror(errno));
_exit(127);
}
else
{
waitpid (pid, &status, 0);
if (!WIFEXITED(status) ||
WEXITSTATUS(status) != 0)
{
g_warning ("gz: gzip exited abnormally on file %s\n", tmpname);
return 0;
}
}
unlink (tmpname);
return TRUE;
}
static gint32
load_image (char *filename, gint32 run_mode)
{
GParam* params;
gint retvals;
char* ext;
char* tmpname;
int pid;
int status;
ext = find_extension(filename);
if (0 == *ext) {
g_warning("gz: no sensible extension, attempting to load with file magic\n");
}
/* find a temp name */
params = gimp_run_procedure ("gimp_temp_name",
&retvals,
PARAM_STRING, ext + 1,
PARAM_END);
tmpname = params[1].data.d_string;
/* fork off a g(un)zip and wait for it */
if ((pid = fork()) < 0)
{
g_warning ("gz: fork failed: %s\n", g_strerror(errno));
return -1;
}
else if (pid == 0) /* child process */
{
FILE* f;
f = fopen(tmpname,"w");
/* make stdout for this child process be the temp file */
if (-1 == dup2(fileno(f),fileno(stdout)))
g_warning ("gz: dup2 failed: %s\n", g_strerror(errno));
/* and unzip into it */
execlp ("gzip", "gzip", "-cfd", filename, NULL);
g_warning ("gz: exec failed: gunzip: %s\n", g_strerror(errno));
_exit(127);
}
else /* parent process */
{
waitpid (pid, &status, 0);
if (!WIFEXITED(status) ||
WEXITSTATUS(status) != 0)
{
g_warning ("gz: gzip exited abnormally on file %s\n", filename);
return -1;
}
}
/* now that we un-gziped it, load the temp file */
params = gimp_run_procedure ("gimp_file_load",
&retvals,
PARAM_INT32, run_mode,
PARAM_STRING, tmpname,
PARAM_STRING, tmpname,
PARAM_END);
unlink (tmpname);
if (params[0].data.d_status == FALSE)
return -1;
else
{
gimp_image_set_filename (params[1].data.d_int32, filename);
return params[1].data.d_int32;
}
}
static int valid_file (char* filename)
{
int stat_res;
struct stat buf;
stat_res = stat(filename, &buf);
if ((0 == stat_res) && (buf.st_size > 0))
return 1;
else
return 0;
}
static char* find_extension (char* filename)
{
char* filename_copy;
char* ext;
/* we never free this copy - aren't we evil! */
filename_copy = malloc(strlen(filename)+1);
strcpy(filename_copy, filename);
/* find the extension, boy! */
ext = strrchr (filename_copy, '.');
while (1) {
if (!ext || ext[1] == 0 || strchr(ext, '/'))
{
return "";
}
if (0 == strcmp(ext, ".xcfgz")) {
return ".xcf"; /* we've found it */
}
if (0 != strcmp(ext,".gz")) {
return ext;
} else {
/* we found ".gz" so strip it, loop back, and look again */
*ext = 0;
ext = strrchr (filename_copy, '.');
}
}
}

View File

@ -1,154 +0,0 @@
#include <stdlib.h>
#include <stdio.h>
#include "libgimp/gimp.h"
/* Declare some local functions.
*/
static void query (void);
static void run (char *name,
int nparams,
GParam *param,
int *nreturn_vals,
GParam **return_vals);
static int save_image (char *filename,
gint32 image_ID,
gint32 drawable_ID);
GPlugInInfo PLUG_IN_INFO =
{
NULL, /* init_proc */
NULL, /* quit_proc */
query, /* query_proc */
run, /* run_proc */
};
MAIN ()
static void
query ()
{
static GParamDef save_args[] =
{
{ PARAM_INT32, "run_mode", "Interactive, non-interactive" },
{ PARAM_IMAGE, "image", "Input image" },
{ PARAM_DRAWABLE, "drawable", "Drawable to save" },
{ PARAM_STRING, "filename", "The name of the file to save the image in" },
{ PARAM_STRING, "raw_filename", "The name of the file to save the image in" },
};
static int nsave_args = sizeof (save_args) / sizeof (save_args[0]);
gimp_install_procedure ("file_header_save",
"saves files as C unsigned character array",
"FIXME: write help",
"Spencer Kimball & Peter Mattis",
"Spencer Kimball & Peter Mattis",
"1997",
"<Save>/Header",
"RGB*",
PROC_PLUG_IN,
nsave_args, 0,
save_args, NULL);
gimp_register_save_handler ("file_header_save", "h", "");
}
static void
run (char *name,
int nparams,
GParam *param,
int *nreturn_vals,
GParam **return_vals)
{
static GParam values[2];
GRunModeType run_mode;
run_mode = param[0].data.d_int32;
*nreturn_vals = 1;
*return_vals = values;
values[0].type = PARAM_STATUS;
values[0].data.d_status = STATUS_CALLING_ERROR;
if (strcmp (name, "file_header_save") == 0)
{
*nreturn_vals = 1;
if (save_image (param[3].data.d_string, param[1].data.d_int32, param[2].data.d_int32))
values[0].data.d_status = STATUS_SUCCESS;
else
values[0].data.d_status = STATUS_EXECUTION_ERROR;
}
}
static int
save_image (char *filename,
gint32 image_ID,
gint32 drawable_ID)
{
GPixelRgn pixel_rgn;
GDrawable *drawable;
GDrawableType drawable_type;
FILE *fp;
int x, y, b, c;
gchar *backslash = "\\\\";
gchar *quote = "\\\"";
gchar *newline = "\"\n\t\"";
gchar buf[4];
guchar *d;
guchar *data;
if ((fp = fopen (filename, "w")) == NULL)
return FALSE;
drawable = gimp_drawable_get (drawable_ID);
drawable_type = gimp_drawable_type (drawable_ID);
gimp_pixel_rgn_init (&pixel_rgn, drawable, 0, 0, drawable->width, drawable->height, FALSE, FALSE);
fprintf (fp, "/* GIMP header image file format (RGB-only): %s */\n\n", filename);
fprintf (fp, "static unsigned int width = %d;\n", drawable->width);
fprintf (fp, "static unsigned int height = %d;\n\n", drawable->height);
fprintf (fp, "/* Call this macro repeatedly. After each use, the pixel data can be extracted */\n\n");
fprintf (fp, "#define HEADER_PIXEL(data,pixel) \\\n pixel[0] = (((data[0] - 33) << 2) | ((data[1] - 33) >> 4)); \\\n pixel[1] = ((((data[1] - 33) & 0xF) << 4) | ((data[2] - 33) >> 2)); \\\n pixel[2] = ((((data[2] - 33) & 0x3) << 6) | ((data[3] - 33))); \\\n data += 4;\n\n");
fprintf (fp, "static char *header_data =\n\t\"");
data = g_new (guchar, drawable->width * drawable->bpp);
c = 0;
for (y = 0; y < drawable->height; y++)
{
gimp_pixel_rgn_get_row (&pixel_rgn, data, 0, y, drawable->width);
for (x = 0; x < drawable->width; x++)
{
d = data + x * drawable->bpp;
buf[0] = ((d[0] >> 2) & 0x3F) + 33;
buf[1] = ((((d[0] & 0x3) << 4) | (d[1] >> 4)) & 0x3F) + 33;
buf[2] = ((((d[1] & 0xF) << 2) | (d[2] >> 6)) & 0x3F) + 33;
buf[3] = (d[2] & 0x3F) + 33;
for (b = 0; b < 4; b++)
if (buf[b] == 34)
fwrite (quote, 1, 2, fp);
else if (buf[b] == 92)
fwrite (backslash, 1, 2, fp);
else
fwrite (buf + b, 1, 1, fp);
c++;
if (c >= 16)
{
fwrite (newline, 1, 4, fp);
c = 0;
}
}
}
fprintf (fp, "\";\n");
fclose (fp);
g_free (data);
gimp_drawable_detach (drawable);
return TRUE;
}

View File

@ -1,900 +0,0 @@
/* The GIMP -- an image manipulation program * Copyright (C) 1995 Spencer
* Kimball and Peter Mattis * * 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 * the Free Software Foundation; either
* version 2 of the License, or * (at your option) any later version. * *
* This program is distributed in the hope that it will be useful, * but
* WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU
* General Public License for more details. * * 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., 675 Mass Ave, Cambridge, MA
* 02139, USA. */
/* Holes 0.5 */
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include "libgimp/gimp.h"
#include "gtk/gtk.h"
/* Declare local functions. */
static void query(void);
static void run(char *name,
int nparams,
GParam * param,
int *nreturn_vals,
GParam ** return_vals);
static void doit(GDrawable * drawable);
/* UI funcs */
#define ENTRY_WIDTH 50
#define SCALE_WIDTH 150
static void UI_int_entryscale_new ( GtkTable *table, gint x, gint y,
guchar *caption, gint *intvar,
gint min, gint max, gint constraint);
static void UI_paired_entry_destroy_callback (GtkWidget *widget,
gpointer data);
static void UI_paired_int_scale_update (GtkAdjustment *adjustment,
gpointer data);
static void UI_paired_int_entry_update (GtkWidget *widget,
gpointer data);
static void UI_float_entryscale_new ( GtkTable *table, gint x, gint y,
guchar *caption, gfloat *var,
gfloat min, gfloat max, gint constraint);
static void UI_paired_float_scale_update (GtkAdjustment *adjustment,
gpointer data);
static void UI_paired_float_entry_update (GtkWidget *widget,
gpointer data);
static void UI_close_callback (GtkWidget *widget,
gpointer data);
static void UI_ok_callback (GtkWidget *widget,
gpointer data);
static gint dialog();
GPlugInInfo PLUG_IN_INFO =
{
NULL, /* init_proc */
NULL, /* quit_proc */
query, /* query_proc */
run, /* run_proc */
};
gint bytes;
gint sx1, sy1, sx2, sy2;
guchar *shape_data= NULL, *tmp= NULL;
gint curve[256];
typedef struct {
gint run;
} HolesInterface;
typedef struct {
GtkObject *adjustment;
GtkWidget *entry;
gint constraint;
} EntryScaleData;
static HolesInterface pint =
{
FALSE /* run */
};
typedef struct {
float density;
gint shape, size, flag;
} holes_parameters;
/* possible shapes */
#define SQUARE_SHAPE 0
#define CIRCLE_SHAPE 1
#define DIAMOND_SHAPE 2
static holes_parameters params = { -3.1, CIRCLE_SHAPE, 8, TRUE };
MAIN()
static void query()
{
static GParamDef args[] =
{
{PARAM_INT32, "run_mode", "Interactive, non-interactive"},
{PARAM_IMAGE, "image", "Input image (unused)"},
{PARAM_DRAWABLE, "drawable", "Input drawable"},
{PARAM_FLOAT, "density", "Density (actually the log of the density)"},
{PARAM_INT32, "shape", "shape (0= square, 1= round, 2= diamond)"},
{PARAM_INT32, "size", "size (in pixels)"},
{PARAM_INT32, "flag", "Clear it if you want to make holes in your image, or set it if you want to keep the painted (I mean opaque) regions."},
};
static GParamDef *return_vals = NULL;
static int nargs = sizeof(args) / sizeof(args[0]);
static int nreturn_vals = 0;
gimp_install_procedure("plug_in_holes",
"make bucks on a image.",
"makes holes in the alpha channel of an image, with a density depending on the actual transparency of this image. (so the image must have an alpha channel...)",
"Xavier Bouchoux",
"Xavier Bouchoux",
"1997",
"<Image>/Filters/Holes",
"RGBA, GRAYA, INDEXEDA",
PROC_PLUG_IN,
nargs, nreturn_vals,
args, return_vals
);
}
static void run(char *name, int n_params, GParam * param, int *nreturn_vals,
GParam ** return_vals)
{
static GParam values[1];
GDrawable *drawable;
GRunModeType run_mode;
GStatusType status = STATUS_SUCCESS;
*nreturn_vals = 1;
*return_vals = values;
run_mode = param[0].data.d_int32;
if (run_mode == RUN_NONINTERACTIVE) {
if (n_params != 8) {
status = STATUS_CALLING_ERROR;
} else {
params.density = param[3].data.d_float;
params.shape = param[4].data.d_int32;
params.size = param[5].data.d_int32;
params.flag = param[6].data.d_int32;
}
} else {
/* Possibly retrieve data */
gimp_get_data("plug_in_holes", &params);
if ((run_mode == RUN_INTERACTIVE) ) {
/* Oh boy. We get to do a dialog box, because we can't really expect the
* user to set us up with the right values using gdb.
*/
if (!dialog()) {
/* The dialog was closed, or something similarly evil happened. */
status = STATUS_EXECUTION_ERROR;
}
}
}
if (status == STATUS_SUCCESS) {
/* 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_has_alpha (drawable->id) && (gimp_drawable_color(drawable->id) || gimp_drawable_gray(drawable->id) ||gimp_drawable_indexed (drawable->id))) {
gimp_progress_init("holes");
gimp_tile_cache_ntiles(4);
srand(time(NULL));
doit(drawable);
if (run_mode != RUN_NONINTERACTIVE)
gimp_displays_flush();
if (run_mode == RUN_INTERACTIVE)
gimp_set_data("plug_in_holes", &params, sizeof(params));
} else {
status = STATUS_EXECUTION_ERROR;
}
}
values[0].type = PARAM_STATUS;
values[0].data.d_status = status;
gimp_drawable_detach(drawable);
}
static void make_curve (gdouble sigma)
{
gdouble sigma2;
gint i;
sigma2 = 2 * sigma * sigma;
if (params.flag)
for (i = 0; i < 256; i++)
{
curve[i] = (gint) (exp (- (i/22.0 * i/22.0) / sigma2) * RAND_MAX);
}
else
for (i = 0; i < 256; i++)
{
curve[255-i] = (gint) (exp (- (i/22.0 * i/22.0) / sigma2) * RAND_MAX);
}
}
/* Prepare the shape data: makes a buffer with the shape calculated with
* the goood size.
*/
static int prepare_shape()
{
int i,j, center;
shape_data = malloc(params.size*params.size);
if (shape_data == NULL)
return 0;
switch (params.shape) {
case SQUARE_SHAPE:
for (i=0;i<params.size; i++)
for (j=0; j<params.size; j++)
shape_data[i*params.size+j]=255;
break;
case CIRCLE_SHAPE:
center= params.size/2;
for (i=0;i<params.size; i++)
for (j=0; j<params.size; j++)
if (((i-center)*(i-center)+(j-center)*(j-center))<center*center)
shape_data[i*params.size+j]=255;
else
shape_data[i*params.size+j]=0;
break;
case DIAMOND_SHAPE:
center= params.size/2;
for (i=0; i<params.size; i++)
for (j=0; j<params.size; j++)
if ((abs(i-center)+abs(j-center))<center)
shape_data[i*params.size+j]=255;
else
shape_data[i*params.size+j]=0;
break;
default:
return 0;
}
return 1;
}
/*
* Puts the shape (=the buck) in the alpha layer of the destination image,
* at position x,y
*/
static void make_hole(GPixelRgn * region, int x, int y)
{
int j, k, startx=0, starty=0;
int rx1, rx2, ry1, ry2;
int new;
rx1 = x - params.size / 2;
rx2 = rx1 + params.size;
ry1 = y - params.size / 2;
ry2 = ry1 + params.size;
/* clipping */
if (rx1 < sx1) {
startx=sx1-rx1;
rx1= sx1;
}
if (ry1 < sy1) {
starty=sy1-ry1;
ry1= sy1;
}
rx2 = rx2 > sx2 ? sx2 : rx2;
ry2 = ry2 > sy2 ? sy2 : ry2;
gimp_pixel_rgn_get_rect(region, tmp, rx1, ry1, rx2 - rx1, ry2 - ry1);
for (k = 0; k < (ry2 - ry1); k++) {
for (j = 0; j < (rx2 - rx1); j++) {
new= tmp[((rx2-rx1)*k+j) * bytes + (bytes-1)]-
shape_data[params.size*(k+starty)+j+startx];
tmp[((rx2-rx1)*k+j) * bytes + (bytes-1)]= (new<=0? 0 : new);
}
}
gimp_pixel_rgn_set_rect(region, tmp, rx1, ry1, rx2 - rx1, ry2 - ry1);
}
static void make_hole_inv(GPixelRgn * region, int x, int y)
{
int j, k, startx=0, starty=0;
int rx1, rx2, ry1, ry2;
int new;
rx1 = x - params.size / 2;
rx2 = rx1 + params.size;
ry1 = y - params.size / 2;
ry2 = ry1 + params.size;
/* clipping */
if (rx1 < sx1) {
startx=sx1-rx1;
rx1= sx1;
}
if (ry1 < sy1) {
starty=sy1-ry1;
ry1= sy1;
}
rx2 = rx2 > sx2 ? sx2 : rx2;
ry2 = ry2 > sy2 ? sy2 : ry2;
gimp_pixel_rgn_get_rect(region, tmp, rx1, ry1, rx2 - rx1, ry2 - ry1);
for (k = 0; k < (ry2 - ry1); k++) {
for (j = 0; j < (rx2 - rx1); j++) {
new= tmp[((rx2-rx1)*k+j) * bytes + (bytes-1)]+
shape_data[params.size*(k+starty)+j+startx];
tmp[((rx2-rx1)*k+j) * bytes + (bytes-1)]= (new>255? 255 : new);
}
}
gimp_pixel_rgn_set_rect(region, tmp, rx1, ry1, rx2 - rx1, ry2 - ry1);
}
static void doit(GDrawable * drawable)
{
GPixelRgn srcPR, destPR;
gint width, height;
int x, y;
int col, row, b;
guchar *src_row, *dest_row;
guchar *src, *dest;
gint progress, max_progress;
gpointer pr;
guchar val_alpha;
/* 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, &sx1, &sy1, &sx2, &sy2);
/* Get the size of the input image. (This will/must be the same
* as the size of the output image.
*/
width = drawable->width;
height = drawable->height;
bytes = drawable->bpp;
/* initialize buffers and data */
tmp = (guchar *) malloc(params.size * params.size * bytes);
if (tmp == NULL) {
return;
}
if (!prepare_shape())
return;
make_curve(exp(-params.density));
progress = 0;
max_progress = (sx2 - sx1) * (sy2 - sy1) * 2;
/* initialize the pixel regions */
gimp_pixel_rgn_init(&srcPR, drawable, sx1, sy1, sx2-sx1, sy2-sy1, FALSE, FALSE);
gimp_pixel_rgn_init(&destPR, drawable, sx1, sy1, sx2-sx1, sy2-sy1, TRUE, TRUE);
/* First off, copy the old one to the new one. */
if (params.flag)
val_alpha=0;
else
val_alpha=255;
for (pr = gimp_pixel_rgns_register (2, &srcPR, &destPR);
pr != NULL; pr = gimp_pixel_rgns_process (pr)) {
src_row = srcPR.data;
dest_row = destPR.data;
for ( row = 0; row < srcPR.h; row++) {
src = src_row;
dest = dest_row;
for ( col = 0; col < srcPR.w; col++) {
for (b=0; b< bytes-1; b++)
*dest++ = *src++;
src++; /* set alpha to opaque */
*dest++ = val_alpha;
}
src_row += srcPR.rowstride;
dest_row += destPR.rowstride;
}
progress += srcPR.w * srcPR.h;
gimp_progress_update ((double) progress / (double) max_progress);
}
/* Do the effect */
gimp_pixel_rgn_init(&srcPR, drawable, sx1, sy1, sx2-sx1, sy2-sy1, FALSE, FALSE);
if (params.flag) {
for (pr = gimp_pixel_rgns_register (1, &srcPR);
pr != NULL; pr = gimp_pixel_rgns_process (pr)) {
src_row = srcPR.data;
for ( row = 0, y = srcPR.y; row < srcPR.h; row++, y++) {
src = src_row;
for ( col = 0, x = srcPR.x; col < srcPR.w; col++, x++) {
if (curve[src[bytes-1]]<rand()) {
make_hole_inv(&destPR, x, y);
}
src+= bytes;
}
src_row += srcPR.rowstride;
}
progress += srcPR.w * srcPR.h;
gimp_progress_update ((double) progress / (double) max_progress);
}
} else {
for (pr = gimp_pixel_rgns_register (1, &srcPR);
pr != NULL; pr = gimp_pixel_rgns_process (pr)) {
src_row = srcPR.data;
for ( row = 0, y = srcPR.y; row < srcPR.h; row++, y++) {
src = src_row;
for ( col = 0, x = srcPR.x; col < srcPR.w; col++, x++) {
if (curve[src[bytes-1]]<rand()) {
make_hole(&destPR, x, y);
}
src+= bytes;
}
src_row += srcPR.rowstride;
}
progress += srcPR.w * srcPR.h;
gimp_progress_update ((double) progress / (double) max_progress);
}
}
/* free the mem */
free(tmp);
free(shape_data);
/* update the region */
gimp_drawable_flush(drawable);
gimp_drawable_merge_shadow(drawable->id, TRUE);
gimp_drawable_update(drawable->id, sx1, sy1, sx2 - sx1, sy2 - sy1);
}
/***************************************************
* GUI stuff
*/
/*===================================================================
Entry - Scale Pair
====================================================================*/
/***********************************************************************/
/* */
/* Create new entry-scale pair with label. (int) */
/* 1 row and 2 cols of table are needed. */
/* */
/* `x' and `y' means starting row and col in `table'. */
/* */
/* `caption' is label string. */
/* */
/* `min', `max' are boundary of scale. */
/* */
/* `constraint' means whether value of *intvar should be constraint */
/* by scale adjustment, e.g. between `min' and `max'. */
/* */
/***********************************************************************/
static void
UI_int_entryscale_new ( GtkTable *table, gint x, gint y,
guchar *caption, gint *intvar,
gint min, gint max, gint constraint)
{
GtkWidget *hbox;
GtkWidget *label;
GtkWidget *entry;
GtkWidget *scale;
GtkObject *adjustment;
EntryScaleData *userdata;
guchar buffer[256];
label = gtk_label_new (caption);
gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
adjustment = gtk_adjustment_new ( *intvar, min, max, 1.0, 1.0, 0.0);
scale = gtk_hscale_new ( GTK_ADJUSTMENT(adjustment) );
gtk_widget_set_usize (scale, SCALE_WIDTH, 0);
gtk_scale_set_draw_value (GTK_SCALE (scale), FALSE);
entry = gtk_entry_new ();
gtk_widget_set_usize (entry, ENTRY_WIDTH, 0);
sprintf( buffer, "%d", *intvar );
gtk_entry_set_text( GTK_ENTRY (entry), buffer );
userdata = g_new ( EntryScaleData, 1 );
userdata->entry = entry;
userdata->adjustment = adjustment;
userdata->constraint = constraint;
gtk_object_set_user_data (GTK_OBJECT(entry), userdata);
gtk_object_set_user_data (GTK_OBJECT(adjustment), userdata);
gtk_signal_connect (GTK_OBJECT (entry), "changed",
(GtkSignalFunc) UI_paired_int_entry_update,
intvar);
gtk_signal_connect ( adjustment, "value_changed",
(GtkSignalFunc) UI_paired_int_scale_update,
intvar);
gtk_signal_connect ( GTK_OBJECT( entry ), "destroy",
(GtkSignalFunc) UI_paired_entry_destroy_callback,
userdata );
hbox = gtk_hbox_new ( FALSE, 5 );
gtk_box_pack_start (GTK_BOX (hbox), scale, TRUE, TRUE, 0);
gtk_box_pack_start (GTK_BOX (hbox), entry, FALSE, TRUE, 0);
gtk_table_attach (GTK_TABLE (table), label, x, x+1, y, y+1,
GTK_FILL, GTK_FILL, 0, 0);
gtk_table_attach (GTK_TABLE (table), hbox, x+1, x+2, y, y+1,
GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
gtk_widget_show (label);
gtk_widget_show (entry);
gtk_widget_show (scale);
gtk_widget_show (hbox);
}
/*
when destroyed, userdata is destroyed too
*/
static void
UI_paired_entry_destroy_callback (GtkWidget *widget,
gpointer data)
{
EntryScaleData *userdata;
userdata = data;
g_free ( userdata );
}
/* scale callback (int) */
/* ==================== */
static void
UI_paired_int_scale_update (GtkAdjustment *adjustment,
gpointer data)
{
EntryScaleData *userdata;
GtkEntry *entry;
gchar buffer[256];
gint *val, new_val;
val = data;
new_val = (gint) adjustment->value;
*val = new_val;
userdata = gtk_object_get_user_data (GTK_OBJECT (adjustment));
entry = GTK_ENTRY( userdata->entry );
sprintf (buffer, "%d", (int) new_val );
/* avoid infinite loop (scale, entry, scale, entry ...) */
gtk_signal_handler_block_by_data ( GTK_OBJECT(entry), data );
gtk_entry_set_text ( entry, buffer);
gtk_signal_handler_unblock_by_data ( GTK_OBJECT(entry), data );
}
/*
entry callback (int)
*/
static void
UI_paired_int_entry_update (GtkWidget *widget,
gpointer data)
{
EntryScaleData *userdata;
GtkAdjustment *adjustment;
int new_val, constraint_val;
int *val;
val = data;
new_val = atoi (gtk_entry_get_text (GTK_ENTRY (widget)));
*val = new_val;
userdata = gtk_object_get_user_data (GTK_OBJECT (widget));
adjustment = GTK_ADJUSTMENT( userdata->adjustment );
constraint_val = new_val;
if ( constraint_val < adjustment->lower )
constraint_val = adjustment->lower;
if ( constraint_val > adjustment->upper )
constraint_val = adjustment->upper;
if ( userdata->constraint )
*val = constraint_val;
else
*val = new_val;
adjustment->value = constraint_val;
gtk_signal_handler_block_by_data ( GTK_OBJECT(adjustment), data );
gtk_signal_emit_by_name ( GTK_OBJECT(adjustment), "value_changed");
gtk_signal_handler_unblock_by_data ( GTK_OBJECT(adjustment), data );
}
/* The same thing, but with floats... */
static void
UI_float_entryscale_new ( GtkTable *table, gint x, gint y,
guchar *caption, gfloat *var,
gfloat min, gfloat max, gint constraint)
{
GtkWidget *hbox;
GtkWidget *label;
GtkWidget *entry;
GtkWidget *scale;
GtkObject *adjustment;
EntryScaleData *userdata;
guchar buffer[256];
label = gtk_label_new (caption);
gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
adjustment = gtk_adjustment_new ( *var, min, max, 1.0, 1.0, 0.0);
scale = gtk_hscale_new ( GTK_ADJUSTMENT(adjustment) );
gtk_widget_set_usize (scale, SCALE_WIDTH, 0);
gtk_scale_set_draw_value (GTK_SCALE (scale), FALSE);
entry = gtk_entry_new ();
gtk_widget_set_usize (entry, ENTRY_WIDTH, 0);
sprintf( buffer, "%1.2f", *var );
gtk_entry_set_text( GTK_ENTRY (entry), buffer );
userdata = g_new ( EntryScaleData, 1 );
userdata->entry = entry;
userdata->adjustment = adjustment;
userdata->constraint = constraint;
gtk_object_set_user_data (GTK_OBJECT(entry), userdata);
gtk_object_set_user_data (GTK_OBJECT(adjustment), userdata);
gtk_signal_connect (GTK_OBJECT (entry), "changed",
(GtkSignalFunc) UI_paired_float_entry_update,
var);
gtk_signal_connect ( adjustment, "value_changed",
(GtkSignalFunc) UI_paired_float_scale_update,
var);
gtk_signal_connect ( GTK_OBJECT( entry ), "destroy",
(GtkSignalFunc) UI_paired_entry_destroy_callback,
userdata );
hbox = gtk_hbox_new ( FALSE, 5 );
gtk_box_pack_start (GTK_BOX (hbox), scale, TRUE, TRUE, 0);
gtk_box_pack_start (GTK_BOX (hbox), entry, FALSE, TRUE, 0);
gtk_table_attach (GTK_TABLE (table), label, x, x+1, y, y+1,
GTK_FILL, GTK_FILL, 0, 0);
gtk_table_attach (GTK_TABLE (table), hbox, x+1, x+2, y, y+1,
GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
gtk_widget_show (label);
gtk_widget_show (entry);
gtk_widget_show (scale);
gtk_widget_show (hbox);
}
/* scale callback (float) */
/* ==================== */
static void
UI_paired_float_scale_update (GtkAdjustment *adjustment,
gpointer data)
{
EntryScaleData *userdata;
GtkEntry *entry;
gchar buffer[256];
gfloat *val, new_val;
val = data;
new_val = (gfloat) adjustment->value;
*val = new_val;
userdata = gtk_object_get_user_data (GTK_OBJECT (adjustment));
entry = GTK_ENTRY( userdata->entry );
sprintf (buffer, "%1.2f", (gfloat) new_val );
/* avoid infinite loop (scale, entry, scale, entry ...) */
gtk_signal_handler_block_by_data ( GTK_OBJECT(entry), data );
gtk_entry_set_text ( entry, buffer);
gtk_signal_handler_unblock_by_data ( GTK_OBJECT(entry), data );
}
/*
entry callback (float)
*/
static void
UI_paired_float_entry_update (GtkWidget *widget,
gpointer data)
{
EntryScaleData *userdata;
GtkAdjustment *adjustment;
gfloat new_val, constraint_val;
gfloat *val;
val = data;
new_val = atof (gtk_entry_get_text (GTK_ENTRY (widget)));
*val = new_val;
userdata = gtk_object_get_user_data (GTK_OBJECT (widget));
adjustment = GTK_ADJUSTMENT( userdata->adjustment );
constraint_val = new_val;
if ( constraint_val < adjustment->lower )
constraint_val = adjustment->lower;
if ( constraint_val > adjustment->upper )
constraint_val = adjustment->upper;
if ( userdata->constraint )
*val = constraint_val;
else
*val = new_val;
adjustment->value = constraint_val;
gtk_signal_handler_block_by_data ( GTK_OBJECT(adjustment), data );
gtk_signal_emit_by_name ( GTK_OBJECT(adjustment), "value_changed");
gtk_signal_handler_unblock_by_data ( GTK_OBJECT(adjustment), data );
}
static void
UI_toggle_update (GtkWidget *widget,
gpointer data)
{
int *toggle_val;
toggle_val = (int *) data;
if (GTK_TOGGLE_BUTTON (widget)->active)
*toggle_val = TRUE;
else
*toggle_val = FALSE;
}
void shape_radio_callback(GtkWidget *widget, GtkRadioButton *button)
{
gint id;
/* Get radio button ID */
id=(gint)gtk_object_get_data(GTK_OBJECT(button),"Radio_ID");
if (GTK_TOGGLE_BUTTON(button)->active==TRUE) {
params.shape= id;
}
}
/*** Dialog interface ***/
static void
UI_close_callback (GtkWidget *widget,
gpointer data)
{
gtk_main_quit ();
}
static void
UI_ok_callback (GtkWidget *widget,
gpointer data)
{
pint.run = TRUE;
gtk_widget_destroy (GTK_WIDGET (data));
}
static gint
dialog ()
{
GtkWidget *dlg;
GtkWidget *frame;
GtkWidget *table;
GtkWidget *button;
GtkWidget *toggle;
GSList *group = NULL;
gchar **argv;
gint argc;
argc = 1;
argv = g_new (gchar *, 1);
argv[0] = g_strdup ("holes");
gtk_init (&argc, &argv);
gtk_rc_parse (gimp_gtkrc ());
dlg = gtk_dialog_new ();
gtk_window_set_title (GTK_WINDOW (dlg), "Holes");
gtk_window_position (GTK_WINDOW (dlg), GTK_WIN_POS_MOUSE);
gtk_signal_connect (GTK_OBJECT (dlg), "destroy",
(GtkSignalFunc) UI_close_callback,
NULL);
/* Action area */
button = gtk_button_new_with_label ("OK");
GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
gtk_signal_connect (GTK_OBJECT (button), "clicked",
(GtkSignalFunc) UI_ok_callback,
dlg);
gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dlg)->action_area), button, TRUE, TRUE, 0);
gtk_widget_grab_default (button);
gtk_widget_show (button);
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));
gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dlg)->action_area), button, TRUE, TRUE, 0);
gtk_widget_show (button);
/* parameter settings */
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 (6, 2, FALSE);
gtk_container_border_width (GTK_CONTAINER (table), 10);
gtk_container_add (GTK_CONTAINER (frame), table);
gtk_table_set_row_spacings (GTK_TABLE (table), 3);
gtk_table_set_col_spacings (GTK_TABLE (table), 10);
UI_int_entryscale_new( GTK_TABLE (table), 0, 1,
"Size:", &params.size,
1, 100, TRUE );
UI_float_entryscale_new( GTK_TABLE (table), 0, 2,
"Density:", &params.density,
-5.0, 5.0, TRUE );
toggle = gtk_check_button_new_with_label ("Keep opaque");
gtk_table_attach (GTK_TABLE (table), toggle, 0, 1, 3, 4,
GTK_FILL, GTK_FILL, 0, 0);
gtk_signal_connect (GTK_OBJECT (toggle), "toggled",
(GtkSignalFunc) UI_toggle_update,
&params.flag);
gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (toggle), params.flag);
gtk_widget_show(toggle);
toggle = gtk_radio_button_new_with_label (group,"square shaped holes");
group = gtk_radio_button_group (GTK_RADIO_BUTTON (toggle));
gtk_table_attach (GTK_TABLE (table), toggle, 1, 2, 3, 4,
GTK_FILL, GTK_FILL, 0, 0);
gtk_signal_connect_object (GTK_OBJECT (toggle), "toggled",
(GtkSignalFunc) shape_radio_callback,
(gpointer)toggle);
gtk_object_set_data(GTK_OBJECT(toggle),"Radio_ID",(gpointer)SQUARE_SHAPE);
gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (toggle), (params.shape == SQUARE_SHAPE));
gtk_widget_show (toggle);
toggle = gtk_radio_button_new_with_label (group,"round shaped holes");
group = gtk_radio_button_group (GTK_RADIO_BUTTON (toggle));
gtk_table_attach (GTK_TABLE (table), toggle, 1, 2, 4, 5,
GTK_FILL, GTK_FILL, 0, 0);
gtk_signal_connect_object (GTK_OBJECT (toggle), "toggled",
(GtkSignalFunc) shape_radio_callback,
(gpointer)toggle);
gtk_object_set_data(GTK_OBJECT(toggle),"Radio_ID",(gpointer)CIRCLE_SHAPE);
gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (toggle), (params.shape == CIRCLE_SHAPE));
gtk_widget_show (toggle);
toggle = gtk_radio_button_new_with_label (group,"diamond shaped holes");
group = gtk_radio_button_group (GTK_RADIO_BUTTON (toggle));
gtk_table_attach (GTK_TABLE (table), toggle, 1, 2, 5, 6,
GTK_FILL, GTK_FILL, 0, 0);
gtk_signal_connect_object (GTK_OBJECT (toggle), "toggled",
(GtkSignalFunc) shape_radio_callback,
(gpointer)toggle);
gtk_object_set_data(GTK_OBJECT(toggle),"Radio_ID",(gpointer)DIAMOND_SHAPE);
gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (toggle), (params.shape == DIAMOND_SHAPE));
gtk_widget_show (toggle);
gtk_widget_show (frame);
gtk_widget_show (table);
gtk_widget_show (dlg);
gtk_main ();
gdk_flush ();
return pint.run;
}

View File

@ -1,652 +0,0 @@
/*
* file: hot/hot.c
*
* $Id$
*/
/*
* hot.c - Scan an image for pixels with RGB values that will give
* "unsafe" values of chrominance signal or composite signal
* amplitude when encoded into an NTSC or PAL colour signal.
* (This happens for certain high-intensity high-saturation colours
* that are rare in real scenes, but can easily be present
* in synthetic images.)
*
* Such pixels can be flagged so the user may then choose other
* colours. Or, the offending pixels can be made "safe"
* in a manner that preserves hue.
*
* There are two reasonable ways to make a pixel "safe":
* We can reduce its intensity (luminance) while leaving
* hue and saturation the same. Or, we can reduce saturation
* while leaving hue and luminance the same. A #define selects
* which strategy to use.
*
* Note to the user: You must add your own read_pixel() and write_pixel()
* routines. You may have to modify pix_decode() and pix_encode().
* MAXPIX, WID, and HGT are likely to need modification.
*/
/*
* Originally written as "ikNTSC.c" by Alan Wm Paeth,
* University of Waterloo, August, 1985
* Updated by Dave Martindale, Imax Systems Corp., December 1990
*/
/*
* Compile time options:
*
*
* CHROMA_LIM is the limit (in IRE units) of the overall
* chrominance amplitude; it should be 50 or perhaps
* very slightly higher.
*
* COMPOS_LIM is the maximum amplitude (in IRE units) allowed for
* the composite signal. A value of 100 is the maximum
* monochrome white, and is always safe. 120 is the absolute
* limit for NTSC broadcasting, since the transmitter's carrier
* goes to zero with 120 IRE input signal. Generally, 110
* is a good compromise - it allows somewhat brighter colours
* than 100, while staying safely away from the hard limit.
*/
/*
* run-time options:
*
* Define either NTSC or PAL as 1 to select the colour system.
* Define the other one as zero, or leave it undefined.
*
* Define FLAG_HOT as 1 if you want "hot" pixels set to black
* to identify them. Otherwise they will be made safe.
*
* Define REDUCE_SAT as 1 if you want hot pixels to be repaired by
* reducing their saturation. By default, luminance is reduced.
*
*/
#include <math.h>
#include <stdio.h>
#include <string.h>
#include <libgimp/gimp.h>
#include <gtk/gtk.h>
#include "megawidget.h"
struct Grgb {
guint8 red;
guint8 green;
guint8 blue;
};
struct GRegion {
gint32 x;
gint32 y;
gint32 width;
gint32 height;
};
struct piArgs {
gint32 image;
gint32 drawable;
gint32 mode;
gint32 action;
gint32 new_layerp;
};
typedef enum {
act_lredux = 0,
act_sredux = 1,
act_flag = 2,
} hotAction;
typedef enum {
mode_ntsc = 0,
mode_pal = 1,
} hotModes;
#define CHROMA_LIM 50.0 /* chroma amplitude limit */
#define COMPOS_LIM 110.0 /* max IRE amplitude */
/*
* RGB to YIQ encoding matrix.
*/
struct {
double pedestal;
double gamma;
double code[3][3];
} mode[2] = {
{
7.5,
2.2,
{
{ 0.2989, 0.5866, 0.1144 },
{ 0.5959, -0.2741, -0.3218 },
{ 0.2113, -0.5227, 0.3113 }
}
},
{
0.0,
2.8,
{
{ 0.2989, 0.5866, 0.1144 },
{ -0.1473, -0.2891, 0.4364 },
{ 0.6149, -0.5145, -0.1004 }
}
}
};
#define SCALE 8192 /* scale factor: do floats with int math */
#define MAXPIX 255 /* white value */
int tab[3][3][MAXPIX+1]; /* multiply lookup table */
double chroma_lim; /* chroma limit */
double compos_lim; /* composite amplitude limit */
long ichroma_lim2; /* chroma limit squared (scaled integer) */
int icompos_lim; /* composite amplitude limit (scaled integer) */
static void query(void);
static void run(char *name, int nparam, GParam *param,
int *nretvals, GParam **retvals);
gint pluginCore(struct piArgs *argp);
gint pluginCoreIA(struct piArgs *argp);
static gint hotp(register guint8 r, register guint8 g, register guint8 b);
static void build_tab(int m);
/*
* gc: apply the gamma correction specified for this video standard.
* inv_gc: inverse function of gc.
*
* These are generally just a call to pow(), but be careful!
* Future standards may use more complex functions.
* (e.g. SMPTE 240M's "electro-optic transfer characteristic").
*/
#define gc(x,m) pow(x, 1.0 / mode[m].gamma)
#define inv_gc(x,m) pow(x, mode[m].gamma)
/*
* pix_decode: decode an integer pixel value into a floating-point
* intensity in the range [0, 1].
*
* pix_encode: encode a floating-point intensity into an integer
* pixel value.
*
* The code given here assumes simple linear encoding; you must change
* these routines if you use a different pixel encoding technique.
*/
#define pix_decode(v) ((double)v / (double)MAXPIX)
#define pix_encode(v) ((int)(v * (double)MAXPIX + 0.5))
GPlugInInfo PLUG_IN_INFO = {
NULL, /* init */
NULL, /* quit */
query, /* query */
run, /* run */
};
MAIN()
static void
query(void){
static GParamDef args[] = {
{ PARAM_INT32, "run_mode", "Interactive, non-interactive" },
{ PARAM_IMAGE, "image", "The Image" },
{ PARAM_DRAWABLE, "drawable", "The Drawable" },
{ PARAM_INT32, "mode", "Mode -- NTSC/PAL" },
{ PARAM_INT32, "action", "The action to perform" },
{ PARAM_INT32, "new_layerp", "Create a new layer iff True" },
};
static int nargs = 3;
static GParamDef *rets = NULL;
static int nrets = 0;
gimp_install_procedure("plug_in_hot",
"Look for hot NTSC or PAL pixels ",
"hot scans an image for pixels that will give "
"unsave values of chrominance or composite "
"signale amplitude when encoded into an NTSC "
"or PAL signal. Three actions can be performed on these ``hot'' "
"pixels. (0) reduce luminance, (1) reduce saturation, or (2) Blacken.",
"Eric L. Hernes, Alan Wm Paeth",
"Eric L. Hernes",
"1997",
"<Image>/Filters/Image/Hot",
"RGB",
PROC_PLUG_IN,
nargs, nrets,
args, rets);
}
static void
run(char *name, int nparam, GParam *param,
int *nretvals, GParam **retvals){
static GParam rvals[1];
struct piArgs args;
*nretvals = 1;
*retvals = rvals;
bzero(&args, sizeof(struct piArgs));
args.mode=-1;
gimp_get_data("plug_in_hot", &args);
rvals[0].type = PARAM_STATUS;
rvals[0].data.d_status = STATUS_SUCCESS;
switch (param[0].data.d_int32) {
case RUN_INTERACTIVE:
/* XXX: add code here for interactive running */
args.image = param[1].data.d_image;
args.drawable = param[2].data.d_drawable;
if(args.mode == -1) {
args.mode = mode_ntsc;
args.action = act_lredux;
args.new_layerp = 1;
}
if (pluginCoreIA(&args)==-1) {
rvals[0].data.d_status = STATUS_EXECUTION_ERROR;
}
gimp_set_data("plug_in_hot", &args, sizeof(struct piArgs));
break;
case RUN_NONINTERACTIVE:
/* XXX: add code here for non-interactive running */
if (nparam != 3) {
rvals[0].data.d_status = STATUS_CALLING_ERROR;
break;
}
args.image = param[1].data.d_image;
args.drawable = param[2].data.d_drawable;
args.mode = param[3].data.d_drawable;
args.action = param[4].data.d_drawable;
if (pluginCore(&args)==-1) {
rvals[0].data.d_status = STATUS_EXECUTION_ERROR;
break;
}
break;
case RUN_WITH_LAST_VALS:
/* XXX: add code here for last-values running */
if (pluginCore(&args)==-1) {
rvals[0].data.d_status = STATUS_EXECUTION_ERROR;
}
break;
}
}
gint
pluginCore(struct piArgs *argp) {
GDrawable *drw, *ndrw=NULL;
GPixelRgn srcPr, dstPr;
gint retval = 0;
gint nl=0;
gint y, x, i;
gint Y, I, Q;
guint width, height, Bpp;
gint prog_interval;
guchar *src, *s, *dst, *d;
guchar r, prev_r=0, new_r=0;
guchar g, prev_g=0, new_g=0;
guchar b, prev_b=0, new_b=0;
gdouble fy, fc, t, scale;
gdouble pr, pg, pb;
gdouble py;
drw = gimp_drawable_get(argp->drawable);
width = drw->width;
height = drw->height;
Bpp = drw->bpp;
if(argp->new_layerp) {
char name[40];
char *mode_names[] = {
"ntsc",
"pal",
};
char *action_names[] = {
"lum redux",
"sat redux",
"flag",
};
sprintf(name, "hot mask (%s, %s)", mode_names[argp->mode],
action_names[argp->action]);
nl=gimp_layer_new(argp->image, name, width, height,
RGBA_IMAGE, (gdouble)100, NORMAL_MODE);
ndrw = gimp_drawable_get(nl);
gimp_drawable_fill(nl, TRANS_IMAGE_FILL);
gimp_image_add_layer(argp->image, nl, 0);
}
src = (guchar*)malloc(width*height*Bpp);
dst = (guchar*)malloc(width*height*4);
gimp_pixel_rgn_init (&srcPr, drw, 0, 0, width, height, FALSE, FALSE);
if (argp->new_layerp) {
gimp_pixel_rgn_init (&dstPr, ndrw, 0, 0, width, height, FALSE, FALSE);
} else {
gimp_pixel_rgn_init (&dstPr, drw, 0, 0, width, height, TRUE, TRUE);
}
gimp_pixel_rgn_get_rect(&srcPr, src, 0, 0, width, height);
s=src;
d=dst;
build_tab(argp->mode);
gimp_progress_init("Hot");
prog_interval=height/10;
for(y=0;y<height;y++) {
if (y % prog_interval == 0) gimp_progress_update((double)y/(double)height);
for(x=0;x<width;x++) {
if (hotp(r=*(s+0),g=*(s+1),b=*(s+2))) {
if (argp->action == act_flag) {
for(i=0;i<3;i++)
*d++=0;
s+=3;
if (Bpp==4) *d++=*s++; else if (argp->new_layerp) *d++=255;
} else {
/*
* Optimization: cache the last-computed hot pixel.
*/
if (r == prev_r && g == prev_g && b == prev_b) {
*d++ = new_r;
*d++ = new_g;
*d++ = new_b;
s+=3;
if (Bpp==4) *d++=*s++; else if (argp->new_layerp) *d++=255;
} else {
Y = tab[0][0][r] + tab[0][1][g] + tab[0][2][b];
I = tab[1][0][r] + tab[1][1][g] + tab[1][2][b];
Q = tab[2][0][r] + tab[2][1][g] + tab[2][2][b];
prev_r = r;
prev_g = g;
prev_b = b;
/*
* Get Y and chroma amplitudes in floating point.
*
* If your C library doesn't have hypot(), just use
* hypot(a,b) = sqrt(a*a, b*b);
*
* Then extract linear (un-gamma-corrected)
* floating-point pixel RGB values.
*/
fy = (double)Y / (double)SCALE;
fc = hypot((double)I / (double)SCALE,
(double)Q / (double)SCALE);
pr = (double)pix_decode(r);
pg = (double)pix_decode(g);
pb = (double)pix_decode(b);
/*
* Reducing overall pixel intensity by scaling R,
* G, and B reduces Y, I, and Q by the same factor.
* This changes luminance but not saturation, since
* saturation is determined by the chroma/luminance
* ratio.
*
* On the other hand, by linearly interpolating
* between the original pixel value and a grey
* pixel with the same luminance (R=G=B=Y), we
* change saturation without affecting luminance.
*/
if(argp->action == act_lredux) {
/*
* Calculate a scale factor that will bring the pixel
* within both chroma and composite limits, if we scale
* luminance and chroma simultaneously.
*
* The calculated chrominance reduction applies
* to the gamma-corrected RGB values that are
* the input to the RGB-to-YIQ operation.
* Multiplying the original un-gamma-corrected
* pixel values by the scaling factor raised to
* the "gamma" power is equivalent, and avoids
* calling gc() and inv_gc() three times each. */
scale = chroma_lim / fc;
t = compos_lim / (fy + fc);
if (t < scale)
scale = t;
scale = pow(scale, mode[argp->mode].gamma);
r = (guint8)pix_encode(scale * pr);
g = (guint8)pix_encode(scale * pg);
b = (guint8)pix_encode(scale * pb);
} else { /* act_sredux hopefully */
/*
* Calculate a scale factor that will bring the
* pixel within both chroma and composite
* limits, if we scale chroma while leaving
* luminance unchanged.
*
* We have to interpolate gamma-corrected RGB
* values, so we must convert from linear to
* gamma-corrected before interpolation and then
* back to linear afterwards.
*/
scale = chroma_lim / fc;
t = (compos_lim - fy) / fc;
if (t < scale)
scale = t;
pr = gc(pr,argp->mode);
pg = gc(pg,argp->mode);
pb = gc(pb,argp->mode);
py = pr * mode[argp->mode].code[0][0] + pg *
mode[argp->mode].code[0][1] + pb *
mode[argp->mode].code[0][2];
r = pix_encode(inv_gc(py + scale * (pr - py), argp->mode));
g = pix_encode(inv_gc(py + scale * (pg - py), argp->mode));
b = pix_encode(inv_gc(py + scale * (pb - py), argp->mode));
}
*d++ = new_r = r;
*d++ = new_g = g;
*d++ = new_b = b;
s+=3;
if (Bpp==4) *d++=*s++; else if (argp->new_layerp) *d++=255;
}
}
} else {
if (!argp->new_layerp) {
for(i=0;i<Bpp;i++)
*d++=*s++;
} else {
s+=Bpp;
d+=4;
}
}
}
}
gimp_pixel_rgn_set_rect(&dstPr, dst, 0, 0, width, height);
free(src);
free(dst);
if(argp->new_layerp) {
gimp_drawable_flush(ndrw);
gimp_drawable_update(nl, 0, 0, width, height);
} else {
gimp_drawable_flush(drw);
gimp_drawable_merge_shadow (drw->id, TRUE);
gimp_drawable_update(drw->id, 0, 0, width, height);
}
gimp_displays_flush();
return retval;
}
gint
pluginCoreIA(struct piArgs *argp) {
GtkWidget *dlg;
GtkWidget *hbox;
GtkWidget *vbox;
gint runp;
struct mwRadioGroup modes[] = {
{ "NTSC", 1 },
{ "PAL", 0 },
{ NULL, 0 }
};
struct mwRadioGroup actions[] = {
{ "Reduce Luminance", 0 },
{ "Reduce Saturation", 0 },
{ "Blacken (flag)", 0 },
{ NULL, 0}
};
actions[argp->action].var = 1;
dlg = mw_app_new("plug_in_hot", "Hot", &runp);
hbox = gtk_hbox_new(FALSE, 5);
gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dlg)->vbox), hbox, TRUE, TRUE, 0);
gtk_widget_show(hbox);
vbox = gtk_vbox_new(FALSE, 5);
gtk_box_pack_start(GTK_BOX(hbox), vbox, TRUE, TRUE, 0);
gtk_widget_show(vbox);
mw_toggle_button_new(vbox, NULL, "Create New Layer", &argp->new_layerp);
mw_radio_group_new(vbox, "Mode", modes);
mw_radio_group_new(hbox, "Action", actions);
gtk_widget_show(dlg);
gtk_main();
gdk_flush();
argp->mode = mw_radio_result(modes);
argp->action = mw_radio_result(actions);
if (runp) {
return pluginCore(argp);
} else {
return -1;
}
}
/*
* build_tab: Build multiply lookup table.
*
* For each possible pixel value, decode value into floating-point
* intensity. Then do gamma correction required by the video
* standard. Scale the result by our fixed-point scale factor.
* Then calculate 9 lookup table entries for this pixel value.
*
* We also calculate floating-point and scaled integer versions
* of our limits here. This prevents evaluating expressions every pixel
* when the compiler is too stupid to evaluate constant-valued
* floating-point expressions at compile time.
*
* For convenience, the limits are #defined using IRE units.
* We must convert them here into the units in which YIQ
* are measured. The conversion from IRE to internal units
* depends on the pedestal level in use, since as Y goes from
* 0 to 1, the signal goes from the pedestal level to 100 IRE.
* Chroma is always scaled to remain consistent with Y.
*/
void
build_tab(int m) {
register double f;
register int pv;
for (pv = 0; pv <= MAXPIX; pv++) {
f = (double)SCALE * (double)gc((double)pix_decode(pv),m);
tab[0][0][pv] = (int)(f * mode[m].code[0][0] + 0.5);
tab[0][1][pv] = (int)(f * mode[m].code[0][1] + 0.5);
tab[0][2][pv] = (int)(f * mode[m].code[0][2] + 0.5);
tab[1][0][pv] = (int)(f * mode[m].code[1][0] + 0.5);
tab[1][1][pv] = (int)(f * mode[m].code[1][1] + 0.5);
tab[1][2][pv] = (int)(f * mode[m].code[1][2] + 0.5);
tab[2][0][pv] = (int)(f * mode[m].code[2][0] + 0.5);
tab[2][1][pv] = (int)(f * mode[m].code[2][1] + 0.5);
tab[2][2][pv] = (int)(f * mode[m].code[2][2] + 0.5);
}
chroma_lim = (double)CHROMA_LIM / (100.0 - mode[m].pedestal);
compos_lim = ((double)COMPOS_LIM - mode[m].pedestal) /
(100.0 - mode[m].pedestal);
ichroma_lim2 = (int)(chroma_lim * SCALE + 0.5);
ichroma_lim2 *= ichroma_lim2;
icompos_lim = (int)(compos_lim * SCALE + 0.5);
}
int
hotp(register guint8 r, register guint8 g, register guint8 b) {
register int y, i, q;
register long y2, c2;
/* fprintf(stderr, "\tr: %d, g: %d, b: %d\n", r, g, b);*/
/*
* Pixel decoding, gamma correction, and matrix multiplication
* all done by lookup table.
*
* "i" and "q" are the two chrominance components;
* they are I and Q for NTSC.
* For PAL, "i" is U (scaled B-Y) and "q" is V (scaled R-Y).
* Since we only care about the length of the chroma vector,
* not its angle, we don't care which is which.
*/
y = tab[0][0][r] + tab[0][1][g] + tab[0][2][b];
i = tab[1][0][r] + tab[1][1][g] + tab[1][2][b];
q = tab[2][0][r] + tab[2][1][g] + tab[2][2][b];
/*
* Check to see if the chrominance vector is too long or the
* composite waveform amplitude is too large.
*
* Chrominance is too large if
*
* sqrt(i^2, q^2) > chroma_lim.
*
* The composite signal amplitude is too large if
*
* y + sqrt(i^2, q^2) > compos_lim.
*
* We avoid doing the sqrt by checking
*
* i^2 + q^2 > chroma_lim^2
* and
* y + sqrt(i^2 + q^2) > compos_lim
* sqrt(i^2 + q^2) > compos_lim - y
* i^2 + q^2 > (compos_lim - y)^2
*
*/
c2 = (long)i * i + (long)q * q;
y2 = (long)icompos_lim - y;
y2 *= y2;
/* fprintf(stderr, "hotp: c2: %d; ichroma_lim2: %d; y2: %d; ",
c2, ichroma_lim2, y2);*/
if (c2 <= ichroma_lim2 && c2 <= y2) { /* no problems */
/* fprintf(stderr, "nope\n");*/
return 0;
}
/* fprintf(stderr, "yup\n");*/
return 1;
}
/*
* Local Variables:
* mode: C
* End:
*/
/* end of file: hot/hot.c */

View File

@ -1,512 +0,0 @@
/* The GIMP -- an image manipulation program
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
* HRZ reading and writing code Copyright (C) 1996 Albert Cahalan
*
* 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
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/* $Id$ */
/*
* Albert Cahalan <acahalan at cs.uml.edu>, 1997 - Initial HRZ support.
* Based on PNM code by Erik Nygren (nygren@mit.edu)
*
* Bug reports are wanted. I'd like to remove useless code.
*
* The HRZ file is always 256x240 with RGB values from 0 to 63.
* No compression, no header, just the raw RGB data.
* It is (was?) used for amatuer radio slow-scan TV.
* That makes the size 256*240*3 = 184320 bytes.
*/
#include <setjmp.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <unistd.h>
#include <sys/mman.h>
#include "gtk/gtk.h"
#include "libgimp/gimp.h"
/* Declare local data types
*/
typedef struct
{
gint run; /* run */
} HRZSaveInterface;
/* Declare some local functions.
*/
static void query (void);
static void run (char *name,
int nparams,
GParam *param,
int *nreturn_vals,
GParam **return_vals);
static gint32 load_image (char *filename);
static gint save_image (char *filename,
gint32 image_ID,
gint32 drawable_ID);
static gint save_dialog ();
static void save_close_callback (GtkWidget *widget, gpointer data);
static void save_ok_callback (GtkWidget *widget,
gpointer data);
static void save_toggle_update (GtkWidget *widget,
gpointer data);
#define hrzscanner_eof(s) ((s)->eof)
#define hrzscanner_fp(s) ((s)->fp)
/* Checks for a fatal error */
#define CHECK_FOR_ERROR(predicate, jmpbuf, errmsg) \
if ((predicate)) \
{ /*gimp_message((errmsg));*/ longjmp((jmpbuf),1); }
GPlugInInfo PLUG_IN_INFO =
{
NULL, /* init_proc */
NULL, /* quit_proc */
query, /* query_proc */
run, /* run_proc */
};
static HRZSaveInterface psint =
{
FALSE /* run */
};
MAIN ()
static void
query ()
{
static GParamDef load_args[] =
{
{ PARAM_INT32, "run_mode", "Interactive, non-interactive" },
{ PARAM_STRING, "filename", "The name of the file to load" },
{ PARAM_STRING, "raw_filename", "The name of the file to load" },
};
static GParamDef load_return_vals[] =
{
{ PARAM_IMAGE, "image", "Output image" },
};
static int nload_args = sizeof (load_args) / sizeof (load_args[0]);
static int nload_return_vals = sizeof (load_return_vals) / sizeof (load_return_vals[0]);
static GParamDef save_args[] =
{
{ PARAM_INT32, "run_mode", "Interactive, non-interactive" },
{ PARAM_IMAGE, "image", "Input image" },
{ PARAM_DRAWABLE, "drawable", "Drawable to save" },
{ PARAM_STRING, "filename", "The name of the file to save the image in" },
{ PARAM_STRING, "raw_filename", "The name of the file to save the image in" }
};
static int nsave_args = sizeof (save_args) / sizeof (save_args[0]);
gimp_install_procedure ("file_hrz_load",
"loads files of the hrz file format",
"FIXME: write help for hrz_load",
"Albert Cahalan",
"Albert Cahalan",
"1997",
"<Load>/HRZ",
NULL,
PROC_PLUG_IN,
nload_args, nload_return_vals,
load_args, load_return_vals);
gimp_install_procedure ("file_hrz_save",
"saves files in the hrz file format",
"HRZ saving handles all image types except those with alpha channels.",
"Albert Cahalan",
"Albert Cahalan",
"1997",
"<Save>/HRZ",
"RGB*, GRAY*, INDEXED*",
PROC_PLUG_IN,
nsave_args, 0,
save_args, NULL);
gimp_register_magic_load_handler ("file_hrz_load", "hrz", "", "0,size,184320");
gimp_register_save_handler ("file_hrz_save", "hrz", "");
}
static void
run (char *name,
int nparams,
GParam *param,
int *nreturn_vals,
GParam **return_vals)
{
static GParam values[2];
GRunModeType run_mode;
GStatusType status = STATUS_SUCCESS;
gint32 image_ID;
run_mode = param[0].data.d_int32;
*nreturn_vals = 1;
*return_vals = values;
values[0].type = PARAM_STATUS;
values[0].data.d_status = STATUS_CALLING_ERROR;
if (strcmp (name, "file_hrz_load") == 0)
{
image_ID = load_image (param[1].data.d_string);
if (image_ID != -1)
{
*nreturn_vals = 2;
values[0].data.d_status = STATUS_SUCCESS;
values[1].type = PARAM_IMAGE;
values[1].data.d_image = image_ID;
}
else
{
values[0].data.d_status = STATUS_EXECUTION_ERROR;
}
}
else if (strcmp (name, "file_hrz_save") == 0)
{
switch (run_mode)
{
case RUN_INTERACTIVE:
/* First acquire information with a dialog */
if (! save_dialog ())
return;
break;
case RUN_NONINTERACTIVE:
/* Make sure all the arguments are there! */
if (nparams != 4)
status = STATUS_CALLING_ERROR;
case RUN_WITH_LAST_VALS:
break;
default:
break;
}
*nreturn_vals = 1;
if (save_image (param[3].data.d_string, param[1].data.d_int32, param[2].data.d_int32))
{
values[0].data.d_status = STATUS_SUCCESS;
}
else
values[0].data.d_status = STATUS_EXECUTION_ERROR;
}
}
/************ load HRZ image row *********************/
void
do_hrz_load(void *mapped, GPixelRgn *pixel_rgn)
{
unsigned char *data, *d;
int x, y;
int start, end, scanlines;
data = g_malloc (gimp_tile_height () * 256 * 3);
for (y = 0; y < 240; )
{
start = y;
end = y + gimp_tile_height ();
end = MIN (end, 240);
scanlines = end - start;
d = data;
memcpy(d, ((unsigned char *) mapped)+256*3*y, 256*3*scanlines); /* this is gross */
/* scale 0..63 into 0..255 properly */
for (x=0; x<256*3*scanlines; x++) d[x] = (d[x]>>4) | (d[x]<<2);
d += 256*3*y;
gimp_progress_update ((double) y / 240.0);
gimp_pixel_rgn_set_rect (pixel_rgn, data, 0, y, 256, scanlines);
y += scanlines;
}
g_free (data);
}
/********************* Load HRZ image **********************/
static gint32
load_image (char *filename)
{
GPixelRgn pixel_rgn;
gint32 image_ID;
gint32 layer_ID;
GDrawable *drawable;
int filedes;
char *temp;
void *mapped; /* memory mapped file data */
struct stat statbuf; /* must check file size */
temp = g_malloc (strlen (filename) + 11);
sprintf (temp, "Loading %s:", filename);
gimp_progress_init (temp);
g_free (temp);
/* open the file */
filedes = open(filename, O_RDONLY);
if (filedes == -1)
{
/* errno is set to indicate the error, but the user won't know :-( */
/*gimp_message("hrz filter: can't open file\n");*/
return -1;
}
/* stat the file to see if it is the right size */
fstat(filedes, &statbuf);
if(statbuf.st_size != 256*240*3)
{
fprintf(stderr, "hrz filter: file is not HRZ type\n");
return -1;
}
mapped = mmap(NULL, 256*240*3, PROT_READ, MAP_PRIVATE, filedes, 0);
if(mapped == (void *)(-1))
{
fprintf(stderr, "hrz filter: could not map file\n");
return -1;
}
close (filedes); /* not needed anymore, data is memory mapped */
/* Create new image of proper size; associate filename */
image_ID = gimp_image_new (256, 240, RGB);
gimp_image_set_filename (image_ID, filename);
layer_ID = gimp_layer_new (image_ID, "Background",
256, 240,
RGB_IMAGE, 100, NORMAL_MODE);
gimp_image_add_layer (image_ID, layer_ID, 0);
drawable = gimp_drawable_get (layer_ID);
gimp_pixel_rgn_init (&pixel_rgn, drawable, 0, 0, drawable->width, drawable->height, TRUE, FALSE);
do_hrz_load(mapped, &pixel_rgn);
/* close the file */
munmap(mapped, 256*240*3);
/* Tell the GIMP to display the image.
*/
gimp_drawable_flush (drawable);
return image_ID;
}
/************** Writes out RGB raw rows ************/
static void
saverow (FILE *fp, unsigned char *data)
{
int loop = 256*3;
unsigned char *walk = data;
while(loop--)
{
*walk = (*walk >> 2);
walk++;
}
fwrite(data, 1, 256*3, fp);
}
/********************* save image *********************/
static gint
save_image (char *filename,
gint32 image_ID,
gint32 drawable_ID)
{
GPixelRgn pixel_rgn;
GDrawable *drawable;
GDrawableType drawable_type;
unsigned char *data;
unsigned char *d; /* FIX */
unsigned char *rowbuf;
char *temp;
int np = 3;
int xres, yres;
int ypos, yend;
FILE *fp;
drawable = gimp_drawable_get (drawable_ID);
drawable_type = gimp_drawable_type (drawable_ID);
gimp_pixel_rgn_init (&pixel_rgn, drawable, 0, 0, drawable->width, drawable->height, FALSE, FALSE);
/* Make sure we're not saving an image with an alpha channel */
if (gimp_drawable_has_alpha (drawable_ID))
{
/* gimp_message ("HRZ save cannot handle images with alpha channels."); */
return FALSE;
}
/* open the file */
fp = fopen(filename, "wb");
if (fp == NULL)
{
/* Ought to pass errno back... */
fprintf (stderr, "hrz: can't open \"%s\"\n", filename);
return FALSE;
}
xres = drawable->width;
yres = drawable->height;
if ((xres != 256) || (yres != 240))
{
fprintf (stderr, "hrz: Image must be 256x240 for HRZ format.\n");
return FALSE;
}
if (drawable_type == INDEXED_IMAGE)
{
fprintf (stderr, "hrz: Image must be RGB for HRZ format.\n");
return FALSE;
}
temp = g_malloc (strlen (filename) + 11);
sprintf (temp, "Saving %s:", filename);
gimp_progress_init (temp);
g_free (temp);
/* allocate a buffer for retrieving information from the pixel region */
data = (unsigned char *) g_malloc (gimp_tile_height () * drawable->width * drawable->bpp);
rowbuf = g_malloc(256*3);
/* Write the body out */
for (ypos = 0; ypos < yres; ypos++)
{
if ((ypos % gimp_tile_height ()) == 0)
{
yend = ypos + gimp_tile_height ();
yend = MIN (yend, yres);
gimp_pixel_rgn_get_rect (&pixel_rgn, data, 0, ypos, xres, (yend - ypos));
d = data;
}
saverow(fp, d);
d += xres*np;
if (!(ypos & 0x0f))
gimp_progress_update( (double)ypos / 240.0 );
}
/* close the file */
fclose (fp);
g_free(rowbuf);
g_free(data);
gimp_drawable_detach (drawable);
return TRUE;
}
/*********** Save dialog ************/
static gint
save_dialog ()
{
GtkWidget *dlg;
GtkWidget *button;
gchar **argv;
gint argc;
argc = 1;
argv = g_new (gchar *, 1);
argv[0] = g_strdup ("save");
gtk_init (&argc, &argv);
gtk_rc_parse (gimp_gtkrc ());
dlg = gtk_dialog_new ();
gtk_window_set_title (GTK_WINDOW (dlg), "Save as HRZ");
gtk_window_position (GTK_WINDOW (dlg), GTK_WIN_POS_MOUSE);
gtk_signal_connect (GTK_OBJECT (dlg), "destroy",
(GtkSignalFunc) save_close_callback,
NULL);
/* Action area */
button = gtk_button_new_with_label ("OK");
GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
gtk_signal_connect (GTK_OBJECT (button), "clicked",
(GtkSignalFunc) save_ok_callback,
dlg);
gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dlg)->action_area), button, TRUE, TRUE, 0);
gtk_widget_grab_default (button);
gtk_widget_show (button);
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));
gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dlg)->action_area), button, TRUE, TRUE, 0);
gtk_widget_show (button);
gtk_widget_show (dlg);
gtk_main ();
gdk_flush ();
return psint.run;
}
/********** Save interface functions **********/
static void
save_close_callback (GtkWidget *widget,
gpointer data)
{
gtk_main_quit ();
}
static void
save_ok_callback (GtkWidget *widget,
gpointer data)
{
psint.run = TRUE;
gtk_widget_destroy (GTK_WIDGET (data));
}
static void
save_toggle_update (GtkWidget *widget,
gpointer data)
{
int *toggle_val;
toggle_val = (int *) data;
if (GTK_TOGGLE_BUTTON (widget)->active)
*toggle_val = TRUE;
else
*toggle_val = FALSE;
}

File diff suppressed because it is too large Load Diff

View File

@ -1,916 +0,0 @@
/* The GIMP -- an image manipulation program
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* IfsCompose is a interface for creating IFS fractals by
* direct manipulation.
* Copyright (C) 1997 Owen Taylor
*
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <math.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "libgimp/gimp.h"
#include "gdk/gdk.h"
#include "ifscompose.h"
typedef struct {
GdkPoint point;
gdouble angle;
} SortPoint;
/* local functions */
static void
aff_element_compute_click_boundary(AffElement *elem, int num_elements,
gdouble *points_x, gdouble *points_y);
static guchar *
create_brush(IfsComposeVals *ifsvals, gint *brush_size, gdouble *brush_offset);
void
aff2_translate(Aff2 *naff, gdouble x, gdouble y)
{
naff->a11 = 1.0;
naff->a12 = 0;
naff->a21 = 0;
naff->a22 = 1.0;
naff->b1 = x;
naff->b2 = y;
}
void
aff2_rotate(Aff2 *naff, gdouble theta)
{
naff->a11 = cos(theta);
naff->a12 = sin(theta);
naff->a21 = -naff->a12;
naff->a22 = naff->a11;
naff->b1 = 0;
naff->b2 = 0;
}
void
aff2_scale(Aff2 *naff, gdouble s, gint flip)
{
if (flip)
naff->a11 = -s;
else
naff->a11 = s;
naff->a12 = 0;
naff->a21 = 0;
naff->a22 = s;
naff->b1 = 0;
naff->b2 = 0;
}
/* Create a unitary transform with given x-y asymmetry and shear */
void
aff2_distort(Aff2 *naff, gdouble asym, gdouble shear)
{
naff->a11 = asym;
naff->a22 = 1/asym;
naff->a12 = shear;
naff->a21 = 0;
naff->b1 = 0;
naff->b2 = 0;
}
/* Find a pure stretch in some directon that brings xo,yo to xn,yn */
void
aff2_compute_stretch(Aff2 *naff,
gdouble xo, gdouble yo,
gdouble xn, gdouble yn)
{
gdouble denom = xo*xn + yo*yn;
if (denom == 0.0) /* singular */
{
naff->a11 = 1.0;
naff->a12 = 0.0;
naff->a21 = 0.0;
naff->a22 = 1.0;
}
else
{
naff->a11 = (SQR(xn) + SQR(yo))/denom;
naff->a22 = (SQR(xo) + SQR(yn))/denom;
naff->a12 = naff->a21 = (xn*yn - xo*yo)/denom;
}
naff->b1 = 0.0;
naff->b2 = 0.0;
}
void
aff2_compose(Aff2 *naff, Aff2 *aff1, Aff2 *aff2)
{
naff->a11 = aff1->a11*aff2->a11 + aff1->a12*aff2->a21;
naff->a12 = aff1->a11*aff2->a12 + aff1->a12*aff2->a22;
naff->b1 = aff1->a11*aff2->b1 + aff1->a12*aff2->b2 + aff1->b1;
naff->a21 = aff1->a21*aff2->a11 + aff1->a22*aff2->a21;
naff->a22 = aff1->a21*aff2->a12 + aff1->a22*aff2->a22;
naff->b2 = aff1->a21*aff2->b1 + aff1->a22*aff2->b2 + aff1->b2;
}
/* Returns the identity matrix if the original matrix was singular */
void
aff2_invert(Aff2 *naff, Aff2 *aff)
{
gdouble det = aff->a11*aff->a22 - aff->a12*aff->a21;
if (det==0)
{
aff2_scale(naff,1.0,0);
}
else
{
naff->a11 = aff->a22 / det;
naff->a22 = aff->a11 / det;
naff->a21 = - aff->a21 / det;
naff->a12 = - aff->a12 / det;
naff->b1 = - naff->a11*aff->b1 - naff->a12*aff->b2;
naff->b2 = - naff->a21*aff->b1 - naff->a22*aff->b2;
}
}
void
aff2_apply(Aff2 *aff, gdouble x, gdouble y,
gdouble *xf, gdouble *yf)
{
gdouble xt = aff->a11*x + aff->a12*y + aff->b1;
gdouble yt = aff->a21*x + aff->a22*y + aff->b2;
*xf = xt;
*yf = yt;
}
/* Find the fixed point of an affine transformation
(Will return garbage for pure translations) */
void
aff2_fixed_point(Aff2 *aff, gdouble *xf, gdouble *yf)
{
Aff2 t1,t2;
t1.a11 = 1-aff->a11;
t1.a22 = 1-aff->a22;
t1.a12 = -aff->a12;
t1.a21 = -aff->a21;
t1.b1 = 0;
t1.b2 = 0;
aff2_invert(&t2,&t1);
aff2_apply(&t2,aff->b1,aff->b2,xf,yf);
}
void
aff3_apply (Aff3 *t, gdouble x, gdouble y, gdouble z,
gdouble *xf, gdouble *yf, gdouble *zf)
{
double xt = t->vals[0][0]*x + t->vals[0][1]*y + t->vals[0][2]*z + t->vals[0][3];
double yt = t->vals[1][0]*x + t->vals[1][1]*y + t->vals[1][2]*z + t->vals[1][3];
double zt = t->vals[2][0]*x + t->vals[2][1]*y + t->vals[2][2]*z + t->vals[2][3];
*xf = xt;
*yf = yt;
*zf = zt;
}
static int
ipolygon_sort_func(const void *a, const void *b)
{
if (((SortPoint *)a)->angle < ((SortPoint *)b)->angle)
return -1;
else if (((SortPoint *)a)->angle > ((SortPoint *)b)->angle)
return 1;
else
return 0;
}
/* Return a newly-allocated polygon which is the convex hull
of the given polygon.
Uses the Graham scan. see
http://www.cs.curtin.edu.au/units/cg201/notes/node77.html
for a description
*/
IPolygon *
ipolygon_convex_hull(IPolygon *poly)
{
gint num_new = poly->npoints;
GdkPoint *new_points = g_new(GdkPoint,num_new);
SortPoint *sort_points = g_new(SortPoint,num_new);
IPolygon *new_poly = g_new(IPolygon,1);
gint i,j;
gint x1,x2,y1,y2;
gint lowest;
GdkPoint lowest_pt;
new_poly->points = new_points;
if (num_new <= 3)
{
memcpy(new_points,poly->points,num_new*sizeof(GdkPoint));
new_poly->npoints = num_new;
return new_poly;
}
/* scan for the lowest point */
lowest_pt = poly->points[0];
lowest = 0;
for (i=1;i<num_new;i++)
if (poly->points[i].y < lowest_pt.y)
{
lowest_pt = poly->points[i];
lowest = i;
}
/* sort by angle from lowest point */
for (i=0,j=0;i<num_new;i++,j++)
{
if (i==lowest)
j--;
else
{
gdouble dy = poly->points[i].y - lowest_pt.y;
gdouble dx = poly->points[i].x - lowest_pt.x;
if (dy==0 && dx==0)
{
j--;
num_new--;
continue;
}
sort_points[j].point = poly->points[i];
sort_points[j].angle = atan2(dy,dx);
}
}
qsort(sort_points,num_new-1,sizeof(SortPoint),ipolygon_sort_func);
/* now ensure that all turns as we trace the perimiter are
counter-clockwise */
new_points[0] = lowest_pt;
new_points[1] = sort_points[0].point;
x1 = new_points[1].x - new_points[0].x;
y1 = new_points[1].y - new_points[0].y;
for (i=1,j=2;j<num_new;i++,j++)
{
x2 = sort_points[i].point.x - new_points[j-1].x;
y2 = sort_points[i].point.y - new_points[j-1].y;
if (x2==0 && y2==0)
{
num_new--;
j--;
continue;
}
while (x1*y2 - x2*y1 < 0) /* clockwise rotation */
{
num_new--;
j--;
x1 = new_points[j-1].x - new_points[j-2].x;
y1 = new_points[j-1].y - new_points[j-2].y;
x2 = sort_points[i].point.x - new_points[j-1].x;
y2 = sort_points[i].point.y - new_points[j-1].y;
}
new_points[j] = sort_points[i].point;
x1 = x2;
y1 = y2;
}
g_free(sort_points);
new_poly->npoints = num_new;
return new_poly;
}
/* Determines whether a specified point is in the given polygon.
Based on
inpoly.c by Bob Stein and Craig Yap.
(Linux Journal, Issue 35 (March 1997), p 68)
*/
gint
ipolygon_contains(IPolygon *poly, gint xt, gint yt)
{
gint xnew, ynew;
gint xold, yold;
gint x1,y1;
gint x2,y2;
gint i;
gint inside = 0;
if (poly->npoints < 3)
return 0;
xold=poly->points[poly->npoints-1].x;
yold=poly->points[poly->npoints-1].y;
for (i=0;i<poly->npoints;i++)
{
xnew = poly->points[i].x;
ynew = poly->points[i].y;
if (xnew > xold)
{
x1 = xold;
x2 = xnew;
y1 = yold;
y2 = ynew;
}
else
{
x1 = xnew;
x2 = xold;
y1 = ynew;
y2 = yold;
}
if ((xnew < xt) == (xt <= xold) &&
(yt - y1)*(x2 - x1) < (y2 - y1)*(xt - x1))
inside = !inside;
xold = xnew;
yold = ynew;
}
return inside;
}
void
aff_element_compute_color_trans(AffElement *elem)
{
int i,j;
if (elem->v.simple_color)
{
gdouble mag2 = 0;
for (i=0;i<3;i++)
mag2 += SQR(elem->v.target_color.vals[i]);
/* For mag2 == 0, the transformation blows up in general
but is well defined for hue_scale == value_scale, so
we assume that special case. */
if (mag2 == 0)
for (i=0;i<3;i++)
{
for (j=0;j<4;j++)
elem->color_trans.vals[i][j] = 0.0;
elem->color_trans.vals[i][i] = elem->v.hue_scale;
}
else
for (i=0;i<3;i++)
{
for (j=0;j<3;j++)
{
elem->color_trans.vals[i][j] = elem->v.target_color.vals[i]
/ mag2 * (elem->v.value_scale - elem->v.hue_scale);
if (i==j)
elem->color_trans.vals[i][j] += elem->v.hue_scale;
}
elem->color_trans.vals[i][3] =
(1-elem->v.value_scale)*elem->v.target_color.vals[i];
}
aff3_apply(&elem->color_trans,1.0,0.0,0.0,&elem->v.red_color.vals[0],
&elem->v.red_color.vals[1],&elem->v.red_color.vals[2]);
aff3_apply(&elem->color_trans,0.0,1.0,0.0,&elem->v.green_color.vals[0],
&elem->v.green_color.vals[1],&elem->v.green_color.vals[2]);
aff3_apply(&elem->color_trans,0.0,0.0,1.0,&elem->v.blue_color.vals[0],
&elem->v.blue_color.vals[1],&elem->v.blue_color.vals[2]);
aff3_apply(&elem->color_trans,0.0,0.0,0.0,&elem->v.black_color.vals[0],
&elem->v.black_color.vals[1],&elem->v.black_color.vals[2]);
}
else
{
for (i=0;i<3;i++)
elem->color_trans.vals[i][0] = elem->v.red_color.vals[i]
- elem->v.black_color.vals[i];
for (i=0;i<3;i++)
elem->color_trans.vals[i][1] = elem->v.green_color.vals[i]
- elem->v.black_color.vals[i];
for (i=0;i<3;i++)
elem->color_trans.vals[i][2] = elem->v.blue_color.vals[i]
- elem->v.black_color.vals[i];
for (i=0;i<3;i++)
elem->color_trans.vals[i][3] = elem->v.black_color.vals[i];
}
}
void
aff_element_compute_trans(AffElement *elem, gdouble width, gdouble height,
gdouble center_x, gdouble center_y)
{
Aff2 t1, t2, t3;
/* create the rotation, scaling and shearing part of the transform */
aff2_distort(&t1, elem->v.asym, elem->v.shear);
aff2_scale(&t2, elem->v.scale, elem->v.flip);
aff2_compose(&t3, &t2, &t1);
aff2_rotate(&t2, elem->v.theta);
aff2_compose(&t1, &t2, &t3);
/* now create the translational part */
aff2_translate(&t2, -center_x*width, -center_y*width);
aff2_compose(&t3, &t1, &t2);
aff2_translate(&t2, elem->v.x*width, elem->v.y*width);
aff2_compose(&elem->trans, &t2, &t3);
}
void
aff_element_decompose_trans(AffElement *elem, Aff2 *aff, gdouble width,
gdouble height, gdouble center_x,
gdouble center_y)
{
Aff2 t1,t2;
gdouble det,scale,sign;
/* pull of the translational parts */
aff2_translate(&t1,center_x*width,center_y*width);
aff2_compose(&t2,aff,&t1);
elem->v.x = t2.b1 / width;
elem->v.y = t2.b2 / width;
det = t2.a11*t2.a22 - t2.a12*t2.a21;
if (det == 0.0)
{
elem->v.scale = 0.0;
elem->v.theta = 0.0;
elem->v.asym = 1.0;
elem->v.shear = 0.0;
elem->v.flip = 0;
}
else
{
if (det >= 0)
{
scale = elem->v.scale = sqrt(det);
sign = 1;
elem->v.flip = 0;
}
else
{
scale = elem->v.scale = sqrt(-det);
sign = -1;
elem->v.flip = 1;
}
elem->v.theta = atan2(-t2.a21,t2.a11);
if (cos(elem->v.theta) == 0.0)
{
elem->v.asym = - t2.a21 / scale / sin(elem->v.theta);
elem->v.shear = - sign * t2.a22 / scale / sin(elem->v.theta);
}
else
{
elem->v.asym = sign * t2.a11 / scale / cos(elem->v.theta);
elem->v.shear = sign *
(t2.a12/scale - sin(elem->v.theta)/elem->v.asym)
/ cos(elem->v.theta);
}
}
}
static void
aff_element_compute_click_boundary(AffElement *elem, int num_elements,
gdouble *points_x, gdouble *points_y)
{
gint i;
gdouble xtot = 0;
gdouble ytot = 0;
gdouble xc, yc;
gdouble theta;
gdouble sth,cth; /* sin(theta), cos(theta) */
gdouble axis1,axis2;
gdouble axis1max, axis2max, axis1min, axis2min;
/* compute the center of mass of the points */
for (i=0; i<num_elements; i++)
{
xtot += points_x[i];
ytot += points_y[i];
}
xc = xtot/num_elements;
yc = ytot/num_elements;
/* compute the sum of the (x+iy)^2, and take half the the resulting
angle (xtot+iytot = A*exp(2i*theta)), to get an average direction */
xtot = 0;
ytot = 0;
for (i=0; i<num_elements; i++)
{
xtot += SQR(points_x[i]-xc)-SQR(points_y[i]-yc);
ytot += 2*(points_x[i]-xc)*(points_y[i]-yc);
}
theta = 0.5*atan2(ytot,xtot);
sth = sin(theta);
cth = cos(theta);
/* compute the minimum rectangle at angle theta that bounds the points,
1/2 side lenghs left in axis1, axis2, center in xc, yc */
axis1max = axis1min = 0.0;
axis2max = axis2min = 0.0;
for (i=0; i<num_elements; i++)
{
gdouble proj1 = (points_x[i]-xc)*cth + (points_y[i]-yc)*sth;
gdouble proj2 = -(points_x[i]-xc)*sth + (points_y[i]-yc)*cth;
if (proj1 < axis1min)
axis1min = proj1;
if (proj1 > axis1max)
axis1max = proj1;
if (proj2 < axis2min)
axis2min = proj2;
if (proj2 > axis2max)
axis2max = proj2;
}
axis1 = 0.5*(axis1max - axis1min);
axis2 = 0.5*(axis2max - axis2min);
xc += 0.5*((axis1max + axis1min)*cth - (axis2max+axis2min)*sth);
yc += 0.5*((axis1max + axis1min)*sth + (axis2max+axis2min)*cth);
/* if the the rectangle is less than 10 pixels in any dimension,
make it click_boundary, otherwise set click_boundary = draw_boundary */
if (axis1 < 8.0 || axis2 < 8.0)
{
GdkPoint *points = g_new(GdkPoint,4);
elem->click_boundary = g_new(IPolygon,1);
elem->click_boundary->points = points;
elem->click_boundary->npoints = 4;
if (axis1 < 8.0) axis1 = 8.0;
if (axis2 < 8.0) axis2 = 8.0;
points[0].x = xc + axis1*cth - axis2*sth;
points[0].y = yc + axis1*sth + axis2*cth;
points[1].x = xc - axis1*cth - axis2*sth;
points[1].y = yc - axis1*sth + axis2*cth;
points[2].x = xc - axis1*cth + axis2*sth;
points[2].y = yc - axis1*sth - axis2*cth;
points[3].x = xc + axis1*cth + axis2*sth;
points[3].y = yc + axis1*sth - axis2*cth;
}
else
elem->click_boundary = elem->draw_boundary;
}
void
aff_element_compute_boundary(AffElement *elem, gint width,
gint height,
AffElement **elements,
int num_elements)
{
int i;
IPolygon tmp_poly;
gdouble *points_x;
gdouble *points_y;
if (elem->click_boundary && elem->click_boundary != elem->draw_boundary)
g_free(elem->click_boundary);
if (elem->draw_boundary)
g_free(elem->draw_boundary);
tmp_poly.npoints = num_elements;
tmp_poly.points = g_new(GdkPoint,num_elements);
points_x = g_new(gdouble,num_elements);
points_y = g_new(gdouble,num_elements);
for (i=0;i<num_elements;i++)
{
aff2_apply(&elem->trans,elements[i]->v.x*width,elements[i]->v.y*width,
&points_x[i],&points_y[i]);
tmp_poly.points[i].x = (gint)points_x[i];
tmp_poly.points[i].y = (gint)points_y[i];
}
elem->draw_boundary = ipolygon_convex_hull(&tmp_poly);
aff_element_compute_click_boundary(elem,num_elements,points_x,points_y);
g_free(tmp_poly.points);
}
void
aff_element_draw(AffElement *elem, gint selected,
gint width, gint height,
GdkDrawable *win,
GdkGC *normal_gc,GdkGC *selected_gc,
GdkFont *font)
{
GdkGC *gc;
gint string_width = gdk_string_width (font,elem->name);
gint string_height = font->ascent + font->descent + 2;
if (selected)
gc = selected_gc;
else
gc = normal_gc;
gdk_draw_string(win,font,gc,
elem->v.x*width-string_width/2,
elem->v.y*width+string_height/2,elem->name);
if (elem->click_boundary != elem->draw_boundary)
gdk_draw_polygon(win,normal_gc,FALSE,elem->click_boundary->points,
elem->click_boundary->npoints);
gdk_draw_polygon(win,gc,FALSE,elem->draw_boundary->points,
elem->draw_boundary->npoints);
}
AffElement *
aff_element_new(gdouble x, gdouble y, IfsColor color, gint count)
{
AffElement *elem = g_new(AffElement, 1);
char buffer[16];
elem->v.x = x;
elem->v.y = y;
elem->v.theta = 0.0;
elem->v.scale = 0.5;
elem->v.asym = 1.0;
elem->v.shear = 0.0;
elem->v.flip = 0;
elem->v.red_color = color;
elem->v.blue_color = color;
elem->v.green_color = color;
elem->v.black_color = color;
elem->v.target_color = color;
elem->v.hue_scale = 0.5;
elem->v.value_scale = 0.5;
elem->v.simple_color = TRUE;
elem->draw_boundary = NULL;
elem->click_boundary = NULL;
aff_element_compute_color_trans(elem);
elem->v.prob = 1.0;
sprintf(buffer,"%d",count);
elem->name = g_strdup(buffer);
return elem;
}
void
aff_element_free(AffElement *elem)
{
if (elem->click_boundary != elem->draw_boundary)
g_free(elem->click_boundary);
g_free(elem->draw_boundary);
g_free(elem);
}
#ifdef DEBUG_BRUSH
static brush_chars[] = {' ',':','*','@'};
#endif
static guchar *
create_brush(IfsComposeVals *ifsvals, gint *brush_size, gdouble *brush_offset)
{
gint i,j;
gint ii,jj;
guchar *brush;
#ifdef DEBUG_BRUSH
gdouble totpix = 0.0;
#endif
gdouble radius = ifsvals->radius * ifsvals->subdivide;
*brush_size = ceil(2*radius);
*brush_offset = 0.5 * (*brush_size-1);
brush = g_new(guchar,SQR(*brush_size));
for (i=0;i<*brush_size;i++)
{
for (j=0;j<*brush_size;j++)
{
gdouble d = sqrt(SQR(i-*brush_offset)+SQR(j-*brush_offset));
gdouble pixel = 0.0;
if (d-0.5*sqrt(2) > radius)
pixel = 0.0;
else if (d+0.5*sqrt(2) < radius)
pixel = 1.0;
else
for (ii=0;ii<10;ii++)
for (jj=0;jj<10;jj++)
{
d = sqrt(SQR(i-*brush_offset+ii*0.1-0.45)
+SQR(j-*brush_offset+jj*0.1-0.45));
pixel += (d<radius)/100.0;
}
brush[i**brush_size+j] = 255.999*pixel;
#ifdef DEBUG_BRUSH
putchar(brush_chars[(int)(pixel*3.999)]);
totpix += pixel;
#endif DEBUG_BRUSH
}
#ifdef DEBUG_BRUSH
putchar('\n');
#endif DEBUG_BRUSH
}
#ifdef DEBUG_BRUSH
printf("Brush total / area = %f\n",totpix/SQR(ifsvals->subdivide));
#endif DEBUG_BRUSH
return brush;
}
void
ifs_render(AffElement **elements, gint num_elements,
gint width, gint height, gint nsteps,
IfsComposeVals *vals, gint band_y, gint band_height,
guchar *data, guchar *mask, guchar *nhits, gint preview)
{
gint i,k;
gdouble x,y;
gdouble r,g,b;
gint ri,gi,bi;
gint p0,psum;
gdouble pt;
guchar *ptr;
gint *prob;
gdouble *fprob;
gint subdivide;
guchar *brush = NULL;
gint brush_size;
gdouble brush_offset;
if (preview)
subdivide = 1;
else
subdivide = vals->subdivide;
/* compute the probabilities and transforms */
fprob = g_new(gdouble,num_elements);
prob = g_new(gint,num_elements);
pt = 0.0;
for (i=0;i<num_elements;i++)
{
aff_element_compute_trans(elements[i],width*subdivide,height*subdivide,
vals->center_x, vals->center_y);
fprob[i] = fabs(
elements[i]->trans.a11 * elements[i]->trans.a22
- elements[i]->trans.a12 * elements[i]->trans.a21);
/* As a heuristic, if the determinant is really small, it's
probably a line element, so increase the probability so
it gets rendered */
/* FIXME: figure out what 0.01 really should be */
if (fprob[i] < 0.01) fprob[i] = 0.01;
fprob[i] *= elements[i]->v.prob;
pt += fprob[i];
}
psum = 0;
for (i=0;i<num_elements;i++)
{
psum += RAND_MAX * (fprob[i]/pt);
prob[i] = psum;
}
prob[i-1] = RAND_MAX; /* make sure we don't get bitten
by roundoff*/
/* create the brush */
if (!preview)
brush = create_brush(vals,&brush_size,&brush_offset);
x = y = 0;
r = g = b = 0;
/* now run the iteration */
for (i=0;i<nsteps;i++)
{
if (!preview && !(i % 5000))
gimp_progress_update ((gdouble) i / (gdouble) nsteps);
p0 = rand();
k=0;
while (p0 > prob[k])
k++;
aff2_apply(&elements[k]->trans,x,y,&x,&y);
aff3_apply(&elements[k]->color_trans,r,g,b,&r,&g,&b);
if (i<50) continue;
ri= (gint)(255.999*r);
gi = (gint)(255.999*g);
bi = (gint)(255.999*b);
if (preview)
{
if ((x<width) && (y<(band_y+band_height)) &&
(x >= 0) && (y >= band_y) &&
(ri >= 0) && (ri < 256) &&
(gi >= 0) && (gi < 256) &&
(bi >= 0) && (bi < 256))
{
ptr = data + 3 * (((gint)(y-band_y))*width + (gint)x);
*ptr++ = ri;
*ptr++ = gi;
*ptr = bi;
}
}
else
if ((ri >= 0) && (ri < 256) &&
(gi >= 0) && (gi < 256) &&
(bi >= 0) && (bi < 256))
{
guint m_old;
guint m_new;
guint m_pix;
guint n_hits;
guint old_scale;
guint pix_scale;
gint index;
gint ii,jj;
gint jj0 = floor(y-brush_offset-band_y*subdivide);
gint ii0 = floor(x-brush_offset);
gint jjmax,iimax;
gint jjmin = 0;
gint iimin = 0;
if (ii0 < 0)
iimin = - ii0;
else
iimin = 0;
if (jj0 < 0)
jjmin = - jj0;
else
jjmin = 0;
if (jj0+brush_size >= subdivide*band_height)
jjmax = subdivide*band_height - jj0;
else
jjmax = brush_size;
if (ii0+brush_size >= subdivide*width)
iimax = subdivide*width - ii0;
else
iimax = brush_size;
for (jj=jjmin;jj<jjmax;jj++)
for (ii=iimin;ii<iimax;ii++)
{
index = (jj0+jj)*width*subdivide + ii0 + ii;
n_hits = nhits[index];
if (n_hits == 255)
continue;
m_pix = brush[jj*brush_size+ii];
if (!m_pix)
continue;
nhits[index] = ++n_hits;
m_old = mask[index];
m_new = m_old + m_pix - m_old*m_pix/255;
mask[index] = m_new;
/* relative probability that old colored pixel is on top */
old_scale = m_old*(255*n_hits-m_pix);
/* relative probability that new colored pixel is on top */
pix_scale = m_pix*((255-m_old)*n_hits+m_old);
ptr = data + 3*index;
*ptr = ( old_scale * (*ptr) + pix_scale * ri ) /
( old_scale + pix_scale );
ptr++;
*ptr = ( old_scale * (*ptr) + pix_scale * gi ) /
( old_scale + pix_scale );
ptr++;
*ptr = ( old_scale * (*ptr) + pix_scale * bi ) /
( old_scale + pix_scale );
}
}
} /* main iteration */
if (brush)
g_free(brush);
g_free(prob);
g_free(fprob);
}

View File

@ -1,341 +0,0 @@
/* The GIMP -- an image manipulation program
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* 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
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/* This plugin by thorsten@arch.usyd.edu.au */
/* Based on S&P's Gauss and Laplace filters */
/* updated 11/04/97:
Use 8-pixel neighbourhood to create outline,
use min-max operation for local gradient,
don't use rint;
if gamma-channel: set to white if at least one colour channel is >15 */
/* update 03/10/97
#ifdef MAX and MIN */
#include <stdlib.h>
#include "libgimp/gimp.h"
#include <stdio.h>
#include <math.h>
/* Declare local functions.
*/
static void query (void);
static void run (char *name,
int nparams,
GParam *param,
int *nreturn_vals,
GParam **return_vals);
static void laplace (GDrawable *drawable);
static void laplace_prepare_row (GPixelRgn *pixel_rgn,
guchar *data,
int x,
int y,
int w);
GPlugInInfo PLUG_IN_INFO =
{
NULL, /* init_proc */
NULL, /* quit_proc */
query, /* query_proc */
run, /* run_proc */
};
MAIN ();
static void
query ()
{
static GParamDef args[] =
{
{ PARAM_INT32, "run_mode", "Interactive, non-interactive" },
{ PARAM_IMAGE, "image", "Input image (unused)" },
{ PARAM_DRAWABLE, "drawable", "Input drawable" },
};
static GParamDef *return_vals = NULL;
static int nargs = sizeof (args) / sizeof (args[0]);
static int nreturn_vals = 0;
gimp_install_procedure ("plug_in_laplace",
"Edge Detection with Laplace Operation",
"This plugin creates one-pixel wide edges from the image, with the value proportional to the gradient. It uses the Laplace operator (a 3x3 kernel with -8 in the middle)The image has to be laplacered to get usefull results, a gauss_iir with 1.5 - 5.0 depending on the noise in the image is best",
"Thorsten Schnier",
"Thorsten Schnier",
"1997",
"<Image>/Filters/Edge-Detect/Laplace",
"RGB*, GRAY*",
PROC_PLUG_IN,
nargs, nreturn_vals,
args, return_vals);
}
static void
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;
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_tile_cache_ntiles (2 * (drawable->width / gimp_tile_width () + 1));
laplace (drawable);
if (run_mode != RUN_NONINTERACTIVE)
gimp_displays_flush ();
}
else
{
/* gimp_message ("laplace: cannot operate on indexed color images"); */
status = STATUS_EXECUTION_ERROR;
}
*nreturn_vals = 1;
*return_vals = values;
values[0].type = PARAM_STATUS;
values[0].data.d_status = status;
gimp_drawable_detach (drawable);
}
static void
laplace_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++)
{
data[-pixel_rgn->bpp + b] = data[b];
data[w * pixel_rgn->bpp + b] = data[(w - 1) * pixel_rgn->bpp + b];
}
}
#define SIGN(a) (((a) > 0) ? 1 : -1)
#define RMS(a,b) (sqrt (pow ((a),2) + pow ((b), 2)))
#ifndef MAX
#define MAX(a,b) (((a) > (b)) ? (a) : (b))
#endif
#ifndef MIN
#define MIN(a,b) (((a) < (b)) ? (a) : (b))
#endif
#define BLACK_REGION(val) ((val) > 128)
#define WHITE_REGION(val) ((val) <= 128)
static void minmax (gint x1, gint x2, gint x3, gint x4, gint x5,
gint* min_result, gint* max_result)
{
gint min1,min2,max1,max2;
if (x1>x2) {max1=x1; min1=x2;} else {max1=x2; min1=x1;}
if (x3>x4) {max2=x3; min2=x4;} else {max2=x4; min2=x3;}
if (min1<min2)
*min_result = MIN (min1, x5);
else *min_result = MIN (min2, x5);
if (max1>max2)
*max_result = MAX (max1, x5);
else *max_result = MAX (max2, x5);
}
static void
laplace (GDrawable *drawable)
{
GPixelRgn srcPR, destPR;
gint width, height;
gint bytes;
gint current;
gint gradient;
gint max_gradient = 0;
gint alpha;
gint counter;
guchar *dest, *d;
guchar *prev_row, *pr;
guchar *cur_row, *cr;
guchar *next_row, *nr;
guchar *tmp;
gint row, col;
gint x1, y1, x2, y2;
gint minval, maxval;
float scale = 1.0;
/* 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);
gimp_progress_init ("Laplace");
/* Get the size of the input image. (This will/must be the same
* as the size of the output image.
*/
width = drawable->width;
height = drawable->height;
bytes = drawable->bpp;
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);
/* 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);
pr = prev_row + bytes;
cr = cur_row + bytes;
nr = next_row + bytes;
laplace_prepare_row (&srcPR, pr, x1, y1 - 1, (x2 - x1));
laplace_prepare_row (&srcPR, cr, x1, y1, (x2 - x1));
/* loop through the rows, applying the laplace convolution */
for (row = y1; row < y2; row++)
{
/* prepare the next row */
laplace_prepare_row (&srcPR, nr, x1, row + 1, (x2 - x1));
d = dest;
for (col = 0; col < (x2 - x1) * bytes; col++)
if (alpha && (((col + 1) % bytes) == 0)) /* the alpha channel */
*d++ = cr[col];
else
{
minmax (pr[col], cr[col - bytes], cr[col], cr[col + bytes],
nr[col], &minval, &maxval); /* four-neighbourhood */
gradient = (0.5 * MIN ((maxval - cr [col]), (cr[col]- minval)));
max_gradient = MAX(abs(gradient), max_gradient);
*d++ = ((pr[col - bytes] + pr[col] + pr[col + bytes] +
cr[col - bytes] - (8 * cr[col]) + cr[col + bytes] +
nr[col - bytes] + nr[col] + nr[col + bytes]) > 0) ?
gradient : (128 + gradient);
}
/* store the dest */
gimp_pixel_rgn_set_row (&destPR, 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));
}
/* now clean up: leave only edges, but keep gradient value */
gimp_pixel_rgn_init (&srcPR, drawable, 0, 0, width, height, FALSE, TRUE);
pr = prev_row + bytes;
cr = cur_row + bytes;
nr = next_row + bytes;
laplace_prepare_row (&srcPR, pr, x1, y1 - 1, (x2 - x1));
laplace_prepare_row (&srcPR, cr, x1, y1, (x2 - x1));
gimp_progress_init ("Cleanup");
scale = (255.0 / (float) max_gradient);
counter =0;
/* loop through the rows, applying the laplace convolution */
for (row = y1; row < y2; row++)
{
/* prepare the next row */
laplace_prepare_row (&srcPR, nr, x1, row + 1, (x2 - x1));
d = dest;
for (col = 0; col < (x2 - x1) * bytes; col++) {
current = cr[col];
current = (WHITE_REGION(current) &&
(BLACK_REGION (pr[col - bytes]) ||
BLACK_REGION (pr[col]) ||
BLACK_REGION (pr[col + bytes]) ||
BLACK_REGION (cr[col - bytes]) ||
BLACK_REGION (cr[col + bytes]) ||
BLACK_REGION (nr[col - bytes]) ||
BLACK_REGION (nr[col]) ||
BLACK_REGION (nr[col + bytes]))) ?
(gint) (scale * ((float) ((current >= 128) ?
(current-128) : current)))
: 0;
if (alpha && (((col + 1) % bytes) == 0)) { /* the alpha channel */
*d++ = (counter == 0) ? 0 : 255;
counter = 0; }
else {
*d++ = current;
if (current > 15) counter ++;
}
}
/* store the dest */
gimp_pixel_rgn_set_row (&destPR, 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));
}
/* update the laplaced 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);
}

File diff suppressed because it is too large Load Diff

View File

@ -1,338 +0,0 @@
/* The GIMP -- an image manipulation program
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* 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
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
* ---------------------------------------------------------------------------------------
*
* Magic Eye version 0.2
*
* This is a plugin for the gimp.
* Copyright (C) 1997 Alexander Schulz
* New versions: http://www.uni-karlsruhe.de/~Alexander.Schulz/english/gimp/gimp.html
* Mail: Alexander.Schulz@stud.uni-karlsruhe.de
*
* Some parts that deal with the interaction with the Gimp
* are modified from other plugins.
* Thanks to the other programmers.
*/
#include <libgimp/gimp.h>
#include <libgimp/gimpmenu.h>
#include "magiceye.h"
/* Declare local functions.
*/
/* static void text_callback (int, void *, void *); */
gdouble strip_width;
gdouble depth;
gint from_left, up_down;
static char *prog_name;
GDrawable *map_drawable;
GStatusType status = STATUS_SUCCESS;
GPlugInInfo PLUG_IN_INFO =
{
NULL, /* init_proc */
NULL, /* quit_proc */
query, /* query_proc */
run, /* run_proc */
};
MAIN ()
void
query ()
{
static GParamDef args[] =
{
{ PARAM_INT32, "run_mode", "Interactive, non-interactive" },
{ PARAM_IMAGE, "image", "Input image (unused)" },
{ PARAM_DRAWABLE, "drawable", "Input drawable" },
{ PARAM_INT32, "mapimage", "Map Image" },
};
static GParamDef return_vals[] =
{
{ PARAM_IMAGE, "new_image", "Output image" },
{ PARAM_IMAGE, "new_layer", "Output layer" },
};
static int nargs = sizeof (args) / sizeof (args[0]);
static int nreturn_vals = sizeof (return_vals) / sizeof (return_vals[0]);
gimp_install_procedure ("plug_in_magic_eye",
"Create a stereogram",
"Create a stereogram",
"Alexander Schulz",
"Alexander Schulz",
"1997",
"<Image>/Filters/Render/Magic Eye",
"GRAY",
PROC_PLUG_IN,
nargs, nreturn_vals,
args, return_vals);
}
void
run (char *name,
int nparams,
GParam *param,
int *nreturn_vals,
GParam **return_vals)
{
static GParam values[3];
GRunModeType run_mode;
gint32 new_layer;
run_mode = param[0].data.d_int32;
*nreturn_vals = 3;
*return_vals = values;
values[0].type = PARAM_STATUS;
values[0].data.d_status = status;
values[1].type = PARAM_IMAGE;
values[1].type = PARAM_LAYER;
/* Get the specified drawable */
map_drawable = gimp_drawable_get (param[2].data.d_drawable);
switch (run_mode)
{
case RUN_INTERACTIVE:
/* Possibly retrieve data */
/* gimp_get_data ("plug_in_tile", &tvals); */
/* First acquire information with a dialog */
if (! magic_dialog())
return;
break;
case RUN_NONINTERACTIVE:
/* Make sure all the arguments are there! */
/*if (nparams != 5)
status = STATUS_CALLING_ERROR;
if (status == STATUS_SUCCESS)
{
tvals.new_width = param[3].data.d_int32;
tvals.new_height = param[4].data.d_int32;
}
if (tvals.new_width < 0 || tvals.new_height < 0)
status = STATUS_CALLING_ERROR;*/
break;
case RUN_WITH_LAST_VALS:
/* Possibly retrieve data */
/* gimp_get_data ("plug_in_tile", &tvals); */
break;
default:
break;
}
/* Make sure that the drawable is gray or RGB color */
if (status == STATUS_SUCCESS)
{
values[1].data.d_image = magiceye (map_drawable, &new_layer);
values[2].data.d_layer = new_layer;
gimp_display_new (values[1].data.d_image);
return;
}
}
gint
magiceye (GDrawable *mapimage,gint32 *layer)
{
GDrawableType dest_type;
unsigned char *src1p;
unsigned char *src2p;
unsigned char *destp;
unsigned char *cmap;
unsigned char *savep;
unsigned char *temp_buf;
long src1_width, src1_height;
long src2_width, src2_height;
long src1_channels;
long src2_channels;
long dest_channels;
GPixelRgn streifen_rgn;
GDrawable *streifen;
GPixelRgn dest_rgn;
GDrawable *destination;
GPixelRgn map_rgn;
gint32 dest, image_ID;
int src1r, src1g, src1b;
int src2r, src2g, src2b;
int destr, destg, destb;
int i, j, hoehe, x, _up_down;
gint number;
streifen = gimp_drawable_get(magiceye_ID);
image_ID=gimp_drawable_image_id(magiceye_ID);
gimp_pixel_rgn_init(&streifen_rgn, streifen, 0, 0, streifen->width, streifen->height, FALSE, FALSE);
gimp_pixel_rgn_init(&map_rgn, mapimage, 0, 0, mapimage->width, mapimage->height, FALSE, FALSE);
dest_type = gimp_drawable_type(magiceye_ID);
src2_channels = streifen->bpp;
src1p = g_malloc(mapimage->width*mapimage->height);
src2p = g_malloc(streifen->width*streifen->height*src2_channels);
gimp_pixel_rgn_get_rect(&map_rgn, src1p, 0, 0, mapimage->width, mapimage->height);
gimp_pixel_rgn_get_rect(&streifen_rgn, src2p, 0, 0, streifen->width, streifen->height);
src2_width = streifen->width;
src2_height = streifen->height;
src1_width = mapimage->width;
src1_height = mapimage->height;
dest_channels = src2_channels;
switch (dest_type){
case RGB_IMAGE:
dest= gimp_image_new (src1_width, src1_height, RGB);
break;
case GRAY_IMAGE:
dest= gimp_image_new (src1_width, src1_height, GRAY);
break;
case INDEXED_IMAGE:
dest= gimp_image_new (src1_width, src1_height, INDEXED);
break;
default:
printf("Magic Eye: cannot operate on unknown image types or alpha images");
/* gimp_quit (); */
return -1;
break;
}
*layer = gimp_layer_new (dest, "Background", src1_width, src1_height, dest_type, 100, NORMAL_MODE);
gimp_image_add_layer(dest,*layer,0);
destination = gimp_drawable_get(*layer);
destp = g_malloc(mapimage->width*mapimage->height*dest_channels);
savep = destp;
if (dest_type == INDEXED_IMAGE)
{
cmap = gimp_image_get_cmap (image_ID, &number);
#ifdef DEBUG
printf("ColorMap: %i %i \n",magiceye_ID, image_ID);
for (i=0;i<number;i++) { printf("%4i: %x %x %x\n",i,cmap[i],cmap[i+1],cmap[i+2]); }
#endif
gimp_image_set_cmap(dest, cmap, number);
g_free(cmap);
}
#ifdef DEBUG
printf("%i %i %i %i %i %i %i %i %i %i\n",magiceye_ID,src2_width,src2_height,src1_width,src1_height,dest_channels,(int)strip_width,dest,number,cmap);
#endif
temp_buf = g_malloc (20);
sprintf (temp_buf, "Creating image");
gimp_progress_init (temp_buf);
g_free (temp_buf);
/* Here ist the point where the work is done, not too much actually */
/* First copy the Background to the new image */
for (i = 0; i < src1_height; i++)
{
for (j = 0; j < src1_width*dest_channels; j++)
{
*destp++ = *(src2p+((j%((int)strip_width*dest_channels))+src2_width*(i%src2_height)*dest_channels));
}
if ((i % 5) == 0)
gimp_progress_update ((double) i / (double) src1_height);
}
destp = savep;
gimp_progress_update(0);
if (up_down) _up_down=-1; else _up_down=1;
if (from_left) {
/* Then add the map-image */
/* Beginning from the left */
for (j = strip_width; j < src1_width; j++)
{
for (i = 0; i < src1_height; i++)
{
hoehe=src1p[i*src1_width*1+j*1] * depth / 255;
for (x=0; x<dest_channels; x++)
{
destp[(i*src1_width+j-hoehe*_up_down)*dest_channels+x] =
destp[(i*src1_width+j-(int)strip_width)*dest_channels+x];
}
}
if ((j % 5) == 0)
gimp_progress_update ((double) j / (double) src1_width);
}
} else {
/* Or add the map-image */
/* Beginning from the middle */
for (j = (src1_width / 2 / strip_width) * strip_width; j < src1_width; j++)
{
for (i = 0; i < src1_height; i++)
{
hoehe=src1p[i*src1_width*1+j*1] * depth / 255;
for (x=0; x<dest_channels; x++)
{
destp[(i*src1_width+j-hoehe*_up_down)*dest_channels+x] =
destp[(i*src1_width+j-(int)strip_width)*dest_channels+x];
}
}
if ((j % 5) == 0)
gimp_progress_update ((double) (j - (src1_width / 2 / strip_width) * strip_width ) / (double) src1_width);
}
for (j = (src1_width / 2 / strip_width) * strip_width; j > strip_width; j--)
{
for (i = 0; i < src1_height; i++)
{
hoehe=src1p[i*src1_width*1+j*1] * depth / 255;
for (x=0; x<dest_channels; x++)
{
destp[(i*src1_width+j+hoehe*_up_down-(int)strip_width)*dest_channels+x] =
destp[(i*src1_width+j)*dest_channels+x];
}
}
if ((j % 5) == 0)
gimp_progress_update ((double) (src1_width - j) / (double) src1_width);
}
gimp_progress_update(1);
}
gimp_progress_update(0);
/* end of work */
gimp_pixel_rgn_init(&dest_rgn, destination, 0, 0, destination->width, destination->height, TRUE, FALSE);
gimp_pixel_rgn_set_rect(&dest_rgn, savep, 0, 0, destination->width, destination->height);
gimp_drawable_detach(destination);
g_free(src2p);
g_free(src1p);
g_free(savep);
return dest;
}

View File

@ -1,871 +0,0 @@
/* The GIMP -- an image manipulation program
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
* Copyright (C) 1997 Daniel Risacher
*
* 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
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/*
* GUMP - Gimp Useless Mail Plugin (or Gump Useless Mail Plugin if you prefer)
* version about .645 I would say... give or take a few decimal points
*
*
* by Adrian Likins <aklikins@eos.ncsu.edu>
* MIME encapsulation by Reagan Blundell <reagan@emails.net>
*
*
*
* Based heavily on gz.c by Daniel Risacher
*
* Lets you choose to send a image to the mail from the file save as dialog.
* images are piped to uuencode and then to mail...
*
*
* This works fine for .99.10. I havent actually tried it in combination with
* the gz plugin, but it works with all other file types. I will eventually get
* around to making sure it works with gz.
*
* To use: 1) image->File->mail image
* 2) when the mail dialog popups up, fill it out. Only to: and filename are required
* note: the filename needs to a type that the image can be saved as. otherwise
* you will just send an empty message.
* 3) click ok and it should be on its way
*
*
* NOTE: You probabaly need sendmail installed. If your sendmail is in an odd spot
* you can change the #define below. If you use qmail or other MTA's, and this
* works after changing the MAILER, let me know how well or what changes were
* needed.
*
* NOTE: Uuencode is needed. If it is in the path, it should work fine as is. Other-
* wise just change the UUENCODE.
*
*
* TODO: 1) the aforementioned abilty to specify the
* uuencode filename *done*
* 2) someway to do this without tmp files
* * wont happen anytime soon*
* 3) MIME? *done*
* 4) a pointlessly snazzier dialog
* 5) make sure it works with gz
* * works for .xcfgz but not .xcf.gz *
* 6) add an option to choose if mail get
* uuencode or not (or MIME'ed for that matter)
* 7) realtime preview
* 8) better entry for comments
* 9) list of frequently used addreses
* 10) openGL compliance
* 11) better handling of filesave errors
*
*
* Version history
* .5 - 6/30/97 - inital relese
* .51 - 7/3/97 - fixed a few spelling errors and the like
* .65 - 7/4/97 - a fairly significant revision. changed it from a file
* plugin to an image plugin.
* - Changed some strcats into strcpy to be a bit more robust.
* - added the abilty to specify the filename you want it sent as
* - no more annoying hassles with the file saves as dialog
* - plugin now registers itself as <image>/File/Mail image
* .7 - 9/12/97 - (RB) added support for MIME encapsulation
* .71 - 9/17/97 - (RB) included Base64 encoding functions from mpack
* instead of using external program.
* - General cleanup of the MIME handling code.
*
* As always: The utility of this plugin is left as an exercise for the reader
*
*/
#ifndef MAILER
#define MAILER "/usr/lib/sendmail"
#endif
#ifndef UUENCODE
#define UUENCODE "uuencode"
#endif
#define ENCAPSULATION_UUENCODE 0
#define ENCAPSULATION_MIME 1
#include <stdlib.h>
#include <stdio.h>
#include <sys/param.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include "gtk/gtk.h"
#include "libgimp/gimp.h"
static void query (void);
static void run (char *name,
int nparams,
GParam * param,
int *nreturn_vals,
GParam ** return_vals);
static gint save_image (char *filename,
gint32 image_ID,
gint32 drawable_ID,
gint32 run_mode);
static gint save_dialog ();
static void close_callback (GtkWidget * widget, gpointer data);
static void ok_callback (GtkWidget * widget, gpointer data);
static void encap_callback (GtkWidget * widget, gpointer data);
static void receipt_callback (GtkWidget * widget, gpointer data);
static void subject_callback (GtkWidget * widget, gpointer data);
static void comment_callback (GtkWidget * widget, gpointer data);
static void filename_callback (GtkWidget * widget, gpointer data);
static int valid_file (char *filename);
static void create_headers (FILE * mailpipe);
static char *find_extension (char *filename);
static int to64(FILE *infile, FILE *outfile);
static void output64chunk(int c1, int c2, int c3, int pads, FILE *outfile);
GPlugInInfo PLUG_IN_INFO =
{
NULL, /* init_proc */
NULL, /* quit_proc */
query, /* query_proc */
run, /* run_proc */
};
typedef struct
{
char receipt[256];
char subject[256];
char comment[256];
char filename[256];
int encapsulation;
}
m_info;
static m_info mail_info = {
/* I would a assume there is a better way to do this, but this works for now */
"\0",
"\0",
"\0",
"\0",
ENCAPSULATION_MIME, /* Change this to ENCAPSULATION_UUENCODE
if you prefer that as the default */
};
static int run_flag = 0;
MAIN ()
static void
query ()
{
static GParamDef args[] =
{
{PARAM_INT32, "run_mode", "Interactive, non-interactive"},
{PARAM_IMAGE, "image", "Input image"},
{PARAM_DRAWABLE, "drawable", "Drawable to save"},
{PARAM_STRING, "filename", "The name of the file to save the image in"},
{PARAM_STRING, "receipt", "The email address to send to"},
{PARAM_STRING, "subject", "The subject"},
{PARAM_STRING, "comment", "The Comment"},
{PARAM_INT32, "encapsulation", "Uuencode, MIME"},
};
static int nargs = sizeof (args) / sizeof (args[0]);
static GParamDef *return_vals = NULL;
static int nreturn_vals = 0;
gimp_install_procedure ("plug_in_mail_image",
"pipe files to uuencode then mail them",
"You need to have uuencode and mail installed",
"Adrian Likins, Reagan Blundell",
"Adrian Likins, Reagan Blundell, Daniel Risacher, Spencer Kimball and Peter Mattis",
"1995-1997",
"<Image>/File/Mail image",
"RGB*, GRAY*, INDEXED*",
PROC_PLUG_IN,
nargs, nreturn_vals,
args, return_vals);
}
static void
run (char *name,
int nparams,
GParam * param,
int *nreturn_vals,
GParam ** return_vals)
{
static GParam values[2];
GRunModeType run_mode;
gint32 drawable_ID;
GStatusType status = STATUS_SUCCESS;
gint32 image_ID;
run_mode = param[0].data.d_int32;
drawable_ID = param[2].data.d_drawable;
image_ID = param[1].data.d_image;
*nreturn_vals = 1;
*return_vals = values;
values[0].type = PARAM_STATUS;
values[0].data.d_status = STATUS_CALLING_ERROR;
if (strcmp (name, "plug_in_mail_image") == 0)
{
switch (run_mode)
{
case RUN_INTERACTIVE:
gimp_get_data ("plug_in_mail_image", &mail_info);
if (!save_dialog ())
return;
break;
case RUN_NONINTERACTIVE:
/* Make sure all the arguments are there! */
if (nparams != 8)
status = STATUS_CALLING_ERROR;
if(status == STATUS_SUCCESS)
{
/* this hasnt been tested yet */
strncpy (mail_info.filename, param[3].data.d_string,256);
strncpy (mail_info.receipt, param[4].data.d_string,256);
strncpy (mail_info.subject, param[5].data.d_string,256);
strncpy (mail_info.comment, param[6].data.d_string,256);
mail_info.encapsulation = param[7].data.d_int32;
}
break;
case RUN_WITH_LAST_VALS:
gimp_get_data ("plug_in_mail_image", &mail_info);
break;
default:
break;
}
*nreturn_vals = 1;
if (save_image (mail_info.filename,
image_ID,
drawable_ID,
run_mode))
{
values[0].data.d_status = STATUS_SUCCESS;
}
else
values[0].data.d_status = STATUS_EXECUTION_ERROR;
}
else
g_assert (FALSE);
}
static gint
save_image (char *filename,
gint32 image_ID,
gint32 drawable_ID,
gint32 run_mode)
{
GParam *params;
gint retvals;
char *ext;
char *tmpname;
char mailcmdline[512];
int pid;
int status;
FILE *mailpipe;
FILE *infile;
if (NULL == (ext = find_extension (filename)))
return -1;
/* get a temp name with the right extension and save into it. */
params = gimp_run_procedure ("gimp_temp_name",
&retvals,
PARAM_STRING, ext + 1,
PARAM_END);
tmpname = params[1].data.d_string;
/* construct the "sendmail user@location" line */
strcpy (mailcmdline, MAILER);
strcat (mailcmdline, " ");
strcat (mailcmdline, mail_info.receipt);
/* create a pipe to sendmail */
mailpipe = popen (mailcmdline, "w");
create_headers (mailpipe);
/* This is necessary to make the comments and headers work correctly. Not real sure why */
fflush (mailpipe);
params = gimp_run_procedure ("gimp_file_save",
&retvals,
PARAM_INT32, run_mode,
PARAM_IMAGE, image_ID,
PARAM_DRAWABLE, drawable_ID,
PARAM_STRING, tmpname,
PARAM_STRING, tmpname,
PARAM_END);
/* need to figure a way to make sure the user is trying to save in an approriate format */
/* but this can wait.... */
if (params[0].data.d_status == FALSE || !valid_file (tmpname))
{
unlink (tmpname);
return -1;
}
if( mail_info.encapsulation == ENCAPSULATION_UUENCODE ) {
/* fork off a uuencode process */
if ((pid = fork ()) < 0)
{
g_warning ("mail: fork failed: %s\n", g_strerror (errno));
return -1;
}
else if (pid == 0)
{
if (-1 == dup2 (fileno (mailpipe), fileno (stdout)))
{
g_warning ("mail: dup2 failed: %s\n", g_strerror (errno));
}
execlp (UUENCODE, UUENCODE, tmpname, filename, NULL);
/* What are we doing here? exec must have failed */
g_warning ("mail: exec failed: uuencode: %s\n", g_strerror (errno));
/* close the pipe now */
pclose (mailpipe);
_exit (127);
}
else
{
waitpid (pid, &status, 0);
if (!WIFEXITED (status) ||
WEXITSTATUS (status) != 0)
{
g_warning ("mail: mail didnt work or something on file %s\n", tmpname);
return 0;
}
}
}
else { /* This must be MIME stuff. Base64 away... */
infile = fopen(tmpname,"r");
to64(infile,mailpipe);
/* close off mime */
if( mail_info.encapsulation == ENCAPSULATION_MIME ) {
fprintf(mailpipe, "\n--GUMP-MIME-boundary--\n");
}
}
/* delete the tmpfile that was generated */
unlink (tmpname);
return TRUE;
}
static gint
save_dialog ()
{
GtkWidget *dlg;
GtkWidget *button;
GtkWidget *entry;
GtkWidget *table;
GtkWidget *label;
GtkWidget *button1;
GtkWidget *button2;
GSList *group;
gint argc;
gchar **argv;
gchar buffer[32];
argc = 1;
argv = g_new (gchar *, 1);
argv[0] = g_strdup ("mail");
gtk_init (&argc, &argv);
gtk_rc_parse (gimp_gtkrc ());
dlg = gtk_dialog_new ();
gtk_window_set_title (GTK_WINDOW (dlg), "Send to mail");
gtk_signal_connect (GTK_OBJECT (dlg), "destroy",
(GtkSignalFunc) close_callback, NULL);
/* action area */
/* Okay buton */
button = gtk_button_new_with_label ("OK");
GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
gtk_signal_connect (GTK_OBJECT (button), "clicked",
(GtkSignalFunc) ok_callback,
dlg);
gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dlg)->action_area), button, TRUE, TRUE, 0);
gtk_widget_grab_default (button);
gtk_widget_show (button);
/* cancel button */
button = gtk_button_new_with_label ("Cancel");
GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dlg)->action_area), button, TRUE, TRUE, 0);
gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
(GtkSignalFunc) gtk_widget_destroy,
GTK_OBJECT (dlg));
gtk_widget_show (button);
/* table */
table = gtk_table_new (5, 3, FALSE);
gtk_container_border_width (GTK_CONTAINER (table), 10);
gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dlg)->vbox), table, TRUE, TRUE, 0);
gtk_widget_show (table);
gtk_table_set_row_spacings (GTK_TABLE (table), 10);
gtk_table_set_col_spacings (GTK_TABLE (table), 10);
/* To: Label */
label = gtk_label_new ("To:");
gtk_table_attach (GTK_TABLE (table), label,
0, 1, 0, 1,
GTK_EXPAND | GTK_FILL,
GTK_EXPAND | GTK_FILL,
0, 0);
gtk_widget_show (label);
/* to: dialog */
entry = gtk_entry_new ();
gtk_table_attach (GTK_TABLE (table), entry,
1, 3, 0, 1,
GTK_EXPAND | GTK_FILL,
GTK_EXPAND | GTK_FILL,
0, 0);
gtk_widget_set_usize (entry, 200, 0);
sprintf (buffer, "%s", mail_info.receipt);
gtk_entry_set_text (GTK_ENTRY (entry), buffer);
gtk_signal_connect (GTK_OBJECT (entry), "changed",
(GtkSignalFunc) receipt_callback, &mail_info.receipt);
gtk_widget_show (entry);
/* subject Label */
label = gtk_label_new ("Subject:");
gtk_table_attach (GTK_TABLE (table), label,
0, 1, 1, 2,
GTK_EXPAND | GTK_FILL,
GTK_EXPAND | GTK_FILL,
0, 0);
gtk_widget_show (label);
/* Subject entry */
entry = gtk_entry_new ();
gtk_table_attach (GTK_TABLE (table), entry,
1, 3, 1, 2,
GTK_EXPAND | GTK_FILL,
GTK_EXPAND | GTK_FILL,
0, 0);
gtk_widget_set_usize (entry, 200, 0);
sprintf (buffer, "%s", mail_info.subject);
gtk_entry_set_text (GTK_ENTRY (entry), buffer);
gtk_signal_connect (GTK_OBJECT (entry), "changed",
(GtkSignalFunc) subject_callback, &mail_info.subject);
gtk_widget_show (entry);
/* Comment label */
label = gtk_label_new ("Comment:");
gtk_table_attach (GTK_TABLE (table), label,
0, 1, 2, 3,
GTK_EXPAND | GTK_FILL,
GTK_EXPAND | GTK_FILL,
0, 0);
gtk_widget_show (label);
/* Comment dialog */
entry = gtk_entry_new ();
gtk_table_attach (GTK_TABLE (table), entry,
1, 3, 2, 3,
GTK_EXPAND | GTK_FILL,
GTK_EXPAND | GTK_FILL,
0, 0);
gtk_widget_set_usize (entry, 200, 0);
sprintf (buffer, "%s", mail_info.comment);
gtk_entry_set_text (GTK_ENTRY (entry), buffer);
gtk_signal_connect (GTK_OBJECT (entry), "changed",
(GtkSignalFunc) comment_callback, &mail_info.comment);
gtk_widget_show (entry);
/* filename label */
label = gtk_label_new ("Filename:");
gtk_table_attach (GTK_TABLE (table), label,
0, 1, 3, 4,
GTK_EXPAND | GTK_FILL,
GTK_EXPAND | GTK_FILL,
0, 0);
gtk_widget_show (label);
/* Filename dialog */
entry = gtk_entry_new ();
gtk_table_attach (GTK_TABLE (table), entry,
1, 3, 3, 4,
GTK_EXPAND | GTK_FILL,
GTK_EXPAND | GTK_FILL,
0, 0);
gtk_widget_set_usize (entry, 200, 0);
sprintf (buffer, "%s", mail_info.filename);
gtk_entry_set_text (GTK_ENTRY (entry), buffer);
gtk_signal_connect (GTK_OBJECT (entry), "changed",
(GtkSignalFunc) filename_callback, &mail_info.filename);
gtk_widget_show (entry);
/* Encapsulation label */
label = gtk_label_new ("Encapsulation:");
gtk_table_attach( GTK_TABLE (table), label ,
0, 1, 4, 5,
GTK_EXPAND | GTK_FILL,
GTK_EXPAND | GTK_FILL,
0, 0);
gtk_widget_show(label);
/* Encapsulation radiobutton */
button1 = gtk_radio_button_new_with_label( NULL, "Uuencode");
group = gtk_radio_button_group( GTK_RADIO_BUTTON( button1 ) );
button2 = gtk_radio_button_new_with_label( group, "MIME" );
if( mail_info.encapsulation == ENCAPSULATION_UUENCODE ) {
gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(button1),TRUE);
} else {
gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(button2),TRUE);
}
gtk_signal_connect (GTK_OBJECT (button1), "toggled",
(GtkSignalFunc) encap_callback,
(gpointer) "uuencode" );
gtk_signal_connect (GTK_OBJECT (button2), "toggled",
(GtkSignalFunc) encap_callback,
(gpointer) "mime" );
gtk_table_attach( GTK_TABLE (table), button1,
1, 2, 4, 5,
GTK_EXPAND | GTK_FILL,
GTK_EXPAND | GTK_FILL,
0, 0 );
gtk_widget_show( button1 );
gtk_table_attach( GTK_TABLE (table), button2,
2, 3, 4, 5,
GTK_EXPAND | GTK_FILL,
GTK_EXPAND | GTK_FILL,
0, 0 );
gtk_widget_show( button2 );
gtk_widget_show (dlg);
gtk_main ();
gdk_flush ();
return run_flag;
}
static int
valid_file (char *filename)
{
int stat_res;
struct stat buf;
stat_res = stat (filename, &buf);
if ((0 == stat_res) && (buf.st_size > 0))
return 1;
else
return 0;
}
char *
find_content_type (char *filename)
{
/* This function returns a MIME Content-type: value based on the
filename it is given. */
char *type_mappings[20] = {"gif" , "image/gif",
"jpg" , "image/jpeg",
"jpeg", "image/jpeg",
"tif" , "image/tiff",
"tiff", "image/tiff",
"png" , "image/png",
"g3" , "image/g3fax",
"ps", "application/postscript",
"eps", "application/postscript",
NULL, NULL
};
char *ext;
char *mimetype = malloc(100);
int i=0;
ext = find_extension(filename);
if(!ext) {
strcpy( mimetype, "application/octet-stream");
return mimetype;
}
while( type_mappings[i] ) {
if( strcmp( ext+1, type_mappings[i] ) == 0 ) {
strcpy(mimetype,type_mappings[i+1]);
return mimetype;
}
i += 2;
}
strcpy(mimetype,"image/x-");
strncat(mimetype,ext+1,91);
mimetype[99]='\0';
return mimetype;
}
static char *
find_extension (char *filename)
{
char *filename_copy;
char *ext;
/* this whole routine needs to be redone so it works for xccfgz and .gz files */
/* not real sure where to start...... */
/* right now saving for .xcfgz works but not .xcf.gz */
/* this is all pretty close to straight from gz. It needs to be changed to */
/* work better for this plugin */
/* ie, FIXME */
/* we never free this copy - aren't we evil! */
filename_copy = malloc (strlen (filename) + 1);
strcpy (filename_copy, filename);
/* find the extension, boy! */
ext = strrchr (filename_copy, '.');
while (1)
{
if (!ext || ext[1] == 0 || strchr (ext, '/'))
{
g_warning ("mail: some sort of error with the file extension or lack thereof \n");
return NULL;
}
if (0 != strcmp(ext,".gz"))
{
return ext;
}
else
{
/* we found somehting, loop back, and look again */
*ext = 0;
ext = strrchr (filename_copy, '.');
}
}
return ext;
}
static void
close_callback (GtkWidget * widget, gpointer data)
{
gtk_main_quit ();
}
static void
ok_callback (GtkWidget * widget, gpointer data)
{
run_flag = 1;
gtk_widget_destroy (GTK_WIDGET (data));
}
static void
encap_callback (GtkWidget * widget, gpointer data)
{
/* Ignore the toggle-off signal, we are only interested in
what is being set */
if( ! GTK_TOGGLE_BUTTON( widget )->active ) {
return;
}
if(strcmp(data,"uuencode")==0)
mail_info.encapsulation = ENCAPSULATION_UUENCODE;
if(strcmp(data,"mime")==0)
mail_info.encapsulation = ENCAPSULATION_MIME;
}
static void
receipt_callback (GtkWidget * widget, gpointer data)
{
strncpy (mail_info.receipt, gtk_entry_get_text (GTK_ENTRY (widget)), 256);
}
static void
subject_callback (GtkWidget * widget, gpointer data)
{
strncpy (mail_info.subject, gtk_entry_get_text (GTK_ENTRY (widget)), 256);
}
static void
comment_callback (GtkWidget * widget, gpointer data)
{
strncpy (mail_info.comment, gtk_entry_get_text (GTK_ENTRY (widget)), 256);
}
static void
filename_callback (GtkWidget * widget, gpointer data)
{
strncpy (mail_info.filename, gtk_entry_get_text (GTK_ENTRY (widget)), 256);
}
static void
create_headers (FILE * mailpipe)
{
/* create all the mail header stuff. Feel free to add your own */
/* It is advisable to leave the X-Mailer header though, as */
/* there is a possibilty of a Gimp mail scanner/reader in the */
/* future. It will probabaly need that header. */
fprintf (mailpipe, "To: %s \n", mail_info.receipt);
fprintf (mailpipe, "Subject: %s \n", mail_info.subject);
fprintf (mailpipe, "X-Mailer: GIMP Useless Mail Program v.65\n");
fprintf (mailpipe, "X-GUMP-Author: Adrian Likins\n");
if(mail_info.encapsulation == ENCAPSULATION_MIME ){
fprintf (mailpipe, "MIME-Version: 1.0\n");
fprintf (mailpipe, "Content-type: multipart/mixed; boundary=GUMP-MIME-boundary\n");
}
fprintf (mailpipe, "\n\n");
if(mail_info.encapsulation == ENCAPSULATION_MIME ) {
fprintf (mailpipe, "--GUMP-MIME-boundary\n");
fprintf (mailpipe, "Content-type: text/plain; charset=US-ASCII\n\n");
}
fprintf (mailpipe, mail_info.comment);
fprintf (mailpipe, "\n\n");
if(mail_info.encapsulation == ENCAPSULATION_MIME ) {
char *content;
content=find_content_type(mail_info.filename);
fprintf (mailpipe, "--GUMP-MIME-boundary\n");
fprintf (mailpipe, "Content-type: %s\n",content);
fprintf (mailpipe, "Content-transfer-encoding: base64\n");
fprintf (mailpipe, "Content-disposition: attachment; filename=\"%s\"\n",mail_info.filename);
fprintf (mailpipe, "Content-description: %s\n\n",mail_info.filename);
free(content);
}
}
/*
* The following code taken from codes.c in the mpack-1.5 distribution
* by Carnegie Mellon University.
*
*
* (C) Copyright 1993,1994 by Carnegie Mellon University
* All Rights Reserved.
*
* Permission to use, copy, modify, distribute, and sell this software
* and its documentation for any purpose is hereby granted without
* fee, provided that the above copyright notice appear in all copies
* and that both that copyright notice and this permission notice
* appear in supporting documentation, and that the name of Carnegie
* Mellon University not be used in advertising or publicity
* pertaining to distribution of the software without specific,
* written prior permission. Carnegie Mellon University makes no
* representations about the suitability of this software for any
* purpose. It is provided "as is" without express or implied
* warranty.
*
* CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
* THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
* FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
* AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
* SOFTWARE.
*/
/*
Copyright (c) 1991 Bell Communications Research, Inc. (Bellcore)
Permission to use, copy, modify, and distribute this material
for any purpose and without fee is hereby granted, provided
that the above copyright notice and this permission notice
appear in all copies, and that the name of Bellcore not be
used in advertising or publicity pertaining to this
material without the specific, prior written permission
of an authorized representative of Bellcore. BELLCORE
MAKES NO REPRESENTATIONS ABOUT THE ACCURACY OR SUITABILITY
OF THIS MATERIAL FOR ANY PURPOSE. IT IS PROVIDED "AS IS",
WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES. */
static char basis_64[] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
static int to64(infile, outfile)
FILE *infile, *outfile;
{
int c1, c2, c3, ct=0, written=0;
while ((c1 = getc(infile)) != EOF) {
c2 = getc(infile);
if (c2 == EOF) {
output64chunk(c1, 0, 0, 2, outfile);
} else {
c3 = getc(infile);
if (c3 == EOF) {
output64chunk(c1, c2, 0, 1, outfile);
} else {
output64chunk(c1, c2, c3, 0, outfile);
}
}
ct += 4;
if (ct > 71) {
putc('\n', outfile);
written += 73;
ct = 0;
}
}
if (ct) {
putc('\n', outfile);
ct++;
}
return written + ct;
}
static void
output64chunk(c1, c2, c3, pads, outfile)
FILE *outfile;
{
putc(basis_64[c1>>2], outfile);
putc(basis_64[((c1 & 0x3)<< 4) | ((c2 & 0xF0) >> 4)], outfile);
if (pads == 2) {
putc('=', outfile);
putc('=', outfile);
} else if (pads) {
putc(basis_64[((c2 & 0xF) << 2) | ((c3 & 0xC0) >>6)], outfile);
putc('=', outfile);
} else {
putc(basis_64[((c2 & 0xF) << 2) | ((c3 & 0xC0) >>6)], outfile);
putc(basis_64[c3 & 0x3F], outfile);
}
}

View File

@ -1,746 +0,0 @@
/* max_rgb.c -- This is a plug-in for the GIMP (1.0's API)
* Author: Shuji Narazaki <narazaki@InetQ.or.jp>
* Time-stamp: <1997/06/08 22:34:38 narazaki@InetQ.or.jp>
* Version: 0.34
*
* Copyright (C) 1997 Shuji Narazaki <narazaki@InetQ.or.jp>
*
* 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
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "gtk/gtk.h"
#include "libgimp/gimp.h"
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* Replace them with the right ones */
#define PLUG_IN_NAME "plug_in_max_rgb"
#define SHORT_NAME "max_rgb"
#define PROGRESS_NAME "max_rgb(0.34): scanning..."
#define MENU_POSITION "<Image>/Filters/Image/Max RGB"
#define MAIN_FUNCTION max_rgb
/* you need not change the following names */
#define INTERFACE max_rgb_interface
#define DIALOG max_rgb_dialog
#define ERROR_DIALOG max_rgb_error_dialog
#define VALS max_rgb_vals
#define OK_CALLBACK _max_rgbok_callback
static void query (void);
static void run (char *name,
int nparams,
GParam *param,
int *nreturn_vals,
GParam **return_vals);
static GStatusType MAIN_FUNCTION (gint32 drawable_id);
static gint DIALOG ();
static void ERROR_DIALOG (gint gtk_was_not_initialized, guchar *message);
static void
OK_CALLBACK (GtkWidget *widget, gpointer data);
/* gtkWrapper functions */
#define PROGRESS_UPDATE_NUM 100
#define ENTRY_WIDTH 100
#define SCALE_WIDTH 100
static void
gtkW_gint_update (GtkWidget *widget, gpointer data);
static void
gtkW_scale_update (GtkAdjustment *adjustment, double *data);
static void
gtkW_close_callback (GtkWidget *widget, gpointer data);
static void
gtkW_toggle_update (GtkWidget *widget, gpointer data);
static GtkWidget *
gtkW_dialog_new (char *name,
GtkSignalFunc ok_callback,
GtkSignalFunc close_callback);
static GtkWidget *
gtkW_error_dialog_new (char * name);
static void
gtkW_table_add_toggle (GtkWidget *table,
gchar *name,
gint x1,
gint x2,
gint y,
GtkSignalFunc update,
gint *value);
static GSList *
gtkW_vbox_add_radio_button (GtkWidget *vbox,
gchar *name,
GSList *group,
GtkSignalFunc update,
gint *value);
static void
gtkW_table_add_gint (GtkWidget *table,
gchar *name,
gint x,
gint y,
GtkSignalFunc update,
gint *value,
gchar *buffer);
static void
gtkW_table_add_scale (GtkWidget *table,
gchar *name,
gint x1,
gint y,
GtkSignalFunc update,
gdouble *value,
gdouble min,
gdouble max,
gdouble step);
GtkWidget *gtkW_check_button_new (GtkWidget *parent,
gchar *name,
GtkSignalFunc update,
gint *value);
GtkWidget *gtkW_frame_new (GtkWidget *parent, gchar *name);
GtkWidget *gtkW_table_new (GtkWidget *parent, gint col, gint row);
GtkWidget *gtkW_hbox_new (GtkWidget *parent);
GtkWidget *gtkW_vbox_new (GtkWidget *parent);
GPlugInInfo PLUG_IN_INFO =
{
NULL, /* init_proc */
NULL, /* quit_proc */
query, /* query_proc */
run, /* run_proc */
};
typedef struct
{
gint max_p; /* gint, gdouble, and so on */
} ValueType;
static ValueType VALS =
{
1
};
typedef struct
{
gint run;
} Interface;
static Interface INTERFACE = { FALSE };
gint hold_max;
gint hold_min;
MAIN ()
static void
query ()
{
static GParamDef args [] =
{
{ PARAM_INT32, "run_mode", "Interactive, non-interactive"},
{ PARAM_IMAGE, "image", "Input image (not used)"},
{ PARAM_DRAWABLE, "drawable", "Input drawable"},
{ PARAM_INT32, "max_p", "1 for maximizing, 0 for minimizing"}
};
static GParamDef *return_vals = NULL;
static int nargs = sizeof (args) / sizeof (args[0]);
static int nreturn_vals = 0;
gimp_install_procedure (PLUG_IN_NAME,
"Return an image in which each pixel holds only the channel that has the maximum value in three (red, green, blue) channels, and other channels are zero-cleared",
"the help is not yet written for this plug-in",
"Shuji Narazaki (narazaki@InetQ.or.jp)",
"Shuji Narazaki",
"1997",
MENU_POSITION,
"RGB*",
PROC_PLUG_IN,
nargs, nreturn_vals,
args, return_vals);
}
static void
run (char *name,
int nparams,
GParam *param,
int *nreturn_vals,
GParam **return_vals)
{
static GParam values[1];
GStatusType status = STATUS_EXECUTION_ERROR;
GRunModeType run_mode;
gint drawable_id;
run_mode = param[0].data.d_int32;
drawable_id = param[2].data.d_int32;
*nreturn_vals = 1;
*return_vals = values;
values[0].type = PARAM_STATUS;
values[0].data.d_status = status;
switch (run_mode)
{
case RUN_INTERACTIVE:
gimp_get_data (PLUG_IN_NAME, &VALS);
hold_max = VALS.max_p;
hold_min = VALS.max_p ? 0 : 1;
/* Since a channel might be selected, we must check wheter RGB or not. */
if (!gimp_drawable_color(drawable_id))
{
ERROR_DIALOG (1, "RGB drawable is not selected.");
return;
}
if (! DIALOG ())
return;
break;
case RUN_NONINTERACTIVE:
/* You must copy the values of parameters to VALS or dialog variables. */
break;
case RUN_WITH_LAST_VALS:
gimp_get_data (PLUG_IN_NAME, &VALS);
break;
}
status = MAIN_FUNCTION (drawable_id);
if (run_mode != RUN_NONINTERACTIVE)
gimp_displays_flush();
if (run_mode == RUN_INTERACTIVE && status == STATUS_SUCCESS )
gimp_set_data (PLUG_IN_NAME, &VALS, sizeof (ValueType));
values[0].type = PARAM_STATUS;
values[0].data.d_status = status;
}
static GStatusType
MAIN_FUNCTION (gint32 drawable_id)
{
GDrawable *drawable;
GPixelRgn src_rgn, dest_rgn;
guchar *src, *dest;
gpointer pr;
gint x, y, x1, x2, y1, y2;
gint gap, total, processed = 0;
gint init_value, flag;
init_value = (VALS.max_p > 0) ? 0 : 255;
flag = (0 < VALS.max_p) ? 1 : -1;
drawable = gimp_drawable_get (drawable_id);
gap = (gimp_drawable_has_alpha (drawable_id)) ? 1 : 0;
gimp_drawable_mask_bounds (drawable_id, &x1, &y1, &x2, &y2);
total = (x2 - x1) * (y2 - y1);
gimp_tile_cache_ntiles (2 * (drawable->width / gimp_tile_width () + 1));
gimp_pixel_rgn_init (&src_rgn, drawable, x1, y1, (x2 - x1), (y2 - y1), FALSE, FALSE);
gimp_pixel_rgn_init (&dest_rgn, drawable, x1, y1, (x2 - x1), (y2 - y1), TRUE, TRUE);
pr = gimp_pixel_rgns_register (2, &src_rgn, &dest_rgn);
gimp_progress_init (PROGRESS_NAME);
for (; pr != NULL; pr = gimp_pixel_rgns_process (pr))
{
for (y = 0; y < src_rgn.h; y++)
{
src = src_rgn.data + y * src_rgn.rowstride;
dest = dest_rgn.data + y * dest_rgn.rowstride;
for (x = 0; x < src_rgn.w; x++)
{
gint ch, max_ch = 0;
guchar max, tmp_value;
max = init_value;
for (ch = 0; ch < 3; ch++)
if (flag * max <= flag * (tmp_value = (*src++)))
if (max == tmp_value)
max_ch += 1 << ch;
else
{
max_ch = 1 << ch; /* clear memories of old channels */
max = tmp_value;
}
for ( ch = 0; ch < 3; ch++)
*dest++ = (guchar)(((max_ch & (1 << ch)) > 0) ? max : 0);
if (gap) *dest++=*src++;
if ((++processed % (total / PROGRESS_UPDATE_NUM)) == 0)
gimp_progress_update ((double)processed /(double) total);
}
}
}
gimp_progress_update (1.0);
gimp_drawable_flush (drawable);
gimp_drawable_merge_shadow (drawable->id, TRUE);
gimp_drawable_update (drawable->id, x1, y1, (x2 - x1), (y2 - y1));
gimp_drawable_detach (drawable);
return STATUS_SUCCESS;
}
/* dialog stuff */
static int
DIALOG ()
{
GtkWidget *dlg;
GtkWidget *hbox;
GtkWidget *vbox;
GtkWidget *frame;
GtkWidget *table;
GSList *group = NULL;
gchar **argv;
gint argc;
argc = 1;
argv = g_new (gchar *, 1);
argv[0] = g_strdup (PLUG_IN_NAME);
gtk_init (&argc, &argv);
gtk_rc_parse (gimp_gtkrc ());
dlg = gtkW_dialog_new (PLUG_IN_NAME,
(GtkSignalFunc) OK_CALLBACK,
(GtkSignalFunc) gtkW_close_callback);
hbox = gtkW_hbox_new ((GTK_DIALOG (dlg)->vbox));
frame = gtkW_frame_new (hbox, "Parameter Settings");
/*
table = gtkW_table_new (frame, 2, 2);
gtkW_table_add_toggle (table, "Hold the maximal channel", 0, 2, 1,
(GtkSignalFunc) gtkW_toggle_update, &VALS.max_p);
gtk_widget_show (table);
*/
vbox = gtkW_vbox_new (frame);
group = gtkW_vbox_add_radio_button (vbox, "Hold the maximal channels", group,
(GtkSignalFunc) gtkW_toggle_update,
&hold_max);
group = gtkW_vbox_add_radio_button (vbox, "Hold the minimal channels", group,
(GtkSignalFunc) gtkW_toggle_update,
&hold_min);
gtk_main ();
gdk_flush ();
return INTERFACE.run;
}
static void
ERROR_DIALOG (gint gtk_was_not_initialized, guchar *message)
{
GtkWidget *dlg;
GtkWidget *table;
GtkWidget *label;
gchar **argv;
gint argc;
if (gtk_was_not_initialized)
{
argc = 1;
argv = g_new (gchar *, 1);
argv[0] = g_strdup (PLUG_IN_NAME);
gtk_init (&argc, &argv);
gtk_rc_parse (gimp_gtkrc ());
}
dlg = gtkW_error_dialog_new (PLUG_IN_NAME);
table = gtk_table_new (1,1, FALSE);
gtk_container_border_width (GTK_CONTAINER (table), 10);
gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dlg)->vbox), table, TRUE, TRUE, 0);
label = gtk_label_new (message);
gtk_table_attach (GTK_TABLE (table), label, 0, 1, 0, 1, GTK_FILL|GTK_EXPAND,
0, 0, 0);
gtk_widget_show (label);
gtk_widget_show (table);
gtk_widget_show (dlg);
gtk_main ();
gdk_flush ();
}
static void
OK_CALLBACK (GtkWidget *widget,
gpointer data)
{
VALS.max_p = hold_max;
INTERFACE.run = TRUE;
gtk_widget_destroy (GTK_WIDGET (data));
}
/* VFtext interface functions */
static void
gtkW_gint_update (GtkWidget *widget,
gpointer data)
{
*(gint *)data = (gint)atof (gtk_entry_get_text (GTK_ENTRY (widget)));
}
static void
gtkW_scale_update (GtkAdjustment *adjustment,
gdouble *scale_val)
{
*scale_val = (gdouble) adjustment->value;
}
static void
gtkW_close_callback (GtkWidget *widget,
gpointer data)
{
gtk_main_quit ();
}
static void
gtkW_toggle_update (GtkWidget *widget,
gpointer data)
{
int *toggle_val;
toggle_val = (int *) data;
if (GTK_TOGGLE_BUTTON (widget)->active)
*toggle_val = TRUE;
else
*toggle_val = FALSE;
}
/* gtkW is the abbreviation of gtk Wrapper */
static GtkWidget *
gtkW_dialog_new (char * name,
GtkSignalFunc ok_callback,
GtkSignalFunc close_callback)
{
GtkWidget *dlg, *button;
dlg = gtk_dialog_new ();
gtk_window_set_title (GTK_WINDOW (dlg), name);
gtk_window_position (GTK_WINDOW (dlg), GTK_WIN_POS_MOUSE);
gtk_signal_connect (GTK_OBJECT (dlg), "destroy",
(GtkSignalFunc) gtkW_close_callback, NULL);
/* Action Area */
button = gtk_button_new_with_label ("OK");
GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
gtk_signal_connect (GTK_OBJECT (button), "clicked",
(GtkSignalFunc) ok_callback, dlg);
gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dlg)->action_area), button,
TRUE, TRUE, 0);
gtk_widget_grab_default (button);
gtk_widget_show (button);
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));
gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dlg)->action_area), button,
TRUE, TRUE, 0);
gtk_widget_show (button);
gtk_widget_show (dlg);
return dlg;
}
static GtkWidget *
gtkW_error_dialog_new (char * name)
{
GtkWidget *dlg, *button;
dlg = gtk_dialog_new ();
gtk_window_set_title (GTK_WINDOW (dlg), name);
gtk_window_position (GTK_WINDOW (dlg), GTK_WIN_POS_MOUSE);
gtk_signal_connect (GTK_OBJECT (dlg), "destroy",
(GtkSignalFunc) gtkW_close_callback, NULL);
/* Action Area */
button = gtk_button_new_with_label ("OK");
GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
gtk_signal_connect (GTK_OBJECT (button), "clicked",
(GtkSignalFunc) gtkW_close_callback, dlg);
gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dlg)->action_area), button,
TRUE, TRUE, 0);
gtk_widget_grab_default (button);
gtk_widget_show (button);
return dlg;
}
GtkWidget *
gtkW_table_new (GtkWidget *parent, gint col, gint row)
{
GtkWidget *table;
table = gtk_table_new (col,row, FALSE);
gtk_container_border_width (GTK_CONTAINER (table), 10);
gtk_container_add (GTK_CONTAINER (parent), table);
return table;
}
GtkWidget *
gtkW_hbox_new (GtkWidget *parent)
{
GtkWidget *hbox;
hbox = gtk_hbox_new (FALSE, 5);
gtk_container_border_width (GTK_CONTAINER (hbox), 5);
gtk_box_pack_start (GTK_BOX (parent), hbox, FALSE, TRUE, 0);
gtk_widget_show (hbox);
return hbox;
}
GtkWidget *
gtkW_vbox_new (GtkWidget *parent)
{
GtkWidget *vbox;
vbox = gtk_vbox_new (FALSE, 5);
gtk_container_border_width (GTK_CONTAINER (vbox), 10);
/* gtk_box_pack_start (GTK_BOX (parent), vbox, TRUE, TRUE, 0); */
gtk_container_add (GTK_CONTAINER (parent), vbox);
gtk_widget_show (vbox);
return vbox;
}
GtkWidget *
gtkW_check_button_new (GtkWidget *parent,
gchar *name,
GtkSignalFunc update,
gint *value)
{
GtkWidget *toggle;
toggle = gtk_check_button_new_with_label (name);
gtk_signal_connect (GTK_OBJECT (toggle), "toggled",
(GtkSignalFunc) update,
value);
gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (toggle), *value);
gtk_container_add (GTK_CONTAINER (parent), toggle);
gtk_widget_show (toggle);
return toggle;
}
GtkWidget *
gtkW_frame_new (GtkWidget *parent,
gchar *name)
{
GtkWidget *frame;
frame = gtk_frame_new (name);
gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_IN);
gtk_container_border_width (GTK_CONTAINER (frame), 5);
gtk_box_pack_start (GTK_BOX(parent), frame, FALSE, FALSE, 0);
gtk_widget_show (frame);
return frame;
}
static void
gtkW_table_add_toggle (GtkWidget *table,
gchar *name,
gint x1,
gint x2,
gint y,
GtkSignalFunc update,
gint *value)
{
GtkWidget *toggle;
toggle = gtk_check_button_new_with_label(name);
gtk_table_attach (GTK_TABLE (table), toggle, x1, x2, y, y+1,
GTK_FILL|GTK_EXPAND, 0, 0, 0);
gtk_signal_connect (GTK_OBJECT (toggle), "toggled",
(GtkSignalFunc) update,
value);
gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (toggle), *value);
gtk_widget_show (toggle);
}
static GSList *
gtkW_vbox_add_radio_button (GtkWidget *vbox,
gchar *name,
GSList *group,
GtkSignalFunc update,
gint *value)
{
GtkWidget *toggle;
toggle = gtk_radio_button_new_with_label(group, name);
group = gtk_radio_button_group (GTK_RADIO_BUTTON (toggle));
gtk_box_pack_start (GTK_BOX (vbox), toggle, FALSE, FALSE, 0);
gtk_signal_connect (GTK_OBJECT (toggle), "toggled",
(GtkSignalFunc) update, value);
gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (toggle), *value);
gtk_widget_show (toggle);
return group;
}
static void
gtkW_table_add_gint (GtkWidget *table,
gchar *name,
gint x,
gint y,
GtkSignalFunc update,
gint *value,
gchar *buffer)
{
GtkWidget *label, *entry;
label = gtk_label_new (name);
gtk_misc_set_alignment (GTK_MISC(label), 0.0, 0.5);
gtk_table_attach (GTK_TABLE(table), label, x, x+1, y, y+1,
GTK_FILL|GTK_EXPAND, GTK_FILL, 5, 0);
gtk_widget_show(label);
entry = gtk_entry_new();
gtk_table_attach (GTK_TABLE(table), entry, x+1, x+2, y, y+1,
GTK_FILL|GTK_EXPAND, GTK_FILL, 10, 0);
gtk_widget_set_usize (entry, ENTRY_WIDTH, 0);
sprintf (buffer, "%d", *(gint *)value);
gtk_entry_set_text (GTK_ENTRY (entry), buffer);
gtk_signal_connect (GTK_OBJECT (entry), "changed",
(GtkSignalFunc) update, value);
gtk_widget_show(entry);
}
static void
gtkW_table_add_scale (GtkWidget *table,
gchar *name,
gint x,
gint y,
GtkSignalFunc update,
gdouble *value,
gdouble min,
gdouble max,
gdouble step)
{
GtkObject *scale_data;
GtkWidget *label, *scale;
label = gtk_label_new (name);
gtk_misc_set_alignment (GTK_MISC(label), 0.0, 0.5);
gtk_table_attach (GTK_TABLE(table), label, x, x+1, y, y+1,
GTK_FILL|GTK_EXPAND, GTK_FILL, 5, 0);
gtk_widget_show (label);
scale_data = gtk_adjustment_new (*value, min, max, step, step, 0.0);
scale = gtk_hscale_new (GTK_ADJUSTMENT (scale_data));
gtk_widget_set_usize (scale, SCALE_WIDTH, 0);
gtk_table_attach (GTK_TABLE (table), scale, x+1, x+2, y, y+1,
GTK_FILL|GTK_EXPAND, GTK_FILL, 10, 5);
gtk_scale_set_value_pos (GTK_SCALE (scale), GTK_POS_TOP);
gtk_scale_set_digits (GTK_SCALE (scale), 2);
gtk_range_set_update_policy (GTK_RANGE (scale), GTK_UPDATE_DELAYED);
gtk_signal_connect (GTK_OBJECT (scale_data), "value_changed",
(GtkSignalFunc) update, value);
gtk_widget_show (label);
gtk_widget_show (scale);
}
static void
gtkW_table_add_scale_entry (GtkWidget *table,
gchar *name,
gint x,
gint y,
GtkSignalFunc scale_update,
GtkSignalFunc entry_update,
gint *value,
gdouble min,
gdouble max,
gdouble step,
gchar *buffer)
{
GtkObject *adjustment;
GtkWidget *label, *hbox, *scale, *entry;
label = gtk_label_new (name);
gtk_misc_set_alignment (GTK_MISC(label), 0.0, 0.5);
gtk_table_attach (GTK_TABLE(table), label, x, x+1, y, y+1,
GTK_FILL|GTK_EXPAND, GTK_FILL, 5, 0);
gtk_widget_show (label);
hbox = gtk_hbox_new (FALSE, 5);
gtk_table_attach (GTK_TABLE (table), hbox, x+1, x+2, y, y+1,
GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
adjustment = gtk_adjustment_new (*value, min, max, step, step, 0.0);
gtk_widget_show (hbox);
scale = gtk_hscale_new (GTK_ADJUSTMENT (adjustment));
gtk_widget_set_usize (scale, SCALE_WIDTH, 0);
gtk_box_pack_start (GTK_BOX (hbox), scale, TRUE, TRUE, 0);
gtk_scale_set_value_pos (GTK_SCALE (scale), GTK_POS_TOP);
gtk_scale_set_digits (GTK_SCALE (scale), 0);
gtk_range_set_update_policy (GTK_RANGE (scale), GTK_UPDATE_DELAYED);
gtk_signal_connect (GTK_OBJECT (adjustment), "value_changed",
(GtkSignalFunc) scale_update, value);
entry = gtk_entry_new ();
gtk_object_set_user_data (GTK_OBJECT (entry), adjustment);
gtk_object_set_user_data (adjustment, entry);
gtk_box_pack_start (GTK_BOX (hbox), entry, TRUE, TRUE, 0);
gtk_widget_set_usize (entry, ENTRY_WIDTH/3, 0);
sprintf (buffer, "%d", *value);
gtk_entry_set_text (GTK_ENTRY (entry), buffer);
gtk_signal_connect (GTK_OBJECT (entry), "changed",
(GtkSignalFunc) entry_update, value);
gtk_widget_show (label);
gtk_widget_show (scale);
gtk_widget_show (entry);
}
static void
gtkW_iscale_update (GtkAdjustment *adjustment,
gpointer data)
{
GtkWidget *entry;
gchar buffer[32];
int *val;
val = data;
if (*val != (int) adjustment->value)
{
*val = adjustment->value;
entry = gtk_object_get_user_data (GTK_OBJECT (adjustment));
sprintf (buffer, "%d", (int) adjustment->value);
gtk_entry_set_text (GTK_ENTRY (entry), buffer);
}
}
static void
gtkW_ientry_update (GtkWidget *widget,
gpointer data)
{
GtkAdjustment *adjustment;
int new_val;
int *val;
val = data;
new_val = atoi (gtk_entry_get_text (GTK_ENTRY (widget)));
if (*val != new_val)
{
adjustment = gtk_object_get_user_data (GTK_OBJECT (widget));
if ((new_val >= adjustment->lower) &&
(new_val <= adjustment->upper))
{
*val = new_val;
adjustment->value = new_val;
gtk_signal_emit_by_name (GTK_OBJECT (adjustment), "value_changed");
}
}
}
/* end of .c */

View File

@ -1,951 +0,0 @@
/* maze.c, version 0.4.2, 17 October 1997
* This is a plug-in for the GIMP.
* It draws mazes... walls and passages are 1 pixel wide.
*
* Implemented as a GIMP 0.99 Plugin by
* Kevin Turner <kevint@poboxes.com>
* http://www.poboxes.com/kevint/gimp/maze.html
*
* mazegen code from rec.games.programmer's maze-faq:
* * maz.c - generate a maze
* *
* * algorithm posted to rec.games.programmer by jallen@ic.sunysb.edu
* * program cleaned and reorganized by mzraly@ldbvax.dnet.lotus.com
* *
* * don't make people pay for this, or I'll jump up and down and
* * yell and scream and embarass you in front of your friends...
*
* Code generously borrowed from assorted GIMP plugins
* and used as a template to get me started on this one. :)
*
* Revision history:
* 0.4.2 - Applied Adrian Likins' patch to fix non-interactive stuff.
* - -ansi and -pedantic-errors clean. Woo-hoo?
* 0.4.1 - get_colors() now works properly for grayscale images.
* I'd still like it to do indexed too, but I don't know
* if that's worth breaking a sweat over.
* - We're -Wall clean now. Woohoo!
* 0.4.0 - Code for the painting of the maze has been almost completely rebuilt.
* Hopefully it's a more sane and speedier approach.
* Utilizes a new function, drawbox, which colors a solid rectangle.
* (Good excercise, in any case.)
* - Order of paramaters changed, defaults are used if not given.
* - Discovery made that that was an utterly useless thing to do.
* 0.3.0 - Maze is centered with dead space around outside
* - Width slider works... And does stuff!
* - Allows partial mazes to be generated with "broken" multiple
* and offset values.
* 0.1.99 - Has dialog box with seed, multiple, and offset.
* 0.1.0 - First release. It works! :)
*
* TO DO:
* Add an option to kill the outer border.
*
* Fix that stray line down there between maze wall and dead space border...
*
* Make get_colors() work with indexed. * HELP! *
*
* Tileable mazes are fun :)
*
* If we add many more paramaters, we'll need a preview box.
*
* Also someday:
* Maybe make it work with irregularly shaped selections?
* Add different generation algorythms.
*
*/
/*
* 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
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
#include <time.h> /* For random seeding */
#include <stdio.h>
#include <stdlib.h>
#include "gtk/gtk.h"
#include "libgimp/gimp.h"
#include "libgimp/gimpui.h"
#define ENTRY_WIDTH 75
#define MAZE_TITLE "Maze 0.4.2"
/* entscale stuff begin */
#define ENTSCALE_INT_SCALE_WIDTH 125
#define ENTSCALE_INT_ENTRY_WIDTH 40
/* entscale stuff end */
typedef struct {
gint width;
gint seed;
gint multiple;
gint offset;
} MazeValues;
typedef struct {
gint run;
} MazeInterface;
/* entscale stuff begin */
typedef void (*EntscaleIntCallbackFunc) (gint value, gpointer data);
typedef struct {
GtkObject *adjustment;
GtkWidget *entry;
gint constraint;
EntscaleIntCallbackFunc callback;
gpointer call_data;
} EntscaleIntData;
/* entscale stuff end */
static void query (void);
static void run (gchar *name,
gint nparams,
GParam *param,
gint *nreturn_vals,
GParam **return_vals);
static void maze (GDrawable * drawable);
static gint mazegen(gint pos,
gchar *maz,
gint x,
gint y,
gint rnd);
static void get_colors (GDrawable * drawable,
guint8 *fg,
guint8 *bg);
static void drawbox (GPixelRgn *dest_rgn,
guint x,
guint y,
guint w,
guint h,
guint8 clr[4]);
static gint maze_dialog (void);
static void maze_close_callback (GtkWidget *widget, gpointer data);
static void maze_ok_callback (GtkWidget *widget, gpointer data);
static void maze_entry_callback (GtkWidget *widget, gpointer data);
/* entscale stuff begin */
void entscale_int_new ( GtkWidget *table, gint x, gint y,
gchar *caption, gint *intvar,
gint min, gint max, gint constraint,
EntscaleIntCallbackFunc callback,
gpointer data );
static void entscale_int_destroy_callback (GtkWidget *widget,
gpointer data);
static void entscale_int_scale_update (GtkAdjustment *adjustment,
gpointer data);
static void entscale_int_entry_update (GtkWidget *widget,
gpointer data);
/* entscale stuff end */
/* message box stuff begin */
GtkWidget * message_box (char *, GtkCallback, gpointer);
/* message box stuff end */
GPlugInInfo PLUG_IN_INFO =
{
NULL, /* init_proc */
NULL, /* quit_proc */
query, /* query_proc */
run, /* run_proc */
};
static MazeValues mvals =
{
1, /* Passage width */
0, /* seed */
57, /* multiple * These two had "Experiment with this?" comments */
1 /* offset * in the maz.c source, so, lets expiriment. :) */
};
static MazeInterface mint =
{
FALSE /* run */
};
MAIN () /*;*/
static void
query ()
{
static GParamDef args[] =
{
{ PARAM_INT32, "run_mode", "Interactive, non-interactive" },
{ PARAM_IMAGE, "image", "Input image (unused)" },
{ PARAM_DRAWABLE, "drawable", "Input drawable" },
/* If we did have parameters, these be them: */
{ PARAM_INT32, "mazep_size", "Size of the passages" },
{ PARAM_INT32, "maze_rseed", "Random Seed"},
{ PARAM_INT32, "maze_multiple", "Multiple (use 57)" },
{ PARAM_INT32, "maze_offset", "Offset (use 1)" }
};
static GParamDef *return_vals = NULL;
static int nargs = sizeof (args) / sizeof (args[0]);
static int nreturn_vals = 0;
gimp_install_procedure ("plug_in_maze",
"Generates a maze.",
"Generates a maze using the depth-first search method.",
"Kevin Turner <kevint@poboxes.com>",
"Kevin Turner",
"1997",
"<Image>/Filters/Render/Maze",
"RGB*, GRAY*, INDEXED*",
PROC_PLUG_IN,
nargs, nreturn_vals,
args, return_vals);
}
static void
run (gchar *name,
gint nparams,
GParam *param,
gint *nreturn_vals,
GParam **return_vals)
{
static GParam values[1];
GDrawable *drawable;
GRunModeType run_mode;
GStatusType status = STATUS_SUCCESS;
run_mode = param[0].data.d_int32;
*nreturn_vals = 1;
*return_vals = values;
values[0].type = PARAM_STATUS;
values[0].data.d_status = status;
drawable = gimp_drawable_get (param[2].data.d_drawable);
#ifdef MAZE_DEBUG
fprintf(stderr, "%d", param[2].data.d_drawable);
#endif
switch (run_mode)
{
case RUN_INTERACTIVE:
/* Possibly retrieve data */
gimp_get_data ("plug_in_maze", &mvals);
/* Acquire info with a dialog */
if (! maze_dialog ()) {
gimp_drawable_detach (drawable);
return;
}
break;
case RUN_NONINTERACTIVE:
/* WARNING: Stupidity Follows */
if (nparams != 7)
{
status = STATUS_CALLING_ERROR;
}
if (status == STATUS_SUCCESS)
{
mvals.width = (gint) param[3].data.d_int32;
mvals.seed = (gint) param[4].data.d_int32;
mvals.multiple = (gint) param[5].data.d_int32;
mvals.offset = (gint) param[6].data.d_int32;
}
break;
/* #define MAZE_DEBUG */
#ifdef MAZE_DEBUG
fprintf(stderr,"nparams: %d width: %d seed: %d multiple: %d offset: %d\n",
nparams, mvals.width, mvals.seed, mvals.multiple, mvals.offset);
#endif
case RUN_WITH_LAST_VALS:
/* Possibly retrieve data */
gimp_get_data ("plug_in_maze", &mvals);
mvals.seed=time(NULL); /* ** USES NEW SEED when reruning with "last" */
/* values. Maybe not the Right Thing, but I find it handy. */
break;
default:
break;
}
/* color, gray, or indexed... hmm, miss anything? ;) */
if (gimp_drawable_color (drawable->id) || gimp_drawable_gray (drawable->id) || gimp_drawable_indexed (drawable->id)) {
gimp_progress_init ("Drawing Maze...");
maze (drawable);
if (run_mode != RUN_NONINTERACTIVE)
gimp_displays_flush ();
if (run_mode == RUN_INTERACTIVE /*|| run_mode == RUN_WITH_LAST_VALS*/)
gimp_set_data ("plug_in_maze", &mvals, sizeof (MazeValues));
} else {
status = STATUS_EXECUTION_ERROR;
}
values[0].data.d_status = status;
gimp_drawable_detach (drawable);
}
static void
maze( GDrawable * drawable)
{
GPixelRgn dest_rgn;
gint mw, mh;
gint deadx, deady;
gint progress, max_progress;
gint x1, y1, x2, y2, x, y;
gint dx, dy, xx, yy;
gint foo, bar, baz;
guint8 fg[4],bg[4];
gpointer pr;
gchar *maz;
gint i;
/* Gets the input area... */
gimp_drawable_mask_bounds (drawable->id, &x1, &y1, &x2, &y2);
/* Initialize pixel region (?) */
gimp_pixel_rgn_init (&dest_rgn, drawable, x1, y1, (x2 - x1), (y2 - y1), TRUE, TRUE);
progress = 0;
max_progress = (x2 - x1) * (y2 - y1);
/* Get the foreground and background colors */
get_colors(drawable,fg,bg);
/* Maze Stuff Happens Here */
mw = (x2-x1) / mvals.width;
mh = (y2-y1) / mvals.width;
mw -= !(mw & 1); /* mazegen doesn't work with even-sized mazes. */
mh -= !(mh & 1); /* Note I don't warn the user about this... */
deadx = ((x2-x1) - mw * mvals.width)/2;
deady = ((y2-y1) - mh * mvals.width)/2;
maz = g_malloc(mw * mh);
for (i = 0; i < (mw * mh); ++i)
maz[i] = 0;
#ifdef MAZE_DEBUG
printf("x: %d\ty: %d\nmw: %d\tmh: %d\ndx: %d\tdy: %d\nwidth:%d\n",
(x2-x1),(y2-y1),mw,mh,deadx,deady,mvals.width);
#endif
(void) mazegen((mw+1), maz, mw, mh, mvals.seed);
/* (void) mazegen(((x2-x1)+1), maz, (x2-x1), (y2-y1), rnd); */
/* It's done happening. Now go through and color dem pixels... */
for (pr = gimp_pixel_rgns_register (1, &dest_rgn);
pr != NULL;
pr = gimp_pixel_rgns_process (pr))
{
x = dest_rgn.x - x1 - deadx;
y = dest_rgn.y - y1 - deady;
/* First boxes by edge of tile must be handled specially
because they may have started on a previous tile,
unbeknownst to us. */
dx = mvals.width - (x % mvals.width);
dy = mvals.width - (y % mvals.width);
foo = x/mvals.width;
bar = mw * (y/mvals.width);
/* Draws the upper-left [split] box */
drawbox(&dest_rgn,0,0,dx,dy,
maz[foo+bar] ? fg : bg);
baz=foo+1;
/* Draw the top row [split] boxes */
for(xx=dx/*1*/; xx < dest_rgn.w; xx+=mvals.width/*+1*/)
{ drawbox(&dest_rgn,xx,0,mvals.width,dy,
maz[bar + baz++] ? fg : bg ); }
baz=bar+mw;
/* Left column */
for(yy=dy/*+1*/; yy < dest_rgn.h; yy+=mvals.width/*+1*/) {
drawbox(&dest_rgn,0,yy,dx,mvals.width,
maz[foo + baz] ? fg : bg );
baz += mw;
}
foo++;
/* Everything else */
for(yy=dy/*+1*/; yy < dest_rgn.h; yy+=mvals.width/*+1*/) {
baz = foo; bar+=mw;
for(xx=dx/*+1*/; xx < dest_rgn.w; xx+=mvals.width/*+1*/)
{
#ifdef MAZE_DEBUG
putchar(maz[bar+baz] ? '#' : '.');
#endif
drawbox(&dest_rgn,xx,yy,mvals.width,mvals.width,
maz[bar + baz++] ? fg : bg ); }
#ifdef MAZE_DEBUG
putchar('\n');
#endif
}
progress += dest_rgn.w * dest_rgn.h;
gimp_progress_update ((double) progress / (double) max_progress);
/* Note the progess indicator doesn't indicate how much of the maze
has been built... It just indicates how much has been drawn
*after* building... Thing is, that's what takes longer. */
}
gimp_drawable_flush (drawable);
gimp_drawable_merge_shadow (drawable->id, TRUE);
gimp_drawable_update (drawable->id, x1, y1, (x2 - x1), (y2 - y1));
}
void drawbox( GPixelRgn *dest_rgn,
guint x, guint y, guint w, guint h,
guint8 clr[4])
{
guint xx,yy, foo, bar;
guint8 bp;
/* This looks ugly, but it's just finding the lower number... */
foo = dest_rgn->h * dest_rgn->rowstride
< y * dest_rgn->rowstride + h * dest_rgn->rowstride
? dest_rgn->h * dest_rgn->rowstride
: y * dest_rgn->rowstride + h * dest_rgn->rowstride;
bar = dest_rgn->w * dest_rgn->bpp
< x * dest_rgn->bpp + w * dest_rgn->bpp
? dest_rgn->w * dest_rgn->bpp
: x * dest_rgn->bpp + w * dest_rgn->bpp;
for (yy = dest_rgn->rowstride * y;
yy < foo;
yy += dest_rgn->rowstride ) {
for (xx= x * dest_rgn->bpp;
xx < bar;
xx+= dest_rgn->bpp) {
for (bp=0; bp < dest_rgn->bpp; bp++) {
dest_rgn->data[yy+xx+bp]=clr[bp];
} /* next bp */
} /* next xx */
} /* next yy */
}
/* The Incredible Recursive Maze Generation Routine */
/* Ripped from rec.programmers.games maze-faq */
/* Modified and commented by me, Kevin Turner. */
gint mazegen(pos, maz, x, y, rnd)
gint pos, x, y, rnd;
gchar *maz;
{
gchar d, i;
gint c=0, j=1;
/* Punch a hole here... */
maz[pos] = 1;
/* If there is a wall two rows above us, bit 1 is 1. */
while((d= (pos <= (x * 2) ? 0 : (maz[pos - x - x ] ? 0 : 1))
/* If there is a wall two rows below us, bit 2 is 1. */
| (pos >= x * (y - 2) ? 0 : (maz[pos + x + x] ? 0 : 2))
/* If there is a wall two columns to the right, bit 3 is 1. */
| (pos % x == x - 2 ? 0 : (maz[pos + 2] ? 0 : 4))
/* If there is a wall two colums to the left, bit 4 is 1. */
| ((pos % x == 1 ) ? 0 : (maz[pos-2] ? 0 : 8)))) {
/* Note if all bits are 0, d is false, we don't do this
while loop, we don't call ourselves again, so this branch
is done. */
/* I see what this loop does (more or less), but I don't know
_why_ it does it this way... I also haven't figured out exactly
which values of multiple will work and which won't. */
do {
rnd = (rnd * mvals.multiple + mvals.offset);
i = 3 & (rnd / d);
if (++c > 100) { /* Break and try to salvage something */
i=99; /* if it looks like we're going to be */
break; /* here forever... */
}
} while ( !(d & ( 1 << i) ) );
/* ...While there's *not* a wall in direction i. */
/* (stop looping when there is) */
switch (i) { /* This is simple enough. */
case 0: /* Go in the direction we just figured . . . */
j= -x;
break;
case 1:
j = x;
break;
case 2:
j=1;
break;
case 3:
j= -1;
break;
case 99:
return 1; /* Hey neat, broken mazes! */
break; /* (Umm... Wow... Yeah, neat.) */
default:
break;
}
/* And punch a hole there. */
maz[pos + j] = 1;
/* Now, start again just past where we punched the hole... */
mazegen(pos + 2 * j, maz, x, y, rnd);
} /* End while(d=...) Loop */
return 0;
}
static void
get_colors (GDrawable *drawable, guint8 *fg, guint8 *bg)
{
GParam *return_vals;
gint nreturn_vals;
switch ( gimp_drawable_type (drawable->id) )
{
case RGBA_IMAGE: /* ASSUMPTION: Assuming the user wants entire */
fg[3] = 255; /* area to be fully opaque. */
bg[3] = 255;
case RGB_IMAGE:
return_vals = gimp_run_procedure ("gimp_palette_get_foreground",
&nreturn_vals,
PARAM_END);
if (return_vals[0].data.d_status == STATUS_SUCCESS)
{
fg[0] = return_vals[1].data.d_color.red;
fg[1] = return_vals[1].data.d_color.green;
fg[2] = return_vals[1].data.d_color.blue;
}
else
{
fg[0] = 255;
fg[1] = 255;
fg[2] = 255;
}
return_vals = gimp_run_procedure ("gimp_palette_get_background",
&nreturn_vals,
PARAM_END);
if (return_vals[0].data.d_status == STATUS_SUCCESS)
{
bg[0] = return_vals[1].data.d_color.red;
bg[1] = return_vals[1].data.d_color.green;
bg[2] = return_vals[1].data.d_color.blue;
}
else
{
bg[0] = 0;
bg[1] = 0;
bg[2] = 0;
}
break;
case GRAYA_IMAGE: /* and again */
fg[1] = 255;
bg[1] = 255;
case GRAY_IMAGE:
return_vals = gimp_run_procedure ("gimp_palette_get_foreground",
&nreturn_vals,
PARAM_END);
if (return_vals[0].data.d_status == STATUS_SUCCESS)
{
fg[0] = 0.30 * return_vals[1].data.d_color.red +
0.59 * return_vals[1].data.d_color.green +
0.11 * return_vals[1].data.d_color.blue;
}
else
{
fg[0] = 255;
}
return_vals = gimp_run_procedure ("gimp_palette_get_background",
&nreturn_vals,
PARAM_END);
if (return_vals[0].data.d_status == STATUS_SUCCESS)
{
bg[0] = 0.30 * return_vals[1].data.d_color.red +
0.59 * return_vals[1].data.d_color.green +
0.11 * return_vals[1].data.d_color.blue;
}
else
{
bg[0] = 0;
}
break;
case INDEXEDA_IMAGE:
case INDEXED_IMAGE: /* FIXME: Should use current fg/bg colors. */
fputs("Maze: Using indexed colors 15 and 0 to draw maze.",stderr);
fg[0] = 15; /* As a plugin, I protest. *I* shouldn't be the */
bg[0] = 0; /* one who has to deal with this colormapcrap. */
break;
default:
break;
}
}
static gint maze_dialog()
{
GtkWidget *dlg;
GtkWidget *frame;
GtkWidget *table;
GtkWidget *button;
GtkWidget *label;
GtkWidget *entry;
GtkWidget *notebook;
gchar **argv;
gint argc;
gchar buffer[32];
argc = 1;
argv = g_new (gchar *, 1);
argv[0] = g_strdup ("maze");
gtk_init (&argc, &argv);
dlg = gtk_dialog_new ();
gtk_window_set_title (GTK_WINDOW (dlg), MAZE_TITLE);
gtk_window_position (GTK_WINDOW (dlg), GTK_WIN_POS_MOUSE);
gtk_signal_connect (GTK_OBJECT (dlg), "destroy",
(GtkSignalFunc) maze_close_callback,
NULL);
/* Action area */
button = gtk_button_new_with_label ("OK");
GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
gtk_signal_connect (GTK_OBJECT (button), "clicked",
(GtkSignalFunc) maze_ok_callback,
dlg);
gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dlg)->action_area), button, TRUE, TRUE, 0);
gtk_widget_grab_default (button);
gtk_widget_show (button);
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));
gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dlg)->action_area), button, TRUE, TRUE, 0);
gtk_widget_show (button);
/* Create notebook */
notebook = gtk_notebook_new ();
gtk_notebook_set_tab_pos (GTK_NOTEBOOK (notebook), GTK_POS_TOP);
gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dlg)->vbox), notebook, TRUE, TRUE, 0);
gtk_widget_show (notebook);
/* Set up Options page */
frame = gtk_frame_new ("Maze Options");
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 (2, 2, FALSE);
gtk_container_border_width (GTK_CONTAINER (table), 10);
gtk_container_add (GTK_CONTAINER (frame), table);
/* Seed input box */
label = gtk_label_new ("Seed");
gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
gtk_table_attach (GTK_TABLE (table), label, 0, 1, 0, 1, GTK_FILL, 0, 5, 0 );
gtk_widget_show (label);
entry = gtk_entry_new ();
gtk_table_attach (GTK_TABLE (table), entry, 1, 2, 0, 1, GTK_FILL, GTK_FILL, 0, 0 );
gtk_widget_set_usize( entry, ENTRY_WIDTH, 0 );
sprintf( buffer, "%d", mvals.seed );
gtk_entry_set_text (GTK_ENTRY (entry), buffer );
gtk_signal_connect (GTK_OBJECT (entry), "changed",
(GtkSignalFunc) maze_entry_callback,
&mvals.seed);
gtk_widget_show (entry);
/* entscale == Entry and Scale pair function found in pixelize.c */
entscale_int_new (table, 0, 1, "Width:", &mvals.width,
1, 64, FALSE,
NULL, NULL);
/* Add Options page to notebook */
gtk_widget_show (frame);
gtk_widget_show (table);
gtk_notebook_append_page (GTK_NOTEBOOK (notebook), frame,
gtk_label_new ("Options"));
/* Set up other page */
frame = gtk_frame_new ("Don't change these");
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 (2, 2, FALSE);
gtk_container_border_width (GTK_CONTAINER (table), 10);
gtk_container_add (GTK_CONTAINER (frame), table);
/* Multiple input box */
label = gtk_label_new ("Multiple (57)");
gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
gtk_table_attach (GTK_TABLE (table), label, 0, 1, 0, 1, GTK_FILL, 0, 5, 0 );
gtk_widget_show (label);
entry = gtk_entry_new ();
gtk_table_attach (GTK_TABLE (table), entry, 1, 2, 0, 1, GTK_FILL, GTK_FILL, 0, 0 );
gtk_widget_set_usize( entry, ENTRY_WIDTH, 0 );
sprintf( buffer, "%d", mvals.multiple );
gtk_entry_set_text (GTK_ENTRY (entry), buffer );
gtk_signal_connect (GTK_OBJECT (entry), "changed",
(GtkSignalFunc) maze_entry_callback,
&mvals.multiple);
gtk_widget_show (entry);
/* Offset input box */
label = gtk_label_new ("Offset (1)");
gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
gtk_table_attach (GTK_TABLE (table), label, 0, 1, 1, 2, GTK_FILL, 0, 5, 0 );
gtk_widget_show (label);
entry = gtk_entry_new ();
gtk_table_attach (GTK_TABLE (table), entry, 1, 2, 1, 2, GTK_FILL, GTK_FILL, 0, 0 );
gtk_widget_set_usize( entry, ENTRY_WIDTH, 0 );
sprintf( buffer, "%d", mvals.offset );
gtk_entry_set_text (GTK_ENTRY (entry), buffer );
gtk_signal_connect (GTK_OBJECT (entry), "changed",
(GtkSignalFunc) maze_entry_callback,
&mvals.offset);
gtk_widget_show (entry);
/* Add Advanced page to notebook */
gtk_widget_show (frame);
gtk_widget_show (table);
gtk_notebook_append_page (GTK_NOTEBOOK (notebook), frame,
gtk_label_new ("Advanced"));
gtk_widget_show (dlg);
gtk_main ();
gdk_flush ();
return mint.run;
}
/* Maze Interface Functions */
static void
maze_close_callback (GtkWidget *widget,
gpointer data)
{
gtk_main_quit ();
}
static void
maze_ok_callback (GtkWidget *widget,
gpointer data)
{
mint.run = TRUE;
gtk_widget_destroy (GTK_WIDGET (data));
}
static void
maze_entry_callback (GtkWidget *widget,
gpointer data)
{
gint *text_val;
text_val = (gint *) data;
*text_val = atoi (gtk_entry_get_text (GTK_ENTRY (widget)));
}
/* ==================================================================== */
/* As found in pixelize.c */
/*
Entry and Scale pair 1.03
TODO:
- Do the proper thing when the user changes value in entry,
so that callback should not be called when value is actually not changed.
- Update delay
*/
/*
* entscale: create new entscale with label. (int)
* 1 row and 2 cols of table are needed.
* Input:
* x, y: starting row and col in table
* caption: label string
* intvar: pointer to variable
* min, max: the boundary of scale
* constraint: (bool) true iff the value of *intvar should be constraint
* by min and max
* callback: called when the value is actually changed
* call_data: data for callback func
*/
void
entscale_int_new ( GtkWidget *table, gint x, gint y,
gchar *caption, gint *intvar,
gint min, gint max, gint constraint,
EntscaleIntCallbackFunc callback,
gpointer call_data)
{
EntscaleIntData *userdata;
GtkWidget *hbox;
GtkWidget *label;
GtkWidget *entry;
GtkWidget *scale;
GtkObject *adjustment;
gchar buffer[256];
gint constraint_val;
userdata = g_new ( EntscaleIntData, 1 );
label = gtk_label_new (caption);
gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
/*
If the first arg of gtk_adjustment_new() isn't between min and
max, it is automatically corrected by gtk later with
"value_changed" signal. I don't like this, since I want to leave
*intvar untouched when `constraint' is false.
The lines below might look oppositely, but this is OK.
*/
userdata->constraint = constraint;
if( constraint )
constraint_val = *intvar;
else
constraint_val = ( *intvar < min ? min : *intvar > max ? max : *intvar );
userdata->adjustment = adjustment =
gtk_adjustment_new ( constraint_val, min, max, 1.0, 1.0, 0.0);
scale = gtk_hscale_new ( GTK_ADJUSTMENT(adjustment) );
gtk_widget_set_usize (scale, ENTSCALE_INT_SCALE_WIDTH, 0);
gtk_scale_set_draw_value (GTK_SCALE (scale), FALSE);
userdata->entry = entry = gtk_entry_new ();
gtk_widget_set_usize (entry, ENTSCALE_INT_ENTRY_WIDTH, 0);
sprintf( buffer, "%d", *intvar );
gtk_entry_set_text( GTK_ENTRY (entry), buffer );
userdata->callback = callback;
userdata->call_data = call_data;
/* userdata is done */
gtk_object_set_user_data (GTK_OBJECT(adjustment), userdata);
gtk_object_set_user_data (GTK_OBJECT(entry), userdata);
/* now ready for signals */
gtk_signal_connect (GTK_OBJECT (entry), "changed",
(GtkSignalFunc) entscale_int_entry_update,
intvar);
gtk_signal_connect (GTK_OBJECT (adjustment), "value_changed",
(GtkSignalFunc) entscale_int_scale_update,
intvar);
gtk_signal_connect (GTK_OBJECT (entry), "destroy",
(GtkSignalFunc) entscale_int_destroy_callback,
userdata );
/* start packing */
hbox = gtk_hbox_new (FALSE, 5);
gtk_box_pack_start (GTK_BOX (hbox), scale, TRUE, TRUE, 0);
gtk_box_pack_start (GTK_BOX (hbox), entry, FALSE, TRUE, 0);
gtk_table_attach (GTK_TABLE (table), label, x, x+1, y, y+1,
GTK_FILL, GTK_FILL, 0, 0);
gtk_table_attach (GTK_TABLE (table), hbox, x+1, x+2, y, y+1,
GTK_EXPAND | GTK_FILL, GTK_FILL, 0, 0);
gtk_widget_show (label);
gtk_widget_show (entry);
gtk_widget_show (scale);
gtk_widget_show (hbox);
}
/* when destroyed, userdata is destroyed too */
static void
entscale_int_destroy_callback (GtkWidget *widget,
gpointer data)
{
EntscaleIntData *userdata;
userdata = data;
g_free ( userdata );
}
static void
entscale_int_scale_update (GtkAdjustment *adjustment,
gpointer data)
{
EntscaleIntData *userdata;
GtkEntry *entry;
gchar buffer[256];
gint *intvar = data;
gint new_val;
userdata = gtk_object_get_user_data (GTK_OBJECT (adjustment));
new_val = (gint) adjustment->value;
*intvar = new_val;
entry = GTK_ENTRY( userdata->entry );
sprintf (buffer, "%d", (int) new_val );
/* avoid infinite loop (scale, entry, scale, entry ...) */
gtk_signal_handler_block_by_data ( GTK_OBJECT(entry), data );
gtk_entry_set_text ( entry, buffer);
gtk_signal_handler_unblock_by_data ( GTK_OBJECT(entry), data );
if (userdata->callback)
(*userdata->callback) (*intvar, userdata->call_data);
}
static void
entscale_int_entry_update (GtkWidget *widget,
gpointer data)
{
EntscaleIntData *userdata;
GtkAdjustment *adjustment;
int new_val, constraint_val;
int *intvar = data;
userdata = gtk_object_get_user_data (GTK_OBJECT (widget));
adjustment = GTK_ADJUSTMENT( userdata->adjustment );
new_val = atoi (gtk_entry_get_text (GTK_ENTRY (widget)));
constraint_val = new_val;
if ( constraint_val < adjustment->lower )
constraint_val = adjustment->lower;
if ( constraint_val > adjustment->upper )
constraint_val = adjustment->upper;
if ( userdata->constraint )
*intvar = constraint_val;
else
*intvar = new_val;
adjustment->value = constraint_val;
gtk_signal_handler_block_by_data ( GTK_OBJECT(adjustment), data );
gtk_signal_emit_by_name ( GTK_OBJECT(adjustment), "value_changed");
gtk_signal_handler_unblock_by_data ( GTK_OBJECT(adjustment), data );
if (userdata->callback)
(*userdata->callback) (*intvar, userdata->call_data);
}

View File

@ -1,911 +0,0 @@
/* The GIMP -- an image manipulation program
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* Motion Blur plug-in for GIMP 0.99
* Copyright (C) 1997 Daniel Skarda (0rfelyus@atrey.karlin.mff.cuni.cz)
*
* This plug-in is port of Motion Blur plug-in for GIMP 0.54 by Thorsten Martinsen
* Copyright (C) 1996 Torsten Martinsen <torsten@danbbs.dk>
* Bresenham algorithm stuff hacked from HP2xx written by Heinz W. Werntges
* Changes for version 1.11/1.12 Copyright (C) 1996 Federico Mena Quintero
* quartic@polloux.fciencias.unam.mx
*
* I also used some code from Whirl and Pinch plug-in by Federico Mena Quintero
* (federico@nuclecu.unam.mx)
*
* 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
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/* Version 1.2
*
* Everything is new - no changes
*
* TODO:
* Bilinear interpolation from original mblur for 0.54
* Speed all things up
* ? better caching scheme
* - while bluring along long trajektory do not averrage all
* pixels but averrage only few samples
* Function for weight of samples along trajectory
* Preview
* Support paths in GiMP 1.1 :-)
* Smash all bugs :-)
*/
#include <signal.h>
#include <unistd.h>
#include <gtk/gtk.h>
#include <libgimp/gimp.h>
#define PLUG_IN_NAME "plug_in_mblur"
#define PLUG_IN_VERSION "Sep 1997, 1.2"
#define MBLUR_LINEAR 0
#define MBLUR_RADIAL 1
#define MBLUR_ZOOM 2
#define MBLUR_MAX MBLUR_ZOOM
typedef struct {
gint32 mblur_type;
gint32 length;
gint32 angle;
} mblur_vals_t;
typedef struct {
gint col, row;
gint img_width, img_height, img_bpp, img_has_alpha;
gint tile_width, tile_height;
guchar bg_color[4];
GDrawable *drawable;
GTile *tile;
} pixel_fetcher_t;
/***** Prototypes *****/
static void query(void);
static void run(char *name,
int nparams,
GParam *param,
int *nreturn_vals,
GParam **return_vals);
static pixel_fetcher_t *pixel_fetcher_new(GDrawable *drawable);
static void pixel_fetcher_set_bg_color(pixel_fetcher_t *pf, guchar r, guchar g, guchar b, guchar a);
static void pixel_fetcher_get_pixel(pixel_fetcher_t *pf, int x, int y, guchar *pixel);
static void pixel_fetcher_destroy(pixel_fetcher_t *pf);
static void mblur(void);
static void mblur_linear(void);
static void mblur_radial(void);
static void mblur_zoom(void);
static void dialog_close_callback(GtkWidget *, gpointer);
static void dialog_ok_callback(GtkWidget *, gpointer);
static void dialog_cancel_callback(GtkWidget *, gpointer);
static void dialog_help_callback(GtkWidget *, gpointer);
static void dialog_scale_update(GtkAdjustment *, gint32 *);
static void dialog_toggle_update(GtkWidget *, gint32);
static gint mblur_dialog(void);
/***** Variables *****/
GPlugInInfo PLUG_IN_INFO = {
NULL, /* init_proc */
NULL, /* quit_proc */
query, /* query_proc */
run /* run_proc */
}; /* PLUG_IN_INFO */
static mblur_vals_t mbvals = {
MBLUR_LINEAR, /* mblur_type */
5, /* length */
45 /* radius */
}; /* mb_vals */
static mb_run= FALSE;
static GDrawable *drawable;
static gint img_width, img_height, img_bpp, img_has_alpha;
static gint sel_x1, sel_y1, sel_x2, sel_y2;
static gint sel_width, sel_height;
static double cen_x, cen_y;
/***** Functions *****/
/*****/
MAIN()
/*****/
static void
query(void)
{
static GParamDef args[] = {
{ PARAM_INT32, "run_mode", "Interactive, non-interactive" },
{ PARAM_IMAGE, "image", "Input image" },
{ PARAM_DRAWABLE, "drawable", "Input drawable" },
{ PARAM_INT32, "type", "Type of motion blur (0 - linear, 1 - radial, 2 - zoom)" },
{ PARAM_INT32, "length", "Length" },
{ PARAM_INT32, "angle", "Angle" }
}; /* args */
static GParamDef *return_vals = NULL;
static int nargs = sizeof(args) / sizeof(args[0]);
static int nreturn_vals = 0;
gimp_install_procedure(PLUG_IN_NAME,
"Motion blur of image",
"This plug-in simulates the effect seen when photographing a"
"moving object at a slow shutter speed."
"Done by adding multiple displaced copies.",
"Torsten Martinsen, Federico Mena Quintero and Daniel Skarda",
"Torsten Martinsen, Federico Mena Quintero and Daniel Skarda",
PLUG_IN_VERSION,
"<Image>/Filters/Blur/Motion Blur",
"RGB*, GRAY*",
PROC_PLUG_IN,
nargs,
nreturn_vals,
args,
return_vals);
} /* query */
/*****/
static void
run(char *name,
int nparams,
GParam *param,
int *nreturn_vals,
GParam **return_vals)
{
static GParam values[1];
GRunModeType run_mode;
GStatusType status;
#if 0
printf("Waiting... (pid %d)\n", getpid());
kill(getpid(), SIGSTOP);
#endif
status = STATUS_SUCCESS;
run_mode = param[0].data.d_int32;
values[0].type = PARAM_STATUS;
values[0].data.d_status = status;
*nreturn_vals = 1;
*return_vals = values;
/* Get the active drawable info */
drawable = gimp_drawable_get(param[2].data.d_drawable);
img_width = gimp_drawable_width(drawable->id);
img_height = gimp_drawable_height(drawable->id);
img_bpp = gimp_drawable_bpp(drawable->id);
img_has_alpha = gimp_drawable_has_alpha(drawable->id);
gimp_drawable_mask_bounds(drawable->id, &sel_x1, &sel_y1, &sel_x2, &sel_y2);
/* Calculate scaling parameters */
sel_width = sel_x2 - sel_x1;
sel_height = sel_y2 - sel_y1;
cen_x = (double) (sel_x1 + sel_x2 - 1) / 2.0;
cen_y = (double) (sel_y1 + sel_y2 - 1) / 2.0;
switch (run_mode) {
case RUN_INTERACTIVE:
/* Possibly retrieve data */
gimp_get_data(PLUG_IN_NAME, &mbvals);
/* Get information from the dialog */
if (!mblur_dialog())
return;
break;
case RUN_NONINTERACTIVE:
/* Make sure all the arguments are present */
if (nparams != 6)
status = STATUS_CALLING_ERROR;
if (status == STATUS_SUCCESS) {
mbvals.mblur_type = param[3].data.d_int32;
mbvals.length = param[4].data.d_int32;
mbvals.angle = param[5].data.d_int32;
} /* if */
if ((mbvals.mblur_type < 0) && (mbvals.mblur_type > MBLUR_ZOOM))
status= STATUS_CALLING_ERROR;
break;
case RUN_WITH_LAST_VALS:
/* Possibly retrieve data */
gimp_get_data(PLUG_IN_NAME, &mbvals);
break;
default:
break;
} /* switch */
/* Blur the image */
if ((status == STATUS_SUCCESS) &&
(gimp_drawable_color(drawable->id) ||
gimp_drawable_gray(drawable->id))) {
/* Set the tile cache size */
gimp_tile_cache_ntiles(2 * (drawable->width + gimp_tile_width() - 1) / gimp_tile_width());
/* Run! */
mblur();
/* If run mode is interactive, flush displays */
if (run_mode != RUN_NONINTERACTIVE)
gimp_displays_flush();
/* Store data */
if (run_mode == RUN_INTERACTIVE)
gimp_set_data(PLUG_IN_NAME, &mbvals, sizeof(mblur_vals_t));
} else if (status == STATUS_SUCCESS)
status = STATUS_EXECUTION_ERROR;
values[0].data.d_status = status;
gimp_drawable_detach(drawable);
} /* run */
/*****/
static void
mblur_linear(void)
{
GPixelRgn dest_rgn;
pixel_fetcher_t *pft;
gpointer pr;
guchar *dest, *d;
guchar pixel[4], bg_color[4];
gint32 sum[4];
gint progress, max_progress;
gint c;
int x, y, i, xx, yy, n;
int dx, dy, px, py, swapdir, err, e, s1, s2;
gimp_pixel_rgn_init(&dest_rgn, drawable, sel_x1, sel_y1, sel_width, sel_height, TRUE, TRUE);
pft = pixel_fetcher_new(drawable);
gimp_palette_get_background(&bg_color[0], &bg_color[1], &bg_color[2]);
pixel_fetcher_set_bg_color(pft, bg_color[0], bg_color[1], bg_color[2], (img_has_alpha ? 0 : 255));
progress = 0;
max_progress = sel_width * sel_height;
n = mbvals.length;
px = n*cos(mbvals.angle/180.0*M_PI);
py = n*sin(mbvals.angle/180.0*M_PI);
/*
* Initialization for Bresenham algorithm:
* dx = abs(x2-x1), s1 = sign(x2-x1)
* dy = abs(y2-y1), s2 = sign(y2-y1)
*/
if ((dx = px) != 0) {
if (dx < 0) {
dx = -dx;
s1 = -1;
}
else
s1 = 1;
} else
s1 = 0;
if ((dy = py) != 0) {
if (dy < 0) {
dy = -dy;
s2 = -1;
}
else
s2 = 1;
} else
s2 = 0;
if (dy > dx) {
swapdir = dx;
dx = dy;
dy = swapdir;
swapdir = 1;
}
else
swapdir = 0;
dy *= 2;
err = dy - dx; /* Initial error term */
dx *= 2;
for (pr = gimp_pixel_rgns_register (1, &dest_rgn); pr != NULL; pr = gimp_pixel_rgns_process (pr)) {
dest = dest_rgn.data;
for (y = dest_rgn.y; y < (dest_rgn.y + dest_rgn.h); y++) {
d = dest;
for (x = dest_rgn.x; x < (dest_rgn.x + dest_rgn.w); x++) {
xx = x; yy = y; e = err;
for (c= 0; c < img_bpp; c++) sum[c]= 0;
for (i = 0; i < n; ) {
pixel_fetcher_get_pixel(pft,xx,yy,pixel);
for (c= 0; c < img_bpp; c++)
sum[c]+= pixel[c];
i++;
while (e >= 0) {
if (swapdir)
xx += s1;
else
yy += s2;
e -= dx;
}
if (swapdir)
yy += s2;
else
xx += s1;
e += dy;
if ((xx < sel_x1)||(xx >= sel_x2)||(yy < sel_y1)||(yy >= sel_y2))
break;
}
if ( i==0 )
{
pixel_fetcher_get_pixel(pft,xx,yy,d);
}
else
{
for (c=0; c < img_bpp; c++)
d[c]= sum[c] / i;
}
d+= dest_rgn.bpp;
}
dest += dest_rgn.rowstride;
}
progress += dest_rgn.w * dest_rgn.h;
gimp_progress_update((double) progress / max_progress);
}
pixel_fetcher_destroy(pft);
}
static void
mblur_radial(void)
{
GPixelRgn dest_rgn;
pixel_fetcher_t *pft;
gpointer pr;
guchar *dest, *d;
guchar pixel[4], bg_color[4];
gint32 sum[4];
gint progress, max_progress, c;
int x, y, i, n, xr, yr;
int count, R, r, w, h, step;
float angle, theta, * ct, * st, offset, xx, yy;
gimp_pixel_rgn_init(&dest_rgn, drawable, sel_x1, sel_y1, sel_width, sel_height, TRUE, TRUE);
pft = pixel_fetcher_new(drawable);
gimp_palette_get_background(&bg_color[0], &bg_color[1], &bg_color[2]);
pixel_fetcher_set_bg_color(pft, bg_color[0], bg_color[1], bg_color[2], (img_has_alpha ? 0 : 255));
progress = 0;
max_progress = sel_width * sel_height;
angle = ((float) mbvals.angle)/180.0*M_PI;
w = MAX(img_width-cen_x, cen_x);
h = MAX(img_height-cen_y, cen_y);
R = sqrt(w*w + h*h);
n = 4*angle*sqrt(R)+2;
theta = angle/((float) (n-1));
if (((ct = malloc(n*sizeof(float))) == NULL) ||
((st = malloc(n*sizeof(float))) == NULL))
return;
offset = theta*(n-1)/2;
for (i = 0; i < n; ++i) {
ct[i] = cos(theta*i-offset);
st[i] = sin(theta*i-offset);
}
for (pr = gimp_pixel_rgns_register (1, &dest_rgn); pr != NULL; pr = gimp_pixel_rgns_process (pr)) {
dest = dest_rgn.data;
for (y = dest_rgn.y; y < (dest_rgn.y + dest_rgn.h); y++) {
d = dest;
for (x = dest_rgn.x; x < (dest_rgn.x + dest_rgn.w); x++) {
xr = x-cen_x;
yr = y-cen_y;
r = sqrt(xr*xr + yr*yr);
if (r == 0)
step = 1;
else if ((step = R/r) == 0)
step = 1;
else if (step > n-1)
step = n-1;
for (c=0; c < img_bpp; c++) sum[c]=0;
for (i = 0, count = 0; i < n; i += step) {
xx = cen_x + xr*ct[i] - yr*st[i];
yy = cen_y + xr*st[i] + yr*ct[i];
if ((yy < sel_y1) || (yy >= sel_y2) ||
(xx < sel_x1) || (xx >= sel_x2))
continue;
++count;
pixel_fetcher_get_pixel(pft,xx,yy,pixel);
for (c=0; c < img_bpp; c++)
sum[c]+= pixel[c];
}
if ( count==0 )
{
pixel_fetcher_get_pixel(pft,xx,yy,d);
}
else
{
for (c=0; c < img_bpp; c++)
d[c]= sum[c] / count;
}
d+= dest_rgn.bpp;
}
dest += dest_rgn.rowstride;
}
progress += dest_rgn.w * dest_rgn.h;
gimp_progress_update((double) progress / max_progress);
}
pixel_fetcher_destroy(pft);
free(ct);
free(st);
}
static void
mblur_zoom(void)
{
GPixelRgn dest_rgn;
pixel_fetcher_t *pft;
gpointer pr;
guchar *dest, *d;
guchar pixel[4], bg_color[4];
gint32 sum[4];
gint progress, max_progress;
int x, y, i, xx, yy, n, c;
float f;
gimp_pixel_rgn_init(&dest_rgn, drawable, sel_x1, sel_y1, sel_width, sel_height, TRUE, TRUE);
pft = pixel_fetcher_new(drawable);
gimp_palette_get_background(&bg_color[0], &bg_color[1], &bg_color[2]);
pixel_fetcher_set_bg_color(pft, bg_color[0], bg_color[1], bg_color[2], (img_has_alpha ? 0 : 255));
progress = 0;
max_progress = sel_width * sel_height;
n = mbvals.length;
f = 0.02;
for (pr = gimp_pixel_rgns_register (1, &dest_rgn); pr != NULL; pr = gimp_pixel_rgns_process (pr))
{
dest = dest_rgn.data;
for (y = dest_rgn.y; y < (dest_rgn.y + dest_rgn.h); y++) {
d = dest;
for (x = dest_rgn.x; x < (dest_rgn.x + dest_rgn.w); x++) {
for (c=0; c < img_bpp; c++) sum[c]=0;
for (i = 0; i < n; ++i) {
xx = cen_x + (x-cen_x)*(1.0 + f*i);
yy = cen_y + (y-cen_y)*(1.0 + f*i);
if ((yy < sel_y1) || (yy >= sel_y2) ||
(xx < sel_x1) || (xx >= sel_x2))
break;
pixel_fetcher_get_pixel(pft,xx,yy,pixel);
for (c= 0; c < img_bpp; c++)
sum[c]+= pixel[c];
}
if ( i==0 )
{
pixel_fetcher_get_pixel(pft,xx,yy,d);
}
else
{
for (c=0; c < img_bpp; c++)
d[c]= sum[c] / i;
}
d+= dest_rgn.bpp;
}
dest += dest_rgn.rowstride;
}
progress += dest_rgn.w * dest_rgn.h;
gimp_progress_update((double) progress / max_progress);
}
pixel_fetcher_destroy(pft);
}
static void
mblur(void)
{
gimp_progress_init("Bluring...");
switch (mbvals.mblur_type)
{
case MBLUR_LINEAR:
mblur_linear();
break;
case MBLUR_RADIAL:
mblur_radial();
break;
case MBLUR_ZOOM:
mblur_zoom();
break;
default:
;
}
gimp_drawable_flush(drawable);
gimp_drawable_merge_shadow(drawable->id, TRUE);
gimp_drawable_update(drawable->id, sel_x1, sel_y1, sel_width, sel_height);
}
/*****************************************
*
* pixel_fetcher from whirlpinch plug-in
*
****************************************/
static pixel_fetcher_t *
pixel_fetcher_new(GDrawable *drawable)
{
pixel_fetcher_t *pf;
pf = g_malloc(sizeof(pixel_fetcher_t));
pf->col = -1;
pf->row = -1;
pf->img_width = gimp_drawable_width(drawable->id);
pf->img_height = gimp_drawable_height(drawable->id);
pf->img_bpp = gimp_drawable_bpp(drawable->id);
pf->img_has_alpha = gimp_drawable_has_alpha(drawable->id);
pf->tile_width = gimp_tile_width();
pf->tile_height = gimp_tile_height();
pf->bg_color[0] = 0;
pf->bg_color[1] = 0;
pf->bg_color[2] = 0;
pf->bg_color[3] = 0;
pf->drawable = drawable;
pf->tile = NULL;
return pf;
} /* pixel_fetcher_new */
/*****/
static void
pixel_fetcher_set_bg_color(pixel_fetcher_t *pf, guchar r, guchar g, guchar b, guchar a)
{
pf->bg_color[0] = r;
pf->bg_color[1] = g;
pf->bg_color[2] = b;
if (pf->img_has_alpha)
pf->bg_color[pf->img_bpp - 1] = a;
} /* pixel_fetcher_set_bg_color */
/*****/
static void
pixel_fetcher_get_pixel(pixel_fetcher_t *pf, int x, int y, guchar *pixel)
{
gint col, row;
gint coloff, rowoff;
guchar *p;
int i;
if ((x < sel_x1) || (x >= sel_x2) ||
(y < sel_y1) || (y >= sel_y2)) {
for (i = 0; i < pf->img_bpp; i++)
pixel[i] = pf->bg_color[i];
return;
} /* if */
col = x / pf->tile_width;
coloff = x % pf->tile_width;
row = y / pf->tile_height;
rowoff = y % pf->tile_height;
if ((col != pf->col) ||
(row != pf->row) ||
(pf->tile == NULL)) {
if (pf->tile != NULL)
gimp_tile_unref(pf->tile, FALSE);
pf->tile = gimp_drawable_get_tile(pf->drawable, FALSE, row, col);
gimp_tile_ref(pf->tile);
pf->col = col;
pf->row = row;
} /* if */
p = pf->tile->data + pf->img_bpp * (pf->tile->ewidth * rowoff + coloff);
for (i = pf->img_bpp; i; i--)
*pixel++ = *p++;
} /* pixel_fetcher_get_pixel */
/*****/
static void
pixel_fetcher_destroy(pixel_fetcher_t *pf)
{
if (pf->tile != NULL)
gimp_tile_unref(pf->tile, FALSE);
g_free(pf);
} /* pixel_fetcher_destroy */
/****************************************
*
* UI
*
****************************************/
static gint
mblur_dialog(void)
{
GtkWidget *dialog;
GtkWidget *oframe, *iframe;
GtkWidget *evbox, *ovbox, *ivbox;
GtkWidget *button, *label;
GtkWidget *scale;
GtkObject *adjustment;
gint argc;
gchar **argv;
argc = 1;
argv = g_new(gchar *, 1);
argv[0] = g_strdup("whirlpinch");
gtk_init(&argc, &argv);
gtk_rc_parse (gimp_gtkrc ());
gdk_set_use_xshm(gimp_use_xshm());
dialog= gtk_dialog_new();
gtk_window_set_title(GTK_WINDOW(dialog), "Motion blur");
gtk_window_position(GTK_WINDOW(dialog), GTK_WIN_POS_MOUSE);
gtk_container_border_width(GTK_CONTAINER(dialog), 0);
gtk_signal_connect(GTK_OBJECT(dialog), "destroy",
(GtkSignalFunc) dialog_close_callback,
NULL);
button = gtk_button_new_with_label("OK");
GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT);
gtk_signal_connect(GTK_OBJECT(button), "clicked",
(GtkSignalFunc) dialog_ok_callback,
dialog);
gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->action_area), button, TRUE, TRUE, 0);
gtk_widget_grab_default(button);
gtk_widget_show(button);
button = gtk_button_new_with_label("Cancel");
GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT);
gtk_signal_connect(GTK_OBJECT(button), "clicked",
(GtkSignalFunc) dialog_cancel_callback,
dialog);
gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->action_area), button, TRUE, TRUE, 0);
gtk_widget_show(button);
button = gtk_button_new_with_label("Help");
GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT);
gtk_signal_connect(GTK_OBJECT(button), "clicked",
(GtkSignalFunc) dialog_help_callback,
dialog);
gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->action_area),
button, TRUE, TRUE, 0);
gtk_widget_set_sensitive(button, FALSE);
gtk_widget_show(button);
/********************/
evbox= gtk_vbox_new(FALSE, 5);
gtk_container_border_width (GTK_CONTAINER (evbox), 5);
gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox),
evbox, FALSE,FALSE,0);
oframe= gtk_frame_new("Options");
gtk_frame_set_shadow_type(GTK_FRAME(oframe), GTK_SHADOW_ETCHED_IN);
gtk_box_pack_start(GTK_BOX(evbox),
oframe, TRUE, TRUE, 0);
ovbox= gtk_vbox_new(FALSE, 5);
gtk_container_border_width (GTK_CONTAINER (ovbox), 5);
gtk_container_add(GTK_CONTAINER(oframe), ovbox);
label=gtk_label_new("Length");
gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
gtk_box_pack_start(GTK_BOX(ovbox), label, FALSE, FALSE, 0);
gtk_widget_show(label);
adjustment = gtk_adjustment_new( mbvals.length, 0.0, 256.0,
1.0, 1.0, 1.0);
gtk_signal_connect(adjustment,"value_changed",
(GtkSignalFunc) dialog_scale_update,
&(mbvals.length));
scale= gtk_hscale_new( GTK_ADJUSTMENT(adjustment));
gtk_widget_set_usize(GTK_WIDGET(scale), 150, 30);
gtk_range_set_update_policy(GTK_RANGE(scale), GTK_UPDATE_DELAYED);
gtk_scale_set_digits(GTK_SCALE(scale), 0);
gtk_scale_set_draw_value(GTK_SCALE(scale), TRUE);
gtk_box_pack_start(GTK_BOX(ovbox), scale, FALSE, FALSE,0);
gtk_widget_show( scale );
/*****/
iframe= gtk_frame_new("Blur type");
gtk_frame_set_shadow_type(GTK_FRAME(iframe), GTK_SHADOW_ETCHED_IN);
gtk_box_pack_start(GTK_BOX(ovbox),
iframe, FALSE, FALSE, 0);
ivbox= gtk_vbox_new(FALSE, 5);
gtk_container_border_width (GTK_CONTAINER (ivbox), 5);
gtk_container_add(GTK_CONTAINER(iframe), ivbox);
{
int i;
char * name[3]= {"Linear", "Radial", "Zoom"};
button= NULL;
for (i=0; i < 3; i++)
{
button= gtk_radio_button_new_with_label(
(button==NULL)? NULL :
gtk_radio_button_group(GTK_RADIO_BUTTON(button)),
name[i]);
gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(button),
(mbvals.mblur_type==i));
gtk_signal_connect (GTK_OBJECT (button), "toggled",
(GtkSignalFunc) dialog_toggle_update,
(gpointer) i);
gtk_box_pack_start(GTK_BOX(ivbox), button, FALSE, FALSE,0);
gtk_widget_show(button);
}
}
gtk_widget_show(ivbox);
gtk_widget_show(iframe);
/*****/
label=gtk_label_new("Angle");
gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
gtk_box_pack_start(GTK_BOX(ovbox), label, FALSE, FALSE, 0);
gtk_widget_show(label);
adjustment = gtk_adjustment_new( mbvals.angle, 0.0, 360.0,
1.0, 1.0, 1.0);
gtk_signal_connect(adjustment,"value_changed",
(GtkSignalFunc) dialog_scale_update,
&(mbvals.angle));
scale= gtk_hscale_new( GTK_ADJUSTMENT(adjustment));
gtk_widget_set_usize(GTK_WIDGET(scale), 150, 30);
gtk_range_set_update_policy(GTK_RANGE(scale), GTK_UPDATE_DELAYED);
gtk_scale_set_digits(GTK_SCALE(scale), 0);
gtk_scale_set_draw_value(GTK_SCALE(scale), TRUE);
gtk_box_pack_start(GTK_BOX(ovbox), scale, FALSE, FALSE,0);
gtk_widget_show( scale );
gtk_widget_show(ovbox);
gtk_widget_show(oframe);
gtk_widget_show(evbox);
gtk_widget_show(dialog);
gtk_main();
gdk_flush();
return mb_run;
}
static void
dialog_close_callback(GtkWidget *widget, gpointer data)
{
gtk_main_quit();
}
static void
dialog_ok_callback(GtkWidget *widget, gpointer data)
{
mb_run= TRUE;
gtk_widget_destroy(GTK_WIDGET(data));
}
static void
dialog_cancel_callback(GtkWidget *widget, gpointer data)
{
gtk_widget_destroy(GTK_WIDGET(data));
}
static void
dialog_help_callback(GtkWidget *widget, gpointer data)
{
}
/*****/
static void
dialog_scale_update(GtkAdjustment *adjustment, gint32 *value)
{
*value= adjustment->value;
}
static void
dialog_toggle_update(GtkWidget *widget, gint32 value)
{
if (GTK_TOGGLE_BUTTON (widget)->active)
mbvals.mblur_type= value;
}

View File

@ -1,847 +0,0 @@
/**************************************************
* file: megawidget/megawidget.c
*
* Copyright (c) 1997 Eric L. Hernes (erich@rrnet.com)
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. The name of the author may not be used to endorse or promote products
* derived from this software withough specific prior written permission
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* $Id$
*/
/* Functions added by Xavier Bouchoux (Xavier.Bouchoux@ensimag.imag.fr)
* mw_value_radio_group_new()
* --> it modifies a user variable to a value associated with the current
* button
* mw_ientry_button_new()
* mw_fentry_button_new()
* ---> Guess...
* mw_color_select_button_create()
* --> Creates a colored button, wich creates a colorselection window
* (just like ifs compose)
*/
#include <gtk/gtk.h>
#include <libgimp/gimp.h>
#include "megawidget.h"
static void mw_scale_entry_new(GtkWidget *table, gchar *name,
gfloat defval, gfloat lorange,
gfloat hirange, gfloat st_inc,
gfloat pg_inc, gfloat pgsiz,
gpointer variablep, gchar *fmtvar,
gint left_a, gint right_a, gint top_a,
gint bottom_a, GtkCallback scale_cb,
GtkCallback entry_cb);
static void mw_entry_new(GtkWidget *parent, gchar *fname,
gchar *name, gpointer variablep,
guchar *buffer, GtkCallback entry_cb);
static void ui_ok_callback(GtkWidget *widget, gpointer data);
static void ui_close_callback(GtkWidget *widget, gpointer data);
static void ui_fscale_callback(GtkAdjustment *adj, gpointer data);
static void ui_fentry_callback(GtkWidget *widget, gpointer data);
static void ui_iscale_callback(GtkAdjustment *adj, gpointer data);
static void ui_ientry_callback(GtkWidget *widget, gpointer data);
static void ui_toggle_callback(GtkWidget *widget, gpointer data);
static void ui_ientry_alone_callback(GtkWidget *widget, gpointer data);
static void ui_fentry_alone_callback(GtkWidget *widget, gpointer data);
static void ui_value_toggle_callback(GtkWidget *widget, gpointer data);
static void create_color_selection (GtkWidget *widget, struct mwColorSel *cs);
static void color_selection_cancel (GtkWidget *widget, struct mwColorSel *cs);
static void color_selection_destroy_window (GtkWidget *widget,
GtkWidget **window);
static void color_selection_changed_cb (GtkWidget *w, struct mwColorSel *cs);
static void color_selection_ok_cb (GtkWidget *w, struct mwColorSel *cs);
static void color_select_fill_button_color(GtkWidget *preview, gdouble *color);
#ifndef NO_PREVIEW
static mw_preview_t *mw_do_preview = NULL;
static gint do_preview = 1;
#endif
GtkWidget *
mw_app_new(gchar *resname, gchar *appname, gint *runpp){
gchar **argv;
gint argc;
GtkWidget *dlg;
GtkWidget *button;
argc = 1;
argv = g_new(gchar *, 1);
*runpp = 0;
argv[0] = g_strdup(resname);
gtk_init(&argc, &argv);
dlg = gtk_dialog_new();
gtk_object_set_data(GTK_OBJECT(dlg), "runp", runpp);
gtk_window_set_title(GTK_WINDOW(dlg), appname);
gtk_window_position(GTK_WINDOW(dlg), GTK_WIN_POS_MOUSE);
gtk_signal_connect(GTK_OBJECT(dlg), "destroy",
(GtkSignalFunc) ui_close_callback,
NULL);
button = gtk_button_new_with_label("OK");
GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT);
gtk_signal_connect(GTK_OBJECT (button), "clicked",
(GtkSignalFunc) ui_ok_callback,
dlg);
gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dlg)->action_area), button,
TRUE, TRUE, 0);
gtk_widget_grab_default(button);
gtk_widget_show(button);
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));
gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dlg)->action_area), button,
TRUE, TRUE, 0);
gtk_widget_show(button);
return dlg;
}
void
mw_fscale_entry_new(GtkWidget *table, gchar *name,
gfloat lorange, gfloat hirange,
gfloat st_inc, gfloat pg_inc, gfloat pgsiz,
gint left_a, gint right_a, gint top_a, gint bottom_a,
gdouble *var) {
gchar buffer[40];
sprintf(buffer, "%0.3f", *var);
mw_scale_entry_new(table, name, *var, lorange, hirange,
st_inc, pg_inc, pgsiz, var, buffer,
left_a, right_a, top_a, bottom_a,
(GtkCallback)ui_fscale_callback,
(GtkCallback)ui_fentry_callback);
}
void
mw_iscale_entry_new(GtkWidget *table, gchar *name,
gint lorange, gint hirange,
gint st_inc, gint pg_inc, gint pgsiz,
gint left_a, gint right_a, gint top_a, gint bottom_a,
gint *varp) {
gchar buffer[40];
sprintf(buffer, "%d", *varp);
mw_scale_entry_new(table, name, (gfloat)*varp, (gfloat)lorange,
(gfloat)hirange, (gfloat)st_inc, (gfloat)pg_inc,
(gfloat)pgsiz, varp, buffer,
left_a, right_a, top_a, bottom_a,
(GtkCallback)ui_iscale_callback,
(GtkCallback)ui_ientry_callback);
}
GSList *
mw_radio_group_new(GtkWidget *parent, gchar *name, struct mwRadioGroup *rg){
GSList *lst = NULL;
GtkWidget *frame;
GtkWidget *vbox;
struct mwRadioGroup *c;
if (name != NULL) {
frame = gtk_frame_new(name);
gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_ETCHED_IN);
/* gtk_container_border_width(GTK_CONTAINER(frame), 0);*/
gtk_box_pack_start(GTK_BOX(parent), frame, FALSE, FALSE, 0);
gtk_widget_show(frame);
vbox=gtk_vbox_new(TRUE, 3);
/* gtk_container_border_width(GTK_CONTAINER(vbox), 0);*/
gtk_container_add(GTK_CONTAINER(frame), vbox);
gtk_widget_show(vbox);
for(c=rg;c->name; c++)
lst = mw_radio_new(lst, vbox, c->name, &c->var, c->var);
} else { /* name == NULL */
vbox=gtk_vbox_new(TRUE, 3);
gtk_box_pack_start(GTK_BOX(parent), vbox, FALSE, FALSE, 0);
gtk_widget_show(vbox);
for(c=rg;c->name; c++)
lst = mw_radio_new(lst, vbox, c->name, &c->var, c->var);
}
return lst;
}
GSList *
mw_radio_new(GSList *gsl, GtkWidget *parent, gchar *name,
gint *varp, gint init) {
GtkWidget *button;
GSList *rv;
button=gtk_radio_button_new_with_label(gsl, name);
rv=gtk_radio_button_group(GTK_RADIO_BUTTON(button));
gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(button), init);
gtk_signal_connect(GTK_OBJECT(button), "toggled",
(GtkSignalFunc) ui_toggle_callback,
varp);
gtk_box_pack_start(GTK_BOX(parent), button, FALSE, FALSE, 0);
gtk_widget_show(button);
return(rv);
}
gint
mw_radio_result(struct mwRadioGroup *rg) {
gint i=0;
for(i=0;rg[i].name;i++)
if (rg[i].var) return i;
return 0;
}
GSList *
mw_value_radio_group_new(GtkWidget *parent, gchar *name,
struct mwValueRadioGroup *rg, gint *var)
{
GSList *lst = NULL;
GtkWidget *frame;
GtkWidget *vbox;
GtkWidget *button;
struct mwValueRadioGroup *c;
gint value;
if (name != NULL) {
frame = gtk_frame_new(name);
gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_ETCHED_IN);
gtk_box_pack_start(GTK_BOX(parent), frame, FALSE, FALSE, 0);
gtk_widget_show(frame);
vbox=gtk_vbox_new(TRUE, 3);
gtk_container_add(GTK_CONTAINER(frame), vbox);
gtk_widget_show(vbox);
} else { /* name == NULL */
vbox=gtk_vbox_new(TRUE, 3);
gtk_box_pack_start(GTK_BOX(parent), vbox, FALSE, FALSE, 0);
gtk_widget_show(vbox);
}
value = *var;
for(c=rg; c->name!=NULL; c++) {
button=gtk_radio_button_new_with_label(lst, c->name);
lst=gtk_radio_button_group(GTK_RADIO_BUTTON(button));
gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(button), (c->val==value));
gtk_signal_connect(GTK_OBJECT(button), "toggled",
(GtkSignalFunc) ui_value_toggle_callback,
(gpointer)var);
gtk_object_set_data(GTK_OBJECT(button),"Radio_ID",(gpointer)c->val);
gtk_box_pack_start(GTK_BOX(vbox), button, FALSE, FALSE, 0);
gtk_widget_show(button);
}
return lst;
}
GtkWidget *
mw_toggle_button_new(GtkWidget *parent, gchar *fname,
gchar *label, gint *varp){
GtkWidget *frame;
GtkWidget *button;
if (fname != NULL) {
frame = gtk_frame_new(fname);
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(parent), frame, FALSE, TRUE, 0);
gtk_widget_show(frame);
button=gtk_check_button_new_with_label(label);
gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(button), *varp);
gtk_signal_connect(GTK_OBJECT(button), "toggled",
(GtkSignalFunc) ui_toggle_callback,
varp);
gtk_container_add(GTK_CONTAINER(frame), button);
gtk_widget_show(button);
return frame;
} else { /*Name == NULL */
button=gtk_check_button_new_with_label(label);
gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(button), *varp);
gtk_signal_connect(GTK_OBJECT(button), "toggled",
(GtkSignalFunc) ui_toggle_callback,
varp);
gtk_box_pack_start(GTK_BOX(parent), button, FALSE, TRUE, 0);
gtk_widget_show(button);
return parent; /* ????? */
}
}
struct mwColorSel * mw_color_select_button_create(
GtkWidget *parent, gchar *name, gdouble *color,
gint opacity)
{
#define COLOR_SAMPLE_SIZE 30
GtkWidget *button;
struct mwColorSel *cs = g_new(struct mwColorSel,1);
cs->name = name;
cs->color = color;
cs->opacity = opacity;
cs->window = NULL;
button = gtk_button_new();
gtk_box_pack_start(GTK_BOX(parent),button,FALSE,FALSE,0);
gtk_widget_show(button);
cs->preview = gtk_preview_new(GTK_PREVIEW_COLOR);
gtk_preview_size(GTK_PREVIEW(cs->preview),
COLOR_SAMPLE_SIZE,COLOR_SAMPLE_SIZE);
gtk_container_add (GTK_CONTAINER(button),cs->preview);
gtk_widget_show(cs->preview);
color_select_fill_button_color(cs->preview,color);
gtk_signal_connect(GTK_OBJECT(button),"clicked",
(GtkSignalFunc)create_color_selection,
cs);
return cs;
}
void mw_ientry_new(GtkWidget *parent, gchar *fname,
gchar *name, gint *varp)
{
gchar buffer[40];
sprintf (buffer, "%d", *varp);
mw_entry_new(parent, fname, name,
varp, buffer,
(GtkCallback)ui_ientry_alone_callback);
}
void mw_fentry_new(GtkWidget *parent, gchar *fname,
gchar *name, gdouble *varp)
{
gchar buffer[40];
sprintf (buffer, "%f0.3", *varp);
mw_entry_new(parent, fname, name,
varp, buffer,
(GtkCallback)ui_fentry_alone_callback);
}
#ifndef NO_PREVIEW
struct mwPreview *
mw_preview_build_virgin(GDrawable *drw) {
struct mwPreview *mwp;
mwp = (struct mwPreview *)malloc(sizeof(struct mwPreview));
if (drw->width > drw->height) {
mwp->scale = (gdouble)drw->width/(gdouble)PREVIEW_SIZE;
mwp->width = PREVIEW_SIZE;
mwp->height = (drw->height)/(mwp->scale);
} else {
mwp->scale = (gdouble)drw->height/(gdouble)PREVIEW_SIZE;
mwp->height = PREVIEW_SIZE;
mwp->width = (drw->width)/(mwp->scale);
}
mwp->bpp = 3;
mwp->bits = NULL;
return(mwp);
}
struct mwPreview *
mw_preview_build(GDrawable *drw) {
struct mwPreview *mwp;
gint x, y, b;
guchar *bc, *drwBits;
GPixelRgn pr;
mwp= mw_preview_build_virgin(drw);
gimp_pixel_rgn_init(&pr, drw, 0, 0, drw->width, drw->height, FALSE, FALSE);
drwBits = (guchar *)malloc(drw->width * drw->bpp);
mwp->bpp = 3;
bc = mwp->bits = (guchar *)malloc(mwp->width*mwp->height*mwp->bpp);
for(y=0;y<mwp->height;y++) {
gimp_pixel_rgn_get_row(&pr, drwBits, 0, (int)(y*mwp->scale), drw->width);
for(x=0;x<mwp->width;x++) {
for(b=0;b<mwp->bpp;b++)
*bc++=*(drwBits+((gint)(x*mwp->scale)*drw->bpp)+b);
}
}
free(drwBits);
return(mwp);
}
GtkWidget *
mw_preview_new(GtkWidget *parent, struct mwPreview *mwp, mw_preview_t *fcn){
GtkWidget *preview;
GtkWidget *frame;
GtkWidget *pframe;
GtkWidget *vbox;
GtkWidget *button;
guchar *color_cube;
gtk_preview_set_gamma (gimp_gamma ());
gtk_preview_set_install_cmap (gimp_install_cmap ());
color_cube = gimp_color_cube ();
gtk_preview_set_color_cube (color_cube[0], color_cube[1],
color_cube[2], color_cube[3]);
gtk_widget_set_default_visual (gtk_preview_get_visual ());
gtk_widget_set_default_colormap (gtk_preview_get_cmap ());
frame = gtk_frame_new("Preview");
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(parent), frame, FALSE, FALSE, 0);
gtk_widget_show(frame);
vbox = gtk_vbox_new(FALSE, 2);
gtk_container_border_width(GTK_CONTAINER(vbox), 2);
gtk_container_add(GTK_CONTAINER(frame), vbox);
gtk_widget_show(vbox);
pframe = gtk_frame_new(NULL);
gtk_frame_set_shadow_type(GTK_FRAME(pframe), GTK_SHADOW_IN);
gtk_container_border_width(GTK_CONTAINER(pframe), 3);
gtk_box_pack_start(GTK_BOX(vbox), pframe, FALSE, FALSE, 0);
gtk_widget_show(pframe);
preview = gtk_preview_new(GTK_PREVIEW_COLOR);
gtk_preview_size(GTK_PREVIEW(preview), mwp->width, mwp->height);
gtk_container_add(GTK_CONTAINER(pframe), preview);
gtk_widget_show(preview);
mw_do_preview = fcn;
button=gtk_check_button_new_with_label("Do Preview");
gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(button), do_preview);
gtk_signal_connect(GTK_OBJECT(button), "toggled",
(GtkSignalFunc) ui_toggle_callback,
&do_preview);
gtk_box_pack_start(GTK_BOX(vbox), button, FALSE, FALSE, 0);
gtk_widget_show(button);
return preview;
}
#endif /* NO_PREVIEW */
/* internals */
static void
mw_scale_entry_new(GtkWidget *table, gchar *name,
gfloat defval, gfloat lorange, gfloat hirange,
gfloat st_inc, gfloat pg_inc, gfloat pgsiz,
gpointer variablep, gchar *fmtvar,
gint left_a, gint right_a, gint top_a, gint bottom_a,
GtkCallback scale_cb, GtkCallback entry_cb) {
GtkWidget *label;
GtkWidget *hbox;
GtkWidget *scale;
GtkWidget *entry;
GtkObject *adjustment;
label = gtk_label_new(name);
gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
gtk_table_attach(GTK_TABLE(table), label,
left_a, right_a, top_a, bottom_a,
GTK_FILL, GTK_FILL, 0, 0);
gtk_widget_show(label);
hbox = gtk_hbox_new(FALSE, 5);
gtk_table_attach(GTK_TABLE(table), hbox,
left_a+1, right_a+1, top_a, bottom_a,
GTK_EXPAND | GTK_FILL, GTK_FILL, 0, 0);
gtk_widget_show(hbox);
adjustment = gtk_adjustment_new(defval, lorange, hirange, st_inc,
pg_inc, pgsiz);
gtk_signal_connect(GTK_OBJECT(adjustment), "value_changed",
(GtkSignalFunc) scale_cb,
variablep);
scale = gtk_hscale_new(GTK_ADJUSTMENT(adjustment));
gtk_widget_set_usize(GTK_WIDGET(scale), 140, 0);
gtk_scale_set_digits(GTK_SCALE(scale), 2);
gtk_scale_set_draw_value(GTK_SCALE(scale), FALSE);
gtk_box_pack_start(GTK_BOX(hbox), scale, TRUE, TRUE, 0);
gtk_widget_show(scale);
entry = gtk_entry_new();
gtk_object_set_user_data(GTK_OBJECT(entry), adjustment);
gtk_object_set_user_data(adjustment, entry);
gtk_box_pack_start(GTK_BOX(hbox), entry, FALSE, TRUE, 0);
gtk_widget_set_usize(entry, 75, 0);
gtk_entry_set_text(GTK_ENTRY(entry), fmtvar);
gtk_signal_connect(GTK_OBJECT(entry), "changed",
(GtkSignalFunc) entry_cb,
variablep);
gtk_widget_show(entry);
}
static void
mw_entry_new(GtkWidget *parent, gchar *fname,
gchar *name, gpointer variablep,
guchar *buffer, GtkCallback entry_cb)
{
GtkWidget *frame;
GtkWidget *entry, *label;
GtkWidget *hbox;
if (fname != NULL) {
frame = gtk_frame_new(fname);
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(parent), frame, FALSE, TRUE, 0);
gtk_widget_show(frame);
hbox = gtk_hbox_new (FALSE, 5);
gtk_container_add(GTK_CONTAINER(frame), hbox);
} else { /*Name == NULL */
hbox = gtk_hbox_new (FALSE, 5);
gtk_box_pack_start (GTK_BOX (parent), hbox, TRUE, TRUE, 0);
}
label = gtk_label_new (name);
gtk_box_pack_start (GTK_BOX (hbox), label, TRUE, FALSE, 0);
gtk_widget_show (label);
entry = gtk_entry_new();
gtk_box_pack_start (GTK_BOX (hbox), entry, TRUE, TRUE, 0);
gtk_widget_set_usize (entry, 75, 0);
gtk_entry_set_text (GTK_ENTRY (entry), buffer);
gtk_signal_connect (GTK_OBJECT (entry), "changed",
(GtkSignalFunc) entry_cb,
variablep);
gtk_widget_show (entry);
gtk_widget_show (hbox);
}
static void
ui_close_callback(GtkWidget *widget, gpointer data){
gtk_main_quit();
}
static void
ui_ok_callback(GtkWidget *widget, gpointer data){
gint *rp;
rp = gtk_object_get_data(GTK_OBJECT(data), "runp");
*rp=1;
gtk_widget_destroy(GTK_WIDGET(data));
}
static void
ui_fscale_callback(GtkAdjustment *adj, gpointer data){
GtkWidget *ent;
double *nval;
gchar buf[40];
nval = (double*)data;
if (*nval != adj->value) {
*nval = adj->value;
ent = gtk_object_get_user_data(GTK_OBJECT(adj));
sprintf(buf, "%0.2f", adj->value);
gtk_signal_handler_block_by_data(GTK_OBJECT(ent), data);
gtk_entry_set_text(GTK_ENTRY(ent), buf);
gtk_signal_handler_unblock_by_data(GTK_OBJECT(ent), data);
#ifndef NO_PREVIEW
if (do_preview && mw_do_preview!=NULL) (*mw_do_preview)(NULL);
#endif
}
}
static void
ui_fentry_callback(GtkWidget *widget, gpointer data){
GtkAdjustment *adjustment;
double new_val;
double *val;
val = (double*)data;
new_val = atof(gtk_entry_get_text(GTK_ENTRY(widget)));
if (*val != new_val) {
adjustment = gtk_object_get_user_data(GTK_OBJECT(widget));
if ((new_val >= adjustment->lower) &&
(new_val <= adjustment->upper)) {
*val = new_val;
adjustment->value = new_val;
gtk_signal_emit_by_name(GTK_OBJECT(adjustment), "value_changed");
}
#ifndef NO_PREVIEW
if (do_preview && mw_do_preview!=NULL) (*mw_do_preview)(NULL);
#endif
}
}
static void
ui_iscale_callback(GtkAdjustment *adj, gpointer data){
GtkWidget *ent;
gint *nval;
gchar buf[40];
nval = (gint*)data;
if (*nval != (gint)adj->value) {
*nval = (gint)adj->value;
ent = gtk_object_get_user_data(GTK_OBJECT(adj));
sprintf(buf, "%d", (gint)adj->value);
gtk_entry_set_text(GTK_ENTRY(ent), buf);
#ifndef NO_PREVIEW
if (do_preview && mw_do_preview!=NULL) (*mw_do_preview)(NULL);
#endif
}
}
static void
ui_ientry_callback(GtkWidget *widget, gpointer data){
GtkAdjustment *adj;
gint new_val;
gint *val;
val = (gint *)data;
new_val = strtol(gtk_entry_get_text(GTK_ENTRY(widget)), NULL, 0);
if (*val != new_val) {
adj = gtk_object_get_user_data(GTK_OBJECT(widget));
if ((new_val >= adj->lower) &&
(new_val <= adj->upper)) {
*val = new_val;
adj->value = new_val;
gtk_signal_emit_by_name(GTK_OBJECT(adj), "value_changed");
}
#ifndef NO_PREVIEW
if (do_preview && mw_do_preview!=NULL) (*mw_do_preview)(NULL);
#endif
}
}
static void
ui_ientry_alone_callback(GtkWidget *widget, gpointer data)
{
gint new_val;
gint *val;
val = (gint *)data;
new_val = strtol(gtk_entry_get_text(GTK_ENTRY(widget)), NULL, 0);
if (*val != new_val) {
*val= new_val;
#ifndef NO_PREVIEW
if (do_preview && mw_do_preview!=NULL) (*mw_do_preview)(NULL);
#endif
}
}
static void
ui_fentry_alone_callback(GtkWidget *widget, gpointer data)
{
gdouble new_val;
gdouble *val;
val = (gdouble *)data;
new_val = atof(gtk_entry_get_text(GTK_ENTRY(widget)));
if (*val != new_val) {
*val= new_val;
#ifndef NO_PREVIEW
if (do_preview && mw_do_preview!=NULL) (*mw_do_preview)(NULL);
#endif
}
}
static void
ui_toggle_callback(GtkWidget *widget, gpointer data) {
gint *toggle_val;
toggle_val = (gint *) data;
if (GTK_TOGGLE_BUTTON (widget)->active)
*toggle_val = TRUE;
else
*toggle_val = FALSE;
#ifndef NO_PREVIEW
if (do_preview && mw_do_preview!=NULL) (*mw_do_preview)(NULL);
#endif
}
static void
ui_value_toggle_callback(GtkWidget *widget, gpointer data) {
gint id;
/* Get radio button ID */
id=(gint)gtk_object_get_data(GTK_OBJECT(widget),"Radio_ID");
if (GTK_TOGGLE_BUTTON (widget)->active) {
*(gint *)data= id;
#ifndef NO_PREVIEW
if (do_preview && mw_do_preview!=NULL) (*mw_do_preview)(NULL);
#endif
}
}
/* color_selection_* stuff */
static void
color_selection_ok_cb (GtkWidget *w,
struct mwColorSel *cs)
{
GtkColorSelection *colorsel;
colorsel=GTK_COLOR_SELECTION(GTK_COLOR_SELECTION_DIALOG(cs->window)->colorsel);
gtk_color_selection_get_color(colorsel,cs->color);
gtk_widget_destroy(cs->window);
color_select_fill_button_color(cs->preview, cs->color);
#ifndef NO_PREVIEW
if (do_preview && mw_do_preview!=NULL) (*mw_do_preview)(NULL);
#endif
}
static void
color_selection_changed_cb (GtkWidget *w,
struct mwColorSel *cs)
{
GtkColorSelection *colorsel;
colorsel=GTK_COLOR_SELECTION(GTK_COLOR_SELECTION_DIALOG(cs->window)->colorsel);
gtk_color_selection_get_color(colorsel,cs->color);
#ifndef NO_PREVIEW
if (do_preview && mw_do_preview!=NULL) (*mw_do_preview)(NULL);
#endif
}
static void
color_selection_destroy_window (GtkWidget *widget,
GtkWidget **window)
{
*window = NULL;
}
static void
color_selection_cancel (GtkWidget *widget,
struct mwColorSel *cs)
{
(cs->color)[0]=cs->savcolor[0];
(cs->color)[1]=cs->savcolor[1];
(cs->color)[2]=cs->savcolor[2];
if (cs->opacity)
(cs->color)[3]=cs->savcolor[3];
gtk_widget_destroy(cs->window);
cs->window = NULL;
#ifndef NO_PREVIEW
if (do_preview && mw_do_preview!=NULL) (*mw_do_preview)(NULL);
#endif
}
static void
create_color_selection (GtkWidget *widget,
struct mwColorSel *cs)
{
if (!(cs->window)) {
cs->window = gtk_color_selection_dialog_new (cs->name);
cs->savcolor[0]=cs->color[0]; /* For the cancel .... */
cs->savcolor[1]=cs->color[1];
cs->savcolor[2]=cs->color[2];
if (cs->opacity)
cs->savcolor[3]=cs->color[3];
gtk_color_selection_set_opacity(
GTK_COLOR_SELECTION(GTK_COLOR_SELECTION_DIALOG(cs->window)->colorsel),cs->opacity);
gtk_color_selection_set_update_policy(
GTK_COLOR_SELECTION(GTK_COLOR_SELECTION_DIALOG(cs->window)->colorsel),GTK_UPDATE_DELAYED);
gtk_widget_destroy ( GTK_COLOR_SELECTION_DIALOG(cs->window)->help_button );
gtk_signal_connect (GTK_OBJECT (cs->window), "destroy",
(GtkSignalFunc) color_selection_destroy_window,
&(cs->window));
gtk_signal_connect (GTK_OBJECT(GTK_COLOR_SELECTION_DIALOG(cs->window)->colorsel),
"color_changed",(GtkSignalFunc) color_selection_changed_cb,
cs);
gtk_signal_connect (GTK_OBJECT (GTK_COLOR_SELECTION_DIALOG (cs->window)->ok_button),
"clicked", (GtkSignalFunc) color_selection_ok_cb,
cs);
gtk_signal_connect (GTK_OBJECT (GTK_COLOR_SELECTION_DIALOG (cs->window)->cancel_button),
"clicked", (GtkSignalFunc) color_selection_cancel,
cs);
}
gtk_color_selection_set_color(GTK_COLOR_SELECTION(GTK_COLOR_SELECTION_DIALOG(cs->window)->colorsel),cs->color);
gtk_window_position (GTK_WINDOW (cs->window), GTK_WIN_POS_MOUSE);
gtk_widget_show(cs->window);
}
static void
color_select_fill_button_color(GtkWidget *preview, gdouble *color)
{
gint i;
guchar buf[3*COLOR_SAMPLE_SIZE];
for (i=0;i<COLOR_SAMPLE_SIZE;i++)
{
buf[3*i] = (guchar)(255.999*color[0]);
buf[3*i+1] = (guchar)(255.999*color[1]);
buf[3*i+2] = (guchar)(255.999*color[2]);
}
for (i=0;i<COLOR_SAMPLE_SIZE;i++)
gtk_preview_draw_row(GTK_PREVIEW(preview),buf,0,i,COLOR_SAMPLE_SIZE);
gtk_widget_draw (preview, NULL);
}
/* end of megawidget/megawidget.c */

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,555 +0,0 @@
/*
* This is a plugin for the GIMP.
*
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
* Copyright (C) 1996 Torsten Martinsen
*
* 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
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id$
*/
/*
* This filter adds random noise to an image.
* The amount of noise can be set individually for each RGB channel.
* This filter does not operate on indexed images.
*/
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include "gtk/gtk.h"
#include "libgimp/gimp.h"
#define ENTRY_WIDTH 60
#define SCALE_WIDTH 125
#define TILE_CACHE_SIZE 16
typedef struct
{
gint independent;
gdouble noise[4]; /* per channel */
} NoisifyVals;
typedef struct
{
gint run;
} NoisifyInterface;
/* Declare local functions.
*/
static void query (void);
static void run (char *name,
int nparams,
GParam *param,
int *nreturn_vals,
GParam **return_vals);
static void noisify (GDrawable * drawable);
static gint noisify_dialog (gint channels);
static gdouble gauss (void);
static void noisify_close_callback (GtkWidget *widget,
gpointer data);
static void noisify_ok_callback (GtkWidget *widget,
gpointer data);
static void noisify_toggle_update (GtkWidget *widget,
gpointer data);
static void noisify_scale_update (GtkAdjustment *adjustment,
double *scale_val);
static void noisify_entry_update (GtkWidget *widget,
gdouble *value);
static void dialog_create_value (char *title,
GtkTable *table,
int row,
gdouble *value,
double left,
double right);
GPlugInInfo PLUG_IN_INFO =
{
NULL, /* init_proc */
NULL, /* quit_proc */
query, /* query_proc */
run, /* run_proc */
};
static NoisifyVals nvals =
{
TRUE,
{ 0.20, 0.20, 0.20, 0.20 }
};
static NoisifyInterface noise_int =
{
FALSE /* run */
};
MAIN ()
static void
query ()
{
static GParamDef args[] =
{
{ PARAM_INT32, "run_mode", "Interactive, non-interactive" },
{ PARAM_IMAGE, "image", "Input image (unused)" },
{ PARAM_DRAWABLE, "drawable", "Input drawable" },
{ PARAM_INT32, "independent", "Noise in channels independent" },
{ PARAM_FLOAT, "noise_1", "Noise in the first channel (red, gray)" },
{ PARAM_FLOAT, "noise_2", "Noise in the second channel (green, gray_alpha)" },
{ PARAM_FLOAT, "noise_3", "Noise in the third channel (blue)" },
{ PARAM_FLOAT, "noise_4", "Noise in the fourth channel (alpha)" }
};
static GParamDef *return_vals = NULL;
static int nargs = sizeof (args) / sizeof (args[0]);
static int nreturn_vals = 0;
gimp_install_procedure ("plug_in_noisify",
"Adds random noise to a drawable's channels",
"More here later",
"Torsten Martinsen",
"Torsten Martinsen",
"1996",
"<Image>/Filters/Distorts/Noisify",
"RGB*, GRAY*",
PROC_PLUG_IN,
nargs, nreturn_vals,
args, return_vals);
}
static void
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;
run_mode = param[0].data.d_int32;
*nreturn_vals = 1;
*return_vals = values;
values[0].type = PARAM_STATUS;
values[0].data.d_status = status;
/* Get the specified drawable */
drawable = gimp_drawable_get (param[2].data.d_drawable);
switch (run_mode)
{
case RUN_INTERACTIVE:
/* Possibly retrieve data */
gimp_get_data ("plug_in_noisify", &nvals);
/* First acquire information with a dialog */
if (! noisify_dialog (drawable->bpp))
{
gimp_drawable_detach (drawable);
return;
}
break;
case RUN_NONINTERACTIVE:
/* Make sure all the arguments are there! */
if (nparams != 8)
status = STATUS_CALLING_ERROR;
if (status == STATUS_SUCCESS)
{
nvals.independent = (param[3].data.d_int32) ? TRUE : FALSE;
nvals.noise[0] = param[4].data.d_float;
nvals.noise[1] = param[5].data.d_float;
nvals.noise[2] = param[6].data.d_float;
nvals.noise[3] = param[7].data.d_float;
}
break;
case RUN_WITH_LAST_VALS:
/* Possibly retrieve data */
gimp_get_data ("plug_in_noisify", &nvals);
break;
default:
break;
}
/* Make sure that the drawable is gray or RGB color */
if (gimp_drawable_color (drawable->id) || gimp_drawable_gray (drawable->id))
{
gimp_progress_init ("Adding Noise...");
gimp_tile_cache_ntiles (TILE_CACHE_SIZE);
/* seed the random number generator */
srand (time (NULL));
/* compute the luminosity which exceeds the luminosity threshold */
noisify (drawable);
if (run_mode != RUN_NONINTERACTIVE)
gimp_displays_flush ();
/* Store data */
if (run_mode == RUN_INTERACTIVE)
gimp_set_data ("plug_in_noisify", &nvals, sizeof (NoisifyVals));
}
else
{
/* gimp_message ("blur: cannot operate on indexed color images"); */
status = STATUS_EXECUTION_ERROR;
}
values[0].data.d_status = status;
gimp_drawable_detach (drawable);
}
static void
noisify (GDrawable *drawable)
{
GPixelRgn src_rgn, dest_rgn;
guchar *src_row, *dest_row;
guchar *src, *dest;
gint row, col, b;
gint x1, y1, x2, y2, p;
gint noise;
gint progress, max_progress;
gpointer pr;
gimp_drawable_mask_bounds (drawable->id, &x1, &y1, &x2, &y2);
gimp_pixel_rgn_init (&src_rgn, drawable, x1, y1, (x2 - x1), (y2 - y1), FALSE, FALSE);
gimp_pixel_rgn_init (&dest_rgn, drawable, x1, y1, (x2 - x1), (y2 - y1), TRUE, TRUE);
/* Initialize progress */
progress = 0;
max_progress = (x2 - x1) * (y2 - y1);
for (pr = gimp_pixel_rgns_register (2, &src_rgn, &dest_rgn); pr != NULL; pr = gimp_pixel_rgns_process (pr))
{
src_row = src_rgn.data;
dest_row = dest_rgn.data;
for (row = 0; row < src_rgn.h; row++)
{
src = src_row;
dest = dest_row;
for (col = 0; col < src_rgn.w; col++)
{
if (nvals.independent == FALSE)
noise = (gint) (nvals.noise[0] * gauss() * 127);
for (b = 0; b < src_rgn.bpp; b++)
{
if (nvals.independent == TRUE)
noise = (gint) (nvals.noise[b] * gauss() * 127);
p = src[b] + noise;
if (p < 0)
p = 0;
else if (p > 255)
p = 255;
if (nvals.noise[b] != 0)
dest[b] = p;
}
src += src_rgn.bpp;
dest += dest_rgn.bpp;
}
src_row += src_rgn.rowstride;
dest_row += dest_rgn.rowstride;
}
/* Update progress */
progress += src_rgn.w * src_rgn.h;
gimp_progress_update ((double) progress / (double) max_progress);
}
/* 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));
}
static gint
noisify_dialog (gint channels)
{
GtkWidget *dlg;
GtkWidget *button;
GtkWidget *toggle;
GtkWidget *frame;
GtkWidget *table;
gchar buffer[32];
gchar **argv;
gint argc;
int i;
argc = 1;
argv = g_new (gchar *, 1);
argv[0] = g_strdup ("noisify");
gtk_init (&argc, &argv);
gtk_rc_parse (gimp_gtkrc ());
dlg = gtk_dialog_new ();
gtk_window_set_title (GTK_WINDOW (dlg), "Noisify");
gtk_window_position (GTK_WINDOW (dlg), GTK_WIN_POS_MOUSE);
gtk_signal_connect (GTK_OBJECT (dlg), "destroy",
(GtkSignalFunc) noisify_close_callback,
NULL);
/* Action area */
button = gtk_button_new_with_label ("OK");
GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
gtk_signal_connect (GTK_OBJECT (button), "clicked",
(GtkSignalFunc) noisify_ok_callback,
dlg);
gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dlg)->action_area), button, TRUE, TRUE, 0);
gtk_widget_grab_default (button);
gtk_widget_show (button);
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));
gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dlg)->action_area), button, TRUE, TRUE, 0);
gtk_widget_show (button);
/* parameter settings */
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 (channels + 1, 3, FALSE);
gtk_container_border_width (GTK_CONTAINER (table), 10);
gtk_container_add (GTK_CONTAINER (frame), table);
toggle = gtk_check_button_new_with_label ("Independent");
gtk_table_attach (GTK_TABLE (table), toggle, 0, 2, 0, 1, GTK_FILL, 0, 0, 0);
gtk_signal_connect (GTK_OBJECT (toggle), "toggled",
(GtkSignalFunc) noisify_toggle_update,
&nvals.independent);
gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (toggle), nvals.independent);
gtk_widget_show (toggle);
/* for (i = 0; i < channels; i++)
{
sprintf (buffer, "Channel #%d", i);
dialog_create_value(buffer, GTK_TABLE(table), i+1, &nvals.noise[i], 0.0, 1.0);
}
*/
if (channels == 1)
{
sprintf (buffer, "Gray");
dialog_create_value(buffer, GTK_TABLE(table), 1, &nvals.noise[0], 0.0, 1.0);
}
else if (channels == 2)
{
sprintf (buffer, "Gray");
dialog_create_value(buffer, GTK_TABLE(table), 1, &nvals.noise[0], 0.0, 1.0);
sprintf (buffer, "Alpha");
dialog_create_value(buffer, GTK_TABLE(table), 2, &nvals.noise[1], 0.0, 1.0);
}
else if (channels == 3)
{
sprintf (buffer, "Red");
dialog_create_value(buffer, GTK_TABLE(table), 1, &nvals.noise[0], 0.0, 1.0);
sprintf (buffer, "Green");
dialog_create_value(buffer, GTK_TABLE(table), 2, &nvals.noise[1], 0.0, 1.0);
sprintf (buffer, "Blue");
dialog_create_value(buffer, GTK_TABLE(table), 3, &nvals.noise[2], 0.0, 1.0);
}
else if (channels == 4)
{
sprintf (buffer, "Red");
dialog_create_value(buffer, GTK_TABLE(table), 1, &nvals.noise[0], 0.0, 1.0);
sprintf (buffer, "Green");
dialog_create_value(buffer, GTK_TABLE(table), 2, &nvals.noise[1], 0.0, 1.0);
sprintf (buffer, "Blue");
dialog_create_value(buffer, GTK_TABLE(table), 3, &nvals.noise[2], 0.0, 1.0);
sprintf (buffer, "Alpha");
dialog_create_value(buffer, GTK_TABLE(table), 4, &nvals.noise[3], 0.0, 1.0);
}
else
{
for (i = 0; i < channels; i++)
{
sprintf (buffer, "Channel #%d", i);
dialog_create_value(buffer, GTK_TABLE(table), i+1, &nvals.noise[i], 0.0, 1.0);
}
}
gtk_widget_show (frame);
gtk_widget_show (table);
gtk_widget_show (dlg);
gtk_main ();
gdk_flush ();
return noise_int.run;
}
/*
* Return a Gaussian (aka normal) random variable.
*
* Adapted from ppmforge.c, which is part of PBMPLUS.
* The algorithm comes from:
* 'The Science Of Fractal Images'. Peitgen, H.-O., and Saupe, D. eds.
* Springer Verlag, New York, 1988.
*/
static gdouble
gauss ()
{
gint i;
gdouble sum = 0.0;
for (i = 0; i < 4; i++)
sum += rand () & 0x7FFF;
return sum * 5.28596089837e-5 - 3.46410161514;
}
/* Noisify interface functions */
static void
noisify_close_callback (GtkWidget *widget,
gpointer data)
{
gtk_main_quit ();
}
static void
noisify_ok_callback (GtkWidget *widget,
gpointer data)
{
noise_int.run = TRUE;
gtk_widget_destroy (GTK_WIDGET (data));
}
static void
noisify_toggle_update (GtkWidget *widget,
gpointer data)
{
int *toggle_val;
toggle_val = (int *) data;
if (GTK_TOGGLE_BUTTON (widget)->active)
*toggle_val = TRUE;
else
*toggle_val = FALSE;
}
/*
* Thanks to Quartic for these.
*/
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,
(right - left) / 200.0,
(right - left) / 200.0,
0.0);
gtk_signal_connect(GTK_OBJECT(scale_data), "value_changed",
(GtkSignalFunc) noisify_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, "%0.2f", *value);
gtk_entry_set_text(GTK_ENTRY(entry), buf);
gtk_signal_connect(GTK_OBJECT(entry), "changed",
(GtkSignalFunc) noisify_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
noisify_entry_update(GtkWidget *widget, gdouble *value)
{
GtkAdjustment *adjustment;
gdouble new_value;
new_value = atof(gtk_entry_get_text(GTK_ENTRY(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 */
}
static void
noisify_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, "%0.2f", *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 */
}

View File

@ -1,293 +0,0 @@
/* Normalize 1.00 --- image filter plug-in for The GIMP
*
* Copyright (C) 1997 Adam D. Moss (adam@foxbox.org)
* Very largely based on Quartic's "Contrast Autostretch"
*
* 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
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/* This plugin performs almost the same operation as the 'contrast
* autostretch' plugin, except that it won't allow the colour channels
* to normalize independently. This is actually what most people probably
* want instead of contrast-autostretch; use c-a only if you wish to remove
* an undesirable colour-tint from a source image which is supposed to
* contain pure-white and pure-black.
*/
#include <stdlib.h>
#include <stdio.h>
#include "libgimp/gimp.h"
/* Declare local functions.
*/
static void query (void);
static void run (char *name,
int nparams,
GParam *param,
int *nreturn_vals,
GParam **return_vals);
static void norma (GDrawable * drawable);
static void indexed_norma (gint32 image_ID);
GPlugInInfo PLUG_IN_INFO =
{
NULL, /* init_proc */
NULL, /* quit_proc */
query, /* query_proc */
run, /* run_proc */
};
MAIN ()
static void
query ()
{
static GParamDef args[] =
{
{ PARAM_INT32, "run_mode", "Interactive, non-interactive" },
{ PARAM_IMAGE, "image", "Input image" },
{ PARAM_DRAWABLE, "drawable", "Input drawable" },
};
static GParamDef *return_vals = NULL;
static int nargs = sizeof (args) / sizeof (args[0]);
static int nreturn_vals = 0;
gimp_install_procedure ("plug_in_normalize",
"Normalize the contrast of the specified drawable to cover all possible ranges.",
"This plugin performs almost the same operation as the 'contrast autostretch' plugin, except that it won't allow the colour channels to normalize independently. This is actually what most people probably want instead of contrast-autostretch; use c-a only if you wish to remove an undesirable colour-tint from a source image which is supposed to contain pure-white and pure-black.",
"Adam D. Moss, Federico Mena Quintero",
"Adam D. Moss, Federico Mena Quintero",
"1997",
"<Image>/Filters/Image/Normalize",
"RGB*, GRAY*, INDEXED*",
PROC_PLUG_IN,
nargs, nreturn_vals,
args, return_vals);
}
static void
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;
gint32 image_ID;
run_mode = param[0].data.d_int32;
/* Get the specified drawable */
drawable = gimp_drawable_get (param[2].data.d_drawable);
image_ID = param[1].data.d_image;
/* Make sure that the drawable is gray or RGB color */
if (gimp_drawable_color (drawable->id) || gimp_drawable_gray (drawable->id))
{
gimp_progress_init ("Normalizing...");
gimp_tile_cache_ntiles (2 * (drawable->width / gimp_tile_width () + 1));
norma (drawable);
if (run_mode != RUN_NONINTERACTIVE)
gimp_displays_flush ();
}
else if (gimp_drawable_indexed (drawable->id))
{
indexed_norma (image_ID);
/* GIMP doesn't implicitly update an image whose cmap has
changed - it probably should. */
gimp_drawable_update (drawable->id, 0, 0,
gimp_drawable_width(drawable->id),
gimp_drawable_height(drawable->id));
gimp_displays_flush ();
}
else
{
/* gimp_message ("normalize: cannot operate on indexed color images"); */
status = STATUS_EXECUTION_ERROR;
}
*nreturn_vals = 1;
*return_vals = values;
values[0].type = PARAM_STATUS;
values[0].data.d_status = status;
gimp_drawable_detach (drawable);
}
static void
indexed_norma(gint32 image_ID) /* a.d.m. */
{
guchar *cmap;
gint ncols,i;
gint hi=0,lo=255;
cmap = gimp_image_get_cmap (image_ID, &ncols);
if (cmap==NULL)
{
printf("normalize: cmap was NULL! Quitting...\n");
gimp_quit();
}
for (i=0;i<ncols;i++)
{
if (cmap[i*3 +0] > hi) hi=cmap[i*3 +0];
if (cmap[i*3 +1] > hi) hi=cmap[i*3 +1];
if (cmap[i*3 +2] > hi) hi=cmap[i*3 +2];
if (cmap[i*3 +0] < lo) lo=cmap[i*3 +0];
if (cmap[i*3 +1] < lo) lo=cmap[i*3 +1];
if (cmap[i*3 +2] < lo) lo=cmap[i*3 +2];
}
if (hi!=lo)
for (i=0;i<ncols;i++)
{
cmap[i*3 +0] = (255 * (cmap[i*3 +0] - lo)) / (hi-lo);
cmap[i*3 +1] = (255 * (cmap[i*3 +1] - lo)) / (hi-lo);
cmap[i*3 +2] = (255 * (cmap[i*3 +2] - lo)) / (hi-lo);
}
gimp_image_set_cmap (image_ID, cmap, ncols);
}
static void
norma (GDrawable *drawable)
{
GPixelRgn src_rgn, dest_rgn;
guchar *src, *s;
guchar *dest, *d;
guchar min, max;
guchar range;
guchar lut[256];
gint progress, max_progress;
gint has_alpha, alpha;
gint x1, y1, x2, y2;
gint x, y, b;
gpointer pr;
/* Get selection area */
gimp_drawable_mask_bounds (drawable->id, &x1, &y1, &x2, &y2);
has_alpha = gimp_drawable_has_alpha (drawable->id);
alpha = (has_alpha) ? drawable->bpp - 1 : drawable->bpp;
/* Initialize progress */
progress = 0;
max_progress = (x2 - x1) * (y2 - y1) * 2;
/* Get minimum and maximum values for each channel */
min = 255;
max = 0;
gimp_pixel_rgn_init (&src_rgn, drawable, x1, y1, (x2 - x1), (y2 - y1), FALSE, FALSE);
for (pr = gimp_pixel_rgns_register (1, &src_rgn); pr != NULL; pr = gimp_pixel_rgns_process (pr))
{
src = src_rgn.data;
for (y = 0; y < src_rgn.h; y++)
{
s = src;
for (x = 0; x < src_rgn.w; x++)
{
for (b = 0; b < alpha; b++)
{
if (!has_alpha || (has_alpha && s[alpha]))
{
if (s[b] < min)
min = s[b];
if (s[b] > max)
max = s[b];
}
}
s += src_rgn.bpp;
}
src += src_rgn.rowstride;
}
/* Update progress */
progress += src_rgn.w * src_rgn.h;
gimp_progress_update ((double) progress / (double) max_progress);
}
/* Calculate LUT */
range = max - min;
if (range != 0)
for (x = min; x <= max; x++)
lut[x] = 255 * (x - min) / range;
else
lut[min] = min;
/* Now substitute pixel vales */
gimp_pixel_rgn_init (&src_rgn, drawable, x1, y1, (x2 - x1), (y2 - y1), FALSE, FALSE);
gimp_pixel_rgn_init (&dest_rgn, drawable, x1, y1, (x2 - x1), (y2 - y1), TRUE, TRUE);
for (pr = gimp_pixel_rgns_register (2, &src_rgn, &dest_rgn); pr != NULL; pr = gimp_pixel_rgns_process (pr))
{
src = src_rgn.data;
dest = dest_rgn.data;
for (y = 0; y < src_rgn.h; y++)
{
s = src;
d = dest;
for (x = 0; x < src_rgn.w; x++)
{
for (b = 0; b < alpha; b++)
d[b] = lut[s[b]];
if (has_alpha)
d[alpha] = s[alpha];
s += src_rgn.bpp;
d += dest_rgn.bpp;
}
src += src_rgn.rowstride;
dest += dest_rgn.rowstride;
}
/* Update progress */
progress += src_rgn.w * src_rgn.h;
gimp_progress_update ((double) progress / (double) max_progress);
}
/* update the region */
gimp_drawable_flush (drawable);
gimp_drawable_merge_shadow (drawable->id, TRUE);
gimp_drawable_update (drawable->id, x1, y1, (x2 - x1), (y2 - y1));
}

File diff suppressed because it is too large Load Diff

View File

@ -1,463 +0,0 @@
/*
* This is a plug-in for the GIMP.
*
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
* Copyright (C) 1996 Torsten Martinsen
*
* 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
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id$
*/
#include <stdio.h>
#include "gtk/gtk.h"
#include "libgimp/gimp.h"
#define ENTRY_WIDTH 30
#define SCALE_WIDTH 125
#define HISTSIZE 256
typedef struct {
gdouble mask_size;
} OilifyVals;
typedef struct {
gint run;
} OilifyInterface;
/* Declare local functions.
*/
static void query (void);
static void run (char *name,
int nparams,
GParam *param,
int *nreturn_vals,
GParam **return_vals);
static void oilify (GDrawable * drawable);
static gint oilify_dialog ();
static void oilify_close_callback (GtkWidget *widget,
gpointer data);
static void oilify_ok_callback (GtkWidget *widget,
gpointer data);
static void oilify_scale_update (GtkAdjustment *adjustment,
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);
GPlugInInfo PLUG_IN_INFO =
{
NULL, /* init_proc */
NULL, /* quit_proc */
query, /* query_proc */
run, /* run_proc */
};
static OilifyVals ovals =
{
7.0 /* mask size */
};
static OilifyInterface oint =
{
FALSE /* run */
};
MAIN ()
static void
query ()
{
static GParamDef args[] =
{
{ PARAM_INT32, "run_mode", "Interactive, non-interactive" },
{ PARAM_IMAGE, "image", "Input image (unused)" },
{ PARAM_DRAWABLE, "drawable", "Input drawable" },
{ PARAM_INT32, "mask_size", "Oil paint mask size" },
};
static GParamDef *return_vals = NULL;
static int nargs = sizeof (args) / sizeof (args[0]);
static int nreturn_vals = 0;
gimp_install_procedure ("plug_in_oilify",
"Modify the specified drawable to resemble an oil painting",
"This function performs the well-known oil-paint effect on the specified drawable. The size of the input mask is specified by 'mask_size'.",
"Torsten Martinsen",
"Torsten Martinsen",
"1996",
"<Image>/Filters/Artistic/Oilify",
"RGB*, GRAY*",
PROC_PLUG_IN,
nargs, nreturn_vals,
args, return_vals);
}
static void
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;
run_mode = param[0].data.d_int32;
*nreturn_vals = 1;
*return_vals = values;
values[0].type = PARAM_STATUS;
values[0].data.d_status = status;
switch (run_mode)
{
case RUN_INTERACTIVE:
/* Possibly retrieve data */
gimp_get_data ("plug_in_oilify", &ovals);
/* First acquire information with a dialog */
if (! oilify_dialog ())
return;
break;
case RUN_NONINTERACTIVE:
/* Make sure all the arguments are there! */
if (nparams != 4)
status = STATUS_CALLING_ERROR;
if (status == STATUS_SUCCESS)
{
ovals.mask_size = (gdouble) param[3].data.d_int32;
}
if (status == STATUS_SUCCESS &&
(ovals.mask_size < 1.0))
status = STATUS_CALLING_ERROR;
break;
case RUN_WITH_LAST_VALS:
/* Possibly retrieve data */
gimp_get_data ("plug_in_oilify", &ovals);
break;
default:
break;
}
/* Get the specified drawable */
drawable = gimp_drawable_get (param[2].data.d_drawable);
/* Make sure that the drawable is gray or RGB color */
if ((status == STATUS_SUCCESS) &&
(gimp_drawable_color (drawable->id) || gimp_drawable_gray (drawable->id)))
{
gimp_progress_init ("Oil Painting...");
gimp_tile_cache_ntiles (2 * (drawable->width / gimp_tile_width () + 1));
oilify (drawable);
if (run_mode != RUN_NONINTERACTIVE)
gimp_displays_flush ();
/* Store data */
if (run_mode == RUN_INTERACTIVE)
gimp_set_data ("plug_in_oilify", &ovals, sizeof (OilifyVals));
}
else
{
/* gimp_message ("oilify: cannot operate on indexed color images"); */
status = STATUS_EXECUTION_ERROR;
}
values[0].data.d_status = status;
gimp_drawable_detach (drawable);
}
/*
* 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).
*/
static void
oilify (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, px, xx, yy, n;
gint x1, y1, x2, y2;
gint x3, y3, x4, y4;
gint Val[4];
gint Cnt[4];
gint Hist[4][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++)
{
for (b = 0; b < bytes; b++)
{
Cnt[b] = 0;
Val[b] = 0;
for (i = 0; i < HISTSIZE; i++)
Hist[b][i] = 0;
}
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);
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; b < bytes; b++)
{
if ((c = ++Hist[b][px = src[b]]) > Cnt[b])
{
Val[b] = px;
Cnt[b] = c;
}
}
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;
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));
}
static gint
oilify_dialog ()
{
GtkWidget *dlg;
GtkWidget *button;
GtkWidget *frame;
GtkWidget *table;
gchar **argv;
gint argc;
argc = 1;
argv = g_new (gchar *, 1);
argv[0] = g_strdup ("oilify");
gtk_init (&argc, &argv);
gtk_rc_parse (gimp_gtkrc ());
dlg = gtk_dialog_new ();
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);
/* Action area */
button = gtk_button_new_with_label ("OK");
GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
gtk_signal_connect (GTK_OBJECT (button), "clicked",
(GtkSignalFunc) oilify_ok_callback,
dlg);
gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dlg)->action_area), button, TRUE, TRUE, 0);
gtk_widget_grab_default (button);
gtk_widget_show (button);
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));
gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dlg)->action_area), button, TRUE, TRUE, 0);
gtk_widget_show (button);
/* parameter settings */
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 (2, 3, FALSE);
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);
gtk_widget_show (frame);
gtk_widget_show (table);
gtk_widget_show (dlg);
gtk_main ();
gdk_flush ();
return oint.run;
}
/* Oilify interface functions */
static void
oilify_close_callback (GtkWidget *widget,
gpointer data)
{
gtk_main_quit ();
}
static void
oilify_ok_callback (GtkWidget *widget,
gpointer data)
{
oint.run = TRUE;
gtk_widget_destroy (GTK_WIDGET (data));
}
/*
* Thanks to Quartic for these.
*/
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);
}
static void
oilify_entry_update(GtkWidget *widget, gdouble *value)
{
GtkAdjustment *adjustment;
gdouble new_value;
new_value = atof(gtk_entry_get_text(GTK_ENTRY(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 */
}
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 */
}

View File

@ -1,406 +0,0 @@
/*
* pat plug-in version 1.01
* Loads/saves version 1 GIMP .pat files, by Tim Newsome <drz@frody.bloke.com>
* Some bits stolen from the .99.7 source tree.
*/
#include <setjmp.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include "gtk/gtk.h"
#include "libgimp/gimp.h"
#include "app/pattern_header.h"
#include <netinet/in.h>
/* Declare local data types
*/
char description[256] = "GIMP Pattern";
int run_flag = 0;
/* Declare some local functions.
*/
static void query (void);
static void run (char *name,
int nparams,
GParam *param,
int *nreturn_vals,
GParam **return_vals);
static gint32 load_image (char *filename);
static gint save_image (char *filename,
gint32 image_ID,
gint32 drawable_ID);
static gint save_dialog ();
static void close_callback(GtkWidget * widget, gpointer data);
static void ok_callback(GtkWidget * widget, gpointer data);
static void entry_callback(GtkWidget * widget, gpointer data);
GPlugInInfo PLUG_IN_INFO =
{
NULL, /* init_proc */
NULL, /* quit_proc */
query, /* query_proc */
run, /* run_proc */
};
MAIN ()
static void
query ()
{
static GParamDef load_args[] =
{
{ PARAM_INT32, "run_mode", "Interactive, non-interactive" },
{ PARAM_STRING, "filename", "The name of the file to load" },
{ PARAM_STRING, "raw_filename", "The name of the file to load" },
};
static GParamDef load_return_vals[] =
{
{ PARAM_IMAGE, "image", "Output image" },
};
static int nload_args = sizeof (load_args) / sizeof (load_args[0]);
static int nload_return_vals = sizeof (load_return_vals) / sizeof (load_return_vals[0]);
static GParamDef save_args[] =
{
{ PARAM_INT32, "run_mode", "Interactive, non-interactive" },
{ PARAM_IMAGE, "image", "Input image" },
{ PARAM_DRAWABLE, "drawable", "Drawable to save" },
{ PARAM_STRING, "filename", "The name of the file to save the image in" },
{ PARAM_STRING, "raw_filename", "The name of the file to save the image in" },
{ PARAM_STRING, "description", "Short description of the pattern" },
};
static int nsave_args = sizeof (save_args) / sizeof (save_args[0]);
gimp_install_procedure ("file_pat_load",
"loads files of the .pat file format",
"FIXME: write help",
"Tim Newsome",
"Tim Newsome",
"1997",
"<Load>/PAT",
NULL,
PROC_PLUG_IN,
nload_args, nload_return_vals,
load_args, load_return_vals);
gimp_install_procedure ("file_pat_save",
"saves files in the .pat file format",
"Yeah!",
"Tim Newsome",
"Tim Newsome",
"1997",
"<Save>/PAT",
"RGB*, GRAY*",
PROC_PLUG_IN,
nsave_args, 0,
save_args, NULL);
gimp_register_magic_load_handler ("file_pat_load", "pat", "", "20,string,GPAT");
gimp_register_save_handler ("file_pat_save", "pat", "");
}
static void
run (char *name,
int nparams,
GParam *param,
int *nreturn_vals,
GParam **return_vals)
{
static GParam values[2];
GRunModeType run_mode;
gint32 image_ID;
GStatusType status = STATUS_SUCCESS;
run_mode = param[0].data.d_int32;
*return_vals = values;
values[0].type = PARAM_STATUS;
values[0].data.d_status = STATUS_CALLING_ERROR;
values[1].type = PARAM_IMAGE;
values[1].data.d_image = -1;
if (strcmp (name, "file_pat_load") == 0) {
image_ID = load_image (param[1].data.d_string);
if (image_ID != -1) {
values[0].data.d_status = STATUS_SUCCESS;
values[1].data.d_image = image_ID;
} else {
values[0].data.d_status = STATUS_EXECUTION_ERROR;
}
*nreturn_vals = 2;
}
else if (strcmp (name, "file_pat_save") == 0) {
switch (run_mode) {
case RUN_INTERACTIVE:
/* Possibly retrieve data */
gimp_get_data("file_pat_save", description);
if (!save_dialog())
return;
break;
case RUN_NONINTERACTIVE:
if (nparams != 6)
status = STATUS_CALLING_ERROR;
case RUN_WITH_LAST_VALS:
gimp_get_data ("file_pat_save", description);
break;
}
if (save_image (param[3].data.d_string, param[1].data.d_int32,
param[2].data.d_int32)) {
gimp_set_data ("file_pat_save", description, 256);
values[0].data.d_status = STATUS_SUCCESS;
} else
values[0].data.d_status = STATUS_EXECUTION_ERROR;
*nreturn_vals = 1;
}
}
static gint32 load_image (char *filename) {
char *temp;
int fd;
PatternHeader ph;
gchar *buffer;
gint32 image_ID, layer_ID;
GDrawable *drawable;
gint line;
GPixelRgn pixel_rgn;
temp = g_malloc(strlen (filename) + 11);
sprintf(temp, "Loading %s:", filename);
gimp_progress_init(temp);
g_free (temp);
fd = open(filename, O_RDONLY);
if (fd == -1) {
return -1;
}
if (read(fd, &ph, sizeof(ph)) != sizeof(ph)) {
close(fd);
return -1;
}
/* rearrange the bytes in each unsigned int */
ph.header_size = ntohl(ph.header_size);
ph.version = ntohl(ph.version);
ph.width = ntohl(ph.width);
ph.height = ntohl(ph.height);
ph.bytes = ntohl(ph.bytes);
ph.magic_number = ntohl(ph.magic_number);
if (ph.magic_number != GPATTERN_MAGIC || ph.version != 1 ||
ph.header_size <= sizeof(ph)) {
close(fd);
return -1;
}
if (lseek(fd, ph.header_size - sizeof(ph), SEEK_CUR) !=
ph.header_size) {
close(fd);
return -1;
}
/* Now there's just raw data left. */
/*
* Create a new image of the proper size and associate the filename with it.
*/
image_ID = gimp_image_new(ph.width, ph.height, (ph.bytes >= 3) ? RGB : GRAY);
gimp_image_set_filename(image_ID, filename);
layer_ID = gimp_layer_new(image_ID, "Background", ph.width, ph.height,
(ph.bytes >= 3) ? RGB_IMAGE : GRAY_IMAGE, 100, NORMAL_MODE);
gimp_image_add_layer(image_ID, layer_ID, 0);
drawable = gimp_drawable_get(layer_ID);
gimp_pixel_rgn_init(&pixel_rgn, drawable, 0, 0, drawable->width,
drawable->height, TRUE, FALSE);
buffer = g_malloc(ph.width * ph.bytes);
for (line = 0; line < ph.height; line++) {
if (read(fd, buffer, ph.width * ph.bytes) != ph.width * ph.bytes) {
close(fd);
g_free(buffer);
return -1;
}
gimp_pixel_rgn_set_row(&pixel_rgn, buffer, 0, line, ph.width);
gimp_progress_update((double) line / (double) ph.height);
}
gimp_drawable_flush(drawable);
return image_ID;
}
static gint save_image (char *filename, gint32 image_ID, gint32 drawable_ID) {
int fd;
PatternHeader ph;
unsigned char *buffer;
GDrawable *drawable;
gint line;
GPixelRgn pixel_rgn;
char *temp;
temp = g_malloc(strlen (filename) + 10);
sprintf(temp, "Saving %s:", filename);
gimp_progress_init(temp);
g_free(temp);
drawable = gimp_drawable_get(drawable_ID);
gimp_pixel_rgn_init(&pixel_rgn, drawable, 0, 0, drawable->width,
drawable->height, FALSE, FALSE);
fd = open(filename, O_CREAT | O_TRUNC | O_WRONLY, 0644);
if (fd == -1) {
return 0;
}
ph.header_size = htonl(sizeof(ph) + strlen(description) + 1);
ph.version = htonl(1);
ph.width = htonl(drawable->width);
ph.height = htonl(drawable->height);
ph.bytes = htonl(drawable->bpp);
ph.magic_number = htonl(GPATTERN_MAGIC);
if (write(fd, &ph, sizeof(ph)) != sizeof(ph)) {
close(fd);
return 0;
}
if (write(fd, description, strlen(description) + 1) !=
strlen(description) + 1) {
close(fd);
return 0;
}
buffer = g_malloc(drawable->width * drawable->bpp);
if (buffer == NULL) {
close(fd);
return 0;
}
for (line = 0; line < drawable->height; line++) {
gimp_pixel_rgn_get_row(&pixel_rgn, buffer, 0, line, drawable->width);
if (write(fd, buffer, drawable->width * drawable->bpp) !=
drawable->width * drawable->bpp) {
close(fd);
return 0;
}
gimp_progress_update((double) line / (double) drawable->height);
}
g_free(buffer);
close(fd);
return 1;
}
static gint save_dialog()
{
GtkWidget *dlg;
GtkWidget *button;
GtkWidget *label;
GtkWidget *entry;
GtkWidget *table;
gchar **argv;
gint argc;
argc = 1;
argv = g_new(gchar *, 1);
argv[0] = g_strdup("plasma");
gtk_init(&argc, &argv);
gtk_rc_parse (gimp_gtkrc ());
dlg = gtk_dialog_new();
gtk_window_set_title(GTK_WINDOW(dlg), "Save As Pattern");
gtk_window_position(GTK_WINDOW(dlg), GTK_WIN_POS_MOUSE);
gtk_signal_connect(GTK_OBJECT(dlg), "destroy",
(GtkSignalFunc) close_callback, NULL);
/* Action area */
button = gtk_button_new_with_label("OK");
GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT);
gtk_signal_connect(GTK_OBJECT(button), "clicked",
(GtkSignalFunc) ok_callback,
dlg);
gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dlg)->action_area), button, TRUE, TRUE, 0);
gtk_widget_grab_default(button);
gtk_widget_show(button);
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));
gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dlg)->action_area), button, TRUE, TRUE, 0);
gtk_widget_show(button);
/* The main table */
/* Set its size (y, x) */
table = gtk_table_new(1, 2, FALSE);
gtk_container_border_width(GTK_CONTAINER(table), 10);
gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dlg)->vbox), table, TRUE, TRUE, 0);
gtk_widget_show(table);
gtk_table_set_row_spacings(GTK_TABLE(table), 10);
gtk_table_set_col_spacings(GTK_TABLE(table), 10);
/**********************
* label
**********************/
label = gtk_label_new("Description:");
gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
gtk_table_attach(GTK_TABLE(table), label, 0, 1, 0, 1, GTK_FILL, GTK_FILL, 0,
0);
gtk_widget_show(label);
/************************
* The entry
************************/
entry = gtk_entry_new();
gtk_table_attach(GTK_TABLE(table), entry, 1, 2, 0, 1, GTK_EXPAND | GTK_FILL,
GTK_EXPAND | GTK_FILL, 0, 0);
gtk_widget_set_usize(entry, 200, 0);
gtk_entry_set_text(GTK_ENTRY(entry), description);
gtk_signal_connect(GTK_OBJECT(entry), "changed",
(GtkSignalFunc) entry_callback, description);
gtk_widget_show(entry);
gtk_widget_show(dlg);
gtk_main();
gdk_flush();
return run_flag;
}
static void close_callback(GtkWidget * widget, gpointer data)
{
gtk_main_quit();
}
static void ok_callback(GtkWidget * widget, gpointer data)
{
run_flag = 1;
gtk_widget_destroy(GTK_WIDGET(data));
}
static void entry_callback(GtkWidget * widget, gpointer data)
{
if (data == description)
strncpy(description, gtk_entry_get_text(GTK_ENTRY(widget)), 256);
}

View File

@ -1,724 +0,0 @@
/* PCX loading and saving file filter for the Gimp
* -Francisco Bustamante
*
* This filter's code is based on the GIF loading/saving filter for the GIMP,
* by Peter Mattis, and Spencer Kimball. However, code from the "netpbm" package
* is no longer used in this plug-in.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "gtk/gtk.h"
#include "libgimp/gimp.h"
/* Declare some local functions.
*/
static void query (void);
static void run (char *name,
int nparams,
GParam *param,
int *nreturn_vals,
GParam **return_vals);
static gint32 load_image (char *filename);
static gint save_image (char *filename,
gint32 image_ID,
gint32 drawable_ID);
GPlugInInfo PLUG_IN_INFO =
{
NULL, /* init_proc */
NULL, /* quit_proc */
query, /* query_proc */
run, /* run_proc */
};
MAIN ()
static void
query ()
{
static GParamDef load_args[] =
{
{ PARAM_INT32, "run_mode", "Interactive, non-interactive" },
{ PARAM_STRING, "filename", "The name of the file to load" },
{ PARAM_STRING, "raw_filename", "The name entered" },
};
static GParamDef load_return_vals[] =
{
{ PARAM_IMAGE, "image", "Output image" },
};
static int nload_args = sizeof (load_args) / sizeof (load_args[0]);
static int nload_return_vals = sizeof (load_return_vals) / sizeof (load_return_vals[0]);
static GParamDef save_args[] =
{
{ PARAM_INT32, "run_mode", "Interactive, non-interactive" },
{ PARAM_IMAGE, "image", "Input image" },
{ PARAM_DRAWABLE, "drawable", "Drawable to save" },
{ PARAM_STRING, "filename", "The name of the file to save the image in" },
{ PARAM_STRING, "raw_filename", "The name entered" },
};
static int nsave_args = sizeof (save_args) / sizeof (save_args[0]);
gimp_install_procedure ("file_pcx_load",
"Loads files of Zsoft PCX file format",
"FIXME: write help for pcx_load",
"Francisco Bustamante",
"Francisco Bustamante",
"1997",
"<Load>/PCX",
NULL,
PROC_PLUG_IN,
nload_args, nload_return_vals,
load_args, load_return_vals);
gimp_install_procedure ("file_pcx_save",
"Saves files in ZSoft PCX file format",
"FIXME: write help for pcx_save",
"Francisco Bustamante",
"Francisco Bustamante",
"1997",
"<Save>/PCX",
"INDEXED*",
PROC_PLUG_IN,
nsave_args, 0,
save_args, NULL);
gimp_register_magic_load_handler ("file_pcx_load", "pcx", "",
"0&,byte,10,2&,byte,1,3&,byte,>0,3,byte,<9");
gimp_register_save_handler ("file_pcx_save", "pcx", "");
}
static void
run (char *name,
int nparams,
GParam *param,
int *nreturn_vals,
GParam **return_vals)
{
static GParam values[2];
GStatusType status = STATUS_SUCCESS;
GRunModeType run_mode;
gint32 image_ID;
run_mode = param[0].data.d_int32;
*nreturn_vals = 1;
*return_vals = values;
values[0].type = PARAM_STATUS;
values[0].data.d_status = STATUS_CALLING_ERROR;
if (strcmp (name, "file_pcx_load") == 0)
{
image_ID = load_image (param[1].data.d_string);
if (image_ID != -1)
{
*nreturn_vals = 2;
values[0].data.d_status = STATUS_SUCCESS;
values[1].type = PARAM_IMAGE;
values[1].data.d_image = image_ID;
}
else
{
values[0].data.d_status = STATUS_EXECUTION_ERROR;
}
}
else if (strcmp (name, "file_pcx_save") == 0)
{
switch (run_mode)
{
case RUN_INTERACTIVE:
/* Possibly retrieve data */
/*gimp_get_data ("file_pcx_save", &gsvals);*/
/* First acquire information with a dialog */
/* return;*/
break;
case RUN_NONINTERACTIVE:
/* Make sure all the arguments are there! */
if (nparams != 5)
status = STATUS_CALLING_ERROR;
break;
case RUN_WITH_LAST_VALS:
/* Possibly retrieve data */
/* gimp_get_data ("file_pcx_save", &gsvals);*/
break;
default:
break;
}
*nreturn_vals = 1;
if (save_image (param[3].data.d_string, param[1].data.d_int32, param[2].data.d_int32))
{
/* Store psvals data */
/* gimp_set_data ("file_pcx_save", &gsvals, sizeof (GIFSaveVals));*/
values[0].data.d_status = STATUS_SUCCESS;
}
else
values[0].data.d_status = STATUS_EXECUTION_ERROR;
}
}
#define MAXCOLORMAPSIZE 256
#define TRUE 1
#define FALSE 0
#define OK 0
#define ERROR 1
#define CM_RED 0
#define CM_GREEN 1
#define CM_BLUE 2
#define BitSet(byte, bit) (((byte) & (bit)) == (bit))
#define ReadOK(file,buffer,len) (fread(buffer, len, 1, file) != 0)
#define GRAYSCALE 1
#define COLOR 2
#define RGB 3
typedef unsigned char CMap[3][MAXCOLORMAPSIZE];
static struct {
unsigned char manufacturer;
unsigned char version;
unsigned char encoding;
unsigned char bitsperpixel;
short int x1, y1;
short int x2, y2;
short int hdpi;
short int vdpi;
unsigned char colormap[48];
unsigned char reserved;
unsigned char nplanes;
short int bytesperline;
short int paletteinfo;
short int hscreensize;
short int vscreensize;
unsigned char filler[54];
} pcx_header;
int verbose = TRUE;
static gint32 ReadImage (FILE *, char *, int, int, int, int, int);
static gint32
load_image (char *filename)
{
FILE *fd;
char * name_buf;
int imageCount = 0;
gint32 image_ID = -1;
int img_height, img_width;
short int bpp;
name_buf = g_malloc (strlen (filename) + 11);
sprintf (name_buf, "Loading %s:", filename);
gimp_progress_init (name_buf);
g_free (name_buf);
fd = fopen (filename, "rb");
if (!fd) {
printf ("PCX: can't open \"%s\"\n", filename);
return -1;
}
if(!ReadOK(fd, &pcx_header, 128)) {
printf("PCX: error reading file \"%s\"\n", filename);
return -1;
}
if(pcx_header.manufacturer != 10) {
printf ("PCX: error reading magic number\n");
return -1;
}
bpp = pcx_header.bitsperpixel * pcx_header.nplanes;
++imageCount;
img_width = pcx_header.x2 - pcx_header.x1 + 1;
img_height = pcx_header.y2 - pcx_header.y1 + 1;
image_ID = ReadImage (fd, filename,
img_width,
img_height,
MAXCOLORMAPSIZE,
COLOR,
imageCount);
return image_ID;
}
int
load_monochrome(FILE *fp,
int len,
int height,
char *buffer,
int bytes_per_line);
int
load_8bit(FILE *fp,
int len,
int height,
char *buffer,
int bytes_per_line);
int
load_24bit(FILE *fp,
int len,
int height,
char *buffer,
int bytes_per_line);
static gint32
ReadImage (FILE *fd,
char *filename,
int len,
int height,
int ncols,
int format,
int number)
{
static gint32 image_ID;
gint32 layer_ID;
/* gint32 mask_ID; */
GPixelRgn pixel_rgn;
GDrawable *drawable;
guchar *dest;
guchar gimp_cmap[768];
static gint frame_number = 1;
int bpp;
gint cur_progress, max_progress;
gint i, j;
gchar framename[20];
gboolean alpha_frame = FALSE;
if (frame_number == 1 )
{
image_ID = gimp_image_new (len, height, INDEXED);
gimp_image_set_filename (image_ID, filename);
layer_ID = gimp_layer_new (image_ID, "Background",
len, height,
INDEXED_IMAGE, 100, NORMAL_MODE);
}
else
{
sprintf(framename, "Frame %d", frame_number);
layer_ID = gimp_layer_new (image_ID, framename,
len, height,
INDEXEDA_IMAGE, 100, NORMAL_MODE);
alpha_frame = TRUE;
}
frame_number++;
bpp = pcx_header.bitsperpixel * pcx_header.nplanes;
gimp_image_add_layer (image_ID, layer_ID, 0);
drawable = gimp_drawable_get (layer_ID);
cur_progress = 0;
max_progress = height;
if (alpha_frame)
dest = (guchar *) g_malloc (len * height * 2);
else
dest = (guchar *) g_malloc (len * height);
if (verbose)
printf ("PCX: reading %d by %d PCX image, ncols=%d\n",
len, height, ncols);
if((bpp == 1) && !alpha_frame) {
load_monochrome(fd, len, height, dest, pcx_header.bytesperline);
}
else if((bpp == 8) && !alpha_frame) {
load_8bit(fd, len, height, dest, pcx_header.bytesperline);
}
else {
return -1;
}
if((pcx_header.bitsperpixel == 8) && (pcx_header.nplanes == 1)) {
fseek(fd, -768L, SEEK_END);
for (i = 0, j = 0; i < ncols; i++) {
gimp_cmap[j++] = fgetc(fd);
gimp_cmap[j++] = fgetc(fd);
gimp_cmap[j++] = fgetc(fd);
}
}
else if(pcx_header.bitsperpixel == 1) {
gimp_cmap[0] = 0;
gimp_cmap[1] = 0;
gimp_cmap[2] = 0;
gimp_cmap[3] = 255;
gimp_cmap[4] = 255;
gimp_cmap[5] = 255;
}
gimp_pixel_rgn_init (&pixel_rgn, drawable, 0, 0, drawable->width, drawable->height, TRUE, FALSE);
gimp_pixel_rgn_set_rect (&pixel_rgn, dest, 0, 0, drawable->width, drawable->height);
g_free (dest);
gimp_image_set_cmap (image_ID, gimp_cmap, ncols);
gimp_drawable_flush (drawable);
gimp_drawable_detach (drawable);
return image_ID;
} /*read_image*/
int
load_monochrome(FILE *fp,
int len,
int height,
char *buffer,
int bytes_per_line)
{
guchar *temp;
gint v;
gint cur_x = 0, cur_y = 0;
gint times;
gint cur_progress = 0, max_progress = height;
int cur_bit;
while((cur_y < height) && (!feof(fp))) {
v = fgetc(fp);
if(v >= 192) {
times = v - 192;
v = fgetc(fp);
while(times > 0) {
times --;
for(cur_bit = 7; cur_bit >= 0; cur_bit--) {
temp = buffer + (cur_y * len) + cur_x;
if(BitSet(v, 1 << cur_bit)) {
*temp = 1;
}
else {
*temp = 0;
}
++cur_x;
if(cur_x == len) {
cur_x = 0;
++cur_y;
cur_progress++;
if ((cur_progress % 10) == 0)
gimp_progress_update ((double) cur_progress / (double) max_progress);
}
}
}
}
else {
for(cur_bit = 7; cur_bit >= 0; cur_bit --) {
temp = buffer + (cur_y * len) + cur_x;
if(BitSet(v, 1 << cur_bit)) {
*temp = 1;
}
else *temp = 0;
++cur_x;
if(cur_x == len) {
cur_x = 0;
++cur_y;
cur_progress++;
if ((cur_progress % 10) == 0)
gimp_progress_update ((double) cur_progress / (double) max_progress);
}
}
}
if(cur_x == len) {
cur_x = 0;
++cur_y;
cur_progress++;
if ((cur_progress % 10) == 0)
gimp_progress_update ((double) cur_progress / (double) max_progress);
}
if(cur_y == height)
break;
}
return OK;
}
int
load_8bit(FILE *fp,
int len,
int height,
char *buffer,
int bytes_per_line)
{
guchar *temp;
gint v;
gint cur_progress = 0, max_progress = height;
gint times;
gint cur_x = 0, cur_y = 0;
while(cur_y < height) {
v = fgetc(fp);
if(v >= 192) {
times = v - 192;
v = fgetc(fp);
while(times > 0) {
times--;
temp = buffer + (cur_y * len) + cur_x;
*temp = v;
++cur_x;
if(cur_x == len) {
cur_x = 0;
cur_y ++;
cur_progress++;
if ((cur_progress % 10) == 0)
gimp_progress_update ((double) cur_progress / (double) max_progress);
}
}
}
else {
temp = buffer + (cur_y * len) + cur_x;
*temp = v;
++cur_x;
if(cur_x == len) {
cur_x = 0;
cur_y ++;
cur_progress++;
if((cur_progress % 10) == 0)
gimp_progress_update((double) cur_progress / (double) max_progress);
}
}
if(cur_x == len) {
cur_x = 0;
cur_y ++;
cur_progress++;
if((cur_progress % 10) == 0)
gimp_progress_update((double) cur_progress / (double) max_progress);
}
}
return OK;
}
int
load_24bit(FILE *fp,
int len,
int height,
char *buffer,
int bytes_per_line)
{
return OK;
}
#define MAXCOLORS 256
gint
colorstobpp(int colors);
gint
save_8bit(FILE *out,
guchar *buffer,
int len,
int height);
guchar *pixels;
gint
save_image (char *filename,
gint32 image_ID,
gint32 drawable_ID)
{
GPixelRgn pixel_rgn;
GDrawable *drawable;
GDrawableType drawable_type;
int Red[MAXCOLORS];
int Green[MAXCOLORS];
int Blue[MAXCOLORS];
guchar *cmap;
int width, height;
int bpp;
int colors;
guchar *temp;
FILE *outfile;
guchar *name_buf;
gint cur_progress = 0, max_progress;
int i;
drawable = gimp_drawable_get(drawable_ID);
drawable_type = gimp_drawable_type(drawable_ID);
gimp_pixel_rgn_init(&pixel_rgn, drawable, 0, 0, drawable->width, drawable->height, FALSE, FALSE);
name_buf = (guchar *) g_malloc(strlen(filename) + 11);
sprintf(name_buf, "Saving %s:", filename);
gimp_progress_init(name_buf);
g_free(name_buf);
max_progress = drawable->height;
switch(drawable_type) {
case INDEXED_IMAGE :
cmap = gimp_image_get_cmap(image_ID, &colors);
for(i = 0; i < colors; i++) {
Red[i] = *cmap++;
Green[i] = *cmap++;
Blue[i] = *cmap++;
}
for( ; i < 256; i++) {
Red[i] = 0;
Green[i] = 0;
Blue[i] = 0;
}
bpp = colorstobpp(colors);
break;
case INDEXEDA_IMAGE : case RGBA_IMAGE :
fprintf(stderr, "PCX: unable to save alpha images");
return FALSE;
break;
case RGB_IMAGE :
bpp = 24;
break;
default :
fprintf(stderr, "PCX: you should not receive this error for any reason\n");
break;
}
if((outfile = fopen(filename, "wb")) == NULL) {
fprintf(stderr, "PCX: Can't open \"%s\"\n", filename);
return FALSE;
}
pixels = (guchar *) g_malloc(drawable->width * drawable->height);
gimp_pixel_rgn_get_rect(&pixel_rgn, pixels, 0, 0, drawable->width, drawable->height);
width = drawable->width;
height = drawable->height;
pcx_header.manufacturer = 10;
pcx_header.version = 5;
pcx_header.encoding = 1;
pcx_header.x1 = 0;
pcx_header.y1 = 0;
pcx_header.x2 = width - 1;
pcx_header.y2 = height - 1;
pcx_header.paletteinfo = 1;
if(bpp <= 8) {
pcx_header.bitsperpixel = 8;
pcx_header.nplanes = 1;
}
else {
pcx_header.bitsperpixel = 8;
pcx_header.nplanes = 3;
}
pcx_header.hdpi = 300;
pcx_header.vdpi = 300;
pcx_header.reserved = 0;
if(bpp <= 4) {
for(i = 0; i < colors; i++) {
pcx_header.colormap[(i*3)] = Red[i];
pcx_header.colormap[(i*3) + 1] = Green[i];
pcx_header.colormap[(i*3) + 2] = Blue[i];
}
}
fwrite(&pcx_header, 128, 1, outfile);
if(bpp == 8) {
save_8bit(outfile, pixels, width, height);
fputc(0x0c, outfile);
fputc(0x0c, outfile);
for(i = 0; i <= 255; i++) {
fputc(Red[i], outfile);
fputc(Green[i], outfile);
fputc(Blue[i], outfile);
}
}
gimp_drawable_detach(drawable);
g_free(pixels);
fclose(outfile);
return TRUE;
}
gint
save_8bit(FILE *out,
guchar *buffer,
int len,
int height)
{
guchar *temp;
int times;
gint max;
unsigned char v;
gint cur_x = 0, cur_y = 0;
gint cur_progress = 0, max_progress = height;
printf("saving %d * %d\n", len, height);
while(cur_y < height) {
while(cur_x <= len) {
temp = (cur_y * len) + cur_x + buffer;
v = *temp;
times = 1;
++cur_x;
temp = (cur_y * len) + cur_x + buffer;
if(cur_x + 63 > len) {
max = len;
}
else
max = cur_x + 63;
while((*temp == v) && (cur_x < max)) {
times ++;
temp = (cur_y * len) + cur_x + buffer;
cur_x ++;
}
if(times == 1) {
if(v >= 0xC0) {
fputc(0xC0 + 1, out);
fputc(v, out);
}
else fputc(v, out);
}
else {
max = 0xC0 + times;
fputc(max, out);
fputc(v, out);
}
}
cur_x = 0;
cur_y++;
cur_progress++;
if((cur_progress % 10) == 0)
gimp_progress_update((double) cur_progress / (double) max_progress);
}
return OK;
}
gint
colorstobpp(int colors) {
int bpp;
if(colors <= 2)
bpp = 1;
else if(colors <= 4)
bpp = 2;
else if(colors <= 16)
bpp = 4;
else if(colors <= 256)
bpp = 8;
else
bpp = 24;
return bpp;
}
/* The End */

View File

@ -1,594 +0,0 @@
/* The GIMP -- an image manipulation program
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
* Alias|Wavefront pix/matte image reading and writing code
* Copyright (C) 1997 Mike Taylor
* (email: mtaylor@aw.sgi.com, WWW: http://reality.sgi.com/mtaylor)
*
* 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
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
/* This plug-in was written using the online documentation from
* Alias|Wavefront Inc's PowerAnimator product.
*
* Bug reports or suggestions should be e-mailed to mtaylor@aw.sgi.com
*/
/* Event history:
* V 1.0, MT, 02-Jul-97: initial version of plug-in
*/
/* Features
* - loads and saves
* - 24-bit (.pix)
* - 8-bit (.matte, .alpha, or .mask) images
*
* NOTE: pix and matte files do not support alpha channels or indexed
* colour, so neither does this plug-in
*/
static char ident[] = "@(#) GIMP Alias|Wavefront pix image file-plugin v1.0 24-jun-97";
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <gtk/gtk.h>
#include <libgimp/gimp.h>
/* #define PIX_DEBUG */
#ifdef PIX_DEBUG
# define PIX_DEBUG_PRINT(a,b) fprintf(stderr,a,b)
#else
# define PIX_DEBUG_PRINT(a,b)
#endif
/**************
* Prototypes *
**************/
/* Standard Plug-in Functions */
static void query ();
static void run ( char *name, int nparams, GParam *param,
int *nreturn_vals, GParam **return_vals );
/* Local Helper Functions */
static gint32 load_image( char *filename );
static gint save_image( char *filename, gint32 image_ID, gint32 drawable_ID );
static guint16 get_short( FILE * file );
static void put_short( guint16 value, FILE * file );
static guint32 get_long( FILE * file );
static gchar get_char( FILE * file );
/******************
* Implementation *
******************/
GPlugInInfo PLUG_IN_INFO =
{
NULL, /* init_proc */
NULL, /* quit_proc */
query, /* query_proc */
run, /* run_proc */
};
MAIN ()
static void query ()
/*
* Description:
* Register the services provided by this plug-in
*/
{
static GParamDef load_args[] = {
{ PARAM_INT32, "run_mode", "Interactive, non-interactive" },
{ PARAM_STRING, "filename", "The name of the file to load" },
{ PARAM_STRING, "raw_filename", "The name entered" },
};
static GParamDef load_return_vals[] = {
{ PARAM_IMAGE, "image", "Output image" },
};
static int nload_args = sizeof (load_args) / sizeof (load_args[0]);
static int nload_return_vals = sizeof (load_return_vals) /
sizeof (load_return_vals[0]);
static GParamDef save_args[] = {
{ PARAM_INT32, "run_mode", "Interactive, non-interactive" },
{ PARAM_IMAGE, "image", "Input image" },
{ PARAM_DRAWABLE, "drawable", "Drawable to save" },
{ PARAM_STRING, "filename", "The name of the file to save the image in" },
{ PARAM_STRING, "raw_filename",
"The name of the file to save the image in" }
};
static int nsave_args = sizeof (save_args) / sizeof (save_args[0]);
gimp_install_procedure ("file_pix_load",
"loads files of the PIX file format",
"loads files of the PIX file format",
"Michael Taylor",
"Michael Taylor",
"1997",
"<Load>/PIX",
NULL,
PROC_PLUG_IN,
nload_args, nload_return_vals,
load_args, load_return_vals);
gimp_install_procedure ("file_pix_save",
"save file in the Alias|Wavefront pix/matte file format",
"save file in the Alias|Wavefront pix/matte file format",
"Michael Taylor",
"Michael Taylor",
"1997",
"<Save>/PIX",
"RGB*, GRAY*",
PROC_PLUG_IN,
nsave_args, 0,
save_args, NULL);
gimp_register_load_handler ("file_pix_load", "pix,matte,mask,alpha", "");
gimp_register_save_handler ("file_pix_save", "pix,matte,mask,alpha", "");
}
static void run ( char *name, int nparams, GParam *param, int *nreturn_vals,
GParam **return_vals )
/*
* Description:
* perform registered plug-in function
*
* Arguments:
* name - name of the function to perform
* nparams - number of parameters passed to the function
* param - parameters passed to the function
* nreturn_vals - number of parameters returned by the function
* return_vals - parameters returned by the function
*/
{
static GParam values[2];
GRunModeType run_mode;
GStatusType status = STATUS_SUCCESS;
gint32 image_ID;
run_mode = param[0].data.d_int32;
*nreturn_vals = 1;
*return_vals = values;
values[0].type = PARAM_STATUS;
values[0].data.d_status = STATUS_CALLING_ERROR;
if (strcmp (name, "file_pix_load") == 0) {
/* Perform the image load */
image_ID = load_image (param[1].data.d_string);
if (image_ID != -1) {
/* The image load was successful */
*nreturn_vals = 2;
values[0].data.d_status = STATUS_SUCCESS;
values[1].type = PARAM_IMAGE;
values[1].data.d_image = image_ID;
} else {
/* The image load falied */
values[0].data.d_status = STATUS_EXECUTION_ERROR;
}
} else if (strcmp (name, "file_pix_save") == 0) {
if (status == STATUS_SUCCESS) {
if ( !save_image ( param[3].data.d_string, param[1].data.d_int32,
param[2].data.d_int32))
{
status = STATUS_EXECUTION_ERROR;
}
}
values[0].data.d_status = status;
} else {
g_assert (FALSE);
}
}
static guint16 get_short( FILE * file )
/*
* Description:
* Reads a 16-bit integer from a file in such a way that the machine's
* bit ordering should not matter
*/
{
guchar buf[2];
fread( buf, 2, 1, file);
return ( buf[0] << 8 ) + ( buf[1] << 0 );
}
static void put_short( guint16 value, FILE * file )
/*
* Description:
* Reads a 16-bit integer from a file in such a way that the machine's
* bit ordering should not matter
*/
{
guchar buf[2];
buf[0] = (guchar)( value >> 8 );
buf[1] = (guchar)( value % 256 );
fwrite( buf, 2, 1, file);
}
static guint32 get_long( FILE * file )
/*
* Description:
* Reads a 16-bit integer from a file in such a way that the machine's
* bit ordering should not matter
*/
{
guchar buf[4];
fread( buf, 4, 1, file );
return ( buf[0] << 24 ) + ( buf[1] << 16 )
+ ( buf[2] << 8 ) + ( buf[3] << 0 );
}
static gchar get_char( FILE * file )
/*
* Description:
* Reads a byte from a file. Provided for convenience;
*/
{
gchar result;
fread( &result, 1, 1, file );
return result;
}
static gint32 load_image (char *filename)
/*
* Description:
* load the given image into gimp
*
* Arguments:
* filename - name on the file to read
*
* Return Value:
* Image id for the loaded image
*
*/
{
gint i, j, tile_height, row;
gint result = -1;
FILE * file = NULL;
gint32 * offsetTable = NULL;
gint32 * lengthTable = NULL;
gchar * progMessage;
guchar * dest;
guchar * dest_base;
GDrawable * drawable;
gint32 image_ID;
gint32 layer_ID;
GPixelRgn pixel_rgn;
gushort width, height, depth;
GImageType imgtype;
GDrawableType gdtype;
/* Set up progress display */
progMessage = malloc (strlen (filename) + 12);
if (!progMessage) gimp_quit ();
sprintf (progMessage, "Loading %s:", filename);
gimp_progress_init (progMessage);
free (progMessage);
PIX_DEBUG_PRINT("Opening file: %s\n",filename);
/* Open the file */
file = fopen( filename, "r" );
if ( NULL == file ) {
return -1;
}
/* Read header information */
width = get_short( file );
height = get_short( file );
get_short( file ); /* Discard obsolete fields */
get_short( file ); /* Discard obsolete fields */
depth = get_short( file );
PIX_DEBUG_PRINT( "Width %hu\n", width );
PIX_DEBUG_PRINT( "Height %hu\n", height );
if ( depth == 8 ) {
/* Loading a matte file */
imgtype = GRAY;
gdtype = GRAY_IMAGE;
} else if ( depth == 24 ) {
/* Loading an RGB file */
imgtype = RGB;
gdtype = RGB_IMAGE;
} else {
/* Header is invalid */
fclose( file );
return -1;
}
image_ID = gimp_image_new ( width, height, imgtype );
gimp_image_set_filename ( image_ID, filename );
layer_ID = gimp_layer_new ( image_ID, "Background",
width,
height,
gdtype, 100, NORMAL_MODE );
gimp_image_add_layer ( image_ID, layer_ID, 0);
drawable = gimp_drawable_get ( layer_ID );
gimp_pixel_rgn_init ( &pixel_rgn, drawable, 0, 0, drawable->width,
drawable->height, TRUE, FALSE );
tile_height = gimp_tile_height();
if ( depth == 24 ) {
/* Read a 24-bit Pix image */
guchar record[4];
gint readlen;
tile_height = gimp_tile_height();
dest_base = dest = g_new (guchar, 3 * width * tile_height);
for (i = 0; i < height;) {
for ( dest = dest_base, row = 0;
row < tile_height && i < height;
i += 1, row += 1)
{
guchar count;
/* Read a row of the image */
j = 0;
while ( j < width ) {
readlen = fread( record, 1, 4, file );
if ( readlen < 4 ) break;
for ( count = 0; count < record[0]; ++count ) {
dest[0] = record[3];
dest[1] = record[2];
dest[2] = record[1];
dest += 3;
j++;
if ( j >= width ) break;
}
}
}
gimp_pixel_rgn_set_rect (&pixel_rgn, dest_base, 0, i-row,
width, row);
gimp_progress_update ((double) i / (double) height);
}
free( dest_base );
} else {
/* Read an 8-bit Matte image */
guchar record[2];
gint readlen;
dest_base = dest = g_new (guchar, width * tile_height);
for (i = 0; i < height;) {
for ( dest = dest_base, row = 0;
row < tile_height && i < height;
i += 1, row += 1)
{
guchar count;
/* Read a row of the image */
j = 0;
while ( j < width ) {
readlen = fread( record, 1, 2, file );
if ( readlen < 2 ) break;
for ( count = 0; count < record[0]; ++count ) {
dest[j] = record[1];
j++;
if ( j >= width ) break;
}
}
dest += width;
}
gimp_pixel_rgn_set_rect (&pixel_rgn, dest_base, 0, i-row,
width, row);
gimp_progress_update ((double) i / (double) height);
}
free( dest_base );
}
gimp_drawable_flush (drawable);
gimp_drawable_detach (drawable);
fclose( file );
return image_ID;
}
static gint save_image( char *filename, gint32 image_ID, gint32 drawable_ID )
/*
* Description:
* save the given file out as an alias pix or matte file
*
* Arguments:
* filename - name of file to save to
* image_ID - ID of image to save
* drawable_ID - current drawable
*/
{
gint depth, i, j, row, tile_height, writelen, rectHeight;
gboolean savingAlpha = FALSE;
gboolean savingColor = TRUE;
guchar * src;
guchar * src_base;
gchar * progMessage;
GDrawable * drawable;
GPixelRgn pixel_rgn;
FILE * file;
/* Get info about image */
drawable = gimp_drawable_get(drawable_ID);
gimp_pixel_rgn_init(&pixel_rgn, drawable, 0, 0, drawable->width,
drawable->height, FALSE, FALSE);
switch (gimp_drawable_type(drawable_ID))
{
case GRAY_IMAGE:
savingColor = FALSE;
depth = 1;
break;
case GRAYA_IMAGE:
savingColor = FALSE;
depth = 2;
break;
case RGB_IMAGE:
savingColor = TRUE;
depth = 3;
break;
case RGBA_IMAGE:
savingColor = TRUE;
depth = 4;
break;
default:
return FALSE;
};
/* Open the output file. */
file = fopen (filename, "wb");
if ( !file ) {
return (FALSE);
}
/* Set up progress display */
progMessage = malloc (strlen (filename) + 12);
if (!progMessage) gimp_quit ();
sprintf (progMessage, "Saving %s:", filename);
gimp_progress_init (progMessage);
free (progMessage);
/* Write the image header */
PIX_DEBUG_PRINT( "Width %hu\n", drawable->width );
PIX_DEBUG_PRINT( "Height %hu\n", drawable->height );
put_short( drawable->width, file );
put_short( drawable->height, file );
put_short( 0, file );
put_short( 0, file );
if ( savingColor ) {
put_short( 24, file );
} else {
put_short( 8, file );
}
tile_height = gimp_tile_height();
src_base = g_new( guchar, tile_height * drawable->width * depth );
if ( savingColor ) {
/* Writing a 24-bit Pix image */
guchar record[4];
for (i = 0; i < drawable->height;) {
rectHeight = ( tile_height < ( drawable->height - i - 1 ) ) ?
tile_height : ( drawable->height - i - 1 );
gimp_pixel_rgn_get_rect (&pixel_rgn, src_base, 0, i,
drawable->width, rectHeight);
for ( src = src_base, row = 0;
row < tile_height && i < drawable->height;
i += 1, row += 1)
{
/* Write a row of the image */
guchar count;
gint cnt = 0;
record[0] = 1;
record[3] = src[0];
record[2] = src[1];
record[1] = src[2];
src += depth;
for ( j = 1; j < drawable->width; ++j ) {
if ( ( record[3] != src[0] ) ||
( record[2] != src[1] ) ||
( record[1] != src[2] ) ||
( record[0] == 255 ) )
{
/* Write current RLE record and start a new one */
writelen = fwrite( record, 1, 4, file );
record[0] = 1;
record[3] = src[0];
record[2] = src[1];
record[1] = src[2];
} else {
/* increment run length in current record */
record[0] ++;
}
src += depth;
}
/* Write last record in row */
writelen = fwrite( record, 1, 4, file );
}
gimp_progress_update ((double) i / (double) drawable->height);
}
} else {
/* Writing a 8-bit Matte (Mask) image */
guchar record[2];
for (i = 0; i < drawable->height;) {
rectHeight = ( tile_height < ( drawable->height - i - 1 ) ) ?
tile_height : ( drawable->height - i - 1 );
gimp_pixel_rgn_get_rect (&pixel_rgn, src_base, 0, i,
drawable->width, rectHeight);
for ( src = src_base, row = 0;
row < tile_height && i < drawable->height;
i += 1, row += 1)
{
/* Write a row of the image */
guchar count;
gint cnt = 0;
record[0] = 1;
record[1] = src[0];
src += depth;
for ( j = 1; j < drawable->width; ++j ) {
if ( ( record[1] != src[0] ) ||
( record[0] == 255 ) )
{
/* Write current RLE record and start a new one */
writelen = fwrite( record, 1, 2, file );
record[0] = 1;
record[1] = src[0];
} else {
/* increment run length in current record */
record[0] ++;
}
src += depth;
}
/* Write last record in row */
writelen = fwrite( record, 1, 2, file );
}
gimp_progress_update ((double) i / (double) drawable->height);
}
}
free( src_base );
fclose( file );
return (1);
}

View File

@ -1,802 +0,0 @@
/* The GIMP -- an image manipulation program
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* Pixelize plug-in (ported to GIMP v1.0)
* Copyright (C) 1997 Eiichi Takamori <taka@ma1.seikyou.ne.jp>
* original pixelize.c for GIMP 0.54 by Tracy Scott
*
* 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
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/*
* version 1.04
* This version requires GIMP v0.99.10 or above.
*
* This plug-in "pixelizes" the image.
*
* Eiichi Takamori <taka@ma1.seikyou.ne.jp>
* http://ha1.seikyou.ne.jp/home/taka/gimp/
*
* Changes from version 1.03 to version 1.04:
* - Added gtk_rc_parse
* - Added entry with scale
* - Fixed bug that large pixelwidth >=64 sometimes caused core dump
*
* Changes from gimp-0.99.9/plug-ins/pixelize.c to version 1.03:
* - Fixed comments and help strings
* - Fixed `RGB, GRAY' to `RGB*, GRAY*'
* - Fixed procedure db name `pixelize' to `plug_in_pixelize'
*
* Differences from Tracy Scott's original `pixelize' plug-in:
*
* - Algorithm is modified to work around with the tile management.
* The way of pixelizing is switched by the value of pixelwidth. If
* pixelwidth is greater than (or equal to) tile width, then this
* plug-in makes GPixelRgn with that width and proceeds. Otherwise,
* it makes the region named `PixelArea', whose size is smaller than
* tile width and is multiply of pixel width, and acts onto it.
*/
/* pixelize filter written for the GIMP
* -Tracy Scott
*
* This filter acts as a low pass filter on the color components of
* the provided region
*/
#include <stdio.h>
#include <stdlib.h>
#include "gtk/gtk.h"
#include "libgimp/gimp.h"
#include "libgimp/gimpui.h"
#ifdef RCSID
static char rcsid[] = "$Id$";
#endif
/* Some useful macros */
#define TILE_CACHE_SIZE 16
#define ENTSCALE_INT_SCALE_WIDTH 125
#define ENTSCALE_INT_ENTRY_WIDTH 40
typedef struct {
gint pixelwidth;
} PixelizeValues;
typedef struct {
gint run;
} PixelizeInterface;
typedef struct {
gint x, y, w, h;
gint width;
guchar *data;
} PixelArea;
typedef void (*EntscaleIntCallbackFunc) (gint value, gpointer data);
typedef struct {
GtkObject *adjustment;
GtkWidget *entry;
gint constraint;
EntscaleIntCallbackFunc callback;
gpointer call_data;
} EntscaleIntData;
/* Declare local functions.
*/
static void query (void);
static void run (gchar *name,
gint nparams,
GParam *param,
gint *nreturn_vals,
GParam **return_vals);
static gint pixelize_dialog (void);
static void pixelize_close_callback (GtkWidget *widget,
gpointer data);
static void pixelize_ok_callback (GtkWidget *widget,
gpointer data);
static void pixelize (GDrawable *drawable);
static void pixelize_large (GDrawable *drawable, gint pixelwidth);
static void pixelize_small (GDrawable *drawable, gint pixelwidth, gint tile_width);
static void pixelize_sub ( gint pixelwidth, gint bpp, gint color_n );
void entscale_int_new ( GtkWidget *table, gint x, gint y,
gchar *caption, gint *intvar,
gint min, gint max, gint constraint,
EntscaleIntCallbackFunc callback,
gpointer data );
static void entscale_int_destroy_callback (GtkWidget *widget,
gpointer data);
static void entscale_int_scale_update (GtkAdjustment *adjustment,
gpointer data);
static void entscale_int_entry_update (GtkWidget *widget,
gpointer data);
/***** Local vars *****/
GPlugInInfo PLUG_IN_INFO =
{
NULL, /* init_proc */
NULL, /* quit_proc */
query, /* query_proc */
run /* run_proc */
};
static PixelizeValues pvals =
{
10
};
static PixelizeInterface pint =
{
FALSE /* run */
};
static PixelArea area;
/***** Functions *****/
MAIN ()
static void
query()
{
static GParamDef args[]=
{
{ PARAM_INT32, "run_mode", "Interactive, non-interactive" },
{ PARAM_IMAGE, "image", "Input image (unused)" },
{ PARAM_DRAWABLE, "drawable", "Input drawable" },
{ PARAM_INT32, "pixelwidth", "Pixel width (the decrease in resolution)" }
};
static GParamDef *return_vals = NULL;
static gint nargs = sizeof (args) / sizeof (args[0]);
static gint nreturn_vals = 0;
gimp_install_procedure ("plug_in_pixelize",
"Pixelize the contents of the specified drawable",
"Pixelize the contents of the specified drawable with speficied pixelizing width.",
"Spencer Kimball & Peter Mattis, Tracy Scott, (ported to 1.0 by) Eiichi Takamori",
"Spencer Kimball & Peter Mattis, Tracy Scott",
"1995",
"<Image>/Filters/Image/Pixelize",
"RGB*, GRAY*",
PROC_PLUG_IN,
nargs, nreturn_vals,
args, return_vals);
}
static void
run (gchar *name,
gint nparams,
GParam *param,
gint *nreturn_vals,
GParam **return_vals)
{
static GParam values[1];
GDrawable *drawable;
GRunModeType run_mode;
GStatusType status = STATUS_SUCCESS;
run_mode = param[0].data.d_int32;
*nreturn_vals = 1;
*return_vals = values;
values[0].type = PARAM_STATUS;
values[0].data.d_status = status;
/* Get the specified drawable */
drawable = gimp_drawable_get (param[2].data.d_drawable);
switch (run_mode)
{
case RUN_INTERACTIVE:
/* Possibly retrieve data */
gimp_get_data ("plug_in_pixelize", &pvals);
/* First acquire information with a dialog */
if (! pixelize_dialog ())
{
gimp_drawable_detach (drawable);
return;
}
break;
case RUN_NONINTERACTIVE:
/* Make sure all the arguments are there! */
if (nparams != 4)
status = STATUS_CALLING_ERROR;
if (status == STATUS_SUCCESS)
{
pvals.pixelwidth = (gdouble) param[3].data.d_int32;
}
if ((status == STATUS_SUCCESS) &&
pvals.pixelwidth <= 0 )
status = STATUS_CALLING_ERROR;
break;
case RUN_WITH_LAST_VALS:
/* Possibly retrieve data */
gimp_get_data ("plug_in_pixelize", &pvals);
break;
default:
break;
}
if (status == STATUS_SUCCESS)
{
/* Make sure that the drawable is gray or RGB color */
if (gimp_drawable_color (drawable->id) || gimp_drawable_gray (drawable->id))
{
gimp_progress_init ("Pixelizing...");
/* set the tile cache size */
gimp_tile_cache_ntiles (TILE_CACHE_SIZE);
/* run the pixelize effect */
pixelize (drawable);
if (run_mode != RUN_NONINTERACTIVE)
gimp_displays_flush ();
/* Store data */
if (run_mode == RUN_INTERACTIVE)
gimp_set_data ("plug_in_pixelize", &pvals, sizeof (PixelizeValues));
}
else
{
/* gimp_message ("pixelize: cannot operate on indexed color images"); */
status = STATUS_EXECUTION_ERROR;
}
}
values[0].data.d_status = status;
gimp_drawable_detach (drawable);
}
static gint
pixelize_dialog ()
{
GtkWidget *dlg;
GtkWidget *frame;
GtkWidget *table;
GtkWidget *button;
gchar **argv;
gint argc;
argc = 1;
argv = g_new (gchar *, 1);
argv[0] = g_strdup ("pixelize");
gtk_init (&argc, &argv);
gtk_rc_parse (gimp_gtkrc ());
dlg = gtk_dialog_new ();
gtk_window_set_title (GTK_WINDOW (dlg), "Pixelize");
gtk_window_position (GTK_WINDOW (dlg), GTK_WIN_POS_MOUSE);
gtk_signal_connect (GTK_OBJECT (dlg), "destroy",
(GtkSignalFunc) pixelize_close_callback,
NULL);
/* Action area */
button = gtk_button_new_with_label ("OK");
GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
gtk_signal_connect (GTK_OBJECT (button), "clicked",
(GtkSignalFunc) pixelize_ok_callback,
dlg);
gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dlg)->action_area), button, TRUE, TRUE, 0);
gtk_widget_grab_default (button);
gtk_widget_show (button);
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));
gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dlg)->action_area), button, TRUE, TRUE, 0);
gtk_widget_show (button);
/* parameter settings */
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 (3, 2, FALSE);
gtk_container_border_width (GTK_CONTAINER (table), 10);
gtk_container_add (GTK_CONTAINER (frame), table);
entscale_int_new (table, 0, 0, "Pixel Width:", &pvals.pixelwidth,
1, 64, FALSE,
NULL, NULL);
gtk_widget_show (frame);
gtk_widget_show (table);
gtk_widget_show (dlg);
gtk_main ();
gdk_flush ();
return pint.run;
}
/* Pixelize interface functions */
static void
pixelize_close_callback (GtkWidget *widget,
gpointer data)
{
gtk_main_quit ();
}
static void
pixelize_ok_callback (GtkWidget *widget,
gpointer data)
{
pint.run = TRUE;
gtk_widget_destroy (GTK_WIDGET (data));
}
/*
Pixelize Effect
*/
static void
pixelize (GDrawable *drawable)
{
gint tile_width;
gint pixelwidth;
tile_width = gimp_tile_width();
pixelwidth = pvals.pixelwidth;
if (pixelwidth < 0)
pixelwidth = - pixelwidth;
if (pixelwidth < 1)
pixelwidth = 1;
if( pixelwidth >= tile_width )
pixelize_large( drawable, pixelwidth );
else
pixelize_small( drawable, pixelwidth, tile_width );
}
/*
This function operates on the image when pixelwidth >= tile_width.
It simply sets the size of GPixelRgn as pixelwidth and proceeds.
*/
static void
pixelize_large (GDrawable *drawable, gint pixelwidth )
{
GPixelRgn src_rgn, dest_rgn;
guchar *src_row, *dest_row;
guchar *src, *dest;
gulong *average;
gint row, col, b, bpp;
gint x, y, x_step, y_step;
gulong count;
gint x1, y1, x2, y2;
gint progress, max_progress;
gpointer pr;
gimp_drawable_mask_bounds (drawable->id, &x1, &y1, &x2, &y2);
if( gimp_drawable_color( drawable->id ) )
bpp = 3;
else
bpp = 1;
average = g_new( gulong, bpp );
/* Initialize progress */
progress = 0;
max_progress = 2 * (x2 - x1) * (y2 - y1);
for( y = y1; y < y2; y += pixelwidth - ( y % pixelwidth ) )
{
for( x = x1; x < x2; x += pixelwidth - ( x % pixelwidth ) )
{
x_step = pixelwidth - ( x % pixelwidth );
y_step = pixelwidth - ( y % pixelwidth );
x_step = MIN( x_step, x2-x );
y_step = MIN( y_step, y2-y );
gimp_pixel_rgn_init (&src_rgn, drawable, x, y, x_step, y_step, FALSE, FALSE);
for( b = 0; b < bpp; b++ )
average[b] = 0;
count = 0;
for (pr = gimp_pixel_rgns_register (1, &src_rgn); pr != NULL; pr = gimp_pixel_rgns_process (pr))
{
src_row = src_rgn.data;
for (row = 0; row < src_rgn.h; row++)
{
src = src_row;
for (col = 0; col < src_rgn.w; col++)
{
for( b = 0; b < bpp; b++ )
average[b] += src[b];
src += src_rgn.bpp;
count += 1;
}
src_row += src_rgn.rowstride;
}
/* Update progress */
progress += src_rgn.w * src_rgn.h;
gimp_progress_update ((double) progress / (double) max_progress);
}
if ( count > 0 )
{
for ( b = 0; b < bpp; b++ )
average[b] = (guchar) ( average[b] / count );
}
gimp_pixel_rgn_init (&dest_rgn, drawable, x, y, x_step, y_step, TRUE, TRUE);
for (pr = gimp_pixel_rgns_register (1, &dest_rgn); pr != NULL; pr = gimp_pixel_rgns_process (pr))
{
dest_row = dest_rgn.data;
for (row = 0; row < dest_rgn.h; row++)
{
dest = dest_row;
for (col = 0; col < dest_rgn.w; col++)
{
for( b = 0; b < bpp; b++ )
dest[b] = average[b];
dest += dest_rgn.bpp;
count += 1;
}
dest_row += dest_rgn.rowstride;
}
/* Update progress */
progress += dest_rgn.w * dest_rgn.h;
gimp_progress_update ((double) progress / (double) max_progress);
}
}
}
g_free( average );
/* 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));
}
/*
This function operates on PixelArea, whose width and height are
multiply of pixel width, and less than the tile size (to enhance
its speed).
If any coordinates of mask boundary is not multiply of pixel width
( e.g. x1 % pixelwidth != 0 ), operates on the region whose width
or height is the remainder.
*/
static void
pixelize_small ( GDrawable *drawable, gint pixelwidth, gint tile_width )
{
GPixelRgn src_rgn, dest_rgn;
gint bpp, color_n;
gint x1, y1, x2, y2;
gint progress, max_progress;
gimp_drawable_mask_bounds (drawable->id, &x1, &y1, &x2, &y2);
gimp_pixel_rgn_init (&src_rgn, drawable, x1, y1, x2-x1, y2-y1, FALSE, FALSE);
gimp_pixel_rgn_init (&dest_rgn, drawable, x1, y1, x2-x1, y2-y1, TRUE, TRUE);
/* Initialize progress */
progress = 0;
max_progress = (x2 - x1) * (y2 - y1);
bpp = drawable->bpp;
if( gimp_drawable_color(drawable->id) )
color_n = 3;
else
color_n = 1;
area.width = ( tile_width / pixelwidth ) * pixelwidth;
area.data= g_new( guchar, (glong) bpp * area.width * area.width );
for( area.y = y1; area.y < y2;
area.y += area.width - ( area.y % area.width ) )
{
area.h = area.width - ( area.y % area.width );
area.h = MIN( area.h, y2 - area.y );
for( area.x = x1; area.x < x2;
area.x += area.width - ( area.x % area.width ) )
{
area.w = area.width - ( area.x % area.width );
area.w = MIN( area.w, x2 - area.x );
gimp_pixel_rgn_get_rect( &src_rgn, area.data, area.x, area.y, area.w, area.h );
pixelize_sub( pixelwidth, bpp, color_n );
gimp_pixel_rgn_set_rect( &dest_rgn, area.data, area.x, area.y, area.w, area.h );
/* Update progress */
progress += area.w * area.h;
gimp_progress_update ((double) progress / (double) max_progress);
}
}
g_free( area.data );
/* update the pixelized region */
gimp_drawable_flush (drawable);
gimp_drawable_merge_shadow (drawable->id, TRUE);
gimp_drawable_update (drawable->id, x1, y1, (x2 - x1), (y2 - y1));
}
/*
This function acts on one PixelArea. Since there were so many
nested FORs in pixelize_small(), I put a few of them here...
*/
static void
pixelize_sub( gint pixelwidth, gint bpp, gint color_n )
{
glong average[3]; /* color_n <= 3 */
gint x, y, w, h;
guchar *buf_row, *buf;
gint row, col;
gint rowstride;
gint count;
gint i;
rowstride = area.w * bpp;
for( y = area.y; y < area.y + area.h; y += pixelwidth - ( y % pixelwidth ) )
{
h = pixelwidth - ( y % pixelwidth );
h = MIN( h, area.y + area.h - y );
for( x = area.x; x < area.x + area.w; x += pixelwidth - ( x % pixelwidth ) )
{
w = pixelwidth - ( x % pixelwidth );
w = MIN( w, area.x + area.w - x );
for( i = 0; i < color_n; i++ )
average[i] = 0;
count = 0;
/* Read */
buf_row = area.data + (y-area.y)*rowstride + (x-area.x)*bpp;
for( row = 0; row < h; row++ )
{
buf = buf_row;
for( col = 0; col < w; col++ )
{
for( i = 0; i < color_n; i++ )
average[i] += buf[i];
count++;
buf += bpp;
}
buf_row += rowstride;
}
/* Average */
if ( count > 0 )
{
for( i = 0; i < color_n; i++ )
average[i] /= count;
}
/* Write */
buf_row = area.data + (y-area.y)*rowstride + (x-area.x)*bpp;
for( row = 0; row < h; row++ )
{
buf = buf_row;
for( col = 0; col < w; col++ )
{
for( i = 0; i < color_n; i++ )
buf[i] = average[i];
count++;
buf += bpp;
}
buf_row += rowstride;
}
}
}
}
/* ====================================================================== */
/*
Entry and Scale pair 1.03
TODO:
- Do the proper thing when the user changes value in entry,
so that callback should not be called when value is actually not changed.
- Update delay
*/
/*
* entscale: create new entscale with label. (int)
* 1 row and 2 cols of table are needed.
* Input:
* x, y: starting row and col in table
* caption: label string
* intvar: pointer to variable
* min, max: the boundary of scale
* constraint: (bool) true iff the value of *intvar should be constraint
* by min and max
* callback: called when the value is actually changed
* call_data: data for callback func
*/
void
entscale_int_new ( GtkWidget *table, gint x, gint y,
gchar *caption, gint *intvar,
gint min, gint max, gint constraint,
EntscaleIntCallbackFunc callback,
gpointer call_data)
{
EntscaleIntData *userdata;
GtkWidget *hbox;
GtkWidget *label;
GtkWidget *entry;
GtkWidget *scale;
GtkObject *adjustment;
gchar buffer[256];
gint constraint_val;
userdata = g_new ( EntscaleIntData, 1 );
label = gtk_label_new (caption);
gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
/*
If the first arg of gtk_adjustment_new() isn't between min and
max, it is automatically corrected by gtk later with
"value_changed" signal. I don't like this, since I want to leave
*intvar untouched when `constraint' is false.
The lines below might look oppositely, but this is OK.
*/
userdata->constraint = constraint;
if( constraint )
constraint_val = *intvar;
else
constraint_val = ( *intvar < min ? min : *intvar > max ? max : *intvar );
userdata->adjustment = adjustment =
gtk_adjustment_new ( constraint_val, min, max, 1.0, 1.0, 0.0);
scale = gtk_hscale_new ( GTK_ADJUSTMENT(adjustment) );
gtk_widget_set_usize (scale, ENTSCALE_INT_SCALE_WIDTH, 0);
gtk_scale_set_draw_value (GTK_SCALE (scale), FALSE);
userdata->entry = entry = gtk_entry_new ();
gtk_widget_set_usize (entry, ENTSCALE_INT_ENTRY_WIDTH, 0);
sprintf( buffer, "%d", *intvar );
gtk_entry_set_text( GTK_ENTRY (entry), buffer );
userdata->callback = callback;
userdata->call_data = call_data;
/* userdata is done */
gtk_object_set_user_data (GTK_OBJECT(adjustment), userdata);
gtk_object_set_user_data (GTK_OBJECT(entry), userdata);
/* now ready for signals */
gtk_signal_connect (GTK_OBJECT (entry), "changed",
(GtkSignalFunc) entscale_int_entry_update,
intvar);
gtk_signal_connect (GTK_OBJECT (adjustment), "value_changed",
(GtkSignalFunc) entscale_int_scale_update,
intvar);
gtk_signal_connect (GTK_OBJECT (entry), "destroy",
(GtkSignalFunc) entscale_int_destroy_callback,
userdata );
/* start packing */
hbox = gtk_hbox_new (FALSE, 5);
gtk_box_pack_start (GTK_BOX (hbox), scale, TRUE, TRUE, 0);
gtk_box_pack_start (GTK_BOX (hbox), entry, FALSE, TRUE, 0);
gtk_table_attach (GTK_TABLE (table), label, x, x+1, y, y+1,
GTK_FILL, GTK_FILL, 0, 0);
gtk_table_attach (GTK_TABLE (table), hbox, x+1, x+2, y, y+1,
GTK_EXPAND | GTK_FILL, GTK_FILL, 0, 0);
gtk_widget_show (label);
gtk_widget_show (entry);
gtk_widget_show (scale);
gtk_widget_show (hbox);
}
/* when destroyed, userdata is destroyed too */
static void
entscale_int_destroy_callback (GtkWidget *widget,
gpointer data)
{
EntscaleIntData *userdata;
userdata = data;
g_free ( userdata );
}
static void
entscale_int_scale_update (GtkAdjustment *adjustment,
gpointer data)
{
EntscaleIntData *userdata;
GtkEntry *entry;
gchar buffer[256];
gint *intvar = data;
gint new_val;
userdata = gtk_object_get_user_data (GTK_OBJECT (adjustment));
new_val = (gint) adjustment->value;
*intvar = new_val;
entry = GTK_ENTRY( userdata->entry );
sprintf (buffer, "%d", (int) new_val );
/* avoid infinite loop (scale, entry, scale, entry ...) */
gtk_signal_handler_block_by_data ( GTK_OBJECT(entry), data );
gtk_entry_set_text ( entry, buffer);
gtk_signal_handler_unblock_by_data ( GTK_OBJECT(entry), data );
if (userdata->callback)
(*userdata->callback) (*intvar, userdata->call_data);
}
static void
entscale_int_entry_update (GtkWidget *widget,
gpointer data)
{
EntscaleIntData *userdata;
GtkAdjustment *adjustment;
int new_val, constraint_val;
int *intvar = data;
userdata = gtk_object_get_user_data (GTK_OBJECT (widget));
adjustment = GTK_ADJUSTMENT( userdata->adjustment );
new_val = atoi (gtk_entry_get_text (GTK_ENTRY (widget)));
constraint_val = new_val;
if ( constraint_val < adjustment->lower )
constraint_val = adjustment->lower;
if ( constraint_val > adjustment->upper )
constraint_val = adjustment->upper;
if ( userdata->constraint )
*intvar = constraint_val;
else
*intvar = new_val;
adjustment->value = constraint_val;
gtk_signal_handler_block_by_data ( GTK_OBJECT(adjustment), data );
gtk_signal_emit_by_name ( GTK_OBJECT(adjustment), "value_changed");
gtk_signal_handler_unblock_by_data ( GTK_OBJECT(adjustment), data );
if (userdata->callback)
(*userdata->callback) (*intvar, userdata->call_data);
}

View File

@ -1,690 +0,0 @@
/*
* This is a plugin for the GIMP.
*
* Copyright (C) 1996 Stephen Norris
*
* 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
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
/*
* This plug-in produces plasma fractal images. The algorithm is losely
* based on a description of the fractint algorithm, but completely
* re-implemented because the fractint code was too ugly to read :)
*
* Please send any patches or suggestions to me: srn@flibble.cs.su.oz.au.
*/
/*
* TODO:
* - The progress bar sucks.
* - It writes some pixels more than once.
*/
/* Version 1.01 */
/*
* Ported to GIMP Plug-in API 1.0
* by Eiichi Takamori <taka@ma1.seikyou.ne.jp>
*
* $Id$
*
* A few functions names and their order are changed :)
* Plasma implementation almost hasn't been changed.
*
* Feel free to correct my WRONG English, or to modify Plug-in Path,
* and so on. ;-)
*/
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include "gtk/gtk.h"
#include "libgimp/gimp.h"
#include "libgimp/gimpui.h"
/* Some useful macros */
#define ENTRY_WIDTH 75
#define SCALE_WIDTH 128
#define TILE_CACHE_SIZE 32
typedef struct {
gint seed;
gdouble turbulence;
} PlasmaValues;
typedef struct {
gint run;
} PlasmaInterface;
/*
* Function prototypes.
*/
static void query (void);
static void run (gchar *name,
gint nparams,
GParam *param,
gint *nreturn_vals,
GParam **return_vals);
static gint plasma_dialog (void);
static void plasma_close_callback (GtkWidget *widget,
gpointer data);
static void plasma_ok_callback (GtkWidget *widget,
gpointer data);
static void plasma_entry_callback (GtkWidget *widget,
gpointer data);
static void plasma_scale_update (GtkAdjustment *adjustment,
gpointer data);
static void plasma (GDrawable *drawable);
static void random_rgb (guchar *d);
static void add_random (guchar *d, gint amnt);
static void init_plasma (GDrawable *drawable);
static void provide_tile (GDrawable *drawable, gint col, gint row );
static void end_plasma (GDrawable *drawable);
static void get_pixel (GDrawable *drawable, gint x, gint y, guchar *pixel );
static void put_pixel (GDrawable *drawable, gint x, gint y, guchar *pixel );
static gint do_plasma (GDrawable *drawable, gint x1, gint y1,
gint x2, gint y2, gint depth, gint scale_depth );
/***** Local vars *****/
GPlugInInfo PLUG_IN_INFO =
{
NULL, /* init_proc */
NULL, /* quit_proc */
query, /* query_proc */
run, /* run_proc */
};
static PlasmaValues pvals =
{
0, /* seed */
1.0 /* turbulence */
};
static PlasmaInterface pint =
{
FALSE /* run */
};
/***** Functions *****/
MAIN ()
static void
query()
{
static GParamDef args[]=
{
{ PARAM_INT32, "run_mode", "Interactive, non-interactive" },
{ PARAM_IMAGE, "image", "Input image (unused)" },
{ PARAM_DRAWABLE, "drawable", "Input drawable" },
{ PARAM_INT32, "seed", "Random seed" },
{ PARAM_FLOAT, "turbulence", "Turbulence of plasma" }
};
static GParamDef *return_vals = NULL;
static gint nargs = sizeof (args) / sizeof (args[0]);
static gint nreturn_vals = 0;
gimp_install_procedure ("plug_in_plasma",
"Create a plasma cloud like image to the specified drawable",
"More help",
"Stephen Norris & (ported to 1.0 by) Eiichi Takamori",
"Stephen Norris",
"1995",
"<Image>/Filters/Render/Plasma",
"RGB*, GRAY*",
PROC_PLUG_IN,
nargs, nreturn_vals,
args, return_vals);
}
static void
run (gchar *name,
gint nparams,
GParam *param,
gint *nreturn_vals,
GParam **return_vals)
{
static GParam values[1];
GDrawable *drawable;
GRunModeType run_mode;
GStatusType status = STATUS_SUCCESS;
run_mode = param[0].data.d_int32;
*nreturn_vals = 1;
*return_vals = values;
values[0].type = PARAM_STATUS;
values[0].data.d_status = status;
/* Get the specified drawable */
drawable = gimp_drawable_get (param[2].data.d_drawable);
switch (run_mode)
{
case RUN_INTERACTIVE:
/* Possibly retrieve data */
gimp_get_data ("plug_in_plasma", &pvals);
/* First acquire information with a dialog */
if (! plasma_dialog ())
{
gimp_drawable_detach (drawable);
return;
}
break;
case RUN_NONINTERACTIVE:
/* Make sure all the arguments are there! */
if (nparams != 5)
status = STATUS_CALLING_ERROR;
if (status == STATUS_SUCCESS)
{
pvals.seed = (gint) param[3].data.d_int32;
pvals.turbulence = (gdouble) param[4].data.d_float;
}
if ((status == STATUS_SUCCESS) &&
pvals.turbulence <= 0 )
status = STATUS_CALLING_ERROR;
break;
case RUN_WITH_LAST_VALS:
/* Possibly retrieve data */
gimp_get_data ("plug_in_plasma", &pvals);
break;
default:
break;
}
if (status == STATUS_SUCCESS)
{
/* Make sure that the drawable is gray or RGB color */
if (gimp_drawable_color (drawable->id) || gimp_drawable_gray (drawable->id))
{
gimp_progress_init ("Plasma...");
gimp_tile_cache_ntiles (TILE_CACHE_SIZE);
plasma (drawable);
if (run_mode != RUN_NONINTERACTIVE)
gimp_displays_flush ();
/* Store data */
if (run_mode == RUN_INTERACTIVE)
gimp_set_data ("plug_in_plasma", &pvals, sizeof (PlasmaValues));
}
else
{
/* gimp_message ("plasma: cannot operate on indexed color images"); */
status = STATUS_EXECUTION_ERROR;
}
}
values[0].data.d_status = status;
gimp_drawable_detach (drawable);
}
static gint
plasma_dialog()
{
GtkWidget *dlg;
GtkWidget *frame;
GtkWidget *table;
GtkWidget *button;
GtkWidget *label;
GtkWidget *entry;
GtkWidget *scale;
GtkObject *scale_data;
gchar **argv;
gint argc;
guchar buffer[32];
argc = 1;
argv = g_new (gchar *, 1);
argv[0] = g_strdup ("plasma");
gtk_init (&argc, &argv);
gtk_rc_parse (gimp_gtkrc ());
dlg = gtk_dialog_new ();
gtk_window_set_title (GTK_WINDOW (dlg), "Plasma");
gtk_window_position (GTK_WINDOW (dlg), GTK_WIN_POS_MOUSE);
gtk_signal_connect (GTK_OBJECT (dlg), "destroy",
(GtkSignalFunc) plasma_close_callback,
NULL);
/* Action area */
button = gtk_button_new_with_label ("OK");
GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
gtk_signal_connect (GTK_OBJECT (button), "clicked",
(GtkSignalFunc) plasma_ok_callback,
dlg);
gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dlg)->action_area), button, TRUE, TRUE, 0);
gtk_widget_grab_default (button);
gtk_widget_show (button);
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));
gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dlg)->action_area), button, TRUE, TRUE, 0);
gtk_widget_show (button);
/* parameter settings */
frame = gtk_frame_new ("Plasma Options");
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 (2, 2, FALSE);
gtk_container_border_width (GTK_CONTAINER (table), 10);
gtk_container_add (GTK_CONTAINER (frame), table);
label = gtk_label_new ("Seed");
gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
gtk_table_attach (GTK_TABLE (table), label, 0, 1, 0, 1, GTK_FILL, 0, 5, 0 );
gtk_widget_show (label);
entry = gtk_entry_new ();
gtk_table_attach (GTK_TABLE (table), entry, 1, 2, 0, 1, GTK_FILL, GTK_FILL, 0, 0 );
gtk_widget_set_usize( entry, ENTRY_WIDTH, 0 );
sprintf( buffer, "%d", pvals.seed );
gtk_entry_set_text (GTK_ENTRY (entry), buffer );
gtk_signal_connect (GTK_OBJECT (entry), "changed",
(GtkSignalFunc) plasma_entry_callback,
&pvals.seed);
gtk_widget_show (entry);
label = gtk_label_new ("Turbulence");
gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
gtk_table_attach (GTK_TABLE (table), label, 0, 1, 1, 2, GTK_FILL, 0, 5, 0);
gtk_widget_show (label);
scale_data = gtk_adjustment_new (pvals.turbulence, 0.1, 7.0, 0.1, 0.1, 0.0);
scale = gtk_hscale_new (GTK_ADJUSTMENT (scale_data));
gtk_widget_set_usize (scale, SCALE_WIDTH, 0);
gtk_table_attach (GTK_TABLE (table), scale, 1, 2, 1, 2, GTK_FILL, 0, 0, 0);
gtk_scale_set_value_pos (GTK_SCALE (scale), GTK_POS_TOP);
gtk_scale_set_digits (GTK_SCALE (scale), 1);
gtk_range_set_update_policy (GTK_RANGE (scale), GTK_UPDATE_DELAYED);
gtk_signal_connect (GTK_OBJECT (scale_data), "value_changed",
(GtkSignalFunc) plasma_scale_update,
&pvals.turbulence);
gtk_widget_show (scale);
gtk_widget_show (frame);
gtk_widget_show (table);
gtk_widget_show (dlg);
gtk_main ();
gdk_flush ();
return pint.run;
}
/* Plasma interface functions */
static void
plasma_close_callback (GtkWidget *widget,
gpointer data)
{
gtk_main_quit ();
}
static void
plasma_ok_callback (GtkWidget *widget,
gpointer data)
{
pint.run = TRUE;
gtk_widget_destroy (GTK_WIDGET (data));
}
static void
plasma_entry_callback (GtkWidget *widget,
gpointer data)
{
gint *text_val;
text_val = (gint *) data;
*text_val = atoi (gtk_entry_get_text (GTK_ENTRY (widget)));
}
static void
plasma_scale_update (GtkAdjustment *adjustment,
gpointer data)
{
gdouble *dptr = (gdouble*) data;
*dptr = adjustment->value;
}
#define AVE(n, v1, v2) n[0] = ((gint)v1[0] + (gint)v2[0]) / 2;\
n[1] = ((gint)v1[1] + (gint)v2[1]) / 2;\
n[2] = ((gint)v1[2] + (gint)v2[2]) / 2;
/*
* Some glabals to save passing too many paramaters that don't change.
*/
gint ix1, iy1, ix2, iy2; /* Selected image size. */
GTile *tile=NULL;
gint tile_row, tile_col;
gint tile_width, tile_height;
gint tile_dirty;
gint bpp, has_alpha, alpha;
gdouble turbulence;
glong max_progress, progress;
/*
* The setup function.
*/
static void
plasma(GDrawable *drawable)
{
gint depth;
init_plasma(drawable);
/*
* This first time only puts in the seed pixels - one in each
* corner, and one in the center of each edge, plus one in the
* center of the image.
*/
do_plasma( drawable, ix1, iy1, ix2 - 1, iy2 - 1, -1, 0);
/*
* Now we recurse through the images, going further each time.
*/
depth = 1;
while (!do_plasma( drawable, ix1, iy1, ix2 - 1, iy2 - 1, depth, 0)){
depth ++;
}
end_plasma( drawable );
}
static void
init_plasma( GDrawable *drawable )
{
srand( pvals.seed );
turbulence = pvals.turbulence;
gimp_drawable_mask_bounds(drawable->id, &ix1, &iy1, &ix2, &iy2);
max_progress = (ix2 - ix1) * (iy2 - iy1);
progress = 0;
tile_width = gimp_tile_width ();
tile_height = gimp_tile_height ();
tile = NULL;
tile_row = 0; tile_col = 0;
bpp = drawable->bpp;
has_alpha = gimp_drawable_has_alpha( drawable->id );
if( has_alpha )
alpha = bpp-1;
else
alpha = bpp;
}
static void
provide_tile( GDrawable *drawable, gint col, gint row )
{
if ( col != tile_col || row != tile_row || !tile )
{
if( tile )
gimp_tile_unref( tile, tile_dirty );
tile_col = col;
tile_row = row;
tile = gimp_drawable_get_tile( drawable, TRUE, tile_row, tile_col );
tile_dirty = FALSE;
gimp_tile_ref( tile );
}
}
static void
end_plasma( GDrawable *drawable )
{
if( tile )
gimp_tile_unref( tile, tile_dirty );
tile=NULL;
gimp_drawable_flush (drawable);
gimp_drawable_merge_shadow (drawable->id, TRUE);
gimp_drawable_update (drawable->id, ix1, iy1, (ix2 - ix1), (iy2 - iy1));
}
static void
get_pixel( GDrawable *drawable, gint x, gint y, guchar *pixel )
{
gint row, col;
gint offx, offy, i;
guchar *ptr;
if (x < ix1) x = ix1;
if (x > ix2 - 1) x = ix2 - 1;
if (y < iy1) y = iy1;
if (y > iy2 - 1) y = iy2 - 1;
col = x / tile_width;
row = y / tile_height;
offx = x % tile_width;
offy = y % tile_height;
provide_tile( drawable, col, row );
ptr = tile->data + ( offy * tile->ewidth + offx ) * bpp;
for( i = 0; i < alpha; i++ )
pixel[i] = ptr[i];
}
static void
put_pixel( GDrawable *drawable, gint x, gint y, guchar *pixel )
{
gint row, col;
gint offx, offy, i;
guchar *ptr;
if (x < ix1) x = ix1;
if (x > ix2 - 1) x = ix2 - 1;
if (y < iy1) y = iy1;
if (y > iy2 - 1) y = iy2 - 1;
col = x / tile_width;
row = y / tile_height;
offx = x % tile_width;
offy = y % tile_height;
provide_tile( drawable, col, row );
ptr = tile->data + ( offy * tile->ewidth + offx ) * bpp;
for( i = 0; i < alpha; i++ )
ptr[i] = pixel[i];
if( has_alpha )
ptr[alpha] = 255;
tile_dirty = TRUE;
progress++;
}
static void
random_rgb(guchar *d)
{
gint i;
for( i = 0; i < alpha; i++ ) {
d[i] = rand() % 256;
}
}
static void
add_random(guchar *d, gint amnt)
{
gint i, tmp;
for (i = 0; i < alpha; i++){
if (amnt == 0){
amnt = 1;
}
tmp = amnt/2 - rand() % amnt;
if ((gint)d[i] + tmp < 0){
d[i] = 0;
} else if ((gint)d[i] + tmp > 255){
d[i] = 255;
} else {
d[i] += tmp;
}
}
}
static gint
do_plasma( GDrawable *drawable, gint x1, gint y1, gint x2, gint y2,
gint depth, gint scale_depth)
{
guchar tl[3], ml[3], bl[3], mt[3], mm[3], mb[3], tr[3], mr[3], br[3];
guchar tmp[3];
gint ran;
gint xm, ym;
static gint count = 0;
/* Initial pass through - no averaging. */
if (depth == -1){
random_rgb(tl);
put_pixel( drawable, x1, y1, tl);
random_rgb(tr);
put_pixel( drawable, x2, y1, tr);
random_rgb(bl);
put_pixel( drawable, x1, y2, bl);
random_rgb(br);
put_pixel( drawable, x2, y2, br);
random_rgb(mm);
put_pixel( drawable, (x1 + x2) / 2, (y1 + y2) / 2, mm);
random_rgb(ml);
put_pixel( drawable, x1, (y1 + y2) / 2, ml);
random_rgb(mr);
put_pixel( drawable, x2, (y1 + y2) / 2, mr);
random_rgb(mt);
put_pixel( drawable, (x1 + x2) / 2, y1, mt);
random_rgb(ml);
put_pixel( drawable, (x1 + x2) / 2, y2, ml);
return 0;
}
/*
* Some later pass, at the bottom of this pass,
* with averaging at this depth.
*/
if (depth == 0){
gdouble rnd;
gint xave, yave;
get_pixel( drawable, x1, y1, tl);
get_pixel( drawable, x1, y2, bl);
get_pixel( drawable, x2, y1, tr);
get_pixel( drawable, x2, y2, br);
rnd = (256.0 / (2.0 * (gdouble)scale_depth)) * turbulence;
ran = rnd;
xave = (x1 + x2) / 2;
yave = (y1 + y2) / 2;
if (xave == x1 && xave == x2 && yave == y1 && yave == y2){
return 0;
}
if (xave != x1 || xave != x2){
/* Left. */
AVE(ml, tl, bl);
add_random(ml, ran);
put_pixel( drawable, x1, yave, ml);
if (x1 != x2){
/* Right. */
AVE(mr, tr, br);
add_random(mr, ran);
put_pixel( drawable, x2, yave, mr);
}
}
if (yave != y1 || yave != y2){
if (x1 != xave || yave != y2){
/* Bottom. */
AVE(mb, bl, br);
add_random(mb, ran);
put_pixel( drawable, xave, y2, mb);
}
if (y1 != y2){
/* Top. */
AVE(mt, tl, tr);
add_random(mt, ran);
put_pixel( drawable, xave, y1, mt);
}
}
if (y1 != y2 || x1 != x2){
/* Middle pixel. */
AVE(mm, tl, br);
AVE(tmp, bl, tr);
AVE(mm, mm, tmp);
add_random(mm, ran);
put_pixel( drawable, xave, yave, mm);
}
count ++;
if (!(count % 2000)){
gimp_progress_update( (double) progress / (double) max_progress);
}
if ((x2 - x1) < 3 && (y2 - y1) < 3){
return 1;
}
return 0;
}
xm = (x1 + x2) >> 1;
ym = (y1 + y2) >> 1;
/* Top left. */
do_plasma( drawable, x1, y1, xm, ym, depth - 1, scale_depth + 1);
/* Bottom left. */
do_plasma( drawable, x1, ym, xm ,y2, depth - 1, scale_depth + 1);
/* Top right. */
do_plasma( drawable, xm, y1, x2 , ym, depth - 1, scale_depth + 1);
/* Bottom right. */
return do_plasma( drawable, xm, ym, x2, y2, depth - 1, scale_depth + 1);
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,611 +0,0 @@
/*
* "$Id$"
*
* Print plug-in EPSON ESC/P2 driver for the GIMP.
*
* Copyright 1997 Michael Sweet (mike@easysw.com)
*
* 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 the Free
* Software Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* Contents:
*
* escp2_print() - Print an image to an EPSON printer.
* escp2_write() - Send ESC/P2 graphics using TIFF packbits compression.
*
* Revision History:
*
* $Log$
* Revision 1.1.1.1 1997/11/24 22:03:34 sopwith
* Let's try this import one last time.
*
* Revision 1.3 1997/10/03 22:18:14 nobody
* updated print er too the latest version
*
* : ----------------------------------------------------------------------
*
* Revision 1.6 1997/07/30 20:33:05 mike
* Final changes for 1.1 release.
*
* Revision 1.6 1997/07/30 20:33:05 mike
* Final changes for 1.1 release.
*
* Revision 1.5 1997/07/30 18:47:39 mike
* Added scaling, orientation, and offset options.
*
* Revision 1.4 1997/07/15 20:57:11 mike
* Updated ESC 800/1520/3000 output code to use vertical spacing of 5 instead of 40.
*
* Revision 1.3 1997/07/03 13:21:15 mike
* Updated documentation for 1.0 release.
*
* Revision 1.2 1997/07/03 13:03:57 mike
* Added horizontal offset to try to center image.
* Got rid of initial vertical positioning since the top margin is
* now set properly.
*
* Revision 1.2 1997/07/03 13:03:57 mike
* Added horizontal offset to try to center image.
* Got rid of initial vertical positioning since the top margin is
* now set properly.
*
* Revision 1.1 1997/07/02 13:51:53 mike
* Initial revision
*/
#include "print.h"
/*
* Local functions...
*/
static void escp2_write(FILE *, unsigned char *, int, int, int, int, int, int);
/*
* 'escp2_print()' - Print an image to an EPSON printer.
*/
void
escp2_print(FILE *prn, /* I - Print file or command */
GDrawable *drawable, /* I - Image to print */
int media_size, /* I - Output size */
int xdpi, /* I - Horizontal resolution */
int ydpi, /* I - Vertical resolution */
int output_type, /* I - Color or grayscale? */
int model, /* I - Model of printer */
guchar *lut, /* I - Brightness lookup table */
guchar *cmap, /* I - Colormap (for indexed images) */
int orientation, /* I - Orientation of image */
int scaling, /* I - Scaling of image */
int left, /* I - Left offset of image (10ths) */
int top) /* I - Top offset of image (10ths) */
{
int x, y; /* Looping vars */
int n; /* Output number */
GPixelRgn rgn; /* Image region */
unsigned char *in, /* Input pixels */
*out, /* Output pixels */
*black, /* Black bitmap data */
*cyan, /* Cyan bitmap data */
*magenta, /* Magenta bitmap data */
*yellow; /* Yellow bitmap data */
int page_width, /* Width of page */
page_height, /* Height of page */
out_width, /* Width of image on page */
out_height, /* Height of image on page */
out_bpp, /* Output bytes per pixel */
temp_width, /* Temporary width of image on page */
temp_height, /* Temporary height of image on page */
landscape, /* True if we rotate the output 90 degrees */
length, /* Length of raster data */
errdiv, /* Error dividend */
errmod, /* Error modulus */
errval, /* Current error value */
errline, /* Current raster line */
errlast; /* Last raster line loaded */
convert_t colorfunc; /* Color conversion function... */
/*
* Setup a read-only pixel region for the entire image...
*/
gimp_pixel_rgn_init(&rgn, drawable, 0, 0, drawable->width, drawable->height,
FALSE, FALSE);
/*
* Choose the correct color conversion function...
*/
if (drawable->bpp < 3 && cmap == NULL)
output_type = OUTPUT_GRAY; /* Force grayscale output */
if (output_type == OUTPUT_COLOR)
{
out_bpp = 3;
if (drawable->bpp >= 3)
colorfunc = rgb_to_rgb;
else
colorfunc = indexed_to_rgb;
}
else
{
out_bpp = 1;
if (drawable->bpp >= 3)
colorfunc = rgb_to_gray;
else if (cmap == NULL)
colorfunc = gray_to_gray;
else
colorfunc = indexed_to_gray;
};
/*
* Compute the output size...
*/
landscape = 0;
page_width = media_width(media_size, xdpi);
page_height = media_height(media_size, ydpi);
/*
* Portrait width/height...
*/
out_width = page_width * scaling / 100;
out_height = out_width * ydpi / xdpi * drawable->height / drawable->width;
if (out_height > page_height)
{
out_height = page_height;
out_width = out_height * xdpi / ydpi * drawable->width / drawable->height;
};
/*
* Landscape width/height...
*/
temp_width = page_width * scaling / 100;
temp_height = temp_width * ydpi / xdpi * drawable->width / drawable->height;
if (temp_height > page_height)
{
temp_height = page_height;
temp_width = temp_height * xdpi / ydpi * drawable->height / drawable->width;
};
/*
* See which orientation has the greatest area...
*/
if ((temp_width * temp_height) > (out_width * out_height) &&
orientation != ORIENT_PORTRAIT)
{
out_width = temp_width;
out_height = temp_height;
landscape = 1;
/*
* Swap left/top offsets...
*/
x = top;
top = left;
left = x;
};
/*
* Let the user know what we're doing...
*/
gimp_progress_init("Printing...");
/*
* Send ESC/P2 initialization commands...
*/
fputs("\033@", prn); /* ESC/P2 reset */
fwrite("\033(G\001\000\001", 6, 1, prn); /* Enter graphics mode */
switch (ydpi) /* Set line feed increment */
{
case 180 :
fwrite("\033(U\001\000\024", 6, 1, prn);
break;
case 360 :
fwrite("\033(U\001\000\012", 6, 1, prn);
break;
case 720 :
fwrite("\033(U\001\000\005", 6, 1, prn);
break;
};
fwrite("\033(C\002\000", 5, 1, prn); /* Page length */
n = page_height + ydpi;
putc(n & 255, prn);
putc(n >> 8, prn);
if (left < 0 || top < 0)
{
left = (page_width - out_width) / 2;
top = (page_height - out_height + ydpi) / 2;
}
else
{
left *= xdpi / 10;
top = top * ydpi / 10 + ydpi / 2;
};
fwrite("\033(c\004\000", 5, 1, prn); /* Top/bottom margins */
putc(top & 255, prn);
putc(top >> 8, prn);
n = page_height + ydpi / 2;
putc(n & 255, prn);
putc(n >> 8, prn);
switch (model) /* Printer specific initialization */
{
case 0 : /* ESC */
break;
case 1 : /* ESC Pro, Pro XL, 400, 500 */
fwrite("\033(e\002\000\000\001", 7, 1, prn); /* Small dots */
break;
case 2 : /* ESC 1500 */
fwrite("\033(e\002\000\000\001", 7, 1, prn); /* Small dots */
break;
case 3 : /* ESC 600 */
if (output_type == OUTPUT_GRAY)
fwrite("\033(K\002\000\000\001", 7, 1, prn); /* Fast black printing */
else
fwrite("\033(K\002\000\000\002", 7, 1, prn); /* Color printing */
fwrite("\033(e\002\000\000\003", 7, 1, prn); /* Small dots */
break;
case 4 : /* ESC 800, 1520, 3000 */
if (output_type == OUTPUT_GRAY)
fwrite("\033(K\002\000\000\001", 7, 1, prn); /* Fast black printing */
else
fwrite("\033(K\002\000\000\002", 7, 1, prn); /* Color printing */
fwrite("\033(e\002\000\000\002", 7, 1, prn); /* Small dots */
break;
};
/*
* Allocate memory for the raster data...
*/
length = (out_width + 7) / 8;
if (output_type == OUTPUT_GRAY)
{
black = g_malloc(length);
cyan = NULL;
magenta = NULL;
yellow = NULL;
}
else
{
cyan = g_malloc(length);
magenta = g_malloc(length);
yellow = g_malloc(length);
if (model != 2)
black = g_malloc(length);
else
black = NULL;
};
/*
* Output the page, rotating as necessary...
*/
if (landscape)
{
in = g_malloc(drawable->height * drawable->bpp);
out = g_malloc(drawable->height * out_bpp);
errdiv = drawable->width / out_height;
errmod = drawable->width % out_height;
errval = 0;
errlast = -1;
errline = drawable->width - 1;
for (x = 0; x < out_height; x ++)
{
#ifdef DEBUG
printf("escp2_print: x = %d, line = %d, val = %d, mod = %d, height = %d\n",
x, errline, errval, errmod, out_height);
#endif /* DEBUG */
if ((x & 255) == 0)
gimp_progress_update((double)x / (double)out_height);
if (errline != errlast)
{
errlast = errline;
gimp_pixel_rgn_get_col(&rgn, in, errline, 0, drawable->height);
};
(*colorfunc)(in, out, drawable->height, drawable->bpp, lut, cmap);
if (output_type == OUTPUT_GRAY)
{
dither_black(out, x, drawable->height, out_width, black);
escp2_write(prn, black, length, 0, ydpi, model, out_width, left);
}
else
{
dither_cmyk(out, x, drawable->height, out_width, cyan, magenta,
yellow, black);
escp2_write(prn, cyan, length, 2, ydpi, model, out_width, left);
escp2_write(prn, magenta, length, 1, ydpi, model, out_width, left);
escp2_write(prn, yellow, length, 4, ydpi, model, out_width, left);
if (black != NULL)
escp2_write(prn, black, length, 0, ydpi, model, out_width, left);
};
fwrite("\033(v\002\000\001\000", 7, 1, prn); /* Feed one line */
errval += errmod;
errline -= errdiv;
if (errval >= out_height)
{
errval -= out_height;
errline --;
};
};
}
else
{
in = g_malloc(drawable->width * drawable->bpp);
out = g_malloc(drawable->width * out_bpp);
errdiv = drawable->height / out_height;
errmod = drawable->height % out_height;
errval = 0;
errlast = -1;
errline = 0;
for (y = 0; y < out_height; y ++)
{
#ifdef DEBUG
printf("escp2_print: y = %d, line = %d, val = %d, mod = %d, height = %d\n",
y, errline, errval, errmod, out_height);
#endif /* DEBUG */
if ((y & 255) == 0)
gimp_progress_update((double)y / (double)out_height);
if (errline != errlast)
{
errlast = errline;
gimp_pixel_rgn_get_row(&rgn, in, 0, errline, drawable->width);
};
(*colorfunc)(in, out, drawable->width, drawable->bpp, lut, cmap);
if (output_type == OUTPUT_GRAY)
{
dither_black(out, y, drawable->width, out_width, black);
escp2_write(prn, black, length, 0, ydpi, model, out_width, left);
}
else
{
dither_cmyk(out, y, drawable->width, out_width, cyan, magenta,
yellow, black);
escp2_write(prn, cyan, length, 2, ydpi, model, out_width, left);
escp2_write(prn, magenta, length, 1, ydpi, model, out_width, left);
escp2_write(prn, yellow, length, 4, ydpi, model, out_width, left);
if (black != NULL)
escp2_write(prn, black, length, 0, ydpi, model, out_width, left);
};
fwrite("\033(v\002\000\001\000", 7, 1, prn); /* Feed one line */
errval += errmod;
errline += errdiv;
if (errval >= out_height)
{
errval -= out_height;
errline ++;
};
};
};
/*
* Cleanup...
*/
g_free(in);
g_free(out);
if (black != NULL)
g_free(black);
if (cyan != NULL)
{
g_free(cyan);
g_free(magenta);
g_free(yellow);
};
putc('\014', prn); /* Eject page */
fputs("\033@", prn); /* ESC/P2 reset */
}
/*
* 'escp2_write()' - Send ESC/P2 graphics using TIFF packbits compression.
*/
void
escp2_write(FILE *prn, /* I - Print file or command */
unsigned char *line, /* I - Output bitmap data */
int length, /* I - Length of bitmap data */
int plane, /* I - True if this is the last plane */
int ydpi, /* I - Vertical resolution */
int model, /* I - Printer model */
int width, /* I - Printed width */
int offset) /* I - Offset from left side */
{
unsigned char comp_buf[1536], /* Compression buffer */
*comp_ptr, /* Current slot in buffer */
*start, /* Start of compressed data */
repeat; /* Repeating char */
int count, /* Count of compressed bytes */
tcount; /* Temporary count < 128 */
static int last_plane = 0; /* Last color plane printed */
/*
* Don't send blank lines...
*/
if (line[0] == 0 && memcmp(line, line + 1, length - 1) == 0)
return;
/*
* Compress using TIFF "packbits" run-length encoding...
*/
comp_ptr = comp_buf;
while (length > 0)
{
/*
* Get a run of non-repeated chars...
*/
start = line;
line += 2;
length -= 2;
while (length > 0 && (line[-2] != line[-1] || line[-1] != line[0]))
{
line ++;
length --;
};
line -= 2;
length += 2;
/*
* Output the non-repeated sequences (max 128 at a time).
*/
count = line - start;
while (count > 0)
{
tcount = count > 128 ? 128 : count;
comp_ptr[0] = tcount - 1;
memcpy(comp_ptr + 1, start, tcount);
comp_ptr += tcount + 1;
start += tcount;
count -= tcount;
};
if (length <= 0)
break;
/*
* Find the repeated sequences...
*/
start = line;
repeat = line[0];
line ++;
length --;
while (length > 0 && *line == repeat)
{
line ++;
length --;
};
/*
* Output the repeated sequences (max 128 at a time).
*/
count = line - start;
while (count > 0)
{
tcount = count > 128 ? 128 : count;
comp_ptr[0] = 1 - tcount;
comp_ptr[1] = repeat;
comp_ptr += 2;
count -= tcount;
};
};
/*
* Set the print head position.
*/
putc('\r', prn);
fprintf(prn, "\033\\%c%c", offset & 255, offset >> 8);
/*
* Set the color if necessary...
*/
if (last_plane != plane)
{
last_plane = plane;
fprintf(prn, "\033r%c", plane);
};
/*
* Send a line of raster graphics...
*/
switch (ydpi) /* Raster graphics header */
{
case 180 :
fwrite("\033.\001\024\024\001", 6, 1, prn);
break;
case 360 :
fwrite("\033.\001\012\012\001", 6, 1, prn);
break;
case 720 :
if (model == 3)
fwrite("\033.\001\050\005\001", 6, 1, prn);
else
fwrite("\033.\001\005\005\001", 6, 1, prn);
break;
};
putc(width & 255, prn); /* Width of raster line in pixels */
putc(width >> 8, prn);
fwrite(comp_buf, comp_ptr - comp_buf, 1, prn);
}
/*
* End of "$Id$".
*/

View File

@ -1,621 +0,0 @@
/*
* "$Id$"
*
* Print plug-in HP PCL driver for the GIMP.
*
* Copyright 1997 Michael Sweet (mike@easysw.com)
*
* 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 the Free
* Software Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* Contents:
*
* pcl_print() - Print an image to an HP printer.
* pcl_mode0() - Send PCL graphics using mode 0 (no) compression.
* pcl_mode2() - Send PCL graphics using mode 2 (TIFF) compression.
*
* Revision History:
*
* $Log$
* Revision 1.1.1.1 1997/11/24 22:03:34 sopwith
* Let's try this import one last time.
*
* Revision 1.3 1997/10/03 22:18:14 nobody
* updated print er too the latest version
*
* : ----------------------------------------------------------------------
*
* Revision 1.6 1997/10/02 17:57:26 mike
* Updated positioning code to use "decipoint" commands.
*
* Revision 1.5 1997/07/30 20:33:05 mike
* Final changes for 1.1 release.
*
* Revision 1.4 1997/07/30 18:47:39 mike
* Added scaling, orientation, and offset options.
*
* Revision 1.3 1997/07/03 13:24:12 mike
* Updated documentation for 1.0 release.
*
* Revision 1.2 1997/07/02 18:48:14 mike
* Added mode 2 compression code.
* Fixed bug in pcl_mode0 and pcl_mode2 - wasn't sending 'V' or 'W' at
* the right times.
*
* Revision 1.2 1997/07/02 18:48:14 mike
* Added mode 2 compression code.
* Fixed bug in pcl_mode0 and pcl_mode2 - wasn't sending 'V' or 'W' at
* the right times.
*
* Revision 1.1 1997/07/02 13:51:53 mike
* Initial revision
*/
#include "print.h"
/*
* Local functions...
*/
static void pcl_mode0(FILE *, unsigned char *, int, int);
static void pcl_mode2(FILE *, unsigned char *, int, int);
/*
* 'pcl_print()' - Print an image to an HP printer.
*/
void
pcl_print(FILE *prn, /* I - Print file or command */
GDrawable *drawable, /* I - Image to print */
int media_size, /* I - Output size */
int xdpi, /* I - Horizontal resolution */
int ydpi, /* I - Vertical resolution */
int output_type, /* I - Color or grayscale? */
int model, /* I - Model of printer */
guchar *lut, /* I - Brightness lookup table */
guchar *cmap, /* I - Colormap (for indexed images) */
int orientation, /* I - Orientation of image */
int scaling, /* I - Scaling of image */
int left, /* I - Left offset of image (10ths) */
int top) /* I - Top offset of image (10ths) */
{
int x, y; /* Looping vars */
GPixelRgn rgn; /* Image region */
unsigned char *in, /* Input pixels */
*out, /* Output pixels */
*black, /* Black bitmap data */
*cyan, /* Cyan bitmap data */
*magenta, /* Magenta bitmap data */
*yellow; /* Yellow bitmap data */
int page_width, /* Width of page */
page_height, /* Height of page */
out_width, /* Width of image on page */
out_height, /* Height of image on page */
out_bpp, /* Output bytes per pixel */
temp_width, /* Temporary width of image on page */
temp_height, /* Temporary height of image on page */
landscape, /* True if we rotate the output 90 degrees */
length, /* Length of raster data */
errdiv, /* Error dividend */
errmod, /* Error modulus */
errval, /* Current error value */
errline, /* Current raster line */
errlast; /* Last raster line loaded */
convert_t colorfunc; /* Color conversion function... */
void (*writefunc)(FILE *, unsigned char *, int, int);
/* PCL output function */
/*
* Setup a read-only pixel region for the entire image...
*/
gimp_pixel_rgn_init(&rgn, drawable, 0, 0, drawable->width, drawable->height,
FALSE, FALSE);
/*
* Choose the correct color conversion function...
*/
if ((drawable->bpp < 3 && cmap == NULL) || model <= 500)
output_type = OUTPUT_GRAY; /* Force grayscale output */
if (output_type == OUTPUT_COLOR)
{
out_bpp = 3;
if (drawable->bpp >= 3)
colorfunc = rgb_to_rgb;
else
colorfunc = indexed_to_rgb;
if (model == 800)
xdpi = ydpi = 300;
}
else
{
out_bpp = 1;
if (drawable->bpp >= 3)
colorfunc = rgb_to_gray;
else if (cmap == NULL)
colorfunc = gray_to_gray;
else
colorfunc = indexed_to_gray;
};
/*
* Compute the output size...
*/
landscape = 0;
page_width = media_width(media_size, xdpi);
page_height = media_height(media_size, ydpi);
/*
* Portrait width/height...
*/
out_width = page_width * scaling / 100;
out_height = out_width * ydpi / xdpi * drawable->height / drawable->width;
if (out_height > page_height)
{
out_height = page_height;
out_width = out_height * xdpi / ydpi * drawable->width / drawable->height;
};
/*
* Landscape width/height...
*/
temp_width = page_width * scaling / 100;
temp_height = temp_width * ydpi / xdpi * drawable->width / drawable->height;
if (temp_height > page_height)
{
temp_height = page_height;
temp_width = temp_height * xdpi / ydpi * drawable->height / drawable->width;
};
/*
* See which orientation has the greatest area...
*/
if ((temp_width * temp_height) > (out_width * out_height) &&
orientation != ORIENT_PORTRAIT)
{
out_width = temp_width;
out_height = temp_height;
landscape = 1;
/*
* Swap left/top offsets...
*/
x = top;
top = left;
left = x;
};
/*
* Let the user know what we're doing...
*/
gimp_progress_init("Printing...");
/*
* Send PCL initialization commands...
*/
fputs("\033E", prn); /* PCL reset */
switch (media_size) /* Set media size... */
{
case MEDIA_LETTER :
fputs("\033&l2A", prn);
break;
case MEDIA_LEGAL :
fputs("\033&l3A", prn);
break;
case MEDIA_TABLOID :
fputs("\033&l6A", prn);
break;
case MEDIA_A4 :
fputs("\033&l26A", prn);
break;
case MEDIA_A3 :
fputs("\033&l27A", prn);
break;
};
if (xdpi != ydpi) /* Set resolution */
{
/*
* Send 26-byte configure image data command with horizontal and
* vertical resolutions as well as a color count...
*/
fputs("\033*g26W", prn);
putc(2, prn); /* Format 2 */
if (output_type == OUTPUT_COLOR)
putc(4, prn); /* # output planes */
else
putc(1, prn); /* # output planes */
putc(xdpi >> 8, prn); /* Black resolution */
putc(xdpi, prn);
putc(ydpi >> 8, prn);
putc(ydpi, prn);
putc(0, prn);
putc(2, prn); /* # of black levels */
putc(xdpi >> 8, prn); /* Cyan resolution */
putc(xdpi, prn);
putc(ydpi >> 8, prn);
putc(ydpi, prn);
putc(0, prn);
putc(2, prn); /* # of cyan levels */
putc(xdpi >> 8, prn); /* Magenta resolution */
putc(xdpi, prn);
putc(ydpi >> 8, prn);
putc(ydpi, prn);
putc(0, prn);
putc(2, prn); /* # of magenta levels */
putc(xdpi >> 8, prn); /* Yellow resolution */
putc(xdpi, prn);
putc(ydpi >> 8, prn);
putc(ydpi, prn);
putc(0, prn);
putc(2, prn); /* # of yellow levels */
}
else
{
fprintf(prn, "\033*t%dR", xdpi); /* Simple resolution */
if (output_type == OUTPUT_COLOR)
{
if (model == 501 || model == 1200)
fputs("\033*r-3U", prn); /* Simple CMY color */
else
fputs("\033*r-4U", prn); /* Simple KCMY color */
};
};
if (model < 3 || model == 500)
fputs("\033*b0M", prn); /* Mode 0 (no compression) */
else
fputs("\033*b2M", prn); /* Mode 2 (TIFF) */
if (left < 0 || top < 0)
{
left = (page_width - out_width) / 2;
top = (page_height - out_height) / 2;
}
else
{
left *= 30;
top *= 30;
};
fprintf(prn, "\033&a%dH", 720 * left / xdpi); /* Set left raster position */
fprintf(prn, "\033&a%dV", 720 * top / ydpi); /* Set top raster position */
fprintf(prn, "\033*r%dS", out_width); /* Set raster width */
fprintf(prn, "\033*r%dT", out_height); /* Set raster height */
fputs("\033*r1A", prn); /* Start GFX */
/*
* Allocate memory for the raster data...
*/
length = (out_width + 7) / 8;
if (output_type == OUTPUT_GRAY)
{
black = g_malloc(length);
cyan = NULL;
magenta = NULL;
yellow = NULL;
}
else
{
cyan = g_malloc(length);
magenta = g_malloc(length);
yellow = g_malloc(length);
if (model != 501 && model != 1200)
black = g_malloc(length);
else
black = NULL;
};
/*
* Output the page, rotating as necessary...
*/
if (model < 3 || model == 500)
writefunc = pcl_mode0;
else
writefunc = pcl_mode2;
if (landscape)
{
in = g_malloc(drawable->height * drawable->bpp);
out = g_malloc(drawable->height * out_bpp);
errdiv = drawable->width / out_height;
errmod = drawable->width % out_height;
errval = 0;
errlast = -1;
errline = drawable->width - 1;
for (x = 0; x < out_height; x ++)
{
#ifdef DEBUG
printf("pcl_print: x = %d, line = %d, val = %d, mod = %d, height = %d\n",
x, errline, errval, errmod, out_height);
#endif /* DEBUG */
if ((x & 255) == 0)
gimp_progress_update((double)x / (double)out_height);
if (errline != errlast)
{
errlast = errline;
gimp_pixel_rgn_get_col(&rgn, in, errline, 0, drawable->height);
};
(*colorfunc)(in, out, drawable->height, drawable->bpp, lut, cmap);
if (output_type == OUTPUT_GRAY)
{
dither_black(out, x, drawable->height, out_width, black);
(*writefunc)(prn, black, length, 1);
}
else
{
dither_cmyk(out, x, drawable->height, out_width, cyan, magenta,
yellow, black);
if (black != NULL)
(*writefunc)(prn, black, length, 0);
(*writefunc)(prn, cyan, length, 0);
(*writefunc)(prn, magenta, length, 0);
(*writefunc)(prn, yellow, length, 1);
};
errval += errmod;
errline -= errdiv;
if (errval >= out_height)
{
errval -= out_height;
errline --;
};
};
}
else
{
in = g_malloc(drawable->width * drawable->bpp);
out = g_malloc(drawable->width * out_bpp);
errdiv = drawable->height / out_height;
errmod = drawable->height % out_height;
errval = 0;
errlast = -1;
errline = 0;
for (y = 0; y < out_height; y ++)
{
#ifdef DEBUG
printf("pcl_print: y = %d, line = %d, val = %d, mod = %d, height = %d\n",
y, errline, errval, errmod, out_height);
#endif /* DEBUG */
if ((y & 255) == 0)
gimp_progress_update((double)y / (double)out_height);
if (errline != errlast)
{
errlast = errline;
gimp_pixel_rgn_get_row(&rgn, in, 0, errline, drawable->width);
};
(*colorfunc)(in, out, drawable->width, drawable->bpp, lut, cmap);
if (output_type == OUTPUT_GRAY)
{
dither_black(out, y, drawable->width, out_width, black);
(*writefunc)(prn, black, length, 1);
}
else
{
dither_cmyk(out, y, drawable->width, out_width, cyan, magenta,
yellow, black);
if (black != NULL)
(*writefunc)(prn, black, length, 0);
(*writefunc)(prn, cyan, length, 0);
(*writefunc)(prn, magenta, length, 0);
(*writefunc)(prn, yellow, length, 1);
};
errval += errmod;
errline += errdiv;
if (errval >= out_height)
{
errval -= out_height;
errline ++;
};
};
};
/*
* Cleanup...
*/
g_free(in);
g_free(out);
if (black != NULL)
g_free(black);
if (cyan != NULL)
{
g_free(cyan);
g_free(magenta);
g_free(yellow);
};
switch (model) /* End raster graphics */
{
case 1 :
case 2 :
case 3 :
case 500 :
fputs("\033*rB", prn);
break;
default :
fputs("\033*rbC", prn);
break;
};
fputs("\033&l0H", prn); /* Eject page */
fputs("\033E", prn); /* PCL reset */
}
/*
* 'pcl_mode0()' - Send PCL graphics using mode 0 (no) compression.
*/
void
pcl_mode0(FILE *prn, /* I - Print file or command */
unsigned char *line, /* I - Output bitmap data */
int length, /* I - Length of bitmap data */
int last_plane) /* I - True if this is the last plane */
{
fprintf(prn, "\033*b%d%c", length, last_plane ? 'W' : 'V');
fwrite(line, length, 1, prn);
}
/*
* 'pcl_mode2()' - Send PCL graphics using mode 2 (TIFF) compression.
*/
void
pcl_mode2(FILE *prn, /* I - Print file or command */
unsigned char *line, /* I - Output bitmap data */
int length, /* I - Length of bitmap data */
int last_plane) /* I - True if this is the last plane */
{
unsigned char comp_buf[1536], /* Compression buffer */
*comp_ptr, /* Current slot in buffer */
*start, /* Start of compressed data */
repeat; /* Repeating char */
int count, /* Count of compressed bytes */
tcount; /* Temporary count < 128 */
/*
* Compress using TIFF "packbits" run-length encoding...
*/
comp_ptr = comp_buf;
while (length > 0)
{
/*
* Get a run of non-repeated chars...
*/
start = line;
line += 2;
length -= 2;
while (length > 0 && (line[-2] != line[-1] || line[-1] != line[0]))
{
line ++;
length --;
};
line -= 2;
length += 2;
/*
* Output the non-repeated sequences (max 128 at a time).
*/
count = line - start;
while (count > 0)
{
tcount = count > 128 ? 128 : count;
comp_ptr[0] = tcount - 1;
memcpy(comp_ptr + 1, start, tcount);
comp_ptr += tcount + 1;
start += tcount;
count -= tcount;
};
if (length <= 0)
break;
/*
* Find the repeated sequences...
*/
start = line;
repeat = line[0];
line ++;
length --;
while (length > 0 && *line == repeat)
{
line ++;
length --;
};
/*
* Output the repeated sequences (max 128 at a time).
*/
count = line - start;
while (count > 0)
{
tcount = count > 128 ? 128 : count;
comp_ptr[0] = 1 - tcount;
comp_ptr[1] = repeat;
comp_ptr += 2;
count -= tcount;
};
};
/*
* Send a line of raster graphics...
*/
fprintf(prn, "\033*b%d%c", comp_ptr - comp_buf, last_plane ? 'W' : 'V');
fwrite(comp_buf, comp_ptr - comp_buf, 1, prn);
}
/*
* End of "$Id$".
*/

View File

@ -1,342 +0,0 @@
/*
* "$Id$"
*
* Print plug-in Adobe PostScript driver for the GIMP.
*
* Copyright 1997 Michael Sweet (mike@easysw.com)
*
* 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 the Free
* Software Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* Contents:
*
* ps_print() - Print an image to a PostScript printer.
* ps_hex() - Print binary data as a series of hexadecimal numbers.
*
* Revision History:
*
* $Log$
* Revision 1.1.1.1 1997/11/24 22:03:34 sopwith
* Let's try this import one last time.
*
* Revision 1.3 1997/10/03 22:18:14 nobody
* updated print er too the latest version
*
* : ----------------------------------------------------------------------
*
* Revision 1.7 1997/07/30 20:33:05 mike
* Final changes for 1.1 release.
*
* Revision 1.7 1997/07/30 20:33:05 mike
* Final changes for 1.1 release.
*
* Revision 1.6 1997/07/30 18:47:39 mike
* Added scaling, orientation, and offset options.
*
* Revision 1.5 1997/07/26 18:38:55 mike
* Bug - was using asctime instead of ctime... D'oh!
*
* Revision 1.4 1997/07/26 18:19:54 mike
* Fixed positioning/scaling bug.
*
* Revision 1.3 1997/07/03 13:26:46 mike
* Updated documentation for 1.0 release.
*
* Revision 1.2 1997/07/02 18:49:36 mike
* Forgot to free memory buffers...
*
* Revision 1.2 1997/07/02 18:49:36 mike
* Forgot to free memory buffers...
*
* Revision 1.1 1997/07/02 13:51:53 mike
* Initial revision
*/
#include "print.h"
/*
* Local functions...
*/
static void ps_hex(FILE *, guchar *, int);
/*
* 'ps_print()' - Print an image to a PostScript printer.
*/
void
ps_print(FILE *prn, /* I - File to print to */
GDrawable *drawable, /* I - Image to print */
int media_size, /* I - Size of output */
int xdpi, /* I - Horizontal resolution (always 72) */
int ydpi, /* I - Vertical resolution (always 72) */
int output_type, /* I - Output type (color/grayscale) */
int model, /* I - Model (ignored) */
guchar *lut, /* I - Brightness lookup table */
guchar *cmap, /* I - Colormap (for indexed images) */
int orientation, /* I - Orientation of image */
int scaling, /* I - Scaling of image */
int left, /* I - Left offset of image (10ths) */
int top) /* I - Top offset of image (10ths) */
{
int x, y; /* Looping vars */
GPixelRgn rgn; /* Image region */
guchar *in, /* Input pixels from image */
*out, /* Output pixels for printer */
*outptr; /* Current output pixel */
int page_width, /* Width of page */
page_height, /* Height of page */
out_width, /* Width of image on page */
out_height, /* Height of image on page */
out_bpp, /* Output bytes per pixel */
temp_width, /* Temporary width of image on page */
temp_height, /* Temporary height of image on page */
landscape; /* True if we rotate the output 90 degrees */
time_t curtime; /* Current time of day */
convert_t colorfunc; /* Color conversion function... */
/*
* Setup a read-only pixel region for the entire image...
*/
gimp_pixel_rgn_init(&rgn, drawable, 0, 0, drawable->width, drawable->height,
FALSE, FALSE);
/*
* Choose the correct color conversion function...
*/
if (drawable->bpp < 3 && cmap == NULL)
output_type = OUTPUT_GRAY; /* Force grayscale output */
if (output_type == OUTPUT_COLOR)
{
out_bpp = 3;
if (drawable->bpp >= 3)
colorfunc = rgb_to_rgb;
else
colorfunc = indexed_to_rgb;
}
else
{
out_bpp = 1;
if (drawable->bpp >= 3)
colorfunc = rgb_to_gray;
else if (cmap == NULL)
colorfunc = gray_to_gray;
else
colorfunc = indexed_to_gray;
};
/*
* Compute the output size...
*/
landscape = 0;
page_width = media_width(media_size, xdpi);
page_height = media_height(media_size, ydpi);
/*
* Portrait width/height...
*/
out_width = page_width * scaling / 100;
out_height = out_width * ydpi / xdpi * drawable->height / drawable->width;
if (out_height > page_height)
{
out_height = page_height;
out_width = out_height * xdpi / ydpi * drawable->width / drawable->height;
};
/*
* Landscape width/height...
*/
temp_width = page_width * scaling / 100;
temp_height = temp_width * ydpi / xdpi * drawable->width / drawable->height;
if (temp_height > page_height)
{
temp_height = page_height;
temp_width = temp_height * xdpi / ydpi * drawable->height / drawable->width;
};
/*
* See which orientation has the greatest area...
*/
if ((temp_width * temp_height) > (out_width * out_height) &&
orientation != ORIENT_PORTRAIT)
{
out_width = temp_width;
out_height = temp_height;
landscape = 1;
/*
* Swap left/top offsets...
*/
x = top;
top = left;
left = x;
};
/*
* Let the user know what we're doing...
*/
gimp_progress_init("Printing...");
/*
* Output a standard PostScript header with DSC comments...
*/
curtime = time(NULL);
fputs("%!PS-Adobe-3.0\n", prn);
fputs("%%Creator: " PLUG_IN_NAME " plug-in V" PLUG_IN_VERSION " for GIMP.\n", prn);
fprintf(prn, "%%%%CreationDate: %s", ctime(&curtime));
fputs("%%Copyright: 1997 by Michael Sweet (mike@easysw.com)\n", prn);
fprintf(prn, "%%%%BoundingBox: %d %d %d %d\n",
(page_width - out_width) / 2 + 18, (page_height - out_height) / 2 + 36,
(page_width + out_width) / 2 + 18, (page_height + out_height) / 2 + 36);
fputs("%%DocumentData: Clean7Bit\n", prn);
fprintf(prn, "%%%%LanguageLevel: %d\n", output_type + 1);
fputs("%%Pages: 1\n", prn);
fputs("%%Orientation: Portrait\n", prn);
fputs("%%EndComments\n", prn);
/*
* Output the page, rotating as necessary...
*/
fputs("%%Page: 1\n", prn);
fputs("gsave\n", prn);
if (top < 0 || left < 0)
{
left = (page_width - out_width) / 2 + 18;
top = (page_height - out_height) / 2 + 36;
}
else
{
left = 72 * left / 10 + 18;
top = page_height - out_height - 72 * top / 10 + 36;
};
fprintf(prn, "%d %d translate\n", left, top);
fprintf(prn, "%d %d scale\n", out_width, out_height);
if (landscape)
{
in = g_malloc(drawable->height * drawable->bpp);
out = g_malloc(drawable->height * out_bpp);
fprintf(prn, "/picture %d string def\n", drawable->height * out_bpp);
if (output_type == OUTPUT_GRAY)
fprintf(prn, "%d %d 8 [%d 0 0 %d 0 %d] {currentfile picture readhexstring pop} image\n",
drawable->height, drawable->width,
drawable->height, drawable->width, 0);
else
fprintf(prn, "%d %d 8 [%d 0 0 %d 0 %d] {currentfile picture readhexstring pop} false 3 colorimage\n",
drawable->height, drawable->width,
drawable->height, drawable->width, 0);
for (x = 0; x < drawable->width; x ++)
{
if ((x & 15) == 0)
gimp_progress_update((double)x / (double)drawable->width);
gimp_pixel_rgn_get_col(&rgn, in, x, 0, drawable->height);
(*colorfunc)(in, out, drawable->height, drawable->bpp, lut, cmap);
ps_hex(prn, out, drawable->height * out_bpp);
};
}
else
{
in = g_malloc(drawable->width * drawable->bpp);
out = g_malloc(drawable->width * out_bpp);
fprintf(prn, "/picture %d string def\n", drawable->width * out_bpp);
if (output_type == OUTPUT_GRAY)
fprintf(prn, "%d %d 8 [%d 0 0 %d 0 %d] {currentfile picture readhexstring pop} image\n",
drawable->width, drawable->height,
drawable->width, -drawable->height, drawable->height);
else
fprintf(prn, "%d %d 8 [%d 0 0 %d 0 %d] {currentfile picture readhexstring pop} false 3 colorimage\n",
drawable->width, drawable->height,
drawable->width, -drawable->height, drawable->height);
for (y = 0; y < drawable->height; y ++)
{
if ((y & 15) == 0)
gimp_progress_update((double)y / (double)drawable->height);
gimp_pixel_rgn_get_row(&rgn, in, 0, y, drawable->width);
(*colorfunc)(in, out, drawable->width, drawable->bpp, lut, cmap);
ps_hex(prn, out, drawable->width * out_bpp);
};
};
g_free(in);
g_free(out);
fputs("grestore\n", prn);
fputs("showpage\n", prn);
fputs("%%EndPage\n", prn);
fputs("%%EOF\n", prn);
}
/*
* 'ps_hex()' - Print binary data as a series of hexadecimal numbers.
*/
static void
ps_hex(FILE *prn, /* I - File to print to */
guchar *data, /* I - Data to print */
int length) /* I - Number of bytes to print */
{
static char *hex = "0123456789ABCDEF";
while (length > 0)
{
/*
* Put the hex chars out to the file; note that we don't use fprintf()
* for speed reasons...
*/
putc(hex[*data >> 4], prn);
putc(hex[*data & 15], prn);
data ++;
length --;
};
putc('\n', prn);
}
/*
* End of "$Id$".
*/

View File

@ -1,542 +0,0 @@
/*
* "$Id$"
*
* Print plug-in driver utility functions for the GIMP.
*
* Copyright 1997 Michael Sweet (mike@easysw.com)
*
* 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 the Free
* Software Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* Contents:
*
* dither_black() - Dither grayscale pixels to black.
* dither_cmyk() - Dither RGB pixels to cyan, magenta, yellow, and black.
* gray_to_gray() - Convert grayscale image data to grayscale (brightness
* adjusted).
* indexed_to_gray() - Convert indexed image data to grayscale.
* indexed_to_rgb() - Convert indexed image data to RGB.
* media_width() - Get the addressable width of the page.
* media_height() - Get the addressable height of the page.
* rgb_to_gray() - Convert RGB image data to grayscale.
* rgb_to_rgb() - Convert RGB image data to RGB (brightness adjusted).
*
* Revision History:
*
* $Log$
* Revision 1.1.1.1 1997/11/24 22:03:34 sopwith
* Let's try this import one last time.
*
* Revision 1.3 1997/10/03 22:18:14 nobody
* updated print er too the latest version
*
* : ----------------------------------------------------------------------
*
* Revision 1.7 1997/10/02 17:57:26 mike
* Replaced ordered dither with Burkes dither (error-diffusion).
* Now dither K separate from CMY.
*
* Revision 1.6 1997/07/30 20:33:05 mike
* Final changes for 1.1 release.
*
* Revision 1.5 1997/07/26 18:43:04 mike
* Fixed dither_black and dither_cmyk - wasn't clearing extra bits
* (caused problems with A3/A4 size output).
*
* Revision 1.5 1997/07/26 18:43:04 mike
* Fixed dither_black and dither_cmyk - wasn't clearing extra bits
* (caused problems with A3/A4 size output).
*
* Revision 1.4 1997/07/02 18:46:26 mike
* Fixed stupid bug in dither_black() - wasn't comparing against gray
* pixels (comparing against the first black byte - d'oh!)
* Changed 255 in dither matrix to 254 to shade correctly.
*
* Revision 1.4 1997/07/02 18:46:26 mike
* Fixed stupid bug in dither_black() - wasn't comparing against gray
* pixels (comparing against the first black byte - d'oh!)
* Changed 255 in dither matrix to 254 to shade correctly.
*
* Revision 1.3 1997/07/02 13:51:53 mike
* Added rgb_to_rgb and gray_to_gray conversion functions.
* Standardized calling args to conversion functions.
*
* Revision 1.2 1997/07/01 19:28:44 mike
* Updated dither matrix.
* Fixed scaling bugs in dither_*() functions.
*
* Revision 1.1 1997/06/19 02:18:15 mike
* Initial revision
*/
#include "print.h"
/*
* RGB to grayscale luminance constants...
*/
#define LUM_RED 31
#define LUM_GREEN 61
#define LUM_BLUE 8
/*
* Error buffer for dither functions. This needs to be at least 11xMAXDPI
* (currently 720) to avoid problems...
*/
int error[2][4][11*720+4] = { 0 };
/*
* 'dither_black()' - Dither grayscale pixels to black.
*/
void
dither_black(guchar *gray, /* I - Grayscale pixels */
int row, /* I - Current Y coordinate */
int src_width, /* I - Width of input row */
int dst_width, /* I - Width of output row */
unsigned char *black) /* O - Black bitmap pixels */
{
int x, /* Current X coordinate */
xerror, /* X error count */
xstep, /* X step */
xmod, /* X error modulus */
length; /* Length of output bitmap in bytes */
unsigned char bit, /* Current bit */
*kptr; /* Current black pixel */
int k, /* Current black error */
*kerror0, /* Pointer to current error row */
*kerror1; /* Pointer to next error row */
xstep = src_width / dst_width;
xmod = src_width % dst_width;
length = (dst_width + 7) / 8;
kerror0 = error[row & 1][3] + 2;
kerror1 = error[1 - (row & 1)][3] + 2;
kerror1[0] = 0;
kerror1[1] = 0;
memset(black, 0, length);
for (x = 0, bit = 128, kptr = black, xerror = 0;
x < dst_width;
x ++, kerror0 ++, kerror1 ++)
{
k = 255 - *gray + *kerror0;
if (k > 127)
{
*kptr |= bit;
k -= 255;
};
kerror0[1] += k / 4;
kerror0[2] += k / 8;
kerror1[-2] += k / 16;
kerror1[-1] += k / 8;
kerror1[0] += k / 4;
kerror1[1] += k / 8;
kerror1[2] = k / 16;
if (bit == 1)
{
kptr ++;
bit = 128;
}
else
bit >>= 1;
gray += xstep;
xerror += xmod;
if (xerror >= dst_width)
{
xerror -= dst_width;
gray ++;
};
};
}
/*
* 'dither_cmyk()' - Dither RGB pixels to cyan, magenta, yellow, and black.
*/
void
dither_cmyk(guchar *rgb, /* I - RGB pixels */
int row, /* I - Current Y coordinate */
int src_width, /* I - Width of input row */
int dst_width, /* I - Width of output rows */
unsigned char *cyan, /* O - Cyan bitmap pixels */
unsigned char *magenta, /* O - Magenta bitmap pixels */
unsigned char *yellow, /* O - Yellow bitmap pixels */
unsigned char *black) /* O - Black bitmap pixels */
{
int x, /* Current X coordinate */
xerror, /* X error count */
xstep, /* X step */
xmod, /* X error modulus */
length; /* Length of output bitmap in bytes */
int c, m, y, k, ik; /* CMYK values */
unsigned char bit, /* Current bit */
*cptr, /* Current cyan pixel */
*mptr, /* Current magenta pixel */
*yptr, /* Current yellow pixel */
*kptr; /* Current black pixel */
int cerror, /* Current cyan error */
*cerror0, /* Pointer to current error row */
*cerror1; /* Pointer to next error row */
int yerror, /* Current yellow error */
*yerror0, /* Pointer to current error row */
*yerror1; /* Pointer to next error row */
int merror, /* Current magenta error */
*merror0, /* Pointer to current error row */
*merror1; /* Pointer to next error row */
int kerror, /* Current black error */
*kerror0, /* Pointer to current error row */
*kerror1; /* Pointer to next error row */
xstep = 3 * (src_width / dst_width);
xmod = src_width % dst_width;
length = (dst_width + 7) / 8;
cerror0 = error[row & 1][0] + 2;
cerror1 = error[1 - (row & 1)][0] + 2;
cerror1[0] = 0;
cerror1[1] = 0;
merror0 = error[row & 1][1] + 2;
merror1 = error[1 - (row & 1)][1] + 2;
merror1[0] = 0;
merror1[1] = 0;
yerror0 = error[row & 1][2] + 2;
yerror1 = error[1 - (row & 1)][2] + 2;
yerror1[0] = 0;
yerror1[1] = 0;
kerror0 = error[row & 1][3] + 2;
kerror1 = error[1 - (row & 1)][3] + 2;
kerror1[0] = 0;
kerror1[1] = 0;
memset(cyan, 0, length);
memset(magenta, 0, length);
memset(yellow, 0, length);
if (black != NULL)
memset(black, 0, length);
for (x = 0, bit = 128, cptr = cyan, mptr = magenta, yptr = yellow, kptr=black,
xerror = 0;
x < dst_width;
x ++, cerror0 ++, cerror1 ++, merror0 ++, merror1 ++, yerror0 ++,
yerror1 ++, kerror0 ++, kerror1 ++)
{
c = 255 - rgb[0];
m = 255 - rgb[1];
y = 255 - rgb[2];
if (black != NULL)
{
k = MIN(c, MIN(m, y));
if (k >= 255)
c = m = y = 0;
else if (k > 0)
{
ik = 255 - k;
c = 255 * (c - k) / ik;
m = 255 * (m - k) / ik;
y = 255 * (y - k) / ik;
};
k += *kerror0;
if (k > 127)
{
*kptr |= bit;
k -= 255;
};
kerror0[1] += k / 4;
kerror0[2] += k / 8;
kerror1[-2] += k / 16;
kerror1[-1] += k / 8;
kerror1[0] += k / 4;
kerror1[1] += k / 8;
kerror1[2] = k / 16;
if (bit == 1)
kptr ++;
};
c += *cerror0;
if (c > 127)
{
*cptr |= bit;
c -= 255;
};
cerror0[1] += c / 4;
cerror0[2] += c / 8;
cerror1[-2] += c / 16;
cerror1[-1] += c / 8;
cerror1[0] += c / 4;
cerror1[1] += c / 8;
cerror1[2] = c / 16;
m += *merror0;
if (m > 127)
{
*mptr |= bit;
m -= 255;
};
merror0[1] += m / 4;
merror0[2] += m / 8;
merror1[-2] += m / 16;
merror1[-1] += m / 8;
merror1[0] += m / 4;
merror1[1] += m / 8;
merror1[2] = m / 16;
y += *yerror0;
if (y > 127)
{
*yptr |= bit;
y -= 255;
};
yerror0[1] += y / 4;
yerror0[2] += y / 8;
yerror1[-2] += y / 16;
yerror1[-1] += y / 8;
yerror1[0] += y / 4;
yerror1[1] += y / 8;
yerror1[2] = y / 16;
if (bit == 1)
{
cptr ++;
mptr ++;
yptr ++;
bit = 128;
}
else
bit >>= 1;
rgb += xstep;
xerror += xmod;
if (xerror >= dst_width)
{
xerror -= dst_width;
rgb += 3;
};
};
}
/*
* 'gray_to_gray()' - Convert grayscale image data to grayscale (brightness
* adjusted).
*/
void
gray_to_gray(guchar *grayin, /* I - RGB pixels */
guchar *grayout, /* O - RGB pixels */
int width, /* I - Width of row */
int bpp, /* I - Bytes-per-pixel in grayin */
guchar *lut, /* I - Brightness lookup table */
guchar *cmap) /* I - Colormap (unused) */
{
while (width > 0)
{
*grayout = lut[*grayin];
grayout ++;
grayin += bpp;
width --;
};
}
/*
* 'indexed_to_gray()' - Convert indexed image data to grayscale.
*/
void
indexed_to_gray(guchar *indexed, /* I - Indexed pixels */
guchar *gray, /* O - Grayscale pixels */
int width, /* I - Width of row */
int bpp, /* I - Bytes-per-pixel in indexed */
guchar *lut, /* I - Brightness lookup table */
guchar *cmap) /* I - Colormap */
{
int i; /* Looping var */
unsigned char gray_cmap[256]; /* Grayscale colormap */
for (i = 0; i < 256; i ++, cmap += 3)
gray_cmap[i] = lut[(cmap[0] * LUM_RED + cmap[1] * LUM_GREEN + cmap[2] * LUM_BLUE) / 100];
while (width > 0)
{
*gray = gray_cmap[*indexed];
gray ++;
indexed += bpp;
width --;
};
}
/*
* 'indexed_to_rgb()' - Convert indexed image data to RGB.
*/
void
indexed_to_rgb(guchar *indexed, /* I - Indexed pixels */
guchar *rgb, /* O - RGB pixels */
int width, /* I - Width of row */
int bpp, /* I - Bytes-per-pixel in indexed */
guchar *lut, /* I - Brightness lookup table */
guchar *cmap) /* I - Colormap */
{
while (width > 0)
{
rgb[0] = lut[cmap[*indexed * 3 + 0]];
rgb[1] = lut[cmap[*indexed * 3 + 1]];
rgb[2] = lut[cmap[*indexed * 3 + 2]];
rgb += 3;
indexed += bpp;
width --;
};
}
/*
* 'media_width()' - Get the addressable width of the page.
*
* This function assumes a standard left/right margin of 0.25".
*/
int
media_width(int media_size, /* I - Media size code */
int dpi) /* I - Resolution in dots-per-inch */
{
switch (media_size)
{
case MEDIA_LETTER :
case MEDIA_LEGAL :
return (8 * dpi);
case MEDIA_TABLOID :
return ((int)(10.5 * dpi + 0.5));
case MEDIA_A4 :
return ((int)(7.77 * dpi + 0.5));
case MEDIA_A3 :
return ((int)(11.09 * dpi + 0.5));
default :
return (0);
};
}
/*
* 'media_height()' - Get the addressable height of the page.
*
* This function assumes a standard top/bottom margin of 0.5".
*/
int
media_height(int media_size, /* I - Media size code */
int dpi) /* I - Resolution in dots-per-inch */
{
switch (media_size)
{
case MEDIA_LETTER :
return (10 * dpi);
case MEDIA_LEGAL :
return (13 * dpi);
case MEDIA_TABLOID :
return (16 * dpi);
case MEDIA_A4 :
return ((int)(10.69 * dpi + 0.5));
case MEDIA_A3 :
return ((int)(15.54 * dpi + 0.5));
default :
return (0);
};
}
/*
* 'rgb_to_gray()' - Convert RGB image data to grayscale.
*/
void
rgb_to_gray(guchar *rgb, /* I - RGB pixels */
guchar *gray, /* O - Grayscale pixels */
int width, /* I - Width of row */
int bpp, /* I - Bytes-per-pixel in RGB */
guchar *lut, /* I - Brightness lookup table */
guchar *cmap) /* I - Colormap (unused) */
{
while (width > 0)
{
*gray = lut[(rgb[0] * LUM_RED + rgb[1] * LUM_GREEN + rgb[2] * LUM_BLUE) / 100];
gray ++;
rgb += bpp;
width --;
};
}
/*
* 'rgb_to_rgb()' - Convert RGB image data to RGB (brightness adjusted).
*/
void
rgb_to_rgb(guchar *rgbin, /* I - RGB pixels */
guchar *rgbout, /* O - RGB pixels */
int width, /* I - Width of row */
int bpp, /* I - Bytes-per-pixel in RGB */
guchar *lut, /* I - Brightness lookup table */
guchar *cmap) /* I - Colormap (unused) */
{
while (width > 0)
{
rgbout[0] = lut[rgbin[0]];
rgbout[1] = lut[rgbin[1]];
rgbout[2] = lut[rgbin[2]];
rgbout += 3;
rgbin += bpp;
width --;
};
}
/*
* End of "$Id$".
*/

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,942 +0,0 @@
/****************************************************************************
* This is a plugin for the GIMP v 0.99.8 or later.
*
* Copyright (C) 1997 Miles O'Neal
* Blur code Copyright (C) 1995 Spencer Kimball and Peter Mattis
* GUI based on GTK code from:
* 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
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*
****************************************************************************/
/****************************************************************************
* Randomize:
*
* randomize version 0.4c (17 May 1997, MEO)
* history
* 0.5 - 20 May 1997 MEO
* added seed initialization choices (current time or user value)
* added randomization type to progress label
* added RNDM_VERSION macro so version changes made in one place
* speed optimizations:
* - changed randomize_prepare_row to #define
* - moved updates back outside main loop
* - less frequent progress updates
* minor intialization string and comment cleanup
* 0.4c - 17 May 1997 MEO
* minor comment cleanup
* 0.4b - 17 May 1997 MEO
* minor comment cleanup
* 0.4a - 16 May 1997 MEO
* added, corrected & cleaned up comments
* removed unused variables, code
* cleaned up wrong names
* added version to popups
* 0.4 - 13 May 1997 MEO
* added SLUR function
* 0.3 - 12 May 1997 MEO
* added HURL function
* moved from Blurs menu to Distorts menu.
* 0.2 - 11 May 1997 MEO
* converted percentage control from text to scale
* standardized tab stops, style
* 0.1 - 10 May 1997 MEO
* initial release, with BLUR and PICK
*
* Please send any patches or suggestions to the author: meo@rru.com .
*
* 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)
*
* 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
* 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,
* there is an 80% chance the pixel above be used; otherwise, one
* 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.
*
* This plug-in's effectiveness varies a lot with the type
* and clarity of the image being "randomized".
*
* Hurling more than 75% or so onto an existing image will
* make the image nearly unrecognizable. By 90% hurl, most
* images are indistinguishable from random noise.
*
* The repeat count is especially useful with slurring.
*
* TODO List
*
* - Add a real melt function.
****************************************************************************/
#include <stdlib.h>
#include <time.h>
#include "libgimp/gimp.h"
#include "gtk/gtk.h"
/*
* Set this to 0 for faster processing, to 1 if for some
* reason you want all functions to be subroutines
*/
#define SUBS_NOT_DEFINES 0
/*
* progress meter update frequency
*/
#define PROG_UPDATE_TIME ((row % 10) == 0)
#define RNDM_VERSION "Randomize 0.5"
/*********************************
*
* LOCAL DATA
*
********************************/
#define RNDM_BLUR 1
#define RNDM_PICK 2
#define RNDM_HURL 3
#define RNDM_SLUR 4
#define SEED_TIME 10
#define SEED_USER 11
#define ENTRY_WIDTH 75
#define SCALE_WIDTH 100
typedef struct {
gint rndm_type; /* type of randomization to apply */
gdouble rndm_pct; /* likelihood of randomization (as %age) */
gint seed_type; /* seed init. type - current time or user value */
gint rndm_seed; /* seed value for rand() function */
gdouble rndm_rcount; /* repeat count */
} RandomizeVals;
static RandomizeVals pivals = {
RNDM_BLUR,
50.0,
SEED_TIME,
0,
1.0,
};
typedef struct {
gint run;
} RandomizeInterface;
static RandomizeInterface rndm_int = {
FALSE /* have we run? */
};
static gint is_indexed_drawable = FALSE;
/*********************************
*
* LOCAL FUNCTIONS
*
********************************/
static void query(void);
static void run(
char *name,
int nparams,
GParam *param,
int *nreturn_vals,
GParam **return_vals
);
GPlugInInfo PLUG_IN_INFO = {
NULL, /* init_proc */
NULL, /* quit_proc */
query, /* query_proc */
run, /* run_proc */
};
static void randomize(GDrawable *drawable);
#if (SUBS_NOT_DEFINES == 1)
static void randomize_prepare_row(
GPixelRgn *pixel_rgn,
guchar *data,
int x,
int y,
int w
);
#endif
static gint randomize_dialog();
static void randomize_close_callback(
GtkWidget *widget,
gpointer data
);
static void randomize_ok_callback(
GtkWidget *widget,
gpointer data
);
static void randomize_cancel_callback(
GtkWidget *widget,
gpointer data
);
static void randomize_scale_update(
GtkAdjustment *adjustment,
double *scale_val
);
static void randomize_toggle_update(
GtkWidget *widget,
gpointer data
);
static void randomize_text_update(
GtkWidget *widget,
gpointer data
);
MAIN()
/*********************************
*
* query() - query_proc
*
* called by the GIMP to learn about this plug-in
*
********************************/
static void
query()
{
static GParamDef args[] = {
{ PARAM_INT32, "run_mode", "Interactive, non-interactive" },
{ PARAM_IMAGE, "image", "Input image (unused)" },
{ PARAM_DRAWABLE, "drawable", "Input drawable" },
{ PARAM_INT32, "rndm_type", "Randomization type" },
{ PARAM_FLOAT, "rndm_pct", "Randomization percentage" },
{ PARAM_FLOAT, "rndm_rcount", "Repeat count" },
};
static GParamDef *return_vals = NULL;
static int nargs = sizeof(args) / sizeof (args[0]);
static int nreturn_vals = 0;
gimp_install_procedure("plug_in_randomize",
"Add a random factor to the image, by blurring, picking a nearby pixel, slurring (similar to melting), or just hurling on it.",
"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.",
"Miles O'Neal",
"Miles O'Neal, Spencer Kimball, Peter Mattis, Torsten Martinsen, Brian Degenhardt, Federico Mena Quintero",
"1995-1997",
"<Image>/Filters/Distorts/Randomize",
"RGB*, GRAY*, INDEXED*",
PROC_PLUG_IN,
nargs, nreturn_vals,
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!
*/
#define FIX_INDEX_BLUR() \
if (gimp_drawable_indexed(drawable->id)) { \
is_indexed_drawable = TRUE; \
if (pivals.rndm_type == RNDM_BLUR) { \
pivals.rndm_type = RNDM_PICK; \
} \
}
/*********************************
*
* 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,
GParam **return_vals)
{
static GParam values[1];
GDrawable *drawable;
GRunModeType run_mode;
GStatusType status = STATUS_SUCCESS; /* assume the best! */
char *rndm_type_str = '\0';
char prog_label[32];
/*
* Get the specified drawable, do standard initialization.
*/
run_mode = param[0].data.d_int32;
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_indexed(drawable->id)) {
switch (run_mode) {
/*
* If we're running interactively, pop up the dialog box.
*/
case RUN_INTERACTIVE:
FIX_INDEX_BLUR();
gimp_get_data("plug_in_randomize", &pivals);
if (!randomize_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 they all
* parameters have legitimate values.
*/
case RUN_NONINTERACTIVE:
FIX_INDEX_BLUR();
if (nparams != 6) {
status = STATUS_CALLING_ERROR;
}
if (status == STATUS_SUCCESS) {
pivals.rndm_type = (gint) param[3].data.d_int32;
pivals.rndm_pct = (gdouble) param[4].data.d_float;
pivals.rndm_rcount = (gdouble) param[5].data.d_int32;
}
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) ||
(pivals.rndm_rcount < 1.0 || pivals.rndm_rcount > 100.0))) {
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_randomize", &pivals);
break;
/*
* Hopefully we never get here!
*/
default:
break;
}
/*
* 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;
}
sprintf(prog_label, "%s (%s)", RNDM_VERSION, rndm_type_str);
gimp_progress_init(prog_label);
gimp_tile_cache_ntiles(2 * (drawable->width / gimp_tile_width() + 1));
/*
* Initialie the rand() function seed
*/
if (pivals.seed_type == SEED_TIME)
srand(time(NULL));
else
srand(pivals.rndm_seed);
randomize(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_randomize", &pivals, sizeof(RandomizeVals));
}
} 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);
}
/*********************************
*
* randomize_prepare_row()
*
* Get a row of pixels. If the requested row
* is off the edge, clone the edge row.
*
********************************/
#if (SUBS_NOT_DEFINES == 1)
static void
randomize_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++) {
data[-pixel_rgn->bpp + b] = data[b];
data[w * pixel_rgn->bpp + b] = data[(w - 1) * pixel_rgn->bpp + b];
}
}
#else
#define randomize_prepare_row(pixel_rgn, data, x, y, 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++) { \
data[-(pixel_rgn)->bpp + b] = data[b]; \
data[w * (pixel_rgn)->bpp + b] = data[(w - 1) * (pixel_rgn)->bpp + b]; \
} \
}
#endif
/*********************************
*
* randomize()
*
* Actually mess with the image.
*
********************************/
static void
randomize(GDrawable *drawable)
{
GPixelRgn srcPR, destPR;
gint width, height;
gint bytes;
guchar *dest, *d;
guchar *prev_row, *pr;
guchar *cur_row, *cr;
guchar *next_row, *nr;
guchar *tmp;
gint row, col;
gint x1, y1, x2, y2;
gint cnt;
/*
* 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.
*/
width = drawable->width;
height = drawable->height;
bytes = drawable->bpp;
/*
* 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);
for (cnt = 1; cnt <= pivals.rndm_rcount; cnt++) {
/*
* 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);
pr = prev_row + bytes;
cr = cur_row + bytes;
nr = next_row + bytes;
/*
* prepare the first row and previous row
*/
randomize_prepare_row(&srcPR, pr, x1, y1 - 1, (x2 - x1));
randomize_prepare_row(&srcPR, cr, x1, y1, (x2 - x1));
/*
* loop through the rows, applying the selected convolution
*/
for (row = y1; row < y2; row++) {
/* prepare the next row */
randomize_prepare_row(&srcPR, nr, x1, row + 1, (x2 - x1));
d = dest;
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.
*/
case RNDM_HURL:
*d++ = rand() % 256;
break;
/*
* PICK
* pick at random from a neighboring pixel.
*/
case RNDM_PICK:
switch (rand() % 9) {
case 0:
*d++ = (gint) pr[col - bytes];
break;
case 1:
*d++ = (gint) pr[col];
break;
case 2:
*d++ = (gint) pr[col + bytes];
break;
case 3:
*d++ = (gint) cr[col - bytes];
break;
case 4:
*d++ = (gint) cr[col];
break;
case 5:
*d++ = (gint) cr[col + bytes];
break;
case 6:
*d++ = (gint) nr[col - bytes];
break;
case 7:
*d++ = (gint) nr[col];
break;
case 8:
*d++ = (gint) nr[col + bytes];
break;
}
break;
/*
* SLUR
* 80% chance it's from directly above,
* 10% from above left,
* 10% from above right.
*/
case RNDM_SLUR:
switch (rand() % 10) {
case 0:
*d++ = (gint) pr[col - bytes];
break;
case 9:
*d++ = (gint) pr[col + bytes];
break;
default:
*d++ = (gint) pr[col];
break;
}
break;
}
/*
* Otherwise, this pixel was not selected for randomization,
* so use the current value.
*/
} else {
*d++ = (gint) cr[col];
}
}
/*
* Save the modified row, shuffle the row pointers, and every
* so often, update the progress meter.
*/
gimp_pixel_rgn_set_row(&destPR, dest, x1, row, (x2 - x1));
tmp = pr;
pr = cr;
cr = nr;
nr = tmp;
if (PROG_UPDATE_TIME)
gimp_progress_update((double) row / (double) (y2 - y1));
}
}
gimp_progress_update((double) 100);
/*
* update the randomized 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
*
********************************/
#define randomize_add_action_button(label, callback, dialog) \
{ \
GtkWidget *button; \
\
button = gtk_button_new_with_label(label); \
GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT); \
gtk_signal_connect(GTK_OBJECT(button), "clicked", callback, dialog); \
gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->action_area), \
button, TRUE, TRUE, 0); \
gtk_widget_grab_default(button); \
gtk_widget_show(button); \
}
#define randomize_add_radio_button(group, label, box, callback, value) \
{ \
GtkWidget *toggle; \
\
toggle = gtk_radio_button_new_with_label(group, label); \
group = gtk_radio_button_group(GTK_RADIO_BUTTON(toggle)); \
gtk_box_pack_start(GTK_BOX(box), toggle, FALSE, FALSE, 0); \
gtk_signal_connect(GTK_OBJECT(toggle), "toggled", \
(GtkSignalFunc) callback, value); \
gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(toggle), *value); \
gtk_widget_show(toggle); \
gtk_widget_show(box); \
}
/*********************************
*
* randomize_dialog() - set up the plug-in's dialog box
*
********************************/
static gint
randomize_dialog()
{
GtkWidget *dlg, *entry, *frame, *label, *scale,
*seed_hbox, *seed_vbox, *table, *toggle_hbox;
GtkObject *scale_data;
GSList *type_group = NULL;
GSList *seed_group = NULL;
gchar **argv;
gint argc;
gchar buffer[10];
/*
* 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);
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("randomize");
gtk_init(&argc, &argv);
/*
* Open a new dialog, label it and set up its
* destroy callback.
*/
dlg = gtk_dialog_new();
gtk_window_set_title(GTK_WINDOW(dlg), RNDM_VERSION);
gtk_window_position(GTK_WINDOW(dlg), GTK_WIN_POS_MOUSE);
gtk_signal_connect(GTK_OBJECT(dlg), "destroy",
(GtkSignalFunc) randomize_close_callback, NULL);
/*
* Action area OK & Cancel buttons
*/
randomize_add_action_button("OK",
(GtkSignalFunc) randomize_ok_callback, dlg);
randomize_add_action_button("Cancel",
(GtkSignalFunc) randomize_cancel_callback, dlg);
/*
* 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);
/*
* Randomization Type - label & radio buttons
*/
label = gtk_label_new("Randomization Type:");
gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
gtk_table_attach(GTK_TABLE(table), label, 0, 1, 0, 1,
GTK_FILL | GTK_EXPAND, GTK_FILL, 5, 0);
gtk_widget_show(label);
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);
/*
* Blur button (won't work with indexed - if the drawable is indexed,
* don't allow blur as an option)
*/
if (! is_indexed_drawable) {
randomize_add_radio_button(type_group, "Blur", toggle_hbox,
(GtkSignalFunc) randomize_toggle_update, &do_blur);
}
/*
* Hurl, Pick and Slur buttons
*/
randomize_add_radio_button(type_group, "Hurl", toggle_hbox,
(GtkSignalFunc) randomize_toggle_update, &do_hurl);
randomize_add_radio_button(type_group, "Pick", toggle_hbox,
(GtkSignalFunc) randomize_toggle_update, &do_pick);
randomize_add_radio_button(type_group, "Slur", toggle_hbox,
(GtkSignalFunc) randomize_toggle_update, &do_slur);
/*
* Randomization seed initialization controls
*/
label = gtk_label_new("Seed");
gtk_misc_set_alignment(GTK_MISC (label), 0.0, 0.5);
gtk_table_attach(GTK_TABLE(table), label, 0, 1, 1, 2, GTK_FILL, 0, 5, 0);
gtk_widget_show(label);
/*
* 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
*/
randomize_add_radio_button(seed_group, "Current Time", seed_vbox,
(GtkSignalFunc) randomize_toggle_update, &do_time);
/*
* 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
*/
randomize_add_radio_button(seed_group, "User", seed_hbox,
(GtkSignalFunc) randomize_toggle_update, &do_user);
/*
* Randomization seed 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.rndm_seed);
gtk_entry_set_text(GTK_ENTRY(entry), buffer);
gtk_signal_connect(GTK_OBJECT(entry), "changed",
(GtkSignalFunc) randomize_text_update, &pivals.rndm_seed);
gtk_widget_show(entry);
gtk_widget_show(seed_hbox);
/*
* Randomization percentage label & scale (1 to 100)
*/
label = gtk_label_new("Randomization %:");
gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
gtk_table_attach(GTK_TABLE(table), label, 0, 1, 2, 3,
GTK_FILL | GTK_EXPAND, GTK_FILL, 5, 0);
scale_data = gtk_adjustment_new(pivals.rndm_pct,
1.0, 100.0, 1.0, 1.0, 0.0);
scale = gtk_hscale_new(GTK_ADJUSTMENT(scale_data));
gtk_widget_set_usize(scale, SCALE_WIDTH, 0);
gtk_table_attach(GTK_TABLE(table), scale, 1, 2, 2, 3,
GTK_FILL | GTK_EXPAND, GTK_FILL, 0, 0);
gtk_scale_set_value_pos(GTK_SCALE(scale), GTK_POS_TOP);
gtk_scale_set_digits(GTK_SCALE(scale), 0);
gtk_range_set_update_policy(GTK_RANGE(scale), GTK_UPDATE_DELAYED);
gtk_signal_connect(GTK_OBJECT(scale_data), "value_changed",
(GtkSignalFunc) randomize_scale_update, &pivals.rndm_pct);
gtk_widget_show(label);
gtk_widget_show(scale);
/*
* Repeat count label & scale (1 to 100)
*/
label = gtk_label_new("Repeat");
gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
gtk_table_attach(GTK_TABLE(table), label, 0, 1, 3, 4,
GTK_FILL, 0, 5, 0);
scale_data = gtk_adjustment_new(pivals.rndm_rcount,
1.0, 100.0, 1.0, 1.0, 0.0);
scale = gtk_hscale_new(GTK_ADJUSTMENT(scale_data));
gtk_widget_set_usize(scale, SCALE_WIDTH, 0);
gtk_table_attach(GTK_TABLE(table), scale, 1, 2, 3, 4,
GTK_FILL | GTK_EXPAND, GTK_FILL, 0, 0);
gtk_scale_set_value_pos(GTK_SCALE(scale), GTK_POS_TOP);
gtk_scale_set_digits(GTK_SCALE(scale), 0);
gtk_range_set_update_policy(GTK_RANGE(scale), GTK_UPDATE_DELAYED);
gtk_signal_connect(GTK_OBJECT(scale_data), "value_changed",
(GtkSignalFunc) randomize_scale_update, &pivals.rndm_rcount);
gtk_widget_show(label);
gtk_widget_show(scale);
/*
* Display everything.
*/
gtk_widget_show(frame);
gtk_widget_show(table);
gtk_widget_show(dlg);
gtk_main();
gdk_flush();
/*
* Figure out which type of randomization to apply.
*/
if (do_blur) {
pivals.rndm_type = RNDM_BLUR;
} else if (do_pick) {
pivals.rndm_type = RNDM_PICK;
} else if (do_slur) {
pivals.rndm_type = RNDM_SLUR;
} else {
pivals.rndm_type = RNDM_HURL;
}
/*
* Figure out which type of seed initialization to apply.
*/
if (do_time) {
pivals.seed_type = SEED_TIME;
} else {
pivals.seed_type = SEED_USER;
}
return rndm_int.run;
}
/*********************************
*
* GUI accessories (callbacks, etc)
*
********************************/
static void
randomize_close_callback(GtkWidget *widget, gpointer data) {
gtk_main_quit();
}
static void
randomize_ok_callback(GtkWidget *widget, gpointer data) {
rndm_int.run = TRUE;
gtk_widget_destroy(GTK_WIDGET(data));
}
static void
randomize_cancel_callback(GtkWidget *widget, gpointer data) {
gtk_widget_destroy(GTK_WIDGET(data));
}
static void
randomize_scale_update(GtkAdjustment *adjustment, double *scale_val) {
*scale_val = adjustment->value;
}
static void
randomize_toggle_update(GtkWidget *widget, gpointer data) {
int *toggle_val;
toggle_val = (int *) data;
if (GTK_TOGGLE_BUTTON(widget)->active)
*toggle_val = TRUE;
else
*toggle_val = FALSE;
}
static void
randomize_text_update(GtkWidget *widget, gpointer data) {
gint *text_val;
text_val = (gint *) data;
*text_val = atoi(gtk_entry_get_text(GTK_ENTRY(widget)));
}

File diff suppressed because it is too large Load Diff

View File

@ -1,798 +0,0 @@
/*
* Rotate plug-in v0.4 by Sven Neumann, neumanns@uni-duesseldorf.de
* 1997/10/17
*
* Any suggestions, bug-reports or patches are very welcome.
*
* A lot of changes in version 0.3 were inspired by (or even simply
* copied from) the similar rotators-plug-in by Adam D. Moss.
*
* As I still prefer my version I have not stopped developing it.
* Probably this will result in one plug-in that includes the advantages
* of both approaches.
*/
/* The GIMP -- an image manipulation program
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* 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
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/* Revision history
* (09/28/97) v0.1 first development release
* (09/29/97) v0.2 nicer dialog,
* changed the menu-location to Filters/Transforms
* (10/01/97) v0.3 now handles layered images and undo
* (10/13/97) v0.3a small bugfix, no real changes
* (10/17/97) v0.4 now handles selections
*/
/* TODO List
* - handle channels and masks
* - rewrite the main function to make it work on tiles rather than
* process the image row by row. This should result in a significant
* speedup (thanks to quartic for this suggestion).
*/
#include <gtk/gtk.h>
#include <libgimp/gimp.h>
#include <libgimp/gimpui.h>
/* Defines */
#define PLUG_IN_NAME "plug_in_rotate"
#define PLUG_IN_PRINT_NAME "Rotate"
#define PLUG_IN_VERSION "v0.4 (10/17/97)"
#define PLUG_IN_MENU_PATH "<Image>/Filters/Transforms/Rotate"
#define PLUG_IN_IMAGE_TYPES "RGB*, INDEXED*, GRAY*"
#define PLUG_IN_AUTHOR "Sven Neumann (neumanns@uni-duesseldorf.de)"
#define PLUG_IN_COPYRIGHT "Sven Neumann"
#define PLUG_IN_DESCRIBTION "Rotates a layer or the whole image by 90, 180 or 270 degrees"
#define PLUG_IN_HELP "This plug-in does rotate the active layer or the whole image clockwise by multiples of 90 degrees. When the whole image is choosen, the image is resized if necessary."
#define NUMBER_IN_ARGS 5
#define IN_ARGS { PARAM_INT32, "run_mode", "Interactive, non-interactive"},\
{ PARAM_IMAGE, "image", "Input image" },\
{ PARAM_DRAWABLE, "drawable", "Input drawable"},\
{ PARAM_INT32, "angle", "Angle { 90° (1), 180° (2), 270° (3) }"},\
{ PARAM_INT32, "everything", "Rotate the whole image? { TRUE, FALSE }"}
#define NUMBER_OUT_ARGS 0
#define OUT_ARGS NULL
#define NUM_ANGLES 4
char *angle_label[NUM_ANGLES] = { "", "90°", "180°", "270°" };
typedef struct {
gint angle;
gint everything;
} RotateValues;
typedef struct {
gint run;
} RotateInterface;
static RotateValues rotvals =
{
1, /* default to 90° */
1 /* default to whole image */
};
static RotateInterface rotint =
{
FALSE /* run */
};
static void query (void);
static void run (char *name,
int nparams, /* number of parameters passed in */
GParam * param, /* parameters passed in */
int *nreturn_vals, /* number of parameters returned */
GParam ** return_vals); /* parameters to be returned */
static void rotate (void);
static void rotate_drawable (GDrawable *drawable);
static void rotate_compute_offsets (gint *offsetx,
gint *offsety,
gint image_width, gint image_height,
gint width, gint height);
static gint rotate_dialog (void);
static void rotate_close_callback (GtkWidget *widget,
gpointer data);
static void rotate_ok_callback (GtkWidget *widget,
gpointer data);
static void rotate_toggle_update (GtkWidget *widget,
gpointer data);
static void ErrorMessage (guchar *message);
gint32 my_gimp_selection_float (gint32 image_ID, gint32 drawable_ID);
gint32 my_gimp_selection_is_empty (gint32 image_ID);
/* Global Variables */
GPlugInInfo PLUG_IN_INFO =
{
NULL, /* init_proc */
NULL, /* quit_proc */
query, /* query_proc */
run /* run_proc */
};
/* the image and drawable that will be used later */
GDrawable *active_drawable = NULL;
gint32 image_ID = -1;
/* Functions */
MAIN ();
static void query (void)
{
static GParamDef args[] = { IN_ARGS };
static int nargs = NUMBER_IN_ARGS;
static GParamDef *return_vals = OUT_ARGS;
static int nreturn_vals = NUMBER_OUT_ARGS;
/* the actual installation of the plugin */
gimp_install_procedure (PLUG_IN_NAME,
PLUG_IN_DESCRIBTION,
PLUG_IN_HELP,
PLUG_IN_AUTHOR,
PLUG_IN_COPYRIGHT,
PLUG_IN_VERSION,
PLUG_IN_MENU_PATH,
PLUG_IN_IMAGE_TYPES,
PROC_PLUG_IN,
nargs,
nreturn_vals,
args,
return_vals);
}
static void
run (char *name, /* name of plugin */
int nparams, /* number of in-paramters */
GParam * param, /* in-parameters */
int *nreturn_vals, /* number of out-parameters */
GParam ** return_vals) /* out-parameters */
{
gint longside;
/* Get the runmode from the in-parameters */
GRunModeType run_mode = param[0].data.d_int32;
/* status variable, use it to check for errors in invocation usualy only
during non-interactive calling */
GStatusType status = STATUS_SUCCESS;
/*always return at least the status to the caller. */
static GParam values[1];
/* initialize the return of the status */
values[0].type = PARAM_STATUS;
values[0].data.d_status = status;
*nreturn_vals = 1;
*return_vals = values;
/* get image and drawable */
image_ID = param[1].data.d_int32;
active_drawable = gimp_drawable_get (param[2].data.d_drawable);
/*how are we running today? */
switch (run_mode)
{
case RUN_INTERACTIVE:
/* Possibly retrieve data from a previous run */
gimp_get_data (PLUG_IN_NAME, &rotvals);
rotvals.angle = rotvals.angle % NUM_ANGLES;
/* Get information from the dialog */
if (!rotate_dialog())
return;
break;
case RUN_NONINTERACTIVE:
/* check to see if invoked with the correct number of parameters */
if (nparams == NUMBER_IN_ARGS)
{
rotvals.angle = (gint) param[3].data.d_int32;
rotvals.angle = rotvals.angle % NUM_ANGLES;
rotvals.everything = (gint) param[4].data.d_int32;
}
else
status = STATUS_CALLING_ERROR;
break;
case RUN_WITH_LAST_VALS:
/* Possibly retrieve data from a previous run */
gimp_get_data (PLUG_IN_NAME, &rotvals);
rotvals.angle = rotvals.angle % NUM_ANGLES;
break;
default:
break;
}
if (status == STATUS_SUCCESS)
{
/* Set the number of tiles you want to cache */
/* gimp_tile_cache_ntiles ( ); */
/* Run the main function */
rotate();
/* If run mode is interactive, flush displays, else (script) don't
do it, as the screen updates would make the scripts slow */
if (run_mode != RUN_NONINTERACTIVE)
gimp_displays_flush ();
/* Store variable states for next run */
if (run_mode == RUN_INTERACTIVE)
gimp_set_data (PLUG_IN_NAME, &rotvals, sizeof (RotateValues));
}
values[0].data.d_status = status;
}
/* Some helper functions */
gint32
my_gimp_selection_is_empty (gint32 image_ID)
{
GParam *return_vals;
int nreturn_vals;
gint32 is_empty;
return_vals = gimp_run_procedure ("gimp_selection_is_empty",
&nreturn_vals,
PARAM_IMAGE, image_ID,
PARAM_END);
if (return_vals[0].data.d_status == STATUS_SUCCESS)
is_empty = return_vals[1].data.d_int32;
gimp_destroy_params (return_vals, nreturn_vals);
return is_empty;
}
gint32
my_gimp_selection_float (gint32 image_ID, gint32 drawable_ID)
{
GParam *return_vals;
int nreturn_vals;
gint32 layer_ID;
return_vals = gimp_run_procedure ("gimp_selection_float",
&nreturn_vals,
PARAM_IMAGE, image_ID,
PARAM_DRAWABLE, drawable_ID,
PARAM_INT32, 0,
PARAM_INT32, 0,
PARAM_END);
layer_ID= 0;
if (return_vals[0].data.d_status == STATUS_SUCCESS)
layer_ID = return_vals[1].data.d_layer;
gimp_destroy_params (return_vals, nreturn_vals);
return layer_ID;
}
static void
rotate_compute_offsets (gint* offsetx,
gint* offsety,
gint image_width, gint image_height,
gint width, gint height)
{
gint buffer;
if (rotvals.everything) /* rotate around the image center */
{
switch ( rotvals.angle )
{
case 1: /* 90° */
buffer = *offsetx;
*offsetx = image_height - *offsety - height;
*offsety = buffer;
break;
case 2: /* 180° */
*offsetx = image_width - *offsetx - width;
*offsety = image_height - *offsety - height;
break;
case 3: /* 270° */
buffer = *offsetx;
*offsetx = *offsety;
*offsety = image_width - buffer - width;
}
}
else /* rotate around the drawable center */
{
if (rotvals.angle != 2)
{
*offsetx = *offsetx + (width-height)/2 ;
*offsety = *offsety + (height-width)/2 ;
}
}
return;
}
static void
rotate_drawable (GDrawable *drawable)
{
GPixelRgn srcPR, destPR;
gint width, height, longside, bytes;
gint row, col, byte;
gint offsetx, offsety;
gint was_preserve_transparency = FALSE;
guchar *buffer, *src_row, *dest_row;
/* Get the size of the input drawable. */
width = drawable->width;
height = drawable->height;
bytes = drawable->bpp;
if (gimp_layer_get_preserve_transparency(drawable->id))
{
was_preserve_transparency = TRUE;
gimp_layer_set_preserve_transparency ( drawable->id,FALSE );
}
if (rotvals.angle == 2) /* we're rotating by 180° */
{
if ( !gimp_drawable_layer(drawable->id) ) exit;
/* not a layer, probably a channel, abort operation */
gimp_tile_cache_ntiles ( 2*((width/gimp_tile_width())+1) );
gimp_pixel_rgn_init (&srcPR, drawable, 0, 0, width, height,
FALSE, FALSE);
gimp_pixel_rgn_init (&destPR, drawable, 0, 0, width, height,
TRUE, TRUE);
src_row = (guchar *) g_malloc (width * bytes);
dest_row = (guchar *) g_malloc (width * bytes);
for (row = 0; row < height; row++)
{
gimp_pixel_rgn_get_row (&srcPR, src_row, 0, row, width);
for (col = 0; col < width; col++)
{
for (byte = 0; byte < bytes; byte++)
{
dest_row[col * bytes + byte] =
src_row[(width - col - 1) * bytes + byte];
}
}
gimp_pixel_rgn_set_row (&destPR, dest_row, 0, (height - row - 1),
width);
if ((row % 5) == 0)
gimp_progress_update ((double) row / (double) height);
}
g_free (src_row);
g_free (dest_row);
gimp_drawable_flush (drawable);
gimp_drawable_merge_shadow (drawable->id, TRUE);
gimp_drawable_update (drawable->id, 0, 0, width, height);
}
else /* we're rotating by 90° or 270° */
{
(width > height) ? (longside = width) : (longside = height);
if ( gimp_drawable_layer(drawable->id) )
{
gimp_layer_resize(drawable->id, longside, longside, 0, 0);
gimp_drawable_flush (drawable);
drawable = gimp_drawable_get(drawable->id);
}
else
/* not a layer... probably a channel... abort operation */
exit;
gimp_tile_cache_ntiles ( ((longside/gimp_tile_width())+1) +
((longside/gimp_tile_height())+1) );
gimp_pixel_rgn_init (&srcPR, drawable, 0, 0, longside, longside,
FALSE, FALSE);
gimp_pixel_rgn_init (&destPR, drawable, 0, 0, longside, longside,
TRUE, TRUE);
buffer = g_malloc (longside * bytes);
if (rotvals.angle == 1) /* we're rotating by 90° */
{
for (row = 0; row < height; row++)
{
gimp_pixel_rgn_get_row (&srcPR, buffer, 0, row, width);
gimp_pixel_rgn_set_col (&destPR, buffer, (height - row - 1), 0,
width);
if ((row % 5) == 0)
gimp_progress_update ((double) row / (double) height);
}
}
else /* we're rotating by 270° */
{
for (col = 0; col < width; col++)
{
gimp_pixel_rgn_get_col (&srcPR, buffer, col, 0, height);
gimp_pixel_rgn_set_row (&destPR, buffer, 0, (width - col - 1),
height);
if ((row % 5) == 0)
gimp_progress_update ((double) row / (double) height);
}
}
g_free (buffer);
gimp_progress_update ( 1.0 );
gimp_drawable_flush (drawable);
gimp_drawable_merge_shadow (drawable->id, TRUE);
gimp_drawable_update (drawable->id, 0, 0, height, width);
gimp_layer_resize(drawable->id, height, width, 0, 0);
drawable = gimp_drawable_get(drawable->id);
gimp_drawable_flush (drawable);
gimp_drawable_update (drawable->id, 0, 0, height, width);
}
gimp_drawable_offsets (drawable->id, &offsetx, &offsety);
rotate_compute_offsets (&offsetx, &offsety,
gimp_image_width(image_ID),
gimp_image_height(image_ID),
width, height);
gimp_layer_set_offsets (drawable->id, offsetx, offsety);
if (was_preserve_transparency)
gimp_layer_set_preserve_transparency ( drawable->id, TRUE );
return;
}
/* The main rotate function */
static void
rotate (void)
{
gint nreturn_vals;
GDrawable *drawable;
gint32 *layers;
gint i, nlayers;
gint32 noselection;
if (rotvals.angle == 0) return;
/* if there's a selection and we try to rotate the whole image */
/* create an error message and exit */
if ( rotvals.everything )
{
if ( !my_gimp_selection_is_empty (image_ID) )
{
ErrorMessage("You can not rotate the whole image if there's a selection.");
gimp_drawable_detach (active_drawable);
return;
}
if ( gimp_layer_is_floating_selection (active_drawable->id) )
{
ErrorMessage("You can not rotate the whole image if there's a floating selection.");
gimp_drawable_detach (active_drawable);
return;
}
}
gimp_progress_init ("Rotating...");
gimp_run_procedure ("gimp_undo_push_group_start", &nreturn_vals,
PARAM_IMAGE, image_ID, PARAM_END);
if (rotvals.everything) /* rotate the whole image */
{
gimp_drawable_detach (active_drawable);
layers = gimp_image_get_layers (image_ID, &nlayers);
for ( i=0; i<nlayers; i++ )
{
drawable = gimp_drawable_get (layers[i]);
rotate_drawable (drawable);
gimp_drawable_detach (drawable);
}
g_free(layers);
if (rotvals.angle != 2)
{
gimp_image_resize (image_ID,
gimp_image_height(image_ID),
gimp_image_width(image_ID),
0, 0);
}
}
else /* rotate only the active layer */
{
/* check for active selection and float it */
if ( !my_gimp_selection_is_empty (image_ID) &&
!gimp_layer_is_floating_selection (active_drawable->id) )
active_drawable =
gimp_drawable_get (my_gimp_selection_float (image_ID,
active_drawable->id) );
rotate_drawable (active_drawable);
gimp_drawable_detach (active_drawable);
}
gimp_run_procedure ("gimp_undo_push_group_end", &nreturn_vals,
PARAM_IMAGE, image_ID, PARAM_END);
return;
}
/* Rotate dialog */
static gint
rotate_dialog (void)
{
GtkWidget *dialog;
GtkWidget *button;
GtkWidget *frame;
GtkWidget *table;
GtkWidget *radio_label;
GtkWidget *hbox;
GtkWidget *radio_button;
GtkWidget *check_button;
GSList *radio_group = NULL;
gint radio_pressed[NUM_ANGLES];
gint everything;
gint argc = 1;
gint i;
gchar **argv = g_new (gchar *, 1);
argv[0] = g_strdup ("Rotate");
for (i=0;i<NUM_ANGLES;i++)
{
radio_pressed[i] = (rotvals.angle == i);
}
everything = rotvals.everything;
/* Init GTK */
gtk_init (&argc, &argv);
gtk_rc_parse (gimp_gtkrc ());
gdk_set_use_xshm (gimp_use_xshm ());
gtk_widget_set_default_visual (gtk_preview_get_visual ());
/* Main Dialog */
dialog = gtk_dialog_new ();
gtk_window_set_title (GTK_WINDOW (dialog), PLUG_IN_PRINT_NAME);
gtk_window_position (GTK_WINDOW (dialog), GTK_WIN_POS_MOUSE);
gtk_signal_connect (GTK_OBJECT (dialog), "destroy",
(GtkSignalFunc) rotate_close_callback,
NULL);
/* Action area */
button = gtk_button_new_with_label ("OK");
GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
gtk_signal_connect (GTK_OBJECT (button), "clicked",
(GtkSignalFunc) rotate_ok_callback,
dialog);
gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->action_area),
button, TRUE, TRUE, 0);
gtk_widget_grab_default (button);
gtk_widget_show (button);
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 (dialog));
gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->action_area),
button, TRUE, TRUE, 0);
gtk_widget_show (button);
/* parameter settings */
frame = gtk_frame_new ("Rotate clockwise by");
gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_IN);
gtk_container_border_width (GTK_CONTAINER (frame), 6);
gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox),
frame, TRUE, TRUE, 0);
/* table for radio_buttons */
table = gtk_table_new (5, 5, FALSE);
gtk_table_set_row_spacings (GTK_TABLE (table), 8);
gtk_table_set_col_spacings (GTK_TABLE (table), 1);
gtk_container_border_width (GTK_CONTAINER (table), 6);
gtk_container_add (GTK_CONTAINER (frame), table);
/* radio buttons */
/* 0° */
radio_label = gtk_label_new ( angle_label[0] );
gtk_table_attach ( GTK_TABLE (table), radio_label, 2, 3, 0, 1, 0, 0, 0, 0);
gtk_widget_show (radio_label);
radio_button = gtk_radio_button_new ( radio_group );
radio_group = gtk_radio_button_group ( GTK_RADIO_BUTTON (radio_button) );
gtk_table_attach ( GTK_TABLE (table), radio_button, 2, 3, 1, 2, 0, 0, 0, 0);
gtk_signal_connect ( GTK_OBJECT (radio_button), "toggled",
(GtkSignalFunc) rotate_toggle_update,
&radio_pressed[0]);
gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (radio_button),
radio_pressed[0]);
gtk_widget_show (radio_button);
/* 90° */
radio_label = gtk_label_new ( angle_label[1] );
gtk_table_attach ( GTK_TABLE (table), radio_label, 4, 5, 2, 3, 0, 0, 0, 0);
gtk_widget_show (radio_label);
radio_button = gtk_radio_button_new ( radio_group );
radio_group = gtk_radio_button_group ( GTK_RADIO_BUTTON (radio_button) );
gtk_table_attach ( GTK_TABLE (table), radio_button, 3, 4, 2, 3, 0, 0, 0, 0);
gtk_signal_connect ( GTK_OBJECT (radio_button), "toggled",
(GtkSignalFunc) rotate_toggle_update,
&radio_pressed[1]);
gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (radio_button),
radio_pressed[1]);
gtk_widget_show (radio_button);
/* 180° */
radio_label = gtk_label_new ( angle_label[2] );
gtk_table_attach ( GTK_TABLE (table), radio_label, 2, 3, 4, 5, 0, 0, 0, 0);
gtk_widget_show (radio_label);
radio_button = gtk_radio_button_new ( radio_group );
radio_group = gtk_radio_button_group ( GTK_RADIO_BUTTON (radio_button) );
gtk_table_attach ( GTK_TABLE (table), radio_button, 2, 3, 3, 4, 0, 0, 0, 0);
gtk_signal_connect ( GTK_OBJECT (radio_button), "toggled",
(GtkSignalFunc) rotate_toggle_update,
&radio_pressed[2]);
gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (radio_button),
radio_pressed[2]);
gtk_widget_show (radio_button);
/* 270° */
radio_label = gtk_label_new ( angle_label[3] );
gtk_table_attach ( GTK_TABLE (table), radio_label, 0, 1, 2, 3, 0, 0, 0, 0);
gtk_widget_show (radio_label);
radio_button = gtk_radio_button_new ( radio_group );
radio_group = gtk_radio_button_group ( GTK_RADIO_BUTTON (radio_button) );
gtk_table_attach ( GTK_TABLE (table), radio_button, 1, 2, 2, 3, 0, 0, 0, 0);
gtk_signal_connect ( GTK_OBJECT (radio_button), "toggled",
(GtkSignalFunc) rotate_toggle_update,
&radio_pressed[3]);
gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (radio_button),
radio_pressed[3]);
gtk_widget_show (radio_button);
gtk_widget_show (table);
gtk_widget_show (frame);
/* hbox for check-button */
hbox = gtk_hbox_new (FALSE, 1);
gtk_container_border_width (GTK_CONTAINER (hbox), 6);
gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox),
hbox, TRUE, TRUE, 0);
/* check button */
check_button = gtk_check_button_new_with_label ("Rotate the whole image");
gtk_box_pack_end (GTK_BOX (hbox), check_button, TRUE, TRUE, 0);
gtk_signal_connect (GTK_OBJECT (check_button), "toggled",
(GtkSignalFunc) rotate_toggle_update,
&everything);
gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (check_button),
rotvals.everything);
gtk_widget_show (check_button);
gtk_widget_show (hbox);
gtk_widget_show (dialog);
gtk_main ();
gdk_flush ();
rotvals.angle=0;
for (i = 0; i < NUM_ANGLES; i++)
{
if (radio_pressed[i]==TRUE)
{
rotvals.angle = i;
break;
}
}
rotvals.everything = everything;
return rotint.run;
}
/* Rotate interface functions */
static void
rotate_close_callback (GtkWidget *widget,
gpointer data)
{
gtk_main_quit ();
}
static void
rotate_ok_callback (GtkWidget *widget,
gpointer data)
{
rotint.run = TRUE;
gtk_widget_destroy (GTK_WIDGET (data));
}
static void
rotate_toggle_update (GtkWidget *widget,
gpointer data)
{
gint *toggle_val;
toggle_val = (int *) data;
if (GTK_TOGGLE_BUTTON (widget)->active)
*toggle_val = TRUE;
else
*toggle_val = FALSE;
}
/* Error Message
*
* This code was stolen from Pavel Greenfield's Colormap Rotation plug-in */
static void
ErrorMessage(guchar *message)
{
GtkWidget *window, *label, *button, *table;
gchar **argv=g_new (gchar *, 1);
gint argc=1;
argv[0] = g_strdup ("rotate");
gtk_init (&argc, &argv);
gtk_rc_parse (gimp_gtkrc ());
window=gtk_dialog_new();
gtk_window_position (GTK_WINDOW (window), GTK_WIN_POS_MOUSE);
gtk_window_set_title(GTK_WINDOW(window), "Rotate Error Message");
gtk_signal_connect (GTK_OBJECT (window), "destroy",
(GtkSignalFunc) rotate_close_callback,
NULL);
button = gtk_button_new_with_label ("Got It!");
GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
gtk_signal_connect (GTK_OBJECT (button), "clicked",
(GtkSignalFunc) rotate_ok_callback,
window);
gtk_widget_grab_default (button);
gtk_widget_show (button);
gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->action_area), button, TRUE, TRUE, 0);
table=gtk_table_new(2,2,FALSE);
gtk_box_pack_start(GTK_BOX(GTK_DIALOG(window)->vbox),table,TRUE,TRUE,0);
gtk_widget_show(table);
label=gtk_label_new("");
gtk_label_set(GTK_LABEL(label),message);
gtk_widget_show(label);
gtk_table_attach(GTK_TABLE(table),label,0,1,0,1,
GTK_FILL|GTK_EXPAND,GTK_FILL|GTK_EXPAND,15,15);
gtk_widget_show(window);
gtk_main ();
}

View File

@ -1,360 +0,0 @@
/*
* Rotate plug-in version 1.00 - 97.09.28
* by Adam D. Moss <adam@gimp.org>
*
* This plugin will rotate a single layer or a whole image
* by 90 degrees clockwise or anticlockwise. (So I guess it's
* actually four plugins in one. Bonus!)
*
* This is part of the GIMP package and falls under the GPL.
*/
/*
* TODO:
*
* Work somewhat better with channels & masks
* Test PDB interface
* Progress bar
*
* Do something magical so that only one rotate can be occuring
* at a time!
*/
#include <stdlib.h>
#include <stdio.h>
#include "libgimp/gimp.h"
#include "gtk/gtk.h"
/* Declare local functions. */
static void query(void);
static void run(char *name,
int nparams,
GParam * param,
int *nreturn_vals,
GParam ** return_vals);
static void do_layerrot(GDrawable*, gint32, gboolean, gboolean);
GPlugInInfo PLUG_IN_INFO =
{
NULL, /* init_proc */
NULL, /* quit_proc */
query, /* query_proc */
run, /* run_proc */
};
MAIN()
static void query()
{
static GParamDef args[] =
{
{PARAM_INT32, "run_mode", "Interactive, non-interactive"},
{PARAM_IMAGE, "image", "Input image"},
{PARAM_DRAWABLE, "drawable", "Input drawable"},
};
static GParamDef *return_vals = NULL;
static int nargs = sizeof(args) / sizeof(args[0]);
static int nreturn_vals = 0;
gimp_install_procedure("plug_in_layer_rot90",
"Rotates the given layer 90 degrees clockwise.",
"",
"Adam D. Moss (adam@gimp.org)",
"Adam D. Moss (adam@gimp.org)",
"1997",
"<Image>/Filters/Transforms/Layer/Rotate 90",
"RGB*, GRAY*, INDEXED*",
PROC_PLUG_IN,
nargs, nreturn_vals,
args, return_vals);
gimp_install_procedure("plug_in_layer_rot270",
"Rotates the given layer 90 degrees anticlockwise.",
"",
"Adam D. Moss (adam@gimp.org)",
"Adam D. Moss (adam@gimp.org)",
"1997",
"<Image>/Filters/Transforms/Layer/Rotate 270",
"RGB*, GRAY*, INDEXED*",
PROC_PLUG_IN,
nargs, nreturn_vals,
args, return_vals);
gimp_install_procedure("plug_in_image_rot90",
"Rotates the given image 90 degrees clockwise.",
"",
"Adam D. Moss (adam@gimp.org)",
"Adam D. Moss (adam@gimp.org)",
"1997",
"<Image>/Filters/Transforms/Image/Rotate 90",
"RGB*, GRAY*, INDEXED*",
PROC_PLUG_IN,
nargs, nreturn_vals,
args, return_vals);
gimp_install_procedure("plug_in_image_rot270",
"Rotates the current image 90 degrees anticlockwise.",
"",
"Adam D. Moss (adam@gimp.org)",
"Adam D. Moss (adam@gimp.org)",
"1997",
"<Image>/Filters/Transforms/Image/Rotate 270",
"RGB*, GRAY*, INDEXED*",
PROC_PLUG_IN,
nargs, nreturn_vals,
args, return_vals);
}
static void run(char *name, int n_params, GParam * param, int *nreturn_vals,
GParam ** return_vals)
{
static GParam values[1];
GDrawable *drawable;
GRunModeType run_mode;
GStatusType status = STATUS_SUCCESS;
gint32 image_id;
gboolean clockwise;
gboolean alllayers;
gint32 *layers;
int nlayers,i;
int proc_returnvals;
/* Check the procedure name we were called with, to decide
what needs to be done. */
if (
(strcmp(name,"plug_in_layer_rot90")==0)
||
(strcmp(name,"plug_in_image_rot90")==0)
)
clockwise = TRUE;
else
clockwise = FALSE;
if (
(strcmp(name,"plug_in_image_rot270")==0)
||
(strcmp(name,"plug_in_image_rot90")==0)
)
alllayers = TRUE;
else
alllayers = FALSE;
*nreturn_vals = 1;
*return_vals = values;
run_mode = param[0].data.d_int32;
if (run_mode == RUN_NONINTERACTIVE) {
if (n_params != 3) {
status = STATUS_CALLING_ERROR;
}
}
if (status == STATUS_SUCCESS) {
/* Get the specified drawable */
drawable = gimp_drawable_get(param[2].data.d_drawable);
image_id = param[1].data.d_image;
/* Make sure that the drawable is gray or RGB or indexed */
if (gimp_drawable_color(drawable->id) || gimp_drawable_gray(drawable->id) || gimp_drawable_indexed(drawable->id)) {
gimp_tile_cache_ntiles(7 + 2*(
drawable->width > drawable->height ?
( drawable->width / gimp_tile_width() ) :
( drawable->height / gimp_tile_height() )
)
);
/******************* DO THE WORK **************/
gimp_run_procedure ("gimp_undo_push_group_start", &proc_returnvals,
PARAM_IMAGE, image_id,
PARAM_END);
if (alllayers) /* rotate whole image, including all layers */
{
gimp_drawable_detach(drawable);
/* get a list of layers for this image_id */
layers = gimp_image_get_layers (image_id, &nlayers);
for (i=0;i<nlayers;i++)
{
drawable = gimp_drawable_get (layers[i]);
do_layerrot(drawable, image_id, clockwise, alllayers);
gimp_drawable_detach(drawable);
}
g_free(layers);
gimp_image_resize(image_id,
gimp_image_height(image_id),
gimp_image_width(image_id),
0, 0);
}
else /* just rotate a single layer */
{
do_layerrot(drawable, image_id, clockwise, alllayers);
gimp_drawable_detach(drawable);
}
gimp_run_procedure ("gimp_undo_push_group_end", &proc_returnvals,
PARAM_IMAGE, image_id,
PARAM_END);
/******************* WORK FINISHED **************/
if (run_mode != RUN_NONINTERACTIVE)
gimp_displays_flush();
} else {
status = STATUS_EXECUTION_ERROR;
}
}
values[0].type = PARAM_STATUS;
values[0].data.d_status = status;
}
static void do_layerrot(GDrawable *drawable,
gint32 image_id,
gboolean clockwise,
gboolean alllayers)
{
GPixelRgn rowPR, colPR;
gint width, height, x, y;
guchar *buffer;
gboolean x_is_longer;
gint xoff,yoff, newxoff,newyoff;
gint was_preserve_transparency = FALSE;
gint bytes;
width = drawable->width;
height = drawable->height;
bytes = drawable->bpp;
x_is_longer = (width > height);
if (gimp_drawable_layer(drawable->id))
{
gimp_layer_resize(drawable->id,
x_is_longer? width : height,
x_is_longer? width : height,
0, 0);
gimp_drawable_flush (drawable);
drawable = gimp_drawable_get(drawable->id);
}
else /* not a layer... probably a channel... abort operation */
exit;
/* If 'preserve transparency' was on, we need to temporatily
turn it off while rotating... */
if (gimp_layer_get_preserve_transparency(drawable->id))
{
was_preserve_transparency = TRUE;
gimp_layer_set_preserve_transparency(drawable->id,
FALSE);
}
buffer = g_malloc ((x_is_longer? width: height) * bytes);
/* initialize the pixel regions */
gimp_pixel_rgn_init(&rowPR, drawable, 0, 0,
x_is_longer? width:height,
x_is_longer? width:height,
FALSE, FALSE);
gimp_pixel_rgn_init(&colPR, drawable, 0, 0,
x_is_longer? width:height,
x_is_longer? width:height,
TRUE, TRUE);
if (clockwise)
{
/* CLOCKWISE */
for (y=0; y<height; y++)
{
x=(height-y)-1;
gimp_pixel_rgn_get_row(&rowPR, buffer, 0, y, width);
gimp_pixel_rgn_set_col(&colPR, buffer, x, 0, width);
}
}
else
{
/* ANTICLOCKWISE */
for (x=0; x<width; x++)
{
y=(width-x)-1;
gimp_pixel_rgn_get_col(&rowPR, buffer, x, 0, height);
gimp_pixel_rgn_set_row(&colPR, buffer, 0, y, height);
}
}
g_free(buffer);
gimp_drawable_flush (drawable);
gimp_drawable_merge_shadow (drawable->id, TRUE);
gimp_drawable_update (drawable->id, 0, 0, height, width);
gimp_layer_resize(drawable->id,
height,
width,
0, 0);
drawable = gimp_drawable_get(drawable->id);
gimp_drawable_flush (drawable);
gimp_drawable_update (drawable->id, 0, 0, height, width);
if (!alllayers)
{
/* Offset the layer so that it remains centered on the same spot */
gimp_drawable_offsets (drawable->id,
&xoff,
&yoff);
newxoff = xoff+(width-height)/2;
newyoff = yoff+(height-width)/2;
gimp_layer_set_offsets(drawable->id,
newxoff,
newyoff);
}
else /* alllayers */
{
/* Iterating through all layers... so rotate around the image
centre, not the layer centre. */
gimp_drawable_offsets (drawable->id,
&xoff,
&yoff);
if (clockwise)
{
newyoff = xoff;
newxoff = gimp_image_height(image_id)-yoff-height;
}
else /* anticlockwise */
{
newxoff = yoff;
newyoff = gimp_image_width(image_id)-xoff-width;
}
gimp_layer_set_offsets(drawable->id,
newxoff,
newyoff);
}
/* set 'preserve transparency' if it was set when we started... */
if (was_preserve_transparency)
{
gimp_layer_set_preserve_transparency(drawable->id,
TRUE);
}
}

View File

@ -1,63 +0,0 @@
#ident "@(#)run_tbl.c 3.1 95/08/30 Copyright (c) 1994 Gert Doering"
/* run_tbl.c
*
* this file is part of the mgetty+sendfax distribution
*
* compute a set of arrays that will speed up finding the run length
* of black or white bits in a byte enourmously
* (I do not include the array as it is larger than the source and
* computation is fast enough - 0.005 secs on my machine...)
*/
static unsigned char tab[9] = { 0x00,
0x01, 0x03, 0x07, 0x0f,
0x1f, 0x3f, 0x7f, 0xff };
char w_rtab[8][256];
char b_rtab[8][256];
void make_run_tables ( void )
{
int i, j, k, m; /* byte = kkkjjjmm, "j" starts at bit "i" */
int mask; /* black mask (all ones), start bit i, j bits wide */
for ( i=0; i<8; i++ ) /* for (all starting bits) */
{
for ( j=i+1; j>=0; j-- ) /* for (all possible run lengths) */
{
mask = tab[j] << ((i-j)+1);
if ( i == 7 ) /* no fill bits to the left */
{
if ( j == i+1 ) /* no fill bits to the right */
{
w_rtab[i][0 ] = j;
b_rtab[i][mask] = j;
}
else /* fill bits to the right */
for ( m = ( 1 << (i-j) ) -1 ; m >= 0; m-- )
{
w_rtab[i][0 + (1<<(i-j)) + m ] = j;
b_rtab[i][mask+ 0 + m ] = j;
}
}
else /* i != 7 -> fill higher bits */
for ( k = (0x80>>i) -1; k>= 0; k-- )
{
if ( j == i+1 ) /* no noise to the right */
{
w_rtab[i][ (k << (i+1)) + 0 ] = j;
b_rtab[i][ (k << (i+1)) + mask ] = j;
}
else /* fill bits to left + right */
for ( m = ( 1 << (i-j) ) -1; m >= 0; m-- )
{
w_rtab[i][ (k << (i+1)) + 0 + (1<<(i-j)) + m ] = j;
b_rtab[i][ (k << (i+1)) + mask + 0 + m ] = j;
}
} /* end for (k) [noise left of top bit] */
} /* end for (j) [span] */
} /* end for (i) [top bit] */
}

File diff suppressed because it is too large Load Diff

View File

@ -1,744 +0,0 @@
/*
* "$Id$"
*
* SGI image file plug-in for the GIMP.
*
* Copyright 1997 Michael Sweet (mike@easysw.com)
*
* 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 the Free
* Software Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* Contents:
*
* main() - Main entry - just call gimp_main()...
* query() - Respond to a plug-in query...
* run() - Run the plug-in...
* load_image() - Load a PNG image into a new image window.
* save_image() - Save the specified image to a PNG file.
* save_close_callback() - Close the save dialog window.
* save_ok_callback() - Destroy the save dialog and save the image.
* save_compression_callback() - Update the image compression level.
* save_dialog() - Pop up the save dialog.
*
* Revision History:
*
* $Log$
* Revision 1.1.1.1 1997/11/24 22:03:36 sopwith
* Let's try this import one last time.
*
* Revision 1.4 1997/10/15 18:53:41 nobody
* Fixed Makefile.am's (-I$(includedir) added), removed C++ comments
* (ARGH!) in some plug-ins, fixed typos, changed some plug-ins to follow
* the naming convention.
*
* Revision 1.3 1997/09/30 09:16:01 nobody
* work I men it...
*
* Revision 1.2 1997/07/25 20:44:05 mike
* Fixed image_load_sgi load error bug (causes GIMP hang/crash).
*
* Revision 1.1 1997/06/18 00:55:28 mike
* Initial revision
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include "sgi.h" /* SGI image library definitions */
#include <gtk/gtk.h>
#include <libgimp/gimp.h>
/*
* Constants...
*/
#define PLUG_IN_VERSION "1.0.1"
/*
* Local functions...
*/
static void query(void);
static void run(char *, int, GParam *, int *, GParam **);
static gint32 load_image(char *);
static gint save_image (char *, gint32, gint32);
static gint save_dialog(void);
static void save_close_callback(GtkWidget *, gpointer);
static void save_ok_callback(GtkWidget *, gpointer);
static void save_compression_callback(GtkWidget *, gpointer);
/*
* Globals...
*/
GPlugInInfo PLUG_IN_INFO =
{
NULL, /* init_proc */
NULL, /* quit_proc */
query, /* query_proc */
run, /* run_proc */
};
int compression = SGI_COMP_RLE;
int runme = FALSE;
/*
* 'main()' - Main entry - just call gimp_main()...
*/
int
main(int argc, /* I - Number of command-line args */
char *argv[]) /* I - Command-line args */
{
return (gimp_main(argc, argv));
}
/*
* 'query()' - Respond to a plug-in query...
*/
static void
query(void)
{
static GParamDef load_args[] =
{
{ PARAM_INT32, "run_mode", "Interactive, non-interactive" },
{ PARAM_STRING, "filename", "The name of the file to load" },
{ PARAM_STRING, "raw_filename", "The name of the file to load" },
};
static GParamDef load_return_vals[] =
{
{ PARAM_IMAGE, "image", "Output image" },
};
static int nload_args = sizeof (load_args) / sizeof (load_args[0]);
static int nload_return_vals = sizeof (load_return_vals) / sizeof (load_return_vals[0]);
static GParamDef save_args[] =
{
{ PARAM_INT32, "run_mode", "Interactive, non-interactive" },
{ PARAM_IMAGE, "image", "Input image" },
{ PARAM_DRAWABLE, "drawable", "Drawable to save" },
{ PARAM_STRING, "filename", "The name of the file to save the image in" },
{ PARAM_STRING, "raw_filename", "The name of the file to save the image in" },
{ PARAM_INT32, "compression", "Compression level (0 = none, 1 = RLE, 2 = ARLE)" }
};
static int nsave_args = sizeof (save_args) / sizeof (save_args[0]);
gimp_install_procedure("file_sgi_load",
"Loads files in SGI image file format",
"This plug-in loads SGI image files.",
"Michael Sweet", "Michael Sweet", PLUG_IN_VERSION,
"<Load>/SGI", NULL, PROC_PLUG_IN, nload_args, nload_return_vals,
load_args, load_return_vals);
gimp_install_procedure("file_sgi_save",
"Saves files in SGI image file format",
"This plug-in saves SGI image files.",
"Michael Sweet", "Michael Sweet", PLUG_IN_VERSION,
"<Save>/SGI", "RGB*,GRAY*", PROC_PLUG_IN, nsave_args, 0, save_args, NULL);
gimp_register_magic_load_handler("file_sgi_load", "rgb,bw,sgi", "", "0,short,474");
gimp_register_save_handler("file_sgi_save", "rgb,bw,sgi", "");
}
/*
* 'run()' - Run the plug-in...
*/
static void
run(char *name, /* I - Name of filter program. */
int nparams, /* I - Number of parameters passed in */
GParam *param, /* I - Parameter values */
int *nreturn_vals, /* O - Number of return values */
GParam **return_vals) /* O - Return values */
{
gint32 image_ID; /* ID of loaded image */
static GParam values[2]; /* Return values */
signal(SIGBUS, SIG_DFL);
signal(SIGSEGV, SIG_DFL);
/*
* Initialize parameter data...
*/
values[0].type = PARAM_STATUS;
values[0].data.d_status = STATUS_SUCCESS;
*return_vals = values;
/*
* Load or save an image...
*/
if (strcmp(name, "file_sgi_load") == 0)
{
*nreturn_vals = 2;
image_ID = load_image(param[1].data.d_string);
if (image_ID != -1)
{
values[1].type = PARAM_IMAGE;
values[1].data.d_image = image_ID;
}
else
values[0].data.d_status = STATUS_EXECUTION_ERROR;
}
else if (strcmp (name, "file_sgi_save") == 0)
{
*nreturn_vals = 1;
switch (param[0].data.d_int32)
{
case RUN_INTERACTIVE :
/*
* Possibly retrieve data...
*/
gimp_get_data("file_sgi_save", &compression);
/*
* Then acquire information with a dialog...
*/
if (!save_dialog())
return;
break;
case RUN_NONINTERACTIVE :
/*
* Make sure all the arguments are there!
*/
if (nparams != 6)
values[0].data.d_status = STATUS_CALLING_ERROR;
else
{
compression = param[5].data.d_int32;
if (compression < 0 || compression > 2)
values[0].data.d_status = STATUS_CALLING_ERROR;
};
break;
case RUN_WITH_LAST_VALS :
/*
* Possibly retrieve data...
*/
gimp_get_data("file_sgi_save", &compression);
break;
default :
break;
};
if (values[0].data.d_status == STATUS_SUCCESS)
{
if (save_image(param[3].data.d_string, param[1].data.d_int32,
param[2].data.d_int32))
gimp_set_data("file_sgi_save", &compression, sizeof(compression));
else
values[0].data.d_status = STATUS_EXECUTION_ERROR;
};
}
else
values[0].data.d_status = STATUS_EXECUTION_ERROR;
}
/*
* 'load_image()' - Load a PNG image into a new image window.
*/
static gint32
load_image(char *filename) /* I - File to load */
{
int i, /* Looping var */
x, /* Current X coordinate */
y, /* Current Y coordinate */
image_type, /* Type of image */
layer_type, /* Type of drawable/layer */
tile_height, /* Height of tile in GIMP */
count; /* Count of rows to put in image */
sgi_t *sgip; /* File pointer */
gint32 image, /* Image */
layer; /* Layer */
GDrawable *drawable; /* Drawable for layer */
GPixelRgn pixel_rgn; /* Pixel region for layer */
guchar **pixels, /* Pixel rows */
*pixel, /* Pixel data */
*pptr; /* Current pixel */
short **rows; /* SGI image data */
char progress[255]; /* Title for progress display... */
/*
* Open the file for reading...
*/
sgip = sgiOpen(filename, SGI_READ, 0, 0, 0, 0, 0);
if (sgip == NULL)
{
g_print("can't open image file\n");
gimp_quit();
};
if (strrchr(filename, '/') != NULL)
sprintf(progress, "Loading %s:", strrchr(filename, '/') + 1);
else
sprintf(progress, "Loading %s:", filename);
gimp_progress_init(progress);
/*
* Get the image dimensions and create the image...
*/
switch (sgip->zsize)
{
case 1 : /* Grayscale */
image_type = GRAY;
layer_type = GRAY_IMAGE;
break;
case 2 : /* Grayscale + alpha */
image_type = GRAY;
layer_type = GRAYA_IMAGE;
break;
case 3 : /* RGB */
image_type = RGB;
layer_type = RGB_IMAGE;
break;
case 4 : /* RGBA */
image_type = RGB;
layer_type = RGBA_IMAGE;
break;
};
image = gimp_image_new(sgip->xsize, sgip->ysize, image_type);
if (image == -1)
{
g_print("can't allocate new image\n");
gimp_quit();
};
gimp_image_set_filename(image, filename);
/*
* Create the "background" layer to hold the image...
*/
layer = gimp_layer_new(image, "Background", sgip->xsize, sgip->ysize,
layer_type, 100, NORMAL_MODE);
gimp_image_add_layer(image, layer, 0);
/*
* Get the drawable and set the pixel region for our load...
*/
drawable = gimp_drawable_get(layer);
gimp_pixel_rgn_init(&pixel_rgn, drawable, 0, 0, drawable->width,
drawable->height, TRUE, FALSE);
/*
* Temporary buffers...
*/
tile_height = gimp_tile_height();
pixel = g_new(guchar, tile_height * sgip->xsize * sgip->zsize);
pixels = g_new(guchar *, tile_height);
for (i = 0; i < tile_height; i ++)
pixels[i] = pixel + sgip->xsize * sgip->zsize * i;
rows = g_new(short *, sgip->zsize);
rows[0] = g_new(short, sgip->xsize * sgip->zsize);
for (i = 1; i < sgip->zsize; i ++)
rows[i] = rows[0] + i * sgip->xsize;
/*
* Load the image...
*/
for (y = 0, count = 0;
y < sgip->ysize;
y ++, count ++)
{
if (count >= tile_height)
{
gimp_pixel_rgn_set_rect(&pixel_rgn, pixel, 0, y - count, drawable->width, count);
count = 0;
gimp_progress_update((double)y / (double)sgip->ysize);
};
for (i = 0; i < sgip->zsize; i ++)
if (sgiGetRow(sgip, rows[i], sgip->ysize - 1 - y, i) < 0)
printf("sgiGetRow(sgip, rows[i], %d, %d) failed!\n",
sgip->ysize - 1 - y, i);
if (sgip->bpp == 1)
{
/*
* 8-bit (unsigned) pixels...
*/
for (x = 0, pptr = pixels[count]; x < sgip->xsize; x ++)
for (i = 0; i < sgip->zsize; i ++, pptr ++)
*pptr = rows[i][x];
}
else
{
/*
* 16-bit (signed) pixels...
*/
for (x = 0, pptr = pixels[count]; x < sgip->xsize; x ++)
for (i = 0; i < sgip->zsize; i ++, pptr ++)
*pptr = (unsigned)(rows[i][x] + 32768) >> 8;
};
};
/*
* Do the last n rows (count always > 0)
*/
gimp_pixel_rgn_set_rect(&pixel_rgn, pixel, 0, y - count, drawable->width, count);
/*
* Done with the file...
*/
sgiClose(sgip);
free(pixel);
free(pixels);
free(rows[0]);
free(rows);
/*
* Update the display...
*/
gimp_drawable_flush(drawable);
gimp_drawable_detach(drawable);
return (image);
}
/*
* 'save_image()' - Save the specified image to a PNG file.
*/
static gint
save_image(char *filename, /* I - File to save to */
gint32 image_ID, /* I - Image to save */
gint32 drawable_ID) /* I - Current drawable */
{
int i, j, /* Looping var */
x, /* Current X coordinate */
y, /* Current Y coordinate */
image_type, /* Type of image */
layer_type, /* Type of drawable/layer */
tile_height, /* Height of tile in GIMP */
count, /* Count of rows to put in image */
zsize; /* Number of channels in file */
sgi_t *sgip; /* File pointer */
GDrawable *drawable; /* Drawable for layer */
GPixelRgn pixel_rgn; /* Pixel region for layer */
guchar **pixels, /* Pixel rows */
*pixel, /* Pixel data */
*pptr; /* Current pixel */
short **rows; /* SGI image data */
char progress[255]; /* Title for progress display... */
/*
* Get the drawable for the current image...
*/
drawable = gimp_drawable_get(drawable_ID);
gimp_pixel_rgn_init(&pixel_rgn, drawable, 0, 0, drawable->width,
drawable->height, FALSE, FALSE);
switch (gimp_drawable_type(drawable_ID))
{
case GRAY_IMAGE :
zsize = 1;
break;
case GRAYA_IMAGE :
zsize = 2;
break;
case RGB_IMAGE :
zsize = 3;
break;
case RGBA_IMAGE :
zsize = 4;
break;
};
/*
* Open the file for writing...
*/
sgip = sgiOpen(filename, SGI_WRITE, compression, 1, drawable->width,
drawable->height, zsize);
if (sgip == NULL)
{
g_print("can't create image file\n");
gimp_quit();
};
if (strrchr(filename, '/') != NULL)
sprintf(progress, "Saving %s:", strrchr(filename, '/') + 1);
else
sprintf(progress, "Saving %s:", filename);
gimp_progress_init(progress);
/*
* Allocate memory for "tile_height" rows...
*/
tile_height = gimp_tile_height();
pixel = g_new(guchar, tile_height * drawable->width * zsize);
pixels = g_new(guchar *, tile_height);
for (i = 0; i < tile_height; i ++)
pixels[i]= pixel + drawable->width * zsize * i;
rows = g_new(short *, sgip->zsize);
rows[0] = g_new(short, sgip->xsize * sgip->zsize);
for (i = 1; i < sgip->zsize; i ++)
rows[i] = rows[0] + i * sgip->xsize;
/*
* Save the image...
*/
for (y = 0; y < drawable->height; y += count)
{
/*
* Grab more pixel data...
*/
if ((y + tile_height) >= drawable->height)
count = drawable->height - y;
else
count = tile_height;
gimp_pixel_rgn_get_rect(&pixel_rgn, pixel, 0, y, drawable->width, count);
/*
* Convert to shorts and write each color plane separately...
*/
for (i = 0, pptr = pixels[0]; i < count; i ++)
{
for (x = 0; x < drawable->width; x ++)
for (j = 0; j < zsize; j ++, pptr ++)
rows[j][x] = *pptr;
for (j = 0; j < zsize; j ++)
sgiPutRow(sgip, rows[j], drawable->height - 1 - y - i, j);
};
gimp_progress_update((double)y / (double)drawable->height);
};
/*
* Done with the file...
*/
sgiClose(sgip);
free(pixel);
free(pixels);
free(rows[0]);
free(rows);
return (1);
}
/*
* 'save_close_callback()' - Close the save dialog window.
*/
static void
save_close_callback(GtkWidget *w, /* I - Close button */
gpointer data) /* I - Callback data */
{
gtk_main_quit();
}
/*
* 'save_ok_callback()' - Destroy the save dialog and save the image.
*/
static void
save_ok_callback(GtkWidget *w, /* I - OK button */
gpointer data) /* I - Callback data */
{
runme = TRUE;
gtk_widget_destroy(GTK_WIDGET(data));
}
/*
* 'save_compression_callback()' - Update the image compression level.
*/
static void
save_compression_callback(GtkWidget *w, /* I - Compression button */
gpointer data) /* I - Callback data */
{
if (GTK_TOGGLE_BUTTON(w)->active)
compression = (long)data;
}
/*
* 'save_dialog()' - Pop up the save dialog.
*/
static gint
save_dialog(void)
{
int i; /* Looping var */
GtkWidget *dlg, /* Dialog window */
*button, /* OK/cancel/compression buttons */
*frame, /* Frame for dialog */
*vbox; /* Box for compression types */
GSList *group; /* Button grouping for compression */
gchar **argv; /* Fake command-line args */
gint argc; /* Number of fake command-line args */
static char *types[] = /* Compression types... */
{
"No Compression",
"RLE Compression",
"Advanced RLE"
};
/*
* Fake the command-line args and open a window...
*/
argc = 1;
argv = g_new (gchar *, 1);
argv[0] = g_strdup("sgi");
gtk_init(&argc, &argv);
signal(SIGBUS, SIG_DFL);
signal(SIGSEGV, SIG_DFL);
/*
* Open a dialog window...
*/
dlg = gtk_dialog_new();
gtk_window_set_title(GTK_WINDOW(dlg), "SGI Options");
gtk_window_position(GTK_WINDOW(dlg), GTK_WIN_POS_MOUSE);
gtk_signal_connect(GTK_OBJECT(dlg), "destroy",
(GtkSignalFunc)save_close_callback, NULL);
/*
* OK/cancel buttons...
*/
button = gtk_button_new_with_label("OK");
GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT);
gtk_signal_connect(GTK_OBJECT (button), "clicked",
(GtkSignalFunc)save_ok_callback,
dlg);
gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dlg)->action_area), button, TRUE, TRUE, 0);
gtk_widget_grab_default(button);
gtk_widget_show(button);
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));
gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dlg)->action_area), button, TRUE, TRUE, 0);
gtk_widget_show(button);
/*
* Compression type...
*/
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);
vbox = gtk_vbox_new(FALSE, 0);
gtk_container_border_width(GTK_CONTAINER(vbox), 4);
gtk_container_add(GTK_CONTAINER(frame), vbox);
gtk_widget_show(vbox);
group = NULL;
for (i = 0; i < (sizeof(types) / sizeof(types[0])); i ++)
{
button = gtk_radio_button_new_with_label(group, types[i]);
group = gtk_radio_button_group(GTK_RADIO_BUTTON(button));
if (i == compression)
gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(button), TRUE);
gtk_signal_connect(GTK_OBJECT(button), "toggled",
(GtkSignalFunc)save_compression_callback,
(gpointer)((long)i));
gtk_box_pack_start(GTK_BOX(vbox), button, FALSE, FALSE, 0);
gtk_widget_show(button);
};
/*
* Show everything and go...
*/
gtk_widget_show(frame);
gtk_widget_show(dlg);
gtk_main();
gdk_flush();
return (runme);
}
/*
* End of "$Id$".
*/

View File

@ -1,870 +0,0 @@
/*
* "$Id$"
*
* SGI image file format library routines.
*
* Copyright 1997 Michael Sweet (mike@easysw.com)
*
* 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 the Free
* Software Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* Contents:
*
* sgiClose() - Close an SGI image file.
* sgiGetRow() - Get a row of image data from a file.
* sgiOpen() - Open an SGI image file for reading or writing.
* sgiPutRow() - Put a row of image data to a file.
* getlong() - Get a 32-bit big-endian integer.
* getshort() - Get a 16-bit big-endian integer.
* putlong() - Put a 32-bit big-endian integer.
* putshort() - Put a 16-bit big-endian integer.
* read_rle8() - Read 8-bit RLE data.
* read_rle16() - Read 16-bit RLE data.
* write_rle8() - Write 8-bit RLE data.
* write_rle16() - Write 16-bit RLE data.
*
* Revision History:
*
* $Log$
* Revision 1.1.1.1 1997/11/24 22:03:36 sopwith
* Let's try this import one last time.
*
* Revision 1.4 1997/10/15 18:53:41 nobody
* Fixed Makefile.am's (-I$(includedir) added), removed C++ comments
* (ARGH!) in some plug-ins, fixed typos, changed some plug-ins to follow
* the naming convention.
*
* Revision 1.3 1997/09/30 09:16:02 nobody
* work I men it...
*
* Revision 1.3 1997/07/02 16:40:16 mike
* sgiOpen() wasn't opening files with "rb" or "wb+". This caused problems
* on PCs running Windows/DOS...
*
* Revision 1.2 1997/06/18 00:55:28 mike
* Updated to hold length table when writing.
* Updated to hold current length when doing ARLE.
* Wasn't writing length table on close.
* Wasn't saving new line into arle_row when necessary.
*
* Revision 1.1 1997/06/15 03:37:19 mike
* Initial revision
*/
#include <string.h>
#include "sgi.h"
/*
* Local functions...
*/
static int getlong(FILE *);
static int getshort(FILE *);
static int putlong(long, FILE *);
static int putshort(short, FILE *);
static int read_rle8(FILE *, short *, int);
static int read_rle16(FILE *, short *, int);
static int write_rle8(FILE *, short *, int);
static int write_rle16(FILE *, short *, int);
/*
* 'sgiClose()' - Close an SGI image file.
*/
int
sgiClose(sgi_t *sgip) /* I - SGI image */
{
int i; /* Return status */
long *offset; /* Looping var for offset table */
if (sgip == NULL)
return (-1);
if (sgip->mode == SGI_WRITE && sgip->comp != SGI_COMP_NONE)
{
/*
* Write the scanline offset table to the file...
*/
fseek(sgip->file, 512, SEEK_SET);
for (i = sgip->ysize * sgip->zsize, offset = sgip->table[0];
i > 0;
i --, offset ++)
if (putlong(offset[0], sgip->file) < 0)
return (-1);
for (i = sgip->ysize * sgip->zsize, offset = sgip->length[0];
i > 0;
i --, offset ++)
if (putlong(offset[0], sgip->file) < 0)
return (-1);
};
if (sgip->table != NULL)
{
free(sgip->table[0]);
free(sgip->table);
};
if (sgip->length != NULL)
{
free(sgip->length[0]);
free(sgip->length);
};
if (sgip->comp == SGI_COMP_ARLE)
free(sgip->arle_row);
i = fclose(sgip->file);
free(sgip);
return (i);
}
/*
* 'sgiGetRow()' - Get a row of image data from a file.
*/
int
sgiGetRow(sgi_t *sgip, /* I - SGI image */
short *row, /* O - Row to read */
int y, /* I - Line to read */
int z) /* I - Channel to read */
{
int x; /* X coordinate */
long offset; /* File offset */
if (sgip == NULL ||
row == NULL ||
y < 0 || y >= sgip->ysize ||
z < 0 || z >= sgip->zsize)
return (-1);
switch (sgip->comp)
{
case SGI_COMP_NONE :
/*
* Seek to the image row - optimize buffering by only seeking if
* necessary...
*/
offset = 512 + (y + z * sgip->ysize) * sgip->xsize * sgip->bpp;
if (offset != ftell(sgip->file))
fseek(sgip->file, offset, SEEK_SET);
if (sgip->bpp == 1)
{
for (x = sgip->xsize; x > 0; x --, row ++)
*row = getc(sgip->file);
}
else
{
for (x = sgip->xsize; x > 0; x --, row ++)
*row = getshort(sgip->file);
};
break;
case SGI_COMP_RLE :
offset = sgip->table[z][y];
if (offset != ftell(sgip->file))
fseek(sgip->file, offset, SEEK_SET);
if (sgip->bpp == 1)
return (read_rle8(sgip->file, row, sgip->xsize));
else
return (read_rle16(sgip->file, row, sgip->xsize));
break;
};
return (0);
}
/*
* 'sgiOpen()' - Open an SGI image file for reading or writing.
*/
sgi_t *
sgiOpen(char *filename, /* I - File to open */
int mode, /* I - Open mode (SGI_READ or SGI_WRITE) */
int comp, /* I - Type of compression */
int bpp, /* I - Bytes per pixel */
int xsize, /* I - Width of image in pixels */
int ysize, /* I - Height of image in pixels */
int zsize) /* I - Number of channels */
{
int i, j; /* Looping var */
char name[80]; /* Name of file in image header */
short magic; /* Magic number */
sgi_t *sgip; /* New image pointer */
if ((sgip = calloc(sizeof(sgi_t), 1)) == NULL)
return (NULL);
switch (mode)
{
case SGI_READ :
if (filename == NULL)
{
free(sgip);
return (NULL);
};
if ((sgip->file = fopen(filename, "rb")) == NULL)
{
free(sgip);
return (NULL);
};
sgip->mode = SGI_READ;
magic = getshort(sgip->file);
if (magic != SGI_MAGIC)
{
fclose(sgip->file);
free(sgip);
return (NULL);
};
sgip->comp = getc(sgip->file);
sgip->bpp = getc(sgip->file);
getshort(sgip->file); /* Dimensions */
sgip->xsize = getshort(sgip->file);
sgip->ysize = getshort(sgip->file);
sgip->zsize = getshort(sgip->file);
getlong(sgip->file); /* Minimum pixel */
getlong(sgip->file); /* Maximum pixel */
if (sgip->comp)
{
/*
* This file is compressed; read the scanline tables...
*/
fseek(sgip->file, 512, SEEK_SET);
sgip->table = calloc(sgip->zsize, sizeof(long *));
sgip->table[0] = calloc(sgip->ysize * sgip->zsize, sizeof(long));
for (i = 1; i < sgip->zsize; i ++)
sgip->table[i] = sgip->table[0] + i * sgip->ysize;
for (i = 0; i < sgip->zsize; i ++)
for (j = 0; j < sgip->ysize; j ++)
sgip->table[i][j] = getlong(sgip->file);
};
break;
case SGI_WRITE :
if (filename == NULL ||
xsize < 1 ||
ysize < 1 ||
zsize < 1 ||
bpp < 1 || bpp > 2 ||
comp < SGI_COMP_NONE || comp > SGI_COMP_ARLE)
{
free(sgip);
return (NULL);
};
if ((sgip->file = fopen(filename, "wb+")) == NULL)
{
free(sgip);
return (NULL);
};
sgip->mode = SGI_WRITE;
putshort(SGI_MAGIC, sgip->file);
putc((sgip->comp = comp) != 0, sgip->file);
putc(sgip->bpp = bpp, sgip->file);
putshort(3, sgip->file); /* Dimensions */
putshort(sgip->xsize = xsize, sgip->file);
putshort(sgip->ysize = ysize, sgip->file);
putshort(sgip->zsize = zsize, sgip->file);
if (bpp == 1)
{
putlong(0, sgip->file); /* Minimum pixel */
putlong(255, sgip->file); /* Maximum pixel */
}
else
{
putlong(-32768, sgip->file); /* Minimum pixel */
putlong(32767, sgip->file); /* Maximum pixel */
};
putlong(0, sgip->file); /* Reserved */
memset(name, 0, sizeof(name));
if (strrchr(filename, '/') == NULL)
strncpy(name, filename, sizeof(name) - 1);
else
strncpy(name, strrchr(filename, '/') + 1, sizeof(name) - 1);
fwrite(name, sizeof(name), 1, sgip->file);
for (i = 0; i < 102; i ++)
putlong(0, sgip->file);
switch (comp)
{
case SGI_COMP_NONE : /* No compression */
/*
* This file is uncompressed. To avoid problems with sparse files,
* we need to write blank pixels for the entire image...
*/
if (bpp == 1)
{
for (i = xsize * ysize * zsize; i > 0; i --)
putc(0, sgip->file);
}
else
{
for (i = xsize * ysize * zsize; i > 0; i --)
putshort(0, sgip->file);
};
break;
case SGI_COMP_ARLE : /* Aggressive RLE */
sgip->arle_row = calloc(xsize, sizeof(short));
sgip->arle_offset = 0;
case SGI_COMP_RLE : /* Run-Length Encoding */
/*
* This file is compressed; write the (blank) scanline tables...
*/
for (i = 2 * ysize * zsize; i > 0; i --)
putlong(0, sgip->file);
sgip->firstrow = ftell(sgip->file);
sgip->nextrow = ftell(sgip->file);
sgip->table = calloc(sgip->zsize, sizeof(long *));
sgip->table[0] = calloc(sgip->ysize * sgip->zsize, sizeof(long));
for (i = 1; i < sgip->zsize; i ++)
sgip->table[i] = sgip->table[0] + i * sgip->ysize;
sgip->length = calloc(sgip->zsize, sizeof(long *));
sgip->length[0] = calloc(sgip->ysize * sgip->zsize, sizeof(long));
for (i = 1; i < sgip->zsize; i ++)
sgip->length[i] = sgip->length[0] + i * sgip->ysize;
break;
};
break;
default :
free(sgip);
return (NULL);
};
return (sgip);
}
/*
* 'sgiPutRow()' - Put a row of image data to a file.
*/
int
sgiPutRow(sgi_t *sgip, /* I - SGI image */
short *row, /* I - Row to write */
int y, /* I - Line to write */
int z) /* I - Channel to write */
{
int x; /* X coordinate */
long offset; /* File offset */
if (sgip == NULL ||
row == NULL ||
y < 0 || y >= sgip->ysize ||
z < 0 || z >= sgip->zsize)
return (-1);
switch (sgip->comp)
{
case SGI_COMP_NONE :
/*
* Seek to the image row - optimize buffering by only seeking if
* necessary...
*/
offset = 512 + (y + z * sgip->ysize) * sgip->xsize * sgip->bpp;
if (offset != ftell(sgip->file))
fseek(sgip->file, offset, SEEK_SET);
if (sgip->bpp == 1)
{
for (x = sgip->xsize; x > 0; x --, row ++)
putc(*row, sgip->file);
}
else
{
for (x = sgip->xsize; x > 0; x --, row ++)
putshort(*row, sgip->file);
};
break;
case SGI_COMP_ARLE :
if (sgip->table[z][y] != 0)
return (-1);
/*
* First check the last row written...
*/
if (sgip->arle_offset > 0)
{
for (x = 0; x < sgip->xsize; x ++)
if (row[x] != sgip->arle_row[x])
break;
if (x == sgip->xsize)
{
sgip->table[z][y] = sgip->arle_offset;
sgip->length[z][y] = sgip->arle_length;
return (0);
};
};
/*
* If that didn't match, search all the previous rows...
*/
fseek(sgip->file, sgip->firstrow, SEEK_SET);
if (sgip->bpp == 1)
{
do
{
sgip->arle_offset = ftell(sgip->file);
if ((sgip->arle_length = read_rle8(sgip->file, sgip->arle_row, sgip->xsize)) < 0)
{
x = 0;
break;
};
for (x = 0; x < sgip->xsize; x ++)
if (row[x] != sgip->arle_row[x])
break;
}
while (x < sgip->xsize);
}
else
{
do
{
sgip->arle_offset = ftell(sgip->file);
if ((sgip->arle_length = read_rle16(sgip->file, sgip->arle_row, sgip->xsize)) < 0)
{
x = 0;
break;
};
for (x = 0; x < sgip->xsize; x ++)
if (row[x] != sgip->arle_row[x])
break;
}
while (x < sgip->xsize);
};
if (x == sgip->xsize)
{
sgip->table[z][y] = sgip->arle_offset;
sgip->length[z][y] = sgip->arle_length;
return (0);
}
else
fseek(sgip->file, 0, SEEK_END); /* Clear EOF */
case SGI_COMP_RLE :
if (sgip->table[z][y] != 0)
return (-1);
offset = sgip->table[z][y] = sgip->nextrow;
if (offset != ftell(sgip->file))
fseek(sgip->file, offset, SEEK_SET);
if (sgip->bpp == 1)
x = write_rle8(sgip->file, row, sgip->xsize);
else
x = write_rle16(sgip->file, row, sgip->xsize);
if (sgip->comp == SGI_COMP_ARLE)
{
sgip->arle_offset = offset;
sgip->arle_length = x;
memcpy(sgip->arle_row, row, sgip->xsize * sizeof(short));
};
sgip->nextrow = ftell(sgip->file);
sgip->length[z][y] = x;
return (x);
};
return (0);
}
/*
* 'getlong()' - Get a 32-bit big-endian integer.
*/
static int
getlong(FILE *fp) /* I - File to read from */
{
unsigned char b[4];
fread(b, 4, 1, fp);
return ((b[0] << 24) | (b[1] << 16) | (b[2] << 8) | b[3]);
}
/*
* 'getshort()' - Get a 16-bit big-endian integer.
*/
static int
getshort(FILE *fp) /* I - File to read from */
{
unsigned char b[2];
fread(b, 2, 1, fp);
return ((b[0] << 8) | b[1]);
}
/*
* 'putlong()' - Put a 32-bit big-endian integer.
*/
static int
putlong(long n, /* I - Long to write */
FILE *fp) /* I - File to write to */
{
if (putc(n >> 24, fp) == EOF)
return (EOF);
if (putc(n >> 16, fp) == EOF)
return (EOF);
if (putc(n >> 8, fp) == EOF)
return (EOF);
if (putc(n, fp) == EOF)
return (EOF);
else
return (0);
}
/*
* 'putshort()' - Put a 16-bit big-endian integer.
*/
static int
putshort(short n, /* I - Short to write */
FILE *fp) /* I - File to write to */
{
if (putc(n >> 8, fp) == EOF)
return (EOF);
if (putc(n, fp) == EOF)
return (EOF);
else
return (0);
}
/*
* 'read_rle8()' - Read 8-bit RLE data.
*/
static int
read_rle8(FILE *fp, /* I - File to read from */
short *row, /* O - Data */
int xsize) /* I - Width of data in pixels */
{
int i, /* Looping var */
ch, /* Current character */
count, /* RLE count */
length; /* Number of bytes read... */
length = 0;
while (xsize > 0)
{
if ((ch = getc(fp)) == EOF)
return (-1);
length ++;
count = ch & 127;
if (count == 0)
break;
if (ch & 128)
{
for (i = 0; i < count; i ++, row ++, xsize --, length ++)
*row = getc(fp);
}
else
{
ch = getc(fp);
length ++;
for (i = 0; i < count; i ++, row ++, xsize --)
*row = ch;
};
};
return (xsize > 0 ? -1 : length);
}
/*
* 'read_rle16()' - Read 16-bit RLE data.
*/
static int
read_rle16(FILE *fp, /* I - File to read from */
short *row, /* O - Data */
int xsize) /* I - Width of data in pixels */
{
int i, /* Looping var */
ch, /* Current character */
count, /* RLE count */
length; /* Number of bytes read... */
length = 0;
while (xsize > 0)
{
if ((ch = getshort(fp)) == EOF)
return (-1);
length ++;
count = ch & 127;
if (count == 0)
break;
if (ch & 128)
{
for (i = 0; i < count; i ++, row ++, xsize --, length ++)
*row = getshort(fp);
}
else
{
ch = getshort(fp);
length ++;
for (i = 0; i < count; i ++, row ++, xsize --)
*row = ch;
};
};
return (xsize > 0 ? -1 : length * 2);
}
/*
* 'write_rle8()' - Write 8-bit RLE data.
*/
static int
write_rle8(FILE *fp, /* I - File to write to */
short *row, /* I - Data */
int xsize) /* I - Width of data in pixels */
{
int length,
count,
i,
x;
short *start,
repeat;
for (x = xsize, length = 0; x > 0;)
{
start = row;
row += 2;
x -= 2;
while (x > 0 && (row[-2] != row[-1] || row[-1] != row[0]))
{
row ++;
x --;
};
row -= 2;
x += 2;
count = row - start;
while (count > 0)
{
i = count > 126 ? 126 : count;
count -= i;
if (putc(128 | i, fp) == EOF)
return (-1);
length ++;
while (i > 0)
{
if (putc(*start, fp) == EOF)
return (-1);
start ++;
i --;
length ++;
};
};
if (x <= 0)
break;
start = row;
repeat = row[0];
row ++;
x --;
while (x > 0 && *row == repeat)
{
row ++;
x --;
};
count = row - start;
while (count > 0)
{
i = count > 126 ? 126 : count;
count -= i;
if (putc(i, fp) == EOF)
return (-1);
length ++;
if (putc(repeat, fp) == EOF)
return (-1);
length ++;
};
};
length ++;
if (putc(0, fp) == EOF)
return (-1);
else
return (length);
}
/*
* 'write_rle16()' - Write 16-bit RLE data.
*/
static int
write_rle16(FILE *fp, /* I - File to write to */
short *row, /* I - Data */
int xsize)/* I - Width of data in pixels */
{
int length,
count,
i,
x;
short *start,
repeat;
for (x = xsize, length = 0; x > 0;)
{
start = row;
row += 2;
x -= 2;
while (x > 0 && (row[-2] != row[-1] || row[-1] != row[0]))
{
row ++;
x --;
};
row -= 2;
x += 2;
count = row - start;
while (count > 0)
{
i = count > 126 ? 126 : count;
count -= i;
if (putshort(128 | i, fp) == EOF)
return (-1);
length ++;
while (i > 0)
{
if (putshort(*start, fp) == EOF)
return (-1);
start ++;
i --;
length ++;
};
};
if (x <= 0)
break;
start = row;
repeat = row[0];
row ++;
x --;
while (x > 0 && *row == repeat)
{
row ++;
x --;
};
count = row - start;
while (count > 0)
{
i = count > 126 ? 126 : count;
count -= i;
if (putshort(i, fp) == EOF)
return (-1);
length ++;
if (putshort(repeat, fp) == EOF)
return (-1);
length ++;
};
};
length ++;
if (putshort(0, fp) == EOF)
return (-1);
else
return (2 * length);
}
/*
* End of "$Id$".
*/

View File

@ -1,991 +0,0 @@
/*
* "$Id$"
*
* Sharpen filters for The GIMP -- an image manipulation program
*
* Copyright 1997 Michael Sweet.
*
* 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
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* Contents:
*
* main() - Main entry - just call gimp_main()...
* query() - Respond to a plug-in query...
* run() - Run the filter...
* sharpen() - Sharpen an image using a median filter.
* sharpen_dialog() - Popup a dialog window for the filter box size...
* preview_init() - Initialize the preview window...
* preview_scroll_callback() - Update the preview when a scrollbar is moved.
* preview_update() - Update the preview window.
* preview_exit() - Free all memory used by the preview window...
* dialog_create_ivalue() - Create an integer value control...
* dialog_iscale_update() - Update the value field using the scale.
* dialog_ientry_update() - Update the value field using the text entry.
* dialog_ok_callback() - Start the filter...
* dialog_cancel_callback() - Cancel the filter...
* dialog_close_callback() - Exit the filter dialog application.
*
* Revision History:
*
* $Log$
* Revision 1.1.1.1 1997/11/24 22:03:37 sopwith
* Let's try this import one last time.
*
* Revision 1.5 1997/10/25 07:02:34 nobody
* Final patches for the 0.99.15 release. Please see the ChangeLog for
* details.
*
* The libgimp/ and app/ directories now compile cleanly. Removed the
* gfig and gimptcl plug-ins from the autoconfiguration process because
* they are not yet properly automake'd.
*
* Revision 1.4 1997/10/15 18:53:41 nobody
* Fixed Makefile.am's (-I$(includedir) added), removed C++ comments
* (ARGH!) in some plug-ins, fixed typos, changed some plug-ins to follow
* the naming convention.
*
* Revision 1.3 1997/09/30 09:16:02 nobody
* work I men it...
*
* Revision 1.4 1997/09/29 17:16:29 mike
* To average 8 numbers you do *not* divide by 9! This caused the brightening
* problem when sharpening was "turned up".
*
* Revision 1.2 1997/06/08 22:27:35 mike
* Updated sharpen code for hard-coded 3x3 convolution matrix.
*
* Revision 1.1 1997/06/08 16:46:07 mike
* Initial revision
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <gtk/gtk.h>
#include <libgimp/gimp.h>
#include <libgimp/gimpui.h>
/*
* Constants...
*/
#define PLUG_IN_NAME "plug_in_sharpen"
#define PLUG_IN_VERSION "1.0.2"
#define PREVIEW_SIZE 128
#define SCALE_WIDTH 64
#define ENTRY_WIDTH 64
/*
* Local functions...
*/
static void query(void);
static void run(char *, int, GParam *, int *, GParam **);
static void sharpen(void);
static gint sharpen_dialog(void);
static void dialog_create_ivalue(char *, GtkTable *, int, gint *, int, int);
static void dialog_iscale_update(GtkAdjustment *, gint *);
static void dialog_ientry_update(GtkWidget *, gint *);
static void dialog_ok_callback(GtkWidget *, gpointer);
static void dialog_cancel_callback(GtkWidget *, gpointer);
static void dialog_close_callback(GtkWidget *, gpointer);
static void preview_init(void);
static void preview_exit(void);
static void preview_update(void);
static void preview_scroll_callback(void);
/*
* Globals...
*/
GPlugInInfo PLUG_IN_INFO =
{
NULL, /* init_proc */
NULL, /* quit_proc */
query, /* query_proc */
run /* run_proc */
};
GtkWidget *preview; /* Preview widget */
int preview_width, /* Width of preview widget */
preview_height, /* Height of preview widget */
preview_x1, /* Upper-left X of preview */
preview_y1, /* Upper-left Y of preview */
preview_x2, /* Lower-right X of preview */
preview_y2; /* Lower-right Y of preview */
guchar *preview_src, /* Source pixel image */
*preview_dst, /* Destination pixel image */
*preview_image; /* Preview RGB image */
GtkObject *hscroll_data, /* Horizontal scrollbar data */
*vscroll_data; /* Vertical scrollbar data */
GDrawable *drawable = NULL; /* Current image */
int sel_x1, /* Selection bounds */
sel_y1,
sel_x2,
sel_y2;
int sel_width, /* Selection width */
sel_height; /* Selection height */
int img_bpp; /* Bytes-per-pixel in image */
int sharpen_percent = 10; /* Percent of sharpening */
gint run_filter = FALSE; /* True if we should run the filter */
/*
* 'main()' - Main entry - just call gimp_main()...
*/
int
main(int argc, /* I - Number of command-line args */
char *argv[]) /* I - Command-line args */
{
return (gimp_main(argc, argv));
}
/*
* 'query()' - Respond to a plug-in query...
*/
static void
query(void)
{
static GParamDef args[] =
{
{ PARAM_INT32, "run_mode", "Interactive, non-interactive" },
{ PARAM_IMAGE, "image", "Input image" },
{ PARAM_DRAWABLE, "drawable", "Input drawable" },
{ PARAM_INT32, "percent", "Percent sharpening (default = 10)" }
};
static GParamDef *return_vals = NULL;
static int nargs = sizeof(args) / sizeof(args[0]),
nreturn_vals = 0;
gimp_install_procedure(PLUG_IN_NAME,
"Sharpen filter, typically used to \'sharpen\' a photographic image.",
"This plug-in selectively performs a convolution filter on an image.",
"Michael Sweet", "Michael Sweet",
PLUG_IN_VERSION, "<Image>/Filters/Image/Sharpen...", "RGB*, GRAY*",
PROC_PLUG_IN, nargs, nreturn_vals, args, return_vals);
}
/*
* 'run()' - Run the filter...
*/
static void
run(char *name, /* I - Name of filter program. */
int nparams, /* I - Number of parameters passed in */
GParam *param, /* I - Parameter values */
int *nreturn_vals, /* O - Number of return values */
GParam **return_vals) /* O - Return values */
{
GRunModeType run_mode; /* Current run mode */
GStatusType status; /* Return status */
static GParam values[1]; /* Return values */
/*
* Initialize parameter data...
*/
status = STATUS_SUCCESS;
run_mode = param[0].data.d_int32;
values[0].type = PARAM_STATUS;
values[0].data.d_status = status;
*nreturn_vals = 1;
*return_vals = values;
/*
* Get drawable information...
*/
drawable = gimp_drawable_get(param[2].data.d_drawable);
gimp_drawable_mask_bounds(drawable->id, &sel_x1, &sel_y1, &sel_x2, &sel_y2);
sel_width = sel_x2 - sel_x1;
sel_height = sel_y2 - sel_y1;
img_bpp = gimp_drawable_bpp(drawable->id);
/*
* See how we will run
*/
switch (run_mode)
{
case RUN_INTERACTIVE :
/*
* Possibly retrieve data...
*/
gimp_get_data(PLUG_IN_NAME, &sharpen_percent);
/*
* Get information from the dialog...
*/
if (!sharpen_dialog())
return;
break;
case RUN_NONINTERACTIVE :
/*
* Make sure all the arguments are present...
*/
if (nparams != 4)
status = STATUS_CALLING_ERROR;
else
sharpen_percent = param[3].data.d_int32;
break;
case RUN_WITH_LAST_VALS :
/*
* Possibly retrieve data...
*/
gimp_get_data(PLUG_IN_NAME, &sharpen_percent);
break;
default :
status = STATUS_CALLING_ERROR;
break;;
};
/*
* Sharpen the image...
*/
if (status == STATUS_SUCCESS)
{
if ((gimp_drawable_color(drawable->id) ||
gimp_drawable_gray(drawable->id)))
{
/*
* Set the tile cache size...
*/
gimp_tile_cache_ntiles((drawable->width + gimp_tile_width() - 1) /
gimp_tile_width());
/*
* Run!
*/
sharpen();
/*
* If run mode is interactive, flush displays...
*/
if (run_mode != RUN_NONINTERACTIVE)
gimp_displays_flush();
/*
* Store data...
*/
if (run_mode == RUN_INTERACTIVE)
gimp_set_data(PLUG_IN_NAME, &sharpen_percent, sizeof(sharpen_percent));
}
else
status = STATUS_EXECUTION_ERROR;
};
/*
* Reset the current run status...
*/
values[0].data.d_status = status;
/*
* Detach from the drawable...
*/
gimp_drawable_detach(drawable);
}
/*
* 'sharpen()' - Sharpen an image using a convolution filter.
*/
static void
sharpen(void)
{
GPixelRgn src_rgn, /* Source image region */
dst_rgn; /* Destination image region */
guchar *src_rows[4], /* Source pixel rows */
*dst_row, /* Destination pixel row */
*dst_ptr, /* Current destination pixel */
*src_filters[3];/* Source pixels, ordered for filter */
int i, j, t, d, /* Looping vars */
x, y, /* Current location in image */
xmax, /* Maximum filtered X coordinate */
row, /* Current row in src_rows */
trow, /* Looping var */
count, /* Current number of filled src_rows */
width; /* Byte width of the image */
int fact; /* Scaling for convolution matrix */
/*
* Let the user know what we're doing...
*/
gimp_progress_init("Sharpening...");
/*
* Setup for filter...
*/
gimp_pixel_rgn_init(&src_rgn, drawable, sel_x1, sel_y1, sel_width, sel_height, FALSE, FALSE);
gimp_pixel_rgn_init(&dst_rgn, drawable, sel_x1, sel_y1, sel_width, sel_height, TRUE, TRUE);
fact = 100 - sharpen_percent;
if (fact < 1)
fact = 1;
width = sel_width * img_bpp;
xmax = width - img_bpp;
for (row = 0; row < 4; row ++)
src_rows[row] = g_malloc(width * sizeof(guchar));
dst_row = g_malloc(width * sizeof(guchar));
/*
* Pre-load the first row for the filter...
*/
gimp_pixel_rgn_get_row(&src_rgn, src_rows[0], sel_x1, sel_y1, sel_width);
row = 1;
count = 1;
/*
* Sharpen...
*/
for (y = sel_y1; y < sel_y2; y ++)
{
/*
* Load the next pixel row...
*/
if ((y + 1) < sel_y2)
{
/*
* Check to see if our src_rows[] array is overflowing yet...
*/
if (count >= 3)
count --;
/*
* Grab the next row...
*/
gimp_pixel_rgn_get_row(&src_rgn, src_rows[row], sel_x1, y + 1, sel_width);
count ++;
row = (row + 1) & 3;
}
else
{
/*
* No more pixels at the bottom... Drop the oldest samples...
*/
count --;
};
/*
* Now sharpen pixels and save the results...
*/
if (count == 3)
{
for (i = 0, trow = (row + 1) & 3;
i < 3;
i ++, trow = (trow + 1) & 3)
src_filters[i] = src_rows[trow];
for (x = img_bpp, dst_ptr = dst_row + img_bpp;
x < xmax;
x ++, dst_ptr ++)
{
i = (100 * src_filters[1][x] -
(src_filters[0][x - img_bpp] + src_filters[0][x] +
src_filters[0][x + img_bpp] + src_filters[1][x - img_bpp] +
src_filters[1][x + img_bpp] + src_filters[2][x - img_bpp] +
src_filters[2][x] + src_filters[2][x + img_bpp]) *
sharpen_percent / 8) / fact;
if (i < 0)
*dst_ptr = 0;
else if (i > 255)
*dst_ptr = 255;
else
*dst_ptr = i;
};
gimp_pixel_rgn_set_row(&dst_rgn, dst_row + img_bpp, sel_x1 + 1, y, sel_width - 2);
};
if ((y & 15) == 0)
gimp_progress_update((double)(y - sel_y1) / (double)sel_height);
};
/*
* OK, we're done. Free all memory used...
*/
for (row = 0; row < 4; row ++)
g_free(src_rows[row]);
g_free(dst_row);
/*
* Update the screen...
*/
gimp_drawable_flush(drawable);
gimp_drawable_merge_shadow(drawable->id, TRUE);
gimp_drawable_update(drawable->id, sel_x1, sel_y1, sel_width, sel_height);
}
/*
* 'sharpen_dialog()' - Popup a dialog window for the filter box size...
*/
static gint
sharpen_dialog(void)
{
GtkWidget *dialog, /* Dialog window */
*table, /* Table "container" for controls */
*ptable, /* Preview table */
*frame, /* Frame for preview */
*scrollbar, /* Horizontal + vertical scroller */
*button; /* OK/Cancel buttons */
gint argc; /* Fake argc for GUI */
gchar **argv; /* Fake argv for GUI */
guchar *color_cube; /* Preview color cube... */
/*
* Initialize the program's display...
*/
argc = 1;
argv = g_new(gchar *, 1);
argv[0] = g_strdup("sharpen");
gtk_init(&argc, &argv);
gtk_rc_parse(gimp_gtkrc());
gdk_set_use_xshm(gimp_use_xshm());
gtk_preview_set_gamma(gimp_gamma());
gtk_preview_set_install_cmap(gimp_install_cmap());
color_cube = gimp_color_cube();
gtk_preview_set_color_cube(color_cube[0], color_cube[1], color_cube[2], color_cube[3]);
gtk_widget_set_default_visual(gtk_preview_get_visual());
gtk_widget_set_default_colormap(gtk_preview_get_cmap());
/*
* Dialog window...
*/
dialog = gtk_dialog_new();
gtk_window_set_title(GTK_WINDOW(dialog), "Sharpen");
gtk_window_position(GTK_WINDOW(dialog), GTK_WIN_POS_MOUSE);
gtk_container_border_width(GTK_CONTAINER(dialog), 0);
gtk_signal_connect(GTK_OBJECT(dialog), "destroy",
(GtkSignalFunc) dialog_close_callback,
NULL);
/*
* Top-level table for dialog...
*/
table = gtk_table_new(3, 3, FALSE);
gtk_container_border_width(GTK_CONTAINER(table), 6);
gtk_table_set_row_spacings(GTK_TABLE(table), 4);
gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), table, FALSE, FALSE, 0);
gtk_widget_show(table);
/*
* Preview window...
*/
ptable = gtk_table_new(2, 2, FALSE);
gtk_container_border_width(GTK_CONTAINER(ptable), 0);
gtk_table_attach(GTK_TABLE(table), ptable, 0, 3, 0, 1, 0, 0, 0, 0);
gtk_widget_show(ptable);
frame = gtk_frame_new(NULL);
gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_IN);
gtk_table_attach(GTK_TABLE(ptable), frame, 0, 1, 0, 1, 0, 0, 0, 0);
gtk_widget_show(frame);
preview_width = MIN(sel_width, PREVIEW_SIZE);
preview_height = MIN(sel_height, PREVIEW_SIZE);
preview = gtk_preview_new(GTK_PREVIEW_COLOR);
gtk_preview_size(GTK_PREVIEW(preview), preview_width, preview_height);
gtk_container_add(GTK_CONTAINER(frame), preview);
gtk_widget_show(preview);
hscroll_data = gtk_adjustment_new(0, 0, sel_width - 1, 1.0,
MIN(preview_width, sel_width),
MIN(preview_width, sel_width));
gtk_signal_connect(hscroll_data, "value_changed",
(GtkSignalFunc)preview_scroll_callback, NULL);
scrollbar = gtk_hscrollbar_new(GTK_ADJUSTMENT(hscroll_data));
gtk_range_set_update_policy(GTK_RANGE(scrollbar), GTK_UPDATE_CONTINUOUS);
gtk_table_attach(GTK_TABLE(ptable), scrollbar, 0, 1, 1, 2, GTK_FILL, 0, 0, 0);
gtk_widget_show(scrollbar);
vscroll_data = gtk_adjustment_new(0, 0, sel_height - 1, 1.0,
MIN(preview_height, sel_height),
MIN(preview_height, sel_height));
gtk_signal_connect(vscroll_data, "value_changed",
(GtkSignalFunc)preview_scroll_callback, NULL);
scrollbar = gtk_vscrollbar_new(GTK_ADJUSTMENT(vscroll_data));
gtk_range_set_update_policy(GTK_RANGE(scrollbar), GTK_UPDATE_CONTINUOUS);
gtk_table_attach(GTK_TABLE(ptable), scrollbar, 1, 2, 0, 1, 0, GTK_FILL, 0, 0);
gtk_widget_show(scrollbar);
preview_init();
/*
* Sharpness control...
*/
dialog_create_ivalue("Sharpness", GTK_TABLE(table), 2, &sharpen_percent, 1, 99);
/*
* OK, cancel buttons...
*/
gtk_container_border_width(GTK_CONTAINER(GTK_DIALOG(dialog)->action_area), 6);
button = gtk_button_new_with_label("OK");
GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT);
gtk_signal_connect(GTK_OBJECT(button), "clicked",
(GtkSignalFunc) dialog_ok_callback,
dialog);
gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->action_area), button, TRUE, TRUE, 0);
gtk_widget_grab_default(button);
gtk_widget_show(button);
button = gtk_button_new_with_label("Cancel");
GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT);
gtk_signal_connect(GTK_OBJECT(button), "clicked",
(GtkSignalFunc) dialog_cancel_callback,
dialog);
gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->action_area), button, TRUE, TRUE, 0);
gtk_widget_show(button);
/*
* Show it and wait for the user to do something...
*/
gtk_widget_show(dialog);
preview_update();
gtk_main();
gdk_flush();
/*
* Free the preview data...
*/
preview_exit();
/*
* Return ok/cancel...
*/
return (run_filter);
}
/*
* 'preview_init()' - Initialize the preview window...
*/
static void
preview_init(void)
{
int row, /* Current row in preview_srcs */
width; /* Byte width of the image */
/*
* Setup for preview filter...
*/
width = preview_width * img_bpp;
preview_src = g_malloc(width * preview_height * sizeof(guchar));
preview_dst = g_malloc(width * preview_height * sizeof(guchar));
preview_image = g_malloc(preview_width * preview_height * 3 * sizeof(guchar));
preview_x1 = sel_x1;
preview_y1 = sel_y1;
preview_x2 = preview_x1 + preview_width;
preview_y2 = preview_y1 + preview_height;
}
/*
* 'preview_scroll_callback()' - Update the preview when a scrollbar is moved.
*/
static void
preview_scroll_callback(void)
{
preview_x1 = sel_x1 + GTK_ADJUSTMENT(hscroll_data)->value;
preview_y1 = sel_y1 + GTK_ADJUSTMENT(vscroll_data)->value;
preview_x2 = preview_x1 + MIN(preview_width, sel_width);
preview_y2 = preview_y1 + MIN(preview_height, sel_height);
preview_update();
}
/*
* 'preview_update()' - Update the preview window.
*/
static void
preview_update(void)
{
GPixelRgn src_rgn; /* Source image region */
guchar *src_ptr, /* Current source pixel */
*dst_ptr, /* Current destination pixel */
*image_ptr; /* Current image pixel */
int i, j, t, d, /* Looping vars */
x, y, /* Current location in image */
xmax, /* Maximum X coordinate */
width, /* Byte width of the image */
fact; /* Scaling for convolution matrix */
/*
* Setup for filter...
*/
gimp_pixel_rgn_init(&src_rgn, drawable, preview_x1, preview_y1, preview_width, preview_height, FALSE, FALSE);
fact = 100 - sharpen_percent;
if (fact < 1)
fact = 1;
width = preview_width * img_bpp;
xmax = width - img_bpp;
/*
* Pre-load the first row for the filter...
*/
gimp_pixel_rgn_get_rect(&src_rgn, preview_src, preview_x1, preview_y1,
preview_width, preview_height);
/*
* Sharpen...
*/
memcpy(preview_dst, preview_src, width);
memcpy(preview_dst + width * (preview_height - 1),
preview_src + width * (preview_height - 1),
width);
for (y = 1, src_ptr = preview_src + width, dst_ptr = preview_dst + width;
y < (preview_height - 1);
y ++, src_ptr += width, dst_ptr += width)
{
/*
* Now sharpen pixels and save the results...
*/
memcpy(dst_ptr, src_ptr, img_bpp);
memcpy(dst_ptr + width - img_bpp, src_ptr + width - img_bpp, img_bpp);
for (x = img_bpp; x < xmax; x ++)
{
i = (100 * src_ptr[x] -
(src_ptr[x - width - img_bpp] + src_ptr[x - width] +
src_ptr[x - width + img_bpp] + src_ptr[x - img_bpp] +
src_ptr[x + img_bpp] + src_ptr[x + width - img_bpp] +
src_ptr[x + width] + src_ptr[x + width + img_bpp]) *
sharpen_percent / 8) / fact;
if (i < 0)
dst_ptr[x] = 0;
else if (i > 255)
dst_ptr[x] = 255;
else
dst_ptr[x] = i;
};
};
/*
* Draw the preview image...
*/
switch (img_bpp)
{
case 1 :
case 2 :
for (x = preview_width * preview_height, dst_ptr = preview_dst,
image_ptr = preview_image;
x > 0;
x --, dst_ptr += img_bpp, image_ptr += 3)
image_ptr[0] = image_ptr[1] = image_ptr[2] = *dst_ptr;
for (y = 0, image_ptr = preview_image;
y < preview_height;
y ++, image_ptr += preview_width * 3)
gtk_preview_draw_row(GTK_PREVIEW(preview), image_ptr, 0, y,
preview_width);
break;
case 3 :
for (y = 0, image_ptr = preview_dst;
y < preview_height;
y ++, image_ptr += preview_width * 3)
gtk_preview_draw_row(GTK_PREVIEW(preview), image_ptr, 0, y,
preview_width);
break;
case 4 :
for (x = 0, dst_ptr = preview_dst, image_ptr = preview_image;
x < preview_width;
x ++, dst_ptr += 4, image_ptr += 3)
{
image_ptr[0] = dst_ptr[0];
image_ptr[1] = dst_ptr[1];
image_ptr[2] = dst_ptr[2];
};
for (y = 0, image_ptr = preview_image;
y < preview_height;
y ++, image_ptr += preview_width * 3)
gtk_preview_draw_row(GTK_PREVIEW(preview), image_ptr, 0, y,
preview_width);
break;
};
gtk_widget_draw(preview, NULL);
gdk_flush();
}
/*
* 'preview_exit()' - Free all memory used by the preview window...
*/
static void
preview_exit(void)
{
int row; /* Looping var */
g_free(preview_src);
g_free(preview_dst);
g_free(preview_image);
}
/*
* 'dialog_create_ivalue()' - Create an integer value control...
*/
static void
dialog_create_ivalue(char *title, /* I - Label for control */
GtkTable *table, /* I - Table container to use */
int row, /* I - Row # for container */
gint *value, /* I - Value holder */
int left, /* I - Minimum value for slider */
int right) /* I - Maximum value for slider */
{
GtkWidget *label, /* Control label */
*scale, /* Scale widget */
*entry; /* Text widget */
GtkObject *scale_data; /* Scale data */
char buf[256]; /* String buffer */
/*
* Label...
*/
label = gtk_label_new(title);
gtk_misc_set_alignment(GTK_MISC(label), 0.0, 1.0);
gtk_table_attach(table, label, 0, 1, row, row + 1, GTK_FILL, GTK_FILL, 4, 0);
gtk_widget_show(label);
/*
* Scale...
*/
scale_data = gtk_adjustment_new(*value, left, right, 1.0, 1.0, 1.0);
gtk_signal_connect(GTK_OBJECT(scale_data), "value_changed",
(GtkSignalFunc) dialog_iscale_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_range_set_update_policy(GTK_RANGE(scale), GTK_UPDATE_CONTINUOUS);
gtk_widget_show(scale);
/*
* Text entry...
*/
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, "%d", *value);
gtk_entry_set_text(GTK_ENTRY(entry), buf);
gtk_signal_connect(GTK_OBJECT(entry), "changed",
(GtkSignalFunc) dialog_ientry_update,
value);
gtk_table_attach(GTK_TABLE(table), entry, 2, 3, row, row + 1, GTK_FILL, GTK_FILL, 4, 0);
gtk_widget_show(entry);
}
/*
* 'dialog_iscale_update()' - Update the value field using the scale.
*/
static void
dialog_iscale_update(GtkAdjustment *adjustment, /* I - New value */
gint *value) /* I - Current value */
{
GtkWidget *entry; /* Text entry widget */
char buf[256]; /* Text buffer */
if (*value != adjustment->value)
{
*value = adjustment->value;
entry = gtk_object_get_user_data(GTK_OBJECT(adjustment));
sprintf(buf, "%d", *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);
preview_update();
};
}
/*
* 'dialog_ientry_update()' - Update the value field using the text entry.
*/
static void
dialog_ientry_update(GtkWidget *widget, /* I - Entry widget */
gint *value) /* I - Current value */
{
GtkAdjustment *adjustment;
gint new_value;
new_value = atoi(gtk_entry_get_text(GTK_ENTRY(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");
preview_update();
};
};
}
/*
* 'dialog_ok_callback()' - Start the filter...
*/
static void
dialog_ok_callback(GtkWidget *widget, /* I - OK button widget */
gpointer data) /* I - Dialog window */
{
run_filter = TRUE;
gtk_widget_destroy(GTK_WIDGET(data));
}
/*
* 'dialog_cancel_callback()' - Cancel the filter...
*/
static void
dialog_cancel_callback(GtkWidget *widget, /* I - Cancel button widget */
gpointer data) /* I - Dialog window */
{
gtk_widget_destroy(GTK_WIDGET(data));
}
/*
* 'dialog_close_callback()' - Exit the filter dialog application.
*/
static void
dialog_close_callback(GtkWidget *widget, /* I - Dialog window */
gpointer data) /* I - Dialog window */
{
gtk_main_quit();
}
/*
* End of "$Id$".
*/

View File

@ -1,603 +0,0 @@
/* Shift --- image filter plug-in for The Gimp image manipulation program
* Copyright (C) 1997 Brian Degenhardt and 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
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* Please direct all comments, questions, bug reports etc to Brian Degenhardt
* bdegenha@ucsd.edu
*
* You can contact Federico Mena Quintero at quartic@polloux.fciencias.unam.mx
* You can contact the original The Gimp authors at gimp@xcf.berkeley.edu
*/
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "gtk/gtk.h"
#include "libgimp/gimp.h"
/* Some useful macros */
#define SCALE_WIDTH 200
#define TILE_CACHE_SIZE 16
#define HORIZONTAL 0
#define VERTICAL 1
#define ENTRY_WIDTH 35
typedef struct {
gint shift_amount;
gint orientation;
} ShiftValues;
typedef struct {
gint run;
} ShiftInterface;
/* Declare local functions.
*/
static void query (void);
static void run (gchar *name,
gint nparams,
GParam *param,
gint *nreturn_vals,
GParam **return_vals);
static void shift (GDrawable * drawable);
static gint shift_dialog (void);
static GTile * shift_pixel (GDrawable * drawable,
GTile * tile,
gint x1,
gint y1,
gint x2,
gint y2,
gint x,
gint y,
gint * row,
gint * col,
guchar * pixel);
static void shift_close_callback (GtkWidget *widget,
gpointer data);
static void shift_ok_callback (GtkWidget *widget,
gpointer data);
static void shift_toggle_update (GtkWidget *widget,
gpointer data);
static void shift_ientry_callback (GtkWidget *widget,
gpointer data);
static void shift_iscale_callback (GtkAdjustment *adjustment,
gpointer data);
/***** Local vars *****/
GPlugInInfo PLUG_IN_INFO =
{
NULL, /* init_proc */
NULL, /* quit_proc */
query, /* query_proc */
run, /* run_proc */
};
static ShiftValues shvals =
{
5, /* shift amount */
HORIZONTAL
};
static ShiftInterface shint =
{
FALSE /* run */
};
/***** Functions *****/
MAIN ()
static void
query ()
{
static GParamDef args[] =
{
{ PARAM_INT32, "run_mode", "Interactive, non-interactive" },
{ PARAM_IMAGE, "image", "Input image (unused)" },
{ PARAM_DRAWABLE, "drawable", "Input drawable" },
{ PARAM_INT32, "shift_amount", "shift amount (0 <= shift_amount_x <= 200)" },
{ PARAM_INT32, "orientation", "vertical, horizontal orientation" },
};
static GParamDef *return_vals = NULL;
static gint nargs = sizeof (args) / sizeof (args[0]);
static gint nreturn_vals = 0;
gimp_install_procedure ("plug_in_shift",
"Shift the contents of the specified drawable",
"Shifts the pixels of the specified drawable. Each row will be displaced a random value of pixels.",
"Spencer Kimball and Peter Mattis, ported by Brian Degenhardt and Federico Mena Quintero",
"Brian Degenhardt",
"1997",
"<Image>/Filters/Distorts/Shift",
"RGB*, GRAY*",
PROC_PLUG_IN,
nargs, nreturn_vals,
args, return_vals);
}
static void
run (gchar *name,
gint nparams,
GParam *param,
gint *nreturn_vals,
GParam **return_vals)
{
static GParam values[1];
GDrawable *drawable;
GRunModeType run_mode;
GStatusType status = STATUS_SUCCESS;
run_mode = param[0].data.d_int32;
/* Get the specified drawable */
drawable = gimp_drawable_get (param[2].data.d_drawable);
*nreturn_vals = 1;
*return_vals = values;
values[0].type = PARAM_STATUS;
values[0].data.d_status = status;
switch (run_mode)
{
case RUN_INTERACTIVE:
/* Possibly retrieve data */
gimp_get_data ("plug_in_shift", &shvals);
/* First acquire information with a dialog */
if (! shift_dialog ())
return;
break;
case RUN_NONINTERACTIVE:
/* Make sure all the arguments are there! */
if (nparams != 5)
status = STATUS_CALLING_ERROR;
if (status == STATUS_SUCCESS)
{
shvals.shift_amount = param[3].data.d_int32;
shvals.orientation = (param[4].data.d_int32) ? HORIZONTAL : VERTICAL;
}
if ((status == STATUS_SUCCESS) &&
(shvals.shift_amount < 0 || shvals.shift_amount > 200))
status = STATUS_CALLING_ERROR;
break;
case RUN_WITH_LAST_VALS:
/* Possibly retrieve data */
gimp_get_data ("plug_in_shift", &shvals);
break;
default:
break;
}
if (status == STATUS_SUCCESS)
{
/* Make sure that the drawable is gray or RGB color */
if (gimp_drawable_color (drawable->id) || gimp_drawable_gray (drawable->id))
{
gimp_progress_init ("Shifting...");
/* set the tile cache size */
gimp_tile_cache_ntiles (TILE_CACHE_SIZE);
/* run the shift effect */
shift (drawable);
if (run_mode != RUN_NONINTERACTIVE)
gimp_displays_flush ();
/* Store data */
if (run_mode == RUN_INTERACTIVE)
gimp_set_data ("plug_in_shift", &shvals, sizeof (ShiftValues));
}
else
{
/* gimp_message ("shift: cannot operate on indexed color images"); */
status = STATUS_EXECUTION_ERROR;
}
}
values[0].data.d_status = status;
gimp_drawable_detach (drawable);
}
/*****/
static void
shift (GDrawable *drawable)
{
GPixelRgn dest_rgn;
GTile * tile = NULL;
gint row = -1;
gint col = -1;
gpointer pr;
gint width, height;
gint bytes;
guchar *destline;
guchar *dest;
guchar *otherdest;
guchar pixel[4][4];
gint x1, y1, x2, y2;
gint x, y;
gint progress, max_progress;
gint seed;
gint amount;
gint xdist, ydist;
gint xi, yi;
gint k;
gint mod_value, sub_value;
/* Get selection area */
gimp_drawable_mask_bounds (drawable->id, &x1, &y1, &x2, &y2);
width = drawable->width;
height = drawable->height;
bytes = drawable->bpp;
progress = 0;
max_progress = (x2 - x1) * (y2 - y1);
amount = shvals.shift_amount;
/* Initialize random stuff */
mod_value = amount + 1;
sub_value = mod_value / 2;
seed = time(NULL);
/* Shift the image. It's a pretty simple algorithm. If horizontal
is selected, then every row is shifted a random number of pixels
in the range of -shift_amount/2 to shift_amount/2. The effect is
just reproduced with columns if vertical is selected. Vertical
has been added since 0.54 so that the user doesn't have to rotate
the image to do a vertical shift.
*/
gimp_pixel_rgn_init (&dest_rgn, drawable, x1, y1, (x2 - x1), (y2 - y1), TRUE, TRUE);
for (pr = gimp_pixel_rgns_register (1, &dest_rgn); pr != NULL; pr = gimp_pixel_rgns_process (pr))
{
if (shvals.orientation == VERTICAL)
{
destline = dest_rgn.data;
srand(seed+dest_rgn.x);
for (x = dest_rgn.x; x < (dest_rgn.x + dest_rgn.w); x++)
{
dest = destline;
ydist = (rand() % mod_value) - sub_value;
for (y = dest_rgn.y; y < (dest_rgn.y + dest_rgn.h); y++)
{
otherdest = dest;
yi = (y + ydist + height)%height; /* add width before % because % isn't a true modulo */
tile = shift_pixel (drawable, tile, x1, y1, x2, y2, x, yi, &row, &col, pixel[0]);
for (k = 0; k < bytes; k++)
*otherdest++ = pixel[0][k];
dest += dest_rgn.rowstride;
} /* for */
for (k = 0; k < bytes; k++)
destline++;
} /* for */
progress += dest_rgn.w * dest_rgn.h;
gimp_progress_update ((double) progress / (double) max_progress);
}
else
{
destline = dest_rgn.data;
srand(seed+dest_rgn.y);
for (y = dest_rgn.y; y < (dest_rgn.y + dest_rgn.h); y++)
{
dest = destline;
xdist = (rand() % mod_value) - sub_value;
for (x = dest_rgn.x; x < (dest_rgn.x + dest_rgn.w); x++)
{
xi = (x + xdist + width)%width; /* add width before % because % isn't a true modulo */
tile = shift_pixel (drawable, tile, x1, y1, x2, y2, xi, y, &row, &col, pixel[0]);
for (k = 0; k < bytes; k++)
*dest++ = pixel[0][k];
} /* for */
destline += dest_rgn.rowstride;
} /* for */
progress += dest_rgn.w * dest_rgn.h;
gimp_progress_update ((double) progress / (double) max_progress);
}
} /* for */
if (tile)
gimp_tile_unref (tile, FALSE);
/* update the region */
gimp_drawable_flush (drawable);
gimp_drawable_merge_shadow (drawable->id, TRUE);
gimp_drawable_update (drawable->id, x1, y1, (x2 - x1), (y2 - y1));
} /* shift */
static gint
shift_dialog ()
{
GtkWidget *amount_label;
GtkWidget *amount;
GtkWidget *dlg;
GtkWidget *button;
GtkWidget *toggle;
GtkWidget *frame;
GtkWidget *vbox;
GtkWidget *hbox;
GtkWidget *entry;
GtkObject *amount_data;
GSList *group = NULL;
gchar **argv;
gchar buffer[32];
gint argc;
gint do_horizontal = (shvals.orientation == HORIZONTAL);
gint do_vertical = (shvals.orientation == VERTICAL);
argc = 1;
argv = g_new (gchar *, 1);
argv[0] = g_strdup ("shift");
gtk_init (&argc, &argv);
gtk_rc_parse (gimp_gtkrc ());
dlg = gtk_dialog_new ();
gtk_window_set_title (GTK_WINDOW (dlg), "Shift");
gtk_window_position (GTK_WINDOW (dlg), GTK_WIN_POS_MOUSE);
gtk_signal_connect (GTK_OBJECT (dlg), "destroy",
(GtkSignalFunc) shift_close_callback,
NULL);
/* Action area */
button = gtk_button_new_with_label ("OK");
GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
gtk_signal_connect (GTK_OBJECT (button), "clicked",
(GtkSignalFunc) shift_ok_callback,
dlg);
gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dlg)->action_area), button, TRUE, TRUE, 0);
gtk_widget_grab_default (button);
gtk_widget_show (button);
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));
gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dlg)->action_area), button, TRUE, TRUE, 0);
gtk_widget_show (button);
/* parameter settings */
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);
vbox = gtk_vbox_new (FALSE, 5);
gtk_container_border_width (GTK_CONTAINER (vbox), 10);
gtk_container_add (GTK_CONTAINER (frame), vbox);
toggle = gtk_radio_button_new_with_label (group, "Shift Horizontally");
group = gtk_radio_button_group (GTK_RADIO_BUTTON (toggle));
gtk_box_pack_start (GTK_BOX (vbox), toggle, TRUE, TRUE, 0);
gtk_signal_connect (GTK_OBJECT (toggle), "toggled",
(GtkSignalFunc) shift_toggle_update,
&do_horizontal);
gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (toggle), do_horizontal);
gtk_widget_show (toggle);
toggle = gtk_radio_button_new_with_label (group, "Shift Vertically");
group = gtk_radio_button_group (GTK_RADIO_BUTTON (toggle));
gtk_box_pack_start (GTK_BOX (vbox), toggle, TRUE, TRUE, 0);
gtk_signal_connect (GTK_OBJECT (toggle), "toggled",
(GtkSignalFunc) shift_toggle_update,
&do_vertical);
gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (toggle), do_vertical);
gtk_widget_show (toggle);
hbox = gtk_hbox_new (FALSE, 5);
gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, TRUE, 0);
amount_label = gtk_label_new ("Shift Amount:");
gtk_misc_set_alignment (GTK_MISC (amount_label), 0.0, 0.5);
gtk_box_pack_start (GTK_BOX (hbox), amount_label, TRUE, TRUE, 0);
gtk_widget_show (amount_label);
gtk_widget_show (hbox);
amount_data = gtk_adjustment_new (shvals.shift_amount, 0, 200, 1, 1, 0.0);
gtk_signal_connect (GTK_OBJECT (amount_data), "value_changed",
(GtkSignalFunc) shift_iscale_callback,
&shvals.shift_amount);
amount = gtk_hscale_new (GTK_ADJUSTMENT (amount_data));
gtk_widget_set_usize (amount, SCALE_WIDTH, 0);
gtk_scale_set_digits (GTK_SCALE (amount), 0);
gtk_scale_set_draw_value (GTK_SCALE (amount), FALSE);
gtk_box_pack_start (GTK_BOX (hbox), amount, TRUE, TRUE, 0);
gtk_widget_show (amount);
entry = gtk_entry_new ();
gtk_object_set_user_data (GTK_OBJECT (entry), amount_data);
gtk_object_set_user_data (amount_data, entry);
gtk_box_pack_start (GTK_BOX (hbox), entry, FALSE, TRUE, 0);
gtk_widget_set_usize (entry, ENTRY_WIDTH, 0);
sprintf (buffer, "%d", shvals.shift_amount);
gtk_entry_set_text (GTK_ENTRY (entry), buffer);
gtk_signal_connect (GTK_OBJECT (entry), "changed",
(GtkSignalFunc) shift_ientry_callback,
&shvals.shift_amount);
gtk_widget_show (entry);
gtk_widget_show (vbox);
gtk_widget_show (frame);
gtk_widget_show (dlg);
gtk_main ();
gdk_flush ();
if (do_horizontal)
shvals.orientation = HORIZONTAL;
else
shvals.orientation = VERTICAL;
return shint.run;
}
/*****/
static GTile *
shift_pixel (GDrawable * drawable,
GTile * tile,
gint x1,
gint y1,
gint x2,
gint y2,
gint x,
gint y,
gint * row,
gint * col,
guchar * pixel)
{
static guchar empty_pixel[4] = {0, 0, 0, 0};
guchar *data;
gint b;
if (x >= x1 && y >= y1 && x < x2 && y < y2)
{
if ((x >> 6 != *col) || (y >> 6 != *row))
{
*col = x / 64;
*row = y / 64;
if (tile)
gimp_tile_unref (tile, FALSE);
tile = gimp_drawable_get_tile (drawable, FALSE, *row, *col);
gimp_tile_ref (tile);
}
data = tile->data + tile->bpp * (tile->ewidth * (y % 64) + (x % 64));
}
else
data = empty_pixel;
for (b = 0; b < drawable->bpp; b++)
pixel[b] = data[b];
return tile;
}
/* Shift interface functions */
static void
shift_close_callback (GtkWidget *widget,
gpointer data)
{
gtk_main_quit ();
}
static void
shift_ok_callback (GtkWidget *widget,
gpointer data)
{
shint.run = TRUE;
gtk_widget_destroy (GTK_WIDGET (data));
}
static void
shift_toggle_update (GtkWidget *widget,
gpointer data)
{
int *toggle_val;
toggle_val = (int *) data;
if (GTK_TOGGLE_BUTTON (widget)->active)
*toggle_val = TRUE;
else
*toggle_val = FALSE;
}
static void
shift_ientry_callback (GtkWidget *widget,
gpointer data)
{
GtkAdjustment *adjustment;
int new_val;
int *val;
val = data;
new_val = atoi (gtk_entry_get_text (GTK_ENTRY (widget)));
if (*val != new_val)
{
adjustment = gtk_object_get_user_data (GTK_OBJECT (widget));
if ((new_val >= adjustment->lower) &&
(new_val <= adjustment->upper))
{
*val = new_val;
adjustment->value = new_val;
gtk_signal_emit_by_name (GTK_OBJECT (adjustment), "value_change");
}
}
}
static void
shift_iscale_callback (GtkAdjustment *adjustment,
gpointer data)
{
GtkWidget *entry;
gchar buffer[32];
int *val;
val = data;
if (*val != (int) adjustment->value)
{
*val = adjustment->value;
entry = gtk_object_get_user_data (GTK_OBJECT (adjustment));
sprintf (buffer, "%d", (int) adjustment->value);
gtk_entry_set_text (GTK_ENTRY (entry), buffer);
}
}

View File

@ -1,775 +0,0 @@
/*
* This is a plugin for the GIMP.
*
* Copyright (C) 1997 Xavier Bouchoux
*
* 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
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
/*
* This plug-in produces sinus textures.
*
* Please send any patches or suggestions to me: Xavier.Bouchoux@ensimag.imag.fr.
*/
/* Version 0.99 */
#define USE_LOGO
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <gdk/gdk.h>
#include <gtk/gtk.h>
#include <libgimp/gimp.h>
#include "megawidget.h"
#ifdef USE_LOGO
#include "sinus_logo.h"
#endif
#ifdef __GNUC__
#define inline inline
#else
#define inline
#endif
#define ROUND_TO_INT(val) ((val) + 0.5)
typedef gdouble colRGBA[4];
/*
* This structure is used for persistent data.
*/
#define B_W 0 /* colors setting */
#define USE_FG_BG 1
#define USE_COLORS 2
#define LINEAR 0 /* colorization settings */
#define BILINEAR 1
#define SINUS 2
#define IDEAL 0 /* Perturbation settings */
#define PERTURBED 1
typedef struct {
gdouble scalex, scaley;
gdouble cmplx;
gdouble blend_power;
gint seed;
gint tiling;
gint perturbation;
gint colorization;
gint colors;
colRGBA col1,col2;
} SinusVals;
static SinusVals svals={15.0, 15.0, 1.0, 0.0, 42, TRUE, PERTURBED, LINEAR, USE_COLORS, {1,1,0,1}, {0,0,1,1}};
typedef struct {
gint height, width;
double c11,c12,c13, c21,c22,c23, c31,c32,c33;
double (*blend) (double );
guchar r,g,b,a;
int dr,dg,db,da;
} params;
static gint drawable_is_grayscale= FALSE;
static struct mwPreview *thePreview;
static GDrawable *drawable;
/* Declare functions */
static void query ();
static void run (gchar *name,
gint nparams,
GParam *param,
gint *nreturn_vals,
GParam **return_vals);
static void sinus();
double frac( double v );
double linear (double v);
double bilinear(double v);
double cosinus(double v);
int sinus_dialog(void);
void sinus_do_preview(GtkWidget *w);
void DrawPreviewImage(gint DoCompute);
inline void compute_block_4(guchar *dest_row, guint rowstride,gint x0,gint y0,gint h,gint w, params *p);
inline void compute_block_3(guchar *dest_row, guint rowstride,gint x0,gint y0,gint h,gint w, params *p) ;
inline void compute_block_2(guchar *dest_row, guint rowstride,gint x0,gint y0,gint h,gint w, params *p) ;
inline void compute_block_1(guchar *dest_row, guint rowstride,gint x0,gint y0,gint h,gint w, params *p) ;
GPlugInInfo PLUG_IN_INFO =
{
NULL, /* init_proc */
NULL, /* quit_proc */
query, /* query_proc */
run, /* run_proc */
};
MAIN ()
static void query ()
{
static GParamDef args[] =
{
{ PARAM_INT32, "run_mode", "Interactive, non-interactive" },
{ PARAM_IMAGE, "image", "Input image (unused)" },
{ PARAM_DRAWABLE, "drawable", "Input drawable" },
{ PARAM_FLOAT, "xscale", "Scale value for x axis" },
{ PARAM_FLOAT, "yscale", "Scale value dor y axis" },
{ PARAM_FLOAT, "complex", "Complexity factor" },
{ PARAM_INT32, "seed", "Seed value for random number generator" },
{ PARAM_INT32, "tiling", "If set, the pattern generated will tile" },
{ PARAM_INT32, "perturb", "If set, the pattern is a little more distorted..." },
{ PARAM_INT32, "colors", "where to take the colors (0= B&W, 1= fg/bg, 2= col1/col2)"},
/* { PARAM_COLOR, "col1", "fist color (sometimes unused)" },
{ PARAM_COLOR, "col2", "second color (sometimes unused)" },*/
{ PARAM_FLOAT, "alpha1", "alpha for the first color (used if the drawable has an alpha chanel)" },
{ PARAM_FLOAT, "alpha2", "alpha for the second color (used if the drawable has an alpha chanel)" },
{ PARAM_INT32, "blend", "0= linear, 1= bilinear, 2= sinusoidal" },
{ PARAM_FLOAT, "blend_power", "Power used to strech the blend" }
};
static GParamDef *return_vals = NULL;
static gint nargs = sizeof (args) / sizeof (args[0]);
static gint nreturn_vals = 0;
gimp_install_procedure ("plug_in_sinus",
"Generates a texture with sinus functions",
"FIX ME: sinus help",
"Xavier Bouchoux",
"Xavier Bouchoux",
"1997",
"<Image>/Filters/Textures/Sinus",
"RGB*, GRAY*",
PROC_PLUG_IN,
nargs, nreturn_vals,
args, return_vals);
}
static void run (gchar *name,
gint nparams,
GParam *param,
gint *nreturn_vals,
GParam **return_vals)
{
static GParam values[1];
GRunModeType run_mode;
GStatusType status = STATUS_SUCCESS;
run_mode = param[0].data.d_int32;
*nreturn_vals = 1;
*return_vals = values;
values[0].type = PARAM_STATUS;
values[0].data.d_status = status;
switch (run_mode)
{
case RUN_INTERACTIVE:
/* Possibly retrieve data */
gimp_get_data ("plug_in_sinus", &svals);
/* In order to prepare the dialog I need to know wether it's grayscale or not */
drawable = gimp_drawable_get (param[2].data.d_drawable);
thePreview = mw_preview_build_virgin(drawable);
if (gimp_drawable_gray (drawable->id))
drawable_is_grayscale= TRUE;
else
drawable_is_grayscale= FALSE;
if (!sinus_dialog())
return;
break;
case RUN_NONINTERACTIVE:
/* Make sure all the arguments are there! */
if (nparams != 16)
status = STATUS_CALLING_ERROR;
if (status == STATUS_SUCCESS)
{
svals.seed = param[6].data.d_int32;
svals.scalex = param[3].data.d_float;
svals.scaley = param[4].data.d_float;
svals.cmplx = param[5].data.d_float;
svals.blend_power = param[15].data.d_float;
svals.tiling = param[7].data.d_int32;
svals.perturbation = param[8].data.d_int32;
svals.colorization = param[14].data.d_int32;
svals.colors = param[9].data.d_int32;
svals.col1[3] = param[12].data.d_float;
svals.col2[3] = param[13].data.d_float;
svals.col1[0] = param[10].data.d_color.red/255.999;
svals.col1[1] = param[10].data.d_color.green/255.999;
svals.col1[2] = param[10].data.d_color.blue/255.999;
svals.col2[0] = param[11].data.d_color.red/255.999;
svals.col2[1] = param[11].data.d_color.green/255.999;
svals.col2[2] = param[11].data.d_color.blue/255.999;
}
break;
case RUN_WITH_LAST_VALS:
/* Possibly retrieve data */
gimp_get_data ("plug_in_sinus", &svals);
break;
default:
break;
}
/* Get the specified drawable */
drawable = gimp_drawable_get (param[2].data.d_drawable);
/* Make sure that the drawable is gray or RGB */
if (( status == STATUS_SUCCESS) && (gimp_drawable_color (drawable->id) || gimp_drawable_gray (drawable->id)))
{
gimp_progress_init("Calculating picture...");
gimp_tile_cache_ntiles( 1 );
sinus ();
if (run_mode != RUN_NONINTERACTIVE)
gimp_displays_flush ();
/* Store data */
if (run_mode == RUN_INTERACTIVE)
gimp_set_data ("plug_in_sinus", &svals, sizeof (SinusVals));
}
else
{
status = STATUS_EXECUTION_ERROR;
}
values[0].data.d_status = status;
gimp_drawable_detach (drawable);
}
/*
* Main procedure
*/
void prepare_coef( params *p)
{
typedef struct { guchar r,g,b,a;} type_color;
type_color col1,col2;
double scalex=svals.scalex;
double scaley=svals.scaley;
srand(svals.seed);
switch (svals.colorization) {
case BILINEAR:
p->blend = bilinear;
break;
case SINUS:
p->blend = cosinus;
break;
case LINEAR:
default:
p->blend = linear;
}
if (svals.perturbation==IDEAL) {
p->c11= 0*rand();
p->c12= (2.0*rand()/(RAND_MAX+1.0)-1)*scaley; /*rand+rand is used to keep */
p->c13= (2*M_PI*rand())/RAND_MAX;
p->c21= 0*rand();
p->c22= (2.0*rand()/(RAND_MAX+1.0)-1)*scaley; /*correspondance beetween Ideal*/
p->c23= (2*M_PI*rand())/RAND_MAX;
p->c31= (2.0*rand()/(RAND_MAX+1.0)-1)*scalex; /*and perturbed coefs (I hope...)*/
p->c32= 0*rand();
p->c33= (2*M_PI*rand())/RAND_MAX;
} else {
p->c11= (2.0*rand()/(RAND_MAX+1.0)-1)*scalex;
p->c12= (2.0*rand()/(RAND_MAX+1.0)-1)*scaley;
p->c13= (2*M_PI*rand())/RAND_MAX;
p->c21= (2.0*rand()/(RAND_MAX+1.0)-1)*scalex;
p->c22= (2.0*rand()/(RAND_MAX+1.0)-1)*scaley;
p->c23= (2*M_PI*rand())/RAND_MAX;
p->c31= (2.0*rand()/(RAND_MAX+1.0)-1)*scalex;
p->c32= (2.0*rand()/(RAND_MAX+1.0)-1)*scaley;
p->c33= (2*M_PI*rand())/RAND_MAX;
}
if (svals.tiling) {
p->c11= ROUND_TO_INT(p->c11/(2*M_PI))*2*M_PI;
p->c12= ROUND_TO_INT(p->c12/(2*M_PI))*2*M_PI;
p->c21= ROUND_TO_INT(p->c21/(2*M_PI))*2*M_PI;
p->c22= ROUND_TO_INT(p->c22/(2*M_PI))*2*M_PI;
p->c31= ROUND_TO_INT(p->c31/(2*M_PI))*2*M_PI;
p->c32= ROUND_TO_INT(p->c32/(2*M_PI))*2*M_PI;
}
col2.a=255.999*svals.col2[3];
col1.a=255.999*svals.col1[3];
if (drawable_is_grayscale) {
col1.r=col1.g=col1.b=255;
col2.r=col2.g=col2.b=0;
} else {
switch (svals.colors) {
case USE_COLORS:
col1.r=255.999*svals.col1[0];
col1.g=255.999*svals.col1[1];
col1.b=255.999*svals.col1[2];
col2.r=255.999*svals.col2[0];
col2.g=255.999*svals.col2[1];
col2.b=255.999*svals.col2[2];
break;
case B_W:
col1.r=col1.g=col1.b=255;
col2.r=col2.g=col2.b=0;
break;
case USE_FG_BG:
gimp_palette_get_foreground(&col2.r, &col2.g, &col2.b);
gimp_palette_get_background(&col1.r, &col1.g, &col1.b);
break;
}
}
p->r = col1.r;
p->g = col1.g;
p->b = col1.b;
p->a = col1.a;
p->dr=(int)col2.r-col1.r;
p->dg=(int)col2.g-col1.g;
p->db=(int)col2.b-col1.b;
p->da=(int)col2.a-col1.a;
}
static void
sinus()
{
params p;
gint bytes;
GPixelRgn dest_rgn;
int ix1, iy1, ix2, iy2; /* Selected image size. */
gpointer pr;
gint progress, max_progress;
prepare_coef(&p);
gimp_drawable_mask_bounds(drawable->id, &ix1, &iy1, &ix2, &iy2);
p.width = drawable->width;
p.height = drawable->height;
bytes = drawable->bpp;
gimp_pixel_rgn_init(&dest_rgn, drawable, ix1, iy1, ix2-ix1, iy2-iy1, TRUE,TRUE);
progress = 0;
max_progress = (ix2-ix1)*(iy2-iy1);
for (pr= gimp_pixel_rgns_register(1, &dest_rgn); pr != NULL; pr = gimp_pixel_rgns_process(pr)) {
switch (bytes) {
case 4:
compute_block_4(dest_rgn.data, dest_rgn.rowstride, dest_rgn.x, dest_rgn.y, dest_rgn.w, dest_rgn.h, &p);
break;
case 3:
compute_block_3(dest_rgn.data, dest_rgn.rowstride, dest_rgn.x, dest_rgn.y, dest_rgn.w, dest_rgn.h, &p);
break;
case 2:
compute_block_2(dest_rgn.data, dest_rgn.rowstride, dest_rgn.x, dest_rgn.y, dest_rgn.w, dest_rgn.h, &p);
break;
case 1:
compute_block_1(dest_rgn.data, dest_rgn.rowstride, dest_rgn.x, dest_rgn.y, dest_rgn.w, dest_rgn.h, &p);
break;
}
progress+= dest_rgn.w * dest_rgn.h;
gimp_progress_update((double) progress/ (double) max_progress);
}
gimp_drawable_flush(drawable);
gimp_drawable_merge_shadow(drawable->id, TRUE);
gimp_drawable_update ( drawable->id, ix1, iy1, (ix2-ix1), (iy2-iy1));
}
double linear (double v)
{
register double a=v-(int)v;
return (a<0?1.0+a:a);
}
double bilinear(double v)
{
register double a=v-(int)v;
a=(a<0?1.0+a:a);
return (a>0.5?2-2*a:2*a);
}
double cosinus(double v)
{
return 0.5-0.5*sin((v+0.25)*M_PI*2);
}
inline void compute_block_4(guchar *dest_row, guint rowstride,gint x0,gint y0,gint w,gint h, params *p)
{
gint i,j;
double x,y, grey;
guchar *dest;
for (j=y0; j<(y0+h); j++) {
y=((double)j)/p->height;
dest = dest_row;
for (i= x0; i<(x0+w); i++) {
x=((double)i)/p->width;
grey = sin(p->c11*x + p->c12*y + p->c13) * (0.5+0.5*sin(p->c31*x + p->c32*y +p->c33)) \
+ sin(p->c21*x + p->c22*y + p->c23) * (0.5-0.5*sin(p->c31*x + p->c32*y +p->c33));
grey=pow(p->blend(svals.cmplx*(0.5+0.5*grey)),exp(svals.blend_power));
*dest++= p->r+(int)(grey*p->dr);
*dest++= p->g+(int)(grey*p->dg);
*dest++= p->b+(int)(grey*p->db);
*dest++= p->a+(int)(grey*p->da);
}
dest_row += rowstride;
}
}
inline void compute_block_3(guchar *dest_row, guint rowstride,gint x0,gint y0,gint w,gint h, params *p)
{
gint i,j;
double x,y, grey;
guchar *dest;
for (j=y0; j<(y0+h); j++) {
y=((double)j)/p->height;
dest = dest_row;
for (i= x0; i<(x0+w); i++) {
x=((double)i)/p->width;
grey = sin(p->c11*x + p->c12*y + p->c13) * (0.5+0.5*sin(p->c31*x + p->c32*y +p->c33)) \
+ sin(p->c21*x + p->c22*y + p->c23) * (0.5-0.5*sin(p->c31*x + p->c32*y +p->c33));
grey=pow(p->blend(svals.cmplx*(0.5+0.5*grey)),exp(svals.blend_power));
*dest++= p->r+(int)(grey*p->dr);
*dest++= p->g+(int)(grey*p->dg);
*dest++= p->b+(int)(grey*p->db);
}
dest_row += rowstride;
}
}
inline void compute_block_2(guchar *dest_row, guint rowstride,gint x0,gint y0,gint w,gint h, params *p)
{
gint i,j;
double x,y, grey;
guchar *dest;
for (j=y0; j<(y0+h); j++) {
y=((double)j)/p->height;
dest = dest_row;
for (i= x0; i<(x0+w); i++) {
x=((double)i)/p->width;
grey = sin(p->c11*x + p->c12*y + p->c13) * (0.5+0.5*sin(p->c31*x + p->c32*y +p->c33)) \
+ sin(p->c21*x + p->c22*y + p->c23) * (0.5-0.5*sin(p->c31*x + p->c32*y +p->c33));
grey=pow(p->blend(svals.cmplx*(0.5+0.5*grey)),exp(svals.blend_power));
*dest++= (guchar)(grey*255.0);
*dest++= p->a+(int)(grey*p->da);
}
dest_row += rowstride;
}
}
inline void compute_block_1(guchar *dest_row, guint rowstride,gint x0,gint y0,gint w,gint h, params *p)
{
gint i,j;
double x,y, grey;
guchar *dest;
for (j=y0; j<(y0+h); j++) {
y=((double)j)/p->height;
dest = dest_row;
for (i= x0; i<(x0+w); i++) {
x=((double)i)/p->width;
grey = sin(p->c11*x + p->c12*y + p->c13) * (0.5+0.5*sin(p->c31*x + p->c32*y +p->c33)) \
+ sin(p->c21*x + p->c22*y + p->c23) * (0.5-0.5*sin(p->c31*x + p->c32*y +p->c33));
grey=pow(p->blend(svals.cmplx*(0.5+0.5*grey)),exp(svals.blend_power));
*dest++= (guchar)(grey*255.0);
}
dest_row += rowstride;
}
}
/* ---------------------------------------------------------------*/
/* -------------------------- UI ------------------------------- */
/* -------------------------------------------------------------- */
/*****************************************/
/* The note book */
/*****************************************/
int sinus_dialog(void)
{
GtkWidget *dlg;
GtkWidget *preview;
gint runp;
GtkWidget *main_hbox, *notebook;
GtkWidget *page,*frame, *label, *vbox, *hbox, *table;
struct mwColorSel *push_col1, *push_col2;
#ifdef USE_LOGO
GtkWidget *logo;
gint x,y;
char buf[3*100];
guchar *data;
#endif
static struct mwValueRadioGroup coloriz_radio[] = {
{ "Linear", LINEAR },
{ "Bilinear", BILINEAR },
{ "Sinusoidal", SINUS },
{ NULL, 0 },
};
static struct mwValueRadioGroup colors_radio[] = {
{ "Black & White", B_W },
{ "Foreground & Background", USE_FG_BG },
{ "Choose here:", USE_COLORS},
{ NULL, 0 },
};
static struct mwValueRadioGroup coefs_radio[] = {
{ "Ideal", IDEAL },
{ "Distorted", PERTURBED },
{ NULL, 0 },
};
/* Create Main window with a vbox */
/* ============================== */
dlg = mw_app_new("plug_in_sinus", "Sinus", &runp);
main_hbox = gtk_hbox_new(FALSE, 5);
gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dlg)->vbox), main_hbox, TRUE, TRUE, 0);
gtk_widget_show(main_hbox);
/* Create preview */
/* ============== */
vbox= gtk_vbox_new(TRUE,0);
gtk_box_pack_start(GTK_BOX(main_hbox), vbox, TRUE, FALSE, 0);
gtk_widget_show(vbox);
preview = mw_preview_new(vbox, thePreview, &sinus_do_preview);
sinus_do_preview(preview);
#ifdef USE_LOGO
logo = gtk_preview_new(GTK_PREVIEW_COLOR);
gtk_preview_size(GTK_PREVIEW(logo), 100, 100);
gtk_box_pack_start(GTK_BOX(vbox), logo, TRUE, FALSE, 0);
gtk_widget_show(logo);
data= logo_data;
for (y=0;y<100; y++) {
for (x=0; x<100; x++) {
HEADER_PIXEL(data,(&buf[3*x]));
}
gtk_preview_draw_row(GTK_PREVIEW(logo), buf, 0, y, 100);
}
#endif
/* Create the notebook */
/* =================== */
notebook = gtk_notebook_new();
gtk_notebook_set_tab_pos(GTK_NOTEBOOK(notebook), GTK_POS_TOP);
gtk_box_pack_start(GTK_BOX(main_hbox),notebook,FALSE,FALSE,5);
gtk_widget_show(notebook);
/* Create the drawing settings frame */
/* ================================= */
page = gtk_vbox_new(FALSE, 0);
gtk_container_border_width(GTK_CONTAINER(page), 4);
frame= gtk_frame_new("Drawing 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(page), frame, TRUE, TRUE, 0);
gtk_widget_show(frame);
table = gtk_table_new(4, 2, FALSE);
gtk_container_border_width(GTK_CONTAINER (table), 5);
gtk_container_add(GTK_CONTAINER(frame), table);
mw_fscale_entry_new(table, "X scale: ", 0.0001, 100.0, 0.001, 5, 0,
0, 1, 1, 2, &(svals.scalex));
mw_fscale_entry_new(table, "Y scale: ", 0.0001, 100.0, 0.001, 5, 0,
0, 1, 2, 3, &(svals.scaley));
mw_fscale_entry_new(table, "Complexity: ", 0, 15.0, 0.01, 5, 0,
0, 1, 3, 4, &(svals.cmplx));
gtk_widget_show(table);
frame= gtk_frame_new("Calculation 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(page), frame, TRUE, TRUE, 0);
gtk_widget_show(frame);
vbox= gtk_vbox_new(FALSE, 5);
gtk_container_add(GTK_CONTAINER(frame), vbox);
gtk_widget_show(vbox);
mw_ientry_new(vbox, NULL, "Random seed:", &svals.seed);
mw_toggle_button_new(vbox, NULL, "Force tiling?", &svals.tiling);
mw_value_radio_group_new(vbox, NULL , coefs_radio, &svals.perturbation);
label = gtk_label_new("Settings");
gtk_misc_set_alignment(GTK_MISC(label), 0.5, 0.5);
gtk_notebook_append_page(GTK_NOTEBOOK(notebook), page, label);
gtk_widget_show(page);
/* Color settings dialog: */
/* ====================== */
page = gtk_vbox_new(FALSE, 0);
gtk_container_border_width(GTK_CONTAINER(page), 4);
frame = gtk_frame_new("Colors");
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(page), frame, TRUE, TRUE, 0);
gtk_widget_show(frame);
if (drawable_is_grayscale) {
/*if in grey scale, the colors are necessarily black and white */
label = gtk_label_new("The colors are white and black.");
gtk_misc_set_alignment(GTK_MISC(label), 0.5, 0.5);
gtk_container_add(GTK_CONTAINER(frame), label);
gtk_widget_show(label);
} else {
vbox= gtk_vbox_new(FALSE, 5);
gtk_container_add(GTK_CONTAINER(frame), vbox);
gtk_widget_show(vbox);
mw_value_radio_group_new(vbox, NULL, colors_radio, &svals.colors);
hbox= gtk_hbox_new(TRUE, 20);
gtk_box_pack_start(GTK_BOX(vbox), hbox, TRUE, FALSE, 0);
push_col1 = mw_color_select_button_create(hbox, "Fisrt Color", svals.col1, FALSE);
push_col2 = mw_color_select_button_create(hbox, "Second Color", svals.col2, FALSE);
gtk_widget_show(hbox);
}
frame = gtk_frame_new("Alpha Channels");
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(page), frame, TRUE, TRUE, 0);
gtk_widget_show(frame);
table = gtk_table_new(3, 2, FALSE);
gtk_container_border_width(GTK_CONTAINER (table), 5);
gtk_container_add(GTK_CONTAINER(frame), table);
mw_fscale_entry_new(table, "first color ", 0, 1.0, 0.01, 5, 0,
0, 1, 1, 2, &(svals.col1[3]));
mw_fscale_entry_new(table, "last color ", 0, 1.0, 0.01, 5, 0,
0, 1, 2, 3, &(svals.col2[3]));
gtk_widget_show(table);
label = gtk_label_new("Colors");
gtk_misc_set_alignment(GTK_MISC(label), 0.5, 0.5);
gtk_notebook_append_page(GTK_NOTEBOOK(notebook), page, label);
gtk_widget_show(page);
/* blend settings dialog: */
/* ====================== */
label = gtk_label_new("Blend");
gtk_misc_set_alignment(GTK_MISC(label), 0.5, 0.5);
page = gtk_vbox_new(FALSE, 0);
gtk_container_border_width(GTK_CONTAINER(page), 4);
frame = gtk_frame_new("Blend 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(page), frame, TRUE, TRUE, 0);
gtk_widget_show(frame);
vbox= gtk_vbox_new(FALSE, 5);
gtk_container_add(GTK_CONTAINER(frame), vbox);
gtk_widget_show(vbox);
mw_value_radio_group_new(vbox, "Gradient", coloriz_radio, &svals.colorization);
table = gtk_table_new(2, 2, FALSE);
gtk_container_border_width(GTK_CONTAINER (table), 5);
gtk_container_add(GTK_CONTAINER(vbox), table);
mw_fscale_entry_new(table, "Exponent ", -7.5, 7.5, 0.01, 5.0, 0.0,
0, 1, 0, 1, &svals.blend_power);
gtk_widget_show(table);
gtk_notebook_append_page(GTK_NOTEBOOK(notebook), page, label);
gtk_widget_show(page);
gtk_widget_show(dlg);
gtk_main();
gdk_flush();
/* argp->type = mw_radio_result(mode); */
return runp;
}
/******************************************************************/
/* Draw preview image. if DoCompute is TRUE then recompute image. */
/******************************************************************/
void sinus_do_preview(GtkWidget *w)
{
static GtkWidget *theWidget = NULL;
gint y,rowsize;
guchar *buf, *savbuf;
params p;
if(theWidget==NULL){
theWidget=w;
}
rowsize=thePreview->width*thePreview->bpp;
savbuf = buf = (guchar *)malloc(thePreview->width*thePreview->height*thePreview->bpp);
if (buf != NULL) {
p.height= thePreview->height;
p.width= thePreview->width;
prepare_coef(&p);
if (thePreview->bpp == 3)
compute_block_3(buf, rowsize,0,0,thePreview->width,thePreview->height, &p);
else if (thePreview->bpp == 1) {
compute_block_1(buf, rowsize,0,0,thePreview->width,thePreview->height, &p);
}
else
fprintf(stderr,"Uh Oh.... Little sinus preview-only problem...\n");
for (y=0;y<thePreview->height; y++) {
gtk_preview_draw_row(GTK_PREVIEW(theWidget),
buf, 0, y, thePreview->width);
buf+= rowsize;
}
free(savbuf);
gtk_widget_draw(theWidget, NULL);
gdk_flush();
} else {
fprintf(stderr,"Not enough mem for sinus Preview...\n");
}
}

View File

@ -1,441 +0,0 @@
/*
smooth palette - derive smooth palette from image
Copyright (C) 1997 Scott Draves <spot@cs.cmu.edu>
The GIMP -- an image manipulation program
Copyright (C) 1995 Spencer Kimball and Peter Mattis
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
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include "libgimp/gimp.h"
#include "gtk/gtk.h"
/* Declare local functions. */
static void query(void);
static void run(char *name,
int nparams,
GParam * param,
int *nreturn_vals,
GParam ** return_vals);
static gint dialog();
static gint32 doit(GDrawable * drawable, gint32 *layer_id);
GPlugInInfo PLUG_IN_INFO =
{
NULL, /* init_proc */
NULL, /* quit_proc */
query, /* query_proc */
run, /* run_proc */
};
int run_flag = 0;
MAIN()
static void query()
{
static GParamDef args[] =
{
{PARAM_INT32, "run_mode", "Interactive, non-interactive"},
{PARAM_IMAGE, "image", "Input image (unused)"},
{PARAM_DRAWABLE, "drawable", "Input drawable"},
};
static GParamDef *return_vals = NULL;
static int nargs = sizeof(args) / sizeof(args[0]);
static int nreturn_vals = 0;
gimp_install_procedure("plug_in_smooth_palette",
"derive smooth palette from image",
"help!",
"Scott Draves",
"Scott Draves",
"1997",
"<Image>/Filters/Transforms/SmoothPalette",
"RGB*",
PROC_PLUG_IN,
nargs, nreturn_vals,
args, return_vals);
}
static struct {
gint width;
gint height;
gint ntries;
gint try_size;
} config = {
256,
64,
50,
10000
};
static void
run (char *name,
int nparams,
GParam *param,
int *nreturn_vals,
GParam **return_vals)
{
static GParam values[3];
GRunModeType run_mode;
GStatusType status = STATUS_SUCCESS;
GDrawable *drawable;
run_mode = param[0].data.d_int32;
*nreturn_vals = 3;
*return_vals = values;
values[0].type = PARAM_STATUS;
values[0].data.d_status = status;
values[1].type = PARAM_IMAGE;
values[2].type = PARAM_LAYER;
switch (run_mode) {
case RUN_INTERACTIVE:
gimp_get_data ("plug_in_smooth_palette", &config);
if (! dialog ()) return;
break;
case RUN_NONINTERACTIVE:
status = STATUS_CALLING_ERROR;
break;
case RUN_WITH_LAST_VALS:
/* Possibly retrieve data */
gimp_get_data ("plug_in_smooth_palette", &config);
break;
default:
break;
}
if (status == STATUS_SUCCESS) {
drawable = gimp_drawable_get(param[2].data.d_drawable);
if (gimp_drawable_color(drawable->id)) {
gimp_progress_init ("Deriving smooth palette...");
gimp_tile_cache_ntiles (2 * (drawable->width + 1) / gimp_tile_width ());
values[1].data.d_image = doit(drawable, &values[2].data.d_layer);
if (run_mode == RUN_INTERACTIVE)
gimp_set_data ("plug_in_smooth_palette", &config, sizeof (config));
if (run_mode != RUN_NONINTERACTIVE)
gimp_display_new (values[1].data.d_image);
} else
status = STATUS_EXECUTION_ERROR;
gimp_drawable_detach(drawable);
}
values[0].data.d_status = status;
}
#define R (rand())
static long
pix_diff(guchar *pal, int bpp, int i, int j) {
long r = 0;
int k;
for (k = 0; k < bpp; k++) {
int p1 = pal[j * bpp + k];
int p2 = pal[i * bpp + k];
r += (p1 - p2) * (p1 - p2);
}
return r;
}
static void
pix_swap(guchar *pal, int bpp, int i, int j) {
int k;
for (k = 0; k < bpp; k++) {
guchar t = pal[j * bpp + k];
pal[j * bpp + k] = pal[i * bpp + k];
pal[i * bpp + k] = t;
}
}
static gint32
doit(GDrawable * drawable, gint32 *layer_id) {
gint32 new_image_id;
GDrawable *new_layer;
int psize, i, j;
guchar *pal;
int bpp = drawable->bpp;
GPixelRgn pr;
srand(time(0));
new_image_id = gimp_image_new (config.width, config.height, RGB);
*layer_id = gimp_layer_new (new_image_id, "Background",
config.width, config.height,
gimp_drawable_type (drawable->id),
100, NORMAL_MODE);
gimp_image_add_layer (new_image_id, *layer_id, 0);
new_layer = gimp_drawable_get (*layer_id);
psize = config.width;
pal = malloc(psize * bpp);
gimp_pixel_rgn_init(&pr, drawable, 0, 0, drawable->width,
drawable->height,
FALSE, FALSE);
/* get initial palette */
for (i = 0; i < psize; i++) {
int x = R % drawable->width;
int y = R % drawable->height;
gimp_pixel_rgn_get_pixel(&pr, pal + bpp * i, x, y);
}
/* reorder */
if (1) {
guchar *pal_best = malloc(psize * bpp);
guchar *original = malloc(psize * bpp);
double len_best = 0;
int try;
memcpy(pal_best, pal, bpp * psize);
memcpy(original, pal, bpp * psize);
for (try = 0; try < config.ntries; try++) {
double len;
if (!(try%5))
gimp_progress_update(try/(double)config.ntries);
memcpy(pal, original, bpp * psize);
/* scramble */
for (i = 1; i < psize; i++)
pix_swap(pal, bpp, i, R % psize);
/* measure */
len = 0.0;
for (i = 1; i < psize; i++)
len += pix_diff(pal, bpp, i, i-1);
/* improve */
for (i = 0; i < config.try_size; i++) {
int i0 = 1 + (R % (psize-2));
int i1 = 1 + (R % (psize-2));
long as_is, swapd;
if (1 == (i0 - i1)) {
as_is = (pix_diff(pal, bpp, i1 - 1, i1) +
pix_diff(pal, bpp, i0, i0 + 1));
swapd = (pix_diff(pal, bpp, i1 - 1, i0) +
pix_diff(pal, bpp, i1, i0 + 1));
} else if (1 == (i1 - i0)) {
as_is = (pix_diff(pal, bpp, i0 - 1, i0) +
pix_diff(pal, bpp, i1, i1 + 1));
swapd = (pix_diff(pal, bpp, i0 - 1, i1) +
pix_diff(pal, bpp, i0, i1 + 1));
} else {
as_is = (pix_diff(pal, bpp, i0, i0 + 1) +
pix_diff(pal, bpp, i0, i0 - 1) +
pix_diff(pal, bpp, i1, i1 + 1) +
pix_diff(pal, bpp, i1, i1 - 1));
swapd = (pix_diff(pal, bpp, i1, i0 + 1) +
pix_diff(pal, bpp, i1, i0 - 1) +
pix_diff(pal, bpp, i0, i1 + 1) +
pix_diff(pal, bpp, i0, i1 - 1));
}
if (swapd < as_is) {
pix_swap(pal, bpp, i0, i1);
len += swapd - as_is;
}
}
/* best? */
if (0 == try || len < len_best) {
memcpy(pal_best, pal, bpp * psize);
len_best = len;
}
}
memcpy(pal, pal_best, bpp * psize);
free(pal_best);
free(original);
/* clean */
for (i = 1; i < 4 * psize; i++) {
long as_is, swapd;
int i0 = 1 + R % (psize - 2);
int i1 = i0 + 1;
as_is = (pix_diff(pal, bpp, i0 - 1, i0) +
pix_diff(pal, bpp, i1, i1 + 1));
swapd = (pix_diff(pal, bpp, i0 - 1, i1) +
pix_diff(pal, bpp, i0, i1 + 1));
if (swapd < as_is) {
pix_swap(pal, bpp, i0, i1);
len_best += swapd - as_is;
}
}
}
/* store smooth palette */
gimp_pixel_rgn_init(&pr, new_layer, 0, 0,
config.width, config.height,
TRUE, TRUE);
for (j = 0; j < config.height; j++)
for (i = 0; i < config.width; i++)
gimp_pixel_rgn_set_pixel(&pr, pal + bpp * i, i, j);
free(pal);
gimp_drawable_flush(new_layer);
gimp_drawable_merge_shadow(new_layer->id, TRUE);
gimp_drawable_update(new_layer->id, 0, 0,
config.width, config.height);
return new_image_id;
}
static void close_callback(GtkWidget * widget, gpointer data)
{
gtk_main_quit();
}
static void ok_callback(GtkWidget * widget, gpointer data)
{
run_flag = 1;
gtk_widget_destroy(GTK_WIDGET(data));
}
static void callback(GtkWidget * widget, gpointer data)
{
if (&config.width == data) {
config.width = atoi(gtk_entry_get_text(GTK_ENTRY(widget)));
} else if (&config.height == data) {
config.height = atoi(gtk_entry_get_text(GTK_ENTRY(widget)));
} else if (&config.ntries == data) {
config.ntries = atoi(gtk_entry_get_text(GTK_ENTRY(widget)));
} else {
fprintf(stderr, "bad data in callback: %x\n", (int) data);
}
}
static gint dialog()
{
GtkWidget *dlg;
GtkWidget *button;
GtkWidget *table;
GtkWidget *w;
gchar **argv;
gint argc;
char b[12];
argc = 1;
argv = g_new(gchar *, 1);
argv[0] = g_strdup("smooth palette");
gtk_init(&argc, &argv);
gtk_rc_parse (gimp_gtkrc ());
dlg = gtk_dialog_new();
gtk_window_set_title(GTK_WINDOW(dlg), "Smooth Palette");
gtk_window_position(GTK_WINDOW(dlg), GTK_WIN_POS_MOUSE);
gtk_signal_connect(GTK_OBJECT(dlg), "destroy",
(GtkSignalFunc) close_callback, NULL);
button = gtk_button_new_with_label("ok");
GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT);
gtk_signal_connect(GTK_OBJECT(button), "clicked",
(GtkSignalFunc) ok_callback,
dlg);
gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dlg)->action_area), button, TRUE, TRUE, 0);
gtk_widget_grab_default(button);
gtk_widget_show(button);
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));
gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dlg)->action_area), button, TRUE, TRUE, 0);
gtk_widget_show(button);
table = gtk_table_new(4, 4, FALSE);
gtk_container_border_width(GTK_CONTAINER(table), 10);
gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dlg)->vbox), table, TRUE, TRUE, 0);
gtk_widget_show(table);
gtk_table_set_row_spacings(GTK_TABLE(table), 10);
gtk_table_set_col_spacings(GTK_TABLE(table), 10);
{
w = gtk_label_new("Width:");
gtk_misc_set_alignment(GTK_MISC(w), 0.0, 0.5);
gtk_table_attach(GTK_TABLE(table), w, 0, 2, 0, 1,
GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
gtk_widget_show(w);
w = gtk_entry_new();
gtk_table_attach(GTK_TABLE(table), w, 2, 4, 0, 1,
GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
gtk_widget_set_usize(w, 50, 0);
sprintf(b, "%d", config.width);
gtk_entry_set_text(GTK_ENTRY(w), b);
gtk_signal_connect(GTK_OBJECT(w), "changed",
(GtkSignalFunc) callback, &config.width);
gtk_widget_show(w);
}
{
w = gtk_label_new("Height:");
gtk_misc_set_alignment(GTK_MISC(w), 0.0, 0.5);
gtk_table_attach(GTK_TABLE(table), w, 0, 2, 2, 3,
GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
gtk_widget_show(w);
w = gtk_entry_new();
gtk_table_attach(GTK_TABLE(table), w, 2, 4, 2, 3,
GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
gtk_widget_set_usize(w, 50, 0);
sprintf(b, "%d", config.height);
gtk_entry_set_text(GTK_ENTRY(w), b);
gtk_signal_connect(GTK_OBJECT(w), "changed",
(GtkSignalFunc) callback, &config.height);
gtk_widget_show(w);
}
{
w = gtk_label_new("Search Time:");
gtk_misc_set_alignment(GTK_MISC(w), 0.0, 0.5);
gtk_table_attach(GTK_TABLE(table), w, 0, 2, 3, 4,
GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
gtk_widget_show(w);
w = gtk_entry_new();
gtk_table_attach(GTK_TABLE(table), w, 2, 4, 3, 4,
GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
gtk_widget_set_usize(w, 50, 0);
sprintf(b, "%d", config.ntries);
gtk_entry_set_text(GTK_ENTRY(w), b);
gtk_signal_connect(GTK_OBJECT(w), "changed",
(GtkSignalFunc) callback, &config.ntries);
gtk_widget_show(w);
}
gtk_widget_show(dlg);
gtk_main();
gdk_flush();
return run_flag;
}

Some files were not shown because too many files have changed in this diff Show More