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 / decompose.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-08-24  |  25.4 KB  |  940 lines

  1. /* The GIMP -- an image manipulation program
  2.  * Copyright (C) 1995 Spencer Kimball and Peter Mattis
  3.  *
  4.  * Decompose plug-in (C) 1997 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 filter decomposes RGB-images into several types of channels
  24.  */
  25.  
  26. /* Event history:
  27.  * V 1.00, PK, 29-Jul-97, Creation
  28.  * V 1.01, PK, 19-Mar-99, Update for GIMP V1.1.3
  29.  *                        Prepare for localization
  30.  *                        Use g_message() in interactive mode
  31.  */
  32. static char ident[] = "@(#) GIMP Decompose plug-in v1.01 19-Mar-99";
  33.  
  34. #ifdef HAVE_CONFIG_H
  35. #include "config.h"
  36. #endif
  37.  
  38. #include <stdio.h>
  39. #include <stdlib.h>
  40. #include <string.h>
  41. #include <ctype.h>
  42.  
  43. #include <gtk/gtk.h>
  44.  
  45. #include <libgimp/gimp.h>
  46. #include <libgimp/gimpui.h>
  47.  
  48. #include "libgimp/stdplugins-intl.h"
  49.  
  50.  
  51. /* Declare local functions
  52.  */
  53. static void      query  (void);
  54. static void      run    (gchar     *name,
  55.              gint       nparams,
  56.              GimpParam    *param,
  57.              gint      *nreturn_vals,
  58.              GimpParam   **return_vals);
  59.  
  60. static gint32    decompose (gint32  image_id,
  61.                             gint32  drawable_ID,
  62.                             gchar   *extract_type,
  63.                             gint32  *drawable_ID_dst);
  64.  
  65. static gint32 create_new_image (gchar       *filename,
  66.                 guint        width,
  67.                 guint        height,
  68.                 GimpImageBaseType   type,
  69.                 gint32      *layer_ID,
  70.                 GimpDrawable  **drawable,
  71.                 GimpPixelRgn   *pixel_rgn);
  72.  
  73. static void extract_rgb      (guchar *src, gint bpp, gint numpix, guchar **dst);
  74. static void extract_red      (guchar *src, gint bpp, gint numpix, guchar **dst);
  75. static void extract_green    (guchar *src, gint bpp, gint numpix, guchar **dst);
  76. static void extract_blue     (guchar *src, gint bpp, gint numpix, guchar **dst);
  77. static void extract_alpha    (guchar *src, gint bpp, gint numpix, guchar **dst);
  78. static void extract_hsv      (guchar *src, gint bpp, gint numpix, guchar **dst);
  79. static void extract_hue      (guchar *src, gint bpp, gint numpix, guchar **dst);
  80. static void extract_sat      (guchar *src, gint bpp, gint numpix, guchar **dst);
  81. static void extract_val      (guchar *src, gint bpp, gint numpix, guchar **dst);
  82. static void extract_cmy      (guchar *src, gint bpp, gint numpix, guchar **dst);
  83. static void extract_cyan     (guchar *src, gint bpp, gint numpix, guchar **dst);
  84. static void extract_magenta  (guchar *src, gint bpp, gint numpix, guchar **dst);
  85. static void extract_yellow   (guchar *src, gint bpp, gint numpix, guchar **dst);
  86. static void extract_cmyk     (guchar *src, gint bpp, gint numpix, guchar **dst);
  87. static void extract_cyank    (guchar *src, gint bpp, gint numpix, guchar **dst);
  88. static void extract_magentak (guchar *src, gint bpp, gint numpix, guchar **dst);
  89. static void extract_yellowk  (guchar *src, gint bpp, gint numpix, guchar **dst);
  90.  
  91. static gint decompose_dialog      (void);
  92. static void decompose_ok_callback (GtkWidget *widget,
  93.                    gpointer   data);
  94.  
  95. /* Maximum number of new images generated by an extraction */
  96. #define MAX_EXTRACT_IMAGES 4
  97.  
  98. /* Description of an extraction */
  99. typedef struct
  100. {
  101.   gchar *type;            /* What to extract */
  102.   gint   dialog;          /* Dialog-Flag. Set it to 1 if you want to appear */
  103.                           /* this extract function within the dialog */
  104.   gint   num_images;      /* Number of images to create */
  105.   gchar *channel_name[MAX_EXTRACT_IMAGES];   /* Names of channels to extract */
  106.                           /* Function that performs the extraction */
  107.   void (*extract_fun) (guchar *src, int bpp, gint numpix,
  108.             guchar **dst);
  109. } EXTRACT;
  110.  
  111. static EXTRACT extract[] =
  112. {
  113.   { N_("RGB"),        TRUE,  3, { N_("red"),
  114.                   N_("green"),
  115.                   N_("blue") }, extract_rgb },
  116.   { N_("Red"),        FALSE, 1, { N_("red") }, extract_red },
  117.   { N_("Green"),      FALSE, 1, { N_("green") }, extract_green },
  118.   { N_("Blue"),       FALSE, 1, { N_("blue") }, extract_blue },
  119.   { N_("HSV"),        TRUE,  3, { N_("hue"),
  120.                   N_("saturation"),
  121.                   N_("value") }, extract_hsv },
  122.   { N_("Hue"),        FALSE, 1, { N_("hue") }, extract_hue },
  123.   { N_("Saturation"), FALSE, 1, { N_("saturation") }, extract_sat },
  124.   { N_("Value"),      FALSE, 1, { N_("value") }, extract_val },
  125.   { N_("CMY"),        TRUE,  3, { N_("cyan"),
  126.                   N_("magenta"),
  127.                   N_("yellow") }, extract_cmy },
  128.   { N_("Cyan"),       FALSE, 1, { N_("cyan") }, extract_cyan },
  129.   { N_("Magenta"),    FALSE, 1, { N_("magenta") }, extract_magenta },
  130.   { N_("Yellow"),     FALSE, 1, { N_("yellow") }, extract_yellow },
  131.   { N_("CMYK"),       TRUE,  4, { N_("cyan_k"),
  132.                   N_("magenta_k"),
  133.                   N_("yellow_k"),
  134.                   N_("black") }, extract_cmyk },
  135.   { N_("Cyan_K"),     FALSE, 1, { N_("cyan_k") }, extract_cyank },
  136.   { N_("Magenta_K"),  FALSE, 1, { N_("magenta_k") }, extract_magentak },
  137.   { N_("Yellow_K"),   FALSE, 1, { N_("yellow_k") }, extract_yellowk },
  138.   { N_("Alpha"),      TRUE,  1, { N_("alpha") }, extract_alpha }
  139. };
  140.  
  141. /* Number of types of extractions */
  142. #define NUM_EXTRACT_TYPES (sizeof (extract) / sizeof (extract[0]))
  143.  
  144. typedef struct
  145. {
  146.   gchar extract_type[32];
  147. } DecoVals;
  148.  
  149. typedef struct
  150. {
  151.   gint extract_flag[NUM_EXTRACT_TYPES];
  152.   gint run;
  153. } DecoInterface;
  154.  
  155. GimpPlugInInfo PLUG_IN_INFO =
  156. {
  157.   NULL,  /* init_proc  */
  158.   NULL,  /* quit_proc  */
  159.   query, /* query_proc */
  160.   run,   /* run_proc   */
  161. };
  162.  
  163. static DecoVals decovals =
  164. {
  165.   "rgb"     /* Decompose type */
  166. };
  167.  
  168. static DecoInterface decoint =
  169. {
  170.   { 0 },    /*  extract flags */
  171.   FALSE     /*  run  */
  172. };
  173.  
  174. static GimpRunModeType run_mode;
  175.  
  176.  
  177. MAIN ()
  178.  
  179. static void
  180. query (void)
  181. {
  182.   static GimpParamDef args[] =
  183.   {
  184.     { GIMP_PDB_INT32, "run_mode", "Interactive, non-interactive" },
  185.     { GIMP_PDB_IMAGE, "image", "Input image (unused)" },
  186.     { GIMP_PDB_DRAWABLE, "drawable", "Input drawable" },
  187.     { GIMP_PDB_STRING, "decompose_type", "What to decompose: RGB, Red, Green, Blue, HSV, Hue, Saturation, Value, CMY, Cyan, Magenta, Yellow, CMYK, Cyan_K, Magenta_K, Yellow_K, Alpha" }
  188.   };
  189.   static GimpParamDef return_vals[] =
  190.   {
  191.     { GIMP_PDB_IMAGE, "new_image", "Output gray image" },
  192.     { GIMP_PDB_IMAGE, "new_image", "Output gray image (N/A for single channel extract)" },
  193.     { GIMP_PDB_IMAGE, "new_image", "Output gray image (N/A for single channel extract)" },
  194.     { GIMP_PDB_IMAGE, "new_image", "Output gray image (N/A for single channel extract)" }
  195.   };
  196.   static gint nargs = sizeof (args) / sizeof (args[0]);
  197.   static gint nreturn_vals = sizeof (return_vals) / sizeof (return_vals[0]);
  198.  
  199.   gimp_install_procedure ("plug_in_decompose",
  200.               "Decompose an image into different types of channels",
  201.               "This function creates new gray images with "
  202.               "different channel information in each of them",
  203.               "Peter Kirchgessner",
  204.               "Peter Kirchgessner (peter@kirchgessner.net)",
  205.               "1997",
  206.               N_("<Image>/Image/Mode/Decompose..."),
  207.               "RGB*",
  208.               GIMP_PLUGIN,
  209.               nargs, nreturn_vals,
  210.               args, return_vals);
  211. }
  212.  
  213. static void
  214. run (gchar   *name,
  215.      gint     nparams,
  216.      GimpParam  *param,
  217.      gint    *nreturn_vals,
  218.      GimpParam **return_vals)
  219. {
  220.   static GimpParam values[MAX_EXTRACT_IMAGES+1];
  221.   GimpPDBStatusType status = GIMP_PDB_SUCCESS;
  222.   GimpImageType drawable_type;
  223.   gint32 num_images;
  224.   gint32 image_ID_extract[MAX_EXTRACT_IMAGES];
  225.   gint j;
  226.  
  227.   INIT_I18N_UI();
  228.  
  229.   run_mode = param[0].data.d_int32;
  230.  
  231.   *nreturn_vals = MAX_EXTRACT_IMAGES+1;
  232.   *return_vals = values;
  233.  
  234.   values[0].type = GIMP_PDB_STATUS;
  235.   values[0].data.d_status = status;
  236.   for (j = 0; j < MAX_EXTRACT_IMAGES; j++)
  237.     {
  238.       values[j+1].type = GIMP_PDB_IMAGE;
  239.       values[j+1].data.d_int32 = -1;
  240.     }
  241.  
  242.   switch (run_mode)
  243.     {
  244.     case GIMP_RUN_INTERACTIVE:
  245.       /*  Possibly retrieve data  */
  246.       gimp_get_data ("plug_in_decompose", &decovals);
  247.  
  248.       /*  First acquire information with a dialog  */
  249.       if (! decompose_dialog ())
  250.     return;
  251.       break;
  252.  
  253.     case GIMP_RUN_NONINTERACTIVE:
  254.       /*  Make sure all the arguments are there!  */
  255.       if (nparams != 4)
  256.     {
  257.       status = GIMP_PDB_CALLING_ERROR;
  258.     }
  259.       else
  260.     {
  261.           strncpy (decovals.extract_type, param[3].data.d_string,
  262.                    sizeof (decovals.extract_type));
  263.           decovals.extract_type[sizeof (decovals.extract_type)-1] = '\0';
  264.     }
  265.       break;
  266.  
  267.     case GIMP_RUN_WITH_LAST_VALS:
  268.       /*  Possibly retrieve data  */
  269.       gimp_get_data ("plug_in_decompose", &decovals);
  270.       break;
  271.  
  272.     default:
  273.       break;
  274.     }
  275.  
  276.   /*  Make sure that the drawable is RGB color  */
  277.   drawable_type = gimp_drawable_type (param[2].data.d_drawable);
  278.   if ((drawable_type != GIMP_RGB_IMAGE) && (drawable_type != GIMP_RGBA_IMAGE))
  279.     {
  280.       g_message ("decompose: Can only work on RGB*_IMAGE");
  281.       status = GIMP_PDB_CALLING_ERROR;
  282.     }
  283.   if (status == GIMP_PDB_SUCCESS)
  284.     {
  285.       if (run_mode != GIMP_RUN_NONINTERACTIVE)
  286.         gimp_progress_init (_("Decomposing..."));
  287.       
  288.       num_images = decompose (param[1].data.d_image, param[2].data.d_drawable,
  289.                               decovals.extract_type, image_ID_extract);
  290.       
  291.       if (num_images <= 0)
  292.     {
  293.       status = GIMP_PDB_EXECUTION_ERROR;
  294.     }
  295.       else
  296.     {
  297.       for (j = 0; j < num_images; j++)
  298.         {
  299.           values[j+1].data.d_int32 = image_ID_extract[j];
  300.           gimp_image_undo_enable (image_ID_extract[j]);
  301.           gimp_image_clean_all (image_ID_extract[j]);
  302.           if (run_mode != GIMP_RUN_NONINTERACTIVE)
  303.         gimp_display_new (image_ID_extract[j]);
  304.         }
  305.       
  306.       /*  Store data  */
  307.       if (run_mode == GIMP_RUN_INTERACTIVE)
  308.         gimp_set_data ("plug_in_decompose", &decovals, sizeof (DecoVals));
  309.     }
  310.     }
  311.   
  312.   values[0].data.d_status = status;
  313. }
  314.  
  315.  
  316. /* Decompose an image. It returns the number of new (gray) images.
  317.    The image IDs for the new images are returned in image_ID_dst.
  318.    On failure, -1 is returned.
  319. */
  320. static gint32
  321. decompose (gint32  image_ID,
  322.            gint32  drawable_ID,
  323.            char   *extract_type,
  324.            gint32 *image_ID_dst)
  325. {
  326.   gint i, j, extract_idx, scan_lines;
  327.   gint height, width, tile_height, num_images;
  328.   guchar *src = (guchar *)ident;  /* Just to satisfy gcc/lint */
  329.   gchar *filename;
  330.   guchar *dst[MAX_EXTRACT_IMAGES];
  331.   gint32 layer_ID_dst[MAX_EXTRACT_IMAGES];
  332.   GimpDrawable *drawable_src, *drawable_dst[MAX_EXTRACT_IMAGES];
  333.   GimpPixelRgn pixel_rgn_src, pixel_rgn_dst[MAX_EXTRACT_IMAGES];
  334.  
  335.   extract_idx = -1;   /* Search extract type */
  336.   for (j = 0; j < NUM_EXTRACT_TYPES; j++)
  337.     {
  338.       if (g_strcasecmp (extract_type, extract[j].type) == 0)
  339.     {
  340.       extract_idx = j;
  341.       break;
  342.     }
  343.     }
  344.   if (extract_idx < 0) return (-1);
  345.   
  346.   /* Check structure of source image */
  347.   drawable_src = gimp_drawable_get (drawable_ID);
  348.   if (drawable_src->bpp < 3)
  349.     {
  350.       g_message ("decompose: not an RGB image");
  351.       return (-1);
  352.     }
  353.   if ((extract[extract_idx].extract_fun == extract_alpha) &&
  354.       (!gimp_drawable_has_alpha (drawable_ID)))
  355.     {
  356.       g_message ("decompose: No alpha channel available");
  357.       return (-1);
  358.     }
  359.   
  360.   width = drawable_src->width;
  361.   height = drawable_src->height;
  362.  
  363.   tile_height = gimp_tile_height ();
  364.   gimp_pixel_rgn_init (&pixel_rgn_src, drawable_src, 0, 0, width, height,
  365.                        FALSE, FALSE);
  366.  
  367.   /* allocate a buffer for retrieving information from the src pixel region  */
  368.   src = g_new (guchar, tile_height * width * drawable_src->bpp);
  369.  
  370.   /* Create all new gray images */
  371.   num_images = extract[extract_idx].num_images;
  372.   if (num_images > MAX_EXTRACT_IMAGES) 
  373.     num_images = MAX_EXTRACT_IMAGES;
  374.   
  375.   for (j = 0; j < num_images; j++)
  376.     {
  377.       /* Build a filename like <imagename>-<channel>.<extension> */
  378.       char *fname = g_strdup (gimp_image_get_filename (image_ID));
  379.       char *extension = fname + strlen (fname) - 1;
  380.  
  381.       while (extension >= fname)
  382.       {
  383.         if (*extension == '.') break;
  384.         extension--;
  385.       }
  386.       if (extension >= fname)
  387.       {
  388.         *(extension++) = '\0';
  389.         filename = g_strdup_printf ("%s-%s.%s", fname,
  390.              gettext (extract[extract_idx].channel_name[j]),
  391.              extension);
  392.       }
  393.       else
  394.       {
  395.         filename = g_strdup_printf ("%s-%s", fname,
  396.              gettext (extract[extract_idx].channel_name[j]));
  397.       }
  398.  
  399.       image_ID_dst[j] = create_new_image (filename, width, height, GIMP_GRAY,
  400.                       layer_ID_dst+j, drawable_dst+j,
  401.                       pixel_rgn_dst+j);
  402.       g_free (filename);
  403.       g_free (fname);
  404.       dst[j] = g_new (guchar, tile_height * width);
  405.     }
  406.   
  407.   i = 0;
  408.   while (i < height)
  409.     {
  410.       /* Get source pixel region */
  411.       scan_lines = (i+tile_height-1 < height) ? tile_height : (height-i);
  412.       gimp_pixel_rgn_get_rect (&pixel_rgn_src, src, 0, i, width, scan_lines);
  413.       
  414.       /* Extract the channel information */
  415.       extract[extract_idx].extract_fun (src, drawable_src->bpp, scan_lines*width,
  416.                     dst);
  417.       
  418.       /* Set destination pixel regions */
  419.       for (j = 0; j < num_images; j++)
  420.     gimp_pixel_rgn_set_rect (&(pixel_rgn_dst[j]), dst[j], 0, i, width,
  421.                  scan_lines);
  422.       i += scan_lines;
  423.       
  424.       if (run_mode != GIMP_RUN_NONINTERACTIVE)
  425.     gimp_progress_update (((gdouble)i) / (gdouble)height);
  426.     }
  427.   g_free (src);
  428.   for (j = 0; j < num_images; j++)
  429.     {
  430.       gimp_drawable_flush (drawable_dst[j]);
  431.       gimp_drawable_detach (drawable_dst[j]);
  432.       g_free (dst[j]);
  433.     }
  434.   
  435.   gimp_drawable_flush (drawable_src);
  436.   gimp_drawable_detach (drawable_src);
  437.   
  438.   return (num_images);
  439. }
  440.  
  441.  
  442. /* Create an image. Sets layer_ID, drawable and rgn. Returns image_ID */
  443. static gint32
  444. create_new_image (gchar       *filename,
  445.                   guint        width,
  446.                   guint        height,
  447.                   GimpImageBaseType   type,
  448.                   gint32      *layer_ID,
  449.                   GimpDrawable  **drawable,
  450.                   GimpPixelRgn   *pixel_rgn)
  451. {
  452.   gint32 image_ID;
  453.   GimpImageType gdtype;
  454.   
  455.   if (type == GIMP_GRAY) 
  456.     gdtype = GIMP_GRAY_IMAGE;
  457.   else if (type == GIMP_INDEXED) 
  458.     gdtype = GIMP_INDEXED_IMAGE;
  459.   else 
  460.     gdtype = GIMP_RGB_IMAGE;
  461.   
  462.   image_ID = gimp_image_new (width, height, type);
  463.   gimp_image_set_filename (image_ID, filename);
  464.   
  465.   *layer_ID = gimp_layer_new (image_ID, _("Background"), width, height,
  466.                   gdtype, 100, GIMP_NORMAL_MODE);
  467.   gimp_image_add_layer (image_ID, *layer_ID, 0);
  468.   
  469.   *drawable = gimp_drawable_get (*layer_ID);
  470.   gimp_pixel_rgn_init (pixel_rgn, *drawable, 0, 0, (*drawable)->width,
  471.                (*drawable)->height, TRUE, FALSE);
  472.   
  473.   return (image_ID);
  474. }
  475.  
  476.  
  477. /* Extract functions */
  478.  
  479. static void 
  480. extract_rgb (guchar  *src, 
  481.          gint     bpp, 
  482.          gint     numpix,
  483.          guchar **dst)
  484. {
  485.   register guchar *rgb_src = src;
  486.   register guchar *red_dst = dst[0];
  487.   register guchar *green_dst = dst[1];
  488.   register guchar *blue_dst = dst[2];
  489.   register gint count = numpix, offset = bpp-3;
  490.   
  491.   while (count-- > 0)
  492.     {
  493.       *(red_dst++) = *(rgb_src++);
  494.       *(green_dst++) = *(rgb_src++);
  495.       *(blue_dst++) = *(rgb_src++);
  496.       rgb_src += offset;
  497.     }
  498. }
  499.  
  500.  
  501. static void 
  502. extract_red (guchar  *src, 
  503.          gint     bpp, 
  504.          gint     numpix,
  505.          guchar **dst)
  506. {
  507.   register guchar *rgb_src = src;
  508.   register guchar *red_dst = dst[0];
  509.   register gint count = numpix, offset = bpp;
  510.   
  511.   while (count-- > 0)
  512.     {
  513.       *(red_dst++) = *rgb_src;
  514.       rgb_src += offset;
  515.     }
  516. }
  517.  
  518.  
  519. static void 
  520. extract_green (guchar  *src, 
  521.            gint     bpp, 
  522.            gint     numpix,
  523.            guchar **dst)
  524. {
  525.   register guchar *rgb_src = src+1;
  526.   register guchar *green_dst = dst[0];
  527.   register gint count = numpix, offset = bpp;
  528.   
  529.   while (count-- > 0)
  530.     {
  531.       *(green_dst++) = *rgb_src;
  532.       rgb_src += offset;
  533.     }
  534. }
  535.  
  536.  
  537. static void 
  538. extract_blue (guchar  *src, 
  539.           gint     bpp, 
  540.           gint     numpix,
  541.           guchar **dst)
  542. {
  543.   register guchar *rgb_src = src+2;
  544.   register guchar *blue_dst = dst[0];
  545.   register gint count = numpix, offset = bpp;
  546.   
  547.   while (count-- > 0)
  548.     {
  549.       *(blue_dst++) = *rgb_src;
  550.       rgb_src += offset;
  551.     }
  552. }
  553.  
  554.  
  555. static void 
  556. extract_alpha (guchar  *src, 
  557.            gint     bpp, 
  558.            gint     numpix,
  559.            guchar **dst)
  560. {
  561.   register guchar *rgb_src = src+3;
  562.   register guchar *alpha_dst = dst[0];
  563.   register gint count = numpix, offset = bpp;
  564.   
  565.   while (count-- > 0)
  566.     {
  567.       *(alpha_dst++) = *rgb_src;
  568.       rgb_src += offset;
  569.     }
  570. }
  571.  
  572.  
  573. static void
  574. extract_cmy (guchar  *src, 
  575.          gint     bpp, 
  576.          gint     numpix,
  577.          guchar **dst)
  578. {
  579.   register guchar *rgb_src = src;
  580.   register guchar *cyan_dst = dst[0];
  581.   register guchar *magenta_dst = dst[1];
  582.   register guchar *yellow_dst = dst[2];
  583.   register gint count = numpix, offset = bpp-3;
  584.   
  585.   while (count-- > 0)
  586.     {
  587.       *(cyan_dst++) = 255 - *(rgb_src++);
  588.       *(magenta_dst++) = 255 - *(rgb_src++);
  589.       *(yellow_dst++) = 255 - *(rgb_src++);
  590.       rgb_src += offset;
  591.     }
  592. }
  593.  
  594.  
  595. static void 
  596. extract_hsv (guchar  *src, 
  597.          gint     bpp, 
  598.          gint     numpix,
  599.          guchar **dst)
  600. {
  601.   register guchar *rgb_src = src;
  602.   register guchar *hue_dst = dst[0];
  603.   register guchar *sat_dst = dst[1];
  604.   register guchar *val_dst = dst[2];
  605.   register gint count = numpix, offset = bpp;
  606.   gdouble hue, sat, val;
  607.   
  608.   while (count-- > 0)
  609.     {
  610.       gimp_rgb_to_hsv4 (rgb_src, &hue, &sat, &val);
  611.       *hue_dst++ = (guchar) (hue * 255.999);
  612.       *sat_dst++ = (guchar) (sat * 255.999);
  613.       *val_dst++ = (guchar) (val * 255.999);
  614.       rgb_src += offset;
  615.     }
  616. }
  617.  
  618.  
  619. static void 
  620. extract_hue (guchar  *src, 
  621.          gint     bpp, 
  622.          gint     numpix,
  623.          guchar **dst)
  624. {
  625.   register guchar *rgb_src = src;
  626.   register guchar *hue_dst = dst[0];
  627.   register gint count = numpix, offset = bpp;
  628.   gdouble hue, dummy;
  629.   
  630.   while (count-- > 0)
  631.     {
  632.       gimp_rgb_to_hsv4 (rgb_src, &hue, &dummy, &dummy);
  633.       *hue_dst++ = (guchar) (hue * 255.999);
  634.       rgb_src += offset;
  635.     }
  636. }
  637.  
  638.  
  639. static void 
  640. extract_sat (guchar  *src, 
  641.          gint     bpp, 
  642.          gint     numpix,
  643.          guchar **dst)
  644. {
  645.   register guchar *rgb_src = src;
  646.   register guchar *sat_dst = dst[0];
  647.   register gint count = numpix, offset = bpp;
  648.   gdouble sat, dummy;
  649.   
  650.   while (count-- > 0)
  651.     {
  652.       gimp_rgb_to_hsv4 (rgb_src, &dummy, &sat, &dummy);
  653.       *sat_dst++ = (guchar) (sat * 255.999);
  654.       rgb_src += offset;
  655.     }
  656. }
  657.  
  658.  
  659. static void 
  660. extract_val (guchar  *src, 
  661.          gint     bpp, 
  662.          gint     numpix,
  663.          guchar **dst)
  664. {
  665.   register guchar *rgb_src = src;
  666.   register guchar *val_dst = dst[0];
  667.   register gint count = numpix, offset = bpp;
  668.   gdouble val, dummy;
  669.   
  670.   while (count-- > 0)
  671.     {
  672.       gimp_rgb_to_hsv4 (rgb_src, &dummy, &dummy, &val);
  673.       *val_dst++ = (guchar) (val * 255.999);
  674.       rgb_src += offset;
  675.     }
  676. }
  677.  
  678.  
  679. static void 
  680. extract_cyan (guchar  *src, 
  681.           gint     bpp, 
  682.           gint     numpix,
  683.           guchar **dst)
  684. {
  685.   register guchar *rgb_src = src;
  686.   register guchar *cyan_dst = dst[0];
  687.   register gint count = numpix, offset = bpp-1;
  688.   
  689.   while (count-- > 0)
  690.     {
  691.       *(cyan_dst++) = 255 - *(rgb_src++);
  692.       rgb_src += offset;
  693.     }
  694. }
  695.  
  696.  
  697. static void 
  698. extract_magenta (guchar  *src, 
  699.          gint     bpp, 
  700.          gint     numpix,
  701.          guchar **dst)
  702. {
  703.   register guchar *rgb_src = src+1;
  704.   register guchar *magenta_dst = dst[0];
  705.   register gint count = numpix, offset = bpp-1;
  706.   
  707.   while (count-- > 0)
  708.     {
  709.       *(magenta_dst++) = 255 - *(rgb_src++);
  710.       rgb_src += offset;
  711.     }
  712. }
  713.  
  714.  
  715. static void 
  716. extract_yellow (guchar  *src, 
  717.         gint     bpp, 
  718.         gint     numpix,
  719.         guchar **dst)
  720. {
  721.   register guchar *rgb_src = src+2;
  722.   register guchar *yellow_dst = dst[0];
  723.   register gint count = numpix, offset = bpp-1;
  724.   
  725.   while (count-- > 0)
  726.     {
  727.       *(yellow_dst++) = 255 - *(rgb_src++);
  728.       rgb_src += offset;
  729.     }
  730. }
  731.  
  732.  
  733. static void 
  734. extract_cmyk (guchar  *src, 
  735.           gint     bpp, 
  736.           gint     numpix,
  737.           guchar **dst)
  738.  
  739. {
  740.   register guchar *rgb_src = src;
  741.   register guchar *cyan_dst = dst[0];
  742.   register guchar *magenta_dst = dst[1];
  743.   register guchar *yellow_dst = dst[2];
  744.   register guchar *black_dst = dst[3];
  745.   register guchar k, s;
  746.   register gint count = numpix, offset = bpp-3;
  747.   
  748.   while (count-- > 0)
  749.     {
  750.       *cyan_dst = k = 255 - *(rgb_src++);
  751.       *magenta_dst = s = 255 - *(rgb_src++);
  752.       if (s < k) 
  753.     k = s;
  754.       *yellow_dst = s = 255 - *(rgb_src++);
  755.       if (s < k) 
  756.     k = s;                /* Black intensity is minimum of c, m, y */
  757.       if (k)
  758.     {
  759.       *cyan_dst -= k;     /* Remove common part of c, m, y */
  760.       *magenta_dst -= k;
  761.       *yellow_dst -= k;
  762.     }
  763.       cyan_dst++;
  764.       magenta_dst++;
  765.       yellow_dst++;
  766.       *(black_dst++) = k;
  767.       
  768.       rgb_src += offset;
  769.     }
  770. }
  771.  
  772.  
  773. static void 
  774. extract_cyank (guchar  *src, 
  775.            gint     bpp, 
  776.            gint     numpix,
  777.            guchar **dst)
  778. {
  779.   register guchar *rgb_src = src;
  780.   register guchar *cyan_dst = dst[0];
  781.   register guchar s, k;
  782.   register gint count = numpix, offset = bpp-3;
  783.   
  784.   while (count-- > 0)
  785.     {
  786.       *cyan_dst = k = 255 - *(rgb_src++);
  787.       s = 255 - *(rgb_src++);  /* magenta */
  788.       if (s < k) k = s;
  789.       s = 255 - *(rgb_src++);  /* yellow */
  790.       if (s < k) k = s;
  791.       if (k) *cyan_dst -= k;
  792.       cyan_dst++;
  793.       
  794.       rgb_src += offset;
  795.     }
  796. }
  797.  
  798.  
  799. static void 
  800. extract_magentak (guchar  *src, 
  801.           gint     bpp, 
  802.           gint     numpix,
  803.           guchar **dst)
  804. {
  805.   register guchar *rgb_src = src;
  806.   register guchar *magenta_dst = dst[0];
  807.   register guchar s, k;
  808.   register gint count = numpix, offset = bpp-3;
  809.   
  810.   while (count-- > 0)
  811.     {
  812.       k = 255 - *(rgb_src++);  /* cyan */
  813.       *magenta_dst = s = 255 - *(rgb_src++);  /* magenta */
  814.       if (s < k) 
  815.     k = s;
  816.       s = 255 - *(rgb_src++);  /* yellow */
  817.       if (s < k) 
  818.     k = s;
  819.       if (k) 
  820.     *magenta_dst -= k;
  821.       magenta_dst++;
  822.       
  823.       rgb_src += offset;
  824.     }
  825. }
  826.  
  827.  
  828. static void 
  829. extract_yellowk (guchar  *src, 
  830.          gint     bpp, 
  831.          gint     numpix,
  832.          guchar **dst)
  833.  
  834. {
  835.   register guchar *rgb_src = src;
  836.   register guchar *yellow_dst = dst[0];
  837.   register guchar s, k;
  838.   register gint count = numpix, offset = bpp-3;
  839.   
  840.   while (count-- > 0)
  841.     {
  842.       k = 255 - *(rgb_src++);  /* cyan */
  843.       s = 255 - *(rgb_src++);  /* magenta */
  844.       if (s < k) k = s;
  845.       *yellow_dst = s = 255 - *(rgb_src++);
  846.       if (s < k) 
  847.     k = s;
  848.       if (k) 
  849.     *yellow_dst -= k;
  850.       yellow_dst++;
  851.       
  852.       rgb_src += offset;
  853.     }
  854. }
  855.  
  856.  
  857. static gint
  858. decompose_dialog (void)
  859. {
  860.   GtkWidget *dlg;
  861.   GtkWidget *toggle;
  862.   GtkWidget *frame;
  863.   GtkWidget *vbox;
  864.   GSList *group;
  865.   gint    j;
  866.  
  867.   gimp_ui_init ("decompose", FALSE);
  868.  
  869.   dlg = gimp_dialog_new (_("Decompose"), "decompose",
  870.              gimp_standard_help_func, "filters/decompose.html",
  871.              GTK_WIN_POS_MOUSE,
  872.              FALSE, TRUE, FALSE,
  873.  
  874.              _("OK"), decompose_ok_callback,
  875.              NULL, NULL, NULL, TRUE, FALSE,
  876.              _("Cancel"), gtk_widget_destroy,
  877.              NULL, 1, NULL, FALSE, TRUE,
  878.  
  879.              NULL);
  880.  
  881.   gtk_signal_connect (GTK_OBJECT (dlg), "destroy",
  882.               GTK_SIGNAL_FUNC (gtk_main_quit),
  883.               NULL);
  884.  
  885.   /*  parameter settings  */
  886.   frame = gtk_frame_new (_("Extract Channels:"));
  887.   gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_IN);
  888.   gtk_container_set_border_width (GTK_CONTAINER (frame), 6);
  889.   gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dlg)->vbox), frame, TRUE, TRUE, 0);
  890.  
  891.   vbox = gtk_vbox_new (FALSE, 1);
  892.   gtk_container_set_border_width (GTK_CONTAINER (vbox), 2);
  893.   gtk_container_add (GTK_CONTAINER (frame), vbox);
  894.  
  895.   group = NULL;
  896.   for (j = 0; j < NUM_EXTRACT_TYPES; j++)
  897.     {
  898.       if (!extract[j].dialog) 
  899.     continue;
  900.       toggle = gtk_radio_button_new_with_label (group, gettext (extract[j].type));
  901.       group = gtk_radio_button_group (GTK_RADIO_BUTTON (toggle));
  902.       gtk_box_pack_start (GTK_BOX (vbox), toggle, TRUE, TRUE, 0);
  903.       decoint.extract_flag[j] =
  904.     (g_strcasecmp (decovals.extract_type, extract[j].type) == 0);
  905.       gtk_signal_connect (GTK_OBJECT (toggle), "toggled",
  906.               GTK_SIGNAL_FUNC (gimp_toggle_button_update),
  907.               &(decoint.extract_flag[j]));
  908.       gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle),
  909.                     decoint.extract_flag[j]);
  910.       gtk_widget_show (toggle);
  911.     }
  912.   gtk_widget_show (vbox);
  913.   gtk_widget_show (frame);
  914.   gtk_widget_show (dlg);
  915.  
  916.   gtk_main ();
  917.   gdk_flush ();
  918.  
  919.   return decoint.run;
  920. }
  921.  
  922. static void
  923. decompose_ok_callback (GtkWidget *widget,
  924.                gpointer   data)
  925. {
  926.   gint j;
  927.  
  928.   decoint.run = TRUE;
  929.   gtk_widget_destroy (GTK_WIDGET (data));
  930.  
  931.   for (j = 0; j < NUM_EXTRACT_TYPES; j++)
  932.     {
  933.       if (decoint.extract_flag[j])
  934.     {
  935.       strcpy (decovals.extract_type, extract[j].type);
  936.       break;
  937.     }
  938.     }
  939. }
  940.