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