Index: operations/color/contrast-curve.c =================================================================== --- operations/color/contrast-curve.c (revision 0) +++ operations/color/contrast-curve.c (revision 0) @@ -0,0 +1,103 @@ +/* This file is an image processing operation for GEGL + * + * GEGL 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 2 of the License, or (at your option) any later version. + * + * GEGL 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 GEGL; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + * Copyright 2007 Mark Probst + */ +#if GEGL_CHANT_PROPERTIES + + gegl_chant_int (sampling_points, 0, 65536, 0, "Number of curve sampling points. 0 for exact calculation.") + gegl_chant_curve (curve, "The contrast curve.") + +#else + +#define GEGL_CHANT_POINT_FILTER +#define GEGL_CHANT_NAME contrast_curve +#define GEGL_CHANT_DESCRIPTION "Adjusts the contrast of the image according to a curve." +#define GEGL_CHANT_SELF "contrast-curve.c" +#define GEGL_CHANT_CATEGORIES "color" +#define GEGL_CHANT_INIT +#include "gegl-chant.h" + +static void init (GeglChantOperation *self) +{ + /* set the babl format this operation prefers to work on */ + GEGL_OPERATION_POINT_FILTER (self)->format = babl_format ("YA float"); +} + +static gboolean +process (GeglOperation *op, + void *in_buf, + void *out_buf, + glong samples) +{ + GeglChantOperation *self; + gint i; + gfloat *in = in_buf; + gfloat *out = out_buf; + gint num_sampling_points; + gfloat *xs, *ys; + + self = GEGL_CHANT_OPERATION (op); + + num_sampling_points = self->sampling_points; + + if (num_sampling_points > 0) + { + xs = (gfloat*)g_malloc(sizeof(gfloat) * num_sampling_points); + ys = (gfloat*)g_malloc(sizeof(gfloat) * num_sampling_points); + + gegl_curve_calc_values(self->curve, 0.0, 1.0, num_sampling_points, xs, ys); + + g_free(xs); + + for (i=0; i= num_sampling_points) + y = ys[num_sampling_points - 1]; + else + y = ys[x]; + + out[0] = y; + out[1]=in[1]; + + in += 2; + out+= 2; + } + + g_free(ys); + } + else + for (i=0; icurve, u); + out[1]=in[1]; + + in += 2; + out+= 2; + } + + return TRUE; +} + +#endif Index: bindings/gegl-sharp/gapi/metadata.gegl =================================================================== --- bindings/gegl-sharp/gapi/metadata.gegl (revision 1474) +++ bindings/gegl-sharp/gapi/metadata.gegl (working copy) @@ -24,5 +24,6 @@ GObject GObject + GObject GObject Index: gegl/gegl-curve.c =================================================================== --- gegl/gegl-curve.c (revision 0) +++ gegl/gegl-curve.c (revision 0) @@ -0,0 +1,494 @@ +/* This file is part of GEGL + * + * GEGL 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 2 of the License, or (at your option) any later version. + * + * GEGL 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 GEGL; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + * Copyright 2006 Mark Probst + * Spline Code Copyright 1997 David Mosberger + */ + +#include +#include +#include +#include +#include + +#include "gegl-types.h" + +#include "gegl-curve.h" + +enum +{ + PROP_0, +}; + +typedef struct _GeglCurvePoint GeglCurvePoint; +typedef struct _GeglCurvePrivate GeglCurvePrivate; +typedef struct _CurveNameEntity CurveNameEntity; + +struct _GeglCurvePoint +{ + gfloat x; + gfloat y; + gfloat y2; +}; + +struct _GeglCurvePrivate +{ + gfloat y_min; + gfloat y_max; + GArray *points; + gboolean need_recalc; + GeglCurvePoint **indir; +}; + +static void finalize (GObject *self); +static void set_property (GObject *gobject, + guint prop_id, + const GValue *value, + GParamSpec *pspec); +static void get_property (GObject *gobject, + guint prop_id, + GValue *value, + GParamSpec *pspec); + +G_DEFINE_TYPE (GeglCurve, gegl_curve, G_TYPE_OBJECT); + +#define GEGL_CURVE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GEGL_TYPE_CURVE, GeglCurvePrivate)) + +static void +gegl_curve_init (GeglCurve *self) +{ + GeglCurvePrivate *priv = GEGL_CURVE_GET_PRIVATE (self); + + priv->y_min = 0.0; + priv->y_max = 1.0; + priv->need_recalc = FALSE; + priv->indir = NULL; + priv->points = g_array_new(FALSE, FALSE, sizeof(GeglCurvePoint)); +} + +static void +gegl_curve_class_init (GeglCurveClass *klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + + gobject_class->finalize = finalize; + gobject_class->set_property = set_property; + gobject_class->get_property = get_property; + + g_type_class_add_private (klass, sizeof (GeglCurvePrivate)); +} + +static void +finalize (GObject *gobject) +{ + GeglCurve *self = GEGL_CURVE (gobject); + GeglCurvePrivate *priv = GEGL_CURVE_GET_PRIVATE (self); + + g_array_free(priv->points, TRUE); + priv->points = NULL; + + if (priv->indir != NULL) + { + g_free(priv->indir); + priv->indir = NULL; + } + + G_OBJECT_CLASS (gegl_curve_parent_class)->finalize (gobject); +} + +static void +set_property (GObject *gobject, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + switch (property_id) + { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, property_id, pspec); + break; + } +} + +static void +get_property (GObject *gobject, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + switch (property_id) + { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, property_id, pspec); + break; + } +} + +GeglCurve * +gegl_curve_new (gfloat y_min, + gfloat y_max) +{ + GeglCurve *self = GEGL_CURVE (g_object_new (GEGL_TYPE_CURVE, NULL)); + GeglCurvePrivate *priv = GEGL_CURVE_GET_PRIVATE (self); + + gegl_curve_init(self); + priv->y_min = y_min; + priv->y_max = y_max; + + return self; +} + +GeglCurve* +gegl_curve_default_curve (void) +{ + static GeglCurve *curve = NULL; + + if (curve == NULL) + { + curve = gegl_curve_new(0.0, 1.0); + gegl_curve_add_point(curve, 0.0, 0.0); + gegl_curve_add_point(curve, 1.0, 1.0); + } + + return curve; +} + +void +gegl_curve_get_y_bounds (GeglCurve *self, + gfloat *min_y, + gfloat *max_y) +{ + GeglCurvePrivate *priv = GEGL_CURVE_GET_PRIVATE (self); + + *min_y = priv->y_min; + *max_y = priv->y_max; +} + +guint +gegl_curve_add_point (GeglCurve *self, + gfloat x, + gfloat y) +{ + GeglCurvePrivate *priv = GEGL_CURVE_GET_PRIVATE (GEGL_CURVE (self)); + GeglCurvePoint point = { x, y }; + + g_array_append_val(priv->points, point); + + priv->need_recalc = TRUE; + + return priv->points->len - 1; +} + +void +gegl_curve_get_point (GeglCurve *self, + guint index, + gfloat *x, + gfloat *y) +{ + GeglCurvePrivate *priv = GEGL_CURVE_GET_PRIVATE (GEGL_CURVE (self)); + GeglCurvePoint point; + + g_assert(index < priv->points->len); + point = g_array_index(priv->points, GeglCurvePoint, index); + + *x = point.x; + *y = point.y; +} + +void +gegl_curve_set_point (GeglCurve *self, + guint index, + gfloat x, + gfloat y) +{ + GeglCurvePrivate *priv = GEGL_CURVE_GET_PRIVATE (GEGL_CURVE (self)); + GeglCurvePoint point = { x, y }; + + g_assert(index < priv->points->len); + g_array_index(priv->points, GeglCurvePoint, index) = point; + + priv->need_recalc = TRUE; +} + +guint +gegl_curve_num_points (GeglCurve *self) +{ + GeglCurvePrivate *priv = GEGL_CURVE_GET_PRIVATE (GEGL_CURVE (self)); + + return priv->points->len; +} + +static int +compare_point_indirs (const void *_p1, const void *_p2) +{ + GeglCurvePoint *p1 = *(GeglCurvePoint**)_p1; + GeglCurvePoint *p2 = *(GeglCurvePoint**)_p2; + + if (p1->x < p2->x) + return -1; + if (p1->x > p2->x) + return 1; + return 0; +} + +#define X(i) (priv->indir[(i)]->x) +#define Y(i) (priv->indir[(i)]->y) +#define Y2(i) (priv->indir[(i)]->y2) +#define YCLAMP(y) ((y)y_min ? priv->y_min : ((y)>priv->y_max ? priv->y_max : (y))) + +static void +recalculate (GeglCurvePrivate *priv) +{ + guint len = priv->points->len; + guint i; + gint k; + gfloat *b; + + if (!priv->need_recalc) + return; + + priv->need_recalc = FALSE; + + if (len < 2) + return; + + if (priv->indir != NULL) + g_free(priv->indir); + priv->indir = (GeglCurvePoint**)g_malloc(sizeof(GeglCurvePoint*) * len); + + for (i = 0; i < len; ++i) + priv->indir[i] = &g_array_index(priv->points, GeglCurvePoint, i); + + qsort(priv->indir, len, sizeof(GeglCurvePoint*), compare_point_indirs); + + b = (gfloat*)g_malloc(sizeof(gfloat) * (len - 1)); + + // lower natural boundary conditions + Y2(0) = b[0] = 0.0; + + for (i = 1; i < len - 1; ++i) + { + gfloat sig = (X(i) - X(i-1)) / (X(i+1) - X(i-1)); + gfloat p = sig * Y2(i-1) + 2; + + Y2(i) = (sig - 1) / p; + b[i] = ((Y(i+1) - Y(i)) + / (X(i+1) - X(i)) - (Y(i) - Y(i-1)) / (X(i) - X(i-1))); + b[i] = (6 * b[i] / (X(i+1) - X(i-1)) - sig * b[i-1]) / p; + } + + // upper natural boundary condition + Y2(len-1) = 0.0; + for (k = len - 2; k >= 0; --k) + Y2(k) = Y2(k) * Y2(k+1) + b[k]; + + /* + for (i = 0; i < len; ++i) + { + printf("y2: %f ", Y2(i)) + */ + + g_free(b); +} + +static guint +find_interval (GeglCurvePrivate *priv, gfloat u) +{ + guint len = priv->points->len; + guint i = 0, j = len - 1; + + while (j - i > 1) + { + guint k = (i + j) / 2; + if (X(k) > u) + j = k; + else + i = k; + } + + return i; +} + +static gfloat +apply (GeglCurvePrivate *priv, gfloat u, guint i) +{ + gfloat h = X(i+1) - X(i); + gfloat a = (X(i+1) - u) / h; + gfloat b = (u - X(i)) / h; + gfloat y = a*Y(i) + b*Y(i+1) + ((a*a*a-a)*Y2(i) + (b*b*b-b)*Y2(i+1)) * (h*h)/6; + + return YCLAMP(y); +} + +gfloat +gegl_curve_calc_value (GeglCurve *self, + gfloat x) +{ + GeglCurvePrivate *priv = GEGL_CURVE_GET_PRIVATE (GEGL_CURVE (self)); + + recalculate(priv); + + if (priv->points->len >= 2) + return apply(priv, x, find_interval(priv, x)); + else if (priv->points->len == 1) + return YCLAMP(g_array_index(priv->points, GeglCurvePoint, 0).y); + else + { + g_assert(priv->points->len == 0); + return priv->y_min; + } +} + +void +gegl_curve_calc_values (GeglCurve *self, + gfloat x_min, + gfloat x_max, + guint num_samples, + gfloat *xs, + gfloat *ys) +{ + GeglCurvePrivate *priv = GEGL_CURVE_GET_PRIVATE (GEGL_CURVE (self)); + guint len = priv->points->len; + guint i, j; + + recalculate(priv); + + j = 0; + for (i = 0; i < num_samples; ++i) + { + gfloat u = x_min + (x_max - x_min) * (double)i / (double)(num_samples - 1); + + xs[i] = u; + + if (len >= 2) + { + while (j < len - 2 && X(j+1) < u) + ++j; + + ys[i] = apply(priv, u, j); + } + else if (len == 1) + ys[i] = YCLAMP(g_array_index(priv->points, GeglCurvePoint, 0).y); + else + { + g_assert(len == 0); + ys[i] = priv->y_min; + } + } +} + +#undef X +#undef Y +#undef Y2 +#undef YCLAMP + +/* -------------------------------------------------------------------------- + * A GParamSpec class to describe behavior of GeglCurve as an object property + * follows. + * -------------------------------------------------------------------------- + */ + +#define GEGL_TYPE_PARAM_CURVE (gegl_param_curve_get_type ()) +#define GEGL_PARAM_CURVE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GEGL_TYPE_PARAM_CURVE, GeglParamCurve)) +#define GEGL_IS_PARAM_CURVE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GEGL_TYPE_PARAM_CURVE)) +#define GEGL_IS_PARAM_CURVE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GEGL_TYPE_PARAM_CURVE)) + +typedef struct _GeglParamCurve GeglParamCurve; + +struct _GeglParamCurve +{ + GParamSpec parent_instance; + + GeglCurve *default_curve; +}; + +static void +gegl_param_curve_init (GParamSpec *self) +{ + GEGL_PARAM_CURVE (self)->default_curve = NULL; +} + +static void +gegl_param_curve_finalize (GParamSpec *self) +{ + GeglParamCurve *param_curve = GEGL_PARAM_CURVE (self); + GParamSpecClass *parent_class = g_type_class_peek (g_type_parent (GEGL_TYPE_PARAM_CURVE)); + + if (param_curve->default_curve) + { + g_object_unref (param_curve->default_curve); + param_curve->default_curve = NULL; + } + + parent_class->finalize (self); +} + +static void +value_set_default (GParamSpec *param_spec, + GValue *value) +{ + GeglParamCurve *gegl_curve = GEGL_PARAM_CURVE (param_spec); + + g_object_ref (gegl_curve->default_curve); /* XXX: + not sure why this is needed, + but a reference is leaked + unless it his here */ + g_value_set_object (value, gegl_curve->default_curve); +} + +GType +gegl_param_curve_get_type (void) +{ + static GType param_curve_type = 0; + + if (G_UNLIKELY (param_curve_type == 0)) + { + static GParamSpecTypeInfo param_curve_type_info = { + sizeof (GeglParamCurve), + 0, + gegl_param_curve_init, + 0, + gegl_param_curve_finalize, + value_set_default, + NULL, + NULL + }; + param_curve_type_info.value_type = GEGL_TYPE_CURVE; + + param_curve_type = g_param_type_register_static ("GeglParamCurve", + ¶m_curve_type_info); + } + + return param_curve_type; +} + +GParamSpec * +gegl_param_spec_curve (const gchar *name, + const gchar *nick, + const gchar *blurb, + GeglCurve *default_curve, + GParamFlags flags) +{ + GeglParamCurve *param_curve; + + param_curve = g_param_spec_internal (GEGL_TYPE_PARAM_CURVE, + name, nick, blurb, flags); + + param_curve->default_curve = default_curve; + + return G_PARAM_SPEC (param_curve); +} Index: gegl/gegl-curve.h =================================================================== --- gegl/gegl-curve.h (revision 0) +++ gegl/gegl-curve.h (revision 0) @@ -0,0 +1,97 @@ +/* This file is part of GEGL + * + * GEGL 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 2 of the License, or (at your option) any later version. + * + * GEGL 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 GEGL; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + * Copyright 2007 Mark Probst + */ + +#ifndef __GEGL_CURVE_H__ +#define __GEGL_CURVE_H__ + +#include + +G_BEGIN_DECLS + +#ifndef GEGL_TYPE_CURVE +#define GEGL_TYPE_CURVE (gegl_curve_get_type ()) +#endif +#define GEGL_CURVE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GEGL_TYPE_CURVE, GeglCurve)) +#define GEGL_CURVE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GEGL_TYPE_CURVE, GeglCurveClass)) +#define GEGL_IS_CURVE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GEGL_TYPE_CURVE)) +#define GEGL_IS_CURVE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GEGL_TYPE_CURVE)) +#define GEGL_CURVE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GEGL_TYPE_CURVE, GeglCurveClass)) + +typedef struct _GeglCurve GeglCurve; +typedef struct _GeglCurveClass GeglCurveClass; + +struct _GeglCurve +{ + GObject parent; +}; + +struct _GeglCurveClass +{ + GObjectClass parent; +}; + +GeglCurve* gegl_curve_new (gfloat y_min, + gfloat y_max); + +GeglCurve* gegl_curve_default_curve (void) G_GNUC_CONST; + +GType gegl_curve_get_type (void) G_GNUC_CONST; + +void gegl_curve_get_y_bounds (GeglCurve *self, + gfloat *min_y, + gfloat *max_y); + +guint gegl_curve_add_point (GeglCurve *self, + gfloat x, + gfloat y); + +void gegl_curve_get_point (GeglCurve *self, + guint index, + gfloat *x, + gfloat *y); + +void gegl_curve_set_point (GeglCurve *self, + guint index, + gfloat x, + gfloat y); + +guint gegl_curve_num_points (GeglCurve *self); + +gfloat gegl_curve_calc_value (GeglCurve *self, + gfloat x); + +void gegl_curve_calc_values (GeglCurve *self, + gfloat x_min, + gfloat x_max, + guint num_samples, + gfloat *xs, + gfloat *ys); + +GParamSpec * gegl_param_spec_curve (const gchar *name, + const gchar *nick, + const gchar *blurb, + GeglCurve *default_curve, + GParamFlags flags); + +GType gegl_param_curve_get_type (void) G_GNUC_CONST; + +G_END_DECLS + +#endif /* __GEGL_CURVE_H__ */ Index: gegl/gegl-chant.h =================================================================== --- gegl/gegl-chant.h (revision 1474) +++ gegl/gegl-chant.h (working copy) @@ -78,6 +78,7 @@ #define gegl_chant_object(name, blurb) GObject *name; #define gegl_chant_pointer(name, blurb) gpointer name; #define gegl_chant_color(name, def, blurb) GeglColor *name; +#define gegl_chant_curve(name, blurb) GeglCurve *name; #include GEGL_CHANT_SELF @@ -94,6 +95,7 @@ #undef gegl_chant_object #undef gegl_chant_pointer #undef gegl_chant_color +#undef gegl_chant_curve /****************************************************************************/ @@ -231,6 +233,7 @@ #define gegl_chant_object(name, blurb) PROP_##name, #define gegl_chant_pointer(name, blurb) PROP_##name, #define gegl_chant_color(name, def, blurb) PROP_##name, +#define gegl_chant_curve(name, blurb) PROP_##name, #include GEGL_CHANT_SELF @@ -243,6 +246,7 @@ #undef gegl_chant_object #undef gegl_chant_pointer #undef gegl_chant_color +#undef gegl_chant_curve PROP_LAST }; @@ -274,6 +278,8 @@ case PROP_##name: g_value_set_pointer (value, self->name);break; #define gegl_chant_color(name, def, blurb)\ case PROP_##name: g_value_set_object (value, self->name);break; +#define gegl_chant_curve(name, blurb)\ + case PROP_##name: g_value_set_object (value, self->name);break; #include GEGL_CHANT_SELF @@ -286,6 +292,7 @@ #undef gegl_chant_object #undef gegl_chant_pointer #undef gegl_chant_color +#undef gegl_chant_curve default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, property_id, pspec); break; @@ -349,6 +356,12 @@ g_object_unref (self->name);\ self->name = g_value_get_object (value);\ break; +#define gegl_chant_curve(name, blurb)\ + case PROP_##name:\ + if (self->name != NULL && G_IS_OBJECT (self->name))\ + g_object_unref (self->name);\ + self->name = g_value_get_object (value);\ + break; #include GEGL_CHANT_SELF @@ -361,6 +374,7 @@ #undef gegl_chant_object #undef gegl_chant_pointer #undef gegl_chant_color +#undef gegl_chant_curve default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, property_id, pspec); @@ -437,6 +451,12 @@ g_object_unref (self->name);\ self->name = NULL;\ } +#define gegl_chant_curve(name, blurb)\ + if (self->name)\ + {\ + g_object_unref (self->name);\ + self->name = NULL;\ + } #include GEGL_CHANT_SELF @@ -449,6 +469,7 @@ #undef gegl_chant_object #undef gegl_chant_pointer #undef gegl_chant_color +#undef gegl_chant_curve self = NULL; /* shut up gcc warnings if there were no properties to clean up*/ } @@ -591,6 +612,14 @@ G_PARAM_READWRITE |\ G_PARAM_CONSTRUCT |\ GEGL_PAD_INPUT))); +#define gegl_chant_curve(name, blurb) \ + g_object_class_install_property (object_class, PROP_##name,\ + gegl_param_spec_curve (#name, #name, blurb,\ + gegl_curve_default_curve(),\ + (GParamFlags) (\ + G_PARAM_READWRITE |\ + G_PARAM_CONSTRUCT |\ + GEGL_PAD_INPUT))); #include GEGL_CHANT_SELF #undef gegl_chant_int @@ -602,6 +631,7 @@ #undef gegl_chant_object #undef gegl_chant_pointer #undef gegl_chant_color +#undef gegl_chant_curve } Index: gegl/gegl-plugin.h =================================================================== --- gegl/gegl-plugin.h (revision 1474) +++ gegl/gegl-plugin.h (working copy) @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include Index: gegl/gegl-xml.c =================================================================== --- gegl/gegl-xml.c (revision 1474) +++ gegl/gegl-xml.c (working copy) @@ -30,6 +30,7 @@ #include "gegl-operation.h" #include "gegl-pad.h" #include "gegl-color.h" +#include "gegl-curve.h" #include "gegl-instrument.h" #include "gegl-xml.h" #include "gegl-paramspecs.h" @@ -57,6 +58,7 @@ depending on context */ GList *parent;/*< a stack of parents, as we are recursing into aux branches */ + GeglCurve *curve;/*< the curve whose points we are parsing */ GHashTable *ids; GList *refs; @@ -178,6 +180,16 @@ g_object_unref (color); } + else if (paramspec->value_type == GEGL_TYPE_CURVE) + { + if (pd->curve) + { + gegl_node_set (new, param_name, pd->curve, NULL); + + g_object_unref (pd->curve); + pd->curve = NULL; + } + } else { g_warning ("operation desired unknown parapspec type for %s", @@ -233,6 +245,29 @@ g_assert (name2val (a, v, "name")); pd->param = g_strdup (name2val (a, v, "name")); } + else if (!strcmp (element_name, "curve")) + { + if (pd->curve != NULL) + g_warning ("we haven't cleared previous curve"); + g_assert (name2val (a, v, "ymin")); + g_assert (name2val (a, v, "ymax")); + pd->curve = gegl_curve_new (atof (name2val (a, v, "ymin")), + atof (name2val (a, v, "ymax"))); + } + else if (!strcmp (element_name, "curve-point")) + { + if (!pd->curve) + g_warning ("curve not instantiated"); + else + { + g_assert (name2val (a, v, "x")); + g_assert (name2val (a, v, "y")); + + gegl_curve_add_point (pd->curve, + atof (name2val (a, v, "x")), + atof (name2val (a, v, "y"))); + } + } else if (!strcmp (element_name, "link") || !strcmp (element_name, "links") || !strcmp (element_name, "stack") || @@ -298,7 +333,7 @@ ParseData *pd; pd = user_data; - if (pd->param && pd->iter) + if (pd->param && pd->iter && !pd->curve) { param_set (pd, pd->iter, pd->param, text); } @@ -346,6 +381,11 @@ g_free (pd->param); pd->param = NULL; } + else if (!strcmp (element_name, "curve")) + { + g_assert (pd->param && pd->iter); + param_set (pd, pd->iter, pd->param, NULL); + } else if (!strcmp (element_name, "link") || !strcmp (element_name, "links") || !strcmp (element_name, "launcher") || @@ -353,7 +393,8 @@ !strcmp (element_name, "source") || !strcmp (element_name, "destination") || !strcmp (element_name, "stack") || - !strcmp (element_name, "params")) + !strcmp (element_name, "params") || + !strcmp (element_name, "curve-point")) { /* ignore */ } @@ -784,6 +825,45 @@ } } +static void xml_param_start (SerializeState *ss, + gint indent, + const gchar *key) +{ + g_assert (key); + ind; g_string_append (ss->buf, ""); +} + +static void xml_param_text (SerializeState *ss, + const gchar *value) +{ + gchar *text; + /*gchar *p;*/ + + g_assert (value); + + /* Why isn't this used here??? */ + text = g_markup_escape_text (value, -1); + + g_string_append (ss->buf, value); + /*for (p=text;*p;p++) + { + if (*p=='\n') + g_string_append (ss->buf, " "); + else + g_string_append_c (ss->buf, *p); + + }*/ + + g_free (text); +} + +static void xml_param_end (SerializeState *ss) +{ + g_string_append (ss->buf, "\n"); +} + static void xml_param (SerializeState *ss, gint indent, const gchar *key, @@ -792,26 +872,48 @@ g_assert (key); if (value) - { - gchar *text = g_markup_escape_text (value, -1); - /*gchar *p;*/ + { + xml_param_start (ss, indent, key); + xml_param_text (ss, value); + xml_param_end (ss); + } +} - ind; g_string_append (ss->buf, ""); - g_string_append (ss->buf, value); - /*for (p=text;*p;p++) - { - if (*p=='\n') - g_string_append (ss->buf, " "); - else - g_string_append_c (ss->buf, *p); +static void xml_curve_point (SerializeState *ss, + gint indent, + gfloat x, + gfloat y) +{ + gchar str[64]; + ind; g_string_append (ss->buf, "\n"); +} - }*/ - g_string_append (ss->buf, "\n"); +static void xml_curve (SerializeState *ss, + gint indent, + GeglCurve *curve) +{ + gchar *str; + gfloat min_y, max_y; + guint num_points = gegl_curve_num_points (curve); + guint i; - g_free (text); + gegl_curve_get_y_bounds (curve, &min_y, &max_y); + + ind; str = g_strdup_printf ("\n", min_y, max_y); + g_string_append (ss->buf, str); g_free (str); + for (i = 0; i < num_points; ++i) + { + gfloat x, y; + gegl_curve_get_point (curve, i, &x, &y); + xml_curve_point (ss, indent + 2, x, y); } + ind; g_string_append (ss->buf, "\n"); } static void serialize_properties (SerializeState *ss, @@ -913,9 +1015,21 @@ xml_param (ss, indent + 2, properties[i]->name, value); g_free (value); } + else if (properties[i]->value_type == GEGL_TYPE_CURVE) + { + GeglCurve *curve; + guint num_points; + gegl_node_get (node, properties[i]->name, &curve, NULL); + num_points = gegl_curve_num_points (curve); + xml_param_start (ss, indent + 2, properties[i]->name); + g_string_append (ss->buf, "\n"); + xml_curve (ss, indent + 4, curve); + indent += 2; ind; indent -= 2; xml_param_end (ss); + g_object_unref (curve); + } else { - g_warning ("%s: serialization of %s proeprties not implemented", + g_warning ("%s: serialization of %s properties not implemented", properties[i]->name, g_type_name (properties[i]->value_type)); } } Index: gegl/gegl.h =================================================================== --- gegl/gegl.h (revision 1474) +++ gegl/gegl.h (working copy) @@ -751,7 +751,54 @@ gfloat b, gfloat a); + /*** + * GeglCurve: + */ +#ifndef GEGL_INTERNAL +typedef struct _GeglCurve GeglCurve; +GType gegl_curve_get_type (void) G_GNUC_CONST; +#define GEGL_TYPE_CURVE (gegl_curve_get_type ()) +#define GEGL_CURVE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GEGL_TYPE_CURVE, GeglCurve)) +#endif + + +GeglCurve* gegl_curve_new (gfloat y_min, + gfloat y_max); + +GeglCurve* gegl_curve_default_curve (void) G_GNUC_CONST; + +void gegl_curve_get_y_bounds (GeglCurve *self, + gfloat *min_y, + gfloat *max_y); + +guint gegl_curve_add_point (GeglCurve *self, + gfloat x, + gfloat y); + +void gegl_curve_get_point (GeglCurve *self, + guint index, + gfloat *x, + gfloat *y); + +void gegl_curve_set_point (GeglCurve *self, + guint index, + gfloat x, + gfloat y); + +guint gegl_curve_num_points (GeglCurve *self); + +gfloat gegl_curve_calc_value (GeglCurve *self, + gfloat x); + +void gegl_curve_calc_values (GeglCurve *self, + gfloat x_min, + gfloat x_max, + guint num_samples, + gfloat *xs, + gfloat *ys); + +/*** * Bindings conveniences: * * The following functions are mostly included to make it easier Index: gegl/Makefile.am =================================================================== --- gegl/Makefile.am (revision 1474) +++ gegl/Makefile.am (working copy) @@ -13,6 +13,7 @@ gegl-color.c \ gegl-connection.c \ gegl-cr-visitor.c \ + gegl-curve.c \ gegl-debug-rect-visitor.c \ gegl-eval-mgr.c \ gegl-eval-visitor.c \ @@ -46,6 +47,7 @@ \ gegl-color.h \ gegl-connection.h \ + gegl-curve.h \ gegl-extension-handler.h \ gegl-graph.h \ gegl-init.h \