compose.c 44.4 KB
Newer Older
1
/* GIMP - The GNU Image Manipulation Program
Elliot Lee's avatar
Elliot Lee committed
2
 * Copyright (C) 1995 Spencer Kimball and Peter Mattis
3
 *
4 5
 * Compose plug-in (C) 1997,1999 Peter Kirchgessner
 * e-mail: peter@kirchgessner.net, WWW: http://www.kirchgessner.net
Elliot Lee's avatar
Elliot Lee committed
6
 *
7
 * This program is free software: you can redistribute it and/or modify
Elliot Lee's avatar
Elliot Lee committed
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
Elliot Lee's avatar
Elliot Lee committed
10 11 12 13 14 15 16 17
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
18
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
Elliot Lee's avatar
Elliot Lee committed
19 20 21 22 23 24
 */

/*
 * This plug-in composes RGB-images from several types of channels
 */

25
/*  Lab colorspace support originally written by Alexey Dyachenko,
26
 *  merged into the official plug-in by Sven Neumann.
27 28 29
 *
 *  Support for channels empty or filled with a single mask value
 *  added by Sylvain FORET.
Elliot Lee's avatar
Elliot Lee committed
30
 */
31

32 33 34 35 36
/*
 * All redundant _256 versions of YCbCr* are here only for compatibility .
 * They can be dropped for GIMP 3.0
 */

37
#include "config.h"
Elliot Lee's avatar
Elliot Lee committed
38 39

#include <string.h>
40

41 42 43
#include <libgimp/gimp.h>
#include <libgimp/gimpui.h>

44 45
#include "libgimp/stdplugins-intl.h"

46

47 48 49 50
#define COMPOSE_PROC          "plug-in-compose"
#define DRAWABLE_COMPOSE_PROC "plug-in-drawable-compose"
#define RECOMPOSE_PROC        "plug-in-recompose"
#define PLUG_IN_BINARY        "compose"
51
#define PLUG_IN_ROLE          "gimp-compose"
52

53 54
/* Maximum number of images to compose */
#define MAX_COMPOSE_IMAGES 4
55

56 57 58 59 60 61 62 63 64 65
typedef struct
{
  union
    {
      gint32 ID;  /* Image ID of input images or drawable */
      guchar val; /* Mask value to compose with */
    } comp;
  gboolean is_ID;
} ComposeInput;

66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82
/* Description of a component */
typedef struct
{
  const gchar    *babl_name;
  const gchar    *name;
  const gchar    *icon;
  const float     range_min;      /* val min of the component */
  const float     range_max;      /* val max of the component */
  const gboolean  is_perceptual;  /* Take the componenent from an Y' or Y buffer */
} COMPONENT_DSC;

/* Description of a composition */
typedef struct
{
  const gchar         *babl_model;
  const gchar         *compose_type;  /*  Type of composition ("RGB", "RGBA",...)  */
  gint                 num_images;    /*  Number of input images needed            */
83
                                      /*  Channel information                     */
84 85 86 87 88
  const COMPONENT_DSC  components[MAX_COMPOSE_IMAGES];
  const gchar         *filename;      /*  Name of new image                        */

} COMPOSE_DSC;

89

Elliot Lee's avatar
Elliot Lee committed
90 91
/* Declare local functions
 */
92 93 94 95 96 97
static void      query                  (void);
static void      run                    (const gchar     *name,
                                         gint            nparams,
                                         const GimpParam *param,
                                         gint            *nreturn_vals,
                                         GimpParam      **return_vals);
98

99 100 101
static void      cpn_affine_transform   (GeglBuffer      *buffer,
                                         gdouble          min,
                                         gdouble          max);
Elliot Lee's avatar
Elliot Lee committed
102

103 104 105 106 107
static void fill_buffer_from_components (GeglBuffer      *temp[MAX_COMPOSE_IMAGES],
                                         GeglBuffer      *dst,
                                         gint             num_cpn,
                                         ComposeInput    *inputs,
                                         gdouble          mask_vals[MAX_COMPOSE_IMAGES]);
Elliot Lee's avatar
Elliot Lee committed
108

109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152
static void      perform_composition    (COMPOSE_DSC      curr_compose_dsc,
                                         GeglBuffer      *buffer_src[MAX_COMPOSE_IMAGES],
                                         GeglBuffer      *buffer_dst,
                                         ComposeInput    *inputs,
                                         gint             num_images);

static gint32    compose                (const gchar     *compose_type,
                                         ComposeInput    *inputs,
                                         gboolean         compose_by_drawable);

static gint32    create_new_image       (const gchar     *filename,
                                         guint            width,
                                         guint            height,
                                         GimpImageType    gdtype,
                                         GimpPrecision    precision,
                                         gint32          *layer_ID,
                                         GeglBuffer     **drawable);

static gboolean  compose_dialog         (const gchar     *compose_type,
                                         gint32           drawable_ID);

static gboolean  check_gray             (gint32           image_id,
                                         gint32           drawable_id,
                                         gpointer         data);

static void      combo_callback         (GimpIntComboBox *cbox,
                                         gpointer         data);

static void      scale_callback         (GtkAdjustment   *adj,
                                         ComposeInput    *input);

static void      check_response         (GtkWidget       *dialog,
                                         gint             response,
                                         gpointer         data);

static void      type_combo_callback    (GimpIntComboBox *combo,
                                         gpointer         data);



/* Decompositions availables.
 * All the following values have to be kept in sync with those of decompose.c
 */

153 154 155 156
#define CPN_RGBA_R { "R", N_("_Red:"),   GIMP_ICON_CHANNEL_RED, 0.0, 1.0, FALSE}
#define CPN_RGBA_G { "G", N_("_Green:"), GIMP_ICON_CHANNEL_GREEN, 0.0, 1.0, FALSE}
#define CPN_RGBA_B { "B", N_("_Blue:"),  GIMP_ICON_CHANNEL_BLUE, 0.0, 1.0, FALSE}
#define CPN_RGBA_A { "A", N_("_Alpha:"), GIMP_ICON_CHANNEL_ALPHA, 0.0, 1.0, TRUE}
157

158 159 160
#define CPN_HSV_H  { "hue",        N_("_Hue:"),        NULL, 0.0, 1.0, TRUE}
#define CPN_HSV_S  { "saturation", N_("_Saturation:"), NULL, 0.0, 1.0, TRUE}
#define CPN_HSV_V  { "value",      N_("_Value:"),      NULL, 0.0, 1.0, TRUE}
161

162 163 164
#define CPN_HSL_H  { "hue",        N_("_Hue:"),        NULL, 0.0, 1.0, TRUE}
#define CPN_HSL_S  { "saturation", N_("_Saturation:"), NULL, 0.0, 1.0, TRUE}
#define CPN_HSL_L  { "lightness",  N_("_Lightness:"),  NULL, 0.0, 1.0, TRUE}
165

166 167 168 169
#define CPN_CMYK_C { "cyan",    N_("_Cyan:"),    NULL, 0.0, 1.0, TRUE}
#define CPN_CMYK_M { "magenta", N_("_Magenta:"), NULL, 0.0, 1.0, TRUE}
#define CPN_CMYK_Y { "yellow",  N_("_Yellow:"),  NULL, 0.0, 1.0, TRUE}
#define CPN_CMYK_K { "key",     N_("_Black:"),   NULL, 0.0, 1.0, TRUE}
170

171 172 173
#define CPN_CMY_C  { "cyan",    N_("_Cyan:"),    NULL, 0.0, 1.0, TRUE}
#define CPN_CMY_M  { "magenta", N_("_Magenta:"), NULL, 0.0, 1.0, TRUE}
#define CPN_CMY_Y  { "yellow",  N_("_Yellow:"),  NULL, 0.0, 1.0, TRUE}
174

175 176 177
#define CPN_LAB_L  { "CIE L", N_("_L:"), NULL, 0.0, 100.0, TRUE}
#define CPN_LAB_A  { "CIE a", N_("_A:"), NULL, -127.5, 127.5, TRUE}
#define CPN_LAB_B  { "CIE b", N_("_B:"), NULL, -127.5, 127.5, TRUE}
178

179 180 181
#define CPN_LCH_L  { "CIE L",     N_("_L"), NULL, 0.0, 100.0, TRUE}
#define CPN_LCH_C  { "CIE C(ab)", N_("_C"), NULL, 0.0, 200.0, TRUE}
#define CPN_LCH_H  { "CIE H(ab)", N_("_H"), NULL, 0.0, 360.0, TRUE}
182

183 184 185
#define CPN_YCBCR_Y  { "Y'", N_("_Luma y470:"),      NULL,  0.0, 1.0, TRUE }
#define CPN_YCBCR_CB { "Cb", N_("_Blueness cb470:"), NULL, -0.5, 0.5, TRUE }
#define CPN_YCBCR_CR { "Cr", N_("_Redness cr470:"),  NULL, -0.5, 0.5, TRUE }
186

187 188 189
#define CPN_YCBCR709_Y  { "Y'", N_("_Luma y709:"),      NULL,  0.0, 1.0, TRUE }
#define CPN_YCBCR709_CB { "Cb", N_("_Blueness cb709:"), NULL, -0.5, 0.5, TRUE }
#define CPN_YCBCR709_CR { "Cr", N_("_Redness cr709:"),  NULL, -0.5, 0.5, TRUE }
Elliot Lee's avatar
Elliot Lee committed
190

191

192 193
static COMPOSE_DSC compose_dsc[] =
{
194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244
  { "RGB",
    N_("RGB"), 3,
    { CPN_RGBA_R,
      CPN_RGBA_G,
      CPN_RGBA_B },
    "rgb-compose" },

  { "RGBA",
    N_("RGBA"), 4,
    { CPN_RGBA_R,
      CPN_RGBA_G,
      CPN_RGBA_B,
      CPN_RGBA_A },
    "rgba-compose" },

  { "HSV",
    N_("HSV"), 3,
    { CPN_HSV_H,
      CPN_HSV_S,
      CPN_HSV_V },
    "hsv-compose" },

  { "HSL",
    N_("HSL"), 3,
    { CPN_HSL_H,
      CPN_HSL_S,
      CPN_HSL_L },
    "hsl-compose" },

  { "CMY",
    N_("CMY"), 3,
    { CPN_CMY_C,
      CPN_CMY_M,
      CPN_CMY_Y },
    "cmy-compose" },

  { "CMYK",
    N_("CMYK"), 4,
    { CPN_CMYK_C,
      CPN_CMYK_M,
      CPN_CMYK_Y,
      CPN_CMYK_K },
    "cmyk-compose" },

  { "CIE Lab",
    N_("LAB"), 3,
    { CPN_LAB_L,
      CPN_LAB_A,
      CPN_LAB_B },
    "lab-compose" },

245 246 247 248 249 250 251
  { "CIE LCH(ab)",
    N_("LCH"), 3,
    { CPN_LCH_L,
      CPN_LCH_C,
      CPN_LCH_H },
    "lch-compose" },

252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277
  { "Y'CbCr",
    N_("YCbCr_ITU_R470"), 3,
    { CPN_YCBCR_Y,
      CPN_YCBCR_CB,
      CPN_YCBCR_CR },
    "ycbcr470-compose" },

  { "Y'CbCr709",
    N_("YCbCr_ITU_R709"), 3,
    { CPN_YCBCR709_Y,
      CPN_YCBCR709_CB,
      CPN_YCBCR709_CR },
    "ycbcr709-compose" },

  { "Y'CbCr",
    N_("YCbCr_ITU_R470_256"), 3,
    { CPN_YCBCR_Y,
      CPN_YCBCR_CB,
      CPN_YCBCR_CR },
    "ycbcr470F-compose" },

  { "Y'CbCr709",
    N_("YCbCr_ITU_R709_256"), 3,
    { CPN_YCBCR709_Y,
      CPN_YCBCR709_CB,
      CPN_YCBCR709_CR },
278
    "ycbcr709F-compose" }
Elliot Lee's avatar
Elliot Lee committed
279 280 281
};


282 283
typedef struct
{
284 285 286 287
  ComposeInput inputs[MAX_COMPOSE_IMAGES];  /* Image IDs or mask value of input */
  gchar        compose_type[32];            /* type of composition */
  gboolean     do_recompose;
  gint32       source_layer_ID;             /* for recomposing */
Elliot Lee's avatar
Elliot Lee committed
288 289 290
} ComposeVals;

/* Dialog structure */
291 292
typedef struct
{
293
  gint          width, height;                            /* Size of selected image */
294

295 296 297 298 299
  GtkWidget    *channel_label[MAX_COMPOSE_IMAGES];        /* The labels to change */
  GtkWidget    *channel_icon[MAX_COMPOSE_IMAGES];         /* The icons  */
  GtkWidget    *channel_menu[MAX_COMPOSE_IMAGES];         /* The menus */
  GtkWidget    *color_scales[MAX_COMPOSE_IMAGES];         /* The values color scales */
  GtkWidget    *color_spins[MAX_COMPOSE_IMAGES];          /* The values spin buttons */
Elliot Lee's avatar
Elliot Lee committed
300

301
  ComposeInput  selected[MAX_COMPOSE_IMAGES];             /* Image Ids or mask values from menus */
302

303
  gint          compose_idx;                              /* Compose type */
Elliot Lee's avatar
Elliot Lee committed
304 305
} ComposeInterface;

306
const GimpPlugInInfo PLUG_IN_INFO =
Elliot Lee's avatar
Elliot Lee committed
307
{
308 309 310 311
  NULL,  /* init_proc  */
  NULL,  /* quit_proc  */
  query, /* query_proc */
  run,   /* run_proc   */
Elliot Lee's avatar
Elliot Lee committed
312 313 314 315
};

static ComposeVals composevals =
{
316 317 318 319
  {{{ 0 }}}, /* Image IDs of images to compose or mask values */
  "rgb",     /* Type of composition */
  FALSE,     /* Do recompose */
  -1         /* source layer ID */
Elliot Lee's avatar
Elliot Lee committed
320 321 322 323
};

static ComposeInterface composeint =
{
324 325 326 327 328 329 330
  0, 0,      /* width, height */
  { NULL },  /* Label Widgets */
  { NULL },  /* Icon Widgets */
  { NULL },  /* Menu Widgets */
  { NULL },  /* Color Scale Widgets */
  { NULL },  /* Color Spin Widgets */
  {{{ 0 }}}, /* Image Ids or mask values from menus */
331
  0          /* Compose type */
Elliot Lee's avatar
Elliot Lee committed
332 333 334 335 336
};


MAIN ()

337

Elliot Lee's avatar
Elliot Lee committed
338
static void
339
query (void)
Elliot Lee's avatar
Elliot Lee committed
340
{
341
  static GimpParamDef args[] =
Elliot Lee's avatar
Elliot Lee committed
342
  {
343
    { GIMP_PDB_INT32,    "run-mode",     "The run mode { RUN-INTERACTIVE (0), RUN-NONINTERACTIVE (1) }" },
344 345 346 347 348
    { GIMP_PDB_IMAGE,    "image1",       "First input image" },
    { GIMP_PDB_DRAWABLE, "drawable",     "Input drawable (not used)" },
    { GIMP_PDB_IMAGE,    "image2",       "Second input image" },
    { GIMP_PDB_IMAGE,    "image3",       "Third input image" },
    { GIMP_PDB_IMAGE,    "image4",       "Fourth input image" },
349
    { GIMP_PDB_STRING,   "compose-type", NULL }
Elliot Lee's avatar
Elliot Lee committed
350
  };
351

352
  static const GimpParamDef return_vals[] =
Elliot Lee's avatar
Elliot Lee committed
353
  {
Sven Neumann's avatar
Sven Neumann committed
354
    { GIMP_PDB_IMAGE, "new_image", "Output image" }
Elliot Lee's avatar
Elliot Lee committed
355 356
  };

357
  static GimpParamDef drw_args[] =
358
  {
359
    { GIMP_PDB_INT32,    "run-mode",     "The run mode { RUN-INTERACTIVE (0), RUN-NONINTERACTIVE (1) }" },
360 361 362 363 364
    { GIMP_PDB_IMAGE,    "image1",       "First input image (not used)" },
    { GIMP_PDB_DRAWABLE, "drawable1",    "First input drawable" },
    { GIMP_PDB_DRAWABLE, "drawable2",    "Second input drawable" },
    { GIMP_PDB_DRAWABLE, "drawable3",    "Third input drawable" },
    { GIMP_PDB_DRAWABLE, "drawable4",    "Fourth input drawable" },
365
    { GIMP_PDB_STRING,   "compose-type", NULL }
366
  };
367

368
  static const GimpParamDef drw_return_vals[] =
369
  {
Sven Neumann's avatar
Sven Neumann committed
370
    { GIMP_PDB_IMAGE, "new_image", "Output image" }
371 372
  };

373
  static const GimpParamDef recompose_args[] =
374
  {
375
    { GIMP_PDB_INT32,    "run-mode", "The run mode { RUN-INTERACTIVE (0), RUN-NONINTERACTIVE (1) }" },
376 377 378 379
    { GIMP_PDB_IMAGE,    "image",    "Image to recompose from" },
    { GIMP_PDB_DRAWABLE, "drawable", "Not used" },
  };

380
  GString *type_desc;
381
  gint     i;
382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398

  type_desc = g_string_new ("What to compose: ");
  g_string_append_c (type_desc, '"');
  g_string_append (type_desc, compose_dsc[0].compose_type);
  g_string_append_c (type_desc, '"');

  for (i = 1; i < G_N_ELEMENTS (compose_dsc); i++)
    {
      g_string_append (type_desc, ", ");
      g_string_append_c (type_desc, '"');
      g_string_append (type_desc, compose_dsc[i].compose_type);
      g_string_append_c (type_desc, '"');
    }

  args[6].description = type_desc->str;
  drw_args[6].description = type_desc->str;

399
  gimp_install_procedure (COMPOSE_PROC,
David Odin's avatar
David Odin committed
400 401 402 403 404 405 406 407 408 409
                          N_("Create an image using multiple gray images as color channels"),
                          "This function creates a new image from "
                          "multiple gray images",
                          "Peter Kirchgessner",
                          "Peter Kirchgessner (peter@kirchgessner.net)",
                          "1997",
                          N_("C_ompose..."),
                          "GRAY*",
                          GIMP_PLUGIN,
                          G_N_ELEMENTS (args),
410
                          G_N_ELEMENTS (return_vals),
David Odin's avatar
David Odin committed
411
                          args, return_vals);
412

413
  gimp_plugin_menu_register (COMPOSE_PROC, "<Image>/Colors/Components");
414

415
  gimp_install_procedure (DRAWABLE_COMPOSE_PROC,
David Odin's avatar
David Odin committed
416 417 418 419 420 421 422 423 424 425
                          "Compose an image from multiple drawables of gray images",
                          "This function creates a new image from "
                          "multiple drawables of gray images",
                          "Peter Kirchgessner",
                          "Peter Kirchgessner (peter@kirchgessner.net)",
                          "1998",
                          NULL,   /* It is not available in interactive mode */
                          "GRAY*",
                          GIMP_PLUGIN,
                          G_N_ELEMENTS (drw_args),
426
                          G_N_ELEMENTS (drw_return_vals),
David Odin's avatar
David Odin committed
427
                          drw_args, drw_return_vals);
428

429
  gimp_install_procedure (RECOMPOSE_PROC,
David Odin's avatar
David Odin committed
430 431 432
                          N_("Recompose an image that was previously decomposed"),
                          "This function recombines the grayscale layers produced "
                          "by Decompose into a single RGB or RGBA layer, and "
433 434
                          "replaces the originally decomposed layer with the "
                          "result.",
David Odin's avatar
David Odin committed
435 436 437 438 439 440 441 442
                          "Bill Skaggs",
                          "Bill Skaggs",
                          "2004",
                          N_("R_ecompose"),
                          "GRAY*",
                          GIMP_PLUGIN,
                          G_N_ELEMENTS (recompose_args), 0,
                          recompose_args, NULL);
443

444
  gimp_plugin_menu_register (RECOMPOSE_PROC, "<Image>/Colors/Components");
445 446

  g_string_free (type_desc, TRUE);
Elliot Lee's avatar
Elliot Lee committed
447 448
}

449

Elliot Lee's avatar
Elliot Lee committed
450
static void
451 452 453 454 455
run (const gchar      *name,
     gint              nparams,
     const GimpParam  *param,
     gint             *nreturn_vals,
     GimpParam       **return_vals)
Elliot Lee's avatar
Elliot Lee committed
456
{
457
  static GimpParam  values[2];
Sven Neumann's avatar
Sven Neumann committed
458
  GimpPDBStatusType status = GIMP_PDB_SUCCESS;
459
  GimpRunMode       run_mode;
460 461
  gint32            image_ID;
  gint32            drawable_ID = -1;
462
  gint              compose_by_drawable;
463
  gint              i;
Elliot Lee's avatar
Elliot Lee committed
464

465
  INIT_I18N ();
466
  gegl_init (NULL, NULL);
467

Elliot Lee's avatar
Elliot Lee committed
468
  run_mode = param[0].data.d_int32;
469
  compose_by_drawable = (strcmp (name, DRAWABLE_COMPOSE_PROC) == 0);
Elliot Lee's avatar
Elliot Lee committed
470

471
  *nreturn_vals = 1;
472
  *return_vals  = values;
Elliot Lee's avatar
Elliot Lee committed
473

474
  values[0].type          = GIMP_PDB_STATUS;
Elliot Lee's avatar
Elliot Lee committed
475
  values[0].data.d_status = status;
476 477
  values[1].type          = GIMP_PDB_IMAGE;
  values[1].data.d_int32  = -1;
Elliot Lee's avatar
Elliot Lee committed
478

479
  if (strcmp (name, RECOMPOSE_PROC) == 0)
Elliot Lee's avatar
Elliot Lee committed
480
    {
481 482
      GimpParasite *parasite = gimp_image_get_parasite (param[1].data.d_image,
                                                        "decompose-data");
483

484
      if (! parasite)
485
        {
486 487 488
          g_message (_("You can only run 'Recompose' if the active image "
                       "was originally produced by 'Decompose'."));
          status = GIMP_PDB_EXECUTION_ERROR;
489
        }
490
      else
491
        {
492 493 494
          gint nret;

          nret = sscanf (gimp_parasite_data (parasite),
495
                         "source=%d type=%31s %d %d %d %d",
496 497 498 499 500 501
                         &composevals.source_layer_ID,
                         composevals.compose_type,
                         &composevals.inputs[0].comp.ID,
                         &composevals.inputs[1].comp.ID,
                         &composevals.inputs[2].comp.ID,
                         &composevals.inputs[3].comp.ID);
502

503
          gimp_parasite_free (parasite);
Elliot Lee's avatar
Elliot Lee committed
504

505 506
          for (i = 0; i < MAX_COMPOSE_IMAGES; i++)
            composevals.inputs[i].is_ID = TRUE;
507

508 509 510 511 512 513 514 515 516 517 518 519
          if (nret < 5)
            {
              g_message (_("Error scanning 'decompose-data' parasite: "
                           "too few layers found"));
              status = GIMP_PDB_EXECUTION_ERROR;
            }
          else
            {
              composevals.do_recompose = TRUE;
              compose_by_drawable = TRUE;
            }
        }
520 521 522 523
    }
  else
    {
      composevals.do_recompose = FALSE;
Elliot Lee's avatar
Elliot Lee committed
524

525 526 527 528
      switch (run_mode)
        {
        case GIMP_RUN_INTERACTIVE:
          /*  Possibly retrieve data  */
529
          gimp_get_data (name, &composevals);
Elliot Lee's avatar
Elliot Lee committed
530

531 532
          compose_by_drawable = TRUE;

533
          /* The dialog is now drawable based. Get a drawable-ID of the image */
534
          if (strcmp (name, COMPOSE_PROC) == 0)
535 536
            {
              gint32 *layer_list;
537
              gint    nlayers;
538

539 540
              layer_list = gimp_image_get_layers (param[1].data.d_int32,
                                                  &nlayers);
541 542 543 544 545 546
              if ((layer_list == NULL) || (nlayers <= 0))
                {
                  g_message (_("Could not get layers for image %d"),
                             (gint) param[1].data.d_int32);
                  return;
                }
547

548 549 550 551 552 553 554 555 556 557 558
              drawable_ID = layer_list[0];
              g_free (layer_list);
            }
          else
            {
              drawable_ID = param[2].data.d_int32;
            }

          /*  First acquire information with a dialog  */
          if (! compose_dialog (composevals.compose_type, drawable_ID))
            return;
Elliot Lee's avatar
Elliot Lee committed
559

560 561 562 563
          break;

        case GIMP_RUN_NONINTERACTIVE:
          /*  Make sure all the arguments are there!  */
564
          if (nparams < 7)
565 566 567 568 569
            {
              status = GIMP_PDB_CALLING_ERROR;
            }
          else
            {
570 571 572 573 574 575 576
              composevals.inputs[0].comp.ID = (compose_by_drawable ?
                                               param[2].data.d_int32 :
                                               param[1].data.d_int32);
              composevals.inputs[1].comp.ID = param[3].data.d_int32;
              composevals.inputs[2].comp.ID = param[4].data.d_int32;
              composevals.inputs[3].comp.ID = param[5].data.d_int32;

577 578 579
              strncpy (composevals.compose_type, param[6].data.d_string,
                       sizeof (composevals.compose_type));
              composevals.compose_type[sizeof (composevals.compose_type)-1] = '\0';
580 581 582 583 584

              for (i = 0; i < MAX_COMPOSE_IMAGES; i++)
                {
                  if (composevals.inputs[i].comp.ID == -1)
                    {
585 586
                      composevals.inputs[i].is_ID = FALSE;
                      composevals.inputs[i].comp.val = 0;
587 588
                    }
                  else
589 590 591
                    {
                      composevals.inputs[i].is_ID = TRUE;
                    }
592
                }
593 594 595 596 597 598
            }
          break;

        case GIMP_RUN_WITH_LAST_VALS:
          /*  Possibly retrieve data  */
          gimp_get_data (name, &composevals);
599 600

          compose_by_drawable = TRUE;
601 602 603 604 605
          break;

        default:
          break;
        }
Elliot Lee's avatar
Elliot Lee committed
606 607
    }

Sven Neumann's avatar
Sven Neumann committed
608
  if (status == GIMP_PDB_SUCCESS)
Elliot Lee's avatar
Elliot Lee committed
609
    {
610
      gimp_progress_init (_("Composing"));
Elliot Lee's avatar
Elliot Lee committed
611

612
      image_ID = compose (composevals.compose_type,
613
                          composevals.inputs,
614
                          compose_by_drawable);
Elliot Lee's avatar
Elliot Lee committed
615

616
      if (image_ID < 0)
David Odin's avatar
David Odin committed
617 618 619
        {
          status = GIMP_PDB_EXECUTION_ERROR;
        }
Elliot Lee's avatar
Elliot Lee committed
620
      else
David Odin's avatar
David Odin committed
621 622
        {
          values[1].data.d_int32 = image_ID;
623 624 625 626 627 628 629 630 631

          if (composevals.do_recompose)
            {
              gimp_displays_flush ();
            }
          else
            {
              gimp_image_undo_enable (image_ID);
              gimp_image_clean_all (image_ID);
632

633 634 635
              if (run_mode != GIMP_RUN_NONINTERACTIVE)
                gimp_display_new (image_ID);
            }
David Odin's avatar
David Odin committed
636
        }
Elliot Lee's avatar
Elliot Lee committed
637 638

      /*  Store data  */
Sven Neumann's avatar
Sven Neumann committed
639
      if (run_mode == GIMP_RUN_INTERACTIVE)
640
        gimp_set_data (name, &composevals, sizeof (ComposeVals));
Elliot Lee's avatar
Elliot Lee committed
641 642
    }

643 644
  *nreturn_vals = composevals.do_recompose ? 1 : 2;

Elliot Lee's avatar
Elliot Lee committed
645 646 647
  values[0].data.d_status = status;
}

648
static void
649 650 651
cpn_affine_transform (GeglBuffer *buffer,
                      gdouble     min,
                      gdouble     max)
652 653
{
  GeglBufferIterator *gi;
654 655
  const gdouble       scale  = max - min;
  const gdouble       offset = min;
656 657 658 659 660

  /* We want to scale values linearly, regardless of the format of the buffer */
  gegl_buffer_set_format (buffer, babl_format ("Y double"));

  gi = gegl_buffer_iterator_new (buffer, NULL, 0, NULL,
661
                                 GEGL_ACCESS_READWRITE, GEGL_ABYSS_NONE, 1);
662 663 664

  while (gegl_buffer_iterator_next (gi))
    {
665
      gdouble *data = gi->items[0].data;
666
      guint    k;
667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682

      for (k = 0; k < gi->length; k++)
        {
          data[k] = data[k] * scale + offset;
        }
    }
}

static void
fill_buffer_from_components (GeglBuffer   *temp[MAX_COMPOSE_IMAGES],
                             GeglBuffer   *dst,
                             gint          num_cpn,
                             ComposeInput *inputs,
                             gdouble       mask_vals[MAX_COMPOSE_IMAGES])
{
  GeglBufferIterator *gi;
683
  gint                j;
684 685

  gi = gegl_buffer_iterator_new (dst, NULL, 0, NULL,
686
                                 GEGL_ACCESS_WRITE, GEGL_ABYSS_NONE, 10);
687 688 689 690 691

  for (j = 0; j < num_cpn; j++)
    {
      if (inputs[j].is_ID)
        gegl_buffer_iterator_add (gi, temp[j], NULL, 0, NULL,
692
                                  GEGL_ACCESS_READ, GEGL_ABYSS_NONE);
693 694 695 696
    }

  while (gegl_buffer_iterator_next (gi))
    {
697
      gdouble *src_data[MAX_COMPOSE_IMAGES];
698
      gdouble *dst_data = (gdouble*) gi->items[0].data;
699
      gulong   k, count;
700 701 702 703

      count = 1;
      for (j = 0; j < num_cpn; j++)
        if (inputs[j].is_ID)
704
          src_data[j] = (gdouble*) gi->items[count++].data;
705 706 707 708 709 710

      for (k = 0; k < gi->length; k++)
        {
          gulong pos = k * num_cpn;

          for (j = 0; j < num_cpn; j++)
711 712 713 714 715 716
            {
              if (inputs[j].is_ID)
                dst_data[pos+j] = src_data[j][k];
              else
                dst_data[pos+j] = mask_vals[j];
            }
717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763
        }
    }
}

static void
perform_composition (COMPOSE_DSC   curr_compose_dsc,
                     GeglBuffer   *buffer_src[MAX_COMPOSE_IMAGES],
                     GeglBuffer   *buffer_dst,
                     ComposeInput *inputs,
                     gint          num_images)
{
  const Babl          *dst_format;
  GeglBuffer          *temp[MAX_COMPOSE_IMAGES];
  GeglBuffer          *dst_temp;
  const GeglRectangle *extent = NULL;

  const COMPONENT_DSC *components;
  gdouble              mask_vals[MAX_COMPOSE_IMAGES];
  gint                 i;

  components = curr_compose_dsc.components;

  /* Get all individual components in gray buffers */
  for (i = 0; i < num_images; i++)
    {
      COMPONENT_DSC  cpn_dsc = components[i];
      const Babl    *gray_format;

      if (cpn_dsc.is_perceptual)
        gray_format = babl_format ("Y' double");
      else
        gray_format = babl_format ("Y double");

      if (! inputs[i].is_ID)
        {
          const Babl *fish = babl_fish (babl_format ("Y' u8"), gray_format);

          babl_process (fish, &inputs[i].comp.val, &mask_vals[i], 1);

          mask_vals[i] = mask_vals[i] * (cpn_dsc.range_max - cpn_dsc.range_min) + cpn_dsc.range_min;
        }
      else
        {
          extent = gegl_buffer_get_extent (buffer_src[i]);

          temp[i] = gegl_buffer_new (extent, gray_format);

764
          gegl_buffer_copy (buffer_src[i], NULL, GEGL_ABYSS_NONE, temp[i], NULL);
765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789

          if (cpn_dsc.range_min != 0.0 || cpn_dsc.range_max != 1.0)
            cpn_affine_transform (temp[i], cpn_dsc.range_min, cpn_dsc.range_max);
        }

      gimp_progress_update ((gdouble) i / (gdouble) (num_images + 1.0));
    }

  dst_format = babl_format_new (babl_model (curr_compose_dsc.babl_model),
                                babl_type ("double"),
                                babl_component (components[0].babl_name),
                                num_images > 1 ? babl_component (components[1].babl_name) : NULL,
                                num_images > 2 ? babl_component (components[2].babl_name) : NULL,
                                num_images > 3 ? babl_component (components[3].babl_name) : NULL,
                                NULL);

  /* extent is not NULL because there is at least one drawable */
  dst_temp = gegl_buffer_new (extent, dst_format);

  /* Gather all individual components in the dst_format buffer */
  fill_buffer_from_components (temp, dst_temp, num_images, inputs, mask_vals);

  gimp_progress_update ((gdouble) num_images / (gdouble) (num_images + 1.0));

  /* Copy back to the format GIMP wants (and perform the conversion in itself) */
790
  gegl_buffer_copy (dst_temp, NULL, GEGL_ABYSS_NONE, buffer_dst, NULL);
791 792 793 794 795 796 797

  for (i = 0; i< num_images; i++)
    if( inputs[i].is_ID)
      g_object_unref (temp[i]);

  g_object_unref (dst_temp);
}
Elliot Lee's avatar
Elliot Lee committed
798 799 800

/* Compose an image from several gray-images */
static gint32
801 802 803
compose (const gchar  *compose_type,
         ComposeInput *inputs,
         gboolean      compose_by_drawable)
804
{
805 806
  gint           width, height;
  gint           num_images, compose_idx;
807 808 809
  gint           i, j;
  gint           num_layers;
  gint32         layer_ID_dst, image_ID_dst;
810
  gint           first_ID;
811
  GimpImageType  gdtype_dst;
812 813
  GeglBuffer    *buffer_src[MAX_COMPOSE_IMAGES];
  GeglBuffer    *buffer_dst;
814
  GimpPrecision  precision;
815

Elliot Lee's avatar
Elliot Lee committed
816 817
  /* Search type of composing */
  compose_idx = -1;
818
  for (j = 0; j < G_N_ELEMENTS (compose_dsc); j++)
819
    {
820
      if (g_ascii_strcasecmp (compose_type, compose_dsc[j].compose_type) == 0)
821 822 823 824
        {
          compose_idx = j;
          break;
        }
825
    }
826

Elliot Lee's avatar
Elliot Lee committed
827
  if (compose_idx < 0)
828
    return -1;
829

Elliot Lee's avatar
Elliot Lee committed
830
  num_images = compose_dsc[compose_idx].num_images;
831

832 833 834 835 836 837 838 839 840 841
  /* Check that at least one image or one drawable is provided */
  first_ID = -1;
  for (i = 0; i < num_images; i++)
    {
      if (inputs[i].is_ID)
        {
          first_ID = i;
          break;
        }
    }
842

843 844
  if (-1 == first_ID)
    {
845
      g_message (_("At least one image is needed to compose"));
846 847 848
      return -1;
    }

849 850
  /* Check image sizes */
  if (compose_by_drawable)
Elliot Lee's avatar
Elliot Lee committed
851
    {
852 853
      gint32 first_image = gimp_item_get_image (inputs[first_ID].comp.ID);

854
      if (! gimp_item_is_valid (inputs[first_ID].comp.ID))
855
        {
856 857
          g_message (_("Specified layer %d not found"),
                     inputs[first_ID].comp.ID);
858 859 860
          return -1;
        }

861
      width  = gimp_drawable_width  (inputs[first_ID].comp.ID);
862
      height = gimp_drawable_height (inputs[first_ID].comp.ID);
863

864
      precision = gimp_image_get_precision (first_image);
865

866
      for (j = first_ID + 1; j < num_images; j++)
David Odin's avatar
David Odin committed
867
        {
868
          if (inputs[j].is_ID)
869
            {
870
              if (! gimp_item_is_valid (inputs[j].comp.ID))
871
                {
872 873
                  g_message (_("Specified layer %d not found"),
                             inputs[j].comp.ID);
874 875 876
                  return -1;
                }

877 878
              if ((width  != gimp_drawable_width  (inputs[j].comp.ID)) ||
                  (height != gimp_drawable_height (inputs[j].comp.ID)))
879 880 881 882 883
                {
                  g_message (_("Drawables have different size"));
                  return -1;
                }
            }
David Odin's avatar
David Odin committed
884
        }
885

886
      for (j = 0; j < num_images; j++)
887 888
        {
          if (inputs[j].is_ID)
889
            buffer_src[j] = gimp_drawable_get_buffer (inputs[j].comp.ID);
890
          else
891
            buffer_src[j] = NULL;
892
        }
Elliot Lee's avatar
Elliot Lee committed
893
    }
894
  else    /* Compose by image ID */
Elliot Lee's avatar
Elliot Lee committed
895
    {
896
      width  = gimp_image_width  (inputs[first_ID].comp.ID);
897
      height = gimp_image_height (inputs[first_ID].comp.ID);
898

899
      precision = gimp_image_get_precision (inputs[first_ID].comp.ID);
900

901
      for (j = first_ID + 1; j < num_images; j++)
David Odin's avatar
David Odin committed
902
        {
903 904 905 906 907 908 909 910 911
          if (inputs[j].is_ID)
            {
              if ((width  != gimp_image_width (inputs[j].comp.ID)) ||
                  (height != gimp_image_height (inputs[j].comp.ID)))
                {
                  g_message (_("Images have different size"));
                  return -1;
                }
            }
David Odin's avatar
David Odin committed
912
        }
913

914 915
      /* Get first layer/drawable for all input images */
      for (j = 0; j < num_images; j++)
David Odin's avatar
David Odin committed
916
        {
917 918
          if (inputs[j].is_ID)
            {
Sven Neumann's avatar
Sven Neumann committed
919
              gint32 *layers;
920 921

              /* Get first layer of image */
Sven Neumann's avatar
Sven Neumann committed
922 923 924
              layers = gimp_image_get_layers (inputs[j].comp.ID, &num_layers);

              if (! layers || (num_layers <= 0))
925 926 927 928 929 930
                {
                  g_message (_("Error in getting layer IDs"));
                  return -1;
                }

              /* Get drawable for layer */
931
              buffer_src[j] = gimp_drawable_get_buffer (layers[0]);
Sven Neumann's avatar
Sven Neumann committed
932
              g_free (layers);
933
            }
David Odin's avatar
David Odin committed
934
        }
935
    }
936

937 938 939 940 941
  /* Unless recomposing, create new image */
  if (composevals.do_recompose)
    {
      layer_ID_dst = composevals.source_layer_ID;

942
      if (! gimp_item_is_valid (layer_ID_dst))
943 944 945 946
        {
          g_message (_("Unable to recompose, source layer not found"));
          return -1;
        }
947

948
      image_ID_dst = gimp_item_get_image (layer_ID_dst);
949 950

      buffer_dst = gimp_drawable_get_shadow_buffer (layer_ID_dst);
951 952 953
    }
  else
    {
954
      gdtype_dst = ((babl_model (compose_dsc[compose_idx].babl_model) == babl_model ("RGBA")) ?
955
                    GIMP_RGBA_IMAGE : GIMP_RGB_IMAGE);
956 957

      image_ID_dst = create_new_image (compose_dsc[compose_idx].filename,
958 959
                                       width, height, gdtype_dst, precision,
                                       &layer_ID_dst, &buffer_dst);
960
    }
961 962 963 964 965

  if (! compose_by_drawable)
    {
      gdouble  xres, yres;

966
      gimp_image_get_resolution (inputs[first_ID].comp.ID, &xres, &yres);
967 968 969
      gimp_image_set_resolution (image_ID_dst, xres, yres);
    }

970 971 972 973 974
  perform_composition (compose_dsc[compose_idx],
                       buffer_src,
                       buffer_dst,
                       inputs,
                       num_images);
975

976
  gimp_progress_update (1.0);
977

Elliot Lee's avatar
Elliot Lee committed
978
  for (j = 0; j < num_images; j++)
979
    {
980
      if (inputs[j].is_ID)
981
        g_object_unref (buffer_src[j]);
982
    }
983

984
  g_object_unref (buffer_dst);
985 986 987 988

  if (composevals.do_recompose)
    gimp_drawable_merge_shadow (layer_ID_dst, TRUE);

989 990 991
  gimp_drawable_update (layer_ID_dst, 0, 0,
                        gimp_drawable_width (layer_ID_dst),
                        gimp_drawable_height (layer_ID_dst));
992

Elliot Lee's avatar
Elliot Lee committed
993 994 995 996 997 998
  return image_ID_dst;
}


/* Create an image. Sets layer_ID, drawable and rgn. Returns image_ID */
static gint32
999
create_new_image (const gchar    *filename,
1000 1001
                  guint           width,
                  guint           height,
Sven Neumann's avatar
Sven Neumann committed
1002
                  GimpImageType   gdtype,
1003
                  GimpPrecision   precision,
1004
                  gint32         *layer_ID,
1005
                  GeglBuffer    **buffer)
1006
{
1007
  gint32            image_ID;
Sven Neumann's avatar
Sven Neumann committed
1008
  GimpImageBaseType gitype;
1009

Sven Neumann's avatar
Sven Neumann committed
1010 1011 1012 1013
  if ((gdtype == GIMP_GRAY_IMAGE) || (gdtype == GIMP_GRAYA_IMAGE))
    gitype = GIMP_GRAY;
  else if ((gdtype == GIMP_INDEXED_IMAGE) || (gdtype == GIMP_INDEXEDA_IMAGE))
    gitype = GIMP_INDEXED;
1014
  else
Sven Neumann's avatar
Sven Neumann committed
1015
    gitype = GIMP_RGB;
1016

1017
  image_ID = gimp_image_new_with_precision (width, height, gitype, precision);
1018

1019
  gimp_image_undo_disable (image_ID);
1020
  gimp_image_set_filename (image_ID, filename);
1021

1022
  *layer_ID = gimp_layer_new (image_ID, _("Background"), width, height,
1023
                              gdtype,
1024 1025
                              100,
                              gimp_image_get_default_new_layer_mode (image_ID));
1026
  gimp_image_insert_layer (image_ID, *layer_ID, -1, 0);
1027

1028
  *buffer = gimp_drawable_get_buffer (*layer_ID);
Elliot Lee's avatar
Elliot Lee committed
1029

1030
  return image_ID;
Elliot Lee's avatar
Elliot Lee committed
1031 1032 1033
}


1034
static gboolean
1035 1036
compose_dialog (const gchar *compose_type,
                gint32       drawable_ID)
Elliot Lee's avatar
Elliot Lee committed
1037
{
1038 1039 1040 1041 1042 1043 1044
  GtkWidget    *dialog;
  GtkWidget    *main_vbox;
  GtkWidget    *frame;
  GtkWidget    *vbox;
  GtkWidget    *hbox;
  GtkWidget    *label;
  GtkWidget    *combo;
1045
  GtkWidget    *grid;
1046 1047 1048 1049 1050
  GtkSizeGroup *size_group;
  gint32       *layer_list;
  gint          nlayers;
  gint          j;
  gboolean      run;
Elliot Lee's avatar
Elliot Lee committed
1051 1052

  /* Check default compose type */
1053
  composeint.compose_idx = 0;
1054
  for (j = 0; j < G_N_ELEMENTS (compose_dsc); j++)
1055
    {
1056
      if (g_ascii_strcasecmp (compose_type, compose_dsc[j].compose_type) == 0)
1057
        {
1058
          composeint.compose_idx = j;
1059 1060
          break;
        }
1061
    }
1062

1063
  /* Save original image width/height */
1064
  composeint.width  = gimp_drawable_width (drawable_ID);
1065 1066
  composeint.height = gimp_drawable_height (drawable_ID);

1067
  gimp_ui_init (PLUG_IN_BINARY, TRUE);
Elliot Lee's avatar
Elliot Lee committed
1068

1069
  layer_list = gimp_image_get_layers (gimp_item_get_image (drawable_ID),
1070 1071
                                      &nlayers);

1072
  dialog = gimp_dialog_new (_("Compose"), PLUG_IN_ROLE,
1073 1074
                            NULL, 0,
                            gimp_standard_help_func, COMPOSE_PROC,
1075

1076 1077
                            _("_Cancel"), GTK_RESPONSE_CANCEL,
                            _("_OK"),     GTK_RESPONSE_OK,
1078

1079
                            NULL);
1080

1081
  gimp_dialog_set_alternative_button_order (GTK_DIALOG (dialog),
1082 1083 1084
                                           GTK_RESPONSE_OK,
                                           GTK_RESPONSE_CANCEL,
                                           -1);
1085

1086
  g_signal_connect (dialog, "response",
1087 1088 1089
                    G_CALLBACK (check_response),
                    NULL);

1090 1091
  gimp_window_set_transient (GTK_WINDOW (dialog));

1092
  main_vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
1093
  gtk_container_set_border_width (GTK_CONTAINER (main_vbox), 12);
1094 1095
  gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))),
                      main_vbox, TRUE, TRUE, 0);
1096 1097 1098
  gtk_widget_show (main_vbox);

  /* Compose type combo */
1099

1100 1101 1102 1103
  frame = gimp_frame_new (_("Compose Channels"));
  gtk_box_pack_start (GTK_BOX (main_vbox), frame, FALSE, FALSE, 0);
  gtk_widget_show (frame);

1104
  hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
1105
  gtk_container_add (GTK_CONTAINER (frame), hbox);
Elliot Lee's avatar
Elliot Lee committed
1106 1107
  gtk_widget_show (hbox);

1108 1109
  size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);

1110
  label = gtk_label_new_with_mnemonic (_("Color _model:"));
1111
  gtk_label_set_xalign (GTK_LABEL (label), 0.0);
1112 1113 1114 1115 1116 1117
  gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
  gtk_widget_show (label);

  gtk_size_group_add_widget (size_group, label);
  g_object_unref (size_group);

1118
  combo = g_object_new (GIMP_TYPE_INT_COMBO_BOX, NULL);
1119 1120
  for (j = 0; j < G_N_ELEMENTS (compose_dsc); j++)
    {
1121 1122 1123 1124 1125 1126 1127
      gchar *label = g_strdup (gettext (compose_dsc[j].compose_type));
      gchar *l;

      for (l = label; *l; l++)
        if (*l == '-' || *l == '_')
          *l = ' ';

1128
      gimp_int_combo_box_append (GIMP_INT_COMBO_BOX (combo),
1129 1130
                                 GIMP_INT_STORE_LABEL, label,
                                 GIMP_INT_STORE_VALUE, j,
1131
                                 -1);
1132
      g_free (label);
1133
    }
1134

1135 1136
  gtk_box_pack_start (GTK_BOX (hbox), combo, TRUE, TRUE, 0);
  gtk_widget_show (combo);
Elliot Lee's avatar
Elliot Lee committed
1137

1138
  gtk_label_set_mnemonic_widget (GTK_LABEL (label), combo);
Elliot Lee's avatar
Elliot Lee committed
1139

1140
  /* Channel representation grid */
Elliot Lee's avatar
Elliot Lee committed
1141

1142 1143 1144
  frame = gimp_frame_new (_("Channel Representations"));
  gtk_box_pack_start (GTK_BOX (main_vbox), frame, TRUE, TRUE, 0);
  gtk_widget_show (frame);
Elliot Lee's avatar
Elliot Lee committed
1145

1146
  vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
1147 1148
  gtk_container_add (GTK_CONTAINER (frame), vbox);
  gtk_widget_show (vbox);
Elliot Lee's avatar
Elliot Lee committed
1149

1150 1151 1152 1153 1154
  grid = gtk_grid_new ();
  gtk_grid_set_row_spacing (GTK_GRID (grid), 6);
  gtk_grid_set_column_spacing (GTK_GRID (grid), 6);
  gtk_box_pack_start (GTK_BOX (vbox), grid, FALSE, FALSE, 0);
  gtk_widget_show (grid);
Elliot Lee's avatar
Elliot Lee committed
1155 1156

  for (j = 0; j < MAX_COMPOSE_IMAGES; j++)
1157
    {
1158 1159 1160 1161 1162 1163 1164
      GtkWidget     *image;
      GtkWidget     *label;
      GtkWidget     *combo;
      GtkAdjustment *scale;
      GtkTreeIter    iter;
      GtkTreeModel  *model;
      GdkPixbuf     *ico;
1165

1166
      hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
1167 1168
      gtk_grid_attach (GTK_GRID (grid), hbox, 0, j, 1, 1);
                        // GTK_FILL, GTK_FILL, 0, 0);
1169
      gtk_widget_show (hbox);
1170

1171
      gtk_size_group_add_widget (size_group, hbox);
1172

1173 1174 1175 1176 1177
      composeint.channel_icon[j] = image = gtk_image_new ();
      gtk_box_pack_start (GTK_BOX (hbox), image, FALSE, FALSE, 0);
      gtk_widget_show (image);

      composeint.channel_label[j] = label = gtk_label_new_with_mnemonic ("");
1178
      gtk_label_set_xalign (GTK_LABEL (label), 0.0);
1179
      gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
1180
      gtk_widget_show (label);
Elliot Lee's avatar
Elliot Lee committed
1181

1182 1183 1184 1185 1186 1187
      if (composeint.compose_idx >= 0 &&
          nlayers >= compose_dsc[composeint.compose_idx].num_images &&
          j < nlayers)
        {
          composeint.selected[j].comp.ID = layer_list[j];
        }
1188
      else
1189 1190 1191 1192
        {
          composeint.selected[j].comp.ID = drawable_ID;
        }

1193
      composeint.selected[j].is_ID = TRUE;
1194 1195

      combo = gimp_drawable_combo_box_new (check_gray, NULL);
1196
      composeint.channel_menu[j] = combo;
1197

1198 1199 1200
      ico = gtk_widget_render_icon_pixbuf (dialog,
                                           GIMP_ICON_CHANNEL_GRAY,
                                           GTK_ICON_SIZE_BUTTON);
1201 1202 1203 1204
      model = gtk_combo_box_get_model (GTK_COMBO_BOX (combo));
      gtk_list_store_append (GTK_LIST_STORE (model), &iter);
      gtk_list_store_set (GTK_LIST_STORE (model), &iter,
                          GIMP_INT_STORE_VALUE,  -1,
1205
                          GIMP_INT_STORE_LABEL,  _("Mask value"),
1206 1207 1208
                          GIMP_INT_STORE_PIXBUF, ico,
                          -1);
      g_object_unref (ico);
1209 1210
      gtk_grid_attach (GTK_GRID (grid), combo, 1, j, 1, 1);
                        // GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
1211
      gtk_widget_show (combo);
1212

1213
      gtk_label_set_mnemonic_widget (GTK_LABEL (label), combo);
1214

1215 1216 1217 1218
      scale = gimp_color_scale_entry_new (GTK_GRID (grid), 2, j, NULL,
                                          100, 4,
                                          255.0, 0.0, 255.0, 1.0, 10.0, 0,
                                          NULL, NULL);
1219 1220 1221
      composeint.color_scales[j] = GIMP_SCALE_ENTRY_SCALE (scale);
      composeint.color_spins[j]  = GIMP_SCALE_ENTRY_SPINBUTTON (scale);

1222
      gtk_widget_set_sensitive (composeint.color_scales[j], FALSE);
1223
      gtk_widget_set_sensitive (composeint.color_spins[j],  FALSE);
1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235

      g_signal_connect (scale, "value-changed",
                        G_CALLBACK (scale_callback),
                        &composeint.selected[j]);

      /* This has to be connected last otherwise it will emit before
       * combo_callback has any scale and spinbutton to work with
       */
      gimp_int_combo_box_connect (GIMP_INT_COMBO_BOX (combo),
                                  composeint.selected[j].comp.ID,
                                  G_CALLBACK (combo_callback),
                                  GINT_TO_POINTER (j));
1236
    }
Elliot Lee's avatar
Elliot Lee committed
1237

1238
  g_free (layer_list);
1239

1240 1241
  /* Calls the combo callback and sets icons, labels and sensitivity */
  gimp_int_combo_box_connect (GIMP_INT_COMBO_BOX (combo),
1242
                              composeint.compose_idx,
1243 1244
                              G_CALLBACK (type_combo_callback),
                              NULL);
Elliot Lee's avatar
Elliot Lee committed
1245

1246
  gtk_widget_show (dialog);
Elliot Lee's avatar
Elliot Lee committed
1247

1248
  run = (gimp_dialog_run (GIMP_DIALOG (dialog)) == GTK_RESPONSE_OK);
1249

1250
  gtk_widget_destroy (dialog);
1251 1252 1253 1254 1255 1256

  if (run)
    {
      gint j;

      for (j = 0; j < MAX_COMPOSE_IMAGES; j++)
1257 1258
        {
          composevals.inputs[j].is_ID = composeint.selected[j].is_ID;
1259

1260 1261 1262 1263 1264
          if (composevals.inputs[j].is_ID)
            composevals.inputs[j].comp.ID = composeint.selected[j].comp.ID;
          else
            composevals.inputs[j].comp.val = composeint.selected[j].comp.val;
        }
1265

1266 1267
      strcpy (composevals.compose_type,
              compose_dsc[composeint.compose_idx].compose_type);
1268
    }
Elliot Lee's avatar
Elliot Lee committed
1269

1270
  return run;
Elliot Lee's avatar
Elliot Lee committed
1271 1272 1273 1274
}

/*  Compose interface functions  */

1275
static gboolean
1276 1277
check_gray (gint32   image_id,
            gint32   drawable_id,
Elliot Lee's avatar
Elliot Lee committed
1278 1279 1280
            gpointer data)

{
Sven Neumann's avatar
Sven Neumann committed
1281
  return ((gimp_image_base_type (image_id) == GIMP_GRAY) &&
David Odin's avatar
David Odin committed
1282 1283
          (gimp_image_width  (image_id) == composeint.width) &&
          (gimp_image_height (image_id) == composeint.height));
Elliot Lee's avatar
Elliot Lee committed
1284 1285
}