1 /* sample_colorize.c
2 * A GIMP Plug-In by Wolfgang Hofer
3 */
4
5 /* GIMP - The GNU Image Manipulation Program
6 * Copyright (C) 1995 Spencer Kimball and Peter Mattis
7 *
8 * This program is free software: you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 3 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see <https://www.gnu.org/licenses/>.
20 */
21
22 #include "config.h"
23
24 #include <stdlib.h>
25 #include <string.h>
26
27 #include <glib/gstdio.h>
28
29 #include <libgimp/gimp.h>
30 #include <libgimp/gimpui.h>
31
32 #include "libgimp/stdplugins-intl.h"
33
34
35 /* Some useful macros */
36 #define RESPONSE_RESET 1
37 #define RESPONSE_GET_COLORS 2
38
39 #define PLUG_IN_PROC "plug-in-sample-colorize"
40 #define PLUG_IN_BINARY "sample-colorize"
41 #define PLUG_IN_ROLE "gimp-sample-colorize"
42 #define NUMBER_IN_ARGS 13
43
44 #define LUMINOSITY_0(X) ((X[0] * 30 + X[1] * 59 + X[2] * 11))
45 #define LUMINOSITY_1(X) ((X[0] * 30 + X[1] * 59 + X[2] * 11) / 100)
46 #define MIX_CHANNEL(a, b, m) (((a * m) + (b * (255 - m))) / 255)
47
48 #define SMP_GRADIENT -444
49 #define SMP_INV_GRADIENT -445
50
51
52 #define PREVIEW_BPP 3
53 #define PREVIEW_SIZE_X 256
54 #define PREVIEW_SIZE_Y 256
55 #define DA_WIDTH 256
56 #define DA_HEIGHT 25
57 #define GRADIENT_HEIGHT 15
58 #define CONTROL_HEIGHT DA_HEIGHT - GRADIENT_HEIGHT
59 #define LEVELS_DA_MASK (GDK_EXPOSURE_MASK | \
60 GDK_ENTER_NOTIFY_MASK | \
61 GDK_BUTTON_PRESS_MASK | \
62 GDK_BUTTON_RELEASE_MASK | \
63 GDK_BUTTON1_MOTION_MASK | \
64 GDK_POINTER_MOTION_HINT_MASK)
65
66 #define LOW_INPUT 0x1
67 #define GAMMA 0x2
68 #define HIGH_INPUT 0x4
69 #define LOW_OUTPUT 0x8
70 #define HIGH_OUTPUT 0x10
71 #define INPUT_LEVELS 0x20
72 #define OUTPUT_LEVELS 0x40
73 #define INPUT_SLIDERS 0x80
74 #define OUTPUT_SLIDERS 0x100
75 #define DRAW 0x200
76 #define REFRESH_DST 0x400
77 #define ALL 0xFFF
78
79 #define MC_GET_SAMPLE_COLORS 1
80 #define MC_DST_REMAP 2
81 #define MC_ALL (MC_GET_SAMPLE_COLORS | MC_DST_REMAP)
82
83 typedef struct
84 {
85 gint32 dst_id;
86 gint32 sample_id;
87
88 gint32 hold_inten; /* TRUE or FALSE */
89 gint32 orig_inten; /* TRUE or FALSE */
90 gint32 rnd_subcolors; /* TRUE or FALSE */
91 gint32 guess_missing; /* TRUE or FALSE */
92 gint32 lvl_in_min; /* 0 up to 254 */
93 gint32 lvl_in_max; /* 1 up to 255 */
94 float lvl_in_gamma; /* 0.1 up to 10.0 (1.0 == linear) */
95 gint32 lvl_out_min; /* 0 up to 254 */
96 gint32 lvl_out_max; /* 1 up to 255 */
97
98 float tol_col_err; /* 0.0% up to 100.0%
99 * this is used to find out colors of the same
100 * colortone, while analyzing sample colors,
101 * It does not make much sense for the user to adjust this
102 * value. (I used a param file to find out a suitable value)
103 */
104 } t_values;
105
106 typedef struct
107 {
108 GtkWidget *dialog;
109 GtkWidget *sample_preview;
110 GtkWidget *dst_preview;
111 GtkWidget *sample_colortab_preview;
112 GtkWidget *sample_drawarea;
113 GtkWidget *in_lvl_gray_preview;
114 GtkWidget *in_lvl_drawarea;
115 GtkAdjustment *adj_lvl_in_min;
116 GtkAdjustment *adj_lvl_in_max;
117 GtkAdjustment *adj_lvl_in_gamma;
118 GtkAdjustment *adj_lvl_out_min;
119 GtkAdjustment *adj_lvl_out_max;
120 GtkWidget *orig_inten_button;
121 gint active_slider;
122 gint slider_pos[5]; /* positions for the five sliders */
123
124 gboolean enable_preview_update;
125 gboolean sample_show_selection;
126 gboolean dst_show_selection;
127 gboolean sample_show_color;
128 gboolean dst_show_color;
129 } t_samp_interface;
130
131
132
133 typedef struct
134 {
135 guchar color[4]; /* R,G,B,A */
136 gint32 sum_color; /* nr. of sourcepixels with (nearly the same) color */
137 void *next;
138 } t_samp_color_elem;
139
140
141
142 typedef struct
143 {
144 gint32 all_samples; /* number of all source pixels with this luminosity */
145 gint from_sample; /* TRUE: color found in sample, FALSE: interpolated color added */
146 t_samp_color_elem *col_ptr; /* List of sample colors at same luminosity */
147 } t_samp_table_elem;
148
149
150 typedef struct
151 {
152 gint32 drawable_id;
153 GeglBuffer *buffer;
154 const Babl *format;
155 gint width;
156 gint height;
157 void *sel_gdrw;
158 gint x1;
159 gint y1;
160 gint x2;
161 gint y2;
162 gint index_alpha; /* 0 == no alpha, 1 == GREYA, 3 == RGBA */
163 gint bpp;
164 gint tile_width;
165 gint tile_height;
166 gint shadow;
167 gint32 seldeltax;
168 gint32 seldeltay;
169 } t_GDRW;
170
171 /*
172 * Some globals
173 */
174
175 static t_samp_interface g_di; /* global dialog interface variables */
176 static t_values g_values = { -1, -1, 1, 1, 0, 1, 0, 255, 1.0, 0, 255, 5.5 };
177 static t_samp_table_elem g_lum_tab[256];
178 static guchar g_lvl_trans_tab[256];
179 static guchar g_out_trans_tab[256];
180 static guchar g_sample_color_tab[256 * 3];
181 static guchar g_dst_preview_buffer[PREVIEW_SIZE_X * PREVIEW_SIZE_Y * 4 ]; /* color copy with mask of dst in previewsize */
182
183 static gint32 g_tol_col_err;
184 static gint32 g_max_col_err;
185 static gint g_Sdebug = FALSE;
186 static gint g_show_progress = FALSE;
187
188 /* Declare a local function.
189 */
190 static void query (void);
191 static void run (const gchar *name,
192 gint nparams,
193 const GimpParam *param,
194 gint *nreturn_vals,
195 GimpParam **return_vals);
196
197 static gint main_colorize (gint mc_flags);
198 static void get_filevalues (void);
199 static void smp_dialog (void);
200 static void refresh_dst_preview (GtkWidget *preview,
201 guchar *src_buffer);
202 static void update_preview (gint32 *id_ptr);
203 static void clear_tables (void);
204 static void free_colors (void);
205 static void levels_update (gint update);
206 static gint level_in_events (GtkWidget *widget,
207 GdkEvent *event);
208 static gint level_out_events (GtkWidget *widget,
209 GdkEvent *event);
210 static void calculate_level_transfers (void);
211 static void get_pixel (t_GDRW *gdrw,
212 gint32 x,
213 gint32 y,
214 guchar *pixel);
215 static void init_gdrw (t_GDRW *gdrw,
216 gint32 drawable_id,
217 gboolean shadow);
218 static void end_gdrw (t_GDRW *gdrw);
219 static gint32 is_layer_alive (gint32 drawable_id);
220 static void remap_pixel (guchar *pixel,
221 const guchar *original,
222 gint bpp2);
223 static void guess_missing_colors (void);
224 static void fill_missing_colors (void);
225 static void smp_get_colors (GtkWidget *dialog);
226 static void get_gradient (gint mode);
227 static void clear_preview (GtkWidget *preview);
228
229 const GimpPlugInInfo PLUG_IN_INFO =
230 {
231 NULL, /* init_proc */
232 NULL, /* quit_proc */
233 query, /* query_proc */
234 run /* run_proc */
235 };
236
MAIN()237 MAIN ()
238
239 static void
240 query (void)
241 {
242 static const GimpParamDef args[]=
243 {
244 { GIMP_PDB_INT32, "run-mode", "The run mode { RUN-INTERACTIVE (0), RUN-NONINTERACTIVE (1) }" },
245 { GIMP_PDB_IMAGE, "image", "Input image (unused)" },
246 { GIMP_PDB_DRAWABLE, "dst-drawable", "The drawable to be colorized (Type GRAY* or RGB*)" },
247 { GIMP_PDB_DRAWABLE, "sample-drawable", "Sample drawable (should be of Type RGB or RGBA)" },
248 { GIMP_PDB_INT32, "hold-inten", "hold brightness intensity levels (TRUE, FALSE)" },
249 { GIMP_PDB_INT32, "orig-inten", "TRUE: hold brightness of original intensity levels. FALSE: Hold Intensity of input levels" },
250 { GIMP_PDB_INT32, "rnd-subcolors", "TRUE: Use all subcolors of same intensity, FALSE: use only one color per intensity" },
251 { GIMP_PDB_INT32, "guess-missing", "TRUE: guess samplecolors for the missing intensity values FALSE: use only colors found in the sample" },
252 { GIMP_PDB_INT32, "in-low", "intensity of lowest input (0 <= in_low <= 254)" },
253 { GIMP_PDB_INT32, "in-high", "intensity of highest input (1 <= in_high <= 255)" },
254 { GIMP_PDB_FLOAT, "gamma", "gamma adjustment factor (0.1 <= gamma <= 10) where 1.0 is linear" },
255 { GIMP_PDB_INT32, "out-low", "lowest sample color intensity (0 <= out_low <= 254)" },
256 { GIMP_PDB_INT32, "out-high", "highest sample color intensity (1 <= out_high <= 255)" }
257 };
258
259 static gchar *help_string =
260 "This plug-in colorizes the contents of the specified (gray) layer"
261 " with the help of a sample (color) layer."
262 " It analyzes all colors in the sample layer."
263 " The sample colors are sorted by brightness (== intentisty) and amount"
264 " and stored in a sample colortable (where brightness is the index)"
265 " The pixels of the destination layer are remapped with the help of the"
266 " sample colortable. If use_subcolors is TRUE, the remapping process uses"
267 " all sample colors of the corresponding brightness-intensity and"
268 " distributes the subcolors according to their amount in the sample"
269 " (If the sample has 5 green, 3 yellow, and 1 red pixel of the "
270 " intensity value 105, the destination pixels at intensity value 105"
271 " are randomly painted in green, yellow and red in a relation of 5:3:1"
272 " If use_subcolors is FALSE only one sample color per intensity is used."
273 " (green will be used in this example)"
274 " The brightness intensity value is transformed at the remapping process"
275 " according to the levels: out_lo, out_hi, in_lo, in_high and gamma"
276 " The in_low / in_high levels specify an initial mapping of the intensity."
277 " The gamma value determines how intensities are interpolated between"
278 " the in_lo and in_high levels. A gamma value of 1.0 results in linear"
279 " interpolation. Higher gamma values results in more high-level intensities"
280 " Lower gamma values results in more low-level intensities"
281 " The out_low/out_high levels constrain the resulting intensity index"
282 " The intensity index is used to pick the corresponding color"
283 " in the sample colortable. If hold_inten is FALSE the picked color"
284 " is used 1:1 as resulting remap_color."
285 " If hold_inten is TRUE The brightness of the picked color is adjusted"
286 " back to the origial intensity value (only hue and saturation are"
287 " taken from the picked sample color)"
288 " (or to the input level, if orig_inten is set FALSE)"
289 " Works on both Grayscale and RGB image with/without alpha channel."
290 " (the image with the dst_drawable is converted to RGB if necessary)"
291 " The sample_drawable should be of type RGB or RGBA";
292
293 gimp_install_procedure (PLUG_IN_PROC,
294 N_("Colorize image using a sample image as a guide"),
295 help_string,
296 "Wolfgang Hofer",
297 "hof@hotbot.com",
298 "02/2000",
299 N_("_Sample Colorize..."),
300 "RGB*, GRAY*",
301 GIMP_PLUGIN,
302 G_N_ELEMENTS (args), 0,
303 args, NULL);
304
305 gimp_plugin_menu_register (PLUG_IN_PROC, "<Image>/Colors/Map");
306 }
307
308 static void
run(const gchar * name,gint nparams,const GimpParam * param,gint * nreturn_vals,GimpParam ** return_vals)309 run (const gchar *name,
310 gint nparams,
311 const GimpParam *param,
312 gint *nreturn_vals,
313 GimpParam **return_vals)
314 {
315 static GimpParam values[1];
316 GimpPDBStatusType status = GIMP_PDB_SUCCESS;
317 const gchar *env;
318 GimpRunMode run_mode;
319 gint32 drawable_id;
320
321 INIT_I18N ();
322 gegl_init (NULL, NULL);
323
324 env = g_getenv ("SAMPLE_COLORIZE_DEBUG");
325 if (env != NULL && (*env != 'n') && (*env != 'N'))
326 g_Sdebug = TRUE;
327
328 if (g_Sdebug)
329 g_printf ("sample colorize run\n");
330 g_show_progress = FALSE;
331
332 run_mode = param[0].data.d_int32;
333 drawable_id = param[2].data.d_drawable;
334
335 *nreturn_vals = 1;
336 *return_vals = values;
337
338 values[0].type = GIMP_PDB_STATUS;
339 values[0].data.d_status = status;
340
341 g_values.lvl_out_min = 0;
342 g_values.lvl_out_max = 255;
343 g_values.lvl_in_min = 0;
344 g_values.lvl_in_max = 255;
345 g_values.lvl_in_gamma = 1.0;
346
347 /* Possibly retrieve data from a previous run */
348 gimp_get_data (PLUG_IN_PROC, &g_values);
349 if (g_values.sample_id == SMP_GRADIENT ||
350 g_values.sample_id == SMP_INV_GRADIENT)
351 g_values.sample_id = -1;
352
353 /* fix value */
354 g_values.tol_col_err = 5.5;
355
356 /* Get the specified dst_drawable */
357 g_values.dst_id = drawable_id;
358
359 clear_tables ();
360
361 /* Make sure that the drawable is gray or RGB color */
362 if (gimp_drawable_is_rgb (drawable_id) ||
363 gimp_drawable_is_gray (drawable_id))
364 {
365 switch (run_mode)
366 {
367 case GIMP_RUN_INTERACTIVE:
368 smp_dialog ();
369 free_colors ();
370 gimp_set_data (PLUG_IN_PROC, &g_values, sizeof (t_values));
371 gimp_displays_flush ();
372 break;
373
374 case GIMP_RUN_NONINTERACTIVE:
375 if (nparams == NUMBER_IN_ARGS)
376 {
377 g_values.sample_id = param[3].data.d_drawable;
378 g_values.hold_inten = param[4].data.d_int32;
379 g_values.orig_inten = param[5].data.d_int32;
380 g_values.rnd_subcolors = param[6].data.d_int32;
381 g_values.guess_missing = param[7].data.d_int32;
382 g_values.lvl_in_min = param[8].data.d_int32;
383 g_values.lvl_in_max = param[9].data.d_int32;
384 g_values.lvl_in_gamma = param[10].data.d_float;
385 g_values.lvl_out_min = param[11].data.d_int32;
386 g_values.lvl_out_max = param[12].data.d_int32;
387 if (main_colorize (MC_GET_SAMPLE_COLORS) >= 0)
388 {
389 main_colorize (MC_DST_REMAP);
390 status = GIMP_PDB_SUCCESS;
391 }
392 else
393 {
394 status = GIMP_PDB_EXECUTION_ERROR;
395 }
396 }
397 else
398 {
399 status = GIMP_PDB_CALLING_ERROR;
400 }
401 break;
402
403 case GIMP_RUN_WITH_LAST_VALS:
404 break;
405 }
406 }
407 else
408 {
409 status = GIMP_PDB_EXECUTION_ERROR;
410 }
411
412 values[0].data.d_status = status;
413 }
414
415 /* ============================================================================
416 * callback and constraint procedures for the dialog
417 * ============================================================================
418 */
419
420 static void
smp_response_callback(GtkWidget * widget,gint response_id)421 smp_response_callback (GtkWidget *widget,
422 gint response_id)
423 {
424 switch (response_id)
425 {
426 case RESPONSE_RESET:
427 g_values.lvl_in_min = 0;
428 g_values.lvl_in_max = 255;
429 g_values.lvl_in_gamma = 1.0;
430 g_values.lvl_out_min = 0;
431 g_values.lvl_out_max = 255;
432
433 levels_update (ALL);
434 break;
435
436 case RESPONSE_GET_COLORS:
437 smp_get_colors (widget);
438 break;
439
440 case GTK_RESPONSE_APPLY:
441 g_show_progress = TRUE;
442 if (main_colorize (MC_DST_REMAP) == 0)
443 {
444 gimp_displays_flush ();
445 g_show_progress = FALSE;
446 return;
447 }
448 gtk_dialog_set_response_sensitive (GTK_DIALOG (widget),
449 GTK_RESPONSE_APPLY, FALSE);
450 break;
451
452 default:
453 gtk_widget_destroy (widget);
454 gtk_main_quit ();
455 break;
456 }
457 }
458
459 static void
smp_toggle_callback(GtkWidget * widget,gpointer data)460 smp_toggle_callback (GtkWidget *widget,
461 gpointer data)
462 {
463 gboolean *toggle_val = (gboolean *)data;
464
465 *toggle_val = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget));
466
467 if ((data == &g_di.sample_show_selection) ||
468 (data == &g_di.sample_show_color))
469 {
470 update_preview (&g_values.sample_id);
471 return;
472 }
473
474 if ((data == &g_di.dst_show_selection) ||
475 (data == &g_di.dst_show_color))
476 {
477 update_preview (&g_values.dst_id);
478 return;
479 }
480
481 if ((data == &g_values.hold_inten) ||
482 (data == &g_values.orig_inten) ||
483 (data == &g_values.rnd_subcolors))
484 {
485 if (g_di.orig_inten_button)
486 gtk_widget_set_sensitive (g_di.orig_inten_button,g_values.hold_inten);
487 refresh_dst_preview (g_di.dst_preview, &g_dst_preview_buffer[0]);
488 }
489
490 if (data == &g_values.guess_missing)
491 {
492 if (g_values.guess_missing)
493 guess_missing_colors ();
494 else
495 fill_missing_colors ();
496 smp_get_colors (NULL);
497 }
498 }
499
500 static void
smp_sample_combo_callback(GtkWidget * widget)501 smp_sample_combo_callback (GtkWidget *widget)
502 {
503 gint value;
504
505 gimp_int_combo_box_get_active (GIMP_INT_COMBO_BOX (widget), &value);
506
507 g_values.sample_id = value;
508
509 if (value == SMP_GRADIENT || value == SMP_INV_GRADIENT)
510 {
511 get_gradient (value);
512 smp_get_colors (NULL);
513
514 if (g_di.sample_preview)
515 clear_preview (g_di.sample_preview);
516
517 gtk_dialog_set_response_sensitive (GTK_DIALOG (g_di.dialog),
518 GTK_RESPONSE_APPLY, TRUE);
519 gtk_dialog_set_response_sensitive (GTK_DIALOG (g_di.dialog),
520 RESPONSE_GET_COLORS, FALSE);
521 }
522 else
523 {
524 update_preview (&g_values.sample_id);
525
526 gtk_dialog_set_response_sensitive (GTK_DIALOG (g_di.dialog),
527 RESPONSE_GET_COLORS, TRUE);
528 }
529 }
530
531 static void
smp_dest_combo_callback(GtkWidget * widget)532 smp_dest_combo_callback (GtkWidget *widget)
533 {
534 gimp_int_combo_box_get_active (GIMP_INT_COMBO_BOX (widget),
535 &g_values.dst_id);
536
537 update_preview (&g_values.dst_id);
538
539 gtk_dialog_set_response_sensitive (GTK_DIALOG (g_di.dialog),
540 RESPONSE_GET_COLORS, TRUE);
541 }
542
543 static gint
smp_constrain(gint32 image_id,gint32 drawable_id,gpointer data)544 smp_constrain (gint32 image_id,
545 gint32 drawable_id,
546 gpointer data)
547 {
548 if (image_id < 0)
549 return FALSE;
550
551 /* don't accept layers from indexed images */
552 if (gimp_drawable_is_indexed (drawable_id))
553 return FALSE;
554
555 return TRUE;
556 }
557
558
559 static void
smp_adj_lvl_in_max_upd_callback(GtkAdjustment * adjustment)560 smp_adj_lvl_in_max_upd_callback (GtkAdjustment *adjustment)
561 {
562 gint32 value;
563 gint upd_flags;
564
565 value = CLAMP ((gtk_adjustment_get_value (adjustment)), 1, 255);
566
567 if (value != g_values.lvl_in_max)
568 {
569 g_values.lvl_in_max = value;
570 upd_flags = INPUT_SLIDERS | INPUT_LEVELS | DRAW | REFRESH_DST;
571 if (g_values.lvl_in_max < g_values.lvl_in_min)
572 {
573 g_values.lvl_in_min = g_values.lvl_in_max;
574 upd_flags |= LOW_INPUT;
575 }
576 levels_update (upd_flags);
577 }
578 }
579
580 static void
smp_adj_lvl_in_min_upd_callback(GtkAdjustment * adjustment)581 smp_adj_lvl_in_min_upd_callback (GtkAdjustment *adjustment)
582 {
583 double value;
584 gint upd_flags;
585
586 value = CLAMP ((gtk_adjustment_get_value (adjustment)), 0, 254);
587
588 if (value != g_values.lvl_in_min)
589 {
590 g_values.lvl_in_min = value;
591 upd_flags = INPUT_SLIDERS | INPUT_LEVELS | DRAW | REFRESH_DST;
592 if (g_values.lvl_in_min > g_values.lvl_in_max)
593 {
594 g_values.lvl_in_max = g_values.lvl_in_min;
595 upd_flags |= HIGH_INPUT;
596 }
597 levels_update (upd_flags);
598 }
599 }
600
601 static void
smp_text_gamma_upd_callback(GtkAdjustment * adjustment)602 smp_text_gamma_upd_callback (GtkAdjustment *adjustment)
603 {
604 double value;
605
606 value = CLAMP ((gtk_adjustment_get_value (adjustment)), 0.1, 10.0);
607
608 if (value != g_values.lvl_in_gamma)
609 {
610 g_values.lvl_in_gamma = value;
611 levels_update (INPUT_SLIDERS | INPUT_LEVELS | DRAW | REFRESH_DST);
612 }
613 }
614
615 static void
smp_adj_lvl_out_max_upd_callback(GtkAdjustment * adjustment)616 smp_adj_lvl_out_max_upd_callback (GtkAdjustment *adjustment)
617 {
618 gint32 value;
619 gint upd_flags;
620
621 value = CLAMP ((gtk_adjustment_get_value (adjustment)), 1, 255);
622
623 if (value != g_values.lvl_out_max)
624 {
625 g_values.lvl_out_max = value;
626 upd_flags = OUTPUT_SLIDERS | OUTPUT_LEVELS | DRAW | REFRESH_DST;
627 if (g_values.lvl_out_max < g_values.lvl_out_min)
628 {
629 g_values.lvl_out_min = g_values.lvl_out_max;
630 upd_flags |= LOW_OUTPUT;
631 }
632 levels_update (upd_flags);
633 }
634 }
635
636 static void
smp_adj_lvl_out_min_upd_callback(GtkAdjustment * adjustment)637 smp_adj_lvl_out_min_upd_callback (GtkAdjustment *adjustment)
638 {
639 double value;
640 gint upd_flags;
641
642 value = CLAMP ((gtk_adjustment_get_value (adjustment)), 0, 254);
643
644 if (value != g_values.lvl_out_min)
645 {
646 g_values.lvl_out_min = value;
647 upd_flags = OUTPUT_SLIDERS | OUTPUT_LEVELS | DRAW | REFRESH_DST;
648 if (g_values.lvl_out_min > g_values.lvl_out_max)
649 {
650 g_values.lvl_out_max = g_values.lvl_out_min;
651 upd_flags |= HIGH_OUTPUT;
652 }
653 levels_update (upd_flags);
654 }
655 }
656
657 /* ============================================================================
658 * DIALOG helper procedures
659 * (workers for the updates on the preview widgets)
660 * ============================================================================
661 */
662
663 static void
refresh_dst_preview(GtkWidget * preview,guchar * src_buffer)664 refresh_dst_preview (GtkWidget *preview,
665 guchar *src_buffer)
666 {
667 guchar allrowsbuf[3 * PREVIEW_SIZE_X * PREVIEW_SIZE_Y];
668 guchar *ptr;
669 guchar *src_ptr;
670 guchar lum;
671 guchar maskbyte;
672 gint x, y;
673 gint preview_bpp;
674 gint src_bpp;
675
676 preview_bpp = PREVIEW_BPP;
677 src_bpp = PREVIEW_BPP +1; /* 3 colors + 1 maskbyte */
678 src_ptr = src_buffer;
679
680 ptr = allrowsbuf;
681 for (y = 0; y < PREVIEW_SIZE_Y; y++)
682 {
683 for (x = 0; x < PREVIEW_SIZE_X; x++)
684 {
685 if ((maskbyte = src_ptr[3]) == 0)
686 {
687 ptr[0] = src_ptr[0];
688 ptr[1] = src_ptr[1];
689 ptr[2] = src_ptr[2];
690 }
691 else
692 {
693 if (g_di.dst_show_color)
694 {
695 remap_pixel (ptr, src_ptr, 3);
696 }
697 else
698 {
699 /* lum = g_out_trans_tab[g_lvl_trans_tab[LUMINOSITY_1(src_ptr)]]; */
700 /* get brightness from (uncolorized) original */
701
702 lum = g_lvl_trans_tab[LUMINOSITY_1 (src_ptr)];
703 /* get brightness from (uncolorized) original */
704
705 ptr[0] = lum;
706 ptr[1] = lum;
707 ptr[2] = lum;
708 }
709
710 if (maskbyte < 255)
711 {
712 ptr[0] = MIX_CHANNEL (ptr[0], src_ptr[0], maskbyte);
713 ptr[1] = MIX_CHANNEL (ptr[1], src_ptr[1], maskbyte);
714 ptr[2] = MIX_CHANNEL (ptr[2], src_ptr[2], maskbyte);
715 }
716 }
717 ptr += preview_bpp;
718 src_ptr += src_bpp;
719 }
720 }
721 gimp_preview_area_draw (GIMP_PREVIEW_AREA (preview),
722 0, 0, PREVIEW_SIZE_X, PREVIEW_SIZE_Y,
723 GIMP_RGB_IMAGE,
724 allrowsbuf,
725 PREVIEW_SIZE_X * 3);
726 }
727
728 static void
clear_preview(GtkWidget * preview)729 clear_preview (GtkWidget *preview)
730 {
731 gimp_preview_area_fill (GIMP_PREVIEW_AREA (preview),
732 0, 0, PREVIEW_SIZE_X, PREVIEW_SIZE_Y,
733 170, 170, 170);
734 }
735
736 static void
update_pv(GtkWidget * preview,gboolean show_selection,t_GDRW * gdrw,guchar * dst_buffer,gboolean is_color)737 update_pv (GtkWidget *preview,
738 gboolean show_selection,
739 t_GDRW *gdrw,
740 guchar *dst_buffer,
741 gboolean is_color)
742 {
743 guchar allrowsbuf[4 * PREVIEW_SIZE_X * PREVIEW_SIZE_Y];
744 guchar pixel[4];
745 guchar *ptr;
746 gint x, y;
747 gint x2, y2;
748 gint ofx, ofy;
749 gint sel_width, sel_height;
750 double scale_x, scale_y;
751 guchar *buf_ptr;
752 guchar dummy[4];
753 guchar maskbytes[4];
754 gint dstep;
755 guchar alpha;
756
757
758 if (!preview)
759 return;
760
761 /* init gray pixel (if we are called without a sourceimage (gdwr == NULL) */
762 pixel[0] = pixel[1] =pixel[2] = pixel[3] = 127;
763
764 /* calculate scale factors and offsets */
765 if (show_selection)
766 {
767 sel_width = gdrw->x2 - gdrw->x1;
768 sel_height = gdrw->y2 - gdrw->y1;
769
770 if (sel_height > sel_width)
771 {
772 scale_y = (gfloat) sel_height / PREVIEW_SIZE_Y;
773 scale_x = scale_y;
774 ofx = (gdrw->x1 +
775 ((sel_width - (PREVIEW_SIZE_X * scale_x)) / 2));
776 ofy = gdrw->y1;
777 }
778 else
779 {
780 scale_x = (gfloat) sel_width / PREVIEW_SIZE_X;
781 scale_y = scale_x;
782 ofx = gdrw->x1;
783 ofy = (gdrw->y1 +
784 ((sel_height - (PREVIEW_SIZE_Y * scale_y)) / 2));
785 }
786 }
787 else
788 {
789 if (gdrw->height > gdrw->width)
790 {
791 scale_y = (gfloat) gdrw->height / PREVIEW_SIZE_Y;
792 scale_x = scale_y;
793 ofx = (gdrw->width - (PREVIEW_SIZE_X * scale_x)) / 2;
794 ofy = 0;
795 }
796 else
797 {
798 scale_x = (gfloat) gdrw->width / PREVIEW_SIZE_X;
799 scale_y = scale_x;
800 ofx = 0;
801 ofy = (gdrw->height - (PREVIEW_SIZE_Y * scale_y)) / 2;
802 }
803 }
804
805 /* check if output goes to previw widget or to dst_buffer */
806 if (dst_buffer)
807 {
808 buf_ptr = dst_buffer;
809 dstep = PREVIEW_BPP +1;
810 }
811 else
812 {
813 buf_ptr = &dummy[0];
814 dstep = 0;
815 }
816
817
818 /* render preview */
819 ptr = allrowsbuf;
820 for (y = 0; y < PREVIEW_SIZE_Y; y++)
821 {
822 for (x = 0; x < PREVIEW_SIZE_X; x++)
823 {
824 if (gdrw->drawable_id > 0)
825 {
826 x2 = ofx + (x * scale_x);
827 y2 = ofy + (y * scale_y);
828 get_pixel (gdrw, x2, y2, &pixel[0]);
829 if (gdrw->sel_gdrw)
830 {
831 get_pixel (gdrw->sel_gdrw,
832 x2 + gdrw->seldeltax,
833 y2 + gdrw->seldeltay,
834 &maskbytes[0]);
835 }
836 else
837 {
838 maskbytes[0] = 255;
839 }
840 }
841
842 alpha = pixel[gdrw->index_alpha];
843 if (is_color && (gdrw->bpp > 2))
844 {
845 buf_ptr[0] = ptr[0] = pixel[0];
846 buf_ptr[1] = ptr[1] = pixel[1];
847 buf_ptr[2] = ptr[2] = pixel[2];
848 }
849 else
850 {
851 if (gdrw->bpp > 2)
852 *ptr = LUMINOSITY_1 (pixel);
853 else
854 *ptr = pixel[0];
855
856 *buf_ptr = *ptr;
857 buf_ptr[1] = ptr[1] = *ptr;
858 buf_ptr[2] = ptr[2] = *ptr;
859 }
860 if (gdrw->index_alpha == 0) /* has no alpha channel */
861 buf_ptr[3] = ptr[3] = 255;
862 else
863 buf_ptr[3] = ptr[3] = MIN (maskbytes[0], alpha);
864 buf_ptr += dstep; /* advance (or stay at dummy byte) */
865 ptr += 4;
866 }
867
868 }
869
870 if (dst_buffer == NULL)
871 {
872 gimp_preview_area_draw (GIMP_PREVIEW_AREA (preview),
873 0, 0, PREVIEW_SIZE_X, PREVIEW_SIZE_Y,
874 GIMP_RGBA_IMAGE,
875 allrowsbuf,
876 PREVIEW_SIZE_X * 4);
877 gtk_widget_queue_draw (preview);
878 }
879 }
880
881 static void
update_preview(gint32 * id_ptr)882 update_preview (gint32 *id_ptr)
883 {
884 t_GDRW gdrw;
885 gboolean drawable = FALSE;
886
887 if (g_Sdebug)
888 g_printf ("UPD PREVIEWS ID:%d ENABLE_UPD:%d\n",
889 id_ptr ? (int) *id_ptr : -1, (int)g_di.enable_preview_update);
890
891 if (id_ptr == NULL || !g_di.enable_preview_update)
892 return;
893 if (is_layer_alive (*id_ptr) < 0)
894 {
895 /* clear preview on invalid drawable id
896 * (SMP_GRADIENT and SMP_INV_GRADIENT)
897 */
898 if (id_ptr == &g_values.sample_id)
899 clear_preview (g_di.sample_preview);
900 if (id_ptr == &g_values.dst_id)
901 clear_preview (g_di.dst_preview);
902 return;
903 }
904
905 if (id_ptr == &g_values.sample_id)
906 {
907 drawable = TRUE;
908
909 init_gdrw (&gdrw, *id_ptr, FALSE);
910 update_pv (g_di.sample_preview, g_di.sample_show_selection, &gdrw,
911 NULL, g_di.sample_show_color);
912 }
913 else if (id_ptr == &g_values.dst_id)
914 {
915 drawable = TRUE;
916
917 init_gdrw (&gdrw, *id_ptr, FALSE);
918 update_pv (g_di.dst_preview, g_di.dst_show_selection, &gdrw,
919 &g_dst_preview_buffer[0], g_di.dst_show_color);
920 refresh_dst_preview (g_di.dst_preview, &g_dst_preview_buffer[0]);
921 }
922
923 if (drawable)
924 end_gdrw (&gdrw);
925 }
926
927 static void
levels_draw_slider(cairo_t * cr,GdkColor * border_color,GdkColor * fill_color,gint xpos)928 levels_draw_slider (cairo_t *cr,
929 GdkColor *border_color,
930 GdkColor *fill_color,
931 gint xpos)
932 {
933 cairo_move_to (cr, xpos, 0);
934 cairo_line_to (cr, xpos - (CONTROL_HEIGHT - 1) / 2, CONTROL_HEIGHT - 1);
935 cairo_line_to (cr, xpos + (CONTROL_HEIGHT - 1) / 2, CONTROL_HEIGHT - 1);
936 cairo_line_to (cr, xpos, 0);
937
938 gdk_cairo_set_source_color (cr, fill_color);
939 cairo_fill_preserve (cr);
940
941 gdk_cairo_set_source_color (cr, border_color);
942 cairo_stroke (cr);
943 }
944
945 static void
smp_get_colors(GtkWidget * dialog)946 smp_get_colors (GtkWidget *dialog)
947 {
948 gint i;
949 guchar buffer[3 * DA_WIDTH * GRADIENT_HEIGHT];
950
951 update_preview (&g_values.sample_id);
952
953 if (dialog && main_colorize (MC_GET_SAMPLE_COLORS) >= 0) /* do not colorize, just analyze sample colors */
954 gtk_dialog_set_response_sensitive (GTK_DIALOG (g_di.dialog),
955 GTK_RESPONSE_APPLY, TRUE);
956 for (i = 0; i < GRADIENT_HEIGHT; i++)
957 memcpy (buffer + i * 3 * DA_WIDTH, g_sample_color_tab, 3 * DA_WIDTH);
958
959 update_preview (&g_values.dst_id);
960
961 gimp_preview_area_draw (GIMP_PREVIEW_AREA (g_di.sample_colortab_preview),
962 0, 0, DA_WIDTH, GRADIENT_HEIGHT,
963 GIMP_RGB_IMAGE,
964 buffer,
965 DA_WIDTH * 3);
966 }
967
968
969 static void
levels_update(gint update)970 levels_update (gint update)
971 {
972 gint i;
973
974 if (g_Sdebug)
975 g_printf ("levels_update: update reques %x\n", update);
976
977 /* Recalculate the transfer array */
978 calculate_level_transfers ();
979 if (update & REFRESH_DST)
980 refresh_dst_preview (g_di.dst_preview, &g_dst_preview_buffer[0]);
981
982 /* update the spinbutton entry widgets */
983 if (update & LOW_INPUT)
984 gtk_adjustment_set_value (g_di.adj_lvl_in_min,
985 g_values.lvl_in_min);
986 if (update & GAMMA)
987 gtk_adjustment_set_value (g_di.adj_lvl_in_gamma,
988 g_values.lvl_in_gamma);
989 if (update & HIGH_INPUT)
990 gtk_adjustment_set_value (g_di.adj_lvl_in_max,
991 g_values.lvl_in_max);
992 if (update & LOW_OUTPUT)
993 gtk_adjustment_set_value (g_di.adj_lvl_out_min,
994 g_values.lvl_out_min);
995 if (update & HIGH_OUTPUT)
996 gtk_adjustment_set_value (g_di.adj_lvl_out_max,
997 g_values.lvl_out_max);
998 if (update & INPUT_LEVELS)
999 {
1000 guchar buffer[DA_WIDTH * GRADIENT_HEIGHT];
1001 for (i = 0; i < GRADIENT_HEIGHT; i++)
1002 memcpy (buffer + DA_WIDTH * i, g_lvl_trans_tab, DA_WIDTH);
1003 gimp_preview_area_draw (GIMP_PREVIEW_AREA (g_di.in_lvl_gray_preview),
1004 0, 0, DA_WIDTH, GRADIENT_HEIGHT,
1005 GIMP_GRAY_IMAGE,
1006 buffer,
1007 DA_WIDTH);
1008 }
1009
1010 if (update & INPUT_SLIDERS)
1011 {
1012 GtkStyle *style = gtk_widget_get_style (g_di.in_lvl_drawarea);
1013 cairo_t *cr = gdk_cairo_create (gtk_widget_get_window (g_di.in_lvl_drawarea));
1014 gdouble width, mid, tmp;
1015
1016 gdk_cairo_set_source_color (cr, &style->bg[GTK_STATE_NORMAL]);
1017 cairo_paint (cr);
1018
1019 cairo_translate (cr, 0.5, 0.5);
1020 cairo_set_line_width (cr, 1.0);
1021
1022 g_di.slider_pos[0] = DA_WIDTH * ((double) g_values.lvl_in_min / 255.0);
1023 g_di.slider_pos[2] = DA_WIDTH * ((double) g_values.lvl_in_max / 255.0);
1024
1025 width = (double) (g_di.slider_pos[2] - g_di.slider_pos[0]) / 2.0;
1026 mid = g_di.slider_pos[0] + width;
1027 tmp = log10 (1.0 / g_values.lvl_in_gamma);
1028 g_di.slider_pos[1] = (int) (mid + width * tmp + 0.5);
1029
1030 levels_draw_slider (cr,
1031 &style->black,
1032 &style->dark[GTK_STATE_NORMAL],
1033 g_di.slider_pos[1]);
1034 levels_draw_slider (cr,
1035 &style->black,
1036 &style->black,
1037 g_di.slider_pos[0]);
1038 levels_draw_slider (cr,
1039 &style->black,
1040 &style->white,
1041 g_di.slider_pos[2]);
1042
1043 cairo_destroy (cr);
1044 }
1045
1046 if (update & OUTPUT_SLIDERS)
1047 {
1048 GtkStyle *style = gtk_widget_get_style (g_di.sample_drawarea);
1049 cairo_t *cr = gdk_cairo_create (gtk_widget_get_window (g_di.sample_drawarea));
1050
1051 gdk_cairo_set_source_color (cr, &style->bg[GTK_STATE_NORMAL]);
1052 cairo_paint (cr);
1053
1054 cairo_translate (cr, 0.5, 0.5);
1055 cairo_set_line_width (cr, 1.0);
1056
1057 g_di.slider_pos[3] = DA_WIDTH * ((double) g_values.lvl_out_min / 255.0);
1058 g_di.slider_pos[4] = DA_WIDTH * ((double) g_values.lvl_out_max / 255.0);
1059
1060 levels_draw_slider (cr,
1061 &style->black,
1062 &style->black,
1063 g_di.slider_pos[3]);
1064 levels_draw_slider (cr,
1065 &style->black,
1066 &style->black,
1067 g_di.slider_pos[4]);
1068
1069 cairo_destroy (cr);
1070 }
1071 }
1072
1073 static gboolean
level_in_events(GtkWidget * widget,GdkEvent * event)1074 level_in_events (GtkWidget *widget,
1075 GdkEvent *event)
1076 {
1077 GdkEventButton *bevent;
1078 GdkEventMotion *mevent;
1079 gdouble width, mid, tmp;
1080 gint x, distance;
1081 gint i;
1082 gint update = FALSE;
1083
1084 switch (event->type)
1085 {
1086 case GDK_EXPOSE:
1087 if (g_Sdebug)
1088 g_printf ("EVENT: GDK_EXPOSE\n");
1089 if (widget == g_di.in_lvl_drawarea)
1090 levels_update (INPUT_SLIDERS);
1091 break;
1092
1093 case GDK_BUTTON_PRESS:
1094 if (g_Sdebug)
1095 g_printf ("EVENT: GDK_BUTTON_PRESS\n");
1096 gtk_grab_add (widget);
1097 bevent = (GdkEventButton *) event;
1098
1099 distance = G_MAXINT;
1100 for (i = 0; i < 3; i++)
1101 {
1102 if (fabs (bevent->x - g_di.slider_pos[i]) < distance)
1103 {
1104 g_di.active_slider = i;
1105 distance = fabs (bevent->x - g_di.slider_pos[i]);
1106 }
1107 }
1108 x = bevent->x;
1109 update = TRUE;
1110 break;
1111
1112 case GDK_BUTTON_RELEASE:
1113 if (g_Sdebug)
1114 g_printf ("EVENT: GDK_BUTTON_RELEASE\n");
1115 gtk_grab_remove (widget);
1116 switch (g_di.active_slider)
1117 {
1118 case 0: /* low input */
1119 levels_update (LOW_INPUT | GAMMA | DRAW);
1120 break;
1121
1122 case 1: /* gamma */
1123 levels_update (GAMMA);
1124 break;
1125
1126 case 2: /* high input */
1127 levels_update (HIGH_INPUT | GAMMA | DRAW);
1128 break;
1129 }
1130
1131 refresh_dst_preview (g_di.dst_preview, &g_dst_preview_buffer[0]);
1132 break;
1133
1134 case GDK_MOTION_NOTIFY:
1135 if (g_Sdebug)
1136 g_printf ("EVENT: GDK_MOTION_NOTIFY\n");
1137 mevent = (GdkEventMotion *) event;
1138 x = mevent->x;
1139 gdk_event_request_motions (mevent);
1140 update = TRUE;
1141 break;
1142
1143 default:
1144 if (g_Sdebug)
1145 g_printf ("EVENT: default\n");
1146 break;
1147 }
1148
1149 if (update)
1150 {
1151 if (g_Sdebug)
1152 g_printf ("EVENT: ** update **\n");
1153 switch (g_di.active_slider)
1154 {
1155 case 0: /* low input */
1156 g_values.lvl_in_min = ((double) x / (double) DA_WIDTH) * 255.0;
1157 g_values.lvl_in_min = CLAMP (g_values.lvl_in_min,
1158 0, g_values.lvl_in_max);
1159 break;
1160
1161 case 1: /* gamma */
1162 width = (double) (g_di.slider_pos[2] - g_di.slider_pos[0]) / 2.0;
1163 mid = g_di.slider_pos[0] + width;
1164
1165 x = CLAMP (x, g_di.slider_pos[0], g_di.slider_pos[2]);
1166 tmp = (double) (x - mid) / width;
1167 g_values.lvl_in_gamma = 1.0 / pow (10, tmp);
1168
1169 /* round the gamma value to the nearest 1/100th */
1170 g_values.lvl_in_gamma =
1171 floor (g_values.lvl_in_gamma * 100 + 0.5) / 100.0;
1172 break;
1173
1174 case 2: /* high input */
1175 g_values.lvl_in_max = ((double) x / (double) DA_WIDTH) * 255.0;
1176 g_values.lvl_in_max = CLAMP (g_values.lvl_in_max,
1177 g_values.lvl_in_min, 255);
1178 break;
1179 }
1180
1181 levels_update (INPUT_SLIDERS | INPUT_LEVELS | DRAW);
1182 }
1183
1184 return FALSE;
1185 }
1186
1187 static gboolean
level_out_events(GtkWidget * widget,GdkEvent * event)1188 level_out_events (GtkWidget *widget,
1189 GdkEvent *event)
1190 {
1191 GdkEventButton *bevent;
1192 GdkEventMotion *mevent;
1193 gint x, distance;
1194 gint i;
1195 gint update = FALSE;
1196
1197 switch (event->type)
1198 {
1199 case GDK_EXPOSE:
1200 if (g_Sdebug)
1201 g_printf ("OUT_EVENT: GDK_EXPOSE\n");
1202 if (widget == g_di.sample_drawarea)
1203 levels_update (OUTPUT_SLIDERS);
1204 break;
1205
1206 case GDK_BUTTON_PRESS:
1207 if (g_Sdebug)
1208 g_printf ("OUT_EVENT: GDK_BUTTON_PRESS\n");
1209 bevent = (GdkEventButton *) event;
1210
1211 distance = G_MAXINT;
1212 for (i = 3; i < 5; i++)
1213 {
1214 if (fabs (bevent->x - g_di.slider_pos[i]) < distance)
1215 {
1216 g_di.active_slider = i;
1217 distance = fabs (bevent->x - g_di.slider_pos[i]);
1218 }
1219 }
1220
1221 x = bevent->x;
1222 update = TRUE;
1223 break;
1224
1225 case GDK_BUTTON_RELEASE:
1226 if (g_Sdebug)
1227 g_printf ("OUT_EVENT: GDK_BUTTON_RELEASE\n");
1228 switch (g_di.active_slider)
1229 {
1230 case 3: /* low output */
1231 levels_update (LOW_OUTPUT | DRAW);
1232 break;
1233
1234 case 4: /* high output */
1235 levels_update (HIGH_OUTPUT | DRAW);
1236 break;
1237 }
1238
1239 refresh_dst_preview (g_di.dst_preview, &g_dst_preview_buffer[0]);
1240 break;
1241
1242 case GDK_MOTION_NOTIFY:
1243 if (g_Sdebug)
1244 g_printf ("OUT_EVENT: GDK_MOTION_NOTIFY\n");
1245 mevent = (GdkEventMotion *) event;
1246 x = mevent->x;
1247 gdk_event_request_motions (mevent);
1248 update = TRUE;
1249 break;
1250
1251 default:
1252 if (g_Sdebug)
1253 g_printf ("OUT_EVENT: default\n");
1254 break;
1255 }
1256
1257 if (update)
1258 {
1259 if (g_Sdebug)
1260 g_printf ("OUT_EVENT: ** update **\n");
1261 switch (g_di.active_slider)
1262 {
1263 case 3: /* low output */
1264 g_values.lvl_out_min = ((double) x / (double) DA_WIDTH) * 255.0;
1265 g_values.lvl_out_min = CLAMP (g_values.lvl_out_min,
1266 0, g_values.lvl_out_max);
1267 break;
1268
1269 case 4: /* high output */
1270 g_values.lvl_out_max = ((double) x / (double) DA_WIDTH) * 255.0;
1271 g_values.lvl_out_max = CLAMP (g_values.lvl_out_max,
1272 g_values.lvl_out_min, 255);
1273 break;
1274 }
1275
1276 levels_update (OUTPUT_SLIDERS | OUTPUT_LEVELS | DRAW);
1277 }
1278
1279 return FALSE;
1280 }
1281
1282
1283 /* ============================================================================
1284 * smp_dialog
1285 * The Interactive Dialog
1286 * ============================================================================
1287 */
1288 static void
smp_dialog(void)1289 smp_dialog (void)
1290 {
1291 GtkWidget *dialog;
1292 GtkWidget *hbox;
1293 GtkWidget *vbox2;
1294 GtkWidget *frame;
1295 GtkWidget *table;
1296 GtkWidget *check_button;
1297 GtkWidget *label;
1298 GtkWidget *combo;
1299 GtkWidget *spinbutton;
1300 GtkObject *data;
1301 gint ty;
1302
1303 /* set flags for check buttons from mode value bits */
1304 if (g_Sdebug)
1305 g_print ("smp_dialog START\n");
1306
1307 /* init some dialog variables */
1308 g_di.enable_preview_update = FALSE;
1309 g_di.sample_show_selection = TRUE;
1310 g_di.dst_show_selection = TRUE;
1311 g_di.dst_show_color = TRUE;
1312 g_di.sample_show_color = TRUE;
1313 g_di.orig_inten_button = NULL;
1314
1315 /* Init GTK */
1316 gimp_ui_init (PLUG_IN_BINARY, TRUE);
1317
1318 /* Main Dialog */
1319 g_di.dialog = dialog =
1320 gimp_dialog_new (_("Sample Colorize"), PLUG_IN_ROLE,
1321 NULL, 0,
1322 gimp_standard_help_func, PLUG_IN_PROC,
1323
1324 _("_Reset"), RESPONSE_RESET,
1325 _("Get _Sample Colors"), RESPONSE_GET_COLORS,
1326 _("_Close"), GTK_RESPONSE_CLOSE,
1327 _("_Apply"), GTK_RESPONSE_APPLY,
1328
1329 NULL);
1330
1331 gtk_dialog_set_alternative_button_order (GTK_DIALOG (dialog),
1332 RESPONSE_GET_COLORS,
1333 RESPONSE_RESET,
1334 GTK_RESPONSE_APPLY,
1335 GTK_RESPONSE_CLOSE,
1336 -1);
1337
1338 gimp_window_set_transient (GTK_WINDOW (dialog));
1339
1340 g_signal_connect (dialog, "response",
1341 G_CALLBACK (smp_response_callback),
1342 NULL);
1343
1344 /* table for values */
1345 table = gtk_table_new (7, 5, FALSE);
1346 gtk_table_set_row_spacings (GTK_TABLE (table), 12);
1347 gtk_table_set_col_spacings (GTK_TABLE (table), 6);
1348 gtk_container_set_border_width (GTK_CONTAINER (table), 12);
1349 gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))),
1350 table, TRUE, TRUE, 0);
1351
1352 ty = 0;
1353 /* layer combo_box (Dst) */
1354 label = gtk_label_new (_("Destination:"));
1355 gtk_label_set_xalign (GTK_LABEL (label), 1.0);
1356 gtk_table_attach (GTK_TABLE (table), label, 0, 1, ty, ty + 1,
1357 GTK_FILL, GTK_FILL, 4, 0);
1358 gtk_widget_show (label);
1359
1360 combo = gimp_layer_combo_box_new (smp_constrain, NULL);
1361 gimp_int_combo_box_connect (GIMP_INT_COMBO_BOX (combo), g_values.dst_id,
1362 G_CALLBACK (smp_dest_combo_callback),
1363 NULL);
1364
1365 gtk_table_attach (GTK_TABLE (table), combo, 1, 2, ty, ty + 1,
1366 GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
1367 gtk_widget_show (combo);
1368
1369 /* layer combo_box (Sample) */
1370 label = gtk_label_new (_("Sample:"));
1371 gtk_label_set_xalign (GTK_LABEL (label), 1.0);
1372 gtk_table_attach (GTK_TABLE (table), label, 3, 4, ty, ty + 1,
1373 GTK_FILL, GTK_FILL, 4, 0);
1374 gtk_widget_show (label);
1375
1376 combo = gimp_layer_combo_box_new (smp_constrain, NULL);
1377
1378 gimp_int_combo_box_prepend (GIMP_INT_COMBO_BOX (combo),
1379 GIMP_INT_STORE_VALUE, SMP_INV_GRADIENT,
1380 GIMP_INT_STORE_LABEL, _("From reverse gradient"),
1381 GIMP_INT_STORE_ICON_NAME, GIMP_ICON_GRADIENT,
1382 -1);
1383 gimp_int_combo_box_prepend (GIMP_INT_COMBO_BOX (combo),
1384 GIMP_INT_STORE_VALUE, SMP_GRADIENT,
1385 GIMP_INT_STORE_LABEL, _("From gradient"),
1386 GIMP_INT_STORE_ICON_NAME, GIMP_ICON_GRADIENT,
1387 -1);
1388
1389 gimp_int_combo_box_connect (GIMP_INT_COMBO_BOX (combo), g_values.sample_id,
1390 G_CALLBACK (smp_sample_combo_callback),
1391 NULL);
1392
1393 gtk_table_attach (GTK_TABLE (table), combo, 4, 5, ty, ty + 1,
1394 GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
1395 gtk_widget_show (combo);
1396
1397 ty++;
1398
1399
1400 hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
1401 gtk_table_attach (GTK_TABLE (table), hbox, 0, 2, ty, ty + 1,
1402 GTK_FILL, 0, 0, 0);
1403 gtk_widget_show (hbox);
1404
1405 /* check button */
1406 check_button = gtk_check_button_new_with_mnemonic (_("Sho_w selection"));
1407 gtk_box_pack_start (GTK_BOX (hbox), check_button, FALSE, FALSE, 0);
1408 gtk_widget_show (check_button);
1409
1410 g_signal_connect (check_button, "toggled",
1411 G_CALLBACK (smp_toggle_callback),
1412 &g_di.dst_show_selection);
1413 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (check_button),
1414 g_di.dst_show_selection);
1415
1416 /* check button */
1417 check_button = gtk_check_button_new_with_mnemonic (_("Show co_lor"));
1418 gtk_box_pack_start (GTK_BOX (hbox), check_button, FALSE, FALSE, 0);
1419 gtk_widget_show (check_button);
1420
1421 g_signal_connect (check_button, "toggled",
1422 G_CALLBACK (smp_toggle_callback),
1423 &g_di.dst_show_color);
1424 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (check_button),
1425 g_di.dst_show_color);
1426
1427 hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
1428 gtk_table_attach (GTK_TABLE (table), hbox, 3, 5, ty, ty + 1,
1429 GTK_FILL, 0, 0, 0);
1430 gtk_widget_show (hbox);
1431
1432 /* check button */
1433 check_button = gtk_check_button_new_with_mnemonic (_("Show selec_tion"));
1434 gtk_box_pack_start (GTK_BOX (hbox), check_button, FALSE, FALSE, 0);
1435 gtk_widget_show (check_button);
1436
1437 g_signal_connect (check_button, "toggled",
1438 G_CALLBACK (smp_toggle_callback),
1439 &g_di.sample_show_selection);
1440 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (check_button),
1441 g_di.sample_show_selection);
1442
1443 /* check button */
1444 check_button = gtk_check_button_new_with_mnemonic (_("Show c_olor"));
1445 gtk_box_pack_start (GTK_BOX (hbox), check_button, FALSE, FALSE, 0);
1446 gtk_widget_show (check_button);
1447
1448 g_signal_connect (check_button, "toggled",
1449 G_CALLBACK (smp_toggle_callback),
1450 &g_di.sample_show_color);
1451 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (check_button),
1452 g_di.sample_show_color);
1453
1454 ty++;
1455
1456 /* Preview (Dst) */
1457
1458 frame = gtk_frame_new (NULL);
1459 gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
1460 gtk_table_attach (GTK_TABLE (table),
1461 frame, 0, 2, ty, ty + 1, 0, 0, 0, 0);
1462 gtk_widget_show (frame);
1463
1464 g_di.dst_preview = gimp_preview_area_new ();
1465 gtk_widget_set_size_request (g_di.dst_preview,
1466 PREVIEW_SIZE_X, PREVIEW_SIZE_Y);
1467 gtk_container_add (GTK_CONTAINER (frame), g_di.dst_preview);
1468 gtk_widget_show (g_di.dst_preview);
1469
1470 /* Preview (Sample)*/
1471
1472 frame = gtk_frame_new (NULL);
1473 gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
1474 gtk_table_attach (GTK_TABLE (table),
1475 frame, 3, 5, ty, ty + 1, 0, 0, 0, 0);
1476 gtk_widget_show (frame);
1477
1478 g_di.sample_preview = gimp_preview_area_new ();
1479 gtk_widget_set_size_request (g_di.sample_preview,
1480 PREVIEW_SIZE_X, PREVIEW_SIZE_Y);
1481 gtk_container_add (GTK_CONTAINER (frame), g_di.sample_preview);
1482 gtk_widget_show (g_di.sample_preview);
1483
1484 ty++;
1485
1486 /* The levels graylevel prevev */
1487 frame = gtk_frame_new (NULL);
1488
1489 vbox2 = gtk_box_new (GTK_ORIENTATION_VERTICAL, 2);
1490 gtk_container_add (GTK_CONTAINER (frame), vbox2);
1491 gtk_table_attach (GTK_TABLE (table),
1492 frame, 0, 2, ty, ty + 1, 0, 0, 0, 0);
1493
1494 g_di.in_lvl_gray_preview = gimp_preview_area_new ();
1495 gtk_widget_set_size_request (g_di.in_lvl_gray_preview,
1496 DA_WIDTH, GRADIENT_HEIGHT);
1497 gtk_widget_set_events (g_di.in_lvl_gray_preview, LEVELS_DA_MASK);
1498 gtk_box_pack_start (GTK_BOX (vbox2), g_di.in_lvl_gray_preview, FALSE, TRUE, 0);
1499 gtk_widget_show (g_di.in_lvl_gray_preview);
1500
1501 g_signal_connect (g_di.in_lvl_gray_preview, "event",
1502 G_CALLBACK (level_in_events),
1503 NULL);
1504
1505 /* The levels drawing area */
1506 g_di.in_lvl_drawarea = gtk_drawing_area_new ();
1507 gtk_widget_set_size_request (g_di.in_lvl_drawarea,
1508 DA_WIDTH, CONTROL_HEIGHT);
1509 gtk_widget_set_events (g_di.in_lvl_drawarea, LEVELS_DA_MASK);
1510 gtk_box_pack_start (GTK_BOX (vbox2), g_di.in_lvl_drawarea, FALSE, TRUE, 0);
1511 gtk_widget_show (g_di.in_lvl_drawarea);
1512
1513 g_signal_connect (g_di.in_lvl_drawarea, "event",
1514 G_CALLBACK (level_in_events),
1515 NULL);
1516
1517 gtk_widget_show (vbox2);
1518 gtk_widget_show (frame);
1519
1520 /* The sample_colortable prevev */
1521 frame = gtk_frame_new (NULL);
1522
1523 vbox2 = gtk_box_new (GTK_ORIENTATION_VERTICAL, 2);
1524 gtk_container_add (GTK_CONTAINER (frame), vbox2);
1525 gtk_table_attach (GTK_TABLE (table),
1526 frame, 3, 5, ty, ty + 1, 0, 0, 0, 0);
1527
1528 g_di.sample_colortab_preview = gimp_preview_area_new ();
1529 gtk_widget_set_size_request (g_di.sample_colortab_preview,
1530 DA_WIDTH, GRADIENT_HEIGHT);
1531 gtk_box_pack_start (GTK_BOX (vbox2), g_di.sample_colortab_preview, FALSE, TRUE, 0);
1532 gtk_widget_show (g_di.sample_colortab_preview);
1533
1534 /* The levels drawing area */
1535 g_di.sample_drawarea = gtk_drawing_area_new ();
1536 gtk_widget_set_size_request (g_di.sample_drawarea,
1537 DA_WIDTH, CONTROL_HEIGHT);
1538 gtk_widget_set_events (g_di.sample_drawarea, LEVELS_DA_MASK);
1539 gtk_box_pack_start (GTK_BOX (vbox2), g_di.sample_drawarea, FALSE, TRUE, 0);
1540 gtk_widget_show (g_di.sample_drawarea);
1541
1542 g_signal_connect (g_di.sample_drawarea, "event",
1543 G_CALLBACK (level_out_events),
1544 NULL);
1545
1546 gtk_widget_show (vbox2);
1547 gtk_widget_show (frame);
1548
1549
1550 ty++;
1551
1552 /* Horizontal box for INPUT levels text widget */
1553 hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
1554 gtk_box_set_homogeneous (GTK_BOX (hbox), TRUE);
1555 gtk_table_attach (GTK_TABLE (table), hbox, 0, 2, ty, ty+1,
1556 GTK_FILL, 0, 0, 0);
1557
1558 label = gtk_label_new (_("Input levels:"));
1559 gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
1560 gtk_widget_show (label);
1561
1562 /* min input spinbutton */
1563 data = gtk_adjustment_new ((gfloat)g_values.lvl_in_min, 0.0, 254.0, 1, 10, 0);
1564 g_di.adj_lvl_in_min = GTK_ADJUSTMENT (data);
1565
1566 spinbutton = gimp_spin_button_new (g_di.adj_lvl_in_min, 0.5, 0);
1567 gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (spinbutton), TRUE);
1568 gtk_box_pack_start (GTK_BOX (hbox), spinbutton, FALSE, FALSE, 0);
1569 gtk_widget_show (spinbutton);
1570
1571 g_signal_connect (g_di.adj_lvl_in_min, "value-changed",
1572 G_CALLBACK (smp_adj_lvl_in_min_upd_callback),
1573 &g_di);
1574
1575 /* input gamma spinbutton */
1576 data = gtk_adjustment_new ((gfloat)g_values.lvl_in_gamma, 0.1, 10.0, 0.02, 0.2, 0);
1577 g_di.adj_lvl_in_gamma = GTK_ADJUSTMENT (data);
1578
1579 spinbutton = gimp_spin_button_new (g_di.adj_lvl_in_gamma, 0.5, 2);
1580 gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (spinbutton), TRUE);
1581 gtk_box_pack_start (GTK_BOX (hbox), spinbutton, FALSE, FALSE, 0);
1582 gtk_widget_show (spinbutton);
1583
1584 g_signal_connect (g_di.adj_lvl_in_gamma, "value-changed",
1585 G_CALLBACK (smp_text_gamma_upd_callback),
1586 &g_di);
1587
1588 /* high input spinbutton */
1589 data = gtk_adjustment_new ((gfloat)g_values.lvl_in_max, 1.0, 255.0, 1, 10, 0);
1590 g_di.adj_lvl_in_max = GTK_ADJUSTMENT (data);
1591
1592 spinbutton = gimp_spin_button_new (g_di.adj_lvl_in_max, 0.5, 0);
1593 gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (spinbutton), TRUE);
1594 gtk_box_pack_start (GTK_BOX (hbox), spinbutton, FALSE, FALSE, 0);
1595 gtk_widget_show (spinbutton);
1596
1597 g_signal_connect (g_di.adj_lvl_in_max, "value-changed",
1598 G_CALLBACK (smp_adj_lvl_in_max_upd_callback),
1599 &g_di);
1600
1601 gtk_widget_show (hbox);
1602
1603 /* Horizontal box for OUTPUT levels text widget */
1604 hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 4);
1605 gtk_box_set_homogeneous (GTK_BOX (hbox), TRUE);
1606 gtk_table_attach (GTK_TABLE (table), hbox, 3, 5, ty, ty+1,
1607 GTK_FILL, 0, 0, 0);
1608
1609 label = gtk_label_new (_("Output levels:"));
1610 gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
1611 gtk_widget_show (label);
1612
1613 /* min output spinbutton */
1614 data = gtk_adjustment_new ((gfloat)g_values.lvl_out_min, 0.0, 254.0, 1, 10, 0);
1615 g_di.adj_lvl_out_min = GTK_ADJUSTMENT (data);
1616
1617 spinbutton = gimp_spin_button_new (g_di.adj_lvl_out_min, 0.5, 0);
1618 gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (spinbutton), TRUE);
1619 gtk_box_pack_start (GTK_BOX (hbox), spinbutton, FALSE, FALSE, 0);
1620 gtk_widget_show (spinbutton);
1621
1622 g_signal_connect (g_di.adj_lvl_out_min, "value-changed",
1623 G_CALLBACK (smp_adj_lvl_out_min_upd_callback),
1624 &g_di);
1625
1626 /* high output spinbutton */
1627 data = gtk_adjustment_new ((gfloat)g_values.lvl_out_max, 0.0, 255.0, 1, 10, 0);
1628 g_di.adj_lvl_out_max = GTK_ADJUSTMENT (data);
1629
1630 spinbutton = gimp_spin_button_new (g_di.adj_lvl_out_max, 0.5, 0);
1631 gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (spinbutton), TRUE);
1632 gtk_box_pack_start (GTK_BOX (hbox), spinbutton, FALSE, FALSE, 0);
1633 gtk_widget_show (spinbutton);
1634
1635 g_signal_connect (g_di.adj_lvl_out_max, "value-changed",
1636 G_CALLBACK (smp_adj_lvl_out_max_upd_callback),
1637 &g_di);
1638
1639 gtk_widget_show (hbox);
1640
1641 ty++;
1642
1643 hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
1644 gtk_table_attach (GTK_TABLE (table), hbox, 0, 2, ty, ty+1,
1645 GTK_FILL, 0, 0, 0);
1646 gtk_widget_show (hbox);
1647
1648 /* check button */
1649 check_button = gtk_check_button_new_with_mnemonic (_("Hold _intensity"));
1650 gtk_box_pack_start (GTK_BOX (hbox), check_button, FALSE, FALSE, 0);
1651 gtk_widget_show (check_button);
1652
1653 g_signal_connect (check_button, "toggled",
1654 G_CALLBACK (smp_toggle_callback),
1655 &g_values.hold_inten);
1656 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (check_button),
1657 g_values.hold_inten);
1658
1659 /* check button */
1660 check_button = gtk_check_button_new_with_mnemonic (_("Original i_ntensity"));
1661 g_di.orig_inten_button = check_button;
1662 gtk_box_pack_start (GTK_BOX (hbox), check_button, FALSE, FALSE, 0);
1663 gtk_widget_set_sensitive (g_di.orig_inten_button, g_values.hold_inten);
1664 gtk_widget_show (check_button);
1665
1666 g_signal_connect (check_button, "toggled",
1667 G_CALLBACK (smp_toggle_callback),
1668 &g_values.orig_inten);
1669 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (check_button),
1670 g_values.orig_inten);
1671
1672 hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 4);
1673 gtk_table_attach (GTK_TABLE (table), hbox, 3, 5, ty, ty+1,
1674 GTK_FILL, 0, 0, 0);
1675 gtk_widget_show (hbox);
1676
1677 /* check button */
1678 check_button = gtk_check_button_new_with_mnemonic (_("Us_e subcolors"));
1679 gtk_box_pack_start (GTK_BOX (hbox), check_button, FALSE, FALSE, 0);
1680 gtk_widget_show (check_button);
1681
1682 g_signal_connect (check_button, "toggled",
1683 G_CALLBACK (smp_toggle_callback),
1684 &g_values.rnd_subcolors);
1685 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (check_button),
1686 g_values.rnd_subcolors);
1687
1688 /* check button */
1689 check_button = gtk_check_button_new_with_mnemonic (_("S_mooth samples"));
1690 gtk_box_pack_start (GTK_BOX (hbox), check_button, FALSE, FALSE, 0);
1691 gtk_widget_show (check_button);
1692
1693 g_signal_connect (check_button, "toggled",
1694 G_CALLBACK (smp_toggle_callback),
1695 &g_values.guess_missing);
1696 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (check_button),
1697 g_values.guess_missing);
1698
1699 ty++;
1700
1701 gtk_widget_show (table);
1702 gtk_widget_show (frame);
1703
1704 gtk_widget_show (dialog);
1705
1706 /* set old_id's different (to force updates of the previews) */
1707 g_di.enable_preview_update = TRUE;
1708 smp_get_colors (NULL);
1709 update_preview (&g_values.dst_id);
1710 levels_update (INPUT_SLIDERS | INPUT_LEVELS | DRAW);
1711
1712 gtk_main ();
1713 }
1714
1715 /* -----------------------------
1716 * DEBUG print procedures START
1717 * -----------------------------
1718 */
1719
1720 static void
print_ppm(const gchar * ppm_name)1721 print_ppm (const gchar *ppm_name)
1722 {
1723 FILE *fp;
1724 gint idx;
1725 gint cnt;
1726 gint r;
1727 gint g;
1728 gint b;
1729 t_samp_color_elem *col_ptr;
1730
1731 if (ppm_name == NULL)
1732 return;
1733
1734 fp = g_fopen (ppm_name, "w");
1735 if (fp)
1736 {
1737 fprintf (fp, "P3\n# CREATOR: Gimp sample coloros\n256 256\n255\n");
1738 for (idx = 0; idx < 256; idx++)
1739 {
1740 col_ptr = g_lum_tab[idx].col_ptr;
1741
1742 for (cnt = 0; cnt < 256; cnt++)
1743 {
1744 r = g = b = 0;
1745 if (col_ptr)
1746 {
1747 if ((col_ptr->sum_color > 0) && (cnt != 20))
1748 {
1749 r = (gint) col_ptr->color[0];
1750 g = (gint) col_ptr->color[1];
1751 b = (gint) col_ptr->color[2];
1752 }
1753
1754 if (cnt > 20)
1755 col_ptr = col_ptr->next;
1756 }
1757 fprintf (fp, "%d %d %d\n", r, g, b);
1758 }
1759 }
1760 fclose (fp);
1761 }
1762 }
1763
1764 static void
print_color_list(FILE * fp,t_samp_color_elem * col_ptr)1765 print_color_list (FILE *fp,
1766 t_samp_color_elem *col_ptr)
1767 {
1768 if (fp == NULL)
1769 return;
1770
1771 while (col_ptr)
1772 {
1773 fprintf (fp, " RGBA: %03d %03d %03d %03d sum: [%d]\n",
1774 (gint)col_ptr->color[0],
1775 (gint)col_ptr->color[1],
1776 (gint)col_ptr->color[2],
1777 (gint)col_ptr->color[3],
1778 (gint)col_ptr->sum_color);
1779
1780 col_ptr = col_ptr->next;
1781 }
1782 }
1783
1784 static void
print_table(FILE * fp)1785 print_table (FILE *fp)
1786 {
1787 gint idx;
1788
1789 if (fp == NULL)
1790 return;
1791
1792 fprintf (fp, "---------------------------\n");
1793 fprintf (fp, "print_table\n");
1794 fprintf (fp, "---------------------------\n");
1795
1796 for (idx = 0; idx < 256; idx++)
1797 {
1798 fprintf (fp, "LUM [%03d] pixcount:%d\n",
1799 idx, (int)g_lum_tab[idx].all_samples);
1800 print_color_list (fp, g_lum_tab[idx].col_ptr);
1801 }
1802 }
1803
1804 static void
print_transtable(FILE * fp)1805 print_transtable (FILE *fp)
1806 {
1807 gint idx;
1808
1809 if (fp == NULL)
1810 return;
1811
1812 fprintf (fp, "---------------------------\n");
1813 fprintf (fp, "print_transtable\n");
1814 fprintf (fp, "---------------------------\n");
1815
1816 for (idx = 0; idx < 256; idx++)
1817 {
1818 fprintf (fp, "LVL_TRANS [%03d] in_lvl: %3d out_lvl: %3d\n",
1819 idx, (int)g_lvl_trans_tab[idx], (int)g_out_trans_tab[idx]);
1820 }
1821 }
1822
1823 static void
print_values(FILE * fp)1824 print_values (FILE *fp)
1825 {
1826 if (fp == NULL)
1827 return;
1828
1829 fprintf (fp, "sample_colorize: params\n");
1830 fprintf (fp, "g_values.hold_inten :%d\n", (int)g_values.hold_inten);
1831 fprintf (fp, "g_values.orig_inten :%d\n", (int)g_values.orig_inten);
1832 fprintf (fp, "g_values.rnd_subcolors :%d\n", (int)g_values.rnd_subcolors);
1833 fprintf (fp, "g_values.guess_missing :%d\n", (int)g_values.guess_missing);
1834 fprintf (fp, "g_values.lvl_in_min :%d\n", (int)g_values.lvl_in_min);
1835 fprintf (fp, "g_values.lvl_in_max :%d\n", (int)g_values.lvl_in_max);
1836 fprintf (fp, "g_values.lvl_in_gamma :%f\n", g_values.lvl_in_gamma);
1837 fprintf (fp, "g_values.lvl_out_min :%d\n", (int)g_values.lvl_out_min);
1838 fprintf (fp, "g_values.lvl_out_max :%d\n", (int)g_values.lvl_out_max);
1839
1840 fprintf (fp, "g_values.tol_col_err :%f\n", g_values.tol_col_err);
1841 }
1842
1843 /* -----------------------------
1844 * DEBUG print procedures END
1845 * -----------------------------
1846 */
1847
1848 /* DEBUG: read values from file */
1849 static void
get_filevalues(void)1850 get_filevalues (void)
1851 {
1852 FILE *fp;
1853 gchar buf[1000];
1854
1855 /*
1856 g_values.lvl_out_min = 0;
1857 g_values.lvl_out_max = 255;
1858 g_values.lvl_in_min = 0;
1859 g_values.lvl_in_max = 255;
1860 g_values.lvl_in_gamma = 1.0;
1861 */
1862 g_values.tol_col_err = 5.5;
1863
1864 fp = g_fopen ("sample_colorize.values", "r");
1865 if (fp != NULL)
1866 {
1867 fgets (buf, 999, fp);
1868 sscanf (buf, "%f", &g_values.tol_col_err);
1869 fclose (fp);
1870 }
1871
1872 g_printf ("g_values.tol_col_err :%f\n", g_values.tol_col_err);
1873 }
1874
1875 static gint32
color_error(guchar ref_red,guchar ref_green,guchar ref_blue,guchar cmp_red,guchar cmp_green,guchar cmp_blue)1876 color_error (guchar ref_red, guchar ref_green, guchar ref_blue,
1877 guchar cmp_red, guchar cmp_green, guchar cmp_blue)
1878 {
1879 glong ff;
1880 glong fs;
1881 glong cmp_h, ref_h;
1882
1883 /* 1. Brightness differences */
1884 cmp_h = (3 * cmp_red + 6 * cmp_green + cmp_blue) / 10;
1885 ref_h = (3 * ref_red + 6 * ref_green + ref_blue) / 10;
1886
1887 fs = labs (ref_h - cmp_h);
1888 ff = fs * fs;
1889
1890 /* 2. add Red Color differences */
1891 fs = abs (ref_red - cmp_red);
1892 ff += (fs * fs);
1893
1894 /* 3. add Green Color differences */
1895 fs = abs (ref_green - cmp_green);
1896 ff += (fs * fs);
1897
1898 /* 4. add Blue Color differences */
1899 fs = abs (ref_blue - cmp_blue);
1900 ff += (fs * fs);
1901
1902 return ((gint32)(ff));
1903 }
1904
1905 /* get pixel value
1906 * return light gray transparent pixel if out of bounds
1907 * (should occur in the previews only)
1908 */
1909 static void
get_pixel(t_GDRW * gdrw,gint32 x,gint32 y,guchar * pixel)1910 get_pixel (t_GDRW *gdrw,
1911 gint32 x,
1912 gint32 y,
1913 guchar *pixel)
1914 {
1915 gegl_buffer_sample (gdrw->buffer, x, y, NULL, pixel, gdrw->format,
1916 GEGL_SAMPLER_NEAREST, GEGL_ABYSS_NONE);
1917 }
1918
1919 /* clear table */
1920 static void
clear_tables(void)1921 clear_tables (void)
1922 {
1923 guint i;
1924
1925 for (i = 0; i < 256; i++)
1926 {
1927 g_lum_tab[i].col_ptr = NULL;
1928 g_lum_tab[i].all_samples = 0;
1929 g_lvl_trans_tab[i] = i;
1930 g_out_trans_tab[i] = i;
1931 g_sample_color_tab[3 * i + 0] = i;
1932 g_sample_color_tab[3 * i + 1] = i;
1933 g_sample_color_tab[3 * i + 2] = i;
1934 }
1935 }
1936
1937 /* free all allocated sample colors in table g_lum_tab */
1938 static void
free_colors(void)1939 free_colors (void)
1940 {
1941 gint lum;
1942 t_samp_color_elem *col_ptr;
1943 t_samp_color_elem *next_ptr;
1944
1945 for (lum = 0; lum < 256; lum++)
1946 {
1947 for (col_ptr = g_lum_tab[lum].col_ptr;
1948 col_ptr != NULL;
1949 col_ptr = next_ptr)
1950 {
1951 next_ptr = (t_samp_color_elem *)col_ptr->next;
1952 g_free (col_ptr);
1953 }
1954
1955 g_lum_tab[lum].col_ptr = NULL;
1956 g_lum_tab[lum].all_samples = 0;
1957 }
1958 }
1959
1960 /* setup lum transformer table according to input_levels, gamma and output levels
1961 * (uses sam algorithm as GIMP Level Tool)
1962 */
1963 static void
calculate_level_transfers(void)1964 calculate_level_transfers (void)
1965 {
1966 double inten;
1967 gint i;
1968 gint in_min, in_max;
1969 gint out_min, out_max;
1970
1971 if (g_values.lvl_in_max >= g_values.lvl_in_min)
1972 {
1973 in_max = g_values.lvl_in_max;
1974 in_min = g_values.lvl_in_min;
1975 }
1976 else
1977 {
1978 in_max = g_values.lvl_in_min;
1979 in_min = g_values.lvl_in_max;
1980 }
1981 if (g_values.lvl_out_max >= g_values.lvl_out_min)
1982 {
1983 out_max = g_values.lvl_out_max;
1984 out_min = g_values.lvl_out_min;
1985 }
1986 else
1987 {
1988 out_max = g_values.lvl_out_min;
1989 out_min = g_values.lvl_out_max;
1990 }
1991
1992 /* Recalculate the levels arrays */
1993 for (i = 0; i < 256; i++)
1994 {
1995 /* determine input intensity */
1996 inten = (double) i / 255.0;
1997 if (g_values.lvl_in_gamma != 0.0)
1998 {
1999 inten = pow (inten, (1.0 / g_values.lvl_in_gamma));
2000 }
2001 inten = (double) (inten * (in_max - in_min) + in_min);
2002 inten = CLAMP (inten, 0.0, 255.0);
2003 g_lvl_trans_tab[i] = (guchar) (inten + 0.5);
2004
2005 /* determine the output intensity */
2006 inten = (double) i / 255.0;
2007 inten = (double) (inten * (out_max - out_min) + out_min);
2008 inten = CLAMP (inten, 0.0, 255.0);
2009 g_out_trans_tab[i] = (guchar) (inten + 0.5);
2010 }
2011 }
2012
2013
2014
2015 /* alloc and init new col Element */
2016 static t_samp_color_elem *
new_samp_color(const guchar * color)2017 new_samp_color (const guchar *color)
2018 {
2019 t_samp_color_elem *col_ptr;
2020
2021 col_ptr = g_new0 (t_samp_color_elem, 1);
2022
2023 memcpy (&col_ptr->color[0], color, 4);
2024
2025 col_ptr->sum_color = 1;
2026 col_ptr->next = NULL;
2027
2028 return col_ptr;
2029 }
2030
2031
2032 /* store color in g_lum_tab */
2033 static void
add_color(const guchar * color)2034 add_color (const guchar *color)
2035 {
2036 gint32 lum;
2037 t_samp_color_elem *col_ptr;
2038
2039 lum = LUMINOSITY_1(color);
2040
2041 g_lum_tab[lum].all_samples++;
2042 g_lum_tab[lum].from_sample = TRUE;
2043
2044 /* check if exactly the same color is already in the list */
2045 for (col_ptr = g_lum_tab[lum].col_ptr;
2046 col_ptr != NULL;
2047 col_ptr = (t_samp_color_elem *)col_ptr->next)
2048 {
2049 if ((color[0] == col_ptr->color[0]) &&
2050 (color[1] == col_ptr->color[1]) &&
2051 (color[2] == col_ptr->color[2]))
2052 {
2053 col_ptr->sum_color++;
2054 return;
2055 }
2056 }
2057
2058 /* alloc and init element for the new color */
2059 col_ptr = new_samp_color (color);
2060
2061 if (col_ptr != NULL)
2062 {
2063 /* add new color element as 1.st of the list */
2064 col_ptr->next = g_lum_tab[lum].col_ptr;
2065 g_lum_tab[lum].col_ptr = col_ptr;
2066 }
2067 }
2068
2069 /* sort Sublists (color) by descending sum_color in g_lum_tab
2070 */
2071 static void
sort_color(gint32 lum)2072 sort_color (gint32 lum)
2073 {
2074 t_samp_color_elem *col_ptr;
2075 t_samp_color_elem *next_ptr;
2076 t_samp_color_elem *prev_ptr;
2077 t_samp_color_elem *sorted_col_ptr;
2078 gint32 min;
2079 gint32 min_next;
2080
2081 sorted_col_ptr = NULL;
2082 min_next = 0;
2083
2084 while (g_lum_tab[lum].col_ptr != NULL)
2085 {
2086 min = min_next;
2087 next_ptr = NULL;
2088 prev_ptr = NULL;
2089
2090 for (col_ptr = g_lum_tab[lum].col_ptr;
2091 col_ptr != NULL;
2092 col_ptr = next_ptr)
2093 {
2094 next_ptr = col_ptr->next;
2095 if (col_ptr->sum_color > min)
2096 {
2097 /* check min value for next loop */
2098 if ((col_ptr->sum_color < min_next) || (min == min_next))
2099 {
2100 min_next = col_ptr->sum_color;
2101 }
2102 prev_ptr = col_ptr;
2103 }
2104 else
2105 {
2106 /* add element at head of sorted list */
2107 col_ptr->next = sorted_col_ptr;
2108 sorted_col_ptr = col_ptr;
2109
2110 /* remove element from list */
2111 if (prev_ptr == NULL)
2112 {
2113 g_lum_tab[lum].col_ptr = next_ptr; /* remove 1.st element */
2114 }
2115 else
2116 {
2117 prev_ptr->next = next_ptr;
2118 }
2119 }
2120 }
2121 }
2122
2123 g_lum_tab[lum].col_ptr = sorted_col_ptr;
2124 }
2125
2126 static void
cnt_same_sample_colortones(t_samp_color_elem * ref_ptr,guchar * prev_color,guchar * color_tone,gint * csum)2127 cnt_same_sample_colortones (t_samp_color_elem *ref_ptr,
2128 guchar *prev_color,
2129 guchar *color_tone,
2130 gint *csum)
2131 {
2132 gint32 col_error, ref_error;
2133 t_samp_color_elem *col_ptr;
2134
2135 ref_error = 0;
2136 if (prev_color != NULL)
2137 {
2138 ref_error = color_error (ref_ptr->color[0], ref_ptr->color[1], ref_ptr->color[2],
2139 prev_color[0], prev_color[1], prev_color[2]);
2140 }
2141
2142 /* collect colors that are (nearly) the same */
2143 for (col_ptr = ref_ptr->next;
2144 col_ptr != NULL;
2145 col_ptr = (t_samp_color_elem *)col_ptr->next)
2146 {
2147 if (col_ptr->sum_color < 1)
2148 continue;
2149 col_error = color_error (ref_ptr->color[0], ref_ptr->color[1], ref_ptr->color[2],
2150 col_ptr->color[0], col_ptr->color[1], col_ptr->color[2]);
2151
2152 if (col_error <= g_tol_col_err)
2153 {
2154 /* cout color of the same colortone */
2155 *csum += col_ptr->sum_color;
2156 /* mark the already checked color with negative sum_color value */
2157 col_ptr->sum_color = 0 - col_ptr->sum_color;
2158
2159 if (prev_color != NULL)
2160 {
2161 col_error = color_error (col_ptr->color[0], col_ptr->color[1], col_ptr->color[2],
2162 prev_color[0], prev_color[1], prev_color[2]);
2163 if (col_error < ref_error)
2164 {
2165 /* use the color that is closest to prev_color */
2166 memcpy (color_tone, &col_ptr->color[0], 3);
2167 ref_error = col_error;
2168 }
2169 }
2170 }
2171 }
2172 }
2173
2174 /* find the dominant colortones (out of all sample colors)
2175 * for each available brightness intensity value.
2176 * and store them in g_sample_color_tab
2177 */
2178 static void
ideal_samples(void)2179 ideal_samples (void)
2180 {
2181 gint32 lum;
2182 t_samp_color_elem *col_ptr;
2183 guchar *color;
2184
2185 guchar color_tone[4];
2186 guchar color_ideal[4];
2187 gint csum, maxsum;
2188
2189 color = NULL;
2190 for (lum = 0; lum < 256; lum++)
2191 {
2192 if (g_lum_tab[lum].col_ptr == NULL)
2193 continue;
2194
2195 sort_color (lum);
2196 col_ptr = g_lum_tab[lum].col_ptr;
2197 memcpy (&color_ideal[0], &col_ptr->color[0], 3);
2198
2199 maxsum = 0;
2200
2201 /* collect colors that are (nearly) the same */
2202 for (;
2203 col_ptr != NULL;
2204 col_ptr = (t_samp_color_elem *)col_ptr->next)
2205 {
2206 csum = 0;
2207 if (col_ptr->sum_color > 0)
2208 {
2209 memcpy (&color_tone[0], &col_ptr->color[0], 3);
2210 cnt_same_sample_colortones (col_ptr, color,
2211 &color_tone[0], &csum);
2212 if (csum > maxsum)
2213 {
2214 maxsum = csum;
2215 memcpy (&color_ideal[0], &color_tone[0], 3);
2216 }
2217 }
2218 else
2219 col_ptr->sum_color = abs (col_ptr->sum_color);
2220 }
2221
2222 /* store ideal color and keep track of the color */
2223 color = &g_sample_color_tab[3 * lum];
2224 memcpy (color, &color_ideal[0], 3);
2225 }
2226 }
2227
2228 static void
guess_missing_colors(void)2229 guess_missing_colors (void)
2230 {
2231 gint32 lum;
2232 gint32 idx;
2233 gfloat div;
2234
2235 guchar lo_color[4];
2236 guchar hi_color[4];
2237 guchar new_color[4];
2238
2239 lo_color[0] = 0;
2240 lo_color[1] = 0;
2241 lo_color[2] = 0;
2242 lo_color[3] = 255;
2243
2244 hi_color[0] = 255;
2245 hi_color[1] = 255;
2246 hi_color[2] = 255;
2247 hi_color[3] = 255;
2248
2249 new_color[0] = 0;
2250 new_color[1] = 0;
2251 new_color[2] = 0;
2252 new_color[3] = 255;
2253
2254 for (lum = 0; lum < 256; lum++)
2255 {
2256 if ((g_lum_tab[lum].col_ptr == NULL) ||
2257 (g_lum_tab[lum].from_sample == FALSE))
2258 {
2259 if (lum > 0)
2260 {
2261 for (idx = lum; idx < 256; idx++)
2262 {
2263 if ((g_lum_tab[idx].col_ptr != NULL) &&
2264 g_lum_tab[idx].from_sample)
2265 {
2266 memcpy (&hi_color[0],
2267 &g_sample_color_tab[3 * idx], 3);
2268 break;
2269 }
2270 if (idx == 255)
2271 {
2272 hi_color[0] = 255;
2273 hi_color[1] = 255;
2274 hi_color[2] = 255;
2275 break;
2276 }
2277 }
2278
2279 div = idx - (lum -1);
2280 new_color[0] = lo_color[0] + ((float)(hi_color[0] - lo_color[0]) / div);
2281 new_color[1] = lo_color[1] + ((float)(hi_color[1] - lo_color[1]) / div);
2282 new_color[2] = lo_color[2] + ((float)(hi_color[2] - lo_color[2]) / div);
2283
2284 /*
2285 * printf ("LO: %03d %03d %03d HI: %03d %03d %03d NEW: %03d %03d %03d\n",
2286 * (int)lo_color[0], (int)lo_color[1], (int)lo_color[2],
2287 * (int)hi_color[0], (int)hi_color[1], (int)hi_color[2],
2288 * (int)new_color[0], (int)new_color[1], (int)new_color[2]);
2289 */
2290
2291 }
2292 g_lum_tab[lum].col_ptr = new_samp_color (&new_color[0]);
2293 g_lum_tab[lum].from_sample = FALSE;
2294 memcpy (&g_sample_color_tab [3 * lum], &new_color[0], 3);
2295 }
2296 memcpy (&lo_color[0], &g_sample_color_tab [3 * lum], 3);
2297 }
2298 }
2299
2300 static void
fill_missing_colors(void)2301 fill_missing_colors (void)
2302 {
2303 gint32 lum;
2304 gint32 idx;
2305 gint32 lo_idx;
2306
2307 guchar lo_color[4];
2308 guchar hi_color[4];
2309 guchar new_color[4];
2310
2311 lo_color[0] = 0;
2312 lo_color[1] = 0;
2313 lo_color[2] = 0;
2314 lo_color[3] = 255;
2315
2316 hi_color[0] = 255;
2317 hi_color[1] = 255;
2318 hi_color[2] = 255;
2319 hi_color[3] = 255;
2320
2321 new_color[0] = 0;
2322 new_color[1] = 0;
2323 new_color[2] = 0;
2324 new_color[3] = 255;
2325
2326 lo_idx = 0;
2327 for (lum = 0; lum < 256; lum++)
2328 {
2329 if ((g_lum_tab[lum].col_ptr == NULL) ||
2330 (g_lum_tab[lum].from_sample == FALSE))
2331 {
2332 if (lum > 0)
2333 {
2334 for (idx = lum; idx < 256; idx++)
2335 {
2336 if ((g_lum_tab[idx].col_ptr != NULL) &&
2337 (g_lum_tab[idx].from_sample))
2338 {
2339 memcpy (&hi_color[0],
2340 &g_sample_color_tab[3 * idx], 3);
2341 break;
2342 }
2343
2344 if (idx == 255)
2345 {
2346 /*
2347 * hi_color[0] = 255;
2348 * hi_color[1] = 255;
2349 * hi_color[2] = 255;
2350 */
2351 memcpy (&hi_color[0], &lo_color[0], 3);
2352 break;
2353 }
2354 }
2355
2356 if ((lum > (lo_idx + ((idx - lo_idx ) / 2))) ||
2357 (lo_idx == 0))
2358 {
2359 new_color[0] = hi_color[0];
2360 new_color[1] = hi_color[1];
2361 new_color[2] = hi_color[2];
2362 }
2363 else
2364 {
2365 new_color[0] = lo_color[0];
2366 new_color[1] = lo_color[1];
2367 new_color[2] = lo_color[2];
2368 }
2369 }
2370
2371 g_lum_tab[lum].col_ptr = new_samp_color (&new_color[0]);
2372 g_lum_tab[lum].from_sample = FALSE;
2373 memcpy (&g_sample_color_tab[3 * lum], &new_color[0], 3);
2374 }
2375 else
2376 {
2377 lo_idx = lum;
2378 memcpy (&lo_color[0], &g_sample_color_tab[3 * lum], 3);
2379 }
2380 }
2381 }
2382
2383 /* get 256 samples of active gradient (optional in inverse order) */
2384 static void
get_gradient(gint mode)2385 get_gradient (gint mode)
2386 {
2387 gchar *name;
2388 gint n_f_samples;
2389 gdouble *f_samples;
2390 gdouble *f_samp; /* float samples */
2391 gint lum;
2392
2393 free_colors ();
2394
2395 name = gimp_context_get_gradient ();
2396
2397 gimp_gradient_get_uniform_samples (name, 256 /* n_samples */,
2398 mode == SMP_INV_GRADIENT,
2399 &n_f_samples, &f_samples);
2400
2401 g_free (name);
2402
2403 for (lum = 0; lum < 256; lum++)
2404 {
2405 f_samp = &f_samples[lum * 4];
2406
2407 g_sample_color_tab[3 * lum + 0] = f_samp[0] * 255;
2408 g_sample_color_tab[3 * lum + 1] = f_samp[1] * 255;
2409 g_sample_color_tab[3 * lum + 2] = f_samp[2] * 255;
2410
2411 g_lum_tab[lum].col_ptr =
2412 new_samp_color (&g_sample_color_tab[3 * lum]);
2413 g_lum_tab[lum].from_sample = TRUE;
2414 g_lum_tab[lum].all_samples = 1;
2415 }
2416
2417 g_free (f_samples);
2418 }
2419
2420 static gint32
is_layer_alive(gint32 drawable_id)2421 is_layer_alive (gint32 drawable_id)
2422 {
2423 /* return -1 if layer has become invalid */
2424 if (drawable_id < 0)
2425 return -1;
2426
2427 if (gimp_item_get_image (drawable_id) < 0)
2428 {
2429 g_printf ("sample colorize: unknown layer_id %d (Image closed?)\n",
2430 (int)drawable_id);
2431 return -1;
2432 }
2433
2434 return drawable_id;
2435 }
2436
2437 static void
end_gdrw(t_GDRW * gdrw)2438 end_gdrw (t_GDRW *gdrw)
2439 {
2440 t_GDRW *sel_gdrw = (t_GDRW *) gdrw->sel_gdrw;
2441
2442 if (sel_gdrw && sel_gdrw->buffer)
2443 {
2444 g_object_unref (sel_gdrw->buffer);
2445 sel_gdrw->buffer = NULL;
2446 }
2447
2448 g_object_unref (gdrw->buffer);
2449 gdrw->buffer = NULL;
2450 }
2451
2452 static void
init_gdrw(t_GDRW * gdrw,gint32 drawable_id,gboolean shadow)2453 init_gdrw (t_GDRW *gdrw,
2454 gint32 drawable_id,
2455 gboolean shadow)
2456 {
2457 gint32 image_id;
2458 gint32 sel_channel_id;
2459 gint32 x1, x2, y1, y2;
2460 gint offsetx, offsety;
2461 gint w, h;
2462 gint sel_offsetx, sel_offsety;
2463 t_GDRW *sel_gdrw;
2464 gint32 non_empty;
2465
2466 if (g_Sdebug)
2467 g_printf ("\np_init_gdrw: drawable_ID: %d\n", drawable_id);
2468
2469 gdrw->drawable_id = drawable_id;
2470
2471 if (shadow)
2472 gdrw->buffer = gimp_drawable_get_shadow_buffer (drawable_id);
2473 else
2474 gdrw->buffer = gimp_drawable_get_buffer (drawable_id);
2475
2476 gdrw->width = gimp_drawable_width (drawable_id);
2477 gdrw->height = gimp_drawable_height (drawable_id);
2478 gdrw->tile_width = gimp_tile_width ();
2479 gdrw->tile_height = gimp_tile_height ();
2480 gdrw->shadow = shadow;
2481 gdrw->seldeltax = 0;
2482 gdrw->seldeltay = 0;
2483 /* get offsets within the image */
2484 gimp_drawable_offsets (gdrw->drawable_id, &offsetx, &offsety);
2485
2486 if (! gimp_drawable_mask_intersect (gdrw->drawable_id,
2487 &gdrw->x1, &gdrw->y1, &w, &h))
2488 return;
2489
2490 gdrw->x2 = gdrw->x1 + w;
2491 gdrw->y2 = gdrw->y1 + h;
2492
2493 if (gimp_drawable_has_alpha (drawable_id))
2494 gdrw->format = babl_format ("R'G'B'A u8");
2495 else
2496 gdrw->format = babl_format ("R'G'B' u8");
2497
2498 gdrw->bpp = babl_format_get_bytes_per_pixel (gdrw->format);
2499
2500 if (gimp_drawable_has_alpha (drawable_id))
2501 {
2502 /* index of the alpha channelbyte {1|3} */
2503 gdrw->index_alpha = gdrw->bpp -1;
2504 }
2505 else
2506 {
2507 gdrw->index_alpha = 0; /* there is no alpha channel */
2508 }
2509
2510 image_id = gimp_item_get_image (gdrw->drawable_id);
2511
2512 /* check and see if we have a selection mask */
2513 sel_channel_id = gimp_image_get_selection (image_id);
2514
2515 if (g_Sdebug)
2516 {
2517 g_printf ("init_gdrw: image_id %d sel_channel_id: %d\n",
2518 (int)image_id, (int)sel_channel_id);
2519 g_printf ("init_gdrw: BOUNDS x1: %d y1: %d x2:%d y2: %d\n",
2520 (int)gdrw->x1, (int)gdrw->y1, (int)gdrw->x2,(int)gdrw->y2);
2521 g_printf ("init_gdrw: OFFS x: %d y: %d\n",
2522 (int)offsetx, (int)offsety );
2523 }
2524
2525 gimp_selection_bounds (image_id, &non_empty, &x1, &y1, &x2, &y2);
2526
2527 if (non_empty && (sel_channel_id >= 0))
2528 {
2529 /* selection is TRUE */
2530 sel_gdrw = g_new0 (t_GDRW, 1);
2531 sel_gdrw->drawable_id = sel_channel_id;
2532
2533 sel_gdrw->buffer = gimp_drawable_get_buffer (sel_channel_id);
2534 sel_gdrw->format = babl_format ("Y u8");
2535
2536 sel_gdrw->width = gimp_drawable_width (sel_channel_id);
2537 sel_gdrw->height = gimp_drawable_height (sel_channel_id);
2538
2539 sel_gdrw->tile_width = gimp_tile_width ();
2540 sel_gdrw->tile_height = gimp_tile_height ();
2541 sel_gdrw->shadow = shadow;
2542 sel_gdrw->x1 = x1;
2543 sel_gdrw->y1 = y1;
2544 sel_gdrw->x2 = x2;
2545 sel_gdrw->y2 = y2;
2546 sel_gdrw->seldeltax = 0;
2547 sel_gdrw->seldeltay = 0;
2548 sel_gdrw->bpp = babl_format_get_bytes_per_pixel (sel_gdrw->format);
2549 sel_gdrw->index_alpha = 0; /* there is no alpha channel */
2550 sel_gdrw->sel_gdrw = NULL;
2551
2552 /* offset delta between drawable and selection
2553 * (selection always has image size and should always have offsets of 0 )
2554 */
2555 gimp_drawable_offsets (sel_channel_id, &sel_offsetx, &sel_offsety);
2556 gdrw->seldeltax = offsetx - sel_offsetx;
2557 gdrw->seldeltay = offsety - sel_offsety;
2558
2559 gdrw->sel_gdrw = (t_GDRW *) sel_gdrw;
2560
2561 if (g_Sdebug)
2562 {
2563 g_printf ("init_gdrw: SEL_BOUNDS x1: %d y1: %d x2:%d y2: %d\n",
2564 (int)sel_gdrw->x1, (int)sel_gdrw->y1,
2565 (int)sel_gdrw->x2, (int)sel_gdrw->y2);
2566 g_printf ("init_gdrw: SEL_OFFS x: %d y: %d\n",
2567 (int)sel_offsetx, (int)sel_offsety );
2568 g_printf ("init_gdrw: SEL_DELTA x: %d y: %d\n",
2569 (int)gdrw->seldeltax, (int)gdrw->seldeltay );
2570 }
2571 }
2572 else
2573 gdrw->sel_gdrw = NULL; /* selection is FALSE */
2574 }
2575
2576 /* analyze the colors in the sample_drawable */
2577 static int
sample_analyze(t_GDRW * sample_gdrw)2578 sample_analyze (t_GDRW *sample_gdrw)
2579 {
2580 gint32 sample_pixels;
2581 gint32 row, col;
2582 gint32 first_row, first_col, last_row, last_col;
2583 gint32 x, y;
2584 gint32 x2, y2;
2585 float progress_step;
2586 float progress_max;
2587 float progress;
2588 guchar color[4];
2589 FILE *prot_fp;
2590
2591 sample_pixels = 0;
2592
2593 /* init progress */
2594 progress_max = (sample_gdrw->x2 - sample_gdrw->x1);
2595 progress_step = 1.0 / progress_max;
2596 progress = 0.0;
2597 if (g_show_progress)
2598 gimp_progress_init (_("Sample analyze"));
2599
2600 prot_fp = NULL;
2601 if (g_Sdebug)
2602 prot_fp = g_fopen ("sample_colors.dump", "w");
2603 print_values (prot_fp);
2604
2605 /* ------------------------------------------------
2606 * foreach pixel in the SAMPLE_drawable:
2607 * calculate brightness intensity LUM
2608 * ------------------------------------------------
2609 * the inner loops (x/y) are designed to process
2610 * all pixels of one tile in the sample drawable, the outer loops (row/col) do step
2611 * to the next tiles. (this was done to reduce tile swapping)
2612 */
2613
2614 first_row = sample_gdrw->y1 / sample_gdrw->tile_height;
2615 last_row = (sample_gdrw->y2 / sample_gdrw->tile_height);
2616 first_col = sample_gdrw->x1 / sample_gdrw->tile_width;
2617 last_col = (sample_gdrw->x2 / sample_gdrw->tile_width);
2618
2619 for (row = first_row; row <= last_row; row++)
2620 {
2621 for (col = first_col; col <= last_col; col++)
2622 {
2623 if (col == first_col)
2624 x = sample_gdrw->x1;
2625 else
2626 x = col * sample_gdrw->tile_width;
2627 if (col == last_col)
2628 x2 = sample_gdrw->x2;
2629 else
2630 x2 = (col +1) * sample_gdrw->tile_width;
2631
2632 for ( ; x < x2; x++)
2633 {
2634 if (row == first_row)
2635 y = sample_gdrw->y1;
2636 else
2637 y = row * sample_gdrw->tile_height;
2638 if (row == last_row)
2639 y2 = sample_gdrw->y2;
2640 else
2641 y2 = (row +1) * sample_gdrw->tile_height ;
2642
2643 /* printf ("X: %4d Y:%4d Y2:%4d\n", (int)x, (int)y, (int)y2); */
2644
2645 for ( ; y < y2; y++)
2646 {
2647 /* check if the pixel is in the selection */
2648 if (sample_gdrw->sel_gdrw)
2649 {
2650 get_pixel (sample_gdrw->sel_gdrw,
2651 (x + sample_gdrw->seldeltax),
2652 (y + sample_gdrw->seldeltay),
2653 &color[0]);
2654
2655 if (color[0] == 0)
2656 continue;
2657 }
2658 get_pixel (sample_gdrw, x, y, &color[0]);
2659
2660 /* if this is a visible (non-transparent) pixel */
2661 if ((sample_gdrw->index_alpha < 1) ||
2662 (color[sample_gdrw->index_alpha] != 0))
2663 {
2664 /* store color in the sublists of g_lum_tab */
2665 add_color (&color[0]);
2666 sample_pixels++;
2667 }
2668 }
2669
2670 if (g_show_progress)
2671 gimp_progress_update (progress += progress_step);
2672 }
2673 }
2674 }
2675
2676 if (g_show_progress)
2677 gimp_progress_update (1.0);
2678
2679 if (g_Sdebug)
2680 g_printf ("ROWS: %d - %d COLS: %d - %d\n",
2681 (int)first_row, (int)last_row,
2682 (int)first_col, (int)last_col);
2683
2684 print_table (prot_fp);
2685
2686 if (g_Sdebug)
2687 print_ppm ("sample_color_all.ppm");
2688
2689 /* find out ideal sample colors for each brightness intensity (lum)
2690 * and set g_sample_color_tab to the ideal colors.
2691 */
2692 ideal_samples ();
2693 calculate_level_transfers ();
2694
2695 if (g_values.guess_missing)
2696 guess_missing_colors ();
2697 else
2698 fill_missing_colors ();
2699
2700 print_table (prot_fp);
2701 if (g_Sdebug)
2702 print_ppm ("sample_color_2.ppm");
2703 print_transtable (prot_fp);
2704 if (prot_fp)
2705 fclose (prot_fp);
2706
2707 /* check if there was at least one visible pixel */
2708 if (sample_pixels == 0)
2709 {
2710 g_printf ("Error: Source sample has no visible Pixel\n");
2711 return -1;
2712 }
2713 return 0;
2714 }
2715
2716 static void
rnd_remap(gint32 lum,guchar * mapped_color)2717 rnd_remap (gint32 lum,
2718 guchar *mapped_color)
2719 {
2720 t_samp_color_elem *col_ptr;
2721 gint rnd;
2722 gint ct;
2723 gint idx;
2724
2725 if (g_lum_tab[lum].all_samples > 1)
2726 {
2727 rnd = g_random_int_range (0, g_lum_tab[lum].all_samples);
2728 ct = 0;
2729 idx = 0;
2730
2731 for (col_ptr = g_lum_tab[lum].col_ptr;
2732 col_ptr != NULL;
2733 col_ptr = (t_samp_color_elem *)col_ptr->next)
2734 {
2735 ct += col_ptr->sum_color;
2736
2737 if (rnd < ct)
2738 {
2739 /* printf ("RND_remap: rnd: %d all:%d ct:%d idx:%d\n",
2740 * rnd, (int)g_lum_tab[lum].all_samples, ct, idx);
2741 */
2742 memcpy (mapped_color, &col_ptr->color[0], 3);
2743 return;
2744 }
2745 idx++;
2746 }
2747 }
2748
2749 memcpy (mapped_color, &g_sample_color_tab[lum + lum + lum], 3);
2750 }
2751
2752 static void
remap_pixel(guchar * pixel,const guchar * original,gint bpp2)2753 remap_pixel (guchar *pixel,
2754 const guchar *original,
2755 gint bpp2)
2756 {
2757 guchar mapped_color[4];
2758 gint lum;
2759 double orig_lum, mapped_lum;
2760 double grn, red, blu;
2761 double mg, mr, mb;
2762 double dg, dr, db;
2763 double dlum;
2764
2765 /* get brightness from (uncolorized) original */
2766 lum = g_out_trans_tab[g_lvl_trans_tab[LUMINOSITY_1 (original)]];
2767 if (g_values.rnd_subcolors)
2768 rnd_remap (lum, mapped_color);
2769 else
2770 memcpy (mapped_color, &g_sample_color_tab[3 * lum], 3);
2771
2772 if (g_values.hold_inten)
2773 {
2774 if (g_values.orig_inten)
2775 orig_lum = LUMINOSITY_0(original);
2776 else
2777 orig_lum = 100.0 * g_lvl_trans_tab[LUMINOSITY_1 (original)];
2778
2779 mapped_lum = LUMINOSITY_0 (mapped_color);
2780
2781 if (mapped_lum == 0)
2782 {
2783 /* convert black to greylevel with desired brightness value */
2784 mapped_color[0] = orig_lum / 100.0;
2785 mapped_color[1] = mapped_color[0];
2786 mapped_color[2] = mapped_color[0];
2787 }
2788 else
2789 {
2790 /* Calculate theoretical RGB to reach given intensity LUM
2791 * value (orig_lum)
2792 */
2793 mr = mapped_color[0];
2794 mg = mapped_color[1];
2795 mb = mapped_color[2];
2796
2797 if (mr > 0.0)
2798 {
2799 red =
2800 orig_lum / (30 + (59 * mg / mr) + (11 * mb / mr));
2801 grn = mg * red / mr;
2802 blu = mb * red / mr;
2803 }
2804 else if (mg > 0.0)
2805 {
2806 grn =
2807 orig_lum / ((30 * mr / mg) + 59 + (11 * mb / mg));
2808 red = mr * grn / mg;
2809 blu = mb * grn / mg;
2810 }
2811 else
2812 {
2813 blu =
2814 orig_lum / ((30 * mr / mb) + (59 * mg / mb) + 11);
2815 grn = mg * blu / mb;
2816 red = mr * blu / mb;
2817 }
2818
2819 /* on overflow: Calculate real RGB values
2820 * (this may change the hue and saturation,
2821 * more and more into white)
2822 */
2823
2824 if (red > 255)
2825 {
2826 if ((blu < 255) && (grn < 255))
2827 {
2828 /* overflow in the red channel (compensate with green and blue) */
2829 dlum = (red - 255.0) * 30.0;
2830 if (mg > 0)
2831 {
2832 dg = dlum / (59.0 + (11.0 * mb / mg));
2833 db = dg * mb / mg;
2834 }
2835 else if (mb > 0)
2836 {
2837 db = dlum / (11.0 + (59.0 * mg / mb));
2838 dg = db * mg / mb;
2839 }
2840 else
2841 {
2842 db = dlum / (11.0 + 59.0);
2843 dg = dlum / (59.0 + 11.0);
2844 }
2845
2846 grn += dg;
2847 blu += db;
2848 }
2849
2850 red = 255.0;
2851
2852 if (grn > 255)
2853 {
2854 grn = 255.0;
2855 blu = (orig_lum - 22695) / 11; /* 22695 = (255 * 30) + (255 * 59) */
2856 }
2857 if (blu > 255)
2858 {
2859 blu = 255.0;
2860 grn = (orig_lum - 10455) / 59; /* 10455 = (255 * 30) + (255 * 11) */
2861 }
2862 }
2863 else if (grn > 255)
2864 {
2865 if ((blu < 255) && (red < 255))
2866 {
2867 /* overflow in the green channel (compensate with red and blue) */
2868 dlum = (grn - 255.0) * 59.0;
2869
2870 if (mr > 0)
2871 {
2872 dr = dlum / (30.0 + (11.0 * mb / mr));
2873 db = dr * mb / mr;
2874 }
2875 else if (mb > 0)
2876 {
2877 db = dlum / (11.0 + (30.0 * mr / mb));
2878 dr = db * mr / mb;
2879 }
2880 else
2881 {
2882 db = dlum / (11.0 + 30.0);
2883 dr = dlum / (30.0 + 11.0);
2884 }
2885
2886 red += dr;
2887 blu += db;
2888 }
2889
2890 grn = 255.0;
2891
2892 if (red > 255)
2893 {
2894 red = 255.0;
2895 blu = (orig_lum - 22695) / 11; /* 22695 = (255*59) + (255*30) */
2896 }
2897 if (blu > 255)
2898 {
2899 blu = 255.0;
2900 red = (orig_lum - 17850) / 30; /* 17850 = (255*59) + (255*11) */
2901 }
2902 }
2903 else if (blu > 255)
2904 {
2905 if ((red < 255) && (grn < 255))
2906 {
2907 /* overflow in the blue channel (compensate with green and red) */
2908 dlum = (blu - 255.0) * 11.0;
2909
2910 if (mg > 0)
2911 {
2912 dg = dlum / (59.0 + (30.0 * mr / mg));
2913 dr = dg * mr / mg;
2914 }
2915 else if (mr > 0)
2916 {
2917 dr = dlum / (30.0 + (59.0 * mg / mr));
2918 dg = dr * mg / mr;
2919 }
2920 else
2921 {
2922 dr = dlum / (30.0 + 59.0);
2923 dg = dlum / (59.0 + 30.0);
2924 }
2925
2926 grn += dg;
2927 red += dr;
2928 }
2929
2930 blu = 255.0;
2931
2932 if (grn > 255)
2933 {
2934 grn = 255.0;
2935 red = (orig_lum - 17850) / 30; /* 17850 = (255*11) + (255*59) */
2936 }
2937 if (red > 255)
2938 {
2939 red = 255.0;
2940 grn = (orig_lum - 10455) / 59; /* 10455 = (255*11) + (255*30) */
2941 }
2942 }
2943
2944 mapped_color[0] = CLAMP0255 (red + 0.5);
2945 mapped_color[1] = CLAMP0255 (grn + 0.5);
2946 mapped_color[2] = CLAMP0255 (blu + 0.5);
2947 }
2948 }
2949
2950 /* set colorized pixel in shadow pr */
2951 memcpy (pixel, &mapped_color[0], bpp2);
2952 }
2953
2954 static void
colorize_func(const guchar * src,guchar * dest,gint bpp,gboolean has_alpha)2955 colorize_func (const guchar *src,
2956 guchar *dest,
2957 gint bpp,
2958 gboolean has_alpha)
2959 {
2960 if (has_alpha)
2961 {
2962 bpp--;
2963 dest[bpp] = src[bpp];
2964 }
2965
2966 remap_pixel (dest, src, bpp);
2967 }
2968
2969 static void
colorize_drawable(gint32 drawable_id)2970 colorize_drawable (gint32 drawable_id)
2971 {
2972 GeglBuffer *src_buffer;
2973 GeglBuffer *dest_buffer;
2974 GeglBufferIterator *iter;
2975 const Babl *format;
2976 gboolean has_alpha;
2977 gint bpp;
2978 gint x, y, w, h;
2979 gint total_area;
2980 gint area_so_far;
2981
2982 if (! gimp_drawable_mask_intersect (drawable_id, &x, &y, &w, &h))
2983 return;
2984
2985 src_buffer = gimp_drawable_get_buffer (drawable_id);
2986 dest_buffer = gimp_drawable_get_shadow_buffer (drawable_id);
2987
2988 has_alpha = gimp_drawable_has_alpha (drawable_id);
2989
2990 if (has_alpha)
2991 format = babl_format ("R'G'B'A u8");
2992 else
2993 format = babl_format ("R'G'B' u8");
2994
2995 bpp = babl_format_get_bytes_per_pixel (format);
2996
2997 if (g_show_progress)
2998 gimp_progress_init (_("Remap colorized"));
2999
3000
3001 total_area = w * h;
3002 area_so_far = 0;
3003
3004 if (total_area <= 0)
3005 goto out;
3006
3007 iter = gegl_buffer_iterator_new (src_buffer,
3008 GEGL_RECTANGLE (x, y, w, h), 0, format,
3009 GEGL_ACCESS_READ, GEGL_ABYSS_NONE, 2);
3010
3011 gegl_buffer_iterator_add (iter, dest_buffer,
3012 GEGL_RECTANGLE (x, y, w, h), 0 , format,
3013 GEGL_ACCESS_WRITE, GEGL_ABYSS_NONE);
3014
3015 while (gegl_buffer_iterator_next (iter))
3016 {
3017 const guchar *src = iter->items[0].data;
3018 guchar *dest = iter->items[1].data;
3019 gint row;
3020
3021 for (row = 0; row < iter->items[0].roi.height; row++)
3022 {
3023 const guchar *s = src;
3024 guchar *d = dest;
3025 gint pixels = iter->items[0].roi.width;
3026
3027 while (pixels--)
3028 {
3029 colorize_func (s, d, bpp, has_alpha);
3030
3031 s += bpp;
3032 d += bpp;
3033 }
3034
3035 src += iter->items[0].roi.width * bpp;
3036 dest += iter->items[1].roi.width * bpp;
3037 }
3038
3039 area_so_far += iter->items[0].roi.width * iter->items[0].roi.height;
3040
3041 gimp_progress_update ((gdouble) area_so_far / (gdouble) total_area);
3042 }
3043
3044 g_object_unref (src_buffer);
3045 g_object_unref (dest_buffer);
3046
3047 gimp_drawable_merge_shadow (drawable_id, TRUE);
3048 gimp_drawable_update (drawable_id, x, y, w, h);
3049
3050 out:
3051 if (g_show_progress)
3052 gimp_progress_update (0.0);
3053 }
3054
3055 /* colorize dst_drawable like sample_drawable */
3056 static int
main_colorize(gint mc_flags)3057 main_colorize (gint mc_flags)
3058 {
3059 t_GDRW sample_gdrw;
3060 gboolean sample_drawable = FALSE;
3061 gint32 max;
3062 gint32 id;
3063 gint rc;
3064
3065 if (g_Sdebug)
3066 get_filevalues (); /* for debugging: read values from file */
3067
3068 /* calculate value of tolerable color error */
3069 max = color_error (0,0, 0, 255, 255, 255); /* 260100 */
3070 g_tol_col_err = (((float)max * (g_values.tol_col_err * g_values.tol_col_err)) / (100.0 *100.0));
3071 g_max_col_err = max;
3072
3073 rc = 0;
3074
3075 if (mc_flags & MC_GET_SAMPLE_COLORS)
3076 {
3077 id = g_values.sample_id;
3078 if ((id == SMP_GRADIENT) || (id == SMP_INV_GRADIENT))
3079 {
3080 get_gradient (id);
3081 }
3082 else
3083 {
3084 if (is_layer_alive (id) < 0)
3085 return -1;
3086
3087 sample_drawable = TRUE;
3088
3089 init_gdrw (&sample_gdrw, id, FALSE);
3090 free_colors ();
3091 rc = sample_analyze (&sample_gdrw);
3092 }
3093 }
3094
3095 if ((mc_flags & MC_DST_REMAP) && (rc == 0))
3096 {
3097 if (is_layer_alive (g_values.dst_id) < 0)
3098 return -1;
3099
3100 if (gimp_drawable_is_gray (g_values.dst_id) &&
3101 (mc_flags & MC_DST_REMAP))
3102 {
3103 gimp_image_convert_rgb (gimp_item_get_image (g_values.dst_id));
3104 }
3105
3106 colorize_drawable (g_values.dst_id);
3107 }
3108
3109 if (sample_drawable)
3110 end_gdrw (&sample_gdrw);
3111
3112 return rc;
3113 }
3114