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

  1. /* Normalize 1.00 --- image filter plug-in for The GIMP
  2.  *
  3.  * Copyright (C) 1997 Adam D. Moss (adam@foxbox.org)
  4.  * Very largely based on Quartic's "Contrast Autostretch"
  5.  *
  6.  * This program is free software; you can redistribute it and/or modify
  7.  * it under the terms of the GNU General Public License as published by
  8.  * the Free Software Foundation; either version 2 of the License, or
  9.  * (at your option) any later version.
  10.  *
  11.  * This program is distributed in the hope that it will be useful,
  12.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.  * GNU General Public License for more details.
  15.  *
  16.  * You should have received a copy of the GNU General Public License
  17.  * along with this program; if not, write to the Free Software
  18.  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  19.  */
  20.  
  21.  
  22. /* This plugin performs almost the same operation as the 'contrast
  23.  * autostretch' plugin, except that it won't allow the colour channels
  24.  * to normalize independently.  This is actually what most people probably
  25.  * want instead of contrast-autostretch; use c-a only if you wish to remove
  26.  * an undesirable colour-tint from a source image which is supposed to
  27.  * contain pure-white and pure-black.
  28.  */
  29.  
  30. #include "config.h"
  31.  
  32. #include <stdlib.h>
  33. #include <stdio.h>
  34.  
  35. #include <libgimp/gimp.h>
  36.  
  37. #include "libgimp/stdplugins-intl.h"
  38.  
  39.  
  40. /* Declare local functions.
  41.  */
  42. static void      query  (void);
  43. static void      run    (gchar   *name,
  44.              gint     nparams,
  45.              GimpParam  *param,
  46.              gint    *nreturn_vals,
  47.              GimpParam **return_vals);
  48.  
  49. static void      norma         (GimpDrawable *drawable);
  50. static void      indexed_norma (gint32     image_ID);
  51.  
  52.  
  53. GimpPlugInInfo PLUG_IN_INFO =
  54. {
  55.   NULL,  /* init_proc  */
  56.   NULL,  /* quit_proc  */
  57.   query, /* query_proc */
  58.   run,   /* run_proc   */
  59. };
  60.  
  61.  
  62. MAIN ()
  63.  
  64. static void
  65. query (void)
  66. {
  67.   static GimpParamDef args[] =
  68.   {
  69.     { GIMP_PDB_INT32, "run_mode", "Interactive, non-interactive" },
  70.     { GIMP_PDB_IMAGE, "image", "Input image" },
  71.     { GIMP_PDB_DRAWABLE, "drawable", "Input drawable" }
  72.   };
  73.   static gint nargs = sizeof (args) / sizeof (args[0]);
  74.  
  75.   gimp_install_procedure ("plug_in_normalize",
  76.               "Normalize the contrast of the specified drawable to "
  77.               "cover all possible ranges.",
  78.               "This plugin performs almost the same operation as "
  79.               "the 'contrast autostretch' plugin, except that it "
  80.               "won't allow the color channels to normalize "
  81.               "independently.  This is actually what most people "
  82.               "probably want instead of contrast-autostretch; use "
  83.               "c-a only if you wish to remove an undesirable "
  84.               "color-tint from a source image which is supposed to "
  85.               "contain pure-white and pure-black.",
  86.               "Adam D. Moss, Federico Mena Quintero",
  87.               "Adam D. Moss, Federico Mena Quintero",
  88.               "1997",
  89.               N_("<Image>/Image/Colors/Auto/Normalize"),
  90.               "RGB*, GRAY*, INDEXED*",
  91.               GIMP_PLUGIN,
  92.               nargs, 0,
  93.               args, NULL);
  94. }
  95.  
  96. static void
  97. run (gchar   *name,
  98.      gint     nparams,
  99.      GimpParam  *param,
  100.      gint    *nreturn_vals,
  101.      GimpParam **return_vals)
  102. {
  103.   static GimpParam values[1];
  104.   GimpDrawable *drawable;
  105.   GimpRunModeType run_mode;
  106.   GimpPDBStatusType status = GIMP_PDB_SUCCESS;
  107.  
  108.   gint32 image_ID;
  109.  
  110.   INIT_I18N();
  111.  
  112.   run_mode = param[0].data.d_int32;
  113.  
  114.   /*  Get the specified drawable  */
  115.   drawable = gimp_drawable_get (param[2].data.d_drawable);
  116.   image_ID = param[1].data.d_image;
  117.  
  118.   /*  Make sure that the drawable is gray or RGB color  */
  119.   if (gimp_drawable_is_rgb (drawable->id) || gimp_drawable_is_gray (drawable->id))
  120.     {
  121.       gimp_progress_init (_("Normalizing..."));
  122.       gimp_tile_cache_ntiles (2 * (drawable->width / gimp_tile_width () + 1));
  123.       norma (drawable);
  124.  
  125.       if (run_mode != GIMP_RUN_NONINTERACTIVE)
  126.     gimp_displays_flush ();
  127.     }
  128.   else if (gimp_drawable_is_indexed (drawable->id))
  129.     {
  130.       indexed_norma (image_ID);
  131.       if (run_mode != GIMP_RUN_NONINTERACTIVE)
  132.     gimp_displays_flush ();
  133.     }
  134.   else
  135.     {
  136.       /* gimp_message ("normalize: cannot operate on indexed color images"); */
  137.       status = GIMP_PDB_EXECUTION_ERROR;
  138.     }
  139.  
  140.   *nreturn_vals = 1;
  141.   *return_vals = values;
  142.  
  143.   values[0].type = GIMP_PDB_STATUS;
  144.   values[0].data.d_status = status;
  145.  
  146.   gimp_drawable_detach (drawable);
  147. }
  148.  
  149.  
  150. static void
  151. indexed_norma (gint32 image_ID)  /* a.d.m. */
  152. {
  153.   guchar *cmap;
  154.   gint ncols,i;
  155.   gint hi=0,lo=255;
  156.  
  157.   cmap = gimp_image_get_cmap (image_ID, &ncols);
  158.  
  159.   if (cmap==NULL)
  160.     {
  161.       printf ("normalize: cmap was NULL!  Quitting...\n");
  162.       return;
  163.     }
  164.  
  165.   for (i=0;i<ncols;i++)
  166.     {
  167.       if (cmap[i*3 +0] > hi) hi=cmap[i*3 +0];
  168.       if (cmap[i*3 +1] > hi) hi=cmap[i*3 +1];
  169.       if (cmap[i*3 +2] > hi) hi=cmap[i*3 +2];
  170.       if (cmap[i*3 +0] < lo) lo=cmap[i*3 +0];
  171.       if (cmap[i*3 +1] < lo) lo=cmap[i*3 +1];
  172.       if (cmap[i*3 +2] < lo) lo=cmap[i*3 +2];
  173.     }
  174.  
  175.   if (hi!=lo)
  176.     for (i=0;i<ncols;i++)
  177.       {
  178.     cmap[i*3 +0] = (255 * (cmap[i*3 +0] - lo)) / (hi-lo);
  179.     cmap[i*3 +1] = (255 * (cmap[i*3 +1] - lo)) / (hi-lo);
  180.     cmap[i*3 +2] = (255 * (cmap[i*3 +2] - lo)) / (hi-lo);
  181.       }
  182.  
  183.   gimp_image_set_cmap (image_ID, cmap, ncols);
  184. }
  185.  
  186.  
  187. static void
  188. norma (GimpDrawable *drawable)
  189. {
  190.   GimpPixelRgn src_rgn, dest_rgn;
  191.   guchar *src, *s;
  192.   guchar *dest, *d;
  193.   guchar  min, max;
  194.   guchar  range;
  195.   guchar  lut[256];
  196.   gint    progress, max_progress;
  197.   gint    has_alpha, alpha;
  198.   gint    x1, y1, x2, y2;
  199.   gint    x, y, b;
  200.   gpointer pr;
  201.  
  202.   /* Get selection area */
  203.   gimp_drawable_mask_bounds (drawable->id, &x1, &y1, &x2, &y2);
  204.   has_alpha = gimp_drawable_has_alpha (drawable->id);
  205.   alpha = (has_alpha) ? drawable->bpp - 1 : drawable->bpp;
  206.  
  207.   /* Initialize progress */
  208.   progress = 0;
  209.   max_progress = (x2 - x1) * (y2 - y1) * 2;
  210.  
  211.   /* Get minimum and maximum values for each channel */
  212.   min = 255;
  213.   max = 0;
  214.  
  215.   gimp_pixel_rgn_init (&src_rgn, drawable,
  216.                x1, y1, (x2 - x1), (y2 - y1), FALSE, FALSE);
  217.  
  218.   for (pr = gimp_pixel_rgns_register (1, &src_rgn);
  219.        pr != NULL;
  220.        pr = gimp_pixel_rgns_process (pr))
  221.     {
  222.       src = src_rgn.data;
  223.  
  224.       for (y = 0; y < src_rgn.h; y++)
  225.     {
  226.       s = src;
  227.       for (x = 0; x < src_rgn.w; x++)
  228.         {
  229.           for (b = 0; b < alpha; b++)
  230.         {
  231.           if (!has_alpha || (has_alpha && s[alpha]))
  232.             {
  233.               if (s[b] < min)
  234.             min = s[b];
  235.               if (s[b] > max)
  236.             max = s[b];
  237.             }
  238.         }
  239.  
  240.           s += src_rgn.bpp;
  241.         }
  242.  
  243.       src += src_rgn.rowstride;
  244.     }
  245.  
  246.       /* Update progress */
  247.       progress += src_rgn.w * src_rgn.h;
  248.  
  249.       gimp_progress_update ((double) progress / (double) max_progress);
  250.     }
  251.  
  252.   /* Calculate LUT */
  253.  
  254.   range = max - min;
  255.  
  256.   if (range != 0)
  257.     for (x = min; x <= max; x++)
  258.       lut[x] = 255 * (x - min) / range;
  259.   else
  260.     lut[min] = min;
  261.  
  262.  
  263.   /* Now substitute pixel vales */
  264.   gimp_pixel_rgn_init (&src_rgn, drawable,
  265.                x1, y1, (x2 - x1), (y2 - y1), FALSE, FALSE);
  266.   gimp_pixel_rgn_init (&dest_rgn, drawable,
  267.                x1, y1, (x2 - x1), (y2 - y1), TRUE, TRUE);
  268.  
  269.   for (pr = gimp_pixel_rgns_register (2, &src_rgn, &dest_rgn);
  270.        pr != NULL;
  271.        pr = gimp_pixel_rgns_process (pr))
  272.     {
  273.       src = src_rgn.data;
  274.       dest = dest_rgn.data;
  275.  
  276.       for (y = 0; y < src_rgn.h; y++)
  277.     {
  278.       s = src;
  279.       d = dest;
  280.  
  281.       for (x = 0; x < src_rgn.w; x++)
  282.         {
  283.           for (b = 0; b < alpha; b++)
  284.         d[b] = lut[s[b]];
  285.  
  286.           if (has_alpha)
  287.         d[alpha] = s[alpha];
  288.  
  289.           s += src_rgn.bpp;
  290.           d += dest_rgn.bpp;
  291.         }
  292.  
  293.       src += src_rgn.rowstride;
  294.       dest += dest_rgn.rowstride;
  295.  
  296.     }
  297.  
  298.       /* Update progress */
  299.       progress += src_rgn.w * src_rgn.h;
  300.  
  301.       gimp_progress_update ((double) progress / (double) max_progress);
  302.     }
  303.  
  304.   /*  update the region  */
  305.   gimp_drawable_flush (drawable);
  306.   gimp_drawable_merge_shadow (drawable->id, TRUE);
  307.   gimp_drawable_update (drawable->id, x1, y1, (x2 - x1), (y2 - y1));
  308. }
  309.