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