mirror of https://github.com/GNOME/gimp.git
ScriptFu: fix #10978 handling of color
Revise handling of GeglColor, formerly GimpRGB. Marshall to/from Scheme lists of numeric. Marshall from string CSS names and notations. Conversion to/from GRAY, GRAYA, RGB, RGBA. See color.scm test script.
This commit is contained in:
parent
e92212d02a
commit
6f84a76e7a
|
@ -260,9 +260,65 @@ get_item_from_ID_in_script (scheme *sc,
|
|||
return NULL; /* no error */
|
||||
}
|
||||
|
||||
/* Caller owns the returned GeglColor.
|
||||
/* Walk a Scheme list of numerics, clamping into a C array of bytes.
|
||||
* Expects one to four numerics.
|
||||
* Returns length of list, in range [0,4]
|
||||
* Length zero denotes an error: not a numeric, or list is empty.
|
||||
* A list longer than expected (>4) is not an error, but extra list is not used.
|
||||
*/
|
||||
static void
|
||||
marshal_list_of_numeric_to_rgba (scheme *sc,
|
||||
pointer color_list,
|
||||
guchar (*rgba)[4], /* OUT */
|
||||
guint *length) /* OUT */
|
||||
{
|
||||
*length = 0;
|
||||
for (guint i=0; i<4; i++)
|
||||
{
|
||||
if (sc->vptr->is_number (sc->vptr->pair_car (color_list)))
|
||||
{
|
||||
(*rgba)[i] = CLAMP (sc->vptr->ivalue (sc->vptr->pair_car (color_list)),
|
||||
0, 255);
|
||||
*length = *length + 1;
|
||||
color_list = sc->vptr->pair_cdr (color_list);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Reached end of list or non-numeric. */
|
||||
return;
|
||||
}
|
||||
}
|
||||
/* *length is in [0,4] and *rgba is filled in with same count. */
|
||||
}
|
||||
|
||||
/* Walk a C array of bytes (rgba) creating Scheme list of numeric.
|
||||
* Returns list whose length is in range [0,4].
|
||||
* The list is memory managed by scheme.
|
||||
*/
|
||||
static pointer
|
||||
marshal_rgba_to_list_of_numeric (scheme *sc,
|
||||
guchar rgba[4],
|
||||
guint length)
|
||||
{
|
||||
pointer result_list = sc->NIL;
|
||||
|
||||
/* Walk rgba in reverse. */
|
||||
for (gint i=length-1; i>=0; i--)
|
||||
{
|
||||
/* Prepend to list, returning new list. */
|
||||
result_list = sc->vptr->cons (sc,
|
||||
sc->vptr->mk_integer (sc, rgba[i]),
|
||||
result_list);
|
||||
}
|
||||
|
||||
/* list is numerics from rgba and length (list) == length. */
|
||||
return result_list;
|
||||
}
|
||||
|
||||
/* Returns a GeglColor from a scheme list.
|
||||
* Caller owns the returned GeglColor.
|
||||
* Returns NULL on failure:
|
||||
* - list wrong length
|
||||
* - list wrong length, not >1
|
||||
* - list elements not numbers.
|
||||
*/
|
||||
GeglColor *
|
||||
|
@ -270,73 +326,109 @@ marshal_component_list_to_color (scheme *sc,
|
|||
pointer color_list)
|
||||
{
|
||||
GeglColor *color_result;
|
||||
guchar r = 0, g = 0, b = 0;
|
||||
guchar rgba[4];
|
||||
guint list_length;
|
||||
|
||||
/* FIXME dispatch on list length and create different format colors */
|
||||
|
||||
if (sc->vptr->list_length (sc, color_list) != 3)
|
||||
return NULL;
|
||||
|
||||
if (sc->vptr->is_number (sc->vptr->pair_car (color_list)))
|
||||
r = CLAMP (sc->vptr->ivalue (sc->vptr->pair_car (color_list)),
|
||||
0, 255);
|
||||
marshal_list_of_numeric_to_rgba (sc, color_list, &rgba, &list_length);
|
||||
/* list_length is the count of numerics used. */
|
||||
|
||||
/* Dispatch on list length and create different format colors */
|
||||
if (list_length == 3 || list_length == 4)
|
||||
{
|
||||
/* RGBA */
|
||||
if (list_length == 3)
|
||||
{
|
||||
/* gegl has no three byte rgb. * ScriptFu sets alpha to 1.0 */
|
||||
rgba[3] = 255;
|
||||
}
|
||||
/* Assert rgba is full */
|
||||
color_result = gegl_color_new ("black");
|
||||
gegl_color_set_rgba_with_space (color_result,
|
||||
(gdouble) rgba[0] / 255.0,
|
||||
(gdouble) rgba[1] / 255.0,
|
||||
(gdouble) rgba[2] / 255.0,
|
||||
(gdouble) rgba[3] / 255.0,
|
||||
NULL); /* NULL defaults to sRGB */
|
||||
}
|
||||
else if (list_length == 1)
|
||||
{
|
||||
/* GRAY */
|
||||
GBytes *bytes = g_bytes_new (rgba, 1);
|
||||
|
||||
color_result = gegl_color_new ("black");
|
||||
gegl_color_set_bytes (color_result, babl_format ("Y' u8"), bytes);
|
||||
g_free (bytes);
|
||||
}
|
||||
else if (list_length == 2)
|
||||
{
|
||||
/* GRAYA */
|
||||
GBytes *bytes = g_bytes_new (rgba, 2);
|
||||
|
||||
color_result = gegl_color_new ("black");
|
||||
gegl_color_set_bytes (color_result, babl_format ("Y'A u8"), bytes);
|
||||
g_free (bytes);
|
||||
}
|
||||
else
|
||||
return NULL;
|
||||
{
|
||||
color_result = NULL;
|
||||
}
|
||||
|
||||
color_list = sc->vptr->pair_cdr (color_list);
|
||||
if (sc->vptr->is_number (sc->vptr->pair_car (color_list)))
|
||||
g = CLAMP (sc->vptr->ivalue (sc->vptr->pair_car (color_list)),
|
||||
0, 255);
|
||||
else
|
||||
return NULL;
|
||||
|
||||
color_list = sc->vptr->pair_cdr (color_list);
|
||||
if (sc->vptr->is_number (sc->vptr->pair_car (color_list)))
|
||||
b = CLAMP (sc->vptr->ivalue (sc->vptr->pair_car (color_list)),
|
||||
0, 255);
|
||||
else
|
||||
return NULL;
|
||||
|
||||
color_result = gegl_color_new ("black");
|
||||
gegl_color_set_rgba_with_space (color_result,
|
||||
(gdouble) r / 255.0,
|
||||
(gdouble) g / 255.0,
|
||||
(gdouble) b / 255.0,
|
||||
1.0, NULL);
|
||||
return color_result;
|
||||
}
|
||||
|
||||
/* Returns (0 0 0) if color is NULL. */
|
||||
/* FIXME this should return a list
|
||||
/* Returns a Scheme list of integers or empty list,
|
||||
* the same length as the count of components in the color.
|
||||
* E.G. gimp-drawable-get-pixel may return indexed, rgb, or rgba.
|
||||
* List is length:
|
||||
* 1 GRAY
|
||||
* 2 GRAYA
|
||||
* 3 RGB
|
||||
* 4 RGBA
|
||||
* Returns NIL when color is NULL.
|
||||
*/
|
||||
pointer
|
||||
marshal_color_to_component_list (scheme *sc,
|
||||
GeglColor *color)
|
||||
{
|
||||
guchar rgb[3] = { 0 };
|
||||
pointer result;
|
||||
guint count_components;
|
||||
guchar rgba[4] = { 0 };
|
||||
|
||||
/* Warn when color has different count of components than
|
||||
* the 3 of the pixel we are converting to.
|
||||
*/
|
||||
if (babl_format_get_n_components (gegl_color_get_format (color)) != 3)
|
||||
if (color == NULL)
|
||||
{
|
||||
g_warning ("%s converting to pixel with loss/gain of components", G_STRFUNC);
|
||||
result = sc->NIL;
|
||||
}
|
||||
else
|
||||
{
|
||||
count_components = babl_format_get_n_components (gegl_color_get_format (color));
|
||||
switch (count_components)
|
||||
{
|
||||
case 3:
|
||||
gegl_color_get_pixel (color, babl_format ("R'G'B' u8"), rgba);
|
||||
result = marshal_rgba_to_list_of_numeric (sc, rgba, 3);
|
||||
break;
|
||||
case 4:
|
||||
gegl_color_get_pixel (color, babl_format ("R'G'B'A u8"), rgba);
|
||||
result = marshal_rgba_to_list_of_numeric (sc, rgba, 4);
|
||||
break;
|
||||
case 1:
|
||||
/* Grayscale with TRC from space */
|
||||
gegl_color_get_pixel (color, babl_format ("Y' u8"), rgba);
|
||||
result = marshal_rgba_to_list_of_numeric (sc, rgba, 1);
|
||||
break;
|
||||
case 2:
|
||||
/* Grayscale with TRC from space, separate alpha. */
|
||||
gegl_color_get_pixel (color, babl_format ("Y'A u8"), rgba);
|
||||
result = marshal_rgba_to_list_of_numeric (sc, rgba, 2);
|
||||
break;
|
||||
default:
|
||||
g_warning ("%s unhandled count of color components: %d", G_STRFUNC, count_components);
|
||||
result = sc->NIL;
|
||||
}
|
||||
}
|
||||
|
||||
if (color)
|
||||
gegl_color_get_pixel (color, babl_format ("R'G'B' u8"), rgb);
|
||||
/* else will return (0 0 0) */
|
||||
|
||||
return sc->vptr->cons (
|
||||
sc,
|
||||
sc->vptr->mk_integer (sc, rgb[0]),
|
||||
sc->vptr->cons (sc,
|
||||
sc->vptr->mk_integer (sc, rgb[1]),
|
||||
sc->vptr->cons (sc,
|
||||
sc->vptr->mk_integer (sc, rgb[2]),
|
||||
sc->NIL)));
|
||||
return result;
|
||||
}
|
||||
|
||||
/* ColorArray */
|
||||
|
|
|
@ -37,10 +37,11 @@
|
|||
* and default values, only the declarations of defaults etc.
|
||||
* Since a GimpProcedureConfig carries the values
|
||||
* and GParamSpec carries the defaults.
|
||||
* - ScriptFu might not support RGB triplet repr
|
||||
* - ScriptFu might support other formats
|
||||
*
|
||||
* Complex:
|
||||
* PDB and widgets traffic in GeglColor but SF dumbs it down to a Scheme list (r g b)
|
||||
* PDB and widgets traffic in GeglColor but SF dumbs it down to a Scheme list
|
||||
* e.g. (r g b) (r g b a) or (y) or (y a)
|
||||
*
|
||||
* More SF code deals with GeglColor:
|
||||
* see scheme_marshall.c we marshall from GeglColor to/from Scheme lists of numbers.
|
||||
|
@ -49,19 +50,17 @@
|
|||
|
||||
/* Return the Scheme representation.
|
||||
* Caller owns returned string.
|
||||
*
|
||||
* An alias: knows SFColorType is GeglColor
|
||||
*/
|
||||
gchar*
|
||||
sf_color_get_repr (SFColorType arg_value)
|
||||
{
|
||||
guchar rgb[3] = { 0 };
|
||||
|
||||
if (arg_value)
|
||||
gegl_color_get_pixel (arg_value, babl_format ("R'G'B' u8"), rgb);
|
||||
|
||||
return g_strdup_printf ("'(%d %d %d)", (gint) rgb[0], (gint) rgb[1], (gint) rgb[2]);
|
||||
return sf_color_get_repr_from_gegl_color (arg_value);
|
||||
}
|
||||
|
||||
/* Returns GeglColor from SFColorType.
|
||||
/* Returns GeglColor from arg of type SFColorType.
|
||||
* When arg is NULL, returns GeglColor transparent.
|
||||
*
|
||||
* Returned GeglColor is owned by caller.
|
||||
*/
|
||||
|
@ -78,19 +77,25 @@ void
|
|||
sf_color_set_from_gegl_color (SFColorType *arg_value,
|
||||
GeglColor *color)
|
||||
{
|
||||
const Babl *format = gegl_color_get_format (color);
|
||||
guint8 pixel[48];
|
||||
|
||||
gegl_color_get_pixel (color, format, pixel);
|
||||
if (*arg_value)
|
||||
gegl_color_set_pixel (*arg_value, format, pixel);
|
||||
{
|
||||
/* Arg is already a GeglColor, change its color. */
|
||||
const Babl *format = gegl_color_get_format (color);
|
||||
guint8 pixel[48];
|
||||
|
||||
gegl_color_get_pixel (color, format, pixel);
|
||||
gegl_color_set_pixel (*arg_value, format, pixel);
|
||||
}
|
||||
else
|
||||
*arg_value = gegl_color_duplicate (color);
|
||||
{
|
||||
/* Arg is NULL. Duplicate given color. */
|
||||
*arg_value = gegl_color_duplicate (color);
|
||||
}
|
||||
}
|
||||
|
||||
/* Set the default for an arg of type SFColorType from a string name.
|
||||
*
|
||||
* Keep default value to put in default of param spec when creating procedure.
|
||||
* The default value is later put in default of param spec when creating procedure.
|
||||
*
|
||||
* Also, the old-style dialog resets from the kept default value.
|
||||
* Versus new-style dialog, using ProcedureConfig, which resets from a paramspec.
|
||||
|
@ -115,12 +120,20 @@ sf_color_arg_set_default_by_name (SFArg *arg,
|
|||
}
|
||||
else
|
||||
{
|
||||
/* ScriptFu does not let an author specify RGBA, only RGB. */
|
||||
gimp_color_set_alpha (color, 1.0);
|
||||
/* css named colors are in sRGB.
|
||||
* You cannot name a grayscale color.
|
||||
* However, "transparent" is also a css named color.
|
||||
*/
|
||||
/* We don't override alpha:
|
||||
* Not calling: gimp_color_set_alpha (color, 1.0);
|
||||
*/
|
||||
|
||||
/* Copying a struct that is not allocated, not setting a pointer. */
|
||||
g_clear_object (&arg->default_value.sfa_color);
|
||||
arg->default_value.sfa_color = color;
|
||||
/* Expect the default is NULL, but call the setter anyway,
|
||||
* which sets it when not already NULL.
|
||||
*/
|
||||
sf_color_set_from_gegl_color (&arg->default_value.sfa_color, color);
|
||||
|
||||
g_object_unref (color);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
@ -146,7 +159,7 @@ GeglColor*
|
|||
sf_color_arg_get_default_color (SFArg *arg)
|
||||
{
|
||||
/* require the default was set earlier.
|
||||
* No easy way to assert it was set,
|
||||
* No easy way to assert it was set.
|
||||
*/
|
||||
return sf_color_get_gegl_color (arg->default_value.sfa_color);
|
||||
}
|
||||
|
@ -154,22 +167,53 @@ sf_color_arg_get_default_color (SFArg *arg)
|
|||
|
||||
/* Methods for conversion GeglColor to/from Scheme representation. */
|
||||
|
||||
/* Caller owns returned string.*/
|
||||
/* Convert GeglColor to scheme representation as list of numeric.
|
||||
* List is length in [0,4].
|
||||
* Caller owns returned string.
|
||||
* Length depends on format: GRAY, GRAYA, RGB, or RGBA.
|
||||
* Returns literal for empty list when color is NULL.
|
||||
*/
|
||||
gchar*
|
||||
sf_color_get_repr_from_gegl_color (GeglColor *color)
|
||||
{
|
||||
guchar rgb[3] = { 0 };
|
||||
gchar *result;
|
||||
|
||||
/* Warn when color has different count of components than
|
||||
* the 3 of the pixel we are converting to.
|
||||
*/
|
||||
if (babl_format_get_n_components (gegl_color_get_format (color)) != 3)
|
||||
if (color == NULL)
|
||||
{
|
||||
g_warning ("%s converting to pixel with loss/gain of components", G_STRFUNC);
|
||||
result = g_strdup_printf ("'()");
|
||||
}
|
||||
else
|
||||
{
|
||||
guint count_components = babl_format_get_n_components (gegl_color_get_format (color));
|
||||
guchar rgba[4] = { 0 };
|
||||
|
||||
/* Dispatch on count of components. */
|
||||
switch (count_components)
|
||||
{
|
||||
case 1:
|
||||
gegl_color_get_pixel (color, babl_format ("Y' u8"), rgba);
|
||||
result = g_strdup_printf ("'(%d)", (gint) rgba[0]);
|
||||
break;
|
||||
case 2:
|
||||
gegl_color_get_pixel (color, babl_format ("Y'A u8"), rgba);
|
||||
result = g_strdup_printf ("'(%d %d)", (gint) rgba[0], (gint) rgba[1]);
|
||||
break;
|
||||
case 3:
|
||||
gegl_color_get_pixel (color, babl_format ("R'G'B' u8"), rgba);
|
||||
result = g_strdup_printf ("'(%d %d %d)", (gint) rgba[0], (gint) rgba[1], (gint) rgba[2]);
|
||||
break;
|
||||
case 4:
|
||||
gegl_color_get_pixel (color, babl_format ("R'G'B'A u8"), rgba);
|
||||
result = g_strdup_printf ("'(%d %d %d %d)",
|
||||
(gint) rgba[0], (gint) rgba[1], (gint) rgba[2], (gint) rgba[3]);
|
||||
break;
|
||||
default:
|
||||
g_warning ("%s unhandled count of color components", G_STRFUNC);
|
||||
result = g_strdup_printf ("'()");
|
||||
}
|
||||
}
|
||||
|
||||
gegl_color_get_pixel (color, babl_format ("R'G'B' u8"), rgb);
|
||||
return g_strdup_printf ("'(%d %d %d)", (gint) rgb[0], (gint) rgb[1], (gint) rgb[2]);
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Caller owns the returned GeglColor.
|
||||
|
|
Loading…
Reference in New Issue