app, libgimp, pdb, plug-ins: GimpText* using GeglColor.

One of the big improvement in this commit is that text layers are now much
better at space accuracy. They were already space-aware, yet rendered as sRGB u8
only before being converted to the image's space. It means that text layers had
the following limitations:

* Any color out of sRGB gamut were trimmed.
* Precision was always 8-bit (even if the image was high-bit depth).

Now GimpTextLayout keeps track of its source space (for RGB and CMYK only, this
won't be as easy when we will support more backend, since Cairo has only RGB
support for image data) and the image TRC (in case it bypasses the color space's
TRB) and it draws within this gamut and space.
It means first that we are not limited to sRGB colors; we will draw text main
color in the full image gamut, with still 2 remaining limitations:

* Unbounded colors are impossible because Pango format (to color text) uses
  hexadecimal (so even with half/float images, you can't draw out-of-gamut text
  unfortunately).
* Main color precision is still 8-bit, yet a tiny bit better than before as we
  at least follow TRC (so we avoid some of the precision loss when converting,
  even though the bit-depth is still the biggest loss).

The outline color on the other hand is drawn through Cairo API entirely, in
float. This means that the outline color will now be without any precision loss.

Note that this depends on CAIRO_FORMAT_RGBA128F which is only available since
Cairo 1.17.2 which is not in Debian bookworm (our current baseline for GIMP
3.0). It means that the old precision will still happen with older Cairo
version, as determined by #if code at compilation.
This commit is contained in:
Jehan 2023-11-17 22:36:31 +01:00
parent a60b16f497
commit e992ca3e51
24 changed files with 276 additions and 173 deletions

View file

@ -815,20 +815,6 @@ gimp_image_get_color_transform_to_srgb_u8 (GimpImage *image)
return private->transform_to_srgb_u8;
}
GimpColorTransform *
gimp_image_get_color_transform_from_srgb_u8 (GimpImage *image)
{
GimpImagePrivate *private;
g_return_val_if_fail (GIMP_IS_IMAGE (image), NULL);
private = GIMP_IMAGE_GET_PRIVATE (image);
gimp_image_create_color_transforms (image);
return private->transform_from_srgb_u8;
}
GimpColorTransform *
gimp_image_get_color_transform_to_srgb_double (GimpImage *image)
{
@ -938,7 +924,6 @@ _gimp_image_free_color_transforms (GimpImage *image)
GimpImagePrivate *private = GIMP_IMAGE_GET_PRIVATE (image);
g_clear_object (&private->transform_to_srgb_u8);
g_clear_object (&private->transform_from_srgb_u8);
g_clear_object (&private->transform_to_srgb_double);
g_clear_object (&private->transform_from_srgb_double);
@ -1162,14 +1147,6 @@ gimp_image_create_color_transforms (GimpImage *image)
GIMP_COLOR_RENDERING_INTENT_PERCEPTUAL,
flags);
private->transform_from_srgb_u8 =
gimp_color_transform_new (srgb_profile,
babl_format ("R'G'B'A u8"),
private->color_profile,
gimp_image_get_layer_format (image, TRUE),
GIMP_COLOR_RENDERING_INTENT_PERCEPTUAL,
flags);
private->transform_to_srgb_double =
gimp_color_transform_new (private->color_profile,
gimp_image_get_layer_format (image, TRUE),

View file

@ -110,8 +110,6 @@ void gimp_image_import_color_profile (GimpImage *ima
GimpColorTransform * gimp_image_get_color_transform_to_srgb_u8
(GimpImage *image);
GimpColorTransform * gimp_image_get_color_transform_from_srgb_u8
(GimpImage *image);
GimpColorTransform * gimp_image_get_color_transform_to_srgb_double
(GimpImage *image);

View file

@ -74,7 +74,6 @@ struct _GimpImagePrivate
/* Cached color transforms: from layer to sRGB u8 and double, and back */
gboolean color_transforms_created;
GimpColorTransform *transform_to_srgb_u8;
GimpColorTransform *transform_from_srgb_u8;
GimpColorTransform *transform_to_srgb_double;
GimpColorTransform *transform_from_srgb_double;

View file

@ -389,17 +389,14 @@ gimp_display_shell_dnd_fill (GimpDisplayShell *shell,
gimp_fill_options_get_style (options) == GIMP_FILL_STYLE_BG_COLOR))
{
GeglColor *color;
GimpRGB rgb;
if (gimp_fill_options_get_style (options) == GIMP_FILL_STYLE_FG_COLOR)
color = gimp_context_get_foreground (GIMP_CONTEXT (options));
else
color = gimp_context_get_background (GIMP_CONTEXT (options));
gegl_color_get_rgba_with_space (color, &rgb.r, &rgb.g, &rgb.b, &rgb.a, NULL);
gimp_text_layer_set (iter->data, NULL,
"color", &rgb,
"color", color,
NULL);
}
else

View file

@ -734,20 +734,20 @@ text_layer_get_color_invoker (GimpProcedure *procedure,
gboolean success = TRUE;
GimpValueArray *return_vals;
GimpTextLayer *layer;
GimpRGB color = { 0.0, 0.0, 0.0, 1.0 };
GeglColor *color = NULL;
layer = g_value_get_object (gimp_value_array_index (args, 0));
if (success)
{
color = gimp_text_layer_get_text (layer)->color;
color = gegl_color_duplicate (gimp_text_layer_get_text (layer)->color);
}
return_vals = gimp_procedure_get_return_values (procedure, success,
error ? *error : NULL);
if (success)
gimp_value_set_rgb (gimp_value_array_index (return_vals, 1), &color);
g_value_take_object (gimp_value_array_index (return_vals, 1), color);
return return_vals;
}
@ -1685,12 +1685,11 @@ register_text_layer_procs (GimpPDB *pdb)
FALSE,
GIMP_PARAM_READWRITE));
gimp_procedure_add_return_value (procedure,
gimp_param_spec_rgb ("color",
"color",
"The color of the text.",
FALSE,
NULL,
GIMP_PARAM_READWRITE));
gegl_param_spec_color ("color",
"color",
"The color of the text.",
NULL,
GIMP_PARAM_READWRITE));
gimp_pdb_register_procedure (pdb, procedure);
g_object_unref (procedure);

View file

@ -82,7 +82,7 @@ gimp_text_vectors_new (GimpImage *image,
gimp_image_get_resolution (image, &xres, &yres);
layout = gimp_text_layout_new (text, xres, yres, &error);
layout = gimp_text_layout_new (text, image, xres, yres, &error);
if (error)
{
gimp_message_literal (image->gimp, NULL, GIMP_MESSAGE_ERROR, error->message);

View file

@ -141,8 +141,8 @@ gimp_text_class_init (GimpTextClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GimpObjectClass *gimp_object_class = GIMP_OBJECT_CLASS (klass);
GimpRGB black;
GimpRGB gray;
GeglColor *black = gegl_color_new ("black");
GeglColor *gray = gegl_color_new ("gray");
GimpMatrix2 identity;
gchar *language;
GParamSpec *array_spec;
@ -162,8 +162,6 @@ gimp_text_class_init (GimpTextClass *klass)
gimp_object_class->get_memsize = gimp_text_get_memsize;
gimp_rgba_set (&black, 0.0, 0.0, 0.0, GIMP_OPACITY_OPAQUE);
gimp_rgba_set (&gray, 0.75, 0.75, 0.75, GIMP_OPACITY_OPAQUE);
gimp_matrix2_identity (&identity);
GIMP_CONFIG_PROP_STRING (object_class, PROP_TEXT,
@ -235,11 +233,11 @@ gimp_text_class_init (GimpTextClass *klass)
GIMP_TEXT_DIRECTION_LTR,
GIMP_PARAM_STATIC_STRINGS);
GIMP_CONFIG_PROP_RGB (object_class, PROP_COLOR,
"color",
NULL, NULL,
FALSE, &black,
GIMP_PARAM_STATIC_STRINGS);
GIMP_CONFIG_PROP_COLOR (object_class, PROP_COLOR,
"color",
NULL, NULL,
black,
GIMP_PARAM_STATIC_STRINGS);
GIMP_CONFIG_PROP_ENUM (object_class, PROP_OUTLINE,
"outline",
@ -341,10 +339,10 @@ gimp_text_class_init (GimpTextClass *klass)
"outline-pattern", NULL, NULL,
GIMP_TYPE_PATTERN,
GIMP_PARAM_STATIC_STRINGS);
GIMP_CONFIG_PROP_RGB (object_class, PROP_OUTLINE_FOREGROUND,
"outline-foreground", NULL, NULL,
FALSE, &gray,
GIMP_PARAM_STATIC_STRINGS);
GIMP_CONFIG_PROP_COLOR (object_class, PROP_OUTLINE_FOREGROUND,
"outline-foreground", NULL, NULL,
gray,
GIMP_PARAM_STATIC_STRINGS);
GIMP_CONFIG_PROP_DOUBLE (object_class, PROP_OUTLINE_WIDTH,
"outline-width", NULL, NULL,
0.0, 8192.0, 4.0,
@ -394,6 +392,8 @@ gimp_text_class_init (GimpTextClass *klass)
GIMP_PARAM_READWRITE |
G_PARAM_CONSTRUCT_ONLY));
g_object_unref (black);
g_object_unref (gray);
}
static void
@ -417,6 +417,8 @@ gimp_text_finalize (GObject *object)
g_clear_pointer (&text->markup, g_free);
g_clear_pointer (&text->language, g_free);
g_clear_object (&text->font);
g_clear_object (&text->color);
g_clear_object (&text->outline_foreground);
G_OBJECT_CLASS (parent_class)->finalize (object);
}
@ -462,7 +464,7 @@ gimp_text_get_property (GObject *object,
g_value_set_string (value, text->language);
break;
case PROP_COLOR:
g_value_set_boxed (value, &text->color);
g_value_set_object (value, text->color);
break;
case PROP_OUTLINE:
g_value_set_enum (value, text->outline);
@ -504,7 +506,7 @@ gimp_text_get_property (GObject *object,
g_value_set_enum (value, text->outline_style);
break;
case PROP_OUTLINE_FOREGROUND:
g_value_set_boxed (value, &text->outline_foreground);
g_value_set_object (value, text->outline_foreground);
break;
case PROP_OUTLINE_PATTERN:
g_value_set_object (value, text->outline_pattern);
@ -555,7 +557,6 @@ gimp_text_set_property (GObject *object,
GParamSpec *pspec)
{
GimpText *text = GIMP_TEXT (object);
GimpRGB *color;
GimpMatrix2 *matrix;
switch (property_id)
@ -609,8 +610,7 @@ gimp_text_set_property (GObject *object,
text->base_dir = g_value_get_enum (value);
break;
case PROP_COLOR:
color = g_value_get_boxed (value);
text->color = *color;
g_set_object (&text->color, g_value_get_object (value));;
break;
case PROP_OUTLINE:
text->outline = g_value_get_enum (value);
@ -653,8 +653,7 @@ gimp_text_set_property (GObject *object,
text->outline_style = g_value_get_enum (value);
break;
case PROP_OUTLINE_FOREGROUND:
color = g_value_get_boxed (value);
text->outline_foreground = *color;
g_set_object (&text->outline_foreground, g_value_get_object (value));;
break;
case PROP_OUTLINE_PATTERN:
{

View file

@ -49,10 +49,10 @@ struct _GimpText
gboolean kerning;
gchar *language;
GimpTextDirection base_dir;
GimpRGB color;
GeglColor *color;
GimpCustomStyle outline_style;
GimpPattern *outline_pattern;
GimpRGB outline_foreground;
GeglColor *outline_foreground;
gdouble outline_width;
GimpCapStyle outline_cap_style;
GimpJoinStyle outline_join_style;

View file

@ -53,7 +53,6 @@
#include "gimptext.h"
#include "gimptextlayer.h"
#include "gimptextlayer-transform.h"
#include "gimptextlayout.h"
#include "gimptextlayout-render.h"
@ -725,7 +724,7 @@ gimp_text_layer_render (GimpTextLayer *layer)
gimp_image_get_resolution (image, &xres, &yres);
layout = gimp_text_layout_new (layer->text, xres, yres, &error);
layout = gimp_text_layout_new (layer->text, image, xres, yres, &error);
if (error)
{
gimp_message_literal (image->gimp, NULL, GIMP_MESSAGE_ERROR, error->message);
@ -927,9 +926,8 @@ gimp_text_layer_render_layout (GimpTextLayer *layer,
{
GimpDrawable *drawable = GIMP_DRAWABLE (layer);
GimpItem *item = GIMP_ITEM (layer);
GimpImage *image = gimp_item_get_image (item);
const Babl *format;
GeglBuffer *buffer;
GimpColorTransform *transform;
cairo_t *cr;
cairo_surface_t *surface;
gint width;
@ -941,7 +939,11 @@ gimp_text_layer_render_layout (GimpTextLayer *layer,
width = gimp_item_get_width (item);
height = gimp_item_get_height (item);
#if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1, 17, 2)
surface = cairo_image_surface_create (CAIRO_FORMAT_RGBA128F, width, height);
#else
surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height);
#endif
status = cairo_surface_status (surface);
if (status != CAIRO_STATUS_SUCCESS)
@ -968,7 +970,6 @@ gimp_text_layer_render_layout (GimpTextLayer *layer,
if (layer->text->outline != GIMP_TEXT_OUTLINE_NONE)
{
GimpText *text = layer->text;
GimpRGB col = text->outline_foreground;
cairo_save (cr);
@ -998,7 +999,16 @@ gimp_text_layer_render_layout (GimpTextLayer *layer,
}
else
{
cairo_set_source_rgba (cr, col.r, col.g, col.b, col.a);
GeglColor *col = text->outline_foreground;
gdouble color[3];
format = gimp_text_layout_get_format (layout, "double");
gegl_color_get_pixel (col, format, color);
/* Text layout can be either grayscale or RGB without alpha. */
if (! babl_space_is_gray (babl_format_get_space (format)))
cairo_set_source_rgba (cr, color[0], color[1], color[2], 1.0);
else
cairo_set_source_rgba (cr, color[0], color[0], color[0], 1.0);
}
cairo_set_line_width (cr, text->outline_width * 2);
@ -1014,23 +1024,29 @@ gimp_text_layer_render_layout (GimpTextLayer *layer,
cairo_surface_flush (surface);
buffer = gimp_cairo_surface_create_buffer (surface);
transform = gimp_image_get_color_transform_from_srgb_u8 (image);
if (transform)
#if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1, 17, 2)
/* The CAIRO_FORMAT_RGBA128F surface maps to the layout TRC and space. */
switch (gimp_text_layout_get_trc (layout))
{
gimp_color_transform_process_buffer (transform,
buffer,
NULL,
gimp_drawable_get_buffer (drawable),
NULL);
}
else
{
gimp_gegl_buffer_copy (buffer, NULL, GEGL_ABYSS_NONE,
gimp_drawable_get_buffer (drawable), NULL);
case GIMP_TRC_LINEAR:
format = babl_format_with_space ("RGBA float", gimp_text_layout_get_space (layout));
break;
case GIMP_TRC_NON_LINEAR:
format = babl_format_with_space ("R'G'B'A float", gimp_text_layout_get_space (layout));
break;
case GIMP_TRC_PERCEPTUAL:
format = babl_format_with_space ("R~G~B~A float", gimp_text_layout_get_space (layout));
break;
default:
g_return_if_reached ();
}
#else
format = babl_format_with_space ("cairo-ARGB32", gimp_text_layout_get_space (layout));
#endif
buffer = gimp_cairo_surface_create_buffer (surface, format);
gimp_gegl_buffer_copy (buffer, NULL, GEGL_ABYSS_NONE,
gimp_drawable_get_buffer (drawable), NULL);
g_object_unref (buffer);
cairo_surface_destroy (surface);

View file

@ -32,7 +32,10 @@
#include "text-types.h"
#include "gegl/gimp-babl.h"
#include "core/gimperror.h"
#include "core/gimpimage.h"
#include "gimpfont.h"
@ -50,6 +53,8 @@ struct _GimpTextLayout
gdouble yres;
PangoLayout *layout;
PangoRectangle extents;
const Babl *layout_space;
GimpTRCType layout_trc;
};
@ -105,18 +110,21 @@ gimp_text_layout_finalize (GObject *object)
GimpTextLayout *
gimp_text_layout_new (GimpText *text,
gdouble xres,
gdouble yres,
GError **error)
gimp_text_layout_new (GimpText *text,
GimpImage *target_image,
gdouble xres,
gdouble yres,
GError **error)
{
GimpTextLayout *layout;
const Babl *target_space;
PangoContext *context;
PangoFontDescription *font_desc;
PangoAlignment alignment = PANGO_ALIGN_LEFT;
gint size;
g_return_val_if_fail (GIMP_IS_TEXT (text), NULL);
g_return_val_if_fail (GIMP_IS_IMAGE (target_image), NULL);
font_desc = pango_font_description_from_string (gimp_font_get_lookup_name (text->font));
g_return_val_if_fail (font_desc != NULL, NULL);
@ -141,6 +149,25 @@ gimp_text_layout_new (GimpText *text,
pango_layout_set_font_description (layout->layout, font_desc);
pango_font_description_free (font_desc);
target_space = gimp_image_get_layer_space (target_image);
#if BABL_MINOR_VERSION > 1 || (BABL_MINOR_VERSION == 1 && BABL_MICRO_VERSION >= 107)
if (babl_space_is_rgb (target_space) || babl_space_is_gray (target_space))
#else
if (! babl_space_is_cmyk (target_space))
#endif
layout->layout_space = target_space;
else
layout->layout_space = NULL;
#if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1, 17, 2)
layout->layout_trc = gimp_babl_trc (gimp_image_get_precision (target_image));
#else
/* With older Cairo, we just use cairo-ARGB32 with no linear or perceptual
* option.
*/
layout->layout_trc = GIMP_TRC_NON_LINEAR;
#endif
gimp_text_layout_set_markup (layout, error);
switch (text->justify)
@ -221,6 +248,72 @@ gimp_text_layout_new (GimpText *text,
return layout;
}
const GimpTRCType
gimp_text_layout_get_trc (GimpTextLayout *layout)
{
g_return_val_if_fail (GIMP_IS_TEXT_LAYOUT (layout), GIMP_TRC_NON_LINEAR);
return layout->layout_trc;
}
const Babl *
gimp_text_layout_get_format (GimpTextLayout *layout,
const gchar *babl_type)
{
const Babl *format;
gchar *format_name;
g_return_val_if_fail (GIMP_IS_TEXT_LAYOUT (layout), NULL);
if (! babl_space_is_gray (layout->layout_space))
{
switch (layout->layout_trc)
{
case GIMP_TRC_LINEAR:
format_name = g_strdup_printf ("RGB %s", babl_type);
break;
case GIMP_TRC_NON_LINEAR:
format_name = g_strdup_printf ("R'G'B' %s", babl_type);
break;
case GIMP_TRC_PERCEPTUAL:
format_name = g_strdup_printf ("R~G~B~ %s", babl_type);
break;
default:
g_return_val_if_reached (NULL);
}
}
else
{
switch (layout->layout_trc)
{
case GIMP_TRC_LINEAR:
format_name = g_strdup_printf ("Y %s", babl_type);
break;
case GIMP_TRC_NON_LINEAR:
format_name = g_strdup_printf ("Y' %s", babl_type);
break;
case GIMP_TRC_PERCEPTUAL:
format_name = g_strdup_printf ("Y~ %s", babl_type);
break;
default:
g_return_val_if_reached (NULL);
}
}
format = babl_format_with_space (format_name, layout->layout_space);
g_free (format_name);
return format;
}
const Babl *
gimp_text_layout_get_space (GimpTextLayout *layout)
{
g_return_val_if_fail (GIMP_IS_TEXT_LAYOUT (layout), NULL);
return layout->layout_space;
}
gboolean
gimp_text_layout_get_size (GimpTextLayout *layout,
gint *width,
@ -499,17 +592,31 @@ static gchar *
gimp_text_layout_apply_tags (GimpTextLayout *layout,
const gchar *markup)
{
GimpText *text = layout->text;
gchar *result;
{
guchar r, g, b;
gimp_rgb_get_uchar (&text->color, &r, &g, &b);
const Babl *format;
GimpText *text = layout->text;
gchar *result;
guchar color[3];
/* Unfortunately Pango markup are very limited, color-wise. Colors are
* written in hexadecimal, so they are u8 as maximum precision, and
* unbounded colors are not accessible.
* At the very least, what we do is to write color values in the target
* space in the PangoLayout, so that we don't end up stuck to sRGB text
* colors even in images with wider gamut spaces.
*
* Moreover this is limited to RGB and Grayscale spaces. Therefore, images
* with other backends will be limited to the sRGB gamut, for as long as Pango
* do not evolve (or unless we changed our rendering backend).
*/
format = gimp_text_layout_get_format (layout, "u8");
gegl_color_get_pixel (text->color, format, color);
if (! babl_space_is_gray (babl_format_get_space (format)))
result = g_strdup_printf ("<span color=\"#%02x%02x%02x\">%s</span>",
r, g, b, markup);
}
color[0], color[1], color[2], markup);
else
result = g_strdup_printf ("<span color=\"#%02x%02x%02x\">%s</span>",
color[0], color[0], color[0], markup);
/* Updating font 'locl' (if supported) with 'lang' feature tag */
if (text->language)
{
@ -598,7 +705,9 @@ gimp_text_layout_set_markup (GimpTextLayout *layout,
}
}
else
pango_layout_set_markup (layout->layout, markup, -1);
{
pango_layout_set_markup (layout->layout, markup, -1);
}
g_free (markup);
}

View file

@ -38,9 +38,16 @@ struct _GimpTextLayoutClass
GType gimp_text_layout_get_type (void) G_GNUC_CONST;
GimpTextLayout * gimp_text_layout_new (GimpText *text,
GimpImage *target_image,
gdouble xres,
gdouble yres,
GError **error);
const Babl * gimp_text_layout_get_space (GimpTextLayout *layout);
const GimpTRCType gimp_text_layout_get_trc (GimpTextLayout *layout);
const Babl * gimp_text_layout_get_format (GimpTextLayout *layout,
const gchar *babl_type);
gboolean gimp_text_layout_get_size (GimpTextLayout *layout,
gint *width,
gint *height);

View file

@ -152,10 +152,9 @@ static void
gimp_text_options_class_init (GimpTextOptionsClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GimpRGB gray;
GeglColor *gray = gegl_color_new ("gray");
GParamSpec *array_spec;
gimp_rgba_set (&gray, 0.75, 0.75, 0.75, GIMP_OPACITY_OPAQUE);
object_class->finalize = gimp_text_options_finalize;
object_class->set_property = gimp_text_options_set_property;
object_class->get_property = gimp_text_options_get_property;
@ -286,11 +285,11 @@ gimp_text_options_class_init (GimpTextOptionsClass *klass)
GIMP_TYPE_CUSTOM_STYLE,
GIMP_CUSTOM_STYLE_SOLID_COLOR,
GIMP_PARAM_STATIC_STRINGS);
GIMP_CONFIG_PROP_RGB (object_class, PROP_OUTLINE_FOREGROUND,
"outline-foreground",
NULL, NULL,
FALSE, &gray,
GIMP_PARAM_STATIC_STRINGS);
GIMP_CONFIG_PROP_COLOR (object_class, PROP_OUTLINE_FOREGROUND,
"outline-foreground",
NULL, NULL,
gray,
GIMP_PARAM_STATIC_STRINGS);
GIMP_CONFIG_PROP_OBJECT (object_class, PROP_OUTLINE_PATTERN,
"outline-pattern",
NULL, NULL,
@ -349,6 +348,8 @@ gimp_text_options_class_init (GimpTextOptionsClass *klass)
array_spec,
GIMP_PARAM_STATIC_STRINGS |
GIMP_CONFIG_PARAM_FLAGS));
g_object_unref (gray);
}
static void
@ -365,7 +366,10 @@ gimp_text_options_config_iface_init (GimpConfigInterface *config_iface)
static void
gimp_text_options_init (GimpTextOptions *options)
{
options->size_entry = NULL;
GeglColor *gray = gegl_color_new ("gray");
options->size_entry = NULL;
options->outline_foreground = gray;
}
static void
@ -374,6 +378,7 @@ gimp_text_options_finalize (GObject *object)
GimpTextOptions *options = GIMP_TEXT_OPTIONS (object);
g_clear_pointer (&options->language, g_free);
g_clear_object (&options->outline_foreground);
G_OBJECT_CLASS (parent_class)->finalize (object);
}
@ -429,7 +434,7 @@ gimp_text_options_get_property (GObject *object,
g_value_set_enum (value, options->outline_style);
break;
case PROP_OUTLINE_FOREGROUND:
g_value_set_boxed (value, &options->outline_foreground);
g_value_set_object (value, options->outline_foreground);
break;
case PROP_OUTLINE_PATTERN:
g_value_set_object (value, options->outline_pattern);
@ -491,7 +496,6 @@ gimp_text_options_set_property (GObject *object,
GParamSpec *pspec)
{
GimpTextOptions *options = GIMP_TEXT_OPTIONS (object);
GimpRGB *color;
switch (property_id)
{
@ -537,8 +541,7 @@ gimp_text_options_set_property (GObject *object,
options->outline_style = g_value_get_enum (value);
break;
case PROP_OUTLINE_FOREGROUND:
color = g_value_get_boxed (value);
options->outline_foreground = *color;
g_set_object (&options->outline_foreground, g_value_get_object (value));;
break;
case PROP_OUTLINE_PATTERN:
{
@ -683,17 +686,11 @@ gimp_text_options_notify_color (GimpContext *context,
GParamSpec *pspec,
GimpText *text)
{
GeglColor *color;
GimpRGB rgb;
color = gimp_context_get_foreground (context);
gegl_color_get_pixel (color, babl_format ("R'G'B'A double"), &rgb);
g_signal_handlers_block_by_func (text,
gimp_text_options_notify_text_color,
context);
g_object_set (text, "color", &rgb, NULL);
g_object_set (text, "color", gimp_context_get_foreground (context), NULL);
g_signal_handlers_unblock_by_func (text,
gimp_text_options_notify_text_color,
@ -705,18 +702,13 @@ gimp_text_options_notify_text_color (GimpText *text,
GParamSpec *pspec,
GimpContext *context)
{
GeglColor *color = gegl_color_new ("black");
g_signal_handlers_block_by_func (context,
gimp_text_options_notify_color, text);
gegl_color_set_rgba_with_space (color, text->color.r, text->color.g, text->color.b, text->color.a, NULL);
gimp_context_set_foreground (context, color);
gimp_context_set_foreground (context, text->color);
g_signal_handlers_unblock_by_func (context,
gimp_text_options_notify_color, text);
g_object_unref (color);
}
/* This function could live in gimptexttool.c also.
@ -727,21 +719,16 @@ gimp_text_options_connect_text (GimpTextOptions *options,
GimpText *text)
{
GimpContext *context;
GeglColor *color;
GimpRGB rgb;
g_return_if_fail (GIMP_IS_TEXT_OPTIONS (options));
g_return_if_fail (GIMP_IS_TEXT (text));
context = GIMP_CONTEXT (options);
color = gimp_context_get_foreground (context);
gegl_color_get_pixel (color, babl_format ("R'G'B'A double"), &rgb);
gimp_config_sync (G_OBJECT (options), G_OBJECT (text), 0);
g_object_set (text,
"color", &rgb,
"color", gimp_context_get_foreground (context),
"font", gimp_context_get_font (context),
NULL);

View file

@ -51,7 +51,7 @@ struct _GimpTextOptions
GimpTextOutline outline;
GimpCustomStyle outline_style;
GimpRGB outline_foreground;
GeglColor *outline_foreground;
GimpPattern *outline_pattern;
gdouble outline_width;
GimpUnit outline_unit;

View file

@ -2031,7 +2031,7 @@ gimp_text_tool_ensure_layout (GimpTextTool *text_tool)
gimp_image_get_resolution (image, &xres, &yres);
text_tool->layout = gimp_text_layout_new (text_tool->layer->text,
xres, yres, &error);
image, xres, yres, &error);
if (error)
{
gimp_message_literal (image->gimp, NULL, GIMP_MESSAGE_ERROR, error->message);

View file

@ -781,12 +781,14 @@ gimp_text_style_editor_set_color (GimpTextStyleEditor *editor,
static void
gimp_text_style_editor_set_default_color (GimpTextStyleEditor *editor)
{
GimpRGB rgb;
g_signal_handlers_block_by_func (editor->color_button,
gimp_text_style_editor_color_changed,
editor);
gimp_color_button_set_color (GIMP_COLOR_BUTTON (editor->color_button),
&editor->text->color);
gegl_color_get_pixel (editor->text->color, babl_format ("R'G'B'A double"), &rgb);
gimp_color_button_set_color (GIMP_COLOR_BUTTON (editor->color_button), &rgb);
g_signal_handlers_unblock_by_func (editor->color_button,
gimp_text_style_editor_color_changed,

View file

@ -1209,7 +1209,7 @@ gimp_view_render_temp_buf_to_surface (GimpViewRenderer *renderer,
width, height);
src_buffer = gimp_temp_buf_create_buffer (temp_buf);
dest_buffer = gimp_cairo_surface_create_buffer (alpha_surface);
dest_buffer = gimp_cairo_surface_create_buffer (alpha_surface, NULL);
transform =
gimp_view_renderer_get_color_transform (renderer, widget,
@ -1258,7 +1258,7 @@ gimp_view_render_temp_buf_to_surface (GimpViewRenderer *renderer,
cairo_surface_flush (surface);
src_buffer = gimp_temp_buf_create_buffer (temp_buf);
dest_buffer = gimp_cairo_surface_create_buffer (surface);
dest_buffer = gimp_cairo_surface_create_buffer (surface, NULL);
transform =
gimp_view_renderer_get_color_transform (renderer, widget,

View file

@ -285,7 +285,7 @@ gimp_layer_new_from_surface (GimpImage *image,
if (layer == NULL)
return NULL;
src_buffer = gimp_cairo_surface_create_buffer (surface);
src_buffer = gimp_cairo_surface_create_buffer (surface, NULL);
dest_buffer = gimp_drawable_get_buffer (GIMP_DRAWABLE (layer));
gegl_buffer_copy (src_buffer, NULL, GEGL_ABYSS_NONE,

View file

@ -869,23 +869,21 @@ gimp_text_layer_set_justification (GimpTextLayer *layer,
/**
* gimp_text_layer_get_color:
* @layer: The text layer.
* @color: (out caller-allocates): The color of the text.
*
* Get the color of the text in a text layer.
*
* This procedure returns the color of the text in a text layer.
*
* Returns: TRUE on success.
* Returns: (transfer full): The color of the text.
*
* Since: 2.6
**/
gboolean
gimp_text_layer_get_color (GimpTextLayer *layer,
GimpRGB *color)
GeglColor *
gimp_text_layer_get_color (GimpTextLayer *layer)
{
GimpValueArray *args;
GimpValueArray *return_vals;
gboolean success = TRUE;
GeglColor *color = NULL;
args = gimp_value_array_new_from_types (NULL,
GIMP_TYPE_TEXT_LAYER, layer,
@ -896,14 +894,12 @@ gimp_text_layer_get_color (GimpTextLayer *layer,
args);
gimp_value_array_unref (args);
success = GIMP_VALUES_GET_ENUM (return_vals, 0) == GIMP_PDB_SUCCESS;
if (success)
GIMP_VALUES_GET_RGB (return_vals, 1, &*color);
if (GIMP_VALUES_GET_ENUM (return_vals, 0) == GIMP_PDB_SUCCESS)
color = g_value_dup_object (gimp_value_array_index (return_vals, 1));
gimp_value_array_unref (return_vals);
return success;
return color;
}
/**

View file

@ -69,8 +69,7 @@ gboolean gimp_text_layer_set_base_direction (GimpTextLayer
GimpTextJustification gimp_text_layer_get_justification (GimpTextLayer *layer);
gboolean gimp_text_layer_set_justification (GimpTextLayer *layer,
GimpTextJustification justify);
gboolean gimp_text_layer_get_color (GimpTextLayer *layer,
GimpRGB *color);
GeglColor* gimp_text_layer_get_color (GimpTextLayer *layer);
gboolean gimp_text_layer_set_color (GimpTextLayer *layer,
const GimpRGB *color);
gdouble gimp_text_layer_get_indent (GimpTextLayer *layer);

View file

@ -162,9 +162,14 @@ gimp_cairo_surface_get_format (cairo_surface_t *surface)
switch (cairo_image_surface_get_format (surface))
{
case CAIRO_FORMAT_RGB24: return babl_format ("cairo-RGB24");
case CAIRO_FORMAT_ARGB32: return babl_format ("cairo-ARGB32");
case CAIRO_FORMAT_A8: return babl_format ("cairo-A8");
case CAIRO_FORMAT_RGB24: return babl_format ("cairo-RGB24");
case CAIRO_FORMAT_ARGB32: return babl_format ("cairo-ARGB32");
case CAIRO_FORMAT_A8: return babl_format ("cairo-A8");
#if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1, 17, 2)
/* Since Cairo 1.17.2 */
case CAIRO_FORMAT_RGB96F: return babl_format ("R'B'B' float");
case CAIRO_FORMAT_RGBA128F: return babl_format ("R'G'B'A float");
#endif
default:
break;
@ -176,27 +181,37 @@ gimp_cairo_surface_get_format (cairo_surface_t *surface)
/**
* gimp_cairo_surface_create_buffer:
* @surface: a Cairo surface
* @format: a Babl format.
*
* This function returns a #GeglBuffer which wraps @surface's pixels.
* It must only be called on image surfaces, calling it on other surface
* types is an error.
*
* If @format is set, the returned [class@Gegl.Buffer] will use it. It has to
* map with @surface Cairo format. If unset, the buffer format will be
* determined from @surface. The main difference is that automatically
* determined format has sRGB space and TRC by default.
*
* Returns: (transfer full): a #GeglBuffer
*
* Since: 2.10
**/
GeglBuffer *
gimp_cairo_surface_create_buffer (cairo_surface_t *surface)
gimp_cairo_surface_create_buffer (cairo_surface_t *surface,
const Babl *format)
{
const Babl *format;
gint width;
gint height;
gint width;
gint height;
g_return_val_if_fail (surface != NULL, NULL);
g_return_val_if_fail (cairo_surface_get_type (surface) ==
CAIRO_SURFACE_TYPE_IMAGE, NULL);
g_return_val_if_fail (format == NULL ||
babl_format_get_bytes_per_pixel (format) == babl_format_get_bytes_per_pixel (gimp_cairo_surface_get_format (surface)),
NULL);
format = gimp_cairo_surface_get_format (surface);
if (format == NULL)
format = gimp_cairo_surface_get_format (surface);
width = cairo_image_surface_get_width (surface);
height = cairo_image_surface_get_height (surface);

View file

@ -35,7 +35,8 @@ cairo_pattern_t * gimp_cairo_checkerboard_create (cairo_t *cr,
const GimpRGB *dark);
const Babl * gimp_cairo_surface_get_format (cairo_surface_t *surface);
GeglBuffer * gimp_cairo_surface_create_buffer (cairo_surface_t *surface);
GeglBuffer * gimp_cairo_surface_create_buffer (cairo_surface_t *surface,
const Babl *format);
/* some useful macros for writing directly to a Cairo surface */

View file

@ -351,6 +351,9 @@ if not babl.found()
# because it would be a newer version.
babl = dependency('babl', version: '>='+babl_minver)
endif
# TODO: we want to bump to Cairo 1.17.2 when possible in order to use
# CAIRO_FORMAT_RGBA128F unconditionally. At time of writing, it's not possible
# because of our bookworm availability requirement.
cairo_minver = '1.14.0'
cairo = dependency('cairo', version: '>='+cairo_minver)

View file

@ -732,14 +732,14 @@ HELP
);
@outargs = (
{ name => 'color', type => 'color', void_ret => 1,
{ name => 'color', type => 'geglcolor',
desc => 'The color of the text.' }
);
%invoke = (
code => <<'CODE'
{
color = gimp_text_layer_get_text (layer)->color;
color = gegl_color_duplicate (gimp_text_layer_get_text (layer)->color);
}
CODE
);

View file

@ -1438,7 +1438,7 @@ get_cairo_surface (GimpDrawable *drawable,
return NULL;
}
dest_buffer = gimp_cairo_surface_create_buffer (surface);
dest_buffer = gimp_cairo_surface_create_buffer (surface, NULL);
if (as_mask)
{
/* src_buffer represents a mask in "Y u8", "Y u16", etc. formats.
@ -1555,7 +1555,8 @@ drawText (GimpLayer *layer,
cairo_font_options_t *options;
gint x;
gint y;
GimpRGB rgb;
GeglColor *color;
gdouble rgb[3];
GimpUnit unit;
gdouble size;
GimpTextHintStyle hinting;
@ -1588,20 +1589,18 @@ drawText (GimpLayer *layer,
/* When dealing with a gray/indexed image, the viewed color of the text layer
* can be different than the one kept in the memory */
if (type == GIMP_RGBA_IMAGE)
{
gimp_text_layer_get_color (GIMP_TEXT_LAYER (layer), &rgb);
}
color = gimp_text_layer_get_color (GIMP_TEXT_LAYER (layer));
else
{
GeglColor *color;
gimp_image_pick_color (gimp_item_get_image (GIMP_ITEM (layer)), 1,
(const GimpItem**) &layer, x, y, FALSE, FALSE, 0,
&color);
gimp_image_pick_color (gimp_item_get_image (GIMP_ITEM (layer)), 1,
(const GimpItem**) &layer, x, y, FALSE, FALSE, 0,
&color);
gegl_color_get_rgba_with_space (color, &rgb.r, &rgb.g, &rgb.b, &rgb.a, NULL);
}
cairo_set_source_rgba (cr, rgb.r, rgb.g, rgb.b, opacity);
/* TODO: this export plug-in is not space-aware yet, so we draw everything as
* sRGB for the time being.
*/
gegl_color_get_pixel (color, babl_format_with_space ("R'G'B' double", NULL), rgb);
cairo_set_source_rgba (cr, rgb[0], rgb[1], rgb[2], opacity);
g_object_unref (color);
/* Hinting */
hinting = gimp_text_layer_get_hint_style (GIMP_TEXT_LAYER (layer));