1 /* GIMP - The GNU Image Manipulation Program
2  * Copyright (C) 1995 Spencer Kimball and Peter Mattis
3  *
4  * Compose plug-in (C) 1997,1999 Peter Kirchgessner
5  * e-mail: peter@kirchgessner.net, WWW: http://www.kirchgessner.net
6  *
7  * This program is free software: you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 3 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
19  */
20 
21 /*
22  * This plug-in composes RGB-images from several types of channels
23  */
24 
25 /*  Lab colorspace support originally written by Alexey Dyachenko,
26  *  merged into the official plug-in by Sven Neumann.
27  *
28  *  Support for channels empty or filled with a single mask value
29  *  added by Sylvain FORET.
30  */
31 
32 /*
33  * All redundant _256 versions of YCbCr* are here only for compatibility .
34  * They can be dropped for GIMP 3.0
35  */
36 
37 #include "config.h"
38 
39 #include <string.h>
40 
41 #include <libgimp/gimp.h>
42 #include <libgimp/gimpui.h>
43 
44 #include "libgimp/stdplugins-intl.h"
45 
46 
47 #define COMPOSE_PROC          "plug-in-compose"
48 #define DRAWABLE_COMPOSE_PROC "plug-in-drawable-compose"
49 #define RECOMPOSE_PROC        "plug-in-recompose"
50 #define PLUG_IN_BINARY        "compose"
51 #define PLUG_IN_ROLE          "gimp-compose"
52 
53 /* Maximum number of images to compose */
54 #define MAX_COMPOSE_IMAGES 4
55 
56 typedef struct
57 {
58   union
59     {
60       gint32 ID;  /* Image ID of input images or drawable */
61       guchar val; /* Mask value to compose with */
62     } comp;
63   gboolean is_ID;
64 } ComposeInput;
65 
66 /* Description of a component */
67 typedef struct
68 {
69   const gchar    *babl_name;
70   const gchar    *name;
71   const gchar    *icon;
72   const float     range_min;      /* val min of the component */
73   const float     range_max;      /* val max of the component */
74   const gboolean  is_perceptual;  /* Take the componenent from an Y' or Y buffer */
75 } COMPONENT_DSC;
76 
77 /* Description of a composition */
78 typedef struct
79 {
80   const gchar         *babl_model;
81   const gchar         *compose_type;  /*  Type of composition ("RGB", "RGBA",...)  */
82   gint                 num_images;    /*  Number of input images needed            */
83                                       /*  Channel information                     */
84   const COMPONENT_DSC  components[MAX_COMPOSE_IMAGES];
85   const gchar         *filename;      /*  Name of new image                        */
86 
87 } COMPOSE_DSC;
88 
89 
90 /* Declare local functions
91  */
92 static void      query                  (void);
93 static void      run                    (const gchar     *name,
94                                          gint            nparams,
95                                          const GimpParam *param,
96                                          gint            *nreturn_vals,
97                                          GimpParam      **return_vals);
98 
99 static void      cpn_affine_transform   (GeglBuffer      *buffer,
100                                          gdouble          min,
101                                          gdouble          max);
102 
103 static void fill_buffer_from_components (GeglBuffer      *temp[MAX_COMPOSE_IMAGES],
104                                          GeglBuffer      *dst,
105                                          gint             num_cpn,
106                                          ComposeInput    *inputs,
107                                          gdouble          mask_vals[MAX_COMPOSE_IMAGES]);
108 
109 static void      perform_composition    (COMPOSE_DSC      curr_compose_dsc,
110                                          GeglBuffer      *buffer_src[MAX_COMPOSE_IMAGES],
111                                          GeglBuffer      *buffer_dst,
112                                          ComposeInput    *inputs,
113                                          gint             num_images);
114 
115 static gint32    compose                (const gchar     *compose_type,
116                                          ComposeInput    *inputs,
117                                          gboolean         compose_by_drawable);
118 
119 static gint32    create_new_image       (const gchar     *filename,
120                                          guint            width,
121                                          guint            height,
122                                          GimpImageType    gdtype,
123                                          GimpPrecision    precision,
124                                          gint32          *layer_ID,
125                                          GeglBuffer     **drawable);
126 
127 static gboolean  compose_dialog         (const gchar     *compose_type,
128                                          gint32           drawable_ID);
129 
130 static gboolean  check_gray             (gint32           image_id,
131                                          gint32           drawable_id,
132                                          gpointer         data);
133 
134 static void      combo_callback         (GimpIntComboBox *cbox,
135                                          gpointer         data);
136 
137 static void      scale_callback         (GtkAdjustment   *adj,
138                                          ComposeInput    *input);
139 
140 static void      check_response         (GtkWidget       *dialog,
141                                          gint             response,
142                                          gpointer         data);
143 
144 static void      type_combo_callback    (GimpIntComboBox *combo,
145                                          gpointer         data);
146 
147 
148 
149 /* Decompositions availables.
150  * All the following values have to be kept in sync with those of decompose.c
151  */
152 
153 #define CPN_RGBA_R { "R", N_("_Red:"),   GIMP_ICON_CHANNEL_RED, 0.0, 1.0, FALSE}
154 #define CPN_RGBA_G { "G", N_("_Green:"), GIMP_ICON_CHANNEL_GREEN, 0.0, 1.0, FALSE}
155 #define CPN_RGBA_B { "B", N_("_Blue:"),  GIMP_ICON_CHANNEL_BLUE, 0.0, 1.0, FALSE}
156 #define CPN_RGBA_A { "A", N_("_Alpha:"), GIMP_ICON_CHANNEL_ALPHA, 0.0, 1.0, TRUE}
157 
158 #define CPN_HSV_H  { "hue",        N_("_Hue:"),        NULL, 0.0, 1.0, TRUE}
159 #define CPN_HSV_S  { "saturation", N_("_Saturation:"), NULL, 0.0, 1.0, TRUE}
160 #define CPN_HSV_V  { "value",      N_("_Value:"),      NULL, 0.0, 1.0, TRUE}
161 
162 #define CPN_HSL_H  { "hue",        N_("_Hue:"),        NULL, 0.0, 1.0, TRUE}
163 #define CPN_HSL_S  { "saturation", N_("_Saturation:"), NULL, 0.0, 1.0, TRUE}
164 #define CPN_HSL_L  { "lightness",  N_("_Lightness:"),  NULL, 0.0, 1.0, TRUE}
165 
166 #define CPN_CMYK_C { "Cyan",    N_("_Cyan:"),    NULL, 0.0, 1.0, TRUE}
167 #define CPN_CMYK_M { "Magenta", N_("_Magenta:"), NULL, 0.0, 1.0, TRUE}
168 #define CPN_CMYK_Y { "Yellow",  N_("_Yellow:"),  NULL, 0.0, 1.0, TRUE}
169 #define CPN_CMYK_K { "Key",     N_("_Black:"),   NULL, 0.0, 1.0, TRUE}
170 
171 #define CPN_LAB_L  { "CIE L", N_("_L:"), NULL, 0.0, 100.0, TRUE}
172 #define CPN_LAB_A  { "CIE a", N_("_A:"), NULL, -127.5, 127.5, TRUE}
173 #define CPN_LAB_B  { "CIE b", N_("_B:"), NULL, -127.5, 127.5, TRUE}
174 
175 #define CPN_LCH_L  { "CIE L",     N_("_L"), NULL, 0.0, 100.0, TRUE}
176 #define CPN_LCH_C  { "CIE C(ab)", N_("_C"), NULL, 0.0, 200.0, TRUE}
177 #define CPN_LCH_H  { "CIE H(ab)", N_("_H"), NULL, 0.0, 360.0, TRUE}
178 
179 #define CPN_YCBCR_Y  { "Y'", N_("_Luma y470:"),      NULL,  0.0, 1.0, TRUE }
180 #define CPN_YCBCR_CB { "Cb", N_("_Blueness cb470:"), NULL, -0.5, 0.5, TRUE }
181 #define CPN_YCBCR_CR { "Cr", N_("_Redness cr470:"),  NULL, -0.5, 0.5, TRUE }
182 
183 #define CPN_YCBCR709_Y  { "Y'", N_("_Luma y709:"),      NULL,  0.0, 1.0, TRUE }
184 #define CPN_YCBCR709_CB { "Cb", N_("_Blueness cb709:"), NULL, -0.5, 0.5, TRUE }
185 #define CPN_YCBCR709_CR { "Cr", N_("_Redness cr709:"),  NULL, -0.5, 0.5, TRUE }
186 
187 
188 static COMPOSE_DSC compose_dsc[] =
189 {
190   { "RGB",
191     N_("RGB"), 3,
192     { CPN_RGBA_R,
193       CPN_RGBA_G,
194       CPN_RGBA_B },
195     "rgb-compose" },
196 
197   { "RGBA",
198     N_("RGBA"), 4,
199     { CPN_RGBA_R,
200       CPN_RGBA_G,
201       CPN_RGBA_B,
202       CPN_RGBA_A },
203     "rgba-compose" },
204 
205   { "HSV",
206     N_("HSV"), 3,
207     { CPN_HSV_H,
208       CPN_HSV_S,
209       CPN_HSV_V },
210     "hsv-compose" },
211 
212   { "HSL",
213     N_("HSL"), 3,
214     { CPN_HSL_H,
215       CPN_HSL_S,
216       CPN_HSL_L },
217     "hsl-compose" },
218 
219   { "CMYK",
220     N_("CMYK"), 4,
221     { CPN_CMYK_C,
222       CPN_CMYK_M,
223       CPN_CMYK_Y,
224       CPN_CMYK_K },
225     "cmyk-compose" },
226 
227   { "CIE Lab",
228     N_("LAB"), 3,
229     { CPN_LAB_L,
230       CPN_LAB_A,
231       CPN_LAB_B },
232     "lab-compose" },
233 
234   { "CIE LCH(ab)",
235     N_("LCH"), 3,
236     { CPN_LCH_L,
237       CPN_LCH_C,
238       CPN_LCH_H },
239     "lch-compose" },
240 
241   { "Y'CbCr",
242     N_("YCbCr_ITU_R470"), 3,
243     { CPN_YCBCR_Y,
244       CPN_YCBCR_CB,
245       CPN_YCBCR_CR },
246     "ycbcr470-compose" },
247 
248   { "Y'CbCr709",
249     N_("YCbCr_ITU_R709"), 3,
250     { CPN_YCBCR709_Y,
251       CPN_YCBCR709_CB,
252       CPN_YCBCR709_CR },
253     "ycbcr709-compose" },
254 
255   { "Y'CbCr",
256     N_("YCbCr_ITU_R470_256"), 3,
257     { CPN_YCBCR_Y,
258       CPN_YCBCR_CB,
259       CPN_YCBCR_CR },
260     "ycbcr470F-compose" },
261 
262   { "Y'CbCr709",
263     N_("YCbCr_ITU_R709_256"), 3,
264     { CPN_YCBCR709_Y,
265       CPN_YCBCR709_CB,
266       CPN_YCBCR709_CR },
267     "ycbcr709F-compose" }
268 };
269 
270 
271 typedef struct
272 {
273   ComposeInput inputs[MAX_COMPOSE_IMAGES];  /* Image IDs or mask value of input */
274   gchar        compose_type[32];            /* type of composition */
275   gboolean     do_recompose;
276   gint32       source_layer_ID;             /* for recomposing */
277 } ComposeVals;
278 
279 /* Dialog structure */
280 typedef struct
281 {
282   gint          width, height;                            /* Size of selected image */
283 
284   GtkWidget    *channel_label[MAX_COMPOSE_IMAGES];        /* The labels to change */
285   GtkWidget    *channel_icon[MAX_COMPOSE_IMAGES];         /* The icons  */
286   GtkWidget    *channel_menu[MAX_COMPOSE_IMAGES];         /* The menus */
287   GtkWidget    *color_scales[MAX_COMPOSE_IMAGES];         /* The values color scales */
288   GtkWidget    *color_spins[MAX_COMPOSE_IMAGES];          /* The values spin buttons */
289 
290   ComposeInput  selected[MAX_COMPOSE_IMAGES];             /* Image Ids or mask values from menus */
291 
292   gint          compose_idx;                              /* Compose type */
293 } ComposeInterface;
294 
295 const GimpPlugInInfo PLUG_IN_INFO =
296 {
297   NULL,  /* init_proc  */
298   NULL,  /* quit_proc  */
299   query, /* query_proc */
300   run,   /* run_proc   */
301 };
302 
303 static ComposeVals composevals =
304 {
305   {{{ 0 }}}, /* Image IDs of images to compose or mask values */
306   "rgb",     /* Type of composition */
307   FALSE,     /* Do recompose */
308   -1         /* source layer ID */
309 };
310 
311 static ComposeInterface composeint =
312 {
313   0, 0,      /* width, height */
314   { NULL },  /* Label Widgets */
315   { NULL },  /* Icon Widgets */
316   { NULL },  /* Menu Widgets */
317   { NULL },  /* Color Scale Widgets */
318   { NULL },  /* Color Spin Widgets */
319   {{{ 0 }}}, /* Image Ids or mask values from menus */
320   0          /* Compose type */
321 };
322 
323 
MAIN()324 MAIN ()
325 
326 
327 static void
328 query (void)
329 {
330   static GimpParamDef args[] =
331   {
332     { GIMP_PDB_INT32,    "run-mode",     "The run mode { RUN-INTERACTIVE (0), RUN-NONINTERACTIVE (1) }" },
333     { GIMP_PDB_IMAGE,    "image1",       "First input image" },
334     { GIMP_PDB_DRAWABLE, "drawable",     "Input drawable (not used)" },
335     { GIMP_PDB_IMAGE,    "image2",       "Second input image" },
336     { GIMP_PDB_IMAGE,    "image3",       "Third input image" },
337     { GIMP_PDB_IMAGE,    "image4",       "Fourth input image" },
338     { GIMP_PDB_STRING,   "compose-type", NULL }
339   };
340 
341   static const GimpParamDef return_vals[] =
342   {
343     { GIMP_PDB_IMAGE, "new_image", "Output image" }
344   };
345 
346   static GimpParamDef drw_args[] =
347   {
348     { GIMP_PDB_INT32,    "run-mode",     "The run mode { RUN-INTERACTIVE (0), RUN-NONINTERACTIVE (1) }" },
349     { GIMP_PDB_IMAGE,    "image1",       "First input image (not used)" },
350     { GIMP_PDB_DRAWABLE, "drawable1",    "First input drawable" },
351     { GIMP_PDB_DRAWABLE, "drawable2",    "Second input drawable" },
352     { GIMP_PDB_DRAWABLE, "drawable3",    "Third input drawable" },
353     { GIMP_PDB_DRAWABLE, "drawable4",    "Fourth input drawable" },
354     { GIMP_PDB_STRING,   "compose-type", NULL }
355   };
356 
357   static const GimpParamDef drw_return_vals[] =
358   {
359     { GIMP_PDB_IMAGE, "new_image", "Output image" }
360   };
361 
362   static const GimpParamDef recompose_args[] =
363   {
364     { GIMP_PDB_INT32,    "run-mode", "The run mode { RUN-INTERACTIVE (0), RUN-NONINTERACTIVE (1) }" },
365     { GIMP_PDB_IMAGE,    "image",    "Image to recompose from" },
366     { GIMP_PDB_DRAWABLE, "drawable", "Not used" },
367   };
368 
369   GString *type_desc;
370   gint     i;
371 
372   type_desc = g_string_new ("What to compose: ");
373   g_string_append_c (type_desc, '"');
374   g_string_append (type_desc, compose_dsc[0].compose_type);
375   g_string_append_c (type_desc, '"');
376 
377   for (i = 1; i < G_N_ELEMENTS (compose_dsc); i++)
378     {
379       g_string_append (type_desc, ", ");
380       g_string_append_c (type_desc, '"');
381       g_string_append (type_desc, compose_dsc[i].compose_type);
382       g_string_append_c (type_desc, '"');
383     }
384 
385   args[6].description = type_desc->str;
386   drw_args[6].description = type_desc->str;
387 
388   gimp_install_procedure (COMPOSE_PROC,
389                           N_("Create an image using multiple gray images as color channels"),
390                           "This function creates a new image from "
391                           "multiple gray images",
392                           "Peter Kirchgessner",
393                           "Peter Kirchgessner (peter@kirchgessner.net)",
394                           "1997",
395                           N_("C_ompose..."),
396                           "GRAY*",
397                           GIMP_PLUGIN,
398                           G_N_ELEMENTS (args),
399                           G_N_ELEMENTS (return_vals),
400                           args, return_vals);
401 
402   gimp_plugin_menu_register (COMPOSE_PROC, "<Image>/Colors/Components");
403 
404   gimp_install_procedure (DRAWABLE_COMPOSE_PROC,
405                           "Compose an image from multiple drawables of gray images",
406                           "This function creates a new image from "
407                           "multiple drawables of gray images",
408                           "Peter Kirchgessner",
409                           "Peter Kirchgessner (peter@kirchgessner.net)",
410                           "1998",
411                           NULL,   /* It is not available in interactive mode */
412                           "GRAY*",
413                           GIMP_PLUGIN,
414                           G_N_ELEMENTS (drw_args),
415                           G_N_ELEMENTS (drw_return_vals),
416                           drw_args, drw_return_vals);
417 
418   gimp_install_procedure (RECOMPOSE_PROC,
419                           N_("Recompose an image that was previously decomposed"),
420                           "This function recombines the grayscale layers produced "
421                           "by Decompose into a single RGB or RGBA layer, and "
422                           "replaces the originally decomposed layer with the "
423                           "result.",
424                           "Bill Skaggs",
425                           "Bill Skaggs",
426                           "2004",
427                           N_("R_ecompose"),
428                           "GRAY*",
429                           GIMP_PLUGIN,
430                           G_N_ELEMENTS (recompose_args), 0,
431                           recompose_args, NULL);
432 
433   gimp_plugin_menu_register (RECOMPOSE_PROC, "<Image>/Colors/Components");
434 
435   g_string_free (type_desc, TRUE);
436 }
437 
438 
439 static void
run(const gchar * name,gint nparams,const GimpParam * param,gint * nreturn_vals,GimpParam ** return_vals)440 run (const gchar      *name,
441      gint              nparams,
442      const GimpParam  *param,
443      gint             *nreturn_vals,
444      GimpParam       **return_vals)
445 {
446   static GimpParam  values[2];
447   GimpPDBStatusType status = GIMP_PDB_SUCCESS;
448   GimpRunMode       run_mode;
449   gint32            image_ID;
450   gint32            drawable_ID = -1;
451   gint              compose_by_drawable;
452   gint              i;
453 
454   INIT_I18N ();
455   gegl_init (NULL, NULL);
456 
457   run_mode = param[0].data.d_int32;
458   compose_by_drawable = (strcmp (name, DRAWABLE_COMPOSE_PROC) == 0);
459 
460   *nreturn_vals = 1;
461   *return_vals  = values;
462 
463   values[0].type          = GIMP_PDB_STATUS;
464   values[0].data.d_status = status;
465   values[1].type          = GIMP_PDB_IMAGE;
466   values[1].data.d_int32  = -1;
467 
468   if (strcmp (name, RECOMPOSE_PROC) == 0)
469     {
470       GimpParasite *parasite = gimp_image_get_parasite (param[1].data.d_image,
471                                                         "decompose-data");
472 
473       if (! parasite)
474         {
475           g_message (_("You can only run 'Recompose' if the active image "
476                        "was originally produced by 'Decompose'."));
477           status = GIMP_PDB_EXECUTION_ERROR;
478         }
479       else
480         {
481           gint nret;
482 
483           nret = sscanf (gimp_parasite_data (parasite),
484                          "source=%d type=%31s %d %d %d %d",
485                          &composevals.source_layer_ID,
486                          composevals.compose_type,
487                          &composevals.inputs[0].comp.ID,
488                          &composevals.inputs[1].comp.ID,
489                          &composevals.inputs[2].comp.ID,
490                          &composevals.inputs[3].comp.ID);
491 
492           gimp_parasite_free (parasite);
493 
494           for (i = 0; i < MAX_COMPOSE_IMAGES; i++)
495             composevals.inputs[i].is_ID = TRUE;
496 
497           if (nret < 5)
498             {
499               g_message (_("Error scanning 'decompose-data' parasite: "
500                            "too few layers found"));
501               status = GIMP_PDB_EXECUTION_ERROR;
502             }
503           else
504             {
505               composevals.do_recompose = TRUE;
506               compose_by_drawable = TRUE;
507             }
508         }
509     }
510   else
511     {
512       composevals.do_recompose = FALSE;
513 
514       switch (run_mode)
515         {
516         case GIMP_RUN_INTERACTIVE:
517           /*  Possibly retrieve data  */
518           gimp_get_data (name, &composevals);
519 
520           compose_by_drawable = TRUE;
521 
522           /* The dialog is now drawable based. Get a drawable-ID of the image */
523           if (strcmp (name, COMPOSE_PROC) == 0)
524             {
525               gint32 *layer_list;
526               gint    nlayers;
527 
528               layer_list = gimp_image_get_layers (param[1].data.d_int32,
529                                                   &nlayers);
530               if ((layer_list == NULL) || (nlayers <= 0))
531                 {
532                   g_message (_("Could not get layers for image %d"),
533                              (gint) param[1].data.d_int32);
534                   return;
535                 }
536 
537               drawable_ID = layer_list[0];
538               g_free (layer_list);
539             }
540           else
541             {
542               drawable_ID = param[2].data.d_int32;
543             }
544 
545           /*  First acquire information with a dialog  */
546           if (! compose_dialog (composevals.compose_type, drawable_ID))
547             return;
548 
549           break;
550 
551         case GIMP_RUN_NONINTERACTIVE:
552           /*  Make sure all the arguments are there!  */
553           if (nparams < 7)
554             {
555               status = GIMP_PDB_CALLING_ERROR;
556             }
557           else
558             {
559               composevals.inputs[0].comp.ID = (compose_by_drawable ?
560                                                param[2].data.d_int32 :
561                                                param[1].data.d_int32);
562               composevals.inputs[1].comp.ID = param[3].data.d_int32;
563               composevals.inputs[2].comp.ID = param[4].data.d_int32;
564               composevals.inputs[3].comp.ID = param[5].data.d_int32;
565 
566               strncpy (composevals.compose_type, param[6].data.d_string,
567                        sizeof (composevals.compose_type));
568               composevals.compose_type[sizeof (composevals.compose_type)-1] = '\0';
569 
570               for (i = 0; i < MAX_COMPOSE_IMAGES; i++)
571                 {
572                   if (composevals.inputs[i].comp.ID == -1)
573                     {
574                       composevals.inputs[i].is_ID = FALSE;
575                       composevals.inputs[i].comp.val = 0;
576                     }
577                   else
578                     {
579                       composevals.inputs[i].is_ID = TRUE;
580                     }
581                 }
582             }
583           break;
584 
585         case GIMP_RUN_WITH_LAST_VALS:
586           /*  Possibly retrieve data  */
587           gimp_get_data (name, &composevals);
588 
589           compose_by_drawable = TRUE;
590           break;
591 
592         default:
593           break;
594         }
595     }
596 
597   if (status == GIMP_PDB_SUCCESS)
598     {
599       gimp_progress_init (_("Composing"));
600 
601       image_ID = compose (composevals.compose_type,
602                           composevals.inputs,
603                           compose_by_drawable);
604 
605       if (image_ID < 0)
606         {
607           status = GIMP_PDB_EXECUTION_ERROR;
608         }
609       else
610         {
611           values[1].data.d_int32 = image_ID;
612 
613           if (composevals.do_recompose)
614             {
615               gimp_displays_flush ();
616             }
617           else
618             {
619               gimp_image_undo_enable (image_ID);
620               gimp_image_clean_all (image_ID);
621 
622               if (run_mode != GIMP_RUN_NONINTERACTIVE)
623                 gimp_display_new (image_ID);
624             }
625         }
626 
627       /*  Store data  */
628       if (run_mode == GIMP_RUN_INTERACTIVE)
629         gimp_set_data (name, &composevals, sizeof (ComposeVals));
630     }
631 
632   *nreturn_vals = composevals.do_recompose ? 1 : 2;
633 
634   values[0].data.d_status = status;
635 }
636 
637 static void
cpn_affine_transform(GeglBuffer * buffer,gdouble min,gdouble max)638 cpn_affine_transform (GeglBuffer *buffer,
639                       gdouble     min,
640                       gdouble     max)
641 {
642   GeglBufferIterator *gi;
643   const gdouble       scale  = max - min;
644   const gdouble       offset = min;
645 
646   /* We want to scale values linearly, regardless of the format of the buffer */
647   gegl_buffer_set_format (buffer, babl_format ("Y double"));
648 
649   gi = gegl_buffer_iterator_new (buffer, NULL, 0, NULL,
650                                  GEGL_ACCESS_READWRITE, GEGL_ABYSS_NONE, 1);
651 
652   while (gegl_buffer_iterator_next (gi))
653     {
654       gdouble *data = gi->items[0].data;
655       guint    k;
656 
657       for (k = 0; k < gi->length; k++)
658         {
659           data[k] = data[k] * scale + offset;
660         }
661     }
662 }
663 
664 static void
fill_buffer_from_components(GeglBuffer * temp[MAX_COMPOSE_IMAGES],GeglBuffer * dst,gint num_cpn,ComposeInput * inputs,gdouble mask_vals[MAX_COMPOSE_IMAGES])665 fill_buffer_from_components (GeglBuffer   *temp[MAX_COMPOSE_IMAGES],
666                              GeglBuffer   *dst,
667                              gint          num_cpn,
668                              ComposeInput *inputs,
669                              gdouble       mask_vals[MAX_COMPOSE_IMAGES])
670 {
671   GeglBufferIterator *gi;
672   gint                j;
673 
674   gi = gegl_buffer_iterator_new (dst, NULL, 0, NULL,
675                                  GEGL_ACCESS_WRITE, GEGL_ABYSS_NONE, 10);
676 
677   for (j = 0; j < num_cpn; j++)
678     {
679       if (inputs[j].is_ID)
680         gegl_buffer_iterator_add (gi, temp[j], NULL, 0, NULL,
681                                   GEGL_ACCESS_READ, GEGL_ABYSS_NONE);
682     }
683 
684   while (gegl_buffer_iterator_next (gi))
685     {
686       gdouble *src_data[MAX_COMPOSE_IMAGES];
687       gdouble *dst_data = (gdouble*) gi->items[0].data;
688       gulong   k, count;
689 
690       count = 1;
691       for (j = 0; j < num_cpn; j++)
692         if (inputs[j].is_ID)
693           src_data[j] = (gdouble*) gi->items[count++].data;
694 
695       for (k = 0; k < gi->length; k++)
696         {
697           gulong pos = k * num_cpn;
698 
699           for (j = 0; j < num_cpn; j++)
700             {
701               if (inputs[j].is_ID)
702                 dst_data[pos+j] = src_data[j][k];
703               else
704                 dst_data[pos+j] = mask_vals[j];
705             }
706         }
707     }
708 }
709 
710 static void
perform_composition(COMPOSE_DSC curr_compose_dsc,GeglBuffer * buffer_src[MAX_COMPOSE_IMAGES],GeglBuffer * buffer_dst,ComposeInput * inputs,gint num_images)711 perform_composition (COMPOSE_DSC   curr_compose_dsc,
712                      GeglBuffer   *buffer_src[MAX_COMPOSE_IMAGES],
713                      GeglBuffer   *buffer_dst,
714                      ComposeInput *inputs,
715                      gint          num_images)
716 {
717   const Babl          *dst_format;
718   GeglBuffer          *temp[MAX_COMPOSE_IMAGES];
719   GeglBuffer          *dst_temp;
720   const GeglRectangle *extent = NULL;
721 
722   const COMPONENT_DSC *components;
723   gdouble              mask_vals[MAX_COMPOSE_IMAGES];
724   gint                 i;
725 
726   components = curr_compose_dsc.components;
727 
728   /* Get all individual components in gray buffers */
729   for (i = 0; i < num_images; i++)
730     {
731       COMPONENT_DSC  cpn_dsc = components[i];
732       const Babl    *gray_format;
733 
734       if (cpn_dsc.is_perceptual)
735         gray_format = babl_format ("Y' double");
736       else
737         gray_format = babl_format ("Y double");
738 
739       if (! inputs[i].is_ID)
740         {
741           const Babl *fish = babl_fish (babl_format ("Y' u8"), gray_format);
742 
743           babl_process (fish, &inputs[i].comp.val, &mask_vals[i], 1);
744 
745           mask_vals[i] = mask_vals[i] * (cpn_dsc.range_max - cpn_dsc.range_min) + cpn_dsc.range_min;
746         }
747       else
748         {
749           extent = gegl_buffer_get_extent (buffer_src[i]);
750 
751           temp[i] = gegl_buffer_new (extent, gray_format);
752 
753           gegl_buffer_copy (buffer_src[i], NULL, GEGL_ABYSS_NONE, temp[i], NULL);
754 
755           if (cpn_dsc.range_min != 0.0 || cpn_dsc.range_max != 1.0)
756             cpn_affine_transform (temp[i], cpn_dsc.range_min, cpn_dsc.range_max);
757         }
758 
759       gimp_progress_update ((gdouble) i / (gdouble) (num_images + 1.0));
760     }
761 
762   dst_format = babl_format_new (babl_model (curr_compose_dsc.babl_model),
763                                 babl_type ("double"),
764                                 babl_component (components[0].babl_name),
765                                 num_images > 1 ? babl_component (components[1].babl_name) : NULL,
766                                 num_images > 2 ? babl_component (components[2].babl_name) : NULL,
767                                 num_images > 3 ? babl_component (components[3].babl_name) : NULL,
768                                 NULL);
769 
770   /* extent is not NULL because there is at least one drawable */
771   dst_temp = gegl_buffer_new (extent, dst_format);
772 
773   /* Gather all individual components in the dst_format buffer */
774   fill_buffer_from_components (temp, dst_temp, num_images, inputs, mask_vals);
775 
776   gimp_progress_update ((gdouble) num_images / (gdouble) (num_images + 1.0));
777 
778   /* Copy back to the format GIMP wants (and perform the conversion in itself) */
779   gegl_buffer_copy (dst_temp, NULL, GEGL_ABYSS_NONE, buffer_dst, NULL);
780 
781   for (i = 0; i< num_images; i++)
782     if( inputs[i].is_ID)
783       g_object_unref (temp[i]);
784 
785   g_object_unref (dst_temp);
786 }
787 
788 /* Compose an image from several gray-images */
789 static gint32
compose(const gchar * compose_type,ComposeInput * inputs,gboolean compose_by_drawable)790 compose (const gchar  *compose_type,
791          ComposeInput *inputs,
792          gboolean      compose_by_drawable)
793 {
794   gint           width, height;
795   gint           num_images, compose_idx;
796   gint           i, j;
797   gint           num_layers;
798   gint32         layer_ID_dst, image_ID_dst;
799   gint           first_ID;
800   GimpImageType  gdtype_dst;
801   GeglBuffer    *buffer_src[MAX_COMPOSE_IMAGES];
802   GeglBuffer    *buffer_dst;
803   GimpPrecision  precision;
804 
805   /* Search type of composing */
806   compose_idx = -1;
807   for (j = 0; j < G_N_ELEMENTS (compose_dsc); j++)
808     {
809       if (g_ascii_strcasecmp (compose_type, compose_dsc[j].compose_type) == 0)
810         {
811           compose_idx = j;
812           break;
813         }
814     }
815 
816   if (compose_idx < 0)
817     return -1;
818 
819   num_images = compose_dsc[compose_idx].num_images;
820 
821   /* Check that at least one image or one drawable is provided */
822   first_ID = -1;
823   for (i = 0; i < num_images; i++)
824     {
825       if (inputs[i].is_ID)
826         {
827           first_ID = i;
828           break;
829         }
830     }
831 
832   if (-1 == first_ID)
833     {
834       g_message (_("At least one image is needed to compose"));
835       return -1;
836     }
837 
838   /* Check image sizes */
839   if (compose_by_drawable)
840     {
841       gint32 first_image = gimp_item_get_image (inputs[first_ID].comp.ID);
842 
843       if (! gimp_item_is_valid (inputs[first_ID].comp.ID))
844         {
845           g_message (_("Specified layer %d not found"),
846                      inputs[first_ID].comp.ID);
847           return -1;
848         }
849 
850       width  = gimp_drawable_width  (inputs[first_ID].comp.ID);
851       height = gimp_drawable_height (inputs[first_ID].comp.ID);
852 
853       precision = gimp_image_get_precision (first_image);
854 
855       for (j = first_ID + 1; j < num_images; j++)
856         {
857           if (inputs[j].is_ID)
858             {
859               if (! gimp_item_is_valid (inputs[j].comp.ID))
860                 {
861                   g_message (_("Specified layer %d not found"),
862                              inputs[j].comp.ID);
863                   return -1;
864                 }
865 
866               if ((width  != gimp_drawable_width  (inputs[j].comp.ID)) ||
867                   (height != gimp_drawable_height (inputs[j].comp.ID)))
868                 {
869                   g_message (_("Drawables have different size"));
870                   return -1;
871                 }
872             }
873         }
874 
875       for (j = 0; j < num_images; j++)
876         {
877           if (inputs[j].is_ID)
878             buffer_src[j] = gimp_drawable_get_buffer (inputs[j].comp.ID);
879           else
880             buffer_src[j] = NULL;
881         }
882     }
883   else    /* Compose by image ID */
884     {
885       width  = gimp_image_width  (inputs[first_ID].comp.ID);
886       height = gimp_image_height (inputs[first_ID].comp.ID);
887 
888       precision = gimp_image_get_precision (inputs[first_ID].comp.ID);
889 
890       for (j = first_ID + 1; j < num_images; j++)
891         {
892           if (inputs[j].is_ID)
893             {
894               if ((width  != gimp_image_width (inputs[j].comp.ID)) ||
895                   (height != gimp_image_height (inputs[j].comp.ID)))
896                 {
897                   g_message (_("Images have different size"));
898                   return -1;
899                 }
900             }
901         }
902 
903       /* Get first layer/drawable for all input images */
904       for (j = 0; j < num_images; j++)
905         {
906           if (inputs[j].is_ID)
907             {
908               gint32 *layers;
909 
910               /* Get first layer of image */
911               layers = gimp_image_get_layers (inputs[j].comp.ID, &num_layers);
912 
913               if (! layers || (num_layers <= 0))
914                 {
915                   g_message (_("Error in getting layer IDs"));
916                   return -1;
917                 }
918 
919               /* Get drawable for layer */
920               buffer_src[j] = gimp_drawable_get_buffer (layers[0]);
921               g_free (layers);
922             }
923         }
924     }
925 
926   /* Unless recomposing, create new image */
927   if (composevals.do_recompose)
928     {
929       layer_ID_dst = composevals.source_layer_ID;
930 
931       if (! gimp_item_is_valid (layer_ID_dst))
932         {
933           g_message (_("Unable to recompose, source layer not found"));
934           return -1;
935         }
936 
937       image_ID_dst = gimp_item_get_image (layer_ID_dst);
938 
939       buffer_dst = gimp_drawable_get_shadow_buffer (layer_ID_dst);
940     }
941   else
942     {
943       gdtype_dst = ((babl_model (compose_dsc[compose_idx].babl_model) == babl_model ("RGBA")) ?
944                     GIMP_RGBA_IMAGE : GIMP_RGB_IMAGE);
945 
946       image_ID_dst = create_new_image (compose_dsc[compose_idx].filename,
947                                        width, height, gdtype_dst, precision,
948                                        &layer_ID_dst, &buffer_dst);
949     }
950 
951   if (! compose_by_drawable)
952     {
953       gdouble  xres, yres;
954 
955       gimp_image_get_resolution (inputs[first_ID].comp.ID, &xres, &yres);
956       gimp_image_set_resolution (image_ID_dst, xres, yres);
957     }
958 
959   perform_composition (compose_dsc[compose_idx],
960                        buffer_src,
961                        buffer_dst,
962                        inputs,
963                        num_images);
964 
965   gimp_progress_update (1.0);
966 
967   for (j = 0; j < num_images; j++)
968     {
969       if (inputs[j].is_ID)
970         g_object_unref (buffer_src[j]);
971     }
972 
973   g_object_unref (buffer_dst);
974 
975   if (composevals.do_recompose)
976     gimp_drawable_merge_shadow (layer_ID_dst, TRUE);
977 
978   gimp_drawable_update (layer_ID_dst, 0, 0,
979                         gimp_drawable_width (layer_ID_dst),
980                         gimp_drawable_height (layer_ID_dst));
981 
982   return image_ID_dst;
983 }
984 
985 
986 /* Create an image. Sets layer_ID, drawable and rgn. Returns image_ID */
987 static gint32
create_new_image(const gchar * filename,guint width,guint height,GimpImageType gdtype,GimpPrecision precision,gint32 * layer_ID,GeglBuffer ** buffer)988 create_new_image (const gchar    *filename,
989                   guint           width,
990                   guint           height,
991                   GimpImageType   gdtype,
992                   GimpPrecision   precision,
993                   gint32         *layer_ID,
994                   GeglBuffer    **buffer)
995 {
996   gint32            image_ID;
997   GimpImageBaseType gitype;
998 
999   if ((gdtype == GIMP_GRAY_IMAGE) || (gdtype == GIMP_GRAYA_IMAGE))
1000     gitype = GIMP_GRAY;
1001   else if ((gdtype == GIMP_INDEXED_IMAGE) || (gdtype == GIMP_INDEXEDA_IMAGE))
1002     gitype = GIMP_INDEXED;
1003   else
1004     gitype = GIMP_RGB;
1005 
1006   image_ID = gimp_image_new_with_precision (width, height, gitype, precision);
1007 
1008   gimp_image_undo_disable (image_ID);
1009   gimp_image_set_filename (image_ID, filename);
1010 
1011   *layer_ID = gimp_layer_new (image_ID, _("Background"), width, height,
1012                               gdtype,
1013                               100,
1014                               gimp_image_get_default_new_layer_mode (image_ID));
1015   gimp_image_insert_layer (image_ID, *layer_ID, -1, 0);
1016 
1017   *buffer = gimp_drawable_get_buffer (*layer_ID);
1018 
1019   return image_ID;
1020 }
1021 
1022 
1023 static gboolean
compose_dialog(const gchar * compose_type,gint32 drawable_ID)1024 compose_dialog (const gchar *compose_type,
1025                 gint32       drawable_ID)
1026 {
1027   GtkWidget    *dialog;
1028   GtkWidget    *main_vbox;
1029   GtkWidget    *frame;
1030   GtkWidget    *vbox;
1031   GtkWidget    *hbox;
1032   GtkWidget    *label;
1033   GtkWidget    *combo;
1034   GtkWidget    *table;
1035   GtkSizeGroup *size_group;
1036   gint32       *layer_list;
1037   gint          nlayers;
1038   gint          j;
1039   gboolean      run;
1040 
1041   /* Check default compose type */
1042   composeint.compose_idx = 0;
1043   for (j = 0; j < G_N_ELEMENTS (compose_dsc); j++)
1044     {
1045       if (g_ascii_strcasecmp (compose_type, compose_dsc[j].compose_type) == 0)
1046         {
1047           composeint.compose_idx = j;
1048           break;
1049         }
1050     }
1051 
1052   /* Save original image width/height */
1053   composeint.width  = gimp_drawable_width (drawable_ID);
1054   composeint.height = gimp_drawable_height (drawable_ID);
1055 
1056   gimp_ui_init (PLUG_IN_BINARY, TRUE);
1057 
1058   layer_list = gimp_image_get_layers (gimp_item_get_image (drawable_ID),
1059                                       &nlayers);
1060 
1061   dialog = gimp_dialog_new (_("Compose"), PLUG_IN_ROLE,
1062                             NULL, 0,
1063                             gimp_standard_help_func, COMPOSE_PROC,
1064 
1065                             _("_Cancel"), GTK_RESPONSE_CANCEL,
1066                             _("_OK"),     GTK_RESPONSE_OK,
1067 
1068                             NULL);
1069 
1070   gtk_dialog_set_alternative_button_order (GTK_DIALOG (dialog),
1071                                            GTK_RESPONSE_OK,
1072                                            GTK_RESPONSE_CANCEL,
1073                                            -1);
1074 
1075   g_signal_connect (dialog, "response",
1076                     G_CALLBACK (check_response),
1077                     NULL);
1078 
1079   gimp_window_set_transient (GTK_WINDOW (dialog));
1080 
1081   main_vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
1082   gtk_container_set_border_width (GTK_CONTAINER (main_vbox), 12);
1083   gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))),
1084                       main_vbox, TRUE, TRUE, 0);
1085   gtk_widget_show (main_vbox);
1086 
1087   /* Compose type combo */
1088 
1089   frame = gimp_frame_new (_("Compose Channels"));
1090   gtk_box_pack_start (GTK_BOX (main_vbox), frame, FALSE, FALSE, 0);
1091   gtk_widget_show (frame);
1092 
1093   hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
1094   gtk_container_add (GTK_CONTAINER (frame), hbox);
1095   gtk_widget_show (hbox);
1096 
1097   size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
1098 
1099   label = gtk_label_new_with_mnemonic (_("Color _model:"));
1100   gtk_label_set_xalign (GTK_LABEL (label), 0.0);
1101   gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
1102   gtk_widget_show (label);
1103 
1104   gtk_size_group_add_widget (size_group, label);
1105   g_object_unref (size_group);
1106 
1107   combo = g_object_new (GIMP_TYPE_INT_COMBO_BOX, NULL);
1108   for (j = 0; j < G_N_ELEMENTS (compose_dsc); j++)
1109     {
1110       gchar *label = g_strdup (gettext (compose_dsc[j].compose_type));
1111       gchar *l;
1112 
1113       for (l = label; *l; l++)
1114         if (*l == '-' || *l == '_')
1115           *l = ' ';
1116 
1117       gimp_int_combo_box_append (GIMP_INT_COMBO_BOX (combo),
1118                                  GIMP_INT_STORE_LABEL, label,
1119                                  GIMP_INT_STORE_VALUE, j,
1120                                  -1);
1121       g_free (label);
1122     }
1123 
1124   gtk_box_pack_start (GTK_BOX (hbox), combo, TRUE, TRUE, 0);
1125   gtk_widget_show (combo);
1126 
1127   gtk_label_set_mnemonic_widget (GTK_LABEL (label), combo);
1128 
1129   /* Channel representation table */
1130 
1131   frame = gimp_frame_new (_("Channel Representations"));
1132   gtk_box_pack_start (GTK_BOX (main_vbox), frame, TRUE, TRUE, 0);
1133   gtk_widget_show (frame);
1134 
1135   vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
1136   gtk_container_add (GTK_CONTAINER (frame), vbox);
1137   gtk_widget_show (vbox);
1138 
1139   table = gtk_table_new (MAX_COMPOSE_IMAGES, 4, FALSE);
1140   gtk_table_set_row_spacings (GTK_TABLE (table), 6);
1141   gtk_table_set_col_spacings (GTK_TABLE (table), 6);
1142   gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, FALSE, 0);
1143   gtk_widget_show (table);
1144 
1145   for (j = 0; j < MAX_COMPOSE_IMAGES; j++)
1146     {
1147       GtkWidget    *image;
1148       GtkWidget    *label;
1149       GtkWidget    *combo;
1150       GtkObject    *scale;
1151       GtkTreeIter   iter;
1152       GtkTreeModel *model;
1153       GdkPixbuf    *ico;
1154 
1155       hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
1156       gtk_table_attach (GTK_TABLE (table), hbox, 0, 1, j, j + 1,
1157                         GTK_FILL, GTK_FILL, 0, 0);
1158       gtk_widget_show (hbox);
1159 
1160       gtk_size_group_add_widget (size_group, hbox);
1161 
1162       composeint.channel_icon[j] = image = gtk_image_new ();
1163       gtk_box_pack_start (GTK_BOX (hbox), image, FALSE, FALSE, 0);
1164       gtk_widget_show (image);
1165 
1166       composeint.channel_label[j] = label = gtk_label_new_with_mnemonic ("");
1167       gtk_label_set_xalign (GTK_LABEL (label), 0.0);
1168       gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
1169       gtk_widget_show (label);
1170 
1171       if (composeint.compose_idx >= 0 &&
1172           nlayers >= compose_dsc[composeint.compose_idx].num_images &&
1173           j < nlayers)
1174         {
1175           composeint.selected[j].comp.ID = layer_list[j];
1176         }
1177       else
1178         {
1179           composeint.selected[j].comp.ID = drawable_ID;
1180         }
1181 
1182       composeint.selected[j].is_ID = TRUE;
1183 
1184       combo = gimp_drawable_combo_box_new (check_gray, NULL);
1185       composeint.channel_menu[j] = combo;
1186 
1187       ico = gtk_widget_render_icon (dialog,
1188                                     GIMP_ICON_CHANNEL_GRAY,
1189                                     GTK_ICON_SIZE_BUTTON, NULL);
1190       model = gtk_combo_box_get_model (GTK_COMBO_BOX (combo));
1191       gtk_list_store_append (GTK_LIST_STORE (model), &iter);
1192       gtk_list_store_set (GTK_LIST_STORE (model), &iter,
1193                           GIMP_INT_STORE_VALUE,  -1,
1194                           GIMP_INT_STORE_LABEL,  _("Mask value"),
1195                           GIMP_INT_STORE_PIXBUF, ico,
1196                           -1);
1197       g_object_unref (ico);
1198       gtk_table_attach (GTK_TABLE (table), combo, 1, 2, j, j + 1,
1199                         GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
1200       gtk_widget_show (combo);
1201 
1202       gtk_label_set_mnemonic_widget (GTK_LABEL (label), combo);
1203 
1204       scale = gimp_color_scale_entry_new (GTK_TABLE (table), 2, j, NULL,
1205                                           100, 4,
1206                                           255.0, 0.0, 255.0, 1.0, 10.0, 0,
1207                                           NULL, NULL);
1208       composeint.color_scales[j] = GIMP_SCALE_ENTRY_SCALE (scale);
1209       composeint.color_spins[j]  = GIMP_SCALE_ENTRY_SPINBUTTON (scale);
1210 
1211       gtk_widget_set_sensitive (composeint.color_scales[j], FALSE);
1212       gtk_widget_set_sensitive (composeint.color_spins[j],  FALSE);
1213 
1214       g_signal_connect (scale, "value-changed",
1215                         G_CALLBACK (scale_callback),
1216                         &composeint.selected[j]);
1217 
1218       /* This has to be connected last otherwise it will emit before
1219        * combo_callback has any scale and spinbutton to work with
1220        */
1221       gimp_int_combo_box_connect (GIMP_INT_COMBO_BOX (combo),
1222                                   composeint.selected[j].comp.ID,
1223                                   G_CALLBACK (combo_callback),
1224                                   GINT_TO_POINTER (j));
1225     }
1226 
1227   g_free (layer_list);
1228 
1229   /* Calls the combo callback and sets icons, labels and sensitivity */
1230   gimp_int_combo_box_connect (GIMP_INT_COMBO_BOX (combo),
1231                               composeint.compose_idx,
1232                               G_CALLBACK (type_combo_callback),
1233                               NULL);
1234 
1235   gtk_widget_show (dialog);
1236 
1237   run = (gimp_dialog_run (GIMP_DIALOG (dialog)) == GTK_RESPONSE_OK);
1238 
1239   gtk_widget_destroy (dialog);
1240 
1241   if (run)
1242     {
1243       gint j;
1244 
1245       for (j = 0; j < MAX_COMPOSE_IMAGES; j++)
1246         {
1247           composevals.inputs[j].is_ID = composeint.selected[j].is_ID;
1248 
1249           if (composevals.inputs[j].is_ID)
1250             composevals.inputs[j].comp.ID = composeint.selected[j].comp.ID;
1251           else
1252             composevals.inputs[j].comp.val = composeint.selected[j].comp.val;
1253         }
1254 
1255       strcpy (composevals.compose_type,
1256               compose_dsc[composeint.compose_idx].compose_type);
1257     }
1258 
1259   return run;
1260 }
1261 
1262 /*  Compose interface functions  */
1263 
1264 static gboolean
check_gray(gint32 image_id,gint32 drawable_id,gpointer data)1265 check_gray (gint32   image_id,
1266             gint32   drawable_id,
1267             gpointer data)
1268 
1269 {
1270   return ((gimp_image_base_type (image_id) == GIMP_GRAY) &&
1271           (gimp_image_width  (image_id) == composeint.width) &&
1272           (gimp_image_height (image_id) == composeint.height));
1273 }
1274 
1275 static void
check_response(GtkWidget * dialog,gint response,gpointer data)1276 check_response (GtkWidget *dialog,
1277                 gint       response,
1278                 gpointer   data)
1279 {
1280   switch (response)
1281     {
1282     case GTK_RESPONSE_OK:
1283       {
1284         gint     i;
1285         gint     nb = 0;
1286         gboolean has_image = FALSE;
1287 
1288         nb = compose_dsc[composeint.compose_idx].num_images;
1289 
1290         for (i = 0; i < nb; i++)
1291           {
1292             if (composeint.selected[i].is_ID)
1293               {
1294                 has_image = TRUE;
1295                 break;
1296               }
1297           }
1298 
1299         if (! has_image)
1300           {
1301             GtkWidget *d;
1302 
1303             g_signal_stop_emission_by_name (dialog, "response");
1304             d = gtk_message_dialog_new (GTK_WINDOW (dialog),
1305                                         GTK_DIALOG_DESTROY_WITH_PARENT |
1306                                         GTK_DIALOG_MODAL,
1307                                         GTK_MESSAGE_ERROR,
1308                                         GTK_BUTTONS_CLOSE,
1309                                         _("At least one image is needed to compose"));
1310 
1311             gtk_dialog_run (GTK_DIALOG (d));
1312             gtk_widget_destroy (d);
1313           }
1314       }
1315       break;
1316 
1317     default:
1318       break;
1319     }
1320 }
1321 
1322 static void
combo_callback(GimpIntComboBox * widget,gpointer data)1323 combo_callback (GimpIntComboBox *widget,
1324                 gpointer         data)
1325 {
1326   gint id;
1327   gint n;
1328 
1329   gimp_int_combo_box_get_active (GIMP_INT_COMBO_BOX (widget), &id);
1330   n = GPOINTER_TO_INT (data);
1331 
1332   if (id == -1)
1333     {
1334       gtk_widget_set_sensitive (composeint.color_scales[n], TRUE);
1335       gtk_widget_set_sensitive (composeint.color_spins[n],  TRUE);
1336 
1337       composeint.selected[n].is_ID    = FALSE;
1338       composeint.selected[n].comp.val =
1339           gtk_range_get_value (GTK_RANGE (composeint.color_scales[n]));
1340     }
1341   else
1342     {
1343       gtk_widget_set_sensitive (composeint.color_scales[n], FALSE);
1344       gtk_widget_set_sensitive (composeint.color_spins[n],  FALSE);
1345 
1346       composeint.selected[n].is_ID   = TRUE;
1347       composeint.selected[n].comp.ID = id;
1348     }
1349 }
1350 
1351 static void
scale_callback(GtkAdjustment * adj,ComposeInput * input)1352 scale_callback (GtkAdjustment *adj,
1353                 ComposeInput  *input)
1354 {
1355   input->comp.val = gtk_adjustment_get_value (adj);
1356 }
1357 
1358 static void
type_combo_callback(GimpIntComboBox * combo,gpointer data)1359 type_combo_callback (GimpIntComboBox *combo,
1360                      gpointer         data)
1361 {
1362   if (gimp_int_combo_box_get_active (combo, &composeint.compose_idx))
1363     {
1364       gboolean combo4;
1365       gboolean scale4;
1366       gint     compose_idx;
1367       gint     j;
1368 
1369       compose_idx = composeint.compose_idx;
1370 
1371       for (j = 0; j < MAX_COMPOSE_IMAGES; j++)
1372         {
1373           GtkWidget   *label = composeint.channel_label[j];
1374           GtkWidget   *image = composeint.channel_icon[j];
1375           const gchar *text  = compose_dsc[compose_idx].components[j].name;
1376           const gchar *icon  = compose_dsc[compose_idx].components[j].icon;
1377 
1378           gtk_label_set_text_with_mnemonic (GTK_LABEL (label),
1379                                             text ? gettext (text) : "");
1380 
1381           if (icon)
1382             {
1383               gtk_image_set_from_icon_name (GTK_IMAGE (image),
1384                                             icon, GTK_ICON_SIZE_BUTTON);
1385               gtk_widget_show (image);
1386             }
1387           else
1388             {
1389               gtk_image_clear (GTK_IMAGE (image));
1390               gtk_widget_hide (image);
1391             }
1392         }
1393 
1394       /* Set sensitivity of last menu */
1395       combo4 = (compose_dsc[compose_idx].num_images == 4);
1396       gtk_widget_set_sensitive (composeint.channel_menu[3], combo4);
1397 
1398       scale4 = combo4 && !composeint.selected[3].is_ID;
1399       gtk_widget_set_sensitive (composeint.color_scales[3], scale4);
1400       gtk_widget_set_sensitive (composeint.color_spins[3], scale4);
1401     }
1402 }
1403