/* GIMP - The GNU 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 3 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, see <https://www.gnu.org/licenses/>.
 */

/* NOTE: This file is auto-generated by pdbgen.pl. */

#include "config.h"

#include <gegl.h>

#include <gdk-pixbuf/gdk-pixbuf.h>

#include "libgimpmath/gimpmath.h"

#include "libgimpbase/gimpbase.h"

#include "pdb-types.h"

#include "core/gimp.h"
#include "core/gimpdrawable-equalize.h"
#include "core/gimpdrawable-histogram.h"
#include "core/gimpdrawable-levels.h"
#include "core/gimpdrawable-operation.h"
#include "core/gimpdrawable.h"
#include "core/gimphistogram.h"
#include "core/gimpparamspecs.h"
#include "operations/gimpbrightnesscontrastconfig.h"
#include "operations/gimpcolorbalanceconfig.h"
#include "operations/gimpcurvesconfig.h"
#include "operations/gimphuesaturationconfig.h"
#include "operations/gimplevelsconfig.h"
#include "plug-in/gimpplugin.h"
#include "plug-in/gimppluginmanager.h"

#include "gimppdb.h"
#include "gimppdb-utils.h"
#include "gimpprocedure.h"
#include "internal-procs.h"

#include "gimp-intl.h"


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

  drawable = gimp_value_get_drawable (gimp_value_array_index (args, 0), gimp);
  brightness = g_value_get_int (gimp_value_array_index (args, 1));
  contrast = g_value_get_int (gimp_value_array_index (args, 2));

  if (success)
    {
      if (gimp_pdb_item_is_attached (GIMP_ITEM (drawable), NULL,
                                     GIMP_PDB_ITEM_CONTENT, error) &&
          gimp_pdb_item_is_not_group (GIMP_ITEM (drawable), error))
        {
          GObject *config = g_object_new (GIMP_TYPE_BRIGHTNESS_CONTRAST_CONFIG,
                                          "brightness", brightness / 127.0,
                                          "contrast",   contrast   / 127.0,
                                          NULL);

          gimp_drawable_apply_operation_by_name (drawable, progress,
                                                 C_("undo-type", "Brightness-Contrast"),
                                                 "gimp:brightness-contrast",
                                                 config);
          g_object_unref (config);
        }
      else
        success = FALSE;
    }

  return gimp_procedure_get_return_values (procedure, success,
                                           error ? *error : NULL);
}

static GimpValueArray *
levels_invoker (GimpProcedure         *procedure,
                Gimp                  *gimp,
                GimpContext           *context,
                GimpProgress          *progress,
                const GimpValueArray  *args,
                GError               **error)
{
  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 (gimp_value_array_index (args, 0), gimp);
  channel = g_value_get_enum (gimp_value_array_index (args, 1));
  low_input = g_value_get_int (gimp_value_array_index (args, 2));
  high_input = g_value_get_int (gimp_value_array_index (args, 3));
  gamma = g_value_get_double (gimp_value_array_index (args, 4));
  low_output = g_value_get_int (gimp_value_array_index (args, 5));
  high_output = g_value_get_int (gimp_value_array_index (args, 6));

  if (success)
    {
      if (gimp_pdb_item_is_attached (GIMP_ITEM (drawable), NULL,
                                     GIMP_PDB_ITEM_CONTENT, error) &&
          gimp_pdb_item_is_not_group (GIMP_ITEM (drawable), error) &&
          channel != GIMP_HISTOGRAM_LUMINANCE &&
          (gimp_drawable_has_alpha (drawable) || channel != GIMP_HISTOGRAM_ALPHA) &&
          (! gimp_drawable_is_gray (drawable) ||
           channel == GIMP_HISTOGRAM_VALUE || channel == GIMP_HISTOGRAM_ALPHA))
        {
          GObject *config = g_object_new (GIMP_TYPE_LEVELS_CONFIG,
                                          "channel", channel,
                                          NULL);

          g_object_set (config,
                        "low-input",    low_input   / 255.0,
                        "high-input",   high_input  / 255.0,
                        "clamp-input",  TRUE,
                        "gamma",        gamma,
                        "low-output",   low_output  / 255.0,
                        "high-output",  high_output / 255.0,
                        "clamp-input",  TRUE,
                        NULL);

          gimp_drawable_apply_operation_by_name (drawable, progress,
                                                 C_("undo-type", "Levels"),
                                                 "gimp:levels",
                                                 config);
          g_object_unref (config);
        }
      else
        success = TRUE;
    }

  return gimp_procedure_get_return_values (procedure, success,
                                           error ? *error : NULL);
}

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

  drawable = gimp_value_get_drawable (gimp_value_array_index (args, 0), gimp);

  if (success)
    {
      if (gimp_pdb_item_is_attached (GIMP_ITEM (drawable), NULL,
                                     GIMP_PDB_ITEM_CONTENT, error) &&
          gimp_pdb_item_is_not_group (GIMP_ITEM (drawable), error))
        {
          gimp_drawable_levels_stretch (drawable, progress);
        }
      else
        success = FALSE;
    }

  return gimp_procedure_get_return_values (procedure, success,
                                           error ? *error : NULL);
}

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

  drawable = gimp_value_get_drawable (gimp_value_array_index (args, 0), gimp);

  if (success)
    {
      if (gimp_pdb_item_is_attached (GIMP_ITEM (drawable), NULL,
                                     GIMP_PDB_ITEM_CONTENT, error) &&
          gimp_pdb_item_is_not_group (GIMP_ITEM (drawable), error))
        {
          gimp_drawable_levels_stretch (drawable, progress);
        }
      else
        success = FALSE;
    }

  return gimp_procedure_get_return_values (procedure, success,
                                           error ? *error : NULL);
}

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

  drawable = gimp_value_get_drawable (gimp_value_array_index (args, 0), gimp);
  levels = g_value_get_int (gimp_value_array_index (args, 1));

  if (success)
    {
      if (gimp_pdb_item_is_attached (GIMP_ITEM (drawable), NULL,
                                     GIMP_PDB_ITEM_CONTENT, error) &&
          gimp_pdb_item_is_not_group (GIMP_ITEM (drawable), error))
        {
          GeglNode *node =
            gegl_node_new_child (NULL,
                                 "operation", "gimp:posterize",
                                 "levels",    levels,
                                 NULL);

          gimp_drawable_apply_operation (drawable, progress,
                                         C_("undo-type", "Posterize"),
                                         node);
          g_object_unref (node);
        }
      else
        success = FALSE;
    }

  return gimp_procedure_get_return_values (procedure, success,
                                           error ? *error : NULL);
}

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

  drawable = gimp_value_get_drawable (gimp_value_array_index (args, 0), gimp);

  if (success)
    {
      if (gimp_pdb_item_is_attached (GIMP_ITEM (drawable), NULL,
                                     GIMP_PDB_ITEM_CONTENT, error) &&
          gimp_pdb_item_is_not_group (GIMP_ITEM (drawable), error) &&
          gimp_drawable_is_rgb (drawable))
        {
          GeglNode *node =
            gegl_node_new_child (NULL,
                                 "operation", "gimp:desaturate",
                                 "mode",      GIMP_DESATURATE_LIGHTNESS,
                                 NULL);

          gimp_drawable_apply_operation (drawable, progress,
                                         C_("undo-type", "Desaturate"),
                                         node);
          g_object_unref (node);
        }
      else
        success = FALSE;
    }

  return gimp_procedure_get_return_values (procedure, success,
                                           error ? *error : NULL);
}

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

  drawable = gimp_value_get_drawable (gimp_value_array_index (args, 0), gimp);
  desaturate_mode = g_value_get_enum (gimp_value_array_index (args, 1));

  if (success)
    {
      if (gimp_pdb_item_is_attached (GIMP_ITEM (drawable), NULL,
                                     GIMP_PDB_ITEM_CONTENT, error) &&
          gimp_pdb_item_is_not_group (GIMP_ITEM (drawable), error) &&
          gimp_drawable_is_rgb (drawable))
        {
          GeglNode *node =
            gegl_node_new_child (NULL,
                                 "operation", "gimp:desaturate",
                                 "mode",      desaturate_mode,
                                 NULL);

          gimp_drawable_apply_operation (drawable, progress,
                                         C_("undo-type", "Desaturate"),
                                         node);
          g_object_unref (node);
        }
      else
        success = FALSE;
    }

  return gimp_procedure_get_return_values (procedure, success,
                                           error ? *error : NULL);
}

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

  drawable = gimp_value_get_drawable (gimp_value_array_index (args, 0), gimp);
  mask_only = g_value_get_boolean (gimp_value_array_index (args, 1));

  if (success)
    {
      if (! gimp_pdb_item_is_attached (GIMP_ITEM (drawable), NULL,
                                       GIMP_PDB_ITEM_CONTENT, error) ||
          ! gimp_pdb_item_is_not_group (GIMP_ITEM (drawable), error))
        success = FALSE;

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

  return gimp_procedure_get_return_values (procedure, success,
                                           error ? *error : NULL);
}

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

  drawable = gimp_value_get_drawable (gimp_value_array_index (args, 0), gimp);

  if (success)
    {
      if (gimp_pdb_item_is_attached (GIMP_ITEM (drawable), NULL,
                                     GIMP_PDB_ITEM_CONTENT, error) &&
          gimp_pdb_item_is_not_group (GIMP_ITEM (drawable), error))
        {
          gimp_drawable_apply_operation_by_name (drawable, progress,
                                                 _("Invert"),
                                                 "gegl:invert-gamma",
                                                 NULL);
        }
      else
        success = FALSE;
    }

  return gimp_procedure_get_return_values (procedure, success,
                                           error ? *error : NULL);
}

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

  drawable = gimp_value_get_drawable (gimp_value_array_index (args, 0), gimp);
  channel = g_value_get_enum (gimp_value_array_index (args, 1));
  num_points = g_value_get_int (gimp_value_array_index (args, 2));
  control_pts = gimp_value_get_int8array (gimp_value_array_index (args, 3));

  if (success)
    {
      if (gimp_pdb_item_is_attached (GIMP_ITEM (drawable), NULL,
                                     GIMP_PDB_ITEM_CONTENT, error) &&
          gimp_pdb_item_is_not_group (GIMP_ITEM (drawable), error) &&
          ! (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)  &&
           channel != GIMP_HISTOGRAM_LUMINANCE)
        {
          GObject *config = gimp_curves_config_new_spline_cruft (channel,
                                                                 control_pts,
                                                                 num_points / 2);

          gimp_drawable_apply_operation_by_name (drawable, progress,
                                                 C_("undo-type", "Curves"),
                                                 "gimp:curves",
                                                 config);
          g_object_unref (config);
        }
      else
        success = FALSE;
    }

  return gimp_procedure_get_return_values (procedure, success,
                                           error ? *error : NULL);
}

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

  drawable = gimp_value_get_drawable (gimp_value_array_index (args, 0), gimp);
  channel = g_value_get_enum (gimp_value_array_index (args, 1));
  num_bytes = g_value_get_int (gimp_value_array_index (args, 2));
  curve = gimp_value_get_int8array (gimp_value_array_index (args, 3));

  if (success)
    {
      if (gimp_pdb_item_is_attached (GIMP_ITEM (drawable), NULL,
                                     GIMP_PDB_ITEM_CONTENT, error) &&
          gimp_pdb_item_is_not_group (GIMP_ITEM (drawable), error) &&
          (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) &&
           channel != GIMP_HISTOGRAM_LUMINANCE)
        {
          GObject *config = gimp_curves_config_new_explicit_cruft (channel,
                                                                   curve,
                                                                   num_bytes);

          gimp_drawable_apply_operation_by_name (drawable, progress,
                                                 C_("undo-type", "Curves"),
                                                 "gimp:curves",
                                                 config);
          g_object_unref (config);
        }
      else
        success = FALSE;
    }

  return gimp_procedure_get_return_values (procedure, success,
                                           error ? *error : NULL);
}

static GimpValueArray *
color_balance_invoker (GimpProcedure         *procedure,
                       Gimp                  *gimp,
                       GimpContext           *context,
                       GimpProgress          *progress,
                       const GimpValueArray  *args,
                       GError               **error)
{
  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 (gimp_value_array_index (args, 0), gimp);
  transfer_mode = g_value_get_enum (gimp_value_array_index (args, 1));
  preserve_lum = g_value_get_boolean (gimp_value_array_index (args, 2));
  cyan_red = g_value_get_double (gimp_value_array_index (args, 3));
  magenta_green = g_value_get_double (gimp_value_array_index (args, 4));
  yellow_blue = g_value_get_double (gimp_value_array_index (args, 5));

  if (success)
    {
      if (gimp_pdb_item_is_attached (GIMP_ITEM (drawable), NULL,
                                     GIMP_PDB_ITEM_CONTENT, error)  &&
          gimp_pdb_item_is_not_group (GIMP_ITEM (drawable), error))
        {
          GObject *config = g_object_new (GIMP_TYPE_COLOR_BALANCE_CONFIG,
                                          "range",               transfer_mode,
                                          "preserve-luminosity", preserve_lum,
                                          NULL);

          g_object_set (config,
                        "cyan-red",      cyan_red      / 100.0,
                        "magenta-green", magenta_green / 100.0,
                        "yellow-blue",   yellow_blue   / 100.0,
                        NULL);

          gimp_drawable_apply_operation_by_name (drawable, progress,
                                                 C_("undo-type", "Color Balance"),
                                                 "gimp:color-balance",
                                                 config);
          g_object_unref (config);
        }
      else
        success = FALSE;
    }

  return gimp_procedure_get_return_values (procedure, success,
                                           error ? *error : NULL);
}

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

  drawable = gimp_value_get_drawable (gimp_value_array_index (args, 0), gimp);
  hue = g_value_get_double (gimp_value_array_index (args, 1));
  saturation = g_value_get_double (gimp_value_array_index (args, 2));
  lightness = g_value_get_double (gimp_value_array_index (args, 3));

  if (success)
    {
      if (gimp_pdb_item_is_attached (GIMP_ITEM (drawable), NULL,
                                     GIMP_PDB_ITEM_CONTENT, error) &&
          gimp_pdb_item_is_not_group (GIMP_ITEM (drawable), error) &&
          ! gimp_drawable_is_gray (drawable))
        {
          GeglNode *node =
            gegl_node_new_child (NULL,
                                 "operation", "gimp:colorize",
                                 "hue",        hue        / 360.0,
                                 "saturation", saturation / 100.0,
                                 "lightness",  lightness  / 100.0,
                                 NULL);

          gimp_drawable_apply_operation (drawable, progress,
                                         C_("undo-type", "Colorize"),
                                         node);
          g_object_unref (node);
        }
      else
        success = FALSE;
    }

  return gimp_procedure_get_return_values (procedure, success,
                                           error ? *error : NULL);
}

static GimpValueArray *
histogram_invoker (GimpProcedure         *procedure,
                   Gimp                  *gimp,
                   GimpContext           *context,
                   GimpProgress          *progress,
                   const GimpValueArray  *args,
                   GError               **error)
{
  gboolean success = TRUE;
  GimpValueArray *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 (gimp_value_array_index (args, 0), gimp);
  channel = g_value_get_enum (gimp_value_array_index (args, 1));
  start_range = g_value_get_int (gimp_value_array_index (args, 2));
  end_range = g_value_get_int (gimp_value_array_index (args, 3));

  if (success)
    {
      if (! gimp_pdb_item_is_attached (GIMP_ITEM (drawable), NULL, 0, error) ||
          (! 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;
          gint           start = start_range;
          gint           end   = end_range;
          gboolean       precision_enabled;
          gboolean       linear;
          gint           n_bins;

          precision_enabled =
            gimp->plug_in_manager->current_plug_in &&
            gimp_plug_in_precision_enabled (gimp->plug_in_manager->current_plug_in);

          if (precision_enabled)
            linear = gimp_drawable_get_linear (drawable);
          else
            linear = FALSE;

          histogram = gimp_histogram_new (linear);
          gimp_drawable_calculate_histogram (drawable, histogram, FALSE);

          n_bins = gimp_histogram_n_bins (histogram);

          if (n_bins != 256)
            {
              start = ROUND ((gdouble) start * (n_bins - 1) / 255);
              end   = ROUND ((gdouble) end   * (n_bins - 1) / 255);
            }

          mean       = gimp_histogram_get_mean (histogram, channel,
                                                 start, end);
          std_dev    = gimp_histogram_get_std_dev (histogram, channel,
                                                   start, end);
          median     = gimp_histogram_get_median (histogram, channel,
                                                  start, end);
          pixels     = gimp_histogram_get_count (histogram, channel, 0, n_bins - 1);
          count      = gimp_histogram_get_count (histogram, channel,
                                                 start, end);
          percentile = count / pixels;

          g_object_unref (histogram);

          if (n_bins == 256 || ! precision_enabled)
            {
              mean    *= 255;
              std_dev *= 255;
              median  *= 255;
            }
        }
    }

  return_vals = gimp_procedure_get_return_values (procedure, success,
                                                  error ? *error : NULL);

  if (success)
    {
      g_value_set_double (gimp_value_array_index (return_vals, 1), mean);
      g_value_set_double (gimp_value_array_index (return_vals, 2), std_dev);
      g_value_set_double (gimp_value_array_index (return_vals, 3), median);
      g_value_set_double (gimp_value_array_index (return_vals, 4), pixels);
      g_value_set_double (gimp_value_array_index (return_vals, 5), count);
      g_value_set_double (gimp_value_array_index (return_vals, 6), percentile);
    }

  return return_vals;
}

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

  drawable = gimp_value_get_drawable (gimp_value_array_index (args, 0), gimp);
  hue_range = g_value_get_enum (gimp_value_array_index (args, 1));
  hue_offset = g_value_get_double (gimp_value_array_index (args, 2));
  lightness = g_value_get_double (gimp_value_array_index (args, 3));
  saturation = g_value_get_double (gimp_value_array_index (args, 4));

  if (success)
    {
      if (gimp_pdb_item_is_attached (GIMP_ITEM (drawable), NULL,
                                     GIMP_PDB_ITEM_CONTENT, error) &&
          gimp_pdb_item_is_not_group (GIMP_ITEM (drawable), error))
        {
          GObject *config = g_object_new (GIMP_TYPE_HUE_SATURATION_CONFIG,
                                          "range", hue_range,
                                          NULL);

           g_object_set (config,
                         "hue",        hue_offset / 180.0,
                         "saturation", saturation / 100.0,
                         "lightness",  lightness  / 100.0,
                         NULL);

          gimp_drawable_apply_operation_by_name (drawable, progress,
                                                 _("Hue-Saturation"),
                                                 "gimp:hue-saturation",
                                                 config);
          g_object_unref (config);
        }
      else
        success = FALSE;
    }

  return gimp_procedure_get_return_values (procedure, success,
                                           error ? *error : NULL);
}

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

  drawable = gimp_value_get_drawable (gimp_value_array_index (args, 0), gimp);
  low_threshold = g_value_get_int (gimp_value_array_index (args, 1));
  high_threshold = g_value_get_int (gimp_value_array_index (args, 2));

  if (success)
    {
      if (gimp_pdb_item_is_attached (GIMP_ITEM (drawable), NULL,
                                     GIMP_PDB_ITEM_CONTENT, error) &&
          gimp_pdb_item_is_not_group (GIMP_ITEM (drawable), error))
        {
          GeglNode *node =
            gegl_node_new_child (NULL,
                                 "operation", "gimp:threshold",
                                 "low",       low_threshold  / 255.0,
                                 "high",      high_threshold / 255.0,
                                 NULL);

          gimp_drawable_apply_operation (drawable, progress,
                                         C_("undo-type", "Threshold"),
                                         node);
          g_object_unref (node);
        }
      else
        success = FALSE;
    }

  return gimp_procedure_get_return_values (procedure, success,
                                           error ? *error : NULL);
}

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",
                                     "Deprecated: Use 'gimp-drawable-brightness-contrast' instead.",
                                     "Deprecated: Use 'gimp-drawable-brightness-contrast' instead.",
                                     "",
                                     "",
                                     "",
                                     "gimp-drawable-brightness-contrast");
  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",
                                     "Deprecated: Use 'gimp-drawable-levels' instead.",
                                     "Deprecated: Use 'gimp-drawable-levels' instead.",
                                     "",
                                     "",
                                     "",
                                     "gimp-drawable-levels");
  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 adjustment 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",
                                     "Deprecated: Use 'gimp-drawable-levels-stretch' instead.",
                                     "Deprecated: Use 'gimp-drawable-levels-stretch' instead.",
                                     "",
                                     "",
                                     "",
                                     "gimp-drawable-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",
                                     "Deprecated: Use 'gimp-drawable-levels-stretch' instead.",
                                     "Deprecated: Use 'gimp-drawable-levels-stretch' instead.",
                                     "",
                                     "",
                                     "",
                                     "gimp-drawable-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-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",
                                     "Deprecated: Use 'gimp-drawable-posterize' instead.",
                                     "Deprecated: Use 'gimp-drawable-posterize' instead.",
                                     "",
                                     "",
                                     "",
                                     "gimp-drawable-posterize");
  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",
                                     "Deprecated: Use 'gimp-drawable-desaturate' instead.",
                                     "Deprecated: Use 'gimp-drawable-desaturate' instead.",
                                     "",
                                     "",
                                     "",
                                     "gimp-drawable-desaturate");
  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",
                                     "Deprecated: Use 'gimp-drawable-desaturate' instead.",
                                     "Deprecated: Use 'gimp-drawable-desaturate' instead.",
                                     "",
                                     "",
                                     "",
                                     "gimp-drawable-desaturate");
  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",
                                     "Deprecated: Use 'gimp-drawable-equalize' instead.",
                                     "Deprecated: Use 'gimp-drawable-equalize' instead.",
                                     "",
                                     "",
                                     "",
                                     "gimp-drawable-equalize");
  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",
                                     "Deprecated: Use 'gimp-drawable-invert' instead.",
                                     "Deprecated: Use 'gimp-drawable-invert' instead.",
                                     "",
                                     "",
                                     "",
                                     "gimp-drawable-invert");
  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",
                                     "Deprecated: Use 'gimp-drawable-curves-spline' instead.",
                                     "Deprecated: Use 'gimp-drawable-curves-spline' instead.",
                                     "",
                                     "",
                                     "",
                                     "gimp-drawable-curves-spline");
  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",
                                     "Deprecated: Use 'gimp-drawable-curves-explicit' instead.",
                                     "Deprecated: Use 'gimp-drawable-curves-explicit' instead.",
                                     "",
                                     "",
                                     "",
                                     "gimp-drawable-curves-explicit");
  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, mid-tones, and highlights in an image to be affected differently. The 'preserve-lum' parameter, if TRUE, ensures that the luminosity of each pixel remains fixed.\n"
                                     "\n"
                                     "Deprecated: Use 'gimp-drawable-color-color-balance' instead.",
                                     "Spencer Kimball & Peter Mattis",
                                     "Spencer Kimball & Peter Mattis",
                                     "1997",
                                     "gimp-drawable-color-color-balance");
  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_TRANSFER_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",
                                     "Deprecated: Use 'gimp-drawable-colorize-hsl' instead.",
                                     "Deprecated: Use 'gimp-drawable-colorize-hsl' instead.",
                                     "",
                                     "",
                                     "",
                                     "gimp-drawable-colorize-hsl");
  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",
                                     "Deprecated: Use 'gimp-drawable-histogram' instead.",
                                     "Deprecated: Use 'gimp-drawable-histogram' instead.",
                                     "",
                                     "",
                                     "",
                                     "gimp-drawable-histogram");
  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, 255, 0,
                                                      GIMP_PARAM_READWRITE));
  gimp_procedure_add_argument (procedure,
                               gimp_param_spec_int32 ("end-range",
                                                      "end range",
                                                      "End of the intensity measurement range",
                                                      0, 255, 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",
                                     "Deprecated: Use 'gimp-drawable-hue-saturation' instead.",
                                     "Deprecated: Use 'gimp-drawable-hue-saturation' instead.",
                                     "",
                                     "",
                                     "",
                                     "gimp-drawable-hue-saturation");
  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_HUE_RANGE_ALL,
                                                  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",
                                     "Deprecated: Use 'gimp-drawable-threshold' instead.",
                                     "Deprecated: Use 'gimp-drawable-threshold' instead.",
                                     "",
                                     "",
                                     "",
                                     "gimp-drawable-threshold");
  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);
}
