Eine aufbereitete Darstellung der Quelle

 
     
 
 
Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 

Benutzer

Quelle  gimpcurve.c   Sprache: C

 

/* LIBGIMP - The GIMP Library
 * Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
 *
 * gimpcurve.c
 * Copyright (C) 2026 Alx Sa
 *
 * This library is free software: you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 3 of the License, or (at your option) any later version.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library.  If not, see
 * <https://www.gnu.org/licenses/>.
 */


#include "config.h"

#include "gimp.h"

#include "gimpcurve.h"


enum
{
  PROP_0,
  PROP_CURVE_TYPE,
  PROP_N_SAMPLES,
  N_PROPS
};
static GParamSpec *obj_props[N_PROPS] = { NULL, };

enum
{
  POINTS_CHANGED,
  SAMPLES_CHANGED,
  LAST_SIGNAL
};
static guint gimp_curve_signals[LAST_SIGNAL] = { 0 };

typedef struct
{
  gdouble           x;
  gdouble           y;

 GimpCurvePointType type;
} GimpCurvePoint;

struct _GimpCurve
{
  GObject           parent_instance;

  GimpCurveType     curve_type;

  gint              n_points;
  GimpCurvePoint   *points;

  gint              n_samples;
  gdouble          *samples;

  gboolean          identity;   /* whether the curve is an identity mapping */
};

static void          gimp_curve_finalize          (GObject          *object);
static void          gimp_curve_set_property      (GObject          *object,
                                                   guint             property_id,
                                                   const GValue     *value,
                                                   GParamSpec       *pspec);
static void          gimp_curve_get_property      (GObject          *object,
                                                   guint             property_id,
                                                   GValue           *value,
                                                   GParamSpec       *pspec);

static void          gimp_curve_build_samples     (GimpCurve        *curve);


G_DEFINE_TYPE (GimpCurve, gimp_curve, G_TYPE_OBJECT);

static void  gimp_curve_class_init (GimpCurveClass *klass)
{
  GObjectClass *object_class = G_OBJECT_CLASS (klass);

  /**
   * GimpCurve::points-changed:
   * @curve: the curve emitting the signal
   *
   * Emitted when any points are added, deleted, or edited in @curve.
   *
   * Since: 3.2
   */

  gimp_curve_signals[POINTS_CHANGED] =
    g_signal_new ("points-changed",
                  G_TYPE_FROM_CLASS (klass),
                  G_SIGNAL_RUN_FIRST,
                  0,
                  NULL, NULL, NULL,
                  G_TYPE_NONE, 0);

  /**
   * GimpCurve::samples-changed:
   * @curve: the curve emitting the signal
   *
   * Emitted when any sample is edited, or if the number of samples
   * changed, in @curve.
   *
   * Since: 3.2
   */

  gimp_curve_signals[SAMPLES_CHANGED] =
    g_signal_new ("samples-changed",
                  G_TYPE_FROM_CLASS (klass),
                  G_SIGNAL_RUN_FIRST,
                  0,
                  NULL, NULL, NULL,
                  G_TYPE_NONE, 0);

  object_class->finalize     = gimp_curve_finalize;
  object_class->set_property = gimp_curve_set_property;
  object_class->get_property = gimp_curve_get_property;

  /**
   * GimpCurve:curve-type:
   *
   * The curve type.
   *
   * Since: 3.2
   */

  obj_props[PROP_CURVE_TYPE] =
      g_param_spec_enum ("curve-type",
                         "Curve Type",
                         "The curve type",
                         GIMP_TYPE_CURVE_TYPE,
                         GIMP_CURVE_SMOOTH,
                         GIMP_CONFIG_PARAM_FLAGS |
                         G_PARAM_EXPLICIT_NOTIFY);

  /**
   * GimpCurve:n-samples:
   *
   * The number of samples this [enum@Gimp.CurveType.FREE] curve is
   * split into.
   *
   * Since: 3.2
   */

  obj_props[PROP_N_SAMPLES] =
      g_param_spec_int ("n-samples",
                        "Number of Samples",
                        "The number of samples",
                        256, 256, 256,
                        GIMP_CONFIG_PARAM_FLAGS |
                        G_PARAM_EXPLICIT_NOTIFY);

  g_object_class_install_properties (object_class, N_PROPS, obj_props);
}

static void
gimp_curve_init (GimpCurve *curve)
{
  curve->n_points  = 0;
  curve->points    = NULL;
  curve->n_samples = 256;
  curve->samples   = NULL;
  curve->identity  = FALSE;
}

static void
gimp_curve_finalize (GObject *object)
{
  GimpCurve *curve = GIMP_CURVE (object);

  g_clear_pointer (&curve->points,  g_free);
  curve->n_points = 0;

  g_clear_pointer (&curve->samples, g_free);
  curve->n_samples = 0;
}

static void
gimp_curve_set_property (GObject      *object,
                         guint         property_id,
                         const GValue *value,
                         GParamSpec   *pspec)
{
  GimpCurve *curve = GIMP_CURVE (object);

  switch (property_id)
    {
    case PROP_CURVE_TYPE:
      gimp_curve_set_curve_type (curve, g_value_get_enum (value));
      break;

    case PROP_N_SAMPLES:
      if (curve->curve_type == GIMP_CURVE_FREE)
        gimp_curve_set_n_samples (curve, g_value_get_int (value));
      else
        curve->n_samples = g_value_get_int (value);
      break;

    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
      break;
    }
}

static void
gimp_curve_get_property (GObject    *object,
                         guint       property_id,
                         GValue     *value,
                         GParamSpec *pspec)
{
  GimpCurve *curve = GIMP_CURVE (object);

  switch (property_id)
    {
    case PROP_CURVE_TYPE:
      g_value_set_enum (value, curve->curve_type);
      break;

    case PROP_N_SAMPLES:
      g_value_set_int (value, curve->n_samples);
      break;

    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
      break;
    }
}

/* Public Functions */

/**
 * gimp_curve_new:
 *
 * Creates a new #GimpCurve object, of type
 * [enum@Gimp.CurveType.SMOOTH], with 0 points initially.
 *
 * Returns: (transfer full): a new curve.
 *
 * Since: 3.2
 */

GimpCurve *
gimp_curve_new (void)
{
  return g_object_new (GIMP_TYPE_CURVE, NULL);
}

/**
 * gimp_curve_get_curve_type:
 * @curve: the #GimpCurve.
 *
 * Returns: the @curve type.
 *
 * Since: 3.2
 */

GimpCurveType
gimp_curve_get_curve_type (GimpCurve *curve)
{
  g_return_val_if_fail (GIMP_IS_CURVE (curve), GIMP_CURVE_SMOOTH);

  return curve->curve_type;
}

/**
 * gimp_curve_set_curve_type:
 * @curve: the #GimpCurve.
 * @curve_type: the new curve type.
 *
 * Sets the curve type of @curve, as follows:
 *
 * - Nothing happens if the curve type is unchanged.
 * - If you change to [enum@Gimp.CurveType.SMOOTH], it will create a
 *   non-specified number of points and will approximate their position
 *   along the freehand curve. All default points will be
 *   [enum@Gimp.CurvePointType.SMOOTH].
 * - If you change to [enum@Gimp.CurveType.FREE], all existing points
 *   will be cleared.
 *
 * Since: 3.2
 */

void
gimp_curve_set_curve_type (GimpCurve     *curve,
                           GimpCurveType  curve_type)
{
  g_return_if_fail (GIMP_IS_CURVE (curve));

  if (curve->curve_type != curve_type)
    {
      g_object_freeze_notify (G_OBJECT (curve));

      if (curve_type == GIMP_CURVE_SMOOTH)
        {
          gint i;

          curve->curve_type = curve_type;

          g_free (curve->points);

          /*  pick some points from the curve and make them control
           *  points
           */

          curve->n_points = 9;
          curve->points   = g_new0 (GimpCurvePoint, 9);

          for (i = 0; i < curve->n_points; i++)
            {
              gint sample = i * (curve->n_samples - 1) / (curve->n_points - 1);

              curve->points[i].x    = (gdouble) sample /
                                      (gdouble) (curve->n_samples - 1);
              curve->points[i].y    = curve->samples[sample];
              curve->points[i].type = GIMP_CURVE_POINT_SMOOTH;
            }

          g_signal_emit (G_OBJECT (curve), gimp_curve_signals[POINTS_CHANGED], 0);
        }
      else
        {
          gimp_curve_clear_points (curve);
          curve->curve_type = curve_type;
          gimp_curve_build_samples (curve);
        }

      g_object_notify_by_pspec (G_OBJECT (curve), obj_props[PROP_CURVE_TYPE]);

      g_object_thaw_notify (G_OBJECT (curve));
    }
}

/**
 * gimp_curve_get_n_points:
 * @curve: the #GimpCurve.
 *
 * Gets the number of points in a [enum@Gimp.CurveType.SMOOTH] curve. Note that it will always
 * be 0 for a [enum@Gimp.CurveType.FREE] curve.
 *
 * This can later be used e.g. in [method@Gimp.Curve.get_point] as points
 * are numbered from 0 (included) to the returned number (excluded).
 *
 * Note that the #GimpCurve API is not thread-safe. So be careful that
 * the information on the number of points is still valid when you use
 * it (you may have added or removed points in particular).
 *
 * Returns: the number of points in a smooth curve.
 *
 * Since: 3.2
 */

gint
gimp_curve_get_n_points (GimpCurve *curve)
{
  g_return_val_if_fail (GIMP_IS_CURVE (curve), 0);
  g_return_val_if_fail (curve->curve_type == GIMP_CURVE_SMOOTH, 0);

  return curve->n_points;
}

/**
 * gimp_curve_add_point:
 * @curve: the #GimpCurve.
 * @x: the point abscissa on a `[0.0, 1.0]` range.
 * @y: the point ordinate on a `[0.0, 1.0]` range.
 *
 * Add a new point in a [enum@Gimp.CurveType.SMOOTH] @curve, with
 * coordinates `(x, y)`. Any value outside the `[0.0, 1.0]` range will
 * be silently clamped.
 *
 * The returned identifier can later be used e.g. in
 * [method@Gimp.Curve.get_point] or other functions taking a @point number
 * as argument.
 *
 * Calling this may change identifiers for other points and the total
 * number of points in this @curve. Any such information you currently
 * hold should be considered invalid once the curve is changed.
 *
 * Returns: a point identifier to be used in other functions.
 *
 * Since: 3.2
 */

gint
gimp_curve_add_point (GimpCurve *curve,
                      gdouble    x,
                      gdouble    y)
{
  GimpCurvePoint *points;
  gint            point;

  g_return_val_if_fail (GIMP_IS_CURVE (curve), -1);
  g_return_val_if_fail (curve->curve_type == GIMP_CURVE_SMOOTH, -1);

  x = CLAMP (x, 0.0, 1.0);
  y = CLAMP (y, 0.0, 1.0);

  for (point = 0; point < curve->n_points; point++)
    {
      if (curve->points[point].x > x)
        break;
    }

  points = g_new0 (GimpCurvePoint, curve->n_points + 1);

  memcpy (points,         curve->points,
          point * sizeof (GimpCurvePoint));
  memcpy (points + point + 1, curve->points + point,
          (curve->n_points - point) * sizeof (GimpCurvePoint));

  points[point].x    = x;
  points[point].y    = y;
  points[point].type = GIMP_CURVE_POINT_SMOOTH;

  g_free (curve->points);

  curve->n_points++;
  curve->points = points;

  g_signal_emit (G_OBJECT (curve), gimp_curve_signals[POINTS_CHANGED], 0);

  return point;
}

/**
 * gimp_curve_get_point:
 * @curve: the #GimpCurve.
 * @point: a point identifier.
 * @x: (out) (nullable): the point abscissa on a `[0.0, 1.0]` range.
 * @y: (out) (nullable): the point ordinate on a `[0.0, 1.0]` range.
 *
 * Gets the @point coordinates for a [enum@Gimp.CurveType.SMOOTH] @curve.
 *
 * The @point identifier must be between 0 and the value returned by
 * [method@Gimp.Curve.get_n_points].
 *
 * You may also use a point identifier as returned by
 * [method@Gimp.Curve.add_point], which will correspond to the same
 * point, unless you modified the @curve since (e.g. by calling
 * `gimp_curve_add_point` again, or by deleting or modifying a point).
 *
 * Since: 3.2
 */

void
gimp_curve_get_point (GimpCurve *curve,
                      gint       point,
                      gdouble   *x,
                      gdouble   *y)
{
  g_return_if_fail (GIMP_IS_CURVE (curve));
  g_return_if_fail (curve->curve_type == GIMP_CURVE_SMOOTH);
  g_return_if_fail (point >= 0 && point < curve->n_points);

  if (x) *x = curve->points[point].x;
  if (y) *y = curve->points[point].y;
}

/**
 * gimp_curve_set_point_type:
 * @curve: the #GimpCurve.
 * @point: a point identifier.
 * @type: a point type.
 *
 * Sets the @point type in a [enum@Gimp.CurveType.SMOOTH] @curve.
 *
 * Since: 3.2
 */

void
gimp_curve_set_point_type (GimpCurve          *curve,
                           gint                point,
                           GimpCurvePointType  type)
{
  g_return_if_fail (GIMP_IS_CURVE (curve));
  g_return_if_fail (curve->curve_type == GIMP_CURVE_SMOOTH);
  g_return_if_fail (point >= 0 && point < curve->n_points);

  curve->points[point].type = type;

  g_signal_emit (G_OBJECT (curve), gimp_curve_signals[POINTS_CHANGED], 0);
}

/**
 * gimp_curve_get_point_type:
 * @curve: the #GimpCurve.
 * @point: a point identifier.
 *
 * Returns: the @point type of a [enum@Gimp.CurveType.SMOOTH] @curve.
 *
 * Since: 3.2
 */

GimpCurvePointType
gimp_curve_get_point_type (GimpCurve *curve,
                           gint       point)
{
  g_return_val_if_fail (GIMP_IS_CURVE (curve), GIMP_CURVE_POINT_SMOOTH);
  g_return_val_if_fail (curve->curve_type == GIMP_CURVE_SMOOTH, GIMP_CURVE_POINT_SMOOTH);
  g_return_val_if_fail (point >= 0 && point < curve->n_points, GIMP_CURVE_POINT_SMOOTH);

  return curve->points[point].type;
}

/**
 * gimp_curve_delete_point:
 * @curve: the #GimpCurve.
 * @point: a point identifier.
 *
 * Deletes a specific @point from a [enum@Gimp.CurveType.SMOOTH] @curve.
 *
 * The @point identifier must be between 0 and the value returned by
 * [method@Gimp.Curve.get_n_points].
 *
 * You may also use a point identifier as returned by
 * [method@Gimp.Curve.add_point], which will correspond to the same
 * point, unless you modified the @curve since (e.g. by calling
 * `gimp_curve_add_point` again, or by deleting or modifying a point).
 *
 * Since: 3.2
 */

void
gimp_curve_delete_point (GimpCurve *curve,
                         gint       point)
{
  GimpCurvePoint *points;

  g_return_if_fail (GIMP_IS_CURVE (curve));
  g_return_if_fail (curve->curve_type == GIMP_CURVE_SMOOTH);
  g_return_if_fail (point >= 0 && point < curve->n_points);

  points = g_new0 (GimpCurvePoint, curve->n_points - 1);

  memcpy (points,         curve->points,
          point * sizeof (GimpCurvePoint));
  memcpy (points + point, curve->points + point + 1,
          (curve->n_points - point - 1) * sizeof (GimpCurvePoint));

  g_free (curve->points);

  curve->n_points--;
  curve->points = points;

  g_signal_emit (G_OBJECT (curve), gimp_curve_signals[POINTS_CHANGED], 0);
}

/**
 * gimp_curve_set_point:
 * @curve: the #GimpCurve.
 * @point: a point identifier.
 * @x: the point abscissa on a `[0.0, 1.0]` range.
 * @y: the point ordinate on a `[0.0, 1.0]` range.
 *
 * Sets the @point coordinates in a [enum@Gimp.CurveType.SMOOTH] @curve.
 * Any value outside the `[0.0, 1.0]` range will be silently clamped.
 *
 * Since: 3.2
 */

void
gimp_curve_set_point (GimpCurve *curve,
                      gint       point,
                      gdouble    x,
                      gdouble    y)
{
  g_return_if_fail (GIMP_IS_CURVE (curve));
  g_return_if_fail (curve->curve_type == GIMP_CURVE_SMOOTH);
  g_return_if_fail (point >= 0 && point < curve->n_points);

  curve->points[point].x = CLAMP (x, 0.0, 1.0);
  curve->points[point].y = CLAMP (y, 0.0, 1.0);

  if (point > 0)
    curve->points[point].x = MAX (x, curve->points[point - 1].x);

  if (point < curve->n_points - 1)
    curve->points[point].x = MIN (x, curve->points[point + 1].x);

  g_signal_emit (G_OBJECT (curve), gimp_curve_signals[POINTS_CHANGED], 0);
}

/**
 * gimp_curve_clear_points:
 * @curve: the #GimpCurve.
 *
 * Deletes all points from a [enum@Gimp.CurveType.SMOOTH] @curve.
 *
 * A subsequent call to [method@Gimp.Curve.get_n_points] will return 0.
 *
 * Since: 3.2
 */

void
gimp_curve_clear_points (GimpCurve *curve)
{
  g_return_if_fail (GIMP_IS_CURVE (curve));
  g_return_if_fail (curve->curve_type == GIMP_CURVE_SMOOTH);

  if (curve->points)
    {
      g_clear_pointer (&curve->points, g_free);
      curve->n_points = 0;

      g_signal_emit (G_OBJECT (curve), gimp_curve_signals[POINTS_CHANGED], 0);
    }
}

/**
 * gimp_curve_get_n_samples:
 * @curve: the #GimpCurve.
 *
 * Gets the number of samples in a [enum@Gimp.CurveType.FREE] curve.
 *
 * Returns: the number of samples in a freehand curve.
 *
 * Since: 3.2
 */

gint
gimp_curve_get_n_samples (GimpCurve *curve)
{
  g_return_val_if_fail (GIMP_IS_CURVE (curve), 0);
  g_return_val_if_fail (curve->curve_type == GIMP_CURVE_FREE, 0);

  return curve->n_samples;
}

/**
 * gimp_curve_set_n_samples:
 * @curve: the #GimpCurve.
 * @n_samples: the number of samples.
 *
 * Sets the number of sample in a [enum@Gimp.CurveType.FREE] @curve.
 *
 * Samples will be positioned on the curve abscissa at regular interval.
 * The more samples, the more your curve will have details. Currently,
 * the value of @n_samples is limited and must be between `2^8` and `2^12`.
 *
 * Note that changing the number of samples will reset the curve to an
 * identity curve.
 *
 * Since: 3.2
 */

void
gimp_curve_set_n_samples (GimpCurve *curve,
                          gint       n_samples)
{
  g_return_if_fail (GIMP_IS_CURVE (curve));
  g_return_if_fail (curve->curve_type == GIMP_CURVE_FREE);
  g_return_if_fail (n_samples >= 256);
  g_return_if_fail (n_samples <= 4096);

  if (n_samples != curve->n_samples)
    {
      g_object_freeze_notify (G_OBJECT (curve));
      curve->n_samples = n_samples;
      gimp_curve_build_samples (curve);
      g_object_thaw_notify (G_OBJECT (curve));

      g_object_notify_by_pspec (G_OBJECT (curve), obj_props[PROP_N_SAMPLES]);
      g_signal_emit (G_OBJECT (curve), gimp_curve_signals[SAMPLES_CHANGED], 0);
    }
}

/**
 * gimp_curve_get_sample:
 * @curve: the #GimpCurve.
 * @x: an abscissa on a `[0.0, 1.0]` range.
 *
 * Gets the ordinate @y value corresponding to the passed @x abscissa
 * value, in a [enum@Gimp.CurveType.FREE] @curve.
 *
 * Note that while the @y coordinate will be stored exactly, the @x
 * coordinate will be rounded to the closest curve sample on the
 * abscissa. The more sample was set with
 * [method@Gimp.Curve.set_n_samples], the more precise the rounding will
 * be.
 *
 * Since: 3.2
 */

gdouble
gimp_curve_get_sample (GimpCurve *curve,
                       gdouble    x)
{
  g_return_val_if_fail (GIMP_IS_CURVE (curve), 0);
  g_return_val_if_fail (curve->curve_type == GIMP_CURVE_FREE, 0);
  g_return_val_if_fail (x >= 0 && x <= 1.0, 0);

  return curve->samples[ROUND (x * (gdouble) (curve->n_samples - 1))];
}

/**
 * gimp_curve_set_sample:
 * @curve: the #GimpCurve.
 * @x: the point abscissa on a `[0.0, 1.0]` range.
 * @y: the point ordinate on a `[0.0, 1.0]` range.
 *
 * Sets a sample in a [enum@Gimp.CurveType.FREE] @curve, with
 * coordinates `(x, y)`.
 *
 * Note that while the @y coordinate will be stored exactly, the @x
 * coordinate will be rounded to the closest curve sample on the
 * abscissa. The more sample was set with
 * [method@Gimp.Curve.set_n_samples], the more precise the rounding will
 * be.
 *
 * Since: 3.2
 */

void
gimp_curve_set_sample (GimpCurve *curve,
                       gdouble    x,
                       gdouble    y)
{
  g_return_if_fail (GIMP_IS_CURVE (curve));
  g_return_if_fail (curve->curve_type == GIMP_CURVE_FREE);
  g_return_if_fail (x >= 0 && x <= 1.0);
  g_return_if_fail (y >= 0 && y <= 1.0);

  curve->samples[ROUND (x * (gdouble) (curve->n_samples - 1))] = y;

  g_signal_emit (G_OBJECT (curve), gimp_curve_signals[SAMPLES_CHANGED], 0);
}

/**
 * gimp_curve_is_identity:
 * @curve: a #GimpCurve object
 *
 * If this function returns %TRUE, then the curve maps each value to
 * itself. If it returns %FALSE, then this assumption can not be made.
 *
 * Returns: %TRUE if the curve is an identity mapping, %FALSE otherwise.
 *
 * Since: 3.2
 **/

gboolean
gimp_curve_is_identity (GimpCurve *curve)
{
  g_return_val_if_fail (GIMP_IS_CURVE (curve), FALSE);

  return curve->identity;
}


/* Private functions */

static void
gimp_curve_build_samples (GimpCurve *curve)
{
  curve->samples = g_renew (gdouble, curve->samples, curve->n_samples);

  for (gint i = 0; i < curve->n_samples; i++)
    curve->samples[i] = (gdouble) i / (gdouble) (curve->n_samples - 1);

  if (curve->curve_type == GIMP_CURVE_FREE)
    curve->identity = TRUE;
}

Messung
CHZG
839210091

¤ Dauer der Verarbeitung: 0.13 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover


Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Open Source Software

     Quellcodebibliothek
     Eigene Quellcodes
     Fremde Quellcodes
     Suchen

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Statistik
#Sources=1104838
#Domains=499075