applied gimp-kirchgessner-000320-0

--Sven
This commit is contained in:
Sven Neumann 2000-03-24 16:21:35 +00:00
parent 99f85a4626
commit 0309fec9f1
2 changed files with 347 additions and 40 deletions

View file

@ -1,3 +1,13 @@
Fri Mar 24 17:13:41 CET 2000 Sven Neumann <sven@gimp.org>
plug-ins/common/mapcolor.c: applied gimp-kirchgessner-000320-0.
Fixes problem with divide by zero when selecting same colors,
adds preview and makes the GUI more intuitive.
Additionally, I've added another check for the drawable being RGB
in the function that does the actual work. Remember that the
image_type may change while the dialog is open!
Fri Mar 24 15:48:40 CET 2000 Sven Neumann <sven@gimp.org>
applied gimp-quinet-000310-0 by Raphael Quinet <quinet@gamers.org>

View file

@ -24,10 +24,13 @@
* V 1.00, PK, 26-Oct-98: Creation.
* V 1.01, PK, 21-Nov-99: Fix problem with working on layered images
* Internationalization
* V 1.02, PK, 19-Mar-00: Better explaining text/dialogue
* Preview added
* Fix problem with divide by zero
*/
#define VERSIO 1.01
static char dversio[] = "v1.01 21-Nov-99";
static char ident[] = "@(#) GIMP mapcolor plug-in v1.01 21-Nov-99";
#define VERSIO 1.02
static char dversio[] = "v1.02 19-Mar-00";
static char ident[] = "@(#) GIMP mapcolor plug-in v1.02 19-Mar-00";
#include "config.h"
@ -57,7 +60,7 @@ typedef struct
gint32 map_mode;
} PluginValues;
PluginValues plvals =
PluginValues plvals =
{
{
{ 0, 0, 0},
@ -68,6 +71,26 @@ PluginValues plvals =
0
};
/* Preview handling stuff */
#define IMG_PRV_SIZE 128
typedef struct
{
guint width, height;
guchar *img;
} IMG_PREVIEW;
typedef struct
{
GtkWidget *preview;
IMG_PREVIEW *img_preview;
IMG_PREVIEW *map_preview;
} PLInterface;
gint run_flag = FALSE;
/* Declare some local functions.
@ -87,9 +110,22 @@ GPlugInInfo PLUG_IN_INFO =
run, /* run_proc */
};
static gint dialog (void);
static IMG_PREVIEW *img_preview_alloc (guint width, guint height);
static void img_preview_free (IMG_PREVIEW *ip);
static void img_preview_copy (IMG_PREVIEW *src, IMG_PREVIEW **dst);
static IMG_PREVIEW *img_preview_create_from_drawable (guint maxsize,
gint32 drawable_ID);
static void update_img_preview (void);
static gint dialog (gint32 drawable_ID);
static void mapcolor_ok_callback (GtkWidget *widget,
gpointer data);
static void get_mapping (guchar *src_col1, guchar *src_col2,
guchar *dst_col1, guchar *dst_col2, gint32 map_mode,
guchar *redmap, guchar *greenmap, guchar *bluemap);
static void color_button_color_changed_callback (GtkWidget *widget,
gpointer data);
static void add_color_button (gint csel_index,
gint left,
gint top,
@ -101,14 +137,174 @@ static void color_mapping (GDrawable *drawable);
/* The run mode */
static GRunModeType l_run_mode;
static gchar *csel_title[4] =
{
N_("First Source Color"),
static gchar *csel_title[4] =
{
N_("First Source Color"),
N_("Second Source Color"),
N_("First Destination Color"),
N_("Second Destination Color")
N_("First Destination Color"),
N_("Second Destination Color")
};
static PLInterface plinterface;
/* Allocate image preview structure and preview memory */
static IMG_PREVIEW *
img_preview_alloc (guint width, guint height)
{IMG_PREVIEW *ip;
ip = (IMG_PREVIEW *)g_malloc (sizeof (IMG_PREVIEW));
ip->img = (guchar *)g_malloc (width*height*3);
if (ip->img == NULL)
{
g_free (ip);
return NULL;
}
ip->width = width;
ip->height = height;
return ip;
}
/* Free image preview */
static void
img_preview_free (IMG_PREVIEW *ip)
{
if (ip)
{
if (ip->img)
{
g_free (ip->img);
ip->img = NULL;
}
ip->width = ip->height = 0;
g_free (ip);
}
}
/* Copy image preview. Create/modify destinataion preview */
static void
img_preview_copy (IMG_PREVIEW *src, IMG_PREVIEW **dst)
{int numbytes;
IMG_PREVIEW *dst_p;
if ((src == NULL) || (src->img == NULL) || (dst == NULL)) return;
numbytes = src->width * src->height * 3; /* 1 byte spare */
if (numbytes <= 0) return;
if (*dst == NULL) /* Create new preview ? */
{
*dst = img_preview_alloc (src->width, src->height);
if (*dst == NULL) return;
memcpy ((*dst)->img, src->img, numbytes);
return;
}
/* destination preview already exists */
dst_p = *dst;
/* Did not already allocate enough memory ? */
if ((dst_p->img != NULL) && (dst_p->width*dst_p->height*3 < numbytes))
{
g_free (dst_p->img);
dst_p->width = dst_p->height = 0;
dst_p->img = NULL;
}
if (dst_p->img == NULL)
{
dst_p->img = (guchar *)g_malloc (numbytes);
if (dst_p->img == NULL) return;
}
dst_p->width = src->width;
dst_p->height = src->height;
memcpy (dst_p->img, src->img, numbytes);
}
static IMG_PREVIEW *
img_preview_create_from_drawable (guint maxsize, gint32 drawable_ID)
{GDrawable *drw;
GPixelRgn pixel_rgn;
guint drw_width, drw_height;
guint prv_width, prv_height;
gint src_x, src_y, x, y;
guchar *prv_data, *img_data, *cu_row;
double xfactor, yfactor;
gint tile_height, row_start, row_end;
gint bpp;
IMG_PREVIEW *ip;
drw_width = gimp_drawable_width (drawable_ID);
drw_height = gimp_drawable_height (drawable_ID);
tile_height = (gint)gimp_tile_height();
bpp = gimp_drawable_bpp(drawable_ID);
img_data = g_malloc (drw_width * tile_height * bpp);
if (img_data == NULL) return NULL;
/* Calculate preview size */
if ((drw_width <= maxsize) && (drw_height <= maxsize))
{
prv_width = drw_width;
prv_height = drw_height;
}
else
{
xfactor = ((double)maxsize) / ((double)drw_width);
yfactor = ((double)maxsize) / ((double)drw_height);
if (xfactor < yfactor)
{
prv_width = maxsize;
prv_height = (guint)(drw_height * xfactor);
}
else
{
prv_width = (guint)(drw_width * yfactor);
prv_height = maxsize;
}
}
ip = img_preview_alloc (prv_width, prv_height);
if (ip == NULL) return NULL;
drw = gimp_drawable_get (drawable_ID);
prv_data = ip->img;
gimp_pixel_rgn_init (&pixel_rgn, drw, 0, 0, drw_width, drw_height,
FALSE, FALSE);
row_start = row_end = -1;
/* Get the pixels for the preview from the drawable */
for (y = 0; y < prv_height; y++)
{
src_y = ((drw_height-1) * y) / (prv_height-1);
if (src_y > row_end) /* Need new row ? */
{
row_start = (src_y / tile_height) * tile_height;
row_end = row_start+tile_height-1;
if (row_end > drw_height-1) row_end = drw_height-1;
gimp_pixel_rgn_get_rect (&pixel_rgn, img_data, 0, row_start, drw_width,
row_end-row_start+1);
}
cu_row = img_data + (src_y-row_start)*drw_width*bpp;
for (x = 0; x < prv_width; x++)
{
src_x = ((drw_width-1) * x) / (prv_width-1);
memcpy (prv_data, cu_row+bpp*src_x, 3);
prv_data += 3;
}
}
gimp_drawable_detach (drw);
g_free (img_data);
return ip;
}
MAIN ()
@ -140,10 +336,12 @@ query (void)
INIT_I18N ();
gimp_install_procedure ("plug_in_color_adjust",
"Adjust current foreground/background color in the "
"drawable to black/white",
"The current foreground color is mapped to black, "
"the current background color is mapped to white.",
"Adjust color range given by foreground/background "
"color to black/white",
"The current foreground color is mapped to black "
"(black point), the current background color is "
"mapped to white (white point). Intermediate "
"colors are interpolated",
"Peter Kirchgessner",
"Peter Kirchgessner",
dversio,
@ -154,14 +352,15 @@ query (void)
adjust_args, NULL);
gimp_install_procedure ("plug_in_color_map",
"Map two source colors to two destination colors. "
"Other colors are mapped by interpolation.",
"Map two source colors to two destination colors. "
"Other colors are mapped by interpolation.",
"Map color range specified by two colors"
"to color range specified by two other color.",
"Map color range specified by two colors"
"to color range specified by two other color."
"Intermediate colors are interpolated.",
"Peter Kirchgessner",
"Peter Kirchgessner",
dversio,
N_("<Image>/Filters/Colors/Map/Color Mapping..."),
N_("<Image>/Filters/Colors/Map/Color Range Mapping..."),
"RGB*",
PROC_PLUG_IN,
nmap_args, 0,
@ -268,7 +467,7 @@ run (gchar *name,
c = &(plvals.colors[1][0]); /* Second source color */
gimp_palette_get_background (c, c+1, c+2);
if (!dialog ())
if (!dialog (param[2].data.d_drawable))
break;
}
else if (run_mode == RUN_WITH_LAST_VALS)
@ -302,15 +501,54 @@ run (gchar *name,
values[0].data.d_status = status;
}
static void
update_img_preview (void)
{IMG_PREVIEW *dst_ip = plinterface.map_preview;
IMG_PREVIEW *src_ip = plinterface.img_preview;
guchar *src, *dst;
GtkWidget *preview = plinterface.preview;
int j;
unsigned char redmap[256], greenmap[256], bluemap[256];
unsigned char *src_col1 = plvals.colors[0];
unsigned char *src_col2 = plvals.colors[1];
unsigned char *dst_col1 = plvals.colors[2];
unsigned char *dst_col2 = plvals.colors[3];
if ((dst_ip == NULL) || (src_ip == NULL)) return;
get_mapping (src_col1, src_col2, dst_col1, dst_col2, plvals.map_mode,
redmap, greenmap, bluemap);
j = dst_ip->width*dst_ip->height;
src = src_ip->img;
dst = dst_ip->img;
while (j-- > 0)
{
*(dst++) = redmap[*(src++)];
*(dst++) = greenmap[*(src++)];
*(dst++) = bluemap[*(src++)];
}
for (j = 0; j < dst_ip->height; j++)
gtk_preview_draw_row (GTK_PREVIEW (preview), dst_ip->img + dst_ip->width*3*j,
0, j, dst_ip->width);
gtk_widget_draw (preview, NULL);
gdk_flush ();
}
static gint
dialog (void)
dialog (gint32 drawable_ID)
{
GtkWidget *dlg;
GtkWidget *frame;
GtkWidget *frame, *pframe;
GtkWidget *abox;
GtkWidget *table;
GtkWidget *preview;
IMG_PREVIEW *ip;
guchar *color_cube;
gchar **argv;
gint argc;
gint argc, j;
argc = 1;
argv = g_new (gchar *, 1);
@ -330,7 +568,9 @@ dialog (void)
gtk_widget_set_default_visual (gtk_preview_get_visual ());
gtk_widget_set_default_colormap (gtk_preview_get_cmap ());
dlg = gimp_dialog_new (_("Map Colors"), "mapcolor",
memset (&plinterface, 0, sizeof (plinterface));
dlg = gimp_dialog_new (_("Map Color Range"), "mapcolor",
gimp_plugin_help_func, "filters/mapcolor.html",
GTK_WIN_POS_MOUSE,
FALSE, TRUE, FALSE,
@ -346,24 +586,59 @@ dialog (void)
GTK_SIGNAL_FUNC (gtk_main_quit),
NULL);
frame = gtk_frame_new (_("Colors"));
gtk_container_set_border_width (GTK_CONTAINER (frame), 6);
gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dlg)->vbox), frame, FALSE, FALSE, 0);
gtk_widget_show (frame);
/* Preview */
ip = img_preview_create_from_drawable (IMG_PRV_SIZE, drawable_ID);
if (ip)
{
plinterface.img_preview = ip;
img_preview_copy (plinterface.img_preview, &(plinterface.map_preview));
/* The table keeps the color selections */
table = gtk_table_new (2, 4, FALSE);
gtk_table_set_row_spacings (GTK_TABLE (table), 4);
gtk_table_set_col_spacings (GTK_TABLE (table), 4);
gtk_table_set_col_spacing (GTK_TABLE (table), 1, 6);
gtk_container_set_border_width (GTK_CONTAINER (table), 4);
gtk_container_add (GTK_CONTAINER (frame), table);
gtk_widget_show (table);
frame = gtk_frame_new (_("Preview"));
gtk_container_set_border_width (GTK_CONTAINER (frame), 6);
gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dlg)->vbox),frame,FALSE,FALSE,0);
add_color_button (0, 0, 0, table);
add_color_button (1, 0, 1, table);
add_color_button (2, 2, 0, table);
add_color_button (3, 2, 1, table);
abox = gtk_alignment_new (0.5, 0.5, 0.0, 0.0);
gtk_container_set_border_width (GTK_CONTAINER (abox), 4);
gtk_container_add (GTK_CONTAINER (frame), abox);
pframe = gtk_frame_new (NULL);
gtk_frame_set_shadow_type (GTK_FRAME (pframe), GTK_SHADOW_IN);
gtk_container_set_border_width (GTK_CONTAINER (pframe), 4);
gtk_container_add (GTK_CONTAINER (abox), pframe);
preview = gtk_preview_new (GTK_PREVIEW_COLOR);
plinterface.preview = preview;
gtk_preview_size (GTK_PREVIEW (preview), ip->width, ip->height);
gtk_container_add (GTK_CONTAINER (pframe), preview);
gtk_widget_show (preview);
gtk_widget_show (pframe);
gtk_widget_show (abox);
gtk_widget_show (frame);
}
for (j = 0; j < 2; j++)
{
frame = gtk_frame_new ((j==0) ? _("Source color range")
: _("Destination color range"));
gtk_container_set_border_width (GTK_CONTAINER (frame), 6);
gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dlg)->vbox),frame,FALSE,FALSE,0);
gtk_widget_show (frame);
/* The table keeps the color selections */
table = gtk_table_new (1, 4, FALSE);
gtk_table_set_row_spacings (GTK_TABLE (table), 4);
gtk_table_set_col_spacings (GTK_TABLE (table), 4);
gtk_table_set_col_spacing (GTK_TABLE (table), 1, 6);
gtk_container_set_border_width (GTK_CONTAINER (table), 4);
gtk_container_add (GTK_CONTAINER (frame), table);
gtk_widget_show (table);
add_color_button (j*2, 0, 0, table);
add_color_button (j*2 + 1, 2, 0, table);
}
update_img_preview ();
gtk_widget_show (dlg);
@ -373,6 +648,14 @@ dialog (void)
return run_flag;
}
static void
color_button_color_changed_callback (GtkWidget *widget,
gpointer data)
{
update_img_preview ();
}
static void
add_color_button (gint csel_index,
gint left,
@ -392,11 +675,15 @@ add_color_button (gint csel_index,
button = gimp_color_button_new (gettext (csel_title[csel_index]),
PRV_WIDTH, PRV_HEIGHT,
plvals.colors[csel_index], 3);
gtk_signal_connect (GTK_OBJECT (button), "color_changed",
GTK_SIGNAL_FUNC (color_button_color_changed_callback),
NULL);
gtk_table_attach (GTK_TABLE (table), button, left+1, left+2, top, top+1,
GTK_FILL, GTK_FILL, 0, 0);
gtk_widget_show (button);
}
static void
mapcolor_ok_callback (GtkWidget *widget,
gpointer data)
@ -406,6 +693,9 @@ mapcolor_ok_callback (GtkWidget *widget,
run_flag = TRUE;
gtk_widget_destroy (GTK_WIDGET (data));
img_preview_free (plinterface.img_preview);
img_preview_free (plinterface.map_preview);
}
static void
@ -436,6 +726,7 @@ get_mapping (guchar *src_col1,
{
a = src_col1[rgb]; as = dst_col1[rgb];
b = src_col2[rgb]; bs = dst_col2[rgb];
if (b == a) b = a+1;
for (i = 0; i < 256; i++)
{
j = ((i - a) * (bs - as)) / (b - a) + as;
@ -467,6 +758,12 @@ color_mapping (GDrawable *drawable)
|| (src_col1[1] == src_col2[1])
|| (src_col1[2] == src_col2[2])) return;
if (!gimp_drawable_is_rgb (drawable->id))
{
g_message (_("Color Mapping / Adjust FG/BG:\nCannot operate on gray/indexed images"));
return;
}
gimp_drawable_mask_bounds (drawable->id, &xmin, &ymin, &xmax, &ymax);
if ((ymin == ymax) || (xmin == xmax)) return;
total = (xmax - xmin) * (ymax - ymin);