/* The GIMP -- an image manipulation program
 * Copyright (C) 1995-2003 Spencer Kimball and Peter Mattis
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (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
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */

/* NOTE: This file is autogenerated by pdbgen.pl. */

#include "config.h"


#include <glib-object.h>

#include "pdb-types.h"
#include "gimppdb.h"
#include "gimpprocedure.h"
#include "core/gimpparamspecs.h"

#include "base/color-balance.h"
#include "base/colorize.h"
#include "base/curves.h"
#include "base/gimphistogram.h"
#include "base/gimplut.h"
#include "base/hue-saturation.h"
#include "base/levels.h"
#include "base/lut-funcs.h"
#include "base/pixel-processor.h"
#include "base/pixel-region.h"
#include "base/threshold.h"
#include "core/gimp.h"
#include "core/gimpdrawable-desaturate.h"
#include "core/gimpdrawable-equalize.h"
#include "core/gimpdrawable-histogram.h"
#include "core/gimpdrawable-invert.h"
#include "core/gimpdrawable-levels.h"
#include "core/gimpdrawable.h"
#include "core/gimpimage.h"
#include "gimp-intl.h"


static GValueArray *
brightness_contrast_invoker (GimpProcedure     *procedure,
                             Gimp              *gimp,
                             GimpContext       *context,
                             GimpProgress      *progress,
                             const GValueArray *args)
{
  gboolean success = TRUE;
  GimpDrawable *drawable;
  gint32 brightness;
  gint32 contrast;

  drawable = gimp_value_get_drawable (&args->values[0], gimp);
  brightness = g_value_get_int (&args->values[1]);
  contrast = g_value_get_int (&args->values[2]);

  if (success)
    {
      if (! gimp_item_is_attached (GIMP_ITEM (drawable)) ||
          gimp_drawable_is_indexed (drawable))
        success = FALSE;

      if (success)
        {
          gint x, y, width, height;

          /* The application should occur only within selection bounds */
          if (gimp_drawable_mask_intersect (drawable, &x, &y, &width, &height))
            {
              GimpLut     *lut;
              PixelRegion  srcPR, destPR;

              lut = brightness_contrast_lut_new (brightness / 255.0,
                                                 contrast / 127.0,
                                                 gimp_drawable_bytes (drawable));

              pixel_region_init (&srcPR, gimp_drawable_get_tiles (drawable),
                                 x, y, width, height, FALSE);
              pixel_region_init (&destPR, gimp_drawable_get_shadow_tiles (drawable),
                                 x, y, width, height, TRUE);

              pixel_regions_process_parallel ((PixelProcessorFunc)
                                              gimp_lut_process,
                                              lut, 2, &srcPR, &destPR);

              gimp_lut_free (lut);

              gimp_drawable_merge_shadow (drawable, TRUE, _("Brightness-Contrast"));
              gimp_drawable_update (drawable, x, y, width, height);
            }
        }
    }

  return gimp_procedure_get_return_values (procedure, success);
}

static GValueArray *
levels_invoker (GimpProcedure     *procedure,
                Gimp              *gimp,
                GimpContext       *context,
                GimpProgress      *progress,
                const GValueArray *args)
{
  gboolean success = TRUE;
  GimpDrawable *drawable;
  gint32 channel;
  gint32 low_input;
  gint32 high_input;
  gdouble gamma;
  gint32 low_output;
  gint32 high_output;

  drawable = gimp_value_get_drawable (&args->values[0], gimp);
  channel = g_value_get_enum (&args->values[1]);
  low_input = g_value_get_int (&args->values[2]);
  high_input = g_value_get_int (&args->values[3]);
  gamma = g_value_get_double (&args->values[4]);
  low_output = g_value_get_int (&args->values[5]);
  high_output = g_value_get_int (&args->values[6]);

  if (success)
    {
      if (! gimp_item_is_attached (GIMP_ITEM (drawable)) ||
          gimp_drawable_is_indexed (drawable) ||
          (! gimp_drawable_has_alpha (drawable) &&
           channel == GIMP_HISTOGRAM_ALPHA) ||
          (gimp_drawable_is_gray (drawable) &&
           channel != GIMP_HISTOGRAM_VALUE && channel != GIMP_HISTOGRAM_ALPHA))
        success = FALSE;

      if (success)
        gimp_drawable_levels (drawable, context,
                              channel,
                              low_input, high_input,
                              gamma,
                              low_output, high_output);
    }

  return gimp_procedure_get_return_values (procedure, success);
}

static GValueArray *
levels_auto_invoker (GimpProcedure     *procedure,
                     Gimp              *gimp,
                     GimpContext       *context,
                     GimpProgress      *progress,
                     const GValueArray *args)
{
  gboolean success = TRUE;
  GimpDrawable *drawable;

  drawable = gimp_value_get_drawable (&args->values[0], gimp);

  if (success)
    {
      if (! gimp_item_is_attached (GIMP_ITEM (drawable)) ||
          gimp_drawable_is_indexed (drawable))
        success = FALSE;

      if (success)
        gimp_drawable_levels_stretch (drawable, context);
    }

  return gimp_procedure_get_return_values (procedure, success);
}

static GValueArray *
levels_stretch_invoker (GimpProcedure     *procedure,
                        Gimp              *gimp,
                        GimpContext       *context,
                        GimpProgress      *progress,
                        const GValueArray *args)
{
  gboolean success = TRUE;
  GimpDrawable *drawable;

  drawable = gimp_value_get_drawable (&args->values[0], gimp);

  if (success)
    {
      if (! gimp_item_is_attached (GIMP_ITEM (drawable)) ||
          gimp_drawable_is_indexed (drawable))
        success = FALSE;

      if (success)
        gimp_drawable_levels_stretch (drawable, context);
    }

  return gimp_procedure_get_return_values (procedure, success);
}

static GValueArray *
posterize_invoker (GimpProcedure     *procedure,
                   Gimp              *gimp,
                   GimpContext       *context,
                   GimpProgress      *progress,
                   const GValueArray *args)
{
  gboolean success = TRUE;
  GimpDrawable *drawable;
  gint32 levels;

  drawable = gimp_value_get_drawable (&args->values[0], gimp);
  levels = g_value_get_int (&args->values[1]);

  if (success)
    {
      if (! gimp_item_is_attached (GIMP_ITEM (drawable)) ||
          gimp_drawable_is_indexed (drawable))
        success = FALSE;

      if (success)
        {
          gint x, y, width, height;

          /* The application should occur only within selection bounds */
          if (gimp_drawable_mask_intersect (drawable, &x, &y, &width, &height))
            {
              GimpLut     *lut;
              PixelRegion  srcPR, destPR;

              lut = posterize_lut_new (levels, gimp_drawable_bytes (drawable));

              pixel_region_init (&srcPR, gimp_drawable_get_tiles (drawable),
                                 x, y, width, height, FALSE);
              pixel_region_init (&destPR, gimp_drawable_get_shadow_tiles (drawable),
                                 x, y, width, height, TRUE);

              pixel_regions_process_parallel ((PixelProcessorFunc)
                                              gimp_lut_process,
                                              lut, 2, &srcPR, &destPR);

              gimp_lut_free (lut);

              gimp_drawable_merge_shadow (drawable, TRUE, _("Posterize"));
              gimp_drawable_update (drawable, x, y, width, height);
            }
        }
    }

  return gimp_procedure_get_return_values (procedure, success);
}

static GValueArray *
desaturate_invoker (GimpProcedure     *procedure,
                    Gimp              *gimp,
                    GimpContext       *context,
                    GimpProgress      *progress,
                    const GValueArray *args)
{
  gboolean success = TRUE;
  GimpDrawable *drawable;

  drawable = gimp_value_get_drawable (&args->values[0], gimp);

  if (success)
    {
      if (! gimp_item_is_attached (GIMP_ITEM (drawable)) ||
          ! gimp_drawable_is_rgb (drawable))
        success = FALSE;

      if (success)
        gimp_drawable_desaturate (drawable, GIMP_DESATURATE_LIGHTNESS);
    }

  return gimp_procedure_get_return_values (procedure, success);
}

static GValueArray *
desaturate_full_invoker (GimpProcedure     *procedure,
                         Gimp              *gimp,
                         GimpContext       *context,
                         GimpProgress      *progress,
                         const GValueArray *args)
{
  gboolean success = TRUE;
  GimpDrawable *drawable;
  gint32 desaturate_mode;

  drawable = gimp_value_get_drawable (&args->values[0], gimp);
  desaturate_mode = g_value_get_enum (&args->values[1]);

  if (success)
    {
      if (! gimp_item_is_attached (GIMP_ITEM (drawable)) ||
          ! gimp_drawable_is_rgb (drawable))
        success = FALSE;

      if (success)
        gimp_drawable_desaturate (drawable, desaturate_mode);
    }

  return gimp_procedure_get_return_values (procedure, success);
}

static GValueArray *
equalize_invoker (GimpProcedure     *procedure,
                  Gimp              *gimp,
                  GimpContext       *context,
                  GimpProgress      *progress,
                  const GValueArray *args)
{
  gboolean success = TRUE;
  GimpDrawable *drawable;
  gboolean mask_only;

  drawable = gimp_value_get_drawable (&args->values[0], gimp);
  mask_only = g_value_get_boolean (&args->values[1]);

  if (success)
    {
      if (! gimp_item_is_attached (GIMP_ITEM (drawable)) ||
          gimp_drawable_is_indexed (drawable))
        success = FALSE;

      if (success)
        gimp_drawable_equalize (drawable, mask_only);
    }

  return gimp_procedure_get_return_values (procedure, success);
}

static GValueArray *
invert_invoker (GimpProcedure     *procedure,
                Gimp              *gimp,
                GimpContext       *context,
                GimpProgress      *progress,
                const GValueArray *args)
{
  gboolean success = TRUE;
  GimpDrawable *drawable;

  drawable = gimp_value_get_drawable (&args->values[0], gimp);

  if (success)
    {
      if (! gimp_item_is_attached (GIMP_ITEM (drawable)) ||
          gimp_drawable_is_indexed (drawable))
        success = FALSE;

      if (success)
        gimp_drawable_invert (drawable);
    }

  return gimp_procedure_get_return_values (procedure, success);
}

static GValueArray *
curves_spline_invoker (GimpProcedure     *procedure,
                       Gimp              *gimp,
                       GimpContext       *context,
                       GimpProgress      *progress,
                       const GValueArray *args)
{
  gboolean success = TRUE;
  GimpDrawable *drawable;
  gint32 channel;
  gint32 num_points;
  const guint8 *control_pts;

  drawable = gimp_value_get_drawable (&args->values[0], gimp);
  channel = g_value_get_enum (&args->values[1]);
  num_points = g_value_get_int (&args->values[2]);
  control_pts = gimp_value_get_int8array (&args->values[3]);

  if (success)
    {
      if (! gimp_item_is_attached (GIMP_ITEM (drawable)) ||
          gimp_drawable_is_indexed (drawable) || (num_points & 1) ||
          (! gimp_drawable_has_alpha (drawable) &&
           channel == GIMP_HISTOGRAM_ALPHA) ||
          (gimp_drawable_is_gray (drawable) &&
           channel != GIMP_HISTOGRAM_VALUE && channel != GIMP_HISTOGRAM_ALPHA))
        success = FALSE;

      if (success)
        {
          gint x, y, width, height;

          /* The application should occur only within selection bounds */
          if (gimp_drawable_mask_intersect (drawable, &x, &y, &width, &height))
            {
              Curves       c;
              gint         j;
              PixelRegion  srcPR, destPR;
              GimpLut     *lut;

              /* FIXME: hack */
              if (gimp_drawable_is_gray (drawable) &&
                  channel == GIMP_HISTOGRAM_ALPHA)
                channel = 1;

              lut = gimp_lut_new ();

              curves_init (&c);

              /*  unset the last point  */
              c.points[channel][CURVES_NUM_POINTS - 1][0] = -1;
              c.points[channel][CURVES_NUM_POINTS - 1][1] = -1;

              for (j = 0; j < num_points / 2; j++)
                {
                  c.points[channel][j][0] = control_pts[j * 2];
                  c.points[channel][j][1] = control_pts[j * 2 + 1];
                }

              curves_calculate_curve (&c, channel);

              gimp_lut_setup (lut,
                              (GimpLutFunc) curves_lut_func,
                              &c,
                              gimp_drawable_bytes (drawable));

              pixel_region_init (&srcPR, gimp_drawable_get_tiles (drawable),
                                 x, y, width, height, FALSE);
              pixel_region_init (&destPR, gimp_drawable_get_shadow_tiles (drawable),
                                 x, y, width, height, TRUE);

              pixel_regions_process_parallel ((PixelProcessorFunc)
                                              gimp_lut_process,
                                              lut, 2, &srcPR, &destPR);

              gimp_lut_free (lut);

              gimp_drawable_merge_shadow (drawable, TRUE, _("Curves"));
              gimp_drawable_update (drawable, x, y, width, height);
            }
        }
    }

  return gimp_procedure_get_return_values (procedure, success);
}

static GValueArray *
curves_explicit_invoker (GimpProcedure     *procedure,
                         Gimp              *gimp,
                         GimpContext       *context,
                         GimpProgress      *progress,
                         const GValueArray *args)
{
  gboolean success = TRUE;
  GimpDrawable *drawable;
  gint32 channel;
  gint32 num_bytes;
  const guint8 *curve;

  drawable = gimp_value_get_drawable (&args->values[0], gimp);
  channel = g_value_get_enum (&args->values[1]);
  num_bytes = g_value_get_int (&args->values[2]);
  curve = gimp_value_get_int8array (&args->values[3]);

  if (success)
    {
      if (! gimp_item_is_attached (GIMP_ITEM (drawable)) ||
          gimp_drawable_is_indexed (drawable) || (num_bytes != 256) ||
          (! gimp_drawable_has_alpha (drawable) &&
           channel == GIMP_HISTOGRAM_ALPHA) ||
          (gimp_drawable_is_gray (drawable) &&
           channel != GIMP_HISTOGRAM_VALUE && channel != GIMP_HISTOGRAM_ALPHA))
        success = FALSE;

      if (success)
        {
          gint x, y, width, height;

          /* The application should occur only within selection bounds */
          if (gimp_drawable_mask_intersect (drawable, &x, &y, &width, &height))
            {
              Curves       c;
              gint         j;
              PixelRegion  srcPR, destPR;
              GimpLut     *lut;

              /* FIXME: hack */
              if (gimp_drawable_is_gray (drawable) &&
                  channel == GIMP_HISTOGRAM_ALPHA)
                channel = 1;

              lut = gimp_lut_new ();

              curves_init (&c);

              for (j = 0; j < 256; j++)
                c.curve[channel][j] = curve[j];

              gimp_lut_setup (lut,
                              (GimpLutFunc) curves_lut_func,
                              &c,
                              gimp_drawable_bytes (drawable));

              pixel_region_init (&srcPR, gimp_drawable_get_tiles (drawable),
                                 x, y, width, height, FALSE);
              pixel_region_init (&destPR, gimp_drawable_get_shadow_tiles (drawable),
                                 x, y, width, height, TRUE);

              pixel_regions_process_parallel ((PixelProcessorFunc)
                                              gimp_lut_process,
                                              lut, 2, &srcPR, &destPR);

              gimp_lut_free (lut);

              gimp_drawable_merge_shadow (drawable, TRUE, _("Curves"));
              gimp_drawable_update (drawable, x, y, width, height);
            }
        }
    }

  return gimp_procedure_get_return_values (procedure, success);
}

static GValueArray *
color_balance_invoker (GimpProcedure     *procedure,
                       Gimp              *gimp,
                       GimpContext       *context,
                       GimpProgress      *progress,
                       const GValueArray *args)
{
  gboolean success = TRUE;
  GimpDrawable *drawable;
  gint32 transfer_mode;
  gboolean preserve_lum;
  gdouble cyan_red;
  gdouble magenta_green;
  gdouble yellow_blue;

  drawable = gimp_value_get_drawable (&args->values[0], gimp);
  transfer_mode = g_value_get_enum (&args->values[1]);
  preserve_lum = g_value_get_boolean (&args->values[2]);
  cyan_red = g_value_get_double (&args->values[3]);
  magenta_green = g_value_get_double (&args->values[4]);
  yellow_blue = g_value_get_double (&args->values[5]);

  if (success)
    {
      if (! gimp_item_is_attached (GIMP_ITEM (drawable)) ||
          gimp_drawable_is_indexed (drawable))
        success = FALSE;

      if (success)
        {
          gint x, y, width, height;

          /* The application should occur only within selection bounds */
          if (gimp_drawable_mask_intersect (drawable, &x, &y, &width, &height))
            {
              ColorBalance  cb;
              PixelRegion   srcPR, destPR;

              color_balance_init (&cb);

              cb.preserve_luminosity = preserve_lum;

              cb.cyan_red[transfer_mode]      = cyan_red;
              cb.magenta_green[transfer_mode] = magenta_green;
              cb.yellow_blue[transfer_mode]   = yellow_blue;

              color_balance_create_lookup_tables (&cb);

              pixel_region_init (&srcPR, gimp_drawable_get_tiles (drawable),
                                 x, y, width, height, FALSE);
              pixel_region_init (&destPR, gimp_drawable_get_shadow_tiles (drawable),
                                 x, y, width, height, TRUE);

              pixel_regions_process_parallel ((PixelProcessorFunc) color_balance,
                                              &cb, 2, &srcPR, &destPR);

              gimp_drawable_merge_shadow (drawable, TRUE, _("Color Balance"));
              gimp_drawable_update (drawable, x, y, width, height);
            }
        }
    }

  return gimp_procedure_get_return_values (procedure, success);
}

static GValueArray *
colorize_invoker (GimpProcedure     *procedure,
                  Gimp              *gimp,
                  GimpContext       *context,
                  GimpProgress      *progress,
                  const GValueArray *args)
{
  gboolean success = TRUE;
  GimpDrawable *drawable;
  gdouble hue;
  gdouble saturation;
  gdouble lightness;

  drawable = gimp_value_get_drawable (&args->values[0], gimp);
  hue = g_value_get_double (&args->values[1]);
  saturation = g_value_get_double (&args->values[2]);
  lightness = g_value_get_double (&args->values[3]);

  if (success)
    {
      if (! gimp_item_is_attached (GIMP_ITEM (drawable)) ||
          ! gimp_drawable_is_rgb (drawable))
        success = FALSE;

      if (success)
        {
          gint x, y, width, height;

          /* The application should occur only within selection bounds */
          if (gimp_drawable_mask_intersect (drawable, &x, &y, &width, &height))
            {
              Colorize     colors;
              PixelRegion  srcPR, destPR;

              colorize_init (&colors);

              colors.hue        = hue;
              colors.saturation = saturation;
              colors.lightness  = lightness;

              colorize_calculate (&colors);

              pixel_region_init (&srcPR, gimp_drawable_get_tiles (drawable),
                                 x, y, width, height, FALSE);
              pixel_region_init (&destPR, gimp_drawable_get_shadow_tiles (drawable),
                                 x, y, width, height, TRUE);

              pixel_regions_process_parallel ((PixelProcessorFunc) colorize,
                                              &colors, 2, &srcPR, &destPR);

              gimp_drawable_merge_shadow (drawable, TRUE, _("Colorize"));
              gimp_drawable_update (drawable, x, y, width, height);
            }
        }
    }

  return gimp_procedure_get_return_values (procedure, success);
}

static GValueArray *
histogram_invoker (GimpProcedure     *procedure,
                   Gimp              *gimp,
                   GimpContext       *context,
                   GimpProgress      *progress,
                   const GValueArray *args)
{
  gboolean success = TRUE;
  GValueArray *return_vals;
  GimpDrawable *drawable;
  gint32 channel;
  gint32 start_range;
  gint32 end_range;
  gdouble mean = 0.0;
  gdouble std_dev = 0.0;
  gdouble median = 0.0;
  gdouble pixels = 0.0;
  gdouble count = 0.0;
  gdouble percentile = 0.0;

  drawable = gimp_value_get_drawable (&args->values[0], gimp);
  channel = g_value_get_enum (&args->values[1]);
  start_range = g_value_get_int (&args->values[2]);
  end_range = g_value_get_int (&args->values[3]);

  if (success)
    {
      if (! gimp_item_is_attached (GIMP_ITEM (drawable)) ||
          gimp_drawable_is_indexed (drawable) ||
          (! gimp_drawable_has_alpha (drawable) &&
           channel == GIMP_HISTOGRAM_ALPHA) ||
          (gimp_drawable_is_gray (drawable) &&
           channel != GIMP_HISTOGRAM_VALUE && channel != GIMP_HISTOGRAM_ALPHA))
        success = FALSE;

      if (success)
        {
          GimpHistogram *histogram = gimp_histogram_new ();

          gimp_drawable_calculate_histogram (drawable, histogram);

          mean       = gimp_histogram_get_mean (histogram, channel,
                                                 start_range, end_range);
          std_dev    = gimp_histogram_get_std_dev (histogram, channel,
                                                   start_range, end_range);
          median     = gimp_histogram_get_median (histogram, channel,
                                                  start_range, end_range);
          pixels     = gimp_histogram_get_count (histogram, channel, 0, 255);
          count      = gimp_histogram_get_count (histogram, channel,
                                                 start_range, end_range);
          percentile = count / pixels;

          gimp_histogram_free (histogram);
        }
    }

  return_vals = gimp_procedure_get_return_values (procedure, success);

  if (success)
    {
      g_value_set_double (&return_vals->values[1], mean);
      g_value_set_double (&return_vals->values[2], std_dev);
      g_value_set_double (&return_vals->values[3], median);
      g_value_set_double (&return_vals->values[4], pixels);
      g_value_set_double (&return_vals->values[5], count);
      g_value_set_double (&return_vals->values[6], percentile);
    }

  return return_vals;
}

static GValueArray *
hue_saturation_invoker (GimpProcedure     *procedure,
                        Gimp              *gimp,
                        GimpContext       *context,
                        GimpProgress      *progress,
                        const GValueArray *args)
{
  gboolean success = TRUE;
  GimpDrawable *drawable;
  gint32 hue_range;
  gdouble hue_offset;
  gdouble lightness;
  gdouble saturation;

  drawable = gimp_value_get_drawable (&args->values[0], gimp);
  hue_range = g_value_get_enum (&args->values[1]);
  hue_offset = g_value_get_double (&args->values[2]);
  lightness = g_value_get_double (&args->values[3]);
  saturation = g_value_get_double (&args->values[4]);

  if (success)
    {
      if (! gimp_item_is_attached (GIMP_ITEM (drawable)) ||
          gimp_drawable_is_indexed (drawable))
        success = FALSE;

      if (success)
        {
          gint x, y, width, height;

          /* The application should occur only within selection bounds */
          if (gimp_drawable_mask_intersect (drawable, &x, &y, &width, &height))
            {
              HueSaturation  hs;
              PixelRegion    srcPR, destPR;

              hue_saturation_init (&hs);

              hs.hue[hue_range]        = hue_offset;
              hs.lightness[hue_range]  = lightness;
              hs.saturation[hue_range] = saturation;

              /* Calculate the transfer arrays */
              hue_saturation_calculate_transfers (&hs);

              pixel_region_init (&srcPR, gimp_drawable_get_tiles (drawable),
                                 x, y, width, height, FALSE);
              pixel_region_init (&destPR, gimp_drawable_get_shadow_tiles (drawable),
                                 x, y, width, height, TRUE);

              pixel_regions_process_parallel ((PixelProcessorFunc) hue_saturation,
                                              &hs, 2, &srcPR, &destPR);

              gimp_drawable_merge_shadow (drawable, TRUE, _("Hue-Saturation"));
              gimp_drawable_update (drawable, x, y, width, height);
            }
        }
    }

  return gimp_procedure_get_return_values (procedure, success);
}

static GValueArray *
threshold_invoker (GimpProcedure     *procedure,
                   Gimp              *gimp,
                   GimpContext       *context,
                   GimpProgress      *progress,
                   const GValueArray *args)
{
  gboolean success = TRUE;
  GimpDrawable *drawable;
  gint32 low_threshold;
  gint32 high_threshold;

  drawable = gimp_value_get_drawable (&args->values[0], gimp);
  low_threshold = g_value_get_int (&args->values[1]);
  high_threshold = g_value_get_int (&args->values[2]);

  if (success)
    {
      if (! gimp_item_is_attached (GIMP_ITEM (drawable)) ||
          gimp_drawable_is_indexed (drawable) ||
          (low_threshold >= high_threshold))
        success = FALSE;

      if (success)
        {
          gint x, y, width, height;

          /* The application should occur only within selection bounds */
          if (gimp_drawable_mask_intersect (drawable, &x, &y, &width, &height))
            {
              Threshold   tr;
              PixelRegion srcPR, destPR;

              tr.color          = gimp_drawable_is_rgb (drawable);
              tr.low_threshold  = low_threshold;
              tr.high_threshold = high_threshold;

              pixel_region_init (&srcPR, gimp_drawable_get_tiles (drawable),
                                 x, y, width, height, FALSE);
              pixel_region_init (&destPR, gimp_drawable_get_shadow_tiles (drawable),
                                 x, y, width, height, TRUE);

              pixel_regions_process_parallel ((PixelProcessorFunc) threshold,
                                              &tr, 2, &srcPR, &destPR);

              gimp_drawable_merge_shadow (drawable, TRUE, _("Threshold"));
              gimp_drawable_update (drawable, x, y, width, height);
            }
        }
    }

  return gimp_procedure_get_return_values (procedure, success);
}

void
register_color_procs (GimpPDB *pdb)
{
  GimpProcedure *procedure;

  /*
   * gimp-brightness-contrast
   */
  procedure = gimp_procedure_new (brightness_contrast_invoker);
  gimp_object_set_static_name (GIMP_OBJECT (procedure), "gimp-brightness-contrast");
  gimp_procedure_set_static_strings (procedure,
                                     "gimp-brightness-contrast",
                                     "Modify brightness/contrast in the specified drawable.",
                                     "This procedures allows the brightness and contrast of the specified drawable to be modified. Both 'brightness' and 'contrast' parameters are defined between -127 and 127.",
                                     "Spencer Kimball & Peter Mattis",
                                     "Spencer Kimball & Peter Mattis",
                                     "1997",
                                     NULL);
  gimp_procedure_add_argument (procedure,
                               gimp_param_spec_drawable_id ("drawable",
                                                            "drawable",
                                                            "The drawable",
                                                            pdb->gimp, FALSE,
                                                            GIMP_PARAM_READWRITE));
  gimp_procedure_add_argument (procedure,
                               gimp_param_spec_int32 ("brightness",
                                                      "brightness",
                                                      "Brightness adjustment",
                                                      -127, 127, -127,
                                                      GIMP_PARAM_READWRITE));
  gimp_procedure_add_argument (procedure,
                               gimp_param_spec_int32 ("contrast",
                                                      "contrast",
                                                      "Contrast adjustment",
                                                      -127, 127, -127,
                                                      GIMP_PARAM_READWRITE));
  gimp_pdb_register_procedure (pdb, procedure);
  g_object_unref (procedure);

  /*
   * gimp-levels
   */
  procedure = gimp_procedure_new (levels_invoker);
  gimp_object_set_static_name (GIMP_OBJECT (procedure), "gimp-levels");
  gimp_procedure_set_static_strings (procedure,
                                     "gimp-levels",
                                     "Modifies intensity levels in the specified drawable.",
                                     "This tool allows intensity levels in the specified drawable to be remapped according to a set of parameters. The low/high input levels specify an initial mapping from the source intensities. The gamma value determines how intensities between the low and high input intensities are interpolated. A gamma value of 1.0 results in a linear interpolation. Higher gamma values result in more high-level intensities. Lower gamma values result in more low-level intensities. The low/high output levels constrain the final intensity mapping--that is, no final intensity will be lower than the low output level and no final intensity will be higher than the high output level. This tool is only valid on RGB color and grayscale images. It will not operate on indexed drawables.",
                                     "Spencer Kimball & Peter Mattis",
                                     "Spencer Kimball & Peter Mattis",
                                     "1995-1996",
                                     NULL);
  gimp_procedure_add_argument (procedure,
                               gimp_param_spec_drawable_id ("drawable",
                                                            "drawable",
                                                            "The drawable",
                                                            pdb->gimp, FALSE,
                                                            GIMP_PARAM_READWRITE));
  gimp_procedure_add_argument (procedure,
                               g_param_spec_enum ("channel",
                                                  "channel",
                                                  "The channel to modify",
                                                  GIMP_TYPE_HISTOGRAM_CHANNEL,
                                                  GIMP_HISTOGRAM_VALUE,
                                                  GIMP_PARAM_READWRITE));
  gimp_procedure_add_argument (procedure,
                               gimp_param_spec_int32 ("low-input",
                                                      "low input",
                                                      "Intensity of lowest input",
                                                      0, 255, 0,
                                                      GIMP_PARAM_READWRITE));
  gimp_procedure_add_argument (procedure,
                               gimp_param_spec_int32 ("high-input",
                                                      "high input",
                                                      "Intensity of highest input",
                                                      0, 255, 0,
                                                      GIMP_PARAM_READWRITE));
  gimp_procedure_add_argument (procedure,
                               g_param_spec_double ("gamma",
                                                    "gamma",
                                                    "Gamma correction factor",
                                                    0.1, 10, 0.1,
                                                    GIMP_PARAM_READWRITE));
  gimp_procedure_add_argument (procedure,
                               gimp_param_spec_int32 ("low-output",
                                                      "low output",
                                                      "Intensity of lowest output",
                                                      0, 255, 0,
                                                      GIMP_PARAM_READWRITE));
  gimp_procedure_add_argument (procedure,
                               gimp_param_spec_int32 ("high-output",
                                                      "high output",
                                                      "Intensity of highest output",
                                                      0, 255, 0,
                                                      GIMP_PARAM_READWRITE));
  gimp_pdb_register_procedure (pdb, procedure);
  g_object_unref (procedure);

  /*
   * gimp-levels-auto
   */
  procedure = gimp_procedure_new (levels_auto_invoker);
  gimp_object_set_static_name (GIMP_OBJECT (procedure), "gimp-levels-auto");
  gimp_procedure_set_static_strings (procedure,
                                     "gimp-levels-auto",
                                     "This procedure is deprecated! Use 'gimp-levels-stretch' instead.",
                                     "This procedure is deprecated! Use 'gimp-levels-stretch' instead.",
                                     "",
                                     "",
                                     "",
                                     "gimp-levels-stretch");
  gimp_procedure_add_argument (procedure,
                               gimp_param_spec_drawable_id ("drawable",
                                                            "drawable",
                                                            "The drawable",
                                                            pdb->gimp, FALSE,
                                                            GIMP_PARAM_READWRITE));
  gimp_pdb_register_procedure (pdb, procedure);
  g_object_unref (procedure);

  /*
   * gimp-levels-stretch
   */
  procedure = gimp_procedure_new (levels_stretch_invoker);
  gimp_object_set_static_name (GIMP_OBJECT (procedure), "gimp-levels-stretch");
  gimp_procedure_set_static_strings (procedure,
                                     "gimp-levels-stretch",
                                     "Automatically modifies intensity levels in the specified drawable.",
                                     "This procedure allows intensity levels in the specified drawable to be remapped according to a set of guessed parameters. It is equivalent to clicking the \"Auto\" button in the Levels tool. This procedure is only valid on RGB color and grayscale images. It will not operate on indexed drawables.",
                                     "Joao S.O. Bueno, Shawn Willden",
                                     "Joao S.O. Bueno, Shawn Willden",
                                     "2003",
                                     NULL);
  gimp_procedure_add_argument (procedure,
                               gimp_param_spec_drawable_id ("drawable",
                                                            "drawable",
                                                            "The drawable",
                                                            pdb->gimp, FALSE,
                                                            GIMP_PARAM_READWRITE));
  gimp_pdb_register_procedure (pdb, procedure);
  g_object_unref (procedure);

  /*
   * gimp-posterize
   */
  procedure = gimp_procedure_new (posterize_invoker);
  gimp_object_set_static_name (GIMP_OBJECT (procedure), "gimp-posterize");
  gimp_procedure_set_static_strings (procedure,
                                     "gimp-posterize",
                                     "Posterize the specified drawable.",
                                     "This procedures reduces the number of shades allows in each intensity channel to the specified 'levels' parameter.",
                                     "Spencer Kimball & Peter Mattis",
                                     "Spencer Kimball & Peter Mattis",
                                     "1997",
                                     NULL);
  gimp_procedure_add_argument (procedure,
                               gimp_param_spec_drawable_id ("drawable",
                                                            "drawable",
                                                            "The drawable",
                                                            pdb->gimp, FALSE,
                                                            GIMP_PARAM_READWRITE));
  gimp_procedure_add_argument (procedure,
                               gimp_param_spec_int32 ("levels",
                                                      "levels",
                                                      "Levels of posterization",
                                                      2, 255, 2,
                                                      GIMP_PARAM_READWRITE));
  gimp_pdb_register_procedure (pdb, procedure);
  g_object_unref (procedure);

  /*
   * gimp-desaturate
   */
  procedure = gimp_procedure_new (desaturate_invoker);
  gimp_object_set_static_name (GIMP_OBJECT (procedure), "gimp-desaturate");
  gimp_procedure_set_static_strings (procedure,
                                     "gimp-desaturate",
                                     "Desaturate the contents of the specified drawable.",
                                     "This procedure desaturates the contents of the specified drawable. This procedure only works on drawables of type RGB color.",
                                     "Spencer Kimball & Peter Mattis",
                                     "Spencer Kimball & Peter Mattis",
                                     "1995-1996",
                                     NULL);
  gimp_procedure_add_argument (procedure,
                               gimp_param_spec_drawable_id ("drawable",
                                                            "drawable",
                                                            "The drawable",
                                                            pdb->gimp, FALSE,
                                                            GIMP_PARAM_READWRITE));
  gimp_pdb_register_procedure (pdb, procedure);
  g_object_unref (procedure);

  /*
   * gimp-desaturate-full
   */
  procedure = gimp_procedure_new (desaturate_full_invoker);
  gimp_object_set_static_name (GIMP_OBJECT (procedure), "gimp-desaturate-full");
  gimp_procedure_set_static_strings (procedure,
                                     "gimp-desaturate-full",
                                     "Desaturate the contents of the specified drawable, with the specified formula.",
                                     "This procedure desaturates the contents of the specified drawable, with the specified formula. This procedure only works on drawables of type RGB color.",
                                     "Karine Delvare",
                                     "Karine Delvare",
                                     "2005",
                                     NULL);
  gimp_procedure_add_argument (procedure,
                               gimp_param_spec_drawable_id ("drawable",
                                                            "drawable",
                                                            "The drawable",
                                                            pdb->gimp, FALSE,
                                                            GIMP_PARAM_READWRITE));
  gimp_procedure_add_argument (procedure,
                               g_param_spec_enum ("desaturate-mode",
                                                  "desaturate mode",
                                                  "The formula to use to desaturate",
                                                  GIMP_TYPE_DESATURATE_MODE,
                                                  GIMP_DESATURATE_LIGHTNESS,
                                                  GIMP_PARAM_READWRITE));
  gimp_pdb_register_procedure (pdb, procedure);
  g_object_unref (procedure);

  /*
   * gimp-equalize
   */
  procedure = gimp_procedure_new (equalize_invoker);
  gimp_object_set_static_name (GIMP_OBJECT (procedure), "gimp-equalize");
  gimp_procedure_set_static_strings (procedure,
                                     "gimp-equalize",
                                     "Equalize the contents of the specified drawable.",
                                     "This procedure equalizes the contents of the specified drawable. Each intensity channel is equalizeed independently. The equalized intensity is given as inten' = (255 - inten). Indexed color drawables are not valid for this operation. The 'mask_only' option specifies whether to adjust only the area of the image within the selection bounds, or the entire image based on the histogram of the selected area. If there is no selection, the entire image is adjusted based on the histogram for the entire image.",
                                     "Spencer Kimball & Peter Mattis",
                                     "Spencer Kimball & Peter Mattis",
                                     "1995-1996",
                                     NULL);
  gimp_procedure_add_argument (procedure,
                               gimp_param_spec_drawable_id ("drawable",
                                                            "drawable",
                                                            "The drawable",
                                                            pdb->gimp, FALSE,
                                                            GIMP_PARAM_READWRITE));
  gimp_procedure_add_argument (procedure,
                               g_param_spec_boolean ("mask-only",
                                                     "mask only",
                                                     "Equalization option",
                                                     FALSE,
                                                     GIMP_PARAM_READWRITE));
  gimp_pdb_register_procedure (pdb, procedure);
  g_object_unref (procedure);

  /*
   * gimp-invert
   */
  procedure = gimp_procedure_new (invert_invoker);
  gimp_object_set_static_name (GIMP_OBJECT (procedure), "gimp-invert");
  gimp_procedure_set_static_strings (procedure,
                                     "gimp-invert",
                                     "Invert the contents of the specified drawable.",
                                     "This procedure inverts the contents of the specified drawable. Each intensity channel is inverted independently. The inverted intensity is given as inten' = (255 - inten). Indexed color drawables are not valid for this operation.",
                                     "Spencer Kimball & Peter Mattis",
                                     "Spencer Kimball & Peter Mattis",
                                     "1995-1996",
                                     NULL);
  gimp_procedure_add_argument (procedure,
                               gimp_param_spec_drawable_id ("drawable",
                                                            "drawable",
                                                            "The drawable",
                                                            pdb->gimp, FALSE,
                                                            GIMP_PARAM_READWRITE));
  gimp_pdb_register_procedure (pdb, procedure);
  g_object_unref (procedure);

  /*
   * gimp-curves-spline
   */
  procedure = gimp_procedure_new (curves_spline_invoker);
  gimp_object_set_static_name (GIMP_OBJECT (procedure), "gimp-curves-spline");
  gimp_procedure_set_static_strings (procedure,
                                     "gimp-curves-spline",
                                     "Modifies the intensity curve(s) for specified drawable.",
                                     "Modifies the intensity mapping for one channel in the specified drawable. The drawable must be either grayscale or RGB, and the channel can be either an intensity component, or the value. The 'control_pts' parameter is an array of integers which define a set of control points which describe a Catmull Rom spline which yields the final intensity curve. Use the 'gimp-curves-explicit' function to explicitly modify intensity levels.",
                                     "Spencer Kimball & Peter Mattis",
                                     "Spencer Kimball & Peter Mattis",
                                     "1995-1996",
                                     NULL);
  gimp_procedure_add_argument (procedure,
                               gimp_param_spec_drawable_id ("drawable",
                                                            "drawable",
                                                            "The drawable",
                                                            pdb->gimp, FALSE,
                                                            GIMP_PARAM_READWRITE));
  gimp_procedure_add_argument (procedure,
                               g_param_spec_enum ("channel",
                                                  "channel",
                                                  "The channel to modify",
                                                  GIMP_TYPE_HISTOGRAM_CHANNEL,
                                                  GIMP_HISTOGRAM_VALUE,
                                                  GIMP_PARAM_READWRITE));
  gimp_procedure_add_argument (procedure,
                               gimp_param_spec_int32 ("num-points",
                                                      "num points",
                                                      "The number of values in the control point array",
                                                      4, 34, 4,
                                                      GIMP_PARAM_READWRITE));
  gimp_procedure_add_argument (procedure,
                               gimp_param_spec_int8_array ("control-pts",
                                                           "control pts",
                                                           "The spline control points: { cp1.x, cp1.y, cp2.x, cp2.y, ... }",
                                                           GIMP_PARAM_READWRITE));
  gimp_pdb_register_procedure (pdb, procedure);
  g_object_unref (procedure);

  /*
   * gimp-curves-explicit
   */
  procedure = gimp_procedure_new (curves_explicit_invoker);
  gimp_object_set_static_name (GIMP_OBJECT (procedure), "gimp-curves-explicit");
  gimp_procedure_set_static_strings (procedure,
                                     "gimp-curves-explicit",
                                     "Modifies the intensity curve(s) for specified drawable.",
                                     "Modifies the intensity mapping for one channel in the specified drawable. The drawable must be either grayscale or RGB, and the channel can be either an intensity component, or the value. The 'curve' parameter is an array of bytes which explicitly defines how each pixel value in the drawable will be modified. Use the 'gimp-curves-spline' function to modify intensity levels with Catmull Rom splines.",
                                     "Spencer Kimball & Peter Mattis",
                                     "Spencer Kimball & Peter Mattis",
                                     "1995-1996",
                                     NULL);
  gimp_procedure_add_argument (procedure,
                               gimp_param_spec_drawable_id ("drawable",
                                                            "drawable",
                                                            "The drawable",
                                                            pdb->gimp, FALSE,
                                                            GIMP_PARAM_READWRITE));
  gimp_procedure_add_argument (procedure,
                               g_param_spec_enum ("channel",
                                                  "channel",
                                                  "The channel to modify",
                                                  GIMP_TYPE_HISTOGRAM_CHANNEL,
                                                  GIMP_HISTOGRAM_VALUE,
                                                  GIMP_PARAM_READWRITE));
  gimp_procedure_add_argument (procedure,
                               gimp_param_spec_int32 ("num-bytes",
                                                      "num bytes",
                                                      "The number of bytes in the new curve (always 256)",
                                                      0, G_MAXINT32, 0,
                                                      GIMP_PARAM_READWRITE));
  gimp_procedure_add_argument (procedure,
                               gimp_param_spec_int8_array ("curve",
                                                           "curve",
                                                           "The explicit curve",
                                                           GIMP_PARAM_READWRITE));
  gimp_pdb_register_procedure (pdb, procedure);
  g_object_unref (procedure);

  /*
   * gimp-color-balance
   */
  procedure = gimp_procedure_new (color_balance_invoker);
  gimp_object_set_static_name (GIMP_OBJECT (procedure), "gimp-color-balance");
  gimp_procedure_set_static_strings (procedure,
                                     "gimp-color-balance",
                                     "Modify the color balance of the specified drawable.",
                                     "Modify the color balance of the specified drawable. There are three axis which can be modified: cyan-red, magenta-green, and yellow-blue. Negative values increase the amount of the former, positive values increase the amount of the latter. Color balance can be controlled with the 'transfer_mode' setting, which allows shadows, midtones, and highlights in an image to be affected differently. The 'preserve_lum' parameter, if TRUE, ensures that the luminosity of each pixel remains fixed.",
                                     "Spencer Kimball & Peter Mattis",
                                     "Spencer Kimball & Peter Mattis",
                                     "1997",
                                     NULL);
  gimp_procedure_add_argument (procedure,
                               gimp_param_spec_drawable_id ("drawable",
                                                            "drawable",
                                                            "The drawable",
                                                            pdb->gimp, FALSE,
                                                            GIMP_PARAM_READWRITE));
  gimp_procedure_add_argument (procedure,
                               g_param_spec_enum ("transfer-mode",
                                                  "transfer mode",
                                                  "Transfer mode",
                                                  GIMP_TYPE_TRANSFER_MODE,
                                                  GIMP_SHADOWS,
                                                  GIMP_PARAM_READWRITE));
  gimp_procedure_add_argument (procedure,
                               g_param_spec_boolean ("preserve-lum",
                                                     "preserve lum",
                                                     "Preserve luminosity values at each pixel",
                                                     FALSE,
                                                     GIMP_PARAM_READWRITE));
  gimp_procedure_add_argument (procedure,
                               g_param_spec_double ("cyan-red",
                                                    "cyan red",
                                                    "Cyan-Red color balance",
                                                    -100, 100, -100,
                                                    GIMP_PARAM_READWRITE));
  gimp_procedure_add_argument (procedure,
                               g_param_spec_double ("magenta-green",
                                                    "magenta green",
                                                    "Magenta-Green color balance",
                                                    -100, 100, -100,
                                                    GIMP_PARAM_READWRITE));
  gimp_procedure_add_argument (procedure,
                               g_param_spec_double ("yellow-blue",
                                                    "yellow blue",
                                                    "Yellow-Blue color balance",
                                                    -100, 100, -100,
                                                    GIMP_PARAM_READWRITE));
  gimp_pdb_register_procedure (pdb, procedure);
  g_object_unref (procedure);

  /*
   * gimp-colorize
   */
  procedure = gimp_procedure_new (colorize_invoker);
  gimp_object_set_static_name (GIMP_OBJECT (procedure), "gimp-colorize");
  gimp_procedure_set_static_strings (procedure,
                                     "gimp-colorize",
                                     "Render the drawable as a grayscale image seen through a colored glass.",
                                     "Desatures the drawable, then tints it with the specified color. This tool is only valid on RGB color images. It will not operate on grayscale or indexed drawables.",
                                     "Sven Neumann <sven@gimp.org>",
                                     "Sven Neumann",
                                     "2004",
                                     NULL);
  gimp_procedure_add_argument (procedure,
                               gimp_param_spec_drawable_id ("drawable",
                                                            "drawable",
                                                            "The drawable",
                                                            pdb->gimp, FALSE,
                                                            GIMP_PARAM_READWRITE));
  gimp_procedure_add_argument (procedure,
                               g_param_spec_double ("hue",
                                                    "hue",
                                                    "Hue in degrees",
                                                    0, 360, 0,
                                                    GIMP_PARAM_READWRITE));
  gimp_procedure_add_argument (procedure,
                               g_param_spec_double ("saturation",
                                                    "saturation",
                                                    "Saturation in percent",
                                                    0, 100, 0,
                                                    GIMP_PARAM_READWRITE));
  gimp_procedure_add_argument (procedure,
                               g_param_spec_double ("lightness",
                                                    "lightness",
                                                    "Lightness in percent",
                                                    -100, 100, -100,
                                                    GIMP_PARAM_READWRITE));
  gimp_pdb_register_procedure (pdb, procedure);
  g_object_unref (procedure);

  /*
   * gimp-histogram
   */
  procedure = gimp_procedure_new (histogram_invoker);
  gimp_object_set_static_name (GIMP_OBJECT (procedure), "gimp-histogram");
  gimp_procedure_set_static_strings (procedure,
                                     "gimp-histogram",
                                     "Returns information on the intensity histogram for the specified drawable.",
                                     "This tool makes it possible to gather information about the intensity histogram of a drawable. A channel to examine is first specified. This can be either value, red, green, or blue, depending on whether the drawable is of type color or grayscale. The drawable may not be indexed. Second, a range of intensities are specified. The 'gimp-histogram' function returns statistics based on the pixels in the drawable that fall under this range of values. Mean, standard deviation, median, number of pixels, and percentile are all returned. Additionally, the total count of pixels in the image is returned. Counts of pixels are weighted by any associated alpha values and by the current selection mask. That is, pixels that lie outside an active selection mask will not be counted. Similarly, pixels with transparent alpha values will not be counted.",
                                     "Spencer Kimball & Peter Mattis",
                                     "Spencer Kimball & Peter Mattis",
                                     "1995-1996",
                                     NULL);
  gimp_procedure_add_argument (procedure,
                               gimp_param_spec_drawable_id ("drawable",
                                                            "drawable",
                                                            "The drawable",
                                                            pdb->gimp, FALSE,
                                                            GIMP_PARAM_READWRITE));
  gimp_procedure_add_argument (procedure,
                               g_param_spec_enum ("channel",
                                                  "channel",
                                                  "The channel to modify",
                                                  GIMP_TYPE_HISTOGRAM_CHANNEL,
                                                  GIMP_HISTOGRAM_VALUE,
                                                  GIMP_PARAM_READWRITE));
  gimp_procedure_add_argument (procedure,
                               gimp_param_spec_int32 ("start-range",
                                                      "start range",
                                                      "Start of the intensity measurement range",
                                                      0, 256, 0,
                                                      GIMP_PARAM_READWRITE));
  gimp_procedure_add_argument (procedure,
                               gimp_param_spec_int32 ("end-range",
                                                      "end range",
                                                      "End of the intensity measurement range",
                                                      0, 256, 0,
                                                      GIMP_PARAM_READWRITE));
  gimp_procedure_add_return_value (procedure,
                                   g_param_spec_double ("mean",
                                                        "mean",
                                                        "Mean intensity value",
                                                        -G_MAXDOUBLE, G_MAXDOUBLE, 0,
                                                        GIMP_PARAM_READWRITE));
  gimp_procedure_add_return_value (procedure,
                                   g_param_spec_double ("std-dev",
                                                        "std dev",
                                                        "Standard deviation of intensity values",
                                                        -G_MAXDOUBLE, G_MAXDOUBLE, 0,
                                                        GIMP_PARAM_READWRITE));
  gimp_procedure_add_return_value (procedure,
                                   g_param_spec_double ("median",
                                                        "median",
                                                        "Median intensity value",
                                                        -G_MAXDOUBLE, G_MAXDOUBLE, 0,
                                                        GIMP_PARAM_READWRITE));
  gimp_procedure_add_return_value (procedure,
                                   g_param_spec_double ("pixels",
                                                        "pixels",
                                                        "Alpha-weighted pixel count for entire image",
                                                        -G_MAXDOUBLE, G_MAXDOUBLE, 0,
                                                        GIMP_PARAM_READWRITE));
  gimp_procedure_add_return_value (procedure,
                                   g_param_spec_double ("count",
                                                        "count",
                                                        "Alpha-weighted pixel count for range",
                                                        -G_MAXDOUBLE, G_MAXDOUBLE, 0,
                                                        GIMP_PARAM_READWRITE));
  gimp_procedure_add_return_value (procedure,
                                   g_param_spec_double ("percentile",
                                                        "percentile",
                                                        "Percentile that range falls under",
                                                        -G_MAXDOUBLE, G_MAXDOUBLE, 0,
                                                        GIMP_PARAM_READWRITE));
  gimp_pdb_register_procedure (pdb, procedure);
  g_object_unref (procedure);

  /*
   * gimp-hue-saturation
   */
  procedure = gimp_procedure_new (hue_saturation_invoker);
  gimp_object_set_static_name (GIMP_OBJECT (procedure), "gimp-hue-saturation");
  gimp_procedure_set_static_strings (procedure,
                                     "gimp-hue-saturation",
                                     "Modify hue, lightness, and saturation in the specified drawable.",
                                     "This procedures allows the hue, lightness, and saturation in the specified drawable to be modified. The 'hue_range' parameter provides the capability to limit range of affected hues.",
                                     "Spencer Kimball & Peter Mattis",
                                     "Spencer Kimball & Peter Mattis",
                                     "1997",
                                     NULL);
  gimp_procedure_add_argument (procedure,
                               gimp_param_spec_drawable_id ("drawable",
                                                            "drawable",
                                                            "The drawable",
                                                            pdb->gimp, FALSE,
                                                            GIMP_PARAM_READWRITE));
  gimp_procedure_add_argument (procedure,
                               g_param_spec_enum ("hue-range",
                                                  "hue range",
                                                  "Range of affected hues",
                                                  GIMP_TYPE_HUE_RANGE,
                                                  GIMP_ALL_HUES,
                                                  GIMP_PARAM_READWRITE));
  gimp_procedure_add_argument (procedure,
                               g_param_spec_double ("hue-offset",
                                                    "hue offset",
                                                    "Hue offset in degrees",
                                                    -180, 180, -180,
                                                    GIMP_PARAM_READWRITE));
  gimp_procedure_add_argument (procedure,
                               g_param_spec_double ("lightness",
                                                    "lightness",
                                                    "Lightness modification",
                                                    -100, 100, -100,
                                                    GIMP_PARAM_READWRITE));
  gimp_procedure_add_argument (procedure,
                               g_param_spec_double ("saturation",
                                                    "saturation",
                                                    "Saturation modification",
                                                    -100, 100, -100,
                                                    GIMP_PARAM_READWRITE));
  gimp_pdb_register_procedure (pdb, procedure);
  g_object_unref (procedure);

  /*
   * gimp-threshold
   */
  procedure = gimp_procedure_new (threshold_invoker);
  gimp_object_set_static_name (GIMP_OBJECT (procedure), "gimp-threshold");
  gimp_procedure_set_static_strings (procedure,
                                     "gimp-threshold",
                                     "Threshold the specified drawable.",
                                     "This procedures generates a threshold map of the specified drawable. All pixels between the values of 'low_threshold' and 'high_threshold' are replaced with white, and all other pixels with black.",
                                     "Spencer Kimball & Peter Mattis",
                                     "Spencer Kimball & Peter Mattis",
                                     "1997",
                                     NULL);
  gimp_procedure_add_argument (procedure,
                               gimp_param_spec_drawable_id ("drawable",
                                                            "drawable",
                                                            "The drawable",
                                                            pdb->gimp, FALSE,
                                                            GIMP_PARAM_READWRITE));
  gimp_procedure_add_argument (procedure,
                               gimp_param_spec_int32 ("low-threshold",
                                                      "low threshold",
                                                      "The low threshold value",
                                                      0, 255, 0,
                                                      GIMP_PARAM_READWRITE));
  gimp_procedure_add_argument (procedure,
                               gimp_param_spec_int32 ("high-threshold",
                                                      "high threshold",
                                                      "The high threshold value",
                                                      0, 255, 0,
                                                      GIMP_PARAM_READWRITE));
  gimp_pdb_register_procedure (pdb, procedure);
  g_object_unref (procedure);
}
