From ce887767e76e429d3ca577ed944d815d1bb26aae Mon Sep 17 00:00:00 2001 From: Jehan Date: Tue, 12 Dec 2023 00:34:24 +0900 Subject: [PATCH] app, libgimpconfig: color history is now space-invaded. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit I also changed a bit the new color serialization by adding a (color …) symbol framing the contents, for cases where we don't have a specific property name, e.g. for the color history list stored in colorrc, unlike for GimpConfig GeglColor properties. While doing this, I moved GeglColor property deserialization code into gimp_scanner_parse_color() which is now able to recognize both older (color-rgb|rgba|hsv|hsva with no color space) and newer serialization formats ("color", color model agnostic and space aware). --- app/core/gimp-palettes.c | 4 +- app/core/gimp-palettes.h | 12 +- app/core/gimpfilloptions.c | 4 +- app/core/gimppalettemru.c | 93 ++++--- app/core/gimppalettemru.h | 2 +- app/paint/gimperaser.c | 14 +- app/paint/gimpink.c | 6 +- app/paint/gimpmybrushcore.c | 6 +- app/paint/gimppaintbrush.c | 18 +- app/paint/gimppaintbrush.h | 2 +- app/paint/gimpsmudge.c | 9 +- app/tools/gimptexttool.c | 9 +- app/widgets/gimpcolordialog.c | 32 +-- app/widgets/gimpcoloreditor.c | 10 +- app/widgets/gimpcolorhistory.c | 7 +- app/widgets/gimpcolorhistory.h | 4 +- libgimpconfig/gimpconfig-deserialize.c | 140 +--------- libgimpconfig/gimpconfig-serialize.c | 28 +- libgimpconfig/gimpscanner.c | 351 +++++++++++++++++++------ libgimpconfig/gimpscanner.h | 2 +- 20 files changed, 407 insertions(+), 346 deletions(-) diff --git a/app/core/gimp-palettes.c b/app/core/gimp-palettes.c index 4f189a4fa9..2f91434879 100644 --- a/app/core/gimp-palettes.c +++ b/app/core/gimp-palettes.c @@ -111,8 +111,8 @@ gimp_palettes_get_color_history (Gimp *gimp) } void -gimp_palettes_add_color_history (Gimp *gimp, - const GimpRGB *color) +gimp_palettes_add_color_history (Gimp *gimp, + GeglColor *color) { GimpPalette *history; diff --git a/app/core/gimp-palettes.h b/app/core/gimp-palettes.h index 7858c865f6..b73a817c6c 100644 --- a/app/core/gimp-palettes.h +++ b/app/core/gimp-palettes.h @@ -22,14 +22,14 @@ #define __GIMP_PALETTES__ -void gimp_palettes_init (Gimp *gimp); +void gimp_palettes_init (Gimp *gimp); -void gimp_palettes_load (Gimp *gimp); -void gimp_palettes_save (Gimp *gimp); +void gimp_palettes_load (Gimp *gimp); +void gimp_palettes_save (Gimp *gimp); -GimpPalette * gimp_palettes_get_color_history (Gimp *gimp); -void gimp_palettes_add_color_history (Gimp *gimp, - const GimpRGB *color); +GimpPalette * gimp_palettes_get_color_history (Gimp *gimp); +void gimp_palettes_add_color_history (Gimp *gimp, + GeglColor *color); #endif /* __GIMP_PALETTES__ */ diff --git a/app/core/gimpfilloptions.c b/app/core/gimpfilloptions.c index 0ae67ea452..c04c2b33f3 100644 --- a/app/core/gimpfilloptions.c +++ b/app/core/gimpfilloptions.c @@ -583,7 +583,7 @@ gimp_fill_options_fill_buffer (GimpFillOptions *options, color = gimp_context_get_foreground (GIMP_CONTEXT (options)); gegl_color_get_rgba_with_space (color, &rgb.r, &rgb.g, &rgb.b, &rgb.a, NULL); - gimp_palettes_add_color_history (GIMP_CONTEXT (options)->gimp, &rgb); + gimp_palettes_add_color_history (GIMP_CONTEXT (options)->gimp, color); gimp_drawable_fill_buffer (drawable, buffer, &rgb, NULL, 0, 0); } @@ -596,7 +596,7 @@ gimp_fill_options_fill_buffer (GimpFillOptions *options, 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_palettes_add_color_history (GIMP_CONTEXT (options)->gimp, &rgb); + gimp_palettes_add_color_history (GIMP_CONTEXT (options)->gimp, color); gimp_drawable_fill_buffer (drawable, buffer, &rgb, NULL, 0, 0); } diff --git a/app/core/gimppalettemru.c b/app/core/gimppalettemru.c index d7d98508a4..66848b265d 100644 --- a/app/core/gimppalettemru.c +++ b/app/core/gimppalettemru.c @@ -39,7 +39,8 @@ enum { - COLOR_HISTORY = 1 + COLOR_HISTORY = 1, + COLOR = 2 }; @@ -96,6 +97,8 @@ gimp_palette_mru_load (GimpPaletteMru *mru, g_scanner_scope_add_symbol (scanner, 0, "color-history", GINT_TO_POINTER (COLOR_HISTORY)); + g_scanner_scope_add_symbol (scanner, 0, "color", + GINT_TO_POINTER (COLOR_HISTORY)); token = G_TOKEN_LEFT_PAREN; @@ -114,16 +117,12 @@ gimp_palette_mru_load (GimpPaletteMru *mru, { while (g_scanner_peek_next_token (scanner) == G_TOKEN_LEFT_PAREN) { - GeglColor *color; - GimpRGB rgb; + GeglColor *color = NULL; - if (! gimp_scanner_parse_color (scanner, &rgb)) + if (! gimp_scanner_parse_color (scanner, &color)) goto end; - color = gegl_color_new (NULL); - gegl_color_set_pixel (color, babl_format ("R'G'B'A double"), &rgb); - gimp_palette_add_entry (palette, -1, - _("History Color"), color); + gimp_palette_add_entry (palette, -1, _("History Color"), color); g_object_unref (color); if (gimp_palette_get_n_colors (palette) == MAX_N_COLORS) @@ -173,22 +172,57 @@ gimp_palette_mru_save (GimpPaletteMru *mru, for (list = palette->colors; list; list = g_list_next (list)) { GimpPaletteEntry *entry = list->data; - gchar buf[4][G_ASCII_DTOSTR_BUF_SIZE]; - GimpRGB rgb; + GeglColor *color = gegl_color_duplicate (entry->color); + const gchar *encoding; + const Babl *format = gegl_color_get_format (color); + const Babl *space; + GBytes *bytes; + gconstpointer data; + gsize data_length; + guint8 *profile_data; + int profile_length = 0; - gegl_color_get_pixel (entry->color, babl_format ("R'G'B'A double"), &rgb); - g_ascii_dtostr (buf[0], G_ASCII_DTOSTR_BUF_SIZE, rgb.r); - g_ascii_dtostr (buf[1], G_ASCII_DTOSTR_BUF_SIZE, rgb.g); - g_ascii_dtostr (buf[2], G_ASCII_DTOSTR_BUF_SIZE, rgb.b); - g_ascii_dtostr (buf[3], G_ASCII_DTOSTR_BUF_SIZE, rgb.a); + gimp_config_writer_open (writer, "color"); + + if (babl_format_is_palette (format)) + { + guint8 pixel[40]; + + /* As a special case, we don't want to serialize + * palette colors, because they are just too much + * dependent on external data and cannot be + * deserialized back safely. So we convert them first. + */ + format = babl_format_with_space ("R'G'B'A u8", format); + gegl_color_get_pixel (color, format, pixel); + gegl_color_set_pixel (color, format, pixel); + } + + encoding = babl_format_get_encoding (format); + gimp_config_writer_string (writer, encoding); + + bytes = gegl_color_get_bytes (color, format); + data = g_bytes_get_data (bytes, &data_length); + + gimp_config_writer_printf (writer, "%lu", data_length); + gimp_config_writer_data (writer, data_length, data); + + space = babl_format_get_space (format); + if (space != babl_space ("sRGB")) + { + profile_data = (guint8 *) babl_space_get_icc (space, &profile_length); + gimp_config_writer_printf (writer, "%u", profile_length); + if (profile_data) + gimp_config_writer_data (writer, profile_length, profile_data); + } + else + { + gimp_config_writer_printf (writer, "%u", profile_length); + } - /* TODO: this should be stored as properly GeglColor data with space and - * all! - */ - gimp_config_writer_open (writer, "color-rgba"); - gimp_config_writer_printf (writer, "%s %s %s %s", - buf[0], buf[1], buf[2], buf[3]); gimp_config_writer_close (writer); + g_bytes_unref (bytes); + g_object_unref (color); } gimp_config_writer_close (writer); @@ -198,14 +232,13 @@ gimp_palette_mru_save (GimpPaletteMru *mru, void gimp_palette_mru_add (GimpPaletteMru *mru, - const GimpRGB *rgb) + GeglColor *color) { GimpPalette *palette; GList *list; - GeglColor *color; g_return_if_fail (GIMP_IS_PALETTE_MRU (mru)); - g_return_if_fail (rgb != NULL); + g_return_if_fail (GEGL_IS_COLOR (color)); palette = GIMP_PALETTE (mru); @@ -215,22 +248,15 @@ gimp_palette_mru_add (GimpPaletteMru *mru, list = g_list_next (list)) { GimpPaletteEntry *entry = list->data; - GimpRGB entry_rgb; - gegl_color_get_pixel (entry->color, babl_format ("R'G'B'A double"), &entry_rgb); - if (gimp_rgba_distance (&entry_rgb, rgb) < RGBA_EPSILON) + if (gimp_color_is_perceptually_identical (entry->color, color)) { gimp_palette_move_entry (palette, entry, 0); - color = gegl_color_new (NULL); - gegl_color_set_pixel (color, babl_format ("R'G'B'A double"), rgb); - /* Even though they are nearly the same color, let's make them * exactly equal. */ gimp_palette_set_entry_color (palette, 0, color, FALSE); - g_object_unref (color); - return; } } @@ -242,8 +268,5 @@ gimp_palette_mru_add (GimpPaletteMru *mru, MAX_N_COLORS - 1)); } - color = gegl_color_new (NULL); - gegl_color_set_pixel (color, babl_format ("R'G'B'A double"), rgb); gimp_palette_add_entry (palette, 0, _("History Color"), color); - g_object_unref (color); } diff --git a/app/core/gimppalettemru.h b/app/core/gimppalettemru.h index 052555307a..2566400145 100644 --- a/app/core/gimppalettemru.h +++ b/app/core/gimppalettemru.h @@ -56,7 +56,7 @@ void gimp_palette_mru_save (GimpPaletteMru *mru, GFile *file); void gimp_palette_mru_add (GimpPaletteMru *mru, - const GimpRGB *color); + GeglColor *color); #endif /* __GIMP_PALETTE_MRU_H__ */ diff --git a/app/paint/gimperaser.c b/app/paint/gimperaser.c index 3148c3ed19..218f634f3f 100644 --- a/app/paint/gimperaser.c +++ b/app/paint/gimperaser.c @@ -41,7 +41,7 @@ static gboolean gimp_eraser_get_color_history_color (GimpPaintbrush *paintbrush, GimpDrawable *drawable, GimpPaintOptions *paint_options, - GimpRGB *color); + GeglColor **color); static void gimp_eraser_get_paint_params (GimpPaintbrush *paintbrush, GimpDrawable *drawable, GimpPaintOptions *paint_options, @@ -83,10 +83,10 @@ gimp_eraser_init (GimpEraser *eraser) } static gboolean -gimp_eraser_get_color_history_color (GimpPaintbrush *paintbrush, - GimpDrawable *drawable, - GimpPaintOptions *paint_options, - GimpRGB *rgb) +gimp_eraser_get_color_history_color (GimpPaintbrush *paintbrush, + GimpDrawable *drawable, + GimpPaintOptions *paint_options, + GeglColor **color) { /* Erasing on a drawable without alpha is equivalent to * drawing with background color. So let's save history. @@ -94,10 +94,8 @@ gimp_eraser_get_color_history_color (GimpPaintbrush *paintbrush, if (! gimp_drawable_has_alpha (drawable)) { GimpContext *context = GIMP_CONTEXT (paint_options); - GeglColor *color; - color = gimp_context_get_background (context); - gegl_color_get_rgba_with_space (color, &rgb->r, &rgb->g, &rgb->b, &rgb->a, NULL); + *color = gimp_context_get_background (context); return TRUE; } diff --git a/app/paint/gimpink.c b/app/paint/gimpink.c index 58de474d6e..7d48f4f392 100644 --- a/app/paint/gimpink.c +++ b/app/paint/gimpink.c @@ -169,13 +169,9 @@ gimp_ink_paint (GimpPaintCore *paint_core, case GIMP_PAINT_STATE_INIT: { GimpContext *context = GIMP_CONTEXT (paint_options); - GeglColor *foreground; - GimpRGB rgb; gimp_symmetry_set_stateful (sym, TRUE); - foreground = gimp_context_get_foreground (context); - gegl_color_get_pixel (foreground, babl_format_with_space ("R'G'B'A double", NULL), &rgb); - gimp_palettes_add_color_history (context->gimp, &rgb); + gimp_palettes_add_color_history (context->gimp, gimp_context_get_foreground (context)); if (cur_coords->x == last_coords.x && cur_coords->y == last_coords.y) diff --git a/app/paint/gimpmybrushcore.c b/app/paint/gimpmybrushcore.c index d359ddeb93..ab2b679c98 100644 --- a/app/paint/gimpmybrushcore.c +++ b/app/paint/gimpmybrushcore.c @@ -204,17 +204,13 @@ gimp_mybrush_core_paint (GimpPaintCore *paint_core, GimpContext *context = GIMP_CONTEXT (paint_options); gint offset_x; gint offset_y; - GeglColor *color; - GimpRGB fg; g_return_if_fail (g_list_length (drawables) == 1); switch (paint_state) { case GIMP_PAINT_STATE_INIT: - color = gimp_context_get_foreground (context); - gegl_color_get_rgba_with_space (color, &fg.r, &fg.g, &fg.b, &fg.a, NULL); - gimp_palettes_add_color_history (context->gimp, &fg); + gimp_palettes_add_color_history (context->gimp, gimp_context_get_foreground (context)); gimp_symmetry_set_stateful (sym, TRUE); gimp_item_get_offset (drawables->data, &offset_x, &offset_y); diff --git a/app/paint/gimppaintbrush.c b/app/paint/gimppaintbrush.c index df479a7e6d..7edc7893d6 100644 --- a/app/paint/gimppaintbrush.c +++ b/app/paint/gimppaintbrush.c @@ -56,7 +56,7 @@ static void gimp_paintbrush_paint (GimpPaintCore static gboolean gimp_paintbrush_real_get_color_history_color (GimpPaintbrush *paintbrush, GimpDrawable *drawable, GimpPaintOptions *paint_options, - GimpRGB *color); + GeglColor **color); static void gimp_paintbrush_real_get_paint_params (GimpPaintbrush *paintbrush, GimpDrawable *drawable, GimpPaintOptions *paint_options, @@ -118,7 +118,7 @@ gimp_paintbrush_paint (GimpPaintCore *paint_core, { case GIMP_PAINT_STATE_INIT: { - GimpRGB color; + GeglColor *color = NULL; for (GList *iter = drawables; iter; iter = iter->next) if (GIMP_PAINTBRUSH_GET_CLASS (paintbrush)->get_color_history_color && @@ -129,7 +129,7 @@ gimp_paintbrush_paint (GimpPaintCore *paint_core, { GimpContext *context = GIMP_CONTEXT (paint_options); - gimp_palettes_add_color_history (context->gimp, &color); + gimp_palettes_add_color_history (context->gimp, color); } } break; @@ -148,15 +148,14 @@ gimp_paintbrush_paint (GimpPaintCore *paint_core, } static gboolean -gimp_paintbrush_real_get_color_history_color (GimpPaintbrush *paintbrush, - GimpDrawable *drawable, - GimpPaintOptions *paint_options, - GimpRGB *rgb) +gimp_paintbrush_real_get_color_history_color (GimpPaintbrush *paintbrush, + GimpDrawable *drawable, + GimpPaintOptions *paint_options, + GeglColor **color) { GimpContext *context = GIMP_CONTEXT (paint_options); GimpBrushCore *brush_core = GIMP_BRUSH_CORE (paintbrush); GimpDynamics *dynamics = gimp_context_get_dynamics (context); - GeglColor *color; /* We don't save gradient color history and pixmap brushes * have no color to save. @@ -167,8 +166,7 @@ gimp_paintbrush_real_get_color_history_color (GimpPaintbrush *paintbrush, return FALSE; } - color = gimp_context_get_foreground (context); - gegl_color_get_rgba_with_space (color, &rgb->r, &rgb->g, &rgb->b, &rgb->a, NULL); + *color = gimp_context_get_foreground (context); return TRUE; } diff --git a/app/paint/gimppaintbrush.h b/app/paint/gimppaintbrush.h index 61f8d851ee..a59cdf73e8 100644 --- a/app/paint/gimppaintbrush.h +++ b/app/paint/gimppaintbrush.h @@ -49,7 +49,7 @@ struct _GimpPaintbrushClass gboolean (* get_color_history_color) (GimpPaintbrush *paintbrush, GimpDrawable *drawable, GimpPaintOptions *paint_options, - GimpRGB *color); + GeglColor **color); void (* get_paint_params) (GimpPaintbrush *paintbrush, GimpDrawable *drawable, GimpPaintOptions *paint_options, diff --git a/app/paint/gimpsmudge.c b/app/paint/gimpsmudge.c index b8a6b60cfe..86a5ffa785 100644 --- a/app/paint/gimpsmudge.c +++ b/app/paint/gimpsmudge.c @@ -159,14 +159,7 @@ gimp_smudge_paint (GimpPaintCore *paint_core, if (options->flow > 0.0 && ! gimp_dynamics_is_output_enabled (dynamics, GIMP_DYNAMICS_OUTPUT_COLOR) && ! (brush_core->brush && gimp_brush_get_pixmap (brush_core->brush))) - { - GeglColor *foreground; - GimpRGB rgb; - - foreground = gimp_context_get_foreground (context); - gegl_color_get_rgba_with_space (foreground, &rgb.r, &rgb.g, &rgb.b, &rgb.a, NULL); - gimp_palettes_add_color_history (context->gimp, &rgb); - } + gimp_palettes_add_color_history (context->gimp, gimp_context_get_foreground (context)); } break; diff --git a/app/tools/gimptexttool.c b/app/tools/gimptexttool.c index f98a62e95e..4b041c39b3 100644 --- a/app/tools/gimptexttool.c +++ b/app/tools/gimptexttool.c @@ -2002,11 +2002,14 @@ gimp_text_tool_buffer_end_edit (GimpTextBuffer *buffer, static void gimp_text_tool_buffer_color_applied (GimpTextBuffer *buffer, - const GimpRGB *color, + const GimpRGB *rgb, GimpTextTool *text_tool) { - gimp_palettes_add_color_history (GIMP_TOOL (text_tool)->tool_info->gimp, - color); + GeglColor *color = gegl_color_new (NULL); + + gegl_color_set_pixel (color, babl_format ("R'G'B'A double"), rgb); + gimp_palettes_add_color_history (GIMP_TOOL (text_tool)->tool_info->gimp, color); + g_object_unref (color); } diff --git a/app/widgets/gimpcolordialog.c b/app/widgets/gimpcolordialog.c index 23620a618b..abde52e5be 100644 --- a/app/widgets/gimpcolordialog.c +++ b/app/widgets/gimpcolordialog.c @@ -99,10 +99,6 @@ static void gimp_color_dialog_color_changed (GimpColorSelection *selection, static void gimp_color_history_add_clicked (GtkWidget *widget, GimpColorDialog *dialog); -static void gimp_color_dialog_history_selected (GimpColorHistory *history, - const GimpRGB *rgb, - GimpColorDialog *dialog); - static void gimp_color_dialog_image_changed (GimpContext *context, GimpImage *image, GimpColorDialog *dialog); @@ -259,9 +255,9 @@ gimp_color_dialog_constructed (GObject *object) gtk_box_pack_start (GTK_BOX (hbox), GTK_WIDGET (history), TRUE, TRUE, 0); gtk_widget_show (GTK_WIDGET (history)); - g_signal_connect (history, "color-selected", - G_CALLBACK (gimp_color_dialog_history_selected), - dialog); + g_signal_connect_swapped (history, "color-selected", + G_CALLBACK (gimp_color_selection_set_color), + dialog->selection); g_signal_connect (dialog, "show", G_CALLBACK (gimp_color_dialog_show), @@ -706,28 +702,10 @@ gimp_color_history_add_clicked (GtkWidget *widget, GimpViewableDialog *viewable_dialog = GIMP_VIEWABLE_DIALOG (dialog); GimpPalette *history; GeglColor *color; - GimpRGB rgb; history = gimp_palettes_get_color_history (viewable_dialog->context->gimp); - - color = gimp_color_selection_get_color (GIMP_COLOR_SELECTION (dialog->selection)); - gegl_color_get_pixel (color, babl_format ("R'G'B'A double"), &rgb); - - gimp_palette_mru_add (GIMP_PALETTE_MRU (history), &rgb); -} - -/* Color history callback */ - -static void -gimp_color_dialog_history_selected (GimpColorHistory *history, - const GimpRGB *rgb, - GimpColorDialog *dialog) -{ - GeglColor *color = gegl_color_new (NULL); - - gegl_color_set_pixel (color, babl_format ("R'G'B'A double"), rgb); - gimp_color_selection_set_color (GIMP_COLOR_SELECTION (dialog->selection), color); - g_object_unref (color); + color = gimp_color_selection_get_color (GIMP_COLOR_SELECTION (dialog->selection)); + gimp_palette_mru_add (GIMP_PALETTE_MRU (history), color); } /* Context-related callbacks */ diff --git a/app/widgets/gimpcoloreditor.c b/app/widgets/gimpcoloreditor.c index 8cd06b2600..26807e0df1 100644 --- a/app/widgets/gimpcoloreditor.c +++ b/app/widgets/gimpcoloreditor.c @@ -99,7 +99,7 @@ static void gimp_color_editor_entry_changed (GimpColorHexEntry *entry, GimpColorEditor *editor); static void gimp_color_editor_history_selected (GimpColorHistory *history, - const GimpRGB *rgb, + GeglColor *color, GimpColorEditor *editor); G_DEFINE_TYPE_WITH_CODE (GimpColorEditor, gimp_color_editor, GIMP_TYPE_EDITOR, @@ -733,20 +733,14 @@ gimp_color_editor_entry_changed (GimpColorHexEntry *entry, static void gimp_color_editor_history_selected (GimpColorHistory *history, - const GimpRGB *rgb, + GeglColor *color, GimpColorEditor *editor) { if (editor->context) { - GeglColor *color = gegl_color_new ("black"); - - gegl_color_set_rgba_with_space (color, rgb->r, rgb->g, rgb->b, rgb->a, NULL); - if (editor->edit_bg) gimp_context_set_background (editor->context, color); else gimp_context_set_foreground (editor->context, color); - - g_object_unref (color); } } diff --git a/app/widgets/gimpcolorhistory.c b/app/widgets/gimpcolorhistory.c index 7dbef8c6d0..4a5440699f 100644 --- a/app/widgets/gimpcolorhistory.c +++ b/app/widgets/gimpcolorhistory.c @@ -131,7 +131,7 @@ gimp_color_history_class_init (GimpColorHistoryClass *klass) G_STRUCT_OFFSET (GimpColorHistoryClass, color_selected), NULL, NULL, NULL, G_TYPE_NONE, 1, - G_TYPE_POINTER); + GEGL_TYPE_COLOR); g_object_class_install_property (object_class, PROP_CONTEXT, g_param_spec_object ("context", NULL, NULL, @@ -460,15 +460,12 @@ gimp_color_history_color_clicked (GtkWidget *widget, { GimpColorArea *color_area; GeglColor *color; - GimpRGB rgb; color_area = GIMP_COLOR_AREA (gtk_bin_get_child (GTK_BIN (widget))); color = gimp_color_area_get_color (color_area); - gegl_color_get_pixel (color, babl_format ("R'G'B'A double"), &rgb); + g_signal_emit (history, history_signals[COLOR_SELECTED], 0, color); g_object_unref (color); - - g_signal_emit (history, history_signals[COLOR_SELECTED], 0, &rgb); } /* Color history palette callback. */ diff --git a/app/widgets/gimpcolorhistory.h b/app/widgets/gimpcolorhistory.h index cd86196301..428bdb4dd1 100644 --- a/app/widgets/gimpcolorhistory.h +++ b/app/widgets/gimpcolorhistory.h @@ -51,7 +51,7 @@ struct _GimpColorHistoryClass /* signals */ void (* color_selected) (GimpColorHistory *history, - const GimpRGB *rgb); + GeglColor *color); }; @@ -60,5 +60,5 @@ GType gimp_color_history_get_type (void) G_GNUC_CONST; GtkWidget * gimp_color_history_new (GimpContext *context, gint history_size); -#endif /* __GIMP_COLOR_HISTORY_H__ */ +#endif /* __GIMP_COLOR_HISTORY_H__ */ diff --git a/libgimpconfig/gimpconfig-deserialize.c b/libgimpconfig/gimpconfig-deserialize.c index 8ff26f9945..79f7dd0faf 100644 --- a/libgimpconfig/gimpconfig-deserialize.c +++ b/libgimpconfig/gimpconfig-deserialize.c @@ -716,11 +716,13 @@ gimp_config_deserialize_rgb (GValue *value, GParamSpec *prop_spec, GScanner *scanner) { - GimpRGB rgb; + GeglColor *color = NULL; + GimpRGB rgb; - if (! gimp_scanner_parse_color (scanner, &rgb)) + if (! gimp_scanner_parse_color (scanner, &color)) return G_TOKEN_NONE; + gegl_color_get_pixel (color, babl_format ("R'G'B'A double"), &rgb); g_value_set_boxed (value, &rgb); return G_TOKEN_RIGHT_PAREN; @@ -1097,138 +1099,12 @@ gimp_config_deserialize_color (GValue *value, GParamSpec *prop_spec, GScanner *scanner) { - GTokenType token; + GeglColor *color = NULL; - token = g_scanner_peek_next_token (scanner); + if (! gimp_scanner_parse_color (scanner, &color)) + return G_TOKEN_NONE; - if (token == G_TOKEN_LEFT_PAREN) - { - GeglColor *color; - GimpRGB rgb; - - /* Support historical GimpRGB format which may be stored in various config - * files, but even some data (such as GTP tool presets which contains - * tool-options which are GimpContext). - */ - if (! gimp_scanner_parse_color (scanner, &rgb)) - return G_TOKEN_NONE; - - color = gegl_color_new (NULL); - gegl_color_set_pixel (color, babl_format ("R'G'B'A double"), &rgb); - g_value_take_object (value, color); - } - else if (token == G_TOKEN_IDENTIFIER) - { - g_scanner_get_next_token (scanner); - - if (g_ascii_strcasecmp (scanner->value.v_identifier, "null") != 0) - /* Do not fail the whole color parsing. Just output to stderr and assume - * a NULL color property. - */ - g_printerr ("%s: expected NULL identifier for color property '%s', got '%s'. " - "Assuming NULL instead.\n", - G_STRFUNC, prop_spec->name, scanner->value.v_identifier); - - g_value_set_object (value, NULL); - } - else if (token == G_TOKEN_STRING) - { - const Babl *format; - const Babl *space = NULL; - GeglColor *color; - gchar *encoding; - guint8 *data; - gint data_length; - gint profile_data_length; - - if (! gimp_scanner_parse_string (scanner, &encoding)) - return G_TOKEN_STRING; - - if (! babl_format_exists (encoding)) - { - g_scanner_error (scanner, - "%s: format \"%s\" for color property '%s' is not a valid babl format.", - G_STRFUNC, encoding, prop_spec->name); - g_free (encoding); - return G_TOKEN_NONE; - } - - format = babl_format (encoding); - g_free (encoding); - - if (! gimp_scanner_parse_int (scanner, &data_length)) - return G_TOKEN_INT; - - if (data_length != babl_format_get_bytes_per_pixel (format)) - { - g_scanner_error (scanner, - "%s: format \"%s\" expects %d bpp but color property '%s' was stored with %d bpp.", - G_STRFUNC, babl_get_name (format), - babl_format_get_bytes_per_pixel (format), - prop_spec->name, data_length); - return G_TOKEN_NONE; - } - - if (! gimp_scanner_parse_data (scanner, data_length, &data)) - return G_TOKEN_STRING; - - if (! gimp_scanner_parse_int (scanner, &profile_data_length)) - { - g_free (data); - return G_TOKEN_INT; - } - - if (profile_data_length > 0) - { - GimpColorProfile *profile; - guint8 *profile_data; - GError *error = NULL; - - if (! gimp_scanner_parse_data (scanner, profile_data_length, &profile_data)) - { - g_free (data); - return G_TOKEN_STRING; - } - - profile = gimp_color_profile_new_from_icc_profile (profile_data, profile_data_length, &error); - - if (profile) - { - space = gimp_color_profile_get_space (profile, - GIMP_COLOR_RENDERING_INTENT_RELATIVE_COLORIMETRIC, - &error); - - if (! space) - { - g_scanner_error (scanner, - "%s: failed to create Babl space for color property '%s' from profile: %s\n", - G_STRFUNC, prop_spec->name, error->message); - g_clear_error (&error); - } - g_object_unref (profile); - } - else - { - g_scanner_error (scanner, - "%s: invalid profile data for color property '%s': %s", - G_STRFUNC, prop_spec->name, error->message); - g_error_free (error); - } - format = babl_format_with_space (babl_format_get_encoding (format), space); - - g_free (profile_data); - } - - color = gegl_color_new (NULL); - gegl_color_set_pixel (color, format, data); - g_value_take_object (value, color); - - g_free (data); - } - else - { - return G_TOKEN_INT; - } + g_value_take_object (value, color); return G_TOKEN_RIGHT_PAREN; } diff --git a/libgimpconfig/gimpconfig-serialize.c b/libgimpconfig/gimpconfig-serialize.c index ebb5fc1bf3..f6e81e7706 100644 --- a/libgimpconfig/gimpconfig-serialize.c +++ b/libgimpconfig/gimpconfig-serialize.c @@ -310,12 +310,14 @@ gimp_config_serialize_property (GimpConfig *config, { const gchar *encoding; const Babl *format = gegl_color_get_format (color); + const Babl *space; GBytes *bytes; gconstpointer data; gsize data_length; - guint8 *profile_data; int profile_length = 0; + gimp_config_writer_open (writer, "color"); + if (babl_format_is_palette (format)) { guint8 pixel[40]; @@ -342,11 +344,25 @@ gimp_config_serialize_property (GimpConfig *config, gimp_config_writer_printf (writer, "%lu", data_length); gimp_config_writer_data (writer, data_length, data); - profile_data = (guint8 *) babl_space_get_icc (babl_format_get_space (format), - &profile_length); - gimp_config_writer_printf (writer, "%u", profile_length); - if (profile_data) - gimp_config_writer_data (writer, profile_length, profile_data); + space = babl_format_get_space (format); + if (space != babl_space ("sRGB")) + { + guint8 *profile_data; + + profile_data = (guint8 *) babl_space_get_icc (babl_format_get_space (format), + &profile_length); + gimp_config_writer_printf (writer, "%u", profile_length); + if (profile_data) + gimp_config_writer_data (writer, profile_length, profile_data); + } + else + { + gimp_config_writer_printf (writer, "%u", profile_length); + } + + g_bytes_unref (bytes); + + gimp_config_writer_close (writer); } else { diff --git a/libgimpconfig/gimpscanner.c b/libgimpconfig/gimpscanner.c index a4204c4f75..682f1c2dfe 100644 --- a/libgimpconfig/gimpscanner.c +++ b/libgimpconfig/gimpscanner.c @@ -65,13 +65,15 @@ G_DEFINE_BOXED_TYPE (GimpScanner, gimp_scanner, /* local function prototypes */ -static GimpScanner * gimp_scanner_new (const gchar *name, - GMappedFile *mapped, - gchar *text, - GError **error); -static void gimp_scanner_message (GimpScanner *scanner, - gchar *message, - gboolean is_error); +static GimpScanner * gimp_scanner_new (const gchar *name, + GMappedFile *mapped, + gchar *text, + GError **error); +static void gimp_scanner_message (GimpScanner *scanner, + gchar *message, + gboolean is_error); +static GTokenType gimp_scanner_parse_deprecated_color (GimpScanner *scanner, + GeglColor **color); /* public functions */ @@ -660,33 +662,37 @@ enum COLOR_RGB = 1, COLOR_RGBA, COLOR_HSV, - COLOR_HSVA + COLOR_HSVA, + COLOR }; /** * gimp_scanner_parse_color: * @scanner: A #GimpScanner created by gimp_scanner_new_file() or * gimp_scanner_new_string() - * @dest: (out caller-allocates): Pointer to a color to store the result + * @color: (out callee-allocates): Pointer to a color to store the result * * Returns: %TRUE on success * * Since: 2.4 **/ gboolean -gimp_scanner_parse_color (GimpScanner *scanner, - GimpRGB *dest) +gimp_scanner_parse_color (GimpScanner *scanner, + GeglColor **color) { guint scope_id; guint old_scope_id; GTokenType token; - GimpRGB color = { 0.0, 0.0, 0.0, 1.0 }; + gboolean success = TRUE; scope_id = g_quark_from_static_string ("gimp_scanner_parse_color"); old_scope_id = g_scanner_set_scope (scanner, scope_id); - if (! g_scanner_scope_lookup_symbol (scanner, scope_id, "color-rgb")) + if (! g_scanner_scope_lookup_symbol (scanner, scope_id, "color")) { + g_scanner_scope_add_symbol (scanner, scope_id, + "color", GINT_TO_POINTER (COLOR)); + /* Deprecated. Kept for backward compatibility. */ g_scanner_scope_add_symbol (scanner, scope_id, "color-rgb", GINT_TO_POINTER (COLOR_RGB)); g_scanner_scope_add_symbol (scanner, scope_id, @@ -697,90 +703,192 @@ gimp_scanner_parse_color (GimpScanner *scanner, "color-hsva", GINT_TO_POINTER (COLOR_HSVA)); } - token = G_TOKEN_LEFT_PAREN; + token = g_scanner_peek_next_token (scanner); - while (g_scanner_peek_next_token (scanner) == token) + if (token == G_TOKEN_IDENTIFIER) { - token = g_scanner_get_next_token (scanner); + g_scanner_get_next_token (scanner); - switch (token) + if (g_ascii_strcasecmp (scanner->value.v_identifier, "null") != 0) + /* Do not fail the whole color parsing. Just output to stderr and assume + * a NULL color property. + */ + g_printerr ("%s: expected NULL identifier for serialized color, got '%s'. " + "Assuming NULL instead.\n", + G_STRFUNC, scanner->value.v_identifier); + + *color = NULL; + + token = g_scanner_peek_next_token (scanner); + if (token == G_TOKEN_RIGHT_PAREN) + token = G_TOKEN_NONE; + else + token = G_TOKEN_RIGHT_PAREN; + } + else if (token == G_TOKEN_LEFT_PAREN) + { + g_scanner_get_next_token (scanner); + token = g_scanner_peek_next_token (scanner); + + if (token == G_TOKEN_SYMBOL) + { + if (GPOINTER_TO_INT (scanner->next_value.v_symbol) != COLOR) + { + /* Support historical GimpRGB format which may be stored in various config + * files, but even some data (such as GTP tool presets which contains + * tool-options which are GimpContext). + */ + if (gimp_scanner_parse_deprecated_color (scanner, color)) + token = G_TOKEN_RIGHT_PAREN; + else + success = FALSE; + } + else + { + const Babl *format; + gchar *encoding; + guint8 *data; + gint data_length; + gint profile_data_length; + + g_scanner_get_next_token (scanner); + + if (! gimp_scanner_parse_string (scanner, &encoding)) + { + token = G_TOKEN_STRING; + goto color_parsed; + } + + if (! babl_format_exists (encoding)) + { + g_scanner_error (scanner, + "%s: format \"%s\" for serialized color is not a valid babl format.", + G_STRFUNC, encoding); + g_free (encoding); + success = FALSE; + goto color_parsed; + } + + format = babl_format (encoding); + g_free (encoding); + + if (! gimp_scanner_parse_int (scanner, &data_length)) + { + token = G_TOKEN_INT; + goto color_parsed; + } + + if (data_length != babl_format_get_bytes_per_pixel (format)) + { + g_scanner_error (scanner, + "%s: format \"%s\" expects %d bpp but color was serialized with %d bpp.", + G_STRFUNC, babl_get_name (format), + babl_format_get_bytes_per_pixel (format), + data_length); + success = FALSE; + goto color_parsed; + } + + if (! gimp_scanner_parse_data (scanner, data_length, &data)) + { + token = G_TOKEN_STRING; + goto color_parsed; + } + + if (! gimp_scanner_parse_int (scanner, &profile_data_length)) + { + g_free (data); + token = G_TOKEN_INT; + goto color_parsed; + } + + if (profile_data_length > 0) + { + const Babl *space = NULL; + GimpColorProfile *profile; + guint8 *profile_data; + GError *error = NULL; + + if (! gimp_scanner_parse_data (scanner, profile_data_length, &profile_data)) + { + g_free (data); + token = G_TOKEN_STRING; + goto color_parsed; + } + + profile = gimp_color_profile_new_from_icc_profile (profile_data, profile_data_length, &error); + + if (profile) + { + space = gimp_color_profile_get_space (profile, + GIMP_COLOR_RENDERING_INTENT_RELATIVE_COLORIMETRIC, + &error); + + if (! space) + { + g_scanner_error (scanner, + "%s: failed to create Babl space for serialized color from profile: %s\n", + G_STRFUNC, error->message); + g_clear_error (&error); + } + g_object_unref (profile); + } + else + { + g_scanner_error (scanner, + "%s: invalid profile data for serialized color: %s", + G_STRFUNC, error->message); + g_error_free (error); + } + format = babl_format_with_space (babl_format_get_encoding (format), space); + + g_free (profile_data); + } + + *color = gegl_color_new (NULL); + gegl_color_set_pixel (*color, format, data); + + token = G_TOKEN_RIGHT_PAREN; + g_free (data); + } + } + else { - case G_TOKEN_LEFT_PAREN: token = G_TOKEN_SYMBOL; - break; + } - case G_TOKEN_SYMBOL: - { - gdouble col[4] = { 0.0, 0.0, 0.0, 1.0 }; - gint n_channels = 4; - gboolean is_hsv = FALSE; - gint i; - - switch (GPOINTER_TO_INT (scanner->value.v_symbol)) - { - case COLOR_RGB: - n_channels = 3; - /* fallthrough */ - case COLOR_RGBA: - break; - - case COLOR_HSV: - n_channels = 3; - /* fallthrough */ - case COLOR_HSVA: - is_hsv = TRUE; - break; - } - - token = G_TOKEN_FLOAT; - - for (i = 0; i < n_channels; i++) - { - if (! gimp_scanner_parse_float (scanner, &col[i])) - goto finish; - } - - if (is_hsv) - { - GimpHSV hsv; - - gimp_hsva_set (&hsv, col[0], col[1], col[2], col[3]); - gimp_hsv_to_rgb (&hsv, &color); - } - else - { - gimp_rgba_set (&color, col[0], col[1], col[2], col[3]); - } - - token = G_TOKEN_RIGHT_PAREN; - } - break; - - case G_TOKEN_RIGHT_PAREN: - token = G_TOKEN_NONE; /* indicates success */ - goto finish; - - default: /* do nothing */ - break; + if (success && token == G_TOKEN_RIGHT_PAREN) + { + token = g_scanner_peek_next_token (scanner); + if (token == G_TOKEN_RIGHT_PAREN) + { + g_scanner_get_next_token (scanner); + token = G_TOKEN_NONE; + } + else + { + g_clear_object (color); + token = G_TOKEN_RIGHT_PAREN; + } } } + else + { + token = G_TOKEN_LEFT_PAREN; + } - finish: +color_parsed: - if (token != G_TOKEN_NONE) + if (success && token != G_TOKEN_NONE) { g_scanner_get_next_token (scanner); g_scanner_unexp_token (scanner, token, NULL, NULL, NULL, _("fatal parse error"), TRUE); } - else - { - *dest = color; - } g_scanner_set_scope (scanner, old_scope_id); - return (token == G_TOKEN_NONE); + return (success && token == G_TOKEN_NONE); } /** @@ -887,3 +995,88 @@ gimp_scanner_message (GimpScanner *scanner, g_set_error (data->error, GIMP_CONFIG_ERROR, GIMP_CONFIG_ERROR_PARSE, "Error parsing internal buffer: %s", message); } + +static GTokenType +gimp_scanner_parse_deprecated_color (GimpScanner *scanner, + GeglColor **color) +{ + guint scope_id; + guint old_scope_id; + GTokenType token; + + scope_id = g_quark_from_static_string ("gimp_scanner_parse_deprecated_color"); + old_scope_id = g_scanner_set_scope (scanner, scope_id); + + if (! g_scanner_scope_lookup_symbol (scanner, scope_id, "color-rgb")) + { + g_scanner_scope_add_symbol (scanner, scope_id, + "color-rgb", GINT_TO_POINTER (COLOR_RGB)); + g_scanner_scope_add_symbol (scanner, scope_id, + "color-rgba", GINT_TO_POINTER (COLOR_RGBA)); + g_scanner_scope_add_symbol (scanner, scope_id, + "color-hsv", GINT_TO_POINTER (COLOR_HSV)); + g_scanner_scope_add_symbol (scanner, scope_id, + "color-hsva", GINT_TO_POINTER (COLOR_HSVA)); + } + + token = G_TOKEN_SYMBOL; + + while (g_scanner_peek_next_token (scanner) == token) + { + token = g_scanner_get_next_token (scanner); + + switch (token) + { + case G_TOKEN_SYMBOL: + { + gdouble col[4] = { 0.0, 0.0, 0.0, 1.0 }; + gint n_channels = 4; + gboolean is_hsv = FALSE; + gint i; + + switch (GPOINTER_TO_INT (scanner->value.v_symbol)) + { + case COLOR_RGB: + n_channels = 3; + /* fallthrough */ + case COLOR_RGBA: + break; + + case COLOR_HSV: + n_channels = 3; + /* fallthrough */ + case COLOR_HSVA: + is_hsv = TRUE; + break; + } + + token = G_TOKEN_FLOAT; + + for (i = 0; i < n_channels; i++) + { + if (! gimp_scanner_parse_float (scanner, &col[i])) + goto finish; + } + + *color = gegl_color_new (NULL); + if (is_hsv) + gegl_color_set_pixel (*color, babl_format ("HSVA double"), col); + else + gegl_color_set_pixel (*color, babl_format ("R'G'B'A double"), col); + + /* Indicates success. */ + token = G_TOKEN_NONE; + } + break; + + default: /* do nothing */ + break; + } + } + +finish: + + g_scanner_set_scope (scanner, old_scope_id); + + return token; +} diff --git a/libgimpconfig/gimpscanner.h b/libgimpconfig/gimpscanner.h index 3fd7dced20..2aec159ffe 100644 --- a/libgimpconfig/gimpscanner.h +++ b/libgimpconfig/gimpscanner.h @@ -72,7 +72,7 @@ gboolean gimp_scanner_parse_float (GimpScanner *scanner, gboolean gimp_scanner_parse_boolean (GimpScanner *scanner, gboolean *dest); gboolean gimp_scanner_parse_color (GimpScanner *scanner, - GimpRGB *dest); + GeglColor **color); gboolean gimp_scanner_parse_matrix2 (GimpScanner *scanner, GimpMatrix2 *dest);