home *** CD-ROM | disk | FTP | other *** search
/ PC Pro 2002 April / pcpro0402.iso / essentials / graphics / Gimp / gimp-src-20001226.exe / src / gimp / plug-ins / common / compose.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-08-24  |  28.4 KB  |  953 lines

  1. /* The GIMP -- an 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 2 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, write to the Free Software
  19.  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  20.  */
  21.  
  22. /*
  23.  * This plug-in composes RGB-images from several types of channels
  24.  */
  25.  
  26. /* Event history:
  27.  * V 1.00, PK, 29-Jul-97, Creation
  28.  * V 1.01, nn, 20-Dec-97, Add default case in switch for hsv_to_rgb ()
  29.  * V 1.02, PK, 18-Sep-98, Change variable names in Parameter definition.
  30.  *         Otherwise script-fu merges parameters (reported by Patrick Valsecchi)
  31.  *         Check images for same width/height (interactive mode)
  32.  *         Use drawables in interactive menu
  33.  *         Use g_message in interactive mode
  34.  *         Check sensitivity of menues (thanks to Kevin Turner,
  35.  *           kevint@poboxes.com)
  36.  * V1.03, PK, 17-Mar-99, Update for GIMP 1.1.3
  37.  *         Allow image ID 0
  38.  *         Prepare for localization
  39.  */
  40. static char ident[] = "@(#) GIMP Compose plug-in v1.03 17-Mar-99";
  41.  
  42. #ifdef HAVE_CONFIG_H
  43. #include "config.h"
  44. #endif
  45.  
  46. #include <stdio.h>
  47. #include <stdlib.h>
  48. #include <string.h>
  49. #include <ctype.h>
  50.  
  51. #include <gtk/gtk.h>
  52.  
  53. #include <libgimp/gimp.h>
  54. #include <libgimp/gimpui.h>
  55.  
  56. #include "libgimp/stdplugins-intl.h"
  57.  
  58. /* Declare local functions
  59.  */
  60. static void      query  (void);
  61. static void      run    (gchar     *name,
  62.              gint       nparams,
  63.              GimpParam    *param,
  64.              gint      *nreturn_vals,
  65.              GimpParam   **return_vals);
  66.  
  67. static gint32    compose (gchar *compose_type,
  68.                           gint32 *compose_ID,
  69.                           gint compose_by_drawable);
  70.  
  71. static gint32    create_new_image (gchar          *filename,
  72.                    guint           width,
  73.                    guint           height,
  74.                    GimpImageType   gdtype,
  75.                    gint32         *layer_ID,
  76.                    GimpDrawable     **drawable,
  77.                    GimpPixelRgn      *pixel_rgn);
  78.  
  79. static void  compose_rgb  (guchar **src, gint *incr, gint numpix, guchar *dst);
  80. static void  compose_rgba (guchar **src, gint *incr, gint numpix, guchar *dst);
  81. static void  compose_hsv  (guchar **src, gint *incr, gint numpix, guchar *dst);
  82. static void  compose_cmy  (guchar **src, gint *incr, gint numpix, guchar *dst);
  83. static void  compose_cmyk (guchar **src, gint *incr, gint numpix, guchar *dst);
  84.  
  85. static gint      compose_dialog (gchar  *compose_type,
  86.                                  gint32  drawable_ID);
  87.  
  88. static gint      check_gray     (gint32 image_id,
  89.                  gint32 drawable_id,
  90.                  gpointer data);
  91.  
  92. static void      image_menu_callback (gint32     id,
  93.                                       gpointer   data);
  94.  
  95. static void      compose_ok_callback         (GtkWidget *widget,
  96.                                               gpointer   data);
  97. static void      compose_type_toggle_update  (GtkWidget *widget,
  98.                                               gpointer   data);
  99.  
  100. /* Maximum number of images to compose */
  101. #define MAX_COMPOSE_IMAGES 4
  102.  
  103.  
  104. /* Description of a composition */
  105. typedef struct
  106. {
  107.   gchar  *compose_type;            /* Type of composition ("RGB", "RGBA",...) */
  108.   gint    num_images;              /* Number of input images needed */
  109.   gchar  *channel_name[MAX_COMPOSE_IMAGES];  /* channel names for dialog */
  110.   gchar  *filename;                /* Name of new image */
  111.                                    /* Compose functon */
  112.   void  (*compose_fun) (guchar **src, gint *incr_src, gint numpix, guchar *dst);
  113. } COMPOSE_DSC;
  114.  
  115. /* Array of available compositions. */
  116. #define CHNL_NA "-"
  117.  
  118. static COMPOSE_DSC compose_dsc[] =
  119. {
  120.   { N_("RGB"), 3, { N_("Red:"),
  121.             N_("Green:"),
  122.             N_("Blue:"),
  123.             CHNL_NA }, N_("rgb-compose"),  compose_rgb },
  124.  { N_("RGBA"), 4, { N_("Red:"),
  125.             N_("Green:"),
  126.             N_("Blue:"),
  127.             N_("Alpha:") }, N_("rgba-compose"),  compose_rgba },
  128.  { N_("HSV"),  3, { N_("Hue:"),
  129.             N_("Saturation:"),
  130.             N_("Value:"),
  131.             CHNL_NA }, N_("hsv-compose"),  compose_hsv },
  132.  { N_("CMY"),  3, { N_("Cyan:"),
  133.             N_("Magenta:"),
  134.             N_("Yellow:"),
  135.             CHNL_NA }, N_("cmy-compose"),  compose_cmy },
  136.  { N_("CMYK"), 4, { N_("Cyan:"),
  137.             N_("Magenta:"),
  138.             N_("Yellow:"),
  139.             N_("Black:") }, N_("cmyk-compose"), compose_cmyk }
  140. };
  141.  
  142. #define MAX_COMPOSE_TYPES (sizeof (compose_dsc) / sizeof (compose_dsc[0]))
  143.  
  144.  
  145. typedef struct
  146. {
  147.   gint32 compose_ID[MAX_COMPOSE_IMAGES];  /* Image IDs of input images */
  148.   gchar  compose_type[32];                /* type of composition */
  149. } ComposeVals;
  150.  
  151. /* Dialog structure */
  152. typedef struct
  153. {
  154.   gint width, height;                     /* Size of selected image */
  155.  
  156.   GtkWidget *channel_label[MAX_COMPOSE_IMAGES]; /* The labels to change */
  157.   GtkWidget *channel_menu[MAX_COMPOSE_IMAGES];  /* The menues */
  158.  
  159.   gint32 select_ID[MAX_COMPOSE_IMAGES];    /* Image Ids selected by menu */
  160.   gint   compose_flag[MAX_COMPOSE_TYPES];  /* toggle data of compose type */
  161.   gint   run;
  162. } ComposeInterface;
  163.  
  164. GimpPlugInInfo PLUG_IN_INFO =
  165. {
  166.   NULL,  /* init_proc  */
  167.   NULL,  /* quit_proc  */
  168.   query, /* query_proc */
  169.   run,   /* run_proc   */
  170. };
  171.  
  172. static ComposeVals composevals =
  173. {
  174.   { 0 },  /* Image IDs of images to compose */
  175.   "rgb"   /* Type of composition */
  176. };
  177.  
  178. static ComposeInterface composeint =
  179. {
  180.   0, 0,     /* width, height */
  181.   { NULL }, /* Label Widgets */
  182.   { NULL }, /* Menu Widgets */
  183.   { 0 },    /* Image IDs from menues */
  184.   { 0 },    /* Compose type toggle flags */
  185.   FALSE     /* run */
  186. };
  187.  
  188. static GimpRunModeType run_mode;
  189.  
  190.  
  191. MAIN ()
  192.  
  193. static void
  194. query (void)
  195. {
  196.   static GimpParamDef args[] =
  197.   {
  198.     { GIMP_PDB_INT32, "run_mode", "Interactive, non-interactive" },
  199.     { GIMP_PDB_IMAGE, "image1", "First input image" },
  200.     { GIMP_PDB_DRAWABLE, "drawable", "Input drawable (not used)" },
  201.     { GIMP_PDB_IMAGE, "image2", "Second input image" },
  202.     { GIMP_PDB_IMAGE, "image3", "Third input image" },
  203.     { GIMP_PDB_IMAGE, "image4", "Fourth input image" },
  204.     { GIMP_PDB_STRING, "compose_type", "What to compose: RGB, RGBA, HSV, CMY, CMYK" }
  205.   };
  206.   static GimpParamDef return_vals[] =
  207.   {
  208.     { GIMP_PDB_IMAGE, "new_image", "Output image" }
  209.   };
  210.   static gint nargs = sizeof (args) / sizeof (args[0]);
  211.   static gint nreturn_vals = sizeof (return_vals) / sizeof (return_vals[0]);
  212.  
  213.   static GimpParamDef drw_args[] =
  214.   {
  215.     { GIMP_PDB_INT32, "run_mode", "Interactive, non-interactive" },
  216.     { GIMP_PDB_IMAGE, "image1", "First input image (not used)" },
  217.     { GIMP_PDB_DRAWABLE, "drawable1", "First input drawable" },
  218.     { GIMP_PDB_DRAWABLE, "drawable2", "Second input drawable" },
  219.     { GIMP_PDB_DRAWABLE, "drawable3", "Third input drawable" },
  220.     { GIMP_PDB_DRAWABLE, "drawable4", "Fourth input drawable" },
  221.     { GIMP_PDB_STRING, "compose_type", "What to compose: RGB, RGBA, HSV, CMY, CMYK" }
  222.   };
  223.   static GimpParamDef drw_return_vals[] =
  224.   {
  225.     { GIMP_PDB_IMAGE, "new_image", "Output image" }
  226.   };
  227.   static gint drw_nargs = sizeof (args) / sizeof (args[0]);
  228.   static gint drw_nreturn_vals = sizeof (return_vals) / sizeof (return_vals[0]);
  229.  
  230.   gimp_install_procedure ("plug_in_compose",
  231.               "Compose an image from multiple gray images",
  232.               "This function creates a new image from "
  233.               "multiple gray images",
  234.               "Peter Kirchgessner",
  235.               "Peter Kirchgessner (peter@kirchgessner.net)",
  236.               "1997",
  237.               N_("<Image>/Image/Mode/Compose..."),
  238.               "GRAY*",
  239.               GIMP_PLUGIN,
  240.               nargs, nreturn_vals,
  241.               args, return_vals);
  242.  
  243.   gimp_install_procedure ("plug_in_drawable_compose",
  244.               "Compose an image from multiple drawables of gray images",
  245.               "This function creates a new image from "
  246.               "multiple drawables of gray images",
  247.               "Peter Kirchgessner",
  248.               "Peter Kirchgessner (peter@kirchgessner.net)",
  249.               "1998",
  250.               NULL,   /* It is not available in interactive mode */
  251.               "GRAY*",
  252.               GIMP_PLUGIN,
  253.               drw_nargs, drw_nreturn_vals,
  254.               drw_args, drw_return_vals);
  255. }
  256.  
  257.  
  258. static void
  259. run (gchar   *name,
  260.      gint     nparams,
  261.      GimpParam  *param,
  262.      gint    *nreturn_vals,
  263.      GimpParam **return_vals)
  264. {
  265.   static GimpParam values[2];
  266.   GimpPDBStatusType status = GIMP_PDB_SUCCESS;
  267.   gint32 image_ID, drawable_ID;
  268.   gint compose_by_drawable;
  269.  
  270.   INIT_I18N_UI ();
  271.  
  272.   run_mode = param[0].data.d_int32;
  273.   compose_by_drawable = (strcmp (name, "plug_in_drawable_compose") == 0);
  274.  
  275.   *nreturn_vals = 2;
  276.   *return_vals = values;
  277.  
  278.   values[0].type = GIMP_PDB_STATUS;
  279.   values[0].data.d_status = status;
  280.   values[1].type = GIMP_PDB_IMAGE;
  281.   values[1].data.d_int32 = -1;
  282.  
  283.   switch (run_mode)
  284.     {
  285.     case GIMP_RUN_INTERACTIVE:
  286.       /*  Possibly retrieve data  */
  287.       gimp_get_data (name , &composevals);
  288.  
  289.       /* The dialog is now drawable based. Get a drawable-ID of the image */
  290.       if (strcmp (name, "plug_in_compose") == 0)
  291.       {gint32 *layer_list;
  292.        gint nlayers;
  293.  
  294.         layer_list = gimp_image_get_layers (param[1].data.d_int32, &nlayers);
  295.         if ((layer_list == NULL) || (nlayers <= 0))
  296.         {
  297.       g_message (_("compose: Could not get layers for image %d"),
  298.              (gint) param[1].data.d_int32);
  299.           return;
  300.         }
  301.         drawable_ID = layer_list[0];
  302.         g_free (layer_list);
  303.       }
  304.       else
  305.         drawable_ID = param[2].data.d_int32;
  306.  
  307.       compose_by_drawable = 1;
  308.  
  309.       /*  First acquire information with a dialog  */
  310.       if (! compose_dialog (composevals.compose_type, drawable_ID))
  311.     return;
  312.  
  313.       break;
  314.  
  315.     case GIMP_RUN_NONINTERACTIVE:
  316.       /*  Make sure all the arguments are there!  */
  317.       if (nparams != 7)
  318.     {
  319.       status = GIMP_PDB_CALLING_ERROR;
  320.     }
  321.       else
  322.     {
  323.       composevals.compose_ID[0] =
  324.         compose_by_drawable ? param[2].data.d_int32 : param[1].data.d_int32;
  325.       composevals.compose_ID[1] = param[3].data.d_int32;
  326.       composevals.compose_ID[2] = param[4].data.d_int32;
  327.       composevals.compose_ID[3] = param[5].data.d_int32;
  328.       strncpy (composevals.compose_type, param[6].data.d_string,
  329.            sizeof (composevals.compose_type));
  330.       composevals.compose_type[sizeof (composevals.compose_type)-1] = '\0';
  331.     }
  332.       break;
  333.  
  334.     case GIMP_RUN_WITH_LAST_VALS:
  335.       /*  Possibly retrieve data  */
  336.       gimp_get_data (name, &composevals);
  337.       break;
  338.  
  339.     default:
  340.       break;
  341.     }
  342.  
  343.   if (status == GIMP_PDB_SUCCESS)
  344.     {
  345.       if (run_mode != GIMP_RUN_NONINTERACTIVE)
  346.         gimp_progress_init (_("Composing..."));
  347.  
  348.       image_ID = compose (composevals.compose_type,
  349.               composevals.compose_ID,
  350.                           compose_by_drawable);
  351.  
  352.       if (image_ID < 0)
  353.     {
  354.       status = GIMP_PDB_EXECUTION_ERROR;
  355.     }
  356.       else
  357.     {
  358.       values[1].data.d_int32 = image_ID;
  359.       gimp_image_undo_enable (image_ID);
  360.       gimp_image_clean_all (image_ID);
  361.       if (run_mode != GIMP_RUN_NONINTERACTIVE)
  362.         gimp_display_new (image_ID);
  363.     }
  364.  
  365.       /*  Store data  */
  366.       if (run_mode == GIMP_RUN_INTERACTIVE)
  367.         gimp_set_data (name, &composevals, sizeof (ComposeVals));
  368.     }
  369.  
  370.   values[0].data.d_status = status;
  371. }
  372.  
  373.  
  374. /* Compose an image from several gray-images */
  375. static gint32
  376. compose (gchar  *compose_type,
  377.          gint32 *compose_ID,
  378.          gint    compose_by_drawable)
  379. {
  380.   gint width, height, tile_height, scan_lines;
  381.   gint num_images, compose_idx, incr_src[MAX_COMPOSE_IMAGES];
  382.   gint i, j;
  383.   gint num_layers;
  384.   gint32 layer_ID_dst, image_ID_dst;
  385.   guchar *src[MAX_COMPOSE_IMAGES], *dst = (guchar *)ident;
  386.   GimpImageType gdtype_dst;
  387.   GimpDrawable *drawable_src[MAX_COMPOSE_IMAGES], *drawable_dst;
  388.   GimpPixelRgn pixel_rgn_src[MAX_COMPOSE_IMAGES], pixel_rgn_dst;
  389.   
  390.   /* Search type of composing */
  391.   compose_idx = -1;
  392.   for (j = 0; j < MAX_COMPOSE_TYPES; j++)
  393.     {
  394.       if (g_strcasecmp (compose_type, compose_dsc[j].compose_type) == 0)
  395.     compose_idx = j;
  396.     }
  397.   if (compose_idx < 0)
  398.     return (-1);
  399.   
  400.   num_images = compose_dsc[compose_idx].num_images;
  401.   tile_height = gimp_tile_height ();
  402.   
  403.   /* Check image sizes */
  404.   if (compose_by_drawable)
  405.     {
  406.       width = gimp_drawable_width (compose_ID[0]);
  407.       height = gimp_drawable_height (compose_ID[0]);
  408.       
  409.       for (j = 1; j < num_images; j++)
  410.     {
  411.       if ((width != (gint)gimp_drawable_width (compose_ID[j])) ||
  412.           (height != (gint)gimp_drawable_height (compose_ID[j])))
  413.         {
  414.           g_message (_("Compose: Drawables have different size"));
  415.           return -1;
  416.         }
  417.     }
  418.       for (j = 0; j < num_images; j++)
  419.     drawable_src[j] = gimp_drawable_get (compose_ID[j]);
  420.     }
  421.   else    /* Compose by image ID */
  422.     {
  423.       width = gimp_image_width (compose_ID[0]);
  424.       height = gimp_image_height (compose_ID[0]);
  425.       
  426.       for (j = 1; j < num_images; j++)
  427.     {
  428.       if ((width != (gint)gimp_image_width (compose_ID[j])) ||
  429.           (height != (gint)gimp_image_height (compose_ID[j])))
  430.         {
  431.           g_message (_("Compose: Images have different size"));
  432.           return -1;
  433.         }
  434.     }
  435.       
  436.       /* Get first layer/drawable for all input images */
  437.       for (j = 0; j < num_images; j++)
  438.     {
  439.       gint32 *g32;
  440.     
  441.       /* Get first layer of image */
  442.       g32 = gimp_image_get_layers (compose_ID[j], &num_layers);
  443.       if ((g32 == NULL) || (num_layers <= 0))
  444.         {
  445.           g_message (_("Compose: Error in getting layer IDs"));
  446.           return -1;
  447.         }
  448.  
  449.       /* Get drawable for layer */
  450.       drawable_src[j] = gimp_drawable_get (g32[0]);
  451.       g_free (g32);
  452.     }
  453.     }
  454.   
  455.   /* Get pixel region for all input drawables */
  456.   for (j = 0; j < num_images; j++)
  457.     {
  458.       /* Check bytes per pixel */
  459.       incr_src[j] = drawable_src[j]->bpp;
  460.       if ((incr_src[j] != 1) && (incr_src[j] != 2))
  461.     {
  462.       g_message (_("Compose: Image is not a gray image (bpp=%d)"), 
  463.              incr_src[j]);
  464.       return -1;
  465.     }
  466.       
  467.       /* Get pixel region */
  468.       gimp_pixel_rgn_init (&(pixel_rgn_src[j]), drawable_src[j], 0, 0,
  469.                width, height, FALSE, FALSE);
  470.       
  471.       /* Get memory for retrieving information */
  472.       src[j] = g_new (guchar, tile_height * width * drawable_src[j]->bpp);
  473.     }
  474.   
  475.   /* Create new image */
  476.   gdtype_dst = (compose_dsc[compose_idx].compose_fun == compose_rgba)
  477.     ? GIMP_RGBA_IMAGE : GIMP_RGB_IMAGE;
  478.   image_ID_dst = create_new_image (compose_dsc[compose_idx].filename,
  479.                    width, height, gdtype_dst,
  480.                    &layer_ID_dst, &drawable_dst, &pixel_rgn_dst);
  481.   dst = g_new (guchar, tile_height * width * drawable_dst->bpp);
  482.  
  483.   /* Do the composition */
  484.   i = 0;
  485.   while (i < height)
  486.     {
  487.       scan_lines = (i+tile_height-1 < height) ? tile_height : (height-i);
  488.  
  489.       /* Get source pixel regions */
  490.       for (j = 0; j < num_images; j++)
  491.     gimp_pixel_rgn_get_rect (&(pixel_rgn_src[j]), src[j], 0, i,
  492.                  width, scan_lines);
  493.  
  494.       /* Do the composition */
  495.       compose_dsc[compose_idx].compose_fun (src,incr_src,width*tile_height,dst);
  496.  
  497.       /* Set destination pixel region */
  498.       gimp_pixel_rgn_set_rect (&pixel_rgn_dst, dst, 0, i, width, scan_lines);
  499.  
  500.       i += scan_lines;
  501.  
  502.       if (run_mode != GIMP_RUN_NONINTERACTIVE)
  503.     gimp_progress_update (((gdouble)i) / (gdouble)height);
  504.     }
  505.  
  506.   for (j = 0; j < num_images; j++)
  507.     {
  508.       g_free (src[j]);
  509.       gimp_drawable_flush (drawable_src[j]);
  510.       gimp_drawable_detach (drawable_src[j]);
  511.     }
  512.   g_free (dst);
  513.   gimp_drawable_flush (drawable_dst);
  514.   gimp_drawable_detach (drawable_dst);
  515.   
  516.   return image_ID_dst;
  517. }
  518.  
  519.  
  520. /* Create an image. Sets layer_ID, drawable and rgn. Returns image_ID */
  521. static gint32
  522. create_new_image (gchar          *filename,
  523.                   guint           width,
  524.                   guint           height,
  525.                   GimpImageType   gdtype,
  526.                   gint32         *layer_ID,
  527.                   GimpDrawable     **drawable,
  528.                   GimpPixelRgn      *pixel_rgn)
  529. {
  530.   gint32 image_ID;
  531.   GimpImageBaseType gitype;
  532.  
  533.   if ((gdtype == GIMP_GRAY_IMAGE) || (gdtype == GIMP_GRAYA_IMAGE))
  534.     gitype = GIMP_GRAY;
  535.   else if ((gdtype == GIMP_INDEXED_IMAGE) || (gdtype == GIMP_INDEXEDA_IMAGE))
  536.     gitype = GIMP_INDEXED;
  537.   else
  538.     gitype = GIMP_RGB;
  539.  
  540.   image_ID = gimp_image_new (width, height, gitype);
  541.   gimp_image_set_filename (image_ID, filename);
  542.  
  543.   *layer_ID = gimp_layer_new (image_ID, _("Background"), width, height,
  544.                   gdtype, 100, GIMP_NORMAL_MODE);
  545.   gimp_image_add_layer (image_ID, *layer_ID, 0);
  546.  
  547.   *drawable = gimp_drawable_get (*layer_ID);
  548.   gimp_pixel_rgn_init (pixel_rgn, *drawable, 0, 0, (*drawable)->width,
  549.                (*drawable)->height, TRUE, FALSE);
  550.  
  551.   return image_ID;
  552. }
  553.  
  554. static void
  555. compose_rgb (guchar **src,
  556.              gint    *incr_src,
  557.              gint     numpix,
  558.              guchar  *dst)
  559. {
  560.   register guchar *red_src = src[0];
  561.   register guchar *green_src = src[1];
  562.   register guchar *blue_src = src[2];
  563.   register guchar *rgb_dst = dst;
  564.   register gint count = numpix;
  565.   gint red_incr = incr_src[0], green_incr = incr_src[1], blue_incr = incr_src[2];
  566.   
  567.   if ((red_incr == 1) && (green_incr == 1) && (blue_incr == 1))
  568.     {
  569.       while (count-- > 0)
  570.     {
  571.       *(rgb_dst++) = *(red_src++);
  572.       *(rgb_dst++) = *(green_src++);
  573.       *(rgb_dst++) = *(blue_src++);
  574.     }
  575.     }
  576.   else
  577.     {
  578.       while (count-- > 0)
  579.     {
  580.       *(rgb_dst++) = *red_src;     red_src += red_incr;
  581.       *(rgb_dst++) = *green_src;   green_src += green_incr;
  582.       *(rgb_dst++) = *blue_src;    blue_src += blue_incr;
  583.     }
  584.     }
  585. }
  586.  
  587.  
  588. static void
  589. compose_rgba (guchar **src,
  590.               gint    *incr_src,
  591.               gint     numpix,
  592.               guchar  *dst)
  593. {
  594.   register guchar *red_src = src[0];
  595.   register guchar *green_src = src[1];
  596.   register guchar *blue_src = src[2];
  597.   register guchar *alpha_src = src[3];
  598.   register guchar *rgb_dst = dst;
  599.   register gint count = numpix;
  600.   gint red_incr = incr_src[0], green_incr = incr_src[1],
  601.     blue_incr = incr_src[2], alpha_incr = incr_src[3];
  602.   
  603.   if ((red_incr == 1) && (green_incr == 1) && (blue_incr == 1) &&
  604.       (alpha_incr == 1))
  605.     {
  606.       while (count-- > 0)
  607.     {
  608.       *(rgb_dst++) = *(red_src++);
  609.       *(rgb_dst++) = *(green_src++);
  610.       *(rgb_dst++) = *(blue_src++);
  611.       *(rgb_dst++) = *(alpha_src++);
  612.     }
  613.     }
  614.   else
  615.     {
  616.       while (count-- > 0)
  617.     {
  618.       *(rgb_dst++) = *red_src;    red_src += red_incr;
  619.       *(rgb_dst++) = *green_src;  green_src += green_incr;
  620.       *(rgb_dst++) = *blue_src;   blue_src += blue_incr;
  621.       *(rgb_dst++) = *alpha_src;  alpha_src += alpha_incr;
  622.     }
  623.     }
  624. }
  625.  
  626.  
  627. static void
  628. compose_hsv (guchar **src,
  629.              gint    *incr_src,
  630.              gint     numpix,
  631.              guchar  *dst)
  632. {
  633.   register guchar *hue_src = src[0];
  634.   register guchar *sat_src = src[1];
  635.   register guchar *val_src = src[2];
  636.   register guchar *rgb_dst = dst;
  637.   register gint count = numpix;
  638.   gint hue_incr = incr_src[0], sat_incr = incr_src[1], val_incr = incr_src[2];
  639.  
  640.   while (count-- > 0)
  641.     {
  642.       gimp_hsv_to_rgb4 (rgb_dst, (gdouble) *hue_src / 255.0, 
  643.                      (gdouble) *sat_src / 255.0, 
  644.                      (gdouble) *val_src / 255.0);
  645.       rgb_dst += 3;
  646.       hue_src += hue_incr;
  647.       sat_src += sat_incr;
  648.       val_src += val_incr;
  649.     }
  650. }
  651.  
  652.  
  653. static void
  654. compose_cmy (guchar **src,
  655.              gint            *incr_src,
  656.              gint             numpix,
  657.              guchar  *dst)
  658. {
  659.   register guchar *cyan_src = src[0];
  660.   register guchar *magenta_src = src[1];
  661.   register guchar *yellow_src = src[2];
  662.   register guchar *rgb_dst = dst;
  663.   register gint count = numpix;
  664.   gint cyan_incr = incr_src[0];
  665.   gint magenta_incr = incr_src[1];
  666.   gint yellow_incr = incr_src[2];
  667.  
  668.   if ((cyan_incr == 1) && (magenta_incr == 1) && (yellow_incr == 1))
  669.     {
  670.       while (count-- > 0)
  671.     {
  672.       *(rgb_dst++) = 255 - *(cyan_src++);
  673.       *(rgb_dst++) = 255 - *(magenta_src++);
  674.       *(rgb_dst++) = 255 - *(yellow_src++);
  675.     }
  676.     }
  677.   else
  678.     {
  679.       while (count-- > 0)
  680.     {
  681.       *(rgb_dst++) = 255 - *cyan_src;
  682.       *(rgb_dst++) = 255 - *magenta_src;
  683.       *(rgb_dst++) = 255 - *yellow_src;
  684.       cyan_src += cyan_incr;
  685.       magenta_src += magenta_incr;
  686.       yellow_src += yellow_incr;
  687.     }
  688.     }
  689. }
  690.  
  691.  
  692. static void
  693. compose_cmyk (guchar **src,
  694.               gint    *incr_src,
  695.               gint     numpix,
  696.               guchar  *dst)
  697. {
  698.   register guchar *cyan_src = src[0];
  699.   register guchar *magenta_src = src[1];
  700.   register guchar *yellow_src = src[2];
  701.   register guchar *black_src = src[3];
  702.   register guchar *rgb_dst = dst;
  703.   register gint count = numpix;
  704.   gint cyan, magenta, yellow, black;
  705.   gint cyan_incr = incr_src[0];
  706.   gint magenta_incr = incr_src[1];
  707.   gint yellow_incr = incr_src[2];
  708.   gint black_incr = incr_src[3];
  709.  
  710.   while (count-- > 0)
  711.     {
  712.       black = (gint)*black_src;
  713.       if (black)
  714.     {
  715.       cyan    = (gint) *cyan_src;
  716.       magenta = (gint) *magenta_src;
  717.       yellow  = (gint) *yellow_src;
  718.  
  719.       cyan    += black; if (cyan > 255) cyan = 255;
  720.       magenta += black; if (magenta > 255) magenta = 255;
  721.       yellow  += black; if (yellow > 255) yellow = 255;
  722.  
  723.       *(rgb_dst++) = 255 - cyan;
  724.       *(rgb_dst++) = 255 - magenta;
  725.       *(rgb_dst++) = 255 - yellow;
  726.     }
  727.       else
  728.     {
  729.       *(rgb_dst++) = 255 - *cyan_src;
  730.       *(rgb_dst++) = 255 - *magenta_src;
  731.       *(rgb_dst++) = 255 - *yellow_src;
  732.     }
  733.       cyan_src += cyan_incr;
  734.       magenta_src += magenta_incr;
  735.       yellow_src += yellow_incr;
  736.       black_src += black_incr;
  737.     }
  738. }
  739.  
  740.  
  741. static gint
  742. compose_dialog (gchar  *compose_type,
  743.                 gint32  drawable_ID)
  744. {
  745.   GtkWidget *dlg;
  746.   GtkWidget *toggle;
  747.   GtkWidget *left_frame, *right_frame;
  748.   GtkWidget *left_vbox, *right_vbox;
  749.   GtkWidget *hbox;
  750.   GtkWidget *label;
  751.   GtkWidget *table;
  752.   GtkWidget *image_option_menu, *image_menu;
  753.   GSList *group;
  754.   gint    j, compose_idx, sensitive;
  755.  
  756.   /* Check default compose type */
  757.   compose_idx = -1;
  758.   for (j = 0; j < MAX_COMPOSE_TYPES; j++)
  759.     {
  760.       if (g_strcasecmp (compose_type, compose_dsc[j].compose_type) == 0)
  761.     compose_idx = j;
  762.     }
  763.   if (compose_idx < 0) compose_idx = 0;
  764.  
  765.   /* Save original image width/height */
  766.   composeint.width  = gimp_drawable_width (drawable_ID);
  767.   composeint.height = gimp_drawable_height (drawable_ID);
  768.  
  769.   gimp_ui_init ("compose", TRUE);
  770.  
  771.   dlg = gimp_dialog_new (_("Compose"), "compose",
  772.              gimp_standard_help_func, "filters/compose.html",
  773.              GTK_WIN_POS_MOUSE,
  774.              FALSE, TRUE, FALSE,
  775.  
  776.              _("OK"), compose_ok_callback,
  777.              NULL, NULL, NULL, TRUE, FALSE,
  778.              _("Cancel"), gtk_widget_destroy,
  779.              NULL, 1, NULL, FALSE, TRUE,
  780.  
  781.              NULL);
  782.  
  783.   gtk_signal_connect (GTK_OBJECT (dlg), "destroy",
  784.               GTK_SIGNAL_FUNC (gtk_main_quit),
  785.               NULL);
  786.  
  787.   /*  parameter settings  */
  788.   hbox = gtk_hbox_new (FALSE, 6);
  789.   gtk_container_set_border_width (GTK_CONTAINER (hbox), 6);
  790.   gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dlg)->vbox), hbox, TRUE, TRUE, 0);
  791.   gtk_widget_show (hbox);
  792.  
  793.   /* The left frame keeps the compose type toggles */
  794.   left_frame = gtk_frame_new (_("Compose Channels"));
  795.   gtk_frame_set_shadow_type (GTK_FRAME (left_frame), GTK_SHADOW_ETCHED_IN);
  796.   gtk_box_pack_start (GTK_BOX (hbox), left_frame, FALSE, FALSE, 0);
  797.  
  798.   left_vbox = gtk_vbox_new (FALSE, 1);
  799.   gtk_container_set_border_width (GTK_CONTAINER (left_vbox), 2);
  800.   gtk_container_add (GTK_CONTAINER (left_frame), left_vbox);
  801.  
  802.   /* The right frame keeps the selection menues for images. */
  803.   /* Because the labels within this frame will change when a toggle */
  804.   /* in the left frame is changed, fill in the right part first. */
  805.   /* Otherwise it can occur, that a non-existing label might be changed. */
  806.  
  807.   right_frame = gtk_frame_new (_("Channel Representations"));
  808.   gtk_frame_set_shadow_type (GTK_FRAME (right_frame), GTK_SHADOW_ETCHED_IN);
  809.   gtk_box_pack_start (GTK_BOX (hbox), right_frame, TRUE, TRUE, 0);
  810.  
  811.   right_vbox = gtk_vbox_new (FALSE, 0);
  812.   gtk_container_set_border_width (GTK_CONTAINER (right_vbox), 4);
  813.   gtk_container_add (GTK_CONTAINER (right_frame), right_vbox);
  814.  
  815.   table = gtk_table_new (MAX_COMPOSE_IMAGES, 2, FALSE);
  816.   gtk_table_set_row_spacings (GTK_TABLE (table), 2);
  817.   gtk_table_set_col_spacings (GTK_TABLE (table), 4);
  818.   gtk_box_pack_start (GTK_BOX (right_vbox), table, TRUE, TRUE, 0);
  819.   gtk_widget_show (table);
  820.  
  821.   /* Channel names */
  822.   for (j = 0; j < MAX_COMPOSE_IMAGES; j++)
  823.     {
  824.       composeint.channel_label[j] = label =
  825.     gtk_label_new (gettext (compose_dsc[compose_idx].channel_name[j]));
  826.       gtk_misc_set_alignment (GTK_MISC (label), 1.0, 0.5);
  827.       gtk_table_attach (GTK_TABLE (table), label, 0, 1, j, j+1,
  828.             GTK_FILL, GTK_FILL, 0, 0);
  829.       gtk_widget_show (label);
  830.     }
  831.   /* Set sensitivity of last label */
  832.   sensitive = (strcmp (compose_dsc[compose_idx].channel_name[3],
  833.                        CHNL_NA) != 0);
  834.   gtk_widget_set_sensitive (composeint.channel_label[3], sensitive);
  835.  
  836.   /* Menues to select images */
  837.   for (j = 0; j <  MAX_COMPOSE_IMAGES; j++)
  838.     {
  839.       composeint.select_ID[j] = drawable_ID;
  840.       composeint.channel_menu[j] = image_option_menu = gtk_option_menu_new ();
  841.       image_menu = gimp_drawable_menu_new (check_gray, image_menu_callback,
  842.                        &(composeint.select_ID[j]),
  843.                        composeint.select_ID[j]);
  844.       gtk_table_attach (GTK_TABLE (table), image_option_menu, 1, 2, j, j+1,
  845.             GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
  846.  
  847.       gtk_widget_show (image_option_menu);
  848.       gtk_option_menu_set_menu (GTK_OPTION_MENU (image_option_menu), image_menu);
  849.     }
  850.   gtk_widget_set_sensitive (composeint.channel_menu[3], sensitive);
  851.  
  852.   /* Compose types */
  853.   group = NULL;
  854.   for (j = 0; j < MAX_COMPOSE_TYPES; j++)
  855.     {
  856.       toggle = gtk_radio_button_new_with_label (group,
  857.                         gettext(compose_dsc[j].compose_type));
  858.       group = gtk_radio_button_group (GTK_RADIO_BUTTON (toggle));
  859.       gtk_box_pack_start (GTK_BOX (left_vbox), toggle, TRUE, TRUE, 0);
  860.       composeint.compose_flag[j] = (j == compose_idx);
  861.       gtk_signal_connect (GTK_OBJECT (toggle), "toggled",
  862.               (GtkSignalFunc) compose_type_toggle_update,
  863.               &(composeint.compose_flag[j]));
  864.       gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle),
  865.                     composeint.compose_flag[j]);
  866.       gtk_widget_show (toggle);
  867.     }
  868.  
  869.   gtk_widget_show (left_vbox);
  870.   gtk_widget_show (right_vbox);
  871.   gtk_widget_show (left_frame);
  872.   gtk_widget_show (right_frame);
  873.   gtk_widget_show (dlg);
  874.  
  875.   gtk_main ();
  876.   gdk_flush ();
  877.  
  878.   return composeint.run;
  879. }
  880.  
  881. /*  Compose interface functions  */
  882.  
  883. static gint
  884. check_gray (gint32   image_id,
  885.             gint32   drawable_id,
  886.             gpointer data)
  887.  
  888. {
  889.   return ((gimp_image_base_type (image_id) == GIMP_GRAY) &&
  890.       (gimp_image_width (image_id) == composeint.width) &&
  891.       (gimp_image_height (image_id) == composeint.height));
  892. }
  893.  
  894.  
  895. static void
  896. image_menu_callback (gint32   id,
  897.                      gpointer data)
  898. {
  899.   *(gint32 *) data = id;
  900. }
  901.  
  902.  
  903. static void
  904. compose_ok_callback (GtkWidget *widget,
  905.                      gpointer   data)
  906. {
  907.   gint j;
  908.  
  909.   composeint.run = TRUE;
  910.   gtk_widget_destroy (GTK_WIDGET (data));
  911.  
  912.   for (j = 0; j < MAX_COMPOSE_IMAGES; j++)
  913.     composevals.compose_ID[j] = composeint.select_ID[j];
  914.  
  915.   for (j = 0; j < MAX_COMPOSE_TYPES; j++)
  916.     {
  917.       if (composeint.compose_flag[j])
  918.     {
  919.       strcpy (composevals.compose_type, compose_dsc[j].compose_type);
  920.       break;
  921.     }
  922.     }
  923. }
  924.  
  925.  
  926. static void
  927. compose_type_toggle_update (GtkWidget *widget,
  928.                             gpointer   data)
  929. {
  930.   gint *toggle_val;
  931.   gint  compose_idx, j;
  932.   gint  sensitive;
  933.  
  934.   toggle_val = (gint *) data;
  935.  
  936.   if (GTK_TOGGLE_BUTTON (widget)->active)
  937.     {
  938.       *toggle_val = TRUE;
  939.       compose_idx = toggle_val - &(composeint.compose_flag[0]);
  940.       for (j = 0; j < MAX_COMPOSE_IMAGES; j++)
  941.     gtk_label_set_text (GTK_LABEL (composeint.channel_label[j]),
  942.                 compose_dsc[compose_idx].channel_name[j]);
  943.       
  944.       /* Set sensitivity of last label */
  945.       sensitive = (strcmp (compose_dsc[compose_idx].channel_name[3],
  946.                CHNL_NA) != 0);
  947.       gtk_widget_set_sensitive (composeint.channel_label[3], sensitive);
  948.       gtk_widget_set_sensitive (composeint.channel_menu[3], sensitive);
  949.     }
  950.   else
  951.     *toggle_val = FALSE;
  952. }
  953.