libgimp, pdb: Allow access to GimpCurve in PDB

Adds a GimpCurve object and functions in libgimp.
Rather than creating a GimpCurve object in core and
passing it back and forth, we just pass the attributes
and reconstruct it across.
In the future, we may combine this with the app/core one
and put it in libgimpbase.
This commit is contained in:
Alx Sa 2026-02-09 03:03:39 +00:00 committed by Jehan
parent 66efbd003c
commit 804991a215
22 changed files with 1193 additions and 7 deletions

View file

@ -194,7 +194,7 @@ typedef enum /*< pdb-skip >*/
GType gimp_curve_point_type_get_type (void) G_GNUC_CONST;
typedef enum /*< pdb-skip >*/
typedef enum
{
GIMP_CURVE_POINT_SMOOTH, /*< desc="Smooth" >*/
GIMP_CURVE_POINT_CORNER /*< desc="Corner" >*/
@ -205,7 +205,7 @@ typedef enum /*< pdb-skip >*/
GType gimp_curve_type_get_type (void) G_GNUC_CONST;
typedef enum /*< pdb-skip >*/
typedef enum
{
GIMP_CURVE_SMOOTH, /*< desc="Smooth" >*/
GIMP_CURVE_FREE /*< desc="Freehand" >*/

View file

@ -29,6 +29,7 @@
#include "gimp.h"
#include "gimpbrush.h"
#include "gimpcontext.h"
#include "gimpcurve.h"
#include "gimpdisplay.h"
#include "gimpdrawablefilter.h"
#include "gimpgradient.h"

View file

@ -33,6 +33,7 @@
#include "core/gimp.h"
#include "core/gimpbrush.h"
#include "core/gimpcurve.h"
#include "core/gimpdisplay.h"
#include "core/gimpdrawablefilter.h"
#include "core/gimpgradient.h"

View file

@ -1048,6 +1048,15 @@ plug_in_proc_arg_deserialize (GScanner *scanner,
goto error;
}
break;
case GP_PARAM_DEF_TYPE_CURVE:
if (! gimp_scanner_parse_int (scanner,
&param_def.meta.m_curve.none_ok))
{
token = G_TOKEN_INT;
goto error;
}
break;
}
if (! gimp_scanner_parse_token (scanner, G_TOKEN_RIGHT_PAREN))
@ -1119,6 +1128,9 @@ plug_in_proc_arg_deserialize (GScanner *scanner,
case GP_PARAM_DEF_TYPE_FILE:
g_free (param_def.meta.m_file.default_uri);
break;
case GP_PARAM_DEF_TYPE_CURVE:
break;
}
return token;
@ -1318,6 +1330,11 @@ plug_in_rc_write_proc_arg (GimpConfigWriter *writer,
gimp_config_writer_string (writer,
param_def.meta.m_file.default_uri);
break;
case GP_PARAM_DEF_TYPE_CURVE:
gimp_config_writer_printf (writer, "%d",
param_def.meta.m_curve.none_ok);
break;
}
gimp_config_writer_close (writer);

View file

@ -182,6 +182,22 @@ EXPORTS
gimp_convert_dither_type_get_type
gimp_convolve
gimp_convolve_default
gimp_curve_add_point
gimp_curve_clear_points
gimp_curve_delete_point
gimp_curve_get_n_points
gimp_curve_get_n_samples
gimp_curve_get_point
gimp_curve_get_point_type
gimp_curve_get_type
gimp_curve_is_identity
gimp_curve_new
gimp_curve_point_type_get_type
gimp_curve_set_curve_type
gimp_curve_set_n_samples
gimp_curve_set_point
gimp_curve_set_point_type
gimp_curve_type_get_type
gimp_debug_timer_end
gimp_debug_timer_start
gimp_default_display
@ -731,6 +747,7 @@ EXPORTS
gimp_palettes_set_popup
gimp_param_brush_get_type
gimp_param_channel_get_type
gimp_param_curve_get_type
gimp_param_display_get_type
gimp_param_drawable_filter_get_type
gimp_param_drawable_get_type
@ -750,6 +767,7 @@ EXPORTS
gimp_param_selection_get_type
gimp_param_spec_brush
gimp_param_spec_channel
gimp_param_spec_curve
gimp_param_spec_display
gimp_param_spec_display_none_allowed
gimp_param_spec_drawable

View file

@ -40,6 +40,7 @@
#include <libgimp/gimpbatchprocedure.h>
#include <libgimp/gimpbrush.h>
#include <libgimp/gimpchannel.h>
#include <libgimp/gimpcurve.h>
#include <libgimp/gimpdisplay.h>
#include <libgimp/gimpdrawable.h>
#include <libgimp/gimpdrawablefilter.h>

667
libgimp/gimpcurve.c Normal file
View file

@ -0,0 +1,667 @@
/* 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_POINTS,
PROP_POINTS,
PROP_POINT_TYPES,
PROP_N_SAMPLES,
PROP_SAMPLES,
N_PROPS
};
static GParamSpec *obj_props[N_PROPS] = { NULL, };
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);
G_DEFINE_TYPE (GimpCurve, gimp_curve, G_TYPE_OBJECT);
static void gimp_curve_class_init (GimpCurveClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GParamSpec *array_spec;
object_class->finalize = gimp_curve_finalize;
object_class->set_property = gimp_curve_set_property;
object_class->get_property = gimp_curve_get_property;
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);
obj_props[PROP_N_POINTS] =
g_param_spec_int ("n-points",
"Number of Points",
"The number of points",
0, G_MAXINT, 0,
/* for backward compatibility */
GIMP_CONFIG_PARAM_IGNORE | GIMP_CONFIG_PARAM_FLAGS);
array_spec = g_param_spec_double ("point", NULL, NULL,
-1.0, 1.0, 0.0, GIMP_PARAM_READWRITE);
obj_props[PROP_POINTS] =
gimp_param_spec_value_array ("points",
NULL, NULL,
array_spec,
GIMP_CONFIG_PARAM_FLAGS);
array_spec = g_param_spec_enum ("point-type", NULL, NULL,
GIMP_TYPE_CURVE_POINT_TYPE,
GIMP_CURVE_POINT_SMOOTH,
GIMP_PARAM_READWRITE);
obj_props[PROP_POINT_TYPES] =
gimp_param_spec_value_array ("point-types",
NULL, NULL,
array_spec,
GIMP_CONFIG_PARAM_FLAGS);
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);
array_spec = g_param_spec_double ("sample", NULL, NULL,
0.0, 1.0, 0.0, GIMP_PARAM_READWRITE);
obj_props[PROP_SAMPLES] =
gimp_param_spec_value_array ("samples",
NULL, NULL,
array_spec,
GIMP_CONFIG_PARAM_FLAGS);
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 = 0;
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_POINTS:
/* ignored */
break;
case PROP_POINTS:
{
GimpValueArray *array = g_value_get_boxed (value);
GimpCurvePoint *points;
gint length;
gint n_points;
gint i;
if (! array)
{
gimp_curve_clear_points (curve);
break;
}
length = gimp_value_array_length (array) / 2;
n_points = 0;
points = g_new0 (GimpCurvePoint, length);
for (i = 0; i < length; i++)
{
GValue *x = gimp_value_array_index (array, i * 2);
GValue *y = gimp_value_array_index (array, i * 2 + 1);
/* for backward compatibility */
if (g_value_get_double (x) < 0.0)
continue;
points[n_points].x = CLAMP (g_value_get_double (x), 0.0, 1.0);
points[n_points].y = CLAMP (g_value_get_double (y), 0.0, 1.0);
if (n_points > 0)
{
points[n_points].x = MAX (points[n_points].x,
points[n_points - 1].x);
}
if (n_points < curve->n_points)
points[n_points].type = curve->points[n_points].type;
else
points[n_points].type = GIMP_CURVE_POINT_SMOOTH;
n_points++;
}
g_free (curve->points);
curve->n_points = n_points;
curve->points = points;
g_object_notify_by_pspec (object, obj_props[PROP_N_POINTS]);
g_object_notify_by_pspec (object, obj_props[PROP_POINT_TYPES]);
}
break;
case PROP_POINT_TYPES:
{
GimpValueArray *array = g_value_get_boxed (value);
GimpCurvePoint *points;
gint length;
gdouble x = 0.0;
gdouble y = 0.0;
gint i;
if (! array)
{
gimp_curve_clear_points (curve);
break;
}
length = gimp_value_array_length (array);
points = g_new0 (GimpCurvePoint, length);
for (i = 0; i < length; i++)
{
GValue *type = gimp_value_array_index (array, i);
points[i].type = g_value_get_uint (type);
if (i < curve->n_points)
{
x = curve->points[i].x;
y = curve->points[i].y;
}
points[i].x = x;
points[i].y = y;
}
g_free (curve->points);
curve->n_points = length;
curve->points = points;
g_object_notify_by_pspec (object, obj_props[PROP_N_POINTS]);
g_object_notify_by_pspec (object, obj_props[PROP_POINTS]);
}
break;
case PROP_N_SAMPLES:
gimp_curve_set_n_samples (curve, g_value_get_int (value));
break;
case PROP_SAMPLES:
{
GimpValueArray *array = g_value_get_boxed (value);
gint length;
gint i;
if (! array)
break;
length = gimp_value_array_length (array);
for (i = 0; i < curve->n_samples && i < length; i++)
{
GValue *v = gimp_value_array_index (array, i);
curve->samples[i] = CLAMP (g_value_get_double (v), 0.0, 1.0);
}
}
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_POINTS:
g_value_set_int (value, curve->n_points);
break;
case PROP_POINTS:
{
GimpValueArray *array = gimp_value_array_new (curve->n_points * 2);
GValue v = G_VALUE_INIT;
gint i;
g_value_init (&v, G_TYPE_DOUBLE);
for (i = 0; i < curve->n_points; i++)
{
g_value_set_double (&v, curve->points[i].x);
gimp_value_array_append (array, &v);
g_value_set_double (&v, curve->points[i].y);
gimp_value_array_append (array, &v);
}
g_value_unset (&v);
g_value_take_boxed (value, array);
}
break;
case PROP_POINT_TYPES:
{
GimpValueArray *array = gimp_value_array_new (curve->n_points);
GValue v = G_VALUE_INIT;
gint i;
g_value_init (&v, GIMP_TYPE_CURVE_POINT_TYPE);
for (i = 0; i < curve->n_points; i++)
{
g_value_set_enum (&v, curve->points[i].type);
gimp_value_array_append (array, &v);
}
g_value_unset (&v);
g_value_take_boxed (value, array);
}
break;
case PROP_N_SAMPLES:
g_value_set_int (value, curve->n_samples);
break;
case PROP_SAMPLES:
{
GimpValueArray *array = gimp_value_array_new (curve->n_samples);
GValue v = G_VALUE_INIT;
gint i;
g_value_init (&v, G_TYPE_DOUBLE);
for (i = 0; i < curve->n_samples; i++)
{
g_value_set_double (&v, curve->samples[i]);
gimp_value_array_append (array, &v);
}
g_value_unset (&v);
g_value_take_boxed (value, array);
}
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
/* Public Functions */
GimpCurve *
gimp_curve_new (void)
{
return g_object_new (GIMP_TYPE_CURVE, NULL);
}
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));
curve->curve_type = curve_type;
if (curve_type == GIMP_CURVE_SMOOTH)
{
gint i;
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_object_notify_by_pspec (G_OBJECT (curve), obj_props[PROP_N_POINTS]);
g_object_notify_by_pspec (G_OBJECT (curve), obj_props[PROP_POINTS]);
g_object_notify_by_pspec (G_OBJECT (curve), obj_props[PROP_POINT_TYPES]);
}
else
{
gimp_curve_clear_points (curve);
}
g_object_notify_by_pspec (G_OBJECT (curve), obj_props[PROP_CURVE_TYPE]);
g_object_thaw_notify (G_OBJECT (curve));
}
}
gint
gimp_curve_get_n_points (GimpCurve *curve)
{
g_return_val_if_fail (GIMP_IS_CURVE (curve), 0);
return curve->n_points;
}
void
gimp_curve_set_n_samples (GimpCurve *curve,
gint n_samples)
{
g_return_if_fail (GIMP_IS_CURVE (curve));
g_return_if_fail (n_samples >= 256);
g_return_if_fail (n_samples <= 4096);
if (n_samples != curve->n_samples)
{
gint i;
g_object_freeze_notify (G_OBJECT (curve));
curve->n_samples = n_samples;
g_object_notify_by_pspec (G_OBJECT (curve), obj_props[PROP_N_SAMPLES]);
curve->samples = g_renew (gdouble, curve->samples, curve->n_samples);
for (i = 0; i < curve->n_samples; i++)
curve->samples[i] = (gdouble) i / (gdouble) (curve->n_samples - 1);
g_object_notify_by_pspec (G_OBJECT (curve), obj_props[PROP_SAMPLES]);
if (curve->curve_type == GIMP_CURVE_FREE)
curve->identity = TRUE;
g_object_thaw_notify (G_OBJECT (curve));
}
}
gint
gimp_curve_get_n_samples (GimpCurve *curve)
{
g_return_val_if_fail (GIMP_IS_CURVE (curve), 0);
return curve->n_samples;
}
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);
if (curve->curve_type == GIMP_CURVE_FREE)
return -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_object_notify_by_pspec (G_OBJECT (curve), obj_props[PROP_N_POINTS]);
g_object_notify_by_pspec (G_OBJECT (curve), obj_props[PROP_POINTS]);
g_object_notify_by_pspec (G_OBJECT (curve), obj_props[PROP_POINT_TYPES]);
return point;
}
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 (point >= 0 && point < curve->n_points);
if (x) *x = curve->points[point].x;
if (y) *y = curve->points[point].y;
}
void
gimp_curve_set_point_type (GimpCurve *curve,
gint point,
GimpCurvePointType type)
{
g_return_if_fail (GIMP_IS_CURVE (curve));
g_return_if_fail (point >= 0 && point < curve->n_points);
curve->points[point].type = type;
g_object_notify_by_pspec (G_OBJECT (curve), obj_props[PROP_POINT_TYPES]);
}
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 (point >= 0 && point < curve->n_points, GIMP_CURVE_POINT_SMOOTH);
return curve->points[point].type;
}
void
gimp_curve_delete_point (GimpCurve *curve,
gint point)
{
GimpCurvePoint *points;
g_return_if_fail (GIMP_IS_CURVE (curve));
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_object_notify_by_pspec (G_OBJECT (curve), obj_props[PROP_N_POINTS]);
g_object_notify_by_pspec (G_OBJECT (curve), obj_props[PROP_POINTS]);
g_object_notify_by_pspec (G_OBJECT (curve), obj_props[PROP_POINT_TYPES]);
}
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 (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_object_notify_by_pspec (G_OBJECT (curve), obj_props[PROP_POINTS]);
}
void
gimp_curve_clear_points (GimpCurve *curve)
{
g_return_if_fail (GIMP_IS_CURVE (curve));
if (curve->points)
{
g_clear_pointer (&curve->points, g_free);
curve->n_points = 0;
g_object_notify_by_pspec (G_OBJECT (curve), obj_props[PROP_N_POINTS]);
g_object_notify_by_pspec (G_OBJECT (curve), obj_props[PROP_POINTS]);
g_object_notify_by_pspec (G_OBJECT (curve), obj_props[PROP_POINT_TYPES]);
}
}
/**
* 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.
**/
gboolean
gimp_curve_is_identity (GimpCurve *curve)
{
g_return_val_if_fail (GIMP_IS_CURVE (curve), FALSE);
return curve->identity;
}

76
libgimp/gimpcurve.h Normal file
View file

@ -0,0 +1,76 @@
/* LIBGIMP - The GIMP Library
* Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
*
* gimpcurve.h
* 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/>.
*/
#if !defined (__GIMP_H_INSIDE__) && !defined (GIMP_COMPILATION)
#error "Only <libgimp/gimp.h> can be included directly."
#endif
#ifndef __GIMP_CURVE_H__
#define __GIMP_CURVE_H__
G_BEGIN_DECLS
/* For information look into the C source or the html documentation */
#define GIMP_TYPE_CURVE (gimp_curve_get_type ())
G_DECLARE_FINAL_TYPE (GimpCurve, gimp_curve, GIMP, CURVE, GObject)
GimpCurve * gimp_curve_new (void);
void gimp_curve_set_curve_type (GimpCurve *curve,
GimpCurveType curve_type);
gint gimp_curve_get_n_points (GimpCurve *curve);
void gimp_curve_set_n_samples (GimpCurve *curve,
gint n_samples);
gint gimp_curve_get_n_samples (GimpCurve *curve);
gint gimp_curve_add_point (GimpCurve *curve,
gdouble x,
gdouble y);
void gimp_curve_get_point (GimpCurve *curve,
gint point,
gdouble *x,
gdouble *y);
GimpCurvePointType gimp_curve_get_point_type (GimpCurve *curve,
gint point);
void gimp_curve_set_point_type (GimpCurve *curve,
gint point,
GimpCurvePointType type);
void gimp_curve_delete_point (GimpCurve *curve,
gint point);
void gimp_curve_set_point (GimpCurve *curve,
gint point,
gdouble x,
gdouble y);
void gimp_curve_clear_points (GimpCurve *curve);
gboolean gimp_curve_is_identity (GimpCurve *curve);
G_END_DECLS
#endif /* __GIMP_CURVE_H__ */

View file

@ -18,6 +18,8 @@ static const GimpGetTypeFunc get_type_funcs[] =
gimp_convert_dither_type_get_type,
gimp_convert_palette_type_get_type,
gimp_convolve_type_get_type,
gimp_curve_point_type_get_type,
gimp_curve_type_get_type,
gimp_desaturate_mode_get_type,
gimp_dodge_burn_type_get_type,
gimp_export_capabilities_get_type,
@ -87,6 +89,8 @@ static const gchar * const type_names[] =
"GimpConvertDitherType",
"GimpConvertPaletteType",
"GimpConvolveType",
"GimpCurvePointType",
"GimpCurveType",
"GimpDesaturateMode",
"GimpDodgeBurnType",
"GimpExportCapabilities",

View file

@ -64,6 +64,42 @@ typedef enum
} GimpConvertDitherType;
#define GIMP_TYPE_CURVE_POINT_TYPE (gimp_curve_point_type_get_type ())
GType gimp_curve_point_type_get_type (void) G_GNUC_CONST;
/**
* GimpCurvePointType:
* @GIMP_CURVE_POINT_SMOOTH: GIMP_CURVE_POINT_SMOOTH
* @GIMP_CURVE_POINT_CORNER: GIMP_CURVE_POINT_CORNER
*
* Extracted from app/core/core-enums.h
**/
typedef enum
{
GIMP_CURVE_POINT_SMOOTH,
GIMP_CURVE_POINT_CORNER
} GimpCurvePointType;
#define GIMP_TYPE_CURVE_TYPE (gimp_curve_type_get_type ())
GType gimp_curve_type_get_type (void) G_GNUC_CONST;
/**
* GimpCurveType:
* @GIMP_CURVE_SMOOTH: GIMP_CURVE_SMOOTH
* @GIMP_CURVE_FREE: GIMP_CURVE_FREE
*
* Extracted from app/core/core-enums.h
**/
typedef enum
{
GIMP_CURVE_SMOOTH,
GIMP_CURVE_FREE
} GimpCurveType;
#define GIMP_TYPE_HISTOGRAM_CHANNEL (gimp_histogram_channel_get_type ())
GType gimp_histogram_channel_get_type (void) G_GNUC_CONST;

View file

@ -374,6 +374,12 @@ _gimp_gp_param_def_to_param_spec (const GPParamDef *param_def)
return pspec;
}
break;
case GP_PARAM_DEF_TYPE_CURVE:
if (! strcmp (param_def->type_name, "GimpParamCurve"))
return gimp_param_spec_curve (name, nick, blurb,
param_def->meta.m_id.none_ok,
flags);
}
g_warning ("%s: GParamSpec type unsupported '%s'", G_STRFUNC,
@ -700,6 +706,13 @@ _gimp_param_spec_to_gp_param_def (GParamSpec *pspec,
{
param_def->param_def_type = GP_PARAM_DEF_TYPE_EXPORT_OPTIONS;
}
else if (GIMP_IS_PARAM_SPEC_CURVE (pspec) ||
(pspec_type == G_TYPE_PARAM_OBJECT && value_type == GIMP_TYPE_CURVE))
{
param_def->param_def_type = GP_PARAM_DEF_TYPE_CURVE;
param_def->type_name = "GimpParamCurve";
param_def->meta.m_curve.none_ok = TRUE;
}
else if (pspec_type == G_TYPE_PARAM_OBJECT &&
value_type != G_TYPE_FILE &&
value_type != GEGL_TYPE_COLOR)
@ -1179,7 +1192,8 @@ gimp_gp_param_to_value (gpointer gimp,
{
g_value_set_object (value, get_display_by_id (gimp, param->data.d_int));
}
else if (GIMP_VALUE_HOLDS_RESOURCE (value))
else if (GIMP_VALUE_HOLDS_RESOURCE (value) &&
! GIMP_VALUE_HOLDS_CURVE (value))
{
g_value_set_object (value, get_resource_by_id (param->data.d_int));
}
@ -1187,6 +1201,34 @@ gimp_gp_param_to_value (gpointer gimp,
{
g_value_set_object (value, get_unit_by_id (gimp, param->data.d_int));
}
else if (GIMP_VALUE_HOLDS_CURVE (value))
{
GimpCurve *curve;
curve = g_object_new (GIMP_TYPE_CURVE, NULL);
g_object_set (curve,
"curve-type", param->data.d_curve.curve_type,
NULL);
for (gint j = 0; j < param->data.d_curve.n_points; j++)
{
gimp_curve_add_point (curve, param->data.d_curve.points[j * 2],
param->data.d_curve.points[(j * 2) + 1]);
gimp_curve_set_point_type (curve, j,
param->data.d_curve.point_types[j]);
}
if (param->data.d_curve.n_samples > 0)
g_object_set (curve,
"n-samples", param->data.d_curve.n_samples,
NULL);
g_value_set_object (value, curve);
g_object_unref (curve);
}
else if (g_type_is_a (G_VALUE_TYPE (value), GIMP_TYPE_EXPORT_OPTIONS))
{
GimpExportOptions *options;
@ -1721,7 +1763,8 @@ gimp_value_to_gp_param (const GValue *value,
param->data.d_int = display ? gimp_display_get_id (display) : -1;
}
else if (GIMP_VALUE_HOLDS_RESOURCE (value))
else if (GIMP_VALUE_HOLDS_RESOURCE (value) &&
! GIMP_VALUE_HOLDS_CURVE (value))
{
GObject *resource = g_value_get_object (value);
@ -1741,6 +1784,37 @@ gimp_value_to_gp_param (const GValue *value,
{
param->param_type = GP_PARAM_TYPE_EXPORT_OPTIONS;
}
else if (g_type_is_a (G_VALUE_TYPE (value), GIMP_TYPE_CURVE))
{
GimpCurve *curve = g_value_get_object (value);
param->param_type = GP_PARAM_TYPE_CURVE;
g_object_get (curve,
"curve-type", &param->data.d_curve.curve_type,
"n-points", &param->data.d_curve.n_points,
"n-samples", &param->data.d_curve.n_samples,
NULL);
param->data.d_curve.points = g_new0 (gdouble,
2 * param->data.d_curve.n_points);
param->data.d_curve.point_types = g_new0 (GimpCurvePointType,
param->data.d_curve.n_points);
for (gint j = 0; j < param->data.d_curve.n_points; j++)
{
gdouble x;
gdouble y;
gimp_curve_get_point (curve, j, &x, &y);
param->data.d_curve.points[j * 2] = x;
param->data.d_curve.points[(j * 2) + 1] = y;
param->data.d_curve.point_types[j] =
gimp_curve_get_point_type (curve, j);
}
}
else if (G_VALUE_HOLDS_PARAM (value))
{
param->param_type = GP_PARAM_TYPE_PARAM_DEF;
@ -1868,6 +1942,14 @@ _gimp_gp_params_free (GPParam *params,
params[i].data.d_value_array.n_values,
full_copy);
break;
case GP_PARAM_TYPE_CURVE:
if (full_copy)
{
g_free (params[i].data.d_curve.points);
g_free (params[i].data.d_curve.point_types);
}
break;
}
}

View file

@ -2045,3 +2045,93 @@ gimp_param_spec_font (const gchar *name,
none_ok, GIMP_RESOURCE (default_value),
default_to_context, flags);
}
/*
* GIMP_TYPE_PARAM_CURVE
*/
#define GIMP_PARAM_SPEC_CURVE(pspec) (G_TYPE_CHECK_INSTANCE_CAST ((pspec), GIMP_TYPE_PARAM_CURVE, GimpParamSpecCurve))
typedef struct _GimpParamSpecCurve GimpParamSpecCurve;
struct _GimpParamSpecCurve
{
GParamSpecObject parent_instance;
gboolean none_ok;
};
static void gimp_param_curve_class_init (GParamSpecClass *klass);
static void gimp_param_curve_init (GParamSpec *pspec);
GType
gimp_param_curve_get_type (void)
{
static GType type = 0;
if (! type)
{
const GTypeInfo info =
{
sizeof (GParamSpecClass),
NULL, NULL,
(GClassInitFunc) gimp_param_curve_class_init,
NULL, NULL,
sizeof (GimpParamSpecCurve),
0,
(GInstanceInitFunc) gimp_param_curve_init
};
type = g_type_register_static (G_TYPE_PARAM_OBJECT,
"GimpParamCurve", &info, 0);
}
return type;
}
static void
gimp_param_curve_class_init (GParamSpecClass *klass)
{
klass->value_type = GIMP_TYPE_CURVE;
}
static void
gimp_param_curve_init (GParamSpec *pspec)
{
}
/**
* gimp_param_spec_curve:
* @name: Canonical name of the property specified.
* @nick: Nick name of the property specified.
* @blurb: Description of the property specified.
* @none_ok: Whether no is a valid value.
* @flags: Flags for the property specified.
*
* Creates a new #GimpParamSpecCurve specifying a
* [type@Curve] property.
*
* See g_param_spec_internal() for details on property names.
*
* Returns: (transfer floating): The newly created #GimpParamSpecCurve.
*
* Since: 3.2
**/
GParamSpec *
gimp_param_spec_curve (const gchar *name,
const gchar *nick,
const gchar *blurb,
gboolean none_ok,
GParamFlags flags)
{
GimpParamSpecCurve *cspec;
cspec = g_param_spec_internal (GIMP_TYPE_PARAM_CURVE,
name, nick, blurb, flags);
g_return_val_if_fail (cspec, NULL);
cspec->none_ok = none_ok ? TRUE : FALSE;
return G_PARAM_SPEC (cspec);
}

View file

@ -448,6 +448,25 @@ GParamSpec * gimp_param_spec_font (const gchar *name,
GParamFlags flags);
/*
* GIMP_TYPE_PARAM_CURVE
*/
#define GIMP_VALUE_HOLDS_CURVE(value) (G_TYPE_CHECK_VALUE_TYPE ((value), \
GIMP_TYPE_CURVE))
#define GIMP_TYPE_PARAM_CURVE (gimp_param_curve_get_type ())
#define GIMP_IS_PARAM_SPEC_CURVE(pspec) (G_TYPE_CHECK_INSTANCE_TYPE ((pspec), GIMP_TYPE_PARAM_CURVE))
GType gimp_param_curve_get_type (void) G_GNUC_CONST;
GParamSpec * gimp_param_spec_curve (const gchar *name,
const gchar *nick,
const gchar *blurb,
gboolean none_ok,
GParamFlags flags);
G_END_DECLS
#endif /* __LIBGIMP_GIMP_PARAM_SPECS_H__ */

View file

@ -469,6 +469,20 @@ G_BEGIN_DECLS
g_value_set_object (gimp_value_array_index (args, n), value)
/* Curve */
#define GIMP_VALUES_GET_CURVE(args, n) \
g_value_get_object (gimp_value_array_index (args, n))
#define GIMP_VALUES_DUP_CURVE(args, n) \
g_value_dup_object (gimp_value_array_index (args, n))
#define GIMP_VALUES_SET_CURVE(args, n, value) \
g_value_set_object (gimp_value_array_index (args, n), value)
#define GIMP_VALUES_TAKE_CURVE(args, n, value) \
g_value_take_object (gimp_value_array_index (args, n), value)
/* Unit */
#define GIMP_VALUES_GET_UNIT(args, n) \

View file

@ -59,6 +59,7 @@ typedef struct _GimpDisplay GimpDisplay;
typedef struct _GimpResource GimpResource;
typedef struct _GimpBrush GimpBrush;
typedef struct _GimpCurve GimpCurve;
typedef struct _GimpFont GimpFont;
typedef struct _GimpGradient GimpGradient;
typedef struct _GimpPattern GimpPattern;

View file

@ -186,6 +186,7 @@ libgimp_sources_introspectable = [
'gimpbatchprocedure.c',
'gimpbrush.c',
'gimpchannel.c',
'gimpcurve.c',
'gimpdisplay.c',
'gimpdrawable.c',
'gimpdrawablefilter.c',
@ -252,6 +253,7 @@ libgimp_headers_introspectable = [
'gimpbatchprocedure.h',
'gimpbrush.h',
'gimpchannel.h',
'gimpcurve.h',
'gimpdisplay.h',
'gimpdrawable.h',
'gimpdrawablefilter.h',

View file

@ -1317,6 +1317,13 @@ _gp_param_def_read (GIOChannel *channel,
user_data))
return FALSE;
break;
case GP_PARAM_DEF_TYPE_CURVE:
if (! _gimp_wire_read_int32 (channel,
(guint32 *) &param_def->meta.m_curve.none_ok, 1,
user_data))
return FALSE;
break;
}
return TRUE;
@ -1377,6 +1384,9 @@ _gp_param_def_destroy (GPParamDef *param_def)
case GP_PARAM_DEF_TYPE_FILE:
g_free (param_def->meta.m_file.default_uri);
break;
case GP_PARAM_DEF_TYPE_CURVE:
break;
}
}
@ -1684,6 +1694,13 @@ _gp_param_def_write (GIOChannel *channel,
user_data))
return FALSE;
break;
case GP_PARAM_DEF_TYPE_CURVE:
if (! _gimp_wire_write_int32 (channel,
(guint32 *) &param_def->meta.m_curve.none_ok, 1,
user_data))
return FALSE;
break;
}
return TRUE;
@ -2190,6 +2207,51 @@ _gp_params_read (GIOChannel *channel,
(*params)[i].data.d_value_array.n_values = (guint32) n_values;
break;
}
case GP_PARAM_TYPE_CURVE:
{
if (! _gimp_wire_read_int32 (channel,
&(*params)[i].data.d_curve.curve_type, 1,
user_data))
goto cleanup;
if (! _gimp_wire_read_int32 (channel,
&(*params)[i].data.d_curve.n_points, 1,
user_data))
goto cleanup;
if (! _gimp_wire_read_int32 (channel,
&(*params)[i].data.d_curve.n_samples, 1,
user_data))
goto cleanup;
(*params)[i].data.d_curve.points = g_new0 (gdouble,
2 * (*params)[i].data.d_curve.n_points);
if (! _gimp_wire_read_double (channel,
(*params)[i].data.d_curve.points,
2 * (*params)[i].data.d_curve.n_points,
user_data))
{
g_free ((*params)[i].data.d_curve.points);
(*params)[i].data.d_curve.points = NULL;
goto cleanup;
}
(*params)[i].data.d_curve.point_types = g_new0 (guint32,
(*params)[i].data.d_curve.n_points);
if (! _gimp_wire_read_int32 (channel,
(*params)[i].data.d_curve.point_types,
(*params)[i].data.d_curve.n_points,
user_data))
{
g_free ((*params)[i].data.d_curve.point_types);
(*params)[i].data.d_curve.point_types = NULL;
goto cleanup;
}
}
break;
}
}
@ -2421,6 +2483,34 @@ _gp_params_write (GIOChannel *channel,
user_data);
break;
case GP_PARAM_TYPE_CURVE:
if (! _gimp_wire_write_int32 (channel,
(const guint32 *) &params[i].data.d_curve.curve_type, 1,
user_data))
return;
if (! _gimp_wire_write_int32 (channel,
(const guint32 *) &params[i].data.d_curve.n_points, 1,
user_data))
return;
if (! _gimp_wire_write_int32 (channel,
(const guint32 *) &params[i].data.d_curve.n_samples, 1,
user_data))
return;
if (! _gimp_wire_write_double (channel,
params[i].data.d_curve.points,
2 * params[i].data.d_curve.n_points,
user_data))
return;
if (! _gimp_wire_write_int32 (channel,
(const guint32 *) params[i].data.d_curve.point_types,
params[i].data.d_curve.n_points,
user_data))
return;
break;
}
}
}
@ -2499,6 +2589,13 @@ _gp_params_destroy (GPParam *params,
_gp_params_destroy (params[i].data.d_value_array.values,
params[i].data.d_value_array.n_values);
break;
case GP_PARAM_TYPE_CURVE:
if (params[i].data.d_curve.points)
g_free (params[i].data.d_curve.points);
if (params[i].data.d_curve.point_types)
g_free (params[i].data.d_curve.point_types);
break;
}
}

View file

@ -26,7 +26,7 @@ G_BEGIN_DECLS
/* Increment every time the protocol changes
*/
#define GIMP_PROTOCOL_VERSION 0x0115
#define GIMP_PROTOCOL_VERSION 0x0116
enum
@ -61,7 +61,8 @@ typedef enum
GP_PARAM_DEF_TYPE_ID_ARRAY,
GP_PARAM_DEF_TYPE_EXPORT_OPTIONS,
GP_PARAM_DEF_TYPE_RESOURCE,
GP_PARAM_DEF_TYPE_FILE
GP_PARAM_DEF_TYPE_FILE,
GP_PARAM_DEF_TYPE_CURVE
} GPParamDefType;
typedef enum
@ -81,6 +82,7 @@ typedef enum
GP_PARAM_TYPE_EXPORT_OPTIONS,
GP_PARAM_TYPE_PARAM_DEF,
GP_PARAM_TYPE_VALUE_ARRAY,
GP_PARAM_TYPE_CURVE
} GPParamType;
@ -102,6 +104,7 @@ typedef struct _GPParamDefID GPParamDefID;
typedef struct _GPParamDefIDArray GPParamDefIDArray;
typedef struct _GPParamDefResource GPParamDefResource;
typedef struct _GPParamDefFile GPParamDefFile;
typedef struct _GPParamDefCurve GPParamDefCurve;
typedef struct _GPParam GPParam;
typedef struct _GPParamArray GPParamArray;
typedef struct _GPParamIDArray GPParamIDArray;
@ -110,6 +113,7 @@ typedef struct _GPParamColor GPParamColor;
typedef struct _GPParamColorArray GPParamColorArray;
typedef struct _GPParamExportOptions GPParamExportOptions;
typedef struct _GPParamValueArray GPParamValueArray;
typedef struct _GPParamCurve GPParamCurve;
typedef struct _GPProcRun GPProcRun;
typedef struct _GPProcReturn GPProcReturn;
typedef struct _GPProcInstall GPProcInstall;
@ -250,6 +254,11 @@ struct _GPParamDefFile
gchar *default_uri;
};
struct _GPParamDefCurve
{
gint32 none_ok;
};
struct _GPParamDef
{
GPParamDefType param_def_type;
@ -274,6 +283,7 @@ struct _GPParamDef
GPParamDefChoice m_choice;
GPParamDefResource m_resource;
GPParamDefFile m_file;
GPParamDefCurve m_curve;
} meta;
};
@ -326,6 +336,17 @@ struct _GPParamValueArray
GPParam *values;
};
struct _GPParamCurve
{
guint32 curve_type;
guint32 n_points;
gdouble *points;
guint32 *point_types;
guint32 n_samples;
};
struct _GPParam
{
GPParamType param_type;
@ -347,6 +368,7 @@ struct _GPParam
GPParamExportOptions d_export_options;
GPParamDef d_param_def;
GPParamValueArray d_value_array;
GPParamCurve d_curve;
} data;
};

View file

@ -322,7 +322,8 @@ gimp_config_param_spec_duplicate (GParamSpec *pspec)
g_strcmp0 (type_name, "GimpLayerMask") == 0 ||
g_strcmp0 (type_name, "GimpSelection") == 0 ||
g_strcmp0 (type_name, "GimpPath") == 0 ||
g_strcmp0 (type_name, "GimpDrawableFilter") == 0)
g_strcmp0 (type_name, "GimpDrawableFilter") == 0 ||
g_strcmp0 (type_name, "GimpCurve") == 0)
{
copy = g_param_spec_object (name, nick, blurb,
value_type,

View file

@ -341,6 +341,17 @@ gimp_param_spec_pattern ("$name",
$default,
$default_to_context,
$flags)
CODE
}
elsif ($pdbtype eq 'curve') {
$none_ok = exists $arg->{none_ok} ? 'TRUE' : 'FALSE';
$default = exists $arg->{default} ? $arg->{default} : NULL;
$pspec = <<CODE;
gimp_param_spec_curve ("$name",
"$nick",
"$blurb",
$none_ok,
$flags)
CODE
}
elsif ($pdbtype eq 'item') {

View file

@ -869,6 +869,20 @@ package Gimp::CodeGen::enums;
GIMP_CONVERT_DITHER_FS_LOWBLEED => '2',
GIMP_CONVERT_DITHER_FIXED => '3' }
},
GimpCurvePointType =>
{ contig => 1,
header => 'core/core-enums.h',
symbols => [ qw(GIMP_CURVE_POINT_SMOOTH GIMP_CURVE_POINT_CORNER) ],
mapping => { GIMP_CURVE_POINT_SMOOTH => '0',
GIMP_CURVE_POINT_CORNER => '1' }
},
GimpCurveType =>
{ contig => 1,
header => 'core/core-enums.h',
symbols => [ qw(GIMP_CURVE_SMOOTH GIMP_CURVE_FREE) ],
mapping => { GIMP_CURVE_SMOOTH => '0',
GIMP_CURVE_FREE => '1' }
},
GimpHistogramChannel =>
{ contig => 1,
header => 'core/core-enums.h',

View file

@ -674,6 +674,18 @@ package Gimp::CodeGen::pdb;
take_value_func => 'g_value_set_object ($value, $var)',
headers => [ qw("text/gimpfont.h") ] },
curve => { name => 'CURVE',
gtype => 'GIMP_TYPE_CURVE',
type => 'GimpCurve *',
const_type => 'GimpCurve *',
init_value => 'NULL',
out_annotate => '(transfer full)',
get_value_func => '$var = g_value_get_object ($value)',
dup_value_func => '$var = GIMP_VALUES_DUP_CURVE ($value)',
set_value_func => 'g_value_set_object ($value, $var)',
take_value_func => 'g_value_take_object ($value, $var)',
headers => [ qw("core/gimpcurve.h") ] },
valuearray => { name => 'VALUEARRAY',
gtype => 'GIMP_TYPE_VALUE_ARRAY',
type => 'GimpValueArray *',