Commit 9fe9a44b authored by Øyvind Kolås's avatar Øyvind Kolås

added GeglColor

parent f0632ba3
......@@ -12,6 +12,7 @@ Code:
Richard Kralovic
Kevin Cozens
Victor Bogado
Martin Nordholts
Documentation:
Garry R. Osgood
......
2006-09-10 Øyvind Kolås <pippin@gimp.org>
Integrated contribution from Martin Nordholts that provides a
property type of type color. That accepts a superset of CSS
color strings.
* gegl/gegl-color.[ch]: NEW files.
* gegl/gegl-chant.h: added the ability to chant color properties.
* gegl/Makefile.am:
* gegl/gegl-xml.c: (start_element): handle colors in XML parsing.
* gegl/gegl.h: include GeglColor.
* operations/render/checkerboard.c: (process): make use of GeglColor.
* docs/todo.html: removed GeglColor item.
* AUTHORS: Added Martin Nordholts.
2006-09-09 Øyvind Kolås <pippin@gimp.org>
Disabled some of the 0 padding code of gegl_buffer_get_fmt since it
......
......@@ -22,28 +22,6 @@
<div class='content'>
<a name='To do'><h2>To do</h2></a>
<p>A temporally deficient roadmap for GEGL</p>
<a name='GeglColor'><h2>GeglColor</h2></a>
<p>A data type, that is also chantable for the operations With convenience
methods to get a single chunky pixel in any given babl format, as well as being
settable as such. </p>
<p>More convencience methods for set/get rgba lab luminance or similar things
can be added on top of this</p>
<p>Internally it should probably just store a RGBA32 float for now</p>
<p>It should also be capable of generating/parsing strings of the forms:
</p>
<pre
>#fff
#ffffff
white
rgb(1.0, 1.0, 1.0)
rgba(1.0, 1.0, 1.0, 1.0)
#ffff
#ffffffff
</pre>
<p>All interpreted as fully opaque white.
</p>
<a name='Buffer'><h2>Buffer</h2></a>
......
......@@ -19,6 +19,7 @@ EXTRA_DIST = \
gegl-prepare-visitor.h
GEGL_sources = \
gegl-color.c \
gegl-connection.c \
gegl-cr-visitor.c \
gegl-debug-rect-visitor.c \
......@@ -50,6 +51,7 @@ gegl_SOURCES = \
gegl-options.h
GEGL_public_headers = \
gegl-color.h \
gegl-connection.h \
gegl-extension-handler.h \
gegl-graph.h \
......
......@@ -68,13 +68,14 @@ typedef struct GeneratedClass ChantClass;
struct Generated
{
GEGL_CHANT_PARENT_TypeName parent_instance;
#define gegl_chant_int(name, min, max, def, blurb) gint name;
#define gegl_chant_double(name, min, max, def, blurb) gdouble name;
#define gegl_chant_float(name, min, max, def, blurb) gfloat name;
#define gegl_chant_boolean(name, def, blurb) gboolean name;
#define gegl_chant_string(name, def, blurb) gchar *name;
#define gegl_chant_object(name, blurb) GObject *name;
#define gegl_chant_pointer(name, blurb) gpointer name;
#define gegl_chant_int(name, min, max, def, blurb) gint name;
#define gegl_chant_double(name, min, max, def, blurb) gdouble name;
#define gegl_chant_float(name, min, max, def, blurb) gfloat name;
#define gegl_chant_boolean(name, def, blurb) gboolean name;
#define gegl_chant_string(name, def, blurb) gchar *name;
#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;
#include GEGL_CHANT_SELF
......@@ -88,6 +89,7 @@ struct Generated
#undef gegl_chant_string
#undef gegl_chant_object
#undef gegl_chant_pointer
#undef gegl_chant_color
/****************************************************************************/
......@@ -219,6 +221,7 @@ enum
#define gegl_chant_string(name, def, blurb) PROP_##name,
#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,
#include GEGL_CHANT_SELF
......@@ -229,6 +232,7 @@ enum
#undef gegl_chant_string
#undef gegl_chant_object
#undef gegl_chant_pointer
#undef gegl_chant_color
PROP_LAST
};
......@@ -256,6 +260,8 @@ get_property (GObject *gobject,
case PROP_##name: g_value_set_object (value, self->name);break;
#define gegl_chant_pointer(name, blurb)\
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;
#include GEGL_CHANT_SELF
......@@ -266,6 +272,7 @@ get_property (GObject *gobject,
#undef gegl_chant_string
#undef gegl_chant_object
#undef gegl_chant_pointer
#undef gegl_chant_color
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, property_id, pspec);
break;
......@@ -315,6 +322,12 @@ set_property (GObject *gobject,
case PROP_##name:\
self->name = g_value_get_pointer (value);\
break;
#define gegl_chant_color(name, def, 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
......@@ -325,6 +338,7 @@ set_property (GObject *gobject,
#undef gegl_chant_string
#undef gegl_chant_object
#undef gegl_chant_pointer
#undef gegl_chant_color
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, property_id, pspec);
......@@ -476,6 +490,13 @@ gegl_chant_class_init (ChantClass * klass)
G_PARAM_READWRITE |\
G_PARAM_CONSTRUCT |\
GEGL_PAD_INPUT));
#define gegl_chant_color(name, def, blurb) \
g_object_class_install_property (object_class, PROP_##name,\
gegl_param_spec_color (#name, #name, blurb,\
def,\
G_PARAM_READWRITE |\
G_PARAM_CONSTRUCT |\
GEGL_PAD_INPUT));
#include GEGL_CHANT_SELF
#undef gegl_chant_int
......@@ -485,6 +506,7 @@ gegl_chant_class_init (ChantClass * klass)
#undef gegl_chant_string
#undef gegl_chant_object
#undef gegl_chant_pointer
#undef gegl_chant_color
}
......
/* 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 Martin Nordholts <enselic@hotmail.com>
*/
#include <glib.h>
#include <glib/gprintf.h>
#include <glib-object.h>
#include <string.h>
#include "gegl-color.h"
typedef struct _GeglColorPrivate GeglColorPrivate;
typedef struct _ColorNameEntity ColorNameEntity;
struct _GeglColorPrivate {
gfloat rgba_color[4];
};
struct _ColorNameEntity {
const gchar *color_name;
const gfloat rgba_color[4];
};
static void gegl_color_to_string (const GValue *src_value,
GValue *dest_value);
static void string_to_gegl_color (const GValue *src_value,
GValue *dest_value);
static gboolean parse_float_argument_list (GeglColor *color,
GScanner *scanner,
gint num_arguments);
static gboolean parse_color_name (GeglColor *color,
const gchar *color_string);
static gboolean parse_hex (GeglColor *color,
const gchar *color_string);
/* These color names are based on those defined in the HTML 4.01 standard. See
* http://www.w3.org/TR/html4/types.html#h-6.5
*/
static const ColorNameEntity color_names[] = {
{ "black", { 0.f, 0.f, 0.f, 1.f } },
{ "silver", { 0.75294f, 0.75294f, 0.75294f, 1.f } },
{ "gray", { 0.50196f, 0.50196f, 0.50196f, 1.f } },
{ "white", { 1.f, 1.f, 1.f, 1.f } },
{ "maroon", { 0.50196f, 0.f, 0.f, 1.f } },
{ "red", { 1.f, 0.f, 0.f, 1.f } },
{ "purple", { 0.50196f, 0.f, 0.50196f, 1.f } },
{ "fuchsia", { 1.f, 0.f, 1.f, 1.f } },
{ "green", { 0.f, 0.50196f, 0.f, 1.f } },
{ "lime", { 0.f, 1.f, 0.f, 1.f } },
{ "olive", { 0.50196f, 0.50196f, 0.f, 1.f } },
{ "yellow", { 1.f, 1.f, 01.f, 1.f } },
{ "navy", { 0.f, 0.f, 0.50196f, 1.f } },
{ "blue", { 0.f, 0.f, 1.f, 1.f } },
{ "teal", { 0.f, 0.50196f, 0.50196f, 1.f } },
{ "aqua", { 0.f, 1.f, 1.f, 1.f } }
};
/* Copied into GeglColor:s instances when parsing a color from a string fails. */
static const gfloat parsing_error_color[4] = { 0.f, 1.f, 1.f, 0.67f };
/* Copied into all GeglColor:s at their instantiation. */
static const gfloat init_color[4] = { 1.f, 1.f, 1.f, 1.f };
G_DEFINE_TYPE_WITH_CODE (GeglColor, gegl_color, G_TYPE_OBJECT,
g_value_register_transform_func (g_define_type_id, \
G_TYPE_STRING, \
gegl_color_to_string); \
g_value_register_transform_func (G_TYPE_STRING, \
g_define_type_id, \
string_to_gegl_color);)
#define GEGL_COLOR_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GEGL_TYPE_COLOR, GeglColorPrivate))
static void
gegl_color_init (GeglColor *self)
{
GeglColorPrivate *priv = GEGL_COLOR_GET_PRIVATE (self);
memcpy (priv->rgba_color, init_color, sizeof (init_color));
}
static void
gegl_color_class_init (GeglColorClass *klass)
{
g_type_class_add_private (klass, sizeof (GeglColorPrivate));
}
static void
string_to_gegl_color (const GValue *src_value,
GValue *dest_value)
{
const gchar *color_string;
GeglColor *color;
color_string = g_value_get_string (src_value);
color = g_object_new (GEGL_TYPE_COLOR, NULL);
gegl_color_set_from_string (color, color_string);
g_value_take_object (dest_value, color);
}
static void
gegl_color_to_string (const GValue *src_value,
GValue *dest_value)
{
GeglColor *color;
GeglColorPrivate *priv;
gchar buffer[512];
color = GEGL_COLOR (g_value_get_object (src_value));
priv = GEGL_COLOR_GET_PRIVATE (color);
g_sprintf (buffer, "rgba(%f, %f, %f, %f)",
priv->rgba_color[0],
priv->rgba_color[1],
priv->rgba_color[2],
priv->rgba_color[3]);
g_value_set_string (dest_value, buffer);
}
static gboolean
parse_float_argument_list (GeglColor *color,
GScanner *scanner,
gint num_arguments)
{
GTokenType token_type;
GTokenValue token_value;
GeglColorPrivate *priv;
priv = GEGL_COLOR_GET_PRIVATE (color);
/* Make sure there is a leading '(' */
if (g_scanner_get_next_token (scanner) != G_TOKEN_LEFT_PAREN)
{
return FALSE;
}
/* Iterate through the arguments and copy each value
* to the rgba_color array of GeglColor.
*/
gint i;
for (i = 0; i < num_arguments; ++i)
{
if (g_scanner_get_next_token (scanner) != G_TOKEN_FLOAT)
{
return FALSE;
}
token_value = g_scanner_cur_value (scanner);
priv->rgba_color[i] = token_value.v_float;
/* Verify that there is a ',' after each float, except the last one */
if (i < (num_arguments - 1))
{
token_type = g_scanner_get_next_token (scanner);
if (token_type != G_TOKEN_COMMA)
{
return FALSE;
}
}
}
/* Make sure there is a traling ')' and that that is the last token. */
if (g_scanner_get_next_token (scanner) == G_TOKEN_RIGHT_PAREN &&
g_scanner_get_next_token (scanner) == G_TOKEN_EOF)
{
return TRUE;
}
return FALSE;
}
static gboolean
parse_color_name (GeglColor *color,
const gchar *color_string)
{
GeglColorPrivate *priv = GEGL_COLOR_GET_PRIVATE (color);
gint num_color_names = sizeof (color_names) / sizeof (color_names[0]);
gint i;
for (i = 0; i < num_color_names; ++i)
{
if (g_ascii_strcasecmp (color_names[i].color_name, color_string) == 0)
{
memcpy (priv->rgba_color, color_names[i].rgba_color, sizeof(color_names[i].rgba_color));
return TRUE;
}
}
return FALSE;
}
static gboolean
parse_hex (GeglColor *color,
const gchar *color_string)
{
gint i;
gsize string_length = strlen (color_string);
GeglColorPrivate *priv = GEGL_COLOR_GET_PRIVATE (color);
if (string_length == 7 || /* #rrggbb */
string_length == 9) /* #rrggbbaa */
{
gint num_iterations = (string_length-1) / 2;
for (i = 0; i < num_iterations; ++i)
{
if (g_ascii_isxdigit (color_string[2*i + 1]) &&
g_ascii_isxdigit (color_string[2*i + 2]))
{
priv->rgba_color[i] = (g_ascii_xdigit_value (color_string[2*i + 1]) << 4 |
g_ascii_xdigit_value (color_string[2*i + 2])) / 255.f;
}
else
{
return FALSE;
}
}
/* Successful #rrggbb(aa) parsing! */
return TRUE;
}
else if (string_length == 4 || /* #rgb */
string_length == 5) /* #rgba */
{
gint num_iterations = string_length - 1;
for (i = 0; i < num_iterations; ++i)
{
if (g_ascii_isxdigit (color_string[i + 1]))
{
priv->rgba_color[i] = (g_ascii_xdigit_value (color_string[i + 1]) << 4 |
g_ascii_xdigit_value (color_string[i + 1])) / 255.f;
}
else
{
return FALSE;
}
}
/* Successful #rgb(a) parsing! */
return TRUE;
}
/* String was of unsupported length. */
return FALSE;
}
void
gegl_color_get_rgba (GeglColor *self,
gfloat *r,
gfloat *g,
gfloat *b,
gfloat *a)
{
GeglColorPrivate *priv = GEGL_COLOR_GET_PRIVATE (self);
*r = priv->rgba_color[0];
*g = priv->rgba_color[1];
*b = priv->rgba_color[2];
*a = priv->rgba_color[3];
}
void
gegl_color_set_rgba (GeglColor *self,
gfloat r,
gfloat g,
gfloat b,
gfloat a)
{
GeglColorPrivate *priv = GEGL_COLOR_GET_PRIVATE (self);
priv->rgba_color[0] = r;
priv->rgba_color[1] = g;
priv->rgba_color[2] = b;
priv->rgba_color[3] = a;
}
void
gegl_color_set_from_string (GeglColor *self,
const gchar *color_string)
{
GScanner *scanner;
GTokenType token_type;
GTokenValue token_value;
gboolean color_parsing_successfull;
GeglColorPrivate *priv;
scanner = g_scanner_new (NULL);
scanner->config->cpair_comment_single = "";
g_scanner_input_text (scanner, color_string, strlen (color_string));
priv = GEGL_COLOR_GET_PRIVATE (self);
token_type = g_scanner_get_next_token (scanner);
token_value = g_scanner_cur_value (scanner);
if (token_type == G_TOKEN_IDENTIFIER &&
g_ascii_strcasecmp (token_value.v_identifier, "rgb") == 0)
{
color_parsing_successfull = parse_float_argument_list (self, scanner, 3);
priv->rgba_color[3] = 1.f;
}
else if (token_type == G_TOKEN_IDENTIFIER &&
g_ascii_strcasecmp (token_value.v_identifier, "rgba") == 0)
{
color_parsing_successfull = parse_float_argument_list (self, scanner, 4);
}
else if (token_type == '#') /* FIXME: Verify that this is a safe way to check for '#' */
{
color_parsing_successfull = parse_hex (self, color_string);
}
else if (token_type == G_TOKEN_IDENTIFIER)
{
color_parsing_successfull = parse_color_name (self, color_string);
}
else
{
color_parsing_successfull = FALSE;
}
if (!color_parsing_successfull)
{
memcpy (priv->rgba_color,
parsing_error_color,
sizeof(parsing_error_color));
g_warning ("Parsing of color string \"%s\" into GeglColor failed! "
"Using transparent cyan instead",
color_string);
}
g_scanner_destroy (scanner);
}
/* --------------------------------------------------------------------------
* A GParamSpec class to describe behavior of GeglColor as an object property
* follows.
* --------------------------------------------------------------------------
*/
#define GEGL_TYPE_PARAM_SPEC_COLOR (gegl_param_spec_color_get_type ())
#define GEGL_PARAM_SPEC_COLOR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GEGL_TYPE_PARAM_SPEC_COLOR, GeglParamSpecColor))
#define GEGL_IS_PARAM_SPEC_COLOR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GEGL_TYPE_PARAM_SPEC_COLOR))
#define GEGL_IS_PARAM_SPEC_COLOR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GEGL_TYPE_PARAM_SPEC_COLOR))
typedef struct _GeglParamSpecColor GeglParamSpecColor;
struct _GeglParamSpecColor
{
GParamSpec parent_instance;
const gchar *default_color_string;
};
static void
gegl_param_spec_color_init (GParamSpec *self)
{
GEGL_PARAM_SPEC_COLOR (self)->default_color_string = NULL;
}
static void
finalize (GParamSpec *self)
{
GeglParamSpecColor *param_spec_color = GEGL_PARAM_SPEC_COLOR (self);
GParamSpecClass *parent_class = g_type_class_peek (g_type_parent (GEGL_TYPE_PARAM_SPEC_COLOR));
if (param_spec_color->default_color_string)
{
g_free ((gpointer) param_spec_color->default_color_string);
param_spec_color->default_color_string = NULL;
}
parent_class->finalize (self);
}
static void
value_set_default (GParamSpec *param_spec,
GValue *value)
{
GValue color_string = {0, };
g_value_init (&color_string, G_TYPE_STRING);
g_value_set_string (&color_string, GEGL_PARAM_SPEC_COLOR (param_spec)->default_color_string);
g_value_transform (&color_string, value);
}
GType
gegl_param_spec_color_get_type (void)
{
static GType param_spec_color_type = 0;
if (G_UNLIKELY (param_spec_color_type == 0))
{
static GParamSpecTypeInfo param_spec_color_type_info = {
sizeof (GeglParamSpecColor),
0,
gegl_param_spec_color_init,
0,
finalize,
value_set_default,
NULL,
NULL
};
param_spec_color_type_info.value_type = GEGL_TYPE_COLOR;
param_spec_color_type = g_param_type_register_static ("GeglParamSpecColor",
&param_spec_color_type_info);
}
return param_spec_color_type;
}
GParamSpec *
gegl_param_spec_color (const gchar *name,
const gchar *nick,
const gchar *blurb,
const gchar *default_color_string,
GParamFlags flags)
{
GeglParamSpecColor *param_spec_color;
param_spec_color = g_param_spec_internal (GEGL_TYPE_PARAM_SPEC_COLOR,
name, nick, blurb, flags);
param_spec_color->default_color_string = g_strdup (default_color_string);
return G_PARAM_SPEC (param_spec_color);
}
/* 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 Martin Nordholts <enselic@hotmail.com>
*/
#ifndef __GEGL_COLOR_H__
#define __GEGL_COLOR_H__
#include <glib-object.h>
G_BEGIN_DECLS
#define GEGL_TYPE_COLOR (gegl_color_get_type ())
#define GEGL_COLOR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GEGL_TYPE_COLOR, GeglColor))
#define GEGL_COLOR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GEGL_TYPE_COLOR, GeglColorClass))
#define GEGL_IS_COLOR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GEGL_TYPE_COLOR))
#define GEGL_IS_COLOR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GEGL_TYPE_COLOR))
#define GEGL_COLOR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GEGL_TYPE_COLOR, GeglColorClass))
typedef struct _GeglColor GeglColor;
typedef struct _GeglColorClass GeglColorClass;
struct _GeglColor
{
GObject parent;
};
struct _GeglColorClass
{
GObjectClass parent;
};
void gegl_color_get_rgba (GeglColor *self,
gfloat *r,
gfloat *g,
gfloat *b,
gfloat *a);
void gegl_color_set_rgba (GeglColor *self,
gfloat r,
gfloat g,
gfloat b,
gfloat a);
void gegl_color_set_from_string (GeglColor *self,
const gchar *color_string);
GType gegl_color_get_type (void) G_GNUC_CONST;
GType gegl_param_spec_color_get_type (void) G_GNUC_CONST;
GParamSpec *gegl_param_spec_color (const gchar *name,
const gchar *nick,
const gchar *blurb,
const gchar *default_color_string,
GParamFlags flags);
G_END_DECLS
#endif /* __GEGL_COLOR_H__ */
......@@ -27,6 +27,7 @@
#include "gegl-graph.h"
#include "gegl-node.h"
#include "gegl-pad.h"
#include "gegl-color.h"
typedef struct _ParseData ParseData;
......@@ -195,6 +196,15 @@ static void start_element (GMarkupParseContext *context,
gegl_node_set (new, *a, FALSE, NULL);
}
}
else if (paramspec->value_type == GEGL_TYPE_COLOR)
{
GeglColor *color = g_object_new (GEGL_TYPE_COLOR, NULL);
gegl_color_set_from_string (color, *v);
gegl_node_set (new, *a, color, NULL);
g_object_unref (color);
}
else
{
g_warning ("operation desired unknown parapspec type for %s", *a);
......
......@@ -25,6 +25,7 @@
#include <gegl/gegl-types.h>
#include <gegl/gegl-color.h>
#include <gegl/gegl-connection.h>
#include <gegl/gegl-graph.h>
#include <gegl/gegl-init.h>
......
......@@ -19,19 +19,21 @@
*/
#if GEGL_CHANT_PROPERTIES
gegl_chant_int (x, -G_MAXINT, G_MAXINT, 16, "")
gegl_chant_int (y, -G_MAXINT, G_MAXINT, 16, "")
gegl_chant_int (x_offset, -G_MAXINT, G_MAXINT, 0, "")
gegl_chant_int (y_offset, -G_MAXINT, G_MAXINT, 0, "")
gegl_chant_int (x, -G_MAXINT, G_MAXINT, 16, "")
gegl_chant_int (y, -G_MAXINT, G_MAXINT, 16, "")
gegl_chant_int (x_offset, -G_MAXINT, G_MAXINT, 0, "")
gegl_chant_int (y_offset, -G_MAXINT, G_MAXINT, 0, "")