/* sample_colorize.c * A GIMP Plug-In by Wolfgang Hofer */ /* 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 * (2000/02/28) v1.1.17b hof: checkboard BG for transparent preview pixels * (2000/02/19) v1.1.17 hof: added spinbuttons for level entries and Reset Button * (1999/07/12) v1.0.2 hof: bugfix: progress is now updated properly * make use NLS Macros if available * (1999/03/08) v1.0.1 hof: dont show indexed layers in option menues * dst-Preview refresh needed at text entry callback * (1999/03/04) v1.0 hof: first public release * (1999/02/01) hof: started development */ #include "config.h" #include #include #include #include #ifdef __GNUC__ #warning GTK_DISABLE_DEPRECATED #endif #undef GTK_DISABLE_DEPRECATED #include #include #include #include "libgimp/stdplugins-intl.h" /* Some useful macros */ #define RESPONSE_RESET 1 #define RESPONSE_GET_COLORS 2 #define PLUG_IN_NAME "plug_in_sample_colorize" #define NUMBER_IN_ARGS 13 #define TILE_CACHE_SIZE 32 #define LUMINOSITY_0(X) ((X[0] * 30 + X[1] * 59 + X[2] * 11)) #define LUMINOSITY_1(X) ((X[0] * 30 + X[1] * 59 + X[2] * 11) / 100) #define MIX_CHANNEL(a, b, m) (((a * m) + (b * (255 - m))) / 255) #define SMP_GRADIENT -444 #define SMP_INV_GRADIENT -445 #define PREVIEW_BPP 3 #define PREVIEW_SIZE_X 256 #define PREVIEW_SIZE_Y 256 #define DA_WIDTH 256 #define DA_HEIGHT 25 #define GRADIENT_HEIGHT 15 #define CONTROL_HEIGHT DA_HEIGHT - GRADIENT_HEIGHT #define LEVELS_DA_MASK GDK_EXPOSURE_MASK | \ GDK_ENTER_NOTIFY_MASK | \ GDK_BUTTON_PRESS_MASK | \ GDK_BUTTON_RELEASE_MASK | \ GDK_BUTTON1_MOTION_MASK | \ GDK_POINTER_MOTION_HINT_MASK #define LOW_INPUT 0x1 #define GAMMA 0x2 #define HIGH_INPUT 0x4 #define LOW_OUTPUT 0x8 #define HIGH_OUTPUT 0x10 #define INPUT_LEVELS 0x20 #define OUTPUT_LEVELS 0x40 #define INPUT_SLIDERS 0x80 #define OUTPUT_SLIDERS 0x100 #define DRAW 0x200 #define REFRESH_DST 0x400 #define ALL 0xFFF #define MC_GET_SAMPLE_COLORS 1 #define MC_DST_REMAP 2 #define MC_ALL (MC_GET_SAMPLE_COLORS | MC_DST_REMAP) typedef struct { gint32 dst_id; gint32 sample_id; gint32 hold_inten; /* TRUE or FALSE */ gint32 orig_inten; /* TRUE or FALSE */ gint32 rnd_subcolors; /* TRUE or FALSE */ gint32 guess_missing; /* TRUE or FALSE */ gint32 lvl_in_min; /* 0 upto 254 */ gint32 lvl_in_max; /* 1 upto 255 */ float lvl_in_gamma; /* 0.1 upto 10.0 (1.0 == linear) */ gint32 lvl_out_min; /* 0 upto 254 */ gint32 lvl_out_max; /* 1 upto 255 */ float tol_col_err; /* 0.0% upto 100.0% * this is uesd to findout colors of the same * colortone, while analyzing sample colors, * It does not make much sense for the user to adjust this * value. (I used a param file to findout a suitable value) */ } t_values; typedef struct { GtkWidget *dialog; GtkWidget *sample_preview; GtkWidget *dst_preview; GtkWidget *sample_colortab_preview; GtkWidget *sample_drawarea; GtkWidget *in_lvl_gray_preview; GtkWidget *in_lvl_drawarea; GtkAdjustment *adj_lvl_in_min; GtkAdjustment *adj_lvl_in_max; GtkAdjustment *adj_lvl_in_gamma; GtkAdjustment *adj_lvl_out_min; GtkAdjustment *adj_lvl_out_max; GtkWidget *orig_inten_button; gint active_slider; gint slider_pos[5]; /* positions for the five sliders */ gint32 enable_preview_update; gint32 sample_show_selection; gint32 dst_show_selection; gint32 sample_show_color; gint32 dst_show_color; } t_samp_interface; typedef struct { guchar color[4]; /* R,G,B,A */ gint32 sum_color; /* nr. of sourcepixels with (nearly the same) color */ void *next; } t_samp_color_elem; typedef struct { gint32 all_samples; /* number of all source pixels with this luminosity */ gint from_sample; /* TRUE: color found in sample, FALSE: interpolated color added */ t_samp_color_elem *col_ptr; /* List of sample colors at same luminosity */ } t_samp_table_elem; typedef struct { GimpDrawable *drawable; void *sel_gdrw; GimpPixelRgn pr; gint x1; gint y1; gint x2; gint y2; gint index_alpha; /* 0 == no alpha, 1 == GREYA, 3 == RGBA */ gint bpp; GimpTile *tile; gint tile_row; gint tile_col; gint tile_width; gint tile_height; gint tile_dirty; gint shadow; gint32 seldeltax; gint32 seldeltay; gint32 tile_swapcount; } t_GDRW; /* * Some globals */ static GimpRunMode run_mode; static t_samp_interface g_di; /* global dialog interface varables */ static t_values g_values = { -1, -1, 1, 1, 0, 1, 0, 255, 1.0, 0, 255, 5.5 }; static t_samp_table_elem g_lum_tab[256]; static guchar g_lvl_trans_tab[256]; static guchar g_out_trans_tab[256]; static guchar g_sample_color_tab[256 * 3]; static guchar g_dst_preview_buffer[PREVIEW_SIZE_X * PREVIEW_SIZE_Y * 4 ]; /* color copy with mask of dst in previewsize */ static gint32 g_tol_col_err; static gint32 g_max_col_err; static gint g_Sdebug = FALSE; static gint g_show_progress = FALSE; /* Declare a local function. */ static void query (void); static void run (const gchar *name, gint nparams, const GimpParam *param, gint *nreturn_vals, GimpParam **return_vals); static gint p_main_colorize(gint); static void p_get_filevalues (void); static gint p_smp_dialog (void); static void p_refresh_dst_preview(GtkWidget *preview, guchar *src_buffer); static void p_update_preview(gint32 *id_ptr); static void p_clear_tables(void); static void p_free_colors(void); static void p_levels_update (gint update); static gint p_level_in_events (GtkWidget *widget, GdkEvent *event, gpointer data); static gint p_level_out_events (GtkWidget *widget, GdkEvent *event, gpointer data); static void p_calculate_level_transfers (void); static void p_get_pixel(t_GDRW *gdrw, gint32 x, gint32 y, guchar *pixel); static void p_init_gdrw(t_GDRW *gdrw, GimpDrawable *drawable, gint dirty, gint shadow); static void p_end_gdrw(t_GDRW *gdrw); static gint32 p_is_layer_alive(gint32 drawable_id); static void p_remap_pixel (guchar *pixel, const guchar *original, gint bpp2); static void p_guess_missing_colors(void); static void p_fill_missing_colors(void); static void p_smp_get_colors(GtkWidget *dialog); static void p_gradient_callback(GtkWidget *w, gint32 id); static void p_get_gradient (gint mode); static void p_clear_preview(GtkWidget *preview); GimpPlugInInfo PLUG_IN_INFO = { NULL, /* init_proc */ NULL, /* quit_proc */ query, /* query_proc */ run, /* run_proc */ }; MAIN () static void query (void) { static GimpParamDef args[]= { { GIMP_PDB_INT32, "run_mode", "Interactive, non-interactive" }, { GIMP_PDB_IMAGE, "image", "Input image (unused)" }, { GIMP_PDB_DRAWABLE, "dst_drawable", "The drawable to be colorized (Type GRAY* or RGB*)" }, { GIMP_PDB_DRAWABLE, "sample_drawable", "Sample drawable (should be of Type RGB or RGBA)" }, { GIMP_PDB_INT32, "hold_inten", "hold brightness intensity levels (TRUE, FALSE)" }, { GIMP_PDB_INT32, "orig_inten", "TRUE: hold brightness of original intensity levels. FALSE: Hold Intensity of input levels" }, { GIMP_PDB_INT32, "rnd_subcolors", "TRUE: Use all subcolors of same intensity, FALSE: use only one color per intensity" }, { GIMP_PDB_INT32, "guess_missing", "TRUE: guess samplecolors for the missing intensity values FALSE: use only colors found in the sample" }, { GIMP_PDB_INT32, "in_low", "intensity of lowest input (0 <= in_low <= 254)" }, { GIMP_PDB_INT32, "in_high", "intensity of highest input (1 <= in_high <= 255)" }, { GIMP_PDB_FLOAT, "gamma", "gamma correction factor (0.1 <= gamma <= 10) where 1.0 is linear" }, { GIMP_PDB_INT32, "out_low", "lowest sample color intensity (0 <= out_low <= 254)" }, { GIMP_PDB_INT32, "out_high", "highest sample color intensity (1 <= out_high <= 255)" } }; static gchar *help_string = "This plug-in colorizes the contents of the specified (gray) layer" " with the help of a sample (color) layer." " It analyzes all colors in the sample layer." " The sample colors are sorted by brightness (== intentisty) and amount" " and stored in a sample colortable (where brightness is the index)" " The pixels of the destination layer are remapped with the help of the" " sample colortable. If use_subcolors is TRUE, the remapping process uses" " all sample colors of the corresponding brightness-intensity and" " distributes the subcolors according to their amount in the sample" " (If the sample has 5 green, 3 yellow, and 1 red pixel of the " " intensity value 105, the destination pixels at intensity value 105" " are randomly painted in green, yellow and red in a relation of 5:3:1" " If use_subcolors is FALSE only one sample color per intensity is used." " (green will be used in this example)" " The brightness intensity value is transformed at the remapping process" " according to the levels: out_lo, out_hi, in_lo, in_high and gamma" " The in_low / in_high levels specify an initial mapping of the intensity." " The gamma value determines how intensities are interpolated between" " the in_lo and in_high levels. A gamma value of 1.0 results in linear" " interpolation. Higher gamma values results in more high-level intensities" " Lower gamma values results in more low-level intensities" " The out_low/out_high levels constrain the resulting intensity index" " The intensity index is used to pick the corresponding color" " in the sample colortable. If hold_inten is FALSE the picked color" " is used 1:1 as resulting remap_color." " If hold_inten is TRUE The brightness of the picked color is adjusted" " back to the origial intensity value (only hue and saturation are" " taken from the picked sample color)" " (or to the input level, if orig_inten is set FALSE)" " Works on both Grayscale and RGB image with/without alpha channel." " (the image with the dst_drawable is converted to RGB if necessary)" " The sample_drawable should be of type RGB or RGBA"; gimp_install_procedure (PLUG_IN_NAME, "Colorize the contents of the specified drawable similar to sample drawable", help_string, "Wolfgang Hofer", "hof@hotbot.com", "02/2000", N_("/Filters/Colors/Map/_Sample Colorize..."), "RGB*, GRAY*", GIMP_PLUGIN, G_N_ELEMENTS (args), 0, args, NULL); } static void run (const gchar *name, gint nparams, const GimpParam *param, gint *nreturn_vals, GimpParam **return_vals) { static GimpParam values[1]; GimpDrawable *dst_drawable; GimpPDBStatusType status = GIMP_PDB_SUCCESS; const gchar *l_env; INIT_I18N (); l_env = g_getenv ("SAMPLE_COLORIZE_DEBUG"); if (l_env != NULL) { if((*l_env != 'n') && (*l_env != 'N')) g_Sdebug = TRUE; } if(g_Sdebug) printf("sample colorize run\n"); g_show_progress = FALSE; run_mode = param[0].data.d_int32; *nreturn_vals = 1; *return_vals = values; values[0].type = GIMP_PDB_STATUS; values[0].data.d_status = status; g_values.lvl_out_min = 0; g_values.lvl_out_max = 255; g_values.lvl_in_min = 0; g_values.lvl_in_max = 255; g_values.lvl_in_gamma = 1.0; /* Possibly retrieve data from a previous run */ gimp_get_data (PLUG_IN_NAME, &g_values); /* fix value */ g_values.tol_col_err = 5.5; /* Get the specified dst_drawable */ g_values.dst_id = param[2].data.d_drawable; dst_drawable = gimp_drawable_get (g_values.dst_id ); p_clear_tables(); /* Make sure that the dst_drawable is gray or RGB color */ if (gimp_drawable_is_rgb (dst_drawable->drawable_id) || gimp_drawable_is_gray (dst_drawable->drawable_id)) { gimp_tile_cache_ntiles (TILE_CACHE_SIZE); if (run_mode == GIMP_RUN_INTERACTIVE) { p_smp_dialog(); p_free_colors(); gimp_set_data (PLUG_IN_NAME, &g_values, sizeof (t_values)); } else { if(run_mode == GIMP_RUN_NONINTERACTIVE) { if(nparams == NUMBER_IN_ARGS) { g_values.sample_id = param[3].data.d_drawable; g_values.hold_inten = param[4].data.d_int32; g_values.orig_inten = param[5].data.d_int32; g_values.rnd_subcolors = param[6].data.d_int32; g_values.guess_missing = param[7].data.d_int32; g_values.lvl_in_min = param[8].data.d_int32; g_values.lvl_in_max = param[9].data.d_int32; g_values.lvl_in_gamma = param[10].data.d_float; g_values.lvl_out_min = param[11].data.d_int32; g_values.lvl_out_max = param[12].data.d_int32; } else { status = GIMP_PDB_CALLING_ERROR; } } if(status != GIMP_PDB_CALLING_ERROR) { p_main_colorize(MC_ALL); p_free_colors(); } } if (run_mode != GIMP_RUN_NONINTERACTIVE) { gimp_displays_flush (); } } else { /* gimp_message ("Sample Colorize: cannot operate on indexed color images"); */ status = GIMP_PDB_EXECUTION_ERROR; } values[0].data.d_status = status; gimp_drawable_detach (dst_drawable); } /* ============================================================================ * callback and constraint procedures for the dialog * ============================================================================ */ static void p_smp_response_callback (GtkWidget *widget, gint response_id, gpointer data) { switch (response_id) { case RESPONSE_RESET: g_values.lvl_in_min = 0; g_values.lvl_in_max = 255; g_values.lvl_in_gamma = 1.0; g_values.lvl_out_min = 0; g_values.lvl_out_max = 255; p_levels_update (ALL); break; case RESPONSE_GET_COLORS: p_smp_get_colors (widget); break; case GTK_RESPONSE_APPLY: g_show_progress = TRUE; if(p_main_colorize(MC_DST_REMAP) == 0) { gimp_displays_flush (); g_show_progress = FALSE; return; } gtk_dialog_set_response_sensitive (GTK_DIALOG (widget), GTK_RESPONSE_APPLY, FALSE); break; default: gtk_widget_destroy (widget); gtk_main_quit (); break; } } static void p_smp_toggle_callback (GtkWidget *widget, gpointer data) { gint32 *toggle_val; toggle_val = (gint32 *) data; if (GTK_TOGGLE_BUTTON (widget)->active) { *toggle_val = TRUE; } else { *toggle_val = FALSE; } if((data == &g_di.sample_show_selection) || (data == &g_di.sample_show_color)) { p_update_preview(&g_values.sample_id); return; } if((data == &g_di.dst_show_selection) || (data == &g_di.dst_show_color)) { p_update_preview(&g_values.dst_id); return; } if((data == &g_values.hold_inten) || (data == &g_values.orig_inten) || (data == &g_values.rnd_subcolors)) { if(g_di.orig_inten_button) { gtk_widget_set_sensitive(g_di.orig_inten_button,g_values.hold_inten); } p_refresh_dst_preview(g_di.dst_preview, &g_dst_preview_buffer[0]); } if(data == &g_values.guess_missing) { if(g_values.guess_missing) { p_guess_missing_colors(); } else { p_fill_missing_colors(); } p_smp_get_colors (NULL); } } void p_gradient_callback(GtkWidget *w, gint32 id) { if(g_Sdebug) printf("GRADIENT_MENU_CB: widget %p, id: %d\n", w, (int)id); if((id == SMP_GRADIENT) || (id == SMP_INV_GRADIENT)) { g_values.sample_id = id; p_get_gradient(id); p_smp_get_colors (NULL); if(g_di.sample_preview) p_clear_preview(g_di.sample_preview); gtk_dialog_set_response_sensitive (GTK_DIALOG (g_di.dialog), GTK_RESPONSE_APPLY, TRUE); gtk_dialog_set_response_sensitive (GTK_DIALOG (g_di.dialog), RESPONSE_GET_COLORS, FALSE); } } /* end p_gradient_callback */ static void p_smp_menu_callback(gint32 id, gpointer data) { gint32 *id_ptr; if (g_Sdebug) printf("MENU_CB: id: %d, data %p, dst: %x, samp %x\n", id, data, (int)&g_values.sample_id, (int)&g_values.dst_id); if((id_ptr = (gint32 *)data) != NULL) { *id_ptr = id; p_update_preview(id_ptr); gtk_dialog_set_response_sensitive (GTK_DIALOG (g_di.dialog), RESPONSE_GET_COLORS, TRUE); } } /* end p_smp_menu_callback */ static gint p_smp_constrain(gint32 image_id, gint32 drawable_id, gpointer data) { if(image_id < 0) { return (FALSE); } /* dont accept layers from indexed images */ if (gimp_drawable_is_indexed(drawable_id)) { return (FALSE); } return (TRUE); } /* end p_smp_constrain */ static void p_smp_adj_lvl_in_max_upd_callback(GtkAdjustment *adjustment, gpointer data) { gint32 value; gint upd_flags; value = CLAMP ((adjustment->value), 1, 255); if (value != g_values.lvl_in_max) { g_values.lvl_in_max = value; upd_flags = INPUT_SLIDERS | INPUT_LEVELS | DRAW | REFRESH_DST; if(g_values.lvl_in_max < g_values.lvl_in_min) { g_values.lvl_in_min = g_values.lvl_in_max; upd_flags |= LOW_INPUT; } p_levels_update (upd_flags); } } static void p_smp_adj_lvl_in_min_upd_callback(GtkAdjustment *adjustment, gpointer data) { double value; gint upd_flags; value = CLAMP ((adjustment->value), 0, 254); if (value != g_values.lvl_in_min) { g_values.lvl_in_min = value; upd_flags = INPUT_SLIDERS | INPUT_LEVELS | DRAW | REFRESH_DST; if(g_values.lvl_in_min > g_values.lvl_in_max) { g_values.lvl_in_max = g_values.lvl_in_min; upd_flags |= HIGH_INPUT; } p_levels_update (upd_flags); } } static void p_smp_text_gamma_upd_callback(GtkAdjustment *adjustment, gpointer data) { double value; value = CLAMP ((adjustment->value), 0.1, 10.0); if (value != g_values.lvl_in_gamma) { g_values.lvl_in_gamma = value; p_levels_update (INPUT_SLIDERS | INPUT_LEVELS | DRAW | REFRESH_DST); } } static void p_smp_adj_lvl_out_max_upd_callback(GtkAdjustment *adjustment, gpointer data) { gint32 value; gint upd_flags; value = CLAMP ((adjustment->value), 1, 255); if (value != g_values.lvl_out_max) { g_values.lvl_out_max = value; upd_flags = OUTPUT_SLIDERS | OUTPUT_LEVELS | DRAW | REFRESH_DST; if(g_values.lvl_out_max < g_values.lvl_out_min) { g_values.lvl_out_min = g_values.lvl_out_max; upd_flags |= LOW_OUTPUT; } p_levels_update (upd_flags); } } static void p_smp_adj_lvl_out_min_upd_callback(GtkAdjustment *adjustment, gpointer data) { double value; gint upd_flags; value = CLAMP ((adjustment->value), 0, 254); if (value != g_values.lvl_out_min) { g_values.lvl_out_min = value; upd_flags = OUTPUT_SLIDERS | OUTPUT_LEVELS | DRAW | REFRESH_DST; if(g_values.lvl_out_min > g_values.lvl_out_max) { g_values.lvl_out_max = g_values.lvl_out_min; upd_flags |= HIGH_OUTPUT; } p_levels_update (upd_flags); } } /* ============================================================================ * DIALOG helper procedures * (workers for the updates on the preview widgets) * ============================================================================ */ void p_refresh_dst_preview(GtkWidget *preview, guchar *src_buffer) { guchar l_rowbuf[4 * PREVIEW_SIZE_X]; guchar *l_ptr; guchar *l_src_ptr; guchar l_lum; guchar l_maskbyte; gint l_x, l_y; gint l_preview_bpp; gint l_src_bpp; l_preview_bpp = PREVIEW_BPP; l_src_bpp = PREVIEW_BPP +1; /* 3 colors + 1 maskbyte */ l_src_ptr = src_buffer; for(l_y = 0; l_y < PREVIEW_SIZE_Y; l_y++) { l_ptr = &l_rowbuf[0]; for(l_x = 0; l_x < PREVIEW_SIZE_X; l_x++) { if((l_maskbyte = l_src_ptr[3]) == 0) { l_ptr[0] = l_src_ptr[0]; l_ptr[1] = l_src_ptr[1]; l_ptr[2] = l_src_ptr[2]; } else { if(g_di.dst_show_color) { p_remap_pixel(l_ptr, l_src_ptr, 3); } else { /* l_lum = g_out_trans_tab[g_lvl_trans_tab[LUMINOSITY_1(l_src_ptr)]]; */ /* get brightness from (uncolorized) original */ l_lum = g_lvl_trans_tab[LUMINOSITY_1(l_src_ptr)]; /* get brightness from (uncolorized) original */ *l_ptr = l_lum; l_ptr[1] = l_lum; l_ptr[2] = l_lum; } if(l_maskbyte < 255) { l_ptr[0] = MIX_CHANNEL(l_ptr[0], l_src_ptr[0], l_maskbyte); l_ptr[1] = MIX_CHANNEL(l_ptr[1], l_src_ptr[1], l_maskbyte); l_ptr[2] = MIX_CHANNEL(l_ptr[2], l_src_ptr[2], l_maskbyte); } } l_ptr += l_preview_bpp; l_src_ptr += l_src_bpp; } gtk_preview_draw_row(GTK_PREVIEW(preview), &l_rowbuf[0], 0, l_y, PREVIEW_SIZE_X); } gtk_widget_queue_draw(preview); } /* end p_refresh_dst_preview */ void p_clear_preview(GtkWidget *preview) { gint l_x, l_y; guchar l_rowbuf[4 * PREVIEW_SIZE_X]; guchar *l_ptr; l_ptr = &l_rowbuf[0]; for(l_x = 0; l_x < PREVIEW_SIZE_X; l_x++) { l_ptr[0] = 170; l_ptr[1] = 170; l_ptr[2] = 170; l_ptr += PREVIEW_BPP; } for(l_y = 0; l_y < PREVIEW_SIZE_Y; l_y++) { gtk_preview_draw_row(GTK_PREVIEW(preview), &l_rowbuf[0], 0, l_y, PREVIEW_SIZE_X); } gtk_widget_queue_draw(preview); } /* end p_clear_preview */ void p_update_pv (GtkWidget *preview, gint32 show_selection, t_GDRW *gdrw, guchar *dst_buffer, gint is_color) { guchar l_rowbuf[4 * PREVIEW_SIZE_X]; guchar l_pixel[4]; guchar *l_ptr; gint l_x, l_y; gint l_x2, l_y2; gint l_ofx, l_ofy; gint l_sel_width, l_sel_height; double l_scale_x, l_scale_y; guchar *l_buf_ptr; guchar l_dummy[4]; guchar l_maskbytes[4]; gint l_dstep; guchar l_check; guchar l_alpha; if(preview == NULL) return; /* init gray pixel (if we are called without a sourceimage (gdwr == NULL) */ l_pixel[0] = l_pixel[1] =l_pixel[2] = l_pixel[3] = 127; /* calculate scale factors and offsets */ if(show_selection) { l_sel_width = gdrw->x2 - gdrw->x1; l_sel_height = gdrw->y2 - gdrw->y1; if(l_sel_height > l_sel_width) { l_scale_y = (float)l_sel_height / PREVIEW_SIZE_Y; l_scale_x = l_scale_y; l_ofx = gdrw->x1 + ((l_sel_width - (PREVIEW_SIZE_X * l_scale_x)) / 2); l_ofy = gdrw->y1; } else { l_scale_x = (float)l_sel_width / PREVIEW_SIZE_X; l_scale_y = l_scale_x; l_ofx = gdrw->x1; l_ofy = gdrw->y1 + ((l_sel_height - (PREVIEW_SIZE_Y * l_scale_y)) / 2); } } else { if(gdrw->drawable->height > gdrw->drawable->width) { l_scale_y = (float)gdrw->drawable->height / PREVIEW_SIZE_Y; l_scale_x = l_scale_y; l_ofx = (gdrw->drawable->width - (PREVIEW_SIZE_X * l_scale_x)) / 2; l_ofy = 0; } else { l_scale_x = (float)gdrw->drawable->width / PREVIEW_SIZE_X; l_scale_y = l_scale_x; l_ofx = 0; l_ofy = (gdrw->drawable->height - (PREVIEW_SIZE_Y * l_scale_y)) / 2; } } /* check if output goes to previw widget or to dst_buffer */ if(dst_buffer) { l_buf_ptr = dst_buffer; l_dstep = PREVIEW_BPP +1; } else { l_buf_ptr = &l_dummy[0]; l_dstep = 0; } /* render preview */ for(l_y = 0; l_y < PREVIEW_SIZE_Y; l_y++) { l_ptr = &l_rowbuf[0]; for(l_x = 0; l_x < PREVIEW_SIZE_X; l_x++) { if(gdrw->drawable) { l_x2 = l_ofx + (l_x * l_scale_x); l_y2 = l_ofy + (l_y * l_scale_y); p_get_pixel(gdrw, l_x2, l_y2, &l_pixel[0]); if(gdrw->sel_gdrw) { p_get_pixel(gdrw->sel_gdrw, (l_x2 + gdrw->seldeltax), (l_y2 + gdrw->seldeltay), &l_maskbytes[0]); } else { l_maskbytes[0] = 255; } } l_alpha = l_pixel[gdrw->index_alpha]; if((gdrw->index_alpha == 0) /* has no alpha channel */ || (l_alpha == 255)) /* or is full opaque */ { if(is_color && (gdrw->bpp > 2)) { *l_buf_ptr = *l_ptr = l_pixel[0]; l_buf_ptr[1] = l_ptr[1] = l_pixel[1]; l_buf_ptr[2] = l_ptr[2] = l_pixel[2]; } else { if(gdrw->bpp > 2) *l_ptr = LUMINOSITY_1(l_pixel); else *l_ptr = l_pixel[0]; *l_buf_ptr = *l_ptr; /* copy to buffer (or to dummy byte) */ l_buf_ptr[1] = l_ptr[1] = *l_ptr; /* copy to buffer (or to dummy byte) */ l_buf_ptr[2] = l_ptr[2] = *l_ptr; /* copy to buffer (or to dummy byte) */ } l_buf_ptr[3] = l_maskbytes[0]; } else { if( ( l_y % (GIMP_CHECK_SIZE*2) < GIMP_CHECK_SIZE ) ^ ( l_x % (GIMP_CHECK_SIZE*2) < GIMP_CHECK_SIZE ) ) { l_check = GIMP_CHECK_LIGHT * 255; } else { l_check = GIMP_CHECK_DARK * 255; } if(l_alpha == 0) { /* full transparent */ *l_buf_ptr = *l_ptr = l_check; l_buf_ptr[1] = l_ptr[1] = l_check; l_buf_ptr[2] = l_ptr[2] = l_check; } else { /* more or less transparent */ if(is_color && (gdrw->bpp > 2)) { *l_buf_ptr = *l_ptr = MIX_CHANNEL(l_pixel[0], l_check, l_alpha); l_buf_ptr[1] = l_ptr[1] = MIX_CHANNEL(l_pixel[1], l_check, l_alpha); l_buf_ptr[2] = l_ptr[2] = MIX_CHANNEL(l_pixel[2], l_check, l_alpha); } else { if(gdrw->bpp > 2) *l_ptr = MIX_CHANNEL(LUMINOSITY_1(l_pixel), l_check, l_alpha); else *l_ptr = MIX_CHANNEL(l_pixel[0], l_check, l_alpha); *l_buf_ptr = *l_ptr; /* copy to buffer (or to dummy byte) */ l_buf_ptr[1] = l_ptr[1] = *l_ptr; /* copy to buffer (or to dummy byte) */ l_buf_ptr[2] = l_ptr[2] = *l_ptr; /* copy to buffer (or to dummy byte) */ } } l_buf_ptr[3] = MIN(l_maskbytes[0], l_alpha); } l_buf_ptr += l_dstep; /* advance (or stay at dummy byte) */ l_ptr += PREVIEW_BPP; } if(dst_buffer == NULL) { gtk_preview_draw_row(GTK_PREVIEW(preview), &l_rowbuf[0], 0, l_y, PREVIEW_SIZE_X); } } if(dst_buffer == NULL) { gtk_widget_queue_draw(preview); } } /* end p_update_pv */ void p_update_preview(gint32 *id_ptr) { GimpDrawable *drawable; t_GDRW l_gdrw; if(g_Sdebug) printf("UPD PREVIEWS ID:%d ENABLE_UPD:%d\n", (int)*id_ptr, (int)g_di.enable_preview_update); if(id_ptr == NULL) { return; } if(!g_di.enable_preview_update) { return; } if(p_is_layer_alive(*id_ptr) < 0) { /* clear preview on invalid drawable id * (SMP_GRADIENT and SMP_INV_GRADIENT) */ if(id_ptr == &g_values.sample_id) { p_clear_preview(g_di.sample_preview); } if(id_ptr == &g_values.dst_id) { p_clear_preview(g_di.dst_preview); } return; } drawable = gimp_drawable_get (*id_ptr); if(id_ptr == &g_values.sample_id) { p_init_gdrw(&l_gdrw, drawable, FALSE, FALSE); p_update_pv(g_di.sample_preview, g_di.sample_show_selection, &l_gdrw, NULL, g_di.sample_show_color); } else if (id_ptr == &g_values.dst_id) { p_init_gdrw(&l_gdrw, drawable, FALSE, FALSE); p_update_pv(g_di.dst_preview, g_di.dst_show_selection, &l_gdrw, &g_dst_preview_buffer[0], g_di.dst_show_color); p_refresh_dst_preview(g_di.dst_preview, &g_dst_preview_buffer[0]); } if(drawable) p_end_gdrw(&l_gdrw); } /* end p_update_preview */ static void p_levels_draw_slider (GdkWindow *window, GdkGC *border_gc, GdkGC *fill_gc, gint xpos) { gint y; for (y = 0; y < CONTROL_HEIGHT; y++) gdk_draw_line(window, fill_gc, xpos - y / 2, y, xpos + y / 2, y); gdk_draw_line(window, border_gc, xpos, 0, xpos - (CONTROL_HEIGHT - 1) / 2, CONTROL_HEIGHT - 1); gdk_draw_line(window, border_gc, xpos, 0, xpos + (CONTROL_HEIGHT - 1) / 2, CONTROL_HEIGHT - 1); gdk_draw_line(window, border_gc, xpos - (CONTROL_HEIGHT - 1) / 2, CONTROL_HEIGHT - 1, xpos + (CONTROL_HEIGHT - 1) / 2, CONTROL_HEIGHT - 1); } /* end p_levels_draw_slider */ static void p_levels_erase_slider (GdkWindow *window, gint xpos) { gdk_window_clear_area (window, xpos - (CONTROL_HEIGHT - 1) / 2, 0, CONTROL_HEIGHT - 1, CONTROL_HEIGHT); } /* end p_levels_erase_slider */ static void p_smp_get_colors (GtkWidget *dialog) { gint i; p_update_preview(&g_values.sample_id); if(dialog != NULL) { if (p_main_colorize(MC_GET_SAMPLE_COLORS) >= 0) /* do not colorize, just analyze sample colors */ { gtk_dialog_set_response_sensitive (GTK_DIALOG (g_di.dialog), GTK_RESPONSE_APPLY, TRUE); } } for (i = 0; i < GRADIENT_HEIGHT; i++) { gtk_preview_draw_row (GTK_PREVIEW (g_di.sample_colortab_preview), &g_sample_color_tab[0], 0, i, DA_WIDTH); } p_update_preview(&g_values.dst_id); gtk_widget_queue_draw (g_di.sample_colortab_preview); } static void p_levels_update (gint update) { gint i; if(g_Sdebug) printf("p_levels_update: update reques %x\n", update); /* Recalculate the transfer array */ p_calculate_level_transfers(); if (update & REFRESH_DST) { p_refresh_dst_preview(g_di.dst_preview, &g_dst_preview_buffer[0]); } /* update the spinbutton entry widgets */ if (update & LOW_INPUT) { gtk_adjustment_set_value (g_di.adj_lvl_in_min, g_values.lvl_in_min); } if (update & GAMMA) { gtk_adjustment_set_value (g_di.adj_lvl_in_gamma, g_values.lvl_in_gamma); } if (update & HIGH_INPUT) { gtk_adjustment_set_value (g_di.adj_lvl_in_max, g_values.lvl_in_max); } if (update & LOW_OUTPUT) { gtk_adjustment_set_value (g_di.adj_lvl_out_min, g_values.lvl_out_min); } if (update & HIGH_OUTPUT) { gtk_adjustment_set_value (g_di.adj_lvl_out_max, g_values.lvl_out_max); } if (update & INPUT_LEVELS) { for (i = 0; i < GRADIENT_HEIGHT; i++) { gtk_preview_draw_row (GTK_PREVIEW (g_di.in_lvl_gray_preview), &g_lvl_trans_tab[0], 0, i, DA_WIDTH); } if (update & DRAW) { gtk_widget_queue_draw (g_di.in_lvl_gray_preview); } } if (update & INPUT_SLIDERS) { double width, mid, tmp; p_levels_erase_slider (g_di.in_lvl_drawarea->window, g_di.slider_pos[0]); p_levels_erase_slider (g_di.in_lvl_drawarea->window, g_di.slider_pos[1]); p_levels_erase_slider (g_di.in_lvl_drawarea->window, g_di.slider_pos[2]); g_di.slider_pos[0] = DA_WIDTH * ((double) g_values.lvl_in_min / 255.0); g_di.slider_pos[2] = DA_WIDTH * ((double) g_values.lvl_in_max / 255.0); width = (double) (g_di.slider_pos[2] - g_di.slider_pos[0]) / 2.0; mid = g_di.slider_pos[0] + width; tmp = log10 (1.0 / g_values.lvl_in_gamma); g_di.slider_pos[1] = (int) (mid + width * tmp + 0.5); p_levels_draw_slider (g_di.in_lvl_drawarea->window, g_di.in_lvl_drawarea->style->black_gc, g_di.in_lvl_drawarea->style->dark_gc[GTK_STATE_NORMAL], g_di.slider_pos[1]); p_levels_draw_slider (g_di.in_lvl_drawarea->window, g_di.in_lvl_drawarea->style->black_gc, g_di.in_lvl_drawarea->style->black_gc, g_di.slider_pos[0]); p_levels_draw_slider (g_di.in_lvl_drawarea->window, g_di.in_lvl_drawarea->style->black_gc, g_di.in_lvl_drawarea->style->white_gc, g_di.slider_pos[2]); } if (update & OUTPUT_SLIDERS) { p_levels_erase_slider (g_di.sample_drawarea->window, g_di.slider_pos[3]); p_levels_erase_slider (g_di.sample_drawarea->window, g_di.slider_pos[4]); g_di.slider_pos[3] = DA_WIDTH * ((double) g_values.lvl_out_min / 255.0); g_di.slider_pos[4] = DA_WIDTH * ((double) g_values.lvl_out_max / 255.0); p_levels_draw_slider (g_di.sample_drawarea->window, g_di.sample_drawarea->style->black_gc, g_di.sample_drawarea->style->black_gc, g_di.slider_pos[3]); p_levels_draw_slider (g_di.sample_drawarea->window, g_di.sample_drawarea->style->black_gc, g_di.sample_drawarea->style->black_gc, g_di.slider_pos[4]); } } /* end p_levels_update */ static gint p_level_in_events (GtkWidget *widget, GdkEvent *event, gpointer data) { GdkEventButton *bevent; GdkEventMotion *mevent; gchar text[20]; double width, mid, tmp; gint x, distance; gint i; gint update = FALSE; switch (event->type) { case GDK_EXPOSE: if(g_Sdebug) printf("EVENT: GDK_EXPOSE\n"); if (widget == g_di.in_lvl_drawarea) { p_levels_update (INPUT_SLIDERS); } break; case GDK_BUTTON_PRESS: if(g_Sdebug) printf("EVENT: GDK_BUTTON_PRESS\n"); gtk_grab_add (widget); bevent = (GdkEventButton *) event; distance = G_MAXINT; for (i = 0; i < 3; i++) { if (fabs (bevent->x - g_di.slider_pos[i]) < distance) { g_di.active_slider = i; distance = fabs (bevent->x - g_di.slider_pos[i]); } } x = bevent->x; update = TRUE; break; case GDK_BUTTON_RELEASE: if(g_Sdebug) printf("EVENT: GDK_BUTTON_RELEASE\n"); gtk_grab_remove (widget); switch (g_di.active_slider) { case 0: /* low input */ p_levels_update (LOW_INPUT | GAMMA | DRAW); break; case 1: /* gamma */ p_levels_update (GAMMA); break; case 2: /* high input */ p_levels_update (HIGH_INPUT | GAMMA | DRAW); break; } p_refresh_dst_preview(g_di.dst_preview, &g_dst_preview_buffer[0]); break; case GDK_MOTION_NOTIFY: if(g_Sdebug) printf("EVENT: GDK_MOTION_NOTIFY\n"); mevent = (GdkEventMotion *) event; gdk_window_get_pointer (widget->window, &x, NULL, NULL); update = TRUE; break; default: if(g_Sdebug) printf("EVENT: default\n"); break; } if (update) { if(g_Sdebug) printf("EVENT: ** update **\n"); switch (g_di.active_slider) { case 0: /* low input */ g_values.lvl_in_min = ((double) x / (double) DA_WIDTH) * 255.0; g_values.lvl_in_min = CLAMP (g_values.lvl_in_min, 0, g_values.lvl_in_max); break; case 1: /* gamma */ width = (double) (g_di.slider_pos[2] - g_di.slider_pos[0]) / 2.0; mid = g_di.slider_pos[0] + width; x = CLAMP (x, g_di.slider_pos[0], g_di.slider_pos[2]); tmp = (double) (x - mid) / width; g_values.lvl_in_gamma = 1.0 / pow (10, tmp); /* round the gamma value to the nearest 1/100th */ sprintf (text, "%2.2f", g_values.lvl_in_gamma); g_values.lvl_in_gamma = atof (text); break; case 2: /* high input */ g_values.lvl_in_max = ((double) x / (double) DA_WIDTH) * 255.0; g_values.lvl_in_max = CLAMP (g_values.lvl_in_max, g_values.lvl_in_min, 255); break; } p_levels_update (INPUT_SLIDERS | INPUT_LEVELS | DRAW); } return FALSE; } /* end p_level_in_events */ static gint p_level_out_events (GtkWidget *widget, GdkEvent *event, gpointer data) { GdkEventButton *bevent; GdkEventMotion *mevent; gint x, distance; gint i; gint update = FALSE; switch (event->type) { case GDK_EXPOSE: if(g_Sdebug) printf("OUT_EVENT: GDK_EXPOSE\n"); if (widget == g_di.sample_drawarea) { p_levels_update (OUTPUT_SLIDERS); } break; case GDK_BUTTON_PRESS: if(g_Sdebug) printf("OUT_EVENT: GDK_BUTTON_PRESS\n"); bevent = (GdkEventButton *) event; distance = G_MAXINT; for (i = 3; i < 5; i++) { if (fabs (bevent->x - g_di.slider_pos[i]) < distance) { g_di.active_slider = i; distance = fabs (bevent->x - g_di.slider_pos[i]); } } x = bevent->x; update = TRUE; break; case GDK_BUTTON_RELEASE: if(g_Sdebug) printf("OUT_EVENT: GDK_BUTTON_RELEASE\n"); switch (g_di.active_slider) { case 3: /* low output */ p_levels_update (LOW_OUTPUT | DRAW); break; case 4: /* high output */ p_levels_update (HIGH_OUTPUT | DRAW); break; } p_refresh_dst_preview(g_di.dst_preview, &g_dst_preview_buffer[0]); break; case GDK_MOTION_NOTIFY: if(g_Sdebug) printf("OUT_EVENT: GDK_MOTION_NOTIFY\n"); mevent = (GdkEventMotion *) event; gdk_window_get_pointer (widget->window, &x, NULL, NULL); update = TRUE; break; default: if(g_Sdebug) printf("OUT_EVENT: default\n"); break; } if (update) { if(g_Sdebug) printf("OUT_EVENT: ** update **\n"); switch (g_di.active_slider) { case 3: /* low output */ g_values.lvl_out_min = ((double) x / (double) DA_WIDTH) * 255.0; g_values.lvl_out_min = CLAMP (g_values.lvl_out_min, 0, g_values.lvl_out_max); break; case 4: /* high output */ g_values.lvl_out_max = ((double) x / (double) DA_WIDTH) * 255.0; g_values.lvl_out_max = CLAMP (g_values.lvl_out_max, g_values.lvl_out_min, 255); break; } p_levels_update (OUTPUT_SLIDERS | OUTPUT_LEVELS | DRAW); } return FALSE; } /* end p_level_out_events */ /* ============================================================================ * p_smp_dialog * The Interactive Dialog * ============================================================================ */ static int p_smp_dialog (void) { GtkWidget *dialog; GtkWidget *hbox; GtkWidget *vbox2; GtkWidget *frame; GtkWidget *pframe; GtkWidget *table; GtkWidget *check_button; GtkWidget *label; GtkWidget *option_menu; GtkWidget *menu; GtkWidget *menu_item; GtkWidget *spinbutton; GtkWidget *sep; GtkObject *data; gint l_ty; /* set flags for check buttons from mode value bits */ if (g_Sdebug) g_print ("p_smp_dialog START\n"); /* init some dialog variables */ g_di.enable_preview_update = FALSE; g_di.sample_show_selection = TRUE; g_di.dst_show_selection = TRUE; g_di.dst_show_color = TRUE; g_di.sample_show_color = TRUE; g_di.orig_inten_button = NULL; /* Init GTK */ gimp_ui_init ("sample_colorize", TRUE); /* Main Dialog */ g_di.dialog = dialog = gimp_dialog_new (_("Sample Colorize"), "sample_colorize", NULL, 0, gimp_standard_help_func, "filters/sample_colorize.html", GIMP_STOCK_RESET, RESPONSE_RESET, _("Get Sample Colors"), RESPONSE_GET_COLORS, GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE, _("Apply"), GTK_RESPONSE_APPLY, NULL); g_signal_connect (dialog, "response", G_CALLBACK (p_smp_response_callback), dialog); /* parameter settings */ frame = gtk_frame_new (_("Settings")); gtk_container_set_border_width (GTK_CONTAINER (frame), 6); gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), frame, TRUE, TRUE, 0); /* table for values */ table = gtk_table_new (7, 5, FALSE); gtk_table_set_row_spacings (GTK_TABLE (table), 4); gtk_table_set_col_spacings (GTK_TABLE (table), 4); gtk_container_set_border_width (GTK_CONTAINER (table), 4); gtk_container_add (GTK_CONTAINER (frame), table); /* separator */ sep = gtk_vseparator_new (); gtk_table_attach_defaults (GTK_TABLE (table), sep, 2, 3, 0, 7); gtk_widget_show (sep); l_ty = 0; /* layer optionmenu (Dst) */ label = gtk_label_new (_("Destination:")); gtk_misc_set_alignment (GTK_MISC(label), 1.0, 0.5); gtk_table_attach (GTK_TABLE (table), label, 0, 1, l_ty, l_ty+1, GTK_FILL, GTK_FILL, 4, 0); gtk_widget_show (label); option_menu = gtk_option_menu_new (); gtk_table_attach (GTK_TABLE (table), option_menu, 1, 2, l_ty, l_ty+1, GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0); gtk_widget_show (option_menu); menu = gimp_layer_menu_new (p_smp_constrain, p_smp_menu_callback, &g_values.dst_id, /* data */ g_values.dst_id); gtk_option_menu_set_menu (GTK_OPTION_MENU (option_menu), menu); gtk_widget_show (option_menu); /* layer optionmenu (Sample) */ label = gtk_label_new (_("Sample:")); gtk_misc_set_alignment (GTK_MISC (label), 1.0, 0.5); gtk_table_attach (GTK_TABLE (table), label, 3, 4, l_ty, l_ty+1, GTK_FILL, GTK_FILL, 4, 0); gtk_widget_show (label); option_menu = gtk_option_menu_new (); gtk_table_attach (GTK_TABLE (table), option_menu, 4, 5, l_ty, l_ty+1, GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0); gtk_widget_show (option_menu); menu = gimp_layer_menu_new (p_smp_constrain, p_smp_menu_callback, &g_values.sample_id, /* data */ g_values.sample_id); gtk_option_menu_set_menu (GTK_OPTION_MENU (option_menu), menu); gtk_widget_show (option_menu); /* Add extra menu items for Gradient */ menu_item = gtk_menu_item_new_with_label (_("From Gradient")); gtk_container_add (GTK_CONTAINER (menu), menu_item); gtk_widget_show (menu_item); g_signal_connect (menu_item, "activate", G_CALLBACK (p_gradient_callback), (gpointer)SMP_GRADIENT); /* Add extra menu items for Inverted Gradient */ menu_item = gtk_menu_item_new_with_label (_("From Reverse Gradient")); gtk_container_add (GTK_CONTAINER (menu), menu_item); gtk_widget_show (menu_item); g_signal_connect (menu_item, "activate", G_CALLBACK (p_gradient_callback), (gpointer)SMP_INV_GRADIENT); l_ty++; hbox = gtk_hbox_new (FALSE, 4); gtk_table_attach (GTK_TABLE (table), hbox, 0, 2, l_ty, l_ty+1, GTK_FILL, 0, 0, 0); gtk_widget_show (hbox); /* check button */ check_button = gtk_check_button_new_with_label (_("Show Selection")); gtk_box_pack_start (GTK_BOX (hbox), check_button, FALSE, FALSE, 0); gtk_widget_show (check_button); g_signal_connect (check_button, "toggled", G_CALLBACK (p_smp_toggle_callback), &g_di.dst_show_selection); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (check_button), g_di.dst_show_selection); /* check button */ check_button = gtk_check_button_new_with_label (_("Show Color")); gtk_box_pack_start (GTK_BOX (hbox), check_button, FALSE, FALSE, 0); gtk_widget_show (check_button); g_signal_connect (check_button, "toggled", G_CALLBACK (p_smp_toggle_callback), &g_di.dst_show_color); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (check_button), g_di.dst_show_color); hbox = gtk_hbox_new (FALSE, 4); gtk_table_attach (GTK_TABLE (table), hbox, 3, 5, l_ty, l_ty+1, GTK_FILL, 0, 0, 0); gtk_widget_show (hbox); /* check button */ check_button = gtk_check_button_new_with_label (_("Show Selection")); gtk_box_pack_start (GTK_BOX (hbox), check_button, FALSE, FALSE, 0); gtk_widget_show (check_button); g_signal_connect (check_button, "toggled", (GtkSignalFunc)p_smp_toggle_callback , &g_di.sample_show_selection); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (check_button), g_di.sample_show_selection); /* check button */ check_button = gtk_check_button_new_with_label (_("Show Color")); gtk_box_pack_start (GTK_BOX (hbox), check_button, FALSE, FALSE, 0); gtk_widget_show (check_button); g_signal_connect (check_button, "toggled", (GtkSignalFunc)p_smp_toggle_callback , &g_di.sample_show_color); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (check_button), g_di.sample_show_color); l_ty++; /* Preview (Dst) */ pframe = gtk_frame_new (NULL); gtk_frame_set_shadow_type (GTK_FRAME (pframe), GTK_SHADOW_IN); gtk_table_attach (GTK_TABLE (table), pframe, 0, 2, l_ty, l_ty+1, 0, 0, 0, 0); gtk_widget_show (pframe); g_di.dst_preview = gtk_preview_new (GTK_PREVIEW_COLOR); gtk_preview_size (GTK_PREVIEW (g_di.dst_preview), PREVIEW_SIZE_X, PREVIEW_SIZE_Y); gtk_container_add (GTK_CONTAINER (pframe), g_di.dst_preview); gtk_widget_show (g_di.dst_preview); /* Preview (Sample)*/ pframe = gtk_frame_new (NULL); gtk_frame_set_shadow_type (GTK_FRAME (pframe), GTK_SHADOW_IN); gtk_table_attach (GTK_TABLE (table), pframe, 3, 5, l_ty, l_ty+1, 0, 0, 0, 0); gtk_widget_show (pframe); g_di.sample_preview = gtk_preview_new (GTK_PREVIEW_COLOR); gtk_preview_size (GTK_PREVIEW (g_di.sample_preview), PREVIEW_SIZE_X, PREVIEW_SIZE_Y); gtk_container_add (GTK_CONTAINER (pframe), g_di.sample_preview); gtk_widget_show (g_di.sample_preview); l_ty++; /* The levels graylevel prevev */ pframe = gtk_frame_new (NULL); vbox2 = gtk_vbox_new (FALSE, 2); gtk_container_add (GTK_CONTAINER (pframe), vbox2); gtk_table_attach (GTK_TABLE (table), pframe, 0, 2, l_ty, l_ty+1, 0, 0, 0, 0); g_di.in_lvl_gray_preview = gtk_preview_new (GTK_PREVIEW_GRAYSCALE); gtk_preview_size (GTK_PREVIEW (g_di.in_lvl_gray_preview), DA_WIDTH, GRADIENT_HEIGHT); gtk_widget_set_events (g_di.in_lvl_gray_preview, LEVELS_DA_MASK); gtk_box_pack_start (GTK_BOX (vbox2), g_di.in_lvl_gray_preview, FALSE, TRUE, 0); gtk_widget_show (g_di.in_lvl_gray_preview); g_signal_connect (g_di.in_lvl_gray_preview, "event", G_CALLBACK (p_level_in_events), &g_di); /* The levels drawing area */ g_di.in_lvl_drawarea = gtk_drawing_area_new (); gtk_widget_set_size_request (g_di.in_lvl_drawarea, DA_WIDTH, CONTROL_HEIGHT); gtk_widget_set_events (g_di.in_lvl_drawarea, LEVELS_DA_MASK); gtk_box_pack_start (GTK_BOX (vbox2), g_di.in_lvl_drawarea, FALSE, TRUE, 0); gtk_widget_show (g_di.in_lvl_drawarea); g_signal_connect (g_di.in_lvl_drawarea, "event", G_CALLBACK (p_level_in_events), &g_di); gtk_widget_show(vbox2); gtk_widget_show(pframe); /* The sample_colortable prevev */ pframe = gtk_frame_new (NULL); vbox2 = gtk_vbox_new (FALSE, 2); gtk_container_add (GTK_CONTAINER (pframe), vbox2); gtk_table_attach (GTK_TABLE (table), pframe, 3, 5, l_ty, l_ty+1, 0, 0, 0, 0); g_di.sample_colortab_preview = gtk_preview_new (GTK_PREVIEW_COLOR); gtk_preview_size (GTK_PREVIEW (g_di.sample_colortab_preview), DA_WIDTH, GRADIENT_HEIGHT); gtk_box_pack_start (GTK_BOX (vbox2), g_di.sample_colortab_preview, FALSE, TRUE, 0); gtk_widget_show (g_di.sample_colortab_preview); /* The levels drawing area */ g_di.sample_drawarea = gtk_drawing_area_new (); gtk_widget_set_size_request (g_di.sample_drawarea, DA_WIDTH, CONTROL_HEIGHT); gtk_widget_set_events (g_di.sample_drawarea, LEVELS_DA_MASK); gtk_box_pack_start (GTK_BOX (vbox2), g_di.sample_drawarea, FALSE, TRUE, 0); gtk_widget_show (g_di.sample_drawarea); g_signal_connect (g_di.sample_drawarea, "event", G_CALLBACK (p_level_out_events), &g_di); gtk_widget_show(vbox2); gtk_widget_show(pframe); l_ty++; /* Horizontal box for INPUT levels text widget */ hbox = gtk_hbox_new (TRUE, 4); gtk_table_attach (GTK_TABLE (table), hbox, 0, 2, l_ty, l_ty+1, GTK_FILL, 0, 0, 0); label = gtk_label_new (_("Input Levels:")); gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0); gtk_widget_show (label); /* min input spinbutton */ data = gtk_adjustment_new ((gfloat)g_values.lvl_in_min, 0.0, 254.0, 1, 10, 10); g_di.adj_lvl_in_min = GTK_ADJUSTMENT (data); spinbutton = gtk_spin_button_new (g_di.adj_lvl_in_min, 0.5, 0); gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (spinbutton), TRUE); gtk_box_pack_start (GTK_BOX (hbox), spinbutton, FALSE, FALSE, 0); gtk_widget_show (spinbutton); g_signal_connect (g_di.adj_lvl_in_min, "value_changed", G_CALLBACK (p_smp_adj_lvl_in_min_upd_callback), &g_di); /* input gamma spinbutton */ data = gtk_adjustment_new ((gfloat)g_values.lvl_in_gamma, 0.1, 10.0, 0.02, 0.2, 0.2); g_di.adj_lvl_in_gamma = GTK_ADJUSTMENT (data); spinbutton = gtk_spin_button_new (g_di.adj_lvl_in_gamma, 0.5, 2); gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (spinbutton), TRUE); gtk_box_pack_start (GTK_BOX (hbox), spinbutton, FALSE, FALSE, 0); gtk_widget_show (spinbutton); g_signal_connect (g_di.adj_lvl_in_gamma, "value_changed", G_CALLBACK (p_smp_text_gamma_upd_callback), &g_di); /* high input spinbutton */ data = gtk_adjustment_new ((gfloat)g_values.lvl_in_max, 1.0, 255.0, 1, 10, 10); g_di.adj_lvl_in_max = GTK_ADJUSTMENT (data); spinbutton = gtk_spin_button_new (g_di.adj_lvl_in_max, 0.5, 0); gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (spinbutton), TRUE); gtk_box_pack_start (GTK_BOX (hbox), spinbutton, FALSE, FALSE, 0); gtk_widget_show (spinbutton); g_signal_connect (g_di.adj_lvl_in_max, "value_changed", G_CALLBACK (p_smp_adj_lvl_in_max_upd_callback), &g_di); gtk_widget_show (hbox); /* Horizontal box for OUTPUT levels text widget */ hbox = gtk_hbox_new (TRUE, 4); gtk_table_attach (GTK_TABLE (table), hbox, 3, 5, l_ty, l_ty+1, GTK_FILL, 0, 0, 0); label = gtk_label_new (_("Output Levels:")); gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0); gtk_widget_show (label); /* min output spinbutton */ data = gtk_adjustment_new ((gfloat)g_values.lvl_out_min, 0.0, 254.0, 1, 10, 10); g_di.adj_lvl_out_min = GTK_ADJUSTMENT (data); spinbutton = gtk_spin_button_new (g_di.adj_lvl_out_min, 0.5, 0); gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (spinbutton), TRUE); gtk_box_pack_start (GTK_BOX (hbox), spinbutton, FALSE, FALSE, 0); gtk_widget_show (spinbutton); g_signal_connect (g_di.adj_lvl_out_min, "value_changed", G_CALLBACK (p_smp_adj_lvl_out_min_upd_callback), &g_di); /* high output spinbutton */ data = gtk_adjustment_new ((gfloat)g_values.lvl_out_max, 0.0, 255.0, 1, 10, 10); g_di.adj_lvl_out_max = GTK_ADJUSTMENT (data); spinbutton = gtk_spin_button_new (g_di.adj_lvl_out_max, 0.5, 0); gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (spinbutton), TRUE); gtk_box_pack_start (GTK_BOX (hbox), spinbutton, FALSE, FALSE, 0); gtk_widget_show (spinbutton); g_signal_connect (g_di.adj_lvl_out_max, "value_changed", G_CALLBACK (p_smp_adj_lvl_out_max_upd_callback), &g_di); gtk_widget_show (hbox); l_ty++; hbox = gtk_hbox_new (FALSE, 4); gtk_table_attach (GTK_TABLE (table), hbox, 0, 2, l_ty, l_ty+1, GTK_FILL, 0, 0, 0); gtk_widget_show (hbox); /* check button */ check_button = gtk_check_button_new_with_label (_("Hold Intensity")); gtk_box_pack_start (GTK_BOX (hbox), check_button, FALSE, FALSE, 0); gtk_widget_show (check_button); g_signal_connect (check_button, "toggled", G_CALLBACK (p_smp_toggle_callback), &g_values.hold_inten); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (check_button), g_values.hold_inten); /* check button */ check_button = gtk_check_button_new_with_label (_("Original Intensity")); g_di.orig_inten_button = check_button; gtk_box_pack_start (GTK_BOX (hbox), check_button, FALSE, FALSE, 0); gtk_widget_set_sensitive (g_di.orig_inten_button, g_values.hold_inten); gtk_widget_show (check_button); g_signal_connect (check_button, "toggled", G_CALLBACK (p_smp_toggle_callback), &g_values.orig_inten); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (check_button), g_values.orig_inten); hbox = gtk_hbox_new (FALSE, 4); gtk_table_attach (GTK_TABLE (table), hbox, 3, 5, l_ty, l_ty+1, GTK_FILL, 0, 0, 0); gtk_widget_show (hbox); /* check button */ check_button = gtk_check_button_new_with_label (_("Use Subcolors")); gtk_box_pack_start (GTK_BOX (hbox), check_button, FALSE, FALSE, 0); gtk_widget_show (check_button); g_signal_connect (check_button, "toggled", G_CALLBACK (p_smp_toggle_callback), &g_values.rnd_subcolors); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (check_button), g_values.rnd_subcolors); /* check button */ check_button = gtk_check_button_new_with_label (_("Smooth Samples")); gtk_box_pack_start (GTK_BOX (hbox), check_button, FALSE, FALSE, 0); gtk_widget_show (check_button); g_signal_connect (check_button, "toggled", G_CALLBACK (p_smp_toggle_callback), &g_values.guess_missing); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (check_button), g_values.guess_missing); l_ty++; gtk_widget_show (table); gtk_widget_show (frame); gtk_widget_show (dialog); /* set old_id's different (to force updates of the previews) */ g_di.enable_preview_update = TRUE; p_smp_get_colors (NULL); p_update_preview(&g_values.dst_id); p_levels_update (INPUT_SLIDERS | INPUT_LEVELS | DRAW); gtk_main (); return (0); } /* end p_smp_dialog */ /* ----------------------------- * DEBUG print procedures START * ----------------------------- */ static void p_print_ppm(gchar *ppm_name) { FILE *fp; gint l_idx; gint l_cnt; gint l_r, l_g, l_b; t_samp_color_elem *col_ptr; if(ppm_name == NULL) return; fp = fopen(ppm_name, "w"); if(fp) { fprintf(fp, "P3\n# CREATOR: Gimp sample coloros\n256 256\n255\n"); for(l_idx = 0; l_idx < 256; l_idx++) { col_ptr = g_lum_tab[l_idx].col_ptr; for(l_cnt = 0; l_cnt < 256; l_cnt++) { l_r = l_g = l_b = 0; if(col_ptr) { if((col_ptr->sum_color > 0) && (l_cnt != 20)) { l_r = (int)col_ptr->color[0]; l_g = (int)col_ptr->color[1]; l_b = (int)col_ptr->color[2]; } if(l_cnt > 20) col_ptr = col_ptr->next; } fprintf(fp, "%d %d %d\n", l_r, l_g, l_b); } } fclose(fp); } } static void p_print_color_list(FILE *fp, t_samp_color_elem *col_ptr) { if(fp == NULL) return; while(col_ptr) { fprintf(fp, " RGBA: %03d %03d %03d %03d sum: [%d]\n", (int)col_ptr->color[0], (int)col_ptr->color[1], (int)col_ptr->color[2], (int)col_ptr->color[3], (int)col_ptr->sum_color ); col_ptr = col_ptr->next; } } static void p_print_table(FILE *fp) { gint l_idx; if(fp == NULL) return; fprintf(fp, "---------------------------\n"); fprintf(fp, "p_print_table\n"); fprintf(fp, "---------------------------\n"); for(l_idx = 0; l_idx < 256; l_idx++) { fprintf(fp, "LUM [%03d] pixcount:%d\n", l_idx, (int)g_lum_tab[l_idx].all_samples); p_print_color_list(fp, g_lum_tab[l_idx].col_ptr); } } static void p_print_transtable(FILE *fp) { gint l_idx; if(fp == NULL) return; fprintf(fp, "---------------------------\n"); fprintf(fp, "p_print_transtable\n"); fprintf(fp, "---------------------------\n"); for(l_idx = 0; l_idx < 256; l_idx++) { fprintf(fp, "LVL_TRANS [%03d] in_lvl: %3d out_lvl: %3d\n", l_idx, (int)g_lvl_trans_tab[l_idx], (int)g_out_trans_tab[l_idx]); } } static void p_print_values(FILE *fp) { if(fp == NULL) return; fprintf(fp, "sample_colorize: params\n"); fprintf(fp, "g_values.hold_inten :%d\n", (int)g_values.hold_inten); fprintf(fp, "g_values.orig_inten :%d\n", (int)g_values.orig_inten); fprintf(fp, "g_values.rnd_subcolors :%d\n", (int)g_values.rnd_subcolors); fprintf(fp, "g_values.guess_missing :%d\n", (int)g_values.guess_missing); fprintf(fp, "g_values.lvl_in_min :%d\n", (int)g_values.lvl_in_min); fprintf(fp, "g_values.lvl_in_max :%d\n", (int)g_values.lvl_in_max); fprintf(fp, "g_values.lvl_in_gamma :%f\n", g_values.lvl_in_gamma); fprintf(fp, "g_values.lvl_out_min :%d\n", (int)g_values.lvl_out_min); fprintf(fp, "g_values.lvl_out_max :%d\n", (int)g_values.lvl_out_max); fprintf(fp, "g_values.tol_col_err :%f\n", g_values.tol_col_err); } /* ----------------------------- * DEBUG print procedures END * ----------------------------- */ /* DEBUG: read values from file */ void p_get_filevalues() { FILE *l_fp; gchar l_buf[1000]; /* g_values.lvl_out_min = 0; g_values.lvl_out_max = 255; g_values.lvl_in_min = 0; g_values.lvl_in_max = 255; g_values.lvl_in_gamma = 1.0; */ g_values.tol_col_err = 5.5; l_fp = fopen("sample_colorize.values", "r"); if(l_fp != NULL) { fgets(&l_buf[0], 999, l_fp); sscanf(&l_buf[0], "%f", &g_values.tol_col_err ); fclose(l_fp); } printf("g_values.tol_col_err :%f\n", g_values.tol_col_err); } /* end p_get_filevalues */ gint32 p_color_error(guchar ref_red, guchar ref_green, guchar ref_blue, guchar cmp_red, guchar cmp_green, guchar cmp_blue) { long l_ff; long l_fs; long cmp_h, ref_h; /* 1. Brightness differences */ cmp_h = (3 * cmp_red + 6 * cmp_green + cmp_blue) / 10; ref_h = (3 * ref_red + 6 * ref_green + ref_blue) / 10; l_fs = abs(ref_h - cmp_h); l_ff = l_fs * l_fs; /* 2. add Red Color differences */ l_fs = abs(ref_red - cmp_red); l_ff += (l_fs * l_fs); /* 3. add Green Color differences */ l_fs = abs(ref_green - cmp_green); l_ff += (l_fs * l_fs); /* 4. add Blue Color differences */ l_fs = abs(ref_blue - cmp_blue); l_ff += (l_fs * l_fs); return((gint32)(l_ff)); } /* end p_color_error */ static void p_provide_tile(t_GDRW *gdrw, gint col, gint row, gint shadow ) { guchar *ptr; gint i; if ( col != gdrw->tile_col || row != gdrw->tile_row || !gdrw->tile ) { if( gdrw->tile ) { gimp_tile_unref( gdrw->tile, gdrw->tile_dirty ); } gdrw->tile_col = col; gdrw->tile_row = row; gdrw->tile = gimp_drawable_get_tile( gdrw->drawable, shadow, gdrw->tile_row, gdrw->tile_col ); gdrw->tile_dirty = FALSE; gimp_tile_ref( gdrw->tile ); gdrw->tile_swapcount++; return; /* debug start */ printf("\np_provide_tile: row: %d col: %d data:", (int)row, (int)col); ptr = gdrw->tile->data; for(i=0; i < 16; i++) { printf(" %d", (int)(*ptr)); ptr++; } printf("\n\n"); /* debug stop */ } } /* end p_provide_tile */ /* get pixel value * return light gray transparent pixel if out of bounds * (should occur in the previews only) */ static void p_get_pixel( t_GDRW *gdrw, gint32 x, gint32 y, guchar *pixel ) { gint row, col; gint offx, offy; guchar *ptr; if((x < 0) || (x > gdrw->drawable->width -1) || (y < 0) || (y > gdrw->drawable->height - 1)) { pixel[0] = pixel[1] = pixel[2] = 200; pixel[3] = 0; return; } col = x / gdrw->tile_width; row = y / gdrw->tile_height; offx = x % gdrw->tile_width; offy = y % gdrw->tile_height; p_provide_tile( gdrw, col, row, gdrw->shadow); pixel[1] = 0; pixel[3] = 0; /* simulate full transparent alpha channel */ ptr = gdrw->tile->data + ((( offy * gdrw->tile->ewidth) + offx ) * gdrw->bpp); memcpy(pixel, ptr, gdrw->bpp); return; printf("p_get_pixel: x: %d y: %d bpp:%d RGBA:%d %d %d %d\n", (int)x, (int)y, (int)gdrw->bpp, (int)pixel[0], (int)pixel[1], (int)pixel[2], (int)pixel[3]); } /* clear table */ static void p_clear_tables() { gint l_idx; for(l_idx = 0; l_idx < 256; l_idx++) { g_lum_tab[l_idx].col_ptr = NULL; g_lum_tab[l_idx].all_samples = 0; g_lvl_trans_tab[l_idx] = l_idx; g_out_trans_tab[l_idx] = l_idx; g_sample_color_tab[l_idx + l_idx + l_idx] = l_idx; g_sample_color_tab[l_idx + l_idx + l_idx +1] = l_idx; g_sample_color_tab[l_idx + l_idx + l_idx +2] = l_idx; } } /* free all allocated sample colors in table g_lum_tab */ void p_free_colors() { gint l_lum; t_samp_color_elem *l_col_ptr; t_samp_color_elem *l_next_ptr; for(l_lum = 0; l_lum < 256; l_lum++) { for(l_col_ptr = g_lum_tab[l_lum].col_ptr; l_col_ptr != NULL; l_col_ptr = l_next_ptr) { l_next_ptr = (t_samp_color_elem *)l_col_ptr->next; free(l_col_ptr); } g_lum_tab[l_lum].col_ptr = NULL; g_lum_tab[l_lum].all_samples = 0; } } /* end p_free_colors */ /* setup lum transformer table according to input_levels, gamma and output levels * (uses sam algorithm as GIMP Level Tool) */ static void p_calculate_level_transfers () { double inten; gint i; gint l_in_min, l_in_max; gint l_out_min, l_out_max; if(g_values.lvl_in_max >= g_values.lvl_in_min) { l_in_max = g_values.lvl_in_max; l_in_min = g_values.lvl_in_min; } else { l_in_max = g_values.lvl_in_min; l_in_min = g_values.lvl_in_max; } if(g_values.lvl_out_max >= g_values.lvl_out_min) { l_out_max = g_values.lvl_out_max; l_out_min = g_values.lvl_out_min; } else { l_out_max = g_values.lvl_out_min; l_out_min = g_values.lvl_out_max; } /* Recalculate the levels arrays */ for (i = 0; i < 256; i++) { /* determine input intensity */ inten = (double) i / 255.0; if (g_values.lvl_in_gamma != 0.0) { inten = pow (inten, (1.0 / g_values.lvl_in_gamma)); } inten = (double) (inten * (l_in_max - l_in_min) + l_in_min); inten = CLAMP (inten, 0.0, 255.0); g_lvl_trans_tab[i] = (guchar) (inten + 0.5); /* determine the output intensity */ inten = (double) i / 255.0; inten = (double) (inten * (l_out_max - l_out_min) + l_out_min); inten = CLAMP (inten, 0.0, 255.0); g_out_trans_tab[i] = (guchar) (inten + 0.5); } } /* end p_calculate_level_transfers */ /* alloc and init new col Element */ t_samp_color_elem * p_new_samp_color(guchar *color) { t_samp_color_elem *l_col_ptr; l_col_ptr = calloc(1, sizeof(t_samp_color_elem)); if(l_col_ptr == NULL) { printf("Error: cant get Memory\n"); return(NULL); } memcpy(&l_col_ptr->color[0], color, 4); l_col_ptr->sum_color = 1; l_col_ptr->next = NULL; return (l_col_ptr); } /* end p_new_samp_color */ /* store color in g_lum_tab */ void p_add_color(guchar *color) { gint32 l_lum; t_samp_color_elem *l_col_ptr; l_lum = LUMINOSITY_1(color); g_lum_tab[l_lum].all_samples++; g_lum_tab[l_lum].from_sample = TRUE; /* check if exactly the same color is already in the list */ for(l_col_ptr = g_lum_tab[l_lum].col_ptr; l_col_ptr != NULL; l_col_ptr = (t_samp_color_elem *)l_col_ptr->next) { if((color[0] == l_col_ptr->color[0]) && (color[1] == l_col_ptr->color[1]) && (color[2] == l_col_ptr->color[2])) { l_col_ptr->sum_color++; return; } } /* alloc and init element for the new color */ l_col_ptr = p_new_samp_color(color); if(l_col_ptr != NULL) { /* add new color element as 1.st of the list */ l_col_ptr->next = g_lum_tab[l_lum].col_ptr; g_lum_tab[l_lum].col_ptr = l_col_ptr; } } /* end p_add_color */ /* sort Sublists (color) by descending sum_color in g_lum_tab */ void p_sort_color(gint32 lum) { t_samp_color_elem *l_col_ptr; t_samp_color_elem *l_next_ptr; t_samp_color_elem *l_prev_ptr; t_samp_color_elem *l_sorted_col_ptr; gint32 l_min; gint32 l_min_next; l_sorted_col_ptr = NULL; l_min_next = 0; while(g_lum_tab[lum].col_ptr != NULL) { l_min = l_min_next; l_next_ptr = NULL; l_prev_ptr = NULL; for(l_col_ptr = g_lum_tab[lum].col_ptr; l_col_ptr != NULL; l_col_ptr = l_next_ptr) { l_next_ptr = l_col_ptr->next; if(l_col_ptr->sum_color > l_min) { /* check min value for next loop */ if((l_col_ptr->sum_color < l_min_next) || (l_min == l_min_next)) { l_min_next = l_col_ptr->sum_color; } l_prev_ptr = l_col_ptr; } else { /* add element at head of sorted list */ l_col_ptr->next = l_sorted_col_ptr; l_sorted_col_ptr = l_col_ptr; /* remove element from list */ if(l_prev_ptr == NULL) { g_lum_tab[lum].col_ptr = l_next_ptr; /* remove 1.st element */ } else { l_prev_ptr->next = l_next_ptr; } } } } g_lum_tab[lum].col_ptr = l_sorted_col_ptr; } /* end p_sort_color */ void p_cnt_same_sample_colortones(t_samp_color_elem *ref_ptr, guchar *prev_color, guchar *color_tone, gint *csum) { gint32 l_col_error, l_ref_error; t_samp_color_elem *l_col_ptr; l_ref_error = 0; if(prev_color != NULL) { l_ref_error = p_color_error(ref_ptr->color[0], ref_ptr->color[1], ref_ptr->color[2], prev_color[0], prev_color[1], prev_color[2]); } /* collect colors that are (nearly) the same */ for(l_col_ptr = ref_ptr->next; l_col_ptr != NULL; l_col_ptr = (t_samp_color_elem *)l_col_ptr->next) { if(l_col_ptr->sum_color < 1) { continue; } l_col_error = p_color_error(ref_ptr->color[0], ref_ptr->color[1], ref_ptr->color[2], l_col_ptr->color[0], l_col_ptr->color[1], l_col_ptr->color[2]); if(l_col_error <= g_tol_col_err ) { /* cout color of the same colortone */ *csum += l_col_ptr->sum_color; /* mark the already checked color with negative sum_color value */ l_col_ptr->sum_color = 0 - l_col_ptr->sum_color; if(prev_color != NULL) { l_col_error = p_color_error(l_col_ptr->color[0], l_col_ptr->color[1], l_col_ptr->color[2], prev_color[0], prev_color[1], prev_color[2]); if(l_col_error < l_ref_error) { /* use the color that is closest to prev_color */ memcpy(color_tone, &l_col_ptr->color[0], 3); l_ref_error = l_col_error; } } } } } /* end p_cnt_same_sample_colortones */ /* find the dominant colortones (out of all sample colors) * for each available brightness intensity value. * and store them in g_sample_color_tab */ void p_ideal_samples() { gint32 l_lum; t_samp_color_elem *l_col_ptr; guchar *l_color; guchar l_color_tone[4]; guchar l_color_ideal[4]; gint l_csum, l_maxsum; l_color = NULL; for(l_lum = 0; l_lum < 256; l_lum++) { if(g_lum_tab[l_lum].col_ptr == NULL) { continue; } p_sort_color(l_lum); l_col_ptr = g_lum_tab[l_lum].col_ptr; memcpy(&l_color_ideal[0], &l_col_ptr->color[0], 3); l_maxsum = 0; /* collect colors that are (nearly) the same */ for(; l_col_ptr != NULL; l_col_ptr = (t_samp_color_elem *)l_col_ptr->next) { l_csum = 0; if(l_col_ptr->sum_color > 0) { memcpy(&l_color_tone[0], &l_col_ptr->color[0], 3); p_cnt_same_sample_colortones(l_col_ptr, l_color, &l_color_tone[0], &l_csum); if(l_csum > l_maxsum) { l_maxsum = l_csum; memcpy(&l_color_ideal[0], &l_color_tone[0], 3); } } else { l_col_ptr->sum_color = abs(l_col_ptr->sum_color); } } /* store ideal color and keep track of the color */ l_color = &g_sample_color_tab[l_lum + l_lum + l_lum]; memcpy(l_color, &l_color_ideal[0], 3); } } /* end p_ideal_samples */ void p_guess_missing_colors() { gint32 l_lum; gint32 l_idx; float l_div; guchar l_lo_color[4]; guchar l_hi_color[4]; guchar l_new_color[4]; l_lo_color[0] = 0; l_lo_color[1] = 0; l_lo_color[2] = 0; l_lo_color[3] = 255; l_hi_color[0] = 255; l_hi_color[1] = 255; l_hi_color[2] = 255; l_hi_color[3] = 255; l_new_color[0] = 0; l_new_color[1] = 0; l_new_color[2] = 0; l_new_color[3] = 255; for(l_lum = 0; l_lum < 256; l_lum++) { if((g_lum_tab[l_lum].col_ptr == NULL) || (g_lum_tab[l_lum].from_sample == FALSE)) { if(l_lum > 0) { for(l_idx = l_lum; l_idx < 256; l_idx++) { if((g_lum_tab[l_idx].col_ptr != NULL) && (g_lum_tab[l_idx].from_sample)) { memcpy(&l_hi_color[0], &g_sample_color_tab[l_idx + l_idx + l_idx], 3); break; } if(l_idx == 255) { l_hi_color[0] = 255; l_hi_color[1] = 255; l_hi_color[2] = 255; break; } } l_div = l_idx - (l_lum -1); l_new_color[0] = l_lo_color[0] + ((float)(l_hi_color[0] - l_lo_color[0]) / l_div); l_new_color[1] = l_lo_color[1] + ((float)(l_hi_color[1] - l_lo_color[1]) / l_div); l_new_color[2] = l_lo_color[2] + ((float)(l_hi_color[2] - l_lo_color[2]) / l_div); /* * printf("LO: %03d %03d %03d HI: %03d %03d %03d NEW: %03d %03d %03d\n", * (int)l_lo_color[0], (int)l_lo_color[1], (int)l_lo_color[2], * (int)l_hi_color[0], (int)l_hi_color[1], (int)l_hi_color[2], * (int)l_new_color[0], (int)l_new_color[1], (int)l_new_color[2]); */ } g_lum_tab[l_lum].col_ptr = p_new_samp_color(&l_new_color[0]); g_lum_tab[l_lum].from_sample = FALSE; memcpy(&g_sample_color_tab[l_lum + l_lum + l_lum], &l_new_color[0], 3); } memcpy(&l_lo_color[0], &g_sample_color_tab[l_lum + l_lum + l_lum], 3); } } /* end p_guess_missing_colors */ void p_fill_missing_colors() { gint32 l_lum; gint32 l_idx; gint32 l_lo_idx; guchar l_lo_color[4]; guchar l_hi_color[4]; guchar l_new_color[4]; l_lo_color[0] = 0; l_lo_color[1] = 0; l_lo_color[2] = 0; l_lo_color[3] = 255; l_hi_color[0] = 255; l_hi_color[1] = 255; l_hi_color[2] = 255; l_hi_color[3] = 255; l_new_color[0] = 0; l_new_color[1] = 0; l_new_color[2] = 0; l_new_color[3] = 255; l_lo_idx = 0; for(l_lum = 0; l_lum < 256; l_lum++) { if((g_lum_tab[l_lum].col_ptr == NULL) || (g_lum_tab[l_lum].from_sample == FALSE)) { if(l_lum > 0) { for(l_idx = l_lum; l_idx < 256; l_idx++) { if((g_lum_tab[l_idx].col_ptr != NULL) && (g_lum_tab[l_idx].from_sample)) { memcpy(&l_hi_color[0], &g_sample_color_tab[l_idx + l_idx + l_idx], 3); break; } if(l_idx == 255) { /* * l_hi_color[0] = 255; * l_hi_color[1] = 255; * l_hi_color[2] = 255; */ memcpy(&l_hi_color[0], &l_lo_color[0], 3); break; } } if((l_lum > (l_lo_idx + ((l_idx - l_lo_idx ) / 2))) || (l_lo_idx == 0)) { l_new_color[0] = l_hi_color[0]; l_new_color[1] = l_hi_color[1]; l_new_color[2] = l_hi_color[2]; } else { l_new_color[0] = l_lo_color[0]; l_new_color[1] = l_lo_color[1]; l_new_color[2] = l_lo_color[2]; } } g_lum_tab[l_lum].col_ptr = p_new_samp_color(&l_new_color[0]); g_lum_tab[l_lum].from_sample = FALSE; memcpy(&g_sample_color_tab[l_lum + l_lum + l_lum], &l_new_color[0], 3); } else { l_lo_idx = l_lum; memcpy(&l_lo_color[0], &g_sample_color_tab[l_lum + l_lum + l_lum], 3); } } } /* end p_fill_missing_colors */ /* get 256 samples of active gradient (optional in invers order) */ static void p_get_gradient (gint mode) { gdouble *f_samples, *f_samp; /* float samples */ gint l_lum; p_free_colors(); f_samples = gimp_gradients_sample_uniform (256 /* n_samples */, mode == SMP_INV_GRADIENT); for (l_lum = 0; l_lum < 256; l_lum++) { f_samp = &f_samples[l_lum * 4]; g_sample_color_tab[l_lum + l_lum + l_lum ] = f_samp[0] * 255; g_sample_color_tab[l_lum + l_lum + l_lum +1] = f_samp[1] * 255; g_sample_color_tab[l_lum + l_lum + l_lum +2] = f_samp[2] * 255; g_lum_tab[l_lum].col_ptr = p_new_samp_color(&g_sample_color_tab[l_lum + l_lum + l_lum]); g_lum_tab[l_lum].from_sample = TRUE; g_lum_tab[l_lum].all_samples = 1; } g_free (f_samples); } /* end p_get_gradient */ static gint32 p_is_layer_alive(gint32 drawable_id) { /* return -1 if layer has become invalid */ if (drawable_id < 0) { return -1; } if (gimp_drawable_get_image (drawable_id) < 0) { printf ("sample colorize: unknown layer_id %d (Image closed?)\n", (int)drawable_id); return -1; } return drawable_id; } static void p_end_gdrw(t_GDRW *gdrw) { t_GDRW *sel_gdrw; if (gdrw->tile) { gimp_tile_unref (gdrw->tile, gdrw->tile_dirty); gdrw->tile = NULL; } sel_gdrw = (t_GDRW*)(gdrw->sel_gdrw); if (sel_gdrw) { if(sel_gdrw->tile) { gimp_tile_unref (sel_gdrw->tile, sel_gdrw->tile_dirty); sel_gdrw->tile = NULL; } gdrw->sel_gdrw = NULL; } } static void p_init_gdrw (t_GDRW *gdrw, GimpDrawable *drawable, gint dirty, gint shadow) { gint32 l_image_id; gint32 l_sel_channel_id; gint32 l_x1, l_x2, l_y1, l_y2; gint l_offsetx, l_offsety; gint l_sel_offsetx, l_sel_offsety; t_GDRW *l_sel_gdrw; gint32 non_empty; if(g_Sdebug) printf("\np_init_gdrw: drawable %p ID: %d\n", drawable, (int)drawable->drawable_id); gdrw->drawable = drawable; gdrw->tile = NULL; gdrw->tile_dirty = FALSE; gdrw->tile_width = gimp_tile_width (); gdrw->tile_height = gimp_tile_height (); gdrw->shadow = shadow; gdrw->tile_swapcount = 0; gdrw->seldeltax = 0; gdrw->seldeltay = 0; gimp_drawable_offsets (drawable->drawable_id, &l_offsetx, &l_offsety); /* get offsets within the image */ gimp_drawable_mask_bounds (drawable->drawable_id, &gdrw->x1, &gdrw->y1, &gdrw->x2, &gdrw->y2); gdrw->bpp = drawable->bpp; if (gimp_drawable_has_alpha(drawable->drawable_id)) { /* index of the alpha channelbyte {1|3} */ gdrw->index_alpha = gdrw->bpp -1; } else { gdrw->index_alpha = 0; /* there is no alpha channel */ } l_image_id = gimp_drawable_get_image (drawable->drawable_id); /* check and see if we have a selection mask */ l_sel_channel_id = gimp_image_get_selection (l_image_id); if(g_Sdebug) { printf("p_init_gdrw: image_id %d sel_channel_id: %d\n", (int)l_image_id, (int)l_sel_channel_id); printf("p_init_gdrw: BOUNDS x1: %d y1: %d x2:%d y2: %d\n", (int)gdrw->x1, (int)gdrw->y1, (int)gdrw->x2,(int)gdrw->y2); printf("p_init_gdrw: OFFS x: %d y: %d\n", (int)l_offsetx, (int)l_offsety ); } gimp_selection_bounds (l_image_id, &non_empty, &l_x1, &l_y1, &l_x2, &l_y2); if (non_empty && (l_sel_channel_id >= 0)) { /* selection is TRUE */ l_sel_gdrw = (t_GDRW *) calloc(1, sizeof(t_GDRW)); l_sel_gdrw->drawable = gimp_drawable_get (l_sel_channel_id); l_sel_gdrw->tile = NULL; l_sel_gdrw->tile_dirty = FALSE; l_sel_gdrw->tile_width = gimp_tile_width (); l_sel_gdrw->tile_height = gimp_tile_height (); l_sel_gdrw->shadow = shadow; l_sel_gdrw->tile_swapcount = 0; l_sel_gdrw->x1 = l_x1; l_sel_gdrw->y1 = l_y1; l_sel_gdrw->x2 = l_x2; l_sel_gdrw->y2 = l_y2; l_sel_gdrw->seldeltax = 0; l_sel_gdrw->seldeltay = 0; l_sel_gdrw->bpp = l_sel_gdrw->drawable->bpp; /* should be always 1 */ l_sel_gdrw->index_alpha = 0; /* there is no alpha channel */ l_sel_gdrw->sel_gdrw = NULL; /* offset delta between drawable and selection * (selection always has image size and should always have offsets of 0 ) */ gimp_drawable_offsets (l_sel_channel_id, &l_sel_offsetx, &l_sel_offsety); gdrw->seldeltax = l_offsetx - l_sel_offsetx; gdrw->seldeltay = l_offsety - l_sel_offsety; gdrw->sel_gdrw = (t_GDRW *) l_sel_gdrw; if (g_Sdebug) { printf("p_init_gdrw: SEL_BOUNDS x1: %d y1: %d x2:%d y2: %d\n", (int)l_sel_gdrw->x1, (int)l_sel_gdrw->y1, (int)l_sel_gdrw->x2,(int)l_sel_gdrw->y2); printf("p_init_gdrw: SEL_OFFS x: %d y: %d\n", (int)l_sel_offsetx, (int)l_sel_offsety ); printf("p_init_gdrw: SEL_DELTA x: %d y: %d\n", (int)gdrw->seldeltax, (int)gdrw->seldeltay ); } } else { gdrw->sel_gdrw = NULL; /* selection is FALSE */ } } /* analyze the colors in the sample_drawable */ static int p_sample_analyze(t_GDRW *sample_gdrw) { gint32 l_sample_pixels; gint32 l_row, l_col; gint32 l_first_row, l_first_col, l_last_row, l_last_col; gint32 l_x, l_y; gint32 l_x2, l_y2; float l_progress_step; float l_progress_max; float l_progress; guchar color[4]; FILE *prot_fp; l_sample_pixels = 0; /* init progress */ l_progress_max = (sample_gdrw->x2 - sample_gdrw->x1); l_progress_step = 1.0 / l_progress_max; l_progress = 0.0; if(g_show_progress) gimp_progress_init (_("Sample Analyze...")); prot_fp = NULL; if(g_Sdebug) prot_fp = fopen("sample_colors.dump", "w"); p_print_values(prot_fp); /* ------------------------------------------------ * foreach pixel in the SAMPLE_drawable: * calculate brightness intensity LUM * ------------------------------------------------ * the inner loops (l_x/l_y) are designed to process * all pixels of one tile in the sample drawable, the outer loops (row/col) do step * to the next tiles. (this was done to reduce tile swapping) */ l_first_row = sample_gdrw->y1 / sample_gdrw->tile_height; l_last_row = (sample_gdrw->y2 / sample_gdrw->tile_height); l_first_col = sample_gdrw->x1 / sample_gdrw->tile_width; l_last_col = (sample_gdrw->x2 / sample_gdrw->tile_width); for(l_row = l_first_row; l_row <= l_last_row; l_row++) { for(l_col = l_first_col; l_col <= l_last_col; l_col++) { if(l_col == l_first_col) l_x = sample_gdrw->x1; else l_x = l_col * sample_gdrw->tile_width; if(l_col == l_last_col) l_x2 = sample_gdrw->x2; else l_x2 = (l_col +1) * sample_gdrw->tile_width; for( ; l_x < l_x2; l_x++) { if(l_row == l_first_row) l_y = sample_gdrw->y1; else l_y = l_row * sample_gdrw->tile_height; if(l_row == l_last_row) l_y2 = sample_gdrw->y2; else l_y2 = (l_row +1) * sample_gdrw->tile_height ; /* printf("X: %4d Y:%4d Y2:%4d\n", (int)l_x, (int)l_y, (int)l_y2); */ for( ; l_y < l_y2; l_y++) { /* check if the pixel is in the selection */ if(sample_gdrw->sel_gdrw) { p_get_pixel(sample_gdrw->sel_gdrw, (l_x + sample_gdrw->seldeltax), (l_y + sample_gdrw->seldeltay), &color[0]); if(color[0] == 0) { continue; } } p_get_pixel(sample_gdrw, l_x, l_y, &color[0]); /* if this is a visible (non-transparent) pixel */ if((sample_gdrw->index_alpha < 1) || (color[sample_gdrw->index_alpha] != 0)) { /* store color in the sublists of g_lum_tab */ p_add_color(&color[0]); l_sample_pixels++; } } if(g_show_progress) gimp_progress_update (l_progress += l_progress_step); } } } if(g_Sdebug) printf("ROWS: %d - %d COLS: %d - %d\n", (int)l_first_row, (int)l_last_row, (int)l_first_col, (int)l_last_col); p_print_table(prot_fp); if(g_Sdebug) p_print_ppm("sample_color_all.ppm"); /* findout ideal sample colors for each brightness intensity (lum) * and set g_sample_color_tab to the ideal colors. */ p_ideal_samples(); p_calculate_level_transfers (); if(g_values.guess_missing) { p_guess_missing_colors(); } else { p_fill_missing_colors(); } p_print_table(prot_fp); if(g_Sdebug) p_print_ppm("sample_color_2.ppm"); p_print_transtable(prot_fp); if(prot_fp) fclose(prot_fp); /* check if there was at least one visible pixel */ if (l_sample_pixels == 0) { printf("Error: Source sample has no visible Pixel\n"); return -1; } return 0; } /* end p_sample_analyze */ static void p_rnd_remap(gint32 lum, guchar *mapped_color) { t_samp_color_elem *l_col_ptr; gint l_rnd; gint l_ct; gint l_idx; if (g_lum_tab[lum].all_samples > 1) { l_rnd = g_random_int_range (0, g_lum_tab[lum].all_samples); l_ct = 0; l_idx = 0; for (l_col_ptr = g_lum_tab[lum].col_ptr; l_col_ptr != NULL; l_col_ptr = (t_samp_color_elem *)l_col_ptr->next) { l_ct += l_col_ptr->sum_color; if (l_rnd < l_ct) { /* printf("RND_remap: rnd: %d all:%d ct:%d idx:%d\n", * l_rnd, (int)g_lum_tab[lum].all_samples, l_ct, l_idx); */ memcpy (mapped_color, &l_col_ptr->color[0], 3); return; } l_idx++; } } memcpy (mapped_color, &g_sample_color_tab[lum + lum + lum], 3); } static void p_remap_pixel (guchar *pixel, const guchar *original, gint bpp2) { guchar mapped_color[4]; gint l_lum; double l_orig_lum, l_mapped_lum; double l_grn, l_red, l_blu; double l_mg, l_mr, l_mb; double l_dg, l_dr, l_db; double l_dlum; /* get brightness from (uncolorized) original */ l_lum = g_out_trans_tab[g_lvl_trans_tab[LUMINOSITY_1(original)]]; if (g_values.rnd_subcolors) { p_rnd_remap (l_lum, mapped_color); } else { memcpy (mapped_color, &g_sample_color_tab[l_lum + l_lum + l_lum], 3); } if (g_values.hold_inten) { if (g_values.orig_inten) { l_orig_lum = LUMINOSITY_0(original); } else { l_orig_lum = 100.0 * g_lvl_trans_tab[LUMINOSITY_1(original)]; } l_mapped_lum = LUMINOSITY_0 (mapped_color); if (l_mapped_lum == 0) { /* convert black to greylevel with desired brightness value */ mapped_color[0] = l_orig_lum / 100.0; mapped_color[1] = mapped_color[0]; mapped_color[2] = mapped_color[0]; } else { /* Calculate therotecal RGB to reach given intensity LUM value (l_orig_lum) */ l_mr = mapped_color[0]; l_mg = mapped_color[1]; l_mb = mapped_color[2]; if(l_mr > 0.0) { l_red = l_orig_lum / (30 + (59 * l_mg / l_mr) + (11 * l_mb / l_mr)); l_grn = l_mg * l_red / l_mr; l_blu = l_mb * l_red / l_mr; } else if (l_mg > 0.0) { l_grn = l_orig_lum / ((30 * l_mr / l_mg) + 59 + (11 * l_mb / l_mg)); l_red = l_mr * l_grn / l_mg; l_blu = l_mb * l_grn / l_mg; } else { l_blu = l_orig_lum / ((30 * l_mr / l_mb) + (59 * l_mg / l_mb) + 11); l_grn = l_mg * l_blu / l_mb; l_red = l_mr * l_blu / l_mb; } /* on overflow: Calculate real RGB values * (this may change the hue and saturation, * more and more into white) */ if (l_red > 255) { if ((l_blu < 255) && (l_grn < 255)) { /* overflow in the red channel (compensate with green and blu) */ l_dlum = (l_red - 255.0) * 30.0; if (l_mg > 0) { l_dg = l_dlum / (59.0 + (11.0 * l_mb / l_mg)); l_db = l_dg * l_mb / l_mg; } else if (l_mb > 0) { l_db = l_dlum / (11.0 + (59.0 * l_mg / l_mb)); l_dg = l_db * l_mg / l_mb; } else { l_db = l_dlum / (11.0 + 59.0); l_dg = l_dlum / (59.0 + 11.0); } l_grn += l_dg; l_blu += l_db; } l_red = 255.0; if (l_grn > 255) { l_grn = 255.0; l_blu = (l_orig_lum - 22695) / 11; /* 22695 = (255*30) + (255*59) */ } if (l_blu > 255) { l_blu = 255.0; l_grn = (l_orig_lum - 10455) / 59; /* 10455 = (255*30) + (255*11) */ } } else if (l_grn > 255) { if ((l_blu < 255) && (l_red < 255)) { /* overflow in the green channel (compensate with red and blu) */ l_dlum = (l_grn - 255.0) * 59.0; if (l_mr > 0) { l_dr = l_dlum / (30.0 + (11.0 * l_mb / l_mr)); l_db = l_dr * l_mb / l_mr; } else if (l_mb > 0) { l_db = l_dlum / (11.0 + (30.0 * l_mr / l_mb)); l_dr = l_db * l_mr / l_mb; } else { l_db = l_dlum / (11.0 + 30.0); l_dr = l_dlum / (30.0 + 11.0); } l_red += l_dr; l_blu += l_db; } l_grn = 255.0; if (l_red > 255) { l_red = 255.0; l_blu = (l_orig_lum - 22695) / 11; /* 22695 = (255*59) + (255*30) */ } if (l_blu > 255) { l_blu = 255.0; l_red = (l_orig_lum - 17850) / 30; /* 17850 = (255*59) + (255*11) */ } } else if (l_blu > 255) { if ((l_red < 255) && (l_grn < 255)) { /* overflow in the blue channel (compensate with green and red) */ l_dlum = (l_blu - 255.0) * 11.0; if (l_mg > 0) { l_dg = l_dlum / (59.0 + (30.0 * l_mr / l_mg)); l_dr = l_dg * l_mr / l_mg; } else if (l_mr > 0) { l_dr = l_dlum / (30.0 + (59.0 * l_mg / l_mr)); l_dg = l_dr * l_mg / l_mr; } else { l_dr = l_dlum / (30.0 + 59.0); l_dg = l_dlum / (59.0 + 30.0); } l_grn += l_dg; l_red += l_dr; } l_blu = 255.0; if (l_grn > 255) { l_grn = 255.0; l_red = (l_orig_lum - 17850) / 30; /* 17850 = (255*11) + (255*59) */ } if (l_red > 255) { l_red = 255.0; l_grn = (l_orig_lum - 10455) / 59; /* 10455 = (255*11) + (255*30) */ } } mapped_color[0] = CLAMP0255 (l_red + 0.5); mapped_color[1] = CLAMP0255 (l_grn + 0.5); mapped_color[2] = CLAMP0255 (l_blu + 0.5); } } /* set colorized pixel in shadow pr */ memcpy (pixel, &mapped_color[0], bpp2); } static void colorize_func (const guchar *src, guchar *dest, gint bpp, gpointer data) { gboolean has_alpha = GPOINTER_TO_INT (data); if (has_alpha) { bpp--; dest[bpp] = src[bpp]; } p_remap_pixel (dest, src, bpp); } static void p_colorize_drawable (gint32 drawable_id) { GimpDrawable *drawable; gboolean has_alpha; drawable = gimp_drawable_get (drawable_id); has_alpha = gimp_drawable_has_alpha (drawable->drawable_id); if (g_show_progress) gimp_progress_init (_("Remap Colorized...")); gimp_rgn_iterate2 (drawable, run_mode, colorize_func, GINT_TO_POINTER (has_alpha)); if (g_show_progress) gimp_progress_update (0.0); } /* colorize dst_drawable like sample_drawable */ static int p_main_colorize (gint mc_flags) { GimpDrawable *dst_drawable; GimpDrawable *sample_drawable; t_GDRW l_sample_gdrw; gint32 l_max; gint32 l_id; gint l_rc; if(g_Sdebug) p_get_filevalues (); /* for debugging: read values from file */ sample_drawable = NULL; dst_drawable = NULL; /* calculate value of tolerable color error */ l_max = p_color_error (0,0, 0, 255, 255, 255); /* 260100 */ g_tol_col_err = (((float)l_max * (g_values.tol_col_err * g_values.tol_col_err)) / (100.0 *100.0)); g_max_col_err = l_max; l_rc = 0; if (mc_flags & MC_GET_SAMPLE_COLORS) { l_id = g_values.sample_id; if ((l_id == SMP_GRADIENT) || (l_id == SMP_INV_GRADIENT)) { p_get_gradient (l_id); } else { if (p_is_layer_alive (l_id) < 0) { return -1; } sample_drawable = gimp_drawable_get (l_id); p_init_gdrw (&l_sample_gdrw, sample_drawable, FALSE, FALSE); p_free_colors (); l_rc = p_sample_analyze (&l_sample_gdrw); } } if ((mc_flags & MC_DST_REMAP) && (l_rc == 0)) { if (p_is_layer_alive (g_values.dst_id) < 0) { return -1; } dst_drawable = gimp_drawable_get (g_values.dst_id); if (gimp_drawable_is_gray (g_values.dst_id)) { if (mc_flags & MC_DST_REMAP) { gimp_image_convert_rgb (gimp_drawable_get_image (g_values.dst_id)); } } p_colorize_drawable (dst_drawable->drawable_id); } if (sample_drawable) { p_end_gdrw (&l_sample_gdrw); } return l_rc; }