mirror of https://github.com/GNOME/gimp.git
ed Sep 1 21:27:27 BST 1999 Adam D. Moss <adam@gimp.org>
* app/convert.c app/convert.h: Optional low-bleed FS dithering * app/fsdither.h: Tables are const * app/convert_cmds.c app/internal_procs.c tools/pdbgen/enums.pl tools/pdbgen/pdb/convert.pdb: Clean up 'convert' PDB interface cruft.
This commit is contained in:
parent
e98b563a93
commit
a437ece36f
11
ChangeLog
11
ChangeLog
|
@ -1,3 +1,14 @@
|
|||
Wed Sep 1 21:27:27 BST 1999 Adam D. Moss <adam@gimp.org>
|
||||
|
||||
* app/convert.c app/convert.h:
|
||||
Optional low-bleed FS dithering
|
||||
|
||||
* app/fsdither.h: Tables are const
|
||||
|
||||
* app/convert_cmds.c app/internal_procs.c tools/pdbgen/enums.pl
|
||||
tools/pdbgen/pdb/convert.pdb:
|
||||
Clean up 'convert' PDB interface cruft.
|
||||
|
||||
1999-09-01 Tor Lillqvist <tml@iki.fi>
|
||||
|
||||
* app/appenv.h
|
||||
|
|
207
app/convert.c
207
app/convert.c
|
@ -25,6 +25,8 @@
|
|||
*/
|
||||
|
||||
/*
|
||||
* 99/09/01 - Created a low-bleed FS-dither option. [Adam]
|
||||
*
|
||||
* 99/08/29 - Deterministic colour dithering to arbitrary palettes.
|
||||
* Ideal for animations that are going to be delta-optimized or simply
|
||||
* don't want to look 'busy' in static areas. Also a bunch of bugfixes
|
||||
|
@ -163,6 +165,8 @@ static const unsigned char webpal[] =
|
|||
0,51,0,0,0,255,0,0,204,0,0,153,0,0,102,0,0,51,0,0,0
|
||||
};
|
||||
|
||||
/* Note: convert.c code currently makes assumptions about some of the
|
||||
below defines, so small fixes are needed if they change... */
|
||||
#define DM_WIDTH 128
|
||||
#define DM_WIDTHMASK 127
|
||||
#define DM_WIDTH_SHIFT 7
|
||||
|
@ -333,6 +337,7 @@ struct _QuantizeObj
|
|||
Histogram histogram; /* holds the histogram */
|
||||
|
||||
int want_alpha_dither;
|
||||
int error_freedom; /* 0=much bleed, 1=controlled bleed */
|
||||
};
|
||||
|
||||
typedef struct
|
||||
|
@ -373,6 +378,7 @@ typedef struct
|
|||
GimpImage* gimage;
|
||||
int nodither_flag;
|
||||
int fsdither_flag;
|
||||
int fslowbleeddither_flag;
|
||||
int fixeddither_flag;
|
||||
int alphadither; /* flag */
|
||||
int remdups; /* flag */
|
||||
|
@ -423,17 +429,18 @@ PaletteEntriesP theCustomPalette = NULL;
|
|||
|
||||
|
||||
/* Defaults */
|
||||
static int snum_cols = 256;
|
||||
static gboolean sfsdither_flag = TRUE;
|
||||
static gboolean snodither_flag = FALSE;
|
||||
static gboolean sfixeddither_flag = FALSE;
|
||||
static gboolean smakepal_flag = TRUE;
|
||||
static gboolean salphadither_flag = FALSE;
|
||||
static gboolean sremdups_flag = TRUE;
|
||||
static gboolean swebpal_flag = FALSE;
|
||||
static gboolean scustompal_flag = FALSE;
|
||||
static gboolean smonopal_flag = FALSE;
|
||||
static gboolean sreusepal_flag = FALSE;
|
||||
static int snum_cols = 256;
|
||||
static gboolean sfsdither_flag = TRUE;
|
||||
static gboolean sfslowbleeddither_flag = TRUE;
|
||||
static gboolean snodither_flag = FALSE;
|
||||
static gboolean sfixeddither_flag = FALSE;
|
||||
static gboolean smakepal_flag = TRUE;
|
||||
static gboolean salphadither_flag = FALSE;
|
||||
static gboolean sremdups_flag = TRUE;
|
||||
static gboolean swebpal_flag = FALSE;
|
||||
static gboolean scustompal_flag = FALSE;
|
||||
static gboolean smonopal_flag = FALSE;
|
||||
static gboolean sreusepal_flag = FALSE;
|
||||
|
||||
|
||||
void
|
||||
|
@ -479,6 +486,7 @@ convert_to_indexed (GimpImage *gimage)
|
|||
dialog->num_cols = snum_cols;
|
||||
dialog->nodither_flag = snodither_flag;
|
||||
dialog->fsdither_flag = sfsdither_flag;
|
||||
dialog->fslowbleeddither_flag = sfslowbleeddither_flag;
|
||||
dialog->fixeddither_flag = sfixeddither_flag;
|
||||
dialog->alphadither = salphadither_flag;
|
||||
dialog->remdups = sremdups_flag;
|
||||
|
@ -683,7 +691,24 @@ convert_to_indexed (GimpImage *gimage)
|
|||
{
|
||||
gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
|
||||
|
||||
toggle = gtk_radio_button_new_with_label (group, _("Floyd-Steinberg colour dithering"));
|
||||
toggle = gtk_radio_button_new_with_label (group, _("Floyd-Steinberg colour dithering (reduced colour bleeding)"));
|
||||
group = gtk_radio_button_group (GTK_RADIO_BUTTON (toggle));
|
||||
|
||||
gtk_box_pack_start (GTK_BOX (hbox), toggle, FALSE, FALSE, 0);
|
||||
|
||||
gtk_signal_connect (GTK_OBJECT (toggle), "toggled",
|
||||
(GtkSignalFunc) indexed_radio_update,
|
||||
&(dialog->fslowbleeddither_flag));
|
||||
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle), dialog->fslowbleeddither_flag);
|
||||
|
||||
gtk_widget_show (toggle);
|
||||
}
|
||||
gtk_widget_show (hbox);
|
||||
hbox = gtk_hbox_new (FALSE, 1);
|
||||
{
|
||||
gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
|
||||
|
||||
toggle = gtk_radio_button_new_with_label (group, _("Floyd-Steinberg colour dithering (normal)"));
|
||||
group = gtk_radio_button_group (GTK_RADIO_BUTTON (toggle));
|
||||
|
||||
gtk_box_pack_start (GTK_BOX (hbox), toggle, FALSE, FALSE, 0);
|
||||
|
@ -897,11 +922,13 @@ indexed_ok_callback (GtkWidget *widget,
|
|||
else
|
||||
palette_type = REUSE_PALETTE;
|
||||
|
||||
if (dialog->nodither_flag) dither_type = NODITHER;
|
||||
if (dialog->nodither_flag) dither_type = NO_DITHER;
|
||||
else
|
||||
if (dialog->fsdither_flag) dither_type = FSDITHER;
|
||||
if (dialog->fsdither_flag) dither_type = FS_DITHER;
|
||||
else
|
||||
dither_type = FIXEDDITHER;
|
||||
if (dialog->fslowbleeddither_flag) dither_type = FSLOWBLEED_DITHER;
|
||||
else
|
||||
dither_type = FIXED_DITHER;
|
||||
|
||||
/* Convert the image to indexed color */
|
||||
convert_image (dialog->gimage, INDEXED, dialog->num_cols,
|
||||
|
@ -914,6 +941,7 @@ indexed_ok_callback (GtkWidget *widget,
|
|||
snum_cols = dialog->num_cols;
|
||||
snodither_flag = dialog->nodither_flag;
|
||||
sfsdither_flag = dialog->fsdither_flag;
|
||||
sfslowbleeddither_flag = dialog->fslowbleeddither_flag;
|
||||
sfixeddither_flag = dialog->fixeddither_flag;
|
||||
salphadither_flag = dialog->alphadither;
|
||||
sremdups_flag = dialog->remdups;
|
||||
|
@ -1232,7 +1260,7 @@ convert_image (GImage *gimage,
|
|||
|
||||
/* don't dither if the input is grayscale and we are simply mapping every color */
|
||||
if (old_type == GRAY && num_cols == 256 && palette_type == MAKE_PALETTE)
|
||||
dither = NODITHER;
|
||||
dither = NO_DITHER;
|
||||
|
||||
quantobj = initialize_median_cut (old_type, num_cols, dither,
|
||||
palette_type, alpha_dither);
|
||||
|
@ -1288,7 +1316,7 @@ convert_image (GImage *gimage,
|
|||
|
||||
quantobj->delete_func (quantobj);
|
||||
quantobj = initialize_median_cut (old_type, num_cols,
|
||||
NODESTRUCTDITHER, palette_type,
|
||||
NODESTRUCT_DITHER, palette_type,
|
||||
alpha_dither);
|
||||
/* We can skip the first pass (palette creation) */
|
||||
|
||||
|
@ -3423,55 +3451,66 @@ median_cut_pass2_nodestruct_dither_rgb (QuantizeObj *quantobj,
|
|||
*/
|
||||
|
||||
static int *
|
||||
init_error_limit (void)
|
||||
init_error_limit (const int error_freedom)
|
||||
/* Allocate and fill in the error_limiter table */
|
||||
{
|
||||
int *table;
|
||||
int in, out;
|
||||
|
||||
/* #define STEPSIZE 16 */
|
||||
/* #define STEPSIZE 200 */
|
||||
|
||||
table = g_malloc (sizeof (int) * (255 * 2 + 1));
|
||||
table += 255; /* so we can index -255 ... +255 */
|
||||
|
||||
/* #define STEPSIZE 16 */
|
||||
#define STEPSIZE 200
|
||||
|
||||
for (in = 0; in < STEPSIZE; in++)
|
||||
if (error_freedom == 0)
|
||||
{
|
||||
table[in] = in;
|
||||
table[-in] = -in;
|
||||
/* Coarse function, much bleeding. */
|
||||
|
||||
const int STEPSIZE = 190;
|
||||
|
||||
for (in = 0; in < STEPSIZE; in++)
|
||||
{
|
||||
table[in] = in;
|
||||
table[-in] = -in;
|
||||
}
|
||||
for (; in <= 255; in++)
|
||||
{
|
||||
table[in] = STEPSIZE;
|
||||
table[-in] = -STEPSIZE;
|
||||
}
|
||||
return (table);
|
||||
}
|
||||
for (; in <= 255; in++)
|
||||
else
|
||||
{
|
||||
table[in] = STEPSIZE;
|
||||
table[-in] = -STEPSIZE;
|
||||
/* Smooth function, bleeding more constrained */
|
||||
|
||||
const int STEPSIZE = 24;
|
||||
|
||||
/* Map errors 1:1 up to +- STEPSIZE */
|
||||
out = 0;
|
||||
for (in = 0; in < STEPSIZE; in++, out++)
|
||||
{
|
||||
table[in] = out;
|
||||
table[-in] = -out;
|
||||
}
|
||||
|
||||
/* Map errors 1:2 up to +- 3*STEPSIZE */
|
||||
for (; in < STEPSIZE*3; in++, out += (in&1) ? 0 : 1)
|
||||
{
|
||||
table[in] = out;
|
||||
table[-in] = -out;
|
||||
}
|
||||
|
||||
/* Clamp the rest to final out value (which is STEPSIZE*2) */
|
||||
for (; in <= 255; in++)
|
||||
{
|
||||
table[in] = out;
|
||||
table[-in] = -out;
|
||||
}
|
||||
|
||||
return table;
|
||||
}
|
||||
return (table);
|
||||
|
||||
/* Map errors 1:1 up to +- 16 */
|
||||
out = 0;
|
||||
for (in = 0; in < STEPSIZE; in++, out++)
|
||||
{
|
||||
table[in] = out;
|
||||
table[-in] = -out;
|
||||
}
|
||||
|
||||
/* Map errors 1:2 up to +- 3*16 */
|
||||
for (; in < STEPSIZE*3; in++, out += (in&1) ? 0 : 1)
|
||||
{
|
||||
table[in] = out;
|
||||
table[-in] = -out;
|
||||
}
|
||||
|
||||
/* Clamp the rest to final out value (which is 32) */
|
||||
for (; in <= 255; in++)
|
||||
{
|
||||
table[in] = out;
|
||||
table[-in] = -out;
|
||||
}
|
||||
|
||||
#undef STEPSIZE
|
||||
|
||||
return table;
|
||||
}
|
||||
|
||||
|
||||
|
@ -3490,9 +3529,9 @@ median_cut_pass2_fs_dither_gray (QuantizeObj *quantobj,
|
|||
ColorFreq *cachep;
|
||||
Color *color;
|
||||
int *error_limiter;
|
||||
short *fs_err1, *fs_err2;
|
||||
short *fs_err3, *fs_err4;
|
||||
short *range_limiter;
|
||||
const short *fs_err1, *fs_err2;
|
||||
const short *fs_err3, *fs_err4;
|
||||
const short *range_limiter;
|
||||
int src_bytes, dest_bytes;
|
||||
unsigned char *src, *dest;
|
||||
unsigned char *src_buf, *dest_buf;
|
||||
|
@ -3521,7 +3560,7 @@ median_cut_pass2_fs_dither_gray (QuantizeObj *quantobj,
|
|||
width = GIMP_DRAWABLE(layer)->width;
|
||||
height = GIMP_DRAWABLE(layer)->height;
|
||||
|
||||
error_limiter = init_error_limit ();
|
||||
error_limiter = init_error_limit (quantobj->error_freedom);
|
||||
range_limiter = range_array + 256;
|
||||
|
||||
src_buf = g_malloc (width * src_bytes);
|
||||
|
@ -3686,9 +3725,9 @@ median_cut_pass2_fs_dither_rgb (QuantizeObj *quantobj,
|
|||
ColorFreq *cachep;
|
||||
Color *color;
|
||||
int *error_limiter;
|
||||
short *fs_err1, *fs_err2;
|
||||
short *fs_err3, *fs_err4;
|
||||
short *range_limiter;
|
||||
const short *fs_err1, *fs_err2;
|
||||
const short *fs_err3, *fs_err4;
|
||||
const short *range_limiter;
|
||||
int src_bytes, dest_bytes;
|
||||
unsigned char *src, *dest;
|
||||
unsigned char *src_buf, *dest_buf;
|
||||
|
@ -3733,7 +3772,7 @@ median_cut_pass2_fs_dither_rgb (QuantizeObj *quantobj,
|
|||
width = GIMP_DRAWABLE(layer)->width;
|
||||
height = GIMP_DRAWABLE(layer)->height;
|
||||
|
||||
error_limiter = init_error_limit ();
|
||||
error_limiter = init_error_limit (quantobj->error_freedom);
|
||||
range_limiter = range_array + 256;
|
||||
|
||||
src_buf = g_malloc (width * src_bytes);
|
||||
|
@ -3986,15 +4025,24 @@ initialize_median_cut (int type,
|
|||
palette_type == MONO_PALETTE || palette_type == CUSTOM_PALETTE)
|
||||
switch (dither_type)
|
||||
{
|
||||
case NODITHER:
|
||||
case NODESTRUCT_DITHER:
|
||||
default:
|
||||
g_warning("Uh-oh, bad dither type, W1");
|
||||
case NO_DITHER:
|
||||
quantobj->second_pass_init = median_cut_pass2_rgb_init;
|
||||
quantobj->second_pass = median_cut_pass2_no_dither_rgb;
|
||||
break;
|
||||
case FSDITHER:
|
||||
case FS_DITHER:
|
||||
quantobj->error_freedom = 0;
|
||||
quantobj->second_pass_init = median_cut_pass2_rgb_init;
|
||||
quantobj->second_pass = median_cut_pass2_fs_dither_rgb;
|
||||
break;
|
||||
case FIXEDDITHER:
|
||||
case FSLOWBLEED_DITHER:
|
||||
quantobj->error_freedom = 1;
|
||||
quantobj->second_pass_init = median_cut_pass2_rgb_init;
|
||||
quantobj->second_pass = median_cut_pass2_fs_dither_rgb;
|
||||
break;
|
||||
case FIXED_DITHER:
|
||||
quantobj->second_pass_init = median_cut_pass2_rgb_init;
|
||||
quantobj->second_pass = median_cut_pass2_fixed_dither_rgb;
|
||||
break;
|
||||
|
@ -4002,15 +4050,24 @@ initialize_median_cut (int type,
|
|||
else
|
||||
switch (dither_type)
|
||||
{
|
||||
case NODITHER:
|
||||
case NODESTRUCT_DITHER:
|
||||
default:
|
||||
g_warning("Uh-oh, bad dither type, W2");
|
||||
case NO_DITHER:
|
||||
quantobj->second_pass_init = median_cut_pass2_gray_init;
|
||||
quantobj->second_pass = median_cut_pass2_no_dither_gray;
|
||||
break;
|
||||
case FSDITHER:
|
||||
case FS_DITHER:
|
||||
quantobj->error_freedom = 0;
|
||||
quantobj->second_pass_init = median_cut_pass2_gray_init;
|
||||
quantobj->second_pass = median_cut_pass2_fs_dither_gray;
|
||||
break;
|
||||
case FIXEDDITHER:
|
||||
case FSLOWBLEED_DITHER:
|
||||
quantobj->error_freedom = 1;
|
||||
quantobj->second_pass_init = median_cut_pass2_gray_init;
|
||||
quantobj->second_pass = median_cut_pass2_fs_dither_gray;
|
||||
break;
|
||||
case FIXED_DITHER:
|
||||
quantobj->second_pass_init = median_cut_pass2_gray_init;
|
||||
quantobj->second_pass = median_cut_pass2_fixed_dither_gray;
|
||||
break;
|
||||
|
@ -4036,19 +4093,25 @@ initialize_median_cut (int type,
|
|||
}
|
||||
switch (dither_type)
|
||||
{
|
||||
case NODITHER:
|
||||
case NO_DITHER:
|
||||
quantobj->second_pass_init = median_cut_pass2_rgb_init;
|
||||
quantobj->second_pass = median_cut_pass2_no_dither_rgb;
|
||||
break;
|
||||
case FSDITHER:
|
||||
case FS_DITHER:
|
||||
quantobj->error_freedom = 0;
|
||||
quantobj->second_pass_init = median_cut_pass2_rgb_init;
|
||||
quantobj->second_pass = median_cut_pass2_fs_dither_rgb;
|
||||
break;
|
||||
case NODESTRUCTDITHER:
|
||||
case FSLOWBLEED_DITHER:
|
||||
quantobj->error_freedom = 1;
|
||||
quantobj->second_pass_init = median_cut_pass2_rgb_init;
|
||||
quantobj->second_pass = median_cut_pass2_fs_dither_rgb;
|
||||
break;
|
||||
case NODESTRUCT_DITHER:
|
||||
quantobj->second_pass_init = NULL;
|
||||
quantobj->second_pass = median_cut_pass2_nodestruct_dither_rgb;
|
||||
break;
|
||||
case FIXEDDITHER:
|
||||
case FIXED_DITHER:
|
||||
quantobj->second_pass_init = median_cut_pass2_rgb_init;
|
||||
quantobj->second_pass = median_cut_pass2_fixed_dither_rgb;
|
||||
break;
|
||||
|
|
|
@ -34,11 +34,12 @@ typedef enum {
|
|||
|
||||
/* adam's extra dither stuff */
|
||||
typedef enum {
|
||||
NODITHER = 0,
|
||||
FSDITHER = 1,
|
||||
FIXEDDITHER = 3,
|
||||
NO_DITHER = 0,
|
||||
FS_DITHER = 1,
|
||||
FSLOWBLEED_DITHER = 2,
|
||||
FIXED_DITHER = 3,
|
||||
|
||||
NODESTRUCTDITHER = 2 /* NEVER USE NODESTRUCTDITHER EXPLICITLY */
|
||||
NODESTRUCT_DITHER = 4 /* NEVER USE NODESTRUCT_DITHER EXPLICITLY */
|
||||
} ConvertDitherType;
|
||||
|
||||
#define MAXNUMCOLORS 256
|
||||
|
|
|
@ -29,8 +29,6 @@
|
|||
static ProcRecord convert_rgb_proc;
|
||||
static ProcRecord convert_grayscale_proc;
|
||||
static ProcRecord convert_indexed_proc;
|
||||
static ProcRecord convert_indexed_palette_proc;
|
||||
static ProcRecord convert_indexed2_proc;
|
||||
|
||||
void
|
||||
register_convert_procs (void)
|
||||
|
@ -38,8 +36,6 @@ register_convert_procs (void)
|
|||
procedural_db_register (&convert_rgb_proc);
|
||||
procedural_db_register (&convert_grayscale_proc);
|
||||
procedural_db_register (&convert_indexed_proc);
|
||||
procedural_db_register (&convert_indexed_palette_proc);
|
||||
procedural_db_register (&convert_indexed2_proc);
|
||||
}
|
||||
|
||||
static Argument *
|
||||
|
@ -128,240 +124,6 @@ static ProcRecord convert_grayscale_proc =
|
|||
|
||||
static Argument *
|
||||
convert_indexed_invoker (Argument *args)
|
||||
{
|
||||
gboolean success = TRUE;
|
||||
GimpImage *gimage;
|
||||
gint32 dither;
|
||||
gint32 num_cols;
|
||||
|
||||
gimage = pdb_id_to_image (args[0].value.pdb_int);
|
||||
if (gimage == NULL)
|
||||
success = FALSE;
|
||||
|
||||
dither = args[1].value.pdb_int;
|
||||
switch (dither)
|
||||
{
|
||||
case NODITHER:
|
||||
case FSDITHER:
|
||||
case FIXEDDITHER:
|
||||
case NODESTRUCTDITHER:
|
||||
break;
|
||||
|
||||
default:
|
||||
success = FALSE;
|
||||
break;
|
||||
}
|
||||
|
||||
num_cols = args[2].value.pdb_int;
|
||||
|
||||
if (success)
|
||||
{
|
||||
if ((success = gimage_base_type (gimage) != INDEXED))
|
||||
{
|
||||
switch (dither)
|
||||
{
|
||||
case NODITHER:
|
||||
case FSDITHER:
|
||||
case FIXEDDITHER:
|
||||
break;
|
||||
default:
|
||||
success = FALSE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (num_cols < 1 || num_cols > MAXNUMCOLORS)
|
||||
success = FALSE;
|
||||
|
||||
if (success)
|
||||
convert_image ((void *) gimage, INDEXED, num_cols, dither, 0, 1, 0);
|
||||
}
|
||||
|
||||
return procedural_db_return_args (&convert_indexed_proc, success);
|
||||
}
|
||||
|
||||
static ProcArg convert_indexed_inargs[] =
|
||||
{
|
||||
{
|
||||
PDB_IMAGE,
|
||||
"image",
|
||||
"The image"
|
||||
},
|
||||
{
|
||||
PDB_INT32,
|
||||
"dither",
|
||||
"dither type (0=none, 1=fs, 3=fixed)"
|
||||
},
|
||||
{
|
||||
PDB_INT32,
|
||||
"num_cols",
|
||||
"the number of colors to quantize to"
|
||||
}
|
||||
};
|
||||
|
||||
static ProcRecord convert_indexed_proc =
|
||||
{
|
||||
"gimp_convert_indexed",
|
||||
"Convert specified image to indexed color",
|
||||
"(Note: This procedure is deprecated in favour of convert_indexed2.) This procedure converts the specified image to indexed color. This process requires an image of type GRAY or RGB. The 'num_cols' arguments specifies how many colors the resulting image should be quantized to (1-256).",
|
||||
"Spencer Kimball & Peter Mattis",
|
||||
"Spencer Kimball & Peter Mattis",
|
||||
"1995-1996",
|
||||
PDB_INTERNAL,
|
||||
3,
|
||||
convert_indexed_inargs,
|
||||
0,
|
||||
NULL,
|
||||
{ { convert_indexed_invoker } }
|
||||
};
|
||||
|
||||
static Argument *
|
||||
convert_indexed_palette_invoker (Argument *args)
|
||||
{
|
||||
gboolean success = TRUE;
|
||||
GimpImage *gimage;
|
||||
gint32 dither;
|
||||
gint32 palette_type;
|
||||
gint32 num_cols;
|
||||
gchar *palette_name;
|
||||
|
||||
gimage = pdb_id_to_image (args[0].value.pdb_int);
|
||||
if (gimage == NULL)
|
||||
success = FALSE;
|
||||
|
||||
dither = args[1].value.pdb_int;
|
||||
switch (dither)
|
||||
{
|
||||
case NODITHER:
|
||||
case FSDITHER:
|
||||
case FIXEDDITHER:
|
||||
case NODESTRUCTDITHER:
|
||||
break;
|
||||
|
||||
default:
|
||||
success = FALSE;
|
||||
break;
|
||||
}
|
||||
|
||||
palette_type = args[2].value.pdb_int;
|
||||
|
||||
num_cols = args[3].value.pdb_int;
|
||||
|
||||
palette_name = (gchar *) args[4].value.pdb_pointer;
|
||||
if (palette_name == NULL)
|
||||
success = FALSE;
|
||||
|
||||
if (success)
|
||||
{
|
||||
if ((success = (gimage_base_type (gimage) != INDEXED)))
|
||||
{
|
||||
PaletteEntriesP entries, the_palette = NULL;
|
||||
GSList *list;
|
||||
|
||||
switch (dither)
|
||||
{
|
||||
case NODITHER:
|
||||
case FSDITHER:
|
||||
case FIXEDDITHER:
|
||||
break;
|
||||
default:
|
||||
success = FALSE;
|
||||
break;
|
||||
}
|
||||
|
||||
switch (palette_type)
|
||||
{
|
||||
case MAKE_PALETTE:
|
||||
if (num_cols < 1 || num_cols > MAXNUMCOLORS)
|
||||
success = FALSE;
|
||||
break;
|
||||
|
||||
case REUSE_PALETTE:
|
||||
case WEB_PALETTE:
|
||||
case MONO_PALETTE:
|
||||
break;
|
||||
|
||||
case CUSTOM_PALETTE:
|
||||
if (!palette_entries_list)
|
||||
palette_init_palettes (FALSE);
|
||||
|
||||
for (list = palette_entries_list; list; list = list->next)
|
||||
{
|
||||
entries = (PaletteEntriesP) list->data;
|
||||
if (!strcmp (palette_name, entries->name))
|
||||
{
|
||||
the_palette = entries;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (the_palette == NULL)
|
||||
success = FALSE;
|
||||
else
|
||||
theCustomPalette = the_palette;
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
success = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
if (success)
|
||||
convert_image ((void *) gimage, INDEXED, num_cols, dither, 0, 1,
|
||||
palette_type);
|
||||
}
|
||||
|
||||
return procedural_db_return_args (&convert_indexed_palette_proc, success);
|
||||
}
|
||||
|
||||
static ProcArg convert_indexed_palette_inargs[] =
|
||||
{
|
||||
{
|
||||
PDB_IMAGE,
|
||||
"image",
|
||||
"The image"
|
||||
},
|
||||
{
|
||||
PDB_INT32,
|
||||
"dither",
|
||||
"dither type (0=none, 1=fs, 3=fixed)"
|
||||
},
|
||||
{
|
||||
PDB_INT32,
|
||||
"palette_type",
|
||||
"The type of palette to use: { MAKE_PALETTE (0), REUSE_PALETTE (1), WEB_PALETTE (2), MONO_PALETTE (3), CUSTOM_PALETTE (4) }"
|
||||
},
|
||||
{
|
||||
PDB_INT32,
|
||||
"num_cols",
|
||||
"the number of colors to quantize to, ignored unless (palette_type == MAKE_PALETTE)"
|
||||
},
|
||||
{
|
||||
PDB_STRING,
|
||||
"palette",
|
||||
"The name of the custom palette to use, ignored unless (palette_type == CUSTOM_PALETTE)"
|
||||
}
|
||||
};
|
||||
|
||||
static ProcRecord convert_indexed_palette_proc =
|
||||
{
|
||||
"gimp_convert_indexed_palette",
|
||||
"Convert specified image to indexed color",
|
||||
"(Note: This procedure is deprecated in favour of convert_indexed2.) This procedure converts the specified image to indexed color. This process requires an image of type GRAY or RGB. The 'palette_type' specifies what kind of palette to use, A type of '0' means to use an optimal palette of 'num_cols' generated from the colors in the image. A type of '1' means to re-use the previous palette (not currently implemented). A type of '2' means to use the so-called WWW-optimized palette. Type '3' means to use only black and white colors. A type of '4' means to use a palette from the gimp palettes directories.",
|
||||
"Spencer Kimball & Peter Mattis",
|
||||
"Spencer Kimball & Peter Mattis",
|
||||
"1995-1996",
|
||||
PDB_INTERNAL,
|
||||
5,
|
||||
convert_indexed_palette_inargs,
|
||||
0,
|
||||
NULL,
|
||||
{ { convert_indexed_palette_invoker } }
|
||||
};
|
||||
|
||||
static Argument *
|
||||
convert_indexed2_invoker (Argument *args)
|
||||
{
|
||||
gboolean success = TRUE;
|
||||
GimpImage *gimage;
|
||||
|
@ -377,18 +139,8 @@ convert_indexed2_invoker (Argument *args)
|
|||
success = FALSE;
|
||||
|
||||
dither_type = args[1].value.pdb_int;
|
||||
switch (dither_type)
|
||||
{
|
||||
case NODITHER:
|
||||
case FSDITHER:
|
||||
case FIXEDDITHER:
|
||||
case NODESTRUCTDITHER:
|
||||
break;
|
||||
|
||||
default:
|
||||
success = FALSE;
|
||||
break;
|
||||
}
|
||||
if (dither_type < NO_DITHER || dither_type > NODESTRUCT_DITHER)
|
||||
success = FALSE;
|
||||
|
||||
palette_type = args[2].value.pdb_int;
|
||||
|
||||
|
@ -411,9 +163,10 @@ convert_indexed2_invoker (Argument *args)
|
|||
|
||||
switch (dither_type)
|
||||
{
|
||||
case NODITHER:
|
||||
case FSDITHER:
|
||||
case FIXEDDITHER:
|
||||
case NO_DITHER:
|
||||
case FS_DITHER:
|
||||
case FSLOWBLEED_DITHER:
|
||||
case FIXED_DITHER:
|
||||
break;
|
||||
default:
|
||||
success = FALSE;
|
||||
|
@ -463,10 +216,10 @@ convert_indexed2_invoker (Argument *args)
|
|||
alpha_dither, remove_unused, palette_type);
|
||||
}
|
||||
|
||||
return procedural_db_return_args (&convert_indexed2_proc, success);
|
||||
return procedural_db_return_args (&convert_indexed_proc, success);
|
||||
}
|
||||
|
||||
static ProcArg convert_indexed2_inargs[] =
|
||||
static ProcArg convert_indexed_inargs[] =
|
||||
{
|
||||
{
|
||||
PDB_IMAGE,
|
||||
|
@ -476,7 +229,7 @@ static ProcArg convert_indexed2_inargs[] =
|
|||
{
|
||||
PDB_INT32,
|
||||
"dither_type",
|
||||
"dither type (0=none, 1=fs, 3=fixed)"
|
||||
"dither type (0=none, 1=fs, 2=fs/low-bleed 3=fixed)"
|
||||
},
|
||||
{
|
||||
PDB_INT32,
|
||||
|
@ -505,18 +258,18 @@ static ProcArg convert_indexed2_inargs[] =
|
|||
}
|
||||
};
|
||||
|
||||
static ProcRecord convert_indexed2_proc =
|
||||
static ProcRecord convert_indexed_proc =
|
||||
{
|
||||
"gimp_convert_indexed2",
|
||||
"Convert specified image to indexed color",
|
||||
"This procedure converts the specified image to indexed color. This process requires an image of type GRAY or RGB. The 'palette_type' specifies what kind of palette to use, A type of '0' means to use an optimal palette of 'num_cols' generated from the colors in the image. A type of '1' means to re-use the previous palette (not currently implemented). A type of '2' means to use the so-called WWW-optimized palette. Type '3' means to use only black and white colors. A type of '4' means to use a palette from the gimp palettes directories. The 'dither type' specifies what kind of dithering to use. '0' means no dithering, '1' means standard Floyd-Steinberg error diffusion, '3' means dithering based on pixel location ('Fixed' dithering).",
|
||||
"gimp_convert_indexed",
|
||||
"Convert specified image to and Indexed image",
|
||||
"This procedure converts the specified image to 'indexed' color. This process requires an image of type GRAY or RGB. The 'palette_type' specifies what kind of palette to use, A type of '0' means to use an optimal palette of 'num_cols' generated from the colors in the image. A type of '1' means to re-use the previous palette (not currently implemented). A type of '2' means to use the so-called WWW-optimized palette. Type '3' means to use only black and white colors. A type of '4' means to use a palette from the gimp palettes directories. The 'dither type' specifies what kind of dithering to use. '0' means no dithering, '1' means standard Floyd-Steinberg error diffusion, '2' means Floyd-Steinberg error diffusion with reduced bleeding, '3' means dithering based on pixel location ('Fixed' dithering).",
|
||||
"Spencer Kimball & Peter Mattis",
|
||||
"Spencer Kimball & Peter Mattis",
|
||||
"1995-1996",
|
||||
PDB_INTERNAL,
|
||||
7,
|
||||
convert_indexed2_inargs,
|
||||
convert_indexed_inargs,
|
||||
0,
|
||||
NULL,
|
||||
{ { convert_indexed2_invoker } }
|
||||
{ { convert_indexed_invoker } }
|
||||
};
|
||||
|
|
|
@ -25,7 +25,8 @@
|
|||
* south-west pixels surrounding the current pixel respectively.
|
||||
*/
|
||||
|
||||
short range_array[] = {
|
||||
|
||||
const short range_array[] = {
|
||||
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, 0, 0, 0, 0, 0,
|
||||
|
@ -131,7 +132,7 @@ short range_array[] = {
|
|||
255, 255, 255, 255, 255,
|
||||
};
|
||||
|
||||
short floyd_steinberg_error1[] = {
|
||||
const short floyd_steinberg_error1[] = {
|
||||
-223, -223, -222, -222, -221, -221, -220, -220, -220, -219,
|
||||
-219, -218, -218, -217, -217, -217, -216, -216, -215, -215,
|
||||
-214, -214, -213, -213, -213, -212, -212, -211, -211, -210,
|
||||
|
@ -237,7 +238,7 @@ short floyd_steinberg_error1[] = {
|
|||
222, 223, 223, 224, 224,
|
||||
};
|
||||
|
||||
short floyd_steinberg_error2[] = {
|
||||
const short floyd_steinberg_error2[] = {
|
||||
-95, -95, -95, -95, -95, -94, -94, -94, -94, -94,
|
||||
-93, -93, -93, -93, -93, -93, -92, -92, -92, -92,
|
||||
-92, -91, -91, -91, -91, -91, -90, -90, -90, -90,
|
||||
|
@ -343,7 +344,7 @@ short floyd_steinberg_error2[] = {
|
|||
95, 95, 95, 96, 96,
|
||||
};
|
||||
|
||||
short floyd_steinberg_error3[] = {
|
||||
const short floyd_steinberg_error3[] = {
|
||||
-159, -159, -159, -158, -158, -158, -157, -157, -157, -156,
|
||||
-156, -156, -155, -155, -155, -155, -154, -154, -154, -153,
|
||||
-153, -153, -152, -152, -152, -151, -151, -151, -150, -150,
|
||||
|
@ -449,7 +450,7 @@ short floyd_steinberg_error3[] = {
|
|||
159, 159, 159, 160, 160,
|
||||
};
|
||||
|
||||
short floyd_steinberg_error4[] = {
|
||||
const short floyd_steinberg_error4[] = {
|
||||
-34, -33, -33, -33, -33, -33, -34, -33, -32, -33,
|
||||
-33, -33, -33, -33, -32, -31, -33, -32, -32, -32,
|
||||
-32, -32, -33, -32, -31, -32, -32, -32, -32, -32,
|
||||
|
|
|
@ -25,6 +25,8 @@
|
|||
*/
|
||||
|
||||
/*
|
||||
* 99/09/01 - Created a low-bleed FS-dither option. [Adam]
|
||||
*
|
||||
* 99/08/29 - Deterministic colour dithering to arbitrary palettes.
|
||||
* Ideal for animations that are going to be delta-optimized or simply
|
||||
* don't want to look 'busy' in static areas. Also a bunch of bugfixes
|
||||
|
@ -163,6 +165,8 @@ static const unsigned char webpal[] =
|
|||
0,51,0,0,0,255,0,0,204,0,0,153,0,0,102,0,0,51,0,0,0
|
||||
};
|
||||
|
||||
/* Note: convert.c code currently makes assumptions about some of the
|
||||
below defines, so small fixes are needed if they change... */
|
||||
#define DM_WIDTH 128
|
||||
#define DM_WIDTHMASK 127
|
||||
#define DM_WIDTH_SHIFT 7
|
||||
|
@ -333,6 +337,7 @@ struct _QuantizeObj
|
|||
Histogram histogram; /* holds the histogram */
|
||||
|
||||
int want_alpha_dither;
|
||||
int error_freedom; /* 0=much bleed, 1=controlled bleed */
|
||||
};
|
||||
|
||||
typedef struct
|
||||
|
@ -373,6 +378,7 @@ typedef struct
|
|||
GimpImage* gimage;
|
||||
int nodither_flag;
|
||||
int fsdither_flag;
|
||||
int fslowbleeddither_flag;
|
||||
int fixeddither_flag;
|
||||
int alphadither; /* flag */
|
||||
int remdups; /* flag */
|
||||
|
@ -423,17 +429,18 @@ PaletteEntriesP theCustomPalette = NULL;
|
|||
|
||||
|
||||
/* Defaults */
|
||||
static int snum_cols = 256;
|
||||
static gboolean sfsdither_flag = TRUE;
|
||||
static gboolean snodither_flag = FALSE;
|
||||
static gboolean sfixeddither_flag = FALSE;
|
||||
static gboolean smakepal_flag = TRUE;
|
||||
static gboolean salphadither_flag = FALSE;
|
||||
static gboolean sremdups_flag = TRUE;
|
||||
static gboolean swebpal_flag = FALSE;
|
||||
static gboolean scustompal_flag = FALSE;
|
||||
static gboolean smonopal_flag = FALSE;
|
||||
static gboolean sreusepal_flag = FALSE;
|
||||
static int snum_cols = 256;
|
||||
static gboolean sfsdither_flag = TRUE;
|
||||
static gboolean sfslowbleeddither_flag = TRUE;
|
||||
static gboolean snodither_flag = FALSE;
|
||||
static gboolean sfixeddither_flag = FALSE;
|
||||
static gboolean smakepal_flag = TRUE;
|
||||
static gboolean salphadither_flag = FALSE;
|
||||
static gboolean sremdups_flag = TRUE;
|
||||
static gboolean swebpal_flag = FALSE;
|
||||
static gboolean scustompal_flag = FALSE;
|
||||
static gboolean smonopal_flag = FALSE;
|
||||
static gboolean sreusepal_flag = FALSE;
|
||||
|
||||
|
||||
void
|
||||
|
@ -479,6 +486,7 @@ convert_to_indexed (GimpImage *gimage)
|
|||
dialog->num_cols = snum_cols;
|
||||
dialog->nodither_flag = snodither_flag;
|
||||
dialog->fsdither_flag = sfsdither_flag;
|
||||
dialog->fslowbleeddither_flag = sfslowbleeddither_flag;
|
||||
dialog->fixeddither_flag = sfixeddither_flag;
|
||||
dialog->alphadither = salphadither_flag;
|
||||
dialog->remdups = sremdups_flag;
|
||||
|
@ -683,7 +691,24 @@ convert_to_indexed (GimpImage *gimage)
|
|||
{
|
||||
gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
|
||||
|
||||
toggle = gtk_radio_button_new_with_label (group, _("Floyd-Steinberg colour dithering"));
|
||||
toggle = gtk_radio_button_new_with_label (group, _("Floyd-Steinberg colour dithering (reduced colour bleeding)"));
|
||||
group = gtk_radio_button_group (GTK_RADIO_BUTTON (toggle));
|
||||
|
||||
gtk_box_pack_start (GTK_BOX (hbox), toggle, FALSE, FALSE, 0);
|
||||
|
||||
gtk_signal_connect (GTK_OBJECT (toggle), "toggled",
|
||||
(GtkSignalFunc) indexed_radio_update,
|
||||
&(dialog->fslowbleeddither_flag));
|
||||
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle), dialog->fslowbleeddither_flag);
|
||||
|
||||
gtk_widget_show (toggle);
|
||||
}
|
||||
gtk_widget_show (hbox);
|
||||
hbox = gtk_hbox_new (FALSE, 1);
|
||||
{
|
||||
gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
|
||||
|
||||
toggle = gtk_radio_button_new_with_label (group, _("Floyd-Steinberg colour dithering (normal)"));
|
||||
group = gtk_radio_button_group (GTK_RADIO_BUTTON (toggle));
|
||||
|
||||
gtk_box_pack_start (GTK_BOX (hbox), toggle, FALSE, FALSE, 0);
|
||||
|
@ -897,11 +922,13 @@ indexed_ok_callback (GtkWidget *widget,
|
|||
else
|
||||
palette_type = REUSE_PALETTE;
|
||||
|
||||
if (dialog->nodither_flag) dither_type = NODITHER;
|
||||
if (dialog->nodither_flag) dither_type = NO_DITHER;
|
||||
else
|
||||
if (dialog->fsdither_flag) dither_type = FSDITHER;
|
||||
if (dialog->fsdither_flag) dither_type = FS_DITHER;
|
||||
else
|
||||
dither_type = FIXEDDITHER;
|
||||
if (dialog->fslowbleeddither_flag) dither_type = FSLOWBLEED_DITHER;
|
||||
else
|
||||
dither_type = FIXED_DITHER;
|
||||
|
||||
/* Convert the image to indexed color */
|
||||
convert_image (dialog->gimage, INDEXED, dialog->num_cols,
|
||||
|
@ -914,6 +941,7 @@ indexed_ok_callback (GtkWidget *widget,
|
|||
snum_cols = dialog->num_cols;
|
||||
snodither_flag = dialog->nodither_flag;
|
||||
sfsdither_flag = dialog->fsdither_flag;
|
||||
sfslowbleeddither_flag = dialog->fslowbleeddither_flag;
|
||||
sfixeddither_flag = dialog->fixeddither_flag;
|
||||
salphadither_flag = dialog->alphadither;
|
||||
sremdups_flag = dialog->remdups;
|
||||
|
@ -1232,7 +1260,7 @@ convert_image (GImage *gimage,
|
|||
|
||||
/* don't dither if the input is grayscale and we are simply mapping every color */
|
||||
if (old_type == GRAY && num_cols == 256 && palette_type == MAKE_PALETTE)
|
||||
dither = NODITHER;
|
||||
dither = NO_DITHER;
|
||||
|
||||
quantobj = initialize_median_cut (old_type, num_cols, dither,
|
||||
palette_type, alpha_dither);
|
||||
|
@ -1288,7 +1316,7 @@ convert_image (GImage *gimage,
|
|||
|
||||
quantobj->delete_func (quantobj);
|
||||
quantobj = initialize_median_cut (old_type, num_cols,
|
||||
NODESTRUCTDITHER, palette_type,
|
||||
NODESTRUCT_DITHER, palette_type,
|
||||
alpha_dither);
|
||||
/* We can skip the first pass (palette creation) */
|
||||
|
||||
|
@ -3423,55 +3451,66 @@ median_cut_pass2_nodestruct_dither_rgb (QuantizeObj *quantobj,
|
|||
*/
|
||||
|
||||
static int *
|
||||
init_error_limit (void)
|
||||
init_error_limit (const int error_freedom)
|
||||
/* Allocate and fill in the error_limiter table */
|
||||
{
|
||||
int *table;
|
||||
int in, out;
|
||||
|
||||
/* #define STEPSIZE 16 */
|
||||
/* #define STEPSIZE 200 */
|
||||
|
||||
table = g_malloc (sizeof (int) * (255 * 2 + 1));
|
||||
table += 255; /* so we can index -255 ... +255 */
|
||||
|
||||
/* #define STEPSIZE 16 */
|
||||
#define STEPSIZE 200
|
||||
|
||||
for (in = 0; in < STEPSIZE; in++)
|
||||
if (error_freedom == 0)
|
||||
{
|
||||
table[in] = in;
|
||||
table[-in] = -in;
|
||||
/* Coarse function, much bleeding. */
|
||||
|
||||
const int STEPSIZE = 190;
|
||||
|
||||
for (in = 0; in < STEPSIZE; in++)
|
||||
{
|
||||
table[in] = in;
|
||||
table[-in] = -in;
|
||||
}
|
||||
for (; in <= 255; in++)
|
||||
{
|
||||
table[in] = STEPSIZE;
|
||||
table[-in] = -STEPSIZE;
|
||||
}
|
||||
return (table);
|
||||
}
|
||||
for (; in <= 255; in++)
|
||||
else
|
||||
{
|
||||
table[in] = STEPSIZE;
|
||||
table[-in] = -STEPSIZE;
|
||||
/* Smooth function, bleeding more constrained */
|
||||
|
||||
const int STEPSIZE = 24;
|
||||
|
||||
/* Map errors 1:1 up to +- STEPSIZE */
|
||||
out = 0;
|
||||
for (in = 0; in < STEPSIZE; in++, out++)
|
||||
{
|
||||
table[in] = out;
|
||||
table[-in] = -out;
|
||||
}
|
||||
|
||||
/* Map errors 1:2 up to +- 3*STEPSIZE */
|
||||
for (; in < STEPSIZE*3; in++, out += (in&1) ? 0 : 1)
|
||||
{
|
||||
table[in] = out;
|
||||
table[-in] = -out;
|
||||
}
|
||||
|
||||
/* Clamp the rest to final out value (which is STEPSIZE*2) */
|
||||
for (; in <= 255; in++)
|
||||
{
|
||||
table[in] = out;
|
||||
table[-in] = -out;
|
||||
}
|
||||
|
||||
return table;
|
||||
}
|
||||
return (table);
|
||||
|
||||
/* Map errors 1:1 up to +- 16 */
|
||||
out = 0;
|
||||
for (in = 0; in < STEPSIZE; in++, out++)
|
||||
{
|
||||
table[in] = out;
|
||||
table[-in] = -out;
|
||||
}
|
||||
|
||||
/* Map errors 1:2 up to +- 3*16 */
|
||||
for (; in < STEPSIZE*3; in++, out += (in&1) ? 0 : 1)
|
||||
{
|
||||
table[in] = out;
|
||||
table[-in] = -out;
|
||||
}
|
||||
|
||||
/* Clamp the rest to final out value (which is 32) */
|
||||
for (; in <= 255; in++)
|
||||
{
|
||||
table[in] = out;
|
||||
table[-in] = -out;
|
||||
}
|
||||
|
||||
#undef STEPSIZE
|
||||
|
||||
return table;
|
||||
}
|
||||
|
||||
|
||||
|
@ -3490,9 +3529,9 @@ median_cut_pass2_fs_dither_gray (QuantizeObj *quantobj,
|
|||
ColorFreq *cachep;
|
||||
Color *color;
|
||||
int *error_limiter;
|
||||
short *fs_err1, *fs_err2;
|
||||
short *fs_err3, *fs_err4;
|
||||
short *range_limiter;
|
||||
const short *fs_err1, *fs_err2;
|
||||
const short *fs_err3, *fs_err4;
|
||||
const short *range_limiter;
|
||||
int src_bytes, dest_bytes;
|
||||
unsigned char *src, *dest;
|
||||
unsigned char *src_buf, *dest_buf;
|
||||
|
@ -3521,7 +3560,7 @@ median_cut_pass2_fs_dither_gray (QuantizeObj *quantobj,
|
|||
width = GIMP_DRAWABLE(layer)->width;
|
||||
height = GIMP_DRAWABLE(layer)->height;
|
||||
|
||||
error_limiter = init_error_limit ();
|
||||
error_limiter = init_error_limit (quantobj->error_freedom);
|
||||
range_limiter = range_array + 256;
|
||||
|
||||
src_buf = g_malloc (width * src_bytes);
|
||||
|
@ -3686,9 +3725,9 @@ median_cut_pass2_fs_dither_rgb (QuantizeObj *quantobj,
|
|||
ColorFreq *cachep;
|
||||
Color *color;
|
||||
int *error_limiter;
|
||||
short *fs_err1, *fs_err2;
|
||||
short *fs_err3, *fs_err4;
|
||||
short *range_limiter;
|
||||
const short *fs_err1, *fs_err2;
|
||||
const short *fs_err3, *fs_err4;
|
||||
const short *range_limiter;
|
||||
int src_bytes, dest_bytes;
|
||||
unsigned char *src, *dest;
|
||||
unsigned char *src_buf, *dest_buf;
|
||||
|
@ -3733,7 +3772,7 @@ median_cut_pass2_fs_dither_rgb (QuantizeObj *quantobj,
|
|||
width = GIMP_DRAWABLE(layer)->width;
|
||||
height = GIMP_DRAWABLE(layer)->height;
|
||||
|
||||
error_limiter = init_error_limit ();
|
||||
error_limiter = init_error_limit (quantobj->error_freedom);
|
||||
range_limiter = range_array + 256;
|
||||
|
||||
src_buf = g_malloc (width * src_bytes);
|
||||
|
@ -3986,15 +4025,24 @@ initialize_median_cut (int type,
|
|||
palette_type == MONO_PALETTE || palette_type == CUSTOM_PALETTE)
|
||||
switch (dither_type)
|
||||
{
|
||||
case NODITHER:
|
||||
case NODESTRUCT_DITHER:
|
||||
default:
|
||||
g_warning("Uh-oh, bad dither type, W1");
|
||||
case NO_DITHER:
|
||||
quantobj->second_pass_init = median_cut_pass2_rgb_init;
|
||||
quantobj->second_pass = median_cut_pass2_no_dither_rgb;
|
||||
break;
|
||||
case FSDITHER:
|
||||
case FS_DITHER:
|
||||
quantobj->error_freedom = 0;
|
||||
quantobj->second_pass_init = median_cut_pass2_rgb_init;
|
||||
quantobj->second_pass = median_cut_pass2_fs_dither_rgb;
|
||||
break;
|
||||
case FIXEDDITHER:
|
||||
case FSLOWBLEED_DITHER:
|
||||
quantobj->error_freedom = 1;
|
||||
quantobj->second_pass_init = median_cut_pass2_rgb_init;
|
||||
quantobj->second_pass = median_cut_pass2_fs_dither_rgb;
|
||||
break;
|
||||
case FIXED_DITHER:
|
||||
quantobj->second_pass_init = median_cut_pass2_rgb_init;
|
||||
quantobj->second_pass = median_cut_pass2_fixed_dither_rgb;
|
||||
break;
|
||||
|
@ -4002,15 +4050,24 @@ initialize_median_cut (int type,
|
|||
else
|
||||
switch (dither_type)
|
||||
{
|
||||
case NODITHER:
|
||||
case NODESTRUCT_DITHER:
|
||||
default:
|
||||
g_warning("Uh-oh, bad dither type, W2");
|
||||
case NO_DITHER:
|
||||
quantobj->second_pass_init = median_cut_pass2_gray_init;
|
||||
quantobj->second_pass = median_cut_pass2_no_dither_gray;
|
||||
break;
|
||||
case FSDITHER:
|
||||
case FS_DITHER:
|
||||
quantobj->error_freedom = 0;
|
||||
quantobj->second_pass_init = median_cut_pass2_gray_init;
|
||||
quantobj->second_pass = median_cut_pass2_fs_dither_gray;
|
||||
break;
|
||||
case FIXEDDITHER:
|
||||
case FSLOWBLEED_DITHER:
|
||||
quantobj->error_freedom = 1;
|
||||
quantobj->second_pass_init = median_cut_pass2_gray_init;
|
||||
quantobj->second_pass = median_cut_pass2_fs_dither_gray;
|
||||
break;
|
||||
case FIXED_DITHER:
|
||||
quantobj->second_pass_init = median_cut_pass2_gray_init;
|
||||
quantobj->second_pass = median_cut_pass2_fixed_dither_gray;
|
||||
break;
|
||||
|
@ -4036,19 +4093,25 @@ initialize_median_cut (int type,
|
|||
}
|
||||
switch (dither_type)
|
||||
{
|
||||
case NODITHER:
|
||||
case NO_DITHER:
|
||||
quantobj->second_pass_init = median_cut_pass2_rgb_init;
|
||||
quantobj->second_pass = median_cut_pass2_no_dither_rgb;
|
||||
break;
|
||||
case FSDITHER:
|
||||
case FS_DITHER:
|
||||
quantobj->error_freedom = 0;
|
||||
quantobj->second_pass_init = median_cut_pass2_rgb_init;
|
||||
quantobj->second_pass = median_cut_pass2_fs_dither_rgb;
|
||||
break;
|
||||
case NODESTRUCTDITHER:
|
||||
case FSLOWBLEED_DITHER:
|
||||
quantobj->error_freedom = 1;
|
||||
quantobj->second_pass_init = median_cut_pass2_rgb_init;
|
||||
quantobj->second_pass = median_cut_pass2_fs_dither_rgb;
|
||||
break;
|
||||
case NODESTRUCT_DITHER:
|
||||
quantobj->second_pass_init = NULL;
|
||||
quantobj->second_pass = median_cut_pass2_nodestruct_dither_rgb;
|
||||
break;
|
||||
case FIXEDDITHER:
|
||||
case FIXED_DITHER:
|
||||
quantobj->second_pass_init = median_cut_pass2_rgb_init;
|
||||
quantobj->second_pass = median_cut_pass2_fixed_dither_rgb;
|
||||
break;
|
||||
|
|
|
@ -34,11 +34,12 @@ typedef enum {
|
|||
|
||||
/* adam's extra dither stuff */
|
||||
typedef enum {
|
||||
NODITHER = 0,
|
||||
FSDITHER = 1,
|
||||
FIXEDDITHER = 3,
|
||||
NO_DITHER = 0,
|
||||
FS_DITHER = 1,
|
||||
FSLOWBLEED_DITHER = 2,
|
||||
FIXED_DITHER = 3,
|
||||
|
||||
NODESTRUCTDITHER = 2 /* NEVER USE NODESTRUCTDITHER EXPLICITLY */
|
||||
NODESTRUCT_DITHER = 4 /* NEVER USE NODESTRUCT_DITHER EXPLICITLY */
|
||||
} ConvertDitherType;
|
||||
|
||||
#define MAXNUMCOLORS 256
|
||||
|
|
|
@ -25,7 +25,8 @@
|
|||
* south-west pixels surrounding the current pixel respectively.
|
||||
*/
|
||||
|
||||
short range_array[] = {
|
||||
|
||||
const short range_array[] = {
|
||||
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, 0, 0, 0, 0, 0,
|
||||
|
@ -131,7 +132,7 @@ short range_array[] = {
|
|||
255, 255, 255, 255, 255,
|
||||
};
|
||||
|
||||
short floyd_steinberg_error1[] = {
|
||||
const short floyd_steinberg_error1[] = {
|
||||
-223, -223, -222, -222, -221, -221, -220, -220, -220, -219,
|
||||
-219, -218, -218, -217, -217, -217, -216, -216, -215, -215,
|
||||
-214, -214, -213, -213, -213, -212, -212, -211, -211, -210,
|
||||
|
@ -237,7 +238,7 @@ short floyd_steinberg_error1[] = {
|
|||
222, 223, 223, 224, 224,
|
||||
};
|
||||
|
||||
short floyd_steinberg_error2[] = {
|
||||
const short floyd_steinberg_error2[] = {
|
||||
-95, -95, -95, -95, -95, -94, -94, -94, -94, -94,
|
||||
-93, -93, -93, -93, -93, -93, -92, -92, -92, -92,
|
||||
-92, -91, -91, -91, -91, -91, -90, -90, -90, -90,
|
||||
|
@ -343,7 +344,7 @@ short floyd_steinberg_error2[] = {
|
|||
95, 95, 95, 96, 96,
|
||||
};
|
||||
|
||||
short floyd_steinberg_error3[] = {
|
||||
const short floyd_steinberg_error3[] = {
|
||||
-159, -159, -159, -158, -158, -158, -157, -157, -157, -156,
|
||||
-156, -156, -155, -155, -155, -155, -154, -154, -154, -153,
|
||||
-153, -153, -152, -152, -152, -151, -151, -151, -150, -150,
|
||||
|
@ -449,7 +450,7 @@ short floyd_steinberg_error3[] = {
|
|||
159, 159, 159, 160, 160,
|
||||
};
|
||||
|
||||
short floyd_steinberg_error4[] = {
|
||||
const short floyd_steinberg_error4[] = {
|
||||
-34, -33, -33, -33, -33, -33, -34, -33, -32, -33,
|
||||
-33, -33, -33, -33, -32, -31, -33, -32, -32, -32,
|
||||
-32, -32, -33, -32, -31, -32, -32, -32, -32, -32,
|
||||
|
|
|
@ -25,6 +25,8 @@
|
|||
*/
|
||||
|
||||
/*
|
||||
* 99/09/01 - Created a low-bleed FS-dither option. [Adam]
|
||||
*
|
||||
* 99/08/29 - Deterministic colour dithering to arbitrary palettes.
|
||||
* Ideal for animations that are going to be delta-optimized or simply
|
||||
* don't want to look 'busy' in static areas. Also a bunch of bugfixes
|
||||
|
@ -163,6 +165,8 @@ static const unsigned char webpal[] =
|
|||
0,51,0,0,0,255,0,0,204,0,0,153,0,0,102,0,0,51,0,0,0
|
||||
};
|
||||
|
||||
/* Note: convert.c code currently makes assumptions about some of the
|
||||
below defines, so small fixes are needed if they change... */
|
||||
#define DM_WIDTH 128
|
||||
#define DM_WIDTHMASK 127
|
||||
#define DM_WIDTH_SHIFT 7
|
||||
|
@ -333,6 +337,7 @@ struct _QuantizeObj
|
|||
Histogram histogram; /* holds the histogram */
|
||||
|
||||
int want_alpha_dither;
|
||||
int error_freedom; /* 0=much bleed, 1=controlled bleed */
|
||||
};
|
||||
|
||||
typedef struct
|
||||
|
@ -373,6 +378,7 @@ typedef struct
|
|||
GimpImage* gimage;
|
||||
int nodither_flag;
|
||||
int fsdither_flag;
|
||||
int fslowbleeddither_flag;
|
||||
int fixeddither_flag;
|
||||
int alphadither; /* flag */
|
||||
int remdups; /* flag */
|
||||
|
@ -423,17 +429,18 @@ PaletteEntriesP theCustomPalette = NULL;
|
|||
|
||||
|
||||
/* Defaults */
|
||||
static int snum_cols = 256;
|
||||
static gboolean sfsdither_flag = TRUE;
|
||||
static gboolean snodither_flag = FALSE;
|
||||
static gboolean sfixeddither_flag = FALSE;
|
||||
static gboolean smakepal_flag = TRUE;
|
||||
static gboolean salphadither_flag = FALSE;
|
||||
static gboolean sremdups_flag = TRUE;
|
||||
static gboolean swebpal_flag = FALSE;
|
||||
static gboolean scustompal_flag = FALSE;
|
||||
static gboolean smonopal_flag = FALSE;
|
||||
static gboolean sreusepal_flag = FALSE;
|
||||
static int snum_cols = 256;
|
||||
static gboolean sfsdither_flag = TRUE;
|
||||
static gboolean sfslowbleeddither_flag = TRUE;
|
||||
static gboolean snodither_flag = FALSE;
|
||||
static gboolean sfixeddither_flag = FALSE;
|
||||
static gboolean smakepal_flag = TRUE;
|
||||
static gboolean salphadither_flag = FALSE;
|
||||
static gboolean sremdups_flag = TRUE;
|
||||
static gboolean swebpal_flag = FALSE;
|
||||
static gboolean scustompal_flag = FALSE;
|
||||
static gboolean smonopal_flag = FALSE;
|
||||
static gboolean sreusepal_flag = FALSE;
|
||||
|
||||
|
||||
void
|
||||
|
@ -479,6 +486,7 @@ convert_to_indexed (GimpImage *gimage)
|
|||
dialog->num_cols = snum_cols;
|
||||
dialog->nodither_flag = snodither_flag;
|
||||
dialog->fsdither_flag = sfsdither_flag;
|
||||
dialog->fslowbleeddither_flag = sfslowbleeddither_flag;
|
||||
dialog->fixeddither_flag = sfixeddither_flag;
|
||||
dialog->alphadither = salphadither_flag;
|
||||
dialog->remdups = sremdups_flag;
|
||||
|
@ -683,7 +691,24 @@ convert_to_indexed (GimpImage *gimage)
|
|||
{
|
||||
gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
|
||||
|
||||
toggle = gtk_radio_button_new_with_label (group, _("Floyd-Steinberg colour dithering"));
|
||||
toggle = gtk_radio_button_new_with_label (group, _("Floyd-Steinberg colour dithering (reduced colour bleeding)"));
|
||||
group = gtk_radio_button_group (GTK_RADIO_BUTTON (toggle));
|
||||
|
||||
gtk_box_pack_start (GTK_BOX (hbox), toggle, FALSE, FALSE, 0);
|
||||
|
||||
gtk_signal_connect (GTK_OBJECT (toggle), "toggled",
|
||||
(GtkSignalFunc) indexed_radio_update,
|
||||
&(dialog->fslowbleeddither_flag));
|
||||
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle), dialog->fslowbleeddither_flag);
|
||||
|
||||
gtk_widget_show (toggle);
|
||||
}
|
||||
gtk_widget_show (hbox);
|
||||
hbox = gtk_hbox_new (FALSE, 1);
|
||||
{
|
||||
gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
|
||||
|
||||
toggle = gtk_radio_button_new_with_label (group, _("Floyd-Steinberg colour dithering (normal)"));
|
||||
group = gtk_radio_button_group (GTK_RADIO_BUTTON (toggle));
|
||||
|
||||
gtk_box_pack_start (GTK_BOX (hbox), toggle, FALSE, FALSE, 0);
|
||||
|
@ -897,11 +922,13 @@ indexed_ok_callback (GtkWidget *widget,
|
|||
else
|
||||
palette_type = REUSE_PALETTE;
|
||||
|
||||
if (dialog->nodither_flag) dither_type = NODITHER;
|
||||
if (dialog->nodither_flag) dither_type = NO_DITHER;
|
||||
else
|
||||
if (dialog->fsdither_flag) dither_type = FSDITHER;
|
||||
if (dialog->fsdither_flag) dither_type = FS_DITHER;
|
||||
else
|
||||
dither_type = FIXEDDITHER;
|
||||
if (dialog->fslowbleeddither_flag) dither_type = FSLOWBLEED_DITHER;
|
||||
else
|
||||
dither_type = FIXED_DITHER;
|
||||
|
||||
/* Convert the image to indexed color */
|
||||
convert_image (dialog->gimage, INDEXED, dialog->num_cols,
|
||||
|
@ -914,6 +941,7 @@ indexed_ok_callback (GtkWidget *widget,
|
|||
snum_cols = dialog->num_cols;
|
||||
snodither_flag = dialog->nodither_flag;
|
||||
sfsdither_flag = dialog->fsdither_flag;
|
||||
sfslowbleeddither_flag = dialog->fslowbleeddither_flag;
|
||||
sfixeddither_flag = dialog->fixeddither_flag;
|
||||
salphadither_flag = dialog->alphadither;
|
||||
sremdups_flag = dialog->remdups;
|
||||
|
@ -1232,7 +1260,7 @@ convert_image (GImage *gimage,
|
|||
|
||||
/* don't dither if the input is grayscale and we are simply mapping every color */
|
||||
if (old_type == GRAY && num_cols == 256 && palette_type == MAKE_PALETTE)
|
||||
dither = NODITHER;
|
||||
dither = NO_DITHER;
|
||||
|
||||
quantobj = initialize_median_cut (old_type, num_cols, dither,
|
||||
palette_type, alpha_dither);
|
||||
|
@ -1288,7 +1316,7 @@ convert_image (GImage *gimage,
|
|||
|
||||
quantobj->delete_func (quantobj);
|
||||
quantobj = initialize_median_cut (old_type, num_cols,
|
||||
NODESTRUCTDITHER, palette_type,
|
||||
NODESTRUCT_DITHER, palette_type,
|
||||
alpha_dither);
|
||||
/* We can skip the first pass (palette creation) */
|
||||
|
||||
|
@ -3423,55 +3451,66 @@ median_cut_pass2_nodestruct_dither_rgb (QuantizeObj *quantobj,
|
|||
*/
|
||||
|
||||
static int *
|
||||
init_error_limit (void)
|
||||
init_error_limit (const int error_freedom)
|
||||
/* Allocate and fill in the error_limiter table */
|
||||
{
|
||||
int *table;
|
||||
int in, out;
|
||||
|
||||
/* #define STEPSIZE 16 */
|
||||
/* #define STEPSIZE 200 */
|
||||
|
||||
table = g_malloc (sizeof (int) * (255 * 2 + 1));
|
||||
table += 255; /* so we can index -255 ... +255 */
|
||||
|
||||
/* #define STEPSIZE 16 */
|
||||
#define STEPSIZE 200
|
||||
|
||||
for (in = 0; in < STEPSIZE; in++)
|
||||
if (error_freedom == 0)
|
||||
{
|
||||
table[in] = in;
|
||||
table[-in] = -in;
|
||||
/* Coarse function, much bleeding. */
|
||||
|
||||
const int STEPSIZE = 190;
|
||||
|
||||
for (in = 0; in < STEPSIZE; in++)
|
||||
{
|
||||
table[in] = in;
|
||||
table[-in] = -in;
|
||||
}
|
||||
for (; in <= 255; in++)
|
||||
{
|
||||
table[in] = STEPSIZE;
|
||||
table[-in] = -STEPSIZE;
|
||||
}
|
||||
return (table);
|
||||
}
|
||||
for (; in <= 255; in++)
|
||||
else
|
||||
{
|
||||
table[in] = STEPSIZE;
|
||||
table[-in] = -STEPSIZE;
|
||||
/* Smooth function, bleeding more constrained */
|
||||
|
||||
const int STEPSIZE = 24;
|
||||
|
||||
/* Map errors 1:1 up to +- STEPSIZE */
|
||||
out = 0;
|
||||
for (in = 0; in < STEPSIZE; in++, out++)
|
||||
{
|
||||
table[in] = out;
|
||||
table[-in] = -out;
|
||||
}
|
||||
|
||||
/* Map errors 1:2 up to +- 3*STEPSIZE */
|
||||
for (; in < STEPSIZE*3; in++, out += (in&1) ? 0 : 1)
|
||||
{
|
||||
table[in] = out;
|
||||
table[-in] = -out;
|
||||
}
|
||||
|
||||
/* Clamp the rest to final out value (which is STEPSIZE*2) */
|
||||
for (; in <= 255; in++)
|
||||
{
|
||||
table[in] = out;
|
||||
table[-in] = -out;
|
||||
}
|
||||
|
||||
return table;
|
||||
}
|
||||
return (table);
|
||||
|
||||
/* Map errors 1:1 up to +- 16 */
|
||||
out = 0;
|
||||
for (in = 0; in < STEPSIZE; in++, out++)
|
||||
{
|
||||
table[in] = out;
|
||||
table[-in] = -out;
|
||||
}
|
||||
|
||||
/* Map errors 1:2 up to +- 3*16 */
|
||||
for (; in < STEPSIZE*3; in++, out += (in&1) ? 0 : 1)
|
||||
{
|
||||
table[in] = out;
|
||||
table[-in] = -out;
|
||||
}
|
||||
|
||||
/* Clamp the rest to final out value (which is 32) */
|
||||
for (; in <= 255; in++)
|
||||
{
|
||||
table[in] = out;
|
||||
table[-in] = -out;
|
||||
}
|
||||
|
||||
#undef STEPSIZE
|
||||
|
||||
return table;
|
||||
}
|
||||
|
||||
|
||||
|
@ -3490,9 +3529,9 @@ median_cut_pass2_fs_dither_gray (QuantizeObj *quantobj,
|
|||
ColorFreq *cachep;
|
||||
Color *color;
|
||||
int *error_limiter;
|
||||
short *fs_err1, *fs_err2;
|
||||
short *fs_err3, *fs_err4;
|
||||
short *range_limiter;
|
||||
const short *fs_err1, *fs_err2;
|
||||
const short *fs_err3, *fs_err4;
|
||||
const short *range_limiter;
|
||||
int src_bytes, dest_bytes;
|
||||
unsigned char *src, *dest;
|
||||
unsigned char *src_buf, *dest_buf;
|
||||
|
@ -3521,7 +3560,7 @@ median_cut_pass2_fs_dither_gray (QuantizeObj *quantobj,
|
|||
width = GIMP_DRAWABLE(layer)->width;
|
||||
height = GIMP_DRAWABLE(layer)->height;
|
||||
|
||||
error_limiter = init_error_limit ();
|
||||
error_limiter = init_error_limit (quantobj->error_freedom);
|
||||
range_limiter = range_array + 256;
|
||||
|
||||
src_buf = g_malloc (width * src_bytes);
|
||||
|
@ -3686,9 +3725,9 @@ median_cut_pass2_fs_dither_rgb (QuantizeObj *quantobj,
|
|||
ColorFreq *cachep;
|
||||
Color *color;
|
||||
int *error_limiter;
|
||||
short *fs_err1, *fs_err2;
|
||||
short *fs_err3, *fs_err4;
|
||||
short *range_limiter;
|
||||
const short *fs_err1, *fs_err2;
|
||||
const short *fs_err3, *fs_err4;
|
||||
const short *range_limiter;
|
||||
int src_bytes, dest_bytes;
|
||||
unsigned char *src, *dest;
|
||||
unsigned char *src_buf, *dest_buf;
|
||||
|
@ -3733,7 +3772,7 @@ median_cut_pass2_fs_dither_rgb (QuantizeObj *quantobj,
|
|||
width = GIMP_DRAWABLE(layer)->width;
|
||||
height = GIMP_DRAWABLE(layer)->height;
|
||||
|
||||
error_limiter = init_error_limit ();
|
||||
error_limiter = init_error_limit (quantobj->error_freedom);
|
||||
range_limiter = range_array + 256;
|
||||
|
||||
src_buf = g_malloc (width * src_bytes);
|
||||
|
@ -3986,15 +4025,24 @@ initialize_median_cut (int type,
|
|||
palette_type == MONO_PALETTE || palette_type == CUSTOM_PALETTE)
|
||||
switch (dither_type)
|
||||
{
|
||||
case NODITHER:
|
||||
case NODESTRUCT_DITHER:
|
||||
default:
|
||||
g_warning("Uh-oh, bad dither type, W1");
|
||||
case NO_DITHER:
|
||||
quantobj->second_pass_init = median_cut_pass2_rgb_init;
|
||||
quantobj->second_pass = median_cut_pass2_no_dither_rgb;
|
||||
break;
|
||||
case FSDITHER:
|
||||
case FS_DITHER:
|
||||
quantobj->error_freedom = 0;
|
||||
quantobj->second_pass_init = median_cut_pass2_rgb_init;
|
||||
quantobj->second_pass = median_cut_pass2_fs_dither_rgb;
|
||||
break;
|
||||
case FIXEDDITHER:
|
||||
case FSLOWBLEED_DITHER:
|
||||
quantobj->error_freedom = 1;
|
||||
quantobj->second_pass_init = median_cut_pass2_rgb_init;
|
||||
quantobj->second_pass = median_cut_pass2_fs_dither_rgb;
|
||||
break;
|
||||
case FIXED_DITHER:
|
||||
quantobj->second_pass_init = median_cut_pass2_rgb_init;
|
||||
quantobj->second_pass = median_cut_pass2_fixed_dither_rgb;
|
||||
break;
|
||||
|
@ -4002,15 +4050,24 @@ initialize_median_cut (int type,
|
|||
else
|
||||
switch (dither_type)
|
||||
{
|
||||
case NODITHER:
|
||||
case NODESTRUCT_DITHER:
|
||||
default:
|
||||
g_warning("Uh-oh, bad dither type, W2");
|
||||
case NO_DITHER:
|
||||
quantobj->second_pass_init = median_cut_pass2_gray_init;
|
||||
quantobj->second_pass = median_cut_pass2_no_dither_gray;
|
||||
break;
|
||||
case FSDITHER:
|
||||
case FS_DITHER:
|
||||
quantobj->error_freedom = 0;
|
||||
quantobj->second_pass_init = median_cut_pass2_gray_init;
|
||||
quantobj->second_pass = median_cut_pass2_fs_dither_gray;
|
||||
break;
|
||||
case FIXEDDITHER:
|
||||
case FSLOWBLEED_DITHER:
|
||||
quantobj->error_freedom = 1;
|
||||
quantobj->second_pass_init = median_cut_pass2_gray_init;
|
||||
quantobj->second_pass = median_cut_pass2_fs_dither_gray;
|
||||
break;
|
||||
case FIXED_DITHER:
|
||||
quantobj->second_pass_init = median_cut_pass2_gray_init;
|
||||
quantobj->second_pass = median_cut_pass2_fixed_dither_gray;
|
||||
break;
|
||||
|
@ -4036,19 +4093,25 @@ initialize_median_cut (int type,
|
|||
}
|
||||
switch (dither_type)
|
||||
{
|
||||
case NODITHER:
|
||||
case NO_DITHER:
|
||||
quantobj->second_pass_init = median_cut_pass2_rgb_init;
|
||||
quantobj->second_pass = median_cut_pass2_no_dither_rgb;
|
||||
break;
|
||||
case FSDITHER:
|
||||
case FS_DITHER:
|
||||
quantobj->error_freedom = 0;
|
||||
quantobj->second_pass_init = median_cut_pass2_rgb_init;
|
||||
quantobj->second_pass = median_cut_pass2_fs_dither_rgb;
|
||||
break;
|
||||
case NODESTRUCTDITHER:
|
||||
case FSLOWBLEED_DITHER:
|
||||
quantobj->error_freedom = 1;
|
||||
quantobj->second_pass_init = median_cut_pass2_rgb_init;
|
||||
quantobj->second_pass = median_cut_pass2_fs_dither_rgb;
|
||||
break;
|
||||
case NODESTRUCT_DITHER:
|
||||
quantobj->second_pass_init = NULL;
|
||||
quantobj->second_pass = median_cut_pass2_nodestruct_dither_rgb;
|
||||
break;
|
||||
case FIXEDDITHER:
|
||||
case FIXED_DITHER:
|
||||
quantobj->second_pass_init = median_cut_pass2_rgb_init;
|
||||
quantobj->second_pass = median_cut_pass2_fixed_dither_rgb;
|
||||
break;
|
||||
|
|
|
@ -34,11 +34,12 @@ typedef enum {
|
|||
|
||||
/* adam's extra dither stuff */
|
||||
typedef enum {
|
||||
NODITHER = 0,
|
||||
FSDITHER = 1,
|
||||
FIXEDDITHER = 3,
|
||||
NO_DITHER = 0,
|
||||
FS_DITHER = 1,
|
||||
FSLOWBLEED_DITHER = 2,
|
||||
FIXED_DITHER = 3,
|
||||
|
||||
NODESTRUCTDITHER = 2 /* NEVER USE NODESTRUCTDITHER EXPLICITLY */
|
||||
NODESTRUCT_DITHER = 4 /* NEVER USE NODESTRUCT_DITHER EXPLICITLY */
|
||||
} ConvertDitherType;
|
||||
|
||||
#define MAXNUMCOLORS 256
|
||||
|
|
|
@ -59,7 +59,7 @@ void register_tools_procs (void);
|
|||
void register_undo_procs (void);
|
||||
void register_unit_procs (void);
|
||||
|
||||
/* 311 procedures registered total */
|
||||
/* 309 procedures registered total */
|
||||
|
||||
void
|
||||
internal_procs_init (void)
|
||||
|
@ -73,87 +73,87 @@ internal_procs_init (void)
|
|||
app_init_update_status (NULL, _("Channel"), 0.045);
|
||||
register_channel_procs ();
|
||||
|
||||
app_init_update_status (NULL, _("Channel Ops"), 0.09);
|
||||
app_init_update_status (NULL, _("Channel Ops"), 0.091);
|
||||
register_channel_ops_procs ();
|
||||
|
||||
app_init_update_status (NULL, _("Color"), 0.096);
|
||||
app_init_update_status (NULL, _("Color"), 0.097);
|
||||
register_color_procs ();
|
||||
|
||||
app_init_update_status (NULL, _("Convert"), 0.135);
|
||||
app_init_update_status (NULL, _("Convert"), 0.136);
|
||||
register_convert_procs ();
|
||||
|
||||
app_init_update_status (NULL, _("Drawable procedures"), 0.151);
|
||||
app_init_update_status (NULL, _("Drawable procedures"), 0.146);
|
||||
register_drawable_procs ();
|
||||
|
||||
app_init_update_status (NULL, _("Edit procedures"), 0.222);
|
||||
app_init_update_status (NULL, _("Edit procedures"), 0.217);
|
||||
register_edit_procs ();
|
||||
|
||||
app_init_update_status (NULL, _("File Operations"), 0.241);
|
||||
app_init_update_status (NULL, _("File Operations"), 0.236);
|
||||
register_fileops_procs ();
|
||||
|
||||
app_init_update_status (NULL, _("Floating selections"), 0.26);
|
||||
app_init_update_status (NULL, _("Floating selections"), 0.256);
|
||||
register_floating_sel_procs ();
|
||||
|
||||
app_init_update_status (NULL, _("GDisplay procedures"), 0.28);
|
||||
app_init_update_status (NULL, _("GDisplay procedures"), 0.275);
|
||||
register_gdisplay_procs ();
|
||||
|
||||
app_init_update_status (NULL, _("Image"), 0.289);
|
||||
app_init_update_status (NULL, _("Image"), 0.285);
|
||||
register_gimage_procs ();
|
||||
|
||||
app_init_update_status (NULL, _("Image mask"), 0.469);
|
||||
app_init_update_status (NULL, _("Image mask"), 0.466);
|
||||
register_gimage_mask_procs ();
|
||||
|
||||
app_init_update_status (NULL, _("Gimprc procedures"), 0.524);
|
||||
app_init_update_status (NULL, _("Gimprc procedures"), 0.521);
|
||||
register_gimprc_procs ();
|
||||
|
||||
app_init_update_status (NULL, _("Gradients"), 0.534);
|
||||
app_init_update_status (NULL, _("Gradients"), 0.531);
|
||||
register_gradient_procs ();
|
||||
|
||||
app_init_update_status (NULL, _("Gradient UI"), 0.55);
|
||||
app_init_update_status (NULL, _("Gradient UI"), 0.547);
|
||||
register_gradient_select_procs ();
|
||||
|
||||
app_init_update_status (NULL, _("Guide procedures"), 0.563);
|
||||
app_init_update_status (NULL, _("Guide procedures"), 0.56);
|
||||
register_guides_procs ();
|
||||
|
||||
app_init_update_status (NULL, _("Interface"), 0.582);
|
||||
app_init_update_status (NULL, _("Interface"), 0.579);
|
||||
register_interface_procs ();
|
||||
|
||||
app_init_update_status (NULL, _("Layer"), 0.592);
|
||||
app_init_update_status (NULL, _("Layer"), 0.589);
|
||||
register_layer_procs ();
|
||||
|
||||
app_init_update_status (NULL, _("Miscellaneous"), 0.688);
|
||||
app_init_update_status (NULL, _("Miscellaneous"), 0.686);
|
||||
register_misc_procs ();
|
||||
|
||||
app_init_update_status (NULL, _("Palette"), 0.695);
|
||||
app_init_update_status (NULL, _("Palette"), 0.693);
|
||||
register_palette_procs ();
|
||||
|
||||
app_init_update_status (NULL, _("Parasite procedures"), 0.717);
|
||||
app_init_update_status (NULL, _("Parasite procedures"), 0.715);
|
||||
register_parasite_procs ();
|
||||
|
||||
app_init_update_status (NULL, _("Paths"), 0.759);
|
||||
app_init_update_status (NULL, _("Paths"), 0.757);
|
||||
register_paths_procs ();
|
||||
|
||||
app_init_update_status (NULL, _("Pattern UI"), 0.791);
|
||||
app_init_update_status (NULL, _("Pattern UI"), 0.79);
|
||||
register_pattern_select_procs ();
|
||||
|
||||
app_init_update_status (NULL, _("Patterns"), 0.801);
|
||||
app_init_update_status (NULL, _("Patterns"), 0.799);
|
||||
register_patterns_procs ();
|
||||
|
||||
app_init_update_status (NULL, _("Plug-in"), 0.814);
|
||||
app_init_update_status (NULL, _("Plug-in"), 0.812);
|
||||
register_plug_in_procs ();
|
||||
|
||||
app_init_update_status (NULL, _("Procedural database"), 0.826);
|
||||
app_init_update_status (NULL, _("Procedural database"), 0.825);
|
||||
register_procedural_db_procs ();
|
||||
|
||||
app_init_update_status (NULL, _("Text procedures"), 0.852);
|
||||
app_init_update_status (NULL, _("Text procedures"), 0.851);
|
||||
register_text_tool_procs ();
|
||||
|
||||
app_init_update_status (NULL, _("Tool procedures"), 0.865);
|
||||
app_init_update_status (NULL, _("Tool procedures"), 0.864);
|
||||
register_tools_procs ();
|
||||
|
||||
app_init_update_status (NULL, _("Undo"), 0.958);
|
||||
register_undo_procs ();
|
||||
|
||||
app_init_update_status (NULL, _("Units"), 0.965);
|
||||
app_init_update_status (NULL, _("Units"), 0.964);
|
||||
register_unit_procs ();
|
||||
}
|
||||
|
|
|
@ -249,13 +249,15 @@ package Gimp::CodeGen::enums;
|
|||
CUSTOM_PALETTE => '4' }
|
||||
},
|
||||
ConvertDitherType =>
|
||||
{ contig => 0,
|
||||
{ contig => 1,
|
||||
header => 'convert.h',
|
||||
symbols => [ qw(NODITHER FSDITHER FIXEDDITHER NODESTRUCTDITHER) ],
|
||||
mapping => { NODITHER => '0',
|
||||
FSDITHER => '1',
|
||||
FIXEDDITHER => '3',
|
||||
NODESTRUCTDITHER => '2' }
|
||||
symbols => [ qw(NO_DITHER FS_DITHER FSLOWBLEED_DITHER FIXED_DITHER
|
||||
NODESTRUCT_DITHER) ],
|
||||
mapping => { NO_DITHER => '0',
|
||||
FS_DITHER => '1',
|
||||
FSLOWBLEED_DITHER => '2',
|
||||
FIXED_DITHER => '3',
|
||||
NODESTRUCT_DITHER => '4' }
|
||||
},
|
||||
ConvolveType =>
|
||||
{ contig => 1,
|
||||
|
|
|
@ -61,159 +61,17 @@ HELP
|
|||
}
|
||||
|
||||
sub convert_indexed {
|
||||
$blurb = 'Convert specified image to indexed color';
|
||||
$blurb = 'Convert specified image to and Indexed image';
|
||||
|
||||
$help = <<'HELP';
|
||||
(Note: This procedure is deprecated in favour of convert_indexed2.) This procedure converts the specified image to indexed color. This process
|
||||
requires an image of type GRAY or RGB. The 'num_cols' arguments specifies how
|
||||
many colors the resulting image should be quantized to (1-256).
|
||||
HELP
|
||||
|
||||
&std_pdb_misc;
|
||||
|
||||
@inargs = (
|
||||
&std_image_arg,
|
||||
{ name => 'dither', type => 'enum ConvertDitherType',
|
||||
desc => 'dither type (0=none, 1=fs, 3=fixed)' },
|
||||
{ name => 'num_cols', type => 'int32',
|
||||
desc => 'the number of colors to quantize to' }
|
||||
);
|
||||
|
||||
%invoke = (
|
||||
code => <<'CODE'
|
||||
{
|
||||
if ((success = gimage_base_type (gimage) != INDEXED))
|
||||
{
|
||||
switch (dither)
|
||||
{
|
||||
case NODITHER:
|
||||
case FSDITHER:
|
||||
case FIXEDDITHER:
|
||||
break;
|
||||
default:
|
||||
success = FALSE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (num_cols < 1 || num_cols > MAXNUMCOLORS)
|
||||
success = FALSE;
|
||||
|
||||
if (success)
|
||||
convert_image ((void *) gimage, INDEXED, num_cols, dither, 0, 1, 0);
|
||||
}
|
||||
CODE
|
||||
);
|
||||
}
|
||||
|
||||
sub convert_indexed_palette {
|
||||
$blurb = 'Convert specified image to indexed color';
|
||||
|
||||
$help = <<'HELP';
|
||||
(Note: This procedure is deprecated in favour of convert_indexed2.) This procedure converts the specified image to indexed color. This process
|
||||
requires an image of type GRAY or RGB. The 'palette_type' specifies what kind
|
||||
of palette to use, A type of '0' means to use an optimal palette of 'num_cols'
|
||||
generated from the colors in the image. A type of '1' means to re-use the
|
||||
previous palette (not currently implemented). A type of '2' means to use the so-called WWW-optimized palette. Type
|
||||
'3' means to use only black and white colors. A type of '4' means to use a
|
||||
palette from the gimp palettes directories.
|
||||
HELP
|
||||
|
||||
&std_pdb_misc;
|
||||
|
||||
@inargs = (
|
||||
&std_image_arg,
|
||||
{ name => 'dither', type => 'enum ConvertDitherType',
|
||||
desc => 'dither type (0=none, 1=fs, 3=fixed)' },
|
||||
{ name => 'palette_type', type => 'enum ConvertPaletteType',
|
||||
desc => 'The type of palette to use: { %%desc%% }', no_success => 1 },
|
||||
{ name => 'num_cols', type => 'int32',
|
||||
desc => 'the number of colors to quantize to, ignored unless
|
||||
(palette_type == MAKE_PALETTE)' },
|
||||
{ name => 'palette', type => 'string',
|
||||
desc => 'The name of the custom palette to use, ignored unless
|
||||
(palette_type == CUSTOM_PALETTE)',
|
||||
alias => 'palette_name' }
|
||||
);
|
||||
|
||||
%invoke = (
|
||||
headers => [ qw(<string.h> "palette.h") ],
|
||||
code => <<'CODE'
|
||||
{
|
||||
if ((success = (gimage_base_type (gimage) != INDEXED)))
|
||||
{
|
||||
PaletteEntriesP entries, the_palette = NULL;
|
||||
GSList *list;
|
||||
|
||||
switch (dither)
|
||||
{
|
||||
case NODITHER:
|
||||
case FSDITHER:
|
||||
case FIXEDDITHER:
|
||||
break;
|
||||
default:
|
||||
success = FALSE;
|
||||
break;
|
||||
}
|
||||
|
||||
switch (palette_type)
|
||||
{
|
||||
case MAKE_PALETTE:
|
||||
if (num_cols < 1 || num_cols > MAXNUMCOLORS)
|
||||
success = FALSE;
|
||||
break;
|
||||
|
||||
case REUSE_PALETTE:
|
||||
case WEB_PALETTE:
|
||||
case MONO_PALETTE:
|
||||
break;
|
||||
|
||||
case CUSTOM_PALETTE:
|
||||
if (!palette_entries_list)
|
||||
palette_init_palettes (FALSE);
|
||||
|
||||
for (list = palette_entries_list; list; list = list->next)
|
||||
{
|
||||
entries = (PaletteEntriesP) list->data;
|
||||
if (!strcmp (palette_name, entries->name))
|
||||
{
|
||||
the_palette = entries;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (the_palette == NULL)
|
||||
success = FALSE;
|
||||
else
|
||||
theCustomPalette = the_palette;
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
success = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
if (success)
|
||||
convert_image ((void *) gimage, INDEXED, num_cols, dither, 0, 1,
|
||||
palette_type);
|
||||
}
|
||||
CODE
|
||||
);
|
||||
}
|
||||
|
||||
sub convert_indexed2 {
|
||||
$blurb = 'Convert specified image to indexed color';
|
||||
|
||||
$help = <<'HELP';
|
||||
This procedure converts the specified image to indexed color. This process
|
||||
This procedure converts the specified image to 'indexed' color. This process
|
||||
requires an image of type GRAY or RGB. The 'palette_type' specifies what kind
|
||||
of palette to use, A type of '0' means to use an optimal palette of 'num_cols'
|
||||
generated from the colors in the image. A type of '1' means to re-use the
|
||||
previous palette (not currently implemented). A type of '2' means to use the so-called WWW-optimized palette. Type
|
||||
'3' means to use only black and white colors. A type of '4' means to use a
|
||||
palette from the gimp palettes directories. The 'dither type' specifies
|
||||
what kind of dithering to use. '0' means no dithering, '1' means standard Floyd-Steinberg error diffusion, '3' means dithering based on pixel location ('Fixed' dithering).
|
||||
what kind of dithering to use. '0' means no dithering, '1' means standard Floyd-Steinberg error diffusion, '2' means Floyd-Steinberg error diffusion with reduced bleeding, '3' means dithering based on pixel location ('Fixed' dithering).
|
||||
HELP
|
||||
|
||||
&std_pdb_misc;
|
||||
|
@ -221,7 +79,7 @@ HELP
|
|||
@inargs = (
|
||||
&std_image_arg,
|
||||
{ name => 'dither_type', type => 'enum ConvertDitherType',
|
||||
desc => 'dither type (0=none, 1=fs, 3=fixed)' },
|
||||
desc => 'dither type (0=none, 1=fs, 2=fs/low-bleed 3=fixed)' },
|
||||
{ name => 'palette_type', type => 'enum ConvertPaletteType',
|
||||
desc => 'The type of palette to use: { %%desc%% }', no_success => 1 },
|
||||
{ name => 'num_cols', type => 'int32',
|
||||
|
@ -248,9 +106,10 @@ HELP
|
|||
|
||||
switch (dither_type)
|
||||
{
|
||||
case NODITHER:
|
||||
case FSDITHER:
|
||||
case FIXEDDITHER:
|
||||
case NO_DITHER:
|
||||
case FS_DITHER:
|
||||
case FSLOWBLEED_DITHER:
|
||||
case FIXED_DITHER:
|
||||
break;
|
||||
default:
|
||||
success = FALSE;
|
||||
|
@ -305,8 +164,7 @@ CODE
|
|||
|
||||
@headers = qw("gimage.h" "convert.h");
|
||||
|
||||
@procs = qw(convert_rgb convert_grayscale convert_indexed
|
||||
convert_indexed_palette convert_indexed2);
|
||||
@procs = qw(convert_rgb convert_grayscale convert_indexed);
|
||||
%exports = (app => [@procs]);
|
||||
|
||||
$desc = 'Convert';
|
||||
|
|
Loading…
Reference in New Issue